Merge tag 'folio-6.0' of git://git.infradead.org/users/willy/pagecache
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 3 Aug 2022 17:35:43 +0000 (10:35 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 3 Aug 2022 17:35:43 +0000 (10:35 -0700)
Pull folio updates from Matthew Wilcox:

 - Fix an accounting bug that made NR_FILE_DIRTY grow without limit
   when running xfstests

 - Convert more of mpage to use folios

 - Remove add_to_page_cache() and add_to_page_cache_locked()

 - Convert find_get_pages_range() to filemap_get_folios()

 - Improvements to the read_cache_page() family of functions

 - Remove a few unnecessary checks of PageError

 - Some straightforward filesystem conversions to use folios

 - Split PageMovable users out from address_space_operations into
   their own movable_operations

 - Convert aops->migratepage to aops->migrate_folio

 - Remove nobh support (Christoph Hellwig)

* tag 'folio-6.0' of git://git.infradead.org/users/willy/pagecache: (78 commits)
  fs: remove the NULL get_block case in mpage_writepages
  fs: don't call ->writepage from __mpage_writepage
  fs: remove the nobh helpers
  jfs: stop using the nobh helper
  ext2: remove nobh support
  ntfs3: refactor ntfs_writepages
  mm/folio-compat: Remove migration compatibility functions
  fs: Remove aops->migratepage()
  secretmem: Convert to migrate_folio
  hugetlb: Convert to migrate_folio
  aio: Convert to migrate_folio
  f2fs: Convert to filemap_migrate_folio()
  ubifs: Convert to filemap_migrate_folio()
  btrfs: Convert btrfs_migratepage to migrate_folio
  mm/migrate: Add filemap_migrate_folio()
  mm/migrate: Convert migrate_page() to migrate_folio()
  nfs: Convert to migrate_folio
  btrfs: Convert btree_migratepage to migrate_folio
  mm/migrate: Convert expected_page_refs() to folio_expected_refs()
  mm/migrate: Convert buffer_migrate_page() to buffer_migrate_folio()
  ...

3825 files changed:
.mailmap
CREDITS
Documentation/ABI/stable/sysfs-block
Documentation/ABI/testing/sysfs-class-hwmon
Documentation/ABI/testing/sysfs-devices-system-cpu
Documentation/ABI/testing/sysfs-driver-qat [new file with mode: 0644]
Documentation/ABI/testing/sysfs-firmware-qemu_fw_cfg
Documentation/Kconfig
Documentation/RCU/Design/Requirements/Requirements.rst
Documentation/RCU/stallwarn.rst
Documentation/admin-guide/cgroup-v2.rst
Documentation/admin-guide/device-mapper/writecache.rst
Documentation/admin-guide/devices.rst
Documentation/admin-guide/efi-stub.rst
Documentation/admin-guide/kernel-parameters.txt
Documentation/admin-guide/perf/hns3-pmu.rst [new file with mode: 0644]
Documentation/admin-guide/perf/index.rst
Documentation/admin-guide/pm/cpuidle.rst
Documentation/admin-guide/sysctl/kernel.rst
Documentation/admin-guide/tainted-kernels.rst
Documentation/arm/google/chromebook-boot-flow.rst [new file with mode: 0644]
Documentation/arm/index.rst
Documentation/arm64/elf_hwcaps.rst
Documentation/arm64/memory.rst
Documentation/arm64/silicon-errata.rst
Documentation/core-api/idr.rst
Documentation/core-api/kernel-api.rst
Documentation/core-api/protection-keys.rst
Documentation/core-api/symbol-namespaces.rst
Documentation/dev-tools/coccinelle.rst
Documentation/dev-tools/kselftest.rst
Documentation/dev-tools/kunit/run_wrapper.rst
Documentation/dev-tools/kunit/running_tips.rst
Documentation/dev-tools/kunit/usage.rst
Documentation/devicetree/bindings/arm/altera.yaml
Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/atmel-at91.yaml
Documentation/devicetree/bindings/arm/bcm/brcm,bcm4708.yaml
Documentation/devicetree/bindings/arm/bcm/brcm,bcmbca.yaml
Documentation/devicetree/bindings/arm/cpus.yaml
Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt [deleted file]
Documentation/devicetree/bindings/arm/fsl.yaml
Documentation/devicetree/bindings/arm/marvell/marvell,ac5.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/mediatek.yaml
Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.yaml
Documentation/devicetree/bindings/arm/npcm/npcm.yaml
Documentation/devicetree/bindings/arm/npcm/nuvoton,gcr.yaml
Documentation/devicetree/bindings/arm/qcom.yaml
Documentation/devicetree/bindings/arm/rockchip.yaml
Documentation/devicetree/bindings/arm/samsung/samsung-soc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/stm32/stm32.yaml
Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/sunxi.yaml
Documentation/devicetree/bindings/arm/sunxi/allwinner,sun4i-a10-mbus.yaml
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra-ccplex-cluster.yaml
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra194-axi2apb.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra194-cbb.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra234-cbb.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml
Documentation/devicetree/bindings/clock/fsl,scu-clk.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/clock/nuvoton,npcm845-clk.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/clock/qcom,dispcc-sm8x50.yaml
Documentation/devicetree/bindings/clock/qcom,gpucc-sm8350.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/clock/samsung,exynos7885-clock.yaml
Documentation/devicetree/bindings/clock/st,stm32mp1-rcc.yaml
Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/cpufreq/qcom-cpufreq-nvmem.yaml
Documentation/devicetree/bindings/devfreq/exynos-bus.txt [deleted file]
Documentation/devicetree/bindings/display/allwinner,sun4i-a10-display-engine.yaml
Documentation/devicetree/bindings/display/panel/lgphilips,lb035q02.yaml
Documentation/devicetree/bindings/display/panel/samsung,ld9040.yaml
Documentation/devicetree/bindings/display/panel/sitronix,st7789v.yaml
Documentation/devicetree/bindings/display/panel/tpo,td.yaml
Documentation/devicetree/bindings/dma/allwinner,sun50i-a64-dma.yaml
Documentation/devicetree/bindings/firmware/arm,scmi.yaml
Documentation/devicetree/bindings/firmware/fsl,scu.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/firmware/qcom,scm.txt
Documentation/devicetree/bindings/gpio/gpio-zynq.yaml
Documentation/devicetree/bindings/hwinfo/renesas,prr.yaml [moved from Documentation/devicetree/bindings/arm/renesas,prr.yaml with 85% similarity]
Documentation/devicetree/bindings/hwmon/national,lm90.yaml
Documentation/devicetree/bindings/i2c/marvell,mv64xxx-i2c.yaml
Documentation/devicetree/bindings/input/da9062-onkey.txt
Documentation/devicetree/bindings/input/fsl,scu-key.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/interconnect/samsung,exynos-bus.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/renesas,rzg2l-irqc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml
Documentation/devicetree/bindings/interrupt-controller/sunplus,sp7021-intc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.yaml
Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.yaml
Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml
Documentation/devicetree/bindings/net/ethernet-controller.yaml
Documentation/devicetree/bindings/net/fsl,fec.yaml
Documentation/devicetree/bindings/net/pcs/renesas,rzn1-miic.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/net/wireless/qca,ath9k.yaml
Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml
Documentation/devicetree/bindings/nvmem/fsl,scu-ocotp.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/allwinner,sun4i-a10-pinctrl.yaml
Documentation/devicetree/bindings/pinctrl/fsl,scu-pinctrl.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml
Documentation/devicetree/bindings/power/fsl,scu-pd.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/power/mediatek,power-controller.yaml
Documentation/devicetree/bindings/power/qcom,rpmpd.yaml
Documentation/devicetree/bindings/pwm/clk-pwm.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/pwm-mediatek.txt
Documentation/devicetree/bindings/regulator/mps,mp5416.yaml
Documentation/devicetree/bindings/regulator/pwm-regulator.txt [deleted file]
Documentation/devicetree/bindings/regulator/pwm-regulator.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.yaml
Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt [deleted file]
Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/regulator.yaml
Documentation/devicetree/bindings/reset/nuvoton,npcm750-reset.yaml
Documentation/devicetree/bindings/reset/sunplus,reset.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/fsl,scu-rtc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/soc/bcm/brcm,bcm2835-pm.txt [deleted file]
Documentation/devicetree/bindings/soc/bcm/brcm,bcm2835-pm.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/soc/mediatek/devapc.yaml
Documentation/devicetree/bindings/soc/mediatek/mediatek,mutex.yaml [moved from Documentation/devicetree/bindings/display/mediatek/mediatek,mutex.yaml with 81% similarity]
Documentation/devicetree/bindings/soc/mediatek/mtk-svs.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/soc/microchip/atmel,at91rm9200-tcb.yaml
Documentation/devicetree/bindings/soc/microchip/microchip,mpfs-sys-controller.yaml
Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml
Documentation/devicetree/bindings/soc/qcom/qcom,rpmh-rsc.yaml
Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml
Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml
Documentation/devicetree/bindings/soc/qcom/qcom,wcnss.yaml
Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml
Documentation/devicetree/bindings/soc/samsung/exynos-usi.yaml
Documentation/devicetree/bindings/soc/ti/ti,pruss.yaml
Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml
Documentation/devicetree/bindings/spi/atmel,at91rm9200-spi.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/spi/hpe,gxp-spifi.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/spi/mediatek,spi-mt65xx.yaml
Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml
Documentation/devicetree/bindings/spi/nuvoton,npcm-fiu.txt
Documentation/devicetree/bindings/spi/nvidia,tegra210-quad-peripheral-props.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/spi/nvidia,tegra210-quad.yaml
Documentation/devicetree/bindings/spi/qcom,spi-geni-qcom.yaml
Documentation/devicetree/bindings/spi/samsung,spi.yaml
Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml
Documentation/devicetree/bindings/spi/spi-cadence.yaml
Documentation/devicetree/bindings/spi/spi-controller.yaml
Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.yaml
Documentation/devicetree/bindings/spi/spi_atmel.txt [deleted file]
Documentation/devicetree/bindings/thermal/fsl,scu-thermal.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/thermal/qcom,spmi-temp-alarm.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/thermal/qcom-spmi-temp-alarm.txt [deleted file]
Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.yaml
Documentation/devicetree/bindings/timer/allwinner,sun4i-a10-timer.yaml
Documentation/devicetree/bindings/timer/ingenic,tcu.yaml
Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt
Documentation/devicetree/bindings/timer/nuvoton,npcm7xx-timer.yaml
Documentation/devicetree/bindings/timer/nvidia,tegra186-timer.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/timer/renesas,cmt.yaml
Documentation/devicetree/bindings/timer/st,nomadik-mtu.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/trivial-devices.yaml
Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.yaml
Documentation/devicetree/bindings/usb/atmel-usb.txt
Documentation/devicetree/bindings/usb/generic-ehci.yaml
Documentation/devicetree/bindings/usb/generic-ohci.yaml
Documentation/devicetree/bindings/vendor-prefixes.yaml
Documentation/devicetree/bindings/watchdog/fsl,scu-wdt.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/watchdog/nuvoton,npcm-wdt.txt
Documentation/doc-guide/kernel-doc.rst
Documentation/doc-guide/sphinx.rst
Documentation/driver-api/firmware/other_interfaces.rst
Documentation/driver-api/gpio/consumer.rst
Documentation/driver-api/gpio/driver.rst
Documentation/driver-api/gpio/using-gpio.rst
Documentation/driver-api/hte/tegra194-hte.rst
Documentation/features/time/context-tracking/arch-support.txt
Documentation/features/vm/ioremap_prot/arch-support.txt
Documentation/filesystems/btrfs.rst
Documentation/filesystems/f2fs.rst
Documentation/filesystems/fscrypt.rst
Documentation/filesystems/fsverity.rst
Documentation/filesystems/netfs_library.rst
Documentation/filesystems/overlayfs.rst
Documentation/firmware-guide/acpi/DSD-properties-rules.rst
Documentation/firmware-guide/acpi/apei/einj.rst
Documentation/hwmon/aquacomputer_d5next.rst
Documentation/hwmon/asus_ec_sensors.rst
Documentation/hwmon/dell-smm-hwmon.rst
Documentation/hwmon/index.rst
Documentation/hwmon/lm90.rst
Documentation/hwmon/lt7182s.rst [new file with mode: 0644]
Documentation/hwmon/pmbus-core.rst
Documentation/hwmon/submitting-patches.rst
Documentation/kbuild/llvm.rst
Documentation/kernel-hacking/hacking.rst
Documentation/livepatch/module-elf-format.rst
Documentation/memory-barriers.txt
Documentation/networking/dsa/dsa.rst
Documentation/networking/ip-sysctl.rst
Documentation/power/energy-model.rst
Documentation/power/pci.rst
Documentation/process/5.Posting.rst
Documentation/process/8.Conclusion.rst
Documentation/process/email-clients.rst
Documentation/process/howto.rst
Documentation/process/index.rst
Documentation/process/kernel-docs.rst
Documentation/process/maintainer-netdev.rst
Documentation/process/submitting-drivers.rst [deleted file]
Documentation/process/submitting-patches.rst
Documentation/scsi/scsi_eh.rst
Documentation/scsi/scsi_mid_low_api.rst
Documentation/security/keys/core.rst
Documentation/security/secrets/coco.rst
Documentation/security/siphash.rst
Documentation/sound/soc/dai.rst
Documentation/sphinx/automarkup.py
Documentation/staging/static-keys.rst
Documentation/translations/it_IT/core-api/symbol-namespaces.rst
Documentation/translations/it_IT/devicetree/bindings/submitting-patches.rst [new file with mode: 0644]
Documentation/translations/it_IT/doc-guide/kernel-doc.rst
Documentation/translations/it_IT/doc-guide/sphinx.rst
Documentation/translations/it_IT/kernel-hacking/hacking.rst
Documentation/translations/it_IT/kernel-hacking/locking.rst
Documentation/translations/it_IT/maintainer/configure-git.rst [new file with mode: 0644]
Documentation/translations/it_IT/networking/netdev-FAQ.rst
Documentation/translations/it_IT/process/3.Early-stage.rst
Documentation/translations/it_IT/process/5.Posting.rst
Documentation/translations/it_IT/process/8.Conclusion.rst
Documentation/translations/it_IT/process/changes.rst
Documentation/translations/it_IT/process/coding-style.rst
Documentation/translations/it_IT/process/deprecated.rst
Documentation/translations/it_IT/process/howto.rst
Documentation/translations/it_IT/process/index.rst
Documentation/translations/it_IT/process/maintainer-handbooks.rst [new file with mode: 0644]
Documentation/translations/it_IT/process/maintainer-pgp-guide.rst
Documentation/translations/it_IT/process/maintainer-tip.rst [new file with mode: 0644]
Documentation/translations/it_IT/process/maintainers.rst [new file with mode: 0644]
Documentation/translations/it_IT/process/stable-kernel-rules.rst
Documentation/translations/it_IT/process/submitting-drivers.rst [deleted file]
Documentation/translations/it_IT/process/submitting-patches.rst
Documentation/translations/ja_JP/howto.rst
Documentation/translations/ko_KR/howto.rst
Documentation/translations/zh_CN/PCI/pci-iov-howto.rst
Documentation/translations/zh_CN/PCI/pci.rst
Documentation/translations/zh_CN/admin-guide/index.rst
Documentation/translations/zh_CN/admin-guide/mm/damon/usage.rst
Documentation/translations/zh_CN/admin-guide/reporting-issues.rst
Documentation/translations/zh_CN/admin-guide/reporting-regressions.rst [new file with mode: 0644]
Documentation/translations/zh_CN/core-api/cachetlb.rst
Documentation/translations/zh_CN/core-api/cpu_hotplug.rst
Documentation/translations/zh_CN/core-api/index.rst
Documentation/translations/zh_CN/core-api/irq/irq-domain.rst
Documentation/translations/zh_CN/core-api/kernel-api.rst
Documentation/translations/zh_CN/core-api/mm-api.rst
Documentation/translations/zh_CN/core-api/printk-basics.rst
Documentation/translations/zh_CN/core-api/printk-formats.rst
Documentation/translations/zh_CN/core-api/symbol-namespaces.rst
Documentation/translations/zh_CN/core-api/watch_queue.rst [new file with mode: 0644]
Documentation/translations/zh_CN/core-api/workqueue.rst
Documentation/translations/zh_CN/core-api/xarray.rst
Documentation/translations/zh_CN/dev-tools/kasan.rst
Documentation/translations/zh_CN/dev-tools/sparse.rst
Documentation/translations/zh_CN/dev-tools/testing-overview.rst
Documentation/translations/zh_CN/devicetree/index.rst
Documentation/translations/zh_CN/devicetree/of_unittest.rst
Documentation/translations/zh_CN/devicetree/usage-model.rst
Documentation/translations/zh_CN/doc-guide/kernel-doc.rst
Documentation/translations/zh_CN/iio/iio_configfs.rst
Documentation/translations/zh_CN/kernel-hacking/hacking.rst
Documentation/translations/zh_CN/locking/index.rst
Documentation/translations/zh_CN/locking/mutex-design.rst [new file with mode: 0644]
Documentation/translations/zh_CN/process/5.Posting.rst
Documentation/translations/zh_CN/process/8.Conclusion.rst
Documentation/translations/zh_CN/process/howto.rst
Documentation/translations/zh_CN/process/index.rst
Documentation/translations/zh_CN/process/submitting-drivers.rst [deleted file]
Documentation/translations/zh_CN/process/submitting-patches.rst
Documentation/translations/zh_CN/riscv/index.rst
Documentation/translations/zh_CN/riscv/pmu.rst [deleted file]
Documentation/translations/zh_CN/riscv/vm-layout.rst
Documentation/translations/zh_CN/scheduler/sched-stats.rst
Documentation/translations/zh_CN/vm/free_page_reporting.rst
Documentation/translations/zh_CN/vm/frontswap.rst
Documentation/translations/zh_CN/vm/highmem.rst
Documentation/translations/zh_CN/vm/index.rst
Documentation/translations/zh_CN/vm/page_frags.rst
Documentation/translations/zh_CN/vm/page_migration.rst [new file with mode: 0644]
Documentation/translations/zh_CN/vm/page_owner.rst
Documentation/translations/zh_CN/vm/vmalloced-kernel-stacks.rst [new file with mode: 0644]
Documentation/translations/zh_CN/vm/zsmalloc.rst
Documentation/translations/zh_TW/process/5.Posting.rst
Documentation/translations/zh_TW/process/8.Conclusion.rst
Documentation/translations/zh_TW/process/howto.rst
Documentation/translations/zh_TW/process/index.rst
Documentation/translations/zh_TW/process/submitting-drivers.rst [deleted file]
Documentation/translations/zh_TW/process/submitting-patches.rst
Documentation/virt/hyperv/clocks.rst [new file with mode: 0644]
Documentation/virt/hyperv/index.rst [new file with mode: 0644]
Documentation/virt/hyperv/overview.rst [new file with mode: 0644]
Documentation/virt/hyperv/vmbus.rst [new file with mode: 0644]
Documentation/virt/index.rst
Documentation/virt/kvm/api.rst
Documentation/virt/kvm/arm/hyp-abi.rst
Documentation/virt/kvm/s390/s390-pv-boot.rst
Documentation/virt/kvm/x86/hypercalls.rst
Documentation/virt/uml/user_mode_linux_howto_v2.rst
Documentation/vm/hwpoison.rst
Documentation/vm/overcommit-accounting.rst
Documentation/x86/orc-unwinder.rst
MAINTAINERS
Makefile
arch/Kconfig
arch/alpha/kernel/irq.c
arch/arc/kernel/jump_label.c
arch/arm/Kconfig
arch/arm/Kconfig.debug
arch/arm/Makefile
arch/arm/boot/dts/Makefile
arch/arm/boot/dts/alpine.dtsi
arch/arm/boot/dts/am335x-boneblack-wireless.dts
arch/arm/boot/dts/am335x-boneblack.dts
arch/arm/boot/dts/am335x-boneblue.dts
arch/arm/boot/dts/am335x-bonegreen-wireless.dts
arch/arm/boot/dts/am335x-cm-t335.dts
arch/arm/boot/dts/am335x-evm.dts
arch/arm/boot/dts/am335x-guardian.dts
arch/arm/boot/dts/am335x-moxa-uc-2100-common.dtsi
arch/arm/boot/dts/am335x-moxa-uc-8100-common.dtsi
arch/arm/boot/dts/am335x-pcm-953.dtsi
arch/arm/boot/dts/am335x-pepper.dts
arch/arm/boot/dts/am335x-sancloud-bbe-extended-wifi.dts
arch/arm/boot/dts/am335x-shc.dts
arch/arm/boot/dts/am3517-evm-ui.dtsi
arch/arm/boot/dts/am3517-evm.dts
arch/arm/boot/dts/am3874-iceboard.dts
arch/arm/boot/dts/am437x-idk-evm.dts
arch/arm/boot/dts/am437x-l4.dtsi
arch/arm/boot/dts/animeo_ip.dts
arch/arm/boot/dts/armada-370-c200-v2.dts
arch/arm/boot/dts/armada-370-rd.dts
arch/arm/boot/dts/armada-370-seagate-nas-xbay.dtsi
arch/arm/boot/dts/armada-370-seagate-personal-cloud.dtsi
arch/arm/boot/dts/armada-381-netgear-gs110emx.dts
arch/arm/boot/dts/armada-385-clearfog-gtr.dtsi
arch/arm/boot/dts/armada-385-linksys.dtsi
arch/arm/boot/dts/armada-385-turris-omnia.dts
arch/arm/boot/dts/armada-388-clearfog-base.dts
arch/arm/boot/dts/armada-388-clearfog.dts
arch/arm/boot/dts/armada-xp-axpwifiap.dts
arch/arm/boot/dts/armada-xp-linksys-mamba.dts
arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts
arch/arm/boot/dts/aspeed-ast2500-evb.dts
arch/arm/boot/dts/aspeed-ast2600-evb-a1.dts
arch/arm/boot/dts/aspeed-ast2600-evb.dts
arch/arm/boot/dts/aspeed-bmc-ampere-mtjade.dts
arch/arm/boot/dts/aspeed-bmc-arm-centriq2400-rep.dts [deleted file]
arch/arm/boot/dts/aspeed-bmc-bytedance-g220a.dts
arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts
arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts
arch/arm/boot/dts/aspeed-bmc-inspur-fp5280g2.dts
arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts
arch/arm/boot/dts/aspeed-bmc-opp-mowgli.dts
arch/arm/boot/dts/aspeed-bmc-opp-nicole.dts
arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts
arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts
arch/arm/boot/dts/aspeed-bmc-opp-swift.dts
arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts
arch/arm/boot/dts/aspeed-bmc-opp-vesnin.dts
arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts
arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts
arch/arm/boot/dts/aspeed-bmc-portwell-neptune.dts
arch/arm/boot/dts/aspeed-bmc-qcom-dc-scm-v1.dts [moved from arch/arm/boot/dts/aspeed-bmc-nuvia-dc-scm.dts with 97% similarity]
arch/arm/boot/dts/aspeed-bmc-quanta-s6q.dts
arch/arm/boot/dts/at91-foxg20.dts
arch/arm/boot/dts/at91-gatwick.dts
arch/arm/boot/dts/at91-kizbox.dts
arch/arm/boot/dts/at91-kizbox2-common.dtsi
arch/arm/boot/dts/at91-kizbox3-hs.dts
arch/arm/boot/dts/at91-kizboxmini-common.dtsi
arch/arm/boot/dts/at91-nattis-2-natte-2.dts
arch/arm/boot/dts/at91-qil_a9260.dts
arch/arm/boot/dts/at91-sam9x60ek.dts
arch/arm/boot/dts/at91-sama5d27_som1.dtsi
arch/arm/boot/dts/at91-sama5d27_som1_ek.dts
arch/arm/boot/dts/at91-sama5d27_wlsom1.dtsi
arch/arm/boot/dts/at91-sama5d27_wlsom1_ek.dts
arch/arm/boot/dts/at91-sama5d2_icp.dts
arch/arm/boot/dts/at91-sama5d2_ptc_ek.dts
arch/arm/boot/dts/at91-sama5d2_xplained.dts
arch/arm/boot/dts/at91-sama5d3_xplained.dts
arch/arm/boot/dts/at91-sama5d4_xplained.dts
arch/arm/boot/dts/at91-sama5d4ek.dts
arch/arm/boot/dts/at91-sama7g5ek.dts
arch/arm/boot/dts/at91-wb45n.dts
arch/arm/boot/dts/at91-wb50n.dts
arch/arm/boot/dts/at91sam9260.dtsi
arch/arm/boot/dts/at91sam9260ek.dts
arch/arm/boot/dts/at91sam9261.dtsi
arch/arm/boot/dts/at91sam9261ek.dts
arch/arm/boot/dts/at91sam9263.dtsi
arch/arm/boot/dts/at91sam9263ek.dts
arch/arm/boot/dts/at91sam9g20ek_common.dtsi
arch/arm/boot/dts/at91sam9g25-gardena-smart-gateway.dts
arch/arm/boot/dts/at91sam9g45.dtsi
arch/arm/boot/dts/at91sam9m10g45ek.dts
arch/arm/boot/dts/at91sam9n12.dtsi
arch/arm/boot/dts/at91sam9n12ek.dts
arch/arm/boot/dts/at91sam9rl.dtsi
arch/arm/boot/dts/at91sam9rlek.dts
arch/arm/boot/dts/at91sam9x5.dtsi
arch/arm/boot/dts/axm5516-cpus.dtsi
arch/arm/boot/dts/bcm2711-rpi-400.dts
arch/arm/boot/dts/bcm2711-rpi.dtsi
arch/arm/boot/dts/bcm2711.dtsi
arch/arm/boot/dts/bcm28155-ap.dts
arch/arm/boot/dts/bcm2835-common.dtsi
arch/arm/boot/dts/bcm283x.dtsi
arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts
arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts
arch/arm/boot/dts/bcm4708-buffalo-wzr-1166dhp-common.dtsi
arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
arch/arm/boot/dts/bcm4708-linksys-ea6300-v1.dts
arch/arm/boot/dts/bcm4708-linksys-ea6500-v2.dts
arch/arm/boot/dts/bcm4708-luxul-xap-1510.dts
arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts
arch/arm/boot/dts/bcm4708-netgear-r6250.dts
arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts
arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts
arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts
arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts
arch/arm/boot/dts/bcm47081-luxul-xap-1410.dts
arch/arm/boot/dts/bcm47081-luxul-xwr-1200.dts
arch/arm/boot/dts/bcm47081-tplink-archer-c5-v2.dts
arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts
arch/arm/boot/dts/bcm4709-linksys-ea9200.dts
arch/arm/boot/dts/bcm4709-netgear-r7000.dts
arch/arm/boot/dts/bcm4709-netgear-r8000.dts
arch/arm/boot/dts/bcm4709-tplink-archer-c9-v1.dts
arch/arm/boot/dts/bcm47094-asus-rt-ac88u.dts
arch/arm/boot/dts/bcm47094-dlink-dir-885l.dts
arch/arm/boot/dts/bcm47094-linksys-panamera.dts
arch/arm/boot/dts/bcm47094-luxul-abr-4500.dts
arch/arm/boot/dts/bcm47094-luxul-xap-1610.dts
arch/arm/boot/dts/bcm47094-luxul-xbr-4500.dts
arch/arm/boot/dts/bcm47094-luxul-xwc-2000.dts
arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts
arch/arm/boot/dts/bcm47094-luxul-xwr-3150-v1.dts
arch/arm/boot/dts/bcm47094-netgear-r8500.dts
arch/arm/boot/dts/bcm47094-phicomm-k3.dts
arch/arm/boot/dts/bcm47189-luxul-xap-1440.dts
arch/arm/boot/dts/bcm47189-luxul-xap-810.dts
arch/arm/boot/dts/bcm47189-tenda-ac9.dts
arch/arm/boot/dts/bcm47622.dtsi
arch/arm/boot/dts/bcm53015-meraki-mr26.dts [new file with mode: 0644]
arch/arm/boot/dts/bcm53016-meraki-mr32.dts
arch/arm/boot/dts/bcm5301x.dtsi
arch/arm/boot/dts/bcm63138.dtsi
arch/arm/boot/dts/bcm63148.dtsi [new file with mode: 0644]
arch/arm/boot/dts/bcm63178.dtsi [new file with mode: 0644]
arch/arm/boot/dts/bcm6756.dtsi [new file with mode: 0644]
arch/arm/boot/dts/bcm6846.dtsi [new file with mode: 0644]
arch/arm/boot/dts/bcm6855.dtsi [new file with mode: 0644]
arch/arm/boot/dts/bcm6878.dtsi [new file with mode: 0644]
arch/arm/boot/dts/bcm911360_entphn.dts
arch/arm/boot/dts/bcm947189acdbmr.dts
arch/arm/boot/dts/bcm953012er.dts
arch/arm/boot/dts/bcm958625-meraki-alamo.dtsi
arch/arm/boot/dts/bcm958625-meraki-kingpin.dtsi
arch/arm/boot/dts/bcm963138.dts [new file with mode: 0644]
arch/arm/boot/dts/bcm963138dvt.dts
arch/arm/boot/dts/bcm963148.dts [new file with mode: 0644]
arch/arm/boot/dts/bcm963178.dts [new file with mode: 0644]
arch/arm/boot/dts/bcm96756.dts [new file with mode: 0644]
arch/arm/boot/dts/bcm96846.dts [new file with mode: 0644]
arch/arm/boot/dts/bcm96855.dts [new file with mode: 0644]
arch/arm/boot/dts/bcm96878.dts [new file with mode: 0644]
arch/arm/boot/dts/da850-evm.dts
arch/arm/boot/dts/da850.dtsi
arch/arm/boot/dts/dm8148-evm.dts
arch/arm/boot/dts/dm8168-evm.dts
arch/arm/boot/dts/dra62x-j5eco-evm.dts
arch/arm/boot/dts/dra76x.dtsi
arch/arm/boot/dts/e60k02.dtsi
arch/arm/boot/dts/e70k02.dtsi
arch/arm/boot/dts/ecx-common.dtsi
arch/arm/boot/dts/en7523-evb.dts
arch/arm/boot/dts/en7523.dtsi
arch/arm/boot/dts/exynos-pinctrl.h [new file with mode: 0644]
arch/arm/boot/dts/exynos3250-artik5.dtsi
arch/arm/boot/dts/exynos3250-pinctrl.dtsi
arch/arm/boot/dts/exynos3250.dtsi
arch/arm/boot/dts/exynos4.dtsi
arch/arm/boot/dts/exynos4210-i9100.dts
arch/arm/boot/dts/exynos4210-origen.dts
arch/arm/boot/dts/exynos4210-pinctrl.dtsi
arch/arm/boot/dts/exynos4210-trats.dts
arch/arm/boot/dts/exynos4412-galaxy-s3.dtsi
arch/arm/boot/dts/exynos4412-itop-elite.dts
arch/arm/boot/dts/exynos4412-midas.dtsi
arch/arm/boot/dts/exynos4412-odroidu3.dts
arch/arm/boot/dts/exynos4412-odroidx.dts
arch/arm/boot/dts/exynos4412-p4note.dtsi
arch/arm/boot/dts/exynos4412-pinctrl.dtsi
arch/arm/boot/dts/exynos4412-tiny4412.dts
arch/arm/boot/dts/exynos5.dtsi
arch/arm/boot/dts/exynos5250-arndale.dts
arch/arm/boot/dts/exynos5250-pinctrl.dtsi
arch/arm/boot/dts/exynos5250-snow-common.dtsi
arch/arm/boot/dts/exynos5250-spring.dts
arch/arm/boot/dts/exynos5260-pinctrl.dtsi
arch/arm/boot/dts/exynos5410-pinctrl.dtsi
arch/arm/boot/dts/exynos5420-arndale-octa.dts
arch/arm/boot/dts/exynos5420-peach-pit.dts
arch/arm/boot/dts/exynos5420-pinctrl.dtsi
arch/arm/boot/dts/exynos5422-odroidhc1.dts
arch/arm/boot/dts/exynos5422-odroidxu4.dts
arch/arm/boot/dts/exynos54xx-odroidxu-leds.dtsi
arch/arm/boot/dts/exynos5800-peach-pi.dts
arch/arm/boot/dts/imx25.dtsi
arch/arm/boot/dts/imx27.dtsi
arch/arm/boot/dts/imx31.dtsi
arch/arm/boot/dts/imx50.dtsi
arch/arm/boot/dts/imx51-ts4800.dts
arch/arm/boot/dts/imx51.dtsi
arch/arm/boot/dts/imx53.dtsi
arch/arm/boot/dts/imx6dl-plym2m.dts
arch/arm/boot/dts/imx6dl-prtvt7.dts
arch/arm/boot/dts/imx6dl-victgo.dts
arch/arm/boot/dts/imx6dl.dtsi
arch/arm/boot/dts/imx6q-apalis-eval.dts
arch/arm/boot/dts/imx6q-apalis-ixora-v1.1.dts
arch/arm/boot/dts/imx6q-apalis-ixora-v1.2.dts [new file with mode: 0644]
arch/arm/boot/dts/imx6q-apalis-ixora.dts
arch/arm/boot/dts/imx6q-bosch-acc.dts
arch/arm/boot/dts/imx6q-skov-reve-mi1010ait-1cp1.dts
arch/arm/boot/dts/imx6q.dtsi
arch/arm/boot/dts/imx6qdl-apalis.dtsi
arch/arm/boot/dts/imx6qdl-colibri.dtsi
arch/arm/boot/dts/imx6qdl-prti6q.dtsi
arch/arm/boot/dts/imx6qdl-skov-cpu-revc.dtsi
arch/arm/boot/dts/imx6qdl-skov-cpu.dtsi
arch/arm/boot/dts/imx6qdl-ts7970.dtsi
arch/arm/boot/dts/imx6qdl.dtsi
arch/arm/boot/dts/imx6sl-tolino-shine2hd.dts
arch/arm/boot/dts/imx6sx.dtsi
arch/arm/boot/dts/imx6ul-kontron-n6x1x-s.dtsi
arch/arm/boot/dts/imx6ul-phytec-segin.dtsi
arch/arm/boot/dts/imx6ul-tqma6ul2l.dtsi
arch/arm/boot/dts/imx6ul.dtsi
arch/arm/boot/dts/imx6ull-colibri.dtsi
arch/arm/boot/dts/imx6ull-tqma6ull2.dtsi
arch/arm/boot/dts/imx6ull-tqma6ull2l.dtsi
arch/arm/boot/dts/imx6ull.dtsi
arch/arm/boot/dts/imx6ulz-bsh-smm-m2.dts
arch/arm/boot/dts/imx7-colibri-aster.dtsi
arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi
arch/arm/boot/dts/imx7-colibri-iris-v2.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx7-colibri-iris.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx7-colibri.dtsi
arch/arm/boot/dts/imx7d-colibri-aster.dts
arch/arm/boot/dts/imx7d-colibri-emmc-aster.dts
arch/arm/boot/dts/imx7d-colibri-emmc-eval-v3.dts
arch/arm/boot/dts/imx7d-colibri-emmc-iris-v2.dts [new file with mode: 0644]
arch/arm/boot/dts/imx7d-colibri-emmc-iris.dts [new file with mode: 0644]
arch/arm/boot/dts/imx7d-colibri-emmc.dtsi
arch/arm/boot/dts/imx7d-colibri-eval-v3.dts
arch/arm/boot/dts/imx7d-colibri-iris-v2.dts [new file with mode: 0644]
arch/arm/boot/dts/imx7d-colibri-iris.dts [new file with mode: 0644]
arch/arm/boot/dts/imx7d-colibri.dtsi
arch/arm/boot/dts/imx7d-sdb.dts
arch/arm/boot/dts/imx7d-smegw01.dts
arch/arm/boot/dts/imx7d.dtsi
arch/arm/boot/dts/imx7s-colibri-aster.dts
arch/arm/boot/dts/imx7s-colibri-eval-v3.dts
arch/arm/boot/dts/imx7s-colibri-iris-v2.dts [new file with mode: 0644]
arch/arm/boot/dts/imx7s-colibri-iris.dts [new file with mode: 0644]
arch/arm/boot/dts/imx7s-colibri.dtsi
arch/arm/boot/dts/imx7s.dtsi
arch/arm/boot/dts/imxrt1050.dtsi
arch/arm/boot/dts/keystone-k2e-netcp.dtsi
arch/arm/boot/dts/keystone-k2e.dtsi
arch/arm/boot/dts/keystone-k2g-netcp.dtsi
arch/arm/boot/dts/keystone-k2g.dtsi
arch/arm/boot/dts/keystone-k2hk-netcp.dtsi
arch/arm/boot/dts/keystone-k2hk.dtsi
arch/arm/boot/dts/keystone-k2l-netcp.dtsi
arch/arm/boot/dts/keystone-k2l.dtsi
arch/arm/boot/dts/keystone.dtsi
arch/arm/boot/dts/lan966x-kontron-kswitch-d10-mmt.dtsi
arch/arm/boot/dts/lan966x-pcb8291.dts
arch/arm/boot/dts/lan966x-pcb8309.dts [new file with mode: 0644]
arch/arm/boot/dts/lan966x.dtsi
arch/arm/boot/dts/lpc18xx.dtsi
arch/arm/boot/dts/ls1021a-iot.dts
arch/arm/boot/dts/ls1021a.dtsi
arch/arm/boot/dts/meson.dtsi
arch/arm/boot/dts/meson8.dtsi
arch/arm/boot/dts/meson8b.dtsi
arch/arm/boot/dts/mt2701.dtsi
arch/arm/boot/dts/mt7623.dtsi
arch/arm/boot/dts/mt7623a-rfb-emmc.dts
arch/arm/boot/dts/mt7623a-rfb-nand.dts
arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts
arch/arm/boot/dts/mt7623n-rfb-emmc.dts
arch/arm/boot/dts/mt7629-rfb.dts
arch/arm/boot/dts/nuvoton-common-npcm7xx.dtsi
arch/arm/boot/dts/nuvoton-npcm750.dtsi
arch/arm/boot/dts/omap2420-h4.dts
arch/arm/boot/dts/omap3-evm-37xx.dts
arch/arm/boot/dts/omap3-evm.dts
arch/arm/boot/dts/omap3-gta04.dtsi
arch/arm/boot/dts/omap3-igep.dtsi
arch/arm/boot/dts/omap3-ldp.dts
arch/arm/boot/dts/omap3-lilly-a83x.dtsi
arch/arm/boot/dts/omap3-n900.dts
arch/arm/boot/dts/omap3-n950-n9.dtsi
arch/arm/boot/dts/omap3-overo-base.dtsi
arch/arm/boot/dts/omap3-pandora-common.dtsi
arch/arm/boot/dts/omap3430-sdp.dts
arch/arm/boot/dts/omap5-l4.dtsi
arch/arm/boot/dts/pxa300-raumfeld-common.dtsi
arch/arm/boot/dts/qcom-apq8060-dragonboard.dts
arch/arm/boot/dts/qcom-apq8064-asus-nexus7-flo.dts
arch/arm/boot/dts/qcom-apq8064-cm-qs600.dts
arch/arm/boot/dts/qcom-apq8064-ifc6410.dts
arch/arm/boot/dts/qcom-apq8064-sony-xperia-lagan-yuga.dts
arch/arm/boot/dts/qcom-apq8064.dtsi
arch/arm/boot/dts/qcom-apq8084.dtsi
arch/arm/boot/dts/qcom-ipq4018-ap120c-ac-bit.dts
arch/arm/boot/dts/qcom-ipq4018-ap120c-ac.dts
arch/arm/boot/dts/qcom-ipq4018-ap120c-ac.dtsi
arch/arm/boot/dts/qcom-ipq4019-ap.dk04.1.dtsi
arch/arm/boot/dts/qcom-ipq4019-ap.dk07.1-c1.dts
arch/arm/boot/dts/qcom-ipq4019.dtsi
arch/arm/boot/dts/qcom-ipq8064-ap148.dts
arch/arm/boot/dts/qcom-ipq8064-rb3011.dts
arch/arm/boot/dts/qcom-ipq8064-smb208.dtsi [new file with mode: 0644]
arch/arm/boot/dts/qcom-ipq8064-v1.0.dtsi
arch/arm/boot/dts/qcom-ipq8064.dtsi
arch/arm/boot/dts/qcom-mdm9615-wp8548.dtsi
arch/arm/boot/dts/qcom-mdm9615.dtsi
arch/arm/boot/dts/qcom-msm8226.dtsi
arch/arm/boot/dts/qcom-msm8660.dtsi
arch/arm/boot/dts/qcom-msm8960.dtsi
arch/arm/boot/dts/qcom-msm8974-lge-nexus5-hammerhead.dts
arch/arm/boot/dts/qcom-msm8974-sony-xperia-rhine.dtsi
arch/arm/boot/dts/qcom-msm8974.dtsi
arch/arm/boot/dts/qcom-msm8974pro-fairphone-fp2.dts
arch/arm/boot/dts/qcom-msm8974pro-samsung-klte.dts
arch/arm/boot/dts/qcom-msm8974pro-sony-xperia-shinano-castor.dts
arch/arm/boot/dts/qcom-pm8841.dtsi
arch/arm/boot/dts/qcom-pm8941.dtsi
arch/arm/boot/dts/qcom-pmx55.dtsi
arch/arm/boot/dts/qcom-pmx65.dtsi
arch/arm/boot/dts/qcom-sdx55.dtsi
arch/arm/boot/dts/qcom-sdx65-mtp.dts
arch/arm/boot/dts/qcom-sdx65.dtsi
arch/arm/boot/dts/r7s9210-rza2mevb.dts
arch/arm/boot/dts/r8a7790-lager.dts
arch/arm/boot/dts/r8a7790-stout.dts
arch/arm/boot/dts/r8a7791-koelsch.dts
arch/arm/boot/dts/r8a7791-porter.dts
arch/arm/boot/dts/r8a7792-blanche.dts
arch/arm/boot/dts/r8a7793-gose.dts
arch/arm/boot/dts/r8a7794-alt.dts
arch/arm/boot/dts/r8a7794-silk.dts
arch/arm/boot/dts/r8a77xx-aa104xd12-panel.dtsi [deleted file]
arch/arm/boot/dts/r9a06g032-rzn1d400-db.dts
arch/arm/boot/dts/r9a06g032.dtsi
arch/arm/boot/dts/rk3066a-bqcurie2.dts
arch/arm/boot/dts/rk3066a-mk808.dts
arch/arm/boot/dts/rk3066a-rayeager.dts
arch/arm/boot/dts/rk3188-bqedison2qc.dts
arch/arm/boot/dts/rk3188-px3-evb.dts
arch/arm/boot/dts/rk3188-radxarock.dts
arch/arm/boot/dts/rk3229-evb.dts
arch/arm/boot/dts/rk3288-evb.dtsi
arch/arm/boot/dts/rk3288-firefly-reload.dts
arch/arm/boot/dts/rk3288-firefly.dtsi
arch/arm/boot/dts/rk3288-phycore-rdk.dts
arch/arm/boot/dts/rk3288-popmetal.dts
arch/arm/boot/dts/rk3288-r89.dts
arch/arm/boot/dts/rk3288-rock2-square.dts
arch/arm/boot/dts/rk3288-tinker.dtsi
arch/arm/boot/dts/rk3288-veyron-broadcom-bluetooth.dtsi
arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi
arch/arm/boot/dts/rk3288-veyron-minnie.dts
arch/arm/boot/dts/rk3288-veyron-pinky.dts
arch/arm/boot/dts/rk3288-veyron.dtsi
arch/arm/boot/dts/rv1108-elgin-r1.dts
arch/arm/boot/dts/rv1108-evb.dts
arch/arm/boot/dts/rv1108.dtsi
arch/arm/boot/dts/s3c2410-pinctrl.h [new file with mode: 0644]
arch/arm/boot/dts/s3c2416-pinctrl.dtsi
arch/arm/boot/dts/s3c2416.dtsi
arch/arm/boot/dts/s3c64xx-pinctrl.dtsi
arch/arm/boot/dts/s3c64xx-pinctrl.h [new file with mode: 0644]
arch/arm/boot/dts/s3c64xx.dtsi
arch/arm/boot/dts/s5pv210-aquila.dts
arch/arm/boot/dts/s5pv210-aries.dtsi
arch/arm/boot/dts/s5pv210-fascinate4g.dts
arch/arm/boot/dts/s5pv210-galaxys.dts
arch/arm/boot/dts/s5pv210-pinctrl.dtsi
arch/arm/boot/dts/s5pv210-pinctrl.h [new file with mode: 0644]
arch/arm/boot/dts/s5pv210.dtsi
arch/arm/boot/dts/sam9x60.dtsi
arch/arm/boot/dts/sama5d2.dtsi
arch/arm/boot/dts/sama5d3.dtsi
arch/arm/boot/dts/sama5d4.dtsi
arch/arm/boot/dts/sama7g5.dtsi
arch/arm/boot/dts/sd5203.dts
arch/arm/boot/dts/socfpga_arria10.dtsi
arch/arm/boot/dts/socfpga_arria10_chameleonv3.dts [new file with mode: 0644]
arch/arm/boot/dts/socfpga_arria10_mercury_aa1.dtsi [moved from arch/arm/boot/dts/socfpga_arria10_mercury_aa1.dts with 70% similarity]
arch/arm/boot/dts/spear1310-evb.dts
arch/arm/boot/dts/spear1340-evb.dts
arch/arm/boot/dts/spear1340.dtsi
arch/arm/boot/dts/spear300-evb.dts
arch/arm/boot/dts/spear310-evb.dts
arch/arm/boot/dts/spear320-evb.dts
arch/arm/boot/dts/spear320-hmi.dts
arch/arm/boot/dts/spear320.dtsi
arch/arm/boot/dts/ste-ab8500.dtsi
arch/arm/boot/dts/ste-dbx5x0.dtsi
arch/arm/boot/dts/ste-hrefv60plus.dtsi
arch/arm/boot/dts/ste-ux500-samsung-codina.dts
arch/arm/boot/dts/ste-ux500-samsung-gavini.dts
arch/arm/boot/dts/ste-ux500-samsung-janice.dts
arch/arm/boot/dts/stih407-family.dtsi
arch/arm/boot/dts/stih407.dtsi
arch/arm/boot/dts/stih410.dtsi
arch/arm/boot/dts/stihxxx-b2120.dtsi
arch/arm/boot/dts/stm32429i-eval.dts
arch/arm/boot/dts/stm32h743.dtsi
arch/arm/boot/dts/stm32h743i-disco.dts
arch/arm/boot/dts/stm32h743i-eval.dts
arch/arm/boot/dts/stm32h750i-art-pi.dts
arch/arm/boot/dts/stm32mp131.dtsi
arch/arm/boot/dts/stm32mp133.dtsi
arch/arm/boot/dts/stm32mp135f-dk.dts
arch/arm/boot/dts/stm32mp13xc.dtsi
arch/arm/boot/dts/stm32mp13xf.dtsi
arch/arm/boot/dts/stm32mp15-pinctrl.dtsi
arch/arm/boot/dts/stm32mp15-scmi.dtsi [new file with mode: 0644]
arch/arm/boot/dts/stm32mp151.dtsi
arch/arm/boot/dts/stm32mp153c-dhcor-drc-compact.dts [new file with mode: 0644]
arch/arm/boot/dts/stm32mp157a-dk1-scmi.dts
arch/arm/boot/dts/stm32mp157c-dk2-scmi.dts
arch/arm/boot/dts/stm32mp157c-ed1-scmi.dts
arch/arm/boot/dts/stm32mp157c-ev1-scmi.dts
arch/arm/boot/dts/stm32mp15xx-dhcor-avenger96.dtsi
arch/arm/boot/dts/stm32mp15xx-dhcor-drc-compact.dtsi [new file with mode: 0644]
arch/arm/boot/dts/stm32mp15xx-dhcor-io1v8.dtsi
arch/arm/boot/dts/stm32mp15xx-dhcor-som.dtsi
arch/arm/boot/dts/stm32mp15xx-osd32.dtsi
arch/arm/boot/dts/sun4i-a10-inet9f-rev03.dts
arch/arm/boot/dts/sun4i-a10-pcduino.dts
arch/arm/boot/dts/sun5i-a13-licheepi-one.dts
arch/arm/boot/dts/sun6i-a31.dtsi
arch/arm/boot/dts/sun7i-a20-pcduino3.dts
arch/arm/boot/dts/sun8i-a23-a33.dtsi
arch/arm/boot/dts/sun8i-h2-plus-bananapi-m2-zero.dts
arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts
arch/arm/boot/dts/sun8i-h3-beelink-x2.dts
arch/arm/boot/dts/sun8i-h3-mapleboard-mp130.dts
arch/arm/boot/dts/sun8i-h3-nanopi-duo2.dts
arch/arm/boot/dts/sun8i-h3-nanopi-neo-air.dts
arch/arm/boot/dts/sun8i-h3-nanopi-r1.dts
arch/arm/boot/dts/sun8i-h3-nanopi.dtsi
arch/arm/boot/dts/sun8i-h3-orangepi-2.dts
arch/arm/boot/dts/sun8i-h3-orangepi-lite.dts
arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dts
arch/arm/boot/dts/sun8i-r40-cpu-opp.dtsi [new file with mode: 0644]
arch/arm/boot/dts/sun8i-r40-feta40i.dtsi
arch/arm/boot/dts/sun8i-r40.dtsi
arch/arm/boot/dts/sun8i-t3-cqa3t-bv3.dts
arch/arm/boot/dts/sun8i-v3s.dtsi
arch/arm/boot/dts/sun8i-v40-bananapi-m2-berry.dts
arch/arm/boot/dts/sunplus-sp7021-achip.dtsi [new file with mode: 0644]
arch/arm/boot/dts/sunplus-sp7021-demo-v3.dts [new file with mode: 0644]
arch/arm/boot/dts/sunplus-sp7021.dtsi [new file with mode: 0644]
arch/arm/boot/dts/sunxi-bananapi-m2-plus.dtsi
arch/arm/boot/dts/sunxi-h3-h5-emlid-neutis.dtsi
arch/arm/boot/dts/sunxi-h3-h5.dtsi
arch/arm/boot/dts/sunxi-libretech-all-h3-cc.dtsi
arch/arm/boot/dts/tegra114-asus-tf701t.dts
arch/arm/boot/dts/tegra114-dalmore.dts
arch/arm/boot/dts/tegra114-roth.dts
arch/arm/boot/dts/tegra114-tn7.dts
arch/arm/boot/dts/tegra124-apalis-eval.dts
arch/arm/boot/dts/tegra124-apalis-v1.2-eval.dts
arch/arm/boot/dts/tegra124-jetson-tk1.dts
arch/arm/boot/dts/tegra124-nyan.dtsi
arch/arm/boot/dts/tegra124-venice2.dts
arch/arm/boot/dts/tegra20-acer-a500-picasso.dts
arch/arm/boot/dts/tegra20-asus-tf101.dts
arch/arm/boot/dts/tegra20-colibri-eval-v3.dts
arch/arm/boot/dts/tegra20-colibri-iris.dts
arch/arm/boot/dts/tegra20-harmony.dts
arch/arm/boot/dts/tegra20-paz00.dts
arch/arm/boot/dts/tegra20-seaboard.dts
arch/arm/boot/dts/tegra20-trimslice.dts
arch/arm/boot/dts/tegra20-ventana.dts
arch/arm/boot/dts/tegra30-apalis-eval.dts
arch/arm/boot/dts/tegra30-apalis-v1.1-eval.dts
arch/arm/boot/dts/tegra30-asus-nexus7-grouper-common.dtsi
arch/arm/boot/dts/tegra30-asus-nexus7-tilapia.dtsi
arch/arm/boot/dts/tegra30-asus-transformer-common.dtsi
arch/arm/boot/dts/tegra30-cardhu.dtsi
arch/arm/boot/dts/tegra30-colibri-eval-v3.dts
arch/arm/boot/dts/tegra30-colibri.dtsi
arch/arm/boot/dts/tegra30-ouya.dts
arch/arm/boot/dts/tegra30-pegatron-chagall.dts
arch/arm/boot/dts/zynq-zc702.dts
arch/arm/boot/dts/zynq-zturn-common.dtsi
arch/arm/configs/am200epdkit_defconfig
arch/arm/configs/aspeed_g4_defconfig
arch/arm/configs/aspeed_g5_defconfig
arch/arm/configs/assabet_defconfig
arch/arm/configs/at91_dt_defconfig
arch/arm/configs/axm55xx_defconfig
arch/arm/configs/badge4_defconfig
arch/arm/configs/bcm2835_defconfig
arch/arm/configs/cerfcube_defconfig
arch/arm/configs/clps711x_defconfig
arch/arm/configs/cm_x300_defconfig
arch/arm/configs/cns3420vb_defconfig
arch/arm/configs/colibri_pxa270_defconfig
arch/arm/configs/colibri_pxa300_defconfig
arch/arm/configs/collie_defconfig
arch/arm/configs/corgi_defconfig
arch/arm/configs/davinci_all_defconfig
arch/arm/configs/dove_defconfig
arch/arm/configs/ep93xx_defconfig
arch/arm/configs/eseries_pxa_defconfig
arch/arm/configs/exynos_defconfig
arch/arm/configs/ezx_defconfig
arch/arm/configs/footbridge_defconfig
arch/arm/configs/h3600_defconfig
arch/arm/configs/h5000_defconfig
arch/arm/configs/hackkit_defconfig
arch/arm/configs/hisi_defconfig
arch/arm/configs/imx_v4_v5_defconfig
arch/arm/configs/imx_v6_v7_defconfig
arch/arm/configs/integrator_defconfig
arch/arm/configs/iop32x_defconfig
arch/arm/configs/ixp4xx_defconfig
arch/arm/configs/jornada720_defconfig
arch/arm/configs/keystone_defconfig
arch/arm/configs/lart_defconfig
arch/arm/configs/lpc18xx_defconfig
arch/arm/configs/lpc32xx_defconfig
arch/arm/configs/lpd270_defconfig
arch/arm/configs/lubbock_defconfig
arch/arm/configs/magician_defconfig
arch/arm/configs/mainstone_defconfig
arch/arm/configs/milbeaut_m10v_defconfig
arch/arm/configs/mini2440_defconfig
arch/arm/configs/mmp2_defconfig
arch/arm/configs/moxart_defconfig
arch/arm/configs/mps2_defconfig
arch/arm/configs/multi_v4t_defconfig
arch/arm/configs/multi_v5_defconfig
arch/arm/configs/multi_v7_defconfig
arch/arm/configs/mv78xx0_defconfig
arch/arm/configs/mvebu_v5_defconfig
arch/arm/configs/mvebu_v7_defconfig
arch/arm/configs/mxs_defconfig
arch/arm/configs/neponset_defconfig
arch/arm/configs/netwinder_defconfig
arch/arm/configs/nhk8815_defconfig
arch/arm/configs/omap1_defconfig
arch/arm/configs/omap2plus_defconfig
arch/arm/configs/orion5x_defconfig
arch/arm/configs/oxnas_v6_defconfig
arch/arm/configs/palmz72_defconfig
arch/arm/configs/pcm027_defconfig
arch/arm/configs/pleb_defconfig
arch/arm/configs/pxa168_defconfig
arch/arm/configs/pxa255-idp_defconfig
arch/arm/configs/pxa3xx_defconfig
arch/arm/configs/pxa910_defconfig
arch/arm/configs/pxa_defconfig
arch/arm/configs/qcom_defconfig
arch/arm/configs/realview_defconfig
arch/arm/configs/rpc_defconfig
arch/arm/configs/s3c2410_defconfig
arch/arm/configs/s3c6400_defconfig
arch/arm/configs/s5pv210_defconfig
arch/arm/configs/sama5_defconfig
arch/arm/configs/sama7_defconfig
arch/arm/configs/shannon_defconfig
arch/arm/configs/shmobile_defconfig
arch/arm/configs/simpad_defconfig
arch/arm/configs/socfpga_defconfig
arch/arm/configs/sp7021_defconfig [new file with mode: 0644]
arch/arm/configs/spear13xx_defconfig
arch/arm/configs/spear3xx_defconfig
arch/arm/configs/spear6xx_defconfig
arch/arm/configs/spitz_defconfig
arch/arm/configs/stm32_defconfig
arch/arm/configs/sunxi_defconfig
arch/arm/configs/tct_hammer_defconfig
arch/arm/configs/tegra_defconfig
arch/arm/configs/trizeps4_defconfig
arch/arm/configs/u8500_defconfig
arch/arm/configs/versatile_defconfig
arch/arm/configs/vexpress_defconfig
arch/arm/configs/vf610m4_defconfig
arch/arm/configs/viper_defconfig
arch/arm/configs/vt8500_v6_v7_defconfig
arch/arm/configs/xcep_defconfig
arch/arm/configs/zeus_defconfig
arch/arm/crypto/Kconfig
arch/arm/crypto/Makefile
arch/arm/crypto/blake2s-shash.c [deleted file]
arch/arm/include/asm/archrandom.h
arch/arm/include/asm/dma.h
arch/arm/include/asm/domain.h
arch/arm/include/asm/io.h
arch/arm/include/asm/mach/map.h
arch/arm/include/asm/ptrace.h
arch/arm/kernel/entry-common.S
arch/arm/kernel/entry-header.S
arch/arm/kernel/jump_label.c
arch/arm/lib/findbit.S
arch/arm/mach-at91/pm.c
arch/arm/mach-at91/sam_secure.c
arch/arm/mach-at91/sam_secure.h
arch/arm/mach-at91/sama5.c
arch/arm/mach-axxia/platsmp.c
arch/arm/mach-bcm/Kconfig
arch/arm/mach-bcm/Makefile
arch/arm/mach-bcm/bcm63xx.c [deleted file]
arch/arm/mach-bcm/bcm_kona_smc.c
arch/arm/mach-cns3xxx/Kconfig
arch/arm/mach-cns3xxx/core.c
arch/arm/mach-davinci/Kconfig
arch/arm/mach-davinci/Makefile
arch/arm/mach-davinci/board-dm644x-evm.c [deleted file]
arch/arm/mach-davinci/board-dm646x-evm.c [deleted file]
arch/arm/mach-davinci/board-neuros-osd2.c [deleted file]
arch/arm/mach-davinci/board-sffsdr.c [deleted file]
arch/arm/mach-davinci/dm644x.c [deleted file]
arch/arm/mach-davinci/dm646x.c [deleted file]
arch/arm/mach-dove/Kconfig
arch/arm/mach-dove/pcie.c
arch/arm/mach-ep93xx/Kconfig
arch/arm/mach-exynos/exynos.c
arch/arm/mach-footbridge/Kconfig
arch/arm/mach-hisi/Kconfig
arch/arm/mach-imx/Kconfig
arch/arm/mach-imx/cpu-imx25.c
arch/arm/mach-imx/cpuidle-imx6q.c
arch/arm/mach-iop32x/Kconfig
arch/arm/mach-meson/platsmp.c
arch/arm/mach-mmp/Kconfig
arch/arm/mach-mmp/mmp2.h
arch/arm/mach-mmp/pxa168.h
arch/arm/mach-mmp/pxa910.h
arch/arm/mach-mv78xx0/Kconfig
arch/arm/mach-mv78xx0/pcie.c
arch/arm/mach-omap1/Kconfig
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/display.c
arch/arm/mach-omap2/pdata-quirks.c
arch/arm/mach-omap2/prm3xxx.c
arch/arm/mach-orion5x/Kconfig
arch/arm/mach-orion5x/pci.c
arch/arm/mach-pxa/Kconfig
arch/arm/mach-pxa/corgi.c
arch/arm/mach-pxa/hx4700.c
arch/arm/mach-pxa/icontrol.c
arch/arm/mach-pxa/littleton.c
arch/arm/mach-pxa/magician.c
arch/arm/mach-pxa/spitz.c
arch/arm/mach-pxa/z2.c
arch/arm/mach-qcom/Kconfig
arch/arm/mach-qcom/platsmp.c
arch/arm/mach-rockchip/pm.c
arch/arm/mach-s3c/Kconfig
arch/arm/mach-s3c/Kconfig.s3c24xx
arch/arm/mach-s3c/Kconfig.s3c64xx
arch/arm/mach-s3c/mach-mini2440.c
arch/arm/mach-sa1100/Kconfig
arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c
arch/arm/mach-spear/time.c
arch/arm/mach-sunplus/Kconfig [new file with mode: 0644]
arch/arm/mach-sunplus/Makefile [new file with mode: 0644]
arch/arm/mach-sunplus/sp7021.c [new file with mode: 0644]
arch/arm/mach-zynq/common.c
arch/arm/mm/Kconfig
arch/arm/mm/alignment.c
arch/arm/mm/ioremap.c
arch/arm/mm/mmu.c
arch/arm/mm/nommu.c
arch/arm/mm/proc-v7-bugs.c
arch/arm/probes/decode.h
arch/arm/xen/p2m.c
arch/arm64/Kconfig
arch/arm64/Kconfig.platforms
arch/arm64/boot/Makefile
arch/arm64/boot/dts/Makefile
arch/arm64/boot/dts/allwinner/Makefile
arch/arm64/boot/dts/allwinner/sun50i-a100.dtsi
arch/arm64/boot/dts/allwinner/sun50i-a64-amarula-relic.dts
arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts
arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts
arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts
arch/arm64/boot/dts/allwinner/sun50i-a64-pinebook.dts
arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.0.dts
arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts
arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-r1s-h5.dts
arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts
arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-prime.dts
arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts
arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-lite2.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-orangepi-zero2.dts [new file with mode: 0644]
arch/arm64/boot/dts/allwinner/sun50i-h616-x96-mate.dts [new file with mode: 0644]
arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/altera/Makefile
arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi
arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts
arch/arm64/boot/dts/altera/socfpga_stratix10_socdk_nand.dts
arch/arm64/boot/dts/altera/socfpga_stratix10_swvp.dts [new file with mode: 0644]
arch/arm64/boot/dts/amd/amd-overdrive-rev-b0.dts
arch/arm64/boot/dts/amd/amd-overdrive-rev-b1.dts
arch/arm64/boot/dts/amlogic/meson-axg.dtsi
arch/arm64/boot/dts/amlogic/meson-g12b-gsking-x.dts
arch/arm64/boot/dts/amlogic/meson-g12b-gtking-pro.dts
arch/arm64/boot/dts/amlogic/meson-gx.dtsi
arch/arm64/boot/dts/amlogic/meson-gxbb-kii-pro.dts
arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-play2.dts
arch/arm64/boot/dts/amlogic/meson-gxl-s905d-mecool-kii-pro.dts
arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
arch/arm64/boot/dts/amlogic/meson-gxl-s905d-vero4k-plus.dts
arch/arm64/boot/dts/amlogic/meson-gxl-s905w-jethome-jethub-j80.dts
arch/arm64/boot/dts/amlogic/meson-gxm-mecool-kiii-pro.dts
arch/arm64/boot/dts/amlogic/meson-gxm-minix-neo-u9h.dts
arch/arm64/boot/dts/amlogic/meson-gxm-q200.dts
arch/arm64/boot/dts/amlogic/meson-gxm-wetek-core2.dts
arch/arm64/boot/dts/amlogic/meson-s4.dtsi
arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts
arch/arm64/boot/dts/apm/apm-merlin.dts
arch/arm64/boot/dts/apm/apm-mustang.dts
arch/arm64/boot/dts/apm/apm-shadowcat.dtsi
arch/arm64/boot/dts/apm/apm-storm.dtsi
arch/arm64/boot/dts/arm/fvp-base-revc.dts
arch/arm64/boot/dts/arm/juno-base.dtsi
arch/arm64/boot/dts/arm/juno-cs-r1r2.dtsi
arch/arm64/boot/dts/arm/juno-r1.dts
arch/arm64/boot/dts/arm/juno-r2.dts
arch/arm64/boot/dts/arm/juno-scmi.dtsi
arch/arm64/boot/dts/arm/juno.dts
arch/arm64/boot/dts/broadcom/Makefile
arch/arm64/boot/dts/broadcom/bcm4908/bcm4906-tplink-archer-c2300-v1.dts
arch/arm64/boot/dts/broadcom/bcm4908/bcm4906.dtsi
arch/arm64/boot/dts/broadcom/bcm4908/bcm4908-asus-gt-ac5300.dts
arch/arm64/boot/dts/broadcom/bcm4908/bcm4908.dtsi
arch/arm64/boot/dts/broadcom/bcmbca/Makefile [new file with mode: 0644]
arch/arm64/boot/dts/broadcom/bcmbca/bcm4912-asus-gt-ax6000.dts [new file with mode: 0644]
arch/arm64/boot/dts/broadcom/bcmbca/bcm4912.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/broadcom/bcmbca/bcm63146.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/broadcom/bcmbca/bcm63158.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/broadcom/bcmbca/bcm6813.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/broadcom/bcmbca/bcm6856.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/broadcom/bcmbca/bcm6858.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/broadcom/bcmbca/bcm94912.dts [new file with mode: 0644]
arch/arm64/boot/dts/broadcom/bcmbca/bcm963146.dts [new file with mode: 0644]
arch/arm64/boot/dts/broadcom/bcmbca/bcm963158.dts [new file with mode: 0644]
arch/arm64/boot/dts/broadcom/bcmbca/bcm96813.dts [new file with mode: 0644]
arch/arm64/boot/dts/broadcom/bcmbca/bcm96856.dts [new file with mode: 0644]
arch/arm64/boot/dts/broadcom/bcmbca/bcm96858.dts [new file with mode: 0644]
arch/arm64/boot/dts/broadcom/stingray/stingray.dtsi
arch/arm64/boot/dts/exynos/exynos-pinctrl.h [new file with mode: 0644]
arch/arm64/boot/dts/exynos/exynos5433-pinctrl.dtsi
arch/arm64/boot/dts/exynos/exynos5433.dtsi
arch/arm64/boot/dts/exynos/exynos7-espresso.dts
arch/arm64/boot/dts/exynos/exynos7-pinctrl.dtsi
arch/arm64/boot/dts/exynos/exynos7885-jackpotlte.dts
arch/arm64/boot/dts/exynos/exynos7885-pinctrl.dtsi
arch/arm64/boot/dts/exynos/exynos7885.dtsi
arch/arm64/boot/dts/exynos/exynos850-pinctrl.dtsi
arch/arm64/boot/dts/exynos/exynosautov9-pinctrl.dtsi
arch/arm64/boot/dts/exynos/exynosautov9-sadk.dts
arch/arm64/boot/dts/exynos/exynosautov9.dtsi
arch/arm64/boot/dts/freescale/Makefile
arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts
arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
arch/arm64/boot/dts/freescale/fsl-ls1028a-qds.dts
arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
arch/arm64/boot/dts/freescale/fsl-ls1088a-ten64.dts
arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
arch/arm64/boot/dts/freescale/fsl-lx2160a-qds.dts
arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
arch/arm64/boot/dts/freescale/fsl-lx2162a-qds.dts
arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi
arch/arm64/boot/dts/freescale/imx8mm-beacon-baseboard.dtsi
arch/arm64/boot/dts/freescale/imx8mm-evk.dtsi
arch/arm64/boot/dts/freescale/imx8mm-icore-mx8mm.dtsi
arch/arm64/boot/dts/freescale/imx8mm-mx8menlo.dts
arch/arm64/boot/dts/freescale/imx8mm-phyboard-polis-rdk.dts [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8mm-phycore-som.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8mm-var-som-symphony.dts
arch/arm64/boot/dts/freescale/imx8mm-venice-gw700x.dtsi
arch/arm64/boot/dts/freescale/imx8mm-venice-gw7901.dts
arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts
arch/arm64/boot/dts/freescale/imx8mm-venice-gw7903.dts
arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi
arch/arm64/boot/dts/freescale/imx8mm.dtsi
arch/arm64/boot/dts/freescale/imx8mn-beacon-baseboard.dtsi
arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi
arch/arm64/boot/dts/freescale/imx8mn-var-som-symphony.dts
arch/arm64/boot/dts/freescale/imx8mn-venice-gw7902.dts
arch/arm64/boot/dts/freescale/imx8mn.dtsi
arch/arm64/boot/dts/freescale/imx8mp-dhcom-pdk2.dts [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8mp-evk.dts
arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp-edimm2.2.dts
arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts
arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts
arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi
arch/arm64/boot/dts/freescale/imx8mp.dtsi
arch/arm64/boot/dts/freescale/imx8mq-evk.dts
arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts
arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi
arch/arm64/boot/dts/freescale/imx8mq-nitrogen.dts
arch/arm64/boot/dts/freescale/imx8mq-zii-ultra.dtsi
arch/arm64/boot/dts/freescale/imx8mq.dtsi
arch/arm64/boot/dts/freescale/imx8qm.dtsi
arch/arm64/boot/dts/freescale/imx8qxp-colibri-eval-v3.dtsi
arch/arm64/boot/dts/freescale/imx8qxp.dtsi
arch/arm64/boot/dts/freescale/imx8ulp.dtsi
arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts [new file with mode: 0644]
arch/arm64/boot/dts/freescale/imx93-pinfunc.h [new file with mode: 0755]
arch/arm64/boot/dts/freescale/imx93.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/freescale/mba8mx.dtsi
arch/arm64/boot/dts/freescale/s32g2.dtsi
arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dts
arch/arm64/boot/dts/hisilicon/hi3660.dtsi
arch/arm64/boot/dts/hisilicon/hi3670.dtsi
arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
arch/arm64/boot/dts/hisilicon/hip05-d02.dts
arch/arm64/boot/dts/hisilicon/hip06.dtsi
arch/arm64/boot/dts/hisilicon/hip07.dtsi
arch/arm64/boot/dts/intel/socfpga_agilex.dtsi
arch/arm64/boot/dts/lg/lg1312.dtsi
arch/arm64/boot/dts/lg/lg1313.dtsi
arch/arm64/boot/dts/marvell/Makefile
arch/arm64/boot/dts/marvell/ac5-98dx25xx.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/marvell/ac5-98dx35xx-rd.dts [new file with mode: 0644]
arch/arm64/boot/dts/marvell/ac5-98dx35xx.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts
arch/arm64/boot/dts/marvell/armada-7040-mochabin.dts
arch/arm64/boot/dts/marvell/armada-8040-clearfog-gt-8k.dts
arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtsi
arch/arm64/boot/dts/marvell/armada-8040-puzzle-m801.dts
arch/arm64/boot/dts/marvell/cn9130-db.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/mt6795.dtsi
arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
arch/arm64/boot/dts/mediatek/mt7622.dtsi
arch/arm64/boot/dts/mediatek/mt7986a.dtsi
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-evb.dts
arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi.dtsi
arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.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/mt8192-asurada-hayato-r1.dts [new file with mode: 0644]
arch/arm64/boot/dts/mediatek/mt8192-asurada-spherion-r0.dts [new file with mode: 0644]
arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/mediatek/mt8192.dtsi
arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r1.dts [new file with mode: 0644]
arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r2.dts [new file with mode: 0644]
arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r3.dts [new file with mode: 0644]
arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/mediatek/mt8195-evb.dts
arch/arm64/boot/dts/mediatek/mt8195.dtsi
arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi
arch/arm64/boot/dts/microchip/sparx5_pcb134_board.dtsi
arch/arm64/boot/dts/microchip/sparx5_pcb135_board.dtsi
arch/arm64/boot/dts/nuvoton/Makefile [new file with mode: 0644]
arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/nuvoton/nuvoton-npcm845-evb.dts [new file with mode: 0644]
arch/arm64/boot/dts/nuvoton/nuvoton-npcm845.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/nvidia/tegra132-norrin.dts
arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts
arch/arm64/boot/dts/nvidia/tegra186-p3509-0000+p3636-0001.dts
arch/arm64/boot/dts/nvidia/tegra186.dtsi
arch/arm64/boot/dts/nvidia/tegra194-p2888.dtsi
arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts
arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi
arch/arm64/boot/dts/nvidia/tegra194.dtsi
arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi
arch/arm64/boot/dts/nvidia/tegra210-p2894.dtsi
arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
arch/arm64/boot/dts/nvidia/tegra210-smaug.dts
arch/arm64/boot/dts/nvidia/tegra210.dtsi
arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dts
arch/arm64/boot/dts/nvidia/tegra234.dtsi
arch/arm64/boot/dts/qcom/Makefile
arch/arm64/boot/dts/qcom/apq8016-sbc.dts
arch/arm64/boot/dts/qcom/apq8096-db820c.dts
arch/arm64/boot/dts/qcom/ipq6018-cp01-c1.dts
arch/arm64/boot/dts/qcom/ipq6018.dtsi
arch/arm64/boot/dts/qcom/ipq8074-hk01.dts
arch/arm64/boot/dts/qcom/ipq8074-hk10.dtsi
arch/arm64/boot/dts/qcom/ipq8074.dtsi
arch/arm64/boot/dts/qcom/msm8916-alcatel-idol347.dts
arch/arm64/boot/dts/qcom/msm8916-asus-z00l.dts
arch/arm64/boot/dts/qcom/msm8916-huawei-g7.dts
arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts
arch/arm64/boot/dts/qcom/msm8916-longcheer-l8910.dts
arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi
arch/arm64/boot/dts/qcom/msm8916-samsung-a3u-eur.dts
arch/arm64/boot/dts/qcom/msm8916-samsung-a5u-eur.dts
arch/arm64/boot/dts/qcom/msm8916-samsung-j5.dts
arch/arm64/boot/dts/qcom/msm8916-samsung-serranove.dts
arch/arm64/boot/dts/qcom/msm8916-wingtech-wt88047.dts
arch/arm64/boot/dts/qcom/msm8916.dtsi
arch/arm64/boot/dts/qcom/msm8953.dtsi
arch/arm64/boot/dts/qcom/msm8992-lg-bullhead.dtsi
arch/arm64/boot/dts/qcom/msm8992-xiaomi-libra.dts
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-pmi8996-sony-xperia-tone-dora.dts [deleted file]
arch/arm64/boot/dts/qcom/msm8996-pmi8996-sony-xperia-tone-kagura.dts [deleted file]
arch/arm64/boot/dts/qcom/msm8996-pmi8996-sony-xperia-tone-keyaki.dts [deleted file]
arch/arm64/boot/dts/qcom/msm8996-sony-xperia-tone.dtsi
arch/arm64/boot/dts/qcom/msm8996-xiaomi-common.dtsi
arch/arm64/boot/dts/qcom/msm8996-xiaomi-gemini.dts
arch/arm64/boot/dts/qcom/msm8996-xiaomi-natrium.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/msm8996-xiaomi-scorpio.dts
arch/arm64/boot/dts/qcom/msm8996.dtsi
arch/arm64/boot/dts/qcom/msm8998-asus-novago-tp370ql.dts
arch/arm64/boot/dts/qcom/msm8998-clamshell.dtsi
arch/arm64/boot/dts/qcom/msm8998-fxtec-pro1.dts
arch/arm64/boot/dts/qcom/msm8998-hp-envy-x2.dts
arch/arm64/boot/dts/qcom/msm8998-lenovo-miix-630.dts
arch/arm64/boot/dts/qcom/msm8998-mtp.dts
arch/arm64/boot/dts/qcom/msm8998-mtp.dtsi [deleted file]
arch/arm64/boot/dts/qcom/msm8998-oneplus-cheeseburger.dts
arch/arm64/boot/dts/qcom/msm8998-oneplus-common.dtsi
arch/arm64/boot/dts/qcom/msm8998-sony-xperia-yoshino-lilac.dts
arch/arm64/boot/dts/qcom/msm8998-sony-xperia-yoshino-maple.dts
arch/arm64/boot/dts/qcom/msm8998-sony-xperia-yoshino-poplar.dts
arch/arm64/boot/dts/qcom/msm8998-sony-xperia-yoshino.dtsi
arch/arm64/boot/dts/qcom/msm8998.dtsi
arch/arm64/boot/dts/qcom/pm6350.dtsi
arch/arm64/boot/dts/qcom/pm660.dtsi
arch/arm64/boot/dts/qcom/pm660l.dtsi
arch/arm64/boot/dts/qcom/pm8005.dtsi
arch/arm64/boot/dts/qcom/pm8009.dtsi
arch/arm64/boot/dts/qcom/pm8150.dtsi
arch/arm64/boot/dts/qcom/pm8150b.dtsi
arch/arm64/boot/dts/qcom/pm8150l.dtsi
arch/arm64/boot/dts/qcom/pm8350.dtsi
arch/arm64/boot/dts/qcom/pm8350b.dtsi
arch/arm64/boot/dts/qcom/pm8916.dtsi
arch/arm64/boot/dts/qcom/pm8994.dtsi
arch/arm64/boot/dts/qcom/pmi8994.dtsi
arch/arm64/boot/dts/qcom/pmi8998.dtsi
arch/arm64/boot/dts/qcom/pmm8155au_1.dtsi
arch/arm64/boot/dts/qcom/pmm8155au_2.dtsi
arch/arm64/boot/dts/qcom/pmr735b.dtsi
arch/arm64/boot/dts/qcom/pms405.dtsi
arch/arm64/boot/dts/qcom/qcs404-evb.dtsi
arch/arm64/boot/dts/qcom/qcs404.dtsi
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts
arch/arm64/boot/dts/qcom/sa8295p-adp.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sa8540p.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc7180-idp.dts
arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz.dtsi
arch/arm64/boot/dts/qcom/sc7180-trogdor-homestar.dtsi
arch/arm64/boot/dts/qcom/sc7180-trogdor-kingoftown-r0.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc7180-trogdor-kingoftown-r1.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc7180-trogdor-kingoftown.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor.dtsi
arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland-rev0-auo.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland-rev0-boe.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland-rev0.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland-rev1-auo.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland-rev1-boe.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel-lte-parade.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel-lte-ti.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel-parade.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel-ti.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom.dtsi
arch/arm64/boot/dts/qcom/sc7180-trogdor-quackingstick-r0-lte.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc7180-trogdor-quackingstick-r0.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc7180-trogdor-quackingstick.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc7180-trogdor-r1.dts
arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev0-boe.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev0-inx.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev0.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev1-boe-rt5682s.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev1-boe.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev1-inx-rt5682s.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev1-inx.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler.dtsi [new file with mode: 0644]
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-audio-wcd9385.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc7280-herobrine-crd.dts
arch/arm64/boot/dts/qcom/sc7280-herobrine-herobrine-r1.dts
arch/arm64/boot/dts/qcom/sc7280-herobrine-villager-r0.dts
arch/arm64/boot/dts/qcom/sc7280-herobrine.dtsi
arch/arm64/boot/dts/qcom/sc7280-idp.dtsi
arch/arm64/boot/dts/qcom/sc7280-qcard.dtsi
arch/arm64/boot/dts/qcom/sc7280.dtsi
arch/arm64/boot/dts/qcom/sc8280xp-crd.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc8280xp-pmics.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sc8280xp.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sda660-inforce-ifc6560.dts [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-fairphone-fp3.dts
arch/arm64/boot/dts/qcom/sdm636-sony-xperia-ganges-mermaid.dts
arch/arm64/boot/dts/qcom/sdm660-xiaomi-lavender.dts
arch/arm64/boot/dts/qcom/sdm660.dtsi
arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi
arch/arm64/boot/dts/qcom/sdm845-db845c.dts
arch/arm64/boot/dts/qcom/sdm845-lg-common.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sdm845-lg-judyln.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sdm845-lg-judyp.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi
arch/arm64/boot/dts/qcom/sdm845-shift-axolotl.dts
arch/arm64/boot/dts/qcom/sdm845-sony-xperia-tama-akatsuki.dts
arch/arm64/boot/dts/qcom/sdm845-sony-xperia-tama.dtsi
arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts
arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sdm845.dtsi
arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts
arch/arm64/boot/dts/qcom/sdm850-samsung-w737.dts
arch/arm64/boot/dts/qcom/sdm850.dtsi
arch/arm64/boot/dts/qcom/sm6125-sony-xperia-seine-pdx201.dts
arch/arm64/boot/dts/qcom/sm6125.dtsi
arch/arm64/boot/dts/qcom/sm6350.dtsi
arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts
arch/arm64/boot/dts/qcom/sm8150-hdk.dts
arch/arm64/boot/dts/qcom/sm8150-microsoft-surface-duo.dts
arch/arm64/boot/dts/qcom/sm8150.dtsi
arch/arm64/boot/dts/qcom/sm8250-hdk.dts
arch/arm64/boot/dts/qcom/sm8250-sony-xperia-edo.dtsi
arch/arm64/boot/dts/qcom/sm8250.dtsi
arch/arm64/boot/dts/qcom/sm8350-microsoft-surface-duo2.dts
arch/arm64/boot/dts/qcom/sm8350-sony-xperia-sagami.dtsi
arch/arm64/boot/dts/qcom/sm8350.dtsi
arch/arm64/boot/dts/qcom/sm8450-hdk.dts
arch/arm64/boot/dts/qcom/sm8450-qrd.dts
arch/arm64/boot/dts/qcom/sm8450.dtsi
arch/arm64/boot/dts/renesas/Makefile
arch/arm64/boot/dts/renesas/beacon-renesom-baseboard.dtsi
arch/arm64/boot/dts/renesas/beacon-renesom-som.dtsi
arch/arm64/boot/dts/renesas/draak-ebisu-panel-aa104xd12.dts [new file with mode: 0644]
arch/arm64/boot/dts/renesas/draak.dtsi
arch/arm64/boot/dts/renesas/ebisu.dtsi
arch/arm64/boot/dts/renesas/hihope-common.dtsi
arch/arm64/boot/dts/renesas/panel-aa104xd12.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/renesas/r8a774c0.dtsi
arch/arm64/boot/dts/renesas/r8a77990.dtsi
arch/arm64/boot/dts/renesas/r8a779a0.dtsi
arch/arm64/boot/dts/renesas/r8a779f0-spider-cpu.dtsi
arch/arm64/boot/dts/renesas/r8a779f0-spider.dts
arch/arm64/boot/dts/renesas/r8a779f0.dtsi
arch/arm64/boot/dts/renesas/r8a779m8.dtsi
arch/arm64/boot/dts/renesas/r9a07g043.dtsi
arch/arm64/boot/dts/renesas/r9a07g043u11-smarc.dts
arch/arm64/boot/dts/renesas/r9a07g054l2-smarc.dts
arch/arm64/boot/dts/renesas/r9a09g011-v2mevk2.dts
arch/arm64/boot/dts/renesas/r9a09g011.dtsi
arch/arm64/boot/dts/renesas/rzg2l-smarc-som.dtsi
arch/arm64/boot/dts/renesas/rzg2lc-smarc-som.dtsi
arch/arm64/boot/dts/renesas/rzg2lc-smarc.dtsi
arch/arm64/boot/dts/renesas/rzg2ul-smarc-som.dtsi
arch/arm64/boot/dts/renesas/rzg2ul-smarc.dtsi
arch/arm64/boot/dts/renesas/salvator-common.dtsi
arch/arm64/boot/dts/renesas/salvator-panel-aa104xd12.dts [new file with mode: 0644]
arch/arm64/boot/dts/renesas/ulcb-kf.dtsi
arch/arm64/boot/dts/renesas/ulcb.dtsi
arch/arm64/boot/dts/rockchip/Makefile
arch/arm64/boot/dts/rockchip/px30.dtsi
arch/arm64/boot/dts/rockchip/rk3308-evb.dts
arch/arm64/boot/dts/rockchip/rk3308-rock-pi-s.dts [new file with mode: 0644]
arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts
arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dts
arch/arm64/boot/dts/rockchip/rk3368-evb.dtsi
arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts
arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts
arch/arm64/boot/dts/rockchip/rk3368-px5-evb.dts
arch/arm64/boot/dts/rockchip/rk3368-r88.dts
arch/arm64/boot/dts/rockchip/rk3368.dtsi
arch/arm64/boot/dts/rockchip/rk3399-evb.dts
arch/arm64/boot/dts/rockchip/rk3399-firefly.dts
arch/arm64/boot/dts/rockchip/rk3399-gru-chromebook.dtsi
arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi
arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi
arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dts
arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi
arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts
arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts
arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi
arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi
arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator.dts
arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi
arch/arm64/boot/dts/rockchip/rk3399.dtsi
arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi
arch/arm64/boot/dts/rockchip/rk3566-pinenote.dtsi
arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
arch/arm64/boot/dts/rockchip/rk3566-quartz64-b.dts
arch/arm64/boot/dts/rockchip/rk3566.dtsi
arch/arm64/boot/dts/rockchip/rk3568-bpi-r2-pro.dts
arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts
arch/arm64/boot/dts/rockchip/rk3568-rock-3a.dts
arch/arm64/boot/dts/rockchip/rk3568.dtsi
arch/arm64/boot/dts/rockchip/rk356x.dtsi
arch/arm64/boot/dts/sprd/sc9836.dtsi
arch/arm64/boot/dts/sprd/sc9863a.dtsi
arch/arm64/boot/dts/sprd/whale2.dtsi
arch/arm64/boot/dts/tesla/fsd-evb.dts
arch/arm64/boot/dts/tesla/fsd-pinctrl.dtsi
arch/arm64/boot/dts/tesla/fsd-pinctrl.h [new file with mode: 0644]
arch/arm64/boot/dts/tesla/fsd.dtsi
arch/arm64/boot/dts/ti/k3-am62-main.dtsi
arch/arm64/boot/dts/ti/k3-am625-sk.dts
arch/arm64/boot/dts/ti/k3-am64-main.dtsi
arch/arm64/boot/dts/ti/k3-am642-evm.dts
arch/arm64/boot/dts/ti/k3-am642-sk.dts
arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi
arch/arm64/boot/dts/ti/k3-am65-main.dtsi
arch/arm64/boot/dts/ti/k3-am65-wakeup.dtsi
arch/arm64/boot/dts/ti/k3-am654-base-board.dts
arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi
arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts
arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi
arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi
arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi
arch/arm64/boot/dts/xilinx/zynqmp-clk-ccf.dtsi
arch/arm64/boot/dts/xilinx/zynqmp-sm-k26-revA.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-zcu106-revA.dts
arch/arm64/boot/dts/xilinx/zynqmp-zcu111-revA.dts
arch/arm64/boot/dts/xilinx/zynqmp.dtsi
arch/arm64/configs/defconfig
arch/arm64/crypto/Kconfig
arch/arm64/crypto/Makefile
arch/arm64/crypto/aes-glue.c
arch/arm64/crypto/aes-modes.S
arch/arm64/crypto/aes-neon.S
arch/arm64/crypto/poly1305-glue.c
arch/arm64/crypto/polyval-ce-core.S [new file with mode: 0644]
arch/arm64/crypto/polyval-ce-glue.c [new file with mode: 0644]
arch/arm64/include/asm/archrandom.h
arch/arm64/include/asm/asm-extable.h
arch/arm64/include/asm/asm-uaccess.h
arch/arm64/include/asm/asm_pointer_auth.h
arch/arm64/include/asm/assembler.h
arch/arm64/include/asm/barrier.h
arch/arm64/include/asm/cache.h
arch/arm64/include/asm/cacheflush.h
arch/arm64/include/asm/cpu.h
arch/arm64/include/asm/cpu_ops.h
arch/arm64/include/asm/cpufeature.h
arch/arm64/include/asm/cpuidle.h
arch/arm64/include/asm/el2_setup.h
arch/arm64/include/asm/fixmap.h
arch/arm64/include/asm/hwcap.h
arch/arm64/include/asm/io.h
arch/arm64/include/asm/kernel-pgtable.h
arch/arm64/include/asm/kexec.h
arch/arm64/include/asm/memory.h
arch/arm64/include/asm/mmu_context.h
arch/arm64/include/asm/pgtable-hwdef.h
arch/arm64/include/asm/pgtable.h
arch/arm64/include/asm/processor.h
arch/arm64/include/asm/sysreg.h
arch/arm64/include/asm/uaccess.h
arch/arm64/include/asm/virt.h
arch/arm64/include/uapi/asm/hwcap.h
arch/arm64/kernel/Makefile
arch/arm64/kernel/acpi.c
arch/arm64/kernel/acpi_numa.c
arch/arm64/kernel/alternative.c
arch/arm64/kernel/armv8_deprecated.c
arch/arm64/kernel/cpu_errata.c
arch/arm64/kernel/cpufeature.c
arch/arm64/kernel/cpuidle.c
arch/arm64/kernel/cpuinfo.c
arch/arm64/kernel/entry-common.c
arch/arm64/kernel/entry.S
arch/arm64/kernel/fpsimd.c
arch/arm64/kernel/head.S
arch/arm64/kernel/hibernate.c
arch/arm64/kernel/hyp-stub.S
arch/arm64/kernel/idreg-override.c
arch/arm64/kernel/image-vars.h
arch/arm64/kernel/jump_label.c
arch/arm64/kernel/kaslr.c
arch/arm64/kernel/kexec_image.c
arch/arm64/kernel/kuser32.S
arch/arm64/kernel/mte.c
arch/arm64/kernel/pi/Makefile [new file with mode: 0644]
arch/arm64/kernel/pi/kaslr_early.c [new file with mode: 0644]
arch/arm64/kernel/signal.c
arch/arm64/kernel/sigreturn32.S
arch/arm64/kernel/sleep.S
arch/arm64/kernel/stacktrace.c
arch/arm64/kernel/suspend.c
arch/arm64/kernel/traps.c
arch/arm64/kernel/vdso/Makefile
arch/arm64/kernel/vdso/vdso.lds.S
arch/arm64/kernel/vdso32/Makefile
arch/arm64/kernel/vdso32/vdso.lds.S
arch/arm64/kernel/vmlinux.lds.S
arch/arm64/kvm/hyp/include/nvhe/fixed_config.h
arch/arm64/kvm/hyp/nvhe/sys_regs.c
arch/arm64/kvm/sys_regs.c
arch/arm64/lib/mte.S
arch/arm64/mm/cache.S
arch/arm64/mm/copypage.c
arch/arm64/mm/dma-mapping.c
arch/arm64/mm/extable.c
arch/arm64/mm/fault.c
arch/arm64/mm/hugetlbpage.c
arch/arm64/mm/init.c
arch/arm64/mm/ioremap.c
arch/arm64/mm/kasan_init.c
arch/arm64/mm/mmu.c
arch/arm64/mm/mteswap.c
arch/arm64/mm/proc.S
arch/arm64/tools/cpucaps
arch/arm64/tools/gen-sysreg.awk
arch/arm64/tools/sysreg
arch/csky/Kconfig
arch/csky/include/asm/tlb.h
arch/csky/kernel/entry.S
arch/ia64/kernel/iosapic.c
arch/ia64/kernel/irq.c
arch/ia64/kernel/msi_ia64.c
arch/loongarch/Kconfig
arch/loongarch/include/asm/acpi.h
arch/loongarch/include/asm/asmmacro.h
arch/loongarch/include/asm/atomic.h
arch/loongarch/include/asm/barrier.h
arch/loongarch/include/asm/cmpxchg.h
arch/loongarch/include/asm/compiler.h [deleted file]
arch/loongarch/include/asm/elf.h
arch/loongarch/include/asm/fpregdef.h
arch/loongarch/include/asm/futex.h
arch/loongarch/include/asm/irq.h
arch/loongarch/include/asm/irqflags.h
arch/loongarch/include/asm/local.h
arch/loongarch/include/asm/loongson.h
arch/loongarch/include/asm/page.h
arch/loongarch/include/asm/processor.h
arch/loongarch/include/asm/stacktrace.h
arch/loongarch/include/asm/thread_info.h
arch/loongarch/include/asm/tlb.h
arch/loongarch/include/asm/uaccess.h
arch/loongarch/kernel/acpi.c
arch/loongarch/kernel/asm-offsets.c
arch/loongarch/kernel/cacheinfo.c
arch/loongarch/kernel/entry.S
arch/loongarch/kernel/env.c
arch/loongarch/kernel/fpu.S
arch/loongarch/kernel/genex.S
arch/loongarch/kernel/head.S
arch/loongarch/kernel/irq.c
arch/loongarch/kernel/numa.c
arch/loongarch/kernel/ptrace.c
arch/loongarch/kernel/reset.c
arch/loongarch/kernel/setup.c
arch/loongarch/kernel/smp.c
arch/loongarch/kernel/switch.S
arch/loongarch/kernel/time.c
arch/loongarch/lib/clear_user.S
arch/loongarch/lib/copy_user.S
arch/loongarch/lib/delay.c
arch/loongarch/mm/page.S
arch/loongarch/mm/tlbex.S
arch/loongarch/vdso/Makefile
arch/m68k/Kconfig.cpu
arch/m68k/Kconfig.debug
arch/m68k/Kconfig.machine
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/bitops.h
arch/m68k/include/asm/processor.h
arch/m68k/include/uapi/asm/bootinfo-virt.h
arch/m68k/include/uapi/asm/bootinfo.h
arch/m68k/kernel/traps.c
arch/m68k/mac/iop.c
arch/m68k/mac/macints.c
arch/m68k/q40/README
arch/m68k/q40/q40ints.c
arch/m68k/sun3/mmu_emu.c
arch/m68k/virt/config.c
arch/m68k/virt/ints.c
arch/m68k/virt/platform.c
arch/mips/Kconfig
arch/mips/cavium-octeon/octeon-irq.c
arch/mips/include/asm/jump_label.h
arch/mips/include/asm/mach-loongson64/irq.h
arch/mips/include/uapi/asm/ucontext.h
arch/mips/kernel/jump_label.c
arch/mips/kernel/module.c
arch/openrisc/kernel/unwinder.c
arch/parisc/Kconfig
arch/parisc/include/asm/fb.h
arch/parisc/kernel/asm-offsets.c
arch/parisc/kernel/cache.c
arch/parisc/kernel/irq.c
arch/parisc/kernel/jump_label.c
arch/parisc/kernel/unaligned.c
arch/parisc/math-emu/decode_exc.c
arch/powerpc/Kconfig
arch/powerpc/crypto/aes-spe-glue.c
arch/powerpc/include/asm/archrandom.h
arch/powerpc/include/asm/bpf_perf_event.h [new file with mode: 0644]
arch/powerpc/include/asm/context_tracking.h
arch/powerpc/include/asm/kexec.h
arch/powerpc/include/asm/machdep.h
arch/powerpc/include/asm/tlb.h
arch/powerpc/include/uapi/asm/bpf_perf_event.h [deleted file]
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/process.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/prom_init_check.sh
arch/powerpc/kernel/rtas.c
arch/powerpc/kernel/setup-common.c
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/mm/mem.c
arch/powerpc/mm/nohash/book3e_pgtable.c
arch/powerpc/platforms/microwatt/Kconfig
arch/powerpc/platforms/microwatt/microwatt.h [new file with mode: 0644]
arch/powerpc/platforms/microwatt/rng.c
arch/powerpc/platforms/microwatt/setup.c
arch/powerpc/platforms/powernv/Kconfig
arch/powerpc/platforms/powernv/powernv.h
arch/powerpc/platforms/powernv/rng.c
arch/powerpc/platforms/powernv/setup.c
arch/powerpc/platforms/pseries/Kconfig
arch/powerpc/platforms/pseries/pseries.h
arch/powerpc/platforms/pseries/rng.c
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/sysdev/xive/spapr.c
arch/riscv/Kconfig
arch/riscv/Makefile
arch/riscv/boot/dts/canaan/canaan_kd233.dts
arch/riscv/boot/dts/canaan/sipeed_maix_bit.dts
arch/riscv/boot/dts/canaan/sipeed_maix_dock.dts
arch/riscv/boot/dts/canaan/sipeed_maix_go.dts
arch/riscv/boot/dts/canaan/sipeed_maixduino.dts
arch/riscv/boot/dts/microchip/mpfs.dtsi
arch/riscv/errata/sifive/errata.c
arch/riscv/include/asm/pgtable-64.h
arch/riscv/include/asm/pgtable.h
arch/riscv/kernel/Makefile
arch/riscv/kernel/elf_kexec.c
arch/riscv/kernel/entry.S
arch/riscv/kernel/jump_label.c
arch/riscv/kvm/mmu.c
arch/riscv/kvm/vcpu.c
arch/s390/Kconfig
arch/s390/Makefile
arch/s390/configs/zfcpdump_defconfig
arch/s390/crypto/Makefile
arch/s390/crypto/arch_random.c
arch/s390/include/asm/archrandom.h
arch/s390/include/asm/jump_label.h
arch/s390/include/asm/kexec.h
arch/s390/include/asm/nospec-insn.h
arch/s390/include/asm/qdio.h
arch/s390/include/asm/tlb.h
arch/s390/include/uapi/asm/hwctrset.h
arch/s390/kernel/jump_label.c
arch/s390/kernel/machine_kexec_file.c
arch/s390/kernel/module.c
arch/s390/kernel/setup.c
arch/s390/lib/Makefile
arch/s390/lib/expoline/Makefile [new file with mode: 0644]
arch/s390/lib/expoline/expoline.S [moved from arch/s390/lib/expoline.S with 100% similarity]
arch/s390/purgatory/Makefile
arch/sh/configs/ecovec24_defconfig
arch/sh/include/asm/io.h
arch/sh/kernel/irq.c
arch/sparc/Kconfig
arch/sparc/include/asm/tlb_64.h
arch/sparc/kernel/module.c
arch/sparc/kernel/rtrap_64.S
arch/um/drivers/ubd_kern.c
arch/um/include/asm/archrandom.h [new file with mode: 0644]
arch/um/include/asm/page.h
arch/um/include/shared/mem.h
arch/um/include/shared/os.h
arch/um/kernel/um_arch.c
arch/um/os-Linux/skas/process.c
arch/um/os-Linux/util.c
arch/x86/.gitignore
arch/x86/Kconfig
arch/x86/Kconfig.debug
arch/x86/Makefile
arch/x86/boot/compressed/ident_map_64.c
arch/x86/crypto/Makefile
arch/x86/crypto/aes_ctrby8_avx-x86_64.S
arch/x86/crypto/aesni-intel_glue.c
arch/x86/crypto/blake2s-glue.c
arch/x86/crypto/blake2s-shash.c [deleted file]
arch/x86/crypto/blowfish_glue.c
arch/x86/crypto/polyval-clmulni_asm.S [new file with mode: 0644]
arch/x86/crypto/polyval-clmulni_glue.c [new file with mode: 0644]
arch/x86/entry/Makefile
arch/x86/entry/calling.h
arch/x86/entry/entry.S [new file with mode: 0644]
arch/x86/entry/entry_32.S
arch/x86/entry/entry_64.S
arch/x86/entry/entry_64_compat.S
arch/x86/entry/vdso/Makefile
arch/x86/entry/vsyscall/vsyscall_emu_64.S
arch/x86/events/amd/uncore.c
arch/x86/events/intel/core.c
arch/x86/events/intel/ds.c
arch/x86/events/intel/lbr.c
arch/x86/events/perf_event.h
arch/x86/hyperv/irqdomain.c
arch/x86/include/asm/alternative.h
arch/x86/include/asm/amd-ibs.h
arch/x86/include/asm/archrandom.h
arch/x86/include/asm/cpufeatures.h
arch/x86/include/asm/disabled-features.h
arch/x86/include/asm/fpu/api.h
arch/x86/include/asm/kexec.h
arch/x86/include/asm/linkage.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/mwait.h
arch/x86/include/asm/nospec-branch.h
arch/x86/include/asm/perf_event.h
arch/x86/include/asm/setup.h
arch/x86/include/asm/sev.h
arch/x86/include/asm/special_insns.h
arch/x86/include/asm/static_call.h
arch/x86/include/asm/tlb.h
arch/x86/include/asm/tlbflush.h
arch/x86/include/asm/unwind_hints.h
arch/x86/include/uapi/asm/bootparam.h
arch/x86/include/uapi/asm/kvm.h
arch/x86/kernel/Makefile
arch/x86/kernel/acpi/cppc.c
arch/x86/kernel/alternative.c
arch/x86/kernel/amd_nb.c
arch/x86/kernel/asm-offsets.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/bugs.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/cpu.h
arch/x86/kernel/cpu/hygon.c
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/cpu/mce/inject.c
arch/x86/kernel/cpu/mce/internal.h
arch/x86/kernel/cpu/rdrand.c
arch/x86/kernel/cpu/scattered.c
arch/x86/kernel/cpu/vmware.c
arch/x86/kernel/e820.c
arch/x86/kernel/espfix_64.c
arch/x86/kernel/fpu/core.c
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/jump_label.c
arch/x86/kernel/kexec-bzimage64.c
arch/x86/kernel/module.c
arch/x86/kernel/pmem.c
arch/x86/kernel/process.c
arch/x86/kernel/relocate_kernel_32.S
arch/x86/kernel/relocate_kernel_64.S
arch/x86/kernel/setup.c
arch/x86/kernel/sev-shared.c
arch/x86/kernel/sev.c
arch/x86/kernel/static_call.c
arch/x86/kernel/vmlinux.lds.S
arch/x86/kvm/emulate.c
arch/x86/kvm/svm/vmenter.S
arch/x86/kvm/vmx/capabilities.h
arch/x86/kvm/vmx/nested.c
arch/x86/kvm/vmx/run_flags.h [new file with mode: 0644]
arch/x86/kvm/vmx/vmenter.S
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/vmx/vmx.h
arch/x86/kvm/vmx/vmx_ops.h
arch/x86/kvm/x86.c
arch/x86/lib/memmove_64.S
arch/x86/lib/retpoline.S
arch/x86/mm/extable.c
arch/x86/mm/fault.c
arch/x86/mm/init.c
arch/x86/mm/mem_encrypt_boot.S
arch/x86/mm/pkeys.c
arch/x86/mm/tlb.c
arch/x86/net/bpf_jit_comp.c
arch/x86/platform/efi/efi_thunk_64.S
arch/x86/purgatory/Makefile
arch/x86/purgatory/kexec-purgatory.S [new file with mode: 0644]
arch/x86/xen/enlighten_pv.c
arch/x86/xen/setup.c
arch/x86/xen/xen-asm.S
arch/x86/xen/xen-head.S
arch/x86/xen/xen-ops.h
arch/xtensa/Kconfig
arch/xtensa/kernel/entry.S
arch/xtensa/kernel/irq.c
arch/xtensa/kernel/time.c
arch/xtensa/platforms/iss/simdisk.c
arch/xtensa/platforms/xtfpga/setup.c
block/Kconfig
block/bdev.c
block/bfq-cgroup.c
block/bfq-iosched.c
block/bfq-iosched.h
block/bfq-wf2q.c
block/bio.c
block/blk-cgroup-rwstat.h
block/blk-cgroup.c
block/blk-cgroup.h
block/blk-core.c
block/blk-flush.c
block/blk-ia-ranges.c
block/blk-ioc.c
block/blk-iocost.c
block/blk-iolatency.c
block/blk-ioprio.c
block/blk-ioprio.h
block/blk-lib.c
block/blk-merge.c
block/blk-mq-debugfs-zoned.c
block/blk-mq-debugfs.c
block/blk-mq-sysfs.c
block/blk-mq-tag.c
block/blk-mq-tag.h
block/blk-mq.c
block/blk-mq.h
block/blk-rq-qos.c
block/blk-rq-qos.h
block/blk-settings.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/elevator.h
block/fops.c
block/genhd.c
block/ioctl.c
block/ioprio.c
block/kyber-iosched.c
block/mq-deadline.c
block/partitions/core.c
certs/Kconfig
crypto/Kconfig
crypto/Makefile
crypto/aria.c [new file with mode: 0644]
crypto/blake2s_generic.c [deleted file]
crypto/fips.c
crypto/hctr2.c [new file with mode: 0644]
crypto/polyval-generic.c [new file with mode: 0644]
crypto/rsa.c
crypto/tcrypt.c
crypto/testmgr.c
crypto/testmgr.h
crypto/twofish_common.c
crypto/xctr.c [new file with mode: 0644]
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/acpi_lpit.c
drivers/acpi/acpi_lpss.c
drivers/acpi/acpi_video.c
drivers/acpi/apei/apei-base.c
drivers/acpi/apei/bert.c
drivers/acpi/apei/einj.c
drivers/acpi/bus.c
drivers/acpi/container.c
drivers/acpi/cppc_acpi.c
drivers/acpi/device_pm.c
drivers/acpi/device_sysfs.c
drivers/acpi/ec.c
drivers/acpi/glue.c
drivers/acpi/irq.c
drivers/acpi/pci_link.c
drivers/acpi/processor_driver.c
drivers/acpi/processor_idle.c
drivers/acpi/processor_thermal.c
drivers/acpi/property.c
drivers/acpi/resource.c
drivers/acpi/scan.c
drivers/acpi/sleep.c
drivers/acpi/video_detect.c
drivers/acpi/viot.c
drivers/acpi/x86/s2idle.c
drivers/amba/bus.c
drivers/ata/Kconfig
drivers/ata/pata_cs5535.c
drivers/base/core.c
drivers/base/cpu.c
drivers/base/memory.c
drivers/base/power/domain.c
drivers/base/power/runtime.c
drivers/base/power/wakeup.c
drivers/base/regmap/regcache.c
drivers/base/regmap/regmap-irq.c
drivers/base/regmap/regmap.c
drivers/block/Kconfig
drivers/block/Makefile
drivers/block/amiflop.c
drivers/block/aoe/aoeblk.c
drivers/block/aoe/aoedev.c
drivers/block/ataflop.c
drivers/block/brd.c
drivers/block/drbd/drbd_actlog.c
drivers/block/drbd/drbd_bitmap.c
drivers/block/drbd/drbd_int.h
drivers/block/drbd/drbd_main.c
drivers/block/drbd/drbd_receiver.c
drivers/block/drbd/drbd_req.c
drivers/block/drbd/drbd_worker.c
drivers/block/floppy.c
drivers/block/loop.c
drivers/block/mtip32xx/mtip32xx.c
drivers/block/mtip32xx/mtip32xx.h
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/paride/pcd.c
drivers/block/paride/pd.c
drivers/block/paride/pf.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-proto.h
drivers/block/rnbd/rnbd-srv-dev.c
drivers/block/rnbd/rnbd-srv-dev.h
drivers/block/rnbd/rnbd-srv-sysfs.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/sx8.c
drivers/block/ublk_drv.c [new file with mode: 0644]
drivers/block/virtio_blk.c
drivers/block/xen-blkback/blkback.c
drivers/block/xen-blkfront.c
drivers/block/z2ram.c
drivers/block/zram/zram_drv.c
drivers/bus/bt1-apb.c
drivers/bus/bt1-axi.c
drivers/bus/hisi_lpc.c
drivers/cdrom/gdrom.c
drivers/char/Kconfig
drivers/char/hw_random/Kconfig
drivers/char/hw_random/s390-trng.c
drivers/char/hw_random/via-rng.c
drivers/char/random.c
drivers/clk/.kunitconfig
drivers/clk/bcm/Kconfig
drivers/clk/clk-lan966x.c
drivers/clk/stm32/reset-stm32.c
drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c
drivers/clocksource/Kconfig
drivers/clocksource/Makefile
drivers/clocksource/sh_cmt.c
drivers/clocksource/timer-mediatek.c
drivers/clocksource/timer-microchip-pit64b.c
drivers/clocksource/timer-sun4i.c
drivers/clocksource/timer-sun5i.c
drivers/clocksource/timer-tegra186.c [new file with mode: 0644]
drivers/clocksource/timer-ti-dm.c
drivers/cpufreq/Kconfig
drivers/cpufreq/acpi-cpufreq.c
drivers/cpufreq/amd-pstate.c
drivers/cpufreq/cpufreq-dt-platdev.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_ondemand.c
drivers/cpufreq/mediatek-cpufreq-hw.c
drivers/cpufreq/mediatek-cpufreq.c
drivers/cpufreq/pmac32-cpufreq.c
drivers/cpufreq/qcom-cpufreq-hw.c
drivers/cpufreq/qoriq-cpufreq.c
drivers/cpufreq/scmi-cpufreq.c
drivers/cpuidle/Kconfig.arm
drivers/cpuidle/cpuidle-psci.c
drivers/cpuidle/cpuidle-riscv-sbi.c
drivers/cpuidle/cpuidle.c
drivers/cpuidle/governors/haltpoll.c
drivers/crypto/Kconfig
drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c
drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c
drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c
drivers/crypto/amcc/crypto4xx_core.c
drivers/crypto/atmel-aes.c
drivers/crypto/atmel-ecc.c
drivers/crypto/atmel-sha.c
drivers/crypto/atmel-tdes.c
drivers/crypto/caam/caamalg_qi2.c
drivers/crypto/caam/caamhash_desc.c
drivers/crypto/caam/qi.c
drivers/crypto/cavium/cpt/cpt_hw_types.h
drivers/crypto/ccp/ccp-dev.h
drivers/crypto/ccp/sev-dev.c
drivers/crypto/ccp/sp-pci.c
drivers/crypto/ccp/sp-platform.c
drivers/crypto/ccree/cc_driver.c
drivers/crypto/ccree/cc_pm.c
drivers/crypto/hisilicon/hpre/hpre_crypto.c
drivers/crypto/hisilicon/qm.c
drivers/crypto/hisilicon/sec/sec_algs.c
drivers/crypto/hisilicon/sec/sec_drv.c
drivers/crypto/hisilicon/sec/sec_drv.h
drivers/crypto/hisilicon/sec2/sec.h
drivers/crypto/hisilicon/sec2/sec_crypto.c
drivers/crypto/hisilicon/sec2/sec_crypto.h
drivers/crypto/hisilicon/sec2/sec_main.c
drivers/crypto/hisilicon/trng/trng.c
drivers/crypto/hisilicon/zip/zip_crypto.c
drivers/crypto/hisilicon/zip/zip_main.c
drivers/crypto/inside-secure/safexcel.c
drivers/crypto/inside-secure/safexcel.h
drivers/crypto/keembay/keembay-ocs-ecc.c
drivers/crypto/marvell/octeontx2/otx2_cpt_devlink.c
drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c
drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.h
drivers/crypto/nx/nx-common-powernv.c
drivers/crypto/nx/nx-common-pseries.c
drivers/crypto/omap-aes.c
drivers/crypto/omap-des.c
drivers/crypto/omap-sham.c
drivers/crypto/qat/Kconfig
drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c
drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.h
drivers/crypto/qat/qat_4xxx/adf_drv.c
drivers/crypto/qat/qat_common/Makefile
drivers/crypto/qat/qat_common/adf_accel_devices.h
drivers/crypto/qat/qat_common/adf_cfg.c
drivers/crypto/qat/qat_common/adf_common_drv.h
drivers/crypto/qat/qat_common/adf_init.c
drivers/crypto/qat/qat_common/adf_sriov.c
drivers/crypto/qat/qat_common/adf_sysfs.c [new file with mode: 0644]
drivers/crypto/qat/qat_common/qat_algs.c
drivers/crypto/qat/qat_common/qat_asym_algs.c
drivers/crypto/s5p-sss.c
drivers/crypto/sa2ul.c
drivers/crypto/sa2ul.h
drivers/crypto/ux500/hash/hash_core.c
drivers/crypto/vmx/ghash.c
drivers/crypto/vmx/ghashp8-ppc.pl
drivers/cxl/core/hdm.c
drivers/cxl/core/mbox.c
drivers/cxl/core/port.c
drivers/cxl/cxl.h
drivers/cxl/cxlmem.h
drivers/cxl/mem.c
drivers/cxl/pmem.c
drivers/devfreq/Kconfig
drivers/devfreq/Makefile
drivers/devfreq/devfreq.c
drivers/devfreq/event/exynos-ppmu.c
drivers/devfreq/exynos-bus.c
drivers/devfreq/governor_passive.c
drivers/devfreq/imx-bus.c
drivers/devfreq/mtk-cci-devfreq.c [new file with mode: 0644]
drivers/devfreq/tegra30-devfreq.c
drivers/dma-buf/dma-resv.c
drivers/dma/at_xdmac.c
drivers/dma/dmatest.c
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
drivers/dma/idxd/device.c
drivers/dma/idxd/init.c
drivers/dma/imx-sdma.c
drivers/dma/lgm/lgm-dma.c
drivers/dma/pl330.c
drivers/dma/qcom/bam_dma.c
drivers/dma/ti/dma-crossbar.c
drivers/edac/ghes_edac.c
drivers/edac/synopsys_edac.c
drivers/firmware/arm_scmi/Kconfig
drivers/firmware/arm_scmi/Makefile
drivers/firmware/arm_scmi/base.c
drivers/firmware/arm_scmi/bus.c
drivers/firmware/arm_scmi/clock.c
drivers/firmware/arm_scmi/driver.c
drivers/firmware/arm_scmi/optee.c
drivers/firmware/arm_scmi/perf.c
drivers/firmware/arm_scmi/power.c
drivers/firmware/arm_scmi/powercap.c [new file with mode: 0644]
drivers/firmware/arm_scmi/protocols.h
drivers/firmware/arm_scmi/reset.c
drivers/firmware/arm_scmi/scmi_power_control.c [new file with mode: 0644]
drivers/firmware/arm_scmi/sensors.c
drivers/firmware/arm_scmi/system.c
drivers/firmware/arm_scmi/voltage.c
drivers/firmware/arm_scpi.c
drivers/firmware/efi/reboot.c
drivers/firmware/qcom_scm-legacy.c
drivers/firmware/qcom_scm.c
drivers/firmware/sysfb.c
drivers/firmware/sysfb_simplefb.c
drivers/firmware/tegra/bpmp-debugfs.c
drivers/firmware/tegra/bpmp.c
drivers/firmware/xilinx/zynqmp.c
drivers/gpio/gpio-msc313.c
drivers/gpio/gpio-pca953x.c
drivers/gpio/gpio-sim.c
drivers/gpio/gpio-tegra.c
drivers/gpio/gpio-tegra186.c
drivers/gpio/gpio-thunderx.c
drivers/gpio/gpio-vf610.c
drivers/gpio/gpio-visconti.c
drivers/gpio/gpio-xilinx.c
drivers/gpio/gpiolib-cdev.c
drivers/gpio/gpiolib.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h [deleted file]
drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
drivers/gpu/drm/amd/amdkfd/kfd_device.c
drivers/gpu/drm/amd/display/Kconfig
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
drivers/gpu/drm/amd/display/dc/core/dc_resource.c
drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c
drivers/gpu/drm/bridge/fsl-ldb.c
drivers/gpu/drm/drm_aperture.c
drivers/gpu/drm/drm_gem_ttm_helper.c
drivers/gpu/drm/drm_panel_orientation_quirks.c
drivers/gpu/drm/i915/display/intel_dp_mst.c
drivers/gpu/drm/i915/gem/i915_gem_context.c
drivers/gpu/drm/i915/gem/i915_gem_domain.c
drivers/gpu/drm/i915/gem/i915_gem_region.c
drivers/gpu/drm/i915/gem/i915_gem_ttm.c
drivers/gpu/drm/i915/gem/i915_gem_wait.c
drivers/gpu/drm/i915/gt/intel_context_types.h
drivers/gpu/drm/i915/gt/intel_engine.h
drivers/gpu/drm/i915/gt/intel_engine_cs.c
drivers/gpu/drm/i915/gt/intel_execlists_submission.c
drivers/gpu/drm/i915/gt/intel_gt.c
drivers/gpu/drm/i915/gt/intel_lrc.h
drivers/gpu/drm/i915/gt/intel_reset.c
drivers/gpu/drm/i915/gt/selftest_lrc.c
drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h
drivers/gpu/drm/i915/gt/uc/intel_guc.c
drivers/gpu/drm/i915/gt/uc/intel_guc.h
drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h
drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h
drivers/gpu/drm/i915/gvt/cmd_parser.c
drivers/gpu/drm/i915/i915_driver.c
drivers/gpu/drm/i915/i915_scatterlist.c
drivers/gpu/drm/i915/i915_scatterlist.h
drivers/gpu/drm/i915/i915_vma.c
drivers/gpu/drm/i915/intel_region_ttm.c
drivers/gpu/drm/i915/intel_region_ttm.h
drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
drivers/gpu/drm/i915/selftests/intel_memory_region.c
drivers/gpu/drm/i915/selftests/mock_region.c
drivers/gpu/drm/imx/dcss/dcss-dev.c
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
drivers/gpu/drm/msm/dp/dp_display.c
drivers/gpu/drm/msm/msm_gem_submit.c
drivers/gpu/drm/nouveau/nouveau_dmem.c
drivers/gpu/drm/panel/panel-edp.c
drivers/gpu/drm/panfrost/panfrost_drv.c
drivers/gpu/drm/panfrost/panfrost_mmu.c
drivers/gpu/drm/rockchip/rockchip_drm_drv.c
drivers/gpu/drm/scheduler/sched_entity.c
drivers/gpu/drm/solomon/ssd130x.c
drivers/gpu/drm/tiny/simpledrm.c
drivers/gpu/drm/vc4/vc4_perfmon.c
drivers/hwmon/Kconfig
drivers/hwmon/aquacomputer_d5next.c
drivers/hwmon/aspeed-pwm-tacho.c
drivers/hwmon/asus-ec-sensors.c
drivers/hwmon/asus_wmi_sensors.c
drivers/hwmon/dell-smm-hwmon.c
drivers/hwmon/drivetemp.c
drivers/hwmon/f71882fg.c
drivers/hwmon/gsc-hwmon.c
drivers/hwmon/ibmaem.c
drivers/hwmon/k10temp.c
drivers/hwmon/lm75.h
drivers/hwmon/lm90.c
drivers/hwmon/mcp3021.c
drivers/hwmon/nct6775-platform.c
drivers/hwmon/occ/common.c
drivers/hwmon/occ/common.h
drivers/hwmon/occ/p8_i2c.c
drivers/hwmon/occ/p9_sbe.c
drivers/hwmon/pmbus/Kconfig
drivers/hwmon/pmbus/Makefile
drivers/hwmon/pmbus/lt7182s.c [new file with mode: 0644]
drivers/hwmon/pmbus/ltc2978.c
drivers/hwmon/pmbus/pmbus.h
drivers/hwmon/pmbus/pmbus_core.c
drivers/hwmon/pmbus/ucd9200.c
drivers/hwmon/sch56xx-common.c
drivers/hwmon/sht15.c
drivers/hwmon/tps23861.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-cadence.c
drivers/i2c/busses/i2c-imx.c
drivers/i2c/busses/i2c-mlxcpld.c
drivers/i2c/busses/i2c-piix4.c
drivers/idle/intel_idle.c
drivers/infiniband/core/cm.c
drivers/infiniband/hw/irdma/cm.c
drivers/infiniband/hw/irdma/i40iw_hw.c
drivers/infiniband/hw/irdma/icrdma_hw.c
drivers/infiniband/hw/irdma/irdma.h
drivers/infiniband/hw/irdma/verbs.c
drivers/infiniband/hw/qedr/qedr.h
drivers/infiniband/hw/qedr/verbs.c
drivers/infiniband/ulp/srp/ib_srp.c
drivers/input/touchscreen/goodix.c
drivers/input/touchscreen/usbtouchscreen.c
drivers/input/touchscreen/wm97xx-core.c
drivers/iommu/hyperv-iommu.c
drivers/iommu/intel/dmar.c
drivers/iommu/intel/iommu.c
drivers/iommu/intel/pasid.c
drivers/iommu/intel/pasid.h
drivers/irqchip/Kconfig
drivers/irqchip/Makefile
drivers/irqchip/irq-apple-aic.c
drivers/irqchip/irq-bcm6345-l1.c
drivers/irqchip/irq-gic-v3.c
drivers/irqchip/irq-gic.c
drivers/irqchip/irq-loongarch-cpu.c [new file with mode: 0644]
drivers/irqchip/irq-loongson-eiointc.c [new file with mode: 0644]
drivers/irqchip/irq-loongson-liointc.c
drivers/irqchip/irq-loongson-pch-lpc.c [new file with mode: 0644]
drivers/irqchip/irq-loongson-pch-msi.c
drivers/irqchip/irq-loongson-pch-pic.c
drivers/irqchip/irq-mips-gic.c
drivers/irqchip/irq-or1k-pic.c
drivers/irqchip/irq-renesas-rzg2l.c [new file with mode: 0644]
drivers/irqchip/irq-sifive-plic.c
drivers/irqchip/irq-sp7021-intc.c [new file with mode: 0644]
drivers/irqchip/irq-stm32-exti.c
drivers/md/Makefile
drivers/md/bcache/super.c
drivers/md/dm-bufio.c
drivers/md/dm-cache-metadata.h
drivers/md/dm-cache-target.c
drivers/md/dm-core.h
drivers/md/dm-ebs-target.c
drivers/md/dm-flakey.c
drivers/md/dm-ima.c
drivers/md/dm-integrity.c
drivers/md/dm-io-rewind.c [new file with mode: 0644]
drivers/md/dm-io.c
drivers/md/dm-ioctl.c
drivers/md/dm-kcopyd.c
drivers/md/dm-log.c
drivers/md/dm-raid.c
drivers/md/dm-raid1.c
drivers/md/dm-rq.c
drivers/md/dm-snap-persistent.c
drivers/md/dm-snap.c
drivers/md/dm-table.c
drivers/md/dm-thin-metadata.c
drivers/md/dm-thin.c
drivers/md/dm-verity-loadpin.c [new file with mode: 0644]
drivers/md/dm-verity-target.c
drivers/md/dm-verity.h
drivers/md/dm-writecache.c
drivers/md/dm-zone.c
drivers/md/dm-zoned-metadata.c
drivers/md/dm-zoned-target.c
drivers/md/dm-zoned.h
drivers/md/dm.c
drivers/md/dm.h
drivers/md/md-bitmap.c
drivers/md/md.c
drivers/md/md.h
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5-cache.c
drivers/md/raid5-ppl.c
drivers/md/raid5.c
drivers/memory/Kconfig
drivers/memory/mtk-smi.c
drivers/memory/samsung/exynos5422-dmc.c
drivers/memory/tegra/tegra234.c
drivers/memstick/core/ms_block.c
drivers/memstick/core/mspro_block.c
drivers/mfd/bcm2835-pm.c
drivers/mfd/mfd-core.c
drivers/misc/cardreader/rtsx_usb.c
drivers/misc/eeprom/at25.c
drivers/misc/lkdtm/Makefile
drivers/misc/lkdtm/bugs.c
drivers/mmc/core/block.c
drivers/mmc/core/queue.c
drivers/mmc/host/Kconfig
drivers/mmc/host/sdhci-acpi.c
drivers/mmc/host/sdhci-of-aspeed-test.c
drivers/mmc/host/sdhci-of-aspeed.c
drivers/mmc/host/sdhci-omap.c
drivers/mmc/host/sdhci-pci-core.c
drivers/mtd/mtd_blkdevs.c
drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
drivers/mtd/ubi/block.c
drivers/net/Kconfig
drivers/net/amt.c
drivers/net/bonding/bond_3ad.c
drivers/net/bonding/bond_alb.c
drivers/net/caif/caif_virtio.c
drivers/net/can/grcan.c
drivers/net/can/m_can/m_can.c
drivers/net/can/rcar/rcar_canfd.c
drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
drivers/net/can/spi/mcp251xfd/mcp251xfd-regmap.c
drivers/net/can/usb/gs_usb.c
drivers/net/can/usb/kvaser_usb/kvaser_usb.h
drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c
drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
drivers/net/can/xilinx_can.c
drivers/net/dsa/bcm_sf2.c
drivers/net/dsa/hirschmann/hellcreek_ptp.c
drivers/net/dsa/microchip/ksz_common.c
drivers/net/dsa/ocelot/felix_vsc9959.c
drivers/net/dsa/sja1105/sja1105_main.c
drivers/net/dsa/vitesse-vsc73xx-spi.c
drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt.h
drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c
drivers/net/ethernet/emulex/benet/be_cmds.c
drivers/net/ethernet/emulex/benet/be_cmds.h
drivers/net/ethernet/emulex/benet/be_ethtool.c
drivers/net/ethernet/faraday/ftgmac100.c
drivers/net/ethernet/fungible/funeth/funeth_rx.c
drivers/net/ethernet/fungible/funeth/funeth_tx.c
drivers/net/ethernet/fungible/funeth/funeth_txrx.h
drivers/net/ethernet/ibm/ibmvnic.c
drivers/net/ethernet/intel/e1000e/hw.h
drivers/net/ethernet/intel/e1000e/ich8lan.c
drivers/net/ethernet/intel/e1000e/ich8lan.h
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/intel/i40e/i40e.h
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_register.h
drivers/net/ethernet/intel/i40e/i40e_type.h
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/iavf/iavf.h
drivers/net/ethernet/intel/iavf/iavf_ethtool.c
drivers/net/ethernet/intel/iavf/iavf_main.c
drivers/net/ethernet/intel/iavf/iavf_txrx.c
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
drivers/net/ethernet/intel/ice/ice_devids.h
drivers/net/ethernet/intel/ice/ice_devlink.c
drivers/net/ethernet/intel/ice/ice_ethtool.c
drivers/net/ethernet/intel/ice/ice_fw_update.c
drivers/net/ethernet/intel/ice/ice_main.c
drivers/net/ethernet/intel/ice/ice_sriov.c
drivers/net/ethernet/intel/ice/ice_txrx.c
drivers/net/ethernet/intel/ice/ice_virtchnl.c
drivers/net/ethernet/intel/igc/igc_main.c
drivers/net/ethernet/intel/igc/igc_regs.h
drivers/net/ethernet/intel/ixgbe/ixgbe.h
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h
drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
drivers/net/ethernet/marvell/prestera/prestera_flower.c
drivers/net/ethernet/marvell/prestera/prestera_router.c
drivers/net/ethernet/mediatek/mtk_ppe_offload.c
drivers/net/ethernet/mediatek/mtk_wed.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_rx.c
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c
drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
drivers/net/ethernet/mellanox/mlx5/core/esw/legacy.c
drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
drivers/net/ethernet/microchip/lan966x/lan966x_mac.c
drivers/net/ethernet/microchip/lan966x/lan966x_main.c
drivers/net/ethernet/microchip/lan966x/lan966x_main.h
drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c
drivers/net/ethernet/mscc/ocelot_fdma.c
drivers/net/ethernet/netronome/nfp/bpf/jit.c
drivers/net/ethernet/netronome/nfp/flower/action.c
drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
drivers/net/ethernet/netronome/nfp/nfdk/dp.c
drivers/net/ethernet/realtek/r8169_main.c
drivers/net/ethernet/sfc/ef10.c
drivers/net/ethernet/sfc/ef10_sriov.c
drivers/net/ethernet/sfc/ptp.c
drivers/net/ethernet/smsc/epic100.c
drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c
drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c
drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
drivers/net/ethernet/stmicro/stmmac/dwmac4.h
drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
drivers/net/ethernet/stmicro/stmmac/stmmac.h
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
drivers/net/ethernet/sun/sunhme.c
drivers/net/ethernet/ti/am65-cpsw-nuss.c
drivers/net/ipa/ipa_qmi_msg.h
drivers/net/macsec.c
drivers/net/pcs/pcs-xpcs.c
drivers/net/phy/ax88796b.c
drivers/net/phy/dp83822.c
drivers/net/phy/phy.c
drivers/net/phy/phy_device.c
drivers/net/phy/sfp.c
drivers/net/sungem_phy.c
drivers/net/tun.c
drivers/net/usb/asix.h
drivers/net/usb/asix_common.c
drivers/net/usb/ax88179_178a.c
drivers/net/usb/catc.c
drivers/net/usb/r8152.c
drivers/net/usb/usbnet.c
drivers/net/virtio_net.c
drivers/net/wireless/ath/ath11k/wmi.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/realtek/rtw88/main.h
drivers/net/wireless/realtek/rtw88/rtw8821c.c
drivers/net/xen-netback/rx.c
drivers/net/xen-netfront.c
drivers/nfc/nfcmrvl/i2c.c
drivers/nfc/nfcmrvl/spi.c
drivers/nfc/nxp-nci/i2c.c
drivers/nvdimm/btt.c
drivers/nvdimm/bus.c
drivers/nvdimm/pmem.c
drivers/nvme/host/apple.c
drivers/nvme/host/core.c
drivers/nvme/host/fc.c
drivers/nvme/host/ioctl.c
drivers/nvme/host/multipath.c
drivers/nvme/host/nvme.h
drivers/nvme/host/pci.c
drivers/nvme/host/rdma.c
drivers/nvme/host/tcp.c
drivers/nvme/host/trace.h
drivers/nvme/host/zns.c
drivers/nvme/target/configfs.c
drivers/nvme/target/core.c
drivers/nvme/target/io-cmd-bdev.c
drivers/nvme/target/loop.c
drivers/nvme/target/nvmet.h
drivers/nvme/target/passthru.c
drivers/nvme/target/tcp.c
drivers/nvme/target/zns.c
drivers/of/kexec.c
drivers/opp/of.c
drivers/parisc/iosapic.c
drivers/pci/controller/pci-hyperv.c
drivers/perf/arm-cci.c
drivers/perf/arm-ccn.c
drivers/perf/arm_spe_pmu.c
drivers/perf/fsl_imx8_ddr_perf.c
drivers/perf/hisilicon/Kconfig
drivers/perf/hisilicon/Makefile
drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
drivers/perf/hisilicon/hisi_uncore_pa_pmu.c
drivers/perf/hisilicon/hisi_uncore_pmu.c
drivers/perf/hisilicon/hisi_uncore_pmu.h
drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c
drivers/perf/hisilicon/hns3_pmu.c [new file with mode: 0644]
drivers/perf/marvell_cn10k_tad_pmu.c
drivers/perf/riscv_pmu.c
drivers/perf/riscv_pmu_sbi.c
drivers/phy/broadcom/Kconfig
drivers/pinctrl/Kconfig
drivers/pinctrl/aspeed/pinctrl-aspeed.c
drivers/pinctrl/freescale/pinctrl-imx93.c
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
drivers/pinctrl/pinctrl-ocelot.c
drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
drivers/pinctrl/ralink/pinctrl-ralink.c
drivers/pinctrl/renesas/pinctrl-rzg2l.c
drivers/pinctrl/stm32/pinctrl-stm32.c
drivers/pinctrl/sunplus/sppctl.c
drivers/pinctrl/sunxi/pinctrl-sun8i-a83t.c
drivers/pinctrl/sunxi/pinctrl-sunxi.c
drivers/platform/mellanox/nvsw-sn2201.c
drivers/platform/x86/Kconfig
drivers/platform/x86/amd-pmc.c
drivers/platform/x86/asus-nb-wmi.c
drivers/platform/x86/gigabyte-wmi.c
drivers/platform/x86/hp-wmi.c
drivers/platform/x86/ideapad-laptop.c
drivers/platform/x86/intel/atomisp2/led.c
drivers/platform/x86/intel/ifs/Kconfig
drivers/platform/x86/intel/pmc/core.c
drivers/platform/x86/panasonic-laptop.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/x86-android-tablets.c
drivers/power/reset/arm-versatile-reboot.c
drivers/power/supply/ab8500_fg.c
drivers/power/supply/power_supply_core.c
drivers/powercap/dtpm_cpu.c
drivers/powercap/intel_rapl_common.c
drivers/powercap/intel_rapl_msr.c
drivers/ptp/Kconfig
drivers/pwm/Kconfig
drivers/pwm/Makefile
drivers/pwm/core.c
drivers/pwm/pwm-atmel-tcb.c
drivers/pwm/pwm-clk.c [new file with mode: 0644]
drivers/pwm/pwm-lpc18xx-sct.c
drivers/pwm/pwm-mediatek.c
drivers/pwm/pwm-sifive.c
drivers/pwm/pwm-twl-led.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/core.c
drivers/regulator/devres.c
drivers/regulator/max597x-regulator.c [new file with mode: 0644]
drivers/regulator/mp5416.c
drivers/regulator/mt6370-regulator.c [new file with mode: 0644]
drivers/regulator/mt6380-regulator.c
drivers/regulator/of_regulator.c
drivers/regulator/qcom_smd-regulator.c
drivers/regulator/qcom_spmi-regulator.c
drivers/regulator/rpi-panel-attiny-regulator.c
drivers/regulator/rt5120-regulator.c [new file with mode: 0644]
drivers/regulator/rt5190a-regulator.c
drivers/regulator/scmi-regulator.c
drivers/regulator/ti-abb-regulator.c
drivers/reset/Kconfig
drivers/reset/Makefile
drivers/reset/reset-npcm.c
drivers/reset/reset-sunplus.c [new file with mode: 0644]
drivers/s390/block/dasd.c
drivers/s390/block/dasd_genhd.c
drivers/s390/block/dasd_int.h
drivers/s390/block/dcssblk.c
drivers/s390/block/scm_blk.c
drivers/s390/char/sclp.c
drivers/s390/crypto/ap_bus.c
drivers/s390/net/qeth_core_main.c
drivers/s390/virtio/virtio_ccw.c
drivers/scsi/aacraid/comminit.c
drivers/scsi/aacraid/linit.c
drivers/scsi/device_handler/scsi_dh_alua.c
drivers/scsi/device_handler/scsi_dh_emc.c
drivers/scsi/device_handler/scsi_dh_hp_sw.c
drivers/scsi/device_handler/scsi_dh_rdac.c
drivers/scsi/fnic/fnic_scsi.c
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
drivers/scsi/hosts.c
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/mpi3mr/mpi3mr_os.c
drivers/scsi/mpt3sas/mpt3sas_scsih.c
drivers/scsi/pm8001/pm8001_hwi.c
drivers/scsi/pm8001/pm8001_init.c
drivers/scsi/pm8001/pm80xx_hwi.c
drivers/scsi/scsi_error.c
drivers/scsi/scsi_ioctl.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_priv.h
drivers/scsi/scsi_sysfs.c
drivers/scsi/sd.c
drivers/scsi/sd_zbc.c
drivers/scsi/sr.c
drivers/sh/intc/chip.c
drivers/soc/Kconfig
drivers/soc/Makefile
drivers/soc/amlogic/meson-mx-socinfo.c
drivers/soc/amlogic/meson-secure-pwrc.c
drivers/soc/atmel/soc.c
drivers/soc/bcm/bcm2835-power.c
drivers/soc/bcm/brcmstb/biuctrl.c
drivers/soc/bcm/brcmstb/pm/pm-arm.c
drivers/soc/fsl/guts.c
drivers/soc/fujitsu/Kconfig [new file with mode: 0644]
drivers/soc/fujitsu/Makefile [new file with mode: 0644]
drivers/soc/fujitsu/a64fx-diag.c [new file with mode: 0644]
drivers/soc/imx/gpcv2.c
drivers/soc/imx/imx8m-blk-ctrl.c
drivers/soc/ixp4xx/ixp4xx-npe.c
drivers/soc/mediatek/Kconfig
drivers/soc/mediatek/Makefile
drivers/soc/mediatek/mt6795-pm-domains.h [new file with mode: 0644]
drivers/soc/mediatek/mt8183-pm-domains.h
drivers/soc/mediatek/mt8186-pm-domains.h
drivers/soc/mediatek/mt8192-pm-domains.h
drivers/soc/mediatek/mt8195-pm-domains.h
drivers/soc/mediatek/mt8365-mmsys.h
drivers/soc/mediatek/mtk-devapc.c
drivers/soc/mediatek/mtk-mutex.c
drivers/soc/mediatek/mtk-pm-domains.c
drivers/soc/mediatek/mtk-pm-domains.h
drivers/soc/mediatek/mtk-pmic-wrap.c
drivers/soc/mediatek/mtk-svs.c [new file with mode: 0644]
drivers/soc/qcom/Kconfig
drivers/soc/qcom/Makefile
drivers/soc/qcom/apr.c
drivers/soc/qcom/cmd-db.c
drivers/soc/qcom/icc-bwmon.c [new file with mode: 0644]
drivers/soc/qcom/llcc-qcom.c
drivers/soc/qcom/mdt_loader.c
drivers/soc/qcom/ocmem.c
drivers/soc/qcom/qcom_aoss.c
drivers/soc/qcom/rpmhpd.c
drivers/soc/qcom/rpmpd.c
drivers/soc/qcom/smd-rpm.c
drivers/soc/qcom/smem.c
drivers/soc/qcom/smp2p.c
drivers/soc/qcom/socinfo.c
drivers/soc/qcom/spm.c
drivers/soc/renesas/r8a779a0-sysc.c
drivers/soc/renesas/rcar-gen4-sysc.h
drivers/soc/renesas/rcar-sysc.h
drivers/soc/sunxi/Kconfig
drivers/soc/ti/pruss.c
drivers/soc/ti/wkup_m3_ipc.c
drivers/soc/xilinx/xlnx_event_manager.c
drivers/soundwire/slave.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/atmel-quadspi.c
drivers/spi/spi-altera-dfl.c
drivers/spi/spi-amd.c
drivers/spi/spi-armada-3700.c
drivers/spi/spi-aspeed-smc.c
drivers/spi/spi-atmel.c
drivers/spi/spi-bcm2835.c
drivers/spi/spi-cadence-quadspi.c
drivers/spi/spi-cadence.c
drivers/spi/spi-dw-core.c
drivers/spi/spi-dw-dma.c
drivers/spi/spi-dw-mmio.c
drivers/spi/spi-dw.h
drivers/spi/spi-fsi.c
drivers/spi/spi-gxp.c [new file with mode: 0644]
drivers/spi/spi-intel-pci.c
drivers/spi/spi-intel.c
drivers/spi/spi-microchip-core.c [new file with mode: 0644]
drivers/spi/spi-mpc52xx-psc.c
drivers/spi/spi-npcm-fiu.c
drivers/spi/spi-pxa2xx.c
drivers/spi/spi-rspi.c
drivers/spi/spi-s3c64xx.c
drivers/spi/spi-sh.c
drivers/spi/spi-sifive.c
drivers/spi/spi-stm32-qspi.c
drivers/spi/spi-synquacer.c
drivers/spi/spi-tegra20-slink.c
drivers/spi/spi-tegra210-quad.c
drivers/spi/spi-ti-qspi.c
drivers/spi/spi-topcliff-pch.c
drivers/spi/spi-zynqmp-gqspi.c
drivers/spi/spi.c
drivers/staging/wlan-ng/hfa384x_usb.c
drivers/target/target_core_file.c
drivers/target/target_core_iblock.c
drivers/target/target_core_sbc.c
drivers/tee/optee/optee_smc.h
drivers/tee/optee/smc_abi.c
drivers/tee/tee_core.c
drivers/thermal/cpufreq_cooling.c
drivers/thermal/db8500_thermal.c
drivers/thermal/devfreq_cooling.c
drivers/thermal/gov_fair_share.c
drivers/thermal/gov_power_allocator.c
drivers/thermal/gov_step_wise.c
drivers/thermal/intel/intel_pch_thermal.c
drivers/thermal/intel/intel_tcc_cooling.c
drivers/thermal/intel/x86_pkg_temp_thermal.c
drivers/thermal/k3_j72xx_bandgap.c
drivers/thermal/qcom/qcom-spmi-adc-tm5.c
drivers/thermal/qcom/qcom-spmi-temp-alarm.c
drivers/thermal/qcom/tsens.c
drivers/thermal/qcom/tsens.h
drivers/thermal/rcar_gen3_thermal.c
drivers/thermal/rzg2l_thermal.c
drivers/thermal/sun8i_thermal.c
drivers/thermal/tegra/soctherm.c
drivers/thermal/tegra/tegra30-tsensor.c
drivers/thermal/thermal_core.c
drivers/thermal/thermal_core.h
drivers/thermal/thermal_helpers.c
drivers/thermal/thermal_netlink.c
drivers/thermal/thermal_of.c
drivers/thermal/thermal_sysfs.c
drivers/thermal/ti-soc-thermal/ti-bandgap.c
drivers/thunderbolt/Kconfig
drivers/thunderbolt/acpi.c
drivers/thunderbolt/domain.c
drivers/thunderbolt/tb.h
drivers/thunderbolt/test.c
drivers/tty/pty.c
drivers/tty/serial/8250/8250_core.c
drivers/tty/serial/8250/8250_dma.c
drivers/tty/serial/8250/8250_dw.c
drivers/tty/serial/8250/8250_port.c
drivers/tty/serial/Kconfig
drivers/tty/serial/amba-pl011.c
drivers/tty/serial/mvebu-uart.c
drivers/tty/serial/samsung_tty.c
drivers/tty/serial/serial_core.c
drivers/tty/serial/stm32-usart.c
drivers/tty/tty.h
drivers/tty/tty_buffer.c
drivers/tty/vt/vt.c
drivers/ufs/core/ufshcd.c
drivers/ufs/core/ufshpb.c
drivers/ufs/host/ufshcd-pltfrm.c
drivers/usb/core/usb-acpi.c
drivers/usb/dwc3/dwc3-am62.c
drivers/usb/dwc3/gadget.c
drivers/usb/gadget/function/uvc_configfs.c
drivers/usb/host/ehci-fsl.c
drivers/usb/host/fsl-mph-dr-of.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/typec/class.c
drivers/vdpa/mlx5/net/mlx5_vnet.c
drivers/vdpa/vdpa_user/vduse_dev.c
drivers/vfio/vfio.c
drivers/vhost/vdpa.c
drivers/video/console/sticore.c
drivers/video/fbdev/au1100fb.c
drivers/video/fbdev/cirrusfb.c
drivers/video/fbdev/core/fbcon.c
drivers/video/fbdev/core/fbmem.c
drivers/video/fbdev/intelfb/intelfbdrv.c
drivers/video/fbdev/intelfb/intelfbhw.c
drivers/video/fbdev/omap/sossi.c
drivers/video/fbdev/omap2/omapfb/dss/hdmi_phy.c
drivers/video/fbdev/pxa3xx-gcu.c
drivers/video/fbdev/simplefb.c
drivers/video/fbdev/skeletonfb.c
drivers/virt/coco/sev-guest/sev-guest.c
drivers/virt/nitro_enclaves/Kconfig
drivers/virt/nitro_enclaves/ne_misc_dev.c
drivers/virt/nitro_enclaves/ne_misc_dev_test.c
drivers/virtio/Kconfig
drivers/virtio/virtio.c
drivers/virtio/virtio_mmio.c
drivers/virtio/virtio_pci_modern_dev.c
drivers/virtio/virtio_ring.c
drivers/xen/events/events_base.c
drivers/xen/gntdev.c
fs/Makefile
fs/afs/file.c
fs/attr.c
fs/btrfs/block-group.h
fs/btrfs/check-integrity.c
fs/btrfs/compression.c
fs/btrfs/compression.h
fs/btrfs/ctree.h
fs/btrfs/delayed-inode.c
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/file.c
fs/btrfs/inode.c
fs/btrfs/locking.c
fs/btrfs/raid56.c
fs/btrfs/reflink.c
fs/btrfs/send.c
fs/btrfs/tests/btrfs-tests.c
fs/btrfs/transaction.c
fs/btrfs/zoned.c
fs/btrfs/zoned.h
fs/buffer.c
fs/cachefiles/ondemand.c
fs/ceph/addr.c
fs/ceph/caps.c
fs/cifs/cifs_debug.c
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/connect.c
fs/cifs/misc.c
fs/cifs/sess.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/crypto/fscrypt_private.h
fs/crypto/keysetup.c
fs/crypto/policy.c
fs/direct-io.c
fs/dlm/Kconfig
fs/dlm/Makefile
fs/dlm/ast.c
fs/dlm/config.c
fs/dlm/config.h
fs/dlm/dlm_internal.h
fs/dlm/lock.c
fs/dlm/lock.h
fs/dlm/lockspace.c
fs/dlm/lowcomms.c
fs/dlm/member.c
fs/dlm/plock.c
fs/dlm/recoverd.c
fs/dlm/user.c
fs/erofs/compress.h
fs/erofs/data.c
fs/erofs/decompressor.c
fs/erofs/decompressor_lzma.c
fs/erofs/dir.c
fs/erofs/zdata.c
fs/erofs/zdata.h
fs/erofs/zpvec.h [deleted file]
fs/exec.c
fs/exfat/namei.c
fs/ext2/inode.c
fs/ext2/super.c
fs/ext4/ext4.h
fs/ext4/fast_commit.c
fs/ext4/inode.c
fs/ext4/mmp.c
fs/ext4/super.c
fs/f2fs/data.c
fs/f2fs/f2fs.h
fs/f2fs/file.c
fs/f2fs/node.c
fs/f2fs/recovery.c
fs/f2fs/segment.c
fs/fat/file.c
fs/fscache/cookie.c
fs/fscache/volume.c
fs/gfs2/bmap.c
fs/gfs2/dir.c
fs/gfs2/log.c
fs/gfs2/log.h
fs/gfs2/lops.c
fs/gfs2/lops.h
fs/gfs2/meta_io.c
fs/gfs2/quota.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/part_tbl.c
fs/hfsplus/super.c
fs/hfsplus/wrapper.c
fs/hugetlbfs/inode.c
fs/inode.c
fs/io_uring.c [deleted file]
fs/iomap/buffered-io.c
fs/iomap/direct-io.c
fs/isofs/compress.c
fs/jbd2/commit.c
fs/jbd2/journal.c
fs/jbd2/recovery.c
fs/jfs/file.c
fs/ksmbd/smb2pdu.c
fs/ksmbd/transport_rdma.c
fs/ksmbd/transport_tcp.c
fs/ksmbd/vfs.c
fs/ksmbd/vfs.h
fs/lockd/svcsubs.c
fs/locks.c
fs/mpage.c
fs/netfs/buffered_read.c
fs/nfs/blocklayout/blocklayout.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsd.h
fs/nfsd/vfs.c
fs/nilfs2/btnode.c
fs/nilfs2/btnode.h
fs/nilfs2/btree.c
fs/nilfs2/gcinode.c
fs/nilfs2/mdt.c
fs/nilfs2/nilfs.h
fs/notify/fanotify/fanotify.c
fs/notify/fanotify/fanotify.h
fs/notify/fanotify/fanotify_user.c
fs/notify/fdinfo.c
fs/notify/fsnotify.c
fs/notify/inotify/inotify_user.c
fs/ntfs/aops.c
fs/ntfs/attrib.c
fs/ntfs/compress.c
fs/ntfs/file.c
fs/ntfs/logfile.c
fs/ntfs/mft.c
fs/ntfs3/file.c
fs/ntfs3/fsntfs.c
fs/ntfs3/inode.c
fs/ntfs3/ntfs_fs.h
fs/ocfs2/aops.c
fs/ocfs2/buffer_head_io.c
fs/ocfs2/cluster/heartbeat.c
fs/ocfs2/file.c
fs/ocfs2/ocfs2.h
fs/ocfs2/slot_map.c
fs/ocfs2/super.c
fs/open.c
fs/overlayfs/copy_up.c
fs/overlayfs/inode.c
fs/overlayfs/overlayfs.h
fs/posix_acl.c
fs/pstore/platform.c
fs/pstore/zone.c
fs/quota/dquot.c
fs/read_write.c
fs/reiserfs/inode.c
fs/reiserfs/journal.c
fs/reiserfs/stree.c
fs/reiserfs/super.c
fs/remap_range.c
fs/udf/dir.c
fs/udf/directory.c
fs/udf/inode.c
fs/ufs/balloc.c
fs/userfaultfd.c
fs/verity/Kconfig
fs/xattr.c
fs/xfs/libxfs/xfs_attr.c
fs/xfs/libxfs/xfs_attr.h
fs/xfs/libxfs/xfs_attr_leaf.c
fs/xfs/libxfs/xfs_attr_leaf.h
fs/xfs/xfs_attr_item.c
fs/xfs/xfs_bio_io.c
fs/xfs/xfs_bmap_util.c
fs/xfs/xfs_buf.c
fs/xfs/xfs_file.c
fs/xfs/xfs_icache.c
fs/xfs/xfs_icache.h
fs/xfs/xfs_inode.c
fs/xfs/xfs_iomap.c
fs/xfs/xfs_iops.c
fs/xfs/xfs_linux.h
fs/xfs/xfs_log.c
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_mount.h
fs/xfs/xfs_qm_syscalls.c
fs/xfs/xfs_super.c
fs/xfs/xfs_trace.h
fs/zonefs/super.c
fs/zonefs/trace.h
include/acpi/acpi_bus.h
include/acpi/cppc_acpi.h
include/acpi/processor.h
include/asm-generic/Kbuild
include/asm-generic/archrandom.h [new file with mode: 0644]
include/asm-generic/barrier.h
include/asm-generic/io.h
include/asm-generic/tlb.h
include/clocksource/timer-ti-dm.h
include/crypto/aria.h [new file with mode: 0644]
include/crypto/internal/blake2s.h
include/crypto/polyval.h [new file with mode: 0644]
include/drm/gpu_scheduler.h
include/dt-bindings/clock/exynos7885.h
include/dt-bindings/clock/nuvoton,npcm845-clk.h [new file with mode: 0644]
include/dt-bindings/clock/qcom,dispcc-sm8350.h [new symlink]
include/dt-bindings/clock/qcom,gcc-ipq8074.h
include/dt-bindings/clock/qcom,gpucc-sm8350.h [new file with mode: 0644]
include/dt-bindings/clock/qcom,sm8450-camcc.h [new file with mode: 0644]
include/dt-bindings/clock/sunplus,sp7021-clkc.h [new file with mode: 0644]
include/dt-bindings/clock/tegra234-clock.h
include/dt-bindings/mailbox/qcom-ipcc.h
include/dt-bindings/memory/tegra234-mc.h
include/dt-bindings/net/pcs-rzn1-miic.h [new file with mode: 0644]
include/dt-bindings/power/mt6795-power.h [new file with mode: 0644]
include/dt-bindings/power/qcom-rpmpd.h
include/dt-bindings/power/tegra234-powergate.h
include/dt-bindings/reset/sunplus,sp7021-reset.h [new file with mode: 0644]
include/dt-bindings/reset/tegra234-reset.h
include/dt-bindings/soc/samsung,boot-mode.h [new file with mode: 0644]
include/kunit/test.h
include/linux/acpi.h
include/linux/acpi_viot.h
include/linux/audit.h
include/linux/bio.h
include/linux/blk-mq.h
include/linux/blk_types.h
include/linux/blkdev.h
include/linux/blktrace_api.h
include/linux/buffer_head.h
include/linux/cgroup-defs.h
include/linux/cgroup.h
include/linux/compiler_types.h
include/linux/context_tracking.h
include/linux/context_tracking_irq.h [new file with mode: 0644]
include/linux/context_tracking_state.h
include/linux/cpu.h
include/linux/cpuhotplug.h
include/linux/devfreq.h
include/linux/device-mapper.h
include/linux/dim.h
include/linux/dm-io.h
include/linux/dm-verity-loadpin.h [new file with mode: 0644]
include/linux/energy_model.h
include/linux/entry-common.h
include/linux/evm.h
include/linux/fanotify.h
include/linux/fbcon.h
include/linux/firmware/xlnx-zynqmp.h
include/linux/fs.h
include/linux/fscache.h
include/linux/fsnotify_backend.h
include/linux/gfp.h
include/linux/gpio/driver.h
include/linux/hardirq.h
include/linux/highmem.h
include/linux/hisi_acc_qm.h
include/linux/huge_mm.h
include/linux/ima.h
include/linux/intel-iommu.h
include/linux/io_uring_types.h [new file with mode: 0644]
include/linux/ioprio.h
include/linux/irq.h
include/linux/irqchip/mmp.h
include/linux/irqdesc.h
include/linux/jbd2.h
include/linux/jump_label.h
include/linux/kernel_stat.h
include/linux/kexec.h
include/linux/kvm_host.h
include/linux/lockdep.h
include/linux/lockref.h
include/linux/lsm_hook_defs.h
include/linux/lsm_hooks.h
include/linux/memregion.h
include/linux/mfd/bcm2835-pm.h
include/linux/mm.h
include/linux/mnt_idmapping.h
include/linux/module.h
include/linux/netdevice.h
include/linux/netfs.h
include/linux/nvme.h
include/linux/objtool.h
include/linux/of.h
include/linux/once_lite.h
include/linux/panic.h
include/linux/pci_ids.h
include/linux/perf/riscv_pmu.h
include/linux/perf_event.h
include/linux/phy.h
include/linux/pm_runtime.h
include/linux/pm_wakeup.h
include/linux/posix_acl.h
include/linux/posix_acl_xattr.h
include/linux/pwm.h
include/linux/quotaops.h
include/linux/random.h
include/linux/rcupdate.h
include/linux/rcupdate_trace.h
include/linux/rcutiny.h
include/linux/rcutree.h
include/linux/refcount.h
include/linux/regmap.h
include/linux/regulator/consumer.h
include/linux/regulator/driver.h
include/linux/reset.h
include/linux/rtsx_usb.h
include/linux/sched.h
include/linux/sched/rt.h
include/linux/sched/task.h
include/linux/sched/topology.h
include/linux/scmi_protocol.h
include/linux/security.h
include/linux/serial_core.h
include/linux/skbuff.h
include/linux/soc/mediatek/mtk-mutex.h
include/linux/socket.h
include/linux/spi/spi.h
include/linux/stmmac.h
include/linux/sysfb.h
include/linux/thermal.h
include/linux/tracepoint.h
include/linux/uio.h
include/linux/virtio_config.h
include/linux/wait.h
include/linux/watch_queue.h
include/linux/writeback.h
include/linux/xarray.h
include/linux/xattr.h
include/net/addrconf.h
include/net/amt.h
include/net/bluetooth/l2cap.h
include/net/cfg80211.h
include/net/compat.h
include/net/flow_offload.h
include/net/inet_connection_sock.h
include/net/inet_hashtables.h
include/net/inet_sock.h
include/net/ip.h
include/net/mac80211.h
include/net/netfilter/nf_tables.h
include/net/protocol.h
include/net/raw.h
include/net/route.h
include/net/sock.h
include/net/tcp.h
include/net/tls.h
include/net/udp.h
include/scsi/scsi_cmnd.h
include/scsi/scsi_device.h
include/scsi/scsi_host.h
include/sound/soc.h
include/trace/events/dlm.h
include/trace/events/f2fs.h
include/trace/events/io_uring.h
include/trace/events/iocost.h
include/trace/events/jbd2.h
include/trace/events/kmem.h
include/trace/events/nilfs2.h
include/trace/events/power.h
include/trace/events/scmi.h
include/trace/events/sock.h
include/trace/events/thermal.h
include/uapi/asm-generic/fcntl.h
include/uapi/drm/drm_fourcc.h
include/uapi/drm/i915_drm.h
include/uapi/linux/blkzoned.h
include/uapi/linux/bpf.h
include/uapi/linux/btrfs.h
include/uapi/linux/btrfs_tree.h
include/uapi/linux/can/bcm.h
include/uapi/linux/connector.h
include/uapi/linux/cycx_cfm.h
include/uapi/linux/dm-ioctl.h
include/uapi/linux/dm-log-userspace.h
include/uapi/linux/ethtool.h
include/uapi/linux/fanotify.h
include/uapi/linux/fiemap.h
include/uapi/linux/firewire-cdev.h
include/uapi/linux/fs.h
include/uapi/linux/fscrypt.h
include/uapi/linux/if_alg.h
include/uapi/linux/if_arcnet.h
include/uapi/linux/if_pppox.h
include/uapi/linux/if_tun.h
include/uapi/linux/igmp.h
include/uapi/linux/inet_diag.h
include/uapi/linux/inotify.h
include/uapi/linux/input.h
include/uapi/linux/io_uring.h
include/uapi/linux/ip.h
include/uapi/linux/ip_vs.h
include/uapi/linux/iso_fs.h
include/uapi/linux/jffs2.h
include/uapi/linux/kcov.h
include/uapi/linux/kvm.h
include/uapi/linux/loadpin.h [new file with mode: 0644]
include/uapi/linux/minix_fs.h
include/uapi/linux/mmc/ioctl.h
include/uapi/linux/mptcp.h
include/uapi/linux/ndctl.h
include/uapi/linux/net_dropmon.h
include/uapi/linux/netfilter/x_tables.h
include/uapi/linux/netfilter_arp/arp_tables.h
include/uapi/linux/netfilter_bridge/ebt_among.h
include/uapi/linux/netfilter_ipv4/ip_tables.h
include/uapi/linux/netfilter_ipv6/ip6_tables.h
include/uapi/linux/perf_event.h
include/uapi/linux/pkt_cls.h
include/uapi/linux/raid/md_p.h
include/uapi/linux/random.h
include/uapi/linux/romfs_fs.h
include/uapi/linux/rtnetlink.h
include/uapi/linux/sctp.h
include/uapi/linux/seg6.h
include/uapi/linux/seg6_iptunnel.h
include/uapi/linux/stm.h
include/uapi/linux/target_core_user.h
include/uapi/linux/tty.h
include/uapi/linux/ublk_cmd.h [new file with mode: 0644]
include/uapi/linux/usb/audio.h
include/uapi/linux/usb/cdc.h
include/uapi/linux/usb/ch9.h
include/uapi/linux/usb/raw_gadget.h
include/uapi/linux/usbdevice_fs.h
include/uapi/linux/vhost_types.h
include/uapi/linux/virtio_9p.h
include/uapi/linux/xfrm.h
include/uapi/rdma/hfi/hfi1_user.h
include/uapi/rdma/ib_user_verbs.h
include/uapi/rdma/rdma_user_cm.h
include/uapi/rdma/rdma_user_ioctl_cmds.h
include/uapi/scsi/fc/fc_els.h
include/uapi/scsi/scsi_bsg_fc.h
include/uapi/sound/asound.h
include/uapi/sound/firewire.h
include/uapi/sound/skl-tplg-interface.h
include/uapi/sound/sof/header.h
include/uapi/sound/usb_stream.h
include/video/of_display_timing.h
init/Kconfig
init/init_task.c
init/main.c
io_uring/Makefile [new file with mode: 0644]
io_uring/advise.c [new file with mode: 0644]
io_uring/advise.h [new file with mode: 0644]
io_uring/alloc_cache.h [new file with mode: 0644]
io_uring/cancel.c [new file with mode: 0644]
io_uring/cancel.h [new file with mode: 0644]
io_uring/epoll.c [new file with mode: 0644]
io_uring/epoll.h [new file with mode: 0644]
io_uring/fdinfo.c [new file with mode: 0644]
io_uring/fdinfo.h [new file with mode: 0644]
io_uring/filetable.c [new file with mode: 0644]
io_uring/filetable.h [new file with mode: 0644]
io_uring/fs.c [new file with mode: 0644]
io_uring/fs.h [new file with mode: 0644]
io_uring/io-wq.c [moved from fs/io-wq.c with 99% similarity]
io_uring/io-wq.h [new file with mode: 0644]
io_uring/io_uring.c [new file with mode: 0644]
io_uring/io_uring.h [new file with mode: 0644]
io_uring/kbuf.c [new file with mode: 0644]
io_uring/kbuf.h [new file with mode: 0644]
io_uring/msg_ring.c [new file with mode: 0644]
io_uring/msg_ring.h [new file with mode: 0644]
io_uring/net.c [new file with mode: 0644]
io_uring/net.h [new file with mode: 0644]
io_uring/nop.c [new file with mode: 0644]
io_uring/nop.h [new file with mode: 0644]
io_uring/notif.c [new file with mode: 0644]
io_uring/notif.h [new file with mode: 0644]
io_uring/opdef.c [new file with mode: 0644]
io_uring/opdef.h [new file with mode: 0644]
io_uring/openclose.c [new file with mode: 0644]
io_uring/openclose.h [new file with mode: 0644]
io_uring/poll.c [new file with mode: 0644]
io_uring/poll.h [new file with mode: 0644]
io_uring/refs.h [new file with mode: 0644]
io_uring/rsrc.c [new file with mode: 0644]
io_uring/rsrc.h [new file with mode: 0644]
io_uring/rw.c [new file with mode: 0644]
io_uring/rw.h [new file with mode: 0644]
io_uring/slist.h [moved from fs/io-wq.h with 56% similarity]
io_uring/splice.c [new file with mode: 0644]
io_uring/splice.h [new file with mode: 0644]
io_uring/sqpoll.c [new file with mode: 0644]
io_uring/sqpoll.h [new file with mode: 0644]
io_uring/statx.c [new file with mode: 0644]
io_uring/statx.h [new file with mode: 0644]
io_uring/sync.c [new file with mode: 0644]
io_uring/sync.h [new file with mode: 0644]
io_uring/tctx.c [new file with mode: 0644]
io_uring/tctx.h [new file with mode: 0644]
io_uring/timeout.c [new file with mode: 0644]
io_uring/timeout.h [new file with mode: 0644]
io_uring/uring_cmd.c [new file with mode: 0644]
io_uring/uring_cmd.h [new file with mode: 0644]
io_uring/xattr.c [new file with mode: 0644]
io_uring/xattr.h [new file with mode: 0644]
ipc/namespace.c
kernel/audit.c
kernel/bpf/core.c
kernel/bpf/helpers.c
kernel/bpf/verifier.c
kernel/cfi.c
kernel/cgroup/cgroup-internal.h
kernel/cgroup/cgroup-v1.c
kernel/cgroup/cgroup.c
kernel/cgroup/rstat.c
kernel/configs/x86_debug.config
kernel/context_tracking.c
kernel/cpu_pm.c
kernel/dma/direct.c
kernel/entry/common.c
kernel/events/core.c
kernel/events/ring_buffer.c
kernel/exit.c
kernel/extable.c
kernel/fork.c
kernel/groups.c
kernel/irq/Kconfig
kernel/irq/chip.c
kernel/irq/debugfs.c
kernel/irq/generic-chip.c
kernel/irq/ipi.c
kernel/irq/irqdesc.c
kernel/irq/irqdomain.c
kernel/irq/manage.c
kernel/irq/pm.c
kernel/jump_label.c
kernel/kcsan/.kunitconfig [new file with mode: 0644]
kernel/kexec_core.c
kernel/kexec_file.c
kernel/kthread.c
kernel/locking/lockdep.c
kernel/locking/rwsem.c
kernel/module/internal.h
kernel/module/kallsyms.c
kernel/module/main.c
kernel/nsproxy.c
kernel/panic.c
kernel/power/energy_model.c
kernel/power/qos.c
kernel/power/swap.c
kernel/power/user.c
kernel/printk/printk.c
kernel/ptrace.c
kernel/rcu/Kconfig
kernel/rcu/Kconfig.debug
kernel/rcu/rcu.h
kernel/rcu/rcuscale.c
kernel/rcu/rcutorture.c
kernel/rcu/refscale.c
kernel/rcu/srcutree.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/rcu/tree_stall.h
kernel/rcu/update.c
kernel/rseq.c
kernel/sched/core.c
kernel/sched/core_sched.c
kernel/sched/cpufreq_schedutil.c
kernel/sched/cputime.c
kernel/sched/deadline.c
kernel/sched/fair.c
kernel/sched/features.h
kernel/sched/idle.c
kernel/sched/pelt.h
kernel/sched/psi.c
kernel/sched/rt.c
kernel/sched/sched.h
kernel/sched/topology.c
kernel/signal.c
kernel/smp.c
kernel/softirq.c
kernel/sysctl.c
kernel/time/Kconfig
kernel/time/posix-timers.c
kernel/time/tick-sched.c
kernel/time/timekeeping.c
kernel/trace/Kconfig
kernel/trace/blktrace.c
kernel/trace/trace.c
kernel/trace/trace_events_hist.c
kernel/watch_queue.c
kernel/workqueue.c
lib/Kconfig.debug
lib/Kconfig.ubsan
lib/Makefile
lib/crypto/Kconfig
lib/crypto/Makefile
lib/crypto/blake2s-selftest.c
lib/crypto/blake2s.c
lib/crypto/sha1.c [moved from lib/sha1.c with 98% similarity]
lib/idr.c
lib/iov_iter.c
lib/kunit/executor.c
lib/kunit/executor_test.c
lib/kunit/test.c
lib/lockref.c
lib/mpi/mpi-add.c
lib/mpi/mpi-mul.c
lib/overflow_kunit.c
lib/sbitmap.c
lib/test_kasan.c
mm/damon/reclaim.c
mm/damon/vaddr.c
mm/filemap.c
mm/gup.c
mm/hmm.c
mm/hugetlb.c
mm/hwpoison-inject.c
mm/ioremap.c
mm/kasan/common.c
mm/kfence/core.c
mm/madvise.c
mm/memcontrol.c
mm/memory-failure.c
mm/memory.c
mm/memremap.c
mm/page-writeback.c
mm/page_alloc.c
mm/page_isolation.c
mm/rmap.c
mm/secretmem.c
mm/shmem.c
mm/slab.c
mm/slab.h
mm/slab_common.c
mm/slob.c
mm/slub.c
mm/sparse-vmemmap.c
mm/swap.c
mm/swap_slots.c
mm/usercopy.c
mm/userfaultfd.c
net/8021q/vlan_netlink.c
net/bluetooth/hci_core.c
net/bluetooth/hci_sync.c
net/bluetooth/l2cap_core.c
net/bluetooth/mgmt.c
net/bridge/br_netfilter_hooks.c
net/bridge/br_netlink.c
net/caif/caif_socket.c
net/can/bcm.c
net/compat.c
net/core/datagram.c
net/core/dev.c
net/core/filter.c
net/core/secure_seq.c
net/core/skbuff.c
net/core/sock_reuseport.c
net/decnet/af_decnet.c
net/dsa/port.c
net/dsa/switch.c
net/ipv4/af_inet.c
net/ipv4/ah4.c
net/ipv4/cipso_ipv4.c
net/ipv4/esp4.c
net/ipv4/fib_semantics.c
net/ipv4/fib_trie.c
net/ipv4/icmp.c
net/ipv4/igmp.c
net/ipv4/inet_connection_sock.c
net/ipv4/inet_timewait_sock.c
net/ipv4/inetpeer.c
net/ipv4/ip_forward.c
net/ipv4/ip_input.c
net/ipv4/ip_output.c
net/ipv4/ip_sockglue.c
net/ipv4/ip_tunnel_core.c
net/ipv4/netfilter/nf_reject_ipv4.c
net/ipv4/nexthop.c
net/ipv4/proc.c
net/ipv4/route.c
net/ipv4/syncookies.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp.c
net/ipv4/tcp_fastopen.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_metrics.c
net/ipv4/tcp_minisocks.c
net/ipv4/tcp_output.c
net/ipv4/tcp_recovery.c
net/ipv4/tcp_timer.c
net/ipv6/Kconfig
net/ipv6/addrconf.c
net/ipv6/af_inet6.c
net/ipv6/icmp.c
net/ipv6/ip6_input.c
net/ipv6/ip6_output.c
net/ipv6/mcast.c
net/ipv6/ping.c
net/ipv6/route.c
net/ipv6/seg6_hmac.c
net/ipv6/seg6_iptunnel.c
net/ipv6/seg6_local.c
net/ipv6/sit.c
net/ipv6/syncookies.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/mac80211/cfg.c
net/mac80211/iface.c
net/mac80211/rx.c
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/wme.c
net/mptcp/options.c
net/mptcp/pm.c
net/mptcp/pm_netlink.c
net/mptcp/pm_userspace.c
net/mptcp/protocol.c
net/mptcp/protocol.h
net/mptcp/subflow.c
net/ncsi/ncsi-manage.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_standalone.c
net/netfilter/nf_log_syslog.c
net/netfilter/nf_synproxy_core.c
net/netfilter/nf_tables_api.c
net/netfilter/nf_tables_core.c
net/netfilter/nf_tables_trace.c
net/netfilter/nfnetlink_queue.c
net/netfilter/nft_queue.c
net/netfilter/nft_set_hash.c
net/netfilter/nft_set_pipapo.c
net/rose/rose_route.c
net/rose/rose_timer.c
net/sched/act_api.c
net/sched/act_police.c
net/sched/cls_api.c
net/sctp/associola.c
net/sctp/protocol.c
net/sctp/stream.c
net/sctp/stream_sched.c
net/smc/smc_llc.c
net/socket.c
net/sunrpc/xdr.c
net/tipc/node.c
net/tipc/socket.c
net/tls/tls_device.c
net/tls/tls_main.c
net/tls/tls_sw.c
net/wireless/sme.c
net/xdp/xsk_buff_pool.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_state.c
samples/fprobe/fprobe_example.c
samples/kprobes/kprobe_example.c
samples/kprobes/kretprobe_example.c
scripts/Makefile.lib
scripts/Makefile.modinst
scripts/Makefile.vmlinux_o
scripts/clang-tools/gen_compile_commands.py
scripts/gdb/linux/symbols.py
scripts/gen_autoksyms.sh
scripts/get_feat.pl
scripts/kernel-doc
scripts/mod/modpost.c
scripts/remove-stale-files
scripts/sphinx-pre-install
security/Kconfig
security/apparmor/policy_unpack_test.c
security/integrity/evm/evm_crypto.c
security/integrity/evm/evm_main.c
security/integrity/ima/ima_appraise.c
security/integrity/ima/ima_crypto.c
security/integrity/ima/ima_efi.c
security/integrity/ima/ima_kexec.c
security/integrity/ima/ima_policy.c
security/integrity/ima/ima_template_lib.c
security/loadpin/Kconfig
security/loadpin/loadpin.c
security/safesetid/lsm.c
security/security.c
security/selinux/hooks.c
security/selinux/include/audit.h
security/selinux/include/avc.h
security/selinux/ss/policydb.h
security/selinux/ss/services.c
security/smack/smack_access.c
security/smack/smack_lsm.c
sound/pci/cs46xx/cs46xx.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c
sound/soc/codecs/ak4613.c
sound/soc/codecs/arizona.c
sound/soc/codecs/cs35l41-lib.c
sound/soc/codecs/cs35l41.c
sound/soc/codecs/cs47l15.c
sound/soc/codecs/cs47l92.c
sound/soc/codecs/madera.c
sound/soc/codecs/max98373-sdw.c
sound/soc/codecs/max98396.c
sound/soc/codecs/rt1308-sdw.c
sound/soc/codecs/rt1316-sdw.c
sound/soc/codecs/rt5640.c
sound/soc/codecs/rt5682-sdw.c
sound/soc/codecs/rt700-sdw.c
sound/soc/codecs/rt700.c
sound/soc/codecs/rt711-sdca-sdw.c
sound/soc/codecs/rt711-sdca.c
sound/soc/codecs/rt711-sdw.c
sound/soc/codecs/rt711.c
sound/soc/codecs/rt715-sdca-sdw.c
sound/soc/codecs/rt715-sdw.c
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/sgtl5000.h
sound/soc/codecs/tas2764.c
sound/soc/codecs/tas2764.h
sound/soc/codecs/tlv320adcx140.c
sound/soc/codecs/wcd9335.c
sound/soc/codecs/wcd938x.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8998.c
sound/soc/codecs/wm_adsp.c
sound/soc/generic/audio-graph-card2.c
sound/soc/intel/avs/topology.c
sound/soc/intel/boards/bytcr_wm5102.c
sound/soc/intel/boards/sof_rt5682.c
sound/soc/intel/boards/sof_sdw.c
sound/soc/intel/skylake/skl-nhlt.c
sound/soc/qcom/qdsp6/q6apm-dai.c
sound/soc/qcom/qdsp6/q6apm.c
sound/soc/soc-dapm.c
sound/soc/soc-ops.c
sound/soc/sof/intel/hda-dsp.c
sound/soc/sof/intel/hda-loader.c
sound/soc/sof/intel/hda-pcm.c
sound/soc/sof/intel/hda-stream.c
sound/soc/sof/intel/hda.h
sound/soc/sof/ipc3-topology.c
sound/soc/sof/mediatek/mt8186/mt8186.c
sound/soc/sof/pm.c
sound/soc/sof/sof-priv.h
sound/soc/ti/omap-mcbsp-priv.h
sound/soc/ti/omap-mcbsp-st.c
sound/soc/ti/omap-mcbsp.c
sound/usb/quirks-table.h
sound/usb/quirks.c
tools/Makefile
tools/arch/arm64/include/uapi/asm/kvm.h
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/include/uapi/asm/kvm.h
tools/arch/x86/include/uapi/asm/svm.h
tools/include/linux/objtool.h
tools/include/linux/sched/mm.h
tools/include/nolibc/Makefile
tools/include/nolibc/stdio.h
tools/include/nolibc/stdlib.h
tools/include/uapi/asm-generic/fcntl.h
tools/include/uapi/drm/i915_drm.h
tools/include/uapi/linux/bpf.h
tools/include/uapi/linux/fs.h
tools/include/uapi/linux/if_tun.h
tools/include/uapi/linux/kvm.h
tools/include/uapi/linux/perf_event.h
tools/include/uapi/linux/pkt_cls.h
tools/include/uapi/linux/seg6.h
tools/include/uapi/linux/usbdevice_fs.h
tools/include/uapi/linux/vhost.h
tools/include/uapi/sound/asound.h
tools/objtool/arch/x86/decode.c
tools/objtool/builtin-check.c
tools/objtool/check.c
tools/objtool/include/objtool/arch.h
tools/objtool/include/objtool/builtin.h
tools/objtool/include/objtool/check.h
tools/objtool/include/objtool/elf.h
tools/objtool/include/objtool/objtool.h
tools/objtool/objtool.c
tools/perf/builtin-inject.c
tools/perf/builtin-stat.c
tools/perf/builtin-trace.c
tools/perf/scripts/python/arm-cs-trace-disasm.py
tools/perf/tests/perf-time-to-tsc.c
tools/perf/trace/beauty/arch_errno_names.sh
tools/perf/util/bpf-loader.c
tools/perf/util/bpf-utils.c
tools/perf/util/bpf_off_cpu.c
tools/perf/util/bpf_skel/off_cpu.bpf.c
tools/perf/util/build-id.c
tools/perf/util/evsel.c
tools/perf/util/header.c
tools/perf/util/header.h
tools/perf/util/off_cpu.h
tools/perf/util/symbol-elf.c
tools/perf/util/synthetic-events.c
tools/perf/util/unwind-libunwind-local.c
tools/power/pm-graph/README
tools/power/pm-graph/bootgraph.py
tools/power/pm-graph/config/custom-timeline-functions.cfg
tools/power/pm-graph/sleepgraph.py
tools/power/x86/turbostat/turbostat.8
tools/power/x86/turbostat/turbostat.c
tools/spi/spidev_test.c
tools/testing/kunit/configs/arch_uml.config [new file with mode: 0644]
tools/testing/kunit/configs/coverage_uml.config [new file with mode: 0644]
tools/testing/kunit/kunit.py
tools/testing/kunit/kunit_config.py
tools/testing/kunit/kunit_kernel.py
tools/testing/kunit/kunit_parser.py
tools/testing/kunit/kunit_printer.py [new file with mode: 0644]
tools/testing/kunit/kunit_tool_test.py
tools/testing/selftests/Makefile
tools/testing/selftests/arm64/mte/Makefile
tools/testing/selftests/arm64/signal/Makefile
tools/testing/selftests/arm64/signal/test_signals.h
tools/testing/selftests/bpf/prog_tests/sockmap_ktls.c
tools/testing/selftests/bpf/progs/dynptr_fail.c
tools/testing/selftests/bpf/progs/dynptr_success.c
tools/testing/selftests/bpf/verifier/jmp32.c
tools/testing/selftests/bpf/verifier/jump.c
tools/testing/selftests/damon/_chk_dependency.sh
tools/testing/selftests/drivers/dma-buf/udmabuf.c
tools/testing/selftests/drivers/gpu/drm_mm.sh
tools/testing/selftests/drivers/s390x/uvdevice/Makefile
tools/testing/selftests/futex/functional/Makefile
tools/testing/selftests/gpio/Makefile
tools/testing/selftests/kcmp/kcmp_test.c
tools/testing/selftests/kselftest_deps.sh
tools/testing/selftests/kselftest_module.h
tools/testing/selftests/kvm/Makefile
tools/testing/selftests/kvm/rseq_test.c
tools/testing/selftests/landlock/Makefile
tools/testing/selftests/lib.mk
tools/testing/selftests/net/.gitignore
tools/testing/selftests/net/Makefile
tools/testing/selftests/net/bpf/Makefile
tools/testing/selftests/net/fib_nexthop_nongw.sh [new file with mode: 0755]
tools/testing/selftests/net/forwarding/Makefile
tools/testing/selftests/net/forwarding/lib.sh
tools/testing/selftests/net/io_uring_zerocopy_tx.c [new file with mode: 0644]
tools/testing/selftests/net/io_uring_zerocopy_tx.sh [new file with mode: 0755]
tools/testing/selftests/net/mptcp/Makefile
tools/testing/selftests/net/mptcp/diag.sh
tools/testing/selftests/net/mptcp/mptcp_connect.c
tools/testing/selftests/net/mptcp/mptcp_inq.c
tools/testing/selftests/net/mptcp/mptcp_sockopt.c
tools/testing/selftests/net/mptcp/pm_nl_ctl.c
tools/testing/selftests/net/mptcp/userspace_pm.sh
tools/testing/selftests/net/tun.c [new file with mode: 0644]
tools/testing/selftests/net/udpgro.sh
tools/testing/selftests/net/udpgro_bench.sh
tools/testing/selftests/net/udpgro_frglist.sh
tools/testing/selftests/net/udpgro_fwd.sh
tools/testing/selftests/net/udpgso_bench.sh
tools/testing/selftests/net/veth.sh
tools/testing/selftests/rcutorture/bin/kvm-check-branches.sh
tools/testing/selftests/rcutorture/bin/kvm-remote.sh
tools/testing/selftests/rcutorture/bin/kvm.sh
tools/testing/selftests/rseq/rseq-riscv.h
tools/testing/selftests/rseq/rseq.c
tools/testing/selftests/safesetid/Makefile
tools/testing/selftests/safesetid/safesetid-test.c
tools/testing/selftests/seccomp/seccomp_bpf.c
tools/testing/selftests/tc-testing/Makefile
tools/testing/selftests/tc-testing/tc-tests/actions/gact.json
tools/testing/selftests/timens/Makefile
tools/testing/selftests/timens/vfork_exec.c [new file with mode: 0644]
tools/testing/selftests/timers/adjtick.c
tools/testing/selftests/timers/alarmtimer-suspend.c
tools/testing/selftests/timers/change_skew.c
tools/testing/selftests/timers/clocksource-switch.c
tools/testing/selftests/timers/inconsistency-check.c
tools/testing/selftests/timers/nanosleep.c
tools/testing/selftests/timers/raw_skew.c
tools/testing/selftests/timers/skew_consistency.c
tools/testing/selftests/timers/valid-adjtimex.c
tools/testing/selftests/tpm2/settings [new file with mode: 0644]
tools/testing/selftests/vm/Makefile
tools/testing/selftests/vm/userfaultfd.c
tools/testing/selftests/wireguard/qemu/Makefile
tools/testing/selftests/wireguard/qemu/arch/arm.config
tools/testing/selftests/wireguard/qemu/arch/armeb.config
tools/testing/selftests/wireguard/qemu/arch/i686.config
tools/testing/selftests/wireguard/qemu/arch/m68k.config
tools/testing/selftests/wireguard/qemu/arch/mips.config
tools/testing/selftests/wireguard/qemu/arch/mipsel.config
tools/testing/selftests/wireguard/qemu/arch/powerpc.config
tools/testing/selftests/wireguard/qemu/arch/x86_64.config
tools/testing/selftests/wireguard/qemu/init.c
tools/testing/selftests/wireguard/qemu/kernel.config
tools/thermal/tmon/pid.c
tools/thermal/tmon/tmon.h
tools/vm/slabinfo.c

index 825fae8..71577c3 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -10,6 +10,8 @@
 # Please keep this list dictionary sorted.
 #
 Aaron Durbin <adurbin@google.com>
+Abel Vesa <abelvesa@kernel.org> <abel.vesa@nxp.com>
+Abel Vesa <abelvesa@kernel.org> <abelvesa@gmail.com>
 Abhinav Kumar <quic_abhinavk@quicinc.com> <abhinavk@codeaurora.org>
 Adam Oldham <oldhamca@gmail.com>
 Adam Radford <aradford@gmail.com>
@@ -58,10 +60,17 @@ Arnd Bergmann <arnd@arndb.de>
 Atish Patra <atishp@atishpatra.org> <atish.patra@wdc.com>
 Axel Dyks <xl@xlsigned.net>
 Axel Lin <axel.lin@gmail.com>
+Baolin Wang <baolin.wang@linux.alibaba.com> <baolin.wang@linaro.org>
+Baolin Wang <baolin.wang@linux.alibaba.com> <baolin.wang@spreadtrum.com>
+Baolin Wang <baolin.wang@linux.alibaba.com> <baolin.wang@unisoc.com>
+Baolin Wang <baolin.wang@linux.alibaba.com> <baolin.wang7@gmail.com>
 Bart Van Assche <bvanassche@acm.org> <bart.vanassche@sandisk.com>
 Bart Van Assche <bvanassche@acm.org> <bart.vanassche@wdc.com>
 Ben Gardner <bgardner@wabtec.com>
 Ben M Cahill <ben.m.cahill@intel.com>
+Ben Widawsky <bwidawsk@kernel.org> <ben@bwidawsk.net>
+Ben Widawsky <bwidawsk@kernel.org> <ben.widawsky@intel.com>
+Ben Widawsky <bwidawsk@kernel.org> <benjamin.widawsky@intel.com>
 Björn Steinbrink <B.Steinbrink@gmx.de>
 Björn Töpel <bjorn@kernel.org> <bjorn.topel@gmail.com>
 Björn Töpel <bjorn@kernel.org> <bjorn.topel@intel.com>
@@ -85,6 +94,7 @@ Christian Borntraeger <borntraeger@linux.ibm.com> <borntrae@de.ibm.com>
 Christian Brauner <brauner@kernel.org> <christian@brauner.io>
 Christian Brauner <brauner@kernel.org> <christian.brauner@canonical.com>
 Christian Brauner <brauner@kernel.org> <christian.brauner@ubuntu.com>
+Christian Marangi <ansuelsmth@gmail.com>
 Christophe Ricard <christophe.ricard@gmail.com>
 Christoph Hellwig <hch@lst.de>
 Colin Ian King <colin.king@intel.com> <colin.king@canonical.com>
@@ -129,6 +139,8 @@ Frank Rowand <frowand.list@gmail.com> <frowand@mvista.com>
 Frank Zago <fzago@systemfabricworks.com>
 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>
 Gerald Schaefer <gerald.schaefer@linux.ibm.com> <geraldsc@de.ibm.com>
 Gerald Schaefer <gerald.schaefer@linux.ibm.com> <gerald.schaefer@de.ibm.com>
 Gerald Schaefer <gerald.schaefer@linux.ibm.com> <geraldsc@linux.vnet.ibm.com>
@@ -165,6 +177,7 @@ Jan Glauber <jan.glauber@gmail.com> <jang@de.ibm.com>
 Jan Glauber <jan.glauber@gmail.com> <jang@linux.vnet.ibm.com>
 Jan Glauber <jan.glauber@gmail.com> <jglauber@cavium.com>
 Jarkko Sakkinen <jarkko@kernel.org> <jarkko.sakkinen@linux.intel.com>
+Jarkko Sakkinen <jarkko@kernel.org> <jarkko@profian.com>
 Jason Gunthorpe <jgg@ziepe.ca> <jgg@mellanox.com>
 Jason Gunthorpe <jgg@ziepe.ca> <jgg@nvidia.com>
 Jason Gunthorpe <jgg@ziepe.ca> <jgunthorpe@obsidianresearch.com>
@@ -364,6 +377,7 @@ Sean Nyekjaer <sean@geanix.com> <sean.nyekjaer@prevas.dk>
 Sebastian Reichel <sre@kernel.org> <sebastian.reichel@collabora.co.uk>
 Sebastian Reichel <sre@kernel.org> <sre@debian.org>
 Sedat Dilek <sedat.dilek@gmail.com> <sedat.dilek@credativ.de>
+Seth Forshee <sforshee@kernel.org> <seth.forshee@canonical.com>
 Shiraz Hashim <shiraz.linux.kernel@gmail.com> <shiraz.hashim@st.com>
 Shuah Khan <shuah@kernel.org> <shuahkhan@gmail.com>
 Shuah Khan <shuah@kernel.org> <shuah.khan@hp.com>
diff --git a/CREDITS b/CREDITS
index 7e85a53..40d3c65 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -627,6 +627,10 @@ S: 48287 Sawleaf
 S: Fremont, California 94539
 S: USA
 
+N: Tomas Cech
+E: sleep_walker@suse.com
+D: arm/palm treo support
+
 N: Florent Chabaud
 E: florent.chabaud@polytechnique.org
 D: software suspend
index e8797cd..cd14ecb 100644 (file)
@@ -260,6 +260,15 @@ Description:
                for discards, and don't read this file.
 
 
+What:          /sys/block/<disk>/queue/dma_alignment
+Date:          May 2022
+Contact:       linux-block@vger.kernel.org
+Description:
+               Reports the alignment that user space addresses must have to be
+               used for raw block device access with O_DIRECT and other driver
+               specific passthrough mechanisms.
+
+
 What:          /sys/block/<disk>/queue/fua
 Date:          May 2018
 Contact:       linux-block@vger.kernel.org
index 653d4c7..7271781 100644 (file)
@@ -938,3 +938,12 @@ Description:
                - 1: enable
 
                RW
+
+What:          /sys/class/hwmon/hwmonX/device/pec
+Description:
+               PEC support on I2C devices
+
+               - 0, off, n: disable
+               - 1, on, y: enable
+
+               RW
index bcc974d..df79e12 100644 (file)
@@ -493,12 +493,13 @@ What:             /sys/devices/system/cpu/cpuX/regs/
                /sys/devices/system/cpu/cpuX/regs/identification/
                /sys/devices/system/cpu/cpuX/regs/identification/midr_el1
                /sys/devices/system/cpu/cpuX/regs/identification/revidr_el1
+               /sys/devices/system/cpu/cpuX/regs/identification/smidr_el1
 Date:          June 2016
 Contact:       Linux ARM Kernel Mailing list <linux-arm-kernel@lists.infradead.org>
 Description:   AArch64 CPU registers
 
                'identification' directory exposes the CPU ID registers for
-               identifying model and revision of the CPU.
+               identifying model and revision of the CPU and SMCU.
 
 What:          /sys/devices/system/cpu/aarch32_el0
 Date:          May 2021
diff --git a/Documentation/ABI/testing/sysfs-driver-qat b/Documentation/ABI/testing/sysfs-driver-qat
new file mode 100644 (file)
index 0000000..185f81a
--- /dev/null
@@ -0,0 +1,49 @@
+What:          /sys/bus/pci/devices/<BDF>/qat/state
+Date:          June 2022
+KernelVersion: 5.20
+Contact:       qat-linux@intel.com
+Description:   (RW) Reports the current state of the QAT device. Write to
+               the file to start or stop the device.
+
+               The values are:
+
+               * up: the device is up and running
+               * down: the device is down
+
+
+               It is possible to transition the device from up to down only
+               if the device is up and vice versa.
+
+               This attribute is only available for qat_4xxx devices.
+
+What:          /sys/bus/pci/devices/<BDF>/qat/cfg_services
+Date:          June 2022
+KernelVersion: 5.20
+Contact:       qat-linux@intel.com
+Description:   (RW) Reports the current configuration of the QAT device.
+               Write to the file to change the configured services.
+
+               The values are:
+
+               * sym;asym: the device is configured for running crypto
+                 services
+               * dc: the device is configured for running compression services
+
+               It is possible to set the configuration only if the device
+               is in the `down` state (see /sys/bus/pci/devices/<BDF>/qat/state)
+
+               The following example shows how to change the configuration of
+               a device configured for running crypto services in order to
+               run data compression::
+
+                       # cat /sys/bus/pci/devices/<BDF>/qat/state
+                       up
+                       # cat /sys/bus/pci/devices/<BDF>/qat/cfg_services
+                       sym;asym
+                       # echo down > /sys/bus/pci/devices/<BDF>/qat/state
+                       # echo dc > /sys/bus/pci/devices/<BDF>/qat/cfg_services
+                       # echo up > /sys/bus/pci/devices/<BDF>/qat/state
+                       # cat /sys/bus/pci/devices/<BDF>/qat/cfg_services
+                       dc
+
+               This attribute is only available for qat_4xxx devices.
index ee0d6db..54d1bfd 100644 (file)
@@ -12,8 +12,9 @@ Description:
                configuration data to the guest userspace.
 
                The authoritative guest-side hardware interface documentation
-               to the fw_cfg device can be found in "docs/specs/fw_cfg.txt"
-               in the QEMU source tree.
+               to the fw_cfg device can be found in "docs/specs/fw_cfg.rst"
+               in the QEMU source tree, or online at:
+               https://qemu-project.gitlab.io/qemu/specs/fw_cfg.html
 
                **SysFS fw_cfg Interface**
 
index e549a61..252bfc1 100644 (file)
@@ -1,23 +1,22 @@
 config WARN_MISSING_DOCUMENTS
-
        bool "Warn if there's a missing documentation file"
        depends on COMPILE_TEST
        help
-          It is not uncommon that a document gets renamed.
-          This option makes the Kernel to check for missing dependencies,
-          warning when something is missing. Works only if the Kernel
-          is built from a git tree.
+         It is not uncommon that a document gets renamed.
+         This option makes the Kernel to check for missing dependencies,
+         warning when something is missing. Works only if the Kernel
+         is built from a git tree.
 
-          If unsure, select 'N'.
+         If unsure, select 'N'.
 
 config WARN_ABI_ERRORS
        bool "Warn if there are errors at ABI files"
        depends on COMPILE_TEST
        help
-          The files under Documentation/ABI should follow what's
-          described at Documentation/ABI/README. Yet, as they're manually
-          written, it would be possible that some of those files would
-          have errors that would break them for being parsed by
-          scripts/get_abi.pl. Add a check to verify them.
+         The files under Documentation/ABI should follow what's
+         described at Documentation/ABI/README. Yet, as they're manually
+         written, it would be possible that some of those files would
+         have errors that would break them for being parsed by
+         scripts/get_abi.pl. Add a check to verify them.
 
-          If unsure, select 'N'.
+         If unsure, select 'N'.
index 04ed8bf..a0f8164 100644 (file)
@@ -1844,10 +1844,10 @@ that meets this requirement.
 
 Furthermore, NMI handlers can be interrupted by what appear to RCU to be
 normal interrupts. One way that this can happen is for code that
-directly invokes rcu_irq_enter() and rcu_irq_exit() to be called
+directly invokes ct_irq_enter() and ct_irq_exit() to be called
 from an NMI handler. This astonishing fact of life prompted the current
-code structure, which has rcu_irq_enter() invoking
-rcu_nmi_enter() and rcu_irq_exit() invoking rcu_nmi_exit().
+code structure, which has ct_irq_enter() invoking
+ct_nmi_enter() and ct_irq_exit() invoking ct_nmi_exit().
 And yes, I also learned of this requirement the hard way.
 
 Loadable Modules
@@ -2195,7 +2195,7 @@ scheduling-clock interrupt be enabled when RCU needs it to be:
    sections, and RCU believes this CPU to be idle, no problem. This
    sort of thing is used by some architectures for light-weight
    exception handlers, which can then avoid the overhead of
-   rcu_irq_enter() and rcu_irq_exit() at exception entry and
+   ct_irq_enter() and ct_irq_exit() at exception entry and
    exit, respectively. Some go further and avoid the entireties of
    irq_enter() and irq_exit().
    Just make very sure you are running some of your tests with
@@ -2226,7 +2226,7 @@ scheduling-clock interrupt be enabled when RCU needs it to be:
 +-----------------------------------------------------------------------+
 | **Answer**:                                                           |
 +-----------------------------------------------------------------------+
-| One approach is to do ``rcu_irq_exit();rcu_irq_enter();`` every so    |
+| One approach is to do ``ct_irq_exit();ct_irq_enter();`` every so      |
 | often. But given that long-running interrupt handlers can cause other |
 | problems, not least for response time, shouldn't you work to keep     |
 | your interrupt handler's runtime within reasonable bounds?            |
index 794837e..e38c587 100644 (file)
@@ -97,12 +97,12 @@ warnings:
        which will include additional debugging information.
 
 -      A low-level kernel issue that either fails to invoke one of the
-       variants of rcu_user_enter(), rcu_user_exit(), rcu_idle_enter(),
-       rcu_idle_exit(), rcu_irq_enter(), or rcu_irq_exit() on the one
+       variants of rcu_eqs_enter(true), rcu_eqs_exit(true), ct_idle_enter(),
+       ct_idle_exit(), ct_irq_enter(), or ct_irq_exit() on the one
        hand, or that invokes one of them too many times on the other.
        Historically, the most frequent issue has been an omission
        of either irq_enter() or irq_exit(), which in turn invoke
-       rcu_irq_enter() or rcu_irq_exit(), respectively.  Building your
+       ct_irq_enter() or ct_irq_exit(), respectively.  Building your
        kernel with CONFIG_RCU_EQS_DEBUG=y can help track down these types
        of issues, which sometimes arise in architecture-specific code.
 
index 176298f..bf842b8 100644 (file)
@@ -184,6 +184,14 @@ cgroup v2 currently supports the following mount options.
        ignored on non-init namespace mounts.  Please refer to the
        Delegation section for details.
 
+  favordynmods
+        Reduce the latencies of dynamic cgroup modifications such as
+        task migrations and controller on/offs at the cost of making
+        hot path operations such as forks and exits more expensive.
+        The static usage pattern of creating a cgroup, enabling
+        controllers, and then seeding it with CLONE_INTO_CGROUP is
+        not affected by this option.
+
   memory_localevents
         Only populate memory.events with data for the current cgroup,
         and not any subtrees. This is legacy behaviour, the default
index 1042977..60c16b7 100644 (file)
@@ -20,6 +20,7 @@ Constructor parameters:
    size)
 5. the number of optional parameters (the parameters with an argument
    count as two)
+
        start_sector n          (default: 0)
                offset from the start of cache device in 512-byte sectors
        high_watermark n        (default: 50)
@@ -74,20 +75,21 @@ Constructor parameters:
                the origin volume in the last n milliseconds
 
 Status:
+
 1. error indicator - 0 if there was no error, otherwise error number
 2. the number of blocks
 3. the number of free blocks
 4. the number of blocks under writeback
-5. the number of read requests
-6. the number of read requests that hit the cache
-7. the number of write requests
-8. the number of write requests that hit uncommitted block
-9. the number of write requests that hit committed block
-10. the number of write requests that bypass the cache
-11. the number of write requests that are allocated in the cache
+5. the number of read blocks
+6. the number of read blocks that hit the cache
+7. the number of write blocks
+8. the number of write blocks that hit uncommitted block
+9. the number of write blocks that hit committed block
+10. the number of write blocks that bypass the cache
+11. the number of write blocks that are allocated in the cache
 12. the number of write requests that are blocked on the freelist
 13. the number of flush requests
-14. the number of discard requests
+14. the number of discarded blocks
 
 Messages:
        flush
index 035275f..e3776d7 100644 (file)
@@ -7,10 +7,9 @@ This list is the Linux Device List, the official registry of allocated
 device numbers and ``/dev`` directory nodes for the Linux operating
 system.
 
-The LaTeX version of this document is no longer maintained, nor is
-the document that used to reside at lanana.org.  This version in the
-mainline Linux kernel is the master document.  Updates shall be sent
-as patches to the kernel maintainers (see the
+The version of this document at lanana.org is no longer maintained.  This
+version in the mainline Linux kernel is the master document.  Updates
+shall be sent as patches to the kernel maintainers (see the
 :ref:`Documentation/process/submitting-patches.rst <submittingpatches>` document).
 Specifically explore the sections titled "CHAR and MISC DRIVERS", and
 "BLOCK LAYER" in the MAINTAINERS file to find the right maintainers
index 833edb0..b24e7c4 100644 (file)
@@ -7,10 +7,10 @@ as a PE/COFF image, thereby convincing EFI firmware loaders to load
 it as an EFI executable. The code that modifies the bzImage header,
 along with the EFI-specific entry point that the firmware loader
 jumps to are collectively known as the "EFI boot stub", and live in
-arch/x86/boot/header.S and arch/x86/boot/compressed/eboot.c,
+arch/x86/boot/header.S and drivers/firmware/efi/libstub/x86-stub.c,
 respectively. For ARM the EFI stub is implemented in
 arch/arm/boot/compressed/efi-header.S and
-arch/arm/boot/compressed/efi-stub.c. EFI stub code that is shared
+drivers/firmware/efi/libstub/arm32-stub.c. EFI stub code that is shared
 between architectures is in drivers/firmware/efi/libstub.
 
 For arm64, there is no compressed kernel support, so the Image itself
index 2522b11..0e990f7 100644 (file)
        arm64.nomte     [ARM64] Unconditionally disable Memory Tagging Extension
                        support
 
+       arm64.nosve     [ARM64] Unconditionally disable Scalable Vector
+                       Extension support
+
+       arm64.nosme     [ARM64] Unconditionally disable Scalable Matrix
+                       Extension support
+
        ataflop=        [HW,M68k]
 
        atarimouse=     [HW,MOUSE] Atari Mouse
                        nosocket -- Disable socket memory accounting.
                        nokmem -- Disable kernel memory accounting.
 
-       checkreqprot    [SELINUX] Set initial checkreqprot flag value.
+       checkreqprot=   [SELINUX] Set initial checkreqprot flag value.
                        Format: { "0" | "1" }
                        See security/selinux/Kconfig help text.
                        0 -- check protection applied by kernel (includes
                        (in particular on some ATI chipsets).
                        The kernel tries to set a reasonable default.
 
-       enforcing       [SELINUX] Set initial enforcing status.
+       enforcing=      [SELINUX] Set initial enforcing status.
                        Format: {"0" | "1"}
                        See security/selinux/Kconfig help text.
                        0 -- permissive (log only, no denials).
                        mem_encrypt=on:         Activate SME
                        mem_encrypt=off:        Do not activate SME
 
-                       Refer to Documentation/virt/kvm/amd-memory-encryption.rst
+                       Refer to Documentation/virt/kvm/x86/amd-memory-encryption.rst
                        for details on when memory encryption can be activated.
 
        mem_sleep_default=      [SUSPEND] Default system suspend mode:
                                improves system performance, but it may also
                                expose users to several CPU vulnerabilities.
                                Equivalent to: nopti [X86,PPC]
-                                              kpti=0 [ARM64]
+                                              if nokaslr then kpti=0 [ARM64]
                                               nospectre_v1 [X86,PPC]
                                               nobp=0 [S390]
                                               nospectre_v2 [X86,PPC,S390,ARM64]
                                               no_entry_flush [PPC]
                                               no_uaccess_flush [PPC]
                                               mmio_stale_data=off [X86]
+                                              retbleed=off [X86]
 
                                Exceptions:
                                               This does not have any effect on
                                               mds=full,nosmt [X86]
                                               tsx_async_abort=full,nosmt [X86]
                                               mmio_stale_data=full,nosmt [X86]
+                                              retbleed=auto,nosmt [X86]
 
        mminit_loglevel=
                        [KNL] When CONFIG_DEBUG_MEMORY_INIT is set, this
                        just as if they had also been called out in the
                        rcu_nocbs= boot parameter.
 
+                       Note that this argument takes precedence over
+                       the CONFIG_RCU_NOCB_CPU_DEFAULT_ALL option.
+
        noiotrap        [SH] Disables trapped I/O port accesses.
 
        noirqdebug      [X86-32] Disables the code which attempts to detect and
        noreplace-smp   [X86-32,SMP] Don't replace SMP instructions
                        with UP alternatives
 
-       nordrand        [X86] Disable kernel use of the RDRAND and
-                       RDSEED instructions even if they are supported
-                       by the processor.  RDRAND and RDSEED are still
-                       available to user space applications.
-
        noresume        [SWSUSP] Disables resume and restores original swap
                        space.
 
                        no-callback mode from boot but the mode may be
                        toggled at runtime via cpusets.
 
+                       Note that this argument takes precedence over
+                       the CONFIG_RCU_NOCB_CPU_DEFAULT_ALL option.
+
        rcu_nocb_poll   [KNL]
                        Rather than requiring that offloaded CPUs
                        (specified by rcu_nocbs= above) explicitly
                        When RCU_NOCB_CPU is set, also adjust the
                        priority of NOCB callback kthreads.
 
+       rcutree.rcu_divisor= [KNL]
+                       Set the shift-right count to use to compute
+                       the callback-invocation batch limit bl from
+                       the number of callbacks queued on this CPU.
+                       The result will be bounded below by the value of
+                       the rcutree.blimit kernel parameter.  Every bl
+                       callbacks, the softirq handler will exit in
+                       order to allow the CPU to do other work.
+
+                       Please note that this callback-invocation batch
+                       limit applies only to non-offloaded callback
+                       invocation.  Offloaded callbacks are instead
+                       invoked in the context of an rcuoc kthread, which
+                       scheduler will preempt as it does any other task.
+
+       rcutree.nocb_nobypass_lim_per_jiffy= [KNL]
+                       On callback-offloaded (rcu_nocbs) CPUs,
+                       RCU reduces the lock contention that would
+                       otherwise be caused by callback floods through
+                       use of the ->nocb_bypass list.  However, in the
+                       common non-flooded case, RCU queues directly to
+                       the main ->cblist in order to avoid the extra
+                       overhead of the ->nocb_bypass list and its lock.
+                       But if there are too many callbacks queued during
+                       a single jiffy, RCU pre-queues the callbacks into
+                       the ->nocb_bypass queue.  The definition of "too
+                       many" is supplied by this kernel boot parameter.
+
        rcutree.rcu_nocb_gp_stride= [KNL]
                        Set the number of NOCB callback kthreads in
                        each group, which defaults to the square root
 
        retain_initrd   [RAM] Keep initrd memory after extraction
 
+       retbleed=       [X86] Control mitigation of RETBleed (Arbitrary
+                       Speculative Code Execution with Return Instructions)
+                       vulnerability.
+
+                       off          - no mitigation
+                       auto         - automatically select a migitation
+                       auto,nosmt   - automatically select a mitigation,
+                                      disabling SMT if necessary for
+                                      the full mitigation (only on Zen1
+                                      and older without STIBP).
+                       ibpb         - mitigate short speculation windows on
+                                      basic block boundaries too. Safe, highest
+                                      perf impact.
+                       unret        - force enable untrained return thunks,
+                                      only effective on AMD f15h-f17h
+                                      based systems.
+                       unret,nosmt  - like unret, will disable SMT when STIBP
+                                      is not available.
+
+                       Selecting 'auto' will choose a mitigation method at run
+                       time according to the CPU.
+
+                       Not specifying this option is equivalent to retbleed=auto.
+
        rfkill.default_state=
                0       "airplane mode".  All wifi, bluetooth, wimax, gps, fm,
                        etc. communication is blocked by default.
                        eibrs             - enhanced IBRS
                        eibrs,retpoline   - enhanced IBRS + Retpolines
                        eibrs,lfence      - enhanced IBRS + LFENCE
+                       ibrs              - use IBRS to protect kernel
 
                        Not specifying this option is equivalent to
                        spectre_v2=auto.
                        expediting.  Set to zero to disable automatic
                        expediting.
 
+       srcutree.srcu_max_nodelay [KNL]
+                       Specifies the number of no-delay instances
+                       per jiffy for which the SRCU grace period
+                       worker thread will be rescheduled with zero
+                       delay. Beyond this limit, worker thread will
+                       be rescheduled with a sleep delay of one jiffy.
+
+       srcutree.srcu_max_nodelay_phase [KNL]
+                       Specifies the per-grace-period phase, number of
+                       non-sleeping polls of readers. Beyond this limit,
+                       grace period worker thread will be rescheduled
+                       with a sleep delay of one jiffy, between each
+                       rescan of the readers, for a grace period phase.
+
+       srcutree.srcu_retry_check_delay [KNL]
+                       Specifies number of microseconds of non-sleeping
+                       delay between each non-sleeping poll of readers.
+
        srcutree.small_contention_lim [KNL]
                        Specifies the number of update-side contention
                        events per jiffy will be tolerated before
diff --git a/Documentation/admin-guide/perf/hns3-pmu.rst b/Documentation/admin-guide/perf/hns3-pmu.rst
new file mode 100644 (file)
index 0000000..578407e
--- /dev/null
@@ -0,0 +1,136 @@
+======================================
+HNS3 Performance Monitoring Unit (PMU)
+======================================
+
+HNS3(HiSilicon network system 3) Performance Monitoring Unit (PMU) is an
+End Point device to collect performance statistics of HiSilicon SoC NIC.
+On Hip09, each SICL(Super I/O cluster) has one PMU device.
+
+HNS3 PMU supports collection of performance statistics such as bandwidth,
+latency, packet rate and interrupt rate.
+
+Each HNS3 PMU supports 8 hardware events.
+
+HNS3 PMU driver
+===============
+
+The HNS3 PMU driver registers a perf PMU with the name of its sicl id.::
+
+  /sys/devices/hns3_pmu_sicl_<sicl_id>
+
+PMU driver provides description of available events, filter modes, format,
+identifier and cpumask in sysfs.
+
+The "events" directory describes the event code of all supported events
+shown in perf list.
+
+The "filtermode" directory describes the supported filter modes of each
+event.
+
+The "format" directory describes all formats of the config (events) and
+config1 (filter options) fields of the perf_event_attr structure.
+
+The "identifier" file shows version of PMU hardware device.
+
+The "bdf_min" and "bdf_max" files show the supported bdf range of each
+pmu device.
+
+The "hw_clk_freq" file shows the hardware clock frequency of each pmu
+device.
+
+Example usage of checking event code and subevent code::
+
+  $# cat /sys/devices/hns3_pmu_sicl_0/events/dly_tx_normal_to_mac_time
+  config=0x00204
+  $# cat /sys/devices/hns3_pmu_sicl_0/events/dly_tx_normal_to_mac_packet_num
+  config=0x10204
+
+Each performance statistic has a pair of events to get two values to
+calculate real performance data in userspace.
+
+The bits 0~15 of config (here 0x0204) are the true hardware event code. If
+two events have same value of bits 0~15 of config, that means they are
+event pair. And the bit 16 of config indicates getting counter 0 or
+counter 1 of hardware event.
+
+After getting two values of event pair in usersapce, the formula of
+computation to calculate real performance data is:::
+
+  counter 0 / counter 1
+
+Example usage of checking supported filter mode::
+
+  $# cat /sys/devices/hns3_pmu_sicl_0/filtermode/bw_ssu_rpu_byte_num
+  filter mode supported: global/port/port-tc/func/func-queue/
+
+Example usage of perf::
+
+  $# perf list
+  hns3_pmu_sicl_0/bw_ssu_rpu_byte_num/ [kernel PMU event]
+  hns3_pmu_sicl_0/bw_ssu_rpu_time/     [kernel PMU event]
+  ------------------------------------------
+
+  $# perf stat -g -e hns3_pmu_sicl_0/bw_ssu_rpu_byte_num,global=1/ -e hns3_pmu_sicl_0/bw_ssu_rpu_time,global=1/ -I 1000
+  or
+  $# perf stat -g -e hns3_pmu_sicl_0/config=0x00002,global=1/ -e hns3_pmu_sicl_0/config=0x10002,global=1/ -I 1000
+
+
+Filter modes
+--------------
+
+1. global mode
+PMU collect performance statistics for all HNS3 PCIe functions of IO DIE.
+Set the "global" filter option to 1 will enable this mode.
+Example usage of perf::
+
+  $# perf stat -a -e hns3_pmu_sicl_0/config=0x1020F,global=1/ -I 1000
+
+2. port mode
+PMU collect performance statistic of one whole physical port. The port id
+is same as mac id. The "tc" filter option must be set to 0xF in this mode,
+here tc stands for traffic class.
+
+Example usage of perf::
+
+  $# perf stat -a -e hns3_pmu_sicl_0/config=0x1020F,port=0,tc=0xF/ -I 1000
+
+3. port-tc mode
+PMU collect performance statistic of one tc of physical port. The port id
+is same as mac id. The "tc" filter option must be set to 0 ~ 7 in this
+mode.
+Example usage of perf::
+
+  $# perf stat -a -e hns3_pmu_sicl_0/config=0x1020F,port=0,tc=0/ -I 1000
+
+4. func mode
+PMU collect performance statistic of one PF/VF. The function id is BDF of
+PF/VF, its conversion formula::
+
+  func = (bus << 8) + (device << 3) + (function)
+
+for example:
+  BDF         func
+  35:00.0    0x3500
+  35:00.1    0x3501
+  35:01.0    0x3508
+
+In this mode, the "queue" filter option must be set to 0xFFFF.
+Example usage of perf::
+
+  $# perf stat -a -e hns3_pmu_sicl_0/config=0x1020F,bdf=0x3500,queue=0xFFFF/ -I 1000
+
+5. func-queue mode
+PMU collect performance statistic of one queue of PF/VF. The function id
+is BDF of PF/VF, the "queue" filter option must be set to the exact queue
+id of function.
+Example usage of perf::
+
+  $# perf stat -a -e hns3_pmu_sicl_0/config=0x1020F,bdf=0x3500,queue=0/ -I 1000
+
+6. func-intr mode
+PMU collect performance statistic of one interrupt of PF/VF. The function
+id is BDF of PF/VF, the "intr" filter option must be set to the exact
+interrupt id of function.
+Example usage of perf::
+
+  $# perf stat -a -e hns3_pmu_sicl_0/config=0x00301,bdf=0x3500,intr=0/ -I 1000
index 69b23f0..9c9ece8 100644 (file)
@@ -9,6 +9,7 @@ Performance monitor support
 
    hisi-pmu
    hisi-pcie-pmu
+   hns3-pmu
    imx-ddr
    qcom_l2_pmu
    qcom_l3_pmu
index aec2cd2..19754be 100644 (file)
@@ -612,8 +612,8 @@ the ``menu`` governor to be used on the systems that use the ``ladder`` governor
 by default this way, for example.
 
 The other kernel command line parameters controlling CPU idle time management
-described below are only relevant for the *x86* architecture and some of
-them affect Intel processors only.
+described below are only relevant for the *x86* architecture and references
+to ``intel_idle`` affect Intel processors only.
 
 The *x86* architecture support code recognizes three kernel command line
 options related to CPU idle time management: ``idle=poll``, ``idle=halt``,
@@ -635,10 +635,13 @@ idle, so it very well may hurt single-thread computations performance as well as
 energy-efficiency.  Thus using it for performance reasons may not be a good idea
 at all.]
 
-The ``idle=nomwait`` option disables the ``intel_idle`` driver and causes
-``acpi_idle`` to be used (as long as all of the information needed by it is
-there in the system's ACPI tables), but it is not allowed to use the
-``MWAIT`` instruction of the CPUs to ask the hardware to enter idle states.
+The ``idle=nomwait`` option prevents the use of ``MWAIT`` instruction of
+the CPU to enter idle states. When this option is used, the ``acpi_idle``
+driver will use the ``HLT`` instruction instead of ``MWAIT``. On systems
+running Intel processors, this option disables the ``intel_idle`` driver
+and forces the use of the ``acpi_idle`` driver instead. Note that in either
+case, ``acpi_idle`` driver will function only if all the information needed
+by it is in the system's ACPI tables.
 
 In addition to the architecture-level kernel command line options affecting CPU
 idle time management, there are parameters affecting individual ``CPUIdle``
index ddccd10..8ab042b 100644 (file)
@@ -38,8 +38,8 @@ acct
 
 If BSD-style process accounting is enabled these values control
 its behaviour. If free space on filesystem where the log lives
-goes below ``lowwater``% accounting suspends. If free space gets
-above ``highwater``% accounting resumes. ``frequency`` determines
+goes below ``lowwater``% accounting suspends. If free space gets
+above ``highwater``% accounting resumes. ``frequency`` determines
 how often do we check the amount of free space (value is in
 seconds). Default:
 
index ceeed7b..7d80e8c 100644 (file)
@@ -100,6 +100,7 @@ Bit  Log  Number  Reason that got the kernel tainted
  15  _/K   32768  kernel has been live patched
  16  _/X   65536  auxiliary taint, defined for and used by distros
  17  _/T  131072  kernel was built with the struct randomization plugin
+ 18  _/N  262144  an in-kernel test has been run
 ===  ===  ======  ========================================================
 
 Note: The character ``_`` is representing a blank in this table to make reading
diff --git a/Documentation/arm/google/chromebook-boot-flow.rst b/Documentation/arm/google/chromebook-boot-flow.rst
new file mode 100644 (file)
index 0000000..36da776
--- /dev/null
@@ -0,0 +1,69 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+======================================
+Chromebook Boot Flow
+======================================
+
+Most recent Chromebooks that use device tree are using the opensource
+depthcharge_ bootloader. Depthcharge_ expects the OS to be packaged as a `FIT
+Image`_ which contains an OS image as well as a collection of device trees. It
+is up to depthcharge_ to pick the right device tree from the `FIT Image`_ and
+provide it to the OS.
+
+The scheme that depthcharge_ uses to pick the device tree takes into account
+three variables:
+
+- Board name, specified at depthcharge_ compile time. This is $(BOARD) below.
+- Board revision number, determined at runtime (perhaps by reading GPIO
+  strappings, perhaps via some other method). This is $(REV) below.
+- SKU number, read from GPIO strappings at boot time. This is $(SKU) below.
+
+For recent Chromebooks, depthcharge_ creates a match list that looks like this:
+
+- google,$(BOARD)-rev$(REV)-sku$(SKU)
+- google,$(BOARD)-rev$(REV)
+- google,$(BOARD)-sku$(SKU)
+- google,$(BOARD)
+
+Note that some older Chromebooks use a slightly different list that may
+not include SKU matching or may prioritize SKU/rev differently.
+
+Note that for some boards there may be extra board-specific logic to inject
+extra compatibles into the list, but this is uncommon.
+
+Depthcharge_ will look through all device trees in the `FIT Image`_ trying to
+find one that matches the most specific compatible. It will then look
+through all device trees in the `FIT Image`_ trying to find the one that
+matches the *second most* specific compatible, etc.
+
+When searching for a device tree, depthcharge_ doesn't care where the
+compatible string falls within a device tree's root compatible string array.
+As an example, if we're on board "lazor", rev 4, SKU 0 and we have two device
+trees:
+
+- "google,lazor-rev5-sku0", "google,lazor-rev4-sku0", "qcom,sc7180"
+- "google,lazor", "qcom,sc7180"
+
+Then depthcharge_ will pick the first device tree even though
+"google,lazor-rev4-sku0" was the second compatible listed in that device tree.
+This is because it is a more specific compatible than "google,lazor".
+
+It should be noted that depthcharge_ does not have any smarts to try to
+match board or SKU revisions that are "close by". That is to say that
+if depthcharge_ knows it's on "rev4" of a board but there is no "rev4"
+device tree then depthcharge_ *won't* look for a "rev3" device tree.
+
+In general when any significant changes are made to a board the board
+revision number is increased even if none of those changes need to
+be reflected in the device tree. Thus it's fairly common to see device
+trees with multiple revisions.
+
+It should be noted that, taking into account the above system that
+depthcharge_ has, the most flexibility is achieved if the device tree
+supporting the newest revision(s) of a board omits the "-rev{REV}"
+compatible strings. When this is done then if you get a new board
+revision and try to run old software on it then we'll at pick the
+newest device tree we know about.
+
+.. _depthcharge: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/depthcharge/
+.. _`FIT Image`: https://doc.coreboot.org/lib/payloads/fit.html
index 2bda546..495ada7 100644 (file)
@@ -31,6 +31,8 @@ SoC-specific documents
 .. toctree::
    :maxdepth: 1
 
+   google/chromebook-boot-flow
+
    ixp4xx
 
    marvell
index 3d116fb..52b75a2 100644 (file)
@@ -171,96 +171,73 @@ HWCAP_PACG
     Documentation/arm64/pointer-authentication.rst.
 
 HWCAP2_DCPODP
-
     Functionality implied by ID_AA64ISAR1_EL1.DPB == 0b0010.
 
 HWCAP2_SVE2
-
     Functionality implied by ID_AA64ZFR0_EL1.SVEVer == 0b0001.
 
 HWCAP2_SVEAES
-
     Functionality implied by ID_AA64ZFR0_EL1.AES == 0b0001.
 
 HWCAP2_SVEPMULL
-
     Functionality implied by ID_AA64ZFR0_EL1.AES == 0b0010.
 
 HWCAP2_SVEBITPERM
-
     Functionality implied by ID_AA64ZFR0_EL1.BitPerm == 0b0001.
 
 HWCAP2_SVESHA3
-
     Functionality implied by ID_AA64ZFR0_EL1.SHA3 == 0b0001.
 
 HWCAP2_SVESM4
-
     Functionality implied by ID_AA64ZFR0_EL1.SM4 == 0b0001.
 
 HWCAP2_FLAGM2
-
     Functionality implied by ID_AA64ISAR0_EL1.TS == 0b0010.
 
 HWCAP2_FRINT
-
     Functionality implied by ID_AA64ISAR1_EL1.FRINTTS == 0b0001.
 
 HWCAP2_SVEI8MM
-
     Functionality implied by ID_AA64ZFR0_EL1.I8MM == 0b0001.
 
 HWCAP2_SVEF32MM
-
     Functionality implied by ID_AA64ZFR0_EL1.F32MM == 0b0001.
 
 HWCAP2_SVEF64MM
-
     Functionality implied by ID_AA64ZFR0_EL1.F64MM == 0b0001.
 
 HWCAP2_SVEBF16
-
     Functionality implied by ID_AA64ZFR0_EL1.BF16 == 0b0001.
 
 HWCAP2_I8MM
-
     Functionality implied by ID_AA64ISAR1_EL1.I8MM == 0b0001.
 
 HWCAP2_BF16
-
     Functionality implied by ID_AA64ISAR1_EL1.BF16 == 0b0001.
 
 HWCAP2_DGH
-
     Functionality implied by ID_AA64ISAR1_EL1.DGH == 0b0001.
 
 HWCAP2_RNG
-
     Functionality implied by ID_AA64ISAR0_EL1.RNDR == 0b0001.
 
 HWCAP2_BTI
-
     Functionality implied by ID_AA64PFR0_EL1.BT == 0b0001.
 
 HWCAP2_MTE
-
     Functionality implied by ID_AA64PFR1_EL1.MTE == 0b0010, as described
     by Documentation/arm64/memory-tagging-extension.rst.
 
 HWCAP2_ECV
-
     Functionality implied by ID_AA64MMFR0_EL1.ECV == 0b0001.
 
 HWCAP2_AFP
-
     Functionality implied by ID_AA64MFR1_EL1.AFP == 0b0001.
 
 HWCAP2_RPRES
-
     Functionality implied by ID_AA64ISAR2_EL1.RPRES == 0b0001.
 
 HWCAP2_MTE3
-
     Functionality implied by ID_AA64PFR1_EL1.MTE == 0b0011, as described
     by Documentation/arm64/memory-tagging-extension.rst.
 
@@ -301,6 +278,10 @@ HWCAP2_WFXT
 
     Functionality implied by ID_AA64ISAR2_EL1.WFXT == 0b0010.
 
+HWCAP2_EBF16
+
+    Functionality implied by ID_AA64ISAR1_EL1.BF16 == 0b0010.
+
 4. Unused AT_HWCAP bits
 -----------------------
 
index 901cd09..2a641ba 100644 (file)
@@ -33,9 +33,8 @@ AArch64 Linux memory layout with 4KB pages + 4 levels (48-bit)::
   0000000000000000     0000ffffffffffff         256TB          user
   ffff000000000000     ffff7fffffffffff         128TB          kernel logical memory map
  [ffff600000000000     ffff7fffffffffff]         32TB          [kasan shadow region]
-  ffff800000000000     ffff800007ffffff         128MB          bpf jit region
-  ffff800008000000     ffff80000fffffff         128MB          modules
-  ffff800010000000     fffffbffefffffff         124TB          vmalloc
+  ffff800000000000     ffff800007ffffff         128MB          modules
+  ffff800008000000     fffffbffefffffff         124TB          vmalloc
   fffffbfff0000000     fffffbfffdffffff         224MB          fixed mappings (top down)
   fffffbfffe000000     fffffbfffe7fffff           8MB          [guard region]
   fffffbfffe800000     fffffbffff7fffff          16MB          PCI I/O space
@@ -51,9 +50,8 @@ AArch64 Linux memory layout with 64KB pages + 3 levels (52-bit with HW support):
   0000000000000000     000fffffffffffff           4PB          user
   fff0000000000000     ffff7fffffffffff          ~4PB          kernel logical memory map
  [fffd800000000000     ffff7fffffffffff]        512TB          [kasan shadow region]
-  ffff800000000000     ffff800007ffffff         128MB          bpf jit region
-  ffff800008000000     ffff80000fffffff         128MB          modules
-  ffff800010000000     fffffbffefffffff         124TB          vmalloc
+  ffff800000000000     ffff800007ffffff         128MB          modules
+  ffff800008000000     fffffbffefffffff         124TB          vmalloc
   fffffbfff0000000     fffffbfffdffffff         224MB          fixed mappings (top down)
   fffffbfffe000000     fffffbfffe7fffff           8MB          [guard region]
   fffffbfffe800000     fffffbffff7fffff          16MB          PCI I/O space
index d27db84..33b04db 100644 (file)
@@ -82,10 +82,14 @@ stable kernels.
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A57      | #1319537        | ARM64_ERRATUM_1319367       |
 +----------------+-----------------+-----------------+-----------------------------+
+| ARM            | Cortex-A57      | #1742098        | ARM64_ERRATUM_1742098       |
++----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A72      | #853709         | N/A                         |
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A72      | #1319367        | ARM64_ERRATUM_1319367       |
 +----------------+-----------------+-----------------+-----------------------------+
+| ARM            | Cortex-A72      | #1655431        | ARM64_ERRATUM_1742098       |
++----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A73      | #858921         | ARM64_ERRATUM_858921        |
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A76      | #1188873,1418040| ARM64_ERRATUM_1418040       |
@@ -102,6 +106,8 @@ stable kernels.
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A510     | #2077057        | ARM64_ERRATUM_2077057       |
 +----------------+-----------------+-----------------+-----------------------------+
+| ARM            | Cortex-A510     | #2441009        | ARM64_ERRATUM_2441009       |
++----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A710     | #2119858        | ARM64_ERRATUM_2119858       |
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A710     | #2054223        | ARM64_ERRATUM_2054223       |
index 2eb5afd..18d7248 100644 (file)
@@ -17,6 +17,9 @@ solution to the problem to avoid everybody inventing their own.  The IDR
 provides the ability to map an ID to a pointer, while the IDA provides
 only ID allocation, and as a result is much more memory-efficient.
 
+The IDR interface is deprecated; please use the :doc:`XArray <xarray>`
+instead.
+
 IDR usage
 =========
 
index d6b3f94..0793c40 100644 (file)
@@ -223,7 +223,7 @@ Module Loading
 Inter Module support
 --------------------
 
-Refer to the file kernel/module.c for more information.
+Refer to the files in kernel/module/ for more information.
 
 Hardware Interfaces
 ===================
index ec575e7..bf28ac0 100644 (file)
@@ -4,31 +4,29 @@
 Memory Protection Keys
 ======================
 
-Memory Protection Keys for Userspace (PKU aka PKEYs) is a feature
-which is found on Intel's Skylake (and later) "Scalable Processor"
-Server CPUs. It will be available in future non-server Intel parts
-and future AMD processors.
-
-For anyone wishing to test or use this feature, it is available in
-Amazon's EC2 C5 instances and is known to work there using an Ubuntu
-17.04 image.
-
-Memory Protection Keys provides a mechanism for enforcing page-based
-protections, but without requiring modification of the page tables
-when an application changes protection domains.  It works by
-dedicating 4 previously ignored bits in each page table entry to a
-"protection key", giving 16 possible keys.
-
-There is also a new user-accessible register (PKRU) with two separate
-bits (Access Disable and Write Disable) for each key.  Being a CPU
-register, PKRU is inherently thread-local, potentially giving each
+Memory Protection Keys provide a mechanism for enforcing page-based
+protections, but without requiring modification of the page tables when an
+application changes protection domains.
+
+Pkeys Userspace (PKU) is a feature which can be found on:
+        * Intel server CPUs, Skylake and later
+        * Intel client CPUs, Tiger Lake (11th Gen Core) and later
+        * Future AMD CPUs
+
+Pkeys work by dedicating 4 previously Reserved bits in each page table entry to
+a "protection key", giving 16 possible keys.
+
+Protections for each key are defined with a per-CPU user-accessible register
+(PKRU).  Each of these is a 32-bit register storing two bits (Access Disable
+and Write Disable) for each of 16 keys.
+
+Being a CPU register, PKRU is inherently thread-local, potentially giving each
 thread a different set of protections from every other thread.
 
-There are two new instructions (RDPKRU/WRPKRU) for reading and writing
-to the new register.  The feature is only available in 64-bit mode,
-even though there is theoretically space in the PAE PTEs.  These
-permissions are enforced on data access only and have no effect on
-instruction fetches.
+There are two instructions (RDPKRU/WRPKRU) for reading and writing to the
+register.  The feature is only available in 64-bit mode, even though there is
+theoretically space in the PAE PTEs.  These permissions are enforced on data
+access only and have no effect on instruction fetches.
 
 Syscalls
 ========
index 5ad9e0a..12e4aec 100644 (file)
@@ -51,8 +51,8 @@ namespace ``USB_STORAGE``, use::
 The corresponding ksymtab entry struct ``kernel_symbol`` will have the member
 ``namespace`` set accordingly. A symbol that is exported without a namespace will
 refer to ``NULL``. There is no default namespace if none is defined. ``modpost``
-and kernel/module.c make use the namespace at build time or module load time,
-respectively.
+and kernel/module/main.c make use the namespace at build time or module load
+time, respectively.
 
 2.2 Using the DEFAULT_SYMBOL_NAMESPACE define
 =============================================
index 9c454de..d997606 100644 (file)
@@ -66,7 +66,7 @@ The wiki documentation always refers to the linux-next version of the script.
 
 For Semantic Patch Language(SmPL) grammar documentation refer to:
 
-http://coccinelle.lip6.fr/documentation.php
+https://coccinelle.gitlabpages.inria.fr/website/docs/main_grammar.html
 
 Using Coccinelle on the Linux kernel
 ------------------------------------
index a833ecf..e879737 100644 (file)
@@ -208,6 +208,14 @@ In general, the rules for selftests are
 Contributing new tests (details)
 ================================
 
+ * In your Makefile, use facilities from lib.mk by including it instead of
+   reinventing the wheel. Specify flags and binaries generation flags on
+   need basis before including lib.mk. ::
+
+    CFLAGS = $(KHDR_INCLUDES)
+    TEST_GEN_PROGS := close_range_test
+    include ../lib.mk
+
  * Use TEST_GEN_XXX if such binaries or files are generated during
    compiling.
 
@@ -230,13 +238,30 @@ Contributing new tests (details)
  * First use the headers inside the kernel source and/or git repo, and then the
    system headers.  Headers for the kernel release as opposed to headers
    installed by the distro on the system should be the primary focus to be able
-   to find regressions.
+   to find regressions. Use KHDR_INCLUDES in Makefile to include headers from
+   the kernel source.
 
  * If a test needs specific kernel config options enabled, add a config file in
    the test directory to enable them.
 
    e.g: tools/testing/selftests/android/config
 
+ * Create a .gitignore file inside test directory and add all generated objects
+   in it.
+
+ * Add new test name in TARGETS in selftests/Makefile::
+
+    TARGETS += android
+
+ * All changes should pass::
+
+    kselftest-{all,install,clean,gen_tar}
+    kselftest-{all,install,clean,gen_tar} O=abo_path
+    kselftest-{all,install,clean,gen_tar} O=rel_path
+    make -C tools/testing/selftests {all,install,clean,gen_tar}
+    make -C tools/testing/selftests {all,install,clean,gen_tar} O=abs_path
+    make -C tools/testing/selftests {all,install,clean,gen_tar} O=rel_path
+
 Test Module
 ===========
 
@@ -250,6 +275,14 @@ assist writing kernel modules that are for use with kselftest:
 - ``tools/testing/selftests/kselftest_module.h``
 - ``tools/testing/selftests/kselftest/module.sh``
 
+Note that test modules should taint the kernel with TAINT_TEST. This will
+happen automatically for modules which are in the ``tools/testing/``
+directory, or for modules which use the ``kselftest_module.h`` header above.
+Otherwise, you'll need to add ``MODULE_INFO(test, "Y")`` to your module
+source. selftests which do not load modules typically should not taint the
+kernel, but in cases where a non-test module is loaded, TEST_TAINT can be
+applied from userspace by writing to ``/proc/sys/kernel/tainted``.
+
 How to use
 ----------
 
@@ -308,6 +341,7 @@ A bare bones test module might look like this:
    KSTM_MODULE_LOADERS(test_foo);
    MODULE_AUTHOR("John Developer <jd@fooman.org>");
    MODULE_LICENSE("GPL");
+   MODULE_INFO(test, "Y");
 
 Example test script
 -------------------
index 653985c..cce2031 100644 (file)
@@ -192,6 +192,21 @@ via UML. To run tests on qemu, by default it requires two flags:
     if we have downloaded the microblaze toolchain from the 0-day
     website to a directory in our home directory called toolchains.
 
+This means that for most architectures, running under qemu is as simple as:
+
+.. code-block:: bash
+
+       ./tools/testing/kunit/kunit.py run --arch=x86_64
+
+When cross-compiling, we'll likely need to specify a different toolchain, for
+example:
+
+.. code-block:: bash
+
+       ./tools/testing/kunit/kunit.py run \
+               --arch=s390 \
+               --cross_compile=s390x-linux-gnu-
+
 If we want to run KUnit tests on an architecture not supported by
 the ``--arch`` flag, or want to run KUnit tests on qemu using a
 non-default configuration; then we can write our own``QemuConfig``.
@@ -214,14 +229,11 @@ as
                --jobs=12 \
                --qemu_config=./tools/testing/kunit/qemu_configs/x86_64.py
 
-To run existing KUnit tests on non-UML architectures, see:
-Documentation/dev-tools/kunit/non_uml.rst.
-
 Command-Line Arguments
 ======================
 
 kunit_tool has a number of other command-line arguments which can
-be useful for our test environment. Below the most commonly used
+be useful for our test environment. Below are the most commonly used
 command line arguments:
 
 - ``--help``: Lists all available options. To list common options,
@@ -245,3 +257,64 @@ command line arguments:
             added or modified. Instead, enable all tests
             which have satisfied dependencies by adding
             ``CONFIG_KUNIT_ALL_TESTS=y`` to your ``.kunitconfig``.
+
+- ``--kunitconfig``: Specifies the path or the directory of the ``.kunitconfig``
+  file. For example:
+
+  - ``lib/kunit/.kunitconfig`` can be the path of the file.
+
+  - ``lib/kunit`` can be the directory in which the file is located.
+
+  This file is used to build and run with a predefined set of tests
+  and their dependencies. For example, to run tests for a given subsystem.
+
+- ``--kconfig_add``: Specifies additional configuration options to be
+  appended to the ``.kunitconfig`` file. For example:
+
+  .. code-block::
+
+       ./tools/testing/kunit/kunit.py run --kconfig_add CONFIG_KASAN=y
+
+- ``--arch``: Runs tests on the specified architecture. The architecture
+  argument is same as the Kbuild ARCH environment variable.
+  For example, i386, x86_64, arm, um, etc. Non-UML architectures run on qemu.
+  Default is `um`.
+
+- ``--cross_compile``: Specifies the Kbuild toolchain. It passes the
+  same argument as passed to the ``CROSS_COMPILE`` variable used by
+  Kbuild. This will be the prefix for the toolchain
+  binaries such as GCC. For example:
+
+  - ``sparc64-linux-gnu-`` if we have the sparc toolchain installed on
+    our system.
+
+  - ``$HOME/toolchains/microblaze/gcc-9.2.0-nolibc/microblaze-linux/bin/microblaze-linux``
+    if we have downloaded the microblaze toolchain from the 0-day
+    website to a specified path in our home directory called toolchains.
+
+- ``--qemu_config``: Specifies the path to a file containing a
+  custom qemu architecture definition. This should be a python file
+  containing a `QemuArchParams` object.
+
+- ``--qemu_args``: Specifies additional qemu arguments, for example, ``-smp 8``.
+
+- ``--jobs``: Specifies the number of jobs (commands) to run simultaneously.
+  By default, this is set to the number of cores on your system.
+
+- ``--timeout``: Specifies the maximum number of seconds allowed for all tests to run.
+  This does not include the time taken to build the tests.
+
+- ``--kernel_args``: Specifies additional kernel command-line arguments. May be repeated.
+
+- ``--run_isolated``: If set, boots the kernel for each individual suite/test.
+  This is useful for debugging a non-hermetic test, one that
+  might pass/fail based on what ran before it.
+
+- ``--raw_output``: If set, generates unformatted output from kernel. Possible options are:
+
+   - ``all``: To view the full kernel output, use ``--raw_output=all``.
+
+   - ``kunit``: This is the default option and filters to KUnit output. Use ``--raw_output`` or ``--raw_output=kunit``.
+
+- ``--json``: If set, stores the test results in a JSON format and prints to `stdout` or
+  saves to a file if a filename is specified.
index c36f676..8e8c493 100644 (file)
@@ -15,7 +15,7 @@ It can be handy to create a bash function like:
 .. code-block:: bash
 
        function run_kunit() {
-         ( cd "$(git rev-parse --show-toplevel)" && ./tools/testing/kunit/kunit.py run $@ )
+         ( cd "$(git rev-parse --show-toplevel)" && ./tools/testing/kunit/kunit.py run "$@" )
        }
 
 .. note::
@@ -123,8 +123,7 @@ Putting it together into a copy-pastable sequence of commands:
 .. code-block:: bash
 
        # Append coverage options to the current config
-       $ echo -e "CONFIG_DEBUG_KERNEL=y\nCONFIG_DEBUG_INFO=y\nCONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y\nCONFIG_GCOV=y" >> .kunit/.kunitconfig
-       $ ./tools/testing/kunit/kunit.py run
+       $ ./tools/testing/kunit/kunit.py run --kunitconfig=.kunit/ --kunitconfig=tools/testing/kunit/configs/coverage_uml.config
        # Extract the coverage information from the build dir (.kunit/)
        $ lcov -t "my_kunit_tests" -o coverage.info -c -d .kunit/
 
index d62a042..44158ee 100644 (file)
@@ -505,7 +505,7 @@ By reusing the same ``cases`` array from above, we can write the test as a
                const char *str;
                const char *sha1;
        };
-       struct sha1_test_case cases[] = {
+       const struct sha1_test_case cases[] = {
                {
                        .str = "hello world",
                        .sha1 = "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed",
index 5e2017c..e6de1d7 100644 (file)
@@ -25,7 +25,14 @@ properties:
         items:
           - enum:
               - altr,socfpga-arria10-socdk
-              - enclustra,mercury-aa1
+          - const: altr,socfpga-arria10
+          - const: altr,socfpga
+
+      - description: Mercury+ AA1 boards
+        items:
+          - enum:
+              - google,chameleon-v3
+          - const: enclustra,mercury-aa1
           - const: altr,socfpga-arria10
           - const: altr,socfpga
 
@@ -47,6 +54,7 @@ properties:
         items:
           - enum:
               - altr,socfpga-stratix10-socdk
+              - altr,socfpga-stratix10-swvp
           - const: altr,socfpga-stratix10
 
       - description: SoCFPGA VT
diff --git a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
new file mode 100644 (file)
index 0000000..1895ce9
--- /dev/null
@@ -0,0 +1,87 @@
+# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/aspeed/aspeed.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Aspeed SoC based boards
+
+maintainers:
+  - Joel Stanley <joel@jms.id.au>
+
+properties:
+  $nodename:
+    const: '/'
+  compatible:
+    oneOf:
+      - description: AST2400 based boards
+        items:
+          - enum:
+              - facebook,galaxy100-bmc
+              - facebook,wedge100-bmc
+              - facebook,wedge40-bmc
+              - microsoft,olympus-bmc
+              - quanta,q71l-bmc
+              - tyan,palmetto-bmc
+              - yadro,vesnin-bmc
+          - const: aspeed,ast2400
+
+      - description: AST2500 based boards
+        items:
+          - enum:
+              - amd,ethanolx-bmc
+              - ampere,mtjade-bmc
+              - aspeed,ast2500-evb
+              - asrock,e3c246d4i-bmc
+              - asrock,romed8hm3-bmc
+              - bytedance,g220a-bmc
+              - facebook,cmm-bmc
+              - facebook,minipack-bmc
+              - facebook,tiogapass-bmc
+              - facebook,yamp-bmc
+              - facebook,yosemitev2-bmc
+              - facebook,wedge400-bmc
+              - hxt,stardragon4800-rep2-bmc
+              - ibm,mihawk-bmc
+              - ibm,mowgli-bmc
+              - ibm,romulus-bmc
+              - ibm,swift-bmc
+              - ibm,witherspoon-bmc
+              - ingrasys,zaius-bmc
+              - inspur,fp5280g2-bmc
+              - inspur,nf5280m6-bmc
+              - inspur,on5263m5-bmc
+              - intel,s2600wf-bmc
+              - inventec,lanyang-bmc
+              - lenovo,hr630-bmc
+              - lenovo,hr855xg2-bmc
+              - portwell,neptune-bmc
+              - qcom,centriq2400-rep-bmc
+              - supermicro,x11spi-bmc
+              - tyan,s7106-bmc
+              - tyan,s8036-bmc
+              - yadro,nicole-bmc
+              - yadro,vegman-n110-bmc
+              - yadro,vegman-rx20-bmc
+              - yadro,vegman-sx20-bmc
+          - const: aspeed,ast2500
+
+      - description: AST2600 based boards
+        items:
+          - enum:
+              - aspeed,ast2600-evb
+              - aspeed,ast2600-evb-a1
+              - facebook,bletchley-bmc
+              - facebook,cloudripper-bmc
+              - facebook,elbert-bmc
+              - facebook,fuji-bmc
+              - ibm,everest-bmc
+              - ibm,rainier-bmc
+              - ibm,tacoma-bmc
+              - inventec,transformer-bmc
+              - jabil,rbp-bmc
+              - nuvia,dc-scm-bmc
+              - quanta,s6q-bmc
+          - const: aspeed,ast2600
+
+additionalProperties: true
index 4e495e0..2b7848b 100644 (file)
@@ -163,9 +163,11 @@ properties:
           - const: microchip,sama7g5
           - const: microchip,sama7
 
-      - description: Microchip LAN9662 PCB8291 Evaluation Board.
+      - description: Microchip LAN9662 Evaluation Boards.
         items:
-          - const: microchip,lan9662-pcb8291
+          - enum:
+              - microchip,lan9662-pcb8291
+              - microchip,lan9662-pcb8309
           - const: microchip,lan9662
           - const: microchip,lan966
 
index 8b7e87f..958df32 100644 (file)
@@ -87,6 +87,13 @@ properties:
           - const: brcm,bcm53012
           - const: brcm,bcm4708
 
+      - description: BCM53015 based boards
+        items:
+          - enum:
+              - meraki,mr26
+          - const: brcm,bcm53015
+          - const: brcm,bcm4708
+
       - description: BCM53016 based boards
         items:
           - enum:
index 5fb4558..324e591 100644 (file)
@@ -28,6 +28,99 @@ properties:
           - const: brcm,bcm47622
           - const: brcm,bcmbca
 
+      - description: BCM4912 based boards
+        items:
+          - enum:
+              - asus,gt-ax6000
+              - brcm,bcm94912
+          - const: brcm,bcm4912
+          - const: brcm,bcmbca
+
+      - description: BCM63138 based boards
+        items:
+          - enum:
+              - brcm,bcm963138
+              - brcm,BCM963138DVT
+          - const: brcm,bcm63138
+          - const: brcm,bcmbca
+
+      - description: BCM63146 based boards
+        items:
+          - enum:
+              - brcm,bcm963146
+          - const: brcm,bcm63146
+          - const: brcm,bcmbca
+
+      - description: BCM63148 based boards
+        items:
+          - enum:
+              - brcm,bcm963148
+          - const: brcm,bcm63148
+          - const: brcm,bcmbca
+
+      - description: BCM63158 based boards
+        items:
+          - enum:
+              - brcm,bcm963158
+          - const: brcm,bcm63158
+          - const: brcm,bcmbca
+
+      - description: BCM63178 based boards
+        items:
+          - enum:
+              - brcm,bcm963178
+          - const: brcm,bcm63178
+          - const: brcm,bcmbca
+
+      - description: BCM6756 based boards
+        items:
+          - enum:
+              - brcm,bcm96756
+          - const: brcm,bcm6756
+          - const: brcm,bcmbca
+
+      - description: BCM6813 based boards
+        items:
+          - enum:
+              - brcm,bcm96813
+          - const: brcm,bcm6813
+          - const: brcm,bcmbca
+
+      - description: BCM6846 based boards
+        items:
+          - enum:
+              - brcm,bcm96846
+          - const: brcm,bcm6846
+          - const: brcm,bcmbca
+
+      - description: BCM6855 based boards
+        items:
+          - enum:
+              - brcm,bcm96855
+          - const: brcm,bcm6855
+          - const: brcm,bcmbca
+
+      - description: BCM6856 based boards
+        items:
+          - enum:
+              - brcm,bcm96856
+          - const: brcm,bcm6856
+          - const: brcm,bcmbca
+
+      - description: BCM6858 based boards
+        items:
+          - enum:
+              - brcm,bcm96858
+          - const: brcm,bcm6858
+          - const: brcm,bcmbca
+
+      - description: BCM6878 based boards
+        items:
+          - enum:
+              - brcm,bcm96878
+          - const: brcm,bcm6878
+          - const: brcm,bcmbca
+
 additionalProperties: true
 
 ...
index ed04650..5c2e3a5 100644 (file)
@@ -221,6 +221,7 @@ properties:
           - qcom,kpss-acc-v1
           - qcom,kpss-acc-v2
           - qcom,msm8226-smp
+          - qcom,msm8909-smp
           # Only valid on ARM 32-bit, see above for ARM v8 64-bit
           - qcom,msm8916-smp
           - renesas,apmu
diff --git a/Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt b/Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt
deleted file mode 100644 (file)
index a87ec15..0000000
+++ /dev/null
@@ -1,271 +0,0 @@
-NXP i.MX System Controller Firmware (SCFW)
---------------------------------------------------------------------
-
-The System Controller Firmware (SCFW) is a low-level system function
-which runs on a dedicated Cortex-M core to provide power, clock, and
-resource management. It exists on some i.MX8 processors. e.g. i.MX8QM
-(QM, QP), and i.MX8QX (QXP, DX).
-
-The AP communicates with the SC using a multi-ported MU module found
-in the LSIO subsystem. The current definition of this MU module provides
-5 remote AP connections to the SC to support up to 5 execution environments
-(TZ, HV, standard Linux, etc.). The SC side of this MU module interfaces
-with the LSIO DSC IP bus. The SC firmware will communicate with this MU
-using the MSI bus.
-
-System Controller Device Node:
-============================================================
-
-The scu node with the following properties shall be under the /firmware/ node.
-
-Required properties:
--------------------
-- compatible:  should be "fsl,imx-scu".
-- mbox-names:  should include "tx0", "tx1", "tx2", "tx3",
-                              "rx0", "rx1", "rx2", "rx3";
-               include "gip3" if want to support general MU interrupt.
-- mboxes:      List of phandle of 4 MU channels for tx, 4 MU channels for
-               rx, and 1 optional MU channel for general interrupt.
-               All MU channels must be in the same MU instance.
-               Cross instances are not allowed. The MU instance can only
-               be one of LSIO MU0~M4 for imx8qxp and imx8qm. Users need
-               to make sure use the one which is not conflict with other
-               execution environments. e.g. ATF.
-               Note:
-               Channel 0 must be "tx0" or "rx0".
-               Channel 1 must be "tx1" or "rx1".
-               Channel 2 must be "tx2" or "rx2".
-               Channel 3 must be "tx3" or "rx3".
-               General interrupt rx channel must be "gip3".
-               e.g.
-               mboxes = <&lsio_mu1 0 0
-                         &lsio_mu1 0 1
-                         &lsio_mu1 0 2
-                         &lsio_mu1 0 3
-                         &lsio_mu1 1 0
-                         &lsio_mu1 1 1
-                         &lsio_mu1 1 2
-                         &lsio_mu1 1 3
-                         &lsio_mu1 3 3>;
-               See Documentation/devicetree/bindings/mailbox/fsl,mu.yaml
-               for detailed mailbox binding.
-
-Note: Each mu which supports general interrupt should have an alias correctly
-numbered in "aliases" node.
-e.g.
-aliases {
-       mu1 = &lsio_mu1;
-};
-
-i.MX SCU Client Device Node:
-============================================================
-
-Client nodes are maintained as children of the relevant IMX-SCU device node.
-
-Power domain bindings based on SCU Message Protocol
-------------------------------------------------------------
-
-This binding for the SCU power domain providers uses the generic power
-domain binding[2].
-
-Required properties:
-- compatible:          Should be one of:
-                         "fsl,imx8qm-scu-pd",
-                         "fsl,imx8qxp-scu-pd"
-                       followed by "fsl,scu-pd"
-
-- #power-domain-cells: Must be 1. Contains the Resource ID used by
-                       SCU commands.
-                       See detailed Resource ID list from:
-                       include/dt-bindings/firmware/imx/rsrc.h
-
-Clock bindings based on SCU Message Protocol
-------------------------------------------------------------
-
-This binding uses the common clock binding[1].
-
-Required properties:
-- compatible:          Should be one of:
-                         "fsl,imx8dxl-clk"
-                         "fsl,imx8qm-clk"
-                         "fsl,imx8qxp-clk"
-                       followed by "fsl,scu-clk"
-- #clock-cells:                Should be 2.
-                       Contains the Resource and Clock ID value.
-- clocks:              List of clock specifiers, must contain an entry for
-                       each required entry in clock-names
-- clock-names:         Should include entries "xtal_32KHz", "xtal_24MHz"
-
-The clock consumer should specify the desired clock by having the clock
-ID in its "clocks" phandle cell.
-
-See the full list of clock IDs from:
-include/dt-bindings/clock/imx8qxp-clock.h
-
-Pinctrl bindings based on SCU Message Protocol
-------------------------------------------------------------
-
-This binding uses the i.MX common pinctrl binding[3].
-
-Required properties:
-- compatible:          Should be one of:
-                       "fsl,imx8qm-iomuxc",
-                       "fsl,imx8qxp-iomuxc",
-                       "fsl,imx8dxl-iomuxc".
-
-Required properties for Pinctrl sub nodes:
-- fsl,pins:            Each entry consists of 3 integers which represents
-                       the mux and config setting for one pin. The first 2
-                       integers <pin_id mux_mode> are specified using a
-                       PIN_FUNC_ID macro, which can be found in
-                       <dt-bindings/pinctrl/pads-imx8qm.h>,
-                       <dt-bindings/pinctrl/pads-imx8qxp.h>,
-                       <dt-bindings/pinctrl/pads-imx8dxl.h>.
-                       The last integer CONFIG is the pad setting value like
-                       pull-up on this pin.
-
-                       Please refer to i.MX8QXP Reference Manual for detailed
-                       CONFIG settings.
-
-[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
-[2] Documentation/devicetree/bindings/power/power-domain.yaml
-[3] Documentation/devicetree/bindings/pinctrl/fsl,imx-pinctrl.txt
-
-RTC bindings based on SCU Message Protocol
-------------------------------------------------------------
-
-Required properties:
-- compatible: should be "fsl,imx8qxp-sc-rtc";
-
-OCOTP bindings based on SCU Message Protocol
-------------------------------------------------------------
-Required properties:
-- compatible:          Should be one of:
-                       "fsl,imx8qm-scu-ocotp",
-                       "fsl,imx8qxp-scu-ocotp".
-- #address-cells:      Must be 1. Contains byte index
-- #size-cells:         Must be 1. Contains byte length
-
-Optional Child nodes:
-
-- Data cells of ocotp:
-  Detailed bindings are described in bindings/nvmem/nvmem.txt
-
-Watchdog bindings based on SCU Message Protocol
-------------------------------------------------------------
-
-Required properties:
-- compatible: should be:
-              "fsl,imx8qxp-sc-wdt"
-              followed by "fsl,imx-sc-wdt";
-Optional properties:
-- timeout-sec: contains the watchdog timeout in seconds.
-
-SCU key bindings based on SCU Message Protocol
-------------------------------------------------------------
-
-Required properties:
-- compatible: should be:
-              "fsl,imx8qxp-sc-key"
-              followed by "fsl,imx-sc-key";
-- linux,keycodes: See Documentation/devicetree/bindings/input/input.yaml
-
-Thermal bindings based on SCU Message Protocol
-------------------------------------------------------------
-
-Required properties:
-- compatible:                  Should be :
-                                 "fsl,imx8qxp-sc-thermal"
-                               followed by "fsl,imx-sc-thermal";
-
-- #thermal-sensor-cells:       See Documentation/devicetree/bindings/thermal/thermal-sensor.yaml
-                               for a description.
-
-Example (imx8qxp):
--------------
-aliases {
-       mu1 = &lsio_mu1;
-};
-
-lsio_mu1: mailbox@5d1c0000 {
-       ...
-       #mbox-cells = <2>;
-};
-
-firmware {
-       scu {
-               compatible = "fsl,imx-scu";
-               mbox-names = "tx0", "tx1", "tx2", "tx3",
-                            "rx0", "rx1", "rx2", "rx3",
-                            "gip3";
-               mboxes = <&lsio_mu1 0 0
-                         &lsio_mu1 0 1
-                         &lsio_mu1 0 2
-                         &lsio_mu1 0 3
-                         &lsio_mu1 1 0
-                         &lsio_mu1 1 1
-                         &lsio_mu1 1 2
-                         &lsio_mu1 1 3
-                         &lsio_mu1 3 3>;
-
-               clk: clk {
-                       compatible = "fsl,imx8qxp-clk", "fsl,scu-clk";
-                       #clock-cells = <2>;
-               };
-
-               iomuxc {
-                       compatible = "fsl,imx8qxp-iomuxc";
-
-                       pinctrl_lpuart0: lpuart0grp {
-                               fsl,pins = <
-                                       SC_P_UART0_RX_ADMA_UART0_RX     0x06000020
-                                       SC_P_UART0_TX_ADMA_UART0_TX     0x06000020
-                               >;
-                       };
-                       ...
-               };
-
-               ocotp: imx8qx-ocotp {
-                       compatible = "fsl,imx8qxp-scu-ocotp";
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-
-                       fec_mac0: mac@2c4 {
-                               reg = <0x2c4 8>;
-                       };
-               };
-
-               pd: imx8qx-pd {
-                       compatible = "fsl,imx8qxp-scu-pd", "fsl,scu-pd";
-                       #power-domain-cells = <1>;
-               };
-
-               rtc: rtc {
-                       compatible = "fsl,imx8qxp-sc-rtc";
-               };
-
-               scu_key: scu-key {
-                       compatible = "fsl,imx8qxp-sc-key", "fsl,imx-sc-key";
-                       linux,keycodes = <KEY_POWER>;
-               };
-
-               watchdog {
-                       compatible = "fsl,imx8qxp-sc-wdt", "fsl,imx-sc-wdt";
-                       timeout-sec = <60>;
-               };
-
-               tsens: thermal-sensor {
-                       compatible = "fsl,imx8qxp-sc-thermal", "fsl,imx-sc-thermal";
-                       #thermal-sensor-cells = <1>;
-               };
-       };
-};
-
-serial@5a060000 {
-       ...
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_lpuart0>;
-       clocks = <&uart0_clk IMX_SC_R_UART_0 IMX_SC_PM_CLK_PER>;
-       clock-names = "ipg";
-       power-domains = <&pd IMX_SC_R_UART_0>;
-};
index ef52437..7431579 100644 (file)
@@ -321,6 +321,7 @@ properties:
           - enum:
               - 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
           - const: toradex,apalis_imx6q
           - const: fsl,imx6q
@@ -670,30 +671,30 @@ properties:
       - description: i.MX6ULL Boards with Toradex Colibri iMX6ULL Modules
         items:
           - enum:
-              - toradex,colibri-imx6ull-aster     # Colibri iMX6ULL Module on Aster Carrier Board
-              - toradex,colibri-imx6ull-eval      # Colibri iMX6ULL Module on Colibri Evaluation Board V3
-              - toradex,colibri-imx6ull-iris      # Colibri iMX6ULL Module on Iris Carrier Board
-              - toradex,colibri-imx6ull-iris-v2   # Colibri iMX6ULL Module on Iris V2 Carrier Board
+              - toradex,colibri-imx6ull-aster     # Aster Carrier Board
+              - toradex,colibri-imx6ull-eval      # Colibri Evaluation Board V3
+              - toradex,colibri-imx6ull-iris      # Iris Carrier Board
+              - toradex,colibri-imx6ull-iris-v2   # Iris V2 Carrier Board
           - const: toradex,colibri-imx6ull        # Colibri iMX6ULL Module
           - const: fsl,imx6ull
 
       - description: i.MX6ULL Boards with Toradex Colibri iMX6ULL 1GB (eMMC) Module
         items:
           - enum:
-              - toradex,colibri-imx6ull-emmc-aster     # Colibri iMX6ULL 1G (eMMC) on Aster Carrier Board
-              - toradex,colibri-imx6ull-emmc-eval      # Colibri iMX6ULL 1G (eMMC) on Colibri Evaluation B. V3
-              - toradex,colibri-imx6ull-emmc-iris      # Colibri iMX6ULL 1G (eMMC) on Iris Carrier Board
-              - toradex,colibri-imx6ull-emmc-iris-v2   # Colibri iMX6ULL 1G (eMMC) on Iris V2 Carrier Board
+              - toradex,colibri-imx6ull-emmc-aster     # Aster Carrier Board
+              - toradex,colibri-imx6ull-emmc-eval      # Colibri Evaluation B. V3
+              - toradex,colibri-imx6ull-emmc-iris      # Iris Carrier Board
+              - toradex,colibri-imx6ull-emmc-iris-v2   # Iris V2 Carrier Board
           - const: toradex,colibri-imx6ull-emmc        # Colibri iMX6ULL 1GB (eMMC) Module
           - const: fsl,imx6ull
 
       - description: i.MX6ULL Boards with Toradex Colibri iMX6ULL Wi-Fi / BT Modules
         items:
           - enum:
-              - toradex,colibri-imx6ull-wifi-eval     # Colibri iMX6ULL Wi-Fi / BT M. on Colibri Eval. B. V3
-              - toradex,colibri-imx6ull-wifi-aster    # Colibri iMX6ULL Wi-Fi / BT M. on Aster Carrier Board
-              - toradex,colibri-imx6ull-wifi-iris     # Colibri iMX6ULL Wi-Fi / BT M. on Iris Carrier Board
-              - toradex,colibri-imx6ull-wifi-iris-v2  # Colibri iMX6ULL Wi-Fi / BT M. on Iris V2 Carrier Board
+              - toradex,colibri-imx6ull-wifi-eval     # Colibri Eval. B. V3
+              - toradex,colibri-imx6ull-wifi-aster    # Aster Carrier Board
+              - toradex,colibri-imx6ull-wifi-iris     # Iris Carrier Board
+              - toradex,colibri-imx6ull-wifi-iris-v2  # Iris V2 Carrier Board
           - const: toradex,colibri-imx6ull-wifi       # Colibri iMX6ULL Wi-Fi / BT Module
           - const: fsl,imx6ull
 
@@ -738,6 +739,8 @@ properties:
           - enum:
               - toradex,colibri-imx7s-aster     # Module on Aster Carrier Board
               - toradex,colibri-imx7s-eval-v3   # Module on Colibri Evaluation Board V3
+              - toradex,colibri-imx7s-iris      # Module on Iris Carrier Board
+              - toradex,colibri-imx7s-iris-v2   # Module on Iris Carrier Board V2
           - const: toradex,colibri-imx7s
           - const: fsl,imx7s
 
@@ -789,8 +792,10 @@ properties:
       - description: i.MX7D Boards with Toradex Colibri i.MX7D Module
         items:
           - enum:
-              - toradex,colibri-imx7d-aster   # Colibri iMX7D Module on Aster Carrier Board
-              - toradex,colibri-imx7d-eval-v3 # Colibri iMX7D Module on Colibri Evaluation Board V3
+              - toradex,colibri-imx7d-aster   # Aster Carrier Board
+              - toradex,colibri-imx7d-eval-v3 # Colibri Evaluation Board V3
+              - toradex,colibri-imx7d-iris    # Iris Carrier Board
+              - toradex,colibri-imx7d-iris-v2 # Iris Carrier Board V2
           - const: toradex,colibri-imx7d
           - const: fsl,imx7d
 
@@ -799,6 +804,8 @@ properties:
           - enum:
               - toradex,colibri-imx7d-emmc-aster    # Module on Aster Carrier Board
               - toradex,colibri-imx7d-emmc-eval-v3  # Module on Colibri Evaluation Board V3
+              - toradex,colibri-imx7d-emmc-iris     # Module on Iris Carrier Board
+              - toradex,colibri-imx7d-emmc-iris-v2  # Module on Iris Carrier Board V2
           - const: toradex,colibri-imx7d-emmc
           - const: fsl,imx7d
 
@@ -865,6 +872,12 @@ properties:
           - const: toradex,verdin-imx8mm          # Verdin iMX8M Mini Module
           - const: fsl,imx8mm
 
+      - description: PHYTEC phyCORE-i.MX8MM SoM based boards
+        items:
+          - const: phytec,imx8mm-phyboard-polis-rdk # phyBOARD-Polis RDK
+          - const: phytec,imx8mm-phycore-som        # phyCORE-i.MX8MM SoM
+          - const: fsl,imx8mm
+
       - description: Variscite VAR-SOM-MX8MM based boards
         items:
           - const: variscite,var-som-mx8mm-symphony
@@ -914,6 +927,8 @@ properties:
       - description: i.MX8MP based Boards
         items:
           - enum:
+              - dh,imx8mp-dhcom-som       # i.MX8MP DHCOM SoM
+              - dh,imx8mp-dhcom-pdk2      # i.MX8MP DHCOM SoM on PDK2 board
               - fsl,imx8mp-evk            # i.MX8MP EVK Board
               - gateworks,imx8mp-gw74xx   # i.MX8MP Gateworks Board
               - toradex,verdin-imx8mp     # Verdin iMX8M Plus Modules
@@ -952,6 +967,18 @@ properties:
           - const: toradex,verdin-imx8mp          # Verdin iMX8M Plus Module
           - const: fsl,imx8mp
 
+      - description:
+          TQMa8MPxL is a series of LGA SOM featuring NXP i.MX8MP system-on-chip
+          variants. It is designed to be soldered on different carrier boards.
+          All CPU variants use the same device tree hence only one compatible
+          is needed. MBa8MPxL mainboard can be used as starterkit or in a boxed
+          version as an industrial computing device.
+        items:
+          - enum:
+              - tq,imx8mp-tqma8mpql-mba8mpxl # TQ-Systems GmbH i.MX8MP TQMa8MPQL SOM on MBa8MPxL
+          - const: tq,imx8mp-tqma8mpql       # TQ-Systems GmbH i.MX8MP TQMa8MPQL SOM
+          - const: fsl,imx8mp
+
       - description: i.MX8MQ based Boards
         items:
           - enum:
@@ -1020,6 +1047,12 @@ properties:
               - fsl,imx8ulp-evk           # i.MX8ULP EVK Board
           - const: fsl,imx8ulp
 
+      - description: i.MX93 based Boards
+        items:
+          - enum:
+              - fsl,imx93-11x11-evk       # i.MX93 11x11 EVK Board
+          - const: fsl,imx93
+
       - description:
           Freescale Vybrid Platform Device Tree Bindings
 
diff --git a/Documentation/devicetree/bindings/arm/marvell/marvell,ac5.yaml b/Documentation/devicetree/bindings/arm/marvell/marvell,ac5.yaml
new file mode 100644 (file)
index 0000000..8960fb8
--- /dev/null
@@ -0,0 +1,32 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/marvell/marvell,ac5.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Marvell Alleycat5/5X Platforms
+
+maintainers:
+  - Chris Packham <chris.packham@alliedtelesis.co.nz>
+
+properties:
+  $nodename:
+    const: '/'
+  compatible:
+    oneOf:
+      - description: Alleycat5 (98DX25xx) Reference Design
+        items:
+          - enum:
+              - marvell,rd-ac5
+          - const: marvell,ac5
+
+      - description: Alleycat5X (98DX35xx) Reference Design
+        items:
+          - enum:
+              - marvell,rd-ac5x
+          - const: marvell,ac5x
+          - const: marvell,ac5
+
+additionalProperties: true
+
+...
index 4a2bd97..07c0ea9 100644 (file)
@@ -131,6 +131,36 @@ properties:
           - enum:
               - mediatek,mt8183-evb
           - const: mediatek,mt8183
+      - description: Google Hayato
+        items:
+          - const: google,hayato-rev1
+          - 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: 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,mt8192-evb
index 611f666..8585f6f 100644 (file)
@@ -26,6 +26,7 @@ properties:
               - mediatek,mt8135-pericfg
               - mediatek,mt8173-pericfg
               - mediatek,mt8183-pericfg
+              - mediatek,mt8186-pericfg
               - mediatek,mt8195-pericfg
               - mediatek,mt8516-pericfg
           - const: syscon
index 95e5137..43409e5 100644 (file)
@@ -8,6 +8,7 @@ title: NPCM Platforms Device Tree Bindings
 
 maintainers:
   - Jonathan Neuschäfer <j.neuschaefer@gmx.net>
+  - Tomer Maimon <tmaimon77@gmail.com>
 
 properties:
   $nodename:
@@ -26,4 +27,10 @@ properties:
               - nuvoton,npcm750-evb         # NPCM750 evaluation board
           - const: nuvoton,npcm750
 
+      - description: NPCM845 based boards
+        items:
+          - enum:
+              - nuvoton,npcm845-evb         # NPCM845 evaluation board
+          - const: nuvoton,npcm845
+
 additionalProperties: true
index fcb211a..94e72f2 100644 (file)
@@ -8,6 +8,7 @@ title: Global Control Registers block in Nuvoton SoCs
 
 maintainers:
   - Jonathan Neuschäfer <j.neuschaefer@gmx.net>
+  - Tomer Maimon <tmaimon77@gmail.com>
 
 description:
   The Global Control Registers (GCR) are a block of registers in Nuvoton SoCs
@@ -20,6 +21,7 @@ properties:
       - enum:
           - nuvoton,wpcm450-gcr
           - nuvoton,npcm750-gcr
+          - nuvoton,npcm845-gcr
       - const: syscon
       - const: simple-mfd
 
index 5c06d1b..fb1d00b 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: QCOM device tree bindings
 
 maintainers:
-  - Stephen Boyd <sboyd@codeaurora.org>
+  - Bjorn Andersson <bjorn.andersson@linaro.org>
 
 description: |
   Some qcom based bootloaders identify the dtb blob based on a set of
@@ -38,18 +38,24 @@ description: |
         msm8992
         msm8994
         msm8996
+        msm8998
+        qcs404
         sa8155p
         sa8540p
         sc7180
         sc7280
         sc8180x
         sc8280xp
+        sda660
         sdm630
         sdm632
+        sdm636
         sdm660
         sdm845
         sdx55
         sdx65
+        sm6125
+        sm6350
         sm7225
         sm8150
         sm8250
@@ -90,6 +96,11 @@ description: |
   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:
+  https://docs.kernel.org/arm/google/chromebook-boot-flow.html
+
 properties:
   $nodename:
     const: "/"
@@ -153,28 +164,50 @@ properties:
           - const: qcom,msm8974
 
       - items:
-          - enum:
-              - alcatel,idol347
-          - const: qcom,msm8916-mtp/1
           - const: qcom,msm8916-mtp
+          - const: qcom,msm8916-mtp/1
           - const: qcom,msm8916
 
       - items:
           - enum:
-              - longcheer,l8150
+              - alcatel,idol347
+              - asus,z00l
+              - huawei,g7
+              - longcheer,l8910
               - samsung,a3u-eur
               - samsung,a5u-eur
+              - samsung,j5
+              - samsung,serranove
+              - wingtech,wt88047
+          - const: qcom,msm8916
+
+      - items:
+          - const: longcheer,l8150
+          - const: qcom,msm8916-v1-qrd/9-v1
           - const: qcom,msm8916
 
       - items:
           - enum:
+              - lg,bullhead
+              - microsoft,talkman
+              - xiaomi,libra
+          - const: qcom,msm8992
+
+      - items:
+          - enum:
               - sony,karin_windy
+          - const: qcom,apq8094
+
+      - items:
+          - enum:
+              - huawei,angler
+              - microsoft,cityman
+              - sony,ivy-row
               - sony,karin-row
               - sony,satsuki-row
               - sony,sumire-row
               - sony,suzuran-row
-              - qcom,msm8994
-          - const: qcom,apq8094
+          - const: qcom,msm8994
 
       - items:
           - enum:
@@ -190,11 +223,26 @@ properties:
               - sony,kagura-row
               - sony,keyaki-row
               - xiaomi,gemini
+              - xiaomi,natrium
               - xiaomi,scorpio
           - const: qcom,msm8996
 
       - items:
           - enum:
+              - asus,novago-tp370ql
+              - fxtec,pro1
+              - hp,envy-x2
+              - lenovo,miix-630
+              - oneplus,cheeseburger
+              - oneplus,dumpling
+              - qcom,msm8998-mtp
+              - sony,xperia-lilac
+              - sony,xperia-maple
+              - sony,xperia-poplar
+          - const: qcom,msm8998
+
+      - items:
+          - enum:
               - qcom,ipq4019-ap-dk01.1-c1
               - qcom,ipq4019-ap-dk04.1-c3
               - qcom,ipq4019-ap-dk07.1-c1
@@ -214,19 +262,317 @@ properties:
               - qcom,ipq8074-hk10-c2
           - const: qcom,ipq8074
 
-      - items:
+      - description: Qualcomm Technologies, Inc. SC7180 IDP
+        items:
           - enum:
               - qcom,sc7180-idp
           - const: qcom,sc7180
 
-      - items:
-          - enum:
-              - qcom,sc7280-crd
-              - qcom,sc7280-idp
-              - qcom,sc7280-idp2
-              - google,hoglin
-              - google,piglin
-              - google,senor
+      - description: HP Chromebook x2 11c (rev1 - 2)
+        items:
+          - const: google,coachz-rev1
+          - const: google,coachz-rev2
+          - const: qcom,sc7180
+
+      - description: HP Chromebook x2 11c (newest rev)
+        items:
+          - const: google,coachz
+          - const: qcom,sc7180
+
+      - description: HP Chromebook x2 11c with LTE (rev1 - 2)
+        items:
+          - const: google,coachz-rev1-sku0
+          - const: google,coachz-rev2-sku0
+          - const: qcom,sc7180
+
+      - description: HP Chromebook x2 11c with LTE (newest rev)
+        items:
+          - const: google,coachz-sku0
+          - const: qcom,sc7180
+
+      - description: Lenovo Chromebook Duet 5 13 (rev2)
+        items:
+          - const: google,homestar-rev2
+          - const: google,homestar-rev23
+          - const: qcom,sc7180
+
+      - description: Lenovo Chromebook Duet 5 13 (rev3)
+        items:
+          - const: google,homestar-rev3
+          - const: qcom,sc7180
+
+      - description: Lenovo Chromebook Duet 5 13 (newest rev)
+        items:
+          - const: google,homestar
+          - const: qcom,sc7180
+
+      - description: Google Kingoftown (rev0)
+        items:
+          - const: google,kingoftown-rev0
+          - const: qcom,sc7180
+
+      - description: Google Kingoftown (newest rev)
+        items:
+          - const: google,kingoftown
+          - const: qcom,sc7180
+
+      - description: Acer Chromebook Spin 513 (rev0)
+        items:
+          - const: google,lazor-rev0
+          - const: qcom,sc7180
+
+      - description: Acer Chromebook Spin 513 (rev1 - 2)
+        items:
+          - const: google,lazor-rev1
+          - const: google,lazor-rev2
+          - const: qcom,sc7180
+
+      - description: Acer Chromebook Spin 513 (rev3 - 8)
+        items:
+          - const: google,lazor-rev3
+          - const: google,lazor-rev4
+          - const: google,lazor-rev5
+          - const: google,lazor-rev6
+          - const: google,lazor-rev7
+          - const: google,lazor-rev8
+          - const: qcom,sc7180
+
+      - description: Acer Chromebook Spin 513 (newest rev)
+        items:
+          - const: google,lazor
+          - const: qcom,sc7180
+
+      - description: Acer Chromebook Spin 513 with KB Backlight (rev1 - 2)
+        items:
+          - const: google,lazor-rev1-sku2
+          - const: google,lazor-rev2-sku2
+          - const: qcom,sc7180
+
+      - description: Acer Chromebook Spin 513 with KB Backlight (rev3 - 8)
+        items:
+          - const: google,lazor-rev3-sku2
+          - const: google,lazor-rev4-sku2
+          - const: google,lazor-rev5-sku2
+          - const: google,lazor-rev6-sku2
+          - const: google,lazor-rev7-sku2
+          - const: google,lazor-rev8-sku2
+          - const: qcom,sc7180
+
+      - description: Acer Chromebook Spin 513 with KB Backlight (newest rev)
+        items:
+          - const: google,lazor-sku2
+          - const: qcom,sc7180
+
+      - description: Acer Chromebook Spin 513 with LTE (rev1 - 2)
+        items:
+          - const: google,lazor-rev1-sku0
+          - const: google,lazor-rev2-sku0
+          - const: qcom,sc7180
+
+      - description: Acer Chromebook Spin 513 with LTE (rev3 - 8)
+        items:
+          - const: google,lazor-rev3-sku0
+          - const: google,lazor-rev4-sku0
+          - const: google,lazor-rev5-sku0
+          - const: google,lazor-rev6-sku0
+          - const: google,lazor-rev7-sku0
+          - const: google,lazor-rev8-sku0
+          - const: qcom,sc7180
+
+      - description: Acer Chromebook Spin 513 with LTE (newest rev)
+        items:
+          - const: google,lazor-sku0
+          - const: qcom,sc7180
+
+      - description: Acer Chromebook 511 (rev4 - rev8)
+        items:
+          - const: google,lazor-rev4-sku4
+          - const: google,lazor-rev5-sku4
+          - const: google,lazor-rev6-sku4
+          - const: google,lazor-rev7-sku4
+          - const: google,lazor-rev8-sku4
+          - const: qcom,sc7180
+
+      - description: Acer Chromebook 511 (newest rev)
+        items:
+          - const: google,lazor-sku4
+          - const: qcom,sc7180
+
+      - description: Acer Chromebook 511 without Touchscreen (rev4)
+        items:
+          - const: google,lazor-rev4-sku5
+          - const: qcom,sc7180
+
+      - description: Acer Chromebook 511 without Touchscreen (rev5 - rev8)
+        items:
+          - const: google,lazor-rev5-sku5
+          - const: google,lazor-rev5-sku6
+          - const: google,lazor-rev6-sku6
+          - const: google,lazor-rev7-sku6
+          - const: google,lazor-rev8-sku6
+          - const: qcom,sc7180
+
+      - description: Acer Chromebook 511 without Touchscreen (newest rev)
+        items:
+          - const: google,lazor-sku6
+          - const: qcom,sc7180
+
+      - description: Google Mrbland with AUO panel (rev0)
+        items:
+          - const: google,mrbland-rev0-sku0
+          - const: qcom,sc7180
+
+      - description: Google Mrbland with AUO panel (newest rev)
+        items:
+          - const: google,mrbland-sku1536
+          - const: qcom,sc7180
+
+      - description: Google Mrbland with BOE panel (rev0)
+        items:
+          - const: google,mrbland-rev0-sku16
+          - const: qcom,sc7180
+
+      - description: Google Mrbland with BOE panel (newest rev)
+        items:
+          - const: google,mrbland-sku1024
+          - const: google,mrbland-sku768
+          - const: qcom,sc7180
+
+      - description: Google Pazquel with Parade (newest rev)
+        items:
+          - const: google,pazquel-sku5
+          - const: qcom,sc7180
+
+      - description: Google Pazquel with TI (newest rev)
+        items:
+          - const: google,pazquel-sku1
+          - const: qcom,sc7180
+
+      - description: Google Pazquel with LTE and Parade (newest rev)
+        items:
+          - const: google,pazquel-sku4
+          - const: qcom,sc7180
+
+      - description: Google Pazquel with LTE and TI (newest rev)
+        items:
+          - const: google,pazquel-sku0
+          - const: google,pazquel-sku2
+          - const: qcom,sc7180
+
+      - description: Sharp Dynabook Chromebook C1 (rev1)
+        items:
+          - const: google,pompom-rev1
+          - const: qcom,sc7180
+
+      - description: Sharp Dynabook Chromebook C1 (rev2)
+        items:
+          - const: google,pompom-rev2
+          - const: qcom,sc7180
+
+      - description: Sharp Dynabook Chromebook C1 (newest rev)
+        items:
+          - const: google,pompom
+          - const: qcom,sc7180
+
+      - description: Sharp Dynabook Chromebook C1 with LTE (rev1)
+        items:
+          - const: google,pompom-rev1-sku0
+          - const: qcom,sc7180
+
+      - description: Sharp Dynabook Chromebook C1 with LTE (rev2)
+        items:
+          - const: google,pompom-rev2-sku0
+          - const: qcom,sc7180
+
+      - description: Sharp Dynabook Chromebook C1 with LTE (newest rev)
+        items:
+          - const: google,pompom-sku0
+          - const: qcom,sc7180
+
+      - description: Google Quackingstick (newest rev)
+        items:
+          - const: google,quackingstick-sku1537
+          - const: qcom,sc7180
+
+      - description: Google Quackingstick with LTE (newest rev)
+        items:
+          - const: google,quackingstick-sku1536
+          - const: qcom,sc7180
+
+      - description: Google Trogdor (newest rev)
+        items:
+          - const: google,trogdor
+          - const: qcom,sc7180
+
+      - description: Google Trogdor with LTE (newest rev)
+        items:
+          - const: google,trogdor-sku0
+          - const: qcom,sc7180
+
+      - description: Lenovo IdeaPad Chromebook Duet 3 with BOE panel (rev0)
+        items:
+          - const: google,wormdingler-rev0-sku16
+          - const: qcom,sc7180
+
+      - description: Lenovo IdeaPad Chromebook Duet 3 with BOE panel (newest rev)
+        items:
+          - const: google,wormdingler-sku1024
+          - const: qcom,sc7180
+
+      - description: Lenovo IdeaPad Chromebook Duet 3 with BOE panel and rt5682s (newest rev)
+        items:
+          - const: google,wormdingler-sku1025
+          - const: qcom,sc7180
+
+      - description: Lenovo IdeaPad Chromebook Duet 3 with INX panel (rev0)
+        items:
+          - const: google,wormdingler-rev0-sku0
+          - const: qcom,sc7180
+
+      - description: Lenovo IdeaPad Chromebook Duet 3 with INX panel (newest rev)
+        items:
+          - const: google,wormdingler-sku0
+          - const: qcom,sc7180
+
+      - description: Lenovo IdeaPad Chromebook Duet 3 with INX panel and rt5682s (newest rev)
+        items:
+          - const: google,wormdingler-sku1
+          - const: qcom,sc7180
+
+      - description: Qualcomm Technologies, Inc. sc7280 CRD platform (rev3 - 4)
+        items:
+          - const: qcom,sc7280-crd
+          - const: google,hoglin-rev3
+          - const: google,hoglin-rev4
+          - const: google,piglin-rev3
+          - const: google,piglin-rev4
+          - const: qcom,sc7280
+
+      - description: Qualcomm Technologies, Inc. sc7280 CRD platform (newest rev)
+        items:
+          - const: google,hoglin
+          - const: qcom,sc7280
+
+      - description: Qualcomm Technologies, Inc. sc7280 IDP SKU1 platform
+        items:
+          - const: qcom,sc7280-idp
+          - const: google,senor
+          - const: qcom,sc7280
+
+      - description: Qualcomm Technologies, Inc. sc7280 IDP SKU2 platform
+        items:
+          - const: qcom,sc7280-idp2
+          - const: google,piglin
+          - const: qcom,sc7280
+
+      - description: Google Herobrine (newest rev)
+        items:
+          - const: google,herobrine
+          - const: qcom,sc7280
+
+      - description: Google Villager (newest rev)
+        items:
+          - const: google,villager
           - const: qcom,sc7280
 
       - items:
@@ -238,16 +584,36 @@ properties:
 
       - items:
           - enum:
+              - lenovo,thinkpad-x13s
+              - qcom,sc8280xp-crd
               - qcom,sc8280xp-qrd
           - const: qcom,sc8280xp
 
       - items:
           - enum:
+              - sony,discovery-row
+              - sony,kirin-row
+              - sony,pioneer-row
+              - sony,voyager-row
+          - const: qcom,sdm630
+
+      - items:
+          - enum:
+              - inforce,ifc6560
+          - const: qcom,sda660
+
+      - items:
+          - enum:
               - fairphone,fp3
           - const: qcom,sdm632
 
       - items:
           - enum:
+              - sony,mermaid-row
+          - const: qcom,sdm636
+
+      - items:
+          - enum:
               - xiaomi,lavender
           - const: qcom,sdm660
 
@@ -271,6 +637,13 @@ properties:
 
       - items:
           - enum:
+              - qcom,qcs404-evb-1000
+              - qcom,qcs404-evb-4000
+          - const: qcom,qcs404-evb
+          - const: qcom,qcs404
+
+      - items:
+          - enum:
               - qcom,sa8155p-adp
           - const: qcom,sa8155p
 
@@ -281,24 +654,62 @@ properties:
 
       - items:
           - enum:
+              - lenovo,yoga-c630
+              - lg,judyln
+              - lg,judyp
+              - oneplus,enchilada
+              - oneplus,fajita
+              - qcom,sdm845-mtp
+              - shift,axolotl
+              - samsung,w737
+              - sony,akari-row
+              - sony,akatsuki-row
+              - sony,apollo-row
+              - thundercomm,db845c
+              - xiaomi,beryllium
+              - xiaomi,polaris
+          - const: qcom,sdm845
+
+      - items:
+          - enum:
+              - sony,pdx201
+          - const: qcom,sm6125
+
+      - items:
+          - enum:
+              - sony,pdx213
+          - const: qcom,sm6350
+
+      - items:
+          - enum:
               - fairphone,fp4
           - const: qcom,sm7225
 
       - items:
           - enum:
+              - microsoft,surface-duo
+              - qcom,sm8150-hdk
               - qcom,sm8150-mtp
+              - sony,bahamut-generic
+              - sony,griffin-generic
           - const: qcom,sm8150
 
       - items:
           - enum:
               - qcom,qrb5165-rb5
+              - qcom,sm8250-hdk
               - qcom,sm8250-mtp
+              - sony,pdx203-generic
+              - sony,pdx206-generic
           - const: qcom,sm8250
 
       - items:
           - enum:
+              - microsoft,surface-duo2
               - qcom,sm8350-hdk
               - qcom,sm8350-mtp
+              - sony,pdx214-generic
+              - sony,pdx215-generic
           - const: qcom,sm8350
 
       - items:
index cf9eb1e..7811ba6 100644 (file)
@@ -554,6 +554,11 @@ properties:
           - const: vamrs,rk3399pro-vmarc-som
           - const: rockchip,rk3399pro
 
+      - description: Radxa ROCK Pi S
+        items:
+          - const: radxa,rockpis
+          - const: rockchip,rk3308
+
       - description: Radxa Rock2 Square
         items:
           - const: radxa,rock2-square
diff --git a/Documentation/devicetree/bindings/arm/samsung/samsung-soc.yaml b/Documentation/devicetree/bindings/arm/samsung/samsung-soc.yaml
new file mode 100644 (file)
index 0000000..653f859
--- /dev/null
@@ -0,0 +1,40 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/samsung/samsung-soc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung S3C, S5P and Exynos SoC compatibles naming convention
+
+maintainers:
+  - Krzysztof Kozlowski <krzk@kernel.org>
+
+description: |
+  Guidelines for new compatibles for SoC blocks/components.
+  When adding new compatibles in new bindings, use the format::
+    samsung,SoC-IP
+
+  For example::
+    samsung,exynos5433-cmu-isp
+
+select:
+  properties:
+    compatible:
+      pattern: "^samsung,.*(s3c|s5pv|exynos)[0-9a-z]+.*$"
+  required:
+    - compatible
+
+properties:
+  compatible:
+    oneOf:
+      - description: Preferred naming style for compatibles of SoC components
+        pattern: "^samsung,(s3c|s5pv|exynos|exynosautov)[0-9]+-.*$"
+
+      # Legacy compatibles with wild-cards - list cannot grow with new bindings:
+      - enum:
+          - samsung,exynos4x12-pinctrl
+          - samsung,exynos4x12-usb2-phy
+          - samsung,s3c64xx-pinctrl
+          - samsung,s3c64xx-wakeup-eint
+
+additionalProperties: true
index 8b31565..4c605bc 100644 (file)
@@ -59,12 +59,18 @@ properties:
               - prt,prtt1s   # Protonic PRTT1S
           - const: st,stm32mp151
 
-      - description: DH STM32MP153 SoM based Boards
+      - description: DH STM32MP153 DHCOM SoM based Boards
         items:
           - const: dh,stm32mp153c-dhcom-drc02
           - const: dh,stm32mp153c-dhcom-som
           - const: st,stm32mp153
 
+      - description: DH STM32MP153 DHCOR SoM based Boards
+        items:
+          - const: dh,stm32mp153c-dhcor-drc-compact
+          - const: dh,stm32mp153c-dhcor-som
+          - const: st,stm32mp153
+
       - items:
           - enum:
               - shiratech,stm32mp157a-iot-box # IoT Box
diff --git a/Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml b/Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
new file mode 100644 (file)
index 0000000..def7d0c
--- /dev/null
@@ -0,0 +1,29 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) Sunplus Co., Ltd. 2021
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/sunplus,sp7021.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sunplus SP7021 Boards
+
+maintainers:
+  - qinjian <qinjian@cqplus1.com>
+
+description: |
+  ARM platforms using Sunplus SP7021, an ARM Cortex A7 (4-cores) based SoC.
+  Wiki: https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
+
+properties:
+  $nodename:
+    const: '/'
+  compatible:
+    items:
+      - enum:
+          - sunplus,sp7021-achip
+          - sunplus,sp7021-demo-v3
+      - const: sunplus,sp7021
+
+additionalProperties: true
+
+...
index 95278a6..0c23567 100644 (file)
@@ -863,6 +863,11 @@ properties:
           - const: yones-toptech,bs1078-v2
           - const: allwinner,sun6i-a31s
 
+      - description: X96 Mate TV box
+        items:
+          - const: hechuang,x96-mate
+          - const: allwinner,sun50i-h616
+
       - description: Xunlong OrangePi
         items:
           - const: xunlong,orangepi
@@ -963,4 +968,9 @@ properties:
           - const: xunlong,orangepi-zero-plus2-h3
           - const: allwinner,sun8i-h3
 
+      - description: Xunlong OrangePi Zero 2
+        items:
+          - const: xunlong,orangepi-zero2
+          - const: allwinner,sun50i-h616
+
 additionalProperties: true
index 8eee312..9956668 100644 (file)
@@ -29,10 +29,20 @@ properties:
   compatible:
     enum:
       - allwinner,sun5i-a13-mbus
+      - allwinner,sun8i-a33-mbus
+      - allwinner,sun8i-a50-mbus
+      - allwinner,sun8i-a83t-mbus
       - allwinner,sun8i-h3-mbus
       - allwinner,sun8i-r40-mbus
+      - allwinner,sun8i-v3s-mbus
+      - allwinner,sun8i-v536-mbus
+      - allwinner,sun20i-d1-mbus
       - allwinner,sun50i-a64-mbus
+      - allwinner,sun50i-a100-mbus
       - allwinner,sun50i-h5-mbus
+      - allwinner,sun50i-h6-mbus
+      - allwinner,sun50i-h616-mbus
+      - allwinner,sun50i-r329-mbus
 
   reg:
     minItems: 1
@@ -81,13 +91,13 @@ required:
   - dma-ranges
 
 if:
-  properties:
-    compatible:
-      contains:
-        enum:
-          - allwinner,sun8i-h3-mbus
-          - allwinner,sun50i-a64-mbus
-          - allwinner,sun50i-h5-mbus
+  not:
+    properties:
+      compatible:
+        contains:
+          enum:
+            - allwinner,sun5i-a13-mbus
+            - allwinner,sun8i-r40-mbus
 
 then:
   properties:
diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra194-axi2apb.yaml b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra194-axi2apb.yaml
new file mode 100644 (file)
index 0000000..788a13f
--- /dev/null
@@ -0,0 +1,40 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/arm/tegra/nvidia,tegra194-axi2apb.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: NVIDIA Tegra194 AXI2APB bridge
+
+maintainers:
+  - Sumit Gupta <sumitg@nvidia.com>
+
+properties:
+  $nodename:
+    pattern: "^axi2apb@([0-9a-f]+)$"
+
+  compatible:
+    enum:
+      - nvidia,tegra194-axi2apb
+
+  reg:
+    maxItems: 6
+    description: Physical base address and length of registers for all bridges
+
+additionalProperties: false
+
+required:
+  - compatible
+  - reg
+
+examples:
+  - |
+    axi2apb: axi2apb@2390000 {
+      compatible = "nvidia,tegra194-axi2apb";
+      reg = <0x02390000 0x1000>,
+            <0x023a0000 0x1000>,
+            <0x023b0000 0x1000>,
+            <0x023c0000 0x1000>,
+            <0x023d0000 0x1000>,
+            <0x023e0000 0x1000>;
+    };
diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra194-cbb.yaml b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra194-cbb.yaml
new file mode 100644 (file)
index 0000000..debb2b0
--- /dev/null
@@ -0,0 +1,97 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/arm/tegra/nvidia,tegra194-cbb.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: NVIDIA Tegra194 CBB 1.0 bindings
+
+maintainers:
+  - Sumit Gupta <sumitg@nvidia.com>
+
+description: |+
+  The Control Backbone (CBB) is comprised of the physical path from an
+  initiator to a target's register configuration space. CBB 1.0 has
+  multiple hierarchical sub-NOCs (Network-on-Chip) and connects various
+  initiators and targets using different bridges like AXIP2P, AXI2APB.
+
+  This driver handles errors due to illegal register accesses reported
+  by the NOCs inside the CBB. NOCs reporting errors are cluster NOCs
+  "AON-NOC, SCE-NOC, RCE-NOC, BPMP-NOC, CV-NOC" and "CBB Central NOC"
+  which is the main NOC.
+
+  By default, the access issuing initiator is informed about the error
+  using SError or Data Abort exception unless the ERD (Error Response
+  Disable) is enabled/set for that initiator. If the ERD is enabled, then
+  SError or Data Abort is masked and the error is reported with interrupt.
+
+  - For CCPLEX (CPU Complex) initiator, the driver sets ERD bit. So, the
+    errors due to illegal accesses from CCPLEX are reported by interrupts.
+    If ERD is not set, then error is reported by SError.
+  - For other initiators, the ERD is disabled. So, the access issuing
+    initiator is informed about the illegal access by Data Abort exception.
+    In addition, an interrupt is also generated to CCPLEX. These initiators
+    include all engines using Cortex-R5 (which is ARMv7 CPU cluster) and
+    engines like TSEC (Security co-processor), NVDEC (NVIDIA Video Decoder
+    engine) etc which can initiate transactions.
+
+  The driver prints relevant debug information like Error Code, Error
+  Description, Master, Address, AXI ID, Cache, Protection, Security Group
+  etc on receiving error notification.
+
+properties:
+  $nodename:
+    pattern: "^[a-z]+-noc@[0-9a-f]+$"
+
+  compatible:
+    enum:
+      - nvidia,tegra194-cbb-noc
+      - nvidia,tegra194-aon-noc
+      - nvidia,tegra194-bpmp-noc
+      - nvidia,tegra194-rce-noc
+      - nvidia,tegra194-sce-noc
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    description:
+      CCPLEX receives secure or nonsecure interrupt depending on error type.
+      A secure interrupt is received for SEC(firewall) & SLV errors and a
+      non-secure interrupt is received for TMO & DEC errors.
+    items:
+      - description: non-secure interrupt
+      - description: secure interrupt
+
+  nvidia,axi2apb:
+    $ref: '/schemas/types.yaml#/definitions/phandle'
+    description:
+      Specifies the node having all axi2apb bridges which need to be checked
+      for any error logged in their status register.
+
+  nvidia,apbmisc:
+    $ref: '/schemas/types.yaml#/definitions/phandle'
+    description:
+      Specifies the apbmisc node which need to be used for reading the ERD
+      register.
+
+additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - nvidia,apbmisc
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    cbb-noc@2300000 {
+        compatible = "nvidia,tegra194-cbb-noc";
+        reg = <0x02300000 0x1000>;
+        interrupts = <GIC_SPI 230 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 231 IRQ_TYPE_LEVEL_HIGH>;
+        nvidia,axi2apb = <&axi2apb>;
+        nvidia,apbmisc = <&apbmisc>;
+    };
diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra234-cbb.yaml b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra234-cbb.yaml
new file mode 100644 (file)
index 0000000..7b1fe50
--- /dev/null
@@ -0,0 +1,74 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/arm/tegra/nvidia,tegra234-cbb.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: NVIDIA Tegra CBB 2.0 bindings
+
+maintainers:
+  - Sumit Gupta <sumitg@nvidia.com>
+
+description: |+
+  The Control Backbone (CBB) is comprised of the physical path from an
+  initiator to a target's register configuration space. CBB 2.0 consists
+  of multiple sub-blocks connected to each other to create a topology.
+  The Tegra234 SoC has different fabrics based on CBB 2.0 architecture
+  which include cluster fabrics BPMP, AON, PSC, SCE, RCE, DCE, FSI and
+  "CBB central fabric".
+
+  In CBB 2.0, each initiator which can issue transactions connects to a
+  Root Master Node (MN) before it connects to any other element of the
+  fabric. Each Root MN contains a Error Monitor (EM) which detects and
+  logs error. Interrupts from various EM blocks are collated by Error
+  Notifier (EN) which is per fabric and presents a single interrupt from
+  fabric to the SoC interrupt controller.
+
+  The driver handles errors from CBB due to illegal register accesses
+  and prints debug information about failed transaction on receiving
+  the interrupt from EN. Debug information includes Error Code, Error
+  Description, MasterID, Fabric, SlaveID, Address, Cache, Protection,
+  Security Group etc on receiving error notification.
+
+  If the Error Response Disable (ERD) is set/enabled for an initiator,
+  then SError or Data abort exception error response is masked and an
+  interrupt is used for reporting errors due to illegal accesses from
+  that initiator. The value returned on read failures is '0xFFFFFFFF'
+  for compatibility with PCIE.
+
+properties:
+  $nodename:
+    pattern: "^[a-z]+-fabric@[0-9a-f]+$"
+
+  compatible:
+    enum:
+      - nvidia,tegra234-aon-fabric
+      - nvidia,tegra234-bpmp-fabric
+      - nvidia,tegra234-cbb-fabric
+      - nvidia,tegra234-dce-fabric
+      - nvidia,tegra234-rce-fabric
+      - nvidia,tegra234-sce-fabric
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    items:
+      - description: secure interrupt from error notifier
+
+additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    cbb-fabric@1300000 {
+      compatible = "nvidia,tegra234-cbb-fabric";
+      reg = <0x13a00000 0x400000>;
+      interrupts = <GIC_SPI 231 IRQ_TYPE_LEVEL_HIGH>;
+    };
index e79eeac..17caf78 100644 (file)
@@ -28,6 +28,9 @@ properties:
       - items:
           - const: allwinner,sun8i-r40-de2-clk
           - const: allwinner,sun8i-h3-de2-clk
+      - items:
+          - const: allwinner,sun20i-d1-de2-clk
+          - const: allwinner,sun50i-h5-de2-clk
 
   reg:
     maxItems: 1
diff --git a/Documentation/devicetree/bindings/clock/fsl,scu-clk.yaml b/Documentation/devicetree/bindings/clock/fsl,scu-clk.yaml
new file mode 100644 (file)
index 0000000..f2c4846
--- /dev/null
@@ -0,0 +1,43 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/fsl,scu-clk.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: i.MX SCU Client Device Node - Clock bindings based on SCU Message Protocol
+
+maintainers:
+  - Abel Vesa <abel.vesa@nxp.com>
+
+description: i.MX SCU Client Device Node
+  Client nodes are maintained as children of the relevant IMX-SCU device node.
+  This binding uses the common clock binding.
+  (Documentation/devicetree/bindings/clock/clock-bindings.txt)
+  The clock consumer should specify the desired clock by having the clock
+  ID in its "clocks" phandle cell. See the full list of clock IDs from
+  include/dt-bindings/clock/imx8qxp-clock.h
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - fsl,imx8dxl-clk
+          - fsl,imx8qm-clk
+          - fsl,imx8qxp-clk
+      - const: fsl,scu-clk
+
+  '#clock-cells':
+    const: 2
+
+required:
+  - compatible
+  - '#clock-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    clock-controller {
+        compatible = "fsl,imx8qxp-clk", "fsl,scu-clk";
+        #clock-cells = <2>;
+    };
diff --git a/Documentation/devicetree/bindings/clock/nuvoton,npcm845-clk.yaml b/Documentation/devicetree/bindings/clock/nuvoton,npcm845-clk.yaml
new file mode 100644 (file)
index 0000000..771db2d
--- /dev/null
@@ -0,0 +1,49 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/nuvoton,npcm845-clk.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Nuvoton NPCM8XX Clock Controller Binding
+
+maintainers:
+  - Tomer Maimon <tmaimon77@gmail.com>
+
+description: |
+  Nuvoton Arbel BMC NPCM8XX contains an integrated clock controller, which
+  generates and supplies clocks to all modules within the BMC.
+
+properties:
+  compatible:
+    enum:
+      - nuvoton,npcm845-clk
+
+  reg:
+    maxItems: 1
+
+  '#clock-cells':
+    const: 1
+    description:
+      See include/dt-bindings/clock/nuvoton,npcm8xx-clock.h for the full
+      list of NPCM8XX clock IDs.
+
+required:
+  - compatible
+  - reg
+  - '#clock-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    ahb {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        clock-controller@f0801000 {
+            compatible = "nuvoton,npcm845-clk";
+            reg = <0x0 0xf0801000 0x0 0x1000>;
+            #clock-cells = <1>;
+        };
+    };
+...
index 3149767..7a8d375 100644 (file)
@@ -4,18 +4,19 @@
 $id: http://devicetree.org/schemas/clock/qcom,dispcc-sm8x50.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
-title: Qualcomm Display Clock & Reset Controller Binding for SM8150/SM8250
+title: Qualcomm Display Clock & Reset Controller Binding for SM8150/SM8250/SM8350
 
 maintainers:
   - Jonathan Marek <jonathan@marek.ca>
 
 description: |
   Qualcomm display clock control module which supports the clocks, resets and
-  power domains on SM8150 and SM8250.
+  power domains on SM8150/SM8250/SM8350.
 
   See also:
     dt-bindings/clock/qcom,dispcc-sm8150.h
     dt-bindings/clock/qcom,dispcc-sm8250.h
+    dt-bindings/clock/qcom,dispcc-sm8350.h
 
 properties:
   compatible:
@@ -23,6 +24,7 @@ properties:
       - qcom,sc8180x-dispcc
       - qcom,sm8150-dispcc
       - qcom,sm8250-dispcc
+      - qcom,sm8350-dispcc
 
   clocks:
     items:
diff --git a/Documentation/devicetree/bindings/clock/qcom,gpucc-sm8350.yaml b/Documentation/devicetree/bindings/clock/qcom,gpucc-sm8350.yaml
new file mode 100644 (file)
index 0000000..0a0546c
--- /dev/null
@@ -0,0 +1,72 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/qcom,gpucc-sm8350.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Graphics Clock & Reset Controller Binding
+
+maintainers:
+  - Robert Foss <robert.foss@linaro.org>
+
+description: |
+  Qualcomm graphics clock control module which supports the clocks, resets and
+  power domains on Qualcomm SoCs.
+
+  See also:
+    dt-bindings/clock/qcom,gpucc-sm8350.h
+
+properties:
+  compatible:
+    enum:
+      - qcom,sm8350-gpucc
+
+  clocks:
+    items:
+      - description: Board XO source
+      - description: GPLL0 main branch source
+      - description: GPLL0 div branch source
+
+  '#clock-cells':
+    const: 1
+
+  '#reset-cells':
+    const: 1
+
+  '#power-domain-cells':
+    const: 1
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - '#clock-cells'
+  - '#reset-cells'
+  - '#power-domain-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/qcom,gcc-sm8350.h>
+    #include <dt-bindings/clock/qcom,rpmh.h>
+
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        clock-controller@3d90000 {
+            compatible = "qcom,sm8350-gpucc";
+            reg = <0 0x03d90000 0 0x9000>;
+            clocks = <&rpmhcc RPMH_CXO_CLK>,
+                     <&gcc GCC_GPU_GPLL0_CLK_SRC>,
+                     <&gcc GCC_GPU_GPLL0_DIV_CLK_SRC>;
+            #clock-cells = <1>;
+            #reset-cells = <1>;
+            #power-domain-cells = <1>;
+        };
+    };
+...
diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml
new file mode 100644 (file)
index 0000000..268f4c6
--- /dev/null
@@ -0,0 +1,80 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/qcom,sm8450-camcc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Camera Clock & Reset Controller Binding for SM8450
+
+maintainers:
+  - Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
+
+description: |
+  Qualcomm camera clock control module which supports the clocks, resets and
+  power domains on SM8450.
+
+  See also include/dt-bindings/clock/qcom,sm8450-camcc.h
+
+properties:
+  compatible:
+    const: qcom,sm8450-camcc
+
+  clocks:
+    items:
+      - description: Camera AHB clock from GCC
+      - description: Board XO source
+      - description: Board active XO source
+      - description: Sleep clock source
+
+  power-domains:
+    maxItems: 1
+    description:
+      A phandle and PM domain specifier for the MMCX power domain.
+
+  required-opps:
+    description:
+      A phandle to an OPP node describing required MMCX performance point.
+
+  '#clock-cells':
+    const: 1
+
+  '#reset-cells':
+    const: 1
+
+  '#power-domain-cells':
+    const: 1
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - power-domains
+  - required-opps
+  - '#clock-cells'
+  - '#reset-cells'
+  - '#power-domain-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/qcom,gcc-sm8450.h>
+    #include <dt-bindings/clock/qcom,rpmh.h>
+    #include <dt-bindings/power/qcom-rpmpd.h>
+    clock-controller@ade0000 {
+      compatible = "qcom,sm8450-camcc";
+      reg = <0xade0000 0x20000>;
+      clocks = <&gcc GCC_CAMERA_AHB_CLK>,
+               <&rpmhcc RPMH_CXO_CLK>,
+               <&rpmhcc RPMH_CXO_CLK_A>,
+               <&sleep_clk>;
+      power-domains = <&rpmhpd SM8450_MMCX>;
+      required-opps = <&rpmhpd_opp_low_svs>;
+      #clock-cells = <1>;
+      #reset-cells = <1>;
+      #power-domain-cells = <1>;
+    };
+...
index 5073e56..006d33a 100644 (file)
@@ -33,6 +33,7 @@ properties:
     enum:
       - samsung,exynos7885-cmu-top
       - samsung,exynos7885-cmu-core
+      - samsung,exynos7885-cmu-fsys
       - samsung,exynos7885-cmu-peri
 
   clocks:
@@ -92,6 +93,32 @@ allOf:
       properties:
         compatible:
           contains:
+            const: samsung,exynos7885-cmu-fsys
+
+    then:
+      properties:
+        clocks:
+          items:
+            - description: External reference clock (26 MHz)
+            - description: CMU_FSYS bus clock (from CMU_TOP)
+            - description: MMC_CARD clock (from CMU_TOP)
+            - description: MMC_EMBD clock (from CMU_TOP)
+            - description: MMC_SDIO clock (from CMU_TOP)
+            - description: USB30DRD clock (from CMU_TOP)
+
+        clock-names:
+          items:
+            - const: oscclk
+            - const: dout_fsys_bus
+            - const: dout_fsys_mmc_card
+            - const: dout_fsys_mmc_embd
+            - const: dout_fsys_mmc_sdio
+            - const: dout_fsys_usb30drd
+
+  - if:
+      properties:
+        compatible:
+          contains:
             const: samsung,exynos7885-cmu-peri
 
     then:
index f8c4742..242fe92 100644 (file)
@@ -78,6 +78,7 @@ if:
       contains:
         enum:
           - st,stm32mp1-rcc-secure
+          - st,stm32mp13-rcc
 then:
   properties:
     clocks:
diff --git a/Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml b/Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
new file mode 100644 (file)
index 0000000..bcc1408
--- /dev/null
@@ -0,0 +1,52 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) Sunplus Co., Ltd. 2021
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/sunplus,sp7021-clkc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sunplus SP7021 SoC Clock Controller
+
+maintainers:
+  - Qin Jian <qinjian@cqplus1.com>
+
+properties:
+  compatible:
+    const: sunplus,sp7021-clkc
+
+  reg:
+    maxItems: 3
+
+  clocks:
+    maxItems: 1
+
+  "#clock-cells":
+    const: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - "#clock-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    extclk: osc0 {
+      compatible = "fixed-clock";
+      #clock-cells = <0>;
+      clock-frequency = <27000000>;
+      clock-output-names = "extclk";
+    };
+
+    clkc: clock-controller@9c000004 {
+      compatible = "sunplus,sp7021-clkc";
+      reg = <0x9c000004 0x28>,
+            <0x9c000200 0x44>,
+            <0x9c000268 0x08>;
+      clocks = <&extclk>;
+      #clock-cells = <1>;
+    };
+
+...
index a9a776d..10b3a7a 100644 (file)
@@ -63,8 +63,8 @@ additionalProperties: true
 examples:
   - |
     / {
-        model = "Qualcomm Technologies, Inc. QCS404";
-        compatible = "qcom,qcs404";
+        model = "Qualcomm Technologies, Inc. QCS404 EVB 1000";
+        compatible = "qcom,qcs404-evb-1000", "qcom,qcs404-evb", "qcom,qcs404";
         #address-cells = <2>;
         #size-cells = <2>;
 
diff --git a/Documentation/devicetree/bindings/devfreq/exynos-bus.txt b/Documentation/devicetree/bindings/devfreq/exynos-bus.txt
deleted file mode 100644 (file)
index bcaa2c0..0000000
+++ /dev/null
@@ -1,488 +0,0 @@
-* Generic Exynos Bus frequency device
-
-The Samsung Exynos SoC has many buses for data transfer between DRAM
-and sub-blocks in SoC. Most Exynos SoCs share the common architecture
-for buses. Generally, each bus of Exynos SoC includes a source clock
-and a power line, which are able to change the clock frequency
-of the bus in runtime. To monitor the usage of each bus in runtime,
-the driver uses the PPMU (Platform Performance Monitoring Unit), which
-is able to measure the current load of sub-blocks.
-
-The Exynos SoC includes the various sub-blocks which have the each AXI bus.
-The each AXI bus has the owned source clock but, has not the only owned
-power line. The power line might be shared among one more sub-blocks.
-So, we can divide into two type of device as the role of each sub-block.
-There are two type of bus devices as following:
-- parent bus device
-- passive bus device
-
-Basically, parent and passive bus device share the same power line.
-The parent bus device can only change the voltage of shared power line
-and the rest bus devices (passive bus device) depend on the decision of
-the parent bus device. If there are three blocks which share the VDD_xxx
-power line, Only one block should be parent device and then the rest blocks
-should depend on the parent device as passive device.
-
-       VDD_xxx |--- A block (parent)
-               |--- B block (passive)
-               |--- C block (passive)
-
-There are a little different composition among Exynos SoC because each Exynos
-SoC has different sub-blocks. Therefore, such difference should be specified
-in devicetree file instead of each device driver. In result, this driver
-is able to support the bus frequency for all Exynos SoCs.
-
-Required properties for all bus devices:
-- compatible: Should be "samsung,exynos-bus".
-- clock-names : the name of clock used by the bus, "bus".
-- clocks : phandles for clock specified in "clock-names" property.
-- operating-points-v2: the OPP table including frequency/voltage information
-  to support DVFS (Dynamic Voltage/Frequency Scaling) feature.
-
-Required properties only for parent bus device:
-- vdd-supply: the regulator to provide the buses with the voltage.
-- devfreq-events: the devfreq-event device to monitor the current utilization
-  of buses.
-
-Required properties only for passive bus device:
-- devfreq: the parent bus device.
-
-Optional properties only for parent bus device:
-- exynos,saturation-ratio: the percentage value which is used to calibrate
-                       the performance count against total cycle count.
-
-Optional properties for the interconnect functionality (QoS frequency
-constraints):
-- #interconnect-cells: should be 0.
-- interconnects: as documented in ../interconnect.txt, describes a path at the
-  higher level interconnects used by this interconnect provider.
-  If this interconnect provider is directly linked to a top level interconnect
-  provider the property contains only one phandle. The provider extends
-  the interconnect graph by linking its node to a node registered by provider
-  pointed to by first phandle in the 'interconnects' property.
-
-- samsung,data-clock-ratio: ratio of the data throughput in B/s to minimum data
-   clock frequency in Hz, default value is 8 when this property is missing.
-
-Detailed correlation between sub-blocks and power line according to Exynos SoC:
-- In case of Exynos3250, there are two power line as following:
-       VDD_MIF |--- DMC
-
-       VDD_INT |--- LEFTBUS (parent device)
-               |--- PERIL
-               |--- MFC
-               |--- G3D
-               |--- RIGHTBUS
-               |--- PERIR
-               |--- FSYS
-               |--- LCD0
-               |--- PERIR
-               |--- ISP
-               |--- CAM
-
-- In case of Exynos4210, there is one power line as following:
-       VDD_INT |--- DMC (parent device)
-               |--- LEFTBUS
-               |--- PERIL
-               |--- MFC(L)
-               |--- G3D
-               |--- TV
-               |--- LCD0
-               |--- RIGHTBUS
-               |--- PERIR
-               |--- MFC(R)
-               |--- CAM
-               |--- FSYS
-               |--- GPS
-               |--- LCD0
-               |--- LCD1
-
-- In case of Exynos4x12, there are two power line as following:
-       VDD_MIF |--- DMC
-
-       VDD_INT |--- LEFTBUS (parent device)
-               |--- PERIL
-               |--- MFC(L)
-               |--- G3D
-               |--- TV
-               |--- IMAGE
-               |--- RIGHTBUS
-               |--- PERIR
-               |--- MFC(R)
-               |--- CAM
-               |--- FSYS
-               |--- GPS
-               |--- LCD0
-               |--- ISP
-
-- In case of Exynos5422, there are two power line as following:
-       VDD_MIF |--- DREX 0 (parent device, DRAM EXpress controller)
-               |--- DREX 1
-
-       VDD_INT |--- NoC_Core (parent device)
-               |--- G2D
-               |--- G3D
-               |--- DISP1
-               |--- NoC_WCORE
-               |--- GSCL
-               |--- MSCL
-               |--- ISP
-               |--- MFC
-               |--- GEN
-               |--- PERIS
-               |--- PERIC
-               |--- FSYS
-               |--- FSYS2
-
-- In case of Exynos5433, there is VDD_INT power line as following:
-       VDD_INT |--- G2D (parent device)
-               |--- MSCL
-               |--- GSCL
-               |--- JPEG
-               |--- MFC
-               |--- HEVC
-               |--- BUS0
-               |--- BUS1
-               |--- BUS2
-               |--- PERIS (Fixed clock rate)
-               |--- PERIC (Fixed clock rate)
-               |--- FSYS  (Fixed clock rate)
-
-Example 1:
-       Show the AXI buses of Exynos3250 SoC. Exynos3250 divides the buses to
-       power line (regulator). The MIF (Memory Interface) AXI bus is used to
-       transfer data between DRAM and CPU and uses the VDD_MIF regulator.
-
-       - MIF (Memory Interface) block
-       : VDD_MIF |--- DMC (Dynamic Memory Controller)
-
-       - INT (Internal) block
-       : VDD_INT |--- LEFTBUS (parent device)
-                 |--- PERIL
-                 |--- MFC
-                 |--- G3D
-                 |--- RIGHTBUS
-                 |--- FSYS
-                 |--- LCD0
-                 |--- PERIR
-                 |--- ISP
-                 |--- CAM
-
-       - MIF bus's frequency/voltage table
-       -----------------------
-       |Lv| Freq   | Voltage |
-       -----------------------
-       |L1| 50000  |800000   |
-       |L2| 100000 |800000   |
-       |L3| 134000 |800000   |
-       |L4| 200000 |825000   |
-       |L5| 400000 |875000   |
-       -----------------------
-
-       - INT bus's frequency/voltage table
-       ----------------------------------------------------------
-       |Block|LEFTBUS|RIGHTBUS|MCUISP |ISP    |PERIL  ||VDD_INT |
-       | name|       |LCD0    |       |       |       ||        |
-       |     |       |FSYS    |       |       |       ||        |
-       |     |       |MFC     |       |       |       ||        |
-       ----------------------------------------------------------
-       |Mode |*parent|passive |passive|passive|passive||        |
-       ----------------------------------------------------------
-       |Lv   |Frequency                               ||Voltage |
-       ----------------------------------------------------------
-       |L1   |50000  |50000   |50000  |50000  |50000  ||900000  |
-       |L2   |80000  |80000   |80000  |80000  |80000  ||900000  |
-       |L3   |100000 |100000  |100000 |100000 |100000 ||1000000 |
-       |L4   |134000 |134000  |200000 |200000 |       ||1000000 |
-       |L5   |200000 |200000  |400000 |300000 |       ||1000000 |
-       ----------------------------------------------------------
-
-Example 2:
-       The bus of DMC (Dynamic Memory Controller) block in exynos3250.dtsi
-       is listed below:
-
-       bus_dmc: bus_dmc {
-               compatible = "samsung,exynos-bus";
-               clocks = <&cmu_dmc CLK_DIV_DMC>;
-               clock-names = "bus";
-               operating-points-v2 = <&bus_dmc_opp_table>;
-               status = "disabled";
-       };
-
-       bus_dmc_opp_table: opp_table1 {
-               compatible = "operating-points-v2";
-               opp-shared;
-
-               opp-50000000 {
-                       opp-hz = /bits/ 64 <50000000>;
-                       opp-microvolt = <800000>;
-               };
-               opp-100000000 {
-                       opp-hz = /bits/ 64 <100000000>;
-                       opp-microvolt = <800000>;
-               };
-               opp-134000000 {
-                       opp-hz = /bits/ 64 <134000000>;
-                       opp-microvolt = <800000>;
-               };
-               opp-200000000 {
-                       opp-hz = /bits/ 64 <200000000>;
-                       opp-microvolt = <825000>;
-               };
-               opp-400000000 {
-                       opp-hz = /bits/ 64 <400000000>;
-                       opp-microvolt = <875000>;
-               };
-       };
-
-       bus_leftbus: bus_leftbus {
-               compatible = "samsung,exynos-bus";
-               clocks = <&cmu CLK_DIV_GDL>;
-               clock-names = "bus";
-               operating-points-v2 = <&bus_leftbus_opp_table>;
-               status = "disabled";
-       };
-
-       bus_rightbus: bus_rightbus {
-               compatible = "samsung,exynos-bus";
-               clocks = <&cmu CLK_DIV_GDR>;
-               clock-names = "bus";
-               operating-points-v2 = <&bus_leftbus_opp_table>;
-               status = "disabled";
-       };
-
-       bus_lcd0: bus_lcd0 {
-               compatible = "samsung,exynos-bus";
-               clocks = <&cmu CLK_DIV_ACLK_160>;
-               clock-names = "bus";
-               operating-points-v2 = <&bus_leftbus_opp_table>;
-               status = "disabled";
-       };
-
-       bus_fsys: bus_fsys {
-               compatible = "samsung,exynos-bus";
-               clocks = <&cmu CLK_DIV_ACLK_200>;
-               clock-names = "bus";
-               operating-points-v2 = <&bus_leftbus_opp_table>;
-               status = "disabled";
-       };
-
-       bus_mcuisp: bus_mcuisp {
-               compatible = "samsung,exynos-bus";
-               clocks = <&cmu CLK_DIV_ACLK_400_MCUISP>;
-               clock-names = "bus";
-               operating-points-v2 = <&bus_mcuisp_opp_table>;
-               status = "disabled";
-       };
-
-       bus_isp: bus_isp {
-               compatible = "samsung,exynos-bus";
-               clocks = <&cmu CLK_DIV_ACLK_266>;
-               clock-names = "bus";
-               operating-points-v2 = <&bus_isp_opp_table>;
-               status = "disabled";
-       };
-
-       bus_peril: bus_peril {
-               compatible = "samsung,exynos-bus";
-               clocks = <&cmu CLK_DIV_ACLK_100>;
-               clock-names = "bus";
-               operating-points-v2 = <&bus_peril_opp_table>;
-               status = "disabled";
-       };
-
-       bus_mfc: bus_mfc {
-               compatible = "samsung,exynos-bus";
-               clocks = <&cmu CLK_SCLK_MFC>;
-               clock-names = "bus";
-               operating-points-v2 = <&bus_leftbus_opp_table>;
-               status = "disabled";
-       };
-
-       bus_leftbus_opp_table: opp_table1 {
-               compatible = "operating-points-v2";
-               opp-shared;
-
-               opp-50000000 {
-                       opp-hz = /bits/ 64 <50000000>;
-                       opp-microvolt = <900000>;
-               };
-               opp-80000000 {
-                       opp-hz = /bits/ 64 <80000000>;
-                       opp-microvolt = <900000>;
-               };
-               opp-100000000 {
-                       opp-hz = /bits/ 64 <100000000>;
-                       opp-microvolt = <1000000>;
-               };
-               opp-134000000 {
-                       opp-hz = /bits/ 64 <134000000>;
-                       opp-microvolt = <1000000>;
-               };
-               opp-200000000 {
-                       opp-hz = /bits/ 64 <200000000>;
-                       opp-microvolt = <1000000>;
-               };
-       };
-
-       bus_mcuisp_opp_table: opp_table2 {
-               compatible = "operating-points-v2";
-               opp-shared;
-
-               opp-50000000 {
-                       opp-hz = /bits/ 64 <50000000>;
-               };
-               opp-80000000 {
-                       opp-hz = /bits/ 64 <80000000>;
-               };
-               opp-100000000 {
-                       opp-hz = /bits/ 64 <100000000>;
-               };
-               opp-200000000 {
-                       opp-hz = /bits/ 64 <200000000>;
-               };
-               opp-400000000 {
-                       opp-hz = /bits/ 64 <400000000>;
-               };
-       };
-
-       bus_isp_opp_table: opp_table3 {
-               compatible = "operating-points-v2";
-               opp-shared;
-
-               opp-50000000 {
-                       opp-hz = /bits/ 64 <50000000>;
-               };
-               opp-80000000 {
-                       opp-hz = /bits/ 64 <80000000>;
-               };
-               opp-100000000 {
-                       opp-hz = /bits/ 64 <100000000>;
-               };
-               opp-200000000 {
-                       opp-hz = /bits/ 64 <200000000>;
-               };
-               opp-300000000 {
-                       opp-hz = /bits/ 64 <300000000>;
-               };
-       };
-
-       bus_peril_opp_table: opp_table4 {
-               compatible = "operating-points-v2";
-               opp-shared;
-
-               opp-50000000 {
-                       opp-hz = /bits/ 64 <50000000>;
-               };
-               opp-80000000 {
-                       opp-hz = /bits/ 64 <80000000>;
-               };
-               opp-100000000 {
-                       opp-hz = /bits/ 64 <100000000>;
-               };
-       };
-
-
-       Usage case to handle the frequency and voltage of bus on runtime
-       in exynos3250-rinato.dts is listed below:
-
-       &bus_dmc {
-               devfreq-events = <&ppmu_dmc0_3>, <&ppmu_dmc1_3>;
-               vdd-supply = <&buck1_reg>;      /* VDD_MIF */
-               status = "okay";
-       };
-
-       &bus_leftbus {
-               devfreq-events = <&ppmu_leftbus_3>, <&ppmu_rightbus_3>;
-               vdd-supply = <&buck3_reg>;
-               status = "okay";
-       };
-
-       &bus_rightbus {
-               devfreq = <&bus_leftbus>;
-               status = "okay";
-       };
-
-       &bus_lcd0 {
-               devfreq = <&bus_leftbus>;
-               status = "okay";
-       };
-
-       &bus_fsys {
-               devfreq = <&bus_leftbus>;
-               status = "okay";
-       };
-
-       &bus_mcuisp {
-               devfreq = <&bus_leftbus>;
-               status = "okay";
-       };
-
-       &bus_isp {
-               devfreq = <&bus_leftbus>;
-               status = "okay";
-       };
-
-       &bus_peril {
-               devfreq = <&bus_leftbus>;
-               status = "okay";
-       };
-
-       &bus_mfc {
-               devfreq = <&bus_leftbus>;
-               status = "okay";
-       };
-
-Example 3:
-       An interconnect path "bus_display -- bus_leftbus -- bus_dmc" on
-       Exynos4412 SoC with video mixer as an interconnect consumer device.
-
-       soc {
-               bus_dmc: bus_dmc {
-                       compatible = "samsung,exynos-bus";
-                       clocks = <&clock CLK_DIV_DMC>;
-                       clock-names = "bus";
-                       operating-points-v2 = <&bus_dmc_opp_table>;
-                       samsung,data-clock-ratio = <4>;
-                       #interconnect-cells = <0>;
-               };
-
-               bus_leftbus: bus_leftbus {
-                       compatible = "samsung,exynos-bus";
-                       clocks = <&clock CLK_DIV_GDL>;
-                       clock-names = "bus";
-                       operating-points-v2 = <&bus_leftbus_opp_table>;
-                       #interconnect-cells = <0>;
-                       interconnects = <&bus_dmc>;
-               };
-
-               bus_display: bus_display {
-                       compatible = "samsung,exynos-bus";
-                       clocks = <&clock CLK_ACLK160>;
-                       clock-names = "bus";
-                       operating-points-v2 = <&bus_display_opp_table>;
-                       #interconnect-cells = <0>;
-                       interconnects = <&bus_leftbus &bus_dmc>;
-               };
-
-               bus_dmc_opp_table: opp_table1 {
-                       compatible = "operating-points-v2";
-                       /* ... */
-               }
-
-               bus_leftbus_opp_table: opp_table3 {
-                       compatible = "operating-points-v2";
-                       /* ... */
-               };
-
-               bus_display_opp_table: opp_table4 {
-                       compatible = "operating-points-v2";
-                       /* .. */
-               };
-
-               &mixer {
-                       compatible = "samsung,exynos4212-mixer";
-                       interconnects = <&bus_display &bus_dmc>;
-                       /* ... */
-               };
-       };
index c388ae5..c9c346e 100644 (file)
@@ -94,6 +94,7 @@ if:
           - allwinner,sun8i-a83t-display-engine
           - allwinner,sun8i-r40-display-engine
           - allwinner,sun9i-a80-display-engine
+          - allwinner,sun20i-d1-display-engine
           - allwinner,sun50i-a64-display-engine
 
 then:
index 5e4e0e5..628c4b8 100644 (file)
@@ -21,6 +21,9 @@ properties:
   enable-gpios: true
   port: true
 
+  spi-cpha: true
+  spi-cpol: true
+
 required:
   - compatible
   - enable-gpios
index d525165..c0fabeb 100644 (file)
@@ -42,6 +42,9 @@ properties:
   panel-height-mm:
     description: physical panel height [mm]
 
+  spi-cpha: true
+  spi-cpol: true
+
 required:
   - compatible
   - reg
index 9e1d707..d984b59 100644 (file)
@@ -23,6 +23,9 @@ properties:
   backlight: true
   port: true
 
+  spi-cpha: true
+  spi-cpol: true
+
 required:
   - compatible
   - reg
index f902a9d..e8c8ee8 100644 (file)
@@ -28,6 +28,9 @@ properties:
   backlight: true
   port: true
 
+  spi-cpha: true
+  spi-cpol: true
+
 required:
   - compatible
   - port
index ff0a5c5..e712444 100644 (file)
@@ -67,7 +67,7 @@ if:
 then:
   properties:
     clocks:
-      maxItems: 2
+      minItems: 2
 
   required:
     - clock-names
index 948e2a3..1c0388d 100644 (file)
@@ -183,6 +183,12 @@ properties:
             required:
               - reg
 
+  protocol@18:
+    type: object
+    properties:
+      reg:
+        const: 0x18
+
 additionalProperties: false
 
 patternProperties:
@@ -323,6 +329,10 @@ examples:
                     };
                 };
             };
+
+            scmi_powercap: protocol@18 {
+                reg = <0x18>;
+            };
         };
     };
 
diff --git a/Documentation/devicetree/bindings/firmware/fsl,scu.yaml b/Documentation/devicetree/bindings/firmware/fsl,scu.yaml
new file mode 100644 (file)
index 0000000..b40b0ef
--- /dev/null
@@ -0,0 +1,210 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/firmware/fsl,scu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP i.MX System Controller Firmware (SCFW)
+
+maintainers:
+  - Dong Aisheng <aisheng.dong@nxp.com>
+
+description:
+  The System Controller Firmware (SCFW) is a low-level system function
+  which runs on a dedicated Cortex-M core to provide power, clock, and
+  resource management. It exists on some i.MX8 processors. e.g. i.MX8QM
+  (QM, QP), and i.MX8QX (QXP, DX).
+  The AP communicates with the SC using a multi-ported MU module found
+  in the LSIO subsystem. The current definition of this MU module provides
+  5 remote AP connections to the SC to support up to 5 execution environments
+  (TZ, HV, standard Linux, etc.). The SC side of this MU module interfaces
+  with the LSIO DSC IP bus. The SC firmware will communicate with this MU
+  using the MSI bus.
+
+properties:
+  compatible:
+    const: fsl,imx-scu
+
+  clock-controller:
+    description:
+      Clock controller node that provides the clocks controlled by the SCU
+    $ref: /schemas/clock/fsl,scu-clk.yaml
+
+  ocotp:
+    description:
+      OCOTP controller node provided by the SCU
+    $ref: /schemas/nvmem/fsl,scu-ocotp.yaml
+
+  keys:
+    description:
+      Keys provided by the SCU
+    $ref: /schemas/input/fsl,scu-key.yaml
+
+  mboxes:
+    description:
+      A list of phandles of TX MU channels followed by a list of phandles of
+      RX MU channels. The list may include at the end one more optional MU
+      channel for general interrupt. The number of expected tx and rx
+      channels is 1 TX and 1 RX channels if MU instance is "fsl,imx8-mu-scu"
+      compatible, 4 TX and 4 RX channels otherwise. All MU channels must be
+      within the same MU instance. Cross instances are not allowed. The MU
+      instance can only be one of LSIO MU0~M4 for imx8qxp and imx8qm. Users
+      need to ensure that one is used that does not conflict with other
+      execution environments such as ATF.
+    oneOf:
+      - items:
+          - description: TX0 MU channel
+          - description: RX0 MU channel
+      - items:
+          - description: TX0 MU channel
+          - description: RX0 MU channel
+          - description: optional MU channel for general interrupt
+      - items:
+          - description: TX0 MU channel
+          - description: TX1 MU channel
+          - description: TX2 MU channel
+          - description: TX3 MU channel
+          - description: RX0 MU channel
+          - description: RX1 MU channel
+          - description: RX2 MU channel
+          - description: RX3 MU channel
+      - items:
+          - description: TX0 MU channel
+          - description: TX1 MU channel
+          - description: TX2 MU channel
+          - description: TX3 MU channel
+          - description: RX0 MU channel
+          - description: RX1 MU channel
+          - description: RX2 MU channel
+          - description: RX3 MU channel
+          - description: optional MU channel for general interrupt
+
+  mbox-names:
+    oneOf:
+      - items:
+          - const: tx0
+          - const: rx0
+      - items:
+          - const: tx0
+          - const: rx0
+          - const: gip3
+      - items:
+          - const: tx0
+          - const: tx1
+          - const: tx2
+          - const: tx3
+          - const: rx0
+          - const: rx1
+          - const: rx2
+          - const: rx3
+      - items:
+          - const: tx0
+          - const: tx1
+          - const: tx2
+          - const: tx3
+          - const: rx0
+          - const: rx1
+          - const: rx2
+          - const: rx3
+          - const: gip3
+
+  pinctrl:
+    description:
+      Pin controller provided by the SCU
+    $ref: /schemas/pinctrl/fsl,scu-pinctrl.yaml
+
+  power-controller:
+    description:
+      Power domains controller node that provides the power domains
+      controlled by the SCU
+    $ref: /schemas/power/fsl,scu-pd.yaml
+
+  rtc:
+    description:
+      RTC controller provided by the SCU
+    $ref: /schemas/rtc/fsl,scu-rtc.yaml
+
+  thermal-sensor:
+    description:
+      Thermal sensor provided by the SCU
+    $ref: /schemas/thermal/fsl,scu-thermal.yaml
+
+  watchdog:
+    description:
+      Watchdog controller provided by the SCU
+    $ref: /schemas/watchdog/fsl,scu-wdt.yaml
+
+required:
+  - compatible
+  - mbox-names
+  - mboxes
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/firmware/imx/rsrc.h>
+    #include <dt-bindings/input/input.h>
+    #include <dt-bindings/pinctrl/pads-imx8qxp.h>
+
+    firmware {
+        system-controller {
+            compatible = "fsl,imx-scu";
+            mbox-names = "tx0", "tx1", "tx2", "tx3",
+                         "rx0", "rx1", "rx2", "rx3",
+                         "gip3";
+            mboxes = <&lsio_mu1 0 0 &lsio_mu1 0 1 &lsio_mu1 0 2 &lsio_mu1 0 3
+                      &lsio_mu1 1 0 &lsio_mu1 1 1 &lsio_mu1 1 2 &lsio_mu1 1 3
+                      &lsio_mu1 3 3>;
+
+            clock-controller {
+                compatible = "fsl,imx8qxp-clk", "fsl,scu-clk";
+                #clock-cells = <2>;
+            };
+
+            pinctrl {
+                compatible = "fsl,imx8qxp-iomuxc";
+
+                pinctrl_lpuart0: lpuart0grp {
+                    fsl,pins = <
+                        IMX8QXP_UART0_RX_ADMA_UART0_RX   0x06000020
+                        IMX8QXP_UART0_TX_ADMA_UART0_TX   0x06000020
+                    >;
+                };
+            };
+
+            ocotp {
+                compatible = "fsl,imx8qxp-scu-ocotp";
+                #address-cells = <1>;
+                #size-cells = <1>;
+
+                fec_mac0: mac@2c4 {
+                    reg = <0x2c4 6>;
+                };
+            };
+
+            power-controller {
+                compatible = "fsl,imx8qxp-scu-pd", "fsl,scu-pd";
+                #power-domain-cells = <1>;
+            };
+
+            rtc {
+                compatible = "fsl,imx8qxp-sc-rtc";
+            };
+
+            keys {
+                compatible = "fsl,imx8qxp-sc-key", "fsl,imx-sc-key";
+                linux,keycodes = <KEY_POWER>;
+            };
+
+            watchdog {
+                compatible = "fsl,imx8qxp-sc-wdt", "fsl,imx-sc-wdt";
+                timeout-sec = <60>;
+            };
+
+            thermal-sensor {
+                compatible = "fsl,imx8qxp-sc-thermal", "fsl,imx-sc-thermal";
+                #thermal-sensor-cells = <1>;
+            };
+        };
+    };
index 0f4e5ab..b3f702c 100644 (file)
@@ -23,10 +23,13 @@ Required properties:
  * "qcom,scm-msm8994"
  * "qcom,scm-msm8996"
  * "qcom,scm-msm8998"
+ * "qcom,scm-qcs404"
  * "qcom,scm-sc7180"
  * "qcom,scm-sc7280"
+ * "qcom,scm-sm6125"
  * "qcom,scm-sdm845"
  * "qcom,scm-sdx55"
+ * "qcom,scm-sdx65"
  * "qcom,scm-sm6350"
  * "qcom,scm-sm8150"
  * "qcom,scm-sm8250"
@@ -43,6 +46,7 @@ Required properties:
   clock and "bus" for the bus clock per the requirements of the compatible.
 - qcom,dload-mode: phandle to the TCSR hardware block and offset of the
                   download mode control register (optional)
+- interconnects: Specifies the bandwidth requirements of the SCM interface (optional)
 
 Example for MSM8916:
 
index 378da26..29c27ea 100644 (file)
@@ -11,7 +11,11 @@ maintainers:
 
 properties:
   compatible:
-    const: xlnx,zynq-gpio-1.0
+    enum:
+      - xlnx,zynq-gpio-1.0
+      - xlnx,zynqmp-gpio-1.0
+      - xlnx,versal-gpio-1.0
+      - xlnx,pmc-gpio-1.0
 
   reg:
     maxItems: 1
@@ -24,6 +28,11 @@ properties:
 
   gpio-controller: true
 
+  gpio-line-names:
+    description: strings describing the names of each gpio line
+    minItems: 58
+    maxItems: 174
+
   interrupt-controller: true
 
   "#interrupt-cells":
@@ -32,6 +41,54 @@ properties:
   clocks:
     maxItems: 1
 
+  power-domains:
+    maxItems: 1
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          enum:
+            - xlnx,zynqmp-gpio-1.0
+    then:
+      properties:
+        gpio-line-names:
+          minItems: 174
+          maxItems: 174
+
+  - if:
+      properties:
+        compatible:
+          enum:
+            - xlnx,zynq-gpio-1.0
+    then:
+      properties:
+        gpio-line-names:
+          minItems: 118
+          maxItems: 118
+
+  - if:
+      properties:
+        compatible:
+          enum:
+            - xlnx,versal-gpio-1.0
+    then:
+      properties:
+        gpio-line-names:
+          minItems: 58
+          maxItems: 58
+
+  - if:
+      properties:
+        compatible:
+          enum:
+            - xlnx,pmc-gpio-1.0
+    then:
+      properties:
+        gpio-line-names:
+          minItems: 116
+          maxItems: 116
+
 required:
   - compatible
   - reg
@@ -1,7 +1,7 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
 %YAML 1.2
 ---
-$id: http://devicetree.org/schemas/arm/renesas,prr.yaml#
+$id: http://devicetree.org/schemas/hwinfo/renesas,prr.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
 title: Renesas Product Register
index b046578..e171983 100644 (file)
@@ -16,6 +16,7 @@ properties:
       - adi,adm1032
       - adi,adt7461
       - adi,adt7461a
+      - adi,adt7481
       - dallas,max6646
       - dallas,max6647
       - dallas,max6649
@@ -50,6 +51,12 @@ properties:
   "#thermal-sensor-cells":
     const: 1
 
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
   vcc-supply:
     description: phandle to the regulator that provides the +VCC supply
 
@@ -61,6 +68,29 @@ required:
   - compatible
   - reg
 
+patternProperties:
+  "^channel@([0-2])$":
+    type: object
+    description: Represents channels of the device and their specific configuration.
+
+    properties:
+      reg:
+        description: The channel number. 0 is local channel, 1-2 are remote channels.
+        items:
+          minimum: 0
+          maximum: 2
+
+      label:
+        description: A descriptive name for this channel, like "ambient" or "psu".
+
+      temperature-offset-millicelsius:
+        description: Temperature offset to be added to or subtracted from remote temperature measurements.
+
+    required:
+      - reg
+
+    additionalProperties: false
+
 allOf:
   - if:
       not:
@@ -70,12 +100,84 @@ allOf:
               enum:
                 - adi,adt7461
                 - adi,adt7461a
+                - adi,adt7481
                 - ti,tmp451
                 - ti,tmp461
     then:
       properties:
         ti,extended-range-enable: false
 
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - dallas,max6646
+              - dallas,max6647
+              - dallas,max6649
+              - dallas,max6657
+              - dallas,max6658
+              - dallas,max6659
+              - dallas,max6695
+              - dallas,max6696
+    then:
+      patternProperties:
+        "^channel@([0-2])$":
+          properties:
+            temperature-offset-millicelsius: false
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - adi,adt7461
+              - adi,adt7461a
+              - adi,adt7481
+              - onnn,nct1008
+    then:
+      patternProperties:
+        "^channel@([0-2])$":
+          properties:
+            temperature-offset-millicelsius:
+              maximum: 127750
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - adi,adm1032
+              - dallas,max6680
+              - dallas,max6681
+              - gmt,g781
+              - national,lm86
+              - national,lm89
+              - national,lm90
+              - national,lm99
+              - nxp,sa56004
+              - winbond,w83l771
+    then:
+      patternProperties:
+        "^channel@([0-2])$":
+          properties:
+            temperature-offset-millicelsius:
+              maximum: 127875
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - ti,tmp451
+              - ti,tmp461
+    then:
+      patternProperties:
+        "^channel@([0-2])$":
+          properties:
+            temperature-offset-millicelsius:
+              maximum: 127937
+
 additionalProperties: false
 
 examples:
@@ -94,3 +196,32 @@ examples:
             #thermal-sensor-cells = <1>;
         };
     };
+  - |
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      sensor@4c {
+        compatible = "adi,adt7481";
+        reg = <0x4c>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        channel@0 {
+          reg = <0x0>;
+          label = "local";
+        };
+
+        channel@1 {
+          reg = <0x1>;
+          label = "front";
+          temperature-offset-millicelsius = <4000>;
+        };
+
+        channel@2 {
+          reg = <0x2>;
+          label = "back";
+          temperature-offset-millicelsius = <750>;
+        };
+      };
+    };
index f771c09..0ec033e 100644 (file)
@@ -21,10 +21,18 @@ properties:
           - enum:
               - allwinner,sun8i-a23-i2c
               - allwinner,sun8i-a83t-i2c
+              - allwinner,sun8i-v536-i2c
               - allwinner,sun50i-a64-i2c
-              - allwinner,sun50i-a100-i2c
               - allwinner,sun50i-h6-i2c
+          - const: allwinner,sun6i-a31-i2c
+      - description: Allwinner SoCs with offload support
+        items:
+          - enum:
+              - allwinner,sun20i-d1-i2c
+              - allwinner,sun50i-a100-i2c
               - allwinner,sun50i-h616-i2c
+              - allwinner,sun50i-r329-i2c
+          - const: allwinner,sun8i-v536-i2c
           - const: allwinner,sun6i-a31-i2c
       - const: marvell,mv64xxx-i2c
       - const: marvell,mv78230-i2c
index 5f9fbc6..e5eef59 100644 (file)
@@ -2,7 +2,7 @@
 
 This module is part of the DA9061/DA9062/DA9063. For more details about entire
 DA9062 and DA9061 chips see Documentation/devicetree/bindings/mfd/da9062.txt
-For DA9063 see Documentation/devicetree/bindings/mfd/da9063.txt
+For DA9063 see Documentation/devicetree/bindings/mfd/dlg,da9063.yaml
 
 This module provides the KEY_POWER event.
 
diff --git a/Documentation/devicetree/bindings/input/fsl,scu-key.yaml b/Documentation/devicetree/bindings/input/fsl,scu-key.yaml
new file mode 100644 (file)
index 0000000..e6266d1
--- /dev/null
@@ -0,0 +1,40 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/input/fsl,scu-key.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: i.MX SCU Client Device Node - SCU key bindings based on SCU Message Protocol
+
+maintainers:
+  - Dong Aisheng <aisheng.dong@nxp.com>
+
+description: i.MX SCU Client Device Node
+  Client nodes are maintained as children of the relevant IMX-SCU device node.
+
+allOf:
+  - $ref: input.yaml#
+
+properties:
+  compatible:
+    items:
+      - const: fsl,imx8qxp-sc-key
+      - const: fsl,imx-sc-key
+
+  linux,keycodes:
+    maxItems: 1
+
+required:
+  - compatible
+  - linux,keycodes
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/input/input.h>
+
+    keys {
+        compatible = "fsl,imx8qxp-sc-key", "fsl,imx-sc-key";
+        linux,keycodes = <KEY_POWER>;
+    };
diff --git a/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml b/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
new file mode 100644 (file)
index 0000000..449c7c9
--- /dev/null
@@ -0,0 +1,141 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interconnect/mediatek,cci.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek Cache Coherent Interconnect (CCI) frequency and voltage scaling
+
+maintainers:
+  - Jia-Wei Chang <jia-wei.chang@mediatek.com>
+  - Johnson Wang <johnson.wang@mediatek.com>
+
+description: |
+  MediaTek Cache Coherent Interconnect (CCI) is a hardware engine used by
+  MT8183 and MT8186 SoCs to scale the frequency and adjust the voltage in
+  hardware. It can also optimize the voltage to reduce the power consumption.
+
+properties:
+  compatible:
+    enum:
+      - mediatek,mt8183-cci
+      - mediatek,mt8186-cci
+
+  clocks:
+    items:
+      - description:
+          The multiplexer for clock input of the bus.
+      - description:
+          A parent of "bus" clock which is used as an intermediate clock source
+          when the original clock source (PLL) is under transition and not
+          stable yet.
+
+  clock-names:
+    items:
+      - const: cci
+      - const: intermediate
+
+  operating-points-v2: true
+  opp-table: true
+
+  proc-supply:
+    description:
+      Phandle of the regulator for CCI that provides the supply voltage.
+
+  sram-supply:
+    description:
+      Phandle of the regulator for sram of CCI that provides the supply
+      voltage. When it is present, the implementation needs to do
+      "voltage tracking" to step by step scale up/down Vproc and Vsram to fit
+      SoC specific needs. When absent, the voltage scaling flow is handled by
+      hardware, hence no software "voltage tracking" is needed.
+
+required:
+  - compatible
+  - clocks
+  - clock-names
+  - operating-points-v2
+  - proc-supply
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/mt8183-clk.h>
+    cci: cci {
+        compatible = "mediatek,mt8183-cci";
+        clocks = <&mcucfg CLK_MCU_BUS_SEL>,
+                 <&topckgen CLK_TOP_ARMPLL_DIV_PLL1>;
+        clock-names = "cci", "intermediate";
+        operating-points-v2 = <&cci_opp>;
+        proc-supply = <&mt6358_vproc12_reg>;
+    };
+
+    cci_opp: opp-table-cci {
+        compatible = "operating-points-v2";
+        opp-shared;
+        opp2_00: opp-273000000 {
+            opp-hz = /bits/ 64 <273000000>;
+            opp-microvolt = <650000>;
+        };
+        opp2_01: opp-338000000 {
+            opp-hz = /bits/ 64 <338000000>;
+            opp-microvolt = <687500>;
+        };
+        opp2_02: opp-403000000 {
+            opp-hz = /bits/ 64 <403000000>;
+            opp-microvolt = <718750>;
+        };
+        opp2_03: opp-463000000 {
+            opp-hz = /bits/ 64 <463000000>;
+            opp-microvolt = <756250>;
+        };
+        opp2_04: opp-546000000 {
+            opp-hz = /bits/ 64 <546000000>;
+            opp-microvolt = <800000>;
+        };
+        opp2_05: opp-624000000 {
+            opp-hz = /bits/ 64 <624000000>;
+            opp-microvolt = <818750>;
+        };
+        opp2_06: opp-689000000 {
+            opp-hz = /bits/ 64 <689000000>;
+            opp-microvolt = <850000>;
+        };
+        opp2_07: opp-767000000 {
+            opp-hz = /bits/ 64 <767000000>;
+            opp-microvolt = <868750>;
+        };
+        opp2_08: opp-845000000 {
+            opp-hz = /bits/ 64 <845000000>;
+            opp-microvolt = <893750>;
+        };
+        opp2_09: opp-871000000 {
+            opp-hz = /bits/ 64 <871000000>;
+            opp-microvolt = <906250>;
+        };
+        opp2_10: opp-923000000 {
+            opp-hz = /bits/ 64 <923000000>;
+            opp-microvolt = <931250>;
+        };
+        opp2_11: opp-962000000 {
+            opp-hz = /bits/ 64 <962000000>;
+            opp-microvolt = <943750>;
+        };
+        opp2_12: opp-1027000000 {
+            opp-hz = /bits/ 64 <1027000000>;
+            opp-microvolt = <975000>;
+        };
+        opp2_13: opp-1092000000 {
+            opp-hz = /bits/ 64 <1092000000>;
+            opp-microvolt = <1000000>;
+        };
+        opp2_14: opp-1144000000 {
+            opp-hz = /bits/ 64 <1144000000>;
+            opp-microvolt = <1025000>;
+        };
+        opp2_15: opp-1196000000 {
+            opp-hz = /bits/ 64 <1196000000>;
+            opp-microvolt = <1050000>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml b/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml
new file mode 100644 (file)
index 0000000..c2e697f
--- /dev/null
@@ -0,0 +1,86 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interconnect/qcom,msm8998-bwmon.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Interconnect Bandwidth Monitor
+
+maintainers:
+  - Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+description: |
+  Bandwidth Monitor measures current throughput on buses between various NoC
+  fabrics and provides information when it crosses configured thresholds.
+
+  Certain SoCs might have more than one Bandwidth Monitors, for example on SDM845::
+   - Measuring the bandwidth between CPUs and Last Level Cache Controller -
+     called just BWMON,
+   - Measuring the bandwidth between Last Level Cache Controller and memory
+     (DDR) - called LLCC BWMON.
+
+properties:
+  compatible:
+    oneOf:
+      - items:
+          - enum:
+              - qcom,sdm845-bwmon
+          - const: qcom,msm8998-bwmon
+      - const: qcom,msm8998-bwmon       # BWMON v4
+
+  interconnects:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  operating-points-v2: true
+  opp-table: true
+
+  reg:
+    # BWMON v4 (currently described) and BWMON v5 use one register address
+    # space.  BWMON v2 uses two register spaces - not yet described.
+    maxItems: 1
+
+required:
+  - compatible
+  - interconnects
+  - interrupts
+  - operating-points-v2
+  - opp-table
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interconnect/qcom,sdm845.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    pmu@1436400 {
+        compatible = "qcom,sdm845-bwmon", "qcom,msm8998-bwmon";
+        reg = <0x01436400 0x600>;
+        interrupts = <GIC_SPI 581 IRQ_TYPE_LEVEL_HIGH>;
+        interconnects = <&gladiator_noc MASTER_APPSS_PROC 3 &mem_noc SLAVE_LLCC 3>;
+
+        operating-points-v2 = <&cpu_bwmon_opp_table>;
+
+        cpu_bwmon_opp_table: opp-table {
+            compatible = "operating-points-v2";
+            opp-0 {
+                opp-peak-kBps = <4800000>;
+            };
+            opp-1 {
+                opp-peak-kBps = <9216000>;
+            };
+            opp-2 {
+                opp-peak-kBps = <15052800>;
+            };
+            opp-3 {
+                opp-peak-kBps = <20889600>;
+            };
+            opp-4 {
+                opp-peak-kBps = <25497600>;
+            };
+        };
+    };
diff --git a/Documentation/devicetree/bindings/interconnect/samsung,exynos-bus.yaml b/Documentation/devicetree/bindings/interconnect/samsung,exynos-bus.yaml
new file mode 100644 (file)
index 0000000..ad9ed59
--- /dev/null
@@ -0,0 +1,290 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interconnect/samsung,exynos-bus.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung Exynos SoC Bus and Interconnect
+
+maintainers:
+  - Chanwoo Choi <cw00.choi@samsung.com>
+  - Krzysztof Kozlowski <krzk@kernel.org>
+
+description: |
+  The Samsung Exynos SoC has many buses for data transfer between DRAM and
+  sub-blocks in SoC. Most Exynos SoCs share the common architecture for buses.
+  Generally, each bus of Exynos SoC includes a source clock and a power line,
+  which are able to change the clock frequency of the bus in runtime. To
+  monitor the usage of each bus in runtime, the driver uses the PPMU (Platform
+  Performance Monitoring Unit), which is able to measure the current load of
+  sub-blocks.
+
+  The Exynos SoC includes the various sub-blocks which have the each AXI bus.
+  The each AXI bus has the owned source clock but, has not the only owned power
+  line. The power line might be shared among one more sub-blocks.  So, we can
+  divide into two type of device as the role of each sub-block.  There are two
+  type of bus devices as following::
+   - parent bus device
+   - passive bus device
+
+  Basically, parent and passive bus device share the same power line.  The
+  parent bus device can only change the voltage of shared power line and the
+  rest bus devices (passive bus device) depend on the decision of the parent
+  bus device. If there are three blocks which share the VDD_xxx power line,
+  Only one block should be parent device and then the rest blocks should depend
+  on the parent device as passive device.
+
+    VDD_xxx |--- A block (parent)
+      |--- B block (passive)
+      |--- C block (passive)
+
+  There are a little different composition among Exynos SoC because each Exynos
+  SoC has different sub-blocks. Therefore, such difference should be specified
+  in devicetree file instead of each device driver. In result, this driver is
+  able to support the bus frequency for all Exynos SoCs.
+
+  Detailed correlation between sub-blocks and power line according
+  to Exynos SoC::
+   - In case of Exynos3250, there are two power line as following::
+     VDD_MIF |--- DMC (Dynamic Memory Controller)
+
+     VDD_INT |--- LEFTBUS (parent device)
+       |--- PERIL
+       |--- MFC
+       |--- G3D
+       |--- RIGHTBUS
+       |--- PERIR
+       |--- FSYS
+       |--- LCD0
+       |--- PERIR
+       |--- ISP
+       |--- CAM
+
+     - MIF bus's frequency/voltage table
+       -----------------------
+       |Lv| Freq   | Voltage |
+       -----------------------
+       |L1| 50000  |800000   |
+       |L2| 100000 |800000   |
+       |L3| 134000 |800000   |
+       |L4| 200000 |825000   |
+       |L5| 400000 |875000   |
+       -----------------------
+
+     - INT bus's frequency/voltage table
+       ----------------------------------------------------------
+       |Block|LEFTBUS|RIGHTBUS|MCUISP |ISP    |PERIL  ||VDD_INT |
+       | name|       |LCD0    |       |       |       ||        |
+       |     |       |FSYS    |       |       |       ||        |
+       |     |       |MFC     |       |       |       ||        |
+       ----------------------------------------------------------
+       |Mode |*parent|passive |passive|passive|passive||        |
+       ----------------------------------------------------------
+       |Lv   |Frequency                               ||Voltage |
+       ----------------------------------------------------------
+       |L1   |50000  |50000   |50000  |50000  |50000  ||900000  |
+       |L2   |80000  |80000   |80000  |80000  |80000  ||900000  |
+       |L3   |100000 |100000  |100000 |100000 |100000 ||1000000 |
+       |L4   |134000 |134000  |200000 |200000 |       ||1000000 |
+       |L5   |200000 |200000  |400000 |300000 |       ||1000000 |
+       ----------------------------------------------------------
+
+   - In case of Exynos4210, there is one power line as following::
+     VDD_INT |--- DMC (parent device, Dynamic Memory Controller)
+       |--- LEFTBUS
+       |--- PERIL
+       |--- MFC(L)
+       |--- G3D
+       |--- TV
+       |--- LCD0
+       |--- RIGHTBUS
+       |--- PERIR
+       |--- MFC(R)
+       |--- CAM
+       |--- FSYS
+       |--- GPS
+       |--- LCD0
+       |--- LCD1
+
+   - In case of Exynos4x12, there are two power line as following::
+     VDD_MIF |--- DMC (Dynamic Memory Controller)
+
+     VDD_INT |--- LEFTBUS (parent device)
+       |--- PERIL
+       |--- MFC(L)
+       |--- G3D
+       |--- TV
+       |--- IMAGE
+       |--- RIGHTBUS
+       |--- PERIR
+       |--- MFC(R)
+       |--- CAM
+       |--- FSYS
+       |--- GPS
+       |--- LCD0
+       |--- ISP
+
+   - In case of Exynos5422, there are two power line as following::
+     VDD_MIF |--- DREX 0 (parent device, DRAM EXpress controller)
+             |--- DREX 1
+
+     VDD_INT |--- NoC_Core (parent device)
+       |--- G2D
+       |--- G3D
+       |--- DISP1
+       |--- NoC_WCORE
+       |--- GSCL
+       |--- MSCL
+       |--- ISP
+       |--- MFC
+       |--- GEN
+       |--- PERIS
+       |--- PERIC
+       |--- FSYS
+       |--- FSYS2
+
+   - In case of Exynos5433, there is VDD_INT power line as following::
+     VDD_INT |--- G2D (parent device)
+       |--- MSCL
+       |--- GSCL
+       |--- JPEG
+       |--- MFC
+       |--- HEVC
+       |--- BUS0
+       |--- BUS1
+       |--- BUS2
+       |--- PERIS (Fixed clock rate)
+       |--- PERIC (Fixed clock rate)
+       |--- FSYS  (Fixed clock rate)
+
+properties:
+  compatible:
+    enum:
+      - samsung,exynos-bus
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: bus
+
+  devfreq:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      Parent bus device. Valid and required only for the passive bus devices.
+
+  devfreq-events:
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    minItems: 1
+    maxItems: 4
+    description:
+      Devfreq-event device to monitor the current utilization of buses. Valid
+      and required only for the parent bus devices.
+
+  exynos,saturation-ratio:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      Percentage value which is used to calibrate the performance count against
+      total cycle count.  Valid only for the parent bus devices.
+
+  '#interconnect-cells':
+    const: 0
+
+  interconnects:
+    minItems: 1
+    maxItems: 2
+
+  operating-points-v2: true
+
+  samsung,data-clock-ratio:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    default: 8
+    description:
+      Ratio of the data throughput in B/s to minimum data clock frequency in
+      Hz.
+
+  vdd-supply:
+    description:
+      Main bus power rail. Valid and required only for the parent bus devices.
+
+required:
+  - compatible
+  - clocks
+  - clock-names
+  - operating-points-v2
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/exynos3250.h>
+
+    bus-dmc {
+        compatible = "samsung,exynos-bus";
+        clocks = <&cmu_dmc CLK_DIV_DMC>;
+        clock-names = "bus";
+        operating-points-v2 = <&bus_dmc_opp_table>;
+        devfreq-events = <&ppmu_dmc0_3>, <&ppmu_dmc1_3>;
+        vdd-supply = <&buck1_reg>;
+    };
+
+    ppmu_dmc0: ppmu@106a0000 {
+        compatible = "samsung,exynos-ppmu";
+        reg = <0x106a0000 0x2000>;
+        events {
+            ppmu_dmc0_3: ppmu-event3-dmc0 {
+                event-name = "ppmu-event3-dmc0";
+            };
+        };
+    };
+
+    bus_leftbus: bus-leftbus {
+        compatible = "samsung,exynos-bus";
+        clocks = <&cmu CLK_DIV_GDL>;
+        clock-names = "bus";
+        operating-points-v2 = <&bus_leftbus_opp_table>;
+        devfreq-events = <&ppmu_leftbus_3>, <&ppmu_rightbus_3>;
+        vdd-supply = <&buck3_reg>;
+    };
+
+    bus-rightbus {
+        compatible = "samsung,exynos-bus";
+        clocks = <&cmu CLK_DIV_GDR>;
+        clock-names = "bus";
+        operating-points-v2 = <&bus_leftbus_opp_table>;
+        devfreq = <&bus_leftbus>;
+    };
+
+  - |
+    dmc: bus-dmc {
+        compatible = "samsung,exynos-bus";
+        clocks = <&clock CLK_DIV_DMC>;
+        clock-names = "bus";
+        operating-points-v2 = <&bus_dmc_opp_table>;
+        samsung,data-clock-ratio = <4>;
+        #interconnect-cells = <0>;
+        devfreq-events = <&ppmu_dmc0_3>, <&ppmu_dmc1_3>;
+        vdd-supply = <&buck1_reg>;
+    };
+
+    leftbus: bus-leftbus {
+        compatible = "samsung,exynos-bus";
+        clocks = <&clock CLK_DIV_GDL>;
+        clock-names = "bus";
+        operating-points-v2 = <&bus_leftbus_opp_table>;
+        interconnects = <&dmc>;
+        #interconnect-cells = <0>;
+        devfreq-events = <&ppmu_leftbus_3>, <&ppmu_rightbus_3>;
+        vdd-supply = <&buck3_reg>;
+    };
+
+    display: bus-display {
+        compatible = "samsung,exynos-bus";
+        clocks = <&clock CLK_DIV_ACLK_266>;
+        clock-names = "bus";
+        operating-points-v2 = <&bus_display_opp_table>;
+        interconnects = <&leftbus &dmc>;
+        #interconnect-cells = <0>;
+        devfreq = <&leftbus>;
+    };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,rzg2l-irqc.yaml b/Documentation/devicetree/bindings/interrupt-controller/renesas,rzg2l-irqc.yaml
new file mode 100644 (file)
index 0000000..33b90e9
--- /dev/null
@@ -0,0 +1,134 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interrupt-controller/renesas,rzg2l-irqc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas RZ/G2L (and alike SoC's) Interrupt Controller (IA55)
+
+maintainers:
+  - Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
+  - Geert Uytterhoeven <geert+renesas@glider.be>
+
+description: |
+  IA55 performs various interrupt controls including synchronization for the external
+  interrupts of NMI, IRQ, and GPIOINT and the interrupts of the built-in peripheral
+  interrupts output by each IP. And it notifies the interrupt to the GIC
+    - IRQ sense select for 8 external interrupts, mapped to 8 GIC SPI interrupts
+    - GPIO pins used as external interrupt input pins, mapped to 32 GIC SPI interrupts
+    - NMI edge select (NMI is not treated as NMI exception and supports fall edge and
+      stand-up edge detection interrupts)
+
+allOf:
+  - $ref: /schemas/interrupt-controller.yaml#
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - renesas,r9a07g044-irqc    # RZ/G2{L,LC}
+          - renesas,r9a07g054-irqc    # RZ/V2L
+      - const: renesas,rzg2l-irqc
+
+  '#interrupt-cells':
+    description: The first cell should contain external interrupt number (IRQ0-7) and the
+                 second cell is used to specify the flag.
+    const: 2
+
+  '#address-cells':
+    const: 0
+
+  interrupt-controller: true
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 41
+
+  clocks:
+    maxItems: 2
+
+  clock-names:
+    items:
+      - const: clk
+      - const: pclk
+
+  power-domains:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+required:
+  - compatible
+  - '#interrupt-cells'
+  - '#address-cells'
+  - interrupt-controller
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - power-domains
+  - resets
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/r9a07g044-cpg.h>
+
+    irqc: interrupt-controller@110a0000 {
+            compatible = "renesas,r9a07g044-irqc", "renesas,rzg2l-irqc";
+            reg = <0x110a0000 0x10000>;
+            #interrupt-cells = <2>;
+            #address-cells = <0>;
+            interrupt-controller;
+            interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 444 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 445 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 446 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 447 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 448 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 450 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 451 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 452 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 453 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 454 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 455 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 456 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 457 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 458 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 459 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 460 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 461 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 462 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 463 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 470 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 471 IRQ_TYPE_LEVEL_HIGH>,
+                         <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>;
+            clocks = <&cpg CPG_MOD R9A07G044_IA55_CLK>,
+                     <&cpg CPG_MOD R9A07G044_IA55_PCLK>;
+            clock-names = "clk", "pclk";
+            power-domains = <&cpg>;
+            resets = <&cpg R9A07G044_IA55_RESETN>;
+    };
index 27092c6..92e0f8c 100644 (file)
@@ -26,9 +26,14 @@ description:
   with priority below this threshold will not cause the PLIC to raise its
   interrupt line leading to the context.
 
-  While the PLIC supports both edge-triggered and level-triggered interrupts,
-  interrupt handlers are oblivious to this distinction and therefore it is not
-  specified in the PLIC device-tree binding.
+  The PLIC supports both edge-triggered and level-triggered interrupts. For
+  edge-triggered interrupts, the RISC-V PLIC spec allows two responses to edges
+  seen while an interrupt handler is active; the PLIC may either queue them or
+  ignore them. In the first case, handlers are oblivious to the trigger type, so
+  it is not included in the interrupt specifier. In the second case, software
+  needs to know the trigger type, so it can reorder the interrupt flow to avoid
+  missing interrupts. This special handling is needed by at least the Renesas
+  RZ/Five SoC (AX45MP AndesCore with a NCEPLIC100) and the T-HEAD C900 PLIC.
 
   While the RISC-V ISA doesn't specify a memory layout for the PLIC, the
   "sifive,plic-1.0.0" device is a concrete implementation of the PLIC that
@@ -49,6 +54,10 @@ properties:
     oneOf:
       - items:
           - enum:
+              - renesas,r9a07g043-plic
+          - const: andestech,nceplic100
+      - items:
+          - enum:
               - sifive,fu540-c000-plic
               - starfive,jh7100-plic
               - canaan,k210-plic
@@ -64,8 +73,7 @@ properties:
   '#address-cells':
     const: 0
 
-  '#interrupt-cells':
-    const: 1
+  '#interrupt-cells': true
 
   interrupt-controller: true
 
@@ -82,6 +90,12 @@ properties:
     description:
       Specifies how many external interrupts are supported by this controller.
 
+  clocks: true
+
+  power-domains: true
+
+  resets: true
+
 required:
   - compatible
   - '#address-cells'
@@ -91,6 +105,47 @@ required:
   - interrupts-extended
   - riscv,ndev
 
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - andestech,nceplic100
+              - thead,c900-plic
+
+    then:
+      properties:
+        '#interrupt-cells':
+          const: 2
+
+    else:
+      properties:
+        '#interrupt-cells':
+          const: 1
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: renesas,r9a07g043-plic
+
+    then:
+      properties:
+        clocks:
+          maxItems: 1
+
+        power-domains:
+          maxItems: 1
+
+        resets:
+          maxItems: 1
+
+      required:
+        - clocks
+        - power-domains
+        - resets
+
 additionalProperties: false
 
 examples:
diff --git a/Documentation/devicetree/bindings/interrupt-controller/sunplus,sp7021-intc.yaml b/Documentation/devicetree/bindings/interrupt-controller/sunplus,sp7021-intc.yaml
new file mode 100644 (file)
index 0000000..bd0021d
--- /dev/null
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) Sunplus Co., Ltd. 2021
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interrupt-controller/sunplus,sp7021-intc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sunplus SP7021 SoC Interrupt Controller
+
+maintainers:
+  - Qin Jian <qinjian@cqplus1.com>
+
+properties:
+  compatible:
+    items:
+      - const: sunplus,sp7021-intc
+
+  reg:
+    maxItems: 2
+    description:
+      Specifies base physical address(s) and size of the controller regs.
+      The 1st region include type/polarity/priority/mask regs.
+      The 2nd region include clear/masked_ext0/masked_ext1/group regs.
+
+  interrupt-controller: true
+
+  "#interrupt-cells":
+    const: 2
+    description:
+      The first cell is the IRQ number, the second cell is the trigger
+      type as defined in interrupt.txt in this directory.
+
+  interrupts:
+    maxItems: 2
+    description:
+      EXT_INT0 & EXT_INT1, 2 interrupts references to primary interrupt
+      controller.
+
+required:
+  - compatible
+  - reg
+  - interrupt-controller
+  - "#interrupt-cells"
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    intc: interrupt-controller@9c000780 {
+        compatible = "sunplus,sp7021-intc";
+        reg = <0x9c000780 0x80>, <0x9c000a80 0x80>;
+        interrupt-controller;
+        #interrupt-cells = <2>;
+        interrupt-parent = <&gic>;
+        interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>, /* EXT_INT0 */
+                     <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>; /* EXT_INT1 */
+    };
+
+...
index a98b359..71bc5ce 100644 (file)
@@ -32,6 +32,7 @@ properties:
           - mediatek,mt2701-smi-common
           - mediatek,mt2712-smi-common
           - mediatek,mt6779-smi-common
+          - mediatek,mt6795-smi-common
           - mediatek,mt8167-smi-common
           - mediatek,mt8173-smi-common
           - mediatek,mt8183-smi-common
index c886681..59dcd16 100644 (file)
@@ -20,6 +20,7 @@ properties:
           - mediatek,mt2701-smi-larb
           - mediatek,mt2712-smi-larb
           - mediatek,mt6779-smi-larb
+          - mediatek,mt6795-smi-larb
           - mediatek,mt8167-smi-larb
           - mediatek,mt8173-smi-larb
           - mediatek,mt8183-smi-larb
index 6a4831f..55fc620 100644 (file)
@@ -22,6 +22,7 @@ properties:
           - enum:
               - allwinner,sun20i-d1-emac
               - allwinner,sun50i-h6-emac
+              - allwinner,sun50i-h616-emac0
           - const: allwinner,sun50i-a64-emac
 
   reg:
index 4f15463..170cd20 100644 (file)
@@ -167,70 +167,65 @@ properties:
       - in-band-status
 
   fixed-link:
-    allOf:
-      - if:
-          type: array
-        then:
-          deprecated: true
-          items:
-            - minimum: 0
-              maximum: 31
-              description:
-                Emulated PHY ID, choose any but unique to the all
-                specified fixed-links
-
-            - enum: [0, 1]
-              description:
-                Duplex configuration. 0 for half duplex or 1 for
-                full duplex
-
-            - enum: [10, 100, 1000, 2500, 10000]
-              description:
-                Link speed in Mbits/sec.
-
-            - enum: [0, 1]
-              description:
-                Pause configuration. 0 for no pause, 1 for pause
-
-            - enum: [0, 1]
-              description:
-                Asymmetric pause configuration. 0 for no asymmetric
-                pause, 1 for asymmetric pause
-
-
-      - if:
-          type: object
-        then:
-          properties:
-            speed:
-              description:
-                Link speed.
-              $ref: /schemas/types.yaml#/definitions/uint32
-              enum: [10, 100, 1000, 2500, 10000]
-
-            full-duplex:
-              $ref: /schemas/types.yaml#/definitions/flag
-              description:
-                Indicates that full-duplex is used. When absent, half
-                duplex is assumed.
-
-            pause:
-              $ref: /schemas/types.yaml#definitions/flag
-              description:
-                Indicates that pause should be enabled.
-
-            asym-pause:
-              $ref: /schemas/types.yaml#/definitions/flag
-              description:
-                Indicates that asym_pause should be enabled.
-
-            link-gpios:
-              maxItems: 1
-              description:
-                GPIO to determine if the link is up
-
-          required:
-            - speed
+    oneOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32-array
+        deprecated: true
+        items:
+          - minimum: 0
+            maximum: 31
+            description:
+              Emulated PHY ID, choose any but unique to the all
+              specified fixed-links
+
+          - enum: [0, 1]
+            description:
+              Duplex configuration. 0 for half duplex or 1 for
+              full duplex
+
+          - enum: [10, 100, 1000, 2500, 10000]
+            description:
+              Link speed in Mbits/sec.
+
+          - enum: [0, 1]
+            description:
+              Pause configuration. 0 for no pause, 1 for pause
+
+          - enum: [0, 1]
+            description:
+              Asymmetric pause configuration. 0 for no asymmetric
+              pause, 1 for asymmetric pause
+      - type: object
+        additionalProperties: false
+        properties:
+          speed:
+            description:
+              Link speed.
+            $ref: /schemas/types.yaml#/definitions/uint32
+            enum: [10, 100, 1000, 2500, 10000]
+
+          full-duplex:
+            $ref: /schemas/types.yaml#/definitions/flag
+            description:
+              Indicates that full-duplex is used. When absent, half
+              duplex is assumed.
+
+          pause:
+            $ref: /schemas/types.yaml#definitions/flag
+            description:
+              Indicates that pause should be enabled.
+
+          asym-pause:
+            $ref: /schemas/types.yaml#/definitions/flag
+            description:
+              Indicates that asym_pause should be enabled.
+
+          link-gpios:
+            maxItems: 1
+            description:
+              GPIO to determine if the link is up
+
+        required:
+          - speed
 
 additionalProperties: true
 
index daa2f79..1b18530 100644 (file)
@@ -183,6 +183,7 @@ properties:
       Should specify the gpio for phy reset.
 
   phy-reset-duration:
+    $ref: /schemas/types.yaml#/definitions/uint32
     deprecated: true
     description:
       Reset duration in milliseconds.  Should present only if property
@@ -191,12 +192,14 @@ properties:
       and 1 millisecond will be used instead.
 
   phy-reset-active-high:
+    type: boolean
     deprecated: true
     description:
       If present then the reset sequence using the GPIO specified in the
       "phy-reset-gpios" property is reversed (H=reset state, L=operation state).
 
   phy-reset-post-delay:
+    $ref: /schemas/types.yaml#/definitions/uint32
     deprecated: true
     description:
       Post reset delay in milliseconds. If present then a delay of phy-reset-post-delay
diff --git a/Documentation/devicetree/bindings/net/pcs/renesas,rzn1-miic.yaml b/Documentation/devicetree/bindings/net/pcs/renesas,rzn1-miic.yaml
new file mode 100644 (file)
index 0000000..2d33bba
--- /dev/null
@@ -0,0 +1,171 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/pcs/renesas,rzn1-miic.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas RZ/N1 MII converter
+
+maintainers:
+  - Clément Léger <clement.leger@bootlin.com>
+
+description: |
+  This MII converter is present on the Renesas RZ/N1 SoC family. It is
+  responsible to do MII passthrough or convert it to RMII/RGMII.
+
+properties:
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
+  compatible:
+    items:
+      - enum:
+          - renesas,r9a06g032-miic
+      - const: renesas,rzn1-miic
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: MII reference clock
+      - description: RGMII reference clock
+      - description: RMII reference clock
+      - description: AHB clock used for the MII converter register interface
+
+  clock-names:
+    items:
+      - const: mii_ref
+      - const: rgmii_ref
+      - const: rmii_ref
+      - const: hclk
+
+  renesas,miic-switch-portin:
+    description: MII Switch PORTIN configuration. This value should use one of
+      the values defined in dt-bindings/net/pcs-rzn1-miic.h.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [1, 2]
+
+  power-domains:
+    maxItems: 1
+
+patternProperties:
+  "^mii-conv@[0-5]$":
+    type: object
+    description: MII converter port
+
+    properties:
+      reg:
+        description: MII Converter port number.
+        enum: [1, 2, 3, 4, 5]
+
+      renesas,miic-input:
+        description: Converter input port configuration. This value should use
+          one of the values defined in dt-bindings/net/pcs-rzn1-miic.h.
+        $ref: /schemas/types.yaml#/definitions/uint32
+
+    required:
+      - reg
+      - renesas,miic-input
+
+    additionalProperties: false
+
+    allOf:
+      - if:
+          properties:
+            reg:
+              const: 1
+        then:
+          properties:
+            renesas,miic-input:
+              const: 0
+      - if:
+          properties:
+            reg:
+              const: 2
+        then:
+          properties:
+            renesas,miic-input:
+              enum: [1, 11]
+      - if:
+          properties:
+            reg:
+              const: 3
+        then:
+          properties:
+            renesas,miic-input:
+              enum: [7, 10]
+      - if:
+          properties:
+            reg:
+              const: 4
+        then:
+          properties:
+            renesas,miic-input:
+              enum: [4, 6, 9, 13]
+      - if:
+          properties:
+            reg:
+              const: 5
+        then:
+          properties:
+            renesas,miic-input:
+              enum: [3, 5, 8, 12]
+
+required:
+  - '#address-cells'
+  - '#size-cells'
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - power-domains
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/net/pcs-rzn1-miic.h>
+    #include <dt-bindings/clock/r9a06g032-sysctrl.h>
+
+    eth-miic@44030000 {
+      #address-cells = <1>;
+      #size-cells = <0>;
+      compatible = "renesas,r9a06g032-miic", "renesas,rzn1-miic";
+      reg = <0x44030000 0x10000>;
+      clocks = <&sysctrl R9A06G032_CLK_MII_REF>,
+              <&sysctrl R9A06G032_CLK_RGMII_REF>,
+              <&sysctrl R9A06G032_CLK_RMII_REF>,
+              <&sysctrl R9A06G032_HCLK_SWITCH_RG>;
+      clock-names = "mii_ref", "rgmii_ref", "rmii_ref", "hclk";
+      renesas,miic-switch-portin = <MIIC_GMAC2_PORT>;
+      power-domains = <&sysctrl>;
+
+      mii_conv1: mii-conv@1 {
+        renesas,miic-input = <MIIC_GMAC1_PORT>;
+        reg = <1>;
+      };
+
+      mii_conv2: mii-conv@2 {
+        renesas,miic-input = <MIIC_SWITCH_PORTD>;
+        reg = <2>;
+      };
+
+      mii_conv3: mii-conv@3 {
+        renesas,miic-input = <MIIC_SWITCH_PORTC>;
+        reg = <3>;
+      };
+
+      mii_conv4: mii-conv@4 {
+        renesas,miic-input = <MIIC_SWITCH_PORTB>;
+        reg = <4>;
+      };
+
+      mii_conv5: mii-conv@5 {
+        renesas,miic-input = <MIIC_SWITCH_PORTA>;
+        reg = <5>;
+      };
+    };
index 8cd0adb..7029cb1 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Qualcomm Atheros ath9k wireless devices Generic Binding
 
 maintainers:
-  - Kalle Valo <kvalo@codeaurora.org>
+  - Toke Høiland-Jørgensen <toke@toke.dk>
 
 description: |
   This node provides properties for configuring the ath9k wireless device.
index 8c01fdb..a677b05 100644 (file)
@@ -9,7 +9,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Qualcomm Technologies ath11k wireless devices Generic Binding
 
 maintainers:
-  - Kalle Valo <kvalo@codeaurora.org>
+  - Kalle Valo <kvalo@kernel.org>
 
 description: |
   These are dt entries for Qualcomm Technologies, Inc. IEEE 802.11ax
diff --git a/Documentation/devicetree/bindings/nvmem/fsl,scu-ocotp.yaml b/Documentation/devicetree/bindings/nvmem/fsl,scu-ocotp.yaml
new file mode 100644 (file)
index 0000000..6826882
--- /dev/null
@@ -0,0 +1,56 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/nvmem/fsl,scu-ocotp.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: i.MX SCU Client Device Node - OCOTP bindings based on SCU Message Protocol
+
+maintainers:
+  - Dong Aisheng <aisheng.dong@nxp.com>
+
+description: i.MX SCU Client Device Node
+  Client nodes are maintained as children of the relevant IMX-SCU device node.
+
+allOf:
+  - $ref: nvmem.yaml#
+
+properties:
+  compatible:
+    enum:
+      - fsl,imx8qm-scu-ocotp
+      - fsl,imx8qxp-scu-ocotp
+
+patternProperties:
+  '^mac@[0-9a-f]*$':
+    type: object
+    description:
+      MAC address.
+
+    properties:
+      reg:
+        description:
+          Byte offset within OCOTP where the MAC address is stored
+        maxItems: 1
+
+    required:
+      - reg
+
+    additionalProperties: false
+
+required:
+  - compatible
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    ocotp {
+        compatible = "fsl,imx8qxp-scu-ocotp";
+        #address-cells = <1>;
+        #size-cells = <1>;
+
+        fec_mac0: mac@2c4 {
+            reg = <0x2c4 6>;
+        };
+    };
index bfce850..0681b9a 100644 (file)
@@ -127,20 +127,17 @@ patternProperties:
 
     additionalProperties: false
 
-  "^vcc-p[a-hlm]-supply$":
+  "^vcc-p[a-ilm]-supply$":
     description:
       Power supplies for pin banks.
 
 required:
   - "#gpio-cells"
-  - "#interrupt-cells"
   - compatible
   - reg
-  - interrupts
   - clocks
   - clock-names
   - gpio-controller
-  - interrupt-controller
 
 allOf:
   # FIXME: We should have the pin bank supplies here, but not a lot of
@@ -149,6 +146,19 @@ allOf:
 
   - $ref: "pinctrl.yaml#"
   - if:
+      not:
+        properties:
+          compatible:
+            enum:
+              - allwinner,sun50i-h616-r-pinctrl
+
+    then:
+      required:
+        - "#interrupt-cells"
+        - interrupts
+        - interrupt-controller
+
+  - if:
       properties:
         compatible:
           enum:
diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,scu-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/fsl,scu-pinctrl.yaml
new file mode 100644 (file)
index 0000000..45ea565
--- /dev/null
@@ -0,0 +1,74 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/fsl,scu-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: i.MX SCU Client Device Node - Pinctrl bindings based on SCU Message Protocol
+
+maintainers:
+  - Dong Aisheng <aisheng.dong@nxp.com>
+
+description: i.MX SCU Client Device Node
+  Client nodes are maintained as children of the relevant IMX-SCU device node.
+  This binding uses the i.MX common pinctrl binding.
+  (Documentation/devicetree/bindings/pinctrl/fsl,imx-pinctrl.txt)
+
+allOf:
+  - $ref: pinctrl.yaml#
+
+properties:
+  compatible:
+    enum:
+      - fsl,imx8qm-iomuxc
+      - fsl,imx8qxp-iomuxc
+      - fsl,imx8dxl-iomuxc
+
+patternProperties:
+  'grp$':
+    type: object
+    description:
+      Pinctrl node's client devices use subnodes for desired pin configuration.
+      Client device subnodes use below standard properties.
+
+    properties:
+      fsl,pins:
+        description:
+          each entry consists of 3 integers and represents the pin ID, the mux value
+          and pad setting for the pin. The first 2 integers - pin_id and mux_val - are
+          specified using a PIN_FUNC_ID macro, which can be found in
+          <include/dt-bindings/pinctrl/pads-imx8qxp.h>. The last integer is
+          the pad setting value like pull-up on this pin. Please refer to the
+          appropriate i.MX8 Reference Manual for detailed pad CONFIG settings.
+        $ref: /schemas/types.yaml#/definitions/uint32-matrix
+        items:
+          items:
+            - description: |
+                "pin_id" indicates the pin ID
+            - description: |
+                "mux_val" indicates the mux value to be applied.
+            - description: |
+                "pad_setting" indicates the pad configuration value to be applied.
+
+    required:
+      - fsl,pins
+
+    additionalProperties: false
+
+required:
+  - compatible
+
+additionalProperties: false
+
+examples:
+  - |
+    pinctrl {
+        compatible = "fsl,imx8qxp-iomuxc";
+
+        pinctrl_lpuart0: lpuart0grp {
+            fsl,pins = <
+                111 0 0x06000020
+                112 0 0x06000020
+            >;
+        };
+    };
index 52df1b1..997b746 100644 (file)
@@ -47,6 +47,17 @@ properties:
   gpio-ranges:
     maxItems: 1
 
+  interrupt-controller: true
+
+  '#interrupt-cells':
+    const: 2
+    description:
+      The first cell contains the global GPIO port index, constructed using the
+      RZG2L_GPIO() helper macro in <dt-bindings/pinctrl/rzg2l-pinctrl.h> and the
+      second cell is used to specify the flag.
+      E.g. "interrupts = <RZG2L_GPIO(43, 0) IRQ_TYPE_EDGE_FALLING>;" if P43_0 is
+      being used as an interrupt.
+
   clocks:
     maxItems: 1
 
@@ -110,6 +121,8 @@ required:
   - gpio-controller
   - '#gpio-cells'
   - gpio-ranges
+  - interrupt-controller
+  - '#interrupt-cells'
   - clocks
   - power-domains
   - resets
@@ -126,6 +139,8 @@ examples:
             gpio-controller;
             #gpio-cells = <2>;
             gpio-ranges = <&pinctrl 0 0 392>;
+            interrupt-controller;
+            #interrupt-cells = <2>;
             clocks = <&cpg CPG_MOD R9A07G044_GPIO_HCLK>;
             resets = <&cpg R9A07G044_GPIO_RSTN>,
                      <&cpg R9A07G044_GPIO_PORT_RESETN>,
diff --git a/Documentation/devicetree/bindings/power/fsl,scu-pd.yaml b/Documentation/devicetree/bindings/power/fsl,scu-pd.yaml
new file mode 100644 (file)
index 0000000..1f72b18
--- /dev/null
@@ -0,0 +1,41 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/power/fsl,scu-pd.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: i.MX SCU Client Device Node - Power domain bindings based on SCU Message Protocol
+
+maintainers:
+  - Dong Aisheng <aisheng.dong@nxp.com>
+
+description: i.MX SCU Client Device Node
+  Client nodes are maintained as children of the relevant IMX-SCU device node.
+  Power domain bindings based on SCU Message Protocol
+
+allOf:
+  - $ref: power-domain.yaml#
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - fsl,imx8qm-scu-pd
+          - fsl,imx8qxp-scu-pd
+      - const: fsl,scu-pd
+
+  '#power-domain-cells':
+    const: 1
+
+required:
+  - compatible
+  - '#power-domain-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    power-controller {
+        compatible = "fsl,imx8qxp-scu-pd", "fsl,scu-pd";
+        #power-domain-cells = <1>;
+    };
index 135c6f7..b448101 100644 (file)
@@ -23,6 +23,7 @@ properties:
 
   compatible:
     enum:
+      - mediatek,mt6795-power-controller
       - mediatek,mt8167-power-controller
       - mediatek,mt8173-power-controller
       - mediatek,mt8183-power-controller
@@ -62,6 +63,7 @@ patternProperties:
       reg:
         description: |
           Power domain index. Valid values are defined in:
+              "include/dt-bindings/power/mt6795-power.h" - for MT8167 type power domain.
               "include/dt-bindings/power/mt8167-power.h" - for MT8167 type power domain.
               "include/dt-bindings/power/mt8173-power.h" - for MT8173 type power domain.
               "include/dt-bindings/power/mt8183-power.h" - for MT8183 type power domain.
index ad77a63..0ccca49 100644 (file)
@@ -18,6 +18,7 @@ properties:
     enum:
       - qcom,mdm9607-rpmpd
       - qcom,msm8226-rpmpd
+      - qcom,msm8909-rpmpd
       - qcom,msm8916-rpmpd
       - qcom,msm8939-rpmpd
       - qcom,msm8953-rpmpd
diff --git a/Documentation/devicetree/bindings/pwm/clk-pwm.yaml b/Documentation/devicetree/bindings/pwm/clk-pwm.yaml
new file mode 100644 (file)
index 0000000..ec17682
--- /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/pwm/clk-pwm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Clock based PWM controller
+
+maintainers:
+  - Nikita Travkin <nikita@trvn.ru>
+
+description: |
+  Some systems have clocks that can be exposed to external devices.
+  (e.g. by muxing them to GPIO pins)
+  It's often possible to control duty-cycle of such clocks which makes them
+  suitable for generating PWM signal.
+
+allOf:
+  - $ref: pwm.yaml#
+
+properties:
+  compatible:
+    const: clk-pwm
+
+  clocks:
+    description: Clock used to generate the signal.
+    maxItems: 1
+
+  "#pwm-cells":
+    const: 2
+
+unevaluatedProperties: false
+
+required:
+  - compatible
+  - clocks
+
+examples:
+  - |
+    pwm {
+      compatible = "clk-pwm";
+      #pwm-cells = <2>;
+      clocks = <&gcc 0>;
+      pinctrl-names = "default";
+      pinctrl-0 = <&pwm_clk_flash_default>;
+    };
index 033d1fc..554c96b 100644 (file)
@@ -9,6 +9,8 @@ Required properties:
    - "mediatek,mt7628-pwm": found on mt7628 SoC.
    - "mediatek,mt7629-pwm": found on mt7629 SoC.
    - "mediatek,mt8183-pwm": found on mt8183 SoC.
+   - "mediatek,mt8195-pwm", "mediatek,mt8183-pwm": found on mt8195 SoC.
+   - "mediatek,mt8365-pwm": found on mt8365 SoC.
    - "mediatek,mt8516-pwm": found on mt8516 SoC.
  - reg: physical base address and length of the controller's registers.
  - #pwm-cells: must be 2. See pwm.yaml in this directory for a description of
@@ -18,6 +20,7 @@ Required properties:
                 has no clocks
    - "top": the top clock generator
    - "main": clock used by the PWM core
+   - "pwm1-3": the three per PWM clocks for mt8365
    - "pwm1-8": the eight per PWM clocks for mt2712
    - "pwm1-6": the six per PWM clocks for mt7622
    - "pwm1-5": the five per PWM clocks for mt7623
index 90727fd..7023c59 100644 (file)
@@ -15,6 +15,7 @@ properties:
   compatible:
     enum:
       - mps,mp5416
+      - mps,mp5496
 
   reg:
     maxItems: 1
diff --git a/Documentation/devicetree/bindings/regulator/pwm-regulator.txt b/Documentation/devicetree/bindings/regulator/pwm-regulator.txt
deleted file mode 100644 (file)
index 3d78d50..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-Bindings for the Generic PWM Regulator
-======================================
-
-Currently supports 2 modes of operation:
-
-Voltage Table:         When in this mode, a voltage table (See below) of
-                       predefined voltage <=> duty-cycle values must be
-                       provided via DT. Limitations are that the regulator can
-                       only operate at the voltages supplied in the table.
-                       Intermediary duty-cycle values which would normally
-                       allow finer grained voltage selection are ignored and
-                       rendered useless.  Although more control is given to
-                       the user if the assumptions made in continuous-voltage
-                       mode do not reign true.
-
-Continuous Voltage:    This mode uses the regulator's maximum and minimum
-                       supplied voltages specified in the
-                       regulator-{min,max}-microvolt properties to calculate
-                       appropriate duty-cycle values.  This allows for a much
-                       more fine grained solution when compared with
-                       voltage-table mode above.  This solution does make an
-                       assumption that a %50 duty-cycle value will cause the
-                       regulator voltage to run at half way between the
-                       supplied max_uV and min_uV values.
-
-Required properties:
---------------------
-- compatible:          Should be "pwm-regulator"
-
-- pwms:                        PWM specification (See: ../pwm/pwm.txt)
-
-Only required for Voltage Table Mode:
-- voltage-table:       Voltage and Duty-Cycle table consisting of 2 cells
-                           First cell is voltage in microvolts (uV)
-                           Second cell is duty-cycle in percent (%)
-
-Optional properties for Continuous mode:
-- pwm-dutycycle-unit:  Integer value encoding the duty cycle unit. If not
-                       defined, <100> is assumed, meaning that
-                       pwm-dutycycle-range contains values expressed in
-                       percent.
-
-- pwm-dutycycle-range: Should contain 2 entries. The first entry is encoding
-                       the dutycycle for regulator-min-microvolt and the
-                       second one the dutycycle for regulator-max-microvolt.
-                       Duty cycle values are expressed in pwm-dutycycle-unit.
-                       If not defined, <0 100> is assumed.
-
-NB: To be clear, if voltage-table is provided, then the device will be used
-in Voltage Table Mode.  If no voltage-table is provided, then the device will
-be used in Continuous Voltage Mode.
-
-Optional properties:
---------------------
-- enable-gpios:                GPIO to use to enable/disable the regulator
-
-Any property defined as part of the core regulator binding can also be used.
-(See: ../regulator/regulator.txt)
-
-Continuous Voltage With Enable GPIO Example:
-       pwm_regulator {
-               compatible = "pwm-regulator";
-               pwms = <&pwm1 0 8448 0>;
-               enable-gpios = <&gpio0 23 GPIO_ACTIVE_HIGH>;
-               regulator-min-microvolt = <1016000>;
-               regulator-max-microvolt = <1114000>;
-               regulator-name = "vdd_logic";
-               /* unit == per-mille */
-               pwm-dutycycle-unit = <1000>;
-               /*
-                * Inverted PWM logic, and the duty cycle range is limited
-                * to 30%-70%.
-                */
-               pwm-dutycycle-range = <700 300>; /* */
-       };
-
-Voltage Table Example:
-       pwm_regulator {
-               compatible = "pwm-regulator";
-               pwms = <&pwm1 0 8448 0>;
-               regulator-min-microvolt = <1016000>;
-               regulator-max-microvolt = <1114000>;
-               regulator-name = "vdd_logic";
-
-                             /* Voltage Duty-Cycle */
-               voltage-table = <1114000 0>,
-                               <1095000 10>,
-                               <1076000 20>,
-                               <1056000 30>,
-                               <1036000 40>,
-                               <1016000 50>;
-       };
diff --git a/Documentation/devicetree/bindings/regulator/pwm-regulator.yaml b/Documentation/devicetree/bindings/regulator/pwm-regulator.yaml
new file mode 100644 (file)
index 0000000..82b6f2f
--- /dev/null
@@ -0,0 +1,126 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/pwm-regulator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Bindings for the Generic PWM Regulator
+
+maintainers:
+  - Brian Norris <briannorris@chromium.org>
+  - Lee Jones <lee@kernel.org>
+  - Alexandre Courbot <acourbot@nvidia.com>
+
+description: |
+  Currently supports 2 modes of operation:
+
+  Voltage Table:
+    When in this mode, a voltage table (See below) of predefined voltage <=>
+    duty-cycle values must be provided via DT. Limitations are that the
+    regulator can only operate at the voltages supplied in the table.
+    Intermediary duty-cycle values which would normally allow finer grained
+    voltage selection are ignored and rendered useless.  Although more control
+    is given to the user if the assumptions made in continuous-voltage mode do
+    not reign true.
+
+  Continuous Voltage:
+    This mode uses the regulator's maximum and minimum supplied voltages
+    specified in the regulator-{min,max}-microvolt properties to calculate
+    appropriate duty-cycle values.  This allows for a much more fine grained
+    solution when compared with voltage-table mode above.  This solution does
+    make an assumption that a %50 duty-cycle value will cause the regulator
+    voltage to run at half way between the supplied max_uV and min_uV values.
+
+  If voltage-table is provided, then the device will be used in Voltage Table
+  Mode.  If no voltage-table is provided, then the device will be used in
+  Continuous Voltage Mode.
+
+allOf:
+  - $ref: regulator.yaml#
+
+properties:
+  compatible:
+    const: pwm-regulator
+
+  pwms:
+    maxItems: 1
+
+  voltage-table:
+    description: Voltage and Duty-Cycle table.
+    $ref: /schemas/types.yaml#/definitions/uint32-matrix
+    items:
+      items:
+        - description: voltage in microvolts (uV)
+        - description: duty-cycle in percent (%)
+
+  enable-gpios:
+    description: Regulator enable GPIO
+    maxItems: 1
+
+   # Optional properties for Continuous mode:
+  pwm-dutycycle-unit:
+    description:
+      Integer value encoding the duty cycle unit. If not
+        defined, <100> is assumed, meaning that
+        pwm-dutycycle-range contains values expressed in
+        percent.
+    default: 100
+
+  pwm-dutycycle-range:
+    description:
+      Should contain 2 entries. The first entry is encoding
+        the dutycycle for regulator-min-microvolt and the
+        second one the dutycycle for regulator-max-microvolt.
+        Duty cycle values are expressed in pwm-dutycycle-unit.
+        If not defined, <0 100> is assumed.
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    items:
+      - description: the dutycycle for regulator-min-microvolt
+      - description: the dutycycle for regulator-max-microvolt
+    default: [ 0 100 ]
+
+required:
+  - compatible
+  - pwms
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    // Continuous Voltage With Enable GPIO Example:
+    regulator {
+        compatible = "pwm-regulator";
+        pwms = <&pwm1 0 8448 0>;
+        enable-gpios = <&gpio0 23 GPIO_ACTIVE_HIGH>;
+        regulator-min-microvolt = <1016000>;
+        regulator-max-microvolt = <1114000>;
+        regulator-name = "vdd_logic";
+        /* unit == per-mille */
+        pwm-dutycycle-unit = <1000>;
+        /*
+        * Inverted PWM logic, and the duty cycle range is limited
+        * to 30%-70%.
+        */
+        pwm-dutycycle-range = <700 300>; /* */
+    };
+
+  - |
+    // Voltage Table Example:
+    regulator {
+        compatible = "pwm-regulator";
+        pwms = <&pwm1 0 8448 0>;
+        regulator-min-microvolt = <1016000>;
+        regulator-max-microvolt = <1114000>;
+        regulator-name = "vdd_logic";
+
+                /* Voltage Duty-Cycle */
+        voltage-table = <1114000 0>,
+            <1095000 10>,
+            <1076000 20>,
+            <1056000 30>,
+            <1036000 40>,
+            <1016000 50>;
+    };
+...
index 6a9a7ee..c233461 100644 (file)
@@ -30,6 +30,9 @@ description:
 
   For pm8841, s1, s2, s3, s4, s5, s6, s7, s8
 
+  For pm8909, s1, s2, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13,
+  l14, l15, l17, l18
+
   For pm8916, s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11,
   l12, l13, l14, l15, l16, l17, l18
 
@@ -78,6 +81,7 @@ properties:
       - qcom,rpm-mp5496-regulators
       - qcom,rpm-pm8226-regulators
       - qcom,rpm-pm8841-regulators
+      - qcom,rpm-pm8909-regulators
       - qcom,rpm-pm8916-regulators
       - qcom,rpm-pm8941-regulators
       - qcom,rpm-pm8950-regulators
diff --git a/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt b/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt
deleted file mode 100644 (file)
index c2a39b1..0000000
+++ /dev/null
@@ -1,347 +0,0 @@
-Qualcomm SPMI Regulators
-
-- compatible:
-       Usage: required
-       Value type: <string>
-       Definition: must be one of:
-                       "qcom,pm8004-regulators"
-                       "qcom,pm8005-regulators"
-                       "qcom,pm8226-regulators"
-                       "qcom,pm8841-regulators"
-                       "qcom,pm8916-regulators"
-                       "qcom,pm8941-regulators"
-                       "qcom,pm8950-regulators"
-                       "qcom,pm8994-regulators"
-                       "qcom,pmi8994-regulators"
-                       "qcom,pm660-regulators"
-                       "qcom,pm660l-regulators"
-                       "qcom,pms405-regulators"
-
-- interrupts:
-       Usage: optional
-       Value type: <prop-encoded-array>
-       Definition: List of OCP interrupts.
-
-- interrupt-names:
-       Usage: required if 'interrupts' property present
-       Value type: <string-array>
-       Definition: List of strings defining the names of the
-                   interrupts in the 'interrupts' property 1-to-1.
-                   Supported values are "ocp-<regulator_name>", where
-                   <regulator_name> corresponds to a voltage switch
-                   type regulator.
-
-- vdd_s1-supply:
-- vdd_s2-supply:
-- vdd_s3-supply:
-- vdd_s4-supply:
-- vdd_s5-supply:
-- vdd_s6-supply:
-- vdd_s7-supply:
-- vdd_s8-supply:
-       Usage: optional (pm8841 only)
-       Value type: <phandle>
-       Definition: Reference to regulator supplying the input pin, as
-                   described in the data sheet.
-
-- vdd_s1-supply:
-- vdd_s2-supply:
-- vdd_s3-supply:
-- vdd_s4-supply:
-- vdd_l1_l3-supply:
-- vdd_l2-supply:
-- vdd_l4_l5_l6-supply:
-- vdd_l7-supply:
-- vdd_l8_l11_l14_l15_l16-supply:
-- vdd_l9_l10_l12_l13_l17_l18-supply:
-       Usage: optional (pm8916 only)
-       Value type: <phandle>
-       Definition: Reference to regulator supplying the input pin, as
-                   described in the data sheet.
-
-- vdd_s1-supply:
-- vdd_s2-supply:
-- vdd_s3-supply:
-- vdd_l1_l3-supply:
-- vdd_l2_lvs_1_2_3-supply:
-- vdd_l4_l11-supply:
-- vdd_l5_l7-supply:
-- vdd_l6_l12_l14_l15-supply:
-- vdd_l8_l16_l18_19-supply:
-- vdd_l9_l10_l17_l22-supply:
-- vdd_l13_l20_l23_l24-supply:
-- vdd_l21-supply:
-- vin_5vs-supply:
-       Usage: optional (pm8941 only)
-       Value type: <phandle>
-       Definition: Reference to regulator supplying the input pin, as
-                   described in the data sheet.
-
-- vdd_s1-supply:
-- vdd_s2-supply:
-- vdd_s3-supply:
-- vdd_s4-supply:
-- vdd_s4-supply:
-- vdd_s5-supply:
-- vdd_s6-supply:
-- vdd_l1_l19-supply:
-- vdd_l2_l23-supply:
-- vdd_l3-supply:
-- vdd_l4_l5_l6_l7_l16-supply:
-- vdd_l8_l11_l12_l17_l22-supply:
-- vdd_l9_l10_l13_l14_l15_l18-supply:
-- vdd_l20-supply:
-- vdd_l21-supply:
-       Usage: optional (pm8950 only)
-       Value type: <phandle>
-       Definition: reference to regulator supplying the input pin, as
-                   described in the data sheet
-
-- vdd_s1-supply:
-- vdd_s2-supply:
-- vdd_s3-supply:
-- vdd_s4-supply:
-- vdd_s5-supply:
-- vdd_s6-supply:
-- vdd_s7-supply:
-- vdd_s8-supply:
-- vdd_s9-supply:
-- vdd_s10-supply:
-- vdd_s11-supply:
-- vdd_s12-supply:
-- vdd_l1-supply:
-- vdd_l2_l26_l28-supply:
-- vdd_l3_l11-supply:
-- vdd_l4_l27_l31-supply:
-- vdd_l5_l7-supply:
-- vdd_l6_l12_l32-supply:
-- vdd_l8_l16_l30-supply:
-- vdd_l9_l10_l18_l22-supply:
-- vdd_l13_l19_l23_l24-supply:
-- vdd_l14_l15-supply:
-- vdd_l17_l29-supply:
-- vdd_l20_l21-supply:
-- vdd_l25-supply:
-- vdd_lvs_1_2-supply:
-       Usage: optional (pm8994 only)
-       Value type: <phandle>
-       Definition: Reference to regulator supplying the input pin, as
-                   described in the data sheet.
-
-- vdd_s1-supply:
-- vdd_s2-supply:
-- vdd_s3-supply:
-- vdd_l1-supply:
-       Usage: optional (pmi8994 only)
-       Value type: <phandle>
-       Definition: Reference to regulator supplying the input pin, as
-                   described in the data sheet.
-
-- vdd_l1_l6_l7-supply:
-- vdd_l2_l3-supply:
-- vdd_l5-supply:
-- vdd_l8_l9_l10_l11_l12_l13_l14-supply:
-- vdd_l15_l16_l17_l18_l19-supply:
-- vdd_s1-supply:
-- vdd_s2-supply:
-- vdd_s3-supply:
-- vdd_s5-supply:
-- vdd_s6-supply:
-       Usage: optional (pm660 only)
-       Value type: <phandle>
-       Definition: Reference to regulator supplying the input pin, as
-                   described in the data sheet.
-
-- vdd_l1_l9_l10-supply:
-- vdd_l2-supply:
-- vdd_l3_l5_l7_l8-supply:
-- vdd_l4_l6-supply:
-- vdd_s1-supply:
-- vdd_s2-supply:
-- vdd_s3-supply:
-- vdd_s4-supply:
-- vdd_s5-supply:
-       Usage: optional (pm660l only)
-       Value type: <phandle>
-       Definition: Reference to regulator supplying the input pin, as
-                   described in the data sheet.
-
-- vdd_l1_l2-supply:
-- vdd_l3_l8-supply:
-- vdd_l4-supply:
-- vdd_l5_l6-supply:
-- vdd_l10_l11_l12_l13-supply:
-- vdd_l7-supply:
-- vdd_l9-supply:
-- vdd_s1-supply:
-- vdd_s2-supply:
-- vdd_s3-supply:
-- vdd_s4-supply:
-- vdd_s5-supply
-       Usage: optional (pms405 only)
-       Value type: <phandle>
-       Definition: Reference to regulator supplying the input pin, as
-                   described in the data sheet.
-
-- qcom,saw-reg:
-       Usage: optional
-       Value type: <phandle>
-       Description: Reference to syscon node defining the SAW registers.
-
-
-The regulator node houses sub-nodes for each regulator within the device. Each
-sub-node is identified using the node's name, with valid values listed for each
-of the PMICs below.
-
-pm8004:
-       s2, s5
-
-pm8005:
-       s1, s2, s3, s4
-
-pm8841:
-       s1, s2, s3, s4, s5, s6, s7, s8
-
-pm8916:
-       s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13,
-       l14, l15, l16, l17, l18
-
-pm8941:
-       s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13,
-       l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, lvs1, lvs2, lvs3,
-       5vs1, 5vs2
-
-pm8994:
-       s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, l1, l2, l3, l4, l5,
-       l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, l20,
-       l21, l22, l23, l24, l25, l26, l27, l28, l29, l30, l31, l32, lvs1, lvs2
-
-pmi8994:
-       s1, s2, s3, l1
-
-The content of each sub-node is defined by the standard binding for regulators -
-see regulator.txt - with additional custom properties described below:
-
-- regulator-initial-mode:
-       Usage: optional
-       Value type: <u32>
-       Description: 2 = Set initial mode to auto mode (automatically select
-                   between HPM and LPM); not available on boost type
-                   regulators.
-
-                   1 = Set initial mode to high power mode (HPM), also referred
-                   to as NPM. HPM consumes more ground current than LPM, but
-                   it can source significantly higher load current. HPM is not
-                   available on boost type regulators. For voltage switch type
-                   regulators, HPM implies that over current protection and
-                   soft start are active all the time.
-
-                   0 = Set initial mode to low power mode (LPM).
-
-- qcom,ocp-max-retries:
-       Usage: optional
-       Value type: <u32>
-       Description: Maximum number of times to try toggling a voltage switch
-                    off and back on as a result of consecutive over current
-                    events.
-
-- qcom,ocp-retry-delay:
-       Usage: optional
-       Value type: <u32>
-       Description: Time to delay in milliseconds between each voltage switch
-                    toggle after an over current event takes place.
-
-- qcom,pin-ctrl-enable:
-       Usage: optional
-       Value type: <u32>
-       Description: Bit mask specifying which hardware pins should be used to
-                    enable the regulator, if any; supported bits are:
-                       0 = ignore all hardware enable signals
-                       BIT(0) = follow HW0_EN signal
-                       BIT(1) = follow HW1_EN signal
-                       BIT(2) = follow HW2_EN signal
-                       BIT(3) = follow HW3_EN signal
-
-- qcom,pin-ctrl-hpm:
-       Usage: optional
-       Value type: <u32>
-       Description: Bit mask specifying which hardware pins should be used to
-                    force the regulator into high power mode, if any;
-                    supported bits are:
-                       0 = ignore all hardware enable signals
-                       BIT(0) = follow HW0_EN signal
-                       BIT(1) = follow HW1_EN signal
-                       BIT(2) = follow HW2_EN signal
-                       BIT(3) = follow HW3_EN signal
-                       BIT(4) = follow PMIC awake state
-
-- qcom,vs-soft-start-strength:
-       Usage: optional
-       Value type: <u32>
-       Description: This property sets the soft start strength for voltage
-                    switch type regulators; supported values are:
-                       0 = 0.05 uA
-                       1 = 0.25 uA
-                       2 = 0.55 uA
-                       3 = 0.75 uA
-
-- qcom,saw-slave:
-       Usage: optional
-       Value type: <boo>
-       Description: SAW controlled gang slave. Will not be configured.
-
-- qcom,saw-leader:
-       Usage: optional
-       Value type: <boo>
-       Description: SAW controlled gang leader. Will be configured as
-                    SAW regulator.
-
-Example:
-
-       regulators {
-               compatible = "qcom,pm8941-regulators";
-               vdd_l1_l3-supply = <&s1>;
-
-               s1: s1 {
-                       regulator-min-microvolt = <1300000>;
-                       regulator-max-microvolt = <1400000>;
-               };
-
-               ...
-
-               l1: l1 {
-                       regulator-min-microvolt = <1225000>;
-                       regulator-max-microvolt = <1300000>;
-               };
-
-               ....
-       };
-
-Example 2:
-
-       saw3: syscon@9A10000 {
-               compatible = "syscon";
-               reg = <0x9A10000 0x1000>;
-       };
-
-       ...
-
-       spm-regulators {
-               compatible = "qcom,pm8994-regulators";
-               qcom,saw-reg = <&saw3>;
-               s8 {
-                       qcom,saw-slave;
-               };
-               s9 {
-                       qcom,saw-slave;
-               };
-               s10 {
-                       qcom,saw-slave;
-               };
-               pm8994_s11_saw: s11 {
-                       qcom,saw-leader;
-                       regulator-always-on;
-                       regulator-min-microvolt = <900000>;
-                       regulator-max-microvolt = <1140000>;
-               };
-       };
diff --git a/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.yaml
new file mode 100644 (file)
index 0000000..8b7c4af
--- /dev/null
@@ -0,0 +1,323 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/qcom,spmi-regulator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm SPMI Regulators
+
+maintainers:
+  - Robert Marko <robimarko@gmail.com>
+
+properties:
+  compatible:
+    enum:
+      - qcom,pm660-regulators
+      - qcom,pm660l-regulators
+      - qcom,pm8004-regulators
+      - qcom,pm8005-regulators
+      - qcom,pm8226-regulators
+      - qcom,pm8841-regulators
+      - qcom,pm8916-regulators
+      - qcom,pm8941-regulators
+      - qcom,pm8950-regulators
+      - qcom,pm8994-regulators
+      - qcom,pmi8994-regulators
+      - qcom,pmp8074-regulators
+      - qcom,pms405-regulators
+
+  qcom,saw-reg:
+    description: Reference to syscon node defining the SAW registers
+    $ref: /schemas/types.yaml#/definitions/phandle
+
+patternProperties:
+  "^(5vs[1-2]|(l|s)[1-9][0-9]?|lvs[1-3])$":
+    description: List of regulators and its properties
+    type: object
+    $ref: regulator.yaml#
+
+    properties:
+      qcom,ocp-max-retries:
+        description:
+          Maximum number of times to try toggling a voltage switch off and
+          back on as a result of consecutive over current events
+        $ref: /schemas/types.yaml#/definitions/uint32
+
+      qcom,ocp-retry-delay:
+        description:
+          Time to delay in milliseconds between each voltage switch toggle
+          after an over current event takes place
+        $ref: /schemas/types.yaml#/definitions/uint32
+
+      qcom,pin-ctrl-enable:
+        description:
+          Bit mask specifying which hardware pins should be used to enable the
+          regulator, if any.
+          Supported bits are
+          0 = ignore all hardware enable signals
+          BIT(0) = follow HW0_EN signal
+          BIT(1) = follow HW1_EN signal
+          BIT(2) = follow HW2_EN signal
+          BIT(3) = follow HW3_EN signal
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 15
+
+      qcom,pin-ctrl-hpm:
+        description:
+          Bit mask specifying which hardware pins should be used to force the
+          regulator into high power mode, if any.
+          Supported bits are
+          0 = ignore all hardware enable signals
+          BIT(0) = follow HW0_EN signal
+          BIT(1) = follow HW1_EN signal
+          BIT(2) = follow HW2_EN signal
+          BIT(3) = follow HW3_EN signal
+          BIT(4) = follow PMIC awake state
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 31
+
+      qcom,vs-soft-start-strength:
+        description:
+          This property sets the soft start strength for voltage switch type
+          regulators.
+          Supported values are
+          0 = 0.05 uA
+          1 = 0.25 uA
+          2 = 0.55 uA
+          3 = 0.75 uA
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 3
+
+      qcom,saw-slave:
+        description: SAW controlled gang slave. Will not be configured.
+        type: boolean
+
+      qcom,saw-leader:
+        description:
+          SAW controlled gang leader. Will be configured as SAW regulator.
+        type: boolean
+
+      unevaluatedProperties: false
+
+required:
+  - compatible
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,pm660-regulators
+    then:
+      properties:
+        vdd_l15_l16_l17_l18_l19-supply: true
+        vdd_l1_l6_l7-supply: true
+        vdd_l2_l3-supply: true
+        vdd_l5-supply: true
+        vdd_l8_l9_l10_l11_l12_l13_l14-supply: true
+      patternProperties:
+        "^vdd_s[1-6]-supply$": true
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,pm660l-regulators
+    then:
+      properties:
+        vdd_l1_l9_l10-supply: true
+        vdd_l2-supply: true
+        vdd_l3_l5_l7_l8-supply: true
+        vdd_l4_l6-supply: true
+      patternProperties:
+        "^vdd_s[1-5]-supply$": true
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,pm8004-regulators
+    then:
+      patternProperties:
+        "^vdd_s[25]-supply$": true
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,pm8005-regulators
+    then:
+      patternProperties:
+        "^vdd_s[1-4]-supply$": true
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,pm8226-regulators
+    then:
+      properties:
+        vdd_l10_l11_l13-supply: true
+        vdd_l12_l14-supply: true
+        vdd_l15_l16_l17_l18-supply: true
+        vdd_l19_l20_l21_l22_l23_l28-supply: true
+        vdd_l1_l2_l4_l5-supply: true
+        vdd_l25-supply: true
+        vdd_l3_l24_l26-supply: true
+        vdd_l6_l7_l8_l9_l27-supply: true
+        vdd_lvs1-supply: true
+      patternProperties:
+        "^vdd_s[1-5]-supply$": true
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,pm8841-regulators
+    then:
+      patternProperties:
+        "^vdd_s[1-8]-supply$": true
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,pm8916-regulators
+    then:
+      properties:
+        vdd_l1_l3-supply: true
+        vdd_l4_l5_l6-supply: true
+        vdd_l8_l11_l14_l15_l16-supply: true
+        vdd_l9_l10_l12_l13_l17_l18-supply: true
+      patternProperties:
+        "^vdd_l[27]-supply$": true
+        "^vdd_s[1-4]-supply$": true
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,pm8941-regulators
+    then:
+      properties:
+        interrupts:
+          items:
+            - description: Over-current protection interrupt for 5V S1
+            - description: Over-current protection interrupt for 5V S2
+        interrupt-names:
+          items:
+            - const: ocp-5vs1
+            - const: ocp-5vs2
+        vdd_l13_l20_l23_l24-supply: true
+        vdd_l1_l3-supply: true
+        vdd_l21-supply: true
+        vdd_l2_lvs_1_2_3-supply: true
+        vdd_l4_l11-supply: true
+        vdd_l5_l7-supply: true
+        vdd_l6_l12_l14_l15-supply: true
+        vdd_l8_l16_l18_19-supply: true
+        vdd_l9_l10_l17_l22-supply: true
+        vin_5vs-supply: true
+      patternProperties:
+        "^vdd_s[1-3]-supply$": true
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,pm8950-regulators
+    then:
+      properties:
+        vdd_l1_l19-supply: true
+        vdd_l20-supply: true
+        vdd_l21-supply: true
+        vdd_l2_l23-supply: true
+        vdd_l3-supply: true
+        vdd_l4_l5_l6_l7_l16-supply: true
+        vdd_l8_l11_l12_l17_l22-supply: true
+        vdd_l9_l10_l13_l14_l15_l18-supply: true
+      patternProperties:
+        "^vdd_s[1-6]-supply$": true
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,pm8994-regulators
+    then:
+      properties:
+        vdd_l1-supply: true
+        vdd_l13_l19_l23_l24-supply: true
+        vdd_l14_l15-supply: true
+        vdd_l17_l29-supply: true
+        vdd_l20_l21-supply: true
+        vdd_l25-supply: true
+        vdd_l2_l26_l28-supply: true
+        vdd_l3_l11-supply: true
+        vdd_l4_l27_l31-supply: true
+        vdd_l5_l7-supply: true
+        vdd_l6_l12_l32-supply: true
+        vdd_l8_l16_l30-supply: true
+        vdd_l9_l10_l18_l22-supply: true
+        vdd_lvs_1_2-supply: true
+      patternProperties:
+        "^vdd_s[1-9][0-2]?-supply$": true
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,pmi8994-regulators
+    then:
+      properties:
+        vdd_l1-supply: true
+      patternProperties:
+        "^vdd_s[1-3]-supply$": true
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,pmp8074-regulators
+    then:
+      properties:
+        vdd_l10_l11_l12_l13-supply: true
+        vdd_l1_l2-supply: true
+        vdd_l3_l8-supply: true
+        vdd_l5_l6_l15-supply: true
+      patternProperties:
+        "^vdd_l[479]-supply$": true
+        "^vdd_s[1-5]-supply$": true
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,pms405-regulators
+    then:
+      properties:
+        vdd_s3-supply: true
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    regulators {
+      compatible = "qcom,pm8941-regulators";
+      vdd_l1_l3-supply = <&s1>;
+
+      s1: s1 {
+        regulator-min-microvolt = <1300000>;
+        regulator-max-microvolt = <1400000>;
+      };
+
+      l1: l1 {
+        regulator-min-microvolt = <1225000>;
+        regulator-max-microvolt = <1300000>;
+      };
+    };
+...
index a9b66ec..6e8aa9e 100644 (file)
@@ -23,6 +23,7 @@ properties:
 
   regulator-microvolt-offset:
     description: Offset applied to voltages to compensate for voltage drops
+    $ref: "/schemas/types.yaml#/definitions/uint32"
 
   regulator-min-microamp:
     description: smallest current consumers may set
index fa5e4ea..d82e65e 100644 (file)
@@ -11,7 +11,9 @@ maintainers:
 
 properties:
   compatible:
-    const: nuvoton,npcm750-reset
+    enum:
+      - nuvoton,npcm750-reset        # Poleg NPCM7XX SoC
+      - nuvoton,npcm845-reset        # Arbel NPCM8XX SoC
 
   reg:
     maxItems: 1
@@ -19,6 +21,10 @@ properties:
   '#reset-cells':
     const: 2
 
+  nuvoton,sysgcr:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: a phandle to access GCR registers.
+
   nuvoton,sw-reset-number:
     $ref: /schemas/types.yaml#/definitions/uint32
     minimum: 1
@@ -31,6 +37,7 @@ required:
   - compatible
   - reg
   - '#reset-cells'
+  - nuvoton,sysgcr
 
 additionalProperties: false
 
@@ -41,6 +48,7 @@ examples:
         compatible = "nuvoton,npcm750-reset";
         reg = <0xf0801000 0x70>;
         #reset-cells = <2>;
+        nuvoton,sysgcr = <&gcr>;
         nuvoton,sw-reset-number = <2>;
     };
 
diff --git a/Documentation/devicetree/bindings/reset/sunplus,reset.yaml b/Documentation/devicetree/bindings/reset/sunplus,reset.yaml
new file mode 100644 (file)
index 0000000..f24646b
--- /dev/null
@@ -0,0 +1,38 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) Sunplus Co., Ltd. 2021
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/reset/sunplus,reset.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Sunplus SoC Reset Controller
+
+maintainers:
+  - Qin Jian <qinjian@cqplus1.com>
+
+properties:
+  compatible:
+    const: sunplus,sp7021-reset
+
+  reg:
+    maxItems: 1
+
+  "#reset-cells":
+    const: 1
+
+required:
+  - compatible
+  - reg
+  - "#reset-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    rstc: reset@9c000054 {
+      compatible = "sunplus,sp7021-reset";
+      reg = <0x9c000054 0x28>;
+      #reset-cells = <1>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/rtc/fsl,scu-rtc.yaml b/Documentation/devicetree/bindings/rtc/fsl,scu-rtc.yaml
new file mode 100644 (file)
index 0000000..8c102b7
--- /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/rtc/fsl,scu-rtc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: i.MX SCU Client Device Node - RTC bindings based on SCU Message Protocol
+
+maintainers:
+  - Dong Aisheng <aisheng.dong@nxp.com>
+
+description: i.MX SCU Client Device Node
+  Client nodes are maintained as children of the relevant IMX-SCU device node.
+
+allOf:
+  - $ref: rtc.yaml#
+
+properties:
+  compatible:
+    const: fsl,imx8qxp-sc-rtc
+
+required:
+  - compatible
+
+additionalProperties: false
+
+examples:
+  - |
+    rtc {
+        compatible = "fsl,imx8qxp-sc-rtc";
+    };
diff --git a/Documentation/devicetree/bindings/soc/bcm/brcm,bcm2835-pm.txt b/Documentation/devicetree/bindings/soc/bcm/brcm,bcm2835-pm.txt
deleted file mode 100644 (file)
index 72ff033..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-BCM2835 PM (Power domains, watchdog)
-
-The PM block controls power domains and some reset lines, and includes
-a watchdog timer.  This binding supersedes the brcm,bcm2835-pm-wdt
-binding which covered some of PM's register range and functionality.
-
-Required properties:
-
-- compatible:          Should be "brcm,bcm2835-pm"
-- reg:                 Specifies base physical address and size of the two
-                         register ranges ("PM" and "ASYNC_BRIDGE" in that
-                         order)
-- clocks:              a) v3d: The V3D clock from CPRMAN
-                       b) peri_image: The PERI_IMAGE clock from CPRMAN
-                       c) h264: The H264 clock from CPRMAN
-                       d) isp: The ISP clock from CPRMAN
-- #reset-cells:        Should be 1.  This property follows the reset controller
-                         bindings[1].
-- #power-domain-cells: Should be 1.  This property follows the power domain
-                         bindings[2].
-
-Optional properties:
-
-- timeout-sec:         Contains the watchdog timeout in seconds
-- system-power-controller: Whether the watchdog is controlling the
-    system power.  This node follows the power controller bindings[3].
-
-[1] Documentation/devicetree/bindings/reset/reset.txt
-[2] Documentation/devicetree/bindings/power/power-domain.yaml
-[3] Documentation/devicetree/bindings/power/power-controller.txt
-
-Example:
-
-pm {
-       compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt";
-       #power-domain-cells = <1>;
-       #reset-cells = <1>;
-       reg = <0x7e100000 0x114>,
-             <0x7e00a000 0x24>;
-       clocks = <&clocks BCM2835_CLOCK_V3D>,
-                <&clocks BCM2835_CLOCK_PERI_IMAGE>,
-                <&clocks BCM2835_CLOCK_H264>,
-                <&clocks BCM2835_CLOCK_ISP>;
-       clock-names = "v3d", "peri_image", "h264", "isp";
-       system-power-controller;
-};
diff --git a/Documentation/devicetree/bindings/soc/bcm/brcm,bcm2835-pm.yaml b/Documentation/devicetree/bindings/soc/bcm/brcm,bcm2835-pm.yaml
new file mode 100644 (file)
index 0000000..e28ef19
--- /dev/null
@@ -0,0 +1,86 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/soc/bcm/brcm,bcm2835-pm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: BCM2835 PM (Power domains, watchdog)
+
+description: |
+  The PM block controls power domains and some reset lines, and includes a
+  watchdog timer.
+
+maintainers:
+  - Nicolas Saenz Julienne <nsaenz@kernel.org>
+
+allOf:
+  - $ref: /schemas/watchdog/watchdog.yaml#
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - brcm,bcm2835-pm
+          - brcm,bcm2711-pm
+      - const: brcm,bcm2835-pm-wdt
+
+  reg:
+    minItems: 2
+    maxItems: 3
+
+  reg-names:
+    minItems: 2
+    items:
+      - const: pm
+      - const: asb
+      - const: rpivid_asb
+
+  "#power-domain-cells":
+    const: 1
+
+  "#reset-cells":
+    const: 1
+
+  clocks:
+    minItems: 4
+    maxItems: 4
+
+  clock-names:
+    items:
+      - const: v3d
+      - const: peri_image
+      - const: h264
+      - const: isp
+
+  system-power-controller:
+    type: boolean
+
+  timeout-sec: true
+
+required:
+  - compatible
+  - reg
+  - "#power-domain-cells"
+  - "#reset-cells"
+  - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/bcm2835.h>
+
+    watchdog@7e100000 {
+        compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt";
+        #power-domain-cells = <1>;
+        #reset-cells = <1>;
+        reg = <0x7e100000 0x114>,
+              <0x7e00a000 0x24>;
+        reg-names = "pm", "asb";
+        clocks = <&clocks BCM2835_CLOCK_V3D>,
+               <&clocks BCM2835_CLOCK_PERI_IMAGE>,
+               <&clocks BCM2835_CLOCK_H264>,
+               <&clocks BCM2835_CLOCK_ISP>;
+        clock-names = "v3d", "peri_image", "h264", "isp";
+        system-power-controller;
+    };
index 31e4d3c..d0a4bc3 100644 (file)
@@ -20,6 +20,7 @@ properties:
   compatible:
     enum:
       - mediatek,mt6779-devapc
+      - mediatek,mt8186-devapc
 
   reg:
     description: The base address of devapc register bank
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
 %YAML 1.2
 ---
-$id: http://devicetree.org/schemas/display/mediatek/mediatek,mutex.yaml#
+$id: http://devicetree.org/schemas/soc/mediatek/mediatek,mutex.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
 title: Mediatek mutex
@@ -55,6 +55,18 @@ properties:
       include/dt-bindings/gce/<chip>-gce.h of each chips.
     $ref: /schemas/types.yaml#/definitions/uint32-array
 
+  mediatek,gce-client-reg:
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    items:
+      items:
+        - description: phandle of GCE
+        - description: GCE subsys id
+        - description: register offset
+        - description: register size
+    description: The register of client driver can be configured by gce with
+      4 arguments defined in this property. Each GCE subsys id is mapping to
+      a client defined in the header include/dt-bindings/gce/<chip>-gce.h.
+
 required:
   - compatible
   - reg
diff --git a/Documentation/devicetree/bindings/soc/mediatek/mtk-svs.yaml b/Documentation/devicetree/bindings/soc/mediatek/mtk-svs.yaml
new file mode 100644 (file)
index 0000000..d911fa2
--- /dev/null
@@ -0,0 +1,91 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/soc/mediatek/mtk-svs.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek Smart Voltage Scaling (SVS) Device Tree Bindings
+
+maintainers:
+  - Roger Lu <roger.lu@mediatek.com>
+  - Matthias Brugger <matthias.bgg@gmail.com>
+  - Kevin Hilman <khilman@kernel.org>
+
+description: |+
+  The SVS engine is a piece of hardware which has several
+  controllers(banks) for calculating suitable voltage to
+  different power domains(CPU/GPU/CCI) according to
+  chip process corner, temperatures and other factors. Then DVFS
+  driver could apply SVS bank voltage to PMIC/Buck.
+
+properties:
+  compatible:
+    enum:
+      - mediatek,mt8183-svs
+      - mediatek,mt8192-svs
+
+  reg:
+    maxItems: 1
+    description: Address range of the MTK SVS controller.
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+    description: Main clock for MTK SVS controller to work.
+
+  clock-names:
+    const: main
+
+  nvmem-cells:
+    minItems: 1
+    description:
+      Phandle to the calibration data provided by a nvmem device.
+    items:
+      - description: SVS efuse for SVS controller
+      - description: Thermal efuse for SVS controller
+
+  nvmem-cell-names:
+    items:
+      - const: svs-calibration-data
+      - const: t-calibration-data
+
+  resets:
+    maxItems: 1
+
+  reset-names:
+    items:
+      - const: svs_rst
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - nvmem-cells
+  - nvmem-cell-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/mt8183-clk.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        svs@1100b000 {
+            compatible = "mediatek,mt8183-svs";
+            reg = <0 0x1100b000 0 0x1000>;
+            interrupts = <GIC_SPI 127 IRQ_TYPE_LEVEL_LOW>;
+            clocks = <&infracfg CLK_INFRA_THERM>;
+            clock-names = "main";
+            nvmem-cells = <&svs_calibration>, <&thermal_calibration>;
+            nvmem-cell-names = "svs-calibration-data", "t-calibration-data";
+        };
+    };
index 597d67f..33748a0 100644 (file)
@@ -1,8 +1,8 @@
 # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
 %YAML 1.2
 ---
-$id: "http://devicetree.org/schemas/soc/microchip/atmel,at91rm9200-tcb.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/soc/microchip/atmel,at91rm9200-tcb.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
 
 title: Atmel Timer Counter Block
 
@@ -75,7 +75,7 @@ patternProperties:
 
   "^pwm@[0-2]$":
     description: The timer block channels that are used as PWMs.
-    $ref: ../../pwm/pwm.yaml#
+    $ref: /schemas/pwm/pwm.yaml#
     type: object
     properties:
       compatible:
index b0dae51..04ffee3 100644 (file)
@@ -1,8 +1,8 @@
 # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
 %YAML 1.2
 ---
-$id: "http://devicetree.org/schemas/soc/microchip/microchip,mpfs-sys-controller.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/soc/microchip/microchip,mpfs-sys-controller.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
 
 title: Microchip PolarFire SoC (MPFS) MSS (microprocessor subsystem) system controller
 
index e2e173d..d01e987 100644 (file)
@@ -33,6 +33,7 @@ properties:
           - qcom,sm8150-aoss-qmp
           - qcom,sm8250-aoss-qmp
           - qcom,sm8350-aoss-qmp
+          - qcom,sm8450-aoss-qmp
       - const: qcom,aoss-qmp
 
   reg:
index f5ecf4a..4a50f1d 100644 (file)
@@ -65,33 +65,22 @@ properties:
 
   qcom,tcs-config:
     $ref: /schemas/types.yaml#/definitions/uint32-matrix
+    minItems: 4
+    maxItems: 4
     items:
-      - items:
-          - description: TCS type
-            enum: [ 0, 1, 2, 3 ]
-          - description: Number of TCS
-      - items:
-          - description: TCS type
-            enum: [ 0, 1, 2, 3 ]
-          - description: Number of TCS
-      - items:
-          - description: TCS type
-            enum: [ 0, 1, 2, 3]
-          - description: Numbe r of TCS
-      - items:
-          - description: TCS type
-            enum: [ 0, 1, 2, 3 ]
-          - description: Number of TCS
+      items:
+        - description: |
+            TCS type::
+             - ACTIVE_TCS
+             - SLEEP_TCS
+             - WAKE_TCS
+             - CONTROL_TCS
+          enum: [ 0, 1, 2, 3 ]
+        - description: Number of TCS
     description: |
       The tuple defining the configuration of TCS. Must have two cells which
       describe each TCS type.  The order of the TCS must match the hardware
       configuration.
-      Cell 1 (TCS Type):: TCS types to be specified::
-       - ACTIVE_TCS
-       - SLEEP_TCS
-       - WAKE_TCS
-       - CONTROL_TCS
-      Cell 2 (Number of TCS):: <u32>
 
   qcom,tcs-offset:
     $ref: /schemas/types.yaml#/definitions/uint32
index f0f1bf0..50f8345 100644 (file)
@@ -34,6 +34,7 @@ properties:
       - qcom,rpm-apq8084
       - qcom,rpm-ipq6018
       - qcom,rpm-msm8226
+      - qcom,rpm-msm8909
       - qcom,rpm-msm8916
       - qcom,rpm-msm8936
       - qcom,rpm-msm8953
@@ -51,6 +52,9 @@ properties:
     $ref: /schemas/clock/qcom,rpmcc.yaml#
     unevaluatedProperties: false
 
+  power-controller:
+    $ref: /schemas/power/qcom,rpmpd.yaml#
+
   qcom,smd-channels:
     $ref: /schemas/types.yaml#/definitions/string-array
     description: Channel name used for the RPM communication
index 07d2d53..f433e6e 100644 (file)
@@ -22,6 +22,7 @@ properties:
           - qcom,sdm660-silver-saw2-v4.1-l2
           - qcom,msm8998-gold-saw2-v4.1-l2
           - qcom,msm8998-silver-saw2-v4.1-l2
+          - qcom,msm8909-saw2-v3.0-cpu
           - qcom,msm8916-saw2-v3.0-cpu
           - qcom,msm8226-saw2-v2.1-cpu
           - qcom,msm8974-saw2-v2.1-cpu
index d891ecf..5320504 100644 (file)
@@ -77,7 +77,6 @@ properties:
           Should reference the tx-enable and tx-rings-empty SMEM states.
 
       qcom,smem-state-names:
-        $ref: /schemas/types.yaml#/definitions/string-array
         items:
           - const: tx-enable
           - const: tx-rings-empty
index c30a643..13bb8df 100644 (file)
@@ -49,9 +49,6 @@ properties:
   reg:
     maxItems: 1
 
-  assigned-clock-parents: true
-  assigned-clocks: true
-
   '#clock-cells':
     const: 1
 
@@ -77,14 +74,20 @@ properties:
       Must be identical to the that of the parent interrupt controller.
     const: 3
 
+  reboot-mode:
+    $ref: /schemas/power/reset/syscon-reboot-mode.yaml
+    type: object
+    description:
+      Reboot mode to alter bootloader behavior for the next boot
+
   syscon-poweroff:
-    $ref: "../../power/reset/syscon-poweroff.yaml#"
+    $ref: /schemas/power/reset/syscon-poweroff.yaml#
     type: object
     description:
       Node for power off method
 
   syscon-reboot:
-    $ref: "../../power/reset/syscon-reboot.yaml#"
+    $ref: /schemas/power/reset/syscon-reboot.yaml#
     type: object
     description:
       Node for reboot method
index fde886a..60b4956 100644 (file)
@@ -22,8 +22,12 @@ properties:
     pattern: "^usi@[0-9a-f]+$"
 
   compatible:
-    enum:
-      - samsung,exynos850-usi   # for USIv2 (Exynos850, ExynosAutoV9)
+    oneOf:
+      - items:
+          - const: samsung,exynosautov9-usi
+          - const: samsung,exynos850-usi
+      - enum:
+          - samsung,exynos850-usi
 
   reg: true
 
index 64461d4..8478732 100644 (file)
@@ -65,10 +65,11 @@ properties:
       - ti,am4376-pruss0 # for AM437x SoC family and PRUSS unit 0
       - ti,am4376-pruss1 # for AM437x SoC family and PRUSS unit 1
       - ti,am5728-pruss  # for AM57xx SoC family
-      - ti,k2g-pruss     # for 66AK2G SoC family
+      - ti,am625-pruss   # for K3 AM62x SoC family
+      - ti,am642-icssg   # for K3 AM64x SoC family
       - ti,am654-icssg   # for K3 AM65x SoC family
       - ti,j721e-icssg   # for K3 J721E SoC family
-      - ti,am642-icssg   # for K3 AM64x SoC family
+      - ti,k2g-pruss     # for 66AK2G SoC family
 
   reg:
     maxItems: 1
index e9a5330..ef18a57 100644 (file)
@@ -25,12 +25,12 @@ properties:
       - qcom,sc7280-lpass-cpu
 
   reg:
-    minItems: 2
+    minItems: 1
     maxItems: 6
     description: LPAIF core registers
 
   reg-names:
-    minItems: 2
+    minItems: 1
     maxItems: 6
 
   clocks:
@@ -42,12 +42,12 @@ properties:
     maxItems: 10
 
   interrupts:
-    minItems: 2
+    minItems: 1
     maxItems: 4
     description: LPAIF DMA buffer interrupt
 
   interrupt-names:
-    minItems: 2
+    minItems: 1
     maxItems: 4
 
   qcom,adsp:
index 7e8d252..0d98403 100644 (file)
@@ -13,6 +13,7 @@ properties:
   compatible:
     items:
       - enum:
+          - renesas,r9a07g043-ssi  # RZ/G2UL
           - renesas,r9a07g044-ssi  # RZ/G2{L,LC}
           - renesas,r9a07g054-ssi  # RZ/V2L
       - const: renesas,rz-ssi
@@ -50,7 +51,7 @@ properties:
     minItems: 1
     maxItems: 2
     description:
-      The first cell represents a phandle to dmac
+      The first cell represents a phandle to dmac.
       The second cell specifies the encoded MID/RID values of the SSI port
       connected to the DMA client and the slave channel configuration
       parameters.
diff --git a/Documentation/devicetree/bindings/spi/atmel,at91rm9200-spi.yaml b/Documentation/devicetree/bindings/spi/atmel,at91rm9200-spi.yaml
new file mode 100644 (file)
index 0000000..d85d540
--- /dev/null
@@ -0,0 +1,75 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2022 Microchip Technology, Inc. and its subsidiaries
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/atmel,at91rm9200-spi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Atmel SPI device
+
+maintainers:
+  - Tudor Ambarus <tudor.ambarus@microchip.com>
+
+allOf:
+  - $ref: spi-controller.yaml#
+
+properties:
+  compatible:
+    oneOf:
+      - const: atmel,at91rm9200-spi
+      - items:
+          - const: microchip,sam9x60-spi
+          - const: atmel,at91rm9200-spi
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clock-names:
+    contains:
+      const: spi_clk
+
+  clocks:
+    maxItems: 1
+
+  atmel,fifo-size:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: |
+      Maximum number of data the RX and TX FIFOs can store for FIFO
+      capable SPI controllers.
+    enum: [ 16, 32 ]
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clock-names
+  - clocks
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    spi1: spi@fffcc000 {
+        compatible = "atmel,at91rm9200-spi";
+        reg = <0xfffcc000 0x4000>;
+        interrupts = <13 IRQ_TYPE_LEVEL_HIGH 5>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+        clocks = <&spi1_clk>;
+        clock-names = "spi_clk";
+        cs-gpios = <&pioB 3 GPIO_ACTIVE_HIGH>;
+        atmel,fifo-size = <32>;
+
+        mmc@0 {
+            compatible = "mmc-spi-slot";
+            reg = <0>;
+            gpios = <&pioC 4 GPIO_ACTIVE_HIGH>;    /* CD */
+            spi-max-frequency = <25000000>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/spi/hpe,gxp-spifi.yaml b/Documentation/devicetree/bindings/spi/hpe,gxp-spifi.yaml
new file mode 100644 (file)
index 0000000..7797c31
--- /dev/null
@@ -0,0 +1,56 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/hpe,gxp-spifi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: HPE GXP spi controller flash interface
+
+maintainers:
+  - Nick Hawkins <nick.hawkins@hpe.com>
+  - Jean-Marie Verdun <verdun@hpe.com>
+
+allOf:
+  - $ref: spi-controller.yaml#
+
+properties:
+  compatible:
+    const: hpe,gxp-spifi
+
+  reg:
+    items:
+      - description: cfg registers
+      - description: data registers
+      - description: mapped memory
+
+  interrupts:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+unevaluatedProperties: false
+
+examples:
+  - |
+
+    spi@200 {
+      compatible = "hpe,gxp-spifi";
+      reg = <0x200 0x80>, <0xc000 0x100>, <0x38000000 0x800000>;
+      interrupts = <20>;
+      interrupt-parent = <&vic0>;
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      flash@0 {
+        reg = <0>;
+        compatible = "jedec,spi-nor";
+      };
+
+      flash@1 {
+        reg = <1>;
+        compatible = "jedec,spi-nor";
+      };
+    };
index 94ef055..8d2a6c0 100644 (file)
@@ -18,6 +18,7 @@ properties:
       - items:
           - enum:
               - mediatek,mt7629-spi
+              - mediatek,mt8365-spi
           - const: mediatek,mt7622-spi
       - items:
           - enum:
@@ -33,6 +34,7 @@ properties:
       - items:
           - enum:
               - mediatek,mt7986-spi-ipm
+              - mediatek,mt8188-spi-ipm
           - const: mediatek,spi-ipm
       - items:
           - enum:
index 41e60fe..970b111 100644 (file)
@@ -23,6 +23,10 @@ allOf:
 properties:
   compatible:
     oneOf:
+      - enum:
+          - mediatek,mt8173-nor
+          - mediatek,mt8186-nor
+          - mediatek,mt8192-nor
       - items:
           - enum:
               - mediatek,mt2701-nor
@@ -30,13 +34,13 @@ properties:
               - mediatek,mt7622-nor
               - mediatek,mt7623-nor
               - mediatek,mt7629-nor
-              - mediatek,mt8186-nor
-              - mediatek,mt8192-nor
               - mediatek,mt8195-nor
-          - enum:
-              - mediatek,mt8173-nor
-      - items:
           - const: mediatek,mt8173-nor
+      - items:
+          - enum:
+              - mediatek,mt8188-nor
+          - const: mediatek,mt8186-nor
+
   reg:
     maxItems: 1
 
@@ -64,7 +68,6 @@ properties:
 required:
   - compatible
   - reg
-  - interrupts
   - clocks
   - clock-names
 
index a388005..c63ce4c 100644 (file)
@@ -6,8 +6,13 @@ The NPCM7XX supports three FIU modules,
 FIU0 and FIUx supports two chip selects,
 FIU3 support four chip select.
 
+The NPCM8XX supports four FIU modules,
+FIU0 and FIUx supports two chip selects,
+FIU1 and FIU3 supports four chip selects.
+
 Required properties:
-  - compatible : "nuvoton,npcm750-fiu" for the NPCM7XX BMC
+  - compatible : "nuvoton,npcm750-fiu" for Poleg NPCM7XX BMC
+                            "nuvoton,npcm845-fiu" for Arbel NPCM8XX BMC
   - #address-cells : should be 1.
   - #size-cells : should be 0.
   - reg : the first contains the register location and length,
@@ -30,6 +35,12 @@ Aliases:
                fiu1 represent fiu 3 controller
                fiu2 represent fiu x controller
 
+  In the NPCM8XX BMC:
+               fiu0 represent fiu 0 controller
+               fiu1 represent fiu 1 controller
+               fiu2 represent fiu 3 controller
+               fiu3 represent fiu x controller
+
 Example:
 fiu3: spi@c00000000 {
        compatible = "nuvoton,npcm750-fiu";
diff --git a/Documentation/devicetree/bindings/spi/nvidia,tegra210-quad-peripheral-props.yaml b/Documentation/devicetree/bindings/spi/nvidia,tegra210-quad-peripheral-props.yaml
new file mode 100644 (file)
index 0000000..24e0c21
--- /dev/null
@@ -0,0 +1,33 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/nvidia,tegra210-quad-peripheral-props.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Peripheral properties for Tegra Quad SPI Controller
+
+maintainers:
+  - Thierry Reding <thierry.reding@gmail.com>
+  - Jonathan Hunter <jonathanh@nvidia.com>
+
+properties:
+  nvidia,tx-clk-tap-delay:
+    description:
+      Delays the clock going out to device with this tap value.
+      Tap value varies based on platform design trace lengths from Tegra
+      QSPI to corresponding slave device.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    minimum: 0
+    maximum: 31
+
+  nvidia,rx-clk-tap-delay:
+    description:
+      Delays the clock coming in from the device with this tap value.
+      Tap value varies based on platform design trace lengths from Tegra
+      QSPI to corresponding slave device.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    minimum: 0
+    maximum: 255
+
+unevaluatedProperties: true
+
index 0296edd..6b733e5 100644 (file)
@@ -20,6 +20,7 @@ properties:
       - nvidia,tegra186-qspi
       - nvidia,tegra194-qspi
       - nvidia,tegra234-qspi
+      - nvidia,tegra241-qspi
 
   reg:
     maxItems: 1
@@ -57,27 +58,6 @@ patternProperties:
       spi-tx-bus-width:
         enum: [1, 2, 4]
 
-      nvidia,tx-clk-tap-delay:
-        description:
-          Delays the clock going out to device with this tap value.
-          Tap value varies based on platform design trace lengths from Tegra
-          QSPI to corresponding slave device.
-        $ref: /schemas/types.yaml#/definitions/uint32
-        minimum: 0
-        maximum: 31
-
-      nvidia,rx-clk-tap-delay:
-        description:
-          Delays the clock coming in from the device with this tap value.
-          Tap value varies based on platform design trace lengths from Tegra
-          QSPI to corresponding slave device.
-        $ref: /schemas/types.yaml#/definitions/uint32
-        minimum: 0
-        maximum: 255
-
-    required:
-      - reg
-
 required:
   - compatible
   - reg
index 78ceb9d..2e20ca3 100644 (file)
@@ -45,12 +45,15 @@ properties:
       - const: rx
 
   interconnects:
-    maxItems: 2
+    minItems: 2
+    maxItems: 3
 
   interconnect-names:
+    minItems: 2
     items:
       - const: qup-core
       - const: qup-config
+      - const: qup-memory
 
   interrupts:
     maxItems: 1
index a50f24f..e0a465d 100644 (file)
@@ -20,7 +20,9 @@ properties:
           - samsung,s3c2443-spi # for S3C2443, S3C2416 and S3C2450
           - samsung,s3c6410-spi
           - samsung,s5pv210-spi # for S5PV210 and S5PC110
+          - samsung,exynos4210-spi
           - samsung,exynos5433-spi
+          - samsung,exynosautov9-spi
           - tesla,fsd-spi
       - const: samsung,exynos7-spi
         deprecated: true
@@ -85,7 +87,9 @@ allOf:
       properties:
         compatible:
           contains:
-            const: samsung,exynos5433-spi
+            enum:
+              - samsung,exynos5433-spi
+              - samsung,exynosautov9-spi
     then:
       properties:
         clocks:
index d7e08b0..37c3c27 100644 (file)
@@ -61,6 +61,8 @@ properties:
           - const: snps,dw-apb-ssi
       - description: Intel Keem Bay SPI Controller
         const: intel,keembay-ssi
+      - description: Intel Thunder Bay SPI Controller
+        const: intel,thunderbay-ssi
       - description: Baikal-T1 SPI Controller
         const: baikal,bt1-ssi
       - description: Baikal-T1 System Boot SPI Controller
@@ -124,9 +126,16 @@ properties:
 
   rx-sample-delay-ns:
     default: 0
-    description: Default value of the rx-sample-delay-ns property.
+    description: |
+      Default value of the rx-sample-delay-ns property.
       This value will be used if the property is not explicitly defined
-      for a SPI slave device. See below.
+      for a SPI slave device.
+
+      SPI Rx sample delay offset, unit is nanoseconds.
+      The delay from the default sample time before the actual sample of the
+      rxd input signal occurs. The "rx_sample_delay" is an optional feature
+      of the designware controller, and the upper limit is also subject to
+      controller configuration.
 
 patternProperties:
   "^.*@[0-9a-f]+$":
@@ -136,19 +145,6 @@ patternProperties:
         minimum: 0
         maximum: 3
 
-      spi-rx-bus-width:
-        const: 1
-
-      spi-tx-bus-width:
-        const: 1
-
-      rx-sample-delay-ns:
-        description: SPI Rx sample delay offset, unit is nanoseconds.
-          The delay from the default sample time before the actual
-          sample of the rxd input signal occurs. The "rx_sample_delay"
-          is an optional feature of the designware controller, and the
-          upper limit is also subject to controller configuration.
-
 unevaluatedProperties: false
 
 required:
index 9787be2..82d0ca5 100644 (file)
@@ -49,6 +49,13 @@ properties:
     enum: [ 0, 1 ]
     default: 0
 
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clock-names
+  - clocks
+
 unevaluatedProperties: false
 
 examples:
index ebb4d5f..655713f 100644 (file)
@@ -95,6 +95,17 @@ patternProperties:
     type: object
     $ref: spi-peripheral-props.yaml
 
+    properties:
+      spi-cpha:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description:
+          The device requires shifted clock phase (CPHA) mode.
+
+      spi-cpol:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description:
+          The device requires inverse clock polarity (CPOL) mode.
+
     required:
       - compatible
       - reg
@@ -139,9 +150,9 @@ examples:
         };
 
         flash@2 {
-          compatible = "jedec,spi-nor";
-          spi-max-frequency = <50000000>;
-          reg = <2>, <3>;
-          stacked-memories = /bits/ 64 <0x10000000 0x10000000>;
+            compatible = "jedec,spi-nor";
+            spi-max-frequency = <50000000>;
+            reg = <2>, <3>;
+            stacked-memories = /bits/ 64 <0x10000000 0x10000000>;
         };
     };
index 5e32928..ce048e7 100644 (file)
@@ -34,16 +34,6 @@ properties:
     description:
       The device requires 3-wire mode.
 
-  spi-cpha:
-    $ref: /schemas/types.yaml#/definitions/flag
-    description:
-      The device requires shifted clock phase (CPHA) mode.
-
-  spi-cpol:
-    $ref: /schemas/types.yaml#/definitions/flag
-    description:
-      The device requires inverse clock polarity (CPOL) mode.
-
   spi-cs-high:
     $ref: /schemas/types.yaml#/definitions/flag
     description:
@@ -71,6 +61,11 @@ properties:
     description:
       Delay, in microseconds, after a read transfer.
 
+  rx-sample-delay-ns:
+    description: SPI Rx sample delay offset, unit is nanoseconds.
+      The delay from the default sample time before the actual
+      sample of the rxd input signal occurs.
+
   spi-tx-bus-width:
     description:
       Bus width to the SPI bus used for write transfers.
@@ -112,5 +107,6 @@ properties:
 allOf:
   - $ref: cdns,qspi-nor-peripheral-props.yaml#
   - $ref: samsung,spi-peripheral-props.yaml#
+  - $ref: nvidia,tegra210-quad-peripheral-props.yaml#
 
 additionalProperties: true
index ea72c80..fafde1c 100644 (file)
@@ -30,6 +30,13 @@ properties:
   clocks:
     maxItems: 2
 
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clock-names
+  - clocks
+
 unevaluatedProperties: false
 
 examples:
diff --git a/Documentation/devicetree/bindings/spi/spi_atmel.txt b/Documentation/devicetree/bindings/spi/spi_atmel.txt
deleted file mode 100644 (file)
index 5bb4a8f..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-Atmel SPI device
-
-Required properties:
-- compatible : should be "atmel,at91rm9200-spi" or "microchip,sam9x60-spi".
-- reg: Address and length of the register set for the device
-- interrupts: Should contain spi interrupt
-- cs-gpios: chipselects (optional for SPI controller version >= 2 with the
-  Chip Select Active After Transfer feature).
-- clock-names: tuple listing input clock names.
-       Required elements: "spi_clk"
-- clocks: phandles to input clocks.
-
-Optional properties:
-- atmel,fifo-size: maximum number of data the RX and TX FIFOs can store for FIFO
-  capable SPI controllers.
-
-Example:
-
-spi1: spi@fffcc000 {
-       compatible = "atmel,at91rm9200-spi";
-       reg = <0xfffcc000 0x4000>;
-       interrupts = <13 4 5>;
-       #address-cells = <1>;
-       #size-cells = <0>;
-       clocks = <&spi1_clk>;
-       clock-names = "spi_clk";
-       cs-gpios = <&pioB 3 0>;
-       atmel,fifo-size = <32>;
-
-       mmc-slot@0 {
-               compatible = "mmc-spi-slot";
-               reg = <0>;
-               gpios = <&pioC 4 0>;    /* CD */
-               spi-max-frequency = <25000000>;
-       };
-};
diff --git a/Documentation/devicetree/bindings/thermal/fsl,scu-thermal.yaml b/Documentation/devicetree/bindings/thermal/fsl,scu-thermal.yaml
new file mode 100644 (file)
index 0000000..f9e4b3c
--- /dev/null
@@ -0,0 +1,38 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/thermal/fsl,scu-thermal.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: i.MX SCU Client Device Node - Thermal bindings based on SCU Message Protocol
+
+maintainers:
+  - Dong Aisheng <aisheng.dong@nxp.com>
+
+description: i.MX SCU Client Device Node
+  Client nodes are maintained as children of the relevant IMX-SCU device node.
+
+allOf:
+  - $ref: thermal-sensor.yaml#
+
+properties:
+  compatible:
+    items:
+      - const: fsl,imx8qxp-sc-thermal
+      - const: fsl,imx-sc-thermal
+
+  '#thermal-sensor-cells':
+    const: 1
+
+required:
+  - compatible
+  - '#thermal-sensor-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    thermal-sensor {
+        compatible = "fsl,imx8qxp-sc-thermal", "fsl,imx-sc-thermal";
+        #thermal-sensor-cells = <1>;
+    };
diff --git a/Documentation/devicetree/bindings/thermal/qcom,spmi-temp-alarm.yaml b/Documentation/devicetree/bindings/thermal/qcom,spmi-temp-alarm.yaml
new file mode 100644 (file)
index 0000000..5f08b6e
--- /dev/null
@@ -0,0 +1,85 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/thermal/qcom,spmi-temp-alarm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm QPNP PMIC Temperature Alarm
+
+maintainers:
+  - Bjorn Andersson <bjorn.andersson@linaro.org>
+
+description:
+  QPNP temperature alarm peripherals are found inside of Qualcomm PMIC chips
+  that utilize the Qualcomm SPMI implementation. These peripherals provide an
+  interrupt signal and status register to identify high PMIC die temperature.
+
+allOf:
+  - $ref: thermal-sensor.yaml#
+
+properties:
+  compatible:
+    const: qcom,spmi-temp-alarm
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  io-channels:
+    items:
+      - description: ADC channel, which reports chip die temperature
+
+  io-channel-names:
+    items:
+      - const: thermal
+
+  '#thermal-sensor-cells':
+    const: 0
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - '#thermal-sensor-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    pmic {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        pm8350_temp_alarm: temperature-sensor@a00 {
+            compatible = "qcom,spmi-temp-alarm";
+            reg = <0xa00>;
+            interrupts = <0x1 0xa 0x0 IRQ_TYPE_EDGE_BOTH>;
+            #thermal-sensor-cells = <0>;
+        };
+    };
+
+    thermal-zones {
+        pm8350_thermal: pm8350c-thermal {
+            polling-delay-passive = <100>;
+            polling-delay = <0>;
+            thermal-sensors = <&pm8350_temp_alarm>;
+
+            trips {
+                pm8350_trip0: trip0 {
+                    temperature = <95000>;
+                    hysteresis = <0>;
+                    type = "passive";
+                };
+
+                pm8350_crit: pm8350c-crit {
+                    temperature = <115000>;
+                    hysteresis = <0>;
+                    type = "critical";
+                };
+            };
+        };
+    };
diff --git a/Documentation/devicetree/bindings/thermal/qcom-spmi-temp-alarm.txt b/Documentation/devicetree/bindings/thermal/qcom-spmi-temp-alarm.txt
deleted file mode 100644 (file)
index 2d5b2ad..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-Qualcomm QPNP PMIC Temperature Alarm
-
-QPNP temperature alarm peripherals are found inside of Qualcomm PMIC chips
-that utilize the Qualcomm SPMI implementation. These peripherals provide an
-interrupt signal and status register to identify high PMIC die temperature.
-
-Required properties:
-- compatible:      Should contain "qcom,spmi-temp-alarm".
-- reg:             Specifies the SPMI address.
-- interrupts:      PMIC temperature alarm interrupt.
-- #thermal-sensor-cells: Should be 0. See Documentation/devicetree/bindings/thermal/thermal-sensor.yaml for a description.
-
-Optional properties:
-- io-channels:     Should contain IIO channel specifier for the ADC channel,
-                   which report chip die temperature.
-- io-channel-names: Should contain "thermal".
-
-Example:
-
-       pm8941_temp: thermal-alarm@2400 {
-               compatible = "qcom,spmi-temp-alarm";
-               reg = <0x2400>;
-               interrupts = <0 0x24 0 IRQ_TYPE_EDGE_RISING>;
-               #thermal-sensor-cells = <0>;
-
-               io-channels = <&pm8941_vadc VADC_DIE_TEMP>;
-               io-channel-names = "thermal";
-       };
-
-       thermal-zones {
-               pm8941 {
-                       polling-delay-passive = <250>;
-                       polling-delay = <1000>;
-
-                       thermal-sensors = <&pm8941_temp>;
-
-                       trips {
-                               stage1 {
-                                       temperature = <105000>;
-                                       hysteresis = <2000>;
-                                       type = "passive";
-                               };
-                               stage2 {
-                                       temperature = <125000>;
-                                       hysteresis = <2000>;
-                                       type = "critical";
-                               };
-                       };
-               };
-       };
-
index 1368d90..0f05f5c 100644 (file)
@@ -8,9 +8,9 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Renesas R-Car Gen3 Thermal Sensor
 
 description:
-  On R-Car Gen3 SoCs, the thermal sensor controllers (TSC) control the thermal
-  sensors (THS) which are the analog circuits for measuring temperature (Tj)
-  inside the LSI.
+  On most R-Car Gen3 and later SoCs, the thermal sensor controllers (TSC)
+  control the thermal sensors (THS) which are the analog circuits for
+  measuring temperature (Tj) inside the LSI.
 
 maintainers:
   - Niklas Söderlund <niklas.soderlund@ragnatech.se>
@@ -27,6 +27,7 @@ properties:
       - renesas,r8a77965-thermal # R-Car M3-N
       - renesas,r8a77980-thermal # R-Car V3H
       - renesas,r8a779a0-thermal # R-Car V3U
+      - renesas,r8a779f0-thermal # R-Car S4-8
 
   reg: true
 
@@ -57,31 +58,38 @@ required:
   - "#thermal-sensor-cells"
 
 if:
-  not:
-    properties:
-      compatible:
-        contains:
-          enum:
-            - renesas,r8a779a0-thermal
+  properties:
+    compatible:
+      contains:
+        enum:
+          - renesas,r8a779a0-thermal
 then:
   properties:
     reg:
-      minItems: 2
       items:
+        - description: TSC0 registers
         - description: TSC1 registers
         - description: TSC2 registers
         - description: TSC3 registers
-  required:
-    - interrupts
+        - description: TSC4 registers
 else:
   properties:
     reg:
+      minItems: 2
       items:
-        - description: TSC0 registers
         - description: TSC1 registers
         - description: TSC2 registers
         - description: TSC3 registers
-        - description: TSC4 registers
+  if:
+    not:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - renesas,r8a779f0-thermal
+  then:
+    required:
+      - interrupts
 
 additionalProperties: false
 
index 53fd24b..3711872 100644 (file)
@@ -20,6 +20,7 @@ properties:
           - allwinner,suniv-f1c100s-timer
       - items:
           - enum:
+              - allwinner,sun20i-d1-timer
               - allwinner,sun50i-a64-timer
               - allwinner,sun50i-h6-timer
               - allwinner,sun50i-h616-timer
index d541cf2..0a01e4f 100644 (file)
@@ -113,7 +113,7 @@ properties:
 patternProperties:
   "^watchdog@[a-f0-9]+$":
     type: object
-    $ref: ../watchdog/watchdog.yaml#
+    $ref: /schemas/watchdog/watchdog.yaml#
     properties:
       compatible:
         oneOf:
@@ -145,7 +145,7 @@ patternProperties:
 
   "^pwm@[a-f0-9]+$":
     type: object
-    $ref: ../pwm/pwm.yaml#
+    $ref: /schemas/pwm/pwm.yaml#
     properties:
       compatible:
         oneOf:
index 6f1f9db..f1c848a 100644 (file)
@@ -1,7 +1,8 @@
 MediaTek Timers
 ---------------
 
-MediaTek SoCs have two different timers on different platforms,
+MediaTek SoCs have different timers on different platforms,
+- CPUX (ARM/ARM64 System Timer)
 - GPT (General Purpose Timer)
 - SYST (System Timer)
 
@@ -29,6 +30,9 @@ Required properties:
        * "mediatek,mt7629-timer" for MT7629 compatible timers (SYST)
        * "mediatek,mt6765-timer" for MT6765 and all above compatible timers (SYST)
 
+       For those SoCs that use CPUX
+       * "mediatek,mt6795-systimer" for MT6795 compatible timers (CPUX)
+
 - reg: Should contain location and length for timer register.
 - clocks: Should contain system clock.
 
index 0cbc26a..737af78 100644 (file)
@@ -8,12 +8,14 @@ title: Nuvoton NPCM7xx timer
 
 maintainers:
   - Jonathan Neuschäfer <j.neuschaefer@gmx.net>
+  - Tomer Maimon <tmaimon77@gmail.com>
 
 properties:
   compatible:
     enum:
       - nuvoton,wpcm450-timer  # for Hermon WPCM450
       - nuvoton,npcm750-timer  # for Poleg NPCM750
+      - nuvoton,npcm845-timer  # for Arbel NPCM845
 
   reg:
     maxItems: 1
diff --git a/Documentation/devicetree/bindings/timer/nvidia,tegra186-timer.yaml b/Documentation/devicetree/bindings/timer/nvidia,tegra186-timer.yaml
new file mode 100644 (file)
index 0000000..db8b559
--- /dev/null
@@ -0,0 +1,109 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/timer/nvidia,tegra186-timer.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: NVIDIA Tegra186 timer
+
+maintainers:
+  - Thierry Reding <treding@nvidia.com>
+
+description: >
+  The Tegra timer provides 29-bit timer counters and a 32-bit timestamp
+  counter. Each NV timer selects its timing reference signal from the 1 MHz
+  reference generated by USEC, TSC or either clk_m or OSC. Each TMR can be
+  programmed to generate one-shot, periodic, or watchdog interrupts.
+
+
+properties:
+  compatible:
+    oneOf:
+      - const: nvidia,tegra186-timer
+        description: >
+          The Tegra186 timer provides ten 29-bit timer counters.
+      - const: nvidia,tegra234-timer
+        description: >
+          The Tegra234 timer provides sixteen 29-bit timer counters.
+
+  reg:
+    maxItems: 1
+
+  interrupts: true
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: nvidia,tegra186-timer
+    then:
+      properties:
+        interrupts:
+          maxItems: 10
+          description: >
+            One per each timer channels 0 through 9.
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: nvidia,tegra234-timer
+    then:
+      properties:
+        interrupts:
+          maxItems: 16
+          description: >
+            One per each timer channels 0 through 15.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    timer@3010000 {
+        compatible = "nvidia,tegra186-timer";
+        reg = <0x03010000 0x000e0000>;
+        interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+    };
+
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    timer@2080000 {
+        compatible = "nvidia,tegra234-timer";
+        reg = <0x02080000 0x00121000>;
+        interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+    };
index 53dd6d9..bde6c9b 100644 (file)
@@ -80,7 +80,6 @@ properties:
               - renesas,r8a77980-cmt0     # 32-bit CMT0 on R-Car V3H
               - renesas,r8a77990-cmt0     # 32-bit CMT0 on R-Car E3
               - renesas,r8a77995-cmt0     # 32-bit CMT0 on R-Car D3
-              - renesas,r8a779a0-cmt0     # 32-bit CMT0 on R-Car V3U
           - const: renesas,rcar-gen3-cmt0 # 32-bit CMT0 on R-Car Gen3 and RZ/G2
 
       - items:
@@ -97,9 +96,20 @@ properties:
               - renesas,r8a77980-cmt1     # 48-bit CMT on R-Car V3H
               - renesas,r8a77990-cmt1     # 48-bit CMT on R-Car E3
               - renesas,r8a77995-cmt1     # 48-bit CMT on R-Car D3
-              - renesas,r8a779a0-cmt1     # 48-bit CMT on R-Car V3U
           - const: renesas,rcar-gen3-cmt1 # 48-bit CMT on R-Car Gen3 and RZ/G2
 
+      - items:
+          - enum:
+              - renesas,r8a779a0-cmt0     # 32-bit CMT0 on R-Car V3U
+              - renesas,r8a779f0-cmt0     # 32-bit CMT0 on R-Car S4-8
+          - const: renesas,rcar-gen4-cmt0 # 32-bit CMT0 on R-Car Gen4
+
+      - items:
+          - enum:
+              - renesas,r8a779a0-cmt1     # 48-bit CMT on R-Car V3U
+              - renesas,r8a779f0-cmt1     # 48-bit CMT on R-Car S4-8
+          - const: renesas,rcar-gen4-cmt1 # 48-bit CMT on R-Car Gen4
+
   reg:
     maxItems: 1
 
@@ -135,6 +145,7 @@ allOf:
             enum:
               - renesas,rcar-gen2-cmt0
               - renesas,rcar-gen3-cmt0
+              - renesas,rcar-gen4-cmt0
     then:
       properties:
         interrupts:
@@ -148,6 +159,7 @@ allOf:
             enum:
               - renesas,rcar-gen2-cmt1
               - renesas,rcar-gen3-cmt1
+              - renesas,rcar-gen4-cmt1
     then:
       properties:
         interrupts:
diff --git a/Documentation/devicetree/bindings/timer/st,nomadik-mtu.yaml b/Documentation/devicetree/bindings/timer/st,nomadik-mtu.yaml
new file mode 100644 (file)
index 0000000..901848d
--- /dev/null
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2022 Linaro Ltd.
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/timer/st,nomadik-mtu.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: ST Microelectronics Nomadik Multi-Timer Unit MTU Timer
+
+maintainers:
+  - Linus Walleij <linus.walleij@linaro.org>
+
+description: This timer is found in the ST Microelectronics Nomadik
+  SoCs STn8800, STn8810 and STn8815 as well as in ST-Ericsson DB8500.
+
+properties:
+  compatible:
+    items:
+      - const: st,nomadik-mtu
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    description: The first clock named TIMCLK clocks the actual timers and
+      the second clock clocks the digital interface to the interconnect.
+    maxItems: 2
+
+  clock-names:
+    items:
+      - const: timclk
+      - const: apb_pclk
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/mfd/dbx500-prcmu.h>
+    timer@a03c6000 {
+      compatible = "st,nomadik-mtu";
+      reg = <0xa03c6000 0x1000>;
+      interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+
+      clocks = <&prcmu_clk PRCMU_TIMCLK>, <&prcc_pclk 6 6>;
+      clock-names = "timclk", "apb_pclk";
+    };
index 6aafa71..5d87b84 100644 (file)
@@ -41,6 +41,8 @@ properties:
           - adi,adp5585-02
             # Analog Devices ADP5589 Keypad Decoder and I/O Expansion
           - adi,adp5589
+            # Analog Devices LT7182S Dual Channel 6A, 20V PolyPhase Step-Down Silent Switcher
+          - adi,lt7182s
             # AMS iAQ-Core VOC Sensor
           - ams,iaq-core
             # i2c serial eeprom (24cxx)
index 933fa35..e5dbf41 100644 (file)
@@ -20,6 +20,7 @@ properties:
       - items:
           - enum:
               - allwinner,sun8i-a83t-musb
+              - allwinner,sun20i-d1-musb
               - allwinner,sun50i-h6-musb
           - const: allwinner,sun8i-a33-musb
       - items:
index f512f02..12183ef 100644 (file)
@@ -87,6 +87,9 @@ Required properties:
               "atmel,at91sam9g45-udc"
               "atmel,sama5d3-udc"
               "microchip,sam9x60-udc"
+              "microchip,lan9662-udc"
+              For "microchip,lan9662-udc" the fallback "atmel,sama5d3-udc"
+              is required.
  - reg: Address and length of the register set for the device
  - interrupts: Should contain usba interrupt
  - clocks: Should reference the peripheral and host clocks
index 1e84e1b..25a6c14 100644 (file)
@@ -38,6 +38,7 @@ properties:
               - allwinner,sun8i-h3-ehci
               - allwinner,sun8i-r40-ehci
               - allwinner,sun9i-a80-ehci
+              - allwinner,sun20i-d1-ehci
               - aspeed,ast2400-ehci
               - aspeed,ast2500-ehci
               - aspeed,ast2600-ehci
index bb6bbd5..180361b 100644 (file)
@@ -28,6 +28,7 @@ properties:
               - allwinner,sun8i-h3-ohci
               - allwinner,sun8i-r40-ohci
               - allwinner,sun9i-a80-ohci
+              - allwinner,sun20i-d1-ohci
               - brcm,bcm3384-ohci
               - brcm,bcm63268-ohci
               - brcm,bcm6328-ohci
index 0496773..ff0ac85 100644 (file)
@@ -510,6 +510,8 @@ patternProperties:
     description: Haoyu Microelectronic Co. Ltd.
   "^hardkernel,.*":
     description: Hardkernel Co., Ltd
+  "^hechuang,.*":
+    description: Shenzhen Hechuang Intelligent Co.
   "^hideep,.*":
     description: HiDeep Inc.
   "^himax,.*":
@@ -1101,6 +1103,8 @@ patternProperties:
     description: SGX Sensortech
   "^sharp,.*":
     description: Sharp Corporation
+  "^shift,.*":
+    description: SHIFT GmbH
   "^shimafuji,.*":
     description: Shimafuji Electric, Inc.
   "^shiratech,.*":
diff --git a/Documentation/devicetree/bindings/watchdog/fsl,scu-wdt.yaml b/Documentation/devicetree/bindings/watchdog/fsl,scu-wdt.yaml
new file mode 100644 (file)
index 0000000..f84c45d
--- /dev/null
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/watchdog/fsl,scu-wdt.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: i.MX SCU Client Device Node - Watchdog bindings based on SCU Message Protocol
+
+maintainers:
+  - Dong Aisheng <aisheng.dong@nxp.com>
+
+description: i.MX SCU Client Device Node
+  Client nodes are maintained as children of the relevant IMX-SCU device node.
+
+allOf:
+  - $ref: watchdog.yaml#
+
+properties:
+  compatible:
+    items:
+      - const: fsl,imx8qxp-sc-wdt
+      - const: fsl,imx-sc-wdt
+
+required:
+  - compatible
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    watchdog {
+        compatible = "fsl,imx8qxp-sc-wdt", "fsl,imx-sc-wdt";
+        timeout-sec = <60>;
+    };
index 9059f54..866a958 100644 (file)
@@ -6,7 +6,8 @@ expiry.
 
 Required properties:
 - compatible      : "nuvoton,npcm750-wdt" for NPCM750 (Poleg), or
-                    "nuvoton,wpcm450-wdt" for WPCM450 (Hermon).
+                    "nuvoton,wpcm450-wdt" for WPCM450 (Hermon), or
+                    "nuvoton,npcm845-wdt" for NPCM845 (Arbel).
 - reg             : Offset and length of the register set for the device.
 - interrupts      : Contain the timer interrupt with flags for
                     falling edge.
index a7cb2af..9c779bd 100644 (file)
@@ -1,3 +1,5 @@
+.. title:: Kernel-doc comments
+
 ===========================
 Writing kernel-doc comments
 ===========================
index 2ff1ab4..1228b85 100644 (file)
@@ -132,7 +132,8 @@ format-specific subdirectories under ``Documentation/output``.
 To generate documentation, Sphinx (``sphinx-build``) must obviously be
 installed. For prettier HTML output, the Read the Docs Sphinx theme
 (``sphinx_rtd_theme``) is used if available. For PDF output you'll also need
-``XeLaTeX`` and ``convert(1)`` from ImageMagick (https://www.imagemagick.org).
+``XeLaTeX`` and ``convert(1)`` from ImageMagick
+(https://www.imagemagick.org).\ [#ink]_
 All of these are widely available and packaged in distributions.
 
 To pass extra options to Sphinx, you can use the ``SPHINXOPTS`` make
@@ -150,8 +151,19 @@ If the theme is not available, it will fall-back to the classic one.
 
 The Sphinx theme can be overridden by using the ``DOCS_THEME`` make variable.
 
+There is another make variable ``SPHINXDIRS``, which is useful when test
+building a subset of documentation.  For example, you can build documents
+under ``Documentation/doc-guide`` by running
+``make SPHINXDIRS=doc-guide htmldocs``.
+The documentation section of ``make help`` will show you the list of
+subdirectories you can specify.
+
 To remove the generated documentation, run ``make cleandocs``.
 
+.. [#ink] Having ``inkscape(1)`` from Inkscape (https://inkscape.org)
+         as well would improve the quality of images embedded in PDF
+         documents, especially for kernel releases 5.18 and later.
+
 Writing Documentation
 =====================
 
index b81794e..06ac89a 100644 (file)
@@ -13,6 +13,12 @@ EDD Interfaces
 .. kernel-doc:: drivers/firmware/edd.c
    :internal:
 
+Generic System Framebuffers Interface
+-------------------------------------
+
+.. kernel-doc:: drivers/firmware/sysfb.c
+   :export:
+
 Intel Stratix10 SoC Service Layer
 ---------------------------------
 Some features of the Intel Stratix10 SoC require a level of privilege
index 72bcf5f..de6fc79 100644 (file)
@@ -114,7 +114,7 @@ For a function using multiple GPIOs all of those can be obtained with one call::
 
 This function returns a struct gpio_descs which contains an array of
 descriptors.  It also contains a pointer to a gpiolib private structure which,
-if passed back to get/set array functions, may speed up I/O proocessing::
+if passed back to get/set array functions, may speed up I/O processing::
 
        struct gpio_descs {
                struct gpio_array *info;
index 70ff43a..6baaeab 100644 (file)
@@ -119,7 +119,7 @@ GPIO lines with debounce support
 Debouncing is a configuration set to a pin indicating that it is connected to
 a mechanical switch or button, or similar that may bounce. Bouncing means the
 line is pulled high/low quickly at very short intervals for mechanical
-reasons. This can result in the value being unstable or irqs fireing repeatedly
+reasons. This can result in the value being unstable or irqs firing repeatedly
 unless the line is debounced.
 
 Debouncing in practice involves setting up a timer when something happens on
@@ -219,7 +219,7 @@ use a trick: when a line is set as output, if the line is flagged as open
 drain, and the IN output value is low, it will be driven low as usual. But
 if the IN output value is set to high, it will instead *NOT* be driven high,
 instead it will be switched to input, as input mode is high impedance, thus
-achieveing an "open drain emulation" of sorts: electrically the behaviour will
+achieving an "open drain emulation" of sorts: electrically the behaviour will
 be identical, with the exception of possible hardware glitches when switching
 the mode of the line.
 
@@ -642,7 +642,7 @@ In this case the typical set-up will look like this:
 
 As you can see pretty similar, but you do not supply a parent handler for
 the IRQ, instead a parent irqdomain, an fwnode for the hardware and
-a funcion .child_to_parent_hwirq() that has the purpose of looking up
+a function .child_to_parent_hwirq() that has the purpose of looking up
 the parent hardware irq from a child (i.e. this gpio chip) hardware irq.
 As always it is good to look at examples in the kernel tree for advice
 on how to find the required pieces.
index 64c8d3f..894d888 100644 (file)
@@ -44,7 +44,7 @@ These devices will appear on the system as ``/dev/gpiochip0`` thru
 found in the kernel tree ``tools/gpio`` subdirectory.
 
 For structured and managed applications, we recommend that you make use of the
-libgpiod_ library. This provides helper abstractions, command line utlities
+libgpiod_ library. This provides helper abstractions, command line utilities
 and arbitration for multiple simultaneous consumers on the same GPIO chip.
 
 .. _libgpiod: https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/
index 41983e0..f2d6172 100644 (file)
@@ -25,8 +25,7 @@ and userspace consumers. The kernel space consumers can directly talk to HTE
 subsystem while userspace consumers timestamp requests go through GPIOLIB CDEV
 framework to HTE subsystem.
 
-.. kernel-doc:: drivers/gpio/gpiolib.c
-   :functions: gpiod_enable_hw_timestamp_ns gpiod_disable_hw_timestamp_ns
+See gpiod_enable_hw_timestamp_ns() and gpiod_disable_hw_timestamp_ns().
 
 For userspace consumers, GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE flag must be
 specified during IOCTL calls. Refer to ``tools/gpio/gpio-event-mon.c``, which
@@ -37,7 +36,7 @@ LIC (Legacy Interrupt Controller) IRQ GTE
 
 This GTE instance timestamps LIC IRQ lines in real time. There are 352 IRQ
 lines which this instance can add timestamps to in real time. The hte
-devicetree binding described at ``Documentation/devicetree/bindings/hte/``
+devicetree binding described at ``Documentation/devicetree/bindings/timestamp``
 provides an example of how a consumer can request an IRQ line. Since it is a
 one-to-one mapping with IRQ GTE provider, consumers can simply specify the IRQ
 number that they are interested in. There is no userspace consumer support for
index c9e0a16..e59071a 100644 (file)
@@ -1,7 +1,7 @@
 #
-# Feature name:          context-tracking
-#         Kconfig:       HAVE_CONTEXT_TRACKING
-#         description:   arch supports context tracking for NO_HZ_FULL
+# Feature name:          user-context-tracking
+#         Kconfig:       HAVE_CONTEXT_TRACKING_USER
+#         description:   arch supports user context tracking for NO_HZ_FULL
 #
     -----------------------
     |         arch |status|
index b01bf7b..6bd78eb 100644 (file)
@@ -9,7 +9,7 @@
     |       alpha: | TODO |
     |         arc: |  ok  |
     |         arm: | TODO |
-    |       arm64: | TODO |
+    |       arm64: |  ok  |
     |        csky: | TODO |
     |     hexagon: | TODO |
     |        ia64: | TODO |
index d0904f6..992eddb 100644 (file)
@@ -19,13 +19,23 @@ The main Btrfs features include:
     * Subvolumes (separate internal filesystem roots)
     * Object level mirroring and striping
     * Checksums on data and metadata (multiple algorithms available)
-    * Compression
+    * Compression (multiple algorithms available)
+    * Reflink, deduplication
+    * Scrub (on-line checksum verification)
+    * Hierarchical quota groups (subvolume and snapshot support)
     * Integrated multiple device support, with several raid algorithms
     * Offline filesystem check
-    * Efficient incremental backup and FS mirroring
+    * Efficient incremental backup and FS mirroring (send/receive)
+    * Trim/discard
     * Online filesystem defragmentation
+    * Swapfile support
+    * Zoned mode
+    * Read/write metadata verification
+    * Online resize (shrink, grow)
 
-For more information please refer to the wiki
+For more information please refer to the documentation site or wiki
+
+  https://btrfs.readthedocs.io
 
   https://btrfs.wiki.kernel.org
 
index ad8dc8c..98dc24f 100644 (file)
@@ -818,10 +818,11 @@ Compression implementation
   Instead, the main goal is to reduce data writes to flash disk as much as
   possible, resulting in extending disk life time as well as relaxing IO
   congestion. Alternatively, we've added ioctl(F2FS_IOC_RELEASE_COMPRESS_BLOCKS)
-  interface to reclaim compressed space and show it to user after putting the
-  immutable bit. Immutable bit, after release, it doesn't allow writing/mmaping
-  on the file, until reserving compressed space via
-  ioctl(F2FS_IOC_RESERVE_COMPRESS_BLOCKS) or truncating filesize to zero.
+  interface to reclaim compressed space and show it to user after setting a
+  special flag to the inode. Once the compressed space is released, the flag
+  will block writing data to the file until either the compressed space is
+  reserved via ioctl(F2FS_IOC_RESERVE_COMPRESS_BLOCKS) or the file size is
+  truncated to zero.
 
 Compress metadata layout::
 
@@ -830,12 +831,12 @@ Compress metadata layout::
                | cluster 1 | cluster 2 | ......... | cluster N |
                +-----------------------------------------------+
                .           .                       .           .
-                             .                .                      .
+         .                      .                .                      .
     .         Compressed Cluster       .        .        Normal Cluster            .
     +----------+---------+---------+---------+  +---------+---------+---------+---------+
     |compr flag| block 1 | block 2 | block 3 |  | block 1 | block 2 | block 3 | block 4 |
     +----------+---------+---------+---------+  +---------+---------+---------+---------+
-           .                             .
+              .                             .
            .                                           .
        .                                                           .
        +-------------+-------------+----------+----------------------------+
index 2e9aaa2..5ba5817 100644 (file)
@@ -337,6 +337,7 @@ Currently, the following pairs of encryption modes are supported:
 - AES-256-XTS for contents and AES-256-CTS-CBC for filenames
 - AES-128-CBC for contents and AES-128-CTS-CBC for filenames
 - Adiantum for both contents and filenames
+- AES-256-XTS for contents and AES-256-HCTR2 for filenames (v2 policies only)
 
 If unsure, you should use the (AES-256-XTS, AES-256-CTS-CBC) pair.
 
@@ -357,6 +358,17 @@ To use Adiantum, CONFIG_CRYPTO_ADIANTUM must be enabled.  Also, fast
 implementations of ChaCha and NHPoly1305 should be enabled, e.g.
 CONFIG_CRYPTO_CHACHA20_NEON and CONFIG_CRYPTO_NHPOLY1305_NEON for ARM.
 
+AES-256-HCTR2 is another true wide-block encryption mode that is intended for
+use on CPUs with dedicated crypto instructions.  AES-256-HCTR2 has the property
+that a bitflip in the plaintext changes the entire ciphertext.  This property
+makes it desirable for filename encryption since initialization vectors are
+reused within a directory.  For more details on AES-256-HCTR2, see the paper
+"Length-preserving encryption with HCTR2"
+(https://eprint.iacr.org/2021/1441.pdf).  To use AES-256-HCTR2,
+CONFIG_CRYPTO_HCTR2 must be enabled.  Also, fast implementations of XCTR and
+POLYVAL should be enabled, e.g. CRYPTO_POLYVAL_ARM64_CE and
+CRYPTO_AES_ARM64_CE_BLK for ARM64.
+
 New encryption modes can be added relatively easily, without changes
 to individual filesystems.  However, authenticated encryption (AE)
 modes are not currently supported because of the difficulty of dealing
@@ -404,11 +416,11 @@ alternatively has the file's nonce (for `DIRECT_KEY policies`_) or
 inode number (for `IV_INO_LBLK_64 policies`_) included in the IVs.
 Thus, IV reuse is limited to within a single directory.
 
-With CTS-CBC, the IV reuse means that when the plaintext filenames
-share a common prefix at least as long as the cipher block size (16
-bytes for AES), the corresponding encrypted filenames will also share
-a common prefix.  This is undesirable.  Adiantum does not have this
-weakness, as it is a wide-block encryption mode.
+With CTS-CBC, the IV reuse means that when the plaintext filenames share a
+common prefix at least as long as the cipher block size (16 bytes for AES), the
+corresponding encrypted filenames will also share a common prefix.  This is
+undesirable.  Adiantum and HCTR2 do not have this weakness, as they are
+wide-block encryption modes.
 
 All supported filenames encryption modes accept any plaintext length
 >= 16 bytes; cipher block alignment is not required.  However,
index 756f2c2..cb8e757 100644 (file)
@@ -11,9 +11,9 @@ Introduction
 
 fs-verity (``fs/verity/``) is a support layer that filesystems can
 hook into to support transparent integrity and authenticity protection
-of read-only files.  Currently, it is supported by the ext4 and f2fs
-filesystems.  Like fscrypt, not too much filesystem-specific code is
-needed to support fs-verity.
+of read-only files.  Currently, it is supported by the ext4, f2fs, and
+btrfs filesystems.  Like fscrypt, not too much filesystem-specific
+code is needed to support fs-verity.
 
 fs-verity is similar to `dm-verity
 <https://www.kernel.org/doc/Documentation/device-mapper/verity.txt>`_
@@ -473,9 +473,9 @@ files being swapped around.
 Filesystem support
 ==================
 
-fs-verity is currently supported by the ext4 and f2fs filesystems.
-The CONFIG_FS_VERITY kconfig option must be enabled to use fs-verity
-on either filesystem.
+fs-verity is supported by several filesystems, described below.  The
+CONFIG_FS_VERITY kconfig option must be enabled to use fs-verity on
+any of these filesystems.
 
 ``include/linux/fsverity.h`` declares the interface between the
 ``fs/verity/`` support layer and filesystems.  Briefly, filesystems
@@ -544,6 +544,13 @@ Currently, f2fs verity only supports a Merkle tree block size of 4096.
 Also, f2fs doesn't support enabling verity on files that currently
 have atomic or volatile writes pending.
 
+btrfs
+-----
+
+btrfs supports fs-verity since Linux v5.15.  Verity-enabled inodes are
+marked with a RO_COMPAT inode flag, and the verity metadata is stored
+in separate btree items.
+
 Implementation details
 ======================
 
@@ -622,14 +629,14 @@ workqueue, and then the workqueue work does the decryption or
 verification.  Finally, pages where no decryption or verity error
 occurred are marked Uptodate, and the pages are unlocked.
 
-Files on ext4 and f2fs may contain holes.  Normally, ``->readahead()``
-simply zeroes holes and sets the corresponding pages Uptodate; no bios
-are issued.  To prevent this case from bypassing fs-verity, these
-filesystems use fsverity_verify_page() to verify hole pages.
+On many filesystems, files can contain holes.  Normally,
+``->readahead()`` simply zeroes holes and sets the corresponding pages
+Uptodate; no bios are issued.  To prevent this case from bypassing
+fs-verity, these filesystems use fsverity_verify_page() to verify hole
+pages.
 
-ext4 and f2fs disable direct I/O on verity files, since otherwise
-direct I/O would bypass fs-verity.  (They also do the same for
-encrypted files.)
+Filesystems also disable direct I/O on verity files, since otherwise
+direct I/O would bypass fs-verity.
 
 Userspace utility
 =================
@@ -648,7 +655,7 @@ Tests
 To test fs-verity, use xfstests.  For example, using `kvm-xfstests
 <https://github.com/tytso/xfstests-bld/blob/master/Documentation/kvm-quickstart.md>`_::
 
-    kvm-xfstests -c ext4,f2fs -g verity
+    kvm-xfstests -c ext4,f2fs,btrfs -g verity
 
 FAQ
 ===
@@ -771,15 +778,15 @@ weren't already directly answered in other parts of this document.
     e.g. magically trigger construction of a Merkle tree.
 
 :Q: Does fs-verity support remote filesystems?
-:A: Only ext4 and f2fs support is implemented currently, but in
-    principle any filesystem that can store per-file verity metadata
-    can support fs-verity, regardless of whether it's local or remote.
-    Some filesystems may have fewer options of where to store the
-    verity metadata; one possibility is to store it past the end of
-    the file and "hide" it from userspace by manipulating i_size.  The
-    data verification functions provided by ``fs/verity/`` also assume
-    that the filesystem uses the Linux pagecache, but both local and
-    remote filesystems normally do so.
+:A: So far all filesystems that have implemented fs-verity support are
+    local filesystems, but in principle any filesystem that can store
+    per-file verity metadata can support fs-verity, regardless of
+    whether it's local or remote.  Some filesystems may have fewer
+    options of where to store the verity metadata; one possibility is
+    to store it past the end of the file and "hide" it from userspace
+    by manipulating i_size.  The data verification functions provided
+    by ``fs/verity/`` also assume that the filesystem uses the Linux
+    pagecache, but both local and remote filesystems normally do so.
 
 :Q: Why is anything filesystem-specific at all?  Shouldn't fs-verity
     be implemented entirely at the VFS level?
index 4d19b19..73a4176 100644 (file)
@@ -301,7 +301,7 @@ through which it can issue requests and negotiate::
                void (*issue_read)(struct netfs_io_subrequest *subreq);
                bool (*is_still_valid)(struct netfs_io_request *rreq);
                int (*check_write_begin)(struct file *file, loff_t pos, unsigned len,
-                                        struct folio *folio, void **_fsdata);
+                                        struct folio **foliop, void **_fsdata);
                void (*done)(struct netfs_io_request *rreq);
        };
 
@@ -381,8 +381,10 @@ The operations are as follows:
    allocated/grabbed the folio to be modified to allow the filesystem to flush
    conflicting state before allowing it to be modified.
 
-   It should return 0 if everything is now fine, -EAGAIN if the folio should be
-   regrabbed and any other error code to abort the operation.
+   It may unlock and discard the folio it was given and set the caller's folio
+   pointer to NULL.  It should return 0 if everything is now fine (``*foliop``
+   left set) or the op should be retried (``*foliop`` cleared) and any other
+   error code to abort the operation.
 
  * ``done``
 
index 7da6c30..4c76fda 100644 (file)
@@ -607,7 +607,7 @@ can be removed.
 User xattr
 ----------
 
-The the "-o userxattr" mount option forces overlayfs to use the
+The "-o userxattr" mount option forces overlayfs to use the
 "user.overlay." xattr namespace instead of "trusted.overlay.".  This is
 useful for unprivileged mounting of overlayfs.
 
index 8b2d8d0..70442bc 100644 (file)
@@ -21,7 +21,9 @@ specific type) associated with it.
 
 In the ACPI _DSD context it is an element of the sub-package following the
 generic Device Properties UUID in the _DSD return package as specified in the
-Device Properties UUID definition document [1]_.
+section titled "Well-Known _DSD UUIDs and Data Structure Formats" sub-section
+"Device Properties UUID" in _DSD (Device Specific Data) Implementation Guide
+document [1]_.
 
 It also may be regarded as the definition of a key and the associated data type
 that can be returned by _DSD in the Device Properties UUID sub-package for a
@@ -36,7 +38,9 @@ Property subsets are nested collections of properties.  Each of them is
 associated with an additional key (name) allowing the subset to be referred
 to as a whole (and to be treated as a separate entity).  The canonical
 representation of property subsets is via the mechanism specified in the
-Hierarchical Properties Extension UUID definition document [2]_.
+section titled "Well-Known _DSD UUIDs and Data Structure Formats" sub-section
+"Hierarchical Data Extension UUID" in _DSD (Device Specific Data)
+Implementation Guide document [1]_.
 
 Property sets may be hierarchical.  That is, a property set may contain
 multiple property subsets that each may contain property subsets of its
@@ -96,5 +100,4 @@ contents.
 References
 ==========
 
-.. [1] https://www.uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf
-.. [2] https://www.uefi.org/sites/default/files/resources/_DSD-hierarchical-data-extension-UUID-v1.1.pdf
+.. [1] https://github.com/UEFI/DSD-Guide
index 55e2331..d6b61d2 100644 (file)
@@ -168,7 +168,7 @@ An error injection example::
   0x00000008   Memory Correctable
   0x00000010   Memory Uncorrectable non-fatal
   # echo 0x12345000 > param1           # Set memory address for injection
-  # echo $((-1 << 12)) > param2                # Mask 0xfffffffffffff000 - anywhere in this page
+  # echo 0xfffffffffffff000 > param2           # Mask - anywhere in this page
   # echo 0x8 > error_type                      # Choose correctable memory error
   # echo 1 > error_inject                      # Inject now
 
index 717e282..33649a1 100644 (file)
@@ -9,6 +9,7 @@ Supported devices:
 * Aquacomputer Farbwerk RGB controller
 * Aquacomputer Farbwerk 360 RGB controller
 * Aquacomputer Octo fan controller
+* Aquacomputer Quadro fan controller
 
 Author: Aleksa Savic
 
@@ -33,6 +34,9 @@ better suited for userspace tools.
 The Octo exposes four temperature sensors and eight PWM controllable fans, along
 with their speed (in RPM), power, voltage and current.
 
+The Quadro exposes four temperature sensors, a flow sensor and four PWM controllable
+fans, along with their speed (in RPM), power, voltage and current.
+
 The Farbwerk and Farbwerk 360 expose four temperature sensors. Depending on the device,
 not all sysfs and debugfs entries will be available.
 
@@ -45,13 +49,14 @@ the kernel and supports hotswapping.
 Sysfs entries
 -------------
 
-================ =============================================
+================ ==============================================
 temp[1-4]_input  Temperature sensors (in millidegrees Celsius)
-fan[1-2]_input   Pump/fan speed (in RPM)
-power[1-2]_input Pump/fan power (in micro Watts)
-in[0-2]_input    Pump/fan voltage (in milli Volts)
-curr[1-2]_input  Pump/fan current (in milli Amperes)
-================ =============================================
+fan[1-8]_input   Pump/fan speed (in RPM) / Flow speed (in dL/h)
+power[1-8]_input Pump/fan power (in micro Watts)
+in[0-7]_input    Pump/fan voltage (in milli Volts)
+curr[1-8]_input  Pump/fan current (in milli Amperes)
+pwm[1-8]         Fan PWM (0 - 255)
+================ ==============================================
 
 Debugfs entries
 ---------------
index 78ca69e..02f4ad3 100644 (file)
@@ -13,12 +13,16 @@ Supported boards:
  * ROG CROSSHAIR VIII FORMULA
  * ROG CROSSHAIR VIII HERO
  * ROG CROSSHAIR VIII IMPACT
+ * ROG MAXIMUS XI HERO
+ * ROG MAXIMUS XI HERO (WI-FI)
  * ROG STRIX B550-E GAMING
  * ROG STRIX B550-I GAMING
  * ROG STRIX X570-E GAMING
  * ROG STRIX X570-E GAMING WIFI II
  * ROG STRIX X570-F GAMING
  * ROG STRIX X570-I GAMING
+ * ROG STRIX Z690-A GAMING WIFI D4
+ * ROG ZENITH II EXTREME
 
 Authors:
     - Eugene Shalygin <eugene.shalygin@gmail.com>
index e5d85e4..d8f1d68 100644 (file)
@@ -46,6 +46,9 @@ temp[1-10]_input                RO      Temperature reading in milli-degrees
 temp[1-10]_label                RO      Temperature sensor label.
 =============================== ======= =======================================
 
+Due to the nature of the SMM interface, each pwmX attribute controls
+fan number X.
+
 Disabling automatic BIOS fan control
 ------------------------------------
 
index a72c168..f7113b0 100644 (file)
@@ -109,6 +109,7 @@ Hardware Monitoring Kernel Drivers
    lm95234
    lm95245
    lochnagar
+   lt7182s
    ltc2992
    ltc2945
    ltc2947
index 05391fb..23af17a 100644 (file)
@@ -3,6 +3,14 @@ Kernel driver lm90
 
 Supported chips:
 
+  * National Semiconductor LM84
+
+    Prefix: 'lm84'
+
+    Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
+
+    Datasheet: Publicly available at the National Semiconductor website
+
   * National Semiconductor LM90
 
     Prefix: 'lm90'
@@ -43,6 +51,30 @@ Supported chips:
 
               http://www.national.com/mpf/LM/LM86.html
 
+  * Analog Devices ADM1020
+
+    Prefix: 'adm1020'
+
+    Addresses scanned: I2C 0x4c - 0x4e
+
+    Datasheet: Publicly available at the Analog Devices website
+
+  * Analog Devices ADM1021
+
+    Prefix: 'adm1021'
+
+    Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
+
+    Datasheet: Publicly available at the Analog Devices website
+
+  * Analog Devices ADM1021A/ADM1023
+
+    Prefix: 'adm1023'
+
+    Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
+
+    Datasheet: Publicly available at the Analog Devices website
+
   * Analog Devices ADM1032
 
     Prefix: 'adm1032'
@@ -73,6 +105,36 @@ Supported chips:
 
               https://www.onsemi.com/PowerSolutions/product.do?id=ADT7461A
 
+  * Analog Devices ADT7481
+
+    Prefix: 'adt7481'
+
+    Addresses scanned: I2C 0x4b and 0x4c
+
+    Datasheet: Publicly available at the ON Semiconductor website
+
+              https://www.onsemi.com/PowerSolutions/product.do?id=ADT7481
+
+  * Analog Devices ADT7482
+
+    Prefix: 'adt7482'
+
+    Addresses scanned: I2C 0x4c
+
+    Datasheet: Publicly available at the ON Semiconductor website
+
+              https://www.onsemi.com/PowerSolutions/product.do?id=ADT7482
+
+  * Analog Devices ADT7483A
+
+    Prefix: 'adt7483a'
+
+    Addresses scanned: I2C 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e
+
+    Datasheet: Publicly available at the ON Semiconductor website
+
+              https://www.onsemi.com/PowerSolutions/product.do?id=ADT7483A
+
   * ON Semiconductor NCT1008
 
     Prefix: 'nct1008'
@@ -83,6 +145,72 @@ Supported chips:
 
               https://www.onsemi.com/PowerSolutions/product.do?id=NCT1008
 
+  * ON Semiconductor NCT210
+
+    Prefix: 'adm1021'
+
+    Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
+
+    Datasheet: Publicly available at the ON Semiconductor website
+
+              https://www.onsemi.com/PowerSolutions/product.do?id=NCT210
+
+  * ON Semiconductor NCT214
+
+    Prefix: 'nct214'
+
+    Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
+
+    Datasheet: Publicly available at the ON Semiconductor website
+
+              https://www.onsemi.com/PowerSolutions/product.do?id=NCT214
+
+  * ON Semiconductor NCT218
+
+    Prefix: 'nct218'
+
+    Addresses scanned: I2C 0x4c - 0x4d
+
+    Datasheet: Publicly available at the ON Semiconductor website
+
+              https://www.onsemi.com/PowerSolutions/product.do?id=NCT218
+
+  * ON Semiconductor NCT72
+
+    Prefix: 'nct72'
+
+    Addresses scanned: I2C 0x4c - 0x4d
+
+    Datasheet: Publicly available at the ON Semiconductor website
+
+              https://www.onsemi.com/PowerSolutions/product.do?id=NCT72
+
+  * Maxim MAX1617
+
+    Prefix: 'max1617'
+
+    Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
+
+    Datasheet: Publicly available at the Maxim website
+
+  * Maxim MAX1617A
+
+    Prefix: 'max1617a'
+
+    Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
+
+    Datasheet: Publicly available at the Maxim website
+
+  * Maxim MAX6642
+
+    Prefix: 'max6642'
+
+    Addresses scanned: I2C 0x48-0x4f
+
+    Datasheet: Publicly available at the Maxim website
+
+              http://datasheets.maxim-ic.com/en/ds/MAX6642.pdf
+
   * Maxim MAX6646
 
     Prefix: 'max6646'
@@ -105,7 +233,7 @@ Supported chips:
 
   * Maxim MAX6648
 
-    Prefix: 'max6646'
+    Prefix: 'max6648'
 
     Addresses scanned: I2C 0x4c
 
@@ -191,7 +319,7 @@ Supported chips:
 
   * Maxim MAX6692
 
-    Prefix: 'max6646'
+    Prefix: 'max6648'
 
     Addresses scanned: I2C 0x4c
 
@@ -275,6 +403,46 @@ Supported chips:
 
               https://www.ti.com/lit/gpn/tmp461
 
+  * Philips NE1617, NE1617A
+
+    Prefix: 'max1617' (probably detected as a max1617)
+
+    Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
+
+    Datasheets: Publicly available at the Philips website
+
+  * Philips NE1618
+
+    Prefix: 'ne1618'
+
+    Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
+
+    Datasheets: Publicly available at the Philips website
+
+  * Genesys Logic GL523SM
+
+    Prefix: 'gl523sm'
+
+    Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
+
+    Datasheet:
+
+  * TI THMC10
+
+    Prefix: 'thmc10'
+
+    Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
+
+    Datasheet: Publicly available at the TI website
+
+  * Onsemi MC1066
+
+    Prefix: 'mc1066'
+
+    Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
+
+    Datasheet: Publicly available at the Onsemi website
+
 Author: Jean Delvare <jdelvare@suse.de>
 
 
@@ -285,6 +453,12 @@ The LM90 is a digital temperature sensor. It senses its own temperature as
 well as the temperature of up to one external diode. It is compatible
 with many other devices, many of which are supported by this driver.
 
+The family of chips supported by this driver is derived from MAX1617.
+This chip as well as various compatible chips support a local and a remote
+temperature sensor with 8 bit accuracy. Later chips provide improved accuracy
+and other additional features such as hysteresis and temperature offset
+registers.
+
 Note that there is no easy way to differentiate between the MAX6657,
 MAX6658 and MAX6659 variants. The extra features of the MAX6659 are only
 supported by this driver if the chip is located at address 0x4d or 0x4e,
@@ -292,15 +466,31 @@ or if the chip type is explicitly selected as max6659.
 The MAX6680 and MAX6681 only differ in their pinout, therefore they obviously
 can't (and don't need to) be distinguished.
 
-The specificity of this family of chipsets over the ADM1021/LM84
-family is that it features critical limits with hysteresis, and an
-increased resolution of the remote temperature measurement.
-
 The different chipsets of the family are not strictly identical, although
 very similar. For reference, here comes a non-exhaustive list of specific
 features:
 
+LM84:
+  * 8 bit sensor resolution
+
+ADM1020, ADM1021, GL523SM, MAX1617, NE1617, NE1617A, THMC10:
+  * 8 bit sensor resolution
+  * Low temperature limits
+
+NCT210, NE1618:
+  * 11 bit sensor resolution for remote temperature sensor
+  * Low temperature limits
+
+ADM1021A, ADM1023:
+  * Temperature offset register for remote temperature sensor
+  * 11 bit resolution for remote temperature sensor
+  * Low temperature limits
+
 LM90:
+  * 11 bit resolution for remote temperature sensor
+  * Temperature offset register for remote temperature sensor
+  * Low and critical temperature limits
+  * Configurable conversion rate
   * Filter and alert configuration register at 0xBF.
   * ALERT is triggered by temperatures over critical limits.
 
@@ -322,8 +512,31 @@ ADM1032:
 ADT7461, ADT7461A, NCT1008:
   * Extended temperature range (breaks compatibility)
   * Lower resolution for remote temperature
+  * SMBus PEC support for Write Byte and Receive Byte transactions.
+  * 10 bit temperature resolution
+
+ADT7481, ADT7482, ADT7483:
+  * Temperature offset register
+  * SMBus PEC support
+  * 10 bit temperature resolution for external sensors
+  * Two remote sensors
+  * Selectable address (ADT7483)
+
+MAX6642:
+  * No critical limit register
+  * Conversion rate not configurable
+  * Better local resolution (10 bit)
+  * 10 bit external sensor resolution
+
+MAX6646, MAX6647, MAX6649:
+  * Better local resolution
+  * Extended range unsigned external temperature
+
+MAX6648, MAX6692:
+  * Better local resolution
+  * Unsigned temperature
 
-MAX6654:
+MAX6654, MAX6690:
   * Better local resolution
   * Selectable address
   * Remote sensor type selection
@@ -423,6 +636,6 @@ two transactions will typically mean twice as much delay waiting for
 transaction completion, effectively doubling the register cache refresh time.
 I guess reliability comes at a price, but it's quite expensive this time.
 
-So, as not everyone might enjoy the slowdown, PEC can be disabled through
-sysfs. Just write 0 to the "pec" file and PEC will be disabled. Write 1
-to that file to enable PEC again.
+So, as not everyone might enjoy the slowdown, PEC is disabled by default and
+can be enabled through sysfs. Just write 1 to the "pec" file and PEC will be
+enabled. Write 0 to that file to disable PEC again.
diff --git a/Documentation/hwmon/lt7182s.rst b/Documentation/hwmon/lt7182s.rst
new file mode 100644 (file)
index 0000000..f726831
--- /dev/null
@@ -0,0 +1,92 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Kernel driver lt7182s
+=====================
+
+Supported chips:
+
+  * ADI LT7182S
+
+    Prefix: 'lt7182s'
+
+    Addresses scanned: -
+
+    Datasheet: https://www.analog.com/en/products/lt7182s.html
+
+Author: Guenter Roeck <linux@roeck-us.net>
+
+
+Description
+-----------
+
+LT7182S is a Dual Channel 6A, 20V PolyPhase Step-Down Silent Switcher with
+Digital Power System Management support.
+
+
+Usage Notes
+-----------
+
+This driver does not probe for PMBus devices. You will have to instantiate
+devices explicitly.
+
+Example: the following commands will load the driver for a LT7182S
+at address 0x4f on I2C bus #4::
+
+    # modprobe lt7182s
+    # echo lt7182s 0x4f > /sys/bus/i2c/devices/i2c-4/new_device
+
+It can also be instantiated by declaring an entry in device tree.
+
+
+Sysfs attributes
+----------------
+
+======================= ====================================
+curr[1-2]_label                "iin[12]"
+curr[1-2]_input                Measured input current
+curr[1-2]_max          Maximum input current
+curr[1-2]_max_alarm    Current high alarm
+
+curr[3-4]_label                "iout[1-2]"
+curr[3-4]_input                Measured output current
+curr[3-4]_highest      Highest measured output current
+curr[3-4]_max          Maximum output current
+curr[3-4]_max_alarm    Output current high alarm
+
+in[1-2]_label          "vin[12]"
+in[1-2]_input          Measured input voltage
+in[1-2]_highest                Highest measured input voltage
+in[1-2]_crit           Critical maximum input voltage
+in[1-2]_crit_alarm     Input voltage critical high alarm
+in[1-2]_min            Minimum input voltage
+in[1-2]_min_alarm      Input voltage low alarm
+in[1-2]_rated_min      Rated minimum input voltage
+in[1-2]_rated_max      Rated maximum input voltage
+in1_reset_history      Write to reset history for all attributes
+
+in[3-5]_label          "vmon[1-3]"
+in[3-5]_input          Measured voltage on ITH1/ITH2/EXTVCC pins
+                       Only available if enabled with MFR_ADC_CONTROL_LT7182S
+                       command.
+
+in[3-4|6-7]_label      "vout[1-2]"
+in[3-4|6-7]_input      Measured output voltage
+in[3-4|6-7]_highest    Highest measured output voltage
+in[3-4|6-7]_lcrit      Critical minimum output voltage
+in[3-4|6-7]_lcrit_alarm        Output voltage critical low alarm
+in[3-4|6-7]_min                Minimum output voltage
+in[3-4|6-7]_max_alarm  Output voltage low alarm
+in[3-4|6-7]_max                Maximum output voltage
+in[3-4|6-7]_max_alarm  Output voltage high alarm
+in[3-4|6-7]_crit       Critical maximum output voltage
+in[3-4|6-7]_crit_alarm Output voltage critical high alarm
+
+power[1-2]_label       "pout[1-2]"
+power[1-2]_input       Measured output power
+
+temp1_input            Measured temperature
+temp1_crit             Critical high temperature
+temp1_crit_alarm       Chip temperature critical high alarm
+temp1_max              Maximum temperature
+temp1_max_alarm                Chip temperature high alarm
+======================= ====================================
index e7e0c9e..84c5a4e 100644 (file)
@@ -121,6 +121,15 @@ Specifically, it provides the following information.
   non-standard PMBus commands to standard commands, or to augment standard
   command return values with device specific information.
 
+PEC Support
+===========
+
+Many PMBus devices support SMBus PEC (Packet Error Checking). If supported
+by both the I2C adapter and by the PMBus chip, it is by default enabled.
+If PEC is supported, the PMBus core driver adds an attribute named 'pec' to
+the I2C device. This attribute can be used to control PEC support in the
+communication with the PMBus chip.
+
 API functions
 =============
 
index 9a218ea..d953ee7 100644 (file)
@@ -12,7 +12,6 @@ increase the chances of your change being accepted.
 * It should be unnecessary to mention, but please read and follow:
 
     - Documentation/process/submit-checklist.rst
-    - Documentation/process/submitting-drivers.rst
     - Documentation/process/submitting-patches.rst
     - Documentation/process/coding-style.rst
 
index b854bb4..6b2bac8 100644 (file)
@@ -129,18 +129,24 @@ yet. Bug reports are always welcome at the issue tracker below!
    * - arm64
      - Supported
      - ``LLVM=1``
+   * - hexagon
+     - Maintained
+     - ``LLVM=1``
    * - mips
      - Maintained
-     - ``CC=clang``
+     - ``LLVM=1``
    * - powerpc
      - Maintained
      - ``CC=clang``
    * - riscv
      - Maintained
-     - ``CC=clang``
+     - ``LLVM=1``
    * - s390
      - Maintained
      - ``CC=clang``
+   * - um (User Mode)
+     - Maintained
+     - ``LLVM=1``
    * - x86
      - Supported
      - ``LLVM=1``
index ebd9d90..9a1f020 100644 (file)
@@ -755,8 +755,7 @@ make a neat patch, there's administrative work to be done:
    it implies a more-than-passing commitment to some part of the code.
 
 -  Finally, don't forget to read
-   ``Documentation/process/submitting-patches.rst`` and possibly
-   ``Documentation/process/submitting-drivers.rst``.
+   ``Documentation/process/submitting-patches.rst``
 
 Kernel Cantrips
 ===============
index dbe9b40..7347638 100644 (file)
@@ -210,11 +210,11 @@ module->symtab.
 =====================================
 Normally, a stripped down copy of a module's symbol table (containing only
 "core" symbols) is made available through module->symtab (See layout_symtab()
-in kernel/module.c). For livepatch modules, the symbol table copied into memory
-on module load must be exactly the same as the symbol table produced when the
-patch module was compiled. This is because the relocations in each livepatch
-relocation section refer to their respective symbols with their symbol indices,
-and the original symbol indices (and thus the symtab ordering) must be
+in kernel/module/kallsyms.c). For livepatch modules, the symbol table copied
+into memory on module load must be exactly the same as the symbol table produced
+when the patch module was compiled. This is because the relocations in each
+livepatch relocation section refer to their respective symbols with their symbol
+indices, and the original symbol indices (and thus the symtab ordering) must be
 preserved in order for apply_relocate_add() to find the right symbol.
 
 For example, take this particular rela from a livepatch module:::
index b12df91..832b5d3 100644 (file)
@@ -1894,6 +1894,7 @@ There are some more advanced barrier functions:
 
  (*) dma_wmb();
  (*) dma_rmb();
+ (*) dma_mb();
 
      These are for use with consistent memory to guarantee the ordering
      of writes or reads of shared memory accessible to both the CPU and a
@@ -1925,11 +1926,11 @@ There are some more advanced barrier functions:
      The dma_rmb() allows us guarantee the device has released ownership
      before we read the data from the descriptor, and the dma_wmb() allows
      us to guarantee the data is written to the descriptor before the device
-     can see it now has ownership.  Note that, when using writel(), a prior
-     wmb() is not needed to guarantee that the cache coherent memory writes
-     have completed before writing to the MMIO region.  The cheaper
-     writel_relaxed() does not provide this guarantee and must not be used
-     here.
+     can see it now has ownership.  The dma_mb() implies both a dma_rmb() and
+     a dma_wmb().  Note that, when using writel(), a prior wmb() is not needed
+     to guarantee that the cache coherent memory writes have completed before
+     writing to the MMIO region.  The cheaper writel_relaxed() does not provide
+     this guarantee and must not be used here.
 
      See the subsection "Kernel I/O barrier effects" for more information on
      relaxed I/O accessors and the Documentation/core-api/dma-api.rst file for
index ed7fa76..d742ba6 100644 (file)
@@ -503,26 +503,108 @@ per-port PHY specific details: interface connection, MDIO bus location, etc.
 Driver development
 ==================
 
-DSA switch drivers need to implement a dsa_switch_ops structure which will
+DSA switch drivers need to implement a ``dsa_switch_ops`` structure which will
 contain the various members described below.
 
-``register_switch_driver()`` registers this dsa_switch_ops in its internal list
-of drivers to probe for. ``unregister_switch_driver()`` does the exact opposite.
+Probing, registration and device lifetime
+-----------------------------------------
 
-Unless requested differently by setting the priv_size member accordingly, DSA
-does not allocate any driver private context space.
+DSA switches are regular ``device`` structures on buses (be they platform, SPI,
+I2C, MDIO or otherwise). The DSA framework is not involved in their probing
+with the device core.
+
+Switch registration from the perspective of a driver means passing a valid
+``struct dsa_switch`` pointer to ``dsa_register_switch()``, usually from the
+switch driver's probing function. The following members must be valid in the
+provided structure:
+
+- ``ds->dev``: will be used to parse the switch's OF node or platform data.
+
+- ``ds->num_ports``: will be used to create the port list for this switch, and
+  to validate the port indices provided in the OF node.
+
+- ``ds->ops``: a pointer to the ``dsa_switch_ops`` structure holding the DSA
+  method implementations.
+
+- ``ds->priv``: backpointer to a driver-private data structure which can be
+  retrieved in all further DSA method callbacks.
+
+In addition, the following flags in the ``dsa_switch`` structure may optionally
+be configured to obtain driver-specific behavior from the DSA core. Their
+behavior when set is documented through comments in ``include/net/dsa.h``.
+
+- ``ds->vlan_filtering_is_global``
+
+- ``ds->needs_standalone_vlan_filtering``
+
+- ``ds->configure_vlan_while_not_filtering``
+
+- ``ds->untag_bridge_pvid``
+
+- ``ds->assisted_learning_on_cpu_port``
+
+- ``ds->mtu_enforcement_ingress``
+
+- ``ds->fdb_isolation``
+
+Internally, DSA keeps an array of switch trees (group of switches) global to
+the kernel, and attaches a ``dsa_switch`` structure to a tree on registration.
+The tree ID to which the switch is attached is determined by the first u32
+number of the ``dsa,member`` property of the switch's OF node (0 if missing).
+The switch ID within the tree is determined by the second u32 number of the
+same OF property (0 if missing). Registering multiple switches with the same
+switch ID and tree ID is illegal and will cause an error. Using platform data,
+a single switch and a single switch tree is permitted.
+
+In case of a tree with multiple switches, probing takes place asymmetrically.
+The first N-1 callers of ``dsa_register_switch()`` only add their ports to the
+port list of the tree (``dst->ports``), each port having a backpointer to its
+associated switch (``dp->ds``). Then, these switches exit their
+``dsa_register_switch()`` call early, because ``dsa_tree_setup_routing_table()``
+has determined that the tree is not yet complete (not all ports referenced by
+DSA links are present in the tree's port list). The tree becomes complete when
+the last switch calls ``dsa_register_switch()``, and this triggers the effective
+continuation of initialization (including the call to ``ds->ops->setup()``) for
+all switches within that tree, all as part of the calling context of the last
+switch's probe function.
+
+The opposite of registration takes place when calling ``dsa_unregister_switch()``,
+which removes a switch's ports from the port list of the tree. The entire tree
+is torn down when the first switch unregisters.
+
+It is mandatory for DSA switch drivers to implement the ``shutdown()`` callback
+of their respective bus, and call ``dsa_switch_shutdown()`` from it (a minimal
+version of the full teardown performed by ``dsa_unregister_switch()``).
+The reason is that DSA keeps a reference on the master net device, and if the
+driver for the master device decides to unbind on shutdown, DSA's reference
+will block that operation from finalizing.
+
+Either ``dsa_switch_shutdown()`` or ``dsa_unregister_switch()`` must be called,
+but not both, and the device driver model permits the bus' ``remove()`` method
+to be called even if ``shutdown()`` was already called. Therefore, drivers are
+expected to implement a mutual exclusion method between ``remove()`` and
+``shutdown()`` by setting their drvdata to NULL after any of these has run, and
+checking whether the drvdata is NULL before proceeding to take any action.
+
+After ``dsa_switch_shutdown()`` or ``dsa_unregister_switch()`` was called, no
+further callbacks via the provided ``dsa_switch_ops`` may take place, and the
+driver may free the data structures associated with the ``dsa_switch``.
 
 Switch configuration
 --------------------
 
-- ``tag_protocol``: this is to indicate what kind of tagging protocol is supported,
-  should be a valid value from the ``dsa_tag_protocol`` enum
+- ``get_tag_protocol``: this is to indicate what kind of tagging protocol is
+  supported, should be a valid value from the ``dsa_tag_protocol`` enum.
+  The returned information does not have to be static; the driver is passed the
+  CPU port number, as well as the tagging protocol of a possibly stacked
+  upstream switch, in case there are hardware limitations in terms of supported
+  tag formats.
 
-- ``probe``: probe routine which will be invoked by the DSA platform device upon
-  registration to test for the presence/absence of a switch device. For MDIO
-  devices, it is recommended to issue a read towards internal registers using
-  the switch pseudo-PHY and return whether this is a supported device. For other
-  buses, return a non-NULL string
+- ``change_tag_protocol``: when the default tagging protocol has compatibility
+  problems with the master or other issues, the driver may support changing it
+  at runtime, either through a device tree property or through sysfs. In that
+  case, further calls to ``get_tag_protocol`` should report the protocol in
+  current use.
 
 - ``setup``: setup function for the switch, this function is responsible for setting
   up the ``dsa_switch_ops`` private structure with all it needs: register maps,
@@ -535,7 +617,17 @@ Switch configuration
   fully configured and ready to serve any kind of request. It is recommended
   to issue a software reset of the switch during this setup function in order to
   avoid relying on what a previous software agent such as a bootloader/firmware
-  may have previously configured.
+  may have previously configured. The method responsible for undoing any
+  applicable allocations or operations done here is ``teardown``.
+
+- ``port_setup`` and ``port_teardown``: methods for initialization and
+  destruction of per-port data structures. It is mandatory for some operations
+  such as registering and unregistering devlink port regions to be done from
+  these methods, otherwise they are optional. A port will be torn down only if
+  it has been previously set up. It is possible for a port to be set up during
+  probing only to be torn down immediately afterwards, for example in case its
+  PHY cannot be found. In this case, probing of the DSA switch continues
+  without that particular port.
 
 PHY devices and link management
 -------------------------------
@@ -635,26 +727,198 @@ Power management
   ``BR_STATE_DISABLED`` and propagating changes to the hardware if this port is
   disabled while being a bridge member
 
+Address databases
+-----------------
+
+Switching hardware is expected to have a table for FDB entries, however not all
+of them are active at the same time. An address database is the subset (partition)
+of FDB entries that is active (can be matched by address learning on RX, or FDB
+lookup on TX) depending on the state of the port. An address database may
+occasionally be called "FID" (Filtering ID) in this document, although the
+underlying implementation may choose whatever is available to the hardware.
+
+For example, all ports that belong to a VLAN-unaware bridge (which is
+*currently* VLAN-unaware) are expected to learn source addresses in the
+database associated by the driver with that bridge (and not with other
+VLAN-unaware bridges). During forwarding and FDB lookup, a packet received on a
+VLAN-unaware bridge port should be able to find a VLAN-unaware FDB entry having
+the same MAC DA as the packet, which is present on another port member of the
+same bridge. At the same time, the FDB lookup process must be able to not find
+an FDB entry having the same MAC DA as the packet, if that entry points towards
+a port which is a member of a different VLAN-unaware bridge (and is therefore
+associated with a different address database).
+
+Similarly, each VLAN of each offloaded VLAN-aware bridge should have an
+associated address database, which is shared by all ports which are members of
+that VLAN, but not shared by ports belonging to different bridges that are
+members of the same VID.
+
+In this context, a VLAN-unaware database means that all packets are expected to
+match on it irrespective of VLAN ID (only MAC address lookup), whereas a
+VLAN-aware database means that packets are supposed to match based on the VLAN
+ID from the classified 802.1Q header (or the pvid if untagged).
+
+At the bridge layer, VLAN-unaware FDB entries have the special VID value of 0,
+whereas VLAN-aware FDB entries have non-zero VID values. Note that a
+VLAN-unaware bridge may have VLAN-aware (non-zero VID) FDB entries, and a
+VLAN-aware bridge may have VLAN-unaware FDB entries. As in hardware, the
+software bridge keeps separate address databases, and offloads to hardware the
+FDB entries belonging to these databases, through switchdev, asynchronously
+relative to the moment when the databases become active or inactive.
+
+When a user port operates in standalone mode, its driver should configure it to
+use a separate database called a port private database. This is different from
+the databases described above, and should impede operation as standalone port
+(packet in, packet out to the CPU port) as little as possible. For example,
+on ingress, it should not attempt to learn the MAC SA of ingress traffic, since
+learning is a bridging layer service and this is a standalone port, therefore
+it would consume useless space. With no address learning, the port private
+database should be empty in a naive implementation, and in this case, all
+received packets should be trivially flooded to the CPU port.
+
+DSA (cascade) and CPU ports are also called "shared" ports because they service
+multiple address databases, and the database that a packet should be associated
+to is usually embedded in the DSA tag. This means that the CPU port may
+simultaneously transport packets coming from a standalone port (which were
+classified by hardware in one address database), and from a bridge port (which
+were classified to a different address database).
+
+Switch drivers which satisfy certain criteria are able to optimize the naive
+configuration by removing the CPU port from the flooding domain of the switch,
+and just program the hardware with FDB entries pointing towards the CPU port
+for which it is known that software is interested in those MAC addresses.
+Packets which do not match a known FDB entry will not be delivered to the CPU,
+which will save CPU cycles required for creating an skb just to drop it.
+
+DSA is able to perform host address filtering for the following kinds of
+addresses:
+
+- Primary unicast MAC addresses of ports (``dev->dev_addr``). These are
+  associated with the port private database of the respective user port,
+  and the driver is notified to install them through ``port_fdb_add`` towards
+  the CPU port.
+
+- Secondary unicast and multicast MAC addresses of ports (addresses added
+  through ``dev_uc_add()`` and ``dev_mc_add()``). These are also associated
+  with the port private database of the respective user port.
+
+- Local/permanent bridge FDB entries (``BR_FDB_LOCAL``). These are the MAC
+  addresses of the bridge ports, for which packets must be terminated locally
+  and not forwarded. They are associated with the address database for that
+  bridge.
+
+- Static bridge FDB entries installed towards foreign (non-DSA) interfaces
+  present in the same bridge as some DSA switch ports. These are also
+  associated with the address database for that bridge.
+
+- Dynamically learned FDB entries on foreign interfaces present in the same
+  bridge as some DSA switch ports, only if ``ds->assisted_learning_on_cpu_port``
+  is set to true by the driver. These are associated with the address database
+  for that bridge.
+
+For various operations detailed below, DSA provides a ``dsa_db`` structure
+which can be of the following types:
+
+- ``DSA_DB_PORT``: the FDB (or MDB) entry to be installed or deleted belongs to
+  the port private database of user port ``db->dp``.
+- ``DSA_DB_BRIDGE``: the entry belongs to one of the address databases of bridge
+  ``db->bridge``. Separation between the VLAN-unaware database and the per-VID
+  databases of this bridge is expected to be done by the driver.
+- ``DSA_DB_LAG``: the entry belongs to the address database of LAG ``db->lag``.
+  Note: ``DSA_DB_LAG`` is currently unused and may be removed in the future.
+
+The drivers which act upon the ``dsa_db`` argument in ``port_fdb_add``,
+``port_mdb_add`` etc should declare ``ds->fdb_isolation`` as true.
+
+DSA associates each offloaded bridge and each offloaded LAG with a one-based ID
+(``struct dsa_bridge :: num``, ``struct dsa_lag :: id``) for the purposes of
+refcounting addresses on shared ports. Drivers may piggyback on DSA's numbering
+scheme (the ID is readable through ``db->bridge.num`` and ``db->lag.id`` or may
+implement their own.
+
+Only the drivers which declare support for FDB isolation are notified of FDB
+entries on the CPU port belonging to ``DSA_DB_PORT`` databases.
+For compatibility/legacy reasons, ``DSA_DB_BRIDGE`` addresses are notified to
+drivers even if they do not support FDB isolation. However, ``db->bridge.num``
+and ``db->lag.id`` are always set to 0 in that case (to denote the lack of
+isolation, for refcounting purposes).
+
+Note that it is not mandatory for a switch driver to implement physically
+separate address databases for each standalone user port. Since FDB entries in
+the port private databases will always point to the CPU port, there is no risk
+for incorrect forwarding decisions. In this case, all standalone ports may
+share the same database, but the reference counting of host-filtered addresses
+(not deleting the FDB entry for a port's MAC address if it's still in use by
+another port) becomes the responsibility of the driver, because DSA is unaware
+that the port databases are in fact shared. This can be achieved by calling
+``dsa_fdb_present_in_other_db()`` and ``dsa_mdb_present_in_other_db()``.
+The down side is that the RX filtering lists of each user port are in fact
+shared, which means that user port A may accept a packet with a MAC DA it
+shouldn't have, only because that MAC address was in the RX filtering list of
+user port B. These packets will still be dropped in software, however.
+
 Bridge layer
 ------------
 
+Offloading the bridge forwarding plane is optional and handled by the methods
+below. They may be absent, return -EOPNOTSUPP, or ``ds->max_num_bridges`` may
+be non-zero and exceeded, and in this case, joining a bridge port is still
+possible, but the packet forwarding will take place in software, and the ports
+under a software bridge must remain configured in the same way as for
+standalone operation, i.e. have all bridging service functions (address
+learning etc) disabled, and send all received packets to the CPU port only.
+
+Concretely, a port starts offloading the forwarding plane of a bridge once it
+returns success to the ``port_bridge_join`` method, and stops doing so after
+``port_bridge_leave`` has been called. Offloading the bridge means autonomously
+learning FDB entries in accordance with the software bridge port's state, and
+autonomously forwarding (or flooding) received packets without CPU intervention.
+This is optional even when offloading a bridge port. Tagging protocol drivers
+are expected to call ``dsa_default_offload_fwd_mark(skb)`` for packets which
+have already been autonomously forwarded in the forwarding domain of the
+ingress switch port. DSA, through ``dsa_port_devlink_setup()``, considers all
+switch ports part of the same tree ID to be part of the same bridge forwarding
+domain (capable of autonomous forwarding to each other).
+
+Offloading the TX forwarding process of a bridge is a distinct concept from
+simply offloading its forwarding plane, and refers to the ability of certain
+driver and tag protocol combinations to transmit a single skb coming from the
+bridge device's transmit function to potentially multiple egress ports (and
+thereby avoid its cloning in software).
+
+Packets for which the bridge requests this behavior are called data plane
+packets and have ``skb->offload_fwd_mark`` set to true in the tag protocol
+driver's ``xmit`` function. Data plane packets are subject to FDB lookup,
+hardware learning on the CPU port, and do not override the port STP state.
+Additionally, replication of data plane packets (multicast, flooding) is
+handled in hardware and the bridge driver will transmit a single skb for each
+packet that may or may not need replication.
+
+When the TX forwarding offload is enabled, the tag protocol driver is
+responsible to inject packets into the data plane of the hardware towards the
+correct bridging domain (FID) that the port is a part of. The port may be
+VLAN-unaware, and in this case the FID must be equal to the FID used by the
+driver for its VLAN-unaware address database associated with that bridge.
+Alternatively, the bridge may be VLAN-aware, and in that case, it is guaranteed
+that the packet is also VLAN-tagged with the VLAN ID that the bridge processed
+this packet in. It is the responsibility of the hardware to untag the VID on
+the egress-untagged ports, or keep the tag on the egress-tagged ones.
+
 - ``port_bridge_join``: bridge layer function invoked when a given switch port is
   added to a bridge, this function should do what's necessary at the switch
   level to permit the joining port to be added to the relevant logical
   domain for it to ingress/egress traffic with other members of the bridge.
+  By setting the ``tx_fwd_offload`` argument to true, the TX forwarding process
+  of this bridge is also offloaded.
 
 - ``port_bridge_leave``: bridge layer function invoked when a given switch port is
   removed from a bridge, this function should do what's necessary at the
   switch level to deny the leaving port from ingress/egress traffic from the
-  remaining bridge members. When the port leaves the bridge, it should be aged
-  out at the switch hardware for the switch to (re) learn MAC addresses behind
-  this port.
+  remaining bridge members.
 
 - ``port_stp_state_set``: bridge layer function invoked when a given switch port STP
   state is computed by the bridge layer and should be propagated to switch
-  hardware to forward/block/learn traffic. The switch driver is responsible for
-  computing a STP state change based on current and asked parameters and perform
-  the relevant ageing based on the intersection results
+  hardware to forward/block/learn traffic.
 
 - ``port_bridge_flags``: bridge layer function invoked when a port must
   configure its settings for e.g. flooding of unknown traffic or source address
@@ -667,21 +931,11 @@ Bridge layer
   CPU port, and flooding towards the CPU port should also be enabled, due to a
   lack of an explicit address filtering mechanism in the DSA core.
 
-- ``port_bridge_tx_fwd_offload``: bridge layer function invoked after
-  ``port_bridge_join`` when a driver sets ``ds->num_fwd_offloading_bridges`` to
-  a non-zero value. Returning success in this function activates the TX
-  forwarding offload bridge feature for this port, which enables the tagging
-  protocol driver to inject data plane packets towards the bridging domain that
-  the port is a part of. Data plane packets are subject to FDB lookup, hardware
-  learning on the CPU port, and do not override the port STP state.
-  Additionally, replication of data plane packets (multicast, flooding) is
-  handled in hardware and the bridge driver will transmit a single skb for each
-  packet that needs replication. The method is provided as a configuration
-  point for drivers that need to configure the hardware for enabling this
-  feature.
-
-- ``port_bridge_tx_fwd_unoffload``: bridge layer function invoked when a driver
-  leaves a bridge port which had the TX forwarding offload feature enabled.
+- ``port_fast_age``: bridge layer function invoked when flushing the
+  dynamically learned FDB entries on the port is necessary. This is called when
+  transitioning from an STP state where learning should take place to an STP
+  state where it shouldn't, or when leaving a bridge, or when address learning
+  is turned off via ``port_bridge_flags``.
 
 Bridge VLAN filtering
 ---------------------
@@ -697,55 +951,44 @@ Bridge VLAN filtering
   allowed.
 
 - ``port_vlan_add``: bridge layer function invoked when a VLAN is configured
-  (tagged or untagged) for the given switch port. If the operation is not
-  supported by the hardware, this function should return ``-EOPNOTSUPP`` to
-  inform the bridge code to fallback to a software implementation.
+  (tagged or untagged) for the given switch port. The CPU port becomes a member
+  of a VLAN only if a foreign bridge port is also a member of it (and
+  forwarding needs to take place in software), or the VLAN is installed to the
+  VLAN group of the bridge device itself, for termination purposes
+  (``bridge vlan add dev br0 vid 100 self``). VLANs on shared ports are
+  reference counted and removed when there is no user left. Drivers do not need
+  to manually install a VLAN on the CPU port.
 
 - ``port_vlan_del``: bridge layer function invoked when a VLAN is removed from the
   given switch port
 
-- ``port_vlan_dump``: bridge layer function invoked with a switchdev callback
-  function that the driver has to call for each VLAN the given port is a member
-  of. A switchdev object is used to carry the VID and bridge flags.
-
 - ``port_fdb_add``: bridge layer function invoked when the bridge wants to install a
   Forwarding Database entry, the switch hardware should be programmed with the
   specified address in the specified VLAN Id in the forwarding database
-  associated with this VLAN ID. If the operation is not supported, this
-  function should return ``-EOPNOTSUPP`` to inform the bridge code to fallback to
-  a software implementation.
-
-.. note:: VLAN ID 0 corresponds to the port private database, which, in the context
-        of DSA, would be its port-based VLAN, used by the associated bridge device.
+  associated with this VLAN ID.
 
 - ``port_fdb_del``: bridge layer function invoked when the bridge wants to remove a
   Forwarding Database entry, the switch hardware should be programmed to delete
   the specified MAC address from the specified VLAN ID if it was mapped into
   this port forwarding database
 
-- ``port_fdb_dump``: bridge layer function invoked with a switchdev callback
-  function that the driver has to call for each MAC address known to be behind
-  the given port. A switchdev object is used to carry the VID and FDB info.
+- ``port_fdb_dump``: bridge bypass function invoked by ``ndo_fdb_dump`` on the
+  physical DSA port interfaces. Since DSA does not attempt to keep in sync its
+  hardware FDB entries with the software bridge, this method is implemented as
+  a means to view the entries visible on user ports in the hardware database.
+  The entries reported by this function have the ``self`` flag in the output of
+  the ``bridge fdb show`` command.
 
 - ``port_mdb_add``: bridge layer function invoked when the bridge wants to install
-  a multicast database entry. If the operation is not supported, this function
-  should return ``-EOPNOTSUPP`` to inform the bridge code to fallback to a
-  software implementation. The switch hardware should be programmed with the
+  a multicast database entry. The switch hardware should be programmed with the
   specified address in the specified VLAN ID in the forwarding database
   associated with this VLAN ID.
 
-.. note:: VLAN ID 0 corresponds to the port private database, which, in the context
-        of DSA, would be its port-based VLAN, used by the associated bridge device.
-
 - ``port_mdb_del``: bridge layer function invoked when the bridge wants to remove a
   multicast database entry, the switch hardware should be programmed to delete
   the specified MAC address from the specified VLAN ID if it was mapped into
   this port forwarding database.
 
-- ``port_mdb_dump``: bridge layer function invoked with a switchdev callback
-  function that the driver has to call for each MAC address known to be behind
-  the given port. A switchdev object is used to carry the VID and MDB info.
-
 Link aggregation
 ----------------
 
index 9f41961..d7a1bf1 100644 (file)
@@ -1052,11 +1052,7 @@ udp_rmem_min - INTEGER
        Default: 4K
 
 udp_wmem_min - INTEGER
-       Minimal size of send buffer used by UDP sockets in moderation.
-       Each UDP socket is able to use the size for sending data, even if
-       total pages of UDP sockets exceed udp_mem pressure. The unit is byte.
-
-       Default: 4K
+       UDP does not have tx memory accounting and this tunable has no effect.
 
 RAW variables
 =============
@@ -1085,7 +1081,7 @@ cipso_cache_enable - BOOLEAN
 cipso_cache_bucket_size - INTEGER
        The CIPSO label cache consists of a fixed size hash table with each
        hash bucket containing a number of cache entries.  This variable limits
-       the number of entries in each hash bucket; the larger the value the
+       the number of entries in each hash bucket; the larger the value is, the
        more CIPSO label mappings that can be cached.  When the number of
        entries in a given hash bucket reaches this limit adding new entries
        causes the oldest entry in the bucket to be removed to make room.
@@ -1179,7 +1175,7 @@ ip_autobind_reuse - BOOLEAN
        option should only be set by experts.
        Default: 0
 
-ip_dynaddr - BOOLEAN
+ip_dynaddr - INTEGER
        If set non-zero, enables support for dynamic addresses.
        If set to a non-zero value larger than 1, a kernel log
        message will be printed when dynamic address rewriting
@@ -2870,7 +2866,14 @@ sctp_rmem - vector of 3 INTEGERs: min, default, max
        Default: 4K
 
 sctp_wmem  - vector of 3 INTEGERs: min, default, max
-       Currently this tunable has no effect.
+       Only the first value ("min") is used, "default" and "max" are
+       ignored.
+
+       min: Minimum size of send buffer that can be used by SCTP sockets.
+       It is guaranteed to each SCTP socket (but not association) even
+       under moderate memory pressure.
+
+       Default: 4K
 
 addr_scope_policy - INTEGER
        Control IPv4 address scoping - draft-stewart-tsvwg-sctp-ipv4-00
index feb257b..ef341be 100644 (file)
@@ -20,20 +20,20 @@ possible source of information on its own, the EM framework intervenes as an
 abstraction layer which standardizes the format of power cost tables in the
 kernel, hence enabling to avoid redundant work.
 
-The power values might be expressed in milli-Watts or in an 'abstract scale'.
+The power values might be expressed in micro-Watts or in an 'abstract scale'.
 Multiple subsystems might use the EM and it is up to the system integrator to
 check that the requirements for the power value scale types are met. An example
 can be found in the Energy-Aware Scheduler documentation
 Documentation/scheduler/sched-energy.rst. For some subsystems like thermal or
 powercap power values expressed in an 'abstract scale' might cause issues.
 These subsystems are more interested in estimation of power used in the past,
-thus the real milli-Watts might be needed. An example of these requirements can
+thus the real micro-Watts might be needed. An example of these requirements can
 be found in the Intelligent Power Allocation in
 Documentation/driver-api/thermal/power_allocator.rst.
 Kernel subsystems might implement automatic detection to check whether EM
 registered devices have inconsistent scale (based on EM internal flag).
 Important thing to keep in mind is that when the power values are expressed in
-an 'abstract scale' deriving real energy in milli-Joules would not be possible.
+an 'abstract scale' deriving real energy in micro-Joules would not be possible.
 
 The figure below depicts an example of drivers (Arm-specific here, but the
 approach is applicable to any architecture) providing power costs to the EM
@@ -98,7 +98,7 @@ Drivers are expected to register performance domains into the EM framework by
 calling the following API::
 
   int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
-               struct em_data_callback *cb, cpumask_t *cpus, bool milliwatts);
+               struct em_data_callback *cb, cpumask_t *cpus, bool microwatts);
 
 Drivers must provide a callback function returning <frequency, power> tuples
 for each performance state. The callback function provided by the driver is free
@@ -106,10 +106,10 @@ to fetch data from any relevant location (DT, firmware, ...), and by any mean
 deemed necessary. Only for CPU devices, drivers must specify the CPUs of the
 performance domains using cpumask. For other devices than CPUs the last
 argument must be set to NULL.
-The last argument 'milliwatts' is important to set with correct value. Kernel
+The last argument 'microwatts' is important to set with correct value. Kernel
 subsystems which use EM might rely on this flag to check if all EM devices use
 the same scale. If there are different scales, these subsystems might decide
-to: return warning/error, stop working or panic.
+to return warning/error, stop working or panic.
 See Section 3. for an example of driver implementing this
 callback, or Section 2.4 for further documentation on this API
 
@@ -137,7 +137,7 @@ The .get_cost() allows to provide the 'cost' values which reflect the
 efficiency of the CPUs. This would allow to provide EAS information which
 has different relation than what would be forced by the EM internal
 formulas calculating 'cost' values. To register an EM for such platform, the
-driver must set the flag 'milliwatts' to 0, provide .get_power() callback
+driver must set the flag 'microwatts' to 0, provide .get_power() callback
 and provide .get_cost() callback. The EM framework would handle such platform
 properly during registration. A flag EM_PERF_DOMAIN_ARTIFICIAL is set for such
 platform. Special care should be taken by other frameworks which are using EM
index b04fb18..a125544 100644 (file)
@@ -315,7 +315,7 @@ that these callbacks operate on::
                                           configuration space */
        unsigned int    pme_support:5;  /* Bitmask of states from which PME#
                                           can be generated */
-       unsigned int    pme_interrupt:1;/* Is native PCIe PME signaling used? */
+       unsigned int    pme_poll:1;     /* Poll device's PME status bit */
        unsigned int    d1_support:1;   /* Low power state D1 is supported */
        unsigned int    d2_support:1;   /* Low power state D2 is supported */
        unsigned int    no_d1d2:1;      /* D1 and D2 are forbidden */
index bd36ecb..906235c 100644 (file)
@@ -10,8 +10,7 @@ of conventions and procedures which are used in the posting of patches;
 following them will make life much easier for everybody involved.  This
 document will attempt to cover these expectations in reasonable detail;
 more information can also be found in the files
-:ref:`Documentation/process/submitting-patches.rst <submittingpatches>`,
-:ref:`Documentation/process/submitting-drivers.rst  <submittingdrivers>`
+:ref:`Documentation/process/submitting-patches.rst <submittingpatches>`
 and :ref:`Documentation/process/submit-checklist.rst <submitchecklist>`.
 
 
index b32a402..8c847df 100644 (file)
@@ -5,15 +5,13 @@ For more information
 
 There are numerous sources of information on Linux kernel development and
 related topics.  First among those will always be the Documentation
-directory found in the kernel source distribution.  The top-level :ref:`process/howto.rst <process_howto>`
-file is an important starting point; :ref:`process/submitting-patches.rst <submittingpatches>`
-and :ref:`process/submitting-drivers.rst  <submittingdrivers>`
-are also something which all kernel developers should
-read.  Many internal kernel APIs are documented using the kerneldoc
-mechanism; "make htmldocs" or "make pdfdocs" can be used to generate those
-documents in HTML or PDF format (though the version of TeX shipped by some
-distributions runs into internal limits and fails to process the documents
-properly).
+directory found in the kernel source distribution.  Start with the
+top-level :ref:`process/howto.rst <process_howto>`; also read
+:ref:`process/submitting-patches.rst <submittingpatches>`. Many internal
+kernel APIs are documented using the kerneldoc mechanism; "make htmldocs"
+or "make pdfdocs" can be used to generate those documents in HTML or PDF
+format (though the version of TeX shipped by some distributions runs into
+internal limits and fails to process the documents properly).
 
 Various web sites discuss kernel development at all levels of detail.  Your
 author would like to humbly suggest https://lwn.net/ as a source;
index 16586f6..fc2c46f 100644 (file)
@@ -277,36 +277,61 @@ Thunderbird (GUI)
 Thunderbird is an Outlook clone that likes to mangle text, but there are ways
 to coerce it into behaving.
 
+After doing the modifications, this includes installing the extensions,
+you need to restart Thunderbird.
+
 - Allow use of an external editor:
-  The easiest thing to do with Thunderbird and patches is to use an
-  "external editor" extension and then just use your favorite ``$EDITOR``
-  for reading/merging patches into the body text.  To do this, download
-  and install the extension, then add a button for it using
-  :menuselection:`View-->Toolbars-->Customize...` and finally just click on it
-  when in the :menuselection:`Compose` dialog.
-
-  Please note that "external editor" requires that your editor must not
-  fork, or in other words, the editor must not return before closing.
-  You may have to pass additional flags or change the settings of your
-  editor. Most notably if you are using gvim then you must pass the -f
-  option to gvim by putting ``/usr/bin/gvim -f`` (if the binary is in
-  ``/usr/bin``) to the text editor field in :menuselection:`external editor`
-  settings. If you are using some other editor then please read its manual
-  to find out how to do this.
+
+  The easiest thing to do with Thunderbird and patches is to use extensions
+  which open your favorite external editor.
+
+  Here are some example extensions which are capable of doing this.
+
+  - "External Editor Revived"
+
+    https://github.com/Frederick888/external-editor-revived
+
+    https://addons.thunderbird.net/en-GB/thunderbird/addon/external-editor-revived/
+
+    It requires installing a "native messaging host".
+    Please read the wiki which can be found here:
+    https://github.com/Frederick888/external-editor-revived/wiki
+
+  - "External Editor"
+
+    https://github.com/exteditor/exteditor
+
+    To do this, download and install the extension, then open the
+    :menuselection:`compose` window, add a button for it using
+    :menuselection:`View-->Toolbars-->Customize...`
+    then just click on the new button when you wish to use the external editor.
+
+    Please note that "External Editor" requires that your editor must not
+    fork, or in other words, the editor must not return before closing.
+    You may have to pass additional flags or change the settings of your
+    editor. Most notably if you are using gvim then you must pass the -f
+    option to gvim by putting ``/usr/bin/gvim --nofork"`` (if the binary is in
+    ``/usr/bin``) to the text editor field in :menuselection:`external editor`
+    settings. If you are using some other editor then please read its manual
+    to find out how to do this.
 
 To beat some sense out of the internal editor, do this:
 
-- Edit your Thunderbird config settings so that it won't use ``format=flowed``.
-  Go to :menuselection:`edit-->preferences-->advanced-->config editor` to bring up
-  the thunderbird's registry editor.
+- Edit your Thunderbird config settings so that it won't use ``format=flowed``!
+  Go to your main window and find the button for your main dropdown menu.
+  :menuselection:`Main Menu-->Preferences-->General-->Config Editor...`
+  to bring up the thunderbird's registry editor.
 
-- Set ``mailnews.send_plaintext_flowed`` to ``false``
+  - Set ``mailnews.send_plaintext_flowed`` to ``false``
 
-- Set ``mailnews.wraplength`` from ``72`` to ``0``
+  - Set ``mailnews.wraplength`` from ``72`` to ``0``
 
-- :menuselection:`View-->Message Body As-->Plain Text`
+- Don't write HTML messages! Go to the main window
+  :menuselection:`Main Menu-->Account Settings-->youracc@server.something-->Composition & Addressing`!
+  There you can disable the option "Compose messages in HTML format".
 
-- :menuselection:`View-->Character Encoding-->Unicode (UTF-8)`
+- Open messages only as plain text! Go to the main window
+  :menuselection:`Main Menu-->View-->Message Body As-->Plain Text`!
 
 TkRat (GUI)
 ***********
index e4beeca..cd6997a 100644 (file)
@@ -105,8 +105,8 @@ required reading:
     patches if these rules are followed, and many people will only
     review code if it is in the proper style.
 
-  :ref:`Documentation/process/submitting-patches.rst <submittingpatches>` and :ref:`Documentation/process/submitting-drivers.rst <submittingdrivers>`
-    These files describe in explicit detail how to successfully create
+  :ref:`Documentation/process/submitting-patches.rst <submittingpatches>`
+    This file describes in explicit detail how to successfully create
     and send a patch, including (but not limited to):
 
        - Email contents
index 3587dae..2ba2a15 100644 (file)
@@ -40,7 +40,6 @@ Other guides to the community that are of interest to most developers are:
    :maxdepth: 1
 
    changes
-   submitting-drivers
    stable-api-nonsense
    management-style
    stable-kernel-rules
index da95275..502289d 100644 (file)
@@ -1,9 +1,10 @@
 .. _kernel_docs:
 
-Index of Documentation for People Interested in Writing and/or Understanding the Linux Kernel
-=============================================================================================
+Index of Further Kernel Documentation
+=====================================
 
-          Juan-Mariano de Goyeneche <jmseyas@dit.upm.es>
+Initial Author: Juan-Mariano de Goyeneche (<jmseyas@dit.upm.es>;
+email address is defunct now.)
 
 The need for a document like this one became apparent in the
 linux-kernel mailing list as the same questions, asking for pointers
@@ -16,21 +17,16 @@ philosophy and design decisions behind this code.
 
 Unfortunately, not many documents are available for beginners to
 start. And, even if they exist, there was no "well-known" place which
-kept track of them. These lines try to cover this lack. All documents
-available on line known by the author are listed, while some reference
-books are also mentioned.
+kept track of them. These lines try to cover this lack.
 
 PLEASE, if you know any paper not listed here or write a new document,
-send me an e-mail, and I'll include a reference to it here. Any
-corrections, ideas or comments are also welcomed.
+include a reference to it here, following the kernel's patch submission
+process. Any corrections, ideas or comments are also welcome.
 
-The papers that follow are listed in no particular order. All are
-cataloged with the following fields: the document's "Title", the
-"Author"/s, the "URL" where they can be found, some "Keywords" helpful
-when searching for specific topics, and a brief "Description" of the
-Document.
-
-Enjoy!
+All documents are cataloged with the following fields: the document's
+"Title", the "Author"/s, the "URL" where they can be found, some
+"Keywords" helpful when searching for specific topics, and a brief
+"Description" of the Document.
 
 .. note::
 
@@ -83,6 +79,18 @@ On-line docs
         Finally this trace-log is used as base for more a exact conceptual
         exploration and description of the Linux TCP/IP implementation.*
 
+    * Title: **The Linux Kernel Module Programming Guide**
+
+      :Author: Peter Jay Salzman, Michael Burian, Ori Pomerantz, Bob Mottram,
+        Jim Huang.
+      :URL: https://sysprog21.github.io/lkmpg/
+      :Date: 2021
+      :Keywords: modules, GPL book, /proc, ioctls, system calls,
+        interrupt handlers .
+      :Description: A very nice GPL book on the topic of modules
+        programming. Lots of examples. Currently the new version is being
+        actively maintained at https://github.com/sysprog21/lkmpg.
+
     * Title: **On submitting kernel Patches**
 
       :Author: Andi Kleen
@@ -126,17 +134,19 @@ On-line docs
         describes how to write user-mode utilities for communicating with
         Card Services.
 
-    * Title: **The Linux Kernel Module Programming Guide**
-
-      :Author: Peter Jay Salzman, Michael Burian, Ori Pomerantz, Bob Mottram,
-        Jim Huang.
-      :URL: https://sysprog21.github.io/lkmpg/
-      :Date: 2021
-      :Keywords: modules, GPL book, /proc, ioctls, system calls,
-        interrupt handlers .
-      :Description: A very nice GPL book on the topic of modules
-        programming. Lots of examples. Currently the new version is being
-        actively maintained at https://github.com/sysprog21/lkmpg.
+    * Title: **How NOT to write kernel drivers**
+
+      :Author: Arjan van de Ven.
+      :URL: https://landley.net/kdocs/ols/2002/ols2002-pages-545-555.pdf
+      :Date: 2002
+      :Keywords: driver.
+      :Description: Programming bugs and Do-nots in kernel driver development
+      :Abstract: *Quit a few tutorials, articles and books give an introduction
+        on how to write Linux kernel drivers. Unfortunately the things one
+        should NOT do in Linux kernel code is either only a minor appendix
+        or, more commonly, completely absent. This paper tries to briefly touch
+        the areas in which the most common and serious bugs and do-nots are
+        encountered.*
 
     * Title: **Global spinlock list and usage**
 
index c456b52..d140070 100644 (file)
@@ -6,6 +6,15 @@
 netdev FAQ
 ==========
 
+tl;dr
+-----
+
+ - designate your patch to a tree - ``[PATCH net]`` or ``[PATCH net-next]``
+ - for fixes the ``Fixes:`` tag is required, regardless of the tree
+ - don't post large series (> 15 patches), break them up
+ - don't repost your patches within one 24h period
+ - reverse xmas tree
+
 What is netdev?
 ---------------
 It is a mailing list for all network-related Linux stuff.  This
@@ -136,6 +145,20 @@ it to the maintainer to figure out what is the most recent and current
 version that should be applied. If there is any doubt, the maintainer
 will reply and ask what should be done.
 
+How do I divide my work into patches?
+-------------------------------------
+
+Put yourself in the shoes of the reviewer. Each patch is read separately
+and therefore should constitute a comprehensible step towards your stated
+goal.
+
+Avoid sending series longer than 15 patches. Larger series takes longer
+to review as reviewers will defer looking at it until they find a large
+chunk of time. A small series can be reviewed in a short time, so Maintainers
+just do it. As a result, a sequence of smaller series gets merged quicker and
+with better review coverage. Re-posting large series also increases the mailing
+list traffic.
+
 I made changes to only a few patches in a patch series should I resend only those changed?
 ------------------------------------------------------------------------------------------
 No, please resend the entire patch series and make sure you do number your
@@ -183,6 +206,19 @@ it is requested that you make it look like this::
    * another line of text
    */
 
+What is "reverse xmas tree"?
+----------------------------
+
+Netdev has a convention for ordering local variables in functions.
+Order the variable declaration lines longest to shortest, e.g.::
+
+  struct scatterlist *sg;
+  struct sk_buff *skb;
+  int err, i;
+
+If there are dependencies between the variables preventing the ordering
+move the initialization out of line.
+
 I am working in existing code which uses non-standard formatting. Which formatting should I use?
 ------------------------------------------------------------------------------------------------
 Make your code follow the most recent guidelines, so that eventually all code
diff --git a/Documentation/process/submitting-drivers.rst b/Documentation/process/submitting-drivers.rst
deleted file mode 100644 (file)
index 8413b69..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-.. _submittingdrivers:
-
-Submitting Drivers For The Linux Kernel
-=======================================
-
-This document is intended to explain how to submit device drivers to the
-various kernel trees. Note that if you are interested in video card drivers
-you should probably talk to XFree86 (https://www.xfree86.org/) and/or X.Org
-(https://x.org/) instead.
-
-.. note::
-
-   This document is old and has seen little maintenance in recent years; it
-   should probably be updated or, perhaps better, just deleted.  Most of
-   what is here can be found in the other development documents anyway.
-
-   Oh, and we don't really recommend submitting changes to XFree86 :)
-
-Also read the :ref:`Documentation/process/submitting-patches.rst <submittingpatches>`
-document.
-
-
-Allocating Device Numbers
--------------------------
-
-Major and minor numbers for block and character devices are allocated
-by the Linux assigned name and number authority (currently this is
-Torben Mathiasen). The site is https://www.lanana.org/. This
-also deals with allocating numbers for devices that are not going to
-be submitted to the mainstream kernel.
-See :ref:`Documentation/admin-guide/devices.rst <admin_devices>`
-for more information on this.
-
-If you don't use assigned numbers then when your device is submitted it will
-be given an assigned number even if that is different from values you may
-have shipped to customers before.
-
-Who To Submit Drivers To
-------------------------
-
-Linux 2.0:
-       No new drivers are accepted for this kernel tree.
-
-Linux 2.2:
-       No new drivers are accepted for this kernel tree.
-
-Linux 2.4:
-       If the code area has a general maintainer then please submit it to
-       the maintainer listed in MAINTAINERS in the kernel file. If the
-       maintainer does not respond or you cannot find the appropriate
-       maintainer then please contact Willy Tarreau <w@1wt.eu>.
-
-Linux 2.6 and upper:
-       The same rules apply as 2.4 except that you should follow linux-kernel
-       to track changes in API's. The final contact point for Linux 2.6+
-       submissions is Andrew Morton.
-
-What Criteria Determine Acceptance
-----------------------------------
-
-Licensing:
-               The code must be released to us under the
-               GNU General Public License. If you wish the driver to be
-               useful to other communities such as BSD you may release
-               under multiple licenses. If you choose to release under
-               licenses other than the GPL, you should include your
-               rationale for your license choices in your cover letter.
-               See accepted licenses at include/linux/module.h
-
-Copyright:
-               The copyright owner must agree to use of GPL.
-               It's best if the submitter and copyright owner
-               are the same person/entity. If not, the name of
-               the person/entity authorizing use of GPL should be
-               listed in case it's necessary to verify the will of
-               the copyright owner.
-
-Interfaces:
-               If your driver uses existing interfaces and behaves like
-               other drivers in the same class it will be much more likely
-               to be accepted than if it invents gratuitous new ones.
-               If you need to implement a common API over Linux and NT
-               drivers do it in userspace.
-
-Code:
-               Please use the Linux style of code formatting as documented
-               in :ref:`Documentation/process/coding-style.rst <codingStyle>`.
-               If you have sections of code
-               that need to be in other formats, for example because they
-               are shared with a windows driver kit and you want to
-               maintain them just once separate them out nicely and note
-               this fact.
-
-Portability:
-               Pointers are not always 32bits, not all computers are little
-               endian, people do not all have floating point and you
-               shouldn't use inline x86 assembler in your driver without
-               careful thought. Pure x86 drivers generally are not popular.
-               If you only have x86 hardware it is hard to test portability
-               but it is easy to make sure the code can easily be made
-               portable.
-
-Clarity:
-               It helps if anyone can see how to fix the driver. It helps
-               you because you get patches not bug reports. If you submit a
-               driver that intentionally obfuscates how the hardware works
-               it will go in the bitbucket.
-
-PM support:
-               Since Linux is used on many portable and desktop systems, your
-               driver is likely to be used on such a system and therefore it
-               should support basic power management by implementing, if
-               necessary, the .suspend and .resume methods used during the
-               system-wide suspend and resume transitions.  You should verify
-               that your driver correctly handles the suspend and resume, but
-               if you are unable to ensure that, please at least define the
-               .suspend method returning the -ENOSYS ("Function not
-               implemented") error.  You should also try to make sure that your
-               driver uses as little power as possible when it's not doing
-               anything.  For the driver testing instructions see
-               Documentation/power/drivers-testing.rst and for a relatively
-               complete overview of the power management issues related to
-               drivers see :ref:`Documentation/driver-api/pm/devices.rst <driverapi_pm_devices>`.
-
-Control:
-               In general if there is active maintenance of a driver by
-               the author then patches will be redirected to them unless
-               they are totally obvious and without need of checking.
-               If you want to be the contact and update point for the
-               driver it is a good idea to state this in the comments,
-               and include an entry in MAINTAINERS for your driver.
-
-What Criteria Do Not Determine Acceptance
------------------------------------------
-
-Vendor:
-               Being the hardware vendor and maintaining the driver is
-               often a good thing. If there is a stable working driver from
-               other people already in the tree don't expect 'we are the
-               vendor' to get your driver chosen. Ideally work with the
-               existing driver author to build a single perfect driver.
-
-Author:
-               It doesn't matter if a large Linux company wrote the driver,
-               or you did. Nobody has any special access to the kernel
-               tree. Anyone who tells you otherwise isn't telling the
-               whole story.
-
-
-Resources
----------
-
-Linux kernel master tree:
-       ftp.\ *country_code*\ .kernel.org:/pub/linux/kernel/...
-
-       where *country_code* == your country code, such as
-       **us**, **uk**, **fr**, etc.
-
-       https://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git
-
-Linux kernel mailing list:
-       linux-kernel@vger.kernel.org
-       [mail majordomo@vger.kernel.org to subscribe]
-
-Linux Device Drivers, Third Edition (covers 2.6.10):
-       https://lwn.net/Kernel/LDD3/  (free version)
-
-LWN.net:
-       Weekly summary of kernel development activity - https://lwn.net/
-
-       2.6 API changes:
-
-               https://lwn.net/Articles/2.6-kernel-api/
-
-       Porting drivers from prior kernels to 2.6:
-
-               https://lwn.net/Articles/driver-porting/
-
-KernelNewbies:
-       Documentation and assistance for new kernel programmers
-
-               https://kernelnewbies.org/
-
-Linux USB project:
-       http://www.linux-usb.org/
-
-How to NOT write kernel driver by Arjan van de Ven:
-       https://landley.net/kdocs/ols/2002/ols2002-pages-545-555.pdf
-
-Kernel Janitor:
-       https://kernelnewbies.org/KernelJanitors
-
-GIT, Fast Version Control System:
-       https://git-scm.com/
index a1cb628..be49d8f 100644 (file)
@@ -12,9 +12,8 @@ This document contains a large number of suggestions in a relatively terse
 format.  For detailed information on how the kernel development process
 works, see Documentation/process/development-process.rst. Also, read
 Documentation/process/submit-checklist.rst
-for a list of items to check before submitting code.  If you are submitting
-a driver, also read Documentation/process/submitting-drivers.rst; for device
-tree binding patches, read
+for a list of items to check before submitting code.
+For device tree binding patches, read
 Documentation/devicetree/bindings/submitting-patches.rst.
 
 This documentation assumes that you're using ``git`` to prepare your patches.
index 885395d..bad624f 100644 (file)
@@ -87,8 +87,7 @@ with the command.
 1.2.2 Completing a scmd w/ timeout
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-The timeout handler is scsi_times_out().  When a timeout occurs, this
-function
+The timeout handler is scsi_timeout().  When a timeout occurs, this function
 
  1. invokes optional hostt->eh_timed_out() callback.  Return value can
     be one of
index 63ddea2..a8c5bd1 100644 (file)
@@ -731,7 +731,7 @@ Details::
     *      Notes: If 'no_async_abort' is defined this callback
     *          will be invoked from scsi_eh thread. No other commands
     *  will then be queued on current host during eh.
-    *  Otherwise it will be called whenever scsi_times_out()
+    *  Otherwise it will be called whenever scsi_timeout()
     *      is called due to a command timeout.
     *
     *      Optionally defined in: LLD
index b3ed5c5..811b905 100644 (file)
@@ -1046,7 +1046,7 @@ The keyctl syscall functions are:
      "filter" is either NULL to remove a watch or a filter specification to
      indicate what events are required from the key.
 
-     See Documentation/watch_queue.rst for more information.
+     See Documentation/core-api/watch_queue.rst for more information.
 
      Note that only one watch may be emplaced for any particular { key,
      queue_fd } combination.
index 262e7ab..087e2d1 100644 (file)
@@ -98,6 +98,6 @@ References
 
 See [sev-api-spec]_ for more info regarding SEV ``LAUNCH_SECRET`` operation.
 
-.. [sev] Documentation/virt/kvm/amd-memory-encryption.rst
+.. [sev] Documentation/virt/kvm/x86/amd-memory-encryption.rst
 .. [secrets-coco-abi] Documentation/ABI/testing/securityfs-secrets-coco
 .. [sev-api-spec] https://www.amd.com/system/files/TechDocs/55766_SEV-KM_API_Specification.pdf
index a10380c..023bd95 100644 (file)
@@ -85,7 +85,7 @@ Often times the XuY functions will not be large enough, and instead you'll
 want to pass a pre-filled struct to siphash. When doing this, it's important
 to always ensure the struct has no padding holes. The easiest way to do this
 is to simply arrange the members of the struct in descending order of size,
-and to use offsetendof() instead of sizeof() for getting the size. For
+and to use offsetofend() instead of sizeof() for getting the size. For
 performance reasons, if possible, it's probably a good thing to align the
 struct to the right boundary. Here's an example::
 
index 009b07e..bf84313 100644 (file)
@@ -10,7 +10,7 @@ AC97
 ====
 
 AC97 is a five wire interface commonly found on many PC sound cards. It is
-now also popular in many portable devices. This DAI has a reset line and time
+now also popular in many portable devices. This DAI has a RESET line and time
 multiplexes its data on its SDATA_OUT (playback) and SDATA_IN (capture) lines.
 The bit clock (BCLK) is always driven by the CODEC (usually 12.288MHz) and the
 frame (FRAME) (usually 48kHz) is always driven by the controller. Each AC97
index cc348b2..06b3474 100644 (file)
@@ -121,13 +121,20 @@ def markup_refs(docname, app, node):
     return repl
 
 #
+# Keep track of cross-reference lookups that failed so we don't have to
+# do them again.
+#
+failed_lookups = { }
+def failure_seen(target):
+    return (target) in failed_lookups
+def note_failure(target):
+    failed_lookups[target] = True
+
+#
 # In sphinx3 we can cross-reference to C macro and function, each one with its
 # own C role, but both match the same regex, so we try both.
 #
 def markup_func_ref_sphinx3(docname, app, match):
-    class_str = ['c-func', 'c-macro']
-    reftype_str = ['function', 'macro']
-
     cdom = app.env.domains['c']
     #
     # Go through the dance of getting an xref out of the C domain
@@ -143,27 +150,28 @@ def markup_func_ref_sphinx3(docname, app, match):
 
     if base_target not in Skipnames:
         for target in possible_targets:
-            if target not in Skipfuncs:
-                for class_s, reftype_s in zip(class_str, reftype_str):
-                    lit_text = nodes.literal(classes=['xref', 'c', class_s])
-                    lit_text += target_text
-                    pxref = addnodes.pending_xref('', refdomain = 'c',
-                                                  reftype = reftype_s,
-                                                  reftarget = target, modname = None,
-                                                  classname = None)
-                    #
-                    # XXX The Latex builder will throw NoUri exceptions here,
-                    # work around that by ignoring them.
-                    #
-                    try:
-                        xref = cdom.resolve_xref(app.env, docname, app.builder,
-                                                 reftype_s, target, pxref,
-                                                 lit_text)
-                    except NoUri:
-                        xref = None
-
-                    if xref:
-                        return xref
+            if (target not in Skipfuncs) and not failure_seen(target):
+                lit_text = nodes.literal(classes=['xref', 'c', 'c-func'])
+                lit_text += target_text
+                pxref = addnodes.pending_xref('', refdomain = 'c',
+                                              reftype = 'function',
+                                              reftarget = target,
+                                              modname = None,
+                                              classname = None)
+                #
+                # XXX The Latex builder will throw NoUri exceptions here,
+                # work around that by ignoring them.
+                #
+                try:
+                    xref = cdom.resolve_xref(app.env, docname, app.builder,
+                                             'function', target, pxref,
+                                             lit_text)
+                except NoUri:
+                    xref = None
+
+                if xref:
+                    return xref
+                note_failure(target)
 
     return target_text
 
index 38290b9..b0a519f 100644 (file)
@@ -201,9 +201,6 @@ static_key->entry field makes use of the two least significant bits.
 * ``void arch_jump_label_transform(struct jump_entry *entry, enum jump_label_type type)``,
     see: arch/x86/kernel/jump_label.c
 
-* ``__init_or_module void arch_jump_label_transform_static(struct jump_entry *entry, enum jump_label_type type)``,
-    see: arch/x86/kernel/jump_label.c
-
 * ``struct jump_entry``,
     see: arch/x86/include/asm/jump_label.h
 
index 42f5d04..0f68988 100644 (file)
@@ -50,9 +50,9 @@ Di conseguenza, nella tabella dei simboli del kernel ci sarà una voce
 rappresentata dalla struttura ``kernel_symbol`` che avrà il campo
 ``namespace`` (spazio dei nomi) impostato. Un simbolo esportato senza uno spazio
 dei nomi avrà questo campo impostato a ``NULL``. Non esiste uno spazio dei nomi
-di base. Il programma ``modpost`` e il codice in kernel/module.c usano lo spazio
-dei nomi, rispettivamente, durante la compilazione e durante il caricamento
-di un modulo.
+di base. Il programma ``modpost`` e il codice in kernel/module/main.c usano lo
+spazio dei nomi, rispettivamente, durante la compilazione e durante il
+caricamento di un modulo.
 
 2.2 Usare il simbolo di preprocessore DEFAULT_SYMBOL_NAMESPACE
 ==============================================================
diff --git a/Documentation/translations/it_IT/devicetree/bindings/submitting-patches.rst b/Documentation/translations/it_IT/devicetree/bindings/submitting-patches.rst
new file mode 100644 (file)
index 0000000..b473cd2
--- /dev/null
@@ -0,0 +1,11 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-ita.rst
+
+:Original: Documentation/devicetree/bindings/submitting-patches.rst
+
+================================================
+Sottomettere patch per devicetree (DT) *binding*
+================================================
+
+.. note:: to be translated
index 009cdac..7808228 100644 (file)
@@ -5,6 +5,7 @@
 
 .. _it_kernel_doc:
 
+=================================
 Scrivere i commenti in kernel-doc
 =================================
 
@@ -469,6 +470,7 @@ Il titolo che segue ``DOC:`` funziona da intestazione all'interno del file
 sorgente, ma anche come identificatore per l'estrazione di questi commenti di
 documentazione. Quindi, il titolo dev'essere unico all'interno del file.
 
+=======================================
 Includere i commenti di tipo kernel-doc
 =======================================
 
index 9762452..6452879 100644 (file)
@@ -5,8 +5,9 @@
 
 .. _it_sphinxdoc:
 
-Introduzione
-============
+=============================================
+Usare Sphinx per la documentazione del kernel
+=============================================
 
 Il kernel Linux usa `Sphinx`_ per la generazione della documentazione a partire
 dai file `reStructuredText`_ che si trovano nella cartella ``Documentation``.
@@ -158,6 +159,9 @@ Per poter passare ulteriori opzioni a Sphinx potete utilizzare la variabile
 make ``SPHINXOPTS``. Per esempio, se volete che Sphinx sia più verboso durante
 la generazione potete usare il seguente comando ``make SPHINXOPTS=-v htmldocs``.
 
+Potete anche personalizzare l'ouptut html passando un livello aggiuntivo
+DOCS_CSS usando la rispettiva variabile d'ambiente ``DOCS_CSS``.
+
 Potete eliminare la documentazione generata tramite il comando
 ``make cleandocs``.
 
@@ -276,11 +280,11 @@ incrociato quando questa ha una voce nell'indice.  Se trovate degli usi di
 Tabelle a liste
 ---------------
 
-Raccomandiamo l'uso delle tabelle in formato lista (*list table*). Le tabelle
-in formato lista sono liste di liste. In confronto all'ASCII-art potrebbero
-non apparire di facile lettura nei file in formato testo. Il loro vantaggio è
-che sono facili da creare o modificare e che la differenza di una modifica è
-molto più significativa perché limitata alle modifiche del contenuto.
+Il formato ``list-table`` può essere utile per tutte quelle tabelle che non
+possono essere facilmente scritte usando il formato ASCII-art di Sphinx. Però,
+questo genere di tabelle sono illeggibili per chi legge direttamente i file di
+testo. Dunque, questo formato dovrebbe essere evitato senza forti argomenti che
+ne giustifichino l'uso.
 
 La ``flat-table`` è anch'essa una lista di liste simile alle ``list-table``
 ma con delle funzionalità aggiuntive:
index d5c5213..560f1d0 100644 (file)
@@ -129,8 +129,7 @@ eseguiti simultaneamente.
 .. warning::
 
     Il nome 'tasklet' è ingannevole: non hanno niente a che fare
-    con i 'processi' ('tasks'), e probabilmente hanno più a che vedere
-    con qualche pessima vodka che Alexey Kuznetsov si fece a quel tempo.
+    con i 'processi' ('tasks').
 
 Potete determinate se siete in un softirq (o tasklet) utilizzando la
 macro :c:func:`in_softirq()` (``include/linux/preempt.h``).
@@ -308,7 +307,7 @@ esse copiano una quantità arbitraria di dati da e verso lo spazio utente.
     Al contrario di:c:func:`put_user()` e :c:func:`get_user()`, queste
     funzioni ritornano la quantità di dati copiati (0 è comunque un successo).
 
-[Sì, questa stupida interfaccia mi imbarazza. La battaglia torna in auge anno
+[Sì, questa interfaccia mi imbarazza. La battaglia torna in auge anno
 dopo anno. --RR]
 
 Le funzioni potrebbero dormire implicitamente. Queste non dovrebbero mai essere
@@ -679,9 +678,8 @@ tutti sulle spine: questo riflette cambiamenti fondamentati (eg. la funzione
 non può più essere chiamata con le funzioni attive, o fa controlli aggiuntivi,
 o non fa più controlli che venivano fatti in precedenza). Solitamente a questo
 s'accompagna un'adeguata e completa nota sulla lista di discussone
-linux-kernel; cercate negli archivi.
-Solitamente eseguire una semplice sostituzione su tutto un file rendere
-le cose **peggiori**.
+più adatta; cercate negli archivi. Solitamente eseguire una semplice
+sostituzione su tutto un file rendere le cose **peggiori**.
 
 Inizializzazione dei campi d'una struttura
 ------------------------------------------
@@ -759,14 +757,14 @@ Mettere le vostre cose nel kernel
 Al fine d'avere le vostre cose in ordine per l'inclusione ufficiale, o
 anche per avere patch pulite, c'è del lavoro amministrativo da fare:
 
--  Trovare di chi è lo stagno in cui state pisciando. Guardare in cima
+-  Trovare chi è responsabile del codice che state modificando. Guardare in cima
    ai file sorgenti, all'interno del file ``MAINTAINERS``, ed alla fine
    di tutti nel file ``CREDITS``. Dovreste coordinarvi con queste persone
    per evitare di duplicare gli sforzi, o provare qualcosa che è già stato
    rigettato.
 
    Assicuratevi di mettere il vostro nome ed indirizzo email in cima a
-   tutti i file che create o che mangeggiate significativamente. Questo è
+   tutti i file che create o che maneggiate significativamente. Questo è
    il primo posto dove le persone guarderanno quando troveranno un baco,
    o quando **loro** vorranno fare una modifica.
 
@@ -787,16 +785,15 @@ anche per avere patch pulite, c'è del lavoro amministrativo da fare:
    "obj-$(CONFIG_xxx) += xxx.o". La sintassi è documentata nel file
    ``Documentation/kbuild/makefiles.rst``.
 
--  Aggiungete voi stessi in ``CREDITS`` se avete fatto qualcosa di notevole,
-   solitamente qualcosa che supera il singolo file (comunque il vostro nome
-   dovrebbe essere all'inizio dei file sorgenti). ``MAINTAINERS`` significa
+-  Aggiungete voi stessi in ``CREDITS`` se credete di aver fatto qualcosa di
+   notevole, solitamente qualcosa che supera il singolo file (comunque il vostro
+   nome dovrebbe essere all'inizio dei file sorgenti). ``MAINTAINERS`` significa
    che volete essere consultati quando vengono fatte delle modifiche ad un
-   sottosistema, e quando ci sono dei bachi; questo implica molto di più
-   di un semplice impegno su una parte del codice.
+   sottosistema, e quando ci sono dei bachi; questo implica molto di più di un
+   semplice impegno su una parte del codice.
 
 -  Infine, non dimenticatevi di leggere
-   ``Documentation/process/submitting-patches.rst`` e possibilmente anche
-   ``Documentation/process/submitting-drivers.rst``.
+   ``Documentation/process/submitting-patches.rst``.
 
 Trucchetti del kernel
 =====================
index 163f1bd..51af37f 100644 (file)
@@ -102,16 +102,11 @@ che non esistano.
 Sincronizzazione nel kernel Linux
 =================================
 
-Se posso darvi un suggerimento: non dormite mai con qualcuno più pazzo di
-voi. Ma se dovessi darvi un suggerimento sulla sincronizzazione:
-**mantenetela semplice**.
+Se dovessi darvi un suggerimento sulla sincronizzazione: **mantenetela
+semplice**.
 
 Siate riluttanti nell'introduzione di nuovi *lock*.
 
-Abbastanza strano, quest'ultimo è l'esatto opposto del mio suggerimento
-su quando **avete** dormito con qualcuno più pazzo di voi. E dovreste
-pensare a prendervi un cane bello grande.
-
 I due principali tipi di *lock* nel kernel: spinlock e mutex
 ------------------------------------------------------------
 
@@ -316,7 +311,7 @@ Pete Zaitcev ci offre il seguente riassunto:
 
 -  Se siete in un contesto utente (una qualsiasi chiamata di sistema)
    e volete sincronizzarvi con altri processi, usate i mutex. Potete trattenere
-   il mutex e dormire (``copy_from_user*(`` o ``kmalloc(x,GFP_KERNEL)``).
+   il mutex e dormire (``copy_from_user(`` o ``kmalloc(x,GFP_KERNEL)``).
 
 -  Altrimenti (== i dati possono essere manipolati da un'interruzione) usate
    spin_lock_irqsave() e spin_unlock_irqrestore().
@@ -979,9 +974,6 @@ fallisce nel trovare quello che vuole, quindi rilascia il *lock* di lettura,
 trattiene un *lock* di scrittura ed inserisce un oggetto; questo genere di
 codice presenta una corsa critica.
 
-Se non riuscite a capire il perché, per favore state alla larga dal mio
-codice.
-
 corsa fra temporizzatori: un passatempo del kernel
 --------------------------------------------------
 
diff --git a/Documentation/translations/it_IT/maintainer/configure-git.rst b/Documentation/translations/it_IT/maintainer/configure-git.rst
new file mode 100644 (file)
index 0000000..8316fa5
--- /dev/null
@@ -0,0 +1,10 @@
+.. include:: ../disclaimer-ita.rst
+
+:Original: Documentation/process/botching-up-ioctls.rst
+
+.. _it_configuregit:
+
+Configurare Git
+===============
+
+.. note::  To be translated
index 7e2456b..8a1e049 100644 (file)
@@ -1,6 +1,6 @@
 .. include:: ../disclaimer-ita.rst
 
-:Original: :ref:`Documentation/networking/netdev-FAQ.rst <netdev-FAQ>`
+:Original: :ref:`Documentation/process/maintainer-netdev.rst <netdev-FAQ>`
 
 .. _it_netdev-FAQ:
 
index 443ac1e..0809de3 100644 (file)
@@ -168,14 +168,15 @@ in questa ricerca:
 
        .../scripts/get_maintainer.pl
 
-Se questo script viene eseguito con l'opzione "-f" ritornerà il
-manutentore(i) attuale per un dato file o cartella.  Se viene passata una
-patch sulla linea di comando, lo script elencherà i manutentori che
-dovrebbero riceverne una copia.  Ci sono svariate opzioni che regolano
-quanto a fondo get_maintainer.pl debba cercare i manutentori;
-siate quindi prudenti nell'utilizzare le opzioni più aggressive poiché
-potreste finire per includere sviluppatori che non hanno un vero interesse
-per il codice che state modificando.
+Se questo script viene eseguito con l'opzione "-f" ritornerà il manutentore(i)
+attuale per un dato file o cartella. Se viene passata una patch sulla linea di
+comando, lo script elencherà i manutentori che dovrebbero riceverne una copia.
+Questo è la maniera raccomandata (non quella con "-f") per ottenere la lista di
+persone da aggiungere a Cc per le vostre patch. Ci sono svariate opzioni che
+regolano quanto a fondo get_maintainer.pl debba cercare i manutentori; siate
+quindi prudenti nell'utilizzare le opzioni più aggressive poiché potreste finire
+per includere sviluppatori che non hanno un vero interesse per il codice che
+state modificando.
 
 Se tutto ciò dovesse fallire, parlare con Andrew Morton potrebbe essere
 un modo efficace per capire chi è il manutentore di un dato pezzo di codice.
index 1476d51..cf92a16 100644 (file)
@@ -16,9 +16,8 @@ e di procedure per la pubblicazione delle patch; seguirle renderà la vita
 più facile a tutti quanti.  Questo documento cercherà di coprire questi
 argomenti con un ragionevole livello di dettaglio; più informazioni possono
 essere trovare nella cartella 'Documentation', nei file
-:ref:`translations/it_IT/process/submitting-patches.rst <it_submittingpatches>`,
-:ref:`translations/it_IT/process/submitting-drivers.rst <it_submittingdrivers>`, e
-:ref:`translations/it_IT/process/submit-checklist.rst <it_submitchecklist>`.
+:ref:`translations/it_IT/process/submitting-patches.rst <it_submittingpatches>`
+e :ref:`translations/it_IT/process/submit-checklist.rst <it_submitchecklist>`.
 
 
 Quando pubblicarle
@@ -214,13 +213,28 @@ irrilevanti (quelli generati dal processo di generazione, per esempio, o i file
 di backup del vostro editor).  Il file "dontdiff" nella cartella Documentation
 potrà esservi d'aiuto su questo punto; passatelo a diff con l'opzione "-X".
 
-Le etichette sopra menzionante sono usate per descrivere come i vari
-sviluppatori sono stati associati allo sviluppo di una patch.  Sono descritte
-in dettaglio nel documento :ref:`translations/it_IT/process/submitting-patches.rst <it_submittingpatches>`;
-quello che segue è un breve riassunto.  Ognuna di queste righe ha il seguente
-formato:
+Le etichette sopracitate danno un'idea di come una patch prende vita e sono
+descritte nel dettaglio nel documento
+:ref:`Documentation/translations/it_IT/process/submitting-patches.rst <it_submittingpatches>`.
+Qui di seguito un breve riassunto.
 
-::
+Un'etichetta ci può dire quale commit ha introdotto il problema che viene corretto nella patch::
+
+       Fixes: 1f2e3d4c5b6a ("The first line of the commit specified by the first 12 characters of its SHA-1 ID")
+
+Un'altra etichetta viene usata per fornire collegamenti a pagine web contenenti
+maggiori informazioni, per esempio un rapporto circa il baco risolto dalla
+patch, oppure un documento con le specifiche implementate dalla patch::
+
+       Link: https://example.com/somewhere.html  optional-other-stuff
+
+Alcuni manutentori aggiungono quest'etichetta alla patch per fare riferimento
+alla più recente discussione pubblica. A volte questo è fatto automaticamente da
+alcuni strumenti come b4 or un *hook* git come quello descritto qui
+'Documentation/translations/it_IT/maintainer/configure-git.rst'
+
+Un terzo tipo di etichetta viene usato per indicare chi ha contribuito allo
+sviluppo della patch. Tutte queste etichette seguono il formato::
 
        tag: Full Name <email address>  optional-other-stuff
 
index 039bfc5..32659ff 100644 (file)
@@ -13,9 +13,8 @@ e argomenti correlati. Primo tra questi sarà sempre la cartella Documentation
 che si trova nei sorgenti kernel.
 
 Il file :ref:`process/howto.rst <it_process_howto>` è un punto di partenza
-importante; :ref:`process/submitting-patches.rst <it_submittingpatches>` e
-:ref:`process/submitting-drivers.rst <it_submittingdrivers>` sono
-anch'essi qualcosa che tutti gli sviluppatori del kernel dovrebbero leggere.
+importante; :ref:`process/submitting-patches.rst <it_submittingpatches>` è
+anch'esso qualcosa che tutti gli sviluppatori del kernel dovrebbero leggere.
 Molte API interne al kernel sono documentate utilizzando il meccanismo
 kerneldoc; "make htmldocs" o "make pdfdocs" possono essere usati per generare
 quei documenti in HTML o PDF (sebbene le versioni di TeX di alcune
index dc71933..10e0ef9 100644 (file)
@@ -11,8 +11,8 @@ Requisiti minimi per compilare il kernel
 Introduzione
 ============
 
-Questo documento fornisce una lista dei software necessari per eseguire i
-kernel 4.x.
+Questo documento fornisce una lista dei software necessari per eseguire questa
+versione del kernel.
 
 Questo documento è basato sul file "Changes" del kernel 2.0.x e quindi le
 persone che lo scrissero meritano credito (Jared Mauch, Axel Boldt,
@@ -32,12 +32,13 @@ PC Card, per esempio, probabilmente non dovreste preoccuparvi di pcmciautils.
 ====================== =================  ========================================
         Programma       Versione minima       Comando per verificare la versione
 ====================== =================  ========================================
-GNU C                  4.9                gcc --version
-Clang/LLVM (optional)  10.0.1             clang --version
+GNU C                  5.1                gcc --version
+Clang/LLVM (optional)  11.0.0             clang --version
 GNU make               3.81               make --version
 binutils               2.23               ld -v
 flex                   2.5.35             flex --version
 bison                  2.0                bison --version
+pahole                 1.16               pahole --version
 util-linux             2.10o              fdformat --version
 kmod                   13                 depmod -V
 e2fsprogs              1.41.4             e2fsck -V
@@ -58,6 +59,7 @@ iptables               1.4.2              iptables -V
 openssl & libcrypto    1.0.0              openssl version
 bc                     1.06.95            bc --version
 Sphinx\ [#f1]_         1.7                sphinx-build --version
+cpio                   any                cpio --version
 ====================== =================  ========================================
 
 .. [#f1] Sphinx è necessario solo per produrre la documentazione del Kernel
@@ -111,6 +113,16 @@ Bison
 Dalla versione 4.16, il sistema di compilazione, durante l'esecuzione, genera
 un parsificatore.  Questo richiede bison 2.0 o successivo.
 
+pahole
+------
+
+Dalla versione 5.2, quando viene impostato CONFIG_DEBUG_INFO_BTF, il sistema di
+compilazione genera BTF (BPF Type Format) a partire da DWARF per vmlinux. Più
+tardi anche per i moduli. Questo richiede pahole v1.16 o successivo.
+
+A seconda della distribuzione, lo si può trovare nei pacchetti 'dwarves' o
+'pahole'. Oppure lo si può trovare qui: https://fedorapeople.org/~acme/dwarves/.
+
 Perl
 ----
 
@@ -455,6 +467,11 @@ mcelog
 
 - <http://www.mcelog.org/>
 
+cpio
+----
+
+- <https://www.gnu.org/software/cpio/>
+
 Rete
 ****
 
index ecc74ba..a393ee4 100644 (file)
@@ -466,14 +466,52 @@ la riga della parentesi graffa di chiusura. Ad esempio:
        }
        EXPORT_SYMBOL(system_is_up);
 
+6.1) Prototipi di funzione
+**************************
+
 Nei prototipi di funzione, includete i nomi dei parametri e i loro tipi.
 Nonostante questo non sia richiesto dal linguaggio C, in Linux viene preferito
 perché è un modo semplice per aggiungere informazioni importanti per il
 lettore.
 
-Non usate la parola chiave ``extern`` coi prototipi di funzione perché
+Non usate la parola chiave ``extern`` con le dichiarazioni di funzione perché
 rende le righe più lunghe e non è strettamente necessario.
 
+Quando scrivete i prototipi di funzione mantenete `l'ordine degli elementi <https://lore.kernel.org/mm-commits/CAHk-=wiOCLRny5aifWNhr621kYrJwhfURsa0vFPeUEm8mF0ufg@mail.gmail.com/>`_.
+
+Prendiamo questa dichiarazione di funzione come esempio::
+
+ __init void * __must_check action(enum magic value, size_t size, u8 count,
+                                  char *fmt, ...) __printf(4, 5) __malloc;
+
+L'ordine suggerito per gli elementi di un prototipo di funzione è il seguente:
+
+- classe d'archiviazione (in questo caso ``static __always_inline``. Da notare
+  che ``__always_inline`` è tecnicamente un attributo ma che viene trattato come
+  ``inline``)
+- attributi della classe di archiviazione (in questo caso ``__init``, in altre
+  parole la sezione, ma anche cose tipo ``__cold``)
+- il tipo di ritorno (in questo caso, ``void *``)
+- attributi per il valore di ritorno (in questo caso, ``__must_check``)
+- il nome della funzione (in questo caso, ``action``)
+- i parametri della funzione(in questo caso,
+  ``(enum magic value, size_t size, u8 count, char *fmt, ...)``,
+  da notare che va messo anche il nome del parametro)
+- attributi dei parametri (in questo caso, ``__printf(4, 5)``)
+- attributi per il comportamento della funzione (in questo caso, ``__malloc_``)
+
+Notate che per la **definizione** di una funzione (il altre parole il corpo
+della funzione), il compilatore non permette di usare gli attributi per i
+parametri dopo i parametri. In questi casi, devono essere messi dopo gli
+attributi della classe d'archiviazione (notate che la posizione di
+``__printf(4,5)`` cambia rispetto alla **dichiarazione**)::
+
+ static __always_inline __init __printf(4, 5) void * __must_check action(enum magic value,
+              size_t size, u8 count, char *fmt, ...) __malloc
+ {
+         ...
+ }*)**``)**``)``)``*)``)``)``)``*``)``)``)*)
+
 7) Centralizzare il ritorno delle funzioni
 ------------------------------------------
 
@@ -855,7 +893,7 @@ I messaggi del kernel non devono terminare con un punto fermo.
 Scrivere i numeri fra parentesi (%d) non migliora alcunché e per questo
 dovrebbero essere evitati.
 
-Ci sono alcune macro per la diagnostica in <linux/device.h> che dovreste
+Ci sono alcune macro per la diagnostica in <linux/dev_printk.h> che dovreste
 usare per assicurarvi che i messaggi vengano associati correttamente ai
 dispositivi e ai driver, e che siano etichettati correttamente:  dev_err(),
 dev_warn(), dev_info(), e così via.  Per messaggi che non sono associati ad
index 987f45e..febf838 100644 (file)
@@ -69,8 +69,8 @@ dovrebbero essere fatto negli argomenti di funzioni di allocazione di memoria
 piccoli di quelli che il chiamante si aspettava. L'uso di questo modo di
 allocare può portare ad un overflow della memoria di heap e altri
 malfunzionamenti. (Si fa eccezione per valori numerici per i quali il
-compilatore può generare avvisi circa un potenziale overflow. Tuttavia usare
-i valori numerici come suggerito di seguito è innocuo).
+compilatore può generare avvisi circa un potenziale overflow. Tuttavia, anche in
+questi casi è preferibile riscrivere il codice come suggerito di seguito).
 
 Per esempio, non usate ``count * size`` come argomento::
 
@@ -80,6 +80,9 @@ Al suo posto, si dovrebbe usare l'allocatore a due argomenti::
 
        foo = kmalloc_array(count, size, GFP_KERNEL);
 
+Nello specifico, kmalloc() può essere sostituta da kmalloc_array(), e kzalloc()
+da kcalloc().
+
 Se questo tipo di allocatore non è disponibile, allora dovrebbero essere usate
 le funzioni del tipo *saturate-on-overflow*::
 
@@ -100,9 +103,20 @@ Invece, usate la seguente funzione::
          invitati a riorganizzare il vostro codice usando il
          `flexible array member <#zero-length-and-one-element-arrays>`_.
 
-Per maggiori dettagli fate riferimento a array_size(),
-array3_size(), e struct_size(), così come la famiglia di
-funzioni check_add_overflow() e check_mul_overflow().
+Per altri calcoli, usate le funzioni size_mul(), size_add(), e size_sub(). Per
+esempio, al posto di::
+
+       foo = krealloc(current_size + chunk_size * (count - 3), GFP_KERNEL);
+
+dovreste scrivere:
+
+       foo = krealloc(size_add(current_size,
+                               size_mul(chunk_size,
+                                        size_sub(count, 3))), GFP_KERNEL);
+
+Per maggiori dettagli fate riferimento a array3_size() e flex_array_size(), ma
+anche le funzioni della famiglia check_mul_overflow(), check_add_overflow(),
+check_sub_overflow(), e check_shl_overflow().
 
 simple_strtol(), simple_strtoll(), simple_strtoul(), simple_strtoull()
 ----------------------------------------------------------------------
index 9554368..16ad562 100644 (file)
@@ -109,8 +109,7 @@ Di seguito una lista di file che sono presenti nei sorgente del kernel e che
     accetteranno patch solo se queste osserveranno tali regole, e molte
     persone revisioneranno il codice solo se scritto nello stile appropriato.
 
-  :ref:`Documentation/translations/it_IT/process/submitting-patches.rst <it_submittingpatches>` e
-  :ref:`Documentation/translations/it_IT/process/submitting-drivers.rst <it_submittingdrivers>`
+  :ref:`Documentation/translations/it_IT/process/submitting-patches.rst <it_submittingpatches>`
 
     Questo file descrive dettagliatamente come creare ed inviare una patch
     con successo, includendo (ma non solo questo):
index c4c8671..8d4e36a 100644 (file)
@@ -41,12 +41,12 @@ degli sviluppatori:
    :maxdepth: 1
 
    changes
-   submitting-drivers
    stable-api-nonsense
    management-style
    stable-kernel-rules
    submit-checklist
    kernel-docs
+   maintainers
 
 Ed infine, qui ci sono alcune guide più tecniche che son state messe qua solo
 perché non si è trovato un posto migliore.
diff --git a/Documentation/translations/it_IT/process/maintainer-handbooks.rst b/Documentation/translations/it_IT/process/maintainer-handbooks.rst
new file mode 100644 (file)
index 0000000..d840145
--- /dev/null
@@ -0,0 +1,24 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-ita.rst
+
+:Original: Documentation/process/maintainer-handbooks.rst
+:Translator: Federico Vaga <federico.vaga@vaga.pv.it>
+
+.. _it_maintainer_handbooks_main:
+
+Note sul processo di sviluppo dei sottosistemi e dei sorgenti dei manutentori
+=============================================================================
+
+Lo scopo di questo documento è quello di fornire informazioni sul processo di
+sviluppo dedicate ai sottosistemi che vanno ad integrare quelle più generali
+descritte in :ref:`Documentation/translations/it_IT/process
+<it_development_process_main>`.
+
+Indice:
+
+.. toctree::
+   :numbered:
+   :maxdepth: 2
+
+   maintainer-tip
index f3c8e8d..a1e98ec 100644 (file)
@@ -931,12 +931,11 @@ che avete nel vostro portachiavi::
     uid           [ unknown] Linus Torvalds <torvalds@kernel.org>
     sub   rsa2048 2011-09-20 [E]
 
-Poi, aprite il `PGP pathfinder`_. Nel campo "From", incollate l'impronta
-digitale della chiave di Linus Torvalds che si vede nell'output qui sopra.
-Nel campo "to", incollate il key-id della chiave sconosciuta che avete
-trovato con ``gpg --search``, e poi verificare il risultato:
-
-- `Finding paths to Linus`_
+Poi, cercate un percorso affidabile da Linux Torvalds alla chiave che avete
+trovato con ``gpg --search`` usando la chiave sconosciuta.Per farlo potete usare
+diversi strumenti come https://github.com/mricon/wotmate,
+https://git.kernel.org/pub/scm/docs/kernel/pgpkeys.git/tree/graphs, e
+https://the.earth.li/~noodles/pathfind.html.
 
 Se trovate un paio di percorsi affidabili è un buon segno circa la validità
 della chiave. Ora, potete aggiungerla al vostro portachiavi dal keyserver::
@@ -948,6 +947,3 @@ fiducia nell'amministratore del servizio *PGP Pathfinder* sperando che non
 sia malintenzionato (infatti, questo va contro :ref:`it_devs_not_infra`).
 Tuttavia, se mantenete con cura la vostra rete di fiducia sarà un deciso
 miglioramento rispetto alla cieca fiducia nei keyserver.
-
-.. _`PGP pathfinder`: https://pgp.cs.uu.nl/
-.. _`Finding paths to Linus`: https://pgp.cs.uu.nl/paths/79BE3E4300411886/to/C94035C21B4F2AEB.html
diff --git a/Documentation/translations/it_IT/process/maintainer-tip.rst b/Documentation/translations/it_IT/process/maintainer-tip.rst
new file mode 100644 (file)
index 0000000..126f17e
--- /dev/null
@@ -0,0 +1,10 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-ita.rst
+
+:Original: Documentation/process/maintainer-tip.rst
+
+Il tascabile dei sorgenti tip
+=============================
+
+.. note:: To be translated
diff --git a/Documentation/translations/it_IT/process/maintainers.rst b/Documentation/translations/it_IT/process/maintainers.rst
new file mode 100644 (file)
index 0000000..3225f7c
--- /dev/null
@@ -0,0 +1,13 @@
+:Original: Documentation/process/maintainers.rst
+
+Lista dei manutentori e come inviare modifiche al kernel
+========================================================
+
+Questa pagina non verrà tradotta. Fate riferimento alla versione originale in
+inglese.
+
+.. note:: La pagina originale usa una direttiva speciale per integrare il file
+          `MAINTAINERS` in sphinx. La parte di quel documento che si potrebbe
+          tradurre contiene comunque informazioni già presenti in
+          :ref:`Documentation/translations/it_IT/process/submitting-patches.rst
+          <it_submittingpatches>`.
index 83f48af..0be675b 100644 (file)
@@ -41,10 +41,10 @@ Regole sul tipo di patch che vengono o non vengono accettate nei sorgenti
 Procedura per sottomettere patch per i sorgenti -stable
 -------------------------------------------------------
 
- - Una patch di sicurezza non dovrebbero essere gestite (solamente) dal processo
-   di revisione -stable, ma dovrebbe seguire le procedure descritte in
-   :ref:`Documentation/translations/it_IT/admin-guide/security-bugs.rst <it_securitybugs>`.
-
+.. note::
+  Una patch di sicurezza non dovrebbe essere gestita (solamente) dal processo
+  di revisione -stable, ma dovrebbe seguire le procedure descritte in
+  :ref:`Documentation/translations/it_IT/admin-guide/security-bugs.rst <it_securitybugs>`.
 
 Per tutte le altre sottomissioni, scegliere una delle seguenti procedure
 ------------------------------------------------------------------------
@@ -90,9 +90,9 @@ L':ref:`it_option_2` e l':ref:`it_option_3` sono più utili quando, al momento
 dell'inclusione dei sorgenti principali, si ritiene che non debbano essere
 incluse anche in quelli stabili (per esempio, perché si crede che si dovrebbero
 fare più verifiche per eventuali regressioni). L':ref:`it_option_3` è
-particolarmente utile se la patch ha bisogno di qualche modifica per essere
-applicata ad un kernel più vecchio (per esempio, perché nel frattempo l'API è
-cambiata).
+particolarmente utile se una patch dev'essere riportata su una versione
+precedente (per esempio la patch richiede modifiche a causa di cambiamenti di
+API).
 
 Notate che per l':ref:`it_option_3`, se la patch è diversa da quella nei
 sorgenti principali (per esempio perché è stato necessario un lavoro di
@@ -167,9 +167,18 @@ Ciclo di una revisione
    della lista linux-kernel obietta la bontà della patch, sollevando problemi
    che i manutentori ed i membri non avevano compreso, allora la patch verrà
    rimossa dalla coda.
- - Alla fine del ciclo di revisione tutte le patch che hanno ricevuto l'ACK
-   verranno aggiunte per il prossimo rilascio -stable, e successivamente
-   questo nuovo rilascio verrà fatto.
+ - Le patch che hanno ricevuto un ACK verranno inviate nuovamente come parte di
+   un rilascio candidato (-rc) al fine di essere verificate dagli sviluppatori e
+   dai testatori.
+ - Solitamente si pubblica solo una -rc, tuttavia se si riscontrano problemi
+   importanti, alcune patch potrebbero essere modificate o essere scartate,
+   oppure nuove patch potrebbero essere messe in coda. Dunque, verranno pubblicate
+   nuove -rc e così via finché non si ritiene che non vi siano più problemi.
+ - Si può rispondere ad una -rc scrivendo sulla lista di discussione un'email
+   con l'etichetta "Tested-by:". Questa etichetta verrà raccolta ed aggiunta al
+   commit rilascio.
+ - Alla fine del ciclo di revisione il nuovo rilascio -stable conterrà tutte le
+   patch che erano in coda e sono state verificate.
  - Le patch di sicurezza verranno accettate nei sorgenti -stable direttamente
    dalla squadra per la sicurezza del kernel, e non passerà per il normale
    ciclo di revisione. Contattate la suddetta squadra per maggiori dettagli
@@ -186,8 +195,19 @@ Sorgenti
  - Il rilascio definitivo, e marchiato, di tutti i kernel stabili può essere
    trovato in rami distinti per versione al seguente indirizzo:
 
-       https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git
+       https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
+
+ - I rilasci candidati di tutti i kernel stabili possono essere trovati al
+   seguente indirizzo:
+
+    https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git/
+
 
+   .. warning::
+     I sorgenti -stable-rc sono un'istantanea dei sorgenti stable-queue e
+     subirà frequenti modifiche, dunque verrà anche trapiantato spesso.
+     Dovrebbe essere usato solo allo scopo di verifica (per esempio in un
+     sistema di CI)
 
 Comitato per la revisione
 -------------------------
diff --git a/Documentation/translations/it_IT/process/submitting-drivers.rst b/Documentation/translations/it_IT/process/submitting-drivers.rst
deleted file mode 100644 (file)
index dadd77e..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-.. include:: ../disclaimer-ita.rst
-
-:Original: :ref:`Documentation/process/submitting-drivers.rst <submittingdrivers>`
-:Translator: Federico Vaga <federico.vaga@vaga.pv.it>
-
-.. _it_submittingdrivers:
-
-Sottomettere driver per il kernel Linux
-=======================================
-
-.. note::
-
-   Questo documento è vecchio e negli ultimi anni non è stato più aggiornato;
-   dovrebbe essere aggiornato, o forse meglio, rimosso.  La maggior parte di
-   quello che viene detto qui può essere trovato anche negli altri documenti
-   dedicati allo sviluppo.  Per questo motivo il documento non verrà tradotto.
index 4fb5b3a..a3bb000 100644 (file)
@@ -18,16 +18,18 @@ Questo documento contiene un vasto numero di suggerimenti concisi. Per maggiori
 dettagli su come funziona il processo di sviluppo del kernel leggete
 Documentation/translations/it_IT/process/development-process.rst. Leggete anche
 Documentation/translations/it_IT/process/submit-checklist.rst per una lista di
-punti da verificare prima di inviare del codice. Se state inviando un driver,
-allora leggete anche
-Documentation/translations/it_IT/process/submitting-drivers.rst; per delle patch
-relative alle associazioni per Device Tree leggete
+punti da verificare prima di inviare del codice.
+Per delle patch relative alle associazioni per Device Tree leggete
 Documentation/translations/it_IT/process/submitting-patches.rst.
 
 Questa documentazione assume che sappiate usare ``git`` per preparare le patch.
 Se non siete pratici di ``git``, allora è bene che lo impariate;
 renderà la vostra vita di sviluppatore del kernel molto più semplice.
 
+I sorgenti di alcuni sottosistemi e manutentori contengono più informazioni
+riguardo al loro modo di lavorare ed aspettative. Consultate
+:ref:`Documentation/translations/it_IT/process/maintainer-handbooks.rst <it_maintainer_handbooks_main>`
+
 Ottenere i sorgenti attuali
 ---------------------------
 
@@ -84,11 +86,11 @@ comporti come descritto.
 
 I manutentori vi saranno grati se scrivete la descrizione della patch in un
 formato che sia compatibile con il gestore dei sorgenti usato dal kernel,
-``git``, come un "commit log".  Leggete :ref:`it_explicit_in_reply_to`.
+``git``, come un "commit log". Leggete :ref:`it_the_canonical_patch_format`.
 
 Risolvete solo un problema per patch.  Se la vostra descrizione inizia ad
 essere lunga, potrebbe essere un segno che la vostra patch necessita d'essere
-divisa. Leggete :ref:`split_changes`.
+divisa. Leggete :ref:`it_split_changes`.
 
 Quando inviate o rinviate una patch o una serie, includete la descrizione
 completa delle modifiche e la loro giustificazione.  Non limitatevi a dire che
@@ -104,17 +106,28 @@ do frotz" piuttosto che "[This patch] makes xyzzy do frotz" or "[I] changed
 xyzzy to do frotz", come se steste dando ordini al codice di cambiare il suo
 comportamento.
 
-Se la patch corregge un baco conosciuto, fare riferimento a quel baco inserendo
-il suo numero o il suo URL.  Se la patch è la conseguenza di una discussione
-su una lista di discussione, allora fornite l'URL all'archivio di quella
-discussione;  usate i collegamenti a https://lore.kernel.org/ con il
-``Message-Id``, in questo modo vi assicurerete che il collegamento non diventi
-invalido nel tempo.
+Se ci sono delle discussioni, o altre informazioni d'interesse, che fanno
+riferimento alla patch, allora aggiungete l'etichetta 'Link:' per farvi
+riferimento. Per esempio, se la vostra patch corregge un baco potete aggiungere
+quest'etichetta per fare riferimento ad un rapporto su una lista di discussione
+o un *bug tracker*. Un altro esempio; potete usare quest'etichetta per far
+riferimento ad una discussione precedentemente avvenuta su una lista di
+discussione, o qualcosa di documentato sul web, da cui poi è nata la patch in
+questione.
+
+Quando volete fare riferimento ad una lista di discussione, preferite il
+servizio d'archiviazione lore.kernel.org. Per create un collegamento URL è
+sufficiente usare il campo ``Message-Id``, presente nell'intestazione del
+messaggio, senza parentesi angolari. Per esempio::
+
+     Link: https://lore.kernel.org/r/30th.anniversary.repost@klaava.Helsinki.FI/
+
+Prima d'inviare il messaggio ricordatevi di verificare che il collegamento così
+creato funzioni e che indirizzi verso il messaggio desiderato.
 
-Tuttavia, cercate di rendere la vostra spiegazione comprensibile anche senza
-far riferimento a fonti esterne.  In aggiunta ai collegamenti a bachi e liste
-di discussione, riassumente i punti più importanti della discussione che hanno
-portato alla creazione della patch.
+Tuttavia, provate comunque a dare una spiegazione comprensibile anche senza
+accedere alle fonti esterne. Inoltre, riassumente i punti più salienti che hanno
+condotto all'invio della patch.
 
 Se volete far riferimento a uno specifico commit, non usate solo
 l'identificativo SHA-1.  Per cortesia, aggiungete anche la breve riga
@@ -226,10 +239,11 @@ nella vostra patch.
 
 Dovreste sempre inviare una copia della patch ai manutentori dei sottosistemi
 interessati dalle modifiche; date un'occhiata al file MAINTAINERS e alla storia
-delle revisioni per scoprire chi si occupa del codice.  Lo script
-scripts/get_maintainer.pl può esservi d'aiuto.  Se non riuscite a trovare un
-manutentore per il sottosistema su cui state lavorando, allora Andrew Morton
-(akpm@linux-foundation.org) sarà la vostra ultima possibilità.
+delle revisioni per scoprire chi si occupa del codice. Lo script
+scripts/get_maintainer.pl può esservi d'aiuto (passategli il percorso alle
+vostre patch). Se non riuscite a trovare un manutentore per il sottosistema su
+cui state lavorando, allora Andrew Morton (akpm@linux-foundation.org) sarà la
+vostra ultima possibilità.
 
 Normalmente, dovreste anche scegliere una lista di discussione a cui inviare la
 vostra serie di patch. La lista di discussione linux-kernel@vger.kernel.org
@@ -324,14 +338,19 @@ cosa stia accadendo.
 
 Assicuratevi di dire ai revisori quali cambiamenti state facendo e di
 ringraziarli per il loro tempo.  Revisionare codice è un lavoro faticoso e che
-richiede molto tempo, e a volte i revisori diventano burberi.  Tuttavia, anche
-in questo caso, rispondete con educazione e concentratevi sul problema che
-hanno evidenziato.
+richiede molto tempo, e a volte i revisori diventano burberi. Tuttavia, anche in
+questo caso, rispondete con educazione e concentratevi sul problema che hanno
+evidenziato. Quando inviate una version successiva ricordatevi di aggiungere un
+``patch changelog`` alla email di intestazione o ad ogni singola patch spiegando
+le differenze rispetto a sottomissioni precedenti (vedere
+:ref:`it_the_canonical_patch_format`).
 
 Leggete Documentation/translations/it_IT/process/email-clients.rst per
 le raccomandazioni sui programmi di posta elettronica e l'etichetta da usare
 sulle liste di discussione.
 
+.. _it_resend_reminders:
+
 Non scoraggiatevi - o impazientitevi
 ------------------------------------
 
@@ -504,7 +523,8 @@ Utilizzare Reported-by:, Tested-by:, Reviewed-by:, Suggested-by: e Fixes:
 L'etichetta Reported-by da credito alle persone che trovano e riportano i bachi
 e si spera che questo possa ispirarli ad aiutarci nuovamente in futuro.
 Rammentate che se il baco è stato riportato in privato, dovrete chiedere il
-permesso prima di poter utilizzare l'etichetta Reported-by.
+permesso prima di poter utilizzare l'etichetta Reported-by. Questa etichetta va
+usata per i bachi, dunque non usatela per richieste di nuove funzionalità.
 
 L'etichetta Tested-by: indica che la patch è stata verificata con successo
 (su un qualche sistema) dalla persona citata.  Questa etichetta informa i
@@ -574,6 +594,8 @@ previste per i kernel stabili, e nemmeno dalla necessità di aggiungere
 in copia conoscenza stable@vger.kernel.org su tutte le patch per
 suddetti kernel.
 
+.. _it_the_canonical_patch_format:
+
 Il formato canonico delle patch
 -------------------------------
 
@@ -719,6 +741,8 @@ messe correttamente oltre la riga.::
 
 Maggiori dettagli sul formato delle patch nei riferimenti qui di seguito.
 
+.. _it_backtraces:
+
 Aggiungere i *backtrace* nei messaggi di commit
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
index 38fed6f..649e2ff 100644 (file)
@@ -129,8 +129,8 @@ linux-api@vger.kernel.org に送ることを勧めます。
     ルに従っているものだけを受け付け、多くの人は正しいスタイルのコード
     だけをレビューします。
 
-  :ref:`Documentation/process/submitting-patches.rst <codingstyle>` と :ref:`Documentation/process/submitting-drivers.rst <submittingdrivers>`
-    ã\81\93ã\82\8cã\82\89ã\81®ã\83\95ã\82¡ã\82¤ã\83«ã\81«ã\81¯ã\80\81ã\81©ã\81\86ã\82\84ã\81£ã\81¦ã\81\86ã\81¾ã\81\8fã\83\91ã\83\83ã\83\81ã\82\92ä½\9cã\81£ã\81¦æ\8a\95稿ã\81\99ã\82\8bã\81\8bã\81«ã\81¤
+  :ref:`Documentation/process/submitting-patches.rst <codingstyle>`
+    このファイルには、どうやってうまくパッチを作って投稿するかにつ
     いて非常に詳しく書かれており、以下を含みます (これだけに限らない
     けれども)
 
index e3cdf0c..e439705 100644 (file)
@@ -124,7 +124,7 @@ mtk.manpages@gmail.com의 메인테이너에게 보낼 것을 권장한다.
     메인테이너들은 이 규칙을 따르는 패치들만을 받아들일 것이고 많은 사람들이
     그 패치가 올바른 스타일일 경우만 코드를 검토할 것이다.
 
-  :ref:`Documentation/process/submitting-patches.rst <submittingpatches>` 와 :ref:`Documentation/process/submitting-drivers.rst <submittingdrivers>`
+  :ref:`Documentation/process/submitting-patches.rst <submittingpatches>`
     이 파일들은 성공적으로 패치를 만들고 보내는 법을 다음의 내용들로
     굉장히 상세히 설명하고 있다(그러나 다음으로 한정되진 않는다).
 
index fbc83df..fb023ea 100644 (file)
@@ -123,14 +123,14 @@ nr_virtfn'是要启用的VF的编号。
                ...
        }
 
-       static int dev_suspend(struct pci_dev *dev, pm_message_t state)
+       static int dev_suspend(struct device *dev)
        {
                ...
 
                return 0;
        }
 
-       static int dev_resume(struct pci_dev *dev)
+       static int dev_resume(struct device *dev)
        {
                ...
 
@@ -163,8 +163,7 @@ nr_virtfn'是要启用的VF的编号。
                .id_table =     dev_id_table,
                .probe =        dev_probe,
                .remove =       dev_remove,
-               .suspend =      dev_suspend,
-               .resume =       dev_resume,
+               .driver.pm =    &dev_pm_ops
                .shutdown =     dev_shutdown,
                .sriov_configure = dev_sriov_configure,
        };
index 5207077..83c2a41 100644 (file)
@@ -255,13 +255,13 @@ pci_set_master()将通过设置PCI_COMMAND寄存器中的总线主控位来启
 
 虽然所有的驱动程序都应该明确指出PCI总线主控的DMA功能(如32位或64位),但对于流式
 数据来说,具有超过32位总线主站功能的设备需要驱动程序通过调用带有适当参数的
-``pci_set_dma_mask()`` 来“注册”这种功能。一般来说,在系统RAM高于4G物理地址的情
+``dma_set_mask()`` 来“注册”这种功能。一般来说,在系统RAM高于4G物理地址的情
 况下,这允许更有效的DMA。
 
-所有PCI-X和PCIe兼容设备的驱动程序必须调用 ``pci_set_dma_mask()`` ,因为它们
+所有PCI-X和PCIe兼容设备的驱动程序必须调用 ``dma_set_mask()`` ,因为它们
 是64位DMA设备。
 
-同样,如果设备可以通过调用 ``pci_set_consistent_dma_mask()`` 直接寻址到
+同样,如果设备可以通过调用 ``dma_set_coherent_mask()`` 直接寻址到
 4G物理地址以上的系统RAM中的“一致性内存”,那么驱动程序也必须“注册”这种功能。同
 样,这包括所有PCI-X和PCIe兼容设备的驱动程序。许多64位“PCI”设备(在PCI-X之前)
 和一些PCI-X设备对有效载荷(“流式”)数据具有64位DMA功能,但对控制(“一致性”)数
index be535ff..2f6970d 100644 (file)
@@ -36,6 +36,7 @@ Todolist:
    :maxdepth: 1
 
    reporting-issues
+   reporting-regressions
    security-bugs
    bug-hunting
    bug-bisect
@@ -44,7 +45,6 @@ Todolist:
 
 Todolist:
 
-*   reporting-bugs
 *   ramoops
 *   dynamic-debug-howto
 *   kdump/index
index eee0e8c..2c7d910 100644 (file)
@@ -210,6 +210,8 @@ schemes/<N>/
  - ``pageout``: 为具有 ``MADV_PAGEOUT`` 的区域调用 ``madvise()`` 。
  - ``hugepage``: 为带有 ``MADV_HUGEPAGE`` 的区域调用 ``madvise()`` 。
  - ``nohugepage``: 为带有 ``MADV_NOHUGEPAGE`` 的区域调用 ``madvise()``。
+ - ``lru_prio``: 在其LRU列表上对区域进行优先排序。
+ - ``lru_deprio``: 对区域的LRU列表进行降低优先处理。
  - ``stat``: 什么都不做,只计算统计数据
 
 schemes/<N>/access_pattern/
index 6b4988d..59e51e3 100644 (file)
@@ -1,13 +1,6 @@
 .. SPDX-License-Identifier: (GPL-2.0+ OR CC-BY-4.0)
-..
-   If you want to distribute this text under CC-BY-4.0 only, please use 'The
-   Linux kernel developers' for author attribution and link this as source:
-   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/Documentation/admin-guide/reporting-issues.rst
-..
-   Note: Only the content of this RST file as found in the Linux kernel sources
-   is available under CC-BY-4.0, as versions of this text that were processed
-   (for example by the kernel's build system) might contain content taken from
-   files which use a more restrictive license.
+.. See the bottom of this file for additional redistribution information.
+
 
 .. include:: ../disclaimer-zh_CN.rst
 
@@ -29,7 +22,9 @@
 请搜索 `LKML内核邮件列表 <https://lore.kernel.org/lkml/>`_ 和
 `Linux稳定版邮件列表 <https://lore.kernel.org/stable/>`_ 存档中匹配的报告并
 加入讨论。如果找不到匹配的报告,请安装该系列的最新版本。如果它仍然出现问题,
-报告给稳定版邮件列表(stable@vger.kernel.org)。
+请报告给稳定版邮件列表(stable@vger.kernel.org)并抄送回归邮件列表
+(regressions@lists.linux.dev);理想情况下,还可以抄送维护者和相关子系统的
+邮件列表。
 
 在所有其他情况下,请尽可能猜测是哪个内核部分导致了问题。查看MAINTAINERS文件,
 了解开发人员希望如何得知问题,大多数情况下,报告问题都是通过电子邮件和抄送
 有使用附加模块)。还要确保它是在一个正常的环境中构建和运行,并且在问题发生
 之前没有被污染(tainted)。
 
-在编写报告时,要涵盖与问题相关的所有信息,如使用的内核和发行版。在碰见回归时,
-尝试给出引入它的更改的提交ID,二分可以找到它。如果您同时面临Linux内核的多个
-问题,请分别报告每个问题。
+当你同时面临Linux内核的多个问题时,请分别报告。在编写报告时,要涵盖与问题
+相关的所有信息,如使用的内核和发行版。如果碰见回归,请把报告抄送回归邮件列表
+(regressions@lists.linux.dev)。也请试试用二分法找出源头;如果成功找到,请
+在报告中写上它的提交ID并抄送sign-off-by链中的所有人。
 
 一旦报告发出,请回答任何出现的问题,并尽可能地提供帮助。这包括通过不时重新
 测试新版本并发送状态更新来推动进展。
    存在问题,因为问题可能已经在那里被修复了。如果您第一次发现供应商内核的问题,
    请检查已知最新版本的普通构建是否可以正常运行。
 
- * 向Linux稳定版邮件列表发送一个简短的问题报告(stable@vger.kernel.org)。大致
-   描述问题,并解释如何复现。讲清楚首个出现问题的版本和最后一个工作正常的版本。
-   然后等待进一步的指示。
+ * 向Linux稳定版邮件列表发送一个简短的问题报告(stable@vger.kernel.org)并抄送
+   Linux回归邮件列表(regressions@lists.linux.dev);如果你怀疑是由某子系统
+   引起的,请抄送其维护人员和子系统邮件列表。大致描述问题,并解释如何复现。
+   讲清楚首个出现问题的版本和最后一个工作正常的版本。然后等待进一步的指示。
 
 下面的参考章节部分详细解释了这些步骤中的每一步。
 
@@ -296,17 +293,14 @@ Linus Torvalds和主要的Linux内核开发人员希望看到一些问题尽快
 报告过程中有一些“高优先级问题”的处理略有不同。有三种情况符合条件:回归、安全
 问题和非常严重的问题。
 
-如果在旧版本的Linux内核中工作的东西不能在新版本的Linux内核中工作,或者某种
-程度上在新版本的Linux内核中工作得更差,那么你就需要处理“回归”。因此,当一个
-在Linux 5.7中表现良好的WiFi驱动程序在5.8中表现不佳或根本不能工作时,这是一
-种回归。如果应用程序在新的内核中出现不稳定的现象,这也是一种回归,这可能是
-由于内核和用户空间之间的接口(如procfs和sysfs)发生不兼容的更改造成的。显著
-的性能降低或功耗增加也可以称为回归。但是请记住:新内核需要使用与旧内核相似的
-配置来构建(参见下面如何实现这一点)。这是因为内核开发人员在实现新特性时有
-时无法避免不兼容性;但是为了避免回归,这些特性必须在构建配置期间显式地启用。
+如果某个应用程序或实际用例在原先的Linux内核上运行良好,但在使用类似配置编译的
+较新版本上效果更差、或者根本不能用,那么你就需要处理回归问题。
+Documentation/admin-guide/reporting-regressions.rst 对此进行了更详细的解释。
+它还提供了很多你可能想知道的关于回归的其他信息;例如,它解释了如何将您的问题
+添加到回归跟踪列表中,以确保它不会被忽略。
 
 什么是安全问题留给您自己判断。在继续之前,请考虑阅读
-“Documentation/translations/zh_CN/admin-guide/security-bugs.rst”
+Documentation/translations/zh_CN/admin-guide/security-bugs.rst 
 因为它提供了如何最恰当地处理安全问题的额外细节。
 
 当发生了完全无法接受的糟糕事情时,此问题就是一个“非常严重的问题”。例如,
@@ -390,7 +384,7 @@ Linux内核破坏了它处理的数据或损坏了它运行的硬件。当内核
 核未被污染,那么它应该以“Not infected”结束;如果你看到“Tainted:”且后跟一些
 空格和字母,那就被污染了。
 
-如果你的内核被污染了,请阅读“Documentation/translations/zh_CN/admin-guide/tainted-kernels.rst”
+如果你的内核被污染了,请阅读 Documentation/translations/zh_CN/admin-guide/tainted-kernels.rst
 以找出原因。设法消除污染因素。通常是由以下三种因素之一引起的:
 
  1. 发生了一个可恢复的错误(“kernel Oops”),内核污染了自己,因为内核知道在
@@ -591,7 +585,8 @@ ath10k@lists.infradead.org”,将引导您到ath10k邮件列表的信息页,
 搜索引擎,并添加类似“site:lists.infadead.org/pipermail/ath10k/”这
 样的搜索条件,这会把结果限制在该链接中的档案。
 
-也请进一步搜索网络、LKML和bugzilla.kernel.org网站。
+也请进一步搜索网络、LKML和bugzilla.kernel.org网站。如果你的报告需要发送到缺陷
+跟踪器中,那么您可能还需要检查子系统的邮件列表存档,因为可能有人只在那里报告了它。
 
 有关如何搜索以及在找到匹配报告时如何操作的详细信息,请参阅上面的“搜索现有报告
 (第一部分)”。
@@ -802,10 +797,10 @@ Linux 首席开发者 Linus Torvalds 认为 Linux 内核永远不应恶化,这
 重现它。
 
 有一个叫做“二分”的过程可以来寻找变化,这在
-“Documentation/translations/zh_CN/admin-guide/bug-bisect.rst”文档中进行了详细
+Documentation/translations/zh_CN/admin-guide/bug-bisect.rst 文档中进行了详细
 的描述,这个过程通常需要你构建十到二十个内核镜像,每次都尝试在构建下一个镜像
 之前重现问题。是的,这需要花费一些时间,但不用担心,它比大多数人想象的要快得多。
-多亏了“binary search二进制搜索”,这将引导你在源代码管理系统中找到导致回归的提交。
+多亏了“binary search二搜索”,这将引导你在源代码管理系统中找到导致回归的提交。
 一旦你找到它,就在网上搜索其主题、提交ID和缩短的提交ID(提交ID的前12个字符)。
 如果有的话,这将引导您找到关于它的现有报告。
 
@@ -823,10 +818,10 @@ Linux 首席开发者 Linus Torvalds 认为 Linux 内核永远不应恶化,这
 当处理回归问题时,请确保你所面临的问题真的是由内核引起的,而不是由其他东西
 引起的,如上文所述。
 
-在整个过程中,请记住:只有当旧内核和新内核的配置相似时,问题才算回归。最好
-的方法是:把配置文件(``.config``)从旧的工作内核直接复制到你尝试的每个新内
-æ ¸ç\89\88æ\9c¬ã\80\82ä¹\8bå\90\8eè¿\90è¡\8c ``make oldnoconfig`` æ\9d¥è°\83æ\95´å®\83以é\80\82åº\94æ\96°ç\89\88æ\9c¬ç\9a\84é\9c\80è¦\81ï¼\8cè\80\8cä¸\8då\90¯ç\94¨
-任何新的功能,因为那些功能也可能导致回归
+在整个过程中,请记住:只有当旧内核和新内核的配置相似时,问题才算回归。这可以
+通过 ``make olddefconfig`` 来实现,详细解释参见
+Documentation/admin-guide/reporting-regressions.rst ï¼\9bå®\83è¿\98æ\8f\90ä¾\9bäº\86大é\87\8få\85¶ä»\96æ\82¨
+可能希望了解的有关回归的信息
 
 
 撰写并发送报告
@@ -959,11 +954,19 @@ Linux 首席开发者 Linus Torvalds 认为 Linux 内核永远不应恶化,这
 **非常严重的缺陷** :确保在主题或工单标题以及第一段中明显标出 severeness
 (非常严重的)。
 
-**回归** :如果问题是一个回归,请在邮件的主题或缺陷跟踪器的标题中添加
-[REGRESSION]。如果您没有进行二分,请至少注明您测试的最新主线版本(比如 5.7)
-和出现问题的最新版本(比如 5.8)。如果您成功地进行了二分,请注明导致回归
-的提交ID和主题。也请添加该变更的作者到你的报告中;如果您需要将您的缺陷提交
-到缺陷跟踪器中,请将报告以私人邮件的形式转发给他,并注明报告提交地点。
+**回归** :报告的主题应以“[REGRESSION]”开头。
+
+如果您成功用二分法定位了问题,请使用引入回归之更改的标题作为主题的第二部分。
+请在报告中写明“罪魁祸首”的提交ID。如果未能成功二分,请在报告中讲明最后一个
+正常工作的版本(例如5.7)和最先发生问题的版本(例如5.8-rc1)。
+
+通过邮件发送报告时,请抄送Linux回归邮件列表(regressions@lists.linux.dev)。
+如果报告需要提交到某个web追踪器,请继续提交;并在提交后,通过邮件将报告转发
+至回归列表;抄送相关子系统的维护人员和邮件列表。请确保报告是内联转发的,不要
+把它作为附件。另外请在顶部添加一个简短的说明,在那里写上工单的网址。
+
+在邮寄或转发报告时,如果成功二分,需要将“罪魁祸首”的作者添加到收件人中;同时
+抄送signed-off-by链中的每个人,您可以在提交消息的末尾找到。
 
 **安全问题** :对于这种问题,你将必须评估:如果细节被公开披露,是否会对其他
 用户产生短期风险。如果不会,只需按照所述继续报告问题。如果有此风险,你需要
@@ -980,7 +983,7 @@ Linux 首席开发者 Linus Torvalds 认为 Linux 内核永远不应恶化,这
 报告,请将报告的文本转发到这些地址;但请在报告的顶部加上注释,表明您提交了
 报告,并附上工单链接。
 
-更多信息请参见“Documentation/translations/zh_CN/admin-guide/security-bugs.rst”
+更多信息请参见 Documentation/translations/zh_CN/admin-guide/security-bugs.rst 
 
 
 发布报告后的责任
@@ -1173,14 +1176,18 @@ FLOSS 问题报告的人看,询问他们的意见。同时征求他们关于
 报告回归
 ~~~~~~~~~~
 
-    *向Linux稳定版邮件列表发送一个简短的问题报告(stable@vger.kernel.org)。
-    大致描述问题,并解释如何复现。讲清楚首个出现问题的版本和最后一个工作正常
-    的版本。然后等待进一步的指示。*
+    *向Linux稳定版邮件列表发送一个简短的问题报告(stable@vger.kernel.org)并
+    抄送Linux回归邮件列表(regressions@lists.linux.dev);如果你怀疑是由某
+    子系统引起的,请抄送其维护人员和子系统邮件列表。大致描述问题,并解释如
+    何复现。讲清楚首个出现问题的版本和最后一个工作正常的版本。然后等待进一
+    步的指示。*
 
 当报告在稳定版或长期支持内核线内发生的回归(例如在从5.10.4更新到5.10.5时),
-一份简短的报告足以快速报告问题。因此只需要粗略的描述。
+一份简短的报告足以快速报告问题。因此只需向稳定版和回归邮件列表发送粗略的描述;
+不过如果你怀疑某子系统导致此问题的话,请一并抄送其维护人员和子系统邮件列表,
+这会加快进程。
 
-但是请注意,如果您能够指明引入问题的确切版本,这将对开发人员有很大帮助。因此
+请注意,如果您能够指明引入问题的确切版本,这将对开发人员有很大帮助。因此
 如果有时间的话,请尝试使用普通内核找到该版本。让我们假设发行版发布Linux内核
 5.10.5到5.10.8的更新时发生了故障。那么按照上面的指示,去检查该版本线中的最新
 内核,比如5.10.9。如果问题出现,请尝试普通5.10.5,以确保供应商应用的补丁不会
@@ -1190,7 +1197,9 @@ FLOSS 问题报告的人看,询问他们的意见。同时征求他们关于
 前一段基本粗略地概述了“二分”方法。一旦报告出来,您可能会被要求做一个正确的
 报告,因为它允许精确地定位导致问题的确切更改(然后很容易被恢复以快速修复问题)。
 因此如果时间允许,考虑立即进行适当的二分。有关如何详细信息,请参阅“对回归的
-特别关照”部分和文档“Documentation/translations/zh_CN/admin-guide/bug-bisect.rst”。
+特别关照”部分和文档 Documentation/translations/zh_CN/admin-guide/bug-bisect.rst 。
+如果成功二分的话,请将“罪魁祸首”的作者添加到收件人中;同时抄送所有在
+signed-off-by链中的人,您可以在提交消息的末尾找到。
 
 
 “报告仅在旧内核版本线中发生的问题”的参考
@@ -1207,7 +1216,7 @@ FLOSS 问题报告的人看,询问他们的意见。同时征求他们关于
 
 即使是微小的、看似明显的代码变化,有时也会带来新的、完全意想不到的问题。稳
 定版和长期支持内核的维护者非常清楚这一点,因此他们只对这些内核进行符合
-“Documentation/translations/zh_CN/process/stable-kernel-rules.rst”中所列出的
+Documentation/translations/zh_CN/process/stable-kernel-rules.rst 中所列出的
 规则的修改。
 
 复杂或有风险的修改不符合条件,因此只能应用于主线。其他的修复很容易被回溯到
@@ -1333,3 +1342,27 @@ FLOSS 问题报告的人看,询问他们的意见。同时征求他们关于
 向 Linux 内核开发者报告问题是很难的:这个文档的长度和复杂性以及字里行间的内
 涵都说明了这一点。但目前就是这样了。这篇文字的主要作者希望通过记录现状来为
 以后改善这种状况打下一些基础。
+
+
+..
+   end-of-content
+..
+   This English version of this document is maintained by Thorsten Leemhuis
+   <linux@leemhuis.info>. If you spot a typo or small mistake, feel free to
+   let him know directly and he'll fix it. For translation problems, please
+   contact with translators. You are free to do the same in a mostly informal
+   way if you want to contribute changes to the text, but for copyright
+   reasons please CC linux-doc@vger.kernel.org and "sign-off" your
+   contribution as Documentation/process/submitting-patches.rst outlines in
+   the section "Sign your work - the Developer's Certificate of Origin".
+..
+   This text is available under GPL-2.0+ or CC-BY-4.0, as stated at the top
+   of the file. If you want to distribute this text under CC-BY-4.0 only,
+   please use "The Linux kernel developers" for author attribution and link
+   this as source:
+   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/Documentation/admin-guide/reporting-issues.rst
+..
+   Note: Only the content of this RST file as found in the Linux kernel sources
+   is available under CC-BY-4.0, as versions of this text that were processed
+   (for example by the kernel's build system) might contain content taken from
+   files which use a more restrictive license.
diff --git a/Documentation/translations/zh_CN/admin-guide/reporting-regressions.rst b/Documentation/translations/zh_CN/admin-guide/reporting-regressions.rst
new file mode 100644 (file)
index 0000000..c0461ee
--- /dev/null
@@ -0,0 +1,370 @@
+.. SPDX-License-Identifier: (GPL-2.0+ OR CC-BY-4.0)
+.. 【重分发信息参见本文件结尾】
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/admin-guide/reporting-regressions.rst
+
+:译者:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+
+============
+报告回归问题
+============
+
+“*我们拒绝出现回归*”是Linux内核开发的首要规则;Linux的发起者和领军开发者Linus
+Torvalds立下了此规则并确保它被落实。
+
+本文档描述了这条规则对用户的意义,以及Linux内核开发模型如何确保解决所有被报告
+的回归;关于内核开发者如何处理的方面参见 Documentation/process/handling-regressions.rst 。
+
+
+本文重点(亦即“太长不看”)
+==========================
+
+#. 如果某程序在原先的Linux内核上运行良好,但在较新版本上效果更差、或者根本不
+   能用,那么你就碰见回归问题了。注意,新内核需要使用类似配置编译;更多相关细
+   节参见下方。
+
+#. 按照 Documentation/translations/zh_CN/admin-guide/reporting-issues.rst 中
+   所说的报告你的问题,该文档已经包含了所有关于回归的重要方面,为了方便起见也
+   复制到了下面。两个重点:在报告主题中使用“[REGRESSION]”开头并抄送或转发到
+   `回归邮件列表 <https://lore.kernel.org/regressions/>`_
+   (regressions@lists.linux.dev)。
+
+#. 可选但是建议:在发送或转发报告时,指明该回归发生的起点,以便Linux内核回归
+   追踪机器人“regzbot”可以追踪此问题::
+
+       #regzbot introduced v5.13..v5.14-rc1
+
+
+与用户相关的所有Linux内核回归细节
+=================================
+
+
+基本重点
+--------
+
+
+什么是“回归”以及什么是“无回归规则”?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+如果某程序/实例在原先的Linux内核上运行良好,但在较新版本上效果更差、或者根本
+不能用,那么你就碰见回归问题了。“无回归规则”不允许出现这种情况。如果偶然发
+生了,导致问题的开发者应当迅速修复问题。
+
+也就是说,若Linux 5.13中的WiFi驱动程序运行良好,但是在5.14版本上却不能用、速
+度明显变慢或出现错误,那就出现了回归。如果某正常工作的应用程序突然在新内核上
+出现不稳定,这也是回归;这些问题可能是由于procfs、sysfs或Linux提供给用户空间
+软件的许多其他接口之一的变化。但请记住,前述例子中的5.14需要使用类似于5.13的
+配置构建。这可以用 ``make olddefconfig`` 实现,详细解释见下。
+
+注意本节第一句话中的“实例”:即使开发者需要遵循“无回归”规则,但仍可自由地改
+变内核的任何方面,甚至是导出到用户空间的API或ABI,只要别破坏现有的应用程序或
+用例。
+
+还需注意,“无回归”规则只限制内核提供给用户空间的接口。它不适用于内核内部接
+口,比如一些外部开发的驱动程序用来插入钩子到内核的模块API。
+
+如何报告回归?
+~~~~~~~~~~~~~~
+
+只需按照 Documentation/translations/zh_CN/admin-guide/reporting-issues.rst 中
+所说的报告你的问题,该文档已经包含了要点。下面几点概述了一下只在回归中重要的
+方面:
+
+ * 在检查可加入讨论的现有报告时,别忘了搜索 `Linux回归邮件列表
+   <https://lore.kernel.org/regressions/>`_ 和 `regzbot网页界面
+   <https://linux-regtracking.leemhuis.info/regzbot/>`_ 。
+
+ * 在报告主题的开头加上“[REGRESSION]”。
+
+ * 在你的报告中明确最后一个正常工作的内核版本和首个出问题的版本。如若可能,
+   用二分法尝试找出导致回归的变更,更多细节见下。
+
+ * 记得把报告发到Linux回归邮件列表(regressions@lists.linux.dev)。
+
+   * 如果通过邮件报告回归,请抄送回归列表。
+
+   * 如果你使用某些缺陷追踪器报告回归,请通过邮件转发已提交的报告到回归列表,
+     并抄送维护者以及出问题的相关子系统的邮件列表。
+
+   如果是稳定版或长期支持版系列(如v5.15.3…v5.15.5)的回归,请记得抄送
+   `Linux稳定版邮件列表 <https://lore.kernel.org/stable/>`_ (stable@vger.kernel.org)。
+
+  如果你成功地执行了二分,请抄送肇事提交的信息中所有签了“Signed-off-by:”的人。
+
+在抄送你的报告到列表时,也请记得通知前述的Linux内核回归追踪机器人。只需在邮件
+中包含如下片段::
+
+       #regzbot introduced: v5.13..v5.14-rc1
+
+Regzbot会就将你的邮件视为在某个特定版本区间的回归报告。上例中即linux v5.13仍
+然正常,而Linux 5.14-rc1是首个您遇到问题的版本。如果你执行了二分以查找导致回
+归的提交,请使用指定肇事提交的id代替::
+
+       #regzbot introduced: 1f2e3d4c5d
+
+添加这样的“regzbot命令”对你是有好处的,它会确保报告不会被忽略。如果你省略了
+它,Linux内核的回归跟踪者会把你的回归告诉regzbot,只要你发送了一个副本到回归
+邮件列表。但是回归跟踪者只有一个人,有时不得不休息或甚至偶尔享受可以远离电脑
+的时光(听起来很疯狂)。因此,依赖此人手动将回归添加到 `已追踪且尚未解决的
+Linux内核回归列表 <https://linux-regtracking.leemhuis.info/regzbot/>`_ 和
+regzbot发送的每周回归报告,可能会出现延迟。 这样的延误会导致Linus Torvalds
+在决定“继续开发还是发布新版本?”时忽略严重的回归。
+
+真的修复了所有的回归吗?
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+几乎所有都是,只要引起问题的变更(肇事提交)被可靠定位。也有些回归可以不用这
+样,但通常是必须的。
+
+谁需要找出回归的根本原因?
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+受影响代码区域的开发者应该自行尝试定位问题所在。但仅靠他们的努力往往是不可
+能做到的,很多问题只发生在开发者的无法接触的其他特定外部环境中——例如特定的
+硬件平台、固件、Linux发行版、系统的配置或应用程序。这就是为什么最终往往是报
+告者定位肇事提交;有时用户甚至需要再运行额外测试以查明确切的根本原因。开发
+者应该提供建议和可能的帮助,以使普通用户更容易完成该流程。
+
+如何找到罪魁祸首?
+~~~~~~~~~~~~~~~~~~
+
+如 Documentation/translations/zh_CN/admin-guide/reporting-issues.rst (简要)
+和 Documentation/translations/zh_CN/admin-guide/bug-bisect.rst (详细)中所
+述,执行二分。听起来工作量很大,但大部分情况下很快就能找到罪魁祸首。如果这很
+困难或可靠地重现问题很耗时,请考虑与其他受影响的用户合作,一起缩小搜索范围。
+
+当出现回归时我可以向谁寻求建议?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+发送邮件到回归邮件列表(regressions@lists.linux.dev)同时抄送Linux内核的回归
+跟踪者(regressions@leemhuis.info);如果问题需要保密处理,可以省略列表。
+
+
+关于回归的更多细节
+------------------
+
+
+“无回归规则”的目标是什么?
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+用户应该放心升级内核版本,而不必担心有程序可能崩溃。这符合内核开发者的利益,
+可以使更新有吸引力:他们不希望用户停留在停止维护或超过一年半的稳定/长期Linux
+版本系列上。这也符合所有人的利益,因为 `那些系列可能含有已知的缺陷、安全问题
+或其他后续版本已经修复的问题
+<http://www.kroah.com/log/blog/2018/08/24/what-stable-kernel-should-i-use/>`_ 。
+此外,内核开发者希望使用户测试最新的预发行版或常规发行版变得简单而有吸引力。
+这同样符合所有人的利益,如果新版本出来后很快就有相关报告,会使追踪和修复问题
+更容易。
+
+实际中“无回归”规则真的可行吗?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+这不是句玩笑话,请见Linux创建者和主要开发人员Linus Torvalds在邮件列表中的许
+多发言,其中一些在 Documentation/process/handling-regressions.rst 中被引用。
+
+此规则的例外情况极为罕见;之前当开发者认为某个特定的情况有必要援引例外时,
+基本都被证明错了。
+
+谁来确保“无回归”被落实?
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+照看和支撑树的子系统维护者应该关心这一点——例如,Linus Torvalds之于主线,
+Greg Kroah-Hartman等人之于各种稳定/长期系列。
+
+他们都得到了别人的帮助,以确保回归报告不会被遗漏。其中之一是Thorsten
+Leemhuis,他目前担任Linux内核的“回归跟踪者”;为了做好这项工作,他使用了
+regzbot——Linux内核回归跟踪机器人。所以这就是为什么要抄送或转发你的报告到
+回归邮件列表来通知这些人,已经最好在你的邮件中包含“regzbot命令”来立即追踪它。
+
+回归通常多久能修复?
+~~~~~~~~~~~~~~~~~~~~
+
+开发者应该尽快修复任何被报告的回归,以提供及时为受影响的用户提供解决方案,并
+防止更多用户遇到问题;然而,开发人员需要花足够的时间和注意力确保回归修复不会
+造成额外的损害。
+
+因此,答案取决于各种因素,如回归的影响、存在时长或出现于哪个Linux版本系列。
+但最终,大多数的回归应该在两周内修复。
+
+当问题可以通过升级某些软件解决时,是回归吗?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+基本都是。如果开发人员告诉您其他情况,请咨询上述回归跟踪者。
+
+当新内核变慢或能耗增加,是回归吗?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+是的,但有一些差别。在微型基准测试中变慢5%不太可能被视为回归,除非它也会对
+广泛基准测试的结果产生超过1%的影响。如果有疑问,请寻求建议。
+
+当更新Linux时外部内核模块崩溃了,是回归吗?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+不,因为“无回归”规则仅限于Linux内核提供给用户空间的接口和服务。因此,它不包括
+构建或运行外部开发的内核模块,因为它们在内核空间中运行与挂进内核使用的内部接
+口偶尔会变化。
+
+如何处理安全修复引起的回归?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+在极为罕见的情况下,安全问题无法在不引起回归的情况下修复;这些修复都被放弃了,
+因为它们终究会引起问题。幸运的是这种两难境地基本都可以避免,受影响区域的主要
+开发者以及Linus Torvalds本人通常都会努力在不引入回归的情况下解决安全问题。
+
+如果你仍然面临此种情况,请查看邮件列表档案是否有人尽力避免过回归。如果没有,
+请报告它;如有疑问,请如上所述寻求建议。
+
+当修复回归时不可避免会引入另一个,如何处理?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+很遗憾这种事确实会出现,但幸运的是并不经常出现;如果发生了,受影响代码区的资
+深开发者应当调查该问题以找到避免回归的解决方法,至少避免它们的影响。如果你遇
+到这样的情况,如上所述:检查之前的讨论是否有人已经尽了最大努力,如有疑问请寻
+求建议。
+
+小提示:如果人们在每个开发周期中定期给出主线预发布(即v5.15-rc1或-rc3)以供
+测试,则可以避免这种情况。为了更好地解释,可以设想一个在Linux v5.14和v5.15-rc1
+之间集成的更改,该更改导致了回归,但同时是应用于5.15-rc1的其他改进的强依赖。
+如果有人在5.15发布之前就发现并报告了这个问题,那么所有更改都可以直接撤销,从
+而解决回归问题。而就在几天或几周后,此解决方案变成了不可能,因为一些软件可能
+已经开始依赖于后续更改之一:撤销所有更改将导致上述用户软件出现回归,这是不可
+接受的。
+
+若我所依赖的功能在数月前被移除了,是回归吗?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+是的,但如前节所述,通常很难修复此类回归。因此需要逐案处理。这也是定期测试主
+线预发布对所有人有好处的另一个原因。
+
+如果我似乎是唯一受影响的人,是否仍适用“无回归”规则?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+适用,但仅限于实际使用:Linux开发人员希望能够自由地取消那些只能在阁楼和博物
+馆中找到的硬件的支持。
+
+请注意,有时为了取得进展,不得不出现回归——后者也是防止Linux停滞不前所必需
+的。因此如果回归所影响的用户很少,那么为了他们和其他人更大的利益,还是让事情
+过去吧。尤其是存在某种规避回归的简单方法,例如更新一些软件或者使用专门为此目
+的创建的内核参数。
+
+回归规则是否也适用于staging树中的代码?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+不,参见 `适用于所有staging代码配置选项的帮助文本
+<https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/staging/Kconfig>`_ ,
+其早已声明::
+
+       请注意:这些驱动正在积极开发中,可能无法正常工作,并可能包含会在不久的
+       将来发生变化的用户接口。
+
+虽然staging开发人员通常坚持“无回归”的原则,但有时为了取得进展也会违背它。这就
+是为什么当staging树的WiFi驱动被基本推倒重来时,有些用户不得不处理回归(通常可
+以忽略)。
+
+为什么较新版本必须“使用相似配置编译”?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+因为Linux内核开发人员有时会集成已知的会导致回归的变更,但使它们成为可选的,并
+在内核的默认配置下禁用它们。这一技巧允许进步,否则“无回归”规则将导致停滞。
+
+例如,试想一个新的可以阻止恶意软件滥用某个内核的接口的安全特性,同时又需要满足
+另一个很罕见的应用程序。上述的方法可使两方都满意:使用这些应用程序的人可以关闭
+新的安全功能,而其他不会遇到麻烦的人可以启用它。
+
+如何创建与旧内核相似的配置?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+用一个已知良好的内核启动机器,并用 ``make olddefconfig`` 配置新版的Linux。这
+会让内核的构建脚本从正在运行的内核中摘录配置文件(“.config”文件),作为即将编
+译的新版本的基础配置;同时将所有新的配置选项设为默认值,以禁用可能导致回归的
+新功能。
+
+如何报告在预编译的普通内核中发现的回归?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+您需要确保新的内核是用与旧版相似的配置编译(见上文),因为那些构建它们的人可
+能启用了一些已知的与新内核不兼容的特性。如有疑问,请向内核的提供者报告问题并
+寻求建议。
+
+
+用“regzbot”追踪回归的更多信息
+-----------------------------
+
+什么是回归追踪?为啥我需要关心它?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+像“无回归”这样的规则需要有人来确保它们被遵守,否则会被有意/无意打破。历史证
+明了这一点对于Linux内核开发也适用。这就是为什么Linux内核的回归跟踪者Thorsten
+Leemhuis,,和另一些人尽力关注所有的回归直到他们解决。他们从未为此获得报酬,
+因此这项工作是在尽最大努力的基础上完成的。
+
+为什么/如何使用机器人追踪Linux内核回归?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+由于Linux内核开发过程的分布式和松散结构,完全手动跟踪回归已经被证明是相当困难
+的。因此Linux内核的回归跟踪者开发了regzbot来促进这项工作,其长期目标是尽可能为
+所有相关人员自动化回归跟踪。
+
+Regzbot通过监视跟踪的回归报告的回复来工作。此外,它还查找用“Link:”标签引用这
+些报告的补丁;对这些补丁的回复也会被跟踪。结合这些数据,可以很好地了解当前修
+复过程的状态。
+
+如何查看regzbot当前追踪的回归?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+参见 `regzbot在线 <https://linux-regtracking.leemhuis.info/regzbot/>`_ 。
+
+何种问题可以由regzbot追踪?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+该机器人只为了跟踪回归,因此请不要让regzbot涉及常规问题。但是对于Linux内核的
+回归跟踪者来说,让regzbot跟踪严重问题也可以,如有关挂起、损坏数据或内部错误
+(Panic、Oops、BUG()、warning…)的报告。
+
+如何修改被追踪回归的相关信息?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+在直接或间接回复报告邮件时使用“regzbot命令”即可。最简单的方法是:在“已发送”文
+件夹或邮件列表存档中找到报告,然后使用邮件客户端的“全部回复”功能对其进行回复。
+在该邮件中的独立段落中可使用以下命令之一(即使用空行将这些命令中的一个或多个与
+其余邮件文本分隔开)。
+
+ * 更新回归引入起点,例如在执行二分之后::
+
+       #regzbot introduced: 1f2e3d4c5d
+
+ * 设置或更新标题::
+
+       #regzbot title: foo
+
+ * 监视讨论或bugzilla.kernel.org上有关讨论或修复的工单::
+
+       #regzbot monitor: https://lore.kernel.org/r/30th.anniversary.repost@klaava.Helsinki.FI/
+       #regzbot monitor: https://bugzilla.kernel.org/show_bug.cgi?id=123456789
+
+ * 标记一个有更多相关细节的地方,例如有关但主题不同的邮件列表帖子或缺陷追踪器中的工单::
+
+       #regzbot link: https://bugzilla.kernel.org/show_bug.cgi?id=123456789
+
+ * 标记回归已失效::
+
+       #regzbot invalid: wasn't a regression, problem has always existed
+
+Regzbot还支持其他一些主要由开发人员或回归追踪人员使用的命令。命令的更多细节请
+参考 `入门指南 <https://gitlab.com/knurd42/regzbot/-/blob/main/docs/getting_started.md>`_
+和 `参考手册 <https://gitlab.com/knurd42/regzbot/-/blob/main/docs/reference.md>`_ 。
+
+..
+   正文结束
+..
+   如本文件开头所述,本文以GPL-2.0+或CC-BY-4.0许可发行。如您想仅在CC-BY-4.0许
+   可下重分发本文,请用“Linux内核开发者”作为作者,并用如下链接作为来源:
+   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/Documentation/translations/zh_CN/admin-guide/reporting-regressions.rst
+..
+   注意:本RST文件内容只有在来自Linux内核源代码时是使用CC-BY-4.0许可的,因为经
+   过处理的版本(如经内核的构建系统)可能包含来自使用更严格许可证的文件的内容。
index 6fee45f..b4a76ec 100644 (file)
@@ -5,6 +5,7 @@
 :翻译:
 
  司延腾 Yanteng Si <siyanteng@loongson.cn>
+ 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
 
 :校译:
 
@@ -278,6 +279,11 @@ HyperSparc cpu就是这样一个具有这种属性的cpu。
                                CPU上,因为它将cpu存储到页面上,使其变脏。同样,请看
                                sparc64关于如何处理这个问题的例子。
 
+  ``void flush_dcache_folio(struct folio *folio)``
+
+       该函数的调用情形与flush_dcache_page()相同。它允许架构针对刷新整个
+       folio页面进行优化,而不是一次刷新一页。
+
   ``void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
   unsigned long user_vaddr, void *dst, void *src, int len)``
   ``void copy_from_user_page(struct vm_area_struct *vma, struct page *page,
index 85a2642..4772a90 100644 (file)
@@ -4,6 +4,7 @@
 :翻译:
 
  司延腾 Yanteng Si <siyanteng@loongson.cn>
+ 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
 
 :校译:
 
 内核中的CPU热拔插
 =================
 
-:时间: 2016年12
+:时间: 2021年9
 :作者: Sebastian Andrzej Siewior <bigeasy@linutronix.de>,
-          Rusty Russell <rusty@rustcorp.com.au>,
-          Srivatsa Vaddagiri <vatsa@in.ibm.com>,
-          Ashok Raj <ashok.raj@intel.com>,
-          Joel Schopp <jschopp@austin.ibm.com>
+       Rusty Russell <rusty@rustcorp.com.au>,
+       Srivatsa Vaddagiri <vatsa@in.ibm.com>,
+       Ashok Raj <ashok.raj@intel.com>,
+       Joel Schopp <jschopp@austin.ibm.com>,
+       Thomas Gleixner <tglx@linutronix.de>
 
 简介
 ====
@@ -139,7 +141,7 @@ CPU的热拔插协作
 下线情况
 --------
 
-ä¸\80æ\97¦CPU被é\80»è¾\91å\85³é\97­ï¼\8c注å\86\8cç\9a\84ç\83­æ\8f\92æ\8b\94ç\8a¶æ\80\81ç\9a\84æ¸\85é\99¤å\9b\9eè°\83å°\86被è°\83ç\94¨ï¼\8cä»\8e ``CPUHP_ONLINE`` å¼\80å§\8bï¼\8cå\9c¨
+ä¸\80æ\97¦CPU被é\80»è¾\91å\85³é\97­ï¼\8c注å\86\8cç\9a\84ç\83­æ\8f\92æ\8b\94ç\8a¶æ\80\81ç\9a\84æ¸\85é\99¤å\9b\9eè°\83å°\86被è°\83ç\94¨ï¼\8cä»\8e ``CPUHP_ONLINE`` å¼\80å§\8bï¼\8cå\88°
 ``CPUHP_OFFLINE`` 状态结束。这包括:
 
 * 如果任务因暂停操作而被冻结,那么 *cpuhp_tasks_frozen* 将被设置为true。
@@ -154,82 +156,399 @@ CPU的热拔插协作
 * 一旦所有的服务被迁移,内核会调用一个特定的例程 ``__cpu_disable()`` 来进行特定的清
   理。
 
-使用热插拔API
--------------
+CPU热插拔API
+============
+
+CPU热拔插状态机
+---------------
+
+CPU热插拔使用一个从CPUHP_OFFLINE到CPUHP_ONLINE的线性状态空间的普通状态机。每个状态都
+有一个startup和teardown的回调。
+
+当一个CPU上线时,将按顺序调用startup回调,直到达到CPUHP_ONLINE状态。当设置状态的回调
+或将实例添加到多实例状态时,也可以调用它们。
+
+当一个CPU下线时,将按相反的顺序依次调用teardown回调,直到达到CPUHP_OFFLINE状态。当删
+除状态的回调或从多实例状态中删除实例时,也可以调用它们。
+
+如果某个使用场景只需要一个方向的热插拔操作回调(CPU上线或CPU下线),则在设置状态时,
+可以将另一个不需要的回调设置为NULL。
+
+状态空间被划分成三个阶段:
+
+* PREPARE阶段
+
+  PREPARE阶段涵盖了从CPUHP_OFFLINE到CPUHP_BRINGUP_CPU之间的状态空间。
+
+  在该阶段中,startup回调在CPU上线操作启动CPU之前被调用,teardown回调在CPU下线操作使
+  CPU功能失效之后被调用。
+
+  这些回调是在控制CPU上调用的,因为它们显然不能在热插拔的CPU上运行,此时热插拔的CPU要
+  么还没有启动,要么已经功能失效。
+
+  startup回调用于设置CPU成功上线所需要的资源。teardown回调用于释放资源或在热插拔的CPU
+  功能失效后,将待处理的工作转移到在线的CPU上。
+
+  允许startup回调失败。如果回调失败,CPU上线操作被中止,CPU将再次被降到之前的状态(通
+  常是CPUHP_OFFLINE)。
+
+  本阶段中的teardown回调不允许失败。
+
+* STARTING阶段
+
+  STARTING阶段涵盖了CPUHP_BRINGUP_CPU + 1到CPUHP_AP_ONLINE之间的状态空间。
+
+  该阶段中的startup回调是在早期CPU设置代码中的CPU上线操作期间,禁用中断的情况下在热拔
+  插的CPU上被调用。teardown回调是在CPU完全关闭前不久的CPU下线操作期间,禁用中断的情况
+  下在热拔插的CPU上被调用。
+
+  该阶段中的回调不允许失败。
+
+  回调用于低级别的硬件初始化/关机和核心子系统。
+
+* ONLINE阶段
+
+  ONLINE阶段涵盖了CPUHP_AP_ONLINE + 1到CPUHP_ONLINE之间的状态空间。
+
+  该阶段中的startup回调是在CPU上线时在热插拔的CPU上调用的。teardown回调是在CPU下线操
+  作时在热插拔CPU上调用的。
+
+  回调是在每个CPU热插拔线程的上下文中调用的,该线程绑定在热插拔的CPU上。回调是在启用
+  中断和抢占的情况下调用的。
+
+  允许回调失败。如果回调失败,CPU热插拔操作被中止,CPU将恢复到之前的状态。
+
+CPU 上线/下线操作
+-----------------
+
+一个成功的上线操作如下::
+
+  [CPUHP_OFFLINE]
+  [CPUHP_OFFLINE + 1]->startup()       -> 成功
+  [CPUHP_OFFLINE + 2]->startup()       -> 成功
+  [CPUHP_OFFLINE + 3]                  -> 略过,因为startup == NULL
+  ...
+  [CPUHP_BRINGUP_CPU]->startup()       -> 成功
+  === PREPARE阶段结束
+  [CPUHP_BRINGUP_CPU + 1]->startup()   -> 成功
+  ...
+  [CPUHP_AP_ONLINE]->startup()         -> 成功
+  === STARTUP阶段结束
+  [CPUHP_AP_ONLINE + 1]->startup()     -> 成功
+  ...
+  [CPUHP_ONLINE - 1]->startup()        -> 成功
+  [CPUHP_ONLINE]
+
+一个成功的下线操作如下::
+
+  [CPUHP_ONLINE]
+  [CPUHP_ONLINE - 1]->teardown()       -> 成功
+  ...
+  [CPUHP_AP_ONLINE + 1]->teardown()    -> 成功
+  === STARTUP阶段开始
+  [CPUHP_AP_ONLINE]->teardown()        -> 成功
+  ...
+  [CPUHP_BRINGUP_ONLINE - 1]->teardown()
+  ...
+  === PREPARE阶段开始
+  [CPUHP_BRINGUP_CPU]->teardown()
+  [CPUHP_OFFLINE + 3]->teardown()
+  [CPUHP_OFFLINE + 2]                  -> 略过,因为teardown == NULL
+  [CPUHP_OFFLINE + 1]->teardown()
+  [CPUHP_OFFLINE]
+
+一个失败的上线操作如下::
+
+  [CPUHP_OFFLINE]
+  [CPUHP_OFFLINE + 1]->startup()       -> 成功
+  [CPUHP_OFFLINE + 2]->startup()       -> 成功
+  [CPUHP_OFFLINE + 3]                  -> 略过,因为startup == NULL
+  ...
+  [CPUHP_BRINGUP_CPU]->startup()       -> 成功
+  === PREPARE阶段结束
+  [CPUHP_BRINGUP_CPU + 1]->startup()   -> 成功
+  ...
+  [CPUHP_AP_ONLINE]->startup()         -> 成功
+  === STARTUP阶段结束
+  [CPUHP_AP_ONLINE + 1]->startup()     -> 成功
+  ---
+  [CPUHP_AP_ONLINE + N]->startup()     -> 失败
+  [CPUHP_AP_ONLINE + (N - 1)]->teardown()
+  ...
+  [CPUHP_AP_ONLINE + 1]->teardown()
+  === STARTUP阶段开始
+  [CPUHP_AP_ONLINE]->teardown()
+  ...
+  [CPUHP_BRINGUP_ONLINE - 1]->teardown()
+  ...
+  === PREPARE阶段开始
+  [CPUHP_BRINGUP_CPU]->teardown()
+  [CPUHP_OFFLINE + 3]->teardown()
+  [CPUHP_OFFLINE + 2]                  -> 略过,因为teardown == NULL
+  [CPUHP_OFFLINE + 1]->teardown()
+  [CPUHP_OFFLINE]
+
+一个失败的下线操作如下::
+
+  [CPUHP_ONLINE]
+  [CPUHP_ONLINE - 1]->teardown()       -> 成功
+  ...
+  [CPUHP_ONLINE - N]->teardown()       -> 失败
+  [CPUHP_ONLINE - (N - 1)]->startup()
+  ...
+  [CPUHP_ONLINE - 1]->startup()
+  [CPUHP_ONLINE]
+
+递归失败不能被合理地处理。
+请看下面的例子,由于下线操作失败而导致的递归失败::
+
+  [CPUHP_ONLINE]
+  [CPUHP_ONLINE - 1]->teardown()       -> 成功
+  ...
+  [CPUHP_ONLINE - N]->teardown()       -> 失败
+  [CPUHP_ONLINE - (N - 1)]->startup()  -> 成功
+  [CPUHP_ONLINE - (N - 2)]->startup()  -> 失败
+
+CPU热插拔状态机在此停止,且不再尝试回滚,因为这可能会导致死循环::
+
+  [CPUHP_ONLINE - (N - 1)]->teardown() -> 成功
+  [CPUHP_ONLINE - N]->teardown()       -> 失败
+  [CPUHP_ONLINE - (N - 1)]->startup()  -> 成功
+  [CPUHP_ONLINE - (N - 2)]->startup()  -> 失败
+  [CPUHP_ONLINE - (N - 1)]->teardown() -> 成功
+  [CPUHP_ONLINE - N]->teardown()       -> 失败
+
+周而复始,不断重复。在这种情况下,CPU留在该状态中::
+
+  [CPUHP_ONLINE - (N - 1)]
+
+这至少可以让系统取得进展,让用户有机会进行调试,甚至解决这个问题。
+
+分配一个状态
+------------
+
+有两种方式分配一个CPU热插拔状态:
+
+* 静态分配
+
+  当子系统或驱动程序有相对于其他CPU热插拔状态的排序要求时,必须使用静态分配。例如,
+  在CPU上线操作期间,PERF核心startup回调必须在PERF驱动startup回调之前被调用。在CPU
+  下线操作中,驱动teardown回调必须在核心teardown回调之前调用。静态分配的状态由
+  cpuhp_state枚举中的常量描述,可以在include/linux/cpuhotplug.h中找到。
+
+  在适当的位置将状态插入枚举中,这样就满足了排序要求。状态常量必须被用于状态的设置
+  和移除。
+
+  当状态回调不是在运行时设置的,并且是kernel/cpu.c中CPU热插拔状态数组初始化的一部分
+  时,也需要静态分配。
+
+* 动态分配
+
+  当对状态回调没有排序要求时,动态分配是首选方法。状态编号由setup函数分配,并在成功
+  后返回给调用者。
+
+  只有PREPARE和ONLINE阶段提供了一个动态分配范围。STARTING阶段则没有,因为该部分的大多
+  数回调都有明确的排序要求。
+
+CPU热插拔状态的设置
+-------------------
+
+核心代码提供了以下函数用来设置状态:
+
+* cpuhp_setup_state(state, name, startup, teardown)
+* cpuhp_setup_state_nocalls(state, name, startup, teardown)
+* cpuhp_setup_state_cpuslocked(state, name, startup, teardown)
+* cpuhp_setup_state_nocalls_cpuslocked(state, name, startup, teardown)
+
+对于一个驱动程序或子系统有多个实例,并且每个实例都需要调用相同的CPU hotplug状态回
+调的情况,CPU hotplug核心提供多实例支持。与驱动程序特定的实例列表相比,其优势在于
+与实例相关的函数完全针对CPU hotplug操作进行序列化,并在添加和删除时提供状态回调的
+自动调用。要设置这样一个多实例状态,可以使用以下函数:
+
+* cpuhp_setup_state_multi(state, name, startup, teardown)
+
+@state参数要么是静态分配的状态,要么是动态分配状态(PUHP_PREPARE_DYN,CPUHP_ONLINE_DYN)
+的常量之一, 具体取决于应该分配动态状态的状态阶段(PREPARE,ONLINE)。
+
+@name参数用于sysfs输出和检测。命名惯例是"subsys:mode"或"subsys/driver:mode",
+例如 "perf:mode"或"perf/x86:mode"。常见的mode名称有:
+
+======== ============================================
+prepare  对应PREPARE阶段中的状态
+
+dead     对应PREPARE阶段中不提供startup回调的状态
+
+starting 对应STARTING阶段中的状态
+
+dying    对应STARTING阶段中不提供startup回调的状态
+
+online   对应ONLINE阶段中的状态
+
+offline  对应ONLINE阶段中不提供startup回调的状态
+======== ============================================
+
+由于@name参数只用于sysfs和检测,如果其他mode描述符比常见的描述符更好地描述状态的性质,
+也可以使用。
+
+@name参数的示例:"perf/online", "perf/x86:prepare", "RCU/tree:dying", "sched/waitempty"
+
+@startup参数是一个指向回调的函数指针,在CPU上线操作时被调用。若应用不需要startup
+回调,则将该指针设为NULL。
+
+@teardown参数是一个指向回调的函数指针,在CPU下线操作时调用。若应用不需要teardown
+回调,则将该指针设为NULL。
+
+这些函数在处理已注册回调的方式上有所不同:
+
+  * cpuhp_setup_state_nocalls(), cpuhp_setup_state_nocalls_cpuslocked()和
+    cpuhp_setup_state_multi()只注册回调。
+
+  * cpuhp_setup_state()和cpuhp_setup_state_cpuslocked()注册回调,并对当前状态大于新
+    安装状态的所有在线CPU调用@startup回调(如果不是NULL)。根据状态阶段,回调要么在
+    当前的CPU上调用(PREPARE阶段),要么在CPU的热插拔线程中调用每个在线CPU(ONLINE阶段)。
+
+    如果CPU N的回调失败,那么CPU 0...N-1的teardown回调被调用以回滚操作。状态设置失败,
+    状态的回调没有被注册,在动态分配的情况下,分配的状态被释放。
+
+状态设置和回调调用是针对CPU热拔插操作进行序列化的。如果设置函数必须从CPU热插拔的读
+锁定区域调用,那么必须使用_cpuslocked()变体。这些函数不能在CPU热拔插回调中使用。
+
+函数返回值:
+  ======== ==========================================================
+  0        静态分配的状态设置成功
+
+  >0       动态分配的状态设置成功
+
+           返回的数值是被分配的状态编号。如果状态回调后来必须被移除,
+           例如模块移除,那么这个数值必须由调用者保存,并作为状态移
+           除函数的@state参数。对于多实例状态,动态分配的状态编号也
+           需要作为实例添加/删除操作的@state参数。
+
+  <0      操作失败
+  ======== ==========================================================
+
+移除CPU热拔插状态
+-----------------
+
+为了移除一个之前设置好的状态,提供了如下函数:
+
+* cpuhp_remove_state(state)
+* cpuhp_remove_state_nocalls(state)
+* cpuhp_remove_state_nocalls_cpuslocked(state)
+* cpuhp_remove_multi_state(state)
+
+@state参数要么是静态分配的状态,要么是由cpuhp_setup_state*()在动态范围内分配
+的状态编号。如果状态在动态范围内,则状态编号被释放,可再次进行动态分配。
+
+这些函数在处理已注册回调的方式上有所不同:
+
+  * cpuhp_remove_state_nocalls(), cpuhp_remove_state_nocalls_cpuslocked()
+    和 cpuhp_remove_multi_state()只删除回调。
+
+  * cpuhp_remove_state()删除回调,并调用所有当前状态大于被删除状态的在线CPU的
+    teardown回调(如果不是NULL)。根据状态阶段,回调要么在当前的CPU上调用
+    (PREPARE阶段),要么在CPU的热插拔线程中调用每个在线CPU(ONLINE阶段)。
+
+    为了完成移除工作,teardown回调不能失败。
+
+状态移除和回调调用是针对CPU热拔插操作进行序列化的。如果移除函数必须从CPU hotplug
+读取锁定区域调用,那么必须使用_cpuslocked()变体。这些函数不能从CPU热插拔的回调中使用。
+
+如果一个多实例的状态被移除,那么调用者必须先移除所有的实例。
+
+多实例状态实例管理
+------------------
+
+一旦多实例状态被建立,实例就可以被添加到状态中:
 
-一旦一个CPU下线或上线,就有可能收到通知。这对某些需要根据可用CPU数量执行某种设置或清
-理功能的驱动程序来说可能很重要::
+  * cpuhp_state_add_instance(state, node)
+  * cpuhp_state_add_instance_nocalls(state, node)
 
-  #include <linux/cpuhotplug.h>
+@state参数是一个静态分配的状态或由cpuhp_setup_state_multi()在动态范围内分配的状
+态编号。
 
-  ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "X/Y:online",
-                          Y_online, Y_prepare_down);
+@node参数是一个指向hlist_node的指针,它被嵌入到实例的数据结构中。这个指针被交给
+多实例状态的回调,可以被回调用来通过container_of()检索到实例。
 
-*X* 是子系统, *Y* 是特定的驱动程序。 *Y_online* 回调将在所有在线CPU的注册过程中被调用。
-如果在线回调期间发生错误, *Y_prepare_down*  回调将在所有之前调用过在线回调的CPU上调
-用。注册完成后,一旦有CPU上线, *Y_online* 回调将被调用,当CPU关闭时, *Y_prepare_down*
-将被调用。所有之前在 *Y_online* 中分配的资源都应该在 *Y_prepare_down* 中释放。如果在
-注册过程中发生错误,返回值 *ret* 为负值。否则会返回一个正值,其中包含动态分配状态
-( *CPUHP_AP_ONLINE_DYN* )的分配热拔插。对于预定义的状态,它将返回0。
+这些函数在处理已注册回调的方式上有所不同:
 
-该回调可以通过调用 ``cpuhp_remove_state()`` 来删除。如果是动态分配的状态
-( *CPUHP_AP_ONLINE_DYN* ),则使用返回的状态。在移除热插拔状态的过程中,将调用拆解回调。
+  * cpuhp_state_add_instance_nocalls()只将实例添加到多实例状态的节点列表中。
 
-多个实例
-~~~~~~~~
+  * cpuhp_state_add_instance()为所有当前状态大于@state的在线CPU添加实例并调用与
+    @state相关的startup回调(如果不是NULL)。该回调只对将要添加的实例进行调用。
+    根据状态阶段,回调要么在当前的CPU上调用(PREPARE阶段),要么在CPU的热插拔线
+    程中调用每个在线CPU(ONLINE阶段)。
 
-如果一个驱动程序有多个实例,并且每个实例都需要独立执行回调,那么很可能应该使用
-``multi-state`` 。首先需要注册一个多状态的状态::
+    如果CPU N的回调失败,那么CPU 0 ... N-1的teardown回调被调用以回滚操作,该函数
+    失败,实例不会被添加到多实例状态的节点列表中。
 
-  ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "X/Y:online,
-                                Y_online, Y_prepare_down);
-  Y_hp_online = ret;
+要从状态的节点列表中删除一个实例,可以使用这些函数:
 
-``cpuhp_setup_state_multi()`` 的行为与 ``cpuhp_setup_state()`` 类似,只是它
-为多状态准备了回调,但不调用回调。这是一个一次性的设置。
-一旦分配了一个新的实例,你需要注册这个新实例::
+  * cpuhp_state_remove_instance(state, node)
+  * cpuhp_state_remove_instance_nocalls(state, node)
 
-  ret = cpuhp_state_add_instance(Y_hp_online, &d->node);
+参数与上述cpuhp_state_add_instance*()变体相同。
 
-这个函数将把这个实例添加到你先前分配的 ``Y_hp_online`` 状态,并在所有在线的
-CPU上调用先前注册的回调( ``Y_online`` )。 *node* 元素是你的每个实例数据结构
-中的一个 ``struct hlist_node`` 成员。
+这些函数在处理已注册回调的方式上有所不同:
 
-在移除该实例时::
+  * cpuhp_state_remove_instance_nocalls()只从状态的节点列表中删除实例。
 
-  cpuhp_state_remove_instance(Y_hp_online, &d->node)
+  * cpuhp_state_remove_instance()删除实例并调用与@state相关的回调(如果不是NULL),
+    用于所有当前状态大于@state的在线CPU。 该回调只对将要被移除的实例进行调用。
+    根据状态阶段,回调要么在当前的CPU上调用(PREPARE阶段),要么在CPU的热插拔
+    线程中调用每个在线CPU(ONLINE阶段)。
 
-应该被调用,这将在所有在线CPU上调用拆分回调
+    为了完成移除工作,teardown回调不能失败
 
-手动设置
-~~~~~~~~
+节点列表的添加/删除操作和回调调用是针对CPU热拔插操作进行序列化。这些函数不能在
+CPU hotplug回调和CPU hotplug读取锁定区域内使用。
 
-通常情况下,在注册或移除状态时调用setup和teamdown回调是很方便的,因为通常在CPU上线
-(下线)和驱动的初始设置(关闭)时需要执行该操作。然而,每个注册和删除功能也有一个
-_nocalls的后缀,如果不希望调用回调,则不调用所提供的回调。在手动设置(或关闭)期间,
-应该使用 ``get_online_cpus()`` 和 ``put_online_cpus()`` 函数来抑制CPU热插拔操作。
+样例
+----
 
+在STARTING阶段设置和取消静态分配的状态,以获取上线和下线操作的通知::
 
-事件的顺序
-----------
+   ret = cpuhp_setup_state(CPUHP_SUBSYS_STARTING, "subsys:starting", subsys_cpu_starting, subsys_cpu_dying);
+   if (ret < 0)
+        return ret;
+   ....
+   cpuhp_remove_state(CPUHP_SUBSYS_STARTING);
 
-热插拔状态被定义在 ``include/linux/cpuhotplug.h``:
+在ONLINE阶段设置和取消动态分配的状态,以获取下线操作的通知::
 
-* ``CPUHP_OFFLINE`` ... ``CPUHP_AP_OFFLINE`` 状态是在CPU启动前调用的。
+   state = cpuhp_setup_state(CPUHP_ONLINE_DYN, "subsys:offline", NULL, subsys_cpu_offline);
+   if (state < 0)
+       return state;
+   ....
+   cpuhp_remove_state(state);
 
-* ``CPUHP_AP_OFFLINE`` ... ``CPUHP_AP_ONLINE`` 状态是在CPU被启动后被调用的。
-  中断是关闭的,调度程序还没有在这个CPU上活动。从 ``CPUHP_AP_OFFLINE`` 开始,
-  回调被调用到目标CPU上。
+在ONLINE阶段设置和取消动态分配的状态,以获取有关上线操作的通知,而无需调用回调::
 
-* ``CPUHP_AP_ONLINE_DYN`` 和 ``CPUHP_AP_ONLINE_DYN_END`` 之间的状态被保留
-  给动态分配。
+   state = cpuhp_setup_state_nocalls(CPUHP_ONLINE_DYN, "subsys:online", subsys_cpu_online, NULL);
+   if (state < 0)
+       return state;
+   ....
+   cpuhp_remove_state_nocalls(state);
 
-* 这些状态在CPU关闭时以相反的顺序调用,从 ``CPUHP_ONLINE`` 开始,在 ``CPUHP_OFFLINE``
-  停止。这里的回调是在将被关闭的CPU上调用的,直到 ``CPUHP_AP_OFFLINE`` 。
+在ONLINE阶段设置、使用和取消动态分配的多实例状态,以获得上线和下线操作的通知::
 
-通过 ``CPUHP_AP_ONLINE_DYN`` 动态分配的状态通常已经足够了。然而,如果在启动或关闭
-期间需要更早的调用,那么应该获得一个显式状态。如果热拔插事件需要相对于另一个热拔插事
-件的特定排序,也可能需要一个显式状态。
+   state = cpuhp_setup_state_multi(CPUHP_ONLINE_DYN, "subsys:online", subsys_cpu_online, subsys_cpu_offline);
+   if (state < 0)
+       return state;
+   ....
+   ret = cpuhp_state_add_instance(state, &inst1->node);
+   if (ret)
+        return ret;
+   ....
+   ret = cpuhp_state_add_instance(state, &inst2->node);
+   if (ret)
+        return ret;
+   ....
+   cpuhp_remove_instance(state, &inst1->node);
+   ....
+   cpuhp_remove_instance(state, &inst2->node);
+   ....
+   remove_multi_state(state);
 
 测试热拔插状态
 ==============
index 26d9913..7ca4462 100644 (file)
@@ -28,6 +28,7 @@
    printk-basics
    printk-formats
    workqueue
+   watch_queue
    symbol-namespaces
 
 数据结构和低级实用程序
index 7d07774..9174fce 100644 (file)
@@ -5,6 +5,7 @@
 :翻译:
 
  司延腾 Yanteng Si <siyanteng@loongson.cn>
+ 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
 
 .. _cn_irq-domain.rst:
 
@@ -52,8 +53,18 @@ irq_domain和一个hwirq号作为参数。 如果hwirq的映射还不存在,
 一个新的Linux irq_desc,将其与hwirq关联起来,并调用.map()回调,这样驱动
 程序就可以执行任何必要的硬件设置。
 
-当接收到一个中断时,应该使用irq_find_mapping()函数从hwirq号中找到
-Linux IRQ号。
+一旦建立了映射,可以通过多种方法检索或使用它:
+
+- irq_resolve_mapping()返回一个指向给定域和hwirq号的irq_desc结构指针,
+  如果没有映射则返回NULL。
+
+- irq_find_mapping()返回给定域和hwirq的Linux IRQ号,如果没有映射则返回0。
+
+- irq_linear_revmap()现与irq_find_mapping()相同,已被废弃。
+
+- generic_handle_domain_irq()处理一个由域和hwirq号描述的中断。
+
+请注意,irq域的查找必须发生在与RCU读临界区兼容的上下文中。
 
 在调用irq_find_mapping()之前,至少要调用一次irq_create_mapping()函数,
 以免描述符不能被分配。
@@ -119,7 +130,8 @@ irq_domain_add_tree()和irq_domain_create_tree()在功能上是等价的,除
 Linux IRQ号编入硬件本身,这样就不需要映射了。 调用irq_create_direct_mapping()
 会分配一个Linux IRQ号,并调用.map()回调,这样驱动就可以将Linux IRQ号编入硬件中。
 
-大多数驱动程序不能使用这个映射。
+大多数驱动程序无法使用此映射,现在它由CONFIG_IRQ_DOMAIN_NOMAP选项控制。
+请不要引入此API的新用户。
 
 传统映射类型
 ------------
@@ -128,7 +140,6 @@ Linux IRQ号编入硬件本身,这样就不需要映射了。 调用irq_create
 
        irq_domain_add_simple()
        irq_domain_add_legacy()
-       irq_domain_add_legacy_isa()
        irq_domain_create_simple()
        irq_domain_create_legacy()
 
@@ -137,6 +148,9 @@ Linux IRQ号编入硬件本身,这样就不需要映射了。 调用irq_create
 一组用于IRQ号的定义(#define),这些定义被传递给struct设备注册。 在这种情况下,
 不能动态分配Linux IRQ号,应该使用传统映射。
 
+顾名思义,\*_legacy()系列函数已被废弃,只是为了方便对古老平台的支持而存在。
+不应该增加新的用户。当\*_simple()系列函数的使用导致遗留行为时,他们也是如此。
+
 传统映射假设已经为控制器分配了一个连续的IRQ号范围,并且可以通过向hwirq号添加一
 个固定的偏移来计算IRQ号,反之亦然。 缺点是需要中断控制器管理IRQ分配,并且需要为每
 个hwirq分配一个irq_desc,即使它没有被使用。
index e45fe80..c226626 100644 (file)
@@ -5,6 +5,7 @@
 :翻译:
 
  司延腾 Yanteng Si <siyanteng@loongson.cn>
+ 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
 
 .. _cn_kernel-api.rst:
 
@@ -224,7 +225,7 @@ kernel/kmod.c
 模块接口支持
 ------------
 
-更多信息请参考文件kernel/module.c
+更多信息请参阅kernel/module/目录下的文件
 
 硬件接口
 ========
@@ -282,6 +283,8 @@ kernel/acct.c
 
 该API在以下内核代码中:
 
+include/linux/bio.h
+
 block/blk-core.c
 
 block/blk-core.c
index 0ea43dc..a732b0e 100644 (file)
@@ -5,6 +5,7 @@
 :翻译:
 
  司延腾 Yanteng Si <siyanteng@loongson.cn>
+ 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
 
 :校译:
 
@@ -66,12 +67,24 @@ mm/vmalloc.c
 
 该API在以下内核代码中:
 
-mm/readahead.c
+文件映射
+--------
 
 mm/filemap.c
 
+预读
+----
+
+mm/readahead.c
+
+回写
+----
+
 mm/page-writeback.c
 
+截断
+----
+
 mm/truncate.c
 
 include/linux/pagemap.h
@@ -105,6 +118,14 @@ mm/mempolicy.c
 
 include/linux/mm_types.h
 
+include/linux/mm_inline.h
+
+include/linux/page-flags.h
+
 include/linux/mm.h
 
+include/linux/page_ref.h
+
 include/linux/mmzone.h
+
+mm/util.c
index d574de3..59c6efb 100644 (file)
@@ -6,6 +6,7 @@
 :翻译:
 
  司延腾 Yanteng Si <siyanteng@loongson.cn>
+ 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
 
 .. _cn_printk-basics.rst:
 
@@ -107,6 +108,4 @@ pr_debug()和pr_devel(),除非定义了 ``DEBUG`` (或者在pr_debug()的情
 
 该API在以下内核代码中:
 
-kernel/printk/printk.c
-
 include/linux/printk.h
index ce39c78..bd36d35 100644 (file)
@@ -5,6 +5,7 @@
 :翻译:
 
  司延腾 Yanteng Si <siyanteng@loongson.cn>
+ 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
 
 .. _cn_printk-formats.rst:
 
@@ -548,7 +549,7 @@ nodemask_pr_args()来方便打印cpumask和nodemask。
 
 ::
 
-       %pGp    referenced|uptodate|lru|active|private|node=0|zone=2|lastcpupid=0x1fffff
+       %pGp    0x17ffffc0002036(referenced|uptodate|lru|active|private|node=0|zone=2|lastcpupid=0x1fffff)
        %pGg    GFP_USER|GFP_DMA32|GFP_NOWARN
        %pGv    read|exec|mayread|maywrite|mayexec|denywrite
 
index 6abf7ed..bb16f06 100644 (file)
@@ -52,7 +52,7 @@
 
 相应的 ksymtab 条目结构体 ``kernel_symbol`` 将有相应的成员 ``命名空间`` 集。
 导出时未指明命名空间的符号将指向 ``NULL`` 。如果没有定义命名空间,则默认没有。
-``modpost`` 和kernel/module.c分别在构建时或模块加载时使用名称空间。
+``modpost`` 和kernel/module/main.c分别在构建时或模块加载时使用名称空间。
 
 2.2 使用DEFAULT_SYMBOL_NAMESPACE定义
 ====================================
diff --git a/Documentation/translations/zh_CN/core-api/watch_queue.rst b/Documentation/translations/zh_CN/core-api/watch_queue.rst
new file mode 100644 (file)
index 0000000..23b17ae
--- /dev/null
@@ -0,0 +1,313 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/watch_queue.rst
+
+:翻译:
+
+周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
+
+:校译:
+
+司延腾 Yanteng Si <siyanteng@loongson.cn>
+吴想成 Wu Xiangcheng <bobwxc@email.cn>
+
+
+============
+通用通知机制
+============
+
+通用通知机制是建立在标准管道驱动之上的,它可以有效地将来自内核的通知消息拼接到用
+户空间打开的管道中。这可以与以下方面结合使用::
+
+  * Key/keyring 通知
+
+通知缓冲区可以通过以下方式启用:
+
+       “General setup”/“General notification queue”
+       (CONFIG_WATCH_QUEUE)
+
+文档包含以下章节:
+
+.. contents:: :local:
+
+
+概述
+====
+
+该设施以一种特殊模式打开的管道形式出现,管道的内部环形缓冲区用于保存内核生成的消
+息。然后通过read()读出这些消息。在此类管道上禁用拼接以及类似的操作,因为它们希望
+在某些情况下将其添加的内容还原到环中-这可能最终会与通知消息重叠。
+
+管道的所有者必须告诉内核它想通过该管道观察哪些源。只有连接到该管道上的源才会将消
+息插入其中。请注意,一个源可能绑定到多个管道,并同时将消息插入到所有管道中。
+
+还可以将过滤器放置在管道上,以便在不感兴趣时可以忽略某些源类型和子事件。
+
+如果环中没有可用的插槽,或者没有预分配的消息缓冲区可用,则将丢弃消息。在这两种情
+况下,read()都会在读取缓冲区中当前的最后一条消息后,将WATCH_META_LOSS_NOTIFICATION
+插入到输出缓冲区中。
+
+请注意,当生成一个通知时,内核不会等待消费者收集它,而是继续执行。这意味着可以在
+持有自旋锁的同时生成通知,并且还可以保护内核不被用户空间故障无限期地阻碍。
+
+
+消息结构
+========
+
+通知消息由一个简短的头部开始::
+
+       struct watch_notification {
+               __u32   type:24;
+               __u32   subtype:8;
+               __u32   info;
+       };
+
+“type”表示通知记录的来源,“subtype”表示该来源的记录类型(见下文观测源章节)。该类
+型也可以是“WATCH_TYPE_META”。这是一个由观测队列本身在内部生成的特殊记录类型。有两
+个子类型:
+
+  * WATCH_META_REMOVAL_NOTIFICATION
+  * WATCH_META_LOSS_NOTIFICATION
+
+第一个表示安装了观察的对象已被删除或销毁,第二个表示某些消息已丢失。
+
+“info”表示一系列东西,包括:
+
+  * 消息的长度,以字节为单位,包括头(带有WATCH_INFO_LENGTH的掩码,并按
+    WATCH_INFO_LENGTH__SHIFT移位)。这表示记录的大小,可能在8到127字节之间。
+
+  * 观测ID(带有WATCH_INFO_ID掩码,并按WATCH_INFO_ID__SHIFT移位)。这表示观测的主
+    叫ID,可能在0到255之间。多个观测组可以共享一个队列,这提供了一种区分它们的方法。
+
+  * 特定类型的字段(WATCH_INFO_TYPE_INFO)。这是由通知生产者设置的,以指示类型和
+    子类型的某些特定含义。
+
+除长度外,信息中的所有内容都可以用于过滤。
+
+头部后面可以有补充信息。此格式是由类型和子类型决定的。
+
+
+观测列表(通知源)API
+=====================
+
+“观测列表“是订阅通知源的观测者的列表。列表可以附加到对象(比如键或超级块),也可
+以是全局的(比如对于设备事件)。从用户空间的角度来看,一个非全局的观测列表通常是
+通过引用它所属的对象来引用的(比如使用KEYCTL_NOTIFY并给它一个密钥序列号来观测特定
+的密钥)。
+
+为了管理观测列表,提供了以下函数:
+
+  * ::
+
+       void init_watch_list(struct watch_list *wlist,
+                            void (*release_watch)(struct watch *wlist));
+
+    初始化一个观测列表。 如果 ``release_watch`` 不是NULL,那么这表示当watch_list对
+    象被销毁时,应该调用函数来丢弃观测列表对被观测对象的任何引用。
+
+  * ``void remove_watch_list(struct watch_list *wlist);``
+
+    这将删除订阅watch_list的所有观测,并释放它们,然后销毁watch_list对象本身。
+
+
+观测队列(通知输出)API
+=======================
+
+“观测队列”是由应用程序分配的用以记录通知的缓冲区,其工作原理完全隐藏在管道设备驱
+动中,但必须获得对它的引用才能设置观测。可以通过以下方式进行管理:
+
+  * ``struct watch_queue *get_watch_queue(int fd);``
+
+    由于观测队列在内核中通过实现缓冲区的管道的文件描述符表示,用户空间必须通过系
+    统调用传递该文件描述符,这可以用于从系统调用中查找指向观测队列的不透明指针。
+
+  * ``void put_watch_queue(struct watch_queue *wqueue);``
+
+    该函数用以丢弃从 ``get_watch_queue()`` 获得的引用。
+
+
+观测订阅API
+===========
+
+“观测”是观测列表上的订阅,表示观测队列,从而表示应写入通知记录的缓冲区。观测队列
+对象还可以携带该对象的过滤规则,由用户空间设置。watch结构体的某些部分可以由驱动程
+序设置::
+
+       struct watch {
+               union {
+                       u32             info_id;        /* 在info字段中进行OR运算的ID */
+                       ...
+               };
+               void                    *private;       /* 被观测对象的私有数据 */
+               u64                     id;             /* 内部标识符 */
+               ...
+       };
+
+``info_id`` 值是从用户空间获得并按WATCH_INFO_ID__SHIFT移位的8位数字。当通知写入关
+联的观测队列缓冲区时,这将与struct watch_notification::info的WATCH_INFO_ID字段进
+行或运算。
+
+``private`` 字段是与watch_list相关联的驱动程序数据,并由 ``watch_list::release_watch()``
+函数清除。
+
+``id`` 字段是源的ID。使用不同ID发布的通知将被忽略。
+
+提供以下函数来管理观测:
+
+  * ``void init_watch(struct watch *watch, struct watch_queue *wqueue);``
+
+    初始化一个观测对象,把它的指针设置到观察队列中,使用适当的限制来避免死锁。
+
+  * ``int add_watch_to_object(struct watch *watch, struct watch_list *wlist);``
+
+    将观测订阅到观测列表(通知源)。watch结构体中的driver-settable字段必须在调用
+    它之前设置。
+
+  * ::
+
+       int remove_watch_from_object(struct watch_list *wlist,
+                                    struct watch_queue *wqueue,
+                                    u64 id, false);
+
+    从观测列表中删除一个观测,该观测必须与指定的观测队列(``wqueue``)和对象标识
+    符(``id``)匹配。通知(``WATCH_META_REMOVAL_NOTIFICATION``)被发送到观测队列
+    表示该观测已被删除。
+
+  * ``int remove_watch_from_object(struct watch_list *wlist, NULL, 0, true);``
+
+    从观测列表中删除所有观测。预计这将被称为销毁前的准备工作,届时新的观测将无法
+    访问观测列表。通知(``WATCH_META_REMOVAL_NOTIFICATION``)被发送到每个订阅观测
+    的观测队列,以表明该观测已被删除。
+
+
+通知发布API
+===========
+
+要将通知发布到观测列表以便订阅的观测可以看到,应使用以下函数::
+
+       void post_watch_notification(struct watch_list *wlist,
+                                    struct watch_notification *n,
+                                    const struct cred *cred,
+                                    u64 id);
+
+应预先设置通知格式,并应传入一个指向头部(``n``)的指针。通知可能大于此值,并且缓
+冲槽为单位的大小在 ``n->info & WATCH_INFO_LENGTH`` 中注明。
+
+``cred`` 结构体表示源(对象)的证书,并传递给LSM,例如SELinux,以允许或禁止根据该队
+列(对象)的证书在每个单独队列中记录注释。
+
+``id`` 是源对象ID(如密钥上的序列号)。只有设置相同ID的观测才能看到这个通知。
+
+
+观测源
+======
+
+任何特定的缓冲区都可以从多个源获取信息。 这些源包括:
+
+  * WATCH_TYPE_KEY_NOTIFY
+
+    这种类型的通知表示密钥和密钥环的变化,包括密钥环内容或密钥属性的变化。
+
+    更多信息请参见Documentation/security/keys/core.rst。
+
+
+事件过滤
+========
+
+当创建观测队列后,我们可以应用一组过滤器以限制接收的事件::
+
+       struct watch_notification_filter filter = {
+               ...
+       };
+       ioctl(fd, IOC_WATCH_QUEUE_SET_FILTER, &filter)
+
+过滤器的描述的类型变量是::
+
+       struct watch_notification_filter {
+               __u32   nr_filters;
+               __u32   __reserved;
+               struct watch_notification_type_filter filters[];
+       };
+
+其中“nr_filters”表示filters[]数组中过滤器的数量,而“__reserved”应为0。
+“filter”数组有以下类型的元素::
+
+       struct watch_notification_type_filter {
+               __u32   type;
+               __u32   info_filter;
+               __u32   info_mask;
+               __u32   subtype_filter[8];
+       };
+
+其中:
+
+  * ``type`` 是过滤的事件类型,应类似于“WATCH_TYPE_KEY_NOTIFY”。
+
+  * ``info_filter`` 与 ``info_mask`` 充当通知记录的信息字段的过滤器,只有在以下情
+    况,通知才会写入缓冲区::
+
+       (watch.info & info_mask) == info_filter
+
+    例如,这可以用于忽略不在一个挂载树上的观测点的事件。
+
+  * ``subtype_filter`` 是一个位掩码,表示感兴趣的子类型。subtype_filter[0]的
+    bit[0]对应子类型0,bit[1]对应子类型1,以此类推。
+
+若ioctl()的参数为NULL,则过滤器将被移除,并且来自观测源的所有事件都将通过。
+
+
+用户空间代码示例
+================
+
+缓冲区的创建如下所示::
+
+       pipe2(fds, O_TMPFILE);
+       ioctl(fds[1], IOC_WATCH_QUEUE_SET_SIZE, 256);
+
+它可以被设置成接收密钥环变化的通知::
+
+       keyctl(KEYCTL_WATCH_KEY, KEY_SPEC_SESSION_KEYRING, fds[1], 0x01);
+
+然后,这些通知可以被如下方式所使用::
+
+       static void consumer(int rfd, struct watch_queue_buffer *buf)
+       {
+               unsigned char buffer[128];
+               ssize_t buf_len;
+
+               while (buf_len = read(rfd, buffer, sizeof(buffer)),
+                      buf_len > 0
+                      ) {
+                       void *p = buffer;
+                       void *end = buffer + buf_len;
+                       while (p < end) {
+                               union {
+                                       struct watch_notification n;
+                                       unsigned char buf1[128];
+                               } n;
+                               size_t largest, len;
+
+                               largest = end - p;
+                               if (largest > 128)
+                                       largest = 128;
+                               memcpy(&n, p, largest);
+
+                               len = (n->info & WATCH_INFO_LENGTH) >>
+                                       WATCH_INFO_LENGTH__SHIFT;
+                               if (len == 0 || len > largest)
+                                       return;
+
+                               switch (n.n.type) {
+                               case WATCH_TYPE_META:
+                                       got_meta(&n.n);
+                               case WATCH_TYPE_KEY_NOTIFY:
+                                       saw_key_change(&n.n);
+                                       break;
+                               }
+
+                               p += len;
+                       }
+               }
+       }
index e372fa5..f6567cf 100644 (file)
@@ -6,6 +6,7 @@
 :翻译:
 
  司延腾 Yanteng Si <siyanteng@loongson.cn>
+ 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
 
 .. _cn_workqueue.rst:
 
@@ -178,10 +179,6 @@ workqueue将自动创建与属性相匹配的后备工作者池。调节并发
 
   这个标志对于未绑定的wq来说是没有意义的。
 
-请注意,标志 ``WQ_NON_REENTRANT`` 不再存在,因为现在所有的工作
-队列都是不可逆的——任何工作项都保证在任何时间内最多被整个系统的一
-个工作者执行。
-
 
 ``max_active``
 --------------
@@ -328,6 +325,22 @@ And with cmwq with ``@max_active`` >= 3, ::
 
 工作项函数在堆栈追踪中应该是微不足道的。
 
+不可重入条件
+============
+
+工作队列保证,如果在工作项排队后满足以下条件,则工作项不能重入:
+
+
+        1. 工作函数没有被改变。
+        2. 没有人将该工作项排到另一个工作队列中。
+        3. 该工作项尚未被重新启动。
+
+换言之,如果上述条件成立,则保证在任何给定时间最多由一个系统范围内的工作程序执行
+该工作项。
+
+请注意,在self函数中将工作项重新排队(到同一队列)不会破坏这些条件,因此可以安全
+地执行此操作。否则在破坏工作函数内部的条件时需要小心。
+
 
 内核内联文档参考
 ================
index ff2d9bc..fb19324 100644 (file)
@@ -6,6 +6,7 @@
 :翻译:
 
  司延腾 Yanteng Si <siyanteng@loongson.cn>
+ 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
 
 :校译:
 
@@ -254,7 +255,8 @@ __xa_set_mark() 和 __xa_clear_mark() 函数也适用于你查找一个条目并
 
 高级API是基于xa_state的。这是一个不透明的数据结构,你使用XA_STATE()宏在堆栈中声明。这个宏初始化了
 xa_state,准备开始在XArray上移动。它被用作一个游标来保持在XArray中的位置,并让你把各种操作组合在一
-起,而不必每次都从头开始。
+起,而不必每次都从头开始。xa_state的内容受rcu_read_lock()或xas_lock()的保护。如果需要删除保护状态
+和树的这些锁中的任何一个,你必须调用xas_pause()以便将来的调用不会依赖于状态中未受保护的部分。
 
 xa_state也被用来存储错误(store errors)。你可以调用xas_error()来检索错误。所有的操作在进行之前都
 会检查xa_state是否处于错误状态,所以你没有必要在每次调用之后检查错误;你可以连续进行多次调用,只在
index 23db9d4..fe76cbe 100644 (file)
 概述
 ----
 
-KernelAddressSANitizer(KASAN)是一种动态内存安全错误检测工具,主要功能是
-检查内存越界访问和使用已释放内存的问题。KASAN有三种模式:
+Kernel Address SANitizer(KASAN)是一种动态内存安全错误检测工具,主要功能是
+检查内存越界访问和使用已释放内存的问题。
 
-1. 通用KASAN(与用户空间的ASan类似)
-2. 基于软件标签的KASAN(与用户空间的HWASan类似)
-3. 基于硬件标签的KASAN(基于硬件内存标签)
+KASAN有三种模式:
 
-由于通用KASAN的内存开销较大,通用KASAN主要用于调试。基于软件标签的KASAN
-可用于dogfood测试,因为它具有较低的内存开销,并允许将其用于实际工作量。
-基于硬件标签的KASAN具有较低的内存和性能开销,因此可用于生产。同时可用于
-检测现场内存问题或作为安全缓解措施。
+1. 通用KASAN
+2. 基于软件标签的KASAN
+3. 基于硬件标签的KASAN
 
-软件KASAN模式(#1和#2)使用编译时工具在每次内存访问之前插入有效性检查,
-因此需要一个支持它的编译器版本
+用CONFIG_KASAN_GENERIC启用的通用KASAN,是用于调试的模式,类似于用户空
+间的ASan。这种模式在许多CPU架构上都被支持,但它有明显的性能和内存开销
 
-通用KASAN在GCC和Clang受支持。GCC需要8.3.0或更高版本。任何受支持的Clang
-版本都是兼容的,但从Clang 11才开始支持检测全局变量的越界访问。
+基于软件标签的KASAN或SW_TAGS KASAN,通过CONFIG_KASAN_SW_TAGS启用,
+可以用于调试和自我测试,类似于用户空间HWASan。这种模式只支持arm64,但其
+适度的内存开销允许在内存受限的设备上用真实的工作负载进行测试。
 
-基于软件标签的KASAN模式仅在Clang中受支持。
+基于硬件标签的KASAN或HW_TAGS KASAN,用CONFIG_KASAN_HW_TAGS启用,被
+用作现场内存错误检测器或作为安全缓解的模式。这种模式只在支持MTE(内存标签
+扩展)的arm64 CPU上工作,但它的内存和性能开销很低,因此可以在生产中使用。
 
-硬件KASAN模式(#3)依赖硬件来执行检查,但仍需要支持内存标签指令的编译器
-版本。GCC 10+和Clang 11+支持此模式。
+关于每种KASAN模式的内存和性能影响的细节,请参见相应的Kconfig选项的描述。
 
-两种软件KASAN模式都适用于SLUB和SLAB内存分配器,而基于硬件标签的KASAN目前
-仅支持SLUB
+通用模式和基于软件标签的模式通常被称为软件模式。基于软件标签的模式和基于
+硬件标签的模式被称为基于标签的模式
 
-目前x86_64、arm、arm64、xtensa、s390、riscv架构支持通用KASAN模式,仅
-arm64架构支持基于标签的KASAN模式。
+支持
+----
+
+体系架构
+~~~~~~~~
+
+在x86_64、arm、arm64、powerpc、riscv、s390和xtensa上支持通用KASAN,
+而基于标签的KASAN模式只在arm64上支持。
+
+编译器
+~~~~~~
+
+软件KASAN模式使用编译时工具在每个内存访问之前插入有效性检查,因此需要一个
+提供支持的编译器版本。基于硬件标签的模式依靠硬件来执行这些检查,但仍然需要
+一个支持内存标签指令的编译器版本。
+
+通用KASAN需要GCC 8.3.0版本或更高版本,或者内核支持的任何Clang版本。
+
+基于软件标签的KASAN需要GCC 11+或者内核支持的任何Clang版本。
+
+基于硬件标签的KASAN需要GCC 10+或Clang 12+。
+
+内存类型
+~~~~~~~~
+
+通用KASAN支持在所有的slab、page_alloc、vmap、vmalloc、堆栈和全局内存
+中查找错误。
+
+基于软件标签的KASAN支持slab、page_alloc、vmalloc和堆栈内存。
+
+基于硬件标签的KASAN支持slab、page_alloc和不可执行的vmalloc内存。
+
+对于slab,两种软件KASAN模式都支持SLUB和SLAB分配器,而基于硬件标签的
+KASAN只支持SLUB。
 
 用法
 ----
@@ -53,7 +84,7 @@ arm64架构支持基于标签的KASAN模式。
 
 对于软件模式,还可以在 ``CONFIG_KASAN_OUTLINE`` 和 ``CONFIG_KASAN_INLINE``
 之间进行选择。outline和inline是编译器插桩类型。前者产生较小的二进制文件,
-而后者快1.1-2倍。
+而后者快2倍。
 
 要将受影响的slab对象的alloc和free堆栈跟踪包含到报告中,请启用
 ``CONFIG_STACKTRACE`` 。要包括受影响物理页面的分配和释放堆栈跟踪的话,
@@ -172,21 +203,29 @@ KASAN受通用 ``panic_on_warn`` 命令行参数的影响。启用该功能后
 默认情况下,KASAN只为第一次无效内存访问打印错误报告。使用 ``kasan_multi_shot`` ,
 KASAN会针对每个无效访问打印报告。这有效地禁用了KASAN报告的 ``panic_on_warn`` 。
 
+另外,独立于 ``panic_on_warn`` , ``kasan.fault=`` 引导参数可以用来控制恐慌和报
+告行为:
+
+- ``kasan.fault=report`` 或 ``=panic`` 控制是只打印KASAN报告还是同时使内核恐慌
+  (默认: ``report`` )。即使启用了 ``kasan_multi_shot`` ,也会发生内核恐慌。
+
 基于硬件标签的KASAN模式(请参阅下面有关各种模式的部分)旨在在生产中用作安全缓解
-措施。因此,它支持允许禁用KASAN或控制其功能的引导参数。
+措施。因此,它支持允许禁用KASAN或控制其功能的附加引导参数。
 
 - ``kasan=off`` 或 ``=on`` 控制KASAN是否启用 (默认: ``on`` )。
 
-- ``kasan.mode=sync`` 或 ``=async`` 控制KASAN是否配置为同步或异步执行模式(默认:
-  ``sync`` )。同步模式:当标签检查错误发生时,立即检测到错误访问。异步模式:
-  延迟错误访问检测。当标签检查错误发生时,信息存储在硬件中(在arm64的
+- ``kasan.mode=sync`` 、 ``=async`` 或 ``=asymm`` 控制KASAN是否配置
+  为同步或异步执行模式(默认:``sync`` )。
+  同步模式:当标签检查错误发生时,立即检测到错误访问。
+  异步模式:延迟错误访问检测。当标签检查错误发生时,信息存储在硬件中(在arm64的
   TFSR_EL1寄存器中)。内核会定期检查硬件,并且仅在这些检查期间报告标签错误。
+  非对称模式:读取时同步检测不良访问,写入时异步检测。
+
+- ``kasan.vmalloc=off`` 或 ``=on`` 禁用或启用vmalloc分配的标记(默认:``on`` )。
 
 - ``kasan.stacktrace=off`` 或 ``=on`` 禁用或启用alloc和free堆栈跟踪收集
   (默认: ``on`` )。
 
-- ``kasan.fault=report`` 或 ``=panic`` 控制是只打印KASAN报告还是同时使内核恐慌
-  (默认: ``report`` )。即使启用了 ``kasan_multi_shot`` ,也会发生内核恐慌。
 
 实施细则
 --------
@@ -244,7 +283,6 @@ KASAN会针对每个无效访问打印报告。这有效地禁用了KASAN报告
 基于软件标签的KASAN使用0xFF作为匹配所有指针标签(不检查通过带有0xFF指针标签
 的指针进行的访问)。值0xFE当前保留用于标记已释放的内存区域。
 
-基于软件标签的KASAN目前仅支持对Slab和page_alloc内存进行标记。
 
 基于硬件标签的KASAN模式
 ~~~~~~~~~~~~~~~~~~~~~~~
@@ -262,8 +300,6 @@ KASAN会针对每个无效访问打印报告。这有效地禁用了KASAN报告
 基于硬件标签的KASAN使用0xFF作为匹配所有指针标签(不检查通过带有0xFF指针标签的
 指针进行的访问)。值0xFE当前保留用于标记已释放的内存区域。
 
-基于硬件标签的KASAN目前仅支持对Slab和page_alloc内存进行标记。
-
 如果硬件不支持MTE(ARMv8.5之前),则不会启用基于硬件标签的KASAN。在这种情况下,
 所有KASAN引导参数都将被忽略。
 
@@ -275,6 +311,8 @@ KASAN会针对每个无效访问打印报告。这有效地禁用了KASAN报告
 影子内存
 --------
 
+本节的内容只适用于软件KASAN模式。
+
 内核将内存映射到地址空间的几个不同部分。内核虚拟地址的范围很大:没有足够的真实
 内存来支持内核可以访问的每个地址的真实影子区域。因此,KASAN只为地址空间的某些
 部分映射真实的影子。
@@ -297,7 +335,7 @@ CONFIG_KASAN_VMALLOC
 ~~~~~~~~~~~~~~~~~~~~
 
 使用 ``CONFIG_KASAN_VMALLOC`` ,KASAN可以以更大的内存使用为代价覆盖vmalloc
-空间。目前,这在x86、riscv、s390和powerpc上受支持。
+空间。目前,这在arm64、x86、riscv、s390和powerpc上受支持。
 
 这通过连接到vmalloc和vmap并动态分配真实的影子内存来支持映射。
 
@@ -349,10 +387,10 @@ KASAN连接到vmap基础架构以懒清理未使用的影子内存。
 ``kasan_disable_current()``/``kasan_enable_current()`` 部分注释这部分代码。
 这也会禁用通过函数调用发生的间接访问的报告。
 
-对äº\8eå\9fºäº\8eæ \87ç­¾ç\9a\84KASAN模å¼\8fï¼\88å\8c\85æ\8b¬ç¡¬ä»¶æ¨¡å¼\8fï¼\89ï¼\8cè¦\81ç¦\81ç\94¨è®¿é\97®æ£\80æ\9f¥ï¼\8c请使ç\94¨
-``kasan_reset_tag()`` 或 ``page_kasan_tag_reset()`` 。请注意,通过
-``page_kasan_tag_reset()`` 临时禁用访问检查需要通过 ``page_kasan_tag``
-/ ``page_kasan_tag_set`` 保存和恢复每页KASAN标签。
+对äº\8eå\9fºäº\8eæ \87ç­¾ç\9a\84KASAN模å¼\8fï¼\8cè¦\81ç¦\81ç\94¨è®¿é\97®æ£\80æ\9f¥ï¼\8c请使ç\94¨ ``kasan_reset_tag()`` æ\88\96
+``page_kasan_tag_reset()`` 。请注意,通过 ``page_kasan_tag_reset()``
+临时禁用访问检查需要通过 ``page_kasan_tag`` / ``page_kasan_tag_set`` 保
+存和恢复每页KASAN标签。
 
 测试
 ~~~~
@@ -381,11 +419,10 @@ KASAN连接到vmap基础架构以懒清理未使用的影子内存。
 
 当由于缺少KASAN报告而导致测试失败时::
 
-        # kmalloc_double_kzfree: EXPECTATION FAILED at lib/test_kasan.c:629
-        Expected kasan_data->report_expected == kasan_data->report_found, but
-        kasan_data->report_expected == 1
-        kasan_data->report_found == 0
-        not ok 28 - kmalloc_double_kzfree
+        # kmalloc_double_kzfree: EXPECTATION FAILED at lib/test_kasan.c:974
+        KASAN failure expected in "kfree_sensitive(ptr)", but none occurred
+        not ok 44 - kmalloc_double_kzfree
+
 
 最后打印所有KASAN测试的累积状态。成功::
 
index 5562824..0664c63 100644 (file)
@@ -106,3 +106,5 @@ __releases  - 指定的锁在函数进入时被持有,但在退出时不被持
 
 make 的可选变量 CHECKFLAGS 可以用来向 sparse 工具传递参数。编译系统会自
 动向 sparse 工具传递 -Wbitwise 参数。
+
+注意sparse定义了__CHECKER__预处理器符号。
\ No newline at end of file
index b7a1d13..d6f2c65 100644 (file)
@@ -107,3 +107,28 @@ Documentation/dev-tools/kcov.rst 是能够构建在内核之中,用于在每
 之后你就能确保这些错误在测试过程中都不会发生了。
 
 一些工具与KUnit和kselftest集成,并且在检测到问题时会自动打断测试。
+
+静态分析工具
+============
+
+除了测试运行中的内核,我们还可以使用**静态分析**工具直接分析内核的源代
+码(**在编译时**)。内核中常用的工具允许人们检查整个源代码树或其中的特
+定文件。它们使得在开发过程中更容易发现和修复问题。
+
+ Sparse可以通过执行类型检查、锁检查、值范围检查来帮助测试内核,此外还
+ 可以在检查代码时报告各种错误和警告。关于如何使用它的细节,请参阅
+ Documentation/translations/zh_CN/dev-tools/sparse.rst。
+
+ Smatch扩展了Sparse,并提供了对编程逻辑错误的额外检查,如开关语句中
+ 缺少断点,错误检查中未使用的返回值,忘记在错误路径的返回中设置错误代
+ 码等。Smatch也有针对更严重问题的测试,如整数溢出、空指针解除引用和内
+ 存泄漏。见项目页面http://smatch.sourceforge.net/。
+
+ Coccinelle是我们可以使用的另一个静态分析器。Coccinelle经常被用来
+ 帮助源代码的重构和并行演化,但它也可以帮助避免常见代码模式中出现的某
+ 些错误。可用的测试类型包括API测试、内核迭代器的正确使用测试、自由操
+ 作的合理性检查、锁定行为的分析,以及已知的有助于保持内核使用一致性的
+ 进一步测试。详情请见Documentation/dev-tools/coccinelle.rst。
+
+ 不过要注意的是,静态分析工具存在**假阳性**的问题。在试图修复错误和警
+ 告之前,需要仔细评估它们。
index 23d0b6f..3fc355f 100644 (file)
@@ -1,7 +1,7 @@
 .. SPDX-License-Identifier: GPL-2.0
 .. include:: ../disclaimer-zh_CN.rst
 
-:Original: Documentation/Devicetree/index.rst
+:Original: Documentation/devicetree/index.rst
 
 :翻译:
 
index abd94e7..11eb08c 100644 (file)
@@ -1,7 +1,7 @@
 .. SPDX-License-Identifier: GPL-2.0
 .. include:: ../disclaimer-zh_CN.rst
 
-:Original: Documentation/Devicetree/of_unittest.rst
+:Original: Documentation/devicetree/of_unittest.rst
 
 :翻译:
 
index accdc33..c6aee82 100644 (file)
@@ -1,7 +1,7 @@
 .. SPDX-License-Identifier: GPL-2.0
 .. include:: ../disclaimer-zh_CN.rst
 
-:Original: Documentation/Devicetree/usage-model.rst
+:Original: Documentation/devicetree/usage-model.rst
 
 :翻译:
 
index 82ec844..ccfb9b8 100644 (file)
@@ -14,7 +14,7 @@ Linux内核源文件可以包含kernel-doc格式的结构化文档注释,用
           实际有着明显的不同。内核源包含成千上万个kernel-doc注释。请坚持遵循
           此处描述的风格。
 
-.. note:: kernel-doc无法包含Rust代码:请参考 Documentation/rust/docs.rst 。
+.. note:: kernel-doc无法包含Rust代码:请参考 Documentation/rust/general-information.rst 。
 
 从注释中提取kernel-doc结构,并从中生成适当的 `Sphinx C 域`_ 函数和带有锚点的
 类型描述。这些注释将被过滤以生成特殊kernel-doc高亮和交叉引用。详见下文。
index d5460e9..eccaf1c 100644 (file)
@@ -37,10 +37,10 @@ configfs轻松配置的对象(例如:设备,触发器)。
 3. 软件触发器
 =============
 
-IIO默认configfs组之一是“触发器”组。 挂载configfs后可以自动访问它,并且可
+IIO默认configfs组之一是“触发器”组。挂载configfs后可以自动访问它,并且可
 以在/config/iio/triggers下找到。
 
-IIO软件触发器为创建多种触发器类型提供了支持。 通常在include/linux/iio
+IIO软件触发器为创建多种触发器类型提供了支持。通常在include/linux/iio
 /sw_trigger.h:中的接口下将新的触发器类型实现为单独的内核模块:
 ::
 
@@ -76,10 +76,10 @@ IIO软件触发器为创建多种触发器类型提供了支持。 通常在incl
        .ops = &iio_trig_sample_ops,
   };
 
-module_iio_sw_trigger_driver(iio_trig_sample);
+  module_iio_sw_trigger_driver(iio_trig_sample);
 
-每种触发器类型在/config/iio/triggers下都有其自己的目录。 加载iio-trig-sample
-模块将创建“ trig-sample”触发器类型目录/config/iio/triggers/trig-sample.
+每种触发器类型在/config/iio/triggers下都有其自己的目录。加载iio-trig-sample
+模块将创建“trig-sample”触发器类型目录/config/iio/triggers/trig-sample.
 
 我们支持以下中断源(触发器类型)
 
@@ -102,3 +102,5 @@ module_iio_sw_trigger_driver(iio_trig_sample);
 ----------------------------
 
 "hrtimer”触发器类型没有来自/config dir的任何可配置属性。
+它确实引入了触发目录的sampling_frequency属性。
+该属性以Hz为单位设置轮询频率,精度为mHz。
\ No newline at end of file
index f2bc154..9112949 100644 (file)
@@ -81,7 +81,7 @@
 过硬件中断)的“软件中断”将运行( ``kernel/softirq.c`` )。
 
 此处完成了许多真正的中断处理工作。在向SMP过渡的早期,只有“bottom halves下半
-部”(BHs)机制,无法利用多个CPU的优势。在从那些一团糟的电脑切换过来后不久,
+部”(BHs)机制,无法利用多个CPU的优势。在从那些一团糟的电脑切换过来后不久,
 我们放弃了这个限制,转而使用“软中断”。
 
 ``include/linux/interrupt.h`` 列出了不同的软中断。定时器软中断是一个非常重要
@@ -95,8 +95,7 @@
 
 .. warning::
 
-    “tasklet”这个名字是误导性的:它们与“任务”无关,可能更多与当时
-    阿列克谢·库兹涅佐夫享用的糟糕伏特加有关。
+    “tasklet”这个名字是误导性的:它们与“任务”无关。
 
 你可以使用 :c:func:`in_softirq()` 宏( ``include/linux/preempt.h`` )来确认
 是否处于软中断(或子任务)中。
@@ -247,7 +246,7 @@ Provide mechanism not policy”。
     与 :c:func:`put_user()` 和 :c:func:`get_user()` 不同,它们返回未复制的
     数据量(即0仍然意味着成功)。
 
-【是的,这个愚蠢的接口真心让我尴尬。火爆的口水仗大概每年都会发生。
+【是的,这个讨厌的接口真心让我尴尬。火爆的口水仗大概每年都会发生。
 —— Rusty Russell】
 
 这些函数可以隐式睡眠。它不应该在用户上下文之外调用(没有意义)、调用时禁用中断
@@ -538,9 +537,9 @@ Documentation/core-api/symbol-namespaces.rst 。
 
 Linus和其他开发人员有时会更改开发内核中的函数或结构体名称;这样做不仅是为了
 让每个人都保持警惕,还反映了一个重大的更改(例如,不能再在打开中断的情况下
-调用,或者执行额外的检查,或者不执行以前捕获的检查)。通常这会附带一个linux
-内核邮件列表中相当全面的注释;请搜索存档以查看。简单地对文件进行全局替换通常
-会让事情变得 **更糟** 。
+调用,或者执行额外的检查,或者不执行以前捕获的检查)。通常这会附带发送一个
+相当全面的注释到相应的内核邮件列表中;请搜索存档以查看。简单地对文件进行全局
+替换通常只会让事情变得 **更糟** 。
 
 初始化结构体成员
 ------------------
@@ -610,7 +609,7 @@ C++
 
 为了让你的东西更正式、补丁更整洁,还有一些工作要做:
 
--  搞清楚你在谁的地界儿上干活。查看源文件的顶部、 ``MAINTAINERS`` 文件以及
+-  搞清楚你修改的代码属于谁。查看源文件的根目录、 ``MAINTAINERS`` 文件以及
    ``CREDITS`` 文件的最后一部分。你应该和此人协调,确保你没有重新发明轮子,
    或者尝试一些已经被拒绝的东西。
 
@@ -629,12 +628,12 @@ C++
    “obj-$(CONFIG_xxx) += xxx.o”。语法记录在
    Documentation/kbuild/makefiles.rst 。
 
--  如果你做了一些有意义的事情,那可以把自己放进 ``CREDITS`` ,通常不止一个
-   文件(无论如何你的名字都应该在源文件的顶部)。维护人员意味着您希望在对
-   子系统进行更改时得到询问,并了解缺陷;这意味着对某部分代码做出更多承诺。
+-  如果你认为自己做了一些有意义的事情,可以把自己放进 ``CREDITS`` ,通常不
+   止一个文件(无论如何你的名字都应该在源文件的顶部)。  ``MAINTAINERS``
+   意味着您希望在对子系统进行更改时得到询问,并了解缺陷;这意味着对某部分
+   代码做出更多承诺。
 
--  最后,别忘记去阅读 Documentation/process/submitting-patches.rst ,
-   也许还有 Documentation/process/submitting-drivers.rst 。
+-  最后,别忘记去阅读 Documentation/process/submitting-patches.rst。
 
 Kernel 仙女棒
 ===============
index 700df8a..f0b1070 100644 (file)
 .. toctree::
     :maxdepth: 1
 
+    mutex-design
+    spinlocks
+
 TODOList:
 
     * locktypes
     * lockdep-design
     * lockstat
     * locktorture
-    * mutex-design
     * rt-mutex-design
     * rt-mutex
     * seqlock
-    * spinlocks
     * ww-mutex-design
     * preempt-locking
     * pi-futex
diff --git a/Documentation/translations/zh_CN/locking/mutex-design.rst b/Documentation/translations/zh_CN/locking/mutex-design.rst
new file mode 100644 (file)
index 0000000..6aad543
--- /dev/null
@@ -0,0 +1,145 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/locking/mutex-design.rst
+
+:翻译:
+
+  唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
+
+================
+通用互斥锁子系统
+================
+
+:初稿:
+
+  Ingo Molnar <mingo@redhat.com>
+
+:更新:
+
+  Davidlohr Bueso <davidlohr@hp.com>
+
+什么是互斥锁?
+--------------
+
+在Linux内核中,互斥锁(mutex)指的是一个特殊的加锁原语,它在共享内存系统上
+强制保证序列化,而不仅仅是指在学术界或类似的理论教科书中出现的通用术语“相互
+排斥”。互斥锁是一种睡眠锁,它的行为类似于二进制信号量(semaphores),在
+2006年被引入时[1],作为后者的替代品。这种新的数据结构提供了许多优点,包括更
+简单的接口,以及在当时更少的代码量(见缺陷)。
+
+[1] https://lwn.net/Articles/164802/
+
+实现
+----
+
+互斥锁由“struct mutex”表示,在include/linux/mutex.h中定义,并在
+kernel/locking/mutex.c中实现。这些锁使用一个原子变量(->owner)来跟踪
+它们生命周期内的锁状态。字段owner实际上包含的是指向当前锁所有者的
+`struct task_struct *` 指针,因此如果无人持有锁,则它的值为空(NULL)。
+由于task_struct的指针至少按L1_CACHE_BYTES对齐,低位(3)被用来存储额外
+的状态(例如,等待者列表非空)。在其最基本的形式中,它还包括一个等待队列和
+一个确保对其序列化访问的自旋锁。此外,CONFIG_MUTEX_SPIN_ON_OWNER=y的
+系统使用一个自旋MCS锁(->osq,译注:MCS是两个人名的合并缩写),在下文的
+(ii)中描述。
+
+准备获得一把自旋锁时,有三种可能经过的路径,取决于锁的状态:
+
+(i) 快速路径:试图通过调用cmpxchg()修改锁的所有者为当前任务,以此原子化地
+    获取锁。这只在无竞争的情况下有效(cmpxchg()检查值是否为0,所以3个状态
+    比特必须为0)。如果锁处在竞争状态,代码进入下一个可能的路径。
+
+(ii) 中速路径:也就是乐观自旋,当锁的所有者正在运行并且没有其它优先级更高的
+     任务(need_resched,需要重新调度)准备运行时,当前任务试图自旋来获得
+     锁。原理是,如果锁的所有者正在运行,它很可能不久就会释放锁。互斥锁自旋体
+     使用MCS锁排队,这样只有一个自旋体可以竞争互斥锁。
+
+     MCS锁(由Mellor-Crummey和Scott提出)是一个简单的自旋锁,它具有一些
+     理想的特性,比如公平,以及每个CPU在试图获得锁时在一个本地变量上自旋。
+     它避免了常见的“检测-设置”自旋锁实现导致的(CPU核间)缓存行回弹
+     (cacheline bouncing)这种昂贵的开销。一个类MCS锁是为实现睡眠锁的
+     乐观自旋而专门定制的。这种定制MCS锁的一个重要特性是,它有一个额外的属性,
+     当自旋体需要重新调度时,它们能够退出MCS自旋锁队列。这进一步有助于避免
+     以下场景:需要重新调度的MCS自旋体将继续自旋等待自旋体所有者,即将获得
+     MCS锁时却直接进入慢速路径。
+
+(iii) 慢速路径:最后的手段,如果仍然无法获得锁,该任务会被添加到等待队列中,
+      休眠直到被解锁路径唤醒。在通常情况下,它以TASK_UNINTERRUPTIBLE状态
+      阻塞。
+
+虽然从形式上看,内核互斥锁是可睡眠的锁,路径(ii)使它实际上成为混合类型。通过
+简单地不中断一个任务并忙着等待几个周期,而不是立即睡眠,这种锁已经被认为显著
+改善一些工作负载的性能。注意,这种技术也被用于读写信号量(rw-semaphores)。
+
+语义
+----
+
+互斥锁子系统检查并强制执行以下规则:
+
+    - 每次只有一个任务可以持有该互斥锁。
+    - 只有锁的所有者可以解锁该互斥锁。
+    - 不允许多次解锁。
+    - 不允许递归加锁/解锁。
+    - 互斥锁只能通过API进行初始化(见下文)。
+    - 一个任务不能在持有互斥锁的情况下退出。
+    - 持有锁的内存区域不得被释放。
+    - 被持有的锁不能被重新初始化。
+    - 互斥锁不能用于硬件或软件中断上下文,如小任务(tasklet)和定时器。
+
+当CONFIG DEBUG_MUTEXES被启用时,这些语义将被完全强制执行。此外,互斥锁
+调试代码还实现了一些其它特性,使锁的调试更容易、更快速:
+
+    - 当打印到调试输出时,总是使用互斥锁的符号名称。
+    - 加锁点跟踪,函数名符号化查找,系统持有的全部锁的列表,打印出它们。
+    - 所有者跟踪。
+    - 检测自我递归的锁并打印所有相关信息。
+    - 检测多任务环形依赖死锁,并打印所有受影响的锁和任务(并且只限于这些任务)。
+
+
+接口
+----
+静态定义互斥锁::
+
+   DEFINE_MUTEX(name);
+
+动态初始化互斥锁::
+
+   mutex_init(mutex);
+
+以不可中断方式(uninterruptible)获取互斥锁::
+
+   void mutex_lock(struct mutex *lock);
+   void mutex_lock_nested(struct mutex *lock, unsigned int subclass);
+   int  mutex_trylock(struct mutex *lock);
+
+以可中断方式(interruptible)获取互斥锁::
+
+   int mutex_lock_interruptible_nested(struct mutex *lock,
+                                      unsigned int subclass);
+   int mutex_lock_interruptible(struct mutex *lock);
+
+当原子变量减为0时,以可中断方式(interruptible)获取互斥锁::
+
+   int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock);
+
+释放互斥锁::
+
+   void mutex_unlock(struct mutex *lock);
+
+检测是否已经获取互斥锁::
+
+   int mutex_is_locked(struct mutex *lock);
+
+缺陷
+----
+
+与它最初的设计和目的不同,'struct mutex' 是内核中最大的锁之一。例如:在
+x86-64上它是32字节,而 'struct semaphore' 是24字节,rw_semaphore是
+40字节。更大的结构体大小意味着更多的CPU缓存和内存占用。
+
+
+何时使用互斥锁
+--------------
+
+总是优先选择互斥锁而不是任何其它锁原语,除非互斥锁的严格语义不合适,和/或临界区
+阻止锁被共享。
index 4ee7de1..6a469e1 100644 (file)
@@ -19,8 +19,7 @@
 内核开发社区已经发展出一套用于发布补丁的约定和过程;遵循这些约定和过程将使
 参与其中的每个人的生活更加轻松。本文档试图描述这些约定的部分细节;更多信息
 也可在以下文档中找到
-:ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`,
-:ref:`Documentation/translations/zh_CN/process/submitting-drivers.rst <cn_submittingdrivers>`
+:ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`
 和 :ref:`Documentation/translations/zh_CN/process/submit-checklist.rst <cn_submitchecklist>`。
 
 何时寄送
index 4707f01..643b88a 100644 (file)
@@ -19,7 +19,6 @@
 :ref:`Documentation/translations/zh_CN/process/howto.rst <cn_process_howto>`
 文件是一个重要的起点;
 :ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`
-和 :ref:`Documentation/translations/zh_CN/process/submitting-drivers.rst <cn_submittingdrivers>`
 也是所有内核开发人员都应该阅读的内容。许多内部内核API都是使用kerneldoc机制
 记录的;“make htmldocs”或“make pdfdocs”可用于以HTML或PDF格式生成这些文档
 (尽管某些发行版提供的tex版本会遇到内部限制,无法正确处理文档)。
index 1334cdb..1455190 100644 (file)
@@ -96,7 +96,6 @@ Linux内核代码中包含有大量的文档。这些文档对于学习如何与
     的代码。
 
   :ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`
-  :ref:`Documentation/process/submitting-drivers.rst <submittingdrivers>`
 
     这两份文档明确描述如何创建和发送补丁,其中包括(但不仅限于):
        - 邮件内容
index 39e9c88..a683dbe 100644 (file)
@@ -40,7 +40,6 @@
 .. toctree::
    :maxdepth: 1
 
-   submitting-drivers
    submit-checklist
    stable-api-nonsense
    stable-kernel-rules
diff --git a/Documentation/translations/zh_CN/process/submitting-drivers.rst b/Documentation/translations/zh_CN/process/submitting-drivers.rst
deleted file mode 100644 (file)
index 98341e7..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-.. _cn_submittingdrivers:
-
-.. include:: ../disclaimer-zh_CN.rst
-
-:Original: :ref:`Documentation/process/submitting-drivers.rst
-           <submittingdrivers>`
-
-如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
-交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
-译存在问题,请联系中文版维护者::
-
-        中文版维护者: 李阳  Li Yang <leoyang.li@nxp.com>
-        中文版翻译者: 李阳  Li Yang <leoyang.li@nxp.com>
-        中文版校译者: 陈琦 Maggie Chen <chenqi@beyondsoft.com>
-                       王聪 Wang Cong <xiyou.wangcong@gmail.com>
-                       张巍 Zhang Wei <wezhang@outlook.com>
-
-如何向 Linux 内核提交驱动程序
-=============================
-
-这篇文档将会解释如何向不同的内核源码树提交设备驱动程序。请注意,如果你感
-兴趣的是显卡驱动程序,你也许应该访问 XFree86 项目(https://www.xfree86.org/)
-和/或 X.org 项目 (https://x.org)。
-
-另请参阅 Documentation/translations/zh_CN/process/submitting-patches.rst 文档。
-
-
-分配设备号
-----------
-
-块设备和字符设备的主设备号与从设备号是由 Linux 命名编号分配权威 LANANA(
-现在是 Torben Mathiasen)负责分配。申请的网址是 https://www.lanana.org/。
-即使不准备提交到主流内核的设备驱动也需要在这里分配设备号。有关详细信息,
-请参阅 Documentation/admin-guide/devices.rst。
-
-如果你使用的不是已经分配的设备号,那么当你提交设备驱动的时候,它将会被强
-制分配一个新的设备号,即便这个设备号和你之前发给客户的截然不同。
-
-设备驱动的提交对象
-------------------
-
-Linux 2.0:
-       此内核源码树不接受新的驱动程序。
-
-Linux 2.2:
-       此内核源码树不接受新的驱动程序。
-
-Linux 2.4:
-       如果所属的代码领域在内核的 MAINTAINERS 文件中列有一个总维护者,
-       那么请将驱动程序提交给他。如果此维护者没有回应或者你找不到恰当的
-       维护者,那么请联系 Willy Tarreau <w@1wt.eu>。
-
-Linux 2.6:
-       除了遵循和 2.4 版内核同样的规则外,你还需要在 linux-kernel 邮件
-       列表上跟踪最新的 API 变化。向 Linux 2.6 内核提交驱动的顶级联系人
-       是 Andrew Morton <akpm@linux-foundation.org>。
-
-决定设备驱动能否被接受的条件
-----------------------------
-
-许可:              代码必须使用 GNU 通用公开许可证 (GPL) 提交给 Linux,但是
-               我们并不要求 GPL 是唯一的许可。你或许会希望同时使用多种
-               许可证发布,如果希望驱动程序可以被其他开源社区(比如BSD)
-               使用。请参考 include/linux/module.h 文件中所列出的可被
-               接受共存的许可。
-
-版权:              版权所有者必须同意使用 GPL 许可。最好提交者和版权所有者
-               是相同个人或实体。否则,必需列出授权使用 GPL 的版权所有
-               人或实体,以备验证之需。
-
-接口:              如果你的驱动程序使用现成的接口并且和其他同类的驱动程序行
-               为相似,而不是去发明无谓的新接口,那么它将会更容易被接受。
-               如果你需要一个 Linux 和 NT 的通用驱动接口,那么请在用
-               户空间实现它。
-
-代码:              请使用 Documentation/process/coding-style.rst 中所描述的 Linux 代码风
-               格。如果你的某些代码段(例如那些与 Windows 驱动程序包共
-               享的代码段)需要使用其他格式,而你却只希望维护一份代码,
-               那么请将它们很好地区分出来,并且注明原因。
-
-可移植性:        请注意,指针并不永远是 32 位的,不是所有的计算机都使用小
-               尾模式 (little endian) 存储数据,不是所有的人都拥有浮点
-               单元,不要随便在你的驱动程序里嵌入 x86 汇编指令。只能在
-               x86 上运行的驱动程序一般是不受欢迎的。虽然你可能只有 x86
-               硬件,很难测试驱动程序在其他平台上是否可用,但是确保代码
-               可以被轻松地移植却是很简单的。
-
-清晰度:   做到所有人都能修补这个驱动程序将会很有好处,因为这样你将
-               会直接收到修复的补丁而不是 bug 报告。如果你提交一个试图
-               隐藏硬件工作机理的驱动程序,那么它将会被扔进废纸篓。
-
-电源管理:        因为 Linux 正在被很多移动设备和桌面系统使用,所以你的驱
-               动程序也很有可能被使用在这些设备上。它应该支持最基本的电
-               源管理,即在需要的情况下实现系统级休眠和唤醒要用到的
-               .suspend 和 .resume 函数。你应该检查你的驱动程序是否能正
-               确地处理休眠与唤醒,如果实在无法确认,请至少把 .suspend
-               函数定义成返回 -ENOSYS(功能未实现)错误。你还应该尝试确
-               保你的驱动在什么都不干的情况下将耗电降到最低。要获得驱动
-               程序测试的指导,请参阅
-               Documentation/power/drivers-testing.rst。有关驱动程序电
-               源管理问题相对全面的概述,请参阅
-               Documentation/driver-api/pm/devices.rst。
-
-管理:              如果一个驱动程序的作者还在进行有效的维护,那么通常除了那
-               些明显正确且不需要任何检查的补丁以外,其他所有的补丁都会
-               被转发给作者。如果你希望成为驱动程序的联系人和更新者,最
-               好在代码注释中写明并且在 MAINTAINERS 文件中加入这个驱动
-               程序的条目。
-
-不影响设备驱动能否被接受的条件
-------------------------------
-
-供应商:   由硬件供应商来维护驱动程序通常是一件好事。不过,如果源码
-               树里已经有其他人提供了可稳定工作的驱动程序,那么请不要期
-               望“我是供应商”会成为内核改用你的驱动程序的理由。理想的情
-               况是:供应商与现有驱动程序的作者合作,构建一个统一完美的
-               驱动程序。
-
-作者:              驱动程序是由大的 Linux 公司研发还是由你个人编写,并不影
-               响其是否能被内核接受。没有人对内核源码树享有特权。只要你
-               充分了解内核社区,你就会发现这一点。
-
-
-资源列表
---------
-
-Linux 内核主源码树:
-       ftp.??.kernel.org:/pub/linux/kernel/...
-       ?? == 你的国家代码,例如 "cn"、"us"、"uk"、"fr" 等等
-
-Linux 内核邮件列表:
-       linux-kernel@vger.kernel.org
-       [可通过向majordomo@vger.kernel.org发邮件来订阅]
-
-Linux 设备驱动程序,第三版(探讨 2.6.10 版内核):
-       https://lwn.net/Kernel/LDD3/ (免费版)
-
-LWN.net:
-       每周内核开发活动摘要 - https://lwn.net/
-
-       2.6 版中 API 的变更:
-
-               https://lwn.net/Articles/2.6-kernel-api/
-
-       将旧版内核的驱动程序移植到 2.6 版:
-
-               https://lwn.net/Articles/driver-porting/
-
-内核新手(KernelNewbies):
-       为新的内核开发者提供文档和帮助
-       https://kernelnewbies.org/
-
-Linux USB项目:
-       http://www.linux-usb.org/
-
-写内核驱动的“不要”(Arjan van de Ven著):
-       http://www.fenrus.org/how-to-not-write-a-device-driver-paper.pdf
-
-内核清洁工 (Kernel Janitor):
-       https://kernelnewbies.org/KernelJanitors
index a957016..ebb7f37 100644 (file)
@@ -23,9 +23,7 @@
 以下文档含有大量简洁的建议, 具体请见:
 :ref:`Documentation/process <development_process_main>`
 同样,:ref:`Documentation/translations/zh_CN/process/submit-checklist.rst <cn_submitchecklist>`
-给出在提交代码前需要检查的项目的列表。如果你在提交一个驱动程序,那么
-同时阅读一下:
-:ref:`Documentation/process/submitting-drivers.rst <submittingdrivers>`
+给出在提交代码前需要检查的项目的列表。
 
 其中许多步骤描述了Git版本控制系统的默认行为;如果您使用Git来准备补丁,
 您将发现它为您完成的大部分机械工作,尽管您仍然需要准备和记录一组合理的
index 614cde0..131e405 100644 (file)
@@ -19,7 +19,6 @@ RISC-V 体系结构
 
     boot-image-header
     vm-layout
-    pmu
     patch-acceptance
 
 
diff --git a/Documentation/translations/zh_CN/riscv/pmu.rst b/Documentation/translations/zh_CN/riscv/pmu.rst
deleted file mode 100644 (file)
index 7ec8010..0000000
+++ /dev/null
@@ -1,235 +0,0 @@
-.. include:: ../disclaimer-zh_CN.rst
-
-:Original: Documentation/riscv/pmu.rst
-
-:翻译:
-
- 司延腾 Yanteng Si <siyanteng@loongson.cn>
-
-.. _cn_riscv_pmu:
-
-========================
-RISC-V平台上对PMUs的支持
-========================
-
-Alan Kao <alankao@andestech.com>, Mar 2018
-
-简介
-------------
-
-截止本文撰写时,在The RISC-V ISA Privileged Version 1.10中提到的 perf_event
-相关特性如下:
-(详情请查阅手册)
-
-* [m|s]counteren
-* mcycle[h], cycle[h]
-* minstret[h], instret[h]
-* mhpeventx, mhpcounterx[h]
-
-仅有以上这些功能,移植perf需要做很多工作,究其原因是缺少以下通用架构的性能
-监测特性:
-
-* 启用/停用计数器
-  在我们这里,计数器一直在自由运行。
-* 计数器溢出引起的中断
-  规范中没有这种功能。
-* 中断指示器
-  不可能所有的计数器都有很多的中断端口,所以需要一个中断指示器让软件来判断
-  哪个计数器刚好溢出。
-* 写入计数器
-  由于内核不能修改计数器,所以会有一个SBI来支持这个功能[1]。 另外,一些厂商
-  考虑实现M-S-U型号机器的硬件扩展来直接写入计数器。
-
-这篇文档旨在为开发者提供一个在内核中支持PMU的简要指南。下面的章节简要解释了
-perf' 机制和待办事项。
-
-你可以在这里查看以前的讨论[1][2]。 另外,查看附录中的相关内核结构体可能会有
-帮助。
-
-
-1. 初始化
----------
-
-*riscv_pmu* 是一个类型为 *struct riscv_pmu* 的全局指针,它包含了根据perf内部
-约定的各种方法和PMU-specific参数。人们应该声明这样的实例来代表PMU。 默认情况
-下, *riscv_pmu* 指向一个常量结构体 *riscv_base_pmu* ,它对基准QEMU模型有非常
-基础的支持。
-
-
-然后他/她可以将实例的指针分配给 *riscv_pmu* ,这样就可以利用已经实现的最小逻
-辑,或者创建他/她自己的 *riscv_init_platform_pmu* 实现。
-
-换句话说,现有的 *riscv_base_pmu* 源只是提供了一个参考实现。 开发者可以灵活地
-决定多少部分可用,在最极端的情况下,他们可以根据自己的需要定制每一个函数。
-
-
-2. Event Initialization
------------------------
-
-当用户启动perf命令来监控一些事件时,首先会被用户空间的perf工具解释为多个
-*perf_event_open* 系统调用,然后进一步调用上一步分配的 *event_init* 成员函数
-的主体。 在 *riscv_base_pmu* 的情况下,就是 *riscv_event_init* 。
-
-该功能的主要目的是将用户提供的事件翻译成映射图,从而可以直接对HW-related的控
-制寄存器或计数器进行操作。该翻译基于 *riscv_pmu* 中提供的映射和方法。
-
-注意,有些功能也可以在这个阶段完成:
-
-(1) 中断设置,这个在下一节说;
-(2) 特限级设置(仅用户空间、仅内核空间、两者都有);
-(3) 析构函数设置。 通常应用 *riscv_destroy_event* 即可;
-(4) 对非采样事件的调整,这将被函数应用,如 *perf_adjust_period* ,通常如下::
-
-      if (!is_sampling_event(event)) {
-              hwc->sample_period = x86_pmu.max_period;
-              hwc->last_period = hwc->sample_period;
-              local64_set(&hwc->period_left, hwc->sample_period);
-      }
-
-
-在 *riscv_base_pmu* 的情况下,目前只提供了(3)。
-
-
-3. 中断
--------
-
-3.1. 中断初始化
-
-这种情况经常出现在 *event_init* 方案的开头。通常情况下,这应该是一个代码段,如::
-
-  int x86_reserve_hardware(void)
-  {
-        int err = 0;
-
-        if (!atomic_inc_not_zero(&pmc_refcount)) {
-                mutex_lock(&pmc_reserve_mutex);
-                if (atomic_read(&pmc_refcount) == 0) {
-                        if (!reserve_pmc_hardware())
-                                err = -EBUSY;
-                        else
-                                reserve_ds_buffers();
-                }
-                if (!err)
-                        atomic_inc(&pmc_refcount);
-                mutex_unlock(&pmc_reserve_mutex);
-        }
-
-        return err;
-  }
-
-而神奇的是 *reserve_pmc_hardware* ,它通常做原子操作,使实现的IRQ可以从某个全局函
-数指针访问。 而 *release_pmc_hardware* 的作用正好相反,它用在上一节提到的事件分配
-器中。
-
- (注:从所有架构的实现来看,*reserve/release* 对总是IRQ设置,所以 *pmc_hardware*
- 似乎有些误导。 它并不处理事件和物理计数器之间的绑定,这一点将在下一节介绍。)
-
-3.2. IRQ结构体
-
-基本上,一个IRQ运行以下伪代码::
-
-  for each hardware counter that triggered this overflow
-
-      get the event of this counter
-
-      // following two steps are defined as *read()*,
-      // check the section Reading/Writing Counters for details.
-      count the delta value since previous interrupt
-      update the event->count (# event occurs) by adding delta, and
-                 event->hw.period_left by subtracting delta
-
-      if the event overflows
-          sample data
-          set the counter appropriately for the next overflow
-
-          if the event overflows again
-              too frequently, throttle this event
-          fi
-      fi
-
-  end for
-
- 然而截至目前,没有一个RISC-V的实现为perf设计了中断,所以具体的实现要在未来完成。
-
-4. Reading/Writing 计数
------------------------
-
-它们看似差不多,但perf对待它们的态度却截然不同。 对于读,在 *struct pmu* 中有一个
-*read* 接口,但它的作用不仅仅是读。 根据上下文,*read* 函数不仅要读取计数器的内容
-(event->count),还要更新左周期到下一个中断(event->hw.period_left)。
-
- 但 perf 的核心不需要直接写计数器。 写计数器隐藏在以下两点的抽象化之后,
- 1) *pmu->start* ,从字面上看就是开始计数,所以必须把计数器设置成一个合适的值,以
- 便下一次中断;
- 2)在IRQ里面,应该把计数器设置成同样的合理值。
-
-在RISC-V中,读操作不是问题,但写操作就需要费些力气了,因为S模式不允许写计数器。
-
-
-5. add()/del()/start()/stop()
------------------------------
-
-基本思想: add()/del() 向PMU添加/删除事件,start()/stop() 启动/停止PMU中某个事件
-的计数器。 所有这些函数都使用相同的参数: *struct perf_event *event* 和 *int flag* 。
-
-把 perf 看作一个状态机,那么你会发现这些函数作为这些状态之间的状态转换过程。
-定义了三种状态(event->hw.state):
-
-* PERF_HES_STOPPED:    计数停止
-* PERF_HES_UPTODATE:   event->count是最新的
-* PERF_HES_ARCH:       依赖于体系结构的用法,。。。我们现在并不需要它。
-
-这些状态转换的正常流程如下:
-
-* 用户启动一个 perf 事件,导致调用 *event_init* 。
-* 当被上下文切换进来的时候,*add* 会被 perf core 调用,并带有一个标志 PERF_EF_START,
-  也就是说事件被添加后应该被启动。 在这个阶段,如果有的话,一般事件会被绑定到一个物
-  理计数器上。当状态变为PERF_HES_STOPPED和PERF_HES_UPTODATE,因为现在已经停止了,
-  (软件)事件计数不需要更新。
-
-  - 然后调用 *start* ,并启用计数器。
-    通过PERF_EF_RELOAD标志,它向计数器写入一个适当的值(详细情况请参考上一节)。
-    如果标志不包含PERF_EF_RELOAD,则不会写入任何内容。
-    现在状态被重置为none,因为它既没有停止也没有更新(计数已经开始)。
-
-*当被上下文切换出来时被调用。 然后,它检查出PMU中的所有事件,并调用 *stop* 来更新它们
- 的计数。
-
-  - *stop* 被 *del* 和perf核心调用,标志为PERF_EF_UPDATE,它经常以相同的逻辑和 *read*
-    共用同一个子程序。
-    状态又一次变为PERF_HES_STOPPED和PERF_HES_UPTODATE。
-
-  - 这两对程序的生命周期: *add* 和 *del* 在任务切换时被反复调用;*start* 和 *stop* 在
-    perf核心需要快速停止和启动时也会被调用,比如在调整中断周期时。
-
-目前的实现已经足够了,将来可以很容易地扩展到功能。
-
-A. 相关结构体
--------------
-
-* struct pmu: include/linux/perf_event.h
-* struct riscv_pmu: arch/riscv/include/asm/perf_event.h
-
-  两个结构体都被设计为只读。
-
-  *struct pmu* 定义了一些函数指针接口,它们大多以 *struct perf_event* 作为主参数,根据
-  perf的内部状态机处理perf事件(详情请查看kernel/events/core.c)。
-
-  *struct riscv_pmu* 定义了PMU的具体参数。 命名遵循所有其它架构的惯例。
-
-* struct perf_event: include/linux/perf_event.h
-* struct hw_perf_event
-
-  表示 perf 事件的通用结构体,以及硬件相关的细节。
-
-* struct riscv_hw_events: arch/riscv/include/asm/perf_event.h
-
-  保存事件状态的结构有两个固定成员。
-  事件的数量和事件的数组。
-
-参考文献
---------
-
-[1] https://github.com/riscv/riscv-linux/pull/124
-
-[2] https://groups.google.com/a/groups.riscv.org/forum/#!topic/sw-dev/f19TmCNP6yA
index 585cb89..91884e2 100644 (file)
@@ -6,6 +6,7 @@
 :翻译:
 
  司延腾 Yanteng Si <siyanteng@loongson.cn>
+        Binbin Zhou <zhoubinbin@loongson.cn>
 
 ============================
 RISC-V Linux上的虚拟内存布局
@@ -65,3 +66,39 @@ RISC-V Linux Kernel SV39
    ffffffff00000000 |   -4    GB | ffffffff7fffffff |    2 GB | modules, BPF
    ffffffff80000000 |   -2    GB | ffffffffffffffff |    2 GB | kernel
   __________________|____________|__________________|_________|____________________________________________________________
+
+
+RISC-V Linux Kernel SV48
+------------------------
+
+::
+
+ ========================================================================================================================
+      开始地址       |   偏移      |     结束地址      |  大小    | 虚拟内存区域描述
+ ========================================================================================================================
+                    |            |                  |         |
+   0000000000000000 |    0       | 00007fffffffffff |  128 TB | 用户空间虚拟内存,每个内存管理器不同
+  __________________|____________|__________________|_________|___________________________________________________________
+                    |            |                  |         |
+   0000800000000000 | +128    TB | ffff7fffffffffff | ~16M TB | ... 巨大的、几乎64位宽的直到内核映射的-128TB地方
+                    |            |                  |         |     开始偏移的非经典虚拟内存地址空洞。
+                    |            |                  |         |
+  __________________|____________|__________________|_________|___________________________________________________________
+                                                              |
+                                                              | 内核空间的虚拟内存,在所有进程之间共享:
+  ____________________________________________________________|___________________________________________________________
+                    |            |                  |         |
+   ffff8d7ffee00000 |  -114.5 TB | ffff8d7ffeffffff |    2 MB | fixmap
+   ffff8d7fff000000 |  -114.5 TB | ffff8d7fffffffff |   16 MB | PCI io
+   ffff8d8000000000 |  -114.5 TB | ffff8f7fffffffff |    2 TB | vmemmap
+   ffff8f8000000000 |  -112.5 TB | ffffaf7fffffffff |   32 TB | vmalloc/ioremap space
+   ffffaf8000000000 |  -80.5  TB | ffffef7fffffffff |   64 TB | 直接映射所有物理内存
+   ffffef8000000000 |  -16.5  TB | fffffffeffffffff | 16.5 TB | kasan
+  __________________|____________|__________________|_________|____________________________________________________________
+                                                              |
+                                                              | 从此处开始,与39-bit布局相同:
+  ____________________________________________________________|____________________________________________________________
+                    |            |                  |         |
+   ffffffff00000000 |   -4    GB | ffffffff7fffffff |    2 GB | modules, BPF
+   ffffffff80000000 |   -2    GB | ffffffffffffffff |    2 GB | kernel
+  __________________|____________|__________________|_________|____________________________________________________________
index 1c68c3d..c5e0be6 100644 (file)
@@ -57,8 +57,8 @@ cpu<N> 1 2 3 4 5 6 7 8 9
 
 接下来的三个统计数据描述了调度延迟:
 
-     7) 本处理器运行任务的总时间,单位是jiffies
-     8) 本处理器任务等待运行的时间,单位是jiffies
+     7) 本处理器运行任务的总时间,单位是纳秒
+     8) 本处理器任务等待运行的时间,单位是纳秒
      9) 本CPU运行了#个时间片
 
 域统计数据
@@ -146,8 +146,8 @@ domain<N> <cpumask> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 schedstats还添加了一个新的/proc/<pid>/schedstat文件,来提供一些进程级的
 相同信息。这个文件中,有三个字段与该进程相关:
 
-     1) 在CPU上运行花费的时间
-     2) 在运行队列上等待的时间
+     1) 在CPU上运行花费的时间(单位是纳秒)
+     2) 在运行队列上等待的时间(单位是纳秒)
      3) 在CPU上运行了#个时间片
 
 可以很容易地编写一个程序,利用这些额外的字段来报告一个特定的进程或一组进程在
index 31d6c34..14336a3 100644 (file)
@@ -1,6 +1,6 @@
 .. include:: ../disclaimer-zh_CN.rst
 
-:Original: Documentation/vm/_free_page_reporting.rst
+:Original: Documentation/vm/free_page_reporting.rst
 
 :翻译:
 
index 3eb0787..98aa6f5 100644 (file)
@@ -1,4 +1,4 @@
-:Original: Documentation/vm/_free_page_reporting.rst
+:Original: Documentation/vm/free_page_reporting.rst
 
 :翻译:
 
index 018838e..2003217 100644 (file)
 临时虚拟映射
 ============
 
-内核包含几种创建临时映射的方法。:
+内核包含几种创建临时映射的方法。下面的列表按照使用的优先顺序显示了它们。
 
-* vmap().  这可以用来将多个物理页长期映射到一个连续的虚拟空间。它需要synchronization
-  来解除映射
+* kmap_local_page()。这个函数是用来要求短期映射的。它可以从任何上下文(包括中断)中调用,
+  但是映射只能在获取它们的上下文中使用
 
-* kmap().  这允许对单个页面进行短期映射。它需要synchronization,但在一定程度上被摊销。
-  当以嵌套方式使用时,它也很容易出现死锁,因此不建议在新代码中使用它。
+  在可行的情况下,这个函数应该比其他所有的函数优先使用。
 
-* kmap_atomic().  这允许对单个页面进行非常短的时间映射。由于映射被限制在发布它的CPU上,
-  它表现得很好,但发布任务因此被要求留在该CPU上直到它完成,以免其他任务取代它的映射。
-
-  kmap_atomic() 也可以由中断上下文使用,因为它不睡眠,而且调用者可能在调用kunmap_atomic()
-  之后才睡眠。
-
-  可以假设k[un]map_atomic()不会失败。
+  这些映射是线程本地和CPU本地的,这意味着映射只能从这个线程中访问,并且当映射处于活动状
+  态时,该线程与CPU绑定。即使线程被抢占了(因为抢占永远不会被函数禁用),CPU也不能通过
+  CPU-hotplug从系统中拔出,直到映射被处理掉。
 
+  在本地的kmap区域中采取pagefaults是有效的,除非获取本地映射的上下文由于其他原因不允许
+  这样做。
 
-使用kmap_atomic
-===============
+  kmap_local_page()总是返回一个有效的虚拟地址,并且假定kunmap_local()不会失败。
 
-何时何地使用 kmap_atomic() 是很直接的。当代码想要访问一个可能从高内存(见__GFP_HIGHMEM)
-分配的页面的内容时,例如在页缓存中的页面,就会使用它。该API有两个函数,它们的使用方式与
-下面类似::
+  嵌套kmap_local_page()和kmap_atomic()映射在一定程度上是允许的(最多到KMAP_TYPE_NR),
+  但是它们的调用必须严格排序,因为映射的实现是基于堆栈的。关于如何管理嵌套映射的细节,
+  请参见kmap_local_page() kdocs(包含在 "函数 "部分)。
 
-       /* 找到感兴趣的页面。 */
-       struct page *page = find_get_page(mapping, offset);
-
-       /* 获得对该页内容的访问权。 */
-       void *vaddr = kmap_atomic(page);
+* kmap_atomic().  这允许对单个页面进行非常短的时间映射。由于映射被限制在发布它的CPU上,
+  它表现得很好,但发布的任务因此被要求留在该CPU上直到它完成,以免其他任务取代它的映射。
 
-       /* 对该页的内容做一些处理。 */
-       memset(vaddr, 0, PAGE_SIZE);
+  kmap_atomic()也可以被中断上下文使用,因为它不睡眠,调用者也可能在调用kunmap_atomic()
+  后才睡眠。
 
-       /* 解除该页面的映射。 */
-       kunmap_atomic(vaddr);
+  内核中对kmap_atomic()的每次调用都会创建一个不可抢占的段,并禁用缺页异常。这可能是
+  未预期延迟的来源之一。因此用户应该选择kmap_local_page()而不是kmap_atomic()。
 
-注意,kunmap_atomic()调用的是kmap_atomic()调用的结果而不是参数
+  假设k[un]map_atomic()不会失败
 
-如果你需要映射两个页面,因为你想从一个页面复制到另一个页面,你需要保持kmap_atomic调用严
-格嵌套,如::
+* kmap()。这应该被用来对单个页面进行短时间的映射,对抢占或迁移没有限制。它会带来开销,
+  因为映射空间是受限制的,并且受到全局锁的保护,以实现同步。当不再需要映射时,必须用
+  kunmap()释放该页被映射的地址。
 
-       vaddr1 = kmap_atomic(page1);
-       vaddr2 = kmap_atomic(page2);
+  映射变化必须广播到所有CPU(核)上,kmap()还需要在kmap的池被回绕(TLB项用光了,需要从第
+   一项复用)时进行全局TLB无效化,当映射空间被完全利用时,它可能会阻塞,直到有一个可用的
+   槽出现。因此,kmap()只能从可抢占的上下文中调用。
 
-       memcpy(vaddr1, vaddr2, PAGE_SIZE);
+  如果一个映射必须持续相对较长的时间,上述所有的工作都是必要的,但是内核中大部分的
+  高内存映射都是短暂的,而且只在一个地方使用。这意味着在这种情况下,kmap()的成本大
+  多被浪费了。kmap()并不是为长期映射而设计的,但是它已经朝着这个方向发展了,在较新
+  的代码中强烈不鼓励使用它,前面的函数集应该是首选。
 
-       kunmap_atomic(vaddr2);
-       kunmap_atomic(vaddr1);
+  在64位系统中,调用kmap_local_page()、kmap_atomic()和kmap()没有实际作用,因为64位
+  地址空间足以永久映射所有物理内存页面。
 
+* vmap()。这可以用来将多个物理页长期映射到一个连续的虚拟空间。它需要全局同步来解除
+  映射。
 
 临时映射的成本
 ==============
@@ -126,3 +126,12 @@ i386 PAE
 
 一般的建议是,你不要在32位机器上使用超过8GiB的空间--尽管更多的空间可能对你和你的工作
 量有用,但你几乎是靠你自己--不要指望内核开发者真的会很关心事情的进展情况。
+
+函数
+====
+
+该API在以下内核代码中:
+
+include/linux/highmem.h
+
+include/linux/highmem-internal.h
index a1c6d52..c77a565 100644 (file)
 Linux内存管理文档
 =================
 
-这是一个关于Linux内存管理(mm)子系统内部的文档集,其中有不同层次的细节,包括注释
-和邮件列表的回复,用于阐述数据结构和算法的基本情况。如果你正在寻找关于简单分配内存的建
-议,请参阅(Documentation/translations/zh_CN/core-api/memory-allocation.rst)。
-对于控制和调整指南,请参阅(Documentation/admin-guide/mm/index)。
-TODO:待引用文档集被翻译完毕后请及时修改此处)
+这是一份关于了解Linux的内存管理子系统的指南。如果你正在寻找关于简单分配内存的
+建议,请参阅内存分配指南
+(Documentation/translations/zh_CN/core-api/memory-allocation.rst)。
+关于控制和调整的指南,请看管理指南
+(Documentation/translations/zh_CN/admin-guide/mm/index.rst)。
+
+
+.. toctree::
+   :maxdepth: 1
+
+   highmem
+
+该处剩余文档待原始文档有内容后翻译。
+
+
+遗留文档
+========
+
+这是一个关于Linux内存管理(MM)子系统内部的旧文档的集合,其中有不同层次的细节,
+包括注释和邮件列表的回复,用于阐述数据结构和算法的描述。它应该被很好地整合到上述
+结构化的文档中,如果它已经完成了它的使命,可以删除。
 
 .. toctree::
    :maxdepth: 1
@@ -25,7 +41,6 @@ TODO:待引用文档集被翻译完毕后请及时修改此处)
    balance
    damon/index
    free_page_reporting
-   highmem
    ksm
    frontswap
    hmm
@@ -36,10 +51,12 @@ TODO:待引用文档集被翻译完毕后请及时修改此处)
    numa
    overcommit-accounting
    page_frags
+   page_migration
    page_owner
    page_table_check
    remap_file_pages
    split_page_table_lock
+   vmalloced-kernel-stacks
    z3fold
    zsmalloc
 
@@ -47,8 +64,6 @@ TODOLIST:
 * arch_pgtable_helpers
 * free_page_reporting
 * hugetlbfs_reserv
-* page_migration
 * slub
 * transhuge
 * unevictable-lru
-* vmalloced-kernel-stacks
index ad27fed..38ecddb 100644 (file)
@@ -1,4 +1,4 @@
-:Original: Documentation/vm/page_frag.rst
+:Original: Documentation/vm/page_frags.rst
 
 :翻译:
 
diff --git a/Documentation/translations/zh_CN/vm/page_migration.rst b/Documentation/translations/zh_CN/vm/page_migration.rst
new file mode 100644 (file)
index 0000000..566880a
--- /dev/null
@@ -0,0 +1,228 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/vm/index.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+========
+页面迁移
+========
+
+页面迁移允许在进程运行时在NUMA系统的节点之间移动页面的物理位置。这意味着进程所看到的虚拟地
+址并没有改变。然而,系统会重新安排这些页面的物理位置。
+
+也可以参见 :ref: `<异构内存管理 (HMM)>` 以了解将页面迁移到设备私有内存或从设备私有内存中迁移。
+
+页面迁移的主要目的是通过将页面移到访问该内存的进程所运行的处理器附近来减少内存访问的延迟。
+
+页面迁移允许进程通过MF_MOVE和MF_MOVE_ALL选项手动重新定位其页面所在的节点,同时通过
+mbind()设置一个新的内存策略。一个进程的页面也可以通过sys_migrate_pages()函数调用从另
+一个进程重新定位。migrate_pages()函数调用接收两组节点,并将一个进程位于旧节点上的页面移
+动到目标节点上。页面迁移功能由Andi Kleen的numactl包提供(需要0.9.3以上的版本,其仓库
+地址https://github.com/numactl/numactl.git)。numactl提供了libnuma,它为页面迁移
+提供了与其他NUMA功能类似的接口。执行 cat ``/proc/<pid>/numa_maps``  允许轻松查看进
+程的页面位置。参见proc(5)手册中的numa_maps文档。
+
+如果调度程序将一个进程重新安置到一个遥远的节点上的处理器,手动迁移是很有用的。批量调度程序
+或管理员可以检测到这种情况,并将进程的页面移到新处理器附近。内核本身只提供手动的页迁移支持。
+自动的页面迁移可以通过用户空间的进程移动页面来实现。一个特殊的函数调用 "move_pages" 允许
+在一个进程中移动单个页面。例如,NUMA分析器可以获得一个显示频繁的节点外访问的日志,并可以使
+用这个结果将页面移动到更有利的位置。
+
+较大型的设备通常使用cpusets将系统分割成若干个节点。Paul Jackson为cpusets配备了当任务被
+转移到另一个cpuset时移动页面的能力(见:ref:`CPUSETS <cpusets>`)。Cpusets允许进程定
+位的自动化。如果一个任务被移到一个新的cpuset上,那么它的所有页面也会随之移动,这样进程的
+性能就不会急剧下降。如果cpuset允许的内存节点发生变化,cpuset中的进程页也会被移动。
+
+页面迁移允许为所有迁移技术保留一组节点中页面的相对位置,这将保留生成的特定内存分配模式即使
+进程已被迁移。为了保留内存延迟,这一点是必要的。迁移后的进程将以类似的性能运行。
+
+页面迁移分几个步骤进行。首先为那些试图从内核中使用migrate_pages()的进程做一个高层次的
+描述(对于用户空间的使用,可以参考上面提到的Andi Kleen的numactl包),然后对低水平的细
+节工作做一个低水平描述。
+
+在内核中使用 migrate_pages()
+============================
+
+1. 从LRU中移除页面。
+
+   要迁移的页面列表是通过扫描页面并把它们移到列表中来生成的。这是通过调用 isolate_lru_page()
+   来完成的。调用isolate_lru_page()增加了对该页的引用,这样在页面迁移发生时它就不会
+   消失。它还可以防止交换器或其他扫描器遇到该页。
+
+
+2. 我们需要有一个new_page_t类型的函数,可以传递给migrate_pages()。这个函数应该计算
+   出如何在给定的旧页面中分配正确的新页面。
+
+3. migrate_pages()函数被调用,它试图进行迁移。它将调用该函数为每个被考虑迁移的页面分
+   配新的页面。
+
+migrate_pages()如何工作
+=======================
+
+migrate_pages()对它的页面列表进行了多次处理。如果当时对一个页面的所有引用都可以被移除,
+那么这个页面就会被移动。该页已经通过isolate_lru_page()从LRU中移除,并且refcount被
+增加,以便在页面迁移发生时不释放该页。
+
+步骤:
+
+1. 锁定要迁移的页面。
+
+2. 确保回写已经完成。
+
+3. 锁定我们要迁移到的新页面。锁定它是为了在迁移过程中立即阻止对这个(尚未更新的)页面的
+   访问。
+
+4. 所有对该页的页表引用都被转换为迁移条目。这就减少了一个页面的mapcount。如果产生的
+   mapcount不是零,那么我们就不迁移该页。所有试图访问该页的用户空间进程现在将等待页
+   面锁或者等待迁移页表项被移除。
+
+5. i_pages的锁被持有。这将导致所有试图通过映射访问该页的进程在自旋锁上阻塞。
+
+6. 检查该页的Refcount,如果还有引用,我们就退出。否则,我们知道我们是唯一引用这个页
+   面的人。
+
+7. 检查基数树,如果它不包含指向这个页面的指针,那么我们就退出,因为其他人修改了基数树。
+
+8. 新的页面要用旧的页面的一些设置进行预处理,这样访问新的页面就会发现一个具有正确设置
+   的页面。
+
+9. 基数树被改变以指向新的页面。
+
+10. 旧页的引用计数被删除,因为地址空间的引用已经消失。对新页的引用被建立,因为新页被
+    地址空间引用。
+
+11. i_pages锁被放弃。这样一来,在映射中的查找又变得可能了。进程将从在锁上自旋到在
+    被锁的新页上睡眠。
+
+12. 页面内容被复制到新的页面上。
+
+13. 剩余的页面标志被复制到新的页面上。
+
+14. 旧的页面标志被清除,以表明该页面不再提供任何信息。
+
+15. 新页面上的回写队列被触发了。
+
+16. 如果迁移条目被插入到页表中,那么就用真正的ptes替换它们。这样做将使那些尚未等待页
+    锁的用户空间进程能够访问。
+
+17. 页面锁从新旧页面上被撤销。等待页锁的进程将重做他们的缺页异常,并将到达新的页面。
+
+18. 新的页面被移到LRU中,可以被交换器等再次扫描。
+
+非LRU页面迁移
+=============
+
+尽管迁移最初的目的是为了减少NUMA的内存访问延迟,但压缩也使用迁移来创建高阶页面。
+
+目前实现的问题是,它被设计为只迁移*LRU*页。然而,有一些潜在的非LRU页面可以在驱动中
+被迁移,例如,zsmalloc,virtio-balloon页面。
+
+对于virtio-balloon页面,迁移代码路径的某些部分已经被钩住,并添加了virtio-balloon
+的特定函数来拦截迁移逻辑。这对一个驱动来说太特殊了,所以其他想让自己的页面可移动的驱
+动就必须在迁移路径中添加自己的特定钩子。
+
+为了克服这个问题,VM支持非LRU页面迁移,它为非LRU可移动页面提供了通用函数,而在迁移
+路径中没有特定的驱动程序钩子。
+
+如果一个驱动程序想让它的页面可移动,它应该定义三个函数,这些函数是
+struct address_space_operations的函数指针。
+
+1. ``bool (*isolate_page) (struct page *page, isolate_mode_t mode);``
+
+   VM对驱动的isolate_page()函数的期望是,如果驱动成功隔离了该页,则返回*true*。
+   返回true后,VM会将该页标记为PG_isolated,这样多个CPU的并发隔离就会跳过该
+   页进行隔离。如果驱动程序不能隔离该页,它应该返回*false*。
+
+   一旦页面被成功隔离,VM就会使用page.lru字段,因此驱动程序不应期望保留这些字段的值。
+
+2. ``int (*migratepage) (struct address_space *mapping,``
+|      ``struct page *newpage, struct page *oldpage, enum migrate_mode);``
+
+   隔离后,虚拟机用隔离的页面调用驱动的migratepage()。migratepage()的功能是将旧页
+   的内容移动到新页,并设置struct page newpage的字段。请记住,如果你成功迁移了旧页
+   并返回MIGRATEPAGE_SUCCESS,你应该通过page_lock下的__ClearPageMovable()向虚
+   拟机表明旧页不再可移动。如果驱动暂时不能迁移该页,驱动可以返回-EAGAIN。在-EAGAIN
+   时,VM会在短时间内重试页面迁移,因为VM将-EAGAIN理解为 "临时迁移失败"。在返回除
+   -EAGAIN以外的任何错误时,VM将放弃页面迁移而不重试。
+
+   在migratepage()函数中,驱动程序不应该接触page.lru字段。
+
+3. ``void (*putback_page)(struct page *);``
+
+   如果在隔离页上迁移失败,VM应该将隔离页返回给驱动,因此VM用隔离页调用驱动的
+   putback_page()。在这个函数中,驱动应该把隔离页放回自己的数据结构中。
+
+非LRU可移动页标志
+
+   有两个页面标志用于支持非LRU可移动页面。
+
+   * PG_movable
+
+     驱动应该使用下面的函数来使页面在page_lock下可移动。::
+
+       void __SetPageMovable(struct page *page, struct address_space *mapping)
+
+     它需要address_space的参数来注册将被VM调用的migration family函数。确切地说,
+     PG_movable不是struct page的一个真正的标志。相反,VM复用了page->mapping的低
+     位来表示它::
+
+       #define PAGE_MAPPING_MOVABLE 0x2
+       page->mapping = page->mapping | PAGE_MAPPING_MOVABLE;
+
+     所以驱动不应该直接访问page->mapping。相反,驱动应该使用page_mapping(),它可
+     以在页面锁下屏蔽掉page->mapping的低2位,从而获得正确的struct address_space。
+
+     对于非LRU可移动页面的测试,VM支持__PageMovable()函数。然而,它并不能保证识别
+     非LRU可移动页面,因为page->mapping字段与struct page中的其他变量是统一的。如
+     果驱动程序在被虚拟机隔离后释放了页面,尽管page->mapping设置了PAGE_MAPPING_MOVABLE,
+     但它并没有一个稳定的值(看看__ClearPageMovable)。但是__PageMovable()在页
+     面被隔离后,无论页面是LRU还是非LRU可移动的,调用它开销都很低,因为LRU页面在
+     page->mapping中不可能有PAGE_MAPPING_MOVABLE设置。在用pfn扫描中的lock_page()
+     进行更大开销的检查来选择受害者之前,它也很适合只是瞥一眼来测试非LRU可移动的页面。
+
+     为了保证非LRU的可移动页面,VM提供了PageMovable()函数。与__PageMovable()不
+     同,PageMovable()在lock_page()下验证page->mapping和
+     mapping->a_ops->isolate_page。lock_page()可以防止突然破坏page->mapping。
+
+     使用__SetPageMovable()的驱动应该在释放页面之前通过page_lock()下的
+     __ClearMovablePage()清除该标志。
+
+   * PG_isolated
+
+     为了防止几个CPU同时进行隔离,VM在lock_page()下将隔离的页面标记为PG_isolated。
+     因此,如果一个CPU遇到PG_isolated非LRU可移动页面,它可以跳过它。驱动程序不需要
+     操作这个标志,因为VM会自动设置/清除它。请记住,如果驱动程序看到PG_isolated页,
+     这意味着该页已经被VM隔离,所以它不应该碰page.lru字段。PG_isolated标志与
+     PG_reclaim标志是同义的,所以驱动程序不应该为自己的目的使用PG_isolated。
+
+监测迁移
+========
+
+以下事件(计数器)可用于监控页面迁移。
+
+1. PGMIGRATE_SUCCESS: 正常的页面迁移成功。每个计数器意味着一个页面被迁移了。如果该
+   页是一个非THP和非hugetlb页,那么这个计数器会增加1。如果该页面是一个THP或hugetlb
+   页面,那么这个计数器会随着THP或hugetlb子页面的数量而增加。例如,迁移一个有4KB大小
+   的基础页(子页)的2MB THP,将导致这个计数器增加512。
+
+2. PGMIGRATE_FAIL: 正常的页面迁移失败。与上面PGMIGRATE_SUCCESS的计数规则相同:如
+   果是THP或hugetlb,这个计数将被子页的数量增加。
+
+3. THP_MIGRATION_SUCCESS: 一个THP被迁移而没有被分割。
+
+4. THP_MIGRATION_FAIL: 一个THP不能被迁移,也不能被分割。
+
+5. THP_MIGRATION_SPLIT: 一个THP被迁移了,但不是这样的:首先,这个THP必须被分割。
+   在拆分之后,对它的子页面进行了迁移重试。
+
+THP_MIGRATION_* 事件也会更新相应的PGMIGRATE_SUCCESS或PGMIGRATE_FAIL事件。
+例如,一个THP迁移失败将导致THP_MIGRATION_FAIL和PGMIGRATE_FAIL增加。
+
+Christoph Lameter,2006年5月8日。
+
+Minchan Kim,2016年3月28日。
index 9e951fa..7bd740b 100644 (file)
@@ -96,21 +96,82 @@ page owner在默认情况下是禁用的。所以,如果你想使用它,你
    默认情况下, ``page_owner_sort`` 是根据buf的时间来排序的。如果你想
    按buf的页数排序,请使用-m参数。详细的参数是:
 
-   基本函数:
+   基本函数::
 
-       Sort:
+       排序:
                -a              按内存分配时间排序
                -m              按总内存排序
                -p              按pid排序。
                -P              按tgid排序。
+               -n              按任务命令名称排序。
                -r              按内存释放时间排序。
                -s              按堆栈跟踪排序。
                -t              按时间排序(默认)。
-
-   其它函数:
-
-       Cull:
-               -c              通过比较堆栈跟踪而不是总块来进行剔除。
-
-       Filter:
+       --sort <order> 指定排序顺序。排序的语法是[+|-]key[,[+|-]key[,...]]。从
+       **标准格式指定器**那一节选择一个键。"+"是可选的,因为默认的方向是数字或
+       词法的增加。允许混合使用缩写和完整格式的键。
+
+        例子:
+                               ./page_owner_sort <input> <output> --sort=n,+pid,-tgid
+                               ./page_owner_sort <input> <output> --sort=at
+
+    其它函数::
+
+       剔除:
+               --cull <rules>
+                       指定剔除规则。剔除的语法是key[,key[,...]]。从**标准格式指定器**
+                               部分选择一个多字母键。
+               <rules>是一个以逗号分隔的列表形式的单一参数,它提供了一种指定单个剔除规则的
+               方法。 识别的关键字在下面的**标准格式指定器**部分有描述。<规则>可以通过键的
+               序列k1,k2,...来指定,在下面的标准排序键部分有描述。允许混合使用简写和完整形
+               式的键。
+
+               Examples:
+                               ./page_owner_sort <input> <output> --cull=stacktrace
+                               ./page_owner_sort <input> <output> --cull=st,pid,name
+                               ./page_owner_sort <input> <output> --cull=n,f
+
+       过滤:
                -f              过滤掉内存已被释放的块的信息。
+
+       选择:
+               --pid <pidlist>         按pid选择。这将选择进程ID号出现在<pidlist>中的块。
+               --tgid <tgidlist>       按tgid选择。这将选择其线程组ID号出现在<tgidlist>
+                                   中的块。
+               --name <cmdlist>        按任务命令名称选择。这将选择其任务命令名称出现在
+                                   <cmdlist>中的区块。
+
+               <pidlist>, <tgidlist>, <cmdlist>是以逗号分隔的列表形式的单个参数,
+               它提供了一种指定单个选择规则的方法。
+
+
+               例子:
+                               ./page_owner_sort <input> <output> --pid=1
+                               ./page_owner_sort <input> <output> --tgid=1,2,3
+                               ./page_owner_sort <input> <output> --name name1,name2
+
+标准格式指定器
+==============
+::
+
+  --sort的选项:
+
+       短键          长键          描述
+       p               pid             进程ID
+       tg              tgid            线程组ID
+       n               name            任务命令名称
+       st              stacktrace      页面分配的堆栈跟踪
+       T               txt             块的全文
+       ft              free_ts         页面释放时的时间戳
+       at              alloc_ts        页面被分配时的时间戳
+       ator            allocator       页面的内存分配器
+
+  --curl的选项:
+
+       短键          长键          描述
+       p               pid             进程ID
+       tg              tgid            线程组ID
+       n               name            任务命令名称
+       f               free            该页是否已经释放
+       st              stacktrace      页面分配的堆栈跟踪
+       ator            allocator       页面的内存分配器
diff --git a/Documentation/translations/zh_CN/vm/vmalloced-kernel-stacks.rst b/Documentation/translations/zh_CN/vm/vmalloced-kernel-stacks.rst
new file mode 100644 (file)
index 0000000..ad23f27
--- /dev/null
@@ -0,0 +1,133 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/vm/vmalloced-kernel-stacks.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+====================
+支持虚拟映射的内核栈
+====================
+
+:作者: Shuah Khan <skhan@linuxfoundation.org>
+
+.. contents:: :local:
+
+概览
+----
+
+这是介绍 `虚拟映射内核栈功能 <https://lwn.net/Articles/694348/>` 的代码
+和原始补丁系列的信息汇总。
+
+简介
+----
+
+内核堆栈溢出通常难以调试,并使内核容易被(恶意)利用。问题可能在稍后的时间出现,使其难以
+隔离和究其根本原因。
+
+带有保护页的虚拟映射内核堆栈如果溢出,会被立即捕获,而不会放任其导致难以诊断的损
+坏。
+
+HAVE_ARCH_VMAP_STACK和VMAP_STACK配置选项能够支持带有保护页的虚拟映射堆栈。
+当堆栈溢出时,这个特性会引发可靠的异常。溢出后堆栈跟踪的可用性以及对溢出本身的
+响应取决于架构。
+
+.. note::
+        截至本文撰写时, arm64, powerpc, riscv, s390, um, 和 x86 支持VMAP_STACK。
+
+HAVE_ARCH_VMAP_STACK
+--------------------
+
+能够支持虚拟映射内核栈的架构应该启用这个bool配置选项。要求是:
+
+- vmalloc空间必须大到足以容纳许多内核堆栈。这可能排除了许多32位架构。
+- vmalloc空间的堆栈需要可靠地工作。例如,如果vmap页表是按需创建的,当堆栈指向
+  具有未填充页表的虚拟地址时,这种机制需要工作,或者架构代码(switch_to()和
+  switch_mm(),很可能)需要确保堆栈的页表项在可能未填充的堆栈上运行之前已经填
+  充。
+- 如果堆栈溢出到一个保护页,就应该发生一些合理的事情。“合理”的定义是灵活的,但
+  在没有记录任何东西的情况下立即重启是不友好的。
+
+VMAP_STACK
+----------
+
+VMAP_STACK bool配置选项在启用时分配虚拟映射的任务栈。这个选项依赖于
+HAVE_ARCH_VMAP_STACK。
+
+- 如果你想使用带有保护页的虚拟映射的内核堆栈,请启用该选项。这将导致内核栈溢出
+  被立即捕获,而不是难以诊断的损坏。
+
+.. note::
+
+        使用KASAN的这个功能需要架构支持用真实的影子内存来支持虚拟映射,并且
+        必须启用KASAN_VMALLOC。
+
+.. note::
+
+        启用VMAP_STACK时,无法在堆栈分配的数据上运行DMA。
+
+内核配置选项和依赖性不断变化。请参考最新的代码库:
+
+`Kconfig <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/Kconfig>`
+
+分配方法
+--------
+
+当一个新的内核线程被创建时,线程堆栈是由页级分配器分配的虚拟连续的内存页组成。这
+些页面被映射到有PAGE_KERNEL保护的连续的内核虚拟空间。
+
+alloc_thread_stack_node()调用__vmalloc_node_range()来分配带有PAGE_KERNEL
+保护的栈。
+
+- 分配的堆栈被缓存起来,以后会被新的线程重用,所以在分配/释放堆栈给任务时,要手动
+  进行memcg核算。因此,__vmalloc_node_range被调用时没有__GFP_ACCOUNT。
+- vm_struct被缓存起来,以便能够找到在中断上下文中启动的空闲线程。 free_thread_stack()
+  可以在中断上下文中调用。
+- 在arm64上,所有VMAP的堆栈都需要有相同的对齐方式,以确保VMAP的堆栈溢出检测正常
+  工作。架构特定的vmap堆栈分配器照顾到了这个细节。
+- 这并不涉及中断堆栈--参考原始补丁
+
+线程栈分配是由clone()、fork()、vfork()、kernel_thread()通过kernel_clone()
+启动的。留点提示在这,以便搜索代码库,了解线程栈何时以及如何分配。
+
+大量的代码是在:
+`kernel/fork.c <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/kernel/fork.c>`.
+
+task_struct中的stack_vm_area指针可以跟踪虚拟分配的堆栈,一个非空的stack_vm_area
+指针可以表明虚拟映射的内核堆栈已经启用。
+
+::
+
+        struct vm_struct *stack_vm_area;
+
+堆栈溢出处理
+------------
+
+前守护页和后守护页有助于检测堆栈溢出。当堆栈溢出到守护页时,处理程序必须小心不要再
+次溢出堆栈。当处理程序被调用时,很可能只留下很少的堆栈空间。
+
+在x86上,这是通过处理表明内核堆栈溢出的双异常堆栈的缺页异常来实现的。
+
+用守护页测试VMAP分配
+--------------------
+
+我们如何确保VMAP_STACK在分配时确实有前守护页和后守护页的保护?下面的 lkdtm 测试
+可以帮助检测任何回归。
+
+::
+
+        void lkdtm_STACK_GUARD_PAGE_LEADING()
+        void lkdtm_STACK_GUARD_PAGE_TRAILING()
+
+结论
+----
+
+- vmalloced堆栈的percpu缓存似乎比高阶堆栈分配要快一些,至少在缓存命中时是这样。
+- THREAD_INFO_IN_TASK完全摆脱了arch-specific thread_info,并简单地将
+  thread_info(仅包含标志)和'int cpu'嵌入task_struct中。
+- 一旦任务死亡,线程栈就可以被释放(无需等待RCU),然后,如果使用vmapped栈,就
+  可以将整个栈缓存起来,以便在同一cpu上重复使用。
index 29e9c70..45a9b7a 100644 (file)
@@ -1,4 +1,4 @@
-:Original: Documentation/vm/zs_malloc.rst
+:Original: Documentation/vm/zsmalloc.rst
 
 :翻译:
 
index 5578bca..280a883 100644 (file)
@@ -22,8 +22,7 @@
 內核開發社區已經發展出一套用於發布補丁的約定和過程;遵循這些約定和過程將使
 參與其中的每個人的生活更加輕鬆。本文檔試圖描述這些約定的部分細節;更多信息
 也可在以下文檔中找到
-:ref:`Documentation/translations/zh_TW/process/submitting-patches.rst <tw_submittingpatches>`,
-:ref:`Documentation/translations/zh_TW/process/submitting-drivers.rst <tw_submittingdrivers>`
+:ref:`Documentation/translations/zh_TW/process/submitting-patches.rst <tw_submittingpatches>`
 和 :ref:`Documentation/translations/zh_TW/process/submit-checklist.rst <tw_submitchecklist>`。
 
 何時郵寄
index 7572b17..044fcc1 100644 (file)
@@ -22,7 +22,6 @@
 :ref:`Documentation/translations/zh_TW/process/howto.rst <tw_process_howto>`
 文件是一個重要的起點;
 :ref:`Documentation/translations/zh_TW/process/submitting-patches.rst <tw_submittingpatches>`
-和 :ref:`Documentation/translations/zh_TW/process/submitting-drivers.rst <tw_submittingdrivers>`
 也是所有內核開發人員都應該閱讀的內容。許多內部內核API都是使用kerneldoc機制
 記錄的;「make htmldocs」或「make pdfdocs」可用於以HTML或PDF格式生成這些文檔
 (儘管某些發行版提供的tex版本會遇到內部限制,無法正確處理文檔)。
index 2043691..68ae441 100644 (file)
@@ -99,7 +99,6 @@ Linux內核代碼中包含有大量的文檔。這些文檔對於學習如何與
     的代碼。
 
   :ref:`Documentation/translations/zh_TW/process/submitting-patches.rst <tw_submittingpatches>`
-  :ref:`Documentation/process/submitting-drivers.rst <submittingdrivers>`
 
     這兩份文檔明確描述如何創建和發送補丁,其中包括(但不僅限於):
        - 郵件內容
index ec7ad14..c5c59b4 100644 (file)
@@ -43,7 +43,6 @@
 .. toctree::
    :maxdepth: 1
 
-   submitting-drivers
    submit-checklist
    stable-api-nonsense
    stable-kernel-rules
diff --git a/Documentation/translations/zh_TW/process/submitting-drivers.rst b/Documentation/translations/zh_TW/process/submitting-drivers.rst
deleted file mode 100644 (file)
index 2fdd742..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0
-
-.. _tw_submittingdrivers:
-
-.. include:: ../disclaimer-zh_TW.rst
-
-:Original: :ref:`Documentation/process/submitting-drivers.rst
-           <submittingdrivers>`
-
-如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
-交流有困難的話,也可以向中文版維護者求助。如果本翻譯更新不及時或者翻
-譯存在問題,請聯繫中文版維護者::
-
-        中文版維護者: 李陽  Li Yang <leoyang.li@nxp.com>
-        中文版翻譯者: 李陽  Li Yang <leoyang.li@nxp.com>
-        中文版校譯者: 陳琦 Maggie Chen <chenqi@beyondsoft.com>
-                       王聰 Wang Cong <xiyou.wangcong@gmail.com>
-                       張巍 Zhang Wei <wezhang@outlook.com>
-                       胡皓文 Hu Haowen <src.res@email.cn>
-
-如何向 Linux 內核提交驅動程序
-=============================
-
-這篇文檔將會解釋如何向不同的內核源碼樹提交設備驅動程序。請注意,如果你感
-興趣的是顯卡驅動程序,你也許應該訪問 XFree86 項目(https://www.xfree86.org/)
-和/或 X.org 項目 (https://x.org)。
-
-另請參閱 Documentation/translations/zh_TW/process/submitting-patches.rst 文檔。
-
-
-分配設備號
-----------
-
-塊設備和字符設備的主設備號與從設備號是由 Linux 命名編號分配權威 LANANA(
-現在是 Torben Mathiasen)負責分配。申請的網址是 https://www.lanana.org/。
-即使不準備提交到主流內核的設備驅動也需要在這裡分配設備號。有關詳細信息,
-請參閱 Documentation/admin-guide/devices.rst。
-
-如果你使用的不是已經分配的設備號,那麼當你提交設備驅動的時候,它將會被強
-制分配一個新的設備號,即便這個設備號和你之前發給客戶的截然不同。
-
-設備驅動的提交對象
-------------------
-
-Linux 2.0:
-       此內核源碼樹不接受新的驅動程序。
-
-Linux 2.2:
-       此內核源碼樹不接受新的驅動程序。
-
-Linux 2.4:
-       如果所屬的代碼領域在內核的 MAINTAINERS 文件中列有一個總維護者,
-       那麼請將驅動程序提交給他。如果此維護者沒有回應或者你找不到恰當的
-       維護者,那麼請聯繫 Willy Tarreau <w@1wt.eu>。
-
-Linux 2.6:
-       除了遵循和 2.4 版內核同樣的規則外,你還需要在 linux-kernel 郵件
-       列表上跟蹤最新的 API 變化。向 Linux 2.6 內核提交驅動的頂級聯繫人
-       是 Andrew Morton <akpm@linux-foundation.org>。
-
-決定設備驅動能否被接受的條件
-----------------------------
-
-許可:              代碼必須使用 GNU 通用公開許可證 (GPL) 提交給 Linux,但是
-               我們並不要求 GPL 是唯一的許可。你或許會希望同時使用多種
-               許可證發布,如果希望驅動程序可以被其他開源社區(比如BSD)
-               使用。請參考 include/linux/module.h 文件中所列出的可被
-               接受共存的許可。
-
-版權:              版權所有者必須同意使用 GPL 許可。最好提交者和版權所有者
-               是相同個人或實體。否則,必需列出授權使用 GPL 的版權所有
-               人或實體,以備驗證之需。
-
-接口:              如果你的驅動程序使用現成的接口並且和其他同類的驅動程序行
-               爲相似,而不是去發明無謂的新接口,那麼它將會更容易被接受。
-               如果你需要一個 Linux 和 NT 的通用驅動接口,那麼請在用
-               戶空間實現它。
-
-代碼:              請使用 Documentation/process/coding-style.rst 中所描述的 Linux 代碼風
-               格。如果你的某些代碼段(例如那些與 Windows 驅動程序包共
-               享的代碼段)需要使用其他格式,而你卻只希望維護一份代碼,
-               那麼請將它們很好地區分出來,並且註明原因。
-
-可移植性:        請注意,指針並不永遠是 32 位的,不是所有的計算機都使用小
-               尾模式 (little endian) 存儲數據,不是所有的人都擁有浮點
-               單元,不要隨便在你的驅動程序里嵌入 x86 彙編指令。只能在
-               x86 上運行的驅動程序一般是不受歡迎的。雖然你可能只有 x86
-               硬體,很難測試驅動程序在其他平台上是否可用,但是確保代碼
-               可以被輕鬆地移植卻是很簡單的。
-
-清晰度:   做到所有人都能修補這個驅動程序將會很有好處,因爲這樣你將
-               會直接收到修復的補丁而不是 bug 報告。如果你提交一個試圖
-               隱藏硬體工作機理的驅動程序,那麼它將會被扔進廢紙簍。
-
-電源管理:        因爲 Linux 正在被很多行動裝置和桌面系統使用,所以你的驅
-               動程序也很有可能被使用在這些設備上。它應該支持最基本的電
-               源管理,即在需要的情況下實現系統級休眠和喚醒要用到的
-               .suspend 和 .resume 函數。你應該檢查你的驅動程序是否能正
-               確地處理休眠與喚醒,如果實在無法確認,請至少把 .suspend
-               函數定義成返回 -ENOSYS(功能未實現)錯誤。你還應該嘗試確
-               保你的驅動在什麼都不乾的情況下將耗電降到最低。要獲得驅動
-               程序測試的指導,請參閱
-               Documentation/power/drivers-testing.rst。有關驅動程序電
-               源管理問題相對全面的概述,請參閱
-               Documentation/driver-api/pm/devices.rst。
-
-管理:              如果一個驅動程序的作者還在進行有效的維護,那麼通常除了那
-               些明顯正確且不需要任何檢查的補丁以外,其他所有的補丁都會
-               被轉發給作者。如果你希望成爲驅動程序的聯繫人和更新者,最
-               好在代碼注釋中寫明並且在 MAINTAINERS 文件中加入這個驅動
-               程序的條目。
-
-不影響設備驅動能否被接受的條件
-------------------------------
-
-供應商:   由硬體供應商來維護驅動程序通常是一件好事。不過,如果源碼
-               樹里已經有其他人提供了可穩定工作的驅動程序,那麼請不要期
-               望「我是供應商」會成爲內核改用你的驅動程序的理由。理想的情
-               況是:供應商與現有驅動程序的作者合作,構建一個統一完美的
-               驅動程序。
-
-作者:              驅動程序是由大的 Linux 公司研發還是由你個人編寫,並不影
-               響其是否能被內核接受。沒有人對內核源碼樹享有特權。只要你
-               充分了解內核社區,你就會發現這一點。
-
-
-資源列表
---------
-
-Linux 內核主源碼樹:
-       ftp.??.kernel.org:/pub/linux/kernel/...
-       ?? == 你的國家代碼,例如 "cn"、"us"、"uk"、"fr" 等等
-
-Linux 內核郵件列表:
-       linux-kernel@vger.kernel.org
-       [可通過向majordomo@vger.kernel.org發郵件來訂閱]
-
-Linux 設備驅動程序,第三版(探討 2.6.10 版內核):
-       https://lwn.net/Kernel/LDD3/ (免費版)
-
-LWN.net:
-       每周內核開發活動摘要 - https://lwn.net/
-
-       2.6 版中 API 的變更:
-
-               https://lwn.net/Articles/2.6-kernel-api/
-
-       將舊版內核的驅動程序移植到 2.6 版:
-
-               https://lwn.net/Articles/driver-porting/
-
-內核新手(KernelNewbies):
-       爲新的內核開發者提供文檔和幫助
-       https://kernelnewbies.org/
-
-Linux USB項目:
-       http://www.linux-usb.org/
-
-寫內核驅動的「不要」(Arjan van de Ven著):
-       http://www.fenrus.org/how-to-not-write-a-device-driver-paper.pdf
-
-內核清潔工 (Kernel Janitor):
-       https://kernelnewbies.org/KernelJanitors
-
index c4fd48f..3f77ef5 100644 (file)
@@ -26,9 +26,7 @@
 以下文檔含有大量簡潔的建議, 具體請見:
 :ref:`Documentation/process <development_process_main>`
 同樣,:ref:`Documentation/translations/zh_TW/process/submit-checklist.rst <tw_submitchecklist>`
-給出在提交代碼前需要檢查的項目的列表。如果你在提交一個驅動程序,那麼
-同時閱讀一下:
-:ref:`Documentation/process/submitting-drivers.rst <submittingdrivers>`
+給出在提交代碼前需要檢查的項目的列表。
 
 其中許多步驟描述了Git版本控制系統的默認行爲;如果您使用Git來準備補丁,
 您將發現它爲您完成的大部分機械工作,儘管您仍然需要準備和記錄一組合理的
diff --git a/Documentation/virt/hyperv/clocks.rst b/Documentation/virt/hyperv/clocks.rst
new file mode 100644 (file)
index 0000000..2da2879
--- /dev/null
@@ -0,0 +1,73 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Clocks and Timers
+=================
+
+arm64
+-----
+On arm64, Hyper-V virtualizes the ARMv8 architectural system counter
+and timer. Guest VMs use this virtualized hardware as the Linux
+clocksource and clockevents via the standard arm_arch_timer.c
+driver, just as they would on bare metal. Linux vDSO support for the
+architectural system counter is functional in guest VMs on Hyper-V.
+While Hyper-V also provides a synthetic system clock and four synthetic
+per-CPU timers as described in the TLFS, they are not used by the
+Linux kernel in a Hyper-V guest on arm64.  However, older versions
+of Hyper-V for arm64 only partially virtualize the ARMv8
+architectural timer, such that the timer does not generate
+interrupts in the VM. Because of this limitation, running current
+Linux kernel versions on these older Hyper-V versions requires an
+out-of-tree patch to use the Hyper-V synthetic clocks/timers instead.
+
+x86/x64
+-------
+On x86/x64, Hyper-V provides guest VMs with a synthetic system clock
+and four synthetic per-CPU timers as described in the TLFS. Hyper-V
+also provides access to the virtualized TSC via the RDTSC and
+related instructions. These TSC instructions do not trap to
+the hypervisor and so provide excellent performance in a VM.
+Hyper-V performs TSC calibration, and provides the TSC frequency
+to the guest VM via a synthetic MSR.  Hyper-V initialization code
+in Linux reads this MSR to get the frequency, so it skips TSC
+calibration and sets tsc_reliable. Hyper-V provides virtualized
+versions of the PIT (in Hyper-V  Generation 1 VMs only), local
+APIC timer, and RTC. Hyper-V does not provide a virtualized HPET in
+guest VMs.
+
+The Hyper-V synthetic system clock can be read via a synthetic MSR,
+but this access traps to the hypervisor. As a faster alternative,
+the guest can configure a memory page to be shared between the guest
+and the hypervisor.  Hyper-V populates this memory page with a
+64-bit scale value and offset value. To read the synthetic clock
+value, the guest reads the TSC and then applies the scale and offset
+as described in the Hyper-V TLFS. The resulting value advances
+at a constant 10 MHz frequency. In the case of a live migration
+to a host with a different TSC frequency, Hyper-V adjusts the
+scale and offset values in the shared page so that the 10 MHz
+frequency is maintained.
+
+Starting with Windows Server 2022 Hyper-V, Hyper-V uses hardware
+support for TSC frequency scaling to enable live migration of VMs
+across Hyper-V hosts where the TSC frequency may be different.
+When a Linux guest detects that this Hyper-V functionality is
+available, it prefers to use Linux's standard TSC-based clocksource.
+Otherwise, it uses the clocksource for the Hyper-V synthetic system
+clock implemented via the shared page (identified as
+"hyperv_clocksource_tsc_page").
+
+The Hyper-V synthetic system clock is available to user space via
+vDSO, and gettimeofday() and related system calls can execute
+entirely in user space.  The vDSO is implemented by mapping the
+shared page with scale and offset values into user space.  User
+space code performs the same algorithm of reading the TSC and
+appying the scale and offset to get the constant 10 MHz clock.
+
+Linux clockevents are based on Hyper-V synthetic timer 0. While
+Hyper-V offers 4 synthetic timers for each CPU, Linux only uses
+timer 0. Interrupts from stimer0 are recorded on the "HVS" line in
+/proc/interrupts.  Clockevents based on the virtualized PIT and
+local APIC timer also work, but the Hyper-V synthetic timer is
+preferred.
+
+The driver for the Hyper-V synthetic system clock and timers is
+drivers/clocksource/hyperv_timer.c.
diff --git a/Documentation/virt/hyperv/index.rst b/Documentation/virt/hyperv/index.rst
new file mode 100644 (file)
index 0000000..4a7a1b7
--- /dev/null
@@ -0,0 +1,12 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+======================
+Hyper-V Enlightenments
+======================
+
+.. toctree::
+   :maxdepth: 1
+
+   overview
+   vmbus
+   clocks
diff --git a/Documentation/virt/hyperv/overview.rst b/Documentation/virt/hyperv/overview.rst
new file mode 100644 (file)
index 0000000..cd49333
--- /dev/null
@@ -0,0 +1,207 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Overview
+========
+The Linux kernel contains a variety of code for running as a fully
+enlightened guest on Microsoft's Hyper-V hypervisor.  Hyper-V
+consists primarily of a bare-metal hypervisor plus a virtual machine
+management service running in the parent partition (roughly
+equivalent to KVM and QEMU, for example).  Guest VMs run in child
+partitions.  In this documentation, references to Hyper-V usually
+encompass both the hypervisor and the VMM service without making a
+distinction about which functionality is provided by which
+component.
+
+Hyper-V runs on x86/x64 and arm64 architectures, and Linux guests
+are supported on both.  The functionality and behavior of Hyper-V is
+generally the same on both architectures unless noted otherwise.
+
+Linux Guest Communication with Hyper-V
+--------------------------------------
+Linux guests communicate with Hyper-V in four different ways:
+
+* Implicit traps: As defined by the x86/x64 or arm64 architecture,
+  some guest actions trap to Hyper-V.  Hyper-V emulates the action and
+  returns control to the guest.  This behavior is generally invisible
+  to the Linux kernel.
+
+* Explicit hypercalls: Linux makes an explicit function call to
+  Hyper-V, passing parameters.  Hyper-V performs the requested action
+  and returns control to the caller.  Parameters are passed in
+  processor registers or in memory shared between the Linux guest and
+  Hyper-V.   On x86/x64, hypercalls use a Hyper-V specific calling
+  sequence.  On arm64, hypercalls use the ARM standard SMCCC calling
+  sequence.
+
+* Synthetic register access: Hyper-V implements a variety of
+  synthetic registers.  On x86/x64 these registers appear as MSRs in
+  the guest, and the Linux kernel can read or write these MSRs using
+  the normal mechanisms defined by the x86/x64 architecture.  On
+  arm64, these synthetic registers must be accessed using explicit
+  hypercalls.
+
+* VMbus: VMbus is a higher-level software construct that is built on
+  the other 3 mechanisms.  It is a message passing interface between
+  the Hyper-V host and the Linux guest.  It uses memory that is shared
+  between Hyper-V and the guest, along with various signaling
+  mechanisms.
+
+The first three communication mechanisms are documented in the
+`Hyper-V Top Level Functional Spec (TLFS)`_.  The TLFS describes
+general Hyper-V functionality and provides details on the hypercalls
+and synthetic registers.  The TLFS is currently written for the
+x86/x64 architecture only.
+
+.. _Hyper-V Top Level Functional Spec (TLFS): https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/tlfs
+
+VMbus is not documented.  This documentation provides a high-level
+overview of VMbus and how it works, but the details can be discerned
+only from the code.
+
+Sharing Memory
+--------------
+Many aspects are communication between Hyper-V and Linux are based
+on sharing memory.  Such sharing is generally accomplished as
+follows:
+
+* Linux allocates memory from its physical address space using
+  standard Linux mechanisms.
+
+* Linux tells Hyper-V the guest physical address (GPA) of the
+  allocated memory.  Many shared areas are kept to 1 page so that a
+  single GPA is sufficient.   Larger shared areas require a list of
+  GPAs, which usually do not need to be contiguous in the guest
+  physical address space.  How Hyper-V is told about the GPA or list
+  of GPAs varies.  In some cases, a single GPA is written to a
+  synthetic register.  In other cases, a GPA or list of GPAs is sent
+  in a VMbus message.
+
+* Hyper-V translates the GPAs into "real" physical memory addresses,
+  and creates a virtual mapping that it can use to access the memory.
+
+* Linux can later revoke sharing it has previously established by
+  telling Hyper-V to set the shared GPA to zero.
+
+Hyper-V operates with a page size of 4 Kbytes. GPAs communicated to
+Hyper-V may be in the form of page numbers, and always describe a
+range of 4 Kbytes.  Since the Linux guest page size on x86/x64 is
+also 4 Kbytes, the mapping from guest page to Hyper-V page is 1-to-1.
+On arm64, Hyper-V supports guests with 4/16/64 Kbyte pages as
+defined by the arm64 architecture.   If Linux is using 16 or 64
+Kbyte pages, Linux code must be careful to communicate with Hyper-V
+only in terms of 4 Kbyte pages.  HV_HYP_PAGE_SIZE and related macros
+are used in code that communicates with Hyper-V so that it works
+correctly in all configurations.
+
+As described in the TLFS, a few memory pages shared between Hyper-V
+and the Linux guest are "overlay" pages.  With overlay pages, Linux
+uses the usual approach of allocating guest memory and telling
+Hyper-V the GPA of the allocated memory.  But Hyper-V then replaces
+that physical memory page with a page it has allocated, and the
+original physical memory page is no longer accessible in the guest
+VM.  Linux may access the memory normally as if it were the memory
+that it originally allocated.  The "overlay" behavior is visible
+only because the contents of the page (as seen by Linux) change at
+the time that Linux originally establishes the sharing and the
+overlay page is inserted.  Similarly, the contents change if Linux
+revokes the sharing, in which case Hyper-V removes the overlay page,
+and the guest page originally allocated by Linux becomes visible
+again.
+
+Before Linux does a kexec to a kdump kernel or any other kernel,
+memory shared with Hyper-V should be revoked.  Hyper-V could modify
+a shared page or remove an overlay page after the new kernel is
+using the page for a different purpose, corrupting the new kernel.
+Hyper-V does not provide a single "set everything" operation to
+guest VMs, so Linux code must individually revoke all sharing before
+doing kexec.   See hv_kexec_handler() and hv_crash_handler().  But
+the crash/panic path still has holes in cleanup because some shared
+pages are set using per-CPU synthetic registers and there's no
+mechanism to revoke the shared pages for CPUs other than the CPU
+running the panic path.
+
+CPU Management
+--------------
+Hyper-V does not have a ability to hot-add or hot-remove a CPU
+from a running VM.  However, Windows Server 2019 Hyper-V and
+earlier versions may provide guests with ACPI tables that indicate
+more CPUs than are actually present in the VM.  As is normal, Linux
+treats these additional CPUs as potential hot-add CPUs, and reports
+them as such even though Hyper-V will never actually hot-add them.
+Starting in Windows Server 2022 Hyper-V, the ACPI tables reflect
+only the CPUs actually present in the VM, so Linux does not report
+any hot-add CPUs.
+
+A Linux guest CPU may be taken offline using the normal Linux
+mechanisms, provided no VMbus channel interrupts are assigned to
+the CPU.  See the section on VMbus Interrupts for more details
+on how VMbus channel interrupts can be re-assigned to permit
+taking a CPU offline.
+
+32-bit and 64-bit
+-----------------
+On x86/x64, Hyper-V supports 32-bit and 64-bit guests, and Linux
+will build and run in either version. While the 32-bit version is
+expected to work, it is used rarely and may suffer from undetected
+regressions.
+
+On arm64, Hyper-V supports only 64-bit guests.
+
+Endian-ness
+-----------
+All communication between Hyper-V and guest VMs uses Little-Endian
+format on both x86/x64 and arm64.  Big-endian format on arm64 is not
+supported by Hyper-V, and Linux code does not use endian-ness macros
+when accessing data shared with Hyper-V.
+
+Versioning
+----------
+Current Linux kernels operate correctly with older versions of
+Hyper-V back to Windows Server 2012 Hyper-V. Support for running
+on the original Hyper-V release in Windows Server 2008/2008 R2
+has been removed.
+
+A Linux guest on Hyper-V outputs in dmesg the version of Hyper-V
+it is running on.  This version is in the form of a Windows build
+number and is for display purposes only. Linux code does not
+test this version number at runtime to determine available features
+and functionality. Hyper-V indicates feature/function availability
+via flags in synthetic MSRs that Hyper-V provides to the guest,
+and the guest code tests these flags.
+
+VMbus has its own protocol version that is negotiated during the
+initial VMbus connection from the guest to Hyper-V. This version
+number is also output to dmesg during boot.  This version number
+is checked in a few places in the code to determine if specific
+functionality is present.
+
+Furthermore, each synthetic device on VMbus also has a protocol
+version that is separate from the VMbus protocol version. Device
+drivers for these synthetic devices typically negotiate the device
+protocol version, and may test that protocol version to determine
+if specific device functionality is present.
+
+Code Packaging
+--------------
+Hyper-V related code appears in the Linux kernel code tree in three
+main areas:
+
+1. drivers/hv
+
+2. arch/x86/hyperv and arch/arm64/hyperv
+
+3. individual device driver areas such as drivers/scsi, drivers/net,
+   drivers/clocksource, etc.
+
+A few miscellaneous files appear elsewhere. See the full list under
+"Hyper-V/Azure CORE AND DRIVERS" and "DRM DRIVER FOR HYPERV
+SYNTHETIC VIDEO DEVICE" in the MAINTAINERS file.
+
+The code in #1 and #2 is built only when CONFIG_HYPERV is set.
+Similarly, the code for most Hyper-V related drivers is built only
+when CONFIG_HYPERV is set.
+
+Most Hyper-V related code in #1 and #3 can be built as a module.
+The architecture specific code in #2 must be built-in.  Also,
+drivers/hv/hv_common.c is low-level code that is common across
+architectures and must be built-in.
diff --git a/Documentation/virt/hyperv/vmbus.rst b/Documentation/virt/hyperv/vmbus.rst
new file mode 100644 (file)
index 0000000..d2012d9
--- /dev/null
@@ -0,0 +1,303 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+VMbus
+=====
+VMbus is a software construct provided by Hyper-V to guest VMs.  It
+consists of a control path and common facilities used by synthetic
+devices that Hyper-V presents to guest VMs.   The control path is
+used to offer synthetic devices to the guest VM and, in some cases,
+to rescind those devices.   The common facilities include software
+channels for communicating between the device driver in the guest VM
+and the synthetic device implementation that is part of Hyper-V, and
+signaling primitives to allow Hyper-V and the guest to interrupt
+each other.
+
+VMbus is modeled in Linux as a bus, with the expected /sys/bus/vmbus
+entry in a running Linux guest.  The VMbus driver (drivers/hv/vmbus_drv.c)
+establishes the VMbus control path with the Hyper-V host, then
+registers itself as a Linux bus driver.  It implements the standard
+bus functions for adding and removing devices to/from the bus.
+
+Most synthetic devices offered by Hyper-V have a corresponding Linux
+device driver.  These devices include:
+
+* SCSI controller
+* NIC
+* Graphics frame buffer
+* Keyboard
+* Mouse
+* PCI device pass-thru
+* Heartbeat
+* Time Sync
+* Shutdown
+* Memory balloon
+* Key/Value Pair (KVP) exchange with Hyper-V
+* Hyper-V online backup (a.k.a. VSS)
+
+Guest VMs may have multiple instances of the synthetic SCSI
+controller, synthetic NIC, and PCI pass-thru devices.  Other
+synthetic devices are limited to a single instance per VM.  Not
+listed above are a small number of synthetic devices offered by
+Hyper-V that are used only by Windows guests and for which Linux
+does not have a driver.
+
+Hyper-V uses the terms "VSP" and "VSC" in describing synthetic
+devices.  "VSP" refers to the Hyper-V code that implements a
+particular synthetic device, while "VSC" refers to the driver for
+the device in the guest VM.  For example, the Linux driver for the
+synthetic NIC is referred to as "netvsc" and the Linux driver for
+the synthetic SCSI controller is "storvsc".  These drivers contain
+functions with names like "storvsc_connect_to_vsp".
+
+VMbus channels
+--------------
+An instance of a synthetic device uses VMbus channels to communicate
+between the VSP and the VSC.  Channels are bi-directional and used
+for passing messages.   Most synthetic devices use a single channel,
+but the synthetic SCSI controller and synthetic NIC may use multiple
+channels to achieve higher performance and greater parallelism.
+
+Each channel consists of two ring buffers.  These are classic ring
+buffers from a university data structures textbook.  If the read
+and writes pointers are equal, the ring buffer is considered to be
+empty, so a full ring buffer always has at least one byte unused.
+The "in" ring buffer is for messages from the Hyper-V host to the
+guest, and the "out" ring buffer is for messages from the guest to
+the Hyper-V host.  In Linux, the "in" and "out" designations are as
+viewed by the guest side.  The ring buffers are memory that is
+shared between the guest and the host, and they follow the standard
+paradigm where the memory is allocated by the guest, with the list
+of GPAs that make up the ring buffer communicated to the host.  Each
+ring buffer consists of a header page (4 Kbytes) with the read and
+write indices and some control flags, followed by the memory for the
+actual ring.  The size of the ring is determined by the VSC in the
+guest and is specific to each synthetic device.   The list of GPAs
+making up the ring is communicated to the Hyper-V host over the
+VMbus control path as a GPA Descriptor List (GPADL).  See function
+vmbus_establish_gpadl().
+
+Each ring buffer is mapped into contiguous Linux kernel virtual
+space in three parts:  1) the 4 Kbyte header page, 2) the memory
+that makes up the ring itself, and 3) a second mapping of the memory
+that makes up the ring itself.  Because (2) and (3) are contiguous
+in kernel virtual space, the code that copies data to and from the
+ring buffer need not be concerned with ring buffer wrap-around.
+Once a copy operation has completed, the read or write index may
+need to be reset to point back into the first mapping, but the
+actual data copy does not need to be broken into two parts.  This
+approach also allows complex data structures to be easily accessed
+directly in the ring without handling wrap-around.
+
+On arm64 with page sizes > 4 Kbytes, the header page must still be
+passed to Hyper-V as a 4 Kbyte area.  But the memory for the actual
+ring must be aligned to PAGE_SIZE and have a size that is a multiple
+of PAGE_SIZE so that the duplicate mapping trick can be done.  Hence
+a portion of the header page is unused and not communicated to
+Hyper-V.  This case is handled by vmbus_establish_gpadl().
+
+Hyper-V enforces a limit on the aggregate amount of guest memory
+that can be shared with the host via GPADLs.  This limit ensures
+that a rogue guest can't force the consumption of excessive host
+resources.  For Windows Server 2019 and later, this limit is
+approximately 1280 Mbytes.  For versions prior to Windows Server
+2019, the limit is approximately 384 Mbytes.
+
+VMbus messages
+--------------
+All VMbus messages have a standard header that includes the message
+length, the offset of the message payload, some flags, and a
+transactionID.  The portion of the message after the header is
+unique to each VSP/VSC pair.
+
+Messages follow one of two patterns:
+
+* Unidirectional:  Either side sends a message and does not
+  expect a response message
+* Request/response:  One side (usually the guest) sends a message
+  and expects a response
+
+The transactionID (a.k.a. "requestID") is for matching requests &
+responses.  Some synthetic devices allow multiple requests to be in-
+flight simultaneously, so the guest specifies a transactionID when
+sending a request.  Hyper-V sends back the same transactionID in the
+matching response.
+
+Messages passed between the VSP and VSC are control messages.  For
+example, a message sent from the storvsc driver might be "execute
+this SCSI command".   If a message also implies some data transfer
+between the guest and the Hyper-V host, the actual data to be
+transferred may be embedded with the control message, or it may be
+specified as a separate data buffer that the Hyper-V host will
+access as a DMA operation.  The former case is used when the size of
+the data is small and the cost of copying the data to and from the
+ring buffer is minimal.  For example, time sync messages from the
+Hyper-V host to the guest contain the actual time value.  When the
+data is larger, a separate data buffer is used.  In this case, the
+control message contains a list of GPAs that describe the data
+buffer.  For example, the storvsc driver uses this approach to
+specify the data buffers to/from which disk I/O is done.
+
+Three functions exist to send VMbus messages:
+
+1. vmbus_sendpacket():  Control-only messages and messages with
+   embedded data -- no GPAs
+2. vmbus_sendpacket_pagebuffer(): Message with list of GPAs
+   identifying data to transfer.  An offset and length is
+   associated with each GPA so that multiple discontinuous areas
+   of guest memory can be targeted.
+3. vmbus_sendpacket_mpb_desc(): Message with list of GPAs
+   identifying data to transfer.  A single offset and length is
+   associated with a list of GPAs.  The GPAs must describe a
+   single logical area of guest memory to be targeted.
+
+Historically, Linux guests have trusted Hyper-V to send well-formed
+and valid messages, and Linux drivers for synthetic devices did not
+fully validate messages.  With the introduction of processor
+technologies that fully encrypt guest memory and that allow the
+guest to not trust the hypervisor (AMD SNP-SEV, Intel TDX), trusting
+the Hyper-V host is no longer a valid assumption.  The drivers for
+VMbus synthetic devices are being updated to fully validate any
+values read from memory that is shared with Hyper-V, which includes
+messages from VMbus devices.  To facilitate such validation,
+messages read by the guest from the "in" ring buffer are copied to a
+temporary buffer that is not shared with Hyper-V.  Validation is
+performed in this temporary buffer without the risk of Hyper-V
+maliciously modifying the message after it is validated but before
+it is used.
+
+VMbus interrupts
+----------------
+VMbus provides a mechanism for the guest to interrupt the host when
+the guest has queued new messages in a ring buffer.  The host
+expects that the guest will send an interrupt only when an "out"
+ring buffer transitions from empty to non-empty.  If the guest sends
+interrupts at other times, the host deems such interrupts to be
+unnecessary.  If a guest sends an excessive number of unnecessary
+interrupts, the host may throttle that guest by suspending its
+execution for a few seconds to prevent a denial-of-service attack.
+
+Similarly, the host will interrupt the guest when it sends a new
+message on the VMbus control path, or when a VMbus channel "in" ring
+buffer transitions from empty to non-empty.  Each CPU in the guest
+may receive VMbus interrupts, so they are best modeled as per-CPU
+interrupts in Linux.  This model works well on arm64 where a single
+per-CPU IRQ is allocated for VMbus.  Since x86/x64 lacks support for
+per-CPU IRQs, an x86 interrupt vector is statically allocated (see
+HYPERVISOR_CALLBACK_VECTOR) across all CPUs and explicitly coded to
+call the VMbus interrupt service routine.  These interrupts are
+visible in /proc/interrupts on the "HYP" line.
+
+The guest CPU that a VMbus channel will interrupt is selected by the
+guest when the channel is created, and the host is informed of that
+selection.  VMbus devices are broadly grouped into two categories:
+
+1. "Slow" devices that need only one VMbus channel.  The devices
+   (such as keyboard, mouse, heartbeat, and timesync) generate
+   relatively few interrupts.  Their VMbus channels are all
+   assigned to interrupt the VMBUS_CONNECT_CPU, which is always
+   CPU 0.
+
+2. "High speed" devices that may use multiple VMbus channels for
+   higher parallelism and performance.  These devices include the
+   synthetic SCSI controller and synthetic NIC.  Their VMbus
+   channels interrupts are assigned to CPUs that are spread out
+   among the available CPUs in the VM so that interrupts on
+   multiple channels can be processed in parallel.
+
+The assignment of VMbus channel interrupts to CPUs is done in the
+function init_vp_index().  This assignment is done outside of the
+normal Linux interrupt affinity mechanism, so the interrupts are
+neither "unmanaged" nor "managed" interrupts.
+
+The CPU that a VMbus channel will interrupt can be seen in
+/sys/bus/vmbus/devices/<deviceGUID>/ channels/<channelRelID>/cpu.
+When running on later versions of Hyper-V, the CPU can be changed
+by writing a new value to this sysfs entry.  Because the interrupt
+assignment is done outside of the normal Linux affinity mechanism,
+there are no entries in /proc/irq corresponding to individual
+VMbus channel interrupts.
+
+An online CPU in a Linux guest may not be taken offline if it has
+VMbus channel interrupts assigned to it.  Any such channel
+interrupts must first be manually reassigned to another CPU as
+described above.  When no channel interrupts are assigned to the
+CPU, it can be taken offline.
+
+When a guest CPU receives a VMbus interrupt from the host, the
+function vmbus_isr() handles the interrupt.  It first checks for
+channel interrupts by calling vmbus_chan_sched(), which looks at a
+bitmap setup by the host to determine which channels have pending
+interrupts on this CPU.  If multiple channels have pending
+interrupts for this CPU, they are processed sequentially.  When all
+channel interrupts have been processed, vmbus_isr() checks for and
+processes any message received on the VMbus control path.
+
+The VMbus channel interrupt handling code is designed to work
+correctly even if an interrupt is received on a CPU other than the
+CPU assigned to the channel.  Specifically, the code does not use
+CPU-based exclusion for correctness.  In normal operation, Hyper-V
+will interrupt the assigned CPU.  But when the CPU assigned to a
+channel is being changed via sysfs, the guest doesn't know exactly
+when Hyper-V will make the transition.  The code must work correctly
+even if there is a time lag before Hyper-V starts interrupting the
+new CPU.  See comments in target_cpu_store().
+
+VMbus device creation/deletion
+------------------------------
+Hyper-V and the Linux guest have a separate message-passing path
+that is used for synthetic device creation and deletion. This
+path does not use a VMbus channel.  See vmbus_post_msg() and
+vmbus_on_msg_dpc().
+
+The first step is for the guest to connect to the generic
+Hyper-V VMbus mechanism.  As part of establishing this connection,
+the guest and Hyper-V agree on a VMbus protocol version they will
+use.  This negotiation allows newer Linux kernels to run on older
+Hyper-V versions, and vice versa.
+
+The guest then tells Hyper-V to "send offers".  Hyper-V sends an
+offer message to the guest for each synthetic device that the VM
+is configured to have. Each VMbus device type has a fixed GUID
+known as the "class ID", and each VMbus device instance is also
+identified by a GUID. The offer message from Hyper-V contains
+both GUIDs to uniquely (within the VM) identify the device.
+There is one offer message for each device instance, so a VM with
+two synthetic NICs will get two offers messages with the NIC
+class ID. The ordering of offer messages can vary from boot-to-boot
+and must not be assumed to be consistent in Linux code. Offer
+messages may also arrive long after Linux has initially booted
+because Hyper-V supports adding devices, such as synthetic NICs,
+to running VMs. A new offer message is processed by
+vmbus_process_offer(), which indirectly invokes vmbus_add_channel_work().
+
+Upon receipt of an offer message, the guest identifies the device
+type based on the class ID, and invokes the correct driver to set up
+the device.  Driver/device matching is performed using the standard
+Linux mechanism.
+
+The device driver probe function opens the primary VMbus channel to
+the corresponding VSP. It allocates guest memory for the channel
+ring buffers and shares the ring buffer with the Hyper-V host by
+giving the host a list of GPAs for the ring buffer memory.  See
+vmbus_establish_gpadl().
+
+Once the ring buffer is set up, the device driver and VSP exchange
+setup messages via the primary channel.  These messages may include
+negotiating the device protocol version to be used between the Linux
+VSC and the VSP on the Hyper-V host.  The setup messages may also
+include creating additional VMbus channels, which are somewhat
+mis-named as "sub-channels" since they are functionally
+equivalent to the primary channel once they are created.
+
+Finally, the device driver may create entries in /dev as with
+any device driver.
+
+The Hyper-V host can send a "rescind" message to the guest to
+remove a device that was previously offered. Linux drivers must
+handle such a rescind message at any time. Rescinding a device
+invokes the device driver "remove" function to cleanly shut
+down the device and remove it. Once a synthetic device is
+rescinded, neither Hyper-V nor Linux retains any state about
+its previous existence. Such a device might be re-added later,
+in which case it is treated as an entirely new device. See
+vmbus_onoffer_rescind().
index 492f092..2f1cffa 100644 (file)
@@ -14,6 +14,7 @@ Linux Virtualization Support
    ne_overview
    acrn/index
    coco/sev-guest
+   hyperv/index
 
 .. only:: html and subproject
 
index 11e00a4..dca9267 100644 (file)
@@ -4667,7 +4667,7 @@ encrypted VMs.
 
 Currently, this ioctl is used for issuing Secure Encrypted Virtualization
 (SEV) commands on AMD Processors. The SEV commands are defined in
-Documentation/virt/kvm/amd-memory-encryption.rst.
+Documentation/virt/kvm/x86/amd-memory-encryption.rst.
 
 4.111 KVM_MEMORY_ENCRYPT_REG_REGION
 -----------------------------------
@@ -5657,7 +5657,8 @@ by a string of size ``name_size``.
        #define KVM_STATS_UNIT_BYTES            (0x1 << KVM_STATS_UNIT_SHIFT)
        #define KVM_STATS_UNIT_SECONDS          (0x2 << KVM_STATS_UNIT_SHIFT)
        #define KVM_STATS_UNIT_CYCLES           (0x3 << KVM_STATS_UNIT_SHIFT)
-       #define KVM_STATS_UNIT_MAX              KVM_STATS_UNIT_CYCLES
+       #define KVM_STATS_UNIT_BOOLEAN          (0x4 << KVM_STATS_UNIT_SHIFT)
+       #define KVM_STATS_UNIT_MAX              KVM_STATS_UNIT_BOOLEAN
 
        #define KVM_STATS_BASE_SHIFT            8
        #define KVM_STATS_BASE_MASK             (0xF << KVM_STATS_BASE_SHIFT)
@@ -5702,14 +5703,13 @@ Bits 0-3 of ``flags`` encode the type:
     by the ``hist_param`` field. The range of the Nth bucket (1 <= N < ``size``)
     is [``hist_param``*(N-1), ``hist_param``*N), while the range of the last
     bucket is [``hist_param``*(``size``-1), +INF). (+INF means positive infinity
-    value.) The bucket value indicates how many samples fell in the bucket's range.
+    value.)
   * ``KVM_STATS_TYPE_LOG_HIST``
     The statistic is reported as a logarithmic histogram. The number of
     buckets is specified by the ``size`` field. The range of the first bucket is
     [0, 1), while the range of the last bucket is [pow(2, ``size``-2), +INF).
     Otherwise, The Nth bucket (1 < N < ``size``) covers
-    [pow(2, N-2), pow(2, N-1)). The bucket value indicates how many samples fell
-    in the bucket's range.
+    [pow(2, N-2), pow(2, N-1)).
 
 Bits 4-7 of ``flags`` encode the unit:
 
@@ -5724,6 +5724,15 @@ Bits 4-7 of ``flags`` encode the unit:
     It indicates that the statistics data is used to measure time or latency.
   * ``KVM_STATS_UNIT_CYCLES``
     It indicates that the statistics data is used to measure CPU clock cycles.
+  * ``KVM_STATS_UNIT_BOOLEAN``
+    It indicates that the statistic will always be either 0 or 1.  Boolean
+    statistics of "peak" type will never go back from 1 to 0.  Boolean
+    statistics can be linear histograms (with two buckets) but not logarithmic
+    histograms.
+
+Note that, in the case of histograms, the unit applies to the bucket
+ranges, while the bucket value indicates how many samples fell in the
+bucket's range.
 
 Bits 8-11 of ``flags``, together with ``exponent``, encode the scale of the
 unit:
@@ -5746,7 +5755,7 @@ the corresponding statistics data.
 
 The ``bucket_size`` field is used as a parameter for histogram statistics data.
 It is only used by linear histogram statistics data, specifying the size of a
-bucket.
+bucket in the unit expressed by bits 4-11 of ``flags`` together with ``exponent``.
 
 The ``name`` field is the name string of the statistics data. The name string
 starts at the end of ``struct kvm_stats_desc``.  The maximum length including
@@ -7670,7 +7679,7 @@ architecture-specific interfaces.  This capability and the architecture-
 specific interfaces must be consistent, i.e. if one says the feature
 is supported, than the other should as well and vice versa.  For arm64
 see Documentation/virt/kvm/devices/vcpu.rst "KVM_ARM_VCPU_PVTIME_CTRL".
-For x86 see Documentation/virt/kvm/msr.rst "MSR_KVM_STEAL_TIME".
+For x86 see Documentation/virt/kvm/x86/msr.rst "MSR_KVM_STEAL_TIME".
 
 8.25 KVM_CAP_S390_DIAG318
 -------------------------
index 4d43fbc..412b276 100644 (file)
@@ -60,12 +60,13 @@ these functions (see arch/arm{,64}/include/asm/virt.h):
 
 * ::
 
-    x0 = HVC_VHE_RESTART (arm64 only)
+    x0 = HVC_FINALISE_EL2 (arm64 only)
 
-  Attempt to upgrade the kernel's exception level from EL1 to EL2 by enabling
-  the VHE mode. This is conditioned by the CPU supporting VHE, the EL2 MMU
-  being off, and VHE not being disabled by any other means (command line
-  option, for example).
+  Finish configuring EL2 depending on the command-line options,
+  including an attempt to upgrade the kernel's exception level from
+  EL1 to EL2 by enabling the VHE mode. This is conditioned by the CPU
+  supporting VHE, the EL2 MMU being off, and VHE not being disabled by
+  any other means (command line option, for example).
 
 Any other value of r0/x0 triggers a hypervisor-specific handling,
 which is not documented here.
index 73a6083..96c4848 100644 (file)
@@ -10,7 +10,7 @@ The memory of Protected Virtual Machines (PVMs) is not accessible to
 I/O or the hypervisor. In those cases where the hypervisor needs to
 access the memory of a PVM, that memory must be made accessible.
 Memory made accessible to the hypervisor will be encrypted. See
-Documentation/virt/kvm/s390-pv.rst for details."
+Documentation/virt/kvm/s390/s390-pv.rst for details."
 
 On IPL (boot) a small plaintext bootloader is started, which provides
 information about the encrypted components and necessary metadata to
index e56fa8b..10db792 100644 (file)
@@ -22,7 +22,7 @@ S390:
   number in R1.
 
   For further information on the S390 diagnose call as supported by KVM,
-  refer to Documentation/virt/kvm/s390-diag.rst.
+  refer to Documentation/virt/kvm/s390/s390-diag.rst.
 
 PowerPC:
   It uses R3-R10 and hypercall number in R11. R4-R11 are used as output registers.
index 863f67b..af2a974 100644 (file)
@@ -322,7 +322,7 @@ Shared Options
 * ``v6=[0,1]`` to specify if a v6 connection is desired for all
   transports which operate over IP. Additionally, for transports that
   have some differences in the way they operate over v4 and v6 (for example
-  EoL2TPv3), sets the correct mode of operation. In the absense of this
+  EoL2TPv3), sets the correct mode of operation. In the absence of this
   option, the socket type is determined based on what do the src and dst
   arguments resolve/parse to.
 
index c742de1..b9d5253 100644 (file)
@@ -120,7 +120,8 @@ Testing
   unpoison-pfn
        Software-unpoison page at PFN echoed into this file. This way
        a page can be reused again.  This only works for Linux
-       injected failures, not for real memory failures.
+       injected failures, not for real memory failures. Once any hardware
+       memory failure happens, this feature is disabled.
 
   Note these injection interfaces are not stable and might change between
   kernel versions
index 1addb0c..a4895d6 100644 (file)
@@ -1,5 +1,3 @@
-.. _overcommit_accounting:
-
 =====================
 Overcommit Accounting
 =====================
index 9a66a88..cdb2570 100644 (file)
@@ -140,7 +140,7 @@ Unwinder implementation details
 
 Objtool generates the ORC data by integrating with the compile-time
 stack metadata validation feature, which is described in detail in
-tools/objtool/Documentation/stack-validation.txt.  After analyzing all
+tools/objtool/Documentation/objtool.txt.  After analyzing all
 the code paths of a .o file, it creates an array of orc_entry structs,
 and a parallel array of instruction addresses associated with those
 structs, and writes them to the .orc_unwind and .orc_unwind_ip sections
index 0633324..bd82078 100644 (file)
@@ -242,6 +242,11 @@ F: include/trace/events/9p.h
 F:     include/uapi/linux/virtio_9p.h
 F:     net/9p/
 
+A64FX DIAG DRIVER
+M:     Hitomi Hasegawa <hasegawa-hitomi@fujitsu.com>
+S:     Supported
+F:     drivers/soc/fujitsu/a64fx-diag.c
+
 A8293 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
@@ -426,7 +431,6 @@ F:  drivers/acpi/*thermal*
 ACPI VIOT DRIVER
 M:     Jean-Philippe Brucker <jean-philippe@linaro.org>
 L:     linux-acpi@vger.kernel.org
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 S:     Maintained
 F:     drivers/acpi/viot.c
@@ -960,7 +964,6 @@ F:  drivers/video/fbdev/geode/
 AMD IOMMU (AMD-VI)
 M:     Joerg Roedel <joro@8bytes.org>
 R:     Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git
@@ -1040,6 +1043,7 @@ F:        arch/arm64/boot/dts/amd/
 
 AMD XGBE DRIVER
 M:     Tom Lendacky <thomas.lendacky@amd.com>
+M:     "Shyam Sundar S K" <Shyam-sundar.S-k@amd.com>
 L:     netdev@vger.kernel.org
 S:     Supported
 F:     arch/arm64/boot/dts/amd/amd-seattle-xgbe*.dtsi
@@ -1895,6 +1899,7 @@ L:        linux-aspeed@lists.ozlabs.org (moderated for non-subscribers)
 S:     Supported
 Q:     https://patchwork.ozlabs.org/project/linux-aspeed/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/joel/aspeed.git
+F:     Documentation/devicetree/bindings/arm/aspeed/
 F:     arch/arm/boot/dts/aspeed-*
 F:     arch/arm/mach-aspeed/
 N:     aspeed
@@ -2142,11 +2147,13 @@ M:      Jean-Marie Verdun <verdun@hpe.com>
 M:     Nick Hawkins <nick.hawkins@hpe.com>
 S:     Maintained
 F:     Documentation/devicetree/bindings/arm/hpe,gxp.yaml
+F:     Documentation/devicetree/bindings/spi/hpe,gxp-spi.yaml
 F:     Documentation/devicetree/bindings/timer/hpe,gxp-timer.yaml
 F:     arch/arm/boot/dts/hpe-bmc*
 F:     arch/arm/boot/dts/hpe-gxp*
 F:     arch/arm/mach-hpe/
 F:     drivers/clocksource/timer-gxp.c
+F:     drivers/spi/spi-gxp.c
 F:     drivers/watchdog/gxp-wdt.c
 
 ARM/IGEP MACHINE SUPPORT
@@ -2450,9 +2457,11 @@ F:       Documentation/devicetree/bindings/*/*npcm*
 F:     Documentation/devicetree/bindings/arm/npcm/*
 F:     arch/arm/boot/dts/nuvoton-npcm*
 F:     arch/arm/mach-npcm/
+F:     arch/arm64/boot/dts/nuvoton/
 F:     drivers/*/*npcm*
 F:     drivers/*/*/*npcm*
 F:     include/dt-bindings/clock/nuvoton,npcm7xx-clock.h
+F:     include/dt-bindings/clock/nuvoton,npcm845-clk.h
 
 ARM/NUVOTON WPCM450 ARCHITECTURE
 M:     Jonathan Neuschäfer <j.neuschaefer@gmx.net>
@@ -2469,6 +2478,7 @@ ARM/NXP S32G ARCHITECTURE
 M:     Chester Lin <clin@suse.com>
 R:     Andreas Färber <afaerber@suse.de>
 R:     Matthias Brugger <mbrugger@suse.com>
+R:     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*
@@ -2498,10 +2508,8 @@ F:       drivers/power/reset/oxnas-restart.c
 N:     oxnas
 
 ARM/PALM TREO SUPPORT
-M:     Tomas Cech <sleep_walker@suse.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     Maintained
-W:     http://hackndev.com
+S:     Orphan
 F:     arch/arm/mach-pxa/palmtreo.*
 
 ARM/PALMTX,PALMT5,PALMLD,PALMTE2,PALMTC SUPPORT
@@ -2539,6 +2547,7 @@ W:        http://www.armlinux.org.uk/
 ARM/QUALCOMM SUPPORT
 M:     Andy Gross <agross@kernel.org>
 M:     Bjorn Andersson <bjorn.andersson@linaro.org>
+R:     Konrad Dybcio <konrad.dybcio@somainline.org>
 L:     linux-arm-msm@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux.git
@@ -2617,6 +2626,8 @@ Q:        http://patchwork.kernel.org/project/linux-renesas-soc/list/
 C:     irc://irc.libera.chat/renesas-soc
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-devel.git next
 F:     Documentation/devicetree/bindings/arm/renesas.yaml
+F:     Documentation/devicetree/bindings/hwinfo/renesas,prr.yaml
+F:     Documentation/devicetree/bindings/soc/renesas/
 F:     arch/arm64/boot/dts/renesas/
 F:     drivers/soc/renesas/
 F:     include/linux/soc/renesas/
@@ -2735,6 +2746,7 @@ Q:        http://patchwork.kernel.org/project/linux-renesas-soc/list/
 C:     irc://irc.libera.chat/renesas-soc
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-devel.git next
 F:     Documentation/devicetree/bindings/arm/renesas.yaml
+F:     Documentation/devicetree/bindings/soc/renesas/
 F:     arch/arm/boot/dts/emev2*
 F:     arch/arm/boot/dts/gr-peach*
 F:     arch/arm/boot/dts/iwg20d-q7*
@@ -2824,6 +2836,23 @@ F:       drivers/clocksource/armv7m_systick.c
 N:     stm32
 N:     stm
 
+ARM/SUNPLUS SP7021 SOC SUPPORT
+M:     Qin Jian <qinjian@cqplus1.com>
+L:     linux-arm-kernel@lists.infradead.org (moderated for mon-subscribers)
+S:     Maintained
+W:     https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
+F:     Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
+F:     Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
+F:     Documentation/devicetree/bindings/interrupt-controller/sunplus,sp7021-intc.yaml
+F:     Documentation/devicetree/bindings/reset/sunplus,reset.yaml
+F:     arch/arm/boot/dts/sunplus-sp7021*.dts*
+F:     arch/arm/configs/sp7021_*defconfig
+F:     arch/arm/mach-sunplus/
+F:     drivers/irqchip/irq-sp7021-intc.c
+F:     drivers/reset/reset-sunplus.c
+F:     include/dt-bindings/clock/sunplus,sp7021-clkc.h
+F:     include/dt-bindings/reset/sunplus,sp7021-reset.h
+
 ARM/Synaptics SoC support
 M:     Jisheng Zhang <jszhang@kernel.org>
 M:     Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
@@ -3616,16 +3645,18 @@ S:      Maintained
 F:     Documentation/devicetree/bindings/iio/accel/bosch,bma400.yaml
 F:     drivers/iio/accel/bma400*
 
-BPF (Safe dynamic programs and tools)
+BPF [GENERAL] (Safe Dynamic Programs and Tools)
 M:     Alexei Starovoitov <ast@kernel.org>
 M:     Daniel Borkmann <daniel@iogearbox.net>
 M:     Andrii Nakryiko <andrii@kernel.org>
-R:     Martin KaFai Lau <kafai@fb.com>
-R:     Song Liu <songliubraving@fb.com>
+R:     Martin KaFai Lau <martin.lau@linux.dev>
+R:     Song Liu <song@kernel.org>
 R:     Yonghong Song <yhs@fb.com>
 R:     John Fastabend <john.fastabend@gmail.com>
 R:     KP Singh <kpsingh@kernel.org>
-L:     netdev@vger.kernel.org
+R:     Stanislav Fomichev <sdf@google.com>
+R:     Hao Luo <haoluo@google.com>
+R:     Jiri Olsa <jolsa@kernel.org>
 L:     bpf@vger.kernel.org
 S:     Supported
 W:     https://bpf.io/
@@ -3657,12 +3688,9 @@ F:       scripts/pahole-version.sh
 F:     tools/bpf/
 F:     tools/lib/bpf/
 F:     tools/testing/selftests/bpf/
-N:     bpf
-K:     bpf
 
 BPF JIT for ARM
 M:     Shubham Bansal <illusionist.neo@gmail.com>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Odd Fixes
 F:     arch/arm/net/
@@ -3671,7 +3699,6 @@ BPF JIT for ARM64
 M:     Daniel Borkmann <daniel@iogearbox.net>
 M:     Alexei Starovoitov <ast@kernel.org>
 M:     Zi Shen Lim <zlim.lnx@gmail.com>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Supported
 F:     arch/arm64/net/
@@ -3679,14 +3706,12 @@ F:      arch/arm64/net/
 BPF JIT for MIPS (32-BIT AND 64-BIT)
 M:     Johan Almbladh <johan.almbladh@anyfinetworks.com>
 M:     Paul Burton <paulburton@kernel.org>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Maintained
 F:     arch/mips/net/
 
 BPF JIT for NFP NICs
 M:     Jakub Kicinski <kuba@kernel.org>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Odd Fixes
 F:     drivers/net/ethernet/netronome/nfp/bpf/
@@ -3694,7 +3719,6 @@ F:        drivers/net/ethernet/netronome/nfp/bpf/
 BPF JIT for POWERPC (32-BIT AND 64-BIT)
 M:     Naveen N. Rao <naveen.n.rao@linux.ibm.com>
 M:     Michael Ellerman <mpe@ellerman.id.au>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Supported
 F:     arch/powerpc/net/
@@ -3702,7 +3726,6 @@ F:        arch/powerpc/net/
 BPF JIT for RISC-V (32-bit)
 M:     Luke Nelson <luke.r.nels@gmail.com>
 M:     Xi Wang <xi.wang@gmail.com>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Maintained
 F:     arch/riscv/net/
@@ -3710,7 +3733,6 @@ X:        arch/riscv/net/bpf_jit_comp64.c
 
 BPF JIT for RISC-V (64-bit)
 M:     Björn Töpel <bjorn@kernel.org>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Maintained
 F:     arch/riscv/net/
@@ -3720,7 +3742,6 @@ BPF JIT for S390
 M:     Ilya Leoshkevich <iii@linux.ibm.com>
 M:     Heiko Carstens <hca@linux.ibm.com>
 M:     Vasily Gorbik <gor@linux.ibm.com>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Supported
 F:     arch/s390/net/
@@ -3728,14 +3749,12 @@ X:      arch/s390/net/pnet.c
 
 BPF JIT for SPARC (32-BIT AND 64-BIT)
 M:     David S. Miller <davem@davemloft.net>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Odd Fixes
 F:     arch/sparc/net/
 
 BPF JIT for X86 32-BIT
 M:     Wang YanQing <udknight@gmail.com>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Odd Fixes
 F:     arch/x86/net/bpf_jit_comp32.c
@@ -3743,13 +3762,60 @@ F:      arch/x86/net/bpf_jit_comp32.c
 BPF JIT for X86 64-BIT
 M:     Alexei Starovoitov <ast@kernel.org>
 M:     Daniel Borkmann <daniel@iogearbox.net>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Supported
 F:     arch/x86/net/
 X:     arch/x86/net/bpf_jit_comp32.c
 
-BPF LSM (Security Audit and Enforcement using BPF)
+BPF [CORE]
+M:     Alexei Starovoitov <ast@kernel.org>
+M:     Daniel Borkmann <daniel@iogearbox.net>
+R:     John Fastabend <john.fastabend@gmail.com>
+L:     bpf@vger.kernel.org
+S:     Maintained
+F:     kernel/bpf/verifier.c
+F:     kernel/bpf/tnum.c
+F:     kernel/bpf/core.c
+F:     kernel/bpf/syscall.c
+F:     kernel/bpf/dispatcher.c
+F:     kernel/bpf/trampoline.c
+F:     include/linux/bpf*
+F:     include/linux/filter.h
+
+BPF [BTF]
+M:     Martin KaFai Lau <martin.lau@linux.dev>
+L:     bpf@vger.kernel.org
+S:     Maintained
+F:     kernel/bpf/btf.c
+F:     include/linux/btf*
+
+BPF [TRACING]
+M:     Song Liu <song@kernel.org>
+R:     Jiri Olsa <jolsa@kernel.org>
+L:     bpf@vger.kernel.org
+S:     Maintained
+F:     kernel/trace/bpf_trace.c
+F:     kernel/bpf/stackmap.c
+
+BPF [NETWORKING] (tc BPF, sock_addr)
+M:     Martin KaFai Lau <martin.lau@linux.dev>
+M:     Daniel Borkmann <daniel@iogearbox.net>
+R:     John Fastabend <john.fastabend@gmail.com>
+L:     bpf@vger.kernel.org
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     net/core/filter.c
+F:     net/sched/act_bpf.c
+F:     net/sched/cls_bpf.c
+
+BPF [NETWORKING] (struct_ops, reuseport)
+M:     Martin KaFai Lau <martin.lau@linux.dev>
+L:     bpf@vger.kernel.org
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     kernel/bpf/bpf_struct*
+
+BPF [SECURITY & LSM] (Security Audit and Enforcement using BPF)
 M:     KP Singh <kpsingh@kernel.org>
 R:     Florent Revest <revest@chromium.org>
 R:     Brendan Jackman <jackmanb@chromium.org>
@@ -3760,7 +3826,27 @@ F:       include/linux/bpf_lsm.h
 F:     kernel/bpf/bpf_lsm.c
 F:     security/bpf/
 
-BPF L7 FRAMEWORK
+BPF [STORAGE & CGROUPS]
+M:     Martin KaFai Lau <martin.lau@linux.dev>
+L:     bpf@vger.kernel.org
+S:     Maintained
+F:     kernel/bpf/cgroup.c
+F:     kernel/bpf/*storage.c
+F:     kernel/bpf/bpf_lru*
+
+BPF [RINGBUF]
+M:     Andrii Nakryiko <andrii@kernel.org>
+L:     bpf@vger.kernel.org
+S:     Maintained
+F:     kernel/bpf/ringbuf.c
+
+BPF [ITERATOR]
+M:     Yonghong Song <yhs@fb.com>
+L:     bpf@vger.kernel.org
+S:     Maintained
+F:     kernel/bpf/*iter.c
+
+BPF [L7 FRAMEWORK] (sockmap)
 M:     John Fastabend <john.fastabend@gmail.com>
 M:     Jakub Sitnicki <jakub@cloudflare.com>
 L:     netdev@vger.kernel.org
@@ -3773,13 +3859,31 @@ F:      net/ipv4/tcp_bpf.c
 F:     net/ipv4/udp_bpf.c
 F:     net/unix/unix_bpf.c
 
-BPFTOOL
+BPF [LIBRARY] (libbpf)
+M:     Andrii Nakryiko <andrii@kernel.org>
+L:     bpf@vger.kernel.org
+S:     Maintained
+F:     tools/lib/bpf/
+
+BPF [TOOLING] (bpftool)
 M:     Quentin Monnet <quentin@isovalent.com>
 L:     bpf@vger.kernel.org
 S:     Maintained
 F:     kernel/bpf/disasm.*
 F:     tools/bpf/bpftool/
 
+BPF [SELFTESTS] (Test Runners & Infrastructure)
+M:     Andrii Nakryiko <andrii@kernel.org>
+R:     Mykola Lysenko <mykolal@fb.com>
+L:     bpf@vger.kernel.org
+S:     Maintained
+F:     tools/testing/selftests/bpf/
+
+BPF [MISC]
+L:     bpf@vger.kernel.org
+S:     Odd Fixes
+K:     (?:\b|_)bpf(?:\b|_)
+
 BROADCOM B44 10/100 ETHERNET DRIVER
 M:     Michael Chan <michael.chan@broadcom.com>
 L:     netdev@vger.kernel.org
@@ -3801,23 +3905,36 @@ BROADCOM BCMBCA ARM ARCHITECTURE
 M:     William Zhang <william.zhang@broadcom.com>
 M:     Anand Gore <anand.gore@broadcom.com>
 M:     Kursad Oney <kursad.oney@broadcom.com>
+M:     Florian Fainelli <f.fainelli@gmail.com>
 R:     Broadcom internal kernel review list <bcm-kernel-feedback-list@broadcom.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 T:     git git://github.com/broadcom/stblinux.git
 F:     Documentation/devicetree/bindings/arm/bcm/brcm,bcmbca.yaml
-F:     arch/arm/boot/dts/bcm47622.dtsi
-F:     arch/arm/boot/dts/bcm947622.dts
+F:     arch/arm64/boot/dts/broadcom/bcmbca/*
 N:     bcmbca
 N:     bcm[9]?47622
+N:     bcm[9]?4912
+N:     bcm[9]?63138
+N:     bcm[9]?63146
+N:     bcm[9]?63148
+N:     bcm[9]?63158
+N:     bcm[9]?63178
+N:     bcm[9]?6756
+N:     bcm[9]?6813
+N:     bcm[9]?6846
+N:     bcm[9]?6855
+N:     bcm[9]?6856
+N:     bcm[9]?6858
+N:     bcm[9]?6878
 
 BROADCOM BCM2711/BCM2835 ARM ARCHITECTURE
-M:     Nicolas Saenz Julienne <nsaenz@kernel.org>
+M:     Florian Fainelli <f.fainelli@gmail.com>
 R:     Broadcom internal kernel review list <bcm-kernel-feedback-list@broadcom.com>
 L:     linux-rpi-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/nsaenz/linux-rpi.git
+T:     git git://github.com/broadcom/stblinux.git
 F:     Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
 F:     drivers/pci/controller/pcie-brcmstb.c
 F:     drivers/staging/vc04_services
@@ -3885,14 +4002,6 @@ S:       Maintained
 F:     arch/arm/boot/dts/bcm47189*
 F:     arch/arm/boot/dts/bcm53573*
 
-BROADCOM BCM63XX ARM ARCHITECTURE
-M:     Florian Fainelli <f.fainelli@gmail.com>
-R:     Broadcom internal kernel review list <bcm-kernel-feedback-list@broadcom.com>
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     Maintained
-T:     git git://github.com/broadcom/stblinux.git
-N:     bcm63xx
-
 BROADCOM BCM63XX/BCM33XX UDC DRIVER
 M:     Kevin Cernekee <cernekee@gmail.com>
 L:     linux-usb@vger.kernel.org
@@ -4299,7 +4408,7 @@ L:        linux-pm@vger.kernel.org
 L:     linux-samsung-soc@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
-F:     Documentation/devicetree/bindings/devfreq/exynos-bus.txt
+F:     Documentation/devicetree/bindings/interconnect/samsung,exynos-bus.yaml
 F:     drivers/devfreq/exynos-bus.c
 
 BUSLOGIC SCSI DRIVER
@@ -4889,7 +4998,7 @@ R:        Nick Desaulniers <ndesaulniers@google.com>
 L:     llvm@lists.linux.dev
 S:     Supported
 B:     https://github.com/ClangBuiltLinux/linux/issues
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/clang/features
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/hardening
 F:     include/linux/cfi.h
 F:     kernel/cfi.c
 
@@ -4975,6 +5084,7 @@ Q:        http://patchwork.kernel.org/project/linux-clk/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git
 F:     Documentation/devicetree/bindings/clock/
 F:     drivers/clk/
+F:     include/dt-bindings/clock/
 F:     include/linux/clk-pr*
 F:     include/linux/clk/
 F:     include/linux/of_clk.h
@@ -5025,7 +5135,7 @@ COMPUTE EXPRESS LINK (CXL)
 M:     Alison Schofield <alison.schofield@intel.com>
 M:     Vishal Verma <vishal.l.verma@intel.com>
 M:     Ira Weiny <ira.weiny@intel.com>
-M:     Ben Widawsky <ben.widawsky@intel.com>
+M:     Ben Widawsky <bwidawsk@kernel.org>
 M:     Dan Williams <dan.j.williams@intel.com>
 L:     linux-cxl@vger.kernel.org
 S:     Maintained
@@ -5055,6 +5165,7 @@ F:        include/linux/console*
 
 CONTEXT TRACKING
 M:     Frederic Weisbecker <frederic@kernel.org>
+M:     "Paul E. McKenney" <paulmck@kernel.org>
 S:     Maintained
 F:     kernel/context_tracking.c
 F:     include/linux/context_tracking*
@@ -5780,6 +5891,7 @@ L:        linux-pm@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
 F:     Documentation/devicetree/bindings/devfreq/
+F:     Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
 F:     drivers/devfreq/
 F:     include/linux/devfreq.h
 F:     include/trace/events/devfreq.h
@@ -5977,7 +6089,6 @@ DMA MAPPING HELPERS
 M:     Christoph Hellwig <hch@lst.de>
 M:     Marek Szyprowski <m.szyprowski@samsung.com>
 R:     Robin Murphy <robin.murphy@arm.com>
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 S:     Supported
 W:     http://git.infradead.org/users/hch/dma-mapping.git
@@ -5990,7 +6101,6 @@ F:        kernel/dma/
 
 DMA MAPPING BENCHMARK
 M:     Xiang Chen <chenxiang66@hisilicon.com>
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 F:     kernel/dma/map_benchmark.c
 F:     tools/testing/selftests/dma/
@@ -6732,7 +6842,7 @@ L:        dri-devel@lists.freedesktop.org
 L:     linux-tegra@vger.kernel.org
 S:     Supported
 T:     git git://anongit.freedesktop.org/tegra/linux.git
-F:     Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt
+F:     Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.yaml
 F:     Documentation/devicetree/bindings/gpu/host1x/
 F:     drivers/gpu/drm/tegra/
 F:     drivers/gpu/host1x/
@@ -7412,6 +7522,8 @@ F:        include/video/s1d13xxxfb.h
 EROFS FILE SYSTEM
 M:     Gao Xiang <xiang@kernel.org>
 M:     Chao Yu <chao@kernel.org>
+R:     Yue Hu <huyue2@coolpad.com>
+R:     Jeffle Xu <jefflexu@linux.alibaba.com>
 L:     linux-erofs@lists.ozlabs.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git
@@ -7575,7 +7687,6 @@ F:        drivers/gpu/drm/exynos/exynos_dp*
 
 EXYNOS SYSMMU (IOMMU) driver
 M:     Marek Szyprowski <m.szyprowski@samsung.com>
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 S:     Maintained
 F:     drivers/iommu/exynos-iommu.c
@@ -7701,9 +7812,6 @@ F:        include/linux/fs.h
 F:     include/linux/fs_types.h
 F:     include/uapi/linux/fs.h
 F:     include/uapi/linux/openat2.h
-X:     fs/io-wq.c
-X:     fs/io-wq.h
-X:     fs/io_uring.c
 
 FINTEK F75375S HARDWARE MONITOR AND FAN CONTROLLER DRIVER
 M:     Riku Voipio <riku.voipio@iki.fi>
@@ -7802,6 +7910,7 @@ FORTIFY_SOURCE
 M:     Kees Cook <keescook@chromium.org>
 L:     linux-hardening@vger.kernel.org
 S:     Supported
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/hardening
 F:     include/linux/fortify-string.h
 F:     lib/test_fortify/*
 F:     scripts/test_fortify.sh
@@ -8244,6 +8353,7 @@ GCC PLUGINS
 M:     Kees Cook <keescook@chromium.org>
 L:     linux-hardening@vger.kernel.org
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/hardening
 F:     Documentation/kbuild/gcc-plugins.rst
 F:     scripts/Makefile.gcc-plugins
 F:     scripts/gcc-plugins/
@@ -8964,16 +9074,31 @@ F:      Documentation/admin-guide/perf/hisi-pcie-pmu.rst
 F:     Documentation/admin-guide/perf/hisi-pmu.rst
 F:     drivers/perf/hisilicon
 
-HISILICON QM AND ZIP Controller DRIVER
+HISILICON HNS3 PMU DRIVER
+M:     Guangbin Huang <huangguangbin2@huawei.com>
+S:     Supported
+F:     Documentation/admin-guide/perf/hns3-pmu.rst
+F:     drivers/perf/hisilicon/hns3_pmu.c
+
+HISILICON QM DRIVER
+M:     Weili Qian <qianweili@huawei.com>
 M:     Zhou Wang <wangzhou1@hisilicon.com>
 L:     linux-crypto@vger.kernel.org
 S:     Maintained
-F:     Documentation/ABI/testing/debugfs-hisi-zip
+F:     drivers/crypto/hisilicon/Kconfig
+F:     drivers/crypto/hisilicon/Makefile
 F:     drivers/crypto/hisilicon/qm.c
 F:     drivers/crypto/hisilicon/sgl.c
-F:     drivers/crypto/hisilicon/zip/
 F:     include/linux/hisi_acc_qm.h
 
+HISILICON ZIP Controller DRIVER
+M:     Yang Shen <shenyang39@huawei.com>
+M:     Zhou Wang <wangzhou1@hisilicon.com>
+L:     linux-crypto@vger.kernel.org
+S:     Maintained
+F:     Documentation/ABI/testing/debugfs-hisi-zip
+F:     drivers/crypto/hisilicon/zip/
+
 HISILICON ROCE DRIVER
 M:     Wenpeng Liang <liangwenpeng@huawei.com>
 M:     Weihang Li <liweihang@huawei.com>
@@ -9152,6 +9277,7 @@ F:        drivers/media/platform/st/sti/hva
 
 HWPOISON MEMORY FAILURE HANDLING
 M:     Naoya Horiguchi <naoya.horiguchi@nec.com>
+R:     Miaohe Lin <linmiaohe@huawei.com>
 L:     linux-mm@kvack.org
 S:     Maintained
 F:     mm/hwpoison-inject.c
@@ -9200,6 +9326,7 @@ S:        Supported
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux.git
 F:     Documentation/ABI/stable/sysfs-bus-vmbus
 F:     Documentation/ABI/testing/debugfs-hyperv
+F:     Documentation/virt/hyperv
 F:     Documentation/networking/device_drivers/ethernet/microsoft/netvsc.rst
 F:     arch/arm64/hyperv
 F:     arch/arm64/include/asm/hyperv-tlfs.h
@@ -9545,6 +9672,7 @@ F:        drivers/input/misc/ideapad_slidebar.c
 
 IDMAPPED MOUNTS
 M:     Christian Brauner <brauner@kernel.org>
+M:     Seth Forshee <sforshee@kernel.org>
 L:     linux-fsdevel@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux.git
@@ -9833,7 +9961,10 @@ INTEL ASoC DRIVERS
 M:     Cezary Rojewski <cezary.rojewski@intel.com>
 M:     Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
 M:     Liam Girdwood <liam.r.girdwood@linux.intel.com>
-M:     Jie Yang <yang.jie@linux.intel.com>
+M:     Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
+M:     Bard Liao <yung-chuan.liao@linux.intel.com>
+M:     Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
+M:     Kai Vehmanen <kai.vehmanen@linux.intel.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Supported
 F:     sound/soc/intel/
@@ -9996,7 +10127,6 @@ F:       drivers/hid/intel-ish-hid/
 INTEL IOMMU (VT-d)
 M:     David Woodhouse <dwmw2@infradead.org>
 M:     Lu Baolu <baolu.lu@linux.intel.com>
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 S:     Supported
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git
@@ -10376,7 +10506,6 @@ F:      include/linux/iomap.h
 IOMMU DRIVERS
 M:     Joerg Roedel <joro@8bytes.org>
 M:     Will Deacon <will@kernel.org>
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git
@@ -10402,9 +10531,7 @@ L:      io-uring@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.dk/linux-block
 T:     git git://git.kernel.dk/liburing
-F:     fs/io-wq.c
-F:     fs/io-wq.h
-F:     fs/io_uring.c
+F:     io_uring/
 F:     include/linux/io_uring.h
 F:     include/uapi/linux/io_uring.h
 F:     tools/io_uring/
@@ -10764,6 +10891,17 @@ F:     scripts/mk*
 F:     scripts/mod/
 F:     scripts/package/
 
+KERNEL HARDENING (not covered by other areas)
+M:     Kees Cook <keescook@chromium.org>
+L:     linux-hardening@vger.kernel.org
+S:     Supported
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/hardening
+F:     include/linux/overflow.h
+F:     include/linux/randomize_kstack.h
+F:     mm/usercopy.c
+K:     \b(add|choose)_random_kstack_offset\b
+K:     \b__check_(object_size|heap_object)\b
+
 KERNEL JANITORS
 L:     kernel-janitors@vger.kernel.org
 S:     Odd Fixes
@@ -11574,7 +11712,7 @@ F:      drivers/media/usb/dvb-usb-v2/lmedm04*
 LOADPIN SECURITY MODULE
 M:     Kees Cook <keescook@chromium.org>
 S:     Supported
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git lsm/loadpin
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/hardening
 F:     Documentation/admin-guide/LSM/LoadPin.rst
 F:     security/loadpin/
 
@@ -11623,6 +11761,7 @@ F:      drivers/gpu/drm/bridge/lontium-lt8912b.c
 LOONGARCH
 M:     Huacai Chen <chenhuacai@kernel.org>
 R:     WANG Xuerui <kernel@xen0n.name>
+L:     loongarch@lists.linux.dev
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson.git
 F:     arch/loongarch/
@@ -12535,7 +12674,6 @@ F:      drivers/i2c/busses/i2c-mt65xx.c
 
 MEDIATEK IOMMU DRIVER
 M:     Yong Wu <yong.wu@mediatek.com>
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 L:     linux-mediatek@lists.infradead.org (moderated for non-subscribers)
 S:     Supported
@@ -12879,9 +13017,8 @@ M:      Andrew Morton <akpm@linux-foundation.org>
 L:     linux-mm@kvack.org
 S:     Maintained
 W:     http://www.linux-mm.org
-T:     quilt https://ozlabs.org/~akpm/mmotm/
-T:     quilt https://ozlabs.org/~akpm/mmots/
-T:     git git://github.com/hnaz/linux-mm.git
+T:     git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
+T:     quilt git://git.kernel.org/pub/scm/linux/kernel/git/akpm/25-new
 F:     include/linux/gfp.h
 F:     include/linux/memory_hotplug.h
 F:     include/linux/mm.h
@@ -12891,6 +13028,18 @@ F:     include/linux/vmalloc.h
 F:     mm/
 F:     tools/testing/selftests/vm/
 
+MEMORY HOT(UN)PLUG
+M:     David Hildenbrand <david@redhat.com>
+M:     Oscar Salvador <osalvador@suse.de>
+L:     linux-mm@kvack.org
+S:     Maintained
+F:     Documentation/admin-guide/mm/memory-hotplug.rst
+F:     Documentation/core-api/memory-hotplug.rst
+F:     drivers/base/memory.c
+F:     include/linux/memory_hotplug.h
+F:     mm/memory_hotplug.c
+F:     tools/testing/selftests/memory-hotplug/
+
 MEMORY TECHNOLOGY DEVICES (MTD)
 M:     Miquel Raynal <miquel.raynal@bootlin.com>
 M:     Richard Weinberger <richard@nod.at>
@@ -14277,7 +14426,8 @@ S:      Maintained
 F:     drivers/net/phy/nxp-c45-tja11xx.c
 
 NXP FSPI DRIVER
-M:     Ashish Kumar <ashish.kumar@nxp.com>
+M:     Han Xu <han.xu@nxp.com>
+M:     Haibo Chen <haibo.chen@nxp.com>
 R:     Yogesh Gaur <yogeshgaur.83@gmail.com>
 L:     linux-spi@vger.kernel.org
 S:     Maintained
@@ -14295,7 +14445,7 @@ F:      drivers/iio/gyro/fxas21002c_i2c.c
 F:     drivers/iio/gyro/fxas21002c_spi.c
 
 NXP i.MX CLOCK DRIVERS
-M:     Abel Vesa <abel.vesa@nxp.com>
+M:     Abel Vesa <abelvesa@kernel.org>
 L:     linux-clk@vger.kernel.org
 L:     linux-imx@nxp.com
 S:     Maintained
@@ -14383,9 +14533,8 @@ F:      Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml
 F:     sound/soc/codecs/tfa989x.c
 
 NXP-NCI NFC DRIVER
-R:     Charles Gorand <charles.gorand@effinnov.com>
 L:     linux-nfc@lists.01.org (subscribers-only)
-S:     Supported
+S:     Orphan
 F:     Documentation/devicetree/bindings/net/nfc/nxp,nci.yaml
 F:     drivers/nfc/nxp-nci
 
@@ -15764,7 +15913,7 @@ PIN CONTROLLER - FREESCALE
 M:     Dong Aisheng <aisheng.dong@nxp.com>
 M:     Fabio Estevam <festevam@gmail.com>
 M:     Shawn Guo <shawnguo@kernel.org>
-M:     Stefan Agner <stefan@agner.ch>
+M:     Jacky Bai <ping.bai@nxp.com>
 R:     Pengutronix Kernel Team <kernel@pengutronix.de>
 L:     linux-gpio@vger.kernel.org
 S:     Maintained
@@ -15774,7 +15923,7 @@ F:      drivers/pinctrl/freescale/
 PIN CONTROLLER - INTEL
 M:     Mika Westerberg <mika.westerberg@linux.intel.com>
 M:     Andy Shevchenko <andy@kernel.org>
-S:     Maintained
+S:     Supported
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/intel.git
 F:     drivers/pinctrl/intel/
 
@@ -16240,7 +16389,6 @@ F:      drivers/media/rc/pwm-ir-tx.c
 PWM SUBSYSTEM
 M:     Thierry Reding <thierry.reding@gmail.com>
 R:     Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
-M:     Lee Jones <lee.jones@linaro.org>
 L:     linux-pwm@vger.kernel.org
 S:     Maintained
 Q:     https://patchwork.ozlabs.org/project/linux-pwm/list/
@@ -16251,6 +16399,7 @@ F:      Documentation/driver-api/pwm.rst
 F:     drivers/gpio/gpio-mvebu.c
 F:     drivers/pwm/
 F:     drivers/video/backlight/pwm_bl.c
+F:     include/dt-bindings/pwm/
 F:     include/linux/pwm.h
 F:     include/linux/pwm_backlight.h
 K:     pwm_(config|apply_state|ops)
@@ -16296,7 +16445,7 @@ F:      drivers/crypto/qat/
 
 QCOM AUDIO (ASoC) DRIVERS
 M:     Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
-M:     Banajit Goswami <bgoswami@codeaurora.org>
+M:     Banajit Goswami <bgoswami@quicinc.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Supported
 F:     sound/soc/codecs/lpass-va-macro.c
@@ -16523,7 +16672,7 @@ F:      Documentation/devicetree/bindings/opp/opp-v2-kryo-cpu.yaml
 F:     drivers/cpufreq/qcom-cpufreq-nvmem.c
 
 QUALCOMM CRYPTO DRIVERS
-M:     Thara Gopinath <thara.gopinath@linaro.org>
+M:     Thara Gopinath <thara.gopinath@gmail.com>
 L:     linux-crypto@vger.kernel.org
 L:     linux-arm-msm@vger.kernel.org
 S:     Maintained
@@ -16575,9 +16724,15 @@ S:     Maintained
 F:     Documentation/devicetree/bindings/i2c/i2c-qcom-cci.txt
 F:     drivers/i2c/busses/i2c-qcom-cci.c
 
+QUALCOMM INTERCONNECT BWMON DRIVER
+M:     Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+L:     linux-arm-msm@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml
+F:     drivers/soc/qcom/icc-bwmon.c
+
 QUALCOMM IOMMU
 M:     Rob Clark <robdclark@gmail.com>
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 L:     linux-arm-msm@vger.kernel.org
 S:     Maintained
@@ -16634,7 +16789,7 @@ F:      include/linux/if_rmnet.h
 
 QUALCOMM TSENS THERMAL DRIVER
 M:     Amit Kucheria <amitk@kernel.org>
-M:     Thara Gopinath <thara.gopinath@linaro.org>
+M:     Thara Gopinath <thara.gopinath@gmail.com>
 L:     linux-pm@vger.kernel.org
 L:     linux-arm-msm@vger.kernel.org
 S:     Maintained
@@ -17189,13 +17344,17 @@ N:    riscv
 K:     riscv
 
 RISC-V/MICROCHIP POLARFIRE SOC SUPPORT
-M:     Lewis Hanly <lewis.hanly@microchip.com>
 M:     Conor Dooley <conor.dooley@microchip.com>
+M:     Daire McNamara <daire.mcnamara@microchip.com>
 L:     linux-riscv@lists.infradead.org
 S:     Supported
 F:     arch/riscv/boot/dts/microchip/
+F:     drivers/char/hw_random/mpfs-rng.c
+F:     drivers/clk/microchip/clk-mpfs.c
 F:     drivers/mailbox/mailbox-mpfs.c
+F:     drivers/pci/controller/pcie-microchip-host.c
 F:     drivers/soc/microchip/
+F:     drivers/spi/spi-microchip-core.c
 F:     include/soc/microchip/mpfs.h
 
 RNBD BLOCK DRIVERS
@@ -17891,7 +18050,7 @@ M:      Kees Cook <keescook@chromium.org>
 R:     Andy Lutomirski <luto@amacapital.net>
 R:     Will Drewry <wad@chromium.org>
 S:     Supported
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git seccomp
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/seccomp
 F:     Documentation/userspace-api/seccomp_filter.rst
 F:     include/linux/seccomp.h
 F:     include/uapi/linux/seccomp.h
@@ -17962,12 +18121,13 @@ S:    Supported
 F:     Documentation/admin-guide/security-bugs.rst
 
 SECURITY SUBSYSTEM
+M:     Paul Moore <paul@paul-moore.com>
 M:     James Morris <jmorris@namei.org>
 M:     "Serge E. Hallyn" <serge@hallyn.com>
 L:     linux-security-module@vger.kernel.org (suggested Cc:)
 S:     Supported
 W:     http://kernsec.org/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm.git
 F:     security/
 X:     security/selinux/
 
@@ -18091,6 +18251,7 @@ F:      drivers/misc/sgi-xp/
 
 SHARED MEMORY COMMUNICATIONS (SMC) SOCKETS
 M:     Karsten Graul <kgraul@linux.ibm.com>
+M:     Wenjia Zhang <wenjia@linux.ibm.com>
 L:     linux-s390@vger.kernel.org
 S:     Supported
 W:     http://www.ibm.com/developerworks/linux/linux390/
@@ -18723,8 +18884,10 @@ F:     sound/soc/
 SOUND - SOUND OPEN FIRMWARE (SOF) DRIVERS
 M:     Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
 M:     Liam Girdwood <lgirdwood@gmail.com>
+M:     Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
+M:     Bard Liao <yung-chuan.liao@linux.intel.com>
 M:     Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
-M:     Kai Vehmanen <kai.vehmanen@linux.intel.com>
+R:     Kai Vehmanen <kai.vehmanen@linux.intel.com>
 M:     Daniel Baluta <daniel.baluta@nxp.com>
 L:     sound-open-firmware@alsa-project.org (moderated for non-subscribers)
 S:     Supported
@@ -19203,7 +19366,6 @@ F:      arch/x86/boot/video*
 
 SWIOTLB SUBSYSTEM
 M:     Christoph Hellwig <hch@infradead.org>
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 S:     Supported
 W:     http://git.infradead.org/users/hch/dma-mapping.git
@@ -19684,7 +19846,7 @@ M:      Sowjanya Komatineni <skomatineni@nvidia.com>
 L:     linux-media@vger.kernel.org
 L:     linux-tegra@vger.kernel.org
 S:     Maintained
-F:     Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt
+F:     Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.yaml
 F:     drivers/staging/media/tegra-video/
 
 TEGRA XUSB PADCTL DRIVER
@@ -19807,6 +19969,7 @@ F:      Documentation/ABI/testing/sysfs-class-thermal
 F:     Documentation/devicetree/bindings/thermal/
 F:     Documentation/driver-api/thermal/
 F:     drivers/thermal/
+F:     include/dt-bindings/thermal/
 F:     include/linux/cpu_cooling.h
 F:     include/linux/thermal.h
 F:     include/uapi/linux/thermal.h
@@ -20281,7 +20444,7 @@ F:      tools/tracing/rtla/
 
 TRADITIONAL CHINESE DOCUMENTATION
 M:     Hu Haowen <src.res@email.cn>
-L:     linux-doc-tw-discuss@lists.sourceforge.net
+L:     linux-doc-tw-discuss@lists.sourceforge.net (moderated for non-subscribers)
 S:     Maintained
 W:     https://github.com/srcres258/linux-doc
 T:     git git://github.com/srcres258/linux-doc.git doc-zh-tw
@@ -20401,6 +20564,13 @@ F:     Documentation/filesystems/ubifs-authentication.rst
 F:     Documentation/filesystems/ubifs.rst
 F:     fs/ubifs/
 
+UBLK USERSPACE BLOCK DRIVER
+M:     Ming Lei <ming.lei@redhat.com>
+L:     linux-block@vger.kernel.org
+S:     Maintained
+F:     drivers/block/ublk_drv.c
+F:     include/uapi/linux/ublk_cmd.h
+
 UCLINUX (M68KNOMMU AND COLDFIRE)
 M:     Greg Ungerer <gerg@linux-m68k.org>
 L:     linux-m68k@lists.linux-m68k.org
@@ -21879,7 +22049,6 @@ XEN SWIOTLB SUBSYSTEM
 M:     Juergen Gross <jgross@suse.com>
 M:     Stefano Stabellini <sstabellini@kernel.org>
 L:     xen-devel@lists.xenproject.org (moderated for non-subscribers)
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 S:     Supported
 F:     arch/x86/xen/*swiotlb*
@@ -22030,7 +22199,7 @@ F:      include/linux/yam.h
 YAMA SECURITY MODULE
 M:     Kees Cook <keescook@chromium.org>
 S:     Supported
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git yama/tip
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/hardening
 F:     Documentation/admin-guide/LSM/Yama.rst
 F:     security/yama/
 
index 513c1fb..dc6295f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 5
 PATCHLEVEL = 19
 SUBLEVEL = 0
-EXTRAVERSION = -rc3
+EXTRAVERSION =
 NAME = Superb Owl
 
 # *DOCUMENTATION*
@@ -1097,6 +1097,7 @@ export MODULES_NSDEPS := $(extmod_prefix)modules.nsdeps
 ifeq ($(KBUILD_EXTMOD),)
 core-y                 += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/
 core-$(CONFIG_BLOCK)   += block/
+core-$(CONFIG_IO_URING)        += io_uring/
 
 vmlinux-dirs   := $(patsubst %/,%,$(filter %/, \
                     $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
@@ -1141,7 +1142,7 @@ KBUILD_MODULES := 1
 
 autoksyms_recursive: descend modules.order
        $(Q)$(CONFIG_SHELL) $(srctree)/scripts/adjust_autoksyms.sh \
-         "$(MAKE) -f $(srctree)/Makefile vmlinux"
+         "$(MAKE) -f $(srctree)/Makefile autoksyms_recursive"
 endif
 
 autoksyms_h := $(if $(CONFIG_TRIM_UNUSED_KSYMS), include/generated/autoksyms.h)
@@ -1347,10 +1348,10 @@ tools/%: FORCE
 # Kernel selftest
 
 PHONY += kselftest
-kselftest:
+kselftest: headers
        $(Q)$(MAKE) -C $(srctree)/tools/testing/selftests run_tests
 
-kselftest-%: FORCE
+kselftest-%: headers FORCE
        $(Q)$(MAKE) -C $(srctree)/tools/testing/selftests $*
 
 PHONY += kselftest-merge
index fcf9a41..761d169 100644 (file)
@@ -223,6 +223,9 @@ config HAVE_FUNCTION_DESCRIPTORS
 config TRACE_IRQFLAGS_SUPPORT
        bool
 
+config TRACE_IRQFLAGS_NMI_SUPPORT
+       bool
+
 #
 # An arch should select this if it provides all these things:
 #
@@ -438,6 +441,13 @@ config MMU_GATHER_PAGE_SIZE
 
 config MMU_GATHER_NO_RANGE
        bool
+       select MMU_GATHER_MERGE_VMAS
+
+config MMU_GATHER_NO_FLUSH_CACHE
+       bool
+
+config MMU_GATHER_MERGE_VMAS
+       bool
 
 config MMU_GATHER_NO_GATHER
        bool
@@ -774,7 +784,7 @@ config HAVE_ARCH_WITHIN_STACK_FRAMES
          and similar) by implementing an inline arch_within_stack_frames(),
          which is used by CONFIG_HARDENED_USERCOPY.
 
-config HAVE_CONTEXT_TRACKING
+config HAVE_CONTEXT_TRACKING_USER
        bool
        help
          Provide kernel/user boundaries probes necessary for subsystems
@@ -782,10 +792,10 @@ config HAVE_CONTEXT_TRACKING
          Syscalls need to be wrapped inside user_exit()-user_enter(), either
          optimized behind static key or through the slow path using TIF_NOHZ
          flag. Exceptions handlers must be wrapped as well. Irqs are already
-         protected inside rcu_irq_enter/rcu_irq_exit() but preemption or signal
+         protected inside ct_irq_enter/ct_irq_exit() but preemption or signal
          handling on irq exit still need to be protected.
 
-config HAVE_CONTEXT_TRACKING_OFFSTACK
+config HAVE_CONTEXT_TRACKING_USER_OFFSTACK
        bool
        help
          Architecture neither relies on exception_enter()/exception_exit()
@@ -797,7 +807,7 @@ config HAVE_CONTEXT_TRACKING_OFFSTACK
 
          - Critical entry code isn't preemptible (or better yet:
            not interruptible).
-         - No use of RCU read side critical sections, unless rcu_nmi_enter()
+         - No use of RCU read side critical sections, unless ct_nmi_enter()
            got called.
          - No use of instrumentation, unless instrumentation_begin() got
            called.
index f6d2946..15f2eff 100644 (file)
@@ -60,7 +60,7 @@ int irq_select_affinity(unsigned int irq)
                cpu = (cpu < (NR_CPUS-1) ? cpu + 1 : 0);
        last_cpu = cpu;
 
-       cpumask_copy(irq_data_get_affinity_mask(data), cpumask_of(cpu));
+       irq_data_update_affinity(data, cpumask_of(cpu));
        chip->irq_set_affinity(data, cpumask_of(cpu), false);
        return 0;
 }
index b8600dc..70b74a5 100644 (file)
@@ -96,19 +96,6 @@ void arch_jump_label_transform(struct jump_entry *entry,
        flush_icache_range(entry->code, entry->code + JUMP_LABEL_NOP_SIZE);
 }
 
-void arch_jump_label_transform_static(struct jump_entry *entry,
-                                     enum jump_label_type type)
-{
-       /*
-        * We use only one NOP type (1x, 4 byte) in arch_static_branch, so
-        * there's no need to patch an identical NOP over the top of it here.
-        * The generic code calls 'arch_jump_label_transform' if the NOP needs
-        * to be replaced by a branch, so 'arch_jump_label_transform_static' is
-        * never called with type other than JUMP_LABEL_NOP.
-        */
-       BUG_ON(type != JUMP_LABEL_NOP);
-}
-
 #ifdef CONFIG_ARC_DBG_JUMP_LABEL
 #define SELFTEST_MSG   "ARC: instruction generation self-test: "
 
index 7630ba9..4294c01 100644 (file)
@@ -84,7 +84,7 @@ config ARM
        select HAVE_ARCH_TRANSPARENT_HUGEPAGE if ARM_LPAE
        select HAVE_ARM_SMCCC if CPU_V7
        select HAVE_EBPF_JIT if !CPU_ENDIAN_BE32
-       select HAVE_CONTEXT_TRACKING
+       select HAVE_CONTEXT_TRACKING_USER
        select HAVE_C_RECORDMCOUNT
        select HAVE_BUILDTIME_MCOUNT_SORT
        select HAVE_DEBUG_KMEMLEAK if !XIP_KERNEL
@@ -350,6 +350,7 @@ config ARCH_MULTIPLATFORM
 config ARCH_FOOTBRIDGE
        bool "FootBridge"
        depends on CPU_LITTLE_ENDIAN
+       depends on ATAGS
        select CPU_SA110
        select FOOTBRIDGE
        select NEED_MACH_MEMORY_H
@@ -361,6 +362,7 @@ config ARCH_RPC
        bool "RiscPC"
        depends on !CC_IS_CLANG && GCC_VERSION < 90100 && GCC_VERSION >= 60000
        depends on CPU_LITTLE_ENDIAN
+       depends on ATAGS
        select ARCH_ACORN
        select ARCH_MAY_HAVE_PC_FDC
        select ARCH_SPARSEMEM_ENABLE
@@ -380,6 +382,7 @@ config ARCH_RPC
 config ARCH_SA1100
        bool "SA1100-based"
        depends on CPU_LITTLE_ENDIAN
+       depends on ATAGS
        select ARCH_MTD_XIP
        select ARCH_SPARSEMEM_ENABLE
        select CLKSRC_MMIO
@@ -588,6 +591,8 @@ source "arch/arm/mach-sti/Kconfig"
 
 source "arch/arm/mach-stm32/Kconfig"
 
+source "arch/arm/mach-sunplus/Kconfig"
+
 source "arch/arm/mach-sunxi/Kconfig"
 
 source "arch/arm/mach-tegra/Kconfig"
@@ -1539,14 +1544,26 @@ config USE_OF
          Include support for flattened device tree machine descriptions.
 
 config ATAGS
-       bool "Support for the traditional ATAGS boot data passing" if USE_OF
+       bool "Support for the traditional ATAGS boot data passing"
        default y
        help
          This is the traditional way of passing data to the kernel at boot
          time. If you are solely relying on the flattened device tree (or
          the ARM_ATAG_DTB_COMPAT option) then you may unselect this option
-         to remove ATAGS support from your kernel binary.  If unsure,
-         leave this to y.
+         to remove ATAGS support from your kernel binary.
+
+config UNUSED_BOARD_FILES
+       bool "Board support for machines without known users"
+       depends on ATAGS
+       help
+         Most ATAGS based board files are completely unused and are
+         scheduled for removal in early 2023, and left out of kernels
+         by default now.  If you are using a board file that is marked
+         as unused, turn on this option to build support into the kernel.
+
+         To keep support for your individual board from being removed,
+         send a reply to the email discussion at
+         https://lore.kernel.org/all/CAK8P3a0Z9vGEQbVRBo84bSyPFM-LF+hs5w8ZA51g2Z+NsdtDQA@mail.gmail.com/
 
 config DEPRECATED_PARAM_STRUCT
        bool "Provide old way to pass kernel parameters"
index 9b0aa48..792796a 100644 (file)
@@ -271,7 +271,7 @@ choice
 
        config DEBUG_BCM63XX_UART
                bool "Kernel low-level debugging on BCM63XX UART"
-               depends on ARCH_BCM_63XX
+               depends on ARCH_BCMBCA
 
        config DEBUG_BERLIN_UART
                bool "Marvell Berlin SoC Debug UART"
index c8e3633..56f655d 100644 (file)
@@ -215,6 +215,7 @@ machine-$(CONFIG_ARCH_RENESAS)              += shmobile
 machine-$(CONFIG_ARCH_INTEL_SOCFPGA)   += socfpga
 machine-$(CONFIG_ARCH_STI)             += sti
 machine-$(CONFIG_ARCH_STM32)           += stm32
+machine-$(CONFIG_ARCH_SUNPLUS)         += sunplus
 machine-$(CONFIG_ARCH_SUNXI)           += sunxi
 machine-$(CONFIG_ARCH_TEGRA)           += tegra
 machine-$(CONFIG_ARCH_U8500)           += ux500
index 1848998..05d8aef 100644 (file)
@@ -79,6 +79,8 @@ dtb-$(CONFIG_SOC_SAM_V7) += \
        at91-vinco.dtb
 dtb-$(CONFIG_SOC_SAMA7G5) += \
        at91-sama7g5ek.dtb
+dtb-$(CONFIG_SOC_SP7021) += \
+       sunplus-sp7021-demo-v3.dtb
 dtb-$(CONFIG_ARCH_AXXIA) += \
        axm5516-amarillo.dtb
 dtb-$(CONFIG_ARCH_BCM2835) += \
@@ -135,6 +137,7 @@ dtb-$(CONFIG_ARCH_BCM_5301X) += \
        bcm47094-luxul-xwr-3150-v1.dtb \
        bcm47094-netgear-r8500.dtb \
        bcm47094-phicomm-k3.dtb \
+       bcm53015-meraki-mr26.dtb \
        bcm53016-meraki-mr32.dtb \
        bcm94708.dtb \
        bcm94709.dtb \
@@ -146,8 +149,6 @@ dtb-$(CONFIG_ARCH_BCM_53573) += \
        bcm47189-luxul-xap-810.dtb \
        bcm47189-tenda-ac9.dtb \
        bcm947189acdbmr.dtb
-dtb-$(CONFIG_ARCH_BCM_63XX) += \
-       bcm963138dvt.dtb
 dtb-$(CONFIG_ARCH_BCM_CYGNUS) += \
        bcm911360_entphn.dtb \
        bcm911360k.dtb \
@@ -182,7 +183,15 @@ dtb-$(CONFIG_ARCH_BERLIN) += \
 dtb-$(CONFIG_ARCH_BRCMSTB) += \
        bcm7445-bcm97445svmb.dtb
 dtb-$(CONFIG_ARCH_BCMBCA) += \
-       bcm947622.dtb
+       bcm947622.dtb \
+       bcm963138.dtb \
+       bcm963138dvt.dtb \
+       bcm963148.dtb \
+       bcm963178.dtb \
+       bcm96756.dtb \
+       bcm96846.dtb \
+       bcm96855.dtb \
+       bcm96878.dtb
 dtb-$(CONFIG_ARCH_CLPS711X) += \
        ep7211-edb7211.dtb
 dtb-$(CONFIG_ARCH_DAVINCI) += \
@@ -550,6 +559,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
        imx6q-apalis-eval.dtb \
        imx6q-apalis-ixora.dtb \
        imx6q-apalis-ixora-v1.1.dtb \
+       imx6q-apalis-ixora-v1.2.dtb \
        imx6q-apf6dev.dtb \
        imx6q-arm2.dtb \
        imx6q-b450v3.dtb \
@@ -741,8 +751,12 @@ dtb-$(CONFIG_SOC_IMX7D) += \
        imx7d-cl-som-imx7.dtb \
        imx7d-colibri-aster.dtb \
        imx7d-colibri-emmc-aster.dtb \
+       imx7d-colibri-emmc-iris.dtb \
+       imx7d-colibri-emmc-iris-v2.dtb \
        imx7d-colibri-emmc-eval-v3.dtb \
        imx7d-colibri-eval-v3.dtb \
+       imx7d-colibri-iris.dtb \
+       imx7d-colibri-iris-v2.dtb \
        imx7d-flex-concentrator.dtb \
        imx7d-flex-concentrator-mfg.dtb \
        imx7d-mba7.dtb \
@@ -762,6 +776,8 @@ dtb-$(CONFIG_SOC_IMX7D) += \
        imx7d-zii-rpu2.dtb \
        imx7s-colibri-aster.dtb \
        imx7s-colibri-eval-v3.dtb \
+       imx7s-colibri-iris.dtb \
+       imx7s-colibri-iris-v2.dtb \
        imx7s-mba7.dtb \
        imx7s-warp.dtb
 dtb-$(CONFIG_SOC_IMX7ULP) += \
@@ -770,9 +786,10 @@ dtb-$(CONFIG_SOC_IMX7ULP) += \
 dtb-$(CONFIG_SOC_IMXRT) += \
        imxrt1050-evk.dtb
 dtb-$(CONFIG_SOC_LAN966) += \
-       lan966x-pcb8291.dtb \
        lan966x-kontron-kswitch-d10-mmt-6g-2gs.dtb \
-       lan966x-kontron-kswitch-d10-mmt-8g.dtb
+       lan966x-kontron-kswitch-d10-mmt-8g.dtb \
+       lan966x-pcb8291.dtb \
+       lan966x-pcb8309.dtb
 dtb-$(CONFIG_SOC_LS1021A) += \
        ls1021a-iot.dtb \
        ls1021a-moxa-uc-8410a.dtb \
@@ -1148,7 +1165,7 @@ dtb-$(CONFIG_ARCH_S5PV210) += \
        s5pv210-torbreck.dtb
 dtb-$(CONFIG_ARCH_INTEL_SOCFPGA) += \
        socfpga_arria5_socdk.dtb \
-       socfpga_arria10_mercury_aa1.dtb \
+       socfpga_arria10_chameleonv3.dtb \
        socfpga_arria10_socdk_nand.dtb \
        socfpga_arria10_socdk_qspi.dtb \
        socfpga_arria10_socdk_sdmmc.dtb \
@@ -1192,6 +1209,7 @@ dtb-$(CONFIG_ARCH_STM32) += \
        stm32mp151a-prtt1c.dtb \
        stm32mp151a-prtt1s.dtb \
        stm32mp153c-dhcom-drc02.dtb \
+       stm32mp153c-dhcor-drc-compact.dtb \
        stm32mp157a-avenger96.dtb \
        stm32mp157a-dhcor-avenger96.dtb \
        stm32mp157a-dk1.dtb \
@@ -1558,7 +1576,6 @@ dtb-$(CONFIG_ARCH_ASPEED) += \
        aspeed-ast2600-evb.dtb \
        aspeed-bmc-amd-ethanolx.dtb \
        aspeed-bmc-ampere-mtjade.dtb \
-       aspeed-bmc-arm-centriq2400-rep.dtb \
        aspeed-bmc-arm-stardragon4800-rep2.dtb \
        aspeed-bmc-asrock-e3c246d4i.dtb \
        aspeed-bmc-asrock-romed8hm3.dtb \
@@ -1586,7 +1603,6 @@ dtb-$(CONFIG_ARCH_ASPEED) += \
        aspeed-bmc-lenovo-hr630.dtb \
        aspeed-bmc-lenovo-hr855xg2.dtb \
        aspeed-bmc-microsoft-olympus.dtb \
-       aspeed-bmc-nuvia-dc-scm.dtb \
        aspeed-bmc-opp-lanyang.dtb \
        aspeed-bmc-opp-mihawk.dtb \
        aspeed-bmc-opp-mowgli.dtb \
@@ -1599,6 +1615,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \
        aspeed-bmc-opp-witherspoon.dtb \
        aspeed-bmc-opp-zaius.dtb \
        aspeed-bmc-portwell-neptune.dtb \
+       aspeed-bmc-qcom-dc-scm-v1.dtb \
        aspeed-bmc-quanta-q71l.dtb \
        aspeed-bmc-quanta-s6q.dtb \
        aspeed-bmc-supermicro-x11spi.dtb \
index 3b0675a..4be9887 100644 (file)
                        reg = <0x0 0xfbc00000 0x0 0x100000>;
                        interrupt-map-mask = <0xf800 0 0 7>;
                        /* Add legacy interrupts for SATA devices only */
-                       interrupt-map = <0x4000 0 0 1 &gic 0 43 4>,
+                       interrupt-map = <0x4000 0 0 1 &gic 0 43 4>,
                                        <0x4800 0 0 1 &gic 0 44 4>;
 
                        /* 32 bit non prefetchable memory space */
index c72b09a..207d2b6 100644 (file)
@@ -19,7 +19,7 @@
                regulator-name = "wlan-en-regulator";
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <1800000>;
-               startup-delay-us= <70000>;
+               startup-delay-us = <70000>;
 
                /* WL_EN */
                gpio = <&gpio3 9 0>;
index 9312197..b956e2f 100644 (file)
                "NC",
                "NC";
 };
+
+&baseboard_eeprom {
+       vcc-supply = <&ldo4_reg>;
+};
index 147c00d..34579e9 100644 (file)
                regulator-name = "wlan-en-regulator";
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <1800000>;
-               startup-delay-us= <70000>;
+               startup-delay-us = <70000>;
 
                /* WL_EN */
                gpio = <&gpio3 9 0>;
index 215f279..d388cff 100644 (file)
@@ -18,7 +18,7 @@
                regulator-name = "wlan-en-regulator";
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <1800000>;
-               startup-delay-us= <70000>;
+               startup-delay-us = <70000>;
 
                /* WL_EN */
                gpio = <&gpio0 26 0>;
index d9f003d..993b134 100644 (file)
@@ -325,7 +325,7 @@ status = "okay";
        tlv320aic23: codec@1a {
                compatible = "ti,tlv320aic23";
                reg = <0x1a>;
-               #sound-dai-cells= <0>;
+               #sound-dai-cells = <0>;
                status = "okay";
        };
 };
@@ -491,7 +491,7 @@ status = "okay";
                tx-num-evt = <1>;
                rx-num-evt = <1>;
 
-               #sound-dai-cells= <0>;
+               #sound-dai-cells = <0>;
                status = "okay";
 };
 
index b9745a2..25c6ac9 100644 (file)
                                0x0201006c>;    /* DOWN */
        };
 
-       gpio_keys: volume_keys0 {
+       gpio_keys: volume-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
                autorepeat;
 
-               switch9 {
+               switch-9 {
                        label = "volume-up";
                        linux,code = <115>;
                        gpios = <&gpio0 2 GPIO_ACTIVE_LOW>;
                        wakeup-source;
                };
 
-               switch10 {
+               switch-10 {
                        label = "volume-down";
                        linux,code = <114>;
                        gpios = <&gpio0 3 GPIO_ACTIVE_LOW>;
index 1a7e187..f635626 100644 (file)
@@ -33,8 +33,6 @@
                pinctrl-names = "default";
                pinctrl-0 = <&guardian_button_pins>;
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
                select-button {
                        label = "guardian-select-button";
index 92a0e98..7b40ca9 100644 (file)
 &buttons {
        pinctrl-names = "default";
        pinctrl-0 = <&push_button_pins>;
-       #address-cells = <1>;
-       #size-cells = <0>;
 
-       button@0 {
+       button-0 {
                label = "push_button";
                linux,code = <0x100>;
                gpios = <&gpio2 23 GPIO_ACTIVE_LOW>;
index e7e439a..e0364ad 100644 (file)
 &buttons {
        pinctrl-names = "default";
        pinctrl-0 = <&push_button_pins>;
-       #address-cells = <1>;
-       #size-cells = <0>;
 
-       button@0 {
+       button-0 {
                label = "push_button";
                linux,code = <0x100>;
                gpios = <&gpio3 21 GPIO_ACTIVE_LOW>;
index 124026f..dae4480 100644 (file)
                pinctrl-names = "default";
                pinctrl-0 = <&user_buttons_pins>;
 
-               button@0 {
+               button-0 {
                        label = "home";
                        linux,code = <KEY_HOME>;
                        gpios = <&gpio3 7 GPIO_ACTIVE_HIGH>;
                        wakeup-source;
                };
 
-               button@1 {
+               button-1 {
                        label = "menu";
                        linux,code = <KEY_MENU>;
                        gpios = <&gpio3 8 GPIO_ACTIVE_HIGH>;
index b5e88e6..8691eec 100644 (file)
 &buttons {
        pinctrl-names = "default";
        pinctrl-0 = <&user_buttons_pins>;
-       #address-cells = <1>;
-       #size-cells = <0>;
 
-       button0 {
+       button-0 {
                label = "home";
                linux,code = <KEY_HOME>;
                gpios = <&gpio1 22 GPIO_ACTIVE_LOW>;
                wakeup-source;
        };
 
-       button1 {
+       button-1 {
                label = "menu";
                linux,code = <KEY_MENU>;
                gpios = <&gpio1 23 GPIO_ACTIVE_LOW>;
                wakeup-source;
        };
 
-       buttons2 {
+       button-2 {
                label = "power";
                linux,code = <KEY_POWER>;
                gpios = <&gpio0 7 GPIO_ACTIVE_LOW>;
index 246a1a9..a2676d1 100644 (file)
@@ -23,7 +23,7 @@
                regulator-name = "wlan-en-regulator";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
-               startup-delay-us= <100000>;
+               startup-delay-us = <100000>;
        };
 };
 
index 6b98775..c497200 100644 (file)
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               back_button {
+               back-button {
                        label = "Back Button";
                        gpios = <&gpio1 29 GPIO_ACTIVE_HIGH>;
                        linux,code = <KEY_BACK>;
@@ -47,7 +47,7 @@
                        wakeup-source;
                };
 
-               front_button {
+               front-button {
                        label = "Front Button";
                        gpios = <&gpio1 25 GPIO_ACTIVE_HIGH>;
                        linux,code = <KEY_FRONT>;
index 7d8f32b..75ad421 100644 (file)
                compatible = "gpio-keys-polled";
                poll-interval = <100>;
 
-               record {
+               key-record {
                        label = "Record";
                        /* linux,code = <BTN_0>; */
                        gpios = <&tca6416_2 15 GPIO_ACTIVE_LOW>;
                };
 
-               play {
+               key-play {
                        label = "Play";
                        linux,code = <KEY_PLAY>;
                        gpios = <&tca6416_2 14 GPIO_ACTIVE_LOW>;
                };
 
-               Stop {
+               key-stop {
                        label = "Stop";
                        linux,code = <KEY_STOP>;
                        gpios = <&tca6416_2 13 GPIO_ACTIVE_LOW>;
                };
 
-               fwd {
+               key-fwd {
                        label = "FWD";
                        linux,code = <KEY_FASTFORWARD>;
                        gpios = <&tca6416_2 12 GPIO_ACTIVE_LOW>;
                };
 
-               rwd {
+               key-rwd {
                        label = "RWD";
                        linux,code = <KEY_REWIND>;
                        gpios = <&tca6416_2 11 GPIO_ACTIVE_LOW>;
                };
 
-               shift {
+               key-shift {
                        label = "Shift";
                        linux,code = <KEY_LEFTSHIFT>;
                        gpios = <&tca6416_2 10 GPIO_ACTIVE_LOW>;
                };
 
-               Mode {
+               key-mode {
                        label = "Mode";
                        linux,code = <BTN_MODE>;
                        gpios = <&tca6416_2 9 GPIO_ACTIVE_LOW>;
                };
 
-               Menu {
+               key-menu {
                        label = "Menu";
                        linux,code = <KEY_MENU>;
                        gpios = <&tca6416_2 8 GPIO_ACTIVE_LOW>;
                };
 
-               Up {
+               key-up {
                        label = "Up";
                        linux,code = <KEY_UP>;
                        gpios = <&tca6416_2 7 GPIO_ACTIVE_LOW>;
                };
 
-               Down {
+               key-down {
                        label = "Down";
                        linux,code = <KEY_DOWN>;
                        gpios = <&tca6416_2 6 GPIO_ACTIVE_LOW>;
        tlv320aic23_1: codec@1a {
                compatible = "ti,tlv320aic23";
                reg = <0x1a>;
-               #sound-dai-cells= <0>;
+               #sound-dai-cells = <0>;
                status = "okay";
        };
 
        tlv320aic23_2: codec@1b {
                compatible = "ti,tlv320aic23";
                reg = <0x1b>;
-               #sound-dai-cells= <0>;
+               #sound-dai-cells = <0>;
                status = "okay";
        };
 };
        tlv320aic23_3: codec@1a {
                compatible = "ti,tlv320aic23";
                reg = <0x1a>;
-               #sound-dai-cells= <0>;
+               #sound-dai-cells = <0>;
                status = "okay";
        };
 
index c8b80f1..35b6530 100644 (file)
                compatible = "gpio-keys-polled";
                poll-interval = <100>;
 
-               user_pb {
+               button-user {
                        label = "User Push Button";
                        linux,code = <BTN_0>;
                        gpios = <&tca6416 5 GPIO_ACTIVE_LOW>;
                };
 
-               user_sw_1 {
+               switch-1 {
                        label = "User Switch 1";
                        linux,code = <BTN_1>;
                        gpios = <&tca6416 8 GPIO_ACTIVE_LOW>;
                };
 
-               user_sw_2 {
+               switch-2 {
                        label = "User Switch 2";
                        linux,code = <BTN_2>;
                        gpios = <&tca6416 9 GPIO_ACTIVE_LOW>;
                };
 
-               user_sw_3 {
+               switch-3 {
                        label = "User Switch 3";
                        linux,code = <BTN_3>;
                        gpios = <&tca6416 10 GPIO_ACTIVE_LOW>;
                };
 
-               user_sw_4 {
+               switch-4 {
                        label = "User Switch 4";
                        linux,code = <BTN_4>;
                        gpios = <&tca6416 11 GPIO_ACTIVE_LOW>;
                };
 
-               user_sw_5 {
+               switch-5 {
                        label = "User Switch 5";
                        linux,code = <BTN_5>;
                        gpios = <&tca6416 12 GPIO_ACTIVE_LOW>;
                };
 
-               user_sw_6 {
+               switch-6 {
                        label = "User Switch 6";
                        linux,code = <BTN_6>;
                        gpios = <&tca6416 13 GPIO_ACTIVE_LOW>;
                };
 
-               user_sw_7 {
+               switch-7 {
                        label = "User Switch 7";
                        linux,code = <BTN_7>;
                        gpios = <&tca6416 14 GPIO_ACTIVE_LOW>;
                };
 
-               user_sw_8 {
+               switch-8 {
                        label = "User Switch 8";
                        linux,code = <BTN_8>;
                        gpios = <&tca6416 15 GPIO_ACTIVE_LOW>;
index c9323d1..d039af8 100644 (file)
 
                        u48: pca9575@22 {
                                compatible = "nxp,pca9575";
-                               reg=<0x22>;
+                               reg = <0x22>;
                                gpio-controller;
                                #gpio-cells = <2>;
 
 
                        u59: pca9575@23 {
                                compatible = "nxp,pca9575";
-                               reg=<0x23>;
+                               reg = <0x23>;
                                gpio-controller;
                                #gpio-cells = <2>;
                                gpio-line-names =
index 5a74b83..123a95f 100644 (file)
                vin-supply = <&v1_5dreg>;
        };
 
-       gpio_keys: gpio_keys {
+       gpio_keys: gpio-keys {
                compatible = "gpio-keys";
                pinctrl-names = "default";
                pinctrl-0 = <&gpio_keys_pins_default>;
-               #address-cells = <1>;
-               #size-cells = <0>;
 
-               switch0 {
+               switch-0 {
                        label = "power-button";
                        linux,code = <KEY_POWER>;
                        gpios = <&gpio4 2 GPIO_ACTIVE_LOW>;
index 8f2268c..415210b 100644 (file)
 
                                adc {
                                        #io-channel-cells = <1>;
-                                       compatible ="ti,am4372-adc";
+                                       compatible = "ti,am4372-adc";
                                };
                        };
                };
index 7da718a..29936bf 100644 (file)
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
-               keyswitch_in {
+               key-switch-in {
                        label = "keyswitch_in";
                        gpios = <&pioB 1 GPIO_ACTIVE_HIGH>;
                        linux,code = <28>;
                        wakeup-source;
                };
 
-               error_in {
+               key-error-in {
                        label = "error_in";
                        gpios = <&pioB 2 GPIO_ACTIVE_HIGH>;
                        linux,code = <29>;
                        wakeup-source;
                };
 
-               btn {
+               key-s {
                        label = "btn";
                        gpios = <&pioC 23 GPIO_ACTIVE_HIGH>;
                        linux,code = <31>;
index 1a4a09b..84d40e1 100644 (file)
                pinctrl-0 = <&pmx_buttons>;
                pinctrl-names = "default";
 
-               power {
+               button-power {
                        label = "Power Button";
                        linux,code = <KEY_POWER>;
                        gpios = <&gpio0 10 GPIO_ACTIVE_HIGH>;
                };
 
-               reset {
+               button-reset {
                        label = "Reset Button";
                        linux,code = <KEY_RESTART>;
                        gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
                };
 
-               usb1 {
+               button-usb1 {
                        label = "USB1 Button";
                        linux,code = <BTN_0>;
                        gpios = <&gpio1 0 GPIO_ACTIVE_LOW>;
                };
 
-               usb2 {
+               button-usb2 {
                        label = "USB2 Button";
                        linux,code = <BTN_1>;
                        gpios = <&gpio0 14 GPIO_ACTIVE_LOW>;
index c910d15..6ba7699 100644 (file)
@@ -84,8 +84,6 @@
 
                        gpio-keys {
                                compatible = "gpio-keys";
-                               #address-cells = <1>;
-                               #size-cells = <0>;
                                button {
                                        label = "Software Button";
                                        linux,code = <KEY_POWER>;
index b52634e..866b863 100644 (file)
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
-               power {
+               button-power {
                        label = "Power button";
                        linux,code = <KEY_POWER>;
                        gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;
                        debounce-interval = <100>;
                };
-               backup {
+               button-backup {
                        label = "Backup button";
                        linux,code = <KEY_OPTION>;
                        gpios = <&gpio0 31 GPIO_ACTIVE_LOW>;
                        debounce-interval = <100>;
                };
-               reset {
+               button-reset {
                        label = "Reset Button";
                        linux,code = <KEY_RESTART>;
                        gpios = <&gpio1 23 GPIO_ACTIVE_LOW>;
index 0abac5f..702a85a 100644 (file)
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
-               power {
+               button-power {
                        label = "Power button";
                        linux,code = <KEY_POWER>;
                        gpios = <&gpio1 19 GPIO_ACTIVE_HIGH>;
                        debounce-interval = <100>;
                };
-               reset {
+               button-reset {
                        label = "Reset Button";
                        linux,code = <KEY_RESTART>;
                        gpios = <&gpio1 23 GPIO_ACTIVE_LOW>;
                        debounce-interval = <100>;
                };
-               button {
+               button-usb {
                        label = "USB VBUS error";
                        linux,code = <KEY_UNKNOWN>;
                        gpios = <&gpio1 21 GPIO_ACTIVE_LOW>;
index 3961720..095df55 100644 (file)
@@ -24,7 +24,7 @@
                pinctrl-0 = <&front_button_pins>;
                pinctrl-names = "default";
 
-               factory_default {
+               key-factory-default {
                        label = "Factory Default";
                        gpios = <&gpio1 6 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_RESTART>;
index 10ad46f..d1452a0 100644 (file)
                pinctrl-0 = <&cf_gtr_rear_button_pins &cf_gtr_front_button_pins>;
                pinctrl-names = "default";
 
-               button_0 {
+               button-0 {
                        label = "Rear Button";
                        gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
                        linux,can-disable;
                        linux,code = <BTN_0>;
                };
 
-               button_1 {
+               button-1 {
                        label = "Front Button";
                        gpios = <&gpio1 21 GPIO_ACTIVE_LOW>;
                        linux,can-disable;
index fb9c8a0..116aca5 100644 (file)
                pinctrl-0 = <&gpio_keys_pins>;
                pinctrl-names = "default";
 
-               wps {
+               button-wps {
                        label = "WPS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&gpio0 24 GPIO_ACTIVE_LOW>;
                };
 
-               reset {
+               button-reset {
                        label = "Factory Reset Button";
                        linux,code = <KEY_RESTART>;
                        gpios = <&gpio0 29 GPIO_ACTIVE_LOW>;
index f4878df..d1e0db6 100644 (file)
                                reg = <0x2b>;
                                #address-cells = <1>;
                                #size-cells = <0>;
+                               status = "okay";
 
                                /*
                                 * LEDs are controlled by MCU (STM32F0) at
                                 * address 0x2b.
                                 *
-                                * The driver does not support HW control mode
-                                * for the LEDs yet. Disable the LEDs for now.
-                                *
-                                * Also LED functions are not stable yet:
+                                * LED functions are not stable yet:
                                 * - there are 3 LEDs connected via MCU to PCIe
                                 *   ports. One of these ports supports mSATA.
                                 *   There is no mSATA nor PCIe function.
                                 *   B. Again there is no such function defined.
                                 *   For now we use LED_FUNCTION_INDICATOR
                                 */
-                               status = "disabled";
 
                                multi-led@0 {
                                        reg = <0x0>;
        phy1: ethernet-phy@1 {
                compatible = "ethernet-phy-ieee802.3-c22";
                reg = <1>;
-               marvell,reg-init = <3 18 0 0x4985>;
+               marvell,reg-init = <3 18 0 0x4985>,
+                                  <3 16 0xfff0 0x0001>;
 
                /* irq is connected to &pcawan pin 7 */
        };
index 53b4bd3..f7daa3b 100644 (file)
@@ -19,7 +19,7 @@
                pinctrl-0 = <&rear_button_pins>;
                pinctrl-names = "default";
 
-               button_0 {
+               button-0 {
                        /* The rear SW3 button */
                        label = "Rear Button";
                        gpios = <&gpio1 12 GPIO_ACTIVE_LOW>;
index 4140a53..9529916 100644 (file)
@@ -35,7 +35,7 @@
                pinctrl-0 = <&rear_button_pins>;
                pinctrl-names = "default";
 
-               button_0 {
+               button-0 {
                        /* The rear SW3 button */
                        label = "Rear Button";
                        gpios = <&gpio1 2 GPIO_ACTIVE_LOW>;
index 3e77b43..5a74197 100644 (file)
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
                pinctrl-0 = <&keys_pin>;
                pinctrl-names = "default";
 
-               reset {
+               button-reset {
                        label = "Factory Reset Button";
                        linux,code = <KEY_SETUP>;
                        gpios = <&gpio1 1 GPIO_ACTIVE_LOW>;
index 36932e3..622ac40 100644 (file)
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
                pinctrl-0 = <&keys_pin>;
                pinctrl-names = "default";
 
-               wps {
+               button-wps {
                        label = "WPS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&gpio1 0 GPIO_ACTIVE_LOW>;
                };
 
-               reset {
+               button-reset {
                        label = "Factory Reset Button";
                        linux,code = <KEY_RESTART>;
                        gpios = <&gpio1 1 GPIO_ACTIVE_LOW>;
index 0efcc16..1ecf72a 100644 (file)
                                };
                        };
 
-                       gpio_keys {
+                       gpio-keys {
                                compatible = "gpio-keys";
-                               #address-cells = <1>;
-                               #size-cells = <0>;
 
-                               init {
+                               button-init {
                                        label = "Init Button";
                                        linux,code = <KEY_POWER>;
                                        gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>;
index 1d24b39..a497dd1 100644 (file)
@@ -5,7 +5,7 @@
 
 / {
        model = "AST2500 EVB";
-       compatible = "aspeed,ast2500";
+       compatible = "aspeed,ast2500-evb", "aspeed,ast2500";
 
        aliases {
                serial4 = &uart5;
index dd71480..d0a5c2f 100644 (file)
@@ -5,6 +5,7 @@
 
 / {
        model = "AST2600 A1 EVB";
+       compatible = "aspeed,ast2600-evb-a1", "aspeed,ast2600";
 
        /delete-node/regulator-vcc-sdhci0;
        /delete-node/regulator-vcc-sdhci1;
index 5a6063b..c698e65 100644 (file)
@@ -8,7 +8,7 @@
 
 / {
        model = "AST2600 EVB";
-       compatible = "aspeed,ast2600";
+       compatible = "aspeed,ast2600-evb-a1", "aspeed,ast2600";
 
        aliases {
                serial4 = &uart5;
index 1b2e7ad..82a6f14 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               shutdown_ack {
+               event-shutdown-ack {
                        label = "SHUTDOWN_ACK";
                        gpios = <&gpio ASPEED_GPIO(G, 2) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(G, 2)>;
                };
 
-               reboot_ack {
+               event-reboot-ack {
                        label = "REBOOT_ACK";
                        gpios = <&gpio ASPEED_GPIO(J, 3) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(J, 3)>;
                };
 
-               S0_overtemp {
+               event-s0-overtemp {
                        label = "S0_OVERTEMP";
                        gpios = <&gpio ASPEED_GPIO(G, 3) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(G, 3)>;
                };
 
-               S0_hightemp {
+               event-s0-hightemp {
                        label = "S0_HIGHTEMP";
                        gpios = <&gpio ASPEED_GPIO(J, 0) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(J, 0)>;
                };
 
-               S0_cpu_fault {
+               event-s0-cpu-fault {
                        label = "S0_CPU_FAULT";
                        gpios = <&gpio ASPEED_GPIO(J, 1) GPIO_ACTIVE_HIGH>;
                        linux,code = <ASPEED_GPIO(J, 1)>;
                };
 
-               S0_scp_auth_fail {
+               event-s0-scp-auth-fail {
                        label = "S0_SCP_AUTH_FAIL";
                        gpios = <&gpio ASPEED_GPIO(J, 2) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(J, 2)>;
                };
 
-               S1_scp_auth_fail {
+               event-s1-scp-auth-fail {
                        label = "S1_SCP_AUTH_FAIL";
                        gpios = <&gpio ASPEED_GPIO(Z, 5) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(Z, 5)>;
                };
 
-               S1_overtemp {
+               event-s1-overtemp {
                        label = "S1_OVERTEMP";
                        gpios = <&gpio ASPEED_GPIO(Z, 6) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(Z, 6)>;
                };
 
-               S1_hightemp {
+               event-s1-hightemp {
                        label = "S1_HIGHTEMP";
                        gpios = <&gpio ASPEED_GPIO(AB, 0) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(AB, 0)>;
                };
 
-               S1_cpu_fault {
+               event-s1-cpu-fault {
                        label = "S1_CPU_FAULT";
                        gpios = <&gpio ASPEED_GPIO(Z, 1) GPIO_ACTIVE_HIGH>;
                        linux,code = <ASPEED_GPIO(Z, 1)>;
                };
 
-               id_button {
+               event-id {
                        label = "ID_BUTTON";
                        gpios = <&gpio ASPEED_GPIO(Q, 5) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(Q, 5)>;
                };
 
-               psu1_vin_good {
+               event-psu1-vin-good {
                        label = "PSU1_VIN_GOOD";
                        gpios = <&gpio ASPEED_GPIO(H, 4) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(H, 4)>;
                };
 
-               psu2_vin_good {
+               event-psu2-vin-good {
                        label = "PSU2_VIN_GOOD";
                        gpios = <&gpio ASPEED_GPIO(H, 5) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(H, 5)>;
                };
 
-               psu1_present {
+               event-psu1-present {
                        label = "PSU1_PRESENT";
                        gpios = <&gpio ASPEED_GPIO(I, 0) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(I, 0)>;
                };
 
-               psu2_present {
+               event-psu2-present {
                        label = "PSU2_PRESENT";
                        gpios = <&gpio ASPEED_GPIO(I, 1) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(I, 1)>;
diff --git a/arch/arm/boot/dts/aspeed-bmc-arm-centriq2400-rep.dts b/arch/arm/boot/dts/aspeed-bmc-arm-centriq2400-rep.dts
deleted file mode 100644 (file)
index 3395de9..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/dts-v1/;
-
-#include "aspeed-g5.dtsi"
-#include <dt-bindings/gpio/aspeed-gpio.h>
-
-/ {
-       model = "Qualcomm Centriq 2400  REP AST2520";
-       compatible = "qualcomm,centriq2400-rep-bmc", "aspeed,ast2500";
-
-       chosen {
-               stdout-path = &uart5;
-               bootargs = "console=ttyS4,115200 earlycon";
-       };
-
-       memory@80000000 {
-               reg = <0x80000000 0x40000000>;
-       };
-
-       iio-hwmon {
-               compatible = "iio-hwmon";
-               io-channels = <&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>,
-                        <&adc 4>, <&adc 5>, <&adc 6>, <&adc 8>;
-       };
-
-       iio-hwmon-battery {
-               compatible = "iio-hwmon";
-               io-channels = <&adc 7>;
-       };
-
-       leds {
-               compatible = "gpio-leds";
-
-               uid_led {
-                       label = "UID_LED";
-                       gpios = <&gpio ASPEED_GPIO(Q, 5) GPIO_ACTIVE_LOW>;
-               };
-
-               ras_error_led {
-                       label = "RAS_ERROR_LED";
-                       gpios = <&gpio ASPEED_GPIO(F, 6) GPIO_ACTIVE_LOW>;
-               };
-
-               system_fault {
-                       label = "System_fault";
-                       gpios = <&gpio ASPEED_GPIO(A, 1) GPIO_ACTIVE_LOW>;
-               };
-       };
-};
-
-&fmc {
-       status = "okay";
-       flash@0 {
-               status = "okay";
-               m25p,fast-read;
-               label = "bmc";
-#include "openbmc-flash-layout.dtsi"
-       };
-};
-
-&spi1 {
-       status = "okay";
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_spi1_default>;
-       flash@0 {
-               status = "okay";
-       };
-};
-
-&spi2 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_spi2ck_default
-                       &pinctrl_spi2miso_default
-                       &pinctrl_spi2mosi_default
-                       &pinctrl_spi2cs0_default>;
-};
-
-&uart3 {
-       status = "okay";
-
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_txd3_default &pinctrl_rxd3_default>;
-       current-speed = <115200>;
-};
-
-&uart5 {
-       status = "okay";
-};
-
-&mac0 {
-       status = "okay";
-
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_rgmii1_default &pinctrl_mdio1_default>;
-};
-
-&i2c0 {
-       status = "okay";
-};
-
-&i2c1 {
-       status = "okay";
-
-       tmp421@1e {
-               compatible = "ti,tmp421";
-               reg = <0x1e>;
-       };
-       tmp421@2a {
-               compatible = "ti,tmp421";
-               reg = <0x2a>;
-       };
-       tmp421@4e {
-               compatible = "ti,tmp421";
-               reg = <0x4e>;
-       };
-       tmp421@1c {
-               compatible = "ti,tmp421";
-               reg = <0x1c>;
-       };
-};
-
-&i2c2 {
-       status = "okay";
-};
-
-&i2c3 {
-       status = "okay";
-};
-
-&i2c4 {
-       status = "okay";
-};
-
-&i2c5 {
-       status = "okay";
-};
-
-&i2c6 {
-       status = "okay";
-
-       tmp421@1d {
-               compatible = "ti,tmp421";
-               reg = <0x1d>;
-       };
-       tmp421@1f {
-               compatible = "ti,tmp421";
-               reg = <0x1f>;
-       };
-       tmp421@4d {
-               compatible = "ti,tmp421";
-               reg = <0x4d>;
-       };
-       tmp421@4f {
-               compatible = "ti,tmp421";
-               reg = <0x4f>;
-       };
-       nvt210@4c {
-               compatible = "nvt210";
-               reg = <0x4c>;
-       };
-       eeprom@50 {
-               compatible = "atmel,24c128";
-               reg = <0x50>;
-               pagesize = <128>;
-       };
-};
-
-&i2c7 {
-       status = "okay";
-};
-
-&i2c8 {
-       status = "okay";
-
-       pca9641@70 {
-               compatible = "nxp,pca9641";
-               reg = <0x70>;
-               i2c-arb {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       tmp421@1d {
-                               compatible = "tmp421";
-                               reg = <0x1d>;
-                       };
-                       adm1278@12 {
-                               compatible = "adi,adm1278";
-                               reg = <0x12>;
-                               Rsense = <500>;
-                       };
-                       eeprom@50 {
-                               compatible = "atmel,24c02";
-                               reg = <0x50>;
-                       };
-                       ds1100@58 {
-                               compatible = "ds1100";
-                               reg = <0x58>;
-                       };
-               };
-       };
-};
-
-&i2c9 {
-       status = "okay";
-};
-
-&vuart {
-       status = "okay";
-};
-
-&gfx {
-       status = "okay";
-};
-
-&pinctrl {
-       aspeed,external-nodes = <&gfx &lhc>;
-};
-
-&gpio {
-       pin_gpio_c7 {
-               gpio-hog;
-               gpios = <ASPEED_GPIO(C, 7) GPIO_ACTIVE_HIGH>;
-               output;
-               line-name = "BIOS_SPI_MUX_S";
-       };
-};
index 0d1fb5c..f75cad4 100644 (file)
 
        gpio-keys {
                compatible = "gpio-keys";
-               burn-in-signal {
+               event-burn-in-signal {
                        label = "burn-in";
                        gpios = <&gpio ASPEED_GPIO(R, 5) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(R, 5)>;
                compatible = "gpio-keys-polled";
                poll-interval = <1000>;
 
-               rear-riser1-presence {
+               event-rear-riser1-presence {
                        label = "rear-riser1-presence";
                        gpios = <&pca0 1 GPIO_ACTIVE_LOW>;
                        linux,code = <1>;
                };
 
-               alrt-pvddq-cpu0 {
+               event-alrt-pvddq-cpu0 {
                        label = "alrt-pvddq-cpu0";
                        gpios = <&pca0 8 GPIO_ACTIVE_LOW>;
                        linux,code = <2>;
                };
 
-               rear-riser0-presence {
+               event-rear-riser0-presence {
                        label = "rear-riser0-presence";
                        gpios = <&pca0 9 GPIO_ACTIVE_LOW>;
                        linux,code = <3>;
                };
 
-               fault-pvddq-cpu0 {
+               event-fault-pvddq-cpu0 {
                        label = "fault-pvddq-cpu0";
                        gpios = <&pca0 10 GPIO_ACTIVE_LOW>;
                        linux,code = <4>;
                };
 
-               alrt-pvddq-cpu1 {
+               event-alrt-pvddq-cpu1 {
                        label = "alrt-pvddq-cpu1";
                        gpios = <&pca0 11 GPIO_ACTIVE_LOW>;
                        linux,code = <5>;
                };
 
-               fault-pvddq-cpu1 {
+               event-fault-pvddq-cpu1 {
                        label = "alrt-pvddq-cpu1";
                        gpios = <&pca0 12 GPIO_ACTIVE_LOW>;
                        linux,code = <6>;
                };
 
-               fault-pvccin-cpu1 {
+               event-fault-pvccin-cpu1 {
                        label = "fault-pvccin-cpuq";
                        gpios = <&pca0 13 GPIO_ACTIVE_LOW>;
                        linux,code = <7>;
                };
 
-               bmc-rom0-wp {
+               event-bmc-rom0-wp {
                        label = "bmc-rom0-wp";
                        gpios = <&pca1 0 GPIO_ACTIVE_LOW>;
                        linux,code = <8>;
                };
 
-               bmc-rom1-wp {
+               event-bmc-rom1-wp {
                        label = "bmc-rom1-wp";
                        gpios = <&pca1 1 GPIO_ACTIVE_LOW>;
                        linux,code = <9>;
                };
 
-               fan0-presence {
+               event-fan0-presence {
                        label = "fan0-presence";
                        gpios = <&pca1 2 GPIO_ACTIVE_LOW>;
                        linux,code = <10>;
                };
 
-               fan1-presence {
+               event-fan1-presence {
                        label = "fan1-presence";
                        gpios = <&pca1 3 GPIO_ACTIVE_LOW>;
                        linux,code = <11>;
                };
 
-               fan2-presence {
+               event-fan2-presence {
                        label = "fan2-presence";
                        gpios = <&pca1 4 GPIO_ACTIVE_LOW>;
                        linux,code = <12>;
                };
 
-               fan3-presence {
+               event-fan3-presence {
                        label = "fan3-presence";
                        gpios = <&pca1 5 GPIO_ACTIVE_LOW>;
                        linux,code = <13>;
                };
 
-               fan4-presence {
+               event-fan4-presence {
                        label = "fan4-presence";
                        gpios = <&pca1 6 GPIO_ACTIVE_LOW>;
                        linux,code = <14>;
                };
 
-               fan5-presence {
+               event-fan5-presence {
                        label = "fan5-presence";
                        gpios = <&pca1 7 GPIO_ACTIVE_LOW>;
                        linux,code = <15>;
                };
 
-               front-bp1-presence {
+               event-front-bp1-presence {
                        label = "front-bp1-presence";
                        gpios = <&pca1 8 GPIO_ACTIVE_LOW>;
                        linux,code = <16>;
                };
 
-               rear-bp-presence {
+               event-rear-bp-presence {
                        label = "rear-bp-presence";
                        gpios = <&pca1 9 GPIO_ACTIVE_LOW>;
                        linux,code = <17>;
                };
 
-               fault-pvccin-cpu0 {
+               event-fault-pvccin-cpu0 {
                        label = "fault-pvccin-cpu0";
                        gpios = <&pca1 10 GPIO_ACTIVE_LOW>;
                        linux,code = <18>;
                };
 
-               alrt-p1v05-pvcc {
+               event-alrt-p1v05-pvcc {
                        label = "alrt-p1v05-pvcc1";
                        gpios = <&pca1 11 GPIO_ACTIVE_LOW>;
                        linux,code = <19>;
                };
 
-               fault-p1v05-pvccio {
+               event-fault-p1v05-pvccio {
                        label = "alrt-p1v05-pvcc1";
                        gpios = <&pca1 12 GPIO_ACTIVE_LOW>;
                        linux,code = <20>;
                };
 
-               alrt-p1v8-pvccio {
+               event-alrt-p1v8-pvccio {
                        label = "alrt-p1v8-pvccio";
                        gpios = <&pca1 13 GPIO_ACTIVE_LOW>;
                        linux,code = <21>;
                };
 
-               fault-p1v8-pvccio {
+               event-fault-p1v8-pvccio {
                        label = "fault-p1v8-pvccio";
                        gpios = <&pca1 14 GPIO_ACTIVE_LOW>;
                        linux,code = <22>;
                };
 
-               front-bp0-presence {
+               event-front-bp0-presence {
                        label = "front-bp0-presence";
                        gpios = <&pca1 15 GPIO_ACTIVE_LOW>;
                        linux,code = <23>;
index 382da79..a6a2bc3 100644 (file)
 
        gpio-keys-polled {
                compatible = "gpio-keys-polled";
-               #address-cells = <1>;
-               #size-cells = <0>;
                poll-interval = <1000>;
 
-               fan0-presence {
+               event-fan0-presence {
                        label = "fan0-presence";
                        gpios = <&pca0 15 GPIO_ACTIVE_LOW>;
                        linux,code = <15>;
                };
 
-               fan1-presence {
+               event-fan1-presence {
                        label = "fan1-presence";
                        gpios = <&pca0 14 GPIO_ACTIVE_LOW>;
                        linux,code = <14>;
                };
 
-               fan2-presence {
+               event-fan2-presence {
                        label = "fan2-presence";
                        gpios = <&pca0 13 GPIO_ACTIVE_LOW>;
                        linux,code = <13>;
                };
 
-               fan3-presence {
+               event-fan3-presence {
                        label = "fan3-presence";
                        gpios = <&pca0 12 GPIO_ACTIVE_LOW>;
                        linux,code = <12>;
index 7213434..bf59a99 100644 (file)
 
        gpio-keys-polled {
                compatible = "gpio-keys-polled";
-               #address-cells = <1>;
-               #size-cells = <0>;
                poll-interval = <1000>;
 
-               fan0-presence {
+               event-fan0-presence {
                        label = "fan0-presence";
                        gpios = <&pca0 6 GPIO_ACTIVE_LOW>;
                        linux,code = <6>;
                };
 
-               fan1-presence {
+               event-fan1-presence {
                        label = "fan1-presence";
                        gpios = <&pca0 7 GPIO_ACTIVE_LOW>;
                        linux,code = <7>;
                };
 
-               fan2-presence {
+               event-fan2-presence {
                        label = "fan2-presence";
                        gpios = <&pca0 8 GPIO_ACTIVE_LOW>;
                        linux,code = <8>;
                };
 
-               fan3-presence {
+               event-fan3-presence {
                        label = "fan3-presence";
                        gpios = <&pca0 9 GPIO_ACTIVE_LOW>;
                        linux,code = <9>;
                };
 
-               fan4-presence {
+               event-fan4-presence {
                        label = "fan4-presence";
                        gpios = <&pca0 10 GPIO_ACTIVE_LOW>;
                        linux,code = <10>;
                };
 
-               fan5-presence {
+               event-fan5-presence {
                        label = "fan5-presence";
                        gpios = <&pca0 11 GPIO_ACTIVE_LOW>;
                        linux,code = <11>;
index 60a39ea..208b0f0 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               checkstop {
+               event-checkstop {
                        label = "checkstop";
                        gpios = <&gpio ASPEED_GPIO(B, 3) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(B, 3)>;
                };
 
-               ps0-presence {
+               event-ps0-presence {
                        label = "ps0-presence";
                        gpios = <&gpio ASPEED_GPIO(F, 0) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(F, 0)>;
                };
 
-               ps1-presence {
+               event-ps1-presence {
                        label = "ps1-presence";
                        gpios = <&gpio ASPEED_GPIO(F, 1) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(F, 1)>;
                compatible = "gpio-keys-polled";
                poll-interval = <1000>;
 
-               fan0-presence {
+               event-fan0-presence {
                        label = "fan0-presence";
                        gpios = <&pca1 0 GPIO_ACTIVE_LOW>;
                        linux,code = <1>;
                };
 
-               fan1-presence {
+               event-fan1-presence {
                        label = "fan1-presence";
                        gpios = <&pca1 1 GPIO_ACTIVE_LOW>;
                        linux,code = <2>;
                };
 
-               fan2-presence {
+               event-fan2-presence {
                        label = "fan2-presence";
                        gpios = <&pca1 2 GPIO_ACTIVE_LOW>;
                        linux,code = <3>;
                };
 
-               fan3-presence {
+               event-fan3-presence {
                        label = "fan3-presence";
                        gpios = <&pca1 3 GPIO_ACTIVE_LOW>;
                        linux,code = <4>;
                };
 
-               fan4-presence {
+               event-fan4-presence {
                        label = "fan4-presence";
                        gpios = <&pca1 4 GPIO_ACTIVE_LOW>;
                        linux,code = <5>;
                };
 
-               fan5-presence {
+               event-fan5-presence {
                        label = "fan5-presence";
                        gpios = <&pca1 5 GPIO_ACTIVE_LOW>;
                        linux,code = <6>;
                };
 
-               fan6-presence {
+               event-fan6-presence {
                        label = "fan6-presence";
                        gpios = <&pca1 6 GPIO_ACTIVE_LOW>;
                        linux,code = <7>;
                };
 
-               fan7-presence {
+               event-fan7-presence {
                        label = "fan7-presence";
                        gpios = <&pca1 7 GPIO_ACTIVE_LOW>;
                        linux,code = <8>;
index a52a289..48776fb 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               air-water {
+               event-air-water {
                        label = "air-water";
                        gpios = <&gpio ASPEED_GPIO(F, 6) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(F, 6)>;
                };
 
-               checkstop {
+               event-checkstop {
                        label = "checkstop";
                        gpios = <&gpio ASPEED_GPIO(J, 2) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(J, 2)>;
                };
 
-               ps0-presence {
+               event-ps0-presence {
                        label = "ps0-presence";
                        gpios = <&gpio ASPEED_GPIO(Z, 2) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(Z, 2)>;
                };
 
-               ps1-presence {
+               event-ps1-presence {
                        label = "ps1-presence";
                        gpios = <&gpio ASPEED_GPIO(Z, 0) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(Z, 0)>;
                };
-               id-button {
+
+               button-id {
                        label = "id-button";
                        gpios = <&gpio ASPEED_GPIO(F, 1) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(F, 1)>;
                compatible = "gpio-keys-polled";
                poll-interval = <1000>;
 
-               fan0-presence {
+               event-fan0-presence {
                        label = "fan0-presence";
                        gpios = <&pca9552 9 GPIO_ACTIVE_LOW>;
                        linux,code = <9>;
                };
 
-               fan1-presence {
+               event-fan1-presence {
                        label = "fan1-presence";
                        gpios = <&pca9552 10 GPIO_ACTIVE_LOW>;
                        linux,code = <10>;
                };
 
-               fan2-presence {
+               event-fan2-presence {
                        label = "fan2-presence";
                        gpios = <&pca9552 11 GPIO_ACTIVE_LOW>;
                        linux,code = <11>;
                };
 
-               fan3-presence {
+               event-fan3-presence {
                        label = "fan3-presence";
                        gpios = <&pca9552 12 GPIO_ACTIVE_LOW>;
                        linux,code = <12>;
                };
 
-               fan4-presence {
+               event-fan4-presence {
                        label = "fan4-presence";
                        gpios = <&pca9552 13 GPIO_ACTIVE_LOW>;
                        linux,code = <13>;
                };
 
-               fan5-presence {
+               event-fan5-presence {
                        label = "fan5-presence";
                        gpios = <&pca9552 14 GPIO_ACTIVE_LOW>;
                        linux,code = <14>;
index 7d38d12..31ff19e 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               air-water {
+               event-air-water {
                        label = "air-water";
                        gpios = <&gpio ASPEED_GPIO(F, 6) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(F, 6)>;
                };
 
-               checkstop {
+               event-checkstop {
                        label = "checkstop";
                        gpios = <&gpio ASPEED_GPIO(J, 2) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(J, 2)>;
                };
 
-               ps0-presence {
+               event-ps0-presence {
                        label = "ps0-presence";
                        gpios = <&gpio ASPEED_GPIO(Z, 2) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(Z, 2)>;
                };
 
-               ps1-presence {
+               event-ps1-presence {
                        label = "ps1-presence";
                        gpios = <&gpio ASPEED_GPIO(Z, 0) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(Z, 0)>;
                };
 
-               id-button {
+               button-id {
                        label = "id-button";
                        gpios = <&gpio ASPEED_GPIO(F, 1) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(F, 1)>;
                compatible = "gpio-keys-polled";
                poll-interval = <1000>;
 
-               fan0-presence {
+               event-fan0-presence {
                        label = "fan0-presence";
                        gpios = <&pca9552 9 GPIO_ACTIVE_LOW>;
                        linux,code = <9>;
                };
 
-               fan1-presence {
+               event-fan1-presence {
                        label = "fan1-presence";
                        gpios = <&pca9552 10 GPIO_ACTIVE_LOW>;
                        linux,code = <10>;
                };
 
-               fan2-presence {
+               event-fan2-presence {
                        label = "fan2-presence";
                        gpios = <&pca9552 11 GPIO_ACTIVE_LOW>;
                        linux,code = <11>;
                };
 
-               fan3-presence {
+               event-fan3-presence {
                        label = "fan3-presence";
                        gpios = <&pca9552 12 GPIO_ACTIVE_LOW>;
                        linux,code = <12>;
                };
 
-               fan4-presence {
+               event-fan4-presence {
                        label = "fan4-presence";
                        gpios = <&pca9552 13 GPIO_ACTIVE_LOW>;
                        linux,code = <13>;
index 3d4bdad..ac0d666 100644 (file)
@@ -96,7 +96,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               checkstop {
+               event-checkstop {
                        label = "checkstop";
                        gpios = <&gpio ASPEED_GPIO(J, 2) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(J, 2)>;
index cd660c1..45631b4 100644 (file)
@@ -73,7 +73,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               checkstop {
+               event-checkstop {
                        label = "checkstop";
                        gpios = <&gpio ASPEED_GPIO(P, 5) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(P, 5)>;
index 084f548..893e621 100644 (file)
@@ -87,7 +87,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               checkstop {
+               event-checkstop {
                        label = "checkstop";
                        gpios = <&gpio ASPEED_GPIO(J, 2) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(J, 2)>;
index 4816486..bbf864f 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               air-water {
+               event-air-water {
                        label = "air-water";
                        gpios = <&gpio ASPEED_GPIO(B, 5) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(B, 5)>;
                };
 
-               checkstop {
+               event-checkstop {
                        label = "checkstop";
                        gpios = <&gpio ASPEED_GPIO(J, 2) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(J, 2)>;
                };
 
-               ps0-presence {
+               event-ps0-presence {
                        label = "ps0-presence";
                        gpios = <&gpio ASPEED_GPIO(R, 7) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(R, 7)>;
                };
 
-               ps1-presence {
+               event-ps1-presence {
                        label = "ps1-presence";
                        gpios = <&gpio ASPEED_GPIO(N, 0) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(N, 0)>;
                };
 
-               oppanel-presence {
+               event-oppanel-presence {
                        label = "oppanel-presence";
                        gpios = <&gpio ASPEED_GPIO(A, 7) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(A, 7)>;
                };
 
-               opencapi-riser-presence {
+               event-opencapi-riser-presence {
                        label = "opencapi-riser-presence";
                        gpios = <&gpio ASPEED_GPIO(I, 0) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(I, 0)>;
                compatible = "gpio-keys-polled";
                poll-interval = <1000>;
 
-               scm0-presence {
+               event-scm0-presence {
                        label = "scm0-presence";
                        gpios = <&pca9552 6 GPIO_ACTIVE_LOW>;
                        linux,code = <6>;
                };
 
-               scm1-presence {
+               event-scm1-presence {
                        label = "scm1-presence";
                        gpios = <&pca9552 7 GPIO_ACTIVE_LOW>;
                        linux,code = <7>;
                };
 
-               cpu0vrm-presence {
+               event-cpu0vrm-presence {
                        label = "cpu0vrm-presence";
                        gpios = <&pca9552 12 GPIO_ACTIVE_LOW>;
                        linux,code = <12>;
                };
 
-               cpu1vrm-presence {
+               event-cpu1vrm-presence {
                        label = "cpu1vrm-presence";
                        gpios = <&pca9552 13 GPIO_ACTIVE_LOW>;
                        linux,code = <13>;
                };
 
-               fan0-presence {
+               event-fan0-presence {
                        label = "fan0-presence";
                        gpios = <&pca0 5 GPIO_ACTIVE_LOW>;
                        linux,code = <5>;
                };
 
-               fan1-presence {
+               event-fan1-presence {
                        label = "fan1-presence";
                        gpios = <&pca0 6 GPIO_ACTIVE_LOW>;
                        linux,code = <6>;
                };
 
-               fan2-presence {
+               event-fan2-presence {
                        label = "fan2-presence";
                        gpios = <&pca0 7 GPIO_ACTIVE_LOW>;
                        linux,code = <7>;
                };
 
-               fan3-presence {
+               event-fan3-presence {
                        label = "fan3-presence";
                        gpios = <&pca0 8 GPIO_ACTIVE_LOW>;
                        linux,code = <8>;
                };
 
-               fanboost-presence {
+               event-fanboost-presence {
                        label = "fanboost-presence";
                        gpios = <&pca0 9 GPIO_ACTIVE_LOW>;
                        linux,code = <9>;
index 72b7a66..3f6010e 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               ps0-presence {
+               event-ps0-presence {
                        label = "ps0-presence";
                        gpios = <&gpio0 ASPEED_GPIO(H, 3) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(H, 3)>;
                };
 
-               ps1-presence {
+               event-ps1-presence {
                        label = "ps1-presence";
                        gpios = <&gpio0 ASPEED_GPIO(E, 5) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(E, 5)>;
 
        gpio-keys-polled {
                compatible = "gpio-keys-polled";
-               #address-cells = <1>;
-               #size-cells = <0>;
                poll-interval = <1000>;
 
-               fan0-presence {
+               event-fan0-presence {
                        label = "fan0-presence";
                        gpios = <&pca0 4 GPIO_ACTIVE_LOW>;
                        linux,code = <4>;
                };
 
-               fan1-presence {
+               event-fan1-presence {
                        label = "fan1-presence";
                        gpios = <&pca0 5 GPIO_ACTIVE_LOW>;
                        linux,code = <5>;
                };
 
-               fan2-presence {
+               event-fan2-presence {
                        label = "fan2-presence";
                        gpios = <&pca0 6 GPIO_ACTIVE_LOW>;
                        linux,code = <6>;
                };
 
-               fan3-presence {
+               event-fan3-presence {
                        label = "fan3-presence";
                        gpios = <&pca0 7 GPIO_ACTIVE_LOW>;
                        linux,code = <7>;
index 328ef47..8a7fb55 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               button_checkstop {
+               event-checkstop {
                        label = "checkstop";
                        linux,code = <74>;
                        gpios = <&gpio ASPEED_GPIO(P, 5) GPIO_ACTIVE_LOW>;
                };
 
-               button_identify {
+               event-identify {
                        label = "identify";
                        linux,code = <152>;
                        gpios = <&gpio ASPEED_GPIO(O, 7) GPIO_ACTIVE_LOW>;
index 230f358..a20a532 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               air-water {
+               event-air-water {
                        label = "air-water";
                        gpios = <&gpio ASPEED_GPIO(B, 5) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(B, 5)>;
                };
 
-               checkstop {
+               event-checkstop {
                        label = "checkstop";
                        gpios = <&gpio ASPEED_GPIO(J, 2) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(J, 2)>;
                };
 
-               ps0-presence {
+               event-ps0-presence {
                        label = "ps0-presence";
                        gpios = <&gpio ASPEED_GPIO(P, 7) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(P, 7)>;
                };
 
-               ps1-presence {
+               event-ps1-presence {
                        label = "ps1-presence";
                        gpios = <&gpio ASPEED_GPIO(N, 0) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(N, 0)>;
                compatible = "gpio-keys-polled";
                poll-interval = <1000>;
 
-               fan0-presence {
+               event-fan0-presence {
                        label = "fan0-presence";
                        gpios = <&pca0 4 GPIO_ACTIVE_LOW>;
                        linux,code = <4>;
                };
 
-               fan1-presence {
+               event-fan1-presence {
                        label = "fan1-presence";
                        gpios = <&pca0 5 GPIO_ACTIVE_LOW>;
                        linux,code = <5>;
                };
 
-               fan2-presence {
+               event-fan2-presence {
                        label = "fan2-presence";
                        gpios = <&pca0 6 GPIO_ACTIVE_LOW>;
                        linux,code = <6>;
                };
 
-               fan3-presence {
+               event-fan3-presence {
                        label = "fan3-presence";
                        gpios = <&pca0 7 GPIO_ACTIVE_LOW>;
                        linux,code = <7>;
index 7ae4ea0..0cb7b20 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               checkstop {
+               event-checkstop {
                        label = "checkstop";
                        gpios = <&gpio ASPEED_GPIO(F, 7) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(F, 7)>;
                };
 
-               pcie-e2b-present{
+               event-pcie-e2b-present{
                        label = "pcie-e2b-present";
                        gpios = <&gpio ASPEED_GPIO(E, 7) GPIO_ACTIVE_LOW>;
                        linux,code = <ASPEED_GPIO(E, 7)>;
index 61bc74b..a5e64cc 100644 (file)
        leds {
                compatible = "gpio-leds";
                postcode0 {
-                       label="BMC_UP";
+                       label = "BMC_UP";
                        gpios = <&gpio ASPEED_GPIO(H, 0) GPIO_ACTIVE_HIGH>;
                        default-state = "on";
                };
                postcode1 {
-                       label="BMC_HB";
+                       label = "BMC_HB";
                        gpios = <&gpio ASPEED_GPIO(H, 1) GPIO_ACTIVE_HIGH>;
                        linux,default-trigger = "heartbeat";
                };
                postcode2 {
-                       label="FAULT";
+                       label = "FAULT";
                        gpios = <&gpio ASPEED_GPIO(H, 2) GPIO_ACTIVE_HIGH>;
                };
                // postcode3-7 are GPIOH3-H7
@@ -6,8 +6,8 @@
 #include "aspeed-g6.dtsi"
 
 / {
-       model = "Nuvia DC-SCM BMC";
-       compatible = "nuvia,dc-scm-bmc", "aspeed,ast2600";
+       model = "Qualcomm DC-SCM V1 BMC";
+       compatible = "qcom,dc-scm-v1-bmc", "aspeed,ast2600";
 
        aliases {
                serial4 = &uart5;
index 69e1bd2..46cbba6 100644 (file)
                compatible = "gpio-leds";
 
                BMC_HEARTBEAT_N {
-                       label="BMC_HEARTBEAT_N";
+                       label = "BMC_HEARTBEAT_N";
                        gpios = <&gpio0 ASPEED_GPIO(P, 7) GPIO_ACTIVE_LOW>;
                        linux,default-trigger = "heartbeat";
                };
 
                BMC_LED_STATUS_AMBER_N {
-                       label="BMC_LED_STATUS_AMBER_N";
+                       label = "BMC_LED_STATUS_AMBER_N";
                        gpios = <&gpio0 ASPEED_GPIO(S, 6) GPIO_ACTIVE_LOW>;
                        default-state = "off";
                };
 
                FM_ID_LED_N {
-                       label="FM_ID_LED_N";
+                       label = "FM_ID_LED_N";
                        gpios = <&gpio0 ASPEED_GPIO(B, 5) GPIO_ACTIVE_LOW>;
                        default-state = "off";
                };
index 7edf057..9dfd5de 100644 (file)
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               btn {
+               button {
                        label = "Button";
                        gpios = <&pioC 4 GPIO_ACTIVE_LOW>;
                        linux,code = <0x103>;
index 5a81cab..2c718cf 100644 (file)
@@ -13,7 +13,7 @@
        model = "Laird Workgroup Bridge 50N - Project Gatwick";
        compatible = "laird,gatwick", "laird,wb50n", "atmel,sama5d31", "atmel,sama5d3", "atmel,sama5";
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
                autorepeat;
 
index 3b8812f..307663b 100644 (file)
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
-               reset {
+               button-reset {
                        label = "PB_RST";
                        gpios = <&pioB 30 GPIO_ACTIVE_HIGH>;
                        linux,code = <0x100>;
                        wakeup-source;
                };
 
-               user {
+               button-user {
                        label = "PB_USER";
                        gpios = <&pioB 31 GPIO_ACTIVE_HIGH>;
                        linux,code = <0x101>;
index c08834d..e5e21df 100644 (file)
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
-               prog {
+               button-prog {
                        label = "PB_PROG";
                        gpios = <&pioE 27 GPIO_ACTIVE_LOW>;
                        linux,code = <0x102>;
                        wakeup-source;
                };
 
-               reset {
+               button-reset {
                        label = "PB_RST";
                        gpios = <&pioE 29 GPIO_ACTIVE_LOW>;
                        linux,code = <0x100>;
                        wakeup-source;
                };
 
-               user {
+               button-user {
                        label = "PB_USER";
                        gpios = <&pioE 31 GPIO_ACTIVE_HIGH>;
                        linux,code = <0x101>;
index 2799b2a..7075df6 100644 (file)
@@ -55,7 +55,7 @@
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
                pinctrl-names = "default" , "default", "default",
                                "default", "default" ;
                             &pinctrl_pio_zbe_rst>;
                pinctrl-4 = <&pinctrl_pio_input>;
 
-               SW1 {
+               switch-1 {
                        label = "SW1";
                        gpios = <&pioA PIN_PA29 GPIO_ACTIVE_LOW>;
                        linux,code = <0x101>;
                        wakeup-source;
                };
 
-               SW2 {
+               switch-2 {
                        label = "SW2";
                        gpios = <&pioA PIN_PA18 GPIO_ACTIVE_LOW>;
                        linux,code = <0x102>;
                        wakeup-source;
                };
 
-               SW3 {
+               switch-3 {
                        label = "SW3";
                        gpios = <&pioA PIN_PA22 GPIO_ACTIVE_LOW>;
                        linux,code = <0x103>;
                        wakeup-source;
                };
 
-               SW7 {
+               switch-7 {
                        label = "SW7";
                        gpios = <&pioA PIN_PA26 GPIO_ACTIVE_LOW>;
                        linux,code = <0x107>;
                        wakeup-source;
                };
 
-               SW8 {
+               switch-8 {
                        label = "SW8";
                        gpios = <&pioA PIN_PA24 GPIO_ACTIVE_LOW>;
                        linux,code = <0x108>;
 
 &pioA {
        pinctrl_key_gpio_default: key_gpio_default {
-               pinmux <PIN_PA22__GPIO>,
+               pinmux = <PIN_PA22__GPIO>,
                <PIN_PA24__GPIO>,
                <PIN_PA26__GPIO>,
                <PIN_PA29__GPIO>,
index 9c62289..42640fe 100644 (file)
 
        gpio_keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
-               prog {
+               key-prog {
                        label = "PB_PROG";
                        gpios = <&pioC 17 GPIO_ACTIVE_LOW>;
                        linux,code = <0x102>;
                        wakeup-source;
                };
 
-               reset {
+               key-reset {
                        label = "PB_RST";
                        gpios = <&pioC 16 GPIO_ACTIVE_LOW>;
                        linux,code = <0x100>;
index 4f12347..f71377c 100644 (file)
@@ -18,7 +18,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               wakeup {
+               key-wakeup {
                        label = "Wakeup";
                        linux,code = <10>;
                        wakeup-source;
index 969d990..9d26f99 100644 (file)
 
        gpio_keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
-               user_pb {
+               button-user {
                        label = "user_pb";
                        gpios = <&pioB 10 GPIO_ACTIVE_LOW>;
                        linux,code = <28>;
index 7719ea3..81c38e1 100644 (file)
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_key_gpio_default>;
-               status = "okay";
 
-               sw1 {
+               button-1 {
                        label = "SW1";
                        gpios = <&pioD 18 GPIO_ACTIVE_LOW>;
-                       linux,code=<KEY_PROG1>;
+                       linux,code = <KEY_PROG1>;
                        wakeup-source;
                };
        };
                status = "okay";
 
                eeprom@53 {
-                       compatible = "atmel,24c32";
+                       compatible = "atmel,24c02";
                        reg = <0x53>;
                        pagesize = <16>;
-                       size = <128>;
                        status = "okay";
                };
        };
index a4623cc..8aa9e8d 100644 (file)
@@ -15,7 +15,7 @@
        compatible = "atmel,sama5d27-som1", "atmel,sama5d27", "atmel,sama5d2", "atmel,sama5";
 
        aliases {
-               i2c0    = &i2c0;
+               i2c0 = &i2c0;
        };
 
        clocks {
@@ -83,6 +83,8 @@
                        macb0: ethernet@f8008000 {
                                pinctrl-names = "default";
                                pinctrl-0 = <&pinctrl_macb0_default>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
                                phy-mode = "rmii";
 
                                ethernet-phy@7 {
index 08f0d4b..0dc6ca3 100644 (file)
@@ -21,8 +21,8 @@
                serial0 = &uart1;       /* DBGU */
                serial1 = &uart4;       /* mikro BUS 1 */
                serial2 = &uart2;       /* mikro BUS 2 */
-               i2c1    = &i2c1;
-               i2c2    = &i2c3;
+               i2c1 = &i2c1;
+               i2c2 = &i2c3;
        };
 
        chosen {
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_key_gpio_default>;
 
-               pb4 {
+               button {
                        label = "USER";
                        gpios = <&pioA PIN_PA29 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_PROG1>;
index ba62178..76b2025 100644 (file)
 &macb0 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_macb0_default>;
+       #address-cells = <1>;
+       #size-cells = <0>;
        phy-mode = "rmii";
 
        ethernet-phy@0 {
index 5e8755f..b665ddc 100644 (file)
                serial1 = &uart6;       /* BT */
                serial2 = &uart5;       /* mikro BUS 2 */
                serial3 = &uart3;       /* mikro BUS 1 */
-               i2c1    = &i2c1;
+               i2c1 = &i2c1;
        };
 
        chosen {
                stdout-path = "serial0:115200n8";
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_key_gpio_default>;
-               status = "okay";
 
-               sw4 {
+               button-1 {
                        label = "USER BUTTON";
                        gpios = <&pioA PIN_PB2 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_PROG1>;
index 806eb1d..6865be8 100644 (file)
@@ -24,8 +24,8 @@
                serial1 = &uart1;       /* mikro BUS 3 */
                serial3 = &uart3;       /* mikro BUS 2 */
                serial5 = &uart7;       /* flx2 */
-               i2c0    = &i2c0;
-               i2c1    = &i2c1;
+               i2c0 = &i2c0;
+               i2c1 = &i2c1;
        };
 
        chosen {
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_key_gpio_default>;
-               status = "okay";
 
-               sw4 {
+               button-1 {
                        label = "USER_PB1";
                        gpios = <&pioA PIN_PD0 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_PROG1>;
        status = "okay";
 
        eeprom@50 {
-               compatible = "atmel,24c32";
+               compatible = "atmel,24c02";
                reg = <0x50>;
                pagesize = <16>;
                status = "okay";
        };
 
        eeprom@52 {
-               compatible = "atmel,24c32";
+               compatible = "atmel,24c02";
                reg = <0x52>;
                pagesize = <16>;
                status = "disabled";
        };
 
        eeprom@53 {
-               compatible = "atmel,24c32";
+               compatible = "atmel,24c02";
                reg = <0x53>;
                pagesize = <16>;
                status = "disabled";
index 8ed58af..76a711b 100644 (file)
@@ -20,9 +20,9 @@
 
        aliases {
                serial0 = &uart0;       /* DBGU */
-               i2c0    = &i2c0;        /* mikroBUS 1 */
-               i2c1    = &i2c1;        /* XPRO EXT1 */
-               i2c2    = &i2c2;
+               i2c0 = &i2c0;   /* mikroBUS 1 */
+               i2c1 = &i2c1;   /* XPRO EXT1 */
+               i2c2 = &i2c2;
        };
 
        chosen {
                        macb0: ethernet@f8008000 {
                                pinctrl-names = "default";
                                pinctrl-0 = <&pinctrl_macb0_default &pinctrl_macb0_phy_irq>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
                                phy-mode = "rmii";
                                status = "okay";
 
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_key_gpio_default>;
 
-               bp1 {
+               button-1 {
                        label = "PB_USER";
                        gpios = <&pioA PIN_PA10 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_PROG1>;
index cdfe891..85949c2 100644 (file)
                        macb0: ethernet@f8008000 {
                                pinctrl-names = "default";
                                pinctrl-0 = <&pinctrl_macb0_default &pinctrl_macb0_phy_irq>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
                                phy-mode = "rmii";
                                status = "okay";
 
 
                                                        regulator-state-mem {
                                                                regulator-on-in-suspend;
-                                                               regulator-suspend-min-microvolt=<1400000>;
-                                                               regulator-suspend-max-microvolt=<1400000>;
+                                                               regulator-suspend-min-microvolt = <1400000>;
+                                                               regulator-suspend-max-microvolt = <1400000>;
                                                                regulator-changeable-in-suspend;
-                                                               regulator-mode=<ACT8945A_REGULATOR_MODE_LOWPOWER>;
+                                                               regulator-mode = <ACT8945A_REGULATOR_MODE_LOWPOWER>;
                                                        };
                                                };
 
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_key_gpio_default>;
 
-               bp1 {
+               button {
                        label = "PB_USER";
                        gpios = <&pioA PIN_PB9 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_PROG1>;
index a49c296..1f42a6a 100644 (file)
                regulator-always-on;
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_key_gpio>;
 
-               bp3 {
+               button {
                        label = "PB_USER";
                        gpios = <&pioE 29 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_PROG1>;
index e519d27..f122f30 100644 (file)
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_key_gpio>;
 
-               pb_user1 {
+               button {
                        label = "pb_user1";
                        gpios = <&pioE 8 GPIO_ACTIVE_HIGH>;
                        linux,code = <KEY_PROG1>;
index 7017f62..fce4e93 100644 (file)
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_key_gpio>;
 
-               pb_user1 {
+               button {
                        label = "pb_user1";
                        gpios = <&pioE 13 GPIO_ACTIVE_HIGH>;
                        linux,code = <0x100>;
index 1035446..de44da2 100644 (file)
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_key_gpio_default>;
 
-               bp1 {
+               button {
                        label = "PB_USER";
                        gpios = <&pioA PIN_PA12 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_PROG1>;
index 54d130c..ef73f72 100644 (file)
        model = "Laird Workgroup Bridge 45N - Atmel AT91SAM (dt)";
        compatible = "laird,wb45n", "laird,wbxx", "atmel,at91sam9x5", "atmel,at91sam9";
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
-               irqbtn@18 {
-                       reg = <18>;
+               button {
                        label = "IRQBTN";
                        linux,code = <99>;
                        gpios = <&pioB 18 GPIO_ACTIVE_LOW>;
index 89f0f71..ec2becf 100644 (file)
        model = "Laird Workgroup Bridge 50N - Atmel SAMA5D";
        compatible = "laird,wb50n", "atmel,sama5d31", "atmel,sama5d3", "atmel,sama5";
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
-               btn0@10 {
-                       reg = <10>;
+               button-0 {
                        label = "BTNESC";
                        linux,code = <1>; /* ESC button */
                        gpios = <&pioA 10 GPIO_ACTIVE_LOW>;
                        wakeup-source;
                };
 
-               irqbtn@31 {
-                       reg = <31>;
+               button-1 {
                        label = "IRQBTN";
                        linux,code = <99>; /* SysReq button */
                        gpios = <&pioE 31 GPIO_ACTIVE_LOW>;
index 7368347..9d9820d 100644 (file)
                                clock-names = "slow_xtal", "main_xtal";
                        };
 
-                       rstc@fffffd00 {
+                       reset-controller@fffffd00 {
                                compatible = "atmel,at91sam9260-rstc";
                                reg = <0xfffffd00 0x10>;
                                clocks = <&pmc PMC_TYPE_CORE PMC_SLOW>;
index 6381088..bb72f05 100644 (file)
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               btn3 {
+               button-3 {
                        label = "Button 3";
                        gpios = <&pioA 30 GPIO_ACTIVE_LOW>;
                        linux,code = <0x103>;
                        wakeup-source;
                };
 
-               btn4 {
+               button-4 {
                        label = "Button 4";
                        gpios = <&pioA 31 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_PROG1>;
index 7adc36c..259aca5 100644 (file)
                                clock-names = "slow_xtal", "main_xtal";
                        };
 
-                       rstc@fffffd00 {
+                       reset-controller@fffffd00 {
                                compatible = "atmel,at91sam9260-rstc";
                                reg = <0xfffffd00 0x10>;
                                clocks = <&slow_xtal>;
index 6fb4fe4..88869ca 100644 (file)
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               button_0 {
+               button-0 {
                        label = "button_0";
                        gpios = <&pioA 27 GPIO_ACTIVE_LOW>;
                        linux,code = <256>;
                        wakeup-source;
                };
 
-               button_1 {
+               button-1 {
                        label = "button_1";
                        gpios = <&pioA 26 GPIO_ACTIVE_LOW>;
                        linux,code = <257>;
                        wakeup-source;
                };
 
-               button_2 {
+               button-2 {
                        label = "button_2";
                        gpios = <&pioA 25 GPIO_ACTIVE_LOW>;
                        linux,code = <258>;
                        wakeup-source;
                };
 
-               button_3 {
+               button-3 {
                        label = "button_3";
                        gpios = <&pioA 24 GPIO_ACTIVE_LOW>;
                        linux,code = <259>;
index fe45d96..c080df8 100644 (file)
                                clock-names = "t0_clk", "slow_clk";
                        };
 
-                       rstc@fffffd00 {
+                       reset-controller@fffffd00 {
                                compatible = "atmel,at91sam9260-rstc";
                                reg = <0xfffffd00 0x10>;
                                clocks = <&slow_xtal>;
index e732565..ce8baff 100644 (file)
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               left_click {
+               button-left-click {
                        label = "left_click";
                        gpios = <&pioC 5 GPIO_ACTIVE_LOW>;
                        linux,code = <272>;
                        wakeup-source;
                };
 
-               right_click {
+               button-right-click {
                        label = "right_click";
                        gpios = <&pioC 4 GPIO_ACTIVE_LOW>;
                        linux,code = <273>;
index 85c17dd..60d6129 100644 (file)
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               btn3 {
+               button-3 {
                        label = "Button 3";
                        gpios = <&pioA 30 GPIO_ACTIVE_LOW>;
                        linux,code = <0x103>;
                        wakeup-source;
                };
 
-               btn4 {
+               button-4 {
                        label = "Button 4";
                        gpios = <&pioA 31 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_PROG1>;
index 7da70ae..92f2c05 100644 (file)
@@ -23,7 +23,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               user_btn1 {
+               button {
                        label = "USER_BTN1";
                        gpios = <&pioA 24 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_PROG1>;
index 2ab730f..0979456 100644 (file)
                                clock-names = "slow_clk", "main_xtal";
                        };
 
-                       rstc@fffffd00 {
+                       reset-controller@fffffd00 {
                                compatible = "atmel,at91sam9g45-rstc";
                                reg = <0xfffffd00 0x10>;
                                clocks = <&clk32k>;
index e5db198..7f45e81 100644 (file)
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               left_click {
+               button-left-click {
                        label = "left_click";
                        gpios = <&pioB 6 GPIO_ACTIVE_LOW>;
                        linux,code = <272>;
                        wakeup-source;
                };
 
-               right_click {
+               button-right-click {
                        label = "right_click";
                        gpios = <&pioB 7 GPIO_ACTIVE_LOW>;
                        linux,code = <273>;
                        wakeup-source;
                };
 
-               left {
+               button-left {
                        label = "Joystick Left";
                        gpios = <&pioB 14 GPIO_ACTIVE_LOW>;
                        linux,code = <105>;
                };
 
-               right {
+               button-right {
                        label = "Joystick Right";
                        gpios = <&pioB 15 GPIO_ACTIVE_LOW>;
                        linux,code = <106>;
                };
 
-               up {
+               button-up {
                        label = "Joystick Up";
                        gpios = <&pioB 16 GPIO_ACTIVE_LOW>;
                        linux,code = <103>;
                };
 
-               down {
+               button-down {
                        label = "Joystick Down";
                        gpios = <&pioB 17 GPIO_ACTIVE_LOW>;
                        linux,code = <108>;
                };
 
-               enter {
+               button-enter {
                        label = "Joystick Press";
                        gpios = <&pioB 18 GPIO_ACTIVE_LOW>;
                        linux,code = <28>;
index 0785389..556f35c 100644 (file)
                                interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
                        };
 
-                       rstc@fffffe00 {
+                       reset-controller@fffffe00 {
                                compatible = "atmel,at91sam9g45-rstc";
                                reg = <0xfffffe00 0x10>;
                                clocks = <&clk32k>;
index c905d7b..4c644d4 100644 (file)
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               enter {
+               button-enter {
                        label = "Enter";
                        gpios = <&pioB 3 GPIO_ACTIVE_LOW>;
                        linux,code = <28>;
index 730d118..12c6348 100644 (file)
                                clock-names = "slow_clk", "main_xtal";
                        };
 
-                       rstc@fffffd00 {
+                       reset-controller@fffffd00 {
                                compatible = "atmel,at91sam9260-rstc";
                                reg = <0xfffffd00 0x10>;
                                clocks = <&clk32k>;
index ddaadfe..a573512 100644 (file)
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               right_click {
+               button-right-click {
                        label = "right_click";
                        gpios = <&pioB 0 GPIO_ACTIVE_LOW>;
                        linux,code = <273>;
                        wakeup-source;
                };
 
-               left_click {
+               button-left-click {
                        label = "left_click";
                        gpios = <&pioB 1 GPIO_ACTIVE_LOW>;
                        linux,code = <272>;
index 395e883..ea3b113 100644 (file)
                                clock-names = "slow_clk", "main_xtal";
                        };
 
-                       reset_controller: rstc@fffffe00 {
+                       reset_controller: reset-controller@fffffe00 {
                                compatible = "atmel,at91sam9g45-rstc";
                                reg = <0xfffffe00 0x10>;
                                clocks = <&clk32k>;
index 3bcf4e0..f13ef80 100644 (file)
@@ -73,7 +73,7 @@
                        device_type = "cpu";
                        compatible = "arm,cortex-a15";
                        reg = <0x00>;
-                       clock-frequency= <1400000000>;
+                       clock-frequency = <1400000000>;
                        cpu-release-addr = <0>; // Fixed by the boot loader
                };
 
@@ -81,7 +81,7 @@
                        device_type = "cpu";
                        compatible = "arm,cortex-a15";
                        reg = <0x01>;
-                       clock-frequency= <1400000000>;
+                       clock-frequency = <1400000000>;
                        cpu-release-addr = <0>; // Fixed by the boot loader
                };
 
@@ -89,7 +89,7 @@
                        device_type = "cpu";
                        compatible = "arm,cortex-a15";
                        reg = <0x02>;
-                       clock-frequency= <1400000000>;
+                       clock-frequency = <1400000000>;
                        cpu-release-addr = <0>; // Fixed by the boot loader
                };
 
@@ -97,7 +97,7 @@
                        device_type = "cpu";
                        compatible = "arm,cortex-a15";
                        reg = <0x03>;
-                       clock-frequency= <1400000000>;
+                       clock-frequency = <1400000000>;
                        cpu-release-addr = <0>; // Fixed by the boot loader
                };
 
                        device_type = "cpu";
                        compatible = "arm,cortex-a15";
                        reg = <0x100>;
-                       clock-frequency= <1400000000>;
+                       clock-frequency = <1400000000>;
                        cpu-release-addr = <0>; // Fixed by the boot loader
                };
 
                        device_type = "cpu";
                        compatible = "arm,cortex-a15";
                        reg = <0x101>;
-                       clock-frequency= <1400000000>;
+                       clock-frequency = <1400000000>;
                        cpu-release-addr = <0>; // Fixed by the boot loader
                };
 
                        device_type = "cpu";
                        compatible = "arm,cortex-a15";
                        reg = <0x102>;
-                       clock-frequency= <1400000000>;
+                       clock-frequency = <1400000000>;
                        cpu-release-addr = <0>; // Fixed by the boot loader
                };
 
                        device_type = "cpu";
                        compatible = "arm,cortex-a15";
                        reg = <0x103>;
-                       clock-frequency= <1400000000>;
+                       clock-frequency = <1400000000>;
                        cpu-release-addr = <0>; // Fixed by the boot loader
                };
 
                        device_type = "cpu";
                        compatible = "arm,cortex-a15";
                        reg = <0x200>;
-                       clock-frequency= <1400000000>;
+                       clock-frequency = <1400000000>;
                        cpu-release-addr = <0>; // Fixed by the boot loader
                };
 
                        device_type = "cpu";
                        compatible = "arm,cortex-a15";
                        reg = <0x201>;
-                       clock-frequency= <1400000000>;
+                       clock-frequency = <1400000000>;
                        cpu-release-addr = <0>; // Fixed by the boot loader
                };
 
                        device_type = "cpu";
                        compatible = "arm,cortex-a15";
                        reg = <0x202>;
-                       clock-frequency= <1400000000>;
+                       clock-frequency = <1400000000>;
                        cpu-release-addr = <0>; // Fixed by the boot loader
                };
 
                        device_type = "cpu";
                        compatible = "arm,cortex-a15";
                        reg = <0x203>;
-                       clock-frequency= <1400000000>;
+                       clock-frequency = <1400000000>;
                        cpu-release-addr = <0>; // Fixed by the boot loader
                };
 
                        device_type = "cpu";
                        compatible = "arm,cortex-a15";
                        reg = <0x300>;
-                       clock-frequency= <1400000000>;
+                       clock-frequency = <1400000000>;
                        cpu-release-addr = <0>; // Fixed by the boot loader
                };
 
                        device_type = "cpu";
                        compatible = "arm,cortex-a15";
                        reg = <0x301>;
-                       clock-frequency= <1400000000>;
+                       clock-frequency = <1400000000>;
                        cpu-release-addr = <0>; // Fixed by the boot loader
                };
 
                        device_type = "cpu";
                        compatible = "arm,cortex-a15";
                        reg = <0x302>;
-                       clock-frequency= <1400000000>;
+                       clock-frequency = <1400000000>;
                        cpu-release-addr = <0>; // Fixed by the boot loader
                };
 
                        device_type = "cpu";
                        compatible = "arm,cortex-a15";
                        reg = <0x303>;
-                       clock-frequency= <1400000000>;
+                       clock-frequency = <1400000000>;
                        cpu-release-addr = <0>; // Fixed by the boot loader
                };
        };
index f4d2fc2..c53d9eb 100644 (file)
 &expgpio {
        gpio-line-names = "BT_ON",
                          "WL_ON",
-                         "",
+                         "PWR_LED_OFF",
                          "GLOBAL_RESET",
                          "VDD_SD_IO_SEL",
-                         "CAM_GPIO",
+                         "GLOBAL_SHUTDOWN",
                          "SD_PWR_ON",
-                         "SD_OC_N";
+                         "SHUTDOWN_REQUEST";
 };
 
 &genet_mdio {
index ca266c5..98817a6 100644 (file)
        };
 };
 
+&v3d {
+       clocks = <&firmware_clocks 5>;
+};
+
 &vchiq {
        interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
 };
index 89af574..941c4d1 100644 (file)
                };
 
                pm: watchdog@7e100000 {
-                       compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt";
+                       compatible = "brcm,bcm2711-pm", "brcm,bcm2835-pm-wdt";
                        #power-domain-cells = <1>;
                        #reset-cells = <1>;
                        reg = <0x7e100000 0x114>,
                              <0x7e00a000 0x24>,
                              <0x7ec11000 0x20>;
+                       reg-names = "pm", "asb", "rpivid_asb";
                        clocks = <&clocks BCM2835_CLOCK_V3D>,
                                 <&clocks BCM2835_CLOCK_PERI_IMAGE>,
                                 <&clocks BCM2835_CLOCK_H264>,
                                #size-cells = <0x0>;
                        };
                };
+
+               v3d: gpu@7ec00000 {
+                       compatible = "brcm,2711-v3d";
+                       reg = <0x0 0x7ec00000 0x4000>,
+                             <0x0 0x7ec04000 0x4000>;
+                       reg-names = "hub", "core0";
+
+                       power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>;
+                       resets = <&pm BCM2835_RESET_V3D>;
+                       interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
+               };
        };
 };
 
index ead6e98..78465ad 100644 (file)
        };
 
        i2c@3e016000 {
-               status="okay";
+               status = "okay";
                clock-frequency = <400000>;
        };
 
        i2c@3e017000 {
-               status="okay";
+               status = "okay";
                clock-frequency = <400000>;
        };
 
        i2c@3e018000 {
-               status="okay";
+               status = "okay";
                clock-frequency = <400000>;
        };
 
        i2c@3500d000 {
-               status="okay";
+               status = "okay";
                clock-frequency = <100000>;
 
                pmu: pmu@8 {
index c25e797..a037d2b 100644 (file)
@@ -62,6 +62,7 @@
                        #reset-cells = <1>;
                        reg = <0x7e100000 0x114>,
                              <0x7e00a000 0x24>;
+                       reg-names = "pm", "asb";
                        clocks = <&clocks BCM2835_CLOCK_V3D>,
                                 <&clocks BCM2835_CLOCK_PERI_IMAGE>,
                                 <&clocks BCM2835_CLOCK_H264>,
index c113661..d2d9c6e 100644 (file)
@@ -50,9 +50,9 @@
 
                        trips {
                                cpu-crit {
-                                       temperature     = <90000>;
-                                       hysteresis      = <0>;
-                                       type            = "critical";
+                                       temperature = <90000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
                                };
                        };
 
                        clocks = <&clocks BCM2835_CLOCK_VPU>,
                                 <&clocks BCM2835_CLOCK_DPI>;
                        clock-names = "core", "pixel";
-                       #address-cells = <1>;
-                       #size-cells = <0>;
                        status = "disabled";
                };
 
index 8ed4037..09ee3e4 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               rfkill {
+               button-rfkill {
                        label = "WiFi";
                        linux,code = <KEY_RFKILL>;
                        gpios = <&chipcommon 7 GPIO_ACTIVE_LOW>;
                };
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
                };
 
-               wps {
+               button-wps {
                        label = "WPS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&chipcommon 15 GPIO_ACTIVE_LOW>;
index 667b118..32619c6 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               brightness {
+               button-brightness {
                        label = "Backlight";
                        linux,code = <KEY_BRIGHTNESS_ZERO>;
                        gpios = <&chipcommon 5 GPIO_ACTIVE_LOW>;
                };
 
-               wps {
+               button-wps {
                        label = "WPS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&chipcommon 7 GPIO_ACTIVE_LOW>;
                };
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
                };
 
-               rfkill {
+               button-rfkill {
                        label = "WiFi";
                        linux,code = <KEY_RFKILL>;
                        gpios = <&chipcommon 15 GPIO_ACTIVE_LOW>;
index d659e40..a658b9b 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
                };
 
-               aoss {
+               button-aoss {
                        label = "AOSS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&chipcommon 12 GPIO_ACTIVE_LOW>;
                };
 
                /* Commit mode set by switch? */
-               mode {
+               button-mode {
                        label = "Mode";
                        linux,code = <KEY_SETUP>;
                        gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>;
                };
 
                /* Switch: AP mode */
-               sw_ap {
+               button-sw-ap {
                        label = "AP";
                        linux,code = <BTN_0>;
                        gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>;
                };
 
-               eject {
+               button-eject {
                        label = "USB eject";
                        linux,code = <KEY_EJECTCD>;
                        gpios = <&chipcommon 15 GPIO_ACTIVE_LOW>;
index ff31ce4..f8f5345 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
                };
 
-               aoss {
+               button-aoss {
                        label = "AOSS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&chipcommon 12 GPIO_ACTIVE_LOW>;
                };
 
                /* Commit mode set by switch? */
-               mode {
+               button-mode {
                        label = "Mode";
                        linux,code = <KEY_SETUP>;
                        gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>;
                };
 
                /* Switch: AP mode */
-               sw_ap {
+               button-sw-ap {
                        label = "AP";
                        linux,code = <BTN_0>;
                        gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>;
                };
 
-               eject {
+               button-eject {
                        label = "USB eject";
                        linux,code = <KEY_EJECTCD>;
                        gpios = <&chipcommon 15 GPIO_ACTIVE_LOW>;
index 5bac1e1..0ed25bf 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               wps {
+               button-wps {
                        label = "WPS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&chipcommon 7 GPIO_ACTIVE_LOW>;
                };
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
index cd797b4..f1412ba 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               wps {
+               button-wps {
                        label = "WPS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&chipcommon 7 GPIO_ACTIVE_LOW>;
                };
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
index 5b4a481..14ee410 100644 (file)
@@ -45,7 +45,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
index c81944c..600ab08 100644 (file)
@@ -52,7 +52,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 7 GPIO_ACTIVE_LOW>;
index 43a5d67..fd6d8d2 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               wps {
+               button-wps {
                        label = "WPS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&chipcommon 4 GPIO_ACTIVE_LOW>;
                };
 
-               rfkill {
+               button-rfkill {
                        label = "WiFi";
                        linux,code = <KEY_RFKILL>;
                        gpios = <&chipcommon 5 GPIO_ACTIVE_LOW>;
                };
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 6 GPIO_ACTIVE_LOW>;
index 4c60eda..76fc109 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               wps {
+               button-wps {
                        label = "WPS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&chipcommon 4 GPIO_ACTIVE_LOW>;
                };
 
-               rfkill {
+               button-rfkill {
                        label = "WiFi";
                        linux,code = <KEY_RFKILL>;
                        gpios = <&chipcommon 5 GPIO_ACTIVE_LOW>;
                };
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 6 GPIO_ACTIVE_LOW>;
index 9ca6d1b..6bcdfb7 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               rfkill {
+               button-rfkill {
                        label = "WiFi";
                        linux,code = <KEY_RFKILL>;
                        gpios = <&chipcommon 0 GPIO_ACTIVE_LOW>;
                };
 
-               wps {
+               button-wps {
                        label = "WPS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&chipcommon 7 GPIO_ACTIVE_LOW>;
                };
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
index 0e273c5..ca47cc4 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 7 GPIO_ACTIVE_LOW>;
                };
 
-               wps {
+               button-wps {
                        label = "WPS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
index d00495a..0edc254 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               aoss {
+               button-aoss {
                        label = "AOSS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&chipcommon 9 GPIO_ACTIVE_LOW>;
                };
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
                };
 
                /* Switch device mode? */
-               mode {
+               button-mode {
                        label = "Mode";
                        linux,code = <KEY_SETUP>;
                        gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>;
                };
 
-               eject {
+               button-eject {
                        label = "USB eject";
                        linux,code = <KEY_EJECTCD>;
                        gpios = <&chipcommon 15 GPIO_ACTIVE_LOW>;
index 8b1a05a..1f0998f 100644 (file)
@@ -96,7 +96,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
index 68aaf0a..c8c0237 100644 (file)
@@ -45,7 +45,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
index 9316a36..3b35a7a 100644 (file)
@@ -94,7 +94,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
index 12e34a0..19a7971 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               rfkill {
+               button-rfkill {
                        label = "WiFi";
                        linux,code = <KEY_RFKILL>;
                        gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
                };
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 7 GPIO_ACTIVE_LOW>;
index 7546c8d..f52a75c 100644 (file)
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
-               wps {
+               button-wps {
                        label = "WPS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&chipcommon 2 GPIO_ACTIVE_LOW>;
                };
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
index beae9ea..5ff6c58 100644 (file)
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
-               power {
+               button-power {
                        label = "Power";
                        linux,code = <KEY_POWER>;
                        gpios = <&chipcommon 1 GPIO_ACTIVE_LOW>;
                };
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 15 GPIO_ACTIVE_LOW>;
                };
 
-               aoss {
+               button-aoss {
                        label = "AOSS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&chipcommon 16 GPIO_ACTIVE_LOW>;
                };
 
                /* Commit mode set by switch? */
-               mode {
+               button-mode {
                        label = "Mode";
                        linux,code = <KEY_SETUP>;
                        gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>;
                };
 
                /* Switch: AP mode */
-               sw_ap {
+               button-sw-ap {
                        label = "AP";
                        linux,code = <BTN_0>;
                        gpios = <&chipcommon 18 GPIO_ACTIVE_LOW>;
                };
 
-               eject {
+               button-eject {
                        label = "USB eject";
                        linux,code = <KEY_EJECTCD>;
                        gpios = <&chipcommon 20 GPIO_ACTIVE_LOW>;
index 7879f7d..99253fd 100644 (file)
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
-               wps {
+               button-wps {
                        label = "WPS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
                };
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>;
index 56d309d..de961fb 100644 (file)
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
-               wps {
+               button-wps {
                        label = "WPS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&chipcommon 4 GPIO_ACTIVE_LOW>;
                };
 
-               rfkill {
+               button-rfkill {
                        label = "WiFi";
                        linux,code = <KEY_RFKILL>;
                        gpios = <&chipcommon 5 GPIO_ACTIVE_LOW>;
                };
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 6 GPIO_ACTIVE_LOW>;
index 89f992a..087f7f6 100644 (file)
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
-               rfkill {
+               button-rfkill {
                        label = "WiFi";
                        linux,code = <KEY_RFKILL>;
                        gpios = <&chipcommon 4 GPIO_ACTIVE_LOW>;
                };
 
-               wps {
+               button-wps {
                        label = "WPS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&chipcommon 5 GPIO_ACTIVE_LOW>;
                };
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 6 GPIO_ACTIVE_LOW>;
                };
 
-               brightness {
+               button-brightness {
                        label = "Backlight";
                        linux,code = <KEY_BRIGHTNESS_ZERO>;
                        gpios = <&chipcommon 19 GPIO_ACTIVE_LOW>;
index c2a266a..11d1068 100644 (file)
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
-               wps {
+               button-wps {
                        label = "WPS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&chipcommon 0 GPIO_ACTIVE_LOW>;
                };
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
index d850375..a5fec56 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               wps {
+               button-wps {
                        label = "WPS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&chipcommon 20 GPIO_ACTIVE_LOW>;
                };
 
-               reset {
+               button-reset {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
                };
 
-               wifi {
+               button-wifi {
                        label = "Wi-Fi";
                        linux,code = <KEY_RFKILL>;
                        gpios = <&chipcommon 18 GPIO_ACTIVE_LOW>;
                };
 
-               led {
+               button-led {
                        label = "Backlight";
                        linux,code = <KEY_BRIGHTNESS_ZERO>;
                        gpios = <&chipcommon 4 GPIO_ACTIVE_LOW>;
index 60bfd52..2c38b64 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               wps {
+               button-wps {
                        label = "WPS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&chipcommon 7 GPIO_ACTIVE_LOW>;
                };
 
                /* Switch: router / extender */
-               extender {
+               button-extender {
                        label = "Extender";
                        linux,code = <BTN_0>;
                        gpios = <&chipcommon 10 GPIO_ACTIVE_LOW>;
                };
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>;
index 9bef6b9..86c7cc0 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               wps {
+               button-wps {
                        label = "WPS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
                };
 
-               rfkill {
+               button-rfkill {
                                label = "WiFi";
                                linux,code = <KEY_RFKILL>;
                                gpios = <&chipcommon 16 GPIO_ACTIVE_LOW>;
                };
 
-               reset {
+               button-reset {
                                label = "Reset";
                                linux,code = <KEY_RESTART>;
                                gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>;
index b51a0ee..9ad15bc 100644 (file)
@@ -49,7 +49,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>;
index 6fa101f..ee24d37 100644 (file)
@@ -43,7 +43,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>;
index b959a95..6549d07 100644 (file)
@@ -49,7 +49,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>;
index b0d8a68..654fcce 100644 (file)
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 19 GPIO_ACTIVE_LOW>;
index cbe8c8e..bf053a2 100644 (file)
@@ -89,7 +89,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>;
index 9efcb24..78a90dd 100644 (file)
@@ -67,7 +67,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>;
index 42097a4..f850dce 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               brightness {
+               button-brightness {
                        label = "Backlight";
                        linux,code = <KEY_BRIGHTNESS_ZERO>;
                        gpios = <&chipcommon 1 GPIO_ACTIVE_LOW>;
                };
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 10 GPIO_ACTIVE_LOW>;
                };
 
-               wps {
+               button-wps {
                        label = "WPS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>;
                };
 
-               rfkill {
+               button-rfkill {
                        label = "WiFi";
                        linux,code = <KEY_RFKILL>;
                        gpios = <&chipcommon 20 GPIO_ACTIVE_LOW>;
index a2566ad..3bf6e24 100644 (file)
@@ -22,7 +22,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>;
index 57ca1cf..e20b6d2 100644 (file)
@@ -39,7 +39,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 7 GPIO_ACTIVE_LOW>;
index 2e1a7e3..9d86357 100644 (file)
@@ -49,7 +49,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 7 GPIO_ACTIVE_LOW>;
index 07eb3a8..55b9264 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               rfkill {
+               button-rfkill {
                        label = "WiFi";
                        linux,code = <KEY_RFKILL>;
                        gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
                };
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 7 GPIO_ACTIVE_LOW>;
                };
 
-               wps {
+               button-wps {
                        label = "WPS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&chipcommon 9 GPIO_ACTIVE_LOW>;
index c016e12..2df0452 100644 (file)
@@ -32,6 +32,7 @@
                        next-level-cache = <&L2_0>;
                        enable-method = "psci";
                };
+
                CA7_2: cpu@2 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a7";
@@ -39,6 +40,7 @@
                        next-level-cache = <&L2_0>;
                        enable-method = "psci";
                };
+
                CA7_3: cpu@3 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a7";
@@ -46,6 +48,7 @@
                        next-level-cache = <&L2_0>;
                        enable-method = "psci";
                };
+
                L2_0: l2-cache0 {
                        compatible = "cache";
                };
@@ -76,6 +79,7 @@
                        #clock-cells = <0>;
                        clock-frequency = <200000000>;
                };
+
                uart_clk: uart-clk {
                        compatible = "fixed-factor-clock";
                        #clock-cells = <0>;
        psci {
                compatible = "arm,psci-0.2";
                method = "smc";
-               cpu_off = <1>;
-               cpu_on = <2>;
        };
 
        axi@81000000 {
                compatible = "simple-bus";
                #address-cells = <1>;
                #size-cells = <1>;
-               ranges = <0 0x81000000 0x818000>;
+               ranges = <0 0x81000000 0x8000>;
 
                gic: interrupt-controller@1000 {
                        compatible = "arm,cortex-a7-gic";
                        #interrupt-cells = <3>;
-                       #address-cells = <0>;
                        interrupt-controller;
+                       interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
                        reg = <0x1000 0x1000>,
-                               <0x2000 0x2000>;
+                               <0x2000 0x2000>,
+                               <0x4000 0x2000>,
+                               <0x6000 0x2000>;
                };
        };
 
diff --git a/arch/arm/boot/dts/bcm53015-meraki-mr26.dts b/arch/arm/boot/dts/bcm53015-meraki-mr26.dts
new file mode 100644 (file)
index 0000000..14f5803
--- /dev/null
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Broadcom BCM470X / BCM5301X ARM platform code.
+ * DTS for Meraki MR26 / Codename: Venom
+ *
+ * Copyright (C) 2022 Christian Lamparter <chunkeey@gmail.com>
+ */
+
+/dts-v1/;
+
+#include "bcm4708.dtsi"
+#include "bcm5301x-nand-cs0-bch8.dtsi"
+#include <dt-bindings/leds/common.h>
+
+/ {
+       compatible = "meraki,mr26", "brcm,bcm53015", "brcm,bcm4708";
+       model = "Meraki MR26";
+
+       memory@0 {
+               reg = <0x00000000 0x08000000>;
+               device_type = "memory";
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               led-0 {
+                       function = LED_FUNCTION_FAULT;
+                       color = <LED_COLOR_ID_AMBER>;
+                       gpios = <&chipcommon 13 GPIO_ACTIVE_HIGH>;
+                       panic-indicator;
+               };
+               led-1 {
+                       function = LED_FUNCTION_INDICATOR;
+                       color = <LED_COLOR_ID_WHITE>;
+                       gpios = <&chipcommon 12 GPIO_ACTIVE_HIGH>;
+               };
+       };
+
+       keys {
+               compatible = "gpio-keys";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               key-restart {
+                       label = "Reset";
+                       linux,code = <KEY_RESTART>;
+                       gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
+               };
+       };
+};
+
+&uart0 {
+       clock-frequency = <50000000>;
+       /delete-property/ clocks;
+};
+
+&uart1 {
+       status = "disabled";
+};
+
+&gmac0 {
+       status = "okay";
+};
+
+&gmac1 {
+       status = "disabled";
+};
+&gmac2 {
+       status = "disabled";
+};
+&gmac3 {
+       status = "disabled";
+};
+
+&nandcs {
+       nand-ecc-algo = "hw";
+
+       partitions {
+               compatible = "fixed-partitions";
+               #address-cells = <0x1>;
+               #size-cells = <0x1>;
+
+               partition@0 {
+                       label = "u-boot";
+                       reg = <0x0 0x200000>;
+                       read-only;
+               };
+
+               partition@200000 {
+                       label = "u-boot-env";
+                       reg = <0x200000 0x200000>;
+                       /* empty */
+               };
+
+               partition@400000 {
+                       label = "u-boot-backup";
+                       reg = <0x400000 0x200000>;
+                       /* empty */
+               };
+
+               partition@600000 {
+                       label = "u-boot-env-backup";
+                       reg = <0x600000 0x200000>;
+                       /* empty */
+               };
+
+               partition@800000 {
+                       label = "ubi";
+                       reg = <0x800000 0x7780000>;
+               };
+       };
+};
+
+&srab {
+       status = "okay";
+
+       ports {
+               port@0 {
+                       reg = <0>;
+                       label = "poe";
+               };
+
+               port@5 {
+                       reg = <5>;
+                       label = "cpu";
+                       ethernet = <&gmac0>;
+
+                       fixed-link {
+                               speed = <1000>;
+                               duplex-full;
+                       };
+               };
+       };
+};
+
+&i2c0 {
+       status = "okay";
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinmux_i2c>;
+
+       clock-frequency = <100000>;
+
+       ina219@40 {
+               compatible = "ti,ina219"; /* PoE power */
+               reg = <0x40>;
+               shunt-resistor = <60000>; /* = 60 mOhms */
+       };
+
+       eeprom@56 {
+               compatible = "atmel,24c64";
+               reg = <0x56>;
+               pagesize = <32>;
+               read-only;
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               /* it's empty */
+       };
+};
+
+&thermal {
+       status = "disabled";
+       /* does not work, reads 418 degree Celsius */
+};
index daca63f..e678bc0 100644 (file)
 
        keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 21 GPIO_ACTIVE_LOW>;
index 65f8a75..5fc1b84 100644 (file)
 
                        trips {
                                cpu-crit {
-                                       temperature     = <125000>;
-                                       hysteresis      = <0>;
-                                       type            = "critical";
+                                       temperature = <125000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
                                };
                        };
 
index cca49a2..b774a8d 100644 (file)
@@ -9,8 +9,8 @@
 / {
        #address-cells = <1>;
        #size-cells = <1>;
-       compatible = "brcm,bcm63138";
-       model = "Broadcom BCM63138 DSL SoC";
+       compatible = "brcm,bcm63138", "brcm,bcmbca";
+       model = "Broadcom BCM963138 Reference Board";
        interrupt-parent = <&gic>;
 
        aliases {
diff --git a/arch/arm/boot/dts/bcm63148.dtsi b/arch/arm/boot/dts/bcm63148.dtsi
new file mode 100644 (file)
index 0000000..df5307b
--- /dev/null
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2022 Broadcom Ltd.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+       compatible = "brcm,bcm63148", "brcm,bcmbca";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       interrupt-parent = <&gic>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               B15_0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "brcm,brahma-b15";
+                       reg = <0x0>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               B15_1: cpu@1 {
+                       device_type = "cpu";
+                       compatible = "brcm,brahma-b15";
+                       reg = <0x1>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               L2_0: l2-cache0 {
+                       compatible = "cache";
+               };
+       };
+
+       timer {
+               compatible = "arm,armv7-timer";
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>;
+       };
+
+       pmu: pmu {
+               compatible = "arm,cortex-a15-pmu";
+               interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-affinity = <&B15_0>, <&B15_1>;
+       };
+
+       clocks: clocks {
+               periph_clk: periph-clk {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <50000000>;
+               };
+       };
+
+       psci {
+               compatible = "arm,psci-0.2";
+               method = "smc";
+       };
+
+       axi@80030000 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0 0x80030000 0x8000>;
+
+               gic: interrupt-controller@1000 {
+                       compatible = "arm,cortex-a15-gic";
+                       #interrupt-cells = <3>;
+                       interrupt-controller;
+                       reg = <0x1000 0x1000>,
+                               <0x2000 0x2000>,
+                               <0x4000 0x2000>,
+                               <0x6000 0x2000>;
+                       interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) |
+                                       IRQ_TYPE_LEVEL_HIGH)>;
+               };
+       };
+
+       bus@ff800000 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0 0xfffe8000 0x8000>;
+
+               uart0: serial@600 {
+                       compatible = "brcm,bcm6345-uart";
+                       reg = <0x600 0x20>;
+                       interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&periph_clk>;
+                       clock-names = "refclk";
+                       status = "disabled";
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/bcm63178.dtsi b/arch/arm/boot/dts/bcm63178.dtsi
new file mode 100644 (file)
index 0000000..5463443
--- /dev/null
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2022 Broadcom Ltd.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+       compatible = "brcm,bcm63178", "brcm,bcmbca";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       interrupt-parent = <&gic>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               CA7_0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a7";
+                       reg = <0x0>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               CA7_1: cpu@1 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a7";
+                       reg = <0x1>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+               CA7_2: cpu@2 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a7";
+                       reg = <0x2>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+               L2_0: l2-cache0 {
+                       compatible = "cache";
+               };
+       };
+
+       timer {
+               compatible = "arm,armv7-timer";
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+               arm,cpu-registers-not-fw-configured;
+       };
+
+       pmu: pmu {
+               compatible = "arm,cortex-a7-pmu";
+               interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-affinity = <&CA7_0>, <&CA7_1>,
+                       <&CA7_2>;
+       };
+
+       clocks: clocks {
+               periph_clk: periph-clk {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <200000000>;
+               };
+               uart_clk: uart-clk {
+                       compatible = "fixed-factor-clock";
+                       #clock-cells = <0>;
+                       clocks = <&periph_clk>;
+                       clock-div = <4>;
+                       clock-mult = <1>;
+               };
+       };
+
+       psci {
+               compatible = "arm,psci-0.2";
+               method = "smc";
+               cpu_off = <1>;
+               cpu_on = <2>;
+       };
+
+       axi@81000000 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0 0x81000000 0x4000>;
+
+               gic: interrupt-controller@1000 {
+                       compatible = "arm,cortex-a7-gic";
+                       #interrupt-cells = <3>;
+                       #address-cells = <0>;
+                       interrupt-controller;
+                       reg = <0x1000 0x1000>,
+                               <0x2000 0x2000>;
+               };
+       };
+
+       bus@ff800000 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0 0xff800000 0x800000>;
+
+               uart0: serial@12000 {
+                       compatible = "arm,pl011", "arm,primecell";
+                       reg = <0x12000 0x1000>;
+                       interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&uart_clk>, <&uart_clk>;
+                       clock-names = "uartclk", "apb_pclk";
+                       status = "disabled";
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/bcm6756.dtsi b/arch/arm/boot/dts/bcm6756.dtsi
new file mode 100644 (file)
index 0000000..ce1b59f
--- /dev/null
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2022 Broadcom Ltd.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+       compatible = "brcm,bcm6756", "brcm,bcmbca";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       interrupt-parent = <&gic>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               CA7_0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a7";
+                       reg = <0x0>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               CA7_1: cpu@1 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a7";
+                       reg = <0x1>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               CA7_2: cpu@2 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a7";
+                       reg = <0x2>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               CA7_3: cpu@3 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a7";
+                       reg = <0x3>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               L2_0: l2-cache0 {
+                       compatible = "cache";
+               };
+       };
+
+       timer {
+               compatible = "arm,armv7-timer";
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+               arm,cpu-registers-not-fw-configured;
+       };
+
+       pmu: pmu {
+               compatible = "arm,cortex-a7-pmu";
+               interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-affinity = <&CA7_0>, <&CA7_1>,
+                       <&CA7_2>, <&CA7_3>;
+       };
+
+       clocks: clocks {
+               periph_clk: periph-clk {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <200000000>;
+               };
+
+               uart_clk: uart-clk {
+                       compatible = "fixed-factor-clock";
+                       #clock-cells = <0>;
+                       clocks = <&periph_clk>;
+                       clock-div = <4>;
+                       clock-mult = <1>;
+               };
+       };
+
+       psci {
+               compatible = "arm,psci-0.2";
+               method = "smc";
+       };
+
+       axi@81000000 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0 0x81000000 0x8000>;
+
+               gic: interrupt-controller@1000 {
+                       compatible = "arm,cortex-a7-gic";
+                       #interrupt-cells = <3>;
+                       interrupt-controller;
+                       interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+                       reg = <0x1000 0x1000>,
+                               <0x2000 0x2000>,
+                               <0x4000 0x2000>,
+                               <0x6000 0x2000>;
+               };
+       };
+
+       bus@ff800000 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0 0xff800000 0x800000>;
+
+               uart0: serial@12000 {
+                       compatible = "arm,pl011", "arm,primecell";
+                       reg = <0x12000 0x1000>;
+                       interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&uart_clk>, <&uart_clk>;
+                       clock-names = "uartclk", "apb_pclk";
+                       status = "disabled";
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/bcm6846.dtsi b/arch/arm/boot/dts/bcm6846.dtsi
new file mode 100644 (file)
index 0000000..e610c10
--- /dev/null
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2022 Broadcom Ltd.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+       compatible = "brcm,bcm6846", "brcm,bcmbca";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       interrupt-parent = <&gic>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               CA7_0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a7";
+                       reg = <0x0>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               CA7_1: cpu@1 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a7";
+                       reg = <0x1>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               L2_0: l2-cache0 {
+                       compatible = "cache";
+               };
+       };
+
+       timer {
+               compatible = "arm,armv7-timer";
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+               arm,cpu-registers-not-fw-configured;
+       };
+
+       pmu: pmu {
+               compatible = "arm,cortex-a7-pmu";
+               interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-affinity = <&CA7_0>, <&CA7_1>;
+       };
+
+       clocks: clocks {
+               periph_clk: periph-clk {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <200000000>;
+               };
+       };
+
+       psci {
+               compatible = "arm,psci-0.2";
+               method = "smc";
+               cpu_off = <1>;
+               cpu_on = <2>;
+       };
+
+       axi@81000000 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0 0x81000000 0x4000>;
+
+               gic: interrupt-controller@1000 {
+                       compatible = "arm,cortex-a7-gic";
+                       #interrupt-cells = <3>;
+                       #address-cells = <0>;
+                       interrupt-controller;
+                       reg = <0x1000 0x1000>,
+                               <0x2000 0x2000>;
+               };
+       };
+
+       bus@ff800000 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0 0xff800000 0x800000>;
+
+               uart0: serial@640 {
+                       compatible = "brcm,bcm6345-uart";
+                       reg = <0x640 0x1b>;
+                       interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&periph_clk>;
+                       clock-names = "refclk";
+                       status = "disabled";
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/bcm6855.dtsi b/arch/arm/boot/dts/bcm6855.dtsi
new file mode 100644 (file)
index 0000000..620f51a
--- /dev/null
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2022 Broadcom Ltd.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+       compatible = "brcm,bcm6855", "brcm,bcmbca";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       interrupt-parent = <&gic>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               CA7_0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a7";
+                       reg = <0x0>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               CA7_1: cpu@1 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a7";
+                       reg = <0x1>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               CA7_2: cpu@2 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a7";
+                       reg = <0x2>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               L2_0: l2-cache0 {
+                       compatible = "cache";
+               };
+       };
+
+       timer {
+               compatible = "arm,armv7-timer";
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(3) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(3) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(3) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(3) | IRQ_TYPE_LEVEL_LOW)>;
+               arm,cpu-registers-not-fw-configured;
+       };
+
+       pmu: pmu {
+               compatible = "arm,cortex-a7-pmu";
+               interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-affinity = <&CA7_0>, <&CA7_1>, <&CA7_2>;
+       };
+
+       clocks: clocks {
+               periph_clk: periph-clk {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <200000000>;
+               };
+
+               uart_clk: uart-clk {
+                       compatible = "fixed-factor-clock";
+                       #clock-cells = <0>;
+                       clocks = <&periph_clk>;
+                       clock-div = <4>;
+                       clock-mult = <1>;
+               };
+       };
+
+       psci {
+               compatible = "arm,psci-0.2";
+               method = "smc";
+       };
+
+       axi@81000000 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0 0x81000000 0x8000>;
+
+               gic: interrupt-controller@1000 {
+                       compatible = "arm,cortex-a7-gic";
+                       #interrupt-cells = <3>;
+                       interrupt-controller;
+                       interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(3) | IRQ_TYPE_LEVEL_HIGH)>;
+                       reg = <0x1000 0x1000>,
+                               <0x2000 0x2000>,
+                               <0x4000 0x2000>,
+                               <0x6000 0x2000>;
+               };
+       };
+
+       bus@ff800000 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0 0xff800000 0x800000>;
+
+               uart0: serial@12000 {
+                       compatible = "arm,pl011", "arm,primecell";
+                       reg = <0x12000 0x1000>;
+                       interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&uart_clk>, <&uart_clk>;
+                       clock-names = "uartclk", "apb_pclk";
+                       status = "disabled";
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/bcm6878.dtsi b/arch/arm/boot/dts/bcm6878.dtsi
new file mode 100644 (file)
index 0000000..a7dff59
--- /dev/null
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2022 Broadcom Ltd.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+       compatible = "brcm,bcm6878", "brcm,bcmbca";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       interrupt-parent = <&gic>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               CA7_0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a7";
+                       reg = <0x0>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               CA7_1: cpu@1 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a7";
+                       reg = <0x1>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+               L2_0: l2-cache0 {
+                       compatible = "cache";
+               };
+       };
+
+       timer {
+               compatible = "arm,armv7-timer";
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+               arm,cpu-registers-not-fw-configured;
+       };
+
+       pmu: pmu {
+               compatible = "arm,cortex-a7-pmu";
+               interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-affinity = <&CA7_0>, <&CA7_1>;
+       };
+
+       clocks: clocks {
+               periph_clk: periph-clk {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <200000000>;
+               };
+               uart_clk: uart-clk {
+                       compatible = "fixed-factor-clock";
+                       #clock-cells = <0>;
+                       clocks = <&periph_clk>;
+                       clock-div = <4>;
+                       clock-mult = <1>;
+               };
+       };
+
+       psci {
+               compatible = "arm,psci-0.2";
+               method = "smc";
+       };
+
+       axi@81000000 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0 0x81000000 0x8000>;
+
+               gic: interrupt-controller@1000 {
+                       compatible = "arm,cortex-a7-gic";
+                       #interrupt-cells = <3>;
+                       interrupt-controller;
+                       reg = <0x1000 0x1000>,
+                               <0x2000 0x2000>,
+                               <0x4000 0x2000>,
+                               <0x6000 0x2000>;
+                       interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) |
+                                       IRQ_TYPE_LEVEL_HIGH)>;
+               };
+       };
+
+       bus@ff800000 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0 0xff800000 0x800000>;
+
+               uart0: serial@12000 {
+                       compatible = "arm,pl011", "arm,primecell";
+                       reg = <0x12000 0x1000>;
+                       interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&uart_clk>, <&uart_clk>;
+                       clock-names = "uartclk", "apb_pclk";
+                       status = "disabled";
+               };
+       };
+};
index a76c74b..363009e 100644 (file)
                stdout-path = "serial0:115200n8";
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               hook {
+               button-hook {
                        label = "HOOK";
                        linux,code = <KEY_O>;
                        gpios = <&gpio_asiu 48 0>;
index b0b8c77..16e70a2 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 7 GPIO_ACTIVE_HIGH>;
                };
 
-               wps {
+               button-wps {
                        label = "WPS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&chipcommon 9 GPIO_ACTIVE_LOW>;
index dd63a14..4fe3b36 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               wps {
+               button-wps {
                        label = "WPS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&chipcommon 6 GPIO_ACTIVE_LOW>;
                };
 
-               restart {
+               button-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&chipcommon 15 GPIO_ACTIVE_LOW>;
index 58b7d9f..c54451d 100644 (file)
@@ -13,7 +13,7 @@
                autorepeat;
                poll-interval = <20>;
 
-               reset {
+               button-reset {
                        label = "reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&gpioa 8 GPIO_ACTIVE_LOW>;
index 576cfc5..1830844 100644 (file)
@@ -14,7 +14,7 @@
                autorepeat;
                poll-interval = <20>;
 
-               reset {
+               button-reset {
                        label = "reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&gpioa 6 GPIO_ACTIVE_LOW>;
diff --git a/arch/arm/boot/dts/bcm963138.dts b/arch/arm/boot/dts/bcm963138.dts
new file mode 100644 (file)
index 0000000..d28c4f1
--- /dev/null
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2022 Broadcom Ltd.
+ */
+
+/dts-v1/;
+
+#include "bcm63138.dtsi"
+
+/ {
+       model = "Broadcom BCM963138 Reference Board";
+       compatible = "brcm,bcm963138", "brcm,bcm63138", "brcm,bcmbca";
+
+       chosen {
+               bootargs = "console=ttyS0,115200";
+               stdout-path = &serial0;
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x0 0x08000000>;
+       };
+};
+
+&serial0 {
+       status = "okay";
+};
index df5c8ab..15bec75 100644 (file)
@@ -8,7 +8,7 @@
 #include "bcm63138.dtsi"
 
 / {
-       compatible = "brcm,BCM963138DVT", "brcm,bcm63138";
+       compatible = "brcm,BCM963138DVT", "brcm,bcm63138", "brcm,bcmbca";
        model = "Broadcom BCM963138DVT";
 
        chosen {
diff --git a/arch/arm/boot/dts/bcm963148.dts b/arch/arm/boot/dts/bcm963148.dts
new file mode 100644 (file)
index 0000000..98f6a6d
--- /dev/null
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2019 Broadcom Ltd.
+ */
+
+/dts-v1/;
+
+#include "bcm63148.dtsi"
+
+/ {
+       model = "Broadcom BCM963148 Reference Board";
+       compatible = "brcm,bcm963148", "brcm,bcm63148", "brcm,bcmbca";
+
+       aliases {
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x0 0x08000000>;
+       };
+};
+
+&uart0 {
+       status = "okay";
+};
diff --git a/arch/arm/boot/dts/bcm963178.dts b/arch/arm/boot/dts/bcm963178.dts
new file mode 100644 (file)
index 0000000..fa096e9
--- /dev/null
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2019 Broadcom Ltd.
+ */
+
+/dts-v1/;
+
+#include "bcm63178.dtsi"
+
+/ {
+       model = "Broadcom BCM963178 Reference Board";
+       compatible = "brcm,bcm963178", "brcm,bcm63178", "brcm,bcmbca";
+
+       aliases {
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x0 0x08000000>;
+       };
+};
+
+&uart0 {
+       status = "okay";
+};
diff --git a/arch/arm/boot/dts/bcm96756.dts b/arch/arm/boot/dts/bcm96756.dts
new file mode 100644 (file)
index 0000000..9a4a87b
--- /dev/null
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2019 Broadcom Ltd.
+ */
+
+/dts-v1/;
+
+#include "bcm6756.dtsi"
+
+/ {
+       model = "Broadcom BCM96756 Reference Board";
+       compatible = "brcm,bcm96756", "brcm,bcm6756", "brcm,bcmbca";
+
+       aliases {
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x0 0x08000000>;
+       };
+};
+
+&uart0 {
+       status = "okay";
+};
diff --git a/arch/arm/boot/dts/bcm96846.dts b/arch/arm/boot/dts/bcm96846.dts
new file mode 100644 (file)
index 0000000..c70ebcc
--- /dev/null
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2022 Broadcom Ltd.
+ */
+
+/dts-v1/;
+
+#include "bcm6846.dtsi"
+
+/ {
+       model = "Broadcom BCM96846 Reference Board";
+       compatible = "brcm,bcm96846", "brcm,bcm6846", "brcm,bcmbca";
+
+       aliases {
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x0 0x08000000>;
+       };
+};
+
+&uart0 {
+       status = "okay";
+};
diff --git a/arch/arm/boot/dts/bcm96855.dts b/arch/arm/boot/dts/bcm96855.dts
new file mode 100644 (file)
index 0000000..4438152
--- /dev/null
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2019 Broadcom Ltd.
+ */
+
+/dts-v1/;
+
+#include "bcm6855.dtsi"
+
+/ {
+       model = "Broadcom BCM96855 Reference Board";
+       compatible = "brcm,bcm96855", "brcm,bcm6855", "brcm,bcmbca";
+
+       aliases {
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x0 0x08000000>;
+       };
+};
+
+&uart0 {
+       status = "okay";
+};
diff --git a/arch/arm/boot/dts/bcm96878.dts b/arch/arm/boot/dts/bcm96878.dts
new file mode 100644 (file)
index 0000000..8fbc175
--- /dev/null
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2019 Broadcom Ltd.
+ */
+
+/dts-v1/;
+
+#include "bcm6878.dtsi"
+
+/ {
+       model = "Broadcom BCM96878 Reference Board";
+       compatible = "brcm,bcm96878", "brcm,bcm6878", "brcm,bcmbca";
+
+       aliases {
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x0 0x08000000>;
+       };
+};
+
+&uart0 {
+       status = "okay";
+};
index e9aecac..1fdd9a2 100644 (file)
                enable-gpios = <&gpio 40 GPIO_ACTIVE_HIGH>; /* lcd_panel_pwr */
 
                panel-info {
-                       ac-bias         = <255>;
-                       ac-bias-intrpt  = <0>;
-                       dma-burst-sz    = <16>;
-                       bpp             = <16>;
-                       fdd             = <0x80>;
-                       sync-edge       = <0>;
-                       sync-ctrl       = <1>;
-                       raster-order    = <0>;
-                       fifo-th         = <0>;
+                       ac-bias = <255>;
+                       ac-bias-intrpt = <0>;
+                       dma-burst-sz = <16>;
+                       bpp = <16>;
+                       fdd = <0x80>;
+                       sync-edge = <0>;
+                       sync-ctrl = <1>;
+                       raster-order = <0>;
+                       fifo-th = <0>;
                };
 
                display-timings {
index 0386376..e46e4d2 100644 (file)
                edma0: edma@0 {
                        compatible = "ti,edma3-tpcc";
                        /* eDMA3 CC0: 0x01c0 0000 - 0x01c0 7fff */
-                       reg =   <0x0 0x8000>;
+                       reg = <0x0 0x8000>;
                        reg-names = "edma3_cc";
                        interrupts = <11 12>;
                        interrupt-names = "edma3_ccint", "edma3_ccerrint";
                };
                edma0_tptc0: tptc@8000 {
                        compatible = "ti,edma3-tptc";
-                       reg =   <0x8000 0x400>;
+                       reg = <0x8000 0x400>;
                        interrupts = <13>;
                        interrupt-names = "edm3_tcerrint";
                        power-domains = <&psc0 1>;
                };
                edma0_tptc1: tptc@8400 {
                        compatible = "ti,edma3-tptc";
-                       reg =   <0x8400 0x400>;
+                       reg = <0x8400 0x400>;
                        interrupts = <32>;
                        interrupt-names = "edm3_tcerrint";
                        power-domains = <&psc0 2>;
                edma1: edma@230000 {
                        compatible = "ti,edma3-tpcc";
                        /* eDMA3 CC1: 0x01e3 0000 - 0x01e3 7fff */
-                       reg =   <0x230000 0x8000>;
+                       reg = <0x230000 0x8000>;
                        reg-names = "edma3_cc";
                        interrupts = <93 94>;
                        interrupt-names = "edma3_ccint", "edma3_ccerrint";
                };
                edma1_tptc0: tptc@238000 {
                        compatible = "ti,edma3-tptc";
-                       reg =   <0x238000 0x400>;
+                       reg = <0x238000 0x400>;
                        interrupts = <95>;
                        interrupt-names = "edm3_tcerrint";
                        power-domains = <&psc1 21>;
 
                        cppi41dma: dma-controller@201000 {
                                compatible = "ti,da830-cppi41";
-                               reg =  <0x201000 0x1000
+                               reg = <0x201000 0x1000
                                        0x202000 0x1000
                                        0x204000 0x4000>;
                                reg-names = "controller",
index 8ef48c0..fe3f9a9 100644 (file)
@@ -51,7 +51,7 @@
                interrupt-parent = <&gpmc>;
                interrupts = <0 IRQ_TYPE_NONE>, /* fifoevent */
                             <1 IRQ_TYPE_NONE>; /* termcount */
-               linux,mtd-name= "micron,mt29f2g16aadwp";
+               linux,mtd-name = "micron,mt29f2g16aadwp";
                #address-cells = <1>;
                #size-cells = <1>;
                ti,nand-ecc-opt = "bch8";
index 778796c..244a957 100644 (file)
 
        nand@0,0 {
                compatible = "ti,omap2-nand";
-               linux,mtd-name= "micron,mt29f2g16aadwp";
+               linux,mtd-name = "micron,mt29f2g16aadwp";
                reg = <0 0 4>; /* CS0, offset 0, IO size 4 */
                interrupt-parent = <&gpmc>;
                interrupts = <0 IRQ_TYPE_NONE>, /* fifoevent */
index c16e183..577114c 100644 (file)
@@ -51,7 +51,7 @@
                interrupt-parent = <&gpmc>;
                interrupts = <0 IRQ_TYPE_NONE>, /* fifoevent */
                             <1 IRQ_TYPE_NONE>; /* termcount */
-               linux,mtd-name= "micron,mt29f2g16aadwp";
+               linux,mtd-name = "micron,mt29f2g16aadwp";
                #address-cells = <1>;
                #size-cells = <1>;
                ti,nand-ecc-opt = "bch8";
index bc4ae91..931db79 100644 (file)
@@ -90,8 +90,8 @@
                clocks = <&dpll_gmac_x2_ck>;
                ti,max-div = <63>;
                reg = <0x03fc>;
-               ti,bit-shift=<20>;
-               ti,latch-bit=<26>;
+               ti,bit-shift = <20>;
+               ti,latch-bit = <26>;
                assigned-clocks = <&dpll_gmac_h14x2_ctrl_ck>;
                assigned-clock-rates = <80000000>;
        };
                clocks = <&dpll_gmac_ck>, <&dpll_gmac_h14x2_ctrl_ck>;
                reg = <0x3fc>;
                ti,bit-shift = <29>;
-               ti,latch-bit=<26>;
+               ti,latch-bit = <26>;
                assigned-clocks = <&dpll_gmac_h14x2_ctrl_mux_ck>;
                assigned-clock-parents = <&dpll_gmac_h14x2_ctrl_ck>;
        };
index 1a49f15..935e235 100644 (file)
        gpio_keys: gpio-keys {
                compatible = "gpio-keys";
 
-               power {
+               key-power {
                        label = "Power";
                        gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
                        wakeup-source;
                };
 
-               cover {
+               key-cover {
                        label = "Cover";
                        gpios = <&gpio5 12 GPIO_ACTIVE_LOW>;
                        linux,code = <SW_LID>;
index 156de65..27ef9a6 100644 (file)
        gpio_keys: gpio-keys {
                compatible = "gpio-keys";
 
-               power {
+               key-power {
                        label = "Power";
                        gpios = <&gpio4 25 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
                        wakeup-source;
                };
 
-               cover {
+               key-cover {
                        label = "Cover";
                        gpios = <&gpio4 23 GPIO_ACTIVE_LOW>;
                        linux,code = <SW_LID>;
                        wakeup-source;
                };
 
-               pageup {
+               key-pageup {
                        label = "PageUp";
                        gpios = <&gpio4 0 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_PAGEUP>;
                };
 
-               pagedown {
+               key-pagedown {
                        label = "PageDown";
                        gpios = <&gpio4 2 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_PAGEDOWN>;
index 57a028a..ce5221c 100644 (file)
@@ -9,11 +9,11 @@
        };
 
        psci {
-               compatible      = "arm,psci";
-               method          = "smc";
-               cpu_suspend     = <0x84000002>;
-               cpu_off         = <0x84000004>;
-               cpu_on          = <0x84000006>;
+               compatible = "arm,psci";
+               method = "smc";
+               cpu_suspend = <0x84000002>;
+               cpu_off = <0x84000004>;
+               cpu_on = <0x84000006>;
        };
 
        soc {
index a8d8bb0..f23a25c 100644 (file)
 &gpio1 {
        status = "okay";
 };
+
+&pcie0 {
+       status = "okay";
+};
+
+&pcie1 {
+       status = "okay";
+};
index 36597f5..7f83933 100644 (file)
@@ -3,6 +3,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/clock/en7523-clk.h>
 
 / {
        interrupt-parent = <&gic>;
                };
        };
 
+       scu: system-controller@1fa20000 {
+               compatible = "airoha,en7523-scu";
+               reg = <0x1fa20000 0x400>,
+                     <0x1fb00000 0x1000>;
+               #clock-cells = <1>;
+       };
+
        gic: interrupt-controller@9000000 {
                compatible = "arm,gic-v3";
                interrupt-controller;
                gpio-controller;
                #gpio-cells = <2>;
        };
+
+       pcie0: pcie@1fa91000 {
+               compatible = "airoha,en7523-pcie", "mediatek,mt7622-pcie";
+               device_type = "pci";
+               reg = <0x1fa91000 0x1000>;
+               reg-names = "port0";
+               linux,pci-domain = <0>;
+               #address-cells = <3>;
+               #size-cells = <2>;
+               interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "pcie_irq";
+               clocks = <&scu EN7523_CLK_PCIE>;
+               clock-names = "sys_ck0";
+               bus-range = <0x00 0xff>;
+               ranges = <0x82000000 0 0x20000000  0x20000000  0 0x8000000>;
+               status = "disabled";
+
+               #interrupt-cells = <1>;
+               interrupt-map-mask = <0 0 0 7>;
+               interrupt-map = <0 0 0 1 &pcie_intc0 0>,
+                               <0 0 0 2 &pcie_intc0 1>,
+                               <0 0 0 3 &pcie_intc0 2>,
+                               <0 0 0 4 &pcie_intc0 3>;
+               pcie_intc0: interrupt-controller {
+                       interrupt-controller;
+                       #address-cells = <0>;
+                       #interrupt-cells = <1>;
+               };
+       };
+
+       pcie1: pcie@1fa92000 {
+               compatible = "airoha,en7523-pcie", "mediatek,mt7622-pcie";
+               device_type = "pci";
+               reg = <0x1fa92000 0x1000>;
+               reg-names = "port1";
+               linux,pci-domain = <1>;
+               #address-cells = <3>;
+               #size-cells = <2>;
+               interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "pcie_irq";
+               clocks = <&scu EN7523_CLK_PCIE>;
+               clock-names = "sys_ck1";
+               bus-range = <0x00 0xff>;
+               ranges = <0x82000000 0 0x28000000  0x28000000  0 0x8000000>;
+               status = "disabled";
+
+               #interrupt-cells = <1>;
+               interrupt-map-mask = <0 0 0 7>;
+               interrupt-map = <0 0 0 1 &pcie_intc1 0>,
+                               <0 0 0 2 &pcie_intc1 1>,
+                               <0 0 0 3 &pcie_intc1 2>,
+                               <0 0 0 4 &pcie_intc1 3>;
+               pcie_intc1: interrupt-controller {
+                       interrupt-controller;
+                       #address-cells = <0>;
+                       #interrupt-cells = <1>;
+               };
+       };
 };
diff --git a/arch/arm/boot/dts/exynos-pinctrl.h b/arch/arm/boot/dts/exynos-pinctrl.h
new file mode 100644 (file)
index 0000000..e3a6df9
--- /dev/null
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Samsung Exynos DTS pinctrl constants
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ * Copyright (c) 2022 Linaro Ltd
+ * Author: Krzysztof Kozlowski <krzk@kernel.org>
+ */
+
+#ifndef __DTS_ARM_SAMSUNG_EXYNOS_PINCTRL_H__
+#define __DTS_ARM_SAMSUNG_EXYNOS_PINCTRL_H__
+
+#define EXYNOS_PIN_PULL_NONE           0
+#define EXYNOS_PIN_PULL_DOWN           1
+#define EXYNOS_PIN_PULL_UP             3
+
+/* Pin function in power down mode */
+#define EXYNOS_PIN_PDN_OUT0            0
+#define EXYNOS_PIN_PDN_OUT1            1
+#define EXYNOS_PIN_PDN_INPUT           2
+#define EXYNOS_PIN_PDN_PREV            3
+
+/* Drive strengths for Exynos3250, Exynos4 (all) and Exynos5250 */
+#define EXYNOS4_PIN_DRV_LV1            0
+#define EXYNOS4_PIN_DRV_LV2            2
+#define EXYNOS4_PIN_DRV_LV3            1
+#define EXYNOS4_PIN_DRV_LV4            3
+
+/* Drive strengths for Exynos5260 */
+#define EXYNOS5260_PIN_DRV_LV1         0
+#define EXYNOS5260_PIN_DRV_LV2         1
+#define EXYNOS5260_PIN_DRV_LV4         2
+#define EXYNOS5260_PIN_DRV_LV6         3
+
+/*
+ * Drive strengths for Exynos5410, Exynos542x, Exynos5800 and Exynos850 (except
+ * GPIO_HSI block)
+ */
+#define EXYNOS5420_PIN_DRV_LV1         0
+#define EXYNOS5420_PIN_DRV_LV2         1
+#define EXYNOS5420_PIN_DRV_LV3         2
+#define EXYNOS5420_PIN_DRV_LV4         3
+
+#define EXYNOS_PIN_FUNC_INPUT          0
+#define EXYNOS_PIN_FUNC_OUTPUT         1
+#define EXYNOS_PIN_FUNC_2              2
+#define EXYNOS_PIN_FUNC_3              3
+#define EXYNOS_PIN_FUNC_4              4
+#define EXYNOS_PIN_FUNC_5              5
+#define EXYNOS_PIN_FUNC_6              6
+#define EXYNOS_PIN_FUNC_EINT           0xf
+#define EXYNOS_PIN_FUNC_F              EXYNOS_PIN_FUNC_EINT
+
+#endif /* __DTS_ARM_SAMSUNG_EXYNOS_PINCTRL_H__ */
index 7b42962..0ac3f28 100644 (file)
 
 &pinctrl_1 {
        bten: bten-pins {
-               samsung,pins ="gpx1-7";
+               samsung,pins = "gpx1-7";
                samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
                samsung,pin-con-pdn = <EXYNOS_PIN_PDN_PREV>;
index cc30d15..011ba2e 100644 (file)
@@ -9,7 +9,7 @@
  * tree nodes are listed in this file.
  */
 
-#include <dt-bindings/pinctrl/samsung.h>
+#include "exynos-pinctrl.h"
 
 #define PIN_IN(_pin, _pull, _drv)                                      \
        pin- ## _pin {                                                  \
index 78dad23..326b9e0 100644 (file)
                        status = "disabled";
                };
 
-               mshc_0: mshc@12510000 {
+               mshc_0: mmc@12510000 {
                        compatible = "samsung,exynos5420-dw-mshc";
                        reg = <0x12510000 0x1000>;
                        interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>;
                        status = "disabled";
                };
 
-               mshc_1: mshc@12520000 {
+               mshc_1: mmc@12520000 {
                        compatible = "samsung,exynos5420-dw-mshc";
                        reg = <0x12520000 0x1000>;
                        interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
                        status = "disabled";
                };
 
-               mshc_2: mshc@12530000 {
+               mshc_2: mmc@12530000 {
                        compatible = "samsung,exynos5250-dw-mshc";
                        reg = <0x12530000 0x1000>;
                        interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
index 6f0ca33..5c4ecda 100644 (file)
                        status = "disabled";
                };
 
-               sdhci_0: sdhci@12510000 {
+               sdhci_0: mmc@12510000 {
                        compatible = "samsung,exynos4210-sdhci";
                        reg = <0x12510000 0x100>;
                        interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
                        status = "disabled";
                };
 
-               sdhci_1: sdhci@12520000 {
+               sdhci_1: mmc@12520000 {
                        compatible = "samsung,exynos4210-sdhci";
                        reg = <0x12520000 0x100>;
                        interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
                        status = "disabled";
                };
 
-               sdhci_2: sdhci@12530000 {
+               sdhci_2: mmc@12530000 {
                        compatible = "samsung,exynos4210-sdhci";
                        reg = <0x12530000 0x100>;
                        interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
                        status = "disabled";
                };
 
-               sdhci_3: sdhci@12540000 {
+               sdhci_3: mmc@12540000 {
                        compatible = "samsung,exynos4210-sdhci";
                        reg = <0x12540000 0x100>;
                        interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
index 3c0a18b..bba8501 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               vol-down {
+               key-vol-down {
                        gpios = <&gpx2 1 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEDOWN>;
                        label = "volume down";
                        debounce-interval = <10>;
                };
 
-               vol-up {
+               key-vol-up {
                        gpios = <&gpx2 0 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
                        label = "volume up";
                        debounce-interval = <10>;
                };
 
-               power {
+               key-power {
                        gpios = <&gpx2 7 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
                        label = "power";
                        wakeup-source;
                };
 
-               ok {
+               key-ok {
                        gpios = <&gpx3 5 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_OK>;
                        label = "ok";
index a08ce2f..5f37b75 100644 (file)
@@ -15,6 +15,7 @@
 #include "exynos4210.dtsi"
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
 #include "exynos-mfc-reserved-memory.dtsi"
 
 / {
        gpio-keys {
                compatible = "gpio-keys";
 
-               up {
+               key-up {
                        label = "Up";
                        gpios = <&gpx2 0 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_UP>;
                        wakeup-source;
                };
 
-               down {
+               key-down {
                        label = "Down";
                        gpios = <&gpx2 1 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_DOWN>;
                        wakeup-source;
                };
 
-               back {
+               key-back {
                        label = "Back";
                        gpios = <&gpx1 7 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_BACK>;
                        wakeup-source;
                };
 
-               home {
+               key-home {
                        label = "Home";
                        gpios = <&gpx1 6 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_HOME>;
                        wakeup-source;
                };
 
-               menu {
+               key-menu {
                        label = "Menu";
                        gpios = <&gpx1 5 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_MENU>;
@@ -86,6 +87,7 @@
                compatible = "gpio-leds";
                status {
                        gpios = <&gpx1 3 GPIO_ACTIVE_LOW>;
+                       function = LED_FUNCTION_HEARTBEAT;
                        linux,default-trigger = "heartbeat";
                };
        };
index 6373009..76f44ae 100644 (file)
@@ -11,7 +11,7 @@
  * tree nodes are listed in this file.
  */
 
-#include <dt-bindings/pinctrl/samsung.h>
+#include "exynos-pinctrl.h"
 
 &pinctrl_0 {
        gpa0: gpa0-gpio-bank {
index 01f44d9..b8e9dd2 100644 (file)
                vdd3-supply = <&vcclcd_reg>;
                vci-supply = <&vlcd_reg>;
                reset-gpios = <&gpy4 5 GPIO_ACTIVE_HIGH>;
-               power-on-delay= <50>;
+               power-on-delay = <50>;
                reset-delay = <100>;
                init-delay = <100>;
                flip-horizontal;
index 03dffc6..94122e9 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 /dts-v1/;
+#include <dt-bindings/leds/common.h>
 #include "exynos4412-midas.dtsi"
 
 / {
@@ -25,8 +26,9 @@
                pinctrl-1 = <&camera_flash_host>;
                pinctrl-2 = <&camera_flash_isp>;
 
-               flash-led {
-                       label = "flash";
+               led {
+                       function = LED_FUNCTION_FLASH;
+                       color = <LED_COLOR_ID_WHITE>;
                        led-max-microamp = <520833>;
                        flash-max-microamp = <1012500>;
                        flash-max-timeout-us = <1940000>;
                vdd3-supply = <&lcd_vdd3_reg>;
                vci-supply = <&ldo25_reg>;
                reset-gpios = <&gpf2 1 GPIO_ACTIVE_HIGH>;
-               power-on-delay= <50>;
+               power-on-delay = <50>;
                reset-delay = <100>;
                init-delay = <100>;
                flip-horizontal;
index a940628..202ab0f 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 /dts-v1/;
+#include <dt-bindings/leds/common.h>
 #include <dt-bindings/pwm/pwm.h>
 #include <dt-bindings/sound/samsung-i2s.h>
 #include "exynos4412-itop-scp-core.dtsi"
@@ -28,7 +29,8 @@
                compatible = "gpio-leds";
 
                led2 {
-                       label = "red:system";
+                       function = LED_FUNCTION_HEARTBEAT;
+                       color = <LED_COLOR_ID_RED>;
                        gpios = <&gpx1 0 GPIO_ACTIVE_HIGH>;
                        default-state = "off";
                        linux,default-trigger = "heartbeat";
@@ -36,6 +38,7 @@
 
                led3 {
                        label = "red:user";
+                       color = <LED_COLOR_ID_RED>;
                        gpios = <&gpk1 1 GPIO_ACTIVE_HIGH>;
                        default-state = "off";
                };
        gpio-keys {
                compatible = "gpio-keys";
 
-               home {
+               key-home {
                        label = "GPIO Key Home";
                        linux,code = <KEY_HOME>;
                        gpios = <&gpx1 1 GPIO_ACTIVE_LOW>;
                };
 
-               back {
+               key-back {
                        label = "GPIO Key Back";
                        linux,code = <KEY_BACK>;
                        gpios = <&gpx1 2 GPIO_ACTIVE_LOW>;
                };
 
-               sleep {
+               key-sleep {
                        label = "GPIO Key Sleep";
                        linux,code = <KEY_POWER>;
                        gpios = <&gpx3 3 GPIO_ACTIVE_LOW>;
                };
 
-               vol-up {
+               key-vol-up {
                        label = "GPIO Key Vol+";
                        linux,code = <KEY_UP>;
                        gpios = <&gpx2 1 GPIO_ACTIVE_LOW>;
                };
 
-               vol-down {
+               key-vol-down {
                        label = "GPIO Key Vol-";
                        linux,code = <KEY_DOWN>;
                        gpios = <&gpx2 0 GPIO_ACTIVE_LOW>;
index 23f50c9..b967397 100644 (file)
 /dts-v1/;
 #include "exynos4412.dtsi"
 #include "exynos4412-ppmu-common.dtsi"
+
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/input/input.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/clock/maxim,max77686.h>
-#include <dt-bindings/pinctrl/samsung.h>
+#include "exynos-pinctrl.h"
 
 / {
        compatible = "samsung,midas", "samsung,exynos4412", "samsung,exynos4";
index 36c369c..a5ad88b 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 /dts-v1/;
+#include <dt-bindings/leds/common.h>
 #include "exynos4412-odroid-common.dtsi"
 #include "exynos4412-prime.dtsi"
 
@@ -37,7 +38,8 @@
        leds {
                compatible = "gpio-leds";
                led1 {
-                       label = "led1:heart";
+                       function = LED_FUNCTION_HEARTBEAT;
+                       color = <LED_COLOR_ID_BLUE>;
                        gpios = <&gpc1 0 GPIO_ACTIVE_LOW>;
                        default-state = "on";
                        linux,default-trigger = "heartbeat";
index 1f17cc3..68d589e 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 /dts-v1/;
+#include <dt-bindings/leds/common.h>
 #include "exynos4412-odroid-common.dtsi"
 
 / {
        leds {
                compatible = "gpio-leds";
                led1 {
-                       label = "led1:heart";
+                       function = LED_FUNCTION_HEARTBEAT;
+                       color = <LED_COLOR_ID_BLUE>;
                        gpios = <&gpc1 0 GPIO_ACTIVE_LOW>;
                        default-state = "on";
                        linux,default-trigger = "heartbeat";
                };
                led2 {
                        label = "led2:mmc0";
+                       function = LED_FUNCTION_DISK_ACTIVITY;
                        gpios = <&gpc1 2 GPIO_ACTIVE_LOW>;
                        default-state = "on";
                        linux,default-trigger = "mmc0";
index 97f131b..7a515b8 100644 (file)
@@ -15,8 +15,8 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/input/linux-event-codes.h>
 #include <dt-bindings/interrupt-controller/irq.h>
-#include <dt-bindings/pinctrl/samsung.h>
 #include <dt-bindings/power/summit,smb347-charger.h>
+#include "exynos-pinctrl.h"
 
 / {
        compatible = "samsung,p4note", "samsung,exynos4412", "samsung,exynos4";
                regulator-always-on;
        };
 
+       panel_vdd: voltage-regulator-4 {
+               compatible = "regulator-fixed";
+               regulator-name = "LCD_ENABLE";
+               pinctrl-names = "default";
+               pinctrl-0 = <&lcd_enable>;
+               gpios = <&gpc0 1 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               regulator-boot-on;
+       };
+
        wlan_pwrseq: sdhci3-pwrseq {
                compatible = "mmc-pwrseq-simple";
                reset-gpios = <&gpm3 5 GPIO_ACTIVE_LOW>;
                        monitored-battery = <&battery_cell>;
                };
        };
+
+       panel {
+               compatible = "samsung,ltl101al01";
+               pinctrl-0 = <&lvds_nshdn>;
+               pinctrl-names = "default";
+               power-supply = <&panel_vdd>;
+               enable-gpios = <&gpm0 5 GPIO_ACTIVE_HIGH>;
+               backlight = <&backlight>;
+
+               port {
+                       lcd_ep: endpoint {
+                               remote-endpoint = <&fimd_ep>;
+                       };
+               };
+       };
+
+       backlight: backlight {
+               compatible = "pwm-backlight";
+               pinctrl-0 = <&led_bl_reset>;
+               pinctrl-names = "default";
+               enable-gpios = <&gpm0 1 GPIO_ACTIVE_HIGH>;
+               pwms = <&pwm 1 78770 0>;
+               brightness-levels = <0 48 128 255>;
+               num-interpolated-steps = <8>;
+               default-brightness-level = <12>;
+       };
 };
 
 &adc {
 };
 
 &fimd {
-       pinctrl-0 = <&lcd_clk &lcd_data24 &pwm1_out>;
+       pinctrl-0 = <&lcd_clk &lcd_data24>;
        pinctrl-names = "default";
+       #address-cells = <1>;
+       #size-cells = <0>;
        status = "okay";
 
-       display-timings {
-               timing0 {
-                       clock-frequency = <66666666>;
-                       hactive = <1280>;
-                       vactive = <800>;
-                       hfront-porch = <18>;
-                       hback-porch = <36>;
-                       hsync-len = <16>;
-                       vback-porch = <16>;
-                       vfront-porch = <4>;
-                       vsync-len = <3>;
-                       hsync-active = <1>;
+       samsung,invert-vclk;
+
+       port@3 {
+               reg = <3>;
+
+               fimd_ep: endpoint {
+                       remote-endpoint = <&lcd_ep>;
                };
        };
 };
                samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
        };
 
+       lcd_enable: lcd-enable-pins {
+               samsung,pins = "gpc0-1";
+               samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+               samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+       };
+
        sleep0: sleep-state {
                PIN_SLP(gpa0-0, INPUT, NONE);
                PIN_SLP(gpa0-1, OUT0, NONE);
                /* 0 = CP, 1 = AP (serial output) */
        };
 
+       led_bl_reset: led-bl-reset-pins {
+               samsung,pins = "gpm0-1";
+               samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+               samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+       };
+
        tsp_rst: tsp-rst-pins {
                samsung,pins = "gpm0-4";
                samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
        };
 
+       lvds_nshdn: lvds-nshdn-pins {
+               samsung,pins = "gpm0-5";
+               samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+               samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+       };
+
        tsp_irq: tsp-irq-pins {
                samsung,pins = "gpm2-3";
                samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
        assigned-clock-parents = <&clock CLK_XUSBXTI>;
 };
 
+&pwm {
+       pinctrl-0 = <&pwm1_out>;
+       pinctrl-names = "default";
+       samsung,pwm-outputs = <1>;
+       status = "okay";
+};
+
 &rtc {
        clocks = <&clock CLK_RTC>, <&max77686 MAX77686_CLK_AP>;
        clock-names = "rtc", "rtc_src";
index 88b8afd..58847d4 100644 (file)
@@ -9,7 +9,7 @@
  * tree nodes are listed in this file.
  */
 
-#include <dt-bindings/pinctrl/samsung.h>
+#include "exynos-pinctrl.h"
 
 #define PIN_SLP(_pin, _mode, _pull)                                    \
        _pin {                                                          \
index 017b261..04388c5 100644 (file)
@@ -11,6 +11,7 @@
 /dts-v1/;
 #include "exynos4412.dtsi"
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
 
 / {
        model = "FriendlyARM TINY4412 board based on Exynos4412";
@@ -30,6 +31,7 @@
 
                led1 {
                        label = "led1";
+                       function = LED_FUNCTION_HEARTBEAT;
                        gpios = <&gpm4 0 GPIO_ACTIVE_LOW>;
                        default-state = "off";
                        linux,default-trigger = "heartbeat";
@@ -49,6 +51,7 @@
 
                led4 {
                        label = "led4";
+                       function = LED_FUNCTION_DISK_ACTIVITY;
                        gpios = <&gpm4 3 GPIO_ACTIVE_LOW>;
                        default-state = "off";
                        linux,default-trigger = "mmc0";
index 9ce9fb3..c8da0d4 100644 (file)
@@ -89,7 +89,7 @@
                        compatible = "arm,gic-400", "arm,cortex-a15-gic";
                        #interrupt-cells = <3>;
                        interrupt-controller;
-                       reg =   <0x10481000 0x1000>,
+                       reg = <0x10481000 0x1000>,
                                <0x10482000 0x2000>,
                                <0x10484000 0x2000>,
                                <0x10486000 0x2000>;
index f7795f2..71c0e87 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               menu {
+               key-menu {
                        label = "SW-TACT2";
                        gpios = <&gpx1 4 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_MENU>;
                        wakeup-source;
                };
 
-               home {
+               key-home {
                        label = "SW-TACT3";
                        gpios = <&gpx1 5 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_HOME>;
                        wakeup-source;
                };
 
-               up {
+               key-up {
                        label = "SW-TACT4";
                        gpios = <&gpx1 6 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_UP>;
                        wakeup-source;
                };
 
-               down {
+               key-down {
                        label = "SW-TACT5";
                        gpios = <&gpx1 7 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_DOWN>;
                        wakeup-source;
                };
 
-               back {
+               key-back {
                        label = "SW-TACT6";
                        gpios = <&gpx2 0 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_BACK>;
                        wakeup-source;
                };
 
-               wakeup {
+               key-wakeup {
                        label = "SW-TACT7";
                        gpios = <&gpx2 1 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_WAKEUP>;
index 918947a..48732ed 100644 (file)
@@ -9,7 +9,7 @@
  * tree nodes are listed in this file.
  */
 
-#include <dt-bindings/pinctrl/samsung.h>
+#include "exynos-pinctrl.h"
 
 &pinctrl_0 {
        gpa0: gpa0-gpio-bank {
index c15ecfc..3d84b9c 100644 (file)
@@ -32,7 +32,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&power_key_irq &lid_irq>;
 
-               power {
+               power-key {
                        label = "Power";
                        gpios = <&gpx1 3 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
index 24609bb..5eca10e 100644 (file)
@@ -33,7 +33,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&power_key_irq>, <&lid_irq>;
 
-               power {
+               power-key {
                        label = "Power";
                        gpios = <&gpx1 3 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
index 150607f..43e4a54 100644 (file)
@@ -9,7 +9,7 @@
  * tree nodes are listed in this file.
  */
 
-#include <dt-bindings/pinctrl/samsung.h>
+#include "exynos-pinctrl.h"
 
 &pinctrl_0 {
        gpa0: gpa0-gpio-bank {
index 6c7814b..f7b9233 100644 (file)
@@ -6,7 +6,7 @@
  *              https://www.hardkernel.com
  */
 
-#include <dt-bindings/pinctrl/samsung.h>
+#include "exynos-pinctrl.h"
 
 &pinctrl_0 {
        gpa0: gpa0-gpio-bank {
index 946b791..55b7759 100644 (file)
@@ -42,7 +42,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               wakeup {
+               key-wakeup {
                        label = "SW-TACT1";
                        gpios = <&gpx2 7 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_WAKEUP>;
index d6434ec..9e21234 100644 (file)
@@ -60,7 +60,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&power_key_irq &lid_irq>;
 
-               power {
+               power-key {
                        label = "Power";
                        gpios = <&gpx1 2 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
index 546ba27..14cf9c4 100644 (file)
@@ -9,7 +9,7 @@
  * tree nodes are listed in this file.
  */
 
-#include <dt-bindings/pinctrl/samsung.h>
+#include "exynos-pinctrl.h"
 
 &pinctrl_0 {
        gpy7: gpy7-gpio-bank {
index d91f7fa..3de7019 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 /dts-v1/;
+#include <dt-bindings/leds/common.h>
 #include "exynos5422-odroid-core.dtsi"
 
 / {
@@ -19,7 +20,8 @@
                compatible = "pwm-leds";
 
                led-1 {
-                       label = "blue:heartbeat";
+                       function = LED_FUNCTION_HEARTBEAT;
+                       color = <LED_COLOR_ID_BLUE>;
                        pwms = <&pwm 2 2000000 0>;
                        pwm-names = "pwm2";
                        max-brightness = <255>;
index 1c24f9b..f5fb617 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 /dts-v1/;
+#include <dt-bindings/leds/common.h>
 #include <dt-bindings/sound/samsung-i2s.h>
 #include "exynos5422-odroidxu3-common.dtsi"
 
@@ -21,7 +22,8 @@
                compatible = "pwm-leds";
 
                led-1 {
-                       label = "blue:heartbeat";
+                       function = LED_FUNCTION_HEARTBEAT;
+                       color = <LED_COLOR_ID_BLUE>;
                        pwms = <&pwm 2 2000000 0>;
                        pwm-names = "pwm2";
                        max-brightness = <255>;
index 982752e..8c0e171 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
 
 / {
        led-controller-1 {
@@ -16,6 +17,8 @@
 
                led-1 {
                        label = "green:mmc0";
+                       function = LED_FUNCTION_DISK_ACTIVITY;
+                       color = <LED_COLOR_ID_GREEN>;
                        pwms = <&pwm 1 2000000 0>;
                        pwm-names = "pwm1";
                        /*
@@ -27,7 +30,8 @@
                };
 
                led-2 {
-                       label = "blue:heartbeat";
+                       function = LED_FUNCTION_HEARTBEAT;
+                       color = <LED_COLOR_ID_BLUE>;
                        pwms = <&pwm 2 2000000 0>;
                        pwm-names = "pwm2";
                        max-brightness = <255>;
@@ -40,6 +44,8 @@
 
                led-3 {
                        label = "red:microSD";
+                       function = LED_FUNCTION_DISK_ACTIVITY;
+                       color = <LED_COLOR_ID_RED>;
                        gpios = <&gpx2 3 GPIO_ACTIVE_HIGH>;
                        default-state = "off";
                        linux,default-trigger = "mmc1";
index 4ee7628..0ebcb66 100644 (file)
@@ -59,7 +59,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&power_key_irq &lid_irq>;
 
-               power {
+               power-key {
                        label = "Power";
                        gpios = <&gpx1 2 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
index fa8044c..bc4de0c 100644 (file)
@@ -68,7 +68,7 @@
                };
        };
 
-       soc {
+       soc: soc {
                #address-cells = <1>;
                #size-cells = <1>;
                compatible = "simple-bus";
index b660c7d..e140307 100644 (file)
                };
        };
 
-       soc {
+       soc: soc {
                #address-cells = <1>;
                #size-cells = <1>;
                compatible = "simple-bus";
                interrupt-parent = <&aitc>;
                ranges;
 
-               aipi@10000000 { /* AIPI1 */
+               aipi1: aipi@10000000 { /* AIPI1 */
                        compatible = "fsl,aipi-bus", "simple-bus";
                        #address-cells = <1>;
                        #size-cells = <1>;
                        };
                };
 
-               aipi@10020000 { /* AIPI2 */
+               aipi2: aipi@10020000 { /* AIPI2 */
                        compatible = "fsl,aipi-bus", "simple-bus";
                        #address-cells = <1>;
                        #size-cells = <1>;
index 2adb923..5c4938b 100644 (file)
@@ -48,7 +48,7 @@
                reg = <0x68000000 0x100000>;
        };
 
-       soc {
+       soc: soc {
                #address-cells = <1>;
                #size-cells = <1>;
                compatible = "simple-bus";
@@ -63,7 +63,7 @@
                        ranges = <0 0x1fffc000 0x4000>;
                };
 
-               bus@43f00000 { /* AIPS1 */
+               aips1: bus@43f00000 { /* AIPS1 */
                        compatible = "fsl,aips-bus", "simple-bus";
                        #address-cells = <1>;
                        #size-cells = <1>;
index be0de0f..c0c7575 100644 (file)
                status = "okay";
        };
 
-       soc {
+       soc: soc {
                #address-cells = <1>;
                #size-cells = <1>;
                compatible = "simple-bus";
                interrupt-parent = <&tzic>;
                ranges;
 
-               bus@50000000 { /* AIPS1 */
+               aips1: bus@50000000 { /* AIPS1 */
                        compatible = "fsl,aips-bus", "simple-bus";
                        #address-cells = <1>;
                        #size-cells = <1>;
                        };
                };
 
-               bus@60000000 {  /* AIPS2 */
+               aips2: bus@60000000 {   /* AIPS2 */
                        compatible = "fsl,aips-bus", "simple-bus";
                        #address-cells = <1>;
                        #size-cells = <1>;
index 85654d6..f740872 100644 (file)
                        pinctrl-names = "default";
                        pinctrl-0 = <&pinctrl_interrupt_fpga>;
                        interrupt-parent = <&gpio2>;
-                       interrupts= <9 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupts = <9 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                };
index 1e20a66..592d9c2 100644 (file)
                ports = <&ipu_di0>, <&ipu_di1>;
        };
 
-       soc {
+       soc: soc {
                #address-cells = <1>;
                #size-cells = <1>;
                compatible = "simple-bus";
                        };
                };
 
-               bus@70000000 { /* AIPS1 */
+               aips1: bus@70000000 { /* AIPS1 */
                        compatible = "fsl,aips-bus", "simple-bus";
                        #address-cells = <1>;
                        #size-cells = <1>;
                        };
                };
 
-               bus@80000000 {  /* AIPS2 */
+               aips2: bus@80000000 {   /* AIPS2 */
                        compatible = "fsl,aips-bus", "simple-bus";
                        #address-cells = <1>;
                        #size-cells = <1>;
index 67487f3..b7a6469 100644 (file)
                status = "okay";
        };
 
-       soc {
+       soc: soc {
                #address-cells = <1>;
                #size-cells = <1>;
                compatible = "simple-bus";
                        clock-names = "core_clk", "mem_iface_clk";
                };
 
-               bus@50000000 { /* AIPS1 */
+               aips1: bus@50000000 { /* AIPS1 */
                        compatible = "fsl,aips-bus", "simple-bus";
                        #address-cells = <1>;
                        #size-cells = <1>;
                        };
                };
 
-               bus@60000000 {  /* AIPS2 */
+               aips2: bus@60000000 {   /* AIPS2 */
                        compatible = "fsl,aips-bus", "simple-bus";
                        #address-cells = <1>;
                        #size-cells = <1>;
index c4ce23d..522660c 100644 (file)
                compatible = "ti,tsc2046e-adc";
                reg = <0>;
                pinctrl-0 = <&pinctrl_tsc2046>;
-               pinctrl-names ="default";
+               pinctrl-names = "default";
                spi-max-frequency = <1000000>;
                interrupts-extended = <&gpio3 20 IRQ_TYPE_LEVEL_LOW>;
                #io-channel-cells = <1>;
index b86deeb..0a0b7ac 100644 (file)
                compatible = "ti,tsc2046e-adc";
                reg = <0>;
                pinctrl-0 = <&pinctrl_tsc>;
-               pinctrl-names ="default";
+               pinctrl-names = "default";
                spi-max-frequency = <1000000>;
                interrupts-extended = <&gpio3 20 IRQ_TYPE_LEVEL_LOW>;
                #io-channel-cells = <1>;
index 516ec91..779b528 100644 (file)
                compatible = "ti,tsc2046e-adc";
                reg = <0>;
                pinctrl-0 = <&pinctrl_touchscreen>;
-               pinctrl-names ="default";
+               pinctrl-names = "default";
                spi-max-frequency = <1000000>;
                interrupts-extended = <&gpio5 8 IRQ_TYPE_LEVEL_LOW>;
                #io-channel-cells = <1>;
index fdd81fd..8e0ed20 100644 (file)
@@ -80,7 +80,7 @@
                };
        };
 
-       soc {
+       soc: soc {
                ocram: sram@900000 {
                        compatible = "mmio-sram";
                        reg = <0x00900000 0x20000>;
index a0683b4..fa160a3 100644 (file)
@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: GPL-2.0+ OR MIT
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
 /*
- * Copyright 2014-2020 Toradex
+ * Copyright 2014-2022 Toradex
  * Copyright 2012 Freescale Semiconductor, Inc.
  * Copyright 2011 Linaro Ltd.
  */
                stdout-path = "serial0:115200n8";
        };
 
-       gpio-keys {
-               compatible = "gpio-keys";
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_gpio_keys>;
-
-               wakeup {
-                       label = "Wake-Up";
-                       gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_WAKEUP>;
-                       debounce-interval = <10>;
-                       wakeup-source;
-               };
-       };
-
-       lcd_display: disp0 {
-               compatible = "fsl,imx-parallel-display";
-               #address-cells = <1>;
-               #size-cells = <0>;
-               interface-pix-fmt = "rgb24";
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_ipu1_lcdif>;
-               status = "okay";
-
-               port@0 {
-                       reg = <0>;
-
-                       lcd_display_in: endpoint {
-                               remote-endpoint = <&ipu1_di1_disp1>;
-                       };
-               };
-
-               port@1 {
-                       reg = <1>;
-
-                       lcd_display_out: endpoint {
-                               remote-endpoint = <&lcd_panel_in>;
-                       };
-               };
-       };
-
-       panel: panel {
-               /*
-                * edt,et057090dhu: EDT 5.7" LCD TFT
-                * edt,et070080dh6: EDT 7.0" LCD TFT
-                */
-               compatible = "edt,et057090dhu";
-               backlight = <&backlight>;
-               power-supply = <&reg_3v3_sw>;
-
-               port {
-                       lcd_panel_in: endpoint {
-                               remote-endpoint = <&lcd_display_out>;
-                       };
-               };
-       };
-
        reg_pcie_switch: regulator-pcie-switch {
                compatible = "regulator-fixed";
-               regulator-name = "pcie_switch";
-               regulator-min-microvolt = <1800000>;
-               regulator-max-microvolt = <1800000>;
+               enable-active-high;
                gpio = <&gpio1 2 GPIO_ACTIVE_HIGH>;
+               regulator-max-microvolt = <1800000>;
+               regulator-min-microvolt = <1800000>;
+               regulator-name = "pcie_switch";
                startup-delay-us = <100000>;
-               enable-active-high;
                status = "okay";
        };
 
        reg_3v3_sw: regulator-3v3-sw {
                compatible = "regulator-fixed";
-               regulator-name = "3.3V_SW";
-               regulator-min-microvolt = <3300000>;
-               regulator-max-microvolt = <3300000>;
                regulator-always-on;
+               regulator-max-microvolt = <3300000>;
+               regulator-min-microvolt = <3300000>;
+               regulator-name = "3.3V_SW";
        };
 };
 
-&backlight {
-       brightness-levels = <0 127 191 223 239 247 251 255>;
-       default-brightness-level = <1>;
-       power-supply = <&reg_3v3_sw>;
-       status = "okay";
-};
-
 &can1 {
        xceiver-supply = <&reg_3v3_sw>;
        status = "okay";
        status = "okay";
 };
 
-&hdmi {
-       status = "okay";
-};
-
 /* I2C1_SDA/SCL on MXM3 209/211 (e.g. RTC on carrier board) */
 &i2c1 {
        status = "okay";
 
-       /*
-        * Touchscreen is using SODIMM 28/30, also used for PWM<B>, PWM<C>,
-        * aka pwm2, pwm3. so if you enable touchscreen, disable the pwms
-        */
-       touchscreen@4a {
-               compatible = "atmel,maxtouch";
-               reg = <0x4a>;
-               interrupt-parent = <&gpio6>;
-               interrupts = <10 IRQ_TYPE_EDGE_FALLING>;
-               reset-gpios = <&gpio6 9 GPIO_ACTIVE_LOW>; /* SODIMM 13 */
-               status = "disabled";
-       };
-
        pcie-switch@58 {
                compatible = "plx,pex8605";
                reg = <0x58>;
        status = "okay";
 };
 
-&ipu1_di1_disp1 {
-       remote-endpoint = <&lcd_display_in>;
-};
-
-&ldb {
-       status = "okay";
-};
-
 &pcie {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_reset_moci>;
        status = "okay";
 };
 
-&reg_usb_otg_vbus {
+&reg_usb_host_vbus {
        status = "okay";
 };
 
-&reg_usb_host_vbus {
+&reg_usb_otg_vbus {
        status = "okay";
 };
 
 
 /* MMC1 */
 &usdhc1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_usdhc1_4bit &pinctrl_usdhc1_8bit &pinctrl_mmc_cd>;
-       cd-gpios = <&gpio4 20 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
 
 /* SD1 */
 &usdhc2 {
+       cd-gpios = <&gpio6 14 GPIO_ACTIVE_LOW>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc2 &pinctrl_sd_cd>;
-       cd-gpios = <&gpio6 14 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
-
-&iomuxc {
-       /*
-        * Mux the Apalis GPIOs
-        */
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_apalis_gpio1 &pinctrl_apalis_gpio2
-                    &pinctrl_apalis_gpio3 &pinctrl_apalis_gpio4
-                    &pinctrl_apalis_gpio5 &pinctrl_apalis_gpio6
-                    &pinctrl_apalis_gpio7 &pinctrl_apalis_gpio8
-                   >;
-};
index 86e8478..44637d6 100644 (file)
-// SPDX-License-Identifier: GPL-2.0+ OR MIT
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
 /*
- * Copyright 2014-2020 Toradex
+ * Copyright 2014-2022 Toradex
  * Copyright 2012 Freescale Semiconductor, Inc.
  * Copyright 2011 Linaro Ltd.
  */
 
-/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-ixora-v1.2.dts"
 
 / {
        model = "Toradex Apalis iMX6Q/D Module on Ixora Carrier Board V1.1";
-       compatible = "toradex,apalis_imx6q-ixora-v1.1",
-                    "toradex,apalis_imx6q-ixora", "toradex,apalis_imx6q",
+       compatible = "toradex,apalis_imx6q-ixora-v1.1", "toradex,apalis_imx6q",
                     "fsl,imx6q";
 
-       aliases {
-               i2c0 = &i2c1;
-               i2c1 = &i2c3;
-               i2c2 = &i2c2;
-               rtc0 = &rtc_i2c;
-               rtc1 = &snvs_rtc;
-       };
-
-       chosen {
-               stdout-path = "serial0:115200n8";
-       };
-
-       gpio-keys {
-               compatible = "gpio-keys";
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_gpio_keys>;
-
-               wakeup {
-                       label = "Wake-Up";
-                       gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_WAKEUP>;
-                       debounce-interval = <10>;
-                       wakeup-source;
-               };
-       };
-
-       lcd_display: disp0 {
-               compatible = "fsl,imx-parallel-display";
-               #address-cells = <1>;
-               #size-cells = <0>;
-               interface-pix-fmt = "rgb24";
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_ipu1_lcdif>;
-               status = "okay";
-
-               port@0 {
-                       reg = <0>;
-
-                       lcd_display_in: endpoint {
-                               remote-endpoint = <&ipu1_di1_disp1>;
-                       };
-               };
-
-               port@1 {
-                       reg = <1>;
-
-                       lcd_display_out: endpoint {
-                               remote-endpoint = <&lcd_panel_in>;
-                       };
-               };
-       };
 
-       panel: panel {
-               /*
-                * edt,et057090dhu: EDT 5.7" LCD TFT
-                * edt,et070080dh6: EDT 7.0" LCD TFT
-                */
-               compatible = "edt,et057090dhu";
-               backlight = <&backlight>;
-
-               port {
-                       lcd_panel_in: endpoint {
-                               remote-endpoint = <&lcd_display_out>;
-                       };
-               };
-       };
-
-       leds {
-               compatible = "gpio-leds";
-
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_leds_ixora>;
-
-               led4-green {
-                       label = "LED_4_GREEN";
-                       gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>;
-               };
-
-               led4-red {
-                       label = "LED_4_RED";
-                       gpios = <&gpio1 12 GPIO_ACTIVE_HIGH>;
-               };
-
-               led5-green {
-                       label = "LED_5_GREEN";
-                       gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>;
-               };
-
-               led5-red {
-                       label = "LED_5_RED";
-                       gpios = <&gpio2 2 GPIO_ACTIVE_HIGH>;
-               };
-       };
 };
 
-&backlight {
-       brightness-levels = <0 127 191 223 239 247 251 255>;
-       default-brightness-level = <1>;
-       status = "okay";
-};
+/delete-node/ &eeprom;
+/delete-node/ &reg_3v3_vmmc;
+/delete-node/ &reg_can1_supply;
+/delete-node/ &reg_can2_supply;
 
 &can1 {
-       status = "okay";
+       /delete-property/ xceiver-supply;
 };
 
 &can2 {
-       status = "okay";
-};
-
-&hdmi {
-       status = "okay";
-};
-
-/* I2C1_SDA/SCL on MXM3 209/211 (e.g. RTC on carrier board) */
-&i2c1 {
-       status = "okay";
-
-       /*
-        * Touchscreen is using SODIMM 28/30, also used for PWM<B>, PWM<C>,
-        * aka pwm2, pwm3. so if you enable touchscreen, disable the pwms
-        */
-       touchscreen@4a {
-               compatible = "atmel,maxtouch";
-               reg = <0x4a>;
-               interrupt-parent = <&gpio6>;
-               interrupts = <10 IRQ_TYPE_EDGE_FALLING>;
-               reset-gpios = <&gpio6 9 GPIO_ACTIVE_LOW>; /* SODIMM 13 */
-               status = "disabled";
-       };
-
-       /* 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";
-};
-
-&ipu1_di1_disp1 {
-       remote-endpoint = <&lcd_display_in>;
-};
-
-&ldb {
-       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;
-       status = "okay";
-};
-
-&pwm1 {
-       status = "okay";
-};
-
-&pwm2 {
-       status = "okay";
-};
-
-&pwm3 {
-       status = "okay";
-};
-
-&pwm4 {
-       status = "okay";
-};
-
-&reg_usb_otg_vbus {
-       status = "okay";
-};
-
-&reg_usb_host_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 {
-       vbus-supply = <&reg_usb_host_vbus>;
-       status = "okay";
-};
-
-&usbotg {
-       vbus-supply = <&reg_usb_otg_vbus>;
-       status = "okay";
+       /delete-property/ xceiver-supply;
 };
 
 /* MMC1 */
 &usdhc1 {
+       /delete-property/ cap-power-off-card;
+       /delete-property/ pinctrl-1;
+       /delete-property/ vmmc-supply;
        pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_usdhc1_4bit &pinctrl_mmc_cd>;
-       cd-gpios = <&gpio4 20 GPIO_ACTIVE_LOW>;
-       bus-width = <4>;
-       status = "okay";
-};
-
-&iomuxc {
-       /*
-        * Mux the Apalis GPIOs
-        */
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_apalis_gpio1 &pinctrl_apalis_gpio2
-                    &pinctrl_apalis_gpio3 &pinctrl_apalis_gpio4
-                    &pinctrl_apalis_gpio5 &pinctrl_apalis_gpio6
-                    &pinctrl_apalis_gpio7 &pinctrl_apalis_gpio8
-                   >;
-
-       pinctrl_leds_ixora: ledsixoragrp {
-               fsl,pins = <
-                       MX6QDL_PAD_SD2_DAT1__GPIO1_IO14 0x1b0b0
-                       MX6QDL_PAD_SD2_DAT3__GPIO1_IO12 0x1b0b0
-                       MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x1b0b0
-                       MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x1b0b0
-               >;
-       };
 };
diff --git a/arch/arm/boot/dts/imx6q-apalis-ixora-v1.2.dts b/arch/arm/boot/dts/imx6q-apalis-ixora-v1.2.dts
new file mode 100644 (file)
index 0000000..f9f7d99
--- /dev/null
@@ -0,0 +1,276 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright 2014-2022 Toradex
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2011 Linaro Ltd.
+ */
+
+/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"
+
+/ {
+       model = "Toradex Apalis iMX6Q/D Module on Ixora Carrier Board V1.2";
+       compatible = "toradex,apalis_imx6q-ixora-v1.2", "toradex,apalis_imx6q",
+                    "fsl,imx6q";
+
+       aliases {
+               i2c0 = &i2c1;
+               i2c1 = &i2c3;
+               i2c2 = &i2c2;
+               rtc0 = &rtc_i2c;
+               rtc1 = &snvs_rtc;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_leds_ixora>;
+
+               led4-green {
+                       gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>;
+                       label = "LED_4_GREEN";
+               };
+
+               led4-red {
+                       gpios = <&gpio1 12 GPIO_ACTIVE_HIGH>;
+                       label = "LED_4_RED";
+               };
+
+               led5-green {
+                       gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>;
+                       label = "LED_5_GREEN";
+               };
+
+               led5-red {
+                       gpios = <&gpio2 2 GPIO_ACTIVE_HIGH>;
+                       label = "LED_5_RED";
+               };
+       };
+
+       reg_3v3_vmmc: regulator-3v3-vmmc {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio2 0 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_enable_3v3_vmmc>;
+               regulator-max-microvolt = <3300000>;
+               regulator-min-microvolt = <3300000>;
+               regulator-name = "3v3_vmmc";
+               startup-delay-us = <100>;
+       };
+
+       reg_can1_supply: regulator-can1-supply {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio2 3 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_enable_can1_power>;
+               regulator-name = "can1_supply";
+       };
+
+       reg_can2_supply: regulator-can2-supply {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio3 15 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_enable_can2_power>;
+               regulator-name = "can2_supply";
+       };
+};
+
+&can1 {
+       xceiver-supply = <&reg_can1_supply>;
+       status = "okay";
+};
+
+&can2 {
+       xceiver-supply = <&reg_can2_supply>;
+       status = "okay";
+};
+
+&gpio1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart24_forceoff>;
+
+       /*
+        * uart-2-4-on-x21-enable-hog enables the UART transceiver for Apalis
+        * UART2 and UART3. If one wants to disable the transceiver force
+        * the GPIO to output-low, if one wants to control the transceiver
+        * from user space delete the hog node.
+        */
+       uart-2-4-on-x21-enable-hog {
+               gpio-hog;
+               gpios = <11 GPIO_ACTIVE_HIGH>; /* MXM3 180 */
+               output-high;
+       };
+};
+
+/* I2C1_SDA/SCL on MXM3 209/211 (e.g. RTC on carrier board) */
+&i2c1 {
+       status = "okay";
+
+       /* M41T0M6 real time clock on carrier board */
+       rtc_i2c: rtc@68 {
+               compatible = "st,m41t0";
+               reg = <0x68>;
+       };
+
+       eeprom: eeprom@50 {
+               compatible = "atmel,24c02";
+               reg = <0x50>;
+               pagesize = <16>;
+       };
+};
+
+/*
+ * 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;
+       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 {
+       vbus-supply = <&reg_usb_host_vbus>;
+       status = "okay";
+};
+
+&usbotg {
+       vbus-supply = <&reg_usb_otg_vbus>;
+       status = "okay";
+};
+
+/* MMC1 */
+&usdhc1 {
+       pinctrl-names = "default", "sleep";
+       pinctrl-0 = <&pinctrl_usdhc1_4bit &pinctrl_mmc_cd>;
+       pinctrl-1 = <&pinctrl_usdhc1_4bit_sleep &pinctrl_mmc_cd_sleep>;
+       bus-width = <4>;
+       cap-power-off-card;
+       vmmc-supply = <&reg_3v3_vmmc>;
+       status = "okay";
+};
+
+&iomuxc {
+       pinctrl_enable_3v3_vmmc: enable3v3vmmcgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x1b0b0
+               >;
+       };
+
+       pinctrl_enable_can1_power: enablecan1powergrp {
+               fsl,pins = <
+                       MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x1b0b0
+               >;
+       };
+
+       pinctrl_enable_can2_power: enablecan2powergrp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_DA15__GPIO3_IO15 0x1b0b0
+               >;
+       };
+
+       pinctrl_uart24_forceoff: uart24forceoffgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD2_CMD__GPIO1_IO11 0x1b0b0
+               >;
+       };
+
+       pinctrl_leds_ixora: ledsixoragrp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD2_DAT1__GPIO1_IO14 0x1b0b0
+                       MX6QDL_PAD_SD2_DAT3__GPIO1_IO12 0x1b0b0
+                       MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x1b0b0
+                       MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x1b0b0
+               >;
+       };
+
+       pinctrl_mmc_cd_sleep: mmccdslpgrp {
+               fsl,pins = <
+                        /* MMC1 CD */
+                       MX6QDL_PAD_DI0_PIN4__GPIO4_IO20 0x0
+               >;
+       };
+
+       pinctrl_usdhc1_4bit_sleep: usdhc1-4bitslpgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_SD1_CMD__SD1_CMD     0x3000
+                       MX6QDL_PAD_SD1_CLK__SD1_CLK     0x3000
+                       MX6QDL_PAD_SD1_DAT0__SD1_DATA0  0x3000
+                       MX6QDL_PAD_SD1_DAT1__SD1_DATA1  0x3000
+                       MX6QDL_PAD_SD1_DAT2__SD1_DATA2  0x3000
+                       MX6QDL_PAD_SD1_DAT3__SD1_DATA3  0x3000
+               >;
+       };
+};
index 62e7277..ce39c6a 100644 (file)
@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: GPL-2.0+ OR MIT
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
 /*
- * Copyright 2014-2020 Toradex
+ * Copyright 2014-2022 Toradex
  * Copyright 2012 Freescale Semiconductor, Inc.
  * Copyright 2011 Linaro Ltd.
  */
                stdout-path = "serial0:115200n8";
        };
 
-       gpio-keys {
-               compatible = "gpio-keys";
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_gpio_keys>;
-
-               wakeup {
-                       label = "Wake-Up";
-                       gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
-                       linux,code = <KEY_WAKEUP>;
-                       debounce-interval = <10>;
-                       wakeup-source;
-               };
-       };
-
-       lcd_display: disp0 {
-               compatible = "fsl,imx-parallel-display";
-               #address-cells = <1>;
-               #size-cells = <0>;
-               interface-pix-fmt = "rgb24";
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_ipu1_lcdif>;
-               status = "okay";
-
-               port@0 {
-                       reg = <0>;
-
-                       lcd_display_in: endpoint {
-                               remote-endpoint = <&ipu1_di1_disp1>;
-                       };
-               };
-
-               port@1 {
-                       reg = <1>;
-
-                       lcd_display_out: endpoint {
-                               remote-endpoint = <&lcd_panel_in>;
-                       };
-               };
-       };
-
-       panel: panel {
-               /*
-                * edt,et057090dhu: EDT 5.7" LCD TFT
-                * edt,et070080dh6: EDT 7.0" LCD TFT
-                */
-               compatible = "edt,et057090dhu";
-               backlight = <&backlight>;
-
-               port {
-                       lcd_panel_in: endpoint {
-                               remote-endpoint = <&lcd_display_out>;
-                       };
-               };
-       };
-
        leds {
                compatible = "gpio-leds";
-
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_leds_ixora>;
 
                led4-green {
-                       label = "LED_4_GREEN";
                        gpios = <&gpio1 17 GPIO_ACTIVE_HIGH>;
+                       label = "LED_4_GREEN";
                };
 
                led4-red {
-                       label = "LED_4_RED";
                        gpios = <&gpio1 21 GPIO_ACTIVE_HIGH>;
+                       label = "LED_4_RED";
                };
 
                led5-green {
-                       label = "LED_5_GREEN";
                        gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>;
+                       label = "LED_5_GREEN";
                };
 
                led5-red {
-                       label = "LED_5_RED";
                        gpios = <&gpio2 2 GPIO_ACTIVE_HIGH>;
+                       label = "LED_5_RED";
                };
        };
 };
 
-&backlight {
-       brightness-levels = <0 127 191 223 239 247 251 255>;
-       default-brightness-level = <1>;
-       status = "okay";
-};
-
 &can1 {
        status = "okay";
 };
        status = "okay";
 };
 
-&hdmi {
-       status = "okay";
-};
-
 /* I2C1_SDA/SCL on MXM3 209/211 (e.g. RTC on carrier board) */
 &i2c1 {
        status = "okay";
 
-       /*
-        * Touchscreen is using SODIMM 28/30, also used for PWM<B>, PWM<C>,
-        * aka pwm2, pwm3. so if you enable touchscreen, disable the pwms
-        */
-       touchscreen@4a {
-               compatible = "atmel,maxtouch";
-               reg = <0x4a>;
-               interrupt-parent = <&gpio6>;
-               interrupts = <10 IRQ_TYPE_EDGE_FALLING>;
-               reset-gpios = <&gpio6 9 GPIO_ACTIVE_LOW>; /* SODIMM 13 */
-               status = "disabled";
-       };
-
        eeprom@50 {
                compatible = "atmel,24c02";
                reg = <0x50>;
        status = "okay";
 };
 
-&ipu1_di1_disp1 {
-       remote-endpoint = <&lcd_display_in>;
-};
-
-&ldb {
-       status = "okay";
-};
-
 &pcie {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_reset_moci>;
        status = "okay";
 };
 
-&reg_usb_otg_vbus {
+&reg_usb_host_vbus {
        status = "okay";
 };
 
-&reg_usb_host_vbus {
+&reg_usb_otg_vbus {
        status = "okay";
 };
 
 
 /* SD1 */
 &usdhc2 {
+       cd-gpios = <&gpio6 14 GPIO_ACTIVE_LOW>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc2 &pinctrl_sd_cd>;
-       cd-gpios = <&gpio6 14 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
 
 &iomuxc {
-       /* Mux the Apalis GPIOs */
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_apalis_gpio1 &pinctrl_apalis_gpio2
-                    &pinctrl_apalis_gpio3 &pinctrl_apalis_gpio4
-                    &pinctrl_apalis_gpio5 &pinctrl_apalis_gpio6
-                    &pinctrl_apalis_gpio7 &pinctrl_apalis_gpio8
-                   >;
-
        pinctrl_leds_ixora: ledsixoragrp {
                fsl,pins = <
                        MX6QDL_PAD_SD1_DAT1__GPIO1_IO17 0x1b0b0
index 8768222..8263bfe 100644 (file)
        cd-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
        no-1-8-v;
        keep-power-in-suspend;
-       enable-sdio-wakeup;
+       wakeup-source;
        voltage-ranges = <3300 3300>;
        vmmc-supply = <&reg_sw4>;
        fsl,wp-controller;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_wdog1>;
        fsl,ext-reset-output;
-       timeout-sec=<10>;
+       timeout-sec = <10>;
        status = "okay";
 };
 
index 7f1f19b..a3f247c 100644 (file)
                >;
        };
 };
+
+&reg_tft_vcom {
+       regulator-min-microvolt = <3160000>;
+       regulator-max-microvolt = <3160000>;
+       voltage-table = <3160000 73>;
+};
index 9caba45..3b77eae 100644 (file)
                };
        };
 
-       soc {
+       soc: soc {
                ocram: sram@900000 {
                        compatible = "mmio-sram";
                        reg = <0x00900000 0x40000>;
                        clocks = <&clks IMX6QDL_CLK_OCRAM>;
                };
 
-               bus@2000000 { /* AIPS1 */
+               aips1: bus@2000000 { /* AIPS1 */
                        spba-bus@2000000 {
                                ecspi5: spi@2018000 {
                                        #address-cells = <1>;
index bd763ba..7c17b91 100644 (file)
@@ -1,11 +1,12 @@
-// SPDX-License-Identifier: GPL-2.0+ OR MIT
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
 /*
- * Copyright 2014-2020 Toradex
+ * Copyright 2014-2022 Toradex
  * Copyright 2012 Freescale Semiconductor, Inc.
  * Copyright 2011 Linaro Ltd.
  */
 
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pwm/pwm.h>
 
 / {
        model = "Toradex Apalis iMX6Q/D Module";
 
        backlight: backlight {
                compatible = "pwm-backlight";
+               brightness-levels = <0 45 63 88 119 158 203 255>;
+               default-brightness-level = <4>;
+               enable-gpios = <&gpio3 13 GPIO_ACTIVE_HIGH>;
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_gpio_bl_on>;
-               pwms = <&pwm4 0 5000000>;
-               enable-gpios = <&gpio3 13 GPIO_ACTIVE_HIGH>;
+               power-supply = <&reg_module_3v3>;
+               pwms = <&pwm4 0 5000000 PWM_POLARITY_INVERTED>;
+               status = "disabled";
+       };
+
+       clk_ov5640_osc: clk-ov5640-osc {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <24000000>;
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_gpio_keys>;
+
+               wakeup {
+                       debounce-interval = <10>;
+                       gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
+                       label = "Wake-Up";
+                       linux,code = <KEY_WAKEUP>;
+                       wakeup-source;
+               };
+       };
+
+       lcd_display: disp0 {
+               compatible = "fsl,imx-parallel-display";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               interface-pix-fmt = "rgb24";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_ipu1_lcdif>;
                status = "disabled";
+
+               port@0 {
+                       reg = <0>;
+
+                       lcd_display_in: endpoint {
+                               remote-endpoint = <&ipu1_di1_disp1>;
+                       };
+               };
+
+               port@1 {
+                       reg = <1>;
+
+                       lcd_display_out: endpoint {
+                               remote-endpoint = <&lcd_panel_in>;
+                       };
+               };
+       };
+
+       panel_dpi: panel-dpi {
+               compatible = "edt,et057090dhu";
+               backlight = <&backlight>;
+
+               status = "disabled";
+
+               port {
+                       lcd_panel_in: endpoint {
+                               remote-endpoint = <&lcd_display_out>;
+                       };
+               };
+       };
+
+       panel_lvds: panel-lvds {
+               compatible = "panel-lvds";
+               backlight = <&backlight>;
+               status = "disabled";
+
+               port {
+                       lvds_panel_in: endpoint {
+                               remote-endpoint = <&lvds0_out>;
+                       };
+               };
        };
 
        reg_module_3v3: regulator-module-3v3 {
                compatible = "regulator-fixed";
-               regulator-name = "+V3.3";
-               regulator-min-microvolt = <3300000>;
-               regulator-max-microvolt = <3300000>;
                regulator-always-on;
+               regulator-max-microvolt = <3300000>;
+               regulator-min-microvolt = <3300000>;
+               regulator-name = "+V3.3";
        };
 
        reg_module_3v3_audio: regulator-module-3v3-audio {
                compatible = "regulator-fixed";
-               regulator-name = "+V3.3_AUDIO";
-               regulator-min-microvolt = <3300000>;
+               regulator-always-on;
                regulator-max-microvolt = <3300000>;
+               regulator-min-microvolt = <3300000>;
+               regulator-name = "+V3.3_AUDIO";
+       };
+
+       reg_ov5640_1v8_d_o_vdd: regulator-ov5640-1v8-d-o-vdd {
+               compatible = "regulator-fixed";
+               regulator-always-on;
+               regulator-max-microvolt = <1800000>;
+               regulator-min-microvolt = <1800000>;
+               regulator-name = "DOVDD/DVDD_1.8V";
+               /* Note: The CSI module uses on-board 3.3V_SW supply */
+               vin-supply = <&reg_module_3v3>;
+       };
+
+       reg_ov5640_2v8_a_vdd: regulator-ov5640-2v8-a-vdd {
+               compatible = "regulator-fixed";
                regulator-always-on;
+               regulator-max-microvolt = <2800000>;
+               regulator-min-microvolt = <2800000>;
+               regulator-name = "AVDD/AFVDD_2.8V";
+               /* Note: The CSI module uses on-board 3.3V_SW supply */
+               vin-supply = <&reg_module_3v3>;
        };
 
        reg_usb_otg_vbus: regulator-usb-otg-vbus {
                compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio3 22 GPIO_ACTIVE_HIGH>;
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_regulator_usbotg_pwr>;
-               regulator-name = "usb_otg_vbus";
-               regulator-min-microvolt = <5000000>;
                regulator-max-microvolt = <5000000>;
-               gpio = <&gpio3 22 GPIO_ACTIVE_HIGH>;
-               enable-active-high;
+               regulator-min-microvolt = <5000000>;
+               regulator-name = "usb_otg_vbus";
                status = "disabled";
        };
 
        /* on module USB hub */
        reg_usb_host_vbus_hub: regulator-usb-host-vbus-hub {
                compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio3 28 GPIO_ACTIVE_HIGH>;
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_regulator_usbhub_pwr>;
-               regulator-name = "usb_host_vbus_hub";
-               regulator-min-microvolt = <5000000>;
                regulator-max-microvolt = <5000000>;
-               gpio = <&gpio3 28 GPIO_ACTIVE_HIGH>;
+               regulator-min-microvolt = <5000000>;
+               regulator-name = "usb_host_vbus_hub";
                startup-delay-us = <2000>;
-               enable-active-high;
                status = "okay";
        };
 
        reg_usb_host_vbus: regulator-usb-host-vbus {
                compatible = "regulator-fixed";
+               enable-active-high;
+               gpio =  <&gpio1 0 GPIO_ACTIVE_HIGH>;
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_regulator_usbh_pwr>;
-               regulator-name = "usb_host_vbus";
-               regulator-min-microvolt = <5000000>;
                regulator-max-microvolt = <5000000>;
-               gpio =  <&gpio1 0 GPIO_ACTIVE_HIGH>;
-               enable-active-high;
+               regulator-min-microvolt = <5000000>;
+               regulator-name = "usb_host_vbus";
                vin-supply = <&reg_usb_host_vbus_hub>;
                status = "disabled";
        };
 
        sound {
                compatible = "fsl,imx-audio-sgtl5000";
-               model = "imx6q-apalis-sgtl5000";
-               ssi-controller = <&ssi1>;
                audio-codec = <&codec>;
                audio-routing =
                        "LINE_IN", "Line In Jack",
                        "MIC_IN", "Mic Jack",
                        "Mic Jack", "Mic Bias",
                        "Headphone Jack", "HP_OUT";
-               mux-int-port = <1>;
+               model = "imx6q-apalis-sgtl5000";
                mux-ext-port = <4>;
+               mux-int-port = <1>;
+               ssi-controller = <&ssi1>;
        };
 
        sound_spdif: sound-spdif {
                compatible = "fsl,imx-audio-spdif";
-               model = "imx-spdif";
                spdif-controller = <&spdif>;
                spdif-in;
                spdif-out;
+               model = "imx-spdif";
                status = "disabled";
        };
 };
        status = "disabled";
 };
 
+&clks {
+       fsl,pmic-stby-poweroff;
+};
+
 /* Apalis SPI1 */
 &ecspi1 {
        cs-gpios = <&gpio5 25 GPIO_ACTIVE_LOW>;
        status = "disabled";
 };
 
+&gpio1 {
+       gpio-line-names = "MXM3_84",
+                         "MXM3_4",
+                         "MXM3_15/GPIO7",
+                         "MXM3_96",
+                         "MXM3_37",
+                         "",
+                         "MXM3_17/GPIO8",
+                         "MXM3_14",
+                         "MXM3_12",
+                         "MXM3_2",
+                         "MXM3_184",
+                         "MXM3_180",
+                         "MXM3_178",
+                         "MXM3_176",
+                         "MXM3_188",
+                         "MXM3_186",
+                         "MXM3_160",
+                         "MXM3_162",
+                         "MXM3_150",
+                         "MXM3_144",
+                         "MXM3_154",
+                         "MXM3_146",
+                         "",
+                         "",
+                         "MXM3_72";
+};
+
+&gpio2 {
+       gpio-line-names = "MXM3_148",
+                         "MXM3_152",
+                         "MXM3_156",
+                         "MXM3_158",
+                         "MXM3_1/GPIO1",
+                         "MXM3_3/GPIO2",
+                         "MXM3_5/GPIO3",
+                         "MXM3_7/GPIO4",
+                         "MXM3_95",
+                         "MXM3_6",
+                         "MXM3_8",
+                         "MXM3_123",
+                         "MXM3_126",
+                         "MXM3_128",
+                         "MXM3_130",
+                         "MXM3_132",
+                         "MXM3_253",
+                         "MXM3_251",
+                         "MXM3_283",
+                         "MXM3_281",
+                         "MXM3_279",
+                         "MXM3_277",
+                         "MXM3_243",
+                         "MXM3_235",
+                         "MXM3_231",
+                         "MXM3_229",
+                         "MXM3_233",
+                         "MXM3_198",
+                         "MXM3_275",
+                         "MXM3_273",
+                         "MXM3_207",
+                         "MXM3_122";
+};
+
+&gpio3 {
+       gpio-line-names = "MXM3_271",
+                         "MXM3_269",
+                         "MXM3_301",
+                         "MXM3_299",
+                         "MXM3_297",
+                         "MXM3_295",
+                         "MXM3_293",
+                         "MXM3_291",
+                         "MXM3_289",
+                         "MXM3_287",
+                         "MXM3_249",
+                         "MXM3_247",
+                         "MXM3_245",
+                         "MXM3_286",
+                         "MXM3_239",
+                         "MXM3_35",
+                         "MXM3_205",
+                         "MXM3_203",
+                         "MXM3_201",
+                         "MXM3_116",
+                         "MXM3_114",
+                         "MXM3_262",
+                         "MXM3_274",
+                         "MXM3_124",
+                         "MXM3_110",
+                         "MXM3_120",
+                         "MXM3_263",
+                         "MXM3_265",
+                         "",
+                         "MXM3_135",
+                         "MXM3_261",
+                         "MXM3_259";
+};
+
+&gpio4 {
+       gpio-line-names = "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "MXM3_194",
+                         "MXM3_136",
+                         "MXM3_134",
+                         "MXM3_140",
+                         "MXM3_138",
+                         "",
+                         "MXM3_220",
+                         "",
+                         "",
+                         "MXM3_18",
+                         "MXM3_16",
+                         "",
+                         "",
+                         "MXM3_214",
+                         "MXM3_216",
+                         "MXM3_164";
+};
+
+&gpio5 {
+       gpio-line-names = "MXM3_159",
+                         "",
+                         "",
+                         "",
+                         "MXM3_257",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "MXM3_200",
+                         "MXM3_196",
+                         "MXM3_204",
+                         "MXM3_202",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "MXM3_191",
+                         "MXM3_197",
+                         "MXM3_77",
+                         "MXM3_195",
+                         "MXM3_221",
+                         "MXM3_225",
+                         "MXM3_223",
+                         "MXM3_227",
+                         "MXM3_209",
+                         "MXM3_211",
+                         "MXM3_118",
+                         "MXM3_112",
+                         "MXM3_187",
+                         "MXM3_185";
+};
+
+&gpio6 {
+       gpio-line-names = "MXM3_183",
+                         "MXM3_181",
+                         "MXM3_179",
+                         "MXM3_177",
+                         "MXM3_175",
+                         "MXM3_173",
+                         "MXM3_255",
+                         "MXM3_83",
+                         "MXM3_91",
+                         "MXM3_13/GPIO6",
+                         "MXM3_11/GPIO5",
+                         "MXM3_79",
+                         "",
+                         "",
+                         "MXM3_190",
+                         "MXM3_193",
+                         "MXM3_89";
+};
+
+&gpio7 {
+       gpio-line-names = "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "MXM3_99",
+                         "MXM3_85",
+                         "MXM3_217",
+                         "MXM3_215";
+};
+
+&gpr {
+       ipu1_csi0_mux {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               status = "disabled";
+
+               port@1 {
+                       reg = <1>;
+                       ipu1_csi0_mux_from_parallel_sensor: endpoint {
+                               remote-endpoint = <&adv7280_to_ipu1_csi0_mux>;
+                       };
+               };
+       };
+};
+
 &fec {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_enet>;
        scl-gpios = <&gpio5 27 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
        sda-gpios = <&gpio5 26 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
        status = "disabled";
+
+       atmel_mxt_ts: touchscreen@4a {
+               compatible = "atmel,maxtouch";
+               /* These GPIOs are muxed with the iomuxc node */
+               interrupt-parent = <&gpio6>;
+               interrupts = <10 IRQ_TYPE_EDGE_FALLING>;        /* MXM3_11 */
+               reg = <0x4a>;
+               reset-gpios = <&gpio6 9 GPIO_ACTIVE_LOW>;       /* MXM3_13 */
+               status = "disabled";
+       };
 };
 
 /*
        sda-gpios = <&gpio4 13 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
        status = "okay";
 
-       pmic: pfuze100@8 {
+       pmic: pmic@8 {
                compatible = "fsl,pfuze100";
+               fsl,pmic-stby-poweroff;
                reg = <0x08>;
 
                regulators {
                        sw1a_reg: sw1ab {
-                               regulator-min-microvolt = <300000>;
-                               regulator-max-microvolt = <1875000>;
-                               regulator-boot-on;
                                regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <1875000>;
+                               regulator-min-microvolt = <300000>;
                                regulator-ramp-delay = <6250>;
                        };
 
                        sw1c_reg: sw1c {
-                               regulator-min-microvolt = <300000>;
-                               regulator-max-microvolt = <1875000>;
-                               regulator-boot-on;
                                regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <1875000>;
+                               regulator-min-microvolt = <300000>;
                                regulator-ramp-delay = <6250>;
                        };
 
                        sw3a_reg: sw3a {
-                               regulator-min-microvolt = <400000>;
-                               regulator-max-microvolt = <1975000>;
-                               regulator-boot-on;
                                regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <1975000>;
+                               regulator-min-microvolt = <400000>;
                        };
 
                        swbst_reg: swbst {
-                               regulator-min-microvolt = <5000000>;
-                               regulator-max-microvolt = <5150000>;
-                               regulator-boot-on;
                                regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <5150000>;
+                               regulator-min-microvolt = <5000000>;
                        };
 
                        snvs_reg: vsnvs {
-                               regulator-min-microvolt = <1000000>;
-                               regulator-max-microvolt = <3000000>;
-                               regulator-boot-on;
                                regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-min-microvolt = <1000000>;
                        };
 
                        vref_reg: vrefddr {
-                               regulator-boot-on;
                                regulator-always-on;
+                               regulator-boot-on;
                        };
 
                        vgen1_reg: vgen1 {
-                               regulator-min-microvolt = <800000>;
-                               regulator-max-microvolt = <1550000>;
-                               regulator-boot-on;
                                regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <1550000>;
+                               regulator-min-microvolt = <800000>;
                        };
 
                        vgen2_reg: vgen2 {
-                               regulator-min-microvolt = <800000>;
-                               regulator-max-microvolt = <1550000>;
-                               regulator-boot-on;
                                regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <1550000>;
+                               regulator-min-microvolt = <800000>;
                        };
 
                        vgen3_reg: vgen3 {
-                               regulator-min-microvolt = <1800000>;
-                               regulator-max-microvolt = <3300000>;
-                               regulator-boot-on;
                                regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-min-microvolt = <1800000>;
                        };
 
                        vgen4_reg: vgen4 {
-                               regulator-min-microvolt = <1800000>;
-                               regulator-max-microvolt = <1800000>;
-                               regulator-boot-on;
                                regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-min-microvolt = <1800000>;
                        };
 
                        vgen5_reg: vgen5 {
-                               regulator-min-microvolt = <1800000>;
-                               regulator-max-microvolt = <3300000>;
-                               regulator-boot-on;
                                regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-min-microvolt = <1800000>;
                        };
 
                        vgen6_reg: vgen6 {
-                               regulator-min-microvolt = <1800000>;
-                               regulator-max-microvolt = <3300000>;
-                               regulator-boot-on;
                                regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-min-microvolt = <1800000>;
                        };
                };
        };
 
        codec: sgtl5000@a {
                compatible = "fsl,sgtl5000";
-               reg = <0x0a>;
+               #sound-dai-cells = <0>;
+               clocks = <&clks IMX6QDL_CLK_CKO>;
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_sgtl5000>;
-               clocks = <&clks IMX6QDL_CLK_CKO>;
+               reg = <0x0a>;
                VDDA-supply = <&reg_module_3v3_audio>;
                VDDIO-supply = <&reg_module_3v3>;
                VDDD-supply = <&vgen4_reg>;
        /* STMPE811 touch screen controller */
        stmpe811@41 {
                compatible = "st,stmpe811";
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_touch_int>;
-               reg = <0x41>;
+               blocks = <0x5>;
+               id = <0>;
                interrupts = <10 IRQ_TYPE_LEVEL_LOW>;
-               interrupt-parent = <&gpio4>;
                interrupt-controller;
-               id = <0>;
-               blocks = <0x5>;
+               interrupt-parent = <&gpio4>;
                irq-trigger = <0x1>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_touch_int>;
+               reg = <0x41>;
                /* 3.25 MHz ADC clock speed */
                st,adc-freq = <1>;
                /* 12-bit ADC */
                /* ADC conversion time: 80 clocks */
                st,sample-time = <4>;
 
-               stmpe_touchscreen: stmpe-touchscreen {
+               stmpe_ts: stmpe_touchscreen {
                        compatible = "st,stmpe-ts";
                        /* 8 sample average control */
                        st,ave-ctrl = <3>;
                        st,settling = <3>;
                        /* 5 ms touch detect interrupt delay */
                        st,touch-det-delay = <5>;
+                       status = "disabled";
                };
 
-               stmpe_adc: stmpe-adc {
+               stmpe_adc: stmpe_adc {
                        compatible = "st,stmpe-adc";
+                       #io-channel-cells = <1>;
                        /* forbid to use ADC channels 3-0 (touch) */
                        st,norequest-mask = <0x0F>;
-                       #io-channel-cells = <1>;
                };
        };
 };
        scl-gpios = <&gpio3 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
        sda-gpios = <&gpio3 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
        status = "disabled";
+
+       adv_7280: adv7280@21 {
+               compatible = "adi,adv7280";
+               adv,force-bt656-4;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_ipu1_csi0>;
+               reg = <0x21>;
+               status = "disabled";
+
+               port {
+                       adv7280_to_ipu1_csi0_mux: endpoint {
+                               bus-width = <8>;
+                               remote-endpoint = <&ipu1_csi0_mux_from_parallel_sensor>;
+                       };
+               };
+       };
+
+       ov5640_csi_cam: ov5640_mipi@3c {
+               compatible = "ovti,ov5640";
+               AVDD-supply = <&reg_ov5640_2v8_a_vdd>;
+               DOVDD-supply = <&reg_ov5640_1v8_d_o_vdd>;
+               DVDD-supply = <&reg_ov5640_1v8_d_o_vdd>;
+               clock-names = "xclk";
+               clocks = <&clks IMX6QDL_CLK_CKO2>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_cam_mclk>;
+               /* These GPIOs are muxed with the iomuxc node */
+               powerdown-gpios = <&gpio2 5 GPIO_ACTIVE_HIGH>;
+               reg = <0x3c>;
+               reset-gpios = <&gpio2 4 GPIO_ACTIVE_LOW>;
+               status = "disabled";
+
+               port {
+                       ov5640_to_mipi_csi2: endpoint {
+                               clock-lanes = <0>;
+                               data-lanes = <1 2>;
+                               remote-endpoint = <&mipi_csi_from_ov5640>;
+                       };
+               };
+       };
+};
+
+&ipu1_di1_disp1 {
+       remote-endpoint = <&lcd_display_in>;
+};
+
+&ldb {
+       lvds-channel@0 {
+               port@4 {
+                       reg = <4>;
+
+                       lvds0_out: endpoint {
+                               remote-endpoint = <&lvds_panel_in>;
+                       };
+               };
+       };
+
+       lvds-channel@1 {
+               fsl,data-mapping = "spwg";
+               fsl,data-width = <18>;
+
+               port@4 {
+                       reg = <4>;
+
+                       lvds1_out: endpoint {
+                       };
+               };
+       };
+};
+
+&mipi_csi {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       status = "disabled";
+
+       port@0 {
+               reg = <0>;
+
+               mipi_csi_from_ov5640: endpoint {
+                       clock-lanes = <0>;
+                       data-lanes = <1 2>;
+                       remote-endpoint = <&ov5640_to_mipi_csi2>;
+               };
+       };
 };
 
 &pwm1 {
 };
 
 &pwm4 {
-       #pwm-cells = <2>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_pwm4>;
        status = "disabled";
 };
 
 &uart1 {
+       fsl,dte-mode;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart1_dte &pinctrl_uart1_ctrl>;
-       fsl,dte-mode;
        uart-has-rtscts;
        status = "disabled";
 };
 
 &uart2 {
+       fsl,dte-mode;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart2_dte>;
-       fsl,dte-mode;
        uart-has-rtscts;
        status = "disabled";
 };
 
 &uart4 {
+       fsl,dte-mode;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart4_dte>;
-       fsl,dte-mode;
        status = "disabled";
 };
 
 &uart5 {
+       fsl,dte-mode;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart5_dte>;
-       fsl,dte-mode;
        status = "disabled";
 };
 
 &usbotg {
+       disable-over-current;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usbotg>;
-       disable-over-current;
        status = "disabled";
 };
 
 /* MMC1 */
 &usdhc1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_usdhc1_4bit &pinctrl_usdhc1_8bit>;
-       vqmmc-supply = <&reg_module_3v3>;
        bus-width = <8>;
+       cd-gpios = <&gpio4 20 GPIO_ACTIVE_LOW>;
        disable-wp;
        no-1-8-v;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usdhc1_4bit &pinctrl_usdhc1_8bit &pinctrl_mmc_cd>;
+       vqmmc-supply = <&reg_module_3v3>;
        status = "disabled";
 };
 
 /* SD1 */
 &usdhc2 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_usdhc2>;
-       vqmmc-supply = <&reg_module_3v3>;
        bus-width = <4>;
        disable-wp;
        no-1-8-v;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usdhc2>;
+       vqmmc-supply = <&reg_module_3v3>;
        status = "disabled";
 };
 
 /* eMMC */
 &usdhc3 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_usdhc3>;
-       vqmmc-supply = <&reg_module_3v3>;
        bus-width = <8>;
        no-1-8-v;
        non-removable;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usdhc3>;
+       vqmmc-supply = <&reg_module_3v3>;
        status = "okay";
 };
 
 };
 
 &iomuxc {
-       pinctrl_apalis_gpio1: gpio2io04grp {
+       /* Mux the Apalis GPIOs */
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_apalis_gpio1 &pinctrl_apalis_gpio2
+                    &pinctrl_apalis_gpio3 &pinctrl_apalis_gpio4
+                    &pinctrl_apalis_gpio5 &pinctrl_apalis_gpio6
+                    &pinctrl_apalis_gpio7 &pinctrl_apalis_gpio8
+                   >;
+
+       pinctrl_apalis_gpio1: apalisgpio1grp {
                fsl,pins = <
                        MX6QDL_PAD_NANDF_D4__GPIO2_IO04 0x130b0
                >;
        };
 
-       pinctrl_apalis_gpio2: gpio2io05grp {
+       pinctrl_apalis_gpio2: apalisgpio2grp {
                fsl,pins = <
                        MX6QDL_PAD_NANDF_D5__GPIO2_IO05 0x130b0
                >;
        };
 
-       pinctrl_apalis_gpio3: gpio2io06grp {
+       pinctrl_apalis_gpio3: apalisgpio3grp {
                fsl,pins = <
                        MX6QDL_PAD_NANDF_D6__GPIO2_IO06 0x130b0
                >;
        };
 
-       pinctrl_apalis_gpio4: gpio2io07grp {
+       pinctrl_apalis_gpio4: apalisgpio4grp {
                fsl,pins = <
                        MX6QDL_PAD_NANDF_D7__GPIO2_IO07 0x130b0
                >;
        };
 
-       pinctrl_apalis_gpio5: gpio6io10grp {
+       pinctrl_apalis_gpio5: apalisgpio5grp {
                fsl,pins = <
                        MX6QDL_PAD_NANDF_RB0__GPIO6_IO10 0x130b0
                >;
        };
 
-       pinctrl_apalis_gpio6: gpio6io09grp {
+       pinctrl_apalis_gpio6: apalisgpio6grp {
                fsl,pins = <
                        MX6QDL_PAD_NANDF_WP_B__GPIO6_IO09 0x130b0
                >;
        };
 
-       pinctrl_apalis_gpio7: gpio1io02grp {
+       pinctrl_apalis_gpio7: apalisgpio7grp {
                fsl,pins = <
                        MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x130b0
                >;
        };
 
-       pinctrl_apalis_gpio8: gpio1io06grp {
+       pinctrl_apalis_gpio8: apalisgpio8grp {
                fsl,pins = <
                        MX6QDL_PAD_GPIO_6__GPIO1_IO06 0x130b0
                >;
                >;
        };
 
-       pinctrl_gpio_bl_on: gpioblon {
+       pinctrl_gpio_bl_on: gpioblongrp {
                fsl,pins = <
                        MX6QDL_PAD_EIM_DA13__GPIO3_IO13 0x1b0b0
                >;
                >;
        };
 
-       pinctrl_mmc_cd: gpiommccdgrp {
+       pinctrl_mmc_cd: mmccdgrp {
                fsl,pins = <
                         /* MMC1 CD */
                        MX6QDL_PAD_DI0_PIN4__GPIO4_IO20 0x000b0
                >;
        };
 
-       pinctrl_regulator_usbh_pwr: gpioregusbhpwrgrp {
+       pinctrl_regulator_usbh_pwr: regusbhpwrgrp {
                fsl,pins = <
                        /* USBH_EN */
                        MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x0f058
                >;
        };
 
-       pinctrl_regulator_usbhub_pwr: gpioregusbhubpwrgrp {
+       pinctrl_regulator_usbhub_pwr: regusbhubpwrgrp {
                fsl,pins = <
                        /* USBH_HUB_EN */
                        MX6QDL_PAD_EIM_D28__GPIO3_IO28 0x0f058
                >;
        };
 
-       pinctrl_regulator_usbotg_pwr: gpioregusbotgpwrgrp {
+       pinctrl_regulator_usbotg_pwr: regusbotgpwrgrp {
                fsl,pins = <
                        /* USBO1 power en */
                        MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x0f058
                >;
        };
 
-       pinctrl_reset_moci: gpioresetmocigrp {
+       pinctrl_reset_moci: resetmocigrp {
                fsl,pins = <
                        /* RESET_MOCI control */
                        MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x0f058
                >;
        };
 
-       pinctrl_sd_cd: gpiosdcdgrp {
+       pinctrl_sd_cd: sdcdgrp {
                fsl,pins = <
                        /* SD1 CD */
                        MX6QDL_PAD_NANDF_CS1__GPIO6_IO14 0x000b0
                >;
        };
 
-       pinctrl_touch_int: gpiotouchintgrp {
+       pinctrl_touch_int: touchintgrp {
                fsl,pins = <
                        /* STMPE811 interrupt */
                        MX6QDL_PAD_KEY_COL2__GPIO4_IO10 0x1b0b0
                >;
        };
 
+       /* Additional DTR, DSR, DCD */
+       pinctrl_uart1_ctrl: uart1ctrlgrp {
+               fsl,pins = <
+                       MX6QDL_PAD_EIM_D23__UART1_DCD_B 0x1b0b0
+                       MX6QDL_PAD_EIM_D24__UART1_DTR_B 0x1b0b0
+                       MX6QDL_PAD_EIM_D25__UART1_DSR_B 0x1b0b0
+               >;
+       };
+
        pinctrl_uart1_dce: uart1dcegrp {
                fsl,pins = <
                        MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1
                >;
        };
 
-       /* Additional DTR, DSR, DCD */
-       pinctrl_uart1_ctrl: uart1ctrlgrp {
-               fsl,pins = <
-                       MX6QDL_PAD_EIM_D23__UART1_DCD_B 0x1b0b0
-                       MX6QDL_PAD_EIM_D24__UART1_DTR_B 0x1b0b0
-                       MX6QDL_PAD_EIM_D25__UART1_DSR_B 0x1b0b0
-               >;
-       };
-
        pinctrl_uart2_dce: uart2dcegrp {
                fsl,pins = <
                        MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA      0x1b0b1
                >;
        };
 
-       pinctrl_usdhc1_4bit: usdhc1grp_4bit {
+       pinctrl_usdhc1_4bit: usdhc1-4bitgrp {
                fsl,pins = <
                        MX6QDL_PAD_SD1_CMD__SD1_CMD    0x17071
                        MX6QDL_PAD_SD1_CLK__SD1_CLK    0x10071
                >;
        };
 
-       pinctrl_usdhc1_8bit: usdhc1grp_8bit {
+       pinctrl_usdhc1_8bit: usdhc1-8bitgrp {
                fsl,pins = <
                        MX6QDL_PAD_NANDF_D0__SD1_DATA4 0x17071
                        MX6QDL_PAD_NANDF_D1__SD1_DATA5 0x17071
index c383e0e..023e762 100644 (file)
@@ -6,6 +6,7 @@
  */
 
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pwm/pwm.h>
 
 / {
        model = "Toradex Colibri iMX6DL/S Module";
 
        backlight: backlight {
                compatible = "pwm-backlight";
-               brightness-levels = <0 127 191 223 239 247 251 255>;
-               default-brightness-level = <1>;
+               brightness-levels = <0 45 63 88 119 158 203 255>;
+               default-brightness-level = <4>;
                enable-gpios = <&gpio3 26 GPIO_ACTIVE_HIGH>; /* Colibri BL_ON */
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_gpio_bl_on>;
                power-supply = <&reg_module_3v3>;
-               pwms = <&pwm3 0 5000000>;
+               pwms = <&pwm3 0 5000000 PWM_POLARITY_INVERTED>;
                status = "disabled";
        };
 
                compatible = "fsl,sgtl5000";
                clocks = <&clks IMX6QDL_CLK_CKO>;
                lrclk-strength = <3>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_sgtl5000>;
                reg = <0x0a>;
                #sound-dai-cells = <0>;
                VDDA-supply = <&reg_module_3v3_audio>;
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_atmel_conn>;
                reg = <0x4a>;
-               reset-gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>;     /* SODIMM 106 */
+               reset-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>;      /* SODIMM 106 */
                status = "disabled";
        };
 };
 
 /* Colibri PWM<A> */
 &pwm3 {
-       #pwm-cells = <2>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_pwm3>;
        status = "disabled";
 
        pinctrl_audmux: audmuxgrp {
                fsl,pins = <
-                       /* SGTL5000 sys_mclk */
-                       MX6QDL_PAD_GPIO_0__CCM_CLKO1    0x000b0
                        MX6QDL_PAD_KEY_COL0__AUD5_TXC   0x130b0
                        MX6QDL_PAD_KEY_ROW0__AUD5_TXD   0x130b0
                        MX6QDL_PAD_KEY_COL1__AUD5_TXFS  0x130b0
                >;
        };
 
+       pinctrl_sgtl5000: sgtl5000grp {
+               fsl,pins = <
+                       /* SGTL5000 sys_mclk */
+                       MX6QDL_PAD_GPIO_0__CCM_CLKO1    0x000b0
+               >;
+       };
+
        pinctrl_spdif: spdifgrp {
                fsl,pins = <
                        MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x1b0b0
index 19578f6..f0db0d4 100644 (file)
@@ -94,6 +94,9 @@
        pinctrl-0 = <&pinctrl_usdhc3>;
        bus-width = <8>;
        non-removable;
+       no-1-8-v;
+       no-sd;
+       no-sdio;
        status = "okay";
 };
 
index 69ae430..8254bce 100644 (file)
                reg = <0>;
                spi-max-frequency = <1000000>;
                interrupts-extended = <&gpio3 19 IRQ_TYPE_LEVEL_LOW>;
-               vcc-supply  = <&reg_3v3>;
+               vcc-supply = <&reg_3v3>;
                pendown-gpio = <&gpio3 19 GPIO_ACTIVE_LOW>;
                ti,x-plate-ohms = /bits/ 16 <850>;
                ti,y-plate-ohms = /bits/ 16 <295>;
                ti,pressure-min = /bits/ 16 <2>;
                ti,pressure-max = /bits/ 16 <1500>;
-               ti,vref-mv      = /bits/ 16 <3300>;
+               ti,vref-mv = /bits/ 16 <3300>;
                ti,settle-delay-usec = /bits/ 16 <15>;
                ti,vref-delay-usecs = /bits/ 16 <0>;
                ti,penirq-recheck-delay-usecs = /bits/ 16 <100>;
index 77a91a9..3def1b6 100644 (file)
                gpio = <&gpio4 11 GPIO_ACTIVE_LOW>;
        };
 
+       reg_tft_vcom: regulator-tft-vcom {
+               compatible = "pwm-regulator";
+               pwms = <&pwm3 0 20000 0>;
+               regulator-name = "tft_vcom";
+               regulator-min-microvolt = <3600000>;
+               regulator-max-microvolt = <3600000>;
+               regulator-always-on;
+               voltage-table = <3600000 26>;
+       };
+
        reg_vcc_mmc: regulator-vcc-mmc {
                compatible = "regulator-fixed";
                pinctrl-names = "default";
index fded07f..d6ba4b2 100644 (file)
                reg = <0x28>;
                #gpio-cells = <2>;
                gpio-controller;
-               ngpio = <32>;
+               ngpios = <62>;
        };
 
        sgtl5000: codec@a {
index d27beb4..4f7fefc 100644 (file)
                #phy-cells = <0>;
        };
 
-       soc {
+       soc: soc {
                #address-cells = <1>;
                #size-cells = <1>;
                compatible = "simple-bus";
                        status = "disabled";
                };
 
-               bus@2000000 { /* AIPS1 */
+               aips1: bus@2000000 { /* AIPS1 */
                        compatible = "fsl,aips-bus", "simple-bus";
                        #address-cells = <1>;
                        #size-cells = <1>;
                                        regulator-name = "vddpu";
                                        regulator-min-microvolt = <725000>;
                                        regulator-max-microvolt = <1450000>;
-                                       regulator-enable-ramp-delay = <150>;
+                                       regulator-enable-ramp-delay = <380>;
                                        anatop-reg-offset = <0x140>;
                                        anatop-vol-bit-shift = <9>;
                                        anatop-vol-bit-width = <5>;
                        };
                };
 
-               bus@2100000 { /* AIPS2 */
+               aips2: bus@2100000 { /* AIPS2 */
                        compatible = "fsl,aips-bus", "simple-bus";
                        #address-cells = <1>;
                        #size-cells = <1>;
index a17b8bb..663ee9d 100644 (file)
@@ -27,7 +27,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_gpio_keys>;
 
-               cover {
+               key-cover {
                        label = "Cover";
                        gpios = <&gpio5 12 GPIO_ACTIVE_LOW>;
                        linux,code = <SW_LID>;
                        wakeup-source;
                };
 
-               fl {
+               key-fl {
                        label = "Frontlight";
                        gpios = <&gpio3 26 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_BRIGHTNESS_CYCLE>;
                };
 
-               home {
+               key-home {
                        label = "Home";
                        gpios = <&gpio3 25 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_HOME>;
                };
 
-               power {
+               key-power {
                        label = "Power";
                        gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
@@ -60,7 +60,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_led>;
 
-               on {
+               led-0 {
                        label = "tolinoshine2hd:white:on";
                        gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
                        linux,default-trigger = "timer";
index fc63343..4d075e2 100644 (file)
                #phy-cells = <0>;
        };
 
-       soc {
+       soc: soc {
                #address-cells = <1>;
                #size-cells = <1>;
                compatible = "simple-bus";
index a6cf0f2..4386831 100644 (file)
@@ -72,7 +72,6 @@
 &adc1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_adc1>;
-       num-channels = <3>;
        vref-supply = <&reg_vref_adc>;
        status = "okay";
 };
index 0d4ba94..38ea4dc 100644 (file)
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_adc1>;
        vref-supply = <&reg_adc1_vref_3v3>;
-       /*
-        * driver can not separate a specific channel so we request 4 channels
-        * here - we need only the fourth channel
-        */
-       num-channels = <4>;
        status = "disabled";
 };
 
index caf2c5d..4b87e2d 100644 (file)
@@ -14,7 +14,7 @@
 };
 
 &usdhc2 {
-       fsl,tuning-step= <6>;
+       fsl,tuning-step = <6>;
 };
 
 &iomuxc {
index afeec01..c95efd1 100644 (file)
                        clock-frequency = <696000000>;
                        clock-latency = <61036>; /* two CLK32 periods */
                        #cooling-cells = <2>;
-                       operating-points = <
+                       operating-points =
                                /* kHz  uV */
-                               696000  1275000
-                               528000  1175000
-                               396000  1025000
-                               198000  950000
-                       >;
-                       fsl,soc-operating-points = <
+                               <696000 1275000>,
+                               <528000 1175000>,
+                               <396000 1025000>,
+                               <198000 950000>;
+                       fsl,soc-operating-points =
                                /* KHz  uV */
-                               696000  1275000
-                               528000  1175000
-                               396000  1175000
-                               198000  1175000
-                       >;
+                               <696000 1275000>,
+                               <528000 1175000>,
+                               <396000 1175000>,
+                               <198000 1175000>;
                        clocks = <&clks IMX6UL_CLK_ARM>,
                                 <&clks IMX6UL_CLK_PLL2_BUS>,
                                 <&clks IMX6UL_CLK_PLL2_PFD2>,
                interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
        };
 
-       soc {
+       soc: soc {
                #address-cells = <1>;
                #size-cells = <1>;
                compatible = "simple-bus";
                ocram: sram@900000 {
                        compatible = "mmio-sram";
                        reg = <0x00900000 0x20000>;
+                       ranges = <0 0x00900000 0x20000>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                };
 
                intc: interrupt-controller@a01000 {
                        };
 
                        kpp: keypad@20b8000 {
-                               compatible = "fsl,imx6ul-kpp", "fsl,imx6q-kpp", "fsl,imx21-kpp";
+                               compatible = "fsl,imx6ul-kpp", "fsl,imx21-kpp";
                                reg = <0x020b8000 0x4000>;
                                interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&clks IMX6UL_CLK_KPP>;
                                reg = <0x02198000 0x4000>;
                                interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&clks IMX6UL_CLK_ADC1>;
-                               num-channels = <2>;
                                clock-names = "adc";
                                fsl,adck-max-frequency = <30000000>, <40000000>,
                                                         <20000000>;
                        };
 
                        csi: csi@21c4000 {
-                               compatible = "fsl,imx6ul-csi", "fsl,imx7-csi";
+                               compatible = "fsl,imx6ul-csi";
                                reg = <0x021c4000 0x4000>;
                                interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&clks IMX6UL_CLK_CSI>;
                        };
 
                        lcdif: lcdif@21c8000 {
-                               compatible = "fsl,imx6ul-lcdif", "fsl,imx28-lcdif";
+                               compatible = "fsl,imx6ul-lcdif", "fsl,imx6sx-lcdif";
                                reg = <0x021c8000 0x4000>;
                                interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&clks IMX6UL_CLK_LCDIF_PIX>,
                        qspi: spi@21e0000 {
                                #address-cells = <1>;
                                #size-cells = <0>;
-                               compatible = "fsl,imx6ul-qspi", "fsl,imx6sx-qspi";
+                               compatible = "fsl,imx6ul-qspi";
                                reg = <0x021e0000 0x4000>, <0x60000000 0x10000000>;
                                reg-names = "QuadSPI", "QuadSPI-memory";
                                interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
index 15621e0..577a424 100644 (file)
@@ -94,7 +94,6 @@
 };
 
 &adc1 {
-       num-channels = <10>;
        vref-supply = <&reg_module_3v3_avdd>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_adc1>;
        atmel_mxt_ts: touchscreen@4a {
                compatible = "atmel,maxtouch";
                pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_atmel_conn>;
+               pinctrl-0 = <&pinctrl_atmel_conn &pinctrl_atmel_snvs_conn>;
                reg = <0x4a>;
                interrupt-parent = <&gpio5>;
                interrupts = <4 IRQ_TYPE_EDGE_FALLING>;       /* SODIMM 107 / INT */
        pinctrl_atmel_conn: atmelconngrp {
                fsl,pins = <
                        MX6UL_PAD_JTAG_MOD__GPIO1_IO10          0xb0a0  /* SODIMM 106 */
-                       MX6ULL_PAD_SNVS_TAMPER4__GPIO5_IO04     0xb0a0  /* SODIMM 107 */
                >;
        };
 
 };
 
 &iomuxc_snvs {
+       pinctrl_atmel_snvs_conn: atmelsnvsconngrp {
+               fsl,pins = <
+                       MX6ULL_PAD_SNVS_TAMPER4__GPIO5_IO04     0xb0a0  /* SODIMM 107 */
+               >;
+       };
+
        pinctrl_snvs_gpio1: snvsgpio1grp {
                fsl,pins = <
                        MX6ULL_PAD_SNVS_TAMPER6__GPIO5_IO06     0x110a0 /* SODIMM 93 */
index 326e6da..8541cb3 100644 (file)
@@ -14,7 +14,7 @@
 };
 
 &usdhc2 {
-       fsl,tuning-step= <6>;
+       fsl,tuning-step = <6>;
        /* Errata ERR010450 Workaround */
        max-frequency = <99000000>;
        assigned-clocks = <&clks IMX6UL_CLK_USDHC2_SEL>, <&clks IMX6UL_CLK_USDHC2>;
index 8e4d5cd..be593d4 100644 (file)
@@ -14,7 +14,7 @@
 };
 
 &usdhc2 {
-       fsl,tuning-step= <6>;
+       fsl,tuning-step = <6>;
        /* Errata ERR010450 Workaround */
        max-frequency = <99000000>;
        assigned-clocks = <&clks IMX6UL_CLK_USDHC2_SEL>, <&clks IMX6UL_CLK_USDHC2>;
index 9bf6749..2bccd45 100644 (file)
@@ -50,7 +50,7 @@
 };
 
 / {
-       soc {
+       soc: soc {
                aips3: bus@2200000 {
                        compatible = "fsl,aips-bus", "simple-bus";
                        #address-cells = <1>;
index 59bcfc9..c92e4e2 100644 (file)
        status = "okay";
 };
 
+&snvs_poweroff {
+       status = "okay";
+};
+
 &uart3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart3>;
index b770fc9..fa488a6 100644 (file)
-// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
 /*
- * Copyright 2017-2020 Toradex AG
- *
+ * Copyright 2017-2022 Toradex
  */
 
-
-#include <dt-bindings/input/input.h>
-#include <dt-bindings/pwm/pwm.h>
-
-/ {
-       chosen {
-               stdout-path = "serial0:115200n8";
-       };
-
-       gpio-keys {
-               compatible = "gpio-keys";
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_gpiokeys>;
-
-               power {
-                       label = "Wake-Up";
-                       gpios = <&gpio1 1 GPIO_ACTIVE_HIGH>;
-                       linux,code = <KEY_WAKEUP>;
-                       debounce-interval = <10>;
-                       wakeup-source;
-               };
-       };
-
-       panel: panel {
-               compatible = "edt,et057090dhu";
-               backlight = <&bl>;
-               power-supply = <&reg_3v3>;
-
-               port {
-                       panel_in: endpoint {
-                               remote-endpoint = <&lcdif_out>;
-                       };
-               };
-       };
-
-       reg_3v3: regulator-3v3 {
-               compatible = "regulator-fixed";
-               regulator-name = "3.3V";
-               regulator-min-microvolt = <3300000>;
-               regulator-max-microvolt = <3300000>;
-       };
-
-       reg_5v0: regulator-5v0 {
-               compatible = "regulator-fixed";
-               regulator-name = "5V";
-               regulator-min-microvolt = <5000000>;
-               regulator-max-microvolt = <5000000>;
-       };
-
-       reg_usbh_vbus: regulator-usbh-vbus {
-               compatible = "regulator-fixed";
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_usbh_reg>;
-               regulator-name = "VCC_USB[1-4]";
-               regulator-min-microvolt = <5000000>;
-               regulator-max-microvolt = <5000000>;
-               gpio = <&gpio4 7 GPIO_ACTIVE_LOW>;
-               vin-supply = <&reg_5v0>;
-       };
-};
-
+/* Colibri AD0 to AD3 */
 &adc1 {
        status = "okay";
 };
 
-/*
- * ADC2 is not available on the Aster board and
- * conflicts with AD7879 resistive touchscreen.
- */
-&adc2 {
-       status = "disabled";
-};
-
-&bl {
-       brightness-levels = <0 4 8 16 32 64 128 255>;
-       default-brightness-level = <6>;
-       power-supply = <&reg_3v3>;
+/* Colibri SSP */
+&ecspi3 {
+       cs-gpios = <
+               &gpio4 11 GPIO_ACTIVE_LOW /* SODIMM 86 / regular SSPFRM as UNO_SPI_CS or  */
+               &gpio4 23 GPIO_ACTIVE_LOW /* SODIMM 65 / already muxed pinctrl_gpio2 as SPI_CE0_N */
+               &gpio4 22 GPIO_ACTIVE_LOW /* SODIMM 85 / already muxed pinctrl_gpio2 as SPI_CE1_N */
+       >;
        status = "okay";
 };
 
+/* Colibri Fast Ethernet */
 &fec1 {
        status = "okay";
 };
 
+/* Colibri I2C: I2C3_SDA/SCL on SODIMM 194/196 */
 &i2c4 {
        status = "okay";
-
-       /* Microchip/Atmel maxtouch controller */
-       touchscreen@4a {
-               compatible = "atmel,maxtouch";
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_gpiotouch>;
-               reg = <0x4a>;
-               interrupt-parent = <&gpio2>;
-               interrupts = <15 IRQ_TYPE_EDGE_FALLING>;        /* SODIMM 107 */
-               reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>;      /* SODIMM 106 */
-       };
-
-       /* M41T0M6 real time clock on carrier board */
-       rtc: rtc@68 {
-               compatible = "st,m41t0";
-               reg = <0x68>;
-       };
-};
-
-&iomuxc {
-       pinctrl_gpiotouch: touchgpios {
-               fsl,pins = <
-                       MX7D_PAD_EPDC_DATA15__GPIO2_IO15        0x74
-                       MX7D_PAD_EPDC_BDR0__GPIO2_IO28          0x14
-               >;
-       };
-};
-
-&lcdif {
-       status = "okay";
-
-       port {
-               lcdif_out: endpoint {
-                       remote-endpoint = <&panel_in>;
-               };
-       };
 };
 
+/* Colibri PWM<A> */
 &pwm1 {
        status = "okay";
 };
 
+/* Colibri PWM<B> */
 &pwm2 {
        status = "okay";
 };
 
+/* Colibri PWM<C> */
 &pwm3 {
        status = "okay";
 };
 
+/* Colibri PWM<D> */
 &pwm4 {
        status = "okay";
 };
 
+/* M41T0M6 real time clock */
+&rtc {
+       status = "okay";
+};
+
+/* Colibri UART_A */
 &uart1 {
        status = "okay";
 };
 
+/* Colibri UART_B */
 &uart2 {
        status = "okay";
 };
 
+/* Colibri UART_C */
 &uart3 {
        status = "okay";
 };
 
+/* Colibri USBC */
 &usbotg1 {
        status = "okay";
 };
 
+/* Colibri MMC/SD */
 &usdhc1 {
-       keep-power-in-suspend;
-       no-1-8-v;
-       wakeup-source;
-       vmmc-supply = <&reg_3v3>;
        status = "okay";
 };
index 3b9df8c..826f13d 100644 (file)
-// SPDX-License-Identifier: GPL-2.0+ OR MIT
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
 /*
- * Copyright 2016-2020 Toradex
+ * Copyright 2016-2022 Toradex
  */
 
 / {
-       aliases {
-               rtc0 = &rtc;
-               rtc1 = &snvs_rtc;
-       };
-
-       chosen {
-               stdout-path = "serial0:115200n8";
-       };
-
-       /* fixed crystal dedicated to mpc258x */
+       /* Fixed crystal dedicated to MCP2515. */
        clk16m: clk16m {
                compatible = "fixed-clock";
                #clock-cells = <0>;
                clock-frequency = <16000000>;
        };
-
-       gpio-keys {
-               compatible = "gpio-keys";
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_gpiokeys>;
-
-               power {
-                       label = "Wake-Up";
-                       gpios = <&gpio1 1 GPIO_ACTIVE_HIGH>;
-                       linux,code = <KEY_WAKEUP>;
-                       debounce-interval = <10>;
-                       wakeup-source;
-               };
-       };
-
-       panel: panel {
-               compatible = "edt,et057090dhu";
-               backlight = <&bl>;
-               power-supply = <&reg_3v3>;
-
-               port {
-                       panel_in: endpoint {
-                               remote-endpoint = <&lcdif_out>;
-                       };
-               };
-       };
-
-       reg_3v3: regulator-3v3 {
-               compatible = "regulator-fixed";
-               regulator-name = "3.3V";
-               regulator-min-microvolt = <3300000>;
-               regulator-max-microvolt = <3300000>;
-       };
-
-       reg_5v0: regulator-5v0 {
-               compatible = "regulator-fixed";
-               regulator-name = "5V";
-               regulator-min-microvolt = <5000000>;
-               regulator-max-microvolt = <5000000>;
-       };
-
-       reg_usbh_vbus: regulator-usbh-vbus {
-               compatible = "regulator-fixed";
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_usbh_reg>;
-               regulator-name = "VCC_USB[1-4]";
-               regulator-min-microvolt = <5000000>;
-               regulator-max-microvolt = <5000000>;
-               gpio = <&gpio4 7 GPIO_ACTIVE_LOW>;
-               vin-supply = <&reg_5v0>;
-       };
-};
-
-&bl {
-       brightness-levels = <0 4 8 16 32 64 128 255>;
-       default-brightness-level = <6>;
-       power-supply = <&reg_3v3>;
-
-       status = "okay";
 };
 
+/* Colibri AD0 to AD3 */
 &adc1 {
        status = "okay";
 };
 
-&adc2 {
-       status = "okay";
+/*
+ * The Atmel maxtouch controller uses SODIMM 28/30, also used for PWM<B>, PWM<C>, aka pwm2, pwm3.
+ * So if you enable following capacitive touch controller, disable pwm2/pwm3 first.
+ */
+&atmel_mxt_ts {
+       interrupt-parent = <&gpio1>;
+       interrupts = <9 IRQ_TYPE_EDGE_FALLING>;         /* SODIMM 28 / INT */
+       pinctrl-0 = <&pinctrl_atmel_adapter>;
+       reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;      /* SODIMM 30 / RST */
+       status = "disabled";
 };
 
+/* Colibri SSP */
 &ecspi3 {
        status = "okay";
 
        mcp2515: can@0 {
+               clocks = <&clk16m>;
                compatible = "microchip,mcp2515";
+               interrupt-parent = <&gpio5>;
+               interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_can_int>;
                reg = <0>;
-               clocks = <&clk16m>;
-               interrupt-parent = <&gpio5>;
-               interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
                spi-max-frequency = <10000000>;
                vdd-supply = <&reg_3v3>;
                xceiver-supply = <&reg_5v0>;
-               status = "okay";
        };
 };
 
+/* Colibri Fast Ethernet */
 &fec1 {
        status = "okay";
 };
 
+/* Colibri I2C: I2C3_SDA/SCL on SODIMM 194/196 */
 &i2c4 {
        status = "okay";
-
-       /*
-        * Touchscreen is using SODIMM 28/30, also used for PWM<B>, PWM<C>,
-        * aka pwm2, pwm3. so if you enable touchscreen, disable the pwms
-        */
-       touchscreen@4a {
-               compatible = "atmel,maxtouch";
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_gpiotouch>;
-               reg = <0x4a>;
-               interrupt-parent = <&gpio1>;
-               interrupts = <9 IRQ_TYPE_EDGE_FALLING>;         /* SODIMM 28 */
-               reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;      /* SODIMM 30 */
-               status = "disabled";
-       };
-
-       /* M41T0M6 real time clock on carrier board */
-       rtc: rtc@68 {
-               compatible = "st,m41t0";
-               reg = <0x68>;
-       };
-};
-
-&lcdif {
-       status = "okay";
-
-       port {
-               lcdif_out: endpoint {
-                       remote-endpoint = <&panel_in>;
-               };
-       };
 };
 
+/* Colibri PWM<A> */
 &pwm1 {
        status = "okay";
 };
 
+/* Colibri PWM<B> */
 &pwm2 {
+       /* The pwm2 should be disabled to enable atmel_mxt_ts touchscreen for adapter. */
        status = "okay";
 };
 
+/* Colibri PWM<C> */
 &pwm3 {
+       /* The pwm3 should be disabled to enable atmel_mxt_ts touchscreen for adapter. */
        status = "okay";
 };
 
+/* Colibri PWM<D> */
 &pwm4 {
        status = "okay";
 };
 
+/* M41T0M6 real time clock */
+&rtc {
+       status = "okay";
+};
+
+/* Colibri UART_A */
 &uart1 {
        status = "okay";
 };
 
+/* Colibri UART_B */
 &uart2 {
        status = "okay";
 };
 
+/* Colibri UART_C */
 &uart3 {
        status = "okay";
 };
 
+/* Colibri USBC */
 &usbotg1 {
        status = "okay";
 };
 
+/* Colibri MMC/SD */
 &usdhc1 {
-       keep-power-in-suspend;
-       wakeup-source;
-       vmmc-supply = <&reg_3v3>;
        status = "okay";
 };
-
-&iomuxc {
-       pinctrl_gpiotouch: touchgpios {
-               fsl,pins = <
-                       MX7D_PAD_GPIO1_IO09__GPIO1_IO9          0x74
-                       MX7D_PAD_GPIO1_IO10__GPIO1_IO10         0x14
-               >;
-       };
-};
diff --git a/arch/arm/boot/dts/imx7-colibri-iris-v2.dtsi b/arch/arm/boot/dts/imx7-colibri-iris-v2.dtsi
new file mode 100644 (file)
index 0000000..6e19961
--- /dev/null
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright 2022 Toradex
+ */
+
+/ {
+       reg_3v3_vmmc: regulator-3v3-vmmc {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio5 16 GPIO_ACTIVE_HIGH>; /* SODIMM 100 */
+               regulator-max-microvolt = <3300000>;
+               regulator-min-microvolt = <3300000>;
+               regulator-name = "3v3_vmmc";
+               startup-delay-us = <100>;
+       };
+};
+
+/* Colibri AD0 to AD3 */
+&adc1 {
+       status = "okay";
+};
+
+/* Colibri SSP */
+&ecspi3 {
+       status = "okay";
+};
+
+/* Colibri Fast Ethernet */
+&fec1 {
+       status = "okay";
+};
+
+&gpio2 {
+       /*
+        * uart_b_c_on_x14_enable turns the UART transceiver for UART2 and 5 on. If one wants to
+        * turn the transceiver off, that property has to be deleted and the gpio handled in
+        * userspace.
+        * The same applies to uart_a_on_x13_enable where the UART_A transceiver is turned on.
+        */
+       uart-b-c-on-x14-enable-hog {
+               gpio-hog;
+               gpios = <27 GPIO_ACTIVE_HIGH>; /* SODIMM 104 */
+               output-high;
+       };
+};
+
+&gpio5 {
+       uart-a-on-x13-enable-hog {
+               gpio-hog;
+               gpios = <17 GPIO_ACTIVE_HIGH>; /* SODIMM 102 */
+               output-high;
+       };
+};
+
+/* Colibri I2C: I2C3_SDA/SCL on SODIMM 194/196 */
+&i2c4 {
+       status = "okay";
+};
+
+/* Colibri PWM<A> */
+&pwm1 {
+       status = "okay";
+};
+
+/* Colibri PWM<B> */
+&pwm2 {
+       status = "okay";
+};
+
+/* Colibri PWM<C> */
+&pwm3 {
+       status = "okay";
+};
+
+/* Colibri PWM<D> */
+&pwm4 {
+       status = "okay";
+};
+
+/* M41T0M6 real time clock */
+&rtc {
+       status = "okay";
+};
+
+/* Colibri UART_A */
+&uart1 {
+       status = "okay";
+};
+
+/* Colibri UART_B */
+&uart2 {
+       status = "okay";
+};
+
+/* Colibri UART_C */
+&uart3 {
+       status = "okay";
+};
+
+/* Colibri USBC */
+&usbotg1 {
+       status = "okay";
+};
+
+/* Colibri MMC/SD, UHS-I capable uSD slot */
+&usdhc1 {
+       cap-power-off-card;
+       /delete-property/ keep-power-in-suspend;
+       /delete-property/ no-1-8-v;
+       vmmc-supply = <&reg_3v3_vmmc>;
+       status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx7-colibri-iris.dtsi b/arch/arm/boot/dts/imx7-colibri-iris.dtsi
new file mode 100644 (file)
index 0000000..175c5d4
--- /dev/null
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright 2022 Toradex
+ */
+
+/* Colibri AD0 to AD3 */
+&adc1 {
+       status = "okay";
+};
+
+/*
+ * The Atmel maxtouch controller uses SODIMM 28/30, also used for PWM<B>, PWM<C>, aka pwm2, pwm3.
+ * So if you enable following capacitive touch controller, disable pwm2/pwm3 first.
+ */
+&atmel_mxt_ts {
+       interrupt-parent = <&gpio1>;
+       interrupts = <9 IRQ_TYPE_EDGE_FALLING>;         /* SODIMM 28 / INT */
+       pinctrl-0 = <&pinctrl_atmel_adapter>;
+       reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;      /* SODIMM 30 / RST */
+};
+
+/* Colibri SSP */
+&ecspi3 {
+       status = "okay";
+};
+
+/* Colibri Fast Ethernet */
+&fec1 {
+       status = "okay";
+};
+
+&gpio2 {
+       /*
+        * uart25 turns the UART transceiver for UART2 and 5 on. If one wants to turn the
+        * transceiver off, that property has to be deleted and the gpio handled in userspace.
+        * The same applies to uart1_tx_on where the UART1 transceiver is turned on.
+        */
+       uart25-tx-on-hog {
+               gpio-hog;
+               gpios = <27 GPIO_ACTIVE_HIGH>; /* SODIMM 104 */
+               output-high;
+       };
+};
+
+&gpio5 {
+       uart1-tx-on-hog {
+               gpio-hog;
+               gpios = <17 GPIO_ACTIVE_HIGH>; /* SODIMM 102 */
+               output-high;
+       };
+};
+
+/* Colibri I2C: I2C3_SDA/SCL on SODIMM 194/196 */
+&i2c4 {
+       status = "okay";
+};
+
+/* Colibri PWM<A> */
+&pwm1 {
+       status = "okay";
+};
+
+/* Colibri PWM<B> */
+&pwm2 {
+       /* The pwm2 should be disabled to enable atmel_mxt_ts touchscreen for adapter. */
+       status = "okay";
+};
+
+/* Colibri PWM<C> */
+&pwm3 {
+       /* The pwm3 should be disabled to enable atmel_mxt_ts touchscreen for adapter. */
+       status = "okay";
+};
+
+/* Colibri PWM<D> */
+&pwm4 {
+       status = "okay";
+};
+
+/* M41T0M6 real time clock */
+&rtc {
+       status = "okay";
+};
+
+/* Colibri UART_A */
+&uart1 {
+       status = "okay";
+};
+
+/* Colibri UART_B */
+&uart2 {
+       status = "okay";
+};
+
+/* Colibri UART_C */
+&uart3 {
+       status = "okay";
+};
+
+/* Colibri USBC */
+&usbotg1 {
+       status = "okay";
+};
+
+/* Colibri MMC/SD */
+&usdhc1 {
+       status = "okay";
+};
index f1c60b0..a8c31ee 100644 (file)
-// SPDX-License-Identifier: GPL-2.0+ OR MIT
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
 /*
- * Copyright 2016-2020 Toradex
+ * Copyright 2016-2022 Toradex
  */
 
+#include <dt-bindings/pwm/pwm.h>
+
 / {
-       bl: backlight {
+       aliases {
+               rtc0 = &rtc;
+               rtc1 = &snvs_rtc;
+       };
+
+       backlight: backlight {
+               brightness-levels = <0 45 63 88 119 158 203 255>;
                compatible = "pwm-backlight";
+               default-brightness-level = <4>;
+               enable-gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>;
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_gpio_bl_on>;
-               pwms = <&pwm1 0 5000000 0>;
-               enable-gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>;
+               power-supply = <&reg_module_3v3>;
+               pwms = <&pwm1 0 6666667 PWM_POLARITY_INVERTED>;
+               status = "disabled";
        };
 
-       reg_module_3v3: regulator-module-3v3 {
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       extcon_usbc_det: usbc-det {
+               compatible = "linux,extcon-usb-gpio";
+               debounce = <25>;
+               id-gpio = <&gpio7 14 GPIO_ACTIVE_HIGH>; /* SODIMM 137 / USBC_DET */
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_usbc_det>;
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_gpiokeys>;
+
+               wakeup {
+                       debounce-interval = <10>;
+                       gpios = <&gpio1 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; /* SODIMM 45 */
+                       label = "Wake-Up";
+                       linux,code = <KEY_WAKEUP>;
+                       wakeup-source;
+               };
+       };
+
+       panel_dpi: panel-dpi {
+               backlight = <&backlight>;
+               compatible = "edt,et057090dhu";
+               power-supply = <&reg_3v3>;
+               status = "disabled";
+
+               port {
+                       lcd_panel_in: endpoint {
+                               remote-endpoint = <&lcdif_out>;
+                       };
+               };
+       };
+
+       reg_3v3: regulator-3v3 {
                compatible = "regulator-fixed";
-               regulator-name = "+V3.3";
-               regulator-min-microvolt = <3300000>;
+               regulator-always-on;
                regulator-max-microvolt = <3300000>;
+               regulator-min-microvolt = <3300000>;
+               regulator-name = "3.3V";
+       };
+
+       reg_5v0: regulator-5v0 {
+               compatible = "regulator-fixed";
                regulator-always-on;
+               regulator-max-microvolt = <5000000>;
+               regulator-min-microvolt = <5000000>;
+               regulator-name = "5V";
+       };
+
+       reg_module_3v3: regulator-module-3v3 {
+               compatible = "regulator-fixed";
+               regulator-always-on;
+               regulator-max-microvolt = <3300000>;
+               regulator-min-microvolt = <3300000>;
+               regulator-name = "+V3.3";
        };
 
        reg_module_3v3_avdd: regulator-module-3v3-avdd {
                compatible = "regulator-fixed";
+               regulator-always-on;
+               regulator-max-microvolt = <3300000>;
+               regulator-min-microvolt = <3300000>;
                regulator-name = "+V3.3_AVDD_AUDIO";
+       };
+
+       reg_module_3v3_eth: regulator-module-3v3-eth {
+               compatible = "regulator-fixed";
+               off-on-delay-us = <200000>;
+               regulator-name = "+V3.3_ETH";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
-               regulator-always-on;
+               regulator-boot-on;
+               startup-delay-us = <200000>;
+               vin-supply = <&reg_LDO1>;
+       };
+
+       reg_usbh_vbus: regulator-usbh-vbus {
+               compatible = "regulator-fixed";
+               gpio = <&gpio4 7 GPIO_ACTIVE_LOW>; /* SODIMM 129 / USBH_PEN */
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_usbh_reg>;
+               regulator-max-microvolt = <5000000>;
+               regulator-min-microvolt = <5000000>;
+               regulator-name = "VCC_USB[1-4]";
+               vin-supply = <&reg_5v0>;
        };
 
        sound {
                compatible = "simple-audio-card";
-               simple-audio-card,name = "imx7-sgtl5000";
-               simple-audio-card,format = "i2s";
                simple-audio-card,bitclock-master = <&dailink_master>;
+               simple-audio-card,format = "i2s";
                simple-audio-card,frame-master = <&dailink_master>;
+               simple-audio-card,name = "imx7-sgtl5000";
+
                simple-audio-card,cpu {
                        sound-dai = <&sai1>;
                };
 
                dailink_master: simple-audio-card,codec {
-                       sound-dai = <&codec>;
                        clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>;
+                       sound-dai = <&codec>;
                };
        };
 };
 
+/* Colibri AD0 to AD3 */
 &adc1 {
        vref-supply = <&reg_DCDC3>;
 };
 
-&adc2 {
-       vref-supply = <&reg_DCDC3>;
-};
+/* ADC2 is not available as it conflicts with AD7879 resistive touchscreen. */
 
 &cpu0 {
        cpu-supply = <&reg_DCDC2>;
 };
 
+/* Colibri SSP */
 &ecspi3 {
+       cs-gpios = <&gpio4 11 GPIO_ACTIVE_LOW>; /* SODIMM 86 / SSPFRM */
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_ecspi3 &pinctrl_ecspi3_cs>;
-       cs-gpios = <&gpio4 11 GPIO_ACTIVE_LOW>;
 };
 
+/* Colibri Fast Ethernet */
 &fec1 {
-       pinctrl-names = "default", "sleep";
-       pinctrl-0 = <&pinctrl_enet1>;
-       pinctrl-1 = <&pinctrl_enet1_sleep>;
-       clocks = <&clks IMX7D_ENET_AXI_ROOT_CLK>,
-               <&clks IMX7D_ENET_AXI_ROOT_CLK>,
-               <&clks IMX7D_ENET1_TIME_ROOT_CLK>,
-               <&clks IMX7D_PLL_ENET_MAIN_50M_CLK>;
-       clock-names = "ipg", "ahb", "ptp", "enet_clk_ref";
-       assigned-clocks = <&clks IMX7D_ENET1_TIME_ROOT_SRC>,
-                         <&clks IMX7D_ENET1_TIME_ROOT_CLK>;
        assigned-clock-parents = <&clks IMX7D_PLL_ENET_MAIN_100M_CLK>;
        assigned-clock-rates = <0>, <100000000>;
-       phy-mode = "rmii";
-       phy-supply = <&reg_LDO1>;
+       assigned-clocks = <&clks IMX7D_ENET1_TIME_ROOT_SRC>,
+                         <&clks IMX7D_ENET1_TIME_ROOT_CLK>;
+       clock-names = "ipg", "ahb", "ptp", "enet_clk_ref";
+       clocks = <&clks IMX7D_ENET_AXI_ROOT_CLK>,
+                <&clks IMX7D_ENET_AXI_ROOT_CLK>,
+                <&clks IMX7D_ENET1_TIME_ROOT_CLK>,
+                <&clks IMX7D_PLL_ENET_MAIN_50M_CLK>;
        fsl,magic-packet;
+       phy-handle = <&ethphy0>;
+       phy-mode = "rmii";
+       phy-supply = <&reg_module_3v3_eth>;
+       pinctrl-names = "default", "sleep";
+       pinctrl-0 = <&pinctrl_enet1>;
+       pinctrl-1 = <&pinctrl_enet1_sleep>;
+
+       mdio {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               /* Micrel KSZ8041RNL */
+               ethphy0: ethernet-phy@0 {
+                       compatible = "ethernet-phy-ieee802.3-c22";
+                       max-speed = <100>;
+                       micrel,led-mode = <0>;
+                       reg = <0>;
+               };
+       };
 };
 
 &flexcan1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_flexcan1>;
-       status = "disabled";
 };
 
 &flexcan2 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_flexcan2>;
-       status = "disabled";
 };
 
 &gpio1 {
                          "SODIMM_137";
 };
 
+/* NAND on such SKUs */
 &gpmi {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_gpmi_nand>;
        fsl,use-minimum-ecc;
-       nand-on-flash-bbt;
        nand-ecc-mode = "hw";
+       nand-on-flash-bbt;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_gpmi_nand>;
 };
 
+/* On-module Power I2C */
 &i2c1 {
        clock-frequency = <100000>;
        pinctrl-names = "default", "gpio";
        pinctrl-1 = <&pinctrl_i2c1_recovery &pinctrl_i2c1_int>;
        scl-gpios = <&gpio1 4 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
        sda-gpios = <&gpio1 5 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
-
        status = "okay";
 
        codec: sgtl5000@a {
-               compatible = "fsl,sgtl5000";
                #sound-dai-cells = <0>;
-               reg = <0x0a>;
                clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>;
+               compatible = "fsl,sgtl5000";
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_sai1_mclk>;
+               reg = <0xa>;
                VDDA-supply = <&reg_module_3v3_avdd>;
-               VDDIO-supply = <&reg_module_3v3>;
                VDDD-supply = <&reg_DCDC3>;
+               VDDIO-supply = <&reg_module_3v3>;
        };
 
-       ad7879@2c {
+       ad7879_ts: touchscreen@2c {
+               adi,acquisition-time = /bits/ 8 <1>;
+               adi,averaging = /bits/ 8 <1>;
+               adi,conversion-interval = /bits/ 8 <255>;
+               adi,first-conversion-delay = /bits/ 8 <3>;
+               adi,median-filter-size = /bits/ 8 <2>;
+               adi,resistance-plate-x = <120>;
                compatible = "adi,ad7879-1";
-               reg = <0x2c>;
                interrupt-parent = <&gpio1>;
                interrupts = <13 IRQ_TYPE_EDGE_FALLING>;
+               reg = <0x2c>;
                touchscreen-max-pressure = <4096>;
-               adi,resistance-plate-x = <120>;
-               adi,first-conversion-delay = /bits/ 8 <3>;
-               adi,acquisition-time = /bits/ 8 <1>;
-               adi,median-filter-size = /bits/ 8 <2>;
-               adi,averaging = /bits/ 8 <1>;
-               adi,conversion-interval = /bits/ 8 <255>;
+               status = "disabled";
        };
 
        pmic@33 {
                reg = <0x33>;
 
                regulators {
-                       reg_DCDC1: DCDC1 {  /* V1.0_SOC */
-                               regulator-min-microvolt = <1000000>;
-                               regulator-max-microvolt = <1100000>;
-                               regulator-boot-on;
+                       reg_DCDC1: DCDC1 {
                                regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <1100000>;
+                               regulator-min-microvolt = <1000000>;
+                               regulator-name = "+V1.0_SOC";
                        };
 
-                       reg_DCDC2: DCDC2 { /* V1.1_ARM */
-                               regulator-min-microvolt = <975000>;
-                               regulator-max-microvolt = <1100000>;
-                               regulator-boot-on;
+                       reg_DCDC2: DCDC2 {
                                regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <1100000>;
+                               regulator-min-microvolt = <975000>;
+                               regulator-name = "+V1.1_ARM";
                        };
 
-                       reg_DCDC3: DCDC3 { /* V1.8 */
-                               regulator-min-microvolt = <1800000>;
-                               regulator-max-microvolt = <1800000>;
-                               regulator-boot-on;
+                       reg_DCDC3: DCDC3 {
                                regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-name = "+V1.8";
                        };
 
-                       reg_DCDC4: DCDC4 { /* V1.35_DRAM */
-                               regulator-min-microvolt = <1350000>;
-                               regulator-max-microvolt = <1350000>;
-                               regulator-boot-on;
+                       reg_DCDC4: DCDC4 {
                                regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-min-microvolt = <1350000>;
+                               regulator-name = "+V1.35_DRAM";
                        };
 
-                       reg_LDO1: LDO1 { /* PWR_EN_+V3.3_ETH */
-                               regulator-min-microvolt = <1800000>;
-                               regulator-max-microvolt = <3300000>;
+                       reg_LDO1: LDO1 {
                                regulator-boot-on;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-name = "PWR_EN_+V3.3_ETH";
                        };
 
-                       reg_LDO2: LDO2 { /* +V1.8_SD */
-                               regulator-min-microvolt = <1800000>;
-                               regulator-max-microvolt = <3300000>;
-                               regulator-boot-on;
+                       reg_LDO2: LDO2 {
                                regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-name = "+V1.8_SD";
                        };
 
-                       reg_LDO3: LDO3 { /* PWR_EN_+V3.3_LPSR */
-                               regulator-min-microvolt = <3300000>;
-                               regulator-max-microvolt = <3300000>;
-                               regulator-boot-on;
+                       reg_LDO3: LDO3 {
                                regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-name = "PWR_EN_+V3.3_LPSR";
                        };
 
-                       reg_LDO4: LDO4 { /* V1.8_LPSR */
-                               regulator-min-microvolt = <1800000>;
-                               regulator-max-microvolt = <1800000>;
-                               regulator-boot-on;
+                       reg_LDO4: LDO4 {
                                regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-name = "+V1.8_LPSR";
                        };
 
-                       reg_LDO5: LDO5 { /* PWR_EN_+V3.3 */
-                               regulator-min-microvolt = <3300000>;
-                               regulator-max-microvolt = <3300000>;
-                               regulator-boot-on;
+                       reg_LDO5: LDO5 {
                                regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-name = "PWR_EN_+V3.3";
                        };
                };
        };
 };
 
+/* Colibri I2C: I2C3_SDA/SCL on SODIMM 194/196 */
 &i2c4 {
        clock-frequency = <100000>;
        pinctrl-names = "default", "gpio";
        pinctrl-1 = <&pinctrl_i2c4_recovery>;
        scl-gpios = <&gpio7 8 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
        sda-gpios = <&gpio7 9 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       status = "disabled";
+
+       /* Atmel maxtouch controller */
+       atmel_mxt_ts: touchscreen@4a {
+               compatible = "atmel,maxtouch";
+               interrupt-parent = <&gpio2>;
+               interrupts = <15 IRQ_TYPE_EDGE_FALLING>;        /* SODIMM 107 / INT */
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_atmel_connector>;
+               reg = <0x4a>;
+               reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>;      /* SODIMM 106 / RST */
+               status = "disabled";
+       };
+
+       /* M41T0M6 real time clock on carrier board */
+       rtc: rtc@68 {
+               compatible = "st,m41t0";
+               reg = <0x68>;
+               status = "disabled";
+       };
 };
 
 &lcdif {
+       assigned-clocks = <&clks IMX7D_LCDIF_PIXEL_ROOT_SRC>;
+       assigned-clock-parents = <&clks IMX7D_PLL_VIDEO_POST_DIV>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_lcdif_dat
                     &pinctrl_lcdif_ctrl>;
+       status = "disabled";
+
+       port {
+               lcdif_out: endpoint {
+                       remote-endpoint = <&lcd_panel_in>;
+               };
+       };
 };
 
+/* Colibri PWM<A> */
 &pwm1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_pwm1>;
 };
 
+/* Colibri PWM<B> */
 &pwm2 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_pwm2>;
 };
 
+/* Colibri PWM<C> */
 &pwm3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_pwm3>;
 };
 
+/* Colibri PWM<D> */
 &pwm4 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_pwm4>;
 };
 
 &reg_1p0d {
-       vin-supply = <&reg_DCDC3>;
+       vin-supply = <&reg_DCDC3>; /* VDDA_1P8_IN */
 };
 
 &sai1 {
        status = "okay";
 };
 
+/* Colibri UART_A */
 &uart1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_uart1 &pinctrl_uart1_ctrl1 &pinctrl_uart1_ctrl2>;
        assigned-clocks = <&clks IMX7D_UART1_ROOT_SRC>;
        assigned-clock-parents = <&clks IMX7D_OSC_24M_CLK>;
-       uart-has-rtscts;
        fsl,dte-mode;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1 &pinctrl_uart1_ctrl1 &pinctrl_uart1_ctrl2>;
+       uart-has-rtscts;
 };
 
+/* Colibri UART_B */
 &uart2 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_uart2>;
        assigned-clocks = <&clks IMX7D_UART2_ROOT_SRC>;
        assigned-clock-parents = <&clks IMX7D_OSC_24M_CLK>;
-       uart-has-rtscts;
        fsl,dte-mode;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart2>;
+       uart-has-rtscts;
 };
 
+/* Colibri UART_C */
 &uart3 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_uart3>;
        assigned-clocks = <&clks IMX7D_UART3_ROOT_SRC>;
        assigned-clock-parents = <&clks IMX7D_OSC_24M_CLK>;
        fsl,dte-mode;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart3>;
 };
 
+/* Colibri USBC */
 &usbotg1 {
-       dr_mode = "host";
+       dr_mode = "otg";
+       extcon = <0>, <&extcon_usbc_det>;
 };
 
+/* Colibri MMC/SD */
 &usdhc1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_usdhc1 &pinctrl_cd_usdhc1>;
        cd-gpios = <&gpio1 0 GPIO_ACTIVE_LOW>;
        disable-wp;
+       no-1-8-v;
+       pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
+       pinctrl-0 = <&pinctrl_usdhc1 &pinctrl_cd_usdhc1>;
+       pinctrl-1 = <&pinctrl_usdhc1_100mhz &pinctrl_cd_usdhc1>;
+       pinctrl-2 = <&pinctrl_usdhc1_200mhz &pinctrl_cd_usdhc1>;
+       pinctrl-3 = <&pinctrl_usdhc1_sleep &pinctrl_cd_usdhc1_sleep>;
+       vmmc-supply = <&reg_3v3>;
        vqmmc-supply = <&reg_LDO2>;
+       wakeup-source;
 };
 
+/* eMMC on 1GB (eMMC) SKUs */
 &usdhc3 {
-       pinctrl-names = "default", "state_100mhz", "state_200mhz";
-       pinctrl-0 = <&pinctrl_usdhc3>;
-       pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
-       pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
        assigned-clocks = <&clks IMX7D_USDHC3_ROOT_CLK>;
        assigned-clock-rates = <400000000>;
        bus-width = <8>;
        fsl,tuning-step = <2>;
-       vmmc-supply = <&reg_module_3v3>;
-       vqmmc-supply = <&reg_DCDC3>;
        non-removable;
+       pinctrl-names = "default", "state_100mhz", "state_200mhz";
+       pinctrl-0 = <&pinctrl_usdhc3>;
+       pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
+       pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
        sdhci-caps-mask = <0x80000000 0x0>;
+       vmmc-supply = <&reg_module_3v3>;
+       vqmmc-supply = <&reg_DCDC3>;
 };
 
 &iomuxc {
        pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_gpio1 &pinctrl_gpio2 &pinctrl_gpio3 &pinctrl_gpio4
-                    &pinctrl_gpio7 &pinctrl_usbc_det>;
-
-       pinctrl_gpio1: gpio1-grp {
-               fsl,pins = <
-                       MX7D_PAD_SAI1_RX_SYNC__GPIO6_IO16       0x14 /* SODIMM 77 */
-                       MX7D_PAD_EPDC_DATA09__GPIO2_IO9         0x14 /* SODIMM 89 */
-                       MX7D_PAD_EPDC_DATA08__GPIO2_IO8         0x74 /* SODIMM 91 */
-                       MX7D_PAD_LCD_RESET__GPIO3_IO4           0x14 /* SODIMM 93 */
-                       MX7D_PAD_EPDC_DATA13__GPIO2_IO13        0x14 /* SODIMM 95 */
-                       MX7D_PAD_ENET1_RGMII_TXC__GPIO7_IO11    0x14 /* SODIMM 99 */
-                       MX7D_PAD_EPDC_DATA10__GPIO2_IO10        0x74 /* SODIMM 105 */
-                       MX7D_PAD_EPDC_DATA00__GPIO2_IO0         0x14 /* SODIMM 111 */
-                       MX7D_PAD_EPDC_DATA01__GPIO2_IO1         0x14 /* SODIMM 113 */
-                       MX7D_PAD_EPDC_DATA02__GPIO2_IO2         0x14 /* SODIMM 115 */
-                       MX7D_PAD_EPDC_DATA03__GPIO2_IO3         0x14 /* SODIMM 117 */
-                       MX7D_PAD_EPDC_DATA04__GPIO2_IO4         0x14 /* SODIMM 119 */
-                       MX7D_PAD_EPDC_DATA05__GPIO2_IO5         0x14 /* SODIMM 121 */
-                       MX7D_PAD_EPDC_DATA06__GPIO2_IO6         0x14 /* SODIMM 123 */
-                       MX7D_PAD_EPDC_DATA07__GPIO2_IO7         0x14 /* SODIMM 125 */
-                       MX7D_PAD_EPDC_SDCE2__GPIO2_IO22         0x14 /* SODIMM 127 */
-                       MX7D_PAD_UART3_RTS_B__GPIO4_IO6         0x14 /* SODIMM 131 */
-                       MX7D_PAD_EPDC_GDRL__GPIO2_IO26          0x14 /* SODIMM 133 */
-                       MX7D_PAD_SAI1_RX_DATA__GPIO6_IO12       0x14 /* SODIMM 169 */
-                       MX7D_PAD_SAI1_RX_BCLK__GPIO6_IO17       0x14 /* SODIMM 24 */
-                       MX7D_PAD_SD2_DATA2__GPIO5_IO16          0x14 /* SODIMM 100 */
-                       MX7D_PAD_SD2_DATA3__GPIO5_IO17          0x14 /* SODIMM 102 */
-                       MX7D_PAD_EPDC_GDSP__GPIO2_IO27          0x14 /* SODIMM 104 */
-                       MX7D_PAD_EPDC_BDR1__GPIO2_IO29          0x14 /* SODIMM 110 */
-                       MX7D_PAD_EPDC_PWR_COM__GPIO2_IO30       0x14 /* SODIMM 112 */
-                       MX7D_PAD_EPDC_SDCLK__GPIO2_IO16         0x14 /* SODIMM 114 */
-                       MX7D_PAD_EPDC_SDLE__GPIO2_IO17          0x14 /* SODIMM 116 */
-                       MX7D_PAD_EPDC_SDOE__GPIO2_IO18          0x14 /* SODIMM 118 */
-                       MX7D_PAD_EPDC_SDSHR__GPIO2_IO19         0x14 /* SODIMM 120 */
-                       MX7D_PAD_EPDC_SDCE0__GPIO2_IO20         0x14 /* SODIMM 122 */
-                       MX7D_PAD_EPDC_SDCE1__GPIO2_IO21         0x14 /* SODIMM 124 */
-                       MX7D_PAD_EPDC_DATA14__GPIO2_IO14        0x14 /* SODIMM 126 */
-                       MX7D_PAD_EPDC_PWR_STAT__GPIO2_IO31      0x14 /* SODIMM 128 */
-                       MX7D_PAD_EPDC_SDCE3__GPIO2_IO23         0x14 /* SODIMM 130 */
-                       MX7D_PAD_EPDC_GDCLK__GPIO2_IO24         0x14 /* SODIMM 132 */
-                       MX7D_PAD_EPDC_GDOE__GPIO2_IO25          0x14 /* SODIMM 134 */
-                       MX7D_PAD_EPDC_DATA12__GPIO2_IO12        0x14 /* SODIMM 150 */
-                       MX7D_PAD_EPDC_DATA11__GPIO2_IO11        0x14 /* SODIMM 152 */
-                       MX7D_PAD_SD2_CLK__GPIO5_IO12            0x14 /* SODIMM 184 */
-                       MX7D_PAD_SD2_CMD__GPIO5_IO13            0x14 /* SODIMM 186 */
-               >;
-       };
-
-       pinctrl_gpio2: gpio2-grp { /* On X22 Camera interface */
+       pinctrl-0 = <&pinctrl_gpio1 &pinctrl_gpio2 &pinctrl_gpio3 &pinctrl_gpio4>;
+
+       /*
+        * Atmel MXT touchsceen + Capacitive Touch Adapter
+        * NOTE: This pin group conflicts with pin groups pinctrl_pwm2/pinctrl_pwm3.
+        * Don't use them simultaneously.
+        */
+       pinctrl_atmel_adapter: atmelconnectorgrp {
                fsl,pins = <
-                       MX7D_PAD_ECSPI2_SS0__GPIO4_IO23         0x14 /* SODIMM 65 */
-                       MX7D_PAD_SD1_CD_B__GPIO5_IO0            0x74 /* SODIMM 69 */
-                       MX7D_PAD_I2C4_SDA__GPIO4_IO15           0x14 /* SODIMM 75 */
-                       MX7D_PAD_ECSPI1_MISO__GPIO4_IO18        0x14 /* SODIMM 79 */
-                       MX7D_PAD_I2C3_SCL__GPIO4_IO12           0x14 /* SODIMM 81 */
-                       MX7D_PAD_ECSPI2_MISO__GPIO4_IO22        0x14 /* SODIMM 85 */
-                       MX7D_PAD_ECSPI1_SS0__GPIO4_IO19         0x14 /* SODIMM 97 */
-                       MX7D_PAD_ECSPI1_SCLK__GPIO4_IO16        0x14 /* SODIMM 101 */
-                       MX7D_PAD_ECSPI1_MOSI__GPIO4_IO17        0x14 /* SODIMM 103 */
-                       MX7D_PAD_I2C3_SDA__GPIO4_IO13           0x14 /* SODIMM 94 */
-                       MX7D_PAD_I2C4_SCL__GPIO4_IO14           0x14 /* SODIMM 96 */
-                       MX7D_PAD_SD2_RESET_B__GPIO5_IO11        0x14 /* SODIMM 98 */
+                       MX7D_PAD_GPIO1_IO09__GPIO1_IO9          0x74 /* SODIMM 28 / INT */
+                       MX7D_PAD_GPIO1_IO10__GPIO1_IO10         0x14 /* SODIMM 30 / RST */
                >;
        };
 
-       pinctrl_gpio3: gpio3-grp { /* LCD 18-23 */
+       /* Atmel MXT touchsceen + boards with built-in Capacitive Touch Connector */
+       pinctrl_atmel_connector: atmeladaptergrp {
                fsl,pins = <
-                       MX7D_PAD_LCD_DATA18__GPIO3_IO23         0x14 /* SODIMM 136 */
-                       MX7D_PAD_LCD_DATA19__GPIO3_IO24         0x14 /* SODIMM 138 */
-                       MX7D_PAD_LCD_DATA20__GPIO3_IO25         0x14 /* SODIMM 140 */
-                       MX7D_PAD_LCD_DATA21__GPIO3_IO26         0x14 /* SODIMM 142 */
-                       MX7D_PAD_LCD_DATA22__GPIO3_IO27         0x74 /* SODIMM 144 */
-                       MX7D_PAD_LCD_DATA23__GPIO3_IO28         0x74 /* SODIMM 146 */
+                       MX7D_PAD_EPDC_BDR0__GPIO2_IO28          0x14 /* SODIMM 106 / RST */
+                       MX7D_PAD_EPDC_DATA15__GPIO2_IO15        0x74 /* SODIMM 107 / INT */
                >;
        };
 
-       pinctrl_gpio4: gpio4-grp { /* Alternatively CAN2 */
+       pinctrl_can_int: canintgrp {
                fsl,pins = <
-                       MX7D_PAD_GPIO1_IO15__GPIO1_IO15         0x14 /* SODIMM 178 */
-                       MX7D_PAD_GPIO1_IO14__GPIO1_IO14         0x14 /* SODIMM 188 */
+                       MX7D_PAD_SD1_RESET_B__GPIO5_IO2         0X14 /* SODIMM 73 */
                >;
        };
 
-       pinctrl_gpio7: gpio7-grp { /* Alternatively CAN1 */
+       pinctrl_ecspi3: ecspi3grp {
                fsl,pins = <
-                       MX7D_PAD_ENET1_RGMII_RD3__GPIO7_IO3     0x14 /* SODIMM 55 */
-                       MX7D_PAD_ENET1_RGMII_RD2__GPIO7_IO2     0x14 /* SODIMM 63 */
+                       MX7D_PAD_I2C1_SCL__ECSPI3_MISO          0x2 /* SODIMM 90 */
+                       MX7D_PAD_I2C1_SDA__ECSPI3_MOSI          0x2 /* SODIMM 92 */
+                       MX7D_PAD_I2C2_SCL__ECSPI3_SCLK          0x2 /* SODIMM 88 */
                >;
        };
 
-       pinctrl_i2c1_int: i2c1-int-grp { /* PMIC / TOUCH */
+       pinctrl_ecspi3_cs: ecspi3csgrp {
                fsl,pins = <
-                       MX7D_PAD_GPIO1_IO13__GPIO1_IO13 0x79
-               >;
-       };
-
-       pinctrl_can_int: can-int-grp {
-               fsl,pins = <
-                       MX7D_PAD_SD1_RESET_B__GPIO5_IO2         0X14 /* SODIMM 73 */
+                       MX7D_PAD_I2C2_SDA__GPIO4_IO11           0x14 /* SODIMM 86 */
                >;
        };
 
        pinctrl_enet1: enet1grp {
                fsl,pins = <
-                       MX7D_PAD_ENET1_RGMII_RX_CTL__ENET1_RGMII_RX_CTL 0x73
                        MX7D_PAD_ENET1_RGMII_RD0__ENET1_RGMII_RD0       0x73
                        MX7D_PAD_ENET1_RGMII_RD1__ENET1_RGMII_RD1       0x73
                        MX7D_PAD_ENET1_RGMII_RXC__ENET1_RX_ER           0x73
-
-                       MX7D_PAD_ENET1_RGMII_TX_CTL__ENET1_RGMII_TX_CTL 0x73
+                       MX7D_PAD_ENET1_RGMII_RX_CTL__ENET1_RGMII_RX_CTL 0x73
                        MX7D_PAD_ENET1_RGMII_TD0__ENET1_RGMII_TD0       0x73
                        MX7D_PAD_ENET1_RGMII_TD1__ENET1_RGMII_TD1       0x73
+                       MX7D_PAD_ENET1_RGMII_TX_CTL__ENET1_RGMII_TX_CTL 0x73
                        MX7D_PAD_GPIO1_IO12__CCM_ENET_REF_CLK1          0x73
                        MX7D_PAD_SD2_CD_B__ENET1_MDIO                   0x3
                        MX7D_PAD_SD2_WP__ENET1_MDC                      0x3
                >;
        };
 
-       pinctrl_enet1_sleep: enet1sleepgrp {
+       pinctrl_enet1_sleep: enet1-sleepgrp {
                fsl,pins = <
-                       MX7D_PAD_ENET1_RGMII_RX_CTL__GPIO7_IO4          0x0
                        MX7D_PAD_ENET1_RGMII_RD0__GPIO7_IO0             0x0
                        MX7D_PAD_ENET1_RGMII_RD1__GPIO7_IO1             0x0
                        MX7D_PAD_ENET1_RGMII_RXC__GPIO7_IO5             0x0
-
-                       MX7D_PAD_ENET1_RGMII_TX_CTL__GPIO7_IO10         0x0
+                       MX7D_PAD_ENET1_RGMII_RX_CTL__GPIO7_IO4          0x0
                        MX7D_PAD_ENET1_RGMII_TD0__GPIO7_IO6             0x0
                        MX7D_PAD_ENET1_RGMII_TD1__GPIO7_IO7             0x0
+                       MX7D_PAD_ENET1_RGMII_TX_CTL__GPIO7_IO10         0x0
                        MX7D_PAD_GPIO1_IO12__GPIO1_IO12                 0x0
                        MX7D_PAD_SD2_CD_B__GPIO5_IO9                    0x0
                        MX7D_PAD_SD2_WP__GPIO5_IO10                     0x0
                >;
        };
 
-       pinctrl_ecspi3_cs: ecspi3-cs-grp {
+       pinctrl_flexcan1: flexcan1grp {
                fsl,pins = <
-                       MX7D_PAD_I2C2_SDA__GPIO4_IO11           0x14
+                       MX7D_PAD_ENET1_RGMII_RD2__FLEXCAN1_RX   0x79 /* SODIMM 63 */
+                       MX7D_PAD_ENET1_RGMII_RD3__FLEXCAN1_TX   0x79 /* SODIMM 55 */
                >;
        };
 
-       pinctrl_ecspi3: ecspi3-grp {
+       pinctrl_flexcan2: flexcan2grp {
                fsl,pins = <
-                       MX7D_PAD_I2C1_SCL__ECSPI3_MISO          0x2
-                       MX7D_PAD_I2C1_SDA__ECSPI3_MOSI          0x2
-                       MX7D_PAD_I2C2_SCL__ECSPI3_SCLK          0x2
+                       MX7D_PAD_GPIO1_IO14__FLEXCAN2_RX        0x79 /* SODIMM 188 */
+                       MX7D_PAD_GPIO1_IO15__FLEXCAN2_TX        0x79 /* SODIMM 178 */
                >;
        };
 
-       pinctrl_flexcan1: flexcan1-grp {
+       pinctrl_gpio1: gpio1grp {
                fsl,pins = <
-                       MX7D_PAD_ENET1_RGMII_RD3__FLEXCAN1_TX   0x79 /* SODIMM 55 */
-                       MX7D_PAD_ENET1_RGMII_RD2__FLEXCAN1_RX   0x79 /* SODIMM 63 */
+                       MX7D_PAD_EPDC_BDR1__GPIO2_IO29          0x14 /* SODIMM 110 */
+                       MX7D_PAD_EPDC_DATA00__GPIO2_IO0         0x14 /* SODIMM 111 */
+                       MX7D_PAD_EPDC_DATA01__GPIO2_IO1         0x14 /* SODIMM 113 */
+                       MX7D_PAD_EPDC_DATA02__GPIO2_IO2         0x14 /* SODIMM 115 */
+                       MX7D_PAD_EPDC_DATA03__GPIO2_IO3         0x14 /* SODIMM 117 */
+                       MX7D_PAD_EPDC_DATA04__GPIO2_IO4         0x14 /* SODIMM 119 */
+                       MX7D_PAD_EPDC_DATA05__GPIO2_IO5         0x14 /* SODIMM 121 */
+                       MX7D_PAD_EPDC_DATA06__GPIO2_IO6         0x14 /* SODIMM 123 */
+                       MX7D_PAD_EPDC_DATA07__GPIO2_IO7         0x14 /* SODIMM 125 */
+                       MX7D_PAD_EPDC_DATA08__GPIO2_IO8         0x74 /* SODIMM 91 */
+                       MX7D_PAD_EPDC_DATA09__GPIO2_IO9         0x14 /* SODIMM 89 */
+                       MX7D_PAD_EPDC_DATA10__GPIO2_IO10        0x74 /* SODIMM 105 */
+                       MX7D_PAD_EPDC_DATA11__GPIO2_IO11        0x14 /* SODIMM 152 */
+                       MX7D_PAD_EPDC_DATA12__GPIO2_IO12        0x14 /* SODIMM 150 */
+                       MX7D_PAD_EPDC_DATA14__GPIO2_IO14        0x14 /* SODIMM 126 */
+                       MX7D_PAD_EPDC_GDCLK__GPIO2_IO24         0x14 /* SODIMM 132 */
+                       MX7D_PAD_EPDC_GDOE__GPIO2_IO25          0x14 /* SODIMM 134 */
+                       MX7D_PAD_EPDC_GDRL__GPIO2_IO26          0x14 /* SODIMM 133 */
+                       MX7D_PAD_EPDC_GDSP__GPIO2_IO27          0x14 /* SODIMM 104 */
+                       MX7D_PAD_EPDC_PWR_COM__GPIO2_IO30       0x14 /* SODIMM 112 */
+                       MX7D_PAD_EPDC_PWR_STAT__GPIO2_IO31      0x14 /* SODIMM 128 */
+                       MX7D_PAD_EPDC_SDCE0__GPIO2_IO20         0x14 /* SODIMM 122 */
+                       MX7D_PAD_EPDC_SDCE1__GPIO2_IO21         0x14 /* SODIMM 124 */
+                       MX7D_PAD_EPDC_SDCE2__GPIO2_IO22         0x14 /* SODIMM 127 */
+                       MX7D_PAD_EPDC_SDCE3__GPIO2_IO23         0x14 /* SODIMM 130 */
+                       MX7D_PAD_EPDC_SDCLK__GPIO2_IO16         0x14 /* SODIMM 114 */
+                       MX7D_PAD_EPDC_SDLE__GPIO2_IO17          0x14 /* SODIMM 116 */
+                       MX7D_PAD_EPDC_SDOE__GPIO2_IO18          0x14 /* SODIMM 118 */
+                       MX7D_PAD_EPDC_SDSHR__GPIO2_IO19         0x14 /* SODIMM 120 */
+                       MX7D_PAD_LCD_RESET__GPIO3_IO4           0x14 /* SODIMM 93 */
+                       MX7D_PAD_SAI1_RX_BCLK__GPIO6_IO17       0x14 /* SODIMM 24 */
+                       MX7D_PAD_SAI1_RX_DATA__GPIO6_IO12       0x14 /* SODIMM 169 */
+                       MX7D_PAD_SAI1_RX_SYNC__GPIO6_IO16       0x14 /* SODIMM 77 */
+                       MX7D_PAD_SD2_CLK__GPIO5_IO12            0x14 /* SODIMM 184 */
+                       MX7D_PAD_SD2_CMD__GPIO5_IO13            0x14 /* SODIMM 186 */
+                       MX7D_PAD_SD2_DATA2__GPIO5_IO16          0x14 /* SODIMM 100 */
+                       MX7D_PAD_SD2_DATA3__GPIO5_IO17          0x14 /* SODIMM 102 */
+                       MX7D_PAD_UART3_RTS_B__GPIO4_IO6         0x14 /* SODIMM 131 */
                >;
        };
 
-       pinctrl_flexcan2: flexcan2-grp {
+       pinctrl_gpio2: gpio2grp { /* On X22 Camera interface */
                fsl,pins = <
-                       MX7D_PAD_GPIO1_IO14__FLEXCAN2_RX        0x79 /* SODIMM 188 */
-                       MX7D_PAD_GPIO1_IO15__FLEXCAN2_TX        0x79 /* SODIMM 178 */
+                       MX7D_PAD_ECSPI1_MISO__GPIO4_IO18        0x14 /* SODIMM 79 */
+                       MX7D_PAD_ECSPI1_MOSI__GPIO4_IO17        0x14 /* SODIMM 103 */
+                       MX7D_PAD_ECSPI1_SCLK__GPIO4_IO16        0x14 /* SODIMM 101 */
+                       MX7D_PAD_ECSPI1_SS0__GPIO4_IO19         0x14 /* SODIMM 97 */
+                       MX7D_PAD_ECSPI2_MISO__GPIO4_IO22        0x14 /* SODIMM 85 */
+                       MX7D_PAD_ECSPI2_SS0__GPIO4_IO23         0x14 /* SODIMM 65 */
+                       MX7D_PAD_I2C3_SCL__GPIO4_IO12           0x14 /* SODIMM 81 */
+                       MX7D_PAD_I2C3_SDA__GPIO4_IO13           0x14 /* SODIMM 94 */
+                       MX7D_PAD_I2C4_SCL__GPIO4_IO14           0x14 /* SODIMM 96 */
+                       MX7D_PAD_I2C4_SDA__GPIO4_IO15           0x14 /* SODIMM 75 */
+                       MX7D_PAD_SD1_CD_B__GPIO5_IO0            0x74 /* SODIMM 69 */
+                       MX7D_PAD_SD2_RESET_B__GPIO5_IO11        0x14 /* SODIMM 98 */
+               >;
+       };
+
+       pinctrl_gpio3: gpio3grp { /* LCD 18-23 */
+               fsl,pins = <
+                       MX7D_PAD_LCD_DATA18__GPIO3_IO23         0x14 /* SODIMM 136 */
+                       MX7D_PAD_LCD_DATA19__GPIO3_IO24         0x14 /* SODIMM 138 */
+                       MX7D_PAD_LCD_DATA20__GPIO3_IO25         0x14 /* SODIMM 140 */
+                       MX7D_PAD_LCD_DATA21__GPIO3_IO26         0x14 /* SODIMM 142 */
+                       MX7D_PAD_LCD_DATA22__GPIO3_IO27         0x74 /* SODIMM 144 */
+                       MX7D_PAD_LCD_DATA23__GPIO3_IO28         0x74 /* SODIMM 146 */
+               >;
+       };
+
+       pinctrl_gpio4: gpio4grp { /* Alternatively CAN2 */
+               fsl,pins = <
+                       MX7D_PAD_GPIO1_IO14__GPIO1_IO14         0x14 /* SODIMM 188 */
+                       MX7D_PAD_GPIO1_IO15__GPIO1_IO15         0x14 /* SODIMM 178 */
+               >;
+       };
+
+       pinctrl_gpio7: gpio7grp { /* Alternatively CAN1 */
+               fsl,pins = <
+                       MX7D_PAD_ENET1_RGMII_RD2__GPIO7_IO2     0x14 /* SODIMM 63 */
+                       MX7D_PAD_ENET1_RGMII_RD3__GPIO7_IO3     0x14 /* SODIMM 55 */
                >;
        };
 
-       pinctrl_gpio_bl_on: gpio-bl-on {
+       pinctrl_gpio_bl_on: gpioblongrp {
                fsl,pins = <
                        MX7D_PAD_SD1_WP__GPIO5_IO1              0x14 /* SODIMM 71 */
                >;
        };
 
-       pinctrl_gpmi_nand: gpmi-nand-grp {
+       pinctrl_gpmi_nand: gpminandgrp {
                fsl,pins = <
-                       MX7D_PAD_SD3_CLK__NAND_CLE              0x71
-                       MX7D_PAD_SD3_CMD__NAND_ALE              0x71
                        MX7D_PAD_SAI1_TX_BCLK__NAND_CE0_B       0x71
                        MX7D_PAD_SAI1_TX_DATA__NAND_READY_B     0x74
-                       MX7D_PAD_SD3_STROBE__NAND_RE_B          0x71
-                       MX7D_PAD_SD3_RESET_B__NAND_WE_B         0x71
+                       MX7D_PAD_SD3_CLK__NAND_CLE              0x71
+                       MX7D_PAD_SD3_CMD__NAND_ALE              0x71
                        MX7D_PAD_SD3_DATA0__NAND_DATA00         0x71
                        MX7D_PAD_SD3_DATA1__NAND_DATA01         0x71
                        MX7D_PAD_SD3_DATA2__NAND_DATA02         0x71
                        MX7D_PAD_SD3_DATA5__NAND_DATA05         0x71
                        MX7D_PAD_SD3_DATA6__NAND_DATA06         0x71
                        MX7D_PAD_SD3_DATA7__NAND_DATA07         0x71
+                       MX7D_PAD_SD3_RESET_B__NAND_WE_B         0x71
+                       MX7D_PAD_SD3_STROBE__NAND_RE_B          0x71
                >;
        };
 
-       pinctrl_i2c4: i2c4-grp {
+       pinctrl_i2c1_int: i2c1intgrp { /* PMIC / TOUCH */
                fsl,pins = <
-                       MX7D_PAD_ENET1_RGMII_TD3__I2C4_SDA      0x4000007f
-                       MX7D_PAD_ENET1_RGMII_TD2__I2C4_SCL      0x4000007f
+                       MX7D_PAD_GPIO1_IO13__GPIO1_IO13 0x79
+               >;
+       };
+
+       pinctrl_i2c4: i2c4grp {
+               fsl,pins = <
+                       MX7D_PAD_ENET1_RGMII_TD2__I2C4_SCL      0x4000007f /* SODIMM 196 */
+                       MX7D_PAD_ENET1_RGMII_TD3__I2C4_SDA      0x4000007f /* SODIMM 194 */
                >;
        };
 
                >;
        };
 
-       pinctrl_lcdif_dat: lcdif-dat-grp {
+       pinctrl_lcdif_dat: lcdifdatgrp {
+               fsl,pins = <
+                       MX7D_PAD_LCD_DATA00__LCD_DATA0          0x79 /* SODIMM 76 */
+                       MX7D_PAD_LCD_DATA01__LCD_DATA1          0x79 /* SODIMM 70 */
+                       MX7D_PAD_LCD_DATA02__LCD_DATA2          0x79 /* SODIMM 60 */
+                       MX7D_PAD_LCD_DATA03__LCD_DATA3          0x79 /* SODIMM 58 */
+                       MX7D_PAD_LCD_DATA04__LCD_DATA4          0x79 /* SODIMM 78 */
+                       MX7D_PAD_LCD_DATA05__LCD_DATA5          0x79 /* SODIMM 72 */
+                       MX7D_PAD_LCD_DATA06__LCD_DATA6          0x79 /* SODIMM 80 */
+                       MX7D_PAD_LCD_DATA07__LCD_DATA7          0x79 /* SODIMM 46 */
+                       MX7D_PAD_LCD_DATA08__LCD_DATA8          0x79 /* SODIMM 62 */
+                       MX7D_PAD_LCD_DATA09__LCD_DATA9          0x79 /* SODIMM 48 */
+                       MX7D_PAD_LCD_DATA10__LCD_DATA10         0x79 /* SODIMM 74 */
+                       MX7D_PAD_LCD_DATA11__LCD_DATA11         0x79 /* SODIMM 50 */
+                       MX7D_PAD_LCD_DATA12__LCD_DATA12         0x79 /* SODIMM 52 */
+                       MX7D_PAD_LCD_DATA13__LCD_DATA13         0x79 /* SODIMM 54 */
+                       MX7D_PAD_LCD_DATA14__LCD_DATA14         0x79 /* SODIMM 66 */
+                       MX7D_PAD_LCD_DATA15__LCD_DATA15         0x79 /* SODIMM 64 */
+                       MX7D_PAD_LCD_DATA16__LCD_DATA16         0x79 /* SODIMM 57 */
+                       MX7D_PAD_LCD_DATA17__LCD_DATA17         0x79 /* SODIMM 61 */
+               >;
+       };
+
+       pinctrl_lcdif_dat_24: lcdifdat24grp {
                fsl,pins = <
-                       MX7D_PAD_LCD_DATA00__LCD_DATA0          0x79
-                       MX7D_PAD_LCD_DATA01__LCD_DATA1          0x79
-                       MX7D_PAD_LCD_DATA02__LCD_DATA2          0x79
-                       MX7D_PAD_LCD_DATA03__LCD_DATA3          0x79
-                       MX7D_PAD_LCD_DATA04__LCD_DATA4          0x79
-                       MX7D_PAD_LCD_DATA05__LCD_DATA5          0x79
-                       MX7D_PAD_LCD_DATA06__LCD_DATA6          0x79
-                       MX7D_PAD_LCD_DATA07__LCD_DATA7          0x79
-                       MX7D_PAD_LCD_DATA08__LCD_DATA8          0x79
-                       MX7D_PAD_LCD_DATA09__LCD_DATA9          0x79
-                       MX7D_PAD_LCD_DATA10__LCD_DATA10         0x79
-                       MX7D_PAD_LCD_DATA11__LCD_DATA11         0x79
-                       MX7D_PAD_LCD_DATA12__LCD_DATA12         0x79
-                       MX7D_PAD_LCD_DATA13__LCD_DATA13         0x79
-                       MX7D_PAD_LCD_DATA14__LCD_DATA14         0x79
-                       MX7D_PAD_LCD_DATA15__LCD_DATA15         0x79
-                       MX7D_PAD_LCD_DATA16__LCD_DATA16         0x79
-                       MX7D_PAD_LCD_DATA17__LCD_DATA17         0x79
+                       MX7D_PAD_LCD_DATA18__LCD_DATA18         0x79 /* SODIMM 136 */
+                       MX7D_PAD_LCD_DATA19__LCD_DATA19         0x79 /* SODIMM 138 */
+                       MX7D_PAD_LCD_DATA20__LCD_DATA20         0x79 /* SODIMM 140 */
+                       MX7D_PAD_LCD_DATA21__LCD_DATA21         0x79 /* SODIMM 142 */
+                       MX7D_PAD_LCD_DATA22__LCD_DATA22         0x79 /* SODIMM 144 */
+                       MX7D_PAD_LCD_DATA23__LCD_DATA23         0x79 /* SODIMM 146 */
                >;
        };
 
-       pinctrl_lcdif_dat_24: lcdif-dat-24-grp {
+       pinctrl_lcdif_ctrl: lcdifctrlgrp {
                fsl,pins = <
-                       MX7D_PAD_LCD_DATA18__LCD_DATA18         0x79
-                       MX7D_PAD_LCD_DATA19__LCD_DATA19         0x79
-                       MX7D_PAD_LCD_DATA20__LCD_DATA20         0x79
-                       MX7D_PAD_LCD_DATA21__LCD_DATA21         0x79
-                       MX7D_PAD_LCD_DATA22__LCD_DATA22         0x79
-                       MX7D_PAD_LCD_DATA23__LCD_DATA23         0x79
+                       MX7D_PAD_LCD_CLK__LCD_CLK               0x79 /* SODIMM 56 */
+                       MX7D_PAD_LCD_ENABLE__LCD_ENABLE         0x79 /* SODIMM 44 */
+                       MX7D_PAD_LCD_HSYNC__LCD_HSYNC           0x79 /* SODIMM 68 */
+                       MX7D_PAD_LCD_VSYNC__LCD_VSYNC           0x79 /* SODIMM 82 */
                >;
        };
 
-       pinctrl_lcdif_ctrl: lcdif-ctrl-grp {
+       pinctrl_lvds_transceiver: lvdstx {
                fsl,pins = <
-                       MX7D_PAD_LCD_CLK__LCD_CLK               0x79
-                       MX7D_PAD_LCD_ENABLE__LCD_ENABLE         0x79
-                       MX7D_PAD_LCD_VSYNC__LCD_VSYNC           0x79
-                       MX7D_PAD_LCD_HSYNC__LCD_HSYNC           0x79
+                       MX7D_PAD_ENET1_RGMII_RD2__GPIO7_IO2     0x14 /* SODIMM 63 */
+                       MX7D_PAD_ENET1_RGMII_RD3__GPIO7_IO3     0x74 /* SODIMM 55 */
+                       MX7D_PAD_ENET1_RGMII_TXC__GPIO7_IO11    0x14 /* SODIMM 99 */
+                       MX7D_PAD_EPDC_DATA13__GPIO2_IO13        0x14 /* SODIMM 95 */
                >;
        };
 
-       pinctrl_pwm1: pwm1-grp {
+       pinctrl_pwm1: pwm1grp {
                fsl,pins = <
-                       MX7D_PAD_GPIO1_IO08__PWM1_OUT           0x79
-                       MX7D_PAD_ECSPI2_MOSI__GPIO4_IO21        0x4
+                       MX7D_PAD_ECSPI2_MOSI__GPIO4_IO21        0x4  /* SODIMM 59 */
+                       MX7D_PAD_GPIO1_IO08__PWM1_OUT           0x79 /* SODIMM 59 */
                >;
        };
 
-       pinctrl_pwm2: pwm2-grp {
+       pinctrl_pwm2: pwm2grp {
                fsl,pins = <
-                       MX7D_PAD_GPIO1_IO09__PWM2_OUT           0x79
+                       MX7D_PAD_GPIO1_IO09__PWM2_OUT           0x79 /* SODIMM 28 */
                >;
        };
 
-       pinctrl_pwm3: pwm3-grp {
+       pinctrl_pwm3: pwm3grp {
                fsl,pins = <
-                       MX7D_PAD_GPIO1_IO10__PWM3_OUT           0x79
+                       MX7D_PAD_GPIO1_IO10__PWM3_OUT           0x79 /* SODIMM 30 */
                >;
        };
 
-       pinctrl_pwm4: pwm4-grp {
+       pinctrl_pwm4: pwm4grp {
                fsl,pins = <
-                       MX7D_PAD_GPIO1_IO11__PWM4_OUT           0x79
-                       MX7D_PAD_ECSPI2_SCLK__GPIO4_IO20        0x4
+                       MX7D_PAD_ECSPI2_SCLK__GPIO4_IO20        0x4  /* SODIMM 67 */
+                       MX7D_PAD_GPIO1_IO11__PWM4_OUT           0x79 /* SODIMM 67 */
                >;
        };
 
-       pinctrl_uart1: uart1-grp {
+       pinctrl_uart1: uart1grp {
                fsl,pins = <
-                       MX7D_PAD_UART1_TX_DATA__UART1_DTE_RX    0x79
-                       MX7D_PAD_UART1_RX_DATA__UART1_DTE_TX    0x79
-                       MX7D_PAD_SAI2_TX_BCLK__UART1_DTE_CTS    0x79
-                       MX7D_PAD_SAI2_TX_SYNC__UART1_DTE_RTS    0x79
+                       MX7D_PAD_SAI2_TX_BCLK__UART1_DTE_CTS    0x79 /* SODIMM 25 */
+                       MX7D_PAD_SAI2_TX_SYNC__UART1_DTE_RTS    0x79 /* SODIMM 27 */
+                       MX7D_PAD_UART1_RX_DATA__UART1_DTE_TX    0x79 /* SODIMM 35 */
+                       MX7D_PAD_UART1_TX_DATA__UART1_DTE_RX    0x79 /* SODIMM 33 */
                >;
        };
 
-       pinctrl_uart1_ctrl1: uart1-ctrl1-grp {
+       pinctrl_uart1_ctrl1: uart1ctrl1grp {
                fsl,pins = <
-                       MX7D_PAD_SD2_DATA1__GPIO5_IO15          0x14 /* DCD */
-                       MX7D_PAD_SD2_DATA0__GPIO5_IO14          0x14 /* DTR */
+                       MX7D_PAD_SD2_DATA0__GPIO5_IO14          0x14 /* SODIMM 23 / DTR */
+                       MX7D_PAD_SD2_DATA1__GPIO5_IO15          0x14 /* SODIMM 31 / DCD */
                >;
        };
 
-       pinctrl_uart2: uart2-grp {
+       pinctrl_uart2: uart2grp {
+               fsl,pins = <
+                       MX7D_PAD_SAI2_RX_DATA__UART2_DTE_RTS    0x79 /* SODIMM 32 / CTS */
+                       MX7D_PAD_SAI2_TX_DATA__UART2_DTE_CTS    0x79 /* SODIMM 34 / RTS */
+                       MX7D_PAD_UART2_RX_DATA__UART2_DTE_TX    0x79 /* SODIMM 38 */
+                       MX7D_PAD_UART2_TX_DATA__UART2_DTE_RX    0x79 /* SODIMM 36 */
+               >;
+       };
+       pinctrl_uart3: uart3grp {
                fsl,pins = <
-                       MX7D_PAD_UART2_TX_DATA__UART2_DTE_RX 0x79
-                       MX7D_PAD_UART2_RX_DATA__UART2_DTE_TX 0x79
-                       MX7D_PAD_SAI2_RX_DATA__UART2_DTE_RTS 0x79
-                       MX7D_PAD_SAI2_TX_DATA__UART2_DTE_CTS 0x79
+                       MX7D_PAD_UART3_RX_DATA__UART3_DTE_TX    0x79 /* SODIMM 21 */
+                       MX7D_PAD_UART3_TX_DATA__UART3_DTE_RX    0x79 /* SODIMM 19 */
                >;
        };
-       pinctrl_uart3: uart3-grp {
+
+       pinctrl_usbc_det: usbcdetgrp {
                fsl,pins = <
-                       MX7D_PAD_UART3_TX_DATA__UART3_DTE_RX 0x79
-                       MX7D_PAD_UART3_RX_DATA__UART3_DTE_TX 0x79
+                       MX7D_PAD_ENET1_CRS__GPIO7_IO14          0x14 /* SODIMM 137 / USBC_DET */
                >;
        };
 
-       pinctrl_usbc_det: gpio-usbc-det {
+       pinctrl_usbh_reg: usbhreggrp {
                fsl,pins = <
-                       MX7D_PAD_ENET1_CRS__GPIO7_IO14  0x14
+                       MX7D_PAD_UART3_CTS_B__GPIO4_IO7         0x14 /* SODIMM 129 / USBH_PEN */
                >;
        };
 
-       pinctrl_usbh_reg: gpio-usbh-vbus {
+       pinctrl_usdhc1: usdhc1grp {
                fsl,pins = <
-                       MX7D_PAD_UART3_CTS_B__GPIO4_IO7 0x14 /* SODIMM 129 USBH PEN */
+                       MX7D_PAD_SD1_CLK__SD1_CLK               0x19 /* SODIMM 47 */
+                       MX7D_PAD_SD1_CMD__SD1_CMD               0x59 /* SODIMM 190 */
+                       MX7D_PAD_SD1_DATA0__SD1_DATA0           0x59 /* SODIMM 192 */
+                       MX7D_PAD_SD1_DATA1__SD1_DATA1           0x59 /* SODIMM 49 */
+                       MX7D_PAD_SD1_DATA2__SD1_DATA2           0x59 /* SODIMM 51 */
+                       MX7D_PAD_SD1_DATA3__SD1_DATA3           0x59 /* SODIMM 53 */
                >;
        };
 
-       pinctrl_usdhc1: usdhc1-grp {
+       pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp {
                fsl,pins = <
-                       MX7D_PAD_SD1_CMD__SD1_CMD       0x59
-                       MX7D_PAD_SD1_CLK__SD1_CLK       0x19
-                       MX7D_PAD_SD1_DATA0__SD1_DATA0   0x59
-                       MX7D_PAD_SD1_DATA1__SD1_DATA1   0x59
-                       MX7D_PAD_SD1_DATA2__SD1_DATA2   0x59
-                       MX7D_PAD_SD1_DATA3__SD1_DATA3   0x59
+                       MX7D_PAD_SD1_CLK__SD1_CLK               0x1a
+                       MX7D_PAD_SD1_CMD__SD1_CMD               0x5a
+                       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_100mhz: usdhc1grp_100mhz {
+       pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp {
                fsl,pins = <
-                       MX7D_PAD_SD1_CMD__SD1_CMD       0x5a
-                       MX7D_PAD_SD1_CLK__SD1_CLK       0x1a
-                       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
+                       MX7D_PAD_SD1_CLK__SD1_CLK               0x1b
+                       MX7D_PAD_SD1_CMD__SD1_CMD               0x5b
+                       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
                >;
        };
 
-       pinctrl_usdhc1_200mhz: usdhc1grp_200mhz {
+       /* Avoid backfeeding with removed card power. */
+       pinctrl_usdhc1_sleep: usdhc1-slpgrp {
                fsl,pins = <
-                       MX7D_PAD_SD1_CMD__SD1_CMD       0x5b
-                       MX7D_PAD_SD1_CLK__SD1_CLK       0x1b
-                       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
+                       MX7D_PAD_SD1_CMD__SD1_CMD               0x10
+                       MX7D_PAD_SD1_CLK__SD1_CLK               0x10
+                       MX7D_PAD_SD1_DATA0__SD1_DATA0           0x10
+                       MX7D_PAD_SD1_DATA1__SD1_DATA1           0x10
+                       MX7D_PAD_SD1_DATA2__SD1_DATA2           0x10
+                       MX7D_PAD_SD1_DATA3__SD1_DATA3           0x10
                >;
        };
 
        pinctrl_usdhc3: usdhc3grp {
                fsl,pins = <
-                       MX7D_PAD_SD3_CMD__SD3_CMD               0x59
                        MX7D_PAD_SD3_CLK__SD3_CLK               0x19
+                       MX7D_PAD_SD3_CMD__SD3_CMD               0x59
                        MX7D_PAD_SD3_DATA0__SD3_DATA0           0x59
                        MX7D_PAD_SD3_DATA1__SD3_DATA1           0x59
                        MX7D_PAD_SD3_DATA2__SD3_DATA2           0x59
                >;
        };
 
-       pinctrl_usdhc3_100mhz: usdhc3grp_100mhz {
+       pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp {
                fsl,pins = <
-                       MX7D_PAD_SD3_CMD__SD3_CMD               0x5a
                        MX7D_PAD_SD3_CLK__SD3_CLK               0x1a
+                       MX7D_PAD_SD3_CMD__SD3_CMD               0x5a
                        MX7D_PAD_SD3_DATA0__SD3_DATA0           0x5a
                        MX7D_PAD_SD3_DATA1__SD3_DATA1           0x5a
                        MX7D_PAD_SD3_DATA2__SD3_DATA2           0x5a
                >;
        };
 
-       pinctrl_usdhc3_200mhz: usdhc3grp_200mhz {
+       pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp {
                fsl,pins = <
-                       MX7D_PAD_SD3_CMD__SD3_CMD               0x5b
                        MX7D_PAD_SD3_CLK__SD3_CLK               0x1b
+                       MX7D_PAD_SD3_CMD__SD3_CMD               0x5b
                        MX7D_PAD_SD3_DATA0__SD3_DATA0           0x5b
                        MX7D_PAD_SD3_DATA1__SD3_DATA1           0x5b
                        MX7D_PAD_SD3_DATA2__SD3_DATA2           0x5b
                >;
        };
 
-       pinctrl_sai1: sai1-grp {
+       pinctrl_sai1: sai1grp {
                fsl,pins = <
-                       MX7D_PAD_ENET1_RX_CLK__SAI1_TX_BCLK     0x1f
-                       MX7D_PAD_SAI1_TX_SYNC__SAI1_TX_SYNC     0x1f
                        MX7D_PAD_ENET1_COL__SAI1_TX_DATA0       0x30
+                       MX7D_PAD_ENET1_RX_CLK__SAI1_TX_BCLK     0x1f
                        MX7D_PAD_ENET1_TX_CLK__SAI1_RX_DATA0    0x1f
+                       MX7D_PAD_SAI1_TX_SYNC__SAI1_TX_SYNC     0x1f
                >;
        };
 
-       pinctrl_sai1_mclk: sai1grp_mclk {
+       pinctrl_sai1_mclk: sai1mclkgrp {
                fsl,pins = <
                        MX7D_PAD_SAI1_MCLK__SAI1_MCLK           0x1f
                >;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_gpio_lpsr>;
 
-       pinctrl_gpio_lpsr: gpio1-grp {
+       pinctrl_cd_usdhc1: cdusdhc1grp {
                fsl,pins = <
-                       MX7D_PAD_LPSR_GPIO1_IO02__GPIO1_IO2     0x59
-                       MX7D_PAD_LPSR_GPIO1_IO03__GPIO1_IO3     0x59
+                       MX7D_PAD_LPSR_GPIO1_IO00__GPIO1_IO0     0x59 /* SODIMM 43 / MMC_CD */
+               >;
+       };
+
+       pinctrl_cd_usdhc1_sleep: cdusdhc1-slpgrp {
+               fsl,pins = <
+                       MX7D_PAD_LPSR_GPIO1_IO00__GPIO1_IO0     0x0
+               >;
+       };
+
+       pinctrl_gpio_lpsr: gpiolpsrgrp {
+               fsl,pins = <
+                       MX7D_PAD_LPSR_GPIO1_IO02__GPIO1_IO2     0x59 /* SODIMM 135 */
+                       MX7D_PAD_LPSR_GPIO1_IO03__GPIO1_IO3     0x59 /* SODIMM 22 */
                >;
        };
 
        pinctrl_gpiokeys: gpiokeysgrp {
                fsl,pins = <
-                       MX7D_PAD_LPSR_GPIO1_IO01__GPIO1_IO1     0x19
+                       MX7D_PAD_LPSR_GPIO1_IO01__GPIO1_IO1     0x19 /* SODIMM 45 / WAKE_UP */
                >;
        };
 
-       pinctrl_i2c1: i2c1-grp {
+       pinctrl_i2c1: i2c1grp {
                fsl,pins = <
-                       MX7D_PAD_LPSR_GPIO1_IO05__I2C1_SDA      0x4000007f
                        MX7D_PAD_LPSR_GPIO1_IO04__I2C1_SCL      0x4000007f
+                       MX7D_PAD_LPSR_GPIO1_IO05__I2C1_SDA      0x4000007f
                >;
        };
 
                >;
        };
 
-       pinctrl_cd_usdhc1: usdhc1-cd-grp {
-               fsl,pins = <
-                       MX7D_PAD_LPSR_GPIO1_IO00__GPIO1_IO0     0x59 /* CD */
-               >;
-       };
-
-       pinctrl_uart1_ctrl2: uart1-ctrl2-grp {
+       pinctrl_uart1_ctrl2: uart1ctrl2grp {
                fsl,pins = <
-                       MX7D_PAD_LPSR_GPIO1_IO07__GPIO1_IO7     0x14 /* DSR */
-                       MX7D_PAD_LPSR_GPIO1_IO06__GPIO1_IO6     0x14 /* RI */
+                       MX7D_PAD_LPSR_GPIO1_IO06__GPIO1_IO6     0x14 /* SODIMM 37 / RI */
+                       MX7D_PAD_LPSR_GPIO1_IO07__GPIO1_IO7     0x14 /* SODIMM 29 / DSR */
                >;
        };
 };
index f3f0537..90aaedd 100644 (file)
@@ -1,7 +1,6 @@
-// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
 /*
- * Copyright 2017-2020 Toradex AG
- *
+ * Copyright 2017-2022 Toradex
  */
 
 /dts-v1/;
 
 / {
        model = "Toradex Colibri iMX7D on Aster Carrier Board";
-       compatible = "toradex,colibri-imx7d-aster", "toradex,colibri-imx7d",
+       compatible = "toradex,colibri-imx7d-aster",
+                    "toradex,colibri-imx7d",
                     "fsl,imx7d";
 };
 
+&ad7879_ts {
+       status = "okay";
+};
+
+&atmel_mxt_ts {
+       status = "okay";
+};
+
+&backlight {
+       status = "okay";
+};
+
+&lcdif {
+       status = "okay";
+};
+
+&panel_dpi {
+       status = "okay";
+};
+
+/* Colibri USBH */
 &usbotg2 {
-       vbus-supply = <&reg_usbh_vbus>;
        status = "okay";
 };
index 2048027..3ec9ef6 100644 (file)
@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
 /*
- * Copyright 2017-2020 Toradex AG
+ * Copyright 2017-2022 Toradex
  *
  */
 
 / {
        model = "Toradex Colibri iMX7D 1GB (eMMC) on Aster Carrier Board";
        compatible = "toradex,colibri-imx7d-emmc-aster",
-                    "toradex,colibri-imx7d-emmc", "fsl,imx7d";
+                    "toradex,colibri-imx7d-emmc",
+                    "toradex,colibri-imx7d",
+                    "fsl,imx7d";
 };
 
+/* Colibri USBH */
 &usbotg2 {
-       vbus-supply = <&reg_usbh_vbus>;
        status = "okay";
 };
index 8ee73c8..6d505cb 100644 (file)
@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
 /*
- * Copyright 2017 Toradex AG
+ * Copyright 2017-2022 Toradex
  */
 
 /dts-v1/;
 / {
        model = "Toradex Colibri iMX7D 1GB (eMMC) on Colibri Evaluation Board V3";
        compatible = "toradex,colibri-imx7d-emmc-eval-v3",
-                    "toradex,colibri-imx7d-emmc", "fsl,imx7d";
+                    "toradex,colibri-imx7d-emmc",
+                    "toradex,colibri-imx7d",
+                    "fsl,imx7d";
 };
 
+/* Colibri USBH */
 &usbotg2 {
-       vbus-supply = <&reg_usbh_vbus>;
        status = "okay";
 };
diff --git a/arch/arm/boot/dts/imx7d-colibri-emmc-iris-v2.dts b/arch/arm/boot/dts/imx7d-colibri-emmc-iris-v2.dts
new file mode 100644 (file)
index 0000000..7347659
--- /dev/null
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright 2022 Toradex
+ */
+
+/dts-v1/;
+#include "imx7d-colibri-emmc.dtsi"
+#include "imx7-colibri-iris-v2.dtsi"
+
+/ {
+       model = "Toradex Colibri iMX7D 1GB on Iris V2 Carrier Board";
+       compatible = "toradex,colibri-imx7d-emmc-iris-v2",
+                    "toradex,colibri-imx7d-emmc",
+                    "toradex,colibri-imx7d",
+                    "fsl,imx7d";
+};
+
+/* Colibri USBH */
+&usbotg2 {
+       status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx7d-colibri-emmc-iris.dts b/arch/arm/boot/dts/imx7d-colibri-emmc-iris.dts
new file mode 100644 (file)
index 0000000..5324c92
--- /dev/null
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright 2022 Toradex
+ */
+
+/dts-v1/;
+#include "imx7d-colibri-emmc.dtsi"
+#include "imx7-colibri-iris.dtsi"
+
+/ {
+       model = "Toradex Colibri iMX7D 1GB on Iris Carrier Board";
+       compatible = "toradex,colibri-imx7d-emmc-iris",
+                    "toradex,colibri-imx7d-emmc",
+                    "toradex,colibri-imx7d",
+                    "fsl,imx7d";
+};
+
+/* Colibri USBH */
+&usbotg2 {
+       status = "okay";
+};
index af39e53..2fb4d21 100644 (file)
@@ -1,18 +1,28 @@
-// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
 /*
- * Copyright 2017 Toradex AG
+ * Copyright 2017-2022 Toradex
  */
 
 #include "imx7d.dtsi"
 #include "imx7-colibri.dtsi"
 
 / {
+       aliases {
+               /* Required to properly pass MAC addresses from bootloader. */
+               ethernet0 = &fec1;
+               ethernet1 = &fec2;
+       };
+
        memory@80000000 {
                device_type = "memory";
                reg = <0x80000000 0x40000000>;
        };
 };
 
+&cpu1 {
+       cpu-supply = <&reg_DCDC2>;
+};
+
 &gpio6 {
        gpio-line-names = "",
                          "",
                          "SODIMM_34";
 };
 
+/* Colibri USBH */
 &usbotg2 {
        dr_mode = "host";
+       vbus-supply = <&reg_usbh_vbus>;
 };
 
+/* eMMC */
 &usdhc3 {
        status = "okay";
 };
index 87b132b..c7a8b5a 100644 (file)
@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: GPL-2.0+ OR MIT
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
 /*
- * Copyright 2016-2020 Toradex
+ * Copyright 2016-2022 Toradex
  */
 
 /dts-v1/;
@@ -9,11 +9,48 @@
 
 / {
        model = "Toradex Colibri iMX7D on Colibri Evaluation Board V3";
-       compatible = "toradex,colibri-imx7d-eval-v3", "toradex,colibri-imx7d",
+       compatible = "toradex,colibri-imx7d-eval-v3",
+                    "toradex,colibri-imx7d",
                     "fsl,imx7d";
 };
 
+&ad7879_ts {
+       status = "okay";
+};
+
+/*
+ * The Atmel maxtouch controller uses SODIMM 28/30, also used for PWM<B>, PWM<C>, aka pwm2, pwm3.
+ * So if you enable following capacitive touch controller, disable pwm2/pwm3 first.
+ */
+&atmel_mxt_ts {
+       status = "disabled";
+};
+
+&backlight {
+       status = "okay";
+};
+
+&lcdif {
+       status = "okay";
+};
+
+&panel_dpi {
+       status = "okay";
+};
+
+/* Colibri PWM<B> */
+&pwm2 {
+       /* The pwm2 should be disabled to enable atmel_mxt_ts touchscreen for adapter. */
+       status = "okay";
+};
+
+/* Colibri PWM<C> */
+&pwm3 {
+       /* The pwm3 should be disabled to enable atmel_mxt_ts touchscreen for adapter. */
+       status = "okay";
+};
+
+/* Colibri USBH */
 &usbotg2 {
-       vbus-supply = <&reg_usbh_vbus>;
        status = "okay";
 };
diff --git a/arch/arm/boot/dts/imx7d-colibri-iris-v2.dts b/arch/arm/boot/dts/imx7d-colibri-iris-v2.dts
new file mode 100644 (file)
index 0000000..5762f51
--- /dev/null
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright 2022 Toradex
+ */
+
+/dts-v1/;
+#include "imx7d-colibri.dtsi"
+#include "imx7-colibri-iris-v2.dtsi"
+
+/ {
+       model = "Toradex Colibri iMX7D on Iris V2 Carrier Board";
+       compatible = "toradex,colibri-imx7d-iris-v2",
+                    "toradex,colibri-imx7d",
+                    "fsl,imx7d";
+};
+
+&ad7879_ts {
+       status = "okay";
+};
+
+&atmel_mxt_ts {
+       status = "okay";
+};
+
+&backlight {
+       status = "okay";
+};
+
+&gpio2 {
+       /*
+        * This switches the LVDS transceiver to VESA color mapping mode.
+        */
+       lvds-color-map-hog {
+               gpio-hog;
+               gpios = <13 GPIO_ACTIVE_HIGH>; /* SODIMM 95 */
+               line-name = "LVDS_COLOR_MAP";
+               output-low;
+       };
+};
+
+&gpio7 {
+       /*
+        * This switches the LVDS transceiver to the 24-bit RGB mode.
+        */
+       lvds-rgb-mode-hog {
+               gpio-hog;
+               gpios = <2 GPIO_ACTIVE_HIGH>; /* SODIMM 63 */
+               line-name = "LVDS_RGB_MODE";
+               output-low;
+       };
+
+       /*
+        * This switches the LVDS transceiver to the single-channel
+        * output mode.
+        */
+       lvds-ch-mode-hog {
+               gpio-hog;
+               gpios = <3 GPIO_ACTIVE_HIGH>; /* SODIMM 55 */
+               line-name = "LVDS_CH_MODE";
+               output-high;
+       };
+
+       /* This turns the LVDS transceiver on */
+       lvds-power-on-hog {
+               gpio-hog;
+               gpios = <11 GPIO_ACTIVE_HIGH>; /* SODIMM 99 */
+               line-name = "LVDS_POWER_ON";
+               output-high;
+       };
+};
+
+&lcdif {
+       status = "okay";
+};
+
+&panel_dpi {
+       status = "okay";
+};
+
+/* Colibri USBH */
+&usbotg2 {
+       status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx7d-colibri-iris.dts b/arch/arm/boot/dts/imx7d-colibri-iris.dts
new file mode 100644 (file)
index 0000000..9c63cb9
--- /dev/null
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright 2022 Toradex
+ */
+
+/dts-v1/;
+#include "imx7d-colibri.dtsi"
+#include "imx7-colibri-iris.dtsi"
+
+/ {
+       model = "Toradex Colibri iMX7D on Iris Carrier Board";
+       compatible = "toradex,colibri-imx7d-iris",
+                    "toradex,colibri-imx7d",
+                    "fsl,imx7d";
+};
+
+&ad7879_ts {
+       status = "okay";
+};
+
+/*
+ * The Atmel maxtouch controller uses SODIMM 28/30, also used for PWM<B>, PWM<C>, aka pwm2, pwm3.
+ * So if you enable following capacitive touch controller, disable pwm2/pwm3 first.
+ */
+&atmel_mxt_ts {
+       status = "disabled";
+};
+
+&backlight {
+       status = "okay";
+};
+
+&lcdif {
+       status = "okay";
+};
+
+&panel_dpi {
+       status = "okay";
+};
+
+/* Colibri PWM<B> */
+&pwm2 {
+       /* The pwm2 should be disabled to enable atmel_mxt_ts touchscreen for adapter. */
+       status = "okay";
+};
+
+/* Colibri PWM<C> */
+&pwm3 {
+       /* The pwm3 should be disabled to enable atmel_mxt_ts touchscreen for adapter. */
+       status = "okay";
+};
+
+/* Colibri USBH */
+&usbotg2 {
+       status = "okay";
+};
index 219a040..531a45b 100644 (file)
@@ -1,12 +1,18 @@
-// SPDX-License-Identifier: GPL-2.0+ OR MIT
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
 /*
- * Copyright 2016-2020 Toradex
+ * Copyright 2016-2022 Toradex
  */
 
 #include "imx7d.dtsi"
 #include "imx7-colibri.dtsi"
 
 / {
+       aliases {
+               /* Required to properly pass MAC addresses from bootloader. */
+               ethernet0 = &fec1;
+               ethernet1 = &fec2;
+       };
+
        memory@80000000 {
                device_type = "memory";
                reg = <0x80000000 0x20000000>;
        cpu-supply = <&reg_DCDC2>;
 };
 
+/* NAND */
 &gpmi {
        status = "okay";
 };
 
+/* Colibri USBH */
 &usbotg2 {
        dr_mode = "host";
+       vbus-supply = <&reg_usbh_vbus>;
 };
index f053f51..78f4224 100644 (file)
                compatible = "ti,tsc2046";
                reg = <0>;
                spi-max-frequency = <1000000>;
-               pinctrl-names ="default";
+               pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_tsc2046_pendown>;
                interrupt-parent = <&gpio2>;
                interrupts = <29 0>;
index c6b3206..546268b 100644 (file)
        pinctrl-0 = <&pinctrl_usdhc1>;
        cd-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
        no-1-8-v;
-       enable-sdio-wakeup;
+       wakeup-source;
        keep-power-in-suspend;
        status = "okay";
 };
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc2>;
        bus-width = <4>;
+       no-1-8-v;
        non-removable;
-       cap-sd-highspeed;
-       sd-uhs-ddr50;
-       mmc-ddr-1_8v;
        vmmc-supply = <&reg_wifi>;
-       enable-sdio-wakeup;
+       wakeup-source;
        status = "okay";
 };
 
index f8cba47..7ceb7c0 100644 (file)
@@ -78,7 +78,7 @@
                #phy-cells = <0>;
        };
 
-       soc {
+       soc: soc {
                etm@3007d000 {
                        compatible = "arm,coresight-etm3x", "arm,primecell";
                        reg = <0x3007d000 0x1000>;
index fca4e0a..58ebb02 100644 (file)
@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
 /*
- * Copyright 2017-2020 Toradex AG
+ * Copyright 2017-2022 Toradex
  *
  */
 
 
 / {
        model = "Toradex Colibri iMX7S on Aster Carrier Board";
-       compatible = "toradex,colibri-imx7s-aster", "toradex,colibri-imx7s",
+       compatible = "toradex,colibri-imx7s-aster",
+                    "toradex,colibri-imx7s",
                     "fsl,imx7s";
 };
+
+&ad7879_ts {
+       status = "okay";
+};
+
+&atmel_mxt_ts {
+       status = "okay";
+};
+
+&backlight {
+       status = "okay";
+};
+
+&lcdif {
+       status = "okay";
+};
+
+&panel_dpi {
+       status = "okay";
+};
index aa70d3f..38de766 100644 (file)
@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: GPL-2.0+ OR MIT
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
 /*
- * Copyright 2016-2020 Toradex
+ * Copyright 2016-2022 Toradex
  */
 
 /dts-v1/;
@@ -9,6 +9,43 @@
 
 / {
        model = "Toradex Colibri iMX7S on Colibri Evaluation Board V3";
-       compatible = "toradex,colibri-imx7s-eval-v3", "toradex,colibri-imx7s",
+       compatible = "toradex,colibri-imx7s-eval-v3",
+                    "toradex,colibri-imx7s",
                     "fsl,imx7s";
 };
+
+&ad7879_ts {
+       status = "okay";
+};
+
+/*
+ * The Atmel maxtouch controller uses SODIMM 28/30, also used for PWM<B>, PWM<C>, aka pwm2, pwm3.
+ * So if you enable following capacitive touch controller, disable pwm2/pwm3 first.
+ */
+&atmel_mxt_ts {
+       status = "disabled";
+};
+
+&backlight {
+       status = "okay";
+};
+
+&lcdif {
+       status = "okay";
+};
+
+&panel_dpi {
+       status = "okay";
+};
+
+/* Colibri PWM<B> */
+&pwm2 {
+       /* The pwm2 should be disabled to enable atmel_mxt_ts touchscreen for adapter. */
+       status = "okay";
+};
+
+/* Colibri PWM<C> */
+&pwm3 {
+       /* The pwm3 should be disabled to enable atmel_mxt_ts touchscreen for adapter. */
+       status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx7s-colibri-iris-v2.dts b/arch/arm/boot/dts/imx7s-colibri-iris-v2.dts
new file mode 100644 (file)
index 0000000..72b5c17
--- /dev/null
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright 2022 Toradex
+ */
+
+/dts-v1/;
+#include "imx7s-colibri.dtsi"
+#include "imx7-colibri-iris-v2.dtsi"
+
+/ {
+       model = "Toradex Colibri iMX7S on Iris V2 Carrier Board";
+       compatible = "toradex,colibri-imx7s-iris-v2",
+                    "toradex,colibri-imx7s",
+                    "fsl,imx7s";
+};
+
+&ad7879_ts {
+       status = "okay";
+};
+
+&atmel_mxt_ts {
+       status = "okay";
+};
+
+&backlight {
+       status = "okay";
+};
+
+&gpio2 {
+       /*
+        * This switches the LVDS transceiver to VESA color mapping mode.
+        */
+       lvds-color-map-hog {
+               gpio-hog;
+               gpios = <13 GPIO_ACTIVE_HIGH>; /* SODIMM 95 */
+               line-name = "LVDS_COLOR_MAP";
+               output-low;
+       };
+};
+
+&gpio7 {
+       /*
+        * This switches the LVDS transceiver to the 24-bit RGB mode.
+        */
+       lvds-rgb-mode-hog {
+               gpio-hog;
+               gpios = <2 GPIO_ACTIVE_HIGH>; /* SODIMM 63 */
+               line-name = "LVDS_RGB_MODE";
+               output-low;
+       };
+
+       /*
+        * This switches the LVDS transceiver to the single-channel
+        * output mode.
+        */
+       lvds-ch-mode-hog {
+               gpio-hog;
+               gpios = <3 GPIO_ACTIVE_HIGH>; /* SODIMM 55 */
+               line-name = "LVDS_CH_MODE";
+               output-high;
+       };
+
+       /* This turns the LVDS transceiver on */
+       lvds-power-on-hog {
+               gpio-hog;
+               gpios = <11 GPIO_ACTIVE_HIGH>; /* SODIMM 99 */
+               line-name = "LVDS_POWER_ON";
+               output-high;
+       };
+};
+
+&lcdif {
+       status = "okay";
+};
+
+&panel_dpi {
+       status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx7s-colibri-iris.dts b/arch/arm/boot/dts/imx7s-colibri-iris.dts
new file mode 100644 (file)
index 0000000..26ba72c
--- /dev/null
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright 2022 Toradex
+ */
+
+/dts-v1/;
+#include "imx7s-colibri.dtsi"
+#include "imx7-colibri-iris.dtsi"
+
+/ {
+       model = "Toradex Colibri iMX7S on Iris Carrier Board";
+       compatible = "toradex,colibri-imx7s-iris",
+                    "toradex,colibri-imx7s",
+                    "fsl,imx7s";
+};
+
+&ad7879_ts {
+       status = "okay";
+};
+
+/*
+ * The Atmel maxtouch controller uses SODIMM 28/30, also used for PWM<B>, PWM<C>, aka pwm2, pwm3.
+ * So if you enable following capacitive touch controller, disable pwm2/pwm3 first.
+ */
+&atmel_mxt_ts {
+       status = "disabled";
+};
+
+&backlight {
+       status = "okay";
+};
+
+&lcdif {
+       status = "okay";
+};
+
+&panel_dpi {
+       status = "okay";
+};
+
+/* Colibri PWM<B> */
+&pwm2 {
+       /* The pwm2 should be disabled to enable atmel_mxt_ts touchscreen for adapter. */
+       status = "okay";
+};
+
+/* Colibri PWM<C> */
+&pwm3 {
+       /* The pwm3 should be disabled to enable atmel_mxt_ts touchscreen for adapter. */
+       status = "okay";
+};
index 94de220..ef51395 100644 (file)
@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: GPL-2.0+ OR MIT
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
 /*
- * Copyright 2016-2020 Toradex
+ * Copyright 2016-2022 Toradex
  */
 
 #include "imx7s.dtsi"
@@ -13,6 +13,7 @@
        };
 };
 
+/* NAND */
 &gpmi {
        status = "okay";
 };
index 008e3da..2914828 100644 (file)
                compatible = "usb-nop-xceiv";
                clocks = <&clks IMX7D_USB_HSIC_ROOT_CLK>;
                clock-names = "main_clk";
+               power-domains = <&pgc_hsic_phy>;
                #phy-cells = <0>;
        };
 
                             <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>;
        };
 
-       soc {
+       soc: soc {
                #address-cells = <1>;
                #size-cells = <1>;
                compatible = "simple-bus";
                                compatible = "fsl,imx7d-usb", "fsl,imx27-usb";
                                reg = <0x30b30000 0x200>;
                                interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
-                               power-domains = <&pgc_hsic_phy>;
                                clocks = <&clks IMX7D_USB_CTRL_CLK>;
                                fsl,usbphy = <&usbphynop3>;
                                fsl,usbmisc = <&usbmisc3 0>;
index 77b911b..03e6a85 100644 (file)
@@ -83,7 +83,7 @@
                };
 
                usdhc1: mmc@402c0000 {
-                       compatible ="fsl,imxrt1050-usdhc", "fsl,imx6sl-usdhc";
+                       compatible = "fsl,imxrt1050-usdhc", "fsl,imx6sl-usdhc";
                        reg = <0x402c0000 0x4000>;
                        interrupts = <110>;
                        clocks = <&clks IMXRT1050_CLK_IPG_PDOF>,
@@ -95,7 +95,7 @@
                        no-1-8-v;
                        max-frequency = <4000000>;
                        fsl,tuning-start-tap = <20>;
-                       fsl,tuning-step= <2>;
+                       fsl,tuning-step = <2>;
                        status = "disabled";
                };
 
index 7106448..42cf74d 100644 (file)
@@ -12,9 +12,9 @@ qmss: qmss@2a40000 {
        #size-cells = <1>;
        clocks = <&chipclk13>;
        ranges;
-       queue-range     = <0 0x2000>;
-       linkram0        = <0x100000 0x4000>;
-       linkram1        = <0 0x10000>;
+       queue-range = <0 0x2000>;
+       linkram0 = <0x100000 0x4000>;
+       linkram1 = <0 0x10000>;
 
        qmgrs {
                #address-cells = <1>;
@@ -176,40 +176,40 @@ netcp: netcp@24000000 {
                        interfaces {
                                gbe0: interface-0 {
                                        slave-port = <0>;
-                                       link-interface  = <1>;
-                                       phy-handle      = <&ethphy0>;
+                                       link-interface = <1>;
+                                       phy-handle = <&ethphy0>;
                                };
                                gbe1: interface-1 {
                                        slave-port = <1>;
-                                       link-interface  = <1>;
-                                       phy-handle      = <&ethphy1>;
+                                       link-interface = <1>;
+                                       phy-handle = <&ethphy1>;
                                };
                        };
 
                        secondary-slave-ports {
                                port-2 {
                                        slave-port = <2>;
-                                       link-interface  = <2>;
+                                       link-interface = <2>;
                                };
                                port-3 {
                                        slave-port = <3>;
-                                       link-interface  = <2>;
+                                       link-interface = <2>;
                                };
                                port-4 {
                                        slave-port = <4>;
-                                       link-interface  = <2>;
+                                       link-interface = <2>;
                                };
                                port-5 {
                                        slave-port = <5>;
-                                       link-interface  = <2>;
+                                       link-interface = <2>;
                                };
                                port-6 {
                                        slave-port = <6>;
-                                       link-interface  = <2>;
+                                       link-interface = <2>;
                                };
                                port-7 {
                                        slave-port = <7>;
-                                       link-interface  = <2>;
+                                       link-interface = <2>;
                                };
                        };
                };
index b8f152e..65c3294 100644 (file)
                        clock-names = "pcie";
                        #address-cells = <3>;
                        #size-cells = <2>;
-                       reg =  <0x21021000 0x2000>, <0x21020000 0x1000>, <0x02620128 4>;
+                       reg = <0x21021000 0x2000>, <0x21020000 0x1000>, <0x02620128 4>;
                        ranges = <0x82000000 0 0x60000000 0x60000000
                                  0 0x10000000>;
 
                };
 
                mdio: mdio@24200f00 {
-                       compatible      = "ti,keystone_mdio", "ti,davinci_mdio";
+                       compatible = "ti,keystone_mdio", "ti,davinci_mdio";
                        #address-cells = <1>;
                        #size-cells = <0>;
                        reg = <0x24200f00 0x100>;
                        status = "disabled";
                        clocks = <&clkcpgmac>;
                        clock-names = "fck";
-                       bus_freq        = <2500000>;
+                       bus_freq = <2500000>;
                };
                /include/ "keystone-k2e-netcp.dtsi"
 };
index d0e6a9a..f630693 100644 (file)
@@ -125,7 +125,7 @@ netcp: netcp@4000000 {
                        interfaces {
                                gbe0: interface-0 {
                                        slave-port = <0>;
-                                       link-interface  = <5>;
+                                       link-interface = <5>;
                                };
                        };
                };
index 3719829..380dd9d 100644 (file)
                         */
                        ti,system-reboot-controller;
                        mbox-names = "rx", "tx";
-                       mboxes= <&msgmgr 5 2>,
+                       mboxes = <&msgmgr 5 2>,
                                <&msgmgr 0 0>;
                        reg-names = "debug_messages";
                        reg = <0x02921c00 0x400>;
 
                dss: dss@02540000 {
                        compatible = "ti,k2g-dss";
-                       reg =   <0x02540000 0x400>,
+                       reg = <0x02540000 0x400>,
                                <0x02550000 0x1000>,
                                <0x02557000 0x1000>,
                                <0x0255a800 0x100>,
                                <0x0255ac00 0x100>;
                        reg-names = "cfg", "common", "vid1", "ovr1", "vp1";
-                       clocks =        <&k2g_clks 0x2 0>,
+                       clocks = <&k2g_clks 0x2 0>,
                                        <&k2g_clks 0x2 1>;
                        clock-names = "fck", "vp1";
                        interrupts = <GIC_SPI 247 IRQ_TYPE_EDGE_RISING>;
 
                edma0: edma@2700000 {
                        compatible = "ti,k2g-edma3-tpcc", "ti,edma3-tpcc";
-                       reg =   <0x02700000 0x8000>;
+                       reg = <0x02700000 0x8000>;
                        reg-names = "edma3_cc";
                        interrupts = <GIC_SPI 200 IRQ_TYPE_EDGE_RISING>,
                                        <GIC_SPI 216 IRQ_TYPE_EDGE_RISING>,
 
                edma0_tptc0: tptc@2760000 {
                        compatible = "ti,k2g-edma3-tptc", "ti,edma3-tptc";
-                       reg =   <0x02760000 0x400>;
+                       reg = <0x02760000 0x400>;
                        power-domains = <&k2g_pds 0x3f>;
                };
 
                edma0_tptc1: tptc@2768000 {
                        compatible = "ti,k2g-edma3-tptc", "ti,edma3-tptc";
-                       reg =   <0x02768000 0x400>;
+                       reg = <0x02768000 0x400>;
                        power-domains = <&k2g_pds 0x3f>;
                };
 
                edma1: edma@2728000 {
                        compatible = "ti,k2g-edma3-tpcc", "ti,edma3-tpcc";
-                       reg =   <0x02728000 0x8000>;
+                       reg = <0x02728000 0x8000>;
                        reg-names = "edma3_cc";
                        interrupts = <GIC_SPI 208 IRQ_TYPE_EDGE_RISING>,
                                        <GIC_SPI 219 IRQ_TYPE_EDGE_RISING>,
 
                edma1_tptc0: tptc@27b0000 {
                        compatible = "ti,k2g-edma3-tptc", "ti,edma3-tptc";
-                       reg =   <0x027b0000 0x400>;
+                       reg = <0x027b0000 0x400>;
                        power-domains = <&k2g_pds 0x4f>;
                };
 
                edma1_tptc1: tptc@27b8000 {
                        compatible = "ti,k2g-edma3-tptc", "ti,edma3-tptc";
-                       reg =   <0x027b8000 0x400>;
+                       reg = <0x027b8000 0x400>;
                        power-domains = <&k2g_pds 0x4f>;
                };
 
index 022d93c..8a421c6 100644 (file)
@@ -12,9 +12,9 @@ qmss: qmss@2a40000 {
        #size-cells = <1>;
        clocks = <&chipclk13>;
        ranges;
-       queue-range     = <0 0x4000>;
-       linkram0        = <0x100000 0x8000>;
-       linkram1        = <0x0 0x10000>;
+       queue-range = <0 0x4000>;
+       linkram0 = <0x100000 0x8000>;
+       linkram1 = <0x0 0x10000>;
 
        qmgrs {
                #address-cells = <1>;
@@ -150,7 +150,7 @@ netcp: netcp@2000000 {
        #size-cells = <1>;
 
        /* NetCP address range */
-       ranges  = <0 0x2000000 0x100000>;
+       ranges = <0 0x2000000 0x100000>;
 
        clocks = <&clkpa>, <&clkcpgmac>;
        clock-names = "pa_clk", "ethss_clk";
@@ -207,11 +207,11 @@ netcp: netcp@2000000 {
                        secondary-slave-ports {
                                port-2 {
                                        slave-port = <2>;
-                                       link-interface  = <2>;
+                                       link-interface = <2>;
                                };
                                port-3 {
                                        slave-port = <3>;
-                                       link-interface  = <2>;
+                                       link-interface = <2>;
                                };
                        };
                };
index 8a94477..da6d393 100644 (file)
                };
 
                mdio: mdio@2090300 {
-                       compatible      = "ti,keystone_mdio", "ti,davinci_mdio";
+                       compatible = "ti,keystone_mdio", "ti,davinci_mdio";
                        #address-cells = <1>;
                        #size-cells = <0>;
                        reg = <0x02090300 0x100>;
                        status = "disabled";
                        clocks = <&clkcpgmac>;
                        clock-names = "fck";
-                       bus_freq        = <2500000>;
+                       bus_freq = <2500000>;
                };
                /include/ "keystone-k2hk-netcp.dtsi"
 };
index e96ca66..5ec6680 100644 (file)
@@ -12,9 +12,9 @@ qmss: qmss@2a40000 {
        #size-cells = <1>;
        clocks = <&chipclk13>;
        ranges;
-       queue-range     = <0 0x2000>;
-       linkram0        = <0x100000 0x4000>;
-       linkram1        = <0x70000000 0x10000>; /* 1MB OSR mem */
+       queue-range = <0 0x2000>;
+       linkram0 = <0x100000 0x4000>;
+       linkram1 = <0x70000000 0x10000>; /* 1MB OSR mem */
 
        qmgrs {
                #address-cells = <1>;
@@ -174,24 +174,24 @@ netcp: netcp@26000000 {
                        interfaces {
                                gbe0: interface-0 {
                                        slave-port = <0>;
-                                       link-interface  = <1>;
-                                       phy-handle      = <&ethphy0>;
+                                       link-interface = <1>;
+                                       phy-handle = <&ethphy0>;
                                };
                                gbe1: interface-1 {
                                        slave-port = <1>;
-                                       link-interface  = <1>;
-                                       phy-handle      = <&ethphy1>;
+                                       link-interface = <1>;
+                                       phy-handle = <&ethphy1>;
                                };
                        };
 
                        secondary-slave-ports {
                                port-2 {
                                        slave-port = <2>;
-                                       link-interface  = <2>;
+                                       link-interface = <2>;
                                };
                                port-3 {
                                        slave-port = <3>;
-                                       link-interface  = <2>;
+                                       link-interface = <2>;
                                };
                        };
                };
index dff5fea..421a02b 100644 (file)
@@ -47,7 +47,7 @@
                        reg-shift = <2>;
                        reg-io-width = <4>;
                        reg = <0x02348400 0x100>;
-                       clocks  = <&clkuart2>;
+                       clocks = <&clkuart2>;
                        interrupts = <GIC_SPI 432 IRQ_TYPE_EDGE_RISING>;
                };
 
@@ -57,7 +57,7 @@
                        reg-shift = <2>;
                        reg-io-width = <4>;
                        reg = <0x02348800 0x100>;
-                       clocks  = <&clkuart3>;
+                       clocks = <&clkuart3>;
                        interrupts = <GIC_SPI 435 IRQ_TYPE_EDGE_RISING>;
                };
 
                };
 
                mdio: mdio@26200f00 {
-                       compatible      = "ti,keystone_mdio", "ti,davinci_mdio";
+                       compatible = "ti,keystone_mdio", "ti,davinci_mdio";
                        #address-cells = <1>;
                        #size-cells = <0>;
                        reg = <0x26200f00 0x100>;
                        status = "disabled";
                        clocks = <&clkcpgmac>;
                        clock-names = "fck";
-                       bus_freq        = <2500000>;
+                       bus_freq = <2500000>;
                };
                /include/ "keystone-k2l-netcp.dtsi"
 };
index fc9fdc8..50789f9 100644 (file)
@@ -14,7 +14,7 @@
        interrupt-parent = <&gic>;
 
        aliases {
-               serial0 = &uart0;
+               serial0 = &uart0;
                spi0 = &spi0;
                spi1 = &spi1;
                spi2 = &spi2;
        };
 
        psci {
-               compatible      = "arm,psci";
-               method          = "smc";
-               cpu_suspend     = <0x84000001>;
-               cpu_off         = <0x84000002>;
-               cpu_on          = <0x84000003>;
+               compatible = "arm,psci";
+               method = "smc";
+               cpu_suspend = <0x84000001>;
+               cpu_off = <0x84000002>;
+               cpu_on = <0x84000003>;
        };
 
        soc0: soc@0 {
                        reg-shift = <2>;
                        reg-io-width = <4>;
                        reg = <0x02530c00 0x100>;
-                       clocks  = <&clkuart0>;
+                       clocks = <&clkuart0>;
                        interrupts = <GIC_SPI 277 IRQ_TYPE_EDGE_RISING>;
                };
 
                        reg-shift = <2>;
                        reg-io-width = <4>;
                        reg = <0x02531000 0x100>;
-                       clocks  = <&clkuart1>;
+                       clocks = <&clkuart1>;
                        interrupts = <GIC_SPI 280 IRQ_TYPE_EDGE_RISING>;
                };
 
                        clock-names = "pcie";
                        #address-cells = <3>;
                        #size-cells = <2>;
-                       reg =  <0x21801000 0x2000>, <0x21800000 0x1000>, <0x02620128 4>;
+                       reg = <0x21801000 0x2000>, <0x21800000 0x1000>, <0x02620128 4>;
                        ranges = <0x82000000 0 0x50000000 0x50000000
                                  0 0x10000000>;
 
index 4cab1b3..0097e72 100644 (file)
                pins = "GPIO_25", "GPIO_26";
                function = "fc0_b";
        };
+
+       usbs_a_pins: usbs-a-pins {
+               /* VBUS_DET */
+               pins = "GPIO_66";
+               function = "gpio";
+       };
 };
 
 &mdio0 {
 
        phy4: ethernet-phy@5 {
                reg = <5>;
-               coma-mode-gpios = <&gpio 37 GPIO_ACTIVE_HIGH>;
+               coma-mode-gpios = <&gpio 37 GPIO_OPEN_DRAIN>;
        };
 
        phy5: ethernet-phy@6 {
                reg = <6>;
-               coma-mode-gpios = <&gpio 37 GPIO_ACTIVE_HIGH>;
+               coma-mode-gpios = <&gpio 37 GPIO_OPEN_DRAIN>;
        };
 
        phy6: ethernet-phy@7 {
                reg = <7>;
-               coma-mode-gpios = <&gpio 37 GPIO_ACTIVE_HIGH>;
+               coma-mode-gpios = <&gpio 37 GPIO_OPEN_DRAIN>;
        };
 
        phy7: ethernet-phy@8 {
                reg = <8>;
-               coma-mode-gpios = <&gpio 37 GPIO_ACTIVE_HIGH>;
+               coma-mode-gpios = <&gpio 37 GPIO_OPEN_DRAIN>;
        };
 };
 
        status = "okay";
 };
 
+&udc {
+       pinctrl-0 = <&usbs_a_pins>;
+       pinctrl-names = "default";
+       atmel,vbus-gpio = <&gpio 66 GPIO_ACTIVE_HIGH>;
+       status = "okay";
+};
+
 &watchdog {
        status = "okay";
 };
index 3c7e3a7..24d9055 100644 (file)
@@ -4,6 +4,7 @@
  */
 /dts-v1/;
 #include "lan966x.dtsi"
+#include "dt-bindings/phy/phy-lan966x-serdes.h"
 
 / {
        model = "Microchip EVB - LAN9662";
        aliases {
                serial0 = &usart3;
        };
-};
-
-&gpio {
-       fc_shrd7_pins: fc_shrd7-pins {
-               pins = "GPIO_49";
-               function = "fc_shrd7";
-       };
 
-       fc_shrd8_pins: fc_shrd8-pins {
-               pins = "GPIO_54";
-               function = "fc_shrd8";
+       gpio-restart {
+               compatible = "gpio-restart";
+               gpios = <&gpio 56 GPIO_ACTIVE_LOW>;
+               priority = <200>;
        };
+};
 
-       fc3_b_pins: fcb3-spi-pins {
-               /* SCK, RXD, TXD */
-               pins = "GPIO_51", "GPIO_52", "GPIO_53";
+&gpio {
+       fc3_b_pins: fc3-b-pins {
+               /* RX, TX */
+               pins = "GPIO_52", "GPIO_53";
                function = "fc3_b";
        };
 
@@ -45,7 +42,7 @@
 &can0 {
        pinctrl-0 = <&can0_b_pins>;
        pinctrl-names = "default";
-       status = "okay";
+       status = "disabled"; /* Conflict with switch */
 };
 
 &flx3 {
        status = "okay";
 
        usart3: serial@200 {
-               pinctrl-0 = <&fc3_b_pins>, <&fc_shrd7_pins>, <&fc_shrd8_pins>;
+               pinctrl-0 = <&fc3_b_pins>;
                pinctrl-names = "default";
                status = "okay";
        };
 };
 
+&mdio1 {
+       status = "okay";
+};
+
+&phy0 {
+       status = "okay";
+};
+
+&phy1 {
+       status = "okay";
+};
+
+&port0 {
+       phy-handle = <&phy0>;
+       phy-mode = "gmii";
+       phys = <&serdes 0 CU(0)>;
+       status = "okay";
+};
+
+&port1 {
+       phy-handle = <&phy1>;
+       phy-mode = "gmii";
+       phys = <&serdes 1 CU(1)>;
+       status = "okay";
+};
+
+&serdes {
+       status = "okay";
+};
+
+&switch {
+       status = "okay";
+};
+
 &watchdog {
        status = "okay";
 };
diff --git a/arch/arm/boot/dts/lan966x-pcb8309.dts b/arch/arm/boot/dts/lan966x-pcb8309.dts
new file mode 100644 (file)
index 0000000..05ce27e
--- /dev/null
@@ -0,0 +1,184 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * lan966x_pcb8309.dts - Device Tree file for PCB8309
+ */
+/dts-v1/;
+#include "lan966x.dtsi"
+#include "dt-bindings/phy/phy-lan966x-serdes.h"
+
+/ {
+       model = "Microchip EVB - LAN9662";
+       compatible = "microchip,lan9662-pcb8309", "microchip,lan9662", "microchip,lan966";
+
+       aliases {
+               serial0 = &usart3;
+               i2c102 = &i2c102;
+               i2c103 = &i2c103;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       gpio-restart {
+               compatible = "gpio-restart";
+               gpios = <&gpio 56 GPIO_ACTIVE_LOW>;
+               priority = <200>;
+       };
+
+       i2c-mux {
+               compatible = "i2c-mux";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               mux-controls = <&mux>;
+               i2c-parent = <&i2c4>;
+
+               i2c102: i2c-sfp@1 {
+                       reg = <1>;
+               };
+
+               i2c103: i2c-sfp@2 {
+                       reg = <2>;
+               };
+       };
+
+       mux: mux-controller {
+               compatible = "gpio-mux";
+               #mux-control-cells = <0>;
+
+               mux-gpios = <&sgpio_out 11 0 GPIO_ACTIVE_HIGH>, /* p11b0 */
+                           <&sgpio_out 11 1 GPIO_ACTIVE_HIGH>; /* p11b1 */
+       };
+
+       sfp2: sfp2 {
+               compatible = "sff,sfp";
+               i2c-bus = <&i2c102>;
+               tx-disable-gpios = <&sgpio_out 10 0 GPIO_ACTIVE_LOW>;
+               los-gpios = <&sgpio_in  2 0 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpios = <&sgpio_in  2 1 GPIO_ACTIVE_LOW>;
+               tx-fault-gpios = <&sgpio_in  1 0 GPIO_ACTIVE_HIGH>;
+       };
+
+       sfp3: sfp3 {
+               compatible = "sff,sfp";
+               i2c-bus = <&i2c103>;
+               tx-disable-gpios = <&sgpio_out 10 1 GPIO_ACTIVE_LOW>;
+               los-gpios = <&sgpio_in  3 0 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpios = <&sgpio_in  3 1 GPIO_ACTIVE_LOW>;
+               tx-fault-gpios = <&sgpio_in  1 1 GPIO_ACTIVE_HIGH>;
+       };
+};
+
+&flx3 {
+       atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_USART>;
+       status = "okay";
+
+       usart3: serial@200 {
+               pinctrl-0 = <&fc3_b_pins>;
+               pinctrl-names = "default";
+               status = "okay";
+       };
+};
+
+&flx4 {
+       atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_TWI>;
+       status = "okay";
+
+       i2c4: i2c@600 {
+               compatible = "microchip,sam9x60-i2c";
+               reg = <0x600 0x200>;
+               interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&nic_clk>;
+               pinctrl-0 = <&fc4_b_pins>;
+               pinctrl-names = "default";
+               i2c-analog-filter;
+               i2c-digital-filter;
+               i2c-digital-filter-width-ns = <35>;
+               i2c-sda-hold-time-ns = <1500>;
+               status = "okay";
+       };
+};
+
+&gpio {
+       fc3_b_pins: fc3-b-pins {
+               /* RXD, TXD */
+               pins = "GPIO_52", "GPIO_53";
+               function = "fc3_b";
+       };
+
+       fc4_b_pins: fc4-b-pins {
+               /* SCL, SDA */
+               pins = "GPIO_57", "GPIO_58";
+               function = "fc4_b";
+       };
+
+       sgpio_a_pins: sgpio-a-pins {
+               /* SCK, D0, D1, LD */
+               pins = "GPIO_32", "GPIO_33", "GPIO_34", "GPIO_35";
+               function = "sgpio_a";
+       };
+};
+
+&mdio1 {
+       status = "okay";
+};
+
+&phy0 {
+       status = "okay";
+};
+
+&phy1 {
+       status = "okay";
+};
+
+&port0 {
+       phy-handle = <&phy0>;
+       phy-mode = "gmii";
+       phys = <&serdes 0 CU(0)>;
+       status = "okay";
+};
+
+&port1 {
+       phy-handle = <&phy1>;
+       phy-mode = "gmii";
+       phys = <&serdes 1 CU(1)>;
+       status = "okay";
+};
+
+&port2 {
+       sfp = <&sfp2>;
+       managed = "in-band-status";
+       phy-mode = "sgmii";
+       phys = <&serdes 2 SERDES6G(0)>;
+       status = "okay";
+};
+
+&port3 {
+       sfp = <&sfp3>;
+       managed = "in-band-status";
+       phy-mode = "sgmii";
+       phys = <&serdes 3 SERDES6G(1)>;
+       status = "okay";
+};
+
+&serdes {
+       status = "okay";
+};
+
+&sgpio {
+       pinctrl-0 = <&sgpio_a_pins>;
+       pinctrl-names = "default";
+       microchip,sgpio-port-ranges = <0 3>, <8 11>;
+       status = "okay";
+
+       gpio@0 {
+               ngpios = <64>;
+       };
+       gpio@1 {
+               ngpios = <64>;
+       };
+};
+
+&switch {
+       status = "okay";
+};
index 3cb02ff..894bf9d 100644 (file)
@@ -38,7 +38,7 @@
                sys_clk: sys_clk {
                        compatible = "fixed-clock";
                        #clock-cells = <0>;
-                       clock-frequency = <162500000>;
+                       clock-frequency = <165625000>;
                };
 
                cpu_clk: cpu_clk {
@@ -65,7 +65,7 @@
                #clock-cells = <1>;
                clocks = <&cpu_clk>, <&ddr_clk>, <&sys_clk>;
                clock-names = "cpu", "ddr", "sys";
-               reg = <0xe00c00a8 0x38>;
+               reg = <0xe00c00a8 0x38>, <0xe00c02cc 0x4>;
        };
 
        timer {
                #size-cells = <1>;
                ranges;
 
+               udc: usb@200000 {
+                       compatible = "microchip,lan9662-udc",
+                                    "atmel,sama5d3-udc";
+                       reg = <0x00200000 0x80000>,
+                             <0xe0808000 0x400>;
+                       interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clks GCK_GATE_UDPHS>, <&nic_clk>;
+                       clock-names = "pclk", "hclk";
+                       status = "disabled";
+               };
+
                switch: switch@e0000000 {
                        compatible = "microchip,lan966x-switch";
                        reg = <0xe0000000 0x0100000>,
                        status = "disabled";
                };
 
+               can1: can@e0820000 {
+                       compatible = "bosch,m_can";
+                       reg = <0xe0820000 0xfc>, <0x00100000 0x8000>;
+                       reg-names = "m_can", "message_ram";
+                       interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "int0", "int1";
+                       clocks = <&clks GCK_ID_MCAN1>, <&clks GCK_ID_MCAN1>;
+                       clock-names = "hclk", "cclk";
+                       assigned-clocks = <&clks GCK_ID_MCAN1>;
+                       assigned-clock-rates = <40000000>;
+                       bosch,mram-cfg = <0x4000 0 0 64 0 0 32 32>;
+                       status = "disabled";
+               };
+
                reset: reset-controller@e200400c {
                        compatible = "microchip,lan966x-switch-reset";
                        reg = <0xe200400c 0x4>;
index 10b8249..1bb686a 100644 (file)
                        status = "disabled";
                };
 
-               usb0: ehci@40006100 {
+               usb0: usb@40006100 {
                        compatible = "nxp,lpc1850-ehci", "generic-ehci";
                        reg = <0x40006100 0x100>;
                        interrupts = <8>;
                        status = "disabled";
                };
 
-               usb1: ehci@40007100 {
+               usb1: usb@40007100 {
                        compatible = "nxp,lpc1850-ehci", "generic-ehci";
                        reg = <0x40007100 0x100>;
                        interrupts = <9>;
                        compatible = "nxp,lpc1850-dwmac", "snps,dwmac-3.611", "snps,dwmac";
                        reg = <0x40010000 0x2000>;
                        interrupts = <5>;
-                       interrupt-names = "macirq";
+                       interrupt-names = "macirq";
                        clocks = <&ccu1 CLK_CPU_ETHERNET>;
                        clock-names = "stmmaceth";
                        resets = <&rgu 22>;
index 66bcdaf..ce8e26d 100644 (file)
        };
 
        sgtl5000: audio-codec@2a {
-               #sound-dai-cells=<0x0>;
+               #sound-dai-cells = <0x0>;
                compatible = "fsl,sgtl5000";
                reg = <0x2a>;
                VDDA-supply = <&reg_3p3v>;
index 6c88be2..fa76162 100644 (file)
                        status = "disabled";
                };
 
+               sfp: efuse@1e80000 {
+                       compatible = "fsl,ls1021a-sfp";
+                       reg = <0x0 0x1e80000 0x0 0x10000>;
+                       clocks = <&clockgen 4 3>;
+                       clock-names = "sfp";
+               };
+
                dcfg: dcfg@1ee0000 {
                        compatible = "fsl,ls1021a-dcfg", "syscon";
                        reg = <0x0 0x1ee0000 0x0 0x1000>;
index 26eaba3..8e3860d 100644 (file)
                        ranges = <0x0 0xc8100000 0x100000>;
 
                        ao_arc_rproc: remoteproc@1c {
-                               compatible= "amlogic,meson-mx-ao-arc";
+                               compatible = "amlogic,meson-mx-ao-arc";
                                reg = <0x1c 0x8>, <0x38 0x8>;
                                reg-names = "remap", "cpu";
                                status = "disabled";
                        };
 
                        ir_receiver: ir-receiver@480 {
-                               compatible= "amlogic,meson6-ir";
+                               compatible = "amlogic,meson6-ir";
                                reg = <0x480 0x20>;
                                interrupts = <GIC_SPI 15 IRQ_TYPE_EDGE_RISING>;
                                status = "disabled";
index 9997a5d..0f8bac8 100644 (file)
 };
 
 &ao_arc_rproc {
-       compatible= "amlogic,meson8-ao-arc", "amlogic,meson-mx-ao-arc";
+       compatible = "amlogic,meson8-ao-arc", "amlogic,meson-mx-ao-arc";
        amlogic,secbus2 = <&secbus2>;
        sram = <&ao_arc_sram>;
        resets = <&reset RESET_MEDIA_CPU>;
index 94f1c03..cf9c04a 100644 (file)
 };
 
 &ao_arc_rproc {
-       compatible= "amlogic,meson8b-ao-arc", "amlogic,meson-mx-ao-arc";
+       compatible = "amlogic,meson8b-ao-arc", "amlogic,meson-mx-ao-arc";
        amlogic,secbus2 = <&secbus2>;
        sram = <&ao_arc_sram>;
        resets = <&reset RESET_MEDIA_CPU>;
index ef583cf..b8eba3b 100644 (file)
 
                afe: audio-controller {
                        compatible = "mediatek,mt2701-audio";
-                       interrupts =  <GIC_SPI 104 IRQ_TYPE_LEVEL_LOW>,
+                       interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_LOW>,
                                      <GIC_SPI 132 IRQ_TYPE_LEVEL_LOW>;
-                       interrupt-names = "afe", "asys";
+                       interrupt-names = "afe", "asys";
                        power-domains = <&scpsys MT2701_POWER_DOMAIN_IFR_MSC>;
 
                        clocks = <&infracfg CLK_INFRA_AUDIO>,
                compatible = "mediatek,mt2701-jpgdec";
                reg = <0 0x15004000 0 0x1000>;
                interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_LOW>;
-               clocks =  <&imgsys CLK_IMG_JPGDEC_SMI>,
+               clocks = <&imgsys CLK_IMG_JPGDEC_SMI>,
                          <&imgsys CLK_IMG_JPGDEC>;
                clock-names = "jpgdec-smi",
                              "jpgdec";
                             "mediatek,mtk-jpgenc";
                reg = <0 0x1500a000 0 0x1000>;
                interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_LOW>;
-               clocks =  <&imgsys CLK_IMG_VENC>;
+               clocks = <&imgsys CLK_IMG_VENC>;
                clock-names = "jpgenc";
                power-domains = <&scpsys MT2701_POWER_DOMAIN_ISP>;
                iommus = <&iommu MT2701_M4U_PORT_JPGENC_RDMA>,
index f484836..25d31e4 100644 (file)
        };
 
        pericfg: syscon@10003000 {
-               compatible =  "mediatek,mt7623-pericfg",
+               compatible = "mediatek,mt7623-pericfg",
                              "mediatek,mt2701-pericfg",
                              "syscon";
                reg = <0 0x10003000 0 0x1000>;
                afe: audio-controller {
                        compatible = "mediatek,mt7623-audio",
                                     "mediatek,mt2701-audio";
-                       interrupts =  <GIC_SPI 104 IRQ_TYPE_LEVEL_LOW>,
+                       interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_LOW>,
                                      <GIC_SPI 132 IRQ_TYPE_LEVEL_LOW>;
-                       interrupt-names = "afe", "asys";
+                       interrupt-names = "afe", "asys";
                        power-domains = <&scpsys MT2701_POWER_DOMAIN_IFR_MSC>;
 
                        clocks = <&infracfg CLK_INFRA_AUDIO>,
index 13c8693..e8b4b6d 100644 (file)
                pinctrl-names = "default";
                pinctrl-0 = <&key_pins_a>;
 
-               factory {
+               button-factory {
                        label = "factory";
                        linux,code = <BTN_0>;
                        gpios = <&pio 256 GPIO_ACTIVE_LOW>;
                };
 
-               wps {
+               button-wps {
                        label = "wps";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&pio 257 GPIO_ACTIVE_HIGH>;
index 88d8f0b..61f5da6 100644 (file)
                pinctrl-names = "default";
                pinctrl-0 = <&key_pins_a>;
 
-               factory {
+               button-factory {
                        label = "factory";
                        linux,code = <BTN_0>;
                        gpios = <&pio 256 GPIO_ACTIVE_LOW>;
                };
 
-               wps {
+               button-wps {
                        label = "wps";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&pio 257 GPIO_ACTIVE_HIGH>;
index 027c1b0..5008115 100644 (file)
                pinctrl-names = "default";
                pinctrl-0 = <&key_pins_a>;
 
-               factory {
+               button-factory {
                        label = "factory";
                        linux,code = <BTN_0>;
                        gpios = <&pio 256 GPIO_ACTIVE_LOW>;
                };
 
-               wps {
+               button-wps {
                        label = "wps";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&pio 257 GPIO_ACTIVE_HIGH>;
index 1b9b9a8..bf67a8e 100644 (file)
                pinctrl-names = "default";
                pinctrl-0 = <&key_pins_a>;
 
-               factory {
+               button-factory {
                        label = "factory";
                        linux,code = <BTN_0>;
                        gpios = <&pio 256 GPIO_ACTIVE_LOW>;
                };
 
-               wps {
+               button-wps {
                        label = "wps";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&pio 257 GPIO_ACTIVE_HIGH>;
index eb536cb..84e14be 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               reset {
+               button-reset {
                        label = "factory";
                        linux,code = <KEY_RESTART>;
                        gpios = <&pio 60 GPIO_ACTIVE_LOW>;
                };
 
-               wps {
+               button-wps {
                        label = "wps";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&pio 58 GPIO_ACTIVE_LOW>;
index 3696980..c7b5ef1 100644 (file)
                        compatible = "nuvoton,npcm750-reset";
                        reg = <0xf0801000 0x70>;
                        #reset-cells = <2>;
+                       nuvoton,sysgcr = <&gcr>;
                };
 
                clk: clock-controller@f0801000 {
                        interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "macirq";
                        ethernet = <0>;
-                       clocks  = <&clk_rg1refck>, <&clk NPCM7XX_CLK_AHB>;
+                       clocks = <&clk_rg1refck>, <&clk NPCM7XX_CLK_AHB>;
                        clock-names = "stmmaceth", "clk_gmac";
                        pinctrl-names = "default";
                        pinctrl-0 = <&rg1_pins
index 13eee0f..30eed40 100644 (file)
@@ -51,7 +51,7 @@
                        interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "macirq";
                        ethernet = <1>;
-                       clocks  = <&clk_rg2refck>, <&clk NPCM7XX_CLK_AHB>;
+                       clocks = <&clk_rg2refck>, <&clk NPCM7XX_CLK_AHB>;
                        clock-names = "stmmaceth", "clk_gmac";
                        pinctrl-names = "default";
                        pinctrl-0 = <&rg2_pins
index af964f1..5acf5dd 100644 (file)
@@ -21,7 +21,7 @@
 
        nor@0,0 {
                compatible = "cfi-flash";
-               linux,mtd-name= "intel,ge28f256l18b85";
+               linux,mtd-name = "intel,ge28f256l18b85";
                #address-cells = <1>;
                #size-cells = <1>;
                reg = <0 0 0x04000000>;
index c933219..abd403c 100644 (file)
@@ -60,7 +60,7 @@
                interrupt-parent = <&gpmc>;
                interrupts = <0 IRQ_TYPE_NONE>, /* fifoevent */
                             <1 IRQ_TYPE_NONE>; /* termcount */
-               linux,mtd-name= "hynix,h8kds0un0mer-4em";
+               linux,mtd-name = "hynix,h8kds0un0mer-4em";
                nand-bus-width = <16>;
                gpmc,device-width = <2>;
                ti,nand-ecc-opt = "bch8";
index 5cc0cf7..f95eea6 100644 (file)
@@ -60,7 +60,7 @@
                interrupt-parent = <&gpmc>;
                interrupts = <0 IRQ_TYPE_NONE>, /* fifoevent */
                             <1 IRQ_TYPE_NONE>; /* termcount */
-               linux,mtd-name= "micron,mt29f2g16abdhc";
+               linux,mtd-name = "micron,mt29f2g16abdhc";
                nand-bus-width = <16>;
                gpmc,device-width = <2>;
                ti,nand-ecc-opt = "bch8";
index 0365f06..28a6a93 100644 (file)
                        spi-cpol;
                        spi-cpha;
 
-                       backlight= <&backlight>;
+                       backlight = <&backlight>;
                        label = "lcd";
                        port {
                                lcd_in: endpoint {
index 99f5585..2192026 100644 (file)
                interrupt-parent = <&gpmc>;
                interrupts = <0 IRQ_TYPE_NONE>, /* fifoevent */
                             <1 IRQ_TYPE_NONE>; /* termcount */
-               linux,mtd-name= "micron,mt29c4g96maz";
+               linux,mtd-name = "micron,mt29c4g96maz";
                nand-bus-width = <16>;
                gpmc,device-width = <2>;
                ti,nand-ecc-opt = "bch8";
index 9c6a927..36fc880 100644 (file)
                interrupt-parent = <&gpmc>;
                interrupts = <0 IRQ_TYPE_NONE>, /* fifoevent */
                             <1 IRQ_TYPE_NONE>; /* termcount */
-               linux,mtd-name= "micron,nand";
+               linux,mtd-name = "micron,nand";
                nand-bus-width = <16>;
                gpmc,device-width = <2>;
                ti,nand-ecc-opt = "bch8";
 };
 
 &mmc2 {
-       status="disabled";
+       status = "disabled";
 };
 
 &mmc3 {
-       status="disabled";
+       status = "disabled";
 };
 
 &omap3_pmx_core {
index 73d4778..c595afe 100644 (file)
                gpmc,device-width = <2>;
                gpmc,wait-pin = <0>;
                gpmc,wait-monitoring-ns = <0>;
-               gpmc,burst-length= <4>;
+               gpmc,burst-length = <4>;
                gpmc,cs-on-ns = <0>;
                gpmc,cs-rd-off-ns = <100>;
                gpmc,cs-wr-off-ns = <100>;
index d40c3d2..dd79715 100644 (file)
 };
 
 &twl_gpio {
-       ti,pullups      = <0x0>;
-       ti,pulldowns    = <0x03ff3f>; /* BIT(0..5) | BIT(8..17) */
+       ti,pullups = <0x0>;
+       ti,pulldowns = <0x03ff3f>; /* BIT(0..5) | BIT(8..17) */
 };
 
 &i2c2 {
index 7dde9fb..f68da82 100644 (file)
 };
 
 &twl_gpio {
-       ti,pullups      = <0x000001>; /* BIT(0) */
-       ti,pulldowns    = <0x008106>; /* BIT(1) | BIT(2) | BIT(8) | BIT(15) */
+       ti,pullups = <0x000001>; /* BIT(0) */
+       ti,pulldowns = <0x008106>; /* BIT(1) | BIT(2) | BIT(8) | BIT(15) */
 };
 
 &vdac {
index 006a6d9..adc714c 100644 (file)
 
        nand@0,0 {
                compatible = "ti,omap2-nand";
-               linux,mtd-name= "micron,mt29c4g96maz";
+               linux,mtd-name = "micron,mt29c4g96maz";
                reg = <0 0 4>;  /* CS0, offset 0, IO size 4 */
                interrupt-parent = <&gpmc>;
                interrupts = <0 IRQ_TYPE_NONE>, /* fifoevent */
index 37608af..5598537 100644 (file)
 
        lcd: lcd@1 {
                reg = <1>;      /* CS1 */
-               compatible =    "tpo,td043mtea1";
+               compatible = "tpo,td043mtea1";
                spi-max-frequency = <100000>;
                spi-cpol;
                spi-cpha;
index 7d530ae..258ecd9 100644 (file)
@@ -53,7 +53,7 @@
 
        nor@0,0 {
                compatible = "cfi-flash";
-               linux,mtd-name= "intel,pf48f6000m0y1be";
+               linux,mtd-name = "intel,pf48f6000m0y1be";
                #address-cells = <1>;
                #size-cells = <1>;
                reg = <0 0 0x08000000>;
                interrupt-parent = <&gpmc>;
                interrupts = <0 IRQ_TYPE_NONE>, /* fifoevent */
                             <1 IRQ_TYPE_NONE>; /* termcount */
-               linux,mtd-name= "micron,mt29f1g08abb";
+               linux,mtd-name = "micron,mt29f1g08abb";
                #address-cells = <1>;
                #size-cells = <1>;
                ti,nand-ecc-opt = "sw";
        };
 
        onenand@2,0 {
-               linux,mtd-name= "samsung,kfm2g16q2m-deb8";
+               linux,mtd-name = "samsung,kfm2g16q2m-deb8";
                #address-cells = <1>;
                #size-cells = <1>;
                compatible = "ti,omap2-onenand";
index 06cc3a1..3b505fe 100644 (file)
                                clocks = <&usb_phy_cm_clk32k>,
                                <&sys_clkin>,
                                <&l3init_clkctrl OMAP5_USB_OTG_SS_CLKCTRL 8>;
-                               clock-names =   "wkupclk",
+                               clock-names = "wkupclk",
                                "sysclk",
                                "refclk";
                                #phy-cells = <0>;
index 8a6721d..147c991 100644 (file)
 
                regulators {
                        regulator-v3 {
-                               regulator-compatible= "V3(DCDC)";
+                               regulator-compatible = "V3(DCDC)";
                                regulator-min-microvolt = <725000>;
                                regulator-max-microvolt = <1800000>;
                        };
 
                        regulator-v4 {
-                               regulator-compatible= "V4(DCDC)";
+                               regulator-compatible = "V4(DCDC)";
                                regulator-min-microvolt = <725000>;
                                regulator-max-microvolt = <1800000>;
                        };
 
                        regulator-v5 {
-                               regulator-compatible= "V5(LDO)";
+                               regulator-compatible = "V5(LDO)";
                                regulator-min-microvolt = <1700000>;
                                regulator-max-microvolt = <2000000>;
                        };
 
                        reg_vcc_sdio: regulator-v6 {
-                               regulator-compatible= "V6(LDO)";
+                               regulator-compatible = "V6(LDO)";
                                regulator-min-microvolt = <3300000>;
                                regulator-max-microvolt = <3300000>;
                        };
 
                        regulator-v7 {
-                               regulator-compatible= "V7(LDO)";
+                               regulator-compatible = "V7(LDO)";
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <3300000>;
                        };
index 138d647..70a1dd6 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
 #include <dt-bindings/input/input.h>
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
 #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
 #include <dt-bindings/pinctrl/qcom,pmic-mpp.h>
 #include "qcom-msm8660.dtsi"
                                };
 
                                gpio@150 {
-                                       dragon_ethernet_gpios: ethernet-gpios {
+                                       dragon_ethernet_gpios: ethernet-state {
                                                pinconf {
                                                        pins = "gpio7";
                                                        function = "normal";
                                                        power-source = <PM8058_GPIO_S3>;
                                                };
                                        };
-                                       dragon_bmp085_gpios: bmp085-gpios {
+                                       dragon_bmp085_gpios: bmp085-state {
                                                pinconf {
                                                        pins = "gpio16";
                                                        function = "normal";
                                                        power-source = <PM8058_GPIO_S3>;
                                                };
                                        };
-                                       dragon_mpu3050_gpios: mpu3050-gpios {
+                                       dragon_mpu3050_gpios: mpu3050-state {
                                                pinconf {
                                                        pins = "gpio17";
                                                        function = "normal";
                                                        power-source = <PM8058_GPIO_S3>;
                                                };
                                        };
-                                       dragon_sdcc3_gpios: sdcc3-gpios {
+                                       dragon_sdcc3_gpios: sdcc3-state {
                                                pinconf {
                                                        pins = "gpio22";
                                                        function = "normal";
                                                        power-source = <PM8058_GPIO_S3>;
                                                };
                                        };
-                                       dragon_sdcc5_gpios: sdcc5-gpios {
+                                       dragon_sdcc5_gpios: sdcc5-state {
                                                pinconf {
                                                        pins = "gpio26";
                                                        function = "normal";
                                                        power-source = <PM8058_GPIO_S3>;
                                                };
                                        };
-                                       dragon_ak8975_gpios: ak8975-gpios {
+                                       dragon_ak8975_gpios: ak8975-state {
                                                pinconf {
                                                        pins = "gpio33";
                                                        function = "normal";
                                                        power-source = <PM8058_GPIO_S3>;
                                                };
                                        };
-                                       dragon_cm3605_gpios: cm3605-gpios {
+                                       dragon_cm3605_gpios: cm3605-state {
                                                /* Pin 34 connected to the proxy IRQ */
-                                               pinconf_gpio34 {
+                                               gpio34-pins {
                                                        pins = "gpio34";
                                                        function = "normal";
                                                        input-enable;
                                                        power-source = <PM8058_GPIO_S3>;
                                                };
                                                /* Pin 35 connected to ASET */
-                                               pinconf_gpio35 {
+                                               gpio35-pins {
                                                        pins = "gpio35";
                                                        function = "normal";
                                                        output-high;
                                                        power-source = <PM8058_GPIO_S3>;
                                                };
                                        };
-                                       dragon_veth_gpios: veth-gpios {
+                                       dragon_veth_gpios: veth-state {
                                                pinconf {
                                                        pins = "gpio40";
                                                        function = "normal";
                                        compatible = "qcom,pm8058-led";
                                        reg = <0x131>;
                                        label = "pm8058:red";
+                                       color = <LED_COLOR_ID_RED>;
                                        default-state = "off";
                                };
                                led@132 {
                                        compatible = "qcom,pm8058-led";
                                        reg = <0x132>;
                                        label = "pm8058:yellow";
+                                       color = <LED_COLOR_ID_YELLOW>;
                                        default-state = "off";
                                        linux,default-trigger = "mmc0";
                                };
                                        compatible = "qcom,pm8058-led";
                                        reg = <0x133>;
                                        label = "pm8058:green";
+                                       function = LED_FUNCTION_HEARTBEAT;
+                                       color = <LED_COLOR_ID_GREEN>;
                                        default-state = "on";
                                        linux,default-trigger = "heartbeat";
                                };
index ca9f735..fee278e 100644 (file)
@@ -24,9 +24,9 @@
                ramoops@88d00000{
                        compatible = "ramoops";
                        reg = <0x88d00000 0x100000>;
-                       record-size     = <0x00020000>;
-                       console-size    = <0x00020000>;
-                       ftrace-size     = <0x00020000>;
+                       record-size = <0x00020000>;
+                       console-size = <0x00020000>;
+                       ftrace-size = <0x00020000>;
                };
        };
 
 
        gpio-keys {
                compatible = "gpio-keys";
-               volume_up {
+               key-volume-up {
                        label = "Volume Up";
                        gpios = <&pm8921_gpio 4 GPIO_ACTIVE_HIGH>;
                        linux,code = <KEY_VOLUMEUP>;
                };
-               volume_down {
+               key-volume-down {
                        label = "Volume Down";
                        gpios = <&pm8921_gpio 38 GPIO_ACTIVE_HIGH>;
                        linux,code = <KEY_VOLUMEDOWN>;
@@ -98,8 +98,8 @@
                                 * tabla2x-slim-VDDIO_CDC
                                 */
                                s4 {
-                                       regulator-min-microvolt = <1800000>;
-                                       regulator-max-microvolt = <1800000>;
+                                       regulator-min-microvolt = <1800000>;
+                                       regulator-max-microvolt = <1800000>;
                                        qcom,switch-mode-frequency = <3200000>;
                                        regulator-always-on;
                                };
                        };
                };
 
-               imem@2a03f000 {
-                       compatible = "syscon", "simple-mfd";
+               sram@2a03f000 {
+                       compatible = "qcom,apq8064-imem", "syscon", "simple-mfd";
                        reg = <0x2a03f000 0x1000>;
 
                        reboot-mode {
                                compatible = "syscon-reboot-mode";
                                offset = <0x65c>;
 
-                               mode-normal     = <0x77665501>;
-                               mode-bootloader = <0x77665500>;
-                               mode-recovery   = <0x77665502>;
+                               mode-normal = <0x77665501>;
+                               mode-bootloader = <0x77665500>;
+                               mode-recovery = <0x77665502>;
                        };
                };
        };
index e068a8d..e3bf57c 100644 (file)
@@ -82,8 +82,8 @@
                                };
 
                                s4 {
-                                       regulator-min-microvolt = <1800000>;
-                                       regulator-max-microvolt = <1800000>;
+                                       regulator-min-microvolt = <1800000>;
+                                       regulator-max-microvolt = <1800000>;
                                        qcom,switch-mode-frequency = <3200000>;
                                };
 
                qcom,ssbi@500000 {
                        pmic@0 {
                                gpio@150 {
-                                       wlan_default_gpios: wlan-gpios {
-                                               pios {
+                                       wlan_default_gpios: wlan-gpios-state {
+                                               pinconf {
                                                        pins = "gpio43";
                                                        function = "normal";
                                                        bias-disable;
                        sdcc3: mmc@12180000 {
                                status = "okay";
                                vmmc-supply = <&v3p3_fixed>;
-                               pinctrl-names   = "default";
-                               pinctrl-0       = <&card_detect>;
-                               cd-gpios        = <&tlmm_pinmux 26 GPIO_ACTIVE_LOW>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&card_detect>;
+                               cd-gpios = <&tlmm_pinmux 26 GPIO_ACTIVE_LOW>;
                        };
                        /* WLAN */
                        sdcc4: mmc@121c0000 {
index 2638b38..0322cb8 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 #include "qcom-apq8064-v2.0.dtsi"
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
 #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
 
 / {
@@ -39,6 +40,7 @@
 
                led@1 {
                        label = "apq8064:green:user1";
+                       color = <LED_COLOR_ID_GREEN>;
                        gpios = <&pm8921_gpio 18 GPIO_ACTIVE_HIGH>;
                        default-state = "on";
                };
                                };
 
                                s4 {
-                                       regulator-min-microvolt = <1800000>;
-                                       regulator-max-microvolt = <1800000>;
+                                       regulator-min-microvolt = <1800000>;
+                                       regulator-max-microvolt = <1800000>;
                                        qcom,switch-mode-frequency = <3200000>;
                                };
 
                };
 
                sata0: sata@29000000 {
-                       status          = "okay";
-                       target-supply   = <&pm8921_s4>;
+                       status = "okay";
+                       target-supply = <&pm8921_s4>;
                };
 
                /* OTG */
                qcom,ssbi@500000 {
                        pmic@0 {
                                gpio@150 {
-                                       wlan_default_gpios: wlan-gpios {
-                                               pios {
+                                       wlan_default_gpios: wlan-gpios-state {
+                                               pinconf {
                                                        pins = "gpio43";
                                                        function = "normal";
                                                        bias-disable;
                                                };
                                        };
 
-                                       notify_led: nled {
-                                               pios {
+                                       notify_led: nled-state {
+                                               pinconf {
                                                        pins = "gpio18";
                                                        function = "normal";
                                                        bias-disable;
                        sdcc3: mmc@12180000 {
                                status = "okay";
                                vmmc-supply = <&pm8921_l6>;
-                               pinctrl-names   = "default";
-                               pinctrl-0       = <&card_detect>;
-                               cd-gpios        = <&tlmm_pinmux 26 GPIO_ACTIVE_LOW>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&card_detect>;
+                               cd-gpios = <&tlmm_pinmux 26 GPIO_ACTIVE_LOW>;
                        };
                        /* WLAN */
                        sdcc4: mmc@121c0000 {
                        status = "okay";
 
                        core-vdda-supply = <&pm8921_hdmi_switch>;
-                       hdmi-mux-supply = <&ext_3p3v>;
 
                        hpd-gpios = <&tlmm_pinmux 72 GPIO_ACTIVE_HIGH>;
 
index 0cee62c..c07c547 100644 (file)
                pinctrl-names = "default";
                pinctrl-0 = <&gpio_keys_pin_a>;
 
-               camera-focus {
+               key-camera-focus {
                        label = "camera_focus";
                        gpios = <&pm8921_gpio 3 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
                        linux,code = <KEY_CAMERA_FOCUS>;
                };
 
-               camera-snapshot {
+               key-camera-snapshot {
                        label = "camera_snapshot";
                        gpios = <&pm8921_gpio 4 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
                        linux,code = <KEY_CAMERA>;
                };
 
-               volume-down {
+               key-volume-down {
                        label = "volume_down";
                        gpios = <&pm8921_gpio 29 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
                        linux,code = <KEY_VOLUMEDOWN>;
                };
 
-               volume-up {
+               key-volume-up {
                        label = "volume_up";
                        gpios = <&pm8921_gpio 35 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
                qcom,ssbi@500000 {
                        pmic@0 {
                                gpio@150 {
-                                       gpio_keys_pin_a: gpio-keys-pin-active {
+                                       gpio_keys_pin_a: gpio-keys-active-state {
                                                pins = "gpio3", "gpio4", "gpio29", "gpio35";
                                                function = "normal";
 
index 34c0ba7..ada4c82 100644 (file)
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
 
-                       thermal-sensors = <&gcc 7>;
+                       thermal-sensors = <&tsens 7>;
                        coefficients = <1199 0>;
 
                        trips {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
 
-                       thermal-sensors = <&gcc 8>;
+                       thermal-sensors = <&tsens 8>;
                        coefficients = <1132 0>;
 
                        trips {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
 
-                       thermal-sensors = <&gcc 9>;
+                       thermal-sensors = <&tsens 9>;
                        coefficients = <1199 0>;
 
                        trips {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
 
-                       thermal-sensors = <&gcc 10>;
+                       thermal-sensors = <&tsens 10>;
                        coefficients = <1132 0>;
 
                        trips {
 
        firmware {
                scm {
-                       compatible = "qcom,scm-apq8064";
+                       compatible = "qcom,scm-apq8064", "qcom,scm";
 
                        clocks = <&rpmcc RPM_DAYTONA_FABRIC_CLK>;
                        clock-names = "core";
                };
 
                sps_sic_non_secure: sps-sic-non-secure@12100000 {
-                       compatible      = "syscon";
-                       reg             = <0x12100000 0x10000>;
+                       compatible = "syscon";
+                       reg = <0x12100000 0x10000>;
                };
 
                gsbi1: gsbi@12440000 {
                };
 
                qfprom: qfprom@700000 {
-                       compatible      = "qcom,qfprom";
-                       reg             = <0x00700000 0x1000>;
-                       #address-cells  = <1>;
-                       #size-cells     = <1>;
+                       compatible = "qcom,apq8064-qfprom", "qcom,qfprom";
+                       reg = <0x00700000 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        ranges;
-                       tsens_calib: calib {
+                       tsens_calib: calib@404 {
                                reg = <0x404 0x10>;
                        };
-                       tsens_backup: backup_calib {
+                       tsens_backup: backup_calib@414 {
                                reg = <0x414 0x10>;
                        };
                };
 
                gcc: clock-controller@900000 {
-                       compatible = "qcom,gcc-apq8064";
+                       compatible = "qcom,gcc-apq8064", "syscon";
                        reg = <0x00900000 0x4000>;
-                       nvmem-cells = <&tsens_calib>, <&tsens_backup>;
-                       nvmem-cell-names = "calib", "calib_backup";
                        #clock-cells = <1>;
                        #power-domain-cells = <1>;
                        #reset-cells = <1>;
-                       #thermal-sensor-cells = <1>;
+
+                       tsens: thermal-sensor {
+                               compatible = "qcom,msm8960-tsens";
+
+                               nvmem-cells = <&tsens_calib>, <&tsens_backup>;
+                               nvmem-cell-names = "calib", "calib_backup";
+                               interrupts = <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-names = "uplow";
+
+                               #qcom,sensors = <11>;
+                               #thermal-sensor-cells = <1>;
+                       };
                };
 
                lcc: clock-controller@28000000 {
                };
 
                l2cc: clock-controller@2011000 {
-                       compatible      = "qcom,kpss-gcc", "syscon";
-                       reg             = <0x2011000 0x1000>;
+                       compatible = "qcom,kpss-gcc", "syscon";
+                       reg = <0x2011000 0x1000>;
                };
 
                rpm@108000 {
-                       compatible      = "qcom,rpm-apq8064";
-                       reg             = <0x108000 0x1000>;
-                       qcom,ipc        = <&l2cc 0x8 2>;
+                       compatible = "qcom,rpm-apq8064";
+                       reg = <0x108000 0x1000>;
+                       qcom,ipc = <&l2cc 0x8 2>;
 
-                       interrupts      = <GIC_SPI 19 IRQ_TYPE_EDGE_RISING>,
-                                         <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>,
-                                         <GIC_SPI 22 IRQ_TYPE_EDGE_RISING>;
-                       interrupt-names = "ack", "err", "wakeup";
+                       interrupts = <GIC_SPI 19 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 22 IRQ_TYPE_EDGE_RISING>;
+                       interrupt-names = "ack", "err", "wakeup";
 
                        rpmcc: clock-controller {
-                               compatible      = "qcom,rpmcc-apq8064", "qcom,rpmcc";
+                               compatible = "qcom,rpmcc-apq8064", "qcom,rpmcc";
                                #clock-cells = <1>;
+                               clocks = <&pxo_board>, <&cxo_board>;
+                               clock-names = "pxo", "cxo";
                        };
 
                        regulators {
                };
 
                sata_phy0: phy@1b400000 {
-                       compatible      = "qcom,apq8064-sata-phy";
-                       status          = "disabled";
-                       reg             = <0x1b400000 0x200>;
-                       reg-names       = "phy_mem";
-                       clocks          = <&gcc SATA_PHY_CFG_CLK>;
-                       clock-names     = "cfg";
-                       #phy-cells      = <0>;
+                       compatible = "qcom,apq8064-sata-phy";
+                       status = "disabled";
+                       reg = <0x1b400000 0x200>;
+                       reg-names = "phy_mem";
+                       clocks = <&gcc SATA_PHY_CFG_CLK>;
+                       clock-names = "cfg";
+                       #phy-cells = <0>;
                };
 
                sata0: sata@29000000 {
-                       compatible              = "qcom,apq8064-ahci", "generic-ahci";
-                       status                  = "disabled";
-                       reg                     = <0x29000000 0x180>;
-                       interrupts              = <GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH>;
-
-                       clocks                  = <&gcc SFAB_SATA_S_H_CLK>,
-                                               <&gcc SATA_H_CLK>,
-                                               <&gcc SATA_A_CLK>,
-                                               <&gcc SATA_RXOOB_CLK>,
-                                               <&gcc SATA_PMALIVE_CLK>;
-                       clock-names             = "slave_iface",
-                                               "iface",
-                                               "bus",
-                                               "rxoob",
-                                               "core_pmalive";
-
-                       assigned-clocks         = <&gcc SATA_RXOOB_CLK>,
-                                               <&gcc SATA_PMALIVE_CLK>;
-                       assigned-clock-rates    = <100000000>, <100000000>;
-
-                       phys                    = <&sata_phy0>;
-                       phy-names               = "sata-phy";
-                       ports-implemented       = <0x1>;
+                       compatible = "qcom,apq8064-ahci", "generic-ahci";
+                       status   = "disabled";
+                       reg      = <0x29000000 0x180>;
+                       interrupts = <GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH>;
+
+                       clocks = <&gcc SFAB_SATA_S_H_CLK>,
+                                <&gcc SATA_H_CLK>,
+                                <&gcc SATA_A_CLK>,
+                                <&gcc SATA_RXOOB_CLK>,
+                                <&gcc SATA_PMALIVE_CLK>;
+                       clock-names = "slave_iface",
+                                     "iface",
+                                     "bus",
+                                     "rxoob",
+                                     "core_pmalive";
+
+                       assigned-clocks = <&gcc SATA_RXOOB_CLK>,
+                                         <&gcc SATA_PMALIVE_CLK>;
+                       assigned-clock-rates = <100000000>, <100000000>;
+
+                       phys = <&sata_phy0>;
+                       phy-names = "sata-phy";
+                       ports-implemented = <0x1>;
                };
 
                /* Temporary fixed regulator */
                        #size-cells = <1>;
                        ranges;
                        sdcc1: mmc@12400000 {
-                               status          = "disabled";
-                               compatible      = "arm,pl18x", "arm,primecell";
-                               pinctrl-names   = "default";
-                               pinctrl-0       = <&sdcc1_pins>;
+                               status = "disabled";
+                               compatible = "arm,pl18x", "arm,primecell";
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&sdcc1_pins>;
                                arm,primecell-periphid = <0x00051180>;
-                               reg             = <0x12400000 0x2000>;
-                               interrupts      = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
-                               interrupt-names = "cmd_irq";
-                               clocks          = <&gcc SDC1_CLK>, <&gcc SDC1_H_CLK>;
-                               clock-names     = "mclk", "apb_pclk";
-                               bus-width       = <8>;
-                               max-frequency   = <96000000>;
+                               reg = <0x12400000 0x2000>;
+                               interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-names = "cmd_irq";
+                               clocks = <&gcc SDC1_CLK>, <&gcc SDC1_H_CLK>;
+                               clock-names = "mclk", "apb_pclk";
+                               bus-width = <8>;
+                               max-frequency = <96000000>;
                                non-removable;
                                cap-sd-highspeed;
                                cap-mmc-highspeed;
                        };
 
                        sdcc3: mmc@12180000 {
-                               compatible      = "arm,pl18x", "arm,primecell";
+                               compatible = "arm,pl18x", "arm,primecell";
                                arm,primecell-periphid = <0x00051180>;
-                               status          = "disabled";
-                               reg             = <0x12180000 0x2000>;
-                               interrupts      = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
-                               interrupt-names = "cmd_irq";
-                               clocks          = <&gcc SDC3_CLK>, <&gcc SDC3_H_CLK>;
-                               clock-names     = "mclk", "apb_pclk";
-                               bus-width       = <4>;
+                               status = "disabled";
+                               reg = <0x12180000 0x2000>;
+                               interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-names = "cmd_irq";
+                               clocks = <&gcc SDC3_CLK>, <&gcc SDC3_H_CLK>;
+                               clock-names = "mclk", "apb_pclk";
+                               bus-width = <4>;
                                cap-sd-highspeed;
                                cap-mmc-highspeed;
-                               max-frequency   = <192000000>;
+                               max-frequency = <192000000>;
                                no-1-8-v;
                                dmas = <&sdcc3bam 2>, <&sdcc3bam 1>;
                                dma-names = "tx", "rx";
                        };
 
                        sdcc4: mmc@121c0000 {
-                               compatible      = "arm,pl18x", "arm,primecell";
+                               compatible = "arm,pl18x", "arm,primecell";
                                arm,primecell-periphid = <0x00051180>;
-                               status          = "disabled";
-                               reg             = <0x121c0000 0x2000>;
-                               interrupts      = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
-                               interrupt-names = "cmd_irq";
-                               clocks          = <&gcc SDC4_CLK>, <&gcc SDC4_H_CLK>;
-                               clock-names     = "mclk", "apb_pclk";
-                               bus-width       = <4>;
+                               status = "disabled";
+                               reg = <0x121c0000 0x2000>;
+                               interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-names = "cmd_irq";
+                               clocks = <&gcc SDC4_CLK>, <&gcc SDC4_H_CLK>;
+                               clock-names = "mclk", "apb_pclk";
+                               bus-width = <4>;
                                cap-sd-highspeed;
                                cap-mmc-highspeed;
-                               max-frequency   = <48000000>;
+                               max-frequency = <48000000>;
                                dmas = <&sdcc4bam 2>, <&sdcc4bam 1>;
                                dma-names = "tx", "rx";
                                pinctrl-names = "default";
                        syscon-sfpb = <&mmss_sfpb>;
                        phys = <&dsi0_phy>;
                        phy-names = "dsi";
+                       status = "disabled";
+
                        ports {
                                #address-cells = <1>;
                                #size-cells = <0>;
                                <0x04700300 0x200>,
                                <0x04700500 0x5c>;
                        reg-names = "dsi_pll", "dsi_phy", "dsi_phy_regulator";
-                       clock-names = "iface_clk", "ref";
+                       clock-names = "iface", "ref";
                        clocks = <&mmcc DSI_M_AHB_CLK>,
                                 <&pxo_board>;
+                       status = "disabled";
                };
 
 
                                      "slave_iface";
 
                        phys = <&hdmi_phy>;
-                       phy-names = "hdmi-phy";
 
                        ports {
                                #address-cells = <1>;
index da50a1a..72f9255 100644 (file)
@@ -95,7 +95,7 @@
 
        firmware {
                scm {
-                       compatible = "qcom,scm";
+                       compatible = "qcom,scm-apq8084", "qcom,scm";
                        clocks = <&gcc GCC_CE1_CLK> , <&gcc GCC_CE1_AXI_CLK>, <&gcc GCC_CE1_AHB_CLK>;
                        clock-names = "core", "bus", "iface";
                };
                };
 
                qfprom: qfprom@fc4bc000 {
+                       compatible = "qcom,apq8084-qfprom", "qcom,qfprom";
+                       reg = <0xfc4bc000 0x1000>;
                        #address-cells = <1>;
                        #size-cells = <1>;
-                       compatible = "qcom,qfprom";
-                       reg = <0xfc4bc000 0x1000>;
                        tsens_calib: calib@d0 {
                                reg = <0xd0 0x18>;
                        };
                        status = "disabled";
                };
 
-               sdhci@f9824900 {
+               mmc@f9824900 {
                        compatible = "qcom,apq8084-sdhci", "qcom,sdhci-msm-v4";
                        reg = <0xf9824900 0x11c>, <0xf9824000 0x800>;
                        reg-names = "hc_mem", "core_mem";
                        status = "disabled";
                };
 
-               sdhci@f98a4900 {
+               mmc@f98a4900 {
                        compatible = "qcom,apq8084-sdhci", "qcom,sdhci-msm-v4";
                        reg = <0xf98a4900 0x11c>, <0xf98a4000 0x800>;
                        reg-names = "hc_mem", "core_mem";
index 028ac8e..cf7da1a 100644 (file)
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-or-later OR MIT
 
+#include <dt-bindings/leds/common.h>
 #include "qcom-ipq4018-ap120c-ac.dtsi"
 
 / {
 
                power {
                        label = "ap120c-ac:green:power";
+                       function = LED_FUNCTION_POWER;
+                       color = <LED_COLOR_ID_GREEN>;
                        gpios = <&tlmm 5 GPIO_ACTIVE_LOW>;
                        default-state = "on";
                };
 
                wlan {
                        label = "ap120c-ac:green:wlan";
+                       function = LED_FUNCTION_WLAN;
+                       color = <LED_COLOR_ID_GREEN>;
                        gpios = <&tlmm 3 GPIO_ACTIVE_HIGH>;
                };
 
                support {
                        label = "ap120c-ac:green:support";
+                       color = <LED_COLOR_ID_GREEN>;
                        gpios = <&tlmm 2 GPIO_ACTIVE_HIGH>;
                        panic-indicator;
                };
index b7916fc..c4f89b7 100644 (file)
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-or-later OR MIT
 
+#include <dt-bindings/leds/common.h>
 #include "qcom-ipq4018-ap120c-ac.dtsi"
 
 / {
@@ -8,18 +9,24 @@
 
                status: status {
                        label = "ap120c-ac:blue:status";
+                       function = LED_FUNCTION_STATUS;
+                       color = <LED_COLOR_ID_BLUE>;
                        gpios = <&tlmm 5 GPIO_ACTIVE_LOW>;
                        default-state = "keep";
                };
 
                wlan2g {
                        label = "ap120c-ac:green:wlan2g";
+                       function = LED_FUNCTION_WLAN;
+                       color = <LED_COLOR_ID_GREEN>;
                        gpios = <&tlmm 3 GPIO_ACTIVE_HIGH>;
                        linux,default-trigger = "phy0tpt";
                };
 
                wlan5g {
                        label = "ap120c-ac:red:wlan5g";
+                       function = LED_FUNCTION_WLAN;
+                       color = <LED_COLOR_ID_RED>;
                        gpios = <&tlmm 2 GPIO_ACTIVE_HIGH>;
                        linux,default-trigger = "phy1tpt";
                };
index 1f3b1ce..af9a26f 100644 (file)
@@ -11,7 +11,7 @@
        keys {
                compatible = "gpio-keys";
 
-               reset {
+               key-reset {
                        label = "reset";
                        gpios = <&tlmm 63 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_RESTART>;
index faeaa6b..44a9597 100644 (file)
@@ -93,7 +93,7 @@
                                #address-cells = <1>;
                                #size-cells = <1>;
                                reg = <0>;
-                               compatible = "n25q128a11";
+                               compatible = "micron,n25q128a11", "jedec,spi-nor";
                                spi-max-frequency = <24000000>;
                        };
                };
index d596dd1..c7a6e77 100644 (file)
@@ -56,7 +56,7 @@
                                #address-cells = <1>;
                                #size-cells = <1>;
                                reg = <0>;
-                               compatible = "n25q128a11";
+                               compatible = "micron,n25q128a11", "jedec,spi-nor";
                                spi-max-frequency = <24000000>;
                        };
                };
index c5da723..bb307b8 100644 (file)
 
        firmware {
                scm {
-                       compatible = "qcom,scm-ipq4019";
+                       compatible = "qcom,scm-ipq4019", "qcom,scm";
                };
        };
 
                        status = "disabled";
                };
 
-               sdhci: sdhci@7824900 {
+               sdhci: mmc@7824900 {
                        compatible = "qcom,sdhci-msm-v4";
                        reg = <0x7824900 0x11c>, <0x7824000 0x800>;
                        interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
index b63d01d..a654d3c 100644 (file)
@@ -7,12 +7,6 @@
 
        soc {
                pinmux@800000 {
-                       i2c4_pins: i2c4_pinmux {
-                               pins = "gpio12", "gpio13";
-                               function = "gsbi4";
-                               bias-disable;
-                       };
-
                        buttons_pins: buttons_pins {
                                mux {
                                        pins = "gpio54", "gpio65";
index 596d129..5a65cce 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 #include "qcom-ipq8064.dtsi"
 #include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
 
 / {
        model = "MikroTik RB3011UiAS-RM";
                        };
                };
 
-               gpio_keys {
+               gpio-keys {
                        compatible = "gpio-keys";
                        pinctrl-0 = <&buttons_pins>;
                        pinctrl-names = "default";
 
-                       button@1 {
+                       button {
                                label = "reset";
                                linux,code = <KEY_RESTART>;
                                gpios = <&qcom_pinmux 66 GPIO_ACTIVE_LOW>;
 
                        led@7 {
                                label = "rb3011:green:user";
+                               color = <LED_COLOR_ID_GREEN>;
                                gpios = <&qcom_pinmux 33 GPIO_ACTIVE_HIGH>;
                                default-state = "off";
                        };
                };
        };
 
-       mdio0_pins: mdio0_pins {
-               mux {
-                       pins = "gpio0", "gpio1";
-                       function = "gpio";
-                       drive-strength = <8>;
-                       bias-disable;
-               };
-       };
-
        mdio1_pins: mdio1_pins {
                mux {
                        pins = "gpio10", "gpio11";
diff --git a/arch/arm/boot/dts/qcom-ipq8064-smb208.dtsi b/arch/arm/boot/dts/qcom-ipq8064-smb208.dtsi
new file mode 100644 (file)
index 0000000..ac9c44f
--- /dev/null
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "qcom-ipq8064.dtsi"
+
+&rpm {
+       smb208_regulators: regulators {
+               compatible = "qcom,rpm-smb208-regulators";
+
+               smb208_s1a: s1a {
+                       regulator-min-microvolt = <1050000>;
+                       regulator-max-microvolt = <1150000>;
+
+                       qcom,switch-mode-frequency = <1200000>;
+               };
+
+               smb208_s1b: s1b {
+                       regulator-min-microvolt = <1050000>;
+                       regulator-max-microvolt = <1150000>;
+
+                       qcom,switch-mode-frequency = <1200000>;
+               };
+
+               smb208_s2a: s2a {
+                       regulator-min-microvolt = < 800000>;
+                       regulator-max-microvolt = <1250000>;
+
+                       qcom,switch-mode-frequency = <1200000>;
+               };
+
+               smb208_s2b: s2b {
+                       regulator-min-microvolt = < 800000>;
+                       regulator-max-microvolt = <1250000>;
+
+                       qcom,switch-mode-frequency = <1200000>;
+               };
+       };
+};
index 5c802b9..411c8d6 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 #include "qcom-ipq8064.dtsi"
 #include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
 
 / {
        model = "Qualcomm Technologies, Inc. IPQ8064-v1.0";
                        status = "okay";
                };
 
-               gpio_keys {
+               gpio-keys {
                        compatible = "gpio-keys";
                        pinctrl-0 = <&buttons_pins>;
                        pinctrl-names = "default";
 
-                       button@1 {
+                       button-1 {
                                label = "reset";
                                linux,code = <KEY_RESTART>;
                                gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>;
                                linux,input-type = <1>;
                                debounce-interval = <60>;
                        };
-                       button@2 {
+                       button-2 {
                                label = "wps";
                                linux,code = <KEY_WPS_BUTTON>;
                                gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>;
 
                        led@9 {
                                label = "status_led_fail";
+                               function = LED_FUNCTION_STATUS;
                                gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>;
                                default-state = "off";
                        };
 
                        led@53 {
                                label = "status_led_pass";
+                               function = LED_FUNCTION_STATUS;
                                gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>;
                                default-state = "off";
                        };
index 808ea18..c8337c8 100644 (file)
                };
 
                smem: smem@41000000 {
+                       compatible = "qcom,smem";
                        reg = <0x41000000 0x200000>;
                        no-map;
+
+                       hwlocks = <&sfpb_mutex 3>;
                };
        };
 
                                };
                        };
 
+                       i2c4_pins: i2c4-default {
+                               pins = "gpio12", "gpio13";
+                               function = "gsbi4";
+                               drive-strength = <12>;
+                               bias-disable;
+                       };
+
                        spi_pins: spi_pins {
                                mux {
                                        pins = "gpio18", "gpio19", "gpio21";
 
                                pullups {
                                        pins = "gpio39";
+                                       function = "nand";
+                                       drive-strength = <10>;
                                        bias-pull-up;
                                };
 
                                        pins = "gpio40", "gpio41", "gpio42",
                                               "gpio43", "gpio44", "gpio45",
                                               "gpio46", "gpio47";
+                                       function = "nand";
+                                       drive-strength = <10>;
                                        bias-bus-hold;
                                };
                        };
+
+                       mdio0_pins: mdio0-pins {
+                               mux {
+                                       pins = "gpio0", "gpio1";
+                                       function = "mdio";
+                                       drive-strength = <8>;
+                                       bias-disable;
+                               };
+                       };
+
+                       rgmii2_pins: rgmii2-pins {
+                               mux {
+                                       pins = "gpio27", "gpio28", "gpio29",
+                                              "gpio30", "gpio31", "gpio32",
+                                              "gpio51", "gpio52", "gpio59",
+                                              "gpio60", "gpio61", "gpio62";
+                                       function = "rgmii2";
+                                       drive-strength = <8>;
+                                       bias-disable;
+                               };
+                       };
                };
 
                intc: interrupt-controller@2000000 {
                        regulator;
                };
 
+               gsbi1: gsbi@12440000 {
+                       compatible = "qcom,gsbi-v1.0.0";
+                       reg = <0x12440000 0x100>;
+                       cell-index = <1>;
+                       clocks = <&gcc GSBI1_H_CLK>;
+                       clock-names = "iface";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+
+                       syscon-tcsr = <&tcsr>;
+
+                       status = "disabled";
+
+                       gsbi1_serial: serial@12450000 {
+                               compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
+                               reg = <0x12450000 0x100>,
+                                     <0x12400000 0x03>;
+                               interrupts = <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&gcc GSBI1_UART_CLK>, <&gcc GSBI1_H_CLK>;
+                               clock-names = "core", "iface";
+
+                               status = "disabled";
+                       };
+
+                       gsbi1_i2c: i2c@12460000 {
+                               compatible = "qcom,i2c-qup-v1.1.1";
+                               reg = <0x12460000 0x1000>;
+                               interrupts = <GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&gcc GSBI1_QUP_CLK>, <&gcc GSBI1_H_CLK>;
+                               clock-names = "core", "iface";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               status = "disabled";
+                       };
+               };
+
                gsbi2: gsbi@12480000 {
                        compatible = "qcom,gsbi-v1.0.0";
                        cell-index = <2>;
                                status = "disabled";
                        };
 
-                       i2c@124a0000 {
+                       gsbi2_i2c: i2c@124a0000 {
                                compatible = "qcom,i2c-qup-v1.1.1";
                                reg = <0x124a0000 0x1000>;
                                interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>;
                        };
                };
 
+               gsbi6: gsbi@16500000 {
+                       compatible = "qcom,gsbi-v1.0.0";
+                       reg = <0x16500000 0x100>;
+                       cell-index = <6>;
+                       clocks = <&gcc GSBI6_H_CLK>;
+                       clock-names = "iface";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+
+                       syscon-tcsr = <&tcsr>;
+
+                       status = "disabled";
+
+                       gsbi6_i2c: i2c@16580000 {
+                               compatible = "qcom,i2c-qup-v1.1.1";
+                               reg = <0x16580000 0x1000>;
+                               interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>;
+
+                               clocks = <&gcc GSBI6_QUP_CLK>, <&gcc GSBI6_H_CLK>;
+                               clock-names = "core", "iface";
+
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               status = "disabled";
+                       };
+
+                       gsbi6_spi: spi@16580000 {
+                               compatible = "qcom,spi-qup-v1.1.1";
+                               reg = <0x16580000 0x1000>;
+                               interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>;
+
+                               clocks = <&gcc GSBI6_QUP_CLK>, <&gcc GSBI6_H_CLK>;
+                               clock-names = "core", "iface";
+
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               status = "disabled";
+                       };
+               };
+
                gsbi7: gsbi@16600000 {
                        status = "disabled";
                        compatible = "qcom,gsbi-v1.0.0";
                                clock-names = "core", "iface";
                                status = "disabled";
                        };
+
+                       gsbi7_i2c: i2c@16680000 {
+                               compatible = "qcom,i2c-qup-v1.1.1";
+                               reg = <0x16680000 0x1000>;
+                               interrupts = <GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>;
+
+                               clocks = <&gcc GSBI7_QUP_CLK>, <&gcc GSBI7_H_CLK>;
+                               clock-names = "core", "iface";
+
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               status = "disabled";
+                       };
                };
 
                rng@1a500000 {
                };
 
                qfprom: qfprom@700000 {
-                       compatible = "qcom,qfprom";
+                       compatible = "qcom,ipq8064-qfprom", "qcom,qfprom";
                        reg = <0x00700000 0x1000>;
                        #address-cells = <1>;
                        #size-cells = <1>;
+                       speedbin_efuse: speedbin@c0 {
+                               reg = <0xc0 0x4>;
+                       };
                        tsens_calib: calib@400 {
                                reg = <0x400 0xb>;
                        };
                        rpmcc: clock-controller {
                                compatible = "qcom,rpmcc-ipq806x", "qcom,rpmcc";
                                #clock-cells = <1>;
+                               clocks = <&pxo_board>;
+                               clock-names = "pxo";
                        };
                };
 
                l2cc: clock-controller@2011000 {
                        compatible = "qcom,kpss-gcc", "syscon";
                        reg = <0x2011000 0x1000>;
-                       clocks = <&gcc PLL8_VOTE>, <&gcc PXO_SRC>;
+                       clocks = <&gcc PLL8_VOTE>, <&pxo_board>;
                        clock-names = "pll8_vote", "pxo";
                        clock-output-names = "acpu_l2_aux";
                };
                        #address-cells = <3>;
                        #size-cells = <2>;
 
-                       ranges = <0x81000000 0 0x0fe00000 0x0fe00000 0 0x00100000   /* downstream I/O */
+                       ranges = <0x81000000 0 0x0fe00000 0x0fe00000 0 0x00010000   /* downstream I/O */
                                  0x82000000 0 0x08000000 0x08000000 0 0x07e00000>; /* non-prefetchable memory */
 
                        interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
                        #address-cells = <3>;
                        #size-cells = <2>;
 
-                       ranges = <0x81000000 0 0x31e00000 0x31e00000 0 0x00100000   /* downstream I/O */
+                       ranges = <0x81000000 0 0x31e00000 0x31e00000 0 0x00010000   /* downstream I/O */
                                  0x82000000 0 0x2e000000 0x2e000000 0 0x03e00000>; /* non-prefetchable memory */
 
                        interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
                        #address-cells = <3>;
                        #size-cells = <2>;
 
-                       ranges = <0x81000000 0 0x35e00000 0x35e00000 0 0x00100000   /* downstream I/O */
+                       ranges = <0x81000000 0 0x35e00000 0x35e00000 0 0x00010000   /* downstream I/O */
                                  0x82000000 0 0x32000000 0x32000000 0 0x03e00000>; /* non-prefetchable memory */
 
                        interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
 
                gmac0: ethernet@37000000 {
                        device_type = "network";
-                       compatible = "qcom,ipq806x-gmac";
+                       compatible = "qcom,ipq806x-gmac", "snps,dwmac";
                        reg = <0x37000000 0x200000>;
                        interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "macirq";
 
                gmac1: ethernet@37200000 {
                        device_type = "network";
-                       compatible = "qcom,ipq806x-gmac";
+                       compatible = "qcom,ipq806x-gmac", "snps,dwmac";
                        reg = <0x37200000 0x200000>;
                        interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "macirq";
 
                gmac2: ethernet@37400000 {
                        device_type = "network";
-                       compatible = "qcom,ipq806x-gmac";
+                       compatible = "qcom,ipq806x-gmac", "snps,dwmac";
                        reg = <0x37400000 0x200000>;
                        interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "macirq";
 
                gmac3: ethernet@37600000 {
                        device_type = "network";
-                       compatible = "qcom,ipq806x-gmac";
+                       compatible = "qcom,ipq806x-gmac", "snps,dwmac";
                        reg = <0x37600000 0x200000>;
                        interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "macirq";
                        clocks = <&gcc USB30_1_UTMI_CLK>;
                        clock-names = "ref";
                        #phy-cells = <0>;
+
+                       status = "disabled";
                };
 
                ss_phy_1: phy@110f8830 {
                        clocks = <&gcc USB30_1_MASTER_CLK>;
                        clock-names = "ref";
                        #phy-cells = <0>;
+
+                       status = "disabled";
                };
 
                usb3_1: usb3@110f8800 {
                        ranges;
 
                        sdcc1: mmc@12400000 {
-                               status          = "disabled";
-                               compatible      = "arm,pl18x", "arm,primecell";
+                               status = "disabled";
+                               compatible = "arm,pl18x", "arm,primecell";
                                arm,primecell-periphid = <0x00051180>;
-                               reg             = <0x12400000 0x2000>;
-                               interrupts      = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
+                               reg = <0x12400000 0x2000>;
+                               interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
                                interrupt-names = "cmd_irq";
-                               clocks          = <&gcc SDC1_CLK>, <&gcc SDC1_H_CLK>;
-                               clock-names     = "mclk", "apb_pclk";
-                               bus-width       = <8>;
-                               max-frequency   = <96000000>;
+                               clocks = <&gcc SDC1_CLK>, <&gcc SDC1_H_CLK>;
+                               clock-names = "mclk", "apb_pclk";
+                               bus-width = <8>;
+                               max-frequency = <96000000>;
                                non-removable;
                                cap-sd-highspeed;
                                cap-mmc-highspeed;
                        };
 
                        sdcc3: mmc@12180000 {
-                               compatible      = "arm,pl18x", "arm,primecell";
+                               compatible = "arm,pl18x", "arm,primecell";
                                arm,primecell-periphid = <0x00051180>;
-                               status          = "disabled";
-                               reg             = <0x12180000 0x2000>;
-                               interrupts      = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
+                               status = "disabled";
+                               reg = <0x12180000 0x2000>;
+                               interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
                                interrupt-names = "cmd_irq";
-                               clocks          = <&gcc SDC3_CLK>, <&gcc SDC3_H_CLK>;
-                               clock-names     = "mclk", "apb_pclk";
-                               bus-width       = <8>;
+                               clocks = <&gcc SDC3_CLK>, <&gcc SDC3_H_CLK>;
+                               clock-names = "mclk", "apb_pclk";
+                               bus-width = <8>;
                                cap-sd-highspeed;
                                cap-mmc-highspeed;
-                               max-frequency   = <192000000>;
+                               max-frequency = <192000000>;
                                sd-uhs-sdr104;
                                sd-uhs-ddr50;
                                vqmmc-supply = <&vsdcc_fixed>;
                                dma-names = "tx", "rx";
                        };
                };
+
+               sfpb_mutex: hwlock@1200600 {
+                       compatible = "qcom,sfpb-mutex";
+                       reg = <0x01200600 0x100>;
+
+                       #hwlock-cells = <1>;
+               };
        };
 };
index 10ad929..49de182 100644 (file)
 };
 
 &pmicgpio {
-       usb_vbus_5v_pins: usb_vbus_5v_pins {
+       usb_vbus_5v_pins: usb-vbus-5v-state {
                pins = "gpio4";
                function = "normal";
                output-high;
index 8f0752c..b47c864 100644 (file)
 
                                pmicgpio: gpio@150 {
                                        compatible = "qcom,pm8018-gpio", "qcom,ssbi-gpio";
+                                       reg = <0x150>;
                                        interrupt-controller;
                                        #interrupt-cells = <2>;
                                        gpio-controller;
                                arm,primecell-periphid = <0x00051180>;
                                reg = <0x12180000 0x2000>;
                                interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
-                               interrupt-names = "cmd_irq";
+                               interrupt-names = "cmd_irq";
                                clocks = <&gcc SDC1_CLK>, <&gcc SDC1_H_CLK>;
                                clock-names = "mclk", "apb_pclk";
                                bus-width = <8>;
                                status = "disabled";
                                reg = <0x12140000 0x2000>;
                                interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
-                               interrupt-names = "cmd_irq";
+                               interrupt-names = "cmd_irq";
                                clocks = <&gcc SDC2_CLK>, <&gcc SDC2_H_CLK>;
                                clock-names = "mclk", "apb_pclk";
                                bus-width = <4>;
                        interrupts = <GIC_SPI 19 IRQ_TYPE_EDGE_RISING>,
                                     <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>,
                                     <GIC_SPI 22 IRQ_TYPE_EDGE_RISING>;
-                       interrupt-names = "ack", "err", "wakeup";
+                       interrupt-names = "ack", "err", "wakeup";
 
                        regulators {
                                compatible = "qcom,rpm-pm8018-regulators";
index 28eca15..0b5effd 100644 (file)
                        reg = <0xf9011000 0x1000>;
                };
 
-               sdhc_1: sdhci@f9824900 {
+               sdhc_1: mmc@f9824900 {
                        compatible = "qcom,msm8226-sdhci", "qcom,sdhci-msm-v4";
                        reg = <0xf9824900 0x11c>, <0xf9824000 0x800>;
                        reg-names = "hc_mem", "core_mem";
                        status = "disabled";
                };
 
-               sdhc_2: sdhci@f98a4900 {
+               sdhc_2: mmc@f98a4900 {
                        compatible = "qcom,msm8226-sdhci", "qcom,sdhci-msm-v4";
                        reg = <0xf98a4900 0x11c>, <0xf98a4000 0x800>;
                        reg-names = "hc_mem", "core_mem";
                        status = "disabled";
                };
 
-               sdhc_3: sdhci@f9864900 {
+               sdhc_3: mmc@f9864900 {
                        compatible = "qcom,msm8226-sdhci", "qcom,sdhci-msm-v4";
                        reg = <0xf9864900 0x11c>, <0xf9864000 0x800>;
                        reg-names = "hc_mem", "core_mem";
index 47b97da..63a501c 100644 (file)
@@ -56,7 +56,7 @@
                        clock-frequency = <19200000>;
                };
 
-               pxo_board {
+               pxo_board: pxo_board {
                        compatible = "fixed-clock";
                        #clock-cells = <0>;
                        clock-frequency = <27000000>;
                };
 
                l2cc: clock-controller@2082000 {
-                       compatible      = "qcom,kpss-gcc", "syscon";
-                       reg             = <0x02082000 0x1000>;
+                       compatible = "qcom,kpss-gcc", "syscon";
+                       reg = <0x02082000 0x1000>;
                };
 
                rpm: rpm@104000 {
-                       compatible      = "qcom,rpm-msm8660";
-                       reg             = <0x00104000 0x1000>;
-                       qcom,ipc        = <&l2cc 0x8 2>;
-
-                       interrupts      = <GIC_SPI 19 IRQ_TYPE_EDGE_RISING>,
-                                         <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>,
-                                         <GIC_SPI 22 IRQ_TYPE_EDGE_RISING>;
-                       interrupt-names = "ack", "err", "wakeup";
+                       compatible = "qcom,rpm-msm8660";
+                       reg = <0x00104000 0x1000>;
+                       qcom,ipc = <&l2cc 0x8 2>;
+
+                       interrupts = <GIC_SPI 19 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 22 IRQ_TYPE_EDGE_RISING>;
+                       interrupt-names = "ack", "err", "wakeup";
                        clocks = <&gcc RPM_MSG_RAM_H_CLK>;
                        clock-names = "ram";
 
                        rpmcc: clock-controller {
-                               compatible      = "qcom,rpmcc-msm8660", "qcom,rpmcc";
+                               compatible = "qcom,rpmcc-msm8660", "qcom,rpmcc";
                                #clock-cells = <1>;
+                               clocks = <&pxo_board>;
+                               clock-names = "pxo";
                        };
 
                        pm8901-regulators {
                        #size-cells = <1>;
                        ranges;
                        sdcc1: mmc@12400000 {
-                               status          = "disabled";
-                               compatible      = "arm,pl18x", "arm,primecell";
+                               status = "disabled";
+                               compatible = "arm,pl18x", "arm,primecell";
                                arm,primecell-periphid = <0x00051180>;
-                               reg             = <0x12400000 0x8000>;
-                               interrupts      = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
-                               interrupt-names = "cmd_irq";
-                               clocks          = <&gcc SDC1_CLK>, <&gcc SDC1_H_CLK>;
-                               clock-names     = "mclk", "apb_pclk";
-                               bus-width       = <8>;
-                               max-frequency   = <48000000>;
+                               reg = <0x12400000 0x8000>;
+                               interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-names = "cmd_irq";
+                               clocks = <&gcc SDC1_CLK>, <&gcc SDC1_H_CLK>;
+                               clock-names = "mclk", "apb_pclk";
+                               bus-width = <8>;
+                               max-frequency = <48000000>;
                                non-removable;
                                cap-sd-highspeed;
                                cap-mmc-highspeed;
                        };
 
                        sdcc2: mmc@12140000 {
-                               status          = "disabled";
-                               compatible      = "arm,pl18x", "arm,primecell";
+                               status = "disabled";
+                               compatible = "arm,pl18x", "arm,primecell";
                                arm,primecell-periphid = <0x00051180>;
-                               reg             = <0x12140000 0x8000>;
-                               interrupts      = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
-                               interrupt-names = "cmd_irq";
-                               clocks          = <&gcc SDC2_CLK>, <&gcc SDC2_H_CLK>;
-                               clock-names     = "mclk", "apb_pclk";
-                               bus-width       = <8>;
-                               max-frequency   = <48000000>;
+                               reg = <0x12140000 0x8000>;
+                               interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-names = "cmd_irq";
+                               clocks = <&gcc SDC2_CLK>, <&gcc SDC2_H_CLK>;
+                               clock-names = "mclk", "apb_pclk";
+                               bus-width = <8>;
+                               max-frequency = <48000000>;
                                cap-sd-highspeed;
                                cap-mmc-highspeed;
                        };
 
                        sdcc3: mmc@12180000 {
-                               compatible      = "arm,pl18x", "arm,primecell";
+                               compatible = "arm,pl18x", "arm,primecell";
                                arm,primecell-periphid = <0x00051180>;
-                               status          = "disabled";
-                               reg             = <0x12180000 0x8000>;
-                               interrupts      = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
-                               interrupt-names = "cmd_irq";
-                               clocks          = <&gcc SDC3_CLK>, <&gcc SDC3_H_CLK>;
-                               clock-names     = "mclk", "apb_pclk";
-                               bus-width       = <4>;
+                               status = "disabled";
+                               reg = <0x12180000 0x8000>;
+                               interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-names = "cmd_irq";
+                               clocks = <&gcc SDC3_CLK>, <&gcc SDC3_H_CLK>;
+                               clock-names = "mclk", "apb_pclk";
+                               bus-width = <4>;
                                cap-sd-highspeed;
                                cap-mmc-highspeed;
-                               max-frequency   = <48000000>;
+                               max-frequency = <48000000>;
                                no-1-8-v;
                        };
 
                        sdcc4: mmc@121c0000 {
-                               compatible      = "arm,pl18x", "arm,primecell";
+                               compatible = "arm,pl18x", "arm,primecell";
                                arm,primecell-periphid = <0x00051180>;
-                               status          = "disabled";
-                               reg             = <0x121c0000 0x8000>;
-                               interrupts      = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
-                               interrupt-names = "cmd_irq";
-                               clocks          = <&gcc SDC4_CLK>, <&gcc SDC4_H_CLK>;
-                               clock-names     = "mclk", "apb_pclk";
-                               bus-width       = <4>;
-                               max-frequency   = <48000000>;
+                               status = "disabled";
+                               reg = <0x121c0000 0x8000>;
+                               interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-names = "cmd_irq";
+                               clocks = <&gcc SDC4_CLK>, <&gcc SDC4_H_CLK>;
+                               clock-names = "mclk", "apb_pclk";
+                               bus-width = <4>;
+                               max-frequency = <48000000>;
                                cap-sd-highspeed;
                                cap-mmc-highspeed;
                        };
 
                        sdcc5: mmc@12200000 {
-                               compatible      = "arm,pl18x", "arm,primecell";
+                               compatible = "arm,pl18x", "arm,primecell";
                                arm,primecell-periphid = <0x00051180>;
-                               status          = "disabled";
-                               reg             = <0x12200000 0x8000>;
-                               interrupts      = <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>;
-                               interrupt-names = "cmd_irq";
-                               clocks          = <&gcc SDC5_CLK>, <&gcc SDC5_H_CLK>;
-                               clock-names     = "mclk", "apb_pclk";
-                               bus-width       = <4>;
+                               status = "disabled";
+                               reg = <0x12200000 0x8000>;
+                               interrupts = <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-names = "cmd_irq";
+                               clocks = <&gcc SDC5_CLK>, <&gcc SDC5_H_CLK>;
+                               clock-names = "mclk", "apb_pclk";
+                               bus-width = <4>;
                                cap-sd-highspeed;
                                cap-mmc-highspeed;
-                               max-frequency   = <48000000>;
+                               max-frequency = <48000000>;
                        };
                };
 
index 4a2d74c..19554f3 100644 (file)
                };
 
                l2cc: clock-controller@2011000 {
-                       compatible      = "qcom,kpss-gcc", "syscon";
-                       reg             = <0x2011000 0x1000>;
+                       compatible = "qcom,kpss-gcc", "syscon";
+                       reg = <0x2011000 0x1000>;
                };
 
                rpm@108000 {
-                       compatible      = "qcom,rpm-msm8960";
-                       reg             = <0x108000 0x1000>;
-                       qcom,ipc        = <&l2cc 0x8 2>;
+                       compatible = "qcom,rpm-msm8960";
+                       reg = <0x108000 0x1000>;
+                       qcom,ipc = <&l2cc 0x8 2>;
 
-                       interrupts      = <GIC_SPI 19 IRQ_TYPE_EDGE_RISING>,
-                                         <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>,
-                                         <GIC_SPI 22 IRQ_TYPE_EDGE_RISING>;
-                       interrupt-names = "ack", "err", "wakeup";
+                       interrupts = <GIC_SPI 19 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 22 IRQ_TYPE_EDGE_RISING>;
+                       interrupt-names = "ack", "err", "wakeup";
 
                        regulators {
                                compatible = "qcom,rpm-pm8921-regulators";
                        #size-cells = <1>;
                        ranges;
                        sdcc1: mmc@12400000 {
-                               status          = "disabled";
-                               compatible      = "arm,pl18x", "arm,primecell";
+                               status = "disabled";
+                               compatible = "arm,pl18x", "arm,primecell";
                                arm,primecell-periphid = <0x00051180>;
-                               reg             = <0x12400000 0x8000>;
-                               interrupts      = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
-                               interrupt-names = "cmd_irq";
-                               clocks          = <&gcc SDC1_CLK>, <&gcc SDC1_H_CLK>;
-                               clock-names     = "mclk", "apb_pclk";
-                               bus-width       = <8>;
-                               max-frequency   = <96000000>;
+                               reg = <0x12400000 0x8000>;
+                               interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-names = "cmd_irq";
+                               clocks = <&gcc SDC1_CLK>, <&gcc SDC1_H_CLK>;
+                               clock-names = "mclk", "apb_pclk";
+                               bus-width = <8>;
+                               max-frequency = <96000000>;
                                non-removable;
                                cap-sd-highspeed;
                                cap-mmc-highspeed;
                        };
 
                        sdcc3: mmc@12180000 {
-                               compatible      = "arm,pl18x", "arm,primecell";
+                               compatible = "arm,pl18x", "arm,primecell";
                                arm,primecell-periphid = <0x00051180>;
-                               status          = "disabled";
-                               reg             = <0x12180000 0x8000>;
-                               interrupts      = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
-                               interrupt-names = "cmd_irq";
-                               clocks          = <&gcc SDC3_CLK>, <&gcc SDC3_H_CLK>;
-                               clock-names     = "mclk", "apb_pclk";
-                               bus-width       = <4>;
+                               status = "disabled";
+                               reg = <0x12180000 0x8000>;
+                               interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupt-names = "cmd_irq";
+                               clocks = <&gcc SDC3_CLK>, <&gcc SDC3_H_CLK>;
+                               clock-names = "mclk", "apb_pclk";
+                               bus-width = <4>;
                                cap-sd-highspeed;
                                cap-mmc-highspeed;
-                               max-frequency   = <192000000>;
+                               max-frequency = <192000000>;
                                no-1-8-v;
                                vmmc-supply = <&vsdcc_fixed>;
                        };
index 9493886..ec5d340 100644 (file)
@@ -3,6 +3,7 @@
 #include "qcom-pm8841.dtsi"
 #include "qcom-pm8941.dtsi"
 #include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
 #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
 
 / {
                pinctrl-names = "default";
                pinctrl-0 = <&gpio_keys_pin_a>;
 
-               volume-up {
+               key-volume-up {
                        label = "volume_up";
                        gpios = <&pm8941_gpios 2 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
                        linux,code = <KEY_VOLUMEUP>;
                };
 
-               volume-down {
+               key-volume-down {
                        label = "volume_down";
                        gpios = <&pm8941_gpios 3 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
 };
 
 &pm8941_gpios {
-       gpio_keys_pin_a: gpio-keys-active {
+       gpio_keys_pin_a: gpio-keys-active-state {
                pins = "gpio2", "gpio3";
                function = "normal";
 
                power-source = <PM8941_GPIO_S3>;
        };
 
-       fuelgauge_pin: fuelgauge-int {
+       fuelgauge_pin: fuelgauge-int-state {
                pins = "gpio9";
                function = "normal";
 
                power-source = <PM8941_GPIO_S3>;
        };
 
-       wlan_sleep_clk_pin: wl-sleep-clk {
+       wlan_sleep_clk_pin: wl-sleep-clk-state {
                pins = "gpio16";
                function = "func2";
 
                power-source = <PM8941_GPIO_S3>;
        };
 
-       wlan_regulator_pin: wl-reg-active {
+       wlan_regulator_pin: wl-reg-active-state {
                pins = "gpio17";
                function = "normal";
 
        };
 };
 
+&pm8941_lpg {
+       status = "okay";
+
+       qcom,power-source = <1>;
+
+       multi-led {
+               color = <LED_COLOR_ID_RGB>;
+               function = LED_FUNCTION_STATUS;
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               led@7 {
+                       reg = <7>;
+                       color = <LED_COLOR_ID_RED>;
+               };
+
+               led@6 {
+                       reg = <6>;
+                       color = <LED_COLOR_ID_GREEN>;
+               };
+
+               led@5 {
+                       reg = <5>;
+                       color = <LED_COLOR_ID_BLUE>;
+               };
+       };
+};
+
 &rpm_requests {
        pm8841-regulators {
                compatible = "qcom,rpm-pm8841-regulators";
index 1d21de4..5a70683 100644 (file)
@@ -3,6 +3,7 @@
 #include "qcom-pm8841.dtsi"
 #include "qcom-pm8941.dtsi"
 #include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
 #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
 
 / {
                pinctrl-names = "default";
                pinctrl-0 = <&gpio_keys_pin_a>;
 
-               volume-down {
+               key-volume-down {
                        label = "volume_down";
                        gpios = <&pm8941_gpios 2 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
                        linux,code = <KEY_VOLUMEDOWN>;
                };
 
-               camera-snapshot {
+               key-camera-snapshot {
                        label = "camera_snapshot";
                        gpios = <&pm8941_gpios 3 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
                        linux,code = <KEY_CAMERA>;
                };
 
-               camera-focus {
+               key-camera-focus {
                        label = "camera_focus";
                        gpios = <&pm8941_gpios 4 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
                        linux,code = <KEY_CAMERA_FOCUS>;
                };
 
-               volume-up {
+               key-volume-up {
                        label = "volume_up";
                        gpios = <&pm8941_gpios 5 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
 };
 
 &pm8941_gpios {
-       gpio_keys_pin_a: gpio-keys-active {
+       gpio_keys_pin_a: gpio-keys-active-state {
                pins = "gpio2", "gpio3", "gpio4", "gpio5";
                function = "normal";
 
        };
 };
 
+&pm8941_lpg {
+       status = "okay";
+
+       qcom,power-source = <1>;
+
+       rgb-led {
+               color = <LED_COLOR_ID_RGB>;
+               function = LED_FUNCTION_STATUS;
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               led@5 {
+                       reg = <5>;
+                       color = <LED_COLOR_ID_BLUE>;
+               };
+
+               led@6 {
+                       reg = <6>;
+                       color = <LED_COLOR_ID_GREEN>;
+               };
+
+               led@7 {
+                       reg = <7>;
+                       color = <LED_COLOR_ID_RED>;
+               };
+       };
+};
+
 &pm8941_wled {
        status = "okay";
 
index 814ad0b..8baca2a 100644 (file)
@@ -96,7 +96,7 @@
 
        firmware {
                scm {
-                       compatible = "qcom,scm";
+                       compatible = "qcom,scm-msm8974", "qcom,scm";
                        clocks = <&gcc GCC_CE1_CLK>, <&gcc GCC_CE1_AXI_CLK>, <&gcc GCC_CE1_AHB_CLK>;
                        clock-names = "core", "bus", "iface";
                };
                        reg = <0xf90b8000 0x1000>, <0xf9008000 0x1000>;
                };
 
-               sdhc_1: sdhci@f9824900 {
+               sdhc_1: mmc@f9824900 {
                        compatible = "qcom,msm8974-sdhci", "qcom,sdhci-msm-v4";
                        reg = <0xf9824900 0x11c>, <0xf9824000 0x800>;
                        reg-names = "hc_mem", "core_mem";
                        status = "disabled";
                };
 
-               sdhc_3: sdhci@f9864900 {
+               sdhc_3: mmc@f9864900 {
                        compatible = "qcom,msm8974-sdhci", "qcom,sdhci-msm-v4";
                        reg = <0xf9864900 0x11c>, <0xf9864000 0x800>;
                        reg-names = "hc_mem", "core_mem";
                        status = "disabled";
                };
 
-               sdhc_2: sdhci@f98a4900 {
+               sdhc_2: mmc@f98a4900 {
                        compatible = "qcom,msm8974-sdhci", "qcom,sdhci-msm-v4";
                        reg = <0xf98a4900 0x11c>, <0xf98a4000 0x800>;
                        reg-names = "hc_mem", "core_mem";
                        interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&gcc GCC_BLSP1_UART2_APPS_CLK>, <&gcc GCC_BLSP1_AHB_CLK>;
                        clock-names = "core", "iface";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&blsp1_uart2_default>;
                        status = "disabled";
                };
 
                blsp2_uart1: serial@f995d000 {
                        compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
                        reg = <0xf995d000 0x1000>;
-                       interrupts = <GIC_SPI 113 IRQ_TYPE_NONE>;
+                       interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&gcc GCC_BLSP2_UART1_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>;
                        clock-names = "core", "iface";
+                       pinctrl-names = "default", "sleep";
+                       pinctrl-0 = <&blsp2_uart1_default>;
+                       pinctrl-1 = <&blsp2_uart1_sleep>;
                        status = "disabled";
                };
 
                        interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&gcc GCC_BLSP2_UART4_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>;
                        clock-names = "core", "iface";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&blsp2_uart4_default>;
                        status = "disabled";
                };
 
                        interrupts = <0 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";
+                       pinctrl-0 = <&blsp2_i2c6_default>;
+                       pinctrl-1 = <&blsp2_i2c6_sleep>;
                        #address-cells = <1>;
                        #size-cells = <0>;
                };
                };
 
                qfprom: qfprom@fc4bc000 {
+                       compatible = "qcom,msm8974-qfprom", "qcom,qfprom";
+                       reg = <0xfc4bc000 0x1000>;
                        #address-cells = <1>;
                        #size-cells = <1>;
-                       compatible = "qcom,qfprom";
-                       reg = <0xfc4bc000 0x1000>;
                        tsens_calib: calib@d0 {
                                reg = <0xd0 0x18>;
                        };
                        #interrupt-cells = <4>;
                };
 
+               bam_dmux_dma: dma-controller@fc834000 {
+                       compatible = "qcom,bam-v1.4.0";
+                       reg = <0xfc834000 0x7000>;
+                       interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+                       #dma-cells = <1>;
+                       qcom,ee = <0>;
+
+                       num-channels = <6>;
+                       qcom,num-ees = <1>;
+                       qcom,powered-remotely;
+               };
+
                remoteproc_mss: remoteproc@fc880000 {
                        compatible = "qcom,msm8974-mss-pil";
                        reg = <0xfc880000 0x100>, <0xfc820000 0x020>;
                        qcom,smem-states = <&modem_smp2p_out 0>;
                        qcom,smem-state-names = "stop";
 
+                       status = "disabled";
+
                        mba {
                                memory-region = <&mba_region>;
                        };
                                memory-region = <&mpss_region>;
                        };
 
+                       bam_dmux: bam-dmux {
+                               compatible = "qcom,bam-dmux";
+
+                               interrupt-parent = <&modem_smsm>;
+                               interrupts = <1 IRQ_TYPE_EDGE_BOTH>, <11 IRQ_TYPE_EDGE_BOTH>;
+                               interrupt-names = "pc", "pc-ack";
+
+                               qcom,smem-states = <&apps_smsm 1>, <&apps_smsm 11>;
+                               qcom,smem-state-names = "pc", "pc-ack";
+
+                               dmas = <&bam_dmux_dma 4>, <&bam_dmux_dma 5>;
+                               dma-names = "tx", "rx";
+                       };
+
                        smd-edge {
                                interrupts = <GIC_SPI 25 IRQ_TYPE_EDGE_RISING>;
 
                                };
                        };
 
-                       blsp1_uart2_active: blsp1-uart2-active {
+                       blsp1_uart2_default: blsp1-uart2-default {
                                rx {
                                        pins = "gpio5";
                                        function = "blsp_uart2";
                                };
                        };
 
-                       blsp2_uart1_active: blsp2-uart1-active {
+                       blsp2_uart1_default: blsp2-uart1-default {
                                tx-rts {
                                        pins = "gpio41", "gpio44";
                                        function = "blsp_uart7";
                                bias-pull-down;
                        };
 
-                       blsp2_uart4_active: blsp2-uart4-active {
+                       blsp2_uart4_default: blsp2-uart4-default {
                                tx-rts {
                                        pins = "gpio53", "gpio56";
                                        function = "blsp_uart10";
                                bias-pull-up;
                        };
 
-                       /* BLSP2_I2C6 info is missing - nobody uses it though? */
+                       blsp2_i2c6_default: blsp2-i2c6-default {
+                               pins = "gpio87", "gpio88";
+                               function = "blsp_i2c12";
+                               drive-strength = <2>;
+                               bias-disable;
+                       };
+
+                       blsp2_i2c6_sleep: blsp2-i2c6-sleep {
+                               pins = "gpio87", "gpio88";
+                               function = "blsp_i2c12";
+                               drive-strength = <2>;
+                               bias-pull-up;
+                       };
 
                        spi8_default: spi8_default {
                                mosi {
 
                        status = "disabled";
 
-                       gpu_opp_table: opp_table {
+                       gpu_opp_table: opp-table {
                                compatible = "operating-points-v2";
 
                                opp-320000000 {
                        };
                };
 
-               ocmem@fdd00000 {
+               sram@fdd00000 {
                        compatible = "qcom,msm8974-ocmem";
                        reg = <0xfdd00000 0x2000>,
                              <0xfec00000 0x180000>;
                        reg-names = "ctrl", "mem";
+                       ranges = <0 0xfec00000 0x180000>;
                        clocks = <&rpmcc RPM_SMD_OCMEMGX_CLK>,
                                 <&mmcc OCMEMCX_OCMEMNOC_CLK>;
                        clock-names = "core", "iface";
                        qcom,smem-states = <&adsp_smp2p_out 0>;
                        qcom,smem-state-names = "stop";
 
+                       status = "disabled";
+
                        smd-edge {
                                interrupts = <GIC_SPI 156 IRQ_TYPE_EDGE_RISING>;
 
                        };
                };
 
-               imem: imem@fe805000 {
-                       compatible = "syscon", "simple-mfd";
+               imem: sram@fe805000 {
+                       compatible = "qcom,msm8974-imem", "syscon", "simple-mfd";
                        reg = <0xfe805000 0x1000>;
 
                        reboot-mode {
index 58cb2ce..ff6e006 100644 (file)
@@ -3,6 +3,7 @@
 #include "qcom-pm8841.dtsi"
 #include "qcom-pm8941.dtsi"
 #include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
 #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
 
 / {
@@ -25,7 +26,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&gpio_keys_pin_a>;
 
-               camera-snapshot {
+               key-camera-snapshot {
                        label = "camera_snapshot";
                        gpios = <&pm8941_gpios 1 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_CAMERA>;
@@ -33,7 +34,7 @@
                        debounce-interval = <15>;
                };
 
-               volume-down {
+               key-volume-down {
                        label = "volume_down";
                        gpios = <&pm8941_gpios 2 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEDOWN>;
@@ -41,7 +42,7 @@
                        debounce-interval = <15>;
                };
 
-               volume-up {
+               key-volume-up {
                        label = "volume_up";
                        gpios = <&pm8941_gpios 5 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
@@ -78,9 +79,9 @@
 
 &imem {
        reboot-mode {
-               mode-normal     = <0x77665501>;
-               mode-bootloader = <0x77665500>;
-               mode-recovery   = <0x77665502>;
+               mode-normal = <0x77665501>;
+               mode-bootloader = <0x77665500>;
+               mode-recovery = <0x77665502>;
        };
 };
 
 };
 
 &pm8941_gpios {
-       gpio_keys_pin_a: gpio-keys-active {
+       gpio_keys_pin_a: gpio-keys-active-state {
                pins = "gpio1", "gpio2", "gpio5";
                function = "normal";
 
        };
 };
 
+&pm8941_lpg {
+       status = "okay";
+
+       qcom,power-source = <1>;
+
+       multi-led {
+               color = <LED_COLOR_ID_RGB>;
+               function = LED_FUNCTION_STATUS;
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               led@7 {
+                       reg = <7>;
+                       color = <LED_COLOR_ID_RED>;
+               };
+
+               led@6 {
+                       reg = <6>;
+                       color = <LED_COLOR_ID_GREEN>;
+               };
+
+               led@5 {
+                       reg = <5>;
+                       color = <LED_COLOR_ID_BLUE>;
+               };
+       };
+};
+
 &pronto {
        status = "okay";
 
 };
 
 &remoteproc_adsp {
+       status = "okay";
        cx-supply = <&pm8841_s2>;
 };
 
 &remoteproc_mss {
+       status = "okay";
        cx-supply = <&pm8841_s2>;
        mss-supply = <&pm8841_s3>;
        mx-supply = <&pm8841_s1>;
index d6b2300..983e10c 100644 (file)
@@ -25,7 +25,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&gpio_keys_pin_a>;
 
-               volume-down {
+               key-volume-down {
                        label = "volume_down";
                        gpios = <&pma8084_gpios 2 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
@@ -33,7 +33,7 @@
                        debounce-interval = <15>;
                };
 
-               home-key {
+               key-home {
                        label = "home_key";
                        gpios = <&pma8084_gpios 3 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
@@ -42,7 +42,7 @@
                        debounce-interval = <15>;
                };
 
-               volume-up {
+               key-volume-up {
                        label = "volume_up";
                        gpios = <&pma8084_gpios 5 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
 };
 
 &pma8084_gpios {
-       gpio_keys_pin_a: gpio-keys-active {
+       gpio_keys_pin_a: gpio-keys-active-state {
                pins = "gpio2", "gpio3", "gpio5";
                function = "normal";
 
                power-source = <PMA8084_GPIO_S4>;
        };
 
-       touchkey_pin: touchkey-int-pin {
+       touchkey_pin: touchkey-int-state {
                pins = "gpio6";
                function = "normal";
                bias-disable;
                power-source = <PMA8084_GPIO_S4>;
        };
 
-       touch_pin: touchscreen-int-pin {
+       touch_pin: touchscreen-int-state {
                pins = "gpio8";
                function = "normal";
                bias-disable;
                power-source = <PMA8084_GPIO_S4>;
        };
 
-       panel_en_pin: panel-en-pin {
+       panel_en_pin: panel-en-state {
                pins = "gpio14";
                function = "normal";
                bias-pull-up;
                qcom,drive-strength = <PMIC_GPIO_STRENGTH_LOW>;
        };
 
-       wlan_sleep_clk_pin: wlan-sleep-clk-pin {
+       wlan_sleep_clk_pin: wlan-sleep-clk-state {
                pins = "gpio16";
                function = "func2";
 
                qcom,drive-strength = <PMIC_GPIO_STRENGTH_HIGH>;
        };
 
-       panel_rst_pin: panel-rst-pin {
+       panel_rst_pin: panel-rst-state {
                pins = "gpio17";
                function = "normal";
                bias-disable;
                qcom,drive-strength = <PMIC_GPIO_STRENGTH_LOW>;
        };
 
-       fuelgauge_pin: fuelgauge-int-pin {
+       fuelgauge_pin: fuelgauge-int-state {
                pins = "gpio21";
                function = "normal";
                bias-disable;
 };
 
 &remoteproc_adsp {
+       status = "okay";
        cx-supply = <&pma8084_s2>;
 };
 
 &remoteproc_mss {
+       status = "okay";
        cx-supply = <&pma8084_s2>;
        mss-supply = <&pma8084_s6>;
        mx-supply = <&pma8084_s1>;
index 9bd8fae..3f45f5c 100644 (file)
@@ -3,6 +3,7 @@
 #include "qcom-pm8841.dtsi"
 #include "qcom-pm8941.dtsi"
 #include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
 #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
 
 / {
                pinctrl-names = "default";
                pinctrl-0 = <&gpio_keys_pin_a>;
 
-               volume-down {
+               key-volume-down {
                        label = "volume_down";
                        gpios = <&pm8941_gpios 2 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
                        linux,code = <KEY_VOLUMEDOWN>;
                };
 
-               camera-snapshot {
+               key-camera-snapshot {
                        label = "camera_snapshot";
                        gpios = <&pm8941_gpios 3 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
                        linux,code = <KEY_CAMERA>;
                };
 
-               camera-focus {
+               key-camera-focus {
                        label = "camera_focus";
                        gpios = <&pm8941_gpios 4 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
                        linux,code = <KEY_CAMERA_FOCUS>;
                };
 
-               volume-up {
+               key-volume-up {
                        label = "volume_up";
                        gpios = <&pm8941_gpios 5 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
 };
 
 &pm8941_gpios {
-       gpio_keys_pin_a: gpio-keys-active {
+       gpio_keys_pin_a: gpio-keys-active-state {
                pins = "gpio2", "gpio5";
                function = "normal";
 
                power-source = <PM8941_GPIO_S3>;
        };
 
-       bt_reg_on_pin: bt-reg-on {
+       bt_reg_on_pin: bt-reg-on-state {
                pins = "gpio16";
                function = "normal";
 
                power-source = <PM8941_GPIO_S3>;
        };
 
-       wlan_sleep_clk_pin: wl-sleep-clk {
+       wlan_sleep_clk_pin: wl-sleep-clk-state {
                pins = "gpio17";
                function = "func2";
 
                power-source = <PM8941_GPIO_S3>;
        };
 
-       wlan_regulator_pin: wl-reg-active {
+       wlan_regulator_pin: wl-reg-active-state {
                pins = "gpio18";
                function = "normal";
 
                power-source = <PM8941_GPIO_S3>;
        };
 
-       lcd_dcdc_en_pin_a: lcd-dcdc-en-active {
+       lcd_dcdc_en_pin_a: lcd-dcdc-en-active-state {
                pins = "gpio20";
                function = "normal";
 
 
 };
 
+&pm8941_lpg {
+       status = "okay";
+
+       qcom,power-source = <1>;
+
+       rgb-led {
+               color = <LED_COLOR_ID_RGB>;
+               function = LED_FUNCTION_STATUS;
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               led@5 {
+                       reg = <5>;
+                       color = <LED_COLOR_ID_BLUE>;
+               };
+
+               led@6 {
+                       reg = <6>;
+                       color = <LED_COLOR_ID_GREEN>;
+               };
+
+               led@7 {
+                       reg = <7>;
+                       color = <LED_COLOR_ID_RED>;
+               };
+       };
+};
+
 &rpm_requests {
        pm8941-regulators {
                compatible = "qcom,rpm-pm8941-regulators";
index 2caf71e..b5cdde0 100644 (file)
@@ -24,6 +24,7 @@
                        compatible = "qcom,spmi-temp-alarm";
                        reg = <0x2400>;
                        interrupts = <4 0x24 0 IRQ_TYPE_EDGE_RISING>;
+                       #thermal-sensor-cells = <0>;
                };
        };
 
index cdd2bdb..59d0cde 100644 (file)
@@ -68,7 +68,7 @@
                        interrupt-controller;
                        #interrupt-cells = <2>;
 
-                       boost_bypass_n_pin: boost-bypass {
+                       boost_bypass_n_pin: boost-bypass-state {
                                pins = "gpio21";
                                function = "normal";
                        };
                #address-cells = <1>;
                #size-cells = <0>;
 
+               pm8941_lpg: lpg {
+                       compatible = "qcom,pm8941-lpg";
+
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       #pwm-cells = <2>;
+
+                       status = "disabled";
+               };
+
                pm8941_wled: wled@d800 {
                        compatible = "qcom,pm8941-wled";
                        reg = <0xd800>;
index 6571b88..9de7578 100644 (file)
@@ -69,6 +69,7 @@
                        compatible = "qcom,pmx55-gpio", "qcom,spmi-gpio";
                        reg = <0xc000>;
                        gpio-controller;
+                       gpio-ranges = <&pmx55_gpios 0 0 11>;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
index 5411b83..abf229a 100644 (file)
                };
 
                pmx65_gpios: pinctrl@8800 {
-                       compatible = "qcom,pmx65-gpio";
+                       compatible = "qcom,pmx65-gpio", "qcom,spmi-gpio";
                        reg = <0x8800>;
                        gpio-controller;
+                       gpio-ranges = <&pmx65_gpios 0 0 16>;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
index 1c2b208..c725402 100644 (file)
                blsp1_uart3: serial@831000 {
                        compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
                        reg = <0x00831000 0x200>;
-                       interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_LOW>;
+                       interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&gcc 30>,
                                 <&gcc 9>;
                        clock-names = "core", "iface";
                        reg = <0x01fc0000 0x1000>;
                };
 
-               sdhc_1: sdhci@8804000 {
+               sdhc_1: mmc@8804000 {
                        compatible = "qcom,sdx55-sdhci", "qcom,sdhci-msm-v5";
                        reg = <0x08804000 0x1000>;
                        interrupts = <GIC_SPI 210 IRQ_TYPE_LEVEL_HIGH>,
                        #interrupt-cells = <2>;
                };
 
-               imem@1468f000 {
-                       compatible = "simple-mfd";
+               sram@1468f000 {
+                       compatible = "qcom,sdx55-imem", "syscon", "simple-mfd";
                        reg = <0x1468f000 0x1000>;
 
                        #address-cells = <1>;
index 79dc31a..85ea02d 100644 (file)
        };
 };
 
-&blsp1_uart3 {
-       status = "ok";
-};
-
 &apps_rsc {
        pmx65-rpmh-regulators {
                compatible = "qcom,pmx65-rpmh-regulators";
                        regulator-max-microvolt = <1300000>;
                };
 
-               ldo1 {
+               vreg_l1b_1p2: ldo1 {
                        regulator-min-microvolt = <1200000>;
                        regulator-max-microvolt = <1200000>;
                        regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
                        regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
                };
 
-               ldo4 {
+               vreg_l4b_0p88: ldo4 {
                        regulator-min-microvolt = <880000>;
                        regulator-max-microvolt = <912000>;
                        regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
                };
 
-               ldo5 {
+               vreg_l5b_1p8: ldo5 {
                        regulator-min-microvolt = <1800000>;
                        regulator-max-microvolt = <1800000>;
                        regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
                        regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
                };
 
-               ldo10 {
+               vreg_l10b_3p08: ldo10 {
                        regulator-min-microvolt = <3088000>;
                        regulator-max-microvolt = <3088000>;
                        regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
                };
        };
 };
+
+&blsp1_uart3 {
+       status = "okay";
+};
+
+&qpic_bam {
+       status = "okay";
+};
+
+&qpic_nand {
+       status = "okay";
+
+       nand@0 {
+               reg = <0>;
+
+               nand-ecc-strength = <4>;
+               nand-ecc-step-size = <512>;
+               nand-bus-width = <8>;
+               /* ico and efs2 partitions are secured */
+               secure-regions = /bits/ 64 <0x500000 0x500000
+                                           0xa00000 0xb00000>;
+       };
+};
+
+&remoteproc_mpss {
+       status = "okay";
+       memory-region = <&mpss_adsp_mem>;
+};
+
+&usb {
+       status = "okay";
+};
+
+&usb_dwc3 {
+       dr_mode = "peripheral";
+};
+
+&usb_hsphy {
+       status = "okay";
+       vdda-pll-supply = <&vreg_l4b_0p88>;
+       vdda33-supply = <&vreg_l10b_3p08>;
+       vdda18-supply = <&vreg_l5b_1p8>;
+};
+
+&usb_qmpphy {
+       status = "okay";
+       vdda-phy-supply = <&vreg_l4b_0p88>;
+       vdda-pll-supply = <&vreg_l1b_1p2>;
+};
index df6f9d6..8daefd5 100644 (file)
                        clock-output-names = "sleep_clk";
                        #clock-cells = <0>;
                };
+
+               nand_clk_dummy: nand-clk-dummy {
+                       compatible = "fixed-clock";
+                       clock-frequency = <32764>;
+                       #clock-cells = <0>;
+               };
        };
 
        cpus {
                        compatible = "arm,cortex-a7";
                        reg = <0x0>;
                        enable-method = "psci";
+                       clocks = <&apcs>;
+                       power-domains = <&rpmhpd SDX65_CX_AO>;
+                       power-domain-names = "rpmhpd";
+                       operating-points-v2 = <&cpu_opp_table>;
                };
        };
 
+       cpu_opp_table: cpu-opp-table {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp-345600000 {
+                       opp-hz = /bits/ 64 <345600000>;
+                       required-opps = <&rpmhpd_opp_low_svs>;
+               };
+
+               opp-576000000 {
+                       opp-hz = /bits/ 64 <576000000>;
+                       required-opps = <&rpmhpd_opp_svs>;
+               };
+
+               opp-1094400000 {
+                       opp-hz = /bits/ 64 <1094400000>;
+                       required-opps = <&rpmhpd_opp_nom>;
+               };
+
+               opp-1497600000 {
+                       opp-hz = /bits/ 64 <1497600000>;
+                       required-opps = <&rpmhpd_opp_turbo>;
+               };
+       };
+
+       firmware {
+               scm {
+                       compatible = "qcom,scm-sdx65", "qcom,scm";
+               };
+       };
+
+       mc_virt: interconnect-mc-virt {
+               compatible = "qcom,sdx65-mc-virt";
+               #interconnect-cells = <1>;
+               qcom,bcm-voters = <&apps_bcm_voter>;
+       };
+
        psci {
                compatible = "arm,psci-1.0";
                method = "smc";
                };
 
                smem_mem: memory@8fe20000 {
-                       no-map;
+                       compatible = "qcom,smem";
                        reg = <0x8fe20000 0xc0000>;
+                       hwlocks = <&tcsr_mutex 3>;
+                       no-map;
                };
 
                cmd_db: reserved-memory@8fee0000 {
                };
        };
 
+       smp2p-mpss {
+               compatible = "qcom,smp2p";
+               qcom,smem = <435>, <428>;
+               interrupts = <GIC_SPI 113 IRQ_TYPE_EDGE_RISING>;
+               mboxes = <&apcs 14>;
+               qcom,local-pid = <0>;
+               qcom,remote-pid = <1>;
+
+               modem_smp2p_out: master-kernel {
+                       qcom,entry-name = "master-kernel";
+                       #qcom,smem-state-cells = <1>;
+               };
+
+               modem_smp2p_in: slave-kernel {
+                       qcom,entry-name = "slave-kernel";
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               ipa_smp2p_out: ipa-ap-to-modem {
+                       qcom,entry-name = "ipa";
+                       #qcom,smem-state-cells = <1>;
+               };
+
+               ipa_smp2p_in: ipa-modem-to-ap {
+                       qcom,entry-name = "ipa";
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+       };
+
        soc: soc {
                #address-cells = <1>;
                #size-cells = <1>;
                        reg = <0x00100000 0x001f7400>;
                        clocks = <&rpmhcc RPMH_CXO_CLK>, <&rpmhcc RPMH_CXO_CLK_A>, <&sleep_clk>;
                        clock-names = "bi_tcxo", "bi_tcxo_ao", "sleep_clk";
+                       #power-domain-cells = <1>;
                        #clock-cells = <1>;
                        #reset-cells = <1>;
                };
                        status = "disabled";
                };
 
+               usb_hsphy: phy@ff4000 {
+                       compatible = "qcom,usb-snps-hs-7nm-phy";
+                       reg = <0xff4000 0x120>;
+                       #phy-cells = <0>;
+                       status = "disabled";
+                       clocks = <&rpmhcc RPMH_CXO_CLK>;
+                       clock-names = "ref";
+                       resets = <&gcc GCC_QUSB2PHY_BCR>;
+               };
+
+               usb_qmpphy: phy@ff6000 {
+                       compatible = "qcom,sdx65-qmp-usb3-uni-phy";
+                       reg = <0x00ff6000 0x1c8>;
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+
+                       clocks = <&gcc GCC_USB3_PHY_AUX_CLK>,
+                                <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
+                                <&gcc GCC_USB3_PRIM_CLKREF_EN>;
+                       clock-names = "aux", "cfg_ahb", "ref";
+
+                       resets = <&gcc GCC_USB3PHY_PHY_BCR>,
+                                <&gcc GCC_USB3_PHY_BCR>;
+                       reset-names = "phy", "common";
+
+                       usb_ssphy: phy@ff6200 {
+                               reg = <0x00ff6e00 0x160>,
+                                     <0x00ff7000 0x1ec>,
+                                     <0x00ff6200 0x1e00>;
+                               #phy-cells = <0>;
+                               #clock-cells = <0>;
+                               clocks = <&gcc GCC_USB3_PHY_PIPE_CLK>;
+                               clock-names = "pipe0";
+                               clock-output-names = "usb3_uni_phy_pipe_clk_src";
+                       };
+               };
+
+               system_noc: interconnect@1620000 {
+                       compatible = "qcom,sdx65-system-noc";
+                       reg = <0x01620000 0x31200>;
+                       #interconnect-cells = <1>;
+                       qcom,bcm-voters = <&apps_bcm_voter>;
+               };
+
+               qpic_bam: dma-controller@1b04000 {
+                       compatible = "qcom,bam-v1.7.0";
+                       reg = <0x01b04000 0x1c000>;
+                       interrupts = <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&rpmhcc RPMH_QPIC_CLK>;
+                       clock-names = "bam_clk";
+                       #dma-cells = <1>;
+                       qcom,ee = <0>;
+                       qcom,controlled-remotely;
+                       status = "disabled";
+               };
+
+               qpic_nand: nand-controller@1b30000 {
+                       compatible = "qcom,sdx55-nand";
+                       reg = <0x01b30000 0x10000>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       clocks = <&rpmhcc RPMH_QPIC_CLK>,
+                                <&nand_clk_dummy>;
+                       clock-names = "core", "aon";
+
+                       dmas = <&qpic_bam 0>,
+                              <&qpic_bam 1>,
+                              <&qpic_bam 2>;
+                       dma-names = "tx", "rx", "cmd";
+                       status = "disabled";
+               };
+
                tcsr_mutex: hwlock@1f40000 {
                        compatible = "qcom,tcsr-mutex";
                        reg = <0x01f40000 0x40000>;
                        #hwlock-cells = <1>;
                };
 
-               sdhc_1: sdhci@8804000 {
+               remoteproc_mpss: remoteproc@4080000 {
+                       compatible = "qcom,sdx55-mpss-pas";
+                       reg = <0x04080000 0x4040>;
+
+                       interrupts-extended = <&intc GIC_SPI 250 IRQ_TYPE_EDGE_RISING>,
+                                             <&modem_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
+                                             <&modem_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
+                                             <&modem_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
+                                             <&modem_smp2p_in 3 IRQ_TYPE_EDGE_RISING>,
+                                             <&modem_smp2p_in 7 IRQ_TYPE_EDGE_RISING>;
+                       interrupt-names = "wdog", "fatal", "ready", "handover",
+                                         "stop-ack", "shutdown-ack";
+
+                       clocks = <&rpmhcc RPMH_CXO_CLK>;
+                       clock-names = "xo";
+
+                       power-domains = <&rpmhpd SDX65_CX>,
+                                       <&rpmhpd SDX65_MSS>;
+                       power-domain-names = "cx", "mss";
+
+                       qcom,smem-states = <&modem_smp2p_out 0>;
+                       qcom,smem-state-names = "stop";
+
+                       status = "disabled";
+
+                       glink-edge {
+                               interrupts = <GIC_SPI 114 IRQ_TYPE_EDGE_RISING>;
+                               label = "mpss";
+                               qcom,remote-pid = <1>;
+                               mboxes = <&apcs 15>;
+                       };
+               };
+
+               sdhc_1: mmc@8804000 {
                        compatible = "qcom,sdx65-sdhci", "qcom,sdhci-msm-v5";
                        reg = <0x08804000 0x1000>;
                        reg-names = "hc_mem";
                        status = "disabled";
                };
 
+               mem_noc: interconnect@9680000 {
+                       compatible = "qcom,sdx65-mem-noc";
+                       reg = <0x09680000 0x27200>;
+                       #interconnect-cells = <1>;
+                       qcom,bcm-voters = <&apps_bcm_voter>;
+               };
+
+               usb: usb@a6f8800 {
+                       compatible = "qcom,sdx65-dwc3", "qcom,dwc3";
+                       reg = <0x0a6f8800 0x400>;
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+
+                       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";
+
+                       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>,
+                                             <&pdc 18 IRQ_TYPE_EDGE_BOTH>,
+                                             <&pdc 19 IRQ_TYPE_EDGE_BOTH>;
+                       interrupt-names = "hs_phy_irq",
+                                         "ss_phy_irq",
+                                         "dm_hs_phy_irq",
+                                         "dp_hs_phy_irq";
+
+                       power-domains = <&gcc USB30_GDSC>;
+
+                       resets = <&gcc GCC_USB30_BCR>;
+
+                       usb_dwc3: usb@a600000 {
+                               compatible = "snps,dwc3";
+                               reg = <0x0a600000 0xcd00>;
+                               interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
+                               iommus = <&apps_smmu 0x1a0 0x0>;
+                               snps,dis_u2_susphy_quirk;
+                               snps,dis_enblslpm_quirk;
+                               phys = <&usb_hsphy>, <&usb_ssphy>;
+                               phy-names = "usb2-phy", "usb3-phy";
+                       };
+               };
+
+               restart@c264000 {
+                       compatible = "qcom,pshold";
+                       reg = <0x0c264000 0x1000>;
+               };
+
                spmi_bus: qcom,spmi@c440000 {
                        compatible = "qcom,spmi-pmic-arb";
                        reg = <0xc440000 0xd00>,
                        interrupt-controller;
                };
 
+               imem@1468f000 {
+                       compatible = "simple-mfd";
+                       reg = <0x1468f000 0x1000>;
+                       ranges = <0x0 0x1468f000 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       pil-reloc@94c {
+                               compatible = "qcom,pil-reloc-info";
+                               reg = <0x94c 0xc8>;
+                       };
+               };
+
                apps_smmu: iommu@15000000 {
                        compatible = "qcom,sdx65-smmu-500", "arm,mmu-500";
                        reg = <0x15000000 0x40000>;
                        #clock-cells = <0>;
                };
 
+               watchdog@17817000 {
+                       compatible = "qcom,apss-wdt-sdx65", "qcom,kpss-wdt";
+                       reg = <0x17817000 0x1000>;
+                       clocks = <&sleep_clk>;
+               };
+
                timer@17820000 {
                        #address-cells = <1>;
                        #size-cells = <1>;
                                        };
                                };
                        };
+
+                       apps_bcm_voter: bcm-voter {
+                               compatible = "qcom,bcm-voter";
+                       };
+
                };
        };
 
index 9c0d968..69a5a44 100644 (file)
        leds {
                compatible = "gpio-leds";
 
-               red {
+               led-red {
                        gpios = <&pinctrl RZA2_PIN(PORT6, 0) GPIO_ACTIVE_HIGH>;
                };
-               green {
+               led-green {
                        gpios = <&pinctrl RZA2_PIN(PORTC, 1) GPIO_ACTIVE_HIGH>;
                };
        };
index 57cd2fa..5ad5349 100644 (file)
                                compatible = "dlg,da9063-rtc";
                        };
 
-                       wdt {
+                       watchdog {
                                compatible = "dlg,da9063-watchdog";
                        };
                };
index c802f9f..fe14727 100644 (file)
                        compatible = "dlg,da9063-rtc";
                };
 
-               wdt {
+               watchdog {
                        compatible = "dlg,da9063-watchdog";
                };
        };
index 6e691b6..26a4078 100644 (file)
                        compatible = "dlg,da9063-rtc";
                };
 
-               wdt {
+               watchdog {
                        compatible = "dlg,da9063-watchdog";
                };
        };
index 38e2ab9..ec0a20d 100644 (file)
                interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
                interrupt-controller;
 
-               wdt {
+               watchdog {
                        compatible = "dlg,da9063-watchdog";
                };
        };
index 62aa9f6..c66de9d 100644 (file)
                        compatible = "dlg,da9063-rtc";
                };
 
-               wdt {
+               watchdog {
                        compatible = "dlg,da9063-watchdog";
                };
        };
index c8978f4..79b537b 100644 (file)
                        compatible = "dlg,da9063-rtc";
                };
 
-               wdt {
+               watchdog {
                        compatible = "dlg,da9063-watchdog";
                };
        };
index 99d554f..4d93319 100644 (file)
                        compatible = "dlg,da9063-rtc";
                };
 
-               wdt {
+               watchdog {
                        compatible = "dlg,da9063-watchdog";
                };
        };
index 92a7616..b7af1be 100644 (file)
                        compatible = "dlg,da9063-rtc";
                };
 
-               wdt {
+               watchdog {
                        compatible = "dlg,da9063-watchdog";
                };
        };
diff --git a/arch/arm/boot/dts/r8a77xx-aa104xd12-panel.dtsi b/arch/arm/boot/dts/r8a77xx-aa104xd12-panel.dtsi
deleted file mode 100644 (file)
index 79fce67..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Common file for the AA104XD12 panel connected to Renesas R-Car boards
- *
- * Copyright (C) 2014 Renesas Electronics Corp.
- */
-
-/ {
-       panel {
-               compatible = "mitsubishi,aa104xd12", "panel-lvds";
-
-               width-mm = <210>;
-               height-mm = <158>;
-               data-mapping = "jeida-18";
-
-               panel-timing {
-                       /* 1024x768 @65Hz */
-                       clock-frequency = <65000000>;
-                       hactive = <1024>;
-                       vactive = <768>;
-                       hsync-len = <136>;
-                       hfront-porch = <20>;
-                       hback-porch = <160>;
-                       vfront-porch = <3>;
-                       vback-porch = <29>;
-                       vsync-len = <6>;
-               };
-
-               port {
-                       panel_in: endpoint {
-                               remote-endpoint = <&lvds_connector>;
-                       };
-               };
-       };
-};
-
-&lvds_connector {
-       remote-endpoint = <&panel_in>;
-};
index 3f8f3ce..4bf8133 100644 (file)
@@ -8,6 +8,9 @@
 
 /dts-v1/;
 
+#include <dt-bindings/pinctrl/rzn1-pinctrl.h>
+#include <dt-bindings/net/pcs-rzn1-miic.h>
+
 #include "r9a06g032.dtsi"
 
 / {
        };
 };
 
+&eth_miic {
+       status = "okay";
+       renesas,miic-switch-portin = <MIIC_GMAC2_PORT>;
+};
+
+&gmac2 {
+       status = "okay";
+       phy-mode = "gmii";
+
+       fixed-link {
+               speed = <1000>;
+               full-duplex;
+       };
+};
+
+&mii_conv4 {
+       renesas,miic-input = <MIIC_SWITCH_PORTB>;
+       status = "okay";
+};
+
+&mii_conv5 {
+       renesas,miic-input = <MIIC_SWITCH_PORTA>;
+       status = "okay";
+};
+
+&pinctrl{
+       pins_eth3: pins_eth3 {
+               pinmux = <RZN1_PINMUX(36, RZN1_FUNC_CLK_ETH_MII_RGMII_RMII)>,
+                        <RZN1_PINMUX(37, RZN1_FUNC_CLK_ETH_MII_RGMII_RMII)>,
+                        <RZN1_PINMUX(38, RZN1_FUNC_CLK_ETH_MII_RGMII_RMII)>,
+                        <RZN1_PINMUX(39, RZN1_FUNC_CLK_ETH_MII_RGMII_RMII)>,
+                        <RZN1_PINMUX(40, RZN1_FUNC_CLK_ETH_MII_RGMII_RMII)>,
+                        <RZN1_PINMUX(41, RZN1_FUNC_CLK_ETH_MII_RGMII_RMII)>,
+                        <RZN1_PINMUX(42, RZN1_FUNC_CLK_ETH_MII_RGMII_RMII)>,
+                        <RZN1_PINMUX(43, RZN1_FUNC_CLK_ETH_MII_RGMII_RMII)>,
+                        <RZN1_PINMUX(44, RZN1_FUNC_CLK_ETH_MII_RGMII_RMII)>,
+                        <RZN1_PINMUX(45, RZN1_FUNC_CLK_ETH_MII_RGMII_RMII)>,
+                        <RZN1_PINMUX(46, RZN1_FUNC_CLK_ETH_MII_RGMII_RMII)>,
+                        <RZN1_PINMUX(47, RZN1_FUNC_CLK_ETH_MII_RGMII_RMII)>;
+               drive-strength = <6>;
+               bias-disable;
+       };
+
+       pins_eth4: pins_eth4 {
+               pinmux = <RZN1_PINMUX(48, RZN1_FUNC_CLK_ETH_MII_RGMII_RMII)>,
+                        <RZN1_PINMUX(49, RZN1_FUNC_CLK_ETH_MII_RGMII_RMII)>,
+                        <RZN1_PINMUX(50, RZN1_FUNC_CLK_ETH_MII_RGMII_RMII)>,
+                        <RZN1_PINMUX(51, RZN1_FUNC_CLK_ETH_MII_RGMII_RMII)>,
+                        <RZN1_PINMUX(52, RZN1_FUNC_CLK_ETH_MII_RGMII_RMII)>,
+                        <RZN1_PINMUX(53, RZN1_FUNC_CLK_ETH_MII_RGMII_RMII)>,
+                        <RZN1_PINMUX(54, RZN1_FUNC_CLK_ETH_MII_RGMII_RMII)>,
+                        <RZN1_PINMUX(55, RZN1_FUNC_CLK_ETH_MII_RGMII_RMII)>,
+                        <RZN1_PINMUX(56, RZN1_FUNC_CLK_ETH_MII_RGMII_RMII)>,
+                        <RZN1_PINMUX(57, RZN1_FUNC_CLK_ETH_MII_RGMII_RMII)>,
+                        <RZN1_PINMUX(58, RZN1_FUNC_CLK_ETH_MII_RGMII_RMII)>,
+                        <RZN1_PINMUX(59, RZN1_FUNC_CLK_ETH_MII_RGMII_RMII)>;
+               drive-strength = <6>;
+               bias-disable;
+       };
+
+       pins_mdio1: pins_mdio1 {
+               pinmux = <RZN1_PINMUX(152, RZN1_FUNC_MDIO1_SWITCH)>,
+                        <RZN1_PINMUX(153, RZN1_FUNC_MDIO1_SWITCH)>;
+       };
+};
+
+&rtc0 {
+       status = "okay";
+};
+
+&switch {
+       status = "okay";
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&pins_eth3>, <&pins_eth4>, <&pins_mdio1>;
+
+       dsa,member = <0 0>;
+
+       mdio {
+               clock-frequency = <2500000>;
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               switch0phy4: ethernet-phy@4 {
+                       reg = <4>;
+                       micrel,led-mode = <1>;
+               };
+
+               switch0phy5: ethernet-phy@5 {
+                       reg = <5>;
+                       micrel,led-mode = <1>;
+               };
+       };
+};
+
+&switch_port0 {
+       label = "lan0";
+       phy-mode = "mii";
+       phy-handle = <&switch0phy5>;
+       status = "okay";
+};
+
+&switch_port1 {
+       label = "lan1";
+       phy-mode = "mii";
+       phy-handle = <&switch0phy4>;
+       status = "okay";
+};
+
+&switch_port4 {
+       status = "okay";
+};
+
 &uart0 {
        status = "okay";
 };
index d366591..5b97fa8 100644 (file)
                        data-width = <8>;
                };
 
+               gmac2: ethernet@44002000 {
+                       compatible = "renesas,r9a06g032-gmac", "renesas,rzn1-gmac", "snps,dwmac";
+                       reg = <0x44002000 0x2000>;
+                       interrupt-parent = <&gic>;
+                       interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "macirq", "eth_wake_irq", "eth_lpi";
+                       clocks = <&sysctrl R9A06G032_HCLK_GMAC1>;
+                       clock-names = "stmmaceth";
+                       power-domains = <&sysctrl>;
+                       snps,multicast-filter-bins = <256>;
+                       snps,perfect-filter-entries = <128>;
+                       tx-fifo-depth = <2048>;
+                       rx-fifo-depth = <4096>;
+                       status = "disabled";
+               };
+
+               eth_miic: eth-miic@44030000 {
+                       compatible = "renesas,r9a06g032-miic", "renesas,rzn1-miic";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x44030000 0x10000>;
+                       clocks = <&sysctrl R9A06G032_CLK_MII_REF>,
+                                <&sysctrl R9A06G032_CLK_RGMII_REF>,
+                                <&sysctrl R9A06G032_CLK_RMII_REF>,
+                                <&sysctrl R9A06G032_HCLK_SWITCH_RG>;
+                       clock-names = "mii_ref", "rgmii_ref", "rmii_ref", "hclk";
+                       power-domains = <&sysctrl>;
+                       status = "disabled";
+
+                       mii_conv1: mii-conv@1 {
+                               reg = <1>;
+                               status = "disabled";
+                       };
+
+                       mii_conv2: mii-conv@2 {
+                               reg = <2>;
+                               status = "disabled";
+                       };
+
+                       mii_conv3: mii-conv@3 {
+                               reg = <3>;
+                               status = "disabled";
+                       };
+
+                       mii_conv4: mii-conv@4 {
+                               reg = <4>;
+                               status = "disabled";
+                       };
+
+                       mii_conv5: mii-conv@5 {
+                               reg = <5>;
+                               status = "disabled";
+                       };
+               };
+
+               switch: switch@44050000 {
+                       compatible = "renesas,r9a06g032-a5psw", "renesas,rzn1-a5psw";
+                       reg = <0x44050000 0x10000>;
+                       clocks = <&sysctrl R9A06G032_HCLK_SWITCH>,
+                                <&sysctrl R9A06G032_CLK_SWITCH>;
+                       clock-names = "hclk", "clk";
+                       power-domains = <&sysctrl>;
+                       status = "disabled";
+
+                       ethernet-ports {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               switch_port0: port@0 {
+                                       reg = <0>;
+                                       pcs-handle = <&mii_conv5>;
+                                       status = "disabled";
+                               };
+
+                               switch_port1: port@1 {
+                                       reg = <1>;
+                                       pcs-handle = <&mii_conv4>;
+                                       status = "disabled";
+                               };
+
+                               switch_port2: port@2 {
+                                       reg = <2>;
+                                       pcs-handle = <&mii_conv3>;
+                                       status = "disabled";
+                               };
+
+                               switch_port3: port@3 {
+                                       reg = <3>;
+                                       pcs-handle = <&mii_conv2>;
+                                       status = "disabled";
+                               };
+
+                               switch_port4: port@4 {
+                                       reg = <4>;
+                                       ethernet = <&gmac2>;
+                                       label = "cpu";
+                                       phy-mode = "internal";
+                                       status = "disabled";
+                                       fixed-link {
+                                               speed = <1000>;
+                                               full-duplex;
+                                       };
+                               };
+                       };
+               };
+
                gic: interrupt-controller@44101000 {
                        compatible = "arm,gic-400", "arm,cortex-a7-gic";
                        interrupt-controller;
index 390aa33..962b4d1 100644 (file)
@@ -48,7 +48,7 @@
                compatible = "gpio-keys";
                autorepeat;
 
-               power {
+               key-power {
                        gpios = <&gpio6 RK_PA2 GPIO_ACTIVE_LOW>; /* GPIO6_A2 */
                        linux,code = <KEY_POWER>;
                        label = "GPIO Key Power";
@@ -56,7 +56,7 @@
                        wakeup-source;
                        debounce-interval = <100>;
                };
-               volume-down {
+               key-volume-down {
                        gpios = <&gpio4 RK_PC5 GPIO_ACTIVE_LOW>; /* GPIO4_C5 */
                        linux,code = <KEY_VOLUMEDOWN>;
                        label = "GPIO Key Vol-";
index 667d57a..cfa318a 100644 (file)
        status = "okay";
 };
 
+&nfc {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       status = "okay";
+
+       nand@0 {
+               reg = <0>;
+               label = "rk-nand";
+               nand-bus-width = <8>;
+               nand-ecc-mode = "hw";
+               nand-ecc-step-size = <1024>;
+               nand-ecc-strength = <40>;
+               nand-is-boot-medium;
+               rockchip,boot-blks = <8>;
+               rockchip,boot-ecc-strength = <24>;
+       };
+};
+
 &pinctrl {
        usb-host {
                host_drv: host-drv {
index 12b2e59..dbbc517 100644 (file)
@@ -32,7 +32,7 @@
        keys: gpio-keys {
                compatible = "gpio-keys";
 
-               power {
+               key-power {
                        wakeup-source;
                        gpios = <&gpio6 RK_PA2 GPIO_ACTIVE_LOW>;
                        label = "GPIO Power";
index 35b7a57..9312be3 100644 (file)
@@ -37,7 +37,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&pwr_key &usb_int>;
 
-               power {
+               key-power {
                        gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
                        label = "GPIO Key Power";
@@ -46,7 +46,7 @@
                        wakeup-source;
                };
 
-               wake_on_usb: wake-on-usb {
+               wake_on_usb: key-wake-on-usb {
                        label = "Wake-on-USB";
                        gpios = <&gpio0 RK_PA7 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_WAKEUP>;
index fc478ac..0a1ae68 100644 (file)
@@ -29,7 +29,7 @@
                compatible = "gpio-keys";
                autorepeat;
 
-               power {
+               key-power {
                        gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
                        label = "GPIO Key Power";
index 36c0945..a9ed3cd 100644 (file)
@@ -24,7 +24,7 @@
                compatible = "gpio-keys";
                autorepeat;
 
-               power {
+               key-power {
                        gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
                        label = "GPIO Key Power";
index 797476e..5c3d08e 100644 (file)
                regulator-boot-on;
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
                autorepeat;
                pinctrl-names = "default";
index c4ca73b..399d6b9 100644 (file)
                pinctrl-names = "default";
                pinctrl-0 = <&pwrbtn>;
 
-               power {
+               key-power {
                        gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
                        label = "GPIO Key Power";
index 9a4a974..a5a0826 100644 (file)
@@ -27,7 +27,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               power {
+               key-power {
                        wakeup-source;
                        gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>;
                        label = "GPIO Power";
index 7fb5823..052afe5 100644 (file)
@@ -49,7 +49,7 @@
        keys: gpio-keys {
                compatible = "gpio-keys";
 
-               power {
+               key-power {
                        wakeup-source;
                        gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>;
                        label = "GPIO Power";
index 1e33859..1a51569 100644 (file)
                pinctrl-names = "default";
                pinctrl-0 = <&user_button_pins>;
 
-               button@0 {
+               button-0 {
                        label = "home";
                        linux,code = <KEY_HOME>;
                        gpios = <&gpio8 0 GPIO_ACTIVE_HIGH>;
                        wakeup-source;
                };
 
-               button@1 {
+               button-1 {
                        label = "menu";
                        linux,code = <KEY_MENU>;
                        gpios = <&gpio8 3 GPIO_ACTIVE_HIGH>;
index 8c7376d..fd90f3b 100644 (file)
@@ -30,7 +30,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&pwrbtn>;
 
-               power {
+               key-power {
                        gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
                        label = "GPIO Key Power";
index 55467bc..633e5a0 100644 (file)
@@ -31,7 +31,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&pwrbtn>;
 
-               power {
+               key-power {
                        gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
                        label = "GPIO Key Power";
index c4d1d14..80e0f07 100644 (file)
@@ -28,7 +28,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               power {
+               key-power {
                        gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>;
                        label = "GPIO Power";
                        linux,code = <KEY_POWER>;
index 9c1e38c..09618bb 100644 (file)
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
                autorepeat;
 
                pinctrl-names = "default";
                pinctrl-0 = <&pwrbtn>;
 
-               button@0 {
+               button {
                        gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
                        label = "GPIO Key Power";
index a10d25a..f9dde0e 100644 (file)
                            <&bt_dev_wake>;
 
                compatible = "brcm,bcm43540-bt";
-               host-wakeup-gpios       = <&gpio4 RK_PD7 GPIO_ACTIVE_HIGH>;
-               shutdown-gpios          = <&gpio4 RK_PD5 GPIO_ACTIVE_HIGH>;
-               device-wakeup-gpios     = <&gpio4 RK_PD2 GPIO_ACTIVE_HIGH>;
-               max-speed               = <3000000>;
-               brcm,bt-pcm-int-params  = [01 02 00 01 01];
+               host-wakeup-gpios = <&gpio4 RK_PD7 GPIO_ACTIVE_HIGH>;
+               shutdown-gpios = <&gpio4 RK_PD5 GPIO_ACTIVE_HIGH>;
+               device-wakeup-gpios = <&gpio4 RK_PD2 GPIO_ACTIVE_HIGH>;
+               max-speed = <3000000>;
+               brcm,bt-pcm-int-params = [01 02 00 01 01];
        };
 };
index 05112c2..700bb54 100644 (file)
@@ -32,7 +32,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&ap_lid_int_l>;
 
-               lid {
+               switch-lid {
                        label = "Lid";
                        gpios = <&gpio0 RK_PA6 GPIO_ACTIVE_LOW>;
                        wakeup-source;
index 82fc6fb..dcdcc55 100644 (file)
                pinctrl-names = "default";
                pinctrl-0 = <&volum_down_l &volum_up_l>;
 
-               volum_down {
+               key-volum-down {
                        label = "Volum_down";
                        gpios = <&gpio5 RK_PB3 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEDOWN>;
                        debounce-interval = <100>;
                };
 
-               volum_up {
+               key-volum-up {
                        label = "Volum_up";
                        gpios = <&gpio5 RK_PB2 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
index 4e9fdb0..e2a4e62 100644 (file)
@@ -45,7 +45,7 @@
 &lid_switch {
        pinctrl-0 = <&pwr_key_h &ap_lid_int_l>;
 
-       power {
+       key-power {
                gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_HIGH>;
        };
 };
index 54a6838..e406c8c 100644 (file)
@@ -29,7 +29,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&pwr_key_l>;
 
-               power {
+               key-power {
                        label = "Power";
                        gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
index 0c99a59..2d99943 100644 (file)
@@ -83,7 +83,7 @@
 
                regulators {
                        vdd_core: DCDC_REG1 {
-                               regulator-name= "vdd_core";
+                               regulator-name = "vdd_core";
                                regulator-min-microvolt = <700000>;
                                regulator-max-microvolt = <1500000>;
                                regulator-always-on;
@@ -95,7 +95,7 @@
                        };
 
                        vdd_buck2: DCDC_REG2 {
-                               regulator-name= "vdd_buck2";
+                               regulator-name = "vdd_buck2";
                                regulator-min-microvolt = <2200000>;
                                regulator-max-microvolt = <2200000>;
                                regulator-always-on;
                        };
 
                        vcc_ddr: DCDC_REG3 {
-                               regulator-name= "vcc_ddr";
+                               regulator-name = "vcc_ddr";
                                regulator-always-on;
                                regulator-boot-on;
                                regulator-state-mem {
                        };
 
                        vcc_io: DCDC_REG4 {
-                               regulator-name= "vcc_io";
+                               regulator-name = "vcc_io";
                                regulator-min-microvolt = <3300000>;
                                regulator-max-microvolt = <3300000>;
                                regulator-always-on;
                        };
 
                        vdd_10: LDO_REG1 {
-                               regulator-name= "vdd_10";
+                               regulator-name = "vdd_10";
                                regulator-min-microvolt = <1000000>;
                                regulator-max-microvolt = <1000000>;
                                regulator-always-on;
                        };
 
                        vcc_18: LDO_REG2 {
-                               regulator-name= "vcc_18";
+                               regulator-name = "vcc_18";
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <1800000>;
                                regulator-always-on;
                        };
 
                        vdd10_pmu: LDO_REG3 {
-                               regulator-name= "vdd10_pmu";
+                               regulator-name = "vdd10_pmu";
                                regulator-min-microvolt = <1000000>;
                                regulator-max-microvolt = <1000000>;
                                regulator-always-on;
index 46cad7c..ef150f4 100644 (file)
@@ -96,7 +96,7 @@
 
                regulators {
                        vdd_core: DCDC_REG1 {
-                               regulator-name= "vdd_core";
+                               regulator-name = "vdd_core";
                                regulator-min-microvolt = <700000>;
                                regulator-max-microvolt = <1500000>;
                                regulator-always-on;
                        };
 
                        vdd_cam: DCDC_REG2 {
-                               regulator-name= "vdd_cam";
+                               regulator-name = "vdd_cam";
                                regulator-min-microvolt = <700000>;
                                regulator-max-microvolt = <2000000>;
                                regulator-state-mem {
                        };
 
                        vcc_ddr: DCDC_REG3 {
-                               regulator-name= "vcc_ddr";
+                               regulator-name = "vcc_ddr";
                                regulator-always-on;
                                regulator-boot-on;
                                regulator-state-mem {
                        };
 
                        vcc_io: DCDC_REG4 {
-                               regulator-name= "vcc_io";
+                               regulator-name = "vcc_io";
                                regulator-min-microvolt = <3300000>;
                                regulator-max-microvolt = <3300000>;
                                regulator-always-on;
                        };
 
                        vdd_10: LDO_REG1 {
-                               regulator-name= "vdd_10";
+                               regulator-name = "vdd_10";
                                regulator-min-microvolt = <1000000>;
                                regulator-max-microvolt = <1000000>;
                                regulator-always-on;
                        };
 
                        vcc_18: LDO_REG2 {
-                               regulator-name= "vcc_18";
+                               regulator-name = "vcc_18";
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <1800000>;
                                regulator-always-on;
                        };
 
                        vdd10_pmu: LDO_REG3 {
-                               regulator-name= "vdd10_pmu";
+                               regulator-name = "vdd10_pmu";
                                regulator-min-microvolt = <1000000>;
                                regulator-max-microvolt = <1000000>;
                                regulator-always-on;
index c158a7e..abf3006 100644 (file)
 
                gmac {
                        rmii_pins: rmii-pins {
-                               rockchip,pins = <1 RK_PC5 2 &pcfg_pull_none>,
+                               rockchip,pins = <1 RK_PC5 2 &pcfg_pull_none>,
                                                <1 RK_PC3 2 &pcfg_pull_none>,
                                                <1 RK_PC4 2 &pcfg_pull_none>,
                                                <1 RK_PB2 3 &pcfg_pull_none_drv_12ma>,
diff --git a/arch/arm/boot/dts/s3c2410-pinctrl.h b/arch/arm/boot/dts/s3c2410-pinctrl.h
new file mode 100644 (file)
index 0000000..76b6171
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Samsung S3C2410 DTS pinctrl constants
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ * Copyright (c) 2022 Linaro Ltd
+ * Author: Krzysztof Kozlowski <krzk@kernel.org>
+ */
+
+#ifndef __DTS_ARM_SAMSUNG_S3C2410_PINCTRL_H__
+#define __DTS_ARM_SAMSUNG_S3C2410_PINCTRL_H__
+
+#define S3C2410_PIN_FUNC_INPUT         0
+#define S3C2410_PIN_FUNC_OUTPUT                1
+#define S3C2410_PIN_FUNC_2             2
+#define S3C2410_PIN_FUNC_3             3
+
+#endif /* __DTS_ARM_SAMSUNG_S3C2410_PINCTRL_H__ */
index 20a7d72..3268366 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de>
  */
 
-#include <dt-bindings/pinctrl/samsung.h>
+#include "s3c2410-pinctrl.h"
 
 &pinctrl_0 {
        /*
 
        uart0_data: uart0-data-pins {
                samsung,pins = "gph-0", "gph-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C2410_PIN_FUNC_2>;
        };
 
        uart0_fctl: uart0-fctl-pins {
                samsung,pins = "gph-8", "gph-9";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C2410_PIN_FUNC_2>;
        };
 
        uart1_data: uart1-data-pins {
                samsung,pins = "gph-2", "gph-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C2410_PIN_FUNC_2>;
        };
 
        uart1_fctl: uart1-fctl-pins {
                samsung,pins = "gph-10", "gph-11";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C2410_PIN_FUNC_2>;
        };
 
        uart2_data: uart2-data-pins {
                samsung,pins = "gph-4", "gph-5";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C2410_PIN_FUNC_2>;
        };
 
        uart2_fctl: uart2-fctl-pins {
                samsung,pins = "gph-6", "gph-7";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C2410_PIN_FUNC_2>;
        };
 
        uart3_data: uart3-data-pins {
                samsung,pins = "gph-6", "gph-7";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C2410_PIN_FUNC_2>;
        };
 
        extuart_clk: extuart-clk-pins {
                samsung,pins = "gph-12";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C2410_PIN_FUNC_2>;
        };
 
        i2c0_bus: i2c0-bus-pins {
                samsung,pins = "gpe-14", "gpe-15";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C2410_PIN_FUNC_2>;
        };
 
        spi0_bus: spi0-bus-pins {
                samsung,pins = "gpe-11", "gpe-12", "gpe-13";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C2410_PIN_FUNC_2>;
        };
 
        sd0_clk: sd0-clk-pins {
                samsung,pins = "gpe-5";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C2410_PIN_FUNC_2>;
        };
 
        sd0_cmd: sd0-cmd-pins {
                samsung,pins = "gpe-6";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C2410_PIN_FUNC_2>;
        };
 
        sd0_bus1: sd0-bus1-pins {
                samsung,pins = "gpe-7";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C2410_PIN_FUNC_2>;
        };
 
        sd0_bus4: sd0-bus4-pins {
                samsung,pins = "gpe-8", "gpe-9", "gpe-10";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C2410_PIN_FUNC_2>;
        };
 
        sd1_cmd: sd1-cmd-pins {
                samsung,pins = "gpl-8";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C2410_PIN_FUNC_2>;
        };
 
        sd1_clk: sd1-clk-pins {
                samsung,pins = "gpl-9";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C2410_PIN_FUNC_2>;
        };
 
        sd1_bus1: sd1-bus1-pins {
                samsung,pins = "gpl-0";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C2410_PIN_FUNC_2>;
        };
 
        sd1_bus4: sd1-bus4-pins {
                samsung,pins = "gpl-1", "gpl-2", "gpl-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C2410_PIN_FUNC_2>;
        };
 };
index 4f084f4..4660751 100644 (file)
@@ -45,7 +45,7 @@
                status = "disabled";
        };
 
-       sdhci_1: sdhci@4ac00000 {
+       sdhci_1: mmc@4ac00000 {
                compatible = "samsung,s3c6410-sdhci";
                reg = <0x4AC00000 0x100>;
                interrupts = <0 0 21 3>;
@@ -56,7 +56,7 @@
                status = "disabled";
        };
 
-       sdhci_0: sdhci@4a800000 {
+       sdhci_0: mmc@4a800000 {
                compatible = "samsung,s3c6410-sdhci";
                reg = <0x4A800000 0x100>;
                interrupts = <0 0 20 3>;
index 0a3186d..f53959b 100644 (file)
@@ -9,7 +9,7 @@
  * listed as device tree nodes in this file.
  */
 
-#include <dt-bindings/pinctrl/samsung.h>
+#include "s3c64xx-pinctrl.h"
 
 &pinctrl0 {
        /*
 
        uart0_data: uart0-data-pins {
                samsung,pins = "gpa-0", "gpa-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        uart0_fctl: uart0-fctl-pins {
                samsung,pins = "gpa-2", "gpa-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        uart1_data: uart1-data-pins {
                samsung,pins = "gpa-4", "gpa-5";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        uart1_fctl: uart1-fctl-pins {
                samsung,pins = "gpa-6", "gpa-7";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        uart2_data: uart2-data-pins {
                samsung,pins = "gpb-0", "gpb-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        uart3_data: uart3-data-pins {
                samsung,pins = "gpb-2", "gpb-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        ext_dma_0: ext-dma-0-pins {
                samsung,pins = "gpb-0", "gpb-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        ext_dma_1: ext-dma-1-pins {
                samsung,pins = "gpb-2", "gpb-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_4>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        irda_data_0: irda-data-0-pins {
                samsung,pins = "gpb-0", "gpb-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_4>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        irda_data_1: irda-data-1-pins {
                samsung,pins = "gpb-2", "gpb-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        irda_sdbw: irda-sdbw-pins {
                samsung,pins = "gpb-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        i2c0_bus: i2c0-bus-pins {
                samsung,pins = "gpb-5", "gpb-6";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
        };
 
        i2c1_bus: i2c1-bus-pins {
                /* S3C6410-only */
                samsung,pins = "gpb-2", "gpb-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_6>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_6>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
        };
 
        spi0_bus: spi0-bus-pins {
                samsung,pins = "gpc-0", "gpc-1", "gpc-2";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
        };
 
        spi0_cs: spi0-cs-pins {
                samsung,pins = "gpc-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        spi1_bus: spi1-bus-pins {
                samsung,pins = "gpc-4", "gpc-5", "gpc-6";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
        };
 
        spi1_cs: spi1-cs-pins {
                samsung,pins = "gpc-7";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        sd0_cmd: sd0-cmd-pins {
                samsung,pins = "gpg-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        sd0_clk: sd0-clk-pins {
                samsung,pins = "gpg-0";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        sd0_bus1: sd0-bus1-pins {
                samsung,pins = "gpg-2";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        sd0_bus4: sd0-bus4-pins {
                samsung,pins = "gpg-2", "gpg-3", "gpg-4", "gpg-5";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        sd0_cd: sd0-cd-pins {
                samsung,pins = "gpg-6";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
        };
 
        sd1_cmd: sd1-cmd-pins {
                samsung,pins = "gph-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        sd1_clk: sd1-clk-pins {
                samsung,pins = "gph-0";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        sd1_bus1: sd1-bus1-pins {
                samsung,pins = "gph-2";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        sd1_bus4: sd1-bus4-pins {
                samsung,pins = "gph-2", "gph-3", "gph-4", "gph-5";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        sd1_bus8: sd1-bus8-pins {
                samsung,pins = "gph-2", "gph-3", "gph-4", "gph-5",
                                "gph-6", "gph-7", "gph-8", "gph-9";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        sd1_cd: sd1-cd-pins {
                samsung,pins = "gpg-6";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
        };
 
        sd2_cmd: sd2-cmd-pins {
                samsung,pins = "gpc-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        sd2_clk: sd2-clk-pins {
                samsung,pins = "gpc-5";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        sd2_bus1: sd2-bus1-pins {
                samsung,pins = "gph-6";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        sd2_bus4: sd2-bus4-pins {
                samsung,pins = "gph-6", "gph-7", "gph-8", "gph-9";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        i2s0_bus: i2s0-bus-pins {
                samsung,pins = "gpd-0", "gpd-2", "gpd-3", "gpd-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        i2s0_cdclk: i2s0-cdclk-pins {
                samsung,pins = "gpd-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        i2s1_bus: i2s1-bus-pins {
                samsung,pins = "gpe-0", "gpe-2", "gpe-3", "gpe-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        i2s1_cdclk: i2s1-cdclk-pins {
                samsung,pins = "gpe-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
                /* S3C6410-only */
                samsung,pins = "gpc-4", "gpc-5", "gpc-6", "gph-6",
                                "gph-8", "gph-9";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_5>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_5>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        i2s2_cdclk: i2s2-cdclk-pins {
                /* S3C6410-only */
                samsung,pins = "gph-7";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_5>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_5>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        pcm0_bus: pcm0-bus-pins {
                samsung,pins = "gpd-0", "gpd-2", "gpd-3", "gpd-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        pcm0_extclk: pcm0-extclk-pins {
                samsung,pins = "gpd-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        pcm1_bus: pcm1-bus-pins {
                samsung,pins = "gpe-0", "gpe-2", "gpe-3", "gpe-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        pcm1_extclk: pcm1-extclk-pins {
                samsung,pins = "gpe-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        ac97_bus_0: ac97-bus-0-pins {
                samsung,pins = "gpd-0", "gpd-1", "gpd-2", "gpd-3", "gpd-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_4>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        ac97_bus_1: ac97-bus-1-pins {
                samsung,pins = "gpe-0", "gpe-1", "gpe-2", "gpe-3", "gpe-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_4>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
                samsung,pins = "gpf-0", "gpf-1", "gpf-2", "gpf-4",
                                "gpf-5", "gpf-6", "gpf-7", "gpf-8",
                                "gpf-9", "gpf-10", "gpf-11", "gpf-12";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        cam_rst: cam-rst-pins {
                samsung,pins = "gpf-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        cam_field: cam-field-pins {
                /* S3C6410-only */
                samsung,pins = "gpb-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        pwm_extclk: pwm-extclk-pins {
                samsung,pins = "gpf-13";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        pwm0_out: pwm0-out-pins {
                samsung,pins = "gpf-14";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        pwm1_out: pwm1-out-pins {
                samsung,pins = "gpf-15";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        clkout0: clkout-0-pins {
                samsung,pins = "gpf-14";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_col0_0: keypad-col0-0-pins {
                samsung,pins = "gph-0";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_4>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_col1_0: keypad-col1-0-pins {
                samsung,pins = "gph-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_4>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_col2_0: keypad-col2-0-pins {
                samsung,pins = "gph-2";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_4>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_col3_0: keypad-col3-0-pins {
                samsung,pins = "gph-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_4>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_col4_0: keypad-col4-0-pins {
                samsung,pins = "gph-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_4>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_col5_0: keypad-col5-0-pins {
                samsung,pins = "gph-5";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_4>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_col6_0: keypad-col6-0-pins {
                samsung,pins = "gph-6";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_4>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_col7_0: keypad-col7-0-pins {
                samsung,pins = "gph-7";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_4>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_col0_1: keypad-col0-1-pins {
                samsung,pins = "gpl-0";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_col1_1: keypad-col1-1-pins {
                samsung,pins = "gpl-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_col2_1: keypad-col2-1-pins {
                samsung,pins = "gpl-2";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_col3_1: keypad-col3-1-pins {
                samsung,pins = "gpl-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_col4_1: keypad-col4-1-pins {
                samsung,pins = "gpl-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_col5_1: keypad-col5-1-pins {
                samsung,pins = "gpl-5";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_col6_1: keypad-col6-1-pins {
                samsung,pins = "gpl-6";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_col7_1: keypad-col7-1-pins {
                samsung,pins = "gpl-7";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_row0_0: keypad-row0-0-pins {
                samsung,pins = "gpk-8";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_row1_0: keypad-row1-0-pins {
                samsung,pins = "gpk-9";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_row2_0: keypad-row2-0-pins {
                samsung,pins = "gpk-10";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_row3_0: keypad-row3-0-pins {
                samsung,pins = "gpk-11";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_row4_0: keypad-row4-0-pins {
                samsung,pins = "gpk-12";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_row5_0: keypad-row5-0-pins {
                samsung,pins = "gpk-13";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_row6_0: keypad-row6-0-pins {
                samsung,pins = "gpk-14";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_row7_0: keypad-row7-0-pins {
                samsung,pins = "gpk-15";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_row0_1: keypad-row0-1-pins {
                samsung,pins = "gpn-0";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_row1_1: keypad-row1-1-pins {
                samsung,pins = "gpn-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_row2_1: keypad-row2-1-pins {
                samsung,pins = "gpn-2";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_row3_1: keypad-row3-1-pins {
                samsung,pins = "gpn-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_row4_1: keypad-row4-1-pins {
                samsung,pins = "gpn-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_row5_1: keypad-row5-1-pins {
                samsung,pins = "gpn-5";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_row6_1: keypad-row6-1-pins {
                samsung,pins = "gpn-6";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        keypad_row7_1: keypad-row7-1-pins {
                samsung,pins = "gpn-7";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        lcd_ctrl: lcd-ctrl-pins {
                samsung,pins = "gpj-8", "gpj-9", "gpj-10", "gpj-11";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
                                "gpi-7", "gpi-10", "gpi-11", "gpi-12",
                                "gpi-13", "gpi-14", "gpi-15", "gpj-3",
                                "gpj-4", "gpj-5", "gpj-6", "gpj-7";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
                                "gpi-12", "gpi-13", "gpi-14", "gpi-15",
                                "gpj-2", "gpj-3", "gpj-4", "gpj-5",
                                "gpj-6", "gpj-7";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
                                "gpi-12", "gpi-13", "gpi-14", "gpi-15",
                                "gpj-0", "gpj-1", "gpj-2", "gpj-3",
                                "gpj-4", "gpj-5", "gpj-6", "gpj-7";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_2>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 
        hsi_bus: hsi-bus-pins {
                samsung,pins = "gpk-0", "gpk-1", "gpk-2", "gpk-3",
                                "gpk-4", "gpk-5", "gpk-6", "gpk-7";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+               samsung,pin-function = <S3C64XX_PIN_FUNC_3>;
                samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
        };
 };
diff --git a/arch/arm/boot/dts/s3c64xx-pinctrl.h b/arch/arm/boot/dts/s3c64xx-pinctrl.h
new file mode 100644 (file)
index 0000000..645c591
--- /dev/null
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Samsung S3C64xx DTS pinctrl constants
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ * Copyright (c) 2022 Linaro Ltd
+ * Author: Krzysztof Kozlowski <krzk@kernel.org>
+ */
+
+#ifndef __DTS_ARM_SAMSUNG_S3C64XX_PINCTRL_H__
+#define __DTS_ARM_SAMSUNG_S3C64XX_PINCTRL_H__
+
+#define S3C64XX_PIN_PULL_NONE          0
+#define S3C64XX_PIN_PULL_DOWN          1
+#define S3C64XX_PIN_PULL_UP            2
+
+#define S3C64XX_PIN_FUNC_INPUT         0
+#define S3C64XX_PIN_FUNC_OUTPUT                1
+#define S3C64XX_PIN_FUNC_2             2
+#define S3C64XX_PIN_FUNC_3             3
+#define S3C64XX_PIN_FUNC_4             4
+#define S3C64XX_PIN_FUNC_5             5
+#define S3C64XX_PIN_FUNC_6             6
+#define S3C64XX_PIN_FUNC_EINT          7
+
+#endif /* __DTS_ARM_SAMSUNG_S3C64XX_PINCTRL_H__ */
index 67a7a66..c03df63 100644 (file)
@@ -59,7 +59,7 @@
                        #interrupt-cells = <1>;
                };
 
-               sdhci0: sdhci@7c200000 {
+               sdhci0: mmc@7c200000 {
                        compatible = "samsung,s3c6410-sdhci";
                        reg = <0x7c200000 0x100>;
                        interrupt-parent = <&vic1>;
@@ -70,7 +70,7 @@
                        status = "disabled";
                };
 
-               sdhci1: sdhci@7c300000 {
+               sdhci1: mmc@7c300000 {
                        compatible = "samsung,s3c6410-sdhci";
                        reg = <0x7c300000 0x100>;
                        interrupt-parent = <&vic1>;
@@ -81,7 +81,7 @@
                        status = "disabled";
                };
 
-               sdhci2: sdhci@7c400000 {
+               sdhci2: mmc@7c400000 {
                        compatible = "samsung,s3c6410-sdhci";
                        reg = <0x7c400000 0x100>;
                        interrupt-parent = <&vic1>;
index bc0b735..0f5c6cd 100644 (file)
 &pinctrl0 {
        t_flash_detect: t-flash-detect-pins {
                samsung,pins = "gph3-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_INPUT>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
        };
 };
index daa1067..5541df4 100644 (file)
 &pinctrl0 {
        bt_reset: bt-reset-pins {
                samsung,pins = "gpb-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_OUTPUT>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        wlan_bt_en: wlan-bt-en-pins {
                samsung,pins = "gpb-5";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_OUTPUT>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
                samsung,pin-val = <1>;
        };
 
        codec_ldo: codec-ldo-pins {
                samsung,pins = "gpf3-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_OUTPUT>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
        };
 
        prox_i2c_pins: gp2a-i2c-pins {
                samsung,pins = "gpg0-2", "gpg2-2";
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        wlan_gpio_rst: wlan-gpio-rst-pins {
                samsung,pins = "gpg1-2";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_OUTPUT>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
        };
 
        bt_wake: bt-wake-pins {
                samsung,pins = "gpg3-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_OUTPUT>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
        };
 
        gp2a_irq: gp2a-irq-pins {
                samsung,pins = "gph0-2";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_DOWN>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_F>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_DOWN>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        pmic_dvs_pins: pmic-dvs-pins {
                samsung,pins = "gph0-3", "gph0-4", "gph0-5";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_OUTPUT>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
                samsung,pin-val = <0>;
        };
 
        pmic_irq: pmic-irq-pins {
                samsung,pins = "gph0-7";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_F>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        wifi_host_wake: wifi-host-wake-pins {
                samsung,pins = "gph2-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_DOWN>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_INPUT>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_DOWN>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        bt_host_wake: bt-host-wake-pins {
                samsung,pins = "gph2-5";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_DOWN>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_INPUT>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_DOWN>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        musb_irq: musq-irq-pins {
                samsung,pins = "gph2-7";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_INPUT>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        tf_detect: tf-detect-pins {
                samsung,pins = "gph3-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_DOWN>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_INPUT>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_DOWN>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        wifi_wake: wifi-wake-pins {
                samsung,pins = "gph3-5";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_OUTPUT>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
        };
 
        magnetometer_i2c_pins: yas529-i2c-pins-pins {
                samsung,pins = "gpj0-0", "gpj0-1";
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        ts_irq: ts-irq-pins {
                samsung,pins = "gpj0-5";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_INPUT>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        vibrator_ena: vibrator-ena-pins {
                samsung,pins = "gpj1-1";
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        gp2a_power: gp2a-power-pins {
                samsung,pins = "gpj1-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_OUTPUT>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        touchkey_i2c_pins: touchkey-i2c-pins {
                samsung,pins = "gpj3-0", "gpj3-1";
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        touchkey_vdd_ena: touchkey-vdd-ena-pins {
                samsung,pins = "gpj3-2";
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        musb_i2c_pins: musb-i2c-pins {
                samsung,pins = "gpj3-4", "gpj3-5";
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        accel_i2c_pins: accel-i2c-pins {
                samsung,pins = "gpj3-6", "gpj3-7";
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        pmic_i2c_pins: pmic-i2c-pins-pins {
                samsung,pins = "gpj4-0", "gpj4-3";
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        touchkey_irq: touchkey-irq-pins {
                samsung,pins = "gpj4-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_INPUT>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_UP>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        lcd_spi_pins: spi-lcd-pins {
                samsung,pins = "mp01-1", "mp04-1", "mp04-3";
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        fg_i2c_pins: fg-i2c-pins {
                samsung,pins = "mp05-0", "mp05-1";
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        sound_i2c_pins: sound-i2c-pins {
                samsung,pins = "mp05-2", "mp05-3";
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        panel_rst: panel-rst-pins {
                samsung,pins = "mp05-5";
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 };
 
index dfb2ee6..eaa7c4f 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               power {
+               key-power {
                        label = "power";
                        gpios = <&gph2 6 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
                        wakeup-source;
                };
 
-               vol-down {
+               key-vol-down {
                        label = "volume_down";
                        gpios = <&gph3 2 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEDOWN>;
                };
 
-               vol-up {
+               key-vol-up {
                        label = "volume_up";
                        gpios = <&gph3 1 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
 
        headset_det: headset-det-pins {
                samsung,pins = "gph0-6", "gph3-6";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_F>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
        };
 
        fg_irq: fg-irq-pins {
                samsung,pins = "gph3-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_F>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        headset_micbias_ena: headset-micbias-ena-pins {
                samsung,pins = "gpj2-5";
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        earpath_sel: earpath-sel-pins {
                samsung,pins = "gpj2-6";
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        main_micbias_ena: main-micbias-ena-pins {
                samsung,pins = "gpj4-2";
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        /* Based on vendor kernel v2.6.35.7 */
index a78caaa..cdd3653 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               power {
+               key-power {
                        label = "power";
                        gpios = <&gph2 6 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
                        wakeup-source;
                };
 
-               vol-down {
+               key-vol-down {
                        label = "volume_down";
                        gpios = <&gph3 1 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEDOWN>;
                };
 
-               vol-up {
+               key-vol-up {
                        label = "volume_up";
                        gpios = <&gph3 2 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
                };
 
-               home {
+               key-home {
                        label = "home";
                        gpios = <&gph3 5 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_HOME>;
 
        fm_i2c_pins: fm-i2c-pins-pins {
                samsung,pins = "gpd1-2", "gpd1-3";
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        headset_det: headset-det-pins {
                samsung,pins = "gph0-6", "gph3-6";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_F>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
        };
 
        fm_irq: fm-irq-pins {
                samsung,pins = "gpj2-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_INPUT>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_UP>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        fm_rst: fm-rst-pins {
                samsung,pins = "gpj2-5";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_OUTPUT>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        earpath_sel: earpath-sel-pins {
                samsung,pins = "gpj2-6";
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        massmemory_en: massmemory-en-pins {
                samsung,pins = "gpj2-7";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_OUTPUT>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        micbias_reg_ena: micbias-reg-ena-pins {
                samsung,pins = "gpj4-2";
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        /* Based on CyanogenMod 3.0.101 kernel */
index ae34e7e..6d6daef 100644 (file)
  * nodes can be added to this file.
  */
 
-#include <dt-bindings/pinctrl/samsung.h>
+#include "s5pv210-pinctrl.h"
 
 #define PIN_SLP(_pin, _mode, _pull)                                    \
        _pin {                                                          \
                samsung,pins = #_pin;                                   \
-               samsung,pin-con-pdn = <EXYNOS_PIN_PDN_ ##_mode>;        \
-               samsung,pin-pud-pdn = <S3C64XX_PIN_PULL_ ##_pull>;      \
+               samsung,pin-con-pdn = <S5PV210_PIN_PDN_ ##_mode>;       \
+               samsung,pin-pud-pdn = <S5PV210_PIN_PULL_ ##_pull>;      \
        }
 
 &pinctrl0 {
 
        uart0_data: uart0-data-pins {
                samsung,pins = "gpa0-0", "gpa0-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        uart0_fctl: uart0-fctl-pins {
                samsung,pins = "gpa0-2", "gpa0-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        uart1_data: uart1-data-pins {
                samsung,pins = "gpa0-4", "gpa0-5";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        uart1_fctl: uart1-fctl-pins {
                samsung,pins = "gpa0-6", "gpa0-7";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        uart2_data: uart2-data-pins {
                samsung,pins = "gpa1-0", "gpa1-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        uart2_fctl: uart2-fctl-pins {
                samsung,pins = "gpa1-2", "gpa1-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_3>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        uart3_data: uart3-data-pins {
                samsung,pins = "gpa1-2", "gpa1-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        uart_audio: uart-audio-pins {
                samsung,pins = "gpa1-2", "gpa1-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_4>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        spi0_bus: spi0-bus-pins {
                samsung,pins = "gpb-0", "gpb-2", "gpb-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_UP>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        spi1_bus: spi1-bus-pins {
                samsung,pins = "gpb-4", "gpb-6", "gpb-7";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_UP>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        i2s0_bus: i2s0-bus-pins {
                samsung,pins = "gpi-0", "gpi-1", "gpi-2", "gpi-3",
                                "gpi-4", "gpi-5", "gpi-6";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        i2s1_bus: i2s1-bus-pins {
                samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3",
                                "gpc0-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        i2s2_bus: i2s2-bus-pins {
                samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3",
                                "gpc1-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_4>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        pcm1_bus: pcm1-bus-pins {
                samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3",
                                "gpc0-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_3>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        ac97_bus: ac97-bus-pins {
                samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3",
                                "gpc0-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_4>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        i2s2_bus: i2s2-bus-pins {
                samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3",
                                "gpc1-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        pcm2_bus: pcm2-bus-pins {
                samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3",
                                "gpc1-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_3>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        spdif_bus: spdif-bus-pins {
                samsung,pins = "gpc1-0", "gpc1-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_4>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        spi2_bus: spi2-bus-pins {
                samsung,pins = "gpc1-1", "gpc1-2", "gpc1-3", "gpc1-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_5>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_5>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_UP>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        i2c0_bus: i2c0-bus-pins {
                samsung,pins = "gpd1-0", "gpd1-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_UP>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        i2c1_bus: i2c1-bus-pins {
                samsung,pins = "gpd1-2", "gpd1-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_UP>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        i2c2_bus: i2c2-bus-pins {
                samsung,pins = "gpd1-4", "gpd1-5";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_UP>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        pwm0_out: pwm0-out-pins {
                samsung,pins = "gpd0-0";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        pwm1_out: pwm1-out-pins {
                samsung,pins = "gpd0-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        pwm2_out: pwm2-out-pins {
                samsung,pins = "gpd0-2";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        pwm3_out: pwm3-out-pins {
                samsung,pins = "gpd0-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        keypad_row0: keypad-row-0-pins {
                samsung,pins = "gph3-0";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_3>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        keypad_row1: keypad-row-1-pins {
                samsung,pins = "gph3-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_3>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        keypad_row2: keypad-row-2-pins {
                samsung,pins = "gph3-2";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_3>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        keypad_row3: keypad-row-3-pins {
                samsung,pins = "gph3-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_3>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        keypad_row4: keypad-row-4-pins {
                samsung,pins = "gph3-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_3>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        keypad_row5: keypad-row-5-pins {
                samsung,pins = "gph3-5";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_3>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        keypad_row6: keypad-row-6-pins {
                samsung,pins = "gph3-6";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_3>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        keypad_row7: keypad-row-7-pins {
                samsung,pins = "gph3-7";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_3>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        keypad_col0: keypad-col-0-pins {
                samsung,pins = "gph2-0";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_3>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        keypad_col1: keypad-col-1-pins {
                samsung,pins = "gph2-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_3>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        keypad_col2: keypad-col-2-pins {
                samsung,pins = "gph2-2";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_3>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        keypad_col3: keypad-col-3-pins {
                samsung,pins = "gph2-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_3>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        keypad_col4: keypad-col-4-pins {
                samsung,pins = "gph2-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_3>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        keypad_col5: keypad-col-5-pins {
                samsung,pins = "gph2-5";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_3>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        keypad_col6: keypad-col-6-pins {
                samsung,pins = "gph2-6";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_3>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        keypad_col7: keypad-col-7-pins {
                samsung,pins = "gph2-7";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_3>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        sd0_clk: sd0-clk-pins {
                samsung,pins = "gpg0-0";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV4>;
        };
 
        sd0_cmd: sd0-cmd-pins {
                samsung,pins = "gpg0-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV4>;
        };
 
        sd0_cd: sd0-cd-pins {
                samsung,pins = "gpg0-2";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_UP>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV4>;
        };
 
        sd0_bus1: sd0-bus-width1-pins {
                samsung,pins = "gpg0-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_UP>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV4>;
        };
 
        sd0_bus4: sd0-bus-width4-pins {
                samsung,pins = "gpg0-3", "gpg0-4", "gpg0-5", "gpg0-6";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_UP>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV4>;
        };
 
        sd0_bus8: sd0-bus-width8-pins {
                samsung,pins = "gpg1-3", "gpg1-4", "gpg1-5", "gpg1-6";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_3>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_UP>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV4>;
        };
 
        sd1_clk: sd1-clk-pins {
                samsung,pins = "gpg1-0";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV4>;
        };
 
        sd1_cmd: sd1-cmd-pins {
                samsung,pins = "gpg1-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV4>;
        };
 
        sd1_cd: sd1-cd-pins {
                samsung,pins = "gpg1-2";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_UP>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV4>;
        };
 
        sd1_bus1: sd1-bus-width1-pins {
                samsung,pins = "gpg1-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_UP>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV4>;
        };
 
        sd1_bus4: sd1-bus-width4-pins {
                samsung,pins = "gpg1-3", "gpg1-4", "gpg1-5", "gpg1-6";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_UP>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV4>;
        };
 
        sd2_clk: sd2-clk-pins {
                samsung,pins = "gpg2-0";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV4>;
        };
 
        sd2_cmd: sd2-cmd-pins {
                samsung,pins = "gpg2-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV4>;
        };
 
        sd2_cd: sd2-cd-pins {
                samsung,pins = "gpg2-2";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_UP>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV4>;
        };
 
        sd2_bus1: sd2-bus-width1-pins {
                samsung,pins = "gpg2-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_UP>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV4>;
        };
 
        sd2_bus4: sd2-bus-width4-pins {
                samsung,pins = "gpg2-3", "gpg2-4", "gpg2-5", "gpg2-6";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_UP>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV4>;
        };
 
        sd2_bus8: sd2-bus-width8-pins {
                samsung,pins = "gpg3-3", "gpg3-4", "gpg3-5", "gpg3-6";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_3>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_UP>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV4>;
        };
 
        sd3_clk: sd3-clk-pins {
                samsung,pins = "gpg3-0";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV4>;
        };
 
        sd3_cmd: sd3-cmd-pins {
                samsung,pins = "gpg3-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV4>;
        };
 
        sd3_cd: sd3-cd-pins {
                samsung,pins = "gpg3-2";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_UP>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV4>;
        };
 
        sd3_bus1: sd3-bus-width1-pins {
                samsung,pins = "gpg3-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_UP>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV4>;
        };
 
        sd3_bus4: sd3-bus-width4-pins {
                samsung,pins = "gpg3-3", "gpg3-4", "gpg3-5", "gpg3-6";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_UP>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV4>;
        };
 
        eint0: ext-int0-pins {
                samsung,pins = "gph0-0";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_F>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        eint8: ext-int8-pins {
                samsung,pins = "gph1-0";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_F>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        eint15: ext-int15-pins {
                samsung,pins = "gph1-7";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_F>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        eint16: ext-int16-pins {
                samsung,pins = "gph2-0";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_F>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        eint31: ext-int31-pins {
                samsung,pins = "gph3-7";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_F>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        cam_port_a_io: cam-port-a-io-pins {
                samsung,pins = "gpe0-0", "gpe0-1", "gpe0-2", "gpe0-3",
                                "gpe0-4", "gpe0-5", "gpe0-6", "gpe0-7",
                                "gpe1-0", "gpe1-1", "gpe1-2", "gpe1-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        cam_port_a_clk_active: cam-port-a-clk-active-pins {
                samsung,pins = "gpe1-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV4>;
        };
 
        cam_port_a_clk_idle: cam-port-a-clk-idle-pins {
                samsung,pins = "gpe1-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_DOWN>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_INPUT>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_DOWN>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        cam_port_b_io: cam-port-b-io-pins {
                samsung,pins = "gpj0-0", "gpj0-1", "gpj0-2", "gpj0-3",
                                "gpj0-4", "gpj0-5", "gpj0-6", "gpj0-7",
                                "gpj1-0", "gpj1-1", "gpj1-2", "gpj1-4";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_3>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        cam_port_b_clk_active: cam-port-b-clk-active-pins {
                samsung,pins = "gpj1-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_3>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV4>;
        };
 
        cam_port_b_clk_idle: cam-port-b-clk-idle-pins {
                samsung,pins = "gpj1-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_DOWN>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_INPUT>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_DOWN>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        lcd_ctrl: lcd-ctrl-pins {
                samsung,pins = "gpd0-0", "gpd0-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_3>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        lcd_sync: lcd-sync-pins {
                samsung,pins = "gpf0-0", "gpf0-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        lcd_clk: lcd-clk-pins {
                samsung,pins = "gpf0-0", "gpf0-1", "gpf0-2", "gpf0-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 
        lcd_data24: lcd-data-width24-pins {
                                "gpf2-0", "gpf2-1", "gpf2-2", "gpf2-3",
                                "gpf2-4", "gpf2-5", "gpf2-6", "gpf2-7",
                                "gpf3-0", "gpf3-1", "gpf3-2", "gpf3-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <S3C64XX_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <S5PV210_PIN_FUNC_2>;
+               samsung,pin-pud = <S5PV210_PIN_PULL_NONE>;
+               samsung,pin-drv = <S5PV210_PIN_DRV_LV1>;
        };
 };
diff --git a/arch/arm/boot/dts/s5pv210-pinctrl.h b/arch/arm/boot/dts/s5pv210-pinctrl.h
new file mode 100644 (file)
index 0000000..29bdf37
--- /dev/null
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Samsung S5PV210 DTS pinctrl constants
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ * Copyright (c) 2022 Linaro Ltd
+ * Author: Krzysztof Kozlowski <krzk@kernel.org>
+ */
+
+#ifndef __DTS_ARM_SAMSUNG_S5PV210_PINCTRL_H__
+#define __DTS_ARM_SAMSUNG_S5PV210_PINCTRL_H__
+
+#define S5PV210_PIN_PULL_NONE          0
+#define S5PV210_PIN_PULL_DOWN          1
+#define S5PV210_PIN_PULL_UP            2
+
+/* Pin function in power down mode */
+#define S5PV210_PIN_PDN_OUT0           0
+#define S5PV210_PIN_PDN_OUT1           1
+#define S5PV210_PIN_PDN_INPUT          2
+#define S5PV210_PIN_PDN_PREV           3
+
+#define S5PV210_PIN_DRV_LV1            0
+#define S5PV210_PIN_DRV_LV2            2
+#define S5PV210_PIN_DRV_LV3            1
+#define S5PV210_PIN_DRV_LV4            3
+
+#define S5PV210_PIN_FUNC_INPUT         0
+#define S5PV210_PIN_FUNC_OUTPUT                1
+#define S5PV210_PIN_FUNC_2             2
+#define S5PV210_PIN_FUNC_3             3
+#define S5PV210_PIN_FUNC_4             4
+#define S5PV210_PIN_FUNC_5             5
+#define S5PV210_PIN_FUNC_6             6
+#define S5PV210_PIN_FUNC_EINT          0xf
+#define S5PV210_PIN_FUNC_F             S5PV210_PIN_FUNC_EINT
+
+#endif /* __DTS_ARM_SAMSUNG_S5PV210_PINCTRL_H__ */
index f1b85aa..12e90a1 100644 (file)
                        status = "disabled";
                };
 
-               sdhci0: sdhci@eb000000 {
+               sdhci0: mmc@eb000000 {
                        compatible = "samsung,s3c6410-sdhci";
                        reg = <0xeb000000 0x100000>;
                        interrupt-parent = <&vic1>;
                        status = "disabled";
                };
 
-               sdhci1: sdhci@eb100000 {
+               sdhci1: mmc@eb100000 {
                        compatible = "samsung,s3c6410-sdhci";
                        reg = <0xeb100000 0x100000>;
                        interrupt-parent = <&vic1>;
                        status = "disabled";
                };
 
-               sdhci2: sdhci@eb200000 {
+               sdhci2: mmc@eb200000 {
                        compatible = "samsung,s3c6410-sdhci";
                        reg = <0xeb200000 0x100000>;
                        interrupt-parent = <&vic1>;
                        status = "disabled";
                };
 
-               sdhci3: sdhci@eb300000 {
+               sdhci3: mmc@eb300000 {
                        compatible = "samsung,s3c6410-sdhci";
                        reg = <0xeb300000 0x100000>;
                        interrupt-parent = <&vic3>;
index c328b67..d3f60f6 100644 (file)
                                interrupts = <18 IRQ_TYPE_LEVEL_HIGH 4>;
                                clocks = <&pmc PMC_TYPE_PERIPHERAL 18>;
                                #pwm-cells = <3>;
-                               status="disabled";
+                               status = "disabled";
                        };
 
                        hlcdc: hlcdc@f8038000 {
                                clock-names = "td_slck", "md_slck", "main_xtal";
                        };
 
-                       reset_controller: rstc@fffffe00 {
+                       reset_controller: reset-controller@fffffe00 {
                                compatible = "microchip,sam9x60-rstc";
                                reg = <0xfffffe00 0x10>;
                                clocks = <&clk32k 0>;
index 89c71d4..2c50a02 100644 (file)
                ranges = <0 0x00200000 0x20000>;
        };
 
+       resistive_touch: resistive-touch {
+               compatible = "resistive-adc-touch";
+               io-channels = <&adc AT91_SAMA5D2_ADC_X_CHANNEL>,
+                             <&adc AT91_SAMA5D2_ADC_Y_CHANNEL>,
+                             <&adc AT91_SAMA5D2_ADC_P_CHANNEL>;
+               io-channel-names = "x", "y", "pressure";
+               touchscreen-min-pressure = <50000>;
+               status = "disabled";
+       };
+
        ahb {
                compatible = "simple-bus";
                #address-cells = <1>;
                                interrupts = <5  IRQ_TYPE_LEVEL_HIGH 3          /* Queue 0 */
                                              66 IRQ_TYPE_LEVEL_HIGH 3          /* Queue 1 */
                                              67 IRQ_TYPE_LEVEL_HIGH 3>;        /* Queue 2 */
-                               #address-cells = <1>;
-                               #size-cells = <0>;
                                clocks = <&pmc PMC_TYPE_PERIPHERAL 5>, <&pmc PMC_TYPE_PERIPHERAL 5>;
                                clock-names = "hclk", "pclk";
                                status = "disabled";
                                ranges = <0 0xf8044000 0x1420>;
                        };
 
-                       reset_controller: rstc@f8048000 {
+                       reset_controller: reset-controller@f8048000 {
                                compatible = "atmel,sama5d3-rstc";
                                reg = <0xf8048000 0x10>;
                                clocks = <&clk32k>;
                                status = "disabled";
                        };
 
-                       resistive_touch: resistive-touch {
-                               compatible = "resistive-adc-touch";
-                               io-channels = <&adc AT91_SAMA5D2_ADC_X_CHANNEL>,
-                                             <&adc AT91_SAMA5D2_ADC_Y_CHANNEL>,
-                                             <&adc AT91_SAMA5D2_ADC_P_CHANNEL>;
-                               io-channel-names = "x", "y", "pressure";
-                               touchscreen-min-pressure = <50000>;
-                               status = "disabled";
-                       };
-
                        pioA: pinctrl@fc038000 {
                                compatible = "atmel,sama5d2-pinctrl";
                                reg = <0xfc038000 0x600>;
                                clocks = <&pmc PMC_TYPE_PERIPHERAL 55>, <&pmc PMC_TYPE_GCK 55>;
                                clock-names = "pclk", "gclk";
                                assigned-clocks = <&pmc PMC_TYPE_CORE PMC_I2S1_MUX>;
-                               assigned-parrents = <&pmc PMC_TYPE_GCK 55>;
+                               assigned-clock-parents = <&pmc PMC_TYPE_GCK 55>;
                                status = "disabled";
                        };
 
index 8fa423c..2d0935a 100644 (file)
                                clock-names = "slow_clk", "main_xtal";
                        };
 
-                       reset_controller: rstc@fffffe00 {
+                       reset_controller: reset-controller@fffffe00 {
                                compatible = "atmel,sama5d3-rstc", "atmel,at91sam9g45-rstc";
                                reg = <0xfffffe00 0x10>;
                                clocks = <&clk32k>;
index 7b92426..1e5c018 100644 (file)
                                };
                        };
 
-                       reset_controller: rstc@fc068600 {
+                       reset_controller: reset-controller@fc068600 {
                                compatible = "atmel,sama5d3-rstc", "atmel,at91sam9g45-rstc";
                                reg = <0xfc068600 0x10>;
                                clocks = <&clk32k>;
index a37e3a8..bb6d71e 100644 (file)
                        clock-names = "td_slck", "md_slck", "main_xtal";
                };
 
+               reset_controller: reset-controller@e001d000 {
+                       compatible = "microchip,sama7g5-rstc";
+                       reg = <0xe001d000 0xc>, <0xe001d0e4 0x4>;
+                       #reset-cells = <1>;
+                       clocks = <&clk32k 0>;
+               };
+
                shdwc: shdwc@e001d010 {
                        compatible = "microchip,sama7g5-shdwc", "syscon";
                        reg = <0xe001d010 0x10>;
index a61a078..6938181 100644 (file)
@@ -15,7 +15,7 @@
        #size-cells = <1>;
 
        chosen {
-               bootargs="console=ttyS0,9600 earlycon=uart8250,mmio32,0x1600d000";
+               bootargs = "console=ttyS0,9600 earlycon=uart8250,mmio32,0x1600d000";
        };
 
        aliases {
index 26bda25..4370e3c 100644 (file)
                                             <37 IRQ_TYPE_LEVEL_HIGH>;
                        };
 
+                       sdmmca-ecc@ff8c2c00 {
+                               compatible = "altr,socfpga-sdmmc-ecc";
+                               reg = <0xff8c2c00 0x400>;
+                               altr,ecc-parent = <&mmc>;
+                               interrupts = <15 IRQ_TYPE_LEVEL_HIGH>,
+                                            <47 IRQ_TYPE_LEVEL_HIGH>,
+                                            <16 IRQ_TYPE_LEVEL_HIGH>,
+                                            <48 IRQ_TYPE_LEVEL_HIGH>;
+                       };
+
                        dma-ecc@ff8c8000 {
                                compatible = "altr,socfpga-dma-ecc";
                                reg = <0xff8c8000 0x400>;
diff --git a/arch/arm/boot/dts/socfpga_arria10_chameleonv3.dts b/arch/arm/boot/dts/socfpga_arria10_chameleonv3.dts
new file mode 100644 (file)
index 0000000..422d00c
--- /dev/null
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2022 Google LLC
+ */
+/dts-v1/;
+#include "socfpga_arria10_mercury_aa1.dtsi"
+
+/ {
+       model = "Google Chameleon V3";
+       compatible = "google,chameleon-v3", "enclustra,mercury-aa1",
+                    "altr,socfpga-arria10", "altr,socfpga";
+
+       aliases {
+               serial0 = &uart0;
+               i2c0 = &i2c0;
+               i2c1 = &i2c1;
+       };
+};
+
+&gmac0 {
+       status = "okay";
+};
+
+&gpio0 {
+       status = "okay";
+};
+
+&gpio1 {
+       status = "okay";
+};
+
+&gpio2 {
+       status = "okay";
+};
+
+&i2c0 {
+       status = "okay";
+
+       ssm2603: audio-codec@1a {
+               compatible = "adi,ssm2603";
+               reg = <0x1a>;
+       };
+};
+
+&i2c1 {
+       status = "okay";
+
+       u80: gpio@21 {
+               compatible = "nxp,pca9535";
+               reg = <0x21>;
+               gpio-controller;
+               #gpio-cells = <2>;
+
+               gpio-line-names =
+                       "SOM_AUD_MUTE",
+                       "DP1_OUT_CEC_EN",
+                       "DP2_OUT_CEC_EN",
+                       "DP1_SOM_PS8469_CAD",
+                       "DPD_SOM_PS8469_CAD",
+                       "DP_OUT_PWR_EN",
+                       "STM32_RST_L",
+                       "STM32_BOOT0",
+
+                       "FPGA_PROT",
+                       "STM32_FPGA_COMM0",
+                       "TP119",
+                       "TP120",
+                       "TP121",
+                       "TP122",
+                       "TP123",
+                       "TP124";
+       };
+};
+
+&mmc {
+       status = "okay";
+};
+
+&uart0 {
+       status = "okay";
+};
+
+&uart1 {
+       status = "okay";
+};
+
+&usb0 {
+       status = "okay";
+       dr_mode = "host";
+};
@@ -1,5 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
-/dts-v1/;
+/*
+ * Copyright 2022 Google LLC
+ */
 
 #include "socfpga_arria10.dtsi"
 
@@ -11,8 +13,6 @@
        aliases {
                ethernet0 = &gmac0;
                serial1 = &uart1;
-               i2c0 = &i2c0;
-               i2c1 = &i2c1;
        };
 
        memory@0 {
        };
 };
 
-&eccmgr {
-       sdmmca-ecc@ff8c2c00 {
-               compatible = "altr,socfpga-sdmmc-ecc";
-               reg = <0xff8c2c00 0x400>;
-               altr,ecc-parent = <&mmc>;
-               interrupts = <15 IRQ_TYPE_LEVEL_HIGH>,
-                            <47 IRQ_TYPE_LEVEL_HIGH>,
-                            <16 IRQ_TYPE_LEVEL_HIGH>,
-                            <48 IRQ_TYPE_LEVEL_HIGH>;
-       };
-};
-
 &gmac0 {
        phy-mode = "rgmii";
        phy-addr = <0xffffffff>; /* probe for phy addr */
 
        max-frame-size = <3800>;
-       status = "okay";
 
        phy-handle = <&phy3>;
 
        };
 };
 
-&gpio0 {
-       status = "okay";
-};
-
-&gpio1 {
-       status = "okay";
-};
-
-&gpio2 {
-       status = "okay";
-};
-
 &i2c1 {
-       status = "okay";
+       atsha204a: crypto@64 {
+               compatible = "atmel,atsha204a";
+               reg = <0x64>;
+       };
+
        isl12022: isl12022@6f {
-               status = "okay";
                compatible = "isil,isl12022";
                reg = <0x6f>;
        };
@@ -92,7 +70,6 @@
 
 /* Following mappings are taken from arria10 socdk dts */
 &mmc {
-       status = "okay";
        cap-sd-highspeed;
        broken-cd;
        bus-width = <4>;
 &osc1 {
        clock-frequency = <33330000>;
 };
-
-&uart1 {
-       status = "okay";
-};
-
-&usb0 {
-       status = "okay";
-       dr_mode = "host";
-};
index ddd1cf4..05408df 100644 (file)
 
                smi: flash@ea000000 {
                        status = "okay";
-                       clock-rate=<50000000>;
+                       clock-rate = <50000000>;
 
                        flash@e6000000 {
                                #address-cells = <1>;
index 3a51a41..7700f2a 100644 (file)
 
                smi: flash@ea000000 {
                        status = "okay";
-                       clock-rate=<50000000>;
+                       clock-rate = <50000000>;
 
                        flash@e6000000 {
                                #address-cells = <1>;
index 13e1bdb..818886e 100644 (file)
@@ -88,7 +88,7 @@
                };
 
                pwm: pwm@e0180000 {
-                       compatible ="st,spear13xx-pwm";
+                       compatible = "st,spear13xx-pwm";
                        reg = <0xe0180000 0x1000>;
                        #pwm-cells = <2>;
                        status = "disabled";
index 2beb30c..303ef29 100644 (file)
@@ -80,7 +80,7 @@
 
                smi: flash@fc000000 {
                        status = "okay";
-                       clock-rate=<50000000>;
+                       clock-rate = <50000000>;
 
                        flash@f8000000 {
                                #address-cells = <1>;
index 1c41e4a..ea0b530 100644 (file)
@@ -94,7 +94,7 @@
 
                smi: flash@fc000000 {
                        status = "okay";
-                       clock-rate=<50000000>;
+                       clock-rate = <50000000>;
 
                        flash@f8000000 {
                                #address-cells = <1>;
index c322407..3c026d0 100644 (file)
@@ -95,7 +95,7 @@
 
                smi: flash@fc000000 {
                        status = "okay";
-                       clock-rate=<50000000>;
+                       clock-rate = <50000000>;
 
                        flash@f8000000 {
                                #address-cells = <1>;
index b587e4e..34503ac 100644 (file)
 
                smi: flash@fc000000 {
                        status = "okay";
-                       clock-rate=<50000000>;
+                       clock-rate = <50000000>;
 
                        flash@f8000000 {
                                #address-cells = <1>;
index 47ac447..b124744 100644 (file)
@@ -78,7 +78,7 @@
                };
 
                pwm: pwm@a8000000 {
-                       compatible ="st,spear-pwm";
+                       compatible = "st,spear-pwm";
                        reg = <0xa8000000 0x1000>;
                        #pwm-cells = <2>;
                        status = "disabled";
index 35137c6..dd30d08 100644 (file)
                                                          "CH_WD_EXP",
                                                          "VBUS_CH_DROP_END";
                                        monitored-battery = <&battery>;
-                                       vddadc-supply   = <&ab8500_ldo_tvout_reg>;
+                                       vddadc-supply = <&ab8500_ldo_tvout_reg>;
                                        io-channels = <&gpadc 0x03>,
                                                      <&gpadc 0x0a>,
                                                      <&gpadc 0x09>,
                                };
 
                                ab8500_chargalg {
-                                       compatible      = "stericsson,ab8500-chargalg";
-                                       monitored-battery       = <&battery>;
+                                       compatible = "stericsson,ab8500-chargalg";
+                                       monitored-battery = <&battery>;
                                };
 
                                ab8500_usb: phy {
index c28b326..9afe830 100644 (file)
 
                        #address-cells = <1>;
                        #size-cells = <0>;
-                       v-i2c-supply = <&db8500_vape_reg>;
 
                        clock-frequency = <400000>;
                        clocks = <&prcc_kclk 3 3>, <&prcc_pclk 3 3>;
 
                        #address-cells = <1>;
                        #size-cells = <0>;
-                       v-i2c-supply = <&db8500_vape_reg>;
 
                        clock-frequency = <400000>;
 
 
                        #address-cells = <1>;
                        #size-cells = <0>;
-                       v-i2c-supply = <&db8500_vape_reg>;
 
                        clock-frequency = <400000>;
 
 
                        #address-cells = <1>;
                        #size-cells = <0>;
-                       v-i2c-supply = <&db8500_vape_reg>;
 
                        clock-frequency = <400000>;
 
 
                        #address-cells = <1>;
                        #size-cells = <0>;
-                       v-i2c-supply = <&db8500_vape_reg>;
 
                        clock-frequency = <400000>;
 
index 8f504ed..e66fa59 100644 (file)
                                         * Drive DISP1 reset high (not reset), driver DISP2 reset low (reset)
                                         */
                                        hrefv60_cfg1 {
-                                               pins ="GPIO65_F1";
+                                               pins = "GPIO65_F1";
                                                ste,config = <&gpio_out_hi>;
                                        };
                                        hrefv60_cfg2 {
-                                               pins ="GPIO66_G3";
+                                               pins = "GPIO66_G3";
                                                ste,config = <&gpio_out_lo>;
                                        };
                                };
index b6746ac..5f41256 100644 (file)
                                reg = <0x19>;
                                vdd-supply = <&ab8500_ldo_aux1_reg>; // 3V
                                vddio-supply = <&ab8500_ldo_aux2_reg>; // 1.8V
-                               mount-matrix = "0", "-1", "0",
-                                              "1", "0", "0",
+                               mount-matrix = "0", "1", "0",
+                                              "-1", "0", "0",
                                               "0", "0", "1";
                        };
                };
index 53062d5..806da3f 100644 (file)
                                        accelerometer@18 {
                                                compatible = "bosch,bma222e";
                                                reg = <0x18>;
-                                               mount-matrix = "0", "1", "0",
-                                                              "-1", "0", "0",
+                                               mount-matrix = "0", "-1", "0",
+                                                              "1", "0", "0",
                                                               "0", "0", "1";
                                                vddio-supply = <&ab8500_ldo_aux2_reg>; // 1.8V
                                                vdd-supply = <&ab8500_ldo_aux1_reg>; // 3V
index e6d4fd0..ed5c79c 100644 (file)
                                        accelerometer@8 {
                                                compatible = "bosch,bma222";
                                                reg = <0x08>;
-                                               mount-matrix = "0", "1", "0",
-                                                              "-1", "0", "0",
+                                               mount-matrix = "0", "-1", "0",
+                                                              "1", "0", "0",
                                                               "0", "0", "1";
                                                vddio-supply = <&ab8500_ldo_aux2_reg>; // 1.8V
                                                vdd-supply = <&ab8500_ldo_aux1_reg>; // 3V
index 1713f78..5ebb779 100644 (file)
        };
 
        irq-syscfg {
-               compatible    = "st,stih407-irq-syscfg";
-               st,syscfg     = <&syscfg_core>;
+               compatible = "st,stih407-irq-syscfg";
+               st,syscfg = <&syscfg_core>;
                st,irq-device = <ST_IRQ_SYSCFG_PMU_0>,
                                <ST_IRQ_SYSCFG_PMU_1>;
                st,fiq-device = <ST_IRQ_SYSCFG_DISABLED>,
        miphy28lp_phy: miphy28lp {
                compatible = "st,miphy28lp-phy";
                st,syscfg = <&syscfg_core>;
-               #address-cells  = <1>;
-               #size-cells     = <1>;
+               #address-cells = <1>;
+               #size-cells = <1>;
                ranges;
 
                phy_port0: port@9b22000 {
        };
 
        st231_gp0: st231-gp0 {
-               compatible      = "st,st231-rproc";
-               memory-region   = <&gp0_reserved>;
-               resets          = <&softreset STIH407_ST231_GP0_SOFTRESET>;
-               reset-names     = "sw_reset";
-               clocks          = <&clk_s_c0_flexgen CLK_ST231_GP_0>;
-               clock-frequency = <600000000>;
-               st,syscfg       = <&syscfg_core 0x22c>;
+               compatible = "st,st231-rproc";
+               memory-region = <&gp0_reserved>;
+               resets = <&softreset STIH407_ST231_GP0_SOFTRESET>;
+               reset-names = "sw_reset";
+               clocks = <&clk_s_c0_flexgen CLK_ST231_GP_0>;
+               clock-frequency = <600000000>;
+               st,syscfg = <&syscfg_core 0x22c>;
                #mbox-cells = <1>;
                mbox-names = "vq0_rx", "vq0_tx", "vq1_rx", "vq1_tx";
                mboxes = <&mailbox0 0 2>, <&mailbox2 0 1>, <&mailbox0 0 3>, <&mailbox2 0 0>;
        };
 
        st231_delta: st231-delta {
-               compatible      = "st,st231-rproc";
-               memory-region   = <&delta_reserved>;
-               resets          = <&softreset STIH407_ST231_DMU_SOFTRESET>;
-               reset-names     = "sw_reset";
-               clocks          = <&clk_s_c0_flexgen CLK_ST231_DMU>;
-               clock-frequency = <600000000>;
-               st,syscfg       = <&syscfg_core 0x224>;
+               compatible = "st,st231-rproc";
+               memory-region = <&delta_reserved>;
+               resets = <&softreset STIH407_ST231_DMU_SOFTRESET>;
+               reset-names = "sw_reset";
+               clocks = <&clk_s_c0_flexgen CLK_ST231_DMU>;
+               clock-frequency = <600000000>;
+               st,syscfg = <&syscfg_core 0x224>;
                #mbox-cells = <1>;
                mbox-names = "vq0_rx", "vq0_tx", "vq1_rx", "vq1_tx";
                mboxes = <&mailbox0 0 0>, <&mailbox3 0 1>, <&mailbox0 0 1>, <&mailbox3 0 0>;
 
 
                st_dwc3: dwc3@8f94000 {
-                       compatible      = "st,stih407-dwc3";
-                       reg             = <0x08f94000 0x1000>, <0x110 0x4>;
-                       reg-names       = "reg-glue", "syscfg-reg";
-                       st,syscfg       = <&syscfg_core>;
-                       resets          = <&powerdown STIH407_USB3_POWERDOWN>,
-                                         <&softreset STIH407_MIPHY2_SOFTRESET>;
-                       reset-names     = "powerdown", "softreset";
-                       #address-cells  = <1>;
-                       #size-cells     = <1>;
-                       pinctrl-names   = "default";
-                       pinctrl-0       = <&pinctrl_usb3>;
+                       compatible = "st,stih407-dwc3";
+                       reg = <0x08f94000 0x1000>, <0x110 0x4>;
+                       reg-names = "reg-glue", "syscfg-reg";
+                       st,syscfg = <&syscfg_core>;
+                       resets = <&powerdown STIH407_USB3_POWERDOWN>,
+                                <&softreset STIH407_MIPHY2_SOFTRESET>;
+                       reset-names = "powerdown", "softreset";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_usb3>;
                        ranges;
 
                        status = "disabled";
 
-                       dwc3: dwc3@9900000 {
-                               compatible      = "snps,dwc3";
-                               reg             = <0x09900000 0x100000>;
-                               interrupts      = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
-                               dr_mode         = "host";
-                               phy-names       = "usb2-phy", "usb3-phy";
-                               phys            = <&usb2_picophy0>,
-                                                 <&phy_port2 PHY_TYPE_USB3>;
+                       dwc3: usb@9900000 {
+                               compatible = "snps,dwc3";
+                               reg = <0x09900000 0x100000>;
+                               interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
+                               dr_mode = "host";
+                               phy-names = "usb2-phy", "usb3-phy";
+                               phys = <&usb2_picophy0>,
+                                      <&phy_port2 PHY_TYPE_USB3>;
                                snps,dis_u3_susphy_quirk;
                        };
                };
 
                /* COMMS PWM Module */
                pwm0: pwm@9810000 {
-                       compatible      = "st,sti-pwm";
-                       #pwm-cells      = <2>;
-                       reg             = <0x9810000 0x68>;
-                       interrupts      = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>;
-                       pinctrl-names   = "default";
-                       pinctrl-0       = <&pinctrl_pwm0_chan0_default>;
-                       clock-names     = "pwm";
-                       clocks          = <&clk_sysin>;
+                       compatible = "st,sti-pwm";
+                       #pwm-cells = <2>;
+                       reg = <0x9810000 0x68>;
+                       interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_pwm0_chan0_default>;
+                       clock-names = "pwm";
+                       clocks = <&clk_sysin>;
                        st,pwm-num-chan = <1>;
 
-                       status          = "disabled";
+                       status = "disabled";
                };
 
                /* SBC PWM Module */
                pwm1: pwm@9510000 {
-                       compatible      = "st,sti-pwm";
-                       #pwm-cells      = <2>;
-                       reg             = <0x9510000 0x68>;
-                       interrupts      = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
-                       pinctrl-names   = "default";
-                       pinctrl-0       = <&pinctrl_pwm1_chan0_default
-                                       &pinctrl_pwm1_chan1_default
-                                       &pinctrl_pwm1_chan2_default
-                                       &pinctrl_pwm1_chan3_default>;
-                       clock-names     = "pwm";
-                       clocks          = <&clk_sysin>;
+                       compatible = "st,sti-pwm";
+                       #pwm-cells = <2>;
+                       reg = <0x9510000 0x68>;
+                       interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_pwm1_chan0_default
+                                    &pinctrl_pwm1_chan1_default
+                                    &pinctrl_pwm1_chan2_default
+                                    &pinctrl_pwm1_chan3_default>;
+                       clock-names = "pwm";
+                       clocks = <&clk_sysin>;
                        st,pwm-num-chan = <4>;
 
-                       status          = "disabled";
+                       status = "disabled";
                };
 
                rng10: rng@8a89000 {
-                       compatible      = "st,rng";
-                       reg             = <0x08a89000 0x1000>;
-                       clocks          = <&clk_sysin>;
-                       status          = "okay";
+                       compatible = "st,rng";
+                       reg = <0x08a89000 0x1000>;
+                       clocks = <&clk_sysin>;
+                       status = "okay";
                };
 
                rng11: rng@8a8a000 {
-                       compatible      = "st,rng";
-                       reg             = <0x08a8a000 0x1000>;
-                       clocks          = <&clk_sysin>;
-                       status          = "okay";
+                       compatible = "st,rng";
+                       reg = <0x08a8a000 0x1000>;
+                       clocks = <&clk_sysin>;
+                       status = "okay";
                };
 
                ethernet0: dwmac@9630000 {
                };
 
                mailbox0: mailbox@8f00000  {
-                       compatible      = "st,stih407-mailbox";
-                       reg             = <0x8f00000 0x1000>;
-                       interrupts      = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
-                       #mbox-cells     = <2>;
-                       mbox-name       = "a9";
-                       status          = "okay";
+                       compatible = "st,stih407-mailbox";
+                       reg = <0x8f00000 0x1000>;
+                       interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
+                       #mbox-cells = <2>;
+                       mbox-name = "a9";
+                       status = "okay";
                };
 
                mailbox1: mailbox@8f01000 {
-                       compatible      = "st,stih407-mailbox";
-                       reg             = <0x8f01000 0x1000>;
-                       #mbox-cells     = <2>;
-                       mbox-name       = "st231_gp_1";
-                       status          = "okay";
+                       compatible = "st,stih407-mailbox";
+                       reg = <0x8f01000 0x1000>;
+                       #mbox-cells = <2>;
+                       mbox-name = "st231_gp_1";
+                       status = "okay";
                };
 
                mailbox2: mailbox@8f02000 {
-                       compatible      = "st,stih407-mailbox";
-                       reg             = <0x8f02000 0x1000>;
-                       #mbox-cells     = <2>;
-                       mbox-name       = "st231_gp_0";
-                       status          = "okay";
+                       compatible = "st,stih407-mailbox";
+                       reg = <0x8f02000 0x1000>;
+                       #mbox-cells = <2>;
+                       mbox-name = "st231_gp_0";
+                       status = "okay";
                };
 
                mailbox3: mailbox@8f03000 {
-                       compatible      = "st,stih407-mailbox";
-                       reg             = <0x8f03000 0x1000>;
-                       #mbox-cells     = <2>;
-                       mbox-name       = "st231_audio_video";
-                       status          = "okay";
+                       compatible = "st,stih407-mailbox";
+                       reg = <0x8f03000 0x1000>;
+                       #mbox-cells = <2>;
+                       mbox-name = "st231_audio_video";
+                       status = "okay";
                };
 
                /* fdma audio */
                        dmas = <&fdma0 2 0 1>;
                        dma-names = "tx";
 
-                       status          = "disabled";
+                       status = "disabled";
                };
 
                sti_uni_player1: sti-uni-player@8d81000 {
index 9e212b0..aca43d2 100644 (file)
@@ -13,7 +13,7 @@
                        #address-cells = <1>;
                        #size-cells = <1>;
                        reg = <0 0>;
-                       assigned-clocks = <&clk_s_d2_quadfs 0>,
+                       assigned-clocks = <&clk_s_d2_quadfs 0>,
                                          <&clk_s_d2_quadfs 1>,
                                          <&clk_s_c0_pll1 0>,
                                          <&clk_s_c0_flexgen CLK_COMPO_DVP>,
                                reg-names = "hdmi-reg";
                                #sound-dai-cells = <0>;
                                interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
-                               interrupt-names = "irq";
+                               interrupt-names = "irq";
                                clock-names = "pix",
                                              "tmds",
                                              "phy",
index ce2f62c..a39dd5f 100644 (file)
                        #size-cells = <1>;
 
                        reg = <0 0>;
-                       assigned-clocks = <&clk_s_d2_quadfs 0>,
+                       assigned-clocks = <&clk_s_d2_quadfs 0>,
                                          <&clk_s_d2_quadfs 1>,
                                          <&clk_s_c0_pll1 0>,
                                          <&clk_s_c0_flexgen CLK_COMPO_DVP>,
                                reg-names = "hdmi-reg";
                                #sound-dai-cells = <0>;
                                interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
-                               interrupt-names = "irq";
+                               interrupt-names = "irq";
                                clock-names = "pix",
                                              "tmds",
                                              "phy",
index 4c72ded..2aa9460 100644 (file)
 
                        /* tsin0 is TSA on NIMA */
                        tsin0: port {
-                               tsin-num        = <0>;
+                               tsin-num = <0>;
                                serial-not-parallel;
-                               i2c-bus         = <&ssc2>;
-                               reset-gpios     = <&pio15 4 GPIO_ACTIVE_HIGH>;
-                               dvb-card        = <STV0367_TDA18212_NIMA_1>;
+                               i2c-bus = <&ssc2>;
+                               reset-gpios = <&pio15 4 GPIO_ACTIVE_HIGH>;
+                               dvb-card = <STV0367_TDA18212_NIMA_1>;
                        };
                };
 
index 0d98aca..3de0e9d 100644 (file)
 
 &mac {
        status = "okay";
-       pinctrl-0       = <&ethernet_mii>;
-       pinctrl-names   = "default";
-       phy-mode        = "mii";
-       phy-handle      = <&phy1>;
+       pinctrl-0 = <&ethernet_mii>;
+       pinctrl-names = "default";
+       phy-mode = "mii";
+       phy-handle = <&phy1>;
        mdio0 {
                #address-cells = <1>;
                #size-cells = <0>;
index 91dde07..2059593 100644 (file)
                        arm,primecell-periphid = <0x10153180>;
                        reg = <0x52007000 0x1000>;
                        interrupts = <49>;
-                       interrupt-names = "cmd_irq";
+                       interrupt-names = "cmd_irq";
                        clocks = <&rcc SDMMC1_CK>;
                        clock-names = "apb_pclk";
                        resets = <&rcc STM32H7_AHB3_RESET(SDMMC1)>;
                        arm,primecell-periphid = <0x10153180>;
                        reg = <0x48022400 0x400>;
                        interrupts = <124>;
-                       interrupt-names = "cmd_irq";
+                       interrupt-names = "cmd_irq";
                        clocks = <&rcc SDMMC2_CK>;
                        clock-names = "apb_pclk";
                        resets = <&rcc STM32H7_AHB2_RESET(SDMMC2)>;
index 59e01ce..2b45288 100644 (file)
 
 &mac {
        status = "disabled";
-       pinctrl-0       = <&ethernet_rmii>;
-       pinctrl-names   = "default";
-       phy-mode        = "rmii";
-       phy-handle      = <&phy0>;
+       pinctrl-0 = <&ethernet_rmii>;
+       pinctrl-names = "default";
+       phy-mode = "rmii";
+       phy-handle = <&phy0>;
 
        mdio0 {
                #address-cells = <1>;
index 38cc7fa..5c5d805 100644 (file)
 
 &mac {
        status = "disabled";
-       pinctrl-0       = <&ethernet_rmii>;
-       pinctrl-names   = "default";
-       phy-mode        = "rmii";
-       phy-handle      = <&phy0>;
+       pinctrl-0 = <&ethernet_rmii>;
+       pinctrl-names = "default";
+       phy-mode = "rmii";
+       phy-handle = <&phy0>;
 
        mdio0 {
                #address-cells = <1>;
index 9bb73bb..f3e70d3 100644 (file)
 
 &mac {
        status = "disabled";
-       pinctrl-0       = <&ethernet_rmii>;
-       pinctrl-names   = "default";
-       phy-mode        = "rmii";
-       phy-handle      = <&phy0>;
+       pinctrl-0 = <&ethernet_rmii>;
+       pinctrl-names = "default";
+       phy-mode = "rmii";
+       phy-handle = <&phy0>;
 
        mdio0 {
                #address-cells = <1>;
index f9ebc47..3a921db 100644 (file)
@@ -4,6 +4,8 @@
  * Author: Alexandre Torgue <alexandre.torgue@foss.st.com> for STMicroelectronics.
  */
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/stm32mp13-clks.h>
+#include <dt-bindings/reset/stm32mp13-resets.h>
 
 / {
        #address-cells = <1>;
                interrupt-parent = <&intc>;
        };
 
-       clocks {
-               clk_axi: clk-axi {
-                       #clock-cells = <0>;
-                       compatible = "fixed-clock";
-                       clock-frequency = <266500000>;
+       firmware {
+               optee {
+                       method = "smc";
+                       compatible = "linaro,optee-tz";
                };
 
-               clk_hse: clk-hse {
-                       #clock-cells = <0>;
-                       compatible = "fixed-clock";
-                       clock-frequency = <24000000>;
-               };
-
-               clk_hsi: clk-hsi {
-                       #clock-cells = <0>;
-                       compatible = "fixed-clock";
-                       clock-frequency = <64000000>;
-               };
-
-               clk_lsi: clk-lsi {
-                       #clock-cells = <0>;
-                       compatible = "fixed-clock";
-                       clock-frequency = <32000>;
-               };
-
-               clk_pclk3: clk-pclk3 {
-                       #clock-cells = <0>;
-                       compatible = "fixed-clock";
-                       clock-frequency = <104438965>;
-               };
-
-               clk_pclk4: clk-pclk4 {
-                       #clock-cells = <0>;
-                       compatible = "fixed-clock";
-                       clock-frequency = <133250000>;
-               };
-
-               clk_pll4_p: clk-pll4_p {
-                       #clock-cells = <0>;
-                       compatible = "fixed-clock";
-                       clock-frequency = <50000000>;
-               };
+               scmi: scmi {
+                       compatible = "linaro,scmi-optee";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       linaro,optee-channel-id = <0>;
+                       shmem = <&scmi_shm>;
 
-               clk_pll4_r: clk-pll4_r {
-                       #clock-cells = <0>;
-                       compatible = "fixed-clock";
-                       clock-frequency = <99000000>;
-               };
+                       scmi_clk: protocol@14 {
+                               reg = <0x14>;
+                               #clock-cells = <1>;
+                       };
 
-               clk_rtc_k: clk-rtc-k {
-                       #clock-cells = <0>;
-                       compatible = "fixed-clock";
-                       clock-frequency = <32768>;
+                       scmi_reset: protocol@16 {
+                               reg = <0x16>;
+                               #reset-cells = <1>;
+                       };
                };
        };
 
                interrupt-parent = <&intc>;
                ranges;
 
+               scmi_sram: sram@2ffff000 {
+                       compatible = "mmio-sram";
+                       reg = <0x2ffff000 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0 0x2ffff000 0x1000>;
+
+                       scmi_shm: scmi-sram@0 {
+                               compatible = "arm,scmi-shmem";
+                               reg = <0 0x80>;
+                       };
+               };
+
                uart4: serial@40010000 {
                        compatible = "st,stm32h7-uart";
                        reg = <0x40010000 0x400>;
                        interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&clk_hsi>;
+                       clocks = <&rcc UART4_K>;
+                       resets = <&rcc UART4_R>;
                        status = "disabled";
                };
 
                                     <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&clk_pclk4>;
+                       clocks = <&rcc DMA1>;
+                       resets = <&rcc DMA1_R>;
                        #dma-cells = <4>;
                        st,mem2mem;
                        dma-requests = <8>;
                                     <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&clk_pclk4>;
+                       clocks = <&rcc DMA2>;
+                       resets = <&rcc DMA2_R>;
                        #dma-cells = <4>;
                        st,mem2mem;
                        dma-requests = <8>;
                dmamux1: dma-router@48002000 {
                        compatible = "st,stm32h7-dmamux";
                        reg = <0x48002000 0x40>;
-                       clocks = <&clk_pclk4>;
+                       clocks = <&rcc DMAMUX1>;
+                       resets = <&rcc DMAMUX1_R>;
                        #dma-cells = <3>;
                        dma-masters = <&dma1 &dma2>;
                        dma-requests = <128>;
                        dma-channels = <16>;
                };
 
+               rcc: rcc@50000000 {
+                       compatible = "st,stm32mp13-rcc", "syscon";
+                       reg = <0x50000000 0x1000>;
+                       #clock-cells = <1>;
+                       #reset-cells = <1>;
+                       clock-names = "hse", "hsi", "csi", "lse", "lsi";
+                       clocks = <&scmi_clk CK_SCMI_HSE>,
+                                <&scmi_clk CK_SCMI_HSI>,
+                                <&scmi_clk CK_SCMI_CSI>,
+                                <&scmi_clk CK_SCMI_LSE>,
+                                <&scmi_clk CK_SCMI_LSI>;
+               };
+
                exti: interrupt-controller@5000d000 {
                        compatible = "st,stm32mp13-exti", "syscon";
                        interrupt-controller;
                syscfg: syscon@50020000 {
                        compatible = "st,stm32mp157-syscfg", "syscon";
                        reg = <0x50020000 0x400>;
-                       clocks = <&clk_pclk3>;
+                       clocks = <&rcc SYSCFG>;
                };
 
                mdma: dma-controller@58000000 {
                        compatible = "st,stm32h7-mdma";
                        reg = <0x58000000 0x1000>;
                        interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&clk_pclk4>;
+                       clocks = <&rcc MDMA>;
                        #dma-cells = <5>;
                        dma-channels = <32>;
                        dma-requests = <48>;
                        reg = <0x58005000 0x1000>, <0x58006000 0x1000>;
                        interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "cmd_irq";
-                       clocks = <&clk_pll4_p>;
+                       clocks = <&rcc SDMMC1_K>;
                        clock-names = "apb_pclk";
+                       resets = <&rcc SDMMC1_R>;
                        cap-sd-highspeed;
                        cap-mmc-highspeed;
                        max-frequency = <130000000>;
                        reg = <0x58007000 0x1000>, <0x58008000 0x1000>;
                        interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "cmd_irq";
-                       clocks = <&clk_pll4_p>;
+                       clocks = <&rcc SDMMC2_K>;
                        clock-names = "apb_pclk";
+                       resets = <&rcc SDMMC2_R>;
                        cap-sd-highspeed;
                        cap-mmc-highspeed;
                        max-frequency = <130000000>;
                iwdg2: watchdog@5a002000 {
                        compatible = "st,stm32mp1-iwdg";
                        reg = <0x5a002000 0x400>;
-                       clocks = <&clk_pclk4>, <&clk_lsi>;
+                       clocks = <&rcc IWDG2>, <&scmi_clk CK_SCMI_LSI>;
                        clock-names = "pclk", "lsi";
                        status = "disabled";
                };
                        compatible = "st,stm32mp1-rtc";
                        reg = <0x5c004000 0x400>;
                        interrupts-extended = <&exti 19 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&clk_pclk4>, <&clk_rtc_k>;
+                       clocks = <&scmi_clk CK_SCMI_RTCAPB>,
+                                <&scmi_clk CK_SCMI_RTC>;
                        clock-names = "pclk", "rtc_ck";
                        status = "disabled";
                };
                                interrupt-controller;
                                #interrupt-cells = <2>;
                                reg = <0x0 0x400>;
-                               clocks = <&clk_pclk4>;
+                               clocks = <&rcc GPIOA>;
                                st,bank-name = "GPIOA";
                                ngpios = <16>;
                                gpio-ranges = <&pinctrl 0 0 16>;
                                interrupt-controller;
                                #interrupt-cells = <2>;
                                reg = <0x1000 0x400>;
-                               clocks = <&clk_pclk4>;
+                               clocks = <&rcc GPIOB>;
                                st,bank-name = "GPIOB";
                                ngpios = <16>;
                                gpio-ranges = <&pinctrl 0 16 16>;
                                interrupt-controller;
                                #interrupt-cells = <2>;
                                reg = <0x2000 0x400>;
-                               clocks = <&clk_pclk4>;
+                               clocks = <&rcc GPIOC>;
                                st,bank-name = "GPIOC";
                                ngpios = <16>;
                                gpio-ranges = <&pinctrl 0 32 16>;
                                interrupt-controller;
                                #interrupt-cells = <2>;
                                reg = <0x3000 0x400>;
-                               clocks = <&clk_pclk4>;
+                               clocks = <&rcc GPIOD>;
                                st,bank-name = "GPIOD";
                                ngpios = <16>;
                                gpio-ranges = <&pinctrl 0 48 16>;
                                interrupt-controller;
                                #interrupt-cells = <2>;
                                reg = <0x4000 0x400>;
-                               clocks = <&clk_pclk4>;
+                               clocks = <&rcc GPIOE>;
                                st,bank-name = "GPIOE";
                                ngpios = <16>;
                                gpio-ranges = <&pinctrl 0 64 16>;
                                interrupt-controller;
                                #interrupt-cells = <2>;
                                reg = <0x5000 0x400>;
-                               clocks = <&clk_pclk4>;
+                               clocks = <&rcc GPIOF>;
                                st,bank-name = "GPIOF";
                                ngpios = <16>;
                                gpio-ranges = <&pinctrl 0 80 16>;
                                interrupt-controller;
                                #interrupt-cells = <2>;
                                reg = <0x6000 0x400>;
-                               clocks = <&clk_pclk4>;
+                               clocks = <&rcc GPIOG>;
                                st,bank-name = "GPIOG";
                                ngpios = <16>;
                                gpio-ranges = <&pinctrl 0 96 16>;
                                interrupt-controller;
                                #interrupt-cells = <2>;
                                reg = <0x7000 0x400>;
-                               clocks = <&clk_pclk4>;
+                               clocks = <&rcc GPIOH>;
                                st,bank-name = "GPIOH";
                                ngpios = <15>;
                                gpio-ranges = <&pinctrl 0 112 15>;
                                interrupt-controller;
                                #interrupt-cells = <2>;
                                reg = <0x8000 0x400>;
-                               clocks = <&clk_pclk4>;
+                               clocks = <&rcc GPIOI>;
                                st,bank-name = "GPIOI";
                                ngpios = <8>;
                                gpio-ranges = <&pinctrl 0 128 8>;
index 0fb1386..531c263 100644 (file)
@@ -15,7 +15,7 @@
                        interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "int0", "int1";
-                       clocks = <&clk_hse>, <&clk_pll4_r>;
+                       clocks = <&scmi_clk CK_SCMI_HSE>, <&rcc FDCAN_K>;
                        clock-names = "hclk", "cclk";
                        bosch,mram-cfg = <0x0 0 0 32 0 0 2 2>;
                        status = "disabled";
@@ -28,7 +28,7 @@
                        interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "int0", "int1";
-                       clocks = <&clk_hse>, <&clk_pll4_r>;
+                       clocks = <&scmi_clk CK_SCMI_HSE>, <&rcc FDCAN_K>;
                        clock-names = "hclk", "cclk";
                        bosch,mram-cfg = <0x1400 0 0 32 0 0 2 2>;
                        status = "disabled";
index 09d6226..e6b8ffd 100644 (file)
                reg = <0xc0000000 0x20000000>;
        };
 
+       reserved-memory {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               optee@dd000000 {
+                       reg = <0xdd000000 0x3000000>;
+                       no-map;
+               };
+       };
+
        gpio-keys {
                compatible = "gpio-keys";
 
index fa6889e..4d00e75 100644 (file)
@@ -10,7 +10,8 @@
                        compatible = "st,stm32mp1-cryp";
                        reg = <0x54002000 0x400>;
                        interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&clk_axi>;
+                       clocks = <&rcc CRYP1>;
+                       resets = <&rcc CRYP1_R>;
                        status = "disabled";
                };
        };
index fa6889e..4d00e75 100644 (file)
@@ -10,7 +10,8 @@
                        compatible = "st,stm32mp1-cryp";
                        reg = <0x54002000 0x400>;
                        interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&clk_axi>;
+                       clocks = <&rcc CRYP1>;
+                       resets = <&rcc CRYP1_R>;
                        status = "disabled";
                };
        };
index 6052243..2cc9341 100644 (file)
                };
        };
 
+       dcmi_pins_c: dcmi-2 {
+               pins {
+                       pinmux = <STM32_PINMUX('A', 4,  AF13)>,/* DCMI_HSYNC */
+                                <STM32_PINMUX('B', 7,  AF13)>,/* DCMI_VSYNC */
+                                <STM32_PINMUX('A', 6,  AF13)>,/* DCMI_PIXCLK */
+                                <STM32_PINMUX('A', 9,  AF13)>,/* DCMI_D0 */
+                                <STM32_PINMUX('H', 10, AF13)>,/* DCMI_D1 */
+                                <STM32_PINMUX('E', 0, AF13)>,/* DCMI_D2 */
+                                <STM32_PINMUX('E', 1, AF13)>,/* DCMI_D3 */
+                                <STM32_PINMUX('H', 14, AF13)>,/* DCMI_D4 */
+                                <STM32_PINMUX('I', 4,  AF13)>,/* DCMI_D5 */
+                                <STM32_PINMUX('I', 6,  AF13)>,/* DCMI_D6 */
+                                <STM32_PINMUX('E', 6,  AF13)>,/* DCMI_D7 */
+                                <STM32_PINMUX('I', 1,  AF13)>,/* DCMI_D8 */
+                                <STM32_PINMUX('H', 7,  AF13)>;/* DCMI_D9 */
+                       bias-pull-up;
+               };
+       };
+
+       dcmi_sleep_pins_c: dcmi-sleep-2 {
+               pins {
+                       pinmux = <STM32_PINMUX('A', 4,  ANALOG)>,/* DCMI_HSYNC */
+                                <STM32_PINMUX('B', 7,  ANALOG)>,/* DCMI_VSYNC */
+                                <STM32_PINMUX('A', 6,  ANALOG)>,/* DCMI_PIXCLK */
+                                <STM32_PINMUX('A', 9,  ANALOG)>,/* DCMI_D0 */
+                                <STM32_PINMUX('H', 10, ANALOG)>,/* DCMI_D1 */
+                                <STM32_PINMUX('E', 0, ANALOG)>,/* DCMI_D2 */
+                                <STM32_PINMUX('E', 1, ANALOG)>,/* DCMI_D3 */
+                                <STM32_PINMUX('H', 14, ANALOG)>,/* DCMI_D4 */
+                                <STM32_PINMUX('I', 4,  ANALOG)>,/* DCMI_D5 */
+                                <STM32_PINMUX('I', 6,  ANALOG)>,/* DCMI_D6 */
+                                <STM32_PINMUX('E', 6,  ANALOG)>,/* DCMI_D7 */
+                                <STM32_PINMUX('I', 1,  ANALOG)>,/* DCMI_D8 */
+                                <STM32_PINMUX('H', 7,  ANALOG)>;/* DCMI_D9 */
+               };
+       };
+
        ethernet0_rgmii_pins_a: rgmii-0 {
                pins1 {
                        pinmux = <STM32_PINMUX('G', 5, AF11)>, /* ETH_RGMII_CLK125 */
                };
        };
 
+       mco1_pins_a: mco1-0 {
+               pins {
+                       pinmux = <STM32_PINMUX('A', 13, AF2)>; /* MCO1 */
+                       bias-disable;
+                       drive-push-pull;
+                       slew-rate = <1>;
+               };
+       };
+
+       mco1_sleep_pins_a: mco1-sleep-0 {
+               pins {
+                       pinmux = <STM32_PINMUX('A', 13, ANALOG)>; /* MCO1 */
+               };
+       };
+
        mco2_pins_a: mco2-0 {
                pins {
                        pinmux = <STM32_PINMUX('G', 2, AF1)>; /* MCO2 */
                };
        };
 
+       m_can1_pins_c: m-can1-2 {
+               pins1 {
+                       pinmux = <STM32_PINMUX('H', 13, AF9)>; /* CAN1_TX */
+                       slew-rate = <1>;
+                       drive-push-pull;
+                       bias-disable;
+               };
+               pins2 {
+                       pinmux = <STM32_PINMUX('H', 14, AF9)>; /* CAN1_RX */
+                       bias-disable;
+               };
+       };
+
+       m_can1_sleep_pins_c: m_can1-sleep-2 {
+               pins {
+                       pinmux = <STM32_PINMUX('H', 13, ANALOG)>, /* CAN1_TX */
+                                <STM32_PINMUX('H', 14, ANALOG)>; /* CAN1_RX */
+               };
+       };
+
        m_can2_pins_a: m-can2-0 {
                pins1 {
                        pinmux = <STM32_PINMUX('B', 13, AF9)>; /* CAN2_TX */
 
        spi2_pins_a: spi2-0 {
                pins1 {
-                       pinmux = <STM32_PINMUX('B', 10, AF5)>, /* SPI1_SCK */
-                                <STM32_PINMUX('I', 3, AF5)>; /* SPI1_MOSI */
+                       pinmux = <STM32_PINMUX('B', 10, AF5)>, /* SPI2_SCK */
+                                <STM32_PINMUX('I', 3, AF5)>; /* SPI2_MOSI */
+                       bias-disable;
+                       drive-push-pull;
+                       slew-rate = <1>;
+               };
+
+               pins2 {
+                       pinmux = <STM32_PINMUX('I', 2, AF5)>; /* SPI2_MISO */
+                       bias-disable;
+               };
+       };
+
+       spi2_pins_b: spi2-1 {
+               pins1 {
+                       pinmux = <STM32_PINMUX('I', 1, AF5)>, /* SPI2_SCK */
+                                <STM32_PINMUX('I', 3, AF5)>; /* SPI2_MOSI */
                        bias-disable;
                        drive-push-pull;
                        slew-rate = <1>;
                };
 
                pins2 {
-                       pinmux = <STM32_PINMUX('I', 2, AF5)>; /* SPI1_MISO */
+                       pinmux = <STM32_PINMUX('I', 2, AF5)>; /* SPI2_MISO */
                        bias-disable;
                };
        };
                };
        };
 
+       uart4_pins_d: uart4-3 {
+               pins1 {
+                       pinmux = <STM32_PINMUX('A', 13, AF8)>; /* UART4_TX */
+                       bias-disable;
+                       drive-push-pull;
+                       slew-rate = <0>;
+               };
+               pins2 {
+                       pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+                       bias-disable;
+               };
+       };
+
+       uart4_idle_pins_d: uart4-idle-3 {
+               pins1 {
+                       pinmux = <STM32_PINMUX('A', 13, ANALOG)>; /* UART4_TX */
+               };
+               pins2 {
+                       pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+                       bias-disable;
+               };
+       };
+
+       uart4_sleep_pins_d: uart4-sleep-3 {
+               pins {
+                       pinmux = <STM32_PINMUX('A', 13, ANALOG)>, /* UART4_TX */
+                                <STM32_PINMUX('B', 2, ANALOG)>; /* UART4_RX */
+               };
+       };
+
+       uart5_pins_a: uart5-0 {
+               pins1 {
+                       pinmux = <STM32_PINMUX('B', 13, AF14)>; /* UART5_TX */
+                       bias-disable;
+                       drive-push-pull;
+                       slew-rate = <0>;
+               };
+               pins2 {
+                       pinmux = <STM32_PINMUX('B', 5, AF12)>; /* UART5_RX */
+                       bias-disable;
+               };
+       };
+
        uart7_pins_a: uart7-0 {
                pins1 {
                        pinmux = <STM32_PINMUX('E', 8, AF7)>; /* UART7_TX */
                };
        };
 
+       usart3_pins_e: usart3-4 {
+               pins1 {
+                       pinmux = <STM32_PINMUX('B', 10, AF7)>, /* USART3_TX */
+                                <STM32_PINMUX('G', 8, AF8)>; /* USART3_RTS */
+                       bias-disable;
+                       drive-push-pull;
+                       slew-rate = <0>;
+               };
+               pins2 {
+                       pinmux = <STM32_PINMUX('B', 11, AF7)>, /* USART3_RX */
+                                <STM32_PINMUX('D', 11, AF7)>; /* USART3_CTS_NSS */
+                       bias-pull-up;
+               };
+       };
+
+       usart3_idle_pins_e: usart3-idle-4 {
+               pins1 {
+                       pinmux = <STM32_PINMUX('B', 10, ANALOG)>, /* USART3_TX */
+                                <STM32_PINMUX('D', 11, ANALOG)>; /* USART3_CTS_NSS */
+               };
+               pins2 {
+                       pinmux = <STM32_PINMUX('G', 8, AF8)>; /* USART3_RTS */
+                       bias-disable;
+                       drive-push-pull;
+                       slew-rate = <0>;
+               };
+               pins3 {
+                       pinmux = <STM32_PINMUX('B', 11, AF7)>; /* USART3_RX */
+                       bias-pull-up;
+               };
+       };
+
+       usart3_sleep_pins_e: usart3-sleep-4 {
+               pins {
+                       pinmux = <STM32_PINMUX('B', 10, ANALOG)>, /* USART3_TX */
+                                <STM32_PINMUX('G', 8, ANALOG)>, /* USART3_RTS */
+                                <STM32_PINMUX('D', 11, ANALOG)>, /* USART3_CTS_NSS */
+                                <STM32_PINMUX('B', 11, ANALOG)>; /* USART3_RX */
+               };
+       };
+
        usbotg_hs_pins_a: usbotg-hs-0 {
                pins {
                        pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* OTG_ID */
diff --git a/arch/arm/boot/dts/stm32mp15-scmi.dtsi b/arch/arm/boot/dts/stm32mp15-scmi.dtsi
new file mode 100644 (file)
index 0000000..543f24c
--- /dev/null
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2022 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@foss.st.com> for STMicroelectronics.
+ */
+
+/ {
+       firmware {
+               optee: optee {
+                       compatible = "linaro,optee-tz";
+                       method = "smc";
+               };
+
+               scmi: scmi {
+                       compatible = "linaro,scmi-optee";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       linaro,optee-channel-id = <0>;
+                       shmem = <&scmi_shm>;
+
+                       scmi_clk: protocol@14 {
+                               reg = <0x14>;
+                               #clock-cells = <1>;
+                       };
+
+                       scmi_reset: protocol@16 {
+                               reg = <0x16>;
+                               #reset-cells = <1>;
+                       };
+
+                       scmi_voltd: protocol@17 {
+                               reg = <0x17>;
+
+                               scmi_reguls: regulators {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       scmi_reg11: reg11@0 {
+                                               reg = <0>;
+                                               regulator-name = "reg11";
+                                               regulator-min-microvolt = <1100000>;
+                                               regulator-max-microvolt = <1100000>;
+                                       };
+
+                                       scmi_reg18: reg18@1 {
+                                               voltd-name = "reg18";
+                                               reg = <1>;
+                                               regulator-name = "reg18";
+                                               regulator-min-microvolt = <1800000>;
+                                               regulator-max-microvolt = <1800000>;
+                                       };
+
+                                       scmi_usb33: usb33@2 {
+                                               reg = <2>;
+                                               regulator-name = "usb33";
+                                               regulator-min-microvolt = <3300000>;
+                                               regulator-max-microvolt = <3300000>;
+                                       };
+                               };
+                       };
+               };
+       };
+
+       soc {
+               scmi_sram: sram@2ffff000 {
+                       compatible = "mmio-sram";
+                       reg = <0x2ffff000 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0 0x2ffff000 0x1000>;
+
+                       scmi_shm: scmi-sram@0 {
+                               compatible = "arm,scmi-shmem";
+                               reg = <0 0x80>;
+                       };
+               };
+       };
+};
+
+&reg11 {
+       status = "disabled";
+};
+
+&reg18 {
+       status = "disabled";
+};
+
+&usb33 {
+       status = "disabled";
+};
+
+&usbotg_hs {
+       usb33d-supply = <&scmi_usb33>;
+};
+
+&usbphyc {
+       vdda1v1-supply = <&scmi_reg11>;
+       vdda1v8-supply = <&scmi_reg18>;
+};
+
+/delete-node/ &clk_hse;
+/delete-node/ &clk_hsi;
+/delete-node/ &clk_lse;
+/delete-node/ &clk_lsi;
+/delete-node/ &clk_csi;
index 1b2fd34..742fdee 100644 (file)
                status = "disabled";
        };
 
-       firmware {
-               optee: optee {
-                       compatible = "linaro,optee-tz";
-                       method = "smc";
-                       status = "disabled";
-               };
-
-               scmi: scmi {
-                       compatible = "linaro,scmi-optee";
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       linaro,optee-channel-id = <0>;
-                       shmem = <&scmi_shm>;
-                       status = "disabled";
-
-                       scmi_clk: protocol@14 {
-                               reg = <0x14>;
-                               #clock-cells = <1>;
-                       };
-
-                       scmi_reset: protocol@16 {
-                               reg = <0x16>;
-                               #reset-cells = <1>;
-                       };
-               };
-       };
-
        soc {
                compatible = "simple-bus";
                #address-cells = <1>;
                interrupt-parent = <&intc>;
                ranges;
 
-               scmi_sram: sram@2ffff000 {
-                       compatible = "mmio-sram";
-                       reg = <0x2ffff000 0x1000>;
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-                       ranges = <0 0x2ffff000 0x1000>;
-
-                       scmi_shm: scmi-sram@0 {
-                               compatible = "arm,scmi-shmem";
-                               reg = <0 0x80>;
-                               status = "disabled";
-                       };
-               };
-
                timers2: timer@40000000 {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        compatible = "st,stm32-cec";
                        reg = <0x40016000 0x400>;
                        interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&rcc CEC_K>, <&clk_lse>;
+                       clocks = <&rcc CEC_K>, <&rcc CEC>;
                        clock-names = "cec", "hdmi-cec";
                        status = "disabled";
                };
                        reg = <0x4c001000 0x400>;
                        st,proc-id = <0>;
                        interrupts-extended =
-                               <&intc GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
-                               <&intc GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
-                               <&exti 61 1>;
-                       interrupt-names = "rx", "tx", "wakeup";
+                               <&exti 61 1>,
+                               <&intc GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "rx", "tx";
                        clocks = <&rcc IPCC>;
                        wakeup-source;
                        status = "disabled";
                usbh_ohci: usb@5800c000 {
                        compatible = "generic-ohci";
                        reg = <0x5800c000 0x1000>;
-                       clocks = <&rcc USBH>, <&usbphyc>;
+                       clocks = <&usbphyc>, <&rcc USBH>;
                        resets = <&rcc USBH_R>;
                        interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
                        status = "disabled";
                usbh_ehci: usb@5800d000 {
                        compatible = "generic-ehci";
                        reg = <0x5800d000 0x1000>;
-                       clocks = <&rcc USBH>;
+                       clocks = <&usbphyc>, <&rcc USBH>;
                        resets = <&rcc USBH_R>;
                        interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
                        companion = <&usbh_ohci>;
diff --git a/arch/arm/boot/dts/stm32mp153c-dhcor-drc-compact.dts b/arch/arm/boot/dts/stm32mp153c-dhcor-drc-compact.dts
new file mode 100644 (file)
index 0000000..c8b9818
--- /dev/null
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Copyright (C) 2022 Marek Vasut <marex@denx.de>
+ *
+ * DHCOR STM32MP1 variant:
+ * DHCR-STM32MP153C-C065-R051-V33-SPI-I-01LG
+ * DHCOR PCB number: 586-100 or newer
+ * DRC Compact PCB number: 627-100 or newer
+ */
+
+/dts-v1/;
+
+#include "stm32mp153.dtsi"
+#include "stm32mp15xc.dtsi"
+#include "stm32mp15xx-dhcor-som.dtsi"
+#include "stm32mp15xx-dhcor-drc-compact.dtsi"
+
+/ {
+       model = "DH electronics STM32MP153C DHCOR DRC Compact";
+       compatible = "dh,stm32mp153c-dhcor-drc-compact",
+                    "dh,stm32mp153c-dhcor-som",
+                    "st,stm32mp153";
+};
+
+&m_can1 {
+       pinctrl-names = "default", "sleep";
+       pinctrl-0 = <&m_can1_pins_c>;
+       pinctrl-1 = <&m_can1_sleep_pins_c>;
+       status = "okay";
+};
index e3d3f3f..e539cc8 100644 (file)
@@ -7,6 +7,7 @@
 /dts-v1/;
 
 #include "stm32mp157a-dk1.dts"
+#include "stm32mp15-scmi.dtsi"
 
 / {
        model = "STMicroelectronics STM32MP157A-DK1 SCMI Discovery Board";
        clocks = <&scmi_clk CK_SCMI_MPU>;
 };
 
+&dsi {
+       clocks = <&rcc DSI_K>, <&scmi_clk CK_SCMI_HSE>, <&rcc DSI_PX>;
+};
+
 &gpioz {
        clocks = <&scmi_clk CK_SCMI_GPIOZ>;
 };
        resets = <&scmi_reset RST_SCMI_MCU>;
 };
 
-&optee {
-       status = "okay";
-};
-
 &rcc {
        compatible = "st,stm32mp1-rcc-secure", "syscon";
        clock-names = "hse", "hsi", "csi", "lse", "lsi";
 &rtc {
        clocks = <&scmi_clk CK_SCMI_RTCAPB>, <&scmi_clk CK_SCMI_RTC>;
 };
-
-&scmi {
-       status = "okay";
-};
-
-&scmi_shm {
-       status = "okay";
-};
index 45dcd29..97e4f94 100644 (file)
@@ -7,6 +7,7 @@
 /dts-v1/;
 
 #include "stm32mp157c-dk2.dts"
+#include "stm32mp15-scmi.dtsi"
 
 / {
        model = "STMicroelectronics STM32MP157C-DK2 SCMI Discovery Board";
@@ -34,6 +35,7 @@
 };
 
 &dsi {
+       phy-dsi-supply = <&scmi_reg18>;
        clocks = <&rcc DSI_K>, <&scmi_clk CK_SCMI_HSE>, <&rcc DSI_PX>;
 };
 
        resets = <&scmi_reset RST_SCMI_MCU>;
 };
 
-&optee {
-       status = "okay";
-};
-
 &rcc {
        compatible = "st,stm32mp1-rcc-secure", "syscon";
        clock-names = "hse", "hsi", "csi", "lse", "lsi";
 &rtc {
        clocks = <&scmi_clk CK_SCMI_RTCAPB>, <&scmi_clk CK_SCMI_RTC>;
 };
-
-&scmi {
-       status = "okay";
-};
-
-&scmi_shm {
-       status = "okay";
-};
index 458e0ca..9cf0a44 100644 (file)
@@ -7,6 +7,7 @@
 /dts-v1/;
 
 #include "stm32mp157c-ed1.dts"
+#include "stm32mp15-scmi.dtsi"
 
 / {
        model = "STMicroelectronics STM32MP157C-ED1 SCMI eval daughter";
        resets = <&scmi_reset RST_SCMI_CRYP1>;
 };
 
+&dsi {
+       clocks = <&rcc DSI_K>, <&scmi_clk CK_SCMI_HSE>, <&rcc DSI_PX>;
+};
+
 &gpioz {
        clocks = <&scmi_clk CK_SCMI_GPIOZ>;
 };
        resets = <&scmi_reset RST_SCMI_MCU>;
 };
 
-&optee {
-       status = "okay";
-};
-
 &rcc {
        compatible = "st,stm32mp1-rcc-secure", "syscon";
        clock-names = "hse", "hsi", "csi", "lse", "lsi";
 &rtc {
        clocks = <&scmi_clk CK_SCMI_RTCAPB>, <&scmi_clk CK_SCMI_RTC>;
 };
-
-&scmi {
-       status = "okay";
-};
-
-&scmi_shm {
-       status = "okay";
-};
index df9c113..3b9dd6f 100644 (file)
@@ -7,6 +7,7 @@
 /dts-v1/;
 
 #include "stm32mp157c-ev1.dts"
+#include "stm32mp15-scmi.dtsi"
 
 / {
        model = "STMicroelectronics STM32MP157C-EV1 SCMI eval daughter on eval mother";
@@ -35,6 +36,7 @@
 };
 
 &dsi {
+       phy-dsi-supply = <&scmi_reg18>;
        clocks = <&rcc DSI_K>, <&scmi_clk CK_SCMI_HSE>, <&rcc DSI_PX>;
 };
 
        resets = <&scmi_reset RST_SCMI_MCU>;
 };
 
-&optee {
-       status = "okay";
-};
-
 &rcc {
        compatible = "st,stm32mp1-rcc-secure", "syscon";
        clock-names = "hse", "hsi", "csi", "lse", "lsi";
 &rtc {
        clocks = <&scmi_clk CK_SCMI_RTCAPB>, <&scmi_clk CK_SCMI_RTC>;
 };
-
-&scmi {
-       status = "okay";
-};
-
-&scmi_shm {
-       status = "okay";
-};
index 76c54b0..9093307 100644 (file)
        };
 };
 
+&dcmi {
+       pinctrl-names = "default", "sleep";
+       pinctrl-0 = <&dcmi_pins_c>;
+       pinctrl-1 = <&dcmi_sleep_pins_c>;
+       status = "disabled";
+
+       port {
+               dcmi_0: endpoint {
+                       remote-endpoint = <&stmipi_2>;
+                       bus-type = <5>;
+                       bus-width = <8>;
+                       pclk-sample = <0>;
+               };
+       };
+};
+
 &ethernet0 {
        status = "okay";
        pinctrl-0 = <&ethernet0_rgmii_pins_c>;
 };
 
 &i2c4 {
+       stmipi: stmipi@14 {
+               compatible = "st,st-mipid02";
+               pinctrl-names = "default", "sleep";
+               pinctrl-0 = <&mco1_pins_a>;
+               pinctrl-1 = <&mco1_sleep_pins_a>;
+               reg = <0x14>;
+               clocks = <&rcc CK_MCO1>;
+               clock-names = "xclk";
+               assigned-clocks = <&rcc CK_MCO1>;
+               assigned-clock-parents = <&rcc CK_HSE>;
+               assigned-clock-rates = <24000000>;
+               VDDE-supply = <&v1v8>;
+               VDDIN-supply = <&v1v8>;
+               reset-gpios = <&gpioz 0 GPIO_ACTIVE_LOW>;
+               status = "disabled";
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+                               stmipi_0: endpoint {
+                               };
+                       };
+
+                       port@2 {
+                               reg = <2>;
+                               stmipi_2: endpoint {
+                                       bus-width = <8>;
+                                       hsync-active = <0>;
+                                       vsync-active = <0>;
+                                       pclk-sample = <0>;
+                                       remote-endpoint = <&dcmi_0>;
+                               };
+                       };
+               };
+       };
+
        hdmi-transmitter@3d {
                compatible = "adi,adv7513";
                reg = <0x3d>, <0x4d>, <0x2d>, <0x5d>;
diff --git a/arch/arm/boot/dts/stm32mp15xx-dhcor-drc-compact.dtsi b/arch/arm/boot/dts/stm32mp15xx-dhcor-drc-compact.dtsi
new file mode 100644 (file)
index 0000000..27477bb
--- /dev/null
@@ -0,0 +1,322 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Copyright (C) 2022 Marek Vasut <marex@denx.de>
+ */
+
+/ {
+       aliases {
+               ethernet0 = &ethernet0;
+               ethernet1 = &ksz8851;
+               mmc0 = &sdmmc1;
+               rtc0 = &hwrtc;
+               rtc1 = &rtc;
+               serial0 = &uart4;
+               serial1 = &uart8;
+               serial2 = &usart3;
+               serial3 = &uart5;
+               spi0 = &qspi;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       led {
+               compatible = "gpio-leds";
+               led1 {
+                       label = "yellow:user0";
+                       gpios = <&gpioz 6 GPIO_ACTIVE_LOW>;
+                       default-state = "off";
+               };
+
+               led2 {
+                       label = "red:user1";
+                       gpios = <&gpioz 3 GPIO_ACTIVE_LOW>;
+                       default-state = "off";
+               };
+       };
+
+       ethernet_vio: vioregulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vio";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               gpio = <&gpioh 2 GPIO_ACTIVE_LOW>;
+               regulator-always-on;
+               regulator-boot-on;
+               vin-supply = <&vdd>;
+       };
+};
+
+&adc { /* X11 ADC inputs */
+       pinctrl-names = "default";
+       pinctrl-0 = <&adc12_ain_pins_b>;
+       vdd-supply = <&vdd>;
+       vdda-supply = <&vdda>;
+       vref-supply = <&vdda>;
+       status = "okay";
+
+       adc1: adc@0 {
+               st,adc-channels = <0 1 6>;
+               st,min-sample-time-nsecs = <5000>;
+               status = "okay";
+       };
+
+       adc2: adc@100 {
+               st,adc-channels = <0 1 2>;
+               st,min-sample-time-nsecs = <5000>;
+               status = "okay";
+       };
+};
+
+&ethernet0 {
+       status = "okay";
+       pinctrl-0 = <&ethernet0_rgmii_pins_c>;
+       pinctrl-1 = <&ethernet0_rgmii_sleep_pins_c>;
+       pinctrl-names = "default", "sleep";
+       phy-mode = "rgmii";
+       max-speed = <1000>;
+       phy-handle = <&phy0>;
+
+       mdio0 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "snps,dwmac-mdio";
+               reset-gpios = <&gpioz 2 GPIO_ACTIVE_LOW>;
+               reset-delay-us = <1000>;
+               reset-post-delay-us = <1000>;
+
+               phy0: ethernet-phy@7 {
+                       reg = <7>;
+
+                       rxc-skew-ps = <1500>;
+                       rxdv-skew-ps = <540>;
+                       rxd0-skew-ps = <420>;
+                       rxd1-skew-ps = <420>;
+                       rxd2-skew-ps = <420>;
+                       rxd3-skew-ps = <420>;
+
+                       txc-skew-ps = <1440>;
+                       txen-skew-ps = <540>;
+                       txd0-skew-ps = <420>;
+                       txd1-skew-ps = <420>;
+                       txd2-skew-ps = <420>;
+                       txd3-skew-ps = <420>;
+               };
+       };
+};
+
+&fmc {
+       pinctrl-names = "default", "sleep";
+       pinctrl-0 = <&fmc_pins_b>;
+       pinctrl-1 = <&fmc_sleep_pins_b>;
+       status = "okay";
+
+       ksz8851: ethernet@1,0 {
+               compatible = "micrel,ks8851-mll";
+               reg = <1 0x0 0x2>, <1 0x2 0x20000>;
+               interrupt-parent = <&gpioc>;
+               interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+               bank-width = <2>;
+
+               /* Timing values are in nS */
+               st,fmc2-ebi-cs-mux-enable;
+               st,fmc2-ebi-cs-transaction-type = <4>;
+               st,fmc2-ebi-cs-buswidth = <16>;
+               st,fmc2-ebi-cs-address-setup-ns = <5>;
+               st,fmc2-ebi-cs-address-hold-ns = <5>;
+               st,fmc2-ebi-cs-bus-turnaround-ns = <5>;
+               st,fmc2-ebi-cs-data-setup-ns = <45>;
+               st,fmc2-ebi-cs-data-hold-ns = <1>;
+               st,fmc2-ebi-cs-write-address-setup-ns = <5>;
+               st,fmc2-ebi-cs-write-address-hold-ns = <5>;
+               st,fmc2-ebi-cs-write-bus-turnaround-ns = <5>;
+               st,fmc2-ebi-cs-write-data-setup-ns = <45>;
+               st,fmc2-ebi-cs-write-data-hold-ns = <1>;
+       };
+};
+
+&gpioa {
+       gpio-line-names = "", "", "", "",
+                         "DRCC-VAR2", "", "", "",
+                         "", "", "", "",
+                         "", "", "", "";
+};
+
+&gpioe {
+       gpio-line-names = "", "", "", "",
+                         "", "DRCC-GPIO0", "", "",
+                         "", "", "", "",
+                         "", "", "", "";
+};
+
+&gpiog {
+       gpio-line-names = "", "", "", "",
+                         "", "", "", "",
+                         "", "", "", "",
+                         "DRCC-GPIO5", "", "", "";
+};
+
+&gpioh {
+       gpio-line-names = "", "", "", "DRCC-HW2",
+                         "DRCC-GPIO4", "", "", "",
+                         "DRCC-HW1", "DRCC-HW0", "", "DRCC-VAR1",
+                         "DRCC-VAR0", "", "", "DRCC-GPIO6";
+};
+
+&gpioi {
+       gpio-line-names = "", "", "", "",
+                         "", "", "", "DRCC-GPIO2",
+                         "", "DRCC-GPIO1", "", "",
+                         "", "", "", "";
+};
+
+&i2c1 {        /* X11 I2C1 */
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c1_pins_b>;
+       i2c-scl-rising-time-ns = <185>;
+       i2c-scl-falling-time-ns = <20>;
+       status = "okay";
+       /delete-property/dmas;
+       /delete-property/dma-names;
+};
+
+&i2c4 {
+       hwrtc: rtc@32 {
+               compatible = "microcrystal,rv8803";
+               reg = <0x32>;
+       };
+
+       eeprom@50 {
+               compatible = "atmel,24c04";
+               reg = <0x50>;
+               pagesize = <16>;
+       };
+};
+
+&sdmmc1 {      /* MicroSD */
+       pinctrl-names = "default", "opendrain", "sleep";
+       pinctrl-0 = <&sdmmc1_b4_pins_a>;
+       pinctrl-1 = <&sdmmc1_b4_od_pins_a>;
+       pinctrl-2 = <&sdmmc1_b4_sleep_pins_a>;
+       cd-gpios = <&gpioi 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
+       disable-wp;
+       st,neg-edge;
+       bus-width = <4>;
+       vmmc-supply = <&vdd>;
+       vqmmc-supply = <&vdd>;
+       status = "okay";
+};
+
+&sdmmc2 {      /* eMMC */
+       pinctrl-names = "default", "opendrain", "sleep";
+       pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_c>;
+       pinctrl-1 = <&sdmmc2_b4_od_pins_a &sdmmc2_d47_pins_c>;
+       pinctrl-2 = <&sdmmc2_b4_sleep_pins_a &sdmmc2_d47_sleep_pins_c>;
+       bus-width = <8>;
+       no-sd;
+       no-sdio;
+       non-removable;
+       st,neg-edge;
+       vmmc-supply = <&v3v3>;
+       vqmmc-supply = <&vdd>;
+       status = "okay";
+};
+
+&sdmmc3 {      /* SDIO Wi-Fi */
+       pinctrl-names = "default", "opendrain", "sleep";
+       pinctrl-0 = <&sdmmc3_b4_pins_a>;
+       pinctrl-1 = <&sdmmc3_b4_od_pins_a>;
+       pinctrl-2 = <&sdmmc3_b4_sleep_pins_a>;
+       broken-cd;
+       bus-width = <4>;
+       mmc-ddr-3_3v;
+       st,neg-edge;
+       vmmc-supply = <&v3v3>;
+       vqmmc-supply = <&v3v3>;
+       status = "okay";
+};
+
+&spi2 {        /* X11 SPI */
+       pinctrl-names = "default";
+       pinctrl-0 = <&spi2_pins_b>;
+       cs-gpios = <&gpioi 0 0>;
+       status = "disabled";
+       /delete-property/dmas;
+       /delete-property/dma-names;
+};
+
+&uart4 {
+       label = "UART0";
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart4_pins_d>;
+       /delete-property/dmas;
+       /delete-property/dma-names;
+       status = "okay";
+};
+
+&uart5 {       /* X11 UART */
+       label = "X11-UART5";
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart5_pins_a>;
+       /delete-property/dmas;
+       /delete-property/dma-names;
+       status = "okay";
+};
+
+&uart8 {
+       label = "RS485-1";
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart8_pins_a &uart8_rtscts_pins_a>;
+       uart-has-rtscts;
+       /delete-property/dmas;
+       /delete-property/dma-names;
+       status = "okay";
+};
+
+&usart3 {      /* RS485 or RS232 */
+       label = "RS485-2";
+       pinctrl-names = "default", "sleep";
+       pinctrl-0 = <&usart3_pins_e>;
+       pinctrl-1 = <&usart3_sleep_pins_e>;
+       uart-has-rtscts;
+       /delete-property/dmas;
+       /delete-property/dma-names;
+       status = "okay";
+};
+
+&usbh_ehci {
+       phys = <&usbphyc_port0>;
+       status = "okay";
+};
+
+&usbh_ohci {
+       phys = <&usbphyc_port0>;
+       status = "okay";
+};
+
+&usbotg_hs {
+       dr_mode = "otg";
+       pinctrl-0 = <&usbotg_hs_pins_a>;
+       pinctrl-names = "default";
+       phy-names = "usb2-phy";
+       phys = <&usbphyc_port1 0>;
+       vbus-supply = <&vbus_otg>;
+       status = "okay";
+};
+
+&usbphyc {
+       status = "okay";
+};
+
+&usbphyc_port0 {
+       phy-supply = <&vdd_usb>;
+       connector {
+               compatible = "usb-a-connector";
+               vbus-supply = <&vbus_sw>;
+       };
+};
+
+&usbphyc_port1 {
+       phy-supply = <&vdd_usb>;
+};
index 7517231..9937b28 100644 (file)
        };
 };
 
+&vdd {
+       regulator-min-microvolt = <2900000>;
+       regulator-max-microvolt = <2900000>;
+};
+
 &pwr_regulators {
        vdd-supply = <&vdd_io>;
 };
index 6336c3c..134a798 100644 (file)
 
                        vdd: buck3 {
                                regulator-name = "vdd";
-                               regulator-min-microvolt = <2900000>;
-                               regulator-max-microvolt = <2900000>;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
                                regulator-always-on;
                                regulator-initial-mode = <0>;
                                regulator-over-current-protection;
index 6706d83..935b708 100644 (file)
                        no-map;
                };
        };
-
-       reg_sip_eeprom: regulator_eeprom {
-               compatible = "regulator-fixed";
-               regulator-name = "sip_eeprom";
-               regulator-always-on;
-       };
 };
 
 &i2c4 {
@@ -78,6 +72,7 @@
                        compatible = "st,stpmic1-regulators";
 
                        ldo1-supply = <&v3v3>;
+                       ldo3-supply = <&vdd_ddr>;
                        ldo6-supply = <&v3v3>;
                        pwr_sw1-supply = <&bst_out>;
 
 
        sip_eeprom: eeprom@50 {
                compatible = "atmel,24c32";
-               vcc-supply = <&reg_sip_eeprom>;
+               vcc-supply = <&vdd>;
                reg = <0x50>;
        };
 };
index 0a562b2..62e7aa5 100644 (file)
@@ -63,7 +63,7 @@
                compatible = "gpio-keys-polled";
                poll-interval = <20>;
 
-               left-joystick-left {
+               event-left-joystick-left {
                        label = "Left Joystick Left";
                        linux,code = <ABS_X>;
                        linux,input-type = <EV_ABS>;
@@ -71,7 +71,7 @@
                        gpios = <&pio 0 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA6 */
                };
 
-               left-joystick-right {
+               event-left-joystick-right {
                        label = "Left Joystick Right";
                        linux,code = <ABS_X>;
                        linux,input-type = <EV_ABS>;
@@ -79,7 +79,7 @@
                        gpios = <&pio 0 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA5 */
                };
 
-               left-joystick-up {
+               event-left-joystick-up {
                        label = "Left Joystick Up";
                        linux,code = <ABS_Y>;
                        linux,input-type = <EV_ABS>;
@@ -87,7 +87,7 @@
                        gpios = <&pio 0 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA8 */
                };
 
-               left-joystick-down {
+               event-left-joystick-down {
                        label = "Left Joystick Down";
                        linux,code = <ABS_Y>;
                        linux,input-type = <EV_ABS>;
@@ -95,7 +95,7 @@
                        gpios = <&pio 0 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA9 */
                };
 
-               right-joystick-left {
+               event-right-joystick-left {
                        label = "Right Joystick Left";
                        linux,code = <ABS_Z>;
                        linux,input-type = <EV_ABS>;
                        gpios = <&pio 0 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA1 */
                };
 
-               right-joystick-right {
+               event-right-joystick-right {
                        label = "Right Joystick Right";
                        linux,code = <ABS_Z>;
                        linux,input-type = <EV_ABS>;
                        gpios = <&pio 0 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA0 */
                };
 
-               right-joystick-up {
+               event-right-joystick-up {
                        label = "Right Joystick Up";
                        linux,code = <ABS_RZ>;
                        linux,input-type = <EV_ABS>;
                        gpios = <&pio 0 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA3 */
                };
 
-               right-joystick-down {
+               event-right-joystick-down {
                        label = "Right Joystick Down";
                        linux,code = <ABS_RZ>;
                        linux,input-type = <EV_ABS>;
                        gpios = <&pio 0 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA4 */
                };
 
-               dpad-left {
+               event-dpad-left {
                        label = "DPad Left";
                        linux,code = <ABS_HAT0X>;
                        linux,input-type = <EV_ABS>;
                        gpios = <&pio 7 23 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PH23 */
                };
 
-               dpad-right {
+               event-dpad-right {
                        label = "DPad Right";
                        linux,code = <ABS_HAT0X>;
                        linux,input-type = <EV_ABS>;
                        gpios = <&pio 7 24 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PH24 */
                };
 
-               dpad-up {
+               event-dpad-up {
                        label = "DPad Up";
                        linux,code = <ABS_HAT0Y>;
                        linux,input-type = <EV_ABS>;
                        gpios = <&pio 7 25 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PH25 */
                };
 
-               dpad-down {
+               event-dpad-down {
                        label = "DPad Down";
                        linux,code = <ABS_HAT0Y>;
                        linux,input-type = <EV_ABS>;
                        gpios = <&pio 7 26 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PH26 */
                };
 
-               x {
+               event-x {
                        label = "Button X";
                        linux,code = <BTN_X>;
                        gpios = <&pio 0 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA16 */
                };
 
-               y {
+               event-y {
                        label = "Button Y";
                        linux,code = <BTN_Y>;
                        gpios = <&pio 0 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA14 */
                };
 
-               a {
+               event-a {
                        label = "Button A";
                        linux,code = <BTN_A>;
                        gpios = <&pio 0 17 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA17 */
                };
 
-               b {
+               event-b {
                        label = "Button B";
                        linux,code = <BTN_B>;
                        gpios = <&pio 0 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA15 */
                };
 
-               select {
+               event-select {
                        label = "Select Button";
                        linux,code = <BTN_SELECT>;
                        gpios = <&pio 0 11 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA11 */
                };
 
-               start {
+               event-start {
                        label = "Start Button";
                        linux,code = <BTN_START>;
                        gpios = <&pio 0 12 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA12 */
                };
 
-               top-left {
+               event-top-left {
                        label = "Top Left Button";
                        linux,code = <BTN_TL>;
                        gpios = <&pio 7 22 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PH22 */
                };
 
-               top-right {
+               event-top-right {
                        label = "Top Right Button";
                        linux,code = <BTN_TR>;
                        gpios = <&pio 0 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PA13 */
index 1ac8237..a332d61 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               back {
+               key-back {
                        label = "Key Back";
                        linux,code = <KEY_BACK>;
                        gpios = <&pio 7 17 GPIO_ACTIVE_LOW>;
                };
 
-               home {
+               key-home {
                        label = "Key Home";
                        linux,code = <KEY_HOME>;
                        gpios = <&pio 7 18 GPIO_ACTIVE_LOW>;
                };
 
-               menu {
+               key-menu {
                        label = "Key Menu";
                        linux,code = <KEY_MENU>;
                        gpios = <&pio 7 19 GPIO_ACTIVE_LOW>;
index 2ce361f..3a6c4bd 100644 (file)
                compatible = "gpio-leds";
 
                led-0 {
-                       label ="licheepi:red:usr";
+                       label = "licheepi:red:usr";
                        gpios = <&pio 2 5 GPIO_ACTIVE_LOW>;
                };
 
                led-1 {
-                       label ="licheepi:green:usr";
+                       label = "licheepi:green:usr";
                        gpios = <&pio 2 19 GPIO_ACTIVE_LOW>;
                        default-state = "on";
                };
 
                led-2 {
-                       label ="licheepi:blue:usr";
+                       label = "licheepi:blue:usr";
                        gpios = <&pio 2 4 GPIO_ACTIVE_LOW>;
                };
 
index 715d748..70e634b 100644 (file)
@@ -46,6 +46,7 @@
 #include <dt-bindings/thermal/thermal.h>
 
 #include <dt-bindings/clock/sun6i-a31-ccu.h>
+#include <dt-bindings/clock/sun6i-rtc.h>
 #include <dt-bindings/reset/sun6i-a31-ccu.h>
 
 / {
                ccu: clock@1c20000 {
                        compatible = "allwinner,sun6i-a31-ccu";
                        reg = <0x01c20000 0x400>;
-                       clocks = <&osc24M>, <&rtc 0>;
+                       clocks = <&osc24M>, <&rtc CLK_OSC32K>;
                        clock-names = "hosc", "losc";
                        #clock-cells = <1>;
                        #reset-cells = <1>;
                                     <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&ccu CLK_APB1_PIO>, <&osc24M>, <&rtc 0>;
+                       clocks = <&ccu CLK_APB1_PIO>, <&osc24M>,
+                                <&rtc CLK_OSC32K>;
                        clock-names = "apb", "hosc", "losc";
                        gpio-controller;
                        interrupt-controller;
                        ar100: ar100_clk {
                                compatible = "allwinner,sun6i-a31-ar100-clk";
                                #clock-cells = <0>;
-                               clocks = <&rtc 0>, <&osc24M>,
+                               clocks = <&rtc CLK_OSC32K>, <&osc24M>,
                                         <&ccu CLK_PLL_PERIPH>,
                                         <&ccu CLK_PLL_PERIPH>;
                                clock-output-names = "ar100";
                        ir_clk: ir_clk {
                                #clock-cells = <0>;
                                compatible = "allwinner,sun4i-a10-mod0-clk";
-                               clocks = <&rtc 0>, <&osc24M>;
+                               clocks = <&rtc CLK_OSC32K>, <&osc24M>;
                                clock-output-names = "ir";
                        };
 
                        interrupt-parent = <&r_intc>;
                        interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&apb0_gates 0>, <&osc24M>, <&rtc 0>;
+                       clocks = <&apb0_gates 0>, <&osc24M>, <&rtc CLK_OSC32K>;
                        clock-names = "apb", "hosc", "losc";
                        resets = <&apb0_rst 0>;
                        gpio-controller;
index 4f8d55d..928b86a 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               back {
+               key-back {
                        label = "Key Back";
                        linux,code = <KEY_BACK>;
                        gpios = <&pio 7 17 GPIO_ACTIVE_LOW>;
                };
 
-               home {
+               key-home {
                        label = "Key Home";
                        linux,code = <KEY_HOME>;
                        gpios = <&pio 7 18 GPIO_ACTIVE_LOW>;
                };
 
-               menu {
+               key-menu {
                        label = "Key Menu";
                        linux,code = <KEY_MENU>;
                        gpios = <&pio 7 19 GPIO_ACTIVE_LOW>;
index 4461d50..1a262a0 100644 (file)
@@ -44,6 +44,7 @@
 
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 
+#include <dt-bindings/clock/sun6i-rtc.h>
 #include <dt-bindings/clock/sun8i-a23-a33-ccu.h>
 #include <dt-bindings/reset/sun8i-a23-a33-ccu.h>
 
 
                ccu: clock@1c20000 {
                        reg = <0x01c20000 0x400>;
-                       clocks = <&osc24M>, <&rtc 0>;
+                       clocks = <&osc24M>, <&rtc CLK_OSC32K>;
                        clock-names = "hosc", "losc";
                        #clock-cells = <1>;
                        #reset-cells = <1>;
                        reg = <0x01c20800 0x400>;
                        interrupt-parent = <&r_intc>;
                        /* interrupts get set in SoC specific dtsi file */
-                       clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&rtc 0>;
+                       clocks = <&ccu CLK_BUS_PIO>, <&osc24M>,
+                                <&rtc CLK_OSC32K>;
                        clock-names = "apb", "hosc", "losc";
                        gpio-controller;
                        interrupt-controller;
                        reg = <0x01f02c00 0x400>;
                        interrupt-parent = <&r_intc>;
                        interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&apb0_gates 0>, <&osc24M>, <&rtc 0>;
+                       clocks = <&apb0_gates 0>, <&osc24M>, <&rtc CLK_OSC32K>;
                        clock-names = "apb", "hosc", "losc";
                        resets = <&apb0_rst 0>;
                        gpio-controller;
index d5c7b79..d729b7c 100644 (file)
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               sw4 {
+               switch-4 {
                        label = "power";
                        linux,code = <KEY_POWER>;
                        gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
        wifi_pwrseq: wifi_pwrseq {
                compatible = "mmc-pwrseq-simple";
                reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 */
-               clocks = <&rtc 1>;
+               clocks = <&rtc CLK_OSC32K_FANOUT>;
                clock-names = "ext_clock";
        };
 };
        bluetooth {
                compatible = "brcm,bcm43438-bt";
                max-speed = <1500000>;
-               clocks = <&rtc 1>;
+               clocks = <&rtc CLK_OSC32K_FANOUT>;
                clock-names = "lpo";
                vbat-supply = <&reg_vcc3v3>;
                vddio-supply = <&reg_vcc3v3>;
index f19ed98..3706216 100644 (file)
        flash@0 {
                #address-cells = <1>;
                #size-cells = <1>;
-               compatible = "mxicy,mx25l1606e", "winbond,w25q128";
+               compatible = "mxicy,mx25l1606e", "jedec,spi-nor";
                reg = <0>;
                spi-max-frequency = <40000000>;
        };
index cd9f655..27a0d51 100644 (file)
                };
        };
 
-       r-gpio-keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               power {
+               key-power {
                        label = "power";
                        linux,code = <KEY_POWER>;
                        gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
        wifi_pwrseq: wifi_pwrseq {
                compatible = "mmc-pwrseq-simple";
                reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 */
-               clocks = <&rtc 1>;
+               clocks = <&rtc CLK_OSC32K_FANOUT>;
                clock-names = "ext_clock";
        };
 };
index ff0a7a9..f5c8ccc 100644 (file)
                };
        };
 
-       r_gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               power {
+               key-power {
                        label = "power";
                        linux,code = <KEY_POWER>;
                        gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>; /* PL3 */
                };
 
-               user {
+               key-user {
                        label = "user";
                        linux,code = <BTN_0>;
                        gpios = <&r_pio 0 4 GPIO_ACTIVE_LOW>;
index 8e7dfcf..43641cb 100644 (file)
                };
        };
 
-       r_gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               k1 {
+               key-0 {
                        label = "k1";
                        linux,code = <BTN_0>;
                        gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>; /* PL3 */
@@ -90,7 +90,7 @@
        wifi_pwrseq: wifi_pwrseq {
                compatible = "mmc-pwrseq-simple";
                reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 */
-               clocks = <&rtc 1>;
+               clocks = <&rtc CLK_OSC32K_FANOUT>;
                clock-names = "ext_clock";
        };
 
 
        bluetooth {
                compatible = "brcm,bcm43438-bt";
-               clocks = <&rtc 1>;
+               clocks = <&rtc CLK_OSC32K_FANOUT>;
                clock-names = "lpo";
                vbat-supply = <&reg_vcc3v3>;
                vddio-supply = <&reg_vcc3v3>;
index cd3df12..9e1a33f 100644 (file)
 
        bluetooth {
                compatible = "brcm,bcm43438-bt";
-               clocks = <&rtc 1>;
+               clocks = <&rtc CLK_OSC32K_FANOUT>;
                clock-names = "lpo";
                vbat-supply = <&reg_vcc3v3>;
                vddio-supply = <&reg_vcc3v3>;
index 26e2e61..42cd113 100644 (file)
@@ -46,7 +46,7 @@
        wifi_pwrseq: wifi_pwrseq {
                compatible = "mmc-pwrseq-simple";
                reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 */
-               clocks = <&rtc 1>;
+               clocks = <&rtc CLK_OSC32K_FANOUT>;
                clock-names = "ext_clock";
        };
 
 
        bluetooth {
                compatible = "brcm,bcm43438-bt";
-               clocks = <&rtc 1>;
+               clocks = <&rtc CLK_OSC32K_FANOUT>;
                clock-names = "lpo";
                vbat-supply = <&reg_vcc3v3>;
                vddio-supply = <&reg_vcc3v3>;
index a9f749f..cf8413f 100644 (file)
                };
        };
 
-       r_gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               k1 {
+               key-0 {
                        label = "k1";
                        linux,code = <KEY_POWER>;
                        gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
index 9daffd9..f1f9dbe 100644 (file)
                };
        };
 
-       r_gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               sw2 {
+               switch-2 {
                        label = "sw2";
                        linux,code = <BTN_1>;
                        gpios = <&r_pio 0 4 GPIO_ACTIVE_LOW>;
                };
 
-               sw4 {
+               switch-4 {
                        label = "sw4";
                        linux,code = <KEY_POWER>;
                        gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
index 6f9c97a..305b34a 100644 (file)
                };
        };
 
-       r_gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               sw4 {
+               switch-4 {
                        label = "sw4";
                        linux,code = <BTN_0>;
                        gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
index 4759ba3..59f6f6d 100644 (file)
                };
        };
 
-       r_gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               sw4 {
+               switch-4 {
                        label = "sw4";
                        linux,code = <BTN_0>;
                        gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
index 90f75fa..b96e015 100644 (file)
                };
        };
 
-       r_gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               sw4 {
+               switch-4 {
                        label = "sw4";
                        linux,code = <KEY_POWER>;
                        gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
index bf5b5e2..bc39468 100644 (file)
@@ -91,7 +91,7 @@
        wifi_pwrseq: wifi_pwrseq {
                compatible = "mmc-pwrseq-simple";
                reset-gpios = <&r_pio 0 6 GPIO_ACTIVE_LOW>; /* PL06 */
-               clocks = <&rtc 1>;
+               clocks = <&rtc CLK_OSC32K_FANOUT>;
                clock-names = "ext_clock";
        };
 };
 
        bluetooth {
                compatible = "brcm,bcm43438-bt";
-               clocks = <&rtc 1>;
+               clocks = <&rtc CLK_OSC32K_FANOUT>;
                clock-names = "lpo";
                vbat-supply = <&reg_dldo1>;
                vddio-supply = <&reg_aldo3>;
index a6a1087..28197bb 100644 (file)
@@ -43,6 +43,7 @@
 
 /dts-v1/;
 #include "sun8i-r40.dtsi"
+#include "sun8i-r40-cpu-opp.dtsi"
 
 #include <dt-bindings/gpio/gpio.h>
 
        status = "okay";
 };
 
+&cpu0 {
+       cpu-supply = <&reg_dcdc2>;
+};
+
 &de {
        status = "okay";
 };
diff --git a/arch/arm/boot/dts/sun8i-r40-cpu-opp.dtsi b/arch/arm/boot/dts/sun8i-r40-cpu-opp.dtsi
new file mode 100644 (file)
index 0000000..649928b
--- /dev/null
@@ -0,0 +1,52 @@
+/{
+       cpu0_opp_table: opp-table-cpu {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp-720000000 {
+                       opp-hz = /bits/ 64 <720000000>;
+                       opp-microvolt = <1000000 1000000 1300000>;
+                       clock-latency-ns = <2000000>;
+               };
+
+               opp-912000000 {
+                       opp-hz = /bits/ 64 <912000000>;
+                       opp-microvolt = <1100000 1100000 1300000>;
+                       clock-latency-ns = <2000000>;
+               };
+
+               opp-1008000000 {
+                       opp-hz = /bits/ 64 <1008000000>;
+                       opp-microvolt = <1160000 1160000 1300000>;
+                       clock-latency-ns = <2000000>;
+               };
+
+               opp-1104000000 {
+                       opp-hz = /bits/ 64 <1104000000>;
+                       opp-microvolt = <1240000 1240000 1300000>;
+                       clock-latency-ns = <2000000>;
+               };
+
+               opp-1200000000 {
+                       opp-hz = /bits/ 64 <1200000000>;
+                       opp-microvolt = <1300000 1300000 1300000>;
+                       clock-latency-ns = <2000000>;
+               };
+       };
+};
+
+&cpu0 {
+       operating-points-v2 = <&cpu0_opp_table>;
+};
+
+&cpu1 {
+       operating-points-v2 = <&cpu0_opp_table>;
+};
+
+&cpu2 {
+       operating-points-v2 = <&cpu0_opp_table>;
+};
+
+&cpu3 {
+       operating-points-v2 = <&cpu0_opp_table>;
+};
index 265e0fa..9f39b5a 100644 (file)
@@ -5,6 +5,11 @@
 //  Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
 
 #include "sun8i-r40.dtsi"
+#include "sun8i-r40-cpu-opp.dtsi"
+
+&cpu0 {
+       cpu-supply = <&reg_dcdc2>;
+};
 
 &i2c0 {
        status = "okay";
index 03d3e5f..4ef26d8 100644 (file)
@@ -42,6 +42,7 @@
  */
 
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/sun6i-rtc.h>
 #include <dt-bindings/clock/sun8i-de2.h>
 #include <dt-bindings/clock/sun8i-r40-ccu.h>
 #include <dt-bindings/clock/sun8i-tcon-top.h>
                        compatible = "arm,cortex-a7";
                        device_type = "cpu";
                        reg = <0>;
+                       clocks = <&ccu CLK_CPU>;
+                       clock-names = "cpu";
+                       #cooling-cells = <2>;
                };
 
                cpu1: cpu@1 {
                        compatible = "arm,cortex-a7";
                        device_type = "cpu";
                        reg = <1>;
+                       clocks = <&ccu CLK_CPU>;
+                       clock-names = "cpu";
+                       #cooling-cells = <2>;
                };
 
                cpu2: cpu@2 {
                        compatible = "arm,cortex-a7";
                        device_type = "cpu";
                        reg = <2>;
+                       clocks = <&ccu CLK_CPU>;
+                       clock-names = "cpu";
+                       #cooling-cells = <2>;
                };
 
                cpu3: cpu@3 {
                        compatible = "arm,cortex-a7";
                        device_type = "cpu";
                        reg = <3>;
+                       clocks = <&ccu CLK_CPU>;
+                       clock-names = "cpu";
+                       #cooling-cells = <2>;
                };
        };
 
                        polling-delay-passive = <0>;
                        polling-delay = <0>;
                        thermal-sensors = <&ths 0>;
+
+                       trips {
+                               cpu_hot_trip: cpu-hot {
+                                       temperature = <80000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+
+                               cpu_very_hot_trip: cpu-very-hot {
+                                       temperature = <115000>;
+                                       hysteresis = <0>;
+                                       type = "critical";
+                               };
+                       };
+
+                       cooling-maps {
+                               cpu-hot-limit {
+                                       trip = <&cpu_hot_trip>;
+                                       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>;
+                               };
+                       };
                };
 
                gpu_thermal: gpu-thermal {
                ccu: clock@1c20000 {
                        compatible = "allwinner,sun8i-r40-ccu";
                        reg = <0x01c20000 0x400>;
-                       clocks = <&osc24M>, <&rtc 0>;
+                       clocks = <&osc24M>, <&rtc CLK_OSC32K>;
                        clock-names = "hosc", "losc";
                        #clock-cells = <1>;
                        #reset-cells = <1>;
                        compatible = "allwinner,sun8i-r40-pinctrl";
                        reg = <0x01c20800 0x400>;
                        interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&rtc 0>;
+                       clocks = <&ccu CLK_BUS_PIO>, <&osc24M>,
+                                <&rtc CLK_OSC32K>;
                        clock-names = "apb", "hosc", "losc";
                        gpio-controller;
                        interrupt-controller;
                        reg-io-width = <1>;
                        interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&ccu CLK_BUS_HDMI0>, <&ccu CLK_HDMI_SLOW>,
-                                <&ccu CLK_HDMI>, <&rtc 0>;
+                                <&ccu CLK_HDMI>, <&rtc CLK_OSC32K>;
                        clock-names = "iahb", "isfr", "tmds", "cec";
                        resets = <&ccu RST_BUS_HDMI1>;
                        reset-names = "ctrl";
index 6931aaa..9f47252 100644 (file)
@@ -45,6 +45,7 @@
 
 /dts-v1/;
 #include "sun8i-r40.dtsi"
+#include "sun8i-r40-cpu-opp.dtsi"
 
 #include <dt-bindings/gpio/gpio.h>
 
        status = "okay";
 };
 
+&cpu0 {
+       cpu-supply = <&reg_dcdc2>;
+};
+
 &de {
        status = "okay";
 };
index 084323d..db194c6 100644 (file)
@@ -42,6 +42,7 @@
  */
 
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/sun6i-rtc.h>
 #include <dt-bindings/clock/sun8i-v3s-ccu.h>
 #include <dt-bindings/reset/sun8i-v3s-ccu.h>
 #include <dt-bindings/clock/sun8i-de2.h>
                ccu: clock@1c20000 {
                        compatible = "allwinner,sun8i-v3s-ccu";
                        reg = <0x01c20000 0x400>;
-                       clocks = <&osc24M>, <&rtc 0>;
+                       clocks = <&osc24M>, <&rtc CLK_OSC32K>;
                        clock-names = "hosc", "losc";
                        #clock-cells = <1>;
                        #reset-cells = <1>;
                        reg = <0x01c20800 0x400>;
                        interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&rtc 0>;
+                       clocks = <&ccu CLK_BUS_PIO>, <&osc24M>,
+                                <&rtc CLK_OSC32K>;
                        clock-names = "apb", "hosc", "losc";
                        gpio-controller;
                        #gpio-cells = <3>;
index 4795455..4348710 100644 (file)
@@ -42,6 +42,7 @@
 
 /dts-v1/;
 #include "sun8i-r40.dtsi"
+#include "sun8i-r40-cpu-opp.dtsi"
 
 #include <dt-bindings/gpio/gpio.h>
 
        status = "okay";
 };
 
+&cpu0 {
+       cpu-supply = <&reg_dcdc2>;
+};
+
 &de {
        status = "okay";
 };
diff --git a/arch/arm/boot/dts/sunplus-sp7021-achip.dtsi b/arch/arm/boot/dts/sunplus-sp7021-achip.dtsi
new file mode 100644 (file)
index 0000000..493d323
--- /dev/null
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device Tree Source for Sunplus SP7021
+ *
+ * Copyright (C) 2021 Sunplus Technology Co.
+ */
+
+#include "sunplus-sp7021.dtsi"
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+       compatible = "sunplus,sp7021-achip", "sunplus,sp7021";
+       model = "Sunplus SP7021 (CA7)";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       interrupt-parent = <&gic>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu0: cpu@0 {
+                       compatible = "arm,cortex-a7";
+                       device_type = "cpu";
+                       reg = <0>;
+                       clock-frequency = <931000000>;
+               };
+               cpu1: cpu@1 {
+                       compatible = "arm,cortex-a7";
+                       device_type = "cpu";
+                       reg = <1>;
+                       clock-frequency = <931000000>;
+               };
+               cpu2: cpu@2 {
+                       compatible = "arm,cortex-a7";
+                       device_type = "cpu";
+                       reg = <2>;
+                       clock-frequency = <931000000>;
+               };
+               cpu3: cpu@3 {
+                       compatible = "arm,cortex-a7";
+                       device_type = "cpu";
+                       reg = <3>;
+                       clock-frequency = <931000000>;
+               };
+       };
+
+       gic: interrupt-controller@9f101000 {
+               compatible = "arm,cortex-a7-gic";
+               interrupt-controller;
+               #interrupt-cells = <3>;
+               reg = <0x9f101000 0x1000>,
+                     <0x9f102000 0x2000>,
+                     <0x9f104000 0x2000>,
+                     <0x9f106000 0x2000>;
+       };
+
+       timer {
+               compatible = "arm,armv7-timer";
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+               clock-frequency = <XTAL>;
+               arm,cpu-registers-not-fw-configured;
+       };
+
+       arm-pmu {
+               compatible = "arm,cortex-a7-pmu";
+               interrupts = <GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 222 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
+       };
+
+       soc@9c000000 {
+               intc: interrupt-controller@780 {
+                       interrupt-parent = <&gic>;
+                       interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>, /* EXT_INT0 */
+                                    <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>; /* EXT_INT1 */
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/sunplus-sp7021-demo-v3.dts b/arch/arm/boot/dts/sunplus-sp7021-demo-v3.dts
new file mode 100644 (file)
index 0000000..d5c5ffc
--- /dev/null
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device Tree Source for Sunplus SP7021 Demo V3 SBC board
+ *
+ * Copyright (C) Sunplus Technology Co.
+ */
+
+/dts-v1/;
+
+#include "sunplus-sp7021-achip.dtsi"
+
+/ {
+       compatible = "sunplus,sp7021-demo-v3", "sunplus,sp7021";
+       model = "Sunplus SP7021/CA7/Demo_V3";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       aliases {
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x00000000 0x20000000>;
+       };
+};
diff --git a/arch/arm/boot/dts/sunplus-sp7021.dtsi b/arch/arm/boot/dts/sunplus-sp7021.dtsi
new file mode 100644 (file)
index 0000000..7dc4ce3
--- /dev/null
@@ -0,0 +1,310 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device Tree Source for Sunplus SP7021
+ *
+ * Copyright (C) 2021 Sunplus Technology Co.
+ */
+
+#include <dt-bindings/clock/sunplus,sp7021-clkc.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/reset/sunplus,sp7021-reset.h>
+#include <dt-bindings/pinctrl/sppctl-sp7021.h>
+#include <dt-bindings/gpio/gpio.h>
+
+#define XTAL   27000000
+
+/ {
+       compatible = "sunplus,sp7021";
+       model = "Sunplus SP7021";
+
+       clocks {
+               extclk: osc0 {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <XTAL>;
+                       clock-output-names = "extclk";
+               };
+       };
+
+       soc@9c000000 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0 0x9c000000 0x400000>;
+               interrupt-parent = <&intc>;
+
+               clkc: clock-controller@4 {
+                       compatible = "sunplus,sp7021-clkc";
+                       reg = <0x4 0x28>,
+                             <0x200 0x44>,
+                             <0x268 0x04>;
+                       clocks = <&extclk>;
+                       #clock-cells = <1>;
+               };
+
+               intc: interrupt-controller@780 {
+                       compatible = "sunplus,sp7021-intc";
+                       reg = <0x780 0x80>, <0xa80 0x80>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               otp: otp@af00 {
+                       compatible = "sunplus,sp7021-ocotp";
+                       reg = <0xaf00 0x34>, <0xaf80 0x58>;
+                       reg-names = "hb_gpio", "otprx";
+                       clocks = <&clkc CLK_OTPRX>;
+                       resets = <&rstc RST_OTPRX>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       therm_calib: thermal-calibration@14 {
+                               reg = <0x14 0x3>;
+                       };
+                       disc_vol: disconnect-voltage@18 {
+                               reg = <0x18 0x2>;
+                       };
+                       mac_addr0: mac-address0@34 {
+                               reg = <0x34 0x6>;
+                       };
+                       mac_addr1: mac-address1@3a {
+                               reg = <0x3a 0x6>;
+                       };
+               };
+
+               pctl: pinctrl@100 {
+                       compatible = "sunplus,sp7021-pctl";
+                       reg = <0x100 0x100>,
+                             <0x300 0x100>,
+                             <0x32e4 0x1C>,
+                             <0x80 0x20>;
+                       reg-names = "moon2", "gpioxt", "first", "moon1";
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       clocks = <&clkc CLK_GPIO>;
+                       resets = <&rstc RST_GPIO>;
+
+                       emac_pins: pinmux-emac-pins {
+                               sunplus,pins = <
+                                       SPPCTL_IOPAD(49,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_CLK_OUT,0)
+                                       SPPCTL_IOPAD(44,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_MAC_SMI_MDC,0)
+                                       SPPCTL_IOPAD(43,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_MAC_SMI_MDIO,0)
+                                       SPPCTL_IOPAD(52,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P0_MAC_RMII_TXEN,0)
+                                       SPPCTL_IOPAD(50,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P0_MAC_RMII_TXD0,0)
+                                       SPPCTL_IOPAD(51,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P0_MAC_RMII_TXD1,0)
+                                       SPPCTL_IOPAD(46,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P0_MAC_RMII_CRSDV,0)
+                                       SPPCTL_IOPAD(47,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P0_MAC_RMII_RXD0,0)
+                                       SPPCTL_IOPAD(48,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P0_MAC_RMII_RXD1,0)
+                                       SPPCTL_IOPAD(45,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P0_MAC_RMII_RXER,0)
+                                       SPPCTL_IOPAD(59,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P1_MAC_RMII_TXEN,0)
+                                       SPPCTL_IOPAD(57,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P1_MAC_RMII_TXD0,0)
+                                       SPPCTL_IOPAD(58,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P1_MAC_RMII_TXD1,0)
+                                       SPPCTL_IOPAD(54,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P1_MAC_RMII_CRSDV,0)
+                                       SPPCTL_IOPAD(55,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P1_MAC_RMII_RXD0,0)
+                                       SPPCTL_IOPAD(56,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P1_MAC_RMII_RXD1,0)
+                                       SPPCTL_IOPAD(53,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P1_MAC_RMII_RXER,0)
+                               >;
+                               sunplus,zerofunc = <
+                                       MUXF_L2SW_LED_FLASH0
+                                       MUXF_L2SW_LED_FLASH1
+                                       MUXF_L2SW_LED_ON0
+                                       MUXF_L2SW_LED_ON1
+                                       MUXF_DAISY_MODE
+                               >;
+                       };
+
+                       emmc_pins: pinmux-emmc-pins {
+                               function = "CARD0_EMMC";
+                               groups = "CARD0_EMMC";
+                       };
+
+                       leds_pins: pinmux-leds-pins {
+                               sunplus,pins = < SPPCTL_IOPAD(0,SPPCTL_PCTL_G_GPIO,0,SPPCTL_PCTL_L_OUT) >;
+                       };
+
+                       sdcard_pins: pinmux-sdcard-pins {
+                               function = "SD_CARD";
+                               groups = "SD_CARD";
+                               sunplus,pins = < SPPCTL_IOPAD(91, SPPCTL_PCTL_G_GPIO, 0, 0) >;
+                       };
+
+                       spi0_pins: pinmux-spi0-pins {
+                               sunplus,pins = <
+                                       SPPCTL_IOPAD(26,SPPCTL_PCTL_G_GPIO,0,0)
+                                       SPPCTL_IOPAD(28,SPPCTL_PCTL_G_GPIO,0,0)
+                                       SPPCTL_IOPAD(23,SPPCTL_PCTL_G_PMUX,MUXF_SPI0S_DO,0)
+                                       SPPCTL_IOPAD(25,SPPCTL_PCTL_G_PMUX,MUXF_SPI0S_DI,0)
+                                       SPPCTL_IOPAD(27,SPPCTL_PCTL_G_PMUX,MUXF_SPI0S_CLK,0)
+                               >;
+                       };
+
+                       uart0_pins: pinmux-uart0-pins {
+                               function = "UA0";
+                               groups = "UA0";
+                       };
+
+                       uart1_pins: pinmux-uart1-pins {
+                               sunplus,pins = <
+                                       SPPCTL_IOPAD(14,SPPCTL_PCTL_G_PMUX,MUXF_UA4_TX,0)
+                                       SPPCTL_IOPAD(16,SPPCTL_PCTL_G_PMUX,MUXF_UA4_RX,0)
+                               >;
+                       };
+
+                       uart2_pins: pinmux-uart2-pins {
+                               sunplus,pins = <
+                                       SPPCTL_IOPAD(16,SPPCTL_PCTL_G_PMUX,MUXF_UA2_TX,0)
+                                       SPPCTL_IOPAD(17,SPPCTL_PCTL_G_PMUX,MUXF_UA2_RX,0)
+                                       SPPCTL_IOPAD(18,SPPCTL_PCTL_G_PMUX,MUXF_UA2_RTS,0)
+                                       SPPCTL_IOPAD(19,SPPCTL_PCTL_G_PMUX,MUXF_UA2_CTS,0)
+                               >;
+                       };
+
+                       uart4_pins: pinmux-uart4-pins {
+                               sunplus,pins = <
+                                       SPPCTL_IOPAD(22,SPPCTL_PCTL_G_PMUX,MUXF_UA4_TX,0)
+                                       SPPCTL_IOPAD(20,SPPCTL_PCTL_G_PMUX,MUXF_UA4_RX,0)
+                                       SPPCTL_IOPAD(23,SPPCTL_PCTL_G_PMUX,MUXF_UA4_RTS,0)
+                                       SPPCTL_IOPAD(21,SPPCTL_PCTL_G_PMUX,MUXF_UA4_CTS,0)
+                               >;
+                       };
+               };
+
+               rstc: reset@54 {
+                       compatible = "sunplus,sp7021-reset";
+                       reg = <0x54 0x28>;
+                       #reset-cells = <1>;
+               };
+
+               rtc: rtc@3a00 {
+                       compatible = "sunplus,sp7021-rtc";
+                       reg = <0x3a00 0x80>;
+                       reg-names = "rtc";
+                       clocks = <&clkc CLK_RTC>;
+                       resets = <&rstc RST_RTC>;
+                       interrupts = <163 IRQ_TYPE_EDGE_RISING>;
+               };
+
+               spi_controller0: spi@2d80 {
+                       compatible = "sunplus,sp7021-spi";
+                       reg = <0x2d80 0x80>, <0x2e00 0x80>;
+                       reg-names = "master", "slave";
+                       interrupts = <144 IRQ_TYPE_LEVEL_HIGH>,
+                                    <146 IRQ_TYPE_LEVEL_HIGH>,
+                                    <145 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "dma_w", "master_risc", "slave_risc";
+                       clocks = <&clkc CLK_SPI_COMBO_0>;
+                       resets = <&rstc RST_SPI_COMBO_0>;
+
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&spi0_pins>;
+                       cs-gpios = <&pctl 26 GPIO_ACTIVE_LOW>,
+                                  <&pctl 28 GPIO_ACTIVE_LOW>;
+               };
+
+               spi_controller1: spi@f480 {
+                       compatible = "sunplus,sp7021-spi";
+                       reg = <0xf480 0x80>, <0xf500 0x80>;
+                       reg-names = "master", "slave";
+                       interrupts = <67 IRQ_TYPE_LEVEL_HIGH>,
+                                    <69 IRQ_TYPE_LEVEL_HIGH>,
+                                    <68 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "dma_w", "master_risc", "slave_risc";
+                       clocks = <&clkc CLK_SPI_COMBO_1>;
+                       resets = <&rstc RST_SPI_COMBO_1>;
+                       spi-max-frequency = <25000000>;
+                       status = "disabled";
+               };
+
+               spi_controller2: spi@f600 {
+                       compatible = "sunplus,sp7021-spi";
+                       reg = <0xf600 0x80>, <0xf680 0x80>;
+                       reg-names = "master", "slave";
+                       interrupts = <70 IRQ_TYPE_LEVEL_HIGH>,
+                                    <72 IRQ_TYPE_LEVEL_HIGH>,
+                                    <71 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "dma_w", "master_risc", "slave_risc";
+                       clocks = <&clkc CLK_SPI_COMBO_2>;
+                       resets = <&rstc RST_SPI_COMBO_2>;
+                       spi-max-frequency = <25000000>;
+                       status = "disabled";
+               };
+
+               spi_controller3: spi@f780 {
+                       compatible = "sunplus,sp7021-spi";
+                       reg = <0xf780 0x80>, <0xf800 0x80>;
+                       reg-names = "master", "slave";
+                       interrupts = <73 IRQ_TYPE_LEVEL_HIGH>,
+                                    <75 IRQ_TYPE_LEVEL_HIGH>,
+                                    <74 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "dma_w", "master_risc", "slave_risc";
+                       clocks = <&clkc CLK_SPI_COMBO_3>;
+                       resets = <&rstc RST_SPI_COMBO_3>;
+                       spi-max-frequency = <25000000>;
+                       status = "disabled";
+               };
+
+               uart0: serial@900 {
+                       compatible = "sunplus,sp7021-uart";
+                       reg = <0x900 0x80>;
+                       interrupts = <53 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clkc CLK_UA0>;
+                       resets = <&rstc RST_UA0>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&uart0_pins>;
+               };
+
+               uart1: serial@980 {
+                       compatible = "sunplus,sp7021-uart";
+                       reg = <0x980 0x80>;
+                       interrupts = <54 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clkc CLK_UA1>;
+                       resets = <&rstc RST_UA1>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&uart1_pins>;
+                       status = "disabled";
+               };
+
+               uart2: serial@800 {
+                       compatible = "sunplus,sp7021-uart";
+                       reg = <0x800 0x80>;
+                       interrupts = <55 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clkc CLK_UA2>;
+                       resets = <&rstc RST_UA2>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&uart2_pins>;
+                       status = "disabled";
+               };
+
+               uart3: serial@880 {
+                       compatible = "sunplus,sp7021-uart";
+                       reg = <0x880 0x80>;
+                       interrupts = <56 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clkc CLK_UA3>;
+                       resets = <&rstc RST_UA3>;
+                       status = "disabled";
+               };
+
+               uart4: serial@8780 {
+                       compatible = "sunplus,sp7021-uart";
+                       reg = <0x8780 0x80>;
+                       interrupts = <134 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clkc CLK_UA4>;
+                       resets = <&rstc RST_UA4>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&uart4_pins>;
+                       status = "disabled";
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+               pinctrl-names = "default";
+               pinctrl-0 = <&leds_pins>;
+               system-led {
+                       label = "system-led";
+                       gpios = <&pctl 0 GPIO_ACTIVE_HIGH>;
+                       default-state = "off";
+                       linux,default-trigger = "heartbeat";
+               };
+       };
+};
index d03f585..e899d14 100644 (file)
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               sw4 {
+               switch-4 {
                        label = "power";
                        linux,code = <KEY_POWER>;
                        gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
        wifi_pwrseq: wifi_pwrseq {
                compatible = "mmc-pwrseq-simple";
                reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 */
-               clocks = <&rtc 1>;
+               clocks = <&rtc CLK_OSC32K_FANOUT>;
                clock-names = "ext_clock";
        };
 };
        bluetooth {
                compatible = "brcm,bcm43438-bt";
                max-speed = <1500000>;
-               clocks = <&rtc 1>;
+               clocks = <&rtc CLK_OSC32K_FANOUT>;
                clock-names = "lpo";
                vbat-supply = <&reg_vcc3v3>;
                vddio-supply = <&reg_vcc3v3>;
index fc67e30..60804b0 100644 (file)
@@ -22,7 +22,7 @@
                compatible = "mmc-pwrseq-simple";
                reset-gpios = <&pio 2 7 GPIO_ACTIVE_LOW>; /* PC7 */
                post-power-on-delay-ms = <200>;
-               clocks = <&rtc 1>;
+               clocks = <&rtc CLK_OSC32K_FANOUT>;
                clock-names = "ext_clock";
        };
 };
 
        bluetooth {
                compatible = "brcm,bcm43438-bt";
-               clocks = <&rtc 1>;
+               clocks = <&rtc CLK_OSC32K_FANOUT>;
                clock-names = "lpo";
                vbat-supply = <&reg_vcc3v3>;
                vddio-supply = <&reg_vcc3v3>;
index d7e9f97..09aefb4 100644 (file)
@@ -40,6 +40,7 @@
  *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
+#include <dt-bindings/clock/sun6i-rtc.h>
 #include <dt-bindings/clock/sun8i-de2.h>
 #include <dt-bindings/clock/sun8i-h3-ccu.h>
 #include <dt-bindings/clock/sun8i-r-ccu.h>
                ccu: clock@1c20000 {
                        /* compatible is in per SoC .dtsi file */
                        reg = <0x01c20000 0x400>;
-                       clocks = <&osc24M>, <&rtc 0>;
+                       clocks = <&osc24M>, <&rtc CLK_OSC32K>;
                        clock-names = "hosc", "losc";
                        #clock-cells = <1>;
                        #reset-cells = <1>;
                        interrupt-parent = <&r_intc>;
                        interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&rtc 0>;
+                       clocks = <&ccu CLK_BUS_PIO>, <&osc24M>,
+                                <&rtc CLK_OSC32K>;
                        clock-names = "apb", "hosc", "losc";
                        gpio-controller;
                        #gpio-cells = <3>;
                        reg-io-width = <1>;
                        interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&ccu CLK_BUS_HDMI>, <&ccu CLK_HDMI_DDC>,
-                                <&ccu CLK_HDMI>, <&rtc 0>;
+                                <&ccu CLK_HDMI>, <&rtc CLK_OSC32K>;
                        clock-names = "iahb", "isfr", "tmds", "cec";
                        resets = <&ccu RST_BUS_HDMI1>;
                        reset-names = "ctrl";
                r_ccu: clock@1f01400 {
                        compatible = "allwinner,sun8i-h3-r-ccu";
                        reg = <0x01f01400 0x100>;
-                       clocks = <&osc24M>, <&rtc 0>, <&rtc 2>,
+                       clocks = <&osc24M>, <&rtc CLK_OSC32K>, <&rtc CLK_IOSC>,
                                 <&ccu CLK_PLL_PERIPH0>;
                        clock-names = "hosc", "losc", "iosc", "pll-periph";
                        #clock-cells = <1>;
                        reg = <0x01f02c00 0x400>;
                        interrupt-parent = <&r_intc>;
                        interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&r_ccu CLK_APB0_PIO>, <&osc24M>, <&rtc 0>;
+                       clocks = <&r_ccu CLK_APB0_PIO>, <&osc24M>,
+                                <&rtc CLK_OSC32K>;
                        clock-names = "apb", "hosc", "losc";
                        gpio-controller;
                        #gpio-cells = <3>;
index 9e14fe5..89731bb 100644 (file)
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               power {
+               key-power {
                        label = "power";
                        linux,code = <KEY_POWER>;
                        gpios = <&r_pio 0 2 GPIO_ACTIVE_LOW>; /* PL2 */
index b791ce9..284209b 100644 (file)
                pinctrl-names = "default";
                pinctrl-0 = <&gpio_keys_default>;
 
-               power {
+               button-power {
                        label = "Power";
                        gpios = <&gpio TEGRA_GPIO(Q, 0) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
                        wakeup-source;
                };
 
-               volume-up {
+               button-volume-up {
                        label = "Volume Up";
                        gpios = <&gpio TEGRA_GPIO(R, 2) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
                        debounce-interval = <10>;
                };
 
-               volume-down {
+               button-volume-down {
                        label = "Volume Down";
                        gpios = <&gpio TEGRA_GPIO(R, 1) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEDOWN>;
                pinctrl-names = "default";
                pinctrl-0 = <&gpio_hall_sensor_default>;
 
-               hall-sensor {
+               switch-hall-sensor {
                        label = "Hall Effect Sensor";
                        gpios = <&gpio TEGRA_GPIO(O, 5) GPIO_ACTIVE_LOW>;
                        linux,input-type = <EV_SW>;
index 658edfb..fffd62b 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               home {
+               key-home {
                        label = "Home";
                        gpios = <&gpio TEGRA_GPIO(I, 5) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_HOME>;
                };
 
-               power {
+               key-power {
                        label = "Power";
                        gpios = <&gpio TEGRA_GPIO(Q, 0) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
                        wakeup-source;
                };
 
-               volume_down {
+               key-volume-down {
                        label = "Volume Down";
                        gpios = <&gpio TEGRA_GPIO(R, 1) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEDOWN>;
                };
 
-               volume_up {
+               key-volume-up {
                        label = "Volume Up";
                        gpios = <&gpio TEGRA_GPIO(R, 2) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
index 2498cf1..b9d0000 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               back {
+               key-back {
                        label = "Back";
                        gpios = <&gpio TEGRA_GPIO(R, 2) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_BACK>;
                };
 
-               home {
+               key-home {
                        label = "Home";
                        gpios = <&gpio TEGRA_GPIO(R, 1) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_HOME>;
                };
 
-               power {
+               key-power {
                        label = "Power";
                        gpios = <&gpio TEGRA_GPIO(Q, 0) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
index ef8f722..f02d8c7 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               power {
+               key-power {
                        label = "Power";
                        gpios = <&gpio TEGRA_GPIO(Q, 0) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
                        wakeup-source;
                };
 
-               volume_down {
+               key-volume-down {
                        label = "Volume Down";
                        gpios = <&gpio TEGRA_GPIO(Q, 2) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEDOWN>;
                };
 
-               volume_up {
+               key-volume-up {
                        label = "Volume Up";
                        gpios = <&gpio TEGRA_GPIO(R, 2) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
index 3209554..bce12b3 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               wakeup {
+               key-wakeup {
                        label = "WAKE1_MICO";
                        gpios = <&gpio TEGRA_GPIO(DD, 3) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_WAKEUP>;
index 814257c..800283a 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               wakeup {
+               key-wakeup {
                        label = "WAKE1_MICO";
                        gpios = <&gpio TEGRA_GPIO(DD, 3) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_WAKEUP>;
index 28b889e..f41dd40 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               power {
+               key-power {
                        label = "Power";
                        gpios = <&gpio TEGRA_GPIO(Q, 0) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
index a93cfb4..13061ab 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               lid {
+               switch-lid {
                        label = "Lid";
                        gpios = <&gpio TEGRA_GPIO(R, 4) GPIO_ACTIVE_LOW>;
                        linux,input-type = <5>;
                        wakeup-source;
                };
 
-               power {
+               key-power {
                        label = "Power";
                        gpios = <&gpio TEGRA_GPIO(Q, 0) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
index 6a9592c..8f40fcf 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               power {
+               key-power {
                        label = "Power";
                        gpios = <&gpio TEGRA_GPIO(Q, 0) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
index a170a4b..dac6d02 100644 (file)
                        vddio-supply = <&vdd_1v8_sys>;
 
                        device-wakeup-gpios = <&gpio TEGRA_GPIO(U, 1) GPIO_ACTIVE_HIGH>;
-                       shutdown-gpios =      <&gpio TEGRA_GPIO(U, 0) GPIO_ACTIVE_HIGH>;
+                       shutdown-gpios = <&gpio TEGRA_GPIO(U, 0) GPIO_ACTIVE_HIGH>;
                };
        };
 
        gpio-keys {
                compatible = "gpio-keys";
 
-               power {
+               key-power {
                        label = "Power";
                        gpios = <&gpio TEGRA_GPIO(I, 3) GPIO_ACTIVE_HIGH>;
                        linux,code = <KEY_POWER>;
                        wakeup-source;
                };
 
-               rotation-lock {
+               key-rotation-lock {
                        label = "Rotate-lock";
                        gpios = <&gpio TEGRA_GPIO(Q, 2) GPIO_ACTIVE_HIGH>;
                        linux,code = <SW_ROTATE_LOCK>;
                        debounce-interval = <10>;
                };
 
-               volume-up {
+               key-volume-up {
                        label = "Volume Up";
                        gpios = <&gpio TEGRA_GPIO(Q, 4) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
                        wakeup-source;
                };
 
-               volume-down {
+               key-volume-down {
                        label = "Volume Down";
                        gpios = <&gpio TEGRA_GPIO(Q, 5) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEDOWN>;
index a054d39..bf797a1 100644 (file)
                        vddio-supply = <&vdd_1v8_sys>;
 
                        device-wakeup-gpios = <&gpio TEGRA_GPIO(U, 1) GPIO_ACTIVE_HIGH>;
-                       shutdown-gpios =      <&gpio TEGRA_GPIO(U, 0) GPIO_ACTIVE_HIGH>;
+                       shutdown-gpios = <&gpio TEGRA_GPIO(U, 0) GPIO_ACTIVE_HIGH>;
                };
        };
 
        gpio-keys {
                compatible = "gpio-keys";
 
-               dock-hall-sensor {
+               switch-dock-hall-sensor {
                        label = "Lid";
                        gpios = <&gpio TEGRA_GPIO(S, 4) GPIO_ACTIVE_LOW>;
                        linux,input-type = <EV_SW>;
                        wakeup-source;
                };
 
-               power {
+               key-power {
                        label = "Power";
                        gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
                        wakeup-source;
                };
 
-               volume-up {
+               key-volume-up {
                        label = "Volume Up";
                        gpios = <&gpio TEGRA_GPIO(Q, 5) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
                        wakeup-source;
                };
 
-               volume-down {
+               key-volume-down {
                        label = "Volume Down";
                        gpios = <&gpio TEGRA_GPIO(Q, 4) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEDOWN>;
index d2a3bf9..cb1190b 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               wakeup {
+               key-wakeup {
                        label = "SODIMM pin 45 wakeup";
                        gpios = <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
                        linux,code = <KEY_WAKEUP>;
index 00ecbbd..53487cc 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               wakeup {
+               key-wakeup {
                        label = "SODIMM pin 45 wakeup";
                        gpios = <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
                        linux,code = <KEY_WAKEUP>;
index 79b6b79..11f21ae 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               power {
+               key-power {
                        label = "Power";
                        gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
index 0fb4b1f..48fe628 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               wakeup {
+               key-wakeup {
                        label = "Wakeup";
                        gpios = <&gpio TEGRA_GPIO(J, 7) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_WAKEUP>;
index c4a6a6a..5b4c5ef 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               power {
+               key-power {
                        label = "Power";
                        gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
                        wakeup-source;
                };
 
-               lid {
+               switch-lid {
                        label = "Lid";
                        gpios = <&gpio TEGRA_GPIO(C, 7) GPIO_ACTIVE_HIGH>;
                        linux,input-type = <5>; /* EV_SW */
index 9d0c867..dc51835 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               power {
+               key-power {
                        label = "Power";
                        gpios = <&gpio TEGRA_GPIO(X, 6) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
index b0a0097..caa17e8 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               power {
+               key-power {
                        label = "Power";
                        gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
index 93b83b3..ad968ff 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               wakeup {
+               key-wakeup {
                        label = "WAKE1_MICO";
                        gpios = <&gpio TEGRA_GPIO(V, 1) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_WAKEUP>;
index fbfa75e..c172fdb 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               wakeup {
+               key-wakeup {
                        label = "WAKE1_MICO";
                        gpios = <&gpio TEGRA_GPIO(V, 1) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_WAKEUP>;
index 2c2ad2a..ee683c5 100644 (file)
@@ -63,7 +63,7 @@
        gpio@6000d000 {
                init-mode-hog {
                        gpio-hog;
-                       gpios = <TEGRA_GPIO(DD, 7) GPIO_ACTIVE_HIGH>,
+                       gpios = <TEGRA_GPIO(DD, 7) GPIO_ACTIVE_HIGH>,
                                <TEGRA_GPIO(CC, 6) GPIO_ACTIVE_HIGH>,
                                <TEGRA_GPIO(R, 0) GPIO_ACTIVE_HIGH>;
                        output-low;
                        vddio-supply = <&vdd_1v8>;
 
                        device-wakeup-gpios = <&gpio TEGRA_GPIO(U, 1) GPIO_ACTIVE_HIGH>;
-                       shutdown-gpios =      <&gpio TEGRA_GPIO(U, 0) GPIO_ACTIVE_HIGH>;
+                       shutdown-gpios = <&gpio TEGRA_GPIO(U, 0) GPIO_ACTIVE_HIGH>;
                };
        };
 
                status = "okay";
 
                touchscreen@10 {
-                       compatible ="elan,ektf3624";
+                       compatible = "elan,ektf3624";
                        reg = <0x10>;
 
                        interrupt-parent = <&gpio>;
        gpio-keys {
                compatible = "gpio-keys";
 
-               hall-sensor {
+               switch-hall-sensor {
                        label = "Lid";
                        gpios = <&gpio TEGRA_GPIO(S, 6) GPIO_ACTIVE_LOW>;
                        linux,input-type = <EV_SW>;
                        wakeup-source;
                };
 
-               power {
+               key-power {
                        label = "Power";
                        gpios = <&gpio TEGRA_GPIO(V, 0) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
                        wakeup-source;
                };
 
-               volume-up {
+               key-volume-up {
                        label = "Volume Up";
                        gpios = <&gpio TEGRA_GPIO(Q, 2) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
                        wakeup-source;
                };
 
-               volume-down {
+               key-volume-down {
                        label = "Volume Down";
                        gpios = <&gpio TEGRA_GPIO(Q, 3) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEDOWN>;
index cd63e0e..1b241f0 100644 (file)
@@ -25,7 +25,7 @@
        gpio@6000d000 {
                init-mode-3g-hog {
                        gpio-hog;
-                       gpios = <TEGRA_GPIO(D, 2) GPIO_ACTIVE_HIGH>,
+                       gpios = <TEGRA_GPIO(D, 2) GPIO_ACTIVE_HIGH>,
                                <TEGRA_GPIO(C, 6) GPIO_ACTIVE_HIGH>,
                                <TEGRA_GPIO(W, 3) GPIO_ACTIVE_HIGH>,
                                <TEGRA_GPIO(P, 1) GPIO_ACTIVE_HIGH>,
index c662ab2..c27e70d 100644 (file)
                compatible = "gpio-keys";
                interrupt-parent = <&gpio>;
 
-               dock-hall-sensor {
+               switch-dock-hall-sensor {
                        label = "Lid sensor";
                        gpios = <&gpio TEGRA_GPIO(S, 6) GPIO_ACTIVE_LOW>;
                        linux,input-type = <EV_SW>;
                        wakeup-source;
                };
 
-               lineout-detect {
+               switch-lineout-detect {
                        label = "Audio dock line-out detect";
                        gpios = <&gpio TEGRA_GPIO(X, 3) GPIO_ACTIVE_LOW>;
                        linux,input-type = <EV_SW>;
                compatible = "gpio-keys";
                interrupt-parent = <&gpio>;
 
-               power {
+               key-power {
                        label = "Power";
                        gpios = <&gpio TEGRA_GPIO(V, 0) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
                        wakeup-source;
                };
 
-               volume-up {
+               key-volume-up {
                        label = "Volume Up";
                        gpios = <&gpio TEGRA_GPIO(Q, 2) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
                        wakeup-source;
                };
 
-               volume-down {
+               key-volume-down {
                        label = "Volume Down";
                        gpios = <&gpio TEGRA_GPIO(Q, 3) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEDOWN>;
index ba257ed..540530c 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               power {
+               key-power {
                        label = "Power";
                        interrupt-parent = <&pmic>;
                        interrupts = <2 0>;
                        wakeup-source;
                };
 
-               volume-down {
+               key-volume-down {
                        label = "Volume Down";
                        gpios = <&gpio TEGRA_GPIO(R, 0) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEDOWN>;
                        debounce-interval = <10>;
                };
 
-               volume-up {
+               key-volume-up {
                        label = "Volume Up";
                        gpios = <&gpio TEGRA_GPIO(R, 1) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
index 7d4a6ca..8dbc15f 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               wakeup {
+               key-wakeup {
                        label = "SODIMM pin 45 wakeup";
                        gpios = <&gpio TEGRA_GPIO(V, 1) GPIO_ACTIVE_HIGH>;
                        linux,code = <KEY_WAKEUP>;
index 22231d4..310dff0 100644 (file)
                                nvidia,enable-input = <TEGRA_PIN_ENABLE>;
                        };
                        spdif-in-pk6 {
-                               nvidia,pins =   "spdif_in_pk6";
+                               nvidia,pins = "spdif_in_pk6";
                                nvidia,function = "hda";
                                nvidia,pull = <TEGRA_PIN_PULL_NONE>;
                                nvidia,tristate = <TEGRA_PIN_DISABLE>;
                        };
                        /* Multiplexed and therefore disabled */
                        cam-mclk-pcc0 {
-                               nvidia,pins =   "cam_mclk_pcc0";
+                               nvidia,pins = "cam_mclk_pcc0";
                                nvidia,function = "vi_alt3";
                                nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
                                nvidia,tristate = <TEGRA_PIN_ENABLE>;
 
                        /* Colibri USBC_DET */
                        spdif-out-pk5 {
-                               nvidia,pins =   "spdif_out_pk5";
+                               nvidia,pins = "spdif_out_pk5";
                                nvidia,function = "rsvd2";
                                nvidia,pull = <TEGRA_PIN_PULL_NONE>;
                                nvidia,tristate = <TEGRA_PIN_DISABLE>;
index e58dda4..b7acea3 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               power {
+               key-power {
                        gpios = <&gpio TEGRA_GPIO(V, 0) GPIO_ACTIVE_LOW>;
                        debounce-interval = <10>;
                        linux,code = <KEY_POWER>;
index 8ce6103..7c81f02 100644 (file)
                compatible = "gpio-keys";
                interrupt-parent = <&gpio>;
 
-               dock-insert {
+               switch-dock-insert {
                        label = "Chagall Dock";
                        gpios = <&gpio TEGRA_GPIO(S, 4) GPIO_ACTIVE_LOW>;
                        linux,input-type = <EV_SW>;
                        wakeup-source;
                };
 
-               lineout-detect {
+               switch-lineout-detect {
                        label = "Audio dock line-out detect";
                        gpios = <&gpio TEGRA_GPIO(S, 3) GPIO_ACTIVE_LOW>;
                        linux,input-type = <EV_SW>;
                compatible = "gpio-keys";
                interrupt-parent = <&gpio>;
 
-               power {
+               key-power {
                        label = "Power";
                        gpios = <&gpio TEGRA_GPIO(V, 0) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
                        wakeup-source;
                };
 
-               volume-up {
+               key-volume-up {
                        label = "Volume Up";
                        gpios = <&gpio TEGRA_GPIO(Q, 0) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
                        wakeup-source;
                };
 
-               volume-down {
+               key-volume-down {
                        label = "Volume Down";
                        gpios = <&gpio TEGRA_GPIO(Q, 1) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEDOWN>;
index cf70aff..d23201b 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
                autorepeat;
-               sw14 {
+               switch-14 {
                        label = "sw14";
                        gpios = <&gpio0 12 0>;
                        linux,code = <108>; /* down */
                        wakeup-source;
                        autorepeat;
                };
-               sw13 {
+               switch-13 {
                        label = "sw13";
                        gpios = <&gpio0 14 0>;
                        linux,code = <103>; /* up */
index bf5d1c4..dfb1fba 100644 (file)
@@ -49,7 +49,7 @@
        gpio-keys {
                compatible = "gpio-keys";
                autorepeat;
-               K1 {
+               key {
                        label = "K1";
                        gpios = <&gpio0 0x32 0x1>;
                        linux,code = <0x66>;
index 9252ce0..3f633ea 100644 (file)
@@ -1,25 +1,22 @@
 CONFIG_LOCALVERSION="gum"
-# CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_PREEMPT=y
 CONFIG_EXPERT=y
 # CONFIG_EPOLL is not set
 # CONFIG_SHMEM is not set
-# CONFIG_VM_EVENT_COUNTERS is not set
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_PXA=y
 CONFIG_ARCH_GUMSTIX=y
-CONFIG_PCCARD=y
-CONFIG_PREEMPT=y
 CONFIG_AEABI=y
 # CONFIG_OABI_COMPAT is not set
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="console=ttyS0,115200n8 root=1f01 rootfstype=jffs2"
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_SWAP is not set
+CONFIG_SLAB=y
+# CONFIG_VM_EVENT_COUNTERS is not set
 CONFIG_NET=y
 CONFIG_PACKET=m
 CONFIG_UNIX=y
@@ -35,6 +32,7 @@ CONFIG_BT_RFCOMM_TTY=y
 CONFIG_BT_BNEP=m
 CONFIG_BT_HCIUART=m
 CONFIG_BT_HCIUART_H4=y
+CONFIG_PCCARD=y
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
@@ -48,14 +46,15 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y
 CONFIG_MTD_PXA2XX=y
 CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_SD=m
+# CONFIG_BLK_DEV_BSG is not set
 CONFIG_ATA=m
 CONFIG_PATA_PCMCIA=m
 CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
 CONFIG_SMC91X=m
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_PXA=y
 CONFIG_SERIAL_PXA_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_HWMON is not set
 CONFIG_WATCHDOG=y
@@ -84,16 +83,15 @@ CONFIG_VFAT_FS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_COMPRESSION_OPTIONS=y
 CONFIG_JFFS2_RUBIN=y
-CONFIG_PARTITION_ADVANCED=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DETECT_SOFTLOCKUP is not set
-# CONFIG_DEBUG_PREEMPT is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
-CONFIG_DEBUG_USER=y
 CONFIG_CRYPTO=y
 CONFIG_CRYPTO_CBC=m
 CONFIG_CRYPTO_ECB=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_ARC4=m
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_USER=y
index 5d20057..67feb06 100644 (file)
@@ -1,5 +1,4 @@
 CONFIG_KERNEL_XZ=y
-# CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_NO_HZ_IDLE=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -17,9 +16,6 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_AIO is not set
 CONFIG_EMBEDDED=y
 CONFIG_PERF_EVENTS=y
-# CONFIG_COMPAT_BRK is not set
-CONFIG_SLAB_FREELIST_RANDOM=y
-CONFIG_SLAB_FREELIST_HARDENED=y
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_ASPEED=y
 CONFIG_MACH_ASPEED_G4=y
@@ -30,7 +26,6 @@ CONFIG_UACCESS_WITH_MEMCPY=y
 CONFIG_ARM_APPENDED_DTB=y
 CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_KEXEC=y
-CONFIG_FIRMWARE_MEMMAP=y
 CONFIG_JUMP_LABEL=y
 CONFIG_STRICT_KERNEL_RWX=y
 # CONFIG_BLK_DEV_BSG is not set
@@ -38,6 +33,10 @@ CONFIG_STRICT_KERNEL_RWX=y
 # CONFIG_MQ_IOSCHED_DEADLINE is not set
 # CONFIG_MQ_IOSCHED_KYBER is not set
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_SWAP is not set
+CONFIG_SLAB_FREELIST_RANDOM=y
+CONFIG_SLAB_FREELIST_HARDENED=y
+# CONFIG_COMPAT_BRK is not set
 # CONFIG_COMPACTION is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
@@ -57,12 +56,12 @@ CONFIG_NET_NCSI=y
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_FIRMWARE_MEMMAP=y
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_PARTITIONED_MASTER=y
 CONFIG_MTD_SPI_NOR=y
 # CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
-CONFIG_SPI_ASPEED_SMC=y
 CONFIG_MTD_UBI=y
 CONFIG_MTD_UBI_FASTMAP=y
 CONFIG_MTD_UBI_BLOCK=y
@@ -88,9 +87,9 @@ CONFIG_FTGMAC100=y
 # CONFIG_NET_VENDOR_MELLANOX is not set
 # CONFIG_NET_VENDOR_MICREL is not set
 # CONFIG_NET_VENDOR_MICROSEMI is not set
+# CONFIG_NET_VENDOR_NI is not set
 # CONFIG_NET_VENDOR_NATSEMI is not set
 # CONFIG_NET_VENDOR_NETRONOME is not set
-# CONFIG_NET_VENDOR_NI is not set
 # CONFIG_NET_VENDOR_QUALCOMM is not set
 # CONFIG_NET_VENDOR_RENESAS is not set
 # CONFIG_NET_VENDOR_ROCKER is not set
@@ -134,6 +133,7 @@ CONFIG_I2C_MUX_PCA954x=y
 CONFIG_I2C_ASPEED=y
 CONFIG_I2C_FSI=y
 CONFIG_SPI=y
+CONFIG_SPI_ASPEED_SMC=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_ASPEED=y
@@ -244,9 +244,8 @@ CONFIG_CRYPTO_USER_API_HASH=y
 # CONFIG_XZ_DEC_SPARC is not set
 CONFIG_PRINTK_TIME=y
 CONFIG_DYNAMIC_DEBUG=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_INFO_REDUCED=y
 CONFIG_DEBUG_INFO_DWARF4=y
+CONFIG_DEBUG_INFO_REDUCED=y
 CONFIG_GDB_SCRIPTS=y
 CONFIG_STRIP_ASM_SYMS=y
 CONFIG_DEBUG_FS=y
index ae4f3c5..247ab72 100644 (file)
@@ -1,5 +1,4 @@
 CONFIG_KERNEL_XZ=y
-# CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_NO_HZ_IDLE=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -17,9 +16,6 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_AIO is not set
 CONFIG_EMBEDDED=y
 CONFIG_PERF_EVENTS=y
-# CONFIG_COMPAT_BRK is not set
-CONFIG_SLAB_FREELIST_RANDOM=y
-CONFIG_SLAB_FREELIST_HARDENED=y
 CONFIG_ARCH_MULTI_V6=y
 CONFIG_ARCH_ASPEED=y
 CONFIG_MACH_ASPEED_G5=y
@@ -36,13 +32,16 @@ CONFIG_KEXEC=y
 CONFIG_VFP=y
 CONFIG_NEON=y
 CONFIG_KERNEL_MODE_NEON=y
-CONFIG_FIRMWARE_MEMMAP=y
 CONFIG_JUMP_LABEL=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_BLK_DEBUG_FS is not set
 # CONFIG_MQ_IOSCHED_DEADLINE is not set
 # CONFIG_MQ_IOSCHED_KYBER is not set
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_SWAP is not set
+CONFIG_SLAB_FREELIST_RANDOM=y
+CONFIG_SLAB_FREELIST_HARDENED=y
+# CONFIG_COMPAT_BRK is not set
 # CONFIG_COMPACTION is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
@@ -70,12 +69,12 @@ CONFIG_NET_NCSI=y
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_FIRMWARE_MEMMAP=y
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_PARTITIONED_MASTER=y
 CONFIG_MTD_SPI_NOR=y
 # CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
-CONFIG_SPI_ASPEED_SMC=y
 CONFIG_MTD_UBI=y
 CONFIG_MTD_UBI_FASTMAP=y
 CONFIG_MTD_UBI_BLOCK=y
@@ -103,9 +102,9 @@ CONFIG_FTGMAC100=y
 # CONFIG_NET_VENDOR_MELLANOX is not set
 # CONFIG_NET_VENDOR_MICREL is not set
 # CONFIG_NET_VENDOR_MICROSEMI is not set
+# CONFIG_NET_VENDOR_NI is not set
 # CONFIG_NET_VENDOR_NATSEMI is not set
 # CONFIG_NET_VENDOR_NETRONOME is not set
-# CONFIG_NET_VENDOR_NI is not set
 # CONFIG_NET_VENDOR_QUALCOMM is not set
 # CONFIG_NET_VENDOR_RENESAS is not set
 # CONFIG_NET_VENDOR_ROCKER is not set
@@ -156,6 +155,7 @@ CONFIG_I2C_ASPEED=y
 CONFIG_I2C_FSI=y
 CONFIG_I2C_SLAVE=y
 CONFIG_SPI=y
+CONFIG_SPI_ASPEED_SMC=y
 CONFIG_SPI_FSI=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
@@ -273,9 +273,8 @@ CONFIG_CRYPTO_USER_API_HASH=y
 # CONFIG_XZ_DEC_SPARC is not set
 CONFIG_PRINTK_TIME=y
 CONFIG_DYNAMIC_DEBUG=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_INFO_REDUCED=y
 CONFIG_DEBUG_INFO_DWARF4=y
+CONFIG_DEBUG_INFO_REDUCED=y
 CONFIG_GDB_SCRIPTS=y
 CONFIG_STRIP_ASM_SYMS=y
 CONFIG_DEBUG_FS=y
index 04c86ff..801383e 100644 (file)
@@ -1,25 +1,19 @@
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_MODULES=y
 CONFIG_ARCH_SA1100=y
 CONFIG_SA1100_ASSABET=y
-CONFIG_PCCARD=y
-CONFIG_PCMCIA_SA1100=y
-CONFIG_LEDS=y
-CONFIG_LEDS_CPU=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="mem=32M console=ttySA0,38400n8 initrd=0xc0800000,3M root=/dev/ram"
 CONFIG_FPE_NWFPE=y
 CONFIG_PM=y
+CONFIG_MODULES=y
+CONFIG_PARTITION_ADVANCED=y
 CONFIG_NET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
 # CONFIG_IPV6 is not set
-CONFIG_IRDA=m
-CONFIG_IRLAN=m
-CONFIG_SA1100_FIR=m
+CONFIG_PCCARD=y
+CONFIG_PCMCIA_SA1100=y
 CONFIG_MTD=y
 CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_BLOCK=y
@@ -46,11 +40,14 @@ CONFIG_FB=y
 CONFIG_FB_SA1100=y
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_SOUND=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_CPU=y
 CONFIG_EXT2_FS=y
 CONFIG_MSDOS_FS=y
 CONFIG_TMPFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_NFS_FS=y
-CONFIG_PARTITION_ADVANCED=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_DEBUG_USER=y
index db15a8b..da90ce9 100644 (file)
@@ -1,5 +1,4 @@
 # CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_NO_HZ_IDLE=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -9,7 +8,6 @@ CONFIG_BLK_DEV_INITRD=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
 CONFIG_ARCH_MULTI_V4T=y
 CONFIG_ARCH_MULTI_V5=y
 # CONFIG_ARCH_MULTI_V7 is not set
@@ -27,8 +25,9 @@ CONFIG_CMDLINE="console=ttyS0,115200 initrd=0x21100000,25165824 root=/dev/ram0 r
 CONFIG_KEXEC=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_SWAP is not set
+CONFIG_SLAB=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -66,6 +65,7 @@ CONFIG_ATMEL_SSC=y
 CONFIG_EEPROM_AT24=m
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
+# CONFIG_BLK_DEV_BSG is not set
 # CONFIG_SCSI_LOWLEVEL is not set
 CONFIG_NETDEVICES=y
 # CONFIG_NET_VENDOR_BROADCOM is not set
@@ -139,9 +139,9 @@ CONFIG_MEDIA_USB_SUPPORT=y
 CONFIG_USB_VIDEO_CLASS=m
 CONFIG_V4L_PLATFORM_DRIVERS=y
 CONFIG_VIDEO_ATMEL_ISI=y
+CONFIG_VIDEO_MT9V032=m
 CONFIG_VIDEO_OV2640=m
 CONFIG_VIDEO_OV7740=m
-CONFIG_VIDEO_MT9V032=m
 CONFIG_DRM=y
 CONFIG_DRM_ATMEL_HLCDC=y
 CONFIG_DRM_PANEL_SIMPLE=y
@@ -206,8 +206,8 @@ CONFIG_PWM_ATMEL=y
 CONFIG_PWM_ATMEL_HLCDC_PWM=y
 CONFIG_PWM_ATMEL_TCB=y
 CONFIG_EXT4_FS=y
-CONFIG_AUTOFS_FS=m
 CONFIG_FANOTIFY=y
+CONFIG_AUTOFS_FS=m
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_UBIFS_FS=y
index 4607521..bfbaa2d 100644 (file)
@@ -3,6 +3,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_FHANDLE=y
 CONFIG_AUDIT=y
 CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_BSD_PROCESS_ACCT_V3=y
 CONFIG_TASKSTATS=y
@@ -21,12 +22,8 @@ CONFIG_SCHED_AUTOGROUP=y
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EMBEDDED=y
-# CONFIG_COMPAT_BRK is not set
 CONFIG_PROFILING=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
 CONFIG_ARCH_AXXIA=y
-CONFIG_GPIO_PCA953X=y
 CONFIG_ARM_LPAE=y
 CONFIG_ARM_THUMBEE=y
 CONFIG_ARM_ERRATA_430973=y
@@ -37,26 +34,24 @@ CONFIG_ARM_ERRATA_754327=y
 CONFIG_ARM_ERRATA_764369=y
 CONFIG_ARM_ERRATA_775420=y
 CONFIG_ARM_ERRATA_798181=y
-CONFIG_PCI=y
-CONFIG_PCI_MSI=y
 CONFIG_PCIE_AXXIA=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=16
 CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT=y
 CONFIG_AEABI=y
 CONFIG_OABI_COMPAT=y
 CONFIG_HIGHMEM=y
-CONFIG_KSM=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_ARM_APPENDED_DTB=y
 CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_VFP=y
 CONFIG_NEON=y
+# CONFIG_SUSPEND is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_BINFMT_MISC=y
-# CONFIG_SUSPEND is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_KSM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -76,6 +71,8 @@ CONFIG_INET_IPCOMP=y
 CONFIG_NETWORK_PHY_TIMESTAMPING=y
 CONFIG_BRIDGE=y
 # CONFIG_WIRELESS is not set
+CONFIG_PCI=y
+CONFIG_PCI_MSI=y
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_MTD=y
@@ -142,9 +139,10 @@ CONFIG_DP83640_PHY=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_PL061=y
-CONFIG_POWER_SUPPLY=y
+CONFIG_GPIO_PCA953X=y
 CONFIG_POWER_RESET=y
 CONFIG_POWER_RESET_AXXIA=y
+CONFIG_POWER_SUPPLY=y
 CONFIG_SENSORS_ADT7475=y
 CONFIG_SENSORS_JC42=y
 CONFIG_SENSORS_LM75=y
@@ -224,8 +222,9 @@ CONFIG_NFS_FSCACHE=y
 CONFIG_SUNRPC_DEBUG=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
+CONFIG_CRYPTO_XCBC=y
 CONFIG_PRINTK_TIME=y
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 CONFIG_DEBUG_FS=y
 CONFIG_MAGIC_SYSRQ=y
 # CONFIG_SCHED_DEBUG is not set
@@ -233,6 +232,5 @@ CONFIG_RCU_CPU_STALL_TIMEOUT=60
 # CONFIG_FTRACE is not set
 CONFIG_DEBUG_USER=y
 CONFIG_CRYPTO_GCM=y
-CONFIG_CRYPTO_XCBC=y
 CONFIG_CRYPTO_SHA256=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
index d9119da..506f337 100644 (file)
@@ -1,26 +1,21 @@
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_EXPERT=y
-CONFIG_MODULES=y
-CONFIG_MODVERSIONS=y
 CONFIG_ARCH_SA1100=y
 CONFIG_SA1100_BADGE4=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_CMDLINE="init=/linuxrc root=/dev/mtdblock3"
 CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
 CONFIG_FPE_NWFPE=y
 CONFIG_BINFMT_AOUT=m
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
 CONFIG_BINFMT_MISC=m
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
 # CONFIG_IPV6 is not set
-CONFIG_IRDA=y
-CONFIG_IRLAN=y
-CONFIG_IRCOMM=y
-CONFIG_IRDA_ULTRA=y
-CONFIG_SA1100_FIR=y
 CONFIG_BT=m
 CONFIG_BT_HCIUART=m
 CONFIG_BT_HCIVHCI=m
@@ -101,10 +96,9 @@ CONFIG_MINIX_FS=m
 CONFIG_NFS_FS=m
 CONFIG_NFS_V3=y
 CONFIG_SMB_FS=m
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_BUGVERBOSE is not set
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
+CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_LL=y
index a9ed79b..c4d2e23 100644 (file)
@@ -2,6 +2,7 @@
 CONFIG_SYSVIPC=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_BSD_PROCESS_ACCT_V3=y
 CONFIG_LOG_BUF_SHIFT=18
@@ -19,19 +20,12 @@ CONFIG_BLK_DEV_INITRD=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_EMBEDDED=y
-# CONFIG_COMPAT_BRK is not set
 CONFIG_PROFILING=y
-CONFIG_JUMP_LABEL=y
 CONFIG_CC_STACKPROTECTOR_REGULAR=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
 CONFIG_ARCH_MULTI_V6=y
 CONFIG_ARCH_BCM=y
 CONFIG_ARCH_BCM2835=y
-CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_AEABI=y
-CONFIG_KSM=y
-CONFIG_CMA=y
 CONFIG_SECCOMP=y
 CONFIG_KEXEC=y
 CONFIG_CRASH_DUMP=y
@@ -44,9 +38,15 @@ CONFIG_CPU_FREQ_GOV_ONDEMAND=y
 CONFIG_CPUFREQ_DT=y
 CONFIG_ARM_RASPBERRYPI_CPUFREQ=y
 CONFIG_VFP=y
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 # CONFIG_SUSPEND is not set
 CONFIG_PM=y
+CONFIG_JUMP_LABEL=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_KSM=y
+CONFIG_CMA=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -63,8 +63,7 @@ CONFIG_MAC80211=y
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_STANDALONE is not set
-CONFIG_DMA_CMA=y
-CONFIG_CMA_SIZE_MBYTES=32
+CONFIG_RASPBERRYPI_FIRMWARE=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_SCSI_CONSTANTS=y
@@ -106,6 +105,7 @@ CONFIG_REGULATOR_GPIO=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_MEDIA_CAMERA_SUPPORT=y
 CONFIG_DRM=y
+CONFIG_DRM_V3D=y
 CONFIG_DRM_VC4=y
 CONFIG_FB_SIMPLE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
@@ -151,7 +151,6 @@ CONFIG_BCM2835_MBOX=y
 CONFIG_RASPBERRYPI_POWER=y
 CONFIG_PWM=y
 CONFIG_PWM_BCM2835=y
-CONFIG_RASPBERRYPI_FIRMWARE=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT2_FS_POSIX_ACL=y
@@ -170,20 +169,22 @@ CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ASCII=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_NLS_UTF8=y
+# CONFIG_XZ_DEC_ARM is not set
+# CONFIG_XZ_DEC_ARMTHUMB is not set
+CONFIG_DMA_CMA=y
+CONFIG_CMA_SIZE_MBYTES=32
 CONFIG_PRINTK_TIME=y
 CONFIG_BOOT_PRINTK_DELAY=y
 CONFIG_DYNAMIC_DEBUG=y
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 # CONFIG_ENABLE_MUST_CHECK is not set
-CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_LOCKUP_DETECTOR=y
-CONFIG_SCHED_TRACER=y
-CONFIG_STACK_TRACER=y
-CONFIG_FUNCTION_PROFILER=y
-CONFIG_TEST_KSTRTOX=y
 CONFIG_DEBUG_FS=y
 CONFIG_KGDB=y
 CONFIG_KGDB_KDB=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_FUNCTION_PROFILER=y
+CONFIG_STACK_TRACER=y
+CONFIG_SCHED_TRACER=y
 CONFIG_STRICT_DEVMEM=y
-# CONFIG_XZ_DEC_ARM is not set
-# CONFIG_XZ_DEC_ARMTHUMB is not set
+CONFIG_TEST_KSTRTOX=y
index 3f910bb..7e6f7df 100644 (file)
@@ -1,23 +1,19 @@
 CONFIG_SYSVIPC=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
 CONFIG_ARCH_SA1100=y
 CONFIG_SA1100_CERF=y
 CONFIG_SA1100_CERF_FLASH_16MB=y
-CONFIG_PCCARD=m
-CONFIG_PCMCIA_SA1100=m
-CONFIG_LEDS=y
-CONFIG_LEDS_CPU=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_CMDLINE="console=ttySA0,38400 root=/dev/mtdblock3 rootfstype=jffs2 rw mem=32M init=/linuxrc"
 CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
 CONFIG_CPU_FREQ_GOV_USERSPACE=m
 CONFIG_FPE_FASTFPE=y
 CONFIG_PM=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -27,9 +23,11 @@ CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
 CONFIG_IP_PNP_RARP=y
 # CONFIG_IPV6 is not set
+CONFIG_PCCARD=m
+CONFIG_PCMCIA_SA1100=m
 CONFIG_MTD=y
-CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_INTELEXT=y
@@ -47,6 +45,10 @@ CONFIG_SERIAL_SA1100_CONSOLE=y
 CONFIG_WATCHDOG=y
 CONFIG_SA1100_WATCHDOG=m
 # CONFIG_VGA_CONSOLE is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_CPU=y
 CONFIG_EXT2_FS=m
 CONFIG_EXT3_FS=m
 CONFIG_MSDOS_FS=m
@@ -60,11 +62,10 @@ CONFIG_NFS_V4=y
 CONFIG_NFSD=m
 CONFIG_NFSD_V4=y
 CONFIG_SMB_FS=m
-CONFIG_PARTITION_ADVANCED=y
 CONFIG_NLS=y
 CONFIG_NLS_CODEPAGE_437=m
 CONFIG_NLS_ISO8859_1=m
-CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_LL=y
index 63a153f..92481b2 100644 (file)
@@ -4,7 +4,6 @@ CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_RD_LZMA=y
 CONFIG_EMBEDDED=y
-CONFIG_SLOB=y
 CONFIG_JUMP_LABEL=y
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_ARCH_CLPS711X=y
@@ -14,16 +13,13 @@ CONFIG_ARCH_CLEP7312=y
 CONFIG_ARCH_EDB7211=y
 CONFIG_ARCH_P720T=y
 CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 # CONFIG_COREDUMP is not set
+CONFIG_SLOB=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
 # CONFIG_IPV6 is not set
-CONFIG_IRDA=y
-CONFIG_IRTTY_SIR=y
 # CONFIG_WIRELESS is not set
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
index bb0fcd8..31f4115 100644 (file)
@@ -1,29 +1,27 @@
 CONFIG_LOCALVERSION="-cm-x300"
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
+CONFIG_NO_HZ=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=18
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_PXA=y
-CONFIG_GPIO_PCA953X=y
 CONFIG_MACH_CM_X300=y
-CONFIG_NO_HZ=y
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_CMDLINE="root=/dev/mtdblock5 rootfstype=ubifs console=ttyS2,38400"
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
 CONFIG_FPE_NWFPE=y
 CONFIG_APM_EMULATION=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -55,6 +53,7 @@ CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
+# CONFIG_BLK_DEV_BSG is not set
 CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
 CONFIG_DM9000=y
@@ -80,6 +79,7 @@ CONFIG_I2C_PXA=y
 CONFIG_SPI=y
 CONFIG_SPI_GPIO=y
 CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_PCA953X=y
 # CONFIG_HWMON is not set
 CONFIG_PMIC_DA903X=y
 CONFIG_REGULATOR=y
@@ -91,8 +91,6 @@ CONFIG_LCD_TDO24M=y
 CONFIG_BACKLIGHT_DA903X=m
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
-CONFIG_FONTS=y
-CONFIG_FONT_6x11=y
 CONFIG_LOGO=y
 CONFIG_SOUND=m
 CONFIG_SND=m
@@ -147,18 +145,19 @@ CONFIG_NFS_V3_ACL=y
 CONFIG_NFS_V4=y
 CONFIG_ROOT_NFS=y
 CONFIG_CIFS=m
-CONFIG_PARTITION_ADVANCED=y
 CONFIG_NLS_CODEPAGE_437=m
 CONFIG_NLS_ISO8859_1=m
-CONFIG_DEBUG_FS=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_T10DIF=y
+CONFIG_FONTS=y
+CONFIG_FONT_6x11=y
 CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_FS=y
 # CONFIG_SCHED_DEBUG is not set
 # CONFIG_FTRACE is not set
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_LL=y
 CONFIG_CRYPTO_ECB=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_AES=m
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
-# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
index 63fa2eb..b3aab97 100644 (file)
@@ -1,5 +1,4 @@
 # CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
@@ -9,23 +8,22 @@ CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_PERF_EVENTS is not set
-CONFIG_SLAB=y
 CONFIG_PROFILING=y
+CONFIG_ARCH_MULTI_V6=y
+CONFIG_ARCH_CNS3XXX=y
+CONFIG_MACH_CNS3420VB=y
+CONFIG_UNUSED_BOARD_FILES=y
+CONFIG_CMDLINE="console=ttyS0,38400 mem=128M root=/dev/mmcblk0p1 ro rootwait"
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
 CONFIG_MODVERSIONS=y
-# CONFIG_BLK_DEV_BSG is not set
 CONFIG_IOSCHED_BFQ=m
-CONFIG_ARCH_MULTI_V6=y
 #CONFIG_ARCH_MULTI_V7 is not set
-CONFIG_ARCH_CNS3XXX=y
-CONFIG_MACH_CNS3420VB=y
 CONFIG_DEBUG_CNS3XXX=y
 CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="console=ttyS0,38400 mem=128M root=/dev/mmcblk0p1 ro rootwait"
+# CONFIG_SWAP is not set
+CONFIG_SLAB=y
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
@@ -36,6 +34,7 @@ CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=20000
 CONFIG_BLK_DEV_SD=y
+# CONFIG_BLK_DEV_BSG is not set
 CONFIG_ATA=y
 # CONFIG_SATA_PMP is not set
 # CONFIG_ATA_SFF is not set
@@ -43,9 +42,9 @@ CONFIG_ATA=y
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_SERIO is not set
+CONFIG_LEGACY_PTY_COUNT=16
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_LEGACY_PTY_COUNT=16
 # CONFIG_HW_RANDOM is not set
 # CONFIG_HWMON is not set
 # CONFIG_VGA_CONSOLE is not set
@@ -59,6 +58,6 @@ CONFIG_AUTOFS4_FS=y
 CONFIG_FSCACHE=y
 CONFIG_TMPFS=y
 # CONFIG_ENABLE_MUST_CHECK is not set
-CONFIG_DEBUG_FS=y
 # CONFIG_ARM_UNWIND is not set
 CONFIG_CRC_CCITT=y
+CONFIG_DEBUG_FS=y
index b29898f..8357d72 100644 (file)
@@ -1,5 +1,6 @@
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_PREEMPT=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_BSD_PROCESS_ACCT_V3=y
 CONFIG_IKCONFIG=y
@@ -9,20 +10,20 @@ CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EXPERT=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
-CONFIG_SLAB=y
+# CONFIG_ARCH_MULTI_V7 is not set
+CONFIG_ARCH_PXA=y
+CONFIG_MACH_COLIBRI=y
+CONFIG_AEABI=y
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
 CONFIG_MODVERSIONS=y
 CONFIG_MODULE_SRCVERSION_ALL=y
 # CONFIG_BLK_DEV_BSG is not set
-# CONFIG_ARCH_MULTI_V7 is not set
-CONFIG_ARCH_PXA=y
-CONFIG_MACH_COLIBRI=y
-CONFIG_PREEMPT=y
-CONFIG_AEABI=y
 CONFIG_FPE_NWFPE=y
 CONFIG_PM=y
+CONFIG_SLAB=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -35,13 +36,6 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_IPV6 is not set
 CONFIG_NETFILTER=y
 CONFIG_VLAN_8021Q=m
-CONFIG_IRDA=m
-CONFIG_IRLAN=m
-CONFIG_IRCOMM=m
-CONFIG_IRDA_ULTRA=y
-CONFIG_IRDA_CACHE_LAST_LSAP=y
-CONFIG_IRDA_FAST_RR=y
-CONFIG_IRTTY_SIR=m
 CONFIG_BT=m
 CONFIG_BT_RFCOMM=m
 CONFIG_BT_RFCOMM_TTY=y
@@ -64,22 +58,22 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y
 CONFIG_MTD_PHYSMAP=y
 CONFIG_MTD_PXA2XX=y
 CONFIG_MTD_BLOCK2MTD=y
+CONFIG_MTD_ONENAND=y
 CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_DISKONCHIP=y
 CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED=y
 CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0x4000000
 CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH=y
 CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE=y
-CONFIG_MTD_ONENAND=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=8
 CONFIG_NETDEVICES=y
-CONFIG_PHYLIB=y
 CONFIG_NET_ETHERNET=y
 CONFIG_DM9000=y
+CONFIG_PHYLIB=y
 CONFIG_HOSTAP=y
 CONFIG_HOSTAP_FIRMWARE=y
 CONFIG_HOSTAP_FIRMWARE_NVRAM=y
@@ -107,9 +101,6 @@ CONFIG_BACKLIGHT_CLASS_DEVICE=y
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
-CONFIG_FONTS=y
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
 CONFIG_LOGO=y
 # CONFIG_USB_HID is not set
 CONFIG_USB=y
@@ -143,13 +134,8 @@ CONFIG_NLS_ASCII=y
 CONFIG_NLS_ISO8859_1=m
 CONFIG_NLS_ISO8859_15=m
 CONFIG_NLS_UTF8=m
-CONFIG_PRINTK_TIME=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_LL=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 CONFIG_KEYS=y
 CONFIG_SECURITY=y
 CONFIG_CRYPTO_PCBC=m
@@ -161,3 +147,11 @@ CONFIG_CRYPTO_DEFLATE=m
 CONFIG_CRC_CCITT=y
 CONFIG_CRC16=y
 CONFIG_LIBCRC32C=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_LL=y
index f9d1102..42adfef 100644 (file)
@@ -1,13 +1,13 @@
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_PXA=y
 CONFIG_MACH_COLIBRI300=y
 CONFIG_AEABI=y
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_CMDLINE="console=ttyS0,115200 rw"
 CONFIG_CPU_IDLE=y
 CONFIG_FPE_NWFPE=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
 CONFIG_NET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
@@ -18,6 +18,7 @@ CONFIG_IPV6=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_SG=y
+# CONFIG_BLK_DEV_BSG is not set
 CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
 CONFIG_AX88796=y
@@ -48,12 +49,12 @@ CONFIG_EXT3_FS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_AES=y
 CONFIG_PRINTK_TIME=y
 CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_LL=y
-CONFIG_CRYPTO_ECB=y
-CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_ARC4=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
index 36384fd..d35cc59 100644 (file)
@@ -1,4 +1,3 @@
-# CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
@@ -6,22 +5,21 @@ CONFIG_BLK_DEV_INITRD=y
 CONFIG_EXPERT=y
 # CONFIG_BASE_FULL is not set
 # CONFIG_EPOLL is not set
-CONFIG_SLOB=y
 CONFIG_ARCH_SA1100=y
 CONFIG_SA1100_COLLIE=y
-CONFIG_PCCARD=y
-CONFIG_PCMCIA_SA1100=y
-CONFIG_PCMCIA_DEBUG=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="noinitrd root=/dev/mtdblock2 rootfstype=jffs2 fbcon=rotate:1"
 CONFIG_FPE_NWFPE=y
 CONFIG_PM=y
+# CONFIG_SWAP is not set
+CONFIG_SLOB=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
 # CONFIG_IPV6 is not set
+CONFIG_PCCARD=y
+CONFIG_PCMCIA_SA1100=y
+CONFIG_PCMCIA_DEBUG=y
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
@@ -48,12 +46,12 @@ CONFIG_KEYBOARD_LOCOMO=y
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_TOUCHSCREEN=y
 # CONFIG_SERIO_SERPORT is not set
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CS=y
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_SA1100=y
 CONFIG_SERIAL_SA1100_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
 # CONFIG_HWMON is not set
 CONFIG_MCP_SA11X0=y
 CONFIG_MCP_UCB1200=y
@@ -64,8 +62,6 @@ CONFIG_FB_SA1100=y
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
-CONFIG_FONTS=y
-CONFIG_FONT_MINI_4x6=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_LOCOMO=y
@@ -80,9 +76,11 @@ CONFIG_ROMFS_FS=y
 CONFIG_NLS_DEFAULT="cp437"
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
+CONFIG_CRC_CCITT=y
+CONFIG_FONTS=y
+CONFIG_FONT_MINI_4x6=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DETECT_SOFTLOCKUP is not set
 CONFIG_DEBUG_MUTEXES=y
-# CONFIG_DEBUG_BUGVERBOSE is not set
-CONFIG_CRC_CCITT=y
index 96c677c..1f137f7 100644 (file)
@@ -1,14 +1,11 @@
 CONFIG_SYSVIPC=y
+CONFIG_PREEMPT=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
 CONFIG_PROFILING=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_PXA=y
 CONFIG_PXA_SHARPSL=y
@@ -16,14 +13,14 @@ CONFIG_MACH_POODLE=y
 CONFIG_MACH_CORGI=y
 CONFIG_MACH_SHEPHERD=y
 CONFIG_MACH_HUSKY=y
-CONFIG_PCCARD=y
-CONFIG_PCMCIA_PXA2XX=y
-CONFIG_PREEMPT=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_CMDLINE="console=ttyS0,115200n8 console=tty1 noinitrd root=/dev/mtdblock2 rootfstype=jffs2   debug"
 CONFIG_FPE_NWFPE=y
 CONFIG_BINFMT_AOUT=m
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
 CONFIG_BINFMT_MISC=m
 CONFIG_PM=y
 CONFIG_NET=y
@@ -58,11 +55,6 @@ CONFIG_IP6_NF_MATCH_RT=m
 CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_MANGLE=m
 CONFIG_IP6_NF_RAW=m
-CONFIG_IRDA=m
-CONFIG_IRLAN=m
-CONFIG_IRNET=m
-CONFIG_IRCOMM=m
-CONFIG_PXA_FICP=m
 CONFIG_BT=m
 CONFIG_BT_RFCOMM=m
 CONFIG_BT_RFCOMM_TTY=y
@@ -81,6 +73,8 @@ CONFIG_BT_HCIBT3C=m
 CONFIG_BT_HCIBLUECARD=m
 CONFIG_BT_HCIBTUART=m
 CONFIG_BT_HCIVHCI=m
+CONFIG_PCCARD=y
+CONFIG_PCMCIA_PXA2XX=y
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
@@ -95,10 +89,15 @@ CONFIG_CHR_DEV_OSST=m
 CONFIG_BLK_DEV_SR=m
 CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_BLK_DEV_BSG is not set
 CONFIG_ATA=y
 CONFIG_PATA_PCMCIA=y
 CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
+CONFIG_PCMCIA_PCNET=m
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_ASYNC=m
 CONFIG_USB_CATC=m
 CONFIG_USB_KAWETH=m
 CONFIG_USB_PEGASUS=m
@@ -106,10 +105,6 @@ CONFIG_USB_RTL8150=m
 CONFIG_USB_USBNET=m
 # CONFIG_USB_NET_CDC_SUBSET is not set
 CONFIG_NET_PCMCIA=y
-CONFIG_PCMCIA_PCNET=m
-CONFIG_PPP=m
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_BSDCOMP=m
 CONFIG_INPUT_FF_MEMLESS=m
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=y
@@ -120,11 +115,11 @@ CONFIG_TOUCHSCREEN_ADS7846=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=m
 # CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_8250=m
 CONFIG_SERIAL_8250_CS=m
 CONFIG_SERIAL_PXA=y
 CONFIG_SERIAL_PXA_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
 CONFIG_I2C=y
 CONFIG_I2C_PXA=y
 CONFIG_SPI=y
@@ -136,13 +131,8 @@ CONFIG_LCD_CORGI=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FONTS=y
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
 CONFIG_SOUND=y
 CONFIG_SOUND_PRIME=y
-CONFIG_USB_KBD=m
-CONFIG_USB_MOUSE=m
 CONFIG_HID_A4TECH=m
 CONFIG_HID_APPLE=m
 CONFIG_HID_BELKIN=m
@@ -159,6 +149,8 @@ CONFIG_HID_PETALYNX=m
 CONFIG_HID_SAMSUNG=m
 CONFIG_HID_SONY=m
 CONFIG_HID_SUNPLUS=m
+CONFIG_USB_KBD=m
+CONFIG_USB_MOUSE=m
 CONFIG_USB=m
 CONFIG_USB_MON=m
 CONFIG_USB_SL811_HCD=m
@@ -220,16 +212,12 @@ CONFIG_NFS_V3=y
 CONFIG_NFS_V4=y
 CONFIG_SMB_FS=m
 CONFIG_SMB_NLS_DEFAULT=y
-CONFIG_PARTITION_ADVANCED=y
+CONFIG_NFS_V4=m
 CONFIG_NLS_DEFAULT="cp437"
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_NLS_UTF8=y
-CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_PREEMPT is not set
-# CONFIG_FTRACE is not set
-CONFIG_DEBUG_LL=y
 CONFIG_CRYPTO_NULL=m
 CONFIG_CRYPTO_TEST=m
 CONFIG_CRYPTO_ECB=m
@@ -252,3 +240,9 @@ CONFIG_CRYPTO_TWOFISH=m
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRC_CCITT=y
 CONFIG_LIBCRC32C=m
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_PREEMPT is not set
+# CONFIG_FTRACE is not set
index b58d45a..fc71a03 100644 (file)
@@ -1,8 +1,8 @@
-# CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
@@ -10,34 +10,16 @@ CONFIG_CGROUPS=y
 CONFIG_CHECKPOINT_RESTORE=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EXPERT=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_PARTITION_ADVANCED=y
 CONFIG_ARCH_MULTIPLATFORM=y
-CONFIG_ARCH_MULTI_V7=n
 CONFIG_ARCH_MULTI_V5=y
+# CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_DAVINCI=y
-CONFIG_ARCH_DAVINCI_DM644x=y
-CONFIG_ARCH_DAVINCI_DM355=y
-CONFIG_ARCH_DAVINCI_DM646x=y
 CONFIG_ARCH_DAVINCI_DA830=y
 CONFIG_ARCH_DAVINCI_DA850=y
-CONFIG_ARCH_DAVINCI_DM365=y
-CONFIG_MACH_SFFSDR=y
-CONFIG_MACH_NEUROS_OSD2=y
-CONFIG_MACH_DM355_LEOPARD=y
-CONFIG_MACH_MITYOMAPL138=y
-CONFIG_MACH_OMAPL138_HAWKBOARD=y
 CONFIG_DAVINCI_MUX_DEBUG=y
 CONFIG_DAVINCI_MUX_WARNINGS=y
-CONFIG_PREEMPT=y
 CONFIG_AEABI=y
-CONFIG_CMA=y
 CONFIG_SECCOMP=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_ARM_APPENDED_DTB=y
 CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_AUTO_ZRELADDR=y
@@ -48,6 +30,13 @@ CONFIG_CPU_FREQ_GOV_POWERSAVE=m
 CONFIG_CPU_FREQ_GOV_ONDEMAND=m
 CONFIG_CPUFREQ_DT=m
 CONFIG_CPU_IDLE=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_SWAP is not set
+CONFIG_CMA=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -65,7 +54,6 @@ CONFIG_BT_HCIUART_LL=y
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_FW_LOADER=m
-CONFIG_DMA_CMA=y
 CONFIG_DA8XX_MSTPRI=y
 CONFIG_MTD=m
 CONFIG_MTD_TESTS=m
@@ -95,8 +83,8 @@ CONFIG_NETCONSOLE=y
 CONFIG_TUN=m
 CONFIG_DM9000=y
 CONFIG_TI_DAVINCI_EMAC=y
-CONFIG_LSI_ET1011C_PHY=y
 CONFIG_LXT_PHY=y
+CONFIG_LSI_ET1011C_PHY=y
 CONFIG_SMSC_PHY=y
 CONFIG_PPP=m
 CONFIG_PPP_DEFLATE=m
@@ -113,7 +101,6 @@ CONFIG_KEYBOARD_XTKBD=m
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_PWM_BEEPER=m
-CONFIG_INPUT_DM355EVM=m
 CONFIG_SERIO_LIBPS2=y
 # CONFIG_VT_CONSOLE is not set
 CONFIG_SERIAL_8250=y
@@ -141,7 +128,6 @@ CONFIG_SYSCON_REBOOT_MODE=m
 CONFIG_BATTERY_LEGO_EV3=m
 CONFIG_WATCHDOG=y
 CONFIG_DAVINCI_WATCHDOG=y
-CONFIG_MFD_DM355EVM_MSP=y
 CONFIG_TPS6507X=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -262,10 +248,11 @@ CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ASCII=m
 CONFIG_NLS_ISO8859_1=y
 CONFIG_NLS_UTF8=m
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_T10DIF=m
+CONFIG_DMA_CMA=y
 CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_RT_MUTEXES=y
 CONFIG_DEBUG_MUTEXES=y
 # CONFIG_ARM_UNWIND is not set
 CONFIG_DEBUG_USER=y
-# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=m
index f8fb475..16ed5c1 100644 (file)
@@ -3,27 +3,21 @@ CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_EXPERT=y
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_PARTITION_ADVANCED=y
 # CONFIG_ARCH_MULTI_V6 is not set
 CONFIG_ARCH_MULTI_V7=y
 CONFIG_ARCH_DOVE=y
 CONFIG_MACH_DOVE_DB=y
 CONFIG_MACH_CM_A510=y
 CONFIG_MACH_DOVE_DT=y
-CONFIG_PCI=y
-CONFIG_PCI_MSI=y
-CONFIG_PCI_MVEBU=y
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_ARM_APPENDED_DTB=y
 CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_VFP=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_SLAB=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -33,6 +27,9 @@ CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
 # CONFIG_IPV6 is not set
+CONFIG_PCI=y
+CONFIG_PCI_MSI=y
+CONFIG_PCI_MVEBU=y
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_MTD=y
@@ -53,6 +50,7 @@ CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=1
 # CONFIG_SCSI_PROC_FS is not set
 CONFIG_BLK_DEV_SD=y
+# CONFIG_BLK_DEV_BSG is not set
 # CONFIG_SCSI_LOWLEVEL is not set
 CONFIG_ATA=y
 CONFIG_SATA_MV=y
@@ -117,14 +115,8 @@ CONFIG_NLS_CODEPAGE_850=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_NLS_ISO8859_2=y
 CONFIG_NLS_UTF8=y
-CONFIG_PRINTK_TIME=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
-# CONFIG_SCHED_DEBUG is not set
 CONFIG_TIMER_STATS=y
-# CONFIG_DEBUG_BUGVERBOSE is not set
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 CONFIG_CRYPTO_NULL=y
 CONFIG_CRYPTO_ECB=m
 CONFIG_CRYPTO_PCBC=m
@@ -142,3 +134,9 @@ CONFIG_CRYPTO_LZO=y
 CONFIG_CRYPTO_DEV_MARVELL_CESA=y
 CONFIG_CRC_CCITT=y
 CONFIG_LIBCRC32C=y
+CONFIG_PRINTK_TIME=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_DEBUG_USER=y
index fef802b..3154125 100644 (file)
@@ -5,16 +5,9 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_EXPERT=y
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_PARTITION_ADVANCED=y
 CONFIG_ARCH_MULTI_V4T=y
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_EP93XX=y
-CONFIG_MACH_ADSSPHERE=y
 CONFIG_MACH_EDB9301=y
 CONFIG_MACH_EDB9302=y
 CONFIG_MACH_EDB9302A=y
@@ -23,19 +16,15 @@ CONFIG_MACH_EDB9307A=y
 CONFIG_MACH_EDB9312=y
 CONFIG_MACH_EDB9315=y
 CONFIG_MACH_EDB9315A=y
-CONFIG_MACH_GESBC9312=y
-CONFIG_MACH_MICRO9H=y
-CONFIG_MACH_MICRO9M=y
-CONFIG_MACH_MICRO9L=y
-CONFIG_MACH_MICRO9S=y
-CONFIG_MACH_SIM_ONE=y
-CONFIG_MACH_SNAPPER_CL15=y
 CONFIG_MACH_TS72XX=y
 CONFIG_MACH_VISION_EP9307=y
 CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="console=ttyAM0,115200 root=/dev/nfs ip=bootp"
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_SLAB=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -52,8 +41,8 @@ CONFIG_IPV6=y
 # CONFIG_IPV6_SIT is not set
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
-CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_ADV_OPTIONS=y
@@ -68,6 +57,7 @@ CONFIG_EEPROM_LEGACY=y
 CONFIG_SCSI=y
 # CONFIG_SCSI_PROC_FS is not set
 CONFIG_BLK_DEV_SD=y
+# CONFIG_BLK_DEV_BSG is not set
 CONFIG_NETDEVICES=y
 CONFIG_EP93XX_ETH=y
 CONFIG_USB_RTL8150=y
@@ -124,6 +114,7 @@ CONFIG_NFS_FS=y
 CONFIG_ROOT_NFS=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
+CONFIG_LIBCRC32C=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_SLAB=y
 CONFIG_DEBUG_SPINLOCK=y
@@ -131,4 +122,3 @@ CONFIG_DEBUG_MUTEXES=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_LL=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
-CONFIG_LIBCRC32C=y
index 2146adc..b4c2e64 100644 (file)
@@ -3,42 +3,33 @@ CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
-# CONFIG_COMPAT_BRK is not set
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_PXA=y
 CONFIG_ARCH_PXA_ESERIES=y
-# CONFIG_ARM_THUMB is not set
 CONFIG_IWMMXT=y
-CONFIG_PCCARD=y
-CONFIG_PCMCIA=m
-CONFIG_PCMCIA_PXA2XX=m
 CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_KEXEC=y
 CONFIG_FPE_NWFPE=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
 CONFIG_BINFMT_MISC=y
 CONFIG_PM=y
+CONFIG_SLAB=y
+# CONFIG_COMPAT_BRK is not set
 CONFIG_NET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
 # CONFIG_IPV6 is not set
-CONFIG_IRDA=y
-CONFIG_IRLAN=m
-CONFIG_IRCOMM=m
-CONFIG_IRDA_ULTRA=y
-CONFIG_IRDA_CACHE_LAST_LSAP=y
-CONFIG_IRDA_FAST_RR=y
-CONFIG_PXA_FICP=y
 CONFIG_CFG80211=m
 CONFIG_MAC80211=m
 CONFIG_MAC80211_RC_PID=y
 # CONFIG_MAC80211_RC_MINSTREL is not set
+CONFIG_PCCARD=y
+CONFIG_PCMCIA=m
+CONFIG_PCMCIA_PXA2XX=m
 # CONFIG_STANDALONE is not set
 CONFIG_MTD=m
 CONFIG_MTD_RAW_NAND=m
@@ -46,6 +37,7 @@ CONFIG_MTD_NAND_TMIO=m
 CONFIG_BLK_DEV_LOOP=m
 # CONFIG_SCSI_PROC_FS is not set
 CONFIG_BLK_DEV_SD=m
+# CONFIG_BLK_DEV_BSG is not set
 # CONFIG_SCSI_LOWLEVEL is not set
 CONFIG_ATA=m
 # CONFIG_SATA_PMP is not set
@@ -62,8 +54,8 @@ CONFIG_KEYBOARD_GPIO=m
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_WM97XX=m
 # CONFIG_SERIO is not set
-CONFIG_SERIAL_PXA=y
 # CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_PXA=y
 # CONFIG_HW_RANDOM is not set
 # CONFIG_HWMON is not set
 CONFIG_MFD_T7L66XB=y
@@ -76,8 +68,6 @@ CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FONTS=y
-CONFIG_FONT_MINI_4x6=y
 CONFIG_SOUND=y
 CONFIG_SND=m
 CONFIG_SND_MIXER_OSS=m
@@ -97,10 +87,11 @@ CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
-CONFIG_PARTITION_ADVANCED=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 # CONFIG_ENABLE_MUST_CHECK is not set
 CONFIG_CRYPTO_CBC=m
 CONFIG_CRYPTO_PCBC=m
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_FONTS=y
+CONFIG_FONT_MINI_4x6=y
index aa06107..1ce74f4 100644 (file)
@@ -13,12 +13,9 @@ CONFIG_BIG_LITTLE=y
 CONFIG_NR_CPUS=8
 CONFIG_HIGHMEM=y
 CONFIG_SECCOMP=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_ARM_APPENDED_DTB=y
 CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_CMDLINE="root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC1,115200 init=/linuxrc mem=256M"
-CONFIG_ENERGY_MODEL=y
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_STAT=y
 CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
@@ -34,6 +31,7 @@ CONFIG_NEON=y
 CONFIG_KERNEL_MODE_NEON=y
 CONFIG_PM_DEBUG=y
 CONFIG_PM_ADVANCED_DEBUG=y
+CONFIG_ENERGY_MODEL=y
 CONFIG_ARM_CRYPTO=y
 CONFIG_CRYPTO_SHA1_ARM_NEON=m
 CONFIG_CRYPTO_SHA256_ARM=m
@@ -170,8 +168,6 @@ CONFIG_THERMAL_EMULATION=y
 CONFIG_WATCHDOG=y
 CONFIG_S3C2410_WATCHDOG=y
 CONFIG_MFD_CROS_EC_DEV=y
-CONFIG_CHROME_PLATFORMS=y
-CONFIG_CROS_EC=y
 CONFIG_MFD_MAX14577=y
 CONFIG_MFD_MAX77686=y
 CONFIG_MFD_MAX77693=y
@@ -207,19 +203,19 @@ CONFIG_MEDIA_PLATFORM_SUPPORT=y
 CONFIG_MEDIA_USB_SUPPORT=y
 CONFIG_USB_VIDEO_CLASS=m
 CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_V4L_MEM2MEM_DRIVERS=y
+CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC=m
 CONFIG_VIDEO_SAMSUNG_EXYNOS4_IS=m
 CONFIG_VIDEO_S5P_FIMC=m
 CONFIG_VIDEO_S5P_MIPI_CSIS=m
 CONFIG_VIDEO_EXYNOS_FIMC_LITE=m
 CONFIG_VIDEO_EXYNOS4_FIMC_IS=m
-CONFIG_V4L_MEM2MEM_DRIVERS=y
 CONFIG_VIDEO_SAMSUNG_S5P_JPEG=m
 CONFIG_VIDEO_SAMSUNG_S5P_MFC=m
-CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC=m
 CONFIG_V4L_TEST_DRIVERS=y
 CONFIG_VIDEO_VIVID=m
-CONFIG_VIDEO_S5K6A3=m
 CONFIG_VIDEO_S5C73M3=m
+CONFIG_VIDEO_S5K6A3=m
 CONFIG_DRM=y
 CONFIG_DRM_EXYNOS=y
 CONFIG_DRM_EXYNOS_FIMD=y
@@ -295,11 +291,11 @@ CONFIG_MMC_DW_EXYNOS=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_CLASS_FLASH=y
-CONFIG_LEDS_AAT1290=y
 CONFIG_LEDS_GPIO=y
 CONFIG_LEDS_PWM=y
-CONFIG_LEDS_MAX77693=y
 CONFIG_LEDS_MAX8997=y
+CONFIG_LEDS_AAT1290=y
+CONFIG_LEDS_MAX77693=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_MAX8998=y
@@ -309,6 +305,8 @@ CONFIG_RTC_DRV_S5M=y
 CONFIG_RTC_DRV_S3C=y
 CONFIG_DMADEVICES=y
 CONFIG_PL330_DMA=y
+CONFIG_CHROME_PLATFORMS=y
+CONFIG_CROS_EC=y
 CONFIG_CROS_EC_I2C=y
 CONFIG_CROS_EC_SPI=y
 CONFIG_COMMON_CLK_MAX77686=y
@@ -319,12 +317,12 @@ CONFIG_DEVFREQ_GOV_PERFORMANCE=y
 CONFIG_DEVFREQ_GOV_POWERSAVE=y
 CONFIG_DEVFREQ_GOV_USERSPACE=y
 CONFIG_ARM_EXYNOS_BUS_DEVFREQ=y
-CONFIG_EXYNOS5422_DMC=y
 CONFIG_DEVFREQ_EVENT_EXYNOS_NOCP=y
 CONFIG_EXTCON=y
 CONFIG_EXTCON_MAX14577=y
 CONFIG_EXTCON_MAX77693=y
 CONFIG_EXTCON_MAX8997=y
+CONFIG_EXYNOS5422_DMC=y
 CONFIG_IIO=y
 CONFIG_EXYNOS_ADC=y
 CONFIG_STMPE_ADC=y
@@ -376,10 +374,10 @@ CONFIG_FONTS=y
 CONFIG_FONT_7x14=y
 CONFIG_PRINTK_TIME=y
 CONFIG_DYNAMIC_DEBUG=y
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
+CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
 CONFIG_SOFTLOCKUP_DETECTOR=y
 # CONFIG_DETECT_HUNG_TASK is not set
 CONFIG_PROVE_LOCKING=y
index 5d000c8..1a41391 100644 (file)
@@ -1,28 +1,21 @@
 CONFIG_LOCALVERSION="-ezx200910312315"
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_RD_BZIP2=y
 CONFIG_RD_LZMA=y
 CONFIG_EXPERT=y
-# CONFIG_COMPAT_BRK is not set
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_MODVERSIONS=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_PXA=y
 CONFIG_PXA_EZX=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_PREEMPT=y
 CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_CMDLINE="console=tty1 root=/dev/mmcblk0p2 rootfstype=ext2 rootdelay=3 ip=192.168.0.202:192.168.0.200:192.168.0.200:255.255.255.0 debug"
 CONFIG_KEXEC=y
 CONFIG_CPU_FREQ=y
@@ -33,9 +26,15 @@ CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
 CONFIG_CPU_IDLE=y
 CONFIG_FPE_NWFPE=y
 CONFIG_BINFMT_AOUT=m
-CONFIG_BINFMT_MISC=m
 CONFIG_PM=y
 CONFIG_APM_EMULATION=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_BINFMT_MISC=m
+CONFIG_SLAB=y
+# CONFIG_COMPAT_BRK is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -72,6 +71,7 @@ CONFIG_NF_CONNTRACK_SANE=m
 CONFIG_NF_CONNTRACK_SIP=m
 CONFIG_NF_CONNTRACK_TFTP=m
 CONFIG_NF_CT_NETLINK=m
+CONFIG_NF_NAT=m
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
 CONFIG_NETFILTER_XT_TARGET_LED=m
 CONFIG_NETFILTER_XT_TARGET_MARK=m
@@ -113,7 +113,6 @@ CONFIG_IP_NF_MATCH_TTL=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
 CONFIG_IP_NF_TARGET_LOG=m
-CONFIG_NF_NAT=m
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_NETMAP=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
@@ -179,15 +178,15 @@ CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=y
-# CONFIG_WLAN is not set
 CONFIG_PPP=m
-CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_FILTER=y
+CONFIG_PPP_MULTILINK=y
 CONFIG_PPP_ASYNC=m
 CONFIG_PPP_SYNC_TTY=m
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPP_BSDCOMP=m
 # CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_WLAN is not set
 CONFIG_INPUT_EVDEV=y
 # CONFIG_KEYBOARD_ATKBD is not set
 CONFIG_KEYBOARD_GPIO=y
@@ -199,9 +198,9 @@ CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
 CONFIG_INPUT_PCAP=y
 # CONFIG_SERIO is not set
+CONFIG_LEGACY_PTY_COUNT=8
 CONFIG_SERIAL_PXA=y
 CONFIG_SERIAL_PXA_CONSOLE=y
-CONFIG_LEGACY_PTY_COUNT=8
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
@@ -218,27 +217,27 @@ CONFIG_REGULATOR_PCAP=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_VIDEO_DEV=y
 CONFIG_MEDIA_TUNER_CUSTOMISE=y
+CONFIG_RADIO_TEA5764=y
+# CONFIG_MEDIA_TUNER_MC44S803 is not set
+# CONFIG_MEDIA_TUNER_MT2060 is not set
+# CONFIG_MEDIA_TUNER_MT20XX is not set
+# CONFIG_MEDIA_TUNER_MT2131 is not set
+# CONFIG_MEDIA_TUNER_MT2266 is not set
+# CONFIG_MEDIA_TUNER_MXL5005S is not set
+# CONFIG_MEDIA_TUNER_MXL5007T is not set
+# CONFIG_MEDIA_TUNER_QT1010 is not set
 # CONFIG_MEDIA_TUNER_SIMPLE is not set
-# CONFIG_MEDIA_TUNER_TDA8290 is not set
-# CONFIG_MEDIA_TUNER_TDA827X is not set
 # CONFIG_MEDIA_TUNER_TDA18271 is not set
+# CONFIG_MEDIA_TUNER_TDA827X is not set
+# CONFIG_MEDIA_TUNER_TDA8290 is not set
 # CONFIG_MEDIA_TUNER_TDA9887 is not set
 # CONFIG_MEDIA_TUNER_TEA5761 is not set
 # CONFIG_MEDIA_TUNER_TEA5767 is not set
-# CONFIG_MEDIA_TUNER_MT20XX is not set
-# CONFIG_MEDIA_TUNER_MT2060 is not set
-# CONFIG_MEDIA_TUNER_MT2266 is not set
-# CONFIG_MEDIA_TUNER_MT2131 is not set
-# CONFIG_MEDIA_TUNER_QT1010 is not set
 # CONFIG_MEDIA_TUNER_XC2028 is not set
 # CONFIG_MEDIA_TUNER_XC5000 is not set
-# CONFIG_MEDIA_TUNER_MXL5005S is not set
-# CONFIG_MEDIA_TUNER_MXL5007T is not set
-# CONFIG_MEDIA_TUNER_MC44S803 is not set
 # CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set
 CONFIG_VIDEO_PXA27x=y
 # CONFIG_V4L_USB_DRIVERS is not set
-CONFIG_RADIO_TEA5764=y
 CONFIG_FB=y
 CONFIG_FB_PXA=y
 CONFIG_FB_PXA_OVERLAY=y
@@ -248,8 +247,6 @@ CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_PWM=y
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FONTS=y
-CONFIG_FONT_MINI_4x6=y
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_MIXER_OSS=y
@@ -260,8 +257,8 @@ CONFIG_SND_PCM_OSS=y
 # CONFIG_SND_USB is not set
 CONFIG_SND_SOC=y
 CONFIG_SND_PXA2XX_SOC=y
-# CONFIG_USB_HID is not set
 CONFIG_HID_APPLE=m
+# CONFIG_USB_HID is not set
 CONFIG_USB=y
 CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_GADGET=y
@@ -354,14 +351,8 @@ CONFIG_NLS_ISO8859_15=m
 CONFIG_NLS_KOI8_R=m
 CONFIG_NLS_KOI8_U=m
 CONFIG_NLS_UTF8=m
-CONFIG_PRINTK_TIME=y
-CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_SCHED_DEBUG is not set
 CONFIG_DEBUG_RT_MUTEXES=y
-CONFIG_PROVE_LOCKING=y
-# CONFIG_FTRACE is not set
-CONFIG_DEBUG_USER=y
 CONFIG_CRYPTO_NULL=m
 CONFIG_CRYPTO_CRYPTD=m
 CONFIG_CRYPTO_TEST=m
@@ -389,3 +380,11 @@ CONFIG_CRYPTO_SERPENT=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_FONTS=y
+CONFIG_FONT_MINI_4x6=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_FS=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_PROVE_LOCKING=y
+# CONFIG_FTRACE is not set
+CONFIG_DEBUG_USER=y
index 7a32de5..5040708 100644 (file)
@@ -4,18 +4,16 @@ CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EXPERT=y
 # CONFIG_HOTPLUG is not set
-CONFIG_MODULES=y
 CONFIG_ARCH_FOOTBRIDGE=y
-CONFIG_ARCH_CATS=y
 CONFIG_ARCH_EBSA285_HOST=y
 CONFIG_ARCH_NETWINDER=y
-CONFIG_LEDS=y
-CONFIG_LEDS_TIMER=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_FPE_NWFPE=y
 CONFIG_FPE_NWFPE_XP=y
 CONFIG_BINFMT_AOUT=y
+CONFIG_MODULES=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_ACORN_PARTITION=y
+CONFIG_ACORN_PARTITION_ADFS=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -26,15 +24,6 @@ CONFIG_IP_PNP_BOOTP=y
 CONFIG_SYN_COOKIES=y
 # CONFIG_IPV6 is not set
 CONFIG_ATM=y
-CONFIG_IRDA=m
-CONFIG_IRLAN=m
-CONFIG_IRNET=m
-CONFIG_IRCOMM=m
-CONFIG_IRDA_ULTRA=y
-CONFIG_IRDA_CACHE_LAST_LSAP=y
-CONFIG_IRDA_FAST_RR=y
-CONFIG_IRDA_DEBUG=y
-CONFIG_WINBOND_FIR=m
 CONFIG_PARPORT=y
 CONFIG_PARPORT_PC=y
 CONFIG_PARPORT_PC_FIFO=y
@@ -71,17 +60,17 @@ CONFIG_VORTEX=y
 CONFIG_NET_PCI=y
 CONFIG_NE2K_PCI=y
 CONFIG_PPP=m
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
 CONFIG_PPPOE=m
+CONFIG_PPP_ASYNC=m
 CONFIG_SLIP=m
 CONFIG_SLIP_COMPRESSED=y
 CONFIG_SLIP_SMART=y
 CONFIG_SLIP_MODE_SLIP6=y
-CONFIG_SERIAL_NONSTANDARD=y
 CONFIG_SERIAL_21285=y
 CONFIG_SERIAL_21285_CONSOLE=y
+CONFIG_SERIAL_NONSTANDARD=y
 CONFIG_PRINTER=m
 CONFIG_DS1620=y
 CONFIG_NWBUTTON=y
@@ -99,6 +88,10 @@ CONFIG_SOUND=m
 CONFIG_USB=m
 CONFIG_USB_MON=m
 CONFIG_USB_PRINTER=m
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
 CONFIG_EXT2_FS=y
 CONFIG_AUTOFS4_FS=y
 CONFIG_ISO9660_FS=m
@@ -109,9 +102,6 @@ CONFIG_ADFS_FS=m
 CONFIG_NFS_FS=y
 CONFIG_ROOT_NFS=y
 CONFIG_NFSD=m
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_ACORN_PARTITION=y
-CONFIG_ACORN_PARTITION_ADFS=y
 CONFIG_NLS=y
 CONFIG_NLS_CODEPAGE_437=m
 CONFIG_NLS_CODEPAGE_850=m
index c02b3e4..5bd1ec5 100644 (file)
@@ -1,28 +1,21 @@
 CONFIG_SYSVIPC=y
 CONFIG_NO_HZ_IDLE=y
 CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_MODULES=y
-# CONFIG_BLK_DEV_BSG is not set
 CONFIG_ARCH_SA1100=y
 CONFIG_SA1100_H3600=y
-CONFIG_PCCARD=y
-CONFIG_PCMCIA_SA1100=y
-CONFIG_PREEMPT=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 # CONFIG_CPU_FREQ_STAT is not set
 CONFIG_FPE_NWFPE=y
+CONFIG_MODULES=y
 CONFIG_NET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
 # CONFIG_IPV6 is not set
-CONFIG_IRDA=m
-CONFIG_IRLAN=m
-CONFIG_IRNET=m
-CONFIG_IRCOMM=m
 # CONFIG_WIRELESS is not set
+CONFIG_PCCARD=y
+CONFIG_PCMCIA_SA1100=y
 CONFIG_MTD=y
 CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_BLOCK=y
@@ -36,6 +29,7 @@ CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_BLK_DEV_SD=y
+# CONFIG_BLK_DEV_BSG is not set
 CONFIG_ATA=y
 CONFIG_PATA_PCMCIA=y
 CONFIG_NETDEVICES=y
index a67d602..d01f1a6 100644 (file)
@@ -5,22 +5,21 @@ CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
 # CONFIG_UID16 is not set
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_PXA=y
 CONFIG_MACH_H5000=y
 CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_CMDLINE="keepinitrd"
 CONFIG_KEXEC=y
 CONFIG_FPE_NWFPE=y
 CONFIG_PM=y
 CONFIG_APM_EMULATION=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_SLAB=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -43,9 +42,9 @@ CONFIG_MTD_PHYSMAP=y
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_SERIO is not set
+CONFIG_LEGACY_PTY_COUNT=32
 CONFIG_SERIAL_PXA=y
 CONFIG_SERIAL_PXA_CONSOLE=y
-CONFIG_LEGACY_PTY_COUNT=32
 # CONFIG_HW_RANDOM is not set
 # CONFIG_HWMON is not set
 # CONFIG_VGA_CONSOLE is not set
@@ -60,11 +59,7 @@ CONFIG_TMPFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_COMPRESSION_OPTIONS=y
 # CONFIG_NETWORK_FILESYSTEMS is not set
-CONFIG_PRINTK_TIME=y
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_SCHED_DEBUG is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_FTRACE is not set
 CONFIG_CRYPTO=y
 CONFIG_CRYPTO_HMAC=y
 CONFIG_CRYPTO_MD5=y
@@ -73,3 +68,7 @@ CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_DEFLATE=y
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC_CCITT=y
+CONFIG_PRINTK_TIME=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_FTRACE is not set
index 742d18c..b9327b2 100644 (file)
@@ -1,17 +1,14 @@
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_MODULES=y
 CONFIG_ARCH_SA1100=y
 CONFIG_SA1100_HACKKIT=y
-CONFIG_LEDS=y
-CONFIG_LEDS_CPU=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_CMDLINE="console=ttySA0,115200 root=/dev/ram0 initrd=0xc0400000,8M init=/rootshell"
 CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
 CONFIG_FPE_NWFPE=y
 CONFIG_BINFMT_AOUT=y
+CONFIG_MODULES=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -33,13 +30,17 @@ CONFIG_DUMMY=y
 CONFIG_SERIAL_SA1100=y
 CONFIG_SERIAL_SA1100_CONSOLE=y
 # CONFIG_VGA_CONSOLE is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_CPU=y
 CONFIG_EXT2_FS=y
 CONFIG_MSDOS_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_CRAMFS=y
-CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_SPINLOCK=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_LL=y
index 74d611e..1db5356 100644 (file)
@@ -1,24 +1,25 @@
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_RD_LZMA=y
 CONFIG_ARCH_HISI=y
 CONFIG_ARCH_HI3xxx=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_CMDLINE_PARTITION=y
-CONFIG_ARCH_HIX5HD2=y
 CONFIG_ARCH_HIP01=y
 CONFIG_ARCH_HIP04=y
+CONFIG_ARCH_HIX5HD2=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=16
-CONFIG_PREEMPT=y
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
 CONFIG_ARM_APPENDED_DTB=y
 CONFIG_ARM_ATAG_DTB_COMPAT=y
+CONFIG_VFP=y
 CONFIG_NEON=y
 CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER=y
 CONFIG_PM=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_CMDLINE_PARTITION=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -39,20 +40,20 @@ CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=2
 CONFIG_SERIAL_8250_RUNTIME_UARTS=2
 CONFIG_SERIAL_8250_DW=y
+CONFIG_SERIAL_OF_PLATFORM=y
 CONFIG_SERIAL_AMBA_PL011=y
 CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
-CONFIG_SERIAL_OF_PLATFORM=y
 CONFIG_I2C_DESIGNWARE_PLATFORM=y
 CONFIG_SPI=y
 CONFIG_SPI_PL022=y
 CONFIG_PINCTRL_SINGLE=y
-CONFIG_DEBUG_GPIO=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIOLIB=y
-CONFIG_GPIO_GENERIC_PLATFORM=y
 CONFIG_REGULATOR_GPIO=y
+CONFIG_DEBUG_GPIO=y
 CONFIG_GPIO_DWAPB=y
 CONFIG_MFD_SYSCON=y
+CONFIG_GPIO_GENERIC_PLATFORM=y
 CONFIG_POWER_RESET_SYSCON=y
 CONFIG_DRM=y
 CONFIG_FB_SIMPLE=y
@@ -66,13 +67,13 @@ CONFIG_USB_OHCI_HCD_PLATFORM=y
 CONFIG_USB_STORAGE=y
 CONFIG_NOP_USB_XCEIV=y
 CONFIG_MMC=y
-CONFIG_RTC_CLASS=y
 CONFIG_MMC_DW=y
 CONFIG_MMC_DW_PLTFM=y
+CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_PL031=y
 CONFIG_DMADEVICES=y
-CONFIG_DW_DMAC=y
 CONFIG_PL330_DMA=y
+CONFIG_DW_DMAC=y
 CONFIG_PWM=y
 CONFIG_PHY_HIX5HD2_SATA=y
 CONFIG_EXT4_FS=y
@@ -81,11 +82,10 @@ CONFIG_NFS_FS=y
 CONFIG_NFS_V3_ACL=y
 CONFIG_NFS_V4=y
 CONFIG_ROOT_NFS=y
-CONFIG_PRINTK_TIME=y
-CONFIG_DEBUG_FS=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_LOCKUP_DETECTOR=y
-CONFIG_VFP=y
 CONFIG_VFPv3=y
+CONFIG_DEBUG_FS=y
index 1d9fa77..bfa2a95 100644 (file)
@@ -1,4 +1,3 @@
-# CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_NO_HZ=y
@@ -8,8 +7,6 @@ CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CGROUPS=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EXPERT=y
-# CONFIG_COMPAT_BRK is not set
-CONFIG_SLAB=y
 CONFIG_PROFILING=y
 CONFIG_ARCH_MULTI_V4T=y
 CONFIG_ARCH_MULTI_V5=y
@@ -24,13 +21,13 @@ CONFIG_SOC_IMX1=y
 CONFIG_SOC_IMX25=y
 CONFIG_SOC_IMX27=y
 CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_PM_DEBUG=y
 CONFIG_KPROBES=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_SWAP is not set
+CONFIG_SLAB=y
+# CONFIG_COMPAT_BRK is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -63,6 +60,7 @@ CONFIG_MTD_UBI=y
 CONFIG_EEPROM_AT24=y
 CONFIG_EEPROM_AT25=y
 CONFIG_BLK_DEV_SD=y
+# CONFIG_BLK_DEV_BSG is not set
 CONFIG_ATA=y
 CONFIG_PATA_IMX=y
 CONFIG_NETDEVICES=y
index 88a3602..0101253 100644 (file)
@@ -13,8 +13,6 @@ CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EXPERT=y
 CONFIG_PERF_EVENTS=y
-# CONFIG_SLUB_DEBUG is not set
-# CONFIG_COMPAT_BRK is not set
 CONFIG_ARCH_MULTI_V6=y
 CONFIG_ARCH_MXC=y
 CONFIG_SOC_IMX31=y
@@ -58,6 +56,7 @@ CONFIG_MODULE_UNLOAD=y
 CONFIG_MODVERSIONS=y
 CONFIG_MODULE_SRCVERSION_ALL=y
 CONFIG_BINFMT_MISC=m
+# CONFIG_COMPAT_BRK is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -258,14 +257,14 @@ CONFIG_MEDIA_SUPPORT=y
 CONFIG_MEDIA_USB_SUPPORT=y
 CONFIG_USB_VIDEO_CLASS=m
 CONFIG_V4L_PLATFORM_DRIVERS=y
-CONFIG_VIDEO_MUX=y
 CONFIG_V4L_MEM2MEM_DRIVERS=y
+CONFIG_VIDEO_MUX=y
 CONFIG_VIDEO_CODA=m
 CONFIG_VIDEO_IMX_PXP=y
-CONFIG_VIDEO_ADV7180=m
 CONFIG_VIDEO_OV2680=m
 CONFIG_VIDEO_OV5640=m
 CONFIG_VIDEO_OV5645=m
+CONFIG_VIDEO_ADV7180=m
 CONFIG_IMX_IPUV3_CORE=y
 CONFIG_DRM=y
 CONFIG_DRM_MSM=y
@@ -468,6 +467,7 @@ CONFIG_PRINTK_TIME=y
 # CONFIG_DEBUG_BUGVERBOSE is not set
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
+# CONFIG_SLUB_DEBUG is not set
 # CONFIG_SCHED_DEBUG is not set
 CONFIG_PROVE_LOCKING=y
 # CONFIG_FTRACE is not set
index 5b48572..9ca43c8 100644 (file)
@@ -81,5 +81,5 @@ CONFIG_ROOT_NFS=y
 CONFIG_NFSD=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
-CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
index ead14c3..c16e92c 100644 (file)
@@ -3,22 +3,20 @@ CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_KALLSYMS_ALL=y
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_IOP32X=y
 CONFIG_MACH_GLANTANK=y
 CONFIG_ARCH_IQ80321=y
 CONFIG_ARCH_IQ31244=y
 CONFIG_MACH_N2100=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs ip=bootp cachepolicy=writealloc"
 CONFIG_FPE_NWFPE=y
 CONFIG_BINFMT_AOUT=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_SLAB=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -45,6 +43,7 @@ CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_SG=y
+# CONFIG_BLK_DEV_BSG is not set
 CONFIG_ATA=y
 CONFIG_SATA_SIL=y
 CONFIG_SATA_VITESSE=y
@@ -95,12 +94,6 @@ CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
 CONFIG_NFSD=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_LL=y
-CONFIG_DEBUG_LL_UART_8250=y
 CONFIG_KEYS=y
 CONFIG_CRYPTO_NULL=y
 CONFIG_CRYPTO_LRW=y
@@ -127,3 +120,8 @@ CONFIG_CRYPTO_TEA=y
 CONFIG_CRYPTO_TWOFISH=y
 CONFIG_CRYPTO_DEFLATE=y
 CONFIG_LIBCRC32C=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_LL=y
+CONFIG_DEBUG_LL_UART_8250=y
index 960978a..6b65ac2 100644 (file)
@@ -8,7 +8,6 @@ CONFIG_INITRAMFS_COMPRESSION_XZ=y
 CONFIG_EXPERT=y
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_IXP4XX=y
-# CONFIG_ARM_THUMB is not set
 CONFIG_CPU_BIG_ENDIAN=y
 CONFIG_AEABI=y
 CONFIG_CMDLINE="console=ttyS0,115200"
index 069f60f..3dcf89d 100644 (file)
@@ -1,18 +1,14 @@
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_MODULES=y
-# CONFIG_BLK_DEV_BSG is not set
 CONFIG_ARCH_SA1100=y
 CONFIG_SA1100_JORNADA720=y
 CONFIG_SA1100_JORNADA720_SSP=y
-CONFIG_PCCARD=y
-CONFIG_PCMCIA_SA1100=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_FPE_NWFPE=y
 CONFIG_BINFMT_AOUT=y
 CONFIG_PM=y
+CONFIG_MODULES=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -20,13 +16,12 @@ CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 # CONFIG_IPV6 is not set
 CONFIG_NETFILTER=y
-CONFIG_IRDA=m
-CONFIG_IRLAN=m
-CONFIG_IRCOMM=m
-CONFIG_SA1100_FIR=m
+CONFIG_PCCARD=y
+CONFIG_PCMCIA_SA1100=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_NBD=y
 CONFIG_BLK_DEV_SD=y
+# CONFIG_BLK_DEV_BSG is not set
 CONFIG_ATA=y
 CONFIG_PATA_PCMCIA=y
 CONFIG_NETDEVICES=y
@@ -40,9 +35,9 @@ CONFIG_KEYBOARD_HP7XX=y
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_HP7XX=y
+CONFIG_LEGACY_PTY_COUNT=32
 CONFIG_SERIAL_SA1100=y
 CONFIG_SERIAL_SA1100_CONSOLE=y
-CONFIG_LEGACY_PTY_COUNT=32
 # CONFIG_HWMON is not set
 CONFIG_FB=y
 CONFIG_FB_S1D13XXX=y
index b1bcb85..68b89b9 100644 (file)
@@ -1,43 +1,41 @@
-# CONFIG_SWAP is not set
 CONFIG_POSIX_MQUEUE=y
 CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CGROUPS=y
+CONFIG_BLK_CGROUP=y
+CONFIG_CGROUP_SCHED=y
 CONFIG_CGROUP_FREEZER=y
 CONFIG_CGROUP_DEVICE=y
 CONFIG_CGROUP_CPUACCT=y
-CONFIG_CGROUP_SCHED=y
-CONFIG_BLK_CGROUP=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_KALLSYMS_ALL=y
 # CONFIG_ELF_CORE is not set
 # CONFIG_BASE_FULL is not set
+CONFIG_KALLSYMS_ALL=y
 CONFIG_EMBEDDED=y
 CONFIG_PROFILING=y
-CONFIG_KPROBES=y
-CONFIG_MODULES=y
-CONFIG_MODULE_FORCE_LOAD=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_MODVERSIONS=y
 CONFIG_ARCH_KEYSTONE=y
 CONFIG_ARM_LPAE=y
-CONFIG_PCI=y
-CONFIG_PCI_MSI=y
 CONFIG_PCI_KEYSTONE=y
 CONFIG_SMP=y
 CONFIG_HOTPLUG_CPU=y
 CONFIG_ARM_PSCI=y
-CONFIG_PREEMPT=y
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
-CONFIG_CMA=y
 CONFIG_VFP=y
 CONFIG_NEON=y
 # CONFIG_SUSPEND is not set
 CONFIG_PM=y
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_SWAP is not set
+CONFIG_CMA=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -113,9 +111,11 @@ CONFIG_VLAN_8021Q=y
 CONFIG_CAN=m
 CONFIG_CAN_C_CAN=m
 CONFIG_CAN_C_CAN_PLATFORM=m
+CONFIG_PCI=y
+CONFIG_PCI_MSI=y
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
-CONFIG_DMA_CMA=y
+CONFIG_TI_SCI_PROTOCOL=y
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
@@ -131,10 +131,15 @@ CONFIG_EEPROM_AT24=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_NETDEVICES=y
+CONFIG_TI_CPTS=y
 CONFIG_TI_KEYSTONE_NETCP=y
 CONFIG_TI_KEYSTONE_NETCP_ETHSS=y
-CONFIG_TI_CPTS=y
 CONFIG_MARVELL_PHY=y
+CONFIG_MICREL_PHY=y
+CONFIG_DP83867_PHY=y
+CONFIG_INPUT_EVDEV=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_GPIO_DECODER=m
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_OF_PLATFORM=y
@@ -144,6 +149,7 @@ CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_DAVINCI=y
 CONFIG_SPI=y
+CONFIG_SPI_CADENCE_QUADSPI=y
 CONFIG_SPI_DAVINCI=y
 CONFIG_SPI_SPIDEV=y
 CONFIG_PTP_1588_CLOCK=y
@@ -152,9 +158,10 @@ CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_DAVINCI=y
 CONFIG_GPIO_SYSCON=y
-CONFIG_POWER_SUPPLY=y
+CONFIG_GPIO_PCA953X=m
 CONFIG_POWER_RESET=y
 CONFIG_POWER_RESET_KEYSTONE=y
+CONFIG_POWER_SUPPLY=y
 # CONFIG_HWMON is not set
 CONFIG_WATCHDOG=y
 CONFIG_DAVINCI_WATCHDOG=y
@@ -166,8 +173,8 @@ CONFIG_USB_MON=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_DWC3=y
-CONFIG_NOP_USB_XCEIV=y
 CONFIG_KEYSTONE_USB_PHY=y
+CONFIG_NOP_USB_XCEIV=y
 CONFIG_MMC=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
@@ -180,6 +187,8 @@ CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_ONESHOT=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
 CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+CONFIG_LEDS_TRIGGER_CPU=y
+CONFIG_LEDS_TRIGGER_ACTIVITY=y
 CONFIG_LEDS_TRIGGER_GPIO=y
 CONFIG_DMADEVICES=y
 CONFIG_TI_EDMA=y
@@ -196,7 +205,6 @@ CONFIG_PWM_TIECAP=m
 CONFIG_KEYSTONE_IRQ=y
 CONFIG_RESET_TI_SCI=m
 CONFIG_RESET_TI_SYSCON=m
-CONFIG_TI_SCI_PROTOCOL=y
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_POSIX_ACL=y
 CONFIG_FANOTIFY=y
@@ -216,10 +224,7 @@ CONFIG_NFSD=y
 CONFIG_NFSD_V3_ACL=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
-CONFIG_PRINTK_TIME=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_SHIRQ=y
-CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 CONFIG_CRYPTO_USER=y
 CONFIG_CRYPTO_AUTHENC=y
 CONFIG_CRYPTO_CBC=y
@@ -229,12 +234,7 @@ CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_ANSI_CPRNG=y
 CONFIG_CRYPTO_USER_API_HASH=y
 CONFIG_CRYPTO_USER_API_SKCIPHER=y
-CONFIG_SPI_CADENCE_QUADSPI=y
-CONFIG_INPUT_MISC=y
-CONFIG_INPUT_EVDEV=m
-CONFIG_INPUT_GPIO_DECODER=m
-CONFIG_GPIO_PCA953X=m
-CONFIG_LEDS_TRIGGER_ACTIVITY=y
-CONFIG_LEDS_TRIGGER_CPU=y
-CONFIG_MICREL_PHY=y
-CONFIG_DP83867_PHY=y
+CONFIG_DMA_CMA=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_SHIRQ=y
+CONFIG_DEBUG_USER=y
index 2dfa33d..0c2f19d 100644 (file)
@@ -1,32 +1,22 @@
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_MODULES=y
 CONFIG_ARCH_SA1100=y
 CONFIG_SA1100_LART=y
-CONFIG_LEDS=y
-CONFIG_LEDS_CPU=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_CMDLINE="console=ttySA0,9600 root=/dev/ram"
 CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
 CONFIG_FPE_NWFPE=y
 CONFIG_BINFMT_AOUT=y
 CONFIG_PM=y
+CONFIG_MODULES=y
 CONFIG_NET=y
 CONFIG_PACKET=m
 CONFIG_UNIX=y
 CONFIG_INET=y
 CONFIG_SYN_COOKIES=y
 # CONFIG_IPV6 is not set
-CONFIG_IRDA=m
-CONFIG_IRLAN=m
-CONFIG_IRNET=m
-CONFIG_IRCOMM=m
-CONFIG_IRDA_CACHE_LAST_LSAP=y
-CONFIG_IRDA_DEBUG=y
-CONFIG_SA1100_FIR=m
 CONFIG_MTD=y
 CONFIG_MTD_DEBUG=y
 CONFIG_MTD_DEBUG_VERBOSE=1
@@ -37,15 +27,19 @@ CONFIG_NETDEVICES=y
 CONFIG_DUMMY=m
 CONFIG_NET_ETHERNET=y
 CONFIG_PPP=m
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_ASYNC=m
 CONFIG_SLIP=m
 CONFIG_SLIP_COMPRESSED=y
 CONFIG_SERIAL_SA1100=y
 CONFIG_SERIAL_SA1100_CONSOLE=y
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_SOUND=m
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_CPU=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=m
 CONFIG_REISERFS_FS=m
index 688c984..142c170 100644 (file)
@@ -15,8 +15,6 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
 CONFIG_EMBEDDED=y
-# CONFIG_VM_EVENT_COUNTERS is not set
-# CONFIG_SLUB_DEBUG is not set
 # CONFIG_MMU is not set
 CONFIG_ARCH_LPC18XX=y
 CONFIG_SET_MEM_PARAM=y
@@ -24,13 +22,11 @@ CONFIG_DRAM_BASE=0x28000000
 CONFIG_DRAM_SIZE=0x02000000
 CONFIG_FLASH_MEM_BASE=0x1b000000
 CONFIG_FLASH_SIZE=0x00080000
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_ARM_APPENDED_DTB=y
-# CONFIG_BLK_DEV_BSG is not set
 CONFIG_BINFMT_FLAT=y
 CONFIG_BINFMT_ZFLAT=y
 # CONFIG_COREDUMP is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -60,6 +56,7 @@ CONFIG_SRAM=y
 CONFIG_EEPROM_AT24=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
+# CONFIG_BLK_DEV_BSG is not set
 # CONFIG_SCSI_LOWLEVEL is not set
 CONFIG_NETDEVICES=y
 # CONFIG_NET_VENDOR_ARC is not set
@@ -92,11 +89,11 @@ CONFIG_KEYBOARD_GPIO_POLLED=y
 # CONFIG_VT is not set
 # CONFIG_UNIX98_PTYS is not set
 # CONFIG_LEGACY_PTYS is not set
-CONFIG_SERIAL_NONSTANDARD=y
 CONFIG_SERIAL_8250=y
 # CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SERIAL_NONSTANDARD=y
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C_LPC2K=y
 CONFIG_SPI=y
@@ -153,11 +150,12 @@ CONFIG_JFFS2_FS=y
 CONFIG_CRC_ITU_T=y
 CONFIG_CRC7=y
 CONFIG_PRINTK_TIME=y
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 # CONFIG_ENABLE_MUST_CHECK is not set
-CONFIG_DEBUG_FS=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+# CONFIG_SLUB_DEBUG is not set
 # CONFIG_SCHED_DEBUG is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
 CONFIG_DEBUG_LL=y
 CONFIG_EARLY_PRINTK=y
index 6c3e4a1..8a41fe4 100644 (file)
@@ -10,12 +10,9 @@ CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_LPC32XX=y
 CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_ARM_APPENDED_DTB=y
 CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_CMDLINE="console=ttyS0,115200n81 root=/dev/ram0"
@@ -24,9 +21,9 @@ CONFIG_VFP=y
 CONFIG_JUMP_LABEL=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 CONFIG_PARTITION_ADVANCED=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_SLAB=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -60,6 +57,7 @@ CONFIG_EEPROM_AT24=y
 CONFIG_EEPROM_AT25=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
+# CONFIG_BLK_DEV_BSG is not set
 CONFIG_NETDEVICES=y
 # CONFIG_NET_VENDOR_BROADCOM is not set
 # CONFIG_NET_VENDOR_CIRRUS is not set
@@ -93,11 +91,11 @@ CONFIG_SERIAL_HS_LPC32XX_CONSOLE=y
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_PNX=y
-CONFIG_GPIO_LPC32XX=y
 CONFIG_SPI=y
 CONFIG_SPI_PL022=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_GENERIC_PLATFORM=y
+CONFIG_GPIO_LPC32XX=y
 CONFIG_GPIO_PCA953X=y
 CONFIG_GPIO_PCF857X=y
 CONFIG_SENSORS_DS620=y
@@ -187,10 +185,10 @@ CONFIG_CRYPTO_ANSI_CPRNG=y
 CONFIG_CRC_CCITT=y
 CONFIG_PRINTK_TIME=y
 CONFIG_DYNAMIC_DEBUG=y
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 CONFIG_GDB_SCRIPTS=y
-CONFIG_DEBUG_FS=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
 CONFIG_PANIC_ON_OOPS=y
 CONFIG_PANIC_TIMEOUT=5
 # CONFIG_SCHED_DEBUG is not set
index 5c0a671..b0c21a9 100644 (file)
@@ -1,15 +1,13 @@
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SLAB=y
-CONFIG_MODULES=y
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_PXA=y
 CONFIG_MACH_LOGICPD_PXA270=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_CMDLINE="root=/dev/nfs ip=bootp console=ttyS0,115200 mem=64M"
 CONFIG_FPE_NWFPE=y
+CONFIG_MODULES=y
+CONFIG_SLAB=y
 CONFIG_NET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
@@ -53,8 +51,8 @@ CONFIG_JFFS2_FS=y
 CONFIG_NFS_FS=y
 CONFIG_ROOT_NFS=y
 CONFIG_NLS_ISO8859_1=y
-CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
+CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_LL=y
index cf49dc1..4fc744c 100644 (file)
@@ -1,24 +1,20 @@
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_MODULES=y
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_PXA=y
 CONFIG_ARCH_LUBBOCK=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_PCCARD=y
-CONFIG_PCMCIA_PXA2XX=y
-CONFIG_LEDS=y
-CONFIG_LEDS_CPU=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_CMDLINE="root=/dev/nfs ip=bootp console=ttyS0,115200 mem=64M"
 CONFIG_FPE_NWFPE=y
+CONFIG_MODULES=y
 CONFIG_NET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_BOOTP=y
 # CONFIG_IPV6 is not set
+CONFIG_PCCARD=y
+CONFIG_PCMCIA_PXA2XX=y
 CONFIG_MTD=y
 CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_BLOCK=y
@@ -29,9 +25,9 @@ CONFIG_MTD_CFI_GEOMETRY=y
 CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
-CONFIG_SMC91X=y
 CONFIG_NET_PCMCIA=y
 CONFIG_PCMCIA_PCNET=y
+CONFIG_SMC91X=y
 CONFIG_INPUT_EVDEV=y
 # CONFIG_SERIO_SERPORT is not set
 CONFIG_SERIO_SA1111=y
@@ -40,14 +36,18 @@ CONFIG_SERIAL_PXA_CONSOLE=y
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_USB_GADGET=y
 CONFIG_USB_G_SERIAL=m
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_CPU=y
 CONFIG_EXT2_FS=y
 CONFIG_MSDOS_FS=y
 CONFIG_JFFS2_FS=y
 CONFIG_NFS_FS=y
 CONFIG_ROOT_NFS=y
 CONFIG_NLS_ISO8859_1=y
-CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
+CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_LL=y
index 13da808..9cbb63c 100644 (file)
@@ -1,29 +1,28 @@
 CONFIG_SYSVIPC=y
+CONFIG_NO_HZ=y
+CONFIG_PREEMPT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=16
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EXPERT=y
 # CONFIG_UID16 is not set
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_PXA=y
 CONFIG_MACH_H4700=y
 CONFIG_MACH_MAGICIAN=y
-CONFIG_NO_HZ=y
-CONFIG_PREEMPT=y
 CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_CMDLINE="keepinitrd"
 CONFIG_KEXEC=y
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
 CONFIG_FPE_NWFPE=y
 CONFIG_PM=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SLAB=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -35,15 +34,6 @@ CONFIG_IP_PNP=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
-CONFIG_IRDA=m
-CONFIG_IRLAN=m
-CONFIG_IRCOMM=m
-CONFIG_IRDA_ULTRA=y
-CONFIG_IRDA_CACHE_LAST_LSAP=y
-CONFIG_IRDA_FAST_RR=y
-CONFIG_IRDA_DEBUG=y
-CONFIG_IRTTY_SIR=m
-CONFIG_PXA_FICP=m
 CONFIG_BT=m
 CONFIG_BT_RFCOMM=m
 CONFIG_BT_RFCOMM_TTY=y
@@ -60,11 +50,11 @@ CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_PHYSMAP=y
 CONFIG_NETDEVICES=y
 CONFIG_PPP=m
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_MPPE=m
 # CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_PPP_ASYNC=m
 CONFIG_INPUT_EVDEV=y
 # CONFIG_KEYBOARD_ATKBD is not set
 CONFIG_KEYBOARD_GPIO=y
@@ -73,19 +63,19 @@ CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=m
 # CONFIG_SERIO is not set
-CONFIG_SERIAL_PXA=y
 # CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_PXA=y
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=m
 CONFIG_I2C_PXA=y
 CONFIG_W1_MASTER_DS1WM=y
+CONFIG_HTC_EGPIO=y
 CONFIG_POWER_SUPPLY=y
 CONFIG_PDA_POWER=y
 CONFIG_BATTERY_DS2760=y
 # CONFIG_HWMON is not set
 CONFIG_MFD_ASIC3=y
-CONFIG_HTC_EGPIO=y
 CONFIG_HTC_PASIC3=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_GPIO=y
@@ -99,8 +89,6 @@ CONFIG_BACKLIGHT_PWM=y
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
-CONFIG_FONTS=y
-CONFIG_FONT_MINI_4x6=y
 CONFIG_SOUND=y
 CONFIG_SND=m
 CONFIG_SND_MIXER_OSS=m
@@ -112,6 +100,7 @@ CONFIG_SND_PXA2XX_SOC=m
 CONFIG_USB=y
 CONFIG_USB_MON=m
 CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_GPIO_VBUS=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_VBUS_DRAW=500
 CONFIG_USB_PXA27X=y
@@ -121,7 +110,6 @@ CONFIG_USB_GADGETFS=m
 CONFIG_USB_MASS_STORAGE=m
 CONFIG_USB_G_SERIAL=m
 CONFIG_USB_CDC_COMPOSITE=m
-CONFIG_USB_GPIO_VBUS=y
 CONFIG_MMC=y
 CONFIG_SDIO_UART=m
 CONFIG_MMC_PXA=y
@@ -148,6 +136,11 @@ CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_CODEPAGE_1251=m
 CONFIG_NLS_ISO8859_1=y
 CONFIG_NLS_UTF8=y
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_CCITT=y
+CONFIG_FONTS=y
+CONFIG_FONT_MINI_4x6=y
 CONFIG_PRINTK_TIME=y
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_SCHED_DEBUG is not set
@@ -155,7 +148,4 @@ CONFIG_TIMER_STATS=y
 # CONFIG_DEBUG_PREEMPT is not set
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_LL=y
-CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
-# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_CCITT=y
index 03b4c61..096cd7b 100644 (file)
@@ -1,16 +1,12 @@
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_MODULES=y
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_PXA=y
 CONFIG_MACH_MAINSTONE=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_LEDS=y
-CONFIG_LEDS_CPU=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_CMDLINE="root=/dev/nfs ip=bootp console=ttyS0,115200 mem=64M"
 CONFIG_FPE_NWFPE=y
+CONFIG_MODULES=y
 CONFIG_NET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
@@ -38,14 +34,18 @@ CONFIG_FB_PXA=y
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_LOGO=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_CPU=y
 CONFIG_EXT2_FS=y
 CONFIG_MSDOS_FS=y
 CONFIG_JFFS2_FS=y
 CONFIG_NFS_FS=y
 CONFIG_ROOT_NFS=y
 CONFIG_NLS_ISO8859_1=y
-CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
+CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_LL=y
index 7c07f98..37739b6 100644 (file)
@@ -45,7 +45,6 @@ CONFIG_VFP=y
 CONFIG_NEON=y
 CONFIG_KERNEL_MODE_NEON=y
 CONFIG_EFI_VARS=m
-CONFIG_EFI_CAPSULE_LOADER=m
 CONFIG_ARM_CRYPTO=y
 CONFIG_CRYPTO_SHA1_ARM_NEON=m
 CONFIG_CRYPTO_SHA1_ARM_CE=m
@@ -64,8 +63,7 @@ CONFIG_CMDLINE_PARTITION=y
 CONFIG_CMA=y
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
-CONFIG_DMA_CMA=y
-CONFIG_CMA_SIZE_MBYTES=64
+CONFIG_EFI_CAPSULE_LOADER=m
 CONFIG_OF_OVERLAY=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
@@ -115,5 +113,7 @@ CONFIG_CRYPTO_AES=y
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC_CCITT=m
 CONFIG_CRC_ITU_T=m
+CONFIG_DMA_CMA=y
+CONFIG_CMA_SIZE_MBYTES=64
 CONFIG_PRINTK_TIME=y
 CONFIG_MAGIC_SYSRQ=y
index 3ef48e7..86e00f6 100644 (file)
@@ -3,7 +3,6 @@ CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
-# CONFIG_COMPAT_BRK is not set
 CONFIG_ARCH_MULTI_V4T=y
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_S3C24XX=y
@@ -12,6 +11,7 @@ CONFIG_S3C_ADC=y
 CONFIG_CPU_S3C2440=y
 CONFIG_MACH_MINI2440=y
 CONFIG_AEABI=y
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_KEXEC=y
 CONFIG_CPU_IDLE=y
 CONFIG_APM_EMULATION=y
@@ -19,7 +19,6 @@ CONFIG_MODULES=y
 CONFIG_MODULE_FORCE_LOAD=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 CONFIG_BLK_DEV_INTEGRITY=y
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_BSD_DISKLABEL=y
@@ -28,6 +27,7 @@ CONFIG_SOLARIS_X86_PARTITION=y
 CONFIG_UNIXWARE_DISKLABEL=y
 CONFIG_LDM_PARTITION=y
 CONFIG_BINFMT_MISC=m
+# CONFIG_COMPAT_BRK is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -104,6 +104,7 @@ CONFIG_SCSI=m
 # CONFIG_SCSI_PROC_FS is not set
 CONFIG_BLK_DEV_SD=m
 CONFIG_CHR_DEV_SG=m
+# CONFIG_BLK_DEV_BSG is not set
 # CONFIG_SCSI_LOWLEVEL is not set
 CONFIG_NETDEVICES=y
 CONFIG_TUN=m
@@ -328,10 +329,10 @@ CONFIG_LIBCRC32C=m
 CONFIG_FONTS=y
 CONFIG_FONT_8x8=y
 CONFIG_FONT_MINI_4x6=y
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 # CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
 CONFIG_STRIP_ASM_SYMS=y
 CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
 # CONFIG_SCHED_DEBUG is not set
 CONFIG_DEBUG_USER=y
index a5e8d22..4d39c61 100644 (file)
@@ -1,22 +1,18 @@
 CONFIG_SYSVIPC=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
 CONFIG_ARCH_MMP=y
-CONFIG_MACH_BROWNSTONE=y
-CONFIG_MACH_FLINT=y
-CONFIG_MACH_MARVELL_JASPER=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_PREEMPT=y
 CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_MACH_MMP2_DT=y
 CONFIG_CMDLINE="root=/dev/nfs rootfstype=nfs nfsroot=192.168.1.100:/nfsroot/ ip=192.168.1.101:192.168.1.100::255.255.255.0::eth0:on console=ttyS2,38400 mem=128M user_debug=255 earlyprintk"
 CONFIG_VFP=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_SLAB=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -28,9 +24,9 @@ CONFIG_IP_PNP=y
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
-CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_ONENAND=y
 CONFIG_MTD_ONENAND_GENERIC=y
+CONFIG_MTD_RAW_NAND=y
 # CONFIG_BLK_DEV is not set
 CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
@@ -39,9 +35,9 @@ CONFIG_SMC91X=y
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_PXA=y
 CONFIG_SERIAL_PXA_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
 CONFIG_I2C_PXA=y
@@ -55,17 +51,18 @@ CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_MAX8925=y
 # CONFIG_VGA_CONSOLE is not set
 # CONFIG_USB_SUPPORT is not set
+CONFIG_MMC=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_MAX8925=y
-CONFIG_MMC=y
-# CONFIG_DNOTIFY is not set
-CONFIG_TMPFS=y
-CONFIG_TMPFS_POSIX_ACL=y
+# CONFIG_RESET_CONTROLLER is not set
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
 CONFIG_EXT4_FS=y
+# CONFIG_DNOTIFY is not set
 CONFIG_MSDOS_FS=y
 CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
 CONFIG_JFFS2_FS=y
 CONFIG_CRAMFS=y
 CONFIG_NFS_FS=y
@@ -73,16 +70,16 @@ CONFIG_NFS_V3=y
 CONFIG_NFS_V3_ACL=y
 CONFIG_NFS_V4=y
 CONFIG_ROOT_NFS=y
+CONFIG_CRC_CCITT=y
 CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_PREEMPT is not set
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 # CONFIG_DYNAMIC_DEBUG is not set
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_LL=y
 CONFIG_DEBUG_MMP_UART3=y
 CONFIG_EARLY_PRINTK=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
-CONFIG_CRC_CCITT=y
index eacc089..082a38a 100644 (file)
@@ -1,7 +1,7 @@
 # CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_NO_HZ=y
+CONFIG_PREEMPT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 # CONFIG_ELF_CORE is not set
@@ -11,18 +11,17 @@ CONFIG_IKCONFIG_PROC=y
 # CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
 CONFIG_EMBEDDED=y
-# CONFIG_VM_EVENT_COUNTERS is not set
-# CONFIG_SLUB_DEBUG is not set
-# CONFIG_COMPAT_BRK is not set
 # CONFIG_BLK_DEV_BSG is not set
 CONFIG_ARCH_MULTI_V4=y
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_MOXART=y
 CONFIG_MACH_UC7112LX=y
-CONFIG_PREEMPT=y
 CONFIG_AEABI=y
 # CONFIG_ATAGS is not set
 CONFIG_ARM_APPENDED_DTB=y
+# CONFIG_SWAP is not set
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -118,10 +117,15 @@ CONFIG_EXT3_FS=y
 CONFIG_TMPFS=y
 CONFIG_CONFIGFS_FS=y
 CONFIG_JFFS2_FS=y
+CONFIG_KEYS=y
+CONFIG_CRC32_BIT=y
+CONFIG_DMA_API_DEBUG=y
 CONFIG_PRINTK_TIME=y
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 # CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_KGDB=y
 CONFIG_DEBUG_PAGEALLOC=y
+# CONFIG_SLUB_DEBUG is not set
 CONFIG_DEBUG_OBJECTS=y
 CONFIG_DEBUG_KMEMLEAK=y
 CONFIG_DEBUG_STACK_USAGE=y
@@ -131,12 +135,8 @@ CONFIG_DETECT_HUNG_TASK=y
 # CONFIG_SCHED_DEBUG is not set
 # CONFIG_DEBUG_PREEMPT is not set
 CONFIG_PROVE_LOCKING=y
-CONFIG_DMA_API_DEBUG=y
-CONFIG_KGDB=y
 CONFIG_DEBUG_LL=y
 CONFIG_DEBUG_LL_UART_8250=y
 CONFIG_DEBUG_UART_PHYS=0x98200000
 CONFIG_DEBUG_UART_VIRT=0xf9820000
 CONFIG_EARLY_PRINTK=y
-CONFIG_KEYS=y
-CONFIG_CRC32_BIT=y
index c1e98e3..7005684 100644 (file)
@@ -1,5 +1,6 @@
 CONFIG_NO_HZ_IDLE=y
 CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_LOG_BUF_SHIFT=16
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_EXPERT=y
@@ -10,21 +11,17 @@ CONFIG_EXPERT=y
 # CONFIG_SIGNALFD is not set
 # CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
-# CONFIG_VM_EVENT_COUNTERS is not set
-# CONFIG_SLUB_DEBUG is not set
-# CONFIG_BLOCK is not set
 # CONFIG_MMU is not set
 CONFIG_ARCH_MPS2=y
 CONFIG_SET_MEM_PARAM=y
 CONFIG_DRAM_BASE=0x21000000
 CONFIG_DRAM_SIZE=0x1000000
-CONFIG_PREEMPT_VOLUNTARY=y
 # CONFIG_ATAGS is not set
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+# CONFIG_SUSPEND is not set
+# CONFIG_BLOCK is not set
 CONFIG_BINFMT_FLAT=y
 # CONFIG_COREDUMP is not set
-# CONFIG_SUSPEND is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -67,9 +64,9 @@ CONFIG_SMSC911X=y
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
 # CONFIG_LEGACY_PTYS is not set
-CONFIG_SERIAL_NONSTANDARD=y
 CONFIG_SERIAL_MPS2_UART_CONSOLE=y
 CONFIG_SERIAL_MPS2_UART=y
+CONFIG_SERIAL_NONSTANDARD=y
 # CONFIG_HW_RANDOM is not set
 # CONFIG_HWMON is not set
 CONFIG_WATCHDOG=y
@@ -97,9 +94,10 @@ CONFIG_NFS_V4_2=y
 CONFIG_ROOT_NFS=y
 CONFIG_NLS=y
 CONFIG_PRINTK_TIME=y
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 # CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
 CONFIG_DEBUG_FS=y
+# CONFIG_SLUB_DEBUG is not set
 # CONFIG_SCHED_DEBUG is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
 CONFIG_MEMTEST=y
index e530107..6c3e45b 100644 (file)
@@ -3,7 +3,6 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EMBEDDED=y
-CONFIG_SLOB=y
 CONFIG_ARCH_MULTI_V4T=y
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_AT91=y
@@ -11,23 +10,22 @@ CONFIG_SOC_AT91RM9200=y
 CONFIG_ARCH_CLPS711X=y
 CONFIG_ARCH_MXC=y
 CONFIG_SOC_IMX1=y
+CONFIG_ARCH_NSPIRE=y
 CONFIG_ARCH_INTEGRATOR=y
 CONFIG_ARCH_INTEGRATOR_AP=y
 CONFIG_INTEGRATOR_IMPD1=y
 CONFIG_INTEGRATOR_CM720T=y
 CONFIG_INTEGRATOR_CM920T=y
 CONFIG_INTEGRATOR_CM922T_XA10=y
-CONFIG_ARCH_NSPIRE=y
 CONFIG_AEABI=y
 # CONFIG_ATAGS is not set
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CPU_IDLE=y
 CONFIG_ARM_CPUIDLE=y
 CONFIG_ARM_CLPS711X_CPUIDLE=y
 CONFIG_JUMP_LABEL=y
 CONFIG_PARTITION_ADVANCED=y
 # CONFIG_COREDUMP is not set
+CONFIG_SLOB=y
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
index f8d3011..e0be0e0 100644 (file)
@@ -12,17 +12,8 @@ CONFIG_MACH_ASPEED_G4=y
 CONFIG_ARCH_AT91=y
 CONFIG_SOC_AT91SAM9=y
 CONFIG_ARCH_DAVINCI=y
-CONFIG_ARCH_DAVINCI_DM644x=y
-CONFIG_ARCH_DAVINCI_DM355=y
-CONFIG_ARCH_DAVINCI_DM646x=y
 CONFIG_ARCH_DAVINCI_DA830=y
 CONFIG_ARCH_DAVINCI_DA850=y
-CONFIG_ARCH_DAVINCI_DM365=y
-CONFIG_MACH_SFFSDR=y
-CONFIG_MACH_NEUROS_OSD2=y
-CONFIG_MACH_DM355_LEOPARD=y
-CONFIG_MACH_MITYOMAPL138=y
-CONFIG_MACH_OMAPL138_HAWKBOARD=y
 CONFIG_ARCH_MXC=y
 CONFIG_SOC_IMX25=y
 CONFIG_SOC_IMX27=y
@@ -31,8 +22,6 @@ CONFIG_MACH_KIRKWOOD=y
 CONFIG_ARCH_NPCM=y
 CONFIG_ARCH_WPCM450=y
 CONFIG_ARCH_ORION5X=y
-CONFIG_MACH_DB88F5281=y
-CONFIG_MACH_RD88F5182=y
 CONFIG_MACH_RD88F5182_DT=y
 CONFIG_MACH_KUROBOX_PRO=y
 CONFIG_MACH_DNS323=y
@@ -40,19 +29,14 @@ CONFIG_MACH_TS209=y
 CONFIG_MACH_TERASTATION_PRO2=y
 CONFIG_MACH_LINKSTATION_PRO=y
 CONFIG_MACH_LINKSTATION_MINI=y
-CONFIG_MACH_LINKSTATION_LS_HGL=y
 CONFIG_MACH_TS409=y
-CONFIG_MACH_WRT350N_V2=y
 CONFIG_MACH_TS78XX=y
 CONFIG_MACH_MV2120=y
 CONFIG_MACH_D2NET_DT=y
 CONFIG_MACH_NET2BIG=y
 CONFIG_MACH_MSS2_DT=y
-CONFIG_MACH_WNR854T=y
-CONFIG_MACH_RD88F5181L_GE=y
-CONFIG_MACH_RD88F5181L_FXO=y
-CONFIG_MACH_RD88F6183AP_GE=y
 CONFIG_ARCH_SUNXI=y
+CONFIG_ARCH_VERSATILE=y
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
 CONFIG_ARM_APPENDED_DTB=y
@@ -78,7 +62,6 @@ CONFIG_NET_PKTGEN=m
 CONFIG_CFG80211=y
 CONFIG_MAC80211=y
 CONFIG_PCI_MVEBU=y
-CONFIG_ARCH_VERSATILE=y
 CONFIG_PCI_VERSATILE=y
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
@@ -98,17 +81,14 @@ CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_ATMEL=y
 CONFIG_MTD_NAND_ORION=y
 CONFIG_MTD_SPI_NOR=y
-CONFIG_SPI_ASPEED_SMC=y
 CONFIG_MTD_UBI=y
 CONFIG_BLK_DEV_LOOP=y
+CONFIG_VIRTIO_BLK=y
 CONFIG_ATMEL_SSC=m
 CONFIG_EEPROM_AT24=y
 # CONFIG_SCSI_PROC_FS is not set
 CONFIG_BLK_DEV_SD=y
 CONFIG_BLK_DEV_SR=m
-CONFIG_VIRTIO_PCI=y
-CONFIG_VIRTIO_MMIO=y
-CONFIG_VIRTIO_BLK=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_ATA=y
 CONFIG_SATA_AHCI=y
@@ -161,6 +141,7 @@ CONFIG_I2C_AT91=y
 CONFIG_I2C_IMX=y
 CONFIG_I2C_MV64XXX=y
 CONFIG_SPI=y
+CONFIG_SPI_ASPEED_SMC=y
 CONFIG_SPI_ATMEL=y
 CONFIG_SPI_IMX=y
 CONFIG_SPI_ORION=y
@@ -273,6 +254,8 @@ CONFIG_RTC_DRV_ASPEED=m
 CONFIG_DMADEVICES=y
 CONFIG_AT_HDMAC=y
 CONFIG_MV_XOR=y
+CONFIG_VIRTIO_PCI=y
+CONFIG_VIRTIO_MMIO=y
 CONFIG_STAGING=y
 CONFIG_ASPEED_LPC_CTRL=m
 CONFIG_ASPEED_LPC_SNOOP=m
@@ -307,10 +290,10 @@ CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_DEV_MARVELL_CESA=y
 CONFIG_CRC_CCITT=y
 CONFIG_LIBCRC32C=y
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
+CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
 # CONFIG_SCHED_DEBUG is not set
 # CONFIG_DEBUG_PREEMPT is not set
 # CONFIG_FTRACE is not set
index ce9826b..bcd7a43 100644 (file)
@@ -6,6 +6,7 @@ CONFIG_BLK_DEV_INITRD=y
 CONFIG_EMBEDDED=y
 CONFIG_PERF_EVENTS=y
 CONFIG_ARCH_VIRT=y
+CONFIG_ARCH_AIROHA=y
 CONFIG_ARCH_ACTIONS=y
 CONFIG_ARCH_ALPINE=y
 CONFIG_ARCH_ARTPEC=y
@@ -28,15 +29,16 @@ CONFIG_ARCH_BCM_21664=y
 CONFIG_ARCH_BCM_23550=y
 CONFIG_ARCH_BCM2835=y
 CONFIG_ARCH_BCM_53573=y
-CONFIG_ARCH_BCM_63XX=y
 CONFIG_ARCH_BRCMSTB=y
 CONFIG_ARCH_BCMBCA=y
+CONFIG_ARCH_BCMBCA_CORTEXA7=y
+CONFIG_ARCH_BCMBCA_CORTEXA9=y
+CONFIG_ARCH_BCMBCA_BRAHMAB15=y
 CONFIG_ARCH_BERLIN=y
 CONFIG_MACH_BERLIN_BG2=y
 CONFIG_MACH_BERLIN_BG2CD=y
 CONFIG_MACH_BERLIN_BG2Q=y
 CONFIG_ARCH_DIGICOLOR=y
-CONFIG_ARCH_AIROHA=y
 CONFIG_ARCH_EXYNOS=y
 CONFIG_ARCH_HIGHBANK=y
 CONFIG_ARCH_HISI=y
@@ -94,6 +96,7 @@ CONFIG_MACH_SPEAR1310=y
 CONFIG_MACH_SPEAR1340=y
 CONFIG_ARCH_STI=y
 CONFIG_ARCH_STM32=y
+CONFIG_ARCH_SUNPLUS=y
 CONFIG_ARCH_SUNXI=y
 CONFIG_ARCH_TEGRA=y
 CONFIG_ARCH_UNIPHIER=y
@@ -129,12 +132,6 @@ CONFIG_ARM_EXYNOS_CPUIDLE=y
 CONFIG_ARM_TEGRA_CPUIDLE=y
 CONFIG_ARM_QCOM_SPM_CPUIDLE=y
 CONFIG_KERNEL_MODE_NEON=y
-CONFIG_ARM_SCMI_PROTOCOL=y
-CONFIG_RASPBERRYPI_FIRMWARE=y
-CONFIG_TRUSTED_FOUNDATIONS=y
-CONFIG_BCM47XX_NVRAM=y
-CONFIG_BCM47XX_SPROM=y
-CONFIG_EFI_CAPSULE_LOADER=m
 CONFIG_ARM_CRYPTO=y
 CONFIG_CRYPTO_SHA1_ARM_NEON=m
 CONFIG_CRYPTO_SHA1_ARM_CE=m
@@ -207,6 +204,12 @@ CONFIG_PCI_EPF_TEST=m
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_OMAP_OCP2SCP=y
+CONFIG_ARM_SCMI_PROTOCOL=y
+CONFIG_RASPBERRYPI_FIRMWARE=y
+CONFIG_TRUSTED_FOUNDATIONS=y
+CONFIG_BCM47XX_NVRAM=y
+CONFIG_BCM47XX_SPROM=y
+CONFIG_EFI_CAPSULE_LOADER=m
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
@@ -227,7 +230,6 @@ CONFIG_MTD_NAND_DAVINCI=y
 CONFIG_MTD_NAND_STM32_FMC2=y
 CONFIG_MTD_NAND_PL35X=y
 CONFIG_MTD_SPI_NOR=y
-CONFIG_SPI_ASPEED_SMC=m
 CONFIG_MTD_UBI=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
@@ -259,13 +261,13 @@ CONFIG_SATA_MV=y
 CONFIG_SATA_RCAR=y
 CONFIG_NETDEVICES=y
 CONFIG_NET_VENDOR_ASIX=y
-CONFIG_SPI_AX88796C=m
 CONFIG_VIRTIO_NET=y
 CONFIG_B53_SPI_DRIVER=m
 CONFIG_B53_MDIO_DRIVER=m
 CONFIG_B53_MMAP_DRIVER=m
 CONFIG_NET_DSA_BCM_SF2=m
 CONFIG_SUN4I_EMAC=y
+CONFIG_SPI_AX88796C=m
 CONFIG_BCMGENET=m
 CONFIG_BGMAC_BCMA=y
 CONFIG_SYSTEMPORT=m
@@ -298,7 +300,6 @@ CONFIG_MARVELL_PHY=y
 CONFIG_AT803X_PHY=y
 CONFIG_ROCKCHIP_PHY=y
 CONFIG_DP83867_PHY=y
-CONFIG_USB_BRCMSTB=m
 CONFIG_MDIO_MSCC_MIIM=m
 CONFIG_USB_PEGASUS=y
 CONFIG_USB_RTL8152=m
@@ -435,6 +436,7 @@ CONFIG_I2C_RCAR=y
 CONFIG_I2C_CROS_EC_TUNNEL=m
 CONFIG_I2C_SLAVE_EEPROM=y
 CONFIG_SPI=y
+CONFIG_SPI_ASPEED_SMC=m
 CONFIG_SPI_ATMEL=m
 CONFIG_SPI_ATMEL_QUADSPI=m
 CONFIG_SPI_BCM2835=y
@@ -465,10 +467,10 @@ CONFIG_SPI_SPIDEV=y
 CONFIG_SPMI=y
 CONFIG_PTP_1588_CLOCK=y
 CONFIG_PINCTRL_AS3722=y
-CONFIG_PINCTRL_STMFX=y
 CONFIG_PINCTRL_MICROCHIP_SGPIO=y
 CONFIG_PINCTRL_OCELOT=y
 CONFIG_PINCTRL_PALMAS=y
+CONFIG_PINCTRL_STMFX=y
 CONFIG_PINCTRL_OWL=y
 CONFIG_PINCTRL_S500=y
 CONFIG_PINCTRL_MSM=y
@@ -511,7 +513,6 @@ CONFIG_BATTERY_ACT8945A=y
 CONFIG_BATTERY_CPCAP=m
 CONFIG_BATTERY_SBS=y
 CONFIG_BATTERY_BQ27XXX=m
-CONFIG_BATTERY_ACER_A500=m
 CONFIG_AXP20X_POWER=m
 CONFIG_BATTERY_MAX17040=m
 CONFIG_BATTERY_MAX17042=m
@@ -523,6 +524,7 @@ CONFIG_CHARGER_MAX8997=m
 CONFIG_CHARGER_MAX8998=m
 CONFIG_CHARGER_SMB347=m
 CONFIG_CHARGER_TPS65090=y
+CONFIG_BATTERY_ACER_A500=m
 CONFIG_SENSORS_ARM_SCMI=y
 CONFIG_SENSORS_ASPEED=m
 CONFIG_SENSORS_IIO_HWMON=y
@@ -577,7 +579,6 @@ CONFIG_GXP_WATCHDOG=y
 CONFIG_BCMA_HOST_SOC=y
 CONFIG_BCMA_DRIVER_GMAC_CMN=y
 CONFIG_BCMA_DRIVER_GPIO=y
-CONFIG_MFD_ACER_A500_EC=m
 CONFIG_MFD_ACT8945A=y
 CONFIG_MFD_AS3711=y
 CONFIG_MFD_AS3722=y
@@ -610,6 +611,7 @@ CONFIG_MFD_TPS6586X=y
 CONFIG_MFD_TPS65910=y
 CONFIG_MFD_STM32_LPTIMER=m
 CONFIG_MFD_STPMIC1=y
+CONFIG_MFD_ACER_A500_EC=m
 CONFIG_REGULATOR_ACT8865=y
 CONFIG_REGULATOR_ACT8945A=y
 CONFIG_REGULATOR_ANATOP=y
@@ -664,31 +666,31 @@ CONFIG_MEDIA_SUPPORT=m
 CONFIG_MEDIA_USB_SUPPORT=y
 CONFIG_USB_VIDEO_CLASS=m
 CONFIG_V4L_PLATFORM_DRIVERS=y
-CONFIG_VIDEO_MMP_CAMERA=m
+CONFIG_V4L_MEM2MEM_DRIVERS=y
 CONFIG_VIDEO_ASPEED=m
-CONFIG_VIDEO_STM32_DCMI=m
+CONFIG_VIDEO_ATMEL_ISC=m
+CONFIG_VIDEO_ATMEL_XISC=m
+CONFIG_VIDEO_ATMEL_ISI=m
+CONFIG_VIDEO_MICROCHIP_CSI2DC=m
+CONFIG_VIDEO_MMP_CAMERA=m
+CONFIG_VIDEO_TEGRA_VDE=m
 CONFIG_VIDEO_RENESAS_CEU=m
+CONFIG_VIDEO_RCAR_VIN=m
+CONFIG_VIDEO_RENESAS_FDP1=m
+CONFIG_VIDEO_RENESAS_JPU=m
+CONFIG_VIDEO_RENESAS_VSP1=m
+CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC=m
 CONFIG_VIDEO_SAMSUNG_EXYNOS4_IS=m
 CONFIG_VIDEO_S5P_FIMC=m
 CONFIG_VIDEO_S5P_MIPI_CSIS=m
 CONFIG_VIDEO_EXYNOS_FIMC_LITE=m
 CONFIG_VIDEO_EXYNOS4_FIMC_IS=m
-CONFIG_VIDEO_RCAR_VIN=m
-CONFIG_VIDEO_ATMEL_ISC=m
-CONFIG_VIDEO_ATMEL_XISC=m
-CONFIG_VIDEO_ATMEL_ISI=m
-CONFIG_VIDEO_MICROCHIP_CSI2DC=m
-CONFIG_V4L_MEM2MEM_DRIVERS=y
 CONFIG_VIDEO_SAMSUNG_S5P_JPEG=m
 CONFIG_VIDEO_SAMSUNG_S5P_MFC=m
-CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC=m
 CONFIG_VIDEO_STI_BDISP=m
-CONFIG_VIDEO_STI_HVA=m
 CONFIG_VIDEO_STI_DELTA=m
-CONFIG_VIDEO_RENESAS_FDP1=m
-CONFIG_VIDEO_RENESAS_JPU=m
-CONFIG_VIDEO_RENESAS_VSP1=m
-CONFIG_VIDEO_TEGRA_VDE=m
+CONFIG_VIDEO_STI_HVA=m
+CONFIG_VIDEO_STM32_DCMI=m
 CONFIG_V4L_TEST_DRIVERS=y
 CONFIG_VIDEO_VIVID=m
 CONFIG_VIDEO_ADV7180=m
@@ -725,13 +727,13 @@ CONFIG_DRM_PANEL_LVDS=m
 CONFIG_DRM_PANEL_SIMPLE=y
 CONFIG_DRM_PANEL_EDP=y
 CONFIG_DRM_PANEL_SAMSUNG_LD9040=m
-CONFIG_DRM_PANEL_SHARP_LQ101R1SX01=m
 CONFIG_DRM_PANEL_ORISETECH_OTM8009A=m
 CONFIG_DRM_PANEL_RAYDIUM_RM68200=m
 CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03=m
 CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0=m
-CONFIG_DRM_LVDS_CODEC=m
+CONFIG_DRM_PANEL_SHARP_LQ101R1SX01=m
 CONFIG_DRM_DISPLAY_CONNECTOR=m
+CONFIG_DRM_LVDS_CODEC=m
 CONFIG_DRM_NXP_PTN3460=m
 CONFIG_DRM_PARADE_PS8622=m
 CONFIG_DRM_SII902X=m
@@ -747,6 +749,7 @@ CONFIG_DRM_IMX_PARALLEL_DISPLAY=m
 CONFIG_DRM_IMX_TVE=m
 CONFIG_DRM_IMX_LDB=m
 CONFIG_DRM_IMX_HDMI=m
+CONFIG_DRM_V3D=m
 CONFIG_DRM_VC4=m
 CONFIG_DRM_ETNAVIV=m
 CONFIG_DRM_MXSFB=m
@@ -832,6 +835,7 @@ CONFIG_USB_OTG=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_MVEBU=y
 CONFIG_USB_XHCI_TEGRA=m
+CONFIG_USB_BRCMSTB=m
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_HCD_STI=y
 CONFIG_USB_EHCI_EXYNOS=m
@@ -936,10 +940,10 @@ CONFIG_LEDS_CLASS_FLASH=m
 CONFIG_LEDS_CPCAP=m
 CONFIG_LEDS_GPIO=y
 CONFIG_LEDS_PWM=y
-CONFIG_LEDS_MAX77693=m
 CONFIG_LEDS_MAX8997=m
 CONFIG_LEDS_ACER_A500=m
 CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_MAX77693=m
 CONFIG_LEDS_TRIGGER_TIMER=y
 CONFIG_LEDS_TRIGGER_ONESHOT=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
@@ -1162,10 +1166,10 @@ CONFIG_KEYSTONE_IRQ=y
 CONFIG_RESET_MCHP_SPARX5=y
 CONFIG_PHY_SUN4I_USB=y
 CONFIG_PHY_SUN9I_USB=y
+CONFIG_PHY_BRCM_USB=m
 CONFIG_PHY_HIX5HD2_SATA=y
 CONFIG_PHY_BERLIN_SATA=y
 CONFIG_PHY_BERLIN_USB=y
-CONFIG_PHY_BRCM_USB=m
 CONFIG_PHY_MMP3_USB=m
 CONFIG_PHY_LAN966X_SERDES=m
 CONFIG_PHY_CPCAP_USB=m
index cd703c1..a53ccd4 100644 (file)
@@ -1,14 +1,12 @@
 CONFIG_SYSVIPC=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
-# CONFIG_SLUB_DEBUG is not set
 CONFIG_PROFILING=y
-CONFIG_KPROBES=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 CONFIG_ARCH_MULTI_V5=y
 # CONFIG_ARCH_MULTI_V6 is not set
 # CONFIG_ARCH_MULTI_V7 is not set
@@ -16,15 +14,16 @@ CONFIG_ARCH_MV78XX0=y
 CONFIG_MACH_DB78X00_BP=y
 CONFIG_MACH_RD78X00_MASA=y
 CONFIG_MACH_TERASTATION_WXL=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_PREEMPT=y
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_FPE_NWFPE=y
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_VFP=y
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_BSD_DISKLABEL=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -52,25 +51,26 @@ CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_BLK_DEV_SR=m
 CONFIG_CHR_DEV_SG=m
+# CONFIG_BLK_DEV_BSG is not set
 CONFIG_ATA=y
 CONFIG_SATA_MV=y
 CONFIG_NETDEVICES=y
-CONFIG_MARVELL_PHY=y
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 CONFIG_NET_PCI=y
 CONFIG_MV643XX_ETH=y
 # CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_MARVELL_PHY=y
 CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
+CONFIG_LEGACY_PTY_COUNT=16
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 # CONFIG_SERIAL_8250_PCI is not set
 CONFIG_SERIAL_8250_RUNTIME_UARTS=2
-CONFIG_LEGACY_PTY_COUNT=16
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
@@ -110,21 +110,20 @@ CONFIG_CRAMFS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_BSD_DISKLABEL=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_CODEPAGE_850=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_NLS_ISO8859_2=y
+CONFIG_CRYPTO_CBC=m
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_DEBUG_BUGVERBOSE is not set
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
+# CONFIG_SLUB_DEBUG is not set
 CONFIG_SCHEDSTATS=y
-# CONFIG_DEBUG_BUGVERBOSE is not set
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_LL=y
-CONFIG_CRYPTO_CBC=m
-CONFIG_CRYPTO_ECB=m
-CONFIG_CRYPTO_PCBC=m
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
index d57ff30..ef3a33e 100644 (file)
@@ -2,18 +2,13 @@ CONFIG_SYSVIPC=y
 CONFIG_FHANDLE=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
 CONFIG_LOG_BUF_SHIFT=19
 CONFIG_PROFILING=y
-CONFIG_KPROBES=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_MVEBU=y
 CONFIG_MACH_KIRKWOOD=y
 CONFIG_ARCH_ORION5X=y
-CONFIG_MACH_DB88F5281=y
-CONFIG_MACH_RD88F5182=y
 CONFIG_MACH_RD88F5182_DT=y
 CONFIG_MACH_KUROBOX_PRO=y
 CONFIG_MACH_DNS323=y
@@ -22,24 +17,14 @@ CONFIG_MACH_TERASTATION_PRO2=y
 CONFIG_MACH_LINKSTATION_PRO=y
 CONFIG_MACH_LINKSTATION_LSCHL=y
 CONFIG_MACH_LINKSTATION_MINI=y
-CONFIG_MACH_LINKSTATION_LS_HGL=y
 CONFIG_MACH_TS409=y
-CONFIG_MACH_WRT350N_V2=y
 CONFIG_MACH_TS78XX=y
 CONFIG_MACH_MV2120=y
 CONFIG_MACH_D2NET_DT=y
 CONFIG_MACH_NET2BIG=y
 CONFIG_MACH_MSS2_DT=y
-CONFIG_MACH_WNR854T=y
-CONFIG_MACH_RD88F5181L_GE=y
-CONFIG_MACH_RD88F5181L_FXO=y
-CONFIG_MACH_RD88F6183AP_GE=y
-CONFIG_PCI_MVEBU=y
-CONFIG_PREEMPT=y
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_ARM_APPENDED_DTB=y
 CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_CPU_FREQ=y
@@ -47,6 +32,9 @@ CONFIG_CPU_FREQ_STAT=y
 CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
 CONFIG_CPU_IDLE=y
 CONFIG_ARM_KIRKWOOD_CPUIDLE=y
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -61,6 +49,7 @@ CONFIG_NET_SWITCHDEV=y
 CONFIG_NET_PKTGEN=m
 CONFIG_CFG80211=y
 CONFIG_MAC80211=y
+CONFIG_PCI_MVEBU=y
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_MTD=y
@@ -84,6 +73,7 @@ CONFIG_EEPROM_AT24=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_BLK_DEV_SR=m
 CONFIG_CHR_DEV_SG=m
+# CONFIG_BLK_DEV_BSG is not set
 CONFIG_ATA=y
 CONFIG_SATA_AHCI=y
 CONFIG_SATA_MV=y
@@ -93,9 +83,9 @@ CONFIG_NET_DSA_MV88E6XXX=y
 CONFIG_MV643XX_ETH=y
 CONFIG_R8169=y
 CONFIG_MARVELL_PHY=y
-CONFIG_MWL8K=m
 CONFIG_LIBERTAS=y
 CONFIG_LIBERTAS_SDIO=y
+CONFIG_MWL8K=m
 CONFIG_INPUT_EVDEV=y
 CONFIG_KEYBOARD_GPIO=y
 # CONFIG_INPUT_MOUSE is not set
@@ -194,16 +184,16 @@ CONFIG_NLS_CODEPAGE_850=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_NLS_ISO8859_2=y
 CONFIG_NLS_UTF8=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_FS=y
-CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
+CONFIG_CRYPTO_CBC=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_DEV_MARVELL_CESA=y
+CONFIG_CRC_CCITT=y
+CONFIG_LIBCRC32C=y
 CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
 # CONFIG_SCHED_DEBUG is not set
 # CONFIG_DEBUG_PREEMPT is not set
 # CONFIG_FTRACE is not set
 CONFIG_DEBUG_USER=y
-CONFIG_CRYPTO_DEV_MARVELL_CESA=y
-CONFIG_CRYPTO_CBC=m
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRC_CCITT=y
-CONFIG_LIBCRC32C=y
index 7b713c0..68a1826 100644 (file)
@@ -4,7 +4,6 @@ CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EXPERT=y
 CONFIG_PERF_EVENTS=y
-CONFIG_SLAB=y
 CONFIG_ARCH_MVEBU=y
 CONFIG_MACH_ARMADA_370=y
 CONFIG_MACH_ARMADA_375=y
@@ -24,6 +23,7 @@ CONFIG_VFP=y
 CONFIG_NEON=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
+CONFIG_SLAB=y
 # CONFIG_COMPACTION is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
@@ -147,7 +147,7 @@ CONFIG_NLS_UTF8=y
 CONFIG_CRYPTO_DEV_MARVELL_CESA=y
 CONFIG_PRINTK_TIME=y
 # CONFIG_DEBUG_BUGVERBOSE is not set
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 CONFIG_MAGIC_SYSRQ=y
 # CONFIG_SCHED_DEBUG is not set
 CONFIG_DEBUG_USER=y
index ca32446..155553e 100644 (file)
@@ -15,7 +15,6 @@ CONFIG_CGROUPS=y
 # CONFIG_NET_NS is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_PERF_EVENTS=y
-# CONFIG_COMPAT_BRK is not set
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_MXS=y
 CONFIG_AEABI=y
@@ -25,6 +24,7 @@ CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
 CONFIG_MODVERSIONS=y
 CONFIG_BLK_DEV_INTEGRITY=y
+# CONFIG_COMPAT_BRK is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -93,6 +93,7 @@ CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_DRM=y
 CONFIG_DRM_PANEL_SEIKO_43WVF1G=y
 CONFIG_DRM_MXSFB=y
+CONFIG_FB=y
 CONFIG_FB_MODE_HELPERS=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
@@ -162,10 +163,10 @@ CONFIG_CRC_ITU_T=m
 CONFIG_CRC7=m
 CONFIG_FONTS=y
 CONFIG_PRINTK_TIME=y
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
+CONFIG_DEBUG_KERNEL=y
 CONFIG_FRAME_WARN=2048
 CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_KERNEL=y
 CONFIG_SOFTLOCKUP_DETECTOR=y
 CONFIG_PROVE_LOCKING=y
 CONFIG_BLK_DEV_IO_TRACE=y
index 018a109..9074035 100644 (file)
@@ -1,16 +1,9 @@
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
 CONFIG_ARCH_SA1100=y
 CONFIG_SA1100_ASSABET=y
 CONFIG_ASSABET_NEPONSET=y
-CONFIG_PCCARD=y
-CONFIG_PCMCIA_SA1100=y
-CONFIG_PCMCIA_SA1111=y
-CONFIG_LEDS=y
-CONFIG_LEDS_CPU=y
 CONFIG_ZBOOT_ROM_TEXT=0x80000
 CONFIG_ZBOOT_ROM_BSS=0xc1000000
 CONFIG_ZBOOT_ROM=y
@@ -18,14 +11,21 @@ CONFIG_CMDLINE="console=ttySA0,38400n8 cpufreq=221200 rw root=/dev/mtdblock2 mtd
 CONFIG_FPE_NWFPE=y
 CONFIG_BINFMT_AOUT=y
 CONFIG_PM=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_MSDOS_PARTITION is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
 # CONFIG_IPV6 is not set
+CONFIG_PCCARD=y
+CONFIG_PCMCIA_SA1100=y
+CONFIG_PCMCIA_SA1111=y
 CONFIG_MTD=y
-CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_ADV_OPTIONS=y
@@ -39,20 +39,20 @@ CONFIG_BLK_DEV_SD=m
 CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
 CONFIG_NET_VENDOR_SMC=y
+CONFIG_PCMCIA_PCNET=y
 CONFIG_SMC9194=y
 CONFIG_SMC91X=y
 CONFIG_NET_PCMCIA=y
-CONFIG_PCMCIA_PCNET=y
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_SERIO_SERPORT=m
 CONFIG_SERIO_SA1111=y
-CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_LEGACY_PTY_COUNT=64
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CS=y
 CONFIG_SERIAL_SA1100=y
 CONFIG_SERIAL_SA1100_CONSOLE=y
-CONFIG_LEGACY_PTY_COUNT=64
+CONFIG_SERIAL_NONSTANDARD=y
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_WATCHDOG=y
@@ -68,17 +68,19 @@ CONFIG_USB=m
 CONFIG_USB_MON=m
 CONFIG_USB_OHCI_HCD=m
 CONFIG_USB_STORAGE=m
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_CPU=y
 CONFIG_EXT2_FS=y
 CONFIG_MSDOS_FS=m
 CONFIG_VFAT_FS=m
 CONFIG_JFFS2_FS=y
 CONFIG_NFS_FS=y
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_MSDOS_PARTITION is not set
 CONFIG_NLS=y
 CONFIG_NLS_CODEPAGE_437=m
 CONFIG_NLS_ISO8859_1=m
-CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_LL=y
index c3c171c..cf7bbcf 100644 (file)
@@ -2,14 +2,11 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_ARCH_FOOTBRIDGE=y
 CONFIG_ARCH_NETWINDER=y
-CONFIG_LEDS=y
-CONFIG_LEDS_CPU=y
 CONFIG_DEPRECATED_PARAM_STRUCT=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="root=0x801"
 CONFIG_FPE_NWFPE=y
 CONFIG_BINFMT_AOUT=y
+CONFIG_PARTITION_ADVANCED=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -51,9 +48,6 @@ CONFIG_977_WATCHDOG=y
 CONFIG_FB=y
 CONFIG_FB_CYBER2000=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FONTS=y
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
 CONFIG_LOGO=y
 CONFIG_SOUND=y
 CONFIG_SOUND_PRIME=y
@@ -62,6 +56,10 @@ CONFIG_SOUND_TRACEINIT=y
 CONFIG_SOUND_DMAP=y
 CONFIG_SOUND_YM3812=y
 CONFIG_SOUND_WAVEARTIST=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_CPU=y
 CONFIG_EXT2_FS=y
 CONFIG_ISO9660_FS=y
 CONFIG_JOLIET=y
@@ -72,7 +70,6 @@ CONFIG_NFS_V4=y
 CONFIG_ROOT_NFS=y
 CONFIG_NFSD=y
 CONFIG_SMB_FS=y
-CONFIG_PARTITION_ADVANCED=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_CODEPAGE_850=y
 CONFIG_NLS_CODEPAGE_852=y
@@ -80,6 +77,9 @@ CONFIG_NLS_ISO8859_1=y
 CONFIG_NLS_ISO8859_2=y
 CONFIG_NLS_ISO8859_15=y
 CONFIG_NLS_UTF8=y
-CONFIG_MAGIC_SYSRQ=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
 CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_USER=y
index 907d651..d5881de 100644 (file)
@@ -1,5 +1,4 @@
 # CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_NO_HZ_IDLE=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -10,14 +9,14 @@ CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
-CONFIG_SLAB=y
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_NOMADIK=y
 CONFIG_MACH_NOMADIK_8815NHK=y
 CONFIG_AEABI=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_SWAP is not set
+CONFIG_SLAB=y
 CONFIG_CMA=y
 CONFIG_NET=y
 CONFIG_PACKET=y
@@ -59,6 +58,7 @@ CONFIG_BLK_DEV_RAM=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_SG=y
+# CONFIG_BLK_DEV_BSG is not set
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_LOGGING=y
 CONFIG_SCSI_SCAN_ASYNC=y
@@ -135,7 +135,7 @@ CONFIG_CRYPTO_MD5=y
 CONFIG_CRYPTO_SHA1=y
 CONFIG_CRYPTO_DES=y
 # CONFIG_DEBUG_BUGVERBOSE is not set
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 CONFIG_DEBUG_FS=y
 # CONFIG_SCHED_DEBUG is not set
 # CONFIG_DEBUG_PREEMPT is not set
index 14c17a2..54a9f50 100644 (file)
@@ -1,64 +1,49 @@
-# CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_IKCONFIG=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EXPERT=y
-# CONFIG_KALLSYMS is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_BASE_FULL is not set
 # CONFIG_SHMEM is not set
-# CONFIG_VM_EVENT_COUNTERS is not set
-CONFIG_SLOB=y
+# CONFIG_KALLSYMS is not set
 CONFIG_PROFILING=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 CONFIG_ARCH_MULTI_V4T=y
 CONFIG_ARCH_MULTI_V5=y
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_OMAP=y
 CONFIG_ARCH_OMAP1=y
-CONFIG_OMAP_RESET_CLOCKS=y
-# CONFIG_OMAP_MUX is not set
 CONFIG_OMAP_32K_TIMER=y
 CONFIG_OMAP_DM_TIMER=y
 CONFIG_ARCH_OMAP730=y
 CONFIG_ARCH_OMAP850=y
 CONFIG_ARCH_OMAP16XX=y
-CONFIG_MACH_OMAP_INNOVATOR=y
-CONFIG_MACH_OMAP_H2=y
-CONFIG_MACH_OMAP_H3=y
-CONFIG_MACH_HERALD=y
+# CONFIG_OMAP_MUX is not set
+CONFIG_OMAP_RESET_CLOCKS=y
 CONFIG_MACH_OMAP_OSK=y
-CONFIG_MACH_OMAP_PERSEUS2=y
-CONFIG_MACH_OMAP_FSAMPLE=y
-CONFIG_MACH_VOICEBLUE=y
 CONFIG_MACH_OMAP_PALMTE=y
-CONFIG_MACH_OMAP_PALMZ71=y
-CONFIG_MACH_OMAP_PALMTT=y
 CONFIG_MACH_SX1=y
 CONFIG_MACH_NOKIA770=y
 CONFIG_MACH_AMS_DELTA=y
 CONFIG_MACH_OMAP_GENERIC=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_PCCARD=y
-CONFIG_OMAP_CF=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_PREEMPT=y
 CONFIG_AEABI=y
-CONFIG_LEDS=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="root=1f03 rootfstype=jffs2"
 CONFIG_FPE_NWFPE=y
-CONFIG_BINFMT_MISC=y
-CONFIG_PM=y
 # CONFIG_SUSPEND is not set
+CONFIG_PM=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_BINFMT_MISC=y
+# CONFIG_SWAP is not set
+CONFIG_SLOB=y
+# CONFIG_VM_EVENT_COUNTERS is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -79,6 +64,8 @@ CONFIG_BT_RFCOMM=y
 CONFIG_BT_RFCOMM_TTY=y
 CONFIG_BT_BNEP=y
 CONFIG_BT_HIDP=y
+CONFIG_PCCARD=y
+CONFIG_OMAP_CF=y
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 CONFIG_CONNECTOR=y
@@ -99,12 +86,21 @@ CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_CHR_DEV_SG=y
+# CONFIG_BLK_DEV_BSG is not set
 CONFIG_ATA=m
 CONFIG_PATA_PCMCIA=m
 CONFIG_NETDEVICES=y
 CONFIG_TUN=y
 CONFIG_PHYLIB=y
 CONFIG_SMC91X=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_ASYNC=y
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
 CONFIG_USB_CATC=y
 CONFIG_USB_KAWETH=y
 CONFIG_USB_PEGASUS=y
@@ -112,14 +108,6 @@ CONFIG_USB_RTL8150=y
 CONFIG_USB_USBNET=y
 # CONFIG_USB_NET_AX8817X is not set
 # CONFIG_USB_NET_CDC_SUBSET is not set
-CONFIG_PPP=y
-CONFIG_PPP_MULTILINK=y
-CONFIG_PPP_FILTER=y
-CONFIG_PPP_ASYNC=y
-CONFIG_PPP_DEFLATE=y
-CONFIG_PPP_BSDCOMP=y
-CONFIG_SLIP=y
-CONFIG_SLIP_COMPRESSED=y
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=y
 CONFIG_INPUT_EVBUG=y
@@ -130,11 +118,11 @@ CONFIG_TOUCHSCREEN_ADS7846=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
 # CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=3
 CONFIG_SERIAL_8250_RUNTIME_UARTS=3
-# CONFIG_LEGACY_PTYS is not set
 CONFIG_HW_RANDOM=y
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
@@ -156,11 +144,6 @@ CONFIG_FB_OMAP_LCD_MIPID=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
-CONFIG_FONTS=y
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
-CONFIG_FONT_6x11=y
-CONFIG_FONT_MINI_4x6=y
 CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_MONO is not set
 # CONFIG_LOGO_LINUX_VGA16 is not set
@@ -222,7 +205,6 @@ CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 CONFIG_NFS_V4=y
 CONFIG_ROOT_NFS=y
-CONFIG_PARTITION_ADVANCED=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_CODEPAGE_850=y
 CONFIG_NLS_CODEPAGE_852=y
@@ -235,13 +217,8 @@ CONFIG_NLS_ISO8859_15=y
 CONFIG_NLS_KOI8_R=y
 CONFIG_NLS_UTF8=y
 # CONFIG_ENABLE_MUST_CHECK is not set
-CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_SPINLOCK=y
-CONFIG_DEBUG_MUTEXES=y
-# CONFIG_DEBUG_BUGVERBOSE is not set
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 CONFIG_SECURITY=y
 CONFIG_CRYPTO_ECB=y
 CONFIG_CRYPTO_PCBC=y
@@ -249,3 +226,13 @@ CONFIG_CRYPTO_DEFLATE=y
 CONFIG_CRYPTO_LZO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_LIBCRC32C=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_FONT_6x11=y
+CONFIG_FONT_MINI_4x6=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_USER=y
index 9380df6..99d015c 100644 (file)
@@ -22,11 +22,8 @@ CONFIG_CGROUP_PERF=y
 CONFIG_NAMESPACES=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EXPERT=y
-CONFIG_SLAB=y
 CONFIG_PROFILING=y
 CONFIG_ARCH_MULTI_V6=y
-CONFIG_POWER_AVS_OMAP=y
-CONFIG_POWER_AVS_OMAP_CLASS3=y
 CONFIG_OMAP_RESET_CLOCKS=y
 CONFIG_ARCH_OMAP2=y
 CONFIG_ARCH_OMAP3=y
@@ -35,6 +32,8 @@ CONFIG_SOC_OMAP5=y
 CONFIG_SOC_AM33XX=y
 CONFIG_SOC_AM43XX=y
 CONFIG_SOC_DRA7XX=y
+CONFIG_POWER_AVS_OMAP=y
+CONFIG_POWER_AVS_OMAP_CLASS3=y
 CONFIG_ARM_THUMBEE=y
 CONFIG_ARM_ERRATA_411920=y
 CONFIG_SMP=y
@@ -69,9 +68,9 @@ CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
 CONFIG_MODVERSIONS=y
 CONFIG_MODULE_SRCVERSION_ALL=y
-# CONFIG_BLK_DEV_BSG is not set
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_BINFMT_MISC=y
+CONFIG_SLAB=y
 CONFIG_CMA=y
 CONFIG_ZSMALLOC=m
 CONFIG_NET=y
@@ -316,6 +315,7 @@ CONFIG_PCI_ENDPOINT_TEST=m
 CONFIG_EEPROM_AT24=m
 CONFIG_EEPROM_AT25=m
 CONFIG_BLK_DEV_SD=y
+# CONFIG_BLK_DEV_BSG is not set
 CONFIG_SCSI_SCAN_ASYNC=y
 CONFIG_ATA=y
 CONFIG_SATA_AHCI_PLATFORM=y
@@ -494,15 +494,15 @@ CONFIG_REGULATOR_TWL4030=y
 CONFIG_RC_CORE=m
 CONFIG_LIRC=y
 CONFIG_RC_DEVICES=y
-CONFIG_IR_SPI=m
-CONFIG_IR_RX51=m
 CONFIG_IR_GPIO_TX=m
 CONFIG_IR_PWM_TX=m
+CONFIG_IR_RX51=m
+CONFIG_IR_SPI=m
 CONFIG_MEDIA_SUPPORT=m
 CONFIG_V4L_PLATFORM_DRIVERS=y
 CONFIG_VIDEO_OMAP3=m
-CONFIG_VIDEO_TVP5150=m
 CONFIG_VIDEO_MT9P031=m
+CONFIG_VIDEO_TVP5150=m
 CONFIG_DRM=m
 CONFIG_DRM_OMAP=m
 CONFIG_OMAP5_DSS_HDMI=y
@@ -726,9 +726,8 @@ CONFIG_FONT_8x8=y
 CONFIG_FONT_8x16=y
 CONFIG_PRINTK_TIME=y
 # CONFIG_DEBUG_BUGVERBOSE is not set
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_INFO_SPLIT=y
 CONFIG_DEBUG_INFO_DWARF4=y
+CONFIG_DEBUG_INFO_SPLIT=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
 CONFIG_SCHEDSTATS=y
index b9e3b64..1311d95 100644 (file)
@@ -1,23 +1,14 @@
 CONFIG_SYSVIPC=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_EXPERT=y
-# CONFIG_SLUB_DEBUG is not set
 CONFIG_PROFILING=y
-CONFIG_KPROBES=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_BSD_DISKLABEL=y
 CONFIG_ARCH_MULTI_V5=y
 # CONFIG_ARCH_MULTI_V6 is not set
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_ORION5X=y
-CONFIG_ARCH_ORION5X_DT=y
-CONFIG_MACH_DB88F5281=y
-CONFIG_MACH_RD88F5182=y
 CONFIG_MACH_RD88F5182_DT=y
 CONFIG_MACH_KUROBOX_PRO=y
 CONFIG_MACH_DNS323=y
@@ -25,28 +16,20 @@ CONFIG_MACH_TS209=y
 CONFIG_MACH_TERASTATION_PRO2=y
 CONFIG_MACH_LINKSTATION_PRO=y
 CONFIG_MACH_LINKSTATION_MINI=y
-CONFIG_MACH_LINKSTATION_LS_HGL=y
 CONFIG_MACH_TS409=y
-CONFIG_MACH_WRT350N_V2=y
 CONFIG_MACH_TS78XX=y
 CONFIG_MACH_MV2120=y
-CONFIG_MACH_EDMINI_V2_DT=y
-CONFIG_MACH_D2NET=y
-CONFIG_MACH_BIGDISK=y
 CONFIG_MACH_NET2BIG=y
-CONFIG_MACH_MSS2=y
-CONFIG_MACH_WNR854T=y
-CONFIG_MACH_RD88F5181L_GE=y
-CONFIG_MACH_RD88F5181L_FXO=y
-CONFIG_MACH_RD88F6183AP_GE=y
-CONFIG_PREEMPT=y
 CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_ARM_APPENDED_DTB=y
 CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_FPE_NWFPE=y
 CONFIG_VFP=y
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_BSD_DISKLABEL=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -58,6 +41,7 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_IPV6 is not set
 CONFIG_NET_DSA=y
 CONFIG_NET_PKTGEN=m
+# CONFIG_VGA_ARB is not set
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
@@ -69,13 +53,14 @@ CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_PHYSMAP=y
 CONFIG_MTD_RAW_NAND=y
-CONFIG_MTD_NAND_PLATFORM=y
 CONFIG_MTD_NAND_ORION=y
+CONFIG_MTD_NAND_PLATFORM=y
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_SCSI_PROC_FS is not set
 CONFIG_BLK_DEV_SD=y
 CONFIG_BLK_DEV_SR=m
 CONFIG_CHR_DEV_SG=m
+# CONFIG_BLK_DEV_BSG is not set
 CONFIG_ATA=y
 CONFIG_SATA_MV=y
 CONFIG_NETDEVICES=y
@@ -103,7 +88,6 @@ CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_MV64XXX=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_SENSORS_LM75=y
-# CONFIG_VGA_ARB is not set
 CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_ROOT_HUB_TT=y
@@ -148,17 +132,18 @@ CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_CODEPAGE_850=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_NLS_ISO8859_2=y
+CONFIG_CRYPTO_CBC=m
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_DEV_MARVELL_CESA=y
+CONFIG_CRC_T10DIF=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
-# CONFIG_DEBUG_BUGVERBOSE is not set
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
+# CONFIG_SLUB_DEBUG is not set
 CONFIG_LATENCYTOP=y
 # CONFIG_FTRACE is not set
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_LL=y
-CONFIG_CRYPTO_CBC=m
-CONFIG_CRYPTO_ECB=m
-CONFIG_CRYPTO_PCBC=m
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
-CONFIG_CRYPTO_DEV_MARVELL_CESA=y
-CONFIG_CRC_T10DIF=y
index de37f7e..600f78b 100644 (file)
@@ -7,16 +7,11 @@ CONFIG_EMBEDDED=y
 CONFIG_PERF_EVENTS=y
 CONFIG_STRICT_KERNEL_RWX=y
 CONFIG_STRICT_MODULE_RWX=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_CMDLINE_PARTITION=y
 CONFIG_ARCH_MULTI_V6=y
 CONFIG_ARCH_OXNAS=y
 CONFIG_MACH_OX820=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=16
-CONFIG_CMA=y
 CONFIG_FORCE_MAX_ZONEORDER=12
 CONFIG_SECCOMP=y
 CONFIG_ARM_APPENDED_DTB=y
@@ -26,6 +21,11 @@ CONFIG_EFI=y
 CONFIG_CPU_IDLE=y
 CONFIG_ARM_CPUIDLE=y
 CONFIG_VFP=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_CMDLINE_PARTITION=y
+CONFIG_CMA=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -44,8 +44,6 @@ CONFIG_IPV6_TUNNEL=m
 CONFIG_IPV6_MULTIPLE_TABLES=y
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
-CONFIG_DMA_CMA=y
-CONFIG_CMA_SIZE_MBYTES=64
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
@@ -88,5 +86,7 @@ CONFIG_PSTORE_RAM=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_NLS_UTF8=y
+CONFIG_DMA_CMA=y
+CONFIG_CMA_SIZE_MBYTES=64
 CONFIG_PRINTK_TIME=y
 CONFIG_MAGIC_SYSRQ=y
index e6acb1d..a9a808b 100644 (file)
@@ -1,24 +1,23 @@
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
+CONFIG_PREEMPT=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_PXA=y
 CONFIG_ARCH_PXA_PALM=y
 # CONFIG_MACH_PALMTX is not set
-CONFIG_PREEMPT=y
 CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_CMDLINE="mem=32M console=tty root=/dev/mmcblk0"
 CONFIG_FPE_NWFPE=y
 CONFIG_PM=y
 CONFIG_APM_EMULATION=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SLAB=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -52,8 +51,6 @@ CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_PWM=y
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FONTS=y
-CONFIG_FONT_8x8=y
 # CONFIG_USB_SUPPORT is not set
 CONFIG_MMC=y
 CONFIG_MMC_DEBUG=y
@@ -72,5 +69,7 @@ CONFIG_TMPFS=y
 CONFIG_NLS_DEFAULT="utf8"
 CONFIG_NLS_CODEPAGE_866=y
 CONFIG_NLS_UTF8=y
-CONFIG_DEBUG_USER=y
 CONFIG_CRC_T10DIF=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_DEBUG_USER=y
index 106d5be..06bc9a8 100644 (file)
@@ -1,6 +1,8 @@
-# CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
@@ -8,22 +10,19 @@ CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_PXA=y
 CONFIG_MACH_PCM027=y
 CONFIG_MACH_PCM990_BASEBOARD=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_PREEMPT=y
 CONFIG_AEABI=y
 # CONFIG_OABI_COMPAT is not set
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_UNUSED_BOARD_FILES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_SWAP is not set
+CONFIG_SLAB=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -43,6 +42,7 @@ CONFIG_MTD_PHYSMAP=y
 # CONFIG_BLK_DEV is not set
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
+# CONFIG_BLK_DEV_BSG is not set
 # CONFIG_SCSI_LOWLEVEL is not set
 CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
@@ -51,9 +51,9 @@ CONFIG_SMC91X=y
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_PXA=y
 CONFIG_SERIAL_PXA_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
@@ -84,7 +84,6 @@ CONFIG_JFFS2_FS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
-CONFIG_PARTITION_ADVANCED=y
 CONFIG_NLS_DEFAULT="iso8859-15"
 CONFIG_NLS_CODEPAGE_850=y
 CONFIG_NLS_ISO8859_15=y
index 2170148..d872633 100644 (file)
@@ -1,19 +1,18 @@
-# CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EXPERT=y
 # CONFIG_HOTPLUG is not set
 # CONFIG_SHMEM is not set
-CONFIG_MODULES=y
 CONFIG_ARCH_SA1100=y
 CONFIG_SA1100_PLEB=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_CMDLINE="console=ttySA0,9600 mem=16M@0xc0000000 mem=16M@0xc8000000 root=/dev/ram initrd=0xc0400000,4M"
 CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
 CONFIG_FPE_NWFPE=y
+CONFIG_MODULES=y
+# CONFIG_SWAP is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -21,9 +20,9 @@ CONFIG_INET=y
 CONFIG_SYN_COOKIES=y
 # CONFIG_IPV6 is not set
 CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
-CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_INTELEXT=y
index 0947f02..70d3278 100644 (file)
@@ -1,12 +1,6 @@
 CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
-CONFIG_ARCH_MMP=y
 CONFIG_MACH_ASPENITE=y
 CONFIG_MACH_ZYLONITE2=y
 CONFIG_MACH_AVENGERS_LITE=y
@@ -14,10 +8,14 @@ CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_ARCH_MMP=y
 CONFIG_CMDLINE="root=/dev/nfs rootfstype=nfs nfsroot=192.168.2.100:/nfsroot/ ip=192.168.2.101:192.168.2.100::255.255.255.0::eth0:on console=ttyS0,115200 mem=128M"
 CONFIG_FPE_NWFPE=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_SLAB=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -34,9 +32,9 @@ CONFIG_SMC91X=y
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_PXA=y
 CONFIG_SERIAL_PXA_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_HWMON is not set
 # CONFIG_VGA_CONSOLE is not set
@@ -49,12 +47,12 @@ CONFIG_NFS_V3=y
 CONFIG_NFS_V3_ACL=y
 CONFIG_NFS_V4=y
 CONFIG_ROOT_NFS=y
+CONFIG_CRC_CCITT=y
 CONFIG_PRINTK_TIME=y
-CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
 # CONFIG_DEBUG_PREEMPT is not set
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_LL=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
-CONFIG_CRC_CCITT=y
index 5663245..ae04449 100644 (file)
@@ -1,16 +1,12 @@
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_MODULES=y
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_PXA=y
 CONFIG_ARCH_PXA_IDP=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_LEDS=y
-CONFIG_LEDS_CPU=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_CMDLINE="root=/dev/nfs ip=dhcp console=ttyS0,115200 mem=64M"
 CONFIG_FPE_NWFPE=y
+CONFIG_MODULES=y
 CONFIG_NET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
@@ -38,18 +34,22 @@ CONFIG_FB=y
 CONFIG_FB_PXA=y
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FONTS=y
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
 CONFIG_LOGO=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_CPU=y
 CONFIG_EXT2_FS=y
 CONFIG_MSDOS_FS=y
 CONFIG_JFFS2_FS=y
 CONFIG_NFS_FS=y
 CONFIG_ROOT_NFS=y
 CONFIG_NLS_ISO8859_1=y
-CONFIG_MAGIC_SYSRQ=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
 CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
+CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_LL=y
index 228d427..d1e83b5 100644 (file)
@@ -1,22 +1,18 @@
 CONFIG_SYSVIPC=y
+CONFIG_PREEMPT=y
 CONFIG_LOG_BUF_SHIFT=18
 CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_KALLSYMS_ALL=y
-CONFIG_SLAB=y
-CONFIG_MODULES=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_PXA=y
-CONFIG_MACH_LITTLETON=y
-CONFIG_MACH_TAVOREVB=y
-CONFIG_MACH_SAAR=y
-CONFIG_PREEMPT=y
+CONFIG_MACH_PXA3XX_DT=y
 CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="root=/dev/nfs rootfstype=nfs nfsroot=192.168.1.100:/nfsroot/ ip=192.168.1.101:192.168.1.100::255.255.255.0::eth0:on console=ttyS0,115200 mem=64M debug"
 CONFIG_FPE_NWFPE=y
+CONFIG_MODULES=y
+CONFIG_SLAB=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -31,11 +27,11 @@ CONFIG_IP_PNP=y
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
-CONFIG_MTD_RAW_NAND=y
-CONFIG_MTD_NAND_MARVELL=y
 CONFIG_MTD_ONENAND=y
 CONFIG_MTD_ONENAND_VERIFY_WRITE=y
 CONFIG_MTD_ONENAND_GENERIC=y
+CONFIG_MTD_RAW_NAND=y
+CONFIG_MTD_NAND_MARVELL=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_NETDEVICES=y
@@ -45,12 +41,10 @@ CONFIG_SMC91X=y
 # CONFIG_KEYBOARD_ATKBD is not set
 CONFIG_KEYBOARD_GPIO=y
 CONFIG_KEYBOARD_PXA27x=y
-CONFIG_KEYBOARD_PXA930_ROTARY=y
-CONFIG_MOUSE_PXA930_TRKBALL=y
 CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_PXA=y
 CONFIG_SERIAL_PXA_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
 # CONFIG_I2C_HELPER_AUTO is not set
@@ -61,7 +55,6 @@ CONFIG_GPIO_MAX732X=y
 CONFIG_GPIO_PCA953X=y
 CONFIG_GPIO_PCF857X=y
 CONFIG_GPIO_MAX7301=y
-CONFIG_POWER_SUPPLY=y
 CONFIG_POWER_SUPPLY_DEBUG=y
 CONFIG_PDA_POWER=y
 CONFIG_BATTERY_DA9030=y
@@ -79,8 +72,6 @@ CONFIG_BACKLIGHT_DA903X=y
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
-CONFIG_FONTS=y
-CONFIG_FONT_6x11=y
 CONFIG_LOGO=y
 # CONFIG_USB_SUPPORT is not set
 CONFIG_MMC=y
@@ -106,9 +97,11 @@ CONFIG_NFS_V3_ACL=y
 CONFIG_NFS_V4=y
 CONFIG_ROOT_NFS=y
 CONFIG_NLS=y
+CONFIG_FONTS=y
+CONFIG_FONT_6x11=y
 CONFIG_PRINTK_TIME=y
-CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_SHIRQ=y
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
 # CONFIG_SCHED_DEBUG is not set
index b211963..5072bde 100644 (file)
@@ -1,23 +1,21 @@
 CONFIG_SYSVIPC=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_SLAB=y
+CONFIG_ARCH_MMP=y
+CONFIG_CMDLINE="root=/dev/nfs rootfstype=nfs nfsroot=192.168.2.100:/nfsroot/ ip=192.168.2.101:192.168.2.100::255.255.255.0::eth0:on console=ttyS0,115200 mem=128M earlyprintk"
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
-CONFIG_ARCH_MMP=y
 CONFIG_MACH_TAVOREVB=y
 CONFIG_MACH_TTC_DKB=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_PREEMPT=y
 CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="root=/dev/nfs rootfstype=nfs nfsroot=192.168.2.100:/nfsroot/ ip=192.168.2.101:192.168.2.100::255.255.255.0::eth0:on console=ttyS0,115200 mem=128M earlyprintk"
 CONFIG_FPE_NWFPE=y
+CONFIG_SLAB=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -34,9 +32,12 @@ CONFIG_SMC91X=y
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_PXA=y
 CONFIG_SERIAL_PXA_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
 CONFIG_SPI=y
+# CONFIG_HWMON is not set
 CONFIG_FB=y
 CONFIG_MMP_DISP=y
 CONFIG_MMP_DISP_CONTROLLER=y
@@ -44,9 +45,6 @@ CONFIG_MMP_SPI=y
 CONFIG_MMP_PANEL_TPOHVGA=y
 CONFIG_MMP_FB=y
 CONFIG_LOGO=y
-# CONFIG_LEGACY_PTYS is not set
-# CONFIG_HW_RANDOM is not set
-# CONFIG_HWMON is not set
 # CONFIG_VGA_CONSOLE is not set
 # CONFIG_USB_SUPPORT is not set
 CONFIG_TMPFS=y
@@ -57,14 +55,14 @@ CONFIG_NFS_V3=y
 CONFIG_NFS_V3_ACL=y
 CONFIG_NFS_V4=y
 CONFIG_ROOT_NFS=y
+CONFIG_CRC_CCITT=y
 CONFIG_PRINTK_TIME=y
-CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
 # CONFIG_DEBUG_PREEMPT is not set
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_LL=y
 CONFIG_DEBUG_MMP_UART2=y
 CONFIG_EARLY_PRINTK=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
-CONFIG_CRC_CCITT=y
index 1db70df..104a457 100644 (file)
@@ -3,6 +3,7 @@ CONFIG_POSIX_MQUEUE=y
 CONFIG_FHANDLE=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_BSD_PROCESS_ACCT_V3=y
 CONFIG_IKCONFIG=y
@@ -11,81 +12,16 @@ CONFIG_LOG_BUF_SHIFT=13
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_EMBEDDED=y
-CONFIG_SLOB=y
 CONFIG_PROFILING=y
-CONFIG_KPROBES=y
-CONFIG_MODULES=y
-CONFIG_MODULE_FORCE_LOAD=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_LDM_PARTITION=y
-CONFIG_CMDLINE_PARTITION=y
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_PXA=y
-CONFIG_ARCH_LUBBOCK=y
-CONFIG_MACH_MAINSTONE=y
-CONFIG_MACH_ZYLONITE300=y
-CONFIG_MACH_ZYLONITE320=y
-CONFIG_MACH_LITTLETON=y
-CONFIG_MACH_TAVOREVB=y
-CONFIG_MACH_SAAR=y
-CONFIG_ARCH_PXA_IDP=y
-CONFIG_ARCH_VIPER=y
-CONFIG_MACH_ARCOM_ZEUS=y
-CONFIG_MACH_BALLOON3=y
-CONFIG_MACH_CSB726=y
-CONFIG_CSB726_CSB701=y
-CONFIG_MACH_EXEDA=y
-CONFIG_MACH_CM_X300=y
-CONFIG_MACH_CAPC7117=y
 CONFIG_ARCH_GUMSTIX=y
-CONFIG_MACH_XCEP=y
-CONFIG_TRIZEPS_PXA=y
-CONFIG_MACH_TRIZEPS4WL=y
-CONFIG_MACH_LOGICPD_PXA270=y
-CONFIG_MACH_PCM027=y
-CONFIG_MACH_PCM990_BASEBOARD=y
-CONFIG_MACH_COLIBRI=y
-CONFIG_MACH_COLIBRI_PXA270_INCOME=y
-CONFIG_MACH_COLIBRI300=y
-CONFIG_MACH_COLIBRI320=y
-CONFIG_MACH_COLIBRI_EVALBOARD=y
-CONFIG_MACH_VPAC270=y
-CONFIG_MACH_H4700=y
-CONFIG_MACH_H5000=y
-CONFIG_MACH_HIMALAYA=y
-CONFIG_MACH_MAGICIAN=y
-CONFIG_MACH_MIOA701=y
-CONFIG_PXA_EZX=y
-CONFIG_MACH_MP900C=y
-CONFIG_ARCH_PXA_PALM=y
 CONFIG_PXA_SHARPSL=y
-CONFIG_MACH_POODLE=y
-CONFIG_MACH_CORGI=y
-CONFIG_MACH_SHEPHERD=y
-CONFIG_MACH_HUSKY=y
 CONFIG_MACH_AKITA=y
 CONFIG_MACH_BORZOI=y
-CONFIG_MACH_TOSA=y
-CONFIG_TOSA_BT=m
-CONFIG_TOSA_USE_EXT_KEYCODES=y
-CONFIG_MACH_ICONTROL=y
-CONFIG_ARCH_PXA_ESERIES=y
-CONFIG_MACH_ZIPIT2=y
-CONFIG_PCI=y
-CONFIG_PCI_MSI=y
-CONFIG_PCIEPORTBUS=y
-CONFIG_PCCARD=m
-CONFIG_YENTA=m
-CONFIG_PCMCIA_PXA2XX=m
-CONFIG_PREEMPT=y
+CONFIG_PXA_SYSTEMS_CPLDS=y
 CONFIG_AEABI=y
-# CONFIG_COMPACTION is not set
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_FORCE_MAX_ZONEORDER=9
 CONFIG_CMDLINE="root=/dev/ram0 ro"
 CONFIG_KEXEC=y
 CONFIG_CPU_FREQ=y
@@ -98,7 +34,24 @@ CONFIG_CPUFREQ_DT=m
 CONFIG_ARM_PXA2xx_CPUFREQ=m
 CONFIG_CPU_IDLE=y
 CONFIG_ARM_CPUIDLE=y
+CONFIG_ARM_CRYPTO=y
+CONFIG_CRYPTO_SHA1_ARM=m
+CONFIG_CRYPTO_SHA256_ARM=m
+CONFIG_CRYPTO_SHA512_ARM=m
+CONFIG_CRYPTO_AES_ARM=m
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_LDM_PARTITION=y
+CONFIG_CMDLINE_PARTITION=y
 CONFIG_BINFMT_MISC=y
+CONFIG_SLOB=y
+# CONFIG_COMPACTION is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -116,16 +69,6 @@ CONFIG_BRIDGE=m
 CONFIG_VLAN_8021Q=m
 CONFIG_IEEE802154=y
 CONFIG_DNS_RESOLVER=y
-CONFIG_IRDA=m
-CONFIG_IRLAN=m
-CONFIG_IRNET=m
-CONFIG_IRCOMM=m
-CONFIG_IRDA_ULTRA=y
-CONFIG_IRDA_CACHE_LAST_LSAP=y
-CONFIG_IRDA_FAST_RR=y
-CONFIG_IRDA_DEBUG=y
-CONFIG_IRTTY_SIR=m
-CONFIG_PXA_FICP=m
 CONFIG_BT=m
 CONFIG_BT_RFCOMM=m
 CONFIG_BT_RFCOMM_TTY=y
@@ -152,51 +95,60 @@ CONFIG_MAC80211=m
 CONFIG_RFKILL=y
 CONFIG_RFKILL_INPUT=y
 CONFIG_RFKILL_GPIO=m
+CONFIG_PCI=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCI_MSI=y
+CONFIG_PCCARD=m
+CONFIG_YENTA=m
+CONFIG_PCMCIA_PXA2XX=m
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_CONNECTOR=y
+CONFIG_MTD=y
+CONFIG_MTD_AR7_PARTS=m
+CONFIG_MTD_CMDLINE_PARTS=m
+CONFIG_MTD_OF_PARTS=m
+CONFIG_MTD_AFS_PARTS=m
 CONFIG_MTD_REDBOOT_PARTS=m
 CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=0
 CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
 CONFIG_MTD_REDBOOT_PARTS_READONLY=y
-CONFIG_MTD_CMDLINE_PARTS=m
-CONFIG_MTD_AFS_PARTS=m
-CONFIG_MTD_OF_PARTS=m
-CONFIG_MTD_AR7_PARTS=m
 CONFIG_MTD_BLOCK=m
 CONFIG_NFTL=m
 CONFIG_NFTL_RW=y
+CONFIG_MTD_CFI=y
 CONFIG_MTD_JEDECPROBE=m
 CONFIG_MTD_CFI_ADV_OPTIONS=y
 CONFIG_MTD_CFI_LE_BYTE_SWAP=y
 CONFIG_MTD_CFI_GEOMETRY=y
 CONFIG_MTD_OTP=y
+CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_CFI_AMDSTD=m
 CONFIG_MTD_CFI_STAA=m
 CONFIG_MTD_RAM=m
 CONFIG_MTD_ROM=m
 CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHYSMAP=y
 CONFIG_MTD_PXA2XX=m
 CONFIG_MTD_M25P80=m
 CONFIG_MTD_BLOCK2MTD=y
 CONFIG_MTD_DOCG3=m
+CONFIG_MTD_ONENAND=m
+CONFIG_MTD_ONENAND_VERIFY_WRITE=y
+CONFIG_MTD_ONENAND_GENERIC=m
 CONFIG_MTD_RAW_NAND=m
-CONFIG_MTD_NAND_ECC_SW_BCH=y
+CONFIG_MTD_NAND_SHARPSL=m
+CONFIG_MTD_NAND_TMIO=m
+CONFIG_MTD_NAND_BRCMNAND=m
 CONFIG_MTD_NAND_GPIO=m
+CONFIG_MTD_NAND_PLATFORM=m
 CONFIG_MTD_NAND_DISKONCHIP=m
 CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED=y
 CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0x4000000
 CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH=y
 CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE=y
-CONFIG_MTD_NAND_SHARPSL=m
-CONFIG_MTD_NAND_MARVELL=m
 CONFIG_MTD_NAND_CM_X270=m
-CONFIG_MTD_NAND_TMIO=m
-CONFIG_MTD_NAND_BRCMNAND=m
-CONFIG_MTD_NAND_PLATFORM=m
-CONFIG_MTD_ONENAND=m
-CONFIG_MTD_ONENAND_VERIFY_WRITE=y
-CONFIG_MTD_ONENAND_GENERIC=m
+CONFIG_MTD_NAND_ECC_SW_BCH=y
 CONFIG_MTD_SPI_NOR=m
 CONFIG_MTD_UBI=m
 CONFIG_MTD_UBI_BLOCK=y
@@ -210,8 +162,6 @@ CONFIG_AD525X_DPOT_I2C=m
 CONFIG_ICS932S401=m
 CONFIG_APDS9802ALS=m
 CONFIG_ISL29003=m
-CONFIG_IIO=m
-CONFIG_AD5446=m
 CONFIG_EEPROM_AT24=m
 CONFIG_SENSORS_LIS3_SPI=m
 CONFIG_SCSI=y
@@ -242,13 +192,13 @@ CONFIG_SMC91X=m
 CONFIG_SMSC911X=m
 CONFIG_STMMAC_ETH=m
 CONFIG_PHYLIB=y
-CONFIG_AT803X_PHY=m
-CONFIG_MARVELL_PHY=m
 CONFIG_SMSC_PHY=m
 CONFIG_BROADCOM_PHY=y
 CONFIG_ICPLUS_PHY=m
 CONFIG_MICREL_PHY=m
 CONFIG_FIXED_PHY=m
+CONFIG_MARVELL_PHY=m
+CONFIG_AT803X_PHY=m
 CONFIG_MDIO_BITBANG=y
 CONFIG_PPP=m
 CONFIG_PPP_BSDCOMP=m
@@ -272,16 +222,16 @@ CONFIG_HOSTAP=m
 CONFIG_HOSTAP_FIRMWARE=y
 CONFIG_HOSTAP_FIRMWARE_NVRAM=y
 CONFIG_HOSTAP_CS=m
-CONFIG_LIBERTAS=m
-CONFIG_LIBERTAS_SDIO=m
 CONFIG_HERMES=m
 CONFIG_PCMCIA_HERMES=m
 CONFIG_PCMCIA_SPECTRUM=m
+CONFIG_LIBERTAS=m
+CONFIG_LIBERTAS_SDIO=m
+CONFIG_MWIFIEX=m
+CONFIG_MWIFIEX_SDIO=m
 CONFIG_RT2X00=m
 CONFIG_RT73USB=m
 CONFIG_RT2800USB=m
-CONFIG_MWIFIEX=m
-CONFIG_MWIFIEX_SDIO=m
 CONFIG_INPUT_FF_MEMLESS=m
 CONFIG_INPUT_MATRIXKMAP=y
 CONFIG_INPUT_MOUSEDEV=m
@@ -294,14 +244,12 @@ CONFIG_KEYBOARD_ATKBD=m
 CONFIG_KEYBOARD_QT1070=m
 CONFIG_KEYBOARD_GPIO=m
 CONFIG_KEYBOARD_PXA27x=m
-CONFIG_KEYBOARD_PXA930_ROTARY=m
 CONFIG_KEYBOARD_CROS_EC=m
 CONFIG_MOUSE_PS2=m
 CONFIG_MOUSE_PS2_ELANTECH=y
 CONFIG_MOUSE_SERIAL=m
 CONFIG_MOUSE_CYAPA=m
 CONFIG_MOUSE_ELAN_I2C=m
-CONFIG_MOUSE_PXA930_TRKBALL=m
 CONFIG_MOUSE_NAVPOINT_PXA27x=m
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ADS7846=m
@@ -312,12 +260,9 @@ CONFIG_TOUCHSCREEN_FUJITSU=m
 CONFIG_TOUCHSCREEN_ELO=m
 CONFIG_TOUCHSCREEN_MTOUCH=m
 CONFIG_TOUCHSCREEN_INEXIO=m
-CONFIG_TOUCHSCREEN_HTCPEN=m
 CONFIG_TOUCHSCREEN_PENMOUNT=m
 CONFIG_TOUCHSCREEN_TOUCHRIGHT=m
 CONFIG_TOUCHSCREEN_TOUCHWIN=m
-CONFIG_TOUCHSCREEN_UCB1400=m
-CONFIG_TOUCHSCREEN_WM97XX=m
 CONFIG_TOUCHSCREEN_TOUCHIT213=m
 CONFIG_TOUCHSCREEN_PCAP=m
 CONFIG_TOUCHSCREEN_ST1232=m
@@ -328,7 +273,6 @@ CONFIG_INPUT_GPIO_ROTARY_ENCODER=m
 CONFIG_INPUT_PCAP=m
 CONFIG_INPUT_ADXL34X=m
 CONFIG_SERIO=m
-CONFIG_SERIO_SA1111=m
 CONFIG_LEGACY_PTY_COUNT=8
 CONFIG_SERIAL_8250=m
 CONFIG_SERIAL_8250_CS=m
@@ -341,6 +285,7 @@ CONFIG_I2C_CHARDEV=m
 CONFIG_I2C_MUX_PCA954x=m
 CONFIG_I2C_MUX_PINCTRL=m
 CONFIG_I2C_DESIGNWARE_PLATFORM=m
+CONFIG_I2C_GPIO=y
 CONFIG_I2C_PXA_SLAVE=y
 CONFIG_I2C_XILINX=m
 CONFIG_I2C_CROS_EC_TUNNEL=m
@@ -354,16 +299,17 @@ CONFIG_SPI_XILINX=m
 CONFIG_SPI_SPIDEV=m
 CONFIG_PPS=y
 CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_DWAPB=m
 CONFIG_GPIO_GENERIC_PLATFORM=m
 CONFIG_GPIO_MAX732X=m
 CONFIG_GPIO_PCA953X=m
 CONFIG_GPIO_PCF857X=m
+CONFIG_HTC_EGPIO=y
 CONFIG_GPIO_PALMAS=y
 CONFIG_GPIO_TPS6586X=y
 CONFIG_GPIO_TPS65910=y
 CONFIG_GPIO_MAX7301=m
-CONFIG_GPIO_SYSFS=y
 CONFIG_POWER_SUPPLY_DEBUG=y
 CONFIG_PDA_POWER=m
 CONFIG_BATTERY_SBS=m
@@ -387,13 +333,8 @@ CONFIG_MFD_AS3711=y
 CONFIG_MFD_BCM590XX=m
 CONFIG_MFD_AXP20X=y
 CONFIG_MFD_CROS_EC_DEV=m
-CONFIG_CHROME_PLATFORMS=y
-CONFIG_CROS_EC=m
-CONFIG_CROS_EC_I2C=m
-CONFIG_CROS_EC_SPI=m
 CONFIG_MFD_ASIC3=y
 CONFIG_PMIC_DA903X=y
-CONFIG_HTC_EGPIO=y
 CONFIG_HTC_PASIC3=m
 CONFIG_MFD_MAX14577=y
 CONFIG_MFD_MAX77693=y
@@ -441,11 +382,13 @@ CONFIG_VIDEO_V4L2_SUBDEV_API=y
 CONFIG_MEDIA_USB_SUPPORT=y
 CONFIG_USB_VIDEO_CLASS=m
 CONFIG_V4L_PLATFORM_DRIVERS=y
-CONFIG_VIDEO_PXA27x=m
 CONFIG_V4L_MEM2MEM_DRIVERS=y
+CONFIG_VIDEO_PXA27x=m
 CONFIG_DRM=m
+CONFIG_FB=y
 CONFIG_FIRMWARE_EDID=y
 CONFIG_FB_TILEBLITTING=y
+CONFIG_FB_PXA=y
 CONFIG_FB_PXA_OVERLAY=y
 CONFIG_FB_PXA_PARAMETERS=y
 CONFIG_PXA3XX_GCU=m
@@ -462,31 +405,20 @@ CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
 CONFIG_LOGO=y
 CONFIG_SOUND=m
 CONFIG_SND=m
-CONFIG_SND_SEQUENCER=m
 CONFIG_SND_MIXER_OSS=m
 CONFIG_SND_PCM_OSS=m
 CONFIG_SND_DYNAMIC_MINORS=y
 CONFIG_SND_VERBOSE_PRINTK=y
 CONFIG_SND_DEBUG=y
+CONFIG_SND_SEQUENCER=m
 CONFIG_SND_USB_AUDIO=m
 CONFIG_SND_SOC=m
 CONFIG_SND_ATMEL_SOC=m
 CONFIG_SND_PXA2XX_SOC=m
-CONFIG_SND_PXA2XX_SOC_CORGI=m
+CONFIG_SND_PXA_SOC_SSP=m
 CONFIG_SND_PXA2XX_SOC_SPITZ=m
-CONFIG_SND_PXA2XX_SOC_Z2=m
-CONFIG_SND_PXA2XX_SOC_POODLE=m
-CONFIG_SND_PXA2XX_SOC_TOSA=m
-CONFIG_SND_PXA2XX_SOC_E740=m
-CONFIG_SND_PXA2XX_SOC_E750=m
-CONFIG_SND_PXA2XX_SOC_E800=m
-CONFIG_SND_PXA2XX_SOC_EM_X270=m
-CONFIG_SND_PXA2XX_SOC_PALM27X=y
-CONFIG_SND_SOC_ZYLONITE=m
-CONFIG_SND_PXA2XX_SOC_HX4700=m
-CONFIG_SND_PXA2XX_SOC_MAGICIAN=m
-CONFIG_SND_PXA2XX_SOC_MIOA701=m
 CONFIG_SND_SOC_AK4642=m
+CONFIG_SND_SOC_WM8731_I2C=m
 CONFIG_SND_SOC_WM8978=m
 CONFIG_SND_SIMPLE_CARD=m
 CONFIG_SOUND_PRIME=m
@@ -575,6 +507,7 @@ CONFIG_USB_LCD=m
 CONFIG_USB_CYTHERM=m
 CONFIG_USB_IDMOUSE=m
 CONFIG_USB_GPIO_VBUS=y
+CONFIG_USB_GPIO_VBUS=m
 CONFIG_USB_ISP1301=m
 CONFIG_USB_GADGET=m
 CONFIG_USB_GADGET_VBUS_DRAW=500
@@ -621,9 +554,9 @@ CONFIG_RTC_DRV_DS1307=m
 CONFIG_RTC_DRV_MAX8907=m
 CONFIG_RTC_DRV_RS5C372=m
 CONFIG_RTC_DRV_ISL1208=m
-CONFIG_RTC_DRV_PALMAS=m
 CONFIG_RTC_DRV_PCF8563=m
 CONFIG_RTC_DRV_PCF8583=m
+CONFIG_RTC_DRV_PALMAS=m
 CONFIG_RTC_DRV_TPS6586X=m
 CONFIG_RTC_DRV_TPS65910=m
 CONFIG_RTC_DRV_S35390A=m
@@ -638,10 +571,16 @@ CONFIG_PXA_DMA=y
 CONFIG_DW_DMAC=m
 CONFIG_UIO=y
 CONFIG_CROS_EC_CHARDEV=m
+CONFIG_CHROME_PLATFORMS=y
+CONFIG_CROS_EC=m
+CONFIG_CROS_EC_I2C=m
+CONFIG_CROS_EC_SPI=m
 CONFIG_COMMON_CLK_S2MPS11=m
 CONFIG_PM_DEVFREQ=y
 CONFIG_EXTCON=y
 CONFIG_MEMORY=y
+CONFIG_IIO=m
+CONFIG_AD5446=m
 CONFIG_PWM=y
 CONFIG_PWM_PXA=m
 CONFIG_PHY_SAMSUNG_USB2=m
@@ -707,17 +646,8 @@ CONFIG_NLS_ASCII=m
 CONFIG_NLS_ISO8859_1=m
 CONFIG_NLS_ISO8859_15=m
 CONFIG_NLS_UTF8=m
-CONFIG_PRINTK_TIME=y
-CONFIG_DYNAMIC_DEBUG=y
-CONFIG_DEBUG_INFO=y
-CONFIG_FRAME_WARN=0
-CONFIG_STRIP_ASM_SYMS=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_SHIRQ=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 CONFIG_TIMER_STATS=y
-CONFIG_FUNCTION_TRACER=y
-CONFIG_FTRACE_SYSCALLS=y
-CONFIG_DEBUG_USER=y
 CONFIG_SECURITY=y
 CONFIG_CRYPTO_MANAGER=y
 CONFIG_CRYPTO_CRYPTD=m
@@ -743,11 +673,6 @@ CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_DEFLATE=y
 CONFIG_CRYPTO_LZO=y
-CONFIG_ARM_CRYPTO=y
-CONFIG_CRYPTO_SHA1_ARM=m
-CONFIG_CRYPTO_SHA256_ARM=m
-CONFIG_CRYPTO_SHA512_ARM=m
-CONFIG_CRYPTO_AES_ARM=m
 CONFIG_CRC_CCITT=y
 CONFIG_CRC_T10DIF=m
 CONFIG_FONTS=y
@@ -755,3 +680,11 @@ CONFIG_FONT_8x8=y
 CONFIG_FONT_8x16=y
 CONFIG_FONT_6x11=y
 CONFIG_FONT_MINI_4x6=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_FRAME_WARN=0
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_SHIRQ=y
+CONFIG_FUNCTION_TRACER=y
+CONFIG_FTRACE_SYSCALLS=y
index 5cd935e..8a59441 100644 (file)
@@ -1,39 +1,38 @@
 CONFIG_SYSVIPC=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_CGROUPS=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_EMBEDDED=y
-# CONFIG_SLUB_DEBUG is not set
-# CONFIG_COMPAT_BRK is not set
 CONFIG_PROFILING=y
-CONFIG_KPROBES=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_PARTITION_ADVANCED=y
 CONFIG_ARCH_QCOM=y
 CONFIG_ARCH_MSM8X60=y
 CONFIG_ARCH_MSM8960=y
 CONFIG_ARCH_MSM8974=y
 CONFIG_ARCH_MDM9615=y
-CONFIG_PCI=y
-CONFIG_PCI_MSI=y
-CONFIG_PCIE_QCOM=y
 CONFIG_SMP=y
-CONFIG_PREEMPT=y
+CONFIG_ARM_PSCI=y
 CONFIG_HIGHMEM=y
 CONFIG_ARM_APPENDED_DTB=y
 CONFIG_ARM_ATAG_DTB_COMPAT=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPUFREQ_DT=y
 CONFIG_CPU_IDLE=y
 CONFIG_ARM_CPUIDLE=y
 CONFIG_VFP=y
 CONFIG_NEON=y
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_COMPAT_BRK is not set
 CONFIG_CMA=y
 CONFIG_NET=y
 CONFIG_PACKET=y
@@ -56,15 +55,18 @@ CONFIG_BT_HCIUART_BCM=y
 CONFIG_CFG80211=m
 CONFIG_MAC80211=m
 CONFIG_RFKILL=y
+CONFIG_PCI=y
+CONFIG_PCI_MSI=y
+CONFIG_PCIE_QCOM=y
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_MTD=y
+CONFIG_MTD_QCOMSMEM_PARTS=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_M25P80=y
 CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_QCOM=y
 CONFIG_MTD_SPI_NOR=y
-CONFIG_MTD_QCOMSMEM_PARTS=y
 CONFIG_MTD_UBI=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
@@ -133,10 +135,10 @@ CONFIG_PINCTRL_MSM8660=y
 CONFIG_PINCTRL_MSM8960=y
 CONFIG_PINCTRL_MDM9615=y
 CONFIG_PINCTRL_MSM8X74=y
-CONFIG_PINCTRL_SDX55=y
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_PINCTRL_QCOM_SSBI_PMIC=y
 CONFIG_GPIOLIB=y
+CONFIG_PINCTRL_SDX55=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_POWER_RESET=y
 CONFIG_POWER_RESET_MSM=y
@@ -144,15 +146,17 @@ CONFIG_CHARGER_QCOM_SMBB=y
 CONFIG_CHARGER_BQ24190=m
 CONFIG_THERMAL=y
 CONFIG_QCOM_TSENS=y
+CONFIG_WATCHDOG=y
+CONFIG_QCOM_WDT=y
 CONFIG_MFD_PM8XXX=y
 CONFIG_MFD_QCOM_RPM=y
 CONFIG_MFD_SPMI_PMIC=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_QCOM_RPM=y
+CONFIG_REGULATOR_QCOM_RPMH=y
 CONFIG_REGULATOR_QCOM_SMD_RPM=y
 CONFIG_REGULATOR_QCOM_SPMI=y
-CONFIG_REGULATOR_QCOM_RPMH=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_DRM=y
 CONFIG_DRM_MSM=m
@@ -160,11 +164,11 @@ CONFIG_DRM_PANEL_SIMPLE=y
 CONFIG_DRM_PANEL_EDP=y
 CONFIG_DRM_ANALOGIX_ANX78XX=m
 CONFIG_FB=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
 # CONFIG_LCD_CLASS_DEVICE is not set
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_LM3630A=y
 CONFIG_BACKLIGHT_LP855X=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_DYNAMIC_MINORS=y
@@ -180,6 +184,7 @@ CONFIG_USB_MON=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_MSM=y
 CONFIG_USB_ACM=y
+CONFIG_USB_DWC3=y
 CONFIG_USB_CHIPIDEA=y
 CONFIG_USB_CHIPIDEA_UDC=y
 CONFIG_USB_CHIPIDEA_HOST=y
@@ -196,7 +201,6 @@ CONFIG_USB_CONFIGFS_ECM=y
 CONFIG_USB_CONFIGFS_F_FS=y
 CONFIG_USB_ULPI_BUS=y
 CONFIG_USB_ETH=m
-CONFIG_USB_DWC3=y
 CONFIG_MMC=y
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_ARMMMCI=y
@@ -218,8 +222,8 @@ CONFIG_COMMON_CLK_QCOM=y
 CONFIG_QCOM_A7PLL=y
 CONFIG_QCOM_CLK_APCS_SDX55=y
 CONFIG_QCOM_CLK_RPM=y
-CONFIG_QCOM_CLK_RPMH=y
 CONFIG_QCOM_CLK_SMD_RPM=y
+CONFIG_QCOM_CLK_RPMH=y
 CONFIG_APQ_MMCC_8084=y
 CONFIG_IPQ_GCC_4019=y
 CONFIG_IPQ_LCC_806X=y
@@ -229,12 +233,12 @@ CONFIG_MDM_LCC_9615=y
 CONFIG_MSM_MMCC_8960=y
 CONFIG_MSM_MMCC_8974=y
 CONFIG_SDX_GCC_55=y
-CONFIG_MSM_IOMMU=y
-CONFIG_ARM_SMMU=y
 CONFIG_HWSPINLOCK=y
 CONFIG_HWSPINLOCK_QCOM=y
 CONFIG_MAILBOX=y
 CONFIG_QCOM_APCS_IPC=y
+CONFIG_MSM_IOMMU=y
+CONFIG_ARM_SMMU=y
 CONFIG_REMOTEPROC=y
 CONFIG_QCOM_ADSP_PIL=y
 CONFIG_QCOM_Q6V5_PAS=y
@@ -247,12 +251,12 @@ CONFIG_QCOM_COMMAND_DB=y
 CONFIG_QCOM_GSBI=y
 CONFIG_QCOM_OCMEM=y
 CONFIG_QCOM_PM=y
+CONFIG_QCOM_RPMH=y
+CONFIG_QCOM_RPMHPD=y
 CONFIG_QCOM_SMEM=y
 CONFIG_QCOM_SMD_RPM=y
 CONFIG_QCOM_SMP2P=y
 CONFIG_QCOM_SMSM=y
-CONFIG_QCOM_RPMH=y
-CONFIG_QCOM_RPMHPD=y
 CONFIG_QCOM_WCNSS_CTRL=y
 CONFIG_EXTCON_QCOM_SPMI_MISC=y
 CONFIG_IIO=y
@@ -270,10 +274,10 @@ CONFIG_BMP280=y
 CONFIG_PWM=y
 CONFIG_PHY_QCOM_APQ8064_SATA=y
 CONFIG_PHY_QCOM_IPQ806X_SATA=y
-CONFIG_PHY_QCOM_USB_HS=y
-CONFIG_PHY_QCOM_USB_HSIC=y
 CONFIG_PHY_QCOM_QMP=y
+CONFIG_PHY_QCOM_USB_HS=y
 CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2=y
+CONFIG_PHY_QCOM_USB_HSIC=y
 CONFIG_QCOM_QFPROM=y
 CONFIG_INTERCONNECT=y
 CONFIG_INTERCONNECT_QCOM=y
@@ -299,19 +303,15 @@ CONFIG_CRYPTO_USER=m
 CONFIG_CRYPTO_USER_API=m
 CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
-CONFIG_CRYPTO_USER_API_AEAD=m
 CONFIG_CRYPTO_USER_API_RNG=m
+CONFIG_CRYPTO_USER_API_AEAD=m
 CONFIG_CRYPTO_DEV_QCOM_RNG=m
 CONFIG_DMA_CMA=y
 CONFIG_CMA_SIZE_MBYTES=64
 CONFIG_PRINTK_TIME=y
 CONFIG_DYNAMIC_DEBUG=y
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
+# CONFIG_SLUB_DEBUG is not set
 # CONFIG_SCHED_DEBUG is not set
-CONFIG_WATCHDOG=y
-CONFIG_QCOM_WDT=y
-CONFIG_ARM_PSCI=y
-CONFIG_CPU_FREQ=y
-CONFIG_CPUFREQ_DT=y
index 3ef3521..92f803c 100644 (file)
@@ -1,10 +1,8 @@
-# CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_NO_HZ_FULL=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_PERF_EVENTS=y
-CONFIG_SLAB=y
 CONFIG_ARCH_MULTI_V6=y
 CONFIG_ARCH_REALVIEW=y
 CONFIG_MACH_REALVIEW_EB=y
@@ -21,7 +19,8 @@ CONFIG_CMDLINE="root=/dev/nfs nfsroot=10.1.69.3:/work/nfsroot ip=dhcp console=tt
 CONFIG_VFP=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_SWAP is not set
+CONFIG_SLAB=y
 CONFIG_CMA=y
 CONFIG_NET=y
 CONFIG_PACKET=y
@@ -43,6 +42,7 @@ CONFIG_MTD_PHYSMAP=y
 CONFIG_MTD_PHYSMAP_OF=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
+# CONFIG_BLK_DEV_BSG is not set
 CONFIG_NETDEVICES=y
 CONFIG_SMC91X=y
 CONFIG_SMSC911X=y
@@ -95,9 +95,9 @@ CONFIG_NFS_FS=y
 CONFIG_ROOT_NFS=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
+CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
 # CONFIG_SCHED_DEBUG is not set
 # CONFIG_FTRACE is not set
 CONFIG_DEBUG_USER=y
index c090643..16d74a1 100644 (file)
@@ -2,16 +2,15 @@
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 CONFIG_ARCH_RPC=y
 CONFIG_CPU_SA110=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_FPE_NWFPE=y
 CONFIG_BINFMT_AOUT=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_SLAB=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -33,6 +32,7 @@ CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_BLK_DEV_SR=y
 CONFIG_CHR_DEV_SG=y
+# CONFIG_BLK_DEV_BSG is not set
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_LOGGING=y
 CONFIG_SCSI_ARXESCSI=m
@@ -55,12 +55,12 @@ CONFIG_INPUT_EVDEV=y
 # CONFIG_MOUSE_PS2 is not set
 CONFIG_MOUSE_RISCPC=y
 # CONFIG_SERIO_SERPORT is not set
+CONFIG_LEGACY_PTY_COUNT=64
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=16
 CONFIG_SERIAL_8250_RUNTIME_UARTS=8
 CONFIG_SERIAL_8250_ACORN=y
-CONFIG_LEGACY_PTY_COUNT=64
 CONFIG_PRINTER=m
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
@@ -69,9 +69,6 @@ CONFIG_I2C_CHARDEV=y
 CONFIG_FB=y
 CONFIG_FB_ACORN=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FONTS=y
-CONFIG_FONT_8x16=y
-CONFIG_FONT_ACORN_8x8=y
 CONFIG_LOGO=y
 CONFIG_SOUND=m
 CONFIG_SOUND_PRIME=m
@@ -89,10 +86,8 @@ CONFIG_MSDOS_FS=m
 CONFIG_VFAT_FS=m
 CONFIG_ADFS_FS=y
 CONFIG_NFS_FS=y
-CONFIG_PARTITION_ADVANCED=y
 # CONFIG_ACORN_PARTITION_CUMANA is not set
 # CONFIG_ACORN_PARTITION_EESOX is not set
-CONFIG_BSD_DISKLABEL=y
 CONFIG_NLS_CODEPAGE_437=m
 CONFIG_NLS_CODEPAGE_737=m
 CONFIG_NLS_CODEPAGE_775=m
@@ -120,8 +115,11 @@ CONFIG_NLS_ISO8859_6=m
 CONFIG_NLS_ISO8859_7=m
 CONFIG_NLS_ISO8859_9=m
 CONFIG_NLS_KOI8_R=m
-CONFIG_MAGIC_SYSRQ=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x16=y
+CONFIG_FONT_ACORN_8x8=y
 CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_LL=y
 CONFIG_DEBUG_LL_UART_8250=y
index 12fa6ca..41b4086 100644 (file)
@@ -3,7 +3,6 @@ CONFIG_IKCONFIG=m
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=16
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_SLAB=y
 CONFIG_ARCH_MULTI_V4T=y
 CONFIG_ARCH_MULTI_V5=y
 # CONFIG_ARCH_MULTI_V7 is not set
@@ -38,18 +37,17 @@ CONFIG_ARCH_S3C2440=y
 CONFIG_MACH_NEO1973_GTA02=y
 CONFIG_MACH_RX1950=y
 CONFIG_MACH_SMDK2443=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_CMDLINE="root=/dev/hda1 ro init=/bin/bash console=ttySAC0"
 CONFIG_FPE_NWFPE=y
 CONFIG_FPE_NWFPE_XP=y
 CONFIG_APM_EMULATION=m
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_BSD_DISKLABEL=y
 CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_SLAB=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -206,6 +204,7 @@ CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_BLK_DEV_SR=y
 CONFIG_CHR_DEV_SG=y
+# CONFIG_BLK_DEV_BSG is not set
 CONFIG_CHR_DEV_SCH=m
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_SCAN_ASYNC=y
@@ -252,7 +251,6 @@ CONFIG_INPUT_YEALINK=m
 CONFIG_INPUT_CM109=m
 CONFIG_INPUT_UINPUT=m
 CONFIG_INPUT_GPIO_ROTARY_ENCODER=m
-CONFIG_SERIAL_NONSTANDARD=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=8
@@ -261,6 +259,7 @@ CONFIG_SERIAL_8250_MANY_PORTS=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
 CONFIG_SERIAL_SAMSUNG=y
 CONFIG_SERIAL_SAMSUNG_CONSOLE=y
+CONFIG_SERIAL_NONSTANDARD=y
 CONFIG_SERIAL_DEV_BUS=m
 CONFIG_PRINTER=y
 CONFIG_PPDEV=y
@@ -430,9 +429,9 @@ CONFIG_NLS_ISO8859_15=m
 CONFIG_NLS_KOI8_R=m
 CONFIG_NLS_KOI8_U=m
 CONFIG_NLS_UTF8=m
-CONFIG_DEBUG_INFO=y
-CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_MUTEXES=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_LL=y
index 59a258d..4f04f58 100644 (file)
@@ -5,15 +5,6 @@ CONFIG_KALLSYMS_ALL=y
 CONFIG_ARCH_MULTI_V6=y
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_S3C64XX=y
-CONFIG_MACH_SMDK6400=y
-CONFIG_MACH_ANW6410=y
-CONFIG_MACH_MINI6410=y
-CONFIG_MACH_REAL6410=y
-CONFIG_MACH_SMDK6410=y
-CONFIG_MACH_NCP=y
-CONFIG_MACH_HMT=y
-CONFIG_MACH_SMARTQ5=y
-CONFIG_MACH_SMARTQ7=y
 CONFIG_MACH_WLF_CRAGG_6410=y
 CONFIG_CMDLINE="console=ttySAC0,115200 root=/dev/ram init=/linuxrc initrd=0x51000000,6M ramdisk_size=6144"
 CONFIG_VFP=y
@@ -71,9 +62,9 @@ CONFIG_TMPFS=y
 CONFIG_TMPFS_POSIX_ACL=y
 CONFIG_CRAMFS=y
 CONFIG_ROMFS_FS=y
-CONFIG_DEBUG_INFO=y
-CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_RT_MUTEXES=y
 CONFIG_DEBUG_SPINLOCK=y
 CONFIG_DEBUG_MUTEXES=y
index 7091971..789e900 100644 (file)
@@ -21,7 +21,6 @@ CONFIG_VFP=y
 CONFIG_NEON=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_BSD_DISKLABEL=y
 CONFIG_SOLARIS_X86_PARTITION=y
@@ -48,6 +47,7 @@ CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_SG=y
+# CONFIG_BLK_DEV_BSG is not set
 CONFIG_NETDEVICES=y
 CONFIG_BRCMFMAC=m
 CONFIG_INPUT_EVDEV=y
@@ -115,9 +115,9 @@ CONFIG_NLS_ASCII=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_NLS_UTF8=y
 CONFIG_CRC_CCITT=y
-CONFIG_DEBUG_INFO=y
-CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
 # CONFIG_DEBUG_PREEMPT is not set
 CONFIG_DEBUG_RT_MUTEXES=y
 CONFIG_DEBUG_SPINLOCK=y
index 1885280..3a6a485 100644 (file)
@@ -1,5 +1,4 @@
 # CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_NO_HZ_IDLE=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -7,7 +6,6 @@ CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CGROUPS=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
 CONFIG_ARCH_AT91=y
 CONFIG_SOC_SAMA5D2=y
 CONFIG_SOC_SAMA5D3=y
@@ -26,8 +24,9 @@ CONFIG_MODULES=y
 CONFIG_MODULE_FORCE_LOAD=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_SWAP is not set
+CONFIG_SLAB=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -72,6 +71,7 @@ CONFIG_ATMEL_SSC=y
 CONFIG_EEPROM_AT24=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
+# CONFIG_BLK_DEV_BSG is not set
 # CONFIG_SCSI_LOWLEVEL is not set
 CONFIG_NETDEVICES=y
 CONFIG_NET_DSA_MICROCHIP_KSZ9477=m
@@ -152,11 +152,11 @@ CONFIG_USB_VIDEO_CLASS=m
 CONFIG_V4L_PLATFORM_DRIVERS=y
 CONFIG_VIDEO_ATMEL_ISC=y
 CONFIG_VIDEO_ATMEL_ISI=y
+CONFIG_VIDEO_MT9V032=m
 CONFIG_VIDEO_OV2640=m
 CONFIG_VIDEO_OV5640=m
 CONFIG_VIDEO_OV7670=m
 CONFIG_VIDEO_OV7740=m
-CONFIG_VIDEO_MT9V032=m
 CONFIG_DRM=y
 CONFIG_DRM_ATMEL_HLCDC=y
 CONFIG_DRM_PANEL_SIMPLE=y
index 6330285..0384030 100644 (file)
@@ -1,5 +1,4 @@
 # CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_NO_HZ_IDLE=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -14,8 +13,6 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_IO_URING is not set
 CONFIG_KALLSYMS_ALL=y
 CONFIG_EMBEDDED=y
-# CONFIG_VM_EVENT_COUNTERS is not set
-CONFIG_SLAB=y
 CONFIG_ARCH_AT91=y
 CONFIG_SOC_SAMA7G5=y
 CONFIG_ATMEL_CLOCKSOURCE_TCB=y
@@ -43,8 +40,11 @@ CONFIG_MODULE_FORCE_UNLOAD=y
 CONFIG_PARTITION_ADVANCED=y
 # CONFIG_EFI_PARTITION is not set
 # CONFIG_COREDUMP is not set
+# CONFIG_SWAP is not set
+CONFIG_SLAB=y
 # CONFIG_COMPACTION is not set
 CONFIG_CMA=y
+# CONFIG_VM_EVENT_COUNTERS is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -229,9 +229,9 @@ CONFIG_CRC_ITU_T=y
 CONFIG_DMA_CMA=y
 CONFIG_CMA_SIZE_MBYTES=32
 CONFIG_CMA_ALIGNMENT=9
+# CONFIG_DEBUG_MISC is not set
 # CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
 CONFIG_DEBUG_FS=y
-# CONFIG_DEBUG_MISC is not set
 # CONFIG_SCHED_DEBUG is not set
 CONFIG_STACKTRACE=y
 # CONFIG_FTRACE is not set
index de33abd..42252e8 100644 (file)
@@ -1,20 +1,20 @@
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_MODULES=y
 CONFIG_ARCH_SA1100=y
 CONFIG_SA1100_SHANNON=y
-CONFIG_PCCARD=y
-CONFIG_PCMCIA_SA1100=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_CMDLINE="console=ttySA0,9600 console=tty1 root=/dev/mtdblock2 init=/linuxrc"
 CONFIG_FPE_NWFPE=y
+CONFIG_MODULES=y
+CONFIG_PARTITION_ADVANCED=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
 # CONFIG_IPV6 is not set
+CONFIG_PCCARD=y
+CONFIG_PCMCIA_SA1100=y
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
@@ -40,5 +40,4 @@ CONFIG_VFAT_FS=y
 CONFIG_JFFS2_FS=y
 CONFIG_MINIX_FS=y
 CONFIG_NFS_FS=y
-CONFIG_PARTITION_ADVANCED=y
 CONFIG_DEBUG_USER=y
index 362643c..a29bebb 100644 (file)
@@ -6,7 +6,6 @@ CONFIG_CGROUPS=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_PERF_EVENTS=y
-CONFIG_SLAB=y
 CONFIG_ARCH_RENESAS=y
 CONFIG_PL310_ERRATA_588369=y
 CONFIG_SMP=y
@@ -25,6 +24,7 @@ CONFIG_CPUFREQ_DT=y
 CONFIG_VFP=y
 CONFIG_NEON=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_SLAB=y
 CONFIG_CMA=y
 CONFIG_NET=y
 CONFIG_PACKET=y
@@ -106,6 +106,7 @@ CONFIG_WATCHDOG=y
 CONFIG_DA9063_WATCHDOG=y
 CONFIG_RENESAS_WDT=y
 CONFIG_RENESAS_RZAWDT=y
+CONFIG_RENESAS_RZN1WDT=y
 CONFIG_MFD_AS3711=y
 CONFIG_MFD_DA9063=y
 CONFIG_MFD_STMPE=y
@@ -177,6 +178,7 @@ CONFIG_RTC_DRV_S35390A=y
 CONFIG_RTC_DRV_RX8581=y
 CONFIG_RTC_DRV_DA9063=y
 CONFIG_RTC_DRV_SH=y
+CONFIG_RTC_DRV_RZN1=y
 CONFIG_DMADEVICES=y
 CONFIG_RCAR_DMAC=y
 CONFIG_RENESAS_USB_DMAC=y
index 28d99d8..cc45172 100644 (file)
@@ -1,20 +1,16 @@
 CONFIG_LOCALVERSION="oe1"
 CONFIG_SYSVIPC=y
+CONFIG_PREEMPT=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
-CONFIG_MODULES=y
 CONFIG_ARCH_SA1100=y
 CONFIG_SA1100_SIMPAD=y
-CONFIG_PCCARD=y
-CONFIG_PCMCIA_SA1100=y
-CONFIG_PREEMPT=y
-CONFIG_LEDS=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_CMDLINE="mtdparts=sa1100:512k(boot),1m(kernel),-(root) console=ttySA0 root=1f02 noinitrd mem=64M jffs2_orphaned_inodes=delete rootfstype=jffs2"
 CONFIG_FPE_NWFPE=y
+CONFIG_MODULES=y
 CONFIG_BINFMT_MISC=m
 CONFIG_PM=y
 CONFIG_NET=y
@@ -25,18 +21,14 @@ CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
 # CONFIG_IPV6 is not set
-CONFIG_IRDA=m
-CONFIG_IRLAN=m
-CONFIG_IRNET=m
-CONFIG_IRCOMM=m
-CONFIG_IRTTY_SIR=m
-CONFIG_SA1100_FIR=m
 CONFIG_BT=m
 CONFIG_BT_RFCOMM=m
 CONFIG_BT_RFCOMM_TTY=y
 CONFIG_BT_BNEP=m
 CONFIG_BT_BNEP_MC_FILTER=y
 CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_PCCARD=y
+CONFIG_PCMCIA_SA1100=y
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
@@ -56,19 +48,19 @@ CONFIG_DUMMY=y
 CONFIG_NET_ETHERNET=y
 CONFIG_NET_PCI=y
 CONFIG_NET_PCMCIA=y
-CONFIG_PCMCIA_3C589=m
 CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_3C589=m
 CONFIG_PCMCIA_PCNET=m
 CONFIG_PCMCIA_SMC91C92=m
 CONFIG_PCMCIA_XIRC2PS=m
 CONFIG_PPP=m
-CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_FILTER=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOE=m
 CONFIG_PPP_ASYNC=m
 CONFIG_PPP_SYNC_TTY=m
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPP_BSDCOMP=m
-CONFIG_PPPOE=m
 CONFIG_INPUT_MOUSEDEV_SCREEN_X=800
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=600
 CONFIG_INPUT_EVDEV=m
@@ -83,6 +75,8 @@ CONFIG_FB=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_LOGO=y
 CONFIG_SOUND=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
 CONFIG_EXT2_FS=m
 CONFIG_EXT3_FS=m
 CONFIG_REISERFS_FS=m
index 2d9404e..d91ae3f 100644 (file)
@@ -14,13 +14,10 @@ CONFIG_ARM_THUMBEE=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=2
 CONFIG_HIGHMEM=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_VFP=y
 CONFIG_NEON=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -52,7 +49,6 @@ CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_DENALI_DT=y
 CONFIG_MTD_SPI_NOR=y
 # CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
-CONFIG_SPI_CADENCE_QUADSPI=y
 CONFIG_OF_OVERLAY=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
@@ -64,6 +60,7 @@ CONFIG_EEPROM_AT24=y
 CONFIG_SCSI=y
 # CONFIG_SCSI_PROC_FS is not set
 CONFIG_BLK_DEV_SD=y
+# CONFIG_BLK_DEV_BSG is not set
 # CONFIG_SCSI_LOWLEVEL is not set
 CONFIG_NETDEVICES=y
 CONFIG_ALTERA_TSE=m
@@ -88,6 +85,7 @@ CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_DESIGNWARE_PLATFORM=y
 CONFIG_SPI=y
+CONFIG_SPI_CADENCE_QUADSPI=y
 CONFIG_SPI_DESIGNWARE=y
 CONFIG_SPI_DW_MMIO=y
 CONFIG_SPI_SPIDEV=y
@@ -154,7 +152,7 @@ CONFIG_NFSD_V4=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_PRINTK_TIME=y
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
 CONFIG_DETECT_HUNG_TASK=y
diff --git a/arch/arm/configs/sp7021_defconfig b/arch/arm/configs/sp7021_defconfig
new file mode 100644 (file)
index 0000000..703b9aa
--- /dev/null
@@ -0,0 +1,59 @@
+CONFIG_SYSVIPC=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_RD_GZIP is not set
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_LZ4 is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PERF_EVENTS=y
+CONFIG_SLAB=y
+CONFIG_ARCH_SUNPLUS=y
+# CONFIG_VDSO is not set
+CONFIG_SMP=y
+CONFIG_THUMB2_KERNEL=y
+CONFIG_FORCE_MAX_ZONEORDER=12
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_UEVENT_HELPER=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_INPUT_SPARSEKMAP=y
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_RESET_CONTROLLER=y
+CONFIG_EXT4_FS=y
+# CONFIG_DNOTIFY is not set
+CONFIG_FANOTIFY=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_IOCHARSET="utf8"
+CONFIG_EXFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_UTF8=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_USER=y
index 0655533..0227dd5 100644 (file)
@@ -1,18 +1,11 @@
 CONFIG_SYSVIPC=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_PARTITION_ADVANCED=y
 CONFIG_PLAT_SPEAR=y
 CONFIG_ARCH_SPEAR13XX=y
 CONFIG_MACH_SPEAR1310=y
 CONFIG_MACH_SPEAR1340=y
 # CONFIG_SWP_EMULATE is not set
-CONFIG_PCI=y
-CONFIG_PCI_MSI=y
-CONFIG_PCIE_SPEAR13XX=y
 CONFIG_SMP=y
 # CONFIG_SMP_ON_UP is not set
 # CONFIG_ARM_CPU_TOPOLOGY is not set
@@ -20,6 +13,10 @@ CONFIG_AEABI=y
 CONFIG_ARM_APPENDED_DTB=y
 CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_VFP=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
 CONFIG_BINFMT_MISC=y
 CONFIG_NET=y
 CONFIG_UNIX=y
@@ -28,6 +25,9 @@ CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
 CONFIG_NET_IPIP=y
+CONFIG_PCI=y
+CONFIG_PCI_MSI=y
+CONFIG_PCIE_SPEAR13XX=y
 CONFIG_MTD=y
 CONFIG_MTD_OF_PARTS=y
 CONFIG_MTD_BLOCK=y
@@ -97,8 +97,8 @@ CONFIG_ROOT_NFS=y
 CONFIG_NLS_DEFAULT="utf8"
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ASCII=m
+CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_SPINLOCK=y
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
index afca722..254d970 100644 (file)
@@ -1,16 +1,16 @@
 CONFIG_SYSVIPC=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_PARTITION_ADVANCED=y
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_PLAT_SPEAR=y
 CONFIG_ARCH_SPEAR3XX=y
 CONFIG_MACH_SPEAR300=y
 CONFIG_MACH_SPEAR310=y
 CONFIG_MACH_SPEAR320=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
 CONFIG_BINFMT_MISC=y
 CONFIG_NET=y
 CONFIG_MTD=y
@@ -77,8 +77,8 @@ CONFIG_JFFS2_FS=y
 CONFIG_NLS_DEFAULT="utf8"
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ASCII=m
+CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_SPINLOCK=y
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
index bc32c02..2809c4e 100644 (file)
@@ -1,13 +1,13 @@
 CONFIG_SYSVIPC=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_BLK_DEV_INITRD=y
+# CONFIG_ARCH_MULTI_V7 is not set
+CONFIG_PLAT_SPEAR=y
+CONFIG_ARCH_SPEAR6XX=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODVERSIONS=y
 CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ARCH_MULTI_V7 is not set
-CONFIG_PLAT_SPEAR=y
-CONFIG_ARCH_SPEAR6XX=y
 CONFIG_BINFMT_MISC=y
 CONFIG_NET=y
 CONFIG_MTD=y
@@ -66,8 +66,8 @@ CONFIG_JFFS2_FS=y
 CONFIG_NLS_DEFAULT="utf8"
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ASCII=m
+CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_SPINLOCK=y
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
index 43d079e..1284a1d 100644 (file)
@@ -1,27 +1,23 @@
 CONFIG_SYSVIPC=y
+CONFIG_PREEMPT=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
 CONFIG_PROFILING=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_PXA=y
 CONFIG_PXA_SHARPSL=y
 CONFIG_MACH_AKITA=y
 CONFIG_MACH_BORZOI=y
-CONFIG_PCCARD=y
-CONFIG_PCMCIA_PXA2XX=y
-CONFIG_PREEMPT=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="console=ttyS0,115200n8 console=tty1 noinitrd root=/dev/mtdblock2 rootfstype=jffs2   debug"
 CONFIG_FPE_NWFPE=y
 CONFIG_BINFMT_AOUT=m
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
 CONFIG_BINFMT_MISC=m
 CONFIG_PM=y
 CONFIG_NET=y
@@ -55,11 +51,6 @@ CONFIG_IP6_NF_MATCH_RT=m
 CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_MANGLE=m
 CONFIG_IP6_NF_RAW=m
-CONFIG_IRDA=m
-CONFIG_IRLAN=m
-CONFIG_IRNET=m
-CONFIG_IRCOMM=m
-CONFIG_PXA_FICP=m
 CONFIG_BT=m
 CONFIG_BT_RFCOMM=m
 CONFIG_BT_RFCOMM_TTY=y
@@ -78,6 +69,8 @@ CONFIG_BT_HCIBT3C=m
 CONFIG_BT_HCIBLUECARD=m
 CONFIG_BT_HCIBTUART=m
 CONFIG_BT_HCIVHCI=m
+CONFIG_PCCARD=y
+CONFIG_PCMCIA_PXA2XX=y
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
@@ -91,10 +84,15 @@ CONFIG_CHR_DEV_ST=m
 CONFIG_CHR_DEV_OSST=m
 CONFIG_BLK_DEV_SR=m
 CONFIG_CHR_DEV_SG=m
+# CONFIG_BLK_DEV_BSG is not set
 CONFIG_ATA=y
 CONFIG_PATA_PCMCIA=y
 CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
+CONFIG_PCMCIA_PCNET=m
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_ASYNC=m
 CONFIG_USB_CATC=m
 CONFIG_USB_KAWETH=m
 CONFIG_USB_PEGASUS=m
@@ -102,10 +100,6 @@ CONFIG_USB_RTL8150=m
 CONFIG_USB_USBNET=m
 # CONFIG_USB_NET_CDC_SUBSET is not set
 CONFIG_NET_PCMCIA=y
-CONFIG_PCMCIA_PCNET=m
-CONFIG_PPP=m
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_BSDCOMP=m
 CONFIG_INPUT_FF_MEMLESS=m
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=y
@@ -116,11 +110,11 @@ CONFIG_TOUCHSCREEN_ADS7846=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=m
 # CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_8250=m
 CONFIG_SERIAL_8250_CS=m
 CONFIG_SERIAL_PXA=y
 CONFIG_SERIAL_PXA_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
 CONFIG_SPI=y
 CONFIG_SPI_PXA2XX=y
 CONFIG_FB=y
@@ -131,11 +125,6 @@ CONFIG_BACKLIGHT_CLASS_DEVICE=y
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
-CONFIG_FONTS=y
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
-CONFIG_USB_KBD=m
-CONFIG_USB_MOUSE=m
 CONFIG_HID_A4TECH=m
 CONFIG_HID_APPLE=m
 CONFIG_HID_BELKIN=m
@@ -152,6 +141,8 @@ CONFIG_HID_PETALYNX=m
 CONFIG_HID_SAMSUNG=m
 CONFIG_HID_SONY=m
 CONFIG_HID_SUNPLUS=m
+CONFIG_USB_KBD=m
+CONFIG_USB_MOUSE=m
 CONFIG_USB=m
 CONFIG_USB_MON=m
 CONFIG_USB_OHCI_HCD=m
@@ -220,16 +211,12 @@ CONFIG_NFS_V3=y
 CONFIG_NFS_V4=y
 CONFIG_SMB_FS=m
 CONFIG_SMB_NLS_DEFAULT=y
-CONFIG_PARTITION_ADVANCED=y
+CONFIG_NFS_V4=m
 CONFIG_NLS_DEFAULT="cp437"
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_NLS_UTF8=y
-CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_PREEMPT is not set
-# CONFIG_FTRACE is not set
-CONFIG_DEBUG_LL=y
 CONFIG_CRYPTO_NULL=m
 CONFIG_CRYPTO_TEST=m
 CONFIG_CRYPTO_ECB=m
@@ -252,3 +239,9 @@ CONFIG_CRYPTO_TWOFISH=m
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRC_CCITT=y
 CONFIG_LIBCRC32C=m
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_PREEMPT is not set
+# CONFIG_FTRACE is not set
index 71d6bfc..1f5446c 100644 (file)
@@ -1,5 +1,6 @@
 CONFIG_NO_HZ_IDLE=y
 CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
 CONFIG_LOG_BUF_SHIFT=16
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -11,8 +12,6 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
 CONFIG_EMBEDDED=y
-# CONFIG_VM_EVENT_COUNTERS is not set
-# CONFIG_SLUB_DEBUG is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_MMU is not set
 CONFIG_ARCH_STM32=y
@@ -21,14 +20,12 @@ CONFIG_SET_MEM_PARAM=y
 CONFIG_DRAM_BASE=0x90000000
 CONFIG_FLASH_MEM_BASE=0x08000000
 CONFIG_FLASH_SIZE=0x00200000
-CONFIG_PREEMPT=y
 # CONFIG_ATAGS is not set
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_XIP_KERNEL=y
 CONFIG_XIP_PHYS_ADDR=0x08008000
 CONFIG_BINFMT_FLAT=y
 # CONFIG_COREDUMP is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_FW_LOADER is not set
@@ -38,9 +35,9 @@ CONFIG_KEYBOARD_GPIO=y
 # CONFIG_VT is not set
 # CONFIG_UNIX98_PTYS is not set
 # CONFIG_LEGACY_PTYS is not set
-CONFIG_SERIAL_NONSTANDARD=y
 CONFIG_SERIAL_STM32=y
 CONFIG_SERIAL_STM32_CONSOLE=y
+CONFIG_SERIAL_NONSTANDARD=y
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
@@ -74,12 +71,13 @@ CONFIG_EXT3_FS=y
 # CONFIG_DNOTIFY is not set
 # CONFIG_INOTIFY_USER is not set
 CONFIG_NLS=y
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC7=y
 CONFIG_PRINTK_TIME=y
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 # CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
 CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SLUB_DEBUG is not set
 # CONFIG_SCHED_DEBUG is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
 CONFIG_CRYPTO=y
-CONFIG_CRC_ITU_T=y
-CONFIG_CRC7=y
index 8ba7935..3d14827 100644 (file)
@@ -97,9 +97,9 @@ CONFIG_IR_SUNXI=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_MEDIA_PLATFORM_SUPPORT=y
 CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_V4L_MEM2MEM_DRIVERS=y
 CONFIG_VIDEO_SUN4I_CSI=y
 CONFIG_VIDEO_SUN6I_CSI=y
-CONFIG_V4L_MEM2MEM_DRIVERS=y
 CONFIG_VIDEO_SUN8I_DEINTERLACE=y
 CONFIG_VIDEO_SUN8I_ROTATE=y
 CONFIG_DRM=y
index 46cbae6..3b29ae1 100644 (file)
@@ -1,26 +1,25 @@
 # CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_SYSFS_DEPRECATED=y
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EXPERT=y
-# CONFIG_KALLSYMS is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_SHMEM is not set
-CONFIG_SLOB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
+# CONFIG_KALLSYMS is not set
 CONFIG_ARCH_MULTI_V4T=y
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_S3C24XX=y
 CONFIG_MACH_TCT_HAMMER=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_CMDLINE="mem=64M root=/dev/ram0 init=/linuxrc rw"
 CONFIG_FPE_NWFPE=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_SWAP is not set
+CONFIG_SLOB=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -55,5 +54,5 @@ CONFIG_JFFS2_FS=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 # CONFIG_ENABLE_MUST_CHECK is not set
-CONFIG_DEBUG_LL=y
 CONFIG_CRC_CCITT=y
+CONFIG_DEBUG_LL=y
index c209722..71400af 100644 (file)
@@ -16,7 +16,6 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_ELF_CORE is not set
 CONFIG_EMBEDDED=y
 CONFIG_PERF_EVENTS=y
-CONFIG_SLAB=y
 CONFIG_ARCH_TEGRA=y
 CONFIG_SMP=y
 CONFIG_HIGHMEM=y
@@ -29,12 +28,11 @@ CONFIG_CPU_IDLE=y
 CONFIG_ARM_TEGRA_CPUIDLE=y
 CONFIG_VFP=y
 CONFIG_NEON=y
-CONFIG_TRUSTED_FOUNDATIONS=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 CONFIG_PARTITION_ADVANCED=y
+CONFIG_SLAB=y
 CONFIG_CMA=y
 CONFIG_NET=y
 CONFIG_PACKET=y
@@ -80,6 +78,7 @@ CONFIG_PCI_TEGRA=y
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_TEGRA_GMI=y
+CONFIG_TRUSTED_FOUNDATIONS=y
 CONFIG_MTD=y
 CONFIG_MTD_SPI_NOR=y
 CONFIG_BLK_DEV_LOOP=y
@@ -91,6 +90,7 @@ CONFIG_ISL29003=y
 CONFIG_EEPROM_AT24=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_BSG is not set
 # CONFIG_SCSI_LOWLEVEL is not set
 CONFIG_ATA=y
 CONFIG_SATA_AHCI=y
@@ -114,9 +114,9 @@ CONFIG_KEYBOARD_GPIO=y
 CONFIG_KEYBOARD_TEGRA=y
 CONFIG_KEYBOARD_CROS_EC=y
 CONFIG_KEYBOARD_CAP11XX=y
+CONFIG_MOUSE_PS2_ELANTECH=y
 CONFIG_MOUSE_ELAN_I2C=m
 CONFIG_MOUSE_ELAN_I2C_SMBUS=y
-CONFIG_MOUSE_PS2_ELANTECH=y
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ATMEL_MXT=y
 CONFIG_TOUCHSCREEN_ELAN=y
@@ -139,6 +139,7 @@ CONFIG_I2C_MUX_GPIO=y
 CONFIG_I2C_MUX_PCA954x=y
 CONFIG_I2C_MUX_PINCTRL=y
 CONFIG_I2C_TEGRA=y
+CONFIG_I2C_CROS_EC_TUNNEL=m
 CONFIG_SPI=y
 CONFIG_SPI_TEGRA114=y
 CONFIG_SPI_TEGRA20_SFLASH=y
@@ -158,9 +159,9 @@ CONFIG_POWER_RESET_AS3722=y
 CONFIG_POWER_RESET_GPIO=y
 CONFIG_POWER_RESET_GPIO_RESTART=y
 CONFIG_BATTERY_SBS=y
-CONFIG_CHARGER_BQ24735=y
 CONFIG_BATTERY_BQ27XXX=y
 CONFIG_CHARGER_GPIO=y
+CONFIG_CHARGER_BQ24735=y
 CONFIG_CHARGER_SMB347=y
 CONFIG_CHARGER_TPS65090=y
 CONFIG_BATTERY_ACER_A500=y
@@ -198,8 +199,10 @@ CONFIG_REGULATOR_TPS6586X=y
 CONFIG_REGULATOR_TPS65910=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_MEDIA_USB_SUPPORT=y
-CONFIG_USB_VIDEO_CLASS=y
 CONFIG_USB_GSPCA=y
+CONFIG_USB_VIDEO_CLASS=y
+CONFIG_V4L_MEM2MEM_DRIVERS=y
+CONFIG_VIDEO_TEGRA_VDE=y
 CONFIG_DRM=y
 CONFIG_DRM_NOUVEAU=m
 CONFIG_DRM_TEGRA=y
@@ -286,13 +289,10 @@ CONFIG_SERIO_NVEC_PS2=y
 CONFIG_NVEC_POWER=y
 CONFIG_NVEC_PAZ00=y
 CONFIG_STAGING_MEDIA=y
-CONFIG_V4L_MEM2MEM_DRIVERS=y
-CONFIG_VIDEO_TEGRA_VDE=y
 CONFIG_CHROME_PLATFORMS=y
 CONFIG_CROS_EC=y
 CONFIG_CROS_EC_I2C=m
 CONFIG_CROS_EC_SPI=m
-CONFIG_I2C_CROS_EC_TUNNEL=m
 CONFIG_TEGRA_IOMMU_GART=y
 CONFIG_TEGRA_IOMMU_SMMU=y
 CONFIG_ARCH_TEGRA_2x_SOC=y
@@ -343,7 +343,7 @@ CONFIG_CRYPTO_TWOFISH=y
 CONFIG_DMA_CMA=y
 CONFIG_CMA_SIZE_MBYTES=64
 CONFIG_PRINTK_TIME=y
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_SLAB=y
 CONFIG_DEBUG_VM=y
index baeba46..009abe1 100644 (file)
@@ -1,5 +1,6 @@
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_PREEMPT=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_BSD_PROCESS_ACCT_V3=y
 CONFIG_IKCONFIG=y
@@ -8,25 +9,24 @@ CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EXPERT=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_PXA=y
 CONFIG_TRIZEPS_PXA=y
 CONFIG_MACH_TRIZEPS4=y
-CONFIG_PCCARD=y
-# CONFIG_PCMCIA_LOAD_CIS is not set
-CONFIG_PCMCIA_PXA2XX=y
-CONFIG_PREEMPT=y
 CONFIG_AEABI=y
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_CMDLINE="root=fe01 console=ttyS0,38400n8 loglevel=5"
 CONFIG_FPE_NWFPE=y
 CONFIG_FPE_NWFPE_XP=y
 CONFIG_PM=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_LDM_PARTITION=y
+CONFIG_SLAB=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -39,14 +39,6 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_IPV6 is not set
 CONFIG_NETFILTER=y
 CONFIG_VLAN_8021Q=m
-CONFIG_IRDA=m
-CONFIG_IRLAN=m
-CONFIG_IRNET=m
-CONFIG_IRCOMM=m
-CONFIG_IRDA_ULTRA=y
-CONFIG_IRDA_CACHE_LAST_LSAP=y
-CONFIG_IRDA_FAST_RR=y
-CONFIG_IRTTY_SIR=m
 CONFIG_BT=m
 CONFIG_BT_RFCOMM=m
 CONFIG_BT_RFCOMM_TTY=y
@@ -55,6 +47,9 @@ CONFIG_BT_BNEP_MC_FILTER=y
 CONFIG_BT_BNEP_PROTO_FILTER=y
 CONFIG_BT_HIDP=m
 CONFIG_CFG80211=y
+CONFIG_PCCARD=y
+# CONFIG_PCMCIA_LOAD_CIS is not set
+CONFIG_PCMCIA_PXA2XX=y
 CONFIG_CONNECTOR=y
 CONFIG_MTD=y
 CONFIG_MTD_REDBOOT_PARTS=y
@@ -77,13 +72,13 @@ CONFIG_MTD_DOC2001PLUS=y
 CONFIG_MTD_DOCPROBE_ADVANCED=y
 CONFIG_MTD_DOCPROBE_ADDRESS=0x4000000
 CONFIG_MTD_DOCPROBE_HIGH=y
+CONFIG_MTD_ONENAND=y
 CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_DISKONCHIP=y
 CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED=y
 CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0x4000000
 CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH=y
 CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE=y
-CONFIG_MTD_ONENAND=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=y
@@ -97,9 +92,17 @@ CONFIG_ATA=m
 CONFIG_PATA_PCMCIA=m
 CONFIG_PATA_PLATFORM=m
 CONFIG_NETDEVICES=y
-CONFIG_PHYLIB=y
 CONFIG_NET_ETHERNET=y
 CONFIG_DM9000=y
+CONFIG_PHYLIB=y
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
 CONFIG_HOSTAP=y
 CONFIG_HOSTAP_FIRMWARE=y
 CONFIG_HOSTAP_FIRMWARE_NVRAM=y
@@ -107,14 +110,6 @@ CONFIG_HOSTAP_CS=y
 CONFIG_HERMES=y
 CONFIG_PCMCIA_HERMES=y
 CONFIG_PCMCIA_SPECTRUM=y
-CONFIG_PPP=m
-CONFIG_PPP_MULTILINK=y
-CONFIG_PPP_FILTER=y
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_SYNC_TTY=m
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPP_BSDCOMP=m
-CONFIG_PPP_MPPE=m
 CONFIG_INPUT_MOUSEDEV_SCREEN_X=640
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480
 CONFIG_INPUT_EVDEV=y
@@ -142,17 +137,14 @@ CONFIG_BACKLIGHT_CLASS_DEVICE=y
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
-CONFIG_FONTS=y
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
 CONFIG_LOGO=y
 CONFIG_SOUND=y
 CONFIG_SND=y
-CONFIG_SND_SEQUENCER=y
 CONFIG_SND_MIXER_OSS=y
 CONFIG_SND_PCM_OSS=y
 CONFIG_SND_VERBOSE_PRINTK=y
 CONFIG_SND_DEBUG=y
+CONFIG_SND_SEQUENCER=y
 CONFIG_SND_PXA2XX_AC97=y
 CONFIG_SND_USB_AUDIO=m
 # CONFIG_USB_HID is not set
@@ -191,8 +183,6 @@ CONFIG_NFSD=y
 CONFIG_NFSD_V4=y
 CONFIG_SMB_FS=m
 CONFIG_CIFS=m
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_LDM_PARTITION=y
 CONFIG_NLS_DEFAULT="iso8859-15"
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_CODEPAGE_850=y
@@ -200,9 +190,6 @@ CONFIG_NLS_ASCII=y
 CONFIG_NLS_ISO8859_1=m
 CONFIG_NLS_ISO8859_15=m
 CONFIG_NLS_UTF8=m
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_USER=y
 CONFIG_KEYS=y
 CONFIG_SECURITY=y
 CONFIG_CRYPTO_PCBC=m
@@ -212,3 +199,9 @@ CONFIG_CRYPTO_DEFLATE=m
 CONFIG_CRC_CCITT=y
 CONFIG_CRC16=y
 CONFIG_LIBCRC32C=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_USER=y
index a352207..3bdc217 100644 (file)
@@ -1,4 +1,3 @@
-# CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_NO_HZ_IDLE=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -21,6 +20,7 @@ CONFIG_NEON=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_PARTITION_ADVANCED=y
+# CONFIG_SWAP is not set
 CONFIG_CMA=y
 CONFIG_NET=y
 CONFIG_PACKET=y
index c2d79a6..67e3f91 100644 (file)
@@ -4,7 +4,6 @@ CONFIG_NO_HZ_IDLE=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_SLAB=y
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_VERSATILE=y
 CONFIG_AEABI=y
@@ -15,6 +14,7 @@ CONFIG_VFP=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_PARTITION_ADVANCED=y
+CONFIG_SLAB=y
 CONFIG_CMA=y
 CONFIG_NET=y
 CONFIG_PACKET=y
@@ -88,8 +88,8 @@ CONFIG_ROOT_NFS=y
 CONFIG_NFSD=y
 CONFIG_NLS_CODEPAGE_850=m
 CONFIG_NLS_ISO8859_1=m
+CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_LL=y
index 9479877..4e3a013 100644 (file)
@@ -20,15 +20,12 @@ CONFIG_MCPM=y
 CONFIG_VMSPLIT_2G=y
 CONFIG_NR_CPUS=8
 CONFIG_ARM_PSCI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="console=ttyAMA0"
 CONFIG_CPU_IDLE=y
 CONFIG_VFP=y
 CONFIG_NEON=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_CMA=y
 CONFIG_NET=y
@@ -56,6 +53,7 @@ CONFIG_MTD_UBI=y
 CONFIG_VIRTIO_BLK=y
 # CONFIG_SCSI_PROC_FS is not set
 CONFIG_BLK_DEV_SD=y
+# CONFIG_BLK_DEV_BSG is not set
 CONFIG_SCSI_VIRTIO=y
 CONFIG_ATA=y
 CONFIG_NETDEVICES=y
@@ -135,9 +133,9 @@ CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 # CONFIG_CRYPTO_HW is not set
 CONFIG_DMA_CMA=y
-CONFIG_DEBUG_INFO=y
-CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
 CONFIG_DETECT_HUNG_TASK=y
 # CONFIG_SCHED_DEBUG is not set
 CONFIG_DEBUG_USER=y
index 70fdbfd..2e47cc5 100644 (file)
@@ -16,9 +16,9 @@ CONFIG_FLASH_SIZE=0x01000000
 CONFIG_CMDLINE="console=/dev/ttyLP2"
 CONFIG_XIP_KERNEL=y
 CONFIG_XIP_PHYS_ADDR=0x0f000080
+# CONFIG_SUSPEND is not set
 CONFIG_BINFMT_FLAT=y
 CONFIG_BINFMT_ZFLAT=y
-# CONFIG_SUSPEND is not set
 # CONFIG_UEVENT_HELPER is not set
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
index 7c10297..02f9849 100644 (file)
@@ -1,23 +1,15 @@
-# CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=13
 CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_EXPERT=y
 # CONFIG_ELF_CORE is not set
 # CONFIG_SHMEM is not set
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_PXA=y
 CONFIG_ARCH_VIPER=y
 CONFIG_IWMMXT=y
-CONFIG_PCCARD=m
-CONFIG_PCMCIA_PXA2XX=m
 CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_CMDLINE="root=31:02 rootfstype=jffs2 ro console=ttyS0,115200"
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=m
@@ -26,6 +18,11 @@ CONFIG_CPU_FREQ_GOV_ONDEMAND=m
 CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
 CONFIG_FPE_FASTFPE=y
 CONFIG_PM=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_SWAP is not set
+CONFIG_SLAB=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -41,6 +38,8 @@ CONFIG_BT_BNEP=m
 CONFIG_BT_HCIUART=m
 CONFIG_BT_HCIUART_H4=y
 CONFIG_BT_HCIUART_BCSP=y
+CONFIG_PCCARD=m
+CONFIG_PCMCIA_PXA2XX=m
 CONFIG_FW_LOADER=m
 CONFIG_MTD=y
 CONFIG_MTD_REDBOOT_PARTS=y
@@ -61,20 +60,21 @@ CONFIG_MTD_PXA2XX=y
 CONFIG_BLK_DEV_LOOP=m
 # CONFIG_SCSI_PROC_FS is not set
 CONFIG_BLK_DEV_SD=m
+# CONFIG_BLK_DEV_BSG is not set
 CONFIG_ATA=m
 # CONFIG_SATA_PMP is not set
 CONFIG_PATA_PCMCIA=m
 CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
 CONFIG_SMC91X=y
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_ASYNC=m
 CONFIG_USB_PEGASUS=m
 CONFIG_USB_USBNET=m
 # CONFIG_USB_NET_CDC_SUBSET is not set
 CONFIG_NET_PCMCIA=y
-CONFIG_PPP=m
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPP_BSDCOMP=m
 CONFIG_INPUT_MOUSEDEV=m
 # CONFIG_INPUT_MOUSEDEV_PSAUX is not set
 CONFIG_INPUT_EVDEV=m
@@ -94,12 +94,12 @@ CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=m
 # CONFIG_CONSOLE_TRANSLATIONS is not set
 # CONFIG_VT_CONSOLE is not set
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_8250=m
 CONFIG_SERIAL_8250_NR_UARTS=5
 CONFIG_SERIAL_8250_RUNTIME_UARTS=5
 CONFIG_SERIAL_PXA=y
 CONFIG_SERIAL_PXA_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 # CONFIG_I2C_HELPER_AUTO is not set
@@ -146,16 +146,15 @@ CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
 CONFIG_NFSD=m
-CONFIG_PARTITION_ADVANCED=y
 CONFIG_NLS_CODEPAGE_437=m
 CONFIG_NLS_CODEPAGE_850=m
 CONFIG_NLS_ISO8859_1=m
 CONFIG_NLS_ISO8859_15=m
 CONFIG_NLS_UTF8=m
+CONFIG_CRC_T10DIF=m
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_MUTEXES=y
 # CONFIG_FTRACE is not set
 CONFIG_CRYPTO_ECB=m
 CONFIG_CRYPTO_ARC4=m
-CONFIG_CRC_T10DIF=m
index 9b85326..cb8d38e 100644 (file)
@@ -50,8 +50,8 @@ CONFIG_I2C_WMT=y
 CONFIG_PINCTRL_SINGLE=y
 CONFIG_PINCTRL_WM8750=y
 CONFIG_GPIO_GENERIC_PLATFORM=y
-CONFIG_POWER_SUPPLY=y
 CONFIG_POWER_RESET=y
+CONFIG_POWER_SUPPLY=y
 CONFIG_MFD_SYSCON=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
index 3752672..0453948 100644 (file)
@@ -1,6 +1,8 @@
 CONFIG_LOCALVERSION=".xcep-itech"
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
@@ -10,26 +12,23 @@ CONFIG_BLK_DEV_INITRD=y
 CONFIG_EXPERT=y
 # CONFIG_UID16 is not set
 # CONFIG_SHMEM is not set
-# CONFIG_VM_EVENT_COUNTERS is not set
-# CONFIG_COMPAT_BRK is not set
-CONFIG_SLOB=y
-CONFIG_KPROBES=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-# CONFIG_BLOCK is not set
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_PXA=y
 CONFIG_MACH_XCEP=y
 CONFIG_IWMMXT=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
 CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_CMDLINE="root=mtd4 rootfstype=jffs2 ro console=ttyS0,115200"
 CONFIG_FPE_NWFPE=y
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+# CONFIG_BLOCK is not set
+CONFIG_SLOB=y
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
 CONFIG_NET=y
 CONFIG_PACKET=m
 CONFIG_UNIX=y
@@ -54,9 +53,9 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_PXA=y
 CONFIG_SERIAL_PXA_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=m
 CONFIG_I2C_CHARDEV=m
@@ -78,13 +77,13 @@ CONFIG_NFS_V3=y
 CONFIG_NLS=m
 CONFIG_NLS_DEFAULT="utf8"
 CONFIG_NLS_UTF8=m
+# CONFIG_CRYPTO_HW is not set
+CONFIG_LIBCRC32C=m
 CONFIG_PRINTK_TIME=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
 CONFIG_STRIP_ASM_SYMS=y
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_SCHED_DEBUG is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
 # CONFIG_FTRACE is not set
 # CONFIG_ARM_UNWIND is not set
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
-# CONFIG_CRYPTO_HW is not set
-CONFIG_LIBCRC32C=m
index 03a12fb..c453531 100644 (file)
@@ -1,17 +1,11 @@
 CONFIG_SYSVIPC=y
 CONFIG_TINY_RCU=y
 CONFIG_LOG_BUF_SHIFT=13
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
 # CONFIG_ARCH_MULTI_V7 is not set
 CONFIG_ARCH_PXA=y
 CONFIG_MACH_ARCOM_ZEUS=y
-CONFIG_PCCARD=m
-CONFIG_PCMCIA_PXA2XX=m
 CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_UNUSED_BOARD_FILES=y
 CONFIG_CMDLINE="root=31:02 rootfstype=jffs2 ro console=ttyS0,115200"
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=m
@@ -21,6 +15,9 @@ CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
 CONFIG_FPE_NWFPE=y
 CONFIG_PM=y
 CONFIG_APM_EMULATION=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -39,6 +36,8 @@ CONFIG_BT_HCIUART_BCSP=y
 CONFIG_CFG80211=m
 CONFIG_LIB80211=m
 CONFIG_MAC80211=m
+CONFIG_PCCARD=m
+CONFIG_PCMCIA_PXA2XX=m
 CONFIG_MTD=y
 CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_REDBOOT_PARTS_READONLY=y
@@ -59,21 +58,22 @@ CONFIG_BLK_DEV_LOOP=m
 CONFIG_EEPROM_AT24=m
 # CONFIG_SCSI_PROC_FS is not set
 CONFIG_BLK_DEV_SD=m
+# CONFIG_BLK_DEV_BSG is not set
 CONFIG_ATA=m
 # CONFIG_SATA_PMP is not set
 CONFIG_PATA_PCMCIA=m
 CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
 CONFIG_DM9000=y
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_ASYNC=m
 CONFIG_HERMES=m
 CONFIG_PCMCIA_HERMES=m
 CONFIG_RT2X00=m
 CONFIG_RT73USB=m
 CONFIG_NET_PCMCIA=y
-CONFIG_PPP=m
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPP_BSDCOMP=m
 # CONFIG_INPUT_MOUSEDEV_PSAUX is not set
 CONFIG_INPUT_EVDEV=m
 # CONFIG_INPUT_KEYBOARD is not set
@@ -90,11 +90,11 @@ CONFIG_TOUCHSCREEN_TOUCHWIN=m
 CONFIG_TOUCHSCREEN_TOUCHIT213=m
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=m
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=7
 CONFIG_SERIAL_8250_RUNTIME_UARTS=7
-# CONFIG_LEGACY_PTYS is not set
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 # CONFIG_I2C_HELPER_AUTO is not set
@@ -161,14 +161,13 @@ CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
 CONFIG_NFSD=m
-CONFIG_PARTITION_ADVANCED=y
 CONFIG_NLS_CODEPAGE_437=m
 CONFIG_NLS_CODEPAGE_850=m
 CONFIG_NLS_ISO8859_1=m
 CONFIG_NLS_ISO8859_15=m
 CONFIG_NLS_UTF8=m
-CONFIG_MAGIC_SYSRQ=y
+CONFIG_CRC_T10DIF=m
 CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_MUTEXES=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
-CONFIG_CRC_T10DIF=m
index e4dba54..149a5bd 100644 (file)
@@ -63,7 +63,7 @@ config CRYPTO_SHA512_ARM
          using optimized ARM assembler and NEON, when available.
 
 config CRYPTO_BLAKE2S_ARM
-       tristate "BLAKE2s digest algorithm (ARM)"
+       bool "BLAKE2s digest algorithm (ARM)"
        select CRYPTO_ARCH_HAVE_LIB_BLAKE2S
        help
          BLAKE2s digest algorithm optimized with ARM scalar instructions.  This
index 0274f81..971e745 100644 (file)
@@ -9,8 +9,7 @@ obj-$(CONFIG_CRYPTO_SHA1_ARM) += sha1-arm.o
 obj-$(CONFIG_CRYPTO_SHA1_ARM_NEON) += sha1-arm-neon.o
 obj-$(CONFIG_CRYPTO_SHA256_ARM) += sha256-arm.o
 obj-$(CONFIG_CRYPTO_SHA512_ARM) += sha512-arm.o
-obj-$(CONFIG_CRYPTO_BLAKE2S_ARM) += blake2s-arm.o
-obj-$(if $(CONFIG_CRYPTO_BLAKE2S_ARM),y) += libblake2s-arm.o
+obj-$(CONFIG_CRYPTO_BLAKE2S_ARM) += libblake2s-arm.o
 obj-$(CONFIG_CRYPTO_BLAKE2B_NEON) += blake2b-neon.o
 obj-$(CONFIG_CRYPTO_CHACHA20_NEON) += chacha-neon.o
 obj-$(CONFIG_CRYPTO_POLY1305_ARM) += poly1305-arm.o
@@ -32,7 +31,6 @@ sha256-arm-neon-$(CONFIG_KERNEL_MODE_NEON) := sha256_neon_glue.o
 sha256-arm-y   := sha256-core.o sha256_glue.o $(sha256-arm-neon-y)
 sha512-arm-neon-$(CONFIG_KERNEL_MODE_NEON) := sha512-neon-glue.o
 sha512-arm-y   := sha512-core.o sha512-glue.o $(sha512-arm-neon-y)
-blake2s-arm-y   := blake2s-shash.o
 libblake2s-arm-y:= blake2s-core.o blake2s-glue.o
 blake2b-neon-y  := blake2b-neon-core.o blake2b-neon-glue.o
 sha1-arm-ce-y  := sha1-ce-core.o sha1-ce-glue.o
diff --git a/arch/arm/crypto/blake2s-shash.c b/arch/arm/crypto/blake2s-shash.c
deleted file mode 100644 (file)
index 763c73b..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * BLAKE2s digest algorithm, ARM scalar implementation
- *
- * Copyright 2020 Google LLC
- */
-
-#include <crypto/internal/blake2s.h>
-#include <crypto/internal/hash.h>
-
-#include <linux/module.h>
-
-static int crypto_blake2s_update_arm(struct shash_desc *desc,
-                                    const u8 *in, unsigned int inlen)
-{
-       return crypto_blake2s_update(desc, in, inlen, false);
-}
-
-static int crypto_blake2s_final_arm(struct shash_desc *desc, u8 *out)
-{
-       return crypto_blake2s_final(desc, out, false);
-}
-
-#define BLAKE2S_ALG(name, driver_name, digest_size)                    \
-       {                                                               \
-               .base.cra_name          = name,                         \
-               .base.cra_driver_name   = driver_name,                  \
-               .base.cra_priority      = 200,                          \
-               .base.cra_flags         = CRYPTO_ALG_OPTIONAL_KEY,      \
-               .base.cra_blocksize     = BLAKE2S_BLOCK_SIZE,           \
-               .base.cra_ctxsize       = sizeof(struct blake2s_tfm_ctx), \
-               .base.cra_module        = THIS_MODULE,                  \
-               .digestsize             = digest_size,                  \
-               .setkey                 = crypto_blake2s_setkey,        \
-               .init                   = crypto_blake2s_init,          \
-               .update                 = crypto_blake2s_update_arm,    \
-               .final                  = crypto_blake2s_final_arm,     \
-               .descsize               = sizeof(struct blake2s_state), \
-       }
-
-static struct shash_alg blake2s_arm_algs[] = {
-       BLAKE2S_ALG("blake2s-128", "blake2s-128-arm", BLAKE2S_128_HASH_SIZE),
-       BLAKE2S_ALG("blake2s-160", "blake2s-160-arm", BLAKE2S_160_HASH_SIZE),
-       BLAKE2S_ALG("blake2s-224", "blake2s-224-arm", BLAKE2S_224_HASH_SIZE),
-       BLAKE2S_ALG("blake2s-256", "blake2s-256-arm", BLAKE2S_256_HASH_SIZE),
-};
-
-static int __init blake2s_arm_mod_init(void)
-{
-       return IS_REACHABLE(CONFIG_CRYPTO_HASH) ?
-               crypto_register_shashes(blake2s_arm_algs,
-                                       ARRAY_SIZE(blake2s_arm_algs)) : 0;
-}
-
-static void __exit blake2s_arm_mod_exit(void)
-{
-       if (IS_REACHABLE(CONFIG_CRYPTO_HASH))
-               crypto_unregister_shashes(blake2s_arm_algs,
-                                         ARRAY_SIZE(blake2s_arm_algs));
-}
-
-module_init(blake2s_arm_mod_init);
-module_exit(blake2s_arm_mod_exit);
-
-MODULE_DESCRIPTION("BLAKE2s digest algorithm, ARM scalar implementation");
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Eric Biggers <ebiggers@google.com>");
-MODULE_ALIAS_CRYPTO("blake2s-128");
-MODULE_ALIAS_CRYPTO("blake2s-128-arm");
-MODULE_ALIAS_CRYPTO("blake2s-160");
-MODULE_ALIAS_CRYPTO("blake2s-160-arm");
-MODULE_ALIAS_CRYPTO("blake2s-224");
-MODULE_ALIAS_CRYPTO("blake2s-224-arm");
-MODULE_ALIAS_CRYPTO("blake2s-256");
-MODULE_ALIAS_CRYPTO("blake2s-256-arm");
index a8e84ca..cc4714e 100644 (file)
@@ -7,4 +7,6 @@ static inline bool __init smccc_probe_trng(void)
        return false;
 }
 
+#include <asm-generic/archrandom.h>
+
 #endif /* _ASM_ARCHRANDOM_H */
index a81dda6..45180a2 100644 (file)
@@ -10,7 +10,7 @@
 #else
 #define MAX_DMA_ADDRESS        ({ \
        extern phys_addr_t arm_dma_zone_size; \
-       arm_dma_zone_size && arm_dma_zone_size < (0x10000000 - PAGE_OFFSET) ? \
+       arm_dma_zone_size && arm_dma_zone_size < (0x100000000ULL - PAGE_OFFSET) ? \
                (PAGE_OFFSET + arm_dma_zone_size) : 0xffffffffUL; })
 #endif
 
index f1d0a78..41536fe 100644 (file)
@@ -112,19 +112,6 @@ static __always_inline void set_domain(unsigned int val)
 }
 #endif
 
-#ifdef CONFIG_CPU_USE_DOMAINS
-#define modify_domain(dom,type)                                        \
-       do {                                                    \
-               unsigned int domain = get_domain();             \
-               domain &= ~domain_mask(dom);                    \
-               domain = domain | domain_val(dom, type);        \
-               set_domain(domain);                             \
-       } while (0)
-
-#else
-static inline void modify_domain(unsigned dom, unsigned type)  { }
-#endif
-
 /*
  * Generate the T (user) versions of the LDR/STR and related
  * instructions (inline assembly)
index eba7cbc..7fcdc78 100644 (file)
@@ -139,11 +139,9 @@ extern void __iomem *__arm_ioremap_caller(phys_addr_t, size_t, unsigned int,
 extern void __iomem *__arm_ioremap_pfn(unsigned long, unsigned long, size_t, unsigned int);
 extern void __iomem *__arm_ioremap_exec(phys_addr_t, size_t, bool cached);
 void __arm_iomem_set_ro(void __iomem *ptr, size_t size);
-extern void __iounmap(volatile void __iomem *addr);
 
 extern void __iomem * (*arch_ioremap_caller)(phys_addr_t, size_t,
        unsigned int, void *);
-extern void (*arch_iounmap)(volatile void __iomem *);
 
 /*
  * Bad read/write accesses...
@@ -380,7 +378,7 @@ void __iomem *ioremap_wc(resource_size_t res_cookie, size_t size);
 #define ioremap_wc ioremap_wc
 #define ioremap_wt ioremap_wc
 
-void iounmap(volatile void __iomem *iomem_cookie);
+void iounmap(volatile void __iomem *io_addr);
 #define iounmap iounmap
 
 void *arch_memremap_wb(phys_addr_t phys_addr, size_t size);
index 9228255..2b8970d 100644 (file)
@@ -27,6 +27,7 @@ enum {
        MT_HIGH_VECTORS,
        MT_MEMORY_RWX,
        MT_MEMORY_RW,
+       MT_MEMORY_RO,
        MT_ROM,
        MT_MEMORY_RWX_NONCACHED,
        MT_MEMORY_RW_DTCM,
index 93051e2..1408a6a 100644 (file)
@@ -163,5 +163,31 @@ static inline unsigned long user_stack_pointer(struct pt_regs *regs)
                ((current_stack_pointer | (THREAD_SIZE - 1)) - 7) - 1;  \
 })
 
+
+/*
+ * Update ITSTATE after normal execution of an IT block instruction.
+ *
+ * The 8 IT state bits are split into two parts in CPSR:
+ *     ITSTATE<1:0> are in CPSR<26:25>
+ *     ITSTATE<7:2> are in CPSR<15:10>
+ */
+static inline unsigned long it_advance(unsigned long cpsr)
+{
+       if ((cpsr & 0x06000400) == 0) {
+               /* ITSTATE<2:0> == 0 means end of IT block, so clear IT state */
+               cpsr &= ~PSR_IT_MASK;
+       } else {
+               /* We need to shift left ITSTATE<4:0> */
+               const unsigned long mask = 0x06001c00;  /* Mask ITSTATE<4:0> */
+               unsigned long it = cpsr & mask;
+               it <<= 1;
+               it |= it >> (27 - 10);  /* Carry ITSTATE<2> to correct place */
+               it &= mask;
+               cpsr &= ~mask;
+               cpsr |= it;
+       }
+       return cpsr;
+}
+
 #endif /* __ASSEMBLY__ */
 #endif
index 7aa3ded..405a607 100644 (file)
@@ -28,7 +28,7 @@
 #include "entry-header.S"
 
 saved_psr      .req    r8
-#if defined(CONFIG_TRACE_IRQFLAGS) || defined(CONFIG_CONTEXT_TRACKING)
+#if defined(CONFIG_TRACE_IRQFLAGS) || defined(CONFIG_CONTEXT_TRACKING_USER)
 saved_pc       .req    r9
 #define TRACE(x...) x
 #else
@@ -38,7 +38,7 @@ saved_pc      .req    lr
 
        .section .entry.text,"ax",%progbits
        .align  5
-#if !(IS_ENABLED(CONFIG_TRACE_IRQFLAGS) || IS_ENABLED(CONFIG_CONTEXT_TRACKING) || \
+#if !(IS_ENABLED(CONFIG_TRACE_IRQFLAGS) || IS_ENABLED(CONFIG_CONTEXT_TRACKING_USER) || \
        IS_ENABLED(CONFIG_DEBUG_RSEQ))
 /*
  * This is the fast syscall return path.  We do as little as possible here,
@@ -302,6 +302,7 @@ local_restart:
        b       ret_fast_syscall
 #endif
 ENDPROC(vector_swi)
+       .ltorg
 
        /*
         * This is the really slow path.  We're going to be doing
index 5865621..99411fa 100644 (file)
@@ -366,25 +366,25 @@ ALT_UP_B(.L1_\@)
  * between user and kernel mode.
  */
        .macro ct_user_exit, save = 1
-#ifdef CONFIG_CONTEXT_TRACKING
+#ifdef CONFIG_CONTEXT_TRACKING_USER
        .if     \save
        stmdb   sp!, {r0-r3, ip, lr}
-       bl      context_tracking_user_exit
+       bl      user_exit_callable
        ldmia   sp!, {r0-r3, ip, lr}
        .else
-       bl      context_tracking_user_exit
+       bl      user_exit_callable
        .endif
 #endif
        .endm
 
        .macro ct_user_enter, save = 1
-#ifdef CONFIG_CONTEXT_TRACKING
+#ifdef CONFIG_CONTEXT_TRACKING_USER
        .if     \save
        stmdb   sp!, {r0-r3, ip, lr}
-       bl      context_tracking_user_enter
+       bl      user_enter_callable
        ldmia   sp!, {r0-r3, ip, lr}
        .else
-       bl      context_tracking_user_enter
+       bl      user_enter_callable
        .endif
 #endif
        .endm
index 303b3ab..eb9c24b 100644 (file)
@@ -27,9 +27,3 @@ void arch_jump_label_transform(struct jump_entry *entry,
 {
        __arch_jump_label_transform(entry, type, false);
 }
-
-void arch_jump_label_transform_static(struct jump_entry *entry,
-                                     enum jump_label_type type)
-{
-       __arch_jump_label_transform(entry, type, true);
-}
index b5e8b9a..7fd3600 100644 (file)
@@ -40,8 +40,8 @@ ENDPROC(_find_first_zero_bit_le)
  * Prototype: int find_next_zero_bit(void *addr, unsigned int maxbit, int offset)
  */
 ENTRY(_find_next_zero_bit_le)
-               teq     r1, #0
-               beq     3b
+               cmp     r2, r1
+               bhs     3b
                ands    ip, r2, #7
                beq     1b                      @ If new byte, goto old routine
  ARM(          ldrb    r3, [r0, r2, lsr #3]    )
@@ -81,8 +81,8 @@ ENDPROC(_find_first_bit_le)
  * Prototype: int find_next_zero_bit(void *addr, unsigned int maxbit, int offset)
  */
 ENTRY(_find_next_bit_le)
-               teq     r1, #0
-               beq     3b
+               cmp     r2, r1
+               bhs     3b
                ands    ip, r2, #7
                beq     1b                      @ If new byte, goto old routine
  ARM(          ldrb    r3, [r0, r2, lsr #3]    )
@@ -115,8 +115,8 @@ ENTRY(_find_first_zero_bit_be)
 ENDPROC(_find_first_zero_bit_be)
 
 ENTRY(_find_next_zero_bit_be)
-               teq     r1, #0
-               beq     3b
+               cmp     r2, r1
+               bhs     3b
                ands    ip, r2, #7
                beq     1b                      @ If new byte, goto old routine
                eor     r3, r2, #0x18           @ big endian byte ordering
@@ -149,8 +149,8 @@ ENTRY(_find_first_bit_be)
 ENDPROC(_find_first_bit_be)
 
 ENTRY(_find_next_bit_be)
-               teq     r1, #0
-               beq     3b
+               cmp     r2, r1
+               bhs     3b
                ands    ip, r2, #7
                beq     1b                      @ If new byte, goto old routine
                eor     r3, r2, #0x18           @ big endian byte ordering
index b1a43d7..df6d673 100644 (file)
@@ -202,7 +202,7 @@ static const struct wakeup_source_info ws_info[] = {
 
 static const struct of_device_id sama5d2_ws_ids[] = {
        { .compatible = "atmel,sama5d2-gem",            .data = &ws_info[0] },
-       { .compatible = "atmel,at91rm9200-rtc",         .data = &ws_info[1] },
+       { .compatible = "atmel,sama5d2-rtc",            .data = &ws_info[1] },
        { .compatible = "atmel,sama5d3-udc",            .data = &ws_info[2] },
        { .compatible = "atmel,at91rm9200-ohci",        .data = &ws_info[2] },
        { .compatible = "usb-ohci",                     .data = &ws_info[2] },
@@ -213,24 +213,24 @@ static const struct of_device_id sama5d2_ws_ids[] = {
 };
 
 static const struct of_device_id sam9x60_ws_ids[] = {
-       { .compatible = "atmel,at91sam9x5-rtc",         .data = &ws_info[1] },
+       { .compatible = "microchip,sam9x60-rtc",        .data = &ws_info[1] },
        { .compatible = "atmel,at91rm9200-ohci",        .data = &ws_info[2] },
        { .compatible = "usb-ohci",                     .data = &ws_info[2] },
        { .compatible = "atmel,at91sam9g45-ehci",       .data = &ws_info[2] },
        { .compatible = "usb-ehci",                     .data = &ws_info[2] },
-       { .compatible = "atmel,at91sam9260-rtt",        .data = &ws_info[4] },
+       { .compatible = "microchip,sam9x60-rtt",        .data = &ws_info[4] },
        { .compatible = "cdns,sam9x60-macb",            .data = &ws_info[5] },
        { /* sentinel */ }
 };
 
 static const struct of_device_id sama7g5_ws_ids[] = {
-       { .compatible = "atmel,at91sam9x5-rtc",         .data = &ws_info[1] },
+       { .compatible = "microchip,sama7g5-rtc",        .data = &ws_info[1] },
        { .compatible = "microchip,sama7g5-ohci",       .data = &ws_info[2] },
        { .compatible = "usb-ohci",                     .data = &ws_info[2] },
        { .compatible = "atmel,at91sam9g45-ehci",       .data = &ws_info[2] },
        { .compatible = "usb-ehci",                     .data = &ws_info[2] },
        { .compatible = "microchip,sama7g5-sdhci",      .data = &ws_info[3] },
-       { .compatible = "atmel,at91sam9260-rtt",        .data = &ws_info[4] },
+       { .compatible = "microchip,sama7g5-rtt",        .data = &ws_info[4] },
        { /* sentinel */ }
 };
 
@@ -1079,7 +1079,7 @@ securam_fail:
        return ret;
 }
 
-static void at91_pm_secure_init(void)
+static void __init at91_pm_secure_init(void)
 {
        int suspend_mode;
        struct arm_smccc_res res;
index 2a01f7a..f7789cb 100644 (file)
@@ -27,6 +27,12 @@ struct arm_smccc_res sam_smccc_call(u32 fn, u32 arg0, u32 arg1)
        return res;
 }
 
+bool sam_linux_is_optee_available(void)
+{
+       /* If optee has been detected, then we are running in normal world */
+       return optee_available;
+}
+
 void __init sam_secure_init(void)
 {
        struct device_node *np;
index 1e7d8b2..1a0b5eb 100644 (file)
@@ -14,5 +14,6 @@
 
 void __init sam_secure_init(void);
 struct arm_smccc_res sam_smccc_call(u32 fn, u32 arg0, u32 arg1);
+bool sam_linux_is_optee_available(void);
 
 #endif /* SAM_SECURE_H */
index de5dd28..67ed68f 100644 (file)
@@ -9,13 +9,27 @@
 #include <linux/of.h>
 #include <linux/of_platform.h>
 
+#include <asm/hardware/cache-l2x0.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+#include <asm/outercache.h>
 #include <asm/system_misc.h>
 
 #include "generic.h"
 #include "sam_secure.h"
 
+static void sama5_l2c310_write_sec(unsigned long val, unsigned reg)
+{
+       /* OP-TEE configures the L2 cache and does not allow modifying it yet */
+}
+
+static void __init sama5_secure_cache_init(void)
+{
+       sam_secure_init();
+       if (sam_linux_is_optee_available())
+               outer_cache.write_sec = sama5_l2c310_write_sec;
+}
+
 static void __init sama5_dt_device_init(void)
 {
        of_platform_default_populate(NULL, NULL, NULL);
@@ -48,7 +62,6 @@ MACHINE_END
 static void __init sama5d2_init(void)
 {
        of_platform_default_populate(NULL, NULL, NULL);
-       sam_secure_init();
        sama5d2_pm_init();
 }
 
@@ -60,6 +73,7 @@ static const char *const sama5d2_compat[] __initconst = {
 DT_MACHINE_START(sama5d2, "Atmel SAMA5")
        /* Maintainer: Atmel */
        .init_machine   = sama5d2_init,
+       .init_early     = sama5_secure_cache_init,
        .dt_compat      = sama5d2_compat,
        .l2c_aux_mask   = ~0UL,
 MACHINE_END
index 512943e..2e20362 100644 (file)
@@ -39,6 +39,7 @@ static int axxia_boot_secondary(unsigned int cpu, struct task_struct *idle)
                return -ENOENT;
 
        syscon = of_iomap(syscon_np, 0);
+       of_node_put(syscon_np);
        if (!syscon)
                return -ENOMEM;
 
index f73a056..8789d93 100644 (file)
@@ -54,8 +54,6 @@ config ARCH_BCM_NSP
        select ARM_ERRATA_775420
        select ARM_ERRATA_764369 if SMP
        select ARM_TIMER_SP804
-       select THERMAL
-       select THERMAL_OF
        help
          Support for Broadcom Northstar Plus SoC.
          Broadcom Northstar Plus family of SoCs are used for switching control
@@ -182,23 +180,6 @@ config ARCH_BCM_53573
          The base chip is BCM53573 and there are some packaging modifications
          like BCM47189 and BCM47452.
 
-config ARCH_BCM_63XX
-       bool "Broadcom BCM63xx DSL SoC"
-       depends on ARCH_MULTI_V7
-       select ARCH_HAS_RESET_CONTROLLER
-       select ARM_ERRATA_754322
-       select ARM_ERRATA_764369 if SMP
-       select ARM_GIC
-       select ARM_GLOBAL_TIMER
-       select CACHE_L2X0
-       select HAVE_ARM_ARCH_TIMER
-       select HAVE_ARM_TWD if SMP
-       select HAVE_ARM_SCU if SMP
-       help
-         This enables support for systems based on Broadcom DSL SoCs.
-         It currently supports the 'BCM63XX' ARM-based family, which includes
-         the BCM63138 variant.
-
 config ARCH_BRCMSTB
        bool "Broadcom BCM7XXX based boards"
        depends on ARCH_MULTI_V7
@@ -218,8 +199,8 @@ config ARCH_BRCMSTB
          This enables support for Broadcom ARM-based set-top box chipsets,
          including the 7445 family of chips.
 
-config ARCH_BCMBCA
-       bool "Broadcom Broadband SoC"
+menuconfig ARCH_BCMBCA
+       bool "Broadcom Broadband Carrier Access (BCA) origin SoC"
        depends on ARCH_MULTI_V7
        select ARM_AMBA
        select ARM_GIC
@@ -230,4 +211,46 @@ config ARCH_BCMBCA
 
          This enables support for Broadcom BCA ARM-based broadband chipsets,
          including the DSL, PON and Wireless family of chips.
+
+comment "BCMBCA sub platforms"
+
+if ARCH_BCMBCA
+
+config ARCH_BCMBCA_CORTEXA7
+       bool "Cortex-A7 SoCs"
+       help
+         Say Y if you intend to run the kernel on a Broadcom Broadband ARM A7
+         based chipset.
+
+         This enables support for Broadcom BCA ARM A7 broadband chipsets,
+         including various DSL, PON and Wireless family of chips.
+
+config ARCH_BCMBCA_CORTEXA9
+       bool "Cortex-A9 SoCS"
+       select ARM_ERRATA_754322
+       select ARM_ERRATA_764369 if SMP
+       select ARCH_HAS_RESET_CONTROLLER
+       select ARM_GLOBAL_TIMER
+       select CACHE_L2X0
+       select HAVE_ARM_TWD if SMP
+       select HAVE_ARM_SCU if SMP
+       help
+         Say Y if you intend to run the kernel on a Broadcom Broadband ARM A9
+         based BCA chipset.
+
+         This enables support for Broadcom BCA ARM A9 broadband chipset. Currently
+         only DSL chip BCM63138.
+
+config ARCH_BCMBCA_BRAHMAB15
+       bool "Brahma-B15 SoCs"
+       select ARM_ERRATA_798181 if SMP
+       help
+         Say Y if you intend to run the kernel on a Broadcom Broadband ARM B15
+         based BCA chipset.
+
+         This enables support for Broadcom BCA ARM B15 broadband chipset. Currently
+         only DSL chip BCM63148.
+
+endif
+
 endif
index b2394dd..020075e 100644 (file)
@@ -57,14 +57,13 @@ ifeq ($(CONFIG_ARCH_BCM_5301X),y)
 obj-$(CONFIG_SMP)              += platsmp.o
 endif
 
-# BCM63XXx
-ifeq ($(CONFIG_ARCH_BCM_63XX),y)
-obj-y                          += bcm63xx.o
-obj-$(CONFIG_SMP)              += bcm63xx_smp.o bcm63xx_pmb.o
-endif
-
 ifeq ($(CONFIG_ARCH_BRCMSTB),y)
 CFLAGS_platsmp-brcmstb.o       += -march=armv7-a
 obj-y                          += brcmstb.o
 obj-$(CONFIG_SMP)              += platsmp-brcmstb.o
 endif
+
+# BCMBCA
+ifeq ($(CONFIG_ARCH_BCMBCA),y)
+obj-$(CONFIG_SMP)              += bcm63xx_smp.o bcm63xx_pmb.o
+endif
diff --git a/arch/arm/mach-bcm/bcm63xx.c b/arch/arm/mach-bcm/bcm63xx.c
deleted file mode 100644 (file)
index c4c66ae..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2014 Broadcom Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/of_platform.h>
-
-#include <asm/mach/arch.h>
-
-static const char * const bcm63xx_dt_compat[] = {
-       "brcm,bcm63138",
-       NULL
-};
-
-DT_MACHINE_START(BCM63XXX_DT, "BCM63xx DSL SoC")
-       .dt_compat      = bcm63xx_dt_compat,
-       .l2c_aux_val    = 0,
-       .l2c_aux_mask   = ~0,
-MACHINE_END
index 43829e4..347bfb7 100644 (file)
@@ -52,6 +52,7 @@ int __init bcm_kona_smc_init(void)
                return -ENODEV;
 
        prop_val = of_get_address(node, 0, &prop_size, NULL);
+       of_node_put(node);
        if (!prop_val)
                return -EINVAL;
 
index 1ecf546..1f85def 100644 (file)
@@ -2,6 +2,7 @@
 menuconfig ARCH_CNS3XXX
        bool "Cavium Networks CNS3XXX family"
        depends on ARCH_MULTI_V6
+       depends on ATAGS && UNUSED_BOARD_FILES
        select ARM_GIC
        help
          Support for Cavium Networks CNS3XXX platform.
index e4f4b20..3fc4ec8 100644 (file)
@@ -372,6 +372,7 @@ static void __init cns3xxx_init(void)
                /* De-Asscer SATA Reset */
                cns3xxx_pwr_soft_rst(CNS3XXX_PWR_SOFTWARE_RST(SATA));
        }
+       of_node_put(dn);
 
        dn = of_find_compatible_node(NULL, NULL, "cavium,cns3420-sdhci");
        if (of_device_is_available(dn)) {
@@ -385,6 +386,7 @@ static void __init cns3xxx_init(void)
                cns3xxx_pwr_clk_en(CNS3XXX_PWR_CLK_EN(SDIO));
                cns3xxx_pwr_soft_rst(CNS3XXX_PWR_SOFTWARE_RST(SDIO));
        }
+       of_node_put(dn);
 
        pm_power_off = cns3xxx_power_off;
 
index 008cbc2..c8cbd9a 100644 (file)
@@ -19,24 +19,16 @@ config ARCH_DAVINCI_DMx
 
 comment "DaVinci Core Type"
 
-config ARCH_DAVINCI_DM644x
-       bool "DaVinci 644x based system"
-       select DAVINCI_AINTC
-       select ARCH_DAVINCI_DMx
-
 config ARCH_DAVINCI_DM355
        bool "DaVinci 355 based system"
-       select DAVINCI_AINTC
-       select ARCH_DAVINCI_DMx
-
-config ARCH_DAVINCI_DM646x
-       bool "DaVinci 646x based system"
+       depends on ATAGS && UNUSED_BOARD_FILES
        select DAVINCI_AINTC
        select ARCH_DAVINCI_DMx
 
 config ARCH_DAVINCI_DA830
        bool "DA830/OMAP-L137/AM17x based system"
        depends on !ARCH_DAVINCI_DMx || (AUTO_ZRELADDR && ARM_PATCH_PHYS_VIRT)
+       depends on ATAGS
        select ARCH_DAVINCI_DA8XX
        # needed on silicon revs 1.0, 1.1:
        select CPU_DCACHE_WRITETHROUGH if !CPU_DCACHE_DISABLE
@@ -45,6 +37,7 @@ config ARCH_DAVINCI_DA830
 config ARCH_DAVINCI_DA850
        bool "DA850/OMAP-L138/AM18x based system"
        depends on !ARCH_DAVINCI_DMx || (AUTO_ZRELADDR && ARM_PATCH_PHYS_VIRT)
+       depends on ATAGS
        select ARCH_DAVINCI_DA8XX
        select DAVINCI_CP_INTC
 
@@ -53,6 +46,7 @@ config ARCH_DAVINCI_DA8XX
 
 config ARCH_DAVINCI_DM365
        bool "DaVinci 365 based system"
+       depends on ATAGS && UNUSED_BOARD_FILES
        select DAVINCI_AINTC
        select ARCH_DAVINCI_DMx
 
@@ -67,28 +61,6 @@ config MACH_DA8XX_DT
          Say y here to include support for TI DaVinci DA850 based using
          Flattened Device Tree. More information at Documentation/devicetree
 
-config MACH_DAVINCI_EVM
-       bool "TI DM644x EVM"
-       default ARCH_DAVINCI_DM644x
-       depends on ARCH_DAVINCI_DM644x
-       help
-         Configure this option to specify the whether the board used
-         for development is a DM644x EVM
-
-config MACH_SFFSDR
-       bool "Lyrtech SFFSDR"
-       depends on ARCH_DAVINCI_DM644x
-       help
-         Say Y here to select the Lyrtech Small Form Factor
-         Software Defined Radio (SFFSDR) board.
-
-config MACH_NEUROS_OSD2
-       bool "Neuros OSD2 Open Television Set Top Box"
-       depends on ARCH_DAVINCI_DM644x
-       help
-         Configure this option to specify the whether the board used
-         for development is a Neuros OSD2 Open Set Top Box.
-
 config MACH_DAVINCI_DM355_EVM
        bool "TI DM355 EVM"
        default ARCH_DAVINCI_DM355
@@ -104,18 +76,6 @@ config MACH_DM355_LEOPARD
          Configure this option to specify the whether the board used
          for development is a DM355 Leopard board.
 
-config MACH_DAVINCI_DM6467_EVM
-       bool "TI DM6467 EVM"
-       default ARCH_DAVINCI_DM646x
-       depends on ARCH_DAVINCI_DM646x
-       select MACH_DAVINCI_DM6467TEVM
-       help
-         Configure this option to specify the whether the board used
-         for development is a DM6467 EVM
-
-config MACH_DAVINCI_DM6467TEVM
-       bool
-
 config MACH_DAVINCI_DM365_EVM
        bool "TI DM365 EVM"
        default ARCH_DAVINCI_DM365
@@ -127,6 +87,7 @@ config MACH_DAVINCI_DM365_EVM
 config MACH_DAVINCI_DA830_EVM
        bool "TI DA830/OMAP-L137/AM17x Reference Platform"
        default ARCH_DAVINCI_DA830
+       depends on ATAGS && UNUSED_BOARD_FILES
        depends on ARCH_DAVINCI_DA830
        select GPIO_PCF857X if I2C
        help
@@ -156,6 +117,7 @@ endchoice
 
 config MACH_DAVINCI_DA850_EVM
        bool "TI DA850/OMAP-L138/AM18x Reference Platform"
+       depends on ATAGS && UNUSED_BOARD_FILES
        default ARCH_DAVINCI_DA850
        depends on ARCH_DAVINCI_DA850
        help
@@ -197,6 +159,7 @@ endchoice
 config MACH_MITYOMAPL138
        bool "Critical Link MityDSP-L138/MityARM-1808 SoM"
        depends on ARCH_DAVINCI_DA850
+       depends on ATAGS && UNUSED_BOARD_FILES
        help
          Say Y here to select the Critical Link MityDSP-L138/MityARM-1808
          System on Module.  Information on this SoM may be found at
@@ -205,6 +168,7 @@ config MACH_MITYOMAPL138
 config MACH_OMAPL138_HAWKBOARD
        bool "TI AM1808 / OMAPL-138 Hawkboard platform"
        depends on ARCH_DAVINCI_DA850
+       depends on ATAGS && UNUSED_BOARD_FILES
        help
          Say Y here to select the TI AM1808 / OMAPL-138 Hawkboard platform .
 
index b04c084..3f4894a 100644 (file)
@@ -10,21 +10,15 @@ obj-y                                       := serial.o usb.o common.o sram.o
 obj-$(CONFIG_DAVINCI_MUX)              += mux.o
 
 # Chip specific
-obj-$(CONFIG_ARCH_DAVINCI_DM644x)       += dm644x.o devices.o
 obj-$(CONFIG_ARCH_DAVINCI_DM355)        += dm355.o devices.o
-obj-$(CONFIG_ARCH_DAVINCI_DM646x)       += dm646x.o devices.o
 obj-$(CONFIG_ARCH_DAVINCI_DM365)       += dm365.o devices.o
 obj-$(CONFIG_ARCH_DAVINCI_DA830)       += da830.o devices-da8xx.o usb-da8xx.o
 obj-$(CONFIG_ARCH_DAVINCI_DA850)       += da850.o devices-da8xx.o usb-da8xx.o
 
 # Board specific
 obj-$(CONFIG_MACH_DA8XX_DT)            += da8xx-dt.o pdata-quirks.o
-obj-$(CONFIG_MACH_DAVINCI_EVM)         += board-dm644x-evm.o
-obj-$(CONFIG_MACH_SFFSDR)              += board-sffsdr.o
-obj-$(CONFIG_MACH_NEUROS_OSD2)         += board-neuros-osd2.o
 obj-$(CONFIG_MACH_DAVINCI_DM355_EVM)   += board-dm355-evm.o
 obj-$(CONFIG_MACH_DM355_LEOPARD)       += board-dm355-leopard.o
-obj-$(CONFIG_MACH_DAVINCI_DM6467_EVM)  += board-dm646x-evm.o
 obj-$(CONFIG_MACH_DAVINCI_DM365_EVM)   += board-dm365-evm.o
 obj-$(CONFIG_MACH_DAVINCI_DA830_EVM)   += board-da830-evm.o
 obj-$(CONFIG_MACH_DAVINCI_DA850_EVM)   += board-da850-evm.o
diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c
deleted file mode 100644 (file)
index 9f405af..0000000
+++ /dev/null
@@ -1,928 +0,0 @@
-/*
- * TI DaVinci EVM board support
- *
- * Author: Kevin Hilman, MontaVista Software, Inc. <source@mvista.com>
- *
- * 2007 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/dma-mapping.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/gpio/machine.h>
-#include <linux/i2c.h>
-#include <linux/platform_data/pcf857x.h>
-#include <linux/platform_data/gpio-davinci.h>
-#include <linux/property.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/physmap.h>
-#include <linux/nvmem-provider.h>
-#include <linux/phy.h>
-#include <linux/clk.h>
-#include <linux/videodev2.h>
-#include <linux/v4l2-dv-timings.h>
-#include <linux/export.h>
-#include <linux/leds.h>
-#include <linux/regulator/fixed.h>
-#include <linux/regulator/machine.h>
-
-#include <media/i2c/tvp514x.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-#include <linux/platform_data/i2c-davinci.h>
-#include <linux/platform_data/mtd-davinci.h>
-#include <linux/platform_data/mmc-davinci.h>
-#include <linux/platform_data/usb-davinci.h>
-#include <linux/platform_data/mtd-davinci-aemif.h>
-#include <linux/platform_data/ti-aemif.h>
-
-#include "davinci.h"
-#include "common.h"
-#include "mux.h"
-#include "serial.h"
-#include "irqs.h"
-
-#define DM644X_EVM_PHY_ID              "davinci_mdio-0:01"
-#define LXT971_PHY_ID  (0x001378e2)
-#define LXT971_PHY_MASK        (0xfffffff0)
-
-static struct mtd_partition davinci_evm_norflash_partitions[] = {
-       /* bootloader (UBL, U-Boot, etc) in first 5 sectors */
-       {
-               .name           = "bootloader",
-               .offset         = 0,
-               .size           = 5 * SZ_64K,
-               .mask_flags     = MTD_WRITEABLE, /* force read-only */
-       },
-       /* bootloader params in the next 1 sectors */
-       {
-               .name           = "params",
-               .offset         = MTDPART_OFS_APPEND,
-               .size           = SZ_64K,
-               .mask_flags     = 0,
-       },
-       /* kernel */
-       {
-               .name           = "kernel",
-               .offset         = MTDPART_OFS_APPEND,
-               .size           = SZ_2M,
-               .mask_flags     = 0
-       },
-       /* file system */
-       {
-               .name           = "filesystem",
-               .offset         = MTDPART_OFS_APPEND,
-               .size           = MTDPART_SIZ_FULL,
-               .mask_flags     = 0
-       }
-};
-
-static struct physmap_flash_data davinci_evm_norflash_data = {
-       .width          = 2,
-       .parts          = davinci_evm_norflash_partitions,
-       .nr_parts       = ARRAY_SIZE(davinci_evm_norflash_partitions),
-};
-
-/* NOTE: CFI probe will correctly detect flash part as 32M, but EMIF
- * limits addresses to 16M, so using addresses past 16M will wrap */
-static struct resource davinci_evm_norflash_resource = {
-       .start          = DM644X_ASYNC_EMIF_DATA_CE0_BASE,
-       .end            = DM644X_ASYNC_EMIF_DATA_CE0_BASE + SZ_16M - 1,
-       .flags          = IORESOURCE_MEM,
-};
-
-static struct platform_device davinci_evm_norflash_device = {
-       .name           = "physmap-flash",
-       .id             = 0,
-       .dev            = {
-               .platform_data  = &davinci_evm_norflash_data,
-       },
-       .num_resources  = 1,
-       .resource       = &davinci_evm_norflash_resource,
-};
-
-/* DM644x EVM includes a 64 MByte small-page NAND flash (16K blocks).
- * It may used instead of the (default) NOR chip to boot, using TI's
- * tools to install the secondary boot loader (UBL) and U-Boot.
- */
-static struct mtd_partition davinci_evm_nandflash_partition[] = {
-       /* Bootloader layout depends on whose u-boot is installed, but we
-        * can hide all the details.
-        *  - block 0 for u-boot environment ... in mainline u-boot
-        *  - block 1 for UBL (plus up to four backup copies in blocks 2..5)
-        *  - blocks 6...? for u-boot
-        *  - blocks 16..23 for u-boot environment ... in TI's u-boot
-        */
-       {
-               .name           = "bootloader",
-               .offset         = 0,
-               .size           = SZ_256K + SZ_128K,
-               .mask_flags     = MTD_WRITEABLE,        /* force read-only */
-       },
-       /* Kernel */
-       {
-               .name           = "kernel",
-               .offset         = MTDPART_OFS_APPEND,
-               .size           = SZ_4M,
-               .mask_flags     = 0,
-       },
-       /* File system (older GIT kernels started this on the 5MB mark) */
-       {
-               .name           = "filesystem",
-               .offset         = MTDPART_OFS_APPEND,
-               .size           = MTDPART_SIZ_FULL,
-               .mask_flags     = 0,
-       }
-       /* A few blocks at end hold a flash BBT ... created by TI's CCS
-        * using flashwriter_nand.out, but ignored by TI's versions of
-        * Linux and u-boot.  We boot faster by using them.
-        */
-};
-
-static struct davinci_aemif_timing davinci_evm_nandflash_timing = {
-       .wsetup         = 20,
-       .wstrobe        = 40,
-       .whold          = 20,
-       .rsetup         = 10,
-       .rstrobe        = 40,
-       .rhold          = 10,
-       .ta             = 40,
-};
-
-static struct davinci_nand_pdata davinci_evm_nandflash_data = {
-       .core_chipsel   = 0,
-       .parts          = davinci_evm_nandflash_partition,
-       .nr_parts       = ARRAY_SIZE(davinci_evm_nandflash_partition),
-       .engine_type    = NAND_ECC_ENGINE_TYPE_ON_HOST,
-       .ecc_bits       = 1,
-       .bbt_options    = NAND_BBT_USE_FLASH,
-       .timing         = &davinci_evm_nandflash_timing,
-};
-
-static struct resource davinci_evm_nandflash_resource[] = {
-       {
-               .start          = DM644X_ASYNC_EMIF_DATA_CE0_BASE,
-               .end            = DM644X_ASYNC_EMIF_DATA_CE0_BASE + SZ_16M - 1,
-               .flags          = IORESOURCE_MEM,
-       }, {
-               .start          = DM644X_ASYNC_EMIF_CONTROL_BASE,
-               .end            = DM644X_ASYNC_EMIF_CONTROL_BASE + SZ_4K - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-};
-
-static struct resource davinci_evm_aemif_resource[] = {
-       {
-               .start          = DM644X_ASYNC_EMIF_CONTROL_BASE,
-               .end            = DM644X_ASYNC_EMIF_CONTROL_BASE + SZ_4K - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-};
-
-static struct aemif_abus_data davinci_evm_aemif_abus_data[] = {
-       {
-               .cs             = 1,
-       },
-};
-
-static struct platform_device davinci_evm_nandflash_devices[] = {
-       {
-               .name           = "davinci_nand",
-               .id             = 0,
-               .dev            = {
-                       .platform_data  = &davinci_evm_nandflash_data,
-               },
-               .num_resources  = ARRAY_SIZE(davinci_evm_nandflash_resource),
-               .resource       = davinci_evm_nandflash_resource,
-       },
-};
-
-static struct aemif_platform_data davinci_evm_aemif_pdata = {
-       .abus_data = davinci_evm_aemif_abus_data,
-       .num_abus_data = ARRAY_SIZE(davinci_evm_aemif_abus_data),
-       .sub_devices = davinci_evm_nandflash_devices,
-       .num_sub_devices = ARRAY_SIZE(davinci_evm_nandflash_devices),
-};
-
-static struct platform_device davinci_evm_aemif_device = {
-       .name                   = "ti-aemif",
-       .id                     = -1,
-       .dev = {
-               .platform_data  = &davinci_evm_aemif_pdata,
-       },
-       .resource               = davinci_evm_aemif_resource,
-       .num_resources          = ARRAY_SIZE(davinci_evm_aemif_resource),
-};
-
-static u64 davinci_fb_dma_mask = DMA_BIT_MASK(32);
-
-static struct platform_device davinci_fb_device = {
-       .name           = "davincifb",
-       .id             = -1,
-       .dev = {
-               .dma_mask               = &davinci_fb_dma_mask,
-               .coherent_dma_mask      = DMA_BIT_MASK(32),
-       },
-       .num_resources = 0,
-};
-
-static struct tvp514x_platform_data dm644xevm_tvp5146_pdata = {
-       .clk_polarity = 0,
-       .hs_polarity = 1,
-       .vs_polarity = 1
-};
-
-#define TVP514X_STD_ALL        (V4L2_STD_NTSC | V4L2_STD_PAL)
-/* Inputs available at the TVP5146 */
-static struct v4l2_input dm644xevm_tvp5146_inputs[] = {
-       {
-               .index = 0,
-               .name = "Composite",
-               .type = V4L2_INPUT_TYPE_CAMERA,
-               .std = TVP514X_STD_ALL,
-       },
-       {
-               .index = 1,
-               .name = "S-Video",
-               .type = V4L2_INPUT_TYPE_CAMERA,
-               .std = TVP514X_STD_ALL,
-       },
-};
-
-/*
- * this is the route info for connecting each input to decoder
- * ouput that goes to vpfe. There is a one to one correspondence
- * with tvp5146_inputs
- */
-static struct vpfe_route dm644xevm_tvp5146_routes[] = {
-       {
-               .input = INPUT_CVBS_VI2B,
-               .output = OUTPUT_10BIT_422_EMBEDDED_SYNC,
-       },
-       {
-               .input = INPUT_SVIDEO_VI2C_VI1C,
-               .output = OUTPUT_10BIT_422_EMBEDDED_SYNC,
-       },
-};
-
-static struct vpfe_subdev_info dm644xevm_vpfe_sub_devs[] = {
-       {
-               .name = "tvp5146",
-               .grp_id = 0,
-               .num_inputs = ARRAY_SIZE(dm644xevm_tvp5146_inputs),
-               .inputs = dm644xevm_tvp5146_inputs,
-               .routes = dm644xevm_tvp5146_routes,
-               .can_route = 1,
-               .ccdc_if_params = {
-                       .if_type = VPFE_BT656,
-                       .hdpol = VPFE_PINPOL_POSITIVE,
-                       .vdpol = VPFE_PINPOL_POSITIVE,
-               },
-               .board_info = {
-                       I2C_BOARD_INFO("tvp5146", 0x5d),
-                       .platform_data = &dm644xevm_tvp5146_pdata,
-               },
-       },
-};
-
-static struct vpfe_config dm644xevm_capture_cfg = {
-       .num_subdevs = ARRAY_SIZE(dm644xevm_vpfe_sub_devs),
-       .i2c_adapter_id = 1,
-       .sub_devs = dm644xevm_vpfe_sub_devs,
-       .card_name = "DM6446 EVM",
-       .ccdc = "DM6446 CCDC",
-};
-
-static struct platform_device rtc_dev = {
-       .name           = "rtc_davinci_evm",
-       .id             = -1,
-};
-
-/*----------------------------------------------------------------------*/
-#ifdef CONFIG_I2C
-/*
- * I2C GPIO expanders
- */
-
-#define PCF_Uxx_BASE(x)        (DAVINCI_N_GPIO + ((x) * 8))
-
-
-/* U2 -- LEDs */
-
-static struct gpio_led evm_leds[] = {
-       { .name = "DS8", .active_low = 1,
-               .default_trigger = "heartbeat", },
-       { .name = "DS7", .active_low = 1, },
-       { .name = "DS6", .active_low = 1, },
-       { .name = "DS5", .active_low = 1, },
-       { .name = "DS4", .active_low = 1, },
-       { .name = "DS3", .active_low = 1, },
-       { .name = "DS2", .active_low = 1,
-               .default_trigger = "mmc0", },
-       { .name = "DS1", .active_low = 1,
-               .default_trigger = "disk-activity", },
-};
-
-static const struct gpio_led_platform_data evm_led_data = {
-       .num_leds       = ARRAY_SIZE(evm_leds),
-       .leds           = evm_leds,
-};
-
-static struct platform_device *evm_led_dev;
-
-static int
-evm_led_setup(struct i2c_client *client, int gpio, unsigned ngpio, void *c)
-{
-       struct gpio_led *leds = evm_leds;
-       int status;
-
-       while (ngpio--) {
-               leds->gpio = gpio++;
-               leds++;
-       }
-
-       /* what an extremely annoying way to be forced to handle
-        * device unregistration ...
-        */
-       evm_led_dev = platform_device_alloc("leds-gpio", 0);
-       platform_device_add_data(evm_led_dev,
-                       &evm_led_data, sizeof evm_led_data);
-
-       evm_led_dev->dev.parent = &client->dev;
-       status = platform_device_add(evm_led_dev);
-       if (status < 0) {
-               platform_device_put(evm_led_dev);
-               evm_led_dev = NULL;
-       }
-       return status;
-}
-
-static void
-evm_led_teardown(struct i2c_client *client, int gpio, unsigned ngpio, void *c)
-{
-       if (evm_led_dev) {
-               platform_device_unregister(evm_led_dev);
-               evm_led_dev = NULL;
-       }
-}
-
-static struct pcf857x_platform_data pcf_data_u2 = {
-       .gpio_base      = PCF_Uxx_BASE(0),
-       .setup          = evm_led_setup,
-       .teardown       = evm_led_teardown,
-};
-
-
-/* U18 - A/V clock generator and user switch */
-
-static int sw_gpio;
-
-static ssize_t
-sw_show(struct device *d, struct device_attribute *a, char *buf)
-{
-       char *s = gpio_get_value_cansleep(sw_gpio) ? "on\n" : "off\n";
-
-       strcpy(buf, s);
-       return strlen(s);
-}
-
-static DEVICE_ATTR(user_sw, S_IRUGO, sw_show, NULL);
-
-static int
-evm_u18_setup(struct i2c_client *client, int gpio, unsigned ngpio, void *c)
-{
-       int     status;
-
-       /* export dip switch option */
-       sw_gpio = gpio + 7;
-       status = gpio_request(sw_gpio, "user_sw");
-       if (status == 0)
-               status = gpio_direction_input(sw_gpio);
-       if (status == 0)
-               status = device_create_file(&client->dev, &dev_attr_user_sw);
-       else
-               gpio_free(sw_gpio);
-       if (status != 0)
-               sw_gpio = -EINVAL;
-
-       /* audio PLL:  48 kHz (vs 44.1 or 32), single rate (vs double) */
-       gpio_request(gpio + 3, "pll_fs2");
-       gpio_direction_output(gpio + 3, 0);
-
-       gpio_request(gpio + 2, "pll_fs1");
-       gpio_direction_output(gpio + 2, 0);
-
-       gpio_request(gpio + 1, "pll_sr");
-       gpio_direction_output(gpio + 1, 0);
-
-       return 0;
-}
-
-static void
-evm_u18_teardown(struct i2c_client *client, int gpio, unsigned ngpio, void *c)
-{
-       gpio_free(gpio + 1);
-       gpio_free(gpio + 2);
-       gpio_free(gpio + 3);
-
-       if (sw_gpio > 0) {
-               device_remove_file(&client->dev, &dev_attr_user_sw);
-               gpio_free(sw_gpio);
-       }
-}
-
-static struct pcf857x_platform_data pcf_data_u18 = {
-       .gpio_base      = PCF_Uxx_BASE(1),
-       .n_latch        = (1 << 3) | (1 << 2) | (1 << 1),
-       .setup          = evm_u18_setup,
-       .teardown       = evm_u18_teardown,
-};
-
-
-/* U35 - various I/O signals used to manage USB, CF, ATA, etc */
-
-static int
-evm_u35_setup(struct i2c_client *client, int gpio, unsigned ngpio, void *c)
-{
-       /* p0 = nDRV_VBUS (initial:  don't supply it) */
-       gpio_request(gpio + 0, "nDRV_VBUS");
-       gpio_direction_output(gpio + 0, 1);
-
-       /* p1 = VDDIMX_EN */
-       gpio_request(gpio + 1, "VDDIMX_EN");
-       gpio_direction_output(gpio + 1, 1);
-
-       /* p2 = VLYNQ_EN */
-       gpio_request(gpio + 2, "VLYNQ_EN");
-       gpio_direction_output(gpio + 2, 1);
-
-       /* p3 = n3V3_CF_RESET (initial: stay in reset) */
-       gpio_request(gpio + 3, "nCF_RESET");
-       gpio_direction_output(gpio + 3, 0);
-
-       /* (p4 unused) */
-
-       /* p5 = 1V8_WLAN_RESET (initial: stay in reset) */
-       gpio_request(gpio + 5, "WLAN_RESET");
-       gpio_direction_output(gpio + 5, 1);
-
-       /* p6 = nATA_SEL (initial: select) */
-       gpio_request(gpio + 6, "nATA_SEL");
-       gpio_direction_output(gpio + 6, 0);
-
-       /* p7 = nCF_SEL (initial: deselect) */
-       gpio_request(gpio + 7, "nCF_SEL");
-       gpio_direction_output(gpio + 7, 1);
-
-       return 0;
-}
-
-static void
-evm_u35_teardown(struct i2c_client *client, int gpio, unsigned ngpio, void *c)
-{
-       gpio_free(gpio + 7);
-       gpio_free(gpio + 6);
-       gpio_free(gpio + 5);
-       gpio_free(gpio + 3);
-       gpio_free(gpio + 2);
-       gpio_free(gpio + 1);
-       gpio_free(gpio + 0);
-}
-
-static struct pcf857x_platform_data pcf_data_u35 = {
-       .gpio_base      = PCF_Uxx_BASE(2),
-       .setup          = evm_u35_setup,
-       .teardown       = evm_u35_teardown,
-};
-
-/*----------------------------------------------------------------------*/
-
-/* Most of this EEPROM is unused, but U-Boot uses some data:
- *  - 0x7f00, 6 bytes Ethernet Address
- *  - 0x0039, 1 byte NTSC vs PAL (bit 0x80 == PAL)
- *  - ... newer boards may have more
- */
-
-static struct nvmem_cell_info dm644evm_nvmem_cells[] = {
-       {
-               .name           = "macaddr",
-               .offset         = 0x7f00,
-               .bytes          = ETH_ALEN,
-       }
-};
-
-static struct nvmem_cell_table dm644evm_nvmem_cell_table = {
-       .nvmem_name     = "1-00500",
-       .cells          = dm644evm_nvmem_cells,
-       .ncells         = ARRAY_SIZE(dm644evm_nvmem_cells),
-};
-
-static struct nvmem_cell_lookup dm644evm_nvmem_cell_lookup = {
-       .nvmem_name     = "1-00500",
-       .cell_name      = "macaddr",
-       .dev_id         = "davinci_emac.1",
-       .con_id         = "mac-address",
-};
-
-static const struct property_entry eeprom_properties[] = {
-       PROPERTY_ENTRY_U32("pagesize", 64),
-       { }
-};
-
-static const struct software_node eeprom_node = {
-       .properties = eeprom_properties,
-};
-
-/*
- * MSP430 supports RTC, card detection, input from IR remote, and
- * a bit more.  It triggers interrupts on GPIO(7) from pressing
- * buttons on the IR remote, and for card detect switches.
- */
-static struct i2c_client *dm6446evm_msp;
-
-static int dm6446evm_msp_probe(struct i2c_client *client)
-{
-       dm6446evm_msp = client;
-       return 0;
-}
-
-static int dm6446evm_msp_remove(struct i2c_client *client)
-{
-       dm6446evm_msp = NULL;
-       return 0;
-}
-
-static const struct i2c_device_id dm6446evm_msp_ids[] = {
-       { "dm6446evm_msp", 0, },
-       { /* end of list */ },
-};
-
-static struct i2c_driver dm6446evm_msp_driver = {
-       .driver.name    = "dm6446evm_msp",
-       .id_table       = dm6446evm_msp_ids,
-       .probe_new      = dm6446evm_msp_probe,
-       .remove         = dm6446evm_msp_remove,
-};
-
-static int dm6444evm_msp430_get_pins(void)
-{
-       static const char txbuf[2] = { 2, 4, };
-       char buf[4];
-       struct i2c_msg msg[2] = {
-               {
-                       .flags = 0,
-                       .len = 2,
-                       .buf = (void __force *)txbuf,
-               },
-               {
-                       .flags = I2C_M_RD,
-                       .len = 4,
-                       .buf = buf,
-               },
-       };
-       int status;
-
-       if (!dm6446evm_msp)
-               return -ENXIO;
-
-       msg[0].addr = dm6446evm_msp->addr;
-       msg[1].addr = dm6446evm_msp->addr;
-
-       /* Command 4 == get input state, returns port 2 and port3 data
-        *   S Addr W [A] len=2 [A] cmd=4 [A]
-        *   RS Addr R [A] [len=4] A [cmd=4] A [port2] A [port3] N P
-        */
-       status = i2c_transfer(dm6446evm_msp->adapter, msg, 2);
-       if (status < 0)
-               return status;
-
-       dev_dbg(&dm6446evm_msp->dev, "PINS: %4ph\n", buf);
-
-       return (buf[3] << 8) | buf[2];
-}
-
-static int dm6444evm_mmc_get_cd(int module)
-{
-       int status = dm6444evm_msp430_get_pins();
-
-       return (status < 0) ? status : !(status & BIT(1));
-}
-
-static int dm6444evm_mmc_get_ro(int module)
-{
-       int status = dm6444evm_msp430_get_pins();
-
-       return (status < 0) ? status : status & BIT(6 + 8);
-}
-
-static struct davinci_mmc_config dm6446evm_mmc_config = {
-       .get_cd         = dm6444evm_mmc_get_cd,
-       .get_ro         = dm6444evm_mmc_get_ro,
-       .wires          = 4,
-};
-
-static struct i2c_board_info __initdata i2c_info[] =  {
-       {
-               I2C_BOARD_INFO("dm6446evm_msp", 0x23),
-       },
-       {
-               I2C_BOARD_INFO("pcf8574", 0x38),
-               .platform_data  = &pcf_data_u2,
-       },
-       {
-               I2C_BOARD_INFO("pcf8574", 0x39),
-               .platform_data  = &pcf_data_u18,
-       },
-       {
-               I2C_BOARD_INFO("pcf8574", 0x3a),
-               .platform_data  = &pcf_data_u35,
-       },
-       {
-               I2C_BOARD_INFO("24c256", 0x50),
-               .swnode = &eeprom_node,
-       },
-       {
-               I2C_BOARD_INFO("tlv320aic33", 0x1b),
-       },
-};
-
-#define DM644X_I2C_SDA_PIN     GPIO_TO_PIN(2, 12)
-#define DM644X_I2C_SCL_PIN     GPIO_TO_PIN(2, 11)
-
-static struct gpiod_lookup_table i2c_recovery_gpiod_table = {
-       .dev_id = "i2c_davinci.1",
-       .table = {
-               GPIO_LOOKUP("davinci_gpio", DM644X_I2C_SDA_PIN, "sda",
-                           GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN),
-               GPIO_LOOKUP("davinci_gpio", DM644X_I2C_SCL_PIN, "scl",
-                           GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN),
-               { }
-       },
-};
-
-/* The msp430 uses a slow bitbanged I2C implementation (ergo 20 KHz),
- * which requires 100 usec of idle bus after i2c writes sent to it.
- */
-static struct davinci_i2c_platform_data i2c_pdata = {
-       .bus_freq       = 20 /* kHz */,
-       .bus_delay      = 100 /* usec */,
-       .gpio_recovery  = true,
-};
-
-static void __init evm_init_i2c(void)
-{
-       gpiod_add_lookup_table(&i2c_recovery_gpiod_table);
-       davinci_init_i2c(&i2c_pdata);
-       i2c_add_driver(&dm6446evm_msp_driver);
-       i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info));
-}
-#endif
-
-/* Fixed regulator support */
-static struct regulator_consumer_supply fixed_supplies_3_3v[] = {
-       /* Baseboard 3.3V: 5V -> TPS54310PWP -> 3.3V */
-       REGULATOR_SUPPLY("AVDD", "1-001b"),
-       REGULATOR_SUPPLY("DRVDD", "1-001b"),
-};
-
-static struct regulator_consumer_supply fixed_supplies_1_8v[] = {
-       /* Baseboard 1.8V: 5V -> TPS54310PWP -> 1.8V */
-       REGULATOR_SUPPLY("IOVDD", "1-001b"),
-       REGULATOR_SUPPLY("DVDD", "1-001b"),
-};
-
-#define VENC_STD_ALL   (V4L2_STD_NTSC | V4L2_STD_PAL)
-
-/* venc standard timings */
-static struct vpbe_enc_mode_info dm644xevm_enc_std_timing[] = {
-       {
-               .name           = "ntsc",
-               .timings_type   = VPBE_ENC_STD,
-               .std_id         = V4L2_STD_NTSC,
-               .interlaced     = 1,
-               .xres           = 720,
-               .yres           = 480,
-               .aspect         = {11, 10},
-               .fps            = {30000, 1001},
-               .left_margin    = 0x79,
-               .upper_margin   = 0x10,
-       },
-       {
-               .name           = "pal",
-               .timings_type   = VPBE_ENC_STD,
-               .std_id         = V4L2_STD_PAL,
-               .interlaced     = 1,
-               .xres           = 720,
-               .yres           = 576,
-               .aspect         = {54, 59},
-               .fps            = {25, 1},
-               .left_margin    = 0x7e,
-               .upper_margin   = 0x16,
-       },
-};
-
-/* venc dv preset timings */
-static struct vpbe_enc_mode_info dm644xevm_enc_preset_timing[] = {
-       {
-               .name           = "480p59_94",
-               .timings_type   = VPBE_ENC_DV_TIMINGS,
-               .dv_timings     = V4L2_DV_BT_CEA_720X480P59_94,
-               .interlaced     = 0,
-               .xres           = 720,
-               .yres           = 480,
-               .aspect         = {1, 1},
-               .fps            = {5994, 100},
-               .left_margin    = 0x80,
-               .upper_margin   = 0x20,
-       },
-       {
-               .name           = "576p50",
-               .timings_type   = VPBE_ENC_DV_TIMINGS,
-               .dv_timings     = V4L2_DV_BT_CEA_720X576P50,
-               .interlaced     = 0,
-               .xres           = 720,
-               .yres           = 576,
-               .aspect         = {1, 1},
-               .fps            = {50, 1},
-               .left_margin    = 0x7e,
-               .upper_margin   = 0x30,
-       },
-};
-
-/*
- * The outputs available from VPBE + encoders. Keep the order same
- * as that of encoders. First those from venc followed by that from
- * encoders. Index in the output refers to index on a particular encoder.
- * Driver uses this index to pass it to encoder when it supports more
- * than one output. Userspace applications use index of the array to
- * set an output.
- */
-static struct vpbe_output dm644xevm_vpbe_outputs[] = {
-       {
-               .output         = {
-                       .index          = 0,
-                       .name           = "Composite",
-                       .type           = V4L2_OUTPUT_TYPE_ANALOG,
-                       .std            = VENC_STD_ALL,
-                       .capabilities   = V4L2_OUT_CAP_STD,
-               },
-               .subdev_name    = DM644X_VPBE_VENC_SUBDEV_NAME,
-               .default_mode   = "ntsc",
-               .num_modes      = ARRAY_SIZE(dm644xevm_enc_std_timing),
-               .modes          = dm644xevm_enc_std_timing,
-       },
-       {
-               .output         = {
-                       .index          = 1,
-                       .name           = "Component",
-                       .type           = V4L2_OUTPUT_TYPE_ANALOG,
-                       .capabilities   = V4L2_OUT_CAP_DV_TIMINGS,
-               },
-               .subdev_name    = DM644X_VPBE_VENC_SUBDEV_NAME,
-               .default_mode   = "480p59_94",
-               .num_modes      = ARRAY_SIZE(dm644xevm_enc_preset_timing),
-               .modes          = dm644xevm_enc_preset_timing,
-       },
-};
-
-static struct vpbe_config dm644xevm_display_cfg = {
-       .module_name    = "dm644x-vpbe-display",
-       .i2c_adapter_id = 1,
-       .osd            = {
-               .module_name    = DM644X_VPBE_OSD_SUBDEV_NAME,
-       },
-       .venc           = {
-               .module_name    = DM644X_VPBE_VENC_SUBDEV_NAME,
-       },
-       .num_outputs    = ARRAY_SIZE(dm644xevm_vpbe_outputs),
-       .outputs        = dm644xevm_vpbe_outputs,
-};
-
-static struct platform_device *davinci_evm_devices[] __initdata = {
-       &davinci_fb_device,
-       &rtc_dev,
-};
-
-static void __init
-davinci_evm_map_io(void)
-{
-       dm644x_init();
-}
-
-static int davinci_phy_fixup(struct phy_device *phydev)
-{
-       unsigned int control;
-       /* CRITICAL: Fix for increasing PHY signal drive strength for
-        * TX lockup issue. On DaVinci EVM, the Intel LXT971 PHY
-        * signal strength was low causing  TX to fail randomly. The
-        * fix is to Set bit 11 (Increased MII drive strength) of PHY
-        * register 26 (Digital Config register) on this phy. */
-       control = phy_read(phydev, 26);
-       phy_write(phydev, 26, (control | 0x800));
-       return 0;
-}
-
-#define HAS_ATA                (IS_ENABLED(CONFIG_BLK_DEV_PALMCHIP_BK3710) || \
-                        IS_ENABLED(CONFIG_PATA_BK3710))
-
-#define HAS_NOR                IS_ENABLED(CONFIG_MTD_PHYSMAP)
-
-#define HAS_NAND       IS_ENABLED(CONFIG_MTD_NAND_DAVINCI)
-
-#define GPIO_nVBUS_DRV         160
-
-static struct gpiod_lookup_table dm644evm_usb_gpio_table = {
-       .dev_id = "musb-davinci",
-       .table = {
-               GPIO_LOOKUP("davinci_gpio", GPIO_nVBUS_DRV, NULL,
-                           GPIO_ACTIVE_HIGH),
-               { }
-       },
-};
-
-static __init void davinci_evm_init(void)
-{
-       int ret;
-       struct clk *aemif_clk;
-       struct davinci_soc_info *soc_info = &davinci_soc_info;
-
-       dm644x_register_clocks();
-
-       regulator_register_always_on(0, "fixed-dummy", fixed_supplies_1_8v,
-                                    ARRAY_SIZE(fixed_supplies_1_8v), 1800000);
-       regulator_register_always_on(1, "fixed-dummy", fixed_supplies_3_3v,
-                                    ARRAY_SIZE(fixed_supplies_3_3v), 3300000);
-
-       dm644x_init_devices();
-
-       ret = dm644x_gpio_register();
-       if (ret)
-               pr_warn("%s: GPIO init failed: %d\n", __func__, ret);
-
-       aemif_clk = clk_get(NULL, "aemif");
-       clk_prepare_enable(aemif_clk);
-
-       if (HAS_ATA) {
-               if (HAS_NAND || HAS_NOR)
-                       pr_warn("WARNING: both IDE and Flash are enabled, but they share AEMIF pins\n"
-                               "\tDisable IDE for NAND/NOR support\n");
-               davinci_init_ide();
-       } else if (HAS_NAND || HAS_NOR) {
-               davinci_cfg_reg(DM644X_HPIEN_DISABLE);
-               davinci_cfg_reg(DM644X_ATAEN_DISABLE);
-
-               /* only one device will be jumpered and detected */
-               if (HAS_NAND) {
-                       platform_device_register(&davinci_evm_aemif_device);
-#ifdef CONFIG_I2C
-                       evm_leds[7].default_trigger = "nand-disk";
-#endif
-                       if (HAS_NOR)
-                               pr_warn("WARNING: both NAND and NOR flash are enabled; disable one of them.\n");
-               } else if (HAS_NOR)
-                       platform_device_register(&davinci_evm_norflash_device);
-       }
-
-       platform_add_devices(davinci_evm_devices,
-                            ARRAY_SIZE(davinci_evm_devices));
-#ifdef CONFIG_I2C
-       nvmem_add_cell_table(&dm644evm_nvmem_cell_table);
-       nvmem_add_cell_lookups(&dm644evm_nvmem_cell_lookup, 1);
-       evm_init_i2c();
-       davinci_setup_mmc(0, &dm6446evm_mmc_config);
-#endif
-       dm644x_init_video(&dm644xevm_capture_cfg, &dm644xevm_display_cfg);
-
-       davinci_serial_init(dm644x_serial_device);
-       dm644x_init_asp();
-
-       /* irlml6401 switches over 1A, in under 8 msec */
-       gpiod_add_lookup_table(&dm644evm_usb_gpio_table);
-       davinci_setup_usb(1000, 8);
-
-       if (IS_BUILTIN(CONFIG_PHYLIB)) {
-               soc_info->emac_pdata->phy_id = DM644X_EVM_PHY_ID;
-               /* Register the fixup for PHY on DaVinci */
-               phy_register_fixup_for_uid(LXT971_PHY_ID, LXT971_PHY_MASK,
-                                               davinci_phy_fixup);
-       }
-}
-
-MACHINE_START(DAVINCI_EVM, "DaVinci DM644x EVM")
-       /* Maintainer: MontaVista Software <source@mvista.com> */
-       .atag_offset  = 0x100,
-       .map_io       = davinci_evm_map_io,
-       .init_irq     = dm644x_init_irq,
-       .init_time      = dm644x_init_time,
-       .init_machine = davinci_evm_init,
-       .init_late      = davinci_init_late,
-       .dma_zone_size  = SZ_128M,
-MACHINE_END
diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c
deleted file mode 100644 (file)
index 84ad065..0000000
+++ /dev/null
@@ -1,873 +0,0 @@
-/*
- * TI DaVinci DM646X EVM board
- *
- * Derived from: arch/arm/mach-davinci/board-evm.c
- * Copyright (C) 2006 Texas Instruments.
- *
- * (C) 2007-2008, MontaVista Software, Inc.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- *
- */
-
-/**************************************************************************
- * Included Files
- **************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/leds.h>
-#include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/i2c.h>
-#include <linux/property.h>
-#include <linux/platform_data/pcf857x.h>
-#include <linux/platform_data/ti-aemif.h>
-
-#include <media/i2c/tvp514x.h>
-#include <media/i2c/adv7343.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/nvmem-provider.h>
-#include <linux/clk.h>
-#include <linux/export.h>
-#include <linux/platform_data/gpio-davinci.h>
-#include <linux/platform_data/i2c-davinci.h>
-#include <linux/platform_data/mtd-davinci.h>
-#include <linux/platform_data/mtd-davinci-aemif.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-#include "common.h"
-#include "serial.h"
-#include "davinci.h"
-#include "irqs.h"
-
-#define NAND_BLOCK_SIZE                SZ_128K
-
-/* Note: We are setting first partition as 'bootloader' constituting UBL, U-Boot
- * and U-Boot environment this avoids dependency on any particular combination
- * of UBL, U-Boot or flashing tools etc.
- */
-static struct mtd_partition davinci_nand_partitions[] = {
-       {
-               /* UBL, U-Boot with environment */
-               .name           = "bootloader",
-               .offset         = MTDPART_OFS_APPEND,
-               .size           = 16 * NAND_BLOCK_SIZE,
-               .mask_flags     = MTD_WRITEABLE,        /* force read-only */
-       }, {
-               .name           = "kernel",
-               .offset         = MTDPART_OFS_APPEND,
-               .size           = SZ_4M,
-               .mask_flags     = 0,
-       }, {
-               .name           = "filesystem",
-               .offset         = MTDPART_OFS_APPEND,
-               .size           = MTDPART_SIZ_FULL,
-               .mask_flags     = 0,
-       }
-};
-
-static struct davinci_aemif_timing dm6467tevm_nandflash_timing = {
-       .wsetup         = 29,
-       .wstrobe        = 24,
-       .whold          = 14,
-       .rsetup         = 19,
-       .rstrobe        = 33,
-       .rhold          = 0,
-       .ta             = 29,
-};
-
-static struct davinci_nand_pdata davinci_nand_data = {
-       .core_chipsel           = 0,
-       .mask_cle               = 0x80000,
-       .mask_ale               = 0x40000,
-       .parts                  = davinci_nand_partitions,
-       .nr_parts               = ARRAY_SIZE(davinci_nand_partitions),
-       .engine_type            = NAND_ECC_ENGINE_TYPE_ON_HOST,
-       .ecc_bits               = 1,
-       .options                = 0,
-};
-
-static struct resource davinci_nand_resources[] = {
-       {
-               .start          = DM646X_ASYNC_EMIF_CS2_SPACE_BASE,
-               .end            = DM646X_ASYNC_EMIF_CS2_SPACE_BASE + SZ_32M - 1,
-               .flags          = IORESOURCE_MEM,
-       }, {
-               .start          = DM646X_ASYNC_EMIF_CONTROL_BASE,
-               .end            = DM646X_ASYNC_EMIF_CONTROL_BASE + SZ_4K - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-};
-
-static struct platform_device davinci_aemif_devices[] = {
-       {
-               .name           = "davinci_nand",
-               .id             = 0,
-               .num_resources  = ARRAY_SIZE(davinci_nand_resources),
-               .resource       = davinci_nand_resources,
-               .dev            = {
-                       .platform_data  = &davinci_nand_data,
-               },
-       },
-};
-
-static struct resource davinci_aemif_resources[] = {
-       {
-               .start  = DM646X_ASYNC_EMIF_CONTROL_BASE,
-               .end    = DM646X_ASYNC_EMIF_CONTROL_BASE + SZ_4K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-};
-
-static struct aemif_abus_data davinci_aemif_abus_data[] = {
-       {
-               .cs     = 1,
-       },
-};
-
-static struct aemif_platform_data davinci_aemif_pdata = {
-       .abus_data              = davinci_aemif_abus_data,
-       .num_abus_data          = ARRAY_SIZE(davinci_aemif_abus_data),
-       .sub_devices            = davinci_aemif_devices,
-       .num_sub_devices        = ARRAY_SIZE(davinci_aemif_devices),
-};
-
-static struct platform_device davinci_aemif_device = {
-       .name           = "ti-aemif",
-       .id             = -1,
-       .dev = {
-               .platform_data  = &davinci_aemif_pdata,
-       },
-       .resource       = davinci_aemif_resources,
-       .num_resources  = ARRAY_SIZE(davinci_aemif_resources),
-};
-
-#define HAS_ATA                (IS_ENABLED(CONFIG_BLK_DEV_PALMCHIP_BK3710) || \
-                        IS_ENABLED(CONFIG_PATA_BK3710))
-
-#ifdef CONFIG_I2C
-/* CPLD Register 0 bits to control ATA */
-#define DM646X_EVM_ATA_RST             BIT(0)
-#define DM646X_EVM_ATA_PWD             BIT(1)
-
-/* CPLD Register 0 Client: used for I/O Control */
-static int cpld_reg0_probe(struct i2c_client *client)
-{
-       if (HAS_ATA) {
-               u8 data;
-               struct i2c_msg msg[2] = {
-                       {
-                               .addr = client->addr,
-                               .flags = I2C_M_RD,
-                               .len = 1,
-                               .buf = &data,
-                       },
-                       {
-                               .addr = client->addr,
-                               .flags = 0,
-                               .len = 1,
-                               .buf = &data,
-                       },
-               };
-
-               /* Clear ATA_RSTn and ATA_PWD bits to enable ATA operation. */
-               i2c_transfer(client->adapter, msg, 1);
-               data &= ~(DM646X_EVM_ATA_RST | DM646X_EVM_ATA_PWD);
-               i2c_transfer(client->adapter, msg + 1, 1);
-       }
-
-       return 0;
-}
-
-static const struct i2c_device_id cpld_reg_ids[] = {
-       { "cpld_reg0", 0, },
-       { },
-};
-
-static struct i2c_driver dm6467evm_cpld_driver = {
-       .driver.name    = "cpld_reg0",
-       .id_table       = cpld_reg_ids,
-       .probe_new      = cpld_reg0_probe,
-};
-
-/* LEDS */
-
-static struct gpio_led evm_leds[] = {
-       { .name = "DS1", .active_low = 1, },
-       { .name = "DS2", .active_low = 1, },
-       { .name = "DS3", .active_low = 1, },
-       { .name = "DS4", .active_low = 1, },
-};
-
-static const struct gpio_led_platform_data evm_led_data = {
-       .num_leds = ARRAY_SIZE(evm_leds),
-       .leds     = evm_leds,
-};
-
-static struct platform_device *evm_led_dev;
-
-static int evm_led_setup(struct i2c_client *client, int gpio,
-                       unsigned int ngpio, void *c)
-{
-       struct gpio_led *leds = evm_leds;
-       int status;
-
-       while (ngpio--) {
-               leds->gpio = gpio++;
-               leds++;
-       }
-
-       evm_led_dev = platform_device_alloc("leds-gpio", 0);
-       platform_device_add_data(evm_led_dev, &evm_led_data,
-                               sizeof(evm_led_data));
-
-       evm_led_dev->dev.parent = &client->dev;
-       status = platform_device_add(evm_led_dev);
-       if (status < 0) {
-               platform_device_put(evm_led_dev);
-               evm_led_dev = NULL;
-       }
-       return status;
-}
-
-static int evm_led_teardown(struct i2c_client *client, int gpio,
-                               unsigned ngpio, void *c)
-{
-       if (evm_led_dev) {
-               platform_device_unregister(evm_led_dev);
-               evm_led_dev = NULL;
-       }
-       return 0;
-}
-
-static int evm_sw_gpio[4] = { -EINVAL, -EINVAL, -EINVAL, -EINVAL };
-
-static int evm_sw_setup(struct i2c_client *client, int gpio,
-                       unsigned ngpio, void *c)
-{
-       int status;
-       int i;
-       char label[10];
-
-       for (i = 0; i < 4; ++i) {
-               snprintf(label, 10, "user_sw%d", i);
-               status = gpio_request(gpio, label);
-               if (status)
-                       goto out_free;
-               evm_sw_gpio[i] = gpio++;
-
-               status = gpio_direction_input(evm_sw_gpio[i]);
-               if (status)
-                       goto out_free;
-
-               status = gpio_export(evm_sw_gpio[i], 0);
-               if (status)
-                       goto out_free;
-       }
-       return 0;
-
-out_free:
-       for (i = 0; i < 4; ++i) {
-               if (evm_sw_gpio[i] != -EINVAL) {
-                       gpio_free(evm_sw_gpio[i]);
-                       evm_sw_gpio[i] = -EINVAL;
-               }
-       }
-       return status;
-}
-
-static int evm_sw_teardown(struct i2c_client *client, int gpio,
-                       unsigned ngpio, void *c)
-{
-       int i;
-
-       for (i = 0; i < 4; ++i) {
-               if (evm_sw_gpio[i] != -EINVAL) {
-                       gpio_unexport(evm_sw_gpio[i]);
-                       gpio_free(evm_sw_gpio[i]);
-                       evm_sw_gpio[i] = -EINVAL;
-               }
-       }
-       return 0;
-}
-
-static int evm_pcf_setup(struct i2c_client *client, int gpio,
-                       unsigned int ngpio, void *c)
-{
-       int status;
-
-       if (ngpio < 8)
-               return -EINVAL;
-
-       status = evm_sw_setup(client, gpio, 4, c);
-       if (status)
-               return status;
-
-       return evm_led_setup(client, gpio+4, 4, c);
-}
-
-static void evm_pcf_teardown(struct i2c_client *client, int gpio,
-                       unsigned int ngpio, void *c)
-{
-       BUG_ON(ngpio < 8);
-
-       evm_sw_teardown(client, gpio, 4, c);
-       evm_led_teardown(client, gpio+4, 4, c);
-}
-
-static struct pcf857x_platform_data pcf_data = {
-       .gpio_base      = DAVINCI_N_GPIO+1,
-       .setup          = evm_pcf_setup,
-       .teardown       = evm_pcf_teardown,
-};
-
-/* Most of this EEPROM is unused, but U-Boot uses some data:
- *  - 0x7f00, 6 bytes Ethernet Address
- *  - ... newer boards may have more
- */
-
-static struct nvmem_cell_info dm646x_evm_nvmem_cells[] = {
-       {
-               .name           = "macaddr",
-               .offset         = 0x7f00,
-               .bytes          = ETH_ALEN,
-       }
-};
-
-static struct nvmem_cell_table dm646x_evm_nvmem_cell_table = {
-       .nvmem_name     = "1-00500",
-       .cells          = dm646x_evm_nvmem_cells,
-       .ncells         = ARRAY_SIZE(dm646x_evm_nvmem_cells),
-};
-
-static struct nvmem_cell_lookup dm646x_evm_nvmem_cell_lookup = {
-       .nvmem_name     = "1-00500",
-       .cell_name      = "macaddr",
-       .dev_id         = "davinci_emac.1",
-       .con_id         = "mac-address",
-};
-
-static const struct property_entry eeprom_properties[] = {
-       PROPERTY_ENTRY_U32("pagesize", 64),
-       { }
-};
-
-static const struct software_node eeprom_node = {
-       .properties = eeprom_properties,
-};
-#endif
-
-static u8 dm646x_iis_serializer_direction[] = {
-       TX_MODE, RX_MODE, INACTIVE_MODE, INACTIVE_MODE,
-};
-
-static u8 dm646x_dit_serializer_direction[] = {
-       TX_MODE,
-};
-
-static struct snd_platform_data dm646x_evm_snd_data[] = {
-       {
-               .tx_dma_offset  = 0x400,
-               .rx_dma_offset  = 0x400,
-               .op_mode        = DAVINCI_MCASP_IIS_MODE,
-               .num_serializer = ARRAY_SIZE(dm646x_iis_serializer_direction),
-               .tdm_slots      = 2,
-               .serial_dir     = dm646x_iis_serializer_direction,
-               .asp_chan_q     = EVENTQ_0,
-       },
-       {
-               .tx_dma_offset  = 0x400,
-               .rx_dma_offset  = 0,
-               .op_mode        = DAVINCI_MCASP_DIT_MODE,
-               .num_serializer = ARRAY_SIZE(dm646x_dit_serializer_direction),
-               .tdm_slots      = 32,
-               .serial_dir     = dm646x_dit_serializer_direction,
-               .asp_chan_q     = EVENTQ_0,
-       },
-};
-
-#ifdef CONFIG_I2C
-static struct i2c_client *cpld_client;
-
-static int cpld_video_probe(struct i2c_client *client)
-{
-       cpld_client = client;
-       return 0;
-}
-
-static int cpld_video_remove(struct i2c_client *client)
-{
-       cpld_client = NULL;
-       return 0;
-}
-
-static const struct i2c_device_id cpld_video_id[] = {
-       { "cpld_video", 0 },
-       { }
-};
-
-static struct i2c_driver cpld_video_driver = {
-       .driver = {
-               .name   = "cpld_video",
-       },
-       .probe_new      = cpld_video_probe,
-       .remove         = cpld_video_remove,
-       .id_table       = cpld_video_id,
-};
-
-static void evm_init_cpld(void)
-{
-       i2c_add_driver(&cpld_video_driver);
-}
-
-static struct i2c_board_info __initdata i2c_info[] =  {
-       {
-               I2C_BOARD_INFO("24c256", 0x50),
-               .swnode = &eeprom_node,
-       },
-       {
-               I2C_BOARD_INFO("pcf8574a", 0x38),
-               .platform_data  = &pcf_data,
-       },
-       {
-               I2C_BOARD_INFO("cpld_reg0", 0x3a),
-       },
-       {
-               I2C_BOARD_INFO("tlv320aic33", 0x18),
-       },
-       {
-               I2C_BOARD_INFO("cpld_video", 0x3b),
-       },
-};
-
-static struct davinci_i2c_platform_data i2c_pdata = {
-       .bus_freq       = 100 /* kHz */,
-       .bus_delay      = 0 /* usec */,
-};
-
-#define VCH2CLK_MASK           (BIT_MASK(10) | BIT_MASK(9) | BIT_MASK(8))
-#define VCH2CLK_SYSCLK8                (BIT(9))
-#define VCH2CLK_AUXCLK         (BIT(9) | BIT(8))
-#define VCH3CLK_MASK           (BIT_MASK(14) | BIT_MASK(13) | BIT_MASK(12))
-#define VCH3CLK_SYSCLK8                (BIT(13))
-#define VCH3CLK_AUXCLK         (BIT(14) | BIT(13))
-
-#define VIDCH2CLK              (BIT(10))
-#define VIDCH3CLK              (BIT(11))
-#define VIDCH1CLK              (BIT(4))
-#define TVP7002_INPUT          (BIT(4))
-#define TVP5147_INPUT          (~BIT(4))
-#define VPIF_INPUT_ONE_CHANNEL (BIT(5))
-#define VPIF_INPUT_TWO_CHANNEL (~BIT(5))
-#define TVP5147_CH0            "tvp514x-0"
-#define TVP5147_CH1            "tvp514x-1"
-
-/* spin lock for updating above registers */
-static spinlock_t vpif_reg_lock;
-
-static int set_vpif_clock(int mux_mode, int hd)
-{
-       unsigned long flags;
-       unsigned int value;
-       int val = 0;
-       int err = 0;
-
-       if (!cpld_client)
-               return -ENXIO;
-
-       /* disable the clock */
-       spin_lock_irqsave(&vpif_reg_lock, flags);
-       value = __raw_readl(DAVINCI_SYSMOD_VIRT(SYSMOD_VSCLKDIS));
-       value |= (VIDCH3CLK | VIDCH2CLK);
-       __raw_writel(value, DAVINCI_SYSMOD_VIRT(SYSMOD_VSCLKDIS));
-       spin_unlock_irqrestore(&vpif_reg_lock, flags);
-
-       val = i2c_smbus_read_byte(cpld_client);
-       if (val < 0)
-               return val;
-
-       if (mux_mode == 1)
-               val &= ~0x40;
-       else
-               val |= 0x40;
-
-       err = i2c_smbus_write_byte(cpld_client, val);
-       if (err)
-               return err;
-
-       value = __raw_readl(DAVINCI_SYSMOD_VIRT(SYSMOD_VIDCLKCTL));
-       value &= ~(VCH2CLK_MASK);
-       value &= ~(VCH3CLK_MASK);
-
-       if (hd >= 1)
-               value |= (VCH2CLK_SYSCLK8 | VCH3CLK_SYSCLK8);
-       else
-               value |= (VCH2CLK_AUXCLK | VCH3CLK_AUXCLK);
-
-       __raw_writel(value, DAVINCI_SYSMOD_VIRT(SYSMOD_VIDCLKCTL));
-
-       spin_lock_irqsave(&vpif_reg_lock, flags);
-       value = __raw_readl(DAVINCI_SYSMOD_VIRT(SYSMOD_VSCLKDIS));
-       /* enable the clock */
-       value &= ~(VIDCH3CLK | VIDCH2CLK);
-       __raw_writel(value, DAVINCI_SYSMOD_VIRT(SYSMOD_VSCLKDIS));
-       spin_unlock_irqrestore(&vpif_reg_lock, flags);
-
-       return 0;
-}
-
-static struct vpif_subdev_info dm646x_vpif_subdev[] = {
-       {
-               .name   = "adv7343",
-               .board_info = {
-                       I2C_BOARD_INFO("adv7343", 0x2a),
-               },
-       },
-       {
-               .name   = "ths7303",
-               .board_info = {
-                       I2C_BOARD_INFO("ths7303", 0x2c),
-               },
-       },
-};
-
-static const struct vpif_output dm6467_ch0_outputs[] = {
-       {
-               .output = {
-                       .index = 0,
-                       .name = "Composite",
-                       .type = V4L2_OUTPUT_TYPE_ANALOG,
-                       .capabilities = V4L2_OUT_CAP_STD,
-                       .std = V4L2_STD_ALL,
-               },
-               .subdev_name = "adv7343",
-               .output_route = ADV7343_COMPOSITE_ID,
-       },
-       {
-               .output = {
-                       .index = 1,
-                       .name = "Component",
-                       .type = V4L2_OUTPUT_TYPE_ANALOG,
-                       .capabilities = V4L2_OUT_CAP_DV_TIMINGS,
-               },
-               .subdev_name = "adv7343",
-               .output_route = ADV7343_COMPONENT_ID,
-       },
-       {
-               .output = {
-                       .index = 2,
-                       .name = "S-Video",
-                       .type = V4L2_OUTPUT_TYPE_ANALOG,
-                       .capabilities = V4L2_OUT_CAP_STD,
-                       .std = V4L2_STD_ALL,
-               },
-               .subdev_name = "adv7343",
-               .output_route = ADV7343_SVIDEO_ID,
-       },
-};
-
-static struct vpif_display_config dm646x_vpif_display_config = {
-       .set_clock      = set_vpif_clock,
-       .subdevinfo     = dm646x_vpif_subdev,
-       .subdev_count   = ARRAY_SIZE(dm646x_vpif_subdev),
-       .i2c_adapter_id = 1,
-       .chan_config[0] = {
-               .outputs = dm6467_ch0_outputs,
-               .output_count = ARRAY_SIZE(dm6467_ch0_outputs),
-       },
-       .card_name      = "DM646x EVM Video Display",
-};
-
-/**
- * setup_vpif_input_path()
- * @channel: channel id (0 - CH0, 1 - CH1)
- * @sub_dev_name: ptr sub device name
- *
- * This will set vpif input to capture data from tvp514x or
- * tvp7002.
- */
-static int setup_vpif_input_path(int channel, const char *sub_dev_name)
-{
-       int err = 0;
-       int val;
-
-       /* for channel 1, we don't do anything */
-       if (channel != 0)
-               return 0;
-
-       if (!cpld_client)
-               return -ENXIO;
-
-       val = i2c_smbus_read_byte(cpld_client);
-       if (val < 0)
-               return val;
-
-       if (!strcmp(sub_dev_name, TVP5147_CH0) ||
-           !strcmp(sub_dev_name, TVP5147_CH1))
-               val &= TVP5147_INPUT;
-       else
-               val |= TVP7002_INPUT;
-
-       err = i2c_smbus_write_byte(cpld_client, val);
-       if (err)
-               return err;
-       return 0;
-}
-
-/**
- * setup_vpif_input_channel_mode()
- * @mux_mode:  mux mode. 0 - 1 channel or (1) - 2 channel
- *
- * This will setup input mode to one channel (TVP7002) or 2 channel (TVP5147)
- */
-static int setup_vpif_input_channel_mode(int mux_mode)
-{
-       unsigned long flags;
-       int err = 0;
-       int val;
-       u32 value;
-
-       if (!cpld_client)
-               return -ENXIO;
-
-       val = i2c_smbus_read_byte(cpld_client);
-       if (val < 0)
-               return val;
-
-       spin_lock_irqsave(&vpif_reg_lock, flags);
-       value = __raw_readl(DAVINCI_SYSMOD_VIRT(SYSMOD_VIDCLKCTL));
-       if (mux_mode) {
-               val &= VPIF_INPUT_TWO_CHANNEL;
-               value |= VIDCH1CLK;
-       } else {
-               val |= VPIF_INPUT_ONE_CHANNEL;
-               value &= ~VIDCH1CLK;
-       }
-       __raw_writel(value, DAVINCI_SYSMOD_VIRT(SYSMOD_VIDCLKCTL));
-       spin_unlock_irqrestore(&vpif_reg_lock, flags);
-
-       err = i2c_smbus_write_byte(cpld_client, val);
-       if (err)
-               return err;
-
-       return 0;
-}
-
-static struct tvp514x_platform_data tvp5146_pdata = {
-       .clk_polarity = 0,
-       .hs_polarity = 1,
-       .vs_polarity = 1
-};
-
-#define TVP514X_STD_ALL (V4L2_STD_NTSC | V4L2_STD_PAL)
-
-static struct vpif_subdev_info vpif_capture_sdev_info[] = {
-       {
-               .name   = TVP5147_CH0,
-               .board_info = {
-                       I2C_BOARD_INFO("tvp5146", 0x5d),
-                       .platform_data = &tvp5146_pdata,
-               },
-       },
-       {
-               .name   = TVP5147_CH1,
-               .board_info = {
-                       I2C_BOARD_INFO("tvp5146", 0x5c),
-                       .platform_data = &tvp5146_pdata,
-               },
-       },
-};
-
-static struct vpif_input dm6467_ch0_inputs[] = {
-       {
-               .input = {
-                       .index = 0,
-                       .name = "Composite",
-                       .type = V4L2_INPUT_TYPE_CAMERA,
-                       .capabilities = V4L2_IN_CAP_STD,
-                       .std = TVP514X_STD_ALL,
-               },
-               .subdev_name = TVP5147_CH0,
-               .input_route = INPUT_CVBS_VI2B,
-               .output_route = OUTPUT_10BIT_422_EMBEDDED_SYNC,
-       },
-};
-
-static struct vpif_input dm6467_ch1_inputs[] = {
-       {
-               .input = {
-                       .index = 0,
-                       .name = "S-Video",
-                       .type = V4L2_INPUT_TYPE_CAMERA,
-                       .capabilities = V4L2_IN_CAP_STD,
-                       .std = TVP514X_STD_ALL,
-               },
-               .subdev_name = TVP5147_CH1,
-               .input_route = INPUT_SVIDEO_VI2C_VI1C,
-               .output_route = OUTPUT_10BIT_422_EMBEDDED_SYNC,
-       },
-};
-
-static struct vpif_capture_config dm646x_vpif_capture_cfg = {
-       .setup_input_path = setup_vpif_input_path,
-       .setup_input_channel_mode = setup_vpif_input_channel_mode,
-       .subdev_info = vpif_capture_sdev_info,
-       .subdev_count = ARRAY_SIZE(vpif_capture_sdev_info),
-       .i2c_adapter_id = 1,
-       .chan_config[0] = {
-               .inputs = dm6467_ch0_inputs,
-               .input_count = ARRAY_SIZE(dm6467_ch0_inputs),
-               .vpif_if = {
-                       .if_type = VPIF_IF_BT656,
-                       .hd_pol = 1,
-                       .vd_pol = 1,
-                       .fid_pol = 0,
-               },
-       },
-       .chan_config[1] = {
-               .inputs = dm6467_ch1_inputs,
-               .input_count = ARRAY_SIZE(dm6467_ch1_inputs),
-               .vpif_if = {
-                       .if_type = VPIF_IF_BT656,
-                       .hd_pol = 1,
-                       .vd_pol = 1,
-                       .fid_pol = 0,
-               },
-       },
-       .card_name = "DM646x EVM Video Capture",
-};
-
-static void __init evm_init_video(void)
-{
-       spin_lock_init(&vpif_reg_lock);
-
-       dm646x_setup_vpif(&dm646x_vpif_display_config,
-                         &dm646x_vpif_capture_cfg);
-}
-
-static void __init evm_init_i2c(void)
-{
-       davinci_init_i2c(&i2c_pdata);
-       i2c_add_driver(&dm6467evm_cpld_driver);
-       i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info));
-       evm_init_cpld();
-       evm_init_video();
-}
-#endif
-
-#define DM646X_REF_FREQ                        27000000
-#define DM646X_AUX_FREQ                        24000000
-#define DM6467T_EVM_REF_FREQ           33000000
-
-static void __init davinci_map_io(void)
-{
-       dm646x_init();
-}
-
-static void __init dm646x_evm_init_time(void)
-{
-       dm646x_init_time(DM646X_REF_FREQ, DM646X_AUX_FREQ);
-}
-
-static void __init dm6467t_evm_init_time(void)
-{
-       dm646x_init_time(DM6467T_EVM_REF_FREQ, DM646X_AUX_FREQ);
-}
-
-#define DM646X_EVM_PHY_ID              "davinci_mdio-0:01"
-/*
- * The following EDMA channels/slots are not being used by drivers (for
- * example: Timer, GPIO, UART events etc) on dm646x, hence they are being
- * reserved for codecs on the DSP side.
- */
-static const s16 dm646x_dma_rsv_chans[][2] = {
-       /* (offset, number) */
-       { 0,  4},
-       {13,  3},
-       {24,  4},
-       {30,  2},
-       {54,  3},
-       {-1, -1}
-};
-
-static const s16 dm646x_dma_rsv_slots[][2] = {
-       /* (offset, number) */
-       { 0,  4},
-       {13,  3},
-       {24,  4},
-       {30,  2},
-       {54,  3},
-       {128, 384},
-       {-1, -1}
-};
-
-static struct edma_rsv_info dm646x_edma_rsv[] = {
-       {
-               .rsv_chans      = dm646x_dma_rsv_chans,
-               .rsv_slots      = dm646x_dma_rsv_slots,
-       },
-};
-
-static __init void evm_init(void)
-{
-       int ret;
-       struct davinci_soc_info *soc_info = &davinci_soc_info;
-
-       dm646x_register_clocks();
-
-       ret = dm646x_gpio_register();
-       if (ret)
-               pr_warn("%s: GPIO init failed: %d\n", __func__, ret);
-
-#ifdef CONFIG_I2C
-       nvmem_add_cell_table(&dm646x_evm_nvmem_cell_table);
-       nvmem_add_cell_lookups(&dm646x_evm_nvmem_cell_lookup, 1);
-       evm_init_i2c();
-#endif
-
-       davinci_serial_init(dm646x_serial_device);
-       dm646x_init_mcasp0(&dm646x_evm_snd_data[0]);
-       dm646x_init_mcasp1(&dm646x_evm_snd_data[1]);
-
-       if (machine_is_davinci_dm6467tevm())
-               davinci_nand_data.timing = &dm6467tevm_nandflash_timing;
-
-       if (platform_device_register(&davinci_aemif_device))
-               pr_warn("%s: Cannot register AEMIF device.\n", __func__);
-
-       dm646x_init_edma(dm646x_edma_rsv);
-
-       if (HAS_ATA)
-               davinci_init_ide();
-
-       soc_info->emac_pdata->phy_id = DM646X_EVM_PHY_ID;
-}
-
-MACHINE_START(DAVINCI_DM6467_EVM, "DaVinci DM646x EVM")
-       .atag_offset  = 0x100,
-       .map_io       = davinci_map_io,
-       .init_irq     = dm646x_init_irq,
-       .init_time      = dm646x_evm_init_time,
-       .init_machine = evm_init,
-       .init_late      = davinci_init_late,
-       .dma_zone_size  = SZ_128M,
-MACHINE_END
-
-MACHINE_START(DAVINCI_DM6467TEVM, "DaVinci DM6467T EVM")
-       .atag_offset  = 0x100,
-       .map_io       = davinci_map_io,
-       .init_irq     = dm646x_init_irq,
-       .init_time      = dm6467t_evm_init_time,
-       .init_machine = evm_init,
-       .init_late      = davinci_init_late,
-       .dma_zone_size  = SZ_128M,
-MACHINE_END
-
diff --git a/arch/arm/mach-davinci/board-neuros-osd2.c b/arch/arm/mach-davinci/board-neuros-osd2.c
deleted file mode 100644 (file)
index 94be492..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Neuros Technologies OSD2 board support
- *
- * Modified from original 644X-EVM board support.
- * 2008 (c) Neuros Technology, LLC.
- * 2009 (c) Jorge Luis Zapata Muga <jorgeluis.zapata@gmail.com>
- * 2009 (c) Andrey A. Porodko <Andrey.Porodko@gmail.com>
- *
- * The Neuros OSD 2.0 is the hardware component of the Neuros Open
- * Internet Television Platform. Hardware is very close to TI
- * DM644X-EVM board. It has:
- *     DM6446M02 module with 256MB NAND, 256MB RAM, TLV320AIC32 AIC,
- *     USB, Ethernet, SD/MMC, UART, THS8200, TVP7000 for video.
- *     Additionally realtime clock, IR remote control receiver,
- *     IR Blaster based on MSP430 (firmware although is different
- *     from used in DM644X-EVM), internal ATA-6 3.5” HDD drive
- *     with PATA interface, two muxed red-green leds.
- *
- * For more information please refer to
- *             http://wiki.neurostechnology.com/index.php/OSD_2.0_HD
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/leds.h>
-#include <linux/mtd/partitions.h>
-#include <linux/platform_data/gpio-davinci.h>
-#include <linux/platform_data/i2c-davinci.h>
-#include <linux/platform_data/mmc-davinci.h>
-#include <linux/platform_data/mtd-davinci.h>
-#include <linux/platform_data/usb-davinci.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-#include "common.h"
-#include "serial.h"
-#include "mux.h"
-#include "davinci.h"
-
-#define NEUROS_OSD2_PHY_ID             "davinci_mdio-0:01"
-#define LXT971_PHY_ID                  0x001378e2
-#define LXT971_PHY_MASK                        0xfffffff0
-
-#define        NTOSD2_AUDIOSOC_I2C_ADDR        0x18
-#define        NTOSD2_MSP430_I2C_ADDR          0x59
-#define        NTOSD2_MSP430_IRQ               2
-
-/* Neuros OSD2 has a Samsung 256 MByte NAND flash (Dev ID of 0xAA,
- * 2048 blocks in the device, 64 pages per block, 2048 bytes per
- * page.
- */
-
-#define NAND_BLOCK_SIZE                SZ_128K
-
-static struct mtd_partition davinci_ntosd2_nandflash_partition[] = {
-       {
-               /* UBL (a few copies) plus U-Boot */
-               .name           = "bootloader",
-               .offset         = 0,
-               .size           = 15 * NAND_BLOCK_SIZE,
-               .mask_flags     = MTD_WRITEABLE, /* force read-only */
-       }, {
-               /* U-Boot environment */
-               .name           = "params",
-               .offset         = MTDPART_OFS_APPEND,
-               .size           = 1 * NAND_BLOCK_SIZE,
-               .mask_flags     = 0,
-       }, {
-               /* Kernel */
-               .name           = "kernel",
-               .offset         = MTDPART_OFS_APPEND,
-               .size           = SZ_4M,
-               .mask_flags     = 0,
-       }, {
-               /* File System */
-               .name           = "filesystem",
-               .offset         = MTDPART_OFS_APPEND,
-               .size           = MTDPART_SIZ_FULL,
-               .mask_flags     = 0,
-       }
-       /* A few blocks at end hold a flash Bad Block Table. */
-};
-
-static struct davinci_nand_pdata davinci_ntosd2_nandflash_data = {
-       .core_chipsel   = 0,
-       .parts          = davinci_ntosd2_nandflash_partition,
-       .nr_parts       = ARRAY_SIZE(davinci_ntosd2_nandflash_partition),
-       .engine_type    = NAND_ECC_ENGINE_TYPE_ON_HOST,
-       .ecc_bits       = 1,
-       .bbt_options    = NAND_BBT_USE_FLASH,
-};
-
-static struct resource davinci_ntosd2_nandflash_resource[] = {
-       {
-               .start          = DM644X_ASYNC_EMIF_DATA_CE0_BASE,
-               .end            = DM644X_ASYNC_EMIF_DATA_CE0_BASE + SZ_16M - 1,
-               .flags          = IORESOURCE_MEM,
-       }, {
-               .start          = DM644X_ASYNC_EMIF_CONTROL_BASE,
-               .end            = DM644X_ASYNC_EMIF_CONTROL_BASE + SZ_4K - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-};
-
-static struct platform_device davinci_ntosd2_nandflash_device = {
-       .name           = "davinci_nand",
-       .id             = 0,
-       .dev            = {
-               .platform_data  = &davinci_ntosd2_nandflash_data,
-       },
-       .num_resources  = ARRAY_SIZE(davinci_ntosd2_nandflash_resource),
-       .resource       = davinci_ntosd2_nandflash_resource,
-};
-
-static u64 davinci_fb_dma_mask = DMA_BIT_MASK(32);
-
-static struct platform_device davinci_fb_device = {
-       .name           = "davincifb",
-       .id             = -1,
-       .dev = {
-               .dma_mask               = &davinci_fb_dma_mask,
-               .coherent_dma_mask      = DMA_BIT_MASK(32),
-       },
-       .num_resources = 0,
-};
-
-static const struct gpio_led ntosd2_leds[] = {
-       { .name = "led1_green", .gpio = 10, },
-       { .name = "led1_red",   .gpio = 11, },
-       { .name = "led2_green", .gpio = 12, },
-       { .name = "led2_red",   .gpio = 13, },
-};
-
-static struct gpio_led_platform_data ntosd2_leds_data = {
-       .num_leds       = ARRAY_SIZE(ntosd2_leds),
-       .leds           = ntosd2_leds,
-};
-
-static struct platform_device ntosd2_leds_dev = {
-       .name = "leds-gpio",
-       .id   = -1,
-       .dev = {
-               .platform_data          = &ntosd2_leds_data,
-       },
-};
-
-
-static struct platform_device *davinci_ntosd2_devices[] __initdata = {
-       &davinci_fb_device,
-       &ntosd2_leds_dev,
-};
-
-static void __init davinci_ntosd2_map_io(void)
-{
-       dm644x_init();
-}
-
-static struct davinci_mmc_config davinci_ntosd2_mmc_config = {
-       .wires          = 4,
-};
-
-#define HAS_ATA                (IS_ENABLED(CONFIG_BLK_DEV_PALMCHIP_BK3710) || \
-                        IS_ENABLED(CONFIG_PATA_BK3710))
-
-#define HAS_NAND       IS_ENABLED(CONFIG_MTD_NAND_DAVINCI)
-
-static __init void davinci_ntosd2_init(void)
-{
-       int ret;
-       struct clk *aemif_clk;
-       struct davinci_soc_info *soc_info = &davinci_soc_info;
-
-       dm644x_register_clocks();
-
-       dm644x_init_devices();
-
-       ret = dm644x_gpio_register();
-       if (ret)
-               pr_warn("%s: GPIO init failed: %d\n", __func__, ret);
-
-       aemif_clk = clk_get(NULL, "aemif");
-       clk_prepare_enable(aemif_clk);
-
-       if (HAS_ATA) {
-               if (HAS_NAND)
-                       pr_warn("WARNING: both IDE and Flash are enabled, but they share AEMIF pins\n"
-                               "\tDisable IDE for NAND/NOR support\n");
-               davinci_init_ide();
-       } else if (HAS_NAND) {
-               davinci_cfg_reg(DM644X_HPIEN_DISABLE);
-               davinci_cfg_reg(DM644X_ATAEN_DISABLE);
-
-               /* only one device will be jumpered and detected */
-               if (HAS_NAND)
-                       platform_device_register(
-                                       &davinci_ntosd2_nandflash_device);
-       }
-
-       platform_add_devices(davinci_ntosd2_devices,
-                               ARRAY_SIZE(davinci_ntosd2_devices));
-
-       davinci_serial_init(dm644x_serial_device);
-       dm644x_init_asp();
-
-       soc_info->emac_pdata->phy_id = NEUROS_OSD2_PHY_ID;
-
-       davinci_setup_usb(1000, 8);
-       /*
-        * Mux the pins to be GPIOs, VLYNQEN is already done at startup.
-        * The AEAWx are five new AEAW pins that can be muxed by separately.
-        * They are a bitmask for GPIO management. According TI
-        * documentation (https://www.ti.com/lit/gpn/tms320dm6446) to employ
-        * gpio(10,11,12,13) for leds any combination of bits works except
-        * four last. So we are to reset all five.
-        */
-       davinci_cfg_reg(DM644X_AEAW0);
-       davinci_cfg_reg(DM644X_AEAW1);
-       davinci_cfg_reg(DM644X_AEAW2);
-       davinci_cfg_reg(DM644X_AEAW3);
-       davinci_cfg_reg(DM644X_AEAW4);
-
-       davinci_setup_mmc(0, &davinci_ntosd2_mmc_config);
-}
-
-MACHINE_START(NEUROS_OSD2, "Neuros OSD2")
-       /* Maintainer: Neuros Technologies <neuros@groups.google.com> */
-       .atag_offset    = 0x100,
-       .map_io          = davinci_ntosd2_map_io,
-       .init_irq       = dm644x_init_irq,
-       .init_time      = dm644x_init_time,
-       .init_machine = davinci_ntosd2_init,
-       .init_late      = davinci_init_late,
-       .dma_zone_size  = SZ_128M,
-MACHINE_END
diff --git a/arch/arm/mach-davinci/board-sffsdr.c b/arch/arm/mach-davinci/board-sffsdr.c
deleted file mode 100644 (file)
index e87fd8f..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Lyrtech SFFSDR board support.
- *
- * Copyright (C) 2008 Philip Balister, OpenSDR <philip@opensdr.com>
- * Copyright (C) 2008 Lyrtech <www.lyrtech.com>
- *
- * Based on DV-EVM platform, original copyright follows:
- *
- * Copyright (C) 2007 MontaVista Software, Inc.
- */
-
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/i2c.h>
-#include <linux/property.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/flash.h>
-
-#include <linux/platform_data/i2c-davinci.h>
-#include <linux/platform_data/usb-davinci.h>
-
-#include "common.h"
-#include "serial.h"
-#include "mux.h"
-#include "davinci.h"
-
-#define SFFSDR_PHY_ID          "davinci_mdio-0:01"
-static struct mtd_partition davinci_sffsdr_nandflash_partition[] = {
-       /* U-Boot Environment: Block 0
-        * UBL:                Block 1
-        * U-Boot:             Blocks 6-7 (256 kb)
-        * Integrity Kernel:   Blocks 8-31 (3 Mb)
-        * Integrity Data:     Blocks 100-END
-        */
-       {
-               .name           = "Linux Kernel",
-               .offset         = 32 * SZ_128K,
-               .size           = 16 * SZ_128K, /* 2 Mb */
-               .mask_flags     = MTD_WRITEABLE, /* Force read-only */
-       },
-       {
-               .name           = "Linux ROOT",
-               .offset         = MTDPART_OFS_APPEND,
-               .size           = 256 * SZ_128K, /* 32 Mb */
-               .mask_flags     = 0, /* R/W */
-       },
-};
-
-static struct flash_platform_data davinci_sffsdr_nandflash_data = {
-       .parts          = davinci_sffsdr_nandflash_partition,
-       .nr_parts       = ARRAY_SIZE(davinci_sffsdr_nandflash_partition),
-};
-
-static struct resource davinci_sffsdr_nandflash_resource[] = {
-       {
-               .start          = DM644X_ASYNC_EMIF_DATA_CE0_BASE,
-               .end            = DM644X_ASYNC_EMIF_DATA_CE0_BASE + SZ_16M - 1,
-               .flags          = IORESOURCE_MEM,
-       }, {
-               .start          = DM644X_ASYNC_EMIF_CONTROL_BASE,
-               .end            = DM644X_ASYNC_EMIF_CONTROL_BASE + SZ_4K - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-};
-
-static struct platform_device davinci_sffsdr_nandflash_device = {
-       .name           = "davinci_nand", /* Name of driver */
-       .id             = 0,
-       .dev            = {
-               .platform_data  = &davinci_sffsdr_nandflash_data,
-       },
-       .num_resources  = ARRAY_SIZE(davinci_sffsdr_nandflash_resource),
-       .resource       = davinci_sffsdr_nandflash_resource,
-};
-
-static const struct property_entry eeprom_properties[] = {
-       PROPERTY_ENTRY_U32("pagesize", 32),
-       { }
-};
-
-static const struct software_node eeprom_node = {
-       .properties = eeprom_properties,
-};
-
-static struct i2c_board_info __initdata i2c_info[] =  {
-       {
-               I2C_BOARD_INFO("24c64", 0x50),
-               .swnode = &eeprom_node,
-       },
-       /* Other I2C devices:
-        * MSP430,  addr 0x23 (not used)
-        * PCA9543, addr 0x70 (setup done by U-Boot)
-        * ADS7828, addr 0x48 (ADC for voltage monitoring.)
-        */
-};
-
-static struct davinci_i2c_platform_data i2c_pdata = {
-       .bus_freq       = 20 /* kHz */,
-       .bus_delay      = 100 /* usec */,
-};
-
-static void __init sffsdr_init_i2c(void)
-{
-       davinci_init_i2c(&i2c_pdata);
-       i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info));
-}
-
-static struct platform_device *davinci_sffsdr_devices[] __initdata = {
-       &davinci_sffsdr_nandflash_device,
-};
-
-static void __init davinci_sffsdr_map_io(void)
-{
-       dm644x_init();
-}
-
-static __init void davinci_sffsdr_init(void)
-{
-       struct davinci_soc_info *soc_info = &davinci_soc_info;
-
-       dm644x_register_clocks();
-
-       dm644x_init_devices();
-
-       platform_add_devices(davinci_sffsdr_devices,
-                            ARRAY_SIZE(davinci_sffsdr_devices));
-       sffsdr_init_i2c();
-       davinci_serial_init(dm644x_serial_device);
-       soc_info->emac_pdata->phy_id = SFFSDR_PHY_ID;
-       davinci_setup_usb(0, 0); /* We support only peripheral mode. */
-
-       /* mux VLYNQ pins */
-       davinci_cfg_reg(DM644X_VLYNQEN);
-       davinci_cfg_reg(DM644X_VLYNQWD);
-}
-
-MACHINE_START(SFFSDR, "Lyrtech SFFSDR")
-       .atag_offset  = 0x100,
-       .map_io       = davinci_sffsdr_map_io,
-       .init_irq     = dm644x_init_irq,
-       .init_time      = dm644x_init_time,
-       .init_machine = davinci_sffsdr_init,
-       .init_late      = davinci_init_late,
-       .dma_zone_size  = SZ_128M,
-MACHINE_END
diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c
deleted file mode 100644 (file)
index 1ce48d0..0000000
+++ /dev/null
@@ -1,765 +0,0 @@
-/*
- * TI DaVinci DM644x chip specific setup
- *
- * Author: Kevin Hilman, Deep Root Systems, LLC
- *
- * 2007 (c) Deep Root Systems, LLC. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#include <linux/clk-provider.h>
-#include <linux/clk/davinci.h>
-#include <linux/clkdev.h>
-#include <linux/dmaengine.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/irqchip/irq-davinci-aintc.h>
-#include <linux/platform_data/edma.h>
-#include <linux/platform_data/gpio-davinci.h>
-#include <linux/platform_device.h>
-#include <linux/serial_8250.h>
-
-#include <clocksource/timer-davinci.h>
-
-#include <asm/mach/map.h>
-
-#include "common.h"
-#include "cputype.h"
-#include "serial.h"
-#include "asp.h"
-#include "davinci.h"
-#include "irqs.h"
-#include "mux.h"
-
-/*
- * Device specific clocks
- */
-#define DM644X_REF_FREQ                27000000
-
-#define DM644X_EMAC_BASE               0x01c80000
-#define DM644X_EMAC_MDIO_BASE          (DM644X_EMAC_BASE + 0x4000)
-#define DM644X_EMAC_CNTRL_OFFSET       0x0000
-#define DM644X_EMAC_CNTRL_MOD_OFFSET   0x1000
-#define DM644X_EMAC_CNTRL_RAM_OFFSET   0x2000
-#define DM644X_EMAC_CNTRL_RAM_SIZE     0x2000
-
-static struct emac_platform_data dm644x_emac_pdata = {
-       .ctrl_reg_offset        = DM644X_EMAC_CNTRL_OFFSET,
-       .ctrl_mod_reg_offset    = DM644X_EMAC_CNTRL_MOD_OFFSET,
-       .ctrl_ram_offset        = DM644X_EMAC_CNTRL_RAM_OFFSET,
-       .ctrl_ram_size          = DM644X_EMAC_CNTRL_RAM_SIZE,
-       .version                = EMAC_VERSION_1,
-};
-
-static struct resource dm644x_emac_resources[] = {
-       {
-               .start  = DM644X_EMAC_BASE,
-               .end    = DM644X_EMAC_BASE + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       {
-               .start = DAVINCI_INTC_IRQ(IRQ_EMACINT),
-               .end   = DAVINCI_INTC_IRQ(IRQ_EMACINT),
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device dm644x_emac_device = {
-       .name           = "davinci_emac",
-       .id             = 1,
-       .dev = {
-              .platform_data   = &dm644x_emac_pdata,
-       },
-       .num_resources  = ARRAY_SIZE(dm644x_emac_resources),
-       .resource       = dm644x_emac_resources,
-};
-
-static struct resource dm644x_mdio_resources[] = {
-       {
-               .start  = DM644X_EMAC_MDIO_BASE,
-               .end    = DM644X_EMAC_MDIO_BASE + SZ_4K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-};
-
-static struct platform_device dm644x_mdio_device = {
-       .name           = "davinci_mdio",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(dm644x_mdio_resources),
-       .resource       = dm644x_mdio_resources,
-};
-
-/*
- * Device specific mux setup
- *
- *     soc     description     mux  mode   mode  mux    dbg
- *                             reg  offset mask  mode
- */
-static const struct mux_config dm644x_pins[] = {
-#ifdef CONFIG_DAVINCI_MUX
-MUX_CFG(DM644X, HDIREN,                0,   16,    1,    1,     true)
-MUX_CFG(DM644X, ATAEN,         0,   17,    1,    1,     true)
-MUX_CFG(DM644X, ATAEN_DISABLE, 0,   17,    1,    0,     true)
-
-MUX_CFG(DM644X, HPIEN_DISABLE, 0,   29,    1,    0,     true)
-
-MUX_CFG(DM644X, AEAW,          0,   0,     31,   31,    true)
-MUX_CFG(DM644X, AEAW0,         0,   0,     1,    0,     true)
-MUX_CFG(DM644X, AEAW1,         0,   1,     1,    0,     true)
-MUX_CFG(DM644X, AEAW2,         0,   2,     1,    0,     true)
-MUX_CFG(DM644X, AEAW3,         0,   3,     1,    0,     true)
-MUX_CFG(DM644X, AEAW4,         0,   4,     1,    0,     true)
-
-MUX_CFG(DM644X, MSTK,          1,   9,     1,    0,     false)
-
-MUX_CFG(DM644X, I2C,           1,   7,     1,    1,     false)
-
-MUX_CFG(DM644X, MCBSP,         1,   10,    1,    1,     false)
-
-MUX_CFG(DM644X, UART1,         1,   1,     1,    1,     true)
-MUX_CFG(DM644X, UART2,         1,   2,     1,    1,     true)
-
-MUX_CFG(DM644X, PWM0,          1,   4,     1,    1,     false)
-
-MUX_CFG(DM644X, PWM1,          1,   5,     1,    1,     false)
-
-MUX_CFG(DM644X, PWM2,          1,   6,     1,    1,     false)
-
-MUX_CFG(DM644X, VLYNQEN,       0,   15,    1,    1,     false)
-MUX_CFG(DM644X, VLSCREN,       0,   14,    1,    1,     false)
-MUX_CFG(DM644X, VLYNQWD,       0,   12,    3,    3,     false)
-
-MUX_CFG(DM644X, EMACEN,                0,   31,    1,    1,     true)
-
-MUX_CFG(DM644X, GPIO3V,                0,   31,    1,    0,     true)
-
-MUX_CFG(DM644X, GPIO0,         0,   24,    1,    0,     true)
-MUX_CFG(DM644X, GPIO3,         0,   25,    1,    0,     false)
-MUX_CFG(DM644X, GPIO43_44,     1,   7,     1,    0,     false)
-MUX_CFG(DM644X, GPIO46_47,     0,   22,    1,    0,     true)
-
-MUX_CFG(DM644X, RGB666,                0,   22,    1,    1,     true)
-
-MUX_CFG(DM644X, LOEEN,         0,   24,    1,    1,     true)
-MUX_CFG(DM644X, LFLDEN,                0,   25,    1,    1,     false)
-#endif
-};
-
-/* FIQ are pri 0-1; otherwise 2-7, with 7 lowest priority */
-static u8 dm644x_default_priorities[DAVINCI_N_AINTC_IRQ] = {
-       [IRQ_VDINT0]            = 2,
-       [IRQ_VDINT1]            = 6,
-       [IRQ_VDINT2]            = 6,
-       [IRQ_HISTINT]           = 6,
-       [IRQ_H3AINT]            = 6,
-       [IRQ_PRVUINT]           = 6,
-       [IRQ_RSZINT]            = 6,
-       [7]                     = 7,
-       [IRQ_VENCINT]           = 6,
-       [IRQ_ASQINT]            = 6,
-       [IRQ_IMXINT]            = 6,
-       [IRQ_VLCDINT]           = 6,
-       [IRQ_USBINT]            = 4,
-       [IRQ_EMACINT]           = 4,
-       [14]                    = 7,
-       [15]                    = 7,
-       [IRQ_CCINT0]            = 5,    /* dma */
-       [IRQ_CCERRINT]          = 5,    /* dma */
-       [IRQ_TCERRINT0]         = 5,    /* dma */
-       [IRQ_TCERRINT]          = 5,    /* dma */
-       [IRQ_PSCIN]             = 7,
-       [21]                    = 7,
-       [IRQ_IDE]               = 4,
-       [23]                    = 7,
-       [IRQ_MBXINT]            = 7,
-       [IRQ_MBRINT]            = 7,
-       [IRQ_MMCINT]            = 7,
-       [IRQ_SDIOINT]           = 7,
-       [28]                    = 7,
-       [IRQ_DDRINT]            = 7,
-       [IRQ_AEMIFINT]          = 7,
-       [IRQ_VLQINT]            = 4,
-       [IRQ_TINT0_TINT12]      = 2,    /* clockevent */
-       [IRQ_TINT0_TINT34]      = 2,    /* clocksource */
-       [IRQ_TINT1_TINT12]      = 7,    /* DSP timer */
-       [IRQ_TINT1_TINT34]      = 7,    /* system tick */
-       [IRQ_PWMINT0]           = 7,
-       [IRQ_PWMINT1]           = 7,
-       [IRQ_PWMINT2]           = 7,
-       [IRQ_I2C]               = 3,
-       [IRQ_UARTINT0]          = 3,
-       [IRQ_UARTINT1]          = 3,
-       [IRQ_UARTINT2]          = 3,
-       [IRQ_SPINT0]            = 3,
-       [IRQ_SPINT1]            = 3,
-       [45]                    = 7,
-       [IRQ_DSP2ARM0]          = 4,
-       [IRQ_DSP2ARM1]          = 4,
-       [IRQ_GPIO0]             = 7,
-       [IRQ_GPIO1]             = 7,
-       [IRQ_GPIO2]             = 7,
-       [IRQ_GPIO3]             = 7,
-       [IRQ_GPIO4]             = 7,
-       [IRQ_GPIO5]             = 7,
-       [IRQ_GPIO6]             = 7,
-       [IRQ_GPIO7]             = 7,
-       [IRQ_GPIOBNK0]          = 7,
-       [IRQ_GPIOBNK1]          = 7,
-       [IRQ_GPIOBNK2]          = 7,
-       [IRQ_GPIOBNK3]          = 7,
-       [IRQ_GPIOBNK4]          = 7,
-       [IRQ_COMMTX]            = 7,
-       [IRQ_COMMRX]            = 7,
-       [IRQ_EMUINT]            = 7,
-};
-
-/*----------------------------------------------------------------------*/
-
-static s8 queue_priority_mapping[][2] = {
-       /* {event queue no, Priority} */
-       {0, 3},
-       {1, 7},
-       {-1, -1},
-};
-
-static const struct dma_slave_map dm644x_edma_map[] = {
-       { "davinci-mcbsp", "tx", EDMA_FILTER_PARAM(0, 2) },
-       { "davinci-mcbsp", "rx", EDMA_FILTER_PARAM(0, 3) },
-       { "spi_davinci", "tx", EDMA_FILTER_PARAM(0, 16) },
-       { "spi_davinci", "rx", EDMA_FILTER_PARAM(0, 17) },
-       { "dm6441-mmc.0", "rx", EDMA_FILTER_PARAM(0, 26) },
-       { "dm6441-mmc.0", "tx", EDMA_FILTER_PARAM(0, 27) },
-};
-
-static struct edma_soc_info dm644x_edma_pdata = {
-       .queue_priority_mapping = queue_priority_mapping,
-       .default_queue          = EVENTQ_1,
-       .slave_map              = dm644x_edma_map,
-       .slavecnt               = ARRAY_SIZE(dm644x_edma_map),
-};
-
-static struct resource edma_resources[] = {
-       {
-               .name   = "edma3_cc",
-               .start  = 0x01c00000,
-               .end    = 0x01c00000 + SZ_64K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       {
-               .name   = "edma3_tc0",
-               .start  = 0x01c10000,
-               .end    = 0x01c10000 + SZ_1K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       {
-               .name   = "edma3_tc1",
-               .start  = 0x01c10400,
-               .end    = 0x01c10400 + SZ_1K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       {
-               .name   = "edma3_ccint",
-               .start  = DAVINCI_INTC_IRQ(IRQ_CCINT0),
-               .flags  = IORESOURCE_IRQ,
-       },
-       {
-               .name   = "edma3_ccerrint",
-               .start  = DAVINCI_INTC_IRQ(IRQ_CCERRINT),
-               .flags  = IORESOURCE_IRQ,
-       },
-       /* not using TC*_ERR */
-};
-
-static const struct platform_device_info dm644x_edma_device __initconst = {
-       .name           = "edma",
-       .id             = 0,
-       .dma_mask       = DMA_BIT_MASK(32),
-       .res            = edma_resources,
-       .num_res        = ARRAY_SIZE(edma_resources),
-       .data           = &dm644x_edma_pdata,
-       .size_data      = sizeof(dm644x_edma_pdata),
-};
-
-/* DM6446 EVM uses ASP0; line-out is a pair of RCA jacks */
-static struct resource dm644x_asp_resources[] = {
-       {
-               .name   = "mpu",
-               .start  = DAVINCI_ASP0_BASE,
-               .end    = DAVINCI_ASP0_BASE + SZ_8K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       {
-               .start  = DAVINCI_DMA_ASP0_TX,
-               .end    = DAVINCI_DMA_ASP0_TX,
-               .flags  = IORESOURCE_DMA,
-       },
-       {
-               .start  = DAVINCI_DMA_ASP0_RX,
-               .end    = DAVINCI_DMA_ASP0_RX,
-               .flags  = IORESOURCE_DMA,
-       },
-};
-
-static struct platform_device dm644x_asp_device = {
-       .name           = "davinci-mcbsp",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(dm644x_asp_resources),
-       .resource       = dm644x_asp_resources,
-};
-
-#define DM644X_VPSS_BASE       0x01c73400
-
-static struct resource dm644x_vpss_resources[] = {
-       {
-               /* VPSS Base address */
-               .name           = "vpss",
-               .start          = DM644X_VPSS_BASE,
-               .end            = DM644X_VPSS_BASE + 0xff,
-               .flags          = IORESOURCE_MEM,
-       },
-};
-
-static struct platform_device dm644x_vpss_device = {
-       .name                   = "vpss",
-       .id                     = -1,
-       .dev.platform_data      = "dm644x_vpss",
-       .num_resources          = ARRAY_SIZE(dm644x_vpss_resources),
-       .resource               = dm644x_vpss_resources,
-};
-
-static struct resource dm644x_vpfe_resources[] = {
-       {
-               .start          = DAVINCI_INTC_IRQ(IRQ_VDINT0),
-               .end            = DAVINCI_INTC_IRQ(IRQ_VDINT0),
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = DAVINCI_INTC_IRQ(IRQ_VDINT1),
-               .end            = DAVINCI_INTC_IRQ(IRQ_VDINT1),
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static u64 dm644x_video_dma_mask = DMA_BIT_MASK(32);
-static struct resource dm644x_ccdc_resource[] = {
-       /* CCDC Base address */
-       {
-               .start          = 0x01c70400,
-               .end            = 0x01c70400 + 0xff,
-               .flags          = IORESOURCE_MEM,
-       },
-};
-
-static struct platform_device dm644x_ccdc_dev = {
-       .name           = "dm644x_ccdc",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(dm644x_ccdc_resource),
-       .resource       = dm644x_ccdc_resource,
-       .dev = {
-               .dma_mask               = &dm644x_video_dma_mask,
-               .coherent_dma_mask      = DMA_BIT_MASK(32),
-       },
-};
-
-static struct platform_device dm644x_vpfe_dev = {
-       .name           = CAPTURE_DRV_NAME,
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(dm644x_vpfe_resources),
-       .resource       = dm644x_vpfe_resources,
-       .dev = {
-               .dma_mask               = &dm644x_video_dma_mask,
-               .coherent_dma_mask      = DMA_BIT_MASK(32),
-       },
-};
-
-#define DM644X_OSD_BASE                0x01c72600
-
-static struct resource dm644x_osd_resources[] = {
-       {
-               .start  = DM644X_OSD_BASE,
-               .end    = DM644X_OSD_BASE + 0x1ff,
-               .flags  = IORESOURCE_MEM,
-       },
-};
-
-static struct platform_device dm644x_osd_dev = {
-       .name           = DM644X_VPBE_OSD_SUBDEV_NAME,
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(dm644x_osd_resources),
-       .resource       = dm644x_osd_resources,
-       .dev            = {
-               .dma_mask               = &dm644x_video_dma_mask,
-               .coherent_dma_mask      = DMA_BIT_MASK(32),
-       },
-};
-
-#define DM644X_VENC_BASE               0x01c72400
-
-static struct resource dm644x_venc_resources[] = {
-       {
-               .start  = DM644X_VENC_BASE,
-               .end    = DM644X_VENC_BASE + 0x17f,
-               .flags  = IORESOURCE_MEM,
-       },
-};
-
-#define DM644X_VPSS_MUXSEL_PLL2_MODE          BIT(0)
-#define DM644X_VPSS_MUXSEL_VPBECLK_MODE       BIT(1)
-#define DM644X_VPSS_VENCLKEN                  BIT(3)
-#define DM644X_VPSS_DACCLKEN                  BIT(4)
-
-static int dm644x_venc_setup_clock(enum vpbe_enc_timings_type type,
-                                  unsigned int pclock)
-{
-       int ret = 0;
-       u32 v = DM644X_VPSS_VENCLKEN;
-
-       switch (type) {
-       case VPBE_ENC_STD:
-               v |= DM644X_VPSS_DACCLKEN;
-               writel(v, DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL));
-               break;
-       case VPBE_ENC_DV_TIMINGS:
-               if (pclock <= 27000000) {
-                       v |= DM644X_VPSS_DACCLKEN;
-                       writel(v, DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL));
-               } else {
-                       /*
-                        * For HD, use external clock source since
-                        * HD requires higher clock rate
-                        */
-                       v |= DM644X_VPSS_MUXSEL_VPBECLK_MODE;
-                       writel(v, DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL));
-               }
-               break;
-       default:
-               ret  = -EINVAL;
-       }
-
-       return ret;
-}
-
-static struct resource dm644x_v4l2_disp_resources[] = {
-       {
-               .start  = DAVINCI_INTC_IRQ(IRQ_VENCINT),
-               .end    = DAVINCI_INTC_IRQ(IRQ_VENCINT),
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device dm644x_vpbe_display = {
-       .name           = "vpbe-v4l2",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(dm644x_v4l2_disp_resources),
-       .resource       = dm644x_v4l2_disp_resources,
-       .dev            = {
-               .dma_mask               = &dm644x_video_dma_mask,
-               .coherent_dma_mask      = DMA_BIT_MASK(32),
-       },
-};
-
-static struct venc_platform_data dm644x_venc_pdata = {
-       .setup_clock    = dm644x_venc_setup_clock,
-};
-
-static struct platform_device dm644x_venc_dev = {
-       .name           = DM644X_VPBE_VENC_SUBDEV_NAME,
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(dm644x_venc_resources),
-       .resource       = dm644x_venc_resources,
-       .dev            = {
-               .dma_mask               = &dm644x_video_dma_mask,
-               .coherent_dma_mask      = DMA_BIT_MASK(32),
-               .platform_data          = &dm644x_venc_pdata,
-       },
-};
-
-static struct platform_device dm644x_vpbe_dev = {
-       .name           = "vpbe_controller",
-       .id             = -1,
-       .dev            = {
-               .dma_mask               = &dm644x_video_dma_mask,
-               .coherent_dma_mask      = DMA_BIT_MASK(32),
-       },
-};
-
-static struct resource dm644_gpio_resources[] = {
-       {       /* registers */
-               .start  = DAVINCI_GPIO_BASE,
-               .end    = DAVINCI_GPIO_BASE + SZ_4K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       {       /* interrupt */
-               .start  = DAVINCI_INTC_IRQ(IRQ_GPIOBNK0),
-               .end    = DAVINCI_INTC_IRQ(IRQ_GPIOBNK0),
-               .flags  = IORESOURCE_IRQ,
-       },
-       {
-               .start  = DAVINCI_INTC_IRQ(IRQ_GPIOBNK1),
-               .end    = DAVINCI_INTC_IRQ(IRQ_GPIOBNK1),
-               .flags  = IORESOURCE_IRQ,
-       },
-       {
-               .start  = DAVINCI_INTC_IRQ(IRQ_GPIOBNK2),
-               .end    = DAVINCI_INTC_IRQ(IRQ_GPIOBNK2),
-               .flags  = IORESOURCE_IRQ,
-       },
-       {
-               .start  = DAVINCI_INTC_IRQ(IRQ_GPIOBNK3),
-               .end    = DAVINCI_INTC_IRQ(IRQ_GPIOBNK3),
-               .flags  = IORESOURCE_IRQ,
-       },
-       {
-               .start  = DAVINCI_INTC_IRQ(IRQ_GPIOBNK4),
-               .end    = DAVINCI_INTC_IRQ(IRQ_GPIOBNK4),
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct davinci_gpio_platform_data dm644_gpio_platform_data = {
-       .no_auto_base   = true,
-       .base           = 0,
-       .ngpio          = 71,
-};
-
-int __init dm644x_gpio_register(void)
-{
-       return davinci_gpio_register(dm644_gpio_resources,
-                                    ARRAY_SIZE(dm644_gpio_resources),
-                                    &dm644_gpio_platform_data);
-}
-/*----------------------------------------------------------------------*/
-
-static struct map_desc dm644x_io_desc[] = {
-       {
-               .virtual        = IO_VIRT,
-               .pfn            = __phys_to_pfn(IO_PHYS),
-               .length         = IO_SIZE,
-               .type           = MT_DEVICE
-       },
-};
-
-/* Contents of JTAG ID register used to identify exact cpu type */
-static struct davinci_id dm644x_ids[] = {
-       {
-               .variant        = 0x0,
-               .part_no        = 0xb700,
-               .manufacturer   = 0x017,
-               .cpu_id         = DAVINCI_CPU_ID_DM6446,
-               .name           = "dm6446",
-       },
-       {
-               .variant        = 0x1,
-               .part_no        = 0xb700,
-               .manufacturer   = 0x017,
-               .cpu_id         = DAVINCI_CPU_ID_DM6446,
-               .name           = "dm6446a",
-       },
-};
-
-/*
- * Bottom half of timer0 is used for clockevent, top half is used for
- * clocksource.
- */
-static const struct davinci_timer_cfg dm644x_timer_cfg = {
-       .reg = DEFINE_RES_IO(DAVINCI_TIMER0_BASE, SZ_4K),
-       .irq = {
-               DEFINE_RES_IRQ(DAVINCI_INTC_IRQ(IRQ_TINT0_TINT12)),
-               DEFINE_RES_IRQ(DAVINCI_INTC_IRQ(IRQ_TINT0_TINT34)),
-       },
-};
-
-static struct plat_serial8250_port dm644x_serial0_platform_data[] = {
-       {
-               .mapbase        = DAVINCI_UART0_BASE,
-               .irq            = DAVINCI_INTC_IRQ(IRQ_UARTINT0),
-               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
-                                 UPF_IOREMAP,
-               .iotype         = UPIO_MEM,
-               .regshift       = 2,
-       },
-       {
-               .flags  = 0,
-       }
-};
-static struct plat_serial8250_port dm644x_serial1_platform_data[] = {
-       {
-               .mapbase        = DAVINCI_UART1_BASE,
-               .irq            = DAVINCI_INTC_IRQ(IRQ_UARTINT1),
-               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
-                                 UPF_IOREMAP,
-               .iotype         = UPIO_MEM,
-               .regshift       = 2,
-       },
-       {
-               .flags  = 0,
-       }
-};
-static struct plat_serial8250_port dm644x_serial2_platform_data[] = {
-       {
-               .mapbase        = DAVINCI_UART2_BASE,
-               .irq            = DAVINCI_INTC_IRQ(IRQ_UARTINT2),
-               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
-                                 UPF_IOREMAP,
-               .iotype         = UPIO_MEM,
-               .regshift       = 2,
-       },
-       {
-               .flags  = 0,
-       }
-};
-
-struct platform_device dm644x_serial_device[] = {
-       {
-               .name                   = "serial8250",
-               .id                     = PLAT8250_DEV_PLATFORM,
-               .dev                    = {
-                       .platform_data  = dm644x_serial0_platform_data,
-               }
-       },
-       {
-               .name                   = "serial8250",
-               .id                     = PLAT8250_DEV_PLATFORM1,
-               .dev                    = {
-                       .platform_data  = dm644x_serial1_platform_data,
-               }
-       },
-       {
-               .name                   = "serial8250",
-               .id                     = PLAT8250_DEV_PLATFORM2,
-               .dev                    = {
-                       .platform_data  = dm644x_serial2_platform_data,
-               }
-       },
-       {
-       }
-};
-
-static const struct davinci_soc_info davinci_soc_info_dm644x = {
-       .io_desc                = dm644x_io_desc,
-       .io_desc_num            = ARRAY_SIZE(dm644x_io_desc),
-       .jtag_id_reg            = 0x01c40028,
-       .ids                    = dm644x_ids,
-       .ids_num                = ARRAY_SIZE(dm644x_ids),
-       .pinmux_base            = DAVINCI_SYSTEM_MODULE_BASE,
-       .pinmux_pins            = dm644x_pins,
-       .pinmux_pins_num        = ARRAY_SIZE(dm644x_pins),
-       .emac_pdata             = &dm644x_emac_pdata,
-       .sram_dma               = 0x00008000,
-       .sram_len               = SZ_16K,
-};
-
-void __init dm644x_init_asp(void)
-{
-       davinci_cfg_reg(DM644X_MCBSP);
-       platform_device_register(&dm644x_asp_device);
-}
-
-void __init dm644x_init(void)
-{
-       davinci_common_init(&davinci_soc_info_dm644x);
-       davinci_map_sysmod();
-}
-
-void __init dm644x_init_time(void)
-{
-       void __iomem *pll1, *psc;
-       struct clk *clk;
-       int rv;
-
-       clk_register_fixed_rate(NULL, "ref_clk", NULL, 0, DM644X_REF_FREQ);
-
-       pll1 = ioremap(DAVINCI_PLL1_BASE, SZ_1K);
-       dm644x_pll1_init(NULL, pll1, NULL);
-
-       psc = ioremap(DAVINCI_PWR_SLEEP_CNTRL_BASE, SZ_4K);
-       dm644x_psc_init(NULL, psc);
-
-       clk = clk_get(NULL, "timer0");
-       if (WARN_ON(IS_ERR(clk))) {
-               pr_err("Unable to get the timer clock\n");
-               return;
-       }
-
-       rv = davinci_timer_register(clk, &dm644x_timer_cfg);
-       WARN(rv, "Unable to register the timer: %d\n", rv);
-}
-
-static struct resource dm644x_pll2_resources[] = {
-       {
-               .start  = DAVINCI_PLL2_BASE,
-               .end    = DAVINCI_PLL2_BASE + SZ_1K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-};
-
-static struct platform_device dm644x_pll2_device = {
-       .name           = "dm644x-pll2",
-       .id             = -1,
-       .resource       = dm644x_pll2_resources,
-       .num_resources  = ARRAY_SIZE(dm644x_pll2_resources),
-};
-
-void __init dm644x_register_clocks(void)
-{
-       /* PLL1 and PSC are registered in dm644x_init_time() */
-       platform_device_register(&dm644x_pll2_device);
-}
-
-int __init dm644x_init_video(struct vpfe_config *vpfe_cfg,
-                               struct vpbe_config *vpbe_cfg)
-{
-       if (vpfe_cfg || vpbe_cfg)
-               platform_device_register(&dm644x_vpss_device);
-
-       if (vpfe_cfg) {
-               dm644x_vpfe_dev.dev.platform_data = vpfe_cfg;
-               platform_device_register(&dm644x_ccdc_dev);
-               platform_device_register(&dm644x_vpfe_dev);
-       }
-
-       if (vpbe_cfg) {
-               dm644x_vpbe_dev.dev.platform_data = vpbe_cfg;
-               platform_device_register(&dm644x_osd_dev);
-               platform_device_register(&dm644x_venc_dev);
-               platform_device_register(&dm644x_vpbe_dev);
-               platform_device_register(&dm644x_vpbe_display);
-       }
-
-       return 0;
-}
-
-static const struct davinci_aintc_config dm644x_aintc_config = {
-       .reg = {
-               .start          = DAVINCI_ARM_INTC_BASE,
-               .end            = DAVINCI_ARM_INTC_BASE + SZ_4K - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       .num_irqs               = 64,
-       .prios                  = dm644x_default_priorities,
-};
-
-void __init dm644x_init_irq(void)
-{
-       davinci_aintc_init(&dm644x_aintc_config);
-}
-
-void __init dm644x_init_devices(void)
-{
-       struct platform_device *edma_pdev;
-       int ret;
-
-       edma_pdev = platform_device_register_full(&dm644x_edma_device);
-       if (IS_ERR(edma_pdev))
-               pr_warn("%s: Failed to register eDMA\n", __func__);
-
-       platform_device_register(&dm644x_mdio_device);
-       platform_device_register(&dm644x_emac_device);
-
-       ret = davinci_init_wdt();
-       if (ret)
-               pr_warn("%s: watchdog init failed: %d\n", __func__, ret);
-
-}
diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c
deleted file mode 100644 (file)
index 971b2d4..0000000
+++ /dev/null
@@ -1,726 +0,0 @@
-/*
- * TI DaVinci DM646x chip specific setup
- *
- * Author: Kevin Hilman, Deep Root Systems, LLC
- *
- * 2007 (c) Deep Root Systems, LLC. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#include <linux/clk-provider.h>
-#include <linux/clk/davinci.h>
-#include <linux/clkdev.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmaengine.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/irqchip/irq-davinci-aintc.h>
-#include <linux/platform_data/edma.h>
-#include <linux/platform_data/gpio-davinci.h>
-#include <linux/platform_device.h>
-#include <linux/serial_8250.h>
-
-#include <clocksource/timer-davinci.h>
-
-#include <asm/mach/map.h>
-
-#include "common.h"
-#include "cputype.h"
-#include "serial.h"
-#include "asp.h"
-#include "davinci.h"
-#include "irqs.h"
-#include "mux.h"
-
-#define DAVINCI_VPIF_BASE       (0x01C12000)
-
-#define VDD3P3V_VID_MASK       (BIT_MASK(3) | BIT_MASK(2) | BIT_MASK(1) |\
-                                       BIT_MASK(0))
-#define VSCLKDIS_MASK          (BIT_MASK(11) | BIT_MASK(10) | BIT_MASK(9) |\
-                                       BIT_MASK(8))
-
-#define DM646X_EMAC_BASE               0x01c80000
-#define DM646X_EMAC_MDIO_BASE          (DM646X_EMAC_BASE + 0x4000)
-#define DM646X_EMAC_CNTRL_OFFSET       0x0000
-#define DM646X_EMAC_CNTRL_MOD_OFFSET   0x1000
-#define DM646X_EMAC_CNTRL_RAM_OFFSET   0x2000
-#define DM646X_EMAC_CNTRL_RAM_SIZE     0x2000
-
-static struct emac_platform_data dm646x_emac_pdata = {
-       .ctrl_reg_offset        = DM646X_EMAC_CNTRL_OFFSET,
-       .ctrl_mod_reg_offset    = DM646X_EMAC_CNTRL_MOD_OFFSET,
-       .ctrl_ram_offset        = DM646X_EMAC_CNTRL_RAM_OFFSET,
-       .ctrl_ram_size          = DM646X_EMAC_CNTRL_RAM_SIZE,
-       .version                = EMAC_VERSION_2,
-};
-
-static struct resource dm646x_emac_resources[] = {
-       {
-               .start  = DM646X_EMAC_BASE,
-               .end    = DM646X_EMAC_BASE + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       {
-               .start  = DAVINCI_INTC_IRQ(IRQ_DM646X_EMACRXTHINT),
-               .end    = DAVINCI_INTC_IRQ(IRQ_DM646X_EMACRXTHINT),
-               .flags  = IORESOURCE_IRQ,
-       },
-       {
-               .start  = DAVINCI_INTC_IRQ(IRQ_DM646X_EMACRXINT),
-               .end    = DAVINCI_INTC_IRQ(IRQ_DM646X_EMACRXINT),
-               .flags  = IORESOURCE_IRQ,
-       },
-       {
-               .start  = DAVINCI_INTC_IRQ(IRQ_DM646X_EMACTXINT),
-               .end    = DAVINCI_INTC_IRQ(IRQ_DM646X_EMACTXINT),
-               .flags  = IORESOURCE_IRQ,
-       },
-       {
-               .start  = DAVINCI_INTC_IRQ(IRQ_DM646X_EMACMISCINT),
-               .end    = DAVINCI_INTC_IRQ(IRQ_DM646X_EMACMISCINT),
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device dm646x_emac_device = {
-       .name           = "davinci_emac",
-       .id             = 1,
-       .dev = {
-               .platform_data  = &dm646x_emac_pdata,
-       },
-       .num_resources  = ARRAY_SIZE(dm646x_emac_resources),
-       .resource       = dm646x_emac_resources,
-};
-
-static struct resource dm646x_mdio_resources[] = {
-       {
-               .start  = DM646X_EMAC_MDIO_BASE,
-               .end    = DM646X_EMAC_MDIO_BASE + SZ_4K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-};
-
-static struct platform_device dm646x_mdio_device = {
-       .name           = "davinci_mdio",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(dm646x_mdio_resources),
-       .resource       = dm646x_mdio_resources,
-};
-
-/*
- * Device specific mux setup
- *
- *     soc     description     mux  mode   mode  mux    dbg
- *                             reg  offset mask  mode
- */
-static const struct mux_config dm646x_pins[] = {
-#ifdef CONFIG_DAVINCI_MUX
-MUX_CFG(DM646X, ATAEN,         0,   0,     5,    1,     true)
-
-MUX_CFG(DM646X, AUDCK1,                0,   29,    1,    0,     false)
-
-MUX_CFG(DM646X, AUDCK0,                0,   28,    1,    0,     false)
-
-MUX_CFG(DM646X, CRGMUX,                        0,   24,    7,    5,     true)
-
-MUX_CFG(DM646X, STSOMUX_DISABLE,       0,   22,    3,    0,     true)
-
-MUX_CFG(DM646X, STSIMUX_DISABLE,       0,   20,    3,    0,     true)
-
-MUX_CFG(DM646X, PTSOMUX_DISABLE,       0,   18,    3,    0,     true)
-
-MUX_CFG(DM646X, PTSIMUX_DISABLE,       0,   16,    3,    0,     true)
-
-MUX_CFG(DM646X, STSOMUX,               0,   22,    3,    2,     true)
-
-MUX_CFG(DM646X, STSIMUX,               0,   20,    3,    2,     true)
-
-MUX_CFG(DM646X, PTSOMUX_PARALLEL,      0,   18,    3,    2,     true)
-
-MUX_CFG(DM646X, PTSIMUX_PARALLEL,      0,   16,    3,    2,     true)
-
-MUX_CFG(DM646X, PTSOMUX_SERIAL,                0,   18,    3,    3,     true)
-
-MUX_CFG(DM646X, PTSIMUX_SERIAL,                0,   16,    3,    3,     true)
-#endif
-};
-
-static u8 dm646x_default_priorities[DAVINCI_N_AINTC_IRQ] = {
-       [IRQ_DM646X_VP_VERTINT0]        = 7,
-       [IRQ_DM646X_VP_VERTINT1]        = 7,
-       [IRQ_DM646X_VP_VERTINT2]        = 7,
-       [IRQ_DM646X_VP_VERTINT3]        = 7,
-       [IRQ_DM646X_VP_ERRINT]          = 7,
-       [IRQ_DM646X_RESERVED_1]         = 7,
-       [IRQ_DM646X_RESERVED_2]         = 7,
-       [IRQ_DM646X_WDINT]              = 7,
-       [IRQ_DM646X_CRGENINT0]          = 7,
-       [IRQ_DM646X_CRGENINT1]          = 7,
-       [IRQ_DM646X_TSIFINT0]           = 7,
-       [IRQ_DM646X_TSIFINT1]           = 7,
-       [IRQ_DM646X_VDCEINT]            = 7,
-       [IRQ_DM646X_USBINT]             = 7,
-       [IRQ_DM646X_USBDMAINT]          = 7,
-       [IRQ_DM646X_PCIINT]             = 7,
-       [IRQ_CCINT0]                    = 7,    /* dma */
-       [IRQ_CCERRINT]                  = 7,    /* dma */
-       [IRQ_TCERRINT0]                 = 7,    /* dma */
-       [IRQ_TCERRINT]                  = 7,    /* dma */
-       [IRQ_DM646X_TCERRINT2]          = 7,
-       [IRQ_DM646X_TCERRINT3]          = 7,
-       [IRQ_DM646X_IDE]                = 7,
-       [IRQ_DM646X_HPIINT]             = 7,
-       [IRQ_DM646X_EMACRXTHINT]        = 7,
-       [IRQ_DM646X_EMACRXINT]          = 7,
-       [IRQ_DM646X_EMACTXINT]          = 7,
-       [IRQ_DM646X_EMACMISCINT]        = 7,
-       [IRQ_DM646X_MCASP0TXINT]        = 7,
-       [IRQ_DM646X_MCASP0RXINT]        = 7,
-       [IRQ_DM646X_RESERVED_3]         = 7,
-       [IRQ_DM646X_MCASP1TXINT]        = 7,
-       [IRQ_TINT0_TINT12]              = 7,    /* clockevent */
-       [IRQ_TINT0_TINT34]              = 7,    /* clocksource */
-       [IRQ_TINT1_TINT12]              = 7,    /* DSP timer */
-       [IRQ_TINT1_TINT34]              = 7,    /* system tick */
-       [IRQ_PWMINT0]                   = 7,
-       [IRQ_PWMINT1]                   = 7,
-       [IRQ_DM646X_VLQINT]             = 7,
-       [IRQ_I2C]                       = 7,
-       [IRQ_UARTINT0]                  = 7,
-       [IRQ_UARTINT1]                  = 7,
-       [IRQ_DM646X_UARTINT2]           = 7,
-       [IRQ_DM646X_SPINT0]             = 7,
-       [IRQ_DM646X_SPINT1]             = 7,
-       [IRQ_DM646X_DSP2ARMINT]         = 7,
-       [IRQ_DM646X_RESERVED_4]         = 7,
-       [IRQ_DM646X_PSCINT]             = 7,
-       [IRQ_DM646X_GPIO0]              = 7,
-       [IRQ_DM646X_GPIO1]              = 7,
-       [IRQ_DM646X_GPIO2]              = 7,
-       [IRQ_DM646X_GPIO3]              = 7,
-       [IRQ_DM646X_GPIO4]              = 7,
-       [IRQ_DM646X_GPIO5]              = 7,
-       [IRQ_DM646X_GPIO6]              = 7,
-       [IRQ_DM646X_GPIO7]              = 7,
-       [IRQ_DM646X_GPIOBNK0]           = 7,
-       [IRQ_DM646X_GPIOBNK1]           = 7,
-       [IRQ_DM646X_GPIOBNK2]           = 7,
-       [IRQ_DM646X_DDRINT]             = 7,
-       [IRQ_DM646X_AEMIFINT]           = 7,
-       [IRQ_COMMTX]                    = 7,
-       [IRQ_COMMRX]                    = 7,
-       [IRQ_EMUINT]                    = 7,
-};
-
-/*----------------------------------------------------------------------*/
-
-/* Four Transfer Controllers on DM646x */
-static s8 dm646x_queue_priority_mapping[][2] = {
-       /* {event queue no, Priority} */
-       {0, 4},
-       {1, 0},
-       {2, 5},
-       {3, 1},
-       {-1, -1},
-};
-
-static const struct dma_slave_map dm646x_edma_map[] = {
-       { "davinci-mcasp.0", "tx", EDMA_FILTER_PARAM(0, 6) },
-       { "davinci-mcasp.0", "rx", EDMA_FILTER_PARAM(0, 9) },
-       { "davinci-mcasp.1", "tx", EDMA_FILTER_PARAM(0, 12) },
-       { "spi_davinci", "tx", EDMA_FILTER_PARAM(0, 16) },
-       { "spi_davinci", "rx", EDMA_FILTER_PARAM(0, 17) },
-};
-
-static struct edma_soc_info dm646x_edma_pdata = {
-       .queue_priority_mapping = dm646x_queue_priority_mapping,
-       .default_queue          = EVENTQ_1,
-       .slave_map              = dm646x_edma_map,
-       .slavecnt               = ARRAY_SIZE(dm646x_edma_map),
-};
-
-static struct resource edma_resources[] = {
-       {
-               .name   = "edma3_cc",
-               .start  = 0x01c00000,
-               .end    = 0x01c00000 + SZ_64K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       {
-               .name   = "edma3_tc0",
-               .start  = 0x01c10000,
-               .end    = 0x01c10000 + SZ_1K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       {
-               .name   = "edma3_tc1",
-               .start  = 0x01c10400,
-               .end    = 0x01c10400 + SZ_1K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       {
-               .name   = "edma3_tc2",
-               .start  = 0x01c10800,
-               .end    = 0x01c10800 + SZ_1K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       {
-               .name   = "edma3_tc3",
-               .start  = 0x01c10c00,
-               .end    = 0x01c10c00 + SZ_1K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       {
-               .name   = "edma3_ccint",
-               .start  = DAVINCI_INTC_IRQ(IRQ_CCINT0),
-               .flags  = IORESOURCE_IRQ,
-       },
-       {
-               .name   = "edma3_ccerrint",
-               .start  = DAVINCI_INTC_IRQ(IRQ_CCERRINT),
-               .flags  = IORESOURCE_IRQ,
-       },
-       /* not using TC*_ERR */
-};
-
-static const struct platform_device_info dm646x_edma_device __initconst = {
-       .name           = "edma",
-       .id             = 0,
-       .dma_mask       = DMA_BIT_MASK(32),
-       .res            = edma_resources,
-       .num_res        = ARRAY_SIZE(edma_resources),
-       .data           = &dm646x_edma_pdata,
-       .size_data      = sizeof(dm646x_edma_pdata),
-};
-
-static struct resource dm646x_mcasp0_resources[] = {
-       {
-               .name   = "mpu",
-               .start  = DAVINCI_DM646X_MCASP0_REG_BASE,
-               .end    = DAVINCI_DM646X_MCASP0_REG_BASE + (SZ_1K << 1) - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       {
-               .name   = "tx",
-               .start  = DAVINCI_DM646X_DMA_MCASP0_AXEVT0,
-               .end    = DAVINCI_DM646X_DMA_MCASP0_AXEVT0,
-               .flags  = IORESOURCE_DMA,
-       },
-       {
-               .name   = "rx",
-               .start  = DAVINCI_DM646X_DMA_MCASP0_AREVT0,
-               .end    = DAVINCI_DM646X_DMA_MCASP0_AREVT0,
-               .flags  = IORESOURCE_DMA,
-       },
-       {
-               .name   = "tx",
-               .start  = DAVINCI_INTC_IRQ(IRQ_DM646X_MCASP0TXINT),
-               .flags  = IORESOURCE_IRQ,
-       },
-       {
-               .name   = "rx",
-               .start  = DAVINCI_INTC_IRQ(IRQ_DM646X_MCASP0RXINT),
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-/* DIT mode only, rx is not supported */
-static struct resource dm646x_mcasp1_resources[] = {
-       {
-               .name   = "mpu",
-               .start  = DAVINCI_DM646X_MCASP1_REG_BASE,
-               .end    = DAVINCI_DM646X_MCASP1_REG_BASE + (SZ_1K << 1) - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       {
-               .name   = "tx",
-               .start  = DAVINCI_DM646X_DMA_MCASP1_AXEVT1,
-               .end    = DAVINCI_DM646X_DMA_MCASP1_AXEVT1,
-               .flags  = IORESOURCE_DMA,
-       },
-       {
-               .name   = "tx",
-               .start  = DAVINCI_INTC_IRQ(IRQ_DM646X_MCASP1TXINT),
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device dm646x_mcasp0_device = {
-       .name           = "davinci-mcasp",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(dm646x_mcasp0_resources),
-       .resource       = dm646x_mcasp0_resources,
-};
-
-static struct platform_device dm646x_mcasp1_device = {
-       .name           = "davinci-mcasp",
-       .id             = 1,
-       .num_resources  = ARRAY_SIZE(dm646x_mcasp1_resources),
-       .resource       = dm646x_mcasp1_resources,
-};
-
-static struct platform_device dm646x_dit_device = {
-       .name   = "spdif-dit",
-       .id     = -1,
-};
-
-static u64 vpif_dma_mask = DMA_BIT_MASK(32);
-
-static struct resource vpif_resource[] = {
-       {
-               .start  = DAVINCI_VPIF_BASE,
-               .end    = DAVINCI_VPIF_BASE + 0x03ff,
-               .flags  = IORESOURCE_MEM,
-       }
-};
-
-static struct platform_device vpif_dev = {
-       .name           = "vpif",
-       .id             = -1,
-       .dev            = {
-                       .dma_mask               = &vpif_dma_mask,
-                       .coherent_dma_mask      = DMA_BIT_MASK(32),
-       },
-       .resource       = vpif_resource,
-       .num_resources  = ARRAY_SIZE(vpif_resource),
-};
-
-static struct resource vpif_display_resource[] = {
-       {
-               .start = DAVINCI_INTC_IRQ(IRQ_DM646X_VP_VERTINT2),
-               .end   = DAVINCI_INTC_IRQ(IRQ_DM646X_VP_VERTINT2),
-               .flags = IORESOURCE_IRQ,
-       },
-       {
-               .start = DAVINCI_INTC_IRQ(IRQ_DM646X_VP_VERTINT3),
-               .end   = DAVINCI_INTC_IRQ(IRQ_DM646X_VP_VERTINT3),
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device vpif_display_dev = {
-       .name           = "vpif_display",
-       .id             = -1,
-       .dev            = {
-                       .dma_mask               = &vpif_dma_mask,
-                       .coherent_dma_mask      = DMA_BIT_MASK(32),
-       },
-       .resource       = vpif_display_resource,
-       .num_resources  = ARRAY_SIZE(vpif_display_resource),
-};
-
-static struct resource vpif_capture_resource[] = {
-       {
-               .start = DAVINCI_INTC_IRQ(IRQ_DM646X_VP_VERTINT0),
-               .end   = DAVINCI_INTC_IRQ(IRQ_DM646X_VP_VERTINT0),
-               .flags = IORESOURCE_IRQ,
-       },
-       {
-               .start = DAVINCI_INTC_IRQ(IRQ_DM646X_VP_VERTINT1),
-               .end   = DAVINCI_INTC_IRQ(IRQ_DM646X_VP_VERTINT1),
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device vpif_capture_dev = {
-       .name           = "vpif_capture",
-       .id             = -1,
-       .dev            = {
-                       .dma_mask               = &vpif_dma_mask,
-                       .coherent_dma_mask      = DMA_BIT_MASK(32),
-       },
-       .resource       = vpif_capture_resource,
-       .num_resources  = ARRAY_SIZE(vpif_capture_resource),
-};
-
-static struct resource dm646x_gpio_resources[] = {
-       {       /* registers */
-               .start  = DAVINCI_GPIO_BASE,
-               .end    = DAVINCI_GPIO_BASE + SZ_4K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       {       /* interrupt */
-               .start  = DAVINCI_INTC_IRQ(IRQ_DM646X_GPIOBNK0),
-               .end    = DAVINCI_INTC_IRQ(IRQ_DM646X_GPIOBNK0),
-               .flags  = IORESOURCE_IRQ,
-       },
-       {
-               .start  = DAVINCI_INTC_IRQ(IRQ_DM646X_GPIOBNK1),
-               .end    = DAVINCI_INTC_IRQ(IRQ_DM646X_GPIOBNK1),
-               .flags  = IORESOURCE_IRQ,
-       },
-       {
-               .start  = DAVINCI_INTC_IRQ(IRQ_DM646X_GPIOBNK2),
-               .end    = DAVINCI_INTC_IRQ(IRQ_DM646X_GPIOBNK2),
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct davinci_gpio_platform_data dm646x_gpio_platform_data = {
-       .no_auto_base   = true,
-       .base           = 0,
-       .ngpio          = 43,
-};
-
-int __init dm646x_gpio_register(void)
-{
-       return davinci_gpio_register(dm646x_gpio_resources,
-                                    ARRAY_SIZE(dm646x_gpio_resources),
-                                    &dm646x_gpio_platform_data);
-}
-/*----------------------------------------------------------------------*/
-
-static struct map_desc dm646x_io_desc[] = {
-       {
-               .virtual        = IO_VIRT,
-               .pfn            = __phys_to_pfn(IO_PHYS),
-               .length         = IO_SIZE,
-               .type           = MT_DEVICE
-       },
-};
-
-/* Contents of JTAG ID register used to identify exact cpu type */
-static struct davinci_id dm646x_ids[] = {
-       {
-               .variant        = 0x0,
-               .part_no        = 0xb770,
-               .manufacturer   = 0x017,
-               .cpu_id         = DAVINCI_CPU_ID_DM6467,
-               .name           = "dm6467_rev1.x",
-       },
-       {
-               .variant        = 0x1,
-               .part_no        = 0xb770,
-               .manufacturer   = 0x017,
-               .cpu_id         = DAVINCI_CPU_ID_DM6467,
-               .name           = "dm6467_rev3.x",
-       },
-};
-
-/*
- * Bottom half of timer0 is used for clockevent, top half is used for
- * clocksource.
- */
-static const struct davinci_timer_cfg dm646x_timer_cfg = {
-       .reg = DEFINE_RES_IO(DAVINCI_TIMER0_BASE, SZ_4K),
-       .irq = {
-               DEFINE_RES_IRQ(DAVINCI_INTC_IRQ(IRQ_TINT0_TINT12)),
-               DEFINE_RES_IRQ(DAVINCI_INTC_IRQ(IRQ_TINT0_TINT34)),
-       },
-};
-
-static struct plat_serial8250_port dm646x_serial0_platform_data[] = {
-       {
-               .mapbase        = DAVINCI_UART0_BASE,
-               .irq            = DAVINCI_INTC_IRQ(IRQ_UARTINT0),
-               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
-                                 UPF_IOREMAP,
-               .iotype         = UPIO_MEM32,
-               .regshift       = 2,
-       },
-       {
-               .flags  = 0,
-       }
-};
-static struct plat_serial8250_port dm646x_serial1_platform_data[] = {
-       {
-               .mapbase        = DAVINCI_UART1_BASE,
-               .irq            = DAVINCI_INTC_IRQ(IRQ_UARTINT1),
-               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
-                                 UPF_IOREMAP,
-               .iotype         = UPIO_MEM32,
-               .regshift       = 2,
-       },
-       {
-               .flags  = 0,
-       }
-};
-static struct plat_serial8250_port dm646x_serial2_platform_data[] = {
-       {
-               .mapbase        = DAVINCI_UART2_BASE,
-               .irq            = DAVINCI_INTC_IRQ(IRQ_DM646X_UARTINT2),
-               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
-                                 UPF_IOREMAP,
-               .iotype         = UPIO_MEM32,
-               .regshift       = 2,
-       },
-       {
-               .flags  = 0,
-       }
-};
-
-struct platform_device dm646x_serial_device[] = {
-       {
-               .name                   = "serial8250",
-               .id                     = PLAT8250_DEV_PLATFORM,
-               .dev                    = {
-                       .platform_data  = dm646x_serial0_platform_data,
-               }
-       },
-       {
-               .name                   = "serial8250",
-               .id                     = PLAT8250_DEV_PLATFORM1,
-               .dev                    = {
-                       .platform_data  = dm646x_serial1_platform_data,
-               }
-       },
-       {
-               .name                   = "serial8250",
-               .id                     = PLAT8250_DEV_PLATFORM2,
-               .dev                    = {
-                       .platform_data  = dm646x_serial2_platform_data,
-               }
-       },
-       {
-       }
-};
-
-static const struct davinci_soc_info davinci_soc_info_dm646x = {
-       .io_desc                = dm646x_io_desc,
-       .io_desc_num            = ARRAY_SIZE(dm646x_io_desc),
-       .jtag_id_reg            = 0x01c40028,
-       .ids                    = dm646x_ids,
-       .ids_num                = ARRAY_SIZE(dm646x_ids),
-       .pinmux_base            = DAVINCI_SYSTEM_MODULE_BASE,
-       .pinmux_pins            = dm646x_pins,
-       .pinmux_pins_num        = ARRAY_SIZE(dm646x_pins),
-       .emac_pdata             = &dm646x_emac_pdata,
-       .sram_dma               = 0x10010000,
-       .sram_len               = SZ_32K,
-};
-
-void __init dm646x_init_mcasp0(struct snd_platform_data *pdata)
-{
-       dm646x_mcasp0_device.dev.platform_data = pdata;
-       platform_device_register(&dm646x_mcasp0_device);
-}
-
-void __init dm646x_init_mcasp1(struct snd_platform_data *pdata)
-{
-       dm646x_mcasp1_device.dev.platform_data = pdata;
-       platform_device_register(&dm646x_mcasp1_device);
-       platform_device_register(&dm646x_dit_device);
-}
-
-void dm646x_setup_vpif(struct vpif_display_config *display_config,
-                      struct vpif_capture_config *capture_config)
-{
-       unsigned int value;
-
-       value = __raw_readl(DAVINCI_SYSMOD_VIRT(SYSMOD_VSCLKDIS));
-       value &= ~VSCLKDIS_MASK;
-       __raw_writel(value, DAVINCI_SYSMOD_VIRT(SYSMOD_VSCLKDIS));
-
-       value = __raw_readl(DAVINCI_SYSMOD_VIRT(SYSMOD_VDD3P3VPWDN));
-       value &= ~VDD3P3V_VID_MASK;
-       __raw_writel(value, DAVINCI_SYSMOD_VIRT(SYSMOD_VDD3P3VPWDN));
-
-       davinci_cfg_reg(DM646X_STSOMUX_DISABLE);
-       davinci_cfg_reg(DM646X_STSIMUX_DISABLE);
-       davinci_cfg_reg(DM646X_PTSOMUX_DISABLE);
-       davinci_cfg_reg(DM646X_PTSIMUX_DISABLE);
-
-       vpif_display_dev.dev.platform_data = display_config;
-       vpif_capture_dev.dev.platform_data = capture_config;
-       platform_device_register(&vpif_dev);
-       platform_device_register(&vpif_display_dev);
-       platform_device_register(&vpif_capture_dev);
-}
-
-int __init dm646x_init_edma(struct edma_rsv_info *rsv)
-{
-       struct platform_device *edma_pdev;
-
-       dm646x_edma_pdata.rsv = rsv;
-
-       edma_pdev = platform_device_register_full(&dm646x_edma_device);
-       return PTR_ERR_OR_ZERO(edma_pdev);
-}
-
-void __init dm646x_init(void)
-{
-       davinci_common_init(&davinci_soc_info_dm646x);
-       davinci_map_sysmod();
-}
-
-void __init dm646x_init_time(unsigned long ref_clk_rate,
-                            unsigned long aux_clkin_rate)
-{
-       void __iomem *pll1, *psc;
-       struct clk *clk;
-       int rv;
-
-       clk_register_fixed_rate(NULL, "ref_clk", NULL, 0, ref_clk_rate);
-       clk_register_fixed_rate(NULL, "aux_clkin", NULL, 0, aux_clkin_rate);
-
-       pll1 = ioremap(DAVINCI_PLL1_BASE, SZ_1K);
-       dm646x_pll1_init(NULL, pll1, NULL);
-
-       psc = ioremap(DAVINCI_PWR_SLEEP_CNTRL_BASE, SZ_4K);
-       dm646x_psc_init(NULL, psc);
-
-       clk = clk_get(NULL, "timer0");
-       if (WARN_ON(IS_ERR(clk))) {
-               pr_err("Unable to get the timer clock\n");
-               return;
-       }
-
-       rv = davinci_timer_register(clk, &dm646x_timer_cfg);
-       WARN(rv, "Unable to register the timer: %d\n", rv);
-}
-
-static struct resource dm646x_pll2_resources[] = {
-       {
-               .start  = DAVINCI_PLL2_BASE,
-               .end    = DAVINCI_PLL2_BASE + SZ_1K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-};
-
-static struct platform_device dm646x_pll2_device = {
-       .name           = "dm646x-pll2",
-       .id             = -1,
-       .resource       = dm646x_pll2_resources,
-       .num_resources  = ARRAY_SIZE(dm646x_pll2_resources),
-};
-
-void __init dm646x_register_clocks(void)
-{
-       /* PLL1 and PSC are registered in dm646x_init_time() */
-       platform_device_register(&dm646x_pll2_device);
-}
-
-static const struct davinci_aintc_config dm646x_aintc_config = {
-       .reg = {
-               .start          = DAVINCI_ARM_INTC_BASE,
-               .end            = DAVINCI_ARM_INTC_BASE + SZ_4K - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       .num_irqs               = 64,
-       .prios                  = dm646x_default_priorities,
-};
-
-void __init dm646x_init_irq(void)
-{
-       davinci_aintc_init(&dm646x_aintc_config);
-}
-
-static int __init dm646x_init_devices(void)
-{
-       int ret = 0;
-
-       if (!cpu_is_davinci_dm646x())
-               return 0;
-
-       platform_device_register(&dm646x_mdio_device);
-       platform_device_register(&dm646x_emac_device);
-
-       ret = davinci_init_wdt();
-       if (ret)
-               pr_warn("%s: watchdog init failed: %d\n", __func__, ret);
-
-       return ret;
-}
-postcore_initcall(dm646x_init_devices);
index c30c69c..2252f46 100644 (file)
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 menuconfig ARCH_DOVE
        bool "Marvell Dove" if ARCH_MULTI_V7
+       depends on ATAGS
        select CPU_PJ4
        select GPIOLIB
        select MVEBU_MBUS
@@ -8,6 +9,7 @@ menuconfig ARCH_DOVE
        select PINCTRL_DOVE
        select PLAT_ORION_LEGACY
        select PM_GENERIC_DOMAINS if PM
+       select PCI_QUIRKS if PCI
        help
          Support for the Marvell Dove SoC 88AP510
 
index 2a493bd..f90f42f 100644 (file)
@@ -136,14 +136,19 @@ static struct pci_ops pcie_ops = {
        .write = pcie_wr_conf,
 };
 
+/*
+ * The root complex has a hardwired class of PCI_CLASS_MEMORY_OTHER, when it
+ * is operating as a root complex this needs to be switched to
+ * PCI_CLASS_BRIDGE_HOST or Linux will errantly try to process the BAR's on
+ * the device. Decoding setup is handled by the orion code.
+ */
 static void rc_pci_fixup(struct pci_dev *dev)
 {
-       /*
-        * Prevent enumeration of root complex.
-        */
        if (dev->bus->parent == NULL && dev->devfn == 0) {
                int i;
 
+               dev->class &= 0xff;
+               dev->class |= PCI_CLASS_BRIDGE_HOST << 8;
                for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
                        dev->resource[i].start = 0;
                        dev->resource[i].end   = 0;
index 21f4cc2..2c40996 100644 (file)
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 menuconfig ARCH_EP93XX
        bool "EP93xx-based"
+       depends on ATAGS
        depends on ARCH_MULTI_V4T
        depends on CPU_LITTLE_ENDIAN
        select ARCH_SPARSEMEM_ENABLE
@@ -26,6 +27,7 @@ comment "EP93xx Platforms"
 
 config MACH_ADSSPHERE
        bool "Support ADS Sphere"
+       depends on UNUSED_BOARD_FILES
        help
          Say 'Y' here if you want your kernel to support the ADS
          Sphere board.
@@ -98,6 +100,7 @@ config MACH_EDB9315A
 
 config MACH_GESBC9312
        bool "Support Glomation GESBC-9312-sx"
+       depends on UNUSED_BOARD_FILES
        help
          Say 'Y' here if you want your kernel to support the Glomation
          GESBC-9312-sx board.
@@ -108,6 +111,7 @@ config MACH_MICRO9
 config MACH_MICRO9H
        bool "Support Contec Micro9-High"
        select MACH_MICRO9
+       depends on UNUSED_BOARD_FILES
        help
          Say 'Y' here if you want your kernel to support the
          Contec Micro9-High board.
@@ -115,6 +119,7 @@ config MACH_MICRO9H
 config MACH_MICRO9M
        bool "Support Contec Micro9-Mid"
        select MACH_MICRO9
+       depends on UNUSED_BOARD_FILES
        help
          Say 'Y' here if you want your kernel to support the
          Contec Micro9-Mid board.
@@ -122,6 +127,7 @@ config MACH_MICRO9M
 config MACH_MICRO9L
        bool "Support Contec Micro9-Lite"
        select MACH_MICRO9
+       depends on UNUSED_BOARD_FILES
        help
          Say 'Y' here if you want your kernel to support the
          Contec Micro9-Lite board.
@@ -129,18 +135,21 @@ config MACH_MICRO9L
 config MACH_MICRO9S
        bool "Support Contec Micro9-Slim"
        select MACH_MICRO9
+       depends on UNUSED_BOARD_FILES
        help
          Say 'Y' here if you want your kernel to support the
          Contec Micro9-Slim board.
 
 config MACH_SIM_ONE
         bool "Support Simplemachines Sim.One board"
+       depends on UNUSED_BOARD_FILES
         help
           Say 'Y' here if you want your kernel to support the
           Simplemachines Sim.One board.
 
 config MACH_SNAPPER_CL15
        bool "Support Bluewater Systems Snapper CL15 Module"
+       depends on UNUSED_BOARD_FILES
        help
          Say 'Y' here if you want your kernel to support the Bluewater
          Systems Snapper CL15 Module.
index 8b48326..51a247c 100644 (file)
@@ -149,6 +149,7 @@ static void exynos_map_pmu(void)
        np = of_find_matching_node(NULL, exynos_dt_pmu_match);
        if (np)
                pmu_base_addr = of_iomap(np, 0);
+       of_node_put(np);
 }
 
 static void __init exynos_init_irq(void)
index 728aff9..bcd4e4c 100644 (file)
@@ -5,6 +5,7 @@ menu "Footbridge Implementations"
 
 config ARCH_CATS
        bool "CATS"
+       depends on UNUSED_BOARD_FILES
        select CLKEVT_I8253
        select CLKSRC_I8253
        select FOOTBRIDGE_HOST
index 75cccbd..7b34406 100644 (file)
@@ -40,7 +40,7 @@ config ARCH_HIP04
        select HAVE_ARM_ARCH_TIMER
        select MCPM if SMP
        select MCPM_QUAD_CLUSTER if SMP
-       select GENERIC_IRQ_EFFECTIVE_AFF_MASK
+       select GENERIC_IRQ_EFFECTIVE_AFF_MASK if SMP
        help
          Support for Hisilicon HiP04 SoC family
 
index 696c59f..77e435d 100644 (file)
@@ -96,7 +96,7 @@ config SOC_IMX5
        select HAVE_IMX_SRC
        select MXC_TZIC
 
-config SOC_IMX50
+config SOC_IMX50
        bool "i.MX50 support"
        select PINCTRL_IMX50
        select SOC_IMX5
@@ -111,7 +111,7 @@ config SOC_IMX51
        help
          This enables support for Freescale i.MX51 processor
 
-config SOC_IMX53
+config SOC_IMX53
        bool "i.MX53 support"
        select PINCTRL_IMX53
        select SOC_IMX5
@@ -216,7 +216,7 @@ config SOC_IMX7D
        select SOC_IMX7D_CM4 if ARM_SINGLE_ARMV7M
        select ARM_ERRATA_814220 if ARCH_MULTI_V7
        help
-               This enables support for Freescale i.MX7 Dual processor.
+         This enables support for Freescale i.MX7 Dual processor.
 
 config SOC_IMX7ULP
        bool "i.MX7ULP support"
index b2e1963..3e63445 100644 (file)
@@ -32,6 +32,8 @@ static int mx25_read_cpu_rev(void)
                return IMX_CHIP_REVISION_1_0;
        case 0x01:
                return IMX_CHIP_REVISION_1_1;
+       case 0x02:
+               return IMX_CHIP_REVISION_1_2;
        default:
                return IMX_CHIP_REVISION_UNKNOWN;
        }
index 094337d..d086cba 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright (C) 2012 Freescale Semiconductor, Inc.
  */
 
+#include <linux/context_tracking.h>
 #include <linux/cpuidle.h>
 #include <linux/module.h>
 #include <asm/cpuidle.h>
@@ -24,9 +25,9 @@ static int imx6q_enter_wait(struct cpuidle_device *dev,
                imx6_set_lpm(WAIT_UNCLOCKED);
        raw_spin_unlock(&cpuidle_lock);
 
-       rcu_idle_enter();
+       ct_idle_enter();
        cpu_do_idle();
-       rcu_idle_exit();
+       ct_idle_exit();
 
        raw_spin_lock(&cpuidle_lock);
        if (num_idle_cpus-- == num_online_cpus())
index 01f60a8..761fbb0 100644 (file)
@@ -3,6 +3,7 @@ menuconfig ARCH_IOP32X
        bool "IOP32x-based platforms"
        depends on ARCH_MULTI_V5
        depends on CPU_LITTLE_ENDIAN
+       depends on ATAGS && UNUSED_BOARD_FILES
        select CPU_XSCALE
        select GPIO_IOP
        select GPIOLIB
index 4b8ad72..32ac60b 100644 (file)
@@ -71,6 +71,7 @@ static void __init meson_smp_prepare_cpus(const char *scu_compatible,
        }
 
        sram_base = of_iomap(node, 0);
+       of_node_put(node);
        if (!sram_base) {
                pr_err("Couldn't map SRAM registers\n");
                return;
@@ -91,6 +92,7 @@ static void __init meson_smp_prepare_cpus(const char *scu_compatible,
        }
 
        scu_base = of_iomap(node, 0);
+       of_node_put(node);
        if (!scu_base) {
                pr_err("Couldn't map SCU registers\n");
                return;
index 333229c..d71417d 100644 (file)
@@ -18,6 +18,7 @@ if ATAGS
 config MACH_ASPENITE
        bool "Marvell's PXA168 Aspenite Development Board"
        depends on ARCH_MULTI_V5
+       depends on UNUSED_BOARD_FILES
        select CPU_PXA168
        help
          Say 'Y' here if you want to support the Marvell PXA168-based
@@ -26,6 +27,7 @@ config MACH_ASPENITE
 config MACH_ZYLONITE2
        bool "Marvell's PXA168 Zylonite2 Development Board"
        depends on ARCH_MULTI_V5
+       depends on UNUSED_BOARD_FILES
        select CPU_PXA168
        help
          Say 'Y' here if you want to support the Marvell PXA168-based
@@ -34,6 +36,7 @@ config MACH_ZYLONITE2
 config MACH_AVENGERS_LITE
        bool "Marvell's PXA168 Avengers Lite Development Board"
        depends on ARCH_MULTI_V5
+       depends on UNUSED_BOARD_FILES
        select CPU_PXA168
        help
          Say 'Y' here if you want to support the Marvell PXA168-based
@@ -42,6 +45,7 @@ config MACH_AVENGERS_LITE
 config MACH_TTC_DKB
        bool "Marvell's PXA910 TavorEVB/TTC_DKB Development Board"
        depends on ARCH_MULTI_V5
+       depends on UNUSED_BOARD_FILES
        select CPU_PXA910
        help
          Say 'Y' here if you want to support the Marvell PXA910-based
@@ -50,6 +54,7 @@ config MACH_TTC_DKB
 config MACH_BROWNSTONE
        bool "Marvell's Brownstone Development Platform"
        depends on ARCH_MULTI_V7
+       depends on UNUSED_BOARD_FILES
        select CPU_MMP2
        help
          Say 'Y' here if you want to support the Marvell MMP2-based
@@ -61,6 +66,7 @@ config MACH_BROWNSTONE
 config MACH_FLINT
        bool "Marvell's Flint Development Platform"
        depends on ARCH_MULTI_V7
+       depends on UNUSED_BOARD_FILES
        select CPU_MMP2
        help
          Say 'Y' here if you want to support the Marvell MMP2-based
@@ -72,6 +78,7 @@ config MACH_FLINT
 config MACH_MARVELL_JASPER
        bool "Marvell's Jasper Development Platform"
        depends on ARCH_MULTI_V7
+       depends on UNUSED_BOARD_FILES
        select CPU_MMP2
        help
          Say 'Y' here if you want to support the Marvell MMP2-base
@@ -83,6 +90,7 @@ config MACH_MARVELL_JASPER
 config MACH_TETON_BGA
        bool "Marvell's PXA168 Teton BGA Development Board"
        depends on ARCH_MULTI_V5
+       depends on UNUSED_BOARD_FILES
        select CPU_PXA168
        help
          Say 'Y' here if you want to support the Marvell PXA168-based
@@ -91,6 +99,7 @@ config MACH_TETON_BGA
 config MACH_GPLUGD
        bool "Marvell's PXA168 GuruPlug Display (gplugD) Board"
        depends on ARCH_MULTI_V5
+       depends on UNUSED_BOARD_FILES
        select CPU_PXA168
        help
          Say 'Y' here if you want to support the Marvell PXA168-based
index 3ebc1bb..7f80b90 100644 (file)
@@ -5,13 +5,13 @@
 #include <linux/platform_data/pxa_sdhci.h>
 
 extern void mmp2_timer_init(void);
-extern void __init mmp2_init_icu(void);
 extern void __init mmp2_init_irq(void);
 extern void mmp2_clear_pmic_int(void);
 
 #include <linux/i2c.h>
 #include <linux/platform_data/i2c-pxa.h>
 #include <linux/platform_data/dma-mmp_tdma.h>
+#include <linux/irqchip/mmp.h>
 
 #include "devices.h"
 
index 34f907c..c1547e0 100644 (file)
@@ -5,7 +5,6 @@
 #include <linux/reboot.h>
 
 extern void pxa168_timer_init(void);
-extern void __init icu_init_irq(void);
 extern void __init pxa168_init_irq(void);
 extern void pxa168_restart(enum reboot_mode, const char *);
 extern void pxa168_clear_keypad_wakeup(void);
@@ -18,6 +17,7 @@ extern void pxa168_clear_keypad_wakeup(void);
 #include <linux/pxa168_eth.h>
 #include <linux/platform_data/mv_usb.h>
 #include <linux/soc/mmp/cputype.h>
+#include <linux/irqchip/mmp.h>
 
 #include "devices.h"
 
index 6ace5a8..7d22921 100644 (file)
@@ -3,13 +3,13 @@
 #define __ASM_MACH_PXA910_H
 
 extern void pxa910_timer_init(void);
-extern void __init icu_init_irq(void);
 extern void __init pxa910_init_irq(void);
 
 #include <linux/i2c.h>
 #include <linux/platform_data/i2c-pxa.h>
 #include <linux/platform_data/mtd-nand-pxa3xx.h>
 #include <video/mmp_disp.h>
+#include <linux/irqchip/mmp.h>
 
 #include "devices.h"
 
index f0276f0..da92f94 100644 (file)
@@ -3,6 +3,7 @@ menuconfig ARCH_MV78XX0
        bool "Marvell MV78xx0"
        depends on ARCH_MULTI_V5
        depends on CPU_LITTLE_ENDIAN
+       depends on ATAGS && UNUSED_BOARD_FILES
        select CPU_FEROCEON
        select GPIOLIB
        select MVEBU_MBUS
index e15646a..4f1847b 100644 (file)
@@ -180,14 +180,19 @@ static struct pci_ops pcie_ops = {
        .write = pcie_wr_conf,
 };
 
+/*
+ * The root complex has a hardwired class of PCI_CLASS_MEMORY_OTHER, when it
+ * is operating as a root complex this needs to be switched to
+ * PCI_CLASS_BRIDGE_HOST or Linux will errantly try to process the BAR's on
+ * the device. Decoding setup is handled by the orion code.
+ */
 static void rc_pci_fixup(struct pci_dev *dev)
 {
-       /*
-        * Prevent enumeration of root complex.
-        */
        if (dev->bus->parent == NULL && dev->devfn == 0) {
                int i;
 
+               dev->class &= 0xff;
+               dev->class |= PCI_CLASS_BRIDGE_HOST << 8;
                for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
                        dev->resource[i].start = 0;
                        dev->resource[i].end   = 0;
index 0ac0567..538a960 100644 (file)
@@ -3,6 +3,7 @@ menuconfig ARCH_OMAP1
        bool "TI OMAP1"
        depends on ARCH_MULTI_V4T || ARCH_MULTI_V5
        depends on CPU_LITTLE_ENDIAN
+       depends on ATAGS
        select ARCH_HAS_HOLES_MEMORYMODEL
        select ARCH_OMAP
        select CLKSRC_MMIO
@@ -131,6 +132,7 @@ comment "OMAP Board Type"
 config MACH_OMAP_INNOVATOR
        bool "TI Innovator"
        depends on ARCH_OMAP15XX || ARCH_OMAP16XX
+       depends on UNUSED_BOARD_FILES
        help
           TI OMAP 1510 or 1610 Innovator board support. Say Y here if you
           have such a board.
@@ -138,6 +140,7 @@ config MACH_OMAP_INNOVATOR
 config MACH_OMAP_H2
        bool "TI H2 Support"
        depends on ARCH_OMAP16XX
+       depends on UNUSED_BOARD_FILES
        help
          TI OMAP 1610/1611B H2 board support. Say Y here if you have such
          a board.
@@ -145,6 +148,7 @@ config MACH_OMAP_H2
 config MACH_OMAP_H3
        bool "TI H3 Support"
        depends on ARCH_OMAP16XX
+       depends on UNUSED_BOARD_FILES
        help
          TI OMAP 1710 H3 board support. Say Y here if you have such
          a board.
@@ -152,6 +156,7 @@ config MACH_OMAP_H3
 config MACH_HERALD
        bool "HTC Herald"
        depends on ARCH_OMAP850
+       depends on UNUSED_BOARD_FILES
        help
          HTC Herald smartphone support (AKA T-Mobile Wing, ...)
 
@@ -165,6 +170,7 @@ config MACH_OMAP_OSK
 config OMAP_OSK_MISTRAL
        bool "Mistral QVGA board Support"
        depends on MACH_OMAP_OSK
+       depends on UNUSED_BOARD_FILES
        help
          The OSK supports an optional add-on board with a Quarter-VGA
          touchscreen, PDA-ish buttons, a resume button, bicolor LED,
@@ -173,6 +179,7 @@ config OMAP_OSK_MISTRAL
 config MACH_OMAP_PERSEUS2
        bool "TI Perseus2"
        depends on ARCH_OMAP730
+       depends on UNUSED_BOARD_FILES
        help
          Support for TI OMAP 730 Perseus2 board. Say Y here if you have such
          a board.
@@ -180,6 +187,7 @@ config MACH_OMAP_PERSEUS2
 config MACH_OMAP_FSAMPLE
        bool "TI F-Sample"
        depends on ARCH_OMAP730
+       depends on UNUSED_BOARD_FILES
        help
          Support for TI OMAP 850 F-Sample board. Say Y here if you have such
          a board.
@@ -196,6 +204,7 @@ config MACH_OMAP_PALMTE
 config MACH_OMAP_PALMZ71
        bool "Palm Zire71"
        depends on ARCH_OMAP15XX
+       depends on UNUSED_BOARD_FILES
        help
         Support for the Palm Zire71 PDA. To boot the kernel,
         you'll need a PalmOS compatible bootloader; check out
@@ -205,6 +214,7 @@ config MACH_OMAP_PALMZ71
 config MACH_OMAP_PALMTT
        bool "Palm Tungsten|T"
        depends on ARCH_OMAP15XX
+       depends on UNUSED_BOARD_FILES
        help
          Support for the Palm Tungsten|T PDA. To boot the kernel, you'll
          need a PalmOS compatible bootloader (Garux); check out
@@ -245,6 +255,7 @@ config MACH_AMS_DELTA
 config MACH_OMAP_GENERIC
        bool "Generic OMAP board"
        depends on ARCH_OMAP15XX || ARCH_OMAP16XX
+       depends on UNUSED_BOARD_FILES
        help
           Support for generic OMAP-1510, 1610 or 1710 board with
           no FPGA. Can be used as template for porting Linux to
index a8adbb4..3b53dda 100644 (file)
@@ -105,6 +105,7 @@ config ARCH_OMAP2PLUS
        select MACH_OMAP_GENERIC
        select MEMORY
        select MFD_SYSCON
+       select OMAP_DM_SYSTIMER
        select OMAP_DM_TIMER
        select OMAP_GPMC
        select PINCTRL
@@ -122,7 +123,7 @@ config ARCH_OMAP2PLUS
 config OMAP_INTERCONNECT_BARRIER
        bool
        select ARM_HEAVY_MB
-       
+
 config ARCH_OMAP
        bool
 
@@ -209,6 +210,7 @@ config SOC_OMAP2420
        bool "OMAP2420 support"
        depends on ARCH_OMAP2
        default y
+       select OMAP_DM_SYSTIMER
        select OMAP_DM_TIMER
        select SOC_HAS_OMAP2_SDRC
 
@@ -241,10 +243,10 @@ config MACH_OMAP2_TUSB6010
        default y if MACH_NOKIA_N8X0
 
 config MACH_NOKIA_N810
-       bool
+       bool
 
 config MACH_NOKIA_N810_WIMAX
-       bool
+       bool
 
 config MACH_NOKIA_N8X0
        bool "Nokia N800/N810"
index 21413a9..8d829f3 100644 (file)
@@ -211,6 +211,7 @@ static int __init omapdss_init_fbdev(void)
        node = of_find_node_by_name(NULL, "omap4_padconf_global");
        if (node)
                omap4_dsi_mux_syscon = syscon_node_to_regmap(node);
+       of_node_put(node);
 
        return 0;
 }
@@ -259,11 +260,13 @@ static int __init omapdss_init_of(void)
 
        if (!pdev) {
                pr_err("Unable to find DSS platform device\n");
+               of_node_put(node);
                return -ENODEV;
        }
 
        r = of_platform_populate(node, NULL, NULL, &pdev->dev);
        put_device(&pdev->dev);
+       of_node_put(node);
        if (r) {
                pr_err("Unable to populate DSS submodule devices\n");
                return r;
index 13f1b89..5b99d60 100644 (file)
@@ -540,6 +540,8 @@ pdata_quirks_init_clocks(const struct of_device_id *omap_dt_match_table)
 
                of_platform_populate(np, omap_dt_match_table,
                                     omap_auxdata_lookup, NULL);
+
+               of_node_put(np);
        }
 }
 
index 1b442b1..63e73e9 100644 (file)
@@ -708,6 +708,7 @@ static int omap3xxx_prm_late_init(void)
        }
 
        irq_num = of_irq_get(np, 0);
+       of_node_put(np);
        if (irq_num == -EPROBE_DEFER)
                return irq_num;
 
index bf833b5..0044b28 100644 (file)
@@ -7,6 +7,7 @@ menuconfig ARCH_ORION5X
        select GPIOLIB
        select MVEBU_MBUS
        select FORCE_PCI
+       select PCI_QUIRKS
        select PHYLIB if NETDEVICES
        select PLAT_ORION_LEGACY
        help
@@ -30,6 +31,7 @@ config ARCH_ORION5X_DT
 config MACH_DB88F5281
        bool "Marvell Orion-2 Development Board"
        select I2C_BOARDINFO if I2C
+       depends on ATAGS && UNUSED_BOARD_FILES
        help
          Say 'Y' here if you want your kernel to support the
          Marvell Orion-2 (88F5281) Development Board
@@ -37,6 +39,7 @@ config MACH_DB88F5281
 config MACH_RD88F5182
        bool "Marvell Orion-NAS Reference Design"
        select I2C_BOARDINFO if I2C
+       depends on ATAGS && UNUSED_BOARD_FILES
        help
          Say 'Y' here if you want your kernel to support the
          Marvell Orion-NAS (88F5182) RD2
@@ -52,6 +55,7 @@ config MACH_RD88F5182_DT
 config MACH_KUROBOX_PRO
        bool "KuroBox Pro"
        select I2C_BOARDINFO if I2C
+       depends on ATAGS
        help
          Say 'Y' here if you want your kernel to support the
          KuroBox Pro platform.
@@ -59,24 +63,28 @@ config MACH_KUROBOX_PRO
 config MACH_DNS323
        bool "D-Link DNS-323"
        select I2C_BOARDINFO if I2C
+       depends on ATAGS
        help
          Say 'Y' here if you want your kernel to support the
          D-Link DNS-323 platform.
 
 config MACH_TS209
        bool "QNAP TS-109/TS-209"
+       depends on ATAGS
        help
          Say 'Y' here if you want your kernel to support the
          QNAP TS-109/TS-209 platform.
 
 config MACH_TERASTATION_PRO2
        bool "Buffalo Terastation Pro II/Live"
+       depends on ATAGS
        help
          Say 'Y' here if you want your kernel to support the
          Buffalo Terastation Pro II/Live platform.
 
 config MACH_LINKSTATION_PRO
        bool "Buffalo Linkstation Pro/Live"
+       depends on ATAGS
        select I2C_BOARDINFO if I2C
        help
          Say 'Y' here if you want your kernel to support the
@@ -92,6 +100,7 @@ config MACH_LINKSTATION_MINI
 
 config MACH_LINKSTATION_LS_HGL
        bool "Buffalo Linkstation LS-HGL"
+       depends on ATAGS && UNUSED_BOARD_FILES
        select I2C_BOARDINFO if I2C
        help
          Say 'Y' here if you want your kernel to support the
@@ -99,24 +108,28 @@ config MACH_LINKSTATION_LS_HGL
 
 config MACH_TS409
        bool "QNAP TS-409"
+       depends on ATAGS
        help
          Say 'Y' here if you want your kernel to support the
          QNAP TS-409 platform.
 
 config MACH_WRT350N_V2
        bool "Linksys WRT350N v2"
+       depends on ATAGS && UNUSED_BOARD_FILES
        help
          Say 'Y' here if you want your kernel to support the
          Linksys WRT350N v2 platform.
 
 config MACH_TS78XX
        bool "Technologic Systems TS-78xx"
+       depends on ATAGS
        help
          Say 'Y' here if you want your kernel to support the
          Technologic Systems TS-78xx platform.
 
 config MACH_MV2120
        bool "HP Media Vault mv2120"
+       depends on ATAGS
        help
          Say 'Y' here if you want your kernel to support the
          HP Media Vault mv2120 or mv5100.
@@ -130,6 +143,7 @@ config MACH_D2NET_DT
 
 config MACH_NET2BIG
        bool "LaCie 2Big Network"
+       depends on ATAGS
        select I2C_BOARDINFO if I2C
        help
          Say 'Y' here if you want your kernel to support the
@@ -144,24 +158,28 @@ config MACH_MSS2_DT
 
 config MACH_WNR854T
        bool "Netgear WNR854T"
+       depends on ATAGS && UNUSED_BOARD_FILES
        help
          Say 'Y' here if you want your kernel to support the
          Netgear WNR854T platform.
 
 config MACH_RD88F5181L_GE
        bool "Marvell Orion-VoIP GE Reference Design"
+       depends on ATAGS && UNUSED_BOARD_FILES
        help
          Say 'Y' here if you want your kernel to support the
          Marvell Orion-VoIP GE (88F5181L) RD.
 
 config MACH_RD88F5181L_FXO
        bool "Marvell Orion-VoIP FXO Reference Design"
+       depends on ATAGS && UNUSED_BOARD_FILES
        help
          Say 'Y' here if you want your kernel to support the
          Marvell Orion-VoIP FXO (88F5181L) RD.
 
 config MACH_RD88F6183AP_GE
        bool "Marvell Orion-1-90 AP GE Reference Design"
+       depends on ATAGS && UNUSED_BOARD_FILES
        help
          Say 'Y' here if you want your kernel to support the
          Marvell Orion-1-90 (88F6183) AP GE RD.
index 92e938b..9574c73 100644 (file)
@@ -515,14 +515,20 @@ static int __init pci_setup(struct pci_sys_data *sys)
 /*****************************************************************************
  * General PCIe + PCI
  ****************************************************************************/
+
+/*
+ * The root complex has a hardwired class of PCI_CLASS_MEMORY_OTHER, when it
+ * is operating as a root complex this needs to be switched to
+ * PCI_CLASS_BRIDGE_HOST or Linux will errantly try to process the BAR's on
+ * the device. Decoding setup is handled by the orion code.
+ */
 static void rc_pci_fixup(struct pci_dev *dev)
 {
-       /*
-        * Prevent enumeration of root complex.
-        */
        if (dev->bus->parent == NULL && dev->devfn == 0) {
                int i;
 
+               dev->class &= 0xff;
+               dev->class |= PCI_CLASS_BRIDGE_HOST << 8;
                for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
                        dev->resource[i].start = 0;
                        dev->resource[i].end   = 0;
index a5df1d9..b90d98b 100644 (file)
@@ -54,14 +54,18 @@ config MACH_PXA3XX_DT
          the device tree. Needn't select any other machine while
          MACH_PXA3XX_DT is enabled.
 
+if ATAGS
+
 config ARCH_LUBBOCK
        bool "Intel DBPXA250 Development Platform (aka Lubbock)"
+       depends on UNUSED_BOARD_FILES
        select GPIO_REG
        select PXA25x
        select SA1111
 
 config MACH_MAINSTONE
        bool "Intel HCDDBBVA0 Development Platform (aka Mainstone)"
+       depends on UNUSED_BOARD_FILES
        select GPIO_REG
        select PXA27x
 
@@ -71,23 +75,27 @@ config MACH_ZYLONITE
 
 config MACH_ZYLONITE300
        bool "PXA3xx Development Platform (aka Zylonite) PXA300/310"
+       depends on UNUSED_BOARD_FILES
        select CPU_PXA300
        select CPU_PXA310
        select MACH_ZYLONITE
 
 config MACH_ZYLONITE320
        bool "PXA3xx Development Platform (aka Zylonite) PXA320"
+       depends on UNUSED_BOARD_FILES
        select CPU_PXA320
        select MACH_ZYLONITE
 
 config MACH_LITTLETON
        bool "PXA3xx Form Factor Platform (aka Littleton)"
+       depends on UNUSED_BOARD_FILES
        select CPU_PXA300
        select CPU_PXA310
        select PXA3xx
 
 config MACH_TAVOREVB
        bool "PXA930 Evaluation Board (aka TavorEVB)"
+       depends on UNUSED_BOARD_FILES
        select CPU_PXA930
        select CPU_PXA935
        select PXA3xx
@@ -96,6 +104,7 @@ config MACH_TAVOREVB
 
 config MACH_SAAR
        bool "PXA930 Handheld Platform (aka SAAR)"
+       depends on UNUSED_BOARD_FILES
        select CPU_PXA930
        select CPU_PXA935
        select PXA3xx
@@ -106,10 +115,12 @@ comment "Third Party Dev Platforms (sorted by vendor name)"
 
 config ARCH_PXA_IDP
        bool "Accelent Xscale IDP"
+       depends on UNUSED_BOARD_FILES
        select PXA25x
 
 config ARCH_VIPER
        bool "Arcom/Eurotech VIPER SBC"
+       depends on UNUSED_BOARD_FILES
        select ARCOM_PCMCIA
        select I2C_GPIO if I2C=y
        select ISA
@@ -117,17 +128,20 @@ config ARCH_VIPER
 
 config MACH_ARCOM_ZEUS
        bool "Arcom/Eurotech ZEUS SBC"
+       depends on UNUSED_BOARD_FILES
        select ARCOM_PCMCIA
        select ISA
        select PXA27x
 
 config MACH_BALLOON3
        bool "Balloon 3 board"
+       depends on UNUSED_BOARD_FILES
        select IWMMXT
        select PXA27x
 
 config MACH_CSB726
        bool "Enable Cogent CSB726 System On a Module"
+       depends on UNUSED_BOARD_FILES
        select IWMMXT
        select PXA27x
        help
@@ -136,16 +150,19 @@ config MACH_CSB726
 
 config CSB726_CSB701
        bool "Enable support for CSB701 baseboard"
+       depends on UNUSED_BOARD_FILES
        depends on MACH_CSB726
 
 config MACH_CM_X300
        bool "CompuLab CM-X300 modules"
+       depends on UNUSED_BOARD_FILES
        select CPU_PXA300
        select CPU_PXA310
        select PXA3xx
 
 config MACH_CAPC7117
        bool "Embedian CAPC-7117 evaluation kit based on the MXM-8x10 CoM"
+       depends on UNUSED_BOARD_FILES
        select CPU_PXA320
        select PXA3xx
 
@@ -170,6 +187,7 @@ endchoice
 
 config MACH_XCEP
        bool "Iskratel Electronics XCEP"
+       depends on UNUSED_BOARD_FILES
        select MTD
        select MTD_CFI
        select MTD_CFI_INTELEXT
@@ -181,6 +199,7 @@ config MACH_XCEP
 
 config TRIZEPS_PXA
        bool "PXA based Keith und Koep Trizeps DIMM-Modules"
+       depends on UNUSED_BOARD_FILES
 
 config MACH_TRIZEPS4
        bool "Keith und Koep Trizeps4 DIMM-Module"
@@ -222,15 +241,18 @@ config TRIZEPS_PCMCIA
 
 config MACH_LOGICPD_PXA270
        bool "LogicPD PXA270 Card Engine Development Platform"
+       depends on UNUSED_BOARD_FILES
        select PXA27x
 
 config MACH_PCM027
        bool "Phytec phyCORE-PXA270 CPU module (PCM-027)"
+       depends on UNUSED_BOARD_FILES
        select IWMMXT
        select PXA27x
 
 config MACH_PCM990_BASEBOARD
        bool "PHYTEC PCM-990 development board"
+       depends on UNUSED_BOARD_FILES
        depends on MACH_PCM027
 
 choice
@@ -250,30 +272,36 @@ endchoice
 
 config MACH_COLIBRI
        bool "Toradex Colibri PXA270"
+       depends on UNUSED_BOARD_FILES
        select PXA27x
 
 config MACH_COLIBRI_PXA270_INCOME
        bool "Income s.r.o. PXA270 SBC"
+       depends on UNUSED_BOARD_FILES
        depends on MACH_COLIBRI
        select PXA27x
 
 config MACH_COLIBRI300
        bool "Toradex Colibri PXA300/310"
+       depends on UNUSED_BOARD_FILES
        select CPU_PXA300
        select CPU_PXA310
        select PXA3xx
 
 config MACH_COLIBRI320
        bool "Toradex Colibri PXA320"
+       depends on UNUSED_BOARD_FILES
        select CPU_PXA320
        select PXA3xx
 
 config MACH_COLIBRI_EVALBOARD
        bool "Toradex Colibri Evaluation Carrier Board support"
+       depends on UNUSED_BOARD_FILES
        depends on MACH_COLIBRI || MACH_COLIBRI300 || MACH_COLIBRI320
 
 config MACH_VPAC270
        bool "Voipac PXA270"
+       depends on UNUSED_BOARD_FILES
        select HAVE_PATA_PLATFORM
        select PXA27x
        help
@@ -283,24 +311,29 @@ comment "End-user Products (sorted by vendor name)"
 
 config MACH_H4700
        bool "HP iPAQ hx4700"
+       depends on UNUSED_BOARD_FILES
        select IWMMXT
        select PXA27x
 
 config MACH_H5000
        bool "HP iPAQ h5000"
+       depends on UNUSED_BOARD_FILES
        select PXA25x
 
 config MACH_HIMALAYA
        bool "HTC Himalaya Support"
+       depends on UNUSED_BOARD_FILES
        select CPU_PXA26x
 
 config MACH_MAGICIAN
        bool "Enable HTC Magician Support"
+       depends on UNUSED_BOARD_FILES
        select IWMMXT
        select PXA27x
 
 config MACH_MIOA701
        bool "Mitac Mio A701 Support"
+       depends on UNUSED_BOARD_FILES
        select IWMMXT
        select PXA27x
        help
@@ -310,6 +343,7 @@ config MACH_MIOA701
 
 config PXA_EZX
        bool "Motorola EZX Platform"
+       depends on UNUSED_BOARD_FILES
        select IWMMXT
        select PXA27x
 
@@ -345,16 +379,19 @@ config MACH_EZX_E2
 
 config MACH_MP900C
        bool "Nec Mobilepro 900/c"
+       depends on UNUSED_BOARD_FILES
        select PXA25x
 
 config ARCH_PXA_PALM
        bool "PXA based Palm PDAs"
+       depends on UNUSED_BOARD_FILES
 
 config MACH_PALM27X
        bool
 
 config MACH_PALMTE2
        bool "Palm Tungsten|E2"
+       depends on UNUSED_BOARD_FILES
        default y
        depends on ARCH_PXA_PALM
        select PXA25x
@@ -373,6 +410,7 @@ config MACH_PALMTC
 
 config MACH_PALMT5
        bool "Palm Tungsten|T5"
+       depends on UNUSED_BOARD_FILES
        default y
        depends on ARCH_PXA_PALM
        select IWMMXT
@@ -384,6 +422,7 @@ config MACH_PALMT5
 
 config MACH_PALMTX
        bool "Palm T|X"
+       depends on UNUSED_BOARD_FILES
        default y
        depends on ARCH_PXA_PALM
        select IWMMXT
@@ -395,6 +434,7 @@ config MACH_PALMTX
 
 config MACH_PALMZ72
        bool "Palm Zire 72"
+       depends on UNUSED_BOARD_FILES
        default y
        depends on ARCH_PXA_PALM
        select IWMMXT
@@ -406,6 +446,7 @@ config MACH_PALMZ72
 
 config MACH_PALMLD
        bool "Palm LifeDrive"
+       depends on UNUSED_BOARD_FILES
        default y
        depends on ARCH_PXA_PALM
        select IWMMXT
@@ -421,6 +462,7 @@ config PALM_TREO
 
 config MACH_CENTRO
        bool "Palm Centro 685 (GSM)"
+       depends on UNUSED_BOARD_FILES
        default y
        depends on ARCH_PXA_PALM
        select IWMMXT
@@ -433,6 +475,7 @@ config MACH_CENTRO
 
 config MACH_TREO680
        bool "Palm Treo 680"
+       depends on UNUSED_BOARD_FILES
        default y
        depends on ARCH_PXA_PALM
        select IWMMXT
@@ -465,24 +508,28 @@ config PXA_SHARPSL_DETECT_MACH_ID
 config MACH_POODLE
        bool "Enable Sharp SL-5600 (Poodle) Support"
        depends on PXA_SHARPSL
+       depends on UNUSED_BOARD_FILES
        select PXA25x
        select SHARP_LOCOMO
 
 config MACH_CORGI
        bool "Enable Sharp SL-C700 (Corgi) Support"
        depends on PXA_SHARPSL
+       depends on UNUSED_BOARD_FILES
        select PXA25x
        select PXA_SHARP_C7xx
 
 config MACH_SHEPHERD
        bool "Enable Sharp SL-C750 (Shepherd) Support"
        depends on PXA_SHARPSL
+       depends on UNUSED_BOARD_FILES
        select PXA25x
        select PXA_SHARP_C7xx
 
 config MACH_HUSKY
        bool "Enable Sharp SL-C760 (Husky) Support"
        depends on PXA_SHARPSL
+       depends on UNUSED_BOARD_FILES
        select PXA25x
        select PXA_SHARP_C7xx
 
@@ -509,6 +556,7 @@ config MACH_BORZOI
 
 config MACH_TOSA
        bool "Enable Sharp SL-6000x (Tosa) Support"
+       depends on UNUSED_BOARD_FILES
        depends on PXA_SHARPSL
        select PXA25x
 
@@ -532,11 +580,13 @@ config TOSA_USE_EXT_KEYCODES
 
 config MACH_ICONTROL
        bool "TMT iControl/SafeTCam based on the MXM-8x10 CoM"
+       depends on UNUSED_BOARD_FILES
        select CPU_PXA320
        select PXA3xx
 
 config ARCH_PXA_ESERIES
        bool "PXA based Toshiba e-series PDAs"
+       depends on UNUSED_BOARD_FILES
        select FB_W100
        select FB
        select PXA25x
@@ -591,7 +641,10 @@ config MACH_E800
 
 config MACH_ZIPIT2
        bool "Zipit Z2 Handheld"
+       depends on UNUSED_BOARD_FILES
        select PXA27x
+
+endif # ATAGS
 endmenu
 
 config PXA25x
index c546356..5738496 100644 (file)
@@ -549,7 +549,7 @@ static struct pxa2xx_spi_controller corgi_spi_info = {
 };
 
 static struct gpiod_lookup_table corgi_spi_gpio_table = {
-       .dev_id = "pxa2xx-spi.1",
+       .dev_id = "spi1",
        .table = {
                GPIO_LOOKUP_IDX("gpio-pxa", CORGI_GPIO_ADS7846_CS, "cs", 0, GPIO_ACTIVE_LOW),
                GPIO_LOOKUP_IDX("gpio-pxa", CORGI_GPIO_LCDCON_CS, "cs", 1, GPIO_ACTIVE_LOW),
index 2ae06ed..2fd6659 100644 (file)
@@ -635,7 +635,7 @@ static struct pxa2xx_spi_controller pxa_ssp2_master_info = {
 };
 
 static struct gpiod_lookup_table pxa_ssp2_gpio_table = {
-       .dev_id = "pxa2xx-spi.2",
+       .dev_id = "spi2",
        .table = {
                GPIO_LOOKUP_IDX("gpio-pxa", GPIO88_HX4700_TSC2046_CS, "cs", 0, GPIO_ACTIVE_LOW),
                { },
index 753fe16..6240882 100644 (file)
@@ -140,7 +140,7 @@ struct platform_device pxa_spi_ssp4 = {
 };
 
 static struct gpiod_lookup_table pxa_ssp3_gpio_table = {
-       .dev_id = "pxa2xx-spi.3",
+       .dev_id = "spi3",
        .table = {
                GPIO_LOOKUP_IDX("gpio-pxa", ICONTROL_MCP251x_nCS1, "cs", 0, GPIO_ACTIVE_LOW),
                GPIO_LOOKUP_IDX("gpio-pxa", ICONTROL_MCP251x_nCS2, "cs", 1, GPIO_ACTIVE_LOW),
@@ -149,7 +149,7 @@ static struct gpiod_lookup_table pxa_ssp3_gpio_table = {
 };
 
 static struct gpiod_lookup_table pxa_ssp4_gpio_table = {
-       .dev_id = "pxa2xx-spi.4",
+       .dev_id = "spi4",
        .table = {
                GPIO_LOOKUP_IDX("gpio-pxa", ICONTROL_MCP251x_nCS3, "cs", 0, GPIO_ACTIVE_LOW),
                GPIO_LOOKUP_IDX("gpio-pxa", ICONTROL_MCP251x_nCS4, "cs", 1, GPIO_ACTIVE_LOW),
index f98dc61..98423a9 100644 (file)
@@ -207,7 +207,7 @@ static struct spi_board_info littleton_spi_devices[] __initdata = {
 };
 
 static struct gpiod_lookup_table littleton_spi_gpio_table = {
-       .dev_id = "pxa2xx-spi.2",
+       .dev_id = "spi2",
        .table = {
                GPIO_LOOKUP_IDX("gpio-pxa", LITTLETON_GPIO_LCD_CS, "cs", 0, GPIO_ACTIVE_LOW),
                { },
index 20456a5..0827ebc 100644 (file)
@@ -994,7 +994,7 @@ static struct pxa2xx_spi_controller magician_spi_info = {
 };
 
 static struct gpiod_lookup_table magician_spi_gpio_table = {
-       .dev_id = "pxa2xx-spi.2",
+       .dev_id = "spi2",
        .table = {
                /* NOTICE must be GPIO, incompatibility with hw PXA SPI framing */
                GPIO_LOOKUP_IDX("gpio-pxa", GPIO14_MAGICIAN_TSC2046_CS, "cs", 0, GPIO_ACTIVE_LOW),
index dd88953..9964729 100644 (file)
@@ -578,7 +578,7 @@ static struct pxa2xx_spi_controller spitz_spi_info = {
 };
 
 static struct gpiod_lookup_table spitz_spi_gpio_table = {
-       .dev_id = "pxa2xx-spi.2",
+       .dev_id = "spi2",
        .table = {
                GPIO_LOOKUP_IDX("gpio-pxa", SPITZ_GPIO_ADS7846_CS, "cs", 0, GPIO_ACTIVE_LOW),
                GPIO_LOOKUP_IDX("gpio-pxa", SPITZ_GPIO_LCDCON_CS, "cs", 1, GPIO_ACTIVE_LOW),
index d035205..c4d4162 100644 (file)
@@ -623,7 +623,7 @@ static struct pxa2xx_spi_controller pxa_ssp2_master_info = {
 };
 
 static struct gpiod_lookup_table pxa_ssp1_gpio_table = {
-       .dev_id = "pxa2xx-spi.1",
+       .dev_id = "spi1",
        .table = {
                GPIO_LOOKUP_IDX("gpio-pxa", GPIO24_ZIPITZ2_WIFI_CS, "cs", 0, GPIO_ACTIVE_LOW),
                { },
@@ -631,7 +631,7 @@ static struct gpiod_lookup_table pxa_ssp1_gpio_table = {
 };
 
 static struct gpiod_lookup_table pxa_ssp2_gpio_table = {
-       .dev_id = "pxa2xx-spi.2",
+       .dev_id = "spi2",
        .table = {
                GPIO_LOOKUP_IDX("gpio-pxa", GPIO88_ZIPITZ2_LCD_CS, "cs", 0, GPIO_ACTIVE_LOW),
                { },
index 109e126..12a812e 100644 (file)
@@ -20,6 +20,10 @@ 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
index 65a0d5c..5d2f386 100644 (file)
@@ -384,6 +384,7 @@ static const struct smp_operations qcom_smp_cortex_a7_ops __initconst = {
 #endif
 };
 CPU_METHOD_OF_DECLARE(qcom_smp_msm8226, "qcom,msm8226-smp", &qcom_smp_cortex_a7_ops);
+CPU_METHOD_OF_DECLARE(qcom_smp_msm8909, "qcom,msm8909-smp", &qcom_smp_cortex_a7_ops);
 CPU_METHOD_OF_DECLARE(qcom_smp_msm8916, "qcom,msm8916-smp", &qcom_smp_cortex_a7_ops);
 
 static const struct smp_operations qcom_smp_kpssv1_ops __initconst = {
index 87389d9..30d781d 100644 (file)
@@ -311,7 +311,7 @@ void __init rockchip_suspend_init(void)
                                             &match);
        if (!match) {
                pr_err("Failed to find PMU node\n");
-               return;
+               goto out_put;
        }
        pm_data = (struct rockchip_pm_data *) match->data;
 
@@ -320,9 +320,12 @@ void __init rockchip_suspend_init(void)
 
                if (ret) {
                        pr_err("%s: matches init error %d\n", __func__, ret);
-                       return;
+                       goto out_put;
                }
        }
 
        suspend_set_ops(pm_data->ops);
+
+out_put:
+       of_node_put(np);
 }
index 54548c0..a641435 100644 (file)
@@ -43,12 +43,12 @@ config SAMSUNG_ATAGS
        def_bool n
        depends on ATAGS
        help
-          This option enables ATAGS based boot support code for
-          Samsung platforms, including static platform devices, legacy
-          clock, timer and interrupt initialization, etc.
+         This option enables ATAGS based boot support code for
+         Samsung platforms, including static platform devices, legacy
+         clock, timer and interrupt initialization, etc.
 
-          Platforms that support only DT based boot need not to select
-          this option.
+         Platforms that support only DT based boot need not to select
+         this option.
 
 if SAMSUNG_ATAGS
 
@@ -102,7 +102,7 @@ config S3C_DEV_HSMMC3
 config S3C_DEV_HWMON
        bool
        help
-           Compile in platform device definitions for HWMON
+         Compile in platform device definitions for HWMON
 
 config S3C_DEV_I2C1
        bool
@@ -194,7 +194,7 @@ config S3C64XX_DEV_SPI0
 config SAMSUNG_DEV_TS
        bool
        help
-           Common in platform device definitions for touchscreen device
+         Common in platform device definitions for touchscreen device
 
 config SAMSUNG_DEV_KEYPAD
        bool
index 662c5ae..7287e17 100644 (file)
@@ -8,7 +8,7 @@ menuconfig ARCH_S3C24XX
        bool "Samsung S3C24XX SoCs (deprecated, see help)"
        depends on ARCH_MULTI_V4T || ARCH_MULTI_V5
        depends on CPU_LITTLE_ENDIAN
-       select ATAGS
+       depends on ATAGS && UNUSED_BOARD_FILES
        select CLKSRC_SAMSUNG_PWM
        select GPIO_SAMSUNG
        select GPIOLIB
@@ -37,8 +37,6 @@ config PLAT_S3C24XX
        help
          Base platform code for any Samsung S3C24XX device
 
-
-
 menu "Samsung S3C24XX SoCs Support"
 
 comment "S3C24XX SoCs"
@@ -293,7 +291,7 @@ config MACH_VR1000
        help
          Say Y here if you are using the Thorcom VR1000 board.
 
-endif  # CPU_S3C2410
+endif # CPU_S3C2410
 
 config S3C2412_PM_SLEEP
        bool
@@ -367,7 +365,7 @@ config MACH_VSTMS
        help
          Say Y here if you are using an VSTMS board
 
-endif  # CPU_S3C2412
+endif # CPU_S3C2412
 
 if CPU_S3C2416
 
@@ -415,7 +413,7 @@ config MACH_S3C2416_DT
          Note: This is under development and not all peripherals can be supported
          with this machine file.
 
-endif  # CPU_S3C2416
+endif # CPU_S3C2416
 
 if CPU_S3C2440 || CPU_S3C2442
 
@@ -444,7 +442,7 @@ config S3C2440_PLL_16934400
        default y if S3C24XX_PLL
        help
          PLL tables for S3C2440 or S3C2442 CPUs with 16.934MHz crystals.
-endif
+endif # CPU_S3C2440 || CPU_S3C2442
 
 if CPU_S3C2440
 
@@ -540,7 +538,7 @@ config SMDK2440_CPU2440
        default y if ARCH_S3C2440
        select S3C2440_XTAL_16934400
 
-endif  # CPU_S3C2440
+endif # CPU_S3C2440
 
 if CPU_S3C2442
 
@@ -559,7 +557,7 @@ config MACH_NEO1973_GTA02
        select POWER_SUPPLY
        select S3C_DEV_USB_HOST
        help
-          Say Y here if you are using the Openmoko GTA02 / Freerunner GSM Phone
+         Say Y here if you are using the Openmoko GTA02 / Freerunner GSM Phone
 
 config MACH_RX1950
        bool "HP iPAQ rx1950"
@@ -570,9 +568,9 @@ config MACH_RX1950
        select S3C2440_XTAL_16934400
        select S3C_DEV_NAND
        help
-          Say Y here if you're using HP iPAQ rx1950
+         Say Y here if you're using HP iPAQ rx1950
 
-endif  # CPU_S3C2442
+endif # CPU_S3C2442
 
 if CPU_S3C2443 || CPU_S3C2416
 
@@ -581,7 +579,7 @@ config S3C2443_SETUP_SPI
        help
          Common setup code for SPI GPIO configurations
 
-endif  # CPU_S3C2443 || CPU_S3C2416
+endif # CPU_S3C2443 || CPU_S3C2416
 
 if CPU_S3C2443
 
@@ -594,13 +592,13 @@ config MACH_SMDK2443
        help
          Say Y here if you are using an SMDK2443
 
-endif  # CPU_S3C2443
+endif # CPU_S3C2443
 
 config PM_H1940
        bool
        help
          Internal node for H1940 and related PM
 
-endmenu        # Samsung S3C24XX SoCs Support
+endmenu # "Samsung S3C24XX SoCs Support"
 
-endif  # ARCH_S3C24XX
+endif # ARCH_S3C24XX
index 2b27bff..0c1b91c 100644 (file)
@@ -104,7 +104,7 @@ config S3C64XX_SETUP_SDHCI_GPIO
 config S3C64XX_SETUP_SPI
        bool
        help
-        Common setup code for SPI GPIO configurations
+         Common setup code for SPI GPIO configurations
 
 config S3C64XX_SETUP_USB_PHY
        bool
@@ -114,8 +114,8 @@ config S3C64XX_SETUP_USB_PHY
 # S36400 Macchine support
 
 config MACH_SMDK6400
-       bool "SMDK6400"
-       depends on ATAGS
+       bool "SMDK6400"
+       depends on ATAGS && UNUSED_BOARD_FILES
        select CPU_S3C6400
        select S3C64XX_SETUP_SDHCI
        select S3C_DEV_HSMMC1
@@ -126,7 +126,7 @@ config MACH_SMDK6400
 
 config MACH_ANW6410
        bool "A&W6410"
-       depends on ATAGS
+       depends on ATAGS && UNUSED_BOARD_FILES
        select CPU_S3C6410
        select S3C64XX_SETUP_FB_24BPP
        select S3C_DEV_FB
@@ -135,7 +135,7 @@ config MACH_ANW6410
 
 config MACH_MINI6410
        bool "MINI6410"
-       depends on ATAGS
+       depends on ATAGS && UNUSED_BOARD_FILES
        select CPU_S3C6410
        select S3C64XX_SETUP_FB_24BPP
        select S3C64XX_SETUP_SDHCI
@@ -151,7 +151,7 @@ config MACH_MINI6410
 
 config MACH_REAL6410
        bool "REAL6410"
-       depends on ATAGS
+       depends on ATAGS && UNUSED_BOARD_FILES
        select CPU_S3C6410
        select S3C64XX_SETUP_FB_24BPP
        select S3C64XX_SETUP_SDHCI
@@ -167,7 +167,7 @@ config MACH_REAL6410
 
 config MACH_SMDK6410
        bool "SMDK6410"
-       depends on ATAGS
+       depends on ATAGS && UNUSED_BOARD_FILES
        select CPU_S3C6410
        select S3C64XX_SETUP_FB_24BPP
        select S3C64XX_SETUP_I2C1
@@ -205,7 +205,7 @@ config SMDK6410_SD_CH0
        bool "Use channel 0 only"
        depends on MACH_SMDK6410
        help
-          Select CON7 (channel 0) as the MMC/SD slot, as
+         Select CON7 (channel 0) as the MMC/SD slot, as
          at least some SMDK6410 boards come with the
          resistors fitted so that the card detects for
          channels 0 and 1 are the same.
@@ -214,7 +214,7 @@ config SMDK6410_SD_CH1
        bool "Use channel 1 only"
        depends on MACH_SMDK6410
        help
-          Select CON6 (channel 1) as the MMC/SD slot, as
+         Select CON6 (channel 1) as the MMC/SD slot, as
          at least some SMDK6410 boards come with the
          resistors fitted so that the card detects for
          channels 0 and 1 are the same.
@@ -254,17 +254,17 @@ config SMDK6410_WM1192_EV1
 
 config MACH_NCP
        bool "NCP"
-       depends on ATAGS
+       depends on ATAGS && UNUSED_BOARD_FILES
        select CPU_S3C6410
        select S3C64XX_SETUP_I2C1
        select S3C_DEV_HSMMC1
        select S3C_DEV_I2C1
        help
-          Machine support for the Samsung NCP
+         Machine support for the Samsung NCP
 
 config MACH_HMT
        bool "Airgoo HMT"
-       depends on ATAGS
+       depends on ATAGS && UNUSED_BOARD_FILES
        select CPU_S3C6410
        select S3C64XX_SETUP_FB_24BPP
        select S3C_DEV_FB
@@ -292,21 +292,21 @@ config MACH_SMARTQ
        select SAMSUNG_DEV_PWM
        select SAMSUNG_DEV_TS
        help
-           Shared machine support for SmartQ 5/7
+         Shared machine support for SmartQ 5/7
 
 config MACH_SMARTQ5
        bool "SmartQ 5"
-       depends on ATAGS
+       depends on ATAGS && UNUSED_BOARD_FILES
        select MACH_SMARTQ
        help
-           Machine support for the SmartQ 5
+         Machine support for the SmartQ 5
 
 config MACH_SMARTQ7
        bool "SmartQ 7"
-       depends on ATAGS
+       depends on ATAGS && UNUSED_BOARD_FILES
        select MACH_SMARTQ
        help
-           Machine support for the SmartQ 7
+         Machine support for the SmartQ 7
 
 config MACH_WLF_CRAGG_6410
        bool "Wolfson Cragganmore 6410"
index 131015c..a6d17ff 100644 (file)
@@ -624,7 +624,7 @@ static char mini2440_features_str[12] __initdata = "0tb";
 static int __init mini2440_features_setup(char *str)
 {
        if (str)
-               strlcpy(mini2440_features_str, str,
+               strscpy(mini2440_features_str, str,
                        sizeof(mini2440_features_str));
        return 1;
 }
index 66e79fa..7e0161c 100644 (file)
@@ -25,6 +25,7 @@ config ASSABET_NEPONSET
 
 config SA1100_CERF
        bool "CerfBoard"
+       depends on UNUSED_BOARD_FILES
        select ARM_SA1110_CPUFREQ
        select LEDS_GPIO_REGISTER
        help
@@ -62,6 +63,7 @@ config SA1100_COLLIE
 
 config SA1100_H3100
        bool "Compaq iPAQ H3100"
+       depends on UNUSED_BOARD_FILES
        select ARM_SA1110_CPUFREQ
        select HTC_EGPIO
        select MFD_IPAQ_MICRO
@@ -80,6 +82,7 @@ config SA1100_H3600
 
 config SA1100_BADGE4
        bool "HP Labs BadgePAD 4"
+       depends on UNUSED_BOARD_FILES
        select ARM_SA1100_CPUFREQ
        select SA1111
        help
@@ -88,6 +91,7 @@ config SA1100_BADGE4
 
 config SA1100_JORNADA720
        bool "HP Jornada 720"
+       depends on UNUSED_BOARD_FILES
        # FIXME: select ARM_SA11x0_CPUFREQ
        select SA1111
        help
@@ -107,6 +111,7 @@ config SA1100_JORNADA720_SSP
 
 config SA1100_HACKKIT
        bool "HackKit Core CPU Board"
+       depends on UNUSED_BOARD_FILES
        select ARM_SA1100_CPUFREQ
        help
          Say Y here to support the HackKit Core CPU Board
@@ -114,6 +119,7 @@ config SA1100_HACKKIT
 
 config SA1100_LART
        bool "LART"
+       depends on UNUSED_BOARD_FILES
        select ARM_SA1100_CPUFREQ
        help
          Say Y here if you are using the Linux Advanced Radio Terminal
@@ -122,6 +128,7 @@ config SA1100_LART
 
 config SA1100_NANOENGINE
        bool "nanoEngine"
+       depends on UNUSED_BOARD_FILES
        select ARM_SA1110_CPUFREQ
        select FORCE_PCI
        select PCI_NANOENGINE
@@ -132,6 +139,7 @@ config SA1100_NANOENGINE
 
 config SA1100_PLEB
        bool "PLEB"
+       depends on UNUSED_BOARD_FILES
        select ARM_SA1100_CPUFREQ
        help
          Say Y here if you are using version 1 of the Portable Linux
@@ -141,6 +149,7 @@ config SA1100_PLEB
 
 config SA1100_SHANNON
        bool "Shannon"
+       depends on UNUSED_BOARD_FILES
        select ARM_SA1100_CPUFREQ
        select REGULATOR
        select REGULATOR_FIXED_VOLTAGE
@@ -152,6 +161,7 @@ config SA1100_SHANNON
 
 config SA1100_SIMPAD
        bool "Simpad"
+       depends on UNUSED_BOARD_FILES
        select ARM_SA1110_CPUFREQ
        help
          The SIEMENS webpad SIMpad is based on the StrongARM 1110. There
@@ -163,6 +173,7 @@ config SA1100_SIMPAD
 
 config SA1100_SSP
        tristate "Generic PIO SSP"
+       depends on UNUSED_BOARD_FILES
        help
          Say Y here to enable support for the generic PIO SSP driver.
          This isn't for audio support, but for attached sensors and
index abea41f..117e7b0 100644 (file)
@@ -125,6 +125,7 @@ remove:
 
        list_for_each_entry_safe(pos, tmp, &quirk_list, list) {
                list_del(&pos->list);
+               of_node_put(pos->np);
                kfree(pos);
        }
 
@@ -174,11 +175,12 @@ static int __init rcar_gen2_regulator_quirk(void)
                memcpy(&quirk->i2c_msg, id->data, sizeof(quirk->i2c_msg));
 
                quirk->id = id;
-               quirk->np = np;
+               quirk->np = of_node_get(np);
                quirk->i2c_msg.addr = addr;
 
                ret = of_irq_parse_one(np, 0, argsa);
                if (ret) {      /* Skip invalid entry and continue */
+                       of_node_put(np);
                        kfree(quirk);
                        continue;
                }
@@ -225,6 +227,7 @@ err_free:
 err_mem:
        list_for_each_entry_safe(pos, tmp, &quirk_list, list) {
                list_del(&pos->list);
+               of_node_put(pos->np);
                kfree(pos);
        }
 
index d1fdb60..c7c17c0 100644 (file)
@@ -218,13 +218,13 @@ void __init spear_setup_of_timer(void)
        irq = irq_of_parse_and_map(np, 0);
        if (!irq) {
                pr_err("%s: No irq passed for timer via DT\n", __func__);
-               return;
+               goto err_put_np;
        }
 
        gpt_base = of_iomap(np, 0);
        if (!gpt_base) {
                pr_err("%s: of iomap failed\n", __func__);
-               return;
+               goto err_put_np;
        }
 
        gpt_clk = clk_get_sys("gpt0", NULL);
@@ -239,6 +239,8 @@ void __init spear_setup_of_timer(void)
                goto err_prepare_enable_clk;
        }
 
+       of_node_put(np);
+
        spear_clockevent_init(irq);
        spear_clocksource_init();
 
@@ -248,4 +250,6 @@ err_prepare_enable_clk:
        clk_put(gpt_clk);
 err_iomap:
        iounmap(gpt_base);
+err_put_np:
+       of_node_put(np);
 }
diff --git a/arch/arm/mach-sunplus/Kconfig b/arch/arm/mach-sunplus/Kconfig
new file mode 100644 (file)
index 0000000..926cde5
--- /dev/null
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+
+menuconfig ARCH_SUNPLUS
+       bool "Sunplus SoCs"
+       depends on ARCH_MULTI_V7
+       help
+         Support for Sunplus SoC family: SP7021 and succeeding SoC-based systems,
+         such as the Banana Pi BPI-F2S development board (and derivatives).
+         (<http://www.sinovoip.com.cn/ecp_view.asp?id=586>)
+         (<https://tibbo.com/store/plus1.html>)
+
+config SOC_SP7021
+       bool "Sunplus SP7021 SoC support"
+       depends on ARCH_SUNPLUS
+       default ARCH_SUNPLUS
+       select HAVE_ARM_ARCH_TIMER
+       select ARM_GIC
+       select ARM_PSCI
+       select PINCTRL
+       select PINCTRL_SPPCTL
+       select SERIAL_SUNPLUS
+       select SERIAL_SUNPLUS_CONSOLE
+       help
+         Support for Sunplus SP7021 SoC. It is based on ARM 4-core
+         Cortex-A7 with various peripherals (e.g.: I2C, SPI, SDIO,
+         Ethernet, etc.), FPGA interface,  chip-to-chip bus.
+         It is designed for industrial control.
diff --git a/arch/arm/mach-sunplus/Makefile b/arch/arm/mach-sunplus/Makefile
new file mode 100644 (file)
index 0000000..d211de6
--- /dev/null
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the linux kernel.
+#
+
+# Object file lists.
+
+obj-$(CONFIG_SOC_SP7021)       += sp7021.o
diff --git a/arch/arm/mach-sunplus/sp7021.c b/arch/arm/mach-sunplus/sp7021.c
new file mode 100644 (file)
index 0000000..774d0a5
--- /dev/null
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * Copyright (C) Sunplus Technology Co., Ltd.
+ *       All rights reserved.
+ */
+#include <linux/kernel.h>
+#include <asm/mach/arch.h>
+
+static const char *sp7021_compat[] __initconst = {
+       "sunplus,sp7021",
+       NULL
+};
+
+DT_MACHINE_START(SP7021_DT, "SP7021")
+       .dt_compat      = sp7021_compat,
+MACHINE_END
index e1ca6a5..15e8a32 100644 (file)
@@ -77,6 +77,7 @@ static int __init zynq_get_revision(void)
        }
 
        zynq_devcfg_base = of_iomap(np, 0);
+       of_node_put(np);
        if (!zynq_devcfg_base) {
                pr_err("%s: Unable to map I/O memory\n", __func__);
                return -1;
index a3a4589..fc439c2 100644 (file)
@@ -631,7 +631,11 @@ config CPU_USE_DOMAINS
        bool
        help
          This option enables or disables the use of domain switching
-         via the set_fs() function.
+         using the DACR (domain access control register) to protect memory
+         domains from each other. In Linux we use three domains: kernel, user
+         and IO. The domains are used to protect userspace from kernelspace
+         and to handle IO-space as a special type of memory by assigning
+         manager or client roles to running code (such as a process).
 
 config CPU_V7M_NUM_IRQ
        int "Number of external interrupts connected to the NVIC"
index 6f49955..f8dd0b3 100644 (file)
@@ -935,6 +935,9 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
        if (type == TYPE_LDST)
                do_alignment_finish_ldst(addr, instr, regs, offset);
 
+       if (thumb_mode(regs))
+               regs->ARM_cpsr = it_advance(regs->ARM_cpsr);
+
        return 0;
 
  bad_or_fault:
index 576c0e6..2129070 100644 (file)
@@ -418,7 +418,7 @@ void *arch_memremap_wb(phys_addr_t phys_addr, size_t size)
                                                   __builtin_return_address(0));
 }
 
-void __iounmap(volatile void __iomem *io_addr)
+void iounmap(volatile void __iomem *io_addr)
 {
        void *addr = (void *)(PAGE_MASK & (unsigned long)io_addr);
        struct static_vm *svm;
@@ -446,13 +446,6 @@ void __iounmap(volatile void __iomem *io_addr)
 
        vunmap(addr);
 }
-
-void (*arch_iounmap)(volatile void __iomem *) = __iounmap;
-
-void iounmap(volatile void __iomem *cookie)
-{
-       arch_iounmap(cookie);
-}
 EXPORT_SYMBOL(iounmap);
 
 #if defined(CONFIG_PCI) || IS_ENABLED(CONFIG_PCMCIA)
index 5e2be37..cd17e32 100644 (file)
@@ -296,6 +296,13 @@ static struct mem_type mem_types[] __ro_after_init = {
                .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,
                .domain    = DOMAIN_KERNEL,
        },
+       [MT_MEMORY_RO] = {
+               .prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+                            L_PTE_XN | L_PTE_RDONLY,
+               .prot_l1   = PMD_TYPE_TABLE,
+               .prot_sect = PMD_TYPE_SECT,
+               .domain    = DOMAIN_KERNEL,
+       },
        [MT_ROM] = {
                .prot_sect = PMD_TYPE_SECT,
                .domain    = DOMAIN_KERNEL,
@@ -489,6 +496,7 @@ static void __init build_mem_type_table(void)
 
                        /* Also setup NX memory mapping */
                        mem_types[MT_MEMORY_RW].prot_sect |= PMD_SECT_XN;
+                       mem_types[MT_MEMORY_RO].prot_sect |= PMD_SECT_XN;
                }
                if (cpu_arch >= CPU_ARCH_ARMv7 && (cr & CR_TRE)) {
                        /*
@@ -568,6 +576,7 @@ static void __init build_mem_type_table(void)
                mem_types[MT_ROM].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
                mem_types[MT_MINICLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
                mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
+               mem_types[MT_MEMORY_RO].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
 #endif
 
                /*
@@ -587,6 +596,8 @@ static void __init build_mem_type_table(void)
                        mem_types[MT_MEMORY_RWX].prot_pte |= L_PTE_SHARED;
                        mem_types[MT_MEMORY_RW].prot_sect |= PMD_SECT_S;
                        mem_types[MT_MEMORY_RW].prot_pte |= L_PTE_SHARED;
+                       mem_types[MT_MEMORY_RO].prot_sect |= PMD_SECT_S;
+                       mem_types[MT_MEMORY_RO].prot_pte |= L_PTE_SHARED;
                        mem_types[MT_MEMORY_DMA_READY].prot_pte |= L_PTE_SHARED;
                        mem_types[MT_MEMORY_RWX_NONCACHED].prot_sect |= PMD_SECT_S;
                        mem_types[MT_MEMORY_RWX_NONCACHED].prot_pte |= L_PTE_SHARED;
@@ -647,6 +658,8 @@ static void __init build_mem_type_table(void)
        mem_types[MT_MEMORY_RWX].prot_pte |= kern_pgprot;
        mem_types[MT_MEMORY_RW].prot_sect |= ecc_mask | cp->pmd;
        mem_types[MT_MEMORY_RW].prot_pte |= kern_pgprot;
+       mem_types[MT_MEMORY_RO].prot_sect |= ecc_mask | cp->pmd;
+       mem_types[MT_MEMORY_RO].prot_pte |= kern_pgprot;
        mem_types[MT_MEMORY_DMA_READY].prot_pte |= kern_pgprot;
        mem_types[MT_MEMORY_RWX_NONCACHED].prot_sect |= ecc_mask;
        mem_types[MT_ROM].prot_sect |= cp->pmd;
@@ -1360,7 +1373,7 @@ static void __init devicemaps_init(const struct machine_desc *mdesc)
                map.pfn = __phys_to_pfn(__atags_pointer & SECTION_MASK);
                map.virtual = FDT_FIXED_BASE;
                map.length = FDT_FIXED_SIZE;
-               map.type = MT_ROM;
+               map.type = MT_MEMORY_RO;
                create_mapping(&map);
        }
 
index 2658f52..c42deba 100644 (file)
@@ -230,14 +230,7 @@ void *arch_memremap_wb(phys_addr_t phys_addr, size_t size)
        return (void *)phys_addr;
 }
 
-void __iounmap(volatile void __iomem *addr)
-{
-}
-EXPORT_SYMBOL(__iounmap);
-
-void (*arch_iounmap)(volatile void __iomem *);
-
-void iounmap(volatile void __iomem *addr)
+void iounmap(volatile void __iomem *io_addr)
 {
 }
 EXPORT_SYMBOL(iounmap);
index fb9f3eb..8bc7a2d 100644 (file)
@@ -108,8 +108,7 @@ static unsigned int spectre_v2_install_workaround(unsigned int method)
 #else
 static unsigned int spectre_v2_install_workaround(unsigned int method)
 {
-       pr_info("CPU%u: Spectre V2: workarounds disabled by configuration\n",
-               smp_processor_id());
+       pr_info_once("Spectre V2: workarounds disabled by configuration\n");
 
        return SPECTRE_VULNERABLE;
 }
@@ -209,10 +208,10 @@ static int spectre_bhb_install_workaround(int method)
                        return SPECTRE_VULNERABLE;
 
                spectre_bhb_method = method;
-       }
 
-       pr_info("CPU%u: Spectre BHB: using %s workaround\n",
-               smp_processor_id(), spectre_bhb_method_name(method));
+               pr_info("CPU%u: Spectre BHB: enabling %s workaround for all CPUs\n",
+                       smp_processor_id(), spectre_bhb_method_name(method));
+       }
 
        return SPECTRE_MITIGATED;
 }
index 9731735..facc889 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/types.h>
 #include <linux/stddef.h>
 #include <asm/probes.h>
+#include <asm/ptrace.h>
 #include <asm/kprobes.h>
 
 void __init arm_probes_decode_init(void);
@@ -35,31 +36,6 @@ void __init find_str_pc_offset(void);
 #endif
 
 
-/*
- * Update ITSTATE after normal execution of an IT block instruction.
- *
- * The 8 IT state bits are split into two parts in CPSR:
- *     ITSTATE<1:0> are in CPSR<26:25>
- *     ITSTATE<7:2> are in CPSR<15:10>
- */
-static inline unsigned long it_advance(unsigned long cpsr)
-       {
-       if ((cpsr & 0x06000400) == 0) {
-               /* ITSTATE<2:0> == 0 means end of IT block, so clear IT state */
-               cpsr &= ~PSR_IT_MASK;
-       } else {
-               /* We need to shift left ITSTATE<4:0> */
-               const unsigned long mask = 0x06001c00;  /* Mask ITSTATE<4:0> */
-               unsigned long it = cpsr & mask;
-               it <<= 1;
-               it |= it >> (27 - 10);  /* Carry ITSTATE<2> to correct place */
-               it &= mask;
-               cpsr &= ~mask;
-               cpsr |= it;
-       }
-       return cpsr;
-}
-
 static inline void __kprobes bx_write_pc(long pcv, struct pt_regs *regs)
 {
        long cpsr = regs->ARM_cpsr;
index 84a1cea..309648c 100644 (file)
@@ -63,11 +63,12 @@ out:
 
 unsigned long __pfn_to_mfn(unsigned long pfn)
 {
-       struct rb_node *n = phys_to_mach.rb_node;
+       struct rb_node *n;
        struct xen_p2m_entry *entry;
        unsigned long irqflags;
 
        read_lock_irqsave(&p2m_lock, irqflags);
+       n = phys_to_mach.rb_node;
        while (n) {
                entry = rb_entry(n, struct xen_p2m_entry, rbnode_phys);
                if (entry->pfn <= pfn &&
@@ -152,10 +153,11 @@ bool __set_phys_to_machine_multi(unsigned long pfn,
        int rc;
        unsigned long irqflags;
        struct xen_p2m_entry *p2m_entry;
-       struct rb_node *n = phys_to_mach.rb_node;
+       struct rb_node *n;
 
        if (mfn == INVALID_P2M_ENTRY) {
                write_lock_irqsave(&p2m_lock, irqflags);
+               n = phys_to_mach.rb_node;
                while (n) {
                        p2m_entry = rb_entry(n, struct xen_p2m_entry, rbnode_phys);
                        if (p2m_entry->pfn <= pfn &&
index 1652a98..e05fc97 100644 (file)
@@ -101,6 +101,7 @@ config ARM64
        select ARCH_WANT_HUGETLB_PAGE_OPTIMIZE_VMEMMAP
        select ARCH_WANT_LD_ORPHAN_WARN
        select ARCH_WANTS_NO_INSTR
+       select ARCH_WANTS_THP_SWAP if ARM64_4K_PAGES
        select ARCH_HAS_UBSAN_SANITIZE_ALL
        select ARM_AMBA
        select ARM_ARCH_TIMER
@@ -126,6 +127,7 @@ config ARM64
        select GENERIC_CPU_VULNERABILITIES
        select GENERIC_EARLY_IOREMAP
        select GENERIC_IDLE_POLL_SETUP
+       select GENERIC_IOREMAP
        select GENERIC_IRQ_IPI
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
@@ -174,7 +176,7 @@ config ARM64
        select HAVE_C_RECORDMCOUNT
        select HAVE_CMPXCHG_DOUBLE
        select HAVE_CMPXCHG_LOCAL
-       select HAVE_CONTEXT_TRACKING
+       select HAVE_CONTEXT_TRACKING_USER
        select HAVE_DEBUG_KMEMLEAK
        select HAVE_DMA_CONTIGUOUS
        select HAVE_DYNAMIC_FTRACE
@@ -188,6 +190,7 @@ config ARM64
        select HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_GCC_PLUGINS
        select HAVE_HW_BREAKPOINT if PERF_EVENTS
+       select HAVE_IOREMAP_PROT
        select HAVE_IRQ_TIME_ACCOUNTING
        select HAVE_KVM
        select HAVE_NMI
@@ -226,6 +229,7 @@ config ARM64
        select THREAD_INFO_IN_TASK
        select HAVE_ARCH_USERFAULTFD_MINOR if USERFAULTFD
        select TRACE_IRQFLAGS_SUPPORT
+       select TRACE_IRQFLAGS_NMI_SUPPORT
        help
          ARM 64-bit (AArch64) Linux support.
 
@@ -503,6 +507,22 @@ config ARM64_ERRATUM_834220
 
          If unsure, say Y.
 
+config ARM64_ERRATUM_1742098
+       bool "Cortex-A57/A72: 1742098: ELR recorded incorrectly on interrupt taken between cryptographic instructions in a sequence"
+       depends on COMPAT
+       default y
+       help
+         This option removes the AES hwcap for aarch32 user-space to
+         workaround erratum 1742098 on Cortex-A57 and Cortex-A72.
+
+         Affected parts may corrupt the AES state if an interrupt is
+         taken between a pair of AES instructions. These instructions
+         are only present if the cryptography extensions are present.
+         All software should have a fallback implementation for CPUs
+         that don't implement the cryptography extensions.
+
+         If unsure, say Y.
+
 config ARM64_ERRATUM_845719
        bool "Cortex-A53: 845719: a load might read incorrect data"
        depends on COMPAT
@@ -821,6 +841,23 @@ config ARM64_ERRATUM_2224489
 
          If unsure, say Y.
 
+config ARM64_ERRATUM_2441009
+       bool "Cortex-A510: Completion of affected memory accesses might not be guaranteed by completion of a TLBI"
+       default y
+       select ARM64_WORKAROUND_REPEAT_TLBI
+       help
+         This option adds a workaround for ARM Cortex-A510 erratum #2441009.
+
+         Under very rare circumstances, affected Cortex-A510 CPUs
+         may not handle a race between a break-before-make sequence on one
+         CPU, and another CPU accessing the same page. This could allow a
+         store to a page that has been unmapped.
+
+         Work around this by adding the affected CPUs to the list that needs
+         TLB sequences to be done twice.
+
+         If unsure, say Y.
+
 config ARM64_ERRATUM_2064142
        bool "Cortex-A510: 2064142: workaround TRBE register writes while disabled"
        depends on CORESIGHT_TRBE
@@ -1858,14 +1895,6 @@ config ARM64_E0PD
 
          This option enables E0PD for TTBR1 where available.
 
-config ARCH_RANDOM
-       bool "Enable support for random number generation"
-       default y
-       help
-         Random number generation (part of the ARMv8.5 Extensions)
-         provides a high bandwidth, cryptographically secure
-         hardware random number generator.
-
 config ARM64_AS_HAS_MTE
        # Initial support for MTE went in binutils 2.32.0, checked with
        # ".arch armv8.5-a+memtag" below. However, this was incomplete
index 4e6d635..74e9e9d 100644 (file)
@@ -49,6 +49,7 @@ config ARCH_BCM2835
 
 config ARCH_BCM4908
        bool "Broadcom BCM4908 family"
+       select ARCH_BCMBCA
        select GPIOLIB
        help
          This enables support for the Broadcom BCM4906, BCM4908 and
@@ -63,6 +64,15 @@ config ARCH_BCM_IPROC
        help
          This enables support for Broadcom iProc based SoCs
 
+config ARCH_BCMBCA
+       bool "Broadcom Broadband Carrier Access (BCA) origin SoC"
+       help
+         Say Y if you intend to run the kernel on a Broadcom Broadband ARM-based
+         BCA chipset.
+
+         This enables support for Broadcom BCA ARM-based broadband chipsets,
+         including the DSL, PON and Wireless family of chips.
+
 config ARCH_BERLIN
        bool "Marvell Berlin SoC Family"
        select DW_APB_ICTL
@@ -182,11 +192,13 @@ config ARCH_MVEBU
        select PINCTRL_ARMADA_37XX
        select PINCTRL_ARMADA_AP806
        select PINCTRL_ARMADA_CP110
+       select PINCTRL_AC5
        help
          This enables support for Marvell EBU familly, including:
           - Armada 3700 SoC Family
           - Armada 7K SoC Family
           - Armada 8K SoC Family
+          - 98DX2530 SoC Family
 
 config ARCH_MXC
        bool "ARMv8 based NXP i.MX SoC family"
@@ -202,6 +214,17 @@ config ARCH_MXC
          This enables support for the ARMv8 based SoCs in the
          NXP i.MX family.
 
+config ARCH_NPCM
+       bool "Nuvoton NPCM Architecture"
+       select PINCTRL
+       select GPIOLIB
+       select NPCM7XX_TIMER
+       select RESET_CONTROLLER
+       select MFD_SYSCON
+       help
+         General support for NPCM8xx BMC (Arbel).
+         Nuvoton NPCM8xx BMC based on the Cortex A35.
+
 config ARCH_QCOM
        bool "Qualcomm Platforms"
        select GPIOLIB
@@ -248,7 +271,8 @@ config ARCH_INTEL_SOCFPGA
        bool "Intel's SoCFPGA ARMv8 Families"
        help
          This enables support for Intel's SoCFPGA ARMv8 families:
-         Stratix 10 (ex. Altera), Agilex and eASIC N5X.
+         Stratix 10 (ex. Altera), Stratix10 Software Virtual Platform,
+         Agilex and eASIC N5X.
 
 config ARCH_SYNQUACER
        bool "Socionext SynQuacer SoC Family"
index ebe80fa..a0e3ded 100644 (file)
@@ -16,7 +16,7 @@
 
 OBJCOPYFLAGS_Image :=-O binary -R .note -R .note.gnu.build-id -R .comment -S
 
-targets := Image Image.bz2 Image.gz Image.lz4 Image.lzma Image.lzo
+targets := Image Image.bz2 Image.gz Image.lz4 Image.lzma Image.lzo Image.zst
 
 $(obj)/Image: vmlinux FORCE
        $(call if_changed,objcopy)
@@ -35,3 +35,6 @@ $(obj)/Image.lzma: $(obj)/Image FORCE
 
 $(obj)/Image.lzo: $(obj)/Image FORCE
        $(call if_changed,lzo)
+
+$(obj)/Image.zst: $(obj)/Image FORCE
+       $(call if_changed,zstd)
index 1ba04e3..7b107fa 100644 (file)
@@ -19,6 +19,7 @@ subdir-y += lg
 subdir-y += marvell
 subdir-y += mediatek
 subdir-y += microchip
+subdir-y += nuvoton
 subdir-y += nvidia
 subdir-y += qcom
 subdir-y += realtek
index 8fa5c06..6a96494 100644 (file)
@@ -38,3 +38,5 @@ dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-pine-h64.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-pine-h64-model-b.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-tanix-tx6.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-tanix-tx6-mini.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h616-orangepi-zero2.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h616-x96-mate.dtb
index f6d7d7f..548539c 100644 (file)
 
                i2c0: i2c@5002000 {
                        compatible = "allwinner,sun50i-a100-i2c",
+                                    "allwinner,sun8i-v536-i2c",
                                     "allwinner,sun6i-a31-i2c";
                        reg = <0x05002000 0x400>;
                        interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
 
                i2c1: i2c@5002400 {
                        compatible = "allwinner,sun50i-a100-i2c",
+                                    "allwinner,sun8i-v536-i2c",
                                     "allwinner,sun6i-a31-i2c";
                        reg = <0x05002400 0x400>;
                        interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
 
                i2c2: i2c@5002800 {
                        compatible = "allwinner,sun50i-a100-i2c",
+                                    "allwinner,sun8i-v536-i2c",
                                     "allwinner,sun6i-a31-i2c";
                        reg = <0x05002800 0x400>;
                        interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
 
                i2c3: i2c@5002c00 {
                        compatible = "allwinner,sun50i-a100-i2c",
+                                    "allwinner,sun8i-v536-i2c",
                                     "allwinner,sun6i-a31-i2c";
                        reg = <0x05002c00 0x400>;
                        interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
 
                r_i2c0: i2c@7081400 {
                        compatible = "allwinner,sun50i-a100-i2c",
+                                    "allwinner,sun8i-v536-i2c",
                                     "allwinner,sun6i-a31-i2c";
                        reg = <0x07081400 0x400>;
                        interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
 
                r_i2c1: i2c@7081800 {
                        compatible = "allwinner,sun50i-a100-i2c",
+                                    "allwinner,sun8i-v536-i2c",
                                     "allwinner,sun6i-a31-i2c";
                        reg = <0x07081800 0x400>;
                        interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
index f17cc89..8233582 100644 (file)
@@ -58,7 +58,7 @@
 
        wifi_pwrseq: wifi-pwrseq {
                compatible = "mmc-pwrseq-simple";
-               clocks = <&rtc 1>;
+               clocks = <&rtc CLK_OSC32K_FANOUT>;
                clock-names = "ext_clock";
                reset-gpios = <&r_pio 0 2 GPIO_ACTIVE_LOW>; /* WL-PMU-EN: PL2 */
        };
index 997a193..e6d5bc0 100644 (file)
@@ -56,7 +56,7 @@
        wifi_pwrseq: wifi_pwrseq {
                compatible = "mmc-pwrseq-simple";
                reset-gpios = <&r_pio 0 2 GPIO_ACTIVE_LOW>; /* PL2 */
-               clocks = <&rtc 1>;
+               clocks = <&rtc CLK_OSC32K_FANOUT>;
                clock-names = "ext_clock";
        };
 };
 
        bluetooth {
                compatible = "brcm,bcm43438-bt";
-               clocks = <&rtc 1>;
+               clocks = <&rtc CLK_OSC32K_FANOUT>;
                clock-names = "lpo";
                vbat-supply = <&reg_dldo2>;
                vddio-supply = <&reg_dldo4>;
index e47ff06..0af6dcd 100644 (file)
@@ -43,7 +43,7 @@
 
        wifi_pwrseq: wifi_pwrseq {
                compatible = "mmc-pwrseq-simple";
-               clocks = <&rtc 1>;
+               clocks = <&rtc CLK_OSC32K_FANOUT>;
                clock-names = "ext_clock";
                reset-gpios = <&r_pio 0 2 GPIO_ACTIVE_LOW>; /* PL2 */
        };
index c519d9f..4f8529d 100644 (file)
@@ -40,7 +40,7 @@
        leds {
                compatible = "gpio-leds";
 
-               status {
+               led-0 {
                        label = "orangepi:green:status";
                        gpios = <&pio 7 11 GPIO_ACTIVE_HIGH>; /* PH11 */
                };
@@ -71,7 +71,7 @@
        wifi_pwrseq: wifi_pwrseq {
                compatible = "mmc-pwrseq-simple";
                reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>; /* PL8 */
-               clocks = <&rtc 1>;
+               clocks = <&rtc CLK_OSC32K_FANOUT>;
                clock-names = "ext_clock";
        };
 };
        bluetooth {
                compatible = "brcm,bcm43438-bt";
                max-speed = <1500000>;
-               clocks = <&rtc 1>;
+               clocks = <&rtc CLK_OSC32K_FANOUT>;
                clock-names = "lpo";
                vbat-supply = <&reg_dldo2>;
                vddio-supply = <&reg_dldo4>;
index 63571df..620cb3e 100644 (file)
                stdout-path = "serial0:115200n8";
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               lid_switch {
+               lid-switch {
                        label = "Lid Switch";
                        gpios = <&r_pio 0 12 GPIO_ACTIVE_LOW>; /* PL12 */
                        linux,input-type = <EV_SW>;
index fb65319..219f720 100644 (file)
        compatible = "pine64,pinephone-1.0", "pine64,pinephone", "allwinner,sun50i-a64";
 };
 
+&codec_analog {
+       allwinner,internal-bias-resistor;
+};
+
 &sgm3140 {
        enable-gpios = <&pio 2 3 GPIO_ACTIVE_HIGH>; /* PC3 */
        flash-gpios = <&pio 3 24 GPIO_ACTIVE_HIGH>; /* PD24 */
index 5e59d37..723af64 100644 (file)
        default-brightness-level = <400>;
 };
 
+&codec_analog {
+       allwinner,internal-bias-resistor;
+};
+
 &sgm3140 {
        enable-gpios = <&pio 3 24 GPIO_ACTIVE_HIGH>; /* PD24 */
        flash-gpios = <&pio 2 3 GPIO_ACTIVE_HIGH>; /* PC3 */
index de77c87..77b5349 100644 (file)
@@ -4,6 +4,7 @@
 //    Copyright (C) 2015 Jens Kuske <jenskuske@gmail.com>
 
 #include <dt-bindings/clock/sun50i-a64-ccu.h>
+#include <dt-bindings/clock/sun6i-rtc.h>
 #include <dt-bindings/clock/sun8i-de2.h>
 #include <dt-bindings/clock/sun8i-r-ccu.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
                ccu: clock@1c20000 {
                        compatible = "allwinner,sun50i-a64-ccu";
                        reg = <0x01c20000 0x400>;
-                       clocks = <&osc24M>, <&rtc 0>;
+                       clocks = <&osc24M>, <&rtc CLK_OSC32K>;
                        clock-names = "hosc", "losc";
                        #clock-cells = <1>;
                        #reset-cells = <1>;
                        interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&rtc 0>;
+                       clocks = <&ccu CLK_BUS_PIO>, <&osc24M>,
+                                <&rtc CLK_OSC32K>;
                        clock-names = "apb", "hosc", "losc";
                        gpio-controller;
                        #gpio-cells = <3>;
                        reg-io-width = <1>;
                        interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&ccu CLK_BUS_HDMI>, <&ccu CLK_HDMI_DDC>,
-                                <&ccu CLK_HDMI>, <&rtc 0>;
+                                <&ccu CLK_HDMI>, <&rtc CLK_OSC32K>;
                        clock-names = "iahb", "isfr", "tmds", "cec";
                        resets = <&ccu RST_BUS_HDMI1>;
                        reset-names = "ctrl";
                r_ccu: clock@1f01400 {
                        compatible = "allwinner,sun50i-a64-r-ccu";
                        reg = <0x01f01400 0x100>;
-                       clocks = <&osc24M>, <&rtc 0>, <&rtc 2>,
+                       clocks = <&osc24M>, <&rtc CLK_OSC32K>, <&rtc CLK_IOSC>,
                                 <&ccu CLK_PLL_PERIPH0>;
                        clock-names = "hosc", "losc", "iosc", "pll-periph";
                        #clock-cells = <1>;
index 55b3695..a3e040d 100644 (file)
                };
        };
 
-       r-gpio-keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               reset {
+               key-reset {
                        label = "reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
index 1010c1b..b5c1ff1 100644 (file)
                };
        };
 
-       r-gpio-keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               sw4 {
+               key-sw4 {
                        label = "sw4";
                        linux,code = <BTN_0>;
                        gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
index 74e0444..d7f8bad 100644 (file)
                };
        };
 
-       r-gpio-keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               sw4 {
+               key-sw4 {
                        label = "sw4";
                        linux,code = <BTN_0>;
                        gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
index c45d7b7..6fc65e8 100644 (file)
@@ -86,7 +86,7 @@
 
        wifi_pwrseq: wifi-pwrseq {
                compatible = "mmc-pwrseq-simple";
-               clocks = <&rtc 1>;
+               clocks = <&rtc CLK_OSC32K_FANOUT>;
                clock-names = "ext_clock";
                reset-gpios = <&r_pio 1 3 GPIO_ACTIVE_LOW>; /* PM3 */
                post-power-on-delay-ms = <200>;
 
        bluetooth {
                compatible = "brcm,bcm4345c5";
-               clocks = <&rtc 1>;
+               clocks = <&rtc CLK_OSC32K_FANOUT>;
                clock-names = "lpo";
                device-wakeup-gpios = <&r_pio 1 2 GPIO_ACTIVE_HIGH>; /* PM2 */
                host-wakeup-gpios = <&r_pio 1 1 GPIO_ACTIVE_HIGH>; /* PM1 */
index e877085..fb31dcb 100644 (file)
@@ -13,7 +13,7 @@
 
        wifi_pwrseq: wifi_pwrseq {
                compatible = "mmc-pwrseq-simple";
-               clocks = <&rtc 1>;
+               clocks = <&rtc CLK_OSC32K_FANOUT>;
                clock-names = "ext_clock";
                reset-gpios = <&r_pio 1 3 GPIO_ACTIVE_LOW>; /* PM3 */
                post-power-on-delay-ms = <200>;
@@ -64,7 +64,7 @@
 
        bluetooth {
                compatible = "brcm,bcm4345c5";
-               clocks = <&rtc 1>;
+               clocks = <&rtc CLK_OSC32K_FANOUT>;
                clock-names = "lpo";
                device-wakeup-gpios = <&r_pio 1 2 GPIO_ACTIVE_HIGH>; /* PM2 */
                host-wakeup-gpios = <&r_pio 1 1 GPIO_ACTIVE_HIGH>; /* PM1 */
index edb71e4..4903d63 100644 (file)
@@ -78,7 +78,7 @@
 
        wifi_pwrseq: wifi-pwrseq {
                compatible = "mmc-pwrseq-simple";
-               clocks = <&rtc 1>;
+               clocks = <&rtc CLK_OSC32K_FANOUT>;
                clock-names = "ext_clock";
                reset-gpios = <&r_pio 1 3 GPIO_ACTIVE_LOW>; /* PM3 */
        };
index fbe94ab..5a28303 100644 (file)
@@ -4,6 +4,7 @@
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/clock/sun50i-h6-ccu.h>
 #include <dt-bindings/clock/sun50i-h6-r-ccu.h>
+#include <dt-bindings/clock/sun6i-rtc.h>
 #include <dt-bindings/clock/sun8i-de2.h>
 #include <dt-bindings/clock/sun8i-tcon-top.h>
 #include <dt-bindings/reset/sun50i-h6-ccu.h>
                ccu: clock@3001000 {
                        compatible = "allwinner,sun50i-h6-ccu";
                        reg = <0x03001000 0x1000>;
-                       clocks = <&osc24M>, <&rtc 0>, <&rtc 2>;
+                       clocks = <&osc24M>, <&rtc CLK_OSC32K>, <&rtc CLK_IOSC>;
                        clock-names = "hosc", "losc", "iosc";
                        #clock-cells = <1>;
                        #reset-cells = <1>;
                                     <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&ccu CLK_APB1>, <&osc24M>, <&rtc 0>;
+                       clocks = <&ccu CLK_APB1>, <&osc24M>, <&rtc CLK_OSC32K>;
                        clock-names = "apb", "hosc", "losc";
                        gpio-controller;
                        #gpio-cells = <3>;
                        interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&ccu CLK_BUS_XHCI>,
                                 <&ccu CLK_BUS_XHCI>,
-                                <&rtc 0>;
+                                <&rtc CLK_OSC32K>;
                        clock-names = "ref", "bus_early", "suspend";
                        resets = <&ccu RST_BUS_XHCI>;
                        /*
                r_ccu: clock@7010000 {
                        compatible = "allwinner,sun50i-h6-r-ccu";
                        reg = <0x07010000 0x400>;
-                       clocks = <&osc24M>, <&rtc 0>, <&rtc 2>,
+                       clocks = <&osc24M>, <&rtc CLK_OSC32K>, <&rtc CLK_IOSC>,
                                 <&ccu CLK_PLL_PERIPH0>;
                        clock-names = "hosc", "losc", "iosc", "pll-periph";
                        #clock-cells = <1>;
                        interrupt-parent = <&r_intc>;
                        interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&r_ccu CLK_R_APB1>, <&osc24M>, <&rtc 0>;
+                       clocks = <&r_ccu CLK_R_APB1>, <&osc24M>,
+                                <&rtc CLK_OSC32K>;
                        clock-names = "apb", "hosc", "losc";
                        gpio-controller;
                        #gpio-cells = <3>;
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h616-orangepi-zero2.dts b/arch/arm64/boot/dts/allwinner/sun50i-h616-orangepi-zero2.dts
new file mode 100644 (file)
index 0000000..02893f3
--- /dev/null
@@ -0,0 +1,213 @@
+// SPDX-License-Identifier: (GPL-2.0+ or MIT)
+/*
+ * Copyright (C) 2020 Arm Ltd.
+ */
+
+/dts-v1/;
+
+#include "sun50i-h616.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/leds/common.h>
+
+/ {
+       model = "OrangePi Zero2";
+       compatible = "xunlong,orangepi-zero2", "allwinner,sun50i-h616";
+
+       aliases {
+               ethernet0 = &emac0;
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               led-0 {
+                       function = LED_FUNCTION_POWER;
+                       color = <LED_COLOR_ID_RED>;
+                       gpios = <&pio 2 12 GPIO_ACTIVE_HIGH>; /* PC12 */
+                       default-state = "on";
+               };
+
+               led-1 {
+                       function = LED_FUNCTION_STATUS;
+                       color = <LED_COLOR_ID_GREEN>;
+                       gpios = <&pio 2 13 GPIO_ACTIVE_HIGH>; /* PC13 */
+               };
+       };
+
+       reg_vcc5v: 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;
+       };
+};
+
+&emac0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&ext_rgmii_pins>;
+       phy-mode = "rgmii";
+       phy-handle = <&ext_rgmii_phy>;
+       phy-supply = <&reg_dcdce>;
+       allwinner,rx-delay-ps = <3100>;
+       allwinner,tx-delay-ps = <700>;
+       status = "okay";
+};
+
+&mdio0 {
+       ext_rgmii_phy: ethernet-phy@1 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <1>;
+       };
+};
+
+&mmc0 {
+       vmmc-supply = <&reg_dcdce>;
+       cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>;  /* PF6 */
+       bus-width = <4>;
+       status = "okay";
+};
+
+&r_rsb {
+       status = "okay";
+
+       axp305: pmic@745 {
+               compatible = "x-powers,axp305", "x-powers,axp805",
+                            "x-powers,axp806";
+               interrupt-controller;
+               #interrupt-cells = <1>;
+               reg = <0x745>;
+
+               x-powers,self-working-mode;
+               vina-supply = <&reg_vcc5v>;
+               vinb-supply = <&reg_vcc5v>;
+               vinc-supply = <&reg_vcc5v>;
+               vind-supply = <&reg_vcc5v>;
+               vine-supply = <&reg_vcc5v>;
+               aldoin-supply = <&reg_vcc5v>;
+               bldoin-supply = <&reg_vcc5v>;
+               cldoin-supply = <&reg_vcc5v>;
+
+               regulators {
+                       reg_aldo1: aldo1 {
+                               regulator-always-on;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-name = "vcc-sys";
+                       };
+
+                       reg_aldo2: aldo2 {      /* 3.3V on headers */
+                               regulator-always-on;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-name = "vcc3v3-ext";
+                       };
+
+                       reg_aldo3: aldo3 {      /* 3.3V on headers */
+                               regulator-always-on;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-name = "vcc3v3-ext2";
+                       };
+
+                       reg_bldo1: bldo1 {
+                               regulator-always-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-name = "vcc1v8";
+                       };
+
+                       bldo2 {
+                               /* unused */
+                       };
+
+                       bldo3 {
+                               /* unused */
+                       };
+
+                       bldo4 {
+                               /* unused */
+                       };
+
+                       cldo1 {
+                               /* reserved */
+                       };
+
+                       cldo2 {
+                               /* unused */
+                       };
+
+                       cldo3 {
+                               /* unused */
+                       };
+
+                       reg_dcdca: dcdca {
+                               regulator-always-on;
+                               regulator-min-microvolt = <810000>;
+                               regulator-max-microvolt = <1100000>;
+                               regulator-name = "vdd-cpu";
+                       };
+
+                       reg_dcdcc: dcdcc {
+                               regulator-always-on;
+                               regulator-min-microvolt = <810000>;
+                               regulator-max-microvolt = <990000>;
+                               regulator-name = "vdd-gpu-sys";
+                       };
+
+                       reg_dcdcd: dcdcd {
+                               regulator-always-on;
+                               regulator-min-microvolt = <1500000>;
+                               regulator-max-microvolt = <1500000>;
+                               regulator-name = "vdd-dram";
+                       };
+
+                       reg_dcdce: dcdce {
+                               regulator-always-on;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-name = "vcc-eth-mmc";
+                       };
+
+                       sw {
+                               /* unused */
+                       };
+               };
+       };
+};
+
+&pio {
+       vcc-pc-supply = <&reg_aldo1>;
+       vcc-pf-supply = <&reg_aldo1>;
+       vcc-pg-supply = <&reg_bldo1>;
+       vcc-ph-supply = <&reg_aldo1>;
+       vcc-pi-supply = <&reg_aldo1>;
+};
+
+&spi0  {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&spi0_pins>, <&spi0_cs0_pin>;
+
+       flash@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "jedec,spi-nor";
+               reg = <0>;
+               spi-max-frequency = <40000000>;
+       };
+};
+
+&uart0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart0_ph_pins>;
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h616-x96-mate.dts b/arch/arm64/boot/dts/allwinner/sun50i-h616-x96-mate.dts
new file mode 100644 (file)
index 0000000..6619db3
--- /dev/null
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: (GPL-2.0+ or MIT)
+/*
+ * Copyright (C) 2021 Arm Ltd.
+ */
+
+/dts-v1/;
+
+#include "sun50i-h616.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+       model = "X96 Mate";
+       compatible = "hechuang,x96-mate", "allwinner,sun50i-h616";
+
+       aliases {
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       reg_vcc5v: vcc5v {
+               /* 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;
+       };
+};
+
+&ir {
+       status = "okay";
+};
+
+&mmc0 {
+       vmmc-supply = <&reg_dcdce>;
+       cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>;  /* PF6 */
+       bus-width = <4>;
+       status = "okay";
+};
+
+&mmc2 {
+       vmmc-supply = <&reg_dcdce>;
+       vqmmc-supply = <&reg_bldo1>;
+       bus-width = <8>;
+       non-removable;
+       cap-mmc-hw-reset;
+       mmc-ddr-1_8v;
+       mmc-hs200-1_8v;
+       status = "okay";
+};
+
+&r_rsb {
+       status = "okay";
+
+       axp305: pmic@745 {
+               compatible = "x-powers,axp305", "x-powers,axp805",
+                            "x-powers,axp806";
+               interrupt-controller;
+               #interrupt-cells = <1>;
+               reg = <0x745>;
+
+               x-powers,self-working-mode;
+               vina-supply = <&reg_vcc5v>;
+               vinb-supply = <&reg_vcc5v>;
+               vinc-supply = <&reg_vcc5v>;
+               vind-supply = <&reg_vcc5v>;
+               vine-supply = <&reg_vcc5v>;
+               aldoin-supply = <&reg_vcc5v>;
+               bldoin-supply = <&reg_vcc5v>;
+               cldoin-supply = <&reg_vcc5v>;
+
+               regulators {
+                       reg_aldo1: aldo1 {
+                               regulator-always-on;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-name = "vcc-sys";
+                       };
+
+                       /* Enabled by the Android BSP */
+                       reg_aldo2: aldo2 {
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-name = "vcc3v3-ext";
+                               status = "disabled";
+                       };
+
+                       /* Enabled by the Android BSP */
+                       reg_aldo3: aldo3 {
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-name = "vcc3v3-ext2";
+                               status = "disabled";
+                       };
+
+                       reg_bldo1: bldo1 {
+                               regulator-always-on;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-name = "vcc1v8";
+                       };
+
+                       /* Enabled by the Android BSP */
+                       reg_bldo2: bldo2 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-name = "vcc1v8-2";
+                               status = "disabled";
+                       };
+
+                       bldo3 {
+                               /* unused */
+                       };
+
+                       bldo4 {
+                               /* unused */
+                       };
+
+                       cldo1 {
+                               regulator-min-microvolt = <2500000>;
+                               regulator-max-microvolt = <2500000>;
+                               regulator-name = "vcc2v5";
+                       };
+
+                       cldo2 {
+                               /* unused */
+                       };
+
+                       cldo3 {
+                               /* unused */
+                       };
+
+                       reg_dcdca: dcdca {
+                               regulator-always-on;
+                               regulator-min-microvolt = <810000>;
+                               regulator-max-microvolt = <1100000>;
+                               regulator-name = "vdd-cpu";
+                       };
+
+                       reg_dcdcc: dcdcc {
+                               regulator-always-on;
+                               regulator-min-microvolt = <810000>;
+                               regulator-max-microvolt = <990000>;
+                               regulator-name = "vdd-gpu-sys";
+                       };
+
+                       reg_dcdcd: dcdcd {
+                               regulator-always-on;
+                               regulator-min-microvolt = <1360000>;
+                               regulator-max-microvolt = <1360000>;
+                               regulator-name = "vdd-dram";
+                       };
+
+                       reg_dcdce: dcdce {
+                               regulator-always-on;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-name = "vcc-eth-mmc";
+                       };
+
+                       sw {
+                               /* unused */
+                       };
+               };
+       };
+};
+
+&uart0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart0_ph_pins>;
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi
new file mode 100644 (file)
index 0000000..622a1f7
--- /dev/null
@@ -0,0 +1,591 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2020 Arm Ltd.
+// based on the H6 dtsi, which is:
+//   Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/sun50i-h616-ccu.h>
+#include <dt-bindings/clock/sun50i-h6-r-ccu.h>
+#include <dt-bindings/clock/sun6i-rtc.h>
+#include <dt-bindings/reset/sun50i-h616-ccu.h>
+#include <dt-bindings/reset/sun50i-h6-r-ccu.h>
+
+/ {
+       interrupt-parent = <&gic>;
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu0: cpu@0 {
+                       compatible = "arm,cortex-a53";
+                       device_type = "cpu";
+                       reg = <0>;
+                       enable-method = "psci";
+                       clocks = <&ccu CLK_CPUX>;
+               };
+
+               cpu1: cpu@1 {
+                       compatible = "arm,cortex-a53";
+                       device_type = "cpu";
+                       reg = <1>;
+                       enable-method = "psci";
+                       clocks = <&ccu CLK_CPUX>;
+               };
+
+               cpu2: cpu@2 {
+                       compatible = "arm,cortex-a53";
+                       device_type = "cpu";
+                       reg = <2>;
+                       enable-method = "psci";
+                       clocks = <&ccu CLK_CPUX>;
+               };
+
+               cpu3: cpu@3 {
+                       compatible = "arm,cortex-a53";
+                       device_type = "cpu";
+                       reg = <3>;
+                       enable-method = "psci";
+                       clocks = <&ccu CLK_CPUX>;
+               };
+       };
+
+       reserved-memory {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               /*
+                * 256 KiB reserved for Trusted Firmware-A (BL31).
+                * This is added by BL31 itself, but some bootloaders fail
+                * to propagate this into the DTB handed to kernels.
+                */
+               secmon@40000000 {
+                       reg = <0x0 0x40000000 0x0 0x40000>;
+                       no-map;
+               };
+       };
+
+       osc24M: osc24M-clk {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <24000000>;
+               clock-output-names = "osc24M";
+       };
+
+       pmu {
+               compatible = "arm,cortex-a53-pmu";
+               interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
+       };
+
+       psci {
+               compatible = "arm,psci-0.2";
+               method = "smc";
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               arm,no-tick-in-suspend;
+               interrupts = <GIC_PPI 13
+                       (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+                            <GIC_PPI 14
+                       (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+                            <GIC_PPI 11
+                       (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+                            <GIC_PPI 10
+                       (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+       };
+
+       soc {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0x0 0x0 0x0 0x40000000>;
+
+               syscon: syscon@3000000 {
+                       compatible = "allwinner,sun50i-h616-system-control";
+                       reg = <0x03000000 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+
+                       sram_c: sram@28000 {
+                               compatible = "mmio-sram";
+                               reg = <0x00028000 0x30000>;
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                               ranges = <0 0x00028000 0x30000>;
+                       };
+               };
+
+               ccu: clock@3001000 {
+                       compatible = "allwinner,sun50i-h616-ccu";
+                       reg = <0x03001000 0x1000>;
+                       clocks = <&osc24M>, <&rtc CLK_OSC32K>, <&rtc CLK_IOSC>;
+                       clock-names = "hosc", "losc", "iosc";
+                       #clock-cells = <1>;
+                       #reset-cells = <1>;
+               };
+
+               watchdog: watchdog@30090a0 {
+                       compatible = "allwinner,sun50i-h616-wdt",
+                                    "allwinner,sun6i-a31-wdt";
+                       reg = <0x030090a0 0x20>;
+                       interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&osc24M>;
+               };
+
+               pio: pinctrl@300b000 {
+                       compatible = "allwinner,sun50i-h616-pinctrl";
+                       reg = <0x0300b000 0x400>;
+                       interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&ccu CLK_APB1>, <&osc24M>, <&rtc CLK_OSC32K>;
+                       clock-names = "apb", "hosc", "losc";
+                       gpio-controller;
+                       #gpio-cells = <3>;
+                       interrupt-controller;
+                       #interrupt-cells = <3>;
+
+                       ext_rgmii_pins: rgmii-pins {
+                               pins = "PI0", "PI1", "PI2", "PI3", "PI4",
+                                      "PI5", "PI7", "PI8", "PI9", "PI10",
+                                      "PI11", "PI12", "PI13", "PI14", "PI15",
+                                      "PI16";
+                               function = "emac0";
+                               drive-strength = <40>;
+                       };
+
+                       i2c0_pins: i2c0-pins {
+                               pins = "PI6", "PI7";
+                               function = "i2c0";
+                       };
+
+                       i2c3_ph_pins: i2c3-ph-pins {
+                               pins = "PH4", "PH5";
+                               function = "i2c3";
+                       };
+
+                       ir_rx_pin: ir-rx-pin {
+                               pins = "PH10";
+                               function = "ir_rx";
+                       };
+
+                       mmc0_pins: mmc0-pins {
+                               pins = "PF0", "PF1", "PF2", "PF3",
+                                      "PF4", "PF5";
+                               function = "mmc0";
+                               drive-strength = <30>;
+                               bias-pull-up;
+                       };
+
+                       /omit-if-no-ref/
+                       mmc1_pins: mmc1-pins {
+                               pins = "PG0", "PG1", "PG2", "PG3",
+                                      "PG4", "PG5";
+                               function = "mmc1";
+                               drive-strength = <30>;
+                               bias-pull-up;
+                       };
+
+                       mmc2_pins: mmc2-pins {
+                               pins = "PC0", "PC1", "PC5", "PC6",
+                                      "PC8", "PC9", "PC10", "PC11",
+                                      "PC13", "PC14", "PC15", "PC16";
+                               function = "mmc2";
+                               drive-strength = <30>;
+                               bias-pull-up;
+                       };
+
+                       /omit-if-no-ref/
+                       spi0_pins: spi0-pins {
+                               pins = "PC0", "PC2", "PC4";
+                               function = "spi0";
+                       };
+
+                       /omit-if-no-ref/
+                       spi0_cs0_pin: spi0-cs0-pin {
+                               pins = "PC3";
+                               function = "spi0";
+                       };
+
+                       /omit-if-no-ref/
+                       spi1_pins: spi1-pins {
+                               pins = "PH6", "PH7", "PH8";
+                               function = "spi1";
+                       };
+
+                       /omit-if-no-ref/
+                       spi1_cs0_pin: spi1-cs0-pin {
+                               pins = "PH5";
+                               function = "spi1";
+                       };
+
+                       uart0_ph_pins: uart0-ph-pins {
+                               pins = "PH0", "PH1";
+                               function = "uart0";
+                       };
+
+                       /omit-if-no-ref/
+                       uart1_pins: uart1-pins {
+                               pins = "PG6", "PG7";
+                               function = "uart1";
+                       };
+
+                       /omit-if-no-ref/
+                       uart1_rts_cts_pins: uart1-rts-cts-pins {
+                               pins = "PG8", "PG9";
+                               function = "uart1";
+                       };
+               };
+
+               gic: interrupt-controller@3021000 {
+                       compatible = "arm,gic-400";
+                       reg = <0x03021000 0x1000>,
+                             <0x03022000 0x2000>,
+                             <0x03024000 0x2000>,
+                             <0x03026000 0x2000>;
+                       interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+                       interrupt-controller;
+                       #interrupt-cells = <3>;
+               };
+
+               mmc0: mmc@4020000 {
+                       compatible = "allwinner,sun50i-h616-mmc",
+                                    "allwinner,sun50i-a100-mmc";
+                       reg = <0x04020000 0x1000>;
+                       clocks = <&ccu CLK_BUS_MMC0>, <&ccu CLK_MMC0>;
+                       clock-names = "ahb", "mmc";
+                       resets = <&ccu RST_BUS_MMC0>;
+                       reset-names = "ahb";
+                       interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&mmc0_pins>;
+                       status = "disabled";
+                       max-frequency = <150000000>;
+                       cap-sd-highspeed;
+                       cap-mmc-highspeed;
+                       mmc-ddr-3_3v;
+                       cap-sdio-irq;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
+               mmc1: mmc@4021000 {
+                       compatible = "allwinner,sun50i-h616-mmc",
+                                    "allwinner,sun50i-a100-mmc";
+                       reg = <0x04021000 0x1000>;
+                       clocks = <&ccu CLK_BUS_MMC1>, <&ccu CLK_MMC1>;
+                       clock-names = "ahb", "mmc";
+                       resets = <&ccu RST_BUS_MMC1>;
+                       reset-names = "ahb";
+                       interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&mmc1_pins>;
+                       status = "disabled";
+                       max-frequency = <150000000>;
+                       cap-sd-highspeed;
+                       cap-mmc-highspeed;
+                       mmc-ddr-3_3v;
+                       cap-sdio-irq;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
+               mmc2: mmc@4022000 {
+                       compatible = "allwinner,sun50i-h616-emmc",
+                                    "allwinner,sun50i-a100-emmc";
+                       reg = <0x04022000 0x1000>;
+                       clocks = <&ccu CLK_BUS_MMC2>, <&ccu CLK_MMC2>;
+                       clock-names = "ahb", "mmc";
+                       resets = <&ccu RST_BUS_MMC2>;
+                       reset-names = "ahb";
+                       interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&mmc2_pins>;
+                       status = "disabled";
+                       max-frequency = <150000000>;
+                       cap-sd-highspeed;
+                       cap-mmc-highspeed;
+                       mmc-ddr-3_3v;
+                       cap-sdio-irq;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
+               uart0: serial@5000000 {
+                       compatible = "snps,dw-apb-uart";
+                       reg = <0x05000000 0x400>;
+                       interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
+                       reg-shift = <2>;
+                       reg-io-width = <4>;
+                       clocks = <&ccu CLK_BUS_UART0>;
+                       resets = <&ccu RST_BUS_UART0>;
+                       status = "disabled";
+               };
+
+               uart1: serial@5000400 {
+                       compatible = "snps,dw-apb-uart";
+                       reg = <0x05000400 0x400>;
+                       interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
+                       reg-shift = <2>;
+                       reg-io-width = <4>;
+                       clocks = <&ccu CLK_BUS_UART1>;
+                       resets = <&ccu RST_BUS_UART1>;
+                       status = "disabled";
+               };
+
+               uart2: serial@5000800 {
+                       compatible = "snps,dw-apb-uart";
+                       reg = <0x05000800 0x400>;
+                       interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
+                       reg-shift = <2>;
+                       reg-io-width = <4>;
+                       clocks = <&ccu CLK_BUS_UART2>;
+                       resets = <&ccu RST_BUS_UART2>;
+                       status = "disabled";
+               };
+
+               uart3: serial@5000c00 {
+                       compatible = "snps,dw-apb-uart";
+                       reg = <0x05000c00 0x400>;
+                       interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
+                       reg-shift = <2>;
+                       reg-io-width = <4>;
+                       clocks = <&ccu CLK_BUS_UART3>;
+                       resets = <&ccu RST_BUS_UART3>;
+                       status = "disabled";
+               };
+
+               uart4: serial@5001000 {
+                       compatible = "snps,dw-apb-uart";
+                       reg = <0x05001000 0x400>;
+                       interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+                       reg-shift = <2>;
+                       reg-io-width = <4>;
+                       clocks = <&ccu CLK_BUS_UART4>;
+                       resets = <&ccu RST_BUS_UART4>;
+                       status = "disabled";
+               };
+
+               uart5: serial@5001400 {
+                       compatible = "snps,dw-apb-uart";
+                       reg = <0x05001400 0x400>;
+                       interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+                       reg-shift = <2>;
+                       reg-io-width = <4>;
+                       clocks = <&ccu CLK_BUS_UART5>;
+                       resets = <&ccu RST_BUS_UART5>;
+                       status = "disabled";
+               };
+
+               i2c0: i2c@5002000 {
+                       compatible = "allwinner,sun50i-h616-i2c",
+                                    "allwinner,sun8i-v536-i2c",
+                                    "allwinner,sun6i-a31-i2c";
+                       reg = <0x05002000 0x400>;
+                       interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&ccu CLK_BUS_I2C0>;
+                       resets = <&ccu RST_BUS_I2C0>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&i2c0_pins>;
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
+               i2c1: i2c@5002400 {
+                       compatible = "allwinner,sun50i-h616-i2c",
+                                    "allwinner,sun8i-v536-i2c",
+                                    "allwinner,sun6i-a31-i2c";
+                       reg = <0x05002400 0x400>;
+                       interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&ccu CLK_BUS_I2C1>;
+                       resets = <&ccu RST_BUS_I2C1>;
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
+               i2c2: i2c@5002800 {
+                       compatible = "allwinner,sun50i-h616-i2c",
+                                    "allwinner,sun8i-v536-i2c",
+                                    "allwinner,sun6i-a31-i2c";
+                       reg = <0x05002800 0x400>;
+                       interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&ccu CLK_BUS_I2C2>;
+                       resets = <&ccu RST_BUS_I2C2>;
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
+               i2c3: i2c@5002c00 {
+                       compatible = "allwinner,sun50i-h616-i2c",
+                                    "allwinner,sun8i-v536-i2c",
+                                    "allwinner,sun6i-a31-i2c";
+                       reg = <0x05002c00 0x400>;
+                       interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&ccu CLK_BUS_I2C3>;
+                       resets = <&ccu RST_BUS_I2C3>;
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
+               i2c4: i2c@5003000 {
+                       compatible = "allwinner,sun50i-h616-i2c",
+                                    "allwinner,sun8i-v536-i2c",
+                                    "allwinner,sun6i-a31-i2c";
+                       reg = <0x05003000 0x400>;
+                       interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&ccu CLK_BUS_I2C4>;
+                       resets = <&ccu RST_BUS_I2C4>;
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
+               spi0: spi@5010000 {
+                       compatible = "allwinner,sun50i-h616-spi",
+                                    "allwinner,sun8i-h3-spi";
+                       reg = <0x05010000 0x1000>;
+                       interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_SPI0>;
+                       clock-names = "ahb", "mod";
+                       resets = <&ccu RST_BUS_SPI0>;
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
+               spi1: spi@5011000 {
+                       compatible = "allwinner,sun50i-h616-spi",
+                                    "allwinner,sun8i-h3-spi";
+                       reg = <0x05011000 0x1000>;
+                       interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&ccu CLK_BUS_SPI1>, <&ccu CLK_SPI1>;
+                       clock-names = "ahb", "mod";
+                       resets = <&ccu RST_BUS_SPI1>;
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
+               emac0: ethernet@5020000 {
+                       compatible = "allwinner,sun50i-h616-emac0",
+                                    "allwinner,sun50i-a64-emac";
+                       reg = <0x05020000 0x10000>;
+                       interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "macirq";
+                       clocks = <&ccu CLK_BUS_EMAC0>;
+                       clock-names = "stmmaceth";
+                       resets = <&ccu RST_BUS_EMAC0>;
+                       reset-names = "stmmaceth";
+                       syscon = <&syscon>;
+                       status = "disabled";
+
+                       mdio0: mdio {
+                               compatible = "snps,dwmac-mdio";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+               };
+
+               rtc: rtc@7000000 {
+                       compatible = "allwinner,sun50i-h616-rtc";
+                       reg = <0x07000000 0x400>;
+                       interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&r_ccu CLK_R_APB1_RTC>, <&osc24M>,
+                                <&ccu CLK_PLL_SYSTEM_32K>;
+                       clock-names = "bus", "hosc",
+                                     "pll-32k";
+                       #clock-cells = <1>;
+               };
+
+               r_ccu: clock@7010000 {
+                       compatible = "allwinner,sun50i-h616-r-ccu";
+                       reg = <0x07010000 0x210>;
+                       clocks = <&osc24M>, <&rtc CLK_OSC32K>, <&rtc CLK_IOSC>,
+                                <&ccu CLK_PLL_PERIPH0>;
+                       clock-names = "hosc", "losc", "iosc", "pll-periph";
+                       #clock-cells = <1>;
+                       #reset-cells = <1>;
+               };
+
+               r_pio: pinctrl@7022000 {
+                       compatible = "allwinner,sun50i-h616-r-pinctrl";
+                       reg = <0x07022000 0x400>;
+                       clocks = <&r_ccu CLK_R_APB1>, <&osc24M>,
+                                <&rtc CLK_OSC32K>;
+                       clock-names = "apb", "hosc", "losc";
+                       gpio-controller;
+                       #gpio-cells = <3>;
+
+                       /omit-if-no-ref/
+                       r_i2c_pins: r-i2c-pins {
+                               pins = "PL0", "PL1";
+                               function = "s_i2c";
+                       };
+
+                       r_rsb_pins: r-rsb-pins {
+                               pins = "PL0", "PL1";
+                               function = "s_rsb";
+                       };
+               };
+
+               ir: ir@7040000 {
+                       compatible = "allwinner,sun50i-h616-ir",
+                                    "allwinner,sun6i-a31-ir";
+                       reg = <0x07040000 0x400>;
+                       interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&r_ccu CLK_R_APB1_IR>,
+                                <&r_ccu CLK_IR>;
+                       clock-names = "apb", "ir";
+                       resets = <&r_ccu RST_R_APB1_IR>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&ir_rx_pin>;
+                       status = "disabled";
+               };
+
+               r_i2c: i2c@7081400 {
+                       compatible = "allwinner,sun50i-h616-i2c",
+                                    "allwinner,sun8i-v536-i2c",
+                                    "allwinner,sun6i-a31-i2c";
+                       reg = <0x07081400 0x400>;
+                       interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&r_ccu CLK_R_APB2_I2C>;
+                       resets = <&r_ccu RST_R_APB2_I2C>;
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
+               r_rsb: rsb@7083000 {
+                       compatible = "allwinner,sun50i-h616-rsb",
+                                    "allwinner,sun8i-a23-rsb";
+                       reg = <0x07083000 0x400>;
+                       interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&r_ccu CLK_R_APB2_RSB>;
+                       clock-frequency = <3000000>;
+                       resets = <&r_ccu RST_R_APB2_RSB>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&r_rsb_pins>;
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+       };
+};
index 4db83fb..1bf0c47 100644 (file)
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
 dtb-$(CONFIG_ARCH_INTEL_SOCFPGA) += socfpga_stratix10_socdk.dtb \
-                               socfpga_stratix10_socdk_nand.dtb
+                               socfpga_stratix10_socdk_nand.dtb \
+                               socfpga_stratix10_swvp.dtb
index aa2bba7..14c220d 100644 (file)
                      <0x0 0xfffc6000 0x0 0x2000>;
        };
 
+       clocks {
+               cb_intosc_hs_div2_clk: cb-intosc-hs-div2-clk {
+                       #clock-cells = <0>;
+                       compatible = "fixed-clock";
+               };
+
+               cb_intosc_ls_clk: cb-intosc-ls-clk {
+                       #clock-cells = <0>;
+                       compatible = "fixed-clock";
+               };
+
+               f2s_free_clk: f2s-free-clk {
+                       #clock-cells = <0>;
+                       compatible = "fixed-clock";
+               };
+
+               osc1: osc1 {
+                       #clock-cells = <0>;
+                       compatible = "fixed-clock";
+               };
+
+               qspi_clk: qspi-clk {
+                       #clock-cells = <0>;
+                       compatible = "fixed-clock";
+                       clock-frequency = <200000000>;
+               };
+       };
+
        soc {
                #address-cells = <1>;
                #size-cells = <1>;
                        #clock-cells = <1>;
                };
 
-               clocks {
-                       cb_intosc_hs_div2_clk: cb-intosc-hs-div2-clk {
-                               #clock-cells = <0>;
-                               compatible = "fixed-clock";
-                       };
-
-                       cb_intosc_ls_clk: cb-intosc-ls-clk {
-                               #clock-cells = <0>;
-                               compatible = "fixed-clock";
-                       };
-
-                       f2s_free_clk: f2s-free-clk {
-                               #clock-cells = <0>;
-                               compatible = "fixed-clock";
-                       };
-
-                       osc1: osc1 {
-                               #clock-cells = <0>;
-                               compatible = "fixed-clock";
-                       };
-
-                       qspi_clk: qspi-clk {
-                               #clock-cells = <0>;
-                               compatible = "fixed-clock";
-                               clock-frequency = <200000000>;
-                       };
-               };
-
                gmac0: ethernet@ff800000 {
                        compatible = "altr,socfpga-stmmac-a10-s10", "snps,dwmac-3.74a", "snps,dwmac";
                        reg = <0xff800000 0x2000>;
                };
 
                qspi: spi@ff8d2000 {
-                       compatible =  "intel,socfpga-qspi", "cdns,qspi-nor";
+                       compatible = "intel,socfpga-qspi", "cdns,qspi-nor";
                        #address-cells = <1>;
                        #size-cells = <0>;
                        reg = <0xff8d2000 0x100>,
index 5159cd5..48424e4 100644 (file)
        };
 
        soc {
-               clocks {
-                       osc1 {
-                               clock-frequency = <25000000>;
-                       };
-               };
-
                eccmgr {
                        sdmmca-ecc@ff8c8c00 {
                                compatible = "altr,socfpga-s10-sdmmc-ecc",
        bus-width = <4>;
 };
 
+&osc1 {
+       clock-frequency = <25000000>;
+};
+
 &uart0 {
        status = "okay";
 };
index 0ab676c..847a7c0 100644 (file)
        };
 
        soc {
-               clocks {
-                       osc1 {
-                               clock-frequency = <25000000>;
-                       };
-               };
-
                eccmgr {
                        sdmmca-ecc@ff8c8c00 {
                                compatible = "altr,socfpga-s10-sdmmc-ecc",
        };
 };
 
+&osc1 {
+       clock-frequency = <25000000>;
+};
+
 &uart0 {
        status = "okay";
 };
diff --git a/arch/arm64/boot/dts/altera/socfpga_stratix10_swvp.dts b/arch/arm64/boot/dts/altera/socfpga_stratix10_swvp.dts
new file mode 100644 (file)
index 0000000..a8db585
--- /dev/null
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022, Intel Corporation
+ */
+
+#include "socfpga_stratix10.dtsi"
+
+/ {
+       model = "SOCFPGA Stratix 10 SWVP";
+       compatible = "altr,socfpga-stratix10-swvp", "altr,socfpga-stratix10";
+
+       aliases {
+               serial0 = &uart0;
+               serial1 = &uart1;
+
+               timer0 = &timer0;
+               timer1 = &timer1;
+               timer2 = &timer2;
+               timer3 = &timer3;
+
+               ethernet0 = &gmac0;
+               ethernet1 = &gmac1;
+               ethernet2 = &gmac2;
+       };
+
+       chosen {
+               stdout-path = "serial1:115200n8";
+               linux,initrd-start = <0x10000000>;
+               linux,initrd-end = <0x125c8324>;
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0x0 0x0 0x0 0x80000000>;
+       };
+};
+
+&cpu0 {
+       enable-method = "spin-table";
+       cpu-release-addr = <0x0 0x0000fff8>;
+};
+
+&cpu1 {
+       enable-method = "spin-table";
+       cpu-release-addr = <0x0 0x0000fff8>;
+};
+
+&cpu2 {
+       enable-method = "spin-table";
+       cpu-release-addr = <0x0 0x0000fff8>;
+};
+
+&cpu3 {
+       enable-method = "spin-table";
+       cpu-release-addr = <0x0 0x0000fff8>;
+};
+
+&osc1 {
+       clock-frequency = <25000000>;
+};
+
+&gmac0 {
+       status = "okay";
+       phy-mode = "rgmii";
+       phy-addr = <0xffffffff>;
+       snps,max-mtu = <0x0>;
+};
+
+&gmac1 {
+       status = "okay";
+       phy-mode = "rgmii";
+       phy-addr = <0xffffffff>;
+};
+
+&gmac2 {
+       status = "okay";
+       phy-mode = "rgmii";
+       phy-addr = <0xffffffff>;
+};
+
+&mmc {
+       status = "okay";
+       altr,dw-mshc-ciu-div = <0x3>;
+       altr,dw-mshc-sdr-timing = <0x0 0x3>;
+       cap-sd-highspeed;
+       cap-mmc-highspeed;
+       broken-cd;
+       bus-width = <4>;
+};
+
+&uart0 {
+       status = "okay";
+};
+
+&uart1 {
+       status = "okay";
+};
+
+&usb0 {
+       clocks = <&clkmgr STRATIX10_L4_MP_CLK>;
+       status = "okay";
+};
+
+&usb1 {
+       clocks = <&clkmgr STRATIX10_L4_MP_CLK>;
+       status = "okay";
+};
+
+&rst {
+       altr,modrst-offset = <0x20>;
+};
+
+&sysmgr {
+       reg = <0xffd12000 0x1000>;
+       interrupts = <0x0 0x10 0x4>;
+       cpu1-start-addr = <0xffd06230>;
+};
index c290d1c..02bff65 100644 (file)
@@ -20,8 +20,8 @@
        };
 
        psci {
-               compatible   = "arm,psci-0.2";
-               method       = "smc";
+               compatible = "arm,psci-0.2";
+               method = "smc";
        };
 };
 
index e0926f6..07dab1f 100644 (file)
@@ -20,8 +20,8 @@
        };
 
        psci {
-               compatible   = "arm,psci-0.2";
-               method       = "smc";
+               compatible = "arm,psci-0.2";
+               method = "smc";
        };
 };
 
index 3f5254e..04f797b 100644 (file)
 
                        sysctrl_AO: sys-ctrl@0 {
                                compatible = "amlogic,meson-axg-ao-sysctrl", "simple-mfd", "syscon";
-                               reg =  <0x0 0x0 0x0 0x100>;
+                               reg = <0x0 0x0 0x0 0x100>;
 
                                clkc_AO: clock-controller {
                                        compatible = "amlogic,meson-axg-aoclkc";
index 6c7bfac..1fa6e75 100644 (file)
                rtc1 = &vrtc;
        };
 
+       gpio_fan: gpio-fan {
+               compatible = "gpio-fan";
+               gpios = <&gpio GPIOH_5 GPIO_ACTIVE_HIGH>;
+               /* Using Dummy Speed */
+               gpio-fan,speed-map = <0 0>, <1 1>;
+               #cooling-cells = <2>;
+       };
+
        gpio-keys-polled {
                compatible = "gpio-keys-polled";
-               #address-cells = <1>;
-               #size-cells = <0>;
                poll-interval = <100>;
 
                power-button {
        status = "okay";
 };
 
+&cpu_thermal {
+       trips {
+               cpu_active: cpu-active {
+                       temperature = <70000>; /* millicelsius */
+                       hysteresis = <2000>; /* millicelsius */
+                       type = "active";
+               };
+       };
+
+       cooling-maps {
+               map {
+                       trip = <&cpu_active>;
+                       cooling-device = <&gpio_fan THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+               };
+       };
+};
+
 &frddr_a {
        status = "okay";
 };
index 707daf9..afe375f 100644 (file)
@@ -21,8 +21,6 @@
 
        gpio-keys-polled {
                compatible = "gpio-keys-polled";
-               #address-cells = <1>;
-               #size-cells = <0>;
                poll-interval = <100>;
 
                power-button {
index aa14ea0..023a520 100644 (file)
 
                        sysctrl_AO: sys-ctrl@0 {
                                compatible = "amlogic,meson-gx-ao-sysctrl", "simple-mfd", "syscon";
-                               reg =  <0x0 0x0 0x0 0x100>;
+                               reg = <0x0 0x0 0x0 0x100>;
 
                                clkc_AO: clock-controller {
                                        compatible = "amlogic,meson-gx-aoclkc";
index e8394a8..6d8cc00 100644 (file)
@@ -26,8 +26,6 @@
 
        gpio-keys-polled {
                compatible = "gpio-keys-polled";
-               #address-cells = <1>;
-               #size-cells = <0>;
                poll-interval = <20>;
 
                button-reset {
index f887bfb..63137ce 100644 (file)
 
        gpio-keys-polled {
                compatible = "gpio-keys-polled";
-               #address-cells = <1>;
-               #size-cells = <0>;
                poll-interval = <100>;
 
-               button@0 {
+               button {
                        label = "reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&gpio_ao GPIOAO_3 GPIO_ACTIVE_LOW>;
index 6eae692..505ffcd 100644 (file)
 
        gpio-keys-polled {
                compatible = "gpio-keys-polled";
-               #address-cells = <1>;
-               #size-cells = <0>;
                poll-interval = <100>;
 
-               button@0 {
+               button {
                        label = "reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&gpio_ao GPIOAO_3 GPIO_ACTIVE_LOW>;
index c529b6c..a4fa186 100644 (file)
 
        gpio-keys-polled {
                compatible = "gpio-keys-polled";
-               #address-cells = <1>;
-               #size-cells = <0>;
                poll-interval = <100>;
 
-               button@0 {
+               button {
                        label = "power";
                        linux,code = <KEY_POWER>;
                        gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_LOW>;
index b2ab05c..c147041 100644 (file)
 
        gpio-keys-polled {
                compatible = "gpio-keys-polled";
-               #address-cells = <1>;
-               #size-cells = <0>;
                poll-interval = <100>;
 
-               button@0 {
+               button {
                        label = "power";
                        linux,code = <KEY_POWER>;
                        gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_LOW>;
index 4b0ff70..595b490 100644 (file)
 
        gpio-keys-polled {
                compatible = "gpio-keys-polled";
-               #address-cells = <1>;
-               #size-cells = <0>;
                poll-interval = <20>;
 
-               button@0 {
+               button {
                        label = "power";
                        linux,code = <KEY_POWER>;
                        gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_HIGH>;
index fcb304c..6831137 100644 (file)
 
        bluetooth {
                compatible = "realtek,rtl8822cs-bt";
-               enable-gpios  = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>;
+               enable-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>;
                host-wake-gpios = <&gpio GPIOX_18 GPIO_ACTIVE_HIGH>;
        };
 };
index ebebf34..f5b3424 100644 (file)
 
        gpio-keys-polled {
                compatible = "gpio-keys-polled";
-               #address-cells = <1>;
-               #size-cells = <0>;
                poll-interval = <100>;
 
-               button@0 {
+               button {
                        label = "power";
                        linux,code = <KEY_POWER>;
                        gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_LOW>;
index ea9f234..b8ef3bd 100644 (file)
 
        gpio-keys-polled {
                compatible = "gpio-keys-polled";
-               #address-cells = <1>;
-               #size-cells = <0>;
                poll-interval = <100>;
 
-               button@0 {
+               button {
                        label = "power";
                        linux,code = <KEY_POWER>;
                        gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_LOW>;
index 8edbfe0..d4858af 100644 (file)
 
        gpio-keys-polled {
                compatible = "gpio-keys-polled";
-               #address-cells = <1>;
-               #size-cells = <0>;
                poll-interval = <100>;
 
-               button@0 {
+               button {
                        label = "power";
                        linux,code = <KEY_POWER>;
                        gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_LOW>;
index 1e7f77f..f8c4034 100644 (file)
@@ -45,8 +45,6 @@
 
        gpio-keys-polled {
                compatible = "gpio-keys-polled";
-               #address-cells = <1>;
-               #size-cells = <0>;
                poll-interval = <100>;
 
                button-power {
index ff21361..ad50cba 100644 (file)
                                clocks = <&xtal>, <&xtal>, <&xtal>;
                                clock-names = "xtal", "pclk", "baud";
                        };
+
+                       reset: reset-controller@2000 {
+                               compatible = "amlogic,meson-s4-reset";
+                               reg = <0x0 0x2000 0x0 0x98>;
+                               #reset-cells = <1>;
+                       };
                };
        };
 };
index a5d79f2..603337c 100644 (file)
@@ -48,7 +48,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               key1 {
+               key-1 {
                        label = "A";
                        linux,code = <BTN_0>;
                        gpios = <&gpio GPIOH_6 GPIO_ACTIVE_LOW>;
@@ -56,7 +56,7 @@
                        interrupts = <34 IRQ_TYPE_EDGE_BOTH>;
                };
 
-               key2 {
+               key-2 {
                        label = "B";
                        linux,code = <BTN_1>;
                        gpios = <&gpio GPIOH_7 GPIO_ACTIVE_LOW>;
@@ -64,7 +64,7 @@
                        interrupts = <35 IRQ_TYPE_EDGE_BOTH>;
                };
 
-               key3 {
+               key-3 {
                        label = "C";
                        linux,code = <BTN_2>;
                        gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_LOW>;
@@ -72,7 +72,7 @@
                        interrupts = <2 IRQ_TYPE_EDGE_BOTH>;
                };
 
-               mic_mute {
+               key-mic-mute {
                        label = "MicMute";
                        linux,code = <SW_MUTE_DEVICE>;
                        linux,input-type = <EV_SW>;
@@ -81,7 +81,7 @@
                        interrupts = <99 IRQ_TYPE_EDGE_BOTH>;
                };
 
-               power_key {
+               key-power {
                        label = "PowerKey";
                        linux,code = <KEY_POWER>;
                        gpios = <&gpio_ao GPIOAO_3 GPIO_ACTIVE_LOW>;
index 217d772..049e7a5 100644 (file)
@@ -22,7 +22,7 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               button@1 {
+               button {
                        label = "POWER";
                        linux,code = <116>;
                        linux,input-type = <0x1>;
index e927811..efac50a 100644 (file)
@@ -22,7 +22,7 @@
 
        gpio-keys {
                compatible = "gpio-keys";
-               button@1 {
+               button {
                        label = "POWER";
                        linux,code = <116>;
                        linux,input-type = <0x1>;
index a83c82c..a8526f8 100644 (file)
                        interrupts = <0x0 0x4c 0x4>;
                };
 
-               /* Do not change dwusb name, coded for backward compatibility */
-               usb0: dwusb@19000000 {
+               /* Node-name might need to be coded as dwusb for backward compatibility */
+               usb0: usb@19000000 {
                        status = "disabled";
                        compatible = "snps,dwc3";
-                       reg =  <0x0 0x19000000 0x0 0x100000>;
+                       reg = <0x0 0x19000000 0x0 0x100000>;
                        interrupts = <0x0 0x5d 0x4>;
                        dma-coherent;
                        dr_mode = "host";
index 0f37e77..f56d687 100644 (file)
                        phy-names = "sata-phy";
                };
 
-               /* Do not change dwusb name, coded for backward compatibility */
-               usb0: dwusb@19000000 {
+               /* Node-name might need to be coded as dwusb for backward compatibility */
+               usb0: usb@19000000 {
                        status = "disabled";
                        compatible = "snps,dwc3";
-                       reg =  <0x0 0x19000000 0x0 0x100000>;
+                       reg = <0x0 0x19000000 0x0 0x100000>;
                        interrupts = <0x0 0x89 0x4>;
                        dma-coherent;
                        dr_mode = "host";
                };
 
-               usb1: dwusb@19800000 {
+               usb1: usb@19800000 {
                        status = "disabled";
                        compatible = "snps,dwc3";
-                       reg =  <0x0 0x19800000 0x0 0x100000>;
+                       reg = <0x0 0x19800000 0x0 0x100000>;
                        interrupts = <0x0 0x8a 0x4>;
                        dma-coherent;
                        dr_mode = "host";
index a496e39..5f6f30c 100644 (file)
        };
 
        panel {
-               compatible = "arm,rtsm-display", "panel-dpi";
+               compatible = "arm,rtsm-display";
                port {
                        panel_in: endpoint {
                                remote-endpoint = <&clcd_pads>;
index 065381c..8d0d45d 100644 (file)
 
                trig-conns@0 {
                        reg = <0>;
-                       arm,trig-in-sigs=<2 3>;
-                       arm,trig-in-types=<SNK_FULL SNK_ACQCOMP>;
-                       arm,trig-out-sigs=<0 1>;
-                       arm,trig-out-types=<SNK_FLUSHIN SNK_TRIGIN>;
+                       arm,trig-in-sigs = <2 3>;
+                       arm,trig-in-types = <SNK_FULL SNK_ACQCOMP>;
+                       arm,trig-out-sigs = <0 1>;
+                       arm,trig-out-types = <SNK_FLUSHIN SNK_TRIGIN>;
                        arm,cs-dev-assoc = <&etr_sys>;
                };
 
                trig-conns@1 {
                        reg = <1>;
-                       arm,trig-in-sigs=<0 1>;
-                       arm,trig-in-types=<SNK_FULL SNK_ACQCOMP>;
-                       arm,trig-out-sigs=<7 6>;
-                       arm,trig-out-types=<SNK_FLUSHIN SNK_TRIGIN>;
+                       arm,trig-in-sigs = <0 1>;
+                       arm,trig-in-types = <SNK_FULL SNK_ACQCOMP>;
+                       arm,trig-out-sigs = <7 6>;
+                       arm,trig-out-types = <SNK_FLUSHIN SNK_TRIGIN>;
                        arm,cs-dev-assoc = <&etf_sys0>;
                };
 
                trig-conns@2 {
                        reg = <2>;
-                       arm,trig-in-sigs=<4 5 6 7>;
-                       arm,trig-in-types=<STM_TOUT_SPTE STM_TOUT_SW
+                       arm,trig-in-sigs = <4 5 6 7>;
+                       arm,trig-in-types = <STM_TOUT_SPTE STM_TOUT_SW
                                           STM_TOUT_HETE STM_ASYNCOUT>;
-                       arm,trig-out-sigs=<4 5>;
-                       arm,trig-out-types=<STM_HWEVENT STM_HWEVENT>;
+                       arm,trig-out-sigs = <4 5>;
+                       arm,trig-out-types = <STM_HWEVENT STM_HWEVENT>;
                        arm,cs-dev-assoc = <&stm_sys>;
                };
 
                trig-conns@3 {
                        reg = <3>;
-                       arm,trig-out-sigs=<2 3>;
-                       arm,trig-out-types=<SNK_FLUSHIN SNK_TRIGIN>;
+                       arm,trig-out-sigs = <2 3>;
+                       arm,trig-out-types = <SNK_FLUSHIN SNK_TRIGIN>;
                        arm,cs-dev-assoc = <&tpiu_sys>;
                };
        };
 
                trig-conns@0 {
                        reg = <0>;
-                       arm,trig-in-sigs=<0>;
-                       arm,trig-in-types=<GEN_INTREQ>;
-                       arm,trig-out-sigs=<0>;
-                       arm,trig-out-types=<GEN_HALTREQ>;
+                       arm,trig-in-sigs = <0>;
+                       arm,trig-in-types = <GEN_INTREQ>;
+                       arm,trig-out-sigs = <0>;
+                       arm,trig-out-types = <GEN_HALTREQ>;
                        arm,trig-conn-name = "sys_profiler";
                };
 
                trig-conns@1 {
                        reg = <1>;
-                       arm,trig-out-sigs=<2 3>;
-                       arm,trig-out-types=<GEN_HALTREQ GEN_RESTARTREQ>;
+                       arm,trig-out-sigs = <2 3>;
+                       arm,trig-out-types = <GEN_HALTREQ GEN_RESTARTREQ>;
                        arm,trig-conn-name = "watchdog";
                };
 
                trig-conns@2 {
                        reg = <2>;
-                       arm,trig-out-sigs=<1 6>;
-                       arm,trig-out-types=<GEN_HALTREQ GEN_RESTARTREQ>;
+                       arm,trig-out-sigs = <1 6>;
+                       arm,trig-out-types = <GEN_HALTREQ GEN_RESTARTREQ>;
                        arm,trig-conn-name = "g_counter";
                };
        };
index 2e43f45..ba88d15 100644 (file)
 
                trig-conns@0 {
                        reg = <0>;
-                       arm,trig-in-sigs=<0 1>;
-                       arm,trig-in-types=<SNK_FULL SNK_ACQCOMP>;
-                       arm,trig-out-sigs=<0 1>;
-                       arm,trig-out-types=<SNK_FLUSHIN SNK_TRIGIN>;
+                       arm,trig-in-sigs = <0 1>;
+                       arm,trig-in-types = <SNK_FULL SNK_ACQCOMP>;
+                       arm,trig-out-sigs = <0 1>;
+                       arm,trig-out-types = <SNK_FLUSHIN SNK_TRIGIN>;
                        arm,cs-dev-assoc = <&etf_sys1>;
                };
 
                trig-conns@1 {
                        reg = <1>;
-                       arm,trig-in-sigs=<2 3 4>;
-                       arm,trig-in-types=<ELA_DBGREQ ELA_TSTART ELA_TSTOP>;
+                       arm,trig-in-sigs = <2 3 4>;
+                       arm,trig-in-types = <ELA_DBGREQ ELA_TSTART ELA_TSTOP>;
                        arm,trig-conn-name = "ela_clus_0";
                };
 
                trig-conns@2 {
                        reg = <2>;
-                       arm,trig-in-sigs=<5 6 7>;
-                       arm,trig-in-types=<ELA_DBGREQ ELA_TSTART ELA_TSTOP>;
+                       arm,trig-in-sigs = <5 6 7>;
+                       arm,trig-in-types = <ELA_DBGREQ ELA_TSTART ELA_TSTOP>;
                        arm,trig-conn-name = "ela_clus_1";
                };
        };
index f099fb6..6451c62 100644 (file)
                        cache-size = <0x200000>;
                        cache-line-size = <64>;
                        cache-sets = <2048>;
+                       cache-level = <2>;
                };
 
                A53_L2: l2-cache1 {
                        cache-size = <0x100000>;
                        cache-line-size = <64>;
                        cache-sets = <1024>;
+                       cache-level = <2>;
                };
        };
 
index 7093895..438cd1f 100644 (file)
                        cache-size = <0x200000>;
                        cache-line-size = <64>;
                        cache-sets = <2048>;
+                       cache-level = <2>;
                };
 
                A53_L2: l2-cache1 {
                        cache-size = <0x100000>;
                        cache-line-size = <64>;
                        cache-sets = <1024>;
+                       cache-level = <2>;
                };
        };
 
index 4135d62..ec85cd2 100644 (file)
 &mailbox {
        compatible = "arm,mhu-doorbell", "arm,primecell";
        #mbox-cells = <2>;
-       mbox-name = "ARM-MHU";
 };
 
 &smmu_etr {
index dbc22e7..cf4a582 100644 (file)
                        cache-size = <0x200000>;
                        cache-line-size = <64>;
                        cache-sets = <2048>;
+                       cache-level = <2>;
                };
 
                A53_L2: l2-cache1 {
                        cache-size = <0x100000>;
                        cache-line-size = <64>;
                        cache-sets = <1024>;
+                       cache-level = <2>;
                };
        };
 
index 5082fcd..e8584d3 100644 (file)
@@ -9,5 +9,6 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-400.dtb \
                              bcm2837-rpi-zero-2-w.dtb
 
 subdir-y       += bcm4908
+subdir-y       += bcmbca
 subdir-y       += northstar2
 subdir-y       += stingray
index b63eefa..064f7f5 100644 (file)
                compatible = "gpio-keys-polled";
                poll-interval = <100>;
 
-               brightness {
+               key-brightness {
                        label = "LEDs";
                        linux,code = <KEY_BRIGHTNESS_ZERO>;
                        gpios = <&gpio0 18 GPIO_ACTIVE_LOW>;
                };
 
-               wps {
+               key-wps {
                        label = "WPS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&gpio0 21 GPIO_ACTIVE_LOW>;
                };
 
-               wifi {
+               key-wifi {
                        label = "WiFi";
                        linux,code = <KEY_RFKILL>;
                        gpios = <&gpio0 22 GPIO_ACTIVE_LOW>;
                };
 
-               restart {
+               key-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&gpio0 23 GPIO_ACTIVE_LOW>;
index 66023d5..d084c33 100644 (file)
@@ -9,6 +9,14 @@
                /delete-node/ cpu@3;
        };
 
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>;
+       };
+
        pmu {
                compatible = "arm,cortex-a53-pmu";
                interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
index 169fbb7..04f8524 100644 (file)
                compatible = "gpio-keys-polled";
                poll-interval = <100>;
 
-               wifi {
+               key-wifi {
                        label = "WiFi";
                        linux,code = <KEY_RFKILL>;
                        gpios = <&gpio0 28 GPIO_ACTIVE_LOW>;
                };
 
-               wps {
+               key-wps {
                        label = "WPS";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&gpio0 29 GPIO_ACTIVE_LOW>;
                };
 
-               restart {
+               key-restart {
                        label = "Reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&gpio0 30 GPIO_ACTIVE_LOW>;
                };
 
-               brightness {
+               key-brightness {
                        label = "LEDs";
                        linux,code = <KEY_BRIGHTNESS_ZERO>;
                        gpios = <&gpio0 31 GPIO_ACTIVE_LOW>;
index a4be040..967d2cd 100644 (file)
@@ -29,6 +29,8 @@
                        device_type = "cpu";
                        compatible = "brcm,brahma-b53";
                        reg = <0x0>;
+                       enable-method = "spin-table";
+                       cpu-release-addr = <0x0 0xfff8>;
                        next-level-cache = <&l2>;
                };
 
diff --git a/arch/arm64/boot/dts/broadcom/bcmbca/Makefile b/arch/arm64/boot/dts/broadcom/bcmbca/Makefile
new file mode 100644 (file)
index 0000000..38f1430
--- /dev/null
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+dtb-$(CONFIG_ARCH_BCMBCA) += \
+                               bcm4912-asus-gt-ax6000.dtb \
+                               bcm94912.dtb \
+                               bcm963158.dtb \
+                               bcm96858.dtb \
+                               bcm963146.dtb \
+                               bcm96856.dtb \
+                               bcm96813.dtb
diff --git a/arch/arm64/boot/dts/broadcom/bcmbca/bcm4912-asus-gt-ax6000.dts b/arch/arm64/boot/dts/broadcom/bcmbca/bcm4912-asus-gt-ax6000.dts
new file mode 100644 (file)
index 0000000..ed55466
--- /dev/null
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+
+/dts-v1/;
+
+#include "bcm4912.dtsi"
+
+/ {
+       compatible = "asus,gt-ax6000", "brcm,bcm4912", "brcm,bcmbca";
+       model = "Asus GT-AX6000";
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x00 0x00 0x00 0x40000000>;
+       };
+};
+
+&uart0 {
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/broadcom/bcmbca/bcm4912.dtsi b/arch/arm64/boot/dts/broadcom/bcmbca/bcm4912.dtsi
new file mode 100644 (file)
index 0000000..3d016c2
--- /dev/null
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2022 Broadcom Ltd.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+       compatible = "brcm,bcm4912", "brcm,bcmbca";
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       interrupt-parent = <&gic>;
+
+       cpus {
+               #address-cells = <2>;
+               #size-cells = <0>;
+
+               B53_0: cpu@0 {
+                       compatible = "brcm,brahma-b53";
+                       device_type = "cpu";
+                       reg = <0x0 0x0>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               B53_1: cpu@1 {
+                       compatible = "brcm,brahma-b53";
+                       device_type = "cpu";
+                       reg = <0x0 0x1>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               B53_2: cpu@2 {
+                       compatible = "brcm,brahma-b53";
+                       device_type = "cpu";
+                       reg = <0x0 0x2>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               B53_3: cpu@3 {
+                       compatible = "brcm,brahma-b53";
+                       device_type = "cpu";
+                       reg = <0x0 0x3>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               L2_0: l2-cache0 {
+                       compatible = "cache";
+               };
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+       };
+
+       pmu: pmu {
+               compatible = "arm,cortex-a53-pmu";
+               interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-affinity = <&B53_0>, <&B53_1>,
+                       <&B53_2>, <&B53_3>;
+       };
+
+       clocks: clocks {
+               periph_clk: periph-clk {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <200000000>;
+               };
+               uart_clk: uart-clk {
+                       compatible = "fixed-factor-clock";
+                       #clock-cells = <0>;
+                       clocks = <&periph_clk>;
+                       clock-div = <4>;
+                       clock-mult = <1>;
+               };
+       };
+
+       psci {
+               compatible = "arm,psci-0.2";
+               method = "smc";
+       };
+
+       axi@81000000 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0x0 0x0 0x81000000 0x8000>;
+
+               gic: interrupt-controller@1000 {
+                       compatible = "arm,gic-400";
+                       #interrupt-cells = <3>;
+                       interrupt-controller;
+                       interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+                       reg = <0x1000 0x1000>,
+                               <0x2000 0x2000>,
+                               <0x4000 0x2000>,
+                               <0x6000 0x2000>;
+               };
+       };
+
+       bus@ff800000 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0x0 0x0 0xff800000 0x800000>;
+
+               uart0: serial@12000 {
+                       compatible = "arm,pl011", "arm,primecell";
+                       reg = <0x12000 0x1000>;
+                       interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&uart_clk>, <&uart_clk>;
+                       clock-names = "uartclk", "apb_pclk";
+                       status = "disabled";
+               };
+       };
+};
diff --git a/arch/arm64/boot/dts/broadcom/bcmbca/bcm63146.dtsi b/arch/arm64/boot/dts/broadcom/bcmbca/bcm63146.dtsi
new file mode 100644 (file)
index 0000000..04de96b
--- /dev/null
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2022 Broadcom Ltd.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+       compatible = "brcm,bcm63146", "brcm,bcmbca";
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       interrupt-parent = <&gic>;
+
+       cpus {
+               #address-cells = <2>;
+               #size-cells = <0>;
+
+               B53_0: cpu@0 {
+                       compatible = "brcm,brahma-b53";
+                       device_type = "cpu";
+                       reg = <0x0 0x0>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               B53_1: cpu@1 {
+                       compatible = "brcm,brahma-b53";
+                       device_type = "cpu";
+                       reg = <0x0 0x1>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               L2_0: l2-cache0 {
+                       compatible = "cache";
+               };
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>;
+       };
+
+       pmu: pmu {
+               compatible = "arm,cortex-a53-pmu";
+               interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-affinity = <&B53_0>, <&B53_1>;
+       };
+
+       clocks: clocks {
+               periph_clk: periph-clk {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <200000000>;
+               };
+               uart_clk: uart-clk {
+                       compatible = "fixed-factor-clock";
+                       #clock-cells = <0>;
+                       clocks = <&periph_clk>;
+                       clock-div = <4>;
+                       clock-mult = <1>;
+               };
+       };
+
+       psci {
+               compatible = "arm,psci-0.2";
+               method = "smc";
+       };
+
+       axi@81000000 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0x0 0x0 0x81000000 0x8000>;
+
+               gic: interrupt-controller@1000 {
+                       compatible = "arm,gic-400";
+                       #interrupt-cells = <3>;
+                       interrupt-controller;
+                       reg = <0x1000 0x1000>,
+                               <0x2000 0x2000>,
+                               <0x4000 0x2000>,
+                               <0x6000 0x2000>;
+                       interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) |
+                                       IRQ_TYPE_LEVEL_HIGH)>;
+               };
+       };
+
+       bus@ff800000 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0x0 0x0 0xff800000 0x800000>;
+
+               uart0: serial@12000 {
+                       compatible = "arm,pl011", "arm,primecell";
+                       reg = <0x12000 0x1000>;
+                       interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&uart_clk>, <&uart_clk>;
+                       clock-names = "uartclk", "apb_pclk";
+                       status = "disabled";
+               };
+       };
+};
diff --git a/arch/arm64/boot/dts/broadcom/bcmbca/bcm63158.dtsi b/arch/arm64/boot/dts/broadcom/bcmbca/bcm63158.dtsi
new file mode 100644 (file)
index 0000000..1362970
--- /dev/null
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2022 Broadcom Ltd.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+       compatible = "brcm,bcm63158", "brcm,bcmbca";
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       interrupt-parent = <&gic>;
+
+       cpus {
+               #address-cells = <2>;
+               #size-cells = <0>;
+
+               B53_0: cpu@0 {
+                       compatible = "brcm,brahma-b53";
+                       device_type = "cpu";
+                       reg = <0x0 0x0>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               B53_1: cpu@1 {
+                       compatible = "brcm,brahma-b53";
+                       device_type = "cpu";
+                       reg = <0x0 0x1>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               B53_2: cpu@2 {
+                       compatible = "brcm,brahma-b53";
+                       device_type = "cpu";
+                       reg = <0x0 0x2>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               B53_3: cpu@3 {
+                       compatible = "brcm,brahma-b53";
+                       device_type = "cpu";
+                       reg = <0x0 0x3>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               L2_0: l2-cache0 {
+                       compatible = "cache";
+               };
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+       };
+
+       pmu: pmu {
+               compatible = "arm,cortex-a53-pmu";
+               interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-affinity = <&B53_0>, <&B53_1>,
+                       <&B53_2>, <&B53_3>;
+       };
+
+       clocks: clocks {
+               periph_clk: periph-clk {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <200000000>;
+               };
+               uart_clk: uart-clk {
+                       compatible = "fixed-factor-clock";
+                       #clock-cells = <0>;
+                       clocks = <&periph_clk>;
+                       clock-div = <4>;
+                       clock-mult = <1>;
+               };
+       };
+
+       psci {
+               compatible = "arm,psci-0.2";
+               method = "smc";
+       };
+
+       axi@81000000 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0x0 0x0 0x81000000 0x8000>;
+
+               gic: interrupt-controller@1000 {
+                       compatible = "arm,gic-400";
+                       #interrupt-cells = <3>;
+                       interrupt-controller;
+                       interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+                       reg = <0x1000 0x1000>,
+                               <0x2000 0x2000>,
+                               <0x4000 0x2000>,
+                               <0x6000 0x2000>;
+               };
+       };
+
+       bus@ff800000 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0x0 0x0 0xff800000 0x800000>;
+
+               uart0: serial@12000 {
+                       compatible = "arm,pl011", "arm,primecell";
+                       reg = <0x12000 0x1000>;
+                       interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&uart_clk>, <&uart_clk>;
+                       clock-names = "uartclk", "apb_pclk";
+                       status = "disabled";
+               };
+       };
+};
diff --git a/arch/arm64/boot/dts/broadcom/bcmbca/bcm6813.dtsi b/arch/arm64/boot/dts/broadcom/bcmbca/bcm6813.dtsi
new file mode 100644 (file)
index 0000000..c3e6197
--- /dev/null
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2022 Broadcom Ltd.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+       compatible = "brcm,bcm6813", "brcm,bcmbca";
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       interrupt-parent = <&gic>;
+
+       cpus {
+               #address-cells = <2>;
+               #size-cells = <0>;
+
+               B53_0: cpu@0 {
+                       compatible = "brcm,brahma-b53";
+                       device_type = "cpu";
+                       reg = <0x0 0x0>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               B53_1: cpu@1 {
+                       compatible = "brcm,brahma-b53";
+                       device_type = "cpu";
+                       reg = <0x0 0x1>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               B53_2: cpu@2 {
+                       compatible = "brcm,brahma-b53";
+                       device_type = "cpu";
+                       reg = <0x0 0x2>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               B53_3: cpu@3 {
+                       compatible = "brcm,brahma-b53";
+                       device_type = "cpu";
+                       reg = <0x0 0x3>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               L2_0: l2-cache0 {
+                       compatible = "cache";
+               };
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+       };
+
+       pmu: pmu {
+               compatible = "arm,cortex-a53-pmu";
+               interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-affinity = <&B53_0>, <&B53_1>,
+                       <&B53_2>, <&B53_3>;
+       };
+
+       clocks: clocks {
+               periph_clk: periph-clk {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <200000000>;
+               };
+               uart_clk: uart-clk {
+                       compatible = "fixed-factor-clock";
+                       #clock-cells = <0>;
+                       clocks = <&periph_clk>;
+                       clock-div = <4>;
+                       clock-mult = <1>;
+               };
+       };
+
+       psci {
+               compatible = "arm,psci-0.2";
+               method = "smc";
+       };
+
+       axi@81000000 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0x0 0x0 0x81000000 0x8000>;
+
+               gic: interrupt-controller@1000 {
+                       compatible = "arm,gic-400";
+                       #interrupt-cells = <3>;
+                       interrupt-controller;
+                       interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+                       reg = <0x1000 0x1000>,
+                               <0x2000 0x2000>,
+                               <0x4000 0x2000>,
+                               <0x6000 0x2000>;
+               };
+       };
+
+       bus@ff800000 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0x0 0x0 0xff800000 0x800000>;
+
+               uart0: serial@12000 {
+                       compatible = "arm,pl011", "arm,primecell";
+                       reg = <0x12000 0x1000>;
+                       interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&uart_clk>, <&uart_clk>;
+                       clock-names = "uartclk", "apb_pclk";
+                       status = "disabled";
+               };
+       };
+};
diff --git a/arch/arm64/boot/dts/broadcom/bcmbca/bcm6856.dtsi b/arch/arm64/boot/dts/broadcom/bcmbca/bcm6856.dtsi
new file mode 100644 (file)
index 0000000..0bce649
--- /dev/null
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2022 Broadcom Ltd.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+       compatible = "brcm,bcm6856", "brcm,bcmbca";
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       interrupt-parent = <&gic>;
+
+       cpus {
+               #address-cells = <2>;
+               #size-cells = <0>;
+
+               B53_0: cpu@0 {
+                       compatible = "brcm,brahma-b53";
+                       device_type = "cpu";
+                       reg = <0x0 0x0>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               B53_1: cpu@1 {
+                       compatible = "brcm,brahma-b53";
+                       device_type = "cpu";
+                       reg = <0x0 0x1>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               L2_0: l2-cache0 {
+                       compatible = "cache";
+               };
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>;
+       };
+
+       pmu: pmu {
+               compatible = "arm,cortex-a53-pmu";
+               interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-affinity = <&B53_0>, <&B53_1>;
+       };
+
+       clocks: clocks {
+               periph_clk:periph-clk {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <200000000>;
+               };
+       };
+
+       psci {
+               compatible = "arm,psci-0.2";
+               method = "smc";
+       };
+
+       axi@81000000 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0x0 0x0 0x81000000 0x8000>;
+
+               gic: interrupt-controller@1000 {
+                       compatible = "arm,gic-400";
+                       #interrupt-cells = <3>;
+                       interrupt-controller;
+                       reg = <0x1000 0x1000>, /* GICD */
+                               <0x2000 0x2000>, /* GICC */
+                               <0x4000 0x2000>, /* GICH */
+                               <0x6000 0x2000>; /* GICV */
+                       interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) |
+                                       IRQ_TYPE_LEVEL_HIGH)>;
+               };
+       };
+
+       bus@ff800000 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0x0 0x0 0xff800000 0x800000>;
+
+               uart0: serial@640 {
+                       compatible = "brcm,bcm6345-uart";
+                       reg = <0x640 0x18>;
+                       interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&periph_clk>;
+                       clock-names = "refclk";
+                       status = "disabled";
+               };
+       };
+};
diff --git a/arch/arm64/boot/dts/broadcom/bcmbca/bcm6858.dtsi b/arch/arm64/boot/dts/broadcom/bcmbca/bcm6858.dtsi
new file mode 100644 (file)
index 0000000..29a880c
--- /dev/null
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2022 Broadcom Ltd.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+       compatible = "brcm,bcm6858", "brcm,bcmbca";
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       interrupt-parent = <&gic>;
+
+       cpus {
+               #address-cells = <2>;
+               #size-cells = <0>;
+
+               B53_0: cpu@0 {
+                       compatible = "brcm,brahma-b53";
+                       device_type = "cpu";
+                       reg = <0x0 0x0>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               B53_1: cpu@1 {
+                       compatible = "brcm,brahma-b53";
+                       device_type = "cpu";
+                       reg = <0x0 0x1>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               B53_2: cpu@2 {
+                       compatible = "brcm,brahma-b53";
+                       device_type = "cpu";
+                       reg = <0x0 0x2>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+
+               B53_3: cpu@3 {
+                       compatible = "brcm,brahma-b53";
+                       device_type = "cpu";
+                       reg = <0x0 0x3>;
+                       next-level-cache = <&L2_0>;
+                       enable-method = "psci";
+               };
+               L2_0: l2-cache0 {
+                       compatible = "cache";
+               };
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                       <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+       };
+
+       pmu: pmu {
+               compatible = "arm,armv8-pmuv3";
+               interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
+                       <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-affinity = <&B53_0>, <&B53_1>,
+                       <&B53_2>, <&B53_3>;
+       };
+
+       clocks: clocks {
+               periph_clk:periph-clk {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <200000000>;
+               };
+       };
+
+       psci {
+               compatible = "arm,psci-0.2";
+               method = "smc";
+       };
+
+       axi@81000000 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0x0 0x0 0x81000000 0x8000>;
+
+               gic: interrupt-controller@1000 {
+                       compatible = "arm,gic-400";
+                       #interrupt-cells = <3>;
+                       interrupt-controller;
+                       reg = <0x1000 0x1000>, /* GICD */
+                               <0x2000 0x2000>, /* GICC */
+                               <0x4000 0x2000>, /* GICH */
+                               <0x6000 0x2000>; /* GICV */
+                       interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) |
+                                       IRQ_TYPE_LEVEL_HIGH)>;
+               };
+       };
+
+       bus@ff800000 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0x0 0x0 0xff800000 0x62000>;
+
+               uart0: serial@640 {
+                       compatible = "brcm,bcm6345-uart";
+                       reg = <0x640 0x18>;
+                       interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&periph_clk>;
+                       clock-names = "refclk";
+                       status = "disabled";
+               };
+       };
+};
diff --git a/arch/arm64/boot/dts/broadcom/bcmbca/bcm94912.dts b/arch/arm64/boot/dts/broadcom/bcmbca/bcm94912.dts
new file mode 100644 (file)
index 0000000..a3623e6
--- /dev/null
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2022 Broadcom Ltd.
+ */
+
+/dts-v1/;
+
+#include "bcm4912.dtsi"
+
+/ {
+       model = "Broadcom BCM94912 Reference Board";
+       compatible = "brcm,bcm94912", "brcm,bcm4912", "brcm,bcmbca";
+
+       aliases {
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x0 0x0 0x0 0x08000000>;
+       };
+};
+
+&uart0 {
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/broadcom/bcmbca/bcm963146.dts b/arch/arm64/boot/dts/broadcom/bcmbca/bcm963146.dts
new file mode 100644 (file)
index 0000000..e39f1e6
--- /dev/null
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2022 Broadcom Ltd.
+ */
+
+/dts-v1/;
+
+#include "bcm63146.dtsi"
+
+/ {
+       model = "Broadcom BCM963146 Reference Board";
+       compatible = "brcm,bcm963146", "brcm,bcm63146", "brcm,bcmbca";
+
+       aliases {
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x0 0x0 0x0 0x08000000>;
+       };
+};
+
+&uart0 {
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/broadcom/bcmbca/bcm963158.dts b/arch/arm64/boot/dts/broadcom/bcmbca/bcm963158.dts
new file mode 100644 (file)
index 0000000..eba07e0
--- /dev/null
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2022 Broadcom Ltd.
+ */
+
+/dts-v1/;
+
+#include "bcm63158.dtsi"
+
+/ {
+       model = "Broadcom BCM963158 Reference Board";
+       compatible = "brcm,bcm963158", "brcm,bcm63158", "brcm,bcmbca";
+
+       aliases {
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x0 0x0 0x0 0x08000000>;
+       };
+};
+
+&uart0 {
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/broadcom/bcmbca/bcm96813.dts b/arch/arm64/boot/dts/broadcom/bcmbca/bcm96813.dts
new file mode 100644 (file)
index 0000000..af17091
--- /dev/null
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2022 Broadcom Ltd.
+ */
+
+/dts-v1/;
+
+#include "bcm6813.dtsi"
+
+/ {
+       model = "Broadcom BCM96813 Reference Board";
+       compatible = "brcm,bcm96813", "brcm,bcm6813", "brcm,bcmbca";
+
+       aliases {
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x0 0x0 0x0 0x08000000>;
+       };
+};
+
+&uart0 {
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/broadcom/bcmbca/bcm96856.dts b/arch/arm64/boot/dts/broadcom/bcmbca/bcm96856.dts
new file mode 100644 (file)
index 0000000..032aeb7
--- /dev/null
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2022 Broadcom Ltd.
+ */
+
+/dts-v1/;
+
+#include "bcm6856.dtsi"
+
+/ {
+       model = "Broadcom BCM96856 Reference Board";
+       compatible = "brcm,bcm96856", "brcm,bcm6856", "brcm,bcmbca";
+
+       aliases {
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x0 0x0 0x0 0x08000000>;
+       };
+};
+
+&uart0 {
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/broadcom/bcmbca/bcm96858.dts b/arch/arm64/boot/dts/broadcom/bcmbca/bcm96858.dts
new file mode 100644 (file)
index 0000000..0cbf582
--- /dev/null
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2022 Broadcom Ltd.
+ */
+
+/dts-v1/;
+
+#include "bcm6858.dtsi"
+
+/ {
+       model = "Broadcom BCM96858 Reference Board";
+       compatible = "brcm,bcm96858", "brcm,bcm6858", "brcm,bcmbca";
+
+       aliases {
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x0 0x0 0x0 0x08000000>;
+       };
+};
+
+&uart0 {
+       status = "okay";
+};
index 09d4aa8..8f8c25e 100644 (file)
                        reg-names = "amac_base";
                        dma-coherent;
                        interrupts = <GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH>;
-                       status= "disabled";
+                       status = "disabled";
                };
 
                nand: nand@360000 {
diff --git a/arch/arm64/boot/dts/exynos/exynos-pinctrl.h b/arch/arm64/boot/dts/exynos/exynos-pinctrl.h
new file mode 100644 (file)
index 0000000..7dd94a9
--- /dev/null
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Samsung Exynos DTS pinctrl constants
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ * Copyright (c) 2022 Linaro Ltd
+ * Author: Krzysztof Kozlowski <krzk@kernel.org>
+ */
+
+#ifndef __DTS_ARM64_SAMSUNG_EXYNOS_PINCTRL_H__
+#define __DTS_ARM64_SAMSUNG_EXYNOS_PINCTRL_H__
+
+#define EXYNOS_PIN_PULL_NONE           0
+#define EXYNOS_PIN_PULL_DOWN           1
+#define EXYNOS_PIN_PULL_UP             3
+
+/* Pin function in power down mode */
+#define EXYNOS_PIN_PDN_OUT0            0
+#define EXYNOS_PIN_PDN_OUT1            1
+#define EXYNOS_PIN_PDN_INPUT           2
+#define EXYNOS_PIN_PDN_PREV            3
+
+/*
+ * Drive strengths for Exynos5410, Exynos542x, Exynos5800, Exynos7885, Exynos850
+ * (except GPIO_HSI block), ExynosAutov9 (FSI0, PERIC1)
+ */
+#define EXYNOS5420_PIN_DRV_LV1         0
+#define EXYNOS5420_PIN_DRV_LV2         1
+#define EXYNOS5420_PIN_DRV_LV3         2
+#define EXYNOS5420_PIN_DRV_LV4         3
+
+/* Drive strengths for Exynos5433 */
+#define EXYNOS5433_PIN_DRV_FAST_SR1    0
+#define EXYNOS5433_PIN_DRV_FAST_SR2    1
+#define EXYNOS5433_PIN_DRV_FAST_SR3    2
+#define EXYNOS5433_PIN_DRV_FAST_SR4    3
+#define EXYNOS5433_PIN_DRV_FAST_SR5    4
+#define EXYNOS5433_PIN_DRV_FAST_SR6    5
+#define EXYNOS5433_PIN_DRV_SLOW_SR1    8
+#define EXYNOS5433_PIN_DRV_SLOW_SR2    9
+#define EXYNOS5433_PIN_DRV_SLOW_SR3    0xa
+#define EXYNOS5433_PIN_DRV_SLOW_SR4    0xb
+#define EXYNOS5433_PIN_DRV_SLOW_SR5    0xc
+#define EXYNOS5433_PIN_DRV_SLOW_SR6    0xf
+
+/* Drive strengths for Exynos7 (except FSYS1) */
+#define EXYNOS7_PIN_DRV_LV1            0
+#define EXYNOS7_PIN_DRV_LV2            2
+#define EXYNOS7_PIN_DRV_LV3            1
+#define EXYNOS7_PIN_DRV_LV4            3
+
+/* Drive strengths for Exynos7 FSYS1 block */
+#define EXYNOS7_FSYS1_PIN_DRV_LV1      0
+#define EXYNOS7_FSYS1_PIN_DRV_LV2      4
+#define EXYNOS7_FSYS1_PIN_DRV_LV3      2
+#define EXYNOS7_FSYS1_PIN_DRV_LV4      6
+#define EXYNOS7_FSYS1_PIN_DRV_LV5      1
+#define EXYNOS7_FSYS1_PIN_DRV_LV6      5
+
+/* Drive strengths for Exynos850 GPIO_HSI block */
+#define EXYNOS850_HSI_PIN_DRV_LV1      0       /* 1x   */
+#define EXYNOS850_HSI_PIN_DRV_LV1_5    1       /* 1.5x */
+#define EXYNOS850_HSI_PIN_DRV_LV2      2       /* 2x   */
+#define EXYNOS850_HSI_PIN_DRV_LV2_5    3       /* 2.5x */
+#define EXYNOS850_HSI_PIN_DRV_LV3      4       /* 3x   */
+#define EXYNOS850_HSI_PIN_DRV_LV4      5       /* 4x   */
+
+#define EXYNOS_PIN_FUNC_INPUT          0
+#define EXYNOS_PIN_FUNC_OUTPUT         1
+#define EXYNOS_PIN_FUNC_2              2
+#define EXYNOS_PIN_FUNC_3              3
+#define EXYNOS_PIN_FUNC_4              4
+#define EXYNOS_PIN_FUNC_5              5
+#define EXYNOS_PIN_FUNC_6              6
+#define EXYNOS_PIN_FUNC_EINT           0xf
+#define EXYNOS_PIN_FUNC_F              EXYNOS_PIN_FUNC_EINT
+
+#endif /* __DTS_ARM64_SAMSUNG_EXYNOS_PINCTRL_H__ */
index 4b46af3..6815535 100644 (file)
@@ -9,7 +9,7 @@
  * tree nodes are listed in this file.
  */
 
-#include <dt-bindings/pinctrl/samsung.h>
+#include "exynos-pinctrl.h"
 
 #define PIN(_pin, _func, _pull, _drv)                                  \
        pin- ## _pin {                                                  \
index 75b548e..bd6a354 100644 (file)
                        };
                };
 
-               mshc_0: mshc@15540000 {
+               mshc_0: mmc@15540000 {
                        compatible = "samsung,exynos7-dw-mshc-smu";
                        interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
                        #address-cells = <1>;
                        status = "disabled";
                };
 
-               mshc_1: mshc@15550000 {
+               mshc_1: mmc@15550000 {
                        compatible = "samsung,exynos7-dw-mshc-smu";
                        interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>;
                        #address-cells = <1>;
                        status = "disabled";
                };
 
-               mshc_2: mshc@15560000 {
+               mshc_2: mmc@15560000 {
                        compatible = "samsung,exynos7-dw-mshc-smu";
                        interrupts = <GIC_SPI 227 IRQ_TYPE_LEVEL_HIGH>;
                        #address-cells = <1>;
index 0895e81..e38c59c 100644 (file)
        pmic_irq: pmic-irq-pins {
                samsung,pins = "gpa0-2";
                samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV4>;
        };
 };
 
                samsung,pins = "gph1-1";
                samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 
        usb3drd_boost_en: usb3drd-boost-en-pins {
                samsung,pins = "gpf4-1";
                samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 };
 
index be9b971..ee9c24a 100644 (file)
@@ -9,7 +9,7 @@
  * device tree nodes in this file.
  */
 
-#include <dt-bindings/pinctrl/samsung.h>
+#include "exynos-pinctrl.h"
 
 &pinctrl_alive {
        gpa0: gpa0-gpio-bank {
                samsung,pins = "gpb0-1", "gpb0-0";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 
        hs_i2c11_bus: hs-i2c11-bus-pins {
                samsung,pins = "gpb0-3", "gpb0-2";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 
        hs_i2c2_bus: hs-i2c2-bus-pins {
                samsung,pins = "gpd0-3", "gpd0-2";
                samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 
        uart0_data: uart0-data-pins {
                samsung,pins = "gpd0-0", "gpd0-1";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 
        uart0_fctl: uart0-fctl-pins {
                samsung,pins = "gpd0-2", "gpd0-3";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 
        uart2_data: uart2-data-pins {
                samsung,pins = "gpd1-4", "gpd1-5";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 
        hs_i2c3_bus: hs-i2c3-bus-pins {
                samsung,pins = "gpd1-3", "gpd1-2";
                samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 
        uart1_data: uart1-data-pins {
                samsung,pins = "gpd1-0", "gpd1-1";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 
        uart1_fctl: uart1-fctl-pins {
                samsung,pins = "gpd1-2", "gpd1-3";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 
        hs_i2c0_bus: hs-i2c0-bus-pins {
                samsung,pins = "gpd2-1", "gpd2-0";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 
        hs_i2c1_bus: hs-i2c1-bus-pins {
                samsung,pins = "gpd2-3", "gpd2-2";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 
        hs_i2c9_bus: hs-i2c9-bus-pins {
                samsung,pins = "gpd2-7", "gpd2-6";
                samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 
        pwm0_out: pwm0-out-pins {
                samsung,pins = "gpd2-4";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 
        pwm1_out: pwm1-out-pins {
                samsung,pins = "gpd2-5";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 
        pwm2_out: pwm2-out-pins {
                samsung,pins = "gpd2-6";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 
        pwm3_out: pwm3-out-pins {
                samsung,pins = "gpd2-7";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 
        hs_i2c8_bus: hs-i2c8-bus-pins {
                samsung,pins = "gpd5-3", "gpd5-2";
                samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 
        uart3_data: uart3-data-pins {
                samsung,pins = "gpd5-0", "gpd5-1";
                samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 
        spi2_bus: spi2-bus-pins {
                samsung,pins = "gpd5-0", "gpd5-1", "gpd5-2", "gpd5-3";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 
        spi1_bus: spi1-bus-pins {
                samsung,pins = "gpd6-2", "gpd6-3", "gpd6-4", "gpd6-5";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 
        spi0_bus: spi0-bus-pins {
                samsung,pins = "gpd8-0", "gpd8-1", "gpd6-0", "gpd6-1";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 
        hs_i2c4_bus: hs-i2c4-bus-pins {
                samsung,pins = "gpg3-1", "gpg3-0";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 
        hs_i2c5_bus: hs-i2c5-bus-pins {
                samsung,pins = "gpg3-3", "gpg3-2";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 };
 
                samsung,pins = "gpj0-1", "gpj0-0";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 };
 
                samsung,pins = "gpj1-1", "gpj1-0";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 };
 
                samsung,pins = "gpg4-0", "gpg4-1", "gpg4-2", "gpg4-3";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 };
 
                samsung,pins = "gpv7-0", "gpv7-1", "gpv7-2", "gpv7-3";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 };
 
                samsung,pins = "gpr4-0";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV4>;
        };
 
        sd2_cmd: sd2-cmd-pins {
                samsung,pins = "gpr4-1";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV4>;
        };
 
        sd2_cd: sd2-cd-pins {
                samsung,pins = "gpr4-2";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV4>;
        };
 
        sd2_bus1: sd2-bus-width1-pins {
                samsung,pins = "gpr4-3";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV4>;
        };
 
        sd2_bus4: sd2-bus-width4-pins {
                samsung,pins = "gpr4-4", "gpr4-5", "gpr4-6";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV4>;
        };
 };
 
                samsung,pins = "gpf2-0", "gpf2-1", "gpf2-2", "gpf2-3";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 
        ufs_refclk_out: ufs-refclk-out-pins {
                samsung,pins = "gpg2-4";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV2>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV2>;
        };
 
        ufs_rst_n: ufs-rst-n-pins {
                samsung,pins = "gph1-5";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-drv = <EXYNOS7_PIN_DRV_LV1>;
        };
 };
index 4cf9aa2..5db9a81 100644 (file)
        };
 };
 
+&mmc_0 {
+       status = "okay";
+       mmc-hs200-1_8v;
+       mmc-hs400-1_8v;
+       cap-mmc-highspeed;
+       non-removable;
+       mmc-hs400-enhanced-strobe;
+       card-detect-delay = <200>;
+       clock-frequency = <800000000>;
+       bus-width = <8>;
+       samsung,dw-mshc-ciu-div = <3>;
+       samsung,dw-mshc-sdr-timing = <0 4>;
+       samsung,dw-mshc-ddr-timing = <2 4>;
+       samsung,dw-mshc-hs400-timing = <0 2>;
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&sd0_clk_fast_slew_rate_3x &sd0_cmd &sd0_rdqs
+                    &sd0_bus1 &sd0_bus4 &sd0_bus8>;
+};
+
 &oscclk {
        clock-frequency = <26000000>;
 };
index a50c1db..34bb121 100644 (file)
@@ -9,8 +9,8 @@
  * device tree nodes in this file.
  */
 
-#include <dt-bindings/pinctrl/samsung.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include "exynos-pinctrl.h"
 
 &pinctrl_alive {
        etc0: etc0-gpio-bank {
index 3170661..23c2e0b 100644 (file)
                        clock-names = "oscclk";
                };
 
+               cmu_fsys: clock-controller@13400000 {
+                       compatible = "samsung,exynos7885-cmu-fsys";
+                       reg = <0x13400000 0x8000>;
+                       #clock-cells = <1>;
+
+                       clocks = <&oscclk>,
+                                <&cmu_top CLK_DOUT_FSYS_BUS>,
+                                <&cmu_top CLK_DOUT_FSYS_MMC_CARD>,
+                                <&cmu_top CLK_DOUT_FSYS_MMC_EMBD>,
+                                <&cmu_top CLK_DOUT_FSYS_MMC_SDIO>,
+                                <&cmu_top CLK_DOUT_FSYS_USB30DRD>;
+                       clock-names = "oscclk",
+                                     "dout_fsys_bus",
+                                     "dout_fsys_mmc_card",
+                                     "dout_fsys_mmc_embd",
+                                     "dout_fsys_mmc_sdio",
+                                     "dout_fsys_usb30drd";
+               };
+
                pinctrl_alive: pinctrl@11cb0000 {
                        compatible = "samsung,exynos7885-pinctrl";
                        reg = <0x11cb0000 0x1000>;
                        reg = <0x11c80000 0x10000>;
                };
 
+               mmc_0: mmc@13500000 {
+                       compatible = "samsung,exynos7-dw-mshc-smu";
+                       reg = <0x13500000 0x2000>;
+                       interrupts = <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       clocks = <&cmu_fsys CLK_GOUT_MMC_EMBD_ACLK>,
+                                <&cmu_fsys CLK_GOUT_MMC_EMBD_SDCLKIN>;
+                       clock-names = "biu", "ciu";
+                       fifo-depth = <0x40>;
+                       status = "disabled";
+               };
+
                serial_0: serial@13800000 {
                        compatible = "samsung,exynos5433-uart";
                        reg = <0x13800000 0x100>;
                        interrupts = <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&uart0_bus>;
-                       clocks = <&cmu_peri CLK_GOUT_UART0_EXT_UCLK>,
-                                <&cmu_peri CLK_GOUT_UART0_PCLK>;
+                       clocks = <&cmu_peri CLK_GOUT_UART0_PCLK>,
+                                <&cmu_peri CLK_GOUT_UART0_EXT_UCLK>;
                        clock-names = "uart", "clk_uart_baud0";
                        samsung,uart-fifosize = <64>;
                        status = "disabled";
                        interrupts = <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&uart1_bus>;
-                       clocks = <&cmu_peri CLK_GOUT_UART1_EXT_UCLK>,
-                                <&cmu_peri CLK_GOUT_UART1_PCLK>;
+                       clocks = <&cmu_peri CLK_GOUT_UART1_PCLK>,
+                                <&cmu_peri CLK_GOUT_UART1_EXT_UCLK>;
                        clock-names = "uart", "clk_uart_baud0";
                        samsung,uart-fifosize = <256>;
                        status = "disabled";
                        interrupts = <GIC_SPI 279 IRQ_TYPE_LEVEL_HIGH>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&uart2_bus>;
-                       clocks = <&cmu_peri CLK_GOUT_UART2_EXT_UCLK>,
-                                <&cmu_peri CLK_GOUT_UART2_PCLK>;
+                       clocks = <&cmu_peri CLK_GOUT_UART2_PCLK>,
+                                <&cmu_peri CLK_GOUT_UART2_EXT_UCLK>;
                        clock-names = "uart", "clk_uart_baud0";
                        samsung,uart-fifosize = <256>;
                        status = "disabled";
index f43e4a2..424bc80 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 #include <dt-bindings/interrupt-controller/arm-gic.h>
-#include <dt-bindings/pinctrl/samsung.h>
+#include "exynos-pinctrl.h"
 
 &pinctrl_alive {
        gpa0: gpa0-gpio-bank {
index ef0349d..e413a51 100644 (file)
@@ -8,7 +8,7 @@
  * device tree nodes in this file.
  */
 
-#include <dt-bindings/pinctrl/samsung.h>
+#include "exynos-pinctrl.h"
 
 &pinctrl_alive {
        gpa0: gpa0-gpio-bank {
 
        /* PERIC1 USI11_SPI */
        spi11_bus: spi11-pins {
-               samsung,pins = "gpp3-6", "gpp3-5", "gpp3-4";
+               samsung,pins = "gpp5-6", "gpp5-5", "gpp5-4";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
                samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
        };
 
        spi11_cs: spi11-cs-pins {
-               samsung,pins = "gpp3-7";
+               samsung,pins = "gpp5-7";
                samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
                samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
        };
 
        spi11_cs_func: spi11-cs-func-pins {
-               samsung,pins = "gpp3-7";
+               samsung,pins = "gpp5-7";
                samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
                samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
                samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
index 17e5688..eec3192 100644 (file)
                regulator-boot-on;
                enable-active-high;
        };
+
+       ufs_1_fixed_vcc_reg: regulator-1 {
+               compatible = "regulator-fixed";
+               regulator-name = "ufs-vcc";
+               gpio = <&gpg2 2 GPIO_ACTIVE_HIGH>;
+               regulator-boot-on;
+               enable-active-high;
+       };
 };
 
 &serial_0 {
+       pinctrl-0 = <&uart0_bus_dual>;
        status = "okay";
 };
 
        status = "okay";
 };
 
+&ufs_1_phy {
+       status = "okay";
+};
+
 &ufs_0 {
        status = "okay";
        vcc-supply = <&ufs_0_fixed_vcc_reg>;
        vcc-fixed-regulator;
 };
 
+&ufs_1 {
+       status = "okay";
+       vcc-supply = <&ufs_1_fixed_vcc_reg>;
+       vcc-fixed-regulator;
+};
+
 &usi_0 {
+       samsung,clkreq-on; /* needed for UART mode */
        status = "okay";
 };
 
index 0ce46ec..2013718 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <dt-bindings/clock/samsung,exynosautov9.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/soc/samsung,boot-mode.h>
 #include <dt-bindings/soc/samsung,exynos-usi.h>
 
 / {
                                                 IRQ_TYPE_LEVEL_HIGH)>;
                };
 
+               pdma0: dma-controller@1b2e0000 {
+                       compatible = "arm,pl330", "arm,primecell";
+                       reg = <0x1b2e0000 0x1000>;
+                       interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cmu_busmc CLK_GOUT_BUSMC_PDMA0_PCLK>;
+                       clock-names = "apb_pclk";
+                       arm,pl330-broken-no-flushp;
+                       #dma-cells = <1>;
+               };
+
                pinctrl_alive: pinctrl@10450000 {
                        compatible = "samsung,exynosautov9-pinctrl";
                        reg = <0x10450000 0x1000>;
                pmu_system_controller: system-controller@10460000 {
                        compatible = "samsung,exynos7-pmu", "syscon";
                        reg = <0x10460000 0x10000>;
+
+                       reboot: syscon-reboot {
+                               compatible = "syscon-reboot";
+                               regmap = <&pmu_system_controller>;
+                               offset = <0x3a00>; /* SYSTEM_CONFIGURATION */
+                               value = <0x2>;
+                               mask = <0x2>;
+                       };
+
+                       reboot-mode {
+                               compatible = "syscon-reboot-mode";
+                               offset = <0x810>; /* SYSIP_DAT0 */
+                               mode-bootloader = <EXYNOSAUTOV9_BOOT_BOOTLOADER>;
+                               mode-fastboot = <EXYNOSAUTOV9_BOOT_FASTBOOT>;
+                               mode-recovery = <EXYNOSAUTOV9_BOOT_RECOVERY>;
+                       };
                };
 
                syscon_fsys2: syscon@17c20000 {
                        reg = <0x10220000 0x2000>;
                };
 
+               syscon_peric1: syscon@10820000 {
+                       compatible = "samsung,exynosautov9-sysreg", "syscon";
+                       reg = <0x10820000 0x2000>;
+               };
+
                usi_0: usi@103000c0 {
-                       compatible = "samsung,exynos850-usi";
+                       compatible = "samsung,exynosautov9-usi",
+                                    "samsung,exynos850-usi";
                        reg = <0x103000c0 0x20>;
                        samsung,sysreg = <&syscon_peric0 0x1000>;
                        samsung,mode = <USI_V2_UART>;
-                       samsung,clkreq-on; /* needed for UART mode */
                        #address-cells = <1>;
                        #size-cells = <1>;
                        ranges;
                        clock-names = "pclk", "ipclk";
                        status = "disabled";
 
-                       /* USI: UART */
                        serial_0: serial@10300000 {
-                               compatible = "samsung,exynos850-uart";
+                               compatible = "samsung,exynosautov9-uart",
+                                            "samsung,exynos850-uart";
                                reg = <0x10300000 0xc0>;
                                interrupts = <GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>;
                                pinctrl-names = "default";
-                               pinctrl-0 = <&uart0_bus_dual>;
+                               pinctrl-0 = <&uart0_bus>;
                                clocks = <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_0>,
                                         <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_0>;
                                clock-names = "uart", "clk_uart_baud0";
+                               samsung,uart-fifosize = <256>;
+                               status = "disabled";
+                       };
+
+                       spi_0: spi@10300000 {
+                               compatible = "samsung,exynosautov9-spi";
+                               reg = <0x10300000 0x30>;
+                               interrupts = <GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&spi0_bus &spi0_cs_func>;
+                               clocks = <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_0>,
+                                        <&cmu_peric0 CLK_DOUT_PERIC0_USI00_USI>,
+                                        <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_0>;
+                               clock-names = "spi", "spi_busclk0", "spi_ioclk";
+                               samsung,spi-src-clk = <0>;
+                               dmas = <&pdma0 1>, <&pdma0 0>;
+                               dma-names = "tx", "rx";
+                               num-cs = <1>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
+                       hsi2c_0: i2c@10300000 {
+                               compatible = "samsung,exynosautov9-hsi2c";
+                               reg = <0x10300000 0xc0>;
+                               interrupts = <GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hsi2c0_bus>;
+                               clocks = <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_0>,
+                                        <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_0>;
+                               clock-names = "hsi2c", "hsi2c_pclk";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+               };
+
+               usi_i2c_0: usi@103100c0 {
+                       compatible = "samsung,exynosautov9-usi",
+                                    "samsung,exynos850-usi";
+                       reg = <0x103100c0 0x20>;
+                       samsung,sysreg = <&syscon_peric0 0x1004>;
+                       samsung,mode = <USI_V2_I2C>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+                       clocks = <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_1>,
+                                <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_1>;
+                       clock-names = "pclk", "ipclk";
+                       status = "disabled";
+
+                       hsi2c_1: i2c@10310000 {
+                               compatible = "samsung,exynosautov9-hsi2c";
+                               reg = <0x10310000 0xc0>;
+                               interrupts = <GIC_SPI 344 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hsi2c1_bus>;
+                               clocks = <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_1>,
+                                        <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_1>;
+                               clock-names = "hsi2c", "hsi2c_pclk";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+               };
+
+               usi_1: usi@103200c0 {
+                       compatible = "samsung,exynosautov9-usi",
+                                    "samsung,exynos850-usi";
+                       reg = <0x103200c0 0x20>;
+                       samsung,sysreg = <&syscon_peric0 0x1008>;
+                       samsung,mode = <USI_V2_UART>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+                       clocks = <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_2>,
+                                <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_2>;
+                       clock-names = "pclk", "ipclk";
+                       status = "disabled";
+
+                       serial_1: serial@10320000 {
+                               compatible = "samsung,exynosautov9-uart",
+                                            "samsung,exynos850-uart";
+                               reg = <0x10320000 0xc0>;
+                               interrupts = <GIC_SPI 347 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&uart1_bus>;
+                               clocks = <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_2>,
+                                        <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_2>;
+                               clock-names = "uart", "clk_uart_baud0";
+                               samsung,uart-fifosize = <256>;
+                               status = "disabled";
+                       };
+
+                       spi_1: spi@10320000 {
+                               compatible = "samsung,exynosautov9-spi";
+                               reg = <0x10320000 0x30>;
+                               interrupts = <GIC_SPI 347 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&spi1_bus &spi1_cs_func>;
+                               clocks = <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_2>,
+                                        <&cmu_peric0 CLK_DOUT_PERIC0_USI01_USI>,
+                                        <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_2>;
+                               clock-names = "spi", "spi_busclk0", "spi_ioclk";
+                               samsung,spi-src-clk = <0>;
+                               dmas = <&pdma0 3>, <&pdma0 2>;
+                               dma-names = "tx", "rx";
+                               num-cs = <1>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
+                       hsi2c_2: i2c@10320000 {
+                               compatible = "samsung,exynosautov9-hsi2c";
+                               reg = <0x10320000 0xc0>;
+                               interrupts = <GIC_SPI 347 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hsi2c2_bus>;
+                               clocks = <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_2>,
+                                        <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_2>;
+                               clock-names = "hsi2c", "hsi2c_pclk";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+               };
+
+               usi_i2c_1: usi@103300c0 {
+                       compatible = "samsung,exynosautov9-usi",
+                                    "samsung,exynos850-usi";
+                       reg = <0x103300c0 0x20>;
+                       samsung,sysreg = <&syscon_peric0 0x100c>;
+                       samsung,mode = <USI_V2_I2C>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+                       clocks = <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_3>,
+                                <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_3>;
+                       clock-names = "pclk", "ipclk";
+                       status = "disabled";
+
+                       hsi2c_3: i2c@10330000 {
+                               compatible = "samsung,exynosautov9-hsi2c";
+                               reg = <0x10330000 0xc0>;
+                               interrupts = <GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hsi2c3_bus>;
+                               clocks = <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_3>,
+                                        <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_3>;
+                               clock-names = "hsi2c", "hsi2c_pclk";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+               };
+
+               usi_2: usi@103400c0 {
+                       compatible = "samsung,exynosautov9-usi",
+                                    "samsung,exynos850-usi";
+                       reg = <0x103400c0 0x20>;
+                       samsung,sysreg = <&syscon_peric0 0x1010>;
+                       samsung,mode = <USI_V2_UART>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+                       clocks = <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_4>,
+                                <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_4>;
+                       clock-names = "pclk", "ipclk";
+                       status = "disabled";
+
+                       serial_2: serial@10340000 {
+                               compatible = "samsung,exynosautov9-uart",
+                                            "samsung,exynos850-uart";
+                               reg = <0x10340000 0xc0>;
+                               interrupts = <GIC_SPI 349 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&uart2_bus>;
+                               clocks = <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_4>,
+                                        <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_4>;
+                               clock-names = "uart", "clk_uart_baud0";
+                               samsung,uart-fifosize = <64>;
+                               status = "disabled";
+                       };
+
+                       spi_2: spi@10340000 {
+                               compatible = "samsung,exynosautov9-spi";
+                               reg = <0x10340000 0x30>;
+                               interrupts = <GIC_SPI 349 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&spi2_bus &spi2_cs_func>;
+                               clocks = <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_4>,
+                                        <&cmu_peric0 CLK_DOUT_PERIC0_USI02_USI>,
+                                        <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_4>;
+                               clock-names = "spi", "spi_busclk0", "spi_ioclk";
+                               samsung,spi-src-clk = <0>;
+                               dmas = <&pdma0 5>, <&pdma0 4>;
+                               dma-names = "tx", "rx";
+                               num-cs = <1>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
+                       hsi2c_4: i2c@10340000 {
+                               compatible = "samsung,exynosautov9-hsi2c";
+                               reg = <0x10340000 0xc0>;
+                               interrupts = <GIC_SPI 349 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hsi2c4_bus>;
+                               clocks = <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_4>,
+                                        <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_4>;
+                               clock-names = "hsi2c", "hsi2c_pclk";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+               };
+
+               usi_i2c_2: usi@103500c0 {
+                       compatible = "samsung,exynosautov9-usi",
+                                    "samsung,exynos850-usi";
+                       reg = <0x103500c0 0x20>;
+                       samsung,sysreg = <&syscon_peric0 0x1014>;
+                       samsung,mode = <USI_V2_I2C>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+                       clocks = <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_5>,
+                                <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_5>;
+                       clock-names = "pclk", "ipclk";
+                       status = "disabled";
+
+                       hsi2c_5: i2c@10350000 {
+                               compatible = "samsung,exynosautov9-hsi2c";
+                               reg = <0x10350000 0xc0>;
+                               interrupts = <GIC_SPI 348 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hsi2c5_bus>;
+                               clocks = <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_5>,
+                                        <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_5>;
+                               clock-names = "hsi2c", "hsi2c_pclk";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+               };
+
+               usi_3: usi@103600c0 {
+                       compatible = "samsung,exynosautov9-usi",
+                                    "samsung,exynos850-usi";
+                       reg = <0x103600c0 0x20>;
+                       samsung,sysreg = <&syscon_peric0 0x1018>;
+                       samsung,mode = <USI_V2_UART>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+                       clocks = <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_6>,
+                                <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_6>;
+                       clock-names = "pclk", "ipclk";
+                       status = "disabled";
+
+                       serial_3: serial@10360000 {
+                               compatible = "samsung,exynosautov9-uart",
+                                            "samsung,exynos850-uart";
+                               reg = <0x10360000 0xc0>;
+                               interrupts = <GIC_SPI 351 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&uart3_bus>;
+                               clocks = <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_6>,
+                                        <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_6>;
+                               clock-names = "uart", "clk_uart_baud0";
+                               samsung,uart-fifosize = <64>;
+                               status = "disabled";
+                       };
+
+                       spi_3: spi@10360000 {
+                               compatible = "samsung,exynosautov9-spi";
+                               reg = <0x10360000 0x30>;
+                               interrupts = <GIC_SPI 351 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&spi3_bus &spi3_cs_func>;
+                               clocks = <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_6>,
+                                        <&cmu_peric0 CLK_DOUT_PERIC0_USI03_USI>,
+                                        <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_6>;
+                               clock-names = "spi", "spi_busclk0", "spi_ioclk";
+                               samsung,spi-src-clk = <0>;
+                               dmas = <&pdma0 7>, <&pdma0 6>;
+                               dma-names = "tx", "rx";
+                               num-cs = <1>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
+                       hsi2c_6: i2c@10360000 {
+                               compatible = "samsung,exynosautov9-hsi2c";
+                               reg = <0x10360000 0xc0>;
+                               interrupts = <GIC_SPI 351 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hsi2c6_bus>;
+                               clocks = <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_6>,
+                                        <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_6>;
+                               clock-names = "hsi2c", "hsi2c_pclk";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+               };
+
+               usi_i2c_3: usi@103700c0 {
+                       compatible = "samsung,exynosautov9-usi",
+                                    "samsung,exynos850-usi";
+                       reg = <0x103700c0 0x20>;
+                       samsung,sysreg = <&syscon_peric0 0x101c>;
+                       samsung,mode = <USI_V2_I2C>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+                       clocks = <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_7>,
+                                <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_7>;
+                       clock-names = "pclk", "ipclk";
+                       status = "disabled";
+
+                       hsi2c_7: i2c@10370000 {
+                               compatible = "samsung,exynosautov9-hsi2c";
+                               reg = <0x10370000 0xc0>;
+                               interrupts = <GIC_SPI 350 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hsi2c7_bus>;
+                               clocks = <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_7>,
+                                        <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_7>;
+                               clock-names = "hsi2c", "hsi2c_pclk";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+               };
+
+               usi_4: usi@103800c0 {
+                       compatible = "samsung,exynosautov9-usi",
+                                    "samsung,exynos850-usi";
+                       reg = <0x103800c0 0x20>;
+                       samsung,sysreg = <&syscon_peric0 0x1020>;
+                       samsung,mode = <USI_V2_UART>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+                       clocks = <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_8>,
+                                <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_8>;
+                       clock-names = "pclk", "ipclk";
+                       status = "disabled";
+
+                       serial_4: serial@10380000 {
+                               compatible = "samsung,exynosautov9-uart",
+                                            "samsung,exynos850-uart";
+                               reg = <0x10380000 0xc0>;
+                               interrupts = <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&uart4_bus>;
+                               clocks = <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_8>,
+                                        <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_8>;
+                               clock-names = "uart", "clk_uart_baud0";
+                               samsung,uart-fifosize = <64>;
+                               status = "disabled";
+                       };
+
+                       spi_4: spi@10380000 {
+                               compatible = "samsung,exynosautov9-spi";
+                               reg = <0x10380000 0x30>;
+                               interrupts = <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&spi4_bus &spi4_cs_func>;
+                               clocks = <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_8>,
+                                        <&cmu_peric0 CLK_DOUT_PERIC0_USI04_USI>,
+                                        <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_8>;
+                               clock-names = "spi", "spi_busclk0", "spi_ioclk";
+                               samsung,spi-src-clk = <0>;
+                               dmas = <&pdma0 9>, <&pdma0 8>;
+                               dma-names = "tx", "rx";
+                               num-cs = <1>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
+                       hsi2c_8: i2c@10380000 {
+                               compatible = "samsung,exynosautov9-hsi2c";
+                               reg = <0x10380000 0xc0>;
+                               interrupts = <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hsi2c8_bus>;
+                               clocks = <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_8>,
+                                        <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_8>;
+                               clock-names = "hsi2c", "hsi2c_pclk";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+               };
+
+               usi_i2c_4: usi@103900c0 {
+                       compatible = "samsung,exynosautov9-usi",
+                                    "samsung,exynos850-usi";
+                       reg = <0x103900c0 0x20>;
+                       samsung,sysreg = <&syscon_peric0 0x1024>;
+                       samsung,mode = <USI_V2_I2C>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+                       clocks = <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_9>,
+                                <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_9>;
+                       clock-names = "pclk", "ipclk";
+                       status = "disabled";
+
+                       hsi2c_9: i2c@10390000 {
+                               compatible = "samsung,exynosautov9-hsi2c";
+                               reg = <0x10390000 0xc0>;
+                               interrupts = <GIC_SPI 352 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hsi2c9_bus>;
+                               clocks = <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_9>,
+                                        <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_9>;
+                               clock-names = "hsi2c", "hsi2c_pclk";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+               };
+
+               usi_5: usi@103a00c0 {
+                       compatible = "samsung,exynosautov9-usi",
+                                    "samsung,exynos850-usi";
+                       reg = <0x103a00c0 0x20>;
+                       samsung,sysreg = <&syscon_peric0 0x1028>;
+                       samsung,mode = <USI_V2_UART>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+                       clocks = <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_10>,
+                                <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_10>;
+                       clock-names = "pclk", "ipclk";
+                       status = "disabled";
+
+                       serial_5: serial@103a0000 {
+                               compatible = "samsung,exynosautov9-uart",
+                                            "samsung,exynos850-uart";
+                               reg = <0x103a0000 0xc0>;
+                               interrupts = <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&uart5_bus>;
+                               clocks = <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_10>,
+                                        <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_10>;
+                               clock-names = "uart", "clk_uart_baud0";
+                               samsung,uart-fifosize = <64>;
+                               status = "disabled";
+                       };
+
+                       spi_5: spi@103a0000 {
+                               compatible = "samsung,exynosautov9-spi";
+                               reg = <0x103a0000 0x30>;
+                               interrupts = <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&spi5_bus &spi5_cs_func>;
+                               clocks = <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_10>,
+                                        <&cmu_peric0 CLK_DOUT_PERIC0_USI05_USI>,
+                                        <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_10>;
+                               clock-names = "spi", "spi_busclk0", "spi_ioclk";
+                               samsung,spi-src-clk = <0>;
+                               dmas = <&pdma0 11>, <&pdma0 10>;
+                               dma-names = "tx", "rx";
+                               num-cs = <1>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
+                       hsi2c_10: i2c@103a0000 {
+                               compatible = "samsung,exynosautov9-hsi2c";
+                               reg = <0x103a0000 0xc0>;
+                               interrupts = <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hsi2c10_bus>;
+                               clocks = <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_10>,
+                                        <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_10>;
+                               clock-names = "hsi2c", "hsi2c_pclk";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+               };
+
+               usi_i2c_5: usi@103b00c0 {
+                       compatible = "samsung,exynosautov9-usi",
+                                    "samsung,exynos850-usi";
+                       reg = <0x103b00c0 0x20>;
+                       samsung,sysreg = <&syscon_peric0 0x102c>;
+                       samsung,mode = <USI_V2_I2C>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+                       clocks = <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_11>,
+                                <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_11>;
+                       clock-names = "pclk", "ipclk";
+                       status = "disabled";
+
+                       hsi2c_11: i2c@103b0000 {
+                               compatible = "samsung,exynosautov9-hsi2c";
+                               reg = <0x103b0000 0xc0>;
+                               interrupts = <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hsi2c11_bus>;
+                               clocks = <&cmu_peric0 CLK_GOUT_PERIC0_IPCLK_11>,
+                                        <&cmu_peric0 CLK_GOUT_PERIC0_PCLK_11>;
+                               clock-names = "hsi2c", "hsi2c_pclk";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+               };
+
+               usi_6: usi@109000c0 {
+                       compatible = "samsung,exynosautov9-usi",
+                                    "samsung,exynos850-usi";
+                       reg = <0x109000c0 0x20>;
+                       samsung,sysreg = <&syscon_peric1 0x1000>;
+                       samsung,mode = <USI_V2_UART>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+                       clocks = <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_0>,
+                                <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_0>;
+                       clock-names = "pclk", "ipclk";
+                       status = "disabled";
+
+                       serial_6: serial@10900000 {
+                               compatible = "samsung,exynosautov9-uart",
+                                            "samsung,exynos850-uart";
+                               reg = <0x10900000 0xc0>;
+                               interrupts = <GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&uart6_bus>;
+                               clocks = <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_0>,
+                                        <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_0>;
+                               clock-names = "uart", "clk_uart_baud0";
+                               samsung,uart-fifosize = <256>;
+                               status = "disabled";
+                       };
+
+                       spi_6: spi@10900000 {
+                               compatible = "samsung,exynosautov9-spi";
+                               reg = <0x10900000 0x30>;
+                               interrupts = <GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&spi6_bus &spi6_cs_func>;
+                               clocks = <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_0>,
+                                        <&cmu_peric1 CLK_DOUT_PERIC1_USI06_USI>,
+                                        <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_0>;
+                               clock-names = "spi", "spi_busclk0", "spi_ioclk";
+                               samsung,spi-src-clk = <0>;
+                               dmas = <&pdma0 13>, <&pdma0 12>;
+                               dma-names = "tx", "rx";
+                               num-cs = <1>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
+                       hsi2c_12: i2c@10900000 {
+                               compatible = "samsung,exynosautov9-hsi2c";
+                               reg = <0x10900000 0xc0>;
+                               interrupts = <GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hsi2c12_bus>;
+                               clocks = <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_0>,
+                                        <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_0>;
+                               clock-names = "hsi2c", "hsi2c_pclk";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+               };
+
+               usi_i2c_6: usi@109100c0 {
+                       compatible = "samsung,exynosautov9-usi",
+                                    "samsung,exynos850-usi";
+                       reg = <0x109100c0 0x20>;
+                       samsung,sysreg = <&syscon_peric1 0x1004>;
+                       samsung,mode = <USI_V2_I2C>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+                       clocks = <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_1>,
+                                <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_1>;
+                       clock-names = "pclk", "ipclk";
+                       status = "disabled";
+
+                       hsi2c_13: i2c@10910000 {
+                               compatible = "samsung,exynosautov9-hsi2c";
+                               reg = <0x10910000 0xc0>;
+                               interrupts = <GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hsi2c13_bus>;
+                               clocks = <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_1>,
+                                        <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_1>;
+                               clock-names = "hsi2c", "hsi2c_pclk";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+               };
+
+               usi_7: usi@109200c0 {
+                       compatible = "samsung,exynosautov9-usi",
+                                    "samsung,exynos850-usi";
+                       reg = <0x109200c0 0x20>;
+                       samsung,sysreg = <&syscon_peric1 0x1008>;
+                       samsung,mode = <USI_V2_UART>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+                       clocks = <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_2>,
+                                <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_2>;
+                       clock-names = "pclk", "ipclk";
+                       status = "disabled";
+
+                       serial_7: serial@10920000 {
+                               compatible = "samsung,exynosautov9-uart",
+                                            "samsung,exynos850-uart";
+                               reg = <0x10920000 0xc0>;
+                               interrupts = <GIC_SPI 360 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&uart7_bus>;
+                               clocks = <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_2>,
+                                        <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_2>;
+                               clock-names = "uart", "clk_uart_baud0";
+                               samsung,uart-fifosize = <64>;
+                               status = "disabled";
+                       };
+
+                       spi_7: spi@10920000 {
+                               compatible = "samsung,exynosautov9-spi";
+                               reg = <0x10920000 0x30>;
+                               interrupts = <GIC_SPI 360 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&spi7_bus &spi7_cs_func>;
+                               clocks = <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_2>,
+                                        <&cmu_peric1 CLK_DOUT_PERIC1_USI07_USI>,
+                                        <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_2>;
+                               clock-names = "spi", "spi_busclk0", "spi_ioclk";
+                               samsung,spi-src-clk = <0>;
+                               dmas = <&pdma0 15>, <&pdma0 14>;
+                               dma-names = "tx", "rx";
+                               num-cs = <1>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
+                       hsi2c_14: i2c@10920000 {
+                               compatible = "samsung,exynosautov9-hsi2c";
+                               reg = <0x10920000 0xc0>;
+                               interrupts = <GIC_SPI 360 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hsi2c14_bus>;
+                               clocks = <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_2>,
+                                        <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_2>;
+                               clock-names = "hsi2c", "hsi2c_pclk";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+               };
+
+               usi_i2c_7: usi@109300c0 {
+                       compatible = "samsung,exynosautov9-usi",
+                                    "samsung,exynos850-usi";
+                       reg = <0x109300c0 0x20>;
+                       samsung,sysreg = <&syscon_peric1 0x100c>;
+                       samsung,mode = <USI_V2_I2C>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+                       clocks = <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_3>,
+                                <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_3>;
+                       clock-names = "pclk", "ipclk";
+                       status = "disabled";
+
+                       hsi2c_15: i2c@10930000 {
+                               compatible = "samsung,exynosautov9-hsi2c";
+                               reg = <0x10930000 0xc0>;
+                               interrupts = <GIC_SPI 359 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hsi2c15_bus>;
+                               clocks = <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_3>,
+                                        <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_3>;
+                               clock-names = "hsi2c", "hsi2c_pclk";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+               };
+
+               usi_8: usi@109400c0 {
+                       compatible = "samsung,exynosautov9-usi",
+                                    "samsung,exynos850-usi";
+                       reg = <0x109400c0 0x20>;
+                       samsung,sysreg = <&syscon_peric1 0x1010>;
+                       samsung,mode = <USI_V2_UART>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+                       clocks = <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_4>,
+                                <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_4>;
+                       clock-names = "pclk", "ipclk";
+                       status = "disabled";
+
+                       serial_8: serial@10940000 {
+                               compatible = "samsung,exynosautov9-uart",
+                                            "samsung,exynos850-uart";
+                               reg = <0x10940000 0xc0>;
+                               interrupts = <GIC_SPI 362 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&uart8_bus>;
+                               clocks = <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_4>,
+                                        <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_4>;
+                               clock-names = "uart", "clk_uart_baud0";
+                               samsung,uart-fifosize = <64>;
+                               status = "disabled";
+                       };
+
+                       spi_8: spi@10940000 {
+                               compatible = "samsung,exynosautov9-spi";
+                               reg = <0x10940000 0x30>;
+                               interrupts = <GIC_SPI 362 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&spi8_bus &spi8_cs_func>;
+                               clocks = <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_4>,
+                                        <&cmu_peric1 CLK_DOUT_PERIC1_USI08_USI>,
+                                        <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_4>;
+                               clock-names = "spi", "spi_busclk0", "spi_ioclk";
+                               samsung,spi-src-clk = <0>;
+                               dmas = <&pdma0 17>, <&pdma0 16>;
+                               dma-names = "tx", "rx";
+                               num-cs = <1>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
+                       hsi2c_16: i2c@10940000 {
+                               compatible = "samsung,exynosautov9-hsi2c";
+                               reg = <0x10940000 0xc0>;
+                               interrupts = <GIC_SPI 362 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hsi2c16_bus>;
+                               clocks = <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_4>,
+                                        <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_4>;
+                               clock-names = "hsi2c", "hsi2c_pclk";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+               };
+
+               usi_i2c_8: usi@109500c0 {
+                       compatible = "samsung,exynosautov9-usi",
+                                    "samsung,exynos850-usi";
+                       reg = <0x109500c0 0x20>;
+                       samsung,sysreg = <&syscon_peric1 0x1014>;
+                       samsung,mode = <USI_V2_I2C>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+                       clocks = <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_5>,
+                                <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_5>;
+                       clock-names = "pclk", "ipclk";
+                       status = "disabled";
+
+                       hsi2c_17: i2c@10950000 {
+                               compatible = "samsung,exynosautov9-hsi2c";
+                               reg = <0x10950000 0xc0>;
+                               interrupts = <GIC_SPI 361 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hsi2c17_bus>;
+                               clocks = <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_5>,
+                                        <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_5>;
+                               clock-names = "hsi2c", "hsi2c_pclk";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+               };
+
+               usi_9: usi@109600c0 {
+                       compatible = "samsung,exynosautov9-usi",
+                                    "samsung,exynos850-usi";
+                       reg = <0x109600c0 0x20>;
+                       samsung,sysreg = <&syscon_peric1 0x1018>;
+                       samsung,mode = <USI_V2_UART>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+                       clocks = <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_6>,
+                                <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_6>;
+                       clock-names = "pclk", "ipclk";
+                       status = "disabled";
+
+                       serial_9: serial@10960000 {
+                               compatible = "samsung,exynosautov9-uart",
+                                            "samsung,exynos850-uart";
+                               reg = <0x10960000 0xc0>;
+                               interrupts = <GIC_SPI 364 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&uart9_bus>;
+                               clocks = <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_6>,
+                                        <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_6>;
+                               clock-names = "uart", "clk_uart_baud0";
+                               samsung,uart-fifosize = <64>;
+                               status = "disabled";
+                       };
+
+                       spi_9: spi@10960000 {
+                               compatible = "samsung,exynosautov9-spi";
+                               reg = <0x10960000 0x30>;
+                               interrupts = <GIC_SPI 364 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&spi9_bus &spi9_cs_func>;
+                               clocks = <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_6>,
+                                        <&cmu_peric1 CLK_DOUT_PERIC1_USI09_USI>,
+                                        <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_6>;
+                               clock-names = "spi", "spi_busclk0", "spi_ioclk";
+                               samsung,spi-src-clk = <0>;
+                               dmas = <&pdma0 19>, <&pdma0 18>;
+                               dma-names = "tx", "rx";
+                               num-cs = <1>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
+                       hsi2c_18: i2c@10960000 {
+                               compatible = "samsung,exynosautov9-hsi2c";
+                               reg = <0x10960000 0xc0>;
+                               interrupts = <GIC_SPI 364 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hsi2c18_bus>;
+                               clocks = <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_6>,
+                                        <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_6>;
+                               clock-names = "hsi2c", "hsi2c_pclk";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+               };
+
+               usi_i2c_9: usi@109700c0 {
+                       compatible = "samsung,exynosautov9-usi",
+                                    "samsung,exynos850-usi";
+                       reg = <0x109700c0 0x20>;
+                       samsung,sysreg = <&syscon_peric1 0x101c>;
+                       samsung,mode = <USI_V2_I2C>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+                       clocks = <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_7>,
+                                <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_7>;
+                       clock-names = "pclk", "ipclk";
+                       status = "disabled";
+
+                       hsi2c_19: i2c@10970000 {
+                               compatible = "samsung,exynosautov9-hsi2c";
+                               reg = <0x10970000 0xc0>;
+                               interrupts = <GIC_SPI 363 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hsi2c19_bus>;
+                               clocks = <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_7>,
+                                        <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_7>;
+                               clock-names = "hsi2c", "hsi2c_pclk";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+               };
+
+               usi_10: usi@109800c0 {
+                       compatible = "samsung,exynosautov9-usi",
+                                    "samsung,exynos850-usi";
+                       reg = <0x109800c0 0x20>;
+                       samsung,sysreg = <&syscon_peric1 0x1020>;
+                       samsung,mode = <USI_V2_UART>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+                       clocks = <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_8>,
+                                <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_8>;
+                       clock-names = "pclk", "ipclk";
+                       status = "disabled";
+
+                       serial_10: serial@10980000 {
+                               compatible = "samsung,exynosautov9-uart",
+                                            "samsung,exynos850-uart";
+                               reg = <0x10980000 0xc0>;
+                               interrupts = <GIC_SPI 366 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&uart10_bus>;
+                               clocks = <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_8>,
+                                        <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_8>;
+                               clock-names = "uart", "clk_uart_baud0";
+                               samsung,uart-fifosize = <64>;
+                               status = "disabled";
+                       };
+
+                       spi_10: spi@10980000 {
+                               compatible = "samsung,exynosautov9-spi";
+                               reg = <0x10980000 0x30>;
+                               interrupts = <GIC_SPI 366 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&spi10_bus &spi10_cs_func>;
+                               clocks = <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_8>,
+                                        <&cmu_peric1 CLK_DOUT_PERIC1_USI10_USI>,
+                                        <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_8>;
+                               clock-names = "spi", "spi_busclk0", "spi_ioclk";
+                               samsung,spi-src-clk = <0>;
+                               dmas = <&pdma0 21>, <&pdma0 20>;
+                               dma-names = "tx", "rx";
+                               num-cs = <1>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
+                       hsi2c_20: i2c@10980000 {
+                               compatible = "samsung,exynosautov9-hsi2c";
+                               reg = <0x10980000 0xc0>;
+                               interrupts = <GIC_SPI 366 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hsi2c20_bus>;
+                               clocks = <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_8>,
+                                        <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_8>;
+                               clock-names = "hsi2c", "hsi2c_pclk";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
                                status = "disabled";
                        };
                };
 
-               ufs_0_phy: ufs0-phy@17e04000 {
+               usi_i2c_10: usi@109900c0 {
+                       compatible = "samsung,exynosautov9-usi",
+                                    "samsung,exynos850-usi";
+                       reg = <0x109900c0 0x20>;
+                       samsung,sysreg = <&syscon_peric1 0x1024>;
+                       samsung,mode = <USI_V2_I2C>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+                       clocks = <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_9>,
+                                <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_9>;
+                       clock-names = "pclk", "ipclk";
+                       status = "disabled";
+
+                       hsi2c_21: i2c@10990000 {
+                               compatible = "samsung,exynosautov9-hsi2c";
+                               reg = <0x10990000 0xc0>;
+                               interrupts = <GIC_SPI 365 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hsi2c21_bus>;
+                               clocks = <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_9>,
+                                        <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_9>;
+                               clock-names = "hsi2c", "hsi2c_pclk";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+               };
+
+               usi_11: usi@109a00c0 {
+                       compatible = "samsung,exynosautov9-usi",
+                                    "samsung,exynos850-usi";
+                       reg = <0x109a00c0 0x20>;
+                       samsung,sysreg = <&syscon_peric1 0x1028>;
+                       samsung,mode = <USI_V2_UART>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+                       clocks = <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_10>,
+                                <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_10>;
+                       clock-names = "pclk", "ipclk";
+                       status = "disabled";
+
+                       serial_11: serial@109a0000 {
+                               compatible = "samsung,exynosautov9-uart",
+                                            "samsung,exynos850-uart";
+                               reg = <0x109a0000 0xc0>;
+                               interrupts = <GIC_SPI 368 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&uart11_bus>;
+                               clocks = <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_10>,
+                                        <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_10>;
+                               clock-names = "uart", "clk_uart_baud0";
+                               samsung,uart-fifosize = <64>;
+                               status = "disabled";
+                       };
+
+                       spi_11: spi@109a0000 {
+                               compatible = "samsung,exynosautov9-spi";
+                               reg = <0x109a0000 0x30>;
+                               interrupts = <GIC_SPI 368 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&spi11_bus &spi11_cs_func>;
+                               clocks = <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_10>,
+                                        <&cmu_peric1 CLK_DOUT_PERIC1_USI11_USI>,
+                                        <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_10>;
+                               clock-names = "spi", "spi_busclk0", "spi_ioclk";
+                               samsung,spi-src-clk = <0>;
+                               num-cs = <1>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
+                       hsi2c_22: i2c@109a0000 {
+                               compatible = "samsung,exynosautov9-hsi2c";
+                               reg = <0x109a0000 0xc0>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hsi2c22_bus>;
+                               interrupts = <GIC_SPI 368 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_10>,
+                                        <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_10>;
+                               clock-names = "hsi2c", "hsi2c_pclk";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+               };
+
+               usi_i2c_11: usi@109b00c0 {
+                       compatible = "samsung,exynosautov9-usi",
+                                    "samsung,exynos850-usi";
+                       reg = <0x109b00c0 0x20>;
+                       samsung,sysreg = <&syscon_peric1 0x102c>;
+                       samsung,mode = <USI_V2_I2C>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+                       clocks = <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_11>,
+                                <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_11>;
+                       clock-names = "pclk", "ipclk";
+                       status = "disabled";
+
+                       hsi2c_23: i2c@109b0000 {
+                               compatible = "samsung,exynosautov9-hsi2c";
+                               reg = <0x109b0000 0xc0>;
+                               interrupts = <GIC_SPI 367 IRQ_TYPE_LEVEL_HIGH>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hsi2c23_bus>;
+                               clocks = <&cmu_peric1 CLK_GOUT_PERIC1_IPCLK_11>,
+                                        <&cmu_peric1 CLK_GOUT_PERIC1_PCLK_11>;
+                               clock-names = "hsi2c", "hsi2c_pclk";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+               };
+
+               ufs_0_phy: phy@17e04000 {
                        compatible = "samsung,exynosautov9-ufs-phy";
                        reg = <0x17e04000 0xc00>;
                        reg-names = "phy-pma";
                        status = "disabled";
                };
 
-               ufs_0: ufs0@17e00000 {
-                       compatible ="samsung,exynosautov9-ufs";
+               ufs_0: ufs@17e00000 {
+                       compatible = "samsung,exynosautov9-ufs";
 
-                       reg = <0x17e00000 0x100>,  /* 0: HCI standard */
-                               <0x17e01100 0x410>,  /* 1: Vendor-specific */
-                               <0x17e80000 0x8000>,  /* 2: UNIPRO */
-                               <0x17dc0000 0x2200>;  /* 3: UFS protector */
+                       reg = <0x17e00000 0x100>,
+                             <0x17e01100 0x410>,
+                             <0x17e80000 0x8000>,
+                             <0x17dc0000 0x2200>;
                        reg-names = "hci", "vs_hci", "unipro", "ufsp";
                        interrupts = <GIC_SPI 227 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cmu_fsys2 CLK_GOUT_FSYS2_UFS_EMBD0_ACLK>,
                        samsung,sysreg = <&syscon_fsys2 0x710>;
                        status = "disabled";
                };
+
+               ufs_1_phy: phy@17f04000 {
+                       compatible = "samsung,exynosautov9-ufs-phy";
+                       reg = <0x17f04000 0xc00>;
+                       reg-names = "phy-pma";
+                       samsung,pmu-syscon = <&pmu_system_controller 0x72c>;
+                       #phy-cells = <0>;
+                       clocks = <&xtcxo>;
+                       clock-names = "ref_clk";
+                       status = "disabled";
+               };
+
+               ufs_1: ufs@17f00000 {
+                       compatible = "samsung,exynosautov9-ufs";
+
+                       reg = <0x17f00000 0x100>,
+                             <0x17f01100 0x410>,
+                             <0x17f80000 0x8000>,
+                             <0x17de0000 0x2200>;
+                       reg-names = "hci", "vs_hci", "unipro", "ufsp";
+                       interrupts = <GIC_SPI 235 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cmu_fsys2 CLK_GOUT_FSYS2_UFS_EMBD1_ACLK>,
+                                <&cmu_fsys2 CLK_GOUT_FSYS2_UFS_EMBD1_UNIPRO>;
+                       clock-names = "core_clk", "sclk_unipro_main";
+                       freq-table-hz = <0 0>, <0 0>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&ufs_rst_n_1 &ufs_refclk_out_1>;
+                       phys = <&ufs_1_phy>;
+                       phy-names = "ufs-phy";
+                       samsung,sysreg = <&syscon_fsys2 0x714>;
+                       status = "disabled";
+               };
+
+               watchdog_cl0: watchdog@10050000 {
+                       compatible = "samsung,exynosautov9-wdt";
+                       reg = <0x10050000 0x100>;
+                       interrupts = <GIC_SPI 476 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cmu_peris CLK_GOUT_WDT_CLUSTER0>, <&xtcxo>;
+                       clock-names = "watchdog", "watchdog_src";
+                       samsung,syscon-phandle = <&pmu_system_controller>;
+                       samsung,cluster-index = <0>;
+               };
+
+               watchdog_cl1: watchdog@10060000 {
+                       compatible = "samsung,exynosautov9-wdt";
+                       reg = <0x10060000 0x100>;
+                       interrupts = <GIC_SPI 475 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cmu_peris CLK_GOUT_WDT_CLUSTER1>, <&xtcxo>;
+                       clock-names = "watchdog", "watchdog_src";
+                       samsung,syscon-phandle = <&pmu_system_controller>;
+                       samsung,cluster-index = <1>;
+               };
        };
 };
 
index 238a83e..8bf7f7e 100644 (file)
@@ -58,6 +58,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mm-icore-mx8mm-edimm2.2.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-kontron-n801x-s.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-mx8menlo.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-nitrogen-r2.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-phyboard-polis-rdk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-tqma8mqml-mba8mx.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-var-som-symphony.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mm-venice-gw71xx-0x.dtb
@@ -79,9 +80,11 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mn-ddr4-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-tqma8mqnl-mba8mx.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-var-som-symphony.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mn-venice-gw7902.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-dhcom-pdk2.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-icore-mx8mp-edimm2.2.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-phyboard-pollux-rdk.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-tqma8mpql-mba8mpxl.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-venice-gw74xx.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-nonwifi-dahlia.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-nonwifi-dev.dtb
@@ -107,6 +110,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8qxp-ai_ml.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8qxp-colibri-eval-v3.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8qxp-mek.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8ulp-evk.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx93-11x11-evk.dtb
 
 imx8mm-venice-gw72xx-0x-imx219-dtbs    := imx8mm-venice-gw73xx-0x.dtb imx8mm-venice-gw73xx-0x-imx219.dtbo
 imx8mm-venice-gw72xx-0x-rs232-rts-dtbs := imx8mm-venice-gw72xx-0x.dtb imx8mm-venice-gw72xx-0x-rs232-rts.dtbo
index e22c5e7..5a8d85a 100644 (file)
@@ -69,7 +69,7 @@
        flash@0 {
                #address-cells = <1>;
                #size-cells = <1>;
-               compatible = "n25q128a11", "jedec,spi-nor";
+               compatible = "micron,n25q128a11", "jedec,spi-nor";
                reg = <0>;
                spi-max-frequency = <10000000>;
        };
index 50a72cd..a863022 100644 (file)
                                compatible = "fsl,sec-v5.4-job-ring",
                                             "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg        = <0x10000 0x10000>;
+                               reg = <0x10000 0x10000>;
                                interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
                        };
 
                                compatible = "fsl,sec-v5.4-job-ring",
                                             "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg        = <0x20000 0x10000>;
+                               reg = <0x20000 0x10000>;
                                interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
                        };
 
                                compatible = "fsl,sec-v5.4-job-ring",
                                             "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg        = <0x30000 0x10000>;
+                               reg = <0x30000 0x10000>;
                                interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
                        };
 
                                compatible = "fsl,sec-v5.4-job-ring",
                                             "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg        = <0x40000 0x10000>;
+                               reg = <0x40000 0x10000>;
                                interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
                        };
 
                        };
                };
 
+               sfp: efuse@1e80000 {
+                       compatible = "fsl,ls1021a-sfp";
+                       reg = <0x0 0x1e80000 0x0 0x10000>;
+                       clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+                                           QORIQ_CLK_PLL_DIV(4)>;
+                       clock-names = "sfp";
+               };
+
                sec_mon: sec_mon@1e90000 {
                        compatible = "fsl,sec-v5.4-mon", "fsl,sec-v5.0-mon",
                                     "fsl,sec-v4.0-mon";
                        status = "disabled";
                };
 
-               edma0: edma@2c00000 {
+               edma0: dma-controller@2c00000 {
                        #dma-cells = <2>;
                        compatible = "fsl,vf610-edma";
                        reg = <0x0 0x2c00000 0x0 0x10000>,
index 5baf060..0bb2f28 100644 (file)
@@ -93,7 +93,7 @@
                compatible = "mdio-mux-multiplexer";
                mux-controls = <&mux 0>;
                mdio-parent-bus = <&enetc_mdio_pf3>;
-               #address-cells=<1>;
+               #address-cells = <1>;
                #size-cells = <0>;
 
                /* on-board RGMII PHY */
index 92465f7..5627dd7 100644 (file)
@@ -96,7 +96,7 @@
        };
 
        reboot {
-               compatible ="syscon-reboot";
+               compatible = "syscon-reboot";
                regmap = <&rst>;
                offset = <0>;
                mask = <0x02>;
        };
 
        gic: interrupt-controller@6000000 {
-               compatible= "arm,gic-v3";
+               compatible = "arm,gic-v3";
                #address-cells = <2>;
                #size-cells = <2>;
                ranges;
-               reg= <0x0 0x06000000 0 0x10000>, /* GIC Dist */
+               reg = <0x0 0x06000000 0 0x10000>, /* GIC Dist */
                        <0x0 0x06040000 0 0x40000>; /* GIC Redistributor */
-               #interrupt-cells= <3>;
+               #interrupt-cells = <3>;
                interrupt-controller;
                interrupts = <GIC_PPI 9 (GIC_CPU_MASK_RAW(0xf) |
                                         IRQ_TYPE_LEVEL_LOW)>;
                        little-endian;
                };
 
-               efuse@1e80000 {
+               sfp: efuse@1e80000 {
                        compatible = "fsl,ls1028a-sfp";
                        reg = <0x0 0x1e80000 0x0 0x10000>;
+                       clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+                                           QORIQ_CLK_PLL_DIV(4)>;
+                       clock-names = "sfp";
                        #address-cells = <1>;
                        #size-cells = <1>;
 
                        sec_jr0: jr@10000 {
                                compatible = "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg     = <0x10000 0x10000>;
+                               reg = <0x10000 0x10000>;
                                interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
                        };
 
                        sec_jr1: jr@20000 {
                                compatible = "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg     = <0x20000 0x10000>;
+                               reg = <0x20000 0x10000>;
                                interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
                        };
 
                        sec_jr2: jr@30000 {
                                compatible = "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg     = <0x30000 0x10000>;
+                               reg = <0x30000 0x10000>;
                                interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>;
                        };
 
                        sec_jr3: jr@40000 {
                                compatible = "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg     = <0x40000 0x10000>;
+                               reg = <0x40000 0x10000>;
                                interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
                        };
                };
index 21200cb..ca3d5a9 100644 (file)
        };
 
        reboot {
-               compatible ="syscon-reboot";
+               compatible = "syscon-reboot";
                regmap = <&dcfg>;
                offset = <0xb0>;
                mask = <0x02>;
                                compatible = "fsl,sec-v5.4-job-ring",
                                             "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg        = <0x10000 0x10000>;
+                               reg = <0x10000 0x10000>;
                                interrupts = <0 71 0x4>;
                        };
 
                                compatible = "fsl,sec-v5.4-job-ring",
                                             "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg        = <0x20000 0x10000>;
+                               reg = <0x20000 0x10000>;
                                interrupts = <0 72 0x4>;
                        };
 
                                compatible = "fsl,sec-v5.4-job-ring",
                                             "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg        = <0x30000 0x10000>;
+                               reg = <0x30000 0x10000>;
                                interrupts = <0 73 0x4>;
                        };
 
                                compatible = "fsl,sec-v5.4-job-ring",
                                             "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg        = <0x40000 0x10000>;
+                               reg = <0x40000 0x10000>;
                                interrupts = <0 74 0x4>;
                        };
                };
 
+               sfp: efuse@1e80000 {
+                       compatible = "fsl,ls1021a-sfp";
+                       reg = <0x0 0x1e80000 0x0 0x10000>;
+                       clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+                                           QORIQ_CLK_PLL_DIV(4)>;
+                       clock-names = "sfp";
+               };
+
                dcfg: dcfg@1ee0000 {
                        compatible = "fsl,ls1043a-dcfg", "syscon";
                        reg = <0x0 0x1ee0000 0x0 0x10000>;
                        big-endian;
                };
 
-               edma0: edma@2c00000 {
+               edma0: dma-controller@2c00000 {
                        #dma-cells = <2>;
                        compatible = "fsl,vf610-edma";
                        reg = <0x0 0x2c00000 0x0 0x10000>,
index 0085e83..feab604 100644 (file)
        };
 
        reboot {
-               compatible ="syscon-reboot";
+               compatible = "syscon-reboot";
                regmap = <&dcfg>;
                offset = <0xb0>;
                mask = <0x02>;
                                compatible = "fsl,sec-v5.4-job-ring",
                                             "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg        = <0x10000 0x10000>;
+                               reg = <0x10000 0x10000>;
                                interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
                        };
 
                                compatible = "fsl,sec-v5.4-job-ring",
                                             "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg        = <0x20000 0x10000>;
+                               reg = <0x20000 0x10000>;
                                interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
                        };
 
                                compatible = "fsl,sec-v5.4-job-ring",
                                             "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg        = <0x30000 0x10000>;
+                               reg = <0x30000 0x10000>;
                                interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
                        };
 
                                compatible = "fsl,sec-v5.4-job-ring",
                                             "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg        = <0x40000 0x10000>;
+                               reg = <0x40000 0x10000>;
                                interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
                        };
                };
                        ranges = <0x0 0x5 0x08000000 0x8000000>;
                };
 
+               sfp: efuse@1e80000 {
+                       compatible = "fsl,ls1021a-sfp";
+                       reg = <0x0 0x1e80000 0x0 0x10000>;
+                       clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+                                           QORIQ_CLK_PLL_DIV(4)>;
+                       clock-names = "sfp";
+               };
+
                dcfg: dcfg@1ee0000 {
                        compatible = "fsl,ls1046a-dcfg", "syscon";
                        reg = <0x0 0x1ee0000 0x0 0x1000>;
                        big-endian;
                };
 
-               edma0: edma@2c00000 {
+               edma0: dma-controller@2c00000 {
                        #dma-cells = <2>;
                        compatible = "fsl,vf610-edma";
                        reg = <0x0 0x2c00000 0x0 0x10000>,
index d3f03dc..ef6c896 100644 (file)
                 * external power off (e.g ATX Power Button)
                 * asserted
                 */
-               powerdn {
+               button-powerdn {
                        label = "External Power Down";
                        gpios = <&gpio1 17 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
                };
 
                /* Rear Panel 'ADMIN' button (GPIO_H) */
-               admin {
+               button-admin {
                        label = "ADMIN button";
                        gpios = <&gpio3 8 GPIO_ACTIVE_HIGH>;
                        linux,code = <KEY_WPS_BUTTON>;
        leds {
                compatible = "gpio-leds";
 
-               sfp1down {
+               led-0 {
                        label = "ten64:green:sfp1:down";
                        gpios = <&gpio3 11 GPIO_ACTIVE_HIGH>;
                };
 
-               sfp2up {
+               led-1 {
                        label = "ten64:green:sfp2:up";
                        gpios = <&gpio3 12 GPIO_ACTIVE_HIGH>;
                };
 
-               admin {
+               led-2 {
                        label = "ten64:admin";
                        gpios = <&sfpgpio 12 GPIO_ACTIVE_HIGH>;
                };
index f476b7d..421d879 100644 (file)
                        };
                };
 
+               sfp: efuse@1e80000 {
+                       compatible = "fsl,ls1028a-sfp";
+                       reg = <0x0 0x1e80000 0x0 0x10000>;
+                       clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+                                           QORIQ_CLK_PLL_DIV(4)>;
+                       clock-names = "sfp";
+               };
+
                tmu: tmu@1f80000 {
                        compatible = "fsl,qoriq-tmu";
                        reg = <0x0 0x1f80000 0x0 0x10000>;
                        sec_jr0: jr@10000 {
                                compatible = "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg        = <0x10000 0x10000>;
+                               reg = <0x10000 0x10000>;
                                interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
                        };
 
                        sec_jr1: jr@20000 {
                                compatible = "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg        = <0x20000 0x10000>;
+                               reg = <0x20000 0x10000>;
                                interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
                        };
 
                        sec_jr2: jr@30000 {
                                compatible = "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg        = <0x30000 0x10000>;
+                               reg = <0x30000 0x10000>;
                                interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>;
                        };
 
                        sec_jr3: jr@40000 {
                                compatible = "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg        = <0x40000 0x10000>;
+                               reg = <0x40000 0x10000>;
                                interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
                        };
                };
index 4ba1e04..d76f1c4 100644 (file)
@@ -73,7 +73,7 @@
        };
 
        reboot {
-               compatible ="syscon-reboot";
+               compatible = "syscon-reboot";
                regmap = <&rstcr>;
                offset = <0x0>;
                mask = <0x2>;
                        little-endian;
                };
 
+               sfp: efuse@1e80000 {
+                       compatible = "fsl,ls1028a-sfp";
+                       reg = <0x0 0x1e80000 0x0 0x10000>;
+                       clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+                                           QORIQ_CLK_PLL_DIV(4)>;
+                       clock-names = "sfp";
+               };
+
                isc: syscon@1f70000 {
                        compatible = "fsl,ls2080a-isc", "syscon";
                        reg = <0x0 0x1f70000 0x0 0x10000>;
                        sec_jr0: jr@10000 {
                                compatible = "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg        = <0x10000 0x10000>;
+                               reg = <0x10000 0x10000>;
                                interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
                        };
 
                        sec_jr1: jr@20000 {
                                compatible = "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg        = <0x20000 0x10000>;
+                               reg = <0x20000 0x10000>;
                                interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
                        };
 
                        sec_jr2: jr@30000 {
                                compatible = "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg        = <0x30000 0x10000>;
+                               reg = <0x30000 0x10000>;
                                interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>;
                        };
 
                        sec_jr3: jr@40000 {
                                compatible = "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg        = <0x40000 0x10000>;
+                               reg = <0x40000 0x10000>;
                                interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
                        };
                };
index 2ecfa90..4d72119 100644 (file)
@@ -36,7 +36,7 @@
                compatible = "mdio-mux-multiplexer";
                mux-controls = <&mux 0>;
                mdio-parent-bus = <&emdio1>;
-               #address-cells=<1>;
+               #address-cells = <1>;
                #size-cells = <0>;
 
                mdio@0 { /* On-board PHY #1 RGMI1*/
                compatible = "mdio-mux-multiplexer";
                mux-controls = <&mux 1>;
                mdio-parent-bus = <&emdio2>;
-               #address-cells=<1>;
+               #address-cells = <1>;
                #size-cells = <0>;
 
                mdio@0 { /* Slot #1 (secondary EMI) */
index 47ea854..6680fb2 100644 (file)
                        sec_jr0: jr@10000 {
                                compatible = "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg        = <0x10000 0x10000>;
+                               reg = <0x10000 0x10000>;
                                interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
                        };
 
                        sec_jr1: jr@20000 {
                                compatible = "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg        = <0x20000 0x10000>;
+                               reg = <0x20000 0x10000>;
                                interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
                        };
 
                        sec_jr2: jr@30000 {
                                compatible = "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg        = <0x30000 0x10000>;
+                               reg = <0x30000 0x10000>;
                                interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>;
                        };
 
                        sec_jr3: jr@40000 {
                                compatible = "fsl,sec-v5.0-job-ring",
                                             "fsl,sec-v4.0-job-ring";
-                               reg        = <0x40000 0x10000>;
+                               reg = <0x40000 0x10000>;
                                interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
                        };
                };
                        little-endian;
                };
 
+               sfp: efuse@1e80000 {
+                       compatible = "fsl,ls1028a-sfp";
+                       reg = <0x0 0x1e80000 0x0 0x10000>;
+                       clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+                                           QORIQ_CLK_PLL_DIV(4)>;
+                       clock-names = "sfp";
+               };
+
                isc: syscon@1f70000 {
                        compatible = "fsl,lx2160a-isc", "syscon";
                        reg = <0x0 0x1f70000 0x0 0x10000>;
index a1644ce..9f5ff1f 100644 (file)
@@ -34,7 +34,7 @@
                compatible = "mdio-mux-multiplexer";
                mux-controls = <&mux 0>;
                mdio-parent-bus = <&emdio1>;
-               #address-cells=<1>;
+               #address-cells = <1>;
                #size-cells = <0>;
 
                mdio@0 { /* On-board RTL8211F PHY #1 RGMII1 */
                compatible = "mdio-mux-multiplexer";
                mux-controls = <&mux 1>;
                mdio-parent-bus = <&emdio2>;
-               #address-cells=<1>;
+               #address-cells = <1>;
                #size-cells = <0>;
 
                mdio@0 { /* Slot #1 (secondary EMI) */
index a79f42a..82a1c44 100644 (file)
@@ -54,7 +54,7 @@ conn_subsys: bus@5b000000 {
                clock-names = "ipg", "per", "ahb";
                power-domains = <&pd IMX_SC_R_SDHC_1>;
                fsl,tuning-start-tap = <20>;
-               fsl,tuning-step= <2>;
+               fsl,tuning-step = <2>;
                status = "disabled";
        };
 
@@ -83,8 +83,8 @@ conn_subsys: bus@5b000000 {
                assigned-clocks = <&clk IMX_SC_R_ENET_0 IMX_SC_PM_CLK_PER>,
                                  <&clk IMX_SC_R_ENET_0 IMX_SC_C_CLKDIV>;
                assigned-clock-rates = <250000000>, <125000000>;
-               fsl,num-tx-queues=<3>;
-               fsl,num-rx-queues=<3>;
+               fsl,num-tx-queues = <3>;
+               fsl,num-rx-queues = <3>;
                power-domains = <&pd IMX_SC_R_ENET_0>;
                status = "disabled";
        };
@@ -103,8 +103,8 @@ conn_subsys: bus@5b000000 {
                assigned-clocks = <&clk IMX_SC_R_ENET_1 IMX_SC_PM_CLK_PER>,
                                  <&clk IMX_SC_R_ENET_1 IMX_SC_C_CLKDIV>;
                assigned-clock-rates = <250000000>, <125000000>;
-               fsl,num-tx-queues=<3>;
-               fsl,num-rx-queues=<3>;
+               fsl,num-tx-queues = <3>;
+               fsl,num-rx-queues = <3>;
                power-domains = <&pd IMX_SC_R_ENET_1>;
                status = "disabled";
        };
index f338a88..03266bd 100644 (file)
 &usbotg1 {
        vbus-supply = <&reg_usbotg1>;
        disable-over-current;
-       dr_mode="otg";
+       dr_mode = "otg";
        status = "okay";
 };
 
 &usbotg2 {
        pinctrl-names = "default";
        disable-over-current;
-       dr_mode="host";
+       dr_mode = "host";
        status = "okay";
 };
 
index c42b966..7d6317d 100644 (file)
                linux,autosuspend-period = <125>;
        };
 
+       audio_codec_bt_sco: audio-codec-bt-sco {
+               compatible = "linux,bt-sco";
+               #sound-dai-cells = <1>;
+       };
+
        wm8524: audio-codec {
                #sound-dai-cells = <0>;
                compatible = "wlf,wm8524";
                wlf,mute-gpios = <&gpio5 21 GPIO_ACTIVE_LOW>;
        };
 
+       sound-bt-sco {
+               compatible = "simple-audio-card";
+               simple-audio-card,name = "bt-sco-audio";
+               simple-audio-card,format = "dsp_a";
+               simple-audio-card,bitclock-inversion;
+               simple-audio-card,frame-master = <&btcpu>;
+               simple-audio-card,bitclock-master = <&btcpu>;
+
+               btcpu: simple-audio-card,cpu {
+                       sound-dai = <&sai2>;
+                       dai-tdm-slot-num = <2>;
+                       dai-tdm-slot-width = <16>;
+               };
+
+               simple-audio-card,codec {
+                       sound-dai = <&audio_codec_bt_sco 1>;
+               };
+       };
+
        sound-wm8524 {
                compatible = "simple-audio-card";
                simple-audio-card,name = "wm8524-audio";
        status = "okay";
 };
 
+&sai2 {
+       #sound-dai-cells = <0>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_sai2>;
+       assigned-clocks = <&clk IMX8MM_CLK_SAI2>;
+       assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL1_OUT>;
+       assigned-clock-rates = <24576000>;
+       status = "okay";
+};
+
 &sai3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_sai3>;
                >;
        };
 
+       pinctrl_sai2: sai2grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SAI2_TXC_SAI2_TX_BCLK      0xd6
+                       MX8MM_IOMUXC_SAI2_TXFS_SAI2_TX_SYNC     0xd6
+                       MX8MM_IOMUXC_SAI2_TXD0_SAI2_TX_DATA0    0xd6
+                       MX8MM_IOMUXC_SAI2_RXD0_SAI2_RX_DATA0    0xd6
+               >;
+       };
+
        pinctrl_sai3: sai3grp {
                fsl,pins = <
                        MX8MM_IOMUXC_SAI3_TXFS_SAI3_TX_SYNC     0xd6
index b40148d..9e6170d 100644 (file)
                        };
 
                        reg_buck1: buck1 {
-                               regulator-min-microvolt =  <400000>;
+                               regulator-min-microvolt = <400000>;
                                regulator-max-microvolt = <1800000>;
                                regulator-always-on;
                                regulator-boot-on;
                        };
 
                        reg_buck2: buck2 {
-                               regulator-min-microvolt =  <400000>;
+                               regulator-min-microvolt = <400000>;
                                regulator-max-microvolt = <1800000>;
                                regulator-always-on;
                                regulator-boot-on;
                        };
 
                        reg_buck3: buck3 {
-                               regulator-min-microvolt =  <400000>;
+                               regulator-min-microvolt = <400000>;
                                regulator-max-microvolt = <1800000>;
                                regulator-always-on;
                                regulator-boot-on;
                        };
 
                        reg_buck4: buck4 {
-                               regulator-min-microvolt =  <400000>;
+                               regulator-min-microvolt = <400000>;
                                regulator-max-microvolt = <1800000>;
                                regulator-always-on;
                                regulator-boot-on;
                        };
 
                        reg_buck5: buck5 {
-                               regulator-min-microvolt =  <400000>;
+                               regulator-min-microvolt = <400000>;
                                regulator-max-microvolt = <1800000>;
                                regulator-always-on;
                                regulator-boot-on;
                        };
 
                        reg_buck6: buck6 {
-                               regulator-min-microvolt =  <400000>;
+                               regulator-min-microvolt = <400000>;
                                regulator-max-microvolt = <1800000>;
                                regulator-always-on;
                                regulator-boot-on;
index 92eaf4e..c97f4e0 100644 (file)
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_led>;
 
-               user1 {
+               led-1 {
                        label = "TestLed601";
                        gpios = <&gpio4 18 GPIO_ACTIVE_HIGH>;
                        linux,default-trigger = "mmc0";
                };
 
-               user2 {
+               led-2 {
                        label = "TestLed602";
                        gpios = <&gpio4 10 GPIO_ACTIVE_HIGH>;
                        linux,default-trigger = "heartbeat";
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-phyboard-polis-rdk.dts b/arch/arm64/boot/dts/freescale/imx8mm-phyboard-polis-rdk.dts
new file mode 100644 (file)
index 0000000..4a3df2b
--- /dev/null
@@ -0,0 +1,450 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022 PHYTEC Messtechnik GmbH
+ * Author: Teresa Remmet <t.remmet@phytec.de>
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/phy/phy-imx8-pcie.h>
+#include "imx8mm-phycore-som.dtsi"
+
+/ {
+       model = "PHYTEC phyBOARD-Polis-i.MX8MM RDK";
+       compatible = "phytec,imx8mm-phyboard-polis-rdk",
+                    "phytec,imx8mm-phycore-som", "fsl,imx8mm";
+
+       chosen {
+               stdout-path = &uart3;
+       };
+
+       bt_osc_32k: bt-lp-clock {
+               compatible = "fixed-clock";
+               clock-frequency = <32768>;
+               clock-output-names = "bt_osc_32k";
+               #clock-cells = <0>;
+       };
+
+       can_osc_40m: can-clock {
+               compatible = "fixed-clock";
+               clock-frequency = <40000000>;
+               clock-output-names = "can_osc_40m";
+               #clock-cells = <0>;
+       };
+
+       fan {
+               compatible = "gpio-fan";
+               gpios = <&gpio4 8 GPIO_ACTIVE_HIGH>;
+               gpio-fan,speed-map = <0     0
+                                     13000 1>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_fan>;
+               #cooling-cells = <2>;
+       };
+
+       leds {
+               compatible = "gpio-leds";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_leds>;
+
+               led-0 {
+                       color = <LED_COLOR_ID_RED>;
+                       function = LED_FUNCTION_DISK;
+                       gpios = <&gpio1 1 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "mmc2";
+               };
+
+               led-1 {
+                       color = <LED_COLOR_ID_BLUE>;
+                       function = LED_FUNCTION_DISK;
+                       gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "mmc1";
+               };
+
+               led-2 {
+                       color = <LED_COLOR_ID_GREEN>;
+                       function = LED_FUNCTION_CPU;
+                       gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "heartbeat";
+               };
+       };
+
+       usdhc1_pwrseq: pwr-seq {
+               compatible = "mmc-pwrseq-simple";
+               post-power-on-delay-ms = <100>;
+               power-off-delay-us = <60>;
+               reset-gpios = <&gpio2 7 GPIO_ACTIVE_LOW>;
+       };
+
+       reg_can_en: regulator-can-en {
+               compatible = "regulator-fixed";
+               gpio = <&gpio1 9 GPIO_ACTIVE_LOW>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_can_en>;
+               regulator-max-microvolt = <3300000>;
+               regulator-min-microvolt = <3300000>;
+               regulator-name = "CAN_EN";
+               startup-delay-us = <20>;
+       };
+
+       reg_usb_otg1_vbus: regulator-usb-otg1 {
+               compatible = "regulator-fixed";
+               gpio = <&gpio1 12 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_usbotg1pwrgrp>;
+               regulator-name = "usb_otg1_vbus";
+               regulator-max-microvolt = <5000000>;
+               regulator-min-microvolt = <5000000>;
+       };
+
+       reg_usdhc2_vmmc: regulator-usdhc2 {
+               compatible = "regulator-fixed";
+               gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               off-on-delay-us = <20000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
+               regulator-max-microvolt = <3300000>;
+               regulator-min-microvolt = <3300000>;
+               regulator-name = "VSD_3V3";
+       };
+
+       reg_vcc_3v3: regulator-vcc-3v3 {
+               compatible = "regulator-fixed";
+               regulator-max-microvolt = <3300000>;
+               regulator-min-microvolt = <3300000>;
+               regulator-name = "VCC_3V3";
+       };
+};
+
+/* SPI - CAN MCP251XFD */
+&ecspi1 {
+       cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi1>;
+       status = "okay";
+
+       can0: can@0 {
+               compatible = "microchip,mcp251xfd";
+               clocks = <&can_osc_40m>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <8 IRQ_TYPE_LEVEL_LOW>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_can_int>;
+               reg = <0>;
+               spi-max-frequency = <20000000>;
+               xceiver-supply = <&reg_can_en>;
+       };
+};
+
+&gpio1 {
+       gpio-line-names = "nINT_ETHPHY", "LED_RED", "WDOG_INT", "X_RTC_INT",
+               "", "", "", "RESET_ETHPHY",
+               "CAN_nINT", "CAN_EN", "nENABLE_FLATLINK", "",
+               "USB_OTG_VBUS_EN", "", "LED_GREEN", "LED_BLUE";
+};
+
+&gpio2 {
+       gpio-line-names = "", "", "", "",
+               "", "", "BT_REG_ON", "WL_REG_ON",
+               "BT_DEV_WAKE", "BT_HOST_WAKE", "", "",
+               "X_SD2_CD_B", "", "", "",
+               "", "", "", "SD2_RESET_B";
+};
+
+&gpio4 {
+       gpio-line-names = "", "", "", "",
+               "", "", "", "",
+               "FAN", "miniPCIe_nPERST", "", "",
+               "COEX1", "COEX2";
+};
+
+&gpio5 {
+       gpio-line-names = "", "", "", "",
+               "", "", "", "",
+               "", "ECSPI1_SS0";
+};
+
+/* PCIe */
+&pcie0 {
+       assigned-clocks = <&clk IMX8MM_CLK_PCIE1_AUX>,
+                         <&clk IMX8MM_CLK_PCIE1_CTRL>;
+       assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_50M>,
+                                <&clk IMX8MM_SYS_PLL2_250M>;
+       assigned-clock-rates = <10000000>, <250000000>;
+       clocks = <&clk IMX8MM_CLK_PCIE1_ROOT>, <&clk IMX8MM_CLK_PCIE1_AUX>,
+                <&clk IMX8MM_CLK_PCIE1_PHY>;
+       clock-names = "pcie", "pcie_aux", "pcie_bus";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pcie>;
+       reset-gpio = <&gpio4 9 GPIO_ACTIVE_LOW>;
+       status = "okay";
+};
+
+&pcie_phy {
+       clocks = <&clk IMX8MM_CLK_PCIE1_PHY>;
+       fsl,clkreq-unsupported;
+       fsl,refclk-pad-mode = <IMX8_PCIE_REFCLK_PAD_OUTPUT>;
+       fsl,tx-deemph-gen1 = <0x2d>;
+       fsl,tx-deemph-gen2 = <0xf>;
+       status = "okay";
+};
+
+&rv3028 {
+       trickle-resistor-ohms = <3000>;
+};
+
+&snvs_pwrkey {
+       status = "okay";
+};
+
+/* UART - RS232/RS485 */
+&uart1 {
+       assigned-clocks = <&clk IMX8MM_CLK_UART1>;
+       assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_80M>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1>;
+       uart-has-rtscts;
+       status = "okay";
+};
+
+/* UART - Sterling-LWB Bluetooth */
+&uart2 {
+       assigned-clocks = <&clk IMX8MM_CLK_UART2>;
+       assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_80M>;
+       fsl,dte-mode;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart2_bt>;
+       uart-has-rtscts;
+       status = "okay";
+
+       bluetooth {
+               compatible = "brcm,bcm43438-bt";
+               clocks = <&bt_osc_32k>;
+               clock-names = "lpo";
+               device-wakeup-gpios = <&gpio2 8 GPIO_ACTIVE_HIGH>;
+               interrupt-names = "host-wakeup";
+               interrupt-parent = <&gpio2>;
+               interrupts = <9 IRQ_TYPE_EDGE_BOTH>;
+               max-speed = <2000000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_bt>;
+               shutdown-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>;
+               vddio-supply = <&reg_vcc_3v3>;
+       };
+};
+
+/* UART - console */
+&uart3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart3>;
+       status = "okay";
+};
+
+/* USB */
+&usbotg1 {
+       adp-disable;
+       dr_mode = "otg";
+       over-current-active-low;
+       samsung,picophy-pre-emp-curr-control = <3>;
+       samsung,picophy-dc-vol-level-adjust = <7>;
+       srp-disable;
+       vbus-supply = <&reg_usb_otg1_vbus>;
+       status = "okay";
+};
+
+&usbotg2 {
+       disable-over-current;
+       dr_mode = "host";
+       samsung,picophy-pre-emp-curr-control = <3>;
+       samsung,picophy-dc-vol-level-adjust = <7>;
+       status = "okay";
+};
+
+/* SDIO - Sterling-LWB Wifi */
+&usdhc1 {
+       assigned-clocks = <&clk IMX8MM_CLK_USDHC1>;
+       assigned-clock-rates = <200000000>;
+       bus-width = <4>;
+       mmc-pwrseq = <&usdhc1_pwrseq>;
+       non-removable;
+       no-1-8-v;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usdhc1>, <&pinctrl_wlan>;
+       #address-cells = <1>;
+       #size-cells = <0>;
+       status = "okay";
+
+       brcmf: wifi@1 {
+               compatible = "brcm,bcm4329-fmac";
+               reg = <1>;
+       };
+};
+
+/* SD-Card */
+&usdhc2 {
+       assigned-clocks = <&clk IMX8MM_CLK_USDHC2>;
+       assigned-clock-rates = <200000000>;
+       bus-width = <4>;
+       cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>;
+       disable-wp;
+       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_vmmc>;
+       vqmmc-supply = <&reg_nvcc_sd2>;
+       status = "okay";
+};
+
+&iomuxc {
+       pinctrl_bt: btgrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SD1_DATA4_GPIO2_IO6        0x00
+                       MX8MM_IOMUXC_SD1_DATA6_GPIO2_IO8        0x00
+                       MX8MM_IOMUXC_SD1_DATA7_GPIO2_IO9        0x00
+               >;
+       };
+
+       pinctrl_can_en: can-engrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_GPIO1_IO09_GPIO1_IO9       0x00
+               >;
+       };
+
+       pinctrl_can_int: can-intgrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_GPIO1_IO08_GPIO1_IO8       0x00
+               >;
+       };
+
+       pinctrl_ecspi1: ecspi1grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_ECSPI1_MISO_ECSPI1_MISO    0x80
+                       MX8MM_IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI    0x80
+                       MX8MM_IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK    0x80
+                       MX8MM_IOMUXC_ECSPI1_SS0_GPIO5_IO9       0x00
+               >;
+       };
+
+       pinctrl_fan: fan0grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SAI1_RXD6_GPIO4_IO8        0x16
+               >;
+       };
+
+       pinctrl_leds: leds1grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_GPIO1_IO01_GPIO1_IO1       0x16
+                       MX8MM_IOMUXC_GPIO1_IO14_GPIO1_IO14      0x16
+                       MX8MM_IOMUXC_GPIO1_IO15_GPIO1_IO15      0x16
+               >;
+       };
+
+       pinctrl_pcie: pciegrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SAI1_RXD7_GPIO4_IO9        0x00
+                       MX8MM_IOMUXC_SAI1_TXD0_GPIO4_IO12       0x12
+                       MX8MM_IOMUXC_SAI1_TXD7_GPIO4_IO19       0x12
+               >;
+       };
+
+       pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SD2_RESET_B_GPIO2_IO19     0x40
+               >;
+       };
+
+       pinctrl_uart1: uart1grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SAI2_RXC_UART1_DCE_RX      0x00
+                       MX8MM_IOMUXC_SAI2_RXD0_UART1_DCE_RTS_B  0x00
+                       MX8MM_IOMUXC_SAI2_RXFS_UART1_DCE_TX     0x00
+                       MX8MM_IOMUXC_SAI2_TXFS_UART1_DCE_CTS_B  0x00
+               >;
+       };
+
+       pinctrl_uart2_bt: uart2btgrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SAI3_RXC_UART2_DTE_RTS_B   0x00
+                       MX8MM_IOMUXC_SAI3_RXD_UART2_DTE_CTS_B   0x00
+                       MX8MM_IOMUXC_SAI3_TXC_UART2_DTE_RX      0x00
+                       MX8MM_IOMUXC_SAI3_TXFS_UART2_DTE_TX     0x00
+               >;
+       };
+
+       pinctrl_uart3: uart3grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_UART3_RXD_UART3_DCE_RX     0x40
+                       MX8MM_IOMUXC_UART3_TXD_UART3_DCE_TX     0x40
+               >;
+       };
+
+       pinctrl_usbotg1pwrgrp: usbotg1pwrgrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_GPIO1_IO12_GPIO1_IO12      0x00
+               >;
+       };
+
+       pinctrl_usdhc1: usdhc1grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SD1_CLK_USDHC1_CLK         0x182
+                       MX8MM_IOMUXC_SD1_CMD_USDHC1_CMD         0xc6
+                       MX8MM_IOMUXC_SD1_DATA0_USDHC1_DATA0     0xc6
+                       MX8MM_IOMUXC_SD1_DATA1_USDHC1_DATA1     0xc6
+                       MX8MM_IOMUXC_SD1_DATA2_USDHC1_DATA2     0xc6
+                       MX8MM_IOMUXC_SD1_DATA3_USDHC1_DATA3     0xc6
+               >;
+       };
+
+       pinctrl_usdhc2_gpio: usdhc2gpiogrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12        0x40
+               >;
+       };
+
+       pinctrl_usdhc2: usdhc2grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT  0x1d0
+                       MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK         0x192
+                       MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD         0x1d2
+                       MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0     0x1d2
+                       MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1     0x1d2
+                       MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2     0x1d2
+                       MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3     0x1d2
+               >;
+       };
+
+       pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT  0x1d0
+                       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
+               >;
+       };
+
+       pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT  0x1d0
+                       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
+               >;
+       };
+
+       pinctrl_wlan: wlangrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_SD1_DATA5_GPIO2_IO7        0x00
+               >;
+       };
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-phycore-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-phycore-som.dtsi
new file mode 100644 (file)
index 0000000..995b44e
--- /dev/null
@@ -0,0 +1,440 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022 PHYTEC Messtechnik GmbH
+ * Author: Teresa Remmet <t.remmet@phytec.de>
+ */
+
+#include "imx8mm.dtsi"
+#include <dt-bindings/net/ti-dp83867.h>
+
+/ {
+       model = "PHYTEC phyCORE-i.MX8MM";
+       compatible = "phytec,imx8mm-phycore-som", "fsl,imx8mm";
+
+       aliases {
+               rtc0 = &rv3028;
+               rtc1 = &snvs_rtc;
+       };
+
+       memory@40000000 {
+               device_type = "memory";
+               reg = <0x0 0x40000000 0 0x80000000>;
+       };
+
+       reg_vdd_3v3_s: regulator-vdd-3v3-s {
+               compatible = "regulator-fixed";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-max-microvolt = <3300000>;
+               regulator-min-microvolt = <3300000>;
+               regulator-name = "VDD_3V3_S";
+       };
+};
+
+&A53_0 {
+       cpu-supply = <&reg_vdd_arm>;
+};
+
+&A53_1 {
+       cpu-supply = <&reg_vdd_arm>;
+};
+
+&A53_2 {
+       cpu-supply = <&reg_vdd_arm>;
+};
+
+&A53_3 {
+       cpu-supply = <&reg_vdd_arm>;
+};
+
+&ddrc {
+       operating-points-v2 = <&ddrc_opp_table>;
+
+       ddrc_opp_table: opp-table {
+               compatible = "operating-points-v2";
+
+               opp-25M {
+                       opp-hz = /bits/ 64 <25000000>;
+               };
+
+               opp-100M {
+                       opp-hz = /bits/ 64 <100000000>;
+               };
+
+               opp-750M {
+                       opp-hz = /bits/ 64 <750000000>;
+               };
+       };
+};
+
+/* Ethernet */
+&fec1 {
+       fsl,magic-packet;
+       phy-mode = "rgmii-id";
+       phy-handle = <&ethphy0>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_fec1>;
+       status = "okay";
+
+       mdio {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               ethphy0: ethernet-phy@0 {
+                       compatible = "ethernet-phy-ieee802.3-c22";
+                       enet-phy-lane-no-swap;
+                       ti,clk-output-sel = <DP83867_CLK_O_SEL_OFF>;
+                       ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
+                       ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
+                       ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
+                       reg = <0>;
+                       reset-gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
+                       reset-assert-us = <1000>;
+                       reset-deassert-us = <1000>;
+               };
+       };
+};
+
+/* SPI Flash */
+&flexspi {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_flexspi0>;
+       status = "okay";
+
+       som_flash: flash@0 {
+               compatible = "jedec,spi-nor";
+               reg = <0>;
+               spi-max-frequency = <80000000>;
+               spi-rx-bus-width = <4>;
+               spi-tx-bus-width = <1>;
+       };
+};
+
+&gpio1 {
+       gpio-line-names = "nINT_ETHPHY", "", "WDOG_INT", "X_RTC_INT",
+               "", "", "", "RESET_ETHPHY",
+               "", "", "nENABLE_FLATLINK";
+};
+
+/* I2C1 */
+&i2c1 {
+       clock-frequency = <400000>;
+       pinctrl-names = "default","gpio";
+       pinctrl-0 = <&pinctrl_i2c1>;
+       pinctrl-1 = <&pinctrl_i2c1_gpio>;
+       scl-gpios = <&gpio5 14 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       sda-gpios = <&gpio5 15 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       status = "okay";
+
+       pmic@8 {
+               compatible = "nxp,pf8121a";
+               reg = <0x08>;
+
+               regulators {
+                       reg_nvcc_sd1: ldo1 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-name = "NVCC_SD1 (LDO1)";
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       reg_nvcc_sd2: ldo2 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-name = "NVCC_SD2 (LDO2)";
+                               vselect-en;
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       reg_vcc_enet: ldo3 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <2500000>;
+                               regulator-min-microvolt = <1500000>;
+                               regulator-name = "VCC_ENET_2V5 (LDO3)";
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       reg_vdda_1v8: ldo4 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-min-microvolt = <1500000>;
+                               regulator-name = "VDDA_1V8 (LDO4)";
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-min-microvolt = <1500000>;
+                                       regulator-suspend-max-microvolt = <1500000>;
+                               };
+                       };
+
+                       reg_soc_vdda_phy: buck1 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <900000>;
+                               regulator-min-microvolt = <400000>;
+                               regulator-name = "VDD_SOC_VDDA_PHY_0P8 (BUCK1)";
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-min-microvolt = <400000>;
+                                       regulator-suspend-max-microvolt = <400000>;
+                               };
+                       };
+
+                       reg_vdd_gpu_dram: buck2 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <1000000>;
+                               regulator-min-microvolt = <1000000>;
+                               regulator-name = "VDD_GPU_DRAM (BUCK2)";
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-max-microvolt = <1000000>;
+                                       regulator-suspend-min-microvolt = <1000000>;
+                               };
+                       };
+
+                       reg_vdd_gpu: buck3 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <1000000>;
+                               regulator-min-microvolt = <400000>;
+                               regulator-name = "VDD_VPU (BUCK3)";
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       reg_vdd_mipi: buck4 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <1050000>;
+                               regulator-min-microvolt = <900000>;
+                               regulator-name = "VDD_MIPI_0P9 (BUCK4)";
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       reg_vdd_arm: buck5 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <1050000>;
+                               regulator-min-microvolt = <400000>;
+                               regulator-name = "VDD_ARM (BUCK5)";
+
+                               regulator-state-mem {
+                                       regulator-off-in-suspend;
+                               };
+                       };
+
+                       reg_vdd_1v8: buck6 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-name = "VDD_1V8 (BUCK6)";
+
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-max-microvolt = <1800000>;
+                                       regulator-suspend-min-microvolt = <1800000>;
+                               };
+                       };
+
+                       reg_nvcc_dram: buck7 {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <1100000>;
+                               regulator-min-microvolt = <1100000>;
+                               regulator-name = "NVCC_DRAM_1P1V (BUCK7)";
+                       };
+
+                       reg_vsnvs: vsnvs {
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-name = "NVCC_SNVS_1P8 (VSNVS)";
+                       };
+               };
+       };
+
+       sn65dsi83: bridge@2d {
+               compatible = "ti,sn65dsi83";
+               enable-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_sn65dsi83>;
+               reg = <0x2d>;
+               status = "disabled";
+       };
+
+       eeprom@51 {
+               compatible = "atmel,24c32";
+               pagesize = <32>;
+               reg = <0x51>;
+               vcc-supply = <&reg_vdd_3v3_s>;
+       };
+
+       rv3028: rtc@52 {
+               compatible = "microcrystal,rv3028";
+               interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+               interrupt-parent = <&gpio1>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_rtc>;
+               reg = <0x52>;
+       };
+};
+
+/* EMMC */
+&usdhc3 {
+       assigned-clocks = <&clk IMX8MM_CLK_USDHC3_ROOT>;
+       assigned-clock-rates = <400000000>;
+       bus-width = <8>;
+       keep-power-in-suspend;
+       pinctrl-names = "default", "state_100mhz", "state_200mhz";
+       pinctrl-0 = <&pinctrl_usdhc3>;
+       pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
+       pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
+       non-removable;
+       status = "okay";
+};
+
+/* Watchdog */
+&wdog1 {
+       fsl,ext-reset-output;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_wdog>;
+       status = "okay";
+};
+
+&iomuxc {
+       pinctrl_fec1: fec1grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_ENET_MDC_ENET1_MDC                 0x2
+                       MX8MM_IOMUXC_ENET_MDIO_ENET1_MDIO               0x2
+                       MX8MM_IOMUXC_ENET_RD0_ENET1_RGMII_RD0           0x90
+                       MX8MM_IOMUXC_ENET_RD1_ENET1_RGMII_RD1           0x90
+                       MX8MM_IOMUXC_ENET_RD2_ENET1_RGMII_RD2           0x90
+                       MX8MM_IOMUXC_ENET_RD3_ENET1_RGMII_RD3           0x90
+                       MX8MM_IOMUXC_ENET_RXC_ENET1_RGMII_RXC           0x90
+                       MX8MM_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL     0x90
+                       MX8MM_IOMUXC_ENET_TD0_ENET1_RGMII_TD0           0x16
+                       MX8MM_IOMUXC_ENET_TD1_ENET1_RGMII_TD1           0x16
+                       MX8MM_IOMUXC_ENET_TD2_ENET1_RGMII_TD2           0x16
+                       MX8MM_IOMUXC_ENET_TD3_ENET1_RGMII_TD3           0x16
+                       MX8MM_IOMUXC_ENET_TXC_ENET1_RGMII_TXC           0x16
+                       MX8MM_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL     0x16
+                       MX8MM_IOMUXC_GPIO1_IO07_GPIO1_IO7               0x10
+               >;
+       };
+
+       pinctrl_flexspi0: flexspi0grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_NAND_ALE_QSPI_A_SCLK               0x1c2
+                       MX8MM_IOMUXC_NAND_CE0_B_QSPI_A_SS0_B            0x82
+                       MX8MM_IOMUXC_NAND_DATA00_QSPI_A_DATA0           0x82
+                       MX8MM_IOMUXC_NAND_DATA01_QSPI_A_DATA1           0x82
+                       MX8MM_IOMUXC_NAND_DATA02_QSPI_A_DATA2           0x82
+                       MX8MM_IOMUXC_NAND_DATA03_QSPI_A_DATA3           0x82
+               >;
+       };
+
+       pinctrl_i2c1: i2c1grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA                  0x400001c0
+                       MX8MM_IOMUXC_I2C1_SCL_I2C1_SCL                  0x400001c0
+               >;
+       };
+
+       pinctrl_i2c1_gpio: i2c1gpiogrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_I2C1_SDA_GPIO5_IO15                0x1e0
+                       MX8MM_IOMUXC_I2C1_SCL_GPIO5_IO14                0x1e0
+               >;
+       };
+
+       pinctrl_rtc: rtcgrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3               0x1c0
+               >;
+       };
+
+       pinctrl_sn65dsi83: sn65dsi83grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_GPIO1_IO10_GPIO1_IO10              0x0
+               >;
+       };
+
+       pinctrl_usdhc3: usdhc3grp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7              0x1d0
+                       MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE           0x190
+                       MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5            0x1d0
+                       MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6            0x1d0
+                       MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0           0x1d0
+                       MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1           0x1d0
+                       MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2           0x1d0
+                       MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3           0x1d0
+                       MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4             0x1d0
+                       MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK               0x190
+                       MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD               0x1d0
+               >;
+       };
+
+       pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7              0x1d4
+                       MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE           0x194
+                       MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5            0x1d4
+                       MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6            0x1d4
+                       MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0           0x1d4
+                       MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1           0x1d4
+                       MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2           0x1d4
+                       MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3           0x1d4
+                       MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4             0x1d4
+                       MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK               0x194
+                       MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD               0x1d4
+               >;
+       };
+
+       pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7              0x1d6
+                       MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE           0x196
+                       MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5            0x1d6
+                       MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6            0x1d6
+                       MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0           0x1d6
+                       MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1           0x1d6
+                       MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2           0x1d6
+                       MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3           0x1d6
+                       MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4             0x1d6
+                       MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK               0x196
+                       MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD               0x1d6
+               >;
+       };
+
+       pinctrl_wdog: wdoggrp {
+               fsl,pins = <
+                       MX8MM_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B            0x26
+               >;
+       };
+};
index ac1fe15..d643381 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               back {
+               key-back {
                        label = "Back";
                        gpios = <&pca9534 1 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_BACK>;
                };
 
-               home {
+               key-home {
                        label = "Home";
                        gpios = <&pca9534 2 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_HOME>;
                };
 
-               menu {
+               key-menu {
                        label = "Menu";
                        gpios = <&pca9534 3 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_MENU>;
index 00f86ca..66a0d10 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               user-pb {
+               key-user-pb {
                        label = "user_pb";
                        gpios = <&gpio 2 GPIO_ACTIVE_LOW>;
                        linux,code = <BTN_0>;
                };
 
-               user-pb1x {
+               key-user-pb1x {
                        label = "user_pb1x";
                        linux,code = <BTN_1>;
                        interrupt-parent = <&gsc>;
                        interrupts = <1>;
                };
 
-               eeprom-wp {
+               key-eeprom-wp {
                        label = "eeprom_wp";
                        linux,code = <BTN_3>;
                        interrupt-parent = <&gsc>;
                        interrupts = <2>;
                };
 
-               tamper {
+               key-tamper {
                        label = "tamper";
                        linux,code = <BTN_4>;
                        interrupt-parent = <&gsc>;
                                regulator-name = "buck1";
                                regulator-min-microvolt = <800000>;
                                regulator-max-microvolt = <1000000>;
-                               regulator-min-microamp  = <3800000>;
-                               regulator-max-microamp  = <6800000>;
+                               regulator-min-microamp = <3800000>;
+                               regulator-max-microamp = <6800000>;
                                regulator-boot-on;
                                regulator-always-on;
                        };
                                regulator-name = "buck2";
                                regulator-min-microvolt = <800000>;
                                regulator-max-microvolt = <900000>;
-                               regulator-min-microamp  = <2200000>;
-                               regulator-max-microamp  = <5200000>;
+                               regulator-min-microamp = <2200000>;
+                               regulator-max-microamp = <5200000>;
                                regulator-boot-on;
                                regulator-always-on;
                        };
                                regulator-name = "buck3";
                                regulator-min-microvolt = <800000>;
                                regulator-max-microvolt = <1000000>;
-                               regulator-min-microamp  = <3800000>;
-                               regulator-max-microamp  = <6800000>;
+                               regulator-min-microamp = <3800000>;
+                               regulator-max-microamp = <6800000>;
                                regulator-always-on;
                        };
 
                                regulator-name = "buck4";
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <1800000>;
-                               regulator-min-microamp  = <2200000>;
-                               regulator-max-microamp  = <5200000>;
+                               regulator-min-microamp = <2200000>;
+                               regulator-max-microamp = <5200000>;
                                regulator-boot-on;
                                regulator-always-on;
                        };
index 24737e8..35fb929 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               user-pb {
+               key-user-pb {
                        label = "user_pb";
                        gpios = <&gpio 2 GPIO_ACTIVE_LOW>;
                        linux,code = <BTN_0>;
                };
 
-               user-pb1x {
+               key-user-pb1x {
                        label = "user_pb1x";
                        linux,code = <BTN_1>;
                        interrupt-parent = <&gsc>;
                        interrupts = <1>;
                };
 
-               eeprom-wp {
+               key-eeprom-wp {
                        label = "eeprom_wp";
                        linux,code = <BTN_3>;
                        interrupt-parent = <&gsc>;
                        interrupts = <2>;
                };
 
-               tamper {
+               key-tamper {
                        label = "tamper";
                        linux,code = <BTN_4>;
                        interrupt-parent = <&gsc>;
index 407ab45..6dc5eda 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               user-pb {
+               key-user-pb {
                        label = "user_pb";
                        gpios = <&gpio 2 GPIO_ACTIVE_LOW>;
                        linux,code = <BTN_0>;
                };
 
-               user-pb1x {
+               key-user-pb1x {
                        label = "user_pb1x";
                        linux,code = <BTN_1>;
                        interrupt-parent = <&gsc>;
                        interrupts = <1>;
                };
 
-               eeprom-wp {
+               key-eeprom-wp {
                        label = "eeprom_wp";
                        linux,code = <BTN_3>;
                        interrupt-parent = <&gsc>;
                        interrupts = <2>;
                };
 
-               tamper {
+               key-tamper {
                        label = "tamper";
                        linux,code = <BTN_4>;
                        interrupt-parent = <&gsc>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart1>, <&pinctrl_uart1_gpio>;
        rts-gpios = <&gpio4 10 GPIO_ACTIVE_LOW>;
-       cts-gpios = <&gpio4 11 GPIO_ACTIVE_LOW>;
+       cts-gpios = <&gpio4 24 GPIO_ACTIVE_LOW>;
        uart-has-rtscts;
        status = "okay";
 };
index a7dae9b..a65761a 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               user-pb {
+               key-user-pb {
                        label = "user_pb";
                        gpios = <&gpio 2 GPIO_ACTIVE_LOW>;
                        linux,code = <BTN_0>;
                };
 
-               user-pb1x {
+               key-user-pb1x {
                        label = "user_pb1x";
                        linux,code = <BTN_1>;
                        interrupt-parent = <&gsc>;
@@ -53,7 +53,7 @@
                        interrupts = <1>;
                };
 
-               eeprom-wp {
+               key-eeprom-wp {
                        label = "eeprom_wp";
                        linux,code = <BTN_3>;
                        interrupt-parent = <&gsc>;
index eafa88d..d1b4582 100644 (file)
@@ -43,7 +43,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_gpio_keys>;
 
-               wakeup {
+               key-wakeup {
                        debounce-interval = <10>;
                        /* Verdin CTRL_WAKE1_MICO# (SODIMM 252) */
                        gpios = <&gpio4 28 GPIO_ACTIVE_LOW>;
        cpu-supply = <&reg_vdd_arm>;
 };
 
+&cpu_alert0 {
+       temperature = <95000>;
+};
+
+&cpu_crit0 {
+       temperature = <105000>;
+};
+
 &ddrc {
        operating-points-v2 = <&ddrc_opp_table>;
 
index 1bf0704..afb90f5 100644 (file)
        clk_ext4: clock-ext4 {
                compatible = "fixed-clock";
                #clock-cells = <0>;
-               clock-frequency= <133000000>;
+               clock-frequency = <133000000>;
                clock-output-names = "clk_ext4";
        };
 
                clock-names = "main_clk";
        };
 
-       soc@0 {
+       soc: soc@0 {
                compatible = "fsl,imx8mm-soc", "simple-bus";
                #address-cells = <1>;
                #size-cells = <1>;
                                        wakeup-source;
                                        status = "disabled";
                                };
+
+                               snvs_lpgpr: snvs-lpgpr {
+                                       compatible = "fsl,imx8mm-snvs-lpgpr",
+                                                    "fsl,imx7d-snvs-lpgpr";
+                               };
                        };
 
                        clk: clock-controller@30380000 {
                                        compatible = "fsl,sec-v4.0-job-ring";
                                        reg = <0x1000 0x1000>;
                                        interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
+                                       status = "disabled";
                                };
 
                                sec_jr1: jr@2000 {
                                         <&clk IMX8MM_CLK_USDHC1_ROOT>;
                                clock-names = "ipg", "ahb", "per";
                                fsl,tuning-start-tap = <20>;
-                               fsl,tuning-step= <2>;
+                               fsl,tuning-step = <2>;
                                bus-width = <4>;
                                status = "disabled";
                        };
                                         <&clk IMX8MM_CLK_USDHC2_ROOT>;
                                clock-names = "ipg", "ahb", "per";
                                fsl,tuning-start-tap = <20>;
-                               fsl,tuning-step= <2>;
+                               fsl,tuning-step = <2>;
                                bus-width = <4>;
                                status = "disabled";
                        };
                                         <&clk IMX8MM_CLK_USDHC3_ROOT>;
                                clock-names = "ipg", "ahb", "per";
                                fsl,tuning-start-tap = <20>;
-                               fsl,tuning-step= <2>;
+                               fsl,tuning-step = <2>;
                                bus-width = <4>;
                                status = "disabled";
                        };
index 02f37dc..9e82069 100644 (file)
 };
 
 &easrc {
-       fsl,asrc-rate  = <48000>;
+       fsl,asrc-rate = <48000>;
        status = "okay";
 };
 
 &usbotg1 {
        vbus-supply = <&reg_usb_otg_vbus>;
        disable-over-current;
-       dr_mode="otg";
+       dr_mode = "otg";
        status = "okay";
 };
 
index d1f6ccc..261c365 100644 (file)
                linux,autosuspend-period = <125>;
        };
 
+       audio_codec_bt_sco: audio-codec-bt-sco {
+               compatible = "linux,bt-sco";
+               #sound-dai-cells = <1>;
+       };
+
        wm8524: audio-codec {
                #sound-dai-cells = <0>;
                compatible = "wlf,wm8524";
                clock-names = "mclk";
        };
 
+       sound-bt-sco {
+               compatible = "simple-audio-card";
+               simple-audio-card,name = "bt-sco-audio";
+               simple-audio-card,format = "dsp_a";
+               simple-audio-card,bitclock-inversion;
+               simple-audio-card,frame-master = <&btcpu>;
+               simple-audio-card,bitclock-master = <&btcpu>;
+
+               btcpu: simple-audio-card,cpu {
+                       sound-dai = <&sai2>;
+                       dai-tdm-slot-num = <2>;
+                       dai-tdm-slot-width = <16>;
+               };
+
+               simple-audio-card,codec {
+                       sound-dai = <&audio_codec_bt_sco 1>;
+               };
+       };
+
        sound-wm8524 {
                compatible = "fsl,imx-audio-wm8524";
                model = "wm8524-audio";
 };
 
 &easrc {
-       fsl,asrc-rate  = <48000>;
+       fsl,asrc-rate = <48000>;
        status = "okay";
 };
 
        };
 };
 
+&sai2 {
+       #sound-dai-cells = <0>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_sai2>;
+       assigned-clocks = <&clk IMX8MN_CLK_SAI2>;
+       assigned-clock-parents = <&clk IMX8MN_AUDIO_PLL1_OUT>;
+       assigned-clock-rates = <24576000>;
+       status = "okay";
+};
+
 &sai3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_sai3>;
                >;
        };
 
+       pinctrl_sai2: sai2grp {
+               fsl,pins = <
+                       MX8MN_IOMUXC_SAI2_TXC_SAI2_TX_BCLK      0xd6
+                       MX8MN_IOMUXC_SAI2_TXFS_SAI2_TX_SYNC     0xd6
+                       MX8MN_IOMUXC_SAI2_TXD0_SAI2_TX_DATA0    0xd6
+                       MX8MN_IOMUXC_SAI2_RXD0_SAI2_RX_DATA0    0xd6
+               >;
+       };
+
        pinctrl_sai3: sai3grp {
                fsl,pins = <
                        MX8MN_IOMUXC_SAI3_TXFS_SAI3_TX_SYNC     0xd6
index f61c487..3ed7021 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               back {
+               key-back {
                        label = "Back";
                        gpios = <&pca9534 1 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_BACK>;
                };
 
-               home {
+               key-home {
                        label = "Home";
                        gpios = <&pca9534 2 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_HOME>;
                };
 
-               menu {
+               key-menu {
                        label = "Menu";
                        gpios = <&pca9534 3 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_MENU>;
index 367a232..636f860 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               user-pb {
+               key-user-pb {
                        label = "user_pb";
                        gpios = <&gpio 2 GPIO_ACTIVE_LOW>;
                        linux,code = <BTN_0>;
                };
 
-               user-pb1x {
+               key-user-pb1x {
                        label = "user_pb1x";
                        linux,code = <BTN_1>;
                        interrupt-parent = <&gsc>;
                        interrupts = <1>;
                };
 
-               eeprom-wp {
+               key-eeprom-wp {
                        label = "eeprom_wp";
                        linux,code = <BTN_3>;
                        interrupt-parent = <&gsc>;
                        interrupts = <2>;
                };
 
-               tamper {
+               key-tamper {
                        label = "tamper";
                        linux,code = <BTN_4>;
                        interrupt-parent = <&gsc>;
index e41e1d5..0c71b74 100644 (file)
        clk_ext4: clock-ext4 {
                compatible = "fixed-clock";
                #clock-cells = <0>;
-               clock-frequency= <133000000>;
+               clock-frequency = <133000000>;
                clock-output-names = "clk_ext4";
        };
 
                arm,no-tick-in-suspend;
        };
 
-       soc@0 {
+       soc: soc@0 {
                compatible = "fsl,imx8mn-soc", "simple-bus";
                #address-cells = <1>;
                #size-cells = <1>;
                                                    "ctx2_rx", "ctx2_tx",
                                                    "ctx3_rx", "ctx3_tx";
                                        firmware-name = "imx/easrc/easrc-imx8mn.bin";
-                                       fsl,asrc-rate  = <8000>;
+                                       fsl,asrc-rate = <8000>;
                                        fsl,asrc-format = <2>;
                                        status = "disabled";
                                };
                                         compatible = "fsl,sec-v4.0-job-ring";
                                         reg = <0x1000 0x1000>;
                                         interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
+                                        status = "disabled";
                                };
 
                                sec_jr1: jr@2000 {
                                         <&clk IMX8MN_CLK_USDHC1_ROOT>;
                                clock-names = "ipg", "ahb", "per";
                                fsl,tuning-start-tap = <20>;
-                               fsl,tuning-step= <2>;
+                               fsl,tuning-step = <2>;
                                bus-width = <4>;
                                status = "disabled";
                        };
                                         <&clk IMX8MN_CLK_USDHC2_ROOT>;
                                clock-names = "ipg", "ahb", "per";
                                fsl,tuning-start-tap = <20>;
-                               fsl,tuning-step= <2>;
+                               fsl,tuning-step = <2>;
                                bus-width = <4>;
                                status = "disabled";
                        };
                                         <&clk IMX8MN_CLK_USDHC3_ROOT>;
                                clock-names = "ipg", "ahb", "per";
                                fsl,tuning-start-tap = <20>;
-                               fsl,tuning-step= <2>;
+                               fsl,tuning-step = <2>;
                                bus-width = <4>;
                                status = "disabled";
                        };
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-pdk2.dts b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-pdk2.dts
new file mode 100644 (file)
index 0000000..2ca2ede
--- /dev/null
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2022 Marek Vasut <marex@denx.de>
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/net/qca-ar803x.h>
+#include <dt-bindings/phy/phy-imx8-pcie.h>
+#include "imx8mp-dhcom-som.dtsi"
+
+/ {
+       model = "DH electronics i.MX8M Plus DHCOM Premium Developer Kit (2)";
+       compatible = "dh,imx8mp-dhcom-pdk2", "fsl,imx8mp";
+
+       chosen {
+               stdout-path = &uart1;
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+
+               button-0 {
+                       gpios = <&gpio1 9 GPIO_ACTIVE_LOW>; /* GPIO A */
+                       label = "TA1-GPIO-A";
+                       linux,code = <KEY_A>;
+                       pinctrl-0 = <&pinctrl_dhcom_a>;
+                       pinctrl-names = "default";
+                       wakeup-source;
+               };
+
+               button-1 {
+                       gpios = <&gpio1 8 GPIO_ACTIVE_LOW>; /* GPIO B */
+                       label = "TA2-GPIO-B";
+                       linux,code = <KEY_B>;
+                       pinctrl-0 = <&pinctrl_dhcom_b>;
+                       pinctrl-names = "default";
+                       wakeup-source;
+               };
+
+               button-2 {
+                       gpios = <&gpio5 2 GPIO_ACTIVE_LOW>; /* GPIO C */
+                       label = "TA3-GPIO-C";
+                       linux,code = <KEY_C>;
+                       pinctrl-0 = <&pinctrl_dhcom_c>;
+                       pinctrl-names = "default";
+                       wakeup-source;
+               };
+
+               button-3 {
+                       gpios = <&gpio4 27 GPIO_ACTIVE_LOW>; /* GPIO D */
+                       label = "TA4-GPIO-D";
+                       linux,code = <KEY_D>;
+                       pinctrl-0 = <&pinctrl_dhcom_d>;
+                       pinctrl-names = "default";
+                       wakeup-source;
+               };
+       };
+
+       led {
+               compatible = "gpio-leds";
+
+               led-0 {
+                       color = <LED_COLOR_ID_GREEN>;
+                       default-state = "off";
+                       function = LED_FUNCTION_INDICATOR;
+                       gpios = <&gpio5 22 GPIO_ACTIVE_HIGH>; /* GPIO E */
+                       pinctrl-0 = <&pinctrl_dhcom_e>;
+                       pinctrl-names = "default";
+               };
+
+               led-1 {
+                       color = <LED_COLOR_ID_GREEN>;
+                       default-state = "off";
+                       function = LED_FUNCTION_INDICATOR;
+                       gpios = <&gpio5 23 GPIO_ACTIVE_HIGH>; /* GPIO F */
+                       pinctrl-0 = <&pinctrl_dhcom_f>;
+                       pinctrl-names = "default";
+               };
+
+               led-2 {
+                       color = <LED_COLOR_ID_GREEN>;
+                       default-state = "off";
+                       function = LED_FUNCTION_INDICATOR;
+                       gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>; /* GPIO H */
+                       pinctrl-0 = <&pinctrl_dhcom_h>;
+                       pinctrl-names = "default";
+               };
+
+               led-3 {
+                       color = <LED_COLOR_ID_GREEN>;
+                       default-state = "off";
+                       function = LED_FUNCTION_INDICATOR;
+                       gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>; /* GPIO I */
+                       pinctrl-0 = <&pinctrl_dhcom_i>;
+                       pinctrl-names = "default";
+               };
+       };
+};
+
+/*
+ * PDK2 carrier board uses SoM with KSZ9131 populated and connected to
+ * SoM EQoS ethernet RGMII interface. Remove the other SoM PHY DT node.
+ */
+/delete-node/ &ethphy0f;
+
+/*
+ * PDK2 carrier board has KSZ9021 PHY populated and connected to SoM FEC
+ * ethernet RGMII interface. The SoM is not populated with second FEC PHY.
+ */
+/delete-node/ &ethphy1f;
+
+&fec { /* Second ethernet */
+       phy-handle = <&ethphypdk>;
+
+       mdio {
+               ethphypdk: ethernet-phy@7 { /* KSZ 9021 */
+                       compatible = "ethernet-phy-ieee802.3-c22";
+                       pinctrl-0 = <&pinctrl_ethphy1>;
+                       pinctrl-names = "default";
+                       interrupt-parent = <&gpio4>;
+                       interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+                       max-speed = <100>;
+                       reg = <7>;
+                       reset-assert-us = <1000>;
+                       reset-deassert-us = <1000>;
+                       reset-gpios = <&gpio4 2 GPIO_ACTIVE_LOW>;
+                       rxc-skew-ps = <3000>;
+                       rxd0-skew-ps = <0>;
+                       rxd1-skew-ps = <0>;
+                       rxd2-skew-ps = <0>;
+                       rxd3-skew-ps = <0>;
+                       rxdv-skew-ps = <0>;
+                       txc-skew-ps = <3000>;
+                       txd0-skew-ps = <0>;
+                       txd1-skew-ps = <0>;
+                       txd2-skew-ps = <0>;
+                       txd3-skew-ps = <0>;
+                       txen-skew-ps = <0>;
+               };
+       };
+};
+
+&flexcan1 {
+       status = "okay";
+};
+
+&usb3_1 {
+       fsl,over-current-active-low;
+};
+
+&iomuxc {
+       /*
+        * GPIO_A,B,C,D are connected to buttons.
+        * GPIO_E,F,H,I are connected to LEDs.
+        * GPIO_M is connected to CLKOUT2.
+        */
+       pinctrl-0 = <&pinctrl_hog_base
+                    &pinctrl_dhcom_g &pinctrl_dhcom_j
+                    &pinctrl_dhcom_k &pinctrl_dhcom_l
+                    &pinctrl_dhcom_int>;
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi
new file mode 100644 (file)
index 0000000..a616eb3
--- /dev/null
@@ -0,0 +1,1030 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021-2022 Marek Vasut <marex@denx.de>
+ */
+
+#include "imx8mp.dtsi"
+
+/ {
+       model = "DH electronics i.MX8M Plus DHCOM SoM";
+       compatible = "dh,imx8mp-dhcom-som", "fsl,imx8mp";
+
+       aliases {
+               ethernet0 = &eqos;
+               ethernet1 = &fec;
+               rtc0 = &rv3032;
+               rtc1 = &snvs_rtc;
+               spi0 = &flexspi;
+       };
+
+       memory@40000000 {
+               device_type = "memory";
+               /* Memory size 512 MiB..8 GiB will be filled by U-Boot */
+               reg = <0x0 0x40000000 0 0x08000000>;
+       };
+
+       reg_eth_vio: regulator-eth-vio {
+               compatible = "regulator-fixed";
+               gpio = <&gpio2 10 GPIO_ACTIVE_LOW>;
+               pinctrl-0 = <&pinctrl_enet_vio>;
+               pinctrl-names = "default";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-name = "eth_vio";
+               vin-supply = <&buck4>;
+       };
+
+       reg_usdhc2_vmmc: regulator-usdhc2-vmmc {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio2 19 0>; /* SD2_RESET */
+               off-on-delay-us = <12000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_usdhc2_vmmc>;
+               regulator-max-microvolt = <3300000>;
+               regulator-min-microvolt = <3300000>;
+               regulator-name = "VDD_3V3_SD";
+               startup-delay-us = <100>;
+               vin-supply = <&buck4>;
+       };
+};
+
+&A53_0 {
+       cpu-supply = <&buck2>;
+};
+
+&A53_1 {
+       cpu-supply = <&buck2>;
+};
+
+&A53_2 {
+       cpu-supply = <&buck2>;
+};
+
+&A53_3 {
+       cpu-supply = <&buck2>;
+};
+
+&ecspi1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi1>;
+       cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
+       status = "disabled";
+};
+
+&ecspi2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi2>;
+       cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
+       status = "disabled";
+};
+
+&eqos {        /* First ethernet */
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_eqos>;
+       phy-handle = <&ethphy0g>;
+       phy-mode = "rgmii-id";
+       status = "okay";
+
+       mdio {
+               compatible = "snps,dwmac-mdio";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               /* Up to one of these two PHYs may be populated. */
+               ethphy0f: ethernet-phy@1 { /* SMSC LAN8740Ai */
+                       compatible = "ethernet-phy-id0007.c110",
+                                    "ethernet-phy-ieee802.3-c22";
+                       interrupt-parent = <&gpio3>;
+                       interrupts = <19 IRQ_TYPE_LEVEL_LOW>;
+                       pinctrl-0 = <&pinctrl_ethphy0>;
+                       pinctrl-names = "default";
+                       reg = <1>;
+                       reset-assert-us = <1000>;
+                       reset-deassert-us = <1000>;
+                       reset-gpios = <&gpio3 20 GPIO_ACTIVE_LOW>;
+                       /* Non-default PHY population option. */
+                       status = "disabled";
+               };
+
+               ethphy0g: ethernet-phy@5 { /* Micrel KSZ9131RNXI */
+                       compatible = "ethernet-phy-id0022.1642",
+                                    "ethernet-phy-ieee802.3-c22";
+                       interrupt-parent = <&gpio3>;
+                       interrupts = <19 IRQ_TYPE_LEVEL_LOW>;
+                       micrel,led-mode = <0>;
+                       pinctrl-0 = <&pinctrl_ethphy0>;
+                       pinctrl-names = "default";
+                       reg = <5>;
+                       reset-assert-us = <1000>;
+                       reset-deassert-us = <1000>;
+                       reset-gpios = <&gpio3 20 GPIO_ACTIVE_LOW>;
+                       /* Default PHY population option. */
+                       status = "okay";
+               };
+       };
+};
+
+&fec { /* Second ethernet */
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_fec>;
+       phy-handle = <&ethphy1f>;
+       phy-mode = "rgmii";
+       fsl,magic-packet;
+       status = "okay";
+
+       mdio {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               /* Up to one PHY may be populated. */
+               ethphy1f: ethernet-phy@1 { /* SMSC LAN8740Ai */
+                       compatible = "ethernet-phy-id0007.c110",
+                                    "ethernet-phy-ieee802.3-c22";
+                       interrupt-parent = <&gpio4>;
+                       interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+                       pinctrl-0 = <&pinctrl_ethphy1>;
+                       pinctrl-names = "default";
+                       reg = <1>;
+                       reset-assert-us = <1000>;
+                       reset-deassert-us = <1000>;
+                       reset-gpios = <&gpio4 2 GPIO_ACTIVE_LOW>;
+                       /* Non-default PHY population option. */
+                       status = "disabled";
+               };
+       };
+};
+
+&flexcan1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_flexcan1>;
+       status = "disabled";
+};
+
+&flexcan2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_flexcan2>;
+       status = "disabled";
+};
+
+&flexspi {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_flexspi>;
+       status = "okay";
+
+       flash@0 {       /* W25Q128JWPIM */
+               compatible = "jedec,spi-nor";
+               reg = <0>;
+               spi-max-frequency = <80000000>;
+               spi-tx-bus-width = <4>;
+               spi-rx-bus-width = <4>;
+       };
+};
+
+&gpio1 {
+       gpio-line-names =
+               "DHCOM-G", "", "", "", "", "DHCOM-I", "DHCOM-J", "DHCOM-L",
+               "DHCOM-B", "DHCOM-A", "", "DHCOM-H", "", "", "", "",
+               "", "", "", "", "", "", "", "",
+               "", "", "", "", "", "", "", "";
+};
+
+&gpio2 {
+       gpio-line-names =
+               "", "", "", "", "", "", "", "",
+               "", "", "", "DHCOM-K", "", "", "", "",
+               "", "", "", "", "DHCOM-INT", "", "", "",
+               "", "", "", "", "", "", "", "";
+};
+
+&gpio3 {
+       gpio-line-names =
+               "", "", "", "", "", "", "", "",
+               "", "", "", "", "", "", "SOM-HW0", "",
+               "", "", "", "", "", "", "SOM-MEM0", "SOM-MEM1",
+               "SOM-MEM2", "SOM-HW2", "", "", "", "", "", "";
+};
+
+&gpio4 {
+       gpio-line-names =
+               "", "", "", "", "", "", "", "",
+               "", "", "", "", "", "", "", "",
+               "", "", "", "SOM-HW1", "", "", "", "",
+               "", "", "", "DHCOM-D", "", "", "", "";
+};
+
+&gpio5 {
+       gpio-line-names =
+               "", "", "DHCOM-C", "", "", "", "", "",
+               "", "", "", "", "", "", "", "",
+               "", "", "", "", "", "", "DHCOM-E", "DHCOM-F",
+               "", "", "", "", "", "", "", "";
+};
+
+&i2c3 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default", "gpio";
+       pinctrl-0 = <&pinctrl_i2c3>;
+       pinctrl-1 = <&pinctrl_i2c3_gpio>;
+       scl-gpios = <&gpio5 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       sda-gpios = <&gpio5 19 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       status = "okay";
+
+       pmic: pmic@25 {
+               compatible = "nxp,pca9450c";
+               reg = <0x25>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_pmic>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+               sd-vsel-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
+
+               /*
+                * i.MX 8M Plus Data Sheet for Consumer Products
+                * 3.1.4 Operating ranges
+                * MIMX8ML8CVNKZAB
+                */
+               regulators {
+                       buck1: BUCK1 {  /* VDD_SOC (dual-phase with BUCK3) */
+                               regulator-compatible = "BUCK1";
+                               regulator-min-microvolt = <850000>;
+                               regulator-max-microvolt = <1000000>;
+                               regulator-ramp-delay = <3125>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+
+                       buck2: BUCK2 {  /* VDD_ARM */
+                               regulator-compatible = "BUCK2";
+                               regulator-min-microvolt = <850000>;
+                               regulator-max-microvolt = <1000000>;
+                               regulator-ramp-delay = <3125>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+
+                       buck4: BUCK4 {  /* VDD_3V3 */
+                               regulator-compatible = "BUCK4";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+
+                       buck5: BUCK5 {  /* VDD_1V8 */
+                               regulator-compatible = "BUCK5";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+
+                       buck6: BUCK6 {  /* NVCC_DRAM_1V1 */
+                               regulator-compatible = "BUCK6";
+                               regulator-min-microvolt = <1100000>;
+                               regulator-max-microvolt = <1100000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+
+                       ldo1: LDO1 {    /* NVCC_SNVS_1V8 */
+                               regulator-compatible = "LDO1";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+
+                       ldo3: LDO3 {    /* VDDA_1V8 */
+                               regulator-compatible = "LDO3";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+
+                       ldo4: LDO4 {    /* PMIC_LDO4 */
+                               regulator-compatible = "LDO4";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+
+                       ldo5: LDO5 {    /* NVCC_SD2 */
+                               regulator-compatible = "LDO5";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+               };
+       };
+
+       adc@48 {
+               compatible = "ti,tla2024";
+               reg = <0x48>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               channel@0 {     /* Voltage over AIN0 and AIN1. */
+                       reg = <0>;
+               };
+
+               channel@1 {     /* Voltage over AIN0 and AIN3. */
+                       reg = <1>;
+               };
+
+               channel@2 {     /* Voltage over AIN1 and AIN3. */
+                       reg = <2>;
+               };
+
+               channel@3 {     /* Voltage over AIN2 and AIN3. */
+                       reg = <3>;
+               };
+
+               channel@4 {     /* Voltage over AIN0 and GND. */
+                       reg = <4>;
+               };
+
+               channel@5 {     /* Voltage over AIN1 and GND. */
+                       reg = <5>;
+               };
+
+               channel@6 {     /* Voltage over AIN2 and GND. */
+                       reg = <6>;
+               };
+
+               channel@7 {     /* Voltage over AIN3 and GND. */
+                       reg = <7>;
+               };
+       };
+
+       touchscreen@49 {
+               compatible = "ti,tsc2004";
+               reg = <0x49>;
+               interrupts-extended = <&gpio4 0 IRQ_TYPE_EDGE_FALLING>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_touch>;
+               vio-supply = <&buck4>;
+       };
+
+       eeprom0: eeprom@50 {    /* EEPROM with EQoS MAC address */
+               compatible = "atmel,24c02";
+               pagesize = <16>;
+               reg = <0x50>;
+       };
+
+       rv3032: rtc@51 {
+               compatible = "microcrystal,rv3032";
+               reg = <0x51>;
+               interrupts-extended = <&gpio5 5 IRQ_TYPE_LEVEL_LOW>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_rtc>;
+       };
+
+       eeprom1: eeprom@53 {    /* EEPROM with FEC MAC address */
+               compatible = "atmel,24c02";
+               pagesize = <16>;
+               reg = <0x53>;
+       };
+};
+
+&i2c4 {
+       clock-frequency = <100000>;
+       pinctrl-names = "default", "gpio";
+       pinctrl-0 = <&pinctrl_i2c4>;
+       pinctrl-1 = <&pinctrl_i2c4_gpio>;
+       scl-gpios = <&gpio5 20 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       sda-gpios = <&gpio5 21 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       status = "okay";
+};
+
+&i2c5 {        /* HDMI EDID bus */
+       clock-frequency = <100000>;
+       pinctrl-names = "default", "gpio";
+       pinctrl-0 = <&pinctrl_i2c5>;
+       pinctrl-1 = <&pinctrl_i2c5_gpio>;
+       scl-gpios = <&gpio5 26 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       sda-gpios = <&gpio5 27 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       status = "okay";
+};
+
+&pwm1 {
+       pinctrl-0 = <&pinctrl_pwm1>;
+       pinctrl-names = "default";
+       status = "disabled";
+};
+
+&uart1 {
+       /* CA53 console */
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1>;
+       status = "okay";
+};
+
+&uart2 {
+       /* Bluetooth */
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart2>;
+       uart-has-rtscts;
+       status = "okay";
+};
+
+&uart3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart3>;
+       uart-has-rtscts;
+       status = "okay";
+};
+
+&uart4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart4>;
+       status = "okay";
+};
+
+&usb3_phy0 {
+       status = "okay";
+};
+
+&usb3_0 {
+       status = "okay";
+};
+
+&usb_dwc3_0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usb0_vbus>;
+       dr_mode = "otg";
+       status = "okay";
+};
+
+&usb3_phy1 {
+       status = "okay";
+};
+
+&usb3_1 {
+       status = "okay";
+};
+
+&usb_dwc3_1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usb1_vbus>;
+       dr_mode = "host";
+       status = "okay";
+};
+
+/* SDIO WiFi */
+&usdhc1 {
+       pinctrl-names = "default", "state_100mhz", "state_200mhz";
+       pinctrl-0 = <&pinctrl_usdhc1>;
+       pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
+       pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
+       vmmc-supply = <&buck4>;
+       bus-width = <4>;
+       non-removable;
+       cap-power-off-card;
+       keep-power-in-suspend;
+       status = "okay";
+
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       brcmf: bcrmf@1 {        /* muRata 2AE */
+               reg = <1>;
+               compatible = "cypress,cyw4373-fmac", "brcm,bcm4329-fmac";
+               /*
+                * The "host-wake" interrupt output is by default not
+                * connected to the SoC, but can be connected on to
+                * SoC pin on the carrier board.
+                */
+               reset-gpios = <&gpio1 13 GPIO_ACTIVE_LOW>;
+       };
+};
+
+/* SD slot */
+&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>;
+       cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>;
+       vmmc-supply = <&reg_usdhc2_vmmc>;
+       bus-width = <4>;
+       status = "okay";
+};
+
+/* eMMC */
+&usdhc3 {
+       pinctrl-names = "default", "state_100mhz", "state_200mhz";
+       pinctrl-0 = <&pinctrl_usdhc3>;
+       pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
+       pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
+       vmmc-supply = <&buck4>;
+       vqmmc-supply = <&buck5>;
+       bus-width = <8>;
+       non-removable;
+       status = "okay";
+};
+
+&wdog1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_wdog>;
+       fsl,ext-reset-output;
+       status = "okay";
+};
+
+&iomuxc {
+       pinctrl-0 = <&pinctrl_hog_base
+                    &pinctrl_dhcom_a &pinctrl_dhcom_b &pinctrl_dhcom_c
+                    &pinctrl_dhcom_d &pinctrl_dhcom_e &pinctrl_dhcom_f
+                    &pinctrl_dhcom_g &pinctrl_dhcom_h &pinctrl_dhcom_i
+                    &pinctrl_dhcom_j &pinctrl_dhcom_k &pinctrl_dhcom_l
+                    /* GPIO_M is connected to CLKOUT2 */
+                    &pinctrl_dhcom_int>;
+       pinctrl-names = "default";
+
+       pinctrl_dhcom_a: dhcom-a-grp {
+               fsl,pins = <
+                       /* ENET_QOS_EVENT0-OUT */
+                       MX8MP_IOMUXC_GPIO1_IO09__GPIO1_IO09             0x2
+               >;
+       };
+
+       pinctrl_dhcom_b: dhcom-b-grp {
+               fsl,pins = <
+                       /* ENET_QOS_EVENT0-IN */
+                       MX8MP_IOMUXC_GPIO1_IO08__GPIO1_IO08             0x2
+               >;
+       };
+
+       pinctrl_dhcom_c: dhcom-c-grp {
+               fsl,pins = <
+                       /* GPIO_C */
+                       MX8MP_IOMUXC_SAI3_MCLK__GPIO5_IO02              0x2
+               >;
+       };
+
+       pinctrl_dhcom_d: dhcom-d-grp {
+               fsl,pins = <
+                       /* GPIO_D */
+                       MX8MP_IOMUXC_SAI2_MCLK__GPIO4_IO27              0x2
+               >;
+       };
+
+       pinctrl_dhcom_e: dhcom-e-grp {
+               fsl,pins = <
+                       /* GPIO_E */
+                       MX8MP_IOMUXC_UART1_RXD__GPIO5_IO22              0x2
+               >;
+       };
+
+       pinctrl_dhcom_f: dhcom-f-grp {
+               fsl,pins = <
+                       /* GPIO_F */
+                       MX8MP_IOMUXC_UART1_TXD__GPIO5_IO23              0x2
+               >;
+       };
+
+       pinctrl_dhcom_g: dhcom-g-grp {
+               fsl,pins = <
+                       /* GPIO_G */
+                       MX8MP_IOMUXC_GPIO1_IO00__GPIO1_IO00             0x2
+               >;
+       };
+
+       pinctrl_dhcom_h: dhcom-h-grp {
+               fsl,pins = <
+                       /* GPIO_H */
+                       MX8MP_IOMUXC_GPIO1_IO11__GPIO1_IO11             0x2
+               >;
+       };
+
+       pinctrl_dhcom_i: dhcom-i-grp {
+               fsl,pins = <
+                       /* CSI1_SYNC */
+                       MX8MP_IOMUXC_GPIO1_IO05__GPIO1_IO05             0x2
+               >;
+       };
+
+       pinctrl_dhcom_j: dhcom-j-grp {
+               fsl,pins = <
+                       /* CSIx_#RST */
+                       MX8MP_IOMUXC_GPIO1_IO06__GPIO1_IO06             0x2
+               >;
+       };
+
+       pinctrl_dhcom_k: dhcom-k-grp {
+               fsl,pins = <
+                       /* CSIx_PWDN */
+                       MX8MP_IOMUXC_SD1_STROBE__GPIO2_IO11             0x2
+               >;
+       };
+
+       pinctrl_dhcom_l: dhcom-l-grp {
+               fsl,pins = <
+                       /* CSI2_SYNC */
+                       MX8MP_IOMUXC_GPIO1_IO07__GPIO1_IO07             0x2
+               >;
+       };
+
+       pinctrl_dhcom_int: dhcom-int-grp {
+               fsl,pins = <
+                       /* INT_HIGHEST_PRIO */
+                       MX8MP_IOMUXC_SD2_WP__GPIO2_IO20                 0x2
+               >;
+       };
+
+       pinctrl_hog_base: dhcom-hog-base-grp {
+               fsl,pins = <
+                       /* GPIOs for memory coding */
+                       MX8MP_IOMUXC_SAI5_RXD1__GPIO3_IO22              0x40000080
+                       MX8MP_IOMUXC_SAI5_RXD2__GPIO3_IO23              0x40000080
+                       MX8MP_IOMUXC_SAI5_RXD3__GPIO3_IO24              0x40000080
+                       /* GPIOs for hardware coding */
+                       MX8MP_IOMUXC_NAND_DQS__GPIO3_IO14               0x40000080
+                       MX8MP_IOMUXC_SAI1_TXD7__GPIO4_IO19              0x40000080
+                       MX8MP_IOMUXC_SAI5_MCLK__GPIO3_IO25              0x40000080
+               >;
+       };
+
+       pinctrl_ecspi1: dhcom-ecspi1-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_ECSPI1_SCLK__ECSPI1_SCLK           0x44
+                       MX8MP_IOMUXC_ECSPI1_MOSI__ECSPI1_MOSI           0x44
+                       MX8MP_IOMUXC_ECSPI1_MISO__ECSPI1_MISO           0x44
+                       MX8MP_IOMUXC_ECSPI1_SS0__GPIO5_IO09             0x40
+               >;
+       };
+
+       pinctrl_ecspi2: dhcom-ecspi2-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_ECSPI2_SCLK__ECSPI2_SCLK           0x44
+                       MX8MP_IOMUXC_ECSPI2_MOSI__ECSPI2_MOSI           0x44
+                       MX8MP_IOMUXC_ECSPI2_MISO__ECSPI2_MISO           0x44
+                       MX8MP_IOMUXC_ECSPI2_SS0__GPIO5_IO13             0x40
+               >;
+       };
+
+       pinctrl_eqos: dhcom-eqos-grp {  /* RGMII */
+               fsl,pins = <
+                       MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC             0x3
+                       MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO           0x3
+                       MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL 0x1f
+                       MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK       0x1f
+                       MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0       0x1f
+                       MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1       0x1f
+                       MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2       0x1f
+                       MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3       0x1f
+                       MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK       0x91
+                       MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL 0x91
+                       MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0       0x91
+                       MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1       0x91
+                       MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2       0x91
+                       MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3       0x91
+               >;
+       };
+
+       pinctrl_enet_vio: dhcom-enet-vio-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_SD1_RESET_B__GPIO2_IO10            0x22
+               >;
+       };
+
+       pinctrl_ethphy0: dhcom-ethphy0-grp {
+               fsl,pins = <
+                       /* ENET1_#RST Reset */
+                       MX8MP_IOMUXC_SAI5_RXC__GPIO3_IO20               0x22
+                       /* ENET1_#INT Interrupt */
+                       MX8MP_IOMUXC_SAI5_RXFS__GPIO3_IO19              0x22
+               >;
+       };
+
+       pinctrl_ethphy1: dhcom-ethphy1-grp {
+               fsl,pins = <
+                       /* ENET1_#RST Reset */
+                       MX8MP_IOMUXC_SAI1_RXD0__GPIO4_IO02              0x11
+                       /* ENET1_#INT Interrupt */
+                       MX8MP_IOMUXC_SAI1_RXD1__GPIO4_IO03              0x11
+               >;
+       };
+
+       pinctrl_fec: dhcom-fec-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_SAI1_MCLK__ENET1_TX_CLK            0x1f
+                       MX8MP_IOMUXC_SAI1_RXD2__ENET1_MDC               0x3
+                       MX8MP_IOMUXC_SAI1_RXD3__ENET1_MDIO              0x3
+                       MX8MP_IOMUXC_SAI1_RXD4__ENET1_RGMII_RD0         0x91
+                       MX8MP_IOMUXC_SAI1_RXD5__ENET1_RGMII_RD1         0x91
+                       MX8MP_IOMUXC_SAI1_RXD6__ENET1_RGMII_RD2         0x91
+                       MX8MP_IOMUXC_SAI1_RXD7__ENET1_RGMII_RD3         0x91
+                       MX8MP_IOMUXC_SAI1_TXC__ENET1_RGMII_RXC          0x91
+                       MX8MP_IOMUXC_SAI1_TXFS__ENET1_RGMII_RX_CTL      0x91
+                       MX8MP_IOMUXC_SAI1_TXD0__ENET1_RGMII_TD0         0x1f
+                       MX8MP_IOMUXC_SAI1_TXD1__ENET1_RGMII_TD1         0x1f
+                       MX8MP_IOMUXC_SAI1_TXD2__ENET1_RGMII_TD2         0x1f
+                       MX8MP_IOMUXC_SAI1_TXD3__ENET1_RGMII_TD3         0x1f
+                       MX8MP_IOMUXC_SAI1_TXD4__ENET1_RGMII_TX_CTL      0x1f
+                       MX8MP_IOMUXC_SAI1_TXD5__ENET1_RGMII_TXC         0x1f
+                       MX8MP_IOMUXC_SAI1_TXD6__ENET1_RX_ER             0x1f
+               >;
+       };
+
+       pinctrl_flexcan1: dhcom-flexcan1-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_SPDIF_RX__CAN1_RX                  0x154
+                       MX8MP_IOMUXC_SPDIF_TX__CAN1_TX                  0x154
+               >;
+       };
+
+       pinctrl_flexcan2: dhcom-flexcan2-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_UART3_RXD__CAN2_TX                 0x154
+                       MX8MP_IOMUXC_UART3_TXD__CAN2_RX                 0x154
+               >;
+       };
+
+       pinctrl_flexspi: dhcom-flexspi-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_NAND_ALE__FLEXSPI_A_SCLK           0x1c2
+                       MX8MP_IOMUXC_NAND_CE0_B__FLEXSPI_A_SS0_B        0x82
+                       MX8MP_IOMUXC_NAND_DATA00__FLEXSPI_A_DATA00      0x82
+                       MX8MP_IOMUXC_NAND_DATA01__FLEXSPI_A_DATA01      0x82
+                       MX8MP_IOMUXC_NAND_DATA02__FLEXSPI_A_DATA02      0x82
+                       MX8MP_IOMUXC_NAND_DATA03__FLEXSPI_A_DATA03      0x82
+               >;
+       };
+
+       pinctrl_hdmi: dhcom-hdmi-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_HDMI_CEC__HDMIMIX_HDMI_CEC         0x154
+                       MX8MP_IOMUXC_HDMI_HPD__HDMIMIX_HDMI_HPD         0x154
+               >;
+       };
+
+       pinctrl_i2c3: dhcom-i2c3-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL                 0x40000084
+                       MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA                 0x40000084
+               >;
+       };
+
+       pinctrl_i2c3_gpio: dhcom-i2c3-gpio-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_I2C3_SCL__GPIO5_IO18               0x84
+                       MX8MP_IOMUXC_I2C3_SDA__GPIO5_IO19               0x84
+               >;
+       };
+
+       pinctrl_i2c4: dhcom-i2c4-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_I2C4_SCL__I2C4_SCL                 0x40000084
+                       MX8MP_IOMUXC_I2C4_SDA__I2C4_SDA                 0x40000084
+               >;
+       };
+
+       pinctrl_i2c4_gpio: dhcom-i2c4-gpio-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_I2C4_SCL__GPIO5_IO20               0x84
+                       MX8MP_IOMUXC_I2C4_SDA__GPIO5_IO21               0x84
+               >;
+       };
+
+       pinctrl_i2c5: dhcom-i2c5-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_HDMI_DDC_SCL__I2C5_SCL             0x40000084
+                       MX8MP_IOMUXC_HDMI_DDC_SDA__I2C5_SDA             0x40000084
+               >;
+       };
+
+       pinctrl_i2c5_gpio: dhcom-i2c5-gpio-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_HDMI_DDC_SCL__GPIO3_IO26           0x84
+                       MX8MP_IOMUXC_HDMI_DDC_SDA__GPIO3_IO27           0x84
+               >;
+       };
+
+       pinctrl_pmic: dhcom-pmic-grp {
+               fsl,pins = <
+                       /* PMIC_nINT */
+                       MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03             0x40000090
+               >;
+       };
+
+       pinctrl_pwm1: dhcom-pwm1-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_GPIO1_IO01__PWM1_OUT               0x6
+               >;
+       };
+
+       pinctrl_rtc: dhcom-rtc-grp {
+               fsl,pins = <
+                       /* RTC_#INT Interrupt */
+                       MX8MP_IOMUXC_SPDIF_EXT_CLK__GPIO5_IO05          0x40000080
+               >;
+       };
+
+       pinctrl_touch: dhcom-touch-grp {
+               fsl,pins = <
+                       /* #TOUCH_INT */
+                       MX8MP_IOMUXC_SAI1_RXFS__GPIO4_IO00              0x40000080
+               >;
+       };
+
+       pinctrl_uart1: dhcom-uart1-grp {
+               fsl,pins = <
+                       /* Console UART */
+                       MX8MP_IOMUXC_SAI2_RXC__UART1_DCE_RX             0x49
+                       MX8MP_IOMUXC_SAI2_RXFS__UART1_DCE_TX            0x49
+                       MX8MP_IOMUXC_SAI2_RXD0__UART1_DCE_RTS           0x49
+                       MX8MP_IOMUXC_SAI2_TXFS__UART1_DCE_CTS           0x49
+               >;
+       };
+
+       pinctrl_uart2: dhcom-uart2-grp {
+               fsl,pins = <
+                       /* Bluetooth UART */
+                       MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX            0x49
+                       MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX            0x49
+                       MX8MP_IOMUXC_SD1_DATA4__UART2_DCE_RTS           0x49
+                       MX8MP_IOMUXC_SD1_DATA5__UART2_DCE_CTS           0x49
+               >;
+       };
+
+       pinctrl_uart3: dhcom-uart3-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_ECSPI1_SCLK__UART3_DCE_RX          0x49
+                       MX8MP_IOMUXC_ECSPI1_MOSI__UART3_DCE_TX          0x49
+                       MX8MP_IOMUXC_ECSPI1_SS0__UART3_DCE_RTS          0x49
+                       MX8MP_IOMUXC_ECSPI1_MISO__UART3_DCE_CTS         0x49
+               >;
+       };
+
+       pinctrl_uart4: dhcom-uart4-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_UART4_RXD__UART4_DCE_RX            0x49
+                       MX8MP_IOMUXC_UART4_TXD__UART4_DCE_TX            0x49
+               >;
+       };
+
+       pinctrl_usb0_vbus: dhcom-usb0-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_GPIO1_IO10__USB1_OTG_ID            0x0
+               >;
+       };
+
+       pinctrl_usb1_vbus: dhcom-usb1-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_GPIO1_IO14__USB2_OTG_PWR           0x6
+                       MX8MP_IOMUXC_GPIO1_IO15__USB2_OTG_OC            0x80
+               >;
+       };
+
+       pinctrl_usdhc1: dhcom-usdhc1-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK                0x190
+                       MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD                0x1d0
+                       MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0            0x1d0
+                       MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1            0x1d0
+                       MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2            0x1d0
+                       MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3            0x1d0
+                       /* BT_REG_EN */
+                       MX8MP_IOMUXC_GPIO1_IO12__GPIO1_IO12             0x144
+                       /* WL_REG_EN */
+                       MX8MP_IOMUXC_GPIO1_IO13__GPIO1_IO13             0x144
+               >;
+       };
+
+       pinctrl_usdhc1_100mhz: dhcom-usdhc1-100mhz-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK                0x194
+                       MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD                0x1d4
+                       MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0            0x1d4
+                       MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1            0x1d4
+                       MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2            0x1d4
+                       MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3            0x1d4
+                       /* BT_REG_EN */
+                       MX8MP_IOMUXC_GPIO1_IO12__GPIO1_IO12             0x144
+                       /* WL_REG_EN */
+                       MX8MP_IOMUXC_GPIO1_IO13__GPIO1_IO13             0x144
+               >;
+       };
+
+       pinctrl_usdhc1_200mhz: dhcom-usdhc1-200mhz-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK                0x196
+                       MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD                0x1d6
+                       MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0            0x1d6
+                       MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1            0x1d6
+                       MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2            0x1d6
+                       MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3            0x1d6
+                       /* BT_REG_EN */
+                       MX8MP_IOMUXC_GPIO1_IO12__GPIO1_IO12             0x144
+                       /* WL_REG_EN */
+                       MX8MP_IOMUXC_GPIO1_IO13__GPIO1_IO13             0x144
+               >;
+       };
+
+       pinctrl_usdhc2: dhcom-usdhc2-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK                0x190
+                       MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD                0x1d0
+                       MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0            0x1d0
+                       MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1            0x1d0
+                       MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2            0x1d0
+                       MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3            0x1d0
+                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT         0xc1
+               >;
+       };
+
+       pinctrl_usdhc2_100mhz: dhcom-usdhc2-100mhz-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK                0x194
+                       MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD                0x1d4
+                       MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0            0x1d4
+                       MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1            0x1d4
+                       MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2            0x1d4
+                       MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3            0x1d4
+                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT         0xc1
+               >;
+       };
+
+       pinctrl_usdhc2_200mhz: dhcom-usdhc2-200mhz-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK                0x196
+                       MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD                0x1d6
+                       MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0            0x1d6
+                       MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1            0x1d6
+                       MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2            0x1d6
+                       MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3            0x1d6
+                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT         0xc1
+               >;
+       };
+
+       pinctrl_usdhc2_vmmc: dhcom-usdhc2-vmmc-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19            0x20
+               >;
+       };
+
+       pinctrl_usdhc2_gpio: dhcom-usdhc2-gpio-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_SD2_CD_B__GPIO2_IO12               0x40000080
+               >;
+       };
+
+       pinctrl_usdhc3: dhcom-usdhc3-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK              0x190
+                       MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD              0x1d0
+                       MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0          0x1d0
+                       MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1          0x1d0
+                       MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2          0x1d0
+                       MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3          0x1d0
+                       MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4            0x1d0
+                       MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5           0x1d0
+                       MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6           0x1d0
+                       MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7             0x1d0
+                       MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE          0x190
+                       MX8MP_IOMUXC_NAND_READY_B__USDHC3_RESET_B       0x141
+               >;
+       };
+
+       pinctrl_usdhc3_100mhz: dhcom-usdhc3-100mhz-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK              0x194
+                       MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD              0x1d4
+                       MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0          0x1d4
+                       MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1          0x1d4
+                       MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2          0x1d4
+                       MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3          0x1d4
+                       MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4            0x1d4
+                       MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5           0x1d4
+                       MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6           0x1d4
+                       MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7             0x1d4
+                       MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE          0x194
+                       MX8MP_IOMUXC_NAND_READY_B__USDHC3_RESET_B       0x141
+               >;
+       };
+
+       pinctrl_usdhc3_200mhz: dhcom-usdhc3-200mhz-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK              0x196
+                       MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD              0x1d6
+                       MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0          0x1d6
+                       MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1          0x1d6
+                       MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2          0x1d6
+                       MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3          0x1d6
+                       MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4            0x1d6
+                       MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5           0x1d6
+                       MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6           0x1d6
+                       MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7             0x1d6
+                       MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE          0x196
+                       MX8MP_IOMUXC_NAND_READY_B__USDHC3_RESET_B       0x141
+               >;
+       };
+
+       pinctrl_wdog: dhcom-wdog-grp {
+               fsl,pins = <
+                       MX8MP_IOMUXC_GPIO1_IO02__WDOG1_WDOG_B           0xc6
+               >;
+       };
+};
index 4c3ac42..f6b017a 100644 (file)
        };
 };
 
-&flexcan1 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_flexcan1>;
-       xceiver-supply = <&reg_can1_stby>;
-       status = "okay";
+&A53_0 {
+       cpu-supply = <&reg_arm>;
 };
 
-&flexcan2 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_flexcan2>;
-       xceiver-supply = <&reg_can2_stby>;
-       status = "disabled";/* can2 pin conflict with pdm */
+&A53_1 {
+       cpu-supply = <&reg_arm>;
+};
+
+&A53_2 {
+       cpu-supply = <&reg_arm>;
+};
+
+&A53_3 {
+       cpu-supply = <&reg_arm>;
 };
 
 &eqos {
        };
 };
 
+&flexcan1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_flexcan1>;
+       xceiver-supply = <&reg_can1_stby>;
+       status = "okay";
+};
+
+&flexcan2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_flexcan2>;
+       xceiver-supply = <&reg_can2_stby>;
+       status = "disabled";/* can2 pin conflict with pdm */
+};
+
 &i2c1 {
        clock-frequency = <400000>;
        pinctrl-names = "default";
                                regulator-ramp-delay = <3125>;
                        };
 
-                       BUCK2 {
+                       reg_arm: BUCK2 {
                                regulator-name = "BUCK2";
                                regulator-min-microvolt = <720000>;
                                regulator-max-microvolt = <1025000>;
 &iomuxc {
        pinctrl_eqos: eqosgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC                             0x3
-                       MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO                           0x3
-                       MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0                       0x91
-                       MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1                       0x91
-                       MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2                       0x91
-                       MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3                       0x91
-                       MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK       0x91
-                       MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL                 0x91
-                       MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0                       0x1f
-                       MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1                       0x1f
-                       MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2                       0x1f
-                       MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3                       0x1f
-                       MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL                 0x1f
-                       MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK       0x1f
-                       MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22                               0x19
+                       MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC                             0x2
+                       MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO                           0x2
+                       MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0                       0x90
+                       MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1                       0x90
+                       MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2                       0x90
+                       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_SAI2_RXC__GPIO4_IO22                               0x10
                >;
        };
 
        pinctrl_fec: fecgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SAI1_RXD2__ENET1_MDC               0x3
-                       MX8MP_IOMUXC_SAI1_RXD3__ENET1_MDIO              0x3
-                       MX8MP_IOMUXC_SAI1_RXD4__ENET1_RGMII_RD0         0x91
-                       MX8MP_IOMUXC_SAI1_RXD5__ENET1_RGMII_RD1         0x91
-                       MX8MP_IOMUXC_SAI1_RXD6__ENET1_RGMII_RD2         0x91
-                       MX8MP_IOMUXC_SAI1_RXD7__ENET1_RGMII_RD3         0x91
-                       MX8MP_IOMUXC_SAI1_TXC__ENET1_RGMII_RXC          0x91
-                       MX8MP_IOMUXC_SAI1_TXFS__ENET1_RGMII_RX_CTL      0x91
-                       MX8MP_IOMUXC_SAI1_TXD0__ENET1_RGMII_TD0         0x1f
-                       MX8MP_IOMUXC_SAI1_TXD1__ENET1_RGMII_TD1         0x1f
-                       MX8MP_IOMUXC_SAI1_TXD2__ENET1_RGMII_TD2         0x1f
-                       MX8MP_IOMUXC_SAI1_TXD3__ENET1_RGMII_TD3         0x1f
-                       MX8MP_IOMUXC_SAI1_TXD4__ENET1_RGMII_TX_CTL      0x1f
-                       MX8MP_IOMUXC_SAI1_TXD5__ENET1_RGMII_TXC         0x1f
-                       MX8MP_IOMUXC_SAI1_RXD0__GPIO4_IO02              0x19
+                       MX8MP_IOMUXC_SAI1_RXD2__ENET1_MDC               0x2
+                       MX8MP_IOMUXC_SAI1_RXD3__ENET1_MDIO              0x2
+                       MX8MP_IOMUXC_SAI1_RXD4__ENET1_RGMII_RD0         0x90
+                       MX8MP_IOMUXC_SAI1_RXD5__ENET1_RGMII_RD1         0x90
+                       MX8MP_IOMUXC_SAI1_RXD6__ENET1_RGMII_RD2         0x90
+                       MX8MP_IOMUXC_SAI1_RXD7__ENET1_RGMII_RD3         0x90
+                       MX8MP_IOMUXC_SAI1_TXC__ENET1_RGMII_RXC          0x90
+                       MX8MP_IOMUXC_SAI1_TXFS__ENET1_RGMII_RX_CTL      0x90
+                       MX8MP_IOMUXC_SAI1_TXD0__ENET1_RGMII_TD0         0x16
+                       MX8MP_IOMUXC_SAI1_TXD1__ENET1_RGMII_TD1         0x16
+                       MX8MP_IOMUXC_SAI1_TXD2__ENET1_RGMII_TD2         0x16
+                       MX8MP_IOMUXC_SAI1_TXD3__ENET1_RGMII_TD3         0x16
+                       MX8MP_IOMUXC_SAI1_TXD4__ENET1_RGMII_TX_CTL      0x16
+                       MX8MP_IOMUXC_SAI1_TXD5__ENET1_RGMII_TXC         0x16
+                       MX8MP_IOMUXC_SAI1_RXD0__GPIO4_IO02              0x10
                >;
        };
 
 
        pinctrl_gpio_led: gpioledgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16   0x19
+                       MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16   0x140
                >;
        };
 
        pinctrl_i2c1: i2c1grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL         0x400001c3
-                       MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA         0x400001c3
+                       MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL         0x400001c2
+                       MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA         0x400001c2
                >;
        };
 
        pinctrl_i2c3: i2c3grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL         0x400001c3
-                       MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA         0x400001c3
+                       MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL         0x400001c2
+                       MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA         0x400001c2
                >;
        };
 
        pinctrl_i2c5: i2c5grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SPDIF_RX__I2C5_SDA         0x400001c3
-                       MX8MP_IOMUXC_SPDIF_TX__I2C5_SCL         0x400001c3
+                       MX8MP_IOMUXC_SPDIF_RX__I2C5_SDA         0x400001c2
+                       MX8MP_IOMUXC_SPDIF_TX__I2C5_SCL         0x400001c2
                >;
        };
 
 
        pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19    0x41
+                       MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19    0x40
                >;
        };
 
        pinctrl_uart2: uart2grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX    0x49
-                       MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX    0x49
+                       MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX    0x140
+                       MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX    0x140
                >;
        };
 
        pinctrl_usb1_vbus: usb1grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_GPIO1_IO14__USB2_OTG_PWR   0x19
+                       MX8MP_IOMUXC_GPIO1_IO14__USB2_OTG_PWR   0x10
                >;
        };
 
                        MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1    0x1d0
                        MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2    0x1d0
                        MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3    0x1d0
-                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
+                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
                >;
        };
 
                        MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1    0x1d4
                        MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2    0x1d4
                        MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3    0x1d4
-                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
+                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
                >;
        };
 
                        MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1    0x1d6
                        MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2    0x1d6
                        MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3    0x1d6
-                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
+                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
                >;
        };
 
index 70a701a..dd703b6 100644 (file)
 &iomuxc {
        pinctrl_eqos: eqosgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC                             0x3
-                       MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO                           0x3
-                       MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0                       0x91
-                       MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1                       0x91
-                       MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2                       0x91
-                       MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3                       0x91
-                       MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK       0x91
-                       MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL                 0x91
-                       MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0                       0x1f
-                       MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1                       0x1f
-                       MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2                       0x1f
-                       MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3                       0x1f
-                       MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL                 0x1f
-                       MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK       0x1f
-                       MX8MP_IOMUXC_NAND_DATA01__GPIO3_IO07                            0x19
+                       MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC                             0x2
+                       MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO                           0x2
+                       MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0                       0x90
+                       MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1                       0x90
+                       MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2                       0x90
+                       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_NAND_DATA01__GPIO3_IO07                            0x10
                >;
        };
 
        pinctrl_uart2: uart2grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX    0x49
-                       MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX    0x49
+                       MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX    0x40
+                       MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX    0x40
                >;
        };
 
                        MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1    0x1d0
                        MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2    0x1d0
                        MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3    0x1d0
-                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
+                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
                >;
        };
 
 
        pinctrl_reg_usb1: regusb1grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14     0x19
+                       MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14     0x10
                >;
        };
 
        pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19    0x41
+                       MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19    0x40
                >;
        };
 };
index 984a6b9..6aa720b 100644 (file)
 &iomuxc {
        pinctrl_eqos: eqosgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC                     0x3
-                       MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO                   0x3
-                       MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0               0x91
-                       MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1               0x91
-                       MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2               0x91
-                       MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3               0x91
-                       MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK       0x91
-                       MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL         0x91
-                       MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0               0x1f
-                       MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1               0x1f
-                       MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2               0x1f
-                       MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3               0x1f
-                       MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL         0x1f
-                       MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK       0x1f
+                       MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC                     0x2
+                       MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO                   0x2
+                       MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0               0x90
+                       MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1               0x90
+                       MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2               0x90
+                       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_SAI1_MCLK__GPIO4_IO20                      0x10
                >;
        };
 
        pinctrl_i2c2: i2c2grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL         0x400001c3
-                       MX8MP_IOMUXC_I2C2_SDA__I2C2_SDA         0x400001c3
+                       MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL         0x400001c2
+                       MX8MP_IOMUXC_I2C2_SDA__I2C2_SDA         0x400001c2
                >;
        };
 
        pinctrl_i2c2_gpio: i2c2gpiogrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_I2C2_SCL__GPIO5_IO16       0x1e3
-                       MX8MP_IOMUXC_I2C2_SDA__GPIO5_IO17       0x1e3
+                       MX8MP_IOMUXC_I2C2_SCL__GPIO5_IO16       0x1e2
+                       MX8MP_IOMUXC_I2C2_SDA__GPIO5_IO17       0x1e2
                >;
        };
 
        pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19    0x41
+                       MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19    0x40
                >;
        };
 
        pinctrl_uart1: uart1grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX    0x49
-                       MX8MP_IOMUXC_UART1_TXD__UART1_DCE_TX    0x49
+                       MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX    0x40
+                       MX8MP_IOMUXC_UART1_TXD__UART1_DCE_TX    0x40
                >;
        };
 
                        MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1    0x1d0
                        MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2    0x1d0
                        MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3    0x1d0
-                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
+                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
                >;
        };
 
                        MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1    0x1d4
                        MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2    0x1d4
                        MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3    0x1d4
-                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
+                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
                >;
        };
 
                        MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1    0x1d6
                        MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2    0x1d6
                        MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3    0x1d6
-                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
+                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
                >;
        };
 };
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts
new file mode 100644 (file)
index 0000000..d8ca529
--- /dev/null
@@ -0,0 +1,702 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright 2021-2022 TQ-Systems GmbH
+ * Author: Alexander Stein <alexander.stein@tq-group.com>
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/net/ti-dp83867.h>
+#include <dt-bindings/pwm/pwm.h>
+#include "imx8mp-tqma8mpql.dtsi"
+
+/ {
+       model = "TQ-Systems i.MX8MPlus TQMa8MPxL on MBa8MPxL";
+       compatible = "tq,imx8mp-tqma8mpql-mba8mpxl", "tq,imx8mp-tqma8mpql", "fsl,imx8mp";
+
+       chosen {
+               stdout-path = &uart4;
+       };
+
+       iio-hwmon {
+               compatible = "iio-hwmon";
+               io-channels = <&adc 0>, <&adc 1>;
+       };
+
+       aliases {
+               mmc0 = &usdhc3;
+               mmc1 = &usdhc2;
+               mmc2 = &usdhc1;
+               rtc0 = &pcf85063;
+               rtc1 = &snvs_rtc;
+               spi0 = &flexspi;
+               spi1 = &ecspi1;
+               spi2 = &ecspi2;
+               spi3 = &ecspi3;
+       };
+
+       backlight_lvds: backlight {
+               compatible = "pwm-backlight";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_backlight>;
+               pwms = <&pwm2 0 5000000 0>;
+               brightness-levels = <0 4 8 16 32 64 128 255>;
+               default-brightness-level = <7>;
+               power-supply = <&reg_vcc_12v0>;
+               enable-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>;
+               status = "disabled";
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_gpiobutton>;
+               autorepeat;
+
+               switch-1 {
+                       label = "S12";
+                       linux,code = <BTN_0>;
+                       gpios = <&gpio5 26 GPIO_ACTIVE_LOW>;
+               };
+
+               switch-2 {
+                       label = "S13";
+                       linux,code = <BTN_1>;
+                       gpios = <&gpio5 27 GPIO_ACTIVE_LOW>;
+               };
+       };
+
+       gpio-leds {
+               compatible = "gpio-leds";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_gpioled>;
+
+               led-0 {
+                       color = <LED_COLOR_ID_GREEN>;
+                       function = LED_FUNCTION_STATUS;
+                       function-enumerator = <0>;
+                       gpios = <&gpio5 5 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "default-on";
+               };
+
+               led-1 {
+                       color = <LED_COLOR_ID_GREEN>;
+                       function = LED_FUNCTION_HEARTBEAT;
+                       gpios = <&gpio5 4 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "heartbeat";
+               };
+
+               led-2 {
+                       color = <LED_COLOR_ID_YELLOW>;
+                       function = LED_FUNCTION_STATUS;
+                       function-enumerator = <1>;
+                       gpios = <&gpio5 3 GPIO_ACTIVE_HIGH>;
+               };
+       };
+
+       display: display {
+               /*
+                * Display is not fixed, so compatible has to be added from
+                * DT overlay
+                */
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_lvdsdisplay>;
+               power-supply = <&reg_vcc_3v3>;
+               enable-gpios = <&gpio3 20 GPIO_ACTIVE_HIGH>;
+               backlight = <&backlight_lvds>;
+               status = "disabled";
+       };
+
+       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 19 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               startup-delay-us = <100>;
+               off-on-delay-us = <12000>;
+       };
+
+       reg_vcc_12v0: regulator-12v0 {
+               compatible = "regulator-fixed";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_reg12v0>;
+               regulator-name = "VCC_12V0";
+               regulator-min-microvolt = <12000000>;
+               regulator-max-microvolt = <12000000>;
+               gpio = <&gpio2 6 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+
+       reg_vcc_3v3: regulator-3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "VCC_3V3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+       };
+
+       reserved-memory {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               ocram: ocram@900000 {
+                       no-map;
+                       reg = <0 0x900000 0 0x70000>;
+               };
+
+               /* global autoconfigured region for contiguous allocations */
+               linux,cma {
+                       compatible = "shared-dma-pool";
+                       reusable;
+                       size = <0 0x38000000>;
+                       alloc-ranges = <0 0x40000000 0 0xB0000000>;
+                       linux,cma-default;
+               };
+       };
+};
+
+&ecspi1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi1>;
+       cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
+       status = "okay";
+};
+
+&ecspi2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi2>;
+       cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
+       status = "okay";
+};
+
+&ecspi3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ecspi3>;
+       cs-gpios = <&gpio5 25 GPIO_ACTIVE_LOW>;
+       status = "okay";
+
+       adc: adc@0 {
+               reg = <0>;
+               compatible = "microchip,mcp3202";
+               /* 100 ksps * 18 */
+               spi-max-frequency = <1800000>;
+               vref-supply = <&reg_vcc_3v3>;
+               #io-channel-cells = <1>;
+       };
+};
+
+&eqos {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_eqos>, <&pinctrl_eqos_phy>;
+       phy-mode = "rgmii-id";
+       phy-handle = <&ethphy3>;
+       status = "okay";
+
+       mdio {
+               compatible = "snps,dwmac-mdio";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               ethphy3: ethernet-phy@3 {
+                       compatible = "ethernet-phy-ieee802.3-c22";
+                       reg = <3>;
+                       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 = <&gpio4 2 GPIO_ACTIVE_LOW>;
+                       reset-assert-us = <500000>;
+                       reset-deassert-us = <50000>;
+                       enet-phy-lane-no-swap;
+                       interrupt-parent = <&gpio4>;
+                       interrupts = <3 IRQ_TYPE_EDGE_FALLING>;
+               };
+       };
+};
+
+&fec {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_fec>, <&pinctrl_fec_phy>;
+       phy-mode = "rgmii-id";
+       phy-handle = <&ethphy0>;
+       fsl,magic-packet;
+       status = "okay";
+
+       mdio {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               ethphy0: ethernet-phy@0 {
+                       compatible = "ethernet-phy-ieee802.3-c22";
+                       reg = <0>;
+                       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 = <&gpio4 0 GPIO_ACTIVE_LOW>;
+                       reset-assert-us = <500000>;
+                       reset-deassert-us = <50000>;
+                       enet-phy-lane-no-swap;
+                       interrupt-parent = <&gpio4>;
+                       interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
+               };
+       };
+};
+
+&flexcan1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_flexcan1>;
+       xceiver-supply = <&reg_vcc_3v3>;
+       status = "okay";
+};
+
+&flexcan2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_flexcan2>;
+       xceiver-supply = <&reg_vcc_3v3>;
+       status = "okay";
+};
+
+&gpio1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_gpio1>;
+
+       gpio-line-names = "GPO1", "GPO0", "", "GPO3",
+                         "", "", "GPO2", "GPI0",
+                         "PMIC_IRQ", "GPI1", "OTG_ID", "USB_HUB_RST#",
+                         "OTG_PWR", "", "GPI2", "GPI3",
+                         "", "", "", "",
+                         "", "", "", "",
+                         "", "", "", "",
+                         "", "", "", "";
+};
+
+&gpio2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_hoggpio2>;
+
+       gpio-line-names = "", "", "", "",
+                         "", "", "VCC12V_EN", "PERST#",
+                         "", "", "CLKREQ#", "PEWAKE#",
+                         "USDHC2_CD", "", "", "",
+                         "", "", "", "V_SD3V3_EN",
+                         "", "", "", "",
+                         "", "", "", "",
+                         "", "", "", "";
+
+       perst-hog {
+               gpio-hog;
+               gpios = <7 0>;
+               output-high;
+               line-name = "PERST#";
+       };
+
+       clkreq-hog {
+               gpio-hog;
+               gpios = <10 0>;
+               input;
+               line-name = "CLKREQ#";
+       };
+
+       pewake-hog {
+               gpio-hog;
+               gpios = <11 0>;
+               input;
+               line-name = "PEWAKE#";
+       };
+};
+
+&gpio3 {
+       gpio-line-names = "", "", "", "",
+                         "", "", "", "",
+                         "", "", "", "",
+                         "", "", "LVDS0_RESET#", "",
+                         "", "", "", "LVDS0_BLT_EN",
+                         "LVDS0_PWR_EN", "", "", "",
+                         "", "", "", "",
+                         "", "", "", "";
+};
+
+&gpio4 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_gpio4>;
+
+       gpio-line-names = "ENET0_RST#", "ENET0_INT#", "ENET1_RST#", "ENET1_INT#",
+                         "", "", "", "",
+                         "", "", "", "",
+                         "", "", "", "",
+                         "", "", "DP_IRQ", "DSI_EN",
+                         "HDMI_OC#", "TEMP_EVENT#", "PCIE_CLK_OE#", "",
+                         "", "", "", "FAN_PWR",
+                         "RTC_EVENT#", "CODEC_RST#", "", "";
+};
+
+&gpio5 {
+       gpio-line-names = "", "", "", "LED2",
+                         "LED1", "LED0", "CSI0_RESET#", "CSI0_SYNC",
+                         "CSI0_TRIGGER", "CSI0_ENABLE", "", "",
+                         "", "ECSPI2_SS0", "", "",
+                         "", "", "", "",
+                         "", "", "", "",
+                         "", "ECSPI3_SS0", "SWITCH_A", "SWITCH_B",
+                         "", "", "", "";
+};
+
+&i2c2 {
+       clock-frequency = <384000>;
+       pinctrl-names = "default", "gpio";
+       pinctrl-0 = <&pinctrl_i2c2>;
+       pinctrl-1 = <&pinctrl_i2c2_gpio>;
+       scl-gpios = <&gpio5 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       sda-gpios = <&gpio5 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       status = "okay";
+
+       /* NXP SE97BTP with temperature sensor + eeprom */
+       se97_1c: temperature-sensor-eeprom@1c {
+               compatible = "nxp,se97", "jedec,jc-42.4-temp";
+               reg = <0x1c>;
+       };
+
+       at24c02_54: eeprom@54 {
+               compatible = "nxp,se97b", "atmel,24c02";
+               reg = <0x54>;
+               pagesize = <16>;
+               vcc-supply = <&reg_vcc_3v3>;
+       };
+};
+
+&i2c4 {
+       clock-frequency = <384000>;
+       pinctrl-names = "default", "gpio";
+       pinctrl-0 = <&pinctrl_i2c4>;
+       pinctrl-1 = <&pinctrl_i2c4_gpio>;
+       scl-gpios = <&gpio5 20 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       sda-gpios = <&gpio5 21 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       status = "okay";
+};
+
+&i2c6 {
+       clock-frequency = <384000>;
+       pinctrl-names = "default", "gpio";
+       pinctrl-0 = <&pinctrl_i2c6>;
+       pinctrl-1 = <&pinctrl_i2c6_gpio>;
+       scl-gpios = <&gpio2 2 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       sda-gpios = <&gpio2 3 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       status = "okay";
+};
+
+&pcf85063 {
+       /* RTC_EVENT# is connected on MBa8MPxL */
+       interrupt-parent = <&gpio4>;
+       interrupts = <28 IRQ_TYPE_EDGE_FALLING>;
+};
+
+&pwm2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pwm2>;
+       status = "disabled";
+};
+
+&pwm3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pwm3>;
+       status = "okay";
+};
+
+&snvs_pwrkey {
+       status = "okay";
+};
+
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1>;
+       assigned-clocks = <&clk IMX8MP_CLK_UART1>;
+       assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_80M>;
+       status = "okay";
+};
+
+&uart2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart2>;
+       assigned-clocks = <&clk IMX8MP_CLK_UART2>;
+       assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_80M>;
+       status = "okay";
+};
+
+&uart3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart3>;
+       assigned-clocks = <&clk IMX8MP_CLK_UART3>;
+       assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_80M>;
+       status = "okay";
+};
+
+&uart4 {
+       /* console */
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart4>;
+       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>;
+       cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>;
+       vmmc-supply = <&reg_usdhc2_vmmc>;
+       no-mmc;
+       no-sdio;
+       disable-wp;
+       bus-width = <4>;
+       status = "okay";
+};
+
+&iomuxc {
+       pinctrl_backlight: backlightgrp {
+               fsl,pins = <MX8MP_IOMUXC_SAI5_RXFS__GPIO3_IO19          0x14>;
+       };
+
+       pinctrl_flexcan1: flexcan1grp {
+               fsl,pins = <MX8MP_IOMUXC_SAI5_RXD1__CAN1_TX             0x150>,
+                          <MX8MP_IOMUXC_SAI5_RXD2__CAN1_RX             0x150>;
+       };
+
+       pinctrl_flexcan2: flexcan2grp {
+               fsl,pins = <MX8MP_IOMUXC_SAI5_RXD3__CAN2_TX             0x150>,
+                          <MX8MP_IOMUXC_SAI5_MCLK__CAN2_RX             0x150>;
+       };
+
+       /* only on X57, primary used as CSI0 control signals */
+       pinctrl_ecspi1: ecspi1grp {
+               fsl,pins = <MX8MP_IOMUXC_ECSPI1_MISO__ECSPI1_MISO       0x1c0>,
+                          <MX8MP_IOMUXC_ECSPI1_MOSI__ECSPI1_MOSI       0x1c0>,
+                          <MX8MP_IOMUXC_ECSPI1_SCLK__ECSPI1_SCLK       0x1c0>,
+                          <MX8MP_IOMUXC_ECSPI1_SS0__GPIO5_IO09         0x1c0>;
+       };
+
+       /* on X63 and optionally on X57, can also be used as CSI1 control signals */
+       pinctrl_ecspi2: ecspi2grp {
+               fsl,pins = <MX8MP_IOMUXC_ECSPI2_MISO__ECSPI2_MISO       0x1c0>,
+                          <MX8MP_IOMUXC_ECSPI2_MOSI__ECSPI2_MOSI       0x1c0>,
+                          <MX8MP_IOMUXC_ECSPI2_SCLK__ECSPI2_SCLK       0x1c0>,
+                          <MX8MP_IOMUXC_ECSPI2_SS0__GPIO5_IO13         0x1c0>;
+       };
+
+       pinctrl_ecspi3: ecspi3grp {
+               fsl,pins = <MX8MP_IOMUXC_UART1_TXD__ECSPI3_MOSI         0x1c0>,
+                          <MX8MP_IOMUXC_UART1_RXD__ECSPI3_SCLK         0x1c0>,
+                          <MX8MP_IOMUXC_UART2_RXD__ECSPI3_MISO         0x1c0>,
+                          <MX8MP_IOMUXC_UART2_TXD__GPIO5_IO25          0x1c0>;
+       };
+
+       pinctrl_eqos: eqosgrp {
+               fsl,pins = <MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC                         0x40000044>,
+                          <MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO                       0x40000044>,
+                          <MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0                   0x90>,
+                          <MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1                   0x90>,
+                          <MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2                   0x90>,
+                          <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                   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   0x14>;
+       };
+
+       pinctrl_eqos_event: eqosevtgrp {
+               fsl,pins = <MX8MP_IOMUXC_SAI2_RXD0__ENET_QOS_1588_EVENT2_OUT            0x100>,
+                          <MX8MP_IOMUXC_SAI2_TXD0__ENET_QOS_1588_EVENT2_IN             0x1c0>;
+       };
+
+       pinctrl_eqos_phy: eqosphygrp {
+               fsl,pins = <MX8MP_IOMUXC_SAI1_RXD0__GPIO4_IO02                          0x100>,
+                          <MX8MP_IOMUXC_SAI1_RXD1__GPIO4_IO03                          0x1c0>;
+       };
+
+       pinctrl_fec: fecgrp {
+               fsl,pins = <MX8MP_IOMUXC_SAI1_RXD2__ENET1_MDC           0x40000044>,
+                          <MX8MP_IOMUXC_SAI1_RXD3__ENET1_MDIO          0x40000044>,
+                          <MX8MP_IOMUXC_SAI1_RXD4__ENET1_RGMII_RD0     0x90>,
+                          <MX8MP_IOMUXC_SAI1_RXD5__ENET1_RGMII_RD1     0x90>,
+                          <MX8MP_IOMUXC_SAI1_RXD6__ENET1_RGMII_RD2     0x90>,
+                          <MX8MP_IOMUXC_SAI1_RXD7__ENET1_RGMII_RD3     0x90>,
+                          <MX8MP_IOMUXC_SAI1_TXC__ENET1_RGMII_RXC      0x90>,
+                          <MX8MP_IOMUXC_SAI1_TXFS__ENET1_RGMII_RX_CTL  0x90>,
+                          <MX8MP_IOMUXC_SAI1_TXD0__ENET1_RGMII_TD0     0x12>,
+                          <MX8MP_IOMUXC_SAI1_TXD1__ENET1_RGMII_TD1     0x12>,
+                          <MX8MP_IOMUXC_SAI1_TXD2__ENET1_RGMII_TD2     0x12>,
+                          <MX8MP_IOMUXC_SAI1_TXD3__ENET1_RGMII_TD3     0x12>,
+                          <MX8MP_IOMUXC_SAI1_TXD4__ENET1_RGMII_TX_CTL  0x12>,
+                          <MX8MP_IOMUXC_SAI1_TXD5__ENET1_RGMII_TXC     0x14>;
+       };
+
+       pinctrl_fec_event: fecevtgrp {
+               fsl,pins = <MX8MP_IOMUXC_SAI1_RXFS__ENET1_1588_EVENT0_IN        0x100>,
+                          <MX8MP_IOMUXC_SAI1_RXC__ENET1_1588_EVENT0_OUT        0x1c0>;
+       };
+
+       pinctrl_fec_phy: fecphygrp {
+               fsl,pins = <MX8MP_IOMUXC_SAI1_RXFS__GPIO4_IO00          0x100>,
+                          <MX8MP_IOMUXC_SAI1_RXC__GPIO4_IO01           0x1c0>;
+       };
+
+       pinctrl_fec_phyalt: fecphyaltgrp {
+               fsl,pins = <MX8MP_IOMUXC_SAI2_TXFS__GPIO4_IO24          0x180>,
+                          <MX8MP_IOMUXC_SAI2_TXC__GPIO4_IO25           0x180>;
+       };
+
+       pinctrl_gpiobutton: gpiobuttongrp {
+               fsl,pins = <MX8MP_IOMUXC_UART3_RXD__GPIO5_IO26          0x10>,
+                          <MX8MP_IOMUXC_UART3_TXD__GPIO5_IO27          0x10>;
+       };
+
+       pinctrl_gpioled: gpioledgrp {
+               fsl,pins = <MX8MP_IOMUXC_SPDIF_EXT_CLK__GPIO5_IO05      0x14>,
+                          <MX8MP_IOMUXC_SPDIF_RX__GPIO5_IO04           0x14>,
+                          <MX8MP_IOMUXC_SPDIF_TX__GPIO5_IO03           0x14>;
+       };
+
+       pinctrl_gpio1: gpio1grp {
+               fsl,pins = <MX8MP_IOMUXC_GPIO1_IO00__GPIO1_IO00         0x10>,
+                          <MX8MP_IOMUXC_GPIO1_IO01__GPIO1_IO01         0x10>,
+                          <MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03         0x10>,
+                          <MX8MP_IOMUXC_GPIO1_IO06__GPIO1_IO06         0x10>,
+                          <MX8MP_IOMUXC_GPIO1_IO07__GPIO1_IO07         0x80>,
+                          <MX8MP_IOMUXC_GPIO1_IO09__GPIO1_IO09         0x80>,
+                          <MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14         0x80>,
+                          <MX8MP_IOMUXC_GPIO1_IO15__GPIO1_IO15         0x80>;
+       };
+
+       pinctrl_gpio4: gpio4grp {
+               fsl,pins = <MX8MP_IOMUXC_SAI1_MCLK__GPIO4_IO20          0x180>,
+                          <MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22           0x180>;
+       };
+
+       pinctrl_hdmi: hdmigrp {
+               fsl,pins = <MX8MP_IOMUXC_HDMI_DDC_SCL__HDMIMIX_HDMI_SCL 0x400001c2>,
+                          <MX8MP_IOMUXC_HDMI_DDC_SDA__HDMIMIX_HDMI_SDA 0x400001c2>,
+                          <MX8MP_IOMUXC_HDMI_HPD__HDMIMIX_HDMI_HPD     0x40000010>,
+                          <MX8MP_IOMUXC_HDMI_CEC__HDMIMIX_HDMI_CEC     0x40000010>;
+       };
+
+       pinctrl_hoggpio2: hoggpio2grp {
+               fsl,pins = <MX8MP_IOMUXC_SD1_DATA5__GPIO2_IO07          0x140>,
+                          <MX8MP_IOMUXC_SD1_RESET_B__GPIO2_IO10        0x140>,
+                          <MX8MP_IOMUXC_SD1_STROBE__GPIO2_IO11         0x140>;
+       };
+
+       pinctrl_i2c2: i2c2grp {
+               fsl,pins = <MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL             0x400001e2>,
+                          <MX8MP_IOMUXC_I2C2_SDA__I2C2_SDA             0x400001e2>;
+       };
+
+       pinctrl_i2c2_gpio: i2c2-gpiogrp {
+               fsl,pins = <MX8MP_IOMUXC_I2C2_SCL__GPIO5_IO16           0x400001e2>,
+                          <MX8MP_IOMUXC_I2C2_SDA__GPIO5_IO17           0x400001e2>;
+       };
+
+       pinctrl_i2c4: i2c4grp {
+               fsl,pins = <MX8MP_IOMUXC_I2C4_SCL__I2C4_SCL             0x400001e2>,
+                          <MX8MP_IOMUXC_I2C4_SDA__I2C4_SDA             0x400001e2>;
+       };
+
+       pinctrl_i2c4_gpio: i2c4-gpiogrp {
+               fsl,pins = <MX8MP_IOMUXC_I2C4_SCL__GPIO5_IO20           0x400001e2>,
+                          <MX8MP_IOMUXC_I2C4_SDA__GPIO5_IO21           0x400001e2>;
+       };
+
+       pinctrl_i2c6: i2c6grp {
+               fsl,pins = <MX8MP_IOMUXC_SD1_DATA0__I2C6_SCL            0x400001e2>,
+                          <MX8MP_IOMUXC_SD1_DATA1__I2C6_SDA            0x400001e2>;
+       };
+
+       pinctrl_i2c6_gpio: i2c6-gpiogrp {
+               fsl,pins = <MX8MP_IOMUXC_SD1_DATA0__GPIO2_IO02          0x400001e2>,
+                          <MX8MP_IOMUXC_SD1_DATA1__GPIO2_IO03          0x400001e2>;
+       };
+
+       pinctrl_lvdsdisplay: lvdsdisplaygrp {
+               fsl,pins = <MX8MP_IOMUXC_SAI5_RXC__GPIO3_IO20           0x10>; /* Power enable */
+       };
+
+       /* LVDS Backlight */
+       pinctrl_pwm2: pwm2grp {
+               fsl,pins = <MX8MP_IOMUXC_SAI5_RXD0__PWM2_OUT            0x14>;
+       };
+
+       /* FAN */
+       pinctrl_pwm3: pwm3grp {
+               fsl,pins = <MX8MP_IOMUXC_I2C3_SDA__PWM3_OUT             0x14>;
+       };
+
+       pinctrl_reg12v0: reg12v0grp {
+               fsl,pins = <MX8MP_IOMUXC_SD1_DATA4__GPIO2_IO06          0x140>; /* VCC12V enable */
+       };
+
+       /* X61 */
+       pinctrl_uart1: uart1grp {
+               fsl,pins = <MX8MP_IOMUXC_SD1_CLK__UART1_DCE_TX          0x140>,
+                          <MX8MP_IOMUXC_SD1_CMD__UART1_DCE_RX          0x140>;
+       };
+
+       /* X61 */
+       pinctrl_uart2: uart2grp {
+               fsl,pins = <MX8MP_IOMUXC_SD1_DATA2__UART2_DCE_TX        0x140>,
+                          <MX8MP_IOMUXC_SD1_DATA3__UART2_DCE_RX        0x140>;
+       };
+
+       pinctrl_uart3: uart3grp {
+               fsl,pins = <MX8MP_IOMUXC_SD1_DATA6__UART3_DCE_TX        0x140>,
+                          <MX8MP_IOMUXC_SD1_DATA7__UART3_DCE_RX        0x140>;
+       };
+
+       pinctrl_uart4: uart4grp {
+               fsl,pins = <MX8MP_IOMUXC_UART4_RXD__UART4_DCE_RX        0x140>,
+                          <MX8MP_IOMUXC_UART4_TXD__UART4_DCE_TX        0x140>;
+       };
+
+       pinctrl_usdhc2: usdhc2grp {
+               fsl,pins = <MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK            0x192>,
+                          <MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD            0x1d2>,
+                          <MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0        0x1d2>,
+                          <MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1        0x1d2>,
+                          <MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2        0x1d2>,
+                          <MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3        0x1d2>,
+                          <MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT     0xc0>;
+       };
+
+       pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+               fsl,pins = <MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK            0x194>,
+                          <MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD            0x1d4>,
+                          <MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0        0x1d4>,
+                          <MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1        0x1d4>,
+                          <MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2        0x1d4>,
+                          <MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3        0x1d4>,
+                          <MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT     0xc0>;
+       };
+
+       pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+               fsl,pins = <MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK            0x194>,
+                          <MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD            0x1d4>,
+                          <MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0        0x1d4>,
+                          <MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1        0x1d4>,
+                          <MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2        0x1d4>,
+                          <MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3        0x1d4>,
+                          <MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT     0xc0>;
+       };
+
+       pinctrl_usdhc2_gpio: usdhc2-gpiogrp {
+               fsl,pins = <MX8MP_IOMUXC_SD2_CD_B__GPIO2_IO12           0x1c0>;
+       };
+};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql.dtsi
new file mode 100644 (file)
index 0000000..7bd680a
--- /dev/null
@@ -0,0 +1,284 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright 2021-2022 TQ-Systems GmbH
+ * Author: Alexander Stein <alexander.stein@tq-group.com>
+ */
+
+#include "imx8mp.dtsi"
+
+/ {
+       model = "TQ-Systems i.MX8MPlus TQMa8MPxL";
+       compatible = "tq,imx8mp-tqma8mpql", "fsl,imx8mp";
+
+       memory@40000000 {
+               device_type = "memory";
+               reg = <0x0 0x40000000 0 0x80000000>;
+       };
+
+       /* identical to buck4_reg, but should never change */
+       reg_vcc3v3: regulator-vcc3v3 {
+               compatible = "regulator-fixed";
+               regulator-name = "VCC3V3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-always-on;
+       };
+
+       /* e-MMC IO, needed for HS modes */
+       reg_vcc1v8: regulator-vcc1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "VCC1V8";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-always-on;
+       };
+};
+
+&A53_0 {
+       cpu-supply = <&buck2_reg>;
+};
+
+&flexspi {
+       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 = <80000000>;
+               spi-tx-bus-width = <1>;
+               spi-rx-bus-width = <4>;
+       };
+};
+
+&i2c1 {
+       clock-frequency = <384000>;
+       pinctrl-names = "default", "gpio";
+       pinctrl-0 = <&pinctrl_i2c1>;
+       pinctrl-1 = <&pinctrl_i2c1_gpio>;
+       scl-gpios = <&gpio5 14 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       sda-gpios = <&gpio5 15 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+       status = "okay";
+
+       /* NXP SE97BTP with temperature sensor + eeprom */
+       se97: temperature-sensor-eeprom@1b {
+               compatible = "nxp,se97", "jedec,jc-42.4-temp";
+               reg = <0x1b>;
+       };
+
+       pmic: pmic@25 {
+               reg = <0x25>;
+               compatible = "nxp,pca9450c";
+
+               /* PMIC PCA9450 PMIC_nINT GPIO1_IO08 */
+               pinctrl-0 = <&pinctrl_pmic>;
+               pinctrl-names = "default";
+               interrupt-parent = <&gpio1>;
+               interrupts = <8 IRQ_TYPE_LEVEL_LOW>;
+
+               regulators {
+                       /* V_0V85_SOC: 0.85 .. 0.95 */
+                       buck1_reg: BUCK1 {
+                               regulator-name = "BUCK1";
+                               regulator-min-microvolt = <850000>;
+                               regulator-max-microvolt = <950000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                               regulator-ramp-delay = <3125>;
+                       };
+
+                       /* VDD_ARM */
+                       buck2_reg: BUCK2 {
+                               regulator-name = "BUCK2";
+                               regulator-min-microvolt = <850000>;
+                               regulator-max-microvolt = <1000000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                               nxp,dvs-run-voltage = <950000>;
+                               nxp,dvs-standby-voltage = <850000>;
+                               regulator-ramp-delay = <3125>;
+                       };
+
+                       /* VCC3V3 -> VMMC, ... must not be changed */
+                       buck4_reg: BUCK4 {
+                               regulator-name = "BUCK4";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       /* V_1V8 -> VQMMC, SPI-NOR, ... must not be changed */
+                       buck5_reg: BUCK5 {
+                               regulator-name = "BUCK5";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       /* V_1V1 -> RAM, ... must not be changed */
+                       buck6_reg: BUCK6 {
+                               regulator-name = "BUCK6";
+                               regulator-min-microvolt = <1100000>;
+                               regulator-max-microvolt = <1100000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       /* V_1V8_SNVS */
+                       ldo1_reg: LDO1 {
+                               regulator-name = "LDO1";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       /* V_1V8_ANA */
+                       ldo3_reg: LDO3 {
+                               regulator-name = "LDO3";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       /* unused */
+                       ldo4_reg: LDO4 {
+                               regulator-name = "LDO4";
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+
+                       /* VCC SD IO - switched using SD2 VSELECT */
+                       ldo5_reg: LDO5 {
+                               regulator-name = "LDO5";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+               };
+       };
+
+       pcf85063: rtc@51 {
+               compatible = "nxp,pcf85063a";
+               reg = <0x51>;
+       };
+
+       at24c02: eeprom@53 {
+               compatible = "nxp,se97b", "atmel,24c02";
+               read-only;
+               reg = <0x53>;
+               pagesize = <16>;
+               vcc-supply = <&reg_vcc3v3>;
+       };
+
+       m24c64: eeprom@57 {
+               compatible = "atmel,24c64";
+               reg = <0x57>;
+               pagesize = <32>;
+               vcc-supply = <&reg_vcc3v3>;
+       };
+};
+
+&usdhc3 {
+       pinctrl-names = "default", "state_100mhz", "state_200mhz";
+       pinctrl-0 = <&pinctrl_usdhc3>;
+       pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
+       pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
+       bus-width = <8>;
+       non-removable;
+       no-sd;
+       no-sdio;
+       vmmc-supply = <&reg_vcc3v3>;
+       vqmmc-supply = <&reg_vcc1v8>;
+       status = "okay";
+};
+
+&wdog1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_wdog>;
+       fsl,ext-reset-output;
+       status = "okay";
+};
+
+&iomuxc {
+       pinctrl_flexspi0: flexspi0grp {
+               fsl,pins = <MX8MP_IOMUXC_NAND_ALE__FLEXSPI_A_SCLK       0x142>,
+                          <MX8MP_IOMUXC_NAND_CE0_B__FLEXSPI_A_SS0_B    0x82>,
+                          <MX8MP_IOMUXC_NAND_DATA00__FLEXSPI_A_DATA00  0x82>,
+                          <MX8MP_IOMUXC_NAND_DATA01__FLEXSPI_A_DATA01  0x82>,
+                          <MX8MP_IOMUXC_NAND_DATA02__FLEXSPI_A_DATA02  0x82>,
+                          <MX8MP_IOMUXC_NAND_DATA03__FLEXSPI_A_DATA03  0x82>;
+       };
+
+       pinctrl_i2c1: i2c1grp {
+               fsl,pins = <MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL             0x400001e2>,
+                          <MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA             0x400001e2>;
+       };
+
+       pinctrl_i2c1_gpio: i2c1-gpiogrp {
+               fsl,pins = <MX8MP_IOMUXC_I2C1_SCL__GPIO5_IO14           0x400001e2>,
+                          <MX8MP_IOMUXC_I2C1_SDA__GPIO5_IO15           0x400001e2>;
+       };
+
+       pinctrl_pmic: pmicirqgrp {
+               fsl,pins = <MX8MP_IOMUXC_GPIO1_IO08__GPIO1_IO08         0x1c0>;
+       };
+
+       pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
+               fsl,pins = <MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19        0x10>;
+       };
+
+       pinctrl_usdhc3: usdhc3grp {
+               fsl,pins = <MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK          0x194>,
+                          <MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD          0x1d4>,
+                          <MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0      0x1d4>,
+                          <MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1      0x1d4>,
+                          <MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2      0x1d4>,
+                          <MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3      0x1d4>,
+                          <MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4        0x1d4>,
+                          <MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5       0x1d4>,
+                          <MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6       0x1d4>,
+                          <MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7         0x1d4>,
+                          <MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE      0x84>,
+                          <MX8MP_IOMUXC_NAND_READY_B__USDHC3_RESET_B   0x84>;
+       };
+
+       pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp {
+               fsl,pins = <MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK          0x194>,
+                          <MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD          0x1d4>,
+                          <MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0      0x1d4>,
+                          <MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1      0x1d4>,
+                          <MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2      0x1d4>,
+                          <MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3      0x1d4>,
+                          <MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4        0x1d4>,
+                          <MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5       0x1d4>,
+                          <MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6       0x1d4>,
+                          <MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7         0x1d4>,
+                          <MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE      0x84>,
+                          <MX8MP_IOMUXC_NAND_READY_B__USDHC3_RESET_B   0x84>;
+       };
+
+       pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp {
+               fsl,pins = <MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK          0x194>,
+                          <MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD          0x1d4>,
+                          <MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0      0x1d4>,
+                          <MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1      0x1d4>,
+                          <MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2      0x1d4>,
+                          <MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3      0x1d4>,
+                          <MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4        0x1d4>,
+                          <MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5       0x1d4>,
+                          <MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6       0x1d4>,
+                          <MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7         0x1d4>,
+                          <MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE      0x84>,
+                          <MX8MP_IOMUXC_NAND_READY_B__USDHC3_RESET_B   0x84>;
+       };
+
+       pinctrl_wdog: wdoggrp {
+               fsl,pins = <MX8MP_IOMUXC_GPIO1_IO02__WDOG1_WDOG_B       0x1c4>;
+       };
+};
index 101d311..5212155 100644 (file)
 
        pinctrl_hog: hoggrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_GPIO1_IO09__GPIO1_IO09     0x40000041 /* DIO0 */
-                       MX8MP_IOMUXC_GPIO1_IO11__GPIO1_IO11     0x40000041 /* DIO1 */
-                       MX8MP_IOMUXC_NAND_DQS__GPIO3_IO14       0x40000041 /* M2SKT_OFF# */
-                       MX8MP_IOMUXC_SD2_DATA2__GPIO2_IO17      0x40000159 /* PCIE1_WDIS# */
-                       MX8MP_IOMUXC_SD2_DATA3__GPIO2_IO18      0x40000159 /* PCIE2_WDIS# */
-                       MX8MP_IOMUXC_SD2_CMD__GPIO2_IO14        0x40000159 /* PCIE3_WDIS# */
-                       MX8MP_IOMUXC_NAND_DATA00__GPIO3_IO06    0x40000041 /* M2SKT_RST# */
-                       MX8MP_IOMUXC_SAI1_TXD6__GPIO4_IO18      0x40000159 /* M2SKT_WDIS# */
-                       MX8MP_IOMUXC_NAND_ALE__GPIO3_IO00       0x40000159 /* M2SKT_GDIS# */
+                       MX8MP_IOMUXC_GPIO1_IO09__GPIO1_IO09     0x40000040 /* DIO0 */
+                       MX8MP_IOMUXC_GPIO1_IO11__GPIO1_IO11     0x40000040 /* DIO1 */
+                       MX8MP_IOMUXC_NAND_DQS__GPIO3_IO14       0x40000040 /* M2SKT_OFF# */
+                       MX8MP_IOMUXC_SD2_DATA2__GPIO2_IO17      0x40000150 /* PCIE1_WDIS# */
+                       MX8MP_IOMUXC_SD2_DATA3__GPIO2_IO18      0x40000150 /* PCIE2_WDIS# */
+                       MX8MP_IOMUXC_SD2_CMD__GPIO2_IO14        0x40000150 /* PCIE3_WDIS# */
+                       MX8MP_IOMUXC_NAND_DATA00__GPIO3_IO06    0x40000040 /* M2SKT_RST# */
+                       MX8MP_IOMUXC_SAI1_TXD6__GPIO4_IO18      0x40000150 /* M2SKT_WDIS# */
+                       MX8MP_IOMUXC_NAND_ALE__GPIO3_IO00       0x40000150 /* M2SKT_GDIS# */
                        MX8MP_IOMUXC_SAI3_TXD__GPIO5_IO01       0x40000104 /* UART_TERM */
                        MX8MP_IOMUXC_SAI3_TXFS__GPIO4_IO31      0x40000104 /* UART_RS485 */
                        MX8MP_IOMUXC_SAI3_TXC__GPIO5_IO00       0x40000104 /* UART_HALF */
 
        pinctrl_accel: accelgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_GPIO1_IO07__GPIO1_IO07     0x159
+                       MX8MP_IOMUXC_GPIO1_IO07__GPIO1_IO07     0x150
                >;
        };
 
        pinctrl_eqos: eqosgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC                             0x3
-                       MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO                           0x3
-                       MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0               0x91
-                       MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1               0x91
-                       MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2               0x91
-                       MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3               0x91
-                       MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK       0x91
-                       MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL         0x91
-                       MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0               0x1f
-                       MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1               0x1f
-                       MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2               0x1f
-                       MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3               0x1f
-                       MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL         0x1f
-                       MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK       0x1f
-                       MX8MP_IOMUXC_SAI3_RXD__GPIO4_IO30               0x141 /* RST# */
-                       MX8MP_IOMUXC_SAI3_RXFS__GPIO4_IO28              0x159 /* IRQ# */
+                       MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC                             0x2
+                       MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO                           0x2
+                       MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0               0x90
+                       MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1               0x90
+                       MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2               0x90
+                       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_SAI3_RXD__GPIO4_IO30               0x140 /* RST# */
+                       MX8MP_IOMUXC_SAI3_RXFS__GPIO4_IO28              0x150 /* IRQ# */
                >;
        };
 
        pinctrl_fec: fecgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SAI1_RXD4__ENET1_RGMII_RD0         0x91
-                       MX8MP_IOMUXC_SAI1_RXD5__ENET1_RGMII_RD1         0x91
-                       MX8MP_IOMUXC_SAI1_RXD6__ENET1_RGMII_RD2         0x91
-                       MX8MP_IOMUXC_SAI1_RXD7__ENET1_RGMII_RD3         0x91
-                       MX8MP_IOMUXC_SAI1_TXC__ENET1_RGMII_RXC          0x91
-                       MX8MP_IOMUXC_SAI1_TXFS__ENET1_RGMII_RX_CTL      0x91
-                       MX8MP_IOMUXC_SAI1_TXD0__ENET1_RGMII_TD0         0x1f
-                       MX8MP_IOMUXC_SAI1_TXD1__ENET1_RGMII_TD1         0x1f
-                       MX8MP_IOMUXC_SAI1_TXD2__ENET1_RGMII_TD2         0x1f
-                       MX8MP_IOMUXC_SAI1_TXD3__ENET1_RGMII_TD3         0x1f
-                       MX8MP_IOMUXC_SAI1_TXD4__ENET1_RGMII_TX_CTL      0x1f
-                       MX8MP_IOMUXC_SAI1_TXD5__ENET1_RGMII_TXC         0x1f
-                       MX8MP_IOMUXC_SAI1_RXFS__ENET1_1588_EVENT0_IN    0x141
-                       MX8MP_IOMUXC_SAI1_RXC__ENET1_1588_EVENT0_OUT    0x141
+                       MX8MP_IOMUXC_SAI1_RXD4__ENET1_RGMII_RD0         0x90
+                       MX8MP_IOMUXC_SAI1_RXD5__ENET1_RGMII_RD1         0x90
+                       MX8MP_IOMUXC_SAI1_RXD6__ENET1_RGMII_RD2         0x90
+                       MX8MP_IOMUXC_SAI1_RXD7__ENET1_RGMII_RD3         0x90
+                       MX8MP_IOMUXC_SAI1_TXC__ENET1_RGMII_RXC          0x90
+                       MX8MP_IOMUXC_SAI1_TXFS__ENET1_RGMII_RX_CTL      0x90
+                       MX8MP_IOMUXC_SAI1_TXD0__ENET1_RGMII_TD0         0x16
+                       MX8MP_IOMUXC_SAI1_TXD1__ENET1_RGMII_TD1         0x16
+                       MX8MP_IOMUXC_SAI1_TXD2__ENET1_RGMII_TD2         0x16
+                       MX8MP_IOMUXC_SAI1_TXD3__ENET1_RGMII_TD3         0x16
+                       MX8MP_IOMUXC_SAI1_TXD4__ENET1_RGMII_TX_CTL      0x16
+                       MX8MP_IOMUXC_SAI1_TXD5__ENET1_RGMII_TXC         0x16
+                       MX8MP_IOMUXC_SAI1_RXFS__ENET1_1588_EVENT0_IN    0x140
+                       MX8MP_IOMUXC_SAI1_RXC__ENET1_1588_EVENT0_OUT    0x140
                >;
        };
 
 
        pinctrl_gsc: gscgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SAI1_MCLK__GPIO4_IO20      0x159
+                       MX8MP_IOMUXC_SAI1_MCLK__GPIO4_IO20      0x150
                >;
        };
 
        pinctrl_i2c1: i2c1grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL         0x400001c3
-                       MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA         0x400001c3
+                       MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL         0x400001c2
+                       MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA         0x400001c2
                >;
        };
 
        pinctrl_i2c2: i2c2grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL         0x400001c3
-                       MX8MP_IOMUXC_I2C2_SDA__I2C2_SDA         0x400001c3
+                       MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL         0x400001c2
+                       MX8MP_IOMUXC_I2C2_SDA__I2C2_SDA         0x400001c2
                >;
        };
 
        pinctrl_i2c3: i2c3grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL         0x400001c3
-                       MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA         0x400001c3
+                       MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL         0x400001c2
+                       MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA         0x400001c2
                >;
        };
 
        pinctrl_i2c4: i2c4grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_I2C4_SCL__I2C4_SCL         0x400001c3
-                       MX8MP_IOMUXC_I2C4_SDA__I2C4_SDA         0x400001c3
+                       MX8MP_IOMUXC_I2C4_SCL__I2C4_SCL         0x400001c2
+                       MX8MP_IOMUXC_I2C4_SDA__I2C4_SDA         0x400001c2
                >;
        };
 
        pinctrl_ksz: kszgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SAI3_RXC__GPIO4_IO29       0x159 /* IRQ# */
-                       MX8MP_IOMUXC_SAI3_MCLK__GPIO5_IO02      0x141 /* RST# */
+                       MX8MP_IOMUXC_SAI3_RXC__GPIO4_IO29       0x150 /* IRQ# */
+                       MX8MP_IOMUXC_SAI3_MCLK__GPIO5_IO02      0x140 /* RST# */
                >;
        };
 
        pinctrl_gpio_leds: ledgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SD2_DATA0__GPIO2_IO15      0x19
-                       MX8MP_IOMUXC_SD2_DATA1__GPIO2_IO16      0x19
+                       MX8MP_IOMUXC_SD2_DATA0__GPIO2_IO15      0x10
+                       MX8MP_IOMUXC_SD2_DATA1__GPIO2_IO16      0x10
                >;
        };
 
        pinctrl_pmic: pmicgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_NAND_DATA01__GPIO3_IO07    0x141
+                       MX8MP_IOMUXC_NAND_DATA01__GPIO3_IO07    0x140
                >;
        };
 
        pinctrl_pps: ppsgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_GPIO1_IO12__GPIO1_IO12     0x141
+                       MX8MP_IOMUXC_GPIO1_IO12__GPIO1_IO12     0x140
                >;
        };
 
 
        pinctrl_reg_usb2: regusb2grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_GPIO1_IO06__GPIO1_IO06     0x141
+                       MX8MP_IOMUXC_GPIO1_IO06__GPIO1_IO06     0x140
                >;
        };
 
        pinctrl_reg_wifi: regwifigrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_NAND_DATA03__GPIO3_IO09    0x119
+                       MX8MP_IOMUXC_NAND_DATA03__GPIO3_IO09    0x110
                >;
        };
 
 
        pinctrl_uart3_gpio: uart3gpiogrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_NAND_DATA02__GPIO3_IO08    0x119
+                       MX8MP_IOMUXC_NAND_DATA02__GPIO3_IO08    0x110
                >;
        };
 
index fb17e32..c5987bd 100644 (file)
@@ -49,7 +49,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_gpio_keys>;
 
-               wakeup {
+               button-wakeup {
                        debounce-interval = <10>;
                        /* Verdin CTRL_WAKE1_MICO# (SODIMM 252) */
                        gpios = <&gpio4 0 GPIO_ACTIVE_LOW>;
        };
 };
 
+&cpu_alert0 {
+       temperature = <95000>;
+};
+
+&cpu_crit0 {
+       temperature = <105000>;
+};
+
 /* Verdin SPI_1 */
 &ecspi1 {
        #address-cells = <1>;
index d9542df..fe178b7 100644 (file)
        clk_ext4: clock-ext4 {
                compatible = "fixed-clock";
                #clock-cells = <0>;
-               clock-frequency= <133000000>;
+               clock-frequency = <133000000>;
                clock-output-names = "clk_ext4";
        };
 
                arm,no-tick-in-suspend;
        };
 
-       soc@0 {
+       soc: soc@0 {
                compatible = "fsl,imx8mp-soc", "simple-bus";
                #address-cells = <1>;
                #size-cells = <1>;
                                        pgc_ispdwp: power-domain@18 {
                                                #power-domain-cells = <0>;
                                                reg = <IMX8MP_POWER_DOMAIN_MEDIAMIX_ISPDWP>;
-                                               clocks = <&clk IMX8MP_CLK_MEDIA_ISP_DIV>;
+                                               clocks = <&clk IMX8MP_CLK_MEDIA_ISP_ROOT>;
                                        };
                                };
                        };
                                        compatible = "fsl,sec-v4.0-job-ring";
                                        reg = <0x1000 0x1000>;
                                        interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
+                                       status = "disabled";
                                };
 
                                sec_jr1: jr@2000 {
                                         <&clk IMX8MP_CLK_USDHC1_ROOT>;
                                clock-names = "ipg", "ahb", "per";
                                fsl,tuning-start-tap = <20>;
-                               fsl,tuning-step= <2>;
+                               fsl,tuning-step = <2>;
                                bus-width = <4>;
                                status = "disabled";
                        };
                                         <&clk IMX8MP_CLK_USDHC2_ROOT>;
                                clock-names = "ipg", "ahb", "per";
                                fsl,tuning-start-tap = <20>;
-                               fsl,tuning-step= <2>;
+                               fsl,tuning-step = <2>;
                                bus-width = <4>;
                                status = "disabled";
                        };
                                         <&clk IMX8MP_CLK_USDHC3_ROOT>;
                                clock-names = "ipg", "ahb", "per";
                                fsl,tuning-start-tap = <20>;
-                               fsl,tuning-step= <2>;
+                               fsl,tuning-step = <2>;
                                bus-width = <4>;
                                status = "disabled";
                        };
                        };
                };
 
+               noc: interconnect@32700000 {
+                       compatible = "fsl,imx8mp-noc", "fsl,imx8m-noc";
+                       reg = <0x32700000 0x100000>;
+                       clocks = <&clk IMX8MP_CLK_NOC>;
+                       #interconnect-cells = <1>;
+                       operating-points-v2 = <&noc_opp_table>;
+
+                       noc_opp_table: opp-table {
+                               compatible = "operating-points-v2";
+
+                               opp-200M {
+                                       opp-hz = /bits/ 64 <200000000>;
+                               };
+
+                               opp-1000M {
+                                       opp-hz = /bits/ 64 <1000000000>;
+                               };
+                       };
+               };
+
                aips4: bus@32c00000 {
                        compatible = "fsl,aips-bus", "simple-bus";
                        reg = <0x32c00000 0x400000>;
index 99fed35..82387b9 100644 (file)
                linux,autosuspend-period = <125>;
        };
 
+       audio_codec_bt_sco: audio-codec-bt-sco {
+               compatible = "linux,bt-sco";
+               #sound-dai-cells = <1>;
+       };
+
        wm8524: audio-codec {
                #sound-dai-cells = <0>;
                compatible = "wlf,wm8524";
                wlf,mute-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>;
        };
 
+       sound-bt-sco {
+               compatible = "simple-audio-card";
+               simple-audio-card,name = "bt-sco-audio";
+               simple-audio-card,format = "dsp_a";
+               simple-audio-card,bitclock-inversion;
+               simple-audio-card,frame-master = <&btcpu>;
+               simple-audio-card,bitclock-master = <&btcpu>;
+
+               btcpu: simple-audio-card,cpu {
+                       sound-dai = <&sai3>;
+                       dai-tdm-slot-num = <2>;
+                       dai-tdm-slot-width = <16>;
+               };
+
+               simple-audio-card,codec {
+                       sound-dai = <&audio_codec_bt_sco 1>;
+               };
+       };
+
        sound-wm8524 {
                compatible = "simple-audio-card";
                simple-audio-card,name = "wm8524-audio";
        status = "okay";
 };
 
+&sai3 {
+       #sound-dai-cells = <0>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_sai3>;
+       assigned-clocks = <&clk IMX8MQ_CLK_SAI3>;
+       assigned-clock-parents = <&clk IMX8MQ_AUDIO_PLL1_OUT>;
+       assigned-clock-rates = <24576000>;
+       status = "okay";
+};
+
 &snvs_pwrkey {
        status = "okay";
 };
                >;
        };
 
+       pinctrl_sai3: sai3grp {
+               fsl,pins = <
+                       MX8MQ_IOMUXC_SAI3_TXFS_SAI3_TX_SYNC     0xd6
+                       MX8MQ_IOMUXC_SAI3_TXC_SAI3_TX_BCLK      0xd6
+                       MX8MQ_IOMUXC_SAI3_TXD_SAI3_TX_DATA0     0xd6
+                       MX8MQ_IOMUXC_SAI3_RXD_SAI3_RX_DATA0     0xd6
+               >;
+       };
+
        pinctrl_spdif1: spdif1grp {
                fsl,pins = <
                        MX8MQ_IOMUXC_SPDIF_TX_SPDIF1_OUT        0xd6
index b86f188..6445c6b 100644 (file)
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_gpio_keys>;
 
-               btn1 {
+               button-1 {
                        label = "VOL_UP";
                        gpios = <&gpio4 21 GPIO_ACTIVE_LOW>;
                        wakeup-source;
                        linux,code = <KEY_VOLUMEUP>;
                };
 
-               btn2 {
+               button-2 {
                        label = "VOL_DOWN";
                        gpios = <&gpio4 22 GPIO_ACTIVE_LOW>;
                        wakeup-source;
                        linux,code = <KEY_VOLUMEDOWN>;
                };
 
-               wwan-wake {
+               button-3 {
                        label = "WWAN_WAKE";
                        gpios = <&gpio3 8 GPIO_ACTIVE_LOW>;
                        interrupt-parent = <&gpio3>;
index 587e55a..9eec8a7 100644 (file)
@@ -37,7 +37,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_keys>;
 
-               vol-down {
+               key-vol-down {
                        label = "VOL_DOWN";
                        gpios = <&gpio1 17 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEDOWN>;
@@ -45,7 +45,7 @@
                        wakeup-source;
                };
 
-               vol-up {
+               key-vol-up {
                        label = "VOL_UP";
                        gpios = <&gpio1 16 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
index f70fb32..9dda2a1 100644 (file)
@@ -26,7 +26,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_gpio_keys>;
 
-               power {
+               button-power {
                        label = "Power Button";
                        gpios = <&gpio1 7 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
                                pinctrl-names = "default";
                                pinctrl-0 = <&pinctrl_reg_arm_dram>;
                                reg = <0x60>;
-                               regulator-min-microvolt =  <900000>;
+                               regulator-min-microvolt = <900000>;
                                regulator-max-microvolt = <1000000>;
                                regulator-always-on;
                                vsel-gpios = <&gpio3 24 GPIO_ACTIVE_HIGH>;
                                pinctrl-names = "default";
                                pinctrl-0 = <&pinctrl_reg_soc_gpu_vpu>;
                                reg = <0x60>;
-                               regulator-min-microvolt =  <900000>;
+                               regulator-min-microvolt = <900000>;
                                regulator-max-microvolt = <1000000>;
                                regulator-always-on;
                                vsel-gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>;
index 2222ef7..4e05120 100644 (file)
        status = "okay";
 
        usbhub: usbhub@2c {
-               compatible ="microchip,usb2513b";
+               compatible = "microchip,usb2513b";
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_usbhub>;
                reg = <0x2c>;
index 49eadb0..e9f0cdd 100644 (file)
@@ -94,7 +94,7 @@
        clk_ext4: clock-ext4 {
                compatible = "fixed-clock";
                #clock-cells = <0>;
-               clock-frequency= <133000000>;
+               clock-frequency = <133000000>;
                clock-output-names = "clk_ext4";
        };
 
                arm,no-tick-in-suspend;
        };
 
-       soc@0 {
+       soc: soc@0 {
                compatible = "fsl,imx8mq-soc", "simple-bus";
                #address-cells = <1>;
                #size-cells = <1>;
                nvmem-cells = <&imx8mq_uid>;
                nvmem-cell-names = "soc_unique_id";
 
-               bus@30000000 { /* AIPS1 */
+               aips1: bus@30000000 { /* AIPS1 */
                        compatible = "fsl,aips-bus", "simple-bus";
                        reg = <0x30000000 0x400000>;
                        #address-cells = <1>;
                                                      <0x00030005 0x00000053>,
                                                      <0x00030006 0x0000005f>,
                                                      <0x00030007 0x00000071>;
-                               #thermal-sensor-cells =  <1>;
+                               #thermal-sensor-cells = <1>;
                        };
 
                        wdog1: watchdog@30280000 {
                        };
                };
 
-               bus@30400000 { /* AIPS2 */
+               aips2: bus@30400000 { /* AIPS2 */
                        compatible = "fsl,aips-bus", "simple-bus";
                        reg = <0x30400000 0x400000>;
                        #address-cells = <1>;
                        };
                };
 
-               bus@30800000 { /* AIPS3 */
+               aips3: bus@30800000 { /* AIPS3 */
                        compatible = "fsl,aips-bus", "simple-bus";
                        reg = <0x30800000 0x400000>;
                        #address-cells = <1>;
                                        compatible = "fsl,sec-v4.0-job-ring";
                                        reg = <0x1000 0x1000>;
                                        interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
+                                       status = "disabled";
                                };
 
                                sec_jr1: jr@2000 {
                        };
                };
 
-               bus@32c00000 { /* AIPS4 */
+               aips4: bus@32c00000 { /* AIPS4 */
                        compatible = "fsl,aips-bus", "simple-bus";
                        reg = <0x32c00000 0x400000>;
                        #address-cells = <1>;
index 4f76701..c9c2b65 100644 (file)
                             <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>; /* Hypervisor */
        };
 
-       scu {
+       system-controller {
                compatible = "fsl,imx-scu";
                mbox-names = "tx0",
                             "rx0",
                          &lsio_mu1 1 0
                          &lsio_mu1 3 3>;
 
-               pd: imx8qx-pd {
+               pd: power-controller {
                        compatible = "fsl,imx8qm-scu-pd", "fsl,scu-pd";
                        #power-domain-cells = <1>;
                };
index 144fc9e..a08e70f 100644 (file)
@@ -16,7 +16,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_gpiokeys>;
 
-               wakeup {
+               key-wakeup {
                        label = "Wake-Up";
                        gpios = <&lsio_gpio3 10 GPIO_ACTIVE_HIGH>;
                        linux,code = <KEY_WAKEUP>;
 
 /* Colibri UART_B */
 &lpuart0 {
-       status= "okay";
+       status = "okay";
 };
 
 /* Colibri UART_C */
 &lpuart2 {
-       status= "okay";
+       status = "okay";
 };
 
 /* Colibri UART_A */
 &lpuart3 {
-       status= "okay";
+       status = "okay";
 };
 
 /* Colibri FastEthernet */
index a79ae33..f4ea18b 100644 (file)
                method = "smc";
        };
 
-       scu {
+       system-controller {
                compatible = "fsl,imx-scu";
                mbox-names = "tx0",
                             "rx0",
                          &lsio_mu1 1 0
                          &lsio_mu1 3 3>;
 
-               pd: imx8qx-pd {
+               pd: power-controller {
                        compatible = "fsl,imx8qxp-scu-pd", "fsl,scu-pd";
                        #power-domain-cells = <1>;
                };
 
                clk: clock-controller {
-                       compatible = "fsl,imx8qxp-clk";
+                       compatible = "fsl,imx8qxp-clk", "fsl,scu-clk";
                        #clock-cells = <2>;
-                       clocks = <&xtal32k &xtal24m>;
-                       clock-names = "xtal_32KHz", "xtal_24Mhz";
                };
 
                iomuxc: pinctrl {
                        compatible = "fsl,imx8qxp-iomuxc";
                };
 
-               ocotp: imx8qx-ocotp {
+               ocotp: ocotp {
                        compatible = "fsl,imx8qxp-scu-ocotp";
                        #address-cells = <1>;
                        #size-cells = <1>;
                };
 
-               scu_key: scu-key {
+               scu_key: keys {
                        compatible = "fsl,imx8qxp-sc-key", "fsl,imx-sc-key";
                        linux,keycodes = <KEY_POWER>;
                        status = "disabled";
        };
 
        thermal_zones: thermal-zones {
-               cpu-thermal0 {
+               cpu0-thermal {
                        polling-delay-passive = <250>;
                        polling-delay = <2000>;
                        thermal-sensors = <&tsens IMX_SC_R_SYSTEM>;
index 09f7364..60c1b01 100644 (file)
                };
        };
 
-       soc@0 {
+       soc: soc@0 {
                compatible = "simple-bus";
                #address-cells = <1>;
                #size-cells = <1>;
                                clock-names = "ipg", "ahb", "per";
                                power-domains = <&scmi_devpd IMX8ULP_PD_USDHC0>;
                                fsl,tuning-start-tap = <20>;
-                               fsl,tuning-step= <2>;
+                               fsl,tuning-step = <2>;
                                bus-width = <4>;
                                status = "disabled";
                        };
                                clock-names = "ipg", "ahb", "per";
                                power-domains = <&scmi_devpd IMX8ULP_PD_USDHC1>;
                                fsl,tuning-start-tap = <20>;
-                               fsl,tuning-step= <2>;
+                               fsl,tuning-step = <2>;
                                bus-width = <4>;
                                status = "disabled";
                        };
                                clock-names = "ipg", "ahb", "per";
                                power-domains = <&scmi_devpd IMX8ULP_PD_USDHC2_USB1>;
                                fsl,tuning-start-tap = <20>;
-                               fsl,tuning-step= <2>;
+                               fsl,tuning-step = <2>;
                                bus-width = <4>;
                                status = "disabled";
                        };
                };
 
-               gpioe: gpio@2d000000 {
+               gpioe: gpio@2d000080 {
                                compatible = "fsl,imx8ulp-gpio", "fsl,imx7ulp-gpio";
                                reg = <0x2d000080 0x1000>, <0x2d000040 0x40>;
                                gpio-controller;
                                gpio-ranges = <&iomuxc1 0 32 24>;
                };
 
-               gpiof: gpio@2d010000 {
+               gpiof: gpio@2d010080 {
                                compatible = "fsl,imx8ulp-gpio", "fsl,imx7ulp-gpio";
                                reg = <0x2d010080 0x1000>, <0x2d010040 0x40>;
                                gpio-controller;
                        };
                };
 
-               gpiod: gpio@2e200000 {
+               gpiod: gpio@2e200080 {
                        compatible = "fsl,imx8ulp-gpio", "fsl,imx7ulp-gpio";
                        reg = <0x2e200080 0x1000>, <0x2e200040 0x40>;
                        gpio-controller;
diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts
new file mode 100644 (file)
index 0000000..69786c3
--- /dev/null
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2022 NXP
+ */
+
+/dts-v1/;
+
+#include "imx93.dtsi"
+
+/ {
+       model = "NXP i.MX93 11X11 EVK board";
+       compatible = "fsl,imx93-11x11-evk", "fsl,imx93";
+
+       chosen {
+               stdout-path = &lpuart1;
+       };
+
+       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 = <&gpio3 7 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+       };
+};
+
+&mu1 {
+       status = "okay";
+};
+
+&mu2 {
+       status = "okay";
+};
+
+&lpuart1 { /* console */
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_uart1>;
+       status = "okay";
+};
+
+&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";
+};
+
+&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;
+};
+
+&iomuxc {
+       pinctrl_uart1: uart1grp {
+               fsl,pins = <
+                       MX93_PAD_UART1_RXD__LPUART1_RX                  0x31e
+                       MX93_PAD_UART1_TXD__LPUART1_TX                  0x31e
+               >;
+       };
+
+       pinctrl_usdhc1: usdhc1grp {
+               fsl,pins = <
+                       MX93_PAD_SD1_CLK__USDHC1_CLK            0x17fe
+                       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      0x17fe
+               >;
+       };
+
+       pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
+               fsl,pins = <
+                       MX93_PAD_SD2_RESET_B__GPIO3_IO07        0x31e
+               >;
+       };
+
+       pinctrl_usdhc2_gpio: usdhc2gpiogrp {
+               fsl,pins = <
+                       MX93_PAD_SD2_CD_B__GPIO3_IO00           0x31e
+               >;
+       };
+
+       pinctrl_usdhc2: usdhc2grp {
+               fsl,pins = <
+                       MX93_PAD_SD2_CLK__USDHC2_CLK            0x17fe
+                       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
+               >;
+       };
+};
diff --git a/arch/arm64/boot/dts/freescale/imx93-pinfunc.h b/arch/arm64/boot/dts/freescale/imx93-pinfunc.h
new file mode 100755 (executable)
index 0000000..4298a14
--- /dev/null
@@ -0,0 +1,623 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright 2022 NXP
+ */
+
+#ifndef __DTS_IMX93_PINFUNC_H
+#define __DTS_IMX93_PINFUNC_H
+
+/*
+ * The pin function ID is a tuple of
+ * <mux_reg conf_reg input_reg mux_mode input_val>
+ */
+#define MX93_PAD_DAP_TDI__JTAG_MUX_TDI                            0x0000 0x01B0 0x03D8 0x0 0x0
+#define MX93_PAD_DAP_TDI__MQS2_LEFT                               0x0000 0x01B0 0x0000 0x1 0x0
+#define MX93_PAD_DAP_TDI__CAN2_TX                                 0x0000 0x01B0 0x0000 0x3 0x0
+#define MX93_PAD_DAP_TDI__FLEXIO2_FLEXIO30                        0x0000 0x01B0 0x0000 0x4 0x0
+#define MX93_PAD_DAP_TDI__GPIO3_IO28                              0x0000 0x01B0 0x0000 0x5 0x0
+#define MX93_PAD_DAP_TDI__LPUART5_RX                              0x0000 0x01B0 0x0430 0x6 0x0
+#define MX93_PAD_DAP_TMS_SWDIO__JTAG_MUX_TMS                      0x0004 0x01B4 0x03DC 0x0 0x0
+#define MX93_PAD_DAP_TMS_SWDIO__FLEXIO2_FLEXIO31                  0x0004 0x01B4 0x0000 0x4 0x0
+#define MX93_PAD_DAP_TMS_SWDIO__GPIO3_IO29                        0x0004 0x01B4 0x0000 0x5 0x0
+#define MX93_PAD_DAP_TMS_SWDIO__LPUART5_RTS_B                     0x0004 0x01B4 0x0000 0x6 0x0
+#define MX93_PAD_DAP_TCLK_SWCLK__JTAG_MUX_TCK                     0x0008 0x01B8 0x03D4 0x0 0x0
+#define MX93_PAD_DAP_TCLK_SWCLK__FLEXIO1_FLEXIO30                 0x0008 0x01B8 0x0000 0x4 0x0
+#define MX93_PAD_DAP_TCLK_SWCLK__GPIO3_IO30                       0x0008 0x01B8 0x0000 0x5 0x0
+#define MX93_PAD_DAP_TCLK_SWCLK__LPUART5_CTS_B                    0x0008 0x01B8 0x042C 0x6 0x0
+#define MX93_PAD_DAP_TDO_TRACESWO__JTAG_MUX_TDO                   0x000C 0x01BC 0x0000 0x0 0x0
+#define MX93_PAD_DAP_TDO_TRACESWO__MQS2_RIGHT                     0x000C 0x01BC 0x0000 0x1 0x0
+#define MX93_PAD_DAP_TDO_TRACESWO__CAN2_RX                        0x000C 0x01BC 0x0364 0x3 0x0
+#define MX93_PAD_DAP_TDO_TRACESWO__FLEXIO1_FLEXIO31               0x000C 0x01BC 0x0000 0x4 0x0
+#define MX93_PAD_DAP_TDO_TRACESWO__GPIO3_IO31                     0x000C 0x01BC 0x0000 0x5 0x0
+#define MX93_PAD_DAP_TDO_TRACESWO__LPUART5_TX                     0x000C 0x01BC 0x0434 0x6 0x0
+#define MX93_PAD_GPIO_IO00__GPIO2_IO00                            0x0010 0x01C0 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO00__LPI2C3_SDA                            0x0010 0x01C0 0x03E4 0x11 0x0
+#define MX93_PAD_GPIO_IO00__MEDIAMIX_CAM_CLK                      0x0010 0x01C0 0x0000 0x2 0x0
+#define MX93_PAD_GPIO_IO00__MEDIAMIX_DISP_CLK                     0x0010 0x01C0 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO00__LPSPI6_PCS0                           0x0010 0x01C0 0x0000 0x4 0x0
+#define MX93_PAD_GPIO_IO00__LPUART5_TX                            0x0010 0x01C0 0x0434 0x5 0x1
+#define MX93_PAD_GPIO_IO00__LPI2C5_SDA                            0x0010 0x01C0 0x03EC 0x16 0x0
+#define MX93_PAD_GPIO_IO00__FLEXIO1_FLEXIO00                      0x0010 0x01C0 0x036C 0x7 0x0
+#define MX93_PAD_GPIO_IO01__GPIO2_IO01                            0x0014 0x01C4 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO01__LPI2C3_SCL                            0x0014 0x01C4 0x03E0 0x11 0x0
+#define MX93_PAD_GPIO_IO01__MEDIAMIX_CAM_DATA00                   0x0014 0x01C4 0x0000 0x2 0x0
+#define MX93_PAD_GPIO_IO01__MEDIAMIX_DISP_DE                      0x0014 0x01C4 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO01__LPSPI6_SIN                            0x0014 0x01C4 0x0000 0x4 0x0
+#define MX93_PAD_GPIO_IO01__LPUART5_RX                            0x0014 0x01C4 0x0430 0x5 0x1
+#define MX93_PAD_GPIO_IO01__LPI2C5_SCL                            0x0014 0x01C4 0x03E8 0x16 0x0
+#define MX93_PAD_GPIO_IO01__FLEXIO1_FLEXIO01                      0x0014 0x01C4 0x0370 0x7 0x0
+#define MX93_PAD_GPIO_IO02__GPIO2_IO02                            0x0018 0x01C8 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO02__LPI2C4_SDA                            0x0018 0x01C8 0x0000 0x11 0x0
+#define MX93_PAD_GPIO_IO02__MEDIAMIX_CAM_VSYNC                    0x0018 0x01C8 0x0000 0x2 0x0
+#define MX93_PAD_GPIO_IO02__MEDIAMIX_DISP_VSYNC                   0x0018 0x01C8 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO02__LPSPI6_SOUT                           0x0018 0x01C8 0x0000 0x4 0x0
+#define MX93_PAD_GPIO_IO02__LPUART5_CTS_B                         0x0018 0x01C8 0x042C 0x5 0x1
+#define MX93_PAD_GPIO_IO02__LPI2C6_SDA                            0x0018 0x01C8 0x03F4 0x16 0x0
+#define MX93_PAD_GPIO_IO02__FLEXIO1_FLEXIO02                      0x0018 0x01C8 0x0374 0x7 0x0
+#define MX93_PAD_GPIO_IO03__GPIO2_IO03                            0x001C 0x01CC 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO03__LPI2C4_SCL                            0x001C 0x01CC 0x0000 0x11 0x0
+#define MX93_PAD_GPIO_IO03__MEDIAMIX_CAM_HSYNC                    0x001C 0x01CC 0x0000 0x2 0x0
+#define MX93_PAD_GPIO_IO03__MEDIAMIX_DISP_HSYNC                   0x001C 0x01CC 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO03__LPSPI6_SCK                            0x001C 0x01CC 0x0000 0x4 0x0
+#define MX93_PAD_GPIO_IO03__LPUART5_RTS_B                         0x001C 0x01CC 0x0000 0x5 0x0
+#define MX93_PAD_GPIO_IO03__LPI2C6_SCL                            0x001C 0x01CC 0x03F0 0x16 0x0
+#define MX93_PAD_GPIO_IO03__FLEXIO1_FLEXIO03                      0x001C 0x01CC 0x0378 0x7 0x0
+#define MX93_PAD_GPIO_IO04__GPIO2_IO04                            0x0020 0x01D0 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO04__TPM3_CH0                              0x0020 0x01D0 0x0000 0x1 0x0
+#define MX93_PAD_GPIO_IO04__PDM_CLK                               0x0020 0x01D0 0x0000 0x2 0x0
+#define MX93_PAD_GPIO_IO04__MEDIAMIX_DISP_DATA00                  0x0020 0x01D0 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO04__LPSPI7_PCS0                           0x0020 0x01D0 0x0000 0x4 0x0
+#define MX93_PAD_GPIO_IO04__LPUART6_TX                            0x0020 0x01D0 0x0000 0x5 0x0
+#define MX93_PAD_GPIO_IO04__LPI2C6_SDA                            0x0020 0x01D0 0x03F4 0x16 0x1
+#define MX93_PAD_GPIO_IO04__FLEXIO1_FLEXIO04                      0x0020 0x01D0 0x037C 0x7 0x0
+#define MX93_PAD_GPIO_IO05__GPIO2_IO05                            0x0024 0x01D4 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO05__TPM4_CH0                              0x0024 0x01D4 0x0000 0x1 0x0
+#define MX93_PAD_GPIO_IO05__PDM_BIT_STREAM00                      0x0024 0x01D4 0x0438 0x2 0x0
+#define MX93_PAD_GPIO_IO05__MEDIAMIX_DISP_DATA01                  0x0024 0x01D4 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO05__LPSPI7_SIN                            0x0024 0x01D4 0x0000 0x4 0x0
+#define MX93_PAD_GPIO_IO05__LPUART6_RX                            0x0024 0x01D4 0x0000 0x5 0x0
+#define MX93_PAD_GPIO_IO05__LPI2C6_SCL                            0x0024 0x01D4 0x03F0 0x16 0x1
+#define MX93_PAD_GPIO_IO05__FLEXIO1_FLEXIO05                      0x0024 0x01D4 0x0380 0x7 0x0
+#define MX93_PAD_GPIO_IO06__GPIO2_IO06                            0x0028 0x01D8 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO06__TPM5_CH0                              0x0028 0x01D8 0x0000 0x1 0x0
+#define MX93_PAD_GPIO_IO06__PDM_BIT_STREAM01                      0x0028 0x01D8 0x043C 0x2 0x0
+#define MX93_PAD_GPIO_IO06__MEDIAMIX_DISP_DATA02                  0x0028 0x01D8 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO06__LPSPI7_SOUT                           0x0028 0x01D8 0x0000 0x4 0x0
+#define MX93_PAD_GPIO_IO06__LPUART6_CTS_B                         0x0028 0x01D8 0x0000 0x5 0x0
+#define MX93_PAD_GPIO_IO06__LPI2C7_SDA                            0x0028 0x01D8 0x03FC 0x16 0x0
+#define MX93_PAD_GPIO_IO06__FLEXIO1_FLEXIO06                      0x0028 0x01D8 0x0384 0x7 0x0
+#define MX93_PAD_GPIO_IO07__GPIO2_IO07                            0x002C 0x01DC 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO07__LPSPI3_PCS1                           0x002C 0x01DC 0x0000 0x1 0x0
+#define MX93_PAD_GPIO_IO07__MEDIAMIX_CAM_DATA01                   0x002C 0x01DC 0x0000 0x2 0x0
+#define MX93_PAD_GPIO_IO07__MEDIAMIX_DISP_DATA03                  0x002C 0x01DC 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO07__LPSPI7_SCK                            0x002C 0x01DC 0x0000 0x4 0x0
+#define MX93_PAD_GPIO_IO07__LPUART6_RTS_B                         0x002C 0x01DC 0x0000 0x5 0x0
+#define MX93_PAD_GPIO_IO07__LPI2C7_SCL                            0x002C 0x01DC 0x03F8 0x16 0x0
+#define MX93_PAD_GPIO_IO07__FLEXIO1_FLEXIO07                      0x002C 0x01DC 0x0388 0x7 0x0
+#define MX93_PAD_GPIO_IO08__GPIO2_IO08                            0x0030 0x01E0 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO08__LPSPI3_PCS0                           0x0030 0x01E0 0x0000 0x1 0x0
+#define MX93_PAD_GPIO_IO08__MEDIAMIX_CAM_DATA02                   0x0030 0x01E0 0x0000 0x2 0x0
+#define MX93_PAD_GPIO_IO08__MEDIAMIX_DISP_DATA04                  0x0030 0x01E0 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO08__TPM6_CH0                              0x0030 0x01E0 0x0000 0x4 0x0
+#define MX93_PAD_GPIO_IO08__LPUART7_TX                            0x0030 0x01E0 0x0000 0x5 0x0
+#define MX93_PAD_GPIO_IO08__LPI2C7_SDA                            0x0030 0x01E0 0x03FC 0x16 0x1
+#define MX93_PAD_GPIO_IO08__FLEXIO1_FLEXIO08                      0x0030 0x01E0 0x038C 0x7 0x0
+#define MX93_PAD_GPIO_IO09__GPIO2_IO09                            0x0034 0x01E4 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO09__LPSPI3_SIN                            0x0034 0x01E4 0x0000 0x1 0x0
+#define MX93_PAD_GPIO_IO09__MEDIAMIX_CAM_DATA03                   0x0034 0x01E4 0x0000 0x2 0x0
+#define MX93_PAD_GPIO_IO09__MEDIAMIX_DISP_DATA05                  0x0034 0x01E4 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO09__TPM3_EXTCLK                           0x0034 0x01E4 0x0000 0x4 0x0
+#define MX93_PAD_GPIO_IO09__LPUART7_RX                            0x0034 0x01E4 0x0000 0x5 0x0
+#define MX93_PAD_GPIO_IO09__LPI2C7_SCL                            0x0034 0x01E4 0x03F8 0x16 0x1
+#define MX93_PAD_GPIO_IO09__FLEXIO1_FLEXIO09                      0x0034 0x01E4 0x0390 0x7 0x0
+#define MX93_PAD_GPIO_IO10__GPIO2_IO10                            0x0038 0x01E8 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO10__LPSPI3_SOUT                           0x0038 0x01E8 0x0000 0x1 0x0
+#define MX93_PAD_GPIO_IO10__MEDIAMIX_CAM_DATA04                   0x0038 0x01E8 0x0000 0x2 0x0
+#define MX93_PAD_GPIO_IO10__MEDIAMIX_DISP_DATA06                  0x0038 0x01E8 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO10__TPM4_EXTCLK                           0x0038 0x01E8 0x0000 0x4 0x0
+#define MX93_PAD_GPIO_IO10__LPUART7_CTS_B                         0x0038 0x01E8 0x0000 0x5 0x0
+#define MX93_PAD_GPIO_IO10__LPI2C8_SDA                            0x0038 0x01E8 0x0404 0x16 0x0
+#define MX93_PAD_GPIO_IO10__FLEXIO1_FLEXIO10                      0x0038 0x01E8 0x0394 0x7 0x0
+#define MX93_PAD_GPIO_IO11__GPIO2_IO11                            0x003C 0x01EC 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO11__LPSPI3_SCK                            0x003C 0x01EC 0x0000 0x1 0x0
+#define MX93_PAD_GPIO_IO11__MEDIAMIX_CAM_DATA05                   0x003C 0x01EC 0x0000 0x2 0x0
+#define MX93_PAD_GPIO_IO11__MEDIAMIX_DISP_DATA07                  0x003C 0x01EC 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO11__TPM5_EXTCLK                           0x003C 0x01EC 0x0000 0x4 0x0
+#define MX93_PAD_GPIO_IO11__LPUART7_RTS_B                         0x003C 0x01EC 0x0000 0x5 0x0
+#define MX93_PAD_GPIO_IO11__LPI2C8_SCL                            0x003C 0x01EC 0x0400 0x16 0x0
+#define MX93_PAD_GPIO_IO11__FLEXIO1_FLEXIO11                      0x003C 0x01EC 0x0398 0x7 0x0
+#define MX93_PAD_GPIO_IO12__GPIO2_IO12                            0x0040 0x01F0 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO12__TPM3_CH2                              0x0040 0x01F0 0x0000 0x1 0x0
+#define MX93_PAD_GPIO_IO12__PDM_BIT_STREAM02                      0x0040 0x01F0 0x0440 0x2 0x0
+#define MX93_PAD_GPIO_IO12__MEDIAMIX_DISP_DATA08                  0x0040 0x01F0 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO12__LPSPI8_PCS0                           0x0040 0x01F0 0x0000 0x4 0x0
+#define MX93_PAD_GPIO_IO12__LPUART8_TX                            0x0040 0x01F0 0x0000 0x5 0x0
+#define MX93_PAD_GPIO_IO12__LPI2C8_SDA                            0x0040 0x01F0 0x0404 0x16 0x1
+#define MX93_PAD_GPIO_IO12__SAI3_RX_SYNC                          0x0040 0x01F0 0x0450 0x7 0x0
+#define MX93_PAD_GPIO_IO13__GPIO2_IO13                            0x0044 0x01F4 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO13__TPM4_CH2                              0x0044 0x01F4 0x0000 0x1 0x0
+#define MX93_PAD_GPIO_IO13__PDM_BIT_STREAM03                      0x0044 0x01F4 0x0444 0x2 0x0
+#define MX93_PAD_GPIO_IO13__MEDIAMIX_DISP_DATA09                  0x0044 0x01F4 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO13__LPSPI8_SIN                            0x0044 0x01F4 0x0000 0x4 0x0
+#define MX93_PAD_GPIO_IO13__LPUART8_RX                            0x0044 0x01F4 0x0000 0x5 0x0
+#define MX93_PAD_GPIO_IO13__LPI2C8_SCL                            0x0044 0x01F4 0x0400 0x16 0x1
+#define MX93_PAD_GPIO_IO13__FLEXIO1_FLEXIO13                      0x0044 0x01F4 0x039C 0x7 0x0
+#define MX93_PAD_GPIO_IO14__GPIO2_IO14                            0x0048 0x01F8 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO14__LPUART3_TX                            0x0048 0x01F8 0x041C 0x1 0x0
+#define MX93_PAD_GPIO_IO14__MEDIAMIX_CAM_DATA06                   0x0048 0x01F8 0x0000 0x2 0x0
+#define MX93_PAD_GPIO_IO14__MEDIAMIX_DISP_DATA10                  0x0048 0x01F8 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO14__LPSPI8_SOUT                           0x0048 0x01F8 0x0000 0x4 0x0
+#define MX93_PAD_GPIO_IO14__LPUART8_CTS_B                         0x0048 0x01F8 0x0000 0x5 0x0
+#define MX93_PAD_GPIO_IO14__LPUART4_TX                            0x0048 0x01F8 0x0428 0x6 0x0
+#define MX93_PAD_GPIO_IO14__FLEXIO1_FLEXIO14                      0x0048 0x01F8 0x03A0 0x7 0x0
+#define MX93_PAD_GPIO_IO15__GPIO2_IO15                            0x004C 0x01FC 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO15__LPUART3_RX                            0x004C 0x01FC 0x0418 0x1 0x0
+#define MX93_PAD_GPIO_IO15__MEDIAMIX_CAM_DATA07                   0x004C 0x01FC 0x0000 0x2 0x0
+#define MX93_PAD_GPIO_IO15__MEDIAMIX_DISP_DATA11                  0x004C 0x01FC 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO15__LPSPI8_SCK                            0x004C 0x01FC 0x0000 0x4 0x0
+#define MX93_PAD_GPIO_IO15__LPUART8_RTS_B                         0x004C 0x01FC 0x0000 0x5 0x0
+#define MX93_PAD_GPIO_IO15__LPUART4_RX                            0x004C 0x01FC 0x0424 0x6 0x0
+#define MX93_PAD_GPIO_IO15__FLEXIO1_FLEXIO15                      0x004C 0x01FC 0x03A4 0x7 0x0
+#define MX93_PAD_GPIO_IO16__GPIO2_IO16                            0x0050 0x0200 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO16__SAI3_TX_BCLK                          0x0050 0x0200 0x0000 0x1 0x0
+#define MX93_PAD_GPIO_IO16__PDM_BIT_STREAM02                      0x0050 0x0200 0x0440 0x2 0x1
+#define MX93_PAD_GPIO_IO16__MEDIAMIX_DISP_DATA12                  0x0050 0x0200 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO16__LPUART3_CTS_B                         0x0050 0x0200 0x0414 0x4 0x0
+#define MX93_PAD_GPIO_IO16__LPSPI4_PCS2                           0x0050 0x0200 0x0000 0x5 0x0
+#define MX93_PAD_GPIO_IO16__LPUART4_CTS_B                         0x0050 0x0200 0x0420 0x6 0x0
+#define MX93_PAD_GPIO_IO16__FLEXIO1_FLEXIO16                      0x0050 0x0200 0x03A8 0x7 0x0
+#define MX93_PAD_GPIO_IO17__GPIO2_IO17                            0x0054 0x0204 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO17__SAI3_MCLK                             0x0054 0x0204 0x0000 0x1 0x0
+#define MX93_PAD_GPIO_IO17__MEDIAMIX_CAM_DATA08                   0x0054 0x0204 0x0000 0x2 0x0
+#define MX93_PAD_GPIO_IO17__MEDIAMIX_DISP_DATA13                  0x0054 0x0204 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO17__LPUART3_RTS_B                         0x0054 0x0204 0x0000 0x4 0x0
+#define MX93_PAD_GPIO_IO17__LPSPI4_PCS1                           0x0054 0x0204 0x0000 0x5 0x0
+#define MX93_PAD_GPIO_IO17__LPUART4_RTS_B                         0x0054 0x0204 0x0000 0x6 0x0
+#define MX93_PAD_GPIO_IO17__FLEXIO1_FLEXIO17                      0x0054 0x0204 0x03AC 0x7 0x0
+#define MX93_PAD_GPIO_IO18__GPIO2_IO18                            0x0058 0x0208 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO18__SAI3_RX_BCLK                          0x0058 0x0208 0x044C 0x1 0x0
+#define MX93_PAD_GPIO_IO18__MEDIAMIX_CAM_DATA09                   0x0058 0x0208 0x0000 0x2 0x0
+#define MX93_PAD_GPIO_IO18__MEDIAMIX_DISP_DATA14                  0x0058 0x0208 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO18__LPSPI5_PCS0                           0x0058 0x0208 0x0000 0x4 0x0
+#define MX93_PAD_GPIO_IO18__LPSPI4_PCS0                           0x0058 0x0208 0x0000 0x5 0x0
+#define MX93_PAD_GPIO_IO18__TPM5_CH2                              0x0058 0x0208 0x0000 0x6 0x0
+#define MX93_PAD_GPIO_IO18__FLEXIO1_FLEXIO18                      0x0058 0x0208 0x03B0 0x7 0x0
+#define MX93_PAD_GPIO_IO19__GPIO2_IO19                            0x005C 0x020C 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO19__SAI3_RX_SYNC                          0x005C 0x020C 0x0450 0x1 0x1
+#define MX93_PAD_GPIO_IO19__PDM_BIT_STREAM03                      0x005C 0x020C 0x0444 0x2 0x1
+#define MX93_PAD_GPIO_IO19__MEDIAMIX_DISP_DATA15                  0x005C 0x020C 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO19__LPSPI5_SIN                            0x005C 0x020C 0x0000 0x4 0x0
+#define MX93_PAD_GPIO_IO19__LPSPI4_SIN                            0x005C 0x020C 0x0000 0x5 0x0
+#define MX93_PAD_GPIO_IO19__TPM6_CH2                              0x005C 0x020C 0x0000 0x6 0x0
+#define MX93_PAD_GPIO_IO19__SAI3_TX_DATA00                        0x005C 0x020C 0x0000 0x7 0x0
+#define MX93_PAD_GPIO_IO20__GPIO2_IO20                            0x0060 0x0210 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO20__SAI3_RX_DATA00                        0x0060 0x0210 0x0000 0x1 0x0
+#define MX93_PAD_GPIO_IO20__PDM_BIT_STREAM00                      0x0060 0x0210 0x0438 0x2 0x1
+#define MX93_PAD_GPIO_IO20__MEDIAMIX_DISP_DATA16                  0x0060 0x0210 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO20__LPSPI5_SOUT                           0x0060 0x0210 0x0000 0x4 0x0
+#define MX93_PAD_GPIO_IO20__LPSPI4_SOUT                           0x0060 0x0210 0x0000 0x5 0x0
+#define MX93_PAD_GPIO_IO20__TPM3_CH1                              0x0060 0x0210 0x0000 0x6 0x0
+#define MX93_PAD_GPIO_IO20__FLEXIO1_FLEXIO20                      0x0060 0x0210 0x03B4 0x7 0x0
+#define MX93_PAD_GPIO_IO21__GPIO2_IO21                            0x0064 0x0214 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO21__SAI3_TX_DATA00                        0x0064 0x0214 0x0000 0x1 0x0
+#define MX93_PAD_GPIO_IO21__PDM_CLK                               0x0064 0x0214 0x0000 0x2 0x0
+#define MX93_PAD_GPIO_IO21__MEDIAMIX_DISP_DATA17                  0x0064 0x0214 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO21__LPSPI5_SCK                            0x0064 0x0214 0x0000 0x4 0x0
+#define MX93_PAD_GPIO_IO21__LPSPI4_SCK                            0x0064 0x0214 0x0000 0x5 0x0
+#define MX93_PAD_GPIO_IO21__TPM4_CH1                              0x0064 0x0214 0x0000 0x6 0x0
+#define MX93_PAD_GPIO_IO21__SAI3_RX_BCLK                          0x0064 0x0214 0x044C 0x7 0x1
+#define MX93_PAD_GPIO_IO22__GPIO2_IO22                            0x0068 0x0218 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO22__USDHC3_CLK                            0x0068 0x0218 0x0458 0x1 0x0
+#define MX93_PAD_GPIO_IO22__SPDIF_IN                              0x0068 0x0218 0x0454 0x2 0x0
+#define MX93_PAD_GPIO_IO22__MEDIAMIX_DISP_DATA18                  0x0068 0x0218 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO22__TPM5_CH1                              0x0068 0x0218 0x0000 0x4 0x0
+#define MX93_PAD_GPIO_IO22__TPM6_EXTCLK                           0x0068 0x0218 0x0000 0x5 0x0
+#define MX93_PAD_GPIO_IO22__LPI2C5_SDA                            0x0068 0x0218 0x03EC 0x16 0x1
+#define MX93_PAD_GPIO_IO22__FLEXIO1_FLEXIO22                      0x0068 0x0218 0x03B8 0x7 0x0
+#define MX93_PAD_GPIO_IO23__GPIO2_IO23                            0x006C 0x021C 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO23__USDHC3_CMD                            0x006C 0x021C 0x045C 0x1 0x0
+#define MX93_PAD_GPIO_IO23__SPDIF_OUT                             0x006C 0x021C 0x0000 0x2 0x0
+#define MX93_PAD_GPIO_IO23__MEDIAMIX_DISP_DATA19                  0x006C 0x021C 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO23__TPM6_CH1                              0x006C 0x021C 0x0000 0x4 0x0
+#define MX93_PAD_GPIO_IO23__LPI2C5_SCL                            0x006C 0x021C 0x03E8 0x16 0x1
+#define MX93_PAD_GPIO_IO23__FLEXIO1_FLEXIO23                      0x006C 0x021C 0x03BC 0x7 0x0
+#define MX93_PAD_GPIO_IO24__GPIO2_IO24                            0x0070 0x0220 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO24__USDHC3_DATA0                          0x0070 0x0220 0x0460 0x1 0x0
+#define MX93_PAD_GPIO_IO24__MEDIAMIX_DISP_DATA20                  0x0070 0x0220 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO24__TPM3_CH3                              0x0070 0x0220 0x0000 0x4 0x0
+#define MX93_PAD_GPIO_IO24__JTAG_MUX_TDO                          0x0070 0x0220 0x0000 0x5 0x0
+#define MX93_PAD_GPIO_IO24__LPSPI6_PCS1                           0x0070 0x0220 0x0000 0x6 0x0
+#define MX93_PAD_GPIO_IO24__FLEXIO1_FLEXIO24                      0x0070 0x0220 0x03C0 0x7 0x0
+#define MX93_PAD_GPIO_IO25__GPIO2_IO25                            0x0074 0x0224 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO25__USDHC3_DATA1                          0x0074 0x0224 0x0464 0x1 0x0
+#define MX93_PAD_GPIO_IO25__CAN2_TX                               0x0074 0x0224 0x0000 0x2 0x0
+#define MX93_PAD_GPIO_IO25__MEDIAMIX_DISP_DATA21                  0x0074 0x0224 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO25__TPM4_CH3                              0x0074 0x0224 0x0000 0x4 0x0
+#define MX93_PAD_GPIO_IO25__JTAG_MUX_TCK                          0x0074 0x0224 0x03D4 0x5 0x1
+#define MX93_PAD_GPIO_IO25__LPSPI7_PCS1                           0x0074 0x0224 0x0000 0x6 0x0
+#define MX93_PAD_GPIO_IO25__FLEXIO1_FLEXIO25                      0x0074 0x0224 0x03C4 0x7 0x0
+#define MX93_PAD_GPIO_IO26__GPIO2_IO26                            0x0078 0x0228 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO26__USDHC3_DATA2                          0x0078 0x0228 0x0468 0x1 0x0
+#define MX93_PAD_GPIO_IO26__PDM_BIT_STREAM01                      0x0078 0x0228 0x043C 0x2 0x1
+#define MX93_PAD_GPIO_IO26__MEDIAMIX_DISP_DATA22                  0x0078 0x0228 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO26__TPM5_CH3                              0x0078 0x0228 0x0000 0x4 0x0
+#define MX93_PAD_GPIO_IO26__JTAG_MUX_TDI                          0x0078 0x0228 0x03D8 0x5 0x1
+#define MX93_PAD_GPIO_IO26__LPSPI8_PCS1                           0x0078 0x0228 0x0000 0x6 0x0
+#define MX93_PAD_GPIO_IO26__SAI3_TX_SYNC                          0x0078 0x0228 0x0000 0x7 0x0
+#define MX93_PAD_GPIO_IO27__GPIO2_IO27                            0x007C 0x022C 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO27__USDHC3_DATA3                          0x007C 0x022C 0x046C 0x1 0x0
+#define MX93_PAD_GPIO_IO27__CAN2_RX                               0x007C 0x022C 0x0364 0x2 0x1
+#define MX93_PAD_GPIO_IO27__MEDIAMIX_DISP_DATA23                  0x007C 0x022C 0x0000 0x3 0x0
+#define MX93_PAD_GPIO_IO27__TPM6_CH3                              0x007C 0x022C 0x0000 0x4 0x0
+#define MX93_PAD_GPIO_IO27__JTAG_MUX_TMS                          0x007C 0x022C 0x03DC 0x5 0x1
+#define MX93_PAD_GPIO_IO27__LPSPI5_PCS1                           0x007C 0x022C 0x0000 0x6 0x0
+#define MX93_PAD_GPIO_IO27__FLEXIO1_FLEXIO27                      0x007C 0x022C 0x03C8 0x7 0x0
+#define MX93_PAD_GPIO_IO28__GPIO2_IO28                            0x0080 0x0230 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO28__LPI2C3_SDA                            0x0080 0x0230 0x03E4 0x11 0x1
+#define MX93_PAD_GPIO_IO28__FLEXIO1_FLEXIO28                      0x0080 0x0230 0x0000 0x7 0x0
+#define MX93_PAD_GPIO_IO29__GPIO2_IO29                            0x0084 0x0234 0x0000 0x0 0x0
+#define MX93_PAD_GPIO_IO29__LPI2C3_SCL                            0x0084 0x0234 0x03E0 0x11 0x1
+#define MX93_PAD_GPIO_IO29__FLEXIO1_FLEXIO29                      0x0084 0x0234 0x0000 0x7 0x0
+#define MX93_PAD_CCM_CLKO1__CCMSRCGPCMIX_CLKO1                    0x0088 0x0238 0x0000 0x0 0x0
+#define MX93_PAD_CCM_CLKO1__FLEXIO1_FLEXIO26                      0x0088 0x0238 0x0000 0x4 0x0
+#define MX93_PAD_CCM_CLKO1__GPIO3_IO26                            0x0088 0x0238 0x0000 0x5 0x0
+#define MX93_PAD_CCM_CLKO2__GPIO3_IO27                            0x008C 0x023C 0x0000 0x5 0x0
+#define MX93_PAD_CCM_CLKO2__CCMSRCGPCMIX_CLKO2                    0x008C 0x023C 0x0000 0x0 0x0
+#define MX93_PAD_CCM_CLKO2__FLEXIO1_FLEXIO27                      0x008C 0x023C 0x03C8 0x4 0x1
+#define MX93_PAD_CCM_CLKO3__CCMSRCGPCMIX_CLKO3                    0x0090 0x0240 0x0000 0x0 0x0
+#define MX93_PAD_CCM_CLKO3__FLEXIO2_FLEXIO28                      0x0090 0x0240 0x0000 0x4 0x0
+#define MX93_PAD_CCM_CLKO3__GPIO4_IO28                            0x0090 0x0240 0x0000 0x5 0x0
+#define MX93_PAD_CCM_CLKO4__CCMSRCGPCMIX_CLKO4                    0x0094 0x0244 0x0000 0x0 0x0
+#define MX93_PAD_CCM_CLKO4__FLEXIO2_FLEXIO29                      0x0094 0x0244 0x0000 0x4 0x0
+#define MX93_PAD_CCM_CLKO4__GPIO4_IO29                            0x0094 0x0244 0x0000 0x5 0x0
+#define MX93_PAD_ENET1_MDC__ENET_QOS_MDC                          0x0098 0x0248 0x0000 0x0 0x0
+#define MX93_PAD_ENET1_MDC__LPUART3_DCB_B                         0x0098 0x0248 0x0000 0x1 0x0
+#define MX93_PAD_ENET1_MDC__I3C2_SCL                              0x0098 0x0248 0x03CC 0x2 0x0
+#define MX93_PAD_ENET1_MDC__HSIOMIX_OTG_ID1                       0x0098 0x0248 0x0000 0x3 0x0
+#define MX93_PAD_ENET1_MDC__FLEXIO2_FLEXIO00                      0x0098 0x0248 0x0000 0x4 0x0
+#define MX93_PAD_ENET1_MDC__GPIO4_IO00                            0x0098 0x0248 0x0000 0x5 0x0
+#define MX93_PAD_ENET1_MDIO__ENET_QOS_MDIO                        0x009C 0x024C 0x0000 0x0 0x0
+#define MX93_PAD_ENET1_MDIO__LPUART3_RIN_B                        0x009C 0x024C 0x0000 0x1 0x0
+#define MX93_PAD_ENET1_MDIO__I3C2_SDA                             0x009C 0x024C 0x03D0 0x2 0x0
+#define MX93_PAD_ENET1_MDIO__HSIOMIX_OTG_PWR1                     0x009C 0x024C 0x0000 0x3 0x0
+#define MX93_PAD_ENET1_MDIO__FLEXIO2_FLEXIO01                     0x009C 0x024C 0x0000 0x4 0x0
+#define MX93_PAD_ENET1_MDIO__GPIO4_IO01                           0x009C 0x024C 0x0000 0x5 0x0
+#define MX93_PAD_ENET1_TD3__ENET_QOS_RGMII_TD3                    0x00A0 0x0250 0x0000 0x0 0x0
+#define MX93_PAD_ENET1_TD3__CAN2_TX                               0x00A0 0x0250 0x0000 0x2 0x0
+#define MX93_PAD_ENET1_TD3__HSIOMIX_OTG_ID2                       0x00A0 0x0250 0x0000 0x3 0x0
+#define MX93_PAD_ENET1_TD3__FLEXIO2_FLEXIO02                      0x00A0 0x0250 0x0000 0x4 0x0
+#define MX93_PAD_ENET1_TD3__GPIO4_IO02                            0x00A0 0x0250 0x0000 0x5 0x0
+#define MX93_PAD_ENET1_TD2__ENET_QOS_RGMII_TD2                    0x00A4 0x0254 0x0000 0x0 0x0
+#define MX93_PAD_ENET1_TD2__CCM_ENET_QOS_CLOCK_GENERATE_REF_CLK   0x00A4 0x0254 0x0000 0x1 0x0
+#define MX93_PAD_ENET1_TD2__CAN2_RX                               0x00A4 0x0254 0x0364 0x2 0x2
+#define MX93_PAD_ENET1_TD2__HSIOMIX_OTG_OC2                       0x00A4 0x0254 0x0000 0x3 0x0
+#define MX93_PAD_ENET1_TD2__FLEXIO2_FLEXIO03                      0x00A4 0x0254 0x0000 0x4 0x0
+#define MX93_PAD_ENET1_TD2__GPIO4_IO03                            0x00A4 0x0254 0x0000 0x5 0x0
+#define MX93_PAD_ENET1_TD1__ENET_QOS_RGMII_TD1                    0x00A8 0x0258 0x0000 0x0 0x0
+#define MX93_PAD_ENET1_TD1__LPUART3_RTS_B                         0x00A8 0x0258 0x0000 0x1 0x0
+#define MX93_PAD_ENET1_TD1__I3C2_PUR                              0x00A8 0x0258 0x0000 0x2 0x0
+#define MX93_PAD_ENET1_TD1__HSIOMIX_OTG_OC1                       0x00A8 0x0258 0x0000 0x3 0x0
+#define MX93_PAD_ENET1_TD1__FLEXIO2_FLEXIO04                      0x00A8 0x0258 0x0000 0x4 0x0
+#define MX93_PAD_ENET1_TD1__GPIO4_IO04                            0x00A8 0x0258 0x0000 0x5 0x0
+#define MX93_PAD_ENET1_TD1__I3C2_PUR_B                            0x00A8 0x0258 0x0000 0x6 0x0
+#define MX93_PAD_ENET1_TD0__ENET_QOS_RGMII_TD0                    0x00AC 0x025C 0x0000 0x0 0x0
+#define MX93_PAD_ENET1_TD0__LPUART3_TX                            0x00AC 0x025C 0x041C 0x1 0x1
+#define MX93_PAD_ENET1_TD0__FLEXIO2_FLEXIO05                      0x00AC 0x025C 0x0000 0x4 0x0
+#define MX93_PAD_ENET1_TD0__GPIO4_IO05                            0x00AC 0x025C 0x0000 0x5 0x0
+#define MX93_PAD_ENET1_TX_CTL__ENET_QOS_RGMII_TX_CTL              0x00B0 0x0260 0x0000 0x0 0x0
+#define MX93_PAD_ENET1_TX_CTL__LPUART3_DTR_B                      0x00B0 0x0260 0x0000 0x1 0x0
+#define MX93_PAD_ENET1_TX_CTL__FLEXIO2_FLEXIO06                   0x00B0 0x0260 0x0000 0x4 0x0
+#define MX93_PAD_ENET1_TX_CTL__GPIO4_IO06                         0x00B0 0x0260 0x0000 0x5 0x0
+#define MX93_PAD_ENET1_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK    0x00B4 0x0264 0x0000 0x0 0x0
+#define MX93_PAD_ENET1_TXC__ENET_QOS_TX_ER                        0x00B4 0x0264 0x0000 0x1 0x0
+#define MX93_PAD_ENET1_TXC__FLEXIO2_FLEXIO07                      0x00B4 0x0264 0x0000 0x4 0x0
+#define MX93_PAD_ENET1_TXC__GPIO4_IO07                            0x00B4 0x0264 0x0000 0x5 0x0
+#define MX93_PAD_ENET1_RX_CTL__ENET_QOS_RGMII_RX_CTL              0x00B8 0x0268 0x0000 0x0 0x0
+#define MX93_PAD_ENET1_RX_CTL__LPUART3_DSR_B                      0x00B8 0x0268 0x0000 0x1 0x0
+#define MX93_PAD_ENET1_RX_CTL__HSIOMIX_OTG_PWR2                   0x00B8 0x0268 0x0000 0x3 0x0
+#define MX93_PAD_ENET1_RX_CTL__FLEXIO2_FLEXIO08                   0x00B8 0x0268 0x0000 0x4 0x0
+#define MX93_PAD_ENET1_RX_CTL__GPIO4_IO08                         0x00B8 0x0268 0x0000 0x5 0x0
+#define MX93_PAD_ENET1_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK    0x00BC 0x026C 0x0000 0x0 0x0
+#define MX93_PAD_ENET1_RXC__ENET_QOS_RX_ER                        0x00BC 0x026C 0x0000 0x1 0x0
+#define MX93_PAD_ENET1_RXC__FLEXIO2_FLEXIO09                      0x00BC 0x026C 0x0000 0x4 0x0
+#define MX93_PAD_ENET1_RXC__GPIO4_IO09                            0x00BC 0x026C 0x0000 0x5 0x0
+#define MX93_PAD_ENET1_RD0__ENET_QOS_RGMII_RD0                    0x00C0 0x0270 0x0000 0x0 0x0
+#define MX93_PAD_ENET1_RD0__LPUART3_RX                            0x00C0 0x0270 0x0418 0x1 0x1
+#define MX93_PAD_ENET1_RD0__FLEXIO2_FLEXIO10                      0x00C0 0x0270 0x0000 0x4 0x0
+#define MX93_PAD_ENET1_RD0__GPIO4_IO10                            0x00C0 0x0270 0x0000 0x5 0x0
+#define MX93_PAD_ENET1_RD1__ENET_QOS_RGMII_RD1                    0x00C4 0x0274 0x0000 0x0 0x0
+#define MX93_PAD_ENET1_RD1__LPUART3_CTS_B                         0x00C4 0x0274 0x0414 0x1 0x1
+#define MX93_PAD_ENET1_RD1__LPTMR2_ALT1                           0x00C4 0x0274 0x0408 0x3 0x0
+#define MX93_PAD_ENET1_RD1__FLEXIO2_FLEXIO11                      0x00C4 0x0274 0x0000 0x4 0x0
+#define MX93_PAD_ENET1_RD1__GPIO4_IO11                            0x00C4 0x0274 0x0000 0x5 0x0
+#define MX93_PAD_ENET1_RD2__ENET_QOS_RGMII_RD2                    0x00C8 0x0278 0x0000 0x0 0x0
+#define MX93_PAD_ENET1_RD2__LPTMR2_ALT2                           0x00C8 0x0278 0x040C 0x3 0x0
+#define MX93_PAD_ENET1_RD2__FLEXIO2_FLEXIO12                      0x00C8 0x0278 0x0000 0x4 0x0
+#define MX93_PAD_ENET1_RD2__GPIO4_IO12                            0x00C8 0x0278 0x0000 0x5 0x0
+#define MX93_PAD_ENET1_RD3__ENET_QOS_RGMII_RD3                    0x00CC 0x027C 0x0000 0x0 0x0
+#define MX93_PAD_ENET1_RD3__FLEXSPI1_TESTER_TRIGGER               0x00CC 0x027C 0x0000 0x2 0x0
+#define MX93_PAD_ENET1_RD3__LPTMR2_ALT3                           0x00CC 0x027C 0x0410 0x3 0x0
+#define MX93_PAD_ENET1_RD3__FLEXIO2_FLEXIO13                      0x00CC 0x027C 0x0000 0x4 0x0
+#define MX93_PAD_ENET1_RD3__GPIO4_IO13                            0x00CC 0x027C 0x0000 0x5 0x0
+#define MX93_PAD_ENET2_MDC__ENET1_MDC                             0x00D0 0x0280 0x0000 0x0 0x0
+#define MX93_PAD_ENET2_MDC__LPUART4_DCB_B                         0x00D0 0x0280 0x0000 0x1 0x0
+#define MX93_PAD_ENET2_MDC__SAI2_RX_SYNC                          0x00D0 0x0280 0x0000 0x2 0x0
+#define MX93_PAD_ENET2_MDC__FLEXIO2_FLEXIO14                      0x00D0 0x0280 0x0000 0x4 0x0
+#define MX93_PAD_ENET2_MDC__GPIO4_IO14                            0x00D0 0x0280 0x0000 0x5 0x0
+#define MX93_PAD_ENET2_MDIO__ENET1_MDIO                           0x00D4 0x0284 0x0000 0x0 0x0
+#define MX93_PAD_ENET2_MDIO__LPUART4_RIN_B                        0x00D4 0x0284 0x0000 0x1 0x0
+#define MX93_PAD_ENET2_MDIO__SAI2_RX_BCLK                         0x00D4 0x0284 0x0000 0x2 0x0
+#define MX93_PAD_ENET2_MDIO__FLEXIO2_FLEXIO15                     0x00D4 0x0284 0x0000 0x4 0x0
+#define MX93_PAD_ENET2_MDIO__GPIO4_IO15                           0x00D4 0x0284 0x0000 0x5 0x0
+#define MX93_PAD_ENET2_TD3__SAI2_RX_DATA00                        0x00D8 0x0288 0x0000 0x2 0x0
+#define MX93_PAD_ENET2_TD3__FLEXIO2_FLEXIO16                      0x00D8 0x0288 0x0000 0x4 0x0
+#define MX93_PAD_ENET2_TD3__GPIO4_IO16                            0x00D8 0x0288 0x0000 0x5 0x0
+#define MX93_PAD_ENET2_TD3__ENET1_RGMII_TD3                       0x00D8 0x0288 0x0000 0x0 0x0
+#define MX93_PAD_ENET2_TD2__ENET1_RGMII_TD2                       0x00DC 0x028C 0x0000 0x0 0x0
+#define MX93_PAD_ENET2_TD2__ENET1_TX_CLK                          0x00DC 0x028C 0x0000 0x1 0x0
+#define MX93_PAD_ENET2_TD2__SAI2_RX_DATA01                        0x00DC 0x028C 0x0000 0x2 0x0
+#define MX93_PAD_ENET2_TD2__FLEXIO2_FLEXIO17                      0x00DC 0x028C 0x0000 0x4 0x0
+#define MX93_PAD_ENET2_TD2__GPIO4_IO17                            0x00DC 0x028C 0x0000 0x5 0x0
+#define MX93_PAD_ENET2_TD1__ENET1_RGMII_TD1                       0x00E0 0x0290 0x0000 0x0 0x0
+#define MX93_PAD_ENET2_TD1__LPUART4_RTS_B                         0x00E0 0x0290 0x0000 0x1 0x0
+#define MX93_PAD_ENET2_TD1__SAI2_RX_DATA02                        0x00E0 0x0290 0x0000 0x2 0x0
+#define MX93_PAD_ENET2_TD1__FLEXIO2_FLEXIO18                      0x00E0 0x0290 0x0000 0x4 0x0
+#define MX93_PAD_ENET2_TD1__GPIO4_IO18                            0x00E0 0x0290 0x0000 0x5 0x0
+#define MX93_PAD_ENET2_TD0__ENET1_RGMII_TD0                       0x00E4 0x0294 0x0000 0x0 0x0
+#define MX93_PAD_ENET2_TD0__LPUART4_TX                            0x00E4 0x0294 0x0428 0x1 0x1
+#define MX93_PAD_ENET2_TD0__SAI2_RX_DATA03                        0x00E4 0x0294 0x0000 0x2 0x0
+#define MX93_PAD_ENET2_TD0__FLEXIO2_FLEXIO19                      0x00E4 0x0294 0x0000 0x4 0x0
+#define MX93_PAD_ENET2_TD0__GPIO4_IO19                            0x00E4 0x0294 0x0000 0x5 0x0
+#define MX93_PAD_ENET2_TX_CTL__ENET1_RGMII_TX_CTL                 0x00E8 0x0298 0x0000 0x0 0x0
+#define MX93_PAD_ENET2_TX_CTL__LPUART4_DTR_B                      0x00E8 0x0298 0x0000 0x1 0x0
+#define MX93_PAD_ENET2_TX_CTL__SAI2_TX_SYNC                       0x00E8 0x0298 0x0000 0x2 0x0
+#define MX93_PAD_ENET2_TX_CTL__FLEXIO2_FLEXIO20                   0x00E8 0x0298 0x0000 0x4 0x0
+#define MX93_PAD_ENET2_TX_CTL__GPIO4_IO20                         0x00E8 0x0298 0x0000 0x5 0x0
+#define MX93_PAD_ENET2_TXC__ENET1_RGMII_TXC                       0x00EC 0x029C 0x0000 0x0 0x0
+#define MX93_PAD_ENET2_TXC__ENET1_TX_ER                           0x00EC 0x029C 0x0000 0x1 0x0
+#define MX93_PAD_ENET2_TXC__SAI2_TX_BCLK                          0x00EC 0x029C 0x0000 0x2 0x0
+#define MX93_PAD_ENET2_TXC__FLEXIO2_FLEXIO21                      0x00EC 0x029C 0x0000 0x4 0x0
+#define MX93_PAD_ENET2_TXC__GPIO4_IO21                            0x00EC 0x029C 0x0000 0x5 0x0
+#define MX93_PAD_ENET2_RX_CTL__ENET1_RGMII_RX_CTL                 0x00F0 0x02A0 0x0000 0x0 0x0
+#define MX93_PAD_ENET2_RX_CTL__LPUART4_DSR_B                      0x00F0 0x02A0 0x0000 0x1 0x0
+#define MX93_PAD_ENET2_RX_CTL__SAI2_TX_DATA00                     0x00F0 0x02A0 0x0000 0x2 0x0
+#define MX93_PAD_ENET2_RX_CTL__FLEXIO2_FLEXIO22                   0x00F0 0x02A0 0x0000 0x4 0x0
+#define MX93_PAD_ENET2_RX_CTL__GPIO4_IO22                         0x00F0 0x02A0 0x0000 0x5 0x0
+#define MX93_PAD_ENET2_RXC__ENET1_RGMII_RXC                       0x00F4 0x02A4 0x0000 0x0 0x0
+#define MX93_PAD_ENET2_RXC__ENET1_RX_ER                           0x00F4 0x02A4 0x0000 0x1 0x0
+#define MX93_PAD_ENET2_RXC__SAI2_TX_DATA01                        0x00F4 0x02A4 0x0000 0x2 0x0
+#define MX93_PAD_ENET2_RXC__FLEXIO2_FLEXIO23                      0x00F4 0x02A4 0x0000 0x4 0x0
+#define MX93_PAD_ENET2_RXC__GPIO4_IO23                            0x00F4 0x02A4 0x0000 0x5 0x0
+#define MX93_PAD_ENET2_RD0__ENET1_RGMII_RD0                       0x00F8 0x02A8 0x0000 0x0 0x0
+#define MX93_PAD_ENET2_RD0__LPUART4_RX                            0x00F8 0x02A8 0x0424 0x1 0x1
+#define MX93_PAD_ENET2_RD0__SAI2_TX_DATA02                        0x00F8 0x02A8 0x0000 0x2 0x0
+#define MX93_PAD_ENET2_RD0__FLEXIO2_FLEXIO24                      0x00F8 0x02A8 0x0000 0x4 0x0
+#define MX93_PAD_ENET2_RD0__GPIO4_IO24                            0x00F8 0x02A8 0x0000 0x5 0x0
+#define MX93_PAD_ENET2_RD1__ENET1_RGMII_RD1                       0x00FC 0x02AC 0x0000 0x0 0x0
+#define MX93_PAD_ENET2_RD1__SPDIF_IN                              0x00FC 0x02AC 0x0454 0x1 0x1
+#define MX93_PAD_ENET2_RD1__SAI2_TX_DATA03                        0x00FC 0x02AC 0x0000 0x2 0x0
+#define MX93_PAD_ENET2_RD1__FLEXIO2_FLEXIO25                      0x00FC 0x02AC 0x0000 0x4 0x0
+#define MX93_PAD_ENET2_RD1__GPIO4_IO25                            0x00FC 0x02AC 0x0000 0x5 0x0
+#define MX93_PAD_ENET2_RD2__ENET1_RGMII_RD2                       0x0100 0x02B0 0x0000 0x0 0x0
+#define MX93_PAD_ENET2_RD2__LPUART4_CTS_B                         0x0100 0x02B0 0x0420 0x1 0x1
+#define MX93_PAD_ENET2_RD2__SAI2_MCLK                             0x0100 0x02B0 0x0000 0x2 0x0
+#define MX93_PAD_ENET2_RD2__MQS2_RIGHT                            0x0100 0x02B0 0x0000 0x3 0x0
+#define MX93_PAD_ENET2_RD2__FLEXIO2_FLEXIO26                      0x0100 0x02B0 0x0000 0x4 0x0
+#define MX93_PAD_ENET2_RD2__GPIO4_IO26                            0x0100 0x02B0 0x0000 0x5 0x0
+#define MX93_PAD_ENET2_RD3__ENET1_RGMII_RD3                       0x0104 0x02B4 0x0000 0x0 0x0
+#define MX93_PAD_ENET2_RD3__SPDIF_OUT                             0x0104 0x02B4 0x0000 0x1 0x0
+#define MX93_PAD_ENET2_RD3__SPDIF_IN                              0x0104 0x02B4 0x0454 0x2 0x2
+#define MX93_PAD_ENET2_RD3__MQS2_LEFT                             0x0104 0x02B4 0x0000 0x3 0x0
+#define MX93_PAD_ENET2_RD3__FLEXIO2_FLEXIO27                      0x0104 0x02B4 0x0000 0x4 0x0
+#define MX93_PAD_ENET2_RD3__GPIO4_IO27                            0x0104 0x02B4 0x0000 0x5 0x0
+#define MX93_PAD_SD1_CLK__FLEXIO1_FLEXIO08                        0x0108 0x02B8 0x038C 0x4 0x1
+#define MX93_PAD_SD1_CLK__GPIO3_IO08                              0x0108 0x02B8 0x0000 0x5 0x0
+#define MX93_PAD_SD1_CLK__USDHC1_CLK                              0x0108 0x02B8 0x0000 0x0 0x0
+#define MX93_PAD_SD1_CMD__USDHC1_CMD                              0x010C 0x02BC 0x0000 0x0 0x0
+#define MX93_PAD_SD1_CMD__FLEXIO1_FLEXIO09                        0x010C 0x02BC 0x0390 0x4 0x1
+#define MX93_PAD_SD1_CMD__GPIO3_IO09                              0x010C 0x02BC 0x0000 0x5 0x0
+#define MX93_PAD_SD1_DATA0__USDHC1_DATA0                          0x0110 0x02C0 0x0000 0x0 0x0
+#define MX93_PAD_SD1_DATA0__FLEXIO1_FLEXIO10                      0x0110 0x02C0 0x0394 0x4 0x1
+#define MX93_PAD_SD1_DATA0__GPIO3_IO10                            0x0110 0x02C0 0x0000 0x5 0x0
+#define MX93_PAD_SD1_DATA1__USDHC1_DATA1                          0x0114 0x02C4 0x0000 0x0 0x0
+#define MX93_PAD_SD1_DATA1__FLEXIO1_FLEXIO11                      0x0114 0x02C4 0x0398 0x4 0x1
+#define MX93_PAD_SD1_DATA1__GPIO3_IO11                            0x0114 0x02C4 0x0000 0x5 0x0
+#define MX93_PAD_SD1_DATA1__CCMSRCGPCMIX_INT_BOOT                 0x0114 0x02C4 0x0000 0x6 0x0
+#define MX93_PAD_SD1_DATA2__USDHC1_DATA2                          0x0118 0x02C8 0x0000 0x0 0x0
+#define MX93_PAD_SD1_DATA2__FLEXIO1_FLEXIO12                      0x0118 0x02C8 0x0000 0x4 0x0
+#define MX93_PAD_SD1_DATA2__GPIO3_IO12                            0x0118 0x02C8 0x0000 0x5 0x0
+#define MX93_PAD_SD1_DATA2__CCMSRCGPCMIX_PMIC_READY               0x0118 0x02C8 0x0000 0x6 0x0
+#define MX93_PAD_SD1_DATA3__USDHC1_DATA3                          0x011C 0x02CC 0x0000 0x0 0x0
+#define MX93_PAD_SD1_DATA3__FLEXSPI1_A_SS1_B                      0x011C 0x02CC 0x0000 0x1 0x0
+#define MX93_PAD_SD1_DATA3__FLEXIO1_FLEXIO13                      0x011C 0x02CC 0x039C 0x4 0x1
+#define MX93_PAD_SD1_DATA3__GPIO3_IO13                            0x011C 0x02CC 0x0000 0x5 0x0
+#define MX93_PAD_SD1_DATA4__USDHC1_DATA4                          0x0120 0x02D0 0x0000 0x0 0x0
+#define MX93_PAD_SD1_DATA4__FLEXSPI1_A_DATA04                     0x0120 0x02D0 0x0000 0x1 0x0
+#define MX93_PAD_SD1_DATA4__FLEXIO1_FLEXIO14                      0x0120 0x02D0 0x03A0 0x4 0x1
+#define MX93_PAD_SD1_DATA4__GPIO3_IO14                            0x0120 0x02D0 0x0000 0x5 0x0
+#define MX93_PAD_SD1_DATA5__USDHC1_DATA5                          0x0124 0x02D4 0x0000 0x0 0x0
+#define MX93_PAD_SD1_DATA5__FLEXSPI1_A_DATA05                     0x0124 0x02D4 0x0000 0x1 0x0
+#define MX93_PAD_SD1_DATA5__USDHC1_RESET_B                        0x0124 0x02D4 0x0000 0x2 0x0
+#define MX93_PAD_SD1_DATA5__FLEXIO1_FLEXIO15                      0x0124 0x02D4 0x03A4 0x4 0x1
+#define MX93_PAD_SD1_DATA5__GPIO3_IO15                            0x0124 0x02D4 0x0000 0x5 0x0
+#define MX93_PAD_SD1_DATA6__USDHC1_DATA6                          0x0128 0x02D8 0x0000 0x0 0x0
+#define MX93_PAD_SD1_DATA6__FLEXSPI1_A_DATA06                     0x0128 0x02D8 0x0000 0x1 0x0
+#define MX93_PAD_SD1_DATA6__USDHC1_CD_B                           0x0128 0x02D8 0x0000 0x2 0x0
+#define MX93_PAD_SD1_DATA6__FLEXIO1_FLEXIO16                      0x0128 0x02D8 0x03A8 0x4 0x1
+#define MX93_PAD_SD1_DATA6__GPIO3_IO16                            0x0128 0x02D8 0x0000 0x5 0x0
+#define MX93_PAD_SD1_DATA7__USDHC1_DATA7                          0x012C 0x02DC 0x0000 0x0 0x0
+#define MX93_PAD_SD1_DATA7__FLEXSPI1_A_DATA07                     0x012C 0x02DC 0x0000 0x1 0x0
+#define MX93_PAD_SD1_DATA7__USDHC1_WP                             0x012C 0x02DC 0x0000 0x2 0x0
+#define MX93_PAD_SD1_DATA7__FLEXIO1_FLEXIO17                      0x012C 0x02DC 0x03AC 0x4 0x1
+#define MX93_PAD_SD1_DATA7__GPIO3_IO17                            0x012C 0x02DC 0x0000 0x5 0x0
+#define MX93_PAD_SD1_STROBE__USDHC1_STROBE                        0x0130 0x02E0 0x0000 0x0 0x0
+#define MX93_PAD_SD1_STROBE__FLEXSPI1_A_DQS                       0x0130 0x02E0 0x0000 0x1 0x0
+#define MX93_PAD_SD1_STROBE__FLEXIO1_FLEXIO18                     0x0130 0x02E0 0x03B0 0x4 0x1
+#define MX93_PAD_SD1_STROBE__GPIO3_IO18                           0x0130 0x02E0 0x0000 0x5 0x0
+#define MX93_PAD_SD2_VSELECT__USDHC2_VSELECT                      0x0134 0x02E4 0x0000 0x0 0x0
+#define MX93_PAD_SD2_VSELECT__USDHC2_WP                           0x0134 0x02E4 0x0000 0x1 0x0
+#define MX93_PAD_SD2_VSELECT__LPTMR2_ALT3                         0x0134 0x02E4 0x0410 0x2 0x1
+#define MX93_PAD_SD2_VSELECT__FLEXIO1_FLEXIO19                    0x0134 0x02E4 0x0000 0x4 0x0
+#define MX93_PAD_SD2_VSELECT__GPIO3_IO19                          0x0134 0x02E4 0x0000 0x5 0x0
+#define MX93_PAD_SD2_VSELECT__CCMSRCGPCMIX_EXT_CLK1               0x0134 0x02E4 0x0368 0x6 0x0
+#define MX93_PAD_SD3_CLK__USDHC3_CLK                              0x0138 0x02E8 0x0458 0x0 0x1
+#define MX93_PAD_SD3_CLK__FLEXSPI1_A_SCLK                         0x0138 0x02E8 0x0000 0x1 0x0
+#define MX93_PAD_SD3_CLK__FLEXIO1_FLEXIO20                        0x0138 0x02E8 0x03B4 0x4 0x1
+#define MX93_PAD_SD3_CLK__GPIO3_IO20                              0x0138 0x02E8 0x0000 0x5 0x0
+#define MX93_PAD_SD3_CMD__USDHC3_CMD                              0x013C 0x02EC 0x045C 0x0 0x1
+#define MX93_PAD_SD3_CMD__FLEXSPI1_A_SS0_B                        0x013C 0x02EC 0x0000 0x1 0x0
+#define MX93_PAD_SD3_CMD__FLEXIO1_FLEXIO21                        0x013C 0x02EC 0x0000 0x4 0x0
+#define MX93_PAD_SD3_CMD__GPIO3_IO21                              0x013C 0x02EC 0x0000 0x5 0x0
+#define MX93_PAD_SD3_DATA0__USDHC3_DATA0                          0x0140 0x02F0 0x0460 0x0 0x1
+#define MX93_PAD_SD3_DATA0__FLEXSPI1_A_DATA00                     0x0140 0x02F0 0x0000 0x1 0x0
+#define MX93_PAD_SD3_DATA0__FLEXIO1_FLEXIO22                      0x0140 0x02F0 0x03B8 0x4 0x1
+#define MX93_PAD_SD3_DATA0__GPIO3_IO22                            0x0140 0x02F0 0x0000 0x5 0x0
+#define MX93_PAD_SD3_DATA1__USDHC3_DATA1                          0x0144 0x02F4 0x0464 0x0 0x1
+#define MX93_PAD_SD3_DATA1__FLEXSPI1_A_DATA01                     0x0144 0x02F4 0x0000 0x1 0x0
+#define MX93_PAD_SD3_DATA1__FLEXIO1_FLEXIO23                      0x0144 0x02F4 0x03BC 0x4 0x1
+#define MX93_PAD_SD3_DATA1__GPIO3_IO23                            0x0144 0x02F4 0x0000 0x5 0x0
+#define MX93_PAD_SD3_DATA2__USDHC3_DATA2                          0x0148 0x02F8 0x0468 0x0 0x1
+#define MX93_PAD_SD3_DATA2__FLEXSPI1_A_DATA02                     0x0148 0x02F8 0x0000 0x1 0x0
+#define MX93_PAD_SD3_DATA2__FLEXIO1_FLEXIO24                      0x0148 0x02F8 0x03C0 0x4 0x1
+#define MX93_PAD_SD3_DATA2__GPIO3_IO24                            0x0148 0x02F8 0x0000 0x5 0x0
+#define MX93_PAD_SD3_DATA3__USDHC3_DATA3                          0x014C 0x02FC 0x046C 0x0 0x1
+#define MX93_PAD_SD3_DATA3__FLEXSPI1_A_DATA03                     0x014C 0x02FC 0x0000 0x1 0x0
+#define MX93_PAD_SD3_DATA3__FLEXIO1_FLEXIO25                      0x014C 0x02FC 0x03C4 0x4 0x1
+#define MX93_PAD_SD3_DATA3__GPIO3_IO25                            0x014C 0x02FC 0x0000 0x5 0x0
+#define MX93_PAD_SD2_CD_B__USDHC2_CD_B                            0x0150 0x0300 0x0000 0x0 0x0
+#define MX93_PAD_SD2_CD_B__ENET_QOS_1588_EVENT0_IN                0x0150 0x0300 0x0000 0x1 0x0
+#define MX93_PAD_SD2_CD_B__I3C2_SCL                               0x0150 0x0300 0x03CC 0x2 0x1
+#define MX93_PAD_SD2_CD_B__FLEXIO1_FLEXIO00                       0x0150 0x0300 0x036C 0x4 0x1
+#define MX93_PAD_SD2_CD_B__GPIO3_IO00                             0x0150 0x0300 0x0000 0x5 0x0
+#define MX93_PAD_SD2_CLK__USDHC2_CLK                              0x0154 0x0304 0x0000 0x0 0x0
+#define MX93_PAD_SD2_CLK__ENET_QOS_1588_EVENT0_OUT                0x0154 0x0304 0x0000 0x1 0x0
+#define MX93_PAD_SD2_CLK__I3C2_SDA                                0x0154 0x0304 0x03D0 0x2 0x1
+#define MX93_PAD_SD2_CLK__FLEXIO1_FLEXIO01                        0x0154 0x0304 0x0370 0x4 0x1
+#define MX93_PAD_SD2_CLK__GPIO3_IO01                              0x0154 0x0304 0x0000 0x5 0x0
+#define MX93_PAD_SD2_CLK__CCMSRCGPCMIX_OBSERVE0                   0x0154 0x0304 0x0000 0x6 0x0
+#define MX93_PAD_SD2_CMD__USDHC2_CMD                              0x0158 0x0308 0x0000 0x0 0x0
+#define MX93_PAD_SD2_CMD__ENET1_1588_EVENT0_IN                    0x0158 0x0308 0x0000 0x1 0x0
+#define MX93_PAD_SD2_CMD__I3C2_PUR                                0x0158 0x0308 0x0000 0x2 0x0
+#define MX93_PAD_SD2_CMD__I3C2_PUR_B                              0x0158 0x0308 0x0000 0x3 0x0
+#define MX93_PAD_SD2_CMD__FLEXIO1_FLEXIO02                        0x0158 0x0308 0x0374 0x4 0x1
+#define MX93_PAD_SD2_CMD__GPIO3_IO02                              0x0158 0x0308 0x0000 0x5 0x0
+#define MX93_PAD_SD2_CMD__CCMSRCGPCMIX_OBSERVE1                   0x0158 0x0308 0x0000 0x6 0x0
+#define MX93_PAD_SD2_DATA0__USDHC2_DATA0                          0x015C 0x030C 0x0000 0x0 0x0
+#define MX93_PAD_SD2_DATA0__ENET1_1588_EVENT0_OUT                 0x015C 0x030C 0x0000 0x1 0x0
+#define MX93_PAD_SD2_DATA0__CAN2_TX                               0x015C 0x030C 0x0000 0x2 0x0
+#define MX93_PAD_SD2_DATA0__FLEXIO1_FLEXIO03                      0x015C 0x030C 0x0378 0x4 0x1
+#define MX93_PAD_SD2_DATA0__GPIO3_IO03                            0x015C 0x030C 0x0000 0x5 0x0
+#define MX93_PAD_SD2_DATA0__CCMSRCGPCMIX_OBSERVE2                 0x015C 0x030C 0x0000 0x6 0x0
+#define MX93_PAD_SD2_DATA1__USDHC2_DATA1                          0x0160 0x0310 0x0000 0x0 0x0
+#define MX93_PAD_SD2_DATA1__ENET1_1588_EVENT1_IN                  0x0160 0x0310 0x0000 0x1 0x0
+#define MX93_PAD_SD2_DATA1__CAN2_RX                               0x0160 0x0310 0x0364 0x2 0x3
+#define MX93_PAD_SD2_DATA1__FLEXIO1_FLEXIO04                      0x0160 0x0310 0x037C 0x4 0x1
+#define MX93_PAD_SD2_DATA1__GPIO3_IO04                            0x0160 0x0310 0x0000 0x5 0x0
+#define MX93_PAD_SD2_DATA1__CCMSRCGPCMIX_WAIT                     0x0160 0x0310 0x0000 0x6 0x0
+#define MX93_PAD_SD2_DATA2__USDHC2_DATA2                          0x0164 0x0314 0x0000 0x0 0x0
+#define MX93_PAD_SD2_DATA2__ENET1_1588_EVENT1_OUT                 0x0164 0x0314 0x0000 0x1 0x0
+#define MX93_PAD_SD2_DATA2__MQS2_RIGHT                            0x0164 0x0314 0x0000 0x2 0x0
+#define MX93_PAD_SD2_DATA2__FLEXIO1_FLEXIO05                      0x0164 0x0314 0x0380 0x4 0x1
+#define MX93_PAD_SD2_DATA2__GPIO3_IO05                            0x0164 0x0314 0x0000 0x5 0x0
+#define MX93_PAD_SD2_DATA2__CCMSRCGPCMIX_STOP                     0x0164 0x0314 0x0000 0x6 0x0
+#define MX93_PAD_SD2_DATA3__USDHC2_DATA3                          0x0168 0x0318 0x0000 0x0 0x0
+#define MX93_PAD_SD2_DATA3__LPTMR2_ALT1                           0x0168 0x0318 0x0408 0x1 0x1
+#define MX93_PAD_SD2_DATA3__MQS2_LEFT                             0x0168 0x0318 0x0000 0x2 0x0
+#define MX93_PAD_SD2_DATA3__FLEXIO1_FLEXIO06                      0x0168 0x0318 0x0384 0x4 0x1
+#define MX93_PAD_SD2_DATA3__GPIO3_IO06                            0x0168 0x0318 0x0000 0x5 0x0
+#define MX93_PAD_SD2_DATA3__CCMSRCGPCMIX_EARLY_RESET              0x0168 0x0318 0x0000 0x6 0x0
+#define MX93_PAD_SD2_RESET_B__USDHC2_RESET_B                      0x016C 0x031C 0x0000 0x0 0x0
+#define MX93_PAD_SD2_RESET_B__LPTMR2_ALT2                         0x016C 0x031C 0x040C 0x1 0x1
+#define MX93_PAD_SD2_RESET_B__FLEXIO1_FLEXIO07                    0x016C 0x031C 0x0388 0x4 0x1
+#define MX93_PAD_SD2_RESET_B__GPIO3_IO07                          0x016C 0x031C 0x0000 0x5 0x0
+#define MX93_PAD_SD2_RESET_B__CCMSRCGPCMIX_SYSTEM_RESET           0x016C 0x031C 0x0000 0x6 0x0
+#define MX93_PAD_I2C1_SCL__LPI2C1_SCL                             0x0170 0x0320 0x0000 0x10 0x0
+#define MX93_PAD_I2C1_SCL__I3C1_SCL                               0x0170 0x0320 0x0000 0x1 0x0
+#define MX93_PAD_I2C1_SCL__LPUART1_DCB_B                          0x0170 0x0320 0x0000 0x2 0x0
+#define MX93_PAD_I2C1_SCL__TPM2_CH0                               0x0170 0x0320 0x0000 0x3 0x0
+#define MX93_PAD_I2C1_SCL__GPIO1_IO00                             0x0170 0x0320 0x0000 0x5 0x0
+#define MX93_PAD_I2C1_SDA__LPI2C1_SDA                             0x0174 0x0324 0x0000 0x10 0x0
+#define MX93_PAD_I2C1_SDA__I3C1_SDA                               0x0174 0x0324 0x0000 0x1 0x0
+#define MX93_PAD_I2C1_SDA__LPUART1_RIN_B                          0x0174 0x0324 0x0000 0x2 0x0
+#define MX93_PAD_I2C1_SDA__TPM2_CH1                               0x0174 0x0324 0x0000 0x3 0x0
+#define MX93_PAD_I2C1_SDA__GPIO1_IO01                             0x0174 0x0324 0x0000 0x5 0x0
+#define MX93_PAD_I2C2_SCL__LPI2C2_SCL                             0x0178 0x0328 0x0000 0x10 0x0
+#define MX93_PAD_I2C2_SCL__I3C1_PUR                               0x0178 0x0328 0x0000 0x1 0x0
+#define MX93_PAD_I2C2_SCL__LPUART2_DCB_B                          0x0178 0x0328 0x0000 0x2 0x0
+#define MX93_PAD_I2C2_SCL__TPM2_CH2                               0x0178 0x0328 0x0000 0x3 0x0
+#define MX93_PAD_I2C2_SCL__SAI1_RX_SYNC                           0x0178 0x0328 0x0000 0x4 0x0
+#define MX93_PAD_I2C2_SCL__GPIO1_IO02                             0x0178 0x0328 0x0000 0x5 0x0
+#define MX93_PAD_I2C2_SCL__I3C1_PUR_B                             0x0178 0x0328 0x0000 0x6 0x0
+#define MX93_PAD_I2C2_SDA__LPI2C2_SDA                             0x017C 0x032C 0x0000 0x10 0x0
+#define MX93_PAD_I2C2_SDA__LPUART2_RIN_B                          0x017C 0x032C 0x0000 0x2 0x0
+#define MX93_PAD_I2C2_SDA__TPM2_CH3                               0x017C 0x032C 0x0000 0x3 0x0
+#define MX93_PAD_I2C2_SDA__SAI1_RX_BCLK                           0x017C 0x032C 0x0000 0x4 0x0
+#define MX93_PAD_I2C2_SDA__GPIO1_IO03                             0x017C 0x032C 0x0000 0x5 0x0
+#define MX93_PAD_UART1_RXD__LPUART1_RX                            0x0180 0x0330 0x0000 0x0 0x0
+#define MX93_PAD_UART1_RXD__S400_UART_RX                          0x0180 0x0330 0x0000 0x1 0x0
+#define MX93_PAD_UART1_RXD__LPSPI2_SIN                            0x0180 0x0330 0x0000 0x2 0x0
+#define MX93_PAD_UART1_RXD__TPM1_CH0                              0x0180 0x0330 0x0000 0x3 0x0
+#define MX93_PAD_UART1_RXD__GPIO1_IO04                            0x0180 0x0330 0x0000 0x5 0x0
+#define MX93_PAD_UART1_TXD__LPUART1_TX                            0x0184 0x0334 0x0000 0x0 0x0
+#define MX93_PAD_UART1_TXD__S400_UART_TX                          0x0184 0x0334 0x0000 0x1 0x0
+#define MX93_PAD_UART1_TXD__LPSPI2_PCS0                           0x0184 0x0334 0x0000 0x2 0x0
+#define MX93_PAD_UART1_TXD__TPM1_CH1                              0x0184 0x0334 0x0000 0x3 0x0
+#define MX93_PAD_UART1_TXD__GPIO1_IO05                            0x0184 0x0334 0x0000 0x5 0x0
+#define MX93_PAD_UART2_RXD__LPUART2_RX                            0x0188 0x0338 0x0000 0x0 0x0
+#define MX93_PAD_UART2_RXD__LPUART1_CTS_B                         0x0188 0x0338 0x0000 0x1 0x0
+#define MX93_PAD_UART2_RXD__LPSPI2_SOUT                           0x0188 0x0338 0x0000 0x2 0x0
+#define MX93_PAD_UART2_RXD__TPM1_CH2                              0x0188 0x0338 0x0000 0x3 0x0
+#define MX93_PAD_UART2_RXD__SAI1_MCLK                             0x0188 0x0338 0x0448 0x4 0x0
+#define MX93_PAD_UART2_RXD__GPIO1_IO06                            0x0188 0x0338 0x0000 0x5 0x0
+#define MX93_PAD_UART2_TXD__LPUART2_TX                            0x018C 0x033C 0x0000 0x0 0x0
+#define MX93_PAD_UART2_TXD__LPUART1_RTS_B                         0x018C 0x033C 0x0000 0x1 0x0
+#define MX93_PAD_UART2_TXD__LPSPI2_SCK                            0x018C 0x033C 0x0000 0x2 0x0
+#define MX93_PAD_UART2_TXD__TPM1_CH3                              0x018C 0x033C 0x0000 0x3 0x0
+#define MX93_PAD_UART2_TXD__GPIO1_IO07                            0x018C 0x033C 0x0000 0x5 0x0
+#define MX93_PAD_PDM_CLK__PDM_CLK                                 0x0190 0x0340 0x0000 0x0 0x0
+#define MX93_PAD_PDM_CLK__MQS1_LEFT                               0x0190 0x0340 0x0000 0x1 0x0
+#define MX93_PAD_PDM_CLK__LPTMR1_ALT1                             0x0190 0x0340 0x0000 0x4 0x0
+#define MX93_PAD_PDM_CLK__GPIO1_IO08                              0x0190 0x0340 0x0000 0x5 0x0
+#define MX93_PAD_PDM_CLK__CAN1_TX                                 0x0190 0x0340 0x0000 0x6 0x0
+#define MX93_PAD_PDM_BIT_STREAM0__PDM_BIT_STREAM00                0x0194 0x0344 0x0438 0x0 0x2
+#define MX93_PAD_PDM_BIT_STREAM0__MQS1_RIGHT                      0x0194 0x0344 0x0000 0x1 0x0
+#define MX93_PAD_PDM_BIT_STREAM0__LPSPI1_PCS1                     0x0194 0x0344 0x0000 0x2 0x0
+#define MX93_PAD_PDM_BIT_STREAM0__TPM1_EXTCLK                     0x0194 0x0344 0x0000 0x3 0x0
+#define MX93_PAD_PDM_BIT_STREAM0__LPTMR1_ALT2                     0x0194 0x0344 0x0000 0x4 0x0
+#define MX93_PAD_PDM_BIT_STREAM0__GPIO1_IO09                      0x0194 0x0344 0x0000 0x5 0x0
+#define MX93_PAD_PDM_BIT_STREAM0__CAN1_RX                         0x0194 0x0344 0x0360 0x6 0x0
+#define MX93_PAD_PDM_BIT_STREAM1__PDM_BIT_STREAM01                0x0198 0x0348 0x043C 0x0 0x2
+#define MX93_PAD_PDM_BIT_STREAM1__NMI_GLUE_NMI                    0x0198 0x0348 0x0000 0x1 0x0
+#define MX93_PAD_PDM_BIT_STREAM1__LPSPI2_PCS1                     0x0198 0x0348 0x0000 0x2 0x0
+#define MX93_PAD_PDM_BIT_STREAM1__TPM2_EXTCLK                     0x0198 0x0348 0x0000 0x3 0x0
+#define MX93_PAD_PDM_BIT_STREAM1__LPTMR1_ALT3                     0x0198 0x0348 0x0000 0x4 0x0
+#define MX93_PAD_PDM_BIT_STREAM1__GPIO1_IO10                      0x0198 0x0348 0x0000 0x5 0x0
+#define MX93_PAD_PDM_BIT_STREAM1__CCMSRCGPCMIX_EXT_CLK1           0x0198 0x0348 0x0368 0x6 0x1
+#define MX93_PAD_SAI1_TXFS__SAI1_TX_SYNC                          0x019C 0x034C 0x0000 0x0 0x0
+#define MX93_PAD_SAI1_TXFS__SAI1_TX_DATA01                        0x019C 0x034C 0x0000 0x1 0x0
+#define MX93_PAD_SAI1_TXFS__LPSPI1_PCS0                           0x019C 0x034C 0x0000 0x2 0x0
+#define MX93_PAD_SAI1_TXFS__LPUART2_DTR_B                         0x019C 0x034C 0x0000 0x3 0x0
+#define MX93_PAD_SAI1_TXFS__MQS1_LEFT                             0x019C 0x034C 0x0000 0x4 0x0
+#define MX93_PAD_SAI1_TXFS__GPIO1_IO11                            0x019C 0x034C 0x0000 0x5 0x0
+#define MX93_PAD_SAI1_TXC__SAI1_TX_BCLK                           0x01A0 0x0350 0x0000 0x0 0x0
+#define MX93_PAD_SAI1_TXC__LPUART2_CTS_B                          0x01A0 0x0350 0x0000 0x1 0x0
+#define MX93_PAD_SAI1_TXC__LPSPI1_SIN                             0x01A0 0x0350 0x0000 0x2 0x0
+#define MX93_PAD_SAI1_TXC__LPUART1_DSR_B                          0x01A0 0x0350 0x0000 0x3 0x0
+#define MX93_PAD_SAI1_TXC__CAN1_RX                                0x01A0 0x0350 0x0360 0x4 0x1
+#define MX93_PAD_SAI1_TXC__GPIO1_IO12                             0x01A0 0x0350 0x0000 0x5 0x0
+#define MX93_PAD_SAI1_TXD0__SAI1_TX_DATA00                        0x01A4 0x0354 0x0000 0x0 0x0
+#define MX93_PAD_SAI1_TXD0__LPUART2_RTS_B                         0x01A4 0x0354 0x0000 0x1 0x0
+#define MX93_PAD_SAI1_TXD0__LPSPI1_SCK                            0x01A4 0x0354 0x0000 0x2 0x0
+#define MX93_PAD_SAI1_TXD0__LPUART1_DTR_B                         0x01A4 0x0354 0x0000 0x3 0x0
+#define MX93_PAD_SAI1_TXD0__CAN1_TX                               0x01A4 0x0354 0x0000 0x4 0x0
+#define MX93_PAD_SAI1_TXD0__GPIO1_IO13                            0x01A4 0x0354 0x0000 0x5 0x0
+#define MX93_PAD_SAI1_RXD0__SAI1_RX_DATA00                        0x01A8 0x0358 0x0000 0x0 0x0
+#define MX93_PAD_SAI1_RXD0__SAI1_MCLK                             0x01A8 0x0358 0x0448 0x1 0x1
+#define MX93_PAD_SAI1_RXD0__LPSPI1_SOUT                           0x01A8 0x0358 0x0000 0x2 0x0
+#define MX93_PAD_SAI1_RXD0__LPUART2_DSR_B                         0x01A8 0x0358 0x0000 0x3 0x0
+#define MX93_PAD_SAI1_RXD0__MQS1_RIGHT                            0x01A8 0x0358 0x0000 0x4 0x0
+#define MX93_PAD_SAI1_RXD0__GPIO1_IO14                            0x01A8 0x0358 0x0000 0x5 0x0
+#define MX93_PAD_WDOG_ANY__WDOG1_WDOG_ANY                         0x01AC 0x035C 0x0000 0x0 0x0
+#define MX93_PAD_WDOG_ANY__GPIO1_IO15                             0x01AC 0x035C 0x0000 0x5 0x0
+
+#endif /* __DTS_IMX93_PINFUNC_H */
diff --git a/arch/arm64/boot/dts/freescale/imx93.dtsi b/arch/arm64/boot/dts/freescale/imx93.dtsi
new file mode 100644 (file)
index 0000000..f83a07c
--- /dev/null
@@ -0,0 +1,334 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2022 NXP
+ */
+
+#include <dt-bindings/clock/imx93-clock.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "imx93-pinfunc.h"
+
+/ {
+       interrupt-parent = <&gic>;
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       aliases {
+               mmc0 = &usdhc1;
+               mmc1 = &usdhc2;
+               mmc2 = &usdhc3;
+               serial0 = &lpuart1;
+               serial1 = &lpuart2;
+               serial2 = &lpuart3;
+               serial3 = &lpuart4;
+               serial4 = &lpuart5;
+               serial5 = &lpuart6;
+               serial6 = &lpuart7;
+               serial7 = &lpuart8;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               A55_0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a55";
+                       reg = <0x0>;
+                       enable-method = "psci";
+                       #cooling-cells = <2>;
+               };
+
+               A55_1: cpu@100 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a55";
+                       reg = <0x100>;
+                       enable-method = "psci";
+                       #cooling-cells = <2>;
+               };
+
+       };
+
+       osc_32k: clock-osc-32k {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <32768>;
+               clock-output-names = "osc_32k";
+       };
+
+       osc_24m: clock-osc-24m {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <24000000>;
+               clock-output-names = "osc_24m";
+       };
+
+       clk_ext1: clock-ext1 {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <133000000>;
+               clock-output-names = "clk_ext1";
+       };
+
+       psci {
+               compatible = "arm,psci-1.0";
+               method = "smc";
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>;
+               clock-frequency = <24000000>;
+               arm,no-tick-in-suspend;
+               interrupt-parent = <&gic>;
+       };
+
+       gic: interrupt-controller@48000000 {
+               compatible = "arm,gic-v3";
+               reg = <0 0x48000000 0 0x10000>,
+                     <0 0x48040000 0 0xc0000>;
+               #interrupt-cells = <3>;
+               interrupt-controller;
+               interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-parent = <&gic>;
+       };
+
+       soc@0 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0x0 0x0 0x0 0x80000000>,
+                        <0x28000000 0x0 0x28000000 0x10000000>;
+
+               aips1: bus@44000000 {
+                       compatible = "fsl,aips-bus", "simple-bus";
+                       reg = <0x44000000 0x800000>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+
+                       mu1: mailbox@44230000 {
+                               compatible = "fsl,imx93-mu", "fsl,imx8ulp-mu";
+                               reg = <0x44230000 0x10000>;
+                               interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
+                               #mbox-cells = <2>;
+                               status = "disabled";
+                       };
+
+                       system_counter: timer@44290000 {
+                               compatible = "nxp,sysctr-timer";
+                               reg = <0x44290000 0x30000>;
+                               interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&osc_24m>;
+                               clock-names = "per";
+                       };
+
+                       lpuart1: serial@44380000 {
+                               compatible = "fsl,imx93-lpuart", "fsl,imx7ulp-lpuart";
+                               reg = <0x44380000 0x1000>;
+                               interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX93_CLK_LPUART1_GATE>;
+                               clock-names = "ipg";
+                               status = "disabled";
+                       };
+
+                       lpuart2: serial@44390000 {
+                               compatible = "fsl,imx93-lpuart", "fsl,imx7ulp-lpuart";
+                               reg = <0x44390000 0x1000>;
+                               interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX93_CLK_LPUART2_GATE>;
+                               clock-names = "ipg";
+                               status = "disabled";
+                       };
+
+                       iomuxc: pinctrl@443c0000 {
+                               compatible = "fsl,imx93-iomuxc";
+                               reg = <0x443c0000 0x10000>;
+                               status = "okay";
+                       };
+
+                       clk: clock-controller@44450000 {
+                               compatible = "fsl,imx93-ccm";
+                               reg = <0x44450000 0x10000>;
+                               #clock-cells = <1>;
+                               clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>;
+                               clock-names = "osc_32k", "osc_24m", "clk_ext1";
+                               status = "okay";
+                       };
+
+                       anatop: anatop@44480000 {
+                               compatible = "fsl,imx93-anatop", "syscon";
+                               reg = <0x44480000 0x10000>;
+                       };
+               };
+
+               aips2: bus@42000000 {
+                       compatible = "fsl,aips-bus", "simple-bus";
+                       reg = <0x42000000 0x800000>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+
+                       mu2: mailbox@42440000 {
+                               compatible = "fsl,imx93-mu", "fsl,imx8ulp-mu";
+                               reg = <0x42440000 0x10000>;
+                               interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
+                               #mbox-cells = <2>;
+                               status = "disabled";
+                       };
+
+                       lpuart3: serial@42570000 {
+                               compatible = "fsl,imx93-lpuart", "fsl,imx7ulp-lpuart";
+                               reg = <0x42570000 0x1000>;
+                               interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX93_CLK_LPUART3_GATE>;
+                               clock-names = "ipg";
+                               status = "disabled";
+                       };
+
+                       lpuart4: serial@42580000 {
+                               compatible = "fsl,imx93-lpuart", "fsl,imx7ulp-lpuart";
+                               reg = <0x42580000 0x1000>;
+                               interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX93_CLK_LPUART4_GATE>;
+                               clock-names = "ipg";
+                               status = "disabled";
+                       };
+
+                       lpuart5: serial@42590000 {
+                               compatible = "fsl,imx93-lpuart", "fsl,imx7ulp-lpuart";
+                               reg = <0x42590000 0x1000>;
+                               interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX93_CLK_LPUART5_GATE>;
+                               clock-names = "ipg";
+                               status = "disabled";
+                       };
+
+                       lpuart6: serial@425a0000 {
+                               compatible = "fsl,imx93-lpuart", "fsl,imx7ulp-lpuart";
+                               reg = <0x425a0000 0x1000>;
+                               interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX93_CLK_LPUART6_GATE>;
+                               clock-names = "ipg";
+                               status = "disabled";
+                       };
+
+                       lpuart7: serial@42690000 {
+                               compatible = "fsl,imx93-lpuart", "fsl,imx7ulp-lpuart";
+                               reg = <0x42690000 0x1000>;
+                               interrupts = <GIC_SPI 210 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX93_CLK_LPUART7_GATE>;
+                               clock-names = "ipg";
+                               status = "disabled";
+                       };
+
+                       lpuart8: serial@426a0000 {
+                               compatible = "fsl,imx93-lpuart", "fsl,imx7ulp-lpuart";
+                               reg = <0x426a0000 0x1000>;
+                               interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX93_CLK_LPUART8_GATE>;
+                               clock-names = "ipg";
+                               status = "disabled";
+                       };
+               };
+
+               aips3: bus@42800000 {
+                       compatible = "fsl,aips-bus", "simple-bus";
+                       reg = <0x42800000 0x800000>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+
+                       usdhc1: mmc@42850000 {
+                               compatible = "fsl,imx93-usdhc", "fsl,imx8mm-usdhc";
+                               reg = <0x42850000 0x10000>;
+                               interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX93_CLK_DUMMY>,
+                                        <&clk IMX93_CLK_DUMMY>,
+                                        <&clk IMX93_CLK_USDHC1_GATE>;
+                               clock-names = "ipg", "ahb", "per";
+                               bus-width = <8>;
+                               fsl,tuning-start-tap = <20>;
+                               fsl,tuning-step= <2>;
+                               status = "disabled";
+                       };
+
+                       usdhc2: mmc@42860000 {
+                               compatible = "fsl,imx93-usdhc", "fsl,imx8mm-usdhc";
+                               reg = <0x42860000 0x10000>;
+                               interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX93_CLK_DUMMY>,
+                                        <&clk IMX93_CLK_DUMMY>,
+                                        <&clk IMX93_CLK_USDHC2_GATE>;
+                               clock-names = "ipg", "ahb", "per";
+                               bus-width = <4>;
+                               fsl,tuning-start-tap = <20>;
+                               fsl,tuning-step= <2>;
+                               status = "disabled";
+                       };
+
+                       usdhc3: mmc@428b0000 {
+                               compatible = "fsl,imx93-usdhc", "fsl,imx8mm-usdhc";
+                               reg = <0x428b0000 0x10000>;
+                               interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clk IMX93_CLK_DUMMY>,
+                                        <&clk IMX93_CLK_DUMMY>,
+                                        <&clk IMX93_CLK_USDHC3_GATE>;
+                               clock-names = "ipg", "ahb", "per";
+                               bus-width = <4>;
+                               fsl,tuning-start-tap = <20>;
+                               fsl,tuning-step= <2>;
+                               status = "disabled";
+                       };
+               };
+
+               gpio2: gpio@43810080 {
+                       compatible = "fsl,imx93-gpio", "fsl,imx7ulp-gpio";
+                       reg = <0x43810080 0x1000>, <0x43810040 0x40>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+                       gpio-ranges = <&iomuxc 0 32 32>;
+               };
+
+               gpio3: gpio@43820080 {
+                       compatible = "fsl,imx93-gpio", "fsl,imx7ulp-gpio";
+                       reg = <0x43820080 0x1000>, <0x43820040 0x40>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+                       gpio-ranges = <&iomuxc 0 64 32>;
+               };
+
+               gpio4: gpio@43830080 {
+                       compatible = "fsl,imx93-gpio", "fsl,imx7ulp-gpio";
+                       reg = <0x43830080 0x1000>, <0x43830040 0x40>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupts = <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+                       gpio-ranges = <&iomuxc 0 96 32>;
+               };
+
+               gpio1: gpio@47400080 {
+                       compatible = "fsl,imx93-gpio", "fsl,imx7ulp-gpio";
+                       reg = <0x47400080 0x1000>, <0x47400040 0x40>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+                       gpio-ranges = <&iomuxc 0 0 32>;
+               };
+       };
+};
index c2f0f1a..104bdd4 100644 (file)
@@ -16,7 +16,6 @@
        };
 
        chosen {
-               // bootargs = "console=ttymxc2,115200 earlycon=ec_imx6q,0x30880000,115200";
                stdout-path = &uart3;
        };
 
                pinctrl-0 = <&pinctrl_gpiobutton>;
                autorepeat;
 
-               switch1 {
+               switch-1 {
                        label = "switch1";
                        linux,code = <BTN_0>;
                        gpios = <&gpio1 5 GPIO_ACTIVE_LOW>;
                        wakeup-source;
                };
 
-               btn2: switch2 {
+               btn2: switch-2 {
                        label = "switch2";
                        linux,code = <BTN_1>;
                        gpios = <&gpio2 0 GPIO_ACTIVE_LOW>;
                        wakeup-source;
                };
 
-               switch3 {
+               switch-3 {
                        label = "switch3";
                        linux,code = <BTN_2>;
                        gpios = <&gpio1 7 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
 
-/* UART4 is assigned to Cortex-M4 */
 &usdhc2 {
        pinctrl-names = "default", "state_100mhz", "state_200mhz";
        pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
index 59ea8a2..824d401 100644 (file)
@@ -79,7 +79,7 @@
                };
        };
 
-       soc {
+       soc@0 {
                compatible = "simple-bus";
                #address-cells = <1>;
                #size-cells = <1>;
index f68580d..0192a01 100644 (file)
@@ -49,9 +49,9 @@
                ramoops@32000000 {
                        compatible = "ramoops";
                        reg = <0x0 0x32000000 0x0 0x00100000>;
-                       record-size     = <0x00020000>;
-                       console-size    = <0x00020000>;
-                       ftrace-size     = <0x00020000>;
+                       record-size = <0x00020000>;
+                       console-size = <0x00020000>;
+                       ftrace-size = <0x00020000>;
                };
        };
 
@@ -63,9 +63,9 @@
                        compatible = "syscon-reboot-mode";
                        offset = <0x0>;
 
-                       mode-normal     = <0x77665501>;
-                       mode-bootloader = <0x77665500>;
-                       mode-recovery   = <0x77665502>;
+                       mode-normal = <0x77665501>;
+                       mode-bootloader = <0x77665500>;
+                       mode-recovery = <0x77665502>;
                };
        };
 
@@ -74,7 +74,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&pwr_key_pmx_func &pwr_key_cfg_func>;
 
-               power {
+               key-power {
                        wakeup-source;
                        gpios = <&gpio4 2 GPIO_ACTIVE_LOW>;
                        label = "GPIO Power";
index 6b3057a..8343d0c 100644 (file)
                        reg = <0x0 0xfdf00000 0x0 0x1000>;
                        interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
                        dma-names = "rx", "tx";
-                       dmas =  <&dma0 2 &dma0 3>;
+                       dmas = <&dma0 2 &dma0 3>;
                        clocks = <&crg_ctrl HI3660_CLK_GATE_UART1>,
                                 <&crg_ctrl HI3660_CLK_GATE_UART1>;
                        clock-names = "uartclk", "apb_pclk";
                        reg = <0x0 0xfdf03000 0x0 0x1000>;
                        interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
                        dma-names = "rx", "tx";
-                       dmas =  <&dma0 4 &dma0 5>;
+                       dmas = <&dma0 4 &dma0 5>;
                        clocks = <&crg_ctrl HI3660_CLK_GATE_UART2>,
                                 <&crg_ctrl HI3660_PCLK>;
                        clock-names = "uartclk", "apb_pclk";
                        reg = <0x0 0xfdf01000 0x0 0x1000>;
                        interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
                        dma-names = "rx", "tx";
-                       dmas =  <&dma0 6 &dma0 7>;
+                       dmas = <&dma0 6 &dma0 7>;
                        clocks = <&crg_ctrl HI3660_CLK_GATE_UART4>,
                                 <&crg_ctrl HI3660_CLK_GATE_UART4>;
                        clock-names = "uartclk", "apb_pclk";
                        reg = <0x0 0xfdf05000 0x0 0x1000>;
                        interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
                        dma-names = "rx", "tx";
-                       dmas =  <&dma0 8 &dma0 9>;
+                       dmas = <&dma0 8 &dma0 9>;
                        clocks = <&crg_ctrl HI3660_CLK_GATE_UART5>,
                                 <&crg_ctrl HI3660_CLK_GATE_UART5>;
                        clock-names = "uartclk", "apb_pclk";
index 3125c38..886b93c 100644 (file)
                        interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
                        gpio-controller;
                        #gpio-cells = <2>;
-                       gpio-ranges =  <&pmx0 0 13 4 &pmx0 7 17 1>;
+                       gpio-ranges = <&pmx0 0 13 4 &pmx0 7 17 1>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
                        clocks = <&crg_ctrl HI3670_PCLK_GPIO3>;
index 3df2afb..629e604 100644 (file)
@@ -54,9 +54,9 @@
                ramoops@21f00000 {
                        compatible = "ramoops";
                        reg = <0x0 0x21f00000 0x0 0x00100000>;
-                       record-size     = <0x00020000>;
-                       console-size    = <0x00020000>;
-                       ftrace-size     = <0x00020000>;
+                       record-size = <0x00020000>;
+                       console-size = <0x00020000>;
+                       ftrace-size = <0x00020000>;
                };
 
                /* global autoconfigured region for contiguous allocations */
@@ -76,9 +76,9 @@
                        compatible = "syscon-reboot-mode";
                        offset = <0x0>;
 
-                       mode-normal     = <0x77665501>;
-                       mode-bootloader = <0x77665500>;
-                       mode-recovery   = <0x77665502>;
+                       mode-normal = <0x77665501>;
+                       mode-bootloader = <0x77665500>;
+                       mode-recovery = <0x77665502>;
                };
        };
 
index 40f3e00..c4eaebb 100644 (file)
                stdout-path = "serial0:115200n8";
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
-               pwrbutton {
+               pwr-button {
                        label = "Power Button";
                        gpios = <&porta 8 GPIO_ACTIVE_LOW>;
                        linux,code = <116>;
index 70d7732..2f8b03b 100644 (file)
 
                        port@1 {
                                reg = <1>;
-                               serdes-syscon= <&serdes_ctrl>;
+                               serdes-syscon = <&serdes_ctrl>;
                                port-rst-offset = <1>;
                                port-mode-offset = <1>;
                                media-type = "fiber";
                        port@4 {
                                reg = <4>;
                                phy-handle = <&phy0>;
-                               serdes-syscon= <&serdes_ctrl>;
+                               serdes-syscon = <&serdes_ctrl>;
                                port-rst-offset = <4>;
                                port-mode-offset = <2>;
                                media-type = "copper";
                        port@5 {
                                reg = <5>;
                                phy-handle = <&phy1>;
-                               serdes-syscon= <&serdes_ctrl>;
+                               serdes-syscon = <&serdes_ctrl>;
                                port-rst-offset = <5>;
                                port-mode-offset = <3>;
                                media-type = "copper";
index 6baf6a6..1a16662 100644 (file)
 
                        port@1 {
                                reg = <1>;
-                               serdes-syscon= <&serdes_ctrl>;
+                               serdes-syscon = <&serdes_ctrl>;
                                cpld-syscon = <&dsa_cpld 0x4>;
                                port-rst-offset = <1>;
                                port-mode-offset = <1>;
                        port@4 {
                                reg = <4>;
                                phy-handle = <&phy0>;
-                               serdes-syscon= <&serdes_ctrl>;
+                               serdes-syscon = <&serdes_ctrl>;
                                port-rst-offset = <4>;
                                port-mode-offset = <2>;
                                mc-mac-mask = [ff f0 00 00 00 00];
                        port@5 {
                                reg = <5>;
                                phy-handle = <&phy1>;
-                               serdes-syscon= <&serdes_ctrl>;
+                               serdes-syscon = <&serdes_ctrl>;
                                port-rst-offset = <5>;
                                port-mode-offset = <3>;
                                mc-mac-mask = [ff f0 00 00 00 00];
index caccb03..7bbec8a 100644 (file)
                        sdramedac {
                                compatible = "altr,sdram-edac-s10";
                                altr,sdr-syscon = <&sdr>;
-                               interrupts = <16 4>;
+                               interrupts = <16 IRQ_TYPE_LEVEL_HIGH>;
                        };
 
                        ocram-ecc@ff8cc000 {
                                             "altr,socfpga-a10-ocram-ecc";
                                reg = <0xff8cc000 0x100>;
                                altr,ecc-parent = <&ocram>;
-                               interrupts = <1 4>;
+                               interrupts = <1 IRQ_TYPE_LEVEL_HIGH>;
                        };
 
                        usb0-ecc@ff8c4000 {
                                             "altr,socfpga-usb-ecc";
                                reg = <0xff8c4000 0x100>;
                                altr,ecc-parent = <&usb0>;
-                               interrupts = <2 4>;
+                               interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
                        };
 
                        emac0-rx-ecc@ff8c0000 {
                                             "altr,socfpga-eth-mac-ecc";
                                reg = <0xff8c0000 0x100>;
                                altr,ecc-parent = <&gmac0>;
-                               interrupts = <4 4>;
+                               interrupts = <4 IRQ_TYPE_LEVEL_HIGH>;
                        };
 
                        emac0-tx-ecc@ff8c0400 {
                                             "altr,socfpga-eth-mac-ecc";
                                reg = <0xff8c0400 0x100>;
                                altr,ecc-parent = <&gmac0>;
-                               interrupts = <5 4>;
+                               interrupts = <5 IRQ_TYPE_LEVEL_HIGH>;
                        };
 
                        sdmmca-ecc@ff8c8c00 {
                                             "altr,socfpga-sdmmc-ecc";
                                reg = <0xff8c8c00 0x100>;
                                altr,ecc-parent = <&mmc>;
-                               interrupts = <14 4>,
-                                            <15 4>;
+                               interrupts = <14 IRQ_TYPE_LEVEL_HIGH>,
+                                            <15 IRQ_TYPE_LEVEL_HIGH>;
                        };
                };
 
index bec9748..78ae73d 100644 (file)
@@ -52,7 +52,7 @@
        };
 
        psci {
-               compatible  = "arm,psci-0.2", "arm,psci";
+               compatible = "arm,psci-0.2", "arm,psci";
                method = "smc";
                cpu_suspend = <0x84000001>;
                cpu_off = <0x84000002>;
                        interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                uart1: serial@fe100000 {
                        compatible = "arm,pl011", "arm,primecell";
                        interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                uart2: serial@fe200000 {
                        compatible = "arm,pl011", "arm,primecell";
                        interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                spi0: spi@fe800000 {
                        compatible = "arm,pl022", "arm,primecell";
                        reg = <0x0 0xfd400000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio1: gpio@fd410000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd410000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio2: gpio@fd420000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd420000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio3: gpio@fd430000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd440000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio5: gpio@fd450000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd450000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio6: gpio@fd460000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd460000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio7: gpio@fd470000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd470000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio8: gpio@fd480000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd480000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio9: gpio@fd490000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd490000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio10: gpio@fd4a0000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd4a0000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio11: gpio@fd4b0000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd4c0000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio13: gpio@fd4d0000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd4d0000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio14: gpio@fd4e0000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd4e0000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio15: gpio@fd4f0000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd4f0000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio16: gpio@fd500000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd500000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio17: gpio@fd510000 {
                        #gpio-cells = <2>;
index ada3d4d..2173316 100644 (file)
@@ -52,7 +52,7 @@
        };
 
        psci {
-               compatible  = "arm,psci-0.2", "arm,psci";
+               compatible = "arm,psci-0.2", "arm,psci";
                method = "smc";
                cpu_suspend = <0x84000001>;
                cpu_off = <0x84000002>;
                        interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                uart1: serial@fe100000 {
                        compatible = "arm,pl011", "arm,primecell";
                        interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                uart2: serial@fe200000 {
                        compatible = "arm,pl011", "arm,primecell";
                        interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                spi0: spi@fe800000 {
                        compatible = "arm,pl022", "arm,primecell";
                        reg = <0x0 0xfd400000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio1: gpio@fd410000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd410000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio2: gpio@fd420000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd420000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio3: gpio@fd430000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd440000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio5: gpio@fd450000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd450000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio6: gpio@fd460000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd460000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio7: gpio@fd470000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd470000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio8: gpio@fd480000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd480000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio9: gpio@fd490000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd490000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio10: gpio@fd4a0000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd4a0000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio11: gpio@fd4b0000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd4c0000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio13: gpio@fd4d0000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd4d0000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio14: gpio@fd4e0000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd4e0000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio15: gpio@fd4f0000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd4f0000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio16: gpio@fd500000 {
                        #gpio-cells = <2>;
                        reg = <0x0 0xfd500000 0x1000>;
                        clocks = <&clk_bus>;
                        clock-names = "apb_pclk";
-                       status="disabled";
+                       status = "disabled";
                };
                gpio17: gpio@fd510000 {
                        #gpio-cells = <2>;
index 1c794cd..b6d493e 100644 (file)
@@ -24,3 +24,4 @@ dtb-$(CONFIG_ARCH_MVEBU) += cn9132-db.dtb
 dtb-$(CONFIG_ARCH_MVEBU) += cn9132-db-B.dtb
 dtb-$(CONFIG_ARCH_MVEBU) += cn9130-crb-A.dtb
 dtb-$(CONFIG_ARCH_MVEBU) += cn9130-crb-B.dtb
+dtb-$(CONFIG_ARCH_MVEBU) += ac5-98dx35xx-rd.dtb
diff --git a/arch/arm64/boot/dts/marvell/ac5-98dx25xx.dtsi b/arch/arm64/boot/dts/marvell/ac5-98dx25xx.dtsi
new file mode 100644 (file)
index 0000000..80b44c7
--- /dev/null
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Device Tree For AC5.
+ *
+ * Copyright (C) 2021 Marvell
+ * Copyright (C) 2022 Allied Telesis Labs
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+       model = "Marvell AC5 SoC";
+       compatible = "marvell,ac5";
+       interrupt-parent = <&gic>;
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       cpus {
+               #address-cells = <2>;
+               #size-cells = <0>;
+
+               cpu-map {
+                       cluster0 {
+                               core0 {
+                                       cpu = <&cpu0>;
+                               };
+                               core1 {
+                                       cpu = <&cpu1>;
+                               };
+                       };
+               };
+
+               cpu0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a55";
+                       reg = <0x0 0x0>;
+                       enable-method = "psci";
+                       next-level-cache = <&l2>;
+               };
+
+               cpu1: cpu@1 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a55";
+                       reg = <0x0 0x100>;
+                       enable-method = "psci";
+                       next-level-cache = <&l2>;
+               };
+
+               l2: l2-cache {
+                       compatible = "cache";
+               };
+       };
+
+       psci {
+               compatible = "arm,psci-0.2";
+               method = "smc";
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_PPI 8 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_PPI 10 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH>;
+       };
+
+       pmu {
+               compatible = "arm,armv8-pmuv3";
+               interrupts = <GIC_PPI 12 IRQ_TYPE_LEVEL_HIGH>;
+       };
+
+       soc {
+               compatible = "simple-bus";
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+               dma-ranges;
+
+               internal-regs@7f000000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "simple-bus";
+                       /* 16M internal register @ 0x7f00_0000 */
+                       ranges = <0x0 0x0 0x7f000000 0x1000000>;
+                       dma-coherent;
+
+                       uart0: serial@12000 {
+                               compatible = "snps,dw-apb-uart";
+                               reg = <0x12000 0x100>;
+                               reg-shift = <2>;
+                               interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+                               reg-io-width = <1>;
+                               clocks = <&cnm_clock>;
+                               status = "okay";
+                       };
+
+                       mdio: mdio@22004 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "marvell,orion-mdio";
+                               reg = <0x22004 0x4>;
+                               clocks = <&cnm_clock>;
+                       };
+
+                       i2c0: i2c@11000{
+                               compatible = "marvell,mv78230-i2c";
+                               reg = <0x11000 0x20>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               clocks = <&cnm_clock>;
+                               clock-names = "core";
+                               interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
+                               clock-frequency=<100000>;
+
+                               pinctrl-names = "default", "gpio";
+                               pinctrl-0 = <&i2c0_pins>;
+                               pinctrl-1 = <&i2c0_gpio>;
+                               scl_gpio = <&gpio0 26 GPIO_ACTIVE_HIGH>;
+                               sda_gpio = <&gpio0 27 GPIO_ACTIVE_HIGH>;
+                               status = "disabled";
+                       };
+
+                       i2c1: i2c@11100{
+                               compatible = "marvell,mv78230-i2c";
+                               reg = <0x11100 0x20>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               clocks = <&cnm_clock>;
+                               clock-names = "core";
+                               interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+                               clock-frequency=<100000>;
+
+                               pinctrl-names = "default", "gpio";
+                               pinctrl-0 = <&i2c1_pins>;
+                               pinctrl-1 = <&i2c1_gpio>;
+                               scl_gpio = <&gpio0 20 GPIO_ACTIVE_HIGH>;
+                               sda_gpio = <&gpio0 21 GPIO_ACTIVE_HIGH>;
+                               status = "disabled";
+                       };
+
+                       gpio0: gpio@18100 {
+                               compatible = "marvell,orion-gpio";
+                               reg = <0x18100 0x40>;
+                               ngpios = <32>;
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               gpio-ranges = <&pinctrl0 0 0 32>;
+                               marvell,pwm-offset = <0x1f0>;
+                               interrupt-controller;
+                               #interrupt-cells = <2>;
+                               interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>,
+                                            <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>,
+                                            <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>,
+                                            <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
+                       };
+
+                       gpio1: gpio@18140 {
+                               reg = <0x18140 0x40>;
+                               compatible = "marvell,orion-gpio";
+                               ngpios = <14>;
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               gpio-ranges = <&pinctrl0 0 32 14>;
+                               marvell,pwm-offset = <0x1f0>;
+                               interrupt-controller;
+                               #interrupt-cells = <2>;
+                               interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>,
+                                            <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+                       };
+               };
+
+               /*
+                * Dedicated section for devices behind 32bit controllers so we
+                * can configure specific DMA mapping for them
+                */
+               behind-32bit-controller@7f000000 {
+                       compatible = "simple-bus";
+                       #address-cells = <0x2>;
+                       #size-cells = <0x2>;
+                       ranges = <0x0 0x0 0x0 0x7f000000 0x0 0x1000000>;
+                       /* Host phy ram starts at 0x200M */
+                       dma-ranges = <0x0 0x0 0x2 0x0 0x1 0x0>;
+                       dma-coherent;
+
+                       eth0: ethernet@20000 {
+                               compatible = "marvell,armada-ac5-neta";
+                               reg = <0x0 0x20000 0x0 0x4000>;
+                               interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&cnm_clock>;
+                               phy-mode = "sgmii";
+                               status = "disabled";
+                       };
+
+                       eth1: ethernet@24000 {
+                               compatible = "marvell,armada-ac5-neta";
+                               reg = <0x0 0x24000 0x0 0x4000>;
+                               interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&cnm_clock>;
+                               phy-mode = "sgmii";
+                               status = "disabled";
+                       };
+
+                       usb0: usb@80000 {
+                               compatible = "marvell,orion-ehci";
+                               reg = <0x0 0x80000 0x0 0x500>;
+                               interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
+                               status = "disabled";
+                       };
+
+                       usb1: usb@a0000 {
+                               compatible = "marvell,orion-ehci";
+                               reg = <0x0 0xa0000 0x0 0x500>;
+                               interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
+                               status = "disabled";
+                       };
+               };
+
+               pinctrl0: pinctrl@80020100 {
+                       compatible = "marvell,ac5-pinctrl";
+                       reg = <0 0x80020100 0 0x20>;
+
+                       i2c0_pins: i2c0-pins {
+                               marvell,pins = "mpp26", "mpp27";
+                               marvell,function = "i2c0";
+                       };
+
+                       i2c0_gpio: i2c0-gpio-pins {
+                               marvell,pins = "mpp26", "mpp27";
+                               marvell,function = "gpio";
+                       };
+
+                       i2c1_pins: i2c1-pins {
+                               marvell,pins = "mpp20", "mpp21";
+                               marvell,function = "i2c1";
+                       };
+
+                       i2c1_gpio: i2c1-gpio-pins {
+                               marvell,pins = "mpp20", "mpp21";
+                               marvell,function = "i2c1";
+                       };
+               };
+
+               spi0: spi@805a0000 {
+                       compatible = "marvell,armada-3700-spi";
+                       reg = <0x0 0x805a0000 0x0 0x50>;
+                       #address-cells = <0x1>;
+                       #size-cells = <0x0>;
+                       clocks = <&spi_clock>;
+                       interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>;
+                       num-cs = <1>;
+                       status = "disabled";
+               };
+
+               spi1: spi@805a8000 {
+                       compatible = "marvell,armada-3700-spi";
+                       reg = <0x0 0x805a8000 0x0 0x50>;
+                       #address-cells = <0x1>;
+                       #size-cells = <0x0>;
+                       clocks = <&spi_clock>;
+                       interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
+                       num-cs = <1>;
+                       status = "disabled";
+               };
+
+               gic: interrupt-controller@80600000 {
+                       compatible = "arm,gic-v3";
+                       #interrupt-cells = <3>;
+                       interrupt-controller;
+                       reg = <0x0 0x80600000 0x0 0x10000>, /* GICD */
+                             <0x0 0x80660000 0x0 0x40000>; /* GICR */
+                       interrupts = <GIC_PPI 6 IRQ_TYPE_LEVEL_HIGH>;
+               };
+       };
+
+       clocks {
+               cnm_clock: cnm-clock {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <328000000>;
+               };
+
+               spi_clock: spi-clock {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <200000000>;
+               };
+       };
+};
diff --git a/arch/arm64/boot/dts/marvell/ac5-98dx35xx-rd.dts b/arch/arm64/boot/dts/marvell/ac5-98dx35xx-rd.dts
new file mode 100644 (file)
index 0000000..f0ebdb8
--- /dev/null
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Device Tree For RD-AC5X.
+ *
+ * Copyright (C) 2021 Marvell
+ * Copyright (C) 2022 Allied Telesis Labs
+ */
+/*
+ * Device Tree file for Marvell Alleycat 5X development board
+ * This board file supports the B configuration of the board
+ */
+
+/dts-v1/;
+
+#include "ac5-98dx35xx.dtsi"
+
+/ {
+       model = "Marvell RD-AC5X Board";
+       compatible = "marvell,rd-ac5x", "marvell,ac5x", "marvell,ac5";
+
+       aliases {
+               serial0 = &uart0;
+               spiflash0 = &spiflash0;
+               gpio0 = &gpio0;
+               gpio1 = &gpio1;
+               ethernet0 = &eth0;
+               ethernet1 = &eth1;
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x2 0x00000000 0x0 0x40000000>;
+       };
+
+       usb1phy: usb-phy {
+               compatible = "usb-nop-xceiv";
+               #phy-cells = <0>;
+       };
+};
+
+&mdio {
+       phy0: ethernet-phy@0 {
+               reg = <0>;
+       };
+};
+
+&i2c0 {
+       status = "okay";
+};
+
+&i2c1 {
+       status = "okay";
+};
+
+&eth0 {
+       status = "okay";
+       phy-handle = <&phy0>;
+};
+
+/* USB0 is a host USB */
+&usb0 {
+       status = "okay";
+};
+
+/* USB1 is a peripheral USB */
+&usb1 {
+       status = "okay";
+       phys = <&usb1phy>;
+       phy-names = "usb-phy";
+       dr_mode = "peripheral";
+};
+
+&spi0 {
+       status = "okay";
+
+       spiflash0: flash@0 {
+               compatible = "jedec,spi-nor";
+               spi-max-frequency = <50000000>;
+               spi-tx-bus-width = <1>; /* 1-single, 2-dual, 4-quad */
+               spi-rx-bus-width = <1>; /* 1-single, 2-dual, 4-quad */
+               reg = <0>;
+
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               partition@0 {
+                       label = "spi_flash_part0";
+                       reg = <0x0 0x800000>;
+               };
+
+               parition@1 {
+                       label = "spi_flash_part1";
+                       reg = <0x800000 0x700000>;
+               };
+
+               parition@2 {
+                       label = "spi_flash_part2";
+                       reg = <0xF00000 0x100000>;
+               };
+       };
+};
diff --git a/arch/arm64/boot/dts/marvell/ac5-98dx35xx.dtsi b/arch/arm64/boot/dts/marvell/ac5-98dx35xx.dtsi
new file mode 100644 (file)
index 0000000..2ab72f8
--- /dev/null
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Device Tree For AC5X.
+ *
+ * Copyright (C) 2022 Allied Telesis Labs
+ */
+
+#include "ac5-98dx25xx.dtsi"
+
+/ {
+       model = "Marvell AC5X SoC";
+       compatible = "marvell,ac5x", "marvell,ac5";
+};
+
+&cnm_clock {
+       clock-frequency = <325000000>;
+};
index caf9c85..de8d0cf 100644 (file)
@@ -35,7 +35,7 @@
 
        leds {
                compatible = "gpio-leds";
-               red {
+               led {
                        label = "mox:red:activity";
                        gpios = <&gpiosb 21 GPIO_ACTIVE_LOW>;
                        linux,default-trigger = "default-on";
@@ -45,7 +45,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               reset {
+               key-reset {
                        label = "reset";
                        linux,code = <KEY_RESTART>;
                        gpios = <&gpiosb 20 GPIO_ACTIVE_LOW>;
index 39a8e5e..b9ba7c4 100644 (file)
@@ -37,7 +37,7 @@
                los-gpio = <&sfp_gpio 3 GPIO_ACTIVE_HIGH>;
                mod-def0-gpio = <&sfp_gpio 2 GPIO_ACTIVE_LOW>;
                tx-disable-gpio = <&sfp_gpio 1 GPIO_ACTIVE_HIGH>;
-               tx-fault-gpio  = <&sfp_gpio 0 GPIO_ACTIVE_HIGH>;
+               tx-fault-gpio = <&sfp_gpio 0 GPIO_ACTIVE_HIGH>;
        };
 
        /* SFP 1G */
@@ -47,7 +47,7 @@
                los-gpio = <&sfp_gpio 7 GPIO_ACTIVE_HIGH>;
                mod-def0-gpio = <&sfp_gpio 6 GPIO_ACTIVE_LOW>;
                tx-disable-gpio = <&sfp_gpio 5 GPIO_ACTIVE_HIGH>;
-               tx-fault-gpio  = <&sfp_gpio 4 GPIO_ACTIVE_HIGH>;
+               tx-fault-gpio = <&sfp_gpio 4 GPIO_ACTIVE_HIGH>;
        };
 };
 
index 871f84b..15f6ca4 100644 (file)
@@ -94,7 +94,7 @@
                pinctrl-0 = <&cp0_gpio_reset_pins &cp1_wps_button_pins>;
                pinctrl-names = "default";
 
-               button_0 {
+               button-0 {
                        /* The rear button */
                        label = "Rear Button";
                        gpios = <&cp0_gpio2 7 GPIO_ACTIVE_LOW>;
                        linux,code = <BTN_0>;
                };
 
-               button_1 {
+               button-1 {
                        /* The wps button */
                        label = "WPS Button";
                        gpios = <&cp1_gpio1 30 GPIO_ACTIVE_LOW>;
index 779cf16..c0389dd 100644 (file)
@@ -68,7 +68,7 @@
                los-gpio = <&cp1_gpio1 28 GPIO_ACTIVE_HIGH>;
                mod-def0-gpio = <&cp1_gpio1 27 GPIO_ACTIVE_LOW>;
                tx-disable-gpio = <&cp1_gpio1 29 GPIO_ACTIVE_HIGH>;
-               tx-fault-gpio  = <&cp1_gpio1 26 GPIO_ACTIVE_HIGH>;
+               tx-fault-gpio = <&cp1_gpio1 26 GPIO_ACTIVE_HIGH>;
                pinctrl-names = "default";
                pinctrl-0 = <&cp1_sfpp0_pins>;
                maximum-power-milliwatt = <2000>;
index 74bed79..cf868e0 100644 (file)
@@ -70,7 +70,7 @@
                los-gpio = <&sfpplus_gpio 11 GPIO_ACTIVE_HIGH>;
                mod-def0-gpio = <&sfpplus_gpio 10 GPIO_ACTIVE_LOW>;
                tx-disable-gpio = <&sfpplus_gpio 9 GPIO_ACTIVE_HIGH>;
-               tx-fault-gpio  = <&sfpplus_gpio 8 GPIO_ACTIVE_HIGH>;
+               tx-fault-gpio = <&sfpplus_gpio 8 GPIO_ACTIVE_HIGH>;
                maximum-power-milliwatt = <3000>;
        };
 
@@ -80,7 +80,7 @@
                los-gpio = <&sfpplus_gpio 3 GPIO_ACTIVE_HIGH>;
                mod-def0-gpio = <&sfpplus_gpio 2 GPIO_ACTIVE_LOW>;
                tx-disable-gpio = <&sfpplus_gpio 1 GPIO_ACTIVE_HIGH>;
-               tx-fault-gpio  = <&sfpplus_gpio 0 GPIO_ACTIVE_HIGH>;
+               tx-fault-gpio = <&sfpplus_gpio 0 GPIO_ACTIVE_HIGH>;
                maximum-power-milliwatt = <3000>;
        };
 
index 7e20987..f58402e 100644 (file)
 &cp0_usb3_1 {
        status = "okay";
        usb-phy = <&cp0_usb3_0_phy1>;
-       phys =  <&cp0_utmi1>;
+       phys = <&cp0_utmi1>;
        phy-names = "utmi";
        dr_mode = "host";
 };
index c7d4636..af362a0 100644 (file)
@@ -37,7 +37,12 @@ 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) += mt8192-asurada-hayato-r1.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8192-asurada-spherion-r0.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8192-evb.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8195-cherry-tomato-r1.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8195-cherry-tomato-r2.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8195-cherry-tomato-r3.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8195-demo.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8195-evb.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8516-pumpkin.dtb
index 11aa135..9b1af9c 100644 (file)
 };
 
 &eth {
-       phy-mode ="rgmii-rxid";
+       phy-mode = "rgmii-rxid";
        phy-handle = <&ethernet_phy0>;
        mediatek,tx-delay-ps = <1530>;
        snps,reset-gpio = <&pio 87 GPIO_ACTIVE_LOW>;
index 623eb3b..4797537 100644 (file)
                interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_LOW>;
                clocks = <&infracfg CLK_INFRA_M4U>;
                clock-names = "bclk";
+               mediatek,infracfg = <&infracfg>;
                mediatek,larbs = <&larb0>, <&larb1>, <&larb2>,
                                 <&larb3>, <&larb6>;
                #iommu-cells = <1>;
                interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_LOW>;
                clocks = <&infracfg CLK_INFRA_M4U>;
                clock-names = "bclk";
+               mediatek,infracfg = <&infracfg>;
                mediatek,larbs = <&larb4>, <&larb5>, <&larb7>;
                #iommu-cells = <1>;
        };
index c85659d..d3bce94 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/pinctrl/mt6795-pinfunc.h>
 
 / {
        compatible = "mediatek,mt6795";
@@ -34,6 +35,8 @@
                        compatible = "arm,cortex-a53";
                        enable-method = "psci";
                        reg = <0x000>;
+                       cci-control-port = <&cci_control2>;
+                       next-level-cache = <&l2_0>;
                };
 
                cpu1: cpu@1 {
@@ -41,6 +44,8 @@
                        compatible = "arm,cortex-a53";
                        enable-method = "psci";
                        reg = <0x001>;
+                       cci-control-port = <&cci_control2>;
+                       next-level-cache = <&l2_0>;
                };
 
                cpu2: cpu@2 {
@@ -48,6 +53,8 @@
                        compatible = "arm,cortex-a53";
                        enable-method = "psci";
                        reg = <0x002>;
+                       cci-control-port = <&cci_control2>;
+                       next-level-cache = <&l2_0>;
                };
 
                cpu3: cpu@3 {
@@ -55,6 +62,8 @@
                        compatible = "arm,cortex-a53";
                        enable-method = "psci";
                        reg = <0x003>;
+                       cci-control-port = <&cci_control2>;
+                       next-level-cache = <&l2_0>;
                };
 
                cpu4: cpu@100 {
@@ -62,6 +71,8 @@
                        compatible = "arm,cortex-a53";
                        enable-method = "psci";
                        reg = <0x100>;
+                       cci-control-port = <&cci_control1>;
+                       next-level-cache = <&l2_1>;
                };
 
                cpu5: cpu@101 {
@@ -69,6 +80,8 @@
                        compatible = "arm,cortex-a53";
                        enable-method = "psci";
                        reg = <0x101>;
+                       cci-control-port = <&cci_control1>;
+                       next-level-cache = <&l2_1>;
                };
 
                cpu6: cpu@102 {
@@ -76,6 +89,8 @@
                        compatible = "arm,cortex-a53";
                        enable-method = "psci";
                        reg = <0x102>;
+                       cci-control-port = <&cci_control1>;
+                       next-level-cache = <&l2_1>;
                };
 
                cpu7: cpu@103 {
                        compatible = "arm,cortex-a53";
                        enable-method = "psci";
                        reg = <0x103>;
+                       cci-control-port = <&cci_control1>;
+                       next-level-cache = <&l2_1>;
+               };
+
+               cpu-map {
+                       cluster0 {
+                               core0 {
+                                       cpu = <&cpu0>;
+                               };
+
+                               core1 {
+                                       cpu = <&cpu1>;
+                               };
+
+                               core2 {
+                                       cpu = <&cpu2>;
+                               };
+
+                               core3 {
+                                       cpu = <&cpu3>;
+                               };
+                       };
+
+                       cluster1 {
+                               core0 {
+                                       cpu = <&cpu4>;
+                               };
+
+                               core1 {
+                                       cpu = <&cpu5>;
+                               };
+
+                               core2 {
+                                       cpu = <&cpu6>;
+                               };
+
+                               core3 {
+                                       cpu = <&cpu7>;
+                               };
+                       };
+               };
+
+               l2_0: l2-cache0 {
+                       compatible = "cache";
+                       cache-level = <2>;
+               };
+
+               l2_1: l2-cache1 {
+                       compatible = "cache";
+                       cache-level = <2>;
                };
        };
 
-       system_clk: dummy13m {
+       clk26m: oscillator-26m {
                compatible = "fixed-clock";
-               clock-frequency = <13000000>;
                #clock-cells = <0>;
+               clock-frequency = <26000000>;
+               clock-output-names = "clk26m";
        };
 
-       rtc_clk: dummy32k {
+       clk32k: oscillator-32k {
                compatible = "fixed-clock";
-               clock-frequency = <32000>;
                #clock-cells = <0>;
+               clock-frequency = <32000>;
+               clock-output-names = "clk32k";
        };
 
-       uart_clk: dummy26m {
+       system_clk: dummy13m {
                compatible = "fixed-clock";
-               clock-frequency = <26000000>;
+               clock-frequency = <13000000>;
                #clock-cells = <0>;
        };
 
+       pmu {
+               compatible = "arm,cortex-a53-pmu";
+               interrupts = <GIC_SPI  8 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_SPI  9 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_SPI 10 IRQ_TYPE_LEVEL_LOW>,
+                            <GIC_SPI 11 IRQ_TYPE_LEVEL_LOW>;
+               interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
+       };
+
        timer {
                compatible = "arm,armv8-timer";
                interrupt-parent = <&gic>;
                             (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>;
        };
 
-       sysirq: intpol-controller@10200620 {
-               compatible = "mediatek,mt6795-sysirq",
-                            "mediatek,mt6577-sysirq";
-               interrupt-controller;
-               #interrupt-cells = <3>;
-               interrupt-parent = <&gic>;
-               reg = <0 0x10200620 0 0x20>;
-       };
+       soc {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               compatible = "simple-bus";
+               ranges;
 
-       gic: interrupt-controller@10221000 {
-               compatible = "arm,gic-400";
-               #interrupt-cells = <3>;
-               interrupt-parent = <&gic>;
-               interrupt-controller;
-               reg = <0 0x10221000 0 0x1000>,
-                     <0 0x10222000 0 0x2000>,
-                     <0 0x10224000 0 0x2000>,
-                     <0 0x10226000 0 0x2000>;
-       };
+               pio: pinctrl@10005000 {
+                       compatible = "mediatek,mt6795-pinctrl";
+                       reg = <0 0x10005000 0 0x1000>, <0 0x1000b000 0 0x1000>;
+                       reg-names = "base", "eint";
+                       interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       gpio-ranges = <&pio 0 0 196>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
 
-       uart0: serial@11002000 {
-               compatible = "mediatek,mt6795-uart",
-                            "mediatek,mt6577-uart";
-               reg = <0 0x11002000 0 0x400>;
-               interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_LOW>;
-               clocks = <&uart_clk>;
-               status = "disabled";
-       };
+               watchdog: watchdog@10007000 {
+                       compatible = "mediatek,mt6795-wdt";
+                       reg = <0 0x10007000 0 0x100>;
+                       interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_LOW>;
+                       #reset-cells = <1>;
+                       timeout-sec = <20>;
+               };
 
-       uart1: serial@11003000 {
-               compatible = "mediatek,mt6795-uart",
-                            "mediatek,mt6577-uart";
-               reg = <0 0x11003000 0 0x400>;
-               interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_LOW>;
-               clocks = <&uart_clk>;
-               status = "disabled";
-       };
+               timer: timer@10008000 {
+                       compatible = "mediatek,mt6795-timer",
+                                    "mediatek,mt6577-timer";
+                       reg = <0 0x10008000 0 0x1000>;
+                       interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_LOW>;
+                       clocks = <&system_clk>, <&clk32k>;
+               };
 
-       uart2: serial@11004000 {
-               compatible = "mediatek,mt6795-uart",
-                            "mediatek,mt6577-uart";
-               reg = <0 0x11004000 0 0x400>;
-               interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_LOW>;
-               clocks = <&uart_clk>;
-               status = "disabled";
-       };
+               sysirq: intpol-controller@10200620 {
+                       compatible = "mediatek,mt6795-sysirq",
+                                    "mediatek,mt6577-sysirq";
+                       interrupt-controller;
+                       #interrupt-cells = <3>;
+                       interrupt-parent = <&gic>;
+                       reg = <0 0x10200620 0 0x20>;
+               };
+
+               gic: interrupt-controller@10221000 {
+                       compatible = "arm,gic-400";
+                       #interrupt-cells = <3>;
+                       interrupt-parent = <&gic>;
+                       interrupt-controller;
+                       reg = <0 0x10221000 0 0x1000>,
+                             <0 0x10222000 0 0x2000>,
+                             <0 0x10224000 0 0x2000>,
+                             <0 0x10226000 0 0x2000>;
+                       interrupts = <GIC_PPI 9
+                               (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+               };
+
+               cci: cci@10390000 {
+                       compatible = "arm,cci-400";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       reg = <0 0x10390000 0 0x1000>;
+                       ranges = <0 0 0x10390000 0x10000>;
 
-       uart3: serial@11005000 {
-               compatible = "mediatek,mt6795-uart",
-                            "mediatek,mt6577-uart";
-               reg = <0 0x11005000 0 0x400>;
-               interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_LOW>;
-               clocks = <&uart_clk>;
-               status = "disabled";
+                       cci_control0: slave-if@1000 {
+                               compatible = "arm,cci-400-ctrl-if";
+                               interface-type = "ace-lite";
+                               reg = <0x1000 0x1000>;
+                       };
+
+                       cci_control1: slave-if@4000 {
+                               compatible = "arm,cci-400-ctrl-if";
+                               interface-type = "ace";
+                               reg = <0x4000 0x1000>;
+                       };
+
+                       cci_control2: slave-if@5000 {
+                               compatible = "arm,cci-400-ctrl-if";
+                               interface-type = "ace";
+                               reg = <0x5000 0x1000>;
+                       };
+
+                       pmu@9000 {
+                               compatible = "arm,cci-400-pmu,r1";
+                               reg = <0x9000 0x5000>;
+                               interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>,
+                                            <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>,
+                                            <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>,
+                                            <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>,
+                                            <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
+                       };
+               };
+
+               uart0: serial@11002000 {
+                       compatible = "mediatek,mt6795-uart",
+                                    "mediatek,mt6577-uart";
+                       reg = <0 0x11002000 0 0x400>;
+                       interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_LOW>;
+                       clocks = <&clk26m>;
+                       status = "disabled";
+               };
+
+               uart1: serial@11003000 {
+                       compatible = "mediatek,mt6795-uart",
+                                    "mediatek,mt6577-uart";
+                       reg = <0 0x11003000 0 0x400>;
+                       interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_LOW>;
+                       clocks = <&clk26m>;
+                       status = "disabled";
+               };
+
+               uart2: serial@11004000 {
+                       compatible = "mediatek,mt6795-uart",
+                                    "mediatek,mt6577-uart";
+                       reg = <0 0x11004000 0 0x400>;
+                       interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_LOW>;
+                       clocks = <&clk26m>;
+                       status = "disabled";
+               };
+
+               uart3: serial@11005000 {
+                       compatible = "mediatek,mt6795-uart",
+                                    "mediatek,mt6577-uart";
+                       reg = <0 0x11005000 0 0x400>;
+                       interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_LOW>;
+                       clocks = <&clk26m>;
+                       status = "disabled";
+               };
        };
 };
index 2b9bf8d..d3f9eab 100644 (file)
@@ -8,6 +8,7 @@
 /dts-v1/;
 #include <dt-bindings/input/input.h>
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
 
 #include "mt7622.dtsi"
 #include "mt6380.dtsi"
        gpio-keys {
                compatible = "gpio-keys";
 
-               factory {
+               factory-key {
                        label = "factory";
                        linux,code = <BTN_0>;
                        gpios = <&pio 0 GPIO_ACTIVE_HIGH>;
                };
 
-               wps {
+               wps-key {
                        label = "wps";
                        linux,code = <KEY_WPS_BUTTON>;
-                       gpios = <&pio 102 GPIO_ACTIVE_HIGH>;
+                       gpios = <&pio 102 GPIO_ACTIVE_LOW>;
                };
        };
 
        leds {
                compatible = "gpio-leds";
 
-               green {
+               led-0 {
                        label = "bpi-r64:pio:green";
+                       color = <LED_COLOR_ID_GREEN>;
                        gpios = <&pio 89 GPIO_ACTIVE_HIGH>;
                        default-state = "off";
                };
 
-               red {
+               led-1 {
                        label = "bpi-r64:pio:red";
+                       color = <LED_COLOR_ID_RED>;
                        gpios = <&pio 88 GPIO_ACTIVE_HIGH>;
                        default-state = "off";
                };
        i2c1_pins: i2c1-pins {
                mux {
                        function = "i2c";
-                       groups =  "i2c1_0";
+                       groups = "i2c1_0";
                };
        };
 
        i2c2_pins: i2c2-pins {
                mux {
                        function = "i2c";
-                       groups =  "i2c2_0";
+                       groups = "i2c2_0";
                };
        };
 
        irrx_pins: irrx-pins {
                mux {
                        function = "ir";
-                       groups =  "ir_1_rx";
+                       groups = "ir_1_rx";
                };
        };
 
        irtx_pins: irtx-pins {
                mux {
                        function = "ir";
-                       groups =  "ir_1_tx";
+                       groups = "ir_1_tx";
                };
        };
 
index 596c073..36722ca 100644 (file)
 
        gpio-keys {
                compatible = "gpio-keys";
-               poll-interval = <100>;
 
-               factory {
+               key-factory {
                        label = "factory";
                        linux,code = <BTN_0>;
                        gpios = <&pio 0 0>;
                };
 
-               wps {
+               key-wps {
                        label = "wps";
                        linux,code = <KEY_WPS_BUTTON>;
                        gpios = <&pio 102 0>;
        i2c1_pins: i2c1-pins {
                mux {
                        function = "i2c";
-                       groups =  "i2c1_0";
+                       groups = "i2c1_0";
                };
        };
 
        i2c2_pins: i2c2-pins {
                mux {
                        function = "i2c";
-                       groups =  "i2c2_0";
+                       groups = "i2c2_0";
                };
        };
 
        irrx_pins: irrx-pins {
                mux {
                        function = "ir";
-                       groups =  "ir_1_rx";
+                       groups = "ir_1_rx";
                };
        };
 
        irtx_pins: irtx-pins {
                mux {
                        function = "ir";
-                       groups =  "ir_1_tx";
+                       groups = "ir_1_tx";
                };
        };
 
index dbcee8b..146e18b 100644 (file)
        };
 
        psci {
-               compatible  = "arm,psci-0.2";
-               method      = "smc";
+               compatible = "arm,psci-0.2";
+               method = "smc";
        };
 
        pmu {
 
                afe: audio-controller {
                        compatible = "mediatek,mt7622-audio";
-                       interrupts =  <GIC_SPI 144 IRQ_TYPE_LEVEL_LOW>,
-                                     <GIC_SPI 145 IRQ_TYPE_LEVEL_LOW>;
-                       interrupt-names = "afe", "asys";
+                       interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_LOW>,
+                                    <GIC_SPI 145 IRQ_TYPE_LEVEL_LOW>;
+                       interrupt-names = "afe", "asys";
 
                        clocks = <&infracfg CLK_INFRA_AUDIO_PD>,
                                 <&topckgen CLK_TOP_AUD1_SEL>,
index d2636a0..e3a407d 100644 (file)
@@ -57,8 +57,8 @@
        };
 
        psci {
-               compatible  = "arm,psci-0.2";
-               method      = "smc";
+               compatible = "arm,psci-0.2";
+               method = "smc";
        };
 
        reserved-memory {
index 44f6149..28433b9 100644 (file)
@@ -21,7 +21,7 @@
 };
 
 &gpio_keys {
-       /delete-node/tablet_mode;
-       /delete-node/volume_down;
-       /delete-node/volume_up;
+       /delete-node/switch-tablet-mode;
+       /delete-node/switch-volume-down;
+       /delete-node/switch-volume-up;
 };
index 9c75fbb..e21feb8 100644 (file)
@@ -53,7 +53,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&gpio_keys_pins>;
 
-               lid {
+               switch-lid {
                        label = "Lid";
                        gpios = <&pio 69 GPIO_ACTIVE_LOW>;
                        linux,code = <SW_LID>;
@@ -61,7 +61,7 @@
                        gpio-key,wakeup;
                };
 
-               power {
+               switch-power {
                        label = "Power";
                        gpios = <&pio 14 GPIO_ACTIVE_HIGH>;
                        linux,code = <KEY_POWER>;
@@ -69,7 +69,7 @@
                        gpio-key,wakeup;
                };
 
-               tablet_mode {
+               switch-tablet-mode {
                        label = "Tablet_mode";
                        gpios = <&pio 121 GPIO_ACTIVE_HIGH>;
                        linux,code = <SW_TABLET_MODE>;
                        gpio-key,wakeup;
                };
 
-               volume_down {
+               switch-volume-down {
                        label = "Volume_down";
                        gpios = <&pio 123 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEDOWN>;
                };
 
-               volume_up {
+               switch-volume-up {
                        label = "Volume_up";
                        gpios = <&pio 124 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
                                regulator-name = "VBUCKA";
                                regulator-min-microvolt = < 700000>;
                                regulator-max-microvolt = <1310000>;
-                               regulator-min-microamp  = <2000000>;
-                               regulator-max-microamp  = <4400000>;
+                               regulator-min-microamp = <2000000>;
+                               regulator-max-microamp = <4400000>;
                                regulator-ramp-delay = <10000>;
                                regulator-always-on;
                                regulator-allowed-modes = <DA9211_BUCK_MODE_SYNC
                                regulator-name = "VBUCKB";
                                regulator-min-microvolt = < 700000>;
                                regulator-max-microvolt = <1310000>;
-                               regulator-min-microamp  = <2000000>;
-                               regulator-max-microamp  = <3000000>;
+                               regulator-min-microamp = <2000000>;
+                               regulator-max-microamp = <3000000>;
                                regulator-ramp-delay = <10000>;
                        };
                };
        mmc-hs400-1_8v;
        cap-mmc-hw-reset;
        hs400-ds-delay = <0x14015>;
-       mediatek,hs200-cmd-int-delay=<30>;
-       mediatek,hs400-cmd-int-delay=<14>;
+       mediatek,hs200-cmd-int-delay = <30>;
+       mediatek,hs400-cmd-int-delay = <14>;
        mediatek,hs400-cmd-resp-sel-rising;
        vmmc-supply = <&mt6397_vemc_3v3_reg>;
        vqmmc-supply = <&mt6397_vio18_reg>;
        sd-uhs-sdr50;
        sd-uhs-sdr104;
        keep-power-in-suspend;
-       enable-sdio-wakeup;
+       wakeup-source;
        cap-sdio-irq;
        vmmc-supply = <&sdio_fixed_3v3>;
        vqmmc-supply = <&mt6397_vgp3_reg>;
index 4fa1e93..0b5f154 100644 (file)
                                regulator-name = "VBUCKA";
                                regulator-min-microvolt = < 700000>;
                                regulator-max-microvolt = <1310000>;
-                               regulator-min-microamp  = <2000000>;
-                               regulator-max-microamp  = <4400000>;
+                               regulator-min-microamp = <2000000>;
+                               regulator-max-microamp = <4400000>;
                                regulator-ramp-delay = <10000>;
                                regulator-always-on;
                        };
                                regulator-name = "VBUCKB";
                                regulator-min-microvolt = < 700000>;
                                regulator-max-microvolt = <1310000>;
-                               regulator-min-microamp  = <2000000>;
-                               regulator-max-microamp  = <3000000>;
+                               regulator-min-microamp = <2000000>;
+                               regulator-max-microamp = <3000000>;
                                regulator-ramp-delay = <10000>;
                        };
                };
        bus-width = <8>;
        max-frequency = <50000000>;
        cap-mmc-highspeed;
-       mediatek,hs200-cmd-int-delay=<26>;
-       mediatek,hs400-cmd-int-delay=<14>;
+       mediatek,hs200-cmd-int-delay = <26>;
+       mediatek,hs400-cmd-int-delay = <14>;
        mediatek,hs400-cmd-resp-sel-rising;
        vmmc-supply = <&mt6397_vemc_3v3_reg>;
        vqmmc-supply = <&mt6397_vio18_reg>;
index 40d7b47..f351117 100644 (file)
        psci {
                compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci";
                method = "smc";
-               cpu_suspend   = <0x84000001>;
-               cpu_off       = <0x84000002>;
-               cpu_on        = <0x84000003>;
+               cpu_suspend = <0x84000001>;
+               cpu_off  = <0x84000002>;
+               cpu_on   = <0x84000003>;
        };
 
        clk26m: oscillator0 {
                        interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_LOW>;
                        clocks = <&infracfg CLK_INFRA_M4U>;
                        clock-names = "bclk";
+                       mediatek,infracfg = <&infracfg>;
                        mediatek,larbs = <&larb0>, <&larb1>, <&larb2>,
                                         <&larb3>, <&larb4>, <&larb5>;
                        #iommu-cells = <1>;
                nor_flash: spi@1100d000 {
                        compatible = "mediatek,mt8173-nor";
                        reg = <0 0x1100d000 0 0xe0>;
+                       assigned-clocks = <&topckgen CLK_TOP_SPI_SEL>;
+                       assigned-clock-parents = <&clk26m>;
                        clocks = <&pericfg CLK_PERI_SPI>,
-                                <&topckgen CLK_TOP_SPINFI_IFR_SEL>;
-                       clock-names = "spi", "sf";
+                                <&topckgen CLK_TOP_SPINFI_IFR_SEL>,
+                                <&pericfg CLK_PERI_NFI>;
+                       clock-names = "spi", "sf", "axi";
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "disabled";
 
                vcodec_enc_vp8: vcodec@19002000 {
                        compatible = "mediatek,mt8173-vcodec-enc-vp8";
-                       reg =  <0 0x19002000 0 0x1000>; /* VENC_LT_SYS */
+                       reg = <0 0x19002000 0 0x1000>; /* VENC_LT_SYS */
                        interrupts = <GIC_SPI 202 IRQ_TYPE_LEVEL_LOW>;
                        iommus = <&iommu M4U_PORT_VENC_RCPU_SET2>,
                                 <&iommu M4U_PORT_VENC_REC_FRM_SET2>,
index f3fd3cc..52dc4a5 100644 (file)
        vmmc-supply = <&mt6358_vmch_reg>;
        vqmmc-supply = <&mt6358_vmc_reg>;
        keep-power-in-suspend;
-       enable-sdio-wakeup;
+       wakeup-source;
        non-removable;
 };
 
 
 };
 
+&cci {
+       proc-supply = <&mt6358_vproc12_reg>;
+};
+
+&cpu0 {
+       proc-supply = <&mt6358_vproc12_reg>;
+};
+
+&cpu1 {
+       proc-supply = <&mt6358_vproc12_reg>;
+};
+
+&cpu2 {
+       proc-supply = <&mt6358_vproc12_reg>;
+};
+
+&cpu3 {
+       proc-supply = <&mt6358_vproc12_reg>;
+};
+
+&cpu4 {
+       proc-supply = <&mt6358_vproc11_reg>;
+};
+
+&cpu5 {
+       proc-supply = <&mt6358_vproc11_reg>;
+};
+
+&cpu6 {
+       proc-supply = <&mt6358_vproc11_reg>;
+};
+
+&cpu7 {
+       proc-supply = <&mt6358_vproc11_reg>;
+};
+
 &uart0 {
        status = "okay";
 };
index 2d7a193..3ac83be 100644 (file)
@@ -73,7 +73,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&volume_button_pins>;
 
-               volume_down {
+               button-volume-down {
                        label = "Volume Down";
                        linux,code = <KEY_VOLUMEDOWN>;
                        debounce-interval = <100>;
@@ -81,7 +81,7 @@
                        gpios = <&pio 6 GPIO_ACTIVE_LOW>;
                };
 
-               volume_up {
+               button-volume-up {
                        label = "Volume Up";
                        linux,code = <KEY_VOLUMEUP>;
                        debounce-interval = <100>;
index 28966a6..50a0dd3 100644 (file)
@@ -45,7 +45,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&pen_eject>;
 
-               pen-insert {
+               switch-pen-insert {
                        label = "Pen Insert";
                        /* Insert = low, eject = high */
                        gpios = <&pio 6 GPIO_ACTIVE_LOW>;
index 8d5bf73..b4b86bb 100644 (file)
                pinctrl-names = "default";
                pinctrl-0 = <&wifi_pins_wakeup>;
 
-               wowlan {
+               button-wowlan {
                        label = "Wake on WiFi";
                        gpios = <&pio 113 GPIO_ACTIVE_HIGH>;
                        linux,code = <KEY_WAKEUP>;
        status = "okay";
 };
 
+&cci {
+       proc-supply = <&mt6358_vproc12_reg>;
+};
+
 &cpu0 {
        proc-supply = <&mt6358_vproc12_reg>;
 };
                avee-supply = <&ppvarp_lcd>;
                pp1800-supply = <&pp1800_lcd>;
                backlight = <&backlight_lcd0>;
+               rotation = <270>;
                port {
                        panel_in: endpoint {
                                remote-endpoint = <&dsi_out>;
        sd-uhs-sdr50;
        sd-uhs-sdr104;
        keep-power-in-suspend;
-       enable-sdio-wakeup;
+       wakeup-source;
        cap-sdio-irq;
        non-removable;
        no-mmc;
        };
 };
 
+&mfg_async {
+       domain-supply = <&mt6358_vsram_gpu_reg>;
+};
+
 &mfg {
        domain-supply = <&mt6358_vgpu_reg>;
 };
index afeb5cd..530e0c9 100644 (file)
        vmmc-supply = <&mt6358_vmch_reg>;
        vqmmc-supply = <&mt6358_vmc_reg>;
        keep-power-in-suspend;
-       enable-sdio-wakeup;
+       wakeup-source;
        non-removable;
 };
 
index 01e6502..9d32871 100644 (file)
                rdma1 = &rdma1;
        };
 
+       cluster0_opp: opp-table-cluster0 {
+               compatible = "operating-points-v2";
+               opp-shared;
+               opp0-793000000 {
+                       opp-hz = /bits/ 64 <793000000>;
+                       opp-microvolt = <650000>;
+                       required-opps = <&opp2_00>;
+               };
+               opp0-910000000 {
+                       opp-hz = /bits/ 64 <910000000>;
+                       opp-microvolt = <687500>;
+                       required-opps = <&opp2_01>;
+               };
+               opp0-1014000000 {
+                       opp-hz = /bits/ 64 <1014000000>;
+                       opp-microvolt = <718750>;
+                       required-opps = <&opp2_02>;
+               };
+               opp0-1131000000 {
+                       opp-hz = /bits/ 64 <1131000000>;
+                       opp-microvolt = <756250>;
+                       required-opps = <&opp2_03>;
+               };
+               opp0-1248000000 {
+                       opp-hz = /bits/ 64 <1248000000>;
+                       opp-microvolt = <800000>;
+                       required-opps = <&opp2_04>;
+               };
+               opp0-1326000000 {
+                       opp-hz = /bits/ 64 <1326000000>;
+                       opp-microvolt = <818750>;
+                       required-opps = <&opp2_05>;
+               };
+               opp0-1417000000 {
+                       opp-hz = /bits/ 64 <1417000000>;
+                       opp-microvolt = <850000>;
+                       required-opps = <&opp2_06>;
+               };
+               opp0-1508000000 {
+                       opp-hz = /bits/ 64 <1508000000>;
+                       opp-microvolt = <868750>;
+                       required-opps = <&opp2_07>;
+               };
+               opp0-1586000000 {
+                       opp-hz = /bits/ 64 <1586000000>;
+                       opp-microvolt = <893750>;
+                       required-opps = <&opp2_08>;
+               };
+               opp0-1625000000 {
+                       opp-hz = /bits/ 64 <1625000000>;
+                       opp-microvolt = <906250>;
+                       required-opps = <&opp2_09>;
+               };
+               opp0-1677000000 {
+                       opp-hz = /bits/ 64 <1677000000>;
+                       opp-microvolt = <931250>;
+                       required-opps = <&opp2_10>;
+               };
+               opp0-1716000000 {
+                       opp-hz = /bits/ 64 <1716000000>;
+                       opp-microvolt = <943750>;
+                       required-opps = <&opp2_11>;
+               };
+               opp0-1781000000 {
+                       opp-hz = /bits/ 64 <1781000000>;
+                       opp-microvolt = <975000>;
+                       required-opps = <&opp2_12>;
+               };
+               opp0-1846000000 {
+                       opp-hz = /bits/ 64 <1846000000>;
+                       opp-microvolt = <1000000>;
+                       required-opps = <&opp2_13>;
+               };
+               opp0-1924000000 {
+                       opp-hz = /bits/ 64 <1924000000>;
+                       opp-microvolt = <1025000>;
+                       required-opps = <&opp2_14>;
+               };
+               opp0-1989000000 {
+                       opp-hz = /bits/ 64 <1989000000>;
+                       opp-microvolt = <1050000>;
+                       required-opps = <&opp2_15>;
+               };      };
+
+       cluster1_opp: opp-table-cluster1 {
+               compatible = "operating-points-v2";
+               opp-shared;
+               opp1-793000000 {
+                       opp-hz = /bits/ 64 <793000000>;
+                       opp-microvolt = <700000>;
+                       required-opps = <&opp2_00>;
+               };
+               opp1-910000000 {
+                       opp-hz = /bits/ 64 <910000000>;
+                       opp-microvolt = <725000>;
+                       required-opps = <&opp2_01>;
+               };
+               opp1-1014000000 {
+                       opp-hz = /bits/ 64 <1014000000>;
+                       opp-microvolt = <750000>;
+                       required-opps = <&opp2_02>;
+               };
+               opp1-1131000000 {
+                       opp-hz = /bits/ 64 <1131000000>;
+                       opp-microvolt = <775000>;
+                       required-opps = <&opp2_03>;
+               };
+               opp1-1248000000 {
+                       opp-hz = /bits/ 64 <1248000000>;
+                       opp-microvolt = <800000>;
+                       required-opps = <&opp2_04>;
+               };
+               opp1-1326000000 {
+                       opp-hz = /bits/ 64 <1326000000>;
+                       opp-microvolt = <825000>;
+                       required-opps = <&opp2_05>;
+               };
+               opp1-1417000000 {
+                       opp-hz = /bits/ 64 <1417000000>;
+                       opp-microvolt = <850000>;
+                       required-opps = <&opp2_06>;
+               };
+               opp1-1508000000 {
+                       opp-hz = /bits/ 64 <1508000000>;
+                       opp-microvolt = <875000>;
+                       required-opps = <&opp2_07>;
+               };
+               opp1-1586000000 {
+                       opp-hz = /bits/ 64 <1586000000>;
+                       opp-microvolt = <900000>;
+                       required-opps = <&opp2_08>;
+               };
+               opp1-1625000000 {
+                       opp-hz = /bits/ 64 <1625000000>;
+                       opp-microvolt = <912500>;
+                       required-opps = <&opp2_09>;
+               };
+               opp1-1677000000 {
+                       opp-hz = /bits/ 64 <1677000000>;
+                       opp-microvolt = <931250>;
+                       required-opps = <&opp2_10>;
+               };
+               opp1-1716000000 {
+                       opp-hz = /bits/ 64 <1716000000>;
+                       opp-microvolt = <950000>;
+                       required-opps = <&opp2_11>;
+               };
+               opp1-1781000000 {
+                       opp-hz = /bits/ 64 <1781000000>;
+                       opp-microvolt = <975000>;
+                       required-opps = <&opp2_12>;
+               };
+               opp1-1846000000 {
+                       opp-hz = /bits/ 64 <1846000000>;
+                       opp-microvolt = <1000000>;
+                       required-opps = <&opp2_13>;
+               };
+               opp1-1924000000 {
+                       opp-hz = /bits/ 64 <1924000000>;
+                       opp-microvolt = <1025000>;
+                       required-opps = <&opp2_14>;
+               };
+               opp1-1989000000 {
+                       opp-hz = /bits/ 64 <1989000000>;
+                       opp-microvolt = <1050000>;
+                       required-opps = <&opp2_15>;
+               };
+       };
+
+       cci_opp: opp-table-cci {
+               compatible = "operating-points-v2";
+               opp-shared;
+               opp2_00: opp-273000000 {
+                       opp-hz = /bits/ 64 <273000000>;
+                       opp-microvolt = <650000>;
+               };
+               opp2_01: opp-338000000 {
+                       opp-hz = /bits/ 64 <338000000>;
+                       opp-microvolt = <687500>;
+               };
+               opp2_02: opp-403000000 {
+                       opp-hz = /bits/ 64 <403000000>;
+                       opp-microvolt = <718750>;
+               };
+               opp2_03: opp-463000000 {
+                       opp-hz = /bits/ 64 <463000000>;
+                       opp-microvolt = <756250>;
+               };
+               opp2_04: opp-546000000 {
+                       opp-hz = /bits/ 64 <546000000>;
+                       opp-microvolt = <800000>;
+               };
+               opp2_05: opp-624000000 {
+                       opp-hz = /bits/ 64 <624000000>;
+                       opp-microvolt = <818750>;
+               };
+               opp2_06: opp-689000000 {
+                       opp-hz = /bits/ 64 <689000000>;
+                       opp-microvolt = <850000>;
+               };
+               opp2_07: opp-767000000 {
+                       opp-hz = /bits/ 64 <767000000>;
+                       opp-microvolt = <868750>;
+               };
+               opp2_08: opp-845000000 {
+                       opp-hz = /bits/ 64 <845000000>;
+                       opp-microvolt = <893750>;
+               };
+               opp2_09: opp-871000000 {
+                       opp-hz = /bits/ 64 <871000000>;
+                       opp-microvolt = <906250>;
+               };
+               opp2_10: opp-923000000 {
+                       opp-hz = /bits/ 64 <923000000>;
+                       opp-microvolt = <931250>;
+               };
+               opp2_11: opp-962000000 {
+                       opp-hz = /bits/ 64 <962000000>;
+                       opp-microvolt = <943750>;
+               };
+               opp2_12: opp-1027000000 {
+                       opp-hz = /bits/ 64 <1027000000>;
+                       opp-microvolt = <975000>;
+               };
+               opp2_13: opp-1092000000 {
+                       opp-hz = /bits/ 64 <1092000000>;
+                       opp-microvolt = <1000000>;
+               };
+               opp2_14: opp-1144000000 {
+                       opp-hz = /bits/ 64 <1144000000>;
+                       opp-microvolt = <1025000>;
+               };
+               opp2_15: opp-1196000000 {
+                       opp-hz = /bits/ 64 <1196000000>;
+                       opp-microvolt = <1050000>;
+               };
+       };
+
+       cci: cci {
+               compatible = "mediatek,mt8183-cci";
+               clocks = <&mcucfg CLK_MCU_BUS_SEL>,
+                        <&topckgen CLK_TOP_ARMPLL_DIV_PLL1>;
+               clock-names = "cci", "intermediate";
+               operating-points-v2 = <&cci_opp>;
+       };
+
        cpus {
                #address-cells = <1>;
                #size-cells = <0>;
                        enable-method = "psci";
                        capacity-dmips-mhz = <741>;
                        cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP0>;
+                       clocks = <&mcucfg CLK_MCU_MP0_SEL>,
+                                <&topckgen CLK_TOP_ARMPLL_DIV_PLL1>;
+                       clock-names = "cpu", "intermediate";
+                       operating-points-v2 = <&cluster0_opp>;
                        dynamic-power-coefficient = <84>;
                        #cooling-cells = <2>;
+                       mediatek,cci = <&cci>;
                };
 
                cpu1: cpu@1 {
                        enable-method = "psci";
                        capacity-dmips-mhz = <741>;
                        cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP0>;
+                       clocks = <&mcucfg CLK_MCU_MP0_SEL>,
+                                <&topckgen CLK_TOP_ARMPLL_DIV_PLL1>;
+                       clock-names = "cpu", "intermediate";
+                       operating-points-v2 = <&cluster0_opp>;
                        dynamic-power-coefficient = <84>;
                        #cooling-cells = <2>;
+                       mediatek,cci = <&cci>;
                };
 
                cpu2: cpu@2 {
                        enable-method = "psci";
                        capacity-dmips-mhz = <741>;
                        cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP0>;
+                       clocks = <&mcucfg CLK_MCU_MP0_SEL>,
+                                <&topckgen CLK_TOP_ARMPLL_DIV_PLL1>;
+                       clock-names = "cpu", "intermediate";
+                       operating-points-v2 = <&cluster0_opp>;
                        dynamic-power-coefficient = <84>;
                        #cooling-cells = <2>;
+                       mediatek,cci = <&cci>;
                };
 
                cpu3: cpu@3 {
                        enable-method = "psci";
                        capacity-dmips-mhz = <741>;
                        cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP0>;
+                       clocks = <&mcucfg CLK_MCU_MP0_SEL>,
+                                <&topckgen CLK_TOP_ARMPLL_DIV_PLL1>;
+                       clock-names = "cpu", "intermediate";
+                       operating-points-v2 = <&cluster0_opp>;
                        dynamic-power-coefficient = <84>;
                        #cooling-cells = <2>;
+                       mediatek,cci = <&cci>;
                };
 
                cpu4: cpu@100 {
                        enable-method = "psci";
                        capacity-dmips-mhz = <1024>;
                        cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP1>;
+                       clocks = <&mcucfg CLK_MCU_MP2_SEL>,
+                                <&topckgen CLK_TOP_ARMPLL_DIV_PLL1>;
+                       clock-names = "cpu", "intermediate";
+                       operating-points-v2 = <&cluster1_opp>;
                        dynamic-power-coefficient = <211>;
                        #cooling-cells = <2>;
+                       mediatek,cci = <&cci>;
                };
 
                cpu5: cpu@101 {
                        enable-method = "psci";
                        capacity-dmips-mhz = <1024>;
                        cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP1>;
+                       clocks = <&mcucfg CLK_MCU_MP2_SEL>,
+                                <&topckgen CLK_TOP_ARMPLL_DIV_PLL1>;
+                       clock-names = "cpu", "intermediate";
+                       operating-points-v2 = <&cluster1_opp>;
                        dynamic-power-coefficient = <211>;
                        #cooling-cells = <2>;
+                       mediatek,cci = <&cci>;
                };
 
                cpu6: cpu@102 {
                        enable-method = "psci";
                        capacity-dmips-mhz = <1024>;
                        cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP1>;
+                       clocks = <&mcucfg CLK_MCU_MP2_SEL>,
+                                <&topckgen CLK_TOP_ARMPLL_DIV_PLL1>;
+                       clock-names = "cpu", "intermediate";
+                       operating-points-v2 = <&cluster1_opp>;
                        dynamic-power-coefficient = <211>;
                        #cooling-cells = <2>;
+                       mediatek,cci = <&cci>;
                };
 
                cpu7: cpu@103 {
                        enable-method = "psci";
                        capacity-dmips-mhz = <1024>;
                        cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP1>;
+                       clocks = <&mcucfg CLK_MCU_MP2_SEL>,
+                                <&topckgen CLK_TOP_ARMPLL_DIV_PLL1>;
+                       clock-names = "cpu", "intermediate";
+                       operating-points-v2 = <&cluster1_opp>;
                        dynamic-power-coefficient = <211>;
                        #cooling-cells = <2>;
+                       mediatek,cci = <&cci>;
                };
 
                idle-states {
        };
 
        psci {
-               compatible      = "arm,psci-1.0";
-               method          = "smc";
+               compatible = "arm,psci-1.0";
+               method = "smc";
        };
 
        clk26m: oscillator {
                compatible = "simple-bus";
                ranges;
 
-               soc_data: soc_data@8000000 {
+               soc_data: efuse@8000000 {
                        compatible = "mediatek,mt8183-efuse",
                                     "mediatek,efuse";
                        reg = <0 0x08000000 0 0x0010>;
                                        #power-domain-cells = <0>;
                                };
 
-                               power-domain@MT8183_POWER_DOMAIN_MFG_ASYNC {
+                               mfg_async: power-domain@MT8183_POWER_DOMAIN_MFG_ASYNC {
                                        reg = <MT8183_POWER_DOMAIN_MFG_ASYNC>;
-                                       clocks =  <&topckgen CLK_TOP_MUX_MFG>;
+                                       clocks = <&topckgen CLK_TOP_MUX_MFG>;
                                        clock-names = "mfg";
                                        #address-cells = <1>;
                                        #size-cells = <0>;
                        status = "disabled";
                };
 
+               svs: svs@1100b000 {
+                       compatible = "mediatek,mt8183-svs";
+                       reg = <0 0x1100b000 0 0x1000>;
+                       interrupts = <GIC_SPI 127 IRQ_TYPE_LEVEL_LOW>;
+                       clocks = <&infracfg CLK_INFRA_THERM>;
+                       clock-names = "main";
+                       nvmem-cells = <&svs_calibration>,
+                                     <&thermal_calibration>;
+                       nvmem-cell-names = "svs-calibration-data",
+                                          "t-calibration-data";
+               };
+
                thermal: thermal@1100b000 {
                        #thermal-sensor-cells = <1>;
                        compatible = "mediatek,mt8183-thermal";
                };
 
                ssusb: usb@11201000 {
-                       compatible ="mediatek,mt8183-mtu3", "mediatek,mtu3";
+                       compatible = "mediatek,mt8183-mtu3", "mediatek,mtu3";
                        reg = <0 0x11201000 0 0x2e00>,
                              <0 0x11203e00 0 0x0100>;
                        reg-names = "mac", "ippc";
                        mipi_tx_calibration: calib@190 {
                                reg = <0x190 0xc>;
                        };
+
+                       svs_calibration: calib@580 {
+                               reg = <0x580 0x64>;
+                       };
                };
 
                u3phy: t-phy@11f40000 {
                        power-domains = <&spm MT8183_POWER_DOMAIN_DISP>;
                        mediatek,gce-events = <CMDQ_EVENT_MUTEX_STREAM_DONE0>,
                                              <CMDQ_EVENT_MUTEX_STREAM_DONE1>;
+                       mediatek,gce-client-reg = <&gce SUBSYS_1401XXXX 0x6000 0x1000>;
                };
 
                larb0: larb@14017000 {
diff --git a/arch/arm64/boot/dts/mediatek/mt8192-asurada-hayato-r1.dts b/arch/arm64/boot/dts/mediatek/mt8192-asurada-hayato-r1.dts
new file mode 100644 (file)
index 0000000..1e91491
--- /dev/null
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2020 Google LLC
+ */
+/dts-v1/;
+#include "mt8192-asurada.dtsi"
+
+/ {
+       model = "Google Hayato rev1";
+       compatible = "google,hayato-rev1", "google,hayato", "mediatek,mt8192";
+};
+
+&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_FORWARD)
+               MATRIX_KEY(0x02, 0x02, KEY_REFRESH)
+               MATRIX_KEY(0x01, 0x02, KEY_FULL_SCREEN)
+               MATRIX_KEY(0x03, 0x04, KEY_SCALE)
+               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
+       >;
+};
+
+&touchscreen {
+       compatible = "hid-over-i2c";
+       post-power-on-delay-ms = <10>;
+       hid-descr-addr = <0x0001>;
+       vdd-supply = <&pp3300_u>;
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8192-asurada-spherion-r0.dts b/arch/arm64/boot/dts/mediatek/mt8192-asurada-spherion-r0.dts
new file mode 100644 (file)
index 0000000..fa3d957
--- /dev/null
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2021 Google LLC
+ */
+/dts-v1/;
+#include "mt8192-asurada.dtsi"
+#include <dt-bindings/leds/common.h>
+
+/ {
+       model = "Google Spherion (rev0 - 3)";
+       compatible = "google,spherion-rev3", "google,spherion-rev2",
+                    "google,spherion-rev1", "google,spherion-rev0",
+                    "google,spherion", "mediatek,mt8192";
+
+       pwmleds {
+               compatible = "pwm-leds";
+
+               led {
+                       function = LED_FUNCTION_KBD_BACKLIGHT;
+                       color = <LED_COLOR_ID_WHITE>;
+                       pwms = <&cros_ec_pwm 0>;
+                       max-brightness = <1023>;
+               };
+       };
+};
+
+&cros_ec_pwm {
+       status = "okay";
+};
+
+&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_FULL_SCREEN)
+               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
+       >;
+};
+
+&touchscreen {
+       compatible = "elan,ekth3500";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi b/arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi
new file mode 100644 (file)
index 0000000..4b31443
--- /dev/null
@@ -0,0 +1,959 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2020 MediaTek Inc.
+ * Author: Seiya Wang <seiya.wang@mediatek.com>
+ */
+/dts-v1/;
+#include "mt8192.dtsi"
+#include "mt6359.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/spmi/spmi.h>
+
+/ {
+       aliases {
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       memory@40000000 {
+               device_type = "memory";
+               reg = <0 0x40000000 0 0x80000000>;
+       };
+
+       /* system wide LDO 1.8V power rail */
+       pp1800_ldo_g: regulator-1v8-g {
+               compatible = "regulator-fixed";
+               regulator-name = "pp1800_ldo_g";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               vin-supply = <&pp3300_g>;
+       };
+
+       /* system wide switching 3.3V power rail */
+       pp3300_g: regulator-3v3-g {
+               compatible = "regulator-fixed";
+               regulator-name = "pp3300_g";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&ppvar_sys>;
+       };
+
+       /* system wide LDO 3.3V power rail */
+       pp3300_ldo_z: regulator-3v3-z {
+               compatible = "regulator-fixed";
+               regulator-name = "pp3300_ldo_z";
+               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_u: regulator-3v3-u {
+               compatible = "regulator-fixed";
+               regulator-name = "pp3300_u";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               /* enable pin wired to GPIO controlled by EC */
+               vin-supply = <&pp3300_g>;
+       };
+
+       pp3300_wlan: regulator-3v3-wlan {
+               compatible = "regulator-fixed";
+               regulator-name = "pp3300_wlan";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pp3300_wlan_pins>;
+               enable-active-high;
+               gpio = <&pio 143 GPIO_ACTIVE_HIGH>;
+       };
+
+       /* system wide switching 5.0V power rail */
+       pp5000_a: regulator-5v0-a {
+               compatible = "regulator-fixed";
+               regulator-name = "pp5000_a";
+               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-var-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;
+
+               scp_mem_reserved: scp@50000000 {
+                       compatible = "shared-dma-pool";
+                       reg = <0 0x50000000 0 0x2900000>;
+                       no-map;
+               };
+
+               wifi_restricted_dma_region: wifi@c0000000 {
+                       compatible = "restricted-dma-pool";
+                       reg = <0 0xc0000000 0 0x4000000>;
+               };
+       };
+};
+
+&i2c0 {
+       status = "okay";
+
+       clock-frequency = <400000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c0_pins>;
+
+       touchscreen: touchscreen@10 {
+               reg = <0x10>;
+               interrupts-extended = <&pio 21 IRQ_TYPE_LEVEL_LOW>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&touchscreen_pins>;
+       };
+};
+
+&i2c1 {
+       status = "okay";
+
+       clock-frequency = <400000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c1_pins>;
+};
+
+&i2c2 {
+       status = "okay";
+
+       clock-frequency = <400000>;
+       clock-stretch-ns = <12600>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c2_pins>;
+
+       trackpad@15 {
+               compatible = "elan,ekth3000";
+               reg = <0x15>;
+               interrupts-extended = <&pio 15 IRQ_TYPE_LEVEL_LOW>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&trackpad_pins>;
+               vcc-supply = <&pp3300_u>;
+               wakeup-source;
+       };
+};
+
+&i2c3 {
+       status = "okay";
+
+       clock-frequency = <400000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c3_pins>;
+};
+
+&i2c7 {
+       status = "okay";
+
+       clock-frequency = <400000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c7_pins>;
+};
+
+&mmc0 {
+       status = "okay";
+
+       pinctrl-names = "default", "state_uhs";
+       pinctrl-0 = <&mmc0_default_pins>;
+       pinctrl-1 = <&mmc0_uhs_pins>;
+       bus-width = <8>;
+       max-frequency = <200000000>;
+       vmmc-supply = <&mt6359_vemc_1_ldo_reg>;
+       vqmmc-supply = <&mt6359_vufs_ldo_reg>;
+       cap-mmc-highspeed;
+       mmc-hs200-1_8v;
+       mmc-hs400-1_8v;
+       supports-cqe;
+       cap-mmc-hw-reset;
+       mmc-hs400-enhanced-strobe;
+       hs400-ds-delay = <0x12814>;
+       no-sdio;
+       no-sd;
+       non-removable;
+};
+
+&mmc1 {
+       status = "okay";
+
+       pinctrl-names = "default", "state_uhs";
+       pinctrl-0 = <&mmc1_default_pins>;
+       pinctrl-1 = <&mmc1_uhs_pins>;
+       bus-width = <4>;
+       max-frequency = <200000000>;
+       cd-gpios = <&pio 17 GPIO_ACTIVE_LOW>;
+       vmmc-supply = <&mt6360_ldo5_reg>;
+       vqmmc-supply = <&mt6360_ldo3_reg>;
+       cap-sd-highspeed;
+       sd-uhs-sdr50;
+       sd-uhs-sdr104;
+       no-sdio;
+       no-mmc;
+};
+
+/* for CORE */
+&mt6359_vgpu11_buck_reg {
+       regulator-always-on;
+};
+
+&mt6359_vgpu11_sshub_buck_reg {
+       regulator-always-on;
+       regulator-min-microvolt = <575000>;
+       regulator-max-microvolt = <575000>;
+};
+
+&mt6359_vrf12_ldo_reg {
+       regulator-always-on;
+};
+
+&mt6359_vufs_ldo_reg {
+       regulator-always-on;
+};
+
+&mt6359codec {
+       mediatek,dmic-mode = <1>; /* one-wire */
+       mediatek,mic-type-0 = <2>; /* DMIC */
+       mediatek,mic-type-2 = <2>; /* DMIC */
+};
+
+&nor_flash {
+       status = "okay";
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&nor_flash_pins>;
+       assigned-clocks = <&topckgen CLK_TOP_SFLASH_SEL>;
+       assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL_D6_D8>;
+
+       flash@0 {
+               compatible = "winbond,w25q64jwm", "jedec,spi-nor";
+               reg = <0>;
+               spi-max-frequency = <52000000>;
+               spi-rx-bus-width = <2>;
+               spi-tx-bus-width = <2>;
+       };
+};
+
+&pcie {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pcie_pins>;
+
+       pcie0: pcie@0,0 {
+               device_type = "pci";
+               reg = <0x0000 0 0 0 0>;
+               num-lanes = <1>;
+               bus-range = <0x1 0x1>;
+
+               #address-cells = <3>;
+               #size-cells = <2>;
+               ranges;
+
+               wifi: wifi@0,0 {
+                       reg = <0x10000 0 0 0 0x100000>,
+                             <0x10000 0 0x100000 0 0x100000>;
+                       memory-region = <&wifi_restricted_dma_region>;
+               };
+       };
+};
+
+&pio {
+       /* 220 lines */
+       gpio-line-names = "I2S_DP_LRCK",
+                         "IS_DP_BCLK",
+                         "I2S_DP_MCLK",
+                         "I2S_DP_DATAOUT",
+                         "SAR0_INT_ODL",
+                         "EC_AP_INT_ODL",
+                         "EDPBRDG_INT_ODL",
+                         "DPBRDG_INT_ODL",
+                         "DPBRDG_PWREN",
+                         "DPBRDG_RST_ODL",
+                         "I2S_HP_MCLK",
+                         "I2S_HP_BCK",
+                         "I2S_HP_LRCK",
+                         "I2S_HP_DATAIN",
+                         /*
+                          * AP_FLASH_WP_L is crossystem ABI. Schematics
+                          * call it AP_FLASH_WP_ODL.
+                          */
+                         "AP_FLASH_WP_L",
+                         "TRACKPAD_INT_ODL",
+                         "EC_AP_HPD_OD",
+                         "SD_CD_ODL",
+                         "HP_INT_ODL_ALC",
+                         "EN_PP1000_DPBRDG",
+                         "AP_GPIO20",
+                         "TOUCH_INT_L_1V8",
+                         "UART_BT_WAKE_ODL",
+                         "AP_GPIO23",
+                         "AP_SPI_FLASH_CS_L",
+                         "AP_SPI_FLASH_CLK",
+                         "EN_PP3300_DPBRDG_DX",
+                         "AP_SPI_FLASH_MOSI",
+                         "AP_SPI_FLASH_MISO",
+                         "I2S_HP_DATAOUT",
+                         "AP_GPIO30",
+                         "I2S_SPKR_MCLK",
+                         "I2S_SPKR_BCLK",
+                         "I2S_SPKR_LRCK",
+                         "I2S_SPKR_DATAIN",
+                         "I2S_SPKR_DATAOUT",
+                         "AP_SPI_H1_TPM_CLK",
+                         "AP_SPI_H1_TPM_CS_L",
+                         "AP_SPI_H1_TPM_MISO",
+                         "AP_SPI_H1_TPM_MOSI",
+                         "BL_PWM",
+                         "EDPBRDG_PWREN",
+                         "EDPBRDG_RST_ODL",
+                         "EN_PP3300_HUB",
+                         "HUB_RST_L",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "SD_CLK",
+                         "SD_CMD",
+                         "SD_DATA3",
+                         "SD_DATA0",
+                         "SD_DATA2",
+                         "SD_DATA1",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "PCIE_WAKE_ODL",
+                         "PCIE_RST_L",
+                         "PCIE_CLKREQ_ODL",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "SPMI_SCL",
+                         "SPMI_SDA",
+                         "AP_GOOD",
+                         "UART_DBG_TX_AP_RX",
+                         "UART_AP_TX_DBG_RX",
+                         "UART_AP_TX_BT_RX",
+                         "UART_BT_TX_AP_RX",
+                         "MIPI_DPI_D0_R",
+                         "MIPI_DPI_D1_R",
+                         "MIPI_DPI_D2_R",
+                         "MIPI_DPI_D3_R",
+                         "MIPI_DPI_D4_R",
+                         "MIPI_DPI_D5_R",
+                         "MIPI_DPI_D6_R",
+                         "MIPI_DPI_D7_R",
+                         "MIPI_DPI_D8_R",
+                         "MIPI_DPI_D9_R",
+                         "MIPI_DPI_D10_R",
+                         "",
+                         "",
+                         "MIPI_DPI_DE_R",
+                         "MIPI_DPI_D11_R",
+                         "MIPI_DPI_VSYNC_R",
+                         "MIPI_DPI_CLK_R",
+                         "MIPI_DPI_HSYNC_R",
+                         "PCM_BT_DATAIN",
+                         "PCM_BT_SYNC",
+                         "PCM_BT_DATAOUT",
+                         "PCM_BT_CLK",
+                         "AP_I2C_AUDIO_SCL",
+                         "AP_I2C_AUDIO_SDA",
+                         "SCP_I2C_SCL",
+                         "SCP_I2C_SDA",
+                         "AP_I2C_WLAN_SCL",
+                         "AP_I2C_WLAN_SDA",
+                         "AP_I2C_DPBRDG_SCL",
+                         "AP_I2C_DPBRDG_SDA",
+                         "EN_PP1800_DPBRDG_DX",
+                         "EN_PP3300_EDP_DX",
+                         "EN_PP1800_EDPBRDG_DX",
+                         "EN_PP1000_EDPBRDG",
+                         "SCP_JTAG0_TDO",
+                         "SCP_JTAG0_TDI",
+                         "SCP_JTAG0_TMS",
+                         "SCP_JTAG0_TCK",
+                         "SCP_JTAG0_TRSTN",
+                         "EN_PP3000_VMC_PMU",
+                         "EN_PP3300_DISPLAY_DX",
+                         "TOUCH_RST_L_1V8",
+                         "TOUCH_REPORT_DISABLE",
+                         "",
+                         "",
+                         "AP_I2C_TRACKPAD_SCL_1V8",
+                         "AP_I2C_TRACKPAD_SDA_1V8",
+                         "EN_PP3300_WLAN",
+                         "BT_KILL_L",
+                         "WIFI_KILL_L",
+                         "SET_VMC_VOLT_AT_1V8",
+                         "EN_SPK",
+                         "AP_WARM_RST_REQ",
+                         "",
+                         "",
+                         "EN_PP3000_SD_S3",
+                         "AP_EDP_BKLTEN",
+                         "",
+                         "",
+                         "",
+                         "AP_SPI_EC_CLK",
+                         "AP_SPI_EC_CS_L",
+                         "AP_SPI_EC_MISO",
+                         "AP_SPI_EC_MOSI",
+                         "AP_I2C_EDPBRDG_SCL",
+                         "AP_I2C_EDPBRDG_SDA",
+                         "MT6315_PROC_INT",
+                         "MT6315_GPU_INT",
+                         "UART_SERVO_TX_SCP_RX",
+                         "UART_SCP_TX_SERVO_RX",
+                         "BT_RTS_AP_CTS",
+                         "AP_RTS_BT_CTS",
+                         "UART_AP_WAKE_BT_ODL",
+                         "WLAN_ALERT_ODL",
+                         "EC_IN_RW_ODL",
+                         "H1_AP_INT_ODL",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "MSDC0_CMD",
+                         "MSDC0_DAT0",
+                         "MSDC0_DAT2",
+                         "MSDC0_DAT4",
+                         "MSDC0_DAT6",
+                         "MSDC0_DAT1",
+                         "MSDC0_DAT5",
+                         "MSDC0_DAT7",
+                         "MSDC0_DSL",
+                         "MSDC0_CLK",
+                         "MSDC0_DAT3",
+                         "MSDC0_RST_L",
+                         "SCP_VREQ_VAO",
+                         "AUD_DAT_MOSI2",
+                         "AUD_NLE_MOSI1",
+                         "AUD_NLE_MOSI0",
+                         "AUD_DAT_MISO2",
+                         "AP_I2C_SAR_SDA",
+                         "AP_I2C_SAR_SCL",
+                         "AP_I2C_PWR_SCL",
+                         "AP_I2C_PWR_SDA",
+                         "AP_I2C_TS_SCL_1V8",
+                         "AP_I2C_TS_SDA_1V8",
+                         "SRCLKENA0",
+                         "SRCLKENA1",
+                         "AP_EC_WATCHDOG_L",
+                         "PWRAP_SPI0_MI",
+                         "PWRAP_SPI0_CSN",
+                         "PWRAP_SPI0_MO",
+                         "PWRAP_SPI0_CK",
+                         "AP_RTC_CLK32K",
+                         "AUD_CLK_MOSI",
+                         "AUD_SYNC_MOSI",
+                         "AUD_DAT_MOSI0",
+                         "AUD_DAT_MOSI1",
+                         "AUD_DAT_MISO0",
+                         "AUD_DAT_MISO1";
+
+       cr50_int: cr50-irq-default-pins {
+               pins-gsc-ap-int-odl {
+                       pinmux = <PINMUX_GPIO171__FUNC_GPIO171>;
+                       input-enable;
+               };
+       };
+
+       cros_ec_int: cros-ec-irq-default-pins {
+               pins-ec-ap-int-odl {
+                       pinmux = <PINMUX_GPIO5__FUNC_GPIO5>;
+                       input-enable;
+                       bias-pull-up;
+               };
+       };
+
+       i2c0_pins: i2c0-default-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO204__FUNC_SCL0>,
+                                <PINMUX_GPIO205__FUNC_SDA0>;
+                       bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+                       drive-strength-microamp = <1000>;
+               };
+       };
+
+       i2c1_pins: i2c1-default-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO118__FUNC_SCL1>,
+                                <PINMUX_GPIO119__FUNC_SDA1>;
+                       bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+                       drive-strength-microamp = <1000>;
+               };
+       };
+
+       i2c2_pins: i2c2-default-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO141__FUNC_SCL2>,
+                                <PINMUX_GPIO142__FUNC_SDA2>;
+                       bias-pull-up = <MTK_PULL_SET_RSEL_011>;
+               };
+       };
+
+       i2c3_pins: i2c3-default-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO160__FUNC_SCL3>,
+                                <PINMUX_GPIO161__FUNC_SDA3>;
+                       bias-disable;
+                       drive-strength-microamp = <1000>;
+               };
+       };
+
+       i2c7_pins: i2c7-default-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO124__FUNC_SCL7>,
+                                <PINMUX_GPIO125__FUNC_SDA7>;
+                       bias-disable;
+                       drive-strength-microamp = <1000>;
+               };
+       };
+
+       mmc0_default_pins: mmc0-default-pins {
+               pins-cmd-dat {
+                       pinmux = <PINMUX_GPIO184__FUNC_MSDC0_DAT0>,
+                                <PINMUX_GPIO188__FUNC_MSDC0_DAT1>,
+                                <PINMUX_GPIO185__FUNC_MSDC0_DAT2>,
+                                <PINMUX_GPIO193__FUNC_MSDC0_DAT3>,
+                                <PINMUX_GPIO186__FUNC_MSDC0_DAT4>,
+                                <PINMUX_GPIO189__FUNC_MSDC0_DAT5>,
+                                <PINMUX_GPIO187__FUNC_MSDC0_DAT6>,
+                                <PINMUX_GPIO190__FUNC_MSDC0_DAT7>,
+                                <PINMUX_GPIO183__FUNC_MSDC0_CMD>;
+                       input-enable;
+                       drive-strength = <8>;
+                       bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+               };
+
+               pins-clk {
+                       pinmux = <PINMUX_GPIO192__FUNC_MSDC0_CLK>;
+                       drive-strength = <8>;
+                       bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+               };
+
+               pins-rst {
+                       pinmux = <PINMUX_GPIO194__FUNC_MSDC0_RSTB>;
+                       drive-strength = <8>;
+                       bias-pull-down = <MTK_PUPD_SET_R1R0_01>;
+               };
+       };
+
+       mmc0_uhs_pins: mmc0-uhs-pins {
+               pins-cmd-dat {
+                       pinmux = <PINMUX_GPIO184__FUNC_MSDC0_DAT0>,
+                                <PINMUX_GPIO188__FUNC_MSDC0_DAT1>,
+                                <PINMUX_GPIO185__FUNC_MSDC0_DAT2>,
+                                <PINMUX_GPIO193__FUNC_MSDC0_DAT3>,
+                                <PINMUX_GPIO186__FUNC_MSDC0_DAT4>,
+                                <PINMUX_GPIO189__FUNC_MSDC0_DAT5>,
+                                <PINMUX_GPIO187__FUNC_MSDC0_DAT6>,
+                                <PINMUX_GPIO190__FUNC_MSDC0_DAT7>,
+                                <PINMUX_GPIO183__FUNC_MSDC0_CMD>;
+                       input-enable;
+                       drive-strength = <10>;
+                       bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+               };
+
+               pins-clk {
+                       pinmux = <PINMUX_GPIO192__FUNC_MSDC0_CLK>;
+                       drive-strength = <10>;
+                       bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+               };
+
+               pins-rst {
+                       pinmux = <PINMUX_GPIO194__FUNC_MSDC0_RSTB>;
+                       drive-strength = <8>;
+                       bias-pull-down = <MTK_PUPD_SET_R1R0_01>;
+               };
+
+               pins-ds {
+                       pinmux = <PINMUX_GPIO191__FUNC_MSDC0_DSL>;
+                       drive-strength = <10>;
+                       bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+               };
+       };
+
+       mmc1_default_pins: mmc1-default-pins {
+               pins-cmd-dat {
+                       pinmux = <PINMUX_GPIO54__FUNC_MSDC1_DAT0>,
+                                <PINMUX_GPIO56__FUNC_MSDC1_DAT1>,
+                                <PINMUX_GPIO55__FUNC_MSDC1_DAT2>,
+                                <PINMUX_GPIO53__FUNC_MSDC1_DAT3>,
+                                <PINMUX_GPIO52__FUNC_MSDC1_CMD>;
+                       input-enable;
+                       drive-strength = <8>;
+                       bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+               };
+
+               pins-clk {
+                       pinmux = <PINMUX_GPIO51__FUNC_MSDC1_CLK>;
+                       drive-strength = <8>;
+                       bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+               };
+
+               pins-insert {
+                       pinmux = <PINMUX_GPIO17__FUNC_GPIO17>;
+                       input-enable;
+                       bias-pull-up;
+               };
+       };
+
+       mmc1_uhs_pins: mmc1-uhs-pins {
+               pins-cmd-dat {
+                       pinmux = <PINMUX_GPIO54__FUNC_MSDC1_DAT0>,
+                                <PINMUX_GPIO56__FUNC_MSDC1_DAT1>,
+                                <PINMUX_GPIO55__FUNC_MSDC1_DAT2>,
+                                <PINMUX_GPIO53__FUNC_MSDC1_DAT3>,
+                                <PINMUX_GPIO52__FUNC_MSDC1_CMD>;
+                       input-enable;
+                       drive-strength = <8>;
+                       bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+               };
+
+               pins-clk {
+                       pinmux = <PINMUX_GPIO51__FUNC_MSDC1_CLK>;
+                       input-enable;
+                       drive-strength = <8>;
+                       bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+               };
+       };
+
+       nor_flash_pins: nor-flash-default-pins {
+               pins-cs-io1 {
+                       pinmux = <PINMUX_GPIO24__FUNC_SPINOR_CS>,
+                                <PINMUX_GPIO28__FUNC_SPINOR_IO1>;
+                       input-enable;
+                       bias-pull-up;
+                       drive-strength = <10>;
+               };
+
+               pins-io0 {
+                       pinmux = <PINMUX_GPIO27__FUNC_SPINOR_IO0>;
+                       bias-pull-up;
+                       drive-strength = <10>;
+               };
+
+               pins-clk {
+                       pinmux = <PINMUX_GPIO25__FUNC_SPINOR_CK>;
+                       input-enable;
+                       bias-pull-up;
+                       drive-strength = <10>;
+               };
+       };
+
+       pcie_pins: pcie-default-pins {
+               pins-pcie-wake {
+                       pinmux = <PINMUX_GPIO63__FUNC_PCIE_WAKE_N>;
+                       bias-pull-up;
+               };
+
+               pins-pcie-pereset {
+                       pinmux = <PINMUX_GPIO64__FUNC_PCIE_PERESET_N>;
+               };
+
+               pins-pcie-clkreq {
+                       pinmux = <PINMUX_GPIO65__FUNC_PCIE_CLKREQ_N>;
+                       bias-pull-up;
+               };
+
+               pins-wifi-kill {
+                       pinmux = <PINMUX_GPIO145__FUNC_GPIO145>; /* WIFI_KILL_L */
+                       output-high;
+               };
+       };
+
+       pp3300_wlan_pins: pp3300-wlan-pins {
+               pins-pcie-en-pp3300-wlan {
+                       pinmux = <PINMUX_GPIO143__FUNC_GPIO143>;
+                       output-high;
+               };
+       };
+
+       scp_pins: scp-pins {
+               pins-vreq-vao {
+                       pinmux = <PINMUX_GPIO195__FUNC_SCP_VREQ_VAO>;
+               };
+       };
+
+       spi1_pins: spi1-default-pins {
+               pins-cs-mosi-clk {
+                       pinmux = <PINMUX_GPIO157__FUNC_SPI1_A_CSB>,
+                                <PINMUX_GPIO159__FUNC_SPI1_A_MO>,
+                                <PINMUX_GPIO156__FUNC_SPI1_A_CLK>;
+                       bias-disable;
+               };
+
+               pins-miso {
+                       pinmux = <PINMUX_GPIO158__FUNC_SPI1_A_MI>;
+                       bias-pull-down;
+               };
+       };
+
+       spi5_pins: spi5-default-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO38__FUNC_SPI5_A_MI>,
+                                <PINMUX_GPIO37__FUNC_GPIO37>,
+                                <PINMUX_GPIO39__FUNC_SPI5_A_MO>,
+                                <PINMUX_GPIO36__FUNC_SPI5_A_CLK>;
+                       bias-disable;
+               };
+       };
+
+       trackpad_pins: trackpad-default-pins {
+               pins-int-n {
+                       pinmux = <PINMUX_GPIO15__FUNC_GPIO15>;
+                       input-enable;
+                       bias-pull-up = <MTK_PUPD_SET_R1R0_11>;
+               };
+       };
+
+       touchscreen_pins: touchscreen-default-pins {
+               pins-irq {
+                       pinmux = <PINMUX_GPIO21__FUNC_GPIO21>;
+                       input-enable;
+                       bias-pull-up;
+               };
+
+               pins-reset {
+                       pinmux = <PINMUX_GPIO137__FUNC_GPIO137>;
+                       output-high;
+               };
+
+               pins-report-sw {
+                       pinmux = <PINMUX_GPIO138__FUNC_GPIO138>;
+                       output-low;
+               };
+       };
+};
+
+&pmic {
+       interrupts-extended = <&pio 214 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&scp {
+       status = "okay";
+
+       firmware-name = "mediatek/mt8192/scp.img";
+       memory-region = <&scp_mem_reserved>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&scp_pins>;
+
+       cros-ec {
+               compatible = "google,cros-ec-rpmsg";
+               mediatek,rpmsg-name = "cros-ec-rpmsg";
+       };
+};
+
+&spi1 {
+       status = "okay";
+
+       mediatek,pad-select = <0>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&spi1_pins>;
+
+       cros_ec: ec@0 {
+               compatible = "google,cros-ec-spi";
+               reg = <0>;
+               interrupts-extended = <&pio 5 IRQ_TYPE_LEVEL_LOW>;
+               spi-max-frequency = <3000000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&cros_ec_int>;
+
+               #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>;
+
+                       status = "disabled";
+               };
+
+               i2c_tunnel: i2c-tunnel {
+                       compatible = "google,cros-ec-i2c-tunnel";
+                       google,remote-bus = <0>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
+               mt6360_ldo3_reg: regulator@0 {
+                       compatible = "google,cros-ec-regulator";
+                       reg = <0>;
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <3300000>;
+               };
+
+               mt6360_ldo5_reg: regulator@1 {
+                       compatible = "google,cros-ec-regulator";
+                       reg = <1>;
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+               };
+
+               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";
+                       };
+               };
+       };
+};
+
+&spi5 {
+       status = "okay";
+
+       cs-gpios = <&pio 37 GPIO_ACTIVE_LOW>;
+       mediatek,pad-select = <0>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&spi5_pins>;
+
+       cr50@0 {
+               compatible = "google,cr50";
+               reg = <0>;
+               interrupts-extended = <&pio 171 IRQ_TYPE_EDGE_RISING>;
+               spi-max-frequency = <1000000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&cr50_int>;
+       };
+};
+
+&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_6_vbuck3: vbuck3 {
+                               regulator-compatible = "vbuck3";
+                               regulator-name = "Vlcpu";
+                               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 = <606250>;
+                               regulator-max-microvolt = <1193750>;
+                               regulator-enable-ramp-delay = <256>;
+                               regulator-allowed-modes = <0 1 2>;
+                       };
+               };
+       };
+};
+
+&uart0 {
+       status = "okay";
+};
+
+&xhci {
+       status = "okay";
+
+       wakeup-source;
+       vusb33-supply = <&pp3300_g>;
+       vbus-supply = <&pp5000_a>;
+};
+
+#include <arm/cros-ec-keyboard.dtsi>
+#include <arm/cros-ec-sbs.dtsi>
index 733aec2..cbae5a5 100644 (file)
@@ -43,7 +43,7 @@
                        reg = <0x000>;
                        enable-method = "psci";
                        clock-frequency = <1701000000>;
-                       cpu-idle-states = <&cpuoff_l &clusteroff_l>;
+                       cpu-idle-states = <&cpu_sleep_l &cluster_sleep_l>;
                        next-level-cache = <&l2_0>;
                        capacity-dmips-mhz = <530>;
                };
@@ -54,7 +54,7 @@
                        reg = <0x100>;
                        enable-method = "psci";
                        clock-frequency = <1701000000>;
-                       cpu-idle-states = <&cpuoff_l &clusteroff_l>;
+                       cpu-idle-states = <&cpu_sleep_l &cluster_sleep_l>;
                        next-level-cache = <&l2_0>;
                        capacity-dmips-mhz = <530>;
                };
@@ -65,7 +65,7 @@
                        reg = <0x200>;
                        enable-method = "psci";
                        clock-frequency = <1701000000>;
-                       cpu-idle-states = <&cpuoff_l &clusteroff_l>;
+                       cpu-idle-states = <&cpu_sleep_l &cluster_sleep_l>;
                        next-level-cache = <&l2_0>;
                        capacity-dmips-mhz = <530>;
                };
@@ -76,7 +76,7 @@
                        reg = <0x300>;
                        enable-method = "psci";
                        clock-frequency = <1701000000>;
-                       cpu-idle-states = <&cpuoff_l &clusteroff_l>;
+                       cpu-idle-states = <&cpu_sleep_l &cluster_sleep_l>;
                        next-level-cache = <&l2_0>;
                        capacity-dmips-mhz = <530>;
                };
@@ -87,7 +87,7 @@
                        reg = <0x400>;
                        enable-method = "psci";
                        clock-frequency = <2171000000>;
-                       cpu-idle-states = <&cpuoff_b &clusteroff_b>;
+                       cpu-idle-states = <&cpu_sleep_b &cluster_sleep_b>;
                        next-level-cache = <&l2_1>;
                        capacity-dmips-mhz = <1024>;
                };
@@ -98,7 +98,7 @@
                        reg = <0x500>;
                        enable-method = "psci";
                        clock-frequency = <2171000000>;
-                       cpu-idle-states = <&cpuoff_b &clusteroff_b>;
+                       cpu-idle-states = <&cpu_sleep_b &cluster_sleep_b>;
                        next-level-cache = <&l2_1>;
                        capacity-dmips-mhz = <1024>;
                };
                        reg = <0x600>;
                        enable-method = "psci";
                        clock-frequency = <2171000000>;
-                       cpu-idle-states = <&cpuoff_b &clusteroff_b>;
+                       cpu-idle-states = <&cpu_sleep_b &cluster_sleep_b>;
                        next-level-cache = <&l2_1>;
                        capacity-dmips-mhz = <1024>;
                };
                        reg = <0x700>;
                        enable-method = "psci";
                        clock-frequency = <2171000000>;
-                       cpu-idle-states = <&cpuoff_b &clusteroff_b>;
+                       cpu-idle-states = <&cpu_sleep_b &cluster_sleep_b>;
                        next-level-cache = <&l2_1>;
                        capacity-dmips-mhz = <1024>;
                };
                };
 
                idle-states {
-                       entry-method = "arm,psci";
-                       cpuoff_l: cpuoff_l {
+                       entry-method = "psci";
+                       cpu_sleep_l: cpu-sleep-l {
                                compatible = "arm,idle-state";
                                arm,psci-suspend-param = <0x00010001>;
                                local-timer-stop;
                                exit-latency-us = <140>;
                                min-residency-us = <780>;
                        };
-                       cpuoff_b: cpuoff_b {
+                       cpu_sleep_b: cpu-sleep-b {
                                compatible = "arm,idle-state";
                                arm,psci-suspend-param = <0x00010001>;
                                local-timer-stop;
                                exit-latency-us = <145>;
                                min-residency-us = <720>;
                        };
-                       clusteroff_l: clusteroff_l {
+                       cluster_sleep_l: cluster-sleep-l {
                                compatible = "arm,idle-state";
                                arm,psci-suspend-param = <0x01010002>;
                                local-timer-stop;
                                exit-latency-us = <155>;
                                min-residency-us = <860>;
                        };
-                       clusteroff_b: clusteroff_b {
+                       cluster_sleep_b: cluster-sleep-b {
                                compatible = "arm,idle-state";
                                arm,psci-suspend-param = <0x01010002>;
                                local-timer-stop;
                        compatible = "mediatek,mt8192-infracfg", "syscon";
                        reg = <0 0x10001000 0 0x1000>;
                        #clock-cells = <1>;
+                       #reset-cells = <1>;
                };
 
                pericfg: syscon@10003000 {
                };
 
                efuse: efuse@11c10000 {
-                       compatible = "mediatek,efuse";
+                       compatible = "mediatek,mt8192-efuse", "mediatek,efuse";
                        reg = <0 0x11c10000 0 0x1000>;
                        #address-cells = <1>;
                        #size-cells = <1>;
diff --git a/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r1.dts b/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r1.dts
new file mode 100644 (file)
index 0000000..3348ba6
--- /dev/null
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2021 MediaTek Inc.
+ */
+/dts-v1/;
+#include "mt8195-cherry.dtsi"
+
+/ {
+       model = "Acer Tomato (rev1) board";
+       compatible = "google,tomato-rev1", "google,tomato", "mediatek,mt8195";
+};
+
+&ts_10 {
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r2.dts b/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r2.dts
new file mode 100644 (file)
index 0000000..4669e9d
--- /dev/null
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2021 MediaTek Inc.
+ */
+/dts-v1/;
+#include "mt8195-cherry.dtsi"
+
+/ {
+       model = "Acer Tomato (rev2) board";
+       compatible = "google,tomato-rev2", "google,tomato", "mediatek,mt8195";
+};
+
+&pio_default {
+       pins-low-power-hdmi-disable {
+               pinmux = <PINMUX_GPIO31__FUNC_GPIO31>,
+                        <PINMUX_GPIO32__FUNC_GPIO32>,
+                        <PINMUX_GPIO33__FUNC_GPIO33>,
+                        <PINMUX_GPIO34__FUNC_GPIO34>,
+                        <PINMUX_GPIO35__FUNC_GPIO35>;
+               input-enable;
+               bias-pull-down;
+       };
+
+       pins-low-power-pcie0-disable {
+               pinmux = <PINMUX_GPIO19__FUNC_GPIO19>,
+                        <PINMUX_GPIO20__FUNC_GPIO20>,
+                        <PINMUX_GPIO21__FUNC_GPIO21>;
+               input-enable;
+               bias-pull-down;
+       };
+};
+
+&ts_10 {
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r3.dts b/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r3.dts
new file mode 100644 (file)
index 0000000..5021edd
--- /dev/null
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2021 MediaTek Inc.
+ */
+/dts-v1/;
+#include "mt8195-cherry.dtsi"
+
+/ {
+       model = "Acer Tomato (rev3 - 4) board";
+       compatible = "google,tomato-rev4", "google,tomato-rev3",
+                    "google,tomato", "mediatek,mt8195";
+};
+
+&pio_default {
+       pins-low-power-hdmi-disable {
+               pinmux = <PINMUX_GPIO31__FUNC_GPIO31>,
+                        <PINMUX_GPIO32__FUNC_GPIO32>,
+                        <PINMUX_GPIO33__FUNC_GPIO33>,
+                        <PINMUX_GPIO34__FUNC_GPIO34>,
+                        <PINMUX_GPIO35__FUNC_GPIO35>;
+               input-enable;
+               bias-pull-down;
+       };
+
+       pins-low-power-pcie0-disable {
+               pinmux = <PINMUX_GPIO19__FUNC_GPIO19>,
+                        <PINMUX_GPIO20__FUNC_GPIO20>,
+                        <PINMUX_GPIO21__FUNC_GPIO21>;
+               input-enable;
+               bias-pull-down;
+       };
+};
+
+&ts_10 {
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi b/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi
new file mode 100644 (file)
index 0000000..fcc6006
--- /dev/null
@@ -0,0 +1,702 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2021 MediaTek Inc.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include "mt8195.dtsi"
+#include "mt6359.dtsi"
+
+/ {
+       aliases {
+               i2c0 = &i2c0;
+               i2c1 = &i2c1;
+               i2c2 = &i2c2;
+               i2c3 = &i2c3;
+               i2c4 = &i2c4;
+               i2c5 = &i2c5;
+               i2c7 = &i2c7;
+               mmc0 = &mmc0;
+               serial0 = &uart0;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       memory@40000000 {
+               device_type = "memory";
+               reg = <0 0x40000000 0 0x80000000>;
+       };
+
+       /* 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;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               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_s5: regulator-pp5000-s5 {
+               compatible = "regulator-fixed";
+               regulator-name = "pp5000_s5";
+               /* 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;
+       };
+
+       usb_vbus: regulator-5v0-usb-vbus {
+               compatible = "regulator-fixed";
+               regulator-name = "usb-vbus";
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+               enable-active-high;
+               regulator-always-on;
+       };
+};
+
+&i2c0 {
+       status = "okay";
+
+       clock-frequency = <400000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c0_pins>;
+};
+
+&i2c1 {
+       status = "okay";
+
+       clock-frequency = <400000>;
+       i2c-scl-internal-delay-ns = <12500>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c1_pins>;
+};
+
+&i2c2 {
+       status = "okay";
+
+       clock-frequency = <400000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c2_pins>;
+};
+
+&i2c3 {
+       status = "okay";
+
+       clock-frequency = <400000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c3_pins>;
+};
+
+&i2c4 {
+       status = "okay";
+
+       clock-frequency = <400000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c4_pins>;
+
+       ts_10: touchscreen@10 {
+               compatible = "hid-over-i2c";
+               reg = <0x10>;
+               hid-descr-addr = <0x0001>;
+               interrupts-extended = <&pio 92 IRQ_TYPE_LEVEL_LOW>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&touchscreen_pins>;
+               post-power-on-delay-ms = <10>;
+               vdd-supply = <&pp3300_s3>;
+               status = "disabled";
+       };
+};
+
+&i2c5 {
+       status = "okay";
+
+       clock-frequency = <400000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c5_pins>;
+};
+
+&i2c7 {
+       status = "okay";
+
+       clock-frequency = <400000>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c7_pins>;
+
+       pmic@34 {
+               #interrupt-cells = <1>;
+               compatible = "mediatek,mt6360";
+               reg = <0x34>;
+               interrupt-controller;
+               interrupts-extended = <&pio 130 IRQ_TYPE_EDGE_FALLING>;
+               interrupt-names = "IRQB";
+               pinctrl-names = "default";
+               pinctrl-0 = <&subpmic_default>;
+               wakeup-source;
+       };
+};
+
+&mmc0 {
+       status = "okay";
+
+       bus-width = <8>;
+       cap-mmc-highspeed;
+       cap-mmc-hw-reset;
+       hs400-ds-delay = <0x14c11>;
+       max-frequency = <200000000>;
+       mmc-hs200-1_8v;
+       mmc-hs400-1_8v;
+       no-sdio;
+       no-sd;
+       non-removable;
+       pinctrl-names = "default", "state_uhs";
+       pinctrl-0 = <&mmc0_pins_default>;
+       pinctrl-1 = <&mmc0_pins_uhs>;
+       vmmc-supply = <&mt6359_vemc_1_ldo_reg>;
+       vqmmc-supply = <&mt6359_vufs_ldo_reg>;
+};
+
+/* for CPU-L */
+&mt6359_vcore_buck_reg {
+       regulator-always-on;
+};
+
+/* for CORE */
+&mt6359_vgpu11_buck_reg {
+       regulator-always-on;
+};
+
+&mt6359_vgpu11_sshub_buck_reg {
+       regulator-always-on;
+       regulator-min-microvolt = <550000>;
+       regulator-max-microvolt = <550000>;
+};
+
+/* for CORE SRAM */
+&mt6359_vpu_buck_reg {
+       regulator-always-on;
+};
+
+&mt6359_vrf12_ldo_reg {
+       regulator-always-on;
+};
+
+/* for GPU SRAM */
+&mt6359_vsram_others_ldo_reg {
+       regulator-always-on;
+       regulator-min-microvolt = <750000>;
+       regulator-max-microvolt = <750000>;
+};
+
+&mt6359_vufs_ldo_reg {
+       regulator-always-on;
+};
+
+&nor_flash {
+       status = "okay";
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&nor_pins_default>;
+
+       flash@0 {
+               compatible = "jedec,spi-nor";
+               reg = <0>;
+               spi-max-frequency = <52000000>;
+               spi-rx-bus-width = <2>;
+               spi-tx-bus-width = <2>;
+       };
+};
+
+&pio {
+       mediatek,rsel-resistance-in-si-unit;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pio_default>;
+
+       /* 144 lines */
+       gpio-line-names =
+               "I2S_SPKR_MCLK",
+               "I2S_SPKR_DATAIN",
+               "I2S_SPKR_LRCK",
+               "I2S_SPKR_BCLK",
+               "EC_AP_INT_ODL",
+               /*
+                * AP_FLASH_WP_L is crossystem ABI. Schematics
+                * call it AP_FLASH_WP_ODL.
+                */
+               "AP_FLASH_WP_L",
+               "TCHPAD_INT_ODL",
+               "EDP_HPD_1V8",
+               "AP_I2C_CAM_SDA",
+               "AP_I2C_CAM_SCL",
+               "AP_I2C_TCHPAD_SDA_1V8",
+               "AP_I2C_TCHPAD_SCL_1V8",
+               "AP_I2C_AUD_SDA",
+               "AP_I2C_AUD_SCL",
+               "AP_I2C_TPM_SDA_1V8",
+               "AP_I2C_TPM_SCL_1V8",
+               "AP_I2C_TCHSCR_SDA_1V8",
+               "AP_I2C_TCHSCR_SCL_1V8",
+               "EC_AP_HPD_OD",
+               "",
+               "PCIE_NVME_RST_L",
+               "PCIE_NVME_CLKREQ_ODL",
+               "PCIE_RST_1V8_L",
+               "PCIE_CLKREQ_1V8_ODL",
+               "PCIE_WAKE_1V8_ODL",
+               "CLK_24M_CAM0",
+               "CAM1_SEN_EN",
+               "AP_I2C_PWR_SCL_1V8",
+               "AP_I2C_PWR_SDA_1V8",
+               "AP_I2C_MISC_SCL",
+               "AP_I2C_MISC_SDA",
+               "EN_PP5000_HDMI_X",
+               "AP_HDMITX_HTPLG",
+               "",
+               "AP_HDMITX_SCL_1V8",
+               "AP_HDMITX_SDA_1V8",
+               "AP_RTC_CLK32K",
+               "AP_EC_WATCHDOG_L",
+               "SRCLKENA0",
+               "SRCLKENA1",
+               "PWRAP_SPI0_CS_L",
+               "PWRAP_SPI0_CK",
+               "PWRAP_SPI0_MOSI",
+               "PWRAP_SPI0_MISO",
+               "SPMI_SCL",
+               "SPMI_SDA",
+               "",
+               "",
+               "",
+               "I2S_HP_DATAIN",
+               "I2S_HP_MCLK",
+               "I2S_HP_BCK",
+               "I2S_HP_LRCK",
+               "I2S_HP_DATAOUT",
+               "SD_CD_ODL",
+               "EN_PP3300_DISP_X",
+               "TCHSCR_RST_1V8_L",
+               "TCHSCR_REPORT_DISABLE",
+               "EN_PP3300_WLAN_X",
+               "BT_KILL_1V8_L",
+               "I2S_SPKR_DATAOUT",
+               "WIFI_KILL_1V8_L",
+               "BEEP_ON",
+               "SCP_I2C_SENSOR_SCL_1V8",
+               "SCP_I2C_SENSOR_SDA_1V8",
+               "",
+               "",
+               "",
+               "",
+               "AUD_CLK_MOSI",
+               "AUD_SYNC_MOSI",
+               "AUD_DAT_MOSI0",
+               "AUD_DAT_MOSI1",
+               "AUD_DAT_MISO0",
+               "AUD_DAT_MISO1",
+               "AUD_DAT_MISO2",
+               "SCP_VREQ_VAO",
+               "AP_SPI_GSC_TPM_CLK",
+               "AP_SPI_GSC_TPM_MOSI",
+               "AP_SPI_GSC_TPM_CS_L",
+               "AP_SPI_GSC_TPM_MISO",
+               "EN_PP1000_CAM_X",
+               "AP_EDP_BKLTEN",
+               "",
+               "USB3_HUB_RST_L",
+               "",
+               "WLAN_ALERT_ODL",
+               "EC_IN_RW_ODL",
+               "GSC_AP_INT_ODL",
+               "HP_INT_ODL",
+               "CAM0_RST_L",
+               "CAM1_RST_L",
+               "TCHSCR_INT_1V8_L",
+               "CAM1_DET_L",
+               "RST_ALC1011_L",
+               "",
+               "",
+               "BL_PWM_1V8",
+               "UART_AP_TX_DBG_RX",
+               "UART_DBG_TX_AP_RX",
+               "EN_SPKR",
+               "AP_EC_WARM_RST_REQ",
+               "UART_SCP_TX_DBGCON_RX",
+               "UART_DBGCON_TX_SCP_RX",
+               "",
+               "",
+               "KPCOL0",
+               "",
+               "MT6315_GPU_INT",
+               "MT6315_PROC_BC_INT",
+               "SD_CMD",
+               "SD_CLK",
+               "SD_DAT0",
+               "SD_DAT1",
+               "SD_DAT2",
+               "SD_DAT3",
+               "EMMC_DAT7",
+               "EMMC_DAT6",
+               "EMMC_DAT5",
+               "EMMC_DAT4",
+               "EMMC_RSTB",
+               "EMMC_CMD",
+               "EMMC_CLK",
+               "EMMC_DAT3",
+               "EMMC_DAT2",
+               "EMMC_DAT1",
+               "EMMC_DAT0",
+               "EMMC_DSL",
+               "",
+               "",
+               "MT6360_INT_ODL",
+               "SCP_JTAG0_TRSTN",
+               "AP_SPI_EC_CS_L",
+               "AP_SPI_EC_CLK",
+               "AP_SPI_EC_MOSI",
+               "AP_SPI_EC_MISO",
+               "SCP_JTAG0_TMS",
+               "SCP_JTAG0_TCK",
+               "SCP_JTAG0_TDO",
+               "SCP_JTAG0_TDI",
+               "AP_SPI_FLASH_CS_L",
+               "AP_SPI_FLASH_CLK",
+               "AP_SPI_FLASH_MOSI",
+               "AP_SPI_FLASH_MISO";
+
+       i2c0_pins: i2c0-default-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO8__FUNC_SDA0>,
+                                <PINMUX_GPIO9__FUNC_SCL0>;
+                       bias-disable;
+                       drive-strength-microamp = <1000>;
+               };
+       };
+
+       i2c1_pins: i2c1-default-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO10__FUNC_SDA1>,
+                                <PINMUX_GPIO11__FUNC_SCL1>;
+                       bias-pull-up = <1000>;
+                       drive-strength-microamp = <1000>;
+               };
+       };
+
+       i2c2_pins: i2c2-default-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO12__FUNC_SDA2>,
+                                <PINMUX_GPIO13__FUNC_SCL2>;
+                       bias-disable;
+                       drive-strength-microamp = <1000>;
+               };
+       };
+
+       i2c3_pins: i2c3-default-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO14__FUNC_SDA3>,
+                                <PINMUX_GPIO15__FUNC_SCL3>;
+                       bias-pull-up = <1000>;
+                       drive-strength-microamp = <1000>;
+               };
+       };
+
+       i2c4_pins: i2c4-default-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO16__FUNC_SDA4>,
+                                <PINMUX_GPIO17__FUNC_SCL4>;
+                       bias-pull-up = <1000>;
+                       drive-strength = <4>;
+               };
+       };
+
+       i2c5_pins: i2c5-default-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO29__FUNC_SCL5>,
+                                <PINMUX_GPIO30__FUNC_SDA5>;
+                       bias-disable;
+                       drive-strength-microamp = <1000>;
+               };
+       };
+
+       i2c7_pins: i2c7-default-pins {
+               pins-bus {
+                       pinmux = <PINMUX_GPIO27__FUNC_SCL7>,
+                                <PINMUX_GPIO28__FUNC_SDA7>;
+                       bias-disable;
+               };
+       };
+
+       mmc0_pins_default: mmc0-default-pins {
+               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>;
+                       input-enable;
+                       drive-strength = <6>;
+                       bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+               };
+
+               pins-clk {
+                       pinmux = <PINMUX_GPIO122__FUNC_MSDC0_CLK>;
+                       drive-strength = <6>;
+                       bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+               };
+
+               pins-rst {
+                       pinmux = <PINMUX_GPIO120__FUNC_MSDC0_RSTB>;
+                       drive-strength = <6>;
+                       bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+               };
+       };
+
+       mmc0_pins_uhs: mmc0-uhs-pins {
+               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>;
+                       input-enable;
+                       drive-strength = <8>;
+                       bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+               };
+
+               pins-clk {
+                       pinmux = <PINMUX_GPIO122__FUNC_MSDC0_CLK>;
+                       drive-strength = <8>;
+                       bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+               };
+
+               pins-ds {
+                       pinmux = <PINMUX_GPIO127__FUNC_MSDC0_DSL>;
+                       drive-strength = <8>;
+                       bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+               };
+
+               pins-rst {
+                       pinmux = <PINMUX_GPIO120__FUNC_MSDC0_RSTB>;
+                       drive-strength = <8>;
+                       bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+               };
+       };
+
+       nor_pins_default: nor-default-pins {
+               pins-ck-io {
+                       pinmux = <PINMUX_GPIO142__FUNC_SPINOR_IO0>,
+                                <PINMUX_GPIO141__FUNC_SPINOR_CK>,
+                                <PINMUX_GPIO143__FUNC_SPINOR_IO1>;
+                       drive-strength = <6>;
+                       bias-pull-down;
+               };
+
+               pins-cs {
+                       pinmux = <PINMUX_GPIO140__FUNC_SPINOR_CS>;
+                       drive-strength = <6>;
+                       bias-pull-up;
+               };
+       };
+
+       pio_default: pio-default-pins {
+               pins-wifi-enable {
+                       pinmux = <PINMUX_GPIO58__FUNC_GPIO58>;
+                       output-high;
+                       drive-strength = <14>;
+               };
+
+               pins-low-power-pd {
+                       pinmux = <PINMUX_GPIO25__FUNC_GPIO25>,
+                                <PINMUX_GPIO26__FUNC_GPIO26>,
+                                <PINMUX_GPIO46__FUNC_GPIO46>,
+                                <PINMUX_GPIO47__FUNC_GPIO47>,
+                                <PINMUX_GPIO48__FUNC_GPIO48>,
+                                <PINMUX_GPIO65__FUNC_GPIO65>,
+                                <PINMUX_GPIO66__FUNC_GPIO66>,
+                                <PINMUX_GPIO67__FUNC_GPIO67>,
+                                <PINMUX_GPIO68__FUNC_GPIO68>,
+                                <PINMUX_GPIO128__FUNC_GPIO128>,
+                                <PINMUX_GPIO129__FUNC_GPIO129>;
+                       input-enable;
+                       bias-pull-down;
+               };
+
+               pins-low-power-pupd {
+                       pinmux = <PINMUX_GPIO77__FUNC_GPIO77>,
+                                <PINMUX_GPIO78__FUNC_GPIO78>,
+                                <PINMUX_GPIO79__FUNC_GPIO79>,
+                                <PINMUX_GPIO80__FUNC_GPIO80>,
+                                <PINMUX_GPIO83__FUNC_GPIO83>,
+                                <PINMUX_GPIO85__FUNC_GPIO85>,
+                                <PINMUX_GPIO90__FUNC_GPIO90>,
+                                <PINMUX_GPIO91__FUNC_GPIO91>,
+                                <PINMUX_GPIO93__FUNC_GPIO93>,
+                                <PINMUX_GPIO94__FUNC_GPIO94>,
+                                <PINMUX_GPIO95__FUNC_GPIO95>,
+                                <PINMUX_GPIO96__FUNC_GPIO96>,
+                                <PINMUX_GPIO104__FUNC_GPIO104>,
+                                <PINMUX_GPIO105__FUNC_GPIO105>,
+                                <PINMUX_GPIO107__FUNC_GPIO107>;
+                       input-enable;
+                       bias-pull-down = <MTK_PUPD_SET_R1R0_01>;
+               };
+       };
+
+       spi0_pins: spi0-default-pins {
+               pins-cs-mosi-clk {
+                       pinmux = <PINMUX_GPIO132__FUNC_SPIM0_CSB>,
+                                <PINMUX_GPIO134__FUNC_SPIM0_MO>,
+                                <PINMUX_GPIO133__FUNC_SPIM0_CLK>;
+                       bias-disable;
+               };
+
+               pins-miso {
+                       pinmux = <PINMUX_GPIO135__FUNC_SPIM0_MI>;
+                       bias-pull-down;
+               };
+       };
+
+       subpmic_default: subpmic-default-pins {
+               subpmic_pin_irq: pins-subpmic-int-n {
+                       pinmux = <PINMUX_GPIO130__FUNC_GPIO130>;
+                       input-enable;
+                       bias-pull-up;
+               };
+       };
+
+       touchscreen_pins: touchscreen-default-pins {
+               pins-int-n {
+                       pinmux = <PINMUX_GPIO92__FUNC_GPIO92>;
+                       input-enable;
+                       bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+               };
+               pins-rst {
+                       pinmux = <PINMUX_GPIO56__FUNC_GPIO56>;
+                       output-high;
+               };
+               pins-report-sw {
+                       pinmux = <PINMUX_GPIO57__FUNC_GPIO57>;
+                       output-low;
+               };
+       };
+};
+
+&pmic {
+       interrupts-extended = <&pio 222 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&spi0 {
+       status = "okay";
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&spi0_pins>;
+       mediatek,pad-select = <0>;
+};
+
+&u3phy0 {
+       status = "okay";
+};
+
+&u3phy1 {
+       status = "okay";
+};
+
+&u3phy2 {
+       status = "okay";
+};
+
+&u3phy3 {
+       status = "okay";
+};
+
+&uart0 {
+       status = "okay";
+};
+
+&xhci0 {
+       status = "okay";
+
+       vusb33-supply = <&mt6359_vusb_ldo_reg>;
+       vbus-supply = <&usb_vbus>;
+};
+
+&xhci1 {
+       status = "okay";
+
+       vusb33-supply = <&mt6359_vusb_ldo_reg>;
+       vbus-supply = <&usb_vbus>;
+};
+
+&xhci2 {
+       status = "okay";
+
+       vusb33-supply = <&mt6359_vusb_ldo_reg>;
+       vbus-supply = <&usb_vbus>;
+};
+
+&xhci3 {
+       status = "okay";
+
+       /* MT7921's USB Bluetooth has issues with USB2 LPM */
+       usb2-lpm-disable;
+       vusb33-supply = <&mt6359_vusb_ldo_reg>;
+       vbus-supply = <&usb_vbus>;
+};
index db25a51..690dc77 100644 (file)
 };
 
 &u3phy0 {
-       status="okay";
+       status = "okay";
 };
 
 &u3phy1 {
-       status="okay";
+       status = "okay";
 };
 
 &u3phy2 {
-       status="okay";
+       status = "okay";
 };
 
 &u3phy3 {
-       status="okay";
+       status = "okay";
 };
 
 &uart0 {
index b57e620..066c149 100644 (file)
@@ -10,7 +10,6 @@
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/phy/phy.h>
 #include <dt-bindings/pinctrl/mt8195-pinfunc.h>
-#include <dt-bindings/reset/ti-syscon.h>
 
 / {
        compatible = "mediatek,mt8195";
                        compatible = "mediatek,mt8195-infracfg_ao", "syscon", "simple-mfd";
                        reg = <0 0x10001000 0 0x1000>;
                        #clock-cells = <1>;
-
-                       infracfg_rst: reset-controller {
-                               compatible = "ti,syscon-reset";
-                               #reset-cells = <1>;
-                               ti,reset-bits = <
-                                       0x140 18 0x144 18 0 0 (ASSERT_SET | DEASSERT_SET | STATUS_NONE) /* pcie */
-                                       0x120 0  0x124 0  0 0 (ASSERT_SET | DEASSERT_SET | STATUS_NONE) /* thermal */
-                                       0x730 10 0x734 10 0 0 (ASSERT_SET | DEASSERT_SET | STATUS_NONE) /* thermal */
-                                       0x150 5  0x154 5  0 0 (ASSERT_SET | DEASSERT_SET | STATUS_NONE) /* svs gpu */
-                               >;
-                       };
+                       #reset-cells = <1>;
                };
 
                pericfg: syscon@10003000 {
                                 <&apmixedsys CLK_APMIXED_USB1PLL>,
                                 <&infracfg_ao CLK_INFRA_AO_SSUSB_XHCI>;
                        clock-names = "sys_ck", "ref_ck", "mcu_ck", "xhci_ck";
+                       mediatek,syscon-wakeup = <&pericfg 0x400 103>;
+                       wakeup-source;
                        status = "disabled";
                };
 
                                 <&apmixedsys CLK_APMIXED_USB1PLL>,
                                 <&pericfg_ao CLK_PERI_AO_SSUSB_1P_XHCI>;
                        clock-names = "sys_ck", "ref_ck", "mcu_ck","xhci_ck";
+                       mediatek,syscon-wakeup = <&pericfg 0x400 104>;
+                       wakeup-source;
                        status = "disabled";
                };
 
                                 <&topckgen CLK_TOP_SSUSB_P2_REF>,
                                 <&pericfg_ao CLK_PERI_AO_SSUSB_2P_XHCI>;
                        clock-names = "sys_ck", "ref_ck", "xhci_ck";
+                       mediatek,syscon-wakeup = <&pericfg 0x400 105>;
+                       wakeup-source;
                        status = "disabled";
                };
 
                                 <&topckgen CLK_TOP_SSUSB_P3_REF>,
                                 <&pericfg_ao CLK_PERI_AO_SSUSB_3P_XHCI>;
                        clock-names = "sys_ck", "ref_ck", "xhci_ck";
+                       mediatek,syscon-wakeup = <&pericfg 0x400 106>;
+                       wakeup-source;
                        status = "disabled";
                };
 
                        status = "disabled";
                };
 
+               efuse: efuse@11c10000 {
+                       compatible = "mediatek,mt8195-efuse", "mediatek,efuse";
+                       reg = <0 0x11c10000 0 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       u3_tx_imp_p0: usb3-tx-imp@184,1 {
+                               reg = <0x184 0x1>;
+                               bits = <0 5>;
+                       };
+                       u3_rx_imp_p0: usb3-rx-imp@184,2 {
+                               reg = <0x184 0x2>;
+                               bits = <5 5>;
+                       };
+                       u3_intr_p0: usb3-intr@185 {
+                               reg = <0x185 0x1>;
+                               bits = <2 6>;
+                       };
+                       comb_tx_imp_p1: usb3-tx-imp@186,1 {
+                               reg = <0x186 0x1>;
+                               bits = <0 5>;
+                       };
+                       comb_rx_imp_p1: usb3-rx-imp@186,2 {
+                               reg = <0x186 0x2>;
+                               bits = <5 5>;
+                       };
+                       comb_intr_p1: usb3-intr@187 {
+                               reg = <0x187 0x1>;
+                               bits = <2 6>;
+                       };
+                       u2_intr_p0: usb2-intr-p0@188,1 {
+                               reg = <0x188 0x1>;
+                               bits = <0 5>;
+                       };
+                       u2_intr_p1: usb2-intr-p1@188,2 {
+                               reg = <0x188 0x2>;
+                               bits = <5 5>;
+                       };
+                       u2_intr_p2: usb2-intr-p2@189,1 {
+                               reg = <0x189 0x1>;
+                               bits = <2 5>;
+                       };
+                       u2_intr_p3: usb2-intr-p3@189,2 {
+                               reg = <0x189 0x2>;
+                               bits = <7 5>;
+                       };
+               };
+
                u3phy2: t-phy@11c40000 {
                        compatible = "mediatek,mt8195-tphy", "mediatek,generic-tphy-v3";
                        #address-cells = <1>;
                                clocks = <&apmixedsys CLK_APMIXED_PLL_SSUSB26M>,
                                         <&topckgen CLK_TOP_SSUSB_PHY_P1_REF>;
                                clock-names = "ref", "da_ref";
+                               nvmem-cells = <&comb_intr_p1>,
+                                             <&comb_rx_imp_p1>,
+                                             <&comb_tx_imp_p1>;
+                               nvmem-cell-names = "intr", "rx_imp", "tx_imp";
                                #phy-cells = <1>;
                        };
                };
                                clocks = <&apmixedsys CLK_APMIXED_PLL_SSUSB26M>,
                                         <&topckgen CLK_TOP_SSUSB_PHY_REF>;
                                clock-names = "ref", "da_ref";
+                               nvmem-cells = <&u3_intr_p0>,
+                                             <&u3_rx_imp_p0>,
+                                             <&u3_tx_imp_p0>;
+                               nvmem-cell-names = "intr", "rx_imp", "tx_imp";
                                #phy-cells = <1>;
                        };
                };
index 7a717f9..8ee1529 100644 (file)
@@ -28,7 +28,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&gpio_keys_default>;
 
-               volume-up {
+               key-volume-up {
                        gpios = <&pio 42 GPIO_ACTIVE_LOW>;
                        label = "volume_up";
                        linux,code = <115>;
@@ -36,7 +36,7 @@
                        debounce-interval = <15>;
                };
 
-               volume-down {
+               key-volume-down {
                        gpios = <&pio 43 GPIO_ACTIVE_LOW>;
                        label = "volume_down";
                        linux,code = <114>;
index 699256f..bf12be5 100644 (file)
 
 &axi {
        sfp_eth12: sfp-eth12 {
-               compatible       = "sff,sfp";
-               i2c-bus          = <&i2c_sfp1>;
+               compatible = "sff,sfp";
+               i2c-bus = <&i2c_sfp1>;
                tx-disable-gpios = <&sgpio_out2 11 1 GPIO_ACTIVE_LOW>;
-               los-gpios        = <&sgpio_in2 11 1 GPIO_ACTIVE_HIGH>;
-               mod-def0-gpios   = <&sgpio_in2 11 2 GPIO_ACTIVE_LOW>;
-               tx-fault-gpios   = <&sgpio_in2 12 0 GPIO_ACTIVE_HIGH>;
+               los-gpios = <&sgpio_in2 11 1 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpios = <&sgpio_in2 11 2 GPIO_ACTIVE_LOW>;
+               tx-fault-gpios = <&sgpio_in2 12 0 GPIO_ACTIVE_HIGH>;
        };
        sfp_eth13: sfp-eth13 {
-               compatible       = "sff,sfp";
-               i2c-bus          = <&i2c_sfp2>;
+               compatible = "sff,sfp";
+               i2c-bus = <&i2c_sfp2>;
                tx-disable-gpios = <&sgpio_out2 12 1 GPIO_ACTIVE_LOW>;
-               los-gpios        = <&sgpio_in2 12 1 GPIO_ACTIVE_HIGH>;
-               mod-def0-gpios   = <&sgpio_in2 12 2 GPIO_ACTIVE_LOW>;
-               tx-fault-gpios   = <&sgpio_in2 13 0 GPIO_ACTIVE_HIGH>;
+               los-gpios = <&sgpio_in2 12 1 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpios = <&sgpio_in2 12 2 GPIO_ACTIVE_LOW>;
+               tx-fault-gpios = <&sgpio_in2 13 0 GPIO_ACTIVE_HIGH>;
        };
        sfp_eth14: sfp-eth14 {
-               compatible       = "sff,sfp";
-               i2c-bus          = <&i2c_sfp3>;
+               compatible = "sff,sfp";
+               i2c-bus = <&i2c_sfp3>;
                tx-disable-gpios = <&sgpio_out2 13 1 GPIO_ACTIVE_LOW>;
-               los-gpios        = <&sgpio_in2 13 1 GPIO_ACTIVE_HIGH>;
-               mod-def0-gpios   = <&sgpio_in2 13 2 GPIO_ACTIVE_LOW>;
-               tx-fault-gpios   = <&sgpio_in2 14 0 GPIO_ACTIVE_HIGH>;
+               los-gpios = <&sgpio_in2 13 1 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpios = <&sgpio_in2 13 2 GPIO_ACTIVE_LOW>;
+               tx-fault-gpios = <&sgpio_in2 14 0 GPIO_ACTIVE_HIGH>;
        };
        sfp_eth15: sfp-eth15 {
-               compatible       = "sff,sfp";
-               i2c-bus          = <&i2c_sfp4>;
+               compatible = "sff,sfp";
+               i2c-bus = <&i2c_sfp4>;
                tx-disable-gpios = <&sgpio_out2 14 1 GPIO_ACTIVE_LOW>;
-               los-gpios        = <&sgpio_in2 14 1 GPIO_ACTIVE_HIGH>;
-               mod-def0-gpios   = <&sgpio_in2 14 2 GPIO_ACTIVE_LOW>;
-               tx-fault-gpios   = <&sgpio_in2 15 0 GPIO_ACTIVE_HIGH>;
+               los-gpios = <&sgpio_in2 14 1 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpios = <&sgpio_in2 14 2 GPIO_ACTIVE_LOW>;
+               tx-fault-gpios = <&sgpio_in2 15 0 GPIO_ACTIVE_HIGH>;
        };
        sfp_eth48: sfp-eth48 {
-               compatible       = "sff,sfp";
-               i2c-bus          = <&i2c_sfp5>;
+               compatible = "sff,sfp";
+               i2c-bus = <&i2c_sfp5>;
                tx-disable-gpios = <&sgpio_out2 15 1 GPIO_ACTIVE_LOW>;
-               los-gpios        = <&sgpio_in2 15 1 GPIO_ACTIVE_HIGH>;
-               mod-def0-gpios   = <&sgpio_in2 15 2 GPIO_ACTIVE_LOW>;
-               tx-fault-gpios   = <&sgpio_in2 16 0 GPIO_ACTIVE_HIGH>;
+               los-gpios = <&sgpio_in2 15 1 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpios = <&sgpio_in2 15 2 GPIO_ACTIVE_LOW>;
+               tx-fault-gpios = <&sgpio_in2 16 0 GPIO_ACTIVE_HIGH>;
        };
        sfp_eth49: sfp-eth49 {
-               compatible       = "sff,sfp";
-               i2c-bus          = <&i2c_sfp6>;
+               compatible = "sff,sfp";
+               i2c-bus = <&i2c_sfp6>;
                tx-disable-gpios = <&sgpio_out2 16 1 GPIO_ACTIVE_LOW>;
-               los-gpios        = <&sgpio_in2 16 1 GPIO_ACTIVE_HIGH>;
-               mod-def0-gpios   = <&sgpio_in2 16 2 GPIO_ACTIVE_LOW>;
-               tx-fault-gpios   = <&sgpio_in2 17 0 GPIO_ACTIVE_HIGH>;
+               los-gpios = <&sgpio_in2 16 1 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpios = <&sgpio_in2 16 2 GPIO_ACTIVE_LOW>;
+               tx-fault-gpios = <&sgpio_in2 17 0 GPIO_ACTIVE_HIGH>;
        };
        sfp_eth50: sfp-eth50 {
-               compatible       = "sff,sfp";
-               i2c-bus          = <&i2c_sfp7>;
+               compatible = "sff,sfp";
+               i2c-bus = <&i2c_sfp7>;
                tx-disable-gpios = <&sgpio_out2 17 1 GPIO_ACTIVE_LOW>;
-               los-gpios        = <&sgpio_in2 17 1 GPIO_ACTIVE_HIGH>;
-               mod-def0-gpios   = <&sgpio_in2 17 2 GPIO_ACTIVE_LOW>;
-               tx-fault-gpios   = <&sgpio_in2 18 0 GPIO_ACTIVE_HIGH>;
+               los-gpios = <&sgpio_in2 17 1 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpios = <&sgpio_in2 17 2 GPIO_ACTIVE_LOW>;
+               tx-fault-gpios = <&sgpio_in2 18 0 GPIO_ACTIVE_HIGH>;
        };
        sfp_eth51: sfp-eth51 {
-               compatible       = "sff,sfp";
-               i2c-bus          = <&i2c_sfp8>;
+               compatible = "sff,sfp";
+               i2c-bus = <&i2c_sfp8>;
                tx-disable-gpios = <&sgpio_out2 18 1 GPIO_ACTIVE_LOW>;
-               los-gpios        = <&sgpio_in2 18 1 GPIO_ACTIVE_HIGH>;
-               mod-def0-gpios   = <&sgpio_in2 18 2 GPIO_ACTIVE_LOW>;
-               tx-fault-gpios   = <&sgpio_in2 19 0 GPIO_ACTIVE_HIGH>;
+               los-gpios = <&sgpio_in2 18 1 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpios = <&sgpio_in2 18 2 GPIO_ACTIVE_LOW>;
+               tx-fault-gpios = <&sgpio_in2 19 0 GPIO_ACTIVE_HIGH>;
        };
        sfp_eth52: sfp-eth52 {
-               compatible       = "sff,sfp";
-               i2c-bus          = <&i2c_sfp9>;
+               compatible = "sff,sfp";
+               i2c-bus = <&i2c_sfp9>;
                tx-disable-gpios = <&sgpio_out2 19 1 GPIO_ACTIVE_LOW>;
-               los-gpios        = <&sgpio_in2 19 1 GPIO_ACTIVE_HIGH>;
-               mod-def0-gpios   = <&sgpio_in2 19 2 GPIO_ACTIVE_LOW>;
-               tx-fault-gpios   = <&sgpio_in2 20 0 GPIO_ACTIVE_HIGH>;
+               los-gpios = <&sgpio_in2 19 1 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpios = <&sgpio_in2 19 2 GPIO_ACTIVE_LOW>;
+               tx-fault-gpios = <&sgpio_in2 20 0 GPIO_ACTIVE_HIGH>;
        };
        sfp_eth53: sfp-eth53 {
-               compatible       = "sff,sfp";
-               i2c-bus          = <&i2c_sfp10>;
+               compatible = "sff,sfp";
+               i2c-bus = <&i2c_sfp10>;
                tx-disable-gpios = <&sgpio_out2 20 1 GPIO_ACTIVE_LOW>;
-               los-gpios        = <&sgpio_in2 20 1 GPIO_ACTIVE_HIGH>;
-               mod-def0-gpios   = <&sgpio_in2 20 2 GPIO_ACTIVE_LOW>;
-               tx-fault-gpios   = <&sgpio_in2 21 0 GPIO_ACTIVE_HIGH>;
+               los-gpios = <&sgpio_in2 20 1 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpios = <&sgpio_in2 20 2 GPIO_ACTIVE_LOW>;
+               tx-fault-gpios = <&sgpio_in2 21 0 GPIO_ACTIVE_HIGH>;
        };
        sfp_eth54: sfp-eth54 {
-               compatible       = "sff,sfp";
-               i2c-bus          = <&i2c_sfp11>;
+               compatible = "sff,sfp";
+               i2c-bus = <&i2c_sfp11>;
                tx-disable-gpios = <&sgpio_out2 21 1 GPIO_ACTIVE_LOW>;
-               los-gpios        = <&sgpio_in2 21 1 GPIO_ACTIVE_HIGH>;
-               mod-def0-gpios   = <&sgpio_in2 21 2 GPIO_ACTIVE_LOW>;
-               tx-fault-gpios   = <&sgpio_in2 22 0 GPIO_ACTIVE_HIGH>;
+               los-gpios = <&sgpio_in2 21 1 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpios = <&sgpio_in2 21 2 GPIO_ACTIVE_LOW>;
+               tx-fault-gpios = <&sgpio_in2 22 0 GPIO_ACTIVE_HIGH>;
        };
        sfp_eth55: sfp-eth55 {
-               compatible       = "sff,sfp";
-               i2c-bus          = <&i2c_sfp12>;
+               compatible = "sff,sfp";
+               i2c-bus = <&i2c_sfp12>;
                tx-disable-gpios = <&sgpio_out2 22 1 GPIO_ACTIVE_LOW>;
-               los-gpios        = <&sgpio_in2 22 1 GPIO_ACTIVE_HIGH>;
-               mod-def0-gpios   = <&sgpio_in2 22 2 GPIO_ACTIVE_LOW>;
-               tx-fault-gpios   = <&sgpio_in2 23 0 GPIO_ACTIVE_HIGH>;
+               los-gpios = <&sgpio_in2 22 1 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpios = <&sgpio_in2 22 2 GPIO_ACTIVE_LOW>;
+               tx-fault-gpios = <&sgpio_in2 23 0 GPIO_ACTIVE_HIGH>;
        };
        sfp_eth56: sfp-eth56 {
-               compatible       = "sff,sfp";
-               i2c-bus          = <&i2c_sfp13>;
+               compatible = "sff,sfp";
+               i2c-bus = <&i2c_sfp13>;
                tx-disable-gpios = <&sgpio_out2 23 1 GPIO_ACTIVE_LOW>;
-               los-gpios        = <&sgpio_in2 23 1 GPIO_ACTIVE_HIGH>;
-               mod-def0-gpios   = <&sgpio_in2 23 2 GPIO_ACTIVE_LOW>;
-               tx-fault-gpios   = <&sgpio_in2 24 0 GPIO_ACTIVE_HIGH>;
+               los-gpios = <&sgpio_in2 23 1 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpios = <&sgpio_in2 23 2 GPIO_ACTIVE_LOW>;
+               tx-fault-gpios = <&sgpio_in2 24 0 GPIO_ACTIVE_HIGH>;
        };
        sfp_eth57: sfp-eth57 {
-               compatible       = "sff,sfp";
-               i2c-bus          = <&i2c_sfp14>;
+               compatible = "sff,sfp";
+               i2c-bus = <&i2c_sfp14>;
                tx-disable-gpios = <&sgpio_out2 24 1 GPIO_ACTIVE_LOW>;
-               los-gpios        = <&sgpio_in2 24 1 GPIO_ACTIVE_HIGH>;
-               mod-def0-gpios   = <&sgpio_in2 24 2 GPIO_ACTIVE_LOW>;
-               tx-fault-gpios   = <&sgpio_in2 25 0 GPIO_ACTIVE_HIGH>;
+               los-gpios = <&sgpio_in2 24 1 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpios = <&sgpio_in2 24 2 GPIO_ACTIVE_LOW>;
+               tx-fault-gpios = <&sgpio_in2 25 0 GPIO_ACTIVE_HIGH>;
        };
        sfp_eth58: sfp-eth58 {
-               compatible       = "sff,sfp";
-               i2c-bus          = <&i2c_sfp15>;
+               compatible = "sff,sfp";
+               i2c-bus = <&i2c_sfp15>;
                tx-disable-gpios = <&sgpio_out2 25 1 GPIO_ACTIVE_LOW>;
-               los-gpios        = <&sgpio_in2 25 1 GPIO_ACTIVE_HIGH>;
-               mod-def0-gpios   = <&sgpio_in2 25 2 GPIO_ACTIVE_LOW>;
-               tx-fault-gpios   = <&sgpio_in2 26 0 GPIO_ACTIVE_HIGH>;
+               los-gpios = <&sgpio_in2 25 1 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpios = <&sgpio_in2 25 2 GPIO_ACTIVE_LOW>;
+               tx-fault-gpios = <&sgpio_in2 26 0 GPIO_ACTIVE_HIGH>;
        };
        sfp_eth59: sfp-eth59 {
-               compatible       = "sff,sfp";
-               i2c-bus          = <&i2c_sfp16>;
+               compatible = "sff,sfp";
+               i2c-bus = <&i2c_sfp16>;
                tx-disable-gpios = <&sgpio_out2 26 1 GPIO_ACTIVE_LOW>;
-               los-gpios        = <&sgpio_in2 26 1 GPIO_ACTIVE_HIGH>;
-               mod-def0-gpios   = <&sgpio_in2 26 2 GPIO_ACTIVE_LOW>;
-               tx-fault-gpios   = <&sgpio_in2 27 0 GPIO_ACTIVE_HIGH>;
+               los-gpios = <&sgpio_in2 26 1 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpios = <&sgpio_in2 26 2 GPIO_ACTIVE_LOW>;
+               tx-fault-gpios = <&sgpio_in2 27 0 GPIO_ACTIVE_HIGH>;
        };
        sfp_eth60: sfp-eth60 {
-               compatible       = "sff,sfp";
-               i2c-bus          = <&i2c_sfp17>;
+               compatible = "sff,sfp";
+               i2c-bus = <&i2c_sfp17>;
                tx-disable-gpios = <&sgpio_out2 27 1 GPIO_ACTIVE_LOW>;
-               los-gpios        = <&sgpio_in2 27 1 GPIO_ACTIVE_HIGH>;
-               mod-def0-gpios   = <&sgpio_in2 27 2 GPIO_ACTIVE_LOW>;
-               tx-fault-gpios   = <&sgpio_in2 28 0 GPIO_ACTIVE_HIGH>;
+               los-gpios = <&sgpio_in2 27 1 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpios = <&sgpio_in2 27 2 GPIO_ACTIVE_LOW>;
+               tx-fault-gpios = <&sgpio_in2 28 0 GPIO_ACTIVE_HIGH>;
        };
        sfp_eth61: sfp-eth61 {
-               compatible       = "sff,sfp";
-               i2c-bus          = <&i2c_sfp18>;
+               compatible = "sff,sfp";
+               i2c-bus = <&i2c_sfp18>;
                tx-disable-gpios = <&sgpio_out2 28 1 GPIO_ACTIVE_LOW>;
-               los-gpios        = <&sgpio_in2 28 1 GPIO_ACTIVE_HIGH>;
-               mod-def0-gpios   = <&sgpio_in2 28 2 GPIO_ACTIVE_LOW>;
-               tx-fault-gpios   = <&sgpio_in2 29 0 GPIO_ACTIVE_HIGH>;
+               los-gpios = <&sgpio_in2 28 1 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpios = <&sgpio_in2 28 2 GPIO_ACTIVE_LOW>;
+               tx-fault-gpios = <&sgpio_in2 29 0 GPIO_ACTIVE_HIGH>;
        };
        sfp_eth62: sfp-eth62 {
-               compatible       = "sff,sfp";
-               i2c-bus          = <&i2c_sfp19>;
+               compatible = "sff,sfp";
+               i2c-bus = <&i2c_sfp19>;
                tx-disable-gpios = <&sgpio_out2 29 1 GPIO_ACTIVE_LOW>;
-               los-gpios        = <&sgpio_in2 29 1 GPIO_ACTIVE_HIGH>;
-               mod-def0-gpios   = <&sgpio_in2 29 2 GPIO_ACTIVE_LOW>;
-               tx-fault-gpios   = <&sgpio_in2 30 0 GPIO_ACTIVE_HIGH>;
+               los-gpios = <&sgpio_in2 29 1 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpios = <&sgpio_in2 29 2 GPIO_ACTIVE_LOW>;
+               tx-fault-gpios = <&sgpio_in2 30 0 GPIO_ACTIVE_HIGH>;
        };
        sfp_eth63: sfp-eth63 {
-               compatible       = "sff,sfp";
-               i2c-bus          = <&i2c_sfp20>;
+               compatible = "sff,sfp";
+               i2c-bus = <&i2c_sfp20>;
                tx-disable-gpios = <&sgpio_out2 30 1 GPIO_ACTIVE_LOW>;
-               los-gpios        = <&sgpio_in2 30 1 GPIO_ACTIVE_HIGH>;
-               mod-def0-gpios   = <&sgpio_in2 30 2 GPIO_ACTIVE_LOW>;
-               tx-fault-gpios   = <&sgpio_in2 31 0 GPIO_ACTIVE_HIGH>;
+               los-gpios = <&sgpio_in2 30 1 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpios = <&sgpio_in2 30 2 GPIO_ACTIVE_LOW>;
+               tx-fault-gpios = <&sgpio_in2 31 0 GPIO_ACTIVE_HIGH>;
        };
 };
 
index d10a917..ec90bda 100644 (file)
 
 &axi {
        sfp_eth60: sfp-eth60 {
-               compatible         = "sff,sfp";
-               i2c-bus            = <&i2c_sfp1>;
-               tx-disable-gpios   = <&sgpio_out2 28 0 GPIO_ACTIVE_LOW>;
+               compatible       = "sff,sfp";
+               i2c-bus = <&i2c_sfp1>;
+               tx-disable-gpios = <&sgpio_out2 28 0 GPIO_ACTIVE_LOW>;
                rate-select0-gpios = <&sgpio_out2 28 1 GPIO_ACTIVE_HIGH>;
-               los-gpios          = <&sgpio_in2 28 0 GPIO_ACTIVE_HIGH>;
-               mod-def0-gpios     = <&sgpio_in2 28 1 GPIO_ACTIVE_LOW>;
-               tx-fault-gpios     = <&sgpio_in2 28 2 GPIO_ACTIVE_HIGH>;
+               los-gpios = <&sgpio_in2 28 0 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpios = <&sgpio_in2 28 1 GPIO_ACTIVE_LOW>;
+               tx-fault-gpios = <&sgpio_in2 28 2 GPIO_ACTIVE_HIGH>;
        };
        sfp_eth61: sfp-eth61 {
-               compatible         = "sff,sfp";
-               i2c-bus            = <&i2c_sfp2>;
-               tx-disable-gpios   = <&sgpio_out2 29 0 GPIO_ACTIVE_LOW>;
+               compatible = "sff,sfp";
+               i2c-bus = <&i2c_sfp2>;
+               tx-disable-gpios = <&sgpio_out2 29 0 GPIO_ACTIVE_LOW>;
                rate-select0-gpios = <&sgpio_out2 29 1 GPIO_ACTIVE_HIGH>;
-               los-gpios          = <&sgpio_in2 29 0 GPIO_ACTIVE_HIGH>;
-               mod-def0-gpios     = <&sgpio_in2 29 1 GPIO_ACTIVE_LOW>;
-               tx-fault-gpios     = <&sgpio_in2 29 2 GPIO_ACTIVE_HIGH>;
+               los-gpios = <&sgpio_in2 29 0 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpios = <&sgpio_in2 29 1 GPIO_ACTIVE_LOW>;
+               tx-fault-gpios = <&sgpio_in2 29 2 GPIO_ACTIVE_HIGH>;
        };
        sfp_eth62: sfp-eth62 {
-               compatible         = "sff,sfp";
-               i2c-bus            = <&i2c_sfp3>;
-               tx-disable-gpios   = <&sgpio_out2 30 0 GPIO_ACTIVE_LOW>;
+               compatible = "sff,sfp";
+               i2c-bus = <&i2c_sfp3>;
+               tx-disable-gpios = <&sgpio_out2 30 0 GPIO_ACTIVE_LOW>;
                rate-select0-gpios = <&sgpio_out2 30 1 GPIO_ACTIVE_HIGH>;
-               los-gpios          = <&sgpio_in2 30 0 GPIO_ACTIVE_HIGH>;
-               mod-def0-gpios     = <&sgpio_in2 30 1 GPIO_ACTIVE_LOW>;
-               tx-fault-gpios     = <&sgpio_in2 30 2 GPIO_ACTIVE_HIGH>;
+               los-gpios = <&sgpio_in2 30 0 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpios = <&sgpio_in2 30 1 GPIO_ACTIVE_LOW>;
+               tx-fault-gpios = <&sgpio_in2 30 2 GPIO_ACTIVE_HIGH>;
        };
        sfp_eth63: sfp-eth63 {
-               compatible         = "sff,sfp";
-               i2c-bus            = <&i2c_sfp4>;
-               tx-disable-gpios   = <&sgpio_out2 31 0 GPIO_ACTIVE_LOW>;
+               compatible = "sff,sfp";
+               i2c-bus = <&i2c_sfp4>;
+               tx-disable-gpios = <&sgpio_out2 31 0 GPIO_ACTIVE_LOW>;
                rate-select0-gpios = <&sgpio_out2 31 1 GPIO_ACTIVE_HIGH>;
-               los-gpios          = <&sgpio_in2 31 0 GPIO_ACTIVE_HIGH>;
-               mod-def0-gpios     = <&sgpio_in2 31 1 GPIO_ACTIVE_LOW>;
-               tx-fault-gpios     = <&sgpio_in2 31 2 GPIO_ACTIVE_HIGH>;
+               los-gpios = <&sgpio_in2 31 0 GPIO_ACTIVE_HIGH>;
+               mod-def0-gpios = <&sgpio_in2 31 1 GPIO_ACTIVE_LOW>;
+               tx-fault-gpios = <&sgpio_in2 31 2 GPIO_ACTIVE_HIGH>;
        };
 };
 
diff --git a/arch/arm64/boot/dts/nuvoton/Makefile b/arch/arm64/boot/dts/nuvoton/Makefile
new file mode 100644 (file)
index 0000000..a99dab9
--- /dev/null
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+dtb-$(CONFIG_ARCH_NPCM) += nuvoton-npcm845-evb.dtb
diff --git a/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi b/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi
new file mode 100644 (file)
index 0000000..aa7aac8
--- /dev/null
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2021 Nuvoton Technology tomer.maimon@nuvoton.com
+
+#include <dt-bindings/clock/nuvoton,npcm845-clk.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+       #address-cells = <2>;
+       #size-cells = <2>;
+       interrupt-parent = <&gic>;
+
+       soc {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               compatible = "simple-bus";
+               interrupt-parent = <&gic>;
+               ranges;
+
+               gcr: system-controller@f0800000 {
+                       compatible = "nuvoton,npcm845-gcr", "syscon";
+                       reg = <0x0 0xf0800000 0x0 0x1000>;
+               };
+
+               gic: interrupt-controller@dfff9000 {
+                       compatible = "arm,gic-400";
+                       reg = <0x0 0xdfff9000 0x0 0x1000>,
+                             <0x0 0xdfffa000 0x0 0x2000>,
+                             <0x0 0xdfffc000 0x0 0x2000>,
+                             <0x0 0xdfffe000 0x0 0x2000>;
+                       interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+                       #interrupt-cells = <3>;
+                       interrupt-controller;
+                       #address-cells = <0>;
+                       ppi-partitions {
+                               ppi_cluster0: interrupt-partition-0 {
+                                       affinity = <&cpu0 &cpu1 &cpu2 &cpu3>;
+                               };
+                       };
+               };
+       };
+
+       ahb {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               compatible = "simple-bus";
+               interrupt-parent = <&gic>;
+               ranges;
+
+               rstc: reset-controller@f0801000 {
+                       compatible = "nuvoton,npcm845-reset";
+                       reg = <0x0 0xf0801000 0x0 0x78>;
+                       #reset-cells = <2>;
+                       nuvoton,sysgcr = <&gcr>;
+               };
+
+               clk: clock-controller@f0801000 {
+                       compatible = "nuvoton,npcm845-clk";
+                       #clock-cells = <1>;
+                       reg = <0x0 0xf0801000 0x0 0x1000>;
+               };
+
+               apb {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "simple-bus";
+                       interrupt-parent = <&gic>;
+                       ranges = <0x0 0x0 0xf0000000 0x00300000>,
+                               <0xfff00000 0x0 0xfff00000 0x00016000>;
+
+                       timer0: timer@8000 {
+                               compatible = "nuvoton,npcm845-timer";
+                               interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+                               reg = <0x8000 0x1C>;
+                               clocks = <&clk NPCM8XX_CLK_REFCLK>;
+                               clock-names = "refclk";
+                       };
+
+                       serial0: serial@0 {
+                               compatible = "nuvoton,npcm845-uart", "nuvoton,npcm750-uart";
+                               reg = <0x0 0x1000>;
+                               clocks = <&clk NPCM8XX_CLK_UART>;
+                               interrupts = <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>;
+                               reg-shift = <2>;
+                               status = "disabled";
+                       };
+
+                       serial1: serial@1000 {
+                               compatible = "nuvoton,npcm845-uart", "nuvoton,npcm750-uart";
+                               reg = <0x1000 0x1000>;
+                               clocks = <&clk NPCM8XX_CLK_UART>;
+                               interrupts = <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>;
+                               reg-shift = <2>;
+                               status = "disabled";
+                       };
+
+                       serial2: serial@2000 {
+                               compatible = "nuvoton,npcm845-uart", "nuvoton,npcm750-uart";
+                               reg = <0x2000 0x1000>;
+                               clocks = <&clk NPCM8XX_CLK_UART>;
+                               interrupts = <GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>;
+                               reg-shift = <2>;
+                               status = "disabled";
+                       };
+
+                       serial3: serial@3000 {
+                               compatible = "nuvoton,npcm845-uart", "nuvoton,npcm750-uart";
+                               reg = <0x3000 0x1000>;
+                               clocks = <&clk NPCM8XX_CLK_UART>;
+                               interrupts = <GIC_SPI 195 IRQ_TYPE_LEVEL_HIGH>;
+                               reg-shift = <2>;
+                               status = "disabled";
+                       };
+
+                       serial4: serial@4000 {
+                               compatible = "nuvoton,npcm845-uart", "nuvoton,npcm750-uart";
+                               reg = <0x4000 0x1000>;
+                               clocks = <&clk NPCM8XX_CLK_UART>;
+                               interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>;
+                               reg-shift = <2>;
+                               status = "disabled";
+                       };
+
+                       serial5: serial@5000 {
+                               compatible = "nuvoton,npcm845-uart", "nuvoton,npcm750-uart";
+                               reg = <0x5000 0x1000>;
+                               clocks = <&clk NPCM8XX_CLK_UART>;
+                               interrupts = <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>;
+                               reg-shift = <2>;
+                               status = "disabled";
+                       };
+
+                       serial6: serial@6000 {
+                               compatible = "nuvoton,npcm845-uart", "nuvoton,npcm750-uart";
+                               reg = <0x6000 0x1000>;
+                               clocks = <&clk NPCM8XX_CLK_UART>;
+                               interrupts = <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>;
+                               reg-shift = <2>;
+                               status = "disabled";
+                       };
+
+                       watchdog0: watchdog@801c {
+                               compatible = "nuvoton,npcm845-wdt", "nuvoton,npcm750-wdt";
+                               interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
+                               reg = <0x801c 0x4>;
+                               status = "disabled";
+                               clocks = <&clk NPCM8XX_CLK_REFCLK>;
+                               syscon = <&gcr>;
+                       };
+
+                       watchdog1: watchdog@901c {
+                               compatible = "nuvoton,npcm845-wdt", "nuvoton,npcm750-wdt";
+                               interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+                               reg = <0x901c 0x4>;
+                               status = "disabled";
+                               clocks = <&clk NPCM8XX_CLK_REFCLK>;
+                               syscon = <&gcr>;
+                       };
+
+                       watchdog2: watchdog@a01c {
+                               compatible = "nuvoton,npcm845-wdt", "nuvoton,npcm750-wdt";
+                               interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+                               reg = <0xa01c 0x4>;
+                               status = "disabled";
+                               clocks = <&clk NPCM8XX_CLK_REFCLK>;
+                               syscon = <&gcr>;
+                       };
+               };
+       };
+};
diff --git a/arch/arm64/boot/dts/nuvoton/nuvoton-npcm845-evb.dts b/arch/arm64/boot/dts/nuvoton/nuvoton-npcm845-evb.dts
new file mode 100644 (file)
index 0000000..a5ab2bc
--- /dev/null
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2021 Nuvoton Technology tomer.maimon@nuvoton.com
+
+/dts-v1/;
+#include "nuvoton-npcm845.dtsi"
+
+/ {
+       model = "Nuvoton npcm845 Development Board (Device Tree)";
+       compatible = "nuvoton,npcm845-evb", "nuvoton,npcm845";
+
+       aliases {
+               serial0 = &serial0;
+       };
+
+       chosen {
+               stdout-path = &serial0;
+       };
+
+       memory {
+               reg = <0x0 0x0 0x0 0x40000000>;
+       };
+};
+
+&serial0 {
+       status = "okay";
+};
+
+&watchdog1 {
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/nuvoton/nuvoton-npcm845.dtsi b/arch/arm64/boot/dts/nuvoton/nuvoton-npcm845.dtsi
new file mode 100644 (file)
index 0000000..12118b7
--- /dev/null
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2021 Nuvoton Technology tomer.maimon@nuvoton.com
+
+#include "nuvoton-common-npcm8xx.dtsi"
+
+/ {
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       cpus {
+               #address-cells = <2>;
+               #size-cells = <0>;
+
+               cpu0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a35";
+                       clocks = <&clk NPCM8XX_CLK_CPU>;
+                       reg = <0x0 0x0>;
+                       next-level-cache = <&l2>;
+                       enable-method = "psci";
+               };
+
+               cpu1: cpu@1 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a35";
+                       clocks = <&clk NPCM8XX_CLK_CPU>;
+                       reg = <0x0 0x1>;
+                       next-level-cache = <&l2>;
+                       enable-method = "psci";
+               };
+
+               cpu2: cpu@2 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a35";
+                       clocks = <&clk NPCM8XX_CLK_CPU>;
+                       reg = <0x0 0x2>;
+                       next-level-cache = <&l2>;
+                       enable-method = "psci";
+               };
+
+               cpu3: cpu@3 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a35";
+                       clocks = <&clk NPCM8XX_CLK_CPU>;
+                       reg = <0x0 0x3>;
+                       next-level-cache = <&l2>;
+                       enable-method = "psci";
+               };
+
+               l2: l2-cache {
+                       compatible = "cache";
+               };
+       };
+
+       arm-pmu {
+               compatible = "arm,cortex-a35-pmu";
+               interrupts = <GIC_SPI 242 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 243 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 244 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
+       };
+
+       psci {
+               compatible      = "arm,psci-1.0";
+               method          = "smc";
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+       };
+};
index f16acb4..d461da0 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               lid {
+               switch-lid {
                        label = "Lid";
                        gpios = <&gpio TEGRA_GPIO(R, 4) GPIO_ACTIVE_LOW>;
                        linux,input-type = <5>;
                        wakeup-source;
                };
 
-               power {
+               key-power {
                        label = "Power";
                        gpios = <&gpio TEGRA_GPIO(Q, 0) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
index 70737a0..47cf201 100644 (file)
                                                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>;
+                                       };
+                               };
                        };
 
                        admaif@290f000 {
                                };
                        };
 
+                       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>;
+                                               };
+                                       };
+                               };
+                       };
+
                        amixer@290bb00 {
                                status = "okay";
 
        gpio-keys {
                compatible = "gpio-keys";
 
-               power {
+               key-power {
                        label = "Power";
                        gpios = <&gpio_aon TEGRA186_AON_GPIO(FF, 0)
                                           GPIO_ACTIVE_LOW>;
                        wakeup-source;
                };
 
-               volume-up {
+               key-volume-up {
                        label = "Volume Up";
                        gpios = <&gpio_aon TEGRA186_AON_GPIO(FF, 1)
                                           GPIO_ACTIVE_LOW>;
                        debounce-interval = <10>;
                };
 
-               volume-down {
+               key-volume-down {
                        label = "Volume Down";
                        gpios = <&gpio_aon TEGRA186_AON_GPIO(FF, 2)
                                           GPIO_ACTIVE_LOW>;
                       <&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>,
                       <&mixer_out5_port>,
                       <&asrc_out1_port>, <&asrc_out2_port>, <&asrc_out3_port>,
                       <&asrc_out4_port>, <&asrc_out5_port>, <&asrc_out6_port>,
+                      <&ope1_out_port>,
                       /* I/O */
                       <&i2s1_port>, <&i2s2_port>, <&i2s3_port>, <&i2s4_port>,
                       <&i2s5_port>, <&i2s6_port>, <&dmic1_port>, <&dmic2_port>,
index 7e9aad9..3e83a4d 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               power {
+               key-power {
                        label = "Power";
                        gpios = <&gpio_aon TEGRA186_AON_GPIO(FF, 0)
                                           GPIO_ACTIVE_LOW>;
                        wakeup-source;
                };
 
-               volume-up {
+               key-volume-up {
                        label = "Volume Up";
                        gpios = <&gpio_aon TEGRA186_AON_GPIO(FF, 1)
                                           GPIO_ACTIVE_LOW>;
                        debounce-interval = <10>;
                };
 
-               volume-down {
+               key-volume-down {
                        label = "Volume Down";
                        gpios = <&gpio_aon TEGRA186_AON_GPIO(FF, 2)
                                           GPIO_ACTIVE_LOW>;
index 0e9afc3..59a10fb 100644 (file)
                                status = "disabled";
                        };
 
+                       tegra_ope1: processing-engine@2908000 {
+                               compatible = "nvidia,tegra186-ope",
+                                            "nvidia,tegra210-ope";
+                               reg = <0x2908000 0x100>;
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                               ranges;
+                               sound-name-prefix = "OPE1";
+                               status = "disabled";
+
+                               equalizer@2908100 {
+                                       compatible = "nvidia,tegra186-peq",
+                                                    "nvidia,tegra210-peq";
+                                       reg = <0x2908100 0x100>;
+                               };
+
+                               dynamic-range-compressor@2908200 {
+                                       compatible = "nvidia,tegra186-mbdrc",
+                                                    "nvidia,tegra210-mbdrc";
+                                       reg = <0x2908200 0x200>;
+                               };
+                       };
+
                        tegra_amixer: amixer@290bb00 {
                                compatible = "nvidia,tegra186-amixer",
                                             "nvidia,tegra210-amixer";
                             <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
-               status = "disabled";
+               status = "okay";
        };
 
        uarta: serial@3100000 {
 
                iommus = <&smmu TEGRA186_SID_HOST1X>;
 
+               /* Context isolation domains */
+               iommu-map = <
+                       0 &smmu TEGRA186_SID_HOST1X_CTX0 1
+                       1 &smmu TEGRA186_SID_HOST1X_CTX1 1
+                       2 &smmu TEGRA186_SID_HOST1X_CTX2 1
+                       3 &smmu TEGRA186_SID_HOST1X_CTX3 1
+                       4 &smmu TEGRA186_SID_HOST1X_CTX4 1
+                       5 &smmu TEGRA186_SID_HOST1X_CTX5 1
+                       6 &smmu TEGRA186_SID_HOST1X_CTX6 1
+                       7 &smmu TEGRA186_SID_HOST1X_CTX7 1>;
+
                dpaux1: dpaux@15040000 {
                        compatible = "nvidia,tegra186-dpaux";
                        reg = <0x15040000 0x10000>;
                #address-cells = <1>;
                #size-cells = <1>;
                ranges = <0x0 0x0 0x30000000 0x50000>;
+               no-memory-wc;
 
                cpu_bpmp_tx: sram@4e000 {
                        reg = <0x4e000 0x1000>;
index a7d7cfd..b0f9393 100644 (file)
@@ -75,7 +75,7 @@
 
                /* SDMMC1 (SD/MMC) */
                mmc@3400000 {
-                       cd-gpios = <&gpio TEGRA194_MAIN_GPIO(A, 0) GPIO_ACTIVE_LOW>;
+                       cd-gpios = <&gpio TEGRA194_MAIN_GPIO(G, 7) GPIO_ACTIVE_LOW>;
                };
 
                /* SDMMC4 (eMMC) */
index bce518a..bc1041d 100644 (file)
                                                        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>;
+                                               };
+                                       };
                                };
 
                                admaif@290f000 {
                                        };
                                };
 
+                               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>;
+                                                       };
+                                               };
+                                       };
+                               };
+
                                amixer@290bb00 {
                                        status = "okay";
 
        gpio-keys {
                compatible = "gpio-keys";
 
-               force-recovery {
+               key-force-recovery {
                        label = "Force Recovery";
                        gpios = <&gpio TEGRA194_MAIN_GPIO(G, 0)
                                       GPIO_ACTIVE_LOW>;
                        debounce-interval = <10>;
                };
 
-               power {
+               key-power {
                        label = "Power";
                        gpios = <&gpio_aon TEGRA194_AON_GPIO(EE, 4)
                                           GPIO_ACTIVE_LOW>;
                       <&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>,
                       <&mixer_out4_port>, <&mixer_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 */
                       <&i2s1_port>, <&i2s2_port>, <&i2s4_port>, <&i2s6_port>,
                       <&dmic3_port>;
index 7acc32d..273a1ef 100644 (file)
                                                        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>;
+                                               };
+                                       };
                                };
 
                                admaif@290f000 {
                                        };
                                };
 
+                               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>;
+                                                       };
+                                               };
+                                       };
+                               };
+
                                amixer@290bb00 {
                                        status = "okay";
 
        gpio-keys {
                compatible = "gpio-keys";
 
-               force-recovery {
+               key-force-recovery {
                        label = "Force Recovery";
                        gpios = <&gpio TEGRA194_MAIN_GPIO(G, 0)
                                       GPIO_ACTIVE_LOW>;
                        debounce-interval = <10>;
                };
 
-               power {
+               key-power {
                        label = "Power";
                        gpios = <&gpio_aon TEGRA194_AON_GPIO(EE, 4)
                                           GPIO_ACTIVE_LOW>;
                       <&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>,
                       <&mixer_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 */
                       <&i2s3_port>, <&i2s5_port>,
                       <&dmic1_port>, <&dmic2_port>, <&dmic4_port>,
index d1f8248..d0ed55e 100644 (file)
@@ -23,7 +23,7 @@
                #size-cells = <1>;
                ranges = <0x0 0x0 0x0 0x40000000>;
 
-               misc@100000 {
+               apbmisc: misc@100000 {
                        compatible = "nvidia,tegra194-misc";
                        reg = <0x00100000 0xf000>,
                              <0x0010f000 0x1000>;
                        gpio-controller;
                };
 
+               cbb-noc@2300000 {
+                       compatible = "nvidia,tegra194-cbb-noc";
+                       reg = <0x02300000 0x1000>;
+                       interrupts = <GIC_SPI 230 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 231 IRQ_TYPE_LEVEL_HIGH>;
+                       nvidia,axi2apb = <&axi2apb>;
+                       nvidia,apbmisc = <&apbmisc>;
+                       status = "okay";
+               };
+
+               axi2apb: axi2apb@2390000 {
+                       compatible = "nvidia,tegra194-axi2apb";
+                       reg = <0x2390000 0x1000>,
+                             <0x23a0000 0x1000>,
+                             <0x23b0000 0x1000>,
+                             <0x23c0000 0x1000>,
+                             <0x23d0000 0x1000>,
+                             <0x23e0000 0x1000>;
+                       status = "okay";
+               };
+
                ethernet@2490000 {
                        compatible = "nvidia,tegra194-eqos",
                                     "nvidia,tegra186-eqos",
                                        status = "disabled";
                                };
 
+                               tegra_ope1: processing-engine@2908000 {
+                                       compatible = "nvidia,tegra194-ope",
+                                                    "nvidia,tegra210-ope";
+                                       reg = <0x2908000 0x100>;
+                                       #address-cells = <1>;
+                                       #size-cells = <1>;
+                                       ranges;
+                                       sound-name-prefix = "OPE1";
+                                       status = "disabled";
+
+                                       equalizer@2908100 {
+                                               compatible = "nvidia,tegra194-peq",
+                                                            "nvidia,tegra210-peq";
+                                               reg = <0x2908100 0x100>;
+                                       };
+
+                                       dynamic-range-compressor@2908200 {
+                                               compatible = "nvidia,tegra194-mbdrc",
+                                                            "nvidia,tegra210-mbdrc";
+                                               reg = <0x2908200 0x200>;
+                                       };
+                               };
+
                                tegra_amixer: amixer@290bb00 {
                                        compatible = "nvidia,tegra194-amixer",
                                                     "nvidia,tegra210-amixer";
                        };
                };
 
+               timer@3010000 {
+                       compatible = "nvidia,tegra186-timer";
+                       reg = <0x03010000 0x000e0000>;
+                       interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+                       status = "okay";
+               };
+
                uarta: serial@3100000 {
                        compatible = "nvidia,tegra194-uart", "nvidia,tegra20-uart";
                        reg = <0x03100000 0x40>;
                        #phy-cells = <0>;
                };
 
+               sce-noc@b600000 {
+                       compatible = "nvidia,tegra194-sce-noc";
+                       reg = <0xb600000 0x1000>;
+                       interrupts = <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
+                       nvidia,axi2apb = <&axi2apb>;
+                       nvidia,apbmisc = <&apbmisc>;
+                       status = "okay";
+               };
+
+               rce-noc@be00000 {
+                       compatible = "nvidia,tegra194-rce-noc";
+                       reg = <0xbe00000 0x1000>;
+                       interrupts = <GIC_SPI 259 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 175 IRQ_TYPE_LEVEL_HIGH>;
+                       nvidia,axi2apb = <&axi2apb>;
+                       nvidia,apbmisc = <&apbmisc>;
+                       status = "okay";
+               };
+
                hsp_aon: hsp@c150000 {
                        compatible = "nvidia,tegra194-hsp";
                        reg = <0x0c150000 0x90000>;
 
                };
 
+               aon-noc@c600000 {
+                       compatible = "nvidia,tegra194-aon-noc";
+                       reg = <0xc600000 0x1000>;
+                       interrupts = <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 172 IRQ_TYPE_LEVEL_HIGH>;
+                       nvidia,apbmisc = <&apbmisc>;
+                       status = "okay";
+               };
+
+               bpmp-noc@d600000 {
+                       compatible = "nvidia,tegra194-bpmp-noc";
+                       reg = <0xd600000 0x1000>;
+                       interrupts = <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
+                       nvidia,axi2apb = <&axi2apb>;
+                       nvidia,apbmisc = <&apbmisc>;
+                       status = "okay";
+               };
+
                iommu@10000000 {
                        compatible = "nvidia,tegra194-smmu", "nvidia,smmu-500";
                        reg = <0x10000000 0x800000>;
                        interconnect-names = "dma-mem";
                        iommus = <&smmu TEGRA194_SID_HOST1X>;
 
+                       /* Context isolation domains */
+                       iommu-map = <
+                               0 &smmu TEGRA194_SID_HOST1X_CTX0 1
+                               1 &smmu TEGRA194_SID_HOST1X_CTX1 1
+                               2 &smmu TEGRA194_SID_HOST1X_CTX2 1
+                               3 &smmu TEGRA194_SID_HOST1X_CTX3 1
+                               4 &smmu TEGRA194_SID_HOST1X_CTX4 1
+                               5 &smmu TEGRA194_SID_HOST1X_CTX5 1
+                               6 &smmu TEGRA194_SID_HOST1X_CTX6 1
+                               7 &smmu TEGRA194_SID_HOST1X_CTX7 1>;
+
                        nvdec@15140000 {
                                compatible = "nvidia,tegra194-nvdec";
                                reg = <0x15140000 0x00040000>;
                #address-cells = <1>;
                #size-cells = <1>;
                ranges = <0x0 0x0 0x40000000 0x50000>;
+               no-memory-wc;
 
                cpu_bpmp_tx: sram@4e000 {
                        reg = <0x4e000 0x1000>;
index 328fbfe..1e26ca9 100644 (file)
                                };
                        };
 
+                       processing-engine@702d8000 {
+                               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>;
+                                               };
+                                       };
+                               };
+                       };
+
+                       processing-engine@702d8400 {
+                               status = "okay";
+
+                               ports {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       port@0 {
+                                               reg = <0x0>;
+
+                                               ope2_cif_in_ep: endpoint {
+                                                       remote-endpoint = <&xbar_ope2_in_ep>;
+                                               };
+                                       };
+
+                                       ope2_out_port: port@1 {
+                                               reg = <0x1>;
+
+                                               ope2_cif_out_ep: endpoint {
+                                                       remote-endpoint = <&xbar_ope2_out_ep>;
+                                               };
+                                       };
+                               };
+                       };
+
                        amixer@702dbb00 {
                                status = "okay";
 
                                                remote-endpoint = <&mixer_out5_ep>;
                                        };
                                };
+
+                               xbar_ope1_in_port: port@41 {
+                                       reg = <0x41>;
+
+                                       xbar_ope1_in_ep: endpoint {
+                                               remote-endpoint = <&ope1_cif_in_ep>;
+                                       };
+                               };
+
+                               port@42 {
+                                       reg = <0x42>;
+
+                                       xbar_ope1_out_ep: endpoint {
+                                               remote-endpoint = <&ope1_cif_out_ep>;
+                                       };
+                               };
+
+                               xbar_ope2_in_port: port@43 {
+                                       reg = <0x43>;
+
+                                       xbar_ope2_in_ep: endpoint {
+                                               remote-endpoint = <&ope2_cif_in_ep>;
+                                       };
+                               };
+
+                               port@44 {
+                                       reg = <0x44>;
+
+                                       xbar_ope2_out_ep: endpoint {
+                                               remote-endpoint = <&ope2_cif_out_ep>;
+                                       };
+                               };
                        };
                };
        };
                       <&xbar_mixer_in5_port>, <&xbar_mixer_in6_port>,
                       <&xbar_mixer_in7_port>, <&xbar_mixer_in8_port>,
                       <&xbar_mixer_in9_port>, <&xbar_mixer_in10_port>,
+                      <&xbar_ope1_in_port>, <&xbar_ope2_in_port>,
                       /* HW accelerators */
                       <&sfc1_out_port>, <&sfc2_out_port>,
                       <&sfc3_out_port>, <&sfc4_out_port>,
                       <&mixer_out1_port>, <&mixer_out2_port>,
                       <&mixer_out3_port>, <&mixer_out4_port>,
                       <&mixer_out5_port>,
+                      <&ope1_out_port>, <&ope2_out_port>,
                       /* I/O DAP Ports */
                       <&i2s1_port>, <&i2s2_port>, <&i2s3_port>, <&i2s4_port>,
                       <&i2s5_port>, <&dmic1_port>, <&dmic2_port>, <&dmic3_port>;
index 4b43b89..a44c56c 100644 (file)
                compatible = "gpio-keys";
                label = "gpio-keys";
 
-               power {
+               key-power {
                        label = "Power";
                        gpios = <&gpio TEGRA_GPIO(X, 5) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
                        wakeup-source;
                };
 
-               volume_down {
+               key-volume-down {
                        label = "Volume Down";
                        gpios = <&gpio TEGRA_GPIO(Y, 0) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEDOWN>;
                };
 
-               volume_up {
+               key-volume-up {
                        label = "Volume Up";
                        gpios = <&gpio TEGRA_GPIO(X, 6) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
index 10347b6..8e657b1 100644 (file)
                compatible = "gpio-keys";
                status = "okay";
 
-               power {
+               key-power {
                        debounce-interval = <30>;
                        gpios = <&gpio TEGRA_GPIO(X, 7) GPIO_ACTIVE_LOW>;
                        label = "Power";
index 746bd52..37678c3 100644 (file)
                                };
                        };
 
+                       processing-engine@702d8000 {
+                               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>;
+                                               };
+                                       };
+                               };
+                       };
+
+                       processing-engine@702d8400 {
+                               status = "okay";
+
+                               ports {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       port@0 {
+                                               reg = <0x0>;
+
+                                               ope2_cif_in_ep: endpoint {
+                                                       remote-endpoint = <&xbar_ope2_in_ep>;
+                                               };
+                                       };
+
+                                       ope2_out_port: port@1 {
+                                               reg = <0x1>;
+
+                                               ope2_cif_out_ep: endpoint {
+                                                       remote-endpoint = <&xbar_ope2_out_ep>;
+                                               };
+                                       };
+                               };
+                       };
+
                        amixer@702dbb00 {
                                status = "okay";
 
                                                remote-endpoint = <&mixer_out5_ep>;
                                        };
                                };
+
+                               xbar_ope1_in_port: port@41 {
+                                       reg = <0x41>;
+
+                                       xbar_ope1_in_ep: endpoint {
+                                               remote-endpoint = <&ope1_cif_in_ep>;
+                                       };
+                               };
+
+                               port@42 {
+                                       reg = <0x42>;
+
+                                       xbar_ope1_out_ep: endpoint {
+                                               remote-endpoint = <&ope1_cif_out_ep>;
+                                       };
+                               };
+
+                               xbar_ope2_in_port: port@43 {
+                                       reg = <0x43>;
+
+                                       xbar_ope2_in_ep: endpoint {
+                                               remote-endpoint = <&ope2_cif_in_ep>;
+                                       };
+                               };
+
+                               port@44 {
+                                       reg = <0x44>;
+
+                                       xbar_ope2_out_ep: endpoint {
+                                               remote-endpoint = <&ope2_cif_out_ep>;
+                                       };
+                               };
                        };
                };
        };
        gpio-keys {
                compatible = "gpio-keys";
 
-               power {
+               key-power {
                        label = "Power";
                        gpios = <&gpio TEGRA_GPIO(X, 5) GPIO_ACTIVE_LOW>;
                        linux,input-type = <EV_KEY>;
                        wakeup-source;
                };
 
-               force-recovery {
+               key-force-recovery {
                        label = "Force Recovery";
                        gpios = <&gpio TEGRA_GPIO(X, 6) GPIO_ACTIVE_LOW>;
                        linux,input-type = <EV_KEY>;
                       <&xbar_mixer_in5_port>, <&xbar_mixer_in6_port>,
                       <&xbar_mixer_in7_port>, <&xbar_mixer_in8_port>,
                       <&xbar_mixer_in9_port>, <&xbar_mixer_in10_port>,
+                      <&xbar_ope1_in_port>, <&xbar_ope2_in_port>,
                       /* HW accelerators */
                       <&sfc1_out_port>, <&sfc2_out_port>,
                       <&sfc3_out_port>, <&sfc4_out_port>,
                       <&mixer_out1_port>, <&mixer_out2_port>,
                       <&mixer_out3_port>, <&mixer_out4_port>,
                       <&mixer_out5_port>,
+                      <&ope1_out_port>, <&ope2_out_port>,
                       /* I/O DAP Ports */
                       <&i2s3_port>, <&i2s4_port>,
                       <&dmic1_port>, <&dmic2_port>;
index a263d51..5f3a1c5 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               power {
+               key-power {
                        label = "Power";
                        gpios = <&gpio TEGRA_GPIO(X, 5) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
                        wakeup-source;
                };
 
-               lid {
+               switch-lid {
                        label = "Lid";
                        gpios = <&gpio TEGRA_GPIO(B, 4) GPIO_ACTIVE_LOW>;
                        linux,input-type = <EV_SW>;
                        wakeup-source;
                };
 
-               tablet_mode {
+               switch-tablet-mode {
                        label = "Tablet Mode";
                        gpios = <&gpio TEGRA_GPIO(Z, 2) GPIO_ACTIVE_HIGH>;
                        linux,input-type = <EV_SW>;
                        wakeup-source;
                };
 
-               volume_down {
+               key-volume-down {
                        label = "Volume Down";
                        gpios = <&gpio TEGRA_GPIO(X, 7) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEDOWN>;
                };
 
-               volume_up {
+               key-volume-up {
                        label = "Volume Up";
                        gpios = <&gpio TEGRA_GPIO(M, 4) GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
index 4f0e51f..724e874 100644 (file)
                interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
                resets = <&tegra_car 142>;
                reset-names = "padctl";
-               nvidia,pmc =  <&tegra_pmc>;
+               nvidia,pmc = <&tegra_pmc>;
 
                status = "disabled";
 
                                status = "disabled";
                        };
 
+                       tegra_ope1: processing-engine@702d8000 {
+                               compatible = "nvidia,tegra210-ope";
+                               reg = <0x702d8000 0x100>;
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                               ranges;
+                               sound-name-prefix = "OPE1";
+                               status = "disabled";
+
+                               equalizer@702d8100 {
+                                       compatible = "nvidia,tegra210-peq";
+                                       reg = <0x702d8100 0x100>;
+                               };
+
+                               dynamic-range-compressor@702d8200 {
+                                       compatible = "nvidia,tegra210-mbdrc";
+                                       reg = <0x702d8200 0x200>;
+                               };
+                       };
+
+                       tegra_ope2: processing-engine@702d8400 {
+                               compatible = "nvidia,tegra210-ope";
+                               reg = <0x702d8400 0x100>;
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                               ranges;
+                               sound-name-prefix = "OPE2";
+                               status = "disabled";
+
+                               equalizer@702d8500 {
+                                       compatible = "nvidia,tegra210-peq";
+                                       reg = <0x702d8500 0x100>;
+                               };
+
+                               dynamic-range-compressor@702d8600 {
+                                       compatible = "nvidia,tegra210-mbdrc";
+                                       reg = <0x702d8600 0x200>;
+                               };
+                       };
+
                        tegra_amixer: amixer@702dbb00 {
                                compatible = "nvidia,tegra210-amixer";
                                reg = <0x702dbb00 0x800>;
index eaf1994..02a10bb 100644 (file)
                                                        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>;
+                                               };
+                                       };
                                };
 
                                i2s@2901000 {
                                        };
                                };
 
+                               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";
 
                compatible = "gpio-keys";
                status = "okay";
 
-               force-recovery {
+               key-force-recovery {
                        label = "Force Recovery";
                        gpios = <&gpio TEGRA234_MAIN_GPIO(G, 0) GPIO_ACTIVE_LOW>;
                        linux,input-type = <EV_KEY>;
                        linux,code = <BTN_1>;
                };
 
-               power-key {
+               key-power {
                        label = "Power";
                        gpios = <&gpio_aon TEGRA234_AON_GPIO(EE, 4) GPIO_ACTIVE_LOW>;
                        linux,input-type = <EV_KEY>;
                        wakeup-source;
                };
 
-               suspend {
+               key-suspend {
                        label = "Suspend";
                        gpios = <&gpio TEGRA234_MAIN_GPIO(G, 2) GPIO_ACTIVE_LOW>;
                        linux,input-type = <EV_KEY>;
                       <&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>,
                       <&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 */
                       <&i2s1_port>, <&i2s2_port>, <&i2s4_port>, <&i2s6_port>,
                       <&dmic3_port>;
index cb3af53..81a0f59 100644 (file)
 
                ranges = <0x0 0x0 0x0 0x40000000>;
 
+               gpcdma: dma-controller@2600000 {
+                       compatible = "nvidia,tegra234-gpcdma",
+                                    "nvidia,tegra194-gpcdma",
+                                    "nvidia,tegra186-gpcdma";
+                       reg = <0x2600000 0x210000>;
+                       resets = <&bpmp TEGRA234_RESET_GPCDMA>;
+                       reset-names = "gpcdma";
+                       interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 81 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>,
+                                    <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 99 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>;
+                       #dma-cells = <1>;
+                       iommus = <&smmu_niso0 TEGRA234_SID_GPCDMA>;
+                       dma-coherent;
+               };
+
                aconnect@2900000 {
                        compatible = "nvidia,tegra234-aconnect",
                                     "nvidia,tegra210-aconnect";
                                        status = "disabled";
                                };
 
+                               tegra_ope1: processing-engine@2908000 {
+                                       compatible = "nvidia,tegra234-ope",
+                                                    "nvidia,tegra210-ope";
+                                       reg = <0x2908000 0x100>;
+                                       #address-cells = <1>;
+                                       #size-cells = <1>;
+                                       ranges;
+                                       sound-name-prefix = "OPE1";
+                                       status = "disabled";
+
+                                       equalizer@2908100 {
+                                               compatible = "nvidia,tegra234-peq",
+                                                            "nvidia,tegra210-peq";
+                                               reg = <0x2908100 0x100>;
+                                       };
+
+                                       dynamic-range-compressor@2908200 {
+                                               compatible = "nvidia,tegra234-mbdrc",
+                                                            "nvidia,tegra210-mbdrc";
+                                               reg = <0x2908200 0x200>;
+                                       };
+                               };
+
                                tegra_mvc1: mvc@290a000 {
                                        compatible = "nvidia,tegra234-mvc",
                                                     "nvidia,tegra210-mvc";
                        status = "okay";
                };
 
+               timer@2080000 {
+                       compatible = "nvidia,tegra234-timer";
+                       reg = <0x02080000 0x00121000>;
+                       interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+                       status = "okay";
+               };
+
+               host1x@13e00000 {
+                       compatible = "nvidia,tegra234-host1x";
+                       reg = <0x13e00000 0x10000>,
+                             <0x13e10000 0x10000>,
+                             <0x13e40000 0x10000>;
+                       reg-names = "common", "hypervisor", "vm";
+                       interrupts = <GIC_SPI 448 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 450 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 451 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 452 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 453 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 454 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 455 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "syncpt0", "syncpt1", "syncpt2", "syncpt3", "syncpt4",
+                                         "syncpt5", "syncpt6", "syncpt7", "host1x";
+                       clocks = <&bpmp TEGRA234_CLK_HOST1X>;
+                       clock-names = "host1x";
+
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       ranges = <0x15000000 0x15000000 0x01000000>;
+                       interconnects = <&mc TEGRA234_MEMORY_CLIENT_HOST1XDMAR &emc>;
+                       interconnect-names = "dma-mem";
+                       iommus = <&smmu_niso1 TEGRA234_SID_HOST1X>;
+
+                       vic@15340000 {
+                               compatible = "nvidia,tegra234-vic";
+                               reg = <0x15340000 0x00040000>;
+                               interrupts = <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&bpmp TEGRA234_CLK_VIC>;
+                               clock-names = "vic";
+                               resets = <&bpmp TEGRA234_RESET_VIC>;
+                               reset-names = "vic";
+
+                               power-domains = <&bpmp TEGRA234_POWER_DOMAIN_VIC>;
+                               interconnects = <&mc TEGRA234_MEMORY_CLIENT_VICSRD &emc>,
+                                               <&mc TEGRA234_MEMORY_CLIENT_VICSWR &emc>;
+                               interconnect-names = "dma-mem", "write";
+                               iommus = <&smmu_niso1 TEGRA234_SID_VIC>;
+                               dma-coherent;
+                       };
+               };
+
                gpio: gpio@2200000 {
                        compatible = "nvidia,tegra234-gpio";
                        reg-names = "security", "gpio";
                        status = "okay";
                };
 
+               sce-fabric@b600000 {
+                       compatible = "nvidia,tegra234-sce-fabric";
+                       reg = <0xb600000 0x40000>;
+                       interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
+                       status = "okay";
+               };
+
+               rce-fabric@be00000 {
+                       compatible = "nvidia,tegra234-rce-fabric";
+                       reg = <0xbe00000 0x40000>;
+                       interrupts = <GIC_SPI 175 IRQ_TYPE_LEVEL_HIGH>;
+                       status = "okay";
+               };
+
                hsp_aon: hsp@c150000 {
                        compatible = "nvidia,tegra234-hsp", "nvidia,tegra194-hsp";
                        reg = <0x0c150000 0x90000>;
                        interrupt-controller;
                };
 
+               aon-fabric@c600000 {
+                       compatible = "nvidia,tegra234-aon-fabric";
+                       reg = <0xc600000 0x40000>;
+                       interrupts = <GIC_SPI 172 IRQ_TYPE_LEVEL_HIGH>;
+                       status = "okay";
+               };
+
+               bpmp-fabric@d600000 {
+                       compatible = "nvidia,tegra234-bpmp-fabric";
+                       reg = <0xd600000 0x40000>;
+                       interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
+                       status = "okay";
+               };
+
+               dce-fabric@de00000 {
+                       compatible = "nvidia,tegra234-sce-fabric";
+                       reg = <0xde00000 0x40000>;
+                       interrupts = <GIC_SPI 381 IRQ_TYPE_LEVEL_HIGH>;
+                       status = "okay";
+               };
+
                gic: interrupt-controller@f400000 {
                        compatible = "arm,gic-v3";
                        reg = <0x0f400000 0x010000>, /* GICD */
                        nvidia,memory-controller = <&mc>;
                        status = "okay";
                };
+
+               cbb-fabric@13a00000 {
+                       compatible = "nvidia,tegra234-cbb-fabric";
+                       reg = <0x13a00000 0x400000>;
+                       interrupts = <GIC_SPI 231 IRQ_TYPE_LEVEL_HIGH>;
+                       status = "okay";
+               };
        };
 
        ccplex@e000000 {
                #address-cells = <1>;
                #size-cells = <1>;
                ranges = <0x0 0x0 0x40000000 0x80000>;
+               no-memory-wc;
 
                cpu_bpmp_tx: sram@70000 {
                        reg = <0x70000 0x1000>;
index 2f8aec2..1d86a33 100644 (file)
@@ -30,13 +30,11 @@ dtb-$(CONFIG_ARCH_QCOM)     += msm8994-sony-xperia-kitakami-satsuki.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += msm8994-sony-xperia-kitakami-sumire.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += msm8994-sony-xperia-kitakami-suzuran.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += msm8996-mtp.dtb
-dtb-$(CONFIG_ARCH_QCOM)        += msm8996-pmi8996-sony-xperia-tone-dora.dtb
-dtb-$(CONFIG_ARCH_QCOM)        += msm8996-pmi8996-sony-xperia-tone-kagura.dtb
-dtb-$(CONFIG_ARCH_QCOM)        += msm8996-pmi8996-sony-xperia-tone-keyaki.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += msm8996-sony-xperia-tone-dora.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += msm8996-sony-xperia-tone-kagura.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += msm8996-sony-xperia-tone-keyaki.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += msm8996-xiaomi-gemini.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += msm8996-xiaomi-natrium.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += msm8996-xiaomi-scorpio.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += msm8998-asus-novago-tp370ql.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += msm8998-fxtec-pro1.dtb
@@ -52,6 +50,7 @@ dtb-$(CONFIG_ARCH_QCOM)       += qcs404-evb-1000.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += qcs404-evb-4000.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += qrb5165-rb5.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sa8155p-adp.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sa8295p-adp.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sc7180-idp.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-coachz-r1.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-coachz-r1-lte.dtb
@@ -60,6 +59,8 @@ dtb-$(CONFIG_ARCH_QCOM)       += sc7180-trogdor-coachz-r3-lte.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-homestar-r2.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-homestar-r3.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-homestar-r4.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-kingoftown-r0.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-kingoftown-r1.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-lazor-r0.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-lazor-r1.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-lazor-r1-kb.dtb
@@ -75,12 +76,28 @@ dtb-$(CONFIG_ARCH_QCOM)     += sc7180-trogdor-lazor-limozeen-r9.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-lazor-limozeen-nots-r4.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-lazor-limozeen-nots-r5.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-lazor-limozeen-nots-r9.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-mrbland-rev0-auo.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-mrbland-rev0-boe.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-mrbland-rev1-auo.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-mrbland-rev1-boe.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-pazquel-lte-parade.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-pazquel-lte-ti.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-pazquel-parade.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-pazquel-ti.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-pompom-r1.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-pompom-r1-lte.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-pompom-r2.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-pompom-r2-lte.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-pompom-r3.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-pompom-r3-lte.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-quackingstick-r0.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-quackingstick-r0-lte.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-wormdingler-rev0-boe.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-wormdingler-rev0-inx.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-wormdingler-rev1-boe.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-wormdingler-rev1-inx.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-wormdingler-rev1-inx-rt5682s.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-wormdingler-rev1-boe-rt5682s.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-r1.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sc7180-trogdor-r1-lte.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sc7280-herobrine-crd.dtb
@@ -89,6 +106,9 @@ dtb-$(CONFIG_ARCH_QCOM)      += sc7280-herobrine-villager-r0.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sc7280-idp.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sc7280-idp2.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sc7280-crd-r3.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sc8280xp-crd.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sc8280xp-lenovo-thinkpad-x13s.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sda660-inforce-ifc6560.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sdm630-sony-xperia-ganges-kirin.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sdm630-sony-xperia-nile-discovery.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sdm630-sony-xperia-nile-pioneer.dtb
@@ -100,6 +120,8 @@ dtb-$(CONFIG_ARCH_QCOM)     += sdm845-cheza-r1.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sdm845-cheza-r2.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sdm845-cheza-r3.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sdm845-db845c.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sdm845-lg-judyln.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sdm845-lg-judyp.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sdm845-mtp.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sdm845-oneplus-enchilada.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sdm845-oneplus-fajita.dtb
@@ -107,6 +129,7 @@ dtb-$(CONFIG_ARCH_QCOM)     += sdm845-sony-xperia-tama-akari.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sdm845-sony-xperia-tama-akatsuki.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sdm845-sony-xperia-tama-apollo.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sdm845-xiaomi-beryllium.dtb
+dtb-$(CONFIG_ARCH_QCOM)        += sdm845-xiaomi-polaris.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sdm845-shift-axolotl.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sdm850-lenovo-yoga-c630.dtb
 dtb-$(CONFIG_ARCH_QCOM)        += sdm850-samsung-w737.dtb
index 7c1eab6..1b61309 100644 (file)
@@ -8,6 +8,7 @@
 #include "msm8916-pm8916.dtsi"
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
 #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
 #include <dt-bindings/pinctrl/qcom,pmic-mpp.h>
 #include <dt-bindings/sound/apq8016-lpass.h>
                serial0 = &blsp1_uart2;
                serial1 = &blsp1_uart1;
                usid0 = &pm8916_0;
-               i2c0    = &blsp_i2c2;
-               i2c1    = &blsp_i2c6;
-               i2c3    = &blsp_i2c4;
-               spi0    = &blsp_spi5;
-               spi1    = &blsp_spi3;
+               i2c0 = &blsp_i2c2;
+               i2c1 = &blsp_i2c6;
+               i2c3 = &blsp_i2c4;
+               spi0 = &blsp_spi5;
+               spi1 = &blsp_spi3;
        };
 
        chosen {
 
        gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
                autorepeat;
 
                pinctrl-names = "default";
                pinctrl-0 = <&msm_key_volp_n_default>;
 
-               button@0 {
+               button {
                        label = "Volume Up";
                        linux,code = <KEY_VOLUMEUP>;
                        gpios = <&msmgpio 107 GPIO_ACTIVE_LOW>;
 
                led@1 {
                        label = "apq8016-sbc:green:user1";
+                       function = LED_FUNCTION_HEARTBEAT;
+                       color = <LED_COLOR_ID_GREEN>;
                        gpios = <&msmgpio 21 GPIO_ACTIVE_HIGH>;
                        linux,default-trigger = "heartbeat";
                        default-state = "off";
 
                led@2 {
                        label = "apq8016-sbc:green:user2";
+                       function = LED_FUNCTION_DISK_ACTIVITY;
+                       color = <LED_COLOR_ID_GREEN>;
                        gpios = <&msmgpio 120 GPIO_ACTIVE_HIGH>;
                        linux,default-trigger = "mmc0";
                        default-state = "off";
 
                led@3 {
                        label = "apq8016-sbc:green:user3";
+                       function = LED_FUNCTION_DISK_ACTIVITY;
+                       color = <LED_COLOR_ID_GREEN>;
                        gpios = <&pm8916_gpios 1 GPIO_ACTIVE_HIGH>;
                        linux,default-trigger = "mmc1";
                        default-state = "off";
 
                led@4 {
                        label = "apq8016-sbc:green:user4";
+                       color = <LED_COLOR_ID_GREEN>;
                        gpios = <&pm8916_gpios 2 GPIO_ACTIVE_HIGH>;
                        linux,default-trigger = "none";
                        panic-indicator;
 
                led@5 {
                        label = "apq8016-sbc:yellow:wlan";
+                       function = LED_FUNCTION_WLAN;
+                       color = <LED_COLOR_ID_YELLOW>;
                        gpios = <&pm8916_mpps 2 GPIO_ACTIVE_HIGH>;
                        linux,default-trigger = "phy0tx";
                        default-state = "off";
 
                led@6 {
                        label = "apq8016-sbc:blue:bt";
+                       function = LED_FUNCTION_BLUETOOTH;
+                       color = <LED_COLOR_ID_BLUE>;
                        gpios = <&pm8916_mpps 3 GPIO_ACTIVE_HIGH>;
                        linux,default-trigger = "bluetooth-power";
                        default-state = "off";
                "USB_HUB_RESET_N_PM",
                "USB_SW_SEL_PM";
 
-       usb_hub_reset_pm: usb-hub-reset-pm {
+       usb_hub_reset_pm: usb-hub-reset-pm-state {
                pins = "gpio3";
                function = PMIC_GPIO_FUNC_NORMAL;
 
                output-high;
        };
 
-       usb_hub_reset_pm_device: usb-hub-reset-pm-device {
+       usb_hub_reset_pm_device: usb-hub-reset-pm-device-state {
                pins = "gpio3";
                function = PMIC_GPIO_FUNC_NORMAL;
 
                output-low;
        };
 
-       usb_sw_sel_pm: usb-sw-sel-pm {
+       usb_sw_sel_pm: usb-sw-sel-pm-state {
                pins = "gpio4";
                function = PMIC_GPIO_FUNC_NORMAL;
 
                output-high;
        };
 
-       usb_sw_sel_pm_device: usb-sw-sel-pm-device {
+       usb_sw_sel_pm_device: usb-sw-sel-pm-device-state {
                pins = "gpio4";
                function = PMIC_GPIO_FUNC_NORMAL;
 
                output-low;
        };
 
-       pm8916_gpios_leds: pm8916-gpios-leds {
+       pm8916_gpios_leds: pm8916-gpios-leds-state {
                pins = "gpio1", "gpio2";
                function = PMIC_GPIO_FUNC_NORMAL;
 
index 49afbb1..c1cb1ba 100644 (file)
@@ -10,6 +10,7 @@
 #include "pmi8994.dtsi"
 #include <dt-bindings/input/input.h>
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
 #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
 #include <dt-bindings/sound/qcom,q6afe.h>
 #include <dt-bindings/sound/qcom,q6asm.h>
                serial0 = &blsp2_uart2;
                serial1 = &blsp2_uart3;
                serial2 = &blsp1_uart2;
-               i2c0    = &blsp1_i2c3;
-               i2c1    = &blsp2_i2c1;
-               i2c2    = &blsp2_i2c1;
-               spi0    = &blsp1_spi1;
-               spi1    = &blsp2_spi6;
+               i2c0 = &blsp1_i2c3;
+               i2c1 = &blsp2_i2c1;
+               i2c2 = &blsp2_i2c1;
+               spi0 = &blsp1_spi1;
+               spi1 = &blsp2_spi6;
        };
 
        chosen {
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
                autorepeat;
 
                pinctrl-names = "default";
                pinctrl-0 = <&volume_up_gpio>;
 
-               button@0 {
+               button {
                        label = "Volume Up";
                        linux,code = <KEY_VOLUMEUP>;
                        gpios = <&pm8994_gpios 2 GPIO_ACTIVE_LOW>;
        pinctrl-names = "default";
        pinctrl-0 = <&ls_exp_gpio_f &bt_en_gpios>;
 
-       ls_exp_gpio_f: pm8994_gpio5 {
+       ls_exp_gpio_f: pm8994-gpio5-state {
                pinconf {
                        pins = "gpio5";
+                       function = PMIC_GPIO_FUNC_NORMAL;
                        output-low;
                        power-source = <2>; // PM8994_GPIO_S4, 1.8V
                };
        };
 
-       bt_en_gpios: bt_en_gpios {
+       bt_en_gpios: bt-en-pios-state {
                pinconf {
                        pins = "gpio19";
                        function = PMIC_GPIO_FUNC_NORMAL;
                };
        };
 
-       wlan_en_gpios: wlan_en_gpios {
+       wlan_en_gpios: wlan-en-gpios-state {
                pinconf {
                        pins = "gpio8";
                        function = PMIC_GPIO_FUNC_NORMAL;
                };
        };
 
-       audio_mclk: clk_div1 {
+       audio_mclk: clk-div1-state {
                pinconf {
                        pins = "gpio15";
                        function = "func1";
                };
        };
 
-       volume_up_gpio: pm8996_gpio2 {
+       volume_up_gpio: pm8996-gpio2-state {
                pinconf {
                        pins = "gpio2";
                        function = "normal";
                };
        };
 
-       divclk4_pin_a: divclk4 {
+       divclk4_pin_a: divclk4-state {
                pinconf {
                        pins = "gpio18";
                        function = PMIC_GPIO_FUNC_FUNC2;
                };
        };
 
-       usb3_vbus_det_gpio: pm8996_gpio22 {
+       usb3_vbus_det_gpio: pm8996-gpio22-state {
                pinconf {
                        pins = "gpio22";
                        function = PMIC_GPIO_FUNC_NORMAL;
                "NC",
                "NC";
 
-       usb2_vbus_det_gpio: pmi8996_gpio6 {
+       usb2_vbus_det_gpio: pmi8996-gpio6-state {
                pinconf {
                        pins = "gpio6";
                        function = PMIC_GPIO_FUNC_NORMAL;
        };
 };
 
+&pmi8994_lpg {
+       qcom,power-source = <1>;
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&pmi8994_mpp2_userled4>;
+
+       qcom,dtest = <0 0>,
+                    <0 0>,
+                    <0 0>,
+                    <4 1>;
+
+       status = "okay";
+
+       led@1 {
+               reg = <1>;
+               color = <LED_COLOR_ID_GREEN>;
+               function = LED_FUNCTION_HEARTBEAT;
+               function-enumerator = <1>;
+
+               linux,default-trigger = "heartbeat";
+               default-state = "on";
+       };
+
+       led@2 {
+               reg = <2>;
+               color = <LED_COLOR_ID_GREEN>;
+               function = LED_FUNCTION_HEARTBEAT;
+               function-enumerator = <0>;
+       };
+
+       led@3 {
+               reg = <3>;
+               color = <LED_COLOR_ID_GREEN>;
+               function = LED_FUNCTION_HEARTBEAT;
+               function-enumerator = <2>;
+       };
+
+       led@4 {
+               reg = <4>;
+               color = <LED_COLOR_ID_GREEN>;
+               function = LED_FUNCTION_HEARTBEAT;
+               function-enumerator = <3>;
+       };
+};
+
+&pmi8994_mpps {
+       pmi8994_mpp2_userled4: mpp2-userled4-state {
+               pins = "mpp2";
+               function = "sink";
+
+               output-low;
+               qcom,dtest = <4>;
+       };
+};
+
 &pmi8994_spmi_regulators {
        vdd_s2-supply = <&vph_pwr>;
 
 &sound {
        compatible = "qcom,apq8096-sndcard";
        model = "DB820c";
-       audio-routing = "RX_BIAS", "MCLK",
+       audio-routing = "RX_BIAS", "MCLK",
                "MM_DL1",  "MultiMedia1 Playback",
                "MM_DL2",  "MultiMedia2 Playback",
                "MultiMedia3 Capture", "MM_UL3";
index 821cb7c..1ba2eca 100644 (file)
        status = "okay";
 };
 
-&i2c_1 {
+&blsp1_i2c3 {
        pinctrl-0 = <&i2c_1_pins>;
        pinctrl-names = "default";
        status = "okay";
 };
 
-&spi_0 {
+&blsp1_spi1 {
        cs-select = <0>;
        status = "okay";
 
@@ -43,7 +43,7 @@
                #address-cells = <1>;
                #size-cells = <1>;
                reg = <0>;
-               compatible = "n25q128a11";
+               compatible = "micron,n25q128a11", "jedec,spi-nor";
                spi-max-frequency = <50000000>;
        };
 };
index c89499e..aaad7d9 100644 (file)
@@ -87,7 +87,7 @@
                };
        };
 
-       cpu_opp_table: cpu_opp_table {
+       cpu_opp_table: opp-table-cpu {
                compatible = "operating-points-v2";
                opp-shared;
 
 
        firmware {
                scm {
-                       compatible = "qcom,scm";
+                       compatible = "qcom,scm-ipq6018", "qcom,scm";
                };
        };
 
                        status = "disabled";
                };
 
-               spi_0: spi@78b5000 {
+               blsp1_spi1: spi@78b5000 {
                        compatible = "qcom,spi-qup-v2.2.1";
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "disabled";
                };
 
-               spi_1: spi@78b6000 {
+               blsp1_spi2: spi@78b6000 {
                        compatible = "qcom,spi-qup-v2.2.1";
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "disabled";
                };
 
-               i2c_0: i2c@78b6000 {
+               blsp1_i2c2: i2c@78b6000 {
                        compatible = "qcom,i2c-qup-v2.2.1";
                        #address-cells = <1>;
                        #size-cells = <0>;
                        clocks = <&gcc GCC_BLSP1_QUP2_I2C_APPS_CLK>,
                                 <&gcc GCC_BLSP1_AHB_CLK>;
                        clock-names = "core", "iface";
-                       clock-frequency  = <400000>;
+                       clock-frequency = <400000>;
                        dmas = <&blsp_dma 14>, <&blsp_dma 15>;
                        dma-names = "tx", "rx";
                        status = "disabled";
                };
 
-               i2c_1: i2c@78b7000 { /* BLSP1 QUP2 */
+               blsp1_i2c3: i2c@78b7000 {
                        compatible = "qcom,i2c-qup-v2.2.1";
                        #address-cells = <1>;
                        #size-cells = <0>;
                        clocks = <&gcc GCC_BLSP1_QUP3_I2C_APPS_CLK>,
                                 <&gcc GCC_BLSP1_AHB_CLK>;
                        clock-names = "core", "iface";
-                       clock-frequency  = <400000>;
+                       clock-frequency = <400000>;
                        dmas = <&blsp_dma 16>, <&blsp_dma 17>;
                        dma-names = "tx", "rx";
                        status = "disabled";
                };
 
                timer@b120000 {
-                       #address-cells = <2>;
-                       #size-cells = <2>;
-                       ranges;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0 0 0 0x10000000>;
                        compatible = "arm,armv7-timer-mem";
                        reg = <0x0 0x0b120000 0x0 0x1000>;
 
                                frame-number = <0>;
                                interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x0b121000 0x0 0x1000>,
-                                     <0x0 0x0b122000 0x0 0x1000>;
+                               reg = <0x0b121000 0x1000>,
+                                     <0x0b122000 0x1000>;
                        };
 
                        frame@b123000 {
                                frame-number = <1>;
                                interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0xb123000 0x0 0x1000>;
+                               reg = <0x0b123000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@b124000 {
                                frame-number = <2>;
                                interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x0b124000 0x0 0x1000>;
+                               reg = <0x0b124000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@b125000 {
                                frame-number = <3>;
                                interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x0b125000 0x0 0x1000>;
+                               reg = <0x0b125000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@b126000 {
                                frame-number = <4>;
                                interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x0b126000 0x0 0x1000>;
+                               reg = <0x0b126000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@b127000 {
                                frame-number = <5>;
                                interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x0b127000 0x0 0x1000>;
+                               reg = <0x0b127000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@b128000 {
                                frame-number = <6>;
                                interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x0b128000 0x0 0x1000>;
+                               reg = <0x0b128000 0x1000>;
                                status = "disabled";
                        };
                };
 
                        glink-edge {
                                interrupts = <GIC_SPI 321 IRQ_TYPE_EDGE_RISING>;
+                               label = "rtr";
                                qcom,remote-pid = <1>;
                                mboxes = <&apcs_glb 8>;
 
                                      <0x0 0x00078800 0x0 0x1F8>, /* PCS */
                                      <0x0 0x00078600 0x0 0x044>; /* PCS misc */
                                #phy-cells = <0>;
-                               #clock-cells = <1>;
+                               #clock-cells = <0>;
                                clocks = <&gcc GCC_USB0_PIPE_CLK>;
                                clock-names = "pipe0";
                                clock-output-names = "gcc_usb0_pipe_clk_src";
index de20cb9..81dc3a0 100644 (file)
@@ -5,11 +5,8 @@
 #include "ipq8074.dtsi"
 
 / {
-       #address-cells = <0x2>;
-       #size-cells = <0x2>;
        model = "Qualcomm Technologies, Inc. IPQ8074-HK01";
        compatible = "qcom,ipq8074-hk01", "qcom,ipq8074";
-       interrupt-parent = <&intc>;
 
        aliases {
                serial0 = &blsp1_uart5;
index ce86d9b..40415d9 100644 (file)
@@ -7,11 +7,6 @@
 #include "ipq8074.dtsi"
 
 / {
-       #address-cells = <0x2>;
-       #size-cells = <0x2>;
-
-       interrupt-parent = <&intc>;
-
        aliases {
                serial0 = &blsp1_uart5;
        };
index 4c38b15..d53675f 100644 (file)
@@ -7,8 +7,12 @@
 #include <dt-bindings/clock/qcom,gcc-ipq8074.h>
 
 / {
+       #address-cells = <2>;
+       #size-cells = <2>;
+
        model = "Qualcomm Technologies, Inc. IPQ8074";
        compatible = "qcom,ipq8074";
+       interrupt-parent = <&intc>;
 
        clocks {
                sleep_clk: sleep_clk {
                                <&xo>;
                        clock-names = "aux", "cfg_ahb", "ref";
 
-                       resets =  <&gcc GCC_USB1_PHY_BCR>,
+                       resets = <&gcc GCC_USB1_PHY_BCR>,
                                <&gcc GCC_USB3PHY_1_PHY_BCR>;
                        reset-names = "phy","common";
                        status = "disabled";
                                      <0x00058800 0x1f8>,     /* PCS  */
                                      <0x00058600 0x044>;     /* PCS misc*/
                                #phy-cells = <0>;
-                               #clock-cells = <1>;
+                               #clock-cells = <0>;
                                clocks = <&gcc GCC_USB1_PIPE_CLK>;
                                clock-names = "pipe0";
                                clock-output-names = "gcc_usb1_pipe_clk_src";
                                <&xo>;
                        clock-names = "aux", "cfg_ahb", "ref";
 
-                       resets =  <&gcc GCC_USB0_PHY_BCR>,
+                       resets = <&gcc GCC_USB0_PHY_BCR>,
                                <&gcc GCC_USB3PHY_0_PHY_BCR>;
                        reset-names = "phy","common";
                        status = "disabled";
                                      <0x00078800 0x1f8>,     /* PCS  */
                                      <0x00078600 0x044>;     /* PCS misc*/
                                #phy-cells = <0>;
-                               #clock-cells = <1>;
+                               #clock-cells = <0>;
                                clocks = <&gcc GCC_USB0_PIPE_CLK>;
                                clock-names = "pipe0";
                                clock-output-names = "gcc_usb0_pipe_clk_src";
                        compatible = "qcom,gcc-ipq8074";
                        reg = <0x01800000 0x80000>;
                        #clock-cells = <0x1>;
+                       #power-domain-cells = <1>;
                        #reset-cells = <0x1>;
                };
 
                        cell-index = <0>;
                };
 
-               sdhc_1: sdhci@7824900 {
+               sdhc_1: mmc@7824900 {
                        compatible = "qcom,sdhci-msm-v4";
                        reg = <0x7824900 0x500>, <0x7824000 0x800>;
                        reg-names = "hc_mem", "core_mem";
                                     <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "hc_irq", "pwr_irq";
 
-                       clocks = <&xo>,
-                                <&gcc GCC_SDCC1_AHB_CLK>,
-                                <&gcc GCC_SDCC1_APPS_CLK>;
-                       clock-names = "xo", "iface", "core";
+                       clocks = <&gcc GCC_SDCC1_AHB_CLK>,
+                                <&gcc GCC_SDCC1_APPS_CLK>,
+                                <&xo>;
+                       clock-names = "iface", "core", "xo";
+                       resets = <&gcc GCC_SDCC1_BCR>;
                        max-frequency = <384000000>;
                        mmc-ddr-1_8v;
                        mmc-hs200-1_8v;
                        status = "disabled";
                };
 
-               qpic_nand: nand@79b0000 {
+               qpic_nand: nand-controller@79b0000 {
                        compatible = "qcom,ipq8074-nand";
                        reg = <0x079b0000 0x10000>;
                        #address-cells = <1>;
                                                <133330000>,
                                                <19200000>;
 
+                       power-domains = <&gcc USB0_GDSC>;
+
                        resets = <&gcc GCC_USB0_BCR>;
                        status = "disabled";
 
                                                <133330000>,
                                                <19200000>;
 
+                       power-domains = <&gcc USB1_GDSC>;
+
                        resets = <&gcc GCC_USB1_BCR>;
                        status = "disabled";
 
                        };
                };
 
-               timer {
-                       compatible = "arm,armv8-timer";
-                       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)>;
-               };
-
                watchdog: watchdog@b017000 {
                        compatible = "qcom,kpss-wdt";
                        reg = <0xb017000 0x1000>;
                        timeout-sec = <30>;
                };
 
+               apcs_glb: mailbox@b111000 {
+                       compatible = "qcom,ipq8074-apcs-apps-global";
+                       reg = <0x0b111000 0x6000>;
+
+                       #clock-cells = <1>;
+                       #mbox-cells = <1>;
+               };
+
                timer@b120000 {
                        #address-cells = <1>;
                        #size-cells = <1>;
                        status = "disabled";
                };
        };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               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)>;
+       };
 };
index 265e539..3dc9619 100644 (file)
@@ -27,7 +27,7 @@
 
                label = "GPIO Buttons";
 
-               volume-up {
+               button-volume-up {
                        label = "Volume Up";
                        gpios = <&msmgpio 107 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
index d4d33dd..dd92070 100644 (file)
 
                label = "GPIO Buttons";
 
-               volume-up {
+               button-volume-up {
                        label = "Volume Up";
                        gpios = <&msmgpio 107 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
                        debounce-interval = <15>;
                };
 
-               volume-down {
+               button-volume-down {
                        label = "Volume Down";
                        gpios = <&msmgpio 117 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEDOWN>;
index 00488af..9e470c6 100644 (file)
@@ -39,7 +39,7 @@
 
                label = "GPIO Buttons";
 
-               volume-up {
+               button-volume-up {
                        label = "Volume Up";
                        gpios = <&msmgpio 107 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
index b3836dd..d85e7f7 100644 (file)
@@ -39,7 +39,7 @@
 
                label = "GPIO Buttons";
 
-               volume-up {
+               button-volume-up {
                        label = "Volume Up";
                        gpios = <&msmgpio 107 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
index f9ce123..b4812f0 100644 (file)
@@ -28,7 +28,7 @@
 
                label = "GPIO Buttons";
 
-               volume-up {
+               button-volume-up {
                        label = "Volume Up";
                        gpios = <&msmgpio 107 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
index 9b4b7de..10f6509 100644 (file)
 
                label = "GPIO Buttons";
 
-               volume-up {
+               button-volume-up {
                        label = "Volume Up";
                        gpios = <&msmgpio 107 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
                };
 
-               home {
+               button-home {
                        label = "Home";
                        gpios = <&msmgpio 109 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_HOMEPAGE>;
@@ -52,7 +52,7 @@
 
                label = "GPIO Hall Effect Sensor";
 
-               hall-sensor {
+               event-hall-sensor {
                        label = "Hall Effect Sensor";
                        gpios = <&msmgpio 52 GPIO_ACTIVE_LOW>;
                        linux,input-type = <EV_SW>;
                drive-strength = <2>;
                bias-disable;
        };
+
+       ts_int_default: ts-int-default {
+               pins = "gpio13";
+               function = "gpio";
+
+               drive-strength = <2>;
+               bias-disable;
+       };
 };
 
 &pm8916_gpios {
-       nfc_clk_req: nfc-clk-req {
+       nfc_clk_req: nfc-clk-req-state {
                pins = "gpio2";
                function = "func1";
 
index 4ba11b0..bc198a2 100644 (file)
                drive-strength = <2>;
                bias-disable;
        };
-
-       ts_int_default: ts-int-default {
-               pins = "gpio13";
-               function = "gpio";
-
-               drive-strength = <2>;
-               bias-disable;
-       };
 };
index d978c9a..7f2ab18 100644 (file)
                drive-strength = <2>;
                bias-disable;
        };
-
-       ts_int_default: ts-int-default {
-               pins = "gpio13";
-               function = "gpio";
-
-               drive-strength = <2>;
-               bias-disable;
-       };
 };
index 6c408d6..eabeed1 100644 (file)
 
                label = "GPIO Buttons";
 
-               volume-up {
+               button-volume-up {
                        label = "Volume Up";
                        gpios = <&msmgpio 107 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
                };
 
-               home-key {
+               button-home {
                        label = "Home Key";
                        gpios = <&msmgpio 109 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_HOMEPAGE>;
index 58dfbff..439e89c 100644 (file)
 
                label = "GPIO Buttons";
 
-               volume-up {
+               button-volume-up {
                        label = "Volume Up";
                        gpios = <&msmgpio 107 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
                };
 
-               home {
+               button-home {
                        label = "Home";
                        gpios = <&msmgpio 109 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_HOMEPAGE>;
@@ -70,7 +70,7 @@
 
                label = "GPIO Hall Effect Sensor";
 
-               hall-sensor {
+               event-hall-sensor {
                        label = "Hall Effect Sensor";
                        gpios = <&msmgpio 52 GPIO_ACTIVE_LOW>;
                        linux,input-type = <EV_SW>;
index 69a44c6..84a352d 100644 (file)
@@ -29,7 +29,7 @@
 
                label = "GPIO Buttons";
 
-               volume-up {
+               button-volume-up {
                        label = "Volume Up";
                        gpios = <&msmgpio 107 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
index 0547251..48bc2e0 100644 (file)
                };
        };
 
-       cpu_opp_table: cpu-opp-table {
+       cpu_opp_table: opp-table-cpu {
                compatible = "operating-points-v2";
                opp-shared;
 
                                rpmcc: clock-controller {
                                        compatible = "qcom,rpmcc-msm8916", "qcom,rpmcc";
                                        #clock-cells = <1>;
+                                       clocks = <&xo_board>;
+                                       clock-names = "xo";
                                };
 
                                rpmpd: power-controller {
                };
 
                qfprom: qfprom@5c000 {
-                       compatible = "qcom,qfprom";
+                       compatible = "qcom,msm8916-qfprom", "qcom,qfprom";
                        reg = <0x0005c000 0x1000>;
                        #address-cells = <1>;
                        #size-cells = <1>;
                        #sound-dai-cells = <1>;
                };
 
-               sdhc_1: sdhci@7824000 {
+               sdhc_1: mmc@7824000 {
                        compatible = "qcom,msm8916-sdhci", "qcom,sdhci-msm-v4";
                        reg = <0x07824900 0x11c>, <0x07824000 0x800>;
                        reg-names = "hc_mem", "core_mem";
                        interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "hc_irq", "pwr_irq";
-                       clocks = <&gcc GCC_SDCC1_APPS_CLK>,
-                                <&gcc GCC_SDCC1_AHB_CLK>,
+                       clocks = <&gcc GCC_SDCC1_AHB_CLK>,
+                                <&gcc GCC_SDCC1_APPS_CLK>,
                                 <&xo_board>;
-                       clock-names = "core", "iface", "xo";
+                       clock-names = "iface", "core", "xo";
                        mmc-ddr-1_8v;
                        bus-width = <8>;
                        non-removable;
                        status = "disabled";
                };
 
-               sdhc_2: sdhci@7864000 {
+               sdhc_2: mmc@7864000 {
                        compatible = "qcom,msm8916-sdhci", "qcom,sdhci-msm-v4";
                        reg = <0x07864900 0x11c>, <0x07864000 0x800>;
                        reg-names = "hc_mem", "core_mem";
                        interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
                                     <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "hc_irq", "pwr_irq";
-                       clocks = <&gcc GCC_SDCC2_APPS_CLK>,
-                                <&gcc GCC_SDCC2_AHB_CLK>,
+                       clocks = <&gcc GCC_SDCC2_AHB_CLK>,
+                                <&gcc GCC_SDCC2_APPS_CLK>,
                                 <&xo_board>;
-                       clock-names = "core", "iface", "xo";
+                       clock-names = "iface", "core", "xo";
                        bus-width = <4>;
                        status = "disabled";
                };
                                        <&rpmpd MSM8916_VDDMX>;
                        power-domain-names = "cx", "mx";
 
-                       qcom,state = <&wcnss_smp2p_out 0>;
-                       qcom,state-names = "stop";
+                       qcom,smem-states = <&wcnss_smp2p_out 0>;
+                       qcom,smem-state-names = "stop";
 
                        pinctrl-names = "default";
                        pinctrl-0 = <&wcnss_pin_a>;
                        compatible = "qcom,msm8916-a53pll";
                        reg = <0x0b016000 0x40>;
                        #clock-cells = <0>;
+                       clocks = <&xo_board>;
+                       clock-names = "xo";
                };
 
                timer@b020000 {
index ffc3ec2..8416a45 100644 (file)
 
        firmware {
                scm: scm {
-                       compatible = "qcom,scm-msm8953";
+                       compatible = "qcom,scm-msm8953", "qcom,scm";
                        clocks = <&gcc GCC_CRYPTO_CLK>,
                                 <&gcc GCC_CRYPTO_AXI_CLK>,
                                 <&gcc GCC_CRYPTO_AHB_CLK>;
                        };
                };
 
-               sdhc_1: sdhci@7824900 {
+               sdhc_1: mmc@7824900 {
                        compatible = "qcom,msm8953-sdhci", "qcom,sdhci-msm-v4";
 
                        reg = <0x7824900 0x500>, <0x7824000 0x800>;
                        };
                };
 
-               sdhc_2: sdhci@7864900 {
+               sdhc_2: mmc@7864900 {
                        compatible = "qcom,msm8953-sdhci", "qcom,sdhci-msm-v4";
 
                        reg = <0x7864900 0x500>, <0x7864000 0x800>;
index 3b0cc85..71e373b 100644 (file)
@@ -74,7 +74,7 @@
                vdd_l17_29-supply = <&vph_pwr>;
                vdd_l20_21-supply = <&vph_pwr>;
                vdd_l25-supply = <&pm8994_s5>;
-               vdd_lvs1_2 = <&pm8994_s4>;
+               vdd_lvs1_2-supply = <&pm8994_s4>;
 
                /* S1, S2, S6 and S12 are managed by RPMPD */
 
index 7748b74..cbe11c0 100644 (file)
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
                autorepeat;
 
-               button@0 {
+               button {
                        label = "Volume Up";
                        gpios = <&pm8994_gpios 3 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
                vdd_l17_29-supply = <&vph_pwr>;
                vdd_l20_21-supply = <&vph_pwr>;
                vdd_l25-supply = <&pm8994_s5>;
-               vdd_lvs1_2 = <&pm8994_s4>;
+               vdd_lvs1_2-supply = <&pm8994_s4>;
 
                /* S1, S2, S6 and S12 are managed by RPMPD */
 
index cc038f9..61ec905 100644 (file)
@@ -64,7 +64,7 @@
                compatible = "gpio-keys";
                autorepeat;
 
-               volupkey {
+               volup-key {
                        label = "Volume Up";
                        gpios = <&pm8994_gpios 3 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
@@ -73,7 +73,7 @@
                        debounce-interval = <15>;
                };
 
-               camsnapkey {
+               camsnap-key {
                        label = "Camera Snapshot";
                        gpios = <&pm8994_gpios 4 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
@@ -82,7 +82,7 @@
                        debounce-interval = <15>;
                };
 
-               camfocuskey {
+               camfocus-key {
                        label = "Camera Focus";
                        gpios = <&pm8994_gpios 5 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
 
                label = "GPIO Hall Effect Sensor";
 
-               hall-front-sensor {
+               event-hall-front-sensor {
                        label = "Hall Effect Front Sensor";
                        gpios = <&tlmm 42 GPIO_ACTIVE_HIGH>;
                        linux,input-type = <EV_SW>;
                        linux,can-disable;
                };
 
-               hall-back-sensor {
+               event-hall-back-sensor {
                        label = "Hall Effect Back Sensor";
                        gpios = <&tlmm 75 GPIO_ACTIVE_HIGH>;
                        linux,input-type = <EV_SW>;
 };
 
 &pm8994_gpios {
-       bt_en_gpios: bt_en_gpios {
+       bt_en_gpios: bt-en-gpios-state {
                pinconf {
                        pins = "gpio19";
                        function = PMIC_GPIO_FUNC_NORMAL;
                };
        };
 
-       divclk4_pin_a: divclk4 {
+       divclk4_pin_a: divclk4-state {
                pinconf {
                        pins = "gpio18";
                        function = PMIC_GPIO_FUNC_FUNC2;
         * TODO: remove once a driver is available
         * TODO: add VBUS GPIO 5
         */
-       hd3ss460_pol: pol_low {
+       hd3ss460_pol: pol-low-state {
                pins = "gpio8";
-               drive-strength = <3>;
+               function = PMIC_GPIO_FUNC_NORMAL;
+               qcom,drive-strength = <3>;
                bias-pull-down;
        };
 
-       hd3ss460_amsel: amsel_high {
+       hd3ss460_amsel: amsel-high-state {
                pins = "gpio9";
-               drive-strength = <1>;
+               function = PMIC_GPIO_FUNC_NORMAL;
+               qcom,drive-strength = <1>;
                bias-pull-up;
        };
 
-       hd3ss460_en: en_high {
+       hd3ss460_en: en-high-state {
                pins = "gpio10";
-               drive-strength = <1>;
+               function = PMIC_GPIO_FUNC_NORMAL;
+               qcom,drive-strength = <1>;
                bias-pull-up;
        };
 };
index e5a45af..f430d79 100644 (file)
        /* Kitakami firmware doesn't support PSCI */
        /delete-node/ psci;
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
                autorepeat;
 
-               button@0 {
+               button-0 {
                        label = "Volume Down";
                        gpios = <&pm8994_gpios 2 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
@@ -42,7 +40,7 @@
                        debounce-interval = <15>;
                };
 
-               button@1 {
+               button-1 {
                        label = "Volume Up";
                        gpios = <&pm8994_gpios 3 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
@@ -51,7 +49,7 @@
                        debounce-interval = <15>;
                };
 
-               button@2 {
+               button-2 {
                        label = "Camera Snapshot";
                        gpios = <&pm8994_gpios 4 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
@@ -60,7 +58,7 @@
                        debounce-interval = <15>;
                };
 
-               button@3 {
+               button-3 {
                        label = "Camera Focus";
                        gpios = <&pm8994_gpios 5 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
index 0318d42..8bc6c07 100644 (file)
                CPU6: cpu@102 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a57";
-                       reg = <0x0 0x101>;
+                       reg = <0x0 0x102>;
                        enable-method = "psci";
                        next-level-cache = <&L2_1>;
                };
                CPU7: cpu@103 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a57";
-                       reg = <0x0 0x101>;
+                       reg = <0x0 0x103>;
                        enable-method = "psci";
                        next-level-cache = <&L2_1>;
                };
                        };
                };
 
-               sdhc1: sdhci@f9824900 {
+               sdhc1: mmc@f9824900 {
                        compatible = "qcom,msm8994-sdhci", "qcom,sdhci-msm-v4";
                        reg = <0xf9824900 0x1a0>, <0xf9824000 0x800>;
                        reg-names = "hc_mem", "core_mem";
                                     <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "hc_irq", "pwr_irq";
 
-                       clocks = <&gcc GCC_SDCC1_APPS_CLK>,
-                                <&gcc GCC_SDCC1_AHB_CLK>,
+                       clocks = <&gcc GCC_SDCC1_AHB_CLK>,
+                                <&gcc GCC_SDCC1_APPS_CLK>,
                                 <&xo_board>;
-                       clock-names = "core", "iface", "xo";
+                       clock-names = "iface", "core", "xo";
 
                        pinctrl-names = "default", "sleep";
                        pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>;
                        status = "disabled";
                };
 
-               sdhc2: sdhci@f98a4900 {
+               sdhc2: mmc@f98a4900 {
                        compatible = "qcom,msm8994-sdhci", "qcom,sdhci-msm-v4";
                        reg = <0xf98a4900 0x11c>, <0xf98a4000 0x800>;
                        reg-names = "hc_mem", "core_mem";
                                <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "hc_irq", "pwr_irq";
 
-                       clocks = <&gcc GCC_SDCC2_APPS_CLK>,
-                               <&gcc GCC_SDCC2_AHB_CLK>,
-                               <&xo_board>;
-                       clock-names = "core", "iface", "xo";
+                       clocks = <&gcc GCC_SDCC2_AHB_CLK>,
+                                <&gcc GCC_SDCC2_APPS_CLK>,
+                                <&xo_board>;
+                       clock-names = "iface", "core", "xo";
 
                        pinctrl-names = "default", "sleep";
                        pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on>;
                                               <600000000>;
                };
 
-               ocmem: ocmem@fdd00000 {
+               ocmem: sram@fdd00000 {
                        compatible = "qcom,msm8974-ocmem";
                        reg = <0xfdd00000 0x2000>,
                              <0xfec00000 0x200000>;
                        reg-names = "ctrl", "mem";
+                       ranges = <0 0xfec00000 0x200000>;
                        clocks = <&rpmcc RPM_SMD_OCMEMGX_CLK>,
                                 <&mmcc OCMEMCX_OCMEMNOC_CLK>;
                        clock-names = "core", "iface";
diff --git a/arch/arm64/boot/dts/qcom/msm8996-pmi8996-sony-xperia-tone-dora.dts b/arch/arm64/boot/dts/qcom/msm8996-pmi8996-sony-xperia-tone-dora.dts
deleted file mode 100644 (file)
index b018693..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-/*
- * Copyright (c) 2021, Konrad Dybcio <konrad.dybcio@somainline.org>
- */
-
-#include "msm8996-sony-xperia-tone-dora.dts"
-#include "pmi8996.dtsi"
-
-/ {
-       model = "Sony Xperia X Performance (PMI8996)";
-};
diff --git a/arch/arm64/boot/dts/qcom/msm8996-pmi8996-sony-xperia-tone-kagura.dts b/arch/arm64/boot/dts/qcom/msm8996-pmi8996-sony-xperia-tone-kagura.dts
deleted file mode 100644 (file)
index 842ea3c..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-/*
- * Copyright (c) 2021, Konrad Dybcio <konrad.dybcio@somainline.org>
- */
-
-#include "msm8996-sony-xperia-tone-kagura.dts"
-#include "pmi8996.dtsi"
-
-/ {
-       model = "Sony Xperia XZ (PMI8996)";
-};
diff --git a/arch/arm64/boot/dts/qcom/msm8996-pmi8996-sony-xperia-tone-keyaki.dts b/arch/arm64/boot/dts/qcom/msm8996-pmi8996-sony-xperia-tone-keyaki.dts
deleted file mode 100644 (file)
index b3f9062..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-/*
- * Copyright (c) 2021, Konrad Dybcio <konrad.dybcio@somainline.org>
- */
-
-#include "msm8996-sony-xperia-tone-keyaki.dts"
-#include "pmi8996.dtsi"
-
-/ {
-       model = "Sony Xperia XZs (PMI8996)";
-};
index ca3c633..e165b5e 100644 (file)
@@ -8,6 +8,7 @@
 #include "msm8996.dtsi"
 #include "pm8994.dtsi"
 #include "pmi8994.dtsi"
+#include "pmi8996.dtsi"
 #include <dt-bindings/input/input.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
@@ -20,7 +21,6 @@
 
 / {
        qcom,msm-id = <246 0x30001>; /* MSM8996 V3.1 (Final) */
-       qcom,pmic-id = <0x20009 0x2000a 0 0>; /* PM8994 + PMI8994 */
        qcom,board-id = <8 0>;
 
        chosen {
                        ecc-size = <16>;
                };
 
-               cont_splash_mem: memory@83401000 {
-                       reg = <0 0x83401000 0 0x23ff000>;
-                       no-map;
-               };
-
                adsp_mem: adsp@8ea00000 {
                        reg = <0x0 0x8ea00000 0x0 0x1a00000>;
                        no-map;
         * probably a reason for it, and just to be on the safe side, we follow suit.
         */
        pm8994_gpios_defaults: pm8994-gpios-default-state {
-               pm8994-gpio1-nc {
+               pm8994-gpio1-nc-pins {
                        pins = "gpio1";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        drive-push-pull;
                        bias-high-impedance;
                };
 
-               vol-down-n {
+               vol-down-n-pins {
                        pins = "gpio2";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        drive-push-pull;
                        power-source = <PM8994_GPIO_S4>;
                };
 
-               vol-up-n {
+               vol-up-n-pins {
                        pins = "gpio3";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        drive-push-pull;
                        power-source = <PM8994_GPIO_S4>;
                };
 
-               camera-snapshot-n {
+               camera-snapshot-n-pins {
                        pins = "gpio4";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        drive-push-pull;
                        power-source = <PM8994_GPIO_S4>;
                };
 
-               camera-focus-n {
+               camera-focus-n-pins {
                        pins = "gpio5";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        drive-push-pull;
                        power-source = <PM8994_GPIO_S4>;
                };
 
-               pm8994-gpio6-nc {
+               pm8994-gpio6-nc-pins {
                        pins = "gpio6";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        drive-push-pull;
                        power-source = <PM8994_GPIO_VPH>;
                };
 
-               nfc-download {
+               nfc-download-pins {
                        pins = "gpio7";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        output-low;
                        power-source = <PM8994_GPIO_S4>;
                };
 
-               pm8994-gpio8-nc {
+               pm8994-gpio8-nc-pins {
                        pins = "gpio8";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        output-low;
                        power-source = <PM8994_GPIO_VPH>;
                };
 
-               pm8994-gpio9-nc {
+               pm8994-gpio9-nc-pins {
                        pins = "gpio9";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        output-high;
                        power-source = <PM8994_GPIO_VPH>;
                };
 
-               nfc-clock {
+               nfc-clock-pins {
                        pins = "gpio10";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        input-enable;
                        power-source = <PM8994_GPIO_S4>;
                };
 
-               pm8994-gpio11-nc {
+               pm8994-gpio11-nc-pins {
                        pins = "gpio11";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        drive-push-pull;
                        power-source = <PM8994_GPIO_VPH>;
                };
 
-               pm8994-gpio12-nc {
+               pm8994-gpio12-nc-pins {
                        pins = "gpio12";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        drive-push-pull;
                        power-source = <PM8994_GPIO_VPH>;
                };
 
-               ear-enable {
+               ear-enable-pins {
                        pins = "gpio13";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        output-high;
                        power-source = <PM8994_GPIO_S4>;
                };
 
-               pm8994-gpio14-nc {
+               pm8994-gpio14-nc-pins {
                        pins = "gpio14";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        drive-push-pull;
                        power-source = <PM8994_GPIO_VPH>;
                };
 
-               pm-divclk1-gpio {
+               pm-divclk1-gpio-pins {
                        pins = "gpio15";
                        function = "func1";
                        output-high;
                        power-source = <PM8994_GPIO_VPH>;
                };
 
-               pmi-clk-gpio {
+               pmi-clk-gpio-pins {
                        pins = "gpio16";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        drive-push-pull;
                };
 
-               pm8994-gpio17-nc {
+               pm8994-gpio17-nc-pins {
                        pins = "gpio17";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        drive-push-pull;
                        power-source = <PM8994_GPIO_VPH>;
                };
 
-               rome-sleep {
+               rome-sleep-pins {
                        pins = "gpio18";
                        function = PMIC_GPIO_FUNC_FUNC2;
                        output-low;
                        power-source = <PM8994_GPIO_S4>;
                };
 
-               pm8994-gpio19-nc {
+               pm8994-gpio19-nc-pins {
                        pins = "gpio19";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        output-low;
                        power-source = <PM8994_GPIO_VPH>;
                };
 
-               pm8994-gpio22-nc {
+               pm8994-gpio22-nc-pins {
                        pins = "gpio22";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        drive-push-pull;
                "RF_ID";
 
        pm8994_mpps_defaults: pm8994-mpps-default-state {
-               lcd-id_adc-mpp {
+               lcd-id_adc-mpp-pins {
                        pins = "mpp2";
                        function = "analog";
                        input-enable;
                        qcom,amux-route = <PMIC_MPP_AMUX_ROUTE_CH6>;
                };
 
-               pm-mpp4-nc {
+               pm-mpp4-nc-pins {
                        pins = "mpp4";
                        function = "digital";
                        bias-high-impedance;
                        power-source = <PM8994_GPIO_VPH>;
                };
 
-               flash-therm-mpp {
+               flash-therm-mpp-pins {
                        pins = "mpp5";
                        function = "analog";
                        input-enable;
                        qcom,amux-route = <PMIC_MPP_AMUX_ROUTE_CH5>;
                };
 
-               mpp6-nc {
+               mpp6-nc-pins {
                        pins = "mpp6";
                        function = "digital";
                        bias-high-impedance;
                };
 
-               rf-id-mpp {
+               rf-id-mpp-pins {
                        pins = "mpp8";
                        function = "analog";
                        input-enable;
                "NC";
 
        pmi8994_gpios_defaults: pmi8994-gpios-default-state {
-               vib-ldo-en-gpio {
+               vib-ldo-en-gpio-pins {
                        pins = "gpio1";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        drive-push-pull;
                        power-source = <PM8994_GPIO_S4>;
                };
 
-               pmi-gpio2-nc {
+               pmi-gpio2-nc-pins {
                        pins = "gpio2";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        drive-push-pull;
                        power-source = <PM8994_GPIO_VPH>;
                };
 
-               pmi-gpio3-nc {
+               pmi-gpio3-nc-pins {
                        pins = "gpio3";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        drive-push-pull;
                        power-source = <PM8994_GPIO_VPH>;
                };
 
-               pmi-gpio4-nc {
+               pmi-gpio4-nc-pins {
                        pins = "gpio4";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        drive-push-pull;
                        power-source = <PM8994_GPIO_S4>;
                };
 
-               pmi-gpio5-nc {
+               pmi-gpio5-nc-pins {
                        pins = "gpio5";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        drive-push-pull;
                        power-source = <PM8994_GPIO_S4>;
                };
 
-               pmi-gpio6-nc {
+               pmi-gpio6-nc-pins {
                        pins = "gpio6";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        drive-push-pull;
                        power-source = <PM8994_GPIO_S4>;
                };
 
-               pmi-gpio7-nc {
+               pmi-gpio7-nc-pins {
                        pins = "gpio7";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        drive-push-pull;
                        power-source = <PM8994_GPIO_S4>;
                };
 
-               pmi-gpio8-nc {
+               pmi-gpio8-nc-pins {
                        pins = "gpio8";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        drive-push-pull;
                        power-source = <PM8994_GPIO_S4>;
                };
 
-               usb-switch-sel {
+               usb-switch-sel-pins {
                        pins = "gpio9";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        drive-push-pull;
                };
 
-               pmi-gpio10-nc {
+               pmi-gpio10-nc-pins {
                        pins = "gpio10";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        output-low;
index a7090be..6276499 100644 (file)
                };
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               vol_up {
+               key-vol-up {
                        label = "Volume Up";
                        gpios = <&pm8994_gpios 2 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
@@ -49,7 +49,7 @@
                        debounce-interval = <15>;
                };
 
-               dome {
+               key-dome {
                        label = "Home";
                        gpios = <&tlmm 34 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_HOME>;
 };
 
 &pm8994_gpios {
-       wlan_en_default: wlan-en-default {
+       wlan_en_default: wlan-en-state {
                pins = "gpio8";
                function = PMIC_GPIO_FUNC_NORMAL;
                output-low;
                bias-disable;
        };
 
-       rome_enable_default: rome-enable-default {
+       rome_enable_default: rome-enable-state {
                pins = "gpio9";
                function = PMIC_GPIO_FUNC_NORMAL;
                output-high;
                power-source = <PM8994_GPIO_VPH>;
        };
 
-       divclk1_default: divclk1_default {
+       divclk1_default: divclk1-state {
                pins = "gpio15";
                function = PMIC_GPIO_FUNC_FUNC1;
                bias-disable;
                qcom,drive-strength = <PMIC_GPIO_STRENGTH_LOW>;
        };
 
-       divclk4_pin_a: divclk4 {
+       divclk4_pin_a: divclk4-state {
                pins = "gpio18";
                function = PMIC_GPIO_FUNC_FUNC2;
                bias-disable;
index 22978d0..25f30ec 100644 (file)
 &sound {
        compatible = "qcom,apq8096-sndcard";
        model = "gemini";
-       audio-routing = "RX_BIAS", "MCLK",
+       audio-routing = "RX_BIAS", "MCLK",
                "MM_DL1",  "MultiMedia1 Playback",
                "MM_DL2",  "MultiMedia2 Playback",
                "MultiMedia3 Capture", "MM_UL3";
                "UIM_BATT_ALARM",       /* GPIO_21 */
                "NC";                   /* GPIO_22 */
 
-       divclk2_pin_a: divclk2 {
+       divclk2_pin_a: divclk2-state {
                pins = "gpio16";
                function = PMIC_GPIO_FUNC_FUNC2;
                bias-disable;
diff --git a/arch/arm64/boot/dts/qcom/msm8996-xiaomi-natrium.dts b/arch/arm64/boot/dts/qcom/msm8996-xiaomi-natrium.dts
new file mode 100644 (file)
index 0000000..ff4673e
--- /dev/null
@@ -0,0 +1,414 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2022, Alec Su <ae40515@yahoo.com.tw>
+ */
+
+/dts-v1/;
+
+#include "msm8996-xiaomi-common.dtsi"
+#include "pmi8996.dtsi"
+#include <dt-bindings/sound/qcom,q6afe.h>
+#include <dt-bindings/sound/qcom,q6asm.h>
+
+/ {
+       model = "Xiaomi Mi 5s Plus";
+       compatible = "xiaomi,natrium", "qcom,msm8996";
+       chassis-type = "handset";
+       qcom,msm-id = <305 0x10000>;
+       qcom,board-id = <47 0>;
+};
+
+&adsp_pil {
+       firmware-name = "qcom/msm8996/natrium/adsp.mbn";
+};
+
+&blsp2_i2c6 {
+       touchscreen@20 {
+               compatible = "syna,rmi4-i2c";
+               reg = <0x20>;
+               interrupt-parent = <&tlmm>;
+               interrupts = <125 IRQ_TYPE_LEVEL_LOW>;
+               vdd-supply = <&vdd_3v2_tp>;
+               syna,reset-delay-ms = <200>;
+               syna,startup-delay-ms = <5>;
+
+               pinctrl-names = "default", "sleep";
+               pinctrl-0 = <&touchscreen_default>;
+               pinctrl-1 = <&touchscreen_sleep>;
+       };
+};
+
+&dsi0 {
+       status = "okay";
+
+       vdda-supply = <&vreg_l2a_1p25>;
+       vcca-supply = <&vreg_l28a_0p925>;
+
+       pinctrl-names = "default", "sleep";
+       pinctrl-0 = <&mdss_dsi_default &mdss_te_default>;
+       pinctrl-1 = <&mdss_dsi_sleep &mdss_te_sleep>;
+
+       panel: panel@0 {
+               compatible = "jdi,fhd-r63452";
+               reg = <0>;
+               reset-gpios = <&tlmm 8 GPIO_ACTIVE_LOW>;
+               backlight = <&pmi8994_wled>;
+
+               port {
+                       panel_in: endpoint {
+                               remote-endpoint = <&dsi0_out>;
+                       };
+               };
+       };
+};
+
+&dsi0_out {
+       remote-endpoint = <&panel_in>;
+};
+
+&gpu {
+       zap-shader {
+               firmware-name = "qcom/msm8996/natrium/a530_zap.mbn";
+       };
+};
+
+&mss_pil {
+       firmware-name = "qcom/msm8996/natrium/mba.mbn",
+                       "qcom/msm8996/natrium/modem.mbn";
+};
+
+&pmi8994_wled {
+       status = "okay";
+
+       qcom,enabled-strings = <0 1>;
+       qcom,switching-freq = <600>;
+};
+
+&q6asmdai {
+       dai@0 {
+               reg = <0>;
+       };
+
+       dai@1 {
+               reg = <1>;
+       };
+
+       dai@2 {
+               reg = <2>;
+       };
+};
+
+&slpi_pil {
+       firmware-name = "qcom/msm8996/natrium/slpi.mbn";
+};
+
+&sound {
+       compatible = "qcom,apq8096-sndcard";
+       model = "natrium";
+       audio-routing = "RX_BIAS", "MCLK";
+
+       mm1-dai-link {
+               link-name = "MultiMedia1";
+               cpu {
+                       sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA1>;
+               };
+       };
+
+       mm2-dai-link {
+               link-name = "MultiMedia2";
+               cpu {
+                       sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA2>;
+               };
+       };
+
+       mm3-dai-link {
+               link-name = "MultiMedia3";
+               cpu {
+                       sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA3>;
+               };
+       };
+
+       slim-dai-link {
+               link-name = "SLIM Playback";
+               cpu {
+                       sound-dai = <&q6afedai SLIMBUS_6_RX>;
+               };
+
+               platform {
+                       sound-dai = <&q6routing>;
+               };
+
+               codec {
+                       sound-dai = <&wcd9335 6>;
+               };
+       };
+
+       slimcap-dai-link {
+               link-name = "SLIM Capture";
+               cpu {
+                       sound-dai = <&q6afedai SLIMBUS_0_TX>;
+               };
+
+               platform {
+                       sound-dai = <&q6routing>;
+               };
+
+               codec {
+                       sound-dai = <&wcd9335 1>;
+               };
+       };
+};
+
+&venus {
+       firmware-name = "qcom/msm8996/natrium/venus.mbn";
+};
+
+&rpm_requests {
+       pm8994-regulators {
+               vreg_l3a_0p875: l3 {
+                       regulator-name = "vreg_l3a_0p875";
+                       regulator-min-microvolt = <850000>;
+                       regulator-max-microvolt = <1300000>;
+               };
+               vreg_l11a_1p1: l11 {
+                       regulator-name = "vreg_l11a_1p1";
+                       regulator-min-microvolt = <1100000>;
+                       regulator-max-microvolt = <1100000>;
+               };
+               vreg_l17a_2p8: l17 {
+                       regulator-name = "vreg_l17a_2p8";
+                       regulator-min-microvolt = <2800000>;
+                       regulator-max-microvolt = <2800000>;
+               };
+               vreg_l18a_2p8: l18 {
+                       regulator-name = "vreg_l18a_2p8";
+                       regulator-min-microvolt = <2800000>;
+                       regulator-max-microvolt = <2800000>;
+               };
+               vreg_l29a_2p8: l29 {
+                       regulator-name = "vreg_l29a_2p8";
+                       regulator-min-microvolt = <2800000>;
+                       regulator-max-microvolt = <2800000>;
+               };
+       };
+};
+
+&pm8994_gpios {
+       gpio-line-names =
+               "NC",                   /* GPIO_1  */
+               "VOL_UP_N",             /* GPIO_2  */
+               "SPKR_ID",              /* GPIO_3  */
+               "PWM_HAPTICS",          /* GPIO_4  */
+               "INFARED_DRV",          /* GPIO_5  */
+               "NC",                   /* GPIO_6  */
+               "KEYPAD_LED_EN_A",      /* GPIO_7  */
+               "WL_EN",                /* GPIO_8  */
+               "3P3_ENABLE",           /* GPIO_9  */
+               "NC",                   /* GPIO_10 */
+               "NC",                   /* GPIO_11 */
+               "NC",                   /* GPIO_12 */
+               "NC",                   /* GPIO_13 */
+               "NC",                   /* GPIO_14 */
+               "DIVCLK1_CDC",          /* GPIO_15 */
+               "DIVCLK2_HAPTICS",      /* GPIO_16 */
+               "NC",                   /* GPIO_17 */
+               "32KHz_CLK_IN",         /* GPIO_18 */
+               "BT_EN",                /* GPIO_19 */
+               "PMIC_SLB",             /* GPIO_20 */
+               "UIM_BATT_ALARM",       /* GPIO_21 */
+               "NC";                   /* GPIO_22 */
+};
+
+&pm8994_mpps {
+       gpio-line-names =
+               "NC",                   /* MPP_1 */
+               "CCI_TIMER1",           /* MPP_2 */
+               "PMIC_SLB",             /* MPP_3 */
+               "EXT_FET_WLED_PWR_EN_N",/* MPP_4 */
+               "NC",                   /* MPP_5 */
+               "NC",                   /* MPP_6 */
+               "NC",                   /* MPP_7 */
+               "NC";                   /* MPP_8 */
+};
+
+&pmi8994_gpios {
+       gpio-line-names =
+               "NC",                   /* GPIO_1  */
+               "SPKR_PA_EN",           /* GPIO_2  */
+               "NC",                   /* GPIO_3  */
+               "NC",                   /* GPIO_4  */
+               "NC",                   /* GPIO_5  */
+               "NC",                   /* GPIO_6  */
+               "NC",                   /* GPIO_7  */
+               "NC",                   /* GPIO_8  */
+               "NC",                   /* GPIO_9  */
+               "NC";                   /* GPIO_10 */
+};
+
+&tlmm {
+       gpio-line-names =
+               "ESE_SPI_MOSI",         /* GPIO_0   */
+               "ESE_SPI_MISO",         /* GPIO_1   */
+               "NC",                   /* GPIO_2   */
+               "ESE_SPI_CLK",          /* GPIO_3   */
+               "MSM_UART_TX",          /* GPIO_4   */
+               "MSM_UART_RX",          /* GPIO_5   */
+               "NFC_I2C_SDA",          /* GPIO_6   */
+               "NFC_I2C_SCL",          /* GPIO_7   */
+               "LCD0_RESET_N",         /* GPIO_8   */
+               "NFC_IRQ",              /* GPIO_9   */
+               "LCD_TE",               /* GPIO_10  */
+               "LCD_ID_DET1",          /* GPIO_11  */
+               "NFC_DISABLE",          /* GPIO_12  */
+               "CAM_MCLK0",            /* GPIO_13  */
+               "CAM_MCLK1",            /* GPIO_14  */
+               "CAM_MCLK2",            /* GPIO_15  */
+               "ESE_PWR_REQ",          /* GPIO_16  */
+               "CCI_I2C_SDA0",         /* GPIO_17  */
+               "CCI_I2C_SCL0",         /* GPIO_18  */
+               "CCI_I2C_SDA1",         /* GPIO_19  */
+               "CCI_I2C_SCL1",         /* GPIO_20  */
+               "NFC_DWL_REQ",          /* GPIO_21  */
+               "CCI_TIMER1",           /* GPIO_22  */
+               "WEBCAM1_RESET_N",      /* GPIO_23  */
+               "ESE_IRQ",              /* GPIO_24  */
+               "NC",                   /* GPIO_25  */
+               "WEBCAM1_STANDBY",      /* GPIO_26  */
+               "NC",                   /* GPIO_27  */
+               "NC",                   /* GPIO_28  */
+               "NC",                   /* GPIO_29  */
+               "CAM_VDD_1P2_EN_2",     /* GPIO_30  */
+               "CAM_RESET_0",          /* GPIO_31  */
+               "CAM_RESET_1",          /* GPIO_32  */
+               "NC",                   /* GPIO_33  */
+               "NC",                   /* GPIO_34  */
+               "PCI_E0_RST_N",         /* GPIO_35  */
+               "PCI_E0_CLKREQ_N",      /* GPIO_36  */
+               "PCI_E0_WAKE",          /* GPIO_37  */
+               "CHARGER_INT",          /* GPIO_38  */
+               "CHARGER_RESET",        /* GPIO_39  */
+               "NC",                   /* GPIO_40  */
+               "QCA_UART_TXD",         /* GPIO_41  */
+               "QCA_UART_RXD",         /* GPIO_42  */
+               "QCA_UART_CTS",         /* GPIO_43  */
+               "QCA_UART_RTS",         /* GPIO_44  */
+               "MAWC_UART_TX",         /* GPIO_45  */
+               "MAWC_UART_RX",         /* GPIO_46  */
+               "NC",                   /* GPIO_47  */
+               "NC",                   /* GPIO_48  */
+               "NC",                   /* GPIO_49  */
+               "FP_SPI_RST",           /* GPIO_50  */
+               "TYPEC_I2C_SDA",        /* GPIO_51  */
+               "TYPEC_I2C_SCL",        /* GPIO_52  */
+               "CODEC_INT2_N",         /* GPIO_53  */
+               "CODEC_INT1_N",         /* GPIO_54  */
+               "APPS_I2C7_SDA",        /* GPIO_55  */
+               "APPS_I2C7_SCL",        /* GPIO_56  */
+               "FORCE_USB_BOOT",       /* GPIO_57  */
+               "NC",                   /* GPIO_58  */
+               "NC",                   /* GPIO_59  */
+               "NC",                   /* GPIO_60  */
+               "NC",                   /* GPIO_61  */
+               "ESE_RSTN",             /* GPIO_62  */
+               "TYPEC_INT",            /* GPIO_63  */
+               "CODEC_RESET_N",        /* GPIO_64  */
+               "PCM_CLK",              /* GPIO_65  */
+               "PCM_SYNC",             /* GPIO_66  */
+               "PCM_DIN",              /* GPIO_67  */
+               "PCM_DOUT",             /* GPIO_68  */
+               "CDC_44K1_CLK",         /* GPIO_69  */
+               "SLIMBUS_CLK",          /* GPIO_70  */
+               "SLIMBUS_DATA0",        /* GPIO_71  */
+               "SLIMBUS_DATA1",        /* GPIO_72  */
+               "LDO_5V_IN_EN",         /* GPIO_73  */
+               "TYPEC_EN_N",           /* GPIO_74  */
+               "NC",                   /* GPIO_75  */
+               "NC",                   /* GPIO_76  */
+               "NC",                   /* GPIO_77  */
+               "NC",                   /* GPIO_78  */
+               "NC",                   /* GPIO_79  */
+               "SENSOR_RESET_N",       /* GPIO_80  */
+               "FP_SPI_MOSI",          /* GPIO_81  */
+               "FP_SPI_MISO",          /* GPIO_82  */
+               "FP_SPI_CS_N",          /* GPIO_83  */
+               "FP_SPI_CLK",           /* GPIO_84  */
+               "NC",                   /* GPIO_85  */
+               "CAM_VDD_1P2_EN",       /* GPIO_86  */
+               "MSM_TS_I2C_SDA",       /* GPIO_87  */
+               "MSM_TS_I2C_SCL",       /* GPIO_88  */
+               "TS_RESOUT_N",          /* GPIO_89  */
+               "ESE_SPI_CS_N",         /* GPIO_90  */
+               "NC",                   /* GPIO_91  */
+               "CAM2_AVDD_EN",         /* GPIO_92  */
+               "CAM2_VCM_EN",          /* GPIO_93  */
+               "NC",                   /* GPIO_94  */
+               "NC",                   /* GPIO_95  */
+               "NC",                   /* GPIO_96  */
+               "GRFC_0",               /* GPIO_97  */
+               "GRFC_1",               /* GPIO_98  */
+               "NC",                   /* GPIO_99  */
+               "GRFC_3",               /* GPIO_100 */
+               "GRFC_4",               /* GPIO_101 */
+               "GRFC_5",               /* GPIO_102 */
+               "NC",                   /* GPIO_103 */
+               "GRFC_7",               /* GPIO_104 */
+               "UIM2_DATA",            /* GPIO_105 */
+               "UIM2_CLK",             /* GPIO_106 */
+               "UIM2_RESET",           /* GPIO_107 */
+               "UIM2_PRESENT",         /* GPIO_108 */
+               "UIM1_DATA",            /* GPIO_109 */
+               "UIM1_CLK",             /* GPIO_110 */
+               "UIM1_RESET",           /* GPIO_111 */
+               "UIM1_PRESENT",         /* GPIO_112 */
+               "UIM_BATT_ALARM",       /* GPIO_113 */
+               "GRFC_8",               /* GPIO_114 */
+               "GRFC_9",               /* GPIO_115 */
+               "TX_GTR_THRES",         /* GPIO_116 */
+               "ACCEL_INT",            /* GPIO_117 */
+               "GYRO_INT",             /* GPIO_118 */
+               "COMPASS_INT",          /* GPIO_119 */
+               "PROXIMITY_INT_N",      /* GPIO_120 */
+               "FP_IRQ",               /* GPIO_121 */
+               "P_SENSE",              /* GPIO_122 */
+               "HALL_INTR2",           /* GPIO_123 */
+               "HALL_INTR1",           /* GPIO_124 */
+               "TS_INT_N",             /* GPIO_125 */
+               "NC",                   /* GPIO_126 */
+               "GRFC_11",              /* GPIO_127 */
+               "NC",                   /* GPIO_128 */
+               "EXT_GPS_LNA_EN",       /* GPIO_129 */
+               "NC",                   /* GPIO_130 */
+               "LCD_ID_DET2",          /* GPIO_131 */
+               "LCD_TE2",              /* GPIO_132 */
+               "GRFC_14",              /* GPIO_133 */
+               "GSM_TX2_PHASE_D",      /* GPIO_134 */
+               "NC",                   /* GPIO_135 */
+               "GRFC_15",              /* GPIO_136 */
+               "RFFE3_DATA",           /* GPIO_137 */
+               "RFFE3_CLK",            /* GPIO_138 */
+               "NC",                   /* GPIO_139 */
+               "NC",                   /* GPIO_140 */
+               "RFFE5_DATA",           /* GPIO_141 */
+               "RFFE5_CLK",            /* GPIO_142 */
+               "NC",                   /* GPIO_143 */
+               "COEX_UART_TX",         /* GPIO_144 */
+               "COEX_UART_RX",         /* GPIO_145 */
+               "RFFE2_DATA",           /* GPIO_146 */
+               "RFFE2_CLK",            /* GPIO_147 */
+               "RFFE1_DATA",           /* GPIO_148 */
+               "RFFE1_CLK";            /* GPIO_149 */
+
+       touchscreen_default: touchscreen-default {
+               pins = "gpio89", "gpio125";
+               function = "gpio";
+               drive-strength = <10>;
+               bias-pull-up;
+       };
+
+       touchscreen_sleep: touchscreen-sleep {
+               pins = "gpio89", "gpio125";
+               function = "gpio";
+               drive-strength = <2>;
+               bias-disable;
+       };
+};
index 1e2dd67..30a9e4b 100644 (file)
 &sound {
        compatible = "qcom,apq8096-sndcard";
        model = "scorpio";
-       audio-routing = "RX_BIAS", "MCLK";
+       audio-routing = "RX_BIAS", "MCLK";
 
        mm1-dai-link {
                link-name = "MultiMedia1";
index 9932186..742eac4 100644 (file)
@@ -6,6 +6,7 @@
 #include <dt-bindings/clock/qcom,gcc-msm8996.h>
 #include <dt-bindings/clock/qcom,mmcc-msm8996.h>
 #include <dt-bindings/clock/qcom,rpmcc.h>
+#include <dt-bindings/interconnect/qcom,msm8996.h>
 #include <dt-bindings/power/qcom-rpmpd.h>
 #include <dt-bindings/soc/qcom,apr.h>
 #include <dt-bindings/thermal/thermal.h>
 
        firmware {
                scm {
-                       compatible = "qcom,scm-msm8996";
+                       compatible = "qcom,scm-msm8996", "qcom,scm";
                        qcom,dload-mode = <&tcsr 0x13000>;
                };
        };
                        rpmcc: qcom,rpmcc {
                                compatible = "qcom,rpmcc-msm8996", "qcom,rpmcc";
                                #clock-cells = <1>;
+                               clocks = <&xo_board>;
+                               clock-names = "xo";
                        };
 
                        rpmpd: power-controller {
                ranges = <0 0 0 0xffffffff>;
                compatible = "simple-bus";
 
-               pcie_phy: phy@34000 {
+               pcie_phy: phy-wrapper@34000 {
                        compatible = "qcom,msm8996-qmp-pcie-phy";
                        reg = <0x00034000 0x488>;
                        #address-cells = <1>;
                        #size-cells = <1>;
-                       ranges;
+                       ranges = <0x0 0x00034000 0x4000>;
 
                        clocks = <&gcc GCC_PCIE_PHY_AUX_CLK>,
                                <&gcc GCC_PCIE_PHY_CFG_AHB_CLK>,
                                <&gcc GCC_PCIE_PHY_COM_BCR>,
                                <&gcc GCC_PCIE_PHY_COM_NOCSR_BCR>;
                        reset-names = "phy", "common", "cfg";
+
                        status = "disabled";
 
-                       pciephy_0: phy@35000 {
-                               reg = <0x00035000 0x130>,
-                                     <0x00035200 0x200>,
-                                     <0x00035400 0x1dc>;
-                               #phy-cells = <0>;
+                       pciephy_0: phy@1000 {
+                               reg = <0x1000 0x130>,
+                                     <0x1200 0x200>,
+                                     <0x1400 0x1dc>;
 
-                               #clock-cells = <1>;
-                               clock-output-names = "pcie_0_pipe_clk_src";
                                clocks = <&gcc GCC_PCIE_0_PIPE_CLK>;
                                clock-names = "pipe0";
                                resets = <&gcc GCC_PCIE_0_PHY_BCR>;
                                reset-names = "lane0";
-                       };
 
-                       pciephy_1: phy@36000 {
-                               reg = <0x00036000 0x130>,
-                                     <0x00036200 0x200>,
-                                     <0x00036400 0x1dc>;
+                               #clock-cells = <0>;
+                               clock-output-names = "pcie_0_pipe_clk_src";
+
                                #phy-cells = <0>;
+                       };
+
+                       pciephy_1: phy@2000 {
+                               reg = <0x2000 0x130>,
+                                     <0x2200 0x200>,
+                                     <0x2400 0x1dc>;
 
-                               clock-output-names = "pcie_1_pipe_clk_src";
                                clocks = <&gcc GCC_PCIE_1_PIPE_CLK>;
                                clock-names = "pipe1";
                                resets = <&gcc GCC_PCIE_1_PHY_BCR>;
                                reset-names = "lane1";
-                       };
 
-                       pciephy_2: phy@37000 {
-                               reg = <0x00037000 0x130>,
-                                     <0x00037200 0x200>,
-                                     <0x00037400 0x1dc>;
+                               #clock-cells = <0>;
+                               clock-output-names = "pcie_1_pipe_clk_src";
+
                                #phy-cells = <0>;
+                       };
+
+                       pciephy_2: phy@3000 {
+                               reg = <0x3000 0x130>,
+                                     <0x3200 0x200>,
+                                     <0x3400 0x1dc>;
 
-                               clock-output-names = "pcie_2_pipe_clk_src";
                                clocks = <&gcc GCC_PCIE_2_PIPE_CLK>;
                                clock-names = "pipe2";
                                resets = <&gcc GCC_PCIE_2_PHY_BCR>;
                                reset-names = "lane2";
+
+                               #clock-cells = <0>;
+                               clock-output-names = "pcie_2_pipe_clk_src";
+
+                               #phy-cells = <0>;
                        };
                };
 
                };
 
                qfprom@74000 {
-                       compatible = "qcom,qfprom";
+                       compatible = "qcom,msm8996-qfprom", "qcom,qfprom";
                        reg = <0x00074000 0x8ff>;
                        #address-cells = <1>;
                        #size-cells = <1>;
 
                        clocks = <&rpmcc RPM_SMD_BB_CLK1>,
                                 <&rpmcc RPM_SMD_LN_BB_CLK>,
-                                <&sleep_clk>;
-                       clock-names = "cxo", "cxo2", "sleep_clk";
+                                <&sleep_clk>,
+                                <&pciephy_0>,
+                                <&pciephy_1>,
+                                <&pciephy_2>,
+                                <&ssusb_phy_0>,
+                                <0>, <0>, <0>;
+                       clock-names = "cxo",
+                                     "cxo2",
+                                     "sleep_clk",
+                                     "pcie_0_pipe_clk_src",
+                                     "pcie_1_pipe_clk_src",
+                                     "pcie_2_pipe_clk_src",
+                                     "usb3_phy_pipe_clk_src",
+                                     "ufs_rx_symbol_0_clk_src",
+                                     "ufs_rx_symbol_1_clk_src",
+                                     "ufs_tx_symbol_0_clk_src";
+               };
+
+               bimc: interconnect@408000 {
+                       compatible = "qcom,msm8996-bimc";
+                       reg = <0x00408000 0x5a000>;
+                       #interconnect-cells = <1>;
+                       clock-names = "bus", "bus_a";
+                       clocks = <&rpmcc RPM_SMD_BIMC_CLK>,
+                                <&rpmcc RPM_SMD_BIMC_A_CLK>;
                };
 
                tsens0: thermal-sensor@4a9000 {
                        dma-names = "rx", "tx";
                };
 
+               cnoc: interconnect@500000 {
+                       compatible = "qcom,msm8996-cnoc";
+                       reg = <0x00500000 0x1000>;
+                       #interconnect-cells = <1>;
+                       clock-names = "bus", "bus_a";
+                       clocks = <&rpmcc RPM_SMD_CNOC_CLK>,
+                                <&rpmcc RPM_SMD_CNOC_A_CLK>;
+               };
+
+               snoc: interconnect@524000 {
+                       compatible = "qcom,msm8996-snoc";
+                       reg = <0x00524000 0x1c000>;
+                       #interconnect-cells = <1>;
+                       clock-names = "bus", "bus_a";
+                       clocks = <&rpmcc RPM_SMD_SNOC_CLK>,
+                                <&rpmcc RPM_SMD_SNOC_A_CLK>;
+               };
+
+               a0noc: interconnect@543000 {
+                       compatible = "qcom,msm8996-a0noc";
+                       reg = <0x00543000 0x6000>;
+                       #interconnect-cells = <1>;
+                       clock-names = "aggre0_snoc_axi",
+                                     "aggre0_cnoc_ahb",
+                                     "aggre0_noc_mpu_cfg";
+                       clocks = <&gcc GCC_AGGRE0_SNOC_AXI_CLK>,
+                                <&gcc GCC_AGGRE0_CNOC_AHB_CLK>,
+                                <&gcc GCC_AGGRE0_NOC_MPU_CFG_AHB_CLK>;
+                       power-domains = <&gcc AGGRE0_NOC_GDSC>;
+               };
+
+               a1noc: interconnect@562000 {
+                       compatible = "qcom,msm8996-a1noc";
+                       reg = <0x00562000 0x5000>;
+                       #interconnect-cells = <1>;
+                       clock-names = "bus", "bus_a";
+                       clocks = <&rpmcc RPM_SMD_AGGR1_NOC_CLK>,
+                                <&rpmcc RPM_SMD_AGGR1_NOC_A_CLK>;
+               };
+
+               a2noc: interconnect@583000 {
+                       compatible = "qcom,msm8996-a2noc";
+                       reg = <0x00583000 0x7000>;
+                       #interconnect-cells = <1>;
+                       clock-names = "bus", "bus_a";
+                       clocks = <&rpmcc RPM_SMD_AGGR2_NOC_CLK>,
+                                <&rpmcc RPM_SMD_AGGR2_NOC_A_CLK>;
+               };
+
+               mnoc: interconnect@5a4000 {
+                       compatible = "qcom,msm8996-mnoc";
+                       reg = <0x005a4000 0x1c000>;
+                       #interconnect-cells = <1>;
+                       clock-names = "bus", "bus_a", "iface";
+                       clocks = <&rpmcc RPM_SMD_MMAXI_CLK>,
+                                <&rpmcc RPM_SMD_MMAXI_A_CLK>,
+                                <&mmcc AHB_CLK_SRC>;
+               };
+
+               pnoc: interconnect@5c0000 {
+                       compatible = "qcom,msm8996-pnoc";
+                       reg = <0x005c0000 0x3000>;
+                       #interconnect-cells = <1>;
+                       clock-names = "bus", "bus_a";
+                       clocks = <&rpmcc RPM_SMD_PCNOC_CLK>,
+                                <&rpmcc RPM_SMD_PCNOC_A_CLK>;
+               };
+
                tcsr_mutex_regs: syscon@740000 {
                        compatible = "syscon";
                        reg = <0x00740000 0x40000>;
                        #reset-cells = <1>;
                        #power-domain-cells = <1>;
                        reg = <0x008c0000 0x40000>;
+                       clocks = <&xo_board>,
+                                <&gcc GCC_MMSS_NOC_CFG_AHB_CLK>,
+                                <&gcc GPLL0>,
+                                <&dsi0_phy 1>,
+                                <&dsi0_phy 0>,
+                                <0>,
+                                <0>,
+                                <0>;
+                       clock-names = "xo",
+                                     "gcc_mmss_noc_cfg_ahb_clk",
+                                     "gpll0",
+                                     "dsi0pll",
+                                     "dsi0pllbyte",
+                                     "dsi1pll",
+                                     "dsi1pllbyte",
+                                     "hdmipll";
                        assigned-clocks = <&mmcc MMPLL9_PLL>,
                                          <&mmcc MMPLL1_PLL>,
                                          <&mmcc MMPLL3_PLL>,
                        interrupt-controller;
                        #interrupt-cells = <1>;
 
-                       clocks = <&mmcc MDSS_AHB_CLK>;
-                       clock-names = "iface";
+                       clocks = <&mmcc MDSS_AHB_CLK>,
+                                <&mmcc MDSS_MDP_CLK>;
+                       clock-names = "iface", "core";
 
                        #address-cells = <1>;
                        #size-cells = <1>;
                                assigned-clock-rates = <300000000>,
                                         <19200000>;
 
+                               interconnects = <&mnoc MASTER_MDP_PORT0 &bimc SLAVE_EBI_CH0>,
+                                               <&mnoc MASTER_MDP_PORT1 &bimc SLAVE_EBI_CH0>,
+                                               <&mnoc MASTER_ROTATOR &bimc SLAVE_EBI_CH0>;
+                               interconnect-names = "mdp0-mem", "mdp1-mem", "rotator-mem";
+
                                ports {
                                        #address-cells = <1>;
                                        #size-cells = <0>;
                                                        remote-endpoint = <&dsi0_in>;
                                                };
                                        };
+
+                                       port@2 {
+                                               reg = <2>;
+                                               mdp5_intf2_out: endpoint {
+                                                       remote-endpoint = <&dsi1_in>;
+                                               };
+                                       };
                                };
                        };
 
                                              "core_mmss",
                                              "pixel",
                                              "core";
+                               assigned-clocks = <&mmcc BYTE0_CLK_SRC>, <&mmcc PCLK0_CLK_SRC>;
+                               assigned-clock-parents = <&dsi0_phy 0>, <&dsi0_phy 1>;
 
                                phys = <&dsi0_phy>;
                                phy-names = "dsi";
                                status = "disabled";
                        };
 
+                       dsi1: dsi@996000 {
+                               compatible = "qcom,mdss-dsi-ctrl";
+                               reg = <0x00996000 0x400>;
+                               reg-names = "dsi_ctrl";
+
+                               interrupt-parent = <&mdss>;
+                               interrupts = <4>;
+
+                               clocks = <&mmcc MDSS_MDP_CLK>,
+                                        <&mmcc MDSS_BYTE1_CLK>,
+                                        <&mmcc MDSS_AHB_CLK>,
+                                        <&mmcc MDSS_AXI_CLK>,
+                                        <&mmcc MMSS_MISC_AHB_CLK>,
+                                        <&mmcc MDSS_PCLK1_CLK>,
+                                        <&mmcc MDSS_ESC1_CLK>;
+                               clock-names = "mdp_core",
+                                             "byte",
+                                             "iface",
+                                             "bus",
+                                             "core_mmss",
+                                             "pixel",
+                                             "core";
+                               assigned-clocks = <&mmcc BYTE1_CLK_SRC>, <&mmcc PCLK1_CLK_SRC>;
+                               assigned-clock-parents = <&dsi1_phy 0>, <&dsi1_phy 1>;
+
+                               phys = <&dsi1_phy>;
+                               phy-names = "dsi";
+                               status = "disabled";
+
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               ports {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       port@0 {
+                                               reg = <0>;
+                                               dsi1_in: endpoint {
+                                                       remote-endpoint = <&mdp5_intf2_out>;
+                                               };
+                                       };
+
+                                       port@1 {
+                                               reg = <1>;
+                                               dsi1_out: endpoint {
+                                               };
+                                       };
+                               };
+                       };
+
+                       dsi1_phy: dsi-phy@996400 {
+                               compatible = "qcom,dsi-phy-14nm";
+                               reg = <0x00996400 0x100>,
+                                     <0x00996500 0x300>,
+                                     <0x00996800 0x188>;
+                               reg-names = "dsi_phy",
+                                           "dsi_phy_lane",
+                                           "dsi_pll";
+
+                               #clock-cells = <1>;
+                               #phy-cells = <0>;
+
+                               clocks = <&mmcc MDSS_AHB_CLK>, <&rpmcc RPM_SMD_BB_CLK1>;
+                               clock-names = "iface", "ref";
+                               status = "disabled";
+                       };
+
                        hdmi: hdmi-tx@9a0000 {
                                compatible = "qcom,hdmi-tx-8996";
                                reg =   <0x009a0000 0x50c>,
                                        "extp";
 
                                phys = <&hdmi_phy>;
-                               phy-names = "hdmi_phy";
                                #sound-dai-cells = <1>;
 
                                status = "disabled";
                                "mem",
                                "mem_iface";
 
+                       interconnects = <&bimc MASTER_GRAPHICS_3D &bimc SLAVE_EBI_CH0>;
+                       interconnect-names = "gfx-mem";
+
                        power-domains = <&mmcc GPU_GX_GDSC>;
                        iommus = <&adreno_smmu 0>;
 
                        #cooling-cells = <2>;
 
                        gpu_opp_table: opp-table {
-                               compatible  ="operating-points-v2";
+                               compatible "operating-points-v2";
 
                                /*
                                 * 624Mhz and 560Mhz are only available on speed
                                        <&gcc GCC_PCIE_0_MSTR_AXI_CLK>,
                                        <&gcc GCC_PCIE_0_SLV_AXI_CLK>;
 
-                               clock-names =  "pipe",
+                               clock-names = "pipe",
                                                "aux",
                                                "cfg",
                                                "bus_master",
                                bus-range = <0x00 0xff>;
                                num-lanes = <1>;
 
-                               status  = "disabled";
+                               status = "disabled";
 
                                reg = <0x00608000 0x2000>,
                                      <0x0d000000 0xf1d>,
                                        <&gcc GCC_PCIE_1_MSTR_AXI_CLK>,
                                        <&gcc GCC_PCIE_1_SLV_AXI_CLK>;
 
-                               clock-names =  "pipe",
+                               clock-names = "pipe",
                                                "aux",
                                                "cfg",
                                                "bus_master",
                                        <&gcc GCC_PCIE_2_MSTR_AXI_CLK>,
                                        <&gcc GCC_PCIE_2_SLV_AXI_CLK>;
 
-                               clock-names =  "pipe",
+                               clock-names = "pipe",
                                                "aux",
                                                "cfg",
                                                "bus_master",
                                 <&mmcc VIDEO_AXI_CLK>,
                                 <&mmcc VIDEO_MAXI_CLK>;
                        clock-names = "core", "iface", "bus", "mbus";
+                       interconnects = <&mnoc MASTER_VIDEO_P0 &bimc SLAVE_EBI_CH0>,
+                                       <&bimc MASTER_AMPSS_M0 &mnoc SLAVE_VENUS_CFG>;
+                       interconnect-names = "video-mem", "cpu-cfg";
                        iommus = <&venus_smmu 0x00>,
                                 <&venus_smmu 0x01>,
                                 <&venus_smmu 0x0a>,
                                          <&gcc GCC_USB30_MASTER_CLK>;
                        assigned-clock-rates = <19200000>, <120000000>;
 
+                       interconnects = <&a2noc MASTER_USB3 &bimc SLAVE_EBI_CH0>,
+                                       <&bimc MASTER_AMPSS_M0 &snoc SLAVE_USB3>;
+                       interconnect-names = "usb-ddr", "apps-usb";
+
                        power-domains = <&gcc USB30_GDSC>;
                        status = "disabled";
 
                                      <0x07410600 0x1a8>;
                                #phy-cells = <0>;
 
-                               #clock-cells = <1>;
+                               #clock-cells = <0>;
                                clock-output-names = "usb3_phy_pipe_clk_src";
                                clocks = <&gcc GCC_USB3_PHY_PIPE_CLK>;
                                clock-names = "pipe0";
                        status = "disabled";
                };
 
-               sdhc1: sdhci@7464900 {
+               sdhc1: mmc@7464900 {
                        compatible = "qcom,msm8996-sdhci", "qcom,sdhci-msm-v4";
                        reg = <0x07464900 0x11c>, <0x07464000 0x800>;
                        reg-names = "hc_mem", "core_mem";
                        clocks = <&gcc GCC_SDCC1_AHB_CLK>,
                                <&gcc GCC_SDCC1_APPS_CLK>,
                                <&rpmcc RPM_SMD_BB_CLK1>;
+                       resets = <&gcc GCC_SDCC1_BCR>;
 
                        pinctrl-names = "default", "sleep";
                        pinctrl-0 = <&sdc1_state_on>;
                        status = "disabled";
                };
 
-               sdhc2: sdhci@74a4900 {
+               sdhc2: mmc@74a4900 {
                        compatible = "qcom,msm8996-sdhci", "qcom,sdhci-msm-v4";
                        reg = <0x074a4900 0x314>, <0x074a4000 0x800>;
                        reg-names = "hc_mem", "core_mem";
                        clocks = <&gcc GCC_SDCC2_AHB_CLK>,
                                <&gcc GCC_SDCC2_APPS_CLK>,
                                <&rpmcc RPM_SMD_BB_CLK1>;
+                       resets = <&gcc GCC_SDCC2_BCR>;
 
                        pinctrl-names = "default", "sleep";
                        pinctrl-0 = <&sdc2_state_on>;
                        compatible = "qcom,bam-v1.7.0";
                        qcom,controlled-remotely;
                        reg = <0x09184000 0x32000>;
-                       num-channels  = <31>;
+                       num-channels = <31>;
                        interrupts = <0 164 IRQ_TYPE_LEVEL_HIGH>;
                        #dma-cells = <1>;
                        qcom,ee = <1>;
                        reg = <0x091c0000 0x2C000>;
                        reg-names = "ctrl";
                        interrupts = <0 163 IRQ_TYPE_LEVEL_HIGH>;
-                       dmas =  <&slimbam 3>, <&slimbam 4>,
+                       dmas = <&slimbam 3>, <&slimbam 4>,
                                <&slimbam 5>, <&slimbam 6>;
                        dma-names = "rx", "tx", "tx2", "rx2";
                        #address-cells = <1>;
 
                                tasha_ifd: tas-ifd {
                                        compatible = "slim217,1a0";
-                                       reg  = <0 0>;
+                                       reg = <0 0>;
                                };
 
                                wcd9335: codec@1{
                                        pinctrl-names = "default";
 
                                        compatible = "slim217,1a0";
-                                       reg  = <1 0>;
+                                       reg = <1 0>;
 
                                        interrupt-parent = <&tlmm>;
                                        interrupts = <54 IRQ_TYPE_LEVEL_HIGH>,
                                                     <53 IRQ_TYPE_LEVEL_HIGH>;
-                                       interrupt-names  = "intr1", "intr2";
+                                       interrupt-names = "intr1", "intr2";
                                        interrupt-controller;
                                        #interrupt-cells = <1>;
                                        reset-gpios = <&tlmm 64 0>;
 
-                                       slim-ifc-dev  = <&tasha_ifd>;
+                                       slim-ifc-dev = <&tasha_ifd>;
 
                                        #sound-dai-cells = <1>;
                                };
index e204b70..102f3e9 100644 (file)
 
        touchpad@15 {
                compatible = "hid-over-i2c";
-               interrupt-parent = <&tlmm>;
-               interrupts = <0x7b IRQ_TYPE_LEVEL_LOW>;
                reg = <0x15>;
-               hid-descr-addr = <0x0001>;
-
                pinctrl-names = "default";
                pinctrl-0 = <&touchpad>;
+
+               interrupt-parent = <&tlmm>;
+               interrupts = <123 IRQ_TYPE_LEVEL_LOW>;
+
+               hid-descr-addr = <0x0001>;
        };
 
        keyboard@3a {
                compatible = "hid-over-i2c";
-               interrupt-parent = <&tlmm>;
-               interrupts = <0x25 IRQ_TYPE_LEVEL_LOW>;
                reg = <0x3a>;
+               interrupt-parent = <&tlmm>;
+               interrupts = <37 IRQ_TYPE_LEVEL_LOW>;
+
                hid-descr-addr = <0x0001>;
        };
 };
 &sdhc2 {
        cd-gpios = <&tlmm 95 GPIO_ACTIVE_HIGH>;
 };
-
-&tlmm {
-       touchpad: touchpad {
-               config {
-                       pins = "gpio123";
-                       bias-pull-up;
-               };
-       };
-};
index b3b3525..7928b81 100644 (file)
@@ -8,13 +8,10 @@
  */
 
 #include "msm8998.dtsi"
-#include "pm8998.dtsi"
 #include "pm8005.dtsi"
+#include "pm8998.dtsi"
 
 / {
-       chosen {
-       };
-
        vph_pwr: vph-pwr-regulator {
                compatible = "regulator-fixed";
                regulator-name = "vph_pwr";
        };
 };
 
+&blsp1_uart3_on {
+       rx {
+               /delete-property/ bias-disable;
+               /*
+                * Configure a pull-up on 45 (RX). This is needed to
+                * avoid garbage data when the TX pin of the Bluetooth
+                * module is in tri-state (module powered off or not
+                * driving the signal yet).
+                */
+               bias-pull-up;
+       };
+
+       cts {
+               /delete-property/ bias-disable;
+               /*
+                * Configure a pull-down on 47 (CTS) to match the pull
+                * of the Bluetooth module.
+                */
+               bias-pull-down;
+       };
+};
+
 /*
  * The laptop FW does not appear to support the retention state as it is
  * not advertised as enabled in ACPI, and enabling it in DT can cause boot
        cpu-idle-states = <&BIG_CPU_SLEEP_1>;
 };
 
+/*
+ * If EFIFB is used, enabling MMCC will cause important MMSS clocks to be cleaned
+ * up, because as far as Linux is concerned - they are unused. Disable it by default
+ * on clamshell devices, as it will break them, unless either simplefb is configured to
+ * hold a vote for these clocks, or panels are brought up properly, using drm/msm.
+ */
+&mmcc {
+       status = "disabled";
+};
+
+&mmss_smmu {
+       status = "disabled";
+};
+
 &pcie0 {
        status = "okay";
 };
        status = "okay";
 };
 
-&pm8005_lsid1 {
-       pm8005-regulators {
-               compatible = "qcom,pm8005-regulators";
+&pm8005_regulators {
+       vdd_s1-supply = <&vph_pwr>;
 
-               vdd_s1-supply = <&vph_pwr>;
+       pm8005_s1: s1 { /* VDD_GFX supply */
+               regulator-min-microvolt = <524000>;
+               regulator-max-microvolt = <1100000>;
+               regulator-enable-ramp-delay = <500>;
 
-               pm8005_s1: s1 { /* VDD_GFX supply */
-                       regulator-min-microvolt = <524000>;
-                       regulator-max-microvolt = <1100000>;
-                       regulator-enable-ramp-delay = <500>;
-
-                       /* hack until we rig up the gpu consumer */
-                       regulator-always-on;
-               };
+               /* hack until we rig up the gpu consumer */
+               regulator-always-on;
        };
 };
 
                        regulator-min-microvolt = <1352000>;
                        regulator-max-microvolt = <1352000>;
                };
+
                vreg_s4a_1p8: s4 {
                        regulator-min-microvolt = <1800000>;
                        regulator-max-microvolt = <1800000>;
                        regulator-allow-set-load;
                };
+
                vreg_s5a_2p04: s5 {
                        regulator-min-microvolt = <1904000>;
                        regulator-max-microvolt = <2040000>;
                };
+
                vreg_s7a_1p025: s7 {
                        regulator-min-microvolt = <900000>;
                        regulator-max-microvolt = <1028000>;
                };
+
                vreg_l1a_0p875: l1 {
                        regulator-min-microvolt = <880000>;
                        regulator-max-microvolt = <880000>;
                        regulator-allow-set-load;
                };
+
                vreg_l2a_1p2: l2 {
                        regulator-min-microvolt = <1200000>;
                        regulator-max-microvolt = <1200000>;
                        regulator-allow-set-load;
                };
+
                vreg_l3a_1p0: l3 {
                        regulator-min-microvolt = <1000000>;
                        regulator-max-microvolt = <1000000>;
                };
+
                vreg_l5a_0p8: l5 {
                        regulator-min-microvolt = <800000>;
                        regulator-max-microvolt = <800000>;
                };
+
                vreg_l6a_1p8: l6 {
                        regulator-min-microvolt = <1808000>;
                        regulator-max-microvolt = <1808000>;
                };
+
                vreg_l7a_1p8: l7 {
                        regulator-min-microvolt = <1800000>;
                        regulator-max-microvolt = <1800000>;
                        regulator-allow-set-load;
                };
+
                vreg_l8a_1p2: l8 {
                        regulator-min-microvolt = <1200000>;
                        regulator-max-microvolt = <1200000>;
                };
+
                vreg_l9a_1p8: l9 {
                        regulator-min-microvolt = <1808000>;
                        regulator-max-microvolt = <2960000>;
                };
+
                vreg_l10a_1p8: l10 {
                        regulator-min-microvolt = <1808000>;
                        regulator-max-microvolt = <2960000>;
                };
+
                vreg_l11a_1p0: l11 {
                        regulator-min-microvolt = <1000000>;
                        regulator-max-microvolt = <1000000>;
                };
+
                vreg_l12a_1p8: l12 {
                        regulator-min-microvolt = <1800000>;
                        regulator-max-microvolt = <1800000>;
                };
+
                vreg_l13a_2p95: l13 {
                        regulator-min-microvolt = <1808000>;
                        regulator-max-microvolt = <2960000>;
                };
+
                vreg_l14a_1p88: l14 {
                        regulator-min-microvolt = <1880000>;
                        regulator-max-microvolt = <1880000>;
                };
+
                vreg_l15a_1p8: l15 {
                        regulator-min-microvolt = <1800000>;
                        regulator-max-microvolt = <1800000>;
                };
+
                vreg_l16a_2p7: l16 {
                        regulator-min-microvolt = <2704000>;
                        regulator-max-microvolt = <2704000>;
                };
+
                vreg_l17a_1p3: l17 {
                        regulator-min-microvolt = <1304000>;
                        regulator-max-microvolt = <1304000>;
                        regulator-allow-set-load;
                };
+
                vreg_l18a_2p7: l18 {
                        regulator-min-microvolt = <2704000>;
                        regulator-max-microvolt = <2704000>;
                };
+
                vreg_l19a_3p0: l19 {
                        regulator-min-microvolt = <3008000>;
                        regulator-max-microvolt = <3008000>;
                };
+
                vreg_l20a_2p95: l20 {
                        regulator-min-microvolt = <2960000>;
                        regulator-max-microvolt = <2960000>;
                        regulator-allow-set-load;
                };
+
                vreg_l21a_2p95: l21 {
                        regulator-min-microvolt = <2960000>;
                        regulator-max-microvolt = <2960000>;
                        regulator-allow-set-load;
                        regulator-system-load = <800000>;
                };
+
                vreg_l22a_2p85: l22 {
                        regulator-min-microvolt = <2864000>;
                        regulator-max-microvolt = <2864000>;
                };
+
                vreg_l23a_3p3: l23 {
                        regulator-min-microvolt = <3312000>;
                        regulator-max-microvolt = <3312000>;
                };
+
                vreg_l24a_3p075: l24 {
                        regulator-min-microvolt = <3088000>;
                        regulator-max-microvolt = <3088000>;
                };
+
                vreg_l25a_3p3: l25 {
                        regulator-min-microvolt = <3104000>;
                        regulator-max-microvolt = <3312000>;
                        regulator-allow-set-load;
                };
+
                vreg_l26a_1p2: l26 {
                        regulator-min-microvolt = <1200000>;
                        regulator-max-microvolt = <1200000>;
                };
+
                vreg_l28_3p0: l28 {
                        regulator-min-microvolt = <3008000>;
                        regulator-max-microvolt = <3008000>;
                        regulator-min-microvolt = <1800000>;
                        regulator-max-microvolt = <1800000>;
                };
-
        };
 };
 
        status = "okay";
 };
 
-&tlmm {
-       gpio-reserved-ranges = <0 4>, <81 4>;
-
-       touchpad: touchpad {
-               config {
-                       pins = "gpio123";
-                       bias-pull-up;           /* pull up */
-               };
-       };
-};
-
 &sdhc2 {
        status = "okay";
 
        vqmmc-supply = <&vreg_l13a_2p95>;
 
        pinctrl-names = "default", "sleep";
-       pinctrl-0 = <&sdc2_clk_on  &sdc2_cmd_on  &sdc2_data_on  &sdc2_cd_on>;
-       pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>;
+       pinctrl-0 = <&sdc2_on &sdc2_cd>;
+       pinctrl-1 = <&sdc2_off &sdc2_cd>;
+};
+
+&tlmm {
+       gpio-reserved-ranges = <0 4>, <81 4>;
+
+       touchpad: touchpad-pin {
+               pins = "gpio123";
+               bias-pull-up;
+       };
 };
 
 &ufshc {
        vdd-1.3-rfa-supply = <&vreg_l17a_1p3>;
        vdd-3.3-ch0-supply = <&vreg_l25a_3p3>;
 };
-
-/* PINCTRL - board-specific pinctrl */
-&blsp1_uart3_on {
-       rx {
-               /delete-property/ bias-disable;
-               /*
-                * Configure a pull-up on 45 (RX). This is needed to
-                * avoid garbage data when the TX pin of the Bluetooth
-                * module is in tri-state (module powered off or not
-                * driving the signal yet).
-                */
-               bias-pull-up;
-       };
-
-       cts {
-               /delete-property/ bias-disable;
-               /*
-                * Configure a pull-down on 47 (CTS) to match the pull
-                * of the Bluetooth module.
-                */
-               bias-pull-down;
-       };
-};
index dc5b9b2..429ba57 100644 (file)
@@ -6,11 +6,13 @@
 
 /dts-v1/;
 
-#include "msm8998-mtp.dtsi"
-
 #include <dt-bindings/input/input.h>
 #include <dt-bindings/leds/common.h>
 #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+#include "msm8998.dtsi"
+#include "pm8005.dtsi"
+#include "pm8998.dtsi"
+#include "pmi8998.dtsi"
 
 / {
        model = "F(x)tec Pro1 (QX1000)";
        chassis-type = "handset";
        qcom,board-id = <0x02000b 0x10>;
 
+       aliases {
+               serial0 = &blsp2_uart1;
+               serial1 = &blsp1_uart3;
+       };
+
        /*
         * Until we hook up type-c detection, we
         * have to stick with this. But it works.
@@ -33,7 +40,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&hall_sensor1_default>;
 
-               hall-sensor1 {
+               event-hall-sensor1 {
                        label = "Keyboard Hall Sensor";
                        gpios = <&tlmm 124 GPIO_ACTIVE_HIGH>;
                        debounce-interval = <15>;
@@ -49,7 +56,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&gpio_kb_pins_extra>;
 
-               home {
+               key-home {
                        label = "Home";
                        gpios = <&tlmm 21 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_HOMEPAGE>;
@@ -57,7 +64,7 @@
                        linux,can-disable;
                };
 
-               super-l {
+               key-super-l {
                        label = "Super Left";
                        gpios = <&tlmm 32 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_FN>;
@@ -65,7 +72,7 @@
                        linux,can-disable;
                };
 
-               super-r {
+               key-super-r {
                        label = "Super Right";
                        gpios = <&tlmm 33 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_FN>;
@@ -73,7 +80,7 @@
                        linux,can-disable;
                };
 
-               shift {
+               key-shift {
                        label = "Shift";
                        gpios = <&tlmm 114 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_RIGHTSHIFT>;
@@ -81,7 +88,7 @@
                        linux,can-disable;
                };
 
-               ctrl {
+               key-ctrl {
                        label = "Ctrl";
                        gpios = <&tlmm 128 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_LEFTCTRL>;
@@ -89,7 +96,7 @@
                        linux,can-disable;
                };
 
-               alt {
+               key-alt {
                        label = "Alt";
                        gpios = <&tlmm 129 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_LEFTALT>;
        gpio-keys {
                compatible = "gpio-keys";
                label = "Side buttons";
-               #address-cells = <1>;
-               #size-cells = <0>;
                pinctrl-names = "default";
                pinctrl-0 = <&vol_up_pin_a>, <&cam_focus_pin_a>,
                            <&cam_snapshot_pin_a>;
-               vol-up {
+               button-vol-up {
                        label = "Volume Up";
                        gpios = <&pm8998_gpio 6 GPIO_ACTIVE_LOW>;
                        linux,input-type = <EV_KEY>;
                        debounce-interval = <15>;
                };
 
-               camera-snapshot {
+               button-camera-snapshot {
                        label = "Camera Snapshot";
                        gpios = <&pm8998_gpio 7 GPIO_ACTIVE_LOW>;
                        linux,input-type = <EV_KEY>;
                        debounce-interval = <15>;
                };
 
-               camera-focus {
+               button-camera-focus {
                        label = "Camera Focus";
                        gpios = <&pm8998_gpio 8 GPIO_ACTIVE_LOW>;
                        linux,input-type = <EV_KEY>;
        keyboard-leds {
                compatible = "gpio-leds";
 
-               backlight {
+               led-0 {
                        color = <LED_COLOR_ID_WHITE>;
                        default-state = "off";
                        function = LED_FUNCTION_KBD_BACKLIGHT;
                        retain-state-suspended;
                };
 
-               caps-lock {
+               led-1 {
                        color = <LED_COLOR_ID_YELLOW>;
                        default-state = "off";
                        function = LED_FUNCTION_CAPSLOCK;
                pinctrl-0 = <&ts_vio_default>;
                regulator-always-on;
        };
+
+       vph_pwr: vph-pwr-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vph_pwr";
+               regulator-always-on;
+               regulator-boot-on;
+       };
+};
+
+&blsp1_uart3 {
+       status = "okay";
+
+       bluetooth {
+               compatible = "qcom,wcn3990-bt";
+
+               vddio-supply = <&vreg_s4a_1p8>;
+               vddxo-supply = <&vreg_l7a_1p8>;
+               vddrf-supply = <&vreg_l17a_1p3>;
+               vddch0-supply = <&vreg_l25a_3p3>;
+               max-speed = <3200000>;
+       };
+};
+
+&blsp1_uart3_on {
+       rx {
+               /delete-property/ bias-disable;
+               /*
+                * Configure a pull-up on 45 (RX). This is needed to
+                * avoid garbage data when the TX pin of the Bluetooth
+                * module is in tri-state (module powered off or not
+                * driving the signal yet).
+                */
+               bias-pull-up;
+       };
+
+       cts {
+               /delete-property/ bias-disable;
+               /*
+                * Configure a pull-down on 47 (CTS) to match the pull
+                * of the Bluetooth module.
+                */
+               bias-pull-down;
+       };
+};
+
+&blsp2_uart1 {
+       status = "okay";
 };
 
 &blsp2_i2c1 {
-       status = "ok";
+       status = "okay";
 
        touchscreen@14 {
                compatible = "goodix,gt9286";
        };
 };
 
-&mmcc {
-       status = "ok";
+&etf {
+       status = "okay";
+};
+
+&etm1 {
+       status = "okay";
+};
+
+&etm2 {
+       status = "okay";
+};
+
+&etm3 {
+       status = "okay";
+};
+
+&etm4 {
+       status = "okay";
+};
+
+&etm5 {
+       status = "okay";
+};
+
+&etm6 {
+       status = "okay";
+};
+
+&etm7 {
+       status = "okay";
+};
+
+&etm8 {
+       status = "okay";
+};
+
+&etr {
+       status = "okay";
 };
 
-&mmss_smmu {
-       status = "ok";
+&funnel1 {
+       status = "okay";
+};
+
+&funnel2 {
+       status = "okay";
+};
+
+&funnel3 {
+       status = "okay";
+};
+
+&funnel4 {
+       // FIXME: Figure out why clock late_initcall crashes the board with
+       // this enabled.
+       // status = "okay";
+};
+
+&funnel5 {
+       // FIXME: Figure out why clock late_initcall crashes the board with
+       // this enabled.
+       // status = "okay";
+};
+
+&pcie0 {
+       status = "okay";
+};
+
+&pcie_phy {
+       status = "okay";
+};
+
+&pm8005_regulators {
+       vdd_s1-supply = <&vph_pwr>;
+
+       pm8005_s1: s1 { /* VDD_GFX supply */
+               regulator-min-microvolt = <524000>;
+               regulator-max-microvolt = <1100000>;
+               regulator-enable-ramp-delay = <500>;
+
+               /* Hack until we rig up the gpu consumer */
+               regulator-always-on;
+       };
 };
 
 &pm8998_gpio {
-       vol_up_pin_a: vol-up-active {
+       vol_up_pin_a: vol-up-active-state {
                pins = "gpio6";
                function = "normal";
                bias-pull-up;
                qcom,drive-strength = <PMIC_GPIO_STRENGTH_NO>;
        };
 
-       cam_focus_pin_a: cam-focus-btn-active {
+       cam_focus_pin_a: cam-focus-btn-active-state {
                pins = "gpio7";
                function = "normal";
                bias-pull-up;
                qcom,drive-strength = <PMIC_GPIO_STRENGTH_NO>;
        };
 
-       cam_snapshot_pin_a: cam-snapshot-btn-active {
+       cam_snapshot_pin_a: cam-snapshot-btn-active-state {
                pins = "gpio8";
                function = "normal";
                bias-pull-up;
        };
 };
 
+&qusb2phy {
+       status = "okay";
+
+       vdda-pll-supply = <&vreg_l12a_1p8>;
+       vdda-phy-dpdm-supply = <&vreg_l24a_3p075>;
+};
+
+&replicator1 {
+       status = "okay";
+};
+
+&rpm_requests {
+       pm8998-regulators {
+               compatible = "qcom,rpm-pm8998-regulators";
+
+               vdd_s1-supply = <&vph_pwr>;
+               vdd_s2-supply = <&vph_pwr>;
+               vdd_s3-supply = <&vph_pwr>;
+               vdd_s4-supply = <&vph_pwr>;
+               vdd_s5-supply = <&vph_pwr>;
+               vdd_s6-supply = <&vph_pwr>;
+               vdd_s7-supply = <&vph_pwr>;
+               vdd_s8-supply = <&vph_pwr>;
+               vdd_s9-supply = <&vph_pwr>;
+               vdd_s10-supply = <&vph_pwr>;
+               vdd_s11-supply = <&vph_pwr>;
+               vdd_s12-supply = <&vph_pwr>;
+               vdd_s13-supply = <&vph_pwr>;
+               vdd_l1_l27-supply = <&vreg_s7a_1p025>;
+               vdd_l2_l8_l17-supply = <&vreg_s3a_1p35>;
+               vdd_l3_l11-supply = <&vreg_s7a_1p025>;
+               vdd_l4_l5-supply = <&vreg_s7a_1p025>;
+               vdd_l6-supply = <&vreg_s5a_2p04>;
+               vdd_l7_l12_l14_l15-supply = <&vreg_s5a_2p04>;
+               vdd_l9-supply = <&vreg_bob>;
+               vdd_l10_l23_l25-supply = <&vreg_bob>;
+               vdd_l13_l19_l21-supply = <&vreg_bob>;
+               vdd_l16_l28-supply = <&vreg_bob>;
+               vdd_l18_l22-supply = <&vreg_bob>;
+               vdd_l20_l24-supply = <&vreg_bob>;
+               vdd_l26-supply = <&vreg_s3a_1p35>;
+               vdd_lvs1_lvs2-supply = <&vreg_s4a_1p8>;
+
+               vreg_s3a_1p35: s3 {
+                       regulator-min-microvolt = <1352000>;
+                       regulator-max-microvolt = <1352000>;
+               };
+
+               vreg_s4a_1p8: s4 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_s5a_2p04: s5 {
+                       regulator-min-microvolt = <1904000>;
+                       regulator-max-microvolt = <2040000>;
+               };
+
+               vreg_s7a_1p025: s7 {
+                       regulator-min-microvolt = <900000>;
+                       regulator-max-microvolt = <1028000>;
+               };
+
+               vreg_l1a_0p875: l1 {
+                       regulator-min-microvolt = <880000>;
+                       regulator-max-microvolt = <880000>;
+               };
+
+               vreg_l2a_1p2: l2 {
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1200000>;
+               };
+
+               vreg_l3a_1p0: l3 {
+                       regulator-min-microvolt = <1000000>;
+                       regulator-max-microvolt = <1000000>;
+               };
+
+               vreg_l5a_0p8: l5 {
+                       regulator-min-microvolt = <800000>;
+                       regulator-max-microvolt = <800000>;
+               };
+
+               vreg_l6a_1p8: l6 {
+                       regulator-min-microvolt = <1808000>;
+                       regulator-max-microvolt = <1808000>;
+               };
+
+               vreg_l7a_1p8: l7 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+               };
+
+               vreg_l8a_1p2: l8 {
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1200000>;
+               };
+
+               vreg_l9a_1p8: l9 {
+                       regulator-min-microvolt = <1808000>;
+                       regulator-max-microvolt = <2960000>;
+               };
+
+               vreg_l10a_1p8: l10 {
+                       regulator-min-microvolt = <1808000>;
+                       regulator-max-microvolt = <2960000>;
+               };
+
+               vreg_l11a_1p0: l11 {
+                       regulator-min-microvolt = <1000000>;
+                       regulator-max-microvolt = <1000000>;
+               };
+
+               vreg_l12a_1p8: l12 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+               };
+
+               vreg_l13a_2p95: l13 {
+                       regulator-min-microvolt = <1808000>;
+                       regulator-max-microvolt = <2960000>;
+               };
+
+               vreg_l14a_1p88: l14 {
+                       regulator-min-microvolt = <1880000>;
+                       regulator-max-microvolt = <1880000>;
+               };
+
+               vreg_l15a_1p8: l15 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+               };
+
+               vreg_l16a_2p7: l16 {
+                       regulator-min-microvolt = <2704000>;
+                       regulator-max-microvolt = <2704000>;
+               };
+
+               vreg_l17a_1p3: l17 {
+                       regulator-min-microvolt = <1304000>;
+                       regulator-max-microvolt = <1304000>;
+               };
+
+               vreg_l18a_2p7: l18 {
+                       regulator-min-microvolt = <2704000>;
+                       regulator-max-microvolt = <2704000>;
+               };
+
+               vreg_l19a_3p0: l19 {
+                       regulator-min-microvolt = <3008000>;
+                       regulator-max-microvolt = <3008000>;
+               };
+
+               vreg_l20a_2p95: l20 {
+                       regulator-min-microvolt = <2960000>;
+                       regulator-max-microvolt = <2960000>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l21a_2p95: l21 {
+                       regulator-min-microvolt = <2960000>;
+                       regulator-max-microvolt = <2960000>;
+                       regulator-system-load = <800000>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l22a_2p85: l22 {
+                       regulator-min-microvolt = <2864000>;
+                       regulator-max-microvolt = <2864000>;
+               };
+
+               vreg_l23a_3p3: l23 {
+                       regulator-min-microvolt = <3312000>;
+                       regulator-max-microvolt = <3312000>;
+               };
+
+               vreg_l24a_3p075: l24 {
+                       regulator-min-microvolt = <3088000>;
+                       regulator-max-microvolt = <3088000>;
+               };
+
+               vreg_l25a_3p3: l25 {
+                       regulator-min-microvolt = <3104000>;
+                       regulator-max-microvolt = <3312000>;
+               };
+
+               vreg_l26a_1p2: l26 {
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1200000>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l28_3p0: l28 {
+                       regulator-min-microvolt = <3008000>;
+                       regulator-max-microvolt = <3008000>;
+               };
+
+               vreg_lvs1a_1p8: lvs1 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+               };
+
+               vreg_lvs2a_1p8: lvs2 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+               };
+
+       };
+
+       pmi8998-regulators {
+               compatible = "qcom,rpm-pmi8998-regulators";
+
+               vdd_bob-supply = <&vph_pwr>;
+
+               vreg_bob: bob {
+                       regulator-min-microvolt = <3312000>;
+                       regulator-max-microvolt = <3600000>;
+               };
+       };
+};
+
+&remoteproc_adsp {
+       status = "okay";
+};
+
+&remoteproc_mss {
+       status = "okay";
+};
+
+&remoteproc_slpi {
+       status = "okay";
+};
+
 &tlmm {
        gpio-reserved-ranges = <0 4>;
 
        };
 };
 
+&sdhc2 {
+       status = "okay";
+       cd-gpios = <&tlmm 95 GPIO_ACTIVE_LOW>;
+
+       vmmc-supply = <&vreg_l21a_2p95>;
+       vqmmc-supply = <&vreg_l13a_2p95>;
+
+       pinctrl-names = "default", "sleep";
+       pinctrl-0 = <&sdc2_on &sdc2_cd>;
+       pinctrl-1 = <&sdc2_off &sdc2_cd>;
+};
+
+&stm {
+       status = "okay";
+};
+
 &ufshc {
-       status = "ok";
+       status = "okay";
+       vcc-supply = <&vreg_l20a_2p95>;
+       vccq-supply = <&vreg_l26a_1p2>;
+       vccq2-supply = <&vreg_s4a_1p8>;
+       vcc-max-microamp = <750000>;
+       vccq-max-microamp = <560000>;
+       vccq2-max-microamp = <750000>;
 };
 
 &ufsphy {
-       status = "ok";
+       status = "okay";
+       vdda-phy-supply = <&vreg_l1a_0p875>;
+       vdda-pll-supply = <&vreg_l2a_1p2>;
+       vddp-ref-clk-supply = <&vreg_l26a_1p2>;
+};
+
+&usb3 {
+       status = "okay";
 };
 
 &usb3_dwc3 {
        extcon = <&extcon_usb>;
 };
 
+&usb3phy {
+       status = "okay";
+
+       vdda-phy-supply = <&vreg_l1a_0p875>;
+       vdda-pll-supply = <&vreg_l2a_1p2>;
+};
+
 /* GT9286 analog supply */
 &vreg_l28_3p0 {
        regulator-min-microvolt = <2800000>;
        regulator-max-microvolt = <2800000>;
 };
+
+&wifi {
+       status = "okay";
+
+       vdd-0.8-cx-mx-supply = <&vreg_l5a_0p8>;
+       vdd-1.8-xo-supply = <&vreg_l7a_1p8>;
+       vdd-1.3-rfa-supply = <&vreg_l17a_1p3>;
+       vdd-3.3-ch0-supply = <&vreg_l25a_3p3>;
+};
index 1eb406b..38389c6 100644 (file)
 
        keyboard@3a {
                compatible = "hid-over-i2c";
-               interrupt-parent = <&tlmm>;
-               interrupts = <0x79 IRQ_TYPE_LEVEL_LOW>;
                reg = <0x3a>;
-               hid-descr-addr = <0x0001>;
-
                pinctrl-names = "default";
                pinctrl-0 = <&touchpad>;
+
+               interrupt-parent = <&tlmm>;
+               interrupts = <121 IRQ_TYPE_LEVEL_LOW>;
+
+               hid-descr-addr = <0x0001>;
        };
 };
 
index f55f6f3..cf81c33 100644 (file)
 
        keyboard@3a {
                compatible = "hid-over-i2c";
-               interrupt-parent = <&tlmm>;
-               interrupts = <0x79 IRQ_TYPE_LEVEL_LOW>;
                reg = <0x3a>;
-               hid-descr-addr = <0x0001>;
-
                pinctrl-names = "default";
                pinctrl-0 = <&touchpad>;
+
+               interrupt-parent = <&tlmm>;
+               interrupts = <121 IRQ_TYPE_LEVEL_LOW>;
+
+               hid-descr-addr = <0x0001>;
        };
 };
 
index 66540d2..a3ca581 100644 (file)
 
 /dts-v1/;
 
-#include "msm8998-mtp.dtsi"
+#include "msm8998.dtsi"
+#include "pm8005.dtsi"
+#include "pm8998.dtsi"
+#include "pmi8998.dtsi"
 
 / {
        model = "Qualcomm Technologies, Inc. MSM8998 v1 MTP";
-       compatible = "qcom,msm8998-mtp";
+       compatible = "qcom,msm8998-mtp", "qcom,msm8998";
 
        qcom,board-id = <8 0>;
+
+       aliases {
+               serial0 = &blsp2_uart1;
+               serial1 = &blsp1_uart3;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       vph_pwr: vph-pwr-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vph_pwr";
+               regulator-always-on;
+               regulator-boot-on;
+       };
+};
+
+&blsp1_uart3 {
+       status = "okay";
+
+       bluetooth {
+               compatible = "qcom,wcn3990-bt";
+
+               vddio-supply = <&vreg_s4a_1p8>;
+               vddxo-supply = <&vreg_l7a_1p8>;
+               vddrf-supply = <&vreg_l17a_1p3>;
+               vddch0-supply = <&vreg_l25a_3p3>;
+               max-speed = <3200000>;
+       };
+};
+
+&blsp1_uart3_on {
+       rx {
+               /delete-property/ bias-disable;
+               /*
+                * Configure a pull-up on 45 (RX). This is needed to
+                * avoid garbage data when the TX pin of the Bluetooth
+                * module is in tri-state (module powered off or not
+                * driving the signal yet).
+                */
+               bias-pull-up;
+       };
+
+       cts {
+               /delete-property/ bias-disable;
+               /*
+                * Configure a pull-down on 47 (CTS) to match the pull
+                * of the Bluetooth module.
+                */
+               bias-pull-down;
+       };
+};
+
+&blsp2_uart1 {
+       status = "okay";
+};
+
+&etf {
+       status = "okay";
+};
+
+&etm1 {
+       status = "okay";
+};
+
+&etm2 {
+       status = "okay";
+};
+
+&etm3 {
+       status = "okay";
+};
+
+&etm4 {
+       status = "okay";
+};
+
+&etm5 {
+       status = "okay";
+};
+
+&etm6 {
+       status = "okay";
+};
+
+&etm7 {
+       status = "okay";
+};
+
+&etm8 {
+       status = "okay";
+};
+
+&etr {
+       status = "okay";
+};
+
+&funnel1 {
+       status = "okay";
+};
+
+&funnel2 {
+       status = "okay";
+};
+
+&funnel3 {
+       status = "okay";
+};
+
+&funnel4 {
+       // FIXME: Figure out why clock late_initcall crashes the board with
+       // this enabled.
+       // status = "okay";
+};
+
+&funnel5 {
+       // FIXME: Figure out why clock late_initcall crashes the board with
+       // this enabled.
+       // status = "okay";
+};
+
+&pcie0 {
+       status = "okay";
+};
+
+&pcie_phy {
+       status = "okay";
+};
+
+&pm8005_regulators {
+       vdd_s1-supply = <&vph_pwr>;
+
+       pm8005_s1: s1 { /* VDD_GFX supply */
+               regulator-min-microvolt = <524000>;
+               regulator-max-microvolt = <1100000>;
+               regulator-enable-ramp-delay = <500>;
+
+               /* Hack until we rig up the gpu consumer */
+               regulator-always-on;
+       };
+};
+
+&qusb2phy {
+       status = "okay";
+
+       vdda-pll-supply = <&vreg_l12a_1p8>;
+       vdda-phy-dpdm-supply = <&vreg_l24a_3p075>;
+};
+
+&replicator1 {
+       status = "okay";
+};
+
+&rpm_requests {
+       pm8998-regulators {
+               compatible = "qcom,rpm-pm8998-regulators";
+
+               vdd_s1-supply = <&vph_pwr>;
+               vdd_s2-supply = <&vph_pwr>;
+               vdd_s3-supply = <&vph_pwr>;
+               vdd_s4-supply = <&vph_pwr>;
+               vdd_s5-supply = <&vph_pwr>;
+               vdd_s6-supply = <&vph_pwr>;
+               vdd_s7-supply = <&vph_pwr>;
+               vdd_s8-supply = <&vph_pwr>;
+               vdd_s9-supply = <&vph_pwr>;
+               vdd_s10-supply = <&vph_pwr>;
+               vdd_s11-supply = <&vph_pwr>;
+               vdd_s12-supply = <&vph_pwr>;
+               vdd_s13-supply = <&vph_pwr>;
+               vdd_l1_l27-supply = <&vreg_s7a_1p025>;
+               vdd_l2_l8_l17-supply = <&vreg_s3a_1p35>;
+               vdd_l3_l11-supply = <&vreg_s7a_1p025>;
+               vdd_l4_l5-supply = <&vreg_s7a_1p025>;
+               vdd_l6-supply = <&vreg_s5a_2p04>;
+               vdd_l7_l12_l14_l15-supply = <&vreg_s5a_2p04>;
+               vdd_l9-supply = <&vreg_bob>;
+               vdd_l10_l23_l25-supply = <&vreg_bob>;
+               vdd_l13_l19_l21-supply = <&vreg_bob>;
+               vdd_l16_l28-supply = <&vreg_bob>;
+               vdd_l18_l22-supply = <&vreg_bob>;
+               vdd_l20_l24-supply = <&vreg_bob>;
+               vdd_l26-supply = <&vreg_s3a_1p35>;
+               vdd_lvs1_lvs2-supply = <&vreg_s4a_1p8>;
+
+               vreg_s3a_1p35: s3 {
+                       regulator-min-microvolt = <1352000>;
+                       regulator-max-microvolt = <1352000>;
+               };
+
+               vreg_s4a_1p8: s4 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_s5a_2p04: s5 {
+                       regulator-min-microvolt = <1904000>;
+                       regulator-max-microvolt = <2040000>;
+               };
+
+               vreg_s7a_1p025: s7 {
+                       regulator-min-microvolt = <900000>;
+                       regulator-max-microvolt = <1028000>;
+               };
+
+               vreg_l1a_0p875: l1 {
+                       regulator-min-microvolt = <880000>;
+                       regulator-max-microvolt = <880000>;
+               };
+
+               vreg_l2a_1p2: l2 {
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1200000>;
+               };
+
+               vreg_l3a_1p0: l3 {
+                       regulator-min-microvolt = <1000000>;
+                       regulator-max-microvolt = <1000000>;
+               };
+
+               vreg_l5a_0p8: l5 {
+                       regulator-min-microvolt = <800000>;
+                       regulator-max-microvolt = <800000>;
+               };
+
+               vreg_l6a_1p8: l6 {
+                       regulator-min-microvolt = <1808000>;
+                       regulator-max-microvolt = <1808000>;
+               };
+
+               vreg_l7a_1p8: l7 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+               };
+
+               vreg_l8a_1p2: l8 {
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1200000>;
+               };
+
+               vreg_l9a_1p8: l9 {
+                       regulator-min-microvolt = <1808000>;
+                       regulator-max-microvolt = <2960000>;
+               };
+
+               vreg_l10a_1p8: l10 {
+                       regulator-min-microvolt = <1808000>;
+                       regulator-max-microvolt = <2960000>;
+               };
+
+               vreg_l11a_1p0: l11 {
+                       regulator-min-microvolt = <1000000>;
+                       regulator-max-microvolt = <1000000>;
+               };
+
+               vreg_l12a_1p8: l12 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+               };
+
+               vreg_l13a_2p95: l13 {
+                       regulator-min-microvolt = <1808000>;
+                       regulator-max-microvolt = <2960000>;
+               };
+
+               vreg_l14a_1p88: l14 {
+                       regulator-min-microvolt = <1880000>;
+                       regulator-max-microvolt = <1880000>;
+               };
+
+               vreg_l15a_1p8: l15 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+               };
+
+               vreg_l16a_2p7: l16 {
+                       regulator-min-microvolt = <2704000>;
+                       regulator-max-microvolt = <2704000>;
+               };
+
+               vreg_l17a_1p3: l17 {
+                       regulator-min-microvolt = <1304000>;
+                       regulator-max-microvolt = <1304000>;
+               };
+
+               vreg_l18a_2p7: l18 {
+                       regulator-min-microvolt = <2704000>;
+                       regulator-max-microvolt = <2704000>;
+               };
+
+               vreg_l19a_3p0: l19 {
+                       regulator-min-microvolt = <3008000>;
+                       regulator-max-microvolt = <3008000>;
+               };
+
+               vreg_l20a_2p95: l20 {
+                       regulator-min-microvolt = <2960000>;
+                       regulator-max-microvolt = <2960000>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l21a_2p95: l21 {
+                       regulator-min-microvolt = <2960000>;
+                       regulator-max-microvolt = <2960000>;
+                       regulator-system-load = <800000>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l22a_2p85: l22 {
+                       regulator-min-microvolt = <2864000>;
+                       regulator-max-microvolt = <2864000>;
+               };
+
+               vreg_l23a_3p3: l23 {
+                       regulator-min-microvolt = <3312000>;
+                       regulator-max-microvolt = <3312000>;
+               };
+
+               vreg_l24a_3p075: l24 {
+                       regulator-min-microvolt = <3088000>;
+                       regulator-max-microvolt = <3088000>;
+               };
+
+               vreg_l25a_3p3: l25 {
+                       regulator-min-microvolt = <3104000>;
+                       regulator-max-microvolt = <3312000>;
+               };
+
+               vreg_l26a_1p2: l26 {
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1200000>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l28_3p0: l28 {
+                       regulator-min-microvolt = <3008000>;
+                       regulator-max-microvolt = <3008000>;
+               };
+
+               vreg_lvs1a_1p8: lvs1 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+               };
+
+               vreg_lvs2a_1p8: lvs2 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+               };
+
+       };
+
+       pmi8998-regulators {
+               compatible = "qcom,rpm-pmi8998-regulators";
+
+               vdd_bob-supply = <&vph_pwr>;
+
+               vreg_bob: bob {
+                       regulator-min-microvolt = <3312000>;
+                       regulator-max-microvolt = <3600000>;
+               };
+       };
+};
+
+&remoteproc_adsp {
+       status = "okay";
+};
+
+&remoteproc_mss {
+       status = "okay";
+};
+
+&remoteproc_slpi {
+       status = "okay";
+};
+
+&tlmm {
+       gpio-reserved-ranges = <0 4>, <81 4>;
+};
+
+&sdhc2 {
+       status = "okay";
+       cd-gpios = <&tlmm 95 GPIO_ACTIVE_LOW>;
+
+       vmmc-supply = <&vreg_l21a_2p95>;
+       vqmmc-supply = <&vreg_l13a_2p95>;
+
+       pinctrl-names = "default", "sleep";
+       pinctrl-0 = <&sdc2_on &sdc2_cd>;
+       pinctrl-1 = <&sdc2_off &sdc2_cd>;
+};
+
+&stm {
+       status = "okay";
+};
+
+&ufshc {
+       status = "okay";
+       vcc-supply = <&vreg_l20a_2p95>;
+       vccq-supply = <&vreg_l26a_1p2>;
+       vccq2-supply = <&vreg_s4a_1p8>;
+       vcc-max-microamp = <750000>;
+       vccq-max-microamp = <560000>;
+       vccq2-max-microamp = <750000>;
+};
+
+&ufsphy {
+       status = "okay";
+       vdda-phy-supply = <&vreg_l1a_0p875>;
+       vdda-pll-supply = <&vreg_l2a_1p2>;
+       vddp-ref-clk-supply = <&vreg_l26a_1p2>;
+};
+
+&usb3 {
+       status = "okay";
+};
+
+&usb3_dwc3 {
+       dr_mode = "host"; /* Force to host until we have Type-C hooked up */
+};
+
+&usb3phy {
+       status = "okay";
+
+       vdda-phy-supply = <&vreg_l1a_0p875>;
+       vdda-pll-supply = <&vreg_l2a_1p2>;
+};
+
+&wifi {
+       status = "okay";
+
+       vdd-0.8-cx-mx-supply = <&vreg_l5a_0p8>;
+       vdd-1.8-xo-supply = <&vreg_l7a_1p8>;
+       vdd-1.3-rfa-supply = <&vreg_l17a_1p3>;
+       vdd-3.3-ch0-supply = <&vreg_l25a_3p3>;
 };
diff --git a/arch/arm64/boot/dts/qcom/msm8998-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8998-mtp.dtsi
deleted file mode 100644 (file)
index af67c64..0000000
+++ /dev/null
@@ -1,421 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved. */
-
-#include "msm8998.dtsi"
-#include "pm8998.dtsi"
-#include "pmi8998.dtsi"
-#include "pm8005.dtsi"
-
-/ {
-       aliases {
-               serial0 = &blsp2_uart1;
-               serial1 = &blsp1_uart3;
-       };
-
-       chosen {
-               stdout-path = "serial0:115200n8";
-       };
-
-       vph_pwr: vph-pwr-regulator {
-               compatible = "regulator-fixed";
-               regulator-name = "vph_pwr";
-               regulator-always-on;
-               regulator-boot-on;
-       };
-};
-
-&blsp1_uart3 {
-       status = "okay";
-
-       bluetooth {
-               compatible = "qcom,wcn3990-bt";
-
-               vddio-supply = <&vreg_s4a_1p8>;
-               vddxo-supply = <&vreg_l7a_1p8>;
-               vddrf-supply = <&vreg_l17a_1p3>;
-               vddch0-supply = <&vreg_l25a_3p3>;
-               max-speed = <3200000>;
-       };
-};
-
-&blsp2_uart1 {
-       status = "okay";
-};
-
-&etf {
-       status = "okay";
-};
-
-&etm1 {
-       status = "okay";
-};
-
-&etm2 {
-       status = "okay";
-};
-
-&etm3 {
-       status = "okay";
-};
-
-&etm4 {
-       status = "okay";
-};
-
-&etm5 {
-       status = "okay";
-};
-
-&etm6 {
-       status = "okay";
-};
-
-&etm7 {
-       status = "okay";
-};
-
-&etm8 {
-       status = "okay";
-};
-
-&etr {
-       status = "okay";
-};
-
-&funnel1 {
-       status = "okay";
-};
-
-&funnel2 {
-       status = "okay";
-};
-
-&funnel3 {
-       status = "okay";
-};
-
-&funnel4 {
-       // FIXME: Figure out why clock late_initcall crashes the board with
-       // this enabled.
-       // status = "okay";
-};
-
-&funnel5 {
-       // FIXME: Figure out why clock late_initcall crashes the board with
-       // this enabled.
-       // status = "okay";
-};
-
-&pcie0 {
-       status = "okay";
-};
-
-&pcie_phy {
-       status = "okay";
-};
-
-&pm8005_lsid1 {
-       pm8005-regulators {
-               compatible = "qcom,pm8005-regulators";
-
-               vdd_s1-supply = <&vph_pwr>;
-
-               pm8005_s1: s1 { /* VDD_GFX supply */
-                       regulator-min-microvolt = <524000>;
-                       regulator-max-microvolt = <1100000>;
-                       regulator-enable-ramp-delay = <500>;
-
-                       /* hack until we rig up the gpu consumer */
-                       regulator-always-on;
-               };
-       };
-};
-
-&qusb2phy {
-       status = "okay";
-
-       vdda-pll-supply = <&vreg_l12a_1p8>;
-       vdda-phy-dpdm-supply = <&vreg_l24a_3p075>;
-};
-
-&replicator1 {
-       status = "okay";
-};
-
-&rpm_requests {
-       pm8998-regulators {
-               compatible = "qcom,rpm-pm8998-regulators";
-
-               vdd_s1-supply = <&vph_pwr>;
-               vdd_s2-supply = <&vph_pwr>;
-               vdd_s3-supply = <&vph_pwr>;
-               vdd_s4-supply = <&vph_pwr>;
-               vdd_s5-supply = <&vph_pwr>;
-               vdd_s6-supply = <&vph_pwr>;
-               vdd_s7-supply = <&vph_pwr>;
-               vdd_s8-supply = <&vph_pwr>;
-               vdd_s9-supply = <&vph_pwr>;
-               vdd_s10-supply = <&vph_pwr>;
-               vdd_s11-supply = <&vph_pwr>;
-               vdd_s12-supply = <&vph_pwr>;
-               vdd_s13-supply = <&vph_pwr>;
-               vdd_l1_l27-supply = <&vreg_s7a_1p025>;
-               vdd_l2_l8_l17-supply = <&vreg_s3a_1p35>;
-               vdd_l3_l11-supply = <&vreg_s7a_1p025>;
-               vdd_l4_l5-supply = <&vreg_s7a_1p025>;
-               vdd_l6-supply = <&vreg_s5a_2p04>;
-               vdd_l7_l12_l14_l15-supply = <&vreg_s5a_2p04>;
-               vdd_l9-supply = <&vreg_bob>;
-               vdd_l10_l23_l25-supply = <&vreg_bob>;
-               vdd_l13_l19_l21-supply = <&vreg_bob>;
-               vdd_l16_l28-supply = <&vreg_bob>;
-               vdd_l18_l22-supply = <&vreg_bob>;
-               vdd_l20_l24-supply = <&vreg_bob>;
-               vdd_l26-supply = <&vreg_s3a_1p35>;
-               vdd_lvs1_lvs2-supply = <&vreg_s4a_1p8>;
-
-               vreg_s3a_1p35: s3 {
-                       regulator-min-microvolt = <1352000>;
-                       regulator-max-microvolt = <1352000>;
-               };
-               vreg_s4a_1p8: s4 {
-                       regulator-min-microvolt = <1800000>;
-                       regulator-max-microvolt = <1800000>;
-                       regulator-allow-set-load;
-               };
-               vreg_s5a_2p04: s5 {
-                       regulator-min-microvolt = <1904000>;
-                       regulator-max-microvolt = <2040000>;
-               };
-               vreg_s7a_1p025: s7 {
-                       regulator-min-microvolt = <900000>;
-                       regulator-max-microvolt = <1028000>;
-               };
-               vreg_l1a_0p875: l1 {
-                       regulator-min-microvolt = <880000>;
-                       regulator-max-microvolt = <880000>;
-               };
-               vreg_l2a_1p2: l2 {
-                       regulator-min-microvolt = <1200000>;
-                       regulator-max-microvolt = <1200000>;
-               };
-               vreg_l3a_1p0: l3 {
-                       regulator-min-microvolt = <1000000>;
-                       regulator-max-microvolt = <1000000>;
-               };
-               vreg_l5a_0p8: l5 {
-                       regulator-min-microvolt = <800000>;
-                       regulator-max-microvolt = <800000>;
-               };
-               vreg_l6a_1p8: l6 {
-                       regulator-min-microvolt = <1808000>;
-                       regulator-max-microvolt = <1808000>;
-               };
-               vreg_l7a_1p8: l7 {
-                       regulator-min-microvolt = <1800000>;
-                       regulator-max-microvolt = <1800000>;
-               };
-               vreg_l8a_1p2: l8 {
-                       regulator-min-microvolt = <1200000>;
-                       regulator-max-microvolt = <1200000>;
-               };
-               vreg_l9a_1p8: l9 {
-                       regulator-min-microvolt = <1808000>;
-                       regulator-max-microvolt = <2960000>;
-               };
-               vreg_l10a_1p8: l10 {
-                       regulator-min-microvolt = <1808000>;
-                       regulator-max-microvolt = <2960000>;
-               };
-               vreg_l11a_1p0: l11 {
-                       regulator-min-microvolt = <1000000>;
-                       regulator-max-microvolt = <1000000>;
-               };
-               vreg_l12a_1p8: l12 {
-                       regulator-min-microvolt = <1800000>;
-                       regulator-max-microvolt = <1800000>;
-               };
-               vreg_l13a_2p95: l13 {
-                       regulator-min-microvolt = <1808000>;
-                       regulator-max-microvolt = <2960000>;
-               };
-               vreg_l14a_1p88: l14 {
-                       regulator-min-microvolt = <1880000>;
-                       regulator-max-microvolt = <1880000>;
-               };
-               vreg_l15a_1p8: l15 {
-                       regulator-min-microvolt = <1800000>;
-                       regulator-max-microvolt = <1800000>;
-               };
-               vreg_l16a_2p7: l16 {
-                       regulator-min-microvolt = <2704000>;
-                       regulator-max-microvolt = <2704000>;
-               };
-               vreg_l17a_1p3: l17 {
-                       regulator-min-microvolt = <1304000>;
-                       regulator-max-microvolt = <1304000>;
-               };
-               vreg_l18a_2p7: l18 {
-                       regulator-min-microvolt = <2704000>;
-                       regulator-max-microvolt = <2704000>;
-               };
-               vreg_l19a_3p0: l19 {
-                       regulator-min-microvolt = <3008000>;
-                       regulator-max-microvolt = <3008000>;
-               };
-               vreg_l20a_2p95: l20 {
-                       regulator-min-microvolt = <2960000>;
-                       regulator-max-microvolt = <2960000>;
-                       regulator-allow-set-load;
-               };
-               vreg_l21a_2p95: l21 {
-                       regulator-min-microvolt = <2960000>;
-                       regulator-max-microvolt = <2960000>;
-                       regulator-allow-set-load;
-                       regulator-system-load = <800000>;
-               };
-               vreg_l22a_2p85: l22 {
-                       regulator-min-microvolt = <2864000>;
-                       regulator-max-microvolt = <2864000>;
-               };
-               vreg_l23a_3p3: l23 {
-                       regulator-min-microvolt = <3312000>;
-                       regulator-max-microvolt = <3312000>;
-               };
-               vreg_l24a_3p075: l24 {
-                       regulator-min-microvolt = <3088000>;
-                       regulator-max-microvolt = <3088000>;
-               };
-               vreg_l25a_3p3: l25 {
-                       regulator-min-microvolt = <3104000>;
-                       regulator-max-microvolt = <3312000>;
-               };
-               vreg_l26a_1p2: l26 {
-                       regulator-min-microvolt = <1200000>;
-                       regulator-max-microvolt = <1200000>;
-                       regulator-allow-set-load;
-               };
-               vreg_l28_3p0: l28 {
-                       regulator-min-microvolt = <3008000>;
-                       regulator-max-microvolt = <3008000>;
-               };
-
-               vreg_lvs1a_1p8: lvs1 {
-                       regulator-min-microvolt = <1800000>;
-                       regulator-max-microvolt = <1800000>;
-               };
-
-               vreg_lvs2a_1p8: lvs2 {
-                       regulator-min-microvolt = <1800000>;
-                       regulator-max-microvolt = <1800000>;
-               };
-
-       };
-
-       pmi8998-regulators {
-               compatible = "qcom,rpm-pmi8998-regulators";
-
-               vdd_bob-supply = <&vph_pwr>;
-
-               vreg_bob: bob {
-                       regulator-min-microvolt = <3312000>;
-                       regulator-max-microvolt = <3600000>;
-               };
-       };
-};
-
-&remoteproc_adsp {
-       status = "okay";
-};
-
-&remoteproc_mss {
-       status = "okay";
-};
-
-&remoteproc_slpi {
-       status = "okay";
-};
-
-&tlmm {
-       gpio-reserved-ranges = <0 4>, <81 4>;
-};
-
-&sdhc2 {
-       status = "okay";
-       cd-gpios = <&tlmm 95 GPIO_ACTIVE_LOW>;
-
-       vmmc-supply = <&vreg_l21a_2p95>;
-       vqmmc-supply = <&vreg_l13a_2p95>;
-
-       pinctrl-names = "default", "sleep";
-       pinctrl-0 = <&sdc2_clk_on  &sdc2_cmd_on  &sdc2_data_on  &sdc2_cd_on>;
-       pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>;
-};
-
-&stm {
-       status = "okay";
-};
-
-&ufshc {
-       status = "okay";
-       vcc-supply = <&vreg_l20a_2p95>;
-       vccq-supply = <&vreg_l26a_1p2>;
-       vccq2-supply = <&vreg_s4a_1p8>;
-       vcc-max-microamp = <750000>;
-       vccq-max-microamp = <560000>;
-       vccq2-max-microamp = <750000>;
-};
-
-&ufsphy {
-       status = "okay";
-       vdda-phy-supply = <&vreg_l1a_0p875>;
-       vdda-pll-supply = <&vreg_l2a_1p2>;
-       vddp-ref-clk-supply = <&vreg_l26a_1p2>;
-};
-
-&usb3 {
-       status = "okay";
-};
-
-&usb3_dwc3 {
-       dr_mode = "host"; /* Force to host until we have Type-C hooked up */
-};
-
-&usb3phy {
-       status = "okay";
-
-       vdda-phy-supply = <&vreg_l1a_0p875>;
-       vdda-pll-supply = <&vreg_l2a_1p2>;
-};
-
-&wifi {
-       status = "okay";
-
-       vdd-0.8-cx-mx-supply = <&vreg_l5a_0p8>;
-       vdd-1.8-xo-supply = <&vreg_l7a_1p8>;
-       vdd-1.3-rfa-supply = <&vreg_l17a_1p3>;
-       vdd-3.3-ch0-supply = <&vreg_l25a_3p3>;
-};
-
-/* PINCTRL - board-specific pinctrl */
-&blsp1_uart3_on {
-       rx {
-               /delete-property/ bias-disable;
-               /*
-                * Configure a pull-up on 45 (RX). This is needed to
-                * avoid garbage data when the TX pin of the Bluetooth
-                * module is in tri-state (module powered off or not
-                * driving the signal yet).
-                */
-               bias-pull-up;
-       };
-
-       cts {
-               /delete-property/ bias-disable;
-               /*
-                * Configure a pull-down on 47 (CTS) to match the pull
-                * of the Bluetooth module.
-                */
-               bias-pull-down;
-       };
-};
index 9563eb6..ef2a88a 100644 (file)
@@ -32,7 +32,7 @@
 };
 
 &pmi8998_gpio {
-       button_backlight_default: button-backlight-default {
+       button_backlight_default: button-backlight-state {
                pinconf {
                        pins = "gpio5";
                        function = "normal";
index dbaea36..62bda23 100644 (file)
@@ -11,9 +11,9 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
 #include "msm8998.dtsi"
+#include "pm8005.dtsi"
 #include "pm8998.dtsi"
 #include "pmi8998.dtsi"
-#include "pm8005.dtsi"
 
 / {
        /* Required for bootloader to select correct board */
                        height = <1920>;
                        stride = <(1080 * 4)>;
                        format = "a8r8g8b8";
+                       /*
+                       * That's a lot of clocks, but it's necessary due
+                       * to unused clk cleanup & no panel driver yet..
+                       */
+                       clocks = <&mmcc MDSS_AHB_CLK>,
+                                <&mmcc MDSS_AXI_CLK>,
+                                <&mmcc MDSS_VSYNC_CLK>,
+                                <&mmcc MDSS_MDP_CLK>,
+                                <&mmcc MDSS_BYTE0_CLK>,
+                                <&mmcc MDSS_BYTE0_INTF_CLK>,
+                                <&mmcc MDSS_PCLK0_CLK>,
+                                <&mmcc MDSS_ESC0_CLK>;
+                       power-domains = <&mmcc MDSS_GDSC>;
                };
        };
 
@@ -77,7 +90,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&vol_keys_default>;
 
-               vol-down {
+               button-vol-down {
                        label = "Volume down";
                        gpios = <&pm8998_gpio 5 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEDOWN>;
@@ -85,7 +98,7 @@
                        wakeup-source;
                };
 
-               vol-up {
+               button-vol-up {
                        label = "Volume up";
                        gpios = <&pm8998_gpio 6 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
                pinctrl-names = "default";
                pinctrl-0 = <&hall_sensor_default>;
 
-               hall-sensor {
+               event-hall-sensor {
                        label = "Hall Effect Sensor";
                        gpios = <&tlmm 124 GPIO_ACTIVE_LOW>;
                        linux,input-type = <EV_SW>;
        status = "okay";
 };
 
-&pm8005_lsid1 {
-       pm8005-regulators {
-               compatible = "qcom,pm8005-regulators";
-
-               vdd_s1-supply = <&vph_pwr>;
-
-               pm8005_s1: s1 { /* VDD_GFX supply */
-                       regulator-min-microvolt = <524000>;
-                       regulator-max-microvolt = <1100000>;
-                       regulator-enable-ramp-delay = <500>;
-
-                       /* hack until we rig up the gpu consumer */
-                       regulator-always-on;
-               };
+&pm8005_regulators {
+       /* VDD_GFX supply */
+       pm8005_s1: s1 {
+               regulator-min-microvolt = <524000>;
+               regulator-max-microvolt = <1100000>;
+               regulator-enable-ramp-delay = <500>;
+               /* Hack until we rig up the gpu consumer */
+               regulator-always-on;
        };
 };
 
 &pm8998_gpio {
-       vol_keys_default: vol-keys-default {
-               pinconf {
-                       pins = "gpio5", "gpio6";
-                       function = "normal";
-                       bias-pull-up;
-                       input-enable;
-                       qcom,drive-strength = <PMIC_GPIO_STRENGTH_NO>;
-               };
+       vol_keys_default: vol-keys-state {
+               pins = "gpio5", "gpio6";
+               function = "normal";
+               bias-pull-up;
+               input-enable;
+               qcom,drive-strength = <PMIC_GPIO_STRENGTH_NO>;
        };
 };
 
                        regulator-min-microvolt = <1352000>;
                        regulator-max-microvolt = <1352000>;
                };
+
                vreg_s4a_1p8: s4 {
                        regulator-min-microvolt = <1800000>;
                        regulator-max-microvolt = <1800000>;
                        regulator-allow-set-load;
                };
+
                vreg_s5a_2p04: s5 {
                        regulator-min-microvolt = <1904000>;
                        regulator-max-microvolt = <2040000>;
                };
+
                vreg_s7a_1p025: s7 {
                        regulator-min-microvolt = <900000>;
                        regulator-max-microvolt = <1028000>;
                };
+
                vreg_l1a_0p875: l1 {
                        regulator-min-microvolt = <880000>;
                        regulator-max-microvolt = <880000>;
                };
+
                vreg_l2a_1p2: l2 {
                        regulator-min-microvolt = <1200000>;
                        regulator-max-microvolt = <1200000>;
                };
+
                vreg_l3a_1p0: l3 {
                        regulator-min-microvolt = <1000000>;
                        regulator-max-microvolt = <1000000>;
                };
+
                vreg_l5a_0p8: l5 {
                        regulator-min-microvolt = <800000>;
                        regulator-max-microvolt = <800000>;
                };
+
                vreg_l6a_1p8: l6 {
                        regulator-min-microvolt = <1808000>;
                        regulator-max-microvolt = <1808000>;
                };
+
                vreg_l7a_1p8: l7 {
                        regulator-min-microvolt = <1800000>;
                        regulator-max-microvolt = <1800000>;
                };
+
                vreg_l8a_1p2: l8 {
                        regulator-min-microvolt = <1200000>;
                        regulator-max-microvolt = <1200000>;
                };
+
                vreg_l9a_1p8: l9 {
                        regulator-min-microvolt = <1808000>;
                        regulator-max-microvolt = <2960000>;
                };
+
                vreg_l10a_1p8: l10 {
                        regulator-min-microvolt = <1808000>;
                        regulator-max-microvolt = <2960000>;
                };
+
                vreg_l11a_1p0: l11 {
                        regulator-min-microvolt = <1000000>;
                        regulator-max-microvolt = <1000000>;
                };
+
                vreg_l12a_1p8: l12 {
                        regulator-min-microvolt = <1800000>;
                        regulator-max-microvolt = <1800000>;
                };
+
                vreg_l13a_2p95: l13 {
                        regulator-min-microvolt = <1808000>;
                        regulator-max-microvolt = <2960000>;
                };
+
                vreg_l14a_1p88: l14 {
                        regulator-min-microvolt = <1880000>;
                        regulator-max-microvolt = <1880000>;
                };
+
                vreg_l15a_1p8: l15 {
                        regulator-min-microvolt = <1800000>;
                        regulator-max-microvolt = <1800000>;
                };
+
                vreg_l16a_2p7: l16 {
                        regulator-min-microvolt = <2704000>;
                        regulator-max-microvolt = <2704000>;
                };
+
                vreg_l17a_1p3: l17 {
                        regulator-min-microvolt = <1304000>;
                        regulator-max-microvolt = <1304000>;
                };
+
                vreg_l18a_2p7: l18 {
                        regulator-min-microvolt = <2704000>;
                        regulator-max-microvolt = <2704000>;
                };
+
                vreg_l19a_3p0: l19 {
                        regulator-min-microvolt = <3008000>;
                        regulator-max-microvolt = <3008000>;
                };
+
                vreg_l20a_2p95: l20 {
                        regulator-min-microvolt = <2960000>;
                        regulator-max-microvolt = <2960000>;
                vreg_l21a_2p95: l21 {
                        regulator-min-microvolt = <2960000>;
                        regulator-max-microvolt = <2960000>;
-                       regulator-allow-set-load;
                        regulator-system-load = <800000>;
+                       regulator-allow-set-load;
                };
+
                vreg_l22a_2p85: l22 {
                        regulator-min-microvolt = <2864000>;
                        regulator-max-microvolt = <2864000>;
                };
+
                vreg_l23a_3p3: l23 {
                        regulator-min-microvolt = <3312000>;
                        regulator-max-microvolt = <3312000>;
                };
+
                vreg_l24a_3p075: l24 {
                        regulator-min-microvolt = <3088000>;
                        regulator-max-microvolt = <3088000>;
                };
+
                vreg_l25a_3p3: l25 {
                        regulator-min-microvolt = <3104000>;
                        regulator-max-microvolt = <3312000>;
                };
+
                vreg_l26a_1p2: l26 {
                        regulator-min-microvolt = <1200000>;
                        regulator-max-microvolt = <1200000>;
                        regulator-allow-set-load;
                };
+
                vreg_l28_3p0: l28 {
                        regulator-min-microvolt = <3008000>;
                        regulator-max-microvolt = <3008000>;
                };
+
                vreg_lvs1a_1p8: lvs1 { };
                vreg_lvs2a_1p8: lvs2 { };
        };
index caacb7c..fcaefc1 100644 (file)
@@ -29,3 +29,7 @@
        regulator-min-microvolt = <2800000>;
        regulator-max-microvolt = <2800000>;
 };
+
+&vreg_lvs1a_1p8 {
+       status = "disabled";
+};
index 978495a..20fe039 100644 (file)
@@ -38,7 +38,7 @@
 };
 
 &pmi8998_gpio {
-       disp_dvdd_en: disp-dvdd-en-active {
+       disp_dvdd_en: disp-dvdd-en-active-state {
                pins = "gpio10";
                function = "normal";
                bias-disable;
index 4a1f98a..c21333a 100644 (file)
 };
 
 &vreg_l18a_2p85 {
-       regulator-min-microvolt = <2850000>;
-       regulator-max-microvolt = <2850000>;
+       /* Note: Round-down from 2850000 to be a multiple of PLDO step-size 8000 */
+       regulator-min-microvolt = <2848000>;
+       regulator-max-microvolt = <2848000>;
 };
 
 &vreg_l22a_2p85 {
-       regulator-min-microvolt = <2700000>;
-       regulator-max-microvolt = <2700000>;
+       /* Note: Round-down from 2700000 to be a multiple of PLDO step-size 8000 */
+       regulator-min-microvolt = <2696000>;
+       regulator-max-microvolt = <2696000>;
 };
index 47488a1..d086390 100644 (file)
@@ -5,15 +5,13 @@
  * Copyright (c) 2021, Konrad Dybcio <konrad.dybcio@somainline.org>
  */
 
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
 #include "msm8998.dtsi"
 #include "pm8005.dtsi"
 #include "pm8998.dtsi"
 #include "pmi8998.dtsi"
-#include <dt-bindings/input/input.h>
-#include <dt-bindings/leds/common.h>
-#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
-#include <dt-bindings/sound/qcom,q6afe.h>
-#include <dt-bindings/sound/qcom,q6asm.h>
 
 / {
        /* required for bootloader to select correct board */
@@ -21,8 +19,6 @@
        qcom,board-id = <8 0>;
 
        clocks {
-               compatible = "simple-bus";
-
                div1_mclk: divclk1 {
                        compatible = "gpio-gate-clock";
                        pinctrl-0 = <&audio_mclk_pin>;
                regulator-boot-on;
        };
 
+       extcon_usb: extcon-usb {
+               compatible = "linux,extcon-usb-gpio";
+               id-gpio = <&tlmm 38 GPIO_ACTIVE_HIGH>;
+               vbus-gpio = <&tlmm 128 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&usb_extcon_active &usb_vbus_active>;
+       };
+
        gpio-keys {
                compatible = "gpio-keys";
                label = "Side buttons";
                pinctrl-names = "default";
                pinctrl-0 = <&vol_down_pin_a>, <&cam_focus_pin_a>,
                            <&cam_snapshot_pin_a>;
-               vol-down {
+               button-vol-down {
                        label = "Volume Down";
                        gpios = <&pm8998_gpio 5 GPIO_ACTIVE_LOW>;
                        linux,input-type = <EV_KEY>;
                        debounce-interval = <15>;
                };
 
-               camera-snapshot {
+               button-camera-snapshot {
                        label = "Camera Snapshot";
                        gpios = <&pm8998_gpio 7 GPIO_ACTIVE_LOW>;
                        linux,input-type = <EV_KEY>;
                        debounce-interval = <15>;
                };
 
-               camera-focus {
+               button-camera-focus {
                        label = "Camera Focus";
                        gpios = <&pm8998_gpio 8 GPIO_ACTIVE_LOW>;
                        linux,input-type = <EV_KEY>;
                pinctrl-names = "default";
                pinctrl-0 = <&hall_sensor0_default>;
 
-               hall-sensor0 {
+               event-hall-sensor0 {
                        label = "Cover Hall Sensor";
                        gpios = <&tlmm 124 GPIO_ACTIVE_LOW>;
                        linux,input-type = <EV_SW>;
        status = "okay";
 };
 
+&blsp2_i2c2 {
+       status = "okay";
+
+       proximity@29 {
+               compatible = "st,vl53l0x";
+               reg = <0x29>;
+
+               interrupt-parent = <&tlmm>;
+               interrupts = <22 IRQ_TYPE_EDGE_FALLING>;
+
+               reset-gpios = <&tlmm 27 GPIO_ACTIVE_LOW>;
+               vdd-supply = <&cam_vio_vreg>;
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&tof_int &tof_reset>;
+       };
+};
+
 &ibb {
        regulator-min-microamp = <800000>;
        regulator-max-microamp = <800000>;
        regulator-soft-start;
 };
 
-&mmcc {
-       status = "ok";
-};
-
-&mmss_smmu {
-       status = "ok";
-};
-
-&pm8005_lsid1 {
-       pm8005-regulators {
-               compatible = "qcom,pm8005-regulators";
-
-               vdd_s1-supply = <&vph_pwr>;
-
-               /* VDD_GFX supply */
-               pm8005_s1: s1 {
-                       regulator-min-microvolt = <524000>;
-                       regulator-max-microvolt = <1088000>;
-                       regulator-enable-ramp-delay = <500>;
-                       regulator-always-on;
-               };
+&pm8005_regulators {
+       /* VDD_GFX supply */
+       pm8005_s1: s1 {
+               regulator-min-microvolt = <524000>;
+               regulator-max-microvolt = <1088000>;
+               regulator-enable-ramp-delay = <500>;
+               /* Hack until we rig up the gpu consumer */
+               regulator-always-on;
        };
 };
 
 &pm8998_gpio {
-       vol_down_pin_a: vol-down-active {
+       vol_down_pin_a: vol-down-active-state {
                pins = "gpio5";
                function = PMIC_GPIO_FUNC_NORMAL;
                bias-pull-up;
                qcom,drive-strength = <PMIC_GPIO_STRENGTH_NO>;
        };
 
-       cam_focus_pin_a: cam-focus-btn-active {
+       cam_focus_pin_a: cam-focus-btn-active-state {
                pins = "gpio7";
                function = PMIC_GPIO_FUNC_NORMAL;
                bias-pull-up;
                qcom,drive-strength = <PMIC_GPIO_STRENGTH_NO>;
        };
 
-       cam_snapshot_pin_a: cam-snapshot-btn-active {
+       cam_snapshot_pin_a: cam-snapshot-btn-active-state {
                pins = "gpio8";
                function = PMIC_GPIO_FUNC_NORMAL;
                bias-pull-up;
                qcom,drive-strength = <PMIC_GPIO_STRENGTH_NO>;
        };
 
-       audio_mclk_pin: audio-mclk-pin-active {
+       audio_mclk_pin: audio-mclk-pin-active-state {
                pins = "gpio13";
                function = "func2";
                power-source = <0>;
 };
 
 &pmi8998_gpio {
-       cam_vio_default: cam-vio-active {
+       cam_vio_default: cam-vio-active-state {
                pins = "gpio1";
                function = PMIC_GPIO_FUNC_NORMAL;
                bias-disable;
                power-source = <1>;
        };
 
-       vib_default: vib-en {
+       vib_default: vib-en-state {
                pins = "gpio5";
                function = PMIC_GPIO_FUNC_NORMAL;
                bias-disable;
        vqmmc-supply = <&vreg_l13a_2p95>;
 
        pinctrl-names = "default", "sleep";
-       pinctrl-0 = <&sdc2_clk_on  &sdc2_cmd_on  &sdc2_data_on  &sdc2_cd_on>;
-       pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>;
+       pinctrl-0 = <&sdc2_on &sdc2_cd>;
+       pinctrl-1 = <&sdc2_off &sdc2_cd>;
 };
 
 &tlmm {
                drive-strength = <2>;
        };
 
+       tof_int: tof-int {
+               pins = "gpio22";
+               function = "gpio";
+               bias-pull-up;
+               drive-strength = <2>;
+               input-enable;
+       };
+
        cam1_vdig_default: cam1-vdig-default {
                pins = "gpio25";
                function = "gpio";
                drive-strength = <2>;
        };
 
+       usb_extcon_active: usb-extcon-active {
+               pins = "gpio38";
+               function = "gpio";
+               bias-disable;
+               drive-strength = <16>;
+       };
+
+       tof_reset: tof-reset {
+               pins = "gpio27";
+               function = "gpio";
+               bias-disable;
+               drive-strength = <2>;
+       };
+
        hall_sensor0_default: acc-cover-open {
                pins = "gpio124";
                function = "gpio";
                bias-pull-up;
        };
 
+       usb_vbus_active: usb-vbus-active {
+               pins = "gpio128";
+               function = "gpio";
+               bias-disable;
+               drive-strength = <2>;
+               output-low;
+       };
+
        ts_vddio_en: ts-vddio-en-default {
                pins = "gpio133";
                function = "gpio";
 &usb3_dwc3 {
        /* Force to peripheral until we have Type-C hooked up */
        dr_mode = "peripheral";
+       extcon = <&extcon_usb>;
 };
 
 &usb3phy {
index 758c45b..02d21bf 100644 (file)
                };
 
                qfprom: qfprom@784000 {
-                       compatible = "qcom,qfprom";
+                       compatible = "qcom,msm8998-qfprom", "qcom,qfprom";
                        reg = <0x00784000 0x621c>;
                        #address-cells = <1>;
                        #size-cells = <1>;
                        interrupts = <GIC_SPI 405 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "msi";
                        interrupt-map-mask = <0 0 0 0x7>;
-                       interrupt-map = <0 0 0 1 &intc 0 0 135 IRQ_TYPE_LEVEL_HIGH>,
+                       interrupt-map = <0 0 0 1 &intc 0 0 135 IRQ_TYPE_LEVEL_HIGH>,
                                        <0 0 0 2 &intc 0 0 136 IRQ_TYPE_LEVEL_HIGH>,
                                        <0 0 0 3 &intc 0 0 138 IRQ_TYPE_LEVEL_HIGH>,
                                        <0 0 0 4 &intc 0 0 139 IRQ_TYPE_LEVEL_HIGH>;
                        reg = <0x03400000 0xc00000>;
                        interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
                        gpio-controller;
-                       #gpio-cells = <0x2>;
+                       #gpio-cells = <2>;
                        interrupt-controller;
-                       #interrupt-cells = <0x2>;
+                       #interrupt-cells = <2>;
 
-                       sdc2_clk_on: sdc2_clk_on {
-                               config {
+                       sdc2_on: sdc2-on {
+                               clk {
                                        pins = "sdc2_clk";
-                                       bias-disable;
                                        drive-strength = <16>;
-                               };
-                       };
-
-                       sdc2_clk_off: sdc2_clk_off {
-                               config {
-                                       pins = "sdc2_clk";
                                        bias-disable;
-                                       drive-strength = <2>;
                                };
-                       };
 
-                       sdc2_cmd_on: sdc2_cmd_on {
-                               config {
+                               cmd {
                                        pins = "sdc2_cmd";
-                                       bias-pull-up;
                                        drive-strength = <10>;
-                               };
-                       };
-
-                       sdc2_cmd_off: sdc2_cmd_off {
-                               config {
-                                       pins = "sdc2_cmd";
                                        bias-pull-up;
-                                       drive-strength = <2>;
                                };
-                       };
 
-                       sdc2_data_on: sdc2_data_on {
-                               config {
+                               data {
                                        pins = "sdc2_data";
-                                       bias-pull-up;
                                        drive-strength = <10>;
+                                       bias-pull-up;
                                };
                        };
 
-                       sdc2_data_off: sdc2_data_off {
-                               config {
-                                       pins = "sdc2_data";
-                                       bias-pull-up;
+                       sdc2_off: sdc2-off {
+                               clk {
+                                       pins = "sdc2_clk";
                                        drive-strength = <2>;
+                                       bias-disable;
                                };
-                       };
 
-                       sdc2_cd_on: sdc2_cd_on {
-                               mux {
-                                       pins = "gpio95";
-                                       function = "gpio";
+                               cmd {
+                                       pins = "sdc2_cmd";
+                                       drive-strength = <2>;
+                                       bias-pull-up;
                                };
 
-                               config {
-                                       pins = "gpio95";
-                                       bias-pull-up;
+                               data {
+                                       pins = "sdc2_data";
                                        drive-strength = <2>;
+                                       bias-pull-up;
                                };
                        };
 
-                       sdc2_cd_off: sdc2_cd_off {
-                               mux {
-                                       pins = "gpio95";
-                                       function = "gpio";
-                               };
-
-                               config {
-                                       pins = "gpio95";
-                                       bias-pull-up;
-                                       drive-strength = <2>;
-                               };
+                       sdc2_cd: sdc2-cd {
+                               pins = "gpio95";
+                               function = "gpio";
+                               bias-pull-up;
+                               drive-strength = <2>;
                        };
 
-                       blsp1_uart3_on: blsp1_uart3_on {
+                       blsp1_uart3_on: blsp1-uart3-on {
                                tx {
                                        pins = "gpio45";
                                        function = "blsp_uart3_a";
                        status = "disabled";
 
                        gpu_opp_table: opp-table {
-                               compatible  = "operating-points-v2";
+                               compatible = "operating-points-v2";
                                opp-710000097 {
                                        opp-hz = /bits/ 64 <710000097>;
                                        opp-level = <RPM_SMD_LEVEL_TURBO>;
                                      <0xc010600 0x128>,
                                      <0xc010800 0x200>;
                                #phy-cells = <0>;
-                               #clock-cells = <1>;
+                               #clock-cells = <0>;
                                clocks = <&gcc GCC_USB3_PHY_PIPE_CLK>;
                                clock-names = "pipe0";
                                clock-output-names = "usb3_phy_pipe_clk_src";
                        nvmem-cells = <&qusb2_hstx_trim>;
                };
 
-               sdhc2: sdhci@c0a4900 {
+               sdhc2: mmc@c0a4900 {
                        compatible = "qcom,sdhci-msm-v4";
                        reg = <0x0c0a4900 0x314>, <0x0c0a4000 0x800>;
                        reg-names = "hc_mem", "core_mem";
                        #reset-cells = <1>;
                        #power-domain-cells = <1>;
                        reg = <0xc8c0000 0x40000>;
-                       status = "disabled";
 
                        clock-names = "xo",
                                      "gpll0",
                                 <&mmcc BIMC_SMMU_AXI_CLK>;
                        clock-names = "iface-mm", "iface-smmu",
                                      "bus-mm", "bus-smmu";
-                       status = "disabled";
 
                        #global-interrupts = <0>;
                        interrupts =
index c5d8506..ecf9b99 100644 (file)
                };
 
                pm6350_gpios: gpios@c000 {
-                       compatible = "qcom,pm6350-gpio";
+                       compatible = "qcom,pm6350-gpio", "qcom,spmi-gpio";
                        reg = <0xc000>;
                        gpio-controller;
+                       gpio-ranges = <&pm6350_gpios 0 0 9>;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
index c482663..d0eefbb 100644 (file)
                };
 
                pm660_gpios: gpios@c000 {
-                       compatible = "qcom,pm660-gpio";
+                       compatible = "qcom,pm660-gpio", "qcom,spmi-gpio";
                        reg = <0xc000>;
                        gpio-controller;
                        gpio-ranges = <&pm660_gpios 0 0 13>;
index cfef423..c794547 100644 (file)
                #address-cells = <1>;
                #size-cells = <0>;
 
+               pm660l_lpg: lpg@b100 {
+                       compatible = "qcom,pm660l-lpg";
+
+                       status = "disabled";
+               };
+
                pm660l_wled: leds@d800 {
                        compatible = "qcom,pm660l-wled";
-                       reg = <0xd800 0xd900>;
+                       reg = <0xd800>, <0xd900>;
                        interrupts = <0x3 0xd8 0x1 IRQ_TYPE_EDGE_RISING>;
                        interrupt-names = "ovp";
                        label = "backlight";
index 3f97607..50fb6c7 100644 (file)
@@ -28,5 +28,9 @@
                reg = <0x5 SPMI_USID>;
                #address-cells = <1>;
                #size-cells = <0>;
+
+               pm8005_regulators: regulators {
+                       compatible = "qcom,pm8005-regulators";
+               };
        };
 };
index b126d7e..0c2c424 100644 (file)
                };
 
                pm8009_gpios: gpio@c000 {
-                       compatible = "qcom,pm8005-gpio";
+                       compatible = "qcom,pm8005-gpio", "qcom,spmi-gpio";
                        reg = <0xc000>;
                        gpio-controller;
+                       gpio-ranges = <&pm8009_gpios 0 0 4>;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
index 0df76f7..fd84342 100644 (file)
                };
 
                pm8150_gpios: gpio@c000 {
-                       compatible = "qcom,pm8150-gpio";
+                       compatible = "qcom,pm8150-gpio", "qcom,spmi-gpio";
                        reg = <0xc000>;
                        gpio-controller;
+                       gpio-ranges = <&pm8150_gpios 0 0 10>;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
index 058cc51..5d1ec3a 100644 (file)
                };
 
                pm8150b_gpios: gpio@c000 {
-                       compatible = "qcom,pm8150b-gpio";
+                       compatible = "qcom,pm8150b-gpio", "qcom,spmi-gpio";
                        reg = <0xc000>;
                        gpio-controller;
+                       gpio-ranges = <&pm8150b_gpios 0 0 12>;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
                reg = <0x3 SPMI_USID>;
                #address-cells = <1>;
                #size-cells = <0>;
+
+               pm8150b_lpg: lpg {
+                       compatible = "qcom,pm8150b-lpg";
+
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       #pwm-cells = <2>;
+
+                       status = "disabled";
+               };
        };
 };
index 52f094a..c62d023 100644 (file)
                };
 
                pm8150l_gpios: gpio@c000 {
-                       compatible = "qcom,pm8150l-gpio";
+                       compatible = "qcom,pm8150l-gpio", "qcom,spmi-gpio";
                        reg = <0xc000>;
                        gpio-controller;
+                       gpio-ranges = <&pm8150l_gpios 0 0 12>;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
                reg = <0x5 SPMI_USID>;
                #address-cells = <1>;
                #size-cells = <0>;
+
+               pm8150l_lpg: lpg {
+                       compatible = "qcom,pm8150l-lpg";
+
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       #pwm-cells = <2>;
+
+                       status = "disabled";
+               };
+
        };
 };
index b10f33a..2dfeb99 100644 (file)
                };
 
                pm8350_gpios: gpio@8800 {
-                       compatible = "qcom,pm8350-gpio";
+                       compatible = "qcom,pm8350-gpio", "qcom,spmi-gpio";
                        reg = <0x8800>;
                        gpio-controller;
+                       gpio-ranges = <&pm8350_gpios 0 0 10>;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
index f1d1d4c..f1c7bd9 100644 (file)
                };
 
                pm8350b_gpios: gpio@8800 {
-                       compatible = "qcom,pm8350b-gpio";
+                       compatible = "qcom,pm8350b-gpio", "qcom,spmi-gpio";
                        reg = <0x8800>;
                        gpio-controller;
+                       gpio-ranges = <&pm8350b_gpios 0 0 8>;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
index d589024..606c2a6 100644 (file)
                };
 
                pm8916_gpios: gpios@c000 {
-                       compatible = "qcom,pm8916-gpio";
+                       compatible = "qcom,pm8916-gpio", "qcom,spmi-gpio";
                        reg = <0xc000>;
                        gpio-controller;
+                       gpio-ranges = <&pm8916_gpios 0 0 4>;
                        #gpio-cells = <2>;
-                       interrupts = <0 0xc0 0 IRQ_TYPE_NONE>,
-                                    <0 0xc1 0 IRQ_TYPE_NONE>,
-                                    <0 0xc2 0 IRQ_TYPE_NONE>,
-                                    <0 0xc3 0 IRQ_TYPE_NONE>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
                };
        };
 
                #address-cells = <1>;
                #size-cells = <0>;
 
+               pm8916_pwm: pwm {
+                       compatible = "qcom,pm8916-pwm";
+
+                       #pwm-cells = <2>;
+
+                       status = "disabled";
+               };
+
                pm8916_vib: vibrator@c000 {
                        compatible = "qcom,pm8916-vib";
                        reg = <0xc000>;
index 5ab4611..ab34239 100644 (file)
                #address-cells = <1>;
                #size-cells = <0>;
 
+               pm8994_lpg: lpg {
+                       compatible = "qcom,pm8994-lpg";
+
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       #pwm-cells = <2>;
+
+                       status = "disabled";
+               };
+
                pm8994_spmi_regulators: regulators {
                        compatible = "qcom,pm8994-regulators";
                };
index 6e7c252..84c4491 100644 (file)
                        interrupt-controller;
                        #interrupt-cells = <2>;
                };
+
+               pmi8994_mpps: mpps@a000 {
+                       compatible = "qcom,pmi8994-mpp";
+                       reg = <0xa000>;
+                       gpio-controller;
+                       gpio-ranges = <&pmi8994_mpps 0 0 4>;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
        };
 
        pmic@3 {
                #address-cells = <1>;
                #size-cells = <0>;
 
+               pmi8994_lpg: lpg {
+                       compatible = "qcom,pmi8994-lpg";
+
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       #pwm-cells = <2>;
+
+                       status = "disabled";
+               };
+
                pmi8994_spmi_regulators: regulators {
                        compatible = "qcom,pmi8994-regulators";
                        #address-cells = <1>;
@@ -35,7 +55,7 @@
 
                pmi8994_wled: wled@d800 {
                        compatible = "qcom,pmi8994-wled";
-                       reg = <0xd800 0xd900>;
+                       reg = <0xd800>, <0xd900>;
                        interrupts = <3 0xd8 0x02 IRQ_TYPE_EDGE_RISING>;
                        interrupt-names = "short";
                        qcom,cabc;
index 0fef5f1..6d3d212 100644 (file)
                        };
                };
 
+               pmi8998_lpg: lpg {
+                       compatible = "qcom,pmi8998-lpg";
+
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       #pwm-cells = <2>;
+
+                       status = "disabled";
+               };
+
                pmi8998_wled: leds@d800 {
                        compatible = "qcom,pmi8998-wled";
-                       reg = <0xd800 0xd900>;
+                       reg = <0xd800>, <0xd900>;
                        interrupts = <0x3 0xd8 0x1 IRQ_TYPE_EDGE_RISING>,
                                     <0x3 0xd8 0x2 IRQ_TYPE_EDGE_RISING>;
                        interrupt-names = "ovp", "short";
@@ -52,6 +62,5 @@
 
                        status = "disabled";
                };
-
        };
 };
index 7072e5a..68e9122 100644 (file)
                };
 
                pmm8155au_1_gpios: gpio@c000 {
-                       compatible = "qcom,pmm8155au-gpio";
+                       compatible = "qcom,pmm8155au-gpio", "qcom,spmi-gpio";
                        reg = <0xc000>;
                        gpio-controller;
                        #gpio-cells = <2>;
index 7207596..c307fc6 100644 (file)
@@ -89,7 +89,7 @@
                };
 
                pmm8155au_2_gpios: gpio@c000 {
-                       compatible = "qcom,pmm8155au-gpio";
+                       compatible = "qcom,pmm8155au-gpio", "qcom,spmi-gpio";
                        reg = <0xc000>;
                        gpio-controller;
                        #gpio-cells = <2>;
index 6043241..ec24c44 100644 (file)
                };
 
                pmr735b_gpios: gpio@8800 {
-                       compatible = "qcom,pmr735b-gpio";
+                       compatible = "qcom,pmr735b-gpio", "qcom,spmi-gpio";
                        reg = <0x8800>;
                        gpio-controller;
+                       gpio-ranges = <&pmr735b_gpios 0 0 4>;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
index 98d173a..634b068 100644 (file)
                #size-cells = <0>;
 
                pms405_gpios: gpio@c000 {
-                       compatible = "qcom,pms405-gpio";
+                       compatible = "qcom,pms405-gpio", "qcom,spmi-gpio";
                        reg = <0xc000>;
                        gpio-controller;
+                       gpio-ranges = <&pms405_gpios 0 0 12>;
                        #gpio-cells = <2>;
-                       interrupts = <0 0xc0 0 IRQ_TYPE_NONE>,
-                               <0 0xc1 0 IRQ_TYPE_NONE>,
-                               <0 0xc2 0 IRQ_TYPE_NONE>,
-                               <0 0xc3 0 IRQ_TYPE_NONE>,
-                               <0 0xc4 0 IRQ_TYPE_NONE>,
-                               <0 0xc5 0 IRQ_TYPE_NONE>,
-                               <0 0xc6 0 IRQ_TYPE_NONE>,
-                               <0 0xc7 0 IRQ_TYPE_NONE>,
-                               <0 0xc8 0 IRQ_TYPE_NONE>,
-                               <0 0xc9 0 IRQ_TYPE_NONE>,
-                               <0 0xca 0 IRQ_TYPE_NONE>,
-                               <0 0xcb 0 IRQ_TYPE_NONE>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
                };
 
                pon@800 {
index 2f3104a..1721ebe 100644 (file)
 };
 
 &pms405_gpios {
-       usb_vbus_boost_pin: usb-vbus-boost-pin {
+       usb_vbus_boost_pin: usb-vbus-boost-state {
                pinconf {
                        pins = "gpio3";
                        function = PMIC_GPIO_FUNC_NORMAL;
                        power-source = <1>;
                };
        };
-       usb3_vbus_pin: usb3-vbus-pin {
+       usb3_vbus_pin: usb3-vbus-state {
                pinconf {
                        pins = "gpio12";
                        function = PMIC_GPIO_FUNC_NORMAL;
index d912166..9ab9900 100644 (file)
                };
 
                qfprom: qfprom@a4000 {
-                       compatible = "qcom,qfprom";
+                       compatible = "qcom,qcs404-qfprom", "qcom,qfprom";
                        reg = <0x000a4000 0x1000>;
                        #address-cells = <1>;
                        #size-cells = <1>;
                                compatible = "snps,dwc3";
                                reg = <0x07580000 0xcd00>;
                                interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
-                               phys = <&usb2_phy_sec>, <&usb3_phy>;
+                               phys = <&usb2_phy_prim>, <&usb3_phy>;
                                phy-names = "usb2-phy", "usb3-phy";
                                snps,has-lpm-erratum;
                                snps,hird-threshold = /bits/ 8 <0x10>;
                                compatible = "snps,dwc3";
                                reg = <0x078c0000 0xcc00>;
                                interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
-                               phys = <&usb2_phy_prim>;
+                               phys = <&usb2_phy_sec>;
                                phy-names = "usb2-phy";
                                snps,has-lpm-erratum;
                                snps,hird-threshold = /bits/ 8 <0x10>;
                        };
 
                        blsp1_spi1_default: blsp1-spi1-default {
-                               pins = "gpio22", "gpio23", "gpio24", "gpio25";
-                               function = "blsp_spi1";
+                               mosi {
+                                       pins = "gpio22";
+                                       function = "blsp_spi_mosi_a1";
+                               };
+
+                               miso {
+                                       pins = "gpio23";
+                                       function = "blsp_spi_miso_a1";
+                               };
+
+                               cs_n {
+                                       pins = "gpio24";
+                                       function = "blsp_spi_cs_n_a1";
+                               };
+
+                               clk {
+                                       pins = "gpio25";
+                                       function = "blsp_spi_clk_a1";
+                               };
                        };
 
                        blsp1_spi2_default: blsp1-spi2-default {
                        status = "disabled";
                };
 
-               sdcc1: sdcc@7804000 {
+               sdcc1: mmc@7804000 {
                        compatible = "qcom,qcs404-sdhci", "qcom,sdhci-msm-v5";
                        reg = <0x07804000 0x1000>, <0x7805000 0x1000>;
                        reg-names = "hc", "cqhci";
                                     <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "hc_irq", "pwr_irq";
 
-                       clocks = <&gcc GCC_SDCC1_APPS_CLK>,
-                                <&gcc GCC_SDCC1_AHB_CLK>,
+                       clocks = <&gcc GCC_SDCC1_AHB_CLK>,
+                                <&gcc GCC_SDCC1_APPS_CLK>,
                                 <&xo_board>;
-                       clock-names = "core", "iface", "xo";
+                       clock-names = "iface", "core", "xo";
 
                        status = "disabled";
                };
                        status = "disabled";
                };
 
-               imem@8600000 {
-                       compatible = "simple-mfd";
+               sram@8600000 {
+                       compatible = "qcom,qcs404-imem", "syscon", "simple-mfd";
                        reg = <0x08600000 0x1000>;
 
                        #address-cells = <1>;
index 0e63f70..bf8077a 100644 (file)
@@ -5,6 +5,7 @@
 
 /dts-v1/;
 
+#include <dt-bindings/leds/common.h>
 #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
 #include <dt-bindings/sound/qcom,q6afe.h>
 #include <dt-bindings/sound/qcom,q6asm.h>
        leds {
                compatible = "gpio-leds";
 
-               user4 {
+               led-user4 {
                        label = "green:user4";
+                       function = LED_FUNCTION_INDICATOR;
+                       color = <LED_COLOR_ID_GREEN>;
                        gpios = <&pm8150_gpios 10 GPIO_ACTIVE_HIGH>;
                        linux,default-trigger = "panic-indicator";
                        default-state = "off";
                };
 
-               wlan {
+               led-wlan {
                        label = "yellow:wlan";
+                       function = LED_FUNCTION_WLAN;
+                       color = <LED_COLOR_ID_YELLOW>;
                        gpios = <&pm8150_gpios 9 GPIO_ACTIVE_HIGH>;
                        linux,default-trigger = "phy0tx";
                        default-state = "off";
                };
 
-               bt {
+               led-bt {
                        label = "blue:bt";
+                       function = LED_FUNCTION_BLUETOOTH;
+                       color = <LED_COLOR_ID_BLUE>;
                        gpios = <&pm8150_gpios 7 GPIO_ACTIVE_HIGH>;
                        linux,default-trigger = "bluetooth-power";
                        default-state = "off";
                };
-
        };
 
        lt9611_1v2: lt9611-vdd12-regulator {
                "NC",
                "PM3003A_MODE";
 
-       lt9611_rst_pin: lt9611-rst-pin {
+       lt9611_rst_pin: lt9611-rst-state {
                pins = "gpio5";
                function = "normal";
 
        };
 };
 
+&pm8150l_lpg {
+       status = "okay";
+
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       led@1 {
+               reg = <1>;
+               color = <LED_COLOR_ID_GREEN>;
+               function = LED_FUNCTION_HEARTBEAT;
+               function-enumerator = <3>;
+
+               linux,default-trigger = "heartbeat";
+               default-state = "on";
+       };
+
+       led@2 {
+               reg = <2>;
+               color = <LED_COLOR_ID_GREEN>;
+               function = LED_FUNCTION_INDICATOR;
+               function-enumerator = <2>;
+               default-state = "on";
+       };
+
+       led@3 {
+               reg = <3>;
+               color = <LED_COLOR_ID_GREEN>;
+               function = LED_FUNCTION_INDICATOR;
+               function-enumerator = <1>;
+       };
+};
+
 &pon_pwrkey {
        status = "okay";
 };
 
 &q6afedai {
        qi2s@16 {
-               reg = <16>;
+               reg = <PRIMARY_MI2S_RX>;
                qcom,sd-lines = <0 1 2 3>;
        };
 };
 /* TERT I2S Uses 1 I2S SD Lines for audio on LT9611 HDMI Bridge */
 &q6afedai {
        qi2s@20 {
-               reg = <20>;
+               reg = <TERTIARY_MI2S_RX>;
                qcom,sd-lines = <0>;
        };
 };
                };
 
                codec {
-                       sound-dai =  <&lt9611_codec 0>;
+                       sound-dai = <&lt9611_codec 0>;
                };
        };
 
diff --git a/arch/arm64/boot/dts/qcom/sa8295p-adp.dts b/arch/arm64/boot/dts/qcom/sa8295p-adp.dts
new file mode 100644 (file)
index 0000000..9398f03
--- /dev/null
@@ -0,0 +1,389 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+#include <dt-bindings/spmi/spmi.h>
+
+#include "sa8540p.dtsi"
+
+/ {
+       model = "Qualcomm SA8295P ADP";
+       compatible = "qcom,sa8295p-adp", "qcom,sa8540p";
+
+       aliases {
+               serial0 = &qup2_uart17;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+};
+
+&apps_rsc {
+       pmm8540-a-regulators {
+               compatible = "qcom,pm8150-rpmh-regulators";
+               qcom,pmic-id = "a";
+
+               vreg_l3a: ldo3 {
+                       regulator-name = "vreg_l3a";
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1208000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l5a: ldo5 {
+                       regulator-name = "vreg_l5a";
+                       regulator-min-microvolt = <912000>;
+                       regulator-max-microvolt = <912000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l7a: ldo7 {
+                       regulator-name = "vreg_l7a";
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l13a: ldo13 {
+                       regulator-name = "vreg_l13a";
+                       regulator-min-microvolt = <3072000>;
+                       regulator-max-microvolt = <3072000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+       };
+
+       pmm8540-c-regulators {
+               compatible = "qcom,pm8150-rpmh-regulators";
+               qcom,pmic-id = "c";
+
+               vreg_l1c: ldo1 {
+                       regulator-name = "vreg_l1c";
+                       regulator-min-microvolt = <912000>;
+                       regulator-max-microvolt = <912000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l2c: ldo2 {
+                       regulator-name = "vreg_l2c";
+                       regulator-min-microvolt = <3072000>;
+                       regulator-max-microvolt = <3072000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l3c: ldo3 {
+                       regulator-name = "vreg_l3c";
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1200000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l4c: ldo4 {
+                       regulator-name = "vreg_l4c";
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1208000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l6c: ldo6 {
+                       regulator-name = "vreg_l6c";
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1200000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l7c: ldo7 {
+                       regulator-name = "vreg_l7c";
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l10c: ldo10 {
+                       regulator-name = "vreg_l10c";
+                       regulator-min-microvolt = <2504000>;
+                       regulator-max-microvolt = <2504000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l17c: ldo17 {
+                       regulator-name = "vreg_l17c";
+                       regulator-min-microvolt = <2504000>;
+                       regulator-max-microvolt = <2504000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+       };
+
+       pmm8540-g-regulators {
+               compatible = "qcom,pm8150-rpmh-regulators";
+               qcom,pmic-id = "g";
+
+               vreg_l3g: ldo3 {
+                       regulator-name = "vreg_l3g";
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1200000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l7g: ldo7 {
+                       regulator-name = "vreg_l7g";
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l8g: ldo8 {
+                       regulator-name = "vreg_l8g";
+                       regulator-min-microvolt = <880000>;
+                       regulator-max-microvolt = <880000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+       };
+};
+
+&qup2 {
+       status = "okay";
+};
+
+&qup2_uart17 {
+       compatible = "qcom,geni-debug-uart";
+       status = "okay";
+};
+
+&remoteproc_adsp {
+       firmware-name = "qcom/sa8540p/adsp.mbn";
+       status = "okay";
+};
+
+&remoteproc_nsp0 {
+       firmware-name = "qcom/sa8540p/cdsp.mbn";
+       status = "okay";
+};
+
+&remoteproc_nsp1 {
+       firmware-name = "qcom/sa8540p/cdsp1.mbn";
+       status = "okay";
+};
+
+&spmi_bus {
+       pm8450a: pmic@0 {
+               compatible = "qcom,pm8150", "qcom,spmi-pmic";
+               reg = <0x0 SPMI_USID>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               pm8450a_gpios: gpio@c000 {
+                       compatible = "qcom,pm8150-gpio";
+                       reg = <0xc000>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+       };
+
+       pm8450c: pmic@4 {
+               compatible = "qcom,pm8150", "qcom,spmi-pmic";
+               reg = <0x4 SPMI_USID>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               pm8450c_gpios: gpio@c000 {
+                       compatible = "qcom,pm8150-gpio";
+                       reg = <0xc000>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+       };
+
+       pm8450e: pmic@8 {
+               compatible = "qcom,pm8150", "qcom,spmi-pmic";
+               reg = <0x8 SPMI_USID>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               pm8450e_gpios: gpio@c000 {
+                       compatible = "qcom,pm8150-gpio";
+                       reg = <0xc000>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+       };
+
+       pm8450g: pmic@c {
+               compatible = "qcom,pm8150", "qcom,spmi-pmic";
+               reg = <0xc SPMI_USID>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               pm8450g_gpios: gpio@c000 {
+                       compatible = "qcom,pm8150-gpio";
+                       reg = <0xc000>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+       };
+};
+
+&ufs_mem_hc {
+       reset-gpios = <&tlmm 228 GPIO_ACTIVE_LOW>;
+
+       vcc-supply = <&vreg_l17c>;
+       vcc-max-microamp = <800000>;
+       vccq-supply = <&vreg_l6c>;
+       vccq-max-microamp = <900000>;
+
+       status = "okay";
+};
+
+&ufs_mem_phy {
+       vdda-phy-supply = <&vreg_l8g>;
+       vdda-pll-supply = <&vreg_l3g>;
+
+       status = "okay";
+};
+
+&ufs_card_hc {
+       reset-gpios = <&tlmm 229 GPIO_ACTIVE_LOW>;
+
+       vcc-supply = <&vreg_l10c>;
+       vcc-max-microamp = <800000>;
+       vccq-supply = <&vreg_l3c>;
+       vccq-max-microamp = <900000>;
+
+       status = "okay";
+};
+
+&ufs_card_phy {
+       vdda-phy-supply = <&vreg_l8g>;
+       vdda-pll-supply = <&vreg_l3g>;
+
+       status = "okay";
+};
+
+&usb_0 {
+       status = "okay";
+};
+
+&usb_0_dwc3 {
+       /* TODO: Define USB-C connector properly */
+       dr_mode = "peripheral";
+};
+
+&usb_0_hsphy {
+       vdda-pll-supply = <&vreg_l5a>;
+       vdda18-supply = <&vreg_l7a>;
+       vdda33-supply = <&vreg_l13a>;
+
+       status = "okay";
+};
+
+&usb_0_qmpphy {
+       vdda-phy-supply = <&vreg_l3a>;
+       vdda-pll-supply = <&vreg_l5a>;
+
+       status = "okay";
+};
+
+&usb_1 {
+       status = "okay";
+};
+
+&usb_1_dwc3 {
+       /* TODO: Define USB-C connector properly */
+       dr_mode = "host";
+};
+
+&usb_1_hsphy {
+       vdda-pll-supply = <&vreg_l1c>;
+       vdda18-supply = <&vreg_l7c>;
+       vdda33-supply = <&vreg_l2c>;
+
+       status = "okay";
+};
+
+&usb_1_qmpphy {
+       vdda-phy-supply = <&vreg_l4c>;
+       vdda-pll-supply = <&vreg_l1c>;
+
+       status = "okay";
+};
+
+&usb_2_hsphy0 {
+       vdda-pll-supply = <&vreg_l5a>;
+       vdda18-supply = <&vreg_l7g>;
+       vdda33-supply = <&vreg_l13a>;
+
+       status = "okay";
+};
+
+&usb_2_hsphy1 {
+       vdda-pll-supply = <&vreg_l5a>;
+       vdda18-supply = <&vreg_l7g>;
+       vdda33-supply = <&vreg_l13a>;
+
+       status = "okay";
+};
+
+&usb_2_hsphy2 {
+       vdda-pll-supply = <&vreg_l5a>;
+       vdda18-supply = <&vreg_l7g>;
+       vdda33-supply = <&vreg_l13a>;
+
+       status = "okay";
+};
+
+&usb_2_hsphy3 {
+       vdda-pll-supply = <&vreg_l5a>;
+       vdda18-supply = <&vreg_l7g>;
+       vdda33-supply = <&vreg_l13a>;
+
+       status = "okay";
+};
+
+&usb_2_qmpphy0 {
+       vdda-phy-supply = <&vreg_l3a>;
+       vdda-pll-supply = <&vreg_l5a>;
+
+       status = "okay";
+};
+
+&usb_2_qmpphy1 {
+       vdda-phy-supply = <&vreg_l3a>;
+       vdda-pll-supply = <&vreg_l5a>;
+
+       status = "okay";
+};
+
+&xo_board_clk {
+       clock-frequency = <38400000>;
+};
+
+/* PINCTRL */
diff --git a/arch/arm64/boot/dts/qcom/sa8540p.dtsi b/arch/arm64/boot/dts/qcom/sa8540p.dtsi
new file mode 100644 (file)
index 0000000..8ea2886
--- /dev/null
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+#include "sc8280xp.dtsi"
+
+/delete-node/ &cpu0_opp_table;
+/delete-node/ &cpu4_opp_table;
+
+/ {
+       cpu0_opp_table: cpu0-opp-table {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp-403200000 {
+                       opp-hz = /bits/ 64 <403200000>;
+               };
+               opp-499200000 {
+                       opp-hz = /bits/ 64 <499200000>;
+               };
+               opp-595200000 {
+                       opp-hz = /bits/ 64 <595200000>;
+               };
+               opp-710400000 {
+                       opp-hz = /bits/ 64 <710400000>;
+               };
+               opp-806400000 {
+                       opp-hz = /bits/ 64 <806400000>;
+               };
+               opp-902400000 {
+                       opp-hz = /bits/ 64 <902400000>;
+               };
+               opp-1017600000 {
+                       opp-hz = /bits/ 64 <1017600000>;
+               };
+               opp-1113600000 {
+                       opp-hz = /bits/ 64 <1113600000>;
+               };
+               opp-1209600000 {
+                       opp-hz = /bits/ 64 <1209600000>;
+               };
+               opp-1324800000 {
+                       opp-hz = /bits/ 64 <1324800000>;
+               };
+               opp-1440000000 {
+                       opp-hz = /bits/ 64 <1440000000>;
+               };
+               opp-1555200000 {
+                       opp-hz = /bits/ 64 <1555200000>;
+               };
+               opp-1670400000 {
+                       opp-hz = /bits/ 64 <1670400000>;
+               };
+               opp-1785600000 {
+                       opp-hz = /bits/ 64 <1785600000>;
+               };
+               opp-1881600000 {
+                       opp-hz = /bits/ 64 <1881600000>;
+               };
+               opp-2016000000 {
+                       opp-hz = /bits/ 64 <2016000000>;
+               };
+               opp-2131200000 {
+                       opp-hz = /bits/ 64 <2131200000>;
+               };
+               opp-2246400000 {
+                       opp-hz = /bits/ 64 <2246400000>;
+               };
+       };
+
+       cpu4_opp_table: cpu4-opp-table {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp-825600000 {
+                       opp-hz = /bits/ 64 <825600000>;
+               };
+               opp-940800000 {
+                       opp-hz = /bits/ 64 <940800000>;
+               };
+               opp-1056000000 {
+                       opp-hz = /bits/ 64 <1056000000>;
+               };
+               opp-1171200000 {
+                       opp-hz = /bits/ 64 <1171200000>;
+               };
+               opp-1286400000 {
+                       opp-hz = /bits/ 64 <1286400000>;
+               };
+               opp-1401600000 {
+                       opp-hz = /bits/ 64 <1401600000>;
+               };
+               opp-1516800000 {
+                       opp-hz = /bits/ 64 <1516800000>;
+               };
+               opp-1632000000 {
+                       opp-hz = /bits/ 64 <1632000000>;
+               };
+               opp-1747200000 {
+                       opp-hz = /bits/ 64 <1747200000>;
+               };
+               opp-1862400000 {
+                       opp-hz = /bits/ 64 <1862400000>;
+               };
+               opp-1977600000 {
+                       opp-hz = /bits/ 64 <1977600000>;
+               };
+               opp-2073600000 {
+                       opp-hz = /bits/ 64 <2073600000>;
+               };
+               opp-2169600000 {
+                       opp-hz = /bits/ 64 <2169600000>;
+               };
+               opp-2284800000 {
+                       opp-hz = /bits/ 64 <2284800000>;
+               };
+               opp-2380800000 {
+                       opp-hz = /bits/ 64 <2380800000>;
+               };
+               opp-2496000000 {
+                       opp-hz = /bits/ 64 <2496000000>;
+               };
+               opp-2592000000 {
+                       opp-hz = /bits/ 64 <2592000000>;
+               };
+       };
+};
+
+&rpmhpd {
+       compatible = "qcom,sa8540p-rpmhpd";
+};
index acdb36f..9dee131 100644 (file)
 
 &dsi_phy {
        status = "okay";
+       vdds-supply = <&vreg_l4a_0p8>;
 };
 
 &mdp {
        pinctrl-names = "default","sleep";
        pinctrl-0 = <&sdc2_on>;
        pinctrl-1 = <&sdc2_off>;
-       vmmc-supply  = <&vreg_l9c_2p9>;
+       vmmc-supply = <&vreg_l9c_2p9>;
        vqmmc-supply = <&vreg_l6c_2p9>;
 
        cd-gpios = <&tlmm 69 GPIO_ACTIVE_LOW>;
 /* PINCTRL - additions to nodes defined in sc7180.dtsi */
 
 &pm6150l_gpio {
-       disp_pins: disp-pins {
+       disp_pins: disp-state {
                pinconf {
                        pins = "gpio3";
                        function = PMIC_GPIO_FUNC_FUNC1;
index 8ac1f1e..7ee407f 100644 (file)
 };
 
 &cros_ec {
+       keyboard-controller {
+               compatible = "google,cros-ec-keyb-switches";
+       };
+
        cros_ec_proximity: proximity {
                compatible = "google,cros-ec-mkbp-proximity";
                label = "proximity-wifi";
index 9b3e3d1..1bd6c7d 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright 2021 Google LLC.
  */
 
-#include "sc7180-trogdor.dtsi"
+/* This file must be included after sc7180-trogdor.dtsi */
 
 / {
        /* BOARD-SPECIFIC TOP LEVEL NODES */
@@ -114,6 +114,12 @@ ap_ts_pen_1v8: &i2c4 {
        status = "okay";
 };
 
+&cros_ec {
+       keyboard-controller {
+               compatible = "google,cros-ec-keyb-switches";
+       };
+};
+
 &panel {
        compatible = "samsung,atna33xc20";
        enable-gpios = <&tlmm 12 GPIO_ACTIVE_HIGH>;
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-kingoftown-r0.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-kingoftown-r0.dts
new file mode 100644 (file)
index 0000000..1a62e8d
--- /dev/null
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Kingoftown board device tree source
+ *
+ * Copyright 2021 Google LLC.
+ */
+
+/dts-v1/;
+
+#include "sc7180-trogdor.dtsi"
+#include "sc7180-trogdor-ti-sn65dsi86.dtsi"
+#include "sc7180-trogdor-kingoftown.dtsi"
+
+/ {
+       model = "Google Kingoftown (rev0)";
+       compatible = "google,kingoftown-rev0", "qcom,sc7180";
+};
+
+/*
+ * In rev1+, the enable pin of pp3300_fp_tp will be tied to pp1800_l10a
+ * power rail instead, since kingoftown does not have FP.
+ */
+&pp3300_fp_tp {
+       gpio = <&tlmm 74 GPIO_ACTIVE_HIGH>;
+       enable-active-high;
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&en_fp_rails>;
+};
+
+&tlmm {
+       en_fp_rails: en-fp-rails {
+               pinmux {
+                       pins = "gpio74";
+                       function = "gpio";
+               };
+
+               pinconf {
+                       pins = "gpio74";
+                       drive-strength = <2>;
+                       bias-disable;
+               };
+       };
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-kingoftown-r1.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-kingoftown-r1.dts
new file mode 100644 (file)
index 0000000..e0752ba
--- /dev/null
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Kingoftown board device tree source
+ *
+ * Copyright 2021 Google LLC.
+ */
+
+/dts-v1/;
+
+#include "sc7180-trogdor.dtsi"
+#include "sc7180-trogdor-parade-ps8640.dtsi"
+#include "sc7180-trogdor-kingoftown.dtsi"
+
+/ {
+       model = "Google Kingoftown (rev1+)";
+       compatible = "google,kingoftown", "qcom,sc7180";
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-kingoftown.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-kingoftown.dtsi
new file mode 100644 (file)
index 0000000..74f0e07
--- /dev/null
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Kingoftown board device tree source
+ *
+ * Copyright 2021 Google LLC.
+ */
+
+/* This file must be included after sc7180-trogdor.dtsi */
+#include <arm/cros-ec-keyboard.dtsi>
+#include "sc7180-trogdor-lte-sku.dtsi"
+
+&alc5682 {
+       compatible = "realtek,rt5682s";
+       realtek,dmic1-clk-pin = <2>;
+       realtek,dmic-clk-rate-hz = <2048000>;
+};
+
+&ap_tp_i2c {
+       status = "okay";
+};
+
+ap_ts_pen_1v8: &i2c4 {
+       status = "okay";
+       clock-frequency = <400000>;
+
+       ap_ts: touchscreen@10 {
+               compatible = "elan,ekth3500";
+               reg = <0x10>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&ts_int_l>, <&ts_reset_l>;
+
+               interrupt-parent = <&tlmm>;
+               interrupts = <9 IRQ_TYPE_LEVEL_LOW>;
+
+               vcc33-supply = <&pp3300_ts>;
+
+               reset-gpios = <&tlmm 8 GPIO_ACTIVE_LOW>;
+       };
+};
+
+&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
+       >;
+};
+
+&panel {
+       compatible = "edp-panel";
+};
+
+&pp3300_dx_edp {
+       gpio = <&tlmm 67 GPIO_ACTIVE_HIGH>;
+};
+
+&sound {
+       compatible = "google,sc7180-trogdor";
+       model = "sc7180-rt5682s-max98357a-1mic";
+};
+
+&wifi {
+       qcom,ath10k-calibration-variant = "GO_KINGOFTOWN";
+};
+
+/* PINCTRL - modifications to sc7180-trogdor.dtsi */
+
+&en_pp3300_dx_edp {
+       pinmux {
+               pins = "gpio67";
+       };
+
+       pinconf {
+               pins = "gpio67";
+       };
+};
+
+/* PINCTRL - board-specific pinctrl */
+
+&tlmm {
+       gpio-line-names = "TP_INT_L",           /* 0 */
+                         "AP_RAM_ID0",
+                         "AP_SKU_ID2",
+                         "AP_RAM_ID1",
+                         "",
+                         "AP_RAM_ID2",
+                         "AP_TP_I2C_SDA",
+                         "AP_TP_I2C_SCL",
+                         "TS_RESET_L",
+                         "TS_INT_L",
+                         "",                   /* 10 */
+                         "EDP_BRIJ_IRQ",
+                         "AP_EDP_BKLTEN",
+                         "",
+                         "",
+                         "EDP_BRIJ_I2C_SDA",
+                         "EDP_BRIJ_I2C_SCL",
+                         "HUB_RST_L",
+                         "",
+                         "",
+                         "",                   /* 20 */
+                         "",
+                         "",
+                         "AMP_EN",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "HP_IRQ",
+                         "",
+                         "",                   /* 30 */
+                         "AP_BRD_ID2",
+                         "BRIJ_SUSPEND",
+                         "AP_BRD_ID0",
+                         "AP_H1_SPI_MISO",
+                         "AP_H1_SPI_MOSI",
+                         "AP_H1_SPI_CLK",
+                         "AP_H1_SPI_CS_L",
+                         "BT_UART_CTS",
+                         "BT_UART_RTS",
+                         "BT_UART_TXD",        /* 40 */
+                         "BT_UART_RXD",
+                         "H1_AP_INT_ODL",
+                         "",
+                         "UART_AP_TX_DBG_RX",
+                         "UART_DBG_TX_AP_RX",
+                         "HP_I2C_SDA",
+                         "HP_I2C_SCL",
+                         "FORCED_USB_BOOT",
+                         "AMP_BCLK",
+                         "AMP_LRCLK",          /* 50 */
+                         "AMP_DIN",
+                         "",
+                         "HP_BCLK",
+                         "HP_LRCLK",
+                         "HP_DOUT",
+                         "HP_DIN",
+                         "HP_MCLK",
+                         "AP_SKU_ID0",
+                         "AP_EC_SPI_MISO",
+                         "AP_EC_SPI_MOSI",     /* 60 */
+                         "AP_EC_SPI_CLK",
+                         "AP_EC_SPI_CS_L",
+                         "AP_SPI_CLK",
+                         "AP_SPI_MOSI",
+                         "AP_SPI_MISO",
+                         /*
+                          * AP_FLASH_WP_L is crossystem ABI. Schematics
+                          * call it BIOS_FLASH_WP_L.
+                          */
+                         "AP_FLASH_WP_L",
+                         "EN_PP3300_DX_EDP",
+                         "AP_SPI_CS0_L",
+                         "",
+                         "",                   /* 70 */
+                         "",
+                         "",
+                         "",
+                         "EN_FP_RAILS",
+                         "UIM2_DATA",
+                         "UIM2_CLK",
+                         "UIM2_RST",
+                         "UIM2_PRESENT_L",
+                         "UIM1_DATA",
+                         "UIM1_CLK",           /* 80 */
+                         "UIM1_RST",
+                         "",
+                         "CODEC_PWR_EN",
+                         "HUB_EN",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "AP_SKU_ID1",         /* 90 */
+                         "AP_RST_REQ",
+                         "",
+                         "AP_BRD_ID1",
+                         "AP_EC_INT_L",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",                   /* 100 */
+                         "",
+                         "",
+                         "",
+                         "EDP_BRIJ_EN",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",                   /* 110 */
+                         "",
+                         "",
+                         "",
+                         "",
+                         "AP_TS_PEN_I2C_SDA",
+                         "AP_TS_PEN_I2C_SCL",
+                         "DP_HOT_PLUG_DET",
+                         "EC_IN_RW_ODL";
+};
index fe2369c..2cf7d52 100644 (file)
@@ -5,7 +5,8 @@
  * Copyright 2020 Google LLC.
  */
 
-#include "sc7180-trogdor.dtsi"
+/* This file must be included after sc7180-trogdor.dtsi */
+#include <arm/cros-ec-keyboard.dtsi>
 
 &ap_sar_sensor {
        semtech,cs0-ground;
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland-rev0-auo.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland-rev0-auo.dts
new file mode 100644 (file)
index 0000000..2767817
--- /dev/null
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Mrbland board device tree source
+ *
+ * Copyright 2021 Google LLC.
+ *
+ * SKU: 0x0 => 0
+ *  - bits 7..4: Panel ID: 0x0 (AUO)
+ */
+
+/dts-v1/;
+
+#include "sc7180-trogdor-mrbland-rev0.dtsi"
+
+/ {
+       model = "Google Mrbland rev0 AUO panel board";
+       compatible = "google,mrbland-rev0-sku0", "qcom,sc7180";
+};
+
+&panel {
+       compatible = "auo,b101uan08.3";
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland-rev0-boe.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland-rev0-boe.dts
new file mode 100644 (file)
index 0000000..7114855
--- /dev/null
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Mrbland board device tree source
+ *
+ * Copyright 2021 Google LLC.
+ *
+ * SKU: 0x10 => 16
+ *  - bits 7..4: Panel ID: 0x1 (BOE)
+ */
+
+/dts-v1/;
+
+#include "sc7180-trogdor-mrbland-rev0.dtsi"
+
+/ {
+       model = "Google Mrbland rev0 BOE panel board";
+       compatible = "google,mrbland-rev0-sku16", "qcom,sc7180";
+};
+
+&panel {
+       compatible = "boe,tv101wum-n53";
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland-rev0.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland-rev0.dtsi
new file mode 100644 (file)
index 0000000..7bc8402
--- /dev/null
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Mrbland board device tree source
+ *
+ * Copyright 2021 Google LLC.
+ *
+ */
+
+/dts-v1/;
+
+#include "sc7180-trogdor-mrbland.dtsi"
+
+&avdd_lcd {
+       gpio = <&tlmm 80 GPIO_ACTIVE_HIGH>;
+};
+
+&panel {
+       enable-gpios = <&tlmm 76 GPIO_ACTIVE_HIGH>;
+};
+
+&v1p8_mipi {
+       gpio = <&tlmm 81 GPIO_ACTIVE_HIGH>;
+};
+
+/* PINCTRL - modifications to sc7180-trogdor-mrbland.dtsi */
+&avdd_lcd_en {
+       pinmux {
+               pins = "gpio80";
+       };
+
+       pinconf {
+               pins = "gpio80";
+       };
+};
+
+&mipi_1800_en {
+       pinmux {
+               pins = "gpio81";
+       };
+
+       pinconf {
+               pins = "gpio81";
+       };
+};
+&vdd_reset_1800 {
+       pinmux {
+               pins = "gpio76";
+       };
+
+       pinconf {
+               pins = "gpio76";
+       };
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland-rev1-auo.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland-rev1-auo.dts
new file mode 100644 (file)
index 0000000..275313e
--- /dev/null
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Mrbland board device tree source
+ *
+ * Copyright 2021 Google LLC.
+ *
+ * SKU: 0x600 => 1536
+ *  - bits 11..8: Panel ID: 0x6 (AUO)
+ */
+
+/dts-v1/;
+
+#include "sc7180-trogdor-mrbland.dtsi"
+
+/ {
+       model = "Google Mrbland rev1+ AUO panel board";
+       compatible = "google,mrbland-sku1536", "qcom,sc7180";
+};
+
+&panel {
+       compatible = "auo,b101uan08.3";
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland-rev1-boe.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland-rev1-boe.dts
new file mode 100644 (file)
index 0000000..87c6b6c
--- /dev/null
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Mrbland board device tree source
+ *
+ * Copyright 2021 Google LLC.
+ *
+ * SKU: 0x300 => 768
+ *  - bits 11..8: Panel ID: 0x3 (BOE)
+ */
+
+/dts-v1/;
+
+#include "sc7180-trogdor-mrbland.dtsi"
+
+/ {
+       model = "Google Mrbland (rev1 - 2) BOE panel board";
+       /* Uses ID 768 on rev1 and 1024 on rev2+ */
+       compatible = "google,mrbland-sku1024", "google,mrbland-sku768",
+               "qcom,sc7180";
+};
+
+&panel {
+       compatible = "boe,tv101wum-n53";
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-mrbland.dtsi
new file mode 100644 (file)
index 0000000..97cba7f
--- /dev/null
@@ -0,0 +1,350 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Mrbland board device tree source
+ *
+ * Copyright 2021 Google LLC.
+ */
+
+/dts-v1/;
+
+#include "sc7180-trogdor.dtsi"
+
+/* This board only has 1 USB Type-C port. */
+/delete-node/ &usb_c1;
+
+/ {
+       avdd_lcd: avdd-lcd {
+               compatible = "regulator-fixed";
+               regulator-name = "avdd_lcd";
+
+               gpio = <&tlmm 88 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               pinctrl-names = "default";
+               pinctrl-0 = <&avdd_lcd_en>;
+
+               vin-supply = <&pp5000_a>;
+       };
+
+       avee_lcd: avee-lcd {
+               compatible = "regulator-fixed";
+               regulator-name = "avee_lcd";
+
+               gpio = <&tlmm 21 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               pinctrl-names = "default";
+               pinctrl-0 = <&avee_lcd_en>;
+
+               vin-supply = <&pp5000_a>;
+       };
+
+       v1p8_mipi: v1p8-mipi {
+               compatible = "regulator-fixed";
+               regulator-name = "v1p8_mipi";
+
+               gpio = <&tlmm 86 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               pinctrl-names = "default";
+               pinctrl-0 = <&mipi_1800_en>;
+
+               vin-supply = <&pp3300_a>;
+       };
+};
+
+&backlight {
+       pwms = <&cros_ec_pwm 0>;
+};
+
+&camcc {
+       status = "okay";
+};
+
+&cros_ec {
+       keyboard-controller {
+               compatible = "google,cros-ec-keyb-switches";
+       };
+};
+
+&dsi0 {
+
+       panel: panel@0 {
+               /* Compatible will be filled in per-board */
+               reg = <0>;
+               enable-gpios = <&tlmm 87 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&vdd_reset_1800>;
+               avdd-supply = <&avdd_lcd>;
+               avee-supply = <&avee_lcd>;
+               pp1800-supply = <&v1p8_mipi>;
+               pp3300-supply = <&pp3300_dx_edp>;
+               backlight = <&backlight>;
+               rotation = <270>;
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       port@0 {
+                               reg = <0>;
+                               panel_in: endpoint {
+                                       remote-endpoint = <&dsi0_out>;
+                               };
+                       };
+               };
+       };
+
+       ports {
+               port@1 {
+                       endpoint {
+                               remote-endpoint = <&panel_in>;
+                               data-lanes = <0 1 2 3>;
+                       };
+               };
+       };
+};
+
+&gpio_keys {
+       status = "okay";
+};
+
+&i2c4 {
+       status = "okay";
+       clock-frequency = <400000>;
+
+       ap_ts: touchscreen@5d {
+               compatible = "goodix,gt7375p";
+               reg = <0x5d>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&ts_int_l>, <&ts_reset_l>;
+
+               interrupt-parent = <&tlmm>;
+               interrupts = <9 IRQ_TYPE_LEVEL_LOW>;
+
+               reset-gpios = <&tlmm 8 GPIO_ACTIVE_LOW>;
+
+               vdd-supply = <&pp3300_ts>;
+       };
+};
+
+&pp1800_uf_cam {
+       status = "okay";
+};
+
+&pp1800_wf_cam {
+       status = "okay";
+};
+
+&pp2800_uf_cam {
+       status = "okay";
+};
+
+&pp2800_wf_cam {
+       status = "okay";
+};
+
+&wifi {
+       qcom,ath10k-calibration-variant = "GO_MRBLAND";
+};
+
+/*
+ * No eDP on this board but it's logically the same signal so just give it
+ * a new name and assign the proper GPIO.
+ */
+pp3300_disp_on: &pp3300_dx_edp {
+       gpio = <&tlmm 85 GPIO_ACTIVE_HIGH>;
+};
+
+/* PINCTRL - modifications to sc7180-trogdor.dtsi */
+
+/*
+ * No eDP on this board but it's logically the same signal so just give it
+ * a new name and assign the proper GPIO.
+ */
+
+tp_en: &en_pp3300_dx_edp {
+       pinmux {
+               pins = "gpio85";
+       };
+
+       pinconf {
+               pins = "gpio85";
+       };
+};
+
+/* PINCTRL - board-specific pinctrl */
+
+&tlmm {
+       gpio-line-names = "HUB_RST_L",
+                         "AP_RAM_ID0",
+                         "AP_SKU_ID2",
+                         "AP_RAM_ID1",
+                         "",
+                         "AP_RAM_ID2",
+                         "UF_CAM_EN",
+                         "WF_CAM_EN",
+                         "TS_RESET_L",
+                         "TS_INT_L",
+                         "",
+                         "",
+                         "AP_EDP_BKLTEN",
+                         "UF_CAM_MCLK",
+                         "WF_CAM_CLK",
+                         "",
+                         "",
+                         "UF_CAM_SDA",
+                         "UF_CAM_SCL",
+                         "WF_CAM_SDA",
+                         "WF_CAM_SCL",
+                         "AVEE_LCD_EN",
+                         "",
+                         "AMP_EN",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "HP_IRQ",
+                         "WF_CAM_RST_L",
+                         "UF_CAM_RST_L",
+                         "AP_BRD_ID2",
+                         "",
+                         "AP_BRD_ID0",
+                         "AP_H1_SPI_MISO",
+                         "AP_H1_SPI_MOSI",
+                         "AP_H1_SPI_CLK",
+                         "AP_H1_SPI_CS_L",
+                         "BT_UART_CTS",
+                         "BT_UART_RTS",
+                         "BT_UART_TXD",
+                         "BT_UART_RXD",
+                         "H1_AP_INT_ODL",
+                         "",
+                         "UART_AP_TX_DBG_RX",
+                         "UART_DBG_TX_AP_RX",
+                         "HP_I2C_SDA",
+                         "HP_I2C_SCL",
+                         "FORCED_USB_BOOT",
+                         "AMP_BCLK",
+                         "AMP_LRCLK",
+                         "AMP_DIN",
+                         "PEN_DET_ODL",
+                         "HP_BCLK",
+                         "HP_LRCLK",
+                         "HP_DOUT",
+                         "HP_DIN",
+                         "HP_MCLK",
+                         "AP_SKU_ID0",
+                         "AP_EC_SPI_MISO",
+                         "AP_EC_SPI_MOSI",
+                         "AP_EC_SPI_CLK",
+                         "AP_EC_SPI_CS_L",
+                         "AP_SPI_CLK",
+                         "AP_SPI_MOSI",
+                         "AP_SPI_MISO",
+                         /*
+                          * AP_FLASH_WP_L is crossystem ABI. Schematics
+                          * call it BIOS_FLASH_WP_L.
+                          */
+                         "AP_FLASH_WP_L",
+                         "",
+                         "AP_SPI_CS0_L",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "WLAN_SW_CTRL",
+                         "",
+                         "REPORT_E",
+                         "",
+                         "ID0",
+                         "",
+                         "ID1",
+                         "",
+                         "",
+                         "",
+                         "CODEC_PWR_EN",
+                         "HUB_EN",
+                         "TP_EN",
+                         "MIPI_1.8V_EN",
+                         "VDD_RESET_1.8V",
+                         "AVDD_LCD_EN",
+                         "",
+                         "AP_SKU_ID1",
+                         "AP_RST_REQ",
+                         "",
+                         "AP_BRD_ID1",
+                         "AP_EC_INT_L",
+                         "SDM_GRFC_3",
+                         "",
+                         "",
+                         "BOOT_CONFIG_4",
+                         "BOOT_CONFIG_2",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "BOOT_CONFIG_3",
+                         "WCI2_LTE_COEX_TXD",
+                         "WCI2_LTE_COEX_RXD",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "FORCED_USB_BOOT_POL",
+                         "AP_TS_PEN_I2C_SDA",
+                         "AP_TS_PEN_I2C_SCL",
+                         "DP_HOT_PLUG_DET",
+                         "EC_IN_RW_ODL";
+
+       avdd_lcd_en: avdd-lcd-en {
+               pinmux {
+                       pins = "gpio88";
+                       function = "gpio";
+               };
+
+               pinconf {
+                       pins = "gpio88";
+                       drive-strength = <2>;
+                       bias-disable;
+               };
+       };
+
+       avee_lcd_en: avee-lcd-en {
+               pinmux {
+                       pins = "gpio21";
+                       function = "gpio";
+               };
+
+               pinconf {
+                       pins = "gpio21";
+                       drive-strength = <2>;
+                       bias-disable;
+               };
+       };
+
+       mipi_1800_en: mipi-1800-en {
+               pinmux {
+                       pins = "gpio86";
+                       function = "gpio";
+               };
+
+               pinconf {
+                       pins = "gpio86";
+                       drive-strength = <2>;
+                       bias-disable;
+               };
+       };
+
+       vdd_reset_1800: vdd-reset-1800 {
+               pinmux {
+                       pins = "gpio87";
+                       function = "gpio";
+               };
+
+               pinconf {
+                       pins = "gpio87";
+                       drive-strength = <2>;
+                       bias-disable;
+               };
+       };
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel-lte-parade.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel-lte-parade.dts
new file mode 100644 (file)
index 0000000..764c451
--- /dev/null
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Pazquel board device tree source
+ *
+ * Copyright 2021 Google LLC.
+ */
+
+/dts-v1/;
+
+#include "sc7180-trogdor.dtsi"
+#include "sc7180-trogdor-parade-ps8640.dtsi"
+#include "sc7180-trogdor-pazquel.dtsi"
+#include "sc7180-trogdor-lte-sku.dtsi"
+
+/ {
+       model = "Google Pazquel (Parade,LTE)";
+       compatible = "google,pazquel-sku4", "qcom,sc7180";
+};
+
+&ap_sar_sensor_i2c {
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel-lte-ti.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel-lte-ti.dts
new file mode 100644 (file)
index 0000000..9145b74
--- /dev/null
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Pazquel board device tree source
+ *
+ * Copyright 2021 Google LLC.
+ */
+
+/dts-v1/;
+
+#include "sc7180-trogdor.dtsi"
+#include "sc7180-trogdor-ti-sn65dsi86.dtsi"
+#include "sc7180-trogdor-pazquel.dtsi"
+#include "sc7180-trogdor-lte-sku.dtsi"
+
+/ {
+       model = "Google Pazquel (TI,LTE)";
+       compatible = "google,pazquel-sku0", "google,pazquel-sku2", "qcom,sc7180";
+};
+
+&ap_sar_sensor_i2c {
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel-parade.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel-parade.dts
new file mode 100644 (file)
index 0000000..9a0e663
--- /dev/null
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Pazquel board device tree source
+ *
+ * Copyright 2022 Google LLC.
+ */
+
+/dts-v1/;
+
+#include "sc7180-trogdor.dtsi"
+#include "sc7180-trogdor-parade-ps8640.dtsi"
+#include "sc7180-trogdor-pazquel.dtsi"
+
+/ {
+       model = "Google Pazquel (Parade)";
+       compatible = "google,pazquel-sku5", "qcom,sc7180";
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel-ti.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel-ti.dts
new file mode 100644 (file)
index 0000000..47c5970
--- /dev/null
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Pazquel board device tree source
+ *
+ * Copyright 2021 Google LLC.
+ */
+
+/dts-v1/;
+
+#include "sc7180-trogdor.dtsi"
+#include "sc7180-trogdor-ti-sn65dsi86.dtsi"
+#include "sc7180-trogdor-pazquel.dtsi"
+
+/ {
+       model = "Google Pazquel (TI)";
+       compatible = "google,pazquel-sku1", "qcom,sc7180";
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pazquel.dtsi
new file mode 100644 (file)
index 0000000..56d7877
--- /dev/null
@@ -0,0 +1,222 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Pazquel board device tree source
+ *
+ * Copyright 2021 Google LLC.
+ */
+
+/* This file must be included after sc7180-trogdor.dtsi */
+#include <arm/cros-ec-keyboard.dtsi>
+
+&ap_sar_sensor {
+       compatible = "semtech,sx9324";
+       semtech,ph0-pin = <1 3 3>;
+       semtech,ph1-pin = <3 1 3>;
+       semtech,ph2-pin = <1 3 3>;
+       semtech,ph3-pin = <0 0 0>;
+       semtech,ph01-resolution = <1024>;
+       semtech,ph23-resolution = <1024>;
+       semtech,startup-sensor = <1>;
+       semtech,ph01-proxraw-strength = <3>;
+       semtech,ph23-proxraw-strength = <1>;
+       semtech,avg-pos-strength = <128>;
+       semtech,input-analog-gain = <0>;
+       semtech,cs-idle-sleep = "gnd";
+
+       /delete-property/ svdd-supply;
+       vdd-supply = <&pp1800_prox>;
+};
+
+/delete-node/&trackpad;
+&ap_tp_i2c {
+       status = "okay";
+       trackpad: trackpad@15 {
+               compatible = "hid-over-i2c";
+               reg = <0x15>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&tp_int_odl>;
+
+               interrupt-parent = <&tlmm>;
+               interrupts = <0 IRQ_TYPE_EDGE_FALLING>;
+
+               vcc-supply = <&pp3300_fp_tp>;
+               post-power-on-delay-ms = <100>;
+               hid-descr-addr = <0x0001>;
+
+               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_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
+       >;
+};
+
+&panel {
+       compatible = "edp-panel";
+};
+
+&pp3300_dx_edp {
+       gpio = <&tlmm 67 GPIO_ACTIVE_HIGH>;
+};
+
+&en_pp3300_dx_edp {
+       pinmux {
+               pins = "gpio67";
+       };
+
+       pinconf {
+               pins = "gpio67";
+       };
+};
+
+/* PINCTRL - board-specific pinctrl */
+
+&tlmm {
+       gpio-line-names = "TP_INT_ODL",
+                         "AP_RAM_ID0",
+                         "AP_SKU_ID2",
+                         "AP_RAM_ID1",
+                         "",
+                         "AP_RAM_ID2",
+                         "AP_TP_I2C_SDA",
+                         "AP_TP_I2C_SCL",
+                         "TS_RESET_L",
+                         "TS_INT_L",
+                         "",
+                         "EDP_BRIJ_IRQ",
+                         "AP_EDP_BKLTEN",
+                         "",
+                         "",
+                         "EDP_BRIJ_I2C_SDA",
+                         "EDP_BRIJ_I2C_SCL",
+                         "HUB_RST_L",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "AMP_EN",
+                         "P_SENSOR_INT_L",
+                         "AP_SAR_SENSOR_SDA",
+                         "AP_SAR_SENSOR_SCL",
+                         "",
+                         "HP_IRQ",
+                         "",
+                         "",
+                         "AP_BRD_ID2",
+                         "BRIJ_SUSPEND",
+                         "AP_BRD_ID0",
+                         "AP_H1_SPI_MISO",
+                         "AP_H1_SPI_MOSI",
+                         "AP_H1_SPI_CLK",
+                         "AP_H1_SPI_CS_L",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "H1_AP_INT_ODL",
+                         "",
+                         "UART_AP_TX_DBG_RX",
+                         "UART_DBG_TX_AP_RX",
+                         "HP_I2C_SDA",
+                         "HP_I2C_SCL",
+                         "FORCED_USB_BOOT",
+                         "AMP_BCLK",
+                         "AMP_LRCLK",
+                         "AMP_DIN",
+                         "",
+                         "HP_BCLK",
+                         "HP_LRCLK",
+                         "HP_DOUT",
+                         "HP_DIN",
+                         "HP_MCLK",
+                         "AP_SKU_ID0",
+                         "AP_EC_SPI_MISO",
+                         "AP_EC_SPI_MOSI",
+                         "AP_EC_SPI_CLK",
+                         "AP_EC_SPI_CS_L",
+                         "AP_SPI_CLK",
+                         "AP_SPI_MOSI",
+                         "AP_SPI_MISO",
+                         /*
+                          * AP_FLASH_WP_L is crossystem ABI. Schematics
+                          * call it BIOS_FLASH_WP_L.
+                          */
+                         "AP_FLASH_WP_L",
+                         "EN_PP3300_DX_EDP",
+                         "AP_SPI_CS0_L",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "UIM2_DATA",
+                         "UIM2_CLK",
+                         "UIM2_RST",
+                         "UIM2_PRESENT",
+                         "UIM1_DATA",
+                         "UIM1_CLK",
+                         "UIM1_RST",
+                         "",
+                         "CODEC_PWR_EN",
+                         "HUB_EN",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "AP_SKU_ID1",
+                         "AP_RST_REQ",
+                         "",
+                         "AP_BRD_ID1",
+                         "AP_EC_INT_L",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "EDP_BRIJ_EN",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "AP_TS_PEN_I2C_SDA",
+                         "AP_TS_PEN_I2C_SCL",
+                         "DP_HOT_PLUG_DET",
+                         "EC_IN_RW_ODL";
+};
index 3df4920..a7582fb 100644 (file)
@@ -6,6 +6,8 @@
  */
 
 #include "sc7180-trogdor.dtsi"
+/* Must come after sc7180-trogdor.dtsi to modify cros_ec */
+#include <arm/cros-ec-keyboard.dtsi>
 #include "sc7180-trogdor-ti-sn65dsi86.dtsi"
 
 / {
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-quackingstick-r0-lte.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-quackingstick-r0-lte.dts
new file mode 100644 (file)
index 0000000..35e8945
--- /dev/null
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Quackingstick board device tree source
+ *
+ * Copyright 2021 Google LLC.
+ *
+ * SKU: 0x600 => 1536
+ *  - bits 11..8: Panel ID: 0x6 (AUO)
+ */
+
+#include "sc7180-trogdor-quackingstick-r0.dts"
+#include "sc7180-trogdor-lte-sku.dtsi"
+
+/ {
+       model = "Google Quackingstick (rev0+) with LTE";
+       compatible = "google,quackingstick-sku1536", "qcom,sc7180";
+};
+
+&ap_sar_sensor {
+       compatible = "semtech,sx9324";
+       semtech,ph0-pin = <3 1 3>;
+       semtech,ph1-pin = <2 1 2>;
+       semtech,ph2-pin = <3 3 1>;
+       semtech,ph3-pin = <1 3 3>;
+       semtech,ph01-resolution = <1024>;
+       semtech,ph23-resolution = <1024>;
+       semtech,startup-sensor = <1>;
+       semtech,ph01-proxraw-strength = <3>;
+       semtech,ph23-proxraw-strength = <3>;
+       semtech,avg-pos-strength = <256>;
+
+       /delete-property/ svdd-supply;
+       vdd-supply = <&pp1800_prox>;
+};
+
+&ap_sar_sensor_i2c {
+       status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-quackingstick-r0.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-quackingstick-r0.dts
new file mode 100644 (file)
index 0000000..5c81e44
--- /dev/null
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Quackingstick board device tree source
+ *
+ * Copyright 2021 Google LLC.
+ *
+ * SKU: 0x601 => 1537
+ *  - bits 11..8: Panel ID: 0x6 (AUO)
+ */
+
+#include "sc7180-trogdor-quackingstick.dtsi"
+
+/ {
+       model = "Google Quackingstick (rev0+)";
+       compatible = "google,quackingstick-sku1537", "qcom,sc7180";
+};
+
+&dsi_phy {
+       qcom,phy-rescode-offset-top = /bits/ 8 <(-13) (-13) (-13) (-13) (-13)>;
+       qcom,phy-rescode-offset-bot = /bits/ 8 <(-13) (-13) (-13) (-13) (-13)>;
+       qcom,phy-drive-ldo-level = <375>;
+};
+
+&panel {
+       compatible = "auo,b101uan08.3";
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-quackingstick.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-quackingstick.dtsi
new file mode 100644 (file)
index 0000000..695b04f
--- /dev/null
@@ -0,0 +1,324 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Quackingstick board device tree source
+ *
+ * Copyright 2021 Google LLC.
+ */
+
+/dts-v1/;
+
+#include "sc7180-trogdor.dtsi"
+
+/* This board only has 1 USB Type-C port. */
+/delete-node/ &usb_c1;
+
+/ {
+       ppvar_lcd: ppvar-lcd {
+               compatible = "regulator-fixed";
+               regulator-name = "ppvar_lcd";
+
+               gpio = <&tlmm 88 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               pinctrl-names = "default";
+               pinctrl-0 = <&ppvar_lcd_en>;
+
+               vin-supply = <&pp5000_a>;
+       };
+
+       v1p8_disp: v1p8-disp {
+               compatible = "regulator-fixed";
+               regulator-name = "v1p8_disp";
+
+               gpio = <&tlmm 86 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pp1800_disp_on>;
+
+               vin-supply = <&pp3300_a>;
+       };
+};
+
+&backlight {
+       pwms = <&cros_ec_pwm 0>;
+};
+
+&camcc {
+       status = "okay";
+};
+
+&cros_ec {
+       keyboard-controller {
+               compatible = "google,cros-ec-keyb-switches";
+       };
+};
+
+&dsi0 {
+       panel: panel@0 {
+               /* Compatible will be filled in per-board */
+               reg = <0>;
+               enable-gpios = <&tlmm 87 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&lcd_rst>;
+               avdd-supply = <&ppvar_lcd>;
+               pp1800-supply = <&v1p8_disp>;
+               pp3300-supply = <&pp3300_dx_edp>;
+               backlight = <&backlight>;
+               rotation = <270>;
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       port@0 {
+                               reg = <0>;
+                               panel_in: endpoint {
+                                       remote-endpoint = <&dsi0_out>;
+                               };
+                       };
+               };
+       };
+
+       ports {
+               port@1 {
+                       endpoint {
+                               remote-endpoint = <&panel_in>;
+                               data-lanes = <0 1 2 3>;
+                       };
+               };
+       };
+};
+
+&gpio_keys {
+       status = "okay";
+};
+
+&i2c4 {
+       status = "okay";
+       clock-frequency = <400000>;
+
+       ap_ts: touchscreen@10 {
+               compatible = "hid-over-i2c";
+               reg = <0x10>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&ts_int_l>, <&ts_reset_l>;
+
+               interrupt-parent = <&tlmm>;
+               interrupts = <9 IRQ_TYPE_LEVEL_LOW>;
+
+               post-power-on-delay-ms = <20>;
+               hid-descr-addr = <0x0001>;
+
+               vdd-supply = <&pp3300_ts>;
+       };
+};
+
+&sdhc_2 {
+       status = "okay";
+};
+
+&pp1800_uf_cam {
+       status = "okay";
+};
+
+&pp1800_wf_cam {
+       status = "okay";
+};
+
+&pp2800_uf_cam {
+       status = "okay";
+};
+
+&pp2800_wf_cam {
+       status = "okay";
+};
+
+/*
+ * No eDP on this board but it's logically the same signal so just give it
+ * a new name and assign the proper GPIO.
+ */
+pp3300_disp_on: &pp3300_dx_edp {
+       gpio = <&tlmm 67 GPIO_ACTIVE_HIGH>;
+};
+
+/* PINCTRL - modifications to sc7180-trogdor.dtsi */
+
+/*
+ * No eDP on this board but it's logically the same signal so just give it
+ * a new name and assign the proper GPIO.
+ */
+
+tp_en: &en_pp3300_dx_edp {
+       pinmux {
+               pins = "gpio67";
+       };
+
+       pinconf {
+               pins = "gpio67";
+       };
+};
+
+/* PINCTRL - board-specific pinctrl */
+
+&tlmm {
+       gpio-line-names = "HUB_RST_L",
+                         "AP_RAM_ID0",
+                         "AP_SKU_ID2",
+                         "AP_RAM_ID1",
+                         "",
+                         "AP_RAM_ID2",
+                         "UF_CAM_EN",
+                         "WF_CAM_EN",
+                         "TS_RESET_L",
+                         "TS_INT_L",
+                         "",
+                         "",
+                         "AP_EDP_BKLTEN",
+                         "UF_CAM_MCLK",
+                         "WF_CAM_CLK",
+                         "EDP_BRIJ_I2C_SDA",
+                         "EDP_BRIJ_I2C_SCL",
+                         "UF_CAM_SDA",
+                         "UF_CAM_SCL",
+                         "WF_CAM_SDA",
+                         "WF_CAM_SCL",
+                         "",
+                         "",
+                         "AMP_EN",
+                         "P_SENSOR_INT_L",
+                         "AP_SAR_SENSOR_SDA",
+                         "AP_SAR_SENSOR_SCL",
+                         "",
+                         "HP_IRQ",
+                         "WF_CAM_RST_L",
+                         "UF_CAM_RST_L",
+                         "AP_BRD_ID2",
+                         "",
+                         "AP_BRD_ID0",
+                         "AP_H1_SPI_MISO",
+                         "AP_H1_SPI_MOSI",
+                         "AP_H1_SPI_CLK",
+                         "AP_H1_SPI_CS_L",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "H1_AP_INT_ODL",
+                         "",
+                         "UART_AP_TX_DBG_RX",
+                         "UART_DBG_TX_AP_RX",
+                         "HP_I2C_SDA",
+                         "HP_I2C_SCL",
+                         "FORCED_USB_BOOT",
+                         "",
+                         "",
+                         "AMP_DIN",
+                         "PEN_DET_ODL",
+                         "HP_BCLK",
+                         "HP_LRCLK",
+                         "HP_DOUT",
+                         "HP_DIN",
+                         "HP_MCLK",
+                         "AP_SKU_ID0",
+                         "AP_EC_SPI_MISO",
+                         "AP_EC_SPI_MOSI",
+                         "AP_EC_SPI_CLK",
+                         "AP_EC_SPI_CS_L",
+                         "AP_SPI_CLK",
+                         "AP_SPI_MOSI",
+                         "AP_SPI_MISO",
+                         /*
+                          * AP_FLASH_WP_L is crossystem ABI. Schematics
+                          * call it BIOS_FLASH_WP_L.
+                          */
+                         "AP_FLASH_WP_L",
+                         "EN_PP3300_DX_EDP",
+                         "AP_SPI_CS0_L",
+                         "SD_CD_ODL",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "UIM2_DATA",
+                         "UIM2_CLK",
+                         "UIM2_RST",
+                         "UIM2_PRESENT_L",
+                         "UIM1_DATA",
+                         "UIM1_CLK",
+                         "UIM1_RST",
+                         "",
+                         "CODEC_PWR_EN",
+                         "HUB_EN",
+                         "",
+                         "PP1800_DISP_ON",
+                         "LCD_RST",
+                         "PPVAR_LCD_EN",
+                         "",
+                         "AP_SKU_ID1",
+                         "AP_RST_REQ",
+                         "",
+                         "AP_BRD_ID1",
+                         "AP_EC_INT_L",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "AP_TS_I2C_SDA",
+                         "AP_TS_I2C_SCL",
+                         "DP_HOT_PLUG_DET",
+                         "EC_IN_RW_ODL";
+
+       lcd_rst: lcd-rst {
+               pinmux {
+                       pins = "gpio87";
+                       function = "gpio";
+               };
+
+               pinconf {
+                       pins = "gpio87";
+                       drive-strength = <2>;
+                       bias-disable;
+               };
+       };
+
+       ppvar_lcd_en: ppvar-lcd-en {
+               pinmux {
+                       pins = "gpio88";
+                       function = "gpio";
+               };
+
+               pinconf {
+                       pins = "gpio88";
+                       drive-strength = <2>;
+                       bias-disable;
+               };
+       };
+
+       pp1800_disp_on: pp1800-disp-on {
+               pinmux {
+                       pins = "gpio86";
+                       function = "gpio";
+               };
+
+               pinconf {
+                       pins = "gpio86";
+                       drive-strength = <2>;
+                       bias-disable;
+               };
+       };
+};
index 352827e..59a23d0 100644 (file)
@@ -8,6 +8,8 @@
 /dts-v1/;
 
 #include "sc7180-trogdor.dtsi"
+/* Must come after sc7180-trogdor.dtsi to modify cros_ec */
+#include <arm/cros-ec-keyboard.dtsi>
 #include "sc7180-trogdor-ti-sn65dsi86.dtsi"
 
 / {
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev0-boe.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev0-boe.dts
new file mode 100644 (file)
index 0000000..d6ed7d0
--- /dev/null
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Wormdingler board device tree source
+ *
+ * Copyright 2021 Google LLC.
+ *
+ * SKU: 0x10 => 16
+ *  - bits 7..4: Panel ID: 0x1 (BOE)
+ */
+
+/dts-v1/;
+
+#include "sc7180-trogdor-wormdingler-rev0.dtsi"
+
+/ {
+       model = "Google Wormdingler rev0 BOE panel board";
+       compatible = "google,wormdingler-rev0-sku16", "qcom,sc7180";
+};
+
+&panel {
+       compatible = "boe,tv110c9m-ll3";
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev0-inx.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev0-inx.dts
new file mode 100644 (file)
index 0000000..c03525e
--- /dev/null
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Wormdingler board device tree source
+ *
+ * Copyright 2021 Google LLC.
+ *
+ * SKU: 0x0 => 0
+ *  - bits 7..4: Panel ID: 0x0 (INX)
+ */
+
+/dts-v1/;
+
+#include "sc7180-trogdor-wormdingler-rev0.dtsi"
+
+/ {
+       model = "Google Wormdingler rev0 INX panel board";
+       compatible = "google,wormdingler-rev0-sku0", "qcom,sc7180";
+};
+
+&panel {
+       compatible = "innolux,hj110iz-01a";
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev0.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev0.dtsi
new file mode 100644 (file)
index 0000000..db29e0c
--- /dev/null
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Wormdingler board device tree source
+ *
+ * Copyright 2021 Google LLC.
+ *
+ */
+
+/dts-v1/;
+
+#include "sc7180-trogdor-wormdingler.dtsi"
+
+&avdd_lcd {
+       gpio = <&tlmm 80 GPIO_ACTIVE_HIGH>;
+};
+
+&panel {
+       enable-gpios = <&tlmm 76 GPIO_ACTIVE_HIGH>;
+};
+
+&v1p8_mipi {
+       gpio = <&tlmm 81 GPIO_ACTIVE_HIGH>;
+};
+
+/* PINCTRL - modifications to sc7180-trogdor-wormdingler.dtsi */
+&avdd_lcd_en {
+       pinmux {
+               pins = "gpio80";
+       };
+
+       pinconf {
+               pins = "gpio80";
+       };
+};
+
+&mipi_1800_en {
+       pinmux {
+               pins = "gpio81";
+       };
+
+       pinconf {
+               pins = "gpio81";
+       };
+};
+&vdd_reset_1800 {
+       pinmux {
+               pins = "gpio76";
+       };
+
+       pinconf {
+               pins = "gpio76";
+       };
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev1-boe-rt5682s.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev1-boe-rt5682s.dts
new file mode 100644 (file)
index 0000000..aa60588
--- /dev/null
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Wormdingler board device tree source
+ *
+ * Copyright 2021 Google LLC.
+ *
+ * SKU: 0x401 => 1025
+ *  - bits 11..8: Panel ID: 0x4 (BOE)
+ */
+
+/dts-v1/;
+
+#include "sc7180-trogdor-wormdingler-rev1-boe.dts"
+
+/ {
+       model = "Google Wormdingler rev1+ (BOE, rt5682s)";
+       compatible = "google,wormdingler-sku1025", "qcom,sc7180";
+};
+
+&alc5682 {
+       compatible = "realtek,rt5682s";
+       realtek,dmic1-clk-pin = <2>;
+       realtek,dmic-clk-rate-hz = <2048000>;
+};
+
+&sound {
+       compatible = "google,sc7180-trogdor";
+       model = "sc7180-rt5682s-max98357a-1mic";
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev1-boe.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev1-boe.dts
new file mode 100644 (file)
index 0000000..c5b0658
--- /dev/null
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Wormdingler board device tree source
+ *
+ * Copyright 2021 Google LLC.
+ *
+ * SKU: 0x400 => 1024
+ *  - bits 11..8: Panel ID: 0x4 (BOE)
+ */
+
+/dts-v1/;
+
+#include "sc7180-trogdor-wormdingler.dtsi"
+
+/ {
+       model = "Google Wormdingler rev1+ BOE panel board";
+       compatible = "google,wormdingler-sku1024", "qcom,sc7180";
+};
+
+&dsi_phy {
+       qcom,phy-rescode-offset-top = /bits/ 8 <31 31 31 31 (-32)>;
+       qcom,phy-rescode-offset-bot = /bits/ 8 <31 31 31 31 (-32)>;
+       qcom,phy-drive-ldo-level = <450>;
+};
+
+&panel {
+       compatible = "boe,tv110c9m-ll3";
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev1-inx-rt5682s.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev1-inx-rt5682s.dts
new file mode 100644 (file)
index 0000000..7116c44
--- /dev/null
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Wormdingler board device tree source
+ *
+ * Copyright 2021 Google LLC.
+ *
+ * SKU: 0x0001 => 1
+ *  - bits 11..8: Panel ID: 0x0 (INX)
+ */
+
+/dts-v1/;
+
+#include "sc7180-trogdor-wormdingler-rev1-inx.dts"
+
+/ {
+       model = "Google Wormdingler rev1+ (INX, rt5682s)";
+       compatible = "google,wormdingler-sku1", "qcom,sc7180";
+};
+
+&alc5682 {
+       compatible = "realtek,rt5682s";
+       realtek,dmic1-clk-pin = <2>;
+       realtek,dmic-clk-rate-hz = <2048000>;
+};
+
+&sound {
+       compatible = "google,sc7180-trogdor";
+       model = "sc7180-rt5682s-max98357a-1mic";
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev1-inx.dts b/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler-rev1-inx.dts
new file mode 100644 (file)
index 0000000..dd34a22
--- /dev/null
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Wormdingler board device tree source
+ *
+ * Copyright 2021 Google LLC.
+ *
+ * SKU: 0x0000 => 0
+ *  - bits 11..8: Panel ID: 0x0 (INX)
+ */
+
+/dts-v1/;
+
+#include "sc7180-trogdor-wormdingler.dtsi"
+
+/ {
+       model = "Google Wormdingler rev1+ INX panel board";
+       compatible = "google,wormdingler-sku0", "qcom,sc7180";
+};
+
+&panel {
+       compatible = "innolux,hj110iz-01a";
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler.dtsi
new file mode 100644 (file)
index 0000000..6312108
--- /dev/null
@@ -0,0 +1,412 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Wormdingler board device tree source
+ *
+ * Copyright 2021 Google LLC.
+ */
+
+/dts-v1/;
+
+#include "sc7180-trogdor.dtsi"
+
+/ {
+       avdd_lcd: avdd-lcd {
+               compatible = "regulator-fixed";
+               regulator-name = "avdd_lcd";
+
+               gpio = <&tlmm 88 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               pinctrl-names = "default";
+               pinctrl-0 = <&avdd_lcd_en>;
+
+               vin-supply = <&pp5000_a>;
+       };
+
+       avee_lcd: avee-lcd {
+               compatible = "regulator-fixed";
+               regulator-name = "avee_lcd";
+
+               gpio = <&tlmm 21 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               pinctrl-names = "default";
+               pinctrl-0 = <&avee_lcd_en>;
+
+               vin-supply = <&pp5000_a>;
+       };
+
+       pp1800_ts:
+       v1p8_mipi: v1p8-mipi {
+               compatible = "regulator-fixed";
+               regulator-name = "v1p8_mipi";
+
+               gpio = <&tlmm 86 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+               pinctrl-names = "default";
+               pinctrl-0 = <&mipi_1800_en>;
+
+               vin-supply = <&pp3300_a>;
+       };
+
+       thermal-zones {
+               skin_temp_thermal: skin-temp-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <0>;
+
+                       thermal-sensors = <&pm6150_adc_tm 1>;
+                       sustainable-power = <574>;
+
+                       trips {
+                               skin_temp_alert0: trip-point0 {
+                                       temperature = <58000>;
+                                       hysteresis = <1000>;
+                                       type = "passive";
+                               };
+
+                               skin_temp_alert1: trip-point1 {
+                                       temperature = <62500>;
+                                       hysteresis = <1000>;
+                                       type = "passive";
+                               };
+
+                               skin-temp-crit {
+                                       temperature = <68000>;
+                                       hysteresis = <1000>;
+                                       type = "critical";
+                               };
+                       };
+
+                       cooling-maps {
+                               map0 {
+                                       trip = <&skin_temp_alert0>;
+                                       cooling-device = <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                        <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+
+                               map1 {
+                                       trip = <&skin_temp_alert1>;
+                                       cooling-device = <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                        <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
+                       };
+               };
+       };
+};
+
+&backlight {
+       pwms = <&cros_ec_pwm 0>;
+};
+
+&camcc {
+       status = "okay";
+};
+
+&cros_ec {
+       base_detection: cbas {
+               compatible = "google,cros-cbas";
+       };
+
+       keyboard-controller {
+               compatible = "google,cros-ec-keyb-switches";
+       };
+};
+
+&dsi0 {
+
+       panel: panel@0 {
+               reg = <0>;
+               enable-gpios = <&tlmm 87 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&vdd_reset_1800>;
+               avdd-supply = <&avdd_lcd>;
+               avee-supply = <&avee_lcd>;
+               pp1800-supply = <&v1p8_mipi>;
+               pp3300-supply = <&pp3300_dx_edp>;
+               backlight = <&backlight>;
+               rotation = <270>;
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       port@0 {
+                               reg = <0>;
+                               panel_in: endpoint {
+                                       remote-endpoint = <&dsi0_out>;
+                               };
+                       };
+               };
+       };
+
+       ports {
+               port@1 {
+                       endpoint {
+                               remote-endpoint = <&panel_in>;
+                               data-lanes = <0 1 2 3>;
+                       };
+               };
+       };
+};
+
+&i2c4 {
+       status = "okay";
+       clock-frequency = <400000>;
+
+       ap_ts: touchscreen@1 {
+               compatible = "hid-over-i2c";
+               reg = <0x01>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&ts_int_l>;
+
+               interrupt-parent = <&tlmm>;
+               interrupts = <9 IRQ_TYPE_EDGE_FALLING>;
+
+               post-power-on-delay-ms = <70>;
+               hid-descr-addr = <0x0001>;
+
+               vdd-supply = <&pp3300_ts>;
+               vddl-supply = <&pp1800_ts>;
+       };
+};
+
+&pm6150_adc {
+       skin-temp-thermistor@4d {
+               reg = <ADC5_AMUX_THM1_100K_PU>;
+               qcom,ratiometric;
+               qcom,hw-settle-time = <200>;
+       };
+};
+
+&pm6150_adc_tm {
+       status = "okay";
+
+       skin-temp-thermistor@1 {
+               reg = <1>;
+               io-channels = <&pm6150_adc ADC5_AMUX_THM1_100K_PU>;
+               qcom,ratiometric;
+               qcom,hw-settle-time-us = <200>;
+       };
+};
+
+&pp1800_uf_cam {
+       status = "okay";
+};
+
+&pp1800_wf_cam {
+       status = "okay";
+};
+
+&pp2800_uf_cam {
+       status = "okay";
+};
+
+&pp2800_wf_cam {
+       status = "okay";
+};
+
+&wifi {
+       qcom,ath10k-calibration-variant = "GO_WORMDINGLER";
+};
+
+/*
+ * No eDP on this board but it's logically the same signal so just give it
+ * a new name and assign the proper GPIO.
+ */
+pp3300_disp_on: &pp3300_dx_edp {
+       gpio = <&tlmm 85 GPIO_ACTIVE_HIGH>;
+};
+
+/* PINCTRL - modifications to sc7180-trogdor.dtsi */
+
+/*
+ * No eDP on this board but it's logically the same signal so just give it
+ * a new name and assign the proper GPIO.
+ */
+
+tp_en: &en_pp3300_dx_edp {
+       pinmux {
+               pins = "gpio85";
+       };
+
+       pinconf {
+               pins = "gpio85";
+       };
+};
+
+/* PINCTRL - board-specific pinctrl */
+
+&tlmm {
+       gpio-line-names = "HUB_RST_L",
+                         "AP_RAM_ID0",
+                         "AP_SKU_ID2",
+                         "AP_RAM_ID1",
+                         "",
+                         "AP_RAM_ID2",
+                         "UF_CAM_EN",
+                         "WF_CAM_EN",
+                         "TS_RESET_L",
+                         "TS_INT_L",
+                         "",
+                         "",
+                         "AP_EDP_BKLTEN",
+                         "UF_CAM_MCLK",
+                         "WF_CAM_CLK",
+                         "",
+                         "",
+                         "UF_CAM_SDA",
+                         "UF_CAM_SCL",
+                         "WF_CAM_SDA",
+                         "WF_CAM_SCL",
+                         "AVEE_LCD_EN",
+                         "",
+                         "AMP_EN",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "HP_IRQ",
+                         "WF_CAM_RST_L",
+                         "UF_CAM_RST_L",
+                         "AP_BRD_ID2",
+                         "",
+                         "AP_BRD_ID0",
+                         "AP_H1_SPI_MISO",
+                         "AP_H1_SPI_MOSI",
+                         "AP_H1_SPI_CLK",
+                         "AP_H1_SPI_CS_L",
+                         "BT_UART_CTS",
+                         "BT_UART_RTS",
+                         "BT_UART_TXD",
+                         "BT_UART_RXD",
+                         "H1_AP_INT_ODL",
+                         "",
+                         "UART_AP_TX_DBG_RX",
+                         "UART_DBG_TX_AP_RX",
+                         "HP_I2C_SDA",
+                         "HP_I2C_SCL",
+                         "FORCED_USB_BOOT",
+                         "AMP_BCLK",
+                         "AMP_LRCLK",
+                         "AMP_DIN",
+                         "",
+                         "HP_BCLK",
+                         "HP_LRCLK",
+                         "HP_DOUT",
+                         "HP_DIN",
+                         "HP_MCLK",
+                         "AP_SKU_ID0",
+                         "AP_EC_SPI_MISO",
+                         "AP_EC_SPI_MOSI",
+                         "AP_EC_SPI_CLK",
+                         "AP_EC_SPI_CS_L",
+                         "AP_SPI_CLK",
+                         "AP_SPI_MOSI",
+                         "AP_SPI_MISO",
+                         /*
+                          * AP_FLASH_WP_L is crossystem ABI. Schematics
+                          * call it BIOS_FLASH_WP_L.
+                          */
+                         "AP_FLASH_WP_L",
+                         "",
+                         "AP_SPI_CS0_L",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "WLAN_SW_CTRL",
+                         "",
+                         "REPORT_E",
+                         "",
+                         "ID0",
+                         "",
+                         "ID1",
+                         "",
+                         "",
+                         "",
+                         "CODEC_PWR_EN",
+                         "HUB_EN",
+                         "TP_EN",
+                         "MIPI_1.8V_EN",
+                         "VDD_RESET_1.8V",
+                         "AVDD_LCD_EN",
+                         "",
+                         "AP_SKU_ID1",
+                         "AP_RST_REQ",
+                         "",
+                         "AP_BRD_ID1",
+                         "AP_EC_INT_L",
+                         "SDM_GRFC_3",
+                         "",
+                         "",
+                         "BOOT_CONFIG_4",
+                         "BOOT_CONFIG_2",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "BOOT_CONFIG_3",
+                         "WCI2_LTE_COEX_TXD",
+                         "WCI2_LTE_COEX_RXD",
+                         "",
+                         "",
+                         "",
+                         "",
+                         "FORCED_USB_BOOT_POL",
+                         "AP_TS_PEN_I2C_SDA",
+                         "AP_TS_PEN_I2C_SCL",
+                         "DP_HOT_PLUG_DET",
+                         "EC_IN_RW_ODL";
+
+       avdd_lcd_en: avdd-lcd-en {
+               pinmux {
+                       pins = "gpio88";
+                       function = "gpio";
+               };
+
+               pinconf {
+                       pins = "gpio88";
+                       drive-strength = <2>;
+                       bias-disable;
+               };
+       };
+
+       avee_lcd_en: avee-lcd-en {
+               pinmux {
+                       pins = "gpio21";
+                       function = "gpio";
+               };
+
+               pinconf {
+                       pins = "gpio21";
+                       drive-strength = <2>;
+                       bias-disable;
+               };
+       };
+
+       mipi_1800_en: mipi-1800-en {
+               pinmux {
+                       pins = "gpio86";
+                       function = "gpio";
+               };
+
+               pinconf {
+                       pins = "gpio86";
+                       drive-strength = <2>;
+                       bias-disable;
+               };
+       };
+
+       vdd_reset_1800: vdd-reset-1800 {
+               pinmux {
+                       pins = "gpio87";
+                       function = "gpio";
+               };
+
+               pinconf {
+                       pins = "gpio87";
+                       drive-strength = <2>;
+                       bias-disable;
+               };
+       };
+};
index e55dbaa..b5f534d 100644 (file)
@@ -8,6 +8,7 @@
 #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/regulator/qcom,rpmh-regulator.h>
 #include <dt-bindings/sound/sc7180-lpass.h>
 
@@ -43,6 +44,7 @@
  */
 
 /delete-node/ &hyp_mem;
+/delete-node/ &ipa_fw_mem;
 /delete-node/ &xbl_mem;
 /delete-node/ &aop_mem;
 /delete-node/ &sec_apps_mem;
                pinctrl-names = "default";
                pinctrl-0 = <&pen_pdct_l>;
 
-               pen_insert: pen-insert {
+               pen_insert: switch-pen-insert {
                        label = "Pen Insert";
 
                        /* Insert = low, eject = high */
                keyboard_backlight: keyboard-backlight {
                        status = "disabled";
                        label = "cros_ec::kbd_backlight";
+                       function = LED_FUNCTION_KBD_BACKLIGHT;
                        pwms = <&cros_ec_pwm 0>;
                        max-brightness = <1023>;
                };
@@ -812,8 +815,6 @@ hp_i2c: &i2c9 {
        pinctrl-names = "default";
        pinctrl-0 = <&dp_hot_plug_det>;
        data-lanes = <0 1>;
-       vdda-1p2-supply = <&vdda_usb_ss_dp_1p2>;
-       vdda-0p9-supply = <&vdda_usb_ss_dp_core>;
 };
 
 &pm6150_adc {
@@ -903,7 +904,6 @@ ap_spi_fp: &spi10 {
        };
 };
 
-#include <arm/cros-ec-keyboard.dtsi>
 #include <arm/cros-ec-sbs.dtsi>
 
 &uart3 {
index 5dcaac2..b82c335 100644 (file)
                };
        };
 
-       cpu0_opp_table: cpu0_opp_table {
+       cpu0_opp_table: opp-table-cpu0 {
                compatible = "operating-points-v2";
                opp-shared;
 
                };
        };
 
-       cpu6_opp_table: cpu6_opp_table {
+       cpu6_opp_table: opp-table-cpu6 {
                compatible = "operating-points-v2";
                opp-shared;
 
                        };
                };
 
-               sdhc_1: sdhci@7c4000 {
+               sdhc_1: mmc@7c4000 {
                        compatible = "qcom,sc7180-sdhci", "qcom,sdhci-msm-v5";
                        reg = <0 0x7c4000 0 0x1000>,
                                <0 0x07c5000 0 0x1000>;
                                        <GIC_SPI 644 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "hc_irq", "pwr_irq";
 
-                       clocks = <&gcc GCC_SDCC1_APPS_CLK>,
-                                <&gcc GCC_SDCC1_AHB_CLK>,
+                       clocks = <&gcc GCC_SDCC1_AHB_CLK>,
+                                <&gcc GCC_SDCC1_APPS_CLK>,
                                 <&rpmhcc RPMH_CXO_CLK>;
-                       clock-names = "core", "iface", "xo";
+                       clock-names = "iface", "core", "xo";
                        interconnects = <&aggre1_noc MASTER_EMMC 0 &mc_virt SLAVE_EBI1 0>,
                                        <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_EMMC_CFG 0>;
                        interconnect-names = "sdhc-ddr","cpu-sdhc";
 
                        status = "disabled";
 
-                       sdhc1_opp_table: sdhc1-opp-table {
+                       sdhc1_opp_table: opp-table {
                                compatible = "operating-points-v2";
 
                                opp-100000000 {
                        };
                };
 
-               qup_opp_table: qup-opp-table {
+               qup_opp_table: opp-table-qup {
                        compatible = "operating-points-v2";
 
                        opp-75000000 {
                };
 
                gmu: gmu@506a000 {
-                       compatible="qcom,adreno-gmu-618.0", "qcom,adreno-gmu";
+                       compatible = "qcom,adreno-gmu-618.0", "qcom,adreno-gmu";
                        reg = <0 0x0506a000 0 0x31000>, <0 0x0b290000 0 0x10000>,
                                <0 0x0b490000 0 0x10000>;
                        reg-names = "gmu", "gmu_pdc", "gmu_pdc_seq";
                        };
                };
 
-               sdhc_2: sdhci@8804000 {
+               sdhc_2: mmc@8804000 {
                        compatible = "qcom,sc7180-sdhci", "qcom,sdhci-msm-v5";
                        reg = <0 0x08804000 0 0x1000>;
 
                                        <GIC_SPI 222 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "hc_irq", "pwr_irq";
 
-                       clocks = <&gcc GCC_SDCC2_APPS_CLK>,
-                                <&gcc GCC_SDCC2_AHB_CLK>,
+                       clocks = <&gcc GCC_SDCC2_AHB_CLK>,
+                                <&gcc GCC_SDCC2_APPS_CLK>,
                                 <&rpmhcc RPMH_CXO_CLK>;
-                       clock-names = "core", "iface", "xo";
+                       clock-names = "iface", "core", "xo";
 
                        interconnects = <&aggre1_noc MASTER_SDCC_2 0 &mc_virt SLAVE_EBI1 0>,
                                        <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_SDCC_2 0>;
 
                        status = "disabled";
 
-                       sdhc2_opp_table: sdhc2-opp-table {
+                       sdhc2_opp_table: opp-table {
                                compatible = "operating-points-v2";
 
                                opp-100000000 {
                        };
                };
 
-               qspi_opp_table: qspi-opp-table {
+               qspi_opp_table: opp-table-qspi {
                        compatible = "operating-points-v2";
 
                        opp-75000000 {
                                compatible = "venus-encoder";
                        };
 
-                       venus_opp_table: venus-opp-table {
+                       venus_opp_table: opp-table {
                                compatible = "operating-points-v2";
 
                                opp-150000000 {
                                 <&dispcc DISP_CC_MDSS_MDP_CLK>;
                        clock-names = "iface", "ahb", "core";
 
-                       assigned-clocks = <&dispcc DISP_CC_MDSS_MDP_CLK>;
-                       assigned-clock-rates = <300000000>;
-
                        interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
 
                        status = "disabled";
 
-                       mdp: mdp@ae01000 {
+                       mdp: display-controller@ae01000 {
                                compatible = "qcom,sc7180-dpu";
                                reg = <0 0x0ae01000 0 0x8f000>,
                                      <0 0x0aeb0000 0 0x2008>;
                                         <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
                                clock-names = "bus", "iface", "rot", "lut", "core",
                                              "vsync";
-                               assigned-clocks = <&dispcc DISP_CC_MDSS_MDP_CLK>,
-                                                 <&dispcc DISP_CC_MDSS_VSYNC_CLK>,
+                               assigned-clocks = <&dispcc DISP_CC_MDSS_VSYNC_CLK>,
                                                  <&dispcc DISP_CC_MDSS_ROT_CLK>,
                                                  <&dispcc DISP_CC_MDSS_AHB_CLK>;
-                               assigned-clock-rates = <300000000>,
-                                                      <19200000>,
+                               assigned-clock-rates = <19200000>,
                                                       <19200000>,
                                                       <19200000>;
                                operating-points-v2 = <&mdp_opp_table>;
                                        };
                                };
 
-                               mdp_opp_table: mdp-opp-table {
+                               mdp_opp_table: opp-table {
                                        compatible = "operating-points-v2";
 
                                        opp-200000000 {
                                        };
                                };
 
-                               dsi_opp_table: dsi-opp-table {
+                               dsi_opp_table: opp-table {
                                        compatible = "operating-points-v2";
 
                                        opp-187500000 {
                                compatible = "qcom,sc7180-dp";
                                status = "disabled";
 
-                               reg = <0 0x0ae90000 0 0x1400>;
+                               reg = <0 0xae90000 0 0x200>,
+                                     <0 0xae90200 0 0x200>,
+                                     <0 0xae90400 0 0xc00>,
+                                     <0 0xae91000 0 0x400>,
+                                     <0 0xae91400 0 0x400>;
 
                                interrupt-parent = <&mdss>;
                                interrupts = <12>;
                                         <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK>;
                                clock-names = "core_iface", "core_aux", "ctrl_link",
                                              "ctrl_link_iface", "stream_pixel";
-                               #clock-cells = <1>;
                                assigned-clocks = <&dispcc DISP_CC_MDSS_DP_LINK_CLK_SRC>,
                                                  <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>;
                                assigned-clock-parents = <&dp_phy 0>, <&dp_phy 1>;
                };
 
                aoss_qmp: power-controller@c300000 {
-                       compatible = "qcom,sc7180-aoss-qmp";
+                       compatible = "qcom,sc7180-aoss-qmp", "qcom,aoss-qmp";
                        reg = <0 0x0c300000 0 0x400>;
                        interrupts = <GIC_SPI 389 IRQ_TYPE_EDGE_RISING>;
                        mboxes = <&apss_shared 0>;
                        cell-index = <0>;
                };
 
-               imem@146aa000 {
-                       compatible = "simple-mfd";
+               sram@146aa000 {
+                       compatible = "qcom,sc7180-imem", "syscon", "simple-mfd";
                        reg = <0 0x146aa000 0 0x2000>;
 
                        #address-cells = <1>;
                };
 
                timer@17c20000{
-                       #address-cells = <2>;
-                       #size-cells = <2>;
-                       ranges;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0 0 0 0x20000000>;
                        compatible = "arm,armv7-timer-mem";
                        reg = <0 0x17c20000 0 0x1000>;
 
                                frame-number = <0>;
                                interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0 0x17c21000 0 0x1000>,
-                                     <0 0x17c22000 0 0x1000>;
+                               reg = <0x17c21000 0x1000>,
+                                     <0x17c22000 0x1000>;
                        };
 
                        frame@17c23000 {
                                frame-number = <1>;
                                interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0 0x17c23000 0 0x1000>;
+                               reg = <0x17c23000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c25000 {
                                frame-number = <2>;
                                interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0 0x17c25000 0 0x1000>;
+                               reg = <0x17c25000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c27000 {
                                frame-number = <3>;
                                interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0 0x17c27000 0 0x1000>;
+                               reg = <0x17c27000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c29000 {
                                frame-number = <4>;
                                interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0 0x17c29000 0 0x1000>;
+                               reg = <0x17c29000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c2b000 {
                                frame-number = <5>;
                                interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0 0x17c2b000 0 0x1000>;
+                               reg = <0x17c2b000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c2d000 {
                                frame-number = <6>;
                                interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0 0x17c2d000 0 0x1000>;
+                               reg = <0x17c2d000 0x1000>;
                                status = "disabled";
                        };
                };
                        compatible = "qcom,sc7180-lpass-cpu";
 
                        reg = <0 0x62d87000 0 0x68000>, <0 0x62f00000 0 0x29000>;
-                       reg-names =  "lpass-hdmiif", "lpass-lpaif";
+                       reg-names = "lpass-hdmiif", "lpass-lpaif";
 
                        iommus = <&apps_smmu 0x1020 0>,
                                <&apps_smmu 0x1021 0>,
index 9f4a9c2..cfe2741 100644 (file)
        status = "okay";
        compatible = "qcom,sc7280-mss-pil";
        iommus = <&apps_smmu 0x124 0x0>, <&apps_smmu 0x488 0x7>;
+       interconnects = <&mc_virt MASTER_LLCC 0 &mc_virt SLAVE_EBI1 0>;
        memory-region = <&mba_mem>, <&mpss_mem>;
+       firmware-name = "qcom/sc7280-herobrine/modem/mba.mbn",
+                       "qcom/sc7280-herobrine/modem/qdsp6sw.mbn";
+};
+
+&remoteproc_wpss {
+       status = "okay";
+       firmware-name = "ath11k/WCN6750/hw1.0/wpss.mdt";
 };
 
 /* Increase the size from 2.5MB to 8MB */
 &rmtfs_mem {
        reg = <0x0 0x9c900000 0x0 0x800000>;
 };
+
+&wifi {
+       status = "okay";
+
+       wifi-firmware {
+               iommus = <&apps_smmu 0x1c02 0x1>;
+       };
+};
diff --git a/arch/arm64/boot/dts/qcom/sc7280-herobrine-audio-wcd9385.dtsi b/arch/arm64/boot/dts/qcom/sc7280-herobrine-audio-wcd9385.dtsi
new file mode 100644 (file)
index 0000000..859faaa
--- /dev/null
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * sc7280 device tree source for boards using Max98360 and wcd9385 codec
+ *
+ * Copyright (c) 2022, The Linux Foundation. All rights reserved.
+ */
+
+/* PINCTRL */
+
+&lpass_dmic01_clk {
+       drive-strength = <8>;
+       bias-disable;
+};
+
+&lpass_dmic01_clk_sleep {
+       drive-strength = <2>;
+};
+
+&lpass_dmic01_data {
+       bias-pull-down;
+};
+
+&lpass_dmic23_clk {
+       drive-strength = <8>;
+       bias-disable;
+};
+
+&lpass_dmic23_clk_sleep {
+       drive-strength = <2>;
+};
+
+&lpass_dmic23_data {
+       bias-pull-down;
+};
+
+&lpass_rx_swr_clk {
+       drive-strength = <2>;
+       slew-rate = <1>;
+       bias-disable;
+};
+
+&lpass_rx_swr_clk_sleep {
+       bias-pull-down;
+};
+
+&lpass_rx_swr_data {
+       drive-strength = <2>;
+       slew-rate = <1>;
+       bias-bus-hold;
+};
+
+&lpass_rx_swr_data_sleep {
+       bias-pull-down;
+};
+
+&lpass_tx_swr_clk {
+       drive-strength = <2>;
+       slew-rate = <1>;
+       bias-disable;
+};
+
+&lpass_tx_swr_clk_sleep {
+       bias-pull-down;
+};
+
+&lpass_tx_swr_data {
+       drive-strength = <2>;
+       slew-rate = <1>;
+       bias-bus-hold;
+};
+
+&mi2s1_data0 {
+       drive-strength = <6>;
+       bias-disable;
+};
+
+&mi2s1_sclk {
+       drive-strength = <6>;
+       bias-disable;
+};
+
+&mi2s1_ws {
+       drive-strength = <6>;
+};
index a4ac33c..7881bbc 100644 (file)
@@ -8,6 +8,7 @@
 /dts-v1/;
 
 #include "sc7280-herobrine.dtsi"
+#include "sc7280-herobrine-audio-wcd9385.dtsi"
 
 / {
        model = "Qualcomm Technologies, Inc. sc7280 CRD platform (rev5+)";
@@ -134,6 +135,17 @@ ap_ts_pen_1v8: &i2c13 {
        status = "okay";
 };
 
+/* PINCTRL - ADDITIONS TO NODES IN PARENT DEVICE TREE FILES */
+
+/*
+ * This pin goes to the display panel but then doesn't actually do anything
+ * on the panel itself (it doesn't connect to the touchscreen controller).
+ * We'll set a pullup here just to park the line.
+ */
+&ts_rst_conn {
+       bias-pull-up;
+};
+
 /* PINCTRL - BOARD-SPECIFIC */
 
 /*
index b69ca09..c1647a8 100644 (file)
@@ -128,6 +128,17 @@ ts_i2c: &i2c13 {
        status = "okay";
 };
 
+/* PINCTRL - ADDITIONS TO NODES IN PARENT DEVICE TREE FILES */
+
+/*
+ * This pin goes to the display panel but then doesn't actually do anything
+ * on the panel itself (it doesn't connect to the touchscreen controller).
+ * We'll set a pullup here just to park the line.
+ */
+&ts_rst_conn {
+       bias-pull-up;
+};
+
 /* PINCTRL - BOARD-SPECIFIC */
 
 /*
index d3d6ffa..2cacafd 100644 (file)
@@ -46,6 +46,25 @@ ap_tp_i2c: &i2c0 {
        };
 };
 
+ts_i2c: &i2c13 {
+       status = "okay";
+       clock-frequency = <400000>;
+
+       ap_ts: touchscreen@10 {
+               compatible = "elan,ekth6915";
+               reg = <0x10>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&ts_int_conn>, <&ts_rst_conn>;
+
+               interrupt-parent = <&tlmm>;
+               interrupts = <55 IRQ_TYPE_LEVEL_LOW>;
+
+               reset-gpios = <&tlmm 54 GPIO_ACTIVE_LOW>;
+
+               vcc33-supply = <&ts_avdd>;
+       };
+};
+
 &ap_sar_sensor_i2c {
        status = "okay";
 };
@@ -76,11 +95,21 @@ ap_tp_i2c: &i2c0 {
        status = "okay";
 };
 
+&pwmleds {
+       status = "okay";
+};
+
 /* For eMMC */
 &sdhc_1 {
        status = "okay";
 };
 
+/* PINCTRL - ADDITIONS TO NODES IN PARENT DEVICE TREE FILES */
+
+&ts_rst_conn {
+       bias-disable;
+};
+
 /* PINCTRL - BOARD-SPECIFIC */
 
 /*
index 9cb1bc8..3f8996c 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <dt-bindings/input/gpio-keys.h>
 #include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
 
 #include "sc7280-qcard.dtsi"
 #include "sc7280-chrome-common.dtsi"
 
        /* BOARD-SPECIFIC TOP LEVEL NODES */
 
-       pwmleds {
+       pwmleds: pwmleds {
                compatible = "pwm-leds";
                status = "disabled";
                keyboard_backlight: keyboard-backlight {
-                       status = "disabled";
                        label = "cros_ec::kbd_backlight";
+                       function = LED_FUNCTION_KBD_BACKLIGHT;
                        pwms = <&cros_ec_pwm 0>;
                        max-brightness = <1023>;
                };
@@ -388,7 +389,7 @@ ap_sar_sensor_i2c: &i2c1 {
 
                vdd-supply = <&pp1800_prox>;
 
-               label = "proximity-wifi-lte0";
+               label = "proximity-wifi_cellular-0";
                status = "disabled";
        };
 
@@ -404,7 +405,7 @@ ap_sar_sensor_i2c: &i2c1 {
 
                vdd-supply = <&pp1800_prox>;
 
-               label = "proximity-wifi-lte1";
+               label = "proximity-wifi_cellular-1";
                status = "disabled";
        };
 };
@@ -429,6 +430,13 @@ ap_i2c_tpm: &i2c14 {
        status = "okay";
 };
 
+&mdss_dp {
+       status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&dp_hot_plug_det>;
+       data-lanes = <0 1>;
+};
+
 &mdss_mdp {
        status = "okay";
 };
@@ -476,6 +484,10 @@ ap_i2c_tpm: &i2c14 {
        cd-gpios = <&tlmm 91 GPIO_ACTIVE_LOW>;
 };
 
+&spi_flash {
+       spi-max-frequency = <50000000>;
+};
+
 /* Fingerprint, enabled on a per-board basis */
 ap_spi_fp: &spi9 {
        pinctrl-0 = <&qup_spi9_data_clk>, <&qup_spi9_cs_gpio_init_high>, <&qup_spi9_cs_gpio>;
index 5eb6689..a74e0b7 100644 (file)
@@ -27,7 +27,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&key_vol_up_default>;
 
-               volume-up {
+               key-volume-up {
                        label = "volume_up";
                        gpios = <&pm7325_gpios 6 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
        bias-disable;
 };
 
+&lpass_dmic01_clk {
+       drive-strength = <8>;
+       bias-disable;
+};
+
+&lpass_dmic01_clk_sleep {
+       drive-strength = <2>;
+};
+
+&lpass_dmic01_data {
+       bias-pull-down;
+};
+
+&lpass_dmic23_clk {
+       drive-strength = <8>;
+       bias-disable;
+};
+
+&lpass_dmic23_clk_sleep {
+       drive-strength = <2>;
+};
+
+&lpass_dmic23_data {
+       bias-pull-down;
+};
+
+&lpass_rx_swr_clk {
+       drive-strength = <2>;
+       slew-rate = <1>;
+       bias-disable;
+};
+
+&lpass_rx_swr_clk_sleep {
+       bias-pull-down;
+};
+
+&lpass_rx_swr_data {
+       drive-strength = <2>;
+       slew-rate = <1>;
+       bias-bus-hold;
+};
+
+&lpass_rx_swr_data_sleep {
+       bias-pull-down;
+};
+
+&lpass_tx_swr_clk {
+       drive-strength = <2>;
+       slew-rate = <1>;
+       bias-disable;
+};
+
+&lpass_tx_swr_clk_sleep {
+       bias-pull-down;
+};
+
+&lpass_tx_swr_data {
+       drive-strength = <2>;
+       slew-rate = <1>;
+       bias-bus-hold;
+};
+
+&mi2s1_data0 {
+       drive-strength = <6>;
+       bias-disable;
+};
+
+&mi2s1_sclk {
+       drive-strength = <6>;
+       bias-disable;
+};
+
+&mi2s1_ws {
+       drive-strength = <6>;
+};
+
 &pm7325_gpios {
-       key_vol_up_default: key-vol-up-default {
+       key_vol_up_default: key-vol-up-state {
                pins = "gpio6";
                function = "normal";
                input-enable;
                bias-pull-down;
        };
 };
-
-&remoteproc_wpss {
-       status = "okay";
-};
-
-&wifi {
-       status = "okay";
-       wifi-firmware {
-               iommus = <&apps_smmu 0x1c02 0x1>;
-       };
-};
index d59002d..7adf31b 100644 (file)
                        regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
                };
 
+               vreg_l17b_1p8: ldo17 {
+                       regulator-min-microvolt = <1700000>;
+                       regulator-max-microvolt = <1900000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
                vdd_px_wcd9385:
                vdd_txrx:
                vddpx_0:
 
 /* NOTE: Not all Qcards have eDP connector stuffed */
 &mdss_edp {
-       vdda-0p9-supply = <&vdd_a_edp_0_0p9>;
-       vdda-1p2-supply = <&vdd_a_edp_0_1p2>;
-
        aux-bus {
                edp_panel: panel {
                        compatible = "edp-panel";
@@ -517,7 +520,7 @@ mos_bt_uart: &uart7 {
  */
 
 &pm8350c_gpios {
-       pmic_edp_bl_en: pmic-edp-bl-en {
+       pmic_edp_bl_en: pmic-edp-bl-en-state {
                pins = "gpio7";
                function = "normal";
                bias-disable;
@@ -527,7 +530,7 @@ mos_bt_uart: &uart7 {
                output-low;
        };
 
-       pmic_edp_bl_pwm: pmic-edp-bl-pwm {
+       pmic_edp_bl_pwm: pmic-edp-bl-pwm-state {
                pins = "gpio8";
                function = "func1";
                bias-disable;
@@ -604,7 +607,6 @@ mos_bt_uart: &uart7 {
        ts_rst_conn: ts-rst-conn {
                pins = "gpio54";
                function = "gpio";
-               bias-pull-up;
                drive-strength = <2>;
        };
 };
index e66fc67..13d7f26 100644 (file)
                };
        };
 
-       cpu0_opp_table: cpu0-opp-table {
+       cpu0_opp_table: opp-table-cpu0 {
                compatible = "operating-points-v2";
                opp-shared;
 
                };
        };
 
-       cpu4_opp_table: cpu4-opp-table {
+       cpu4_opp_table: opp-table-cpu4 {
                compatible = "operating-points-v2";
                opp-shared;
 
                };
        };
 
-       cpu7_opp_table: cpu7-opp-table {
+       cpu7_opp_table: opp-table-cpu7 {
                compatible = "operating-points-v2";
                opp-shared;
 
                method = "smc";
        };
 
-       qspi_opp_table: qspi-opp-table {
+       qspi_opp_table: opp-table-qspi {
                compatible = "operating-points-v2";
 
                opp-75000000 {
                };
        };
 
-       qup_opp_table: qup-opp-table {
+       qup_opp_table: opp-table-qup {
                compatible = "operating-points-v2";
 
                opp-75000000 {
                        reg = <0 0x00100000 0 0x1f0000>;
                        clocks = <&rpmhcc RPMH_CXO_CLK>,
                                 <&rpmhcc RPMH_CXO_CLK_A>, <&sleep_clk>,
-                                <0>, <&pcie1_lane 0>,
+                                <0>, <&pcie1_lane>,
                                 <0>, <0>, <0>, <0>;
                        clock-names = "bi_tcxo", "bi_tcxo_ao", "sleep_clk",
                                      "pcie_0_pipe_clk", "pcie_1_pipe_clk",
                        };
                };
 
-               sdhc_1: sdhci@7c4000 {
+               sdhc_1: mmc@7c4000 {
                        compatible = "qcom,sc7280-sdhci", "qcom,sdhci-msm-v5";
                        pinctrl-names = "default", "sleep";
                        pinctrl-0 = <&sdc1_clk>, <&sdc1_cmd>, <&sdc1_data>, <&sdc1_rclk>;
                                     <GIC_SPI 656 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "hc_irq", "pwr_irq";
 
-                       clocks = <&gcc GCC_SDCC1_APPS_CLK>,
-                                <&gcc GCC_SDCC1_AHB_CLK>,
+                       clocks = <&gcc GCC_SDCC1_AHB_CLK>,
+                                <&gcc GCC_SDCC1_APPS_CLK>,
                                 <&rpmhcc RPMH_CXO_CLK>;
-                       clock-names = "core", "iface", "xo";
+                       clock-names = "iface", "core", "xo";
                        interconnects = <&aggre1_noc MASTER_SDCC_1 0 &mc_virt SLAVE_EBI1 0>,
                                        <&gem_noc MASTER_APPSS_PROC 0 &cnoc2 SLAVE_SDCC_1 0>;
                        interconnect-names = "sdhc-ddr","cpu-sdhc";
 
                        clocks = <&gcc GCC_PCIE_1_PIPE_CLK>,
                                 <&gcc GCC_PCIE_1_PIPE_CLK_SRC>,
-                                <&pcie1_lane 0>,
+                                <&pcie1_lane>,
                                 <&rpmhcc RPMH_CXO_CLK>,
                                 <&gcc GCC_PCIE_1_AUX_CLK>,
                                 <&gcc GCC_PCIE_1_CFG_AHB_CLK>,
                                clock-names = "pipe0";
 
                                #phy-cells = <0>;
-                               #clock-cells = <1>;
+                               #clock-cells = <0>;
                                clock-output-names = "pcie_1_pipe_clk";
                        };
                };
                lpasscore: clock-controller@3900000 {
                        compatible = "qcom,sc7280-lpasscorecc";
                        reg = <0 0x03900000 0 0x50000>;
-                       clocks =  <&rpmhcc RPMH_CXO_CLK>;
+                       clocks = <&rpmhcc RPMH_CXO_CLK>;
                        clock-names = "bi_tcxo";
                        power-domains = <&lpass_hm LPASS_CORE_CC_LPASS_CORE_HM_GDSC>;
                        #clock-cells = <1>;
                        qcom,bcm-voters = <&apps_bcm_voter>;
                };
 
+               lpass_tlmm: pinctrl@33c0000 {
+                       compatible = "qcom,sc7280-lpass-lpi-pinctrl";
+                       reg = <0 0x033c0000 0x0 0x20000>,
+                               <0 0x03550000 0x0 0x10000>;
+                       qcom,adsp-bypass-mode;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       gpio-ranges = <&lpass_tlmm 0 0 15>;
+
+                       #clock-cells = <1>;
+
+                       lpass_dmic01_clk: dmic01-clk {
+                               pins = "gpio6";
+                               function = "dmic1_clk";
+                       };
+
+                       lpass_dmic01_clk_sleep: dmic01-clk-sleep {
+                               pins = "gpio6";
+                               function = "dmic1_clk";
+                       };
+
+                       lpass_dmic01_data: dmic01-data {
+                               pins = "gpio7";
+                               function = "dmic1_data";
+                       };
+
+                       lpass_dmic01_data_sleep: dmic01-data-sleep {
+                               pins = "gpio7";
+                               function = "dmic1_data";
+                       };
+
+                       lpass_dmic23_clk: dmic23-clk {
+                               pins = "gpio8";
+                               function = "dmic2_clk";
+                       };
+
+                       lpass_dmic23_clk_sleep: dmic23-clk-sleep {
+                               pins = "gpio8";
+                               function = "dmic2_clk";
+                       };
+
+                       lpass_dmic23_data: dmic23-data {
+                               pins = "gpio9";
+                               function = "dmic2_data";
+                       };
+
+                       lpass_dmic23_data_sleep: dmic23-data-sleep {
+                               pins = "gpio9";
+                               function = "dmic2_data";
+                       };
+
+                       lpass_rx_swr_clk: rx-swr-clk {
+                               pins = "gpio3";
+                               function = "swr_rx_clk";
+                       };
+
+                       lpass_rx_swr_clk_sleep: rx-swr-clk-sleep {
+                               pins = "gpio3";
+                               function = "swr_rx_clk";
+                       };
+
+                       lpass_rx_swr_data: rx-swr-data {
+                               pins = "gpio4", "gpio5";
+                               function = "swr_rx_data";
+                       };
+
+                       lpass_rx_swr_data_sleep: rx-swr-data-sleep {
+                               pins = "gpio4", "gpio5";
+                               function = "swr_rx_data";
+                       };
+
+                       lpass_tx_swr_clk: tx-swr-clk {
+                               pins = "gpio0";
+                               function = "swr_tx_clk";
+                       };
+
+                       lpass_tx_swr_clk_sleep: tx-swr-clk-sleep {
+                               pins = "gpio0";
+                               function = "swr_tx_clk";
+                       };
+
+                       lpass_tx_swr_data: tx-swr-data {
+                               pins = "gpio1", "gpio2", "gpio14";
+                               function = "swr_tx_data";
+                       };
+
+                       lpass_tx_swr_data_sleep: tx-swr-data-sleep {
+                               pins = "gpio1", "gpio2", "gpio14";
+                               function = "swr_tx_data";
+                       };
+               };
+
                gpu: gpu@3d00000 {
                        compatible = "qcom,adreno-635.0", "qcom,adreno";
                        reg = <0 0x03d00000 0 0x40000>,
                };
 
                gmu: gmu@3d6a000 {
-                       compatible="qcom,adreno-gmu-635.0", "qcom,adreno-gmu";
+                       compatible = "qcom,adreno-gmu-635.0", "qcom,adreno-gmu";
                        reg = <0 0x03d6a000 0 0x34000>,
                                <0 0x3de0000 0 0x10000>,
                                <0 0x0b290000 0 0x10000>;
                        interrupts = <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>,
                                        <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "hfi", "gmu";
-                       clocks = <&gpucc 5>,
-                                       <&gpucc 8>,
-                                       <&gcc GCC_DDRSS_GPU_AXI_CLK>,
-                                       <&gcc GCC_GPU_MEMNOC_GFX_CLK>,
-                                       <&gpucc 2>,
-                                       <&gpucc 15>,
-                                       <&gpucc 11>;
+                       clocks = <&gpucc GPU_CC_CX_GMU_CLK>,
+                                <&gpucc GPU_CC_CXO_CLK>,
+                                <&gcc GCC_DDRSS_GPU_AXI_CLK>,
+                                <&gcc GCC_GPU_MEMNOC_GFX_CLK>,
+                                <&gpucc GPU_CC_AHB_CLK>,
+                                <&gpucc GPU_CC_HUB_CX_INT_CLK>,
+                                <&gpucc GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK>;
                        clock-names = "gmu",
                                      "cxo",
                                      "axi",
                                      "ahb",
                                      "hub",
                                      "smmu_vote";
-                       power-domains = <&gpucc 0>,
-                                       <&gpucc 1>;
+                       power-domains = <&gpucc GPU_CC_CX_GDSC>,
+                                       <&gpucc GPU_CC_GX_GDSC>;
                        power-domain-names = "cx",
                                             "gx";
                        iommus = <&adreno_smmu 5 0x400>;
                                        <GIC_SPI 687 IRQ_TYPE_LEVEL_HIGH>;
 
                        clocks = <&gcc GCC_GPU_MEMNOC_GFX_CLK>,
-                                       <&gcc GCC_GPU_SNOC_DVM_GFX_CLK>,
-                                       <&gpucc 2>,
-                                       <&gpucc 11>,
-                                       <&gpucc 5>,
-                                       <&gpucc 15>,
-                                       <&gpucc 13>;
+                                <&gcc GCC_GPU_SNOC_DVM_GFX_CLK>,
+                                <&gpucc GPU_CC_AHB_CLK>,
+                                <&gpucc GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK>,
+                                <&gpucc GPU_CC_CX_GMU_CLK>,
+                                <&gpucc GPU_CC_HUB_CX_INT_CLK>,
+                                <&gpucc GPU_CC_HUB_AON_CLK>;
                        clock-names = "gcc_gpu_memnoc_gfx_clk",
                                        "gcc_gpu_snoc_dvm_gfx_clk",
                                        "gpu_cc_ahb_clk",
                                        "gpu_cc_hub_cx_int_clk",
                                        "gpu_cc_hub_aon_clk";
 
-                       power-domains = <&gpucc 0>;
+                       power-domains = <&gpucc GPU_CC_CX_GDSC>;
                };
 
                remoteproc_mpss: remoteproc@4080000 {
                        };
                };
 
-               sdhc_2: sdhci@8804000 {
+               sdhc_2: mmc@8804000 {
                        compatible = "qcom,sc7280-sdhci", "qcom,sdhci-msm-v5";
                        pinctrl-names = "default", "sleep";
                        pinctrl-0 = <&sdc2_clk>, <&sdc2_cmd>, <&sdc2_data>;
                                     <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "hc_irq", "pwr_irq";
 
-                       clocks = <&gcc GCC_SDCC2_APPS_CLK>,
-                                <&gcc GCC_SDCC2_AHB_CLK>,
+                       clocks = <&gcc GCC_SDCC2_AHB_CLK>,
+                                <&gcc GCC_SDCC2_APPS_CLK>,
                                 <&rpmhcc RPMH_CXO_CLK>;
-                       clock-names = "core", "iface", "xo";
+                       clock-names = "iface", "core", "xo";
                        interconnects = <&aggre1_noc MASTER_SDCC_2 0 &mc_virt SLAVE_EBI1 0>,
                                        <&gem_noc MASTER_APPSS_PROC 0 &cnoc2 SLAVE_SDCC_2 0>;
                        interconnect-names = "sdhc-ddr","cpu-sdhc";
                        assigned-clock-rates = <19200000>, <200000000>;
 
                        interrupts-extended = <&intc GIC_SPI 240 IRQ_TYPE_LEVEL_HIGH>,
-                                    <&pdc 13 IRQ_TYPE_EDGE_RISING>,
-                                    <&pdc 12 IRQ_TYPE_EDGE_RISING>;
+                                             <&pdc 12 IRQ_TYPE_EDGE_RISING>,
+                                             <&pdc 13 IRQ_TYPE_EDGE_RISING>;
                        interrupt-names = "hs_phy_irq",
-                                         "dm_hs_phy_irq", "dp_hs_phy_irq";
+                                         "dp_hs_phy_irq",
+                                         "dm_hs_phy_irq";
 
                        power-domains = <&gcc GCC_USB30_SEC_GDSC>;
 
                        assigned-clock-rates = <19200000>, <200000000>;
 
                        interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
-                                             <&pdc 17 IRQ_TYPE_EDGE_BOTH>,
+                                             <&pdc 14 IRQ_TYPE_LEVEL_HIGH>,
                                              <&pdc 15 IRQ_TYPE_EDGE_BOTH>,
-                                             <&pdc 14 IRQ_TYPE_LEVEL_HIGH>;
+                                             <&pdc 17 IRQ_TYPE_EDGE_BOTH>;
                        interrupt-names = "hs_phy_irq",
-                                         "ss_phy_irq",
+                                         "dp_hs_phy_irq",
                                          "dm_hs_phy_irq",
-                                         "dp_hs_phy_irq";
+                                         "ss_phy_irq";
 
                        power-domains = <&gcc GCC_USB30_PRIM_GDSC>;
 
                                iommus = <&apps_smmu 0x21a2 0x0>;
                        };
 
-                       venus_opp_table: venus-opp-table {
+                       venus_opp_table: opp-table {
                                compatible = "operating-points-v2";
 
                                opp-133330000 {
                                      "ahb",
                                      "core";
 
-                       assigned-clocks = <&dispcc DISP_CC_MDSS_MDP_CLK>;
-                       assigned-clock-rates = <300000000>;
-
                        interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                                              "lut",
                                              "core",
                                              "vsync";
-                               assigned-clocks = <&dispcc DISP_CC_MDSS_MDP_CLK>,
-                                               <&dispcc DISP_CC_MDSS_VSYNC_CLK>,
+                               assigned-clocks = <&dispcc DISP_CC_MDSS_VSYNC_CLK>,
                                                <&dispcc DISP_CC_MDSS_AHB_CLK>;
-                               assigned-clock-rates = <300000000>,
-                                                       <19200000>,
+                               assigned-clock-rates = <19200000>,
                                                        <19200000>;
                                operating-points-v2 = <&mdp_opp_table>;
                                power-domains = <&rpmhpd SC7280_CX>;
                                interrupt-parent = <&mdss>;
                                interrupts = <14>;
 
-                               clocks = <&rpmhcc RPMH_CXO_CLK>,
-                                        <&gcc GCC_EDP_CLKREF_EN>,
-                                        <&dispcc DISP_CC_MDSS_AHB_CLK>,
+                               clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
                                         <&dispcc DISP_CC_MDSS_EDP_AUX_CLK>,
                                         <&dispcc DISP_CC_MDSS_EDP_LINK_CLK>,
                                         <&dispcc DISP_CC_MDSS_EDP_LINK_INTF_CLK>,
                                         <&dispcc DISP_CC_MDSS_EDP_PIXEL_CLK>;
-                               clock-names = "core_xo",
-                                             "core_ref",
-                                             "core_iface",
+                               clock-names = "core_iface",
                                              "core_aux",
                                              "ctrl_link",
                                              "ctrl_link_iface",
                                              "stream_pixel";
-                               #clock-cells = <1>;
                                assigned-clocks = <&dispcc DISP_CC_MDSS_EDP_LINK_CLK_SRC>,
                                                  <&dispcc DISP_CC_MDSS_EDP_PIXEL_CLK_SRC>;
                                assigned-clock-parents = <&mdss_edp_phy 0>, <&mdss_edp_phy 1>;
                                operating-points-v2 = <&edp_opp_table>;
                                power-domains = <&rpmhpd SC7280_CX>;
 
-                               #address-cells = <1>;
-                               #size-cells = <0>;
-
                                status = "disabled";
 
                                ports {
                        mdss_dp: displayport-controller@ae90000 {
                                compatible = "qcom,sc7280-dp";
 
-                               reg = <0 0x0ae90000 0 0x1400>;
+                               reg = <0 0xae90000 0 0x200>,
+                                     <0 0xae90200 0 0x200>,
+                                     <0 0xae90400 0 0xc00>,
+                                     <0 0xae91000 0 0x400>,
+                                     <0 0xae91400 0 0x400>;
 
                                interrupt-parent = <&mdss>;
                                interrupts = <12>;
                                         <&dispcc DISP_CC_MDSS_DP_LINK_CLK>,
                                         <&dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>,
                                         <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK>;
-                               clock-names =   "core_iface",
+                               clock-names = "core_iface",
                                                "core_aux",
                                                "ctrl_link",
                                                "ctrl_link_iface",
                                                "stream_pixel";
-                               #clock-cells = <1>;
                                assigned-clocks = <&dispcc DISP_CC_MDSS_DP_LINK_CLK_SRC>,
                                                  <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>;
                                assigned-clock-parents = <&dp_phy 0>, <&dp_phy 1>;
                };
 
                aoss_qmp: power-controller@c300000 {
-                       compatible = "qcom,sc7280-aoss-qmp";
+                       compatible = "qcom,sc7280-aoss-qmp", "qcom,aoss-qmp";
                        reg = <0 0x0c300000 0 0x400>;
                        interrupts-extended = <&ipcc IPCC_CLIENT_AOP
                                                     IPCC_MPROC_SIGNAL_GLINK_QMP
                                function = "edp_hot";
                        };
 
+                       mi2s0_data0: mi2s0-data0 {
+                               pins = "gpio98";
+                               function = "mi2s0_data0";
+                       };
+
+                       mi2s0_data1: mi2s0-data1 {
+                               pins = "gpio99";
+                               function = "mi2s0_data1";
+                       };
+
+                       mi2s0_mclk: mi2s0-mclk {
+                               pins = "gpio96";
+                               function = "pri_mi2s";
+                       };
+
+                       mi2s0_sclk: mi2s0-sclk {
+                               pins = "gpio97";
+                               function = "mi2s0_sck";
+                       };
+
+                       mi2s0_ws: mi2s0-ws {
+                               pins = "gpio100";
+                               function = "mi2s0_ws";
+                       };
+
+                       mi2s1_data0: mi2s1-data0 {
+                               pins = "gpio107";
+                               function = "mi2s1_data0";
+                       };
+
+                       mi2s1_sclk: mi2s1-sclk {
+                               pins = "gpio106";
+                               function = "mi2s1_sck";
+                       };
+
+                       mi2s1_ws: mi2s1-ws {
+                               pins = "gpio108";
+                               function = "mi2s1_ws";
+                       };
+
                        pcie1_clkreq_n: pcie1-clkreq-n {
                                pins = "gpio79";
                                function = "pcie1_clkreqn";
                        };
                };
 
-               imem@146a5000 {
-                       compatible = "qcom,sc7280-imem", "syscon";
+               sram@146a5000 {
+                       compatible = "qcom,sc7280-imem", "syscon", "simple-mfd";
                        reg = <0 0x146a5000 0 0x6000>;
 
                        #address-cells = <1>;
                };
 
                timer@17c20000 {
-                       #address-cells = <2>;
-                       #size-cells = <2>;
-                       ranges;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0 0 0 0x20000000>;
                        compatible = "arm,armv7-timer-mem";
                        reg = <0 0x17c20000 0 0x1000>;
 
                                frame-number = <0>;
                                interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0 0x17c21000 0 0x1000>,
-                                     <0 0x17c22000 0 0x1000>;
+                               reg = <0x17c21000 0x1000>,
+                                     <0x17c22000 0x1000>;
                        };
 
                        frame@17c23000 {
                                frame-number = <1>;
                                interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0 0x17c23000 0 0x1000>;
+                               reg = <0x17c23000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c25000 {
                                frame-number = <2>;
                                interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0 0x17c25000 0 0x1000>;
+                               reg = <0x17c25000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c27000 {
                                frame-number = <3>;
                                interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0 0x17c27000 0 0x1000>;
+                               reg = <0x17c27000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c29000 {
                                frame-number = <4>;
                                interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0 0x17c29000 0 0x1000>;
+                               reg = <0x17c29000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c2b000 {
                                frame-number = <5>;
                                interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0 0x17c2b000 0 0x1000>;
+                               reg = <0x17c2b000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c2d000 {
                                frame-number = <6>;
                                interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0 0x17c2d000 0 0x1000>;
+                               reg = <0x17c2d000 0x1000>;
                                status = "disabled";
                        };
                };
diff --git a/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts b/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts
new file mode 100644 (file)
index 0000000..45058ad
--- /dev/null
@@ -0,0 +1,427 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+
+#include "sc8280xp.dtsi"
+#include "sc8280xp-pmics.dtsi"
+
+/ {
+       model = "Qualcomm SC8280XP CRD";
+       compatible = "qcom,sc8280xp-crd", "qcom,sc8280xp";
+
+       aliases {
+               serial0 = &qup2_uart17;
+       };
+
+       backlight {
+               compatible = "pwm-backlight";
+               pwms = <&pmc8280c_lpg 3 1000000>;
+               enable-gpios = <&pmc8280_1_gpios 8 GPIO_ACTIVE_HIGH>;
+               power-supply = <&vreg_edp_bl>;
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&edp_bl_en>, <&edp_bl_pwm>;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       vreg_edp_bl: regulator-edp-bl {
+               compatible = "regulator-fixed";
+
+               regulator-name = "VREG_EDP_BL";
+               regulator-min-microvolt = <3600000>;
+               regulator-max-microvolt = <3600000>;
+
+               gpio = <&pmc8280_1_gpios 9 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&edp_bl_reg_en>;
+
+               regulator-boot-on;
+       };
+
+       vreg_misc_3p3: regulator-misc-3p3 {
+               compatible = "regulator-fixed";
+
+               regulator-name = "VREG_MISC_3P3";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+
+               gpio = <&pmc8280_1_gpios 1 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&misc_3p3_reg_en>;
+
+               regulator-boot-on;
+               regulator-always-on;
+       };
+};
+
+&apps_rsc {
+       pmc8280-1-rpmh-regulators {
+               compatible = "qcom,pm8350-rpmh-regulators";
+               qcom,pmic-id = "b";
+
+               vdd-l3-l5-supply = <&vreg_s11b>;
+
+               vreg_s11b: smps11 {
+                       regulator-name = "vreg_s11b";
+                       regulator-min-microvolt = <1272000>;
+                       regulator-max-microvolt = <1272000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l3b: ldo3 {
+                       regulator-name = "vreg_l3b";
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1200000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-boot-on;
+                       regulator-always-on;
+               };
+
+               vreg_l4b: ldo4 {
+                       regulator-name = "vreg_l4b";
+                       regulator-min-microvolt = <912000>;
+                       regulator-max-microvolt = <912000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l6b: ldo6 {
+                       regulator-name = "vreg_l6b";
+                       regulator-min-microvolt = <880000>;
+                       regulator-max-microvolt = <880000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-boot-on;
+               };
+       };
+
+       pmc8280c-rpmh-regulators {
+               compatible = "qcom,pm8350c-rpmh-regulators";
+               qcom,pmic-id = "c";
+
+               vreg_l1c: ldo1 {
+                       regulator-name = "vreg_l1c";
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l7c: ldo7 {
+                       regulator-name = "vreg_l7c";
+                       regulator-min-microvolt = <2504000>;
+                       regulator-max-microvolt = <2504000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l13c: ldo13 {
+                       regulator-name = "vreg_l13c";
+                       regulator-min-microvolt = <3072000>;
+                       regulator-max-microvolt = <3072000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+       };
+
+       pmc8280-2-rpmh-regulators {
+               compatible = "qcom,pm8350-rpmh-regulators";
+               qcom,pmic-id = "d";
+
+               vdd-l1-l4-supply = <&vreg_s11b>;
+
+               vreg_l3d: ldo3 {
+                       regulator-name = "vreg_l3d";
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1200000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l4d: ldo4 {
+                       regulator-name = "vreg_l4d";
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1200000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l6d: ldo6 {
+                       regulator-name = "vreg_l6d";
+                       regulator-min-microvolt = <880000>;
+                       regulator-max-microvolt = <880000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l7d: ldo7 {
+                       regulator-name = "vreg_l7d";
+                       regulator-min-microvolt = <3072000>;
+                       regulator-max-microvolt = <3072000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l9d: ldo9 {
+                       regulator-name = "vreg_l9d";
+                       regulator-min-microvolt = <912000>;
+                       regulator-max-microvolt = <912000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+       };
+};
+
+&pmc8280c_lpg {
+       status = "okay";
+};
+
+&pmk8280_pon_pwrkey {
+       status = "okay";
+};
+
+&qup0 {
+       status = "okay";
+};
+
+&qup0_i2c4 {
+       clock-frequency = <400000>;
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&qup0_i2c4_default>, <&ts0_default>;
+
+       status = "okay";
+
+       touchscreen@10 {
+               compatible = "hid-over-i2c";
+               reg = <0x10>;
+               hid-descr-addr = <0x1>;
+               interrupts-extended = <&tlmm 175 IRQ_TYPE_LEVEL_LOW>;
+               vdd-supply = <&vreg_misc_3p3>;
+       };
+};
+
+&qup1 {
+       status = "okay";
+};
+
+&qup2 {
+       status = "okay";
+};
+
+&qup2_i2c5 {
+       clock-frequency = <400000>;
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&qup2_i2c5_default>, <&kybd_default>, <&tpad_default>;
+
+       status = "okay";
+
+       touchpad@15 {
+               compatible = "hid-over-i2c";
+               reg = <0x15>;
+               hid-descr-addr = <0x1>;
+               interrupts-extended = <&tlmm 182 IRQ_TYPE_LEVEL_LOW>;
+               vdd-supply = <&vreg_misc_3p3>;
+       };
+
+       keyboard@68 {
+               compatible = "hid-over-i2c";
+               reg = <0x68>;
+               hid-descr-addr = <0x1>;
+               interrupts-extended = <&tlmm 104 IRQ_TYPE_LEVEL_LOW>;
+               vdd-supply = <&vreg_misc_3p3>;
+       };
+};
+
+&qup2_uart17 {
+       compatible = "qcom,geni-debug-uart";
+
+       status = "okay";
+};
+
+&remoteproc_adsp {
+       firmware-name = "qcom/sc8280xp/qcadsp8280.mbn";
+
+       status = "okay";
+};
+
+&remoteproc_nsp0 {
+       firmware-name = "qcom/sc8280xp/qccdsp8280.mbn";
+
+       status = "okay";
+};
+
+&ufs_mem_hc {
+       reset-gpios = <&tlmm 228 GPIO_ACTIVE_LOW>;
+
+       vcc-supply = <&vreg_l7c>;
+       vcc-max-microamp = <800000>;
+       vccq-supply = <&vreg_l3d>;
+       vccq-max-microamp = <900000>;
+
+       status = "okay";
+};
+
+&ufs_mem_phy {
+       vdda-phy-supply = <&vreg_l6b>;
+       vdda-pll-supply = <&vreg_l3b>;
+
+       status = "okay";
+};
+
+&usb_0 {
+       status = "okay";
+};
+
+&usb_0_dwc3 {
+       /* TODO: Define USB-C connector properly */
+       dr_mode = "host";
+};
+
+&usb_0_hsphy {
+       vdda-pll-supply = <&vreg_l9d>;
+       vdda18-supply = <&vreg_l1c>;
+       vdda33-supply = <&vreg_l7d>;
+
+       status = "okay";
+};
+
+&usb_0_qmpphy {
+       vdda-phy-supply = <&vreg_l9d>;
+       vdda-pll-supply = <&vreg_l4d>;
+
+       status = "okay";
+};
+
+&usb_1 {
+       status = "okay";
+};
+
+&usb_1_dwc3 {
+       /* TODO: Define USB-C connector properly */
+       dr_mode = "host";
+};
+
+&usb_1_hsphy {
+       vdda-pll-supply = <&vreg_l4b>;
+       vdda18-supply = <&vreg_l1c>;
+       vdda33-supply = <&vreg_l13c>;
+
+       status = "okay";
+};
+
+&usb_1_qmpphy {
+       vdda-phy-supply = <&vreg_l4b>;
+       vdda-pll-supply = <&vreg_l3b>;
+
+       status = "okay";
+};
+
+&xo_board_clk {
+       clock-frequency = <38400000>;
+};
+
+/* PINCTRL - additions to nodes defined in sc8280xp.dtsi */
+
+&pmc8280_1_gpios {
+       edp_bl_en: edp-bl-en-state {
+               pins = "gpio8";
+               function = "normal";
+       };
+
+       edp_bl_reg_en: edp-bl-reg-en-state {
+               pins = "gpio9";
+               function = "normal";
+       };
+
+       misc_3p3_reg_en: misc-3p3-reg-en-state {
+               pins = "gpio1";
+               function = "normal";
+       };
+};
+
+&pmc8280c_gpios {
+       edp_bl_pwm: edp-bl-pwm-state {
+               pins = "gpio8";
+               function = "func1";
+       };
+};
+
+&tlmm {
+       gpio-reserved-ranges = <74 6>, <83 4>, <125 2>, <128 2>, <154 7>;
+
+       kybd_default: kybd-default-state {
+               disable {
+                       pins = "gpio102";
+                       function = "gpio";
+                       output-low;
+               };
+
+               int-n {
+                       pins = "gpio104";
+                       function = "gpio";
+                       bias-disable;
+               };
+
+               reset {
+                       pins = "gpio105";
+                       function = "gpio";
+                       bias-disable;
+               };
+       };
+
+       qup0_i2c4_default: qup0-i2c4-default-state {
+               pins = "gpio171", "gpio172";
+               function = "qup4";
+
+               bias-disable;
+               drive-strength = <16>;
+       };
+
+       qup2_i2c5_default: qup2-i2c5-default-state {
+               pins = "gpio81", "gpio82";
+               function = "qup21";
+
+               bias-disable;
+               drive-strength = <16>;
+       };
+
+       tpad_default: tpad-default-state {
+               int-n {
+                       pins = "gpio182";
+                       function = "gpio";
+                       bias-disable;
+               };
+       };
+
+       ts0_default: ts0-default-state {
+               int-n {
+                       pins = "gpio175";
+                       function = "gpio";
+                       bias-pull-up;
+               };
+
+               reset-n {
+                       pins = "gpio99";
+                       function = "gpio";
+                       output-high;
+                       drive-strength = <16>;
+               };
+       };
+};
diff --git a/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts b/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts
new file mode 100644 (file)
index 0000000..84dc92d
--- /dev/null
@@ -0,0 +1,386 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+
+#include "sc8280xp.dtsi"
+#include "sc8280xp-pmics.dtsi"
+
+/ {
+       model = "Lenovo ThinkPad X13s";
+       compatible = "lenovo,thinkpad-x13s", "qcom,sc8280xp";
+
+       backlight {
+               compatible = "pwm-backlight";
+               pwms = <&pmc8280c_lpg 3 1000000>;
+               enable-gpios = <&pmc8280_1_gpios 8 GPIO_ACTIVE_HIGH>;
+               power-supply = <&vreg_edp_bl>;
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&edp_bl_en>, <&edp_bl_pwm>;
+       };
+
+       vreg_edp_bl: regulator-edp-bl {
+               compatible = "regulator-fixed";
+
+               regulator-name = "VBL9";
+               regulator-min-microvolt = <3600000>;
+               regulator-max-microvolt = <3600000>;
+
+               gpio = <&pmc8280_1_gpios 9 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&edp_bl_reg_en>;
+
+               regulator-boot-on;
+       };
+
+       vreg_misc_3p3: regulator-misc-3p3 {
+               compatible = "regulator-fixed";
+
+               regulator-name = "VCC3B";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+
+               gpio = <&pmc8280_1_gpios 1 GPIO_ACTIVE_HIGH>;
+               enable-active-high;
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&misc_3p3_reg_en>;
+
+               regulator-boot-on;
+               regulator-always-on;
+       };
+};
+
+&apps_rsc {
+       pmc8280-1-rpmh-regulators {
+               compatible = "qcom,pm8350-rpmh-regulators";
+               qcom,pmic-id = "b";
+
+               vdd-l3-l5-supply = <&vreg_s11b>;
+
+               vreg_s11b: smps11 {
+                       regulator-name = "vreg_s11b";
+                       regulator-min-microvolt = <1272000>;
+                       regulator-max-microvolt = <1272000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l3b: ldo3 {
+                       regulator-name = "vreg_l3b";
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1200000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-boot-on;
+               };
+
+               vreg_l4b: ldo4 {
+                       regulator-name = "vreg_l4b";
+                       regulator-min-microvolt = <912000>;
+                       regulator-max-microvolt = <912000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l6b: ldo6 {
+                       regulator-name = "vreg_l6b";
+                       regulator-min-microvolt = <880000>;
+                       regulator-max-microvolt = <880000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+                       regulator-boot-on;
+                       regulator-always-on;    // FIXME: VDD_A_EDP_0_0P9
+               };
+       };
+
+       pmc8280c-rpmh-regulators {
+               compatible = "qcom,pm8350c-rpmh-regulators";
+               qcom,pmic-id = "c";
+
+               vreg_l1c: ldo1 {
+                       regulator-name = "vreg_l1c";
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l12c: ldo12 {
+                       regulator-name = "vreg_l12c";
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l13c: ldo13 {
+                       regulator-name = "vreg_l13c";
+                       regulator-min-microvolt = <3072000>;
+                       regulator-max-microvolt = <3072000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+       };
+
+       pmc8280-2-rpmh-regulators {
+               compatible = "qcom,pm8350-rpmh-regulators";
+               qcom,pmic-id = "d";
+
+               vdd-l1-l4-supply = <&vreg_s11b>;
+
+               vreg_l3d: ldo3 {
+                       regulator-name = "vreg_l3d";
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1200000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l4d: ldo4 {
+                       regulator-name = "vreg_l4d";
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1200000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l7d: ldo7 {
+                       regulator-name = "vreg_l7d";
+                       regulator-min-microvolt = <3072000>;
+                       regulator-max-microvolt = <3072000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l9d: ldo9 {
+                       regulator-name = "vreg_l9d";
+                       regulator-min-microvolt = <912000>;
+                       regulator-max-microvolt = <912000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-allow-set-load;
+               };
+       };
+};
+
+&pmc8280c_lpg {
+       status = "okay";
+};
+
+&pmk8280_pon_pwrkey {
+       status = "okay";
+};
+
+&qup0 {
+       status = "okay";
+};
+
+&qup0_i2c4 {
+       clock-frequency = <400000>;
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&qup0_i2c4_default>, <&ts0_default>;
+
+       status = "okay";
+
+       /* FIXME: verify */
+       touchscreen@10 {
+               compatible = "hid-over-i2c";
+               reg = <0x10>;
+               hid-descr-addr = <0x1>;
+               interrupts-extended = <&tlmm 175 IRQ_TYPE_LEVEL_LOW>;
+               vdd-supply = <&vreg_misc_3p3>;
+       };
+};
+
+&qup1 {
+       status = "okay";
+};
+
+&qup2 {
+       status = "okay";
+};
+
+&qup2_i2c5 {
+       clock-frequency = <400000>;
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&qup2_i2c5_default>, <&kybd_default>, <&tpad_default>;
+
+       status = "okay";
+
+       touchpad@2c {
+               compatible = "hid-over-i2c";
+               reg = <0x2c>;
+               hid-descr-addr = <0x20>;
+               interrupts-extended = <&tlmm 182 IRQ_TYPE_LEVEL_LOW>;
+               vdd-supply = <&vreg_misc_3p3>;
+       };
+
+       keyboard@68 {
+               compatible = "hid-over-i2c";
+               reg = <0x68>;
+               hid-descr-addr = <0x1>;
+               interrupts-extended = <&tlmm 104 IRQ_TYPE_LEVEL_LOW>;
+               vdd-supply = <&vreg_misc_3p3>;
+       };
+};
+
+&remoteproc_adsp {
+       firmware-name = "qcom/sc8280xp/qcadsp8280.mbn";
+
+       status = "okay";
+};
+
+&remoteproc_nsp0 {
+       firmware-name = "qcom/sc8280xp/qccdsp8280.mbn";
+
+       status = "okay";
+};
+
+&usb_0 {
+       status = "okay";
+};
+
+&usb_0_dwc3 {
+       /* TODO: Define USB-C connector properly */
+       dr_mode = "host";
+};
+
+&usb_0_hsphy {
+       vdda-pll-supply = <&vreg_l9d>;
+       vdda18-supply = <&vreg_l1c>;
+       vdda33-supply = <&vreg_l7d>;
+
+       status = "okay";
+};
+
+&usb_0_qmpphy {
+       vdda-phy-supply = <&vreg_l9d>;
+       vdda-pll-supply = <&vreg_l4d>;
+
+       status = "okay";
+};
+
+&usb_1 {
+       status = "okay";
+};
+
+&usb_1_dwc3 {
+       /* TODO: Define USB-C connector properly */
+       dr_mode = "host";
+};
+
+&usb_1_hsphy {
+       vdda-pll-supply = <&vreg_l4b>;
+       vdda18-supply = <&vreg_l1c>;
+       vdda33-supply = <&vreg_l13c>;
+
+       status = "okay";
+};
+
+&usb_1_qmpphy {
+       vdda-phy-supply = <&vreg_l4b>;
+       vdda-pll-supply = <&vreg_l3b>;
+
+       status = "okay";
+};
+
+&xo_board_clk {
+       clock-frequency = <38400000>;
+};
+
+/* PINCTRL */
+
+&pmc8280_1_gpios {
+       edp_bl_en: edp-bl-en-state {
+               pins = "gpio8";
+               function = "normal";
+       };
+
+       edp_bl_reg_en: edp-bl-reg-en-state {
+               pins = "gpio9";
+               function = "normal";
+       };
+
+       misc_3p3_reg_en: misc-3p3-reg-en-state {
+               pins = "gpio1";
+               function = "normal";
+       };
+};
+
+&pmc8280c_gpios {
+       edp_bl_pwm: edp-bl-pwm-state {
+               pins = "gpio8";
+               function = "func1";
+       };
+};
+
+&tlmm {
+       gpio-reserved-ranges = <70 2>, <74 6>, <83 4>, <125 2>, <128 2>, <154 7>;
+
+       kybd_default: kybd-default-state {
+               disable {
+                       pins = "gpio102";
+                       function = "gpio";
+                       output-low;
+               };
+
+               int-n {
+                       pins = "gpio104";
+                       function = "gpio";
+                       bias-disable;
+               };
+
+               reset {
+                       pins = "gpio105";
+                       function = "gpio";
+                       bias-disable;
+               };
+       };
+
+       qup0_i2c4_default: qup0-i2c4-default-state {
+               pins = "gpio171", "gpio172";
+               function = "qup4";
+               bias-disable;
+               drive-strength = <16>;
+       };
+
+       qup2_i2c5_default: qup2-i2c5-default-state {
+               pins = "gpio81", "gpio82";
+               function = "qup21";
+               bias-disable;
+               drive-strength = <16>;
+       };
+
+       tpad_default: tpad-default-state {
+               int-n {
+                       pins = "gpio182";
+                       function = "gpio";
+                       bias-disable;
+               };
+       };
+
+       ts0_default: ts0-default-state {
+               int-n {
+                       pins = "gpio175";
+                       function = "gpio";
+                       bias-pull-up;
+               };
+
+               reset-n {
+                       pins = "gpio99";
+                       function = "gpio";
+                       output-high;
+                       drive-strength = <16>;
+               };
+       };
+};
diff --git a/arch/arm64/boot/dts/qcom/sc8280xp-pmics.dtsi b/arch/arm64/boot/dts/qcom/sc8280xp-pmics.dtsi
new file mode 100644 (file)
index 0000000..ae90b97
--- /dev/null
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/spmi/spmi.h>
+
+&spmi_bus {
+       pmk8280: pmic@0 {
+               compatible = "qcom,pmk8350", "qcom,spmi-pmic";
+               reg = <0x0 SPMI_USID>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               pmk8280_pon: pon@1300 {
+                       compatible = "qcom,pm8998-pon";
+                       reg = <0x1300>;
+
+                       pmk8280_pon_pwrkey: pwrkey {
+                               compatible = "qcom,pmk8350-pwrkey";
+                               interrupts = <0x0 0x13 0x7 IRQ_TYPE_EDGE_BOTH>;
+                               linux,code = <KEY_POWER>;
+                               status = "disabled";
+                       };
+               };
+       };
+
+       pmc8280_1: pmic@1 {
+               compatible = "qcom,pm8350", "qcom,spmi-pmic";
+               reg = <0x1 SPMI_USID>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               pmc8280_1_gpios: gpio@8800 {
+                       compatible = "qcom,pm8350-gpio", "qcom,spmi-gpio";
+                       reg = <0x8800>;
+                       gpio-controller;
+                       gpio-ranges = <&pmc8280_1_gpios 0 0 10>;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+       };
+
+       pmc8280c: pmic@2 {
+               compatible = "qcom,pm8350c", "qcom,spmi-pmic";
+               reg = <0x2 SPMI_USID>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               pmc8280c_gpios: gpio@8800 {
+                       compatible = "qcom,pm8350c-gpio", "qcom,spmi-gpio";
+                       reg = <0x8800>;
+                       gpio-controller;
+                       gpio-ranges = <&pmc8280c_gpios 0 0 9>;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               pmc8280c_lpg: lpg@e800 {
+                       compatible = "qcom,pm8350c-pwm";
+                       reg = <0xe800>;
+
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       #pwm-cells = <2>;
+
+                       status = "disabled";
+               };
+       };
+
+       pmc8280_2: pmic@3 {
+               compatible = "qcom,pm8350", "qcom,spmi-pmic";
+               reg = <0x3 SPMI_USID>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               pmc8280_2_gpios: gpio@8800 {
+                       compatible = "qcom,pm8350-gpio", "qcom,spmi-gpio";
+                       reg = <0x8800>;
+                       gpio-controller;
+                       gpio-ranges = <&pmc8280_2_gpios 0 0 10>;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+       };
+
+       pmr735a: pmic@4 {
+               compatible = "qcom,pmr735a", "qcom,spmi-pmic";
+               reg = <0x4 SPMI_USID>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               pmr735a_gpios: gpio@8800 {
+                       compatible = "qcom,pmr735a-gpio", "qcom,spmi-gpio";
+                       reg = <0x8800>;
+                       gpio-controller;
+                       gpio-ranges = <&pmr735a_gpios 0 0 4>;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+       };
+};
diff --git a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi
new file mode 100644 (file)
index 0000000..49ea8b5
--- /dev/null
@@ -0,0 +1,2147 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+#include <dt-bindings/clock/qcom,gcc-sc8280xp.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interconnect/qcom,sc8280xp.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/mailbox/qcom-ipcc.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>;
+
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       clocks {
+               xo_board_clk: xo-board-clk {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+               };
+
+               sleep_clk: sleep-clk {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <32764>;
+               };
+       };
+
+       cpu0_opp_table: cpu0-opp-table {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp-300000000 {
+                       opp-hz = /bits/ 64 <300000000>;
+               };
+               opp-403200000 {
+                       opp-hz = /bits/ 64 <403200000>;
+               };
+               opp-499200000 {
+                       opp-hz = /bits/ 64 <499200000>;
+               };
+               opp-595200000 {
+                       opp-hz = /bits/ 64 <595200000>;
+               };
+               opp-691200000 {
+                       opp-hz = /bits/ 64 <691200000>;
+               };
+               opp-806400000 {
+                       opp-hz = /bits/ 64 <806400000>;
+               };
+               opp-902400000 {
+                       opp-hz = /bits/ 64 <902400000>;
+               };
+               opp-1017600000 {
+                       opp-hz = /bits/ 64 <1017600000>;
+               };
+               opp-1113600000 {
+                       opp-hz = /bits/ 64 <1113600000>;
+               };
+               opp-1209600000 {
+                       opp-hz = /bits/ 64 <1209600000>;
+               };
+               opp-1324800000 {
+                       opp-hz = /bits/ 64 <1324800000>;
+               };
+               opp-1440000000 {
+                       opp-hz = /bits/ 64 <1440000000>;
+               };
+               opp-1555200000 {
+                       opp-hz = /bits/ 64 <1555200000>;
+               };
+               opp-1670400000 {
+                       opp-hz = /bits/ 64 <1670400000>;
+               };
+               opp-1785600000 {
+                       opp-hz = /bits/ 64 <1785600000>;
+               };
+               opp-1881600000 {
+                       opp-hz = /bits/ 64 <1881600000>;
+               };
+               opp-1996800000 {
+                       opp-hz = /bits/ 64 <1996800000>;
+               };
+               opp-2112000000 {
+                       opp-hz = /bits/ 64 <2112000000>;
+               };
+               opp-2227200000 {
+                       opp-hz = /bits/ 64 <2227200000>;
+               };
+               opp-2342400000 {
+                       opp-hz = /bits/ 64 <2342400000>;
+               };
+               opp-2438400000 {
+                       opp-hz = /bits/ 64 <2438400000>;
+               };
+       };
+
+       cpu4_opp_table: cpu4-opp-table {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp-825600000 {
+                       opp-hz = /bits/ 64 <825600000>;
+               };
+               opp-940800000 {
+                       opp-hz = /bits/ 64 <940800000>;
+               };
+               opp-1056000000 {
+                       opp-hz = /bits/ 64 <1056000000>;
+               };
+               opp-1171200000 {
+                       opp-hz = /bits/ 64 <1171200000>;
+               };
+               opp-1286400000 {
+                       opp-hz = /bits/ 64 <1286400000>;
+               };
+               opp-1401600000 {
+                       opp-hz = /bits/ 64 <1401600000>;
+               };
+               opp-1516800000 {
+                       opp-hz = /bits/ 64 <1516800000>;
+               };
+               opp-1632000000 {
+                       opp-hz = /bits/ 64 <1632000000>;
+               };
+               opp-1747200000 {
+                       opp-hz = /bits/ 64 <1747200000>;
+               };
+               opp-1862400000 {
+                       opp-hz = /bits/ 64 <1862400000>;
+               };
+               opp-1977600000 {
+                       opp-hz = /bits/ 64 <1977600000>;
+               };
+               opp-2073600000 {
+                       opp-hz = /bits/ 64 <2073600000>;
+               };
+               opp-2169600000 {
+                       opp-hz = /bits/ 64 <2169600000>;
+               };
+               opp-2284800000 {
+                       opp-hz = /bits/ 64 <2284800000>;
+               };
+               opp-2400000000 {
+                       opp-hz = /bits/ 64 <2400000000>;
+               };
+               opp-2496000000 {
+                       opp-hz = /bits/ 64 <2496000000>;
+               };
+               opp-2592000000 {
+                       opp-hz = /bits/ 64 <2592000000>;
+               };
+               opp-2688000000 {
+                       opp-hz = /bits/ 64 <2688000000>;
+               };
+               opp-2803200000 {
+                       opp-hz = /bits/ 64 <2803200000>;
+               };
+               opp-2899200000 {
+                       opp-hz = /bits/ 64 <2899200000>;
+               };
+               opp-2995200000 {
+                       opp-hz = /bits/ 64 <2995200000>;
+               };
+       };
+
+       cpus {
+               #address-cells = <2>;
+               #size-cells = <0>;
+
+               CPU0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "qcom,kryo";
+                       reg = <0x0 0x0>;
+                       enable-method = "psci";
+                       capacity-dmips-mhz = <602>;
+                       next-level-cache = <&L2_0>;
+                       power-domains = <&CPU_PD0>;
+                       power-domain-names = "psci";
+                       qcom,freq-domain = <&cpufreq_hw 0>;
+                       operating-points-v2 = <&cpu0_opp_table>;
+                       #cooling-cells = <2>;
+                       L2_0: l2-cache {
+                               compatible = "cache";
+                               next-level-cache = <&L3_0>;
+                               L3_0: l3-cache {
+                                     compatible = "cache";
+                               };
+                       };
+               };
+
+               CPU1: cpu@100 {
+                       device_type = "cpu";
+                       compatible = "qcom,kryo";
+                       reg = <0x0 0x100>;
+                       enable-method = "psci";
+                       capacity-dmips-mhz = <602>;
+                       next-level-cache = <&L2_100>;
+                       power-domains = <&CPU_PD1>;
+                       power-domain-names = "psci";
+                       qcom,freq-domain = <&cpufreq_hw 0>;
+                       operating-points-v2 = <&cpu0_opp_table>;
+                       #cooling-cells = <2>;
+                       L2_100: l2-cache {
+                               compatible = "cache";
+                               next-level-cache = <&L3_0>;
+                       };
+               };
+
+               CPU2: cpu@200 {
+                       device_type = "cpu";
+                       compatible = "qcom,kryo";
+                       reg = <0x0 0x200>;
+                       enable-method = "psci";
+                       capacity-dmips-mhz = <602>;
+                       next-level-cache = <&L2_200>;
+                       power-domains = <&CPU_PD2>;
+                       power-domain-names = "psci";
+                       qcom,freq-domain = <&cpufreq_hw 0>;
+                       operating-points-v2 = <&cpu0_opp_table>;
+                       #cooling-cells = <2>;
+                       L2_200: l2-cache {
+                               compatible = "cache";
+                               next-level-cache = <&L3_0>;
+                       };
+               };
+
+               CPU3: cpu@300 {
+                       device_type = "cpu";
+                       compatible = "qcom,kryo";
+                       reg = <0x0 0x300>;
+                       enable-method = "psci";
+                       capacity-dmips-mhz = <602>;
+                       next-level-cache = <&L2_300>;
+                       power-domains = <&CPU_PD3>;
+                       power-domain-names = "psci";
+                       qcom,freq-domain = <&cpufreq_hw 0>;
+                       operating-points-v2 = <&cpu0_opp_table>;
+                       #cooling-cells = <2>;
+                       L2_300: l2-cache {
+                               compatible = "cache";
+                               next-level-cache = <&L3_0>;
+                       };
+               };
+
+               CPU4: cpu@400 {
+                       device_type = "cpu";
+                       compatible = "qcom,kryo";
+                       reg = <0x0 0x400>;
+                       enable-method = "psci";
+                       capacity-dmips-mhz = <1024>;
+                       next-level-cache = <&L2_400>;
+                       power-domains = <&CPU_PD4>;
+                       power-domain-names = "psci";
+                       qcom,freq-domain = <&cpufreq_hw 1>;
+                       operating-points-v2 = <&cpu4_opp_table>;
+                       #cooling-cells = <2>;
+                       L2_400: l2-cache {
+                               compatible = "cache";
+                               next-level-cache = <&L3_0>;
+                       };
+               };
+
+               CPU5: cpu@500 {
+                       device_type = "cpu";
+                       compatible = "qcom,kryo";
+                       reg = <0x0 0x500>;
+                       enable-method = "psci";
+                       capacity-dmips-mhz = <1024>;
+                       next-level-cache = <&L2_500>;
+                       power-domains = <&CPU_PD5>;
+                       power-domain-names = "psci";
+                       qcom,freq-domain = <&cpufreq_hw 1>;
+                       operating-points-v2 = <&cpu4_opp_table>;
+                       #cooling-cells = <2>;
+                       L2_500: l2-cache {
+                               compatible = "cache";
+                               next-level-cache = <&L3_0>;
+                       };
+               };
+
+               CPU6: cpu@600 {
+                       device_type = "cpu";
+                       compatible = "qcom,kryo";
+                       reg = <0x0 0x600>;
+                       enable-method = "psci";
+                       capacity-dmips-mhz = <1024>;
+                       next-level-cache = <&L2_600>;
+                       power-domains = <&CPU_PD6>;
+                       power-domain-names = "psci";
+                       qcom,freq-domain = <&cpufreq_hw 1>;
+                       operating-points-v2 = <&cpu4_opp_table>;
+                       #cooling-cells = <2>;
+                       L2_600: l2-cache {
+                               compatible = "cache";
+                               next-level-cache = <&L3_0>;
+                       };
+               };
+
+               CPU7: cpu@700 {
+                       device_type = "cpu";
+                       compatible = "qcom,kryo";
+                       reg = <0x0 0x700>;
+                       enable-method = "psci";
+                       capacity-dmips-mhz = <1024>;
+                       next-level-cache = <&L2_700>;
+                       power-domains = <&CPU_PD7>;
+                       power-domain-names = "psci";
+                       qcom,freq-domain = <&cpufreq_hw 1>;
+                       operating-points-v2 = <&cpu4_opp_table>;
+                       #cooling-cells = <2>;
+                       L2_700: l2-cache {
+                               compatible = "cache";
+                               next-level-cache = <&L3_0>;
+                       };
+               };
+
+               cpu-map {
+                       cluster0 {
+                               core0 {
+                                       cpu = <&CPU0>;
+                               };
+
+                               core1 {
+                                       cpu = <&CPU1>;
+                               };
+
+                               core2 {
+                                       cpu = <&CPU2>;
+                               };
+
+                               core3 {
+                                       cpu = <&CPU3>;
+                               };
+
+                               core4 {
+                                       cpu = <&CPU4>;
+                               };
+
+                               core5 {
+                                       cpu = <&CPU5>;
+                               };
+
+                               core6 {
+                                       cpu = <&CPU6>;
+                               };
+
+                               core7 {
+                                       cpu = <&CPU7>;
+                               };
+                       };
+               };
+
+               idle-states {
+                       entry-method = "psci";
+
+                       LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 {
+                               compatible = "arm,idle-state";
+                               idle-state-name = "little-rail-power-collapse";
+                               arm,psci-suspend-param = <0x40000004>;
+                               entry-latency-us = <355>;
+                               exit-latency-us = <909>;
+                               min-residency-us = <3934>;
+                               local-timer-stop;
+                       };
+
+                       BIG_CPU_SLEEP_0: cpu-sleep-1-0 {
+                               compatible = "arm,idle-state";
+                               idle-state-name = "big-rail-power-collapse";
+                               arm,psci-suspend-param = <0x40000004>;
+                               entry-latency-us = <241>;
+                               exit-latency-us = <1461>;
+                               min-residency-us = <4488>;
+                               local-timer-stop;
+                       };
+               };
+
+               domain-idle-states {
+                       CLUSTER_SLEEP_0: cluster-sleep-0 {
+                               compatible = "domain-idle-state";
+                               idle-state-name = "cluster-power-collapse";
+                               arm,psci-suspend-param = <0x4100c344>;
+                               entry-latency-us = <3263>;
+                               exit-latency-us = <6562>;
+                               min-residency-us = <9987>;
+                       };
+               };
+       };
+
+       firmware {
+               scm: scm {
+                       compatible = "qcom,scm-sc8280xp", "qcom,scm";
+               };
+       };
+
+       aggre1_noc: interconnect-aggre1-noc {
+               compatible = "qcom,sc8280xp-aggre1-noc";
+               #interconnect-cells = <2>;
+               qcom,bcm-voters = <&apps_bcm_voter>;
+       };
+
+       aggre2_noc: interconnect-aggre2-noc {
+               compatible = "qcom,sc8280xp-aggre2-noc";
+               #interconnect-cells = <2>;
+               qcom,bcm-voters = <&apps_bcm_voter>;
+       };
+
+       clk_virt: interconnect-clk-virt {
+               compatible = "qcom,sc8280xp-clk-virt";
+               #interconnect-cells = <2>;
+               qcom,bcm-voters = <&apps_bcm_voter>;
+       };
+
+       config_noc: interconnect-config-noc {
+               compatible = "qcom,sc8280xp-config-noc";
+               #interconnect-cells = <2>;
+               qcom,bcm-voters = <&apps_bcm_voter>;
+       };
+
+       dc_noc: interconnect-dc-noc {
+               compatible = "qcom,sc8280xp-dc-noc";
+               #interconnect-cells = <2>;
+               qcom,bcm-voters = <&apps_bcm_voter>;
+       };
+
+       gem_noc: interconnect-gem-noc {
+               compatible = "qcom,sc8280xp-gem-noc";
+               #interconnect-cells = <2>;
+               qcom,bcm-voters = <&apps_bcm_voter>;
+       };
+
+       lpass_noc: interconnect-lpass-ag-noc {
+               compatible = "qcom,sc8280xp-lpass-ag-noc";
+               #interconnect-cells = <2>;
+               qcom,bcm-voters = <&apps_bcm_voter>;
+       };
+
+       mc_virt: interconnect-mc-virt {
+               compatible = "qcom,sc8280xp-mc-virt";
+               #interconnect-cells = <2>;
+               qcom,bcm-voters = <&apps_bcm_voter>;
+       };
+
+       mmss_noc: interconnect-mmss-noc {
+               compatible = "qcom,sc8280xp-mmss-noc";
+               #interconnect-cells = <2>;
+               qcom,bcm-voters = <&apps_bcm_voter>;
+       };
+
+       nspa_noc: interconnect-nspa-noc {
+               compatible = "qcom,sc8280xp-nspa-noc";
+               #interconnect-cells = <2>;
+               qcom,bcm-voters = <&apps_bcm_voter>;
+       };
+
+       nspb_noc: interconnect-nspb-noc {
+               compatible = "qcom,sc8280xp-nspb-noc";
+               #interconnect-cells = <2>;
+               qcom,bcm-voters = <&apps_bcm_voter>;
+       };
+
+       system_noc: interconnect-system-noc {
+               compatible = "qcom,sc8280xp-system-noc";
+               #interconnect-cells = <2>;
+               qcom,bcm-voters = <&apps_bcm_voter>;
+       };
+
+       memory@80000000 {
+               device_type = "memory";
+               /* We expect the bootloader to fill in the size */
+               reg = <0x0 0x80000000 0x0 0x0>;
+       };
+
+       pmu {
+               compatible = "arm,armv8-pmuv3";
+               interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH>;
+       };
+
+       psci {
+               compatible = "arm,psci-1.0";
+               method = "smc";
+
+               CPU_PD0: cpu0 {
+                       #power-domain-cells = <0>;
+                       power-domains = <&CLUSTER_PD>;
+                       domain-idle-states = <&LITTLE_CPU_SLEEP_0>;
+               };
+
+               CPU_PD1: cpu1 {
+                       #power-domain-cells = <0>;
+                       power-domains = <&CLUSTER_PD>;
+                       domain-idle-states = <&LITTLE_CPU_SLEEP_0>;
+               };
+
+               CPU_PD2: cpu2 {
+                       #power-domain-cells = <0>;
+                       power-domains = <&CLUSTER_PD>;
+                       domain-idle-states = <&LITTLE_CPU_SLEEP_0>;
+               };
+
+               CPU_PD3: cpu3 {
+                       #power-domain-cells = <0>;
+                       power-domains = <&CLUSTER_PD>;
+                       domain-idle-states = <&LITTLE_CPU_SLEEP_0>;
+               };
+
+               CPU_PD4: cpu4 {
+                       #power-domain-cells = <0>;
+                       power-domains = <&CLUSTER_PD>;
+                       domain-idle-states = <&BIG_CPU_SLEEP_0>;
+               };
+
+               CPU_PD5: cpu5 {
+                       #power-domain-cells = <0>;
+                       power-domains = <&CLUSTER_PD>;
+                       domain-idle-states = <&BIG_CPU_SLEEP_0>;
+               };
+
+               CPU_PD6: cpu6 {
+                       #power-domain-cells = <0>;
+                       power-domains = <&CLUSTER_PD>;
+                       domain-idle-states = <&BIG_CPU_SLEEP_0>;
+               };
+
+               CPU_PD7: cpu7 {
+                       #power-domain-cells = <0>;
+                       power-domains = <&CLUSTER_PD>;
+                       domain-idle-states = <&BIG_CPU_SLEEP_0>;
+               };
+
+               CLUSTER_PD: cpu-cluster0 {
+                       #power-domain-cells = <0>;
+                       domain-idle-states = <&CLUSTER_SLEEP_0>;
+               };
+       };
+
+       qup_opp_table_100mhz: qup-100mhz-opp-table {
+               compatible = "operating-points-v2";
+
+               opp-75000000 {
+                       opp-hz = /bits/ 64 <75000000>;
+                       required-opps = <&rpmhpd_opp_low_svs>;
+               };
+
+               opp-100000000 {
+                       opp-hz = /bits/ 64 <100000000>;
+                       required-opps = <&rpmhpd_opp_svs>;
+               };
+       };
+
+       reserved-memory {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               reserved-region@80000000 {
+                       reg = <0 0x80000000 0 0x860000>;
+                       no-map;
+               };
+
+               cmd_db: cmd-db-region@80860000 {
+                       compatible = "qcom,cmd-db";
+                       reg = <0 0x80860000 0 0x20000>;
+                       no-map;
+               };
+
+               reserved-region@80880000 {
+                       reg = <0 0x80880000 0 0x80000>;
+                       no-map;
+               };
+
+               smem_mem: smem-region@80900000 {
+                       compatible = "qcom,smem";
+                       reg = <0 0x80900000 0 0x200000>;
+                       no-map;
+                       hwlocks = <&tcsr_mutex 3>;
+               };
+
+               reserved-region@80b00000 {
+                       reg = <0 0x80b00000 0 0x100000>;
+                       no-map;
+               };
+
+               reserved-region@83b00000 {
+                       reg = <0 0x83b00000 0 0x1700000>;
+                       no-map;
+               };
+
+               reserved-region@85b00000 {
+                       reg = <0 0x85b00000 0 0xc00000>;
+                       no-map;
+               };
+
+               pil_adsp_mem: adsp-region@86c00000 {
+                       reg = <0 0x86c00000 0 0x2000000>;
+                       no-map;
+               };
+
+               pil_nsp0_mem: cdsp0-region@8a100000 {
+                       reg = <0 0x8a100000 0 0x1e00000>;
+                       no-map;
+               };
+
+               pil_nsp1_mem: cdsp1-region@8c600000 {
+                       reg = <0 0x8c600000 0 0x1e00000>;
+                       no-map;
+               };
+
+               reserved-region@aeb00000 {
+                       reg = <0 0xaeb00000 0 0x16600000>;
+                       no-map;
+               };
+       };
+
+       smp2p-adsp {
+               compatible = "qcom,smp2p";
+               qcom,smem = <443>, <429>;
+               interrupts-extended = <&ipcc IPCC_CLIENT_LPASS
+                                            IPCC_MPROC_SIGNAL_SMP2P
+                                            IRQ_TYPE_EDGE_RISING>;
+               mboxes = <&ipcc IPCC_CLIENT_LPASS
+                               IPCC_MPROC_SIGNAL_SMP2P>;
+
+               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-nsp0 {
+               compatible = "qcom,smp2p";
+               qcom,smem = <94>, <432>;
+               interrupts-extended = <&ipcc IPCC_CLIENT_CDSP
+                                            IPCC_MPROC_SIGNAL_SMP2P
+                                            IRQ_TYPE_EDGE_RISING>;
+               mboxes = <&ipcc IPCC_CLIENT_CDSP
+                               IPCC_MPROC_SIGNAL_SMP2P>;
+
+               qcom,local-pid = <0>;
+               qcom,remote-pid = <5>;
+
+               smp2p_nsp0_out: master-kernel {
+                       qcom,entry-name = "master-kernel";
+                       #qcom,smem-state-cells = <1>;
+               };
+
+               smp2p_nsp0_in: slave-kernel {
+                       qcom,entry-name = "slave-kernel";
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+       };
+
+       smp2p-nsp1 {
+               compatible = "qcom,smp2p";
+               qcom,smem = <617>, <616>;
+               interrupts-extended = <&ipcc IPCC_CLIENT_NSP1
+                                            IPCC_MPROC_SIGNAL_SMP2P
+                                            IRQ_TYPE_EDGE_RISING>;
+               mboxes = <&ipcc IPCC_CLIENT_NSP1
+                               IPCC_MPROC_SIGNAL_SMP2P>;
+
+               qcom,local-pid = <0>;
+               qcom,remote-pid = <12>;
+
+               smp2p_nsp1_out: master-kernel {
+                       qcom,entry-name = "master-kernel";
+                       #qcom,smem-state-cells = <1>;
+               };
+
+               smp2p_nsp1_in: slave-kernel {
+                       qcom,entry-name = "slave-kernel";
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+       };
+
+       soc: soc@0 {
+               compatible = "simple-bus";
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges = <0 0 0 0 0x10 0>;
+               dma-ranges = <0 0 0 0 0x10 0>;
+
+               gcc: clock-controller@100000 {
+                       compatible = "qcom,gcc-sc8280xp";
+                       reg = <0x0 0x00100000 0x0 0x1f0000>;
+                       #clock-cells = <1>;
+                       #reset-cells = <1>;
+                       #power-domain-cells = <1>;
+                       clocks = <&rpmhcc RPMH_CXO_CLK>,
+                                <&sleep_clk>,
+                                <0>,
+                                <0>,
+                                <0>,
+                                <0>,
+                                <0>,
+                                <0>,
+                                <&usb_0_ssphy>,
+                                <0>,
+                                <0>,
+                                <0>,
+                                <0>,
+                                <0>,
+                                <0>,
+                                <0>,
+                                <&usb_1_ssphy>,
+                                <0>,
+                                <0>,
+                                <0>,
+                                <0>,
+                                <0>,
+                                <0>,
+                                <0>,
+                                <0>,
+                                <0>,
+                                <0>,
+                                <0>,
+                                <0>,
+                                <0>,
+                                <0>,
+                                <0>,
+                                <0>;
+                       power-domains = <&rpmhpd SC8280XP_CX>;
+               };
+
+               ipcc: mailbox@408000 {
+                       compatible = "qcom,sc8280xp-ipcc", "qcom,ipcc";
+                       reg = <0 0x00408000 0 0x1000>;
+                       interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-controller;
+                       #interrupt-cells = <3>;
+                       #mbox-cells = <2>;
+               };
+
+               qup2: geniqup@8c0000 {
+                       compatible = "qcom,geni-se-qup";
+                       reg = <0 0x008c0000 0 0x2000>;
+                       clocks = <&gcc GCC_QUPV3_WRAP_2_M_AHB_CLK>,
+                                <&gcc GCC_QUPV3_WRAP_2_S_AHB_CLK>;
+                       clock-names = "m-ahb", "s-ahb";
+                       iommus = <&apps_smmu 0xa3 0>;
+
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       ranges;
+
+                       status = "disabled";
+
+                       qup2_uart17: serial@884000 {
+                               compatible = "qcom,geni-uart";
+                               reg = <0 0x00884000 0 0x4000>;
+                               clocks = <&gcc GCC_QUPV3_WRAP2_S1_CLK>;
+                               clock-names = "se";
+                               interrupts = <GIC_SPI 583 IRQ_TYPE_LEVEL_HIGH>;
+                               operating-points-v2 = <&qup_opp_table_100mhz>;
+                               power-domains = <&rpmhpd SC8280XP_CX>;
+                               interconnects = <&clk_virt MASTER_QUP_CORE_2 0 &clk_virt SLAVE_QUP_CORE_2 0>,
+                                               <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_QUP_2 0>;
+                               interconnect-names = "qup-core", "qup-config";
+                               status = "disabled";
+                       };
+
+                       qup2_i2c5: i2c@894000 {
+                               compatible = "qcom,geni-i2c";
+                               reg = <0 0x00894000 0 0x4000>;
+                               clock-names = "se";
+                               clocks = <&gcc GCC_QUPV3_WRAP2_S5_CLK>;
+                               interrupts = <GIC_SPI 587 IRQ_TYPE_LEVEL_HIGH>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               power-domains = <&rpmhpd SC8280XP_CX>;
+                               interconnects = <&clk_virt MASTER_QUP_CORE_2 0 &clk_virt SLAVE_QUP_CORE_2 0>,
+                                               <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_QUP_2 0>,
+                                               <&aggre1_noc MASTER_QUP_2 0 &mc_virt SLAVE_EBI1 0>;
+                               interconnect-names = "qup-core", "qup-config", "qup-memory";
+                               status = "disabled";
+                       };
+               };
+
+               qup0: geniqup@9c0000 {
+                       compatible = "qcom,geni-se-qup";
+                       reg = <0 0x009c0000 0 0x6000>;
+                       clocks = <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+                                <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+                       clock-names = "m-ahb", "s-ahb";
+                       iommus = <&apps_smmu 0x563 0>;
+
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       ranges;
+
+                       status = "disabled";
+
+                       qup0_i2c4: i2c@990000 {
+                               compatible = "qcom,geni-i2c";
+                               reg = <0 0x00990000 0 0x4000>;
+                               clock-names = "se";
+                               clocks = <&gcc GCC_QUPV3_WRAP0_S4_CLK>;
+                               interrupts = <GIC_SPI 605 IRQ_TYPE_LEVEL_HIGH>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               power-domains = <&rpmhpd SC8280XP_CX>;
+                               interconnects = <&clk_virt MASTER_QUP_CORE_0 0 &clk_virt SLAVE_QUP_CORE_0 0>,
+                                               <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_QUP_0 0>,
+                                               <&aggre1_noc MASTER_QUP_0 0 &mc_virt SLAVE_EBI1 0>;
+                               interconnect-names = "qup-core", "qup-config", "qup-memory";
+                               status = "disabled";
+                       };
+               };
+
+               qup1: geniqup@ac0000 {
+                       compatible = "qcom,geni-se-qup";
+                       reg = <0 0x00ac0000 0 0x6000>;
+                       clocks = <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+                                <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+                       clock-names = "m-ahb", "s-ahb";
+                       iommus = <&apps_smmu 0x83 0>;
+
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       ranges;
+
+                       status = "disabled";
+               };
+
+               ufs_mem_hc: ufs@1d84000 {
+                       compatible = "qcom,sc8280xp-ufshc", "qcom,ufshc",
+                                    "jedec,ufs-2.0";
+                       reg = <0 0x01d84000 0 0x3000>;
+                       interrupts = <GIC_SPI 265 IRQ_TYPE_LEVEL_HIGH>;
+                       phys = <&ufs_mem_phy_lanes>;
+                       phy-names = "ufsphy";
+                       lanes-per-direction = <2>;
+                       #reset-cells = <1>;
+                       resets = <&gcc GCC_UFS_PHY_BCR>;
+                       reset-names = "rst";
+
+                       power-domains = <&gcc UFS_PHY_GDSC>;
+                       required-opps = <&rpmhpd_opp_nom>;
+
+                       iommus = <&apps_smmu 0xe0 0x0>;
+
+                       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>,
+                                <&gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>;
+                       clock-names = "core_clk",
+                                     "bus_aggr_clk",
+                                     "iface_clk",
+                                     "core_clk_unipro",
+                                     "ref_clk",
+                                     "tx_lane0_sync_clk",
+                                     "rx_lane0_sync_clk",
+                                     "rx_lane1_sync_clk";
+                       freq-table-hz = <75000000 300000000>,
+                                       <0 0>,
+                                       <0 0>,
+                                       <75000000 300000000>,
+                                       <0 0>,
+                                       <0 0>,
+                                       <0 0>,
+                                       <0 0>;
+                       status = "disabled";
+               };
+
+               ufs_mem_phy: phy@1d87000 {
+                       compatible = "qcom,sc8280xp-qmp-ufs-phy";
+                       reg = <0 0x01d87000 0 0xe10>;
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       ranges;
+                       clock-names = "ref",
+                                     "ref_aux";
+                       clocks = <&rpmhcc RPMH_CXO_CLK>,
+                                <&gcc GCC_UFS_PHY_PHY_AUX_CLK>;
+
+                       resets = <&ufs_mem_hc 0>;
+                       reset-names = "ufsphy";
+                       status = "disabled";
+
+                       ufs_mem_phy_lanes: phy@1d87400 {
+                               reg = <0 0x01d87400 0 0x108>,
+                                     <0 0x01d87600 0 0x1e0>,
+                                     <0 0x01d87c00 0 0x1dc>,
+                                     <0 0x01d87800 0 0x108>,
+                                     <0 0x01d87a00 0 0x1e0>;
+                               #phy-cells = <0>;
+                       };
+               };
+
+               ufs_card_hc: ufs@1da4000 {
+                       compatible = "qcom,sc8280xp-ufshc", "qcom,ufshc",
+                                    "jedec,ufs-2.0";
+                       reg = <0 0x01da4000 0 0x3000>;
+                       interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
+                       phys = <&ufs_card_phy_lanes>;
+                       phy-names = "ufsphy";
+                       lanes-per-direction = <2>;
+                       #reset-cells = <1>;
+                       resets = <&gcc GCC_UFS_CARD_BCR>;
+                       reset-names = "rst";
+
+                       power-domains = <&gcc UFS_CARD_GDSC>;
+
+                       iommus = <&apps_smmu 0x4a0 0x0>;
+
+                       clocks = <&gcc GCC_UFS_CARD_AXI_CLK>,
+                                <&gcc GCC_AGGRE_UFS_CARD_AXI_CLK>,
+                                <&gcc GCC_UFS_CARD_AHB_CLK>,
+                                <&gcc GCC_UFS_CARD_UNIPRO_CORE_CLK>,
+                                <&rpmhcc RPMH_CXO_CLK>,
+                                <&gcc GCC_UFS_CARD_TX_SYMBOL_0_CLK>,
+                                <&gcc GCC_UFS_CARD_RX_SYMBOL_0_CLK>,
+                                <&gcc GCC_UFS_CARD_RX_SYMBOL_1_CLK>;
+                       clock-names = "core_clk",
+                                     "bus_aggr_clk",
+                                     "iface_clk",
+                                     "core_clk_unipro",
+                                     "ref_clk",
+                                     "tx_lane0_sync_clk",
+                                     "rx_lane0_sync_clk",
+                                     "rx_lane1_sync_clk";
+                       freq-table-hz = <75000000 300000000>,
+                                       <0 0>,
+                                       <0 0>,
+                                       <75000000 300000000>,
+                                       <0 0>,
+                                       <0 0>,
+                                       <0 0>,
+                                       <0 0>;
+                       status = "disabled";
+               };
+
+               ufs_card_phy: phy@1da7000 {
+                       compatible = "qcom,sc8280xp-qmp-ufs-phy";
+                       reg = <0 0x01da7000 0 0xe10>;
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       ranges;
+                       clock-names = "ref",
+                                     "ref_aux";
+                       clocks = <&gcc GCC_UFS_1_CARD_CLKREF_CLK>,
+                                <&gcc GCC_UFS_CARD_PHY_AUX_CLK>;
+
+                       resets = <&ufs_card_hc 0>;
+                       reset-names = "ufsphy";
+
+                       status = "disabled";
+
+                       ufs_card_phy_lanes: phy@1da7400 {
+                               reg = <0 0x01da7400 0 0x108>,
+                                     <0 0x01da7600 0 0x1e0>,
+                                     <0 0x01da7c00 0 0x1dc>,
+                                     <0 0x01da7800 0 0x108>,
+                                     <0 0x01da7a00 0 0x1e0>;
+                               #phy-cells = <0>;
+                       };
+               };
+
+               tcsr_mutex: hwlock@1f40000 {
+                       compatible = "qcom,tcsr-mutex";
+                       reg = <0x0 0x01f40000 0x0 0x20000>;
+                       #hwlock-cells = <1>;
+               };
+
+               usb_0_hsphy: phy@88e5000 {
+                       compatible = "qcom,sc8280xp-usb-hs-phy",
+                                    "qcom,usb-snps-hs-5nm-phy";
+                       reg = <0 0x088e5000 0 0x400>;
+                       clocks = <&rpmhcc RPMH_CXO_CLK>;
+                       clock-names = "ref";
+                       resets = <&gcc GCC_QUSB2PHY_PRIM_BCR>;
+
+                       #phy-cells = <0>;
+
+                       status = "disabled";
+               };
+
+               usb_2_hsphy0: phy@88e7000 {
+                       compatible = "qcom,sc8280xp-usb-hs-phy",
+                                    "qcom,usb-snps-hs-5nm-phy";
+                       reg = <0 0x088e7000 0 0x400>;
+                       clocks = <&gcc GCC_USB2_HS0_CLKREF_CLK>;
+                       clock-names = "ref";
+                       resets = <&gcc GCC_QUSB2PHY_HS0_MP_BCR>;
+
+                       #phy-cells = <0>;
+
+                       status = "disabled";
+               };
+
+               usb_2_hsphy1: phy@88e8000 {
+                       compatible = "qcom,sc8280xp-usb-hs-phy",
+                                    "qcom,usb-snps-hs-5nm-phy";
+                       reg = <0 0x088e8000 0 0x400>;
+                       clocks = <&gcc GCC_USB2_HS1_CLKREF_CLK>;
+                       clock-names = "ref";
+                       resets = <&gcc GCC_QUSB2PHY_HS1_MP_BCR>;
+
+                       #phy-cells = <0>;
+
+                       status = "disabled";
+               };
+
+               usb_2_hsphy2: phy@88e9000 {
+                       compatible = "qcom,sc8280xp-usb-hs-phy",
+                                    "qcom,usb-snps-hs-5nm-phy";
+                       reg = <0 0x088e9000 0 0x400>;
+                       clocks = <&gcc GCC_USB2_HS2_CLKREF_CLK>;
+                       clock-names = "ref";
+                       resets = <&gcc GCC_QUSB2PHY_HS2_MP_BCR>;
+
+                       #phy-cells = <0>;
+
+                       status = "disabled";
+               };
+
+               usb_2_hsphy3: phy@88ea000 {
+                       compatible = "qcom,sc8280xp-usb-hs-phy",
+                                    "qcom,usb-snps-hs-5nm-phy";
+                       reg = <0 0x088ea000 0 0x400>;
+                       clocks = <&gcc GCC_USB2_HS3_CLKREF_CLK>;
+                       clock-names = "ref";
+                       resets = <&gcc GCC_QUSB2PHY_HS3_MP_BCR>;
+
+                       #phy-cells = <0>;
+
+                       status = "disabled";
+               };
+
+               usb_2_qmpphy0: phy-wrapper@88ef000 {
+                       compatible = "qcom,sc8280xp-qmp-usb3-uni-phy";
+                       reg = <0 0x088ef000 0 0x1c8>;
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       ranges;
+
+                       clocks = <&gcc GCC_USB3_MP_PHY_AUX_CLK>,
+                                <&rpmhcc RPMH_CXO_CLK>,
+                                <&gcc GCC_USB3_MP0_CLKREF_CLK>,
+                                <&gcc GCC_USB3_MP_PHY_COM_AUX_CLK>;
+                       clock-names = "aux", "ref_clk_src", "ref", "com_aux";
+
+                       resets = <&gcc GCC_USB3_UNIPHY_MP0_BCR>,
+                                <&gcc GCC_USB3UNIPHY_PHY_MP0_BCR>;
+                       reset-names = "phy", "common";
+
+                       power-domains = <&gcc USB30_MP_GDSC>;
+
+                       status = "disabled";
+
+                       usb_2_ssphy0: phy@88efe00 {
+                               reg = <0 0x088efe00 0 0x160>,
+                                     <0 0x088f0000 0 0x1ec>,
+                                     <0 0x088ef200 0 0x1f0>;
+                               #phy-cells = <0>;
+                               #clock-cells = <0>;
+                               clocks = <&gcc GCC_USB3_MP_PHY_PIPE_0_CLK>;
+                               clock-names = "pipe0";
+                               clock-output-names = "usb2_phy0_pipe_clk";
+                       };
+               };
+
+               usb_2_qmpphy1: phy-wrapper@88f1000 {
+                       compatible = "qcom,sc8280xp-qmp-usb3-uni-phy";
+                       reg = <0 0x088f1000 0 0x1c8>;
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       ranges;
+
+                       clocks = <&gcc GCC_USB3_MP_PHY_AUX_CLK>,
+                                <&rpmhcc RPMH_CXO_CLK>,
+                                <&gcc GCC_USB3_MP1_CLKREF_CLK>,
+                                <&gcc GCC_USB3_MP_PHY_COM_AUX_CLK>;
+                       clock-names = "aux", "ref_clk_src", "ref", "com_aux";
+
+                       resets = <&gcc GCC_USB3_UNIPHY_MP1_BCR>,
+                                <&gcc GCC_USB3UNIPHY_PHY_MP1_BCR>;
+                       reset-names = "phy", "common";
+
+                       power-domains = <&gcc USB30_MP_GDSC>;
+
+                       status = "disabled";
+
+                       usb_2_ssphy1: phy@88f1e00 {
+                               reg = <0 0x088f1e00 0 0x160>,
+                                     <0 0x088f2000 0 0x1ec>,
+                                     <0 0x088f1200 0 0x1f0>;
+                               #phy-cells = <0>;
+                               #clock-cells = <0>;
+                               clocks = <&gcc GCC_USB3_MP_PHY_PIPE_1_CLK>;
+                               clock-names = "pipe0";
+                               clock-output-names = "usb2_phy1_pipe_clk";
+                       };
+               };
+
+               remoteproc_adsp: remoteproc@3000000 {
+                       compatible = "qcom,sc8280xp-adsp-pas";
+                       reg = <0 0x03000000 0 0x100>;
+
+                       interrupts-extended = <&intc GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&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>,
+                                             <&smp2p_adsp_in 7 IRQ_TYPE_EDGE_RISING>;
+                       interrupt-names = "wdog", "fatal", "ready",
+                                         "handover", "stop-ack", "shutdown-ack";
+
+                       clocks = <&rpmhcc RPMH_CXO_CLK>;
+                       clock-names = "xo";
+
+                       power-domains = <&rpmhpd SC8280XP_LCX>,
+                                       <&rpmhpd SC8280XP_LMX>;
+                       power-domain-names = "lcx", "lmx";
+
+                       memory-region = <&pil_adsp_mem>;
+
+                       qcom,qmp = <&aoss_qmp>;
+
+                       qcom,smem-states = <&smp2p_adsp_out 0>;
+                       qcom,smem-state-names = "stop";
+
+                       status = "disabled";
+
+                       remoteproc_adsp_glink: 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>;
+                       };
+               };
+
+               usb_0_qmpphy: phy-wrapper@88ec000 {
+                       compatible = "qcom,sc8280xp-qmp-usb43dp-phy";
+                       reg = <0 0x088ec000 0 0x1e4>,
+                             <0 0x088eb000 0 0x40>,
+                             <0 0x088ed000 0 0x1c8>;
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       ranges;
+
+                       clocks = <&gcc GCC_USB3_PRIM_PHY_AUX_CLK>,
+                                <&rpmhcc RPMH_CXO_CLK>,
+                                <&gcc GCC_USB4_EUD_CLKREF_CLK>,
+                                <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>;
+                       clock-names = "aux", "ref_clk_src", "ref", "com_aux";
+
+                       resets = <&gcc GCC_USB3_PHY_PRIM_BCR>,
+                                <&gcc GCC_USB3_DP_PHY_PRIM_BCR>;
+                       reset-names = "phy", "common";
+
+                       power-domains = <&gcc USB30_PRIM_GDSC>;
+
+                       status = "disabled";
+
+                       usb_0_ssphy: usb3-phy@88eb400 {
+                               reg = <0 0x088eb400 0 0x100>,
+                                     <0 0x088eb600 0 0x3ec>,
+                                     <0 0x088ec400 0 0x1f0>,
+                                     <0 0x088eba00 0 0x100>,
+                                     <0 0x088ebc00 0 0x3ec>,
+                                     <0 0x088ec700 0 0x64>;
+                               #phy-cells = <0>;
+                               #clock-cells = <0>;
+                               clocks = <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>;
+                               clock-names = "pipe0";
+                               clock-output-names = "usb0_phy_pipe_clk_src";
+                       };
+
+                       usb_0_dpphy: dp-phy@88ed200 {
+                               reg = <0 0x088ed200 0 0x200>,
+                                     <0 0x088ed400 0 0x200>,
+                                     <0 0x088eda00 0 0x200>,
+                                     <0 0x088ea600 0 0x200>,
+                                     <0 0x088ea800 0 0x200>;
+                               #clock-cells = <1>;
+                               #phy-cells = <0>;
+                       };
+               };
+
+               usb_1_hsphy: phy@8902000 {
+                       compatible = "qcom,sc8280xp-usb-hs-phy",
+                                    "qcom,usb-snps-hs-5nm-phy";
+                       reg = <0 0x08902000 0 0x400>;
+                       #phy-cells = <0>;
+
+                       clocks = <&rpmhcc RPMH_CXO_CLK>;
+                       clock-names = "ref";
+
+                       resets = <&gcc GCC_QUSB2PHY_SEC_BCR>;
+
+                       status = "disabled";
+               };
+
+               usb_1_qmpphy: phy-wrapper@8904000 {
+                       compatible = "qcom,sc8280xp-qmp-usb43dp-phy";
+                       reg = <0 0x08904000 0 0x1e4>,
+                             <0 0x08903000 0 0x40>,
+                             <0 0x08905000 0 0x1c8>;
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       ranges;
+
+                       clocks = <&gcc GCC_USB3_SEC_PHY_AUX_CLK>,
+                                <&rpmhcc RPMH_CXO_CLK>,
+                                <&gcc GCC_USB4_CLKREF_CLK>,
+                                <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>;
+                       clock-names = "aux", "ref_clk_src", "ref", "com_aux";
+
+                       resets = <&gcc GCC_USB3_PHY_SEC_BCR>,
+                                <&gcc GCC_USB4_1_DP_PHY_PRIM_BCR>;
+                       reset-names = "phy", "common";
+
+                       power-domains = <&gcc USB30_SEC_GDSC>;
+
+                       status = "disabled";
+
+                       usb_1_ssphy: usb3-phy@8903400 {
+                               reg = <0 0x08903400 0 0x100>,
+                                     <0 0x08903c00 0 0x3ec>,
+                                     <0 0x08904400 0 0x1f0>,
+                                     <0 0x08903a00 0 0x100>,
+                                     <0 0x08903c00 0 0x3ec>,
+                                     <0 0x08904200 0 0x18>;
+                               #phy-cells = <0>;
+                               #clock-cells = <0>;
+                               clocks = <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>;
+                               clock-names = "pipe0";
+                               clock-output-names = "usb1_phy_pipe_clk_src";
+                       };
+
+                       usb_1_dpphy: dp-phy@8904200 {
+                               reg = <0 0x08904200 0 0x200>,
+                                     <0 0x08904400 0 0x200>,
+                                     <0 0x08904a00 0 0x200>,
+                                     <0 0x08904600 0 0x200>,
+                                     <0 0x08904800 0 0x200>;
+                               #clock-cells = <1>;
+                               #phy-cells = <0>;
+                       };
+               };
+
+               system-cache-controller@9200000 {
+                       compatible = "qcom,sc8280xp-llcc";
+                       reg = <0 0x09200000 0 0x58000>, <0 0x09600000 0 0x58000>;
+                       reg-names = "llcc_base", "llcc_broadcast_base";
+                       interrupts = <GIC_SPI 582 IRQ_TYPE_LEVEL_HIGH>;
+               };
+
+               usb_0: usb@a6f8800 {
+                       compatible = "qcom,sc8280xp-dwc3", "qcom,dwc3";
+                       reg = <0 0x0a6f8800 0 0x400>;
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       ranges;
+
+                       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_AGGRE_USB_NOC_NORTH_AXI_CLK>,
+                                <&gcc GCC_AGGRE_USB_NOC_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_PRIM_MOCK_UTMI_CLK>,
+                                         <&gcc GCC_USB30_PRIM_MASTER_CLK>;
+                       assigned-clock-rates = <19200000>, <200000000>;
+
+                       interrupts-extended = <&intc GIC_SPI 804 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&pdc 14 IRQ_TYPE_EDGE_BOTH>,
+                                             <&pdc 15 IRQ_TYPE_EDGE_BOTH>,
+                                             <&pdc 138 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "dp_hs_phy_irq",
+                                         "dm_hs_phy_irq",
+                                         "ss_phy_irq";
+
+                       power-domains = <&gcc USB30_PRIM_GDSC>;
+
+                       resets = <&gcc GCC_USB30_PRIM_BCR>;
+
+                       interconnects = <&aggre1_noc MASTER_USB3_0 0 &mc_virt SLAVE_EBI1 0>,
+                                       <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_USB3_0 0>;
+                       interconnect-names = "usb-ddr", "apps-usb";
+
+                       status = "disabled";
+
+                       usb_0_dwc3: usb@a600000 {
+                               compatible = "snps,dwc3";
+                               reg = <0 0x0a600000 0 0xcd00>;
+                               interrupts = <GIC_SPI 803 IRQ_TYPE_LEVEL_HIGH>;
+                               iommus = <&apps_smmu 0x820 0x0>;
+                               phys = <&usb_0_hsphy>, <&usb_0_ssphy>;
+                               phy-names = "usb2-phy", "usb3-phy";
+                       };
+               };
+
+               usb_1: usb@a8f8800 {
+                       compatible = "qcom,sc8280xp-dwc3", "qcom,dwc3";
+                       reg = <0 0x0a8f8800 0 0x400>;
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       ranges;
+
+                       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_USB_NOC_NORTH_AXI_CLK>,
+                                <&gcc GCC_AGGRE_USB_NOC_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 811 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&pdc 12 IRQ_TYPE_EDGE_BOTH>,
+                                             <&pdc 13 IRQ_TYPE_EDGE_BOTH>,
+                                             <&pdc 136 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "pwr_event",
+                                         "dp_hs_phy_irq",
+                                         "dm_hs_phy_irq",
+                                         "ss_phy_irq";
+
+                       power-domains = <&gcc USB30_SEC_GDSC>;
+
+                       resets = <&gcc GCC_USB30_SEC_BCR>;
+
+                       interconnects = <&aggre1_noc MASTER_USB3_1 0 &mc_virt SLAVE_EBI1 0>,
+                                       <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_USB3_1 0>;
+                       interconnect-names = "usb-ddr", "apps-usb";
+
+                       status = "disabled";
+
+                       usb_1_dwc3: usb@a800000 {
+                               compatible = "snps,dwc3";
+                               reg = <0 0x0a800000 0 0xcd00>;
+                               interrupts = <GIC_SPI 810 IRQ_TYPE_LEVEL_HIGH>;
+                               iommus = <&apps_smmu 0x860 0x0>;
+                               phys = <&usb_1_hsphy>, <&usb_1_ssphy>;
+                               phy-names = "usb2-phy", "usb3-phy";
+                       };
+               };
+
+               pdc: interrupt-controller@b220000 {
+                       compatible = "qcom,sc8280xp-pdc", "qcom,pdc";
+                       reg = <0 0x0b220000 0 0x30000>, <0 0x17c000f0 0 0x60>;
+                       qcom,pdc-ranges = <0 480 40>,
+                                         <40 140 14>,
+                                         <54 263 1>,
+                                         <55 306 4>,
+                                         <59 312 3>,
+                                         <62 374 2>,
+                                         <64 434 2>,
+                                         <66 438 3>,
+                                         <69 86 1>,
+                                         <70 520 54>,
+                                         <124 609 28>,
+                                         <159 638 1>,
+                                         <160 720 8>,
+                                         <168 801 1>,
+                                         <169 728 30>,
+                                         <199 416 2>,
+                                         <201 449 1>,
+                                         <202 89 1>,
+                                         <203 451 1>,
+                                         <204 462 1>,
+                                         <205 264 1>,
+                                         <206 579 1>,
+                                         <207 653 1>,
+                                         <208 656 1>,
+                                         <209 659 1>,
+                                         <210 122 1>,
+                                         <211 699 1>,
+                                         <212 705 1>,
+                                         <213 450 1>,
+                                         <214 643 1>,
+                                         <216 646 5>,
+                                         <221 390 5>,
+                                         <226 700 3>,
+                                         <229 240 3>,
+                                         <232 269 1>,
+                                         <233 377 1>,
+                                         <234 372 1>,
+                                         <235 138 1>,
+                                         <236 857 1>,
+                                         <237 860 1>,
+                                         <238 137 1>,
+                                         <239 668 1>,
+                                         <240 366 1>,
+                                         <241 949 1>,
+                                         <242 815 5>,
+                                         <247 769 1>,
+                                         <248 768 1>,
+                                         <249 663 1>,
+                                         <250 799 2>,
+                                         <252 798 1>,
+                                         <253 765 1>,
+                                         <254 763 1>,
+                                         <255 454 1>,
+                                         <258 139 1>,
+                                         <259 786 2>,
+                                         <261 370 2>,
+                                         <263 158 2>;
+                       #interrupt-cells = <2>;
+                       interrupt-parent = <&intc>;
+                       interrupt-controller;
+               };
+
+               tsens0: thermal-sensor@c263000 {
+                       compatible = "qcom,sc8280xp-tsens", "qcom,tsens-v2";
+                       reg = <0 0x0c263000 0 0x1ff>, /* TM */
+                             <0 0x0c222000 0 0x8>; /* SROT */
+                       #qcom,sensors = <14>;
+                       interrupts-extended = <&pdc 26 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&pdc 28 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "uplow", "critical";
+                       #thermal-sensor-cells = <1>;
+               };
+
+               tsens1: thermal-sensor@c265000 {
+                       compatible = "qcom,sc8280xp-tsens", "qcom,tsens-v2";
+                       reg = <0 0x0c265000 0 0x1ff>, /* TM */
+                             <0 0x0c223000 0 0x8>; /* SROT */
+                       #qcom,sensors = <16>;
+                       interrupts-extended = <&pdc 27 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&pdc 29 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "uplow", "critical";
+                       #thermal-sensor-cells = <1>;
+               };
+
+               aoss_qmp: power-controller@c300000 {
+                       compatible = "qcom,sc8280xp-aoss-qmp", "qcom,aoss-qmp";
+                       reg = <0 0x0c300000 0 0x400>;
+                       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>;
+               };
+
+               spmi_bus: spmi@c440000 {
+                       compatible = "qcom,spmi-pmic-arb";
+                       reg = <0 0x0c440000 0 0x1100>,
+                             <0 0x0c600000 0 0x2000000>,
+                             <0 0x0e600000 0 0x100000>,
+                             <0 0x0e700000 0 0xa0000>,
+                             <0 0x0c40a000 0 0x26000>;
+                       reg-names = "core", "chnls", "obsrvr", "intr", "cnfg";
+                       interrupt-names = "periph_irq";
+                       interrupts-extended = <&pdc 1 IRQ_TYPE_LEVEL_HIGH>;
+                       qcom,ee = <0>;
+                       qcom,channel = <0>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       interrupt-controller;
+                       #interrupt-cells = <4>;
+               };
+
+               tlmm: pinctrl@f100000 {
+                       compatible = "qcom,sc8280xp-tlmm";
+                       reg = <0 0x0f100000 0 0x300000>;
+                       interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+                       gpio-ranges = <&tlmm 0 0 230>;
+               };
+
+               apps_smmu: iommu@15000000 {
+                       compatible = "qcom,sc8280xp-smmu-500", "arm,mmu-500";
+                       reg = <0 0x15000000 0 0x100000>;
+                       #iommu-cells = <2>;
+                       #global-interrupts = <2>;
+                       interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 65 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>,
+                                    <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 181 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 182 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 183 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 185 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 315 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 317 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 319 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 321 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 322 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 323 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 324 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 325 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 328 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 333 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 334 IRQ_TYPE_LEVEL_HIGH>,
+                                    <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 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>,
+                                    <GIC_SPI 418 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 419 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 412 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 421 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 706 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 423 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 424 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 425 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 689 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 690 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 691 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 692 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 693 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 694 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 695 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 696 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 410 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 411 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 420 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 413 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 422 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 707 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 708 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 709 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 710 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 711 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 414 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 712 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 713 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 714 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 715 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 912 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 911 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 910 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 909 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 908 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 907 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 906 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 905 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 904 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 903 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 902 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 901 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 900 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 899 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 898 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 897 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 896 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 895 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 894 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 893 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 892 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 891 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 890 IRQ_TYPE_LEVEL_HIGH>;
+               };
+
+               intc: interrupt-controller@17a00000 {
+                       compatible = "arm,gic-v3";
+                       interrupt-controller;
+                       #interrupt-cells = <3>;
+                       reg = <0x0 0x17a00000 0x0 0x10000>,     /* GICD */
+                             <0x0 0x17a60000 0x0 0x100000>;    /* GICR * 8 */
+                       interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+                       #redistributor-regions = <1>;
+                       redistributor-stride = <0 0x20000>;
+
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       ranges;
+
+                       gic-its@17a40000 {
+                               compatible = "arm,gic-v3-its";
+                               reg = <0 0x17a40000 0 0x20000>;
+                               msi-controller;
+                               #msi-cells = <1>;
+                       };
+               };
+
+               watchdog@17c10000 {
+                       compatible = "qcom,apss-wdt-sc8280xp", "qcom,kpss-wdt";
+                       reg = <0 0x17c10000 0 0x1000>;
+                       clocks = <&sleep_clk>;
+                       interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
+               };
+
+               timer@17c20000 {
+                       compatible = "arm,armv7-timer-mem";
+                       reg = <0x0 0x17c20000 0x0 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x0 0x0 0x20000000>;
+
+                       frame@17c21000 {
+                               frame-number = <0>;
+                               interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+                                            <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+                               reg = <0x17c21000 0x1000>,
+                                     <0x17c22000 0x1000>;
+                       };
+
+                       frame@17c23000 {
+                               frame-number = <1>;
+                               interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+                               reg = <0x17c23000 0x1000>;
+                               status = "disabled";
+                       };
+
+                       frame@17c25000 {
+                               frame-number = <2>;
+                               interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+                               reg = <0x17c25000 0x1000>;
+                               status = "disabled";
+                       };
+
+                       frame@17c27000 {
+                               frame-number = <3>;
+                               interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+                               reg = <0x17c26000 0x1000>;
+                               status = "disabled";
+                       };
+
+                       frame@17c29000 {
+                               frame-number = <4>;
+                               interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
+                               reg = <0x17c29000 0x1000>;
+                               status = "disabled";
+                       };
+
+                       frame@17c2b000 {
+                               frame-number = <5>;
+                               interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
+                               reg = <0x17c2b000 0x1000>;
+                               status = "disabled";
+                       };
+
+                       frame@17c2d000 {
+                               frame-number = <6>;
+                               interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+                               reg = <0x17c2d000 0x1000>;
+                               status = "disabled";
+                       };
+               };
+
+               apps_rsc: rsc@18200000 {
+                       compatible = "qcom,rpmh-rsc";
+                       reg = <0x0 0x18200000 0x0 0x10000>,
+                               <0x0 0x18210000 0x0 0x10000>,
+                               <0x0 0x18220000 0x0 0x10000>;
+                       reg-names = "drv-0", "drv-1", "drv-2";
+                       interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+                       qcom,tcs-offset = <0xd00>;
+                       qcom,drv-id = <2>;
+                       qcom,tcs-config = <ACTIVE_TCS  2>, <SLEEP_TCS   3>,
+                                         <WAKE_TCS    3>, <CONTROL_TCS 1>;
+                       label = "apps_rsc";
+
+                       apps_bcm_voter: bcm-voter {
+                               compatible = "qcom,bcm-voter";
+                       };
+
+                       rpmhcc: clock-controller {
+                               compatible = "qcom,sc8280xp-rpmh-clk";
+                               #clock-cells = <1>;
+                               clock-names = "xo";
+                               clocks = <&xo_board_clk>;
+                       };
+
+                       rpmhpd: power-controller {
+                               compatible = "qcom,sc8280xp-rpmhpd";
+                               #power-domain-cells = <1>;
+                               operating-points-v2 = <&rpmhpd_opp_table>;
+
+                               rpmhpd_opp_table: opp-table {
+                                       compatible = "operating-points-v2";
+
+                                       rpmhpd_opp_ret: opp1 {
+                                               opp-level = <RPMH_REGULATOR_LEVEL_RETENTION>;
+                                       };
+
+                                       rpmhpd_opp_min_svs: opp2 {
+                                               opp-level = <RPMH_REGULATOR_LEVEL_MIN_SVS>;
+                                       };
+
+                                       rpmhpd_opp_low_svs: opp3 {
+                                               opp-level = <RPMH_REGULATOR_LEVEL_LOW_SVS>;
+                                       };
+
+                                       rpmhpd_opp_svs: opp4 {
+                                               opp-level = <RPMH_REGULATOR_LEVEL_SVS>;
+                                       };
+
+                                       rpmhpd_opp_svs_l1: opp5 {
+                                               opp-level = <RPMH_REGULATOR_LEVEL_SVS_L1>;
+                                       };
+
+                                       rpmhpd_opp_nom: opp6 {
+                                               opp-level = <RPMH_REGULATOR_LEVEL_NOM>;
+                                       };
+
+                                       rpmhpd_opp_nom_l1: opp7 {
+                                               opp-level = <RPMH_REGULATOR_LEVEL_NOM_L1>;
+                                       };
+
+                                       rpmhpd_opp_nom_l2: opp8 {
+                                               opp-level = <RPMH_REGULATOR_LEVEL_NOM_L2>;
+                                       };
+
+                                       rpmhpd_opp_turbo: opp9 {
+                                               opp-level = <RPMH_REGULATOR_LEVEL_TURBO>;
+                                       };
+
+                                       rpmhpd_opp_turbo_l1: opp10 {
+                                               opp-level = <RPMH_REGULATOR_LEVEL_TURBO_L1>;
+                                       };
+                               };
+                       };
+               };
+
+               cpufreq_hw: cpufreq@18591000 {
+                       compatible = "qcom,sc8280xp-cpufreq-epss", "qcom,cpufreq-epss";
+                       reg = <0 0x18591000 0 0x1000>,
+                             <0 0x18592000 0 0x1000>;
+                       reg-names = "freq-domain0", "freq-domain1";
+
+                       clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GCC_GPLL0>;
+                       clock-names = "xo", "alternate";
+
+                       #freq-domain-cells = <1>;
+               };
+
+               remoteproc_nsp0: remoteproc@1b300000 {
+                       compatible = "qcom,sc8280xp-nsp0-pas";
+                       reg = <0 0x1b300000 0 0x100>;
+
+                       interrupts-extended = <&intc GIC_SPI 578 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&smp2p_nsp0_in 0 IRQ_TYPE_EDGE_RISING>,
+                                             <&smp2p_nsp0_in 1 IRQ_TYPE_EDGE_RISING>,
+                                             <&smp2p_nsp0_in 2 IRQ_TYPE_EDGE_RISING>,
+                                             <&smp2p_nsp0_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 SC8280XP_NSP>;
+                       power-domain-names = "nsp";
+
+                       memory-region = <&pil_nsp0_mem>;
+
+                       qcom,smem-states = <&smp2p_nsp0_out 0>;
+                       qcom,smem-state-names = "stop";
+
+                       interconnects = <&nspa_noc MASTER_CDSP_PROC 0 &mc_virt SLAVE_EBI1 0>;
+
+                       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 = "nsp0";
+                               qcom,remote-pid = <5>;
+
+                               fastrpc {
+                                       compatible = "qcom,fastrpc";
+                                       qcom,glink-channels = "fastrpcglink-apps-dsp";
+                                       label = "cdsp";
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       compute-cb@1 {
+                                               compatible = "qcom,fastrpc-compute-cb";
+                                               reg = <1>;
+                                               iommus = <&apps_smmu 0x3181 0x0420>;
+                                       };
+
+                                       compute-cb@2 {
+                                               compatible = "qcom,fastrpc-compute-cb";
+                                               reg = <2>;
+                                               iommus = <&apps_smmu 0x3182 0x0420>;
+                                       };
+
+                                       compute-cb@3 {
+                                               compatible = "qcom,fastrpc-compute-cb";
+                                               reg = <3>;
+                                               iommus = <&apps_smmu 0x3183 0x0420>;
+                                       };
+
+                                       compute-cb@4 {
+                                               compatible = "qcom,fastrpc-compute-cb";
+                                               reg = <4>;
+                                               iommus = <&apps_smmu 0x3184 0x0420>;
+                                       };
+
+                                       compute-cb@5 {
+                                               compatible = "qcom,fastrpc-compute-cb";
+                                               reg = <5>;
+                                               iommus = <&apps_smmu 0x3185 0x0420>;
+                                       };
+
+                                       compute-cb@6 {
+                                               compatible = "qcom,fastrpc-compute-cb";
+                                               reg = <6>;
+                                               iommus = <&apps_smmu 0x3186 0x0420>;
+                                       };
+
+                                       compute-cb@7 {
+                                               compatible = "qcom,fastrpc-compute-cb";
+                                               reg = <7>;
+                                               iommus = <&apps_smmu 0x3187 0x0420>;
+                                       };
+
+                                       compute-cb@8 {
+                                               compatible = "qcom,fastrpc-compute-cb";
+                                               reg = <8>;
+                                               iommus = <&apps_smmu 0x3188 0x0420>;
+                                       };
+
+                                       compute-cb@9 {
+                                               compatible = "qcom,fastrpc-compute-cb";
+                                               reg = <9>;
+                                               iommus = <&apps_smmu 0x318b 0x0420>;
+                                       };
+
+                                       compute-cb@10 {
+                                               compatible = "qcom,fastrpc-compute-cb";
+                                               reg = <10>;
+                                               iommus = <&apps_smmu 0x318b 0x0420>;
+                                       };
+
+                                       compute-cb@11 {
+                                               compatible = "qcom,fastrpc-compute-cb";
+                                               reg = <11>;
+                                               iommus = <&apps_smmu 0x318c 0x0420>;
+                                       };
+
+                                       compute-cb@12 {
+                                               compatible = "qcom,fastrpc-compute-cb";
+                                               reg = <12>;
+                                               iommus = <&apps_smmu 0x318d 0x0420>;
+                                       };
+
+                                       compute-cb@13 {
+                                               compatible = "qcom,fastrpc-compute-cb";
+                                               reg = <13>;
+                                               iommus = <&apps_smmu 0x318e 0x0420>;
+                                       };
+
+                                       compute-cb@14 {
+                                               compatible = "qcom,fastrpc-compute-cb";
+                                               reg = <14>;
+                                               iommus = <&apps_smmu 0x318f 0x0420>;
+                                       };
+                               };
+                       };
+               };
+
+               remoteproc_nsp1: remoteproc@21300000 {
+                       compatible = "qcom,sc8280xp-nsp1-pas";
+                       reg = <0 0x21300000 0 0x100>;
+
+                       interrupts-extended = <&intc GIC_SPI 887 IRQ_TYPE_LEVEL_HIGH>,
+                                             <&smp2p_nsp1_in 0 IRQ_TYPE_EDGE_RISING>,
+                                             <&smp2p_nsp1_in 1 IRQ_TYPE_EDGE_RISING>,
+                                             <&smp2p_nsp1_in 2 IRQ_TYPE_EDGE_RISING>,
+                                             <&smp2p_nsp1_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 SC8280XP_NSP>;
+                       power-domain-names = "nsp";
+
+                       memory-region = <&pil_nsp1_mem>;
+
+                       qcom,smem-states = <&smp2p_nsp1_out 0>;
+                       qcom,smem-state-names = "stop";
+
+                       interconnects = <&nspb_noc MASTER_CDSP_PROC_B 0 &mc_virt SLAVE_EBI1 0>;
+
+                       status = "disabled";
+
+                       glink-edge {
+                               interrupts-extended = <&ipcc IPCC_CLIENT_NSP1
+                                                            IPCC_MPROC_SIGNAL_GLINK_QMP
+                                                            IRQ_TYPE_EDGE_RISING>;
+                               mboxes = <&ipcc IPCC_CLIENT_NSP1
+                                               IPCC_MPROC_SIGNAL_GLINK_QMP>;
+
+                               label = "nsp1";
+                               qcom,remote-pid = <12>;
+                       };
+               };
+       };
+
+       thermal-zones {
+               cpu0-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens0 1>;
+
+                       trips {
+                               cpu-crit {
+                                       temperature = <110000>;
+                                       hysteresis = <1000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               cpu1-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens0 2>;
+
+                       trips {
+                               cpu-crit {
+                                       temperature = <110000>;
+                                       hysteresis = <1000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               cpu2-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens0 3>;
+
+                       trips {
+                               cpu-crit {
+                                       temperature = <110000>;
+                                       hysteresis = <1000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               cpu3-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens0 4>;
+
+                       trips {
+                               cpu-crit {
+                                       temperature = <110000>;
+                                       hysteresis = <1000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               cpu4-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens0 5>;
+
+                       trips {
+                               cpu-crit {
+                                       temperature = <110000>;
+                                       hysteresis = <1000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               cpu5-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens0 6>;
+
+                       trips {
+                               cpu-crit {
+                                       temperature = <110000>;
+                                       hysteresis = <1000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               cpu6-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens0 7>;
+
+                       trips {
+                               cpu-crit {
+                                       temperature = <110000>;
+                                       hysteresis = <1000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               cpu7-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens0 8>;
+
+                       trips {
+                               cpu-crit {
+                                       temperature = <110000>;
+                                       hysteresis = <1000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               cluster0-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens0 9>;
+
+                       trips {
+                               cpu-crit {
+                                       temperature = <110000>;
+                                       hysteresis = <1000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               mem-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&tsens1 15>;
+
+                       trips {
+                               trip-point0 {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "hot";
+                               };
+                       };
+               };
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>;
+       };
+};
diff --git a/arch/arm64/boot/dts/qcom/sda660-inforce-ifc6560.dts b/arch/arm64/boot/dts/qcom/sda660-inforce-ifc6560.dts
new file mode 100644 (file)
index 0000000..28050bc
--- /dev/null
@@ -0,0 +1,461 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021, Linaro Ltd.
+ * Copyright (c) 2020, Konrad Dybcio <konrad.dybcio@somainline.org>
+ * Copyright (c) 2020, AngeloGioacchino Del Regno
+ *                     <angelogioacchino.delregno@somainline.org>
+ */
+
+/dts-v1/;
+
+#include "sdm660.dtsi"
+#include "pm660.dtsi"
+#include "pm660l.dtsi"
+
+/ {
+       model = "Inforce 6560 Single Board Computer";
+       compatible = "inforce,ifc6560", "qcom,sda660";
+       chassis-type = "embedded"; /* SBC */
+
+       aliases {
+               serial0 = &blsp1_uart2;
+               serial1 = &blsp2_uart1;
+       };
+
+       chosen {
+               stdout-path = "serial0:115200n8";
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+
+               volup {
+                       label = "Volume Up";
+                       gpios = <&pm660l_gpios 7 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_VOLUMEUP>;
+                       debounce-interval = <15>;
+               };
+       };
+
+       /*
+        * Until we hook up type-c detection, we
+        * have to stick with this. But it works.
+        */
+       extcon_usb: extcon-usb {
+               compatible = "linux,extcon-usb-gpio";
+               id-gpio = <&tlmm 58 GPIO_ACTIVE_HIGH>;
+       };
+
+       hdmi-out {
+               compatible = "hdmi-connector";
+               type = "a";
+
+               port {
+                       hdmi_con: endpoint {
+                               remote-endpoint = <&adv7533_out>;
+                       };
+               };
+       };
+
+       vph_pwr: vph-pwr-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vph_pwr";
+               regulator-min-microvolt = <3800000>;
+               regulator-max-microvolt = <3800000>;
+
+               regulator-always-on;
+               regulator-boot-on;
+       };
+
+       v3p3_bck_bst: v3p3-bck-bst-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "v3p3_bck_bst";
+
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+
+               vin-supply = <&vph_pwr>;
+       };
+
+       v1p2_ldo: v1p2-ldo-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "v1p2_ldo";
+
+               regulator-min-microvolt = <1200000>;
+               regulator-max-microvolt = <1200000>;
+
+               vin-supply = <&vph_pwr>;
+       };
+
+       v5p0_boost: v5p0-boost-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "v5p0_boost";
+
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+
+               vin-supply = <&vph_pwr>;
+       };
+};
+
+&adsp_pil {
+       firmware-name = "qcom/ifc6560/adsp.mbn";
+};
+
+&blsp_i2c6 {
+       status = "okay";
+
+       adv7533: hdmi@39 {
+               compatible = "adi,adv7535";
+               reg = <0x39>, <0x66>;
+               reg-names = "main", "edid";
+
+               interrupt-parent = <&pm660l_gpios>;
+               interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
+
+               clocks = <&rpmcc RPM_SMD_BB_CLK2>;
+               clock-names = "cec";
+               /*
+                * Limit to 3 lanes to prevent the bridge from changing amount
+                * of lanes in the fly. MSM DSI host doesn't like that.
+                */
+               adi,dsi-lanes = <3>;
+               avdd-supply = <&vreg_l13a_1p8>;
+               dvdd-supply = <&vreg_l13a_1p8>;
+               pvdd-supply = <&vreg_l13a_1p8>;
+               a2vdd-supply = <&vreg_l13a_1p8>;
+               v3p3-supply = <&v3p3_bck_bst>;
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+
+                               adv7533_in: endpoint {
+                                       remote-endpoint = <&dsi0_out>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+
+                               adv7533_out: endpoint {
+                                       remote-endpoint = <&hdmi_con>;
+                               };
+                       };
+               };
+       };
+};
+
+&blsp1_dma {
+       /*
+        * The board will lock up if we toggle the BLSP clock, unless the
+        * BAM DMA interconnects support is in place.
+        */
+       /delete-property/ clocks;
+};
+
+&blsp1_uart2 {
+       status = "okay";
+};
+
+&blsp2_dma {
+       /*
+        * The board will lock up if we toggle the BLSP clock, unless the
+        * BAM DMA interconnects support is in place.
+        */
+       /delete-property/ clocks;
+};
+
+&blsp2_uart1 {
+       status = "okay";
+
+       bluetooth {
+               compatible = "qcom,wcn3990-bt";
+
+               vddio-supply = <&vreg_l13a_1p8>;
+               vddxo-supply = <&vreg_l9a_1p8>;
+               vddrf-supply = <&vreg_l6a_1p3>;
+               vddch0-supply = <&vreg_l19a_3p3>;
+               max-speed = <3200000>;
+       };
+};
+
+&dsi0 {
+       status = "okay";
+       vdda-supply = <&vreg_l1a_1p225>;
+};
+
+&dsi0_out {
+       remote-endpoint = <&adv7533_in>;
+       data-lanes = <0 1 2 3>;
+};
+
+&dsi0_phy {
+       status = "okay";
+       vcca-supply = <&vreg_l1b_0p925>;
+};
+
+&mdss {
+       status = "okay";
+};
+
+&mmss_smmu {
+       status = "okay";
+};
+
+&pon_pwrkey {
+       status = "okay";
+};
+
+&pon_resin {
+       status = "okay";
+
+       linux,code = <KEY_VOLUMEUP>;
+};
+
+&qusb2phy0 {
+       status = "okay";
+
+       vdd-supply = <&vreg_l1b_0p925>;
+       vdda-phy-dpdm-supply = <&vreg_l7b_3p125>;
+};
+
+&qusb2phy1 {
+       status = "okay";
+
+       vdd-supply = <&vreg_l1b_0p925>;
+       vdda-phy-dpdm-supply = <&vreg_l7b_3p125>;
+};
+
+&rpm_requests {
+       pm660-regulators {
+               compatible = "qcom,rpm-pm660-regulators";
+
+               vdd_s1-supply = <&vph_pwr>;
+               vdd_s2-supply = <&vph_pwr>;
+               vdd_s3-supply = <&vph_pwr>;
+               vdd_s4-supply = <&vph_pwr>;
+               vdd_s5-supply = <&vph_pwr>;
+               vdd_s6-supply = <&vph_pwr>;
+
+               vdd_l1_l6_l7-supply = <&vreg_s5a_1p35>;
+               vdd_l2_l3-supply = <&vreg_s2b_1p05>;
+               vdd_l5-supply = <&vreg_s2b_1p05>;
+               vdd_l8_l9_l10_l11_l12_l13_l14-supply = <&vreg_s4a_2p04>;
+               vdd_l15_l16_l17_l18_l19-supply = <&vreg_bob>;
+
+               vreg_s4a_2p04: s4 {
+                       regulator-min-microvolt = <1805000>;
+                       regulator-max-microvolt = <2040000>;
+                       regulator-enable-ramp-delay = <200>;
+                       regulator-ramp-delay = <0>;
+                       regulator-always-on;
+               };
+
+               vreg_s5a_1p35: s5 {
+                       regulator-min-microvolt = <1224000>;
+                       regulator-max-microvolt = <1350000>;
+                       regulator-enable-ramp-delay = <200>;
+                       regulator-ramp-delay = <0>;
+               };
+
+               vreg_l1a_1p225: l1 {
+                       regulator-min-microvolt = <1150000>;
+                       regulator-max-microvolt = <1250000>;
+                       regulator-enable-ramp-delay = <250>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l6a_1p3: l6 {
+                       regulator-min-microvolt = <1304000>;
+                       regulator-max-microvolt = <1368000>;
+                       regulator-enable-ramp-delay = <250>;
+                       regulator-ramp-delay = <0>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l8a_1p8: l8 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-enable-ramp-delay = <250>;
+                       regulator-ramp-delay = <0>;
+                       regulator-system-load = <325000>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l9a_1p8: l9 {
+                       regulator-min-microvolt = <1804000>;
+                       regulator-max-microvolt = <1896000>;
+                       regulator-enable-ramp-delay = <250>;
+                       regulator-ramp-delay = <0>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l13a_1p8: l13 {
+                       /* This gives power to the LPDDR4: never turn it off! */
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1944000>;
+                       regulator-enable-ramp-delay = <250>;
+                       regulator-ramp-delay = <0>;
+                       regulator-always-on;
+                       regulator-boot-on;
+               };
+
+               vreg_l19a_3p3: l19 {
+                       regulator-min-microvolt = <3312000>;
+                       regulator-max-microvolt = <3400000>;
+                       regulator-enable-ramp-delay = <250>;
+                       regulator-ramp-delay = <0>;
+                       regulator-allow-set-load;
+               };
+       };
+
+       pm660l-regulators {
+               compatible = "qcom,rpm-pm660l-regulators";
+
+               vdd_s1-supply = <&vph_pwr>;
+               vdd_s2-supply = <&vph_pwr>;
+               vdd_s3_s4-supply = <&vph_pwr>;
+               vdd_s5-supply = <&vph_pwr>;
+               vdd_s6-supply = <&vph_pwr>;
+
+               vdd_l1_l9_l10-supply = <&vreg_s2b_1p05>;
+               vdd_l2-supply = <&vreg_bob>;
+               vdd_l3_l5_l7_l8-supply = <&vreg_bob>;
+               vdd_l4_l6-supply = <&vreg_bob>;
+               vdd_bob-supply = <&vph_pwr>;
+
+               vreg_s2b_1p05: s2 {
+                       regulator-min-microvolt = <1050000>;
+                       regulator-max-microvolt = <1050000>;
+                       regulator-enable-ramp-delay = <200>;
+                       regulator-ramp-delay = <0>;
+               };
+
+               vreg_l1b_0p925: l1 {
+                       regulator-min-microvolt = <800000>;
+                       regulator-max-microvolt = <925000>;
+                       regulator-enable-ramp-delay = <250>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l2b_2p95: l2 {
+                       regulator-min-microvolt = <1648000>;
+                       regulator-max-microvolt = <3100000>;
+                       regulator-enable-ramp-delay = <250>;
+                       regulator-ramp-delay = <0>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l4b_2p95: l4 {
+                       regulator-min-microvolt = <2944000>;
+                       regulator-max-microvolt = <2952000>;
+                       regulator-enable-ramp-delay = <250>;
+                       regulator-ramp-delay = <0>;
+
+                       regulator-min-microamp = <200>;
+                       regulator-max-microamp = <600000>;
+                       regulator-system-load = <570000>;
+                       regulator-allow-set-load;
+               };
+
+               /*
+                * Downstream specifies a range of 1721-3600mV,
+                * but the only assigned consumers are SDHCI2 VMMC
+                * and Coresight QPDI that both request pinned 2.95V.
+                * Tighten the range to 1.8-3.328 (closest to 3.3) to
+                * make the mmc driver happy.
+                */
+               vreg_l5b_2p95: l5 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <3328000>;
+                       regulator-enable-ramp-delay = <250>;
+                       regulator-system-load = <800000>;
+                       regulator-ramp-delay = <0>;
+                       regulator-allow-set-load;
+               };
+
+               vreg_l7b_3p125: l7 {
+                       regulator-min-microvolt = <2700000>;
+                       regulator-max-microvolt = <3125000>;
+                       regulator-enable-ramp-delay = <250>;
+               };
+
+               vreg_l8b_3p3: l8 {
+                       regulator-min-microvolt = <2800000>;
+                       regulator-max-microvolt = <3400000>;
+                       regulator-enable-ramp-delay = <250>;
+                       regulator-ramp-delay = <0>;
+               };
+
+               vreg_bob: bob {
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3624000>;
+                       regulator-enable-ramp-delay = <500>;
+                       regulator-ramp-delay = <0>;
+               };
+       };
+};
+
+&sdc2_state_on {
+       sd-cd {
+               pins = "gpio54";
+               bias-pull-up;
+               drive-strength = <2>;
+       };
+};
+
+&sdc2_state_off {
+       sd-cd {
+               pins = "gpio54";
+               bias-disable;
+               drive-strength = <2>;
+       };
+};
+
+&sdhc_1 {
+       status = "okay";
+       supports-cqe;
+
+       vmmc-supply = <&vreg_l4b_2p95>;
+       vqmmc-supply = <&vreg_l8a_1p8>;
+
+       mmc-ddr-1_8v;
+       mmc-hs400-1_8v;
+       mmc-hs400-enhanced-strobe;
+};
+
+&sdhc_2 {
+       status = "okay";
+
+       vmmc-supply = <&vreg_l5b_2p95>;
+       vqmmc-supply = <&vreg_l2b_2p95>;
+
+       cd-gpios = <&tlmm 54 GPIO_ACTIVE_LOW>;
+       no-sdio;
+       no-emmc;
+};
+
+&tlmm {
+       gpio-reserved-ranges = <0 4>, <8 4>;
+};
+
+&usb2 {
+       status = "okay";
+};
+
+&usb2_dwc3 {
+       dr_mode = "host";
+};
+
+&usb3 {
+       status = "okay";
+};
+
+&usb3_dwc3 {
+       dr_mode = "peripheral";
+       extcon = <&extcon_usb>;
+};
index 42af1fa..09c0780 100644 (file)
@@ -10,6 +10,7 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/input/input.h>
 #include <dt-bindings/input/gpio-keys.h>
+#include <dt-bindings/leds/common.h>
 
 / {
        /* required for bootloader to select correct board */
@@ -34,7 +35,7 @@
                        height = <1920>;
                        stride = <(1080 * 4)>;
                        format = "a8r8g8b8";
-                       status= "okay";
+                       status = "okay";
                };
        };
 
                pinctrl-0 = <&imx300_vana_default>;
        };
 
-       gpio_keys {
-               status = "okay";
+       gpio-keys {
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
 
-               camera_focus {
+               key-camera-focus {
                        label = "Camera Focus";
                        gpios = <&tlmm 64 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
                        debounce-interval = <15>;
                };
 
-               camera_snapshot {
+               key-camera-snapshot {
                        label = "Camera Snapshot";
                        gpios = <&tlmm 113 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
                        debounce-interval = <15>;
                };
 
-               vol_down {
+               key-vol-down {
                        label = "Volume Down";
                        gpios = <&pm660l_gpios 7 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
        /* HCI Bluetooth */
 };
 
+&pm660l_lpg {
+       qcom,power-source = <1>;
+
+       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_BLUE>;
+               };
+
+               led@2 {
+                       reg = <2>;
+                       color = <LED_COLOR_ID_GREEN>;
+               };
+
+               led@3 {
+                       reg = <3>;
+                       color = <LED_COLOR_ID_RED>;
+               };
+       };
+};
+
 &pon_pwrkey {
        status = "okay";
 };
        linux,code = <KEY_VOLUMEUP>;
 };
 
-&qusb2phy {
+&qusb2phy0 {
        status = "okay";
 
        vdd-supply = <&vreg_l1b_0p925>;
        };
 };
 
+&sdc2_state_on {
+       sd-cd {
+               pins = "gpio54";
+               bias-pull-up;
+               drive-strength = <2>;
+       };
+};
+
+&sdc2_state_off {
+       sd-cd {
+               pins = "gpio54";
+               bias-disable;
+               drive-strength = <2>;
+       };
+};
+
 &sdhc_1 {
        status = "okay";
        supports-cqe;
index b72e8e6..1bc9091 100644 (file)
@@ -8,6 +8,7 @@
 #include <dt-bindings/clock/qcom,gpucc-sdm660.h>
 #include <dt-bindings/clock/qcom,mmcc-sdm660.h>
 #include <dt-bindings/clock/qcom,rpmcc.h>
+#include <dt-bindings/interconnect/qcom,sdm660.h>
 #include <dt-bindings/power/qcom-rpmpd.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
                };
 
                qfprom: qfprom@780000 {
-                       compatible = "qcom,qfprom";
+                       compatible = "qcom,sdm630-qfprom", "qcom,qfprom";
                        reg = <0x00780000 0x621c>;
                        #address-cells = <1>;
                        #size-cells = <1>;
 
                        qusb2_hstx_trim: hstx-trim@240 {
-                               reg = <0x240 0x1>;
-                               bits = <25 3>;
+                               reg = <0x243 0x1>;
+                               bits = <1 3>;
                        };
 
                        gpu_speed_bin: gpu-speed-bin@41a0 {
-                               reg = <0x41a0 0x1>;
-                               bits = <21 7>;
+                               reg = <0x41a2 0x1>;
+                               bits = <5 7>;
                        };
                };
 
                                        bias-pull-up;
                                        drive-strength = <10>;
                                };
-
-                               sd-cd {
-                                       pins = "gpio54";
-                                       bias-pull-up;
-                                       drive-strength = <2>;
-                               };
                        };
 
                        sdc2_state_off: sdc2-off {
                                        bias-pull-up;
                                        drive-strength = <2>;
                                };
-
-                               sd-cd {
-                                       pins = "gpio54";
-                                       bias-disable;
-                                       drive-strength = <2>;
-                               };
                        };
                };
 
                        nvmem-cells = <&gpu_speed_bin>;
                        nvmem-cell-names = "speed_bin";
 
-                       interconnects = <&gnoc 1 &bimc 5>;
+                       interconnects = <&bimc MASTER_OXILI &bimc SLAVE_EBI>;
                        interconnect-names = "gfx-mem";
 
                        operating-points-v2 = <&gpu_sdm630_opp_table>;
 
+                       status = "disabled";
+
                        gpu_sdm630_opp_table: opp-table {
-                               compatible  = "operating-points-v2";
+                               compatible = "operating-points-v2";
                                opp-775000000 {
                                        opp-hz = /bits/ 64 <775000000>;
                                        opp-level = <RPM_SMD_LEVEL_TURBO>;
                                 * haven't seen any devices making use of it.
                                 */
                                maximum-speed = "high-speed";
-                               phys = <&qusb2phy>;
+                               phys = <&qusb2phy0>;
                                phy-names = "usb2-phy";
                                snps,hird-threshold = /bits/ 8 <0>;
                        };
                };
 
-               qusb2phy: phy@c012000 {
+               qusb2phy0: phy@c012000 {
                        compatible = "qcom,sdm660-qusb2-phy";
                        reg = <0x0c012000 0x180>;
                        #phy-cells = <0>;
 
                        clocks = <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
-                               <&gcc GCC_RX1_USB2_CLKREF_CLK>;
+                                <&gcc GCC_RX0_USB2_CLKREF_CLK>;
                        clock-names = "cfg_ahb", "ref";
 
                        resets = <&gcc GCC_QUSB2PHY_PRIM_BCR>;
                        status = "disabled";
                };
 
-               sdhc_2: sdhci@c084000 {
+               qusb2phy1: phy@c014000 {
+                       compatible = "qcom,sdm660-qusb2-phy";
+                       reg = <0x0c014000 0x180>;
+                       #phy-cells = <0>;
+
+                       clocks = <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
+                                <&gcc GCC_RX1_USB2_CLKREF_CLK>;
+                       clock-names = "cfg_ahb", "ref";
+
+                       resets = <&gcc GCC_QUSB2PHY_SEC_BCR>;
+                       nvmem-cells = <&qusb2_hstx_trim>;
+                       status = "disabled";
+               };
+
+               sdhc_2: mmc@c084000 {
                        compatible = "qcom,sdm630-sdhci", "qcom,sdhci-msm-v5";
                        reg = <0x0c084000 0x1000>;
                        reg-names = "hc";
                        interrupt-names = "hc_irq", "pwr_irq";
 
                        bus-width = <4>;
-                       clocks = <&gcc GCC_SDCC2_APPS_CLK>,
-                                       <&gcc GCC_SDCC2_AHB_CLK>,
+
+                       clocks = <&gcc GCC_SDCC2_AHB_CLK>,
+                                       <&gcc GCC_SDCC2_APPS_CLK>,
                                        <&xo_board>;
-                       clock-names = "core", "iface", "xo";
+                       clock-names = "iface", "core", "xo";
+
 
                        interconnects = <&a2noc 3 &a2noc 10>,
                                        <&gnoc 0 &cnoc 28>;
+                       interconnect-names = "sdhc-ddr","cpu-sdhc";
                        operating-points-v2 = <&sdhc2_opp_table>;
 
                        pinctrl-names = "default", "sleep";
                        };
                };
 
-               sdhc_1: sdhci@c0c4000 {
+               sdhc_1: mmc@c0c4000 {
                        compatible = "qcom,sdm630-sdhci", "qcom,sdhci-msm-v5";
                        reg = <0x0c0c4000 0x1000>,
                              <0x0c0c5000 0x1000>,
                                        <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "hc_irq", "pwr_irq";
 
-                       clocks = <&gcc GCC_SDCC1_APPS_CLK>,
-                                <&gcc GCC_SDCC1_AHB_CLK>,
+                       clocks = <&gcc GCC_SDCC1_AHB_CLK>,
+                                <&gcc GCC_SDCC1_APPS_CLK>,
                                 <&xo_board>,
                                 <&gcc GCC_SDCC1_ICE_CORE_CLK>;
-                       clock-names = "core", "iface", "xo", "ice";
+                       clock-names = "iface", "core", "xo", "ice";
 
                        interconnects = <&a2noc 2 &a2noc 10>,
                                        <&gnoc 0 &cnoc 27>;
-                       interconnect-names = "sdhc1-ddr", "cpu-sdhc1";
+                       interconnect-names = "sdhc-ddr", "cpu-sdhc";
                        operating-points-v2 = <&sdhc1_opp_table>;
                        pinctrl-names = "default", "sleep";
                        pinctrl-0 = <&sdc1_state_on>;
                        };
                };
 
+               usb2: usb@c2f8800 {
+                       compatible = "qcom,sdm660-dwc3", "qcom,dwc3";
+                       reg = <0x0c2f8800 0x400>;
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+
+                       clocks = <&gcc GCC_CFG_NOC_USB2_AXI_CLK>,
+                                <&gcc GCC_USB20_MASTER_CLK>,
+                                <&gcc GCC_USB20_MOCK_UTMI_CLK>,
+                                <&gcc GCC_USB20_SLEEP_CLK>;
+                       clock-names = "cfg_noc", "core",
+                                     "mock_utmi", "sleep";
+
+                       assigned-clocks = <&gcc GCC_USB20_MOCK_UTMI_CLK>,
+                                         <&gcc GCC_USB20_MASTER_CLK>;
+                       assigned-clock-rates = <19200000>, <60000000>;
+
+                       interrupts = <GIC_SPI 348 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "hs_phy_irq";
+
+                       qcom,select-utmi-as-pipe-clk;
+
+                       resets = <&gcc GCC_USB_20_BCR>;
+
+                       usb2_dwc3: usb@c200000 {
+                               compatible = "snps,dwc3";
+                               reg = <0x0c200000 0xc8d0>;
+                               interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+                               snps,dis_u2_susphy_quirk;
+                               snps,dis_enblslpm_quirk;
+
+                               /* This is the HS-only host */
+                               maximum-speed = "high-speed";
+                               phys = <&qusb2phy1>;
+                               phy-names = "usb2-phy";
+                               snps,hird-threshold = /bits/ 8 <0>;
+                       };
+               };
+
                mmcc: clock-controller@c8c0000 {
                        compatible = "qcom,mmcc-sdm630";
                        reg = <0x0c8c0000 0x40000>;
                                        <0>;
                };
 
-               dsi_opp_table: dsi-opp-table {
+               dsi_opp_table: opp-table-dsi {
                        compatible = "operating-points-v2";
 
                        opp-131250000 {
                                        };
                                };
 
-                               mdp_opp_table: mdp-opp {
+                               mdp_opp_table: opp-table {
                                        compatible = "operating-points-v2";
 
                                        opp-150000000 {
                                phys = <&dsi0_phy>;
                                phy-names = "dsi";
 
+                               status = "disabled";
+
                                ports {
                                        #address-cells = <1>;
                                        #size-cells = <0>;
 
                                clocks = <&mmcc MDSS_AHB_CLK>, <&xo_board>;
                                clock-names = "iface", "ref";
+                               status = "disabled";
                        };
                };
 
                        status = "disabled";
                };
 
-               imem@146bf000 {
-                       compatible = "simple-mfd";
+               sram@146bf000 {
+                       compatible = "qcom,sdm630-imem", "syscon", "simple-mfd";
                        reg = <0x146bf000 0x1000>;
 
                        #address-cells = <1>;
 
                camss: camss@ca00000 {
                        compatible = "qcom,sdm660-camss";
-                       reg = <0x0c824000 0x1000>,
+                       reg = <0x0ca00020 0x10>,
+                             <0x0ca30000 0x100>,
+                             <0x0ca30400 0x100>,
+                             <0x0ca30800 0x100>,
+                             <0x0ca30c00 0x100>,
+                             <0x0c824000 0x1000>,
                              <0x0ca00120 0x4>,
                              <0x0c825000 0x1000>,
                              <0x0ca00124 0x4>,
                              <0x0c826000 0x1000>,
                              <0x0ca00128 0x4>,
-                             <0x0ca30000 0x100>,
-                             <0x0ca30400 0x100>,
-                             <0x0ca30800 0x100>,
-                             <0x0ca30c00 0x100>,
                              <0x0ca31000 0x500>,
-                             <0x0ca00020 0x10>,
                              <0x0ca10000 0x1000>,
                              <0x0ca14000 0x1000>;
-                       reg-names = "csiphy0",
+                       reg-names = "csi_clk_mux",
+                                   "csid0",
+                                   "csid1",
+                                   "csid2",
+                                   "csid3",
+                                   "csiphy0",
                                    "csiphy0_clk_mux",
                                    "csiphy1",
                                    "csiphy1_clk_mux",
                                    "csiphy2",
                                    "csiphy2_clk_mux",
-                                   "csid0",
-                                   "csid1",
-                                   "csid2",
-                                   "csid3",
                                    "ispif",
-                                   "csi_clk_mux",
                                    "vfe0",
                                    "vfe1";
-                       interrupts = <GIC_SPI 78 IRQ_TYPE_EDGE_RISING>,
-                                    <GIC_SPI 79 IRQ_TYPE_EDGE_RISING>,
-                                    <GIC_SPI 80 IRQ_TYPE_EDGE_RISING>,
-                                    <GIC_SPI 296 IRQ_TYPE_EDGE_RISING>,
+                       interrupts = <GIC_SPI 296 IRQ_TYPE_EDGE_RISING>,
                                     <GIC_SPI 297 IRQ_TYPE_EDGE_RISING>,
                                     <GIC_SPI 298 IRQ_TYPE_EDGE_RISING>,
                                     <GIC_SPI 299 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 78 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 79 IRQ_TYPE_EDGE_RISING>,
+                                    <GIC_SPI 80 IRQ_TYPE_EDGE_RISING>,
                                     <GIC_SPI 309 IRQ_TYPE_EDGE_RISING>,
                                     <GIC_SPI 314 IRQ_TYPE_EDGE_RISING>,
                                     <GIC_SPI 315 IRQ_TYPE_EDGE_RISING>;
-                       interrupt-names = "csiphy0",
-                                         "csiphy1",
-                                         "csiphy2",
-                                         "csid0",
+                       interrupt-names = "csid0",
                                          "csid1",
                                          "csid2",
                                          "csid3",
+                                         "csiphy0",
+                                         "csiphy1",
+                                         "csiphy2",
                                          "ispif",
                                          "vfe0",
                                          "vfe1";
-                       clocks = <&mmcc CAMSS_TOP_AHB_CLK>,
-                               <&mmcc THROTTLE_CAMSS_AXI_CLK>,
-                               <&mmcc CAMSS_ISPIF_AHB_CLK>,
-                               <&mmcc CAMSS_CSI0PHYTIMER_CLK>,
-                               <&mmcc CAMSS_CSI1PHYTIMER_CLK>,
-                               <&mmcc CAMSS_CSI2PHYTIMER_CLK>,
-                               <&mmcc CAMSS_CSI0_AHB_CLK>,
-                               <&mmcc CAMSS_CSI0_CLK>,
-                               <&mmcc CAMSS_CPHY_CSID0_CLK>,
-                               <&mmcc CAMSS_CSI0PIX_CLK>,
-                               <&mmcc CAMSS_CSI0RDI_CLK>,
-                               <&mmcc CAMSS_CSI1_AHB_CLK>,
-                               <&mmcc CAMSS_CSI1_CLK>,
-                               <&mmcc CAMSS_CPHY_CSID1_CLK>,
-                               <&mmcc CAMSS_CSI1PIX_CLK>,
-                               <&mmcc CAMSS_CSI1RDI_CLK>,
-                               <&mmcc CAMSS_CSI2_AHB_CLK>,
-                               <&mmcc CAMSS_CSI2_CLK>,
-                               <&mmcc CAMSS_CPHY_CSID2_CLK>,
-                               <&mmcc CAMSS_CSI2PIX_CLK>,
-                               <&mmcc CAMSS_CSI2RDI_CLK>,
-                               <&mmcc CAMSS_CSI3_AHB_CLK>,
-                               <&mmcc CAMSS_CSI3_CLK>,
-                               <&mmcc CAMSS_CPHY_CSID3_CLK>,
-                               <&mmcc CAMSS_CSI3PIX_CLK>,
-                               <&mmcc CAMSS_CSI3RDI_CLK>,
-                               <&mmcc CAMSS_AHB_CLK>,
-                               <&mmcc CAMSS_VFE0_CLK>,
-                               <&mmcc CAMSS_CSI_VFE0_CLK>,
-                               <&mmcc CAMSS_VFE0_AHB_CLK>,
-                               <&mmcc CAMSS_VFE0_STREAM_CLK>,
-                               <&mmcc CAMSS_VFE1_CLK>,
-                               <&mmcc CAMSS_CSI_VFE1_CLK>,
-                               <&mmcc CAMSS_VFE1_AHB_CLK>,
-                               <&mmcc CAMSS_VFE1_STREAM_CLK>,
-                               <&mmcc CAMSS_VFE_VBIF_AHB_CLK>,
-                               <&mmcc CAMSS_VFE_VBIF_AXI_CLK>,
-                               <&mmcc CSIPHY_AHB2CRIF_CLK>,
-                               <&mmcc CAMSS_CPHY_CSID0_CLK>,
-                               <&mmcc CAMSS_CPHY_CSID1_CLK>,
-                               <&mmcc CAMSS_CPHY_CSID2_CLK>,
-                               <&mmcc CAMSS_CPHY_CSID3_CLK>;
-                       clock-names = "top_ahb",
-                               "throttle_axi",
-                               "ispif_ahb",
-                               "csiphy0_timer",
-                               "csiphy1_timer",
-                               "csiphy2_timer",
-                               "csi0_ahb",
-                               "csi0",
-                               "csi0_phy",
-                               "csi0_pix",
-                               "csi0_rdi",
-                               "csi1_ahb",
-                               "csi1",
-                               "csi1_phy",
-                               "csi1_pix",
-                               "csi1_rdi",
-                               "csi2_ahb",
-                               "csi2",
-                               "csi2_phy",
-                               "csi2_pix",
-                               "csi2_rdi",
-                               "csi3_ahb",
-                               "csi3",
-                               "csi3_phy",
-                               "csi3_pix",
-                               "csi3_rdi",
-                               "ahb",
-                               "vfe0",
-                               "csi_vfe0",
-                               "vfe0_ahb",
-                               "vfe0_stream",
-                               "vfe1",
-                               "csi_vfe1",
-                               "vfe1_ahb",
-                               "vfe1_stream",
-                               "vfe_ahb",
-                               "vfe_axi",
-                               "csiphy_ahb2crif",
-                               "cphy_csid0",
-                               "cphy_csid1",
-                               "cphy_csid2",
-                               "cphy_csid3";
+                       clocks = <&mmcc CAMSS_AHB_CLK>,
+                                <&mmcc CAMSS_CPHY_CSID0_CLK>,
+                                <&mmcc CAMSS_CPHY_CSID1_CLK>,
+                                <&mmcc CAMSS_CPHY_CSID2_CLK>,
+                                <&mmcc CAMSS_CPHY_CSID3_CLK>,
+                                <&mmcc CAMSS_CSI0_AHB_CLK>,
+                                <&mmcc CAMSS_CSI0_CLK>,
+                                <&mmcc CAMSS_CPHY_CSID0_CLK>,
+                                <&mmcc CAMSS_CSI0PIX_CLK>,
+                                <&mmcc CAMSS_CSI0RDI_CLK>,
+                                <&mmcc CAMSS_CSI1_AHB_CLK>,
+                                <&mmcc CAMSS_CSI1_CLK>,
+                                <&mmcc CAMSS_CPHY_CSID1_CLK>,
+                                <&mmcc CAMSS_CSI1PIX_CLK>,
+                                <&mmcc CAMSS_CSI1RDI_CLK>,
+                                <&mmcc CAMSS_CSI2_AHB_CLK>,
+                                <&mmcc CAMSS_CSI2_CLK>,
+                                <&mmcc CAMSS_CPHY_CSID2_CLK>,
+                                <&mmcc CAMSS_CSI2PIX_CLK>,
+                                <&mmcc CAMSS_CSI2RDI_CLK>,
+                                <&mmcc CAMSS_CSI3_AHB_CLK>,
+                                <&mmcc CAMSS_CSI3_CLK>,
+                                <&mmcc CAMSS_CPHY_CSID3_CLK>,
+                                <&mmcc CAMSS_CSI3PIX_CLK>,
+                                <&mmcc CAMSS_CSI3RDI_CLK>,
+                                <&mmcc CAMSS_CSI0PHYTIMER_CLK>,
+                                <&mmcc CAMSS_CSI1PHYTIMER_CLK>,
+                                <&mmcc CAMSS_CSI2PHYTIMER_CLK>,
+                                <&mmcc CSIPHY_AHB2CRIF_CLK>,
+                                <&mmcc CAMSS_CSI_VFE0_CLK>,
+                                <&mmcc CAMSS_CSI_VFE1_CLK>,
+                                <&mmcc CAMSS_ISPIF_AHB_CLK>,
+                                <&mmcc THROTTLE_CAMSS_AXI_CLK>,
+                                <&mmcc CAMSS_TOP_AHB_CLK>,
+                                <&mmcc CAMSS_VFE0_AHB_CLK>,
+                                <&mmcc CAMSS_VFE0_CLK>,
+                                <&mmcc CAMSS_VFE0_STREAM_CLK>,
+                                <&mmcc CAMSS_VFE1_AHB_CLK>,
+                                <&mmcc CAMSS_VFE1_CLK>,
+                                <&mmcc CAMSS_VFE1_STREAM_CLK>,
+                                <&mmcc CAMSS_VFE_VBIF_AHB_CLK>,
+                                <&mmcc CAMSS_VFE_VBIF_AXI_CLK>;
+                       clock-names = "ahb",
+                                     "cphy_csid0",
+                                     "cphy_csid1",
+                                     "cphy_csid2",
+                                     "cphy_csid3",
+                                     "csi0_ahb",
+                                     "csi0",
+                                     "csi0_phy",
+                                     "csi0_pix",
+                                     "csi0_rdi",
+                                     "csi1_ahb",
+                                     "csi1",
+                                     "csi1_phy",
+                                     "csi1_pix",
+                                     "csi1_rdi",
+                                     "csi2_ahb",
+                                     "csi2",
+                                     "csi2_phy",
+                                     "csi2_pix",
+                                     "csi2_rdi",
+                                     "csi3_ahb",
+                                     "csi3",
+                                     "csi3_phy",
+                                     "csi3_pix",
+                                     "csi3_rdi",
+                                     "csiphy0_timer",
+                                     "csiphy1_timer",
+                                     "csiphy2_timer",
+                                     "csiphy_ahb2crif",
+                                     "csi_vfe0",
+                                     "csi_vfe1",
+                                     "ispif_ahb",
+                                     "throttle_axi",
+                                     "top_ahb",
+                                     "vfe0_ahb",
+                                     "vfe0",
+                                     "vfe0_stream",
+                                     "vfe1_ahb",
+                                     "vfe1",
+                                     "vfe1_stream",
+                                     "vfe_ahb",
+                                     "vfe_axi";
                        interconnects = <&mnoc 5 &bimc 5>;
                        interconnect-names = "vfe-mem";
                        iommus = <&mmss_smmu 0xc00>,
                                label = "lpass";
                                mboxes = <&apcs_glb 9>;
                                qcom,remote-pid = <2>;
-                               #address-cells = <1>;
-                               #size-cells = <0>;
 
                                apr {
                                        compatible = "qcom,apr-v2";
index 8b815b2..891e314 100644 (file)
@@ -27,7 +27,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               volume-up {
+               key-volume-up {
                        label = "volume_up";
                        linux,code = <KEY_VOLUMEUP>;
                        gpios = <&tlmm 85 GPIO_ACTIVE_LOW>;
index b96da53..58f687f 100644 (file)
@@ -19,7 +19,7 @@
 };
 
 &sdc2_state_on {
-       pinconf-clk {
+       clk {
                drive-strength = <14>;
        };
 };
index dcbaacf..a3559f6 100644 (file)
@@ -51,7 +51,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               volup {
+               key-volup {
                        label = "Volume Up";
                        gpios = <&pm660l_gpios 7 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
        linux,code = <KEY_VOLUMEDOWN>;
 };
 
-&qusb2phy {
+&qusb2phy0 {
        status = "okay";
 
        vdd-supply = <&vreg_l1b_0p925>;
        };
 };
 
+&pm660l_wled {
+       status = "okay";
+
+       qcom,switching-freq = <800>;
+       qcom,current-limit-microamp = <20000>;
+       qcom,num-strings = <2>;
+};
+
+&sdc2_state_on {
+       sd-cd {
+               pins = "gpio54";
+               bias-pull-up;
+               drive-strength = <2>;
+       };
+};
+
+&sdc2_state_off {
+       sd-cd {
+               pins = "gpio54";
+               bias-disable;
+               drive-strength = <2>;
+       };
+};
+
 &sdhc_1 {
        status = "okay";
        supports-cqe;
index 1d748c5..43220af 100644 (file)
@@ -14,7 +14,7 @@
        operating-points-v2 = <&gpu_sdm660_opp_table>;
 
        gpu_sdm660_opp_table: opp-table {
-               compatible  = "operating-points-v2";
+               compatible = "operating-points-v2";
 
                /*
                 * 775MHz is only available on the highest speed bin
                phys = <&dsi1_phy>;
                phy-names = "dsi";
 
+               status = "disabled";
+
                ports {
                        #address-cells = <1>;
                        #size-cells = <0>;
 
                clocks = <&mmcc MDSS_AHB_CLK>, <&rpmcc RPM_SMD_XO_CLK_SRC>;
                clock-names = "iface", "ref";
+               status = "disabled";
        };
 };
 
index e7e4cc5..b5eb8f7 100644 (file)
                pinctrl-names = "default";
                pinctrl-0 = <&pen_eject_odl>;
 
-               pen-insert {
+               switch-pen-insert {
                        label = "Pen Insert";
                        /* Insert = low, eject = high */
                        gpios = <&tlmm 119 GPIO_ACTIVE_LOW>;
        };
 
        panel: panel {
-               compatible ="innolux,p120zdg-bf1";
+               compatible = "innolux,p120zdg-bf1";
                power-supply = <&pp3300_dx_edp>;
                backlight = <&backlight>;
                no-hpd;
        };
 };
 
+&psci {
+       /delete-node/ cpu0;
+       /delete-node/ cpu1;
+       /delete-node/ cpu2;
+       /delete-node/ cpu3;
+       /delete-node/ cpu4;
+       /delete-node/ cpu5;
+       /delete-node/ cpu6;
+       /delete-node/ cpu7;
+       /delete-node/ cpu-cluster0;
+};
+
+&cpus {
+       /delete-node/ domain-idle-states;
+};
+
+&cpu_idle_states {
+       LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 {
+               compatible = "arm,idle-state";
+               idle-state-name = "little-power-down";
+               arm,psci-suspend-param = <0x40000003>;
+               entry-latency-us = <350>;
+               exit-latency-us = <461>;
+               min-residency-us = <1890>;
+               local-timer-stop;
+       };
+
+       LITTLE_CPU_SLEEP_1: cpu-sleep-0-1 {
+               compatible = "arm,idle-state";
+               idle-state-name = "little-rail-power-down";
+               arm,psci-suspend-param = <0x40000004>;
+               entry-latency-us = <360>;
+               exit-latency-us = <531>;
+               min-residency-us = <3934>;
+               local-timer-stop;
+       };
+
+       BIG_CPU_SLEEP_0: cpu-sleep-1-0 {
+               compatible = "arm,idle-state";
+               idle-state-name = "big-power-down";
+               arm,psci-suspend-param = <0x40000003>;
+               entry-latency-us = <264>;
+               exit-latency-us = <621>;
+               min-residency-us = <952>;
+               local-timer-stop;
+       };
+
+       BIG_CPU_SLEEP_1: cpu-sleep-1-1 {
+               compatible = "arm,idle-state";
+               idle-state-name = "big-rail-power-down";
+               arm,psci-suspend-param = <0x40000004>;
+               entry-latency-us = <702>;
+               exit-latency-us = <1061>;
+               min-residency-us = <4488>;
+               local-timer-stop;
+       };
+
+       CLUSTER_SLEEP_0: cluster-sleep-0 {
+               compatible = "arm,idle-state";
+               idle-state-name = "cluster-power-down";
+               arm,psci-suspend-param = <0x400000F4>;
+               entry-latency-us = <3263>;
+               exit-latency-us = <6562>;
+               min-residency-us = <9987>;
+               local-timer-stop;
+       };
+};
+
+&CPU0 {
+       /delete-property/ power-domains;
+       /delete-property/ power-domain-names;
+       cpu-idle-states = <&LITTLE_CPU_SLEEP_0
+                          &LITTLE_CPU_SLEEP_1
+                          &CLUSTER_SLEEP_0>;
+};
+
+&CPU1 {
+       /delete-property/ power-domains;
+       /delete-property/ power-domain-names;
+       cpu-idle-states = <&LITTLE_CPU_SLEEP_0
+                          &LITTLE_CPU_SLEEP_1
+                          &CLUSTER_SLEEP_0>;
+};
+
+&CPU2 {
+       /delete-property/ power-domains;
+       /delete-property/ power-domain-names;
+       cpu-idle-states = <&LITTLE_CPU_SLEEP_0
+                          &LITTLE_CPU_SLEEP_1
+                          &CLUSTER_SLEEP_0>;
+};
+
+&CPU3 {
+       /delete-property/ power-domains;
+       /delete-property/ power-domain-names;
+       cpu-idle-states = <&LITTLE_CPU_SLEEP_0
+                          &LITTLE_CPU_SLEEP_1
+                          &CLUSTER_SLEEP_0>;
+};
+
+&CPU4 {
+       /delete-property/ power-domains;
+       /delete-property/ power-domain-names;
+       cpu-idle-states = <&BIG_CPU_SLEEP_0
+                          &BIG_CPU_SLEEP_1
+                          &CLUSTER_SLEEP_0>;
+};
+
+&CPU5 {
+       /delete-property/ power-domains;
+       /delete-property/ power-domain-names;
+       cpu-idle-states = <&BIG_CPU_SLEEP_0
+                          &BIG_CPU_SLEEP_1
+                          &CLUSTER_SLEEP_0>;
+};
+
+&CPU6 {
+       /delete-property/ power-domains;
+       /delete-property/ power-domain-names;
+       cpu-idle-states = <&BIG_CPU_SLEEP_0
+                          &BIG_CPU_SLEEP_1
+                          &CLUSTER_SLEEP_0>;
+};
+
+&CPU7 {
+       /delete-property/ power-domains;
+       /delete-property/ power-domain-names;
+       cpu-idle-states = <&BIG_CPU_SLEEP_0
+                          &BIG_CPU_SLEEP_1
+                          &CLUSTER_SLEEP_0>;
+};
+
 /*
  * Reserved memory changes
  *
index 194ebeb..c6e2c57 100644 (file)
@@ -5,6 +5,7 @@
 
 /dts-v1/;
 
+#include <dt-bindings/leds/common.h>
 #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
 #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
 #include <dt-bindings/sound/qcom,q6afe.h>
                regulator-always-on;
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
                autorepeat;
 
                pinctrl-names = "default";
                pinctrl-0 = <&vol_up_pin_a>;
 
-               vol-up {
+               key-vol-up {
                        label = "Volume Up";
                        linux,code = <KEY_VOLUMEUP>;
                        gpios = <&pm8998_gpio 6 GPIO_ACTIVE_LOW>;
        leds {
                compatible = "gpio-leds";
 
-               user4 {
+               led-0 {
                        label = "green:user4";
+                       function = LED_FUNCTION_INDICATOR;
+                       color = <LED_COLOR_ID_GREEN>;
                        gpios = <&pm8998_gpio 13 GPIO_ACTIVE_HIGH>;
                        linux,default-trigger = "panic-indicator";
                        default-state = "off";
                };
 
-               wlan {
+               led-1 {
                        label = "yellow:wlan";
+                       function = LED_FUNCTION_WLAN;
+                       color = <LED_COLOR_ID_YELLOW>;
                        gpios = <&pm8998_gpio 9 GPIO_ACTIVE_HIGH>;
                        linux,default-trigger = "phy0tx";
                        default-state = "off";
                };
 
-               bt {
+               led-2 {
                        label = "blue:bt";
+                       function = LED_FUNCTION_BLUETOOTH;
+                       color = <LED_COLOR_ID_BLUE>;
                        gpios = <&pm8998_gpio 5 GPIO_ACTIVE_HIGH>;
                        linux,default-trigger = "bluetooth-power";
                        default-state = "off";
        status = "okay";
 };
 
+&gpi_dma1 {
+       status = "okay";
+};
+
 &gpu {
        status = "okay";
        zap-shader {
 
 &i2c11 {
        /* On Low speed expansion */
+       clock-frequency = <100000>;
        label = "LS-I2C1";
        status = "okay";
 };
 
 &i2c14 {
        /* On Low speed expansion */
+       clock-frequency = <100000>;
        label = "LS-I2C0";
        status = "okay";
 };
                "OPTION2",
                "PM845_SLB";
 
-       cam0_dvdd_1v2_en_default: cam0-dvdd-1v2-en {
+       cam0_dvdd_1v2_en_default: cam0-dvdd-1v2-en-state {
                pins = "gpio12";
                function = "normal";
 
                qcom,drive-strength = <PMIC_GPIO_STRENGTH_HIGH>;
        };
 
-       cam0_avdd_2v8_en_default: cam0-avdd-2v8-en {
+       cam0_avdd_2v8_en_default: cam0-avdd-2v8-en-state {
                pins = "gpio10";
                function = "normal";
 
                qcom,drive-strength = <PMIC_GPIO_STRENGTH_HIGH>;
        };
 
-       vol_up_pin_a: vol-up-active {
+       vol_up_pin_a: vol-up-active-state {
                pins = "gpio6";
                function = "normal";
                input-enable;
        };
 };
 
+&pmi8998_lpg {
+       status = "okay";
+
+       qcom,power-source = <1>;
+
+       led@3 {
+               reg = <3>;
+               color = <LED_COLOR_ID_GREEN>;
+               function = LED_FUNCTION_HEARTBEAT;
+               function-enumerator = <3>;
+
+               linux,default-trigger = "heartbeat";
+               default-state = "on";
+       };
+
+       led@4 {
+               reg = <4>;
+               color = <LED_COLOR_ID_GREEN>;
+               function = LED_FUNCTION_INDICATOR;
+               function-enumerator = <2>;
+       };
+
+       led@5 {
+               reg = <5>;
+               color = <LED_COLOR_ID_GREEN>;
+               function = LED_FUNCTION_INDICATOR;
+               function-enumerator = <1>;
+       };
+};
+
 /* QUAT I2S Uses 4 I2S SD Lines for audio on LT9611 HDMI Bridge */
 &q6afedai {
        qi2s@22 {
-               reg = <22>;
+               reg = <QUATERNARY_MI2S_RX>;
                qcom,sd-lines = <0 1 2 3>;
        };
 };
                };
 
                codec {
-                       sound-dai =  <&lt9611_codec 0>;
+                       sound-dai = <&lt9611_codec 0>;
                };
        };
 
                };
 
                codec {
-                       sound-dai =  <&left_spkr>, <&right_spkr>, <&swm 0>, <&wcd9340 0>;
+                       sound-dai = <&left_spkr>, <&right_spkr>, <&swm 0>, <&wcd9340 0>;
                };
        };
 
 };
 
 &camss {
-       vdda-supply = <&vreg_l1a_0p875>;
+       vdda-phy-supply = <&vreg_l1a_0p875>;
+       vdda-pll-supply = <&vreg_l26a_1p2>;
 
        status = "ok";
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-lg-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-lg-common.dtsi
new file mode 100644 (file)
index 0000000..20f275f
--- /dev/null
@@ -0,0 +1,614 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SDM845 LG G7 / V35 (judyln / judyp) common device tree
+ *
+ * Copyright (c) 2022, The Linux Foundation. All rights reserved.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+
+#include "sdm845.dtsi"
+#include "pm8998.dtsi"
+#include "pmi8998.dtsi"
+
+/delete-node/ &adsp_mem;
+/delete-node/ &cdsp_mem;
+/delete-node/ &gpu_mem;
+/delete-node/ &ipa_fw_mem;
+/delete-node/ &mba_region;
+/delete-node/ &mpss_region;
+/delete-node/ &qseecom_mem;
+/delete-node/ &rmtfs_mem;
+/delete-node/ &slpi_mem;
+/delete-node/ &spss_mem;
+/delete-node/ &venus_mem;
+/delete-node/ &wlan_msa_mem;
+
+/ {
+       chosen {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+       };
+
+       reserved-memory {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               qseecom_mem: memory@b2000000 {
+                       reg = <0 0xb2000000 0 0x1800000>;
+                       no-map;
+               };
+
+               gpu_mem: memory@8c415000 {
+                       reg = <0 0x8c415000 0 0x2000>;
+                       no-map;
+               };
+
+               ipa_fw_mem: memory@8c400000 {
+                       reg = <0 0x8c400000 0 0x10000>;
+                       no-map;
+               };
+
+               adsp_mem: memory@8c500000 {
+                       reg = <0 0x8c500000 0 0x1e00000>;
+                       no-map;
+               };
+
+               wlan_msa_mem: memory@8e300000 {
+                       reg = <0 0x8e300000 0 0x100000>;
+                       no-map;
+               };
+
+               mpss_region: memory@8e400000 {
+                       reg = <0 0x8e400000 0 0x8900000>;
+                       no-map;
+               };
+
+               venus_mem: memory@96d00000 {
+                       reg = <0 0x96d00000 0 0x500000>;
+                       no-map;
+               };
+
+               cdsp_mem: memory@97200000 {
+                       reg = <0 0x97200000 0 0x800000>;
+                       no-map;
+               };
+
+               mba_region: memory@97a00000 {
+                       reg = <0 0x97a00000 0 0x200000>;
+                       no-map;
+               };
+
+               slpi_mem: memory@97c00000 {
+                       reg = <0 0x97c00000 0 0x1400000>;
+                       no-map;
+               };
+
+               spss_mem: memory@99000000 {
+                       reg = <0 0x99000000 0 0x100000>;
+                       no-map;
+               };
+
+               /* Framebuffer region */
+               memory@9d400000 {
+                       reg = <0x0 0x9d400000 0x0 0x2400000>;
+                       no-map;
+               };
+
+               /* rmtfs lower guard */
+               memory@f0800000 {
+                       reg = <0 0xf0800000 0 0x1000>;
+                       no-map;
+               };
+
+               rmtfs_mem: memory@f0801000 {
+                       compatible = "qcom,rmtfs-mem";
+                       reg = <0 0xf0801000 0 0x200000>;
+                       no-map;
+
+                       qcom,client-id = <1>;
+                       qcom,vmid = <15>;
+               };
+
+               /* rmtfs upper guard */
+               memory@f0a01000 {
+                       reg = <0 0xf0a01000 0 0x1000>;
+                       no-map;
+               };
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&vol_up_pin_a>;
+
+               label = "GPIO Buttons";
+
+               key-vol-up {
+                       label = "Volume up";
+                       linux,code = <KEY_VOLUMEUP>;
+                       gpios = <&pm8998_gpio 6 GPIO_ACTIVE_LOW>;
+               };
+       };
+
+       vph_pwr: vph-pwr-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vph_pwr";
+               regulator-min-microvolt = <3700000>;
+               regulator-max-microvolt = <3700000>;
+       };
+
+       /*
+        * Apparently RPMh does not provide support for PM8998 S4 because it
+        * is always-on; model it as a fixed regulator.
+        */
+       vreg_s4a_1p8: pm8998-smps4-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "vreg_s4a_1p8";
+
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+
+               regulator-always-on;
+               regulator-boot-on;
+
+               vin-supply = <&vph_pwr>;
+       };
+};
+
+&adsp_pas {
+       status = "okay";
+};
+
+&apps_rsc {
+       pm8998-rpmh-regulators {
+               compatible = "qcom,pm8998-rpmh-regulators";
+               qcom,pmic-id = "a";
+
+               vdd-s1-supply = <&vph_pwr>;
+               vdd-s2-supply = <&vph_pwr>;
+               vdd-s3-supply = <&vph_pwr>;
+               vdd-s4-supply = <&vph_pwr>;
+               vdd-s5-supply = <&vph_pwr>;
+               vdd-s6-supply = <&vph_pwr>;
+               vdd-s7-supply = <&vph_pwr>;
+               vdd-s8-supply = <&vph_pwr>;
+               vdd-s9-supply = <&vph_pwr>;
+               vdd-s10-supply = <&vph_pwr>;
+               vdd-s11-supply = <&vph_pwr>;
+               vdd-s12-supply = <&vph_pwr>;
+               vdd-s13-supply = <&vph_pwr>;
+               vdd-l1-l27-supply = <&vreg_s7a_1p025>;
+               vdd-l2-l8-l17-supply = <&vreg_s3a_1p35>;
+               vdd-l3-l11-supply = <&vreg_s7a_1p025>;
+               vdd-l4-l5-supply = <&vreg_s7a_1p025>;
+               vdd-l6-supply = <&vph_pwr>;
+               vdd-l7-l12-l14-l15-supply = <&vreg_s5a_2p04>;
+               vdd-l9-supply = <&vreg_bob>;
+               vdd-l10-l23-l25-supply = <&vreg_bob>;
+               vdd-l13-l19-l21-supply = <&vreg_bob>;
+               vdd-l16-l28-supply = <&vreg_bob>;
+               vdd-l18-l22-supply = <&vreg_bob>;
+               vdd-l20-l24-supply = <&vreg_bob>;
+               vdd-l26-supply = <&vreg_s3a_1p35>;
+               vin-lvs-1-2-supply = <&vreg_s4a_1p8>;
+
+               vreg_s2a_1p125: smps2 {
+                       regulator-min-microvolt = <1100000>;
+                       regulator-max-microvolt = <1100000>;
+               };
+
+               vreg_s3a_1p35: smps3 {
+                       regulator-min-microvolt = <1352000>;
+                       regulator-max-microvolt = <1352000>;
+               };
+
+               vreg_s5a_2p04: smps5 {
+                       regulator-min-microvolt = <1904000>;
+                       regulator-max-microvolt = <2040000>;
+               };
+
+               vreg_s7a_1p025: smps7 {
+                       regulator-min-microvolt = <900000>;
+                       regulator-max-microvolt = <1028000>;
+               };
+
+               vdd_qusb_hs0:
+               vdda_hp_pcie_core:
+               vdda_mipi_csi0_0p9:
+               vdda_mipi_csi1_0p9:
+               vdda_mipi_csi2_0p9:
+               vdda_mipi_dsi0_pll:
+               vdda_mipi_dsi1_pll:
+               vdda_qlink_lv:
+               vdda_qlink_lv_ck:
+               vdda_qrefs_0p875:
+               vdda_pcie_core:
+               vdda_pll_cc_ebi01:
+               vdda_pll_cc_ebi23:
+               vdda_sp_sensor:
+               vdda_ufs1_core:
+               vdda_ufs2_core:
+               vdda_usb1_ss_core:
+               vdda_usb2_ss_core:
+               vreg_l1a_0p875: ldo1 {
+                       regulator-min-microvolt = <880000>;
+                       regulator-max-microvolt = <880000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vddpx_10:
+               vreg_l2a_1p2: ldo2 {
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1200000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-always-on;
+               };
+
+               vreg_l3a_1p0: ldo3 {
+                       regulator-min-microvolt = <1000000>;
+                       regulator-max-microvolt = <1000000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vdd_wcss_cx:
+               vdd_wcss_mx:
+               vdda_wcss_pll:
+               vreg_l5a_0p8: ldo5 {
+                       regulator-min-microvolt = <800000>;
+                       regulator-max-microvolt = <800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vddpx_13:
+               vreg_l6a_1p8: ldo6 {
+                       regulator-min-microvolt = <1856000>;
+                       regulator-max-microvolt = <1856000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l7a_1p8: ldo7 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l8a_1p2: ldo8 {
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1248000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l9a_1p8: ldo9 {
+                       regulator-min-microvolt = <1704000>;
+                       regulator-max-microvolt = <2928000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l10a_1p8: ldo10 {
+                       regulator-min-microvolt = <1704000>;
+                       regulator-max-microvolt = <2928000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l11a_1p0: ldo11 {
+                       regulator-min-microvolt = <1000000>;
+                       regulator-max-microvolt = <1048000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vdd_qfprom:
+               vdd_qfprom_sp:
+               vdda_apc1_cs_1p8:
+               vdda_gfx_cs_1p8:
+               vdda_qrefs_1p8:
+               vdda_qusb_hs0_1p8:
+               vddpx_11:
+               vreg_l12a_1p8: ldo12 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vddpx_2:
+               vreg_l13a_2p95: ldo13 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <2960000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l14a_1p88: ldo14 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1880000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l15a_1p8: ldo15 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l17a_1p3: ldo17 {
+                       regulator-min-microvolt = <1304000>;
+                       regulator-max-microvolt = <1304000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l18a_2p7: ldo18 {
+                       regulator-min-microvolt = <2704000>;
+                       regulator-max-microvolt = <2960000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l20a_2p95: ldo20 {
+                       regulator-min-microvolt = <2704000>;
+                       regulator-max-microvolt = <2960000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l21a_2p95: ldo21 {
+                       regulator-min-microvolt = <2704000>;
+                       regulator-max-microvolt = <2960000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l22a_2p85: ldo22 {
+                       regulator-min-microvolt = <2800000>;
+                       regulator-max-microvolt = <2800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l23a_3p3: ldo23 {
+                       regulator-min-microvolt = <3000000>;
+                       regulator-max-microvolt = <3312000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vdda_qusb_hs0_3p1:
+               vreg_l24a_3p075: ldo24 {
+                       regulator-min-microvolt = <3088000>;
+                       regulator-max-microvolt = <3088000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l25a_3p3: ldo25 {
+                       regulator-min-microvolt = <3000000>;
+                       regulator-max-microvolt = <3312000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vdda_hp_pcie_1p2:
+               vdda_hv_ebi0:
+               vdda_hv_ebi1:
+               vdda_hv_ebi2:
+               vdda_hv_ebi3:
+               vdda_mipi_csi_1p25:
+               vdda_mipi_dsi0_1p2:
+               vdda_mipi_dsi1_1p2:
+               vdda_pcie_1p2:
+               vdda_ufs1_1p2:
+               vdda_ufs2_1p2:
+               vdda_usb1_ss_1p2:
+               vdda_usb2_ss_1p2:
+               vreg_l26a_1p2: ldo26 {
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1200000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l28a_3p0: ldo28 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_lvs1a_1p8: lvs1 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+               };
+
+               vreg_lvs2a_1p8: lvs2 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+               };
+       };
+
+       pmi8998-rpmh-regulators {
+               compatible = "qcom,pmi8998-rpmh-regulators";
+               qcom,pmic-id = "b";
+
+               vdd-bob-supply = <&vph_pwr>;
+
+               vreg_bob: bob {
+                       regulator-min-microvolt = <3312000>;
+                       regulator-max-microvolt = <3600000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_AUTO>;
+                       regulator-allow-bypass;
+               };
+       };
+
+       pm8005-rpmh-regulators {
+               compatible = "qcom,pm8005-rpmh-regulators";
+               qcom,pmic-id = "c";
+
+               vdd-s1-supply = <&vph_pwr>;
+               vdd-s2-supply = <&vph_pwr>;
+               vdd-s3-supply = <&vph_pwr>;
+               vdd-s4-supply = <&vph_pwr>;
+
+               vreg_s3c_0p6: smps3 {
+                       regulator-min-microvolt = <600000>;
+                       regulator-max-microvolt = <600000>;
+               };
+       };
+};
+
+&cdsp_pas {
+       status = "okay";
+};
+
+&dispcc {
+       status = "disabled";
+};
+
+&gcc {
+       protected-clocks = <GCC_QSPI_CORE_CLK>,
+                          <GCC_QSPI_CORE_CLK_SRC>,
+                          <GCC_QSPI_CNOC_PERIPH_AHB_CLK>,
+                          <GCC_LPASS_Q6_AXI_CLK>,
+                          <GCC_LPASS_SWAY_CLK>;
+};
+
+&gpu {
+       status = "okay";
+
+       zap-shader {
+               memory-region = <&gpu_mem>;
+       };
+};
+
+&ipa {
+       status = "okay";
+       modem-init;
+};
+
+&mss_pil {
+       status = "okay";
+};
+
+&pm8998_pon {
+       resin {
+               compatible = "qcom,pm8941-resin";
+               interrupts = <0x0 0x8 1 IRQ_TYPE_EDGE_BOTH>;
+               debounce = <15625>;
+               bias-pull-up;
+               linux,code = <KEY_VOLUMEDOWN>;
+       };
+};
+
+&sdhc_2 {
+       status = "okay";
+
+       cd-gpios = <&tlmm 126 GPIO_ACTIVE_LOW>;
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&sdc2_clk &sdc2_cmd &sdc2_data &sd_card_det_n>;
+
+       vmmc-supply = <&vreg_l21a_2p95>;
+       vqmmc-supply = <&vddpx_2>;
+};
+
+/*
+ * UFS works partially and only with clk_ignore_unused.
+ * Sometimes it crashes with I/O errors.
+ */
+&ufs_mem_hc {
+       status = "okay";
+
+       reset-gpios = <&tlmm 150 GPIO_ACTIVE_LOW>;
+
+       vcc-supply = <&vreg_l20a_2p95>;
+       vcc-max-microamp = <600000>;
+};
+
+&ufs_mem_phy {
+       status = "okay";
+
+       vdda-phy-supply = <&vdda_ufs1_core>;
+       vdda-pll-supply = <&vdda_ufs1_1p2>;
+};
+
+&usb_1 {
+       status = "okay";
+};
+
+&usb_1_dwc3 {
+       /* TODO: these devices have usb id pin */
+       dr_mode = "peripheral";
+};
+
+&usb_1_hsphy {
+       status = "okay";
+
+       vdd-supply = <&vdda_usb1_ss_core>;
+       vdda-pll-supply = <&vdda_qusb_hs0_1p8>;
+       vdda-phy-dpdm-supply = <&vdda_qusb_hs0_3p1>;
+
+       qcom,imp-res-offset-value = <8>;
+       qcom,hstx-trim-value = <QUSB2_V2_HSTX_TRIM_21_6_MA>;
+       qcom,preemphasis-level = <QUSB2_V2_PREEMPHASIS_5_PERCENT>;
+       qcom,preemphasis-width = <QUSB2_V2_PREEMPHASIS_WIDTH_HALF_BIT>;
+};
+
+&usb_1_qmpphy {
+       status = "okay";
+
+       vdda-phy-supply = <&vdda_usb1_ss_1p2>;
+       vdda-pll-supply = <&vdda_usb1_ss_core>;
+};
+
+/* PINCTRL - additions to nodes defined in sdm845.dtsi */
+
+&tlmm {
+       gpio-reserved-ranges = <28 4>, <81 4>;
+
+       sdc2_clk: sdc2-clk {
+               pinconf {
+                       pins = "sdc2_clk";
+                       bias-disable;
+
+                       /*
+                        * It seems that mmc_test reports errors if drive
+                        * strength is not 16 on clk, cmd, and data pins.
+                        *
+                        * TODO: copy-pasted from mtp, try other values
+                        * on these devices.
+                        */
+                       drive-strength = <16>;
+               };
+       };
+
+       sdc2_cmd: sdc2-cmd {
+               pinconf {
+                       pins = "sdc2_cmd";
+                       bias-pull-up;
+                       drive-strength = <16>;
+               };
+       };
+
+       sdc2_data: sdc2-data {
+               pinconf {
+                       pins = "sdc2_data";
+                       bias-pull-up;
+                       drive-strength = <16>;
+               };
+       };
+
+       sd_card_det_n: sd-card-det-n {
+               pinmux {
+                       pins = "gpio126";
+                       function = "gpio";
+               };
+
+               pinconf {
+                       pins = "gpio126";
+                       bias-pull-up;
+               };
+       };
+};
+
+&pm8998_gpio {
+       vol_up_pin_a: vol-up-active-pins {
+               pins = "gpio6";
+               function = "normal";
+               input-enable;
+               bias-pull-up;
+               qcom,drive-strength = <PMIC_GPIO_STRENGTH_NO>;
+       };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-lg-judyln.dts b/arch/arm64/boot/dts/qcom/sdm845-lg-judyln.dts
new file mode 100644 (file)
index 0000000..7d967a1
--- /dev/null
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SDM845 LG G7 (judyln) device tree.
+ *
+ * Copyright (c) 2022, The Linux Foundation. All rights reserved.
+ */
+
+/dts-v1/;
+
+#include "sdm845-lg-common.dtsi"
+
+/ {
+       model = "LG G7 ThinQ";
+       compatible = "lg,judyln", "qcom,sdm845";
+
+       chosen {
+               framebuffer@9d400000 {
+                       compatible = "simple-framebuffer";
+                       reg = <0x0 0x9d400000 0x0 (1440 * 3120 * 4)>;
+                       width = <1440>;
+                       height = <3120>;
+                       stride = <(1440 * 4)>;
+                       format = "a8r8g8b8";
+                       lab-supply = <&lab>;
+                       ibb-supply = <&ibb>;
+               };
+       };
+
+       /* Additional ThinQ key */
+       gpio-keys {
+               pinctrl-0 = <&vol_up_pin_a &thinq_key_default>;
+
+               key-thinq {
+                       label = "ThinQ";
+                       linux,code = <KEY_ASSISTANT>;
+                       interrupt-parent = <&tlmm>;
+                       interrupts = <89 IRQ_TYPE_LEVEL_LOW>;
+               };
+       };
+};
+
+&adsp_pas {
+       firmware-name = "qcom/sdm845/judyln/adsp.mbn";
+};
+
+&cdsp_pas {
+       firmware-name = "qcom/sdm845/judyln/cdsp.mbn";
+};
+
+&gpu {
+       zap-shader {
+               firmware-name = "qcom/sdm845/judyln/a630_zap.mbn";
+       };
+};
+
+&mss_pil {
+       firmware-name = "qcom/sdm845/judyln/mba.mbn", "qcom/sdm845/judyln/modem.mbn";
+};
+
+&tlmm {
+       thinq_key_default: thinq-key-default {
+               pins = "gpio89";
+               function = "gpio";
+
+               drive-strength = <2>;
+               bias-pull-up;
+       };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-lg-judyp.dts b/arch/arm64/boot/dts/qcom/sdm845-lg-judyp.dts
new file mode 100644 (file)
index 0000000..d17d4d4
--- /dev/null
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SDM845 LG V35 (judyp) device tree.
+ *
+ * Copyright (c) 2022, The Linux Foundation. All rights reserved.
+ */
+
+/dts-v1/;
+
+#include "sdm845-lg-common.dtsi"
+
+/ {
+       model = "LG V35 ThinQ";
+       compatible = "lg,judyp", "qcom,sdm845";
+
+       chosen {
+               framebuffer@9d400000 {
+                       compatible = "simple-framebuffer";
+                       reg = <0x0 0x9d400000 0x0 (1440 * 2880 * 4)>;
+                       width = <1440>;
+                       height = <2880>;
+                       stride = <(1440 * 4)>;
+                       format = "a8r8g8b8";
+               };
+       };
+};
+
+&adsp_pas {
+       firmware-name = "qcom/sdm845/judyp/adsp.mbn";
+};
+
+&cdsp_pas {
+       firmware-name = "qcom/sdm845/judyp/cdsp.mbn";
+};
+
+&gpu {
+       zap-shader {
+               firmware-name = "qcom/sdm845/judyp/a630_zap.mbn";
+       };
+};
+
+&mss_pil {
+       firmware-name = "qcom/sdm845/judyp/mba.mbn", "qcom/sdm845/judyp/modem.mbn";
+};
index 07b729f..392461c 100644 (file)
                pinctrl-names = "default";
                pinctrl-0 = <&volume_down_gpio &volume_up_gpio>;
 
-               vol-down {
+               key-vol-down {
                        label = "Volume down";
                        linux,code = <KEY_VOLUMEDOWN>;
                        gpios = <&pm8998_gpio 5 GPIO_ACTIVE_LOW>;
                        debounce-interval = <15>;
                };
 
-               vol-up {
+               key-vol-up {
                        label = "Volume up";
                        linux,code = <KEY_VOLUMEUP>;
                        gpios = <&pm8998_gpio 6 GPIO_ACTIVE_LOW>;
 };
 
 &pm8998_gpio {
-       volume_down_gpio: pm8998_gpio5 {
+       volume_down_gpio: pm8998-gpio5-state {
                pinconf {
                        pins = "gpio5";
                        function = "normal";
                };
        };
 
-       volume_up_gpio: pm8998_gpio6 {
+       volume_up_gpio: pm8998-gpio6-state {
                pinconf {
                        pins = "gpio6";
                        function = "normal";
index 103cc40..83261c9 100644 (file)
@@ -2,11 +2,13 @@
 /*
  * Copyright (c) 2022, Alexander Martinz <amartinz@shiftphones.com>
  * Copyright (c) 2022, Caleb Connolly <caleb@connolly.tech>
+ * Copyright (c) 2022, Dylan Van Assche <me@dylanvanassche.be>
  */
 
 /dts-v1/;
 
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
 #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
 #include "sdm845.dtsi"
 #include "pm8998.dtsi"
@@ -48,7 +50,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&volume_up_gpio>;
 
-               vol-up {
+               key-vol-up {
                        label = "volume_up";
                        linux,code = <KEY_VOLUMEUP>;
                        gpios = <&pm8998_gpio 6 GPIO_ACTIVE_LOW>;
 };
 
 &i2c5 {
-       status="okay";
+       status = "okay";
 
        touchscreen@38 {
                compatible = "focaltech,fts8719";
 };
 
 &pm8998_gpio {
-       volume_up_gpio: pm8998_gpio6 {
+       volume_up_gpio: pm8998-gpio6-state {
                pinconf {
                        pins = "gpio6";
                        function = "normal";
        };
 };
 
+&pmi8998_lpg {
+       status = "okay";
+
+       multi-led {
+               color = <LED_COLOR_ID_RGB>;
+               function = LED_FUNCTION_STATUS;
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               led@3 {
+                       reg = <3>;
+                       color = <LED_COLOR_ID_BLUE>;
+               };
+
+               led@4 {
+                       reg = <4>;
+                       color = <LED_COLOR_ID_GREEN>;
+               };
+
+               led@5 {
+                       reg = <5>;
+                       color = <LED_COLOR_ID_RED>;
+               };
+       };
+};
+
 &qup_uart9_default {
        pinconf-rx {
                pins = "gpio5";
index 8a0d94e..2f5e12d 100644 (file)
@@ -19,8 +19,9 @@
 };
 
 &vreg_l22a_2p8 {
-       regulator-min-microvolt = <2700000>;
-       regulator-max-microvolt = <2700000>;
+       /* Note: Round-down from 2700000 to be a multiple of PLDO step-size 8000 */
+       regulator-min-microvolt = <2696000>;
+       regulator-max-microvolt = <2696000>;
 };
 
 &vreg_l28a_2p8 {
index 281fe6d..51ee42e 100644 (file)
@@ -19,7 +19,7 @@
 
                /* Neither Camera Focus, nor Camera Shutter seem to work... */
 
-               vol-down {
+               key-vol-down {
                        label = "volume_down";
                        gpios = <&pm8998_gpio 5 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEDOWN>;
index d88dc07..82c27f9 100644 (file)
@@ -45,7 +45,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&vol_up_pin_a>;
 
-               vol-up {
+               key-vol-up {
                        label = "Volume Up";
                        linux,code = <KEY_VOLUMEUP>;
                        gpios = <&pm8998_gpio 6 GPIO_ACTIVE_LOW>;
 };
 
 &pm8998_gpio {
-       vol_up_pin_a: vol-up-active {
+       vol_up_pin_a: vol-up-active-state {
                pins = "gpio6";
                function = "normal";
                input-enable;
 /* QUAT I2S Uses 1 I2S SD Line for audio on TAS2559/60 amplifiers */
 &q6afedai {
        qi2s@22 {
-               reg = <22>;
+               reg = <QUATERNARY_MI2S_RX>;
                qcom,sd-lines = <0>;
        };
 };
                };
 
                codec {
-                       sound-dai =  <&wcd9340 0>;
+                       sound-dai = <&wcd9340 0>;
                };
        };
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts
new file mode 100644 (file)
index 0000000..7747081
--- /dev/null
@@ -0,0 +1,762 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2020, Xilin Wu <strongtz@yeah.net>
+ * Copyright (c) 2022, Molly Sophia <mollysophia379@gmail.com>
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/sound/qcom,q6afe.h>
+#include <dt-bindings/sound/qcom,q6asm.h>
+#include "sdm845.dtsi"
+#include "pm8998.dtsi"
+#include "pmi8998.dtsi"
+#include "pm8005.dtsi"
+
+/*
+ * Delete following upstream (sdm845.dtsi) reserved
+ * memory mappings which are different in this device.
+ */
+/delete-node/ &rmtfs_mem;
+/delete-node/ &adsp_mem;
+/delete-node/ &wlan_msa_mem;
+/delete-node/ &mpss_region;
+/delete-node/ &venus_mem;
+/delete-node/ &cdsp_mem;
+/delete-node/ &mba_region;
+/delete-node/ &slpi_mem;
+/delete-node/ &spss_mem;
+
+/ {
+       model = "Xiaomi Mi MIX 2S";
+       compatible = "xiaomi,polaris", "qcom,sdm845";
+       chassis-type = "handset";
+
+       /* required for bootloader to select correct board */
+       qcom,msm-id = <0x141 0x20001>;
+       qcom,board-id = <0x2a 0x0>;
+
+       aliases {
+               serial0 = &uart9;
+               serial1 = &uart6;
+       };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+               autorepeat;
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&volume_up_gpio>;
+
+               key-vol-up {
+                       label = "Volume Up";
+                       linux,code = <KEY_VOLUMEUP>;
+                       gpios = <&pm8998_gpio 6 GPIO_ACTIVE_LOW>;
+                       debounce-interval = <15>;
+               };
+       };
+
+       reserved-memory {
+               adsp_mem: memory@8c500000 {
+                       reg = <0 0x8c500000 0 0x1e00000>;
+                       no-map;
+               };
+
+               wlan_msa_mem: memory@8e300000 {
+                       reg = <0 0x8e300000 0 0x100000>;
+                       no-map;
+               };
+
+               mpss_region: memory@8e400000 {
+                       reg = <0 0x8e400000 0 0x7800000>;
+                       no-map;
+               };
+
+               venus_mem: memory@95c00000 {
+                       reg = <0 0x95c00000 0 0x500000>;
+                       no-map;
+               };
+
+               cdsp_mem: memory@96100000 {
+                       reg = <0 0x96100000 0 0x800000>;
+                       no-map;
+               };
+
+               mba_region: memory@96900000 {
+                       reg = <0 0x96900000 0 0x200000>;
+                       no-map;
+               };
+
+               slpi_mem: memory@96b00000 {
+                       reg = <0 0x96b00000 0 0x1400000>;
+                       no-map;
+               };
+
+               spss_mem: memory@97f00000 {
+                       reg = <0 0x97f00000 0 0x100000>;
+                       no-map;
+               };
+
+               rmtfs_mem: memory@f6301000 {
+                       compatible = "qcom,rmtfs-mem";
+                       reg = <0 0xf6301000 0 0x200000>;
+                       no-map;
+
+                       qcom,client-id = <1>;
+                       qcom,vmid = <15>;
+               };
+       };
+
+       battery: battery {
+               compatible = "simple-battery";
+
+               charge-full-design-microamp-hours = <3400000>;
+               voltage-min-design-microvolt = <3400000>;
+               voltage-max-design-microvolt = <4400000>;
+       };
+
+       vreg_tp_vddio: vreg-tp-vddio {
+               compatible = "regulator-fixed";
+               regulator-name = "vreg_tp_vddio";
+
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+
+               gpio = <&tlmm 23 0>;
+               regulator-always-on;
+               regulator-boot-on;
+               enable-active-high;
+       };
+
+       vreg_s4a_1p8: vreg-s4a-1p8 {
+               compatible = "regulator-fixed";
+               regulator-name = "vreg_s4a_1p8";
+
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-always-on;
+       };
+};
+
+&apps_rsc {
+       pm8998-rpmh-regulators {
+               compatible = "qcom,pm8998-rpmh-regulators";
+               qcom,pmic-id = "a";
+
+               vreg_s2a_1p1: smps2 {
+                       regulator-min-microvolt = <1100000>;
+                       regulator-max-microvolt = <1100000>;
+               };
+
+               vreg_s3a_1p35: smps3 {
+                       regulator-min-microvolt = <1352000>;
+                       regulator-max-microvolt = <1352000>;
+               };
+
+               vreg_s5a_2p04: smps5 {
+                       regulator-min-microvolt = <1904000>;
+                       regulator-max-microvolt = <2040000>;
+               };
+
+               vreg_s7a_1p025: smps7 {
+                       regulator-min-microvolt = <900000>;
+                       regulator-max-microvolt = <1028000>;
+               };
+
+               vdda_mipi_dsi0_pll:
+               vdda_ufs1_core:
+               vreg_l1a_0p875: ldo1 {
+                       regulator-min-microvolt = <880000>;
+                       regulator-max-microvolt = <880000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l2a_1p2: ldo2 {
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1200000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-always-on;
+               };
+
+               vreg_l3a_1p0: ldo3 {
+                       regulator-min-microvolt = <1000000>;
+                       regulator-max-microvolt = <1000000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l5a_0p8: ldo5 {
+                       regulator-min-microvolt = <800000>;
+                       regulator-max-microvolt = <800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l6a_1p8: ldo6 {
+                       regulator-min-microvolt = <1856000>;
+                       regulator-max-microvolt = <1856000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l7a_1p8: ldo7 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l8a_1p2: ldo8 {
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1248000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l9a_1p8: ldo9 {
+                       regulator-min-microvolt = <1704000>;
+                       regulator-max-microvolt = <2928000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l10a_2p95: ldo10 {
+                       regulator-min-microvolt = <1704000>;
+                       regulator-max-microvolt = <2928000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l11a_1p05: ldo11 {
+                       regulator-min-microvolt = <1000000>;
+                       regulator-max-microvolt = <1048000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l12a_1p8: ldo12 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l13a_2p95: ldo13 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <2960000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l14a_1p8: ldo14 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1880000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-always-on;
+               };
+
+               vreg_l15a_1p8: ldo15 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l16a_2p7: ldo16 {
+                       regulator-min-microvolt = <2704000>;
+                       regulator-max-microvolt = <2704000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l17a_1p3: ldo17 {
+                       regulator-min-microvolt = <1304000>;
+                       regulator-max-microvolt = <1304000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-always-on;
+               };
+
+               vreg_l18a_2p9: ldo18 {
+                       regulator-min-microvolt = <2704000>;
+                       regulator-max-microvolt = <2960000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l19a_3p1: ldo19 {
+                       regulator-min-microvolt = <2856000>;
+                       regulator-max-microvolt = <3104000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l20a_2p95: ldo20 {
+                       regulator-min-microvolt = <2704000>;
+                       regulator-max-microvolt = <2960000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l21a_2p95: ldo21 {
+                       regulator-min-microvolt = <2704000>;
+                       regulator-max-microvolt = <2960000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l22a_3p3: ldo22 {
+                       regulator-min-microvolt = <2864000>;
+                       regulator-max-microvolt = <3312000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l23a_3p3: ldo23 {
+                       regulator-min-microvolt = <3000000>;
+                       regulator-max-microvolt = <3312000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l24a_3p075: ldo24 {
+                       regulator-min-microvolt = <3088000>;
+                       regulator-max-microvolt = <3088000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l25a_3p3: ldo25 {
+                       regulator-min-microvolt = <3000000>;
+                       regulator-max-microvolt = <3312000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-always-on;
+               };
+
+               vdda_mipi_dsi0_1p2:
+               vdda_ufs1_1p2:
+               vreg_l26a_1p2: ldo26 {
+                       regulator-min-microvolt = <1200000>;
+                       regulator-max-microvolt = <1200000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+               };
+
+               vreg_l28a_3p0: ldo28 {
+                       regulator-min-microvolt = <2856000>;
+                       regulator-max-microvolt = <3008000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+                       regulator-always-on;
+               };
+
+               vreg_lvs1a_1p8: lvs1 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+               };
+
+               vreg_lvs2a_1p8: lvs2 {
+                       regulator-min-microvolt = <1800000>;
+                       regulator-max-microvolt = <1800000>;
+               };
+       };
+
+       pmi8998-rpmh-regulators {
+               compatible = "qcom,pmi8998-rpmh-regulators";
+               qcom,pmic-id = "b";
+
+               vreg_bob: bob {
+                       regulator-min-microvolt = <3312000>;
+                       regulator-max-microvolt = <3600000>;
+                       regulator-initial-mode = <RPMH_REGULATOR_MODE_AUTO>;
+                       regulator-allow-bypass;
+               };
+       };
+
+       pm8005-rpmh-regulators {
+               compatible = "qcom,pm8005-rpmh-regulators";
+               qcom,pmic-id = "c";
+
+               vreg_smp3c_0p6: smps3 {
+                       regulator-min-microvolt = <600000>;
+                       regulator-max-microvolt = <600000>;
+                       regulator-always-on;
+               };
+       };
+};
+
+&cdsp_pas {
+       firmware-name = "qcom/sdm845/polaris/cdsp.mbn";
+       status = "okay";
+};
+
+&dsi0 {
+       vdda-supply = <&vdda_mipi_dsi0_1p2>;
+       status = "okay";
+
+       display_panel: panel@0 {
+               compatible = "jdi,fhd-nt35596s";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0>;
+
+               reset-gpios = <&tlmm 6 GPIO_ACTIVE_LOW>;
+               vddio-supply = <&vreg_l14a_1p8>;
+               backlight = <&pmi8998_wled>;
+               vddpos-supply = <&lab>;
+               vddneg-supply = <&ibb>;
+
+               pinctrl-names = "default", "sleep";
+               pinctrl-0 = <&sde_dsi_active>;
+               pinctrl-1 = <&sde_dsi_suspend>;
+
+               port {
+                       panel_in: endpoint {
+                               remote-endpoint = <&dsi0_out>;
+                       };
+               };
+       };
+};
+
+&dsi0_out {
+       remote-endpoint = <&panel_in>;
+       data-lanes = <0 1 2 3>;
+};
+
+&dsi0_phy {
+       vdds-supply = <&vdda_mipi_dsi0_pll>;
+       status = "okay";
+};
+
+&gcc {
+       protected-clocks = <GCC_QSPI_CORE_CLK>,
+                               <GCC_QSPI_CORE_CLK_SRC>,
+                               <GCC_QSPI_CNOC_PERIPH_AHB_CLK>,
+                               <GCC_LPASS_Q6_AXI_CLK>,
+                               <GCC_LPASS_SWAY_CLK>;
+};
+
+&gmu {
+       status = "okay";
+};
+
+&gpi_dma0 {
+       status = "okay";
+};
+
+&gpi_dma1 {
+       status = "okay";
+};
+
+&gpu {
+       status = "okay";
+
+       zap-shader {
+               memory-region = <&gpu_mem>;
+               firmware-name = "qcom/sdm845/polaris/a630_zap.mbn";
+       };
+};
+
+&ibb {
+       regulator-min-microvolt = <4600000>;
+       regulator-max-microvolt = <6000000>;
+       regulator-over-current-protection;
+       regulator-pull-down;
+       regulator-soft-start;
+       qcom,discharge-resistor-kohms = <300>;
+};
+
+&ipa {
+       memory-region = <&ipa_fw_mem>;
+       firmware-name = "qcom/sdm845/polaris/ipa_fws.mbn";
+       status = "okay";
+};
+
+&i2c14 {
+       clock-frequency = <400000>;
+       dmas = <&gpi_dma1 0 6 QCOM_GPI_I2C>,
+                  <&gpi_dma1 1 6 QCOM_GPI_I2C>;
+       dma-names = "tx", "rx";
+       status = "okay";
+
+       touchscreen@20 {
+               compatible = "syna,rmi4-i2c";
+               reg = <0x20>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               interrupts-extended = <&tlmm 125 0x2008>;
+
+               pinctrl-names = "default", "sleep";
+               pinctrl-0 = <&ts_int_default &ts_reset_default>;
+               pinctrl-1 = <&ts_int_sleep &ts_reset_sleep>;
+
+               vdd-supply = <&vreg_l28a_3p0>;
+               vio-supply = <&vreg_tp_vddio>;
+
+               syna,startup-delay-ms = <0xc8>;
+               syna,reset-delay-ms = <0xc8>;
+
+               rmi4-f01@1 {
+                       syna,nosleep-mode = <0x1>;
+                       reg = <0x1>;
+               };
+
+               rmi4-f12@12 {
+                       syna,rezero-wait-ms = <0xc8>;
+                       syna,clip-x-high = <0x438>;
+                       syna,clip-y-high = <0x870>;
+                       syna,sensor-type = <0x1>;
+                       syna,clip-x-low = <0x0>;
+                       syna,clip-y-low = <0x0>;
+               };
+       };
+};
+
+&lab {
+       regulator-min-microvolt = <4600000>;
+       regulator-max-microvolt = <6000000>;
+       regulator-soft-start;
+       regulator-pull-down;
+};
+
+&mdss {
+       status = "okay";
+};
+
+&mss_pil {
+       firmware-name = "qcom/sdm845/polaris/mba.mbn", "qcom/sdm845/polaris/modem.mbn";
+       status = "okay";
+};
+
+&pmi8998_wled {
+       qcom,current-limit-microamp = <20000>;
+       qcom,current-boost-limit = <970>;
+       qcom,ovp-millivolt = <19600>;
+       qcom,switching-freq = <600>;
+       qcom,num-strings = <4>;
+       qcom,cabc;
+
+       status = "okay";
+};
+
+&pm8998_gpio {
+       volume_up_gpio: pm8998_gpio6 {
+               pinconf {
+                       qcom,drive-strength = <PMIC_GPIO_STRENGTH_NO>;
+                       function = "normal";
+                       pins = "gpio6";
+                       input-enable;
+                       bias-pull-up;
+               };
+       };
+};
+
+&pm8998_pon {
+       resin {
+               interrupts = <0x0 0x8 1 IRQ_TYPE_EDGE_BOTH>;
+               compatible = "qcom,pm8941-resin";
+               linux,code = <KEY_VOLUMEDOWN>;
+               debounce = <15625>;
+               bias-pull-up;
+       };
+};
+
+&q6afedai {
+       qi2s@22 {
+               reg = <22>;
+               qcom,sd-lines = <0>;
+       };
+};
+
+&q6asmdai {
+       dai@0 {
+               reg = <0>;
+       };
+
+       dai@1 {
+               reg = <1>;
+       };
+
+       dai@2 {
+               reg = <2>;
+       };
+};
+
+&qupv3_id_0 {
+       status = "okay";
+};
+
+&qupv3_id_1 {
+       status = "okay";
+};
+
+&qup_i2c14_default {
+       pinconf {
+               pins = "gpio33", "gpio34";
+               drive-strength = <2>;
+               bias-disable;
+       };
+};
+
+&tlmm {
+       gpio-reserved-ranges = <0 4>, <81 4>;
+
+       ts_reset_default: ts-reset-default {
+               pins = "gpio99";
+               function = "gpio";
+               drive-strength = <16>;
+               output-high;
+       };
+
+       ts_int_default: ts-int-default {
+               pins = "gpio125";
+               function = "gpio";
+               bias-pull-down;
+               drive-strength = <16>;
+               input-enable;
+       };
+
+       ts_reset_sleep: ts-reset-sleep {
+               pins = "gpio99";
+               function = "gpio";
+               bias-disable;
+               drive-strength = <2>;
+       };
+
+       ts_int_sleep: ts-int-sleep {
+               pins = "gpio125";
+               function = "gpio";
+               bias-pull-down;
+               drive-strength = <2>;
+               input-enable;
+       };
+
+       sde_dsi_active: sde-dsi-active {
+               pins = "gpio6", "gpio10";
+               function = "gpio";
+               drive-strength = <8>;
+               bias-disable = <0>;
+       };
+
+       sde_dsi_suspend: sde-dsi-suspend {
+               pins = "gpio6", "gpio10";
+               function = "gpio";
+               drive-strength = <2>;
+               bias-pull-down;
+       };
+
+       wcd_intr_default: wcd-intr-default {
+               pins = "goui54";
+               function = "gpio";
+               input-enable;
+               bias-pull-down;
+               drive-strength = <2>;
+       };
+};
+
+&uart6 {
+       status = "okay";
+
+       bluetooth {
+               compatible = "qcom,wcn3990-bt";
+
+               /* This path is relative to the qca/ subdir under lib/firmware. */
+               firmware-name = "polaris/crnv21.bin";
+
+               vddio-supply = <&vreg_s4a_1p8>;
+               vddxo-supply = <&vreg_l7a_1p8>;
+               vddrf-supply = <&vreg_l17a_1p3>;
+               vddch0-supply = <&vreg_l25a_3p3>;
+               max-speed = <3200000>;
+       };
+};
+
+&usb_1 {
+       /* We'll use this as USB 2.0 only */
+       qcom,select-utmi-as-pipe-clk;
+       status = "okay";
+};
+
+&usb_1_dwc3 {
+       dr_mode = "peripheral";
+
+       /* Fastest mode for USB 2 */
+       maximum-speed = "high-speed";
+
+       /* Remove USB3 phy */
+       phys = <&usb_1_hsphy>;
+       phy-names = "usb2-phy";
+};
+
+&usb_1_hsphy {
+       vdda-phy-dpdm-supply = <&vreg_l24a_3p075>;
+       vdda-pll-supply = <&vreg_l12a_1p8>;
+       vdd-supply = <&vreg_l1a_0p875>;
+
+       qcom,preemphasis-width = <QUSB2_V2_PREEMPHASIS_WIDTH_HALF_BIT>;
+       qcom,preemphasis-level = <QUSB2_V2_PREEMPHASIS_5_PERCENT>;
+       qcom,hstx-trim-value = <QUSB2_V2_HSTX_TRIM_21_6_MA>;
+       qcom,imp-res-offset-value = <8>;
+
+       status = "okay";
+};
+
+&usb_1_qmpphy {
+       vdda-pll-supply = <&vreg_l1a_0p875>;
+       vdda-phy-supply = <&vreg_l26a_1p2>;
+       status = "okay";
+};
+
+&ufs_mem_hc {
+       reset-gpios = <&tlmm 150 GPIO_ACTIVE_LOW>;
+       vcc-supply = <&vreg_l20a_2p95>;
+       vcc-max-microamp = <800000>;
+       status = "okay";
+};
+
+&ufs_mem_phy {
+       vdda-phy-supply = <&vdda_ufs1_core>;
+       vdda-pll-supply = <&vdda_ufs1_1p2>;
+       status = "okay";
+};
+
+&venus {
+       firmware-name = "qcom/sdm845/polaris/venus.mbn";
+       status = "okay";
+};
+
+&wcd9340 {
+       pinctrl-0 = <&wcd_intr_default>;
+       pinctrl-names = "default";
+       clock-names = "extclk";
+       clocks = <&rpmhcc RPMH_LN_BB_CLK2>;
+       reset-gpios = <&tlmm 64 0>;
+       vdd-buck-sido-supply = <&vreg_s4a_1p8>;
+       vdd-buck-supply = <&vreg_s4a_1p8>;
+       vdd-tx-supply = <&vreg_s4a_1p8>;
+       vdd-rx-supply = <&vreg_s4a_1p8>;
+       vdd-io-supply = <&vreg_s4a_1p8>;
+
+       qcom,micbias1-microvolt = <2700000>;
+       qcom,micbias2-microvolt = <1800000>;
+       qcom,micbias3-microvolt = <2700000>;
+       qcom,micbias4-microvolt = <2700000>;
+};
+
+&wifi {
+       vdd-0.8-cx-mx-supply = <&vreg_l5a_0p8>;
+       vdd-1.8-xo-supply = <&vreg_l7a_1p8>;
+       vdd-1.3-rfa-supply = <&vreg_l17a_1p3>;
+       vdd-3.3-ch0-supply = <&vreg_l25a_3p3>;
+       vdd-3.3-ch1-supply = <&vreg_l23a_3p3>;
+
+       qcom,snoc-host-cap-skip-quirk;
+       status = "okay";
+};
+
+/* PINCTRL - additions to nodes defined in sdm845.dtsi */
+
+&qup_uart6_default {
+       pinmux {
+                pins = "gpio45", "gpio46", "gpio47", "gpio48";
+                function = "qup6";
+       };
+
+       cts {
+               pins = "gpio45";
+               bias-disable;
+       };
+
+       rts-tx {
+               pins = "gpio46", "gpio47";
+               drive-strength = <2>;
+               bias-disable;
+       };
+
+       rx {
+               pins = "gpio48";
+               bias-pull-up;
+       };
+};
index 0692ae0..f0e2867 100644 (file)
                };
        };
 
-       cpus {
+       cpus: cpus {
                #address-cells = <2>;
                #size-cells = <0>;
 
                        compatible = "qcom,kryo385";
                        reg = <0x0 0x0>;
                        enable-method = "psci";
-                       cpu-idle-states = <&LITTLE_CPU_SLEEP_0
-                                          &LITTLE_CPU_SLEEP_1
-                                          &CLUSTER_SLEEP_0>;
                        capacity-dmips-mhz = <611>;
                        dynamic-power-coefficient = <290>;
                        qcom,freq-domain = <&cpufreq_hw 0>;
                        operating-points-v2 = <&cpu0_opp_table>;
                        interconnects = <&gladiator_noc MASTER_APPSS_PROC 3 &mem_noc SLAVE_EBI1 3>,
                                        <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>;
+                       power-domains = <&CPU_PD0>;
+                       power-domain-names = "psci";
                        #cooling-cells = <2>;
                        next-level-cache = <&L2_0>;
                        L2_0: l2-cache {
                        compatible = "qcom,kryo385";
                        reg = <0x0 0x100>;
                        enable-method = "psci";
-                       cpu-idle-states = <&LITTLE_CPU_SLEEP_0
-                                          &LITTLE_CPU_SLEEP_1
-                                          &CLUSTER_SLEEP_0>;
                        capacity-dmips-mhz = <611>;
                        dynamic-power-coefficient = <290>;
                        qcom,freq-domain = <&cpufreq_hw 0>;
                        operating-points-v2 = <&cpu0_opp_table>;
                        interconnects = <&gladiator_noc MASTER_APPSS_PROC 3 &mem_noc SLAVE_EBI1 3>,
                                        <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>;
+                       power-domains = <&CPU_PD1>;
+                       power-domain-names = "psci";
                        #cooling-cells = <2>;
                        next-level-cache = <&L2_100>;
                        L2_100: l2-cache {
                        compatible = "qcom,kryo385";
                        reg = <0x0 0x200>;
                        enable-method = "psci";
-                       cpu-idle-states = <&LITTLE_CPU_SLEEP_0
-                                          &LITTLE_CPU_SLEEP_1
-                                          &CLUSTER_SLEEP_0>;
                        capacity-dmips-mhz = <611>;
                        dynamic-power-coefficient = <290>;
                        qcom,freq-domain = <&cpufreq_hw 0>;
                        operating-points-v2 = <&cpu0_opp_table>;
                        interconnects = <&gladiator_noc MASTER_APPSS_PROC 3 &mem_noc SLAVE_EBI1 3>,
                                        <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>;
+                       power-domains = <&CPU_PD2>;
+                       power-domain-names = "psci";
                        #cooling-cells = <2>;
                        next-level-cache = <&L2_200>;
                        L2_200: l2-cache {
                        compatible = "qcom,kryo385";
                        reg = <0x0 0x300>;
                        enable-method = "psci";
-                       cpu-idle-states = <&LITTLE_CPU_SLEEP_0
-                                          &LITTLE_CPU_SLEEP_1
-                                          &CLUSTER_SLEEP_0>;
                        capacity-dmips-mhz = <611>;
                        dynamic-power-coefficient = <290>;
                        qcom,freq-domain = <&cpufreq_hw 0>;
                        interconnects = <&gladiator_noc MASTER_APPSS_PROC 3 &mem_noc SLAVE_EBI1 3>,
                                        <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>;
                        #cooling-cells = <2>;
+                       power-domains = <&CPU_PD3>;
+                       power-domain-names = "psci";
                        next-level-cache = <&L2_300>;
                        L2_300: l2-cache {
                                compatible = "cache";
                        reg = <0x0 0x400>;
                        enable-method = "psci";
                        capacity-dmips-mhz = <1024>;
-                       cpu-idle-states = <&BIG_CPU_SLEEP_0
-                                          &BIG_CPU_SLEEP_1
-                                          &CLUSTER_SLEEP_0>;
                        dynamic-power-coefficient = <442>;
                        qcom,freq-domain = <&cpufreq_hw 1>;
                        operating-points-v2 = <&cpu4_opp_table>;
                        interconnects = <&gladiator_noc MASTER_APPSS_PROC 3 &mem_noc SLAVE_EBI1 3>,
                                        <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>;
+                       power-domains = <&CPU_PD4>;
+                       power-domain-names = "psci";
                        #cooling-cells = <2>;
                        next-level-cache = <&L2_400>;
                        L2_400: l2-cache {
                        reg = <0x0 0x500>;
                        enable-method = "psci";
                        capacity-dmips-mhz = <1024>;
-                       cpu-idle-states = <&BIG_CPU_SLEEP_0
-                                          &BIG_CPU_SLEEP_1
-                                          &CLUSTER_SLEEP_0>;
                        dynamic-power-coefficient = <442>;
                        qcom,freq-domain = <&cpufreq_hw 1>;
                        operating-points-v2 = <&cpu4_opp_table>;
                        interconnects = <&gladiator_noc MASTER_APPSS_PROC 3 &mem_noc SLAVE_EBI1 3>,
                                        <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>;
+                       power-domains = <&CPU_PD5>;
+                       power-domain-names = "psci";
                        #cooling-cells = <2>;
                        next-level-cache = <&L2_500>;
                        L2_500: l2-cache {
                        reg = <0x0 0x600>;
                        enable-method = "psci";
                        capacity-dmips-mhz = <1024>;
-                       cpu-idle-states = <&BIG_CPU_SLEEP_0
-                                          &BIG_CPU_SLEEP_1
-                                          &CLUSTER_SLEEP_0>;
                        dynamic-power-coefficient = <442>;
                        qcom,freq-domain = <&cpufreq_hw 1>;
                        operating-points-v2 = <&cpu4_opp_table>;
                        interconnects = <&gladiator_noc MASTER_APPSS_PROC 3 &mem_noc SLAVE_EBI1 3>,
                                        <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>;
+                       power-domains = <&CPU_PD6>;
+                       power-domain-names = "psci";
                        #cooling-cells = <2>;
                        next-level-cache = <&L2_600>;
                        L2_600: l2-cache {
                        reg = <0x0 0x700>;
                        enable-method = "psci";
                        capacity-dmips-mhz = <1024>;
-                       cpu-idle-states = <&BIG_CPU_SLEEP_0
-                                          &BIG_CPU_SLEEP_1
-                                          &CLUSTER_SLEEP_0>;
                        dynamic-power-coefficient = <442>;
                        qcom,freq-domain = <&cpufreq_hw 1>;
                        operating-points-v2 = <&cpu4_opp_table>;
                        interconnects = <&gladiator_noc MASTER_APPSS_PROC 3 &mem_noc SLAVE_EBI1 3>,
                                        <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>;
+                       power-domains = <&CPU_PD7>;
+                       power-domain-names = "psci";
                        #cooling-cells = <2>;
                        next-level-cache = <&L2_700>;
                        L2_700: l2-cache {
                        };
                };
 
-               idle-states {
+               cpu_idle_states: idle-states {
                        entry-method = "psci";
 
                        LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 {
                                compatible = "arm,idle-state";
-                               idle-state-name = "little-power-down";
-                               arm,psci-suspend-param = <0x40000003>;
+                               idle-state-name = "little-rail-power-collapse";
+                               arm,psci-suspend-param = <0x40000004>;
                                entry-latency-us = <350>;
                                exit-latency-us = <461>;
                                min-residency-us = <1890>;
                                local-timer-stop;
                        };
 
-                       LITTLE_CPU_SLEEP_1: cpu-sleep-0-1 {
-                               compatible = "arm,idle-state";
-                               idle-state-name = "little-rail-power-down";
-                               arm,psci-suspend-param = <0x40000004>;
-                               entry-latency-us = <360>;
-                               exit-latency-us = <531>;
-                               min-residency-us = <3934>;
-                               local-timer-stop;
-                       };
-
                        BIG_CPU_SLEEP_0: cpu-sleep-1-0 {
                                compatible = "arm,idle-state";
-                               idle-state-name = "big-power-down";
-                               arm,psci-suspend-param = <0x40000003>;
+                               idle-state-name = "big-rail-power-collapse";
+                               arm,psci-suspend-param = <0x40000004>;
                                entry-latency-us = <264>;
                                exit-latency-us = <621>;
                                min-residency-us = <952>;
                                local-timer-stop;
                        };
+               };
 
-                       BIG_CPU_SLEEP_1: cpu-sleep-1-1 {
-                               compatible = "arm,idle-state";
-                               idle-state-name = "big-rail-power-down";
-                               arm,psci-suspend-param = <0x40000004>;
-                               entry-latency-us = <702>;
-                               exit-latency-us = <1061>;
-                               min-residency-us = <4488>;
-                               local-timer-stop;
-                       };
-
+               domain-idle-states {
                        CLUSTER_SLEEP_0: cluster-sleep-0 {
-                               compatible = "arm,idle-state";
-                               idle-state-name = "cluster-power-down";
-                               arm,psci-suspend-param = <0x400000F4>;
+                               compatible = "domain-idle-state";
+                               idle-state-name = "cluster-power-collapse";
+                               arm,psci-suspend-param = <0x4100c244>;
                                entry-latency-us = <3263>;
                                exit-latency-us = <6562>;
                                min-residency-us = <9987>;
                };
        };
 
-       cpu0_opp_table: cpu0_opp_table {
+       cpu0_opp_table: opp-table-cpu0 {
                compatible = "operating-points-v2";
                opp-shared;
 
                };
        };
 
-       cpu4_opp_table: cpu4_opp_table {
+       cpu4_opp_table: opp-table-cpu4 {
                compatible = "operating-points-v2";
                opp-shared;
 
                };
        };
 
-       psci {
+       psci: psci {
                compatible = "arm,psci-1.0";
                method = "smc";
+
+               CPU_PD0: power-domain-cpu0 {
+                       #power-domain-cells = <0>;
+                       power-domains = <&CLUSTER_PD>;
+                       domain-idle-states = <&LITTLE_CPU_SLEEP_0>;
+               };
+
+               CPU_PD1: power-domain-cpu1 {
+                       #power-domain-cells = <0>;
+                       power-domains = <&CLUSTER_PD>;
+                       domain-idle-states = <&LITTLE_CPU_SLEEP_0>;
+               };
+
+               CPU_PD2: power-domain-cpu2 {
+                       #power-domain-cells = <0>;
+                       power-domains = <&CLUSTER_PD>;
+                       domain-idle-states = <&LITTLE_CPU_SLEEP_0>;
+               };
+
+               CPU_PD3: power-domain-cpu3 {
+                       #power-domain-cells = <0>;
+                       power-domains = <&CLUSTER_PD>;
+                       domain-idle-states = <&LITTLE_CPU_SLEEP_0>;
+               };
+
+               CPU_PD4: power-domain-cpu4 {
+                       #power-domain-cells = <0>;
+                       power-domains = <&CLUSTER_PD>;
+                       domain-idle-states = <&BIG_CPU_SLEEP_0>;
+               };
+
+               CPU_PD5: power-domain-cpu5 {
+                       #power-domain-cells = <0>;
+                       power-domains = <&CLUSTER_PD>;
+                       domain-idle-states = <&BIG_CPU_SLEEP_0>;
+               };
+
+               CPU_PD6: power-domain-cpu6 {
+                       #power-domain-cells = <0>;
+                       power-domains = <&CLUSTER_PD>;
+                       domain-idle-states = <&BIG_CPU_SLEEP_0>;
+               };
+
+               CPU_PD7: power-domain-cpu7 {
+                       #power-domain-cells = <0>;
+                       power-domains = <&CLUSTER_PD>;
+                       domain-idle-states = <&BIG_CPU_SLEEP_0>;
+               };
+
+               CLUSTER_PD: power-domain-cluster {
+                       #power-domain-cells = <0>;
+                       domain-idle-states = <&CLUSTER_SLEEP_0>;
+               };
        };
 
        soc: soc@0 {
                        clock-names = "core";
                };
 
-               qup_opp_table: qup-opp-table {
+               qup_opp_table: opp-table-qup {
                        compatible = "operating-points-v2";
 
                        opp-50000000 {
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_1 0>,
                                                <&aggre1_noc MASTER_QUP_1 0 &mem_noc SLAVE_EBI1 0>;
                                interconnect-names = "qup-core", "qup-config", "qup-memory";
+                               dmas = <&gpi_dma0 0 0 QCOM_GPI_I2C>,
+                                      <&gpi_dma0 1 0 QCOM_GPI_I2C>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_1 0>,
                                                <&aggre1_noc MASTER_QUP_1 0 &mem_noc SLAVE_EBI1 0>;
                                interconnect-names = "qup-core", "qup-config", "qup-memory";
+                               dmas = <&gpi_dma0 0 1 QCOM_GPI_I2C>,
+                                      <&gpi_dma0 1 1 QCOM_GPI_I2C>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                interconnects = <&aggre1_noc MASTER_QUP_1 0 &config_noc SLAVE_BLSP_1 0>,
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_1 0>;
                                interconnect-names = "qup-core", "qup-config";
+                               dmas = <&gpi_dma0 0 1 QCOM_GPI_SPI>,
+                                      <&gpi_dma0 1 1 QCOM_GPI_SPI>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_1 0>,
                                                <&aggre1_noc MASTER_QUP_1 0 &mem_noc SLAVE_EBI1 0>;
                                interconnect-names = "qup-core", "qup-config", "qup-memory";
+                               dmas = <&gpi_dma0 0 2 QCOM_GPI_I2C>,
+                                      <&gpi_dma0 1 2 QCOM_GPI_I2C>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                interconnects = <&aggre1_noc MASTER_QUP_1 0 &config_noc SLAVE_BLSP_1 0>,
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_1 0>;
                                interconnect-names = "qup-core", "qup-config";
+                               dmas = <&gpi_dma0 0 2 QCOM_GPI_SPI>,
+                                      <&gpi_dma0 1 2 QCOM_GPI_SPI>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_1 0>,
                                                <&aggre1_noc MASTER_QUP_1 0 &mem_noc SLAVE_EBI1 0>;
                                interconnect-names = "qup-core", "qup-config", "qup-memory";
+                               dmas = <&gpi_dma0 0 3 QCOM_GPI_I2C>,
+                                      <&gpi_dma0 1 3 QCOM_GPI_I2C>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                interconnects = <&aggre1_noc MASTER_QUP_1 0 &config_noc SLAVE_BLSP_1 0>,
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_1 0>;
                                interconnect-names = "qup-core", "qup-config";
+                               dmas = <&gpi_dma0 0 3 QCOM_GPI_SPI>,
+                                      <&gpi_dma0 1 3 QCOM_GPI_SPI>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_1 0>,
                                                <&aggre1_noc MASTER_QUP_1 0 &mem_noc SLAVE_EBI1 0>;
                                interconnect-names = "qup-core", "qup-config", "qup-memory";
+                               dmas = <&gpi_dma0 0 4 QCOM_GPI_I2C>,
+                                      <&gpi_dma0 1 4 QCOM_GPI_I2C>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                interconnects = <&aggre1_noc MASTER_QUP_1 0 &config_noc SLAVE_BLSP_1 0>,
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_1 0>;
                                interconnect-names = "qup-core", "qup-config";
+                               dmas = <&gpi_dma0 0 4 QCOM_GPI_SPI>,
+                                      <&gpi_dma0 1 4 QCOM_GPI_SPI>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_1 0>,
                                                <&aggre1_noc MASTER_QUP_1 0 &mem_noc SLAVE_EBI1 0>;
                                interconnect-names = "qup-core", "qup-config", "qup-memory";
+                               dmas = <&gpi_dma0 0 5 QCOM_GPI_I2C>,
+                                      <&gpi_dma0 1 5 QCOM_GPI_I2C>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                interconnects = <&aggre1_noc MASTER_QUP_1 0 &config_noc SLAVE_BLSP_1 0>,
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_1 0>;
                                interconnect-names = "qup-core", "qup-config";
+                               dmas = <&gpi_dma0 0 5 QCOM_GPI_SPI>,
+                                      <&gpi_dma0 1 5 QCOM_GPI_SPI>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_1 0>,
                                                <&aggre1_noc MASTER_QUP_1 0 &mem_noc SLAVE_EBI1 0>;
                                interconnect-names = "qup-core", "qup-config", "qup-memory";
+                               dmas = <&gpi_dma0 0 6 QCOM_GPI_I2C>,
+                                      <&gpi_dma0 1 6 QCOM_GPI_I2C>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                interconnects = <&aggre1_noc MASTER_QUP_1 0 &config_noc SLAVE_BLSP_1 0>,
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_1 0>;
                                interconnect-names = "qup-core", "qup-config";
+                               dmas = <&gpi_dma0 0 6 QCOM_GPI_SPI>,
+                                      <&gpi_dma0 1 6 QCOM_GPI_SPI>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                interconnects = <&aggre1_noc MASTER_QUP_1 0 &config_noc SLAVE_BLSP_1 0>,
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_1 0>;
                                interconnect-names = "qup-core", "qup-config";
+                               dmas = <&gpi_dma0 0 7 QCOM_GPI_SPI>,
+                                      <&gpi_dma0 1 7 QCOM_GPI_SPI>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_2 0>,
                                                <&aggre2_noc MASTER_QUP_2 0 &mem_noc SLAVE_EBI1 0>;
                                interconnect-names = "qup-core", "qup-config", "qup-memory";
+                               dmas = <&gpi_dma1 0 0 QCOM_GPI_I2C>,
+                                      <&gpi_dma1 1 0 QCOM_GPI_I2C>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                interconnects = <&aggre2_noc MASTER_QUP_2 0 &config_noc SLAVE_BLSP_2 0>,
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_2 0>;
                                interconnect-names = "qup-core", "qup-config";
+                               dmas = <&gpi_dma1 0 0 QCOM_GPI_SPI>,
+                                      <&gpi_dma1 1 0 QCOM_GPI_SPI>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_2 0>,
                                                <&aggre2_noc MASTER_QUP_2 0 &mem_noc SLAVE_EBI1 0>;
                                interconnect-names = "qup-core", "qup-config", "qup-memory";
+                               dmas = <&gpi_dma1 0 1 QCOM_GPI_I2C>,
+                                      <&gpi_dma1 1 1 QCOM_GPI_I2C>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                interconnects = <&aggre2_noc MASTER_QUP_2 0 &config_noc SLAVE_BLSP_2 0>,
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_2 0>;
                                interconnect-names = "qup-core", "qup-config";
+                               dmas = <&gpi_dma1 0 1 QCOM_GPI_SPI>,
+                                      <&gpi_dma1 1 1 QCOM_GPI_SPI>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_2 0>,
                                                <&aggre2_noc MASTER_QUP_2 0 &mem_noc SLAVE_EBI1 0>;
                                interconnect-names = "qup-core", "qup-config", "qup-memory";
+                               dmas = <&gpi_dma1 0 2 QCOM_GPI_I2C>,
+                                      <&gpi_dma1 1 2 QCOM_GPI_I2C>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                interconnects = <&aggre2_noc MASTER_QUP_2 0 &config_noc SLAVE_BLSP_2 0>,
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_2 0>;
                                interconnect-names = "qup-core", "qup-config";
+                               dmas = <&gpi_dma1 0 2 QCOM_GPI_SPI>,
+                                      <&gpi_dma1 1 2 QCOM_GPI_SPI>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_2 0>,
                                                <&aggre2_noc MASTER_QUP_2 0 &mem_noc SLAVE_EBI1 0>;
                                interconnect-names = "qup-core", "qup-config", "qup-memory";
+                               dmas = <&gpi_dma1 0 3 QCOM_GPI_I2C>,
+                                      <&gpi_dma1 1 3 QCOM_GPI_I2C>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                interconnects = <&aggre2_noc MASTER_QUP_2 0 &config_noc SLAVE_BLSP_2 0>,
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_2 0>;
                                interconnect-names = "qup-core", "qup-config";
+                               dmas = <&gpi_dma1 0 3 QCOM_GPI_SPI>,
+                                      <&gpi_dma1 1 3 QCOM_GPI_SPI>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_2 0>,
                                                <&aggre2_noc MASTER_QUP_2 0 &mem_noc SLAVE_EBI1 0>;
                                interconnect-names = "qup-core", "qup-config", "qup-memory";
+                               dmas = <&gpi_dma1 0 4 QCOM_GPI_I2C>,
+                                      <&gpi_dma1 1 4 QCOM_GPI_I2C>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                interconnects = <&aggre2_noc MASTER_QUP_2 0 &config_noc SLAVE_BLSP_2 0>,
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_2 0>;
                                interconnect-names = "qup-core", "qup-config";
+                               dmas = <&gpi_dma1 0 4 QCOM_GPI_SPI>,
+                                      <&gpi_dma1 1 4 QCOM_GPI_SPI>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_2 0>,
                                                <&aggre2_noc MASTER_QUP_2 0 &mem_noc SLAVE_EBI1 0>;
                                interconnect-names = "qup-core", "qup-config", "qup-memory";
+                               dmas = <&gpi_dma1 0 5 QCOM_GPI_I2C>,
+                                      <&gpi_dma1 1 5 QCOM_GPI_I2C>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                interconnects = <&aggre2_noc MASTER_QUP_2 0 &config_noc SLAVE_BLSP_2 0>,
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_2 0>;
                                interconnect-names = "qup-core", "qup-config";
+                               dmas = <&gpi_dma1 0 5 QCOM_GPI_SPI>,
+                                      <&gpi_dma1 1 5 QCOM_GPI_SPI>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_2 0>,
                                                <&aggre2_noc MASTER_QUP_2 0 &mem_noc SLAVE_EBI1 0>;
                                interconnect-names = "qup-core", "qup-config", "qup-memory";
+                               dmas = <&gpi_dma1 0 6 QCOM_GPI_I2C>,
+                                      <&gpi_dma1 1 6 QCOM_GPI_I2C>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                interconnects = <&aggre2_noc MASTER_QUP_2 0 &config_noc SLAVE_BLSP_2 0>,
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_2 0>;
                                interconnect-names = "qup-core", "qup-config";
+                               dmas = <&gpi_dma1 0 6 QCOM_GPI_SPI>,
+                                      <&gpi_dma1 1 6 QCOM_GPI_SPI>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_2 0>,
                                                <&aggre2_noc MASTER_QUP_2 0 &mem_noc SLAVE_EBI1 0>;
                                interconnect-names = "qup-core", "qup-config", "qup-memory";
+                               dmas = <&gpi_dma1 0 7 QCOM_GPI_I2C>,
+                                      <&gpi_dma1 1 7 QCOM_GPI_I2C>;
+                               dma-names = "tx", "rx";
                        };
 
                        spi15: spi@a9c000 {
                                interconnects = <&aggre2_noc MASTER_QUP_2 0 &config_noc SLAVE_BLSP_2 0>,
                                                <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_BLSP_2 0>;
                                interconnect-names = "qup-core", "qup-config";
+                               dmas = <&gpi_dma1 0 7 QCOM_GPI_SPI>,
+                                      <&gpi_dma1 1 7 QCOM_GPI_SPI>;
+                               dma-names = "tx", "rx";
                                status = "disabled";
                        };
 
                        interrupts = <GIC_SPI 582 IRQ_TYPE_LEVEL_HIGH>;
                };
 
+               pmu@1436400 {
+                       compatible = "qcom,sdm845-bwmon", "qcom,msm8998-bwmon";
+                       reg = <0 0x01436400 0 0x600>;
+                       interrupts = <GIC_SPI 581 IRQ_TYPE_LEVEL_HIGH>;
+                       interconnects = <&gladiator_noc MASTER_APPSS_PROC 3 &mem_noc SLAVE_LLCC 3>;
+
+                       operating-points-v2 = <&cpu_bwmon_opp_table>;
+
+                       cpu_bwmon_opp_table: opp-table {
+                               compatible = "operating-points-v2";
+
+                               /*
+                                * The interconnect path bandwidth taken from
+                                * cpu4_opp_table bandwidth for OSM L3
+                                * interconnect.  This also matches the OSM L3
+                                * from bandwidth table of qcom,cpu4-l3lat-mon
+                                * (qcom,core-dev-table, bus width: 16 bytes)
+                                * from msm-4.9 downstream kernel.
+                                */
+                               opp-0 {
+                                       opp-peak-kBps = <4800000>;
+                               };
+                               opp-1 {
+                                       opp-peak-kBps = <9216000>;
+                               };
+                               opp-2 {
+                                       opp-peak-kBps = <15052800>;
+                               };
+                               opp-3 {
+                                       opp-peak-kBps = <20889600>;
+                               };
+                               opp-4 {
+                                       opp-peak-kBps = <25497600>;
+                               };
+                       };
+               };
+
                pcie0: pci@1c00000 {
                        compatible = "qcom,pcie-sdm845";
                        reg = <0 0x01c00000 0 0x2000>,
                        };
                };
 
-               sdhc_2: sdhci@8804000 {
+               sdhc_2: mmc@8804000 {
                        compatible = "qcom,sdm845-sdhci", "qcom,sdhci-msm-v5";
                        reg = <0 0x08804000 0 0x1000>;
 
 
                        status = "disabled";
 
-                       sdhc2_opp_table: sdhc2-opp-table {
+                       sdhc2_opp_table: opp-table {
                                compatible = "operating-points-v2";
 
                                opp-9600000 {
                        };
                };
 
-               qspi_opp_table: qspi-opp-table {
+               qspi_opp_table: opp-table-qspi {
                        compatible = "operating-points-v2";
 
                        opp-19200000 {
                        qcom,apps-ch-pipes = <0x780000>;
                        qcom,ea-pc = <0x270>;
                        status = "okay";
-                       dmas =  <&slimbam 3>, <&slimbam 4>,
+                       dmas = <&slimbam 3>, <&slimbam 4>,
                                <&slimbam 5>, <&slimbam 6>;
                        dma-names = "rx", "tx", "tx2", "rx2";
 
 
                                wcd9340_ifd: ifd@0{
                                        compatible = "slim217,250";
-                                       reg  = <0 0>;
+                                       reg = <0 0>;
                                };
 
                                wcd9340: codec@1{
                                        compatible = "slim217,250";
-                                       reg  = <1 0>;
-                                       slim-ifc-dev  = <&wcd9340_ifd>;
+                                       reg = <1 0>;
+                                       slim-ifc-dev = <&wcd9340_ifd>;
 
                                        #sound-dai-cells = <1>;
 
                                                reg = <0xc85 0x40>;
                                                interrupts-extended = <&wcd9340 20>;
 
-                                               qcom,dout-ports = <6>;
-                                               qcom,din-ports  = <2>;
+                                               qcom,dout-ports = <6>;
+                                               qcom,din-ports = <2>;
                                                qcom,ports-sinterval-low =/bits/ 8  <0x07 0x1F 0x3F 0x7 0x1F 0x3F 0x0F 0x0F>;
                                                qcom,ports-offset1 = /bits/ 8 <0x01 0x02 0x0C 0x6 0x12 0x0D 0x07 0x0A >;
                                                qcom,ports-offset2 = /bits/ 8 <0x00 0x00 0x1F 0x00 0x00 0x1F 0x00 0x00>;
                                compatible = "venus-encoder";
                        };
 
-                       venus_opp_table: venus-opp-table {
+                       venus_opp_table: opp-table {
                                compatible = "operating-points-v2";
 
                                opp-100000000 {
                        clock-names = "bi_tcxo";
                };
 
-               dsi_opp_table: dsi-opp-table {
+               dsi_opp_table: opp-table-dsi {
                        compatible = "operating-points-v2";
 
                        opp-19200000 {
 
                        power-domains = <&dispcc MDSS_GDSC>;
 
-                       clocks = <&gcc GCC_DISP_AHB_CLK>,
+                       clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
                                 <&dispcc DISP_CC_MDSS_MDP_CLK>;
                        clock-names = "iface", "core";
 
-                       assigned-clocks = <&dispcc DISP_CC_MDSS_MDP_CLK>;
-                       assigned-clock-rates = <300000000>;
-
                        interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        #size-cells = <2>;
                        ranges;
 
-                       mdss_mdp: mdp@ae01000 {
+                       mdss_mdp: display-controller@ae01000 {
                                compatible = "qcom,sdm845-dpu";
                                reg = <0 0x0ae01000 0 0x8f000>,
                                      <0 0x0aeb0000 0 0x2008>;
                                         <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
                                clock-names = "gcc-bus", "iface", "bus", "core", "vsync";
 
-                               assigned-clocks = <&dispcc DISP_CC_MDSS_MDP_CLK>,
-                                                 <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
-                               assigned-clock-rates = <300000000>,
-                                                      <19200000>;
+                               assigned-clocks = <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
+                               assigned-clock-rates = <19200000>;
                                operating-points-v2 = <&mdp_opp_table>;
                                power-domains = <&rpmhpd SDM845_CX>;
 
                                        };
                                };
 
-                               mdp_opp_table: mdp-opp-table {
+                               mdp_opp_table: opp-table {
                                        compatible = "operating-points-v2";
 
                                        opp-19200000 {
                };
 
                gmu: gmu@506a000 {
-                       compatible="qcom,adreno-gmu-630.2", "qcom,adreno-gmu";
+                       compatible = "qcom,adreno-gmu-630.2", "qcom,adreno-gmu";
 
                        reg = <0 0x506a000 0 0x30000>,
                              <0 0xb280000 0 0x10000>,
                        cell-index = <0>;
                };
 
-               imem@146bf000 {
-                       compatible = "simple-mfd";
+               sram@146bf000 {
+                       compatible = "qcom,sdm845-imem", "syscon", "simple-mfd";
                        reg = <0 0x146bf000 0 0x1000>;
 
                        #address-cells = <1>;
                        compatible = "qcom,bam-v1.7.0";
                        qcom,controlled-remotely;
                        reg = <0 0x17184000 0 0x2a000>;
-                       num-channels  = <31>;
+                       num-channels = <31>;
                        interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
                        #dma-cells = <1>;
                        qcom,ee = <1>;
                };
 
                timer@17c90000 {
-                       #address-cells = <2>;
-                       #size-cells = <2>;
-                       ranges;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0 0 0 0x20000000>;
                        compatible = "arm,armv7-timer-mem";
                        reg = <0 0x17c90000 0 0x1000>;
 
                                frame-number = <0>;
                                interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0 0x17ca0000 0 0x1000>,
-                                     <0 0x17cb0000 0 0x1000>;
+                               reg = <0x17ca0000 0x1000>,
+                                     <0x17cb0000 0x1000>;
                        };
 
                        frame@17cc0000 {
                                frame-number = <1>;
                                interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0 0x17cc0000 0 0x1000>;
+                               reg = <0x17cc0000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17cd0000 {
                                frame-number = <2>;
                                interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0 0x17cd0000 0 0x1000>;
+                               reg = <0x17cd0000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17ce0000 {
                                frame-number = <3>;
                                interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0 0x17ce0000 0 0x1000>;
+                               reg = <0x17ce0000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17cf0000 {
                                frame-number = <4>;
                                interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0 0x17cf0000 0 0x1000>;
+                               reg = <0x17cf0000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17d00000 {
                                frame-number = <5>;
                                interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0 0x17d00000 0 0x1000>;
+                               reg = <0x17d00000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17d10000 {
                                frame-number = <6>;
                                interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0 0x17d10000 0 0x1000>;
+                               reg = <0x17d10000 0x1000>;
                                status = "disabled";
                        };
                };
index f1619b3..a7af1be 100644 (file)
@@ -41,7 +41,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&lid_pin_active>, <&mode_pin_active>;
 
-               lid {
+               switch-lid {
                        gpios = <&tlmm 124 GPIO_ACTIVE_HIGH>;
                        linux,input-type = <EV_SW>;
                        linux,code = <SW_LID>;
@@ -49,7 +49,7 @@
                        wakeup-event-action = <EV_ACT_DEASSERTED>;
                };
 
-               mode {
+               switch-mode {
                        gpios = <&tlmm 95 GPIO_ACTIVE_HIGH>;
                        linux,input-type = <EV_SW>;
                        linux,code = <SW_TABLET_MODE>;
                };
 
                codec {
-                       sound-dai =  <&left_spkr>, <&right_spkr>, <&swm 0>, <&wcd9340 0>;
+                       sound-dai = <&left_spkr>, <&right_spkr>, <&swm 0>, <&wcd9340 0>;
                };
        };
 
                };
 
                codec {
-                       sound-dai =  <&wcd9340 2>;
+                       sound-dai = <&wcd9340 2>;
                };
        };
 };
 
 &crypto {
        /* FIXME: qce_start triggers an SError */
-       status= "disable";
+       status = "disable";
 };
index 2a552d8..b0315ee 100644 (file)
                };
 
                codec {
-                       sound-dai =  <&left_spkr>, <&right_spkr>, <&swm 0>, <&wcd9340 0>;
+                       sound-dai = <&left_spkr>, <&right_spkr>, <&swm 0>, <&wcd9340 0>;
                };
        };
 
                };
 
                codec {
-                       sound-dai =  <&wcd9340 2>;
+                       sound-dai = <&wcd9340 2>;
                };
        };
 };
index b1c2cf5..da9f6fb 100644 (file)
@@ -16,6 +16,5 @@
        cpu4_opp34: opp-2956800000 {
                opp-hz = /bits/ 64 <2956800000>;
                opp-peak-kBps = <7216000 25497600>;
-               turbo-mode;
        };
 };
index 871ccbb..0aad2e9 100644 (file)
        gpio-keys {
                status = "okay";
                compatible = "gpio-keys";
-               #address-cells = <1>;
-               #size-cells = <0>;
                autorepeat;
 
-               vol-dn {
+               key-vol-dn {
                        label = "Volume Down";
                        gpios = <&tlmm 47 GPIO_ACTIVE_LOW>;
                        linux,input-type = <1>;
        status = "okay";
 };
 
-&sdc2_state_off {
+&sdc2_off_state {
        sd-cd {
                pins = "gpio98";
+               drive-strength = <2>;
                bias-disable;
+       };
+};
+
+&sdc2_on_state {
+       sd-cd {
+               pins = "gpio98";
                drive-strength = <2>;
+               bias-pull-up;
        };
 };
 
 
 &tlmm {
        gpio-reserved-ranges = <22 2>, <28 6>;
-
-       sdc2_state_on: sdc2-on {
-               clk {
-                       pins = "sdc2_clk";
-                       bias-disable;
-                       drive-strength = <16>;
-               };
-
-               cmd {
-                       pins = "sdc2_cmd";
-                       bias-pull-up;
-                       drive-strength = <10>;
-               };
-
-               data {
-                       pins = "sdc2_data";
-                       bias-pull-up;
-                       drive-strength = <10>;
-               };
-
-               sd-cd {
-                       pins = "gpio98";
-                       bias-pull-up;
-                       drive-strength = <2>;
-               };
-       };
 };
 
 &usb3 {
index 135e6e0..8c582a9 100644 (file)
                        interrupt-controller;
                        #interrupt-cells = <2>;
 
-                       sdc2_state_off: sdc2-off {
+                       sdc2_off_state: sdc2-off-state {
                                clk {
                                        pins = "sdc2_clk";
-                                       bias-disable;
                                        drive-strength = <2>;
+                                       bias-disable;
                                };
 
                                cmd {
                                        pins = "sdc2_cmd";
+                                       drive-strength = <2>;
                                        bias-pull-up;
+                               };
+
+                               data {
+                                       pins = "sdc2_data";
                                        drive-strength = <2>;
+                                       bias-pull-up;
+                               };
+                       };
+
+                       sdc2_on_state: sdc2-on-state {
+                               clk {
+                                       pins = "sdc2_clk";
+                                       drive-strength = <16>;
+                                       bias-disable;
+                               };
+
+                               cmd {
+                                       pins = "sdc2_cmd";
+                                       drive-strength = <10>;
+                                       bias-pull-up;
                                };
 
                                data {
                                        pins = "sdc2_data";
+                                       drive-strength = <10>;
                                        bias-pull-up;
-                                       drive-strength = <2>;
                                };
                        };
                };
                        reg = <0x045f0000 0x7000>;
                };
 
-               sdhc_1: sdhci@4744000 {
+               sdhc_1: mmc@4744000 {
                        compatible = "qcom,sm6125-sdhci", "qcom,sdhci-msm-v5";
                        reg = <0x04744000 0x1000>, <0x04745000 0x1000>;
                        reg-names = "hc", "core";
 
                        power-domains = <&rpmpd SM6125_VDDCX>;
 
+                       qcom,dll-config = <0x000f642c>;
+                       qcom,ddr-config = <0x80040873>;
+
                        bus-width = <8>;
                        non-removable;
                        status = "disabled";
                };
 
-               sdhc_2: sdhci@4784000 {
+               sdhc_2: mmc@4784000 {
                        compatible = "qcom,sm6125-sdhci", "qcom,sdhci-msm-v5";
                        reg = <0x04784000 0x1000>;
                        reg-names = "hc";
                                 <&xo_board>;
                        clock-names = "iface", "core", "xo";
 
-                       pinctrl-0 = <&sdc2_state_on>;
-                       pinctrl-1 = <&sdc2_state_off>;
+                       pinctrl-0 = <&sdc2_on_state>;
+                       pinctrl-1 = <&sdc2_off_state>;
                        pinctrl-names = "default", "sleep";
 
                        power-domains = <&rpmpd SM6125_VDDCX>;
 
+                       qcom,dll-config = <0x0007642c>;
+                       qcom,ddr-config = <0x80040873>;
+
                        bus-width = <4>;
                        status = "disabled";
                };
index d4f8f33..d06aefd 100644 (file)
                        clock-names = "core";
                };
 
-               sdhc_1: sdhci@7c4000 {
+               sdhc_1: mmc@7c4000 {
                        compatible = "qcom,sm6350-sdhci", "qcom,sdhci-msm-v5";
                        reg = <0 0x007c4000 0 0x1000>,
                                <0 0x007c5000 0 0x1000>,
                        clock-names = "iface", "core", "xo";
                        qcom,dll-config = <0x000f642c>;
                        qcom,ddr-config = <0x80040868>;
-                       power-domains = <&rpmhpd 0>;
+                       power-domains = <&rpmhpd SM6350_CX>;
                        operating-points-v2 = <&sdhc1_opp_table>;
                        bus-width = <8>;
                        non-removable;
 
                        status = "disabled";
 
-                       sdhc1_opp_table: sdhc1-opp-table {
+                       sdhc1_opp_table: opp-table {
                                compatible = "operating-points-v2";
 
                                opp-19200000 {
                        };
                };
 
-               sdhc_2: sdhci@8804000 {
+               sdhc_2: mmc@8804000 {
                        compatible = "qcom,sm6350-sdhci", "qcom,sdhci-msm-v5";
                        reg = <0 0x08804000 0 0x1000>;
 
                        clock-names = "iface", "core", "xo";
                        qcom,dll-config = <0x0007642c>;
                        qcom,ddr-config = <0x80040868>;
-                       power-domains = <&rpmhpd 0>;
+                       power-domains = <&rpmhpd SM6350_CX>;
                        operating-points-v2 = <&sdhc2_opp_table>;
                        bus-width = <4>;
 
                        status = "disabled";
 
-                       sdhc2_opp_table: sdhc2-opp-table {
+                       sdhc2_opp_table: opp-table {
                                compatible = "operating-points-v2";
 
                                opp-100000000 {
                        compatible = "arm,armv7-timer-mem";
                        reg = <0x0 0x17c20000 0x0 0x1000>;
                        clock-frequency = <19200000>;
-                       #address-cells = <2>;
-                       #size-cells = <2>;
-                       ranges;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0 0 0 0x20000000>;
 
                        frame@17c21000 {
                                frame-number = <0>;
                                interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c21000 0x0 0x1000>,
-                                     <0x0 0x17c22000 0x0 0x1000>;
+                               reg = <0x17c21000 0x1000>,
+                                     <0x17c22000 0x1000>;
                        };
 
                        frame@17c23000 {
                                frame-number = <1>;
                                interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c23000 0x0 0x1000>;
+                               reg = <0x17c23000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c25000 {
                                frame-number = <2>;
                                interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c25000 0x0 0x1000>;
+                               reg = <0x17c25000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c27000 {
                                frame-number = <3>;
                                interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c27000 0x0 0x1000>;
+                               reg = <0x17c27000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c29000 {
                                frame-number = <4>;
                                interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c29000 0x0 0x1000>;
+                               reg = <0x17c29000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c2b000 {
                                frame-number = <5>;
                                interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c2b000 0x0 0x1000>;
+                               reg = <0x17c2b000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c2d000 {
                                frame-number = <6>;
                                interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c2d000 0x0 0x1000>;
+                               reg = <0x17c2d000 0x1000>;
                                status = "disabled";
                        };
                };
index 6192521..c76abe7 100644 (file)
@@ -48,7 +48,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&gpio_keys_pin>;
 
-               volume-up {
+               key-volume-up {
                        label = "volume_up";
                        linux,code = <KEY_VOLUMEUP>;
                        gpios = <&pm6350_gpios 2 GPIO_ACTIVE_LOW>;
 };
 
 &pm6350_gpios {
-       gpio_keys_pin: gpio-keys-pin {
+       gpio_keys_pin: gpio-keys-state {
                pins = "gpio2";
                function = PMIC_GPIO_FUNC_NORMAL;
                bias-pull-up;
index 37ddca0..3331ee9 100644 (file)
                vin-supply = <&vph_pwr>;
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               vol-up {
+               key-vol-up {
                        label = "Volume Up";
                        linux,code = <KEY_VOLUMEUP>;
                        gpios = <&pm8150_gpios 6 GPIO_ACTIVE_LOW>;
index a73317e..bb278ec 100644 (file)
                vin-supply = <&vph_pwr>;
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               vol_up {
+               key-vol-up {
                        label = "Volume Up";
                        gpios = <&pm8150_gpios 6 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_VOLUMEUP>;
index 8ea44c4..7d509ec 100644 (file)
                };
        };
 
-       cpu0_opp_table: cpu0_opp_table {
+       cpu0_opp_table: opp-table-cpu0 {
                compatible = "operating-points-v2";
                opp-shared;
 
                };
        };
 
-       cpu4_opp_table: cpu4_opp_table {
+       cpu4_opp_table: opp-table-cpu4 {
                compatible = "operating-points-v2";
                opp-shared;
 
                };
        };
 
-       cpu7_opp_table: cpu7_opp_table {
+       cpu7_opp_table: opp-table-cpu7 {
                compatible = "operating-points-v2";
                opp-shared;
 
                };
 
                gmu: gmu@2c6a000 {
-                       compatible="qcom,adreno-gmu-640.1", "qcom,adreno-gmu";
+                       compatible = "qcom,adreno-gmu-640.1", "qcom,adreno-gmu";
 
                        reg = <0 0x02c6a000 0 0x30000>,
                              <0 0x0b290000 0 0x10000>,
                        };
                };
 
-               sdhc_2: sdhci@8804000 {
+               sdhc_2: mmc@8804000 {
                        compatible = "qcom,sm8150-sdhci", "qcom,sdhci-msm-v5";
                        reg = <0 0x08804000 0 0x1000>;
 
 
                        status = "disabled";
 
-                       sdhc2_opp_table: sdhc2-opp-table {
+                       sdhc2_opp_table: opp-table {
                                compatible = "operating-points-v2";
 
                                opp-19200000 {
                };
 
                aoss_qmp: power-controller@c300000 {
-                       compatible = "qcom,sm8150-aoss-qmp";
+                       compatible = "qcom,sm8150-aoss-qmp", "qcom,aoss-qmp";
                        reg = <0x0 0x0c300000 0x0 0x400>;
                        interrupts = <GIC_SPI 389 IRQ_TYPE_EDGE_RISING>;
                        mboxes = <&apss_shared 0>;
                };
 
                timer@17c20000 {
-                       #address-cells = <2>;
-                       #size-cells = <2>;
-                       ranges;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0 0 0 0x20000000>;
                        compatible = "arm,armv7-timer-mem";
                        reg = <0x0 0x17c20000 0x0 0x1000>;
                        clock-frequency = <19200000>;
                                frame-number = <0>;
                                interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c21000 0x0 0x1000>,
-                                     <0x0 0x17c22000 0x0 0x1000>;
+                               reg = <0x17c21000 0x1000>,
+                                     <0x17c22000 0x1000>;
                        };
 
                        frame@17c23000 {
                                frame-number = <1>;
                                interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c23000 0x0 0x1000>;
+                               reg = <0x17c23000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c25000 {
                                frame-number = <2>;
                                interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c25000 0x0 0x1000>;
+                               reg = <0x17c25000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c27000 {
                                frame-number = <3>;
                                interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c26000 0x0 0x1000>;
+                               reg = <0x17c26000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c29000 {
                                frame-number = <4>;
                                interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c29000 0x0 0x1000>;
+                               reg = <0x17c29000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c2b000 {
                                frame-number = <5>;
                                interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c2b000 0x0 0x1000>;
+                               reg = <0x17c2b000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c2d000 {
                                frame-number = <6>;
                                interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c2d000 0x0 0x1000>;
+                               reg = <0x17c2d000 0x1000>;
                                status = "disabled";
                        };
                };
index 3b08247..632e981 100644 (file)
                vin-supply = <&vph_pwr>;
        };
 
-       gpio_keys {
+       gpio-keys {
                compatible = "gpio-keys";
 
-               vol-up {
+               key-vol-up {
                        label = "Volume Up";
                        linux,code = <KEY_VOLUMEUP>;
                        gpios = <&pm8150_gpios 6 GPIO_ACTIVE_LOW>;
index e819b5b..549e0a2 100644 (file)
@@ -57,7 +57,7 @@
                 * case, they are both on &pm8150b_gpios: camera focus(2), camera snapshot(1).
                 */
 
-               vol-down {
+               key-vol-down {
                        label = "Volume Down";
                        linux,code = <KEY_VOLUMEDOWN>;
                        gpios = <&pm8150_gpios 1 GPIO_ACTIVE_LOW>;
index cf0c97b..bc773e2 100644 (file)
@@ -8,6 +8,8 @@
 #include <dt-bindings/clock/qcom,gcc-sm8250.h>
 #include <dt-bindings/clock/qcom,gpucc-sm8250.h>
 #include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/clock/qcom,sm8250-lpass-aoncc.h>
+#include <dt-bindings/clock/qcom,sm8250-lpass-audiocc.h>
 #include <dt-bindings/dma/qcom-gpi.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/interconnect/qcom,osm-l3.h>
                };
        };
 
-       cpu0_opp_table: cpu0_opp_table {
+       cpu0_opp_table: opp-table-cpu0 {
                compatible = "operating-points-v2";
                opp-shared;
 
                };
        };
 
-       cpu4_opp_table: cpu4_opp_table {
+       cpu4_opp_table: opp-table-cpu4 {
                compatible = "operating-points-v2";
                opp-shared;
 
                };
        };
 
-       cpu7_opp_table: cpu7_opp_table {
+       cpu7_opp_table: opp-table-cpu7 {
                compatible = "operating-points-v2";
                opp-shared;
 
 
        firmware {
                scm: scm {
-                       compatible = "qcom,scm";
+                       compatible = "qcom,scm-sm8250", "qcom,scm";
                        #reset-cells = <1>;
                };
        };
                };
        };
 
+       qup_opp_table: opp-table-qup {
+               compatible = "operating-points-v2";
+
+               opp-50000000 {
+                       opp-hz = /bits/ 64 <50000000>;
+                       required-opps = <&rpmhpd_opp_min_svs>;
+               };
+
+               opp-75000000 {
+                       opp-hz = /bits/ 64 <75000000>;
+                       required-opps = <&rpmhpd_opp_low_svs>;
+               };
+
+               opp-120000000 {
+                       opp-hz = /bits/ 64 <120000000>;
+                       required-opps = <&rpmhpd_opp_svs>;
+               };
+       };
+
        reserved-memory {
                #address-cells = <2>;
                #size-cells = <2>;
                        clock-names = "core";
                };
 
-               qup_opp_table: qup-opp-table {
-                       compatible = "operating-points-v2";
-
-                       opp-50000000 {
-                               opp-hz = /bits/ 64 <50000000>;
-                               required-opps = <&rpmhpd_opp_min_svs>;
-                       };
-
-                       opp-75000000 {
-                               opp-hz = /bits/ 64 <75000000>;
-                               required-opps = <&rpmhpd_opp_low_svs>;
-                       };
-
-                       opp-120000000 {
-                               opp-hz = /bits/ 64 <120000000>;
-                               required-opps = <&rpmhpd_opp_svs>;
-                       };
-               };
-
                gpi_dma2: dma-controller@800000 {
                        compatible = "qcom,sm8250-gpi-dma";
                        reg = <0 0x00800000 0 0x70000>;
                                clock-names = "pipe0";
 
                                #phy-cells = <0>;
+
+                               #clock-cells = <0>;
                                clock-output-names = "pcie_0_pipe_clk";
                        };
                };
                                clock-names = "pipe0";
 
                                #phy-cells = <0>;
+
+                               #clock-cells = <0>;
                                clock-output-names = "pcie_1_pipe_clk";
                        };
                };
                                clock-names = "pipe0";
 
                                #phy-cells = <0>;
+
+                               #clock-cells = <0>;
                                clock-output-names = "pcie_2_pipe_clk";
                        };
                };
                wsamacro: codec@3240000 {
                        compatible = "qcom,sm8250-lpass-wsa-macro";
                        reg = <0 0x03240000 0 0x1000>;
-                       clocks = <&audiocc 1>,
-                                <&audiocc 0>,
+                       clocks = <&audiocc LPASS_CDC_WSA_MCLK>,
+                                <&audiocc LPASS_CDC_WSA_NPL>,
                                 <&q6afecc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
                                 <&q6afecc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
-                                <&aoncc 0>,
+                                <&aoncc LPASS_CDC_VA_MCLK>,
                                 <&vamacro>;
 
                        clock-names = "mclk", "npl", "macro", "dcodec", "va", "fsgen";
                vamacro: codec@3370000 {
                        compatible = "qcom,sm8250-lpass-va-macro";
                        reg = <0 0x03370000 0 0x1000>;
-                       clocks = <&aoncc 0>,
+                       clocks = <&aoncc LPASS_CDC_VA_MCLK>,
                                <&q6afecc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
                                <&q6afecc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>;
 
                };
 
                gmu: gmu@3d6a000 {
-                       compatible="qcom,adreno-gmu-650.2", "qcom,adreno-gmu";
+                       compatible = "qcom,adreno-gmu-650.2", "qcom,adreno-gmu";
 
                        reg = <0 0x03d6a000 0 0x30000>,
                              <0 0x3de0000 0 0x10000>,
                };
 
                adreno_smmu: iommu@3da0000 {
-                       compatible = "qcom,sm8250-smmu-500", "arm,mmu-500";
+                       compatible = "qcom,sm8250-smmu-500", "qcom,adreno-smmu", "arm,mmu-500";
                        reg = <0 0x03da0000 0 0x10000>;
                        #iommu-cells = <2>;
                        #global-interrupts = <2>;
                        };
                };
 
-               sdhc_2: sdhci@8804000 {
+               sdhc_2: mmc@8804000 {
                        compatible = "qcom,sm8250-sdhci", "qcom,sdhci-msm-v5";
                        reg = <0 0x08804000 0 0x1000>;
 
 
                        status = "disabled";
 
-                       sdhc2_opp_table: sdhc2-opp-table {
+                       sdhc2_opp_table: opp-table {
                                compatible = "operating-points-v2";
 
                                opp-19200000 {
                        assigned-clock-rates = <19200000>, <200000000>;
 
                        interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
-                                             <&pdc 14 IRQ_TYPE_EDGE_BOTH>,
+                                             <&pdc 17 IRQ_TYPE_LEVEL_HIGH>,
                                              <&pdc 15 IRQ_TYPE_EDGE_BOTH>,
-                                             <&pdc 17 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "hs_phy_irq", "dp_hs_phy_irq",
-                                         "dm_hs_phy_irq", "ss_phy_irq";
+                                             <&pdc 14 IRQ_TYPE_EDGE_BOTH>;
+                       interrupt-names = "hs_phy_irq",
+                                         "ss_phy_irq",
+                                         "dm_hs_phy_irq",
+                                         "dp_hs_phy_irq";
 
                        power-domains = <&gcc USB30_PRIM_GDSC>;
 
                        assigned-clock-rates = <19200000>, <200000000>;
 
                        interrupts-extended = <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
-                                             <&pdc 12 IRQ_TYPE_EDGE_BOTH>,
+                                             <&pdc 16 IRQ_TYPE_LEVEL_HIGH>,
                                              <&pdc 13 IRQ_TYPE_EDGE_BOTH>,
-                                             <&pdc 16 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "hs_phy_irq", "dp_hs_phy_irq",
-                                         "dm_hs_phy_irq", "ss_phy_irq";
+                                             <&pdc 12 IRQ_TYPE_EDGE_BOTH>;
+                       interrupt-names = "hs_phy_irq",
+                                         "ss_phy_irq",
+                                         "dm_hs_phy_irq",
+                                         "dp_hs_phy_irq";
 
                        power-domains = <&gcc USB30_SEC_GDSC>;
 
                                compatible = "venus-encoder";
                        };
 
-                       venus_opp_table: venus-opp-table {
+                       venus_opp_table: opp-table {
                                compatible = "operating-points-v2";
 
                                opp-720000000 {
                        clock-names = "iface", "bi_tcxo", "bi_tcxo_ao", "sleep_clk";
                        power-domains = <&rpmhpd SM8250_MMCX>;
                        required-opps = <&rpmhpd_opp_low_svs>;
+                       status = "disabled";
                        #clock-cells = <1>;
                        #reset-cells = <1>;
                        #power-domain-cells = <1>;
                                 <&dispcc DISP_CC_MDSS_MDP_CLK>;
                        clock-names = "iface", "bus", "nrt_bus", "core";
 
-                       assigned-clocks = <&dispcc DISP_CC_MDSS_MDP_CLK>;
-                       assigned-clock-rates = <460000000>;
-
                        interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                        #size-cells = <2>;
                        ranges;
 
-                       mdss_mdp: mdp@ae01000 {
+                       mdss_mdp: display-controller@ae01000 {
                                compatible = "qcom,sm8250-dpu";
                                reg = <0 0x0ae01000 0 0x8f000>,
                                      <0 0x0aeb0000 0 0x2008>;
                                         <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
                                clock-names = "iface", "bus", "core", "vsync";
 
-                               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 SM8250_MMCX>;
                                        };
                                };
 
-                               mdp_opp_table: mdp-opp-table {
+                               mdp_opp_table: opp-table {
                                        compatible = "operating-points-v2";
 
                                        opp-200000000 {
 
                                status = "disabled";
 
-                               dsi_opp_table: dsi-opp-table {
+                               dsi_opp_table: opp-table {
                                        compatible = "operating-points-v2";
 
                                        opp-187500000 {
                };
 
                aoss_qmp: power-controller@c300000 {
-                       compatible = "qcom,sm8250-aoss-qmp";
+                       compatible = "qcom,sm8250-aoss-qmp", "qcom,aoss-qmp";
                        reg = <0 0x0c300000 0 0x400>;
                        interrupts-extended = <&ipcc IPCC_CLIENT_AOP
                                                     IPCC_MPROC_SIGNAL_GLINK_QMP
                };
 
                timer@17c20000 {
-                       #address-cells = <2>;
-                       #size-cells = <2>;
-                       ranges;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0 0 0 0x20000000>;
                        compatible = "arm,armv7-timer-mem";
                        reg = <0x0 0x17c20000 0x0 0x1000>;
                        clock-frequency = <19200000>;
                                frame-number = <0>;
                                interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c21000 0x0 0x1000>,
-                                     <0x0 0x17c22000 0x0 0x1000>;
+                               reg = <0x17c21000 0x1000>,
+                                     <0x17c22000 0x1000>;
                        };
 
                        frame@17c23000 {
                                frame-number = <1>;
                                interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c23000 0x0 0x1000>;
+                               reg = <0x17c23000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c25000 {
                                frame-number = <2>;
                                interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c25000 0x0 0x1000>;
+                               reg = <0x17c25000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c27000 {
                                frame-number = <3>;
                                interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c27000 0x0 0x1000>;
+                               reg = <0x17c27000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c29000 {
                                frame-number = <4>;
                                interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c29000 0x0 0x1000>;
+                               reg = <0x17c29000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c2b000 {
                                frame-number = <5>;
                                interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c2b000 0x0 0x1000>;
+                               reg = <0x17c2b000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c2d000 {
                                frame-number = <6>;
                                interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c2d000 0x0 0x1000>;
+                               reg = <0x17c2d000 0x1000>;
                                status = "disabled";
                        };
                };
index 9a6faa9..9c4cfd9 100644 (file)
        status = "okay";
 
        vdda-phy-supply = <&vreg_l5b_0p88>;
-       vdda-max-microamp = <91600>;
        vdda-pll-supply = <&vreg_l6b_1p2>;
-       vdda-pll-max-microamp = <19000>;
 };
 
 &usb_1 {
index 90b13cb..cb9bbd2 100644 (file)
@@ -49,7 +49,7 @@
 
                /* For reasons still unknown, GAssist key and Camera Focus/Shutter don't work.. */
 
-               vol-down {
+               key-vol-down {
                        label = "Volume Down";
                        linux,code = <KEY_VOLUMEDOWN>;
                        gpios = <&pmk8350_gpios 3 GPIO_ACTIVE_LOW>;
index 743cba9..e72a044 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/qcom,dispcc-sm8350.h>
 #include <dt-bindings/clock/qcom,gcc-sm8350.h>
 #include <dt-bindings/clock/qcom,rpmh.h>
 #include <dt-bindings/dma/qcom-gpi.h>
                };
        };
 
+       qup_opp_table_100mhz: opp-table-qup100mhz {
+               compatible = "operating-points-v2";
+
+               opp-50000000 {
+                       opp-hz = /bits/ 64 <50000000>;
+                       required-opps = <&rpmhpd_opp_min_svs>;
+               };
+
+               opp-75000000 {
+                       opp-hz = /bits/ 64 <75000000>;
+                       required-opps = <&rpmhpd_opp_low_svs>;
+               };
+
+               opp-100000000 {
+                       opp-hz = /bits/ 64 <100000000>;
+                       required-opps = <&rpmhpd_opp_svs>;
+               };
+       };
+
+       qup_opp_table_120mhz: opp-table-qup120mhz {
+               compatible = "operating-points-v2";
+
+               opp-50000000 {
+                       opp-hz = /bits/ 64 <50000000>;
+                       required-opps = <&rpmhpd_opp_min_svs>;
+               };
+
+               opp-75000000 {
+                       opp-hz = /bits/ 64 <75000000>;
+                       required-opps = <&rpmhpd_opp_low_svs>;
+               };
+
+               opp-120000000 {
+                       opp-hz = /bits/ 64 <120000000>;
+                       required-opps = <&rpmhpd_opp_svs>;
+               };
+       };
+
        reserved_memory: reserved-memory {
                #address-cells = <2>;
                #size-cells = <2>;
                        #mbox-cells = <2>;
                };
 
-               qup_opp_table_100mhz: qup-100mhz-opp-table {
-                       compatible = "operating-points-v2";
-
-                       opp-50000000 {
-                               opp-hz = /bits/ 64 <50000000>;
-                               required-opps = <&rpmhpd_opp_min_svs>;
-                       };
-
-                       opp-75000000 {
-                               opp-hz = /bits/ 64 <75000000>;
-                               required-opps = <&rpmhpd_opp_low_svs>;
-                       };
-
-                       opp-100000000 {
-                               opp-hz = /bits/ 64 <100000000>;
-                               required-opps = <&rpmhpd_opp_svs>;
-                       };
-               };
-
-               qup_opp_table_120mhz: qup-120mhz-opp-table {
-                       compatible = "operating-points-v2";
-
-                       opp-50000000 {
-                               opp-hz = /bits/ 64 <50000000>;
-                               required-opps = <&rpmhpd_opp_min_svs>;
-                       };
-
-                       opp-75000000 {
-                               opp-hz = /bits/ 64 <75000000>;
-                               required-opps = <&rpmhpd_opp_low_svs>;
-                       };
-
-                       opp-120000000 {
-                               opp-hz = /bits/ 64 <120000000>;
-                               required-opps = <&rpmhpd_opp_svs>;
-                       };
-               };
-
                gpi_dma2: dma-controller@800000 {
                        compatible = "qcom,sm8350-gpi-dma";
                        reg = <0 0x00800000 0 0x60000>;
                        clocks = <&rpmhcc RPMH_CXO_CLK>;
                        clock-names = "xo";
 
-                       power-domains = <&rpmhpd 0>,
-                                       <&rpmhpd 12>;
+                       power-domains = <&rpmhpd SM8350_CX>,
+                                       <&rpmhpd SM8350_MSS>;
                        power-domain-names = "cx", "mss";
 
                        interconnects = <&mc_virt MASTER_LLCC &mc_virt SLAVE_EBI1>;
                                                             IRQ_TYPE_EDGE_RISING>;
                                mboxes = <&ipcc IPCC_CLIENT_MPSS
                                                IPCC_MPROC_SIGNAL_GLINK_QMP>;
-                               interrupts = <GIC_SPI 449 IRQ_TYPE_EDGE_RISING>;
                                label = "modem";
                                qcom,remote-pid = <1>;
                        };
                };
 
                aoss_qmp: power-controller@c300000 {
-                       compatible = "qcom,sm8350-aoss-qmp";
+                       compatible = "qcom,sm8350-aoss-qmp", "qcom,aoss-qmp";
                        reg = <0 0x0c300000 0 0x400>;
                        interrupts-extended = <&ipcc IPCC_CLIENT_AOP IPCC_MPROC_SIGNAL_GLINK_QMP
                                                     IRQ_TYPE_EDGE_RISING>;
 
                timer@17c20000 {
                        compatible = "arm,armv7-timer-mem";
-                       #address-cells = <2>;
-                       #size-cells = <2>;
-                       ranges;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0 0 0 0x20000000>;
                        reg = <0x0 0x17c20000 0x0 0x1000>;
                        clock-frequency = <19200000>;
 
                                frame-number = <0>;
                                interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c21000 0x0 0x1000>,
-                                     <0x0 0x17c22000 0x0 0x1000>;
+                               reg = <0x17c21000 0x1000>,
+                                     <0x17c22000 0x1000>;
                        };
 
                        frame@17c23000 {
                                frame-number = <1>;
                                interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c23000 0x0 0x1000>;
+                               reg = <0x17c23000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c25000 {
                                frame-number = <2>;
                                interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c25000 0x0 0x1000>;
+                               reg = <0x17c25000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c27000 {
                                frame-number = <3>;
                                interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c27000 0x0 0x1000>;
+                               reg = <0x17c27000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c29000 {
                                frame-number = <4>;
                                interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c29000 0x0 0x1000>;
+                               reg = <0x17c29000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c2b000 {
                                frame-number = <5>;
                                interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c2b000 0x0 0x1000>;
+                               reg = <0x17c2b000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17c2d000 {
                                frame-number = <6>;
                                interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17c2d000 0x0 0x1000>;
+                               reg = <0x17c2d000 0x1000>;
                                status = "disabled";
                        };
                };
                                      <0 0x01d87800 0 0x108>,
                                      <0 0x01d87a00 0 0x1e0>;
                                #phy-cells = <0>;
-                               #clock-cells = <0>;
                        };
                };
 
                        clocks = <&rpmhcc RPMH_CXO_CLK>;
                        clock-names = "xo";
 
-                       power-domains = <&rpmhpd 4>,
-                                       <&rpmhpd 5>;
+                       power-domains = <&rpmhpd SM8350_LCX>,
+                                       <&rpmhpd SM8350_LMX>;
                        power-domain-names = "lcx", "lmx";
 
                        memory-region = <&pil_slpi_mem>;
                        clocks = <&rpmhcc RPMH_CXO_CLK>;
                        clock-names = "xo";
 
-                       power-domains = <&rpmhpd 0>,
-                                       <&rpmhpd 10>;
+                       power-domains = <&rpmhpd SM8350_CX>,
+                                       <&rpmhpd SM8350_MXC>;
                        power-domain-names = "cx", "mxc";
 
                        interconnects = <&compute_noc MASTER_CDSP_PROC &mc_virt SLAVE_EBI1>;
                                      <0 0x088e9800 0 0x200>,
                                      <0 0x088e9a00 0 0x100>;
                                #phy-cells = <0>;
-                               #clock-cells = <1>;
+                               #clock-cells = <0>;
                                clocks = <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>;
                                clock-names = "pipe0";
                                clock-output-names = "usb3_phy_pipe_clk_src";
                                      <0 0x088ec000 0 0x200>,
                                      <0 0x088eb200 0 0x1100>;
                                #phy-cells = <0>;
-                               #clock-cells = <1>;
+                               #clock-cells = <0>;
                                clocks = <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>;
                                clock-names = "pipe0";
                                clock-output-names = "usb3_uni_phy_pipe_clk_src";
                        assigned-clock-rates = <19200000>, <200000000>;
 
                        interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
-                                             <&pdc 14 IRQ_TYPE_EDGE_BOTH>,
+                                             <&pdc 17 IRQ_TYPE_LEVEL_HIGH>,
                                              <&pdc 15 IRQ_TYPE_EDGE_BOTH>,
-                                             <&pdc 17 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "hs_phy_irq", "dp_hs_phy_irq",
-                                         "dm_hs_phy_irq", "ss_phy_irq";
+                                             <&pdc 14 IRQ_TYPE_EDGE_BOTH>;
+                       interrupt-names = "hs_phy_irq",
+                                         "ss_phy_irq",
+                                         "dm_hs_phy_irq",
+                                         "dp_hs_phy_irq";
 
                        power-domains = <&gcc USB30_PRIM_GDSC>;
 
                        assigned-clock-rates = <19200000>, <200000000>;
 
                        interrupts-extended = <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
-                                             <&pdc 12 IRQ_TYPE_EDGE_BOTH>,
+                                             <&pdc 16 IRQ_TYPE_LEVEL_HIGH>,
                                              <&pdc 13 IRQ_TYPE_EDGE_BOTH>,
-                                             <&pdc 16 IRQ_TYPE_LEVEL_HIGH>;
-                       interrupt-names = "hs_phy_irq", "dp_hs_phy_irq",
-                                         "dm_hs_phy_irq", "ss_phy_irq";
+                                             <&pdc 12 IRQ_TYPE_EDGE_BOTH>;
+                       interrupt-names = "hs_phy_irq",
+                                         "ss_phy_irq",
+                                         "dm_hs_phy_irq",
+                                         "dp_hs_phy_irq";
 
                        power-domains = <&gcc USB30_SEC_GDSC>;
 
                        };
                };
 
+               dispcc: clock-controller@af00000 {
+                       compatible = "qcom,sm8350-dispcc";
+                       reg = <0 0x0af00000 0 0x10000>;
+                       clocks = <&rpmhcc RPMH_CXO_CLK>,
+                                <0>,
+                                <0>,
+                                <0>,
+                                <0>,
+                                <0>,
+                                <0>;
+                       clock-names = "bi_tcxo",
+                                     "dsi0_phy_pll_out_byteclk",
+                                     "dsi0_phy_pll_out_dsiclk",
+                                     "dsi1_phy_pll_out_byteclk",
+                                     "dsi1_phy_pll_out_dsiclk",
+                                     "dp_phy_pll_link_clk",
+                                     "dp_phy_pll_vco_div_clk";
+                       #clock-cells = <1>;
+                       #reset-cells = <1>;
+                       #power-domain-cells = <1>;
+
+                       power-domains = <&rpmhpd SM8350_MMCX>;
+                       power-domain-names = "mmcx";
+               };
+
                adsp: remoteproc@17300000 {
                        compatible = "qcom,sm8350-adsp-pas";
                        reg = <0 0x17300000 0 0x100>;
                        clocks = <&rpmhcc RPMH_CXO_CLK>;
                        clock-names = "xo";
 
-                       power-domains = <&rpmhpd 4>,
-                                       <&rpmhpd 5>;
+                       power-domains = <&rpmhpd SM8350_LCX>,
+                                       <&rpmhpd SM8350_LMX>;
                        power-domain-names = "lcx", "lmx";
 
                        memory-region = <&pil_adsp_mem>;
index 4e51a9d..38ccd44 100644 (file)
 
        vdda-phy-supply = <&vreg_l5b_0p88>;
        vdda-pll-supply = <&vreg_l6b_1p2>;
-       vdda-max-microamp = <173000>;
-       vdda-pll-max-microamp = <24900>;
 };
 
 &usb_1 {
index 236e539..e58fc73 100644 (file)
 
        vdda-phy-supply = <&vreg_l5b_0p88>;
        vdda-pll-supply = <&vreg_l6b_1p2>;
-       vdda-max-microamp = <173000>;
-       vdda-pll-max-microamp = <24900>;
 };
 
 &usb_1 {
index 7d08fad..4978c5b 100644 (file)
@@ -6,6 +6,7 @@
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/clock/qcom,gcc-sm8450.h>
 #include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/clock/qcom,sm8450-camcc.h>
 #include <dt-bindings/dma/qcom-gpi.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/mailbox/qcom-ipcc.h>
        firmware {
                scm: scm {
                        compatible = "qcom,scm-sm8450", "qcom,scm";
+                       interconnects = <&aggre2_noc MASTER_CRYPTO 0 &mc_virt SLAVE_EBI1 0>;
                        #reset-cells = <1>;
                };
        };
 
-       clk_virt: interconnect@0 {
+       clk_virt: interconnect-0 {
                compatible = "qcom,sm8450-clk-virt";
                #interconnect-cells = <2>;
                qcom,bcm-voters = <&apps_bcm_voter>;
        };
 
-       mc_virt: interconnect@1 {
+       mc_virt: interconnect-1 {
                compatible = "qcom,sm8450-mc-virt";
                #interconnect-cells = <2>;
                qcom,bcm-voters = <&apps_bcm_voter>;
                };
        };
 
-       qup_opp_table_100mhz: qup-100mhz-opp-table {
+       qup_opp_table_100mhz: opp-table-qup {
                compatible = "operating-points-v2";
 
                opp-50000000 {
                                status = "disabled";
                        };
 
+                       uart20: serial@894000 {
+                               compatible = "qcom,geni-uart";
+                               reg = <0 0x00894000 0 0x4000>;
+                               clock-names = "se";
+                               clocks = <&gcc GCC_QUPV3_WRAP2_S5_CLK>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&qup_uart20_default>;
+                               interrupts = <GIC_SPI 587 IRQ_TYPE_LEVEL_HIGH>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               status = "disabled";
+                       };
+
                        spi20: spi@894000 {
                                compatible = "qcom,geni-spi";
                                reg = <0 0x00894000 0 0x4000>;
                                      <0 0x088e9800 0 0x200>,
                                      <0 0x088e9a00 0 0x100>;
                                #phy-cells = <0>;
-                               #clock-cells = <1>;
+                               #clock-cells = <0>;
                                clocks = <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>;
                                clock-names = "pipe0";
                                clock-output-names = "usb3_phy_pipe_clk_src";
                        compatible = "qcom,sm8450-slpi-pas";
                        reg = <0 0x02400000 0 0x4000>;
 
-                       interrupts-extended = <&pdc 9 IRQ_TYPE_LEVEL_HIGH>,
+                       interrupts-extended = <&pdc 9 IRQ_TYPE_EDGE_RISING>,
                                              <&smp2p_slpi_in 0 IRQ_TYPE_EDGE_RISING>,
                                              <&smp2p_slpi_in 1 IRQ_TYPE_EDGE_RISING>,
                                              <&smp2p_slpi_in 2 IRQ_TYPE_EDGE_RISING>,
                        compatible = "qcom,sm8450-adsp-pas";
                        reg = <0 0x030000000 0 0x100>;
 
-                       interrupts-extended = <&pdc 6 IRQ_TYPE_LEVEL_HIGH>,
+                       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>,
                        compatible = "qcom,sm8450-cdsp-pas";
                        reg = <0 0x032300000 0 0x1400000>;
 
-                       interrupts-extended = <&intc GIC_SPI 578 IRQ_TYPE_LEVEL_HIGH>,
+                       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>,
                        compatible = "qcom,sm8450-mpss-pas";
                        reg = <0x0 0x04080000 0x0 0x4040>;
 
-                       interrupts-extended = <&intc GIC_SPI 264 IRQ_TYPE_LEVEL_HIGH>,
+                       interrupts-extended = <&intc GIC_SPI 264 IRQ_TYPE_EDGE_RISING>,
                                              <&smp2p_modem_in 0 IRQ_TYPE_EDGE_RISING>,
                                              <&smp2p_modem_in 1 IRQ_TYPE_EDGE_RISING>,
                                              <&smp2p_modem_in 2 IRQ_TYPE_EDGE_RISING>,
                                                             IRQ_TYPE_EDGE_RISING>;
                                mboxes = <&ipcc IPCC_CLIENT_MPSS
                                                IPCC_MPROC_SIGNAL_GLINK_QMP>;
-                               interrupts = <GIC_SPI 449 IRQ_TYPE_EDGE_RISING>;
                                label = "modem";
                                qcom,remote-pid = <1>;
                        };
                };
 
+               camcc: clock-controller@ade0000 {
+                       compatible = "qcom,sm8450-camcc";
+                       reg = <0 0x0ade0000 0 0x20000>;
+                       clocks = <&gcc GCC_CAMERA_AHB_CLK>,
+                                <&rpmhcc RPMH_CXO_CLK>,
+                                <&rpmhcc RPMH_CXO_CLK_A>,
+                                <&sleep_clk>;
+                       power-domains = <&rpmhpd SM8450_MMCX>;
+                       required-opps = <&rpmhpd_opp_low_svs>;
+                       #clock-cells = <1>;
+                       #reset-cells = <1>;
+                       #power-domain-cells = <1>;
+                       status = "disabled";
+               };
+
                pdc: interrupt-controller@b220000 {
                        compatible = "qcom,sm8450-pdc", "qcom,pdc";
                        reg = <0 0x0b220000 0 0x30000>, <0 0x174000f0 0 0x64>;
                                drive-strength = <2>;
                                bias-disable;
                        };
+
+                       qup_uart20_default: qup-uart20-default {
+                               pins = "gpio76", "gpio77", "gpio78", "gpio79";
+                               function = "qup20";
+                       };
+
                };
 
                apps_smmu: iommu@15000000 {
                        reg = <0x0 0x17100000 0x0 0x10000>,     /* GICD */
                              <0x0 0x17180000 0x0 0x200000>;    /* GICR * 8 */
                        interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       ranges;
+
+                       gic_its: msi-controller@17140000 {
+                               compatible = "arm,gic-v3-its";
+                               reg = <0x0 0x17140000 0x0 0x20000>;
+                               msi-controller;
+                               #msi-cells = <1>;
+                       };
                };
 
                timer@17420000 {
                        compatible = "arm,armv7-timer-mem";
-                       #address-cells = <2>;
-                       #size-cells = <2>;
-                       ranges;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0 0 0 0x20000000>;
                        reg = <0x0 0x17420000 0x0 0x1000>;
                        clock-frequency = <19200000>;
 
                                frame-number = <0>;
                                interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17421000 0x0 0x1000>,
-                                     <0x0 0x17422000 0x0 0x1000>;
+                               reg = <0x17421000 0x1000>,
+                                     <0x17422000 0x1000>;
                        };
 
                        frame@17423000 {
                                frame-number = <1>;
                                interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17423000 0x0 0x1000>;
+                               reg = <0x17423000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17425000 {
                                frame-number = <2>;
                                interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17425000 0x0 0x1000>;
+                               reg = <0x17425000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17427000 {
                                frame-number = <3>;
                                interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17427000 0x0 0x1000>;
+                               reg = <0x17427000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@17429000 {
                                frame-number = <4>;
                                interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x17429000 0x0 0x1000>;
+                               reg = <0x17429000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@1742b000 {
                                frame-number = <5>;
                                interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x1742b000 0x0 0x1000>;
+                               reg = <0x1742b000 0x1000>;
                                status = "disabled";
                        };
 
                        frame@1742d000 {
                                frame-number = <6>;
                                interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
-                               reg = <0x0 0x1742d000 0x0 0x1000>;
+                               reg = <0x1742d000 0x1000>;
                                status = "disabled";
                        };
                };
 
                        iommus = <&apps_smmu 0xe0 0x0>;
 
-                       interconnects = <&aggre1_noc MASTER_UFS_MEM &mc_virt SLAVE_EBI1>,
-                                       <&gem_noc MASTER_APPSS_PROC &config_noc SLAVE_UFS_MEM_CFG>;
+                       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>;
                        interconnect-names = "ufs-ddr", "cpu-ufs";
                        clock-names =
                                "core_clk",
                                      <0 0x01d87800 0 0x108>,
                                      <0 0x01d87a00 0 0x1e0>;
                                #phy-cells = <0>;
-                               #clock-cells = <0>;
                        };
                };
 
index e66d76d..7a64786 100644 (file)
@@ -85,3 +85,6 @@ dtb-$(CONFIG_ARCH_R9A07G044) += r9a07g044l2-smarc.dtb
 dtb-$(CONFIG_ARCH_R9A07G054) += r9a07g054l2-smarc.dtb
 
 dtb-$(CONFIG_ARCH_R9A09G011) += r9a09g011-v2mevk2.dtb
+
+dtb-$(CONFIG_ARCH_RCAR_GEN3) += draak-ebisu-panel-aa104xd12.dtbo
+dtb-$(CONFIG_ARCH_RCAR_GEN3) += salvator-panel-aa104xd12.dtbo
index 142e7ff..63e7a39 100644 (file)
                };
        };
 
-       reg_audio: regulator_audio {
+       reg_audio: regulator-audio {
                compatible = "regulator-fixed";
                regulator-name = "audio-1.8V";
                regulator-min-microvolt = <1800000>;
                vin-supply = <&reg_lcd>;
        };
 
-       reg_cam0: regulator_camera {
+       reg_cam0: regulator-cam0 {
                compatible = "regulator-fixed";
                regulator-name = "reg_cam0";
                regulator-min-microvolt = <1800000>;
                enable-active-high;
        };
 
-       reg_cam1: regulator_camera {
+       reg_cam1: regulator-cam1 {
                compatible = "regulator-fixed";
                regulator-name = "reg_cam1";
                regulator-min-microvolt = <1800000>;
index 877d076..f5c1d74 100644 (file)
@@ -20,7 +20,7 @@
                clock-output-names = "osc_32k";
        };
 
-       reg_1p8v: regulator0 {
+       reg_1p8v: regulator-1p8v {
                compatible = "regulator-fixed";
                regulator-name = "fixed-1.8V";
                regulator-min-microvolt = <1800000>;
@@ -29,7 +29,7 @@
                regulator-always-on;
        };
 
-       reg_3p3v: regulator1 {
+       reg_3p3v: regulator-3p3v {
                compatible = "regulator-fixed";
                regulator-name = "fixed-3.3V";
                regulator-min-microvolt = <3300000>;
diff --git a/arch/arm64/boot/dts/renesas/draak-ebisu-panel-aa104xd12.dts b/arch/arm64/boot/dts/renesas/draak-ebisu-panel-aa104xd12.dts
new file mode 100644 (file)
index 0000000..258f866
--- /dev/null
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Device Tree overlay for the AA104XD12 panel connected to LVDS1 on a Draak or
+ * Ebisu board
+ *
+ * Copyright 2021 Ideas on Board Oy
+ */
+
+/dts-v1/;
+/plugin/;
+
+&{/} {
+#include "panel-aa104xd12.dtsi"
+};
+
+&{/panel} {
+       backlight = <&backlight>;
+
+       port {
+               panel_in: endpoint {
+                       remote-endpoint = <&lvds1_out>;
+               };
+       };
+};
+
+&lvds1 {
+       status = "okay";
+
+       ports {
+               port@1 {
+                       lvds1_out: endpoint {
+                               remote-endpoint = <&panel_in>;
+                       };
+               };
+       };
+};
index 7231f82..ef3bb83 100644 (file)
                                bitclock-master = <&rsnd_for_ak4613>;
                                frame-master = <&rsnd_for_ak4613>;
                                playback = <&ssi3>, <&src5>, <&dvc0>;
-                               capture  = <&ssi4>, <&src6>, <&dvc1>;
+                               capture = <&ssi4>, <&src6>, <&dvc1>;
                        };
                };
        };
index 72f359e..8fc0349 100644 (file)
                reg = <0x0 0x48000000 0x0 0x38000000>;
        };
 
-       reg_1p8v: regulator0 {
+       reg_1p8v: regulator-1p8v {
                compatible = "regulator-fixed";
                regulator-name = "fixed-1.8V";
                regulator-min-microvolt = <1800000>;
                regulator-always-on;
        };
 
-       reg_3p3v: regulator1 {
+       reg_3p3v: regulator-3p3v {
                compatible = "regulator-fixed";
                regulator-name = "fixed-3.3V";
                regulator-min-microvolt = <3300000>;
                regulator-always-on;
        };
 
-       reg_12p0v: regulator2 {
+       reg_12p0v: regulator-12p0v {
                compatible = "regulator-fixed";
                regulator-name = "D12.0V";
                regulator-min-microvolt = <12000000>;
        rcar_sound,dai {
                dai0 {
                        playback = <&ssi0>, <&src0>, <&dvc0>;
-                       capture  = <&ssi1>, <&src1>, <&dvc1>;
+                       capture = <&ssi1>, <&src1>, <&dvc1>;
                };
        };
 
index 935d065..b062f41 100644 (file)
@@ -53,7 +53,7 @@
                };
        };
 
-       reg_1p8v: regulator0 {
+       reg_1p8v: regulator-1p8v {
                compatible = "regulator-fixed";
                regulator-name = "fixed-1.8V";
                regulator-min-microvolt = <1800000>;
@@ -62,7 +62,7 @@
                regulator-always-on;
        };
 
-       reg_3p3v: regulator1 {
+       reg_3p3v: regulator-3p3v {
                compatible = "regulator-fixed";
                regulator-name = "fixed-3.3V";
                regulator-min-microvolt = <3300000>;
diff --git a/arch/arm64/boot/dts/renesas/panel-aa104xd12.dtsi b/arch/arm64/boot/dts/renesas/panel-aa104xd12.dtsi
new file mode 100644 (file)
index 0000000..4b1f098
--- /dev/null
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Common file for the AA104XD12 panel connected to Renesas R-Car Gen3 boards.
+ *
+ * Copyright (C) 2014 Renesas Electronics Corp.
+ */
+
+panel {
+       compatible = "mitsubishi,aa104xd12", "panel-lvds";
+
+       width-mm = <210>;
+       height-mm = <158>;
+       data-mapping = "jeida-18";
+
+       panel-timing {
+               /* 1024x768 @65Hz */
+               clock-frequency = <65000000>;
+               hactive = <1024>;
+               vactive = <768>;
+               hsync-len = <136>;
+               hfront-porch = <20>;
+               hback-porch = <160>;
+               vfront-porch = <3>;
+               vback-porch = <29>;
+               vsync-len = <6>;
+       };
+
+       port {
+       };
+};
index b6aeb22..c563d26 100644 (file)
 
                                        vin4csi40: endpoint@2 {
                                                reg = <2>;
-                                               remote-endpoint= <&csi40vin4>;
+                                               remote-endpoint = <&csi40vin4>;
                                        };
                                };
                        };
 
                                        vin5csi40: endpoint@2 {
                                                reg = <2>;
-                                               remote-endpoint= <&csi40vin5>;
+                                               remote-endpoint = <&csi40vin5>;
                                        };
                                };
                        };
                cpu-thermal {
                        polling-delay-passive = <250>;
                        polling-delay = <0>;
-                       thermal-sensors = <&thermal 0>;
+                       thermal-sensors = <&thermal>;
                        sustainable-power = <717>;
 
                        cooling-maps {
index d330212..565e9d8 100644 (file)
 
                                        vin4csi40: endpoint@2 {
                                                reg = <2>;
-                                               remote-endpoint= <&csi40vin4>;
+                                               remote-endpoint = <&csi40vin4>;
                                        };
                                };
                        };
 
                                        vin5csi40: endpoint@2 {
                                                reg = <2>;
-                                               remote-endpoint= <&csi40vin5>;
+                                               remote-endpoint = <&csi40vin5>;
                                        };
                                };
                        };
                cpu-thermal {
                        polling-delay-passive = <250>;
                        polling-delay = <0>;
-                       thermal-sensors = <&thermal 0>;
+                       thermal-sensors = <&thermal>;
                        sustainable-power = <717>;
 
                        cooling-maps {
index b973150..3d66870 100644 (file)
@@ -41,6 +41,7 @@
                        device_type = "cpu";
                        power-domains = <&sysc R8A779A0_PD_A1E0D0C0>;
                        next-level-cache = <&L3_CA76_0>;
+                       clocks = <&cpg CPG_CORE R8A779A0_CLK_Z0>;
                };
 
                L3_CA76_0: cache-controller-0 {
                };
 
                gpio0: gpio@e6058180 {
-                       compatible = "renesas,gpio-r8a779a0";
+                       compatible = "renesas,gpio-r8a779a0",
+                                    "renesas,rcar-gen4-gpio";
                        reg = <0 0xe6058180 0 0x54>;
                        interrupts = <GIC_SPI 832 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 916>;
                };
 
                gpio1: gpio@e6050180 {
-                       compatible = "renesas,gpio-r8a779a0";
+                       compatible = "renesas,gpio-r8a779a0",
+                                    "renesas,rcar-gen4-gpio";
                        reg = <0 0xe6050180 0 0x54>;
                        interrupts = <GIC_SPI 836 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 915>;
                };
 
                gpio2: gpio@e6050980 {
-                       compatible = "renesas,gpio-r8a779a0";
+                       compatible = "renesas,gpio-r8a779a0",
+                                    "renesas,rcar-gen4-gpio";
                        reg = <0 0xe6050980 0 0x54>;
                        interrupts = <GIC_SPI 840 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 915>;
                };
 
                gpio3: gpio@e6058980 {
-                       compatible = "renesas,gpio-r8a779a0";
+                       compatible = "renesas,gpio-r8a779a0",
+                                    "renesas,rcar-gen4-gpio";
                        reg = <0 0xe6058980 0 0x54>;
                        interrupts = <GIC_SPI 844 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 916>;
                };
 
                gpio4: gpio@e6060180 {
-                       compatible = "renesas,gpio-r8a779a0";
+                       compatible = "renesas,gpio-r8a779a0",
+                                    "renesas,rcar-gen4-gpio";
                        reg = <0 0xe6060180 0 0x54>;
                        interrupts = <GIC_SPI 848 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 917>;
                };
 
                gpio5: gpio@e6060980 {
-                       compatible = "renesas,gpio-r8a779a0";
+                       compatible = "renesas,gpio-r8a779a0",
+                                    "renesas,rcar-gen4-gpio";
                        reg = <0 0xe6060980 0 0x54>;
                        interrupts = <GIC_SPI 852 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 917>;
                };
 
                gpio6: gpio@e6068180 {
-                       compatible = "renesas,gpio-r8a779a0";
+                       compatible = "renesas,gpio-r8a779a0",
+                                    "renesas,rcar-gen4-gpio";
                        reg = <0 0xe6068180 0 0x54>;
                        interrupts = <GIC_SPI 856 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 918>;
                };
 
                gpio7: gpio@e6068980 {
-                       compatible = "renesas,gpio-r8a779a0";
+                       compatible = "renesas,gpio-r8a779a0",
+                                    "renesas,rcar-gen4-gpio";
                        reg = <0 0xe6068980 0 0x54>;
                        interrupts = <GIC_SPI 860 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 918>;
                };
 
                gpio8: gpio@e6069180 {
-                       compatible = "renesas,gpio-r8a779a0";
+                       compatible = "renesas,gpio-r8a779a0",
+                                    "renesas,rcar-gen4-gpio";
                        reg = <0 0xe6069180 0 0x54>;
                        interrupts = <GIC_SPI 864 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 918>;
                };
 
                gpio9: gpio@e6069980 {
-                       compatible = "renesas,gpio-r8a779a0";
+                       compatible = "renesas,gpio-r8a779a0",
+                                    "renesas,rcar-gen4-gpio";
                        reg = <0 0xe6069980 0 0x54>;
                        interrupts = <GIC_SPI 868 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&cpg CPG_MOD 918>;
index 41aa859..28fbf7b 100644 (file)
                function = "i2c4";
        };
 
+       scif0_pins: scif0 {
+               groups = "scif0_data", "scif0_ctrl";
+               function = "scif0";
+       };
+
        scif3_pins: scif3 {
                groups = "scif3_data", "scif3_ctrl";
                function = "scif3";
        status = "okay";
 };
 
+&scif0 {
+       pinctrl-0 = <&scif0_pins>;
+       pinctrl-names = "default";
+
+       uart-has-rtscts;
+       status = "okay";
+};
+
 &scif3 {
        pinctrl-0 = <&scif3_pins>;
        pinctrl-names = "default";
index 2e3b719..7a7c8ff 100644 (file)
@@ -15,6 +15,7 @@
 
        aliases {
                serial0 = &scif3;
+               serial1 = &scif0;
        };
 
        chosen {
index df46fb8..384817f 100644 (file)
                #address-cells = <1>;
                #size-cells = <0>;
 
+               cpu-map {
+                       cluster0 {
+                               core0 {
+                                       cpu = <&a55_0>;
+                               };
+                               core1 {
+                                       cpu = <&a55_1>;
+                               };
+                       };
+
+                       cluster1 {
+                               core0 {
+                                       cpu = <&a55_2>;
+                               };
+                               core1 {
+                                       cpu = <&a55_3>;
+                               };
+                       };
+
+                       cluster2 {
+                               core0 {
+                                       cpu = <&a55_4>;
+                               };
+                               core1 {
+                                       cpu = <&a55_5>;
+                               };
+                       };
+
+                       cluster3 {
+                               core0 {
+                                       cpu = <&a55_6>;
+                               };
+                               core1 {
+                                       cpu = <&a55_7>;
+                               };
+                       };
+               };
+
                a55_0: cpu@0 {
                        compatible = "arm,cortex-a55";
                        reg = <0>;
                        device_type = "cpu";
                        power-domains = <&sysc R8A779F0_PD_A1E0D0C0>;
+                       next-level-cache = <&L3_CA55_0>;
+                       enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
+                       clocks = <&cpg CPG_CORE R8A779F0_CLK_Z0>;
+               };
+
+               a55_1: cpu@100 {
+                       compatible = "arm,cortex-a55";
+                       reg = <0x100>;
+                       device_type = "cpu";
+                       power-domains = <&sysc R8A779F0_PD_A1E0D0C1>;
+                       next-level-cache = <&L3_CA55_0>;
+                       enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
+                       clocks = <&cpg CPG_CORE R8A779F0_CLK_Z0>;
+               };
+
+               a55_2: cpu@10000 {
+                       compatible = "arm,cortex-a55";
+                       reg = <0x10000>;
+                       device_type = "cpu";
+                       power-domains = <&sysc R8A779F0_PD_A1E0D1C0>;
+                       next-level-cache = <&L3_CA55_1>;
+                       enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
+                       clocks = <&cpg CPG_CORE R8A779F0_CLK_Z0>;
+               };
+
+               a55_3: cpu@10100 {
+                       compatible = "arm,cortex-a55";
+                       reg = <0x10100>;
+                       device_type = "cpu";
+                       power-domains = <&sysc R8A779F0_PD_A1E0D1C1>;
+                       next-level-cache = <&L3_CA55_1>;
+                       enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
+                       clocks = <&cpg CPG_CORE R8A779F0_CLK_Z0>;
+               };
+
+               a55_4: cpu@20000 {
+                       compatible = "arm,cortex-a55";
+                       reg = <0x20000>;
+                       device_type = "cpu";
+                       power-domains = <&sysc R8A779F0_PD_A1E1D0C0>;
+                       next-level-cache = <&L3_CA55_2>;
+                       enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
+                       clocks = <&cpg CPG_CORE R8A779F0_CLK_Z1>;
+               };
+
+               a55_5: cpu@20100 {
+                       compatible = "arm,cortex-a55";
+                       reg = <0x20100>;
+                       device_type = "cpu";
+                       power-domains = <&sysc R8A779F0_PD_A1E1D0C1>;
+                       next-level-cache = <&L3_CA55_2>;
+                       enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
+                       clocks = <&cpg CPG_CORE R8A779F0_CLK_Z1>;
+               };
+
+               a55_6: cpu@30000 {
+                       compatible = "arm,cortex-a55";
+                       reg = <0x30000>;
+                       device_type = "cpu";
+                       power-domains = <&sysc R8A779F0_PD_A1E1D1C0>;
+                       next-level-cache = <&L3_CA55_3>;
+                       enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
+                       clocks = <&cpg CPG_CORE R8A779F0_CLK_Z1>;
+               };
+
+               a55_7: cpu@30100 {
+                       compatible = "arm,cortex-a55";
+                       reg = <0x30100>;
+                       device_type = "cpu";
+                       power-domains = <&sysc R8A779F0_PD_A1E1D1C1>;
+                       next-level-cache = <&L3_CA55_3>;
+                       enable-method = "psci";
+                       cpu-idle-states = <&CPU_SLEEP_0>;
+                       clocks = <&cpg CPG_CORE R8A779F0_CLK_Z1>;
+               };
+
+               L3_CA55_0: cache-controller-0 {
+                       compatible = "cache";
+                       power-domains = <&sysc R8A779F0_PD_A2E0D0>;
+                       cache-unified;
+                       cache-level = <3>;
+               };
+
+               L3_CA55_1: cache-controller-1 {
+                       compatible = "cache";
+                       power-domains = <&sysc R8A779F0_PD_A2E0D1>;
+                       cache-unified;
+                       cache-level = <3>;
+               };
+
+               L3_CA55_2: cache-controller-2 {
+                       compatible = "cache";
+                       power-domains = <&sysc R8A779F0_PD_A2E1D0>;
+                       cache-unified;
+                       cache-level = <3>;
+               };
+
+               L3_CA55_3: cache-controller-3 {
+                       compatible = "cache";
+                       power-domains = <&sysc R8A779F0_PD_A2E1D1>;
+                       cache-unified;
+                       cache-level = <3>;
+               };
+
+               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>;
+                       };
                };
        };
 
                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 {
                compatible = "fixed-clock";
                        #power-domain-cells = <1>;
                };
 
+               tsc: thermal@e6198000 {
+                       compatible = "renesas,r8a779f0-thermal";
+                       /* The 4th sensor is in control domain and not for Linux */
+                       reg = <0 0xe6198000 0 0x200>,
+                             <0 0xe61a0000 0 0x200>,
+                             <0 0xe61a8000 0 0x200>;
+                       clocks = <&cpg CPG_MOD 919>;
+                       power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
+                       resets = <&cpg 919>;
+                       #thermal-sensor-cells = <1>;
+               };
+
                i2c0: i2c@e6500000 {
                        compatible = "renesas,i2c-r8a779f0",
                                     "renesas,rcar-gen4-i2c";
                        status = "disabled";
                };
 
+               hscif0: serial@e6540000 {
+                       compatible = "renesas,hscif-r8a779f0",
+                                    "renesas,rcar-gen4-hscif", "renesas,hscif";
+                       reg = <0 0xe6540000 0 0x60>;
+                       interrupts = <GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 514>,
+                                <&cpg CPG_CORE R8A779F0_CLK_S0D3>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac0 0x31>, <&dmac0 0x30>,
+                              <&dmac1 0x31>, <&dmac1 0x30>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
+                       resets = <&cpg 514>;
+                       status = "disabled";
+               };
+
+               hscif1: serial@e6550000 {
+                       compatible = "renesas,hscif-r8a779f0",
+                                    "renesas,rcar-gen4-hscif", "renesas,hscif";
+                       reg = <0 0xe6550000 0 0x60>;
+                       interrupts = <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 515>,
+                                <&cpg CPG_CORE R8A779F0_CLK_S0D3>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac0 0x33>, <&dmac0 0x32>,
+                              <&dmac1 0x33>, <&dmac1 0x32>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
+                       resets = <&cpg 515>;
+                       status = "disabled";
+               };
+
+               hscif2: serial@e6560000 {
+                       compatible = "renesas,hscif-r8a779f0",
+                                    "renesas,rcar-gen4-hscif", "renesas,hscif";
+                       reg = <0 0xe6560000 0 0x60>;
+                       interrupts = <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 516>,
+                                <&cpg CPG_CORE R8A779F0_CLK_S0D3>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac0 0x35>, <&dmac0 0x34>,
+                              <&dmac1 0x35>, <&dmac1 0x34>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
+                       resets = <&cpg 516>;
+                       status = "disabled";
+               };
+
+               hscif3: serial@e66a0000 {
+                       compatible = "renesas,hscif-r8a779f0",
+                                    "renesas,rcar-gen4-hscif", "renesas,hscif";
+                       reg = <0 0xe66a0000 0 0x60>;
+                       interrupts = <GIC_SPI 248 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 517>,
+                                <&cpg CPG_CORE R8A779F0_CLK_S0D3>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac0 0x37>, <&dmac0 0x36>,
+                              <&dmac1 0x37>, <&dmac1 0x36>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
+                       resets = <&cpg 517>;
+                       status = "disabled";
+               };
+
+               ufs: ufs@e6860000 {
+                       compatible = "renesas,r8a779f0-ufs";
+                       reg = <0 0xe6860000 0 0x100>;
+                       interrupts = <GIC_SPI 235 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 1514>, <&ufs30_clk>;
+                       clock-names = "fck", "ref_clk";
+                       freq-table-hz = <200000000 200000000>, <38400000 38400000>;
+                       power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
+                       resets = <&cpg 1514>;
+                       status = "disabled";
+               };
+
+               scif0: serial@e6e60000 {
+                       compatible = "renesas,scif-r8a779f0",
+                                    "renesas,rcar-gen4-scif", "renesas,scif";
+                       reg = <0 0xe6e60000 0 64>;
+                       interrupts = <GIC_SPI 249 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 702>,
+                                <&cpg CPG_CORE R8A779F0_CLK_S0D3_PER>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac0 0x51>, <&dmac0 0x50>,
+                              <&dmac1 0x51>, <&dmac1 0x50>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
+                       resets = <&cpg 702>;
+                       status = "disabled";
+               };
+
+               scif1: serial@e6e68000 {
+                       compatible = "renesas,scif-r8a779f0",
+                                    "renesas,rcar-gen4-scif", "renesas,scif";
+                       reg = <0 0xe6e68000 0 64>;
+                       interrupts = <GIC_SPI 250 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 703>,
+                                <&cpg CPG_CORE R8A779F0_CLK_S0D3_PER>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac0 0x53>, <&dmac0 0x52>,
+                              <&dmac1 0x53>, <&dmac1 0x52>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
+                       resets = <&cpg 703>;
+                       status = "disabled";
+               };
+
                scif3: serial@e6c50000 {
                        compatible = "renesas,scif-r8a779f0",
                                     "renesas,rcar-gen4-scif", "renesas,scif";
                                 <&cpg CPG_CORE R8A779F0_CLK_S0D3_PER>,
                                 <&scif_clk>;
                        clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac0 0x57>, <&dmac0 0x56>,
+                              <&dmac1 0x57>, <&dmac1 0x56>;
+                       dma-names = "tx", "rx", "tx", "rx";
                        power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
                        resets = <&cpg 704>;
                        status = "disabled";
                };
 
+               scif4: serial@e6c40000 {
+                       compatible = "renesas,scif-r8a779f0",
+                                    "renesas,rcar-gen4-scif", "renesas,scif";
+                       reg = <0 0xe6c40000 0 64>;
+                       interrupts = <GIC_SPI 253 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&cpg CPG_MOD 705>,
+                                <&cpg CPG_CORE R8A779F0_CLK_S0D3_PER>,
+                                <&scif_clk>;
+                       clock-names = "fck", "brg_int", "scif_clk";
+                       dmas = <&dmac0 0x59>, <&dmac0 0x58>,
+                              <&dmac1 0x59>, <&dmac1 0x58>;
+                       dma-names = "tx", "rx", "tx", "rx";
+                       power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
+                       resets = <&cpg 705>;
+                       status = "disabled";
+               };
+
                dmac0: dma-controller@e7350000 {
                        compatible = "renesas,dmac-r8a779f0",
                                     "renesas,rcar-gen4-dmac";
                        resets = <&cpg 709>;
                        #dma-cells = <1>;
                        dma-channels = <16>;
+                       iommus = <&ipmmu_ds0 0>, <&ipmmu_ds0 1>,
+                                <&ipmmu_ds0 2>, <&ipmmu_ds0 3>,
+                                <&ipmmu_ds0 4>, <&ipmmu_ds0 5>,
+                                <&ipmmu_ds0 6>, <&ipmmu_ds0 7>,
+                                <&ipmmu_ds0 8>, <&ipmmu_ds0 9>,
+                                <&ipmmu_ds0 10>, <&ipmmu_ds0 11>,
+                                <&ipmmu_ds0 12>, <&ipmmu_ds0 13>,
+                                <&ipmmu_ds0 14>, <&ipmmu_ds0 15>;
                };
 
                dmac1: dma-controller@e7351000 {
                        resets = <&cpg 710>;
                        #dma-cells = <1>;
                        dma-channels = <16>;
+                       iommus = <&ipmmu_ds0 16>, <&ipmmu_ds0 17>,
+                                <&ipmmu_ds0 18>, <&ipmmu_ds0 19>,
+                                <&ipmmu_ds0 20>, <&ipmmu_ds0 21>,
+                                <&ipmmu_ds0 22>, <&ipmmu_ds0 23>,
+                                <&ipmmu_ds0 24>, <&ipmmu_ds0 25>,
+                                <&ipmmu_ds0 26>, <&ipmmu_ds0 27>,
+                                <&ipmmu_ds0 28>, <&ipmmu_ds0 29>,
+                                <&ipmmu_ds0 30>, <&ipmmu_ds0 31>;
+               };
+
+               ipmmu_rt0: iommu@ee480000 {
+                       compatible = "renesas,ipmmu-r8a779f0",
+                                    "renesas,rcar-gen4-ipmmu-vmsa";
+                       reg = <0 0xee480000 0 0x20000>;
+                       renesas,ipmmu-main = <&ipmmu_mm 10>;
+                       power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
+                       #iommu-cells = <1>;
+               };
+
+               ipmmu_rt1: iommu@ee4c0000 {
+                       compatible = "renesas,ipmmu-r8a779f0",
+                                    "renesas,rcar-gen4-ipmmu-vmsa";
+                       reg = <0 0xee4c0000 0 0x20000>;
+                       renesas,ipmmu-main = <&ipmmu_mm 19>;
+                       power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
+                       #iommu-cells = <1>;
+               };
+
+               ipmmu_ds0: iommu@eed00000 {
+                       compatible = "renesas,ipmmu-r8a779f0",
+                                    "renesas,rcar-gen4-ipmmu-vmsa";
+                       reg = <0 0xeed00000 0 0x20000>;
+                       renesas,ipmmu-main = <&ipmmu_mm 0>;
+                       power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
+                       #iommu-cells = <1>;
+               };
+
+               ipmmu_hc: iommu@eed40000 {
+                       compatible = "renesas,ipmmu-r8a779f0",
+                                    "renesas,rcar-gen4-ipmmu-vmsa";
+                       reg = <0 0xeed40000 0 0x20000>;
+                       renesas,ipmmu-main = <&ipmmu_mm 2>;
+                       power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
+                       #iommu-cells = <1>;
+               };
+
+               ipmmu_mm: iommu@eefc0000 {
+                       compatible = "renesas,ipmmu-r8a779f0",
+                                    "renesas,rcar-gen4-ipmmu-vmsa";
+                       reg = <0 0xeefc0000 0 0x20000>;
+                       interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
+                       power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
+                       #iommu-cells = <1>;
                };
 
                gic: interrupt-controller@f1000000 {
                        reg = <0x0 0xf1000000 0 0x20000>,
                              <0x0 0xf1060000 0 0x110000>;
                        interrupts = <GIC_PPI 9
-                                     (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_HIGH)>;
+                                     (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_HIGH)>;
                };
 
                prr: chipid@fff00044 {
                };
        };
 
+       thermal-zones {
+               sensor_thermal1: sensor1-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tsc 0>;
+
+                       trips {
+                               sensor1_crit: sensor1-crit {
+                                       temperature = <120000>;
+                                       hysteresis = <1000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               sensor_thermal2: sensor2-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tsc 1>;
+
+                       trips {
+                               sensor2_crit: sensor2-crit {
+                                       temperature = <120000>;
+                                       hysteresis = <1000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               sensor_thermal3: sensor3-thermal {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tsc 2>;
+
+                       trips {
+                               sensor3_crit: sensor3-crit {
+                                       temperature = <120000>;
+                                       hysteresis = <1000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+       };
+
        timer {
                compatible = "arm,armv8-timer";
-               interrupts-extended = <&gic GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>,
-                                     <&gic GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>,
-                                     <&gic GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>,
-                                     <&gic GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>;
+               interrupts-extended = <&gic GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
+                                     <&gic GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
+                                     <&gic GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
+                                     <&gic GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>;
+       };
+
+       ufs30_clk: ufs30-clk {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               /* This value must be overridden by the board */
+               clock-frequency = <0>;
        };
 };
index 752440b..750bd8c 100644 (file)
@@ -10,3 +10,8 @@
 / {
        compatible = "renesas,r8a779m8", "renesas,r8a7795";
 };
+
+&cluster0_opp {
+       /delete-node/ opp-1600000000;
+       /delete-node/ opp-1700000000;
+};
index b31fb71..40201a1 100644 (file)
                };
 
                adc: adc@10059000 {
+                       compatible = "renesas,r9a07g043-adc", "renesas,rzg2l-adc";
                        reg = <0 0x10059000 0 0x400>;
-                       /* place holder */
+                       interrupts = <GIC_SPI 347 IRQ_TYPE_EDGE_RISING>;
+                       clocks = <&cpg CPG_MOD R9A07G043_ADC_ADCLK>,
+                                <&cpg CPG_MOD R9A07G043_ADC_PCLK>;
+                       clock-names = "adclk", "pclk";
+                       resets = <&cpg R9A07G043_ADC_PRESETN>,
+                                <&cpg R9A07G043_ADC_ADRST_N>;
+                       reset-names = "presetn", "adrst-n";
+                       power-domains = <&cpg>;
+                       status = "disabled";
+
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       channel@0 {
+                               reg = <0>;
+                       };
+                       channel@1 {
+                               reg = <1>;
+                       };
                };
 
                tsu: thermal@10059400 {
index 2d740bd..121e552 100644 (file)
@@ -13,9 +13,3 @@
        model = "Renesas SMARC EVK based on r9a07g043u11";
        compatible = "renesas,smarc-evk", "renesas,r9a07g043u11", "renesas,r9a07g043";
 };
-
-&spi1 {
-       /delete-property/ pinctrl-0;
-       /delete-property/ pinctrl-names;
-       status = "disabled";
-};
index 4e07e1a..3d01a4c 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
 /*
- * Device Tree Source for the RZ/G2L SMARC EVK board
+ * Device Tree Source for the RZ/V2L SMARC EVK board
  *
  * Copyright (C) 2021 Renesas Electronics Corp.
  */
index c207d8c..c3a52fa 100644 (file)
@@ -14,6 +14,7 @@
 
        aliases {
                serial0 = &uart0;
+               ethernet0 = &avb;
        };
 
        chosen {
        };
 };
 
+&avb {
+       renesas,no-ether-link;
+       phy-handle = <&phy0>;
+       phy-mode = "gmii";
+       status = "okay";
+
+       phy0: ethernet-phy@0 {
+               compatible = "ethernet-phy-id001c.c916",
+                            "ethernet-phy-ieee802.3-c22";
+               reg = <0>;
+       };
+};
+
 &extal_clk {
        clock-frequency = <48000000>;
 };
index 27810f4..d4cc545 100644 (file)
                        clock-names = "clk";
                };
 
+               avb: ethernet@a3300000 {
+                       compatible = "renesas,etheravb-r9a09g011","renesas,etheravb-rzv2m";
+                       reg = <0 0xa3300000 0 0x800>;
+                       interrupts = <GIC_SPI 251 IRQ_TYPE_LEVEL_HIGH>, /* ch0: Rx0 BE */
+                                    <GIC_SPI 252 IRQ_TYPE_LEVEL_HIGH>, /* ch1: Rx1 NC */
+                                    <GIC_SPI 253 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 254 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 255 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 257 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 258 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 259 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 260 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 265 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>, /* ch18: Tx0 BE */
+                                    <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>, /* ch19: Tx1 NC */
+                                    <GIC_SPI 271 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 273 IRQ_TYPE_LEVEL_HIGH>, /* DiA */
+                                    <GIC_SPI 274 IRQ_TYPE_LEVEL_HIGH>, /* DiB */
+                                    <GIC_SPI 275 IRQ_TYPE_LEVEL_HIGH>, /* Line1_A */
+                                    <GIC_SPI 276 IRQ_TYPE_LEVEL_HIGH>, /* Line1_B */
+                                    <GIC_SPI 277 IRQ_TYPE_LEVEL_HIGH>, /* Line2_A */
+                                    <GIC_SPI 278 IRQ_TYPE_LEVEL_HIGH>, /* Line2_B */
+                                    <GIC_SPI 279 IRQ_TYPE_LEVEL_HIGH>; /* Line3 MAC */
+                       interrupt-names = "ch0", "ch1", "ch2", "ch3",
+                                         "ch4", "ch5", "ch6", "ch7",
+                                         "ch8", "ch9", "ch10", "ch11",
+                                         "ch12", "ch13", "ch14", "ch15",
+                                         "ch16", "ch17", "ch18", "ch19",
+                                         "ch20", "ch21", "dia", "dib",
+                                         "err_a", "err_b", "mgmt_a", "mgmt_b",
+                                         "line3";
+                       clocks = <&cpg CPG_MOD R9A09G011_ETH0_CLK_AXI>,
+                                <&cpg CPG_MOD R9A09G011_ETH0_CLK_CHI>,
+                                <&cpg CPG_MOD R9A09G011_ETH0_GPTP_EXT>;
+                       clock-names = "axi", "chi", "gptp";
+                       resets = <&cpg R9A09G011_ETH0_RST_HW_N>;
+                       power-domains = <&cpg>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disable";
+               };
+
                cpg: clock-controller@a3500000 {
                        compatible = "renesas,r9a09g011-cpg";
                        reg = <0 0xa3500000 0 0x1000>;
index aeacd22..9410796 100644 (file)
@@ -34,7 +34,7 @@
                reg = <0x0 0x48000000 0x0 0x78000000>;
        };
 
-       reg_1p8v: regulator0 {
+       reg_1p8v: regulator-1p8v {
                compatible = "regulator-fixed";
                regulator-name = "fixed-1.8V";
                regulator-min-microvolt = <1800000>;
@@ -43,7 +43,7 @@
                regulator-always-on;
        };
 
-       reg_3p3v: regulator1 {
+       reg_3p3v: regulator-3p3v {
                compatible = "regulator-fixed";
                regulator-name = "fixed-3.3V";
                regulator-min-microvolt = <3300000>;
index 959a0ad..78e6e23 100644 (file)
@@ -23,7 +23,7 @@
                reg = <0x0 0x48000000 0x0 0x38000000>;
        };
 
-       reg_1p8v: regulator0 {
+       reg_1p8v: regulator-1p8v {
                compatible = "regulator-fixed";
                regulator-name = "fixed-1.8V";
                regulator-min-microvolt = <1800000>;
@@ -32,7 +32,7 @@
                regulator-always-on;
        };
 
-       reg_3p3v: regulator1 {
+       reg_3p3v: regulator-3p3v {
                compatible = "regulator-fixed";
                regulator-name = "fixed-3.3V";
                regulator-min-microvolt = <3300000>;
index aa17049..6be25a8 100644 (file)
@@ -29,7 +29,7 @@
 #define SW_RSPI_CAN    1
 #endif
 
-#if (SW_SCIF_CAN & SW_RSPI_CAN)
+#if (SW_SCIF_CAN && SW_RSPI_CAN)
 #error "Can not set 1 to both SW_SCIF_CAN and SW_RSPI_CAN due to HW routing"
 #endif
 
index a663115..cf3b3d1 100644 (file)
@@ -24,7 +24,7 @@
                reg = <0x0 0x48000000 0x0 0x38000000>;
        };
 
-       reg_1p8v: regulator0 {
+       reg_1p8v: regulator-1p8v {
                compatible = "regulator-fixed";
                regulator-name = "fixed-1.8V";
                regulator-min-microvolt = <1800000>;
@@ -33,7 +33,7 @@
                regulator-always-on;
        };
 
-       reg_3p3v: regulator1 {
+       reg_3p3v: regulator-3p3v {
                compatible = "regulator-fixed";
                regulator-name = "fixed-3.3V";
                regulator-min-microvolt = <3300000>;
 #endif
 };
 
+#if (SW_SW0_DEV_SEL)
+&adc {
+       pinctrl-0 = <&adc_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+};
+#endif
+
 #if (!SW_ET0_EN_N)
 &eth0 {
        pinctrl-0 = <&eth0_pins>;
 };
 
 &pinctrl {
+       adc_pins: adc {
+               pinmux = <RZG2L_PORT_PINMUX(6, 2, 1)>; /* ADC_TRG */
+       };
+
        eth0_pins: eth0 {
                pinmux = <RZG2L_PORT_PINMUX(4, 5, 1)>, /* ET0_LINKSTA */
                         <RZG2L_PORT_PINMUX(4, 3, 1)>, /* ET0_MDC */
                        pinmux = <RZG2L_PORT_PINMUX(0, 0, 1)>; /* SD0_CD */
                };
        };
+
+       spi1_pins: rspi1 {
+               pinmux = <RZG2L_PORT_PINMUX(4, 0, 2)>, /* CK */
+                        <RZG2L_PORT_PINMUX(4, 1, 2)>, /* MOSI */
+                        <RZG2L_PORT_PINMUX(4, 2, 2)>, /* MISO */
+                        <RZG2L_PORT_PINMUX(4, 3, 2)>; /* SSL */
+       };
 };
 
 #if (SW_SW0_DEV_SEL)
index 0051634..f9835c1 100644 (file)
        status = "disabled";
 };
 
+&spi1 {
+       /delete-property/ pinctrl-0;
+       /delete-property/ pinctrl-names;
+       status = "disabled";
+};
+
 &ssi1 {
        /delete-property/ pinctrl-0;
        /delete-property/ pinctrl-names;
index 31837fc..b7c7911 100644 (file)
                };
        };
 
-       reg_1p8v: regulator0 {
+       reg_1p8v: regulator-1p8v {
                compatible = "regulator-fixed";
                regulator-name = "fixed-1.8V";
                regulator-min-microvolt = <1800000>;
                regulator-always-on;
        };
 
-       reg_3p3v: regulator1 {
+       reg_3p3v: regulator-3p3v {
                compatible = "regulator-fixed";
                regulator-name = "fixed-3.3V";
                regulator-min-microvolt = <3300000>;
                regulator-always-on;
        };
 
-       reg_12v: regulator2 {
+       reg_12v: regulator-12v {
                compatible = "regulator-fixed";
                regulator-name = "fixed-12V";
                regulator-min-microvolt = <12000000>;
                                frame-master = <&rsnd_endpoint0>;
 
                                playback = <&ssi0>, <&src0>, <&dvc0>;
-                               capture  = <&ssi1>, <&src1>, <&dvc1>;
+                               capture = <&ssi1>, <&src1>, <&dvc1>;
                        };
                };
 
diff --git a/arch/arm64/boot/dts/renesas/salvator-panel-aa104xd12.dts b/arch/arm64/boot/dts/renesas/salvator-panel-aa104xd12.dts
new file mode 100644 (file)
index 0000000..c83a30a
--- /dev/null
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Device Tree overlay for the AA104XD12 panel connected to LVDS0 on a
+ * Salvator-X or Salvator-XS board
+ *
+ * Copyright 2021 Ideas on Board Oy
+ */
+
+/dts-v1/;
+/plugin/;
+
+&{/} {
+#include "panel-aa104xd12.dtsi"
+};
+
+&{/panel} {
+       backlight = <&backlight>;
+
+       port {
+               panel_in: endpoint {
+                       remote-endpoint = <&lvds0_out>;
+               };
+       };
+};
+
+&lvds0 {
+       status = "okay";
+
+       ports {
+               port@1 {
+                       lvds0_out: endpoint {
+                               remote-endpoint = <&panel_in>;
+                       };
+               };
+       };
+};
index 5bcb844..408871c 100644 (file)
                                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 = <&snd_3p3v>;
+                               VDD2-supply = <&snd_3p3v>;
+                               VCCAD1-supply = <&snd_vcc5v>;
+                               VCCAD2-supply = <&snd_vcc5v>;
+                               VCCDA1-supply = <&snd_vcc5v>;
+                               VCCDA2-supply = <&snd_vcc5v>;
 
                                ports {
                                        #address-cells = <1>;
                                bitclock-master;
                                frame-master;
                                dai-tdm-slot-num = <6>;
-                               capture  = <&ssi4>;
+                               capture = <&ssi4>;
                        };
                };
        };
index 90a4c06..0772dfe 100644 (file)
@@ -76,7 +76,7 @@
                };
        };
 
-       reg_1p8v: regulator0 {
+       reg_1p8v: regulator-1p8v {
                compatible = "regulator-fixed";
                regulator-name = "fixed-1.8V";
                regulator-min-microvolt = <1800000>;
@@ -85,7 +85,7 @@
                regulator-always-on;
        };
 
-       reg_3p3v: regulator1 {
+       reg_3p3v: regulator-3p3v {
                compatible = "regulator-fixed";
                regulator-name = "fixed-3.3V";
                regulator-min-microvolt = <3300000>;
                                bitclock-master;
                                frame-master;
                                playback = <&ssi0>, <&src0>, <&dvc0>;
-                               capture  = <&ssi1>, <&src1>, <&dvc1>;
+                               capture = <&ssi1>, <&src1>, <&dvc1>;
                        };
                };
                rsnd_port1: port@1 {
index 18d00ea..ef79a67 100644 (file)
@@ -5,6 +5,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-engicam-px30-core-ctouch2-of10.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-engicam-px30-core-edimm2.2.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3308-evb.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3308-roc-cc.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3308-rock-pi-s.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3318-a95x-z2.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3326-odroid-go2.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-a1.dtb
index 56dfbb2..214f94f 100644 (file)
        i2c0: i2c@ff180000 {
                compatible = "rockchip,px30-i2c", "rockchip,rk3399-i2c";
                reg = <0x0 0xff180000 0x0 0x1000>;
-               clocks =  <&cru SCLK_I2C0>, <&cru PCLK_I2C0>;
+               clocks = <&cru SCLK_I2C0>, <&cru PCLK_I2C0>;
                clock-names = "i2c", "pclk";
                interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
                pinctrl-names = "default";
index 9b4f855..9fe9b0d 100644 (file)
@@ -75,7 +75,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&pwr_key>;
 
-               power {
+               key-power {
                        gpios = <&gpio0 RK_PA6 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
                        label = "GPIO Key Power";
diff --git a/arch/arm64/boot/dts/rockchip/rk3308-rock-pi-s.dts b/arch/arm64/boot/dts/rockchip/rk3308-rock-pi-s.dts
new file mode 100644 (file)
index 0000000..a71f249
--- /dev/null
@@ -0,0 +1,253 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Akash Gajjar <akash@openedev.com>
+ * Copyright (c) 2019 Jagan Teki <jagan@openedev.com>
+ */
+
+/dts-v1/;
+#include "rk3308.dtsi"
+
+/ {
+       model = "Radxa ROCK Pi S";
+       compatible = "radxa,rockpis", "rockchip,rk3308";
+
+       aliases {
+               ethernet0 = &gmac;
+               mmc0 = &emmc;
+               mmc1 = &sdmmc;
+       };
+
+       chosen {
+               stdout-path = "serial0:1500000n8";
+       };
+
+       leds {
+               compatible = "gpio-leds";
+               pinctrl-names = "default";
+               pinctrl-0 = <&green_led_gio>, <&heartbeat_led_gpio>;
+
+               green-led {
+                       default-state = "on";
+                       gpios = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>;
+                       label = "rockpis:green:power";
+                       linux,default-trigger = "default-on";
+               };
+
+               blue-led {
+                       default-state = "on";
+                       gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_HIGH>;
+                       label = "rockpis:blue:user";
+                       linux,default-trigger = "heartbeat";
+               };
+       };
+
+       sdio_pwrseq: sdio-pwrseq {
+               compatible = "mmc-pwrseq-simple";
+               pinctrl-0 = <&wifi_enable_h>;
+               pinctrl-names = "default";
+               reset-gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_LOW>;
+       };
+
+       vcc_1v8: vcc-1v8 {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc_1v8";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               vin-supply = <&vcc_io>;
+       };
+
+       vcc_io: vcc-io {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc_io";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&vcc5v0_sys>;
+       };
+
+       vcc_ddr: vcc-ddr {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc_ddr";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <1500000>;
+               regulator-max-microvolt = <1500000>;
+               vin-supply = <&vcc5v0_sys>;
+       };
+
+       vcc5v0_otg: vcc5v0-otg {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio0 RK_PC5 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&otg_vbus_drv>;
+               regulator-name = "vcc5v0_otg";
+               regulator-always-on;
+               vin-supply = <&vcc5v0_sys>;
+       };
+
+       vcc5v0_sys: vcc5v0-sys {
+               compatible = "regulator-fixed";
+               regulator-name = "vcc5v0_sys";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <5000000>;
+               regulator-max-microvolt = <5000000>;
+       };
+
+       vdd_core: vdd-core {
+               compatible = "pwm-regulator";
+               pwms = <&pwm0 0 5000 1>;
+               pwm-supply = <&vcc5v0_sys>;
+               regulator-name = "vdd_core";
+               regulator-min-microvolt = <827000>;
+               regulator-max-microvolt = <1340000>;
+               regulator-init-microvolt = <1015000>;
+               regulator-settling-time-up-us = <250>;
+               regulator-always-on;
+               regulator-boot-on;
+       };
+
+       vdd_log: vdd-log {
+               compatible = "regulator-fixed";
+               regulator-name = "vdd_log";
+               regulator-always-on;
+               regulator-boot-on;
+               regulator-min-microvolt = <1050000>;
+               regulator-max-microvolt = <1050000>;
+               vin-supply = <&vcc5v0_sys>;
+       };
+};
+
+&cpu0 {
+       cpu-supply = <&vdd_core>;
+};
+
+&emmc {
+       bus-width = <4>;
+       cap-mmc-highspeed;
+       mmc-hs200-1_8v;
+       non-removable;
+       vmmc-supply = <&vcc_io>;
+       status = "okay";
+};
+
+&gmac {
+       clock_in_out = "output";
+       phy-supply = <&vcc_io>;
+       snps,reset-gpio = <&gpio0 RK_PA7 GPIO_ACTIVE_LOW>;
+       snps,reset-active-low;
+       snps,reset-delays-us = <0 50000 50000>;
+       status = "okay";
+};
+
+&i2c1 {
+       status = "okay";
+};
+
+&pinctrl {
+       pinctrl-names = "default";
+       pinctrl-0 = <&rtc_32k>;
+
+       leds {
+               green_led_gio: green-led-gpio {
+                       rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               heartbeat_led_gpio: heartbeat-led-gpio {
+                       rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       usb {
+               otg_vbus_drv: otg-vbus-drv {
+                       rockchip,pins = <0 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
+       sdio-pwrseq {
+               wifi_enable_h: wifi-enable-h {
+                       rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+
+               wifi_host_wake: wifi-host-wake {
+                       rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_down>;
+               };
+       };
+};
+
+&pwm0 {
+       status = "okay";
+       pinctrl-0 = <&pwm0_pin_pull_down>;
+};
+
+&saradc {
+       vref-supply = <&vcc_1v8>;
+       status = "okay";
+};
+
+&sdio {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       cap-sd-highspeed;
+       cap-sdio-irq;
+       keep-power-in-suspend;
+       max-frequency = <1000000>;
+       mmc-pwrseq = <&sdio_pwrseq>;
+       non-removable;
+       sd-uhs-sdr104;
+       status = "okay";
+};
+
+&sdmmc {
+       cap-sd-highspeed;
+       status = "okay";
+};
+
+&u2phy {
+       status = "okay";
+
+       u2phy_host: host-port {
+               phy-supply = <&vcc5v0_otg>;
+               status = "okay";
+       };
+
+       u2phy_otg: otg-port {
+               phy-supply = <&vcc5v0_otg>;
+               status = "okay";
+       };
+};
+
+&uart0 {
+       status = "okay";
+};
+
+&uart4 {
+       status = "okay";
+
+       bluetooth {
+               compatible = "realtek,rtl8723bs-bt";
+               device-wake-gpios = <&gpio4 RK_PB3 GPIO_ACTIVE_HIGH>;
+               host-wake-gpios = <&gpio4 RK_PB4 GPIO_ACTIVE_HIGH>;
+       };
+};
+
+&usb_host_ehci {
+       status = "okay";
+};
+
+&usb_host_ohci {
+       status = "okay";
+};
+
+&usb20_otg {
+       dr_mode = "peripheral";
+       status = "okay";
+};
+
+&wdt {
+       status = "okay";
+};
index ea0695b..415aa9f 100644 (file)
                 * |------------------------------------------------|
                 */
 
-               sw1 {
+               button-sw1 {
                        gpios = <&gpio1 RK_PB4 GPIO_ACTIVE_LOW>;
                        label = "DPAD-UP";
                        linux,code = <BTN_DPAD_UP>;
                };
-               sw2 {
+               button-sw2 {
                        gpios = <&gpio1 RK_PB5 GPIO_ACTIVE_LOW>;
                        label = "DPAD-DOWN";
                        linux,code = <BTN_DPAD_DOWN>;
                };
-               sw3 {
+               button-sw3 {
                        gpios = <&gpio1 RK_PB6 GPIO_ACTIVE_LOW>;
                        label = "DPAD-LEFT";
                        linux,code = <BTN_DPAD_LEFT>;
                };
-               sw4 {
+               button-sw4 {
                        gpios = <&gpio1 RK_PB7 GPIO_ACTIVE_LOW>;
                        label = "DPAD-RIGHT";
                        linux,code = <BTN_DPAD_RIGHT>;
                };
-               sw5 {
+               button-sw5 {
                        gpios = <&gpio1 RK_PA2 GPIO_ACTIVE_LOW>;
                        label = "BTN-A";
                        linux,code = <BTN_EAST>;
                };
-               sw6 {
+               button-sw6 {
                        gpios = <&gpio1 RK_PA5 GPIO_ACTIVE_LOW>;
                        label = "BTN-B";
                        linux,code = <BTN_SOUTH>;
                };
-               sw7 {
+               button-sw7 {
                        gpios = <&gpio1 RK_PA6 GPIO_ACTIVE_LOW>;
                        label = "BTN-Y";
                        linux,code = <BTN_WEST>;
                };
-               sw8 {
+               button-sw8 {
                        gpios = <&gpio1 RK_PA7 GPIO_ACTIVE_LOW>;
                        label = "BTN-X";
                        linux,code = <BTN_NORTH>;
                };
-               sw9 {
+               button-sw9 {
                        gpios = <&gpio2 RK_PA0 GPIO_ACTIVE_LOW>;
                        label = "F1";
                        linux,code = <BTN_TRIGGER_HAPPY1>;
                };
-               sw10 {
+               button-sw10 {
                        gpios = <&gpio2 RK_PA1 GPIO_ACTIVE_LOW>;
                        label = "F2";
                        linux,code = <BTN_TRIGGER_HAPPY2>;
                };
-               sw11 {
+               button-sw11 {
                        gpios = <&gpio2 RK_PA2 GPIO_ACTIVE_LOW>;
                        label = "F3";
                        linux,code = <BTN_TRIGGER_HAPPY3>;
                };
-               sw12 {
+               button-sw12 {
                        gpios = <&gpio2 RK_PA3 GPIO_ACTIVE_LOW>;
                        label = "F4";
                        linux,code = <BTN_TRIGGER_HAPPY4>;
                };
-               sw13 {
+               button-sw13 {
                        gpios = <&gpio2 RK_PA4 GPIO_ACTIVE_LOW>;
                        label = "F5";
                        linux,code = <BTN_TRIGGER_HAPPY5>;
                };
-               sw14 {
+               button-sw14 {
                        gpios = <&gpio2 RK_PA5 GPIO_ACTIVE_LOW>;
                        label = "F6";
                        linux,code = <BTN_TRIGGER_HAPPY6>;
                };
-               sw15 {
+               button-sw15 {
                        gpios = <&gpio2 RK_PA6 GPIO_ACTIVE_LOW>;
                        label = "TOP-LEFT";
                        linux,code = <BTN_TL>;
                };
-               sw16 {
+               button-sw16 {
                        gpios = <&gpio2 RK_PA7 GPIO_ACTIVE_LOW>;
                        label = "TOP-RIGHT";
                        linux,code = <BTN_TR>;
index 3857d48..1445b87 100644 (file)
@@ -34,7 +34,7 @@
                pinctrl-0 = <&reset_button_pin>;
                pinctrl-names = "default";
 
-               reset {
+               key-reset {
                        label = "reset";
                        gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_RESTART>;
index 15d1fc5..083452c 100644 (file)
@@ -76,7 +76,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&pwr_key>;
 
-               power {
+               key-power {
                        wakeup-source;
                        gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_LOW>;
                        label = "GPIO Power";
index 62aa97a..be06e6e 100644 (file)
@@ -43,7 +43,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&pwr_key>;
 
-               power {
+               key-power {
                        gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_LOW>;
                        label = "GPIO Power";
                        linux,code = <KEY_POWER>;
index 3ebe15e..7f5bba0 100644 (file)
@@ -44,7 +44,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&pwr_key>;
 
-               power {
+               key-power {
                        wakeup-source;
                        gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_HIGH>;
                        label = "GPIO Power";
 
        vccio_sd: vcc-io-sd-regulator {
                compatible = "regulator-fixed";
-               regulator-name= "vccio_sd";
+               regulator-name = "vccio_sd";
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <3300000>;
                regulator-always-on;
index 5ccaa5f..29df84b 100644 (file)
@@ -30,7 +30,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&pwr_key>;
 
-               power {
+               key-power {
                        gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_LOW>;
                        label = "GPIO Power";
                        linux,code = <KEY_POWER>;
index 959d3cc..38d757c 100644 (file)
@@ -37,7 +37,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&pwr_key>;
 
-               power {
+               key-power {
                        wakeup-source;
                        gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_LOW>;
                        label = "GPIO Power";
index 4f0b5fe..a4c5aaf 100644 (file)
 
                gmac {
                        rgmii_pins: rgmii-pins {
-                               rockchip,pins = <3 RK_PC6 1 &pcfg_pull_none>,
+                               rockchip,pins = <3 RK_PC6 1 &pcfg_pull_none>,
                                                <3 RK_PD0 1 &pcfg_pull_none>,
                                                <3 RK_PC3 1 &pcfg_pull_none>,
                                                <3 RK_PB0 1 &pcfg_pull_none_12ma>,
                        };
 
                        rmii_pins: rmii-pins {
-                               rockchip,pins = <3 RK_PC6 1 &pcfg_pull_none>,
+                               rockchip,pins = <3 RK_PC6 1 &pcfg_pull_none>,
                                                <3 RK_PD0 1 &pcfg_pull_none>,
                                                <3 RK_PC3 1 &pcfg_pull_none>,
                                                <3 RK_PB0 1 &pcfg_pull_none_12ma>,
 
                spdif {
                        spdif_tx: spdif-tx {
-                               rockchip,pins = <2 RK_PC7 1 &pcfg_pull_none>;
+                               rockchip,pins = <2 RK_PC7 1 &pcfg_pull_none>;
                        };
                };
 
index 7b717eb..3d1e126 100644 (file)
@@ -55,7 +55,7 @@
        };
 
        edp_panel: edp-panel {
-               compatible ="lg,lp079qx1-sp0v";
+               compatible = "lg,lp079qx1-sp0v";
                backlight = <&backlight>;
                enable-gpios = <&gpio1 RK_PB5 GPIO_ACTIVE_HIGH>;
                power-supply = <&vcc3v3_s0>;
index b340c9e..c5db64f 100644 (file)
@@ -87,7 +87,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&pwrbtn>;
 
-               power {
+               key-power {
                        debounce-interval = <100>;
                        gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>;
                        label = "GPIO Key Power";
index 50d459e..cd07464 100644 (file)
                pinctrl-names = "default";
                pinctrl-0 = <&bt_host_wake_l>;
 
-               wake_on_bt: wake-on-bt {
+               wake_on_bt: key-wake-on-bt {
                        label = "Wake-on-Bluetooth";
                        gpios = <&gpio0 3 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_WAKEUP>;
index 6863689..2cc9b33 100644 (file)
@@ -92,7 +92,7 @@
        pinctrl-names = "default";
        pinctrl-0 = <&bt_host_wake_l>, <&cpu1_pen_eject>;
 
-       pen-insert {
+       switch-pen-insert {
                label = "Pen Insert";
                /* Insert = low, eject = high */
                gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
index 913d845..40d4053 100644 (file)
                pinctrl-names = "default";
                pinctrl-0 = <&pen_eject_odl>;
 
-               pen-insert {
+               switch-pen-insert {
                        label = "Pen Insert";
                        /* Insert = low, eject = high */
                        gpios = <&gpio1 1 GPIO_ACTIVE_LOW>;
@@ -376,7 +376,8 @@ camera: &i2c7 {
                <&cru ACLK_VIO>,
                <&cru ACLK_GIC_PRE>,
                <&cru PCLK_DDR>,
-               <&cru ACLK_HDCP>;
+               <&cru ACLK_HDCP>,
+               <&cru ACLK_VDU>;
        assigned-clock-rates =
                <600000000>, <1600000000>,
                <1000000000>,
@@ -388,6 +389,7 @@ camera: &i2c7 {
                <400000000>,
                <200000000>,
                <200000000>,
+               <400000000>,
                <400000000>;
 };
 
index 46c4581..2a33276 100644 (file)
                pinctrl-names = "default";
                pinctrl-0 = <&pwrbtn>;
 
-               power {
+               key-power {
                        debounce-interval = <100>;
                        gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>;
                        label = "GPIO Key Power";
index cef4d18..fe5b526 100644 (file)
@@ -46,9 +46,9 @@
        gpio-keys {
                pinctrl-0 = <&reset_button_pin>;
 
-               /delete-node/ power;
+               /delete-node/ key-power;
 
-               reset {
+               key-reset {
                        debounce-interval = <50>;
                        gpios = <&gpio1 RK_PC6 GPIO_ACTIVE_LOW>;
                        label = "reset";
index 248ad41..278123b 100644 (file)
                pinctrl-names = "default";
                pinctrl-0 = <&power_key>;
 
-               power {
+               key-power {
                        debounce-interval = <100>;
                        gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>;
                        label = "GPIO Key Power";
index ed856bf..9e2e246 100644 (file)
@@ -78,7 +78,7 @@
                compatible = "gpio-keys";
                autorepeat;
 
-               power {
+               key-power {
                        debounce-interval = <100>;
                        gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>;
                        label = "GPIO Power";
index d6b68d7..194e48c 100644 (file)
@@ -76,7 +76,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&lidbtn_pin>;
 
-               lid {
+               switch-lid {
                        debounce-interval = <20>;
                        gpios = <&gpio1 RK_PA1 GPIO_ACTIVE_LOW>;
                        label = "Lid";
@@ -92,7 +92,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&pwrbtn_pin>;
 
-               power {
+               key-power {
                        debounce-interval = <20>;
                        gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>;
                        label = "Power";
index 3ae5d72..04c752f 100644 (file)
@@ -49,7 +49,7 @@
        sgtl5000_clk: sgtl5000-oscillator  {
                        compatible = "fixed-clock";
                        #clock-cells = <0>;
-                       clock-frequency  = <24576000>;
+                       clock-frequency = <24576000>;
        };
 
        dc_12v: dc-12v {
index 0e45cc2..acb174d 100644 (file)
@@ -54,7 +54,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&pwr_key_l>;
 
-               power {
+               key-power {
                        debounce-interval = <100>;
                        gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>;
                        label = "GPIO Key Power";
index 45e77f8..7815752 100644 (file)
                stdout-path = "serial2:1500000n8";
        };
 
+       /* enable for panel backlight support */
+       backlight: backlight {
+               compatible = "pwm-backlight";
+               brightness-levels = <0 4 8 16 32 64 128 255>;
+               default-brightness-level = <5>;
+               pwms = <&pwm0 0 1000000 0>;
+               status = "disabled";
+       };
+
        clkin_gmac: external-gmac-clock {
                compatible = "fixed-clock";
                clock-frequency = <125000000>;
@@ -33,7 +42,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&pwrbtn>;
 
-               power {
+               key-power {
                        debounce-interval = <100>;
                        gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>;
                        label = "GPIO Key Power";
                };
        };
 
+       avdd: avdd-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "avdd";
+               regulator-min-microvolt = <11000000>;
+               regulator-max-microvolt = <11000000>;
+               vin-supply = <&vcc3v3_s0>;
+       };
+
        vcc12v_dcin: vcc12v-dcin {
                compatible = "regulator-fixed";
                regulator-name = "vcc12v_dcin";
 
                        vcc3v0_touch: LDO_REG2 {
                                regulator-name = "vcc3v0_touch";
-                               regulator-always-on;
-                               regulator-boot-on;
                                regulator-min-microvolt = <3000000>;
                                regulator-max-microvolt = <3000000>;
                                regulator-state-mem {
 
                        vcc3v3_s0: SWITCH_REG2 {
                                regulator-name = "vcc3v3_s0";
-                               regulator-always-on;
-                               regulator-boot-on;
                                regulator-state-mem {
                                        regulator-off-in-suspend;
                                };
                vbus-supply = <&vcc5v0_typec>;
                status = "okay";
        };
+
+       /* enable for pine64 touch screen support */
+       touch: touchscreen@5d {
+               compatible = "goodix,gt911";
+               reg = <0x5d>;
+               interrupt-parent = <&gpio4>;
+               interrupts = <RK_PD5 IRQ_TYPE_EDGE_FALLING>;
+               AVDD28-supply = <&vcc3v0_touch>;
+               VDDIO-supply = <&vcc3v0_touch>;
+               irq-gpios = <&gpio4 RK_PD5 GPIO_ACTIVE_HIGH>;
+               reset-gpios = <&gpio4 RK_PD6 GPIO_ACTIVE_HIGH>;
+               status = "disabled";
+       };
 };
 
 &i2s0 {
        gpio1830-supply = <&vcc_3v0>;
 };
 
+/* enable for pine64 panel display support */
+&mipi_dsi {
+       clock-master;
+       status = "disabled";
+
+       ports {
+               mipi_out: port@1 {
+                       reg = <1>;
+
+                       mipi_out_panel: endpoint {
+                               remote-endpoint = <&mipi_in_panel>;
+                       };
+               };
+       };
+
+       mipi_panel: panel@0 {
+               compatible = "feiyang,fy07024di26a30d";
+               reg = <0>;
+               avdd-supply = <&avdd>;
+               backlight = <&backlight>;
+               dvdd-supply = <&vcc3v3_s0>;
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+
+                               mipi_in_panel: endpoint {
+                                       remote-endpoint = <&mipi_out_panel>;
+                               };
+                       };
+               };
+       };
+};
+
 &pcie0 {
        ep-gpios = <&gpio2 RK_PD4 GPIO_ACTIVE_HIGH>;
        num-lanes = <4>;
index f6b2199..13927e7 100644 (file)
@@ -88,7 +88,7 @@
        };
 
        edp_panel: edp-panel {
-               compatible ="lg,lp079qx1-sp0v";
+               compatible = "lg,lp079qx1-sp0v";
                backlight = <&backlight>;
                enable-gpios = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>;
                pinctrl-names = "default";
index 2aa0fad..e6ac292 100644 (file)
@@ -53,7 +53,7 @@
                compatible = "gpio-keys";
                autorepeat;
 
-               power {
+               key-power {
                        debounce-interval = <100>;
                        gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>;
                        label = "GPIO Power";
index fbd0346..9d5b0e8 100644 (file)
                        <&cru HCLK_PERILP1>, <&cru PCLK_PERILP1>,
                        <&cru ACLK_VIO>, <&cru ACLK_HDCP>,
                        <&cru ACLK_GIC_PRE>,
-                       <&cru PCLK_DDR>;
+                       <&cru PCLK_DDR>,
+                       <&cru ACLK_VDU>;
                assigned-clock-rates =
                         <594000000>,  <800000000>,
                        <1000000000>,
                         <100000000>,   <50000000>,
                         <400000000>, <400000000>,
                         <200000000>,
-                        <200000000>;
+                        <200000000>,
+                        <400000000>;
        };
 
        grf: syscon@ff770000 {
index 01d1a75..935b8c6 100644 (file)
 
        pcie {
                pcie_pwr: pcie-pwr {
-                       rockchip,pins = <4 RK_PD4 RK_FUNC_GPIO &pcfg_pull_up>;
+                       rockchip,pins = <4 RK_PD4 RK_FUNC_GPIO &pcfg_pull_up>;
                };
        };
 
index e01668e..0d45868 100644 (file)
@@ -49,7 +49,7 @@
                pinctrl-0 = <&hall_int_l>;
                pinctrl-names = "default";
 
-               cover {
+               switch-cover {
                        label = "cover";
                        gpios = <&gpio0 RK_PC7 GPIO_ACTIVE_LOW>;
                        linux,input-type = <EV_SW>;
index 1534e11..d943559 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
 #include "rk3566.dtsi"
 
 / {
                gpios = <&gpio0 RK_PD5 GPIO_ACTIVE_HIGH>;
                gpio-fan,speed-map = <0    0
                                      4500 1>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&fan_en_h>;
                #cooling-cells = <2>;
        };
 
+       hdmi-con {
+               compatible = "hdmi-connector";
+               type = "a";
+
+               port {
+                       hdmi_con_in: endpoint {
+                               remote-endpoint = <&hdmi_out_con>;
+                       };
+               };
+       };
+
        leds {
                compatible = "gpio-leds";
 
                vin-supply = <&vcc12v_dcin>;
        };
 
+       vcc3v3_pcie_p: vcc3v3-pcie-p-regulator {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio0 RK_PC6 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pcie_enable_h>;
+               regulator-name = "vcc3v3_pcie_p";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               vin-supply = <&vcc_3v3>;
+       };
+
        vcc5v0_usb: vcc5v0_usb {
                compatible = "regulator-fixed";
                regulator-name = "vcc5v0_usb";
        status = "okay";
 };
 
+&combphy2 {
+       status = "okay";
+};
+
 &cpu0 {
        cpu-supply = <&vdd_cpu>;
 };
        status = "okay";
 };
 
+&hdmi {
+       avdd-0v9-supply = <&vdda_0v9>;
+       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 {
        status = "okay";
 
        status = "okay";
 };
 
+&i2s0_8ch {
+       status = "okay";
+};
+
 &i2s1_8ch {
        pinctrl-names = "default";
        pinctrl-0 = <&i2s1m0_sclktx
        };
 };
 
+&pcie2x1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pcie_reset_h>;
+       reset-gpios = <&gpio1 RK_PB2 GPIO_ACTIVE_HIGH>;
+       vpcie3v3-supply = <&vcc3v3_pcie_p>;
+       status = "okay";
+};
+
 &pinctrl {
        bt {
                bt_enable_h: bt-enable-h {
                };
        };
 
+       fan {
+               fan_en_h: fan-en-h {
+                       rockchip,pins = <0 RK_PD5 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
        leds {
                work_led_enable_h: work-led-enable-h {
                        rockchip,pins = <0 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
+       pcie {
+               pcie_enable_h: pcie-enable-h {
+                       rockchip,pins = <0 RK_PC6 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>;
        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";
        status = "okay";
 };
 
+&sfc {
+       pinctrl-0 = <&fspi_pins>;
+       pinctrl-names = "default";
+       #address-cells = <1>;
+       #size-cells = <0>;
+       status = "disabled";
+
+       flash@0 {
+               compatible = "jedec,spi-nor";
+               reg = <0>;
+               spi-max-frequency = <24000000>;
+               spi-rx-bus-width = <4>;
+               spi-tx-bus-width = <1>;
+       };
+};
+
 /* spdif is exposed on con40 pin 18 */
 &spdif {
        status = "okay";
 };
 
 &usb_host0_xhci {
+       dr_mode = "host";
        status = "okay";
 };
 
        phy-supply = <&vcc5v0_usb20_host>;
        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>;
+       };
+};
index 7bdcecc..02d5f5a 100644 (file)
        assigned-clocks = <&cru SCLK_GMAC1_RX_TX>, <&cru SCLK_GMAC1_RGMII_SPEED>, <&cru SCLK_GMAC1>;
        assigned-clock-parents = <&cru SCLK_GMAC1_RGMII_SPEED>, <&cru SCLK_GMAC1>, <&gmac1_clkin>;
        clock_in_out = "input";
-       phy-mode = "rgmii-id";
+       phy-mode = "rgmii";
        phy-supply = <&vcc_3v3>;
        pinctrl-names = "default";
        pinctrl-0 = <&gmac1m1_miim
index 0b95706..6c4b17d 100644 (file)
@@ -29,3 +29,7 @@
        extcon = <&usb2phy0>;
        maximum-speed = "high-speed";
 };
+
+&vop {
+       compatible = "rockchip,rk3566-vop";
+};
index 40cf223..1d3ffbf 100644 (file)
@@ -8,6 +8,7 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/leds/common.h>
 #include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
 #include "rk3568.dtsi"
 
 / {
                regulator-max-microvolt = <12000000>;
        };
 
+       hdmi-con {
+               compatible = "hdmi-connector";
+               type = "a";
+
+               port {
+                       hdmi_con_in: endpoint {
+                               remote-endpoint = <&hdmi_out_con>;
+                       };
+               };
+       };
+
        vcc3v3_sys: vcc3v3-sys {
                compatible = "regulator-fixed";
                regulator-name = "vcc3v3_sys";
        status = "okay";
 };
 
+&gpu {
+       mali-supply = <&vdd_gpu>;
+       status = "okay";
+};
+
+&hdmi {
+       avdd-0v9-supply = <&vdda0v9_image>;
+       avdd-1v8-supply = <&vcca1v8_image>;
+       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 {
        status = "okay";
 
 
                        vdd_gpu: DCDC_REG2 {
                                regulator-name = "vdd_gpu";
+                               regulator-always-on;
                                regulator-init-microvolt = <900000>;
                                regulator-initial-mode = <0x2>;
                                regulator-min-microvolt = <500000>;
 
                        vdda0v9_image: LDO_REG1 {
                                regulator-name = "vdda0v9_image";
+                               regulator-always-on;
                                regulator-min-microvolt = <900000>;
                                regulator-max-microvolt = <900000>;
 
 
                        vcca1v8_image: LDO_REG9 {
                                regulator-name = "vcca1v8_image";
+                               regulator-always-on;
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <1800000>;
 
        };
 };
 
+&i2c3 {
+       status = "okay";
+
+       hym8563: rtc@51 {
+               compatible = "haoyu,hym8563";
+               reg = <0x51>;
+               interrupt-parent = <&gpio0>;
+               interrupts = <RK_PD3 IRQ_TYPE_EDGE_FALLING>;
+               #clock-cells = <0>;
+               clock-frequency = <32768>;
+               clock-output-names = "rtcic_32kout";
+               pinctrl-names = "default";
+               pinctrl-0 = <&hym8563_int>;
+               wakeup-source;
+       };
+};
+
 &i2c5 {
        /* pin 3 (SDA) + 4 (SCL) of header con2 */
        status = "disabled";
 };
 
+&i2s0_8ch {
+       /* hdmi sound */
+       status = "okay";
+};
+
 &mdio1 {
        rgmii_phy1: ethernet-phy@0 {
                compatible = "ethernet-phy-ieee802.3-c22";
                };
        };
 
+       hym8563 {
+               hym8563_int: hym8563-int {
+                       rockchip,pins = <0 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
+
        pmic {
                pmic_int: pmic_int {
                        rockchip,pins =
 };
 
 &tsadc {
+       rockchip,hw-tshut-mode = <1>;
+       rockchip,hw-tshut-polarity = <0>;
        status = "okay";
 };
 
        phy-supply = <&vcc5v0_usb_otg>;
        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>;
+       };
+};
index 622be8b..6ff89ff 100644 (file)
@@ -8,6 +8,7 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/leds/common.h>
 #include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
 #include "rk3568.dtsi"
 
 / {
                regulator-max-microvolt = <12000000>;
        };
 
+       hdmi-con {
+               compatible = "hdmi-connector";
+               type = "a";
+
+               port {
+                       hdmi_con_in: endpoint {
+                               remote-endpoint = <&hdmi_out_con>;
+                       };
+               };
+       };
+
        leds {
                compatible = "gpio-leds";
 
        status = "okay";
 };
 
+&hdmi {
+       avdd-0v9-supply = <&vdda0v9_image>;
+       avdd-1v8-supply = <&vcca1v8_image>;
+       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 {
        status = "okay";
 
        };
 };
 
+&i2s0_8ch {
+       status = "okay";
+};
+
 &i2s1_8ch {
        rockchip,trcm-sync-tx-only;
        status = "okay";
        phy-supply = <&vcc5v0_usb_host>;
        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>;
+       };
+};
index 0813c0c..6b5093a 100644 (file)
@@ -4,6 +4,7 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/leds/common.h>
 #include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
 #include "rk3568.dtsi"
 
 / {
                stdout-path = "serial2:1500000n8";
        };
 
+       hdmi-con {
+               compatible = "hdmi-connector";
+               type = "a";
+
+               port {
+                       hdmi_con_in: endpoint {
+                               remote-endpoint = <&hdmi_out_con>;
+                       };
+               };
+       };
+
        leds {
                compatible = "gpio-leds";
 
        status = "okay";
 };
 
+&hdmi {
+       avdd-0v9-supply = <&vdda0v9_image>;
+       avdd-1v8-supply = <&vcca1v8_image>;
+       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 {
        status = "okay";
 
        };
 };
 
+&i2s0_8ch {
+       status = "okay";
+};
+
 &i2s1_8ch {
        rockchip,trcm-sync-tx-only;
        status = "okay";
        phy-supply = <&vcc5v0_usb_host>;
        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>;
+       };
+};
index 5eafddf..2bdf8c7 100644 (file)
        phys = <&usb2phy0_otg>, <&combphy0 PHY_TYPE_USB3>;
        phy-names = "usb2-phy", "usb3-phy";
 };
+
+&vop {
+       compatible = "rockchip,rk3568-vop";
+};
index 914f13c..319981c 100644 (file)
                };
        };
 
+       display_subsystem: display-subsystem {
+               compatible = "rockchip,display-subsystem";
+               ports = <&vop_out>;
+       };
+
        firmware {
                scmi: scmi {
                        compatible = "arm,scmi-smc";
                };
        };
 
+       hdmi_sound: hdmi-sound {
+               compatible = "simple-audio-card";
+               simple-audio-card,name = "HDMI";
+               simple-audio-card,format = "i2s";
+               simple-audio-card,mclk-fs = <256>;
+               status = "disabled";
+
+               simple-audio-card,codec {
+                       sound-dai = <&hdmi>;
+               };
+
+               simple-audio-card,cpu {
+                       sound-dai = <&i2s0_8ch>;
+               };
+       };
+
        pmu {
                compatible = "arm,cortex-a55-pmu";
                interrupts = <GIC_SPI 228 IRQ_TYPE_LEVEL_HIGH>,
                };
        };
 
+       vop: vop@fe040000 {
+               reg = <0x0 0xfe040000 0x0 0x3000>, <0x0 0xfe044000 0x0 0x1000>;
+               reg-names = "vop", "gamma-lut";
+               interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cru ACLK_VOP>, <&cru HCLK_VOP>, <&cru DCLK_VOP0>,
+                        <&cru DCLK_VOP1>, <&cru DCLK_VOP2>;
+               clock-names = "aclk", "hclk", "dclk_vp0", "dclk_vp1", "dclk_vp2";
+               iommus = <&vop_mmu>;
+               power-domains = <&power RK3568_PD_VO>;
+               rockchip,grf = <&grf>;
+               status = "disabled";
+
+               vop_out: ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       vp0: port@0 {
+                               reg = <0>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+
+                       vp1: port@1 {
+                               reg = <1>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+
+                       vp2: port@2 {
+                               reg = <2>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+               };
+       };
+
+       vop_mmu: iommu@fe043e00 {
+               compatible = "rockchip,rk3568-iommu";
+               reg = <0x0 0xfe043e00 0x0 0x100>, <0x0 0xfe043f00 0x0 0x100>;
+               interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cru ACLK_VOP>, <&cru HCLK_VOP>;
+               clock-names = "aclk", "iface";
+               #iommu-cells = <0>;
+               status = "disabled";
+       };
+
+       hdmi: hdmi@fe0a0000 {
+               compatible = "rockchip,rk3568-dw-hdmi";
+               reg = <0x0 0xfe0a0000 0x0 0x20000>;
+               interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cru PCLK_HDMI_HOST>,
+                        <&cru CLK_HDMI_SFR>,
+                        <&cru CLK_HDMI_CEC>,
+                        <&pmucru CLK_HDMI_REF>,
+                        <&cru HCLK_VO>;
+               clock-names = "iahb", "isfr", "cec", "ref";
+               pinctrl-names = "default";
+               pinctrl-0 = <&hdmitx_scl &hdmitx_sda &hdmitxm0_cec>;
+               power-domains = <&power RK3568_PD_VO>;
+               reg-io-width = <4>;
+               rockchip,grf = <&grf>;
+               #sound-dai-cells = <0>;
+               status = "disabled";
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       hdmi_in: port@0 {
+                               reg = <0>;
+                       };
+
+                       hdmi_out: port@1 {
+                               reg = <1>;
+                       };
+               };
+       };
+
        qos_gpu: qos@fe128000 {
                compatible = "rockchip,rk3568-qos", "syscon";
                reg = <0x0 0xfe128000 0x0 0x20>;
                reg = <0x0 0xfe1a8100 0x0 0x20>;
        };
 
+       pcie2x1: pcie@fe260000 {
+               compatible = "rockchip,rk3568-pcie";
+               reg = <0x3 0xc0000000 0x0 0x00400000>,
+                     <0x0 0xfe260000 0x0 0x00010000>,
+                     <0x3 0x3f000000 0x0 0x01000000>;
+               reg-names = "dbi", "apb", "config";
+               interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "sys", "pmc", "msi", "legacy", "err";
+               bus-range = <0x0 0xf>;
+               clocks = <&cru ACLK_PCIE20_MST>, <&cru ACLK_PCIE20_SLV>,
+                        <&cru ACLK_PCIE20_DBI>, <&cru PCLK_PCIE20>,
+                        <&cru CLK_PCIE20_AUX_NDFT>;
+               clock-names = "aclk_mst", "aclk_slv",
+                             "aclk_dbi", "pclk", "aux";
+               device_type = "pci";
+               interrupt-map-mask = <0 0 0 7>;
+               interrupt-map = <0 0 0 1 &pcie_intc 0>,
+                               <0 0 0 2 &pcie_intc 1>,
+                               <0 0 0 3 &pcie_intc 2>,
+                               <0 0 0 4 &pcie_intc 3>;
+               linux,pci-domain = <0>;
+               num-ib-windows = <6>;
+               num-ob-windows = <2>;
+               max-link-speed = <2>;
+               msi-map = <0x0 &gic 0x0 0x1000>;
+               num-lanes = <1>;
+               phys = <&combphy2 PHY_TYPE_PCIE>;
+               phy-names = "pcie-phy";
+               power-domains = <&power RK3568_PD_PIPE>;
+               ranges = <0x01000000 0x0 0x3ef00000 0x3 0x3ef00000 0x0 0x00100000
+                         0x02000000 0x0 0x00000000 0x3 0x00000000 0x0 0x3ef00000>;
+               resets = <&cru SRST_PCIE20_POWERUP>;
+               reset-names = "pipe";
+               #address-cells = <3>;
+               #size-cells = <2>;
+               status = "disabled";
+
+               pcie_intc: legacy-interrupt-controller {
+                       #address-cells = <0>;
+                       #interrupt-cells = <1>;
+                       interrupt-controller;
+                       interrupt-parent = <&gic>;
+                       interrupts = <GIC_SPI 72 IRQ_TYPE_EDGE_RISING>;
+               };
+       };
+
        sdmmc0: mmc@fe2b0000 {
                compatible = "rockchip,rk3568-dw-mshc", "rockchip,rk3288-dw-mshc";
                reg = <0x0 0xfe2b0000 0x0 0x4000>;
                status = "disabled";
        };
 
+       i2s0_8ch: i2s@fe400000 {
+               compatible = "rockchip,rk3568-i2s-tdm";
+               reg = <0x0 0xfe400000 0x0 0x1000>;
+               interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
+               assigned-clocks = <&cru CLK_I2S0_8CH_TX_SRC>, <&cru CLK_I2S0_8CH_RX_SRC>;
+               assigned-clock-rates = <1188000000>, <1188000000>;
+               clocks = <&cru MCLK_I2S0_8CH_TX>, <&cru MCLK_I2S0_8CH_RX>, <&cru HCLK_I2S0_8CH>;
+               clock-names = "mclk_tx", "mclk_rx", "hclk";
+               dmas = <&dmac1 0>;
+               dma-names = "tx";
+               resets = <&cru SRST_M_I2S0_8CH_TX>, <&cru SRST_M_I2S0_8CH_RX>;
+               reset-names = "tx-m", "rx-m";
+               rockchip,grf = <&grf>;
+               #sound-dai-cells = <0>;
+               status = "disabled";
+       };
+
        i2s1_8ch: i2s@fe410000 {
                compatible = "rockchip,rk3568-i2s-tdm";
                reg = <0x0 0xfe410000 0x0 0x1000>;
index 231436b..8bb8a70 100644 (file)
        };
 
        psci {
-               compatible      = "arm,psci";
-               method          = "smc";
-               cpu_on          = <0xc4000003>;
-               cpu_off         = <0x84000002>;
-               cpu_suspend     = <0xc4000001>;
+               compatible = "arm,psci";
+               method = "smc";
+               cpu_on = <0xc4000003>;
+               cpu_off = <0x84000002>;
+               cpu_suspend = <0xc4000001>;
        };
 
        timer {
index 8cf4a65..22d81ac 100644 (file)
                        ranges;
 
                        sdio0: sdio@20300000 {
-                               compatible  = "sprd,sdhci-r11";
+                               compatible = "sprd,sdhci-r11";
                                reg = <0 0x20300000 0 0x1000>;
                                interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
 
                        };
 
                        sdio3: sdio@20600000 {
-                               compatible  = "sprd,sdhci-r11";
+                               compatible = "sprd,sdhci-r11";
                                reg = <0 0x20600000 0 0x1000>;
                                interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
 
index 89d91ab..fece497 100644 (file)
                        };
 
                        sdio3: sdio@50430000 {
-                               compatible  = "sprd,sdhci-r11";
+                               compatible = "sprd,sdhci-r11";
                                reg = <0 0x50430000 0 0x1000>;
                                interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
 
index 5af560c..1db6ddf 100644 (file)
@@ -37,3 +37,7 @@
 &serial_0 {
        status = "okay";
 };
+
+&ufs {
+       status = "okay";
+};
index d4d0cb0..d0abb9a 100644 (file)
@@ -8,7 +8,7 @@
  *             https://www.tesla.com
  */
 
-#include <dt-bindings/pinctrl/samsung.h>
+#include "fsd-pinctrl.h"
 
 &pinctrl_fsys0 {
        gpf0: gpf0-gpio-bank {
                interrupt-controller;
                #interrupt-cells = <2>;
        };
+
+       ufs_rst_n: ufs-rst-n-pins {
+               samsung,pins = "gpf5-0";
+               samsung,pin-function = <FSD_PIN_FUNC_2>;
+               samsung,pin-pud = <FSD_PIN_PULL_NONE>;
+               samsung,pin-drv = <FSD_PIN_DRV_LV2>;
+       };
+
+       ufs_refclk_out: ufs-refclk-out-pins {
+               samsung,pins = "gpf5-1";
+               samsung,pin-function = <FSD_PIN_FUNC_2>;
+               samsung,pin-pud = <FSD_PIN_PULL_NONE>;
+               samsung,pin-drv = <FSD_PIN_DRV_LV2>;
+       };
 };
 
 &pinctrl_peric {
 
        pwm0_out: pwm0-out-pins {
                samsung,pins = "gpb6-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV2>;
+               samsung,pin-function = <FSD_PIN_FUNC_2>;
+               samsung,pin-pud = <FSD_PIN_PULL_UP>;
+               samsung,pin-drv = <FSD_PIN_DRV_LV2>;
        };
 
        pwm1_out: pwm1-out-pins {
                samsung,pins = "gpb6-5";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV2>;
+               samsung,pin-function = <FSD_PIN_FUNC_2>;
+               samsung,pin-pud = <FSD_PIN_PULL_UP>;
+               samsung,pin-drv = <FSD_PIN_DRV_LV2>;
        };
 
        hs_i2c0_bus: hs-i2c0-bus-pins {
                samsung,pins = "gpb0-0", "gpb0-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <FSD_PIN_FUNC_2>;
+               samsung,pin-pud = <FSD_PIN_PULL_UP>;
+               samsung,pin-drv = <FSD_PIN_DRV_LV1>;
        };
 
        hs_i2c1_bus: hs-i2c1-bus-pins {
                samsung,pins = "gpb0-2", "gpb0-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <FSD_PIN_FUNC_2>;
+               samsung,pin-pud = <FSD_PIN_PULL_UP>;
+               samsung,pin-drv = <FSD_PIN_DRV_LV1>;
        };
 
        hs_i2c2_bus: hs-i2c2-bus-pins {
                samsung,pins = "gpb0-4", "gpb0-5";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <FSD_PIN_FUNC_2>;
+               samsung,pin-pud = <FSD_PIN_PULL_UP>;
+               samsung,pin-drv = <FSD_PIN_DRV_LV1>;
        };
 
        hs_i2c3_bus: hs-i2c3-bus-pins {
                samsung,pins = "gpb0-6", "gpb0-7";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <FSD_PIN_FUNC_2>;
+               samsung,pin-pud = <FSD_PIN_PULL_UP>;
+               samsung,pin-drv = <FSD_PIN_DRV_LV1>;
        };
 
        hs_i2c4_bus: hs-i2c4-bus-pins {
                samsung,pins = "gpb1-0", "gpb1-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <FSD_PIN_FUNC_2>;
+               samsung,pin-pud = <FSD_PIN_PULL_UP>;
+               samsung,pin-drv = <FSD_PIN_DRV_LV1>;
        };
 
        hs_i2c5_bus: hs-i2c5-bus-pins {
                samsung,pins = "gpb1-2", "gpb1-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <FSD_PIN_FUNC_2>;
+               samsung,pin-pud = <FSD_PIN_PULL_UP>;
+               samsung,pin-drv = <FSD_PIN_DRV_LV1>;
        };
 
        hs_i2c6_bus: hs-i2c6-bus-pins {
                samsung,pins = "gpb1-4", "gpb1-5";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <FSD_PIN_FUNC_2>;
+               samsung,pin-pud = <FSD_PIN_PULL_UP>;
+               samsung,pin-drv = <FSD_PIN_DRV_LV1>;
        };
 
        hs_i2c7_bus: hs-i2c7-bus-pins {
                samsung,pins = "gpb1-6", "gpb1-7";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <FSD_PIN_FUNC_2>;
+               samsung,pin-pud = <FSD_PIN_PULL_UP>;
+               samsung,pin-drv = <FSD_PIN_DRV_LV1>;
        };
 
        uart0_data: uart0-data-pins {
                samsung,pins = "gpb7-0", "gpb7-1";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <FSD_PIN_FUNC_2>;
+               samsung,pin-pud = <FSD_PIN_PULL_NONE>;
+               samsung,pin-drv = <FSD_PIN_DRV_LV1>;
        };
 
        uart1_data: uart1-data-pins {
                samsung,pins = "gpb7-4", "gpb7-5";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <FSD_PIN_FUNC_2>;
+               samsung,pin-pud = <FSD_PIN_PULL_NONE>;
+               samsung,pin-drv = <FSD_PIN_DRV_LV1>;
        };
 
        spi0_bus: spi0-bus-pins {
                samsung,pins = "gpb4-0", "gpb4-2", "gpb4-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <FSD_PIN_FUNC_2>;
+               samsung,pin-pud = <FSD_PIN_PULL_UP>;
+               samsung,pin-drv = <FSD_PIN_DRV_LV1>;
        };
 
        spi1_bus: spi1-bus-pins {
                samsung,pins = "gpb4-4", "gpb4-6", "gpb4-7";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <FSD_PIN_FUNC_2>;
+               samsung,pin-pud = <FSD_PIN_PULL_UP>;
+               samsung,pin-drv = <FSD_PIN_DRV_LV1>;
        };
 
        spi2_bus: spi2-bus-pins {
                samsung,pins = "gpb5-0", "gpb5-2", "gpb5-3";
-               samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-               samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-               samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+               samsung,pin-function = <FSD_PIN_FUNC_2>;
+               samsung,pin-pud = <FSD_PIN_PULL_UP>;
+               samsung,pin-drv = <FSD_PIN_DRV_LV1>;
        };
 };
 
diff --git a/arch/arm64/boot/dts/tesla/fsd-pinctrl.h b/arch/arm64/boot/dts/tesla/fsd-pinctrl.h
new file mode 100644 (file)
index 0000000..6ffbda3
--- /dev/null
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Tesla FSD DTS pinctrl constants
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ * Copyright (c) 2022 Linaro Ltd
+ * Author: Krzysztof Kozlowski <krzk@kernel.org>
+ */
+
+#ifndef __DTS_ARM64_TESLA_FSD_PINCTRL_H__
+#define __DTS_ARM64_TESLA_FSD_PINCTRL_H__
+
+#define FSD_PIN_PULL_NONE              0
+#define FSD_PIN_PULL_DOWN              1
+#define FSD_PIN_PULL_UP                        3
+
+#define FSD_PIN_DRV_LV1                        0
+#define FSD_PIN_DRV_LV2                        2
+#define FSD_PIN_DRV_LV3                        1
+#define FSD_PIN_DRV_LV4                        3
+
+#define FSD_PIN_FUNC_INPUT             0
+#define FSD_PIN_FUNC_OUTPUT            1
+#define FSD_PIN_FUNC_2                 2
+#define FSD_PIN_FUNC_3                 3
+#define FSD_PIN_FUNC_4                 4
+#define FSD_PIN_FUNC_5                 5
+#define FSD_PIN_FUNC_6                 6
+#define FSD_PIN_FUNC_EINT              0xf
+#define FSD_PIN_FUNC_F                 FSD_PIN_FUNC_EINT
+
+#endif /* __DTS_ARM64_TESLA_FSD_PINCTRL_H__ */
index af39655..f35bc5a 100644 (file)
                                enable-method = "psci";
                                clock-frequency = <2400000000>;
                                cpu-idle-states = <&CPU_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 = <&cpucl_l2>;
                };
 
                cpucl0_1: cpu@1 {
                                enable-method = "psci";
                                clock-frequency = <2400000000>;
                                cpu-idle-states = <&CPU_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 = <&cpucl_l2>;
                };
 
                cpucl0_2: cpu@2 {
                                enable-method = "psci";
                                clock-frequency = <2400000000>;
                                cpu-idle-states = <&CPU_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 = <&cpucl_l2>;
                };
 
                cpucl0_3: cpu@3 {
                                reg = <0x0 0x003>;
                                enable-method = "psci";
                                cpu-idle-states = <&CPU_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 = <&cpucl_l2>;
                };
 
                /* Cluster 1 */
                                enable-method = "psci";
                                clock-frequency = <2400000000>;
                                cpu-idle-states = <&CPU_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 = <&cpucl_l2>;
                };
 
                cpucl1_1: cpu@101 {
                                enable-method = "psci";
                                clock-frequency = <2400000000>;
                                cpu-idle-states = <&CPU_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 = <&cpucl_l2>;
                };
 
                cpucl1_2: cpu@102 {
                                enable-method = "psci";
                                clock-frequency = <2400000000>;
                                cpu-idle-states = <&CPU_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 = <&cpucl_l2>;
                };
 
                cpucl1_3: cpu@103 {
                                enable-method = "psci";
                                clock-frequency = <2400000000>;
                                cpu-idle-states = <&CPU_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 = <&cpucl_l2>;
                };
 
                /* Cluster 2 */
                                enable-method = "psci";
                                clock-frequency = <2400000000>;
                                cpu-idle-states = <&CPU_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 = <&cpucl_l2>;
                };
 
                cpucl2_1: cpu@201 {
                                enable-method = "psci";
                                clock-frequency = <2400000000>;
                                cpu-idle-states = <&CPU_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 = <&cpucl_l2>;
                };
 
                cpucl2_2: cpu@202 {
                                enable-method = "psci";
                                clock-frequency = <2400000000>;
                                cpu-idle-states = <&CPU_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 = <&cpucl_l2>;
                };
 
                cpucl2_3: cpu@203 {
                                enable-method = "psci";
                                clock-frequency = <2400000000>;
                                cpu-idle-states = <&CPU_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 = <&cpucl_l2>;
+               };
+
+               cpucl_l2: l2-cache0 {
+                       compatible = "cache";
+                       cache-size = <0x400000>;
+                       cache-line-size = <64>;
+                       cache-sets = <4096>;
                };
 
                idle-states {
                        clocks = <&fin_pll>, <&clock_imem IMEM_MCT_PCLK>;
                        clock-names = "fin_pll", "mct";
                };
+
+               ufs: ufs@15120000 {
+                       compatible = "tesla,fsd-ufs";
+                       reg = <0x0 0x15120000 0x0 0x200>,  /* 0: HCI standard */
+                             <0x0 0x15121100 0x0 0x200>,  /* 1: Vendor specified */
+                             <0x0 0x15110000 0x0 0x8000>,  /* 2: UNIPRO */
+                             <0x0 0x15130000 0x0 0x100>;  /* 3: UFS protector */
+                       reg-names = "hci", "vs_hci", "unipro", "ufsp";
+                       interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&clock_fsys0 UFS0_TOP0_HCLK_BUS>,
+                                <&clock_fsys0 UFS0_TOP0_CLK_UNIPRO>;
+                       clock-names = "core_clk", "sclk_unipro_main";
+                       freq-table-hz = <0 0>, <0 0>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&ufs_rst_n &ufs_refclk_out>;
+                       phys = <&ufs_phy>;
+                       phy-names = "ufs-phy";
+                       status = "disabled";
+               };
+
+               ufs_phy: ufs-phy@15124000 {
+                       compatible = "tesla,fsd-ufs-phy";
+                       reg = <0x0 0x15124000 0x0 0x800>;
+                       reg-names = "phy-pma";
+                       samsung,pmu-syscon = <&pmu_system_controller>;
+                       #phy-cells = <0>;
+                       clocks = <&clock_fsys0 UFS0_MPHY_REFCLK_IXTAL26>;
+                       clock-names = "ref_clk";
+               };
        };
 };
 
index d08abad..12ab754 100644 (file)
                compatible = "ti,k2g-sci";
                ti,host-id = <12>;
                mbox-names = "rx", "tx";
-               mboxes= <&secure_proxy_main 12>,
-                       <&secure_proxy_main 13>;
+               mboxes = <&secure_proxy_main 12>,
+                        <&secure_proxy_main 13>;
                reg-names = "debug_messages";
                reg = <0x00 0x44043000 0x00 0xfe0>;
 
                };
        };
 
+       crypto: crypto@40900000 {
+               compatible = "ti,am62-sa3ul";
+               reg = <0x00 0x40900000 0x00 0x1200>;
+               power-domains = <&k3_pds 70 TI_SCI_PD_SHARED>;
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges = <0x00 0x40900000 0x00 0x40900000 0x00 0x30000>;
+
+               dmas = <&main_pktdma 0xf501 0>, <&main_pktdma 0x7506 0>,
+                      <&main_pktdma 0x7507 0>;
+               dma-names = "tx", "rx1", "rx2";
+       };
+
        main_pmx0: pinctrl@f4000 {
                compatible = "pinctrl-single";
                reg = <0x00 0xf4000 0x00 0x2ac>;
index 39fb1d7..9b4dbae 100644 (file)
@@ -13,7 +13,7 @@
 #include "k3-am625.dtsi"
 
 / {
-       compatible =  "ti,am625-sk", "ti,am625";
+       compatible = "ti,am625-sk", "ti,am625";
        model = "Texas Instruments AM625 SK";
 
        aliases {
                #size-cells = <2>;
                ranges;
 
+               ramoops@9ca00000 {
+                       compatible = "ramoops";
+                       reg = <0x00 0x9ca00000 0x00 0x00100000>;
+                       record-size = <0x8000>;
+                       console-size = <0x8000>;
+                       ftrace-size = <0x00>;
+                       pmsg-size = <0x8000>;
+               };
+
                secure_tfa_ddr: tfa@9e780000 {
                        reg = <0x00 0x9e780000 0x00 0x80000>;
                        alignment = <0x1000>;
index f64b368..ada0057 100644 (file)
                compatible = "ti,k2g-sci";
                ti,host-id = <12>;
                mbox-names = "rx", "tx";
-               mboxes= <&secure_proxy_main 12>,
+               mboxes = <&secure_proxy_main 12>,
                        <&secure_proxy_main 13>;
                reg-names = "debug_messages";
                reg = <0x00 0x44043000 0x00 0xfe0>;
                clock-names = "clk_ahb", "clk_xin";
                mmc-ddr-1_8v;
                mmc-hs200-1_8v;
-               mmc-hs400-1_8v;
                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,otap-del-sel-hs400 = <0x4>;
        };
 
        sdhci1: mmc@fa00000 {
                      <0x00 0x20718000 0x00 0x8000>;
                reg-names = "m_can", "message_ram";
                power-domains = <&k3_pds 99 TI_SCI_PD_EXCLUSIVE>;
-               clocks =  <&k3_clks 99 5>, <&k3_clks 99 0>;
+               clocks = <&k3_clks 99 5>, <&k3_clks 99 0>;
                clock-names = "hclk", "cclk";
                interrupts = <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>;
index 8e7893e..ad150c7 100644 (file)
@@ -13,7 +13,7 @@
 #include "k3-am642.dtsi"
 
 / {
-       compatible =  "ti,am642-evm", "ti,am642";
+       compatible = "ti,am642-evm", "ti,am642";
        model = "Texas Instruments AM642 EVM";
 
        chosen {
index 59f506c..2620469 100644 (file)
@@ -12,7 +12,7 @@
 #include "k3-am642.dtsi"
 
 / {
-       compatible =  "ti,am642-sk", "ti,am642";
+       compatible = "ti,am642-sk", "ti,am642";
        model = "Texas Instruments AM642 SK";
 
        chosen {
                >;
        };
 
+       main_uart0_pins_default: main-uart0-pins-default {
+               pinctrl-single,pins = <
+                       AM64X_IOPAD(0x0238, PIN_INPUT, 0) /* (B16) UART0_CTSn */
+                       AM64X_IOPAD(0x023c, PIN_OUTPUT, 0) /* (A16) UART0_RTSn */
+                       AM64X_IOPAD(0x0230, PIN_INPUT, 0) /* (D15) UART0_RXD */
+                       AM64X_IOPAD(0x0234, PIN_OUTPUT, 0) /* (C16) UART0_TXD */
+               >;
+       };
+
        main_usb0_pins_default: main-usb0-pins-default {
                pinctrl-single,pins = <
                        AM64X_IOPAD(0x02a8, PIN_OUTPUT, 0) /* (E19) USB0_DRVVBUS */
        status = "disabled";
 };
 
+&main_uart0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&main_uart0_pins_default>;
+};
+
 &main_uart1 {
        /* main_uart1 is reserved for firmware usage */
        status = "reserved";
index 6e41f2f..32b7972 100644 (file)
 
        psu: regulator@60 {
                compatible = "ti,tps62363";
-               reg =  <0x60>;
+               reg = <0x60>;
                regulator-name = "tps62363-vout";
                regulator-min-microvolt = <500000>;
                regulator-max-microvolt = <1500000>;
        pinctrl-0 = <&mcu_spi0_pins_default>;
 
        #address-cells = <1>;
-       #size-cells= <0>;
+       #size-cells = <0>;
        ti,pindir-d0-out-d1-in;
 };
 
index e749343..8919fed 100644 (file)
 
        pcie0_rc: pcie@5500000 {
                compatible = "ti,am654-pcie-rc";
-               reg =  <0x0 0x5500000 0x0 0x1000>, <0x0 0x5501000 0x0 0x1000>, <0x0 0x10000000 0x0 0x2000>, <0x0 0x5506000 0x0 0x1000>;
+               reg = <0x0 0x5500000 0x0 0x1000>, <0x0 0x5501000 0x0 0x1000>, <0x0 0x10000000 0x0 0x2000>, <0x0 0x5506000 0x0 0x1000>;
                reg-names = "app", "dbics", "config", "atu";
                power-domains = <&k3_pds 120 TI_SCI_PD_EXCLUSIVE>;
                #address-cells = <3>;
 
        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 = <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 = <&pcie0_mode>;
 
        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>;
+               reg = <0x0 0x5600000 0x0 0x1000>, <0x0 0x5601000 0x0 0x1000>, <0x0 0x18000000 0x0 0x2000>, <0x0 0x5606000 0x0 0x1000>;
                reg-names = "app", "dbics", "config", "atu";
                power-domains = <&k3_pds 121 TI_SCI_PD_EXCLUSIVE>;
                #address-cells = <3>;
 
        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 = <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 = <&pcie1_mode>;
 
                power-domains = <&k3_pds 67 TI_SCI_PD_EXCLUSIVE>;
 
-               clocks =        <&k3_clks 67 1>,
-                               <&k3_clks 216 1>,
-                               <&k3_clks 67 2>;
+               clocks = <&k3_clks 67 1>,
+                        <&k3_clks 216 1>,
+                        <&k3_clks 67 2>;
                clock-names = "fck", "vp1", "vp2";
 
                /*
index 9c69d09..fa11d71 100644 (file)
@@ -12,8 +12,8 @@
 
                mbox-names = "rx", "tx";
 
-               mboxes= <&secure_proxy_main 11>,
-                       <&secure_proxy_main 13>;
+               mboxes = <&secure_proxy_main 11>,
+                        <&secure_proxy_main 13>;
 
                reg-names = "debug_messages";
                reg = <0x44083000 0x1000>;
index 57497cb..5850582 100644 (file)
@@ -10,7 +10,7 @@
 #include <dt-bindings/net/ti-dp83867.h>
 
 / {
-       compatible =  "ti,am654-evm", "ti,am654";
+       compatible = "ti,am654-evm", "ti,am654";
        model = "Texas Instruments AM654 Base Board";
 
        chosen {
                pinctrl-names = "default";
                pinctrl-0 = <&push_button_pins_default>;
 
-               sw5 {
+               switch-5 {
                        label = "GPIO Key USER1";
                        linux,code = <BTN_0>;
                        gpios = <&wkup_gpio0 24 GPIO_ACTIVE_LOW>;
                };
 
-               sw6 {
+               switch-6 {
                        label = "GPIO Key USER2";
                        linux,code = <BTN_1>;
                        gpios = <&wkup_gpio0 27 GPIO_ACTIVE_LOW>;
        pinctrl-names = "default";
        pinctrl-0 = <&main_spi0_pins_default>;
        #address-cells = <1>;
-       #size-cells= <0>;
+       #size-cells = <0>;
        ti,pindir-d0-out-d1-in;
 
        flash@0 {
index 1044ec6..ff13bbe 100644 (file)
@@ -12,8 +12,8 @@
 
                mbox-names = "rx", "tx";
 
-               mboxes= <&secure_proxy_main 11>,
-                       <&secure_proxy_main 13>;
+               mboxes = <&secure_proxy_main 11>,
+                        <&secure_proxy_main 13>;
 
                reg-names = "debug_messages";
                reg = <0x00 0x44083000 0x00 0x1000>;
index 2bc26a2..b1691ac 100644 (file)
                pinctrl-names = "default";
                pinctrl-0 = <&sw10_button_pins_default &sw11_button_pins_default>;
 
-               sw10: sw10 {
+               sw10: switch-10 {
                        label = "GPIO Key USER1";
                        linux,code = <BTN_0>;
                        gpios = <&main_gpio0 0 GPIO_ACTIVE_LOW>;
                };
 
-               sw11: sw11 {
+               sw11: switch-11 {
                        label = "GPIO Key USER2";
                        linux,code = <BTN_1>;
                        gpios = <&wkup_gpio0 7 GPIO_ACTIVE_LOW>;
index b4972df..df08724 100644 (file)
@@ -12,8 +12,8 @@
 
                mbox-names = "rx", "tx";
 
-               mboxes= <&secure_proxy_main 11>,
-                       <&secure_proxy_main 13>;
+               mboxes = <&secure_proxy_main 11>,
+                        <&secure_proxy_main 13>;
 
                reg-names = "debug_messages";
                reg = <0x00 0x44083000 0x0 0x1000>;
index be7f392..34e7d57 100644 (file)
@@ -33,7 +33,7 @@
                ranges;
                #interrupt-cells = <3>;
                interrupt-controller;
-               reg = <0x00 0x01800000 0x00 0x200000>, /* GICD */
+               reg = <0x00 0x01800000 0x00 0x100000>, /* GICD */
                      <0x00 0x01900000 0x00 0x100000>, /* GICR */
                      <0x00 0x6f000000 0x00 0x2000>,   /* GICC */
                      <0x00 0x6f010000 0x00 0x1000>,   /* GICH */
                interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
                power-domains = <&k3_pds 98 TI_SCI_PD_EXCLUSIVE>;
                clocks = <&k3_clks 98 7>, <&k3_clks 98 1>;
-               clock-names =  "clk_ahb", "clk_xin";
+               clock-names = "clk_ahb", "clk_xin";
                assigned-clocks = <&k3_clks 98 1>;
                assigned-clock-parents = <&k3_clks 98 2>;
                bus-width = <8>;
                interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
                power-domains = <&k3_pds 99 TI_SCI_PD_EXCLUSIVE>;
                clocks = <&k3_clks 99 8>, <&k3_clks 99 1>;
-               clock-names =  "clk_ahb", "clk_xin";
+               clock-names = "clk_ahb", "clk_xin";
                assigned-clocks = <&k3_clks 99 1>;
                assigned-clock-parents = <&k3_clks 99 2>;
                bus-width = <4>;
index 6c5c02e..4d1bfab 100644 (file)
@@ -12,8 +12,8 @@
 
                mbox-names = "rx", "tx";
 
-               mboxes= <&secure_proxy_main 11>,
-                       <&secure_proxy_main 13>;
+               mboxes = <&secure_proxy_main 11>,
+                        <&secure_proxy_main 13>;
 
                reg-names = "debug_messages";
                reg = <0x00 0x44083000 0x00 0x1000>;
index 8493dd7..e172fa0 100644 (file)
        clocks = <&zynqmp_clk LPD_WDT>;
 };
 
+&xilinx_ams {
+       clocks = <&zynqmp_clk AMS_REF>;
+};
+
 &zynqmp_dpdma {
        clocks = <&zynqmp_clk DPDMA_REF>;
 };
index 550b389..20e83ca 100644 (file)
@@ -52,7 +52,7 @@
        gpio-keys {
                compatible = "gpio-keys";
                autorepeat;
-               fwuen {
+               key-fwuen {
                        label = "fwuen";
                        gpios = <&gpio 12 GPIO_ACTIVE_LOW>;
                };
                          "", "", "", "", "", /* 155 - 159 */
                          "", "", "", "", "", /* 160 - 164 */
                          "", "", "", "", "", /* 165 - 169 */
-                         "", "", "", ""; /* 170 - 174 */
+                         "", "", "", ""; /* 170 - 173 */
 };
index f6aad41..d61a297 100644 (file)
@@ -49,7 +49,7 @@
        gpio-keys {
                compatible = "gpio-keys";
                autorepeat;
-               sw4 {
+               switch-4 {
                        label = "sw4";
                        gpios = <&gpio 23 GPIO_ACTIVE_LOW>;
                        linux,code = <KEY_POWER>;
index 7b9a88b..5fd6b70 100644 (file)
@@ -47,7 +47,7 @@
        gpio-keys {
                compatible = "gpio-keys";
                autorepeat;
-               sw19 {
+               switch-19 {
                        label = "sw19";
                        gpios = <&gpio 22 GPIO_ACTIVE_HIGH>;
                        linux,code = <KEY_DOWN>;
index 20b7c75..e2dd72f 100644 (file)
@@ -47,7 +47,7 @@
        gpio-keys {
                compatible = "gpio-keys";
                autorepeat;
-               sw19 {
+               switch-19 {
                        label = "sw19";
                        gpios = <&gpio 22 GPIO_ACTIVE_HIGH>;
                        linux,code = <KEY_DOWN>;
index e36df6a..d685d8f 100644 (file)
@@ -47,7 +47,7 @@
        gpio-keys {
                compatible = "gpio-keys";
                autorepeat;
-               sw19 {
+               switch-19 {
                        label = "sw19";
                        gpios = <&gpio 22 GPIO_ACTIVE_HIGH>;
                        linux,code = <KEY_DOWN>;
index c715a18..a549265 100644 (file)
                        timeout-sec = <10>;
                };
 
+               xilinx_ams: ams@ffa50000 {
+                       compatible = "xlnx,zynqmp-ams";
+                       status = "disabled";
+                       interrupt-parent = <&gic>;
+                       interrupts = <0 56 4>;
+                       reg = <0x0 0xffa50000 0x0 0x800>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       #io-channel-cells = <1>;
+                       ranges = <0 0 0xffa50800 0x800>;
+
+                       ams_ps: ams_ps@0 {
+                               compatible = "xlnx,zynqmp-ams-ps";
+                               status = "disabled";
+                               reg = <0x0 0x400>;
+                       };
+
+                       ams_pl: ams_pl@400 {
+                               compatible = "xlnx,zynqmp-ams-pl";
+                               status = "disabled";
+                               reg = <0x400 0x400>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+               };
+
                zynqmp_dpdma: dma-controller@fd4c0000 {
                        compatible = "xlnx,zynqmp-dpdma";
                        status = "disabled";
index 7d11053..d5b2d2d 100644 (file)
@@ -28,7 +28,6 @@ CONFIG_USER_NS=y
 CONFIG_SCHED_AUTOGROUP=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_KALLSYMS_ALL=y
-# CONFIG_COMPAT_BRK is not set
 CONFIG_PROFILING=y
 CONFIG_ARCH_ACTIONS=y
 CONFIG_ARCH_SUNXI=y
@@ -36,6 +35,7 @@ CONFIG_ARCH_ALPINE=y
 CONFIG_ARCH_APPLE=y
 CONFIG_ARCH_BCM2835=y
 CONFIG_ARCH_BCM4908=y
+CONFIG_ARCH_BCMBCA=y
 CONFIG_ARCH_BCM_IPROC=y
 CONFIG_ARCH_BERLIN=y
 CONFIG_ARCH_BRCMSTB=y
@@ -49,6 +49,7 @@ CONFIG_ARCH_MEDIATEK=y
 CONFIG_ARCH_MESON=y
 CONFIG_ARCH_MVEBU=y
 CONFIG_ARCH_MXC=y
+CONFIG_ARCH_NPCM=y
 CONFIG_ARCH_QCOM=y
 CONFIG_ARCH_RENESAS=y
 CONFIG_ARCH_ROCKCHIP=y
@@ -93,12 +94,12 @@ CONFIG_ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM=m
 CONFIG_ARM_ARMADA_37XX_CPUFREQ=y
 CONFIG_ARM_SCPI_CPUFREQ=y
 CONFIG_ARM_IMX_CPUFREQ_DT=m
+CONFIG_ARM_MEDIATEK_CPUFREQ=y
 CONFIG_ARM_QCOM_CPUFREQ_NVMEM=y
 CONFIG_ARM_QCOM_CPUFREQ_HW=y
 CONFIG_ARM_RASPBERRYPI_CPUFREQ=m
 CONFIG_ARM_SCMI_CPUFREQ=y
 CONFIG_ARM_TEGRA186_CPUFREQ=y
-CONFIG_ARM_MEDIATEK_CPUFREQ=y
 CONFIG_QORIQ_CPUFREQ=y
 CONFIG_ACPI=y
 CONFIG_ACPI_APEI=y
@@ -121,10 +122,10 @@ CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
 CONFIG_CRYPTO_CHACHA20_NEON=m
 CONFIG_CRYPTO_AES_ARM64_BS=m
 CONFIG_JUMP_LABEL=y
-CONFIG_SECCOMP=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_COMPAT_BRK is not set
 CONFIG_KSM=y
 CONFIG_MEMORY_FAILURE=y
 CONFIG_TRANSPARENT_HUGEPAGE=y
@@ -174,7 +175,6 @@ CONFIG_NET_CLS_ACT=y
 CONFIG_NET_ACT_GACT=m
 CONFIG_NET_ACT_MIRRED=m
 CONFIG_NET_ACT_GATE=m
-CONFIG_QRTR=m
 CONFIG_QRTR_SMD=m
 CONFIG_QRTR_TUN=m
 CONFIG_CAN=m
@@ -264,9 +264,9 @@ CONFIG_MTD_PHYSMAP_OF=y
 CONFIG_MTD_DATAFLASH=y
 CONFIG_MTD_SST25L=y
 CONFIG_MTD_RAW_NAND=y
-CONFIG_MTD_NAND_BRCMNAND=m
 CONFIG_MTD_NAND_DENALI_DT=y
 CONFIG_MTD_NAND_MARVELL=y
+CONFIG_MTD_NAND_BRCMNAND=m
 CONFIG_MTD_NAND_FSL_IFC=y
 CONFIG_MTD_NAND_QCOM=y
 CONFIG_MTD_SPI_NOR=y
@@ -288,11 +288,6 @@ CONFIG_SCSI_HISI_SAS=y
 CONFIG_SCSI_HISI_SAS_PCI=y
 CONFIG_MEGARAID_SAS=y
 CONFIG_SCSI_MPT3SAS=m
-CONFIG_SCSI_UFSHCD=y
-CONFIG_SCSI_UFSHCD_PLATFORM=y
-CONFIG_SCSI_UFS_QCOM=m
-CONFIG_SCSI_UFS_HISI=y
-CONFIG_SCSI_UFS_EXYNOS=y
 CONFIG_ATA=y
 CONFIG_SATA_AHCI=y
 CONFIG_SATA_AHCI_PLATFORM=y
@@ -322,8 +317,8 @@ CONFIG_AMD_XGBE=y
 CONFIG_NET_XGENE=y
 CONFIG_ATL1C=m
 CONFIG_BCMGENET=m
-CONFIG_SYSTEMPORT=m
 CONFIG_BNX2X=m
+CONFIG_SYSTEMPORT=m
 CONFIG_MACB=y
 CONFIG_THUNDER_NIC_PF=y
 CONFIG_FEC=y
@@ -375,7 +370,6 @@ CONFIG_DP83867_PHY=y
 CONFIG_VITESSE_PHY=y
 CONFIG_MDIO_BUS_MUX_MULTIPLEXER=y
 CONFIG_MDIO_BUS_MUX_MMIOREG=y
-CONFIG_USB_BRCMSTB=m
 CONFIG_USB_PEGASUS=m
 CONFIG_USB_RTL8150=m
 CONFIG_USB_RTL8152=m
@@ -425,10 +419,10 @@ CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
 CONFIG_SERIAL_8250_BCM2835AUX=y
 CONFIG_SERIAL_8250_DW=y
+CONFIG_SERIAL_8250_EM=y
 CONFIG_SERIAL_8250_OMAP=y
 CONFIG_SERIAL_8250_MT6577=y
 CONFIG_SERIAL_8250_UNIPHIER=y
-CONFIG_SERIAL_8250_EM=y
 CONFIG_SERIAL_OF_PLATFORM=y
 CONFIG_SERIAL_AMBA_PL011=y
 CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
@@ -464,6 +458,7 @@ CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_MUX=y
 CONFIG_I2C_MUX_PCA954x=y
 CONFIG_I2C_BCM2835=m
+CONFIG_I2C_CADENCE=m
 CONFIG_I2C_DESIGNWARE_PLATFORM=y
 CONFIG_I2C_GPIO=m
 CONFIG_I2C_IMX=y
@@ -485,7 +480,6 @@ CONFIG_I2C_TEGRA=y
 CONFIG_I2C_UNIPHIER_F=y
 CONFIG_I2C_RCAR=y
 CONFIG_I2C_CROS_EC_TUNNEL=y
-CONFIG_I2C_CADENCE=m
 CONFIG_SPI=y
 CONFIG_SPI_ARMADA_3700=y
 CONFIG_SPI_BCM2835=m
@@ -527,6 +521,7 @@ CONFIG_PINCTRL_IMX8QM=y
 CONFIG_PINCTRL_IMX8QXP=y
 CONFIG_PINCTRL_IMX8DXL=y
 CONFIG_PINCTRL_IMX8ULP=y
+CONFIG_PINCTRL_IMX93=y
 CONFIG_PINCTRL_MSM=y
 CONFIG_PINCTRL_IPQ8074=y
 CONFIG_PINCTRL_IPQ6018=y
@@ -539,6 +534,7 @@ CONFIG_PINCTRL_QDF2XXX=y
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_PINCTRL_SC7180=y
 CONFIG_PINCTRL_SC7280=y
+CONFIG_PINCTRL_SC8280XP=y
 CONFIG_PINCTRL_SDM845=y
 CONFIG_PINCTRL_SM8150=y
 CONFIG_PINCTRL_SM8250=y
@@ -577,6 +573,7 @@ CONFIG_CHARGER_BQ25890=m
 CONFIG_CHARGER_BQ25980=m
 CONFIG_SENSORS_ARM_SCMI=y
 CONFIG_SENSORS_ARM_SCPI=y
+CONFIG_SENSORS_GPIO_FAN=m
 CONFIG_SENSORS_JC42=m
 CONFIG_SENSORS_LM75=m
 CONFIG_SENSORS_LM90=m
@@ -604,16 +601,15 @@ CONFIG_EXYNOS_THERMAL=y
 CONFIG_TEGRA_SOCTHERM=m
 CONFIG_TEGRA_BPMP_THERMAL=m
 CONFIG_QCOM_TSENS=y
+CONFIG_QCOM_SPMI_ADC_TM5=m
 CONFIG_QCOM_SPMI_TEMP_ALARM=m
 CONFIG_QCOM_LMH=m
-CONFIG_QCOM_SPMI_ADC_TM5=m
 CONFIG_UNIPHIER_THERMAL=y
 CONFIG_WATCHDOG=y
 CONFIG_SL28CPLD_WATCHDOG=m
 CONFIG_ARM_SP805_WATCHDOG=y
 CONFIG_ARM_SBSA_WATCHDOG=y
 CONFIG_S3C2410_WATCHDOG=y
-CONFIG_BCM7038_WDT=m
 CONFIG_DW_WATCHDOG=y
 CONFIG_SUNXI_WATCHDOG=m
 CONFIG_IMX2_WDT=y
@@ -627,6 +623,8 @@ CONFIG_RENESAS_RZG2LWDT=y
 CONFIG_UNIPHIER_WATCHDOG=y
 CONFIG_PM8916_WATCHDOG=m
 CONFIG_BCM2835_WDT=y
+CONFIG_BCM7038_WDT=m
+CONFIG_NPCM7XX_WATCHDOG=y
 CONFIG_MFD_ALTERA_SYSMGR=y
 CONFIG_MFD_BD9571MWV=y
 CONFIG_MFD_AXP20X_I2C=y
@@ -684,21 +682,21 @@ CONFIG_MEDIA_PLATFORM_SUPPORT=y
 CONFIG_MEDIA_USB_SUPPORT=y
 CONFIG_USB_VIDEO_CLASS=m
 CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_SDR_PLATFORM_DRIVERS=y
+CONFIG_V4L_MEM2MEM_DRIVERS=y
 CONFIG_VIDEO_QCOM_CAMSS=m
+CONFIG_VIDEO_QCOM_VENUS=m
+CONFIG_VIDEO_RCAR_ISP=m
 CONFIG_VIDEO_RCAR_CSI2=m
 CONFIG_VIDEO_RCAR_VIN=m
-CONFIG_VIDEO_SUN6I_CSI=m
-CONFIG_VIDEO_RCAR_ISP=m
-CONFIG_V4L_MEM2MEM_DRIVERS=y
-CONFIG_VIDEO_SAMSUNG_S5P_JPEG=m
-CONFIG_VIDEO_SAMSUNG_S5P_MFC=m
-CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC=m
-CONFIG_VIDEO_RENESAS_FDP1=m
 CONFIG_VIDEO_RENESAS_FCP=m
+CONFIG_VIDEO_RENESAS_FDP1=m
 CONFIG_VIDEO_RENESAS_VSP1=m
-CONFIG_VIDEO_QCOM_VENUS=m
-CONFIG_SDR_PLATFORM_DRIVERS=y
 CONFIG_VIDEO_RCAR_DRIF=m
+CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC=m
+CONFIG_VIDEO_SAMSUNG_S5P_JPEG=m
+CONFIG_VIDEO_SAMSUNG_S5P_MFC=m
+CONFIG_VIDEO_SUN6I_CSI=m
 CONFIG_VIDEO_IMX219=m
 CONFIG_VIDEO_OV5640=m
 CONFIG_VIDEO_OV5645=m
@@ -754,6 +752,7 @@ CONFIG_DRM_CDNS_MHDP8546=m
 CONFIG_DRM_DW_HDMI_AHB_AUDIO=m
 CONFIG_DRM_DW_HDMI_CEC=m
 CONFIG_DRM_IMX_DCSS=m
+CONFIG_DRM_V3D=m
 CONFIG_DRM_VC4=m
 CONFIG_DRM_ETNAVIV=m
 CONFIG_DRM_HISI_HIBMC=m
@@ -802,12 +801,16 @@ CONFIG_SND_SOC_RK3399_GRU_SOUND=m
 CONFIG_SND_SOC_SAMSUNG=y
 CONFIG_SND_SOC_RCAR=m
 CONFIG_SND_SOC_RZ=m
+CONFIG_SND_SUN8I_CODEC=m
+CONFIG_SND_SUN8I_CODEC_ANALOG=m
+CONFIG_SND_SUN50I_CODEC_ANALOG=m
 CONFIG_SND_SUN4I_I2S=m
 CONFIG_SND_SUN4I_SPDIF=m
 CONFIG_SND_SOC_TEGRA=m
 CONFIG_SND_SOC_TEGRA210_AHUB=m
 CONFIG_SND_SOC_TEGRA210_DMIC=m
 CONFIG_SND_SOC_TEGRA210_I2S=m
+CONFIG_SND_SOC_TEGRA210_OPE=m
 CONFIG_SND_SOC_TEGRA186_ASRC=m
 CONFIG_SND_SOC_TEGRA186_DSPK=m
 CONFIG_SND_SOC_TEGRA210_ADMAIF=m
@@ -853,6 +856,7 @@ CONFIG_USB_OTG=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_PCI_RENESAS=m
 CONFIG_USB_XHCI_TEGRA=y
+CONFIG_USB_BRCMSTB=m
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_EXYNOS=y
 CONFIG_USB_EHCI_HCD_PLATFORM=y
@@ -931,13 +935,20 @@ CONFIG_MMC_MTK=y
 CONFIG_MMC_SDHCI_XENON=y
 CONFIG_MMC_SDHCI_AM654=y
 CONFIG_MMC_OWL=y
+CONFIG_SCSI_UFSHCD=y
+CONFIG_SCSI_UFSHCD_PLATFORM=y
+CONFIG_SCSI_UFS_QCOM=m
+CONFIG_SCSI_UFS_HISI=y
+CONFIG_SCSI_UFS_EXYNOS=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_CLASS_MULTICOLOR=m
 CONFIG_LEDS_LM3692X=m
 CONFIG_LEDS_PCA9532=m
 CONFIG_LEDS_GPIO=y
 CONFIG_LEDS_PWM=y
 CONFIG_LEDS_SYSCON=y
+CONFIG_LEDS_QCOM_LPG=m
 CONFIG_LEDS_TRIGGER_TIMER=y
 CONFIG_LEDS_TRIGGER_DISK=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
@@ -972,8 +983,8 @@ CONFIG_RTC_DRV_PM8XXX=m
 CONFIG_RTC_DRV_TEGRA=y
 CONFIG_RTC_DRV_SNVS=m
 CONFIG_RTC_DRV_IMX_SC=m
-CONFIG_RTC_DRV_XGENE=y
 CONFIG_RTC_DRV_MT6397=m
+CONFIG_RTC_DRV_XGENE=y
 CONFIG_DMADEVICES=y
 CONFIG_DMA_BCM2835=y
 CONFIG_DMA_SUN6I=m
@@ -1021,6 +1032,7 @@ CONFIG_COMMON_CLK_FSL_SAI=y
 CONFIG_COMMON_CLK_S2MPS11=y
 CONFIG_COMMON_CLK_PWM=y
 CONFIG_COMMON_CLK_VC5=y
+CONFIG_COMMON_CLK_NPCM8XX=y
 CONFIG_COMMON_CLK_BD718XX=m
 CONFIG_CLK_RASPBERRYPI=m
 CONFIG_CLK_IMX8MM=y
@@ -1029,6 +1041,7 @@ CONFIG_CLK_IMX8MP=y
 CONFIG_CLK_IMX8MQ=y
 CONFIG_CLK_IMX8QXP=y
 CONFIG_CLK_IMX8ULP=y
+CONFIG_CLK_IMX93=y
 CONFIG_TI_SCI_CLK=y
 CONFIG_COMMON_CLK_QCOM=y
 CONFIG_QCOM_A53PLL=y
@@ -1045,15 +1058,16 @@ CONFIG_MSM_GCC_8998=y
 CONFIG_QCS_GCC_404=y
 CONFIG_SC_GCC_7180=y
 CONFIG_SC_GCC_7280=y
+CONFIG_SC_GCC_8280XP=y
 CONFIG_SDM_CAMCC_845=m
 CONFIG_SDM_GPUCC_845=y
 CONFIG_SDM_VIDEOCC_845=y
 CONFIG_SDM_DISPCC_845=y
+CONFIG_SM_DISPCC_8250=y
 CONFIG_SM_GCC_8350=y
 CONFIG_SM_GCC_8450=y
 CONFIG_SM_GPUCC_8150=y
 CONFIG_SM_GPUCC_8250=y
-CONFIG_SM_DISPCC_8250=y
 CONFIG_SM_VIDEOCC_8250=y
 CONFIG_QCOM_HFPLL=y
 CONFIG_CLK_GFM_LPASS_SM8250=m
@@ -1091,7 +1105,6 @@ CONFIG_FSL_MC_DPIO=y
 CONFIG_FSL_RCPM=y
 CONFIG_MTK_DEVAPC=m
 CONFIG_MTK_PMIC_WRAP=y
-CONFIG_MAILBOX=y
 CONFIG_QCOM_AOSS_QMP=y
 CONFIG_QCOM_COMMAND_DB=y
 CONFIG_QCOM_CPR=y
@@ -1108,6 +1121,7 @@ CONFIG_QCOM_SOCINFO=m
 CONFIG_QCOM_STATS=m
 CONFIG_QCOM_WCNSS_CTRL=m
 CONFIG_QCOM_APR=m
+CONFIG_QCOM_ICC_BWMON=m
 CONFIG_ARCH_R8A77995=y
 CONFIG_ARCH_R8A77990=y
 CONFIG_ARCH_R8A77950=y
@@ -1119,6 +1133,7 @@ CONFIG_ARCH_R8A779F0=y
 CONFIG_ARCH_R8A77980=y
 CONFIG_ARCH_R8A77970=y
 CONFIG_ARCH_R8A779A0=y
+CONFIG_ARCH_R8A779G0=y
 CONFIG_ARCH_R8A774C0=y
 CONFIG_ARCH_R8A774E1=y
 CONFIG_ARCH_R8A774A1=y
@@ -1195,8 +1210,10 @@ CONFIG_PHY_MTK_TPHY=y
 CONFIG_PHY_QCOM_PCIE2=m
 CONFIG_PHY_QCOM_QMP=m
 CONFIG_PHY_QCOM_QUSB2=m
-CONFIG_PHY_QCOM_USB_HS=y
-CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2=y
+CONFIG_PHY_QCOM_USB_HS=m
+CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2=m
+CONFIG_PHY_QCOM_USB_HS_28NM=m
+CONFIG_PHY_QCOM_USB_SS=m
 CONFIG_PHY_RCAR_GEN3_PCIE=y
 CONFIG_PHY_RCAR_GEN3_USB2=y
 CONFIG_PHY_RCAR_GEN3_USB3=m
@@ -1247,8 +1264,12 @@ CONFIG_INTERCONNECT_IMX8MN=m
 CONFIG_INTERCONNECT_IMX8MQ=m
 CONFIG_INTERCONNECT_QCOM=y
 CONFIG_INTERCONNECT_QCOM_MSM8916=m
+CONFIG_INTERCONNECT_QCOM_MSM8996=m
 CONFIG_INTERCONNECT_QCOM_OSM_L3=m
+CONFIG_INTERCONNECT_QCOM_QCS404=m
+CONFIG_INTERCONNECT_QCOM_SC7180=m
 CONFIG_INTERCONNECT_QCOM_SC7280=y
+CONFIG_INTERCONNECT_QCOM_SC8280XP=y
 CONFIG_INTERCONNECT_QCOM_SDM845=y
 CONFIG_INTERCONNECT_QCOM_SM8150=m
 CONFIG_INTERCONNECT_QCOM_SM8250=m
@@ -1296,11 +1317,11 @@ CONFIG_CRYPTO_DEV_HISI_HPRE=m
 CONFIG_CRYPTO_DEV_HISI_TRNG=m
 CONFIG_CMA_SIZE_MBYTES=32
 CONFIG_PRINTK_TIME=y
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 CONFIG_DEBUG_INFO_REDUCED=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
 # CONFIG_SCHED_DEBUG is not set
 # CONFIG_DEBUG_PREEMPT is not set
 # CONFIG_FTRACE is not set
index ac85682..60db5bb 100644 (file)
@@ -71,6 +71,12 @@ config CRYPTO_GHASH_ARM64_CE
        select CRYPTO_HASH
        select CRYPTO_GF128MUL
        select CRYPTO_LIB_AES
+       select CRYPTO_AEAD
+
+config CRYPTO_POLYVAL_ARM64_CE
+       tristate "POLYVAL using ARMv8 Crypto Extensions (for HCTR2)"
+       depends on KERNEL_MODE_NEON
+       select CRYPTO_POLYVAL
 
 config CRYPTO_CRCT10DIF_ARM64_CE
        tristate "CRCT10DIF digest algorithm using PMULL instructions"
@@ -96,13 +102,13 @@ config CRYPTO_AES_ARM64_CE_CCM
        select CRYPTO_LIB_AES
 
 config CRYPTO_AES_ARM64_CE_BLK
-       tristate "AES in ECB/CBC/CTR/XTS modes using ARMv8 Crypto Extensions"
+       tristate "AES in ECB/CBC/CTR/XTS/XCTR modes using ARMv8 Crypto Extensions"
        depends on KERNEL_MODE_NEON
        select CRYPTO_SKCIPHER
        select CRYPTO_AES_ARM64_CE
 
 config CRYPTO_AES_ARM64_NEON_BLK
-       tristate "AES in ECB/CBC/CTR/XTS modes using NEON instructions"
+       tristate "AES in ECB/CBC/CTR/XTS/XCTR modes using NEON instructions"
        depends on KERNEL_MODE_NEON
        select CRYPTO_SKCIPHER
        select CRYPTO_LIB_AES
index bea8995..24bb0c4 100644 (file)
@@ -32,6 +32,9 @@ sm4-neon-y := sm4-neon-glue.o sm4-neon-core.o
 obj-$(CONFIG_CRYPTO_GHASH_ARM64_CE) += ghash-ce.o
 ghash-ce-y := ghash-ce-glue.o ghash-ce-core.o
 
+obj-$(CONFIG_CRYPTO_POLYVAL_ARM64_CE) += polyval-ce.o
+polyval-ce-y := polyval-ce-glue.o polyval-ce-core.o
+
 obj-$(CONFIG_CRYPTO_CRCT10DIF_ARM64_CE) += crct10dif-ce.o
 crct10dif-ce-y := crct10dif-ce-core.o crct10dif-ce-glue.o
 
index 561dd23..162787c 100644 (file)
 #define aes_essiv_cbc_encrypt  ce_aes_essiv_cbc_encrypt
 #define aes_essiv_cbc_decrypt  ce_aes_essiv_cbc_decrypt
 #define aes_ctr_encrypt                ce_aes_ctr_encrypt
+#define aes_xctr_encrypt       ce_aes_xctr_encrypt
 #define aes_xts_encrypt                ce_aes_xts_encrypt
 #define aes_xts_decrypt                ce_aes_xts_decrypt
 #define aes_mac_update         ce_aes_mac_update
-MODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS using ARMv8 Crypto Extensions");
+MODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS/XCTR using ARMv8 Crypto Extensions");
 #else
 #define MODE                   "neon"
 #define PRIO                   200
@@ -50,16 +51,18 @@ MODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS using ARMv8 Crypto Extensions");
 #define aes_essiv_cbc_encrypt  neon_aes_essiv_cbc_encrypt
 #define aes_essiv_cbc_decrypt  neon_aes_essiv_cbc_decrypt
 #define aes_ctr_encrypt                neon_aes_ctr_encrypt
+#define aes_xctr_encrypt       neon_aes_xctr_encrypt
 #define aes_xts_encrypt                neon_aes_xts_encrypt
 #define aes_xts_decrypt                neon_aes_xts_decrypt
 #define aes_mac_update         neon_aes_mac_update
-MODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS using ARMv8 NEON");
+MODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS/XCTR using ARMv8 NEON");
 #endif
 #if defined(USE_V8_CRYPTO_EXTENSIONS) || !IS_ENABLED(CONFIG_CRYPTO_AES_ARM64_BS)
 MODULE_ALIAS_CRYPTO("ecb(aes)");
 MODULE_ALIAS_CRYPTO("cbc(aes)");
 MODULE_ALIAS_CRYPTO("ctr(aes)");
 MODULE_ALIAS_CRYPTO("xts(aes)");
+MODULE_ALIAS_CRYPTO("xctr(aes)");
 #endif
 MODULE_ALIAS_CRYPTO("cts(cbc(aes))");
 MODULE_ALIAS_CRYPTO("essiv(cbc(aes),sha256)");
@@ -89,6 +92,9 @@ asmlinkage void aes_cbc_cts_decrypt(u8 out[], u8 const in[], u32 const rk[],
 asmlinkage void aes_ctr_encrypt(u8 out[], u8 const in[], u32 const rk[],
                                int rounds, int bytes, u8 ctr[]);
 
+asmlinkage void aes_xctr_encrypt(u8 out[], u8 const in[], u32 const rk[],
+                                int rounds, int bytes, u8 ctr[], int byte_ctr);
+
 asmlinkage void aes_xts_encrypt(u8 out[], u8 const in[], u32 const rk1[],
                                int rounds, int bytes, u32 const rk2[], u8 iv[],
                                int first);
@@ -442,6 +448,52 @@ static int __maybe_unused essiv_cbc_decrypt(struct skcipher_request *req)
        return err ?: cbc_decrypt_walk(req, &walk);
 }
 
+static int __maybe_unused xctr_encrypt(struct skcipher_request *req)
+{
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+       struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm);
+       int err, rounds = 6 + ctx->key_length / 4;
+       struct skcipher_walk walk;
+       unsigned int byte_ctr = 0;
+
+       err = skcipher_walk_virt(&walk, req, false);
+
+       while (walk.nbytes > 0) {
+               const u8 *src = walk.src.virt.addr;
+               unsigned int nbytes = walk.nbytes;
+               u8 *dst = walk.dst.virt.addr;
+               u8 buf[AES_BLOCK_SIZE];
+
+               /*
+                * If given less than 16 bytes, we must copy the partial block
+                * into a temporary buffer of 16 bytes to avoid out of bounds
+                * reads and writes.  Furthermore, this code is somewhat unusual
+                * in that it expects the end of the data to be at the end of
+                * the temporary buffer, rather than the start of the data at
+                * the start of the temporary buffer.
+                */
+               if (unlikely(nbytes < AES_BLOCK_SIZE))
+                       src = dst = memcpy(buf + sizeof(buf) - nbytes,
+                                          src, nbytes);
+               else if (nbytes < walk.total)
+                       nbytes &= ~(AES_BLOCK_SIZE - 1);
+
+               kernel_neon_begin();
+               aes_xctr_encrypt(dst, src, ctx->key_enc, rounds, nbytes,
+                                                walk.iv, byte_ctr);
+               kernel_neon_end();
+
+               if (unlikely(nbytes < AES_BLOCK_SIZE))
+                       memcpy(walk.dst.virt.addr,
+                              buf + sizeof(buf) - nbytes, nbytes);
+               byte_ctr += nbytes;
+
+               err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
+       }
+
+       return err;
+}
+
 static int __maybe_unused ctr_encrypt(struct skcipher_request *req)
 {
        struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
@@ -457,6 +509,14 @@ static int __maybe_unused ctr_encrypt(struct skcipher_request *req)
                u8 *dst = walk.dst.virt.addr;
                u8 buf[AES_BLOCK_SIZE];
 
+               /*
+                * If given less than 16 bytes, we must copy the partial block
+                * into a temporary buffer of 16 bytes to avoid out of bounds
+                * reads and writes.  Furthermore, this code is somewhat unusual
+                * in that it expects the end of the data to be at the end of
+                * the temporary buffer, rather than the start of the data at
+                * the start of the temporary buffer.
+                */
                if (unlikely(nbytes < AES_BLOCK_SIZE))
                        src = dst = memcpy(buf + sizeof(buf) - nbytes,
                                           src, nbytes);
@@ -671,6 +731,22 @@ static struct skcipher_alg aes_algs[] = { {
        .decrypt        = ctr_encrypt,
 }, {
        .base = {
+               .cra_name               = "xctr(aes)",
+               .cra_driver_name        = "xctr-aes-" MODE,
+               .cra_priority           = PRIO,
+               .cra_blocksize          = 1,
+               .cra_ctxsize            = sizeof(struct crypto_aes_ctx),
+               .cra_module             = THIS_MODULE,
+       },
+       .min_keysize    = AES_MIN_KEY_SIZE,
+       .max_keysize    = AES_MAX_KEY_SIZE,
+       .ivsize         = AES_BLOCK_SIZE,
+       .chunksize      = AES_BLOCK_SIZE,
+       .setkey         = skcipher_aes_setkey,
+       .encrypt        = xctr_encrypt,
+       .decrypt        = xctr_encrypt,
+}, {
+       .base = {
                .cra_name               = "xts(aes)",
                .cra_driver_name        = "xts-aes-" MODE,
                .cra_priority           = PRIO,
index dc35eb0..5abc834 100644 (file)
@@ -318,127 +318,211 @@ AES_FUNC_END(aes_cbc_cts_decrypt)
        .byte           0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
        .previous
 
-
        /*
-        * aes_ctr_encrypt(u8 out[], u8 const in[], u8 const rk[], int rounds,
-        *                 int bytes, u8 ctr[])
+        * This macro generates the code for CTR and XCTR mode.
         */
+.macro ctr_encrypt xctr
+       // Arguments
+       OUT             .req x0
+       IN              .req x1
+       KEY             .req x2
+       ROUNDS_W        .req w3
+       BYTES_W         .req w4
+       IV              .req x5
+       BYTE_CTR_W      .req w6         // XCTR only
+       // Intermediate values
+       CTR_W           .req w11        // XCTR only
+       CTR             .req x11        // XCTR only
+       IV_PART         .req x12
+       BLOCKS          .req x13
+       BLOCKS_W        .req w13
 
-AES_FUNC_START(aes_ctr_encrypt)
        stp             x29, x30, [sp, #-16]!
        mov             x29, sp
 
-       enc_prepare     w3, x2, x12
-       ld1             {vctr.16b}, [x5]
+       enc_prepare     ROUNDS_W, KEY, IV_PART
+       ld1             {vctr.16b}, [IV]
 
-       umov            x12, vctr.d[1]          /* keep swabbed ctr in reg */
-       rev             x12, x12
-
-.LctrloopNx:
-       add             w7, w4, #15
-       sub             w4, w4, #MAX_STRIDE << 4
-       lsr             w7, w7, #4
+       /*
+        * Keep 64 bits of the IV in a register.  For CTR mode this lets us
+        * easily increment the IV.  For XCTR mode this lets us efficiently XOR
+        * the 64-bit counter with the IV.
+        */
+       .if \xctr
+               umov            IV_PART, vctr.d[0]
+               lsr             CTR_W, BYTE_CTR_W, #4
+       .else
+               umov            IV_PART, vctr.d[1]
+               rev             IV_PART, IV_PART
+       .endif
+
+.LctrloopNx\xctr:
+       add             BLOCKS_W, BYTES_W, #15
+       sub             BYTES_W, BYTES_W, #MAX_STRIDE << 4
+       lsr             BLOCKS_W, BLOCKS_W, #4
        mov             w8, #MAX_STRIDE
-       cmp             w7, w8
-       csel            w7, w7, w8, lt
-       adds            x12, x12, x7
+       cmp             BLOCKS_W, w8
+       csel            BLOCKS_W, BLOCKS_W, w8, lt
 
+       /*
+        * Set up the counter values in v0-v{MAX_STRIDE-1}.
+        *
+        * If we are encrypting less than MAX_STRIDE blocks, the tail block
+        * handling code expects the last keystream block to be in
+        * v{MAX_STRIDE-1}.  For example: if encrypting two blocks with
+        * MAX_STRIDE=5, then v3 and v4 should have the next two counter blocks.
+        */
+       .if \xctr
+               add             CTR, CTR, BLOCKS
+       .else
+               adds            IV_PART, IV_PART, BLOCKS
+       .endif
        mov             v0.16b, vctr.16b
        mov             v1.16b, vctr.16b
        mov             v2.16b, vctr.16b
        mov             v3.16b, vctr.16b
 ST5(   mov             v4.16b, vctr.16b                )
-       bcs             0f
-
-       .subsection     1
-       /* apply carry to outgoing counter */
-0:     umov            x8, vctr.d[0]
-       rev             x8, x8
-       add             x8, x8, #1
-       rev             x8, x8
-       ins             vctr.d[0], x8
-
-       /* apply carry to N counter blocks for N := x12 */
-       cbz             x12, 2f
-       adr             x16, 1f
-       sub             x16, x16, x12, lsl #3
-       br              x16
-       bti             c
-       mov             v0.d[0], vctr.d[0]
-       bti             c
-       mov             v1.d[0], vctr.d[0]
-       bti             c
-       mov             v2.d[0], vctr.d[0]
-       bti             c
-       mov             v3.d[0], vctr.d[0]
-ST5(   bti             c                               )
-ST5(   mov             v4.d[0], vctr.d[0]              )
-1:     b               2f
-       .previous
+       .if \xctr
+               sub             x6, CTR, #MAX_STRIDE - 1
+               sub             x7, CTR, #MAX_STRIDE - 2
+               sub             x8, CTR, #MAX_STRIDE - 3
+               sub             x9, CTR, #MAX_STRIDE - 4
+ST5(           sub             x10, CTR, #MAX_STRIDE - 5       )
+               eor             x6, x6, IV_PART
+               eor             x7, x7, IV_PART
+               eor             x8, x8, IV_PART
+               eor             x9, x9, IV_PART
+ST5(           eor             x10, x10, IV_PART               )
+               mov             v0.d[0], x6
+               mov             v1.d[0], x7
+               mov             v2.d[0], x8
+               mov             v3.d[0], x9
+ST5(           mov             v4.d[0], x10                    )
+       .else
+               bcs             0f
+               .subsection     1
+               /*
+                * This subsection handles carries.
+                *
+                * Conditional branching here is allowed with respect to time
+                * invariance since the branches are dependent on the IV instead
+                * of the plaintext or key.  This code is rarely executed in
+                * practice anyway.
+                */
+
+               /* Apply carry to outgoing counter. */
+0:             umov            x8, vctr.d[0]
+               rev             x8, x8
+               add             x8, x8, #1
+               rev             x8, x8
+               ins             vctr.d[0], x8
+
+               /*
+                * Apply carry to counter blocks if needed.
+                *
+                * Since the carry flag was set, we know 0 <= IV_PART <
+                * MAX_STRIDE.  Using the value of IV_PART we can determine how
+                * many counter blocks need to be updated.
+                */
+               cbz             IV_PART, 2f
+               adr             x16, 1f
+               sub             x16, x16, IV_PART, lsl #3
+               br              x16
+               bti             c
+               mov             v0.d[0], vctr.d[0]
+               bti             c
+               mov             v1.d[0], vctr.d[0]
+               bti             c
+               mov             v2.d[0], vctr.d[0]
+               bti             c
+               mov             v3.d[0], vctr.d[0]
+ST5(           bti             c                               )
+ST5(           mov             v4.d[0], vctr.d[0]              )
+1:             b               2f
+               .previous
+
+2:             rev             x7, IV_PART
+               ins             vctr.d[1], x7
+               sub             x7, IV_PART, #MAX_STRIDE - 1
+               sub             x8, IV_PART, #MAX_STRIDE - 2
+               sub             x9, IV_PART, #MAX_STRIDE - 3
+               rev             x7, x7
+               rev             x8, x8
+               mov             v1.d[1], x7
+               rev             x9, x9
+ST5(           sub             x10, IV_PART, #MAX_STRIDE - 4   )
+               mov             v2.d[1], x8
+ST5(           rev             x10, x10                        )
+               mov             v3.d[1], x9
+ST5(           mov             v4.d[1], x10                    )
+       .endif
 
-2:     rev             x7, x12
-       ins             vctr.d[1], x7
-       sub             x7, x12, #MAX_STRIDE - 1
-       sub             x8, x12, #MAX_STRIDE - 2
-       sub             x9, x12, #MAX_STRIDE - 3
-       rev             x7, x7
-       rev             x8, x8
-       mov             v1.d[1], x7
-       rev             x9, x9
-ST5(   sub             x10, x12, #MAX_STRIDE - 4       )
-       mov             v2.d[1], x8
-ST5(   rev             x10, x10                        )
-       mov             v3.d[1], x9
-ST5(   mov             v4.d[1], x10                    )
-       tbnz            w4, #31, .Lctrtail
-       ld1             {v5.16b-v7.16b}, [x1], #48
+       /*
+        * If there are at least MAX_STRIDE blocks left, XOR the data with
+        * keystream and store.  Otherwise jump to tail handling.
+        */
+       tbnz            BYTES_W, #31, .Lctrtail\xctr
+       ld1             {v5.16b-v7.16b}, [IN], #48
 ST4(   bl              aes_encrypt_block4x             )
 ST5(   bl              aes_encrypt_block5x             )
        eor             v0.16b, v5.16b, v0.16b
-ST4(   ld1             {v5.16b}, [x1], #16             )
+ST4(   ld1             {v5.16b}, [IN], #16             )
        eor             v1.16b, v6.16b, v1.16b
-ST5(   ld1             {v5.16b-v6.16b}, [x1], #32      )
+ST5(   ld1             {v5.16b-v6.16b}, [IN], #32      )
        eor             v2.16b, v7.16b, v2.16b
        eor             v3.16b, v5.16b, v3.16b
 ST5(   eor             v4.16b, v6.16b, v4.16b          )
-       st1             {v0.16b-v3.16b}, [x0], #64
-ST5(   st1             {v4.16b}, [x0], #16             )
-       cbz             w4, .Lctrout
-       b               .LctrloopNx
-
-.Lctrout:
-       st1             {vctr.16b}, [x5]        /* return next CTR value */
+       st1             {v0.16b-v3.16b}, [OUT], #64
+ST5(   st1             {v4.16b}, [OUT], #16            )
+       cbz             BYTES_W, .Lctrout\xctr
+       b               .LctrloopNx\xctr
+
+.Lctrout\xctr:
+       .if !\xctr
+               st1             {vctr.16b}, [IV] /* return next CTR value */
+       .endif
        ldp             x29, x30, [sp], #16
        ret
 
-.Lctrtail:
-       /* XOR up to MAX_STRIDE * 16 - 1 bytes of in/output with v0 ... v3/v4 */
+.Lctrtail\xctr:
+       /*
+        * Handle up to MAX_STRIDE * 16 - 1 bytes of plaintext
+        *
+        * This code expects the last keystream block to be in v{MAX_STRIDE-1}.
+        * For example: if encrypting two blocks with MAX_STRIDE=5, then v3 and
+        * v4 should have the next two counter blocks.
+        *
+        * This allows us to store the ciphertext by writing to overlapping
+        * regions of memory.  Any invalid ciphertext blocks get overwritten by
+        * correctly computed blocks.  This approach greatly simplifies the
+        * logic for storing the ciphertext.
+        */
        mov             x16, #16
-       ands            x6, x4, #0xf
-       csel            x13, x6, x16, ne
+       ands            w7, BYTES_W, #0xf
+       csel            x13, x7, x16, ne
 
-ST5(   cmp             w4, #64 - (MAX_STRIDE << 4)     )
+ST5(   cmp             BYTES_W, #64 - (MAX_STRIDE << 4))
 ST5(   csel            x14, x16, xzr, gt               )
-       cmp             w4, #48 - (MAX_STRIDE << 4)
+       cmp             BYTES_W, #48 - (MAX_STRIDE << 4)
        csel            x15, x16, xzr, gt
-       cmp             w4, #32 - (MAX_STRIDE << 4)
+       cmp             BYTES_W, #32 - (MAX_STRIDE << 4)
        csel            x16, x16, xzr, gt
-       cmp             w4, #16 - (MAX_STRIDE << 4)
+       cmp             BYTES_W, #16 - (MAX_STRIDE << 4)
 
-       adr_l           x12, .Lcts_permute_table
-       add             x12, x12, x13
-       ble             .Lctrtail1x
+       adr_l           x9, .Lcts_permute_table
+       add             x9, x9, x13
+       ble             .Lctrtail1x\xctr
 
-ST5(   ld1             {v5.16b}, [x1], x14             )
-       ld1             {v6.16b}, [x1], x15
-       ld1             {v7.16b}, [x1], x16
+ST5(   ld1             {v5.16b}, [IN], x14             )
+       ld1             {v6.16b}, [IN], x15
+       ld1             {v7.16b}, [IN], x16
 
 ST4(   bl              aes_encrypt_block4x             )
 ST5(   bl              aes_encrypt_block5x             )
 
-       ld1             {v8.16b}, [x1], x13
-       ld1             {v9.16b}, [x1]
-       ld1             {v10.16b}, [x12]
+       ld1             {v8.16b}, [IN], x13
+       ld1             {v9.16b}, [IN]
+       ld1             {v10.16b}, [x9]
 
 ST4(   eor             v6.16b, v6.16b, v0.16b          )
 ST4(   eor             v7.16b, v7.16b, v1.16b          )
@@ -453,32 +537,91 @@ ST5(      eor             v7.16b, v7.16b, v2.16b          )
 ST5(   eor             v8.16b, v8.16b, v3.16b          )
 ST5(   eor             v9.16b, v9.16b, v4.16b          )
 
-ST5(   st1             {v5.16b}, [x0], x14             )
-       st1             {v6.16b}, [x0], x15
-       st1             {v7.16b}, [x0], x16
-       add             x13, x13, x0
+ST5(   st1             {v5.16b}, [OUT], x14            )
+       st1             {v6.16b}, [OUT], x15
+       st1             {v7.16b}, [OUT], x16
+       add             x13, x13, OUT
        st1             {v9.16b}, [x13]         // overlapping stores
-       st1             {v8.16b}, [x0]
-       b               .Lctrout
-
-.Lctrtail1x:
-       sub             x7, x6, #16
-       csel            x6, x6, x7, eq
-       add             x1, x1, x6
-       add             x0, x0, x6
-       ld1             {v5.16b}, [x1]
-       ld1             {v6.16b}, [x0]
+       st1             {v8.16b}, [OUT]
+       b               .Lctrout\xctr
+
+.Lctrtail1x\xctr:
+       /*
+        * Handle <= 16 bytes of plaintext
+        *
+        * This code always reads and writes 16 bytes.  To avoid out of bounds
+        * accesses, XCTR and CTR modes must use a temporary buffer when
+        * encrypting/decrypting less than 16 bytes.
+        *
+        * This code is unusual in that it loads the input and stores the output
+        * relative to the end of the buffers rather than relative to the start.
+        * This causes unusual behaviour when encrypting/decrypting less than 16
+        * bytes; the end of the data is expected to be at the end of the
+        * temporary buffer rather than the start of the data being at the start
+        * of the temporary buffer.
+        */
+       sub             x8, x7, #16
+       csel            x7, x7, x8, eq
+       add             IN, IN, x7
+       add             OUT, OUT, x7
+       ld1             {v5.16b}, [IN]
+       ld1             {v6.16b}, [OUT]
 ST5(   mov             v3.16b, v4.16b                  )
-       encrypt_block   v3, w3, x2, x8, w7
-       ld1             {v10.16b-v11.16b}, [x12]
+       encrypt_block   v3, ROUNDS_W, KEY, x8, w7
+       ld1             {v10.16b-v11.16b}, [x9]
        tbl             v3.16b, {v3.16b}, v10.16b
        sshr            v11.16b, v11.16b, #7
        eor             v5.16b, v5.16b, v3.16b
        bif             v5.16b, v6.16b, v11.16b
-       st1             {v5.16b}, [x0]
-       b               .Lctrout
+       st1             {v5.16b}, [OUT]
+       b               .Lctrout\xctr
+
+       // Arguments
+       .unreq OUT
+       .unreq IN
+       .unreq KEY
+       .unreq ROUNDS_W
+       .unreq BYTES_W
+       .unreq IV
+       .unreq BYTE_CTR_W       // XCTR only
+       // Intermediate values
+       .unreq CTR_W            // XCTR only
+       .unreq CTR              // XCTR only
+       .unreq IV_PART
+       .unreq BLOCKS
+       .unreq BLOCKS_W
+.endm
+
+       /*
+        * aes_ctr_encrypt(u8 out[], u8 const in[], u8 const rk[], int rounds,
+        *                 int bytes, u8 ctr[])
+        *
+        * The input and output buffers must always be at least 16 bytes even if
+        * encrypting/decrypting less than 16 bytes.  Otherwise out of bounds
+        * accesses will occur.  The data to be encrypted/decrypted is expected
+        * to be at the end of this 16-byte temporary buffer rather than the
+        * start.
+        */
+
+AES_FUNC_START(aes_ctr_encrypt)
+       ctr_encrypt 0
 AES_FUNC_END(aes_ctr_encrypt)
 
+       /*
+        * aes_xctr_encrypt(u8 out[], u8 const in[], u8 const rk[], int rounds,
+        *                 int bytes, u8 const iv[], int byte_ctr)
+        *
+        * The input and output buffers must always be at least 16 bytes even if
+        * encrypting/decrypting less than 16 bytes.  Otherwise out of bounds
+        * accesses will occur.  The data to be encrypted/decrypted is expected
+        * to be at the end of this 16-byte temporary buffer rather than the
+        * start.
+        */
+
+AES_FUNC_START(aes_xctr_encrypt)
+       ctr_encrypt 1
+AES_FUNC_END(aes_xctr_encrypt)
+
 
        /*
         * aes_xts_encrypt(u8 out[], u8 const in[], u8 const rk1[], int rounds,
index e47d3ec..9de7fbc 100644 (file)
@@ -66,7 +66,7 @@
        prepare         crypto_aes_inv_sbox, .LReverse_ShiftRows, \temp
        .endm
 
-       /* apply SubBytes transformation using the the preloaded Sbox */
+       /* apply SubBytes transformation using the preloaded Sbox */
        .macro          sub_bytes, in
        sub             v9.16b, \in\().16b, v15.16b
        tbl             \in\().16b, {v16.16b-v19.16b}, \in\().16b
index 9c3d86e..1fae18b 100644 (file)
@@ -52,7 +52,7 @@ static void neon_poly1305_blocks(struct poly1305_desc_ctx *dctx, const u8 *src,
 {
        if (unlikely(!dctx->sset)) {
                if (!dctx->rset) {
-                       poly1305_init_arch(dctx, src);
+                       poly1305_init_arm64(&dctx->h, src);
                        src += POLY1305_BLOCK_SIZE;
                        len -= POLY1305_BLOCK_SIZE;
                        dctx->rset = 1;
diff --git a/arch/arm64/crypto/polyval-ce-core.S b/arch/arm64/crypto/polyval-ce-core.S
new file mode 100644 (file)
index 0000000..b532654
--- /dev/null
@@ -0,0 +1,361 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Implementation of POLYVAL using ARMv8 Crypto Extensions.
+ *
+ * Copyright 2021 Google LLC
+ */
+/*
+ * This is an efficient implementation of POLYVAL using ARMv8 Crypto Extensions
+ * It works on 8 blocks at a time, by precomputing the first 8 keys powers h^8,
+ * ..., h^1 in the POLYVAL finite field. This precomputation allows us to split
+ * finite field multiplication into two steps.
+ *
+ * In the first step, we consider h^i, m_i as normal polynomials of degree less
+ * than 128. We then compute p(x) = h^8m_0 + ... + h^1m_7 where multiplication
+ * is simply polynomial multiplication.
+ *
+ * In the second step, we compute the reduction of p(x) modulo the finite field
+ * modulus g(x) = x^128 + x^127 + x^126 + x^121 + 1.
+ *
+ * This two step process is equivalent to computing h^8m_0 + ... + h^1m_7 where
+ * multiplication is finite field multiplication. The advantage is that the
+ * two-step process  only requires 1 finite field reduction for every 8
+ * polynomial multiplications. Further parallelism is gained by interleaving the
+ * multiplications and polynomial reductions.
+ */
+
+#include <linux/linkage.h>
+#define STRIDE_BLOCKS 8
+
+KEY_POWERS     .req    x0
+MSG            .req    x1
+BLOCKS_LEFT    .req    x2
+ACCUMULATOR    .req    x3
+KEY_START      .req    x10
+EXTRA_BYTES    .req    x11
+TMP    .req    x13
+
+M0     .req    v0
+M1     .req    v1
+M2     .req    v2
+M3     .req    v3
+M4     .req    v4
+M5     .req    v5
+M6     .req    v6
+M7     .req    v7
+KEY8   .req    v8
+KEY7   .req    v9
+KEY6   .req    v10
+KEY5   .req    v11
+KEY4   .req    v12
+KEY3   .req    v13
+KEY2   .req    v14
+KEY1   .req    v15
+PL     .req    v16
+PH     .req    v17
+TMP_V  .req    v18
+LO     .req    v20
+MI     .req    v21
+HI     .req    v22
+SUM    .req    v23
+GSTAR  .req    v24
+
+       .text
+
+       .arch   armv8-a+crypto
+       .align  4
+
+.Lgstar:
+       .quad   0xc200000000000000, 0xc200000000000000
+
+/*
+ * Computes the product of two 128-bit polynomials in X and Y and XORs the
+ * components of the 256-bit product into LO, MI, HI.
+ *
+ * Given:
+ *  X = [X_1 : X_0]
+ *  Y = [Y_1 : Y_0]
+ *
+ * We compute:
+ *  LO += X_0 * Y_0
+ *  MI += (X_0 + X_1) * (Y_0 + Y_1)
+ *  HI += X_1 * Y_1
+ *
+ * Later, the 256-bit result can be extracted as:
+ *   [HI_1 : HI_0 + HI_1 + MI_1 + LO_1 : LO_1 + HI_0 + MI_0 + LO_0 : LO_0]
+ * This step is done when computing the polynomial reduction for efficiency
+ * reasons.
+ *
+ * Karatsuba multiplication is used instead of Schoolbook multiplication because
+ * it was found to be slightly faster on ARM64 CPUs.
+ *
+ */
+.macro karatsuba1 X Y
+       X .req \X
+       Y .req \Y
+       ext     v25.16b, X.16b, X.16b, #8
+       ext     v26.16b, Y.16b, Y.16b, #8
+       eor     v25.16b, v25.16b, X.16b
+       eor     v26.16b, v26.16b, Y.16b
+       pmull2  v28.1q, X.2d, Y.2d
+       pmull   v29.1q, X.1d, Y.1d
+       pmull   v27.1q, v25.1d, v26.1d
+       eor     HI.16b, HI.16b, v28.16b
+       eor     LO.16b, LO.16b, v29.16b
+       eor     MI.16b, MI.16b, v27.16b
+       .unreq X
+       .unreq Y
+.endm
+
+/*
+ * Same as karatsuba1, except overwrites HI, LO, MI rather than XORing into
+ * them.
+ */
+.macro karatsuba1_store X Y
+       X .req \X
+       Y .req \Y
+       ext     v25.16b, X.16b, X.16b, #8
+       ext     v26.16b, Y.16b, Y.16b, #8
+       eor     v25.16b, v25.16b, X.16b
+       eor     v26.16b, v26.16b, Y.16b
+       pmull2  HI.1q, X.2d, Y.2d
+       pmull   LO.1q, X.1d, Y.1d
+       pmull   MI.1q, v25.1d, v26.1d
+       .unreq X
+       .unreq Y
+.endm
+
+/*
+ * Computes the 256-bit polynomial represented by LO, HI, MI. Stores
+ * the result in PL, PH.
+ * [PH : PL] =
+ *   [HI_1 : HI_1 + HI_0 + MI_1 + LO_1 : HI_0 + MI_0 + LO_1 + LO_0 : LO_0]
+ */
+.macro karatsuba2
+       // v4 = [HI_1 + MI_1 : HI_0 + MI_0]
+       eor     v4.16b, HI.16b, MI.16b
+       // v4 = [HI_1 + MI_1 + LO_1 : HI_0 + MI_0 + LO_0]
+       eor     v4.16b, v4.16b, LO.16b
+       // v5 = [HI_0 : LO_1]
+       ext     v5.16b, LO.16b, HI.16b, #8
+       // v4 = [HI_1 + HI_0 + MI_1 + LO_1 : HI_0 + MI_0 + LO_1 + LO_0]
+       eor     v4.16b, v4.16b, v5.16b
+       // HI = [HI_0 : HI_1]
+       ext     HI.16b, HI.16b, HI.16b, #8
+       // LO = [LO_0 : LO_1]
+       ext     LO.16b, LO.16b, LO.16b, #8
+       // PH = [HI_1 : HI_1 + HI_0 + MI_1 + LO_1]
+       ext     PH.16b, v4.16b, HI.16b, #8
+       // PL = [HI_0 + MI_0 + LO_1 + LO_0 : LO_0]
+       ext     PL.16b, LO.16b, v4.16b, #8
+.endm
+
+/*
+ * Computes the 128-bit reduction of PH : PL. Stores the result in dest.
+ *
+ * This macro computes p(x) mod g(x) where p(x) is in montgomery form and g(x) =
+ * x^128 + x^127 + x^126 + x^121 + 1.
+ *
+ * We have a 256-bit polynomial PH : PL = P_3 : P_2 : P_1 : P_0 that is the
+ * product of two 128-bit polynomials in Montgomery form.  We need to reduce it
+ * mod g(x).  Also, since polynomials in Montgomery form have an "extra" factor
+ * of x^128, this product has two extra factors of x^128.  To get it back into
+ * Montgomery form, we need to remove one of these factors by dividing by x^128.
+ *
+ * To accomplish both of these goals, we add multiples of g(x) that cancel out
+ * the low 128 bits P_1 : P_0, leaving just the high 128 bits. Since the low
+ * bits are zero, the polynomial division by x^128 can be done by right
+ * shifting.
+ *
+ * Since the only nonzero term in the low 64 bits of g(x) is the constant term,
+ * the multiple of g(x) needed to cancel out P_0 is P_0 * g(x).  The CPU can
+ * only do 64x64 bit multiplications, so split P_0 * g(x) into x^128 * P_0 +
+ * x^64 * g*(x) * P_0 + P_0, where g*(x) is bits 64-127 of g(x).  Adding this to
+ * the original polynomial gives P_3 : P_2 + P_0 + T_1 : P_1 + T_0 : 0, where T
+ * = T_1 : T_0 = g*(x) * P_0.  Thus, bits 0-63 got "folded" into bits 64-191.
+ *
+ * Repeating this same process on the next 64 bits "folds" bits 64-127 into bits
+ * 128-255, giving the answer in bits 128-255. This time, we need to cancel P_1
+ * + T_0 in bits 64-127. The multiple of g(x) required is (P_1 + T_0) * g(x) *
+ * x^64. Adding this to our previous computation gives P_3 + P_1 + T_0 + V_1 :
+ * P_2 + P_0 + T_1 + V_0 : 0 : 0, where V = V_1 : V_0 = g*(x) * (P_1 + T_0).
+ *
+ * So our final computation is:
+ *   T = T_1 : T_0 = g*(x) * P_0
+ *   V = V_1 : V_0 = g*(x) * (P_1 + T_0)
+ *   p(x) / x^{128} mod g(x) = P_3 + P_1 + T_0 + V_1 : P_2 + P_0 + T_1 + V_0
+ *
+ * The implementation below saves a XOR instruction by computing P_1 + T_0 : P_0
+ * + T_1 and XORing into dest, rather than separately XORing P_1 : P_0 and T_0 :
+ * T_1 into dest.  This allows us to reuse P_1 + T_0 when computing V.
+ */
+.macro montgomery_reduction dest
+       DEST .req \dest
+       // TMP_V = T_1 : T_0 = P_0 * g*(x)
+       pmull   TMP_V.1q, PL.1d, GSTAR.1d
+       // TMP_V = T_0 : T_1
+       ext     TMP_V.16b, TMP_V.16b, TMP_V.16b, #8
+       // TMP_V = P_1 + T_0 : P_0 + T_1
+       eor     TMP_V.16b, PL.16b, TMP_V.16b
+       // PH = P_3 + P_1 + T_0 : P_2 + P_0 + T_1
+       eor     PH.16b, PH.16b, TMP_V.16b
+       // TMP_V = V_1 : V_0 = (P_1 + T_0) * g*(x)
+       pmull2  TMP_V.1q, TMP_V.2d, GSTAR.2d
+       eor     DEST.16b, PH.16b, TMP_V.16b
+       .unreq DEST
+.endm
+
+/*
+ * Compute Polyval on 8 blocks.
+ *
+ * If reduce is set, also computes the montgomery reduction of the
+ * previous full_stride call and XORs with the first message block.
+ * (m_0 + REDUCE(PL, PH))h^8 + ... + m_7h^1.
+ * I.e., the first multiplication uses m_0 + REDUCE(PL, PH) instead of m_0.
+ *
+ * Sets PL, PH.
+ */
+.macro full_stride reduce
+       eor             LO.16b, LO.16b, LO.16b
+       eor             MI.16b, MI.16b, MI.16b
+       eor             HI.16b, HI.16b, HI.16b
+
+       ld1             {M0.16b, M1.16b, M2.16b, M3.16b}, [MSG], #64
+       ld1             {M4.16b, M5.16b, M6.16b, M7.16b}, [MSG], #64
+
+       karatsuba1 M7 KEY1
+       .if \reduce
+       pmull   TMP_V.1q, PL.1d, GSTAR.1d
+       .endif
+
+       karatsuba1 M6 KEY2
+       .if \reduce
+       ext     TMP_V.16b, TMP_V.16b, TMP_V.16b, #8
+       .endif
+
+       karatsuba1 M5 KEY3
+       .if \reduce
+       eor     TMP_V.16b, PL.16b, TMP_V.16b
+       .endif
+
+       karatsuba1 M4 KEY4
+       .if \reduce
+       eor     PH.16b, PH.16b, TMP_V.16b
+       .endif
+
+       karatsuba1 M3 KEY5
+       .if \reduce
+       pmull2  TMP_V.1q, TMP_V.2d, GSTAR.2d
+       .endif
+
+       karatsuba1 M2 KEY6
+       .if \reduce
+       eor     SUM.16b, PH.16b, TMP_V.16b
+       .endif
+
+       karatsuba1 M1 KEY7
+       eor     M0.16b, M0.16b, SUM.16b
+
+       karatsuba1 M0 KEY8
+       karatsuba2
+.endm
+
+/*
+ * Handle any extra blocks after full_stride loop.
+ */
+.macro partial_stride
+       add     KEY_POWERS, KEY_START, #(STRIDE_BLOCKS << 4)
+       sub     KEY_POWERS, KEY_POWERS, BLOCKS_LEFT, lsl #4
+       ld1     {KEY1.16b}, [KEY_POWERS], #16
+
+       ld1     {TMP_V.16b}, [MSG], #16
+       eor     SUM.16b, SUM.16b, TMP_V.16b
+       karatsuba1_store KEY1 SUM
+       sub     BLOCKS_LEFT, BLOCKS_LEFT, #1
+
+       tst     BLOCKS_LEFT, #4
+       beq     .Lpartial4BlocksDone
+       ld1     {M0.16b, M1.16b,  M2.16b, M3.16b}, [MSG], #64
+       ld1     {KEY8.16b, KEY7.16b, KEY6.16b,  KEY5.16b}, [KEY_POWERS], #64
+       karatsuba1 M0 KEY8
+       karatsuba1 M1 KEY7
+       karatsuba1 M2 KEY6
+       karatsuba1 M3 KEY5
+.Lpartial4BlocksDone:
+       tst     BLOCKS_LEFT, #2
+       beq     .Lpartial2BlocksDone
+       ld1     {M0.16b, M1.16b}, [MSG], #32
+       ld1     {KEY8.16b, KEY7.16b}, [KEY_POWERS], #32
+       karatsuba1 M0 KEY8
+       karatsuba1 M1 KEY7
+.Lpartial2BlocksDone:
+       tst     BLOCKS_LEFT, #1
+       beq     .LpartialDone
+       ld1     {M0.16b}, [MSG], #16
+       ld1     {KEY8.16b}, [KEY_POWERS], #16
+       karatsuba1 M0 KEY8
+.LpartialDone:
+       karatsuba2
+       montgomery_reduction SUM
+.endm
+
+/*
+ * Perform montgomery multiplication in GF(2^128) and store result in op1.
+ *
+ * Computes op1*op2*x^{-128} mod x^128 + x^127 + x^126 + x^121 + 1
+ * If op1, op2 are in montgomery form, this computes the montgomery
+ * form of op1*op2.
+ *
+ * void pmull_polyval_mul(u8 *op1, const u8 *op2);
+ */
+SYM_FUNC_START(pmull_polyval_mul)
+       adr     TMP, .Lgstar
+       ld1     {GSTAR.2d}, [TMP]
+       ld1     {v0.16b}, [x0]
+       ld1     {v1.16b}, [x1]
+       karatsuba1_store v0 v1
+       karatsuba2
+       montgomery_reduction SUM
+       st1     {SUM.16b}, [x0]
+       ret
+SYM_FUNC_END(pmull_polyval_mul)
+
+/*
+ * Perform polynomial evaluation as specified by POLYVAL.  This computes:
+ *     h^n * accumulator + h^n * m_0 + ... + h^1 * m_{n-1}
+ * where n=nblocks, h is the hash key, and m_i are the message blocks.
+ *
+ * x0 - pointer to precomputed key powers h^8 ... h^1
+ * x1 - pointer to message blocks
+ * x2 - number of blocks to hash
+ * x3 - pointer to accumulator
+ *
+ * void pmull_polyval_update(const struct polyval_ctx *ctx, const u8 *in,
+ *                          size_t nblocks, u8 *accumulator);
+ */
+SYM_FUNC_START(pmull_polyval_update)
+       adr     TMP, .Lgstar
+       mov     KEY_START, KEY_POWERS
+       ld1     {GSTAR.2d}, [TMP]
+       ld1     {SUM.16b}, [ACCUMULATOR]
+       subs    BLOCKS_LEFT, BLOCKS_LEFT, #STRIDE_BLOCKS
+       blt .LstrideLoopExit
+       ld1     {KEY8.16b, KEY7.16b, KEY6.16b, KEY5.16b}, [KEY_POWERS], #64
+       ld1     {KEY4.16b, KEY3.16b, KEY2.16b, KEY1.16b}, [KEY_POWERS], #64
+       full_stride 0
+       subs    BLOCKS_LEFT, BLOCKS_LEFT, #STRIDE_BLOCKS
+       blt .LstrideLoopExitReduce
+.LstrideLoop:
+       full_stride 1
+       subs    BLOCKS_LEFT, BLOCKS_LEFT, #STRIDE_BLOCKS
+       bge     .LstrideLoop
+.LstrideLoopExitReduce:
+       montgomery_reduction SUM
+.LstrideLoopExit:
+       adds    BLOCKS_LEFT, BLOCKS_LEFT, #STRIDE_BLOCKS
+       beq     .LskipPartial
+       partial_stride
+.LskipPartial:
+       st1     {SUM.16b}, [ACCUMULATOR]
+       ret
+SYM_FUNC_END(pmull_polyval_update)
diff --git a/arch/arm64/crypto/polyval-ce-glue.c b/arch/arm64/crypto/polyval-ce-glue.c
new file mode 100644 (file)
index 0000000..0a3b571
--- /dev/null
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Glue code for POLYVAL using ARMv8 Crypto Extensions
+ *
+ * Copyright (c) 2007 Nokia Siemens Networks - Mikko Herranen <mh1@iki.fi>
+ * Copyright (c) 2009 Intel Corp.
+ *   Author: Huang Ying <ying.huang@intel.com>
+ * Copyright 2021 Google LLC
+ */
+
+/*
+ * Glue code based on ghash-clmulni-intel_glue.c.
+ *
+ * This implementation of POLYVAL uses montgomery multiplication accelerated by
+ * ARMv8 Crypto Extensions instructions to implement the finite field operations.
+ */
+
+#include <crypto/algapi.h>
+#include <crypto/internal/hash.h>
+#include <crypto/internal/simd.h>
+#include <crypto/polyval.h>
+#include <linux/crypto.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/cpufeature.h>
+#include <asm/neon.h>
+#include <asm/simd.h>
+
+#define NUM_KEY_POWERS 8
+
+struct polyval_tfm_ctx {
+       /*
+        * These powers must be in the order h^8, ..., h^1.
+        */
+       u8 key_powers[NUM_KEY_POWERS][POLYVAL_BLOCK_SIZE];
+};
+
+struct polyval_desc_ctx {
+       u8 buffer[POLYVAL_BLOCK_SIZE];
+       u32 bytes;
+};
+
+asmlinkage void pmull_polyval_update(const struct polyval_tfm_ctx *keys,
+       const u8 *in, size_t nblocks, u8 *accumulator);
+asmlinkage void pmull_polyval_mul(u8 *op1, const u8 *op2);
+
+static void internal_polyval_update(const struct polyval_tfm_ctx *keys,
+       const u8 *in, size_t nblocks, u8 *accumulator)
+{
+       if (likely(crypto_simd_usable())) {
+               kernel_neon_begin();
+               pmull_polyval_update(keys, in, nblocks, accumulator);
+               kernel_neon_end();
+       } else {
+               polyval_update_non4k(keys->key_powers[NUM_KEY_POWERS-1], in,
+                       nblocks, accumulator);
+       }
+}
+
+static void internal_polyval_mul(u8 *op1, const u8 *op2)
+{
+       if (likely(crypto_simd_usable())) {
+               kernel_neon_begin();
+               pmull_polyval_mul(op1, op2);
+               kernel_neon_end();
+       } else {
+               polyval_mul_non4k(op1, op2);
+       }
+}
+
+static int polyval_arm64_setkey(struct crypto_shash *tfm,
+                       const u8 *key, unsigned int keylen)
+{
+       struct polyval_tfm_ctx *tctx = crypto_shash_ctx(tfm);
+       int i;
+
+       if (keylen != POLYVAL_BLOCK_SIZE)
+               return -EINVAL;
+
+       memcpy(tctx->key_powers[NUM_KEY_POWERS-1], key, POLYVAL_BLOCK_SIZE);
+
+       for (i = NUM_KEY_POWERS-2; i >= 0; i--) {
+               memcpy(tctx->key_powers[i], key, POLYVAL_BLOCK_SIZE);
+               internal_polyval_mul(tctx->key_powers[i],
+                                    tctx->key_powers[i+1]);
+       }
+
+       return 0;
+}
+
+static int polyval_arm64_init(struct shash_desc *desc)
+{
+       struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);
+
+       memset(dctx, 0, sizeof(*dctx));
+
+       return 0;
+}
+
+static int polyval_arm64_update(struct shash_desc *desc,
+                        const u8 *src, unsigned int srclen)
+{
+       struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);
+       const struct polyval_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm);
+       u8 *pos;
+       unsigned int nblocks;
+       unsigned int n;
+
+       if (dctx->bytes) {
+               n = min(srclen, dctx->bytes);
+               pos = dctx->buffer + POLYVAL_BLOCK_SIZE - dctx->bytes;
+
+               dctx->bytes -= n;
+               srclen -= n;
+
+               while (n--)
+                       *pos++ ^= *src++;
+
+               if (!dctx->bytes)
+                       internal_polyval_mul(dctx->buffer,
+                                           tctx->key_powers[NUM_KEY_POWERS-1]);
+       }
+
+       while (srclen >= POLYVAL_BLOCK_SIZE) {
+               /* allow rescheduling every 4K bytes */
+               nblocks = min(srclen, 4096U) / POLYVAL_BLOCK_SIZE;
+               internal_polyval_update(tctx, src, nblocks, dctx->buffer);
+               srclen -= nblocks * POLYVAL_BLOCK_SIZE;
+               src += nblocks * POLYVAL_BLOCK_SIZE;
+       }
+
+       if (srclen) {
+               dctx->bytes = POLYVAL_BLOCK_SIZE - srclen;
+               pos = dctx->buffer;
+               while (srclen--)
+                       *pos++ ^= *src++;
+       }
+
+       return 0;
+}
+
+static int polyval_arm64_final(struct shash_desc *desc, u8 *dst)
+{
+       struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);
+       const struct polyval_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm);
+
+       if (dctx->bytes) {
+               internal_polyval_mul(dctx->buffer,
+                                    tctx->key_powers[NUM_KEY_POWERS-1]);
+       }
+
+       memcpy(dst, dctx->buffer, POLYVAL_BLOCK_SIZE);
+
+       return 0;
+}
+
+static struct shash_alg polyval_alg = {
+       .digestsize     = POLYVAL_DIGEST_SIZE,
+       .init           = polyval_arm64_init,
+       .update         = polyval_arm64_update,
+       .final          = polyval_arm64_final,
+       .setkey         = polyval_arm64_setkey,
+       .descsize       = sizeof(struct polyval_desc_ctx),
+       .base           = {
+               .cra_name               = "polyval",
+               .cra_driver_name        = "polyval-ce",
+               .cra_priority           = 200,
+               .cra_blocksize          = POLYVAL_BLOCK_SIZE,
+               .cra_ctxsize            = sizeof(struct polyval_tfm_ctx),
+               .cra_module             = THIS_MODULE,
+       },
+};
+
+static int __init polyval_ce_mod_init(void)
+{
+       return crypto_register_shash(&polyval_alg);
+}
+
+static void __exit polyval_ce_mod_exit(void)
+{
+       crypto_unregister_shash(&polyval_alg);
+}
+
+module_cpu_feature_match(PMULL, polyval_ce_mod_init)
+module_exit(polyval_ce_mod_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("POLYVAL hash function accelerated by ARMv8 Crypto Extensions");
+MODULE_ALIAS_CRYPTO("polyval");
+MODULE_ALIAS_CRYPTO("polyval-ce");
index 3a6b6d3..109e2a4 100644 (file)
@@ -2,8 +2,6 @@
 #ifndef _ASM_ARCHRANDOM_H
 #define _ASM_ARCHRANDOM_H
 
-#ifdef CONFIG_ARCH_RANDOM
-
 #include <linux/arm-smccc.h>
 #include <linux/bug.h>
 #include <linux/kernel.h>
@@ -60,7 +58,7 @@ static inline bool __arm64_rndrrs(unsigned long *v)
        return ok;
 }
 
-static inline bool __must_check arch_get_random_long(unsigned long *v)
+static inline size_t __must_check arch_get_random_longs(unsigned long *v, size_t max_longs)
 {
        /*
         * Only support the generic interface after we have detected
@@ -68,27 +66,15 @@ static inline bool __must_check arch_get_random_long(unsigned long *v)
         * cpufeature code and with potential scheduling between CPUs
         * with and without the feature.
         */
-       if (cpus_have_const_cap(ARM64_HAS_RNG) && __arm64_rndr(v))
-               return true;
-       return false;
-}
-
-static inline bool __must_check arch_get_random_int(unsigned int *v)
-{
-       if (cpus_have_const_cap(ARM64_HAS_RNG)) {
-               unsigned long val;
-
-               if (__arm64_rndr(&val)) {
-                       *v = val;
-                       return true;
-               }
-       }
-       return false;
+       if (max_longs && cpus_have_const_cap(ARM64_HAS_RNG) && __arm64_rndr(v))
+               return 1;
+       return 0;
 }
 
-static inline bool __must_check arch_get_random_seed_long(unsigned long *v)
+static inline size_t __must_check arch_get_random_seed_longs(unsigned long *v, size_t max_longs)
 {
-       struct arm_smccc_res res;
+       if (!max_longs)
+               return 0;
 
        /*
         * We prefer the SMCCC call, since its semantics (return actual
@@ -97,10 +83,23 @@ static inline bool __must_check arch_get_random_seed_long(unsigned long *v)
         * (the output of a pseudo RNG freshly seeded by a TRNG).
         */
        if (smccc_trng_available) {
-               arm_smccc_1_1_invoke(ARM_SMCCC_TRNG_RND64, 64, &res);
+               struct arm_smccc_res res;
+
+               max_longs = min_t(size_t, 3, max_longs);
+               arm_smccc_1_1_invoke(ARM_SMCCC_TRNG_RND64, max_longs * 64, &res);
                if ((int)res.a0 >= 0) {
-                       *v = res.a3;
-                       return true;
+                       switch (max_longs) {
+                       case 3:
+                               *v++ = res.a1;
+                               fallthrough;
+                       case 2:
+                               *v++ = res.a2;
+                               fallthrough;
+                       case 1:
+                               *v++ = res.a3;
+                               break;
+                       }
+                       return max_longs;
                }
        }
 
@@ -110,32 +109,9 @@ static inline bool __must_check arch_get_random_seed_long(unsigned long *v)
         * enough to implement this API if no other entropy source exists.
         */
        if (cpus_have_const_cap(ARM64_HAS_RNG) && __arm64_rndrrs(v))
-               return true;
+               return 1;
 
-       return false;
-}
-
-static inline bool __must_check arch_get_random_seed_int(unsigned int *v)
-{
-       struct arm_smccc_res res;
-       unsigned long val;
-
-       if (smccc_trng_available) {
-               arm_smccc_1_1_invoke(ARM_SMCCC_TRNG_RND64, 32, &res);
-               if ((int)res.a0 >= 0) {
-                       *v = res.a3 & GENMASK(31, 0);
-                       return true;
-               }
-       }
-
-       if (cpus_have_const_cap(ARM64_HAS_RNG)) {
-               if (__arm64_rndrrs(&val)) {
-                       *v = val;
-                       return true;
-               }
-       }
-
-       return false;
+       return 0;
 }
 
 static inline bool __init __early_cpu_has_rndr(void)
@@ -145,34 +121,40 @@ static inline bool __init __early_cpu_has_rndr(void)
        return (ftr >> ID_AA64ISAR0_EL1_RNDR_SHIFT) & 0xf;
 }
 
-static inline bool __init __must_check
-arch_get_random_seed_long_early(unsigned long *v)
+static inline size_t __init __must_check
+arch_get_random_seed_longs_early(unsigned long *v, size_t max_longs)
 {
        WARN_ON(system_state != SYSTEM_BOOTING);
 
+       if (!max_longs)
+               return 0;
+
        if (smccc_trng_available) {
                struct arm_smccc_res res;
 
-               arm_smccc_1_1_invoke(ARM_SMCCC_TRNG_RND64, 64, &res);
+               max_longs = min_t(size_t, 3, max_longs);
+               arm_smccc_1_1_invoke(ARM_SMCCC_TRNG_RND64, max_longs * 64, &res);
                if ((int)res.a0 >= 0) {
-                       *v = res.a3;
-                       return true;
+                       switch (max_longs) {
+                       case 3:
+                               *v++ = res.a1;
+                               fallthrough;
+                       case 2:
+                               *v++ = res.a2;
+                               fallthrough;
+                       case 1:
+                               *v++ = res.a3;
+                               break;
+                       }
+                       return max_longs;
                }
        }
 
        if (__early_cpu_has_rndr() && __arm64_rndr(v))
-               return true;
-
-       return false;
-}
-#define arch_get_random_seed_long_early arch_get_random_seed_long_early
+               return 1;
 
-#else /* !CONFIG_ARCH_RANDOM */
-
-static inline bool __init smccc_probe_trng(void)
-{
-       return false;
+       return 0;
 }
+#define arch_get_random_seed_longs_early arch_get_random_seed_longs_early
 
-#endif /* CONFIG_ARCH_RANDOM */
 #endif /* _ASM_ARCHRANDOM_H */
index c39f243..980d1dd 100644 (file)
@@ -2,12 +2,27 @@
 #ifndef __ASM_ASM_EXTABLE_H
 #define __ASM_ASM_EXTABLE_H
 
+#include <linux/bits.h>
+#include <asm/gpr-num.h>
+
 #define EX_TYPE_NONE                   0
-#define EX_TYPE_FIXUP                  1
-#define EX_TYPE_BPF                    2
-#define EX_TYPE_UACCESS_ERR_ZERO       3
+#define EX_TYPE_BPF                    1
+#define EX_TYPE_UACCESS_ERR_ZERO       2
+#define EX_TYPE_KACCESS_ERR_ZERO       3
 #define EX_TYPE_LOAD_UNALIGNED_ZEROPAD 4
 
+/* Data fields for EX_TYPE_UACCESS_ERR_ZERO */
+#define EX_DATA_REG_ERR_SHIFT  0
+#define EX_DATA_REG_ERR                GENMASK(4, 0)
+#define EX_DATA_REG_ZERO_SHIFT 5
+#define EX_DATA_REG_ZERO       GENMASK(9, 5)
+
+/* Data fields for EX_TYPE_LOAD_UNALIGNED_ZEROPAD */
+#define EX_DATA_REG_DATA_SHIFT 0
+#define EX_DATA_REG_DATA       GENMASK(4, 0)
+#define EX_DATA_REG_ADDR_SHIFT 5
+#define EX_DATA_REG_ADDR       GENMASK(9, 5)
+
 #ifdef __ASSEMBLY__
 
 #define __ASM_EXTABLE_RAW(insn, fixup, type, data)     \
        .short          (data);                         \
        .popsection;
 
+#define EX_DATA_REG(reg, gpr)  \
+       (.L__gpr_num_##gpr << EX_DATA_REG_##reg##_SHIFT)
+
+#define _ASM_EXTABLE_UACCESS_ERR_ZERO(insn, fixup, err, zero)          \
+       __ASM_EXTABLE_RAW(insn, fixup,                                  \
+                         EX_TYPE_UACCESS_ERR_ZERO,                     \
+                         (                                             \
+                           EX_DATA_REG(ERR, err) |                     \
+                           EX_DATA_REG(ZERO, zero)                     \
+                         ))
+
+#define _ASM_EXTABLE_UACCESS_ERR(insn, fixup, err)                     \
+       _ASM_EXTABLE_UACCESS_ERR_ZERO(insn, fixup, err, wzr)
+
+#define _ASM_EXTABLE_UACCESS(insn, fixup)                              \
+       _ASM_EXTABLE_UACCESS_ERR_ZERO(insn, fixup, wzr, wzr)
+
 /*
- * Create an exception table entry for `insn`, which will branch to `fixup`
+ * Create an exception table entry for uaccess `insn`, which will branch to `fixup`
  * when an unhandled fault is taken.
  */
-       .macro          _asm_extable, insn, fixup
-       __ASM_EXTABLE_RAW(\insn, \fixup, EX_TYPE_FIXUP, 0)
+       .macro          _asm_extable_uaccess, insn, fixup
+       _ASM_EXTABLE_UACCESS(\insn, \fixup)
        .endm
 
 /*
  * Create an exception table entry for `insn` if `fixup` is provided. Otherwise
  * do nothing.
  */
-       .macro          _cond_extable, insn, fixup
-       .ifnc           \fixup,
-       _asm_extable    \insn, \fixup
+       .macro          _cond_uaccess_extable, insn, fixup
+       .ifnc                   \fixup,
+       _asm_extable_uaccess    \insn, \fixup
        .endif
        .endm
 
 #else /* __ASSEMBLY__ */
 
-#include <linux/bits.h>
 #include <linux/stringify.h>
 
-#include <asm/gpr-num.h>
-
 #define __ASM_EXTABLE_RAW(insn, fixup, type, data)     \
        ".pushsection   __ex_table, \"a\"\n"            \
        ".align         2\n"                            \
        ".short         (" data ")\n"                   \
        ".popsection\n"
 
-#define _ASM_EXTABLE(insn, fixup) \
-       __ASM_EXTABLE_RAW(#insn, #fixup, __stringify(EX_TYPE_FIXUP), "0")
-
-#define EX_DATA_REG_ERR_SHIFT  0
-#define EX_DATA_REG_ERR                GENMASK(4, 0)
-#define EX_DATA_REG_ZERO_SHIFT 5
-#define EX_DATA_REG_ZERO       GENMASK(9, 5)
-
 #define EX_DATA_REG(reg, gpr)                                          \
        "((.L__gpr_num_" #gpr ") << " __stringify(EX_DATA_REG_##reg##_SHIFT) ")"
 
                            EX_DATA_REG(ZERO, zero)                     \
                          ")")
 
+#define _ASM_EXTABLE_KACCESS_ERR_ZERO(insn, fixup, err, zero)          \
+       __DEFINE_ASM_GPR_NUMS                                           \
+       __ASM_EXTABLE_RAW(#insn, #fixup,                                \
+                         __stringify(EX_TYPE_KACCESS_ERR_ZERO),        \
+                         "("                                           \
+                           EX_DATA_REG(ERR, err) " | "                 \
+                           EX_DATA_REG(ZERO, zero)                     \
+                         ")")
+
 #define _ASM_EXTABLE_UACCESS_ERR(insn, fixup, err)                     \
        _ASM_EXTABLE_UACCESS_ERR_ZERO(insn, fixup, err, wzr)
 
-#define EX_DATA_REG_DATA_SHIFT 0
-#define EX_DATA_REG_DATA       GENMASK(4, 0)
-#define EX_DATA_REG_ADDR_SHIFT 5
-#define EX_DATA_REG_ADDR       GENMASK(9, 5)
+#define _ASM_EXTABLE_UACCESS(insn, fixup)                              \
+       _ASM_EXTABLE_UACCESS_ERR_ZERO(insn, fixup, wzr, wzr)
+
+#define _ASM_EXTABLE_KACCESS_ERR(insn, fixup, err)                     \
+       _ASM_EXTABLE_KACCESS_ERR_ZERO(insn, fixup, err, wzr)
 
 #define _ASM_EXTABLE_LOAD_UNALIGNED_ZEROPAD(insn, fixup, data, addr)           \
        __DEFINE_ASM_GPR_NUMS                                                   \
index 0557af8..75b211c 100644 (file)
@@ -61,7 +61,7 @@ alternative_else_nop_endif
 
 #define USER(l, x...)                          \
 9999:  x;                                      \
-       _asm_extable    9999b, l
+       _asm_extable_uaccess    9999b, l
 
 /*
  * Generate the assembly for LDTR/STTR with exception table entries.
@@ -73,8 +73,8 @@ alternative_else_nop_endif
 8889:          ldtr    \reg2, [\addr, #8];
                add     \addr, \addr, \post_inc;
 
-               _asm_extable    8888b,\l;
-               _asm_extable    8889b,\l;
+               _asm_extable_uaccess    8888b, \l;
+               _asm_extable_uaccess    8889b, \l;
        .endm
 
        .macro user_stp l, reg1, reg2, addr, post_inc
@@ -82,14 +82,14 @@ alternative_else_nop_endif
 8889:          sttr    \reg2, [\addr, #8];
                add     \addr, \addr, \post_inc;
 
-               _asm_extable    8888b,\l;
-               _asm_extable    8889b,\l;
+               _asm_extable_uaccess    8888b,\l;
+               _asm_extable_uaccess    8889b,\l;
        .endm
 
        .macro user_ldst l, inst, reg, addr, post_inc
 8888:          \inst           \reg, [\addr];
                add             \addr, \addr, \post_inc;
 
-               _asm_extable    8888b,\l;
+               _asm_extable_uaccess    8888b, \l;
        .endm
 #endif
index ead62f7..13ecc79 100644 (file)
@@ -59,9 +59,9 @@ alternative_else_nop_endif
 
        .macro __ptrauth_keys_init_cpu tsk, tmp1, tmp2, tmp3
        mrs     \tmp1, id_aa64isar1_el1
-       ubfx    \tmp1, \tmp1, #ID_AA64ISAR1_APA_SHIFT, #8
+       ubfx    \tmp1, \tmp1, #ID_AA64ISAR1_EL1_APA_SHIFT, #8
        mrs_s   \tmp2, SYS_ID_AA64ISAR2_EL1
-       ubfx    \tmp2, \tmp2, #ID_AA64ISAR2_APA3_SHIFT, #4
+       ubfx    \tmp2, \tmp2, #ID_AA64ISAR2_EL1_APA3_SHIFT, #4
        orr     \tmp1, \tmp1, \tmp2
        cbz     \tmp1, .Lno_addr_auth\@
        mov_q   \tmp1, (SCTLR_ELx_ENIA | SCTLR_ELx_ENIB | \
index 8c5a61a..5846145 100644 (file)
@@ -360,6 +360,20 @@ alternative_cb_end
        .endm
 
 /*
+ * idmap_get_t0sz - get the T0SZ value needed to cover the ID map
+ *
+ * Calculate the maximum allowed value for TCR_EL1.T0SZ so that the
+ * entire ID map region can be mapped. As T0SZ == (64 - #bits used),
+ * this number conveniently equals the number of leading zeroes in
+ * the physical address of _end.
+ */
+       .macro  idmap_get_t0sz, reg
+       adrp    \reg, _end
+       orr     \reg, \reg, #(1 << VA_BITS_MIN) - 1
+       clz     \reg, \reg
+       .endm
+
+/*
  * tcr_compute_pa_size - set TCR.(I)PS to the highest supported
  * ID_AA64MMFR0_EL1.PARange value
  *
@@ -423,7 +437,7 @@ alternative_endif
        b.lo    .Ldcache_op\@
        dsb     \domain
 
-       _cond_extable .Ldcache_op\@, \fixup
+       _cond_uaccess_extable .Ldcache_op\@, \fixup
        .endm
 
 /*
@@ -462,7 +476,19 @@ alternative_endif
        dsb     ish
        isb
 
-       _cond_extable .Licache_op\@, \fixup
+       _cond_uaccess_extable .Licache_op\@, \fixup
+       .endm
+
+/*
+ * load_ttbr1 - install @pgtbl as a TTBR1 page table
+ * pgtbl preserved
+ * tmp1/tmp2 clobbered, either may overlap with pgtbl
+ */
+       .macro          load_ttbr1, pgtbl, tmp1, tmp2
+       phys_to_ttbr    \tmp1, \pgtbl
+       offset_ttbr1    \tmp1, \tmp2
+       msr             ttbr1_el1, \tmp1
+       isb
        .endm
 
 /*
@@ -478,10 +504,7 @@ alternative_endif
        isb
        tlbi    vmalle1
        dsb     nsh
-       phys_to_ttbr \tmp, \page_table
-       offset_ttbr1 \tmp, \tmp2
-       msr     ttbr1_el1, \tmp
-       isb
+       load_ttbr1 \page_table, \tmp, \tmp2
        .endm
 
 /*
index 9f3e2c3..2cfc424 100644 (file)
 #define pmr_sync()     do {} while (0)
 #endif
 
-#define mb()           dsb(sy)
-#define rmb()          dsb(ld)
-#define wmb()          dsb(st)
+#define __mb()         dsb(sy)
+#define __rmb()                dsb(ld)
+#define __wmb()                dsb(st)
 
-#define dma_mb()       dmb(osh)
-#define dma_rmb()      dmb(oshld)
-#define dma_wmb()      dmb(oshst)
+#define __dma_mb()     dmb(osh)
+#define __dma_rmb()    dmb(oshld)
+#define __dma_wmb()    dmb(oshst)
 
 #define io_stop_wc()   dgh()
 
index 7c2181c..ca9b487 100644 (file)
@@ -5,34 +5,9 @@
 #ifndef __ASM_CACHE_H
 #define __ASM_CACHE_H
 
-#include <asm/cputype.h>
-#include <asm/mte-def.h>
-
-#define CTR_L1IP_SHIFT         14
-#define CTR_L1IP_MASK          3
-#define CTR_DMINLINE_SHIFT     16
-#define CTR_IMINLINE_SHIFT     0
-#define CTR_IMINLINE_MASK      0xf
-#define CTR_ERG_SHIFT          20
-#define CTR_CWG_SHIFT          24
-#define CTR_CWG_MASK           15
-#define CTR_IDC_SHIFT          28
-#define CTR_DIC_SHIFT          29
-
-#define CTR_CACHE_MINLINE_MASK \
-       (0xf << CTR_DMINLINE_SHIFT | CTR_IMINLINE_MASK << CTR_IMINLINE_SHIFT)
-
-#define CTR_L1IP(ctr)          (((ctr) >> CTR_L1IP_SHIFT) & CTR_L1IP_MASK)
-
-#define ICACHE_POLICY_VPIPT    0
-#define ICACHE_POLICY_RESERVED 1
-#define ICACHE_POLICY_VIPT     2
-#define ICACHE_POLICY_PIPT     3
-
 #define L1_CACHE_SHIFT         (6)
 #define L1_CACHE_BYTES         (1 << L1_CACHE_SHIFT)
 
-
 #define CLIDR_LOUU_SHIFT       27
 #define CLIDR_LOC_SHIFT                24
 #define CLIDR_LOUIS_SHIFT      21
 #include <linux/bitops.h>
 #include <linux/kasan-enabled.h>
 
+#include <asm/cputype.h>
+#include <asm/mte-def.h>
+#include <asm/sysreg.h>
+
 #ifdef CONFIG_KASAN_SW_TAGS
 #define ARCH_SLAB_MINALIGN     (1ULL << KASAN_SHADOW_SCALE_SHIFT)
 #elif defined(CONFIG_KASAN_HW_TAGS)
@@ -66,6 +45,12 @@ static inline unsigned int arch_slab_minalign(void)
 #define arch_slab_minalign() arch_slab_minalign()
 #endif
 
+#define CTR_CACHE_MINLINE_MASK \
+       (0xf << CTR_EL0_DMINLINE_SHIFT | \
+        CTR_EL0_IMINLINE_MASK << CTR_EL0_IMINLINE_SHIFT)
+
+#define CTR_L1IP(ctr)          SYS_FIELD_GET(CTR_EL0, L1Ip, ctr)
+
 #define ICACHEF_ALIASING       0
 #define ICACHEF_VPIPT          1
 extern unsigned long __icache_flags;
@@ -86,7 +71,7 @@ static __always_inline int icache_is_vpipt(void)
 
 static inline u32 cache_type_cwg(void)
 {
-       return (read_cpuid_cachetype() >> CTR_CWG_SHIFT) & CTR_CWG_MASK;
+       return (read_cpuid_cachetype() >> CTR_EL0_CWG_SHIFT) & CTR_EL0_CWG_MASK;
 }
 
 #define __read_mostly __section(".data..read_mostly")
@@ -120,12 +105,12 @@ static inline u32 __attribute_const__ read_cpuid_effective_cachetype(void)
 {
        u32 ctr = read_cpuid_cachetype();
 
-       if (!(ctr & BIT(CTR_IDC_SHIFT))) {
+       if (!(ctr & BIT(CTR_EL0_IDC_SHIFT))) {
                u64 clidr = read_sysreg(clidr_el1);
 
                if (CLIDR_LOC(clidr) == 0 ||
                    (CLIDR_LOUIS(clidr) == 0 && CLIDR_LOUU(clidr) == 0))
-                       ctr |= BIT(CTR_IDC_SHIFT);
+                       ctr |= BIT(CTR_EL0_IDC_SHIFT);
        }
 
        return ctr;
index 5a228e2..37185e9 100644 (file)
@@ -105,13 +105,6 @@ static inline void flush_icache_range(unsigned long start, unsigned long end)
 #define flush_icache_range flush_icache_range
 
 /*
- * Cache maintenance functions used by the DMA API. No to be used directly.
- */
-extern void __dma_map_area(const void *, size_t, int);
-extern void __dma_unmap_area(const void *, size_t, int);
-extern void __dma_flush_area(const void *, size_t);
-
-/*
  * Copy user data from/to a page which is mapped into a different
  * processes address space.  Really, we want to allow our "user
  * space" model to handle this.
index 115cdec..fd7a922 100644 (file)
@@ -46,6 +46,7 @@ struct cpuinfo_arm64 {
        u64             reg_midr;
        u64             reg_revidr;
        u64             reg_gmid;
+       u64             reg_smidr;
 
        u64             reg_id_aa64dfr0;
        u64             reg_id_aa64dfr1;
index e95c4df..a444c89 100644 (file)
  * @cpu_die:   Makes a cpu leave the kernel. Must not fail. Called from the
  *             cpu being killed.
  * @cpu_kill:  Ensures a cpu has left the kernel. Called from another cpu.
- * @cpu_init_idle: Reads any data necessary to initialize CPU idle states for
- *                a proposed logical id.
- * @cpu_suspend: Suspends a cpu and saves the required context. May fail owing
- *               to wrong parameters or error conditions. Called from the
- *               CPU being suspended. Must be called with IRQs disabled.
  */
 struct cpu_operations {
        const char      *name;
@@ -49,10 +44,6 @@ struct cpu_operations {
        void            (*cpu_die)(unsigned int cpu);
        int             (*cpu_kill)(unsigned int cpu);
 #endif
-#ifdef CONFIG_CPU_IDLE
-       int             (*cpu_init_idle)(unsigned int);
-       int             (*cpu_suspend)(unsigned long);
-#endif
 };
 
 int __init init_cpu_ops(int cpu);
index 14a8f3d..fd7d75a 100644 (file)
@@ -11,7 +11,7 @@
 #include <asm/hwcap.h>
 #include <asm/sysreg.h>
 
-#define MAX_CPU_FEATURES       64
+#define MAX_CPU_FEATURES       128
 #define cpu_feature(x)         KERNEL_HWCAP_ ## x
 
 #ifndef __ASSEMBLY__
@@ -673,7 +673,7 @@ static inline bool supports_clearbhb(int scope)
                isar2 = read_sanitised_ftr_reg(SYS_ID_AA64ISAR2_EL1);
 
        return cpuid_feature_extract_unsigned_field(isar2,
-                                                   ID_AA64ISAR2_CLEARBHB_SHIFT);
+                                                   ID_AA64ISAR2_EL1_BC_SHIFT);
 }
 
 const struct cpumask *system_32bit_el0_cpumask(void);
@@ -908,7 +908,10 @@ static inline unsigned int get_vmid_bits(u64 mmfr1)
 }
 
 extern struct arm64_ftr_override id_aa64mmfr1_override;
+extern struct arm64_ftr_override id_aa64pfr0_override;
 extern struct arm64_ftr_override id_aa64pfr1_override;
+extern struct arm64_ftr_override id_aa64zfr0_override;
+extern struct arm64_ftr_override id_aa64smfr0_override;
 extern struct arm64_ftr_override id_aa64isar1_override;
 extern struct arm64_ftr_override id_aa64isar2_override;
 
index 14a19d1..2047713 100644 (file)
@@ -4,21 +4,6 @@
 
 #include <asm/proc-fns.h>
 
-#ifdef CONFIG_CPU_IDLE
-extern int arm_cpuidle_init(unsigned int cpu);
-extern int arm_cpuidle_suspend(int index);
-#else
-static inline int arm_cpuidle_init(unsigned int cpu)
-{
-       return -EOPNOTSUPP;
-}
-
-static inline int arm_cpuidle_suspend(int index)
-{
-       return -EOPNOTSUPP;
-}
-#endif
-
 #ifdef CONFIG_ARM64_PSEUDO_NMI
 #include <asm/arch_gicv3.h>
 
index 34ceff0..2630faa 100644 (file)
        msr     cptr_el2, x0                    // Disable copro. traps to EL2
 .endm
 
-/* SVE register access */
-.macro __init_el2_nvhe_sve
-       mrs     x1, id_aa64pfr0_el1
-       ubfx    x1, x1, #ID_AA64PFR0_SVE_SHIFT, #4
-       cbz     x1, .Lskip_sve_\@
-
-       bic     x0, x0, #CPTR_EL2_TZ            // Also disable SVE traps
-       msr     cptr_el2, x0                    // Disable copro. traps to EL2
-       isb
-       mov     x1, #ZCR_ELx_LEN_MASK           // SVE: Enable full vector
-       msr_s   SYS_ZCR_EL2, x1                 // length for EL1.
-.Lskip_sve_\@:
-.endm
-
-/* SME register access and priority mapping */
-.macro __init_el2_nvhe_sme
-       mrs     x1, id_aa64pfr1_el1
-       ubfx    x1, x1, #ID_AA64PFR1_SME_SHIFT, #4
-       cbz     x1, .Lskip_sme_\@
-
-       bic     x0, x0, #CPTR_EL2_TSM           // Also disable SME traps
-       msr     cptr_el2, x0                    // Disable copro. traps to EL2
-       isb
-
-       mrs     x1, sctlr_el2
-       orr     x1, x1, #SCTLR_ELx_ENTP2        // Disable TPIDR2 traps
-       msr     sctlr_el2, x1
-       isb
-
-       mov     x1, #0                          // SMCR controls
-
-       mrs_s   x2, SYS_ID_AA64SMFR0_EL1
-       ubfx    x2, x2, #ID_AA64SMFR0_FA64_SHIFT, #1 // Full FP in SM?
-       cbz     x2, .Lskip_sme_fa64_\@
-
-       orr     x1, x1, SMCR_ELx_FA64_MASK
-.Lskip_sme_fa64_\@:
-
-       orr     x1, x1, #SMCR_ELx_LEN_MASK      // Enable full SME vector
-       msr_s   SYS_SMCR_EL2, x1                // length for EL1.
-
-       mrs_s   x1, SYS_SMIDR_EL1               // Priority mapping supported?
-       ubfx    x1, x1, #SMIDR_EL1_SMPS_SHIFT, #1
-       cbz     x1, .Lskip_sme_\@
-
-       msr_s   SYS_SMPRIMAP_EL2, xzr           // Make all priorities equal
-
-       mrs     x1, id_aa64mmfr1_el1            // HCRX_EL2 present?
-       ubfx    x1, x1, #ID_AA64MMFR1_HCX_SHIFT, #4
-       cbz     x1, .Lskip_sme_\@
-
-       mrs_s   x1, SYS_HCRX_EL2
-       orr     x1, x1, #HCRX_EL2_SMPME_MASK    // Enable priority mapping
-       msr_s   SYS_HCRX_EL2, x1
-
-.Lskip_sme_\@:
-.endm
-
 /* Disable any fine grained traps */
 .macro __init_el2_fgt
        mrs     x1, id_aa64mmfr0_el1
        __init_el2_hstr
        __init_el2_nvhe_idregs
        __init_el2_nvhe_cptr
-       __init_el2_nvhe_sve
-       __init_el2_nvhe_sme
        __init_el2_fgt
        __init_el2_nvhe_prepare_eret
 .endm
index daff882..71ed5fd 100644 (file)
@@ -62,10 +62,12 @@ enum fixed_addresses {
 #endif /* CONFIG_ACPI_APEI_GHES */
 
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
+#ifdef CONFIG_RELOCATABLE
+       FIX_ENTRY_TRAMP_TEXT4,  /* one extra slot for the data page */
+#endif
        FIX_ENTRY_TRAMP_TEXT3,
        FIX_ENTRY_TRAMP_TEXT2,
        FIX_ENTRY_TRAMP_TEXT1,
-       FIX_ENTRY_TRAMP_DATA,
 #define TRAMP_VALIAS           (__fix_to_virt(FIX_ENTRY_TRAMP_TEXT1))
 #endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
        __end_of_permanent_fixed_addresses,
index aa443d8..cef4ae7 100644 (file)
@@ -85,7 +85,7 @@
 #define KERNEL_HWCAP_PACA              __khwcap_feature(PACA)
 #define KERNEL_HWCAP_PACG              __khwcap_feature(PACG)
 
-#define __khwcap2_feature(x)           (const_ilog2(HWCAP2_ ## x) + 32)
+#define __khwcap2_feature(x)           (const_ilog2(HWCAP2_ ## x) + 64)
 #define KERNEL_HWCAP_DCPODP            __khwcap2_feature(DCPODP)
 #define KERNEL_HWCAP_SVE2              __khwcap2_feature(SVE2)
 #define KERNEL_HWCAP_SVEAES            __khwcap2_feature(SVEAES)
 #define KERNEL_HWCAP_SME_F32F32                __khwcap2_feature(SME_F32F32)
 #define KERNEL_HWCAP_SME_FA64          __khwcap2_feature(SME_FA64)
 #define KERNEL_HWCAP_WFXT              __khwcap2_feature(WFXT)
+#define KERNEL_HWCAP_EBF16             __khwcap2_feature(EBF16)
 
 /*
  * This yields a mask that user programs can use to figure out what
index 3995652..87dd42d 100644 (file)
@@ -163,13 +163,16 @@ extern void __memset_io(volatile void __iomem *, int, size_t);
 /*
  * I/O memory mapping functions.
  */
-extern void __iomem *__ioremap(phys_addr_t phys_addr, size_t size, pgprot_t prot);
-extern void iounmap(volatile void __iomem *addr);
-extern void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size);
 
-#define ioremap(addr, size)            __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE))
-#define ioremap_wc(addr, size)         __ioremap((addr), (size), __pgprot(PROT_NORMAL_NC))
-#define ioremap_np(addr, size)         __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRnE))
+bool ioremap_allowed(phys_addr_t phys_addr, size_t size, unsigned long prot);
+#define ioremap_allowed ioremap_allowed
+
+#define _PAGE_IOREMAP PROT_DEVICE_nGnRE
+
+#define ioremap_wc(addr, size) \
+       ioremap_prot((addr), (size), PROT_NORMAL_NC)
+#define ioremap_np(addr, size) \
+       ioremap_prot((addr), (size), PROT_DEVICE_nGnRnE)
 
 /*
  * io{read,write}{16,32,64}be() macros
@@ -184,6 +187,15 @@ extern void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size);
 
 #include <asm-generic/io.h>
 
+#define ioremap_cache ioremap_cache
+static inline void __iomem *ioremap_cache(phys_addr_t addr, size_t size)
+{
+       if (pfn_is_map_memory(__phys_to_pfn(addr)))
+               return (void __iomem *)__phys_to_virt(addr);
+
+       return ioremap_prot(addr, size, PROT_NORMAL);
+}
+
 /*
  * More restrictive address range checking than the default implementation
  * (PHYS_OFFSET and PHYS_MASK taken into account).
index 96dc0f7..02e59fa 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef __ASM_KERNEL_PGTABLE_H
 #define __ASM_KERNEL_PGTABLE_H
 
+#include <asm/boot.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/sparsemem.h>
 
  */
 #if ARM64_KERNEL_USES_PMD_MAPS
 #define SWAPPER_PGTABLE_LEVELS (CONFIG_PGTABLE_LEVELS - 1)
-#define IDMAP_PGTABLE_LEVELS   (ARM64_HW_PGTABLE_LEVELS(PHYS_MASK_SHIFT) - 1)
 #else
 #define SWAPPER_PGTABLE_LEVELS (CONFIG_PGTABLE_LEVELS)
-#define IDMAP_PGTABLE_LEVELS   (ARM64_HW_PGTABLE_LEVELS(PHYS_MASK_SHIFT))
 #endif
 
 
                        + EARLY_PUDS((vstart), (vend))  /* each PUD needs a next level page table */    \
                        + EARLY_PMDS((vstart), (vend))) /* each PMD needs a next level page table */
 #define INIT_DIR_SIZE (PAGE_SIZE * EARLY_PAGES(KIMAGE_VADDR, _end))
-#define IDMAP_DIR_SIZE         (IDMAP_PGTABLE_LEVELS * PAGE_SIZE)
+
+/* the initial ID map may need two extra pages if it needs to be extended */
+#if VA_BITS < 48
+#define INIT_IDMAP_DIR_SIZE    ((INIT_IDMAP_DIR_PAGES + 2) * PAGE_SIZE)
+#else
+#define INIT_IDMAP_DIR_SIZE    (INIT_IDMAP_DIR_PAGES * PAGE_SIZE)
+#endif
+#define INIT_IDMAP_DIR_PAGES   EARLY_PAGES(KIMAGE_VADDR, _end + MAX_FDT_SIZE + SWAPPER_BLOCK_SIZE)
 
 /* Initial memory map size */
 #if ARM64_KERNEL_USES_PMD_MAPS
 #define SWAPPER_PMD_FLAGS      (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S)
 
 #if ARM64_KERNEL_USES_PMD_MAPS
-#define SWAPPER_MM_MMUFLAGS    (PMD_ATTRINDX(MT_NORMAL) | SWAPPER_PMD_FLAGS)
+#define SWAPPER_RW_MMUFLAGS    (PMD_ATTRINDX(MT_NORMAL) | SWAPPER_PMD_FLAGS)
+#define SWAPPER_RX_MMUFLAGS    (SWAPPER_RW_MMUFLAGS | PMD_SECT_RDONLY)
 #else
-#define SWAPPER_MM_MMUFLAGS    (PTE_ATTRINDX(MT_NORMAL) | SWAPPER_PTE_FLAGS)
+#define SWAPPER_RW_MMUFLAGS    (PTE_ATTRINDX(MT_NORMAL) | SWAPPER_PTE_FLAGS)
+#define SWAPPER_RX_MMUFLAGS    (SWAPPER_RW_MMUFLAGS | PTE_RDONLY)
 #endif
 
 /*
index 9839bfc..559bfae 100644 (file)
@@ -84,16 +84,30 @@ static inline void crash_setup_regs(struct pt_regs *newregs,
 extern bool crash_is_nosave(unsigned long pfn);
 extern void crash_prepare_suspend(void);
 extern void crash_post_resume(void);
+
+void crash_free_reserved_phys_range(unsigned long begin, unsigned long end);
+#define crash_free_reserved_phys_range crash_free_reserved_phys_range
 #else
 static inline bool crash_is_nosave(unsigned long pfn) {return false; }
 static inline void crash_prepare_suspend(void) {}
 static inline void crash_post_resume(void) {}
 #endif
 
+struct kimage;
+
 #if defined(CONFIG_KEXEC_CORE)
 void cpu_soft_restart(unsigned long el2_switch, unsigned long entry,
                      unsigned long arg0, unsigned long arg1,
                      unsigned long arg2);
+
+int machine_kexec_post_load(struct kimage *image);
+#define machine_kexec_post_load machine_kexec_post_load
+
+void arch_kexec_protect_crashkres(void);
+#define arch_kexec_protect_crashkres arch_kexec_protect_crashkres
+
+void arch_kexec_unprotect_crashkres(void);
+#define arch_kexec_unprotect_crashkres arch_kexec_unprotect_crashkres
 #endif
 
 #define ARCH_HAS_KIMAGE_ARCH
@@ -113,9 +127,9 @@ struct kimage_arch {
 #ifdef CONFIG_KEXEC_FILE
 extern const struct kexec_file_ops kexec_image_ops;
 
-struct kimage;
+int arch_kimage_file_post_load_cleanup(struct kimage *image);
+#define arch_kimage_file_post_load_cleanup arch_kimage_file_post_load_cleanup
 
-extern int arch_kimage_file_post_load_cleanup(struct kimage *image);
 extern int load_other_segments(struct kimage *image,
                unsigned long kernel_load_addr, unsigned long kernel_size,
                char *initrd, unsigned long initrd_len,
index 0af70d9..227d256 100644 (file)
 #include <linux/types.h>
 #include <asm/bug.h>
 
+#if VA_BITS > 48
 extern u64                     vabits_actual;
+#else
+#define vabits_actual          ((u64)VA_BITS)
+#endif
 
 extern s64                     memstart_addr;
 /* PHYS_OFFSET - the physical address of the start of memory. */
@@ -351,6 +355,11 @@ static inline void *phys_to_virt(phys_addr_t x)
 })
 
 void dump_mem_limit(void);
+
+static inline bool defer_reserve_crashkernel(void)
+{
+       return IS_ENABLED(CONFIG_ZONE_DMA) || IS_ENABLED(CONFIG_ZONE_DMA32);
+}
 #endif /* !ASSEMBLY */
 
 /*
index 6770667..c7ccd82 100644 (file)
@@ -60,8 +60,7 @@ static inline void cpu_switch_mm(pgd_t *pgd, struct mm_struct *mm)
  * TCR_T0SZ(VA_BITS), unless system RAM is positioned very high in
  * physical memory, in which case it will be smaller.
  */
-extern u64 idmap_t0sz;
-extern u64 idmap_ptrs_per_pgd;
+extern int idmap_t0sz;
 
 /*
  * Ensure TCR.T0SZ is set to the provided value.
@@ -106,13 +105,18 @@ static inline void cpu_uninstall_idmap(void)
                cpu_switch_mm(mm->pgd, mm);
 }
 
-static inline void cpu_install_idmap(void)
+static inline void __cpu_install_idmap(pgd_t *idmap)
 {
        cpu_set_reserved_ttbr0();
        local_flush_tlb_all();
        cpu_set_idmap_tcr_t0sz();
 
-       cpu_switch_mm(lm_alias(idmap_pg_dir), &init_mm);
+       cpu_switch_mm(lm_alias(idmap), &init_mm);
+}
+
+static inline void cpu_install_idmap(void)
+{
+       __cpu_install_idmap(idmap_pg_dir);
 }
 
 /*
@@ -143,7 +147,7 @@ static inline void cpu_install_ttbr0(phys_addr_t ttbr0, unsigned long t0sz)
  * Atomically replaces the active TTBR1_EL1 PGD with a new VA-compatible PGD,
  * avoiding the possibility of conflicting TLB entries being allocated.
  */
-static inline void __nocfi cpu_replace_ttbr1(pgd_t *pgdp)
+static inline void __nocfi cpu_replace_ttbr1(pgd_t *pgdp, pgd_t *idmap)
 {
        typedef void (ttbr_replace_func)(phys_addr_t);
        extern ttbr_replace_func idmap_cpu_replace_ttbr1;
@@ -166,7 +170,7 @@ static inline void __nocfi cpu_replace_ttbr1(pgd_t *pgdp)
 
        replace_phys = (void *)__pa_symbol(function_nocfi(idmap_cpu_replace_ttbr1));
 
-       cpu_install_idmap();
+       __cpu_install_idmap(idmap);
        replace_phys(ttbr1);
        cpu_uninstall_idmap();
 }
index dd3d12b..5ab8d16 100644 (file)
  */
 #ifdef CONFIG_ARM64_PA_BITS_52
 /*
- * This should be GENMASK_ULL(47, 2).
  * TTBR_ELx[1] is RES0 in this configuration.
  */
-#define TTBR_BADDR_MASK_52     (((UL(1) << 46) - 1) << 2)
+#define TTBR_BADDR_MASK_52     GENMASK_ULL(47, 2)
 #endif
 
 #ifdef CONFIG_ARM64_VA_BITS_52
index 0b6632f..b5df82a 100644 (file)
        __flush_tlb_range(vma, addr, end, PUD_SIZE, false, 1)
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
+static inline bool arch_thp_swp_supported(void)
+{
+       return !system_supports_mte();
+}
+#define arch_thp_swp_supported arch_thp_swp_supported
+
 /*
  * Outside of a few very special situations (e.g. hibernation), we always
  * use broadcast TLB invalidation instructions, therefore a spurious page
@@ -427,6 +433,16 @@ static inline pte_t pte_swp_clear_exclusive(pte_t pte)
        return clear_pte_bit(pte, __pgprot(PTE_SWP_EXCLUSIVE));
 }
 
+/*
+ * Select all bits except the pfn
+ */
+static inline pgprot_t pte_pgprot(pte_t pte)
+{
+       unsigned long pfn = pte_pfn(pte);
+
+       return __pgprot(pte_val(pfn_pte(pfn, __pgprot(0))) ^ pte_val(pte));
+}
+
 #ifdef CONFIG_NUMA_BALANCING
 /*
  * See the comment in include/linux/pgtable.h
index 9e58749..86eb0bf 100644 (file)
@@ -272,8 +272,9 @@ void tls_preserve_current_state(void);
 
 static inline void start_thread_common(struct pt_regs *regs, unsigned long pc)
 {
+       s32 previous_syscall = regs->syscallno;
        memset(regs, 0, sizeof(*regs));
-       forget_syscall(regs);
+       regs->syscallno = previous_syscall;
        regs->pc = pc;
 
        if (system_uses_irq_prio_masking())
index 42ff95d..7c71358 100644 (file)
 
 #define SYS_ID_AA64PFR0_EL1            sys_reg(3, 0, 0, 4, 0)
 #define SYS_ID_AA64PFR1_EL1            sys_reg(3, 0, 0, 4, 1)
-#define SYS_ID_AA64ZFR0_EL1            sys_reg(3, 0, 0, 4, 4)
-#define SYS_ID_AA64SMFR0_EL1           sys_reg(3, 0, 0, 4, 5)
 
 #define SYS_ID_AA64DFR0_EL1            sys_reg(3, 0, 0, 5, 0)
 #define SYS_ID_AA64DFR1_EL1            sys_reg(3, 0, 0, 5, 1)
 #define SYS_ID_AA64AFR0_EL1            sys_reg(3, 0, 0, 5, 4)
 #define SYS_ID_AA64AFR1_EL1            sys_reg(3, 0, 0, 5, 5)
 
-#define SYS_ID_AA64ISAR1_EL1           sys_reg(3, 0, 0, 6, 1)
-#define SYS_ID_AA64ISAR2_EL1           sys_reg(3, 0, 0, 6, 2)
-
 #define SYS_ID_AA64MMFR0_EL1           sys_reg(3, 0, 0, 7, 0)
 #define SYS_ID_AA64MMFR1_EL1           sys_reg(3, 0, 0, 7, 1)
 #define SYS_ID_AA64MMFR2_EL1           sys_reg(3, 0, 0, 7, 2)
 #define SYS_MAIR_EL1                   sys_reg(3, 0, 10, 2, 0)
 #define SYS_AMAIR_EL1                  sys_reg(3, 0, 10, 3, 0)
 
-#define SYS_LORSA_EL1                  sys_reg(3, 0, 10, 4, 0)
-#define SYS_LOREA_EL1                  sys_reg(3, 0, 10, 4, 1)
-#define SYS_LORN_EL1                   sys_reg(3, 0, 10, 4, 2)
-#define SYS_LORC_EL1                   sys_reg(3, 0, 10, 4, 3)
-#define SYS_LORID_EL1                  sys_reg(3, 0, 10, 4, 7)
-
 #define SYS_VBAR_EL1                   sys_reg(3, 0, 12, 0, 0)
 #define SYS_DISR_EL1                   sys_reg(3, 0, 12, 1, 1)
 
 #define SYS_CNTKCTL_EL1                        sys_reg(3, 0, 14, 1, 0)
 
 #define SYS_CCSIDR_EL1                 sys_reg(3, 1, 0, 0, 0)
-#define SYS_GMID_EL1                   sys_reg(3, 1, 0, 0, 4)
 #define SYS_AIDR_EL1                   sys_reg(3, 1, 0, 0, 7)
 
 #define SMIDR_EL1_IMPLEMENTER_SHIFT    24
 #define SMIDR_EL1_SMPS_SHIFT   15
 #define SMIDR_EL1_AFFINITY_SHIFT       0
 
-#define SYS_CTR_EL0                    sys_reg(3, 3, 0, 0, 1)
-#define SYS_DCZID_EL0                  sys_reg(3, 3, 0, 0, 7)
-
 #define SYS_RNDR_EL0                   sys_reg(3, 3, 2, 4, 0)
 #define SYS_RNDRRS_EL0                 sys_reg(3, 3, 2, 4, 1)
 
 /* Position the attr at the correct index */
 #define MAIR_ATTRIDX(attr, idx)                ((attr) << ((idx) * 8))
 
-/* id_aa64isar1 */
-#define ID_AA64ISAR1_I8MM_SHIFT                52
-#define ID_AA64ISAR1_DGH_SHIFT         48
-#define ID_AA64ISAR1_BF16_SHIFT                44
-#define ID_AA64ISAR1_SPECRES_SHIFT     40
-#define ID_AA64ISAR1_SB_SHIFT          36
-#define ID_AA64ISAR1_FRINTTS_SHIFT     32
-#define ID_AA64ISAR1_GPI_SHIFT         28
-#define ID_AA64ISAR1_GPA_SHIFT         24
-#define ID_AA64ISAR1_LRCPC_SHIFT       20
-#define ID_AA64ISAR1_FCMA_SHIFT                16
-#define ID_AA64ISAR1_JSCVT_SHIFT       12
-#define ID_AA64ISAR1_API_SHIFT         8
-#define ID_AA64ISAR1_APA_SHIFT         4
-#define ID_AA64ISAR1_DPB_SHIFT         0
-
-#define ID_AA64ISAR1_APA_NI                    0x0
-#define ID_AA64ISAR1_APA_ARCHITECTED           0x1
-#define ID_AA64ISAR1_APA_ARCH_EPAC             0x2
-#define ID_AA64ISAR1_APA_ARCH_EPAC2            0x3
-#define ID_AA64ISAR1_APA_ARCH_EPAC2_FPAC       0x4
-#define ID_AA64ISAR1_APA_ARCH_EPAC2_FPAC_CMB   0x5
-#define ID_AA64ISAR1_API_NI                    0x0
-#define ID_AA64ISAR1_API_IMP_DEF               0x1
-#define ID_AA64ISAR1_API_IMP_DEF_EPAC          0x2
-#define ID_AA64ISAR1_API_IMP_DEF_EPAC2         0x3
-#define ID_AA64ISAR1_API_IMP_DEF_EPAC2_FPAC    0x4
-#define ID_AA64ISAR1_API_IMP_DEF_EPAC2_FPAC_CMB        0x5
-#define ID_AA64ISAR1_GPA_NI                    0x0
-#define ID_AA64ISAR1_GPA_ARCHITECTED           0x1
-#define ID_AA64ISAR1_GPI_NI                    0x0
-#define ID_AA64ISAR1_GPI_IMP_DEF               0x1
-
-/* id_aa64isar2 */
-#define ID_AA64ISAR2_CLEARBHB_SHIFT    28
-#define ID_AA64ISAR2_APA3_SHIFT                12
-#define ID_AA64ISAR2_GPA3_SHIFT                8
-#define ID_AA64ISAR2_RPRES_SHIFT       4
-#define ID_AA64ISAR2_WFXT_SHIFT                0
-
-#define ID_AA64ISAR2_RPRES_8BIT                0x0
-#define ID_AA64ISAR2_RPRES_12BIT       0x1
-/*
- * Value 0x1 has been removed from the architecture, and is
- * reserved, but has not yet been removed from the ARM ARM
- * as of ARM DDI 0487G.b.
- */
-#define ID_AA64ISAR2_WFXT_NI           0x0
-#define ID_AA64ISAR2_WFXT_SUPPORTED    0x2
-
-#define ID_AA64ISAR2_APA3_NI                   0x0
-#define ID_AA64ISAR2_APA3_ARCHITECTED          0x1
-#define ID_AA64ISAR2_APA3_ARCH_EPAC            0x2
-#define ID_AA64ISAR2_APA3_ARCH_EPAC2           0x3
-#define ID_AA64ISAR2_APA3_ARCH_EPAC2_FPAC      0x4
-#define ID_AA64ISAR2_APA3_ARCH_EPAC2_FPAC_CMB  0x5
-
-#define ID_AA64ISAR2_GPA3_NI                   0x0
-#define ID_AA64ISAR2_GPA3_ARCHITECTED          0x1
-
 /* id_aa64pfr0 */
 #define ID_AA64PFR0_CSV3_SHIFT         60
 #define ID_AA64PFR0_CSV2_SHIFT         56
 #define ID_AA64PFR1_MTE                        0x2
 #define ID_AA64PFR1_MTE_ASYMM          0x3
 
-/* id_aa64zfr0 */
-#define ID_AA64ZFR0_F64MM_SHIFT                56
-#define ID_AA64ZFR0_F32MM_SHIFT                52
-#define ID_AA64ZFR0_I8MM_SHIFT         44
-#define ID_AA64ZFR0_SM4_SHIFT          40
-#define ID_AA64ZFR0_SHA3_SHIFT         32
-#define ID_AA64ZFR0_BF16_SHIFT         20
-#define ID_AA64ZFR0_BITPERM_SHIFT      16
-#define ID_AA64ZFR0_AES_SHIFT          4
-#define ID_AA64ZFR0_SVEVER_SHIFT       0
-
-#define ID_AA64ZFR0_F64MM              0x1
-#define ID_AA64ZFR0_F32MM              0x1
-#define ID_AA64ZFR0_I8MM               0x1
-#define ID_AA64ZFR0_BF16               0x1
-#define ID_AA64ZFR0_SM4                        0x1
-#define ID_AA64ZFR0_SHA3               0x1
-#define ID_AA64ZFR0_BITPERM            0x1
-#define ID_AA64ZFR0_AES                        0x1
-#define ID_AA64ZFR0_AES_PMULL          0x2
-#define ID_AA64ZFR0_SVEVER_SVE2                0x1
-
-/* id_aa64smfr0 */
-#define ID_AA64SMFR0_FA64_SHIFT                63
-#define ID_AA64SMFR0_I16I64_SHIFT      52
-#define ID_AA64SMFR0_F64F64_SHIFT      48
-#define ID_AA64SMFR0_I8I32_SHIFT       36
-#define ID_AA64SMFR0_F16F32_SHIFT      35
-#define ID_AA64SMFR0_B16F32_SHIFT      34
-#define ID_AA64SMFR0_F32F32_SHIFT      32
-
-#define ID_AA64SMFR0_FA64              0x1
-#define ID_AA64SMFR0_I16I64            0xf
-#define ID_AA64SMFR0_F64F64            0x1
-#define ID_AA64SMFR0_I8I32             0xf
-#define ID_AA64SMFR0_F16F32            0x1
-#define ID_AA64SMFR0_B16F32            0x1
-#define ID_AA64SMFR0_F32F32            0x1
-
 /* id_aa64mmfr0 */
 #define ID_AA64MMFR0_ECV_SHIFT         60
 #define ID_AA64MMFR0_FGT_SHIFT         56
 
 /* id_aa64mmfr1 */
 #define ID_AA64MMFR1_ECBHB_SHIFT       60
+#define ID_AA64MMFR1_TIDCP1_SHIFT      52
 #define ID_AA64MMFR1_HCX_SHIFT         40
 #define ID_AA64MMFR1_AFP_SHIFT         44
 #define ID_AA64MMFR1_ETS_SHIFT         36
 #define ID_AA64MMFR1_VMIDBITS_8                0
 #define ID_AA64MMFR1_VMIDBITS_16       2
 
+#define ID_AA64MMFR1_TIDCP1_NI         0
+#define ID_AA64MMFR1_TIDCP1_IMP                1
+
 /* id_aa64mmfr2 */
 #define ID_AA64MMFR2_E0PD_SHIFT                60
 #define ID_AA64MMFR2_EVT_SHIFT         56
 #define MVFR2_FPMISC_SHIFT             4
 #define MVFR2_SIMDMISC_SHIFT           0
 
-#define DCZID_DZP_SHIFT                        4
-#define DCZID_BS_SHIFT                 0
-
 #define CPACR_EL1_FPEN_EL1EN   (BIT(20)) /* enable EL1 access */
 #define CPACR_EL1_FPEN_EL0EN   (BIT(21)) /* enable EL0 access, if EL1EN set */
 
 #define SYS_RGSR_EL1_SEED_MASK 0xffffUL
 
 /* GMID_EL1 field definitions */
-#define SYS_GMID_EL1_BS_SHIFT  0
-#define SYS_GMID_EL1_BS_SIZE   4
+#define GMID_EL1_BS_SHIFT      0
+#define GMID_EL1_BS_SIZE       4
 
 /* TFSR{,E0}_EL1 bit definitions */
 #define SYS_TFSR_EL1_TF0_SHIFT 0
 
 #endif
 
+#define SYS_FIELD_GET(reg, field, val)         \
+                FIELD_GET(reg##_##field##_MASK, val)
+
 #define SYS_FIELD_PREP(reg, field, val)                \
                 FIELD_PREP(reg##_##field##_MASK, val)
 
index 63f9c82..2fc9f08 100644 (file)
@@ -232,34 +232,34 @@ static inline void __user *__uaccess_mask_ptr(const void __user *ptr)
  * The "__xxx_error" versions set the third argument to -EFAULT if an error
  * occurs, and leave it unchanged on success.
  */
-#define __get_mem_asm(load, reg, x, addr, err)                         \
+#define __get_mem_asm(load, reg, x, addr, err, type)                   \
        asm volatile(                                                   \
        "1:     " load "        " reg "1, [%2]\n"                       \
        "2:\n"                                                          \
-       _ASM_EXTABLE_UACCESS_ERR_ZERO(1b, 2b, %w0, %w1)                 \
+       _ASM_EXTABLE_##type##ACCESS_ERR_ZERO(1b, 2b, %w0, %w1)          \
        : "+r" (err), "=&r" (x)                                         \
        : "r" (addr))
 
-#define __raw_get_mem(ldr, x, ptr, err)                                        \
-do {                                                                   \
-       unsigned long __gu_val;                                         \
-       switch (sizeof(*(ptr))) {                                       \
-       case 1:                                                         \
-               __get_mem_asm(ldr "b", "%w", __gu_val, (ptr), (err));   \
-               break;                                                  \
-       case 2:                                                         \
-               __get_mem_asm(ldr "h", "%w", __gu_val, (ptr), (err));   \
-               break;                                                  \
-       case 4:                                                         \
-               __get_mem_asm(ldr, "%w", __gu_val, (ptr), (err));       \
-               break;                                                  \
-       case 8:                                                         \
-               __get_mem_asm(ldr, "%x",  __gu_val, (ptr), (err));      \
-               break;                                                  \
-       default:                                                        \
-               BUILD_BUG();                                            \
-       }                                                               \
-       (x) = (__force __typeof__(*(ptr)))__gu_val;                     \
+#define __raw_get_mem(ldr, x, ptr, err, type)                                  \
+do {                                                                           \
+       unsigned long __gu_val;                                                 \
+       switch (sizeof(*(ptr))) {                                               \
+       case 1:                                                                 \
+               __get_mem_asm(ldr "b", "%w", __gu_val, (ptr), (err), type);     \
+               break;                                                          \
+       case 2:                                                                 \
+               __get_mem_asm(ldr "h", "%w", __gu_val, (ptr), (err), type);     \
+               break;                                                          \
+       case 4:                                                                 \
+               __get_mem_asm(ldr, "%w", __gu_val, (ptr), (err), type);         \
+               break;                                                          \
+       case 8:                                                                 \
+               __get_mem_asm(ldr, "%x",  __gu_val, (ptr), (err), type);        \
+               break;                                                          \
+       default:                                                                \
+               BUILD_BUG();                                                    \
+       }                                                                       \
+       (x) = (__force __typeof__(*(ptr)))__gu_val;                             \
 } while (0)
 
 /*
@@ -274,7 +274,7 @@ do {                                                                        \
        __chk_user_ptr(ptr);                                            \
                                                                        \
        uaccess_ttbr0_enable();                                         \
-       __raw_get_mem("ldtr", __rgu_val, __rgu_ptr, err);               \
+       __raw_get_mem("ldtr", __rgu_val, __rgu_ptr, err, U);            \
        uaccess_ttbr0_disable();                                        \
                                                                        \
        (x) = __rgu_val;                                                \
@@ -314,40 +314,40 @@ do {                                                                      \
                                                                        \
        __uaccess_enable_tco_async();                                   \
        __raw_get_mem("ldr", *((type *)(__gkn_dst)),                    \
-                     (__force type *)(__gkn_src), __gkn_err);          \
+                     (__force type *)(__gkn_src), __gkn_err, K);       \
        __uaccess_disable_tco_async();                                  \
                                                                        \
        if (unlikely(__gkn_err))                                        \
                goto err_label;                                         \
 } while (0)
 
-#define __put_mem_asm(store, reg, x, addr, err)                                \
+#define __put_mem_asm(store, reg, x, addr, err, type)                  \
        asm volatile(                                                   \
        "1:     " store "       " reg "1, [%2]\n"                       \
        "2:\n"                                                          \
-       _ASM_EXTABLE_UACCESS_ERR(1b, 2b, %w0)                           \
+       _ASM_EXTABLE_##type##ACCESS_ERR(1b, 2b, %w0)                    \
        : "+r" (err)                                                    \
        : "r" (x), "r" (addr))
 
-#define __raw_put_mem(str, x, ptr, err)                                        \
-do {                                                                   \
-       __typeof__(*(ptr)) __pu_val = (x);                              \
-       switch (sizeof(*(ptr))) {                                       \
-       case 1:                                                         \
-               __put_mem_asm(str "b", "%w", __pu_val, (ptr), (err));   \
-               break;                                                  \
-       case 2:                                                         \
-               __put_mem_asm(str "h", "%w", __pu_val, (ptr), (err));   \
-               break;                                                  \
-       case 4:                                                         \
-               __put_mem_asm(str, "%w", __pu_val, (ptr), (err));       \
-               break;                                                  \
-       case 8:                                                         \
-               __put_mem_asm(str, "%x", __pu_val, (ptr), (err));       \
-               break;                                                  \
-       default:                                                        \
-               BUILD_BUG();                                            \
-       }                                                               \
+#define __raw_put_mem(str, x, ptr, err, type)                                  \
+do {                                                                           \
+       __typeof__(*(ptr)) __pu_val = (x);                                      \
+       switch (sizeof(*(ptr))) {                                               \
+       case 1:                                                                 \
+               __put_mem_asm(str "b", "%w", __pu_val, (ptr), (err), type);     \
+               break;                                                          \
+       case 2:                                                                 \
+               __put_mem_asm(str "h", "%w", __pu_val, (ptr), (err), type);     \
+               break;                                                          \
+       case 4:                                                                 \
+               __put_mem_asm(str, "%w", __pu_val, (ptr), (err), type);         \
+               break;                                                          \
+       case 8:                                                                 \
+               __put_mem_asm(str, "%x", __pu_val, (ptr), (err), type);         \
+               break;                                                          \
+       default:                                                                \
+               BUILD_BUG();                                                    \
+       }                                                                       \
 } while (0)
 
 /*
@@ -362,7 +362,7 @@ do {                                                                        \
        __chk_user_ptr(__rpu_ptr);                                      \
                                                                        \
        uaccess_ttbr0_enable();                                         \
-       __raw_put_mem("sttr", __rpu_val, __rpu_ptr, err);               \
+       __raw_put_mem("sttr", __rpu_val, __rpu_ptr, err, U);            \
        uaccess_ttbr0_disable();                                        \
 } while (0)
 
@@ -400,7 +400,7 @@ do {                                                                        \
                                                                        \
        __uaccess_enable_tco_async();                                   \
        __raw_put_mem("str", *((type *)(__pkn_src)),                    \
-                     (__force type *)(__pkn_dst), __pkn_err);          \
+                     (__force type *)(__pkn_dst), __pkn_err, K);       \
        __uaccess_disable_tco_async();                                  \
                                                                        \
        if (unlikely(__pkn_err))                                        \
index 0e80db4..4eb601e 100644 (file)
@@ -36,9 +36,9 @@
 #define HVC_RESET_VECTORS 2
 
 /*
- * HVC_VHE_RESTART - Upgrade the CPU from EL1 to EL2, if possible
+ * HVC_FINALISE_EL2 - Upgrade the CPU from EL1 to EL2, if possible
  */
-#define HVC_VHE_RESTART        3
+#define HVC_FINALISE_EL2       3
 
 /* Max number of HYP stub hypercalls */
 #define HVC_STUB_HCALL_NR 4
 #define BOOT_CPU_MODE_EL1      (0xe11)
 #define BOOT_CPU_MODE_EL2      (0xe12)
 
+/*
+ * Flags returned together with the boot mode, but not preserved in
+ * __boot_cpu_mode. Used by the idreg override code to work out the
+ * boot state.
+ */
+#define BOOT_CPU_FLAG_E2H      BIT_ULL(32)
+
 #ifndef __ASSEMBLY__
 
 #include <asm/ptrace.h>
index 4bb2cc8..1ad2568 100644 (file)
@@ -19,6 +19,9 @@
 
 /*
  * HWCAP flags - for AT_HWCAP
+ *
+ * Bits 62 and 63 are reserved for use by libc.
+ * Bits 32-61 are unallocated for potential use by libc.
  */
 #define HWCAP_FP               (1 << 0)
 #define HWCAP_ASIMD            (1 << 1)
@@ -88,5 +91,6 @@
 #define HWCAP2_SME_F32F32      (1 << 29)
 #define HWCAP2_SME_FA64                (1 << 30)
 #define HWCAP2_WFXT            (1UL << 31)
+#define HWCAP2_EBF16           (1UL << 32)
 
 #endif /* _UAPI__ASM_HWCAP_H */
index fa7981d..1add7b0 100644 (file)
@@ -14,6 +14,11 @@ CFLAGS_REMOVE_return_address.o = $(CC_FLAGS_FTRACE)
 CFLAGS_REMOVE_syscall.o         = -fstack-protector -fstack-protector-strong
 CFLAGS_syscall.o       += -fno-stack-protector
 
+# When KASAN is enabled, a stack trace is recorded for every alloc/free, which
+# can significantly impact performance. Avoid instrumenting the stack trace
+# collection code to minimize this impact.
+KASAN_SANITIZE_stacktrace.o := n
+
 # It's not safe to invoke KCOV when portions of the kernel environment aren't
 # available or are out-of-sync with HW state. Since `noinstr` doesn't always
 # inhibit KCOV instrumentation, disable it for the entire compilation unit.
@@ -59,7 +64,7 @@ obj-$(CONFIG_ACPI)                    += acpi.o
 obj-$(CONFIG_ACPI_NUMA)                        += acpi_numa.o
 obj-$(CONFIG_ARM64_ACPI_PARKING_PROTOCOL)      += acpi_parking_protocol.o
 obj-$(CONFIG_PARAVIRT)                 += paravirt.o
-obj-$(CONFIG_RANDOMIZE_BASE)           += kaslr.o
+obj-$(CONFIG_RANDOMIZE_BASE)           += kaslr.o pi/
 obj-$(CONFIG_HIBERNATION)              += hibernate.o hibernate-asm.o
 obj-$(CONFIG_ELF_CORE)                 += elfcore.o
 obj-$(CONFIG_KEXEC_CORE)               += machine_kexec.o relocate_kernel.o    \
index e4dea8d..a5a256e 100644 (file)
@@ -351,7 +351,7 @@ void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
                                prot = __acpi_get_writethrough_mem_attribute();
                }
        }
-       return __ioremap(phys, size, prot);
+       return ioremap_prot(phys, size, pgprot_val(prot));
 }
 
 /*
index fdfecf0..e51535a 100644 (file)
@@ -109,7 +109,7 @@ void __init acpi_numa_gicc_affinity_init(struct acpi_srat_gicc_affinity *pa)
        pxm = pa->proximity_domain;
        node = acpi_map_pxm_to_node(pxm);
 
-       if (node == NUMA_NO_NODE || node >= MAX_NUMNODES) {
+       if (node == NUMA_NO_NODE) {
                pr_err("SRAT: Too many proximity domains %d\n", pxm);
                bad_srat();
                return;
index 7bbf510..9bcaa5e 100644 (file)
@@ -121,7 +121,7 @@ static void clean_dcache_range_nopatch(u64 start, u64 end)
 
        ctr_el0 = read_sanitised_ftr_reg(SYS_CTR_EL0);
        d_size = 4 << cpuid_feature_extract_unsigned_field(ctr_el0,
-                                                          CTR_DMINLINE_SHIFT);
+                                                          CTR_EL0_DminLine_SHIFT);
        cur = start & ~(d_size - 1);
        do {
                /*
index 6875a16..fb0e7c7 100644 (file)
@@ -59,6 +59,7 @@ struct insn_emulation {
 static LIST_HEAD(insn_emulation);
 static int nr_insn_emulated __initdata;
 static DEFINE_RAW_SPINLOCK(insn_emulation_lock);
+static DEFINE_MUTEX(insn_emulation_mutex);
 
 static void register_emulation_hooks(struct insn_emulation_ops *ops)
 {
@@ -207,10 +208,10 @@ static int emulation_proc_handler(struct ctl_table *table, int write,
                                  loff_t *ppos)
 {
        int ret = 0;
-       struct insn_emulation *insn = (struct insn_emulation *) table->data;
+       struct insn_emulation *insn = container_of(table->data, struct insn_emulation, current_mode);
        enum insn_emulation_mode prev_mode = insn->current_mode;
 
-       table->data = &insn->current_mode;
+       mutex_lock(&insn_emulation_mutex);
        ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
 
        if (ret || !write || prev_mode == insn->current_mode)
@@ -223,7 +224,7 @@ static int emulation_proc_handler(struct ctl_table *table, int write,
                update_insn_emulation_mode(insn, INSN_UNDEF);
        }
 ret:
-       table->data = insn;
+       mutex_unlock(&insn_emulation_mutex);
        return ret;
 }
 
@@ -247,7 +248,7 @@ static void __init register_insn_emulation_sysctl(void)
                sysctl->maxlen = sizeof(int);
 
                sysctl->procname = insn->ops->name;
-               sysctl->data = insn;
+               sysctl->data = &insn->current_mode;
                sysctl->extra1 = &insn->min;
                sysctl->extra2 = &insn->max;
                sysctl->proc_handler = emulation_proc_handler;
index c05cc3b..7e6289e 100644 (file)
@@ -187,7 +187,7 @@ has_neoverse_n1_erratum_1542419(const struct arm64_cpu_capabilities *entry,
                                int scope)
 {
        u32 midr = read_cpuid_id();
-       bool has_dic = read_cpuid_cachetype() & BIT(CTR_DIC_SHIFT);
+       bool has_dic = read_cpuid_cachetype() & BIT(CTR_EL0_DIC_SHIFT);
        const struct midr_range range = MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N1);
 
        WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible());
@@ -212,6 +212,12 @@ static const struct arm64_cpu_capabilities arm64_repeat_tlbi_list[] = {
                ERRATA_MIDR_RANGE(MIDR_QCOM_KRYO_4XX_GOLD, 0xc, 0xe, 0xf, 0xe),
        },
 #endif
+#ifdef CONFIG_ARM64_ERRATUM_2441009
+       {
+               /* Cortex-A510 r0p0 -> r1p1. Fixed in r1p2 */
+               ERRATA_MIDR_RANGE(MIDR_CORTEX_A510, 0, 0, 1, 1),
+       },
+#endif
        {},
 };
 #endif
@@ -395,6 +401,14 @@ static struct midr_range trbe_write_out_of_range_cpus[] = {
 };
 #endif /* CONFIG_ARM64_WORKAROUND_TRBE_WRITE_OUT_OF_RANGE */
 
+#ifdef CONFIG_ARM64_ERRATUM_1742098
+static struct midr_range broken_aarch32_aes[] = {
+       MIDR_RANGE(MIDR_CORTEX_A57, 0, 1, 0xf, 0xf),
+       MIDR_ALL_VERSIONS(MIDR_CORTEX_A72),
+       {},
+};
+#endif /* CONFIG_ARM64_WORKAROUND_TRBE_WRITE_OUT_OF_RANGE */
+
 const struct arm64_cpu_capabilities arm64_errata[] = {
 #ifdef CONFIG_ARM64_WORKAROUND_CLEAN_CACHE
        {
@@ -480,7 +494,7 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
 #endif
 #ifdef CONFIG_ARM64_WORKAROUND_REPEAT_TLBI
        {
-               .desc = "Qualcomm erratum 1009, or ARM erratum 1286807",
+               .desc = "Qualcomm erratum 1009, or ARM erratum 1286807, 2441009",
                .capability = ARM64_WORKAROUND_REPEAT_TLBI,
                .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM,
                .matches = cpucap_multi_entry_cap_matches,
@@ -658,6 +672,14 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
                ERRATA_MIDR_REV_RANGE(MIDR_CORTEX_A510, 0, 0, 1)
        },
 #endif
+#ifdef CONFIG_ARM64_ERRATUM_1742098
+       {
+               .desc = "ARM erratum 1742098",
+               .capability = ARM64_WORKAROUND_1742098,
+               CAP_MIDR_RANGE_LIST(broken_aarch32_aes),
+               .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM,
+       },
+#endif
        {
        }
 };
index 8d88433..907401e 100644 (file)
@@ -79,6 +79,7 @@
 #include <asm/cpufeature.h>
 #include <asm/cpu_ops.h>
 #include <asm/fpsimd.h>
+#include <asm/hwcap.h>
 #include <asm/insn.h>
 #include <asm/kvm_host.h>
 #include <asm/mmu_context.h>
@@ -91,7 +92,7 @@
 #include <asm/virt.h>
 
 /* Kernel representation of AT_HWCAP and AT_HWCAP2 */
-static unsigned long elf_hwcap __read_mostly;
+static DECLARE_BITMAP(elf_hwcap, MAX_CPU_FEATURES) __read_mostly;
 
 #ifdef CONFIG_COMPAT
 #define COMPAT_ELF_HWCAP_DEFAULT       \
@@ -209,35 +210,35 @@ static const struct arm64_ftr_bits ftr_id_aa64isar0[] = {
 };
 
 static const struct arm64_ftr_bits ftr_id_aa64isar1[] = {
-       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_I8MM_SHIFT, 4, 0),
-       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_DGH_SHIFT, 4, 0),
-       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_BF16_SHIFT, 4, 0),
-       ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_SPECRES_SHIFT, 4, 0),
-       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_SB_SHIFT, 4, 0),
-       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_FRINTTS_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_EL1_I8MM_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_EL1_DGH_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_EL1_BF16_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_EL1_SPECRES_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_EL1_SB_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_EL1_FRINTTS_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_PTR_AUTH),
-                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_GPI_SHIFT, 4, 0),
+                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_EL1_GPI_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_PTR_AUTH),
-                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_GPA_SHIFT, 4, 0),
-       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_LRCPC_SHIFT, 4, 0),
-       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_FCMA_SHIFT, 4, 0),
-       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_JSCVT_SHIFT, 4, 0),
+                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_EL1_GPA_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_EL1_LRCPC_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_EL1_FCMA_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_EL1_JSCVT_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_PTR_AUTH),
-                      FTR_STRICT, FTR_EXACT, ID_AA64ISAR1_API_SHIFT, 4, 0),
+                      FTR_STRICT, FTR_EXACT, ID_AA64ISAR1_EL1_API_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_PTR_AUTH),
-                      FTR_STRICT, FTR_EXACT, ID_AA64ISAR1_APA_SHIFT, 4, 0),
-       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_DPB_SHIFT, 4, 0),
+                      FTR_STRICT, FTR_EXACT, ID_AA64ISAR1_EL1_APA_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_EL1_DPB_SHIFT, 4, 0),
        ARM64_FTR_END,
 };
 
 static const struct arm64_ftr_bits ftr_id_aa64isar2[] = {
-       ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_HIGHER_SAFE, ID_AA64ISAR2_CLEARBHB_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_HIGHER_SAFE, ID_AA64ISAR2_EL1_BC_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_PTR_AUTH),
-                      FTR_STRICT, FTR_EXACT, ID_AA64ISAR2_APA3_SHIFT, 4, 0),
+                      FTR_STRICT, FTR_EXACT, ID_AA64ISAR2_EL1_APA3_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_PTR_AUTH),
-                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR2_GPA3_SHIFT, 4, 0),
-       ARM64_FTR_BITS(FTR_VISIBLE, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64ISAR2_RPRES_SHIFT, 4, 0),
-       ARM64_FTR_BITS(FTR_VISIBLE, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64ISAR2_WFXT_SHIFT, 4, 0),
+                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR2_EL1_GPA3_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64ISAR2_EL1_RPRES_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64ISAR2_EL1_WFxT_SHIFT, 4, 0),
        ARM64_FTR_END,
 };
 
@@ -276,41 +277,41 @@ static const struct arm64_ftr_bits ftr_id_aa64pfr1[] = {
 
 static const struct arm64_ftr_bits ftr_id_aa64zfr0[] = {
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SVE),
-                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ZFR0_F64MM_SHIFT, 4, 0),
+                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ZFR0_EL1_F64MM_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SVE),
-                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ZFR0_F32MM_SHIFT, 4, 0),
+                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ZFR0_EL1_F32MM_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SVE),
-                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ZFR0_I8MM_SHIFT, 4, 0),
+                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ZFR0_EL1_I8MM_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SVE),
-                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ZFR0_SM4_SHIFT, 4, 0),
+                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ZFR0_EL1_SM4_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SVE),
-                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ZFR0_SHA3_SHIFT, 4, 0),
+                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ZFR0_EL1_SHA3_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SVE),
-                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ZFR0_BF16_SHIFT, 4, 0),
+                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ZFR0_EL1_BF16_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SVE),
-                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ZFR0_BITPERM_SHIFT, 4, 0),
+                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ZFR0_EL1_BitPerm_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SVE),
-                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ZFR0_AES_SHIFT, 4, 0),
+                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ZFR0_EL1_AES_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SVE),
-                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ZFR0_SVEVER_SHIFT, 4, 0),
+                      FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ZFR0_EL1_SVEver_SHIFT, 4, 0),
        ARM64_FTR_END,
 };
 
 static const struct arm64_ftr_bits ftr_id_aa64smfr0[] = {
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SME),
-                      FTR_STRICT, FTR_EXACT, ID_AA64SMFR0_FA64_SHIFT, 1, 0),
+                      FTR_STRICT, FTR_EXACT, ID_AA64SMFR0_EL1_FA64_SHIFT, 1, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SME),
-                      FTR_STRICT, FTR_EXACT, ID_AA64SMFR0_I16I64_SHIFT, 4, 0),
+                      FTR_STRICT, FTR_EXACT, ID_AA64SMFR0_EL1_I16I64_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SME),
-                      FTR_STRICT, FTR_EXACT, ID_AA64SMFR0_F64F64_SHIFT, 1, 0),
+                      FTR_STRICT, FTR_EXACT, ID_AA64SMFR0_EL1_F64F64_SHIFT, 1, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SME),
-                      FTR_STRICT, FTR_EXACT, ID_AA64SMFR0_I8I32_SHIFT, 4, 0),
+                      FTR_STRICT, FTR_EXACT, ID_AA64SMFR0_EL1_I8I32_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SME),
-                      FTR_STRICT, FTR_EXACT, ID_AA64SMFR0_F16F32_SHIFT, 1, 0),
+                      FTR_STRICT, FTR_EXACT, ID_AA64SMFR0_EL1_F16F32_SHIFT, 1, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SME),
-                      FTR_STRICT, FTR_EXACT, ID_AA64SMFR0_B16F32_SHIFT, 1, 0),
+                      FTR_STRICT, FTR_EXACT, ID_AA64SMFR0_EL1_B16F32_SHIFT, 1, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SME),
-                      FTR_STRICT, FTR_EXACT, ID_AA64SMFR0_F32F32_SHIFT, 1, 0),
+                      FTR_STRICT, FTR_EXACT, ID_AA64SMFR0_EL1_F32F32_SHIFT, 1, 0),
        ARM64_FTR_END,
 };
 
@@ -361,6 +362,7 @@ static const struct arm64_ftr_bits ftr_id_aa64mmfr0[] = {
 };
 
 static const struct arm64_ftr_bits ftr_id_aa64mmfr1[] = {
+       ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64MMFR1_TIDCP1_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR1_AFP_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR1_ETS_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR1_TWED_SHIFT, 4, 0),
@@ -396,18 +398,18 @@ static const struct arm64_ftr_bits ftr_id_aa64mmfr2[] = {
 
 static const struct arm64_ftr_bits ftr_ctr[] = {
        ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, 31, 1, 1), /* RES1 */
-       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, CTR_DIC_SHIFT, 1, 1),
-       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, CTR_IDC_SHIFT, 1, 1),
-       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_HIGHER_OR_ZERO_SAFE, CTR_CWG_SHIFT, 4, 0),
-       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_HIGHER_OR_ZERO_SAFE, CTR_ERG_SHIFT, 4, 0),
-       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, CTR_DMINLINE_SHIFT, 4, 1),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, CTR_EL0_DIC_SHIFT, 1, 1),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, CTR_EL0_IDC_SHIFT, 1, 1),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_HIGHER_OR_ZERO_SAFE, CTR_EL0_CWG_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_HIGHER_OR_ZERO_SAFE, CTR_EL0_ERG_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, CTR_EL0_DminLine_SHIFT, 4, 1),
        /*
         * Linux can handle differing I-cache policies. Userspace JITs will
         * make use of *minLine.
         * If we have differing I-cache policies, report it as the weakest - VIPT.
         */
-       ARM64_FTR_BITS(FTR_VISIBLE, FTR_NONSTRICT, FTR_EXACT, CTR_L1IP_SHIFT, 2, ICACHE_POLICY_VIPT),   /* L1Ip */
-       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, CTR_IMINLINE_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_NONSTRICT, FTR_EXACT, CTR_EL0_L1Ip_SHIFT, 2, CTR_EL0_L1Ip_VIPT),        /* L1Ip */
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, CTR_EL0_IminLine_SHIFT, 4, 0),
        ARM64_FTR_END,
 };
 
@@ -453,13 +455,13 @@ static const struct arm64_ftr_bits ftr_mvfr2[] = {
 };
 
 static const struct arm64_ftr_bits ftr_dczid[] = {
-       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, DCZID_DZP_SHIFT, 1, 1),
-       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, DCZID_BS_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, DCZID_EL0_DZP_SHIFT, 1, 1),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, DCZID_EL0_BS_SHIFT, 4, 0),
        ARM64_FTR_END,
 };
 
 static const struct arm64_ftr_bits ftr_gmid[] = {
-       ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, SYS_GMID_EL1_BS_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, GMID_EL1_BS_SHIFT, 4, 0),
        ARM64_FTR_END,
 };
 
@@ -561,7 +563,7 @@ static const struct arm64_ftr_bits ftr_id_pfr2[] = {
 
 static const struct arm64_ftr_bits ftr_id_dfr0[] = {
        /* [31:28] TraceFilt */
-       S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_PERFMON_SHIFT, 4, 0xf),
+       S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_DFR0_PERFMON_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_MPROFDBG_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_MMAPTRC_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_COPTRC_SHIFT, 4, 0),
@@ -631,7 +633,10 @@ static const struct arm64_ftr_bits ftr_raz[] = {
        __ARM64_FTR_REG_OVERRIDE(#id, id, table, &no_override)
 
 struct arm64_ftr_override __ro_after_init id_aa64mmfr1_override;
+struct arm64_ftr_override __ro_after_init id_aa64pfr0_override;
 struct arm64_ftr_override __ro_after_init id_aa64pfr1_override;
+struct arm64_ftr_override __ro_after_init id_aa64zfr0_override;
+struct arm64_ftr_override __ro_after_init id_aa64smfr0_override;
 struct arm64_ftr_override __ro_after_init id_aa64isar1_override;
 struct arm64_ftr_override __ro_after_init id_aa64isar2_override;
 
@@ -668,11 +673,14 @@ static const struct __ftr_reg_entry {
        ARM64_FTR_REG(SYS_ID_MMFR5_EL1, ftr_id_mmfr5),
 
        /* Op1 = 0, CRn = 0, CRm = 4 */
-       ARM64_FTR_REG(SYS_ID_AA64PFR0_EL1, ftr_id_aa64pfr0),
+       ARM64_FTR_REG_OVERRIDE(SYS_ID_AA64PFR0_EL1, ftr_id_aa64pfr0,
+                              &id_aa64pfr0_override),
        ARM64_FTR_REG_OVERRIDE(SYS_ID_AA64PFR1_EL1, ftr_id_aa64pfr1,
                               &id_aa64pfr1_override),
-       ARM64_FTR_REG(SYS_ID_AA64ZFR0_EL1, ftr_id_aa64zfr0),
-       ARM64_FTR_REG(SYS_ID_AA64SMFR0_EL1, ftr_id_aa64smfr0),
+       ARM64_FTR_REG_OVERRIDE(SYS_ID_AA64ZFR0_EL1, ftr_id_aa64zfr0,
+                              &id_aa64zfr0_override),
+       ARM64_FTR_REG_OVERRIDE(SYS_ID_AA64SMFR0_EL1, ftr_id_aa64smfr0,
+                              &id_aa64smfr0_override),
 
        /* Op1 = 0, CRn = 0, CRm = 5 */
        ARM64_FTR_REG(SYS_ID_AA64DFR0_EL1, ftr_id_aa64dfr0),
@@ -993,15 +1001,24 @@ void __init init_cpu_features(struct cpuinfo_arm64 *info)
        if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0))
                init_32bit_cpu_features(&info->aarch32);
 
-       if (id_aa64pfr0_sve(info->reg_id_aa64pfr0)) {
+       if (IS_ENABLED(CONFIG_ARM64_SVE) &&
+           id_aa64pfr0_sve(read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1))) {
+               info->reg_zcr = read_zcr_features();
                init_cpu_ftr_reg(SYS_ZCR_EL1, info->reg_zcr);
                vec_init_vq_map(ARM64_VEC_SVE);
        }
 
-       if (id_aa64pfr1_sme(info->reg_id_aa64pfr1)) {
+       if (IS_ENABLED(CONFIG_ARM64_SME) &&
+           id_aa64pfr1_sme(read_sanitised_ftr_reg(SYS_ID_AA64PFR1_EL1))) {
+               info->reg_smcr = read_smcr_features();
+               /*
+                * We mask out SMPS since even if the hardware
+                * supports priorities the kernel does not at present
+                * and we block access to them.
+                */
+               info->reg_smidr = read_cpuid(SMIDR_EL1) & ~SMIDR_EL1_SMPS;
                init_cpu_ftr_reg(SYS_SMCR_EL1, info->reg_smcr);
-               if (IS_ENABLED(CONFIG_ARM64_SME))
-                       vec_init_vq_map(ARM64_VEC_SME);
+               vec_init_vq_map(ARM64_VEC_SME);
        }
 
        if (id_aa64pfr1_mte(info->reg_id_aa64pfr1))
@@ -1233,23 +1250,31 @@ void update_cpu_features(int cpu,
        taint |= check_update_ftr_reg(SYS_ID_AA64SMFR0_EL1, cpu,
                                      info->reg_id_aa64smfr0, boot->reg_id_aa64smfr0);
 
-       if (id_aa64pfr0_sve(info->reg_id_aa64pfr0)) {
+       if (IS_ENABLED(CONFIG_ARM64_SVE) &&
+           id_aa64pfr0_sve(read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1))) {
+               info->reg_zcr = read_zcr_features();
                taint |= check_update_ftr_reg(SYS_ZCR_EL1, cpu,
                                        info->reg_zcr, boot->reg_zcr);
 
-               /* Probe vector lengths, unless we already gave up on SVE */
-               if (id_aa64pfr0_sve(read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1)) &&
-                   !system_capabilities_finalized())
+               /* Probe vector lengths */
+               if (!system_capabilities_finalized())
                        vec_update_vq_map(ARM64_VEC_SVE);
        }
 
-       if (id_aa64pfr1_sme(info->reg_id_aa64pfr1)) {
+       if (IS_ENABLED(CONFIG_ARM64_SME) &&
+           id_aa64pfr1_sme(read_sanitised_ftr_reg(SYS_ID_AA64PFR1_EL1))) {
+               info->reg_smcr = read_smcr_features();
+               /*
+                * We mask out SMPS since even if the hardware
+                * supports priorities the kernel does not at present
+                * and we block access to them.
+                */
+               info->reg_smidr = read_cpuid(SMIDR_EL1) & ~SMIDR_EL1_SMPS;
                taint |= check_update_ftr_reg(SYS_SMCR_EL1, cpu,
                                        info->reg_smcr, boot->reg_smcr);
 
-               /* Probe vector lengths, unless we already gave up on SME */
-               if (id_aa64pfr1_sme(read_sanitised_ftr_reg(SYS_ID_AA64PFR1_EL1)) &&
-                   !system_capabilities_finalized())
+               /* Probe vector lengths */
+               if (!system_capabilities_finalized())
                        vec_update_vq_map(ARM64_VEC_SME);
        }
 
@@ -1480,7 +1505,7 @@ static bool has_cache_idc(const struct arm64_cpu_capabilities *entry,
        else
                ctr = read_cpuid_effective_cachetype();
 
-       return ctr & BIT(CTR_IDC_SHIFT);
+       return ctr & BIT(CTR_EL0_IDC_SHIFT);
 }
 
 static void cpu_emulate_effective_ctr(const struct arm64_cpu_capabilities *__unused)
@@ -1491,7 +1516,7 @@ static void cpu_emulate_effective_ctr(const struct arm64_cpu_capabilities *__unu
         * to the CTR_EL0 on this CPU and emulate it with the real/safe
         * value.
         */
-       if (!(read_cpuid_cachetype() & BIT(CTR_IDC_SHIFT)))
+       if (!(read_cpuid_cachetype() & BIT(CTR_EL0_IDC_SHIFT)))
                sysreg_clear_set(sctlr_el1, SCTLR_EL1_UCT, 0);
 }
 
@@ -1505,7 +1530,7 @@ static bool has_cache_dic(const struct arm64_cpu_capabilities *entry,
        else
                ctr = read_cpuid_cachetype();
 
-       return ctr & BIT(CTR_DIC_SHIFT);
+       return ctr & BIT(CTR_EL0_DIC_SHIFT);
 }
 
 static bool __maybe_unused
@@ -1645,14 +1670,34 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry,
 }
 
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
+#define KPTI_NG_TEMP_VA                (-(1UL << PMD_SHIFT))
+
+extern
+void create_kpti_ng_temp_pgd(pgd_t *pgdir, phys_addr_t phys, unsigned long virt,
+                            phys_addr_t size, pgprot_t prot,
+                            phys_addr_t (*pgtable_alloc)(int), int flags);
+
+static phys_addr_t kpti_ng_temp_alloc;
+
+static phys_addr_t kpti_ng_pgd_alloc(int shift)
+{
+       kpti_ng_temp_alloc -= PAGE_SIZE;
+       return kpti_ng_temp_alloc;
+}
+
 static void __nocfi
 kpti_install_ng_mappings(const struct arm64_cpu_capabilities *__unused)
 {
-       typedef void (kpti_remap_fn)(int, int, phys_addr_t);
+       typedef void (kpti_remap_fn)(int, int, phys_addr_t, unsigned long);
        extern kpti_remap_fn idmap_kpti_install_ng_mappings;
        kpti_remap_fn *remap_fn;
 
        int cpu = smp_processor_id();
+       int levels = CONFIG_PGTABLE_LEVELS;
+       int order = order_base_2(levels);
+       u64 kpti_ng_temp_pgd_pa = 0;
+       pgd_t *kpti_ng_temp_pgd;
+       u64 alloc = 0;
 
        if (__this_cpu_read(this_cpu_vector) == vectors) {
                const char *v = arm64_get_bp_hardening_vector(EL1_VECTOR_KPTI);
@@ -1670,12 +1715,40 @@ kpti_install_ng_mappings(const struct arm64_cpu_capabilities *__unused)
 
        remap_fn = (void *)__pa_symbol(function_nocfi(idmap_kpti_install_ng_mappings));
 
+       if (!cpu) {
+               alloc = __get_free_pages(GFP_ATOMIC | __GFP_ZERO, order);
+               kpti_ng_temp_pgd = (pgd_t *)(alloc + (levels - 1) * PAGE_SIZE);
+               kpti_ng_temp_alloc = kpti_ng_temp_pgd_pa = __pa(kpti_ng_temp_pgd);
+
+               //
+               // Create a minimal page table hierarchy that permits us to map
+               // the swapper page tables temporarily as we traverse them.
+               //
+               // The physical pages are laid out as follows:
+               //
+               // +--------+-/-------+-/------ +-\\--------+
+               // :  PTE[] : | PMD[] : | PUD[] : || PGD[]  :
+               // +--------+-\-------+-\------ +-//--------+
+               //      ^
+               // The first page is mapped into this hierarchy at a PMD_SHIFT
+               // aligned virtual address, so that we can manipulate the PTE
+               // level entries while the mapping is active. The first entry
+               // covers the PTE[] page itself, the remaining entries are free
+               // to be used as a ad-hoc fixmap.
+               //
+               create_kpti_ng_temp_pgd(kpti_ng_temp_pgd, __pa(alloc),
+                                       KPTI_NG_TEMP_VA, PAGE_SIZE, PAGE_KERNEL,
+                                       kpti_ng_pgd_alloc, 0);
+       }
+
        cpu_install_idmap();
-       remap_fn(cpu, num_online_cpus(), __pa_symbol(swapper_pg_dir));
+       remap_fn(cpu, num_online_cpus(), kpti_ng_temp_pgd_pa, KPTI_NG_TEMP_VA);
        cpu_uninstall_idmap();
 
-       if (!cpu)
+       if (!cpu) {
+               free_pages(alloc, order);
                arm64_use_ng_mappings = true;
+       }
 }
 #else
 static void
@@ -1971,6 +2044,14 @@ static void cpu_enable_mte(struct arm64_cpu_capabilities const *cap)
 }
 #endif /* CONFIG_ARM64_MTE */
 
+static void elf_hwcap_fixup(void)
+{
+#ifdef CONFIG_ARM64_ERRATUM_1742098
+       if (cpus_have_const_cap(ARM64_WORKAROUND_1742098))
+               compat_elf_hwcap2 &= ~COMPAT_HWCAP2_AES;
+#endif /* ARM64_ERRATUM_1742098 */
+}
+
 #ifdef CONFIG_KVM
 static bool is_kvm_protected_mode(const struct arm64_cpu_capabilities *entry, int __unused)
 {
@@ -1978,6 +2059,11 @@ static bool is_kvm_protected_mode(const struct arm64_cpu_capabilities *entry, in
 }
 #endif /* CONFIG_KVM */
 
+static void cpu_trap_el0_impdef(const struct arm64_cpu_capabilities *__unused)
+{
+       sysreg_clear_set(sctlr_el1, 0, SCTLR_EL1_TIDCP);
+}
+
 /* Internal helper functions to match cpu capability type */
 static bool
 cpucap_late_cpu_optional(const struct arm64_cpu_capabilities *cap)
@@ -2132,7 +2218,7 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .type = ARM64_CPUCAP_SYSTEM_FEATURE,
                .matches = has_cpuid_feature,
                .sys_reg = SYS_ID_AA64ISAR1_EL1,
-               .field_pos = ID_AA64ISAR1_DPB_SHIFT,
+               .field_pos = ID_AA64ISAR1_EL1_DPB_SHIFT,
                .field_width = 4,
                .min_field_value = 1,
        },
@@ -2143,7 +2229,7 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .matches = has_cpuid_feature,
                .sys_reg = SYS_ID_AA64ISAR1_EL1,
                .sign = FTR_UNSIGNED,
-               .field_pos = ID_AA64ISAR1_DPB_SHIFT,
+               .field_pos = ID_AA64ISAR1_EL1_DPB_SHIFT,
                .field_width = 4,
                .min_field_value = 2,
        },
@@ -2303,7 +2389,7 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .type = ARM64_CPUCAP_SYSTEM_FEATURE,
                .matches = has_cpuid_feature,
                .sys_reg = SYS_ID_AA64ISAR1_EL1,
-               .field_pos = ID_AA64ISAR1_SB_SHIFT,
+               .field_pos = ID_AA64ISAR1_EL1_SB_SHIFT,
                .field_width = 4,
                .sign = FTR_UNSIGNED,
                .min_field_value = 1,
@@ -2315,9 +2401,9 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .type = ARM64_CPUCAP_BOOT_CPU_FEATURE,
                .sys_reg = SYS_ID_AA64ISAR1_EL1,
                .sign = FTR_UNSIGNED,
-               .field_pos = ID_AA64ISAR1_APA_SHIFT,
+               .field_pos = ID_AA64ISAR1_EL1_APA_SHIFT,
                .field_width = 4,
-               .min_field_value = ID_AA64ISAR1_APA_ARCHITECTED,
+               .min_field_value = ID_AA64ISAR1_EL1_APA_PAuth,
                .matches = has_address_auth_cpucap,
        },
        {
@@ -2326,9 +2412,9 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .type = ARM64_CPUCAP_BOOT_CPU_FEATURE,
                .sys_reg = SYS_ID_AA64ISAR2_EL1,
                .sign = FTR_UNSIGNED,
-               .field_pos = ID_AA64ISAR2_APA3_SHIFT,
+               .field_pos = ID_AA64ISAR2_EL1_APA3_SHIFT,
                .field_width = 4,
-               .min_field_value = ID_AA64ISAR2_APA3_ARCHITECTED,
+               .min_field_value = ID_AA64ISAR2_EL1_APA3_PAuth,
                .matches = has_address_auth_cpucap,
        },
        {
@@ -2337,9 +2423,9 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .type = ARM64_CPUCAP_BOOT_CPU_FEATURE,
                .sys_reg = SYS_ID_AA64ISAR1_EL1,
                .sign = FTR_UNSIGNED,
-               .field_pos = ID_AA64ISAR1_API_SHIFT,
+               .field_pos = ID_AA64ISAR1_EL1_API_SHIFT,
                .field_width = 4,
-               .min_field_value = ID_AA64ISAR1_API_IMP_DEF,
+               .min_field_value = ID_AA64ISAR1_EL1_API_PAuth,
                .matches = has_address_auth_cpucap,
        },
        {
@@ -2353,9 +2439,9 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .type = ARM64_CPUCAP_SYSTEM_FEATURE,
                .sys_reg = SYS_ID_AA64ISAR1_EL1,
                .sign = FTR_UNSIGNED,
-               .field_pos = ID_AA64ISAR1_GPA_SHIFT,
+               .field_pos = ID_AA64ISAR1_EL1_GPA_SHIFT,
                .field_width = 4,
-               .min_field_value = ID_AA64ISAR1_GPA_ARCHITECTED,
+               .min_field_value = ID_AA64ISAR1_EL1_GPA_IMP,
                .matches = has_cpuid_feature,
        },
        {
@@ -2364,9 +2450,9 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .type = ARM64_CPUCAP_SYSTEM_FEATURE,
                .sys_reg = SYS_ID_AA64ISAR2_EL1,
                .sign = FTR_UNSIGNED,
-               .field_pos = ID_AA64ISAR2_GPA3_SHIFT,
+               .field_pos = ID_AA64ISAR2_EL1_GPA3_SHIFT,
                .field_width = 4,
-               .min_field_value = ID_AA64ISAR2_GPA3_ARCHITECTED,
+               .min_field_value = ID_AA64ISAR2_EL1_GPA3_IMP,
                .matches = has_cpuid_feature,
        },
        {
@@ -2375,9 +2461,9 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .type = ARM64_CPUCAP_SYSTEM_FEATURE,
                .sys_reg = SYS_ID_AA64ISAR1_EL1,
                .sign = FTR_UNSIGNED,
-               .field_pos = ID_AA64ISAR1_GPI_SHIFT,
+               .field_pos = ID_AA64ISAR1_EL1_GPI_SHIFT,
                .field_width = 4,
-               .min_field_value = ID_AA64ISAR1_GPI_IMP_DEF,
+               .min_field_value = ID_AA64ISAR1_EL1_GPI_IMP,
                .matches = has_cpuid_feature,
        },
        {
@@ -2416,7 +2502,6 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .cpu_enable = cpu_enable_e0pd,
        },
 #endif
-#ifdef CONFIG_ARCH_RANDOM
        {
                .desc = "Random Number Generator",
                .capability = ARM64_HAS_RNG,
@@ -2428,7 +2513,6 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .sign = FTR_UNSIGNED,
                .min_field_value = 1,
        },
-#endif
 #ifdef CONFIG_ARM64_BTI
        {
                .desc = "Branch Target Identification",
@@ -2478,7 +2562,7 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .type = ARM64_CPUCAP_SYSTEM_FEATURE,
                .sys_reg = SYS_ID_AA64ISAR1_EL1,
                .sign = FTR_UNSIGNED,
-               .field_pos = ID_AA64ISAR1_LRCPC_SHIFT,
+               .field_pos = ID_AA64ISAR1_EL1_LRCPC_SHIFT,
                .field_width = 4,
                .matches = has_cpuid_feature,
                .min_field_value = 1,
@@ -2503,9 +2587,9 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .capability = ARM64_SME_FA64,
                .sys_reg = SYS_ID_AA64SMFR0_EL1,
                .sign = FTR_UNSIGNED,
-               .field_pos = ID_AA64SMFR0_FA64_SHIFT,
+               .field_pos = ID_AA64SMFR0_EL1_FA64_SHIFT,
                .field_width = 1,
-               .min_field_value = ID_AA64SMFR0_FA64,
+               .min_field_value = ID_AA64SMFR0_EL1_FA64_IMP,
                .matches = has_cpuid_feature,
                .cpu_enable = fa64_kernel_enable,
        },
@@ -2516,10 +2600,22 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .type = ARM64_CPUCAP_SYSTEM_FEATURE,
                .sys_reg = SYS_ID_AA64ISAR2_EL1,
                .sign = FTR_UNSIGNED,
-               .field_pos = ID_AA64ISAR2_WFXT_SHIFT,
+               .field_pos = ID_AA64ISAR2_EL1_WFxT_SHIFT,
+               .field_width = 4,
+               .matches = has_cpuid_feature,
+               .min_field_value = ID_AA64ISAR2_EL1_WFxT_IMP,
+       },
+       {
+               .desc = "Trap EL0 IMPLEMENTATION DEFINED functionality",
+               .capability = ARM64_HAS_TIDCP1,
+               .type = ARM64_CPUCAP_SYSTEM_FEATURE,
+               .sys_reg = SYS_ID_AA64MMFR1_EL1,
+               .sign = FTR_UNSIGNED,
+               .field_pos = ID_AA64MMFR1_TIDCP1_SHIFT,
                .field_width = 4,
+               .min_field_value = ID_AA64MMFR1_TIDCP1_IMP,
                .matches = has_cpuid_feature,
-               .min_field_value = ID_AA64ISAR2_WFXT_SUPPORTED,
+               .cpu_enable = cpu_trap_el0_impdef,
        },
        {},
 };
@@ -2560,33 +2656,33 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
 #ifdef CONFIG_ARM64_PTR_AUTH
 static const struct arm64_cpu_capabilities ptr_auth_hwcap_addr_matches[] = {
        {
-               HWCAP_CPUID_MATCH(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_APA_SHIFT,
+               HWCAP_CPUID_MATCH(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_EL1_APA_SHIFT,
                                  4, FTR_UNSIGNED,
-                                 ID_AA64ISAR1_APA_ARCHITECTED)
+                                 ID_AA64ISAR1_EL1_APA_PAuth)
        },
        {
-               HWCAP_CPUID_MATCH(SYS_ID_AA64ISAR2_EL1, ID_AA64ISAR2_APA3_SHIFT,
-                                 4, FTR_UNSIGNED, ID_AA64ISAR2_APA3_ARCHITECTED)
+               HWCAP_CPUID_MATCH(SYS_ID_AA64ISAR2_EL1, ID_AA64ISAR2_EL1_APA3_SHIFT,
+                                 4, FTR_UNSIGNED, ID_AA64ISAR2_EL1_APA3_PAuth)
        },
        {
-               HWCAP_CPUID_MATCH(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_API_SHIFT,
-                                 4, FTR_UNSIGNED, ID_AA64ISAR1_API_IMP_DEF)
+               HWCAP_CPUID_MATCH(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_EL1_API_SHIFT,
+                                 4, FTR_UNSIGNED, ID_AA64ISAR1_EL1_API_PAuth)
        },
        {},
 };
 
 static const struct arm64_cpu_capabilities ptr_auth_hwcap_gen_matches[] = {
        {
-               HWCAP_CPUID_MATCH(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_GPA_SHIFT,
-                                 4, FTR_UNSIGNED, ID_AA64ISAR1_GPA_ARCHITECTED)
+               HWCAP_CPUID_MATCH(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_EL1_GPA_SHIFT,
+                                 4, FTR_UNSIGNED, ID_AA64ISAR1_EL1_GPA_IMP)
        },
        {
-               HWCAP_CPUID_MATCH(SYS_ID_AA64ISAR2_EL1, ID_AA64ISAR2_GPA3_SHIFT,
-                                 4, FTR_UNSIGNED, ID_AA64ISAR2_GPA3_ARCHITECTED)
+               HWCAP_CPUID_MATCH(SYS_ID_AA64ISAR2_EL1, ID_AA64ISAR2_EL1_GPA3_SHIFT,
+                                 4, FTR_UNSIGNED, ID_AA64ISAR2_EL1_GPA3_IMP)
        },
        {
-               HWCAP_CPUID_MATCH(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_GPI_SHIFT,
-                                 4, FTR_UNSIGNED, ID_AA64ISAR1_GPI_IMP_DEF)
+               HWCAP_CPUID_MATCH(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_EL1_GPI_SHIFT,
+                                 4, FTR_UNSIGNED, ID_AA64ISAR1_EL1_GPI_IMP)
        },
        {},
 };
@@ -2614,30 +2710,31 @@ static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = {
        HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, 4, FTR_SIGNED, 0, CAP_HWCAP, KERNEL_HWCAP_ASIMD),
        HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, 4, FTR_SIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_ASIMDHP),
        HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_DIT_SHIFT, 4, FTR_SIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_DIT),
-       HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_DPB_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_DCPOP),
-       HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_DPB_SHIFT, 4, FTR_UNSIGNED, 2, CAP_HWCAP, KERNEL_HWCAP_DCPODP),
-       HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_JSCVT_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_JSCVT),
-       HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_FCMA_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_FCMA),
-       HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_LRCPC_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_LRCPC),
-       HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_LRCPC_SHIFT, 4, FTR_UNSIGNED, 2, CAP_HWCAP, KERNEL_HWCAP_ILRCPC),
-       HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_FRINTTS_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_FRINT),
-       HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_SB_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_SB),
-       HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_BF16_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_BF16),
-       HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_DGH_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_DGH),
-       HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_I8MM_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_I8MM),
+       HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_EL1_DPB_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_DCPOP),
+       HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_EL1_DPB_SHIFT, 4, FTR_UNSIGNED, 2, CAP_HWCAP, KERNEL_HWCAP_DCPODP),
+       HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_EL1_JSCVT_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_JSCVT),
+       HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_EL1_FCMA_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_FCMA),
+       HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_EL1_LRCPC_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_LRCPC),
+       HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_EL1_LRCPC_SHIFT, 4, FTR_UNSIGNED, 2, CAP_HWCAP, KERNEL_HWCAP_ILRCPC),
+       HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_EL1_FRINTTS_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_FRINT),
+       HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_EL1_SB_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_SB),
+       HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_EL1_BF16_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_BF16),
+       HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_EL1_BF16_SHIFT, 4, FTR_UNSIGNED, 2, CAP_HWCAP, KERNEL_HWCAP_EBF16),
+       HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_EL1_DGH_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_DGH),
+       HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_EL1_I8MM_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_I8MM),
        HWCAP_CAP(SYS_ID_AA64MMFR2_EL1, ID_AA64MMFR2_AT_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_USCAT),
 #ifdef CONFIG_ARM64_SVE
        HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_SVE_SHIFT, 4, FTR_UNSIGNED, ID_AA64PFR0_SVE, CAP_HWCAP, KERNEL_HWCAP_SVE),
-       HWCAP_CAP(SYS_ID_AA64ZFR0_EL1, ID_AA64ZFR0_SVEVER_SHIFT, 4, FTR_UNSIGNED, ID_AA64ZFR0_SVEVER_SVE2, CAP_HWCAP, KERNEL_HWCAP_SVE2),
-       HWCAP_CAP(SYS_ID_AA64ZFR0_EL1, ID_AA64ZFR0_AES_SHIFT, 4, FTR_UNSIGNED, ID_AA64ZFR0_AES, CAP_HWCAP, KERNEL_HWCAP_SVEAES),
-       HWCAP_CAP(SYS_ID_AA64ZFR0_EL1, ID_AA64ZFR0_AES_SHIFT, 4, FTR_UNSIGNED, ID_AA64ZFR0_AES_PMULL, CAP_HWCAP, KERNEL_HWCAP_SVEPMULL),
-       HWCAP_CAP(SYS_ID_AA64ZFR0_EL1, ID_AA64ZFR0_BITPERM_SHIFT, 4, FTR_UNSIGNED, ID_AA64ZFR0_BITPERM, CAP_HWCAP, KERNEL_HWCAP_SVEBITPERM),
-       HWCAP_CAP(SYS_ID_AA64ZFR0_EL1, ID_AA64ZFR0_BF16_SHIFT, 4, FTR_UNSIGNED, ID_AA64ZFR0_BF16, CAP_HWCAP, KERNEL_HWCAP_SVEBF16),
-       HWCAP_CAP(SYS_ID_AA64ZFR0_EL1, ID_AA64ZFR0_SHA3_SHIFT, 4, FTR_UNSIGNED, ID_AA64ZFR0_SHA3, CAP_HWCAP, KERNEL_HWCAP_SVESHA3),
-       HWCAP_CAP(SYS_ID_AA64ZFR0_EL1, ID_AA64ZFR0_SM4_SHIFT, 4, FTR_UNSIGNED, ID_AA64ZFR0_SM4, CAP_HWCAP, KERNEL_HWCAP_SVESM4),
-       HWCAP_CAP(SYS_ID_AA64ZFR0_EL1, ID_AA64ZFR0_I8MM_SHIFT, 4, FTR_UNSIGNED, ID_AA64ZFR0_I8MM, CAP_HWCAP, KERNEL_HWCAP_SVEI8MM),
-       HWCAP_CAP(SYS_ID_AA64ZFR0_EL1, ID_AA64ZFR0_F32MM_SHIFT, 4, FTR_UNSIGNED, ID_AA64ZFR0_F32MM, CAP_HWCAP, KERNEL_HWCAP_SVEF32MM),
-       HWCAP_CAP(SYS_ID_AA64ZFR0_EL1, ID_AA64ZFR0_F64MM_SHIFT, 4, FTR_UNSIGNED, ID_AA64ZFR0_F64MM, CAP_HWCAP, KERNEL_HWCAP_SVEF64MM),
+       HWCAP_CAP(SYS_ID_AA64ZFR0_EL1, ID_AA64ZFR0_EL1_SVEver_SHIFT, 4, FTR_UNSIGNED, ID_AA64ZFR0_EL1_SVEver_SVE2, CAP_HWCAP, KERNEL_HWCAP_SVE2),
+       HWCAP_CAP(SYS_ID_AA64ZFR0_EL1, ID_AA64ZFR0_EL1_AES_SHIFT, 4, FTR_UNSIGNED, ID_AA64ZFR0_EL1_AES_IMP, CAP_HWCAP, KERNEL_HWCAP_SVEAES),
+       HWCAP_CAP(SYS_ID_AA64ZFR0_EL1, ID_AA64ZFR0_EL1_AES_SHIFT, 4, FTR_UNSIGNED, ID_AA64ZFR0_EL1_AES_PMULL128, CAP_HWCAP, KERNEL_HWCAP_SVEPMULL),
+       HWCAP_CAP(SYS_ID_AA64ZFR0_EL1, ID_AA64ZFR0_EL1_BitPerm_SHIFT, 4, FTR_UNSIGNED, ID_AA64ZFR0_EL1_BitPerm_IMP, CAP_HWCAP, KERNEL_HWCAP_SVEBITPERM),
+       HWCAP_CAP(SYS_ID_AA64ZFR0_EL1, ID_AA64ZFR0_EL1_BF16_SHIFT, 4, FTR_UNSIGNED, ID_AA64ZFR0_EL1_BF16_IMP, CAP_HWCAP, KERNEL_HWCAP_SVEBF16),
+       HWCAP_CAP(SYS_ID_AA64ZFR0_EL1, ID_AA64ZFR0_EL1_SHA3_SHIFT, 4, FTR_UNSIGNED, ID_AA64ZFR0_EL1_SHA3_IMP, CAP_HWCAP, KERNEL_HWCAP_SVESHA3),
+       HWCAP_CAP(SYS_ID_AA64ZFR0_EL1, ID_AA64ZFR0_EL1_SM4_SHIFT, 4, FTR_UNSIGNED, ID_AA64ZFR0_EL1_SM4_IMP, CAP_HWCAP, KERNEL_HWCAP_SVESM4),
+       HWCAP_CAP(SYS_ID_AA64ZFR0_EL1, ID_AA64ZFR0_EL1_I8MM_SHIFT, 4, FTR_UNSIGNED, ID_AA64ZFR0_EL1_I8MM_IMP, CAP_HWCAP, KERNEL_HWCAP_SVEI8MM),
+       HWCAP_CAP(SYS_ID_AA64ZFR0_EL1, ID_AA64ZFR0_EL1_F32MM_SHIFT, 4, FTR_UNSIGNED, ID_AA64ZFR0_EL1_F32MM_IMP, CAP_HWCAP, KERNEL_HWCAP_SVEF32MM),
+       HWCAP_CAP(SYS_ID_AA64ZFR0_EL1, ID_AA64ZFR0_EL1_F64MM_SHIFT, 4, FTR_UNSIGNED, ID_AA64ZFR0_EL1_F64MM_IMP, CAP_HWCAP, KERNEL_HWCAP_SVEF64MM),
 #endif
        HWCAP_CAP(SYS_ID_AA64PFR1_EL1, ID_AA64PFR1_SSBS_SHIFT, 4, FTR_UNSIGNED, ID_AA64PFR1_SSBS_PSTATE_INSNS, CAP_HWCAP, KERNEL_HWCAP_SSBS),
 #ifdef CONFIG_ARM64_BTI
@@ -2653,17 +2750,17 @@ static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = {
 #endif /* CONFIG_ARM64_MTE */
        HWCAP_CAP(SYS_ID_AA64MMFR0_EL1, ID_AA64MMFR0_ECV_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_ECV),
        HWCAP_CAP(SYS_ID_AA64MMFR1_EL1, ID_AA64MMFR1_AFP_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_AFP),
-       HWCAP_CAP(SYS_ID_AA64ISAR2_EL1, ID_AA64ISAR2_RPRES_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_RPRES),
-       HWCAP_CAP(SYS_ID_AA64ISAR2_EL1, ID_AA64ISAR2_WFXT_SHIFT, 4, FTR_UNSIGNED, ID_AA64ISAR2_WFXT_SUPPORTED, CAP_HWCAP, KERNEL_HWCAP_WFXT),
+       HWCAP_CAP(SYS_ID_AA64ISAR2_EL1, ID_AA64ISAR2_EL1_RPRES_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_RPRES),
+       HWCAP_CAP(SYS_ID_AA64ISAR2_EL1, ID_AA64ISAR2_EL1_WFxT_SHIFT, 4, FTR_UNSIGNED, ID_AA64ISAR2_EL1_WFxT_IMP, CAP_HWCAP, KERNEL_HWCAP_WFXT),
 #ifdef CONFIG_ARM64_SME
        HWCAP_CAP(SYS_ID_AA64PFR1_EL1, ID_AA64PFR1_SME_SHIFT, 4, FTR_UNSIGNED, ID_AA64PFR1_SME, CAP_HWCAP, KERNEL_HWCAP_SME),
-       HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_FA64_SHIFT, 1, FTR_UNSIGNED, ID_AA64SMFR0_FA64, CAP_HWCAP, KERNEL_HWCAP_SME_FA64),
-       HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_I16I64_SHIFT, 4, FTR_UNSIGNED, ID_AA64SMFR0_I16I64, CAP_HWCAP, KERNEL_HWCAP_SME_I16I64),
-       HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_F64F64_SHIFT, 1, FTR_UNSIGNED, ID_AA64SMFR0_F64F64, CAP_HWCAP, KERNEL_HWCAP_SME_F64F64),
-       HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_I8I32_SHIFT, 4, FTR_UNSIGNED, ID_AA64SMFR0_I8I32, CAP_HWCAP, KERNEL_HWCAP_SME_I8I32),
-       HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_F16F32_SHIFT, 1, FTR_UNSIGNED, ID_AA64SMFR0_F16F32, CAP_HWCAP, KERNEL_HWCAP_SME_F16F32),
-       HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_B16F32_SHIFT, 1, FTR_UNSIGNED, ID_AA64SMFR0_B16F32, CAP_HWCAP, KERNEL_HWCAP_SME_B16F32),
-       HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_F32F32_SHIFT, 1, FTR_UNSIGNED, ID_AA64SMFR0_F32F32, CAP_HWCAP, KERNEL_HWCAP_SME_F32F32),
+       HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_EL1_FA64_SHIFT, 1, FTR_UNSIGNED, ID_AA64SMFR0_EL1_FA64_IMP, CAP_HWCAP, KERNEL_HWCAP_SME_FA64),
+       HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_EL1_I16I64_SHIFT, 4, FTR_UNSIGNED, ID_AA64SMFR0_EL1_I16I64_IMP, CAP_HWCAP, KERNEL_HWCAP_SME_I16I64),
+       HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_EL1_F64F64_SHIFT, 1, FTR_UNSIGNED, ID_AA64SMFR0_EL1_F64F64_IMP, CAP_HWCAP, KERNEL_HWCAP_SME_F64F64),
+       HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_EL1_I8I32_SHIFT, 4, FTR_UNSIGNED, ID_AA64SMFR0_EL1_I8I32_IMP, CAP_HWCAP, KERNEL_HWCAP_SME_I8I32),
+       HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_EL1_F16F32_SHIFT, 1, FTR_UNSIGNED, ID_AA64SMFR0_EL1_F16F32_IMP, CAP_HWCAP, KERNEL_HWCAP_SME_F16F32),
+       HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_EL1_B16F32_SHIFT, 1, FTR_UNSIGNED, ID_AA64SMFR0_EL1_B16F32_IMP, CAP_HWCAP, KERNEL_HWCAP_SME_B16F32),
+       HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_EL1_F32F32_SHIFT, 1, FTR_UNSIGNED, ID_AA64SMFR0_EL1_F32F32_IMP, CAP_HWCAP, KERNEL_HWCAP_SME_F32F32),
 #endif /* CONFIG_ARM64_SME */
        {},
 };
@@ -3098,14 +3195,12 @@ static bool __maybe_unused __system_matches_cap(unsigned int n)
 
 void cpu_set_feature(unsigned int num)
 {
-       WARN_ON(num >= MAX_CPU_FEATURES);
-       elf_hwcap |= BIT(num);
+       set_bit(num, elf_hwcap);
 }
 
 bool cpu_have_feature(unsigned int num)
 {
-       WARN_ON(num >= MAX_CPU_FEATURES);
-       return elf_hwcap & BIT(num);
+       return test_bit(num, elf_hwcap);
 }
 EXPORT_SYMBOL_GPL(cpu_have_feature);
 
@@ -3116,12 +3211,12 @@ unsigned long cpu_get_elf_hwcap(void)
         * note that for userspace compatibility we guarantee that bits 62
         * and 63 will always be returned as 0.
         */
-       return lower_32_bits(elf_hwcap);
+       return elf_hwcap[0];
 }
 
 unsigned long cpu_get_elf_hwcap2(void)
 {
-       return upper_32_bits(elf_hwcap);
+       return elf_hwcap[1];
 }
 
 static void __init setup_system_capabilities(void)
@@ -3143,8 +3238,10 @@ void __init setup_cpu_features(void)
        setup_system_capabilities();
        setup_elf_hwcaps(arm64_elf_hwcaps);
 
-       if (system_supports_32bit_el0())
+       if (system_supports_32bit_el0()) {
                setup_elf_hwcaps(compat_elf_hwcaps);
+               elf_hwcap_fixup();
+       }
 
        if (system_uses_ttbr0_pan())
                pr_info("emulated: Privileged Access Never (PAN) using TTBR0_EL1 switching\n");
@@ -3197,6 +3294,7 @@ static int enable_mismatched_32bit_el0(unsigned int cpu)
                                                         cpu_active_mask);
        get_cpu_device(lucky_winner)->offline_disabled = true;
        setup_elf_hwcaps(compat_elf_hwcaps);
+       elf_hwcap_fixup();
        pr_info("Asymmetric 32-bit EL0 support detected on CPU %u; CPU hot-unplug disabled on CPU %u\n",
                cpu, lucky_winner);
        return 0;
@@ -3218,7 +3316,7 @@ subsys_initcall_sync(init_32bit_el0_mask);
 
 static void __maybe_unused cpu_enable_cnp(struct arm64_cpu_capabilities const *cap)
 {
-       cpu_replace_ttbr1(lm_alias(swapper_pg_dir));
+       cpu_replace_ttbr1(lm_alias(swapper_pg_dir), idmap_pg_dir);
 }
 
 /*
index 3006f43..4150e30 100644 (file)
 #include <linux/of_device.h>
 #include <linux/psci.h>
 
-#include <asm/cpuidle.h>
-#include <asm/cpu_ops.h>
-
-int arm_cpuidle_init(unsigned int cpu)
-{
-       const struct cpu_operations *ops = get_cpu_ops(cpu);
-       int ret = -EOPNOTSUPP;
-
-       if (ops && ops->cpu_suspend && ops->cpu_init_idle)
-               ret = ops->cpu_init_idle(cpu);
-
-       return ret;
-}
-
-/**
- * arm_cpuidle_suspend() - function to enter a low-power idle state
- * @index: argument to pass to CPU suspend operations
- *
- * Return: 0 on success, -EOPNOTSUPP if CPU suspend hook not initialized, CPU
- * operations back-end error code otherwise.
- */
-int arm_cpuidle_suspend(int index)
-{
-       int cpu = smp_processor_id();
-       const struct cpu_operations *ops = get_cpu_ops(cpu);
-
-       return ops->cpu_suspend(index);
-}
-
 #ifdef CONFIG_ACPI
 
 #include <acpi/processor.h>
index 8eff0a3..d7702f3 100644 (file)
 DEFINE_PER_CPU(struct cpuinfo_arm64, cpu_data);
 static struct cpuinfo_arm64 boot_cpu_data;
 
-static const char *icache_policy_str[] = {
-       [ICACHE_POLICY_VPIPT]           = "VPIPT",
-       [ICACHE_POLICY_RESERVED]        = "RESERVED/UNKNOWN",
-       [ICACHE_POLICY_VIPT]            = "VIPT",
-       [ICACHE_POLICY_PIPT]            = "PIPT",
-};
+static inline const char *icache_policy_str(int l1ip)
+{
+       switch (l1ip) {
+       case CTR_EL0_L1Ip_VPIPT:
+               return "VPIPT";
+       case CTR_EL0_L1Ip_VIPT:
+               return "VIPT";
+       case CTR_EL0_L1Ip_PIPT:
+               return "PIPT";
+       default:
+               return "RESERVED/UNKNOWN";
+       }
+}
 
 unsigned long __icache_flags;
 
@@ -107,6 +114,7 @@ static const char *const hwcap_str[] = {
        [KERNEL_HWCAP_SME_F32F32]       = "smef32f32",
        [KERNEL_HWCAP_SME_FA64]         = "smefa64",
        [KERNEL_HWCAP_WFXT]             = "wfxt",
+       [KERNEL_HWCAP_EBF16]            = "ebf16",
 };
 
 #ifdef CONFIG_COMPAT
@@ -267,6 +275,7 @@ static struct kobj_type cpuregs_kobj_type = {
 
 CPUREGS_ATTR_RO(midr_el1, midr);
 CPUREGS_ATTR_RO(revidr_el1, revidr);
+CPUREGS_ATTR_RO(smidr_el1, smidr);
 
 static struct attribute *cpuregs_id_attrs[] = {
        &cpuregs_attr_midr_el1.attr,
@@ -279,6 +288,16 @@ static const struct attribute_group cpuregs_attr_group = {
        .name = "identification"
 };
 
+static struct attribute *sme_cpuregs_id_attrs[] = {
+       &cpuregs_attr_smidr_el1.attr,
+       NULL
+};
+
+static const struct attribute_group sme_cpuregs_attr_group = {
+       .attrs = sme_cpuregs_id_attrs,
+       .name = "identification"
+};
+
 static int cpuid_cpu_online(unsigned int cpu)
 {
        int rc;
@@ -296,6 +315,8 @@ static int cpuid_cpu_online(unsigned int cpu)
        rc = sysfs_create_group(&info->kobj, &cpuregs_attr_group);
        if (rc)
                kobject_del(&info->kobj);
+       if (system_supports_sme())
+               rc = sysfs_merge_group(&info->kobj, &sme_cpuregs_attr_group);
 out:
        return rc;
 }
@@ -342,19 +363,19 @@ static void cpuinfo_detect_icache_policy(struct cpuinfo_arm64 *info)
        u32 l1ip = CTR_L1IP(info->reg_ctr);
 
        switch (l1ip) {
-       case ICACHE_POLICY_PIPT:
+       case CTR_EL0_L1Ip_PIPT:
                break;
-       case ICACHE_POLICY_VPIPT:
+       case CTR_EL0_L1Ip_VPIPT:
                set_bit(ICACHEF_VPIPT, &__icache_flags);
                break;
-       case ICACHE_POLICY_RESERVED:
-       case ICACHE_POLICY_VIPT:
+       case CTR_EL0_L1Ip_VIPT:
+       default:
                /* Assume aliasing */
                set_bit(ICACHEF_ALIASING, &__icache_flags);
                break;
        }
 
-       pr_info("Detected %s I-cache on CPU%d\n", icache_policy_str[l1ip], cpu);
+       pr_info("Detected %s I-cache on CPU%d\n", icache_policy_str(l1ip), cpu);
 }
 
 static void __cpuinfo_store_cpu_32bit(struct cpuinfo_32bit *info)
@@ -418,14 +439,6 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
        if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0))
                __cpuinfo_store_cpu_32bit(&info->aarch32);
 
-       if (IS_ENABLED(CONFIG_ARM64_SVE) &&
-           id_aa64pfr0_sve(info->reg_id_aa64pfr0))
-               info->reg_zcr = read_zcr_features();
-
-       if (IS_ENABLED(CONFIG_ARM64_SME) &&
-           id_aa64pfr1_sme(info->reg_id_aa64pfr1))
-               info->reg_smcr = read_smcr_features();
-
        cpuinfo_detect_icache_policy(info);
 }
 
index 56cefd3..c75ca36 100644 (file)
@@ -41,7 +41,7 @@ static __always_inline void __enter_from_kernel_mode(struct pt_regs *regs)
 
        if (!IS_ENABLED(CONFIG_TINY_RCU) && is_idle_task(current)) {
                lockdep_hardirqs_off(CALLER_ADDR0);
-               rcu_irq_enter();
+               ct_irq_enter();
                trace_hardirqs_off_finish();
 
                regs->exit_rcu = true;
@@ -76,7 +76,7 @@ static __always_inline void __exit_to_kernel_mode(struct pt_regs *regs)
                if (regs->exit_rcu) {
                        trace_hardirqs_on_prepare();
                        lockdep_hardirqs_on_prepare();
-                       rcu_irq_exit();
+                       ct_irq_exit();
                        lockdep_hardirqs_on(CALLER_ADDR0);
                        return;
                }
@@ -84,7 +84,7 @@ static __always_inline void __exit_to_kernel_mode(struct pt_regs *regs)
                trace_hardirqs_on();
        } else {
                if (regs->exit_rcu)
-                       rcu_irq_exit();
+                       ct_irq_exit();
        }
 }
 
@@ -161,7 +161,7 @@ static void noinstr arm64_enter_nmi(struct pt_regs *regs)
        __nmi_enter();
        lockdep_hardirqs_off(CALLER_ADDR0);
        lockdep_hardirq_enter();
-       rcu_nmi_enter();
+       ct_nmi_enter();
 
        trace_hardirqs_off_finish();
        ftrace_nmi_enter();
@@ -182,7 +182,7 @@ static void noinstr arm64_exit_nmi(struct pt_regs *regs)
                lockdep_hardirqs_on_prepare();
        }
 
-       rcu_nmi_exit();
+       ct_nmi_exit();
        lockdep_hardirq_exit();
        if (restore)
                lockdep_hardirqs_on(CALLER_ADDR0);
@@ -199,7 +199,7 @@ static void noinstr arm64_enter_el1_dbg(struct pt_regs *regs)
        regs->lockdep_hardirqs = lockdep_hardirqs_enabled();
 
        lockdep_hardirqs_off(CALLER_ADDR0);
-       rcu_nmi_enter();
+       ct_nmi_enter();
 
        trace_hardirqs_off_finish();
 }
@@ -218,7 +218,7 @@ static void noinstr arm64_exit_el1_dbg(struct pt_regs *regs)
                lockdep_hardirqs_on_prepare();
        }
 
-       rcu_nmi_exit();
+       ct_nmi_exit();
        if (restore)
                lockdep_hardirqs_on(CALLER_ADDR0);
 }
index 5b82b92..254fe31 100644 (file)
@@ -636,18 +636,28 @@ alternative_else_nop_endif
         */
        .endm
 
-       .macro tramp_data_page  dst
-       adr_l   \dst, .entry.tramp.text
-       sub     \dst, \dst, PAGE_SIZE
-       .endm
-
-       .macro tramp_data_read_var      dst, var
-#ifdef CONFIG_RANDOMIZE_BASE
-       tramp_data_page         \dst
-       add     \dst, \dst, #:lo12:__entry_tramp_data_\var
-       ldr     \dst, [\dst]
+       .macro          tramp_data_read_var     dst, var
+#ifdef CONFIG_RELOCATABLE
+       ldr             \dst, .L__tramp_data_\var
+       .ifndef         .L__tramp_data_\var
+       .pushsection    ".entry.tramp.rodata", "a", %progbits
+       .align          3
+.L__tramp_data_\var:
+       .quad           \var
+       .popsection
+       .endif
 #else
-       ldr     \dst, =\var
+       /*
+        * As !RELOCATABLE implies !RANDOMIZE_BASE the address is always a
+        * compile time constant (and hence not secret and not worth hiding).
+        *
+        * As statically allocated kernel code and data always live in the top
+        * 47 bits of the address space we can sign-extend bit 47 and avoid an
+        * instruction to load the upper 16 bits (which must be 0xFFFF).
+        */
+       movz            \dst, :abs_g2_s:\var
+       movk            \dst, :abs_g1_nc:\var
+       movk            \dst, :abs_g0_nc:\var
 #endif
        .endm
 
@@ -695,7 +705,7 @@ alternative_else_nop_endif
        msr     vbar_el1, x30
        isb
        .else
-       ldr     x30, =vectors
+       adr_l   x30, vectors
        .endif // \kpti == 1
 
        .if     \bhb == BHB_MITIGATION_FW
@@ -764,24 +774,7 @@ SYM_CODE_END(tramp_exit_native)
 SYM_CODE_START(tramp_exit_compat)
        tramp_exit      32
 SYM_CODE_END(tramp_exit_compat)
-
-       .ltorg
        .popsection                             // .entry.tramp.text
-#ifdef CONFIG_RANDOMIZE_BASE
-       .pushsection ".rodata", "a"
-       .align PAGE_SHIFT
-SYM_DATA_START(__entry_tramp_data_start)
-__entry_tramp_data_vectors:
-       .quad   vectors
-#ifdef CONFIG_ARM_SDE_INTERFACE
-__entry_tramp_data___sdei_asm_handler:
-       .quad   __sdei_asm_handler
-#endif /* CONFIG_ARM_SDE_INTERFACE */
-__entry_tramp_data_this_cpu_vector:
-       .quad   this_cpu_vector
-SYM_DATA_END(__entry_tramp_data_start)
-       .popsection                             // .rodata
-#endif /* CONFIG_RANDOMIZE_BASE */
 #endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
 
 /*
@@ -932,7 +925,6 @@ NOKPROBE(call_on_irq_stack)
  * This clobbers x4, __sdei_handler() will restore this from firmware's
  * copy.
  */
-.ltorg
 .pushsection ".entry.tramp.text", "ax"
 SYM_CODE_START(__sdei_asm_entry_trampoline)
        mrs     x4, ttbr1_el1
@@ -967,7 +959,6 @@ SYM_CODE_START(__sdei_asm_exit_trampoline)
 1:     sdei_handler_exit exit_mode=x2
 SYM_CODE_END(__sdei_asm_exit_trampoline)
 NOKPROBE(__sdei_asm_exit_trampoline)
-       .ltorg
 .popsection            // .entry.tramp.text
 #endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
 
index aecf307..dd63ffc 100644 (file)
@@ -445,7 +445,6 @@ static void fpsimd_save(void)
 
        if (system_supports_sme()) {
                u64 *svcr = last->svcr;
-               *svcr = read_sysreg_s(SYS_SVCR);
 
                *svcr = read_sysreg_s(SYS_SVCR);
 
index 6a98f1a..cefe6a7 100644 (file)
@@ -37,8 +37,6 @@
 
 #include "efi-header.S"
 
-#define __PHYS_OFFSET  KERNEL_START
-
 #if (PAGE_OFFSET & 0x1fffff) != 0
 #error PAGE_OFFSET must be at least 2MB aligned
 #endif
@@ -51,9 +49,6 @@
  *   MMU = off, D-cache = off, I-cache = on or off,
  *   x0 = physical address to the FDT blob.
  *
- * This code is mostly position independent so you call this at
- * __pa(PAGE_OFFSET).
- *
  * Note that the callee-saved registers are used for storing variables
  * that are useful before the MMU is enabled. The allocations are described
  * in the entry routines.
         * primary lowlevel boot path:
         *
         *  Register   Scope                      Purpose
+        *  x20        primary_entry() .. __primary_switch()    CPU boot mode
         *  x21        primary_entry() .. start_kernel()        FDT pointer passed at boot in x0
+        *  x22        create_idmap() .. start_kernel()         ID map VA of the DT blob
         *  x23        primary_entry() .. start_kernel()        physical misalignment/KASLR offset
-        *  x28        __create_page_tables()                   callee preserved temp register
-        *  x19/x20    __primary_switch()                       callee preserved temp registers
-        *  x24        __primary_switch() .. relocate_kernel()  current RELR displacement
+        *  x24        __primary_switch()                       linear map KASLR seed
+        *  x25        primary_entry() .. start_kernel()        supported VA size
+        *  x28        create_idmap()                           callee preserved temp register
         */
 SYM_CODE_START(primary_entry)
        bl      preserve_boot_args
        bl      init_kernel_el                  // w0=cpu_boot_mode
-       adrp    x23, __PHYS_OFFSET
-       and     x23, x23, MIN_KIMG_ALIGN - 1    // KASLR offset, defaults to 0
-       bl      set_cpu_boot_mode_flag
-       bl      __create_page_tables
+       mov     x20, x0
+       bl      create_idmap
+
        /*
         * The following calls CPU setup code, see arch/arm64/mm/proc.S for
         * details.
         * On return, the CPU will be ready for the MMU to be turned on and
         * the TCR will have been set.
         */
+#if VA_BITS > 48
+       mrs_s   x0, SYS_ID_AA64MMFR2_EL1
+       tst     x0, #0xf << ID_AA64MMFR2_LVA_SHIFT
+       mov     x0, #VA_BITS
+       mov     x25, #VA_BITS_MIN
+       csel    x25, x25, x0, eq
+       mov     x0, x25
+#endif
        bl      __cpu_setup                     // initialise processor
        b       __primary_switch
 SYM_CODE_END(primary_entry)
@@ -122,28 +126,16 @@ SYM_CODE_START_LOCAL(preserve_boot_args)
        b       dcache_inval_poc                // tail call
 SYM_CODE_END(preserve_boot_args)
 
-/*
- * Macro to create a table entry to the next page.
- *
- *     tbl:    page table address
- *     virt:   virtual address
- *     shift:  #imm page table shift
- *     ptrs:   #imm pointers per table page
- *
- * Preserves:  virt
- * Corrupts:   ptrs, tmp1, tmp2
- * Returns:    tbl -> next level table page address
- */
-       .macro  create_table_entry, tbl, virt, shift, ptrs, tmp1, tmp2
-       add     \tmp1, \tbl, #PAGE_SIZE
-       phys_to_pte \tmp2, \tmp1
-       orr     \tmp2, \tmp2, #PMD_TYPE_TABLE   // address of next table and entry type
-       lsr     \tmp1, \virt, #\shift
-       sub     \ptrs, \ptrs, #1
-       and     \tmp1, \tmp1, \ptrs             // table index
-       str     \tmp2, [\tbl, \tmp1, lsl #3]
-       add     \tbl, \tbl, #PAGE_SIZE          // next level table page
-       .endm
+SYM_FUNC_START_LOCAL(clear_page_tables)
+       /*
+        * Clear the init page tables.
+        */
+       adrp    x0, init_pg_dir
+       adrp    x1, init_pg_end
+       sub     x2, x1, x0
+       mov     x1, xzr
+       b       __pi_memset                     // tail call
+SYM_FUNC_END(clear_page_tables)
 
 /*
  * Macro to populate page table entries, these entries can be pointers to the next level
@@ -179,31 +171,20 @@ SYM_CODE_END(preserve_boot_args)
  *     vstart: virtual address of start of range
  *     vend:   virtual address of end of range - we map [vstart, vend]
  *     shift:  shift used to transform virtual address into index
- *     ptrs:   number of entries in page table
+ *     order:  #imm 2log(number of entries in page table)
  *     istart: index in table corresponding to vstart
  *     iend:   index in table corresponding to vend
  *     count:  On entry: how many extra entries were required in previous level, scales
  *                       our end index.
  *             On exit: returns how many extra entries required for next page table level
  *
- * Preserves:  vstart, vend, shift, ptrs
+ * Preserves:  vstart, vend
  * Returns:    istart, iend, count
  */
-       .macro compute_indices, vstart, vend, shift, ptrs, istart, iend, count
-       lsr     \iend, \vend, \shift
-       mov     \istart, \ptrs
-       sub     \istart, \istart, #1
-       and     \iend, \iend, \istart   // iend = (vend >> shift) & (ptrs - 1)
-       mov     \istart, \ptrs
-       mul     \istart, \istart, \count
-       add     \iend, \iend, \istart   // iend += count * ptrs
-                                       // our entries span multiple tables
-
-       lsr     \istart, \vstart, \shift
-       mov     \count, \ptrs
-       sub     \count, \count, #1
-       and     \istart, \istart, \count
-
+       .macro compute_indices, vstart, vend, shift, order, istart, iend, count
+       ubfx    \istart, \vstart, \shift, \order
+       ubfx    \iend, \vend, \shift, \order
+       add     \iend, \iend, \count, lsl \order
        sub     \count, \iend, \istart
        .endm
 
@@ -218,119 +199,116 @@ SYM_CODE_END(preserve_boot_args)
  *     vend:   virtual address of end of range - we map [vstart, vend - 1]
  *     flags:  flags to use to map last level entries
  *     phys:   physical address corresponding to vstart - physical memory is contiguous
- *     pgds:   the number of pgd entries
+ *     order:  #imm 2log(number of entries in PGD table)
+ *
+ * If extra_shift is set, an extra level will be populated if the end address does
+ * not fit in 'extra_shift' bits. This assumes vend is in the TTBR0 range.
  *
  * Temporaries:        istart, iend, tmp, count, sv - these need to be different registers
  * Preserves:  vstart, flags
  * Corrupts:   tbl, rtbl, vend, istart, iend, tmp, count, sv
  */
-       .macro map_memory, tbl, rtbl, vstart, vend, flags, phys, pgds, istart, iend, tmp, count, sv
+       .macro map_memory, tbl, rtbl, vstart, vend, flags, phys, order, istart, iend, tmp, count, sv, extra_shift
        sub \vend, \vend, #1
        add \rtbl, \tbl, #PAGE_SIZE
-       mov \sv, \rtbl
        mov \count, #0
-       compute_indices \vstart, \vend, #PGDIR_SHIFT, \pgds, \istart, \iend, \count
+
+       .ifnb   \extra_shift
+       tst     \vend, #~((1 << (\extra_shift)) - 1)
+       b.eq    .L_\@
+       compute_indices \vstart, \vend, #\extra_shift, #(PAGE_SHIFT - 3), \istart, \iend, \count
+       mov \sv, \rtbl
        populate_entries \tbl, \rtbl, \istart, \iend, #PMD_TYPE_TABLE, #PAGE_SIZE, \tmp
        mov \tbl, \sv
+       .endif
+.L_\@:
+       compute_indices \vstart, \vend, #PGDIR_SHIFT, #\order, \istart, \iend, \count
        mov \sv, \rtbl
+       populate_entries \tbl, \rtbl, \istart, \iend, #PMD_TYPE_TABLE, #PAGE_SIZE, \tmp
+       mov \tbl, \sv
 
 #if SWAPPER_PGTABLE_LEVELS > 3
-       compute_indices \vstart, \vend, #PUD_SHIFT, #PTRS_PER_PUD, \istart, \iend, \count
+       compute_indices \vstart, \vend, #PUD_SHIFT, #(PAGE_SHIFT - 3), \istart, \iend, \count
+       mov \sv, \rtbl
        populate_entries \tbl, \rtbl, \istart, \iend, #PMD_TYPE_TABLE, #PAGE_SIZE, \tmp
        mov \tbl, \sv
-       mov \sv, \rtbl
 #endif
 
 #if SWAPPER_PGTABLE_LEVELS > 2
-       compute_indices \vstart, \vend, #SWAPPER_TABLE_SHIFT, #PTRS_PER_PMD, \istart, \iend, \count
+       compute_indices \vstart, \vend, #SWAPPER_TABLE_SHIFT, #(PAGE_SHIFT - 3), \istart, \iend, \count
+       mov \sv, \rtbl
        populate_entries \tbl, \rtbl, \istart, \iend, #PMD_TYPE_TABLE, #PAGE_SIZE, \tmp
        mov \tbl, \sv
 #endif
 
-       compute_indices \vstart, \vend, #SWAPPER_BLOCK_SHIFT, #PTRS_PER_PTE, \istart, \iend, \count
-       bic \count, \phys, #SWAPPER_BLOCK_SIZE - 1
-       populate_entries \tbl, \count, \istart, \iend, \flags, #SWAPPER_BLOCK_SIZE, \tmp
+       compute_indices \vstart, \vend, #SWAPPER_BLOCK_SHIFT, #(PAGE_SHIFT - 3), \istart, \iend, \count
+       bic \rtbl, \phys, #SWAPPER_BLOCK_SIZE - 1
+       populate_entries \tbl, \rtbl, \istart, \iend, \flags, #SWAPPER_BLOCK_SIZE, \tmp
        .endm
 
 /*
- * Setup the initial page tables. We only setup the barest amount which is
- * required to get the kernel running. The following sections are required:
- *   - identity mapping to enable the MMU (low address, TTBR0)
- *   - first few MB of the kernel linear mapping to jump to once the MMU has
- *     been enabled
+ * Remap a subregion created with the map_memory macro with modified attributes
+ * or output address. The entire remapped region must have been covered in the
+ * invocation of map_memory.
+ *
+ * x0: last level table address (returned in first argument to map_memory)
+ * x1: start VA of the existing mapping
+ * x2: start VA of the region to update
+ * x3: end VA of the region to update (exclusive)
+ * x4: start PA associated with the region to update
+ * x5: attributes to set on the updated region
+ * x6: order of the last level mappings
  */
-SYM_FUNC_START_LOCAL(__create_page_tables)
-       mov     x28, lr
+SYM_FUNC_START_LOCAL(remap_region)
+       sub     x3, x3, #1              // make end inclusive
 
-       /*
-        * Invalidate the init page tables to avoid potential dirty cache lines
-        * being evicted. Other page tables are allocated in rodata as part of
-        * the kernel image, and thus are clean to the PoC per the boot
-        * protocol.
-        */
-       adrp    x0, init_pg_dir
-       adrp    x1, init_pg_end
-       bl      dcache_inval_poc
+       // Get the index offset for the start of the last level table
+       lsr     x1, x1, x6
+       bfi     x1, xzr, #0, #PAGE_SHIFT - 3
 
-       /*
-        * Clear the init page tables.
-        */
-       adrp    x0, init_pg_dir
-       adrp    x1, init_pg_end
-       sub     x1, x1, x0
-1:     stp     xzr, xzr, [x0], #16
-       stp     xzr, xzr, [x0], #16
-       stp     xzr, xzr, [x0], #16
-       stp     xzr, xzr, [x0], #16
-       subs    x1, x1, #64
-       b.ne    1b
+       // Derive the start and end indexes into the last level table
+       // associated with the provided region
+       lsr     x2, x2, x6
+       lsr     x3, x3, x6
+       sub     x2, x2, x1
+       sub     x3, x3, x1
 
-       mov     x7, SWAPPER_MM_MMUFLAGS
+       mov     x1, #1
+       lsl     x6, x1, x6              // block size at this level
 
-       /*
-        * Create the identity mapping.
-        */
-       adrp    x0, idmap_pg_dir
-       adrp    x3, __idmap_text_start          // __pa(__idmap_text_start)
-
-#ifdef CONFIG_ARM64_VA_BITS_52
-       mrs_s   x6, SYS_ID_AA64MMFR2_EL1
-       and     x6, x6, #(0xf << ID_AA64MMFR2_LVA_SHIFT)
-       mov     x5, #52
-       cbnz    x6, 1f
-#endif
-       mov     x5, #VA_BITS_MIN
-1:
-       adr_l   x6, vabits_actual
-       str     x5, [x6]
-       dmb     sy
-       dc      ivac, x6                // Invalidate potentially stale cache line
+       populate_entries x0, x4, x2, x3, x5, x6, x7
+       ret
+SYM_FUNC_END(remap_region)
 
+SYM_FUNC_START_LOCAL(create_idmap)
+       mov     x28, lr
        /*
-        * VA_BITS may be too small to allow for an ID mapping to be created
-        * that covers system RAM if that is located sufficiently high in the
-        * physical address space. So for the ID map, use an extended virtual
-        * range in that case, and configure an additional translation level
-        * if needed.
+        * The ID map carries a 1:1 mapping of the physical address range
+        * covered by the loaded image, which could be anywhere in DRAM. This
+        * means that the required size of the VA (== PA) space is decided at
+        * boot time, and could be more than the configured size of the VA
+        * space for ordinary kernel and user space mappings.
+        *
+        * There are three cases to consider here:
+        * - 39 <= VA_BITS < 48, and the ID map needs up to 48 VA bits to cover
+        *   the placement of the image. In this case, we configure one extra
+        *   level of translation on the fly for the ID map only. (This case
+        *   also covers 42-bit VA/52-bit PA on 64k pages).
         *
-        * Calculate the maximum allowed value for TCR_EL1.T0SZ so that the
-        * entire ID map region can be mapped. As T0SZ == (64 - #bits used),
-        * this number conveniently equals the number of leading zeroes in
-        * the physical address of __idmap_text_end.
+        * - VA_BITS == 48, and the ID map needs more than 48 VA bits. This can
+        *   only happen when using 64k pages, in which case we need to extend
+        *   the root level table rather than add a level. Note that we can
+        *   treat this case as 'always extended' as long as we take care not
+        *   to program an unsupported T0SZ value into the TCR register.
+        *
+        * - Combinations that would require two additional levels of
+        *   translation are not supported, e.g., VA_BITS==36 on 16k pages, or
+        *   VA_BITS==39/4k pages with 5-level paging, where the input address
+        *   requires more than 47 or 48 bits, respectively.
         */
-       adrp    x5, __idmap_text_end
-       clz     x5, x5
-       cmp     x5, TCR_T0SZ(VA_BITS_MIN) // default T0SZ small enough?
-       b.ge    1f                      // .. then skip VA range extension
-
-       adr_l   x6, idmap_t0sz
-       str     x5, [x6]
-       dmb     sy
-       dc      ivac, x6                // Invalidate potentially stale cache line
-
 #if (VA_BITS < 48)
+#define IDMAP_PGD_ORDER        (VA_BITS - PGDIR_SHIFT)
 #define EXTRA_SHIFT    (PGDIR_SHIFT + PAGE_SHIFT - 3)
-#define EXTRA_PTRS     (1 << (PHYS_MASK_SHIFT - EXTRA_SHIFT))
 
        /*
         * If VA_BITS < 48, we have to configure an additional table level.
@@ -342,36 +320,40 @@ SYM_FUNC_START_LOCAL(__create_page_tables)
 #if VA_BITS != EXTRA_SHIFT
 #error "Mismatch between VA_BITS and page size/number of translation levels"
 #endif
-
-       mov     x4, EXTRA_PTRS
-       create_table_entry x0, x3, EXTRA_SHIFT, x4, x5, x6
 #else
+#define IDMAP_PGD_ORDER        (PHYS_MASK_SHIFT - PGDIR_SHIFT)
+#define EXTRA_SHIFT
        /*
         * If VA_BITS == 48, we don't have to configure an additional
         * translation level, but the top-level table has more entries.
         */
-       mov     x4, #1 << (PHYS_MASK_SHIFT - PGDIR_SHIFT)
-       str_l   x4, idmap_ptrs_per_pgd, x5
 #endif
-1:
-       ldr_l   x4, idmap_ptrs_per_pgd
-       adr_l   x6, __idmap_text_end            // __pa(__idmap_text_end)
-
-       map_memory x0, x1, x3, x6, x7, x3, x4, x10, x11, x12, x13, x14
-
-       /*
-        * Map the kernel image (starting with PHYS_OFFSET).
-        */
-       adrp    x0, init_pg_dir
-       mov_q   x5, KIMAGE_VADDR                // compile time __va(_text)
-       add     x5, x5, x23                     // add KASLR displacement
-       mov     x4, PTRS_PER_PGD
-       adrp    x6, _end                        // runtime __pa(_end)
-       adrp    x3, _text                       // runtime __pa(_text)
-       sub     x6, x6, x3                      // _end - _text
-       add     x6, x6, x5                      // runtime __va(_end)
-
-       map_memory x0, x1, x5, x6, x7, x3, x4, x10, x11, x12, x13, x14
+       adrp    x0, init_idmap_pg_dir
+       adrp    x3, _text
+       adrp    x6, _end + MAX_FDT_SIZE + SWAPPER_BLOCK_SIZE
+       mov     x7, SWAPPER_RX_MMUFLAGS
+
+       map_memory x0, x1, x3, x6, x7, x3, IDMAP_PGD_ORDER, x10, x11, x12, x13, x14, EXTRA_SHIFT
+
+       /* Remap the kernel page tables r/w in the ID map */
+       adrp    x1, _text
+       adrp    x2, init_pg_dir
+       adrp    x3, init_pg_end
+       bic     x4, x2, #SWAPPER_BLOCK_SIZE - 1
+       mov     x5, SWAPPER_RW_MMUFLAGS
+       mov     x6, #SWAPPER_BLOCK_SHIFT
+       bl      remap_region
+
+       /* Remap the FDT after the kernel image */
+       adrp    x1, _text
+       adrp    x22, _end + SWAPPER_BLOCK_SIZE
+       bic     x2, x22, #SWAPPER_BLOCK_SIZE - 1
+       bfi     x22, x21, #0, #SWAPPER_BLOCK_SHIFT              // remapped FDT address
+       add     x3, x2, #MAX_FDT_SIZE + SWAPPER_BLOCK_SIZE
+       bic     x4, x21, #SWAPPER_BLOCK_SIZE - 1
+       mov     x5, SWAPPER_RW_MMUFLAGS
+       mov     x6, #SWAPPER_BLOCK_SHIFT
+       bl      remap_region
 
        /*
         * Since the page tables have been populated with non-cacheable
@@ -380,16 +362,27 @@ SYM_FUNC_START_LOCAL(__create_page_tables)
         */
        dmb     sy
 
-       adrp    x0, idmap_pg_dir
-       adrp    x1, idmap_pg_end
+       adrp    x0, init_idmap_pg_dir
+       adrp    x1, init_idmap_pg_end
        bl      dcache_inval_poc
+       ret     x28
+SYM_FUNC_END(create_idmap)
 
+SYM_FUNC_START_LOCAL(create_kernel_mapping)
        adrp    x0, init_pg_dir
-       adrp    x1, init_pg_end
-       bl      dcache_inval_poc
+       mov_q   x5, KIMAGE_VADDR                // compile time __va(_text)
+       add     x5, x5, x23                     // add KASLR displacement
+       adrp    x6, _end                        // runtime __pa(_end)
+       adrp    x3, _text                       // runtime __pa(_text)
+       sub     x6, x6, x3                      // _end - _text
+       add     x6, x6, x5                      // runtime __va(_end)
+       mov     x7, SWAPPER_RW_MMUFLAGS
 
-       ret     x28
-SYM_FUNC_END(__create_page_tables)
+       map_memory x0, x1, x5, x6, x7, x3, (VA_BITS - PGDIR_SHIFT), x10, x11, x12, x13, x14
+
+       dsb     ishst                           // sync with page table walker
+       ret
+SYM_FUNC_END(create_kernel_mapping)
 
        /*
         * Initialize CPU registers with task-specific and cpu-specific context.
@@ -420,7 +413,7 @@ SYM_FUNC_END(__create_page_tables)
 /*
  * The following fragment of code is executed with the MMU enabled.
  *
- *   x0 = __PHYS_OFFSET
+ *   x0 = __pa(KERNEL_START)
  */
 SYM_FUNC_START_LOCAL(__primary_switched)
        adr_l   x4, init_task
@@ -439,6 +432,9 @@ SYM_FUNC_START_LOCAL(__primary_switched)
        sub     x4, x4, x0                      // the kernel virtual and
        str_l   x4, kimage_voffset, x5          // physical mappings
 
+       mov     x0, x20
+       bl      set_cpu_boot_mode_flag
+
        // Clear BSS
        adr_l   x0, __bss_start
        mov     x1, xzr
@@ -447,35 +443,30 @@ SYM_FUNC_START_LOCAL(__primary_switched)
        bl      __pi_memset
        dsb     ishst                           // Make zero page visible to PTW
 
+#if VA_BITS > 48
+       adr_l   x8, vabits_actual               // Set this early so KASAN early init
+       str     x25, [x8]                       // ... observes the correct value
+       dc      civac, x8                       // Make visible to booting secondaries
+#endif
+
+#ifdef CONFIG_RANDOMIZE_BASE
+       adrp    x5, memstart_offset_seed        // Save KASLR linear map seed
+       strh    w24, [x5, :lo12:memstart_offset_seed]
+#endif
 #if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
        bl      kasan_early_init
 #endif
        mov     x0, x21                         // pass FDT address in x0
        bl      early_fdt_map                   // Try mapping the FDT early
+       mov     x0, x20                         // pass the full boot status
        bl      init_feature_override           // Parse cpu feature overrides
-#ifdef CONFIG_RANDOMIZE_BASE
-       tst     x23, ~(MIN_KIMG_ALIGN - 1)      // already running randomized?
-       b.ne    0f
-       bl      kaslr_early_init                // parse FDT for KASLR options
-       cbz     x0, 0f                          // KASLR disabled? just proceed
-       orr     x23, x23, x0                    // record KASLR offset
-       ldp     x29, x30, [sp], #16             // we must enable KASLR, return
-       ret                                     // to __primary_switch()
-0:
-#endif
-       bl      switch_to_vhe                   // Prefer VHE if possible
+       mov     x0, x20
+       bl      finalise_el2                    // Prefer VHE if possible
        ldp     x29, x30, [sp], #16
        bl      start_kernel
        ASM_BUG()
 SYM_FUNC_END(__primary_switched)
 
-       .pushsection ".rodata", "a"
-SYM_DATA_START(kimage_vaddr)
-       .quad           _text
-SYM_DATA_END(kimage_vaddr)
-EXPORT_SYMBOL(kimage_vaddr)
-       .popsection
-
 /*
  * end early head section, begin head code that is also used for
  * hotplug and needs to have the same protections as the text region
@@ -490,8 +481,9 @@ EXPORT_SYMBOL(kimage_vaddr)
  * Since we cannot always rely on ERET synchronizing writes to sysregs (e.g. if
  * SCTLR_ELx.EOS is clear), we place an ISB prior to ERET.
  *
- * Returns either BOOT_CPU_MODE_EL1 or BOOT_CPU_MODE_EL2 in w0 if
- * booted in EL1 or EL2 respectively.
+ * Returns either BOOT_CPU_MODE_EL1 or BOOT_CPU_MODE_EL2 in x0 if
+ * booted in EL1 or EL2 respectively, with the top 32 bits containing
+ * potential context flags. These flags are *not* stored in __boot_cpu_mode.
  */
 SYM_FUNC_START(init_kernel_el)
        mrs     x0, CurrentEL
@@ -520,6 +512,8 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
        msr     vbar_el2, x0
        isb
 
+       mov_q   x1, INIT_SCTLR_EL1_MMU_OFF
+
        /*
         * Fruity CPUs seem to have HCR_EL2.E2H set to RES1,
         * making it impossible to start in nVHE mode. Is that
@@ -529,34 +523,19 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
        and     x0, x0, #HCR_E2H
        cbz     x0, 1f
 
-       /* Switching to VHE requires a sane SCTLR_EL1 as a start */
-       mov_q   x0, INIT_SCTLR_EL1_MMU_OFF
-       msr_s   SYS_SCTLR_EL12, x0
-
-       /*
-        * Force an eret into a helper "function", and let it return
-        * to our original caller... This makes sure that we have
-        * initialised the basic PSTATE state.
-        */
-       mov     x0, #INIT_PSTATE_EL2
-       msr     spsr_el1, x0
-       adr     x0, __cpu_stick_to_vhe
-       msr     elr_el1, x0
-       eret
+       /* Set a sane SCTLR_EL1, the VHE way */
+       msr_s   SYS_SCTLR_EL12, x1
+       mov     x2, #BOOT_CPU_FLAG_E2H
+       b       2f
 
 1:
-       mov_q   x0, INIT_SCTLR_EL1_MMU_OFF
-       msr     sctlr_el1, x0
-
+       msr     sctlr_el1, x1
+       mov     x2, xzr
+2:
        msr     elr_el2, lr
        mov     w0, #BOOT_CPU_MODE_EL2
+       orr     x0, x0, x2
        eret
-
-__cpu_stick_to_vhe:
-       mov     x0, #HVC_VHE_RESTART
-       hvc     #0
-       mov     x0, #BOOT_CPU_MODE_EL2
-       ret
 SYM_FUNC_END(init_kernel_el)
 
 /*
@@ -569,52 +548,21 @@ SYM_FUNC_START_LOCAL(set_cpu_boot_mode_flag)
        b.ne    1f
        add     x1, x1, #4
 1:     str     w0, [x1]                        // Save CPU boot mode
-       dmb     sy
-       dc      ivac, x1                        // Invalidate potentially stale cache line
        ret
 SYM_FUNC_END(set_cpu_boot_mode_flag)
 
-/*
- * These values are written with the MMU off, but read with the MMU on.
- * Writers will invalidate the corresponding address, discarding up to a
- * 'Cache Writeback Granule' (CWG) worth of data. The linker script ensures
- * sufficient alignment that the CWG doesn't overlap another section.
- */
-       .pushsection ".mmuoff.data.write", "aw"
-/*
- * We need to find out the CPU boot mode long after boot, so we need to
- * store it in a writable variable.
- *
- * This is not in .bss, because we set it sufficiently early that the boot-time
- * zeroing of .bss would clobber it.
- */
-SYM_DATA_START(__boot_cpu_mode)
-       .long   BOOT_CPU_MODE_EL2
-       .long   BOOT_CPU_MODE_EL1
-SYM_DATA_END(__boot_cpu_mode)
-/*
- * The booting CPU updates the failed status @__early_cpu_boot_status,
- * with MMU turned off.
- */
-SYM_DATA_START(__early_cpu_boot_status)
-       .quad   0
-SYM_DATA_END(__early_cpu_boot_status)
-
-       .popsection
-
        /*
         * This provides a "holding pen" for platforms to hold all secondary
         * cores are held until we're ready for them to initialise.
         */
 SYM_FUNC_START(secondary_holding_pen)
        bl      init_kernel_el                  // w0=cpu_boot_mode
-       bl      set_cpu_boot_mode_flag
-       mrs     x0, mpidr_el1
+       mrs     x2, mpidr_el1
        mov_q   x1, MPIDR_HWID_BITMASK
-       and     x0, x0, x1
+       and     x2, x2, x1
        adr_l   x3, secondary_holding_pen_release
 pen:   ldr     x4, [x3]
-       cmp     x4, x0
+       cmp     x4, x2
        b.eq    secondary_startup
        wfe
        b       pen
@@ -626,7 +574,6 @@ SYM_FUNC_END(secondary_holding_pen)
         */
 SYM_FUNC_START(secondary_entry)
        bl      init_kernel_el                  // w0=cpu_boot_mode
-       bl      set_cpu_boot_mode_flag
        b       secondary_startup
 SYM_FUNC_END(secondary_entry)
 
@@ -634,16 +581,24 @@ SYM_FUNC_START_LOCAL(secondary_startup)
        /*
         * Common entry point for secondary CPUs.
         */
-       bl      switch_to_vhe
+       mov     x20, x0                         // preserve boot mode
+       bl      finalise_el2
        bl      __cpu_secondary_check52bitva
+#if VA_BITS > 48
+       ldr_l   x0, vabits_actual
+#endif
        bl      __cpu_setup                     // initialise processor
        adrp    x1, swapper_pg_dir
+       adrp    x2, idmap_pg_dir
        bl      __enable_mmu
        ldr     x8, =__secondary_switched
        br      x8
 SYM_FUNC_END(secondary_startup)
 
 SYM_FUNC_START_LOCAL(__secondary_switched)
+       mov     x0, x20
+       bl      set_cpu_boot_mode_flag
+       str_l   xzr, __early_cpu_boot_status, x3
        adr_l   x5, vectors
        msr     vbar_el1, x5
        isb
@@ -691,6 +646,7 @@ SYM_FUNC_END(__secondary_too_slow)
  *
  *  x0  = SCTLR_EL1 value for turning on the MMU.
  *  x1  = TTBR1_EL1 value
+ *  x2  = ID map root table address
  *
  * Returns to the caller via x30/lr. This requires the caller to be covered
  * by the .idmap.text section.
@@ -699,20 +655,15 @@ SYM_FUNC_END(__secondary_too_slow)
  * If it isn't, park the CPU
  */
 SYM_FUNC_START(__enable_mmu)
-       mrs     x2, ID_AA64MMFR0_EL1
-       ubfx    x2, x2, #ID_AA64MMFR0_TGRAN_SHIFT, 4
-       cmp     x2, #ID_AA64MMFR0_TGRAN_SUPPORTED_MIN
+       mrs     x3, ID_AA64MMFR0_EL1
+       ubfx    x3, x3, #ID_AA64MMFR0_TGRAN_SHIFT, 4
+       cmp     x3, #ID_AA64MMFR0_TGRAN_SUPPORTED_MIN
        b.lt    __no_granule_support
-       cmp     x2, #ID_AA64MMFR0_TGRAN_SUPPORTED_MAX
+       cmp     x3, #ID_AA64MMFR0_TGRAN_SUPPORTED_MAX
        b.gt    __no_granule_support
-       update_early_cpu_boot_status 0, x2, x3
-       adrp    x2, idmap_pg_dir
-       phys_to_ttbr x1, x1
        phys_to_ttbr x2, x2
        msr     ttbr0_el1, x2                   // load TTBR0
-       offset_ttbr1 x1, x3
-       msr     ttbr1_el1, x1                   // load TTBR1
-       isb
+       load_ttbr1 x1, x1, x3
 
        set_sctlr_el1   x0
 
@@ -720,7 +671,7 @@ SYM_FUNC_START(__enable_mmu)
 SYM_FUNC_END(__enable_mmu)
 
 SYM_FUNC_START(__cpu_secondary_check52bitva)
-#ifdef CONFIG_ARM64_VA_BITS_52
+#if VA_BITS > 48
        ldr_l   x0, vabits_actual
        cmp     x0, #52
        b.ne    2f
@@ -755,13 +706,10 @@ SYM_FUNC_START_LOCAL(__relocate_kernel)
         * Iterate over each entry in the relocation table, and apply the
         * relocations in place.
         */
-       ldr     w9, =__rela_offset              // offset to reloc table
-       ldr     w10, =__rela_size               // size of reloc table
-
+       adr_l   x9, __rela_start
+       adr_l   x10, __rela_end
        mov_q   x11, KIMAGE_VADDR               // default virtual offset
        add     x11, x11, x23                   // actual virtual offset
-       add     x9, x9, x11                     // __va(.rela)
-       add     x10, x9, x10                    // __va(.rela) + sizeof(.rela)
 
 0:     cmp     x9, x10
        b.hs    1f
@@ -804,21 +752,9 @@ SYM_FUNC_START_LOCAL(__relocate_kernel)
         * entry in x9, the address being relocated by the current address or
         * bitmap entry in x13 and the address being relocated by the current
         * bit in x14.
-        *
-        * Because addends are stored in place in the binary, RELR relocations
-        * cannot be applied idempotently. We use x24 to keep track of the
-        * currently applied displacement so that we can correctly relocate if
-        * __relocate_kernel is called twice with non-zero displacements (i.e.
-        * if there is both a physical misalignment and a KASLR displacement).
         */
-       ldr     w9, =__relr_offset              // offset to reloc table
-       ldr     w10, =__relr_size               // size of reloc table
-       add     x9, x9, x11                     // __va(.relr)
-       add     x10, x9, x10                    // __va(.relr) + sizeof(.relr)
-
-       sub     x15, x23, x24                   // delta from previous offset
-       cbz     x15, 7f                         // nothing to do if unchanged
-       mov     x24, x23                        // save new offset
+       adr_l   x9, __relr_start
+       adr_l   x10, __relr_end
 
 2:     cmp     x9, x10
        b.hs    7f
@@ -826,7 +762,7 @@ SYM_FUNC_START_LOCAL(__relocate_kernel)
        tbnz    x11, #0, 3f                     // branch to handle bitmaps
        add     x13, x11, x23
        ldr     x12, [x13]                      // relocate address entry
-       add     x12, x12, x15
+       add     x12, x12, x23
        str     x12, [x13], #8                  // adjust to start of bitmap
        b       2b
 
@@ -835,7 +771,7 @@ SYM_FUNC_START_LOCAL(__relocate_kernel)
        cbz     x11, 6f
        tbz     x11, #0, 5f                     // skip bit if not set
        ldr     x12, [x14]                      // relocate bit
-       add     x12, x12, x15
+       add     x12, x12, x23
        str     x12, [x14]
 
 5:     add     x14, x14, #8                    // move to next bit's address
@@ -856,43 +792,32 @@ SYM_FUNC_END(__relocate_kernel)
 #endif
 
 SYM_FUNC_START_LOCAL(__primary_switch)
+       adrp    x1, reserved_pg_dir
+       adrp    x2, init_idmap_pg_dir
+       bl      __enable_mmu
+#ifdef CONFIG_RELOCATABLE
+       adrp    x23, KERNEL_START
+       and     x23, x23, MIN_KIMG_ALIGN - 1
 #ifdef CONFIG_RANDOMIZE_BASE
-       mov     x19, x0                         // preserve new SCTLR_EL1 value
-       mrs     x20, sctlr_el1                  // preserve old SCTLR_EL1 value
+       mov     x0, x22
+       adrp    x1, init_pg_end
+       mov     sp, x1
+       mov     x29, xzr
+       bl      __pi_kaslr_early_init
+       and     x24, x0, #SZ_2M - 1             // capture memstart offset seed
+       bic     x0, x0, #SZ_2M - 1
+       orr     x23, x23, x0                    // record kernel offset
+#endif
 #endif
+       bl      clear_page_tables
+       bl      create_kernel_mapping
 
        adrp    x1, init_pg_dir
-       bl      __enable_mmu
+       load_ttbr1 x1, x1, x2
 #ifdef CONFIG_RELOCATABLE
-#ifdef CONFIG_RELR
-       mov     x24, #0                         // no RELR displacement yet
-#endif
        bl      __relocate_kernel
-#ifdef CONFIG_RANDOMIZE_BASE
-       ldr     x8, =__primary_switched
-       adrp    x0, __PHYS_OFFSET
-       blr     x8
-
-       /*
-        * If we return here, we have a KASLR displacement in x23 which we need
-        * to take into account by discarding the current kernel mapping and
-        * creating a new one.
-        */
-       pre_disable_mmu_workaround
-       msr     sctlr_el1, x20                  // disable the MMU
-       isb
-       bl      __create_page_tables            // recreate kernel mapping
-
-       tlbi    vmalle1                         // Remove any stale TLB entries
-       dsb     nsh
-       isb
-
-       set_sctlr_el1   x19                     // re-enable the MMU
-
-       bl      __relocate_kernel
-#endif
 #endif
        ldr     x8, =__primary_switched
-       adrp    x0, __PHYS_OFFSET
+       adrp    x0, KERNEL_START                // __pa(KERNEL_START)
        br      x8
 SYM_FUNC_END(__primary_switch)
index 2e24834..af5df48 100644 (file)
@@ -300,11 +300,6 @@ static void swsusp_mte_restore_tags(void)
                unsigned long pfn = xa_state.xa_index;
                struct page *page = pfn_to_online_page(pfn);
 
-               /*
-                * It is not required to invoke page_kasan_tag_reset(page)
-                * at this point since the tags stored in page->flags are
-                * already restored.
-                */
                mte_restore_page_tags(page_address(page), tags);
 
                mte_free_tag_storage(tags);
index 43d2126..12c7fad 100644 (file)
 #include <asm/ptrace.h>
 #include <asm/virt.h>
 
+// Warning, hardcoded register allocation
+// This will clobber x1 and x2, and expect x1 to contain
+// the id register value as read from the HW
+.macro __check_override idreg, fld, width, pass, fail
+       ubfx    x1, x1, #\fld, #\width
+       cbz     x1, \fail
+
+       adr_l   x1, \idreg\()_override
+       ldr     x2, [x1, FTR_OVR_VAL_OFFSET]
+       ldr     x1, [x1, FTR_OVR_MASK_OFFSET]
+       ubfx    x2, x2, #\fld, #\width
+       ubfx    x1, x1, #\fld, #\width
+       cmp     x1, xzr
+       and     x2, x2, x1
+       csinv   x2, x2, xzr, ne
+       cbnz    x2, \pass
+       b       \fail
+.endm
+
+.macro check_override idreg, fld, pass, fail
+       mrs     x1, \idreg\()_el1
+       __check_override \idreg \fld 4 \pass \fail
+.endm
+
        .text
        .pushsection    .hyp.text, "ax"
 
@@ -51,8 +75,8 @@ SYM_CODE_START_LOCAL(elx_sync)
        msr     vbar_el2, x1
        b       9f
 
-1:     cmp     x0, #HVC_VHE_RESTART
-       b.eq    mutate_to_vhe
+1:     cmp     x0, #HVC_FINALISE_EL2
+       b.eq    __finalise_el2
 
 2:     cmp     x0, #HVC_SOFT_RESTART
        b.ne    3f
@@ -73,27 +97,67 @@ SYM_CODE_START_LOCAL(elx_sync)
        eret
 SYM_CODE_END(elx_sync)
 
-// nVHE? No way! Give me the real thing!
-SYM_CODE_START_LOCAL(mutate_to_vhe)
+SYM_CODE_START_LOCAL(__finalise_el2)
+       check_override id_aa64pfr0 ID_AA64PFR0_SVE_SHIFT .Linit_sve .Lskip_sve
+
+.Linit_sve:    /* SVE register access */
+       mrs     x0, cptr_el2                    // Disable SVE traps
+       bic     x0, x0, #CPTR_EL2_TZ
+       msr     cptr_el2, x0
+       isb
+       mov     x1, #ZCR_ELx_LEN_MASK           // SVE: Enable full vector
+       msr_s   SYS_ZCR_EL2, x1                 // length for EL1.
+
+.Lskip_sve:
+       check_override id_aa64pfr1 ID_AA64PFR1_SME_SHIFT .Linit_sme .Lskip_sme
+
+.Linit_sme:    /* SME register access and priority mapping */
+       mrs     x0, cptr_el2                    // Disable SME traps
+       bic     x0, x0, #CPTR_EL2_TSM
+       msr     cptr_el2, x0
+       isb
+
+       mrs     x1, sctlr_el2
+       orr     x1, x1, #SCTLR_ELx_ENTP2        // Disable TPIDR2 traps
+       msr     sctlr_el2, x1
+       isb
+
+       mov     x0, #0                          // SMCR controls
+
+       // Full FP in SM?
+       mrs_s   x1, SYS_ID_AA64SMFR0_EL1
+       __check_override id_aa64smfr0 ID_AA64SMFR0_EL1_FA64_SHIFT 1 .Linit_sme_fa64 .Lskip_sme_fa64
+
+.Linit_sme_fa64:
+       orr     x0, x0, SMCR_ELx_FA64_MASK
+.Lskip_sme_fa64:
+
+       orr     x0, x0, #SMCR_ELx_LEN_MASK      // Enable full SME vector
+       msr_s   SYS_SMCR_EL2, x0                // length for EL1.
+
+       mrs_s   x1, SYS_SMIDR_EL1               // Priority mapping supported?
+       ubfx    x1, x1, #SMIDR_EL1_SMPS_SHIFT, #1
+       cbz     x1, .Lskip_sme
+
+       msr_s   SYS_SMPRIMAP_EL2, xzr           // Make all priorities equal
+
+       mrs     x1, id_aa64mmfr1_el1            // HCRX_EL2 present?
+       ubfx    x1, x1, #ID_AA64MMFR1_HCX_SHIFT, #4
+       cbz     x1, .Lskip_sme
+
+       mrs_s   x1, SYS_HCRX_EL2
+       orr     x1, x1, #HCRX_EL2_SMPME_MASK    // Enable priority mapping
+       msr_s   SYS_HCRX_EL2, x1
+
+.Lskip_sme:
+
+       // nVHE? No way! Give me the real thing!
        // Sanity check: MMU *must* be off
        mrs     x1, sctlr_el2
        tbnz    x1, #0, 1f
 
        // Needs to be VHE capable, obviously
-       mrs     x1, id_aa64mmfr1_el1
-       ubfx    x1, x1, #ID_AA64MMFR1_VHE_SHIFT, #4
-       cbz     x1, 1f
-
-       // Check whether VHE is disabled from the command line
-       adr_l   x1, id_aa64mmfr1_override
-       ldr     x2, [x1, FTR_OVR_VAL_OFFSET]
-       ldr     x1, [x1, FTR_OVR_MASK_OFFSET]
-       ubfx    x2, x2, #ID_AA64MMFR1_VHE_SHIFT, #4
-       ubfx    x1, x1, #ID_AA64MMFR1_VHE_SHIFT, #4
-       cmp     x1, xzr
-       and     x2, x2, x1
-       csinv   x2, x2, xzr, ne
-       cbnz    x2, 2f
+       check_override id_aa64mmfr1 ID_AA64MMFR1_VHE_SHIFT 2f 1f
 
 1:     mov_q   x0, HVC_STUB_ERR
        eret
@@ -140,10 +204,10 @@ SYM_CODE_START_LOCAL(mutate_to_vhe)
        msr     spsr_el1, x0
 
        b       enter_vhe
-SYM_CODE_END(mutate_to_vhe)
+SYM_CODE_END(__finalise_el2)
 
        // At the point where we reach enter_vhe(), we run with
-       // the MMU off (which is enforced by mutate_to_vhe()).
+       // the MMU off (which is enforced by __finalise_el2()).
        // We thus need to be in the idmap, or everything will
        // explode when enabling the MMU.
 
@@ -222,12 +286,12 @@ SYM_FUNC_START(__hyp_reset_vectors)
 SYM_FUNC_END(__hyp_reset_vectors)
 
 /*
- * Entry point to switch to VHE if deemed capable
+ * Entry point to finalise EL2 and switch to VHE if deemed capable
+ *
+ * w0: boot mode, as returned by init_kernel_el()
  */
-SYM_FUNC_START(switch_to_vhe)
+SYM_FUNC_START(finalise_el2)
        // Need to have booted at EL2
-       adr_l   x1, __boot_cpu_mode
-       ldr     w0, [x1]
        cmp     w0, #BOOT_CPU_MODE_EL2
        b.ne    1f
 
@@ -236,9 +300,8 @@ SYM_FUNC_START(switch_to_vhe)
        cmp     x0, #CurrentEL_EL1
        b.ne    1f
 
-       // Turn the world upside down
-       mov     x0, #HVC_VHE_RESTART
+       mov     x0, #HVC_FINALISE_EL2
        hvc     #0
 1:
        ret
-SYM_FUNC_END(switch_to_vhe)
+SYM_FUNC_END(finalise_el2)
index 8a2ceb5..1b0542c 100644 (file)
 #define FTR_ALIAS_NAME_LEN     30
 #define FTR_ALIAS_OPTION_LEN   116
 
+static u64 __boot_status __initdata;
+
 struct ftr_set_desc {
        char                            name[FTR_DESC_NAME_LEN];
        struct arm64_ftr_override       *override;
        struct {
                char                    name[FTR_DESC_FIELD_LEN];
                u8                      shift;
+               u8                      width;
                bool                    (*filter)(u64 val);
        }                               fields[];
 };
 
+#define FIELD(n, s, f) { .name = n, .shift = s, .width = 4, .filter = f }
+
 static bool __init mmfr1_vh_filter(u64 val)
 {
        /*
@@ -37,24 +42,65 @@ static bool __init mmfr1_vh_filter(u64 val)
         * the user was trying to force nVHE on us, proceed with
         * attitude adjustment.
         */
-       return !(is_kernel_in_hyp_mode() && val == 0);
+       return !(__boot_status == (BOOT_CPU_FLAG_E2H | BOOT_CPU_MODE_EL2) &&
+                val == 0);
 }
 
 static const struct ftr_set_desc mmfr1 __initconst = {
        .name           = "id_aa64mmfr1",
        .override       = &id_aa64mmfr1_override,
        .fields         = {
-               { "vh", ID_AA64MMFR1_VHE_SHIFT, mmfr1_vh_filter },
+               FIELD("vh", ID_AA64MMFR1_VHE_SHIFT, mmfr1_vh_filter),
+               {}
+       },
+};
+
+static bool __init pfr0_sve_filter(u64 val)
+{
+       /*
+        * Disabling SVE also means disabling all the features that
+        * are associated with it. The easiest way to do it is just to
+        * override id_aa64zfr0_el1 to be 0.
+        */
+       if (!val) {
+               id_aa64zfr0_override.val = 0;
+               id_aa64zfr0_override.mask = GENMASK(63, 0);
+       }
+
+       return true;
+}
+
+static const struct ftr_set_desc pfr0 __initconst = {
+       .name           = "id_aa64pfr0",
+       .override       = &id_aa64pfr0_override,
+       .fields         = {
+               FIELD("sve", ID_AA64PFR0_SVE_SHIFT, pfr0_sve_filter),
                {}
        },
 };
 
+static bool __init pfr1_sme_filter(u64 val)
+{
+       /*
+        * Similarly to SVE, disabling SME also means disabling all
+        * the features that are associated with it. Just set
+        * id_aa64smfr0_el1 to 0 and don't look back.
+        */
+       if (!val) {
+               id_aa64smfr0_override.val = 0;
+               id_aa64smfr0_override.mask = GENMASK(63, 0);
+       }
+
+       return true;
+}
+
 static const struct ftr_set_desc pfr1 __initconst = {
        .name           = "id_aa64pfr1",
        .override       = &id_aa64pfr1_override,
        .fields         = {
-               { "bt", ID_AA64PFR1_BT_SHIFT },
-               { "mte", ID_AA64PFR1_MTE_SHIFT},
+               FIELD("bt", ID_AA64PFR1_BT_SHIFT, NULL ),
+               FIELD("mte", ID_AA64PFR1_MTE_SHIFT, NULL),
+               FIELD("sme", ID_AA64PFR1_SME_SHIFT, pfr1_sme_filter),
                {}
        },
 };
@@ -63,10 +109,10 @@ static const struct ftr_set_desc isar1 __initconst = {
        .name           = "id_aa64isar1",
        .override       = &id_aa64isar1_override,
        .fields         = {
-               { "gpi", ID_AA64ISAR1_GPI_SHIFT },
-               { "gpa", ID_AA64ISAR1_GPA_SHIFT },
-               { "api", ID_AA64ISAR1_API_SHIFT },
-               { "apa", ID_AA64ISAR1_APA_SHIFT },
+               FIELD("gpi", ID_AA64ISAR1_EL1_GPI_SHIFT, NULL),
+               FIELD("gpa", ID_AA64ISAR1_EL1_GPA_SHIFT, NULL),
+               FIELD("api", ID_AA64ISAR1_EL1_API_SHIFT, NULL),
+               FIELD("apa", ID_AA64ISAR1_EL1_APA_SHIFT, NULL),
                {}
        },
 };
@@ -75,8 +121,18 @@ static const struct ftr_set_desc isar2 __initconst = {
        .name           = "id_aa64isar2",
        .override       = &id_aa64isar2_override,
        .fields         = {
-               { "gpa3", ID_AA64ISAR2_GPA3_SHIFT },
-               { "apa3", ID_AA64ISAR2_APA3_SHIFT },
+               FIELD("gpa3", ID_AA64ISAR2_EL1_GPA3_SHIFT, NULL),
+               FIELD("apa3", ID_AA64ISAR2_EL1_APA3_SHIFT, NULL),
+               {}
+       },
+};
+
+static const struct ftr_set_desc smfr0 __initconst = {
+       .name           = "id_aa64smfr0",
+       .override       = &id_aa64smfr0_override,
+       .fields         = {
+               /* FA64 is a one bit field... :-/ */
+               { "fa64", ID_AA64SMFR0_EL1_FA64_SHIFT, 1, },
                {}
        },
 };
@@ -89,16 +145,18 @@ static const struct ftr_set_desc kaslr __initconst = {
        .override       = &kaslr_feature_override,
 #endif
        .fields         = {
-               { "disabled", 0 },
+               FIELD("disabled", 0, NULL),
                {}
        },
 };
 
 static const struct ftr_set_desc * const regs[] __initconst = {
        &mmfr1,
+       &pfr0,
        &pfr1,
        &isar1,
        &isar2,
+       &smfr0,
        &kaslr,
 };
 
@@ -108,6 +166,8 @@ static const struct {
 } aliases[] __initconst = {
        { "kvm-arm.mode=nvhe",          "id_aa64mmfr1.vh=0" },
        { "kvm-arm.mode=protected",     "id_aa64mmfr1.vh=0" },
+       { "arm64.nosve",                "id_aa64pfr0.sve=0 id_aa64pfr1.sme=0" },
+       { "arm64.nosme",                "id_aa64pfr1.sme=0" },
        { "arm64.nobti",                "id_aa64pfr1.bt=0" },
        { "arm64.nopauth",
          "id_aa64isar1.gpi=0 id_aa64isar1.gpa=0 "
@@ -144,7 +204,8 @@ static void __init match_options(const char *cmdline)
 
                for (f = 0; strlen(regs[i]->fields[f].name); f++) {
                        u64 shift = regs[i]->fields[f].shift;
-                       u64 mask = 0xfUL << shift;
+                       u64 width = regs[i]->fields[f].width ?: 4;
+                       u64 mask = GENMASK_ULL(shift + width - 1, shift);
                        u64 v;
 
                        if (find_field(cmdline, regs[i], f, &v))
@@ -152,7 +213,7 @@ static void __init match_options(const char *cmdline)
 
                        /*
                         * If an override gets filtered out, advertise
-                        * it by setting the value to 0xf, but
+                        * it by setting the value to the all-ones while
                         * clearing the mask... Yes, this is fragile.
                         */
                        if (regs[i]->fields[f].filter &&
@@ -234,9 +295,9 @@ static __init void parse_cmdline(void)
 }
 
 /* Keep checkers quiet */
-void init_feature_override(void);
+void init_feature_override(u64 boot_status);
 
-asmlinkage void __init init_feature_override(void)
+asmlinkage void __init init_feature_override(u64 boot_status)
 {
        int i;
 
@@ -247,6 +308,8 @@ asmlinkage void __init init_feature_override(void)
                }
        }
 
+       __boot_status = boot_status;
+
        parse_cmdline();
 
        for (i = 0; i < ARRAY_SIZE(regs); i++) {
index 241c86b..afa69e0 100644 (file)
 #error This file should only be included in vmlinux.lds.S
 #endif
 
-#ifdef CONFIG_EFI
-
-__efistub_kernel_size          = _edata - _text;
-__efistub_primary_entry_offset = primary_entry - _text;
-
+PROVIDE(__efistub_kernel_size          = _edata - _text);
+PROVIDE(__efistub_primary_entry_offset = primary_entry - _text);
 
 /*
  * The EFI stub has its own symbol namespace prefixed by __efistub_, to
@@ -25,31 +22,37 @@ __efistub_primary_entry_offset      = primary_entry - _text;
  * linked at. The routines below are all implemented in assembler in a
  * position independent manner
  */
-__efistub_memcmp               = __pi_memcmp;
-__efistub_memchr               = __pi_memchr;
-__efistub_memcpy               = __pi_memcpy;
-__efistub_memmove              = __pi_memmove;
-__efistub_memset               = __pi_memset;
-__efistub_strlen               = __pi_strlen;
-__efistub_strnlen              = __pi_strnlen;
-__efistub_strcmp               = __pi_strcmp;
-__efistub_strncmp              = __pi_strncmp;
-__efistub_strrchr              = __pi_strrchr;
-__efistub_dcache_clean_poc = __pi_dcache_clean_poc;
-
-#if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
-__efistub___memcpy             = __pi_memcpy;
-__efistub___memmove            = __pi_memmove;
-__efistub___memset             = __pi_memset;
-#endif
+PROVIDE(__efistub_memcmp               = __pi_memcmp);
+PROVIDE(__efistub_memchr               = __pi_memchr);
+PROVIDE(__efistub_memcpy               = __pi_memcpy);
+PROVIDE(__efistub_memmove              = __pi_memmove);
+PROVIDE(__efistub_memset               = __pi_memset);
+PROVIDE(__efistub_strlen               = __pi_strlen);
+PROVIDE(__efistub_strnlen              = __pi_strnlen);
+PROVIDE(__efistub_strcmp               = __pi_strcmp);
+PROVIDE(__efistub_strncmp              = __pi_strncmp);
+PROVIDE(__efistub_strrchr              = __pi_strrchr);
+PROVIDE(__efistub_dcache_clean_poc     = __pi_dcache_clean_poc);
+
+PROVIDE(__efistub__text                        = _text);
+PROVIDE(__efistub__end                 = _end);
+PROVIDE(__efistub__edata               = _edata);
+PROVIDE(__efistub_screen_info          = screen_info);
+PROVIDE(__efistub__ctype               = _ctype);
 
-__efistub__text                        = _text;
-__efistub__end                 = _end;
-__efistub__edata               = _edata;
-__efistub_screen_info          = screen_info;
-__efistub__ctype               = _ctype;
+/*
+ * The __ prefixed memcpy/memset/memmove symbols are provided by KASAN, which
+ * instruments the conventional ones. Therefore, any references from the EFI
+ * stub or other position independent, low level C code should be redirected to
+ * the non-instrumented versions as well.
+ */
+PROVIDE(__efistub___memcpy             = __pi_memcpy);
+PROVIDE(__efistub___memmove            = __pi_memmove);
+PROVIDE(__efistub___memset             = __pi_memset);
 
-#endif
+PROVIDE(__pi___memcpy                  = __pi_memcpy);
+PROVIDE(__pi___memmove                 = __pi_memmove);
+PROVIDE(__pi___memset                  = __pi_memset);
 
 #ifdef CONFIG_KVM
 
index fc98037..faf88ec 100644 (file)
@@ -26,14 +26,3 @@ void arch_jump_label_transform(struct jump_entry *entry,
 
        aarch64_insn_patch_text_nosync(addr, insn);
 }
-
-void arch_jump_label_transform_static(struct jump_entry *entry,
-                                     enum jump_label_type type)
-{
-       /*
-        * We use the architected A64 NOP in arch_static_branch, so there's no
-        * need to patch an identical A64 NOP over the top of it here. The core
-        * will call arch_jump_label_transform from a module notifier if the
-        * NOP needs to be replaced by a branch.
-        */
-}
index 418b2bb..325455d 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/pgtable.h>
 #include <linux/random.h>
 
-#include <asm/cacheflush.h>
 #include <asm/fixmap.h>
 #include <asm/kernel-pgtable.h>
 #include <asm/memory.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
 
-enum kaslr_status {
-       KASLR_ENABLED,
-       KASLR_DISABLED_CMDLINE,
-       KASLR_DISABLED_NO_SEED,
-       KASLR_DISABLED_FDT_REMAP,
-};
-
-static enum kaslr_status __initdata kaslr_status;
 u64 __ro_after_init module_alloc_base;
 u16 __initdata memstart_offset_seed;
 
-static __init u64 get_kaslr_seed(void *fdt)
-{
-       int node, len;
-       fdt64_t *prop;
-       u64 ret;
-
-       node = fdt_path_offset(fdt, "/chosen");
-       if (node < 0)
-               return 0;
-
-       prop = fdt_getprop_w(fdt, node, "kaslr-seed", &len);
-       if (!prop || len != sizeof(u64))
-               return 0;
-
-       ret = fdt64_to_cpu(*prop);
-       *prop = 0;
-       return ret;
-}
-
 struct arm64_ftr_override kaslr_feature_override __initdata;
 
-/*
- * This routine will be executed with the kernel mapped at its default virtual
- * address, and if it returns successfully, the kernel will be remapped, and
- * start_kernel() will be executed from a randomized virtual offset. The
- * relocation will result in all absolute references (e.g., static variables
- * containing function pointers) to be reinitialized, and zero-initialized
- * .bss variables will be reset to 0.
- */
-u64 __init kaslr_early_init(void)
+static int __init kaslr_init(void)
 {
-       void *fdt;
-       u64 seed, offset, mask, module_range;
-       unsigned long raw;
+       u64 module_range;
+       u32 seed;
 
        /*
         * Set a reasonable default for module_alloc_base in case
         * we end up running with module randomization disabled.
         */
        module_alloc_base = (u64)_etext - MODULES_VSIZE;
-       dcache_clean_inval_poc((unsigned long)&module_alloc_base,
-                           (unsigned long)&module_alloc_base +
-                                   sizeof(module_alloc_base));
-
-       /*
-        * Try to map the FDT early. If this fails, we simply bail,
-        * and proceed with KASLR disabled. We will make another
-        * attempt at mapping the FDT in setup_machine()
-        */
-       fdt = get_early_fdt_ptr();
-       if (!fdt) {
-               kaslr_status = KASLR_DISABLED_FDT_REMAP;
-               return 0;
-       }
 
-       /*
-        * Retrieve (and wipe) the seed from the FDT
-        */
-       seed = get_kaslr_seed(fdt);
-
-       /*
-        * Check if 'nokaslr' appears on the command line, and
-        * return 0 if that is the case.
-        */
        if (kaslr_feature_override.val & kaslr_feature_override.mask & 0xf) {
-               kaslr_status = KASLR_DISABLED_CMDLINE;
+               pr_info("KASLR disabled on command line\n");
                return 0;
        }
 
-       /*
-        * Mix in any entropy obtainable architecturally if enabled
-        * and supported.
-        */
-
-       if (arch_get_random_seed_long_early(&raw))
-               seed ^= raw;
-
-       if (!seed) {
-               kaslr_status = KASLR_DISABLED_NO_SEED;
+       if (!kaslr_offset()) {
+               pr_warn("KASLR disabled due to lack of seed\n");
                return 0;
        }
 
+       pr_info("KASLR enabled\n");
+
        /*
-        * OK, so we are proceeding with KASLR enabled. Calculate a suitable
-        * kernel image offset from the seed. Let's place the kernel in the
-        * middle half of the VMALLOC area (VA_BITS_MIN - 2), and stay clear of
-        * the lower and upper quarters to avoid colliding with other
-        * allocations.
-        * Even if we could randomize at page granularity for 16k and 64k pages,
-        * let's always round to 2 MB so we don't interfere with the ability to
-        * map using contiguous PTEs
+        * KASAN without KASAN_VMALLOC does not expect the module region to
+        * intersect the vmalloc region, since shadow memory is allocated for
+        * each module at load time, whereas the vmalloc region will already be
+        * shadowed by KASAN zero pages.
         */
-       mask = ((1UL << (VA_BITS_MIN - 2)) - 1) & ~(SZ_2M - 1);
-       offset = BIT(VA_BITS_MIN - 3) + (seed & mask);
+       BUILD_BUG_ON((IS_ENABLED(CONFIG_KASAN_GENERIC) ||
+                     IS_ENABLED(CONFIG_KASAN_SW_TAGS)) &&
+                    !IS_ENABLED(CONFIG_KASAN_VMALLOC));
 
-       /* use the top 16 bits to randomize the linear region */
-       memstart_offset_seed = seed >> 48;
-
-       if (!IS_ENABLED(CONFIG_KASAN_VMALLOC) &&
-           (IS_ENABLED(CONFIG_KASAN_GENERIC) ||
-            IS_ENABLED(CONFIG_KASAN_SW_TAGS)))
-               /*
-                * KASAN without KASAN_VMALLOC does not expect the module region
-                * to intersect the vmalloc region, since shadow memory is
-                * allocated for each module at load time, whereas the vmalloc
-                * region is shadowed by KASAN zero pages. So keep modules
-                * out of the vmalloc region if KASAN is enabled without
-                * KASAN_VMALLOC, and put the kernel well within 4 GB of the
-                * module region.
-                */
-               return offset % SZ_2G;
+       seed = get_random_u32();
 
        if (IS_ENABLED(CONFIG_RANDOMIZE_MODULE_REGION_FULL)) {
                /*
@@ -154,8 +70,7 @@ u64 __init kaslr_early_init(void)
                 * resolved normally.)
                 */
                module_range = SZ_2G - (u64)(_end - _stext);
-               module_alloc_base = max((u64)_end + offset - SZ_2G,
-                                       (u64)MODULES_VADDR);
+               module_alloc_base = max((u64)_end - SZ_2G, (u64)MODULES_VADDR);
        } else {
                /*
                 * Randomize the module region by setting module_alloc_base to
@@ -167,40 +82,12 @@ u64 __init kaslr_early_init(void)
                 * when ARM64_MODULE_PLTS is enabled.
                 */
                module_range = MODULES_VSIZE - (u64)(_etext - _stext);
-               module_alloc_base = (u64)_etext + offset - MODULES_VSIZE;
        }
 
        /* use the lower 21 bits to randomize the base of the module region */
        module_alloc_base += (module_range * (seed & ((1 << 21) - 1))) >> 21;
        module_alloc_base &= PAGE_MASK;
 
-       dcache_clean_inval_poc((unsigned long)&module_alloc_base,
-                           (unsigned long)&module_alloc_base +
-                                   sizeof(module_alloc_base));
-       dcache_clean_inval_poc((unsigned long)&memstart_offset_seed,
-                           (unsigned long)&memstart_offset_seed +
-                                   sizeof(memstart_offset_seed));
-
-       return offset;
-}
-
-static int __init kaslr_init(void)
-{
-       switch (kaslr_status) {
-       case KASLR_ENABLED:
-               pr_info("KASLR enabled\n");
-               break;
-       case KASLR_DISABLED_CMDLINE:
-               pr_info("KASLR disabled on command line\n");
-               break;
-       case KASLR_DISABLED_NO_SEED:
-               pr_warn("KASLR disabled due to lack of seed\n");
-               break;
-       case KASLR_DISABLED_FDT_REMAP:
-               pr_warn("KASLR disabled due to FDT remapping failure\n");
-               break;
-       }
-
        return 0;
 }
-core_initcall(kaslr_init)
+subsys_initcall(kaslr_init)
index 9ec3469..5ed6a58 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/kexec.h>
 #include <linux/pe.h>
 #include <linux/string.h>
-#include <linux/verification.h>
 #include <asm/byteorder.h>
 #include <asm/cpufeature.h>
 #include <asm/image.h>
@@ -130,18 +129,10 @@ static void *image_load(struct kimage *image,
        return NULL;
 }
 
-#ifdef CONFIG_KEXEC_IMAGE_VERIFY_SIG
-static int image_verify_sig(const char *kernel, unsigned long kernel_len)
-{
-       return verify_pefile_signature(kernel, kernel_len, NULL,
-                                      VERIFYING_KEXEC_PE_SIGNATURE);
-}
-#endif
-
 const struct kexec_file_ops kexec_image_ops = {
        .probe = image_probe,
        .load = image_load,
 #ifdef CONFIG_KEXEC_IMAGE_VERIFY_SIG
-       .verify_sig = image_verify_sig,
+       .verify_sig = kexec_kernel_verify_pe_sig,
 #endif
 };
index 42bd8c0..692e9d2 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <asm/unistd.h>
 
+       .section .rodata
        .align  5
        .globl  __kuser_helper_start
 __kuser_helper_start:
index f6b0074..b2b7302 100644 (file)
@@ -48,15 +48,6 @@ static void mte_sync_page_tags(struct page *page, pte_t old_pte,
        if (!pte_is_tagged)
                return;
 
-       page_kasan_tag_reset(page);
-       /*
-        * We need smp_wmb() in between setting the flags and clearing the
-        * tags because if another thread reads page->flags and builds a
-        * tagged address out of it, there is an actual dependency to the
-        * memory access, but on the current thread we do not guarantee that
-        * the new page->flags are visible before the tags were updated.
-        */
-       smp_wmb();
        mte_clear_page_tags(page_address(page));
 }
 
diff --git a/arch/arm64/kernel/pi/Makefile b/arch/arm64/kernel/pi/Makefile
new file mode 100644 (file)
index 0000000..8392914
--- /dev/null
@@ -0,0 +1,33 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright 2022 Google LLC
+
+KBUILD_CFLAGS  := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) -fpie \
+                  -Os -DDISABLE_BRANCH_PROFILING $(DISABLE_STACKLEAK_PLUGIN) \
+                  $(call cc-option,-mbranch-protection=none) \
+                  -I$(srctree)/scripts/dtc/libfdt -fno-stack-protector \
+                  -include $(srctree)/include/linux/hidden.h \
+                  -D__DISABLE_EXPORTS -ffreestanding -D__NO_FORTIFY \
+                  $(call cc-option,-fno-addrsig)
+
+# remove SCS flags from all objects in this directory
+KBUILD_CFLAGS  := $(filter-out $(CC_FLAGS_SCS), $(KBUILD_CFLAGS))
+# disable LTO
+KBUILD_CFLAGS  := $(filter-out $(CC_FLAGS_LTO), $(KBUILD_CFLAGS))
+
+GCOV_PROFILE   := n
+KASAN_SANITIZE := n
+KCSAN_SANITIZE := n
+UBSAN_SANITIZE := n
+KCOV_INSTRUMENT        := n
+
+$(obj)/%.pi.o: OBJCOPYFLAGS := --prefix-symbols=__pi_ \
+                              --remove-section=.note.gnu.property \
+                              --prefix-alloc-sections=.init
+$(obj)/%.pi.o: $(obj)/%.o FORCE
+       $(call if_changed,objcopy)
+
+$(obj)/lib-%.o: $(srctree)/lib/%.c FORCE
+       $(call if_changed_rule,cc_o_c)
+
+obj-y          := kaslr_early.pi.o lib-fdt.pi.o lib-fdt_ro.pi.o
+extra-y                := $(patsubst %.pi.o,%.o,$(obj-y))
diff --git a/arch/arm64/kernel/pi/kaslr_early.c b/arch/arm64/kernel/pi/kaslr_early.c
new file mode 100644 (file)
index 0000000..6c3855e
--- /dev/null
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright 2022 Google LLC
+// Author: Ard Biesheuvel <ardb@google.com>
+
+// NOTE: code in this file runs *very* early, and is not permitted to use
+// global variables or anything that relies on absolute addressing.
+
+#include <linux/libfdt.h>
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/types.h>
+#include <linux/sizes.h>
+#include <linux/string.h>
+
+#include <asm/archrandom.h>
+#include <asm/memory.h>
+
+/* taken from lib/string.c */
+static char *__strstr(const char *s1, const char *s2)
+{
+       size_t l1, l2;
+
+       l2 = strlen(s2);
+       if (!l2)
+               return (char *)s1;
+       l1 = strlen(s1);
+       while (l1 >= l2) {
+               l1--;
+               if (!memcmp(s1, s2, l2))
+                       return (char *)s1;
+               s1++;
+       }
+       return NULL;
+}
+static bool cmdline_contains_nokaslr(const u8 *cmdline)
+{
+       const u8 *str;
+
+       str = __strstr(cmdline, "nokaslr");
+       return str == cmdline || (str > cmdline && *(str - 1) == ' ');
+}
+
+static bool is_kaslr_disabled_cmdline(void *fdt)
+{
+       if (!IS_ENABLED(CONFIG_CMDLINE_FORCE)) {
+               int node;
+               const u8 *prop;
+
+               node = fdt_path_offset(fdt, "/chosen");
+               if (node < 0)
+                       goto out;
+
+               prop = fdt_getprop(fdt, node, "bootargs", NULL);
+               if (!prop)
+                       goto out;
+
+               if (cmdline_contains_nokaslr(prop))
+                       return true;
+
+               if (IS_ENABLED(CONFIG_CMDLINE_EXTEND))
+                       goto out;
+
+               return false;
+       }
+out:
+       return cmdline_contains_nokaslr(CONFIG_CMDLINE);
+}
+
+static u64 get_kaslr_seed(void *fdt)
+{
+       int node, len;
+       fdt64_t *prop;
+       u64 ret;
+
+       node = fdt_path_offset(fdt, "/chosen");
+       if (node < 0)
+               return 0;
+
+       prop = fdt_getprop_w(fdt, node, "kaslr-seed", &len);
+       if (!prop || len != sizeof(u64))
+               return 0;
+
+       ret = fdt64_to_cpu(*prop);
+       *prop = 0;
+       return ret;
+}
+
+asmlinkage u64 kaslr_early_init(void *fdt)
+{
+       u64 seed;
+
+       if (is_kaslr_disabled_cmdline(fdt))
+               return 0;
+
+       seed = get_kaslr_seed(fdt);
+       if (!seed) {
+#ifdef CONFIG_ARCH_RANDOM
+                if (!__early_cpu_has_rndr() ||
+                    !__arm64_rndr((unsigned long *)&seed))
+#endif
+               return 0;
+       }
+
+       /*
+        * OK, so we are proceeding with KASLR enabled. Calculate a suitable
+        * kernel image offset from the seed. Let's place the kernel in the
+        * middle half of the VMALLOC area (VA_BITS_MIN - 2), and stay clear of
+        * the lower and upper quarters to avoid colliding with other
+        * allocations.
+        */
+       return BIT(VA_BITS_MIN - 3) + (seed & GENMASK(VA_BITS_MIN - 3, 0));
+}
index b0980fb..3e6d035 100644 (file)
@@ -280,6 +280,9 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user)
 
                vl = task_get_sme_vl(current);
        } else {
+               if (!system_supports_sve())
+                       return -EINVAL;
+
                vl = task_get_sve_vl(current);
        }
 
@@ -342,9 +345,14 @@ fpsimd_only:
 
 #else /* ! CONFIG_ARM64_SVE */
 
-/* Turn any non-optimised out attempts to use these into a link error: */
+static int restore_sve_fpsimd_context(struct user_ctxs *user)
+{
+       WARN_ON_ONCE(1);
+       return -EINVAL;
+}
+
+/* Turn any non-optimised out attempts to use this into a link error: */
 extern int preserve_sve_context(void __user *ctx);
-extern int restore_sve_fpsimd_context(struct user_ctxs *user);
 
 #endif /* ! CONFIG_ARM64_SVE */
 
@@ -649,14 +657,10 @@ static int restore_sigframe(struct pt_regs *regs,
                if (!user.fpsimd)
                        return -EINVAL;
 
-               if (user.sve) {
-                       if (!system_supports_sve())
-                               return -EINVAL;
-
+               if (user.sve)
                        err = restore_sve_fpsimd_context(&user);
-               } else {
+               else
                        err = restore_fpsimd_context(user.fpsimd);
-               }
        }
 
        if (err == 0 && system_supports_sme() && user.za)
index 475d30d..ccbd4aa 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <asm/unistd.h>
 
+       .section .rodata
        .globl __aarch32_sigret_code_start
 __aarch32_sigret_code_start:
 
index 4ea9392..617f78a 100644 (file)
@@ -100,10 +100,11 @@ SYM_FUNC_END(__cpu_suspend_enter)
        .pushsection ".idmap.text", "awx"
 SYM_CODE_START(cpu_resume)
        bl      init_kernel_el
-       bl      switch_to_vhe
+       bl      finalise_el2
        bl      __cpu_setup
        /* enable the MMU early - so we can access sleep_save_stash by va */
        adrp    x1, swapper_pg_dir
+       adrp    x2, idmap_pg_dir
        bl      __enable_mmu
        ldr     x8, =_cpu_resume
        br      x8
index 0467cb7..fcaa151 100644 (file)
@@ -38,6 +38,8 @@
  * @kr_cur:      When KRETPROBES is selected, holds the kretprobe instance
  *               associated with the most recently encountered replacement lr
  *               value.
+ *
+ * @task:        The task being unwound.
  */
 struct unwind_state {
        unsigned long fp;
@@ -48,13 +50,13 @@ struct unwind_state {
 #ifdef CONFIG_KRETPROBES
        struct llist_node *kr_cur;
 #endif
+       struct task_struct *task;
 };
 
-static notrace void unwind_init(struct unwind_state *state, unsigned long fp,
-                               unsigned long pc)
+static void unwind_init_common(struct unwind_state *state,
+                              struct task_struct *task)
 {
-       state->fp = fp;
-       state->pc = pc;
+       state->task = task;
 #ifdef CONFIG_KRETPROBES
        state->kr_cur = NULL;
 #endif
@@ -72,7 +74,57 @@ static notrace void unwind_init(struct unwind_state *state, unsigned long fp,
        state->prev_fp = 0;
        state->prev_type = STACK_TYPE_UNKNOWN;
 }
-NOKPROBE_SYMBOL(unwind_init);
+
+/*
+ * Start an unwind from a pt_regs.
+ *
+ * The unwind will begin at the PC within the regs.
+ *
+ * The regs must be on a stack currently owned by the calling task.
+ */
+static inline void unwind_init_from_regs(struct unwind_state *state,
+                                        struct pt_regs *regs)
+{
+       unwind_init_common(state, current);
+
+       state->fp = regs->regs[29];
+       state->pc = regs->pc;
+}
+
+/*
+ * Start an unwind from a caller.
+ *
+ * The unwind will begin at the caller of whichever function this is inlined
+ * into.
+ *
+ * The function which invokes this must be noinline.
+ */
+static __always_inline void unwind_init_from_caller(struct unwind_state *state)
+{
+       unwind_init_common(state, current);
+
+       state->fp = (unsigned long)__builtin_frame_address(1);
+       state->pc = (unsigned long)__builtin_return_address(0);
+}
+
+/*
+ * Start an unwind from a blocked task.
+ *
+ * The unwind will begin at the blocked tasks saved PC (i.e. the caller of
+ * cpu_switch_to()).
+ *
+ * The caller should ensure the task is blocked in cpu_switch_to() for the
+ * duration of the unwind, or the unwind will be bogus. It is never valid to
+ * call this for the current task.
+ */
+static inline void unwind_init_from_task(struct unwind_state *state,
+                                        struct task_struct *task)
+{
+       unwind_init_common(state, task);
+
+       state->fp = thread_saved_fp(task);
+       state->pc = thread_saved_pc(task);
+}
 
 /*
  * Unwind from one frame record (A) to the next frame record (B).
@@ -81,9 +133,9 @@ NOKPROBE_SYMBOL(unwind_init);
  * records (e.g. a cycle), determined based on the location and fp value of A
  * and the location (but not the fp value) of B.
  */
-static int notrace unwind_next(struct task_struct *tsk,
-                              struct unwind_state *state)
+static int notrace unwind_next(struct unwind_state *state)
 {
+       struct task_struct *tsk = state->task;
        unsigned long fp = state->fp;
        struct stack_info info;
 
@@ -117,15 +169,15 @@ static int notrace unwind_next(struct task_struct *tsk,
                if (fp <= state->prev_fp)
                        return -EINVAL;
        } else {
-               set_bit(state->prev_type, state->stacks_done);
+               __set_bit(state->prev_type, state->stacks_done);
        }
 
        /*
         * Record this frame record's values and location. The prev_fp and
         * prev_type are only meaningful to the next unwind_next() invocation.
         */
-       state->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp));
-       state->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp + 8));
+       state->fp = READ_ONCE(*(unsigned long *)(fp));
+       state->pc = READ_ONCE(*(unsigned long *)(fp + 8));
        state->prev_fp = fp;
        state->prev_type = info.type;
 
@@ -157,8 +209,7 @@ static int notrace unwind_next(struct task_struct *tsk,
 }
 NOKPROBE_SYMBOL(unwind_next);
 
-static void notrace unwind(struct task_struct *tsk,
-                          struct unwind_state *state,
+static void notrace unwind(struct unwind_state *state,
                           stack_trace_consume_fn consume_entry, void *cookie)
 {
        while (1) {
@@ -166,7 +217,7 @@ static void notrace unwind(struct task_struct *tsk,
 
                if (!consume_entry(cookie, state->pc))
                        break;
-               ret = unwind_next(tsk, state);
+               ret = unwind_next(state);
                if (ret < 0)
                        break;
        }
@@ -212,15 +263,15 @@ noinline notrace void arch_stack_walk(stack_trace_consume_fn consume_entry,
 {
        struct unwind_state state;
 
-       if (regs)
-               unwind_init(&state, regs->regs[29], regs->pc);
-       else if (task == current)
-               unwind_init(&state,
-                               (unsigned long)__builtin_frame_address(1),
-                               (unsigned long)__builtin_return_address(0));
-       else
-               unwind_init(&state, thread_saved_fp(task),
-                               thread_saved_pc(task));
-
-       unwind(task, &state, consume_entry, cookie);
+       if (regs) {
+               if (task != current)
+                       return;
+               unwind_init_from_regs(&state, regs);
+       } else if (task == current) {
+               unwind_init_from_caller(&state);
+       } else {
+               unwind_init_from_task(&state, task);
+       }
+
+       unwind(&state, consume_entry, cookie);
 }
index 2b0887e..9135fe0 100644 (file)
@@ -52,7 +52,7 @@ void notrace __cpu_suspend_exit(void)
 
        /* Restore CnP bit in TTBR1_EL1 */
        if (system_supports_cnp())
-               cpu_replace_ttbr1(lm_alias(swapper_pg_dir));
+               cpu_replace_ttbr1(lm_alias(swapper_pg_dir), idmap_pg_dir);
 
        /*
         * PSTATE was not saved over suspend/resume, re-enable any detected
index 9ac7a81..b7fed33 100644 (file)
@@ -579,11 +579,11 @@ static void ctr_read_handler(unsigned long esr, struct pt_regs *regs)
 
        if (cpus_have_const_cap(ARM64_WORKAROUND_1542419)) {
                /* Hide DIC so that we can trap the unnecessary maintenance...*/
-               val &= ~BIT(CTR_DIC_SHIFT);
+               val &= ~BIT(CTR_EL0_DIC_SHIFT);
 
                /* ... and fake IminLine to reduce the number of traps. */
-               val &= ~CTR_IMINLINE_MASK;
-               val |= (PAGE_SHIFT - 2) & CTR_IMINLINE_MASK;
+               val &= ~CTR_EL0_IminLine_MASK;
+               val |= (PAGE_SHIFT - 2) & CTR_EL0_IminLine_MASK;
        }
 
        pt_regs_write_reg(regs, rt, val);
index f6e25d7..bafbf78 100644 (file)
@@ -24,7 +24,13 @@ btildflags-$(CONFIG_ARM64_BTI_KERNEL) += -z force-bti
 # routines, as x86 does (see 6f121e548f83 ("x86, vdso: Reimplement vdso.so
 # preparation in build-time C")).
 ldflags-y := -shared -soname=linux-vdso.so.1 --hash-style=sysv \
-            -Bsymbolic --build-id=sha1 -n $(btildflags-y) -T
+            -Bsymbolic --build-id=sha1 -n $(btildflags-y)
+
+ifdef CONFIG_LD_ORPHAN_WARN
+  ldflags-y += --orphan-handling=warn
+endif
+
+ldflags-y += -T
 
 ccflags-y := -fno-common -fno-builtin -fno-stack-protector -ffixed-x18
 ccflags-y += -DDISABLE_BRANCH_PROFILING -DBUILD_VDSO
index a5e61e0..e69fb4a 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/const.h>
 #include <asm/page.h>
 #include <asm/vdso.h>
+#include <asm-generic/vmlinux.lds.h>
 
 OUTPUT_FORMAT("elf64-littleaarch64", "elf64-bigaarch64", "elf64-littleaarch64")
 OUTPUT_ARCH(aarch64)
@@ -49,11 +50,24 @@ SECTIONS
 
        .dynamic        : { *(.dynamic) }               :text   :dynamic
 
-       .rodata         : { *(.rodata*) }               :text
+       .rela.dyn       : ALIGN(8) { *(.rela .rela*) }
+
+       .rodata         : {
+               *(.rodata*)
+               *(.got)
+               *(.got.plt)
+               *(.plt)
+               *(.plt.*)
+               *(.iplt)
+               *(.igot .igot.plt)
+       }                                               :text
 
        _end = .;
        PROVIDE(end = .);
 
+       DWARF_DEBUG
+       ELF_DETAILS
+
        /DISCARD/       : {
                *(.data .data.* .gnu.linkonce.d.* .sdata*)
                *(.bss .sbss .dynbss .dynsbss)
index 05ba1aa..36c8f66 100644 (file)
@@ -104,6 +104,7 @@ VDSO_AFLAGS += -D__ASSEMBLY__
 VDSO_LDFLAGS += -Bsymbolic --no-undefined -soname=linux-vdso.so.1
 VDSO_LDFLAGS += -z max-page-size=4096 -z common-page-size=4096
 VDSO_LDFLAGS += -shared --hash-style=sysv --build-id=sha1
+VDSO_LDFLAGS += --orphan-handling=warn
 
 
 # Borrow vdsomunge.c from the arm vDSO
index 3348ce5..8d95d7d 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/const.h>
 #include <asm/page.h>
 #include <asm/vdso.h>
+#include <asm-generic/vmlinux.lds.h>
 
 OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
 OUTPUT_ARCH(arm)
@@ -35,12 +36,30 @@ SECTIONS
 
        .dynamic        : { *(.dynamic) }               :text   :dynamic
 
-       .rodata         : { *(.rodata*) }               :text
+       .rodata         : {
+               *(.rodata*)
+               *(.got)
+               *(.got.plt)
+               *(.plt)
+               *(.rel.iplt)
+               *(.iplt)
+               *(.igot.plt)
+       }                                               :text
 
-       .text           : { *(.text*) }                 :text   =0xe7f001f2
+       .text           : {
+               *(.text*)
+               *(.glue_7)
+               *(.glue_7t)
+               *(.vfp11_veneer)
+               *(.v4_bx)
+       }                                               :text   =0xe7f001f2
 
-       .got            : { *(.got) }
-       .rel.plt        : { *(.rel.plt) }
+       .rel.dyn        : { *(.rel*) }
+
+       .ARM.exidx : { *(.ARM.exidx*) }
+       DWARF_DEBUG
+       ELF_DETAILS
+       .ARM.attributes 0 : { *(.ARM.attributes) }
 
        /DISCARD/       : {
                *(.note.GNU-stack)
index 2d4a8f9..45131e3 100644 (file)
@@ -115,7 +115,8 @@ jiffies = jiffies_64;
        __entry_tramp_text_start = .;                   \
        *(.entry.tramp.text)                            \
        . = ALIGN(PAGE_SIZE);                           \
-       __entry_tramp_text_end = .;
+       __entry_tramp_text_end = .;                     \
+       *(.entry.tramp.rodata)
 #else
 #define TRAMP_TEXT
 #endif
@@ -198,8 +199,7 @@ SECTIONS
        }
 
        idmap_pg_dir = .;
-       . += IDMAP_DIR_SIZE;
-       idmap_pg_end = .;
+       . += PAGE_SIZE;
 
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
        tramp_pg_dir = .;
@@ -235,6 +235,10 @@ SECTIONS
        __inittext_end = .;
        __initdata_begin = .;
 
+       init_idmap_pg_dir = .;
+       . += INIT_IDMAP_DIR_SIZE;
+       init_idmap_pg_end = .;
+
        .init.data : {
                INIT_DATA
                INIT_SETUP(16)
@@ -253,21 +257,17 @@ SECTIONS
        HYPERVISOR_RELOC_SECTION
 
        .rela.dyn : ALIGN(8) {
+               __rela_start = .;
                *(.rela .rela*)
+               __rela_end = .;
        }
 
-       __rela_offset   = ABSOLUTE(ADDR(.rela.dyn) - KIMAGE_VADDR);
-       __rela_size     = SIZEOF(.rela.dyn);
-
-#ifdef CONFIG_RELR
        .relr.dyn : ALIGN(8) {
+               __relr_start = .;
                *(.relr.dyn)
+               __relr_end = .;
        }
 
-       __relr_offset   = ABSOLUTE(ADDR(.relr.dyn) - KIMAGE_VADDR);
-       __relr_size     = SIZEOF(.relr.dyn);
-#endif
-
        . = ALIGN(SEGMENT_ALIGN);
        __initdata_end = .;
        __init_end = .;
index fd55014..fa6e466 100644 (file)
        )
 
 #define PVM_ID_AA64ISAR1_ALLOW (\
-       ARM64_FEATURE_MASK(ID_AA64ISAR1_DPB) | \
-       ARM64_FEATURE_MASK(ID_AA64ISAR1_APA) | \
-       ARM64_FEATURE_MASK(ID_AA64ISAR1_API) | \
-       ARM64_FEATURE_MASK(ID_AA64ISAR1_JSCVT) | \
-       ARM64_FEATURE_MASK(ID_AA64ISAR1_FCMA) | \
-       ARM64_FEATURE_MASK(ID_AA64ISAR1_LRCPC) | \
-       ARM64_FEATURE_MASK(ID_AA64ISAR1_GPA) | \
-       ARM64_FEATURE_MASK(ID_AA64ISAR1_GPI) | \
-       ARM64_FEATURE_MASK(ID_AA64ISAR1_FRINTTS) | \
-       ARM64_FEATURE_MASK(ID_AA64ISAR1_SB) | \
-       ARM64_FEATURE_MASK(ID_AA64ISAR1_SPECRES) | \
-       ARM64_FEATURE_MASK(ID_AA64ISAR1_BF16) | \
-       ARM64_FEATURE_MASK(ID_AA64ISAR1_DGH) | \
-       ARM64_FEATURE_MASK(ID_AA64ISAR1_I8MM) \
+       ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_DPB) | \
+       ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_APA) | \
+       ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_API) | \
+       ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_JSCVT) | \
+       ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_FCMA) | \
+       ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_LRCPC) | \
+       ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_GPA) | \
+       ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_GPI) | \
+       ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_FRINTTS) | \
+       ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_SB) | \
+       ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_SPECRES) | \
+       ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_BF16) | \
+       ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_DGH) | \
+       ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_I8MM) \
        )
 
 #define PVM_ID_AA64ISAR2_ALLOW (\
-       ARM64_FEATURE_MASK(ID_AA64ISAR2_GPA3) | \
-       ARM64_FEATURE_MASK(ID_AA64ISAR2_APA3) \
+       ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_GPA3) | \
+       ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_APA3) \
        )
 
 u64 pvm_read_id_reg(const struct kvm_vcpu *vcpu, u32 id);
index 35a4331..6b94c3e 100644 (file)
@@ -173,10 +173,10 @@ static u64 get_pvm_id_aa64isar1(const struct kvm_vcpu *vcpu)
        u64 allow_mask = PVM_ID_AA64ISAR1_ALLOW;
 
        if (!vcpu_has_ptrauth(vcpu))
-               allow_mask &= ~(ARM64_FEATURE_MASK(ID_AA64ISAR1_APA) |
-                               ARM64_FEATURE_MASK(ID_AA64ISAR1_API) |
-                               ARM64_FEATURE_MASK(ID_AA64ISAR1_GPA) |
-                               ARM64_FEATURE_MASK(ID_AA64ISAR1_GPI));
+               allow_mask &= ~(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_APA) |
+                               ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_API) |
+                               ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_GPA) |
+                               ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_GPI));
 
        return id_aa64isar1_el1_sys_val & allow_mask;
 }
@@ -186,8 +186,8 @@ static u64 get_pvm_id_aa64isar2(const struct kvm_vcpu *vcpu)
        u64 allow_mask = PVM_ID_AA64ISAR2_ALLOW;
 
        if (!vcpu_has_ptrauth(vcpu))
-               allow_mask &= ~(ARM64_FEATURE_MASK(ID_AA64ISAR2_APA3) |
-                               ARM64_FEATURE_MASK(ID_AA64ISAR2_GPA3));
+               allow_mask &= ~(ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_APA3) |
+                               ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_GPA3));
 
        return id_aa64isar2_el1_sys_val & allow_mask;
 }
index c06c047..c4fb387 100644 (file)
@@ -1136,17 +1136,17 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu,
                break;
        case SYS_ID_AA64ISAR1_EL1:
                if (!vcpu_has_ptrauth(vcpu))
-                       val &= ~(ARM64_FEATURE_MASK(ID_AA64ISAR1_APA) |
-                                ARM64_FEATURE_MASK(ID_AA64ISAR1_API) |
-                                ARM64_FEATURE_MASK(ID_AA64ISAR1_GPA) |
-                                ARM64_FEATURE_MASK(ID_AA64ISAR1_GPI));
+                       val &= ~(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_APA) |
+                                ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_API) |
+                                ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_GPA) |
+                                ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_GPI));
                break;
        case SYS_ID_AA64ISAR2_EL1:
                if (!vcpu_has_ptrauth(vcpu))
-                       val &= ~(ARM64_FEATURE_MASK(ID_AA64ISAR2_APA3) |
-                                ARM64_FEATURE_MASK(ID_AA64ISAR2_GPA3));
+                       val &= ~(ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_APA3) |
+                                ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_GPA3));
                if (!cpus_have_final_cap(ARM64_HAS_WFXT))
-                       val &= ~ARM64_FEATURE_MASK(ID_AA64ISAR2_WFXT);
+                       val &= ~ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_WFxT);
                break;
        case SYS_ID_AA64DFR0_EL1:
                /* Limit debug to ARMv8.0 */
index eeb9e45..1b7c93a 100644 (file)
@@ -18,7 +18,7 @@
  */
        .macro  multitag_transfer_size, reg, tmp
        mrs_s   \reg, SYS_GMID_EL1
-       ubfx    \reg, \reg, #SYS_GMID_EL1_BS_SHIFT, #SYS_GMID_EL1_BS_SIZE
+       ubfx    \reg, \reg, #GMID_EL1_BS_SHIFT, #GMID_EL1_BS_SIZE
        mov     \tmp, #4
        lsl     \reg, \tmp, \reg
        .endm
index 21c9079..081058d 100644 (file)
@@ -194,44 +194,3 @@ SYM_FUNC_START(__pi_dcache_clean_pop)
        ret
 SYM_FUNC_END(__pi_dcache_clean_pop)
 SYM_FUNC_ALIAS(dcache_clean_pop, __pi_dcache_clean_pop)
-
-/*
- *     __dma_flush_area(start, size)
- *
- *     clean & invalidate D / U line
- *
- *     - start   - virtual start address of region
- *     - size    - size in question
- */
-SYM_FUNC_START(__pi___dma_flush_area)
-       add     x1, x0, x1
-       dcache_by_line_op civac, sy, x0, x1, x2, x3
-       ret
-SYM_FUNC_END(__pi___dma_flush_area)
-SYM_FUNC_ALIAS(__dma_flush_area, __pi___dma_flush_area)
-
-/*
- *     __dma_map_area(start, size, dir)
- *     - start - kernel virtual start address
- *     - size  - size of region
- *     - dir   - DMA direction
- */
-SYM_FUNC_START(__pi___dma_map_area)
-       add     x1, x0, x1
-       b       __pi_dcache_clean_poc
-SYM_FUNC_END(__pi___dma_map_area)
-SYM_FUNC_ALIAS(__dma_map_area, __pi___dma_map_area)
-
-/*
- *     __dma_unmap_area(start, size, dir)
- *     - start - kernel virtual start address
- *     - size  - size of region
- *     - dir   - DMA direction
- */
-SYM_FUNC_START(__pi___dma_unmap_area)
-       add     x1, x0, x1
-       cmp     w2, #DMA_TO_DEVICE
-       b.ne    __pi_dcache_inval_poc
-       ret
-SYM_FUNC_END(__pi___dma_unmap_area)
-SYM_FUNC_ALIAS(__dma_unmap_area, __pi___dma_unmap_area)
index 0dea80b..2491327 100644 (file)
@@ -23,15 +23,6 @@ void copy_highpage(struct page *to, struct page *from)
 
        if (system_supports_mte() && test_bit(PG_mte_tagged, &from->flags)) {
                set_bit(PG_mte_tagged, &to->flags);
-               page_kasan_tag_reset(to);
-               /*
-                * We need smp_wmb() in between setting the flags and clearing the
-                * tags because if another thread reads page->flags and builds a
-                * tagged address out of it, there is an actual dependency to the
-                * memory access, but on the current thread we do not guarantee that
-                * the new page->flags are visible before the tags were updated.
-                */
-               smp_wmb();
                mte_copy_page_tags(kto, kfrom);
        }
 }
index 6099c81..599cf81 100644 (file)
 #include <asm/xen/xen-ops.h>
 
 void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
-               enum dma_data_direction dir)
+                             enum dma_data_direction dir)
 {
-       __dma_map_area(phys_to_virt(paddr), size, dir);
+       unsigned long start = (unsigned long)phys_to_virt(paddr);
+
+       dcache_clean_poc(start, start + size);
 }
 
 void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
-               enum dma_data_direction dir)
+                          enum dma_data_direction dir)
 {
-       __dma_unmap_area(phys_to_virt(paddr), size, dir);
+       unsigned long start = (unsigned long)phys_to_virt(paddr);
+
+       if (dir == DMA_TO_DEVICE)
+               return;
+
+       dcache_inval_poc(start, start + size);
 }
 
 void arch_dma_prep_coherent(struct page *page, size_t size)
 {
-       __dma_flush_area(page_address(page), size);
+       unsigned long start = (unsigned long)page_address(page);
+
+       dcache_clean_inval_poc(start, start + size);
 }
 
 #ifdef CONFIG_IOMMU_DMA
index 4894553..228d681 100644 (file)
@@ -16,13 +16,6 @@ get_ex_fixup(const struct exception_table_entry *ex)
        return ((unsigned long)&ex->fixup + ex->fixup);
 }
 
-static bool ex_handler_fixup(const struct exception_table_entry *ex,
-                            struct pt_regs *regs)
-{
-       regs->pc = get_ex_fixup(ex);
-       return true;
-}
-
 static bool ex_handler_uaccess_err_zero(const struct exception_table_entry *ex,
                                        struct pt_regs *regs)
 {
@@ -72,11 +65,10 @@ bool fixup_exception(struct pt_regs *regs)
                return false;
 
        switch (ex->type) {
-       case EX_TYPE_FIXUP:
-               return ex_handler_fixup(ex, regs);
        case EX_TYPE_BPF:
                return ex_handler_bpf(ex, regs);
        case EX_TYPE_UACCESS_ERR_ZERO:
+       case EX_TYPE_KACCESS_ERR_ZERO:
                return ex_handler_uaccess_err_zero(ex, regs);
        case EX_TYPE_LOAD_UNALIGNED_ZEROPAD:
                return ex_handler_load_unaligned_zeropad(ex, regs);
index c5e1176..cdf3ffa 100644 (file)
@@ -927,6 +927,5 @@ struct page *alloc_zeroed_user_highpage_movable(struct vm_area_struct *vma,
 void tag_clear_highpage(struct page *page)
 {
        mte_zero_clear_page_tags(page_address(page));
-       page_kasan_tag_reset(page);
        set_bit(PG_mte_tagged, &page->flags);
 }
index e2a5ec9..5307ffd 100644 (file)
@@ -100,16 +100,6 @@ int pud_huge(pud_t pud)
 #endif
 }
 
-/*
- * Select all bits except the pfn
- */
-static inline pgprot_t pte_pgprot(pte_t pte)
-{
-       unsigned long pfn = pte_pfn(pte);
-
-       return __pgprot(pte_val(pfn_pte(pfn, __pgprot(0))) ^ pte_val(pte));
-}
-
 static int find_num_contig(struct mm_struct *mm, unsigned long addr,
                           pte_t *ptep, size_t *pgsize)
 {
@@ -214,6 +204,19 @@ static pte_t get_clear_contig(struct mm_struct *mm,
        return orig_pte;
 }
 
+static pte_t get_clear_contig_flush(struct mm_struct *mm,
+                                   unsigned long addr,
+                                   pte_t *ptep,
+                                   unsigned long pgsize,
+                                   unsigned long ncontig)
+{
+       pte_t orig_pte = get_clear_contig(mm, addr, ptep, pgsize, ncontig);
+       struct vm_area_struct vma = TLB_FLUSH_VMA(mm, 0);
+
+       flush_tlb_range(&vma, addr, addr + (pgsize * ncontig));
+       return orig_pte;
+}
+
 /*
  * Changing some bits of contiguous entries requires us to follow a
  * Break-Before-Make approach, breaking the whole contiguous set
@@ -447,19 +450,20 @@ int huge_ptep_set_access_flags(struct vm_area_struct *vma,
        int ncontig, i;
        size_t pgsize = 0;
        unsigned long pfn = pte_pfn(pte), dpfn;
+       struct mm_struct *mm = vma->vm_mm;
        pgprot_t hugeprot;
        pte_t orig_pte;
 
        if (!pte_cont(pte))
                return ptep_set_access_flags(vma, addr, ptep, pte, dirty);
 
-       ncontig = find_num_contig(vma->vm_mm, addr, ptep, &pgsize);
+       ncontig = find_num_contig(mm, addr, ptep, &pgsize);
        dpfn = pgsize >> PAGE_SHIFT;
 
        if (!__cont_access_flags_changed(ptep, pte, ncontig))
                return 0;
 
-       orig_pte = get_clear_contig(vma->vm_mm, addr, ptep, pgsize, ncontig);
+       orig_pte = get_clear_contig_flush(mm, addr, ptep, pgsize, ncontig);
 
        /* Make sure we don't lose the dirty or young state */
        if (pte_dirty(orig_pte))
@@ -470,7 +474,7 @@ int huge_ptep_set_access_flags(struct vm_area_struct *vma,
 
        hugeprot = pte_pgprot(pte);
        for (i = 0; i < ncontig; i++, ptep++, addr += pgsize, pfn += dpfn)
-               set_pte_at(vma->vm_mm, addr, ptep, pfn_pte(pfn, hugeprot));
+               set_pte_at(mm, addr, ptep, pfn_pte(pfn, hugeprot));
 
        return 1;
 }
@@ -492,7 +496,7 @@ void huge_ptep_set_wrprotect(struct mm_struct *mm,
        ncontig = find_num_contig(mm, addr, ptep, &pgsize);
        dpfn = pgsize >> PAGE_SHIFT;
 
-       pte = get_clear_contig(mm, addr, ptep, pgsize, ncontig);
+       pte = get_clear_contig_flush(mm, addr, ptep, pgsize, ncontig);
        pte = pte_wrprotect(pte);
 
        hugeprot = pte_pgprot(pte);
@@ -505,17 +509,15 @@ void huge_ptep_set_wrprotect(struct mm_struct *mm,
 pte_t huge_ptep_clear_flush(struct vm_area_struct *vma,
                            unsigned long addr, pte_t *ptep)
 {
+       struct mm_struct *mm = vma->vm_mm;
        size_t pgsize;
        int ncontig;
-       pte_t orig_pte;
 
        if (!pte_cont(READ_ONCE(*ptep)))
                return ptep_clear_flush(vma, addr, ptep);
 
-       ncontig = find_num_contig(vma->vm_mm, addr, ptep, &pgsize);
-       orig_pte = get_clear_contig(vma->vm_mm, addr, ptep, pgsize, ncontig);
-       flush_tlb_range(vma, addr, addr + pgsize * ncontig);
-       return orig_pte;
+       ncontig = find_num_contig(mm, addr, ptep, &pgsize);
+       return get_clear_contig_flush(mm, addr, ptep, pgsize, ncontig);
 }
 
 static int __init hugetlbpage_init(void)
index 339ee84..b6ef26f 100644 (file)
@@ -389,7 +389,7 @@ void __init arm64_memblock_init(void)
 
        early_init_fdt_scan_reserved_mem();
 
-       if (!IS_ENABLED(CONFIG_ZONE_DMA) && !IS_ENABLED(CONFIG_ZONE_DMA32))
+       if (!defer_reserve_crashkernel())
                reserve_crashkernel();
 
        high_memory = __va(memblock_end_of_DRAM() - 1) + 1;
@@ -438,7 +438,7 @@ void __init bootmem_init(void)
         * request_standard_resources() depends on crashkernel's memory being
         * reserved, so do it here.
         */
-       if (IS_ENABLED(CONFIG_ZONE_DMA) || IS_ENABLED(CONFIG_ZONE_DMA32))
+       if (defer_reserve_crashkernel())
                reserve_crashkernel();
 
        memblock_dump_all();
index b21f91c..c5af103 100644 (file)
@@ -1,96 +1,22 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/*
- * Based on arch/arm/mm/ioremap.c
- *
- * (C) Copyright 1995 1996 Linus Torvalds
- * Hacked for ARM by Phil Blundell <philb@gnu.org>
- * Hacked to allow all architectures to build, and various cleanups
- * by Russell King
- * Copyright (C) 2012 ARM Ltd.
- */
 
-#include <linux/export.h>
 #include <linux/mm.h>
-#include <linux/vmalloc.h>
 #include <linux/io.h>
 
-#include <asm/fixmap.h>
-#include <asm/tlbflush.h>
-
-static void __iomem *__ioremap_caller(phys_addr_t phys_addr, size_t size,
-                                     pgprot_t prot, void *caller)
+bool ioremap_allowed(phys_addr_t phys_addr, size_t size, unsigned long prot)
 {
-       unsigned long last_addr;
-       unsigned long offset = phys_addr & ~PAGE_MASK;
-       int err;
-       unsigned long addr;
-       struct vm_struct *area;
+       unsigned long last_addr = phys_addr + size - 1;
 
-       /*
-        * Page align the mapping address and size, taking account of any
-        * offset.
-        */
-       phys_addr &= PAGE_MASK;
-       size = PAGE_ALIGN(size + offset);
+       /* Don't allow outside PHYS_MASK */
+       if (last_addr & ~PHYS_MASK)
+               return false;
 
-       /*
-        * Don't allow wraparound, zero size or outside PHYS_MASK.
-        */
-       last_addr = phys_addr + size - 1;
-       if (!size || last_addr < phys_addr || (last_addr & ~PHYS_MASK))
-               return NULL;
-
-       /*
-        * Don't allow RAM to be mapped.
-        */
+       /* Don't allow RAM to be mapped. */
        if (WARN_ON(pfn_is_map_memory(__phys_to_pfn(phys_addr))))
-               return NULL;
-
-       area = get_vm_area_caller(size, VM_IOREMAP, caller);
-       if (!area)
-               return NULL;
-       addr = (unsigned long)area->addr;
-       area->phys_addr = phys_addr;
-
-       err = ioremap_page_range(addr, addr + size, phys_addr, prot);
-       if (err) {
-               vunmap((void *)addr);
-               return NULL;
-       }
-
-       return (void __iomem *)(offset + addr);
-}
-
-void __iomem *__ioremap(phys_addr_t phys_addr, size_t size, pgprot_t prot)
-{
-       return __ioremap_caller(phys_addr, size, prot,
-                               __builtin_return_address(0));
-}
-EXPORT_SYMBOL(__ioremap);
-
-void iounmap(volatile void __iomem *io_addr)
-{
-       unsigned long addr = (unsigned long)io_addr & PAGE_MASK;
-
-       /*
-        * We could get an address outside vmalloc range in case
-        * of ioremap_cache() reusing a RAM mapping.
-        */
-       if (is_vmalloc_addr((void *)addr))
-               vunmap((void *)addr);
-}
-EXPORT_SYMBOL(iounmap);
-
-void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size)
-{
-       /* For normal memory we already have a cacheable mapping. */
-       if (pfn_is_map_memory(__phys_to_pfn(phys_addr)))
-               return (void __iomem *)__phys_to_virt(phys_addr);
+               return false;
 
-       return __ioremap_caller(phys_addr, size, __pgprot(PROT_NORMAL),
-                               __builtin_return_address(0));
+       return true;
 }
-EXPORT_SYMBOL(ioremap_cache);
 
 /*
  * Must be called after early_fixmap_init
index c12cd70..e969e68 100644 (file)
@@ -236,7 +236,7 @@ static void __init kasan_init_shadow(void)
         */
        memcpy(tmp_pg_dir, swapper_pg_dir, sizeof(tmp_pg_dir));
        dsb(ishst);
-       cpu_replace_ttbr1(lm_alias(tmp_pg_dir));
+       cpu_replace_ttbr1(lm_alias(tmp_pg_dir), idmap_pg_dir);
 
        clear_pgds(KASAN_SHADOW_START, KASAN_SHADOW_END);
 
@@ -280,7 +280,7 @@ static void __init kasan_init_shadow(void)
                                PAGE_KERNEL_RO));
 
        memset(kasan_early_shadow_page, KASAN_SHADOW_INIT, PAGE_SIZE);
-       cpu_replace_ttbr1(lm_alias(swapper_pg_dir));
+       cpu_replace_ttbr1(lm_alias(swapper_pg_dir), idmap_pg_dir);
 }
 
 static void __init kasan_init_depth(void)
index 626ec32..db7c4e6 100644 (file)
 #define NO_CONT_MAPPINGS       BIT(1)
 #define NO_EXEC_MAPPINGS       BIT(2)  /* assumes FEAT_HPDS is not used */
 
-u64 idmap_t0sz = TCR_T0SZ(VA_BITS_MIN);
-u64 idmap_ptrs_per_pgd = PTRS_PER_PGD;
+int idmap_t0sz __ro_after_init;
 
-u64 __section(".mmuoff.data.write") vabits_actual;
+#if VA_BITS > 48
+u64 vabits_actual __ro_after_init = VA_BITS_MIN;
 EXPORT_SYMBOL(vabits_actual);
+#endif
+
+u64 kimage_vaddr __ro_after_init = (u64)&_text;
+EXPORT_SYMBOL(kimage_vaddr);
 
 u64 kimage_voffset __ro_after_init;
 EXPORT_SYMBOL(kimage_voffset);
 
+u32 __boot_cpu_mode[] = { BOOT_CPU_MODE_EL2, BOOT_CPU_MODE_EL1 };
+
+/*
+ * The booting CPU updates the failed status @__early_cpu_boot_status,
+ * with MMU turned off.
+ */
+long __section(".mmuoff.data.write") __early_cpu_boot_status;
+
 /*
  * Empty_zero_page is a special page that is used for zero-initialized data
  * and COW.
@@ -388,6 +400,13 @@ static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys,
        } while (pgdp++, addr = next, addr != end);
 }
 
+#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
+extern __alias(__create_pgd_mapping)
+void create_kpti_ng_temp_pgd(pgd_t *pgdir, phys_addr_t phys, unsigned long virt,
+                            phys_addr_t size, pgprot_t prot,
+                            phys_addr_t (*pgtable_alloc)(int), int flags);
+#endif
+
 static phys_addr_t __pgd_pgtable_alloc(int shift)
 {
        void *ptr = (void *)__get_free_page(GFP_PGTABLE_KERNEL);
@@ -529,8 +548,7 @@ static void __init map_mem(pgd_t *pgdp)
 
 #ifdef CONFIG_KEXEC_CORE
        if (crash_mem_map) {
-               if (IS_ENABLED(CONFIG_ZONE_DMA) ||
-                   IS_ENABLED(CONFIG_ZONE_DMA32))
+               if (defer_reserve_crashkernel())
                        flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
                else if (crashk_res.end)
                        memblock_mark_nomap(crashk_res.start,
@@ -571,8 +589,7 @@ static void __init map_mem(pgd_t *pgdp)
         * through /sys/kernel/kexec_crash_size interface.
         */
 #ifdef CONFIG_KEXEC_CORE
-       if (crash_mem_map &&
-           !IS_ENABLED(CONFIG_ZONE_DMA) && !IS_ENABLED(CONFIG_ZONE_DMA32)) {
+       if (crash_mem_map && !defer_reserve_crashkernel()) {
                if (crashk_res.end) {
                        __map_memblock(pgdp, crashk_res.start,
                                       crashk_res.end + 1,
@@ -665,13 +682,9 @@ static int __init map_entry_trampoline(void)
                __set_fixmap(FIX_ENTRY_TRAMP_TEXT1 - i,
                             pa_start + i * PAGE_SIZE, prot);
 
-       if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
-               extern char __entry_tramp_data_start[];
-
-               __set_fixmap(FIX_ENTRY_TRAMP_DATA,
-                            __pa_symbol(__entry_tramp_data_start),
-                            PAGE_KERNEL_RO);
-       }
+       if (IS_ENABLED(CONFIG_RELOCATABLE))
+               __set_fixmap(FIX_ENTRY_TRAMP_TEXT1 - i,
+                            pa_start + i * PAGE_SIZE, PAGE_KERNEL_RO);
 
        return 0;
 }
@@ -762,22 +775,57 @@ static void __init map_kernel(pgd_t *pgdp)
        kasan_copy_shadow(pgdp);
 }
 
+static void __init create_idmap(void)
+{
+       u64 start = __pa_symbol(__idmap_text_start);
+       u64 size = __pa_symbol(__idmap_text_end) - start;
+       pgd_t *pgd = idmap_pg_dir;
+       u64 pgd_phys;
+
+       /* check if we need an additional level of translation */
+       if (VA_BITS < 48 && idmap_t0sz < (64 - VA_BITS_MIN)) {
+               pgd_phys = early_pgtable_alloc(PAGE_SHIFT);
+               set_pgd(&idmap_pg_dir[start >> VA_BITS],
+                       __pgd(pgd_phys | P4D_TYPE_TABLE));
+               pgd = __va(pgd_phys);
+       }
+       __create_pgd_mapping(pgd, start, start, size, PAGE_KERNEL_ROX,
+                            early_pgtable_alloc, 0);
+
+       if (IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0)) {
+               extern u32 __idmap_kpti_flag;
+               u64 pa = __pa_symbol(&__idmap_kpti_flag);
+
+               /*
+                * The KPTI G-to-nG conversion code needs a read-write mapping
+                * of its synchronization flag in the ID map.
+                */
+               __create_pgd_mapping(pgd, pa, pa, sizeof(u32), PAGE_KERNEL,
+                                    early_pgtable_alloc, 0);
+       }
+}
+
 void __init paging_init(void)
 {
        pgd_t *pgdp = pgd_set_fixmap(__pa_symbol(swapper_pg_dir));
+       extern pgd_t init_idmap_pg_dir[];
+
+       idmap_t0sz = 63UL - __fls(__pa_symbol(_end) | GENMASK(VA_BITS_MIN - 1, 0));
 
        map_kernel(pgdp);
        map_mem(pgdp);
 
        pgd_clear_fixmap();
 
-       cpu_replace_ttbr1(lm_alias(swapper_pg_dir));
+       cpu_replace_ttbr1(lm_alias(swapper_pg_dir), init_idmap_pg_dir);
        init_mm.pgd = swapper_pg_dir;
 
        memblock_phys_free(__pa_symbol(init_pg_dir),
                           __pa_symbol(init_pg_end) - __pa_symbol(init_pg_dir));
 
        memblock_allow_resize();
+
+       create_idmap();
 }
 
 /*
index a9e50e9..4334dec 100644 (file)
@@ -53,15 +53,6 @@ bool mte_restore_tags(swp_entry_t entry, struct page *page)
        if (!tags)
                return false;
 
-       page_kasan_tag_reset(page);
-       /*
-        * We need smp_wmb() in between setting the flags and clearing the
-        * tags because if another thread reads page->flags and builds a
-        * tagged address out of it, there is an actual dependency to the
-        * memory access, but on the current thread we do not guarantee that
-        * the new page->flags are visible before the tags were updated.
-        */
-       smp_wmb();
        mte_restore_page_tags(page_address(page), tags);
 
        return true;
index 50bbed9..7837a69 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/asm_pointer_auth.h>
 #include <asm/hwcap.h>
+#include <asm/kernel-pgtable.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/cpufeature.h>
 #include <asm/alternative.h>
@@ -200,34 +201,64 @@ SYM_FUNC_END(idmap_cpu_replace_ttbr1)
        .popsection
 
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
+
+#define KPTI_NG_PTE_FLAGS      (PTE_ATTRINDX(MT_NORMAL) | SWAPPER_PTE_FLAGS)
+
        .pushsection ".idmap.text", "awx"
 
-       .macro  __idmap_kpti_get_pgtable_ent, type
-       dc      cvac, cur_\()\type\()p          // Ensure any existing dirty
-       dmb     sy                              // lines are written back before
-       ldr     \type, [cur_\()\type\()p]       // loading the entry
-       tbz     \type, #0, skip_\()\type        // Skip invalid and
-       tbnz    \type, #11, skip_\()\type       // non-global entries
+       .macro  kpti_mk_tbl_ng, type, num_entries
+       add     end_\type\()p, cur_\type\()p, #\num_entries * 8
+.Ldo_\type:
+       ldr     \type, [cur_\type\()p]          // Load the entry
+       tbz     \type, #0, .Lnext_\type         // Skip invalid and
+       tbnz    \type, #11, .Lnext_\type        // non-global entries
+       orr     \type, \type, #PTE_NG           // Same bit for blocks and pages
+       str     \type, [cur_\type\()p]          // Update the entry
+       .ifnc   \type, pte
+       tbnz    \type, #1, .Lderef_\type
+       .endif
+.Lnext_\type:
+       add     cur_\type\()p, cur_\type\()p, #8
+       cmp     cur_\type\()p, end_\type\()p
+       b.ne    .Ldo_\type
        .endm
 
-       .macro __idmap_kpti_put_pgtable_ent_ng, type
-       orr     \type, \type, #PTE_NG           // Same bit for blocks and pages
-       str     \type, [cur_\()\type\()p]       // Update the entry and ensure
-       dmb     sy                              // that it is visible to all
-       dc      civac, cur_\()\type\()p         // CPUs.
+       /*
+        * Dereference the current table entry and map it into the temporary
+        * fixmap slot associated with the current level.
+        */
+       .macro  kpti_map_pgtbl, type, level
+       str     xzr, [temp_pte, #8 * (\level + 1)]      // break before make
+       dsb     nshst
+       add     pte, temp_pte, #PAGE_SIZE * (\level + 1)
+       lsr     pte, pte, #12
+       tlbi    vaae1, pte
+       dsb     nsh
+       isb
+
+       phys_to_pte pte, cur_\type\()p
+       add     cur_\type\()p, temp_pte, #PAGE_SIZE * (\level + 1)
+       orr     pte, pte, pte_flags
+       str     pte, [temp_pte, #8 * (\level + 1)]
+       dsb     nshst
        .endm
 
 /*
- * void __kpti_install_ng_mappings(int cpu, int num_cpus, phys_addr_t swapper)
+ * void __kpti_install_ng_mappings(int cpu, int num_secondaries, phys_addr_t temp_pgd,
+ *                                unsigned long temp_pte_va)
  *
  * Called exactly once from stop_machine context by each CPU found during boot.
  */
-__idmap_kpti_flag:
-       .long   1
+       .pushsection    ".data", "aw", %progbits
+SYM_DATA(__idmap_kpti_flag, .long 1)
+       .popsection
+
 SYM_FUNC_START(idmap_kpti_install_ng_mappings)
        cpu             .req    w0
+       temp_pte        .req    x0
        num_cpus        .req    w1
-       swapper_pa      .req    x2
+       pte_flags       .req    x1
+       temp_pgd_phys   .req    x2
        swapper_ttb     .req    x3
        flag_ptr        .req    x4
        cur_pgdp        .req    x5
@@ -235,17 +266,16 @@ SYM_FUNC_START(idmap_kpti_install_ng_mappings)
        pgd             .req    x7
        cur_pudp        .req    x8
        end_pudp        .req    x9
-       pud             .req    x10
        cur_pmdp        .req    x11
        end_pmdp        .req    x12
-       pmd             .req    x13
        cur_ptep        .req    x14
        end_ptep        .req    x15
        pte             .req    x16
+       valid           .req    x17
 
+       mov     x5, x3                          // preserve temp_pte arg
        mrs     swapper_ttb, ttbr1_el1
-       restore_ttbr1   swapper_ttb
-       adr     flag_ptr, __idmap_kpti_flag
+       adr_l   flag_ptr, __idmap_kpti_flag
 
        cbnz    cpu, __idmap_kpti_secondary
 
@@ -256,98 +286,71 @@ SYM_FUNC_START(idmap_kpti_install_ng_mappings)
        eor     w17, w17, num_cpus
        cbnz    w17, 1b
 
-       /* We need to walk swapper, so turn off the MMU. */
-       pre_disable_mmu_workaround
-       mrs     x17, sctlr_el1
-       bic     x17, x17, #SCTLR_ELx_M
-       msr     sctlr_el1, x17
+       /* Switch to the temporary page tables on this CPU only */
+       __idmap_cpu_set_reserved_ttbr1 x8, x9
+       offset_ttbr1 temp_pgd_phys, x8
+       msr     ttbr1_el1, temp_pgd_phys
        isb
 
+       mov     temp_pte, x5
+       mov     pte_flags, #KPTI_NG_PTE_FLAGS
+
        /* Everybody is enjoying the idmap, so we can rewrite swapper. */
        /* PGD */
-       mov     cur_pgdp, swapper_pa
-       add     end_pgdp, cur_pgdp, #(PTRS_PER_PGD * 8)
-do_pgd:        __idmap_kpti_get_pgtable_ent    pgd
-       tbnz    pgd, #1, walk_puds
-next_pgd:
-       __idmap_kpti_put_pgtable_ent_ng pgd
-skip_pgd:
-       add     cur_pgdp, cur_pgdp, #8
-       cmp     cur_pgdp, end_pgdp
-       b.ne    do_pgd
-
-       /* Publish the updated tables and nuke all the TLBs */
-       dsb     sy
-       tlbi    vmalle1is
-       dsb     ish
-       isb
+       adrp            cur_pgdp, swapper_pg_dir
+       kpti_map_pgtbl  pgd, 0
+       kpti_mk_tbl_ng  pgd, PTRS_PER_PGD
 
-       /* We're done: fire up the MMU again */
-       mrs     x17, sctlr_el1
-       orr     x17, x17, #SCTLR_ELx_M
-       set_sctlr_el1   x17
+       /* Ensure all the updated entries are visible to secondary CPUs */
+       dsb     ishst
+
+       /* We're done: fire up swapper_pg_dir again */
+       __idmap_cpu_set_reserved_ttbr1 x8, x9
+       msr     ttbr1_el1, swapper_ttb
+       isb
 
        /* Set the flag to zero to indicate that we're all done */
        str     wzr, [flag_ptr]
        ret
 
+.Lderef_pgd:
        /* PUD */
-walk_puds:
-       .if CONFIG_PGTABLE_LEVELS > 3
+       .if             CONFIG_PGTABLE_LEVELS > 3
+       pud             .req    x10
        pte_to_phys     cur_pudp, pgd
-       add     end_pudp, cur_pudp, #(PTRS_PER_PUD * 8)
-do_pud:        __idmap_kpti_get_pgtable_ent    pud
-       tbnz    pud, #1, walk_pmds
-next_pud:
-       __idmap_kpti_put_pgtable_ent_ng pud
-skip_pud:
-       add     cur_pudp, cur_pudp, 8
-       cmp     cur_pudp, end_pudp
-       b.ne    do_pud
-       b       next_pgd
-       .else /* CONFIG_PGTABLE_LEVELS <= 3 */
-       mov     pud, pgd
-       b       walk_pmds
-next_pud:
-       b       next_pgd
+       kpti_map_pgtbl  pud, 1
+       kpti_mk_tbl_ng  pud, PTRS_PER_PUD
+       b               .Lnext_pgd
+       .else           /* CONFIG_PGTABLE_LEVELS <= 3 */
+       pud             .req    pgd
+       .set            .Lnext_pud, .Lnext_pgd
        .endif
 
+.Lderef_pud:
        /* PMD */
-walk_pmds:
-       .if CONFIG_PGTABLE_LEVELS > 2
+       .if             CONFIG_PGTABLE_LEVELS > 2
+       pmd             .req    x13
        pte_to_phys     cur_pmdp, pud
-       add     end_pmdp, cur_pmdp, #(PTRS_PER_PMD * 8)
-do_pmd:        __idmap_kpti_get_pgtable_ent    pmd
-       tbnz    pmd, #1, walk_ptes
-next_pmd:
-       __idmap_kpti_put_pgtable_ent_ng pmd
-skip_pmd:
-       add     cur_pmdp, cur_pmdp, #8
-       cmp     cur_pmdp, end_pmdp
-       b.ne    do_pmd
-       b       next_pud
-       .else /* CONFIG_PGTABLE_LEVELS <= 2 */
-       mov     pmd, pud
-       b       walk_ptes
-next_pmd:
-       b       next_pud
+       kpti_map_pgtbl  pmd, 2
+       kpti_mk_tbl_ng  pmd, PTRS_PER_PMD
+       b               .Lnext_pud
+       .else           /* CONFIG_PGTABLE_LEVELS <= 2 */
+       pmd             .req    pgd
+       .set            .Lnext_pmd, .Lnext_pgd
        .endif
 
+.Lderef_pmd:
        /* PTE */
-walk_ptes:
        pte_to_phys     cur_ptep, pmd
-       add     end_ptep, cur_ptep, #(PTRS_PER_PTE * 8)
-do_pte:        __idmap_kpti_get_pgtable_ent    pte
-       __idmap_kpti_put_pgtable_ent_ng pte
-skip_pte:
-       add     cur_ptep, cur_ptep, #8
-       cmp     cur_ptep, end_ptep
-       b.ne    do_pte
-       b       next_pmd
+       kpti_map_pgtbl  pte, 3
+       kpti_mk_tbl_ng  pte, PTRS_PER_PTE
+       b               .Lnext_pmd
 
        .unreq  cpu
+       .unreq  temp_pte
        .unreq  num_cpus
-       .unreq  swapper_pa
+       .unreq  pte_flags
+       .unreq  temp_pgd_phys
        .unreq  cur_pgdp
        .unreq  end_pgdp
        .unreq  pgd
@@ -360,6 +363,7 @@ skip_pte:
        .unreq  cur_ptep
        .unreq  end_ptep
        .unreq  pte
+       .unreq  valid
 
        /* Secondary CPUs end up here */
 __idmap_kpti_secondary:
@@ -379,7 +383,6 @@ __idmap_kpti_secondary:
        cbnz    w16, 1b
 
        /* All done, act like nothing happened */
-       offset_ttbr1 swapper_ttb, x16
        msr     ttbr1_el1, swapper_ttb
        isb
        ret
@@ -395,6 +398,8 @@ SYM_FUNC_END(idmap_kpti_install_ng_mappings)
  *
  *     Initialise the processor for turning the MMU on.
  *
+ * Input:
+ *     x0 - actual number of VA bits (ignored unless VA_BITS > 48)
  * Output:
  *     Return in x0 the value of the SCTLR_EL1 register.
  */
@@ -464,12 +469,11 @@ SYM_FUNC_START(__cpu_setup)
        tcr_clear_errata_bits tcr, x9, x5
 
 #ifdef CONFIG_ARM64_VA_BITS_52
-       ldr_l           x9, vabits_actual
-       sub             x9, xzr, x9
+       sub             x9, xzr, x0
        add             x9, x9, #64
        tcr_set_t1sz    tcr, x9
 #else
-       ldr_l           x9, idmap_t0sz
+       idmap_get_t0sz  x9
 #endif
        tcr_set_t0sz    tcr, x9
 
index 507b203..7796537 100644 (file)
@@ -36,6 +36,7 @@ HAS_RNG
 HAS_SB
 HAS_STAGE2_FWB
 HAS_SYSREG_GIC_CPUIF
+HAS_TIDCP1
 HAS_TLB_RANGE
 HAS_VIRT_HOST_EXTN
 HAS_WFXT
@@ -61,6 +62,7 @@ WORKAROUND_1418040
 WORKAROUND_1463225
 WORKAROUND_1508412
 WORKAROUND_1542419
+WORKAROUND_1742098
 WORKAROUND_1902691
 WORKAROUND_2038923
 WORKAROUND_2064142
index 5c55509..db46192 100755 (executable)
@@ -88,7 +88,7 @@ END {
 
 # skip blank lines and comment lines
 /^$/ { next }
-/^#/ { next }
+/^[\t ]*#/ { next }
 
 /^SysregFields/ {
        change_block("SysregFields", "None", "SysregFields")
index ff5e552..9ae483e 100644 (file)
 # feature that introduces them (eg, FEAT_LS64_ACCDATA introduces enumeration
 # item ACCDATA) though it may be more taseful to do something else.
 
+Sysreg ID_AA64ZFR0_EL1 3       0       0       4       4
+Res0   63:60
+Enum   59:56   F64MM
+       0b0000  NI
+       0b0001  IMP
+EndEnum
+Enum   55:52   F32MM
+       0b0000  NI
+       0b0001  IMP
+EndEnum
+Res0   51:48
+Enum   47:44   I8MM
+       0b0000  NI
+       0b0001  IMP
+EndEnum
+Enum   43:40   SM4
+       0b0000  NI
+       0b0001  IMP
+EndEnum
+Res0   39:36
+Enum   35:32   SHA3
+       0b0000  NI
+       0b0001  IMP
+EndEnum
+Res0   31:24
+Enum   23:20   BF16
+       0b0000  NI
+       0b0001  IMP
+       0b0010  EBF16
+EndEnum
+Enum   19:16   BitPerm
+       0b0000  NI
+       0b0001  IMP
+EndEnum
+Res0   15:8
+Enum   7:4     AES
+       0b0000  NI
+       0b0001  IMP
+       0b0010  PMULL128
+EndEnum
+Enum   3:0     SVEver
+       0b0000  IMP
+       0b0001  SVE2
+EndEnum
+EndSysreg
+
+Sysreg ID_AA64SMFR0_EL1        3       0       0       4       5
+Enum   63      FA64
+       0b0     NI
+       0b1     IMP
+EndEnum
+Res0   62:60
+Field  59:56   SMEver
+Enum   55:52   I16I64
+       0b0000  NI
+       0b1111  IMP
+EndEnum
+Res0   51:49
+Enum   48      F64F64
+       0b0     NI
+       0b1     IMP
+EndEnum
+Res0   47:40
+Enum   39:36   I8I32
+       0b0000  NI
+       0b1111  IMP
+EndEnum
+Enum   35      F16F32
+       0b0     NI
+       0b1     IMP
+EndEnum
+Enum   34      B16F32
+       0b0     NI
+       0b1     IMP
+EndEnum
+Res0   33
+Enum   32      F32F32
+       0b0     NI
+       0b1     IMP
+EndEnum
+Res0   31:0
+EndSysreg
+
 Sysreg ID_AA64ISAR0_EL1        3       0       0       6       0
 Enum   63:60   RNDR
        0b0000  NI
@@ -114,6 +197,122 @@ EndEnum
 Res0   3:0
 EndSysreg
 
+Sysreg ID_AA64ISAR1_EL1        3       0       0       6       1
+Enum   63:60   LS64
+       0b0000  NI
+       0b0001  LS64
+       0b0010  LS64_V
+       0b0011  LS64_ACCDATA
+EndEnum
+Enum   59:56   XS
+       0b0000  NI
+       0b0001  IMP
+EndEnum
+Enum   55:52   I8MM
+       0b0000  NI
+       0b0001  IMP
+EndEnum
+Enum   51:48   DGH
+       0b0000  NI
+       0b0001  IMP
+EndEnum
+Enum   47:44   BF16
+       0b0000  NI
+       0b0001  IMP
+       0b0010  EBF16
+EndEnum
+Enum   43:40   SPECRES
+       0b0000  NI
+       0b0001  IMP
+EndEnum
+Enum   39:36   SB
+       0b0000  NI
+       0b0001  IMP
+EndEnum
+Enum   35:32   FRINTTS
+       0b0000  NI
+       0b0001  IMP
+EndEnum
+Enum   31:28   GPI
+       0b0000  NI
+       0b0001  IMP
+EndEnum
+Enum   27:24   GPA
+       0b0000  NI
+       0b0001  IMP
+EndEnum
+Enum   23:20   LRCPC
+       0b0000  NI
+       0b0001  IMP
+       0b0010  LRCPC2
+EndEnum
+Enum   19:16   FCMA
+       0b0000  NI
+       0b0001  IMP
+EndEnum
+Enum   15:12   JSCVT
+       0b0000  NI
+       0b0001  IMP
+EndEnum
+Enum   11:8    API
+       0b0000  NI
+       0b0001  PAuth
+       0b0010  EPAC
+       0b0011  PAuth2
+       0b0100  FPAC
+       0b0101  FPACCOMBINE
+EndEnum
+Enum   7:4     APA
+       0b0000  NI
+       0b0001  PAuth
+       0b0010  EPAC
+       0b0011  PAuth2
+       0b0100  FPAC
+       0b0101  FPACCOMBINE
+EndEnum
+Enum   3:0     DPB
+       0b0000  NI
+       0b0001  IMP
+       0b0010  DPB2
+EndEnum
+EndSysreg
+
+Sysreg ID_AA64ISAR2_EL1        3       0       0       6       2
+Res0   63:28
+Enum   27:24   PAC_frac
+       0b0000  NI
+       0b0001  IMP
+EndEnum
+Enum   23:20   BC
+       0b0000  NI
+       0b0001  IMP
+EndEnum
+Enum   19:16   MOPS
+       0b0000  NI
+       0b0001  IMP
+EndEnum
+Enum   15:12   APA3
+       0b0000  NI
+       0b0001  PAuth
+       0b0010  EPAC
+       0b0011  PAuth2
+       0b0100  FPAC
+       0b0101  FPACCOMBINE
+EndEnum
+Enum   11:8    GPA3
+       0b0000  NI
+       0b0001  IMP
+EndEnum
+Enum   7:4     RPRES
+       0b0000  NI
+       0b0001  IMP
+EndEnum
+Enum   3:0     WFxT
+       0b0000  NI
+       0b0010  IMP
+EndEnum
+EndSysreg
+
 Sysreg SCTLR_EL1       3       0       1       0       0
 Field  63      TIDCP
 Field  62      SPINMASK
@@ -257,6 +456,11 @@ Field      5:3     Ctype2
 Field  2:0     Ctype1
 EndSysreg
 
+Sysreg GMID_EL1        3       1       0       0       4
+Res0   63:4
+Field  3:0     BS
+EndSysreg
+
 Sysreg SMIDR_EL1       3       1       0       0       6
 Res0   63:32
 Field  31:24   IMPLEMENTER
@@ -273,6 +477,33 @@ Field      3:1     Level
 Field  0       InD
 EndSysreg
 
+Sysreg CTR_EL0 3       3       0       0       1
+Res0   63:38
+Field  37:32   TminLine
+Res1   31
+Res0   30
+Field  29      DIC
+Field  28      IDC
+Field  27:24   CWG
+Field  23:20   ERG
+Field  19:16   DminLine
+Enum   15:14   L1Ip
+       0b00    VPIPT
+       # This is named as AIVIVT in the ARM but documented as reserved
+       0b01    RESERVED
+       0b10    VIPT
+       0b11    PIPT
+EndEnum
+Res0   13:4
+Field  3:0     IminLine
+EndSysreg
+
+Sysreg DCZID_EL0       3       3       0       0       7
+Res0   63:5
+Field  4       DZP
+Field  3:0     BS
+EndSysreg
+
 Sysreg SVCR    3       3       4       2       2
 Res0   63:2
 Field  1       ZA
@@ -367,3 +598,36 @@ EndSysreg
 Sysreg TTBR1_EL1       3       0       2       0       1
 Fields TTBRx_EL1
 EndSysreg
+
+Sysreg LORSA_EL1       3       0       10      4       0
+Res0   63:52
+Field  51:16   SA
+Res0   15:1
+Field  0       Valid
+EndSysreg
+
+Sysreg LOREA_EL1       3       0       10      4       1
+Res0   63:52
+Field  51:48   EA_51_48
+Field  47:16   EA_47_16
+Res0   15:0
+EndSysreg
+
+Sysreg LORN_EL1        3       0       10      4       2
+Res0   63:8
+Field  7:0     Num
+EndSysreg
+
+Sysreg LORC_EL1        3       0       10      4       3
+Res0   63:10
+Field  9:2     DS
+Res0   1
+Field  0       EN
+EndSysreg
+
+Sysreg LORID_EL1       3       0       10      4       7
+Res0   63:24
+Field  23:16   LD
+Res0   15:8
+Field  7:0     LR
+EndSysreg
index 21d72b0..f55ba17 100644 (file)
@@ -42,7 +42,7 @@ config CSKY
        select HAVE_ARCH_AUDITSYSCALL
        select HAVE_ARCH_MMAP_RND_BITS
        select HAVE_ARCH_SECCOMP_FILTER
-       select HAVE_CONTEXT_TRACKING
+       select HAVE_CONTEXT_TRACKING_USER
        select HAVE_VIRT_CPU_ACCOUNTING_GEN
        select HAVE_DEBUG_BUGVERBOSE
        select HAVE_DEBUG_KMEMLEAK
index 3498e65..702861c 100644 (file)
@@ -4,21 +4,6 @@
 #define __ASM_CSKY_TLB_H
 
 #include <asm/cacheflush.h>
-
-#define tlb_start_vma(tlb, vma) \
-       do { \
-               if (!(tlb)->fullmm) \
-                       flush_cache_range(vma, (vma)->vm_start, (vma)->vm_end); \
-       }  while (0)
-
-#define tlb_end_vma(tlb, vma) \
-       do { \
-               if (!(tlb)->fullmm) \
-                       flush_tlb_range(vma, (vma)->vm_start, (vma)->vm_end); \
-       }  while (0)
-
-#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)
-
 #include <asm-generic/tlb.h>
 
 #endif /* __ASM_CSKY_TLB_H */
index a4ababf..547b4cd 100644 (file)
 .endm
 
 .macro context_tracking
-#ifdef CONFIG_CONTEXT_TRACKING
+#ifdef CONFIG_CONTEXT_TRACKING_USER
        mfcr    a0, epsr
        btsti   a0, 31
        bt      1f
-       jbsr    context_tracking_user_exit
+       jbsr    user_exit_callable
        ldw     a0, (sp, LSAVE_A0)
        ldw     a1, (sp, LSAVE_A1)
        ldw     a2, (sp, LSAVE_A2)
@@ -159,8 +159,8 @@ ret_from_exception:
        and     r10, r9
        cmpnei  r10, 0
        bt      exit_work
-#ifdef CONFIG_CONTEXT_TRACKING
-       jbsr    context_tracking_user_enter
+#ifdef CONFIG_CONTEXT_TRACKING_USER
+       jbsr    user_enter_callable
 #endif
 1:
 #ifdef CONFIG_PREEMPTION
index 35adcf8..9930085 100644 (file)
@@ -834,7 +834,7 @@ iosapic_unregister_intr (unsigned int gsi)
        if (iosapic_intr_info[irq].count == 0) {
 #ifdef CONFIG_SMP
                /* Clear affinity */
-               cpumask_setall(irq_get_affinity_mask(irq));
+               irq_data_update_affinity(irq_get_irq_data(irq), cpu_all_mask);
 #endif
                /* Clear the interrupt information */
                iosapic_intr_info[irq].dest = 0;
index ecef17c..275b9ea 100644 (file)
@@ -57,8 +57,8 @@ static char irq_redir [NR_IRQS]; // = { [0 ... NR_IRQS-1] = 1 };
 void set_irq_affinity_info (unsigned int irq, int hwid, int redir)
 {
        if (irq < NR_IRQS) {
-               cpumask_copy(irq_get_affinity_mask(irq),
-                            cpumask_of(cpu_logical_id(hwid)));
+               irq_data_update_affinity(irq_get_irq_data(irq),
+                                        cpumask_of(cpu_logical_id(hwid)));
                irq_redir[irq] = (char) (redir & 0xff);
        }
 }
index df5c28f..025e513 100644 (file)
@@ -37,7 +37,7 @@ static int ia64_set_msi_irq_affinity(struct irq_data *idata,
        msg.data = data;
 
        pci_write_msi_msg(irq, &msg);
-       cpumask_copy(irq_data_get_affinity_mask(idata), cpumask_of(cpu));
+       irq_data_update_affinity(idata, cpumask_of(cpu));
 
        return 0;
 }
@@ -132,7 +132,7 @@ static int dmar_msi_set_affinity(struct irq_data *data,
        msg.address_lo |= MSI_ADDR_DEST_ID_CPU(cpu_physical_id(cpu));
 
        dmar_msi_write(irq, &msg);
-       cpumask_copy(irq_data_get_affinity_mask(data), mask);
+       irq_data_update_affinity(data, mask);
 
        return 0;
 }
index 1920d52..fc24658 100644 (file)
@@ -2,6 +2,7 @@
 config LOONGARCH
        bool
        default y
+       select ACPI_GENERIC_GSI if ACPI
        select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI
        select ARCH_BINFMT_ELF_STATE
        select ARCH_ENABLE_MEMORY_HOTPLUG
@@ -54,7 +55,6 @@ config LOONGARCH
        select GENERIC_CMOS_UPDATE
        select GENERIC_CPU_AUTOPROBE
        select GENERIC_ENTRY
-       select GENERIC_FIND_FIRST_BIT
        select GENERIC_GETTIMEOFDAY
        select GENERIC_IRQ_MULTI_HANDLER
        select GENERIC_IRQ_PROBE
@@ -70,14 +70,12 @@ config LOONGARCH
        select GENERIC_TIME_VSYSCALL
        select GPIOLIB
        select HAVE_ARCH_AUDITSYSCALL
-       select HAVE_ARCH_COMPILER_H
        select HAVE_ARCH_MMAP_RND_BITS if MMU
        select HAVE_ARCH_SECCOMP_FILTER
        select HAVE_ARCH_TRACEHOOK
        select HAVE_ARCH_TRANSPARENT_HUGEPAGE
        select HAVE_ASM_MODVERSIONS
-       select HAVE_CONTEXT_TRACKING
-       select HAVE_COPY_THREAD_TLS
+       select HAVE_CONTEXT_TRACKING_USER
        select HAVE_DEBUG_STACKOVERFLOW
        select HAVE_DMA_CONTIGUOUS
        select HAVE_EXIT_THREAD
@@ -86,8 +84,6 @@ config LOONGARCH
        select HAVE_IOREMAP_PROT
        select HAVE_IRQ_EXIT_ON_IRQ_STACK
        select HAVE_IRQ_TIME_ACCOUNTING
-       select HAVE_MEMBLOCK
-       select HAVE_MEMBLOCK_NODE_MAP
        select HAVE_MOD_ARCH_SPECIFIC
        select HAVE_NMI
        select HAVE_PERF_EVENTS
@@ -112,6 +108,7 @@ config LOONGARCH
        select TRACE_IRQFLAGS_SUPPORT
        select USE_PERCPU_NUMA_NODE_ID
        select ZONE_DMA32
+       select MMU_GATHER_MERGE_VMAS if MMU
 
 config 32BIT
        bool
index 62044cd..c510821 100644 (file)
@@ -31,6 +31,148 @@ static inline bool acpi_has_cpu_in_madt(void)
 
 extern struct list_head acpi_wakeup_device_list;
 
+/*
+ * Temporary definitions until the core ACPICA code gets updated (see
+ * 1656837932-18257-1-git-send-email-lvjianmin@loongson.cn and its
+ * follow-ups for the "rationale").
+ *
+ * Once the "legal reasons" are cleared and that the code is merged,
+ * this can be dropped entierely.
+ */
+#if (ACPI_CA_VERSION == 0x20220331 && !defined(LOONGARCH_ACPICA_EXT))
+
+#define LOONGARCH_ACPICA_EXT   1
+
+#define        ACPI_MADT_TYPE_CORE_PIC         17
+#define        ACPI_MADT_TYPE_LIO_PIC          18
+#define        ACPI_MADT_TYPE_HT_PIC           19
+#define        ACPI_MADT_TYPE_EIO_PIC          20
+#define        ACPI_MADT_TYPE_MSI_PIC          21
+#define        ACPI_MADT_TYPE_BIO_PIC          22
+#define        ACPI_MADT_TYPE_LPC_PIC          23
+
+/* Values for Version field above */
+
+enum acpi_madt_core_pic_version {
+       ACPI_MADT_CORE_PIC_VERSION_NONE = 0,
+       ACPI_MADT_CORE_PIC_VERSION_V1 = 1,
+       ACPI_MADT_CORE_PIC_VERSION_RESERVED = 2 /* 2 and greater are reserved */
+};
+
+enum acpi_madt_lio_pic_version {
+       ACPI_MADT_LIO_PIC_VERSION_NONE = 0,
+       ACPI_MADT_LIO_PIC_VERSION_V1 = 1,
+       ACPI_MADT_LIO_PIC_VERSION_RESERVED = 2  /* 2 and greater are reserved */
+};
+
+enum acpi_madt_eio_pic_version {
+       ACPI_MADT_EIO_PIC_VERSION_NONE = 0,
+       ACPI_MADT_EIO_PIC_VERSION_V1 = 1,
+       ACPI_MADT_EIO_PIC_VERSION_RESERVED = 2  /* 2 and greater are reserved */
+};
+
+enum acpi_madt_ht_pic_version {
+       ACPI_MADT_HT_PIC_VERSION_NONE = 0,
+       ACPI_MADT_HT_PIC_VERSION_V1 = 1,
+       ACPI_MADT_HT_PIC_VERSION_RESERVED = 2   /* 2 and greater are reserved */
+};
+
+enum acpi_madt_bio_pic_version {
+       ACPI_MADT_BIO_PIC_VERSION_NONE = 0,
+       ACPI_MADT_BIO_PIC_VERSION_V1 = 1,
+       ACPI_MADT_BIO_PIC_VERSION_RESERVED = 2  /* 2 and greater are reserved */
+};
+
+enum acpi_madt_msi_pic_version {
+       ACPI_MADT_MSI_PIC_VERSION_NONE = 0,
+       ACPI_MADT_MSI_PIC_VERSION_V1 = 1,
+       ACPI_MADT_MSI_PIC_VERSION_RESERVED = 2  /* 2 and greater are reserved */
+};
+
+enum acpi_madt_lpc_pic_version {
+       ACPI_MADT_LPC_PIC_VERSION_NONE = 0,
+       ACPI_MADT_LPC_PIC_VERSION_V1 = 1,
+       ACPI_MADT_LPC_PIC_VERSION_RESERVED = 2  /* 2 and greater are reserved */
+};
+
+#pragma pack(1)
+
+/* Core Interrupt Controller */
+
+struct acpi_madt_core_pic {
+       struct acpi_subtable_header header;
+       u8 version;
+       u32 processor_id;
+       u32 core_id;
+       u32 flags;
+};
+
+/* Legacy I/O Interrupt Controller */
+
+struct acpi_madt_lio_pic {
+       struct acpi_subtable_header header;
+       u8 version;
+       u64 address;
+       u16 size;
+       u8 cascade[2];
+       u32 cascade_map[2];
+};
+
+/* Extend I/O Interrupt Controller */
+
+struct acpi_madt_eio_pic {
+       struct acpi_subtable_header header;
+       u8 version;
+       u8 cascade;
+       u8 node;
+       u64 node_map;
+};
+
+/* HT Interrupt Controller */
+
+struct acpi_madt_ht_pic {
+       struct acpi_subtable_header header;
+       u8 version;
+       u64 address;
+       u16 size;
+       u8 cascade[8];
+};
+
+/* Bridge I/O Interrupt Controller */
+
+struct acpi_madt_bio_pic {
+       struct acpi_subtable_header header;
+       u8 version;
+       u64 address;
+       u16 size;
+       u16 id;
+       u16 gsi_base;
+};
+
+/* MSI Interrupt Controller */
+
+struct acpi_madt_msi_pic {
+       struct acpi_subtable_header header;
+       u8 version;
+       u64 msg_address;
+       u32 start;
+       u32 count;
+};
+
+/* LPC Interrupt Controller */
+
+struct acpi_madt_lpc_pic {
+       struct acpi_subtable_header header;
+       u8 version;
+       u64 address;
+       u16 size;
+       u8 cascade;
+};
+
+#pragma pack()
+
+#endif
+
 #endif /* !CONFIG_ACPI */
 
 #define ACPI_TABLE_UPGRADE_MAX_PHYS ARCH_LOW_ADDRESS_LIMIT
index a1a0408..be037a4 100644 (file)
        nor     \dst, \src, zero
 .endm
 
-.macro bgt r0 r1 label
-       blt     \r1, \r0, \label
-.endm
-
-.macro bltz r0 label
-       blt     \r0, zero, \label
-.endm
-
-.macro bgez r0 label
-       bge     \r0, zero, \label
-.endm
-
 #endif /* _ASM_ASMMACRO_H */
index 979367a..6b9aca9 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/types.h>
 #include <asm/barrier.h>
 #include <asm/cmpxchg.h>
-#include <asm/compiler.h>
 
 #if __SIZEOF_LONG__ == 4
 #define __LL           "ll.w   "
@@ -157,27 +156,25 @@ static inline int arch_atomic_sub_if_positive(int i, atomic_t *v)
                __asm__ __volatile__(
                "1:     ll.w    %1, %2          # atomic_sub_if_positive\n"
                "       addi.w  %0, %1, %3                              \n"
-               "       or      %1, %0, $zero                           \n"
-               "       blt     %0, $zero, 2f                           \n"
+               "       move    %1, %0                                  \n"
+               "       bltz    %0, 2f                                  \n"
                "       sc.w    %1, %2                                  \n"
-               "       beq     $zero, %1, 1b                           \n"
+               "       beqz    %1, 1b                                  \n"
                "2:                                                     \n"
                __WEAK_LLSC_MB
-               : "=&r" (result), "=&r" (temp),
-                 "+" GCC_OFF_SMALL_ASM() (v->counter)
+               : "=&r" (result), "=&r" (temp), "+ZC" (v->counter)
                : "I" (-i));
        } else {
                __asm__ __volatile__(
                "1:     ll.w    %1, %2          # atomic_sub_if_positive\n"
                "       sub.w   %0, %1, %3                              \n"
-               "       or      %1, %0, $zero                           \n"
-               "       blt     %0, $zero, 2f                           \n"
+               "       move    %1, %0                                  \n"
+               "       bltz    %0, 2f                                  \n"
                "       sc.w    %1, %2                                  \n"
-               "       beq     $zero, %1, 1b                           \n"
+               "       beqz    %1, 1b                                  \n"
                "2:                                                     \n"
                __WEAK_LLSC_MB
-               : "=&r" (result), "=&r" (temp),
-                 "+" GCC_OFF_SMALL_ASM() (v->counter)
+               : "=&r" (result), "=&r" (temp), "+ZC" (v->counter)
                : "r" (i));
        }
 
@@ -320,27 +317,25 @@ static inline long arch_atomic64_sub_if_positive(long i, atomic64_t *v)
                __asm__ __volatile__(
                "1:     ll.d    %1, %2  # atomic64_sub_if_positive      \n"
                "       addi.d  %0, %1, %3                              \n"
-               "       or      %1, %0, $zero                           \n"
-               "       blt     %0, $zero, 2f                           \n"
+               "       move    %1, %0                                  \n"
+               "       bltz    %0, 2f                                  \n"
                "       sc.d    %1, %2                                  \n"
-               "       beq     %1, $zero, 1b                           \n"
+               "       beqz    %1, 1b                                  \n"
                "2:                                                     \n"
                __WEAK_LLSC_MB
-               : "=&r" (result), "=&r" (temp),
-                 "+" GCC_OFF_SMALL_ASM() (v->counter)
+               : "=&r" (result), "=&r" (temp), "+ZC" (v->counter)
                : "I" (-i));
        } else {
                __asm__ __volatile__(
                "1:     ll.d    %1, %2  # atomic64_sub_if_positive      \n"
                "       sub.d   %0, %1, %3                              \n"
-               "       or      %1, %0, $zero                           \n"
-               "       blt     %0, $zero, 2f                           \n"
+               "       move    %1, %0                                  \n"
+               "       bltz    %0, 2f                                  \n"
                "       sc.d    %1, %2                                  \n"
-               "       beq     %1, $zero, 1b                           \n"
+               "       beqz    %1, 1b                                  \n"
                "2:                                                     \n"
                __WEAK_LLSC_MB
-               : "=&r" (result), "=&r" (temp),
-                 "+" GCC_OFF_SMALL_ASM() (v->counter)
+               : "=&r" (result), "=&r" (temp), "+ZC" (v->counter)
                : "r" (i));
        }
 
index b6517ee..cda9776 100644 (file)
@@ -48,9 +48,9 @@ static inline unsigned long array_index_mask_nospec(unsigned long index,
        __asm__ __volatile__(
                "sltu   %0, %1, %2\n\t"
 #if (__SIZEOF_LONG__ == 4)
-               "sub.w  %0, $r0, %0\n\t"
+               "sub.w  %0, $zero, %0\n\t"
 #elif (__SIZEOF_LONG__ == 8)
-               "sub.d  %0, $r0, %0\n\t"
+               "sub.d  %0, $zero, %0\n\t"
 #endif
                : "=r" (mask)
                : "r" (index), "r" (size)
index 75b3a44..0a9b0fa 100644 (file)
@@ -55,9 +55,9 @@ static inline unsigned long __xchg(volatile void *ptr, unsigned long x,
        __asm__ __volatile__(                                           \
        "1:     " ld "  %0, %2          # __cmpxchg_asm \n"             \
        "       bne     %0, %z3, 2f                     \n"             \
-       "       or      $t0, %z4, $zero                 \n"             \
+       "       move    $t0, %z4                        \n"             \
        "       " st "  $t0, %1                         \n"             \
-       "       beq     $zero, $t0, 1b                  \n"             \
+       "       beqz    $t0, 1b                         \n"             \
        "2:                                             \n"             \
        __WEAK_LLSC_MB                                                  \
        : "=&r" (__ret), "=ZB"(*m)                                      \
diff --git a/arch/loongarch/include/asm/compiler.h b/arch/loongarch/include/asm/compiler.h
deleted file mode 100644 (file)
index 657cebe..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
- */
-#ifndef _ASM_COMPILER_H
-#define _ASM_COMPILER_H
-
-#define GCC_OFF_SMALL_ASM() "ZC"
-
-#define LOONGARCH_ISA_LEVEL "loongarch"
-#define LOONGARCH_ISA_ARCH_LEVEL "arch=loongarch"
-#define LOONGARCH_ISA_LEVEL_RAW loongarch
-#define LOONGARCH_ISA_ARCH_LEVEL_RAW LOONGARCH_ISA_LEVEL_RAW
-
-#endif /* _ASM_COMPILER_H */
index f3960b1..5f3ff47 100644 (file)
@@ -288,8 +288,6 @@ struct arch_elf_state {
        .interp_fp_abi = LOONGARCH_ABI_FP_ANY,  \
 }
 
-#define elf_read_implies_exec(ex, exec_stk) (exec_stk == EXSTACK_DEFAULT)
-
 extern int arch_elf_pt_proc(void *ehdr, void *phdr, struct file *elf,
                            bool is_interp, struct arch_elf_state *state);
 
index adb16e4..b6be527 100644 (file)
@@ -48,6 +48,5 @@
 #define fcsr1  $r1
 #define fcsr2  $r2
 #define fcsr3  $r3
-#define vcsr16 $r16
 
 #endif /* _ASM_FPREGDEF_H */
index 9de8231..feb6658 100644 (file)
@@ -8,7 +8,6 @@
 #include <linux/futex.h>
 #include <linux/uaccess.h>
 #include <asm/barrier.h>
-#include <asm/compiler.h>
 #include <asm/errno.h>
 
 #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg)             \
@@ -17,7 +16,7 @@
        "1:     ll.w    %1, %4 # __futex_atomic_op\n"           \
        "       " insn  "                               \n"     \
        "2:     sc.w    $t0, %2                         \n"     \
-       "       beq     $t0, $zero, 1b                  \n"     \
+       "       beqz    $t0, 1b                         \n"     \
        "3:                                             \n"     \
        "       .section .fixup,\"ax\"                  \n"     \
        "4:     li.w    %0, %6                          \n"     \
@@ -82,9 +81,9 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newv
        "# futex_atomic_cmpxchg_inatomic                        \n"
        "1:     ll.w    %1, %3                                  \n"
        "       bne     %1, %z4, 3f                             \n"
-       "       or      $t0, %z5, $zero                         \n"
+       "       move    $t0, %z5                                \n"
        "2:     sc.w    $t0, %2                                 \n"
-       "       beq     $zero, $t0, 1b                          \n"
+       "       beqz    $t0, 1b                                 \n"
        "3:                                                     \n"
        __WEAK_LLSC_MB
        "       .section .fixup,\"ax\"                          \n"
@@ -95,8 +94,8 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newv
        "       "__UA_ADDR "\t1b, 4b                            \n"
        "       "__UA_ADDR "\t2b, 4b                            \n"
        "       .previous                                       \n"
-       : "+r" (ret), "=&r" (val), "=" GCC_OFF_SMALL_ASM() (*uaddr)
-       : GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oldval), "Jr" (newval),
+       : "+r" (ret), "=&r" (val), "=ZC" (*uaddr)
+       : "ZC" (*uaddr), "Jr" (oldval), "Jr" (newval),
          "i" (-EFAULT)
        : "memory", "t0");
 
index ace3ea6..149b212 100644 (file)
@@ -35,9 +35,6 @@ static inline bool on_irq_stack(int cpu, unsigned long sp)
        return (low <= sp && sp <= high);
 }
 
-int get_ipi_irq(void);
-int get_pmc_irq(void);
-int get_timer_irq(void);
 void spurious_interrupt(void);
 
 #define NR_IRQS_LEGACY 16
@@ -48,6 +45,14 @@ void arch_trigger_cpumask_backtrace(const struct cpumask *mask, bool exclude_sel
 #define MAX_IO_PICS 2
 #define NR_IRQS        (64 + (256 * MAX_IO_PICS))
 
+struct acpi_vector_group {
+       int node;
+       int pci_segment;
+       struct irq_domain *parent;
+};
+extern struct acpi_vector_group pch_group[MAX_IO_PICS];
+extern struct acpi_vector_group msi_group[MAX_IO_PICS];
+
 #define CORES_PER_EIO_NODE     4
 
 #define LOONGSON_CPU_UART0_VEC         10 /* CPU UART0 */
@@ -79,15 +84,6 @@ void arch_trigger_cpumask_backtrace(const struct cpumask *mask, bool exclude_sel
 extern int find_pch_pic(u32 gsi);
 extern int eiointc_get_node(int id);
 
-static inline void eiointc_enable(void)
-{
-       uint64_t misc;
-
-       misc = iocsr_read64(LOONGARCH_IOCSR_MISC_FUNC);
-       misc |= IOCSR_MISC_FUNC_EXT_IOI_EN;
-       iocsr_write64(misc, LOONGARCH_IOCSR_MISC_FUNC);
-}
-
 struct acpi_madt_lio_pic;
 struct acpi_madt_eio_pic;
 struct acpi_madt_ht_pic;
@@ -95,21 +91,29 @@ struct acpi_madt_bio_pic;
 struct acpi_madt_msi_pic;
 struct acpi_madt_lpc_pic;
 
-struct irq_domain *loongarch_cpu_irq_init(void);
-
-struct irq_domain *liointc_acpi_init(struct irq_domain *parent,
+int liointc_acpi_init(struct irq_domain *parent,
                                        struct acpi_madt_lio_pic *acpi_liointc);
-struct irq_domain *eiointc_acpi_init(struct irq_domain *parent,
+int eiointc_acpi_init(struct irq_domain *parent,
                                        struct acpi_madt_eio_pic *acpi_eiointc);
 
 struct irq_domain *htvec_acpi_init(struct irq_domain *parent,
                                        struct acpi_madt_ht_pic *acpi_htvec);
-struct irq_domain *pch_lpc_acpi_init(struct irq_domain *parent,
+int pch_lpc_acpi_init(struct irq_domain *parent,
                                        struct acpi_madt_lpc_pic *acpi_pchlpc);
-struct irq_domain *pch_msi_acpi_init(struct irq_domain *parent,
+#if IS_ENABLED(CONFIG_LOONGSON_PCH_MSI)
+int pch_msi_acpi_init(struct irq_domain *parent,
                                        struct acpi_madt_msi_pic *acpi_pchmsi);
-struct irq_domain *pch_pic_acpi_init(struct irq_domain *parent,
+#else
+static inline int pch_msi_acpi_init(struct irq_domain *parent,
+                                       struct acpi_madt_msi_pic *acpi_pchmsi)
+{
+       return 0;
+}
+#endif
+int pch_pic_acpi_init(struct irq_domain *parent,
                                        struct acpi_madt_bio_pic *acpi_pchpic);
+int find_pch_pic(u32 gsi);
+struct fwnode_handle *get_pch_msi_handle(int pci_segment);
 
 extern struct acpi_madt_lio_pic *acpi_liointc;
 extern struct acpi_madt_eio_pic *acpi_eiointc[MAX_IO_PICS];
@@ -119,11 +123,10 @@ extern struct acpi_madt_lpc_pic *acpi_pchlpc;
 extern struct acpi_madt_msi_pic *acpi_pchmsi[MAX_IO_PICS];
 extern struct acpi_madt_bio_pic *acpi_pchpic[MAX_IO_PICS];
 
-extern struct irq_domain *cpu_domain;
-extern struct irq_domain *liointc_domain;
-extern struct irq_domain *pch_lpc_domain;
-extern struct irq_domain *pch_msi_domain[MAX_IO_PICS];
-extern struct irq_domain *pch_pic_domain[MAX_IO_PICS];
+extern struct fwnode_handle *cpuintc_handle;
+extern struct fwnode_handle *liointc_handle;
+extern struct fwnode_handle *pch_lpc_handle;
+extern struct fwnode_handle *pch_pic_handle[MAX_IO_PICS];
 
 extern irqreturn_t loongson3_ipi_interrupt(int irq, void *dev);
 
index 52121cd..319a8c6 100644 (file)
@@ -9,7 +9,6 @@
 
 #include <linux/compiler.h>
 #include <linux/stringify.h>
-#include <asm/compiler.h>
 #include <asm/loongarch.h>
 
 static inline void arch_local_irq_enable(void)
index 2052a22..65fbbae 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/bitops.h>
 #include <linux/atomic.h>
 #include <asm/cmpxchg.h>
-#include <asm/compiler.h>
 
 typedef struct {
        atomic_long_t a;
index 6a80387..6e8f697 100644 (file)
@@ -39,18 +39,6 @@ extern const struct plat_smp_ops loongson3_smp_ops;
 
 #define MAX_PACKAGES 16
 
-/* Chip Config register of each physical cpu package */
-extern u64 loongson_chipcfg[MAX_PACKAGES];
-#define LOONGSON_CHIPCFG(id) (*(volatile u32 *)(loongson_chipcfg[id]))
-
-/* Chip Temperature register of each physical cpu package */
-extern u64 loongson_chiptemp[MAX_PACKAGES];
-#define LOONGSON_CHIPTEMP(id) (*(volatile u32 *)(loongson_chiptemp[id]))
-
-/* Freq Control register of each physical cpu package */
-extern u64 loongson_freqctrl[MAX_PACKAGES];
-#define LOONGSON_FREQCTRL(id) (*(volatile u32 *)(loongson_freqctrl[id]))
-
 #define xconf_readl(addr) readl(addr)
 #define xconf_readq(addr) readq(addr)
 
@@ -58,7 +46,7 @@ static inline void xconf_writel(u32 val, volatile void __iomem *addr)
 {
        asm volatile (
        "       st.w    %[v], %[hw], 0  \n"
-       "       ld.b    $r0, %[hw], 0   \n"
+       "       ld.b    $zero, %[hw], 0 \n"
        :
        : [hw] "r" (addr), [v] "r" (val)
        );
@@ -68,7 +56,7 @@ static inline void xconf_writeq(u64 val64, volatile void __iomem *addr)
 {
        asm volatile (
        "       st.d    %[v], %[hw], 0  \n"
-       "       ld.b    $r0, %[hw], 0   \n"
+       "       ld.b    $zero, %[hw], 0 \n"
        :
        : [hw] "r" (addr),  [v] "r" (val64)
        );
index 3dba498..dc47fc7 100644 (file)
@@ -6,6 +6,7 @@
 #define _ASM_PAGE_H
 
 #include <linux/const.h>
+#include <asm/addrspace.h>
 
 /*
  * PAGE_SHIFT determines the page size
index 1d63c93..57ec45a 100644 (file)
@@ -80,7 +80,6 @@ BUILD_FPR_ACCESS(64)
 
 struct loongarch_fpu {
        unsigned int    fcsr;
-       unsigned int    vcsr;
        uint64_t        fcc;    /* 8x8 */
        union fpureg    fpr[NUM_FPU_REGS];
 };
@@ -161,7 +160,6 @@ struct thread_struct {
         */                                                     \
        .fpu                    = {                             \
                .fcsr           = 0,                            \
-               .vcsr           = 0,                            \
                .fcc            = 0,                            \
                .fpr            = {{{0,},},},                   \
        },                                                      \
index 26483e3..6b5c2a7 100644 (file)
 static __always_inline void prepare_frametrace(struct pt_regs *regs)
 {
        __asm__ __volatile__(
-               /* Save $r1 */
+               /* Save $ra */
                STORE_ONE_REG(1)
-               /* Use $r1 to save PC */
-               "pcaddi $r1, 0\n\t"
-               STR_LONG_S " $r1, %0\n\t"
-               /* Restore $r1 */
-               STR_LONG_L " $r1, %1, "STR_LONGSIZE"\n\t"
+               /* Use $ra to save PC */
+               "pcaddi $ra, 0\n\t"
+               STR_LONG_S " $ra, %0\n\t"
+               /* Restore $ra */
+               STR_LONG_L " $ra, %1, "STR_LONGSIZE"\n\t"
                STORE_ONE_REG(2)
                STORE_ONE_REG(3)
                STORE_ONE_REG(4)
index 99beb11..b7dd9f1 100644 (file)
@@ -44,14 +44,14 @@ struct thread_info {
 }
 
 /* How to get the thread information struct from C. */
-register struct thread_info *__current_thread_info __asm__("$r2");
+register struct thread_info *__current_thread_info __asm__("$tp");
 
 static inline struct thread_info *current_thread_info(void)
 {
        return __current_thread_info;
 }
 
-register unsigned long current_stack_pointer __asm__("$r3");
+register unsigned long current_stack_pointer __asm__("$sp");
 
 #endif /* !__ASSEMBLY__ */
 
index 4f629ae..dd24f58 100644 (file)
@@ -137,16 +137,6 @@ static inline void invtlb_all(u32 op, u32 info, u64 addr)
                );
 }
 
-/*
- * LoongArch doesn't need any special per-pte or per-vma handling, except
- * we need to flush cache for area to be unmapped.
- */
-#define tlb_start_vma(tlb, vma)                                        \
-       do {                                                    \
-               if (!(tlb)->fullmm)                             \
-                       flush_cache_range(vma, vma->vm_start, vma->vm_end); \
-       }  while (0)
-#define tlb_end_vma(tlb, vma) do { } while (0)
 #define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0)
 
 static void tlb_flush(struct mmu_gather *tlb);
index 217c6a3..2b44edc 100644 (file)
@@ -162,7 +162,7 @@ do {                                                                        \
        "2:                                                     \n"     \
        "       .section .fixup,\"ax\"                          \n"     \
        "3:     li.w    %0, %3                                  \n"     \
-       "       or      %1, $r0, $r0                            \n"     \
+       "       move    %1, $zero                               \n"     \
        "       b       2b                                      \n"     \
        "       .previous                                       \n"     \
        "       .section __ex_table,\"a\"                       \n"     \
index bb729ee..03aa145 100644 (file)
@@ -25,7 +25,6 @@ EXPORT_SYMBOL(acpi_pci_disabled);
 int acpi_strict = 1; /* We have no workarounds on LoongArch */
 int num_processors;
 int disabled_cpus;
-enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_PLATFORM;
 
 u64 acpi_saved_sp;
 
@@ -33,70 +32,6 @@ u64 acpi_saved_sp;
 
 #define PREFIX                 "ACPI: "
 
-int acpi_gsi_to_irq(u32 gsi, unsigned int *irqp)
-{
-       if (irqp != NULL)
-               *irqp = acpi_register_gsi(NULL, gsi, -1, -1);
-       return (*irqp >= 0) ? 0 : -EINVAL;
-}
-EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
-
-int acpi_isa_irq_to_gsi(unsigned int isa_irq, u32 *gsi)
-{
-       if (gsi)
-               *gsi = isa_irq;
-       return 0;
-}
-
-/*
- * success: return IRQ number (>=0)
- * failure: return < 0
- */
-int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
-{
-       struct irq_fwspec fwspec;
-
-       switch (gsi) {
-       case GSI_MIN_CPU_IRQ ... GSI_MAX_CPU_IRQ:
-               fwspec.fwnode = liointc_domain->fwnode;
-               fwspec.param[0] = gsi - GSI_MIN_CPU_IRQ;
-               fwspec.param_count = 1;
-
-               return irq_create_fwspec_mapping(&fwspec);
-
-       case GSI_MIN_LPC_IRQ ... GSI_MAX_LPC_IRQ:
-               if (!pch_lpc_domain)
-                       return -EINVAL;
-
-               fwspec.fwnode = pch_lpc_domain->fwnode;
-               fwspec.param[0] = gsi - GSI_MIN_LPC_IRQ;
-               fwspec.param[1] = acpi_dev_get_irq_type(trigger, polarity);
-               fwspec.param_count = 2;
-
-               return irq_create_fwspec_mapping(&fwspec);
-
-       case GSI_MIN_PCH_IRQ ... GSI_MAX_PCH_IRQ:
-               if (!pch_pic_domain[0])
-                       return -EINVAL;
-
-               fwspec.fwnode = pch_pic_domain[0]->fwnode;
-               fwspec.param[0] = gsi - GSI_MIN_PCH_IRQ;
-               fwspec.param[1] = IRQ_TYPE_LEVEL_HIGH;
-               fwspec.param_count = 2;
-
-               return irq_create_fwspec_mapping(&fwspec);
-       }
-
-       return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(acpi_register_gsi);
-
-void acpi_unregister_gsi(u32 gsi)
-{
-
-}
-EXPORT_SYMBOL_GPL(acpi_unregister_gsi);
-
 void __init __iomem * __acpi_map_table(unsigned long phys, unsigned long size)
 {
 
index bfb65eb..20cd9e1 100644 (file)
@@ -166,7 +166,6 @@ void output_thread_fpu_defines(void)
 
        OFFSET(THREAD_FCSR, loongarch_fpu, fcsr);
        OFFSET(THREAD_FCC,  loongarch_fpu, fcc);
-       OFFSET(THREAD_VCSR, loongarch_fpu, vcsr);
        BLANK();
 }
 
index b38f548..4662b06 100644 (file)
@@ -4,8 +4,9 @@
  *
  * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
  */
-#include <asm/cpu-info.h>
 #include <linux/cacheinfo.h>
+#include <asm/bootinfo.h>
+#include <asm/cpu-info.h>
 
 /* Populates leaf and increments to next leaf */
 #define populate_cache(cache, leaf, c_level, c_type)           \
@@ -17,6 +18,8 @@ do {                                                          \
        leaf->ways_of_associativity = c->cache.ways;            \
        leaf->size = c->cache.linesz * c->cache.sets *          \
                c->cache.ways;                                  \
+       if (leaf->level > 2)                                    \
+               leaf->size *= nodes_per_package;                \
        leaf++;                                                 \
 } while (0)
 
@@ -95,11 +98,15 @@ static void cache_cpumap_setup(unsigned int cpu)
 
 int populate_cache_leaves(unsigned int cpu)
 {
-       int level = 1;
+       int level = 1, nodes_per_package = 1;
        struct cpuinfo_loongarch *c = &current_cpu_data;
        struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
        struct cacheinfo *this_leaf = this_cpu_ci->info_list;
 
+       if (loongson_sysconf.nr_nodes > 1)
+               nodes_per_package = loongson_sysconf.cores_per_package
+                                       / loongson_sysconf.cores_per_node;
+
        if (c->icache.waysize) {
                populate_cache(dcache, this_leaf, level, CACHE_TYPE_DATA);
                populate_cache(icache, this_leaf, level++, CACHE_TYPE_INST);
index d5b3dbc..d53b631 100644 (file)
@@ -27,7 +27,7 @@ SYM_FUNC_START(handle_syscall)
 
        addi.d  sp, sp, -PT_SIZE
        cfi_st  t2, PT_R3
-       cfi_rel_offset  sp, PT_R3
+       cfi_rel_offset  sp, PT_R3
        st.d    zero, sp, PT_R0
        csrrd   t2, LOONGARCH_CSR_PRMD
        st.d    t2, sp, PT_PRMD
@@ -50,7 +50,7 @@ SYM_FUNC_START(handle_syscall)
        cfi_st  a7, PT_R11
        csrrd   ra, LOONGARCH_CSR_ERA
        st.d    ra, sp, PT_ERA
-       cfi_rel_offset ra, PT_ERA
+       cfi_rel_offset  ra, PT_ERA
 
        cfi_st  tp, PT_R2
        cfi_st  u0, PT_R21
index 467946e..82b478a 100644 (file)
@@ -17,21 +17,6 @@ u64 efi_system_table;
 struct loongson_system_configuration loongson_sysconf;
 EXPORT_SYMBOL(loongson_sysconf);
 
-u64 loongson_chipcfg[MAX_PACKAGES];
-u64 loongson_chiptemp[MAX_PACKAGES];
-u64 loongson_freqctrl[MAX_PACKAGES];
-unsigned long long smp_group[MAX_PACKAGES];
-
-static void __init register_addrs_set(u64 *registers, const u64 addr, int num)
-{
-       u64 i;
-
-       for (i = 0; i < num; i++) {
-               *registers = (i << 44) | addr;
-               registers++;
-       }
-}
-
 void __init init_environ(void)
 {
        int efi_boot = fw_arg0;
@@ -50,11 +35,6 @@ void __init init_environ(void)
        efi_memmap_init_early(&data);
        memblock_reserve(data.phys_map & PAGE_MASK,
                         PAGE_ALIGN(data.size + (data.phys_map & ~PAGE_MASK)));
-
-       register_addrs_set(smp_group, TO_UNCACHE(0x1fe01000), 16);
-       register_addrs_set(loongson_chipcfg, TO_UNCACHE(0x1fe00180), 16);
-       register_addrs_set(loongson_chiptemp, TO_UNCACHE(0x1fe0019c), 16);
-       register_addrs_set(loongson_freqctrl, TO_UNCACHE(0x1fe001d0), 16);
 }
 
 static int __init init_cpu_fullname(void)
index 75c6ce0..576b337 100644 (file)
        .endm
 
        .macro sc_save_fp base
-       EX      fst.d $f0,  \base, (0 * FPU_REG_WIDTH)
-       EX      fst.d $f1,  \base, (1 * FPU_REG_WIDTH)
-       EX      fst.d $f2,  \base, (2 * FPU_REG_WIDTH)
-       EX      fst.d $f3,  \base, (3 * FPU_REG_WIDTH)
-       EX      fst.d $f4,  \base, (4 * FPU_REG_WIDTH)
-       EX      fst.d $f5,  \base, (5 * FPU_REG_WIDTH)
-       EX      fst.d $f6,  \base, (6 * FPU_REG_WIDTH)
-       EX      fst.d $f7,  \base, (7 * FPU_REG_WIDTH)
-       EX      fst.d $f8,  \base, (8 * FPU_REG_WIDTH)
-       EX      fst.d $f9,  \base, (9 * FPU_REG_WIDTH)
-       EX      fst.d $f10, \base, (10 * FPU_REG_WIDTH)
-       EX      fst.d $f11, \base, (11 * FPU_REG_WIDTH)
-       EX      fst.d $f12, \base, (12 * FPU_REG_WIDTH)
-       EX      fst.d $f13, \base, (13 * FPU_REG_WIDTH)
-       EX      fst.d $f14, \base, (14 * FPU_REG_WIDTH)
-       EX      fst.d $f15, \base, (15 * FPU_REG_WIDTH)
-       EX      fst.d $f16, \base, (16 * FPU_REG_WIDTH)
-       EX      fst.d $f17, \base, (17 * FPU_REG_WIDTH)
-       EX      fst.d $f18, \base, (18 * FPU_REG_WIDTH)
-       EX      fst.d $f19, \base, (19 * FPU_REG_WIDTH)
-       EX      fst.d $f20, \base, (20 * FPU_REG_WIDTH)
-       EX      fst.d $f21, \base, (21 * FPU_REG_WIDTH)
-       EX      fst.d $f22, \base, (22 * FPU_REG_WIDTH)
-       EX      fst.d $f23, \base, (23 * FPU_REG_WIDTH)
-       EX      fst.d $f24, \base, (24 * FPU_REG_WIDTH)
-       EX      fst.d $f25, \base, (25 * FPU_REG_WIDTH)
-       EX      fst.d $f26, \base, (26 * FPU_REG_WIDTH)
-       EX      fst.d $f27, \base, (27 * FPU_REG_WIDTH)
-       EX      fst.d $f28, \base, (28 * FPU_REG_WIDTH)
-       EX      fst.d $f29, \base, (29 * FPU_REG_WIDTH)
-       EX      fst.d $f30, \base, (30 * FPU_REG_WIDTH)
-       EX      fst.d $f31, \base, (31 * FPU_REG_WIDTH)
+       EX      fst.d   $f0,  \base, (0 * FPU_REG_WIDTH)
+       EX      fst.d   $f1,  \base, (1 * FPU_REG_WIDTH)
+       EX      fst.d   $f2,  \base, (2 * FPU_REG_WIDTH)
+       EX      fst.d   $f3,  \base, (3 * FPU_REG_WIDTH)
+       EX      fst.d   $f4,  \base, (4 * FPU_REG_WIDTH)
+       EX      fst.d   $f5,  \base, (5 * FPU_REG_WIDTH)
+       EX      fst.d   $f6,  \base, (6 * FPU_REG_WIDTH)
+       EX      fst.d   $f7,  \base, (7 * FPU_REG_WIDTH)
+       EX      fst.d   $f8,  \base, (8 * FPU_REG_WIDTH)
+       EX      fst.d   $f9,  \base, (9 * FPU_REG_WIDTH)
+       EX      fst.d   $f10, \base, (10 * FPU_REG_WIDTH)
+       EX      fst.d   $f11, \base, (11 * FPU_REG_WIDTH)
+       EX      fst.d   $f12, \base, (12 * FPU_REG_WIDTH)
+       EX      fst.d   $f13, \base, (13 * FPU_REG_WIDTH)
+       EX      fst.d   $f14, \base, (14 * FPU_REG_WIDTH)
+       EX      fst.d   $f15, \base, (15 * FPU_REG_WIDTH)
+       EX      fst.d   $f16, \base, (16 * FPU_REG_WIDTH)
+       EX      fst.d   $f17, \base, (17 * FPU_REG_WIDTH)
+       EX      fst.d   $f18, \base, (18 * FPU_REG_WIDTH)
+       EX      fst.d   $f19, \base, (19 * FPU_REG_WIDTH)
+       EX      fst.d   $f20, \base, (20 * FPU_REG_WIDTH)
+       EX      fst.d   $f21, \base, (21 * FPU_REG_WIDTH)
+       EX      fst.d   $f22, \base, (22 * FPU_REG_WIDTH)
+       EX      fst.d   $f23, \base, (23 * FPU_REG_WIDTH)
+       EX      fst.d   $f24, \base, (24 * FPU_REG_WIDTH)
+       EX      fst.d   $f25, \base, (25 * FPU_REG_WIDTH)
+       EX      fst.d   $f26, \base, (26 * FPU_REG_WIDTH)
+       EX      fst.d   $f27, \base, (27 * FPU_REG_WIDTH)
+       EX      fst.d   $f28, \base, (28 * FPU_REG_WIDTH)
+       EX      fst.d   $f29, \base, (29 * FPU_REG_WIDTH)
+       EX      fst.d   $f30, \base, (30 * FPU_REG_WIDTH)
+       EX      fst.d   $f31, \base, (31 * FPU_REG_WIDTH)
        .endm
 
        .macro sc_restore_fp base
-       EX      fld.d $f0,  \base, (0 * FPU_REG_WIDTH)
-       EX      fld.d $f1,  \base, (1 * FPU_REG_WIDTH)
-       EX      fld.d $f2,  \base, (2 * FPU_REG_WIDTH)
-       EX      fld.d $f3,  \base, (3 * FPU_REG_WIDTH)
-       EX      fld.d $f4,  \base, (4 * FPU_REG_WIDTH)
-       EX      fld.d $f5,  \base, (5 * FPU_REG_WIDTH)
-       EX      fld.d $f6,  \base, (6 * FPU_REG_WIDTH)
-       EX      fld.d $f7,  \base, (7 * FPU_REG_WIDTH)
-       EX      fld.d $f8,  \base, (8 * FPU_REG_WIDTH)
-       EX      fld.d $f9,  \base, (9 * FPU_REG_WIDTH)
-       EX      fld.d $f10, \base, (10 * FPU_REG_WIDTH)
-       EX      fld.d $f11, \base, (11 * FPU_REG_WIDTH)
-       EX      fld.d $f12, \base, (12 * FPU_REG_WIDTH)
-       EX      fld.d $f13, \base, (13 * FPU_REG_WIDTH)
-       EX      fld.d $f14, \base, (14 * FPU_REG_WIDTH)
-       EX      fld.d $f15, \base, (15 * FPU_REG_WIDTH)
-       EX      fld.d $f16, \base, (16 * FPU_REG_WIDTH)
-       EX      fld.d $f17, \base, (17 * FPU_REG_WIDTH)
-       EX      fld.d $f18, \base, (18 * FPU_REG_WIDTH)
-       EX      fld.d $f19, \base, (19 * FPU_REG_WIDTH)
-       EX      fld.d $f20, \base, (20 * FPU_REG_WIDTH)
-       EX      fld.d $f21, \base, (21 * FPU_REG_WIDTH)
-       EX      fld.d $f22, \base, (22 * FPU_REG_WIDTH)
-       EX      fld.d $f23, \base, (23 * FPU_REG_WIDTH)
-       EX      fld.d $f24, \base, (24 * FPU_REG_WIDTH)
-       EX      fld.d $f25, \base, (25 * FPU_REG_WIDTH)
-       EX      fld.d $f26, \base, (26 * FPU_REG_WIDTH)
-       EX      fld.d $f27, \base, (27 * FPU_REG_WIDTH)
-       EX      fld.d $f28, \base, (28 * FPU_REG_WIDTH)
-       EX      fld.d $f29, \base, (29 * FPU_REG_WIDTH)
-       EX      fld.d $f30, \base, (30 * FPU_REG_WIDTH)
-       EX      fld.d $f31, \base, (31 * FPU_REG_WIDTH)
+       EX      fld.d   $f0,  \base, (0 * FPU_REG_WIDTH)
+       EX      fld.d   $f1,  \base, (1 * FPU_REG_WIDTH)
+       EX      fld.d   $f2,  \base, (2 * FPU_REG_WIDTH)
+       EX      fld.d   $f3,  \base, (3 * FPU_REG_WIDTH)
+       EX      fld.d   $f4,  \base, (4 * FPU_REG_WIDTH)
+       EX      fld.d   $f5,  \base, (5 * FPU_REG_WIDTH)
+       EX      fld.d   $f6,  \base, (6 * FPU_REG_WIDTH)
+       EX      fld.d   $f7,  \base, (7 * FPU_REG_WIDTH)
+       EX      fld.d   $f8,  \base, (8 * FPU_REG_WIDTH)
+       EX      fld.d   $f9,  \base, (9 * FPU_REG_WIDTH)
+       EX      fld.d   $f10, \base, (10 * FPU_REG_WIDTH)
+       EX      fld.d   $f11, \base, (11 * FPU_REG_WIDTH)
+       EX      fld.d   $f12, \base, (12 * FPU_REG_WIDTH)
+       EX      fld.d   $f13, \base, (13 * FPU_REG_WIDTH)
+       EX      fld.d   $f14, \base, (14 * FPU_REG_WIDTH)
+       EX      fld.d   $f15, \base, (15 * FPU_REG_WIDTH)
+       EX      fld.d   $f16, \base, (16 * FPU_REG_WIDTH)
+       EX      fld.d   $f17, \base, (17 * FPU_REG_WIDTH)
+       EX      fld.d   $f18, \base, (18 * FPU_REG_WIDTH)
+       EX      fld.d   $f19, \base, (19 * FPU_REG_WIDTH)
+       EX      fld.d   $f20, \base, (20 * FPU_REG_WIDTH)
+       EX      fld.d   $f21, \base, (21 * FPU_REG_WIDTH)
+       EX      fld.d   $f22, \base, (22 * FPU_REG_WIDTH)
+       EX      fld.d   $f23, \base, (23 * FPU_REG_WIDTH)
+       EX      fld.d   $f24, \base, (24 * FPU_REG_WIDTH)
+       EX      fld.d   $f25, \base, (25 * FPU_REG_WIDTH)
+       EX      fld.d   $f26, \base, (26 * FPU_REG_WIDTH)
+       EX      fld.d   $f27, \base, (27 * FPU_REG_WIDTH)
+       EX      fld.d   $f28, \base, (28 * FPU_REG_WIDTH)
+       EX      fld.d   $f29, \base, (29 * FPU_REG_WIDTH)
+       EX      fld.d   $f30, \base, (30 * FPU_REG_WIDTH)
+       EX      fld.d   $f31, \base, (31 * FPU_REG_WIDTH)
        .endm
 
        .macro sc_save_fcc base, tmp0, tmp1
        movcf2gr        \tmp0, $fcc0
-       move    \tmp1, \tmp0
+       move            \tmp1, \tmp0
        movcf2gr        \tmp0, $fcc1
        bstrins.d       \tmp1, \tmp0, 15, 8
        movcf2gr        \tmp0, $fcc2
        bstrins.d       \tmp1, \tmp0, 55, 48
        movcf2gr        \tmp0, $fcc7
        bstrins.d       \tmp1, \tmp0, 63, 56
-       EX      st.d \tmp1, \base, 0
+       EX      st.d    \tmp1, \base, 0
        .endm
 
        .macro sc_restore_fcc base, tmp0, tmp1
-       EX      ld.d \tmp0, \base, 0
+       EX      ld.d    \tmp0, \base, 0
        bstrpick.d      \tmp1, \tmp0, 7, 0
        movgr2cf        $fcc0, \tmp1
        bstrpick.d      \tmp1, \tmp0, 15, 8
 
        .macro sc_save_fcsr base, tmp0
        movfcsr2gr      \tmp0, fcsr0
-       EX      st.w \tmp0, \base, 0
+       EX      st.w    \tmp0, \base, 0
        .endm
 
        .macro sc_restore_fcsr base, tmp0
-       EX      ld.w \tmp0, \base, 0
+       EX      ld.w    \tmp0, \base, 0
        movgr2fcsr      fcsr0, \tmp0
        .endm
 
-       .macro sc_save_vcsr base, tmp0
-       movfcsr2gr      \tmp0, vcsr16
-       EX      st.w \tmp0, \base, 0
-       .endm
-
-       .macro sc_restore_vcsr base, tmp0
-       EX      ld.w \tmp0, \base, 0
-       movgr2fcsr      vcsr16, \tmp0
-       .endm
-
 /*
  * Save a thread's fp context.
  */
 SYM_FUNC_START(_save_fp)
        fpu_save_csr    a0 t1
-       fpu_save_double a0 t1                   # clobbers t1
+       fpu_save_double a0 t1                   # clobbers t1
        fpu_save_cc     a0 t1 t2                # clobbers t1, t2
-       jirl zero, ra, 0
+       jr              ra
 SYM_FUNC_END(_save_fp)
 EXPORT_SYMBOL(_save_fp)
 
@@ -171,10 +161,10 @@ EXPORT_SYMBOL(_save_fp)
  * Restore a thread's fp context.
  */
 SYM_FUNC_START(_restore_fp)
-       fpu_restore_double a0 t1                # clobbers t1
-       fpu_restore_csr a0 t1
-       fpu_restore_cc  a0 t1 t2                # clobbers t1, t2
-       jirl zero, ra, 0
+       fpu_restore_double      a0 t1           # clobbers t1
+       fpu_restore_csr         a0 t1
+       fpu_restore_cc          a0 t1 t2        # clobbers t1, t2
+       jr                      ra
 SYM_FUNC_END(_restore_fp)
 
 /*
@@ -226,7 +216,7 @@ SYM_FUNC_START(_init_fpu)
        movgr2fr.d      $f30, t1
        movgr2fr.d      $f31, t1
 
-       jirl zero, ra, 0
+       jr      ra
 SYM_FUNC_END(_init_fpu)
 
 /*
@@ -235,11 +225,11 @@ SYM_FUNC_END(_init_fpu)
  * a2: fcsr
  */
 SYM_FUNC_START(_save_fp_context)
-       sc_save_fcc a1 t1 t2
-       sc_save_fcsr a2 t1
-       sc_save_fp a0
-       li.w    a0, 0                                   # success
-       jirl zero, ra, 0
+       sc_save_fcc     a1 t1 t2
+       sc_save_fcsr    a2 t1
+       sc_save_fp      a0
+       li.w            a0, 0                           # success
+       jr              ra
 SYM_FUNC_END(_save_fp_context)
 
 /*
@@ -248,14 +238,14 @@ SYM_FUNC_END(_save_fp_context)
  * a2: fcsr
  */
 SYM_FUNC_START(_restore_fp_context)
-       sc_restore_fp a0
-       sc_restore_fcc a1 t1 t2
-       sc_restore_fcsr a2 t1
-       li.w    a0, 0                                   # success
-       jirl zero, ra, 0
+       sc_restore_fp   a0
+       sc_restore_fcc  a1 t1 t2
+       sc_restore_fcsr a2 t1
+       li.w            a0, 0                           # success
+       jr              ra
 SYM_FUNC_END(_restore_fp_context)
 
 SYM_FUNC_START(fault)
        li.w    a0, -EFAULT                             # failure
-       jirl zero, ra, 0
+       jr      ra
 SYM_FUNC_END(fault)
index 9349685..75e5be8 100644 (file)
@@ -28,23 +28,23 @@ SYM_FUNC_START(__arch_cpu_idle)
        nop
        idle    0
        /* end of rollback region */
-1:     jirl    zero, ra, 0
+1:     jr      ra
 SYM_FUNC_END(__arch_cpu_idle)
 
 SYM_FUNC_START(handle_vint)
        BACKUP_T0T1
        SAVE_ALL
        la.abs  t1, __arch_cpu_idle
-       LONG_L  t0, sp, PT_ERA
+       LONG_L  t0, sp, PT_ERA
        /* 32 byte rollback region */
        ori     t0, t0, 0x1f
        xori    t0, t0, 0x1f
        bne     t0, t1, 1f
-       LONG_S  t0, sp, PT_ERA
+       LONG_S  t0, sp, PT_ERA
 1:     move    a0, sp
        move    a1, sp
        la.abs  t0, do_vint
-       jirl    ra, t0, 0
+       jirl    ra, t0, 0
        RESTORE_ALL_AND_RET
 SYM_FUNC_END(handle_vint)
 
@@ -72,7 +72,7 @@ SYM_FUNC_END(except_vec_cex)
        build_prep_\prep
        move    a0, sp
        la.abs  t0, do_\handler
-       jirl    ra, t0, 0
+       jirl    ra, t0, 0
        RESTORE_ALL_AND_RET
        SYM_FUNC_END(handle_\exception)
        .endm
@@ -91,5 +91,5 @@ SYM_FUNC_END(except_vec_cex)
 
 SYM_FUNC_START(handle_sys)
        la.abs  t0, handle_syscall
-       jirl    zero, t0, 0
+       jr      t0
 SYM_FUNC_END(handle_sys)
index d01e62d..7062cdf 100644 (file)
@@ -32,7 +32,7 @@ SYM_CODE_START(kernel_entry)                  # kernel entry point
        /* We might not get launched at the address the kernel is linked to,
           so we jump there.  */
        la.abs          t0, 0f
-       jirl            zero, t0, 0
+       jr              t0
 0:
        la              t0, __bss_start         # clear .bss
        st.d            zero, t0, 0
@@ -50,7 +50,7 @@ SYM_CODE_START(kernel_entry)                  # kernel entry point
        /* KSave3 used for percpu base, initialized as 0 */
        csrwr           zero, PERCPU_BASE_KS
        /* GPR21 used for percpu base (runtime), initialized as 0 */
-       or              u0, zero, zero
+       move            u0, zero
 
        la              tp, init_thread_union
        /* Set the SP after an empty pt_regs.  */
@@ -85,8 +85,8 @@ SYM_CODE_START(smpboot_entry)
        ld.d            sp, t0, CPU_BOOT_STACK
        ld.d            tp, t0, CPU_BOOT_TINFO
 
-       la.abs  t0, 0f
-       jirl    zero, t0, 0
+       la.abs          t0, 0f
+       jr              t0
 0:
        bl              start_secondary
 SYM_CODE_END(smpboot_entry)
index b34b8d7..1ba19c7 100644 (file)
@@ -25,12 +25,8 @@ DEFINE_PER_CPU(unsigned long, irq_stack);
 DEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
 EXPORT_PER_CPU_SYMBOL(irq_stat);
 
-struct irq_domain *cpu_domain;
-struct irq_domain *liointc_domain;
-struct irq_domain *pch_lpc_domain;
-struct irq_domain *pch_msi_domain[MAX_IO_PICS];
-struct irq_domain *pch_pic_domain[MAX_IO_PICS];
-
+struct acpi_vector_group pch_group[MAX_IO_PICS];
+struct acpi_vector_group msi_group[MAX_IO_PICS];
 /*
  * 'what should we do if we get a hw irq event on an illegal vector'.
  * each architecture has to answer this themselves.
@@ -56,6 +52,51 @@ int arch_show_interrupts(struct seq_file *p, int prec)
        return 0;
 }
 
+static int __init early_pci_mcfg_parse(struct acpi_table_header *header)
+{
+       struct acpi_table_mcfg *mcfg;
+       struct acpi_mcfg_allocation *mptr;
+       int i, n;
+
+       if (header->length < sizeof(struct acpi_table_mcfg))
+               return -EINVAL;
+
+       n = (header->length - sizeof(struct acpi_table_mcfg)) /
+                                       sizeof(struct acpi_mcfg_allocation);
+       mcfg = (struct acpi_table_mcfg *)header;
+       mptr = (struct acpi_mcfg_allocation *) &mcfg[1];
+
+       for (i = 0; i < n; i++, mptr++) {
+               msi_group[i].pci_segment = mptr->pci_segment;
+               pch_group[i].node = msi_group[i].node = (mptr->address >> 44) & 0xf;
+       }
+
+       return 0;
+}
+
+static void __init init_vec_parent_group(void)
+{
+       int i;
+
+       for (i = 0; i < MAX_IO_PICS; i++) {
+               msi_group[i].pci_segment = -1;
+               msi_group[i].node = -1;
+               pch_group[i].node = -1;
+       }
+
+       acpi_table_parse(ACPI_SIG_MCFG, early_pci_mcfg_parse);
+}
+
+static int __init get_ipi_irq(void)
+{
+       struct irq_domain *d = irq_find_matching_fwnode(cpuintc_handle, DOMAIN_BUS_ANY);
+
+       if (d)
+               return irq_create_mapping(d, EXCCODE_IPI - EXCCODE_INT_START);
+
+       return -EINVAL;
+}
+
 void __init init_IRQ(void)
 {
        int i;
@@ -69,9 +110,12 @@ void __init init_IRQ(void)
        clear_csr_ecfg(ECFG0_IM);
        clear_csr_estat(ESTATF_IP);
 
+       init_vec_parent_group();
        irqchip_init();
 #ifdef CONFIG_SMP
-       ipi_irq = EXCCODE_IPI - EXCCODE_INT_START;
+       ipi_irq = get_ipi_irq();
+       if (ipi_irq < 0)
+               panic("IPI IRQ mapping failed\n");
        irq_set_percpu_devid(ipi_irq);
        r = request_percpu_irq(ipi_irq, loongson3_ipi_interrupt, "IPI", &ipi_dummy_dev);
        if (r < 0)
index a76f547..a13f925 100644 (file)
@@ -429,7 +429,6 @@ int __init init_numa_memory(void)
        return 0;
 }
 
-EXPORT_SYMBOL(init_numa_memory);
 #endif
 
 void __init paging_init(void)
index e6ab879..dc2b82e 100644 (file)
@@ -193,7 +193,7 @@ static int fpr_set(struct task_struct *target,
                   const void *kbuf, const void __user *ubuf)
 {
        const int fcc_start = NUM_FPU_REGS * sizeof(elf_fpreg_t);
-       const int fcc_end = fcc_start + sizeof(u64);
+       const int fcsr_start = fcc_start + sizeof(u64);
        int err;
 
        BUG_ON(count % sizeof(elf_fpreg_t));
@@ -209,10 +209,12 @@ static int fpr_set(struct task_struct *target,
        if (err)
                return err;
 
-       if (count > 0)
-               err |= user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-                                         &target->thread.fpu.fcc,
-                                         fcc_start, fcc_end);
+       err |= user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                 &target->thread.fpu.fcc, fcc_start,
+                                 fcc_start + sizeof(u64));
+       err |= user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                 &target->thread.fpu.fcsr, fcsr_start,
+                                 fcsr_start + sizeof(u32));
 
        return err;
 }
index 2b86469..800c965 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/console.h>
 
 #include <acpi/reboot.h>
-#include <asm/compiler.h>
 #include <asm/idle.h>
 #include <asm/loongarch.h>
 #include <asm/reboot.h>
index c74860b..8f5c2f9 100644 (file)
@@ -126,7 +126,7 @@ static void __init parse_bios_table(const struct dmi_header *dm)
        char *dmi_data = (char *)dm;
 
        bios_extern = *(dmi_data + SMBIOS_BIOSEXTERN_OFFSET);
-       b_info.bios_size = *(dmi_data + SMBIOS_BIOSSIZE_OFFSET);
+       b_info.bios_size = (*(dmi_data + SMBIOS_BIOSSIZE_OFFSET) + 1) << 6;
 
        if (bios_extern & LOONGSON_EFI_ENABLE)
                set_bit(EFI_BOOT, &efi.flags);
index 73cec62..0974310 100644 (file)
@@ -278,116 +278,29 @@ void loongson3_cpu_die(unsigned int cpu)
        mb();
 }
 
-/*
- * The target CPU should go to XKPRANGE (uncached area) and flush
- * ICache/DCache/VCache before the control CPU can safely disable its clock.
- */
-static void loongson3_play_dead(int *state_addr)
+void play_dead(void)
 {
-       register int val;
-       register void *addr;
+       register uint64_t addr;
        register void (*init_fn)(void);
 
-       __asm__ __volatile__(
-               "   li.d %[addr], 0x8000000000000000\n"
-               "1: cacop 0x8, %[addr], 0           \n" /* flush ICache */
-               "   cacop 0x8, %[addr], 1           \n"
-               "   cacop 0x8, %[addr], 2           \n"
-               "   cacop 0x8, %[addr], 3           \n"
-               "   cacop 0x9, %[addr], 0           \n" /* flush DCache */
-               "   cacop 0x9, %[addr], 1           \n"
-               "   cacop 0x9, %[addr], 2           \n"
-               "   cacop 0x9, %[addr], 3           \n"
-               "   addi.w %[sets], %[sets], -1     \n"
-               "   addi.d %[addr], %[addr], 0x40   \n"
-               "   bnez %[sets], 1b                \n"
-               "   li.d %[addr], 0x8000000000000000\n"
-               "2: cacop 0xa, %[addr], 0           \n" /* flush VCache */
-               "   cacop 0xa, %[addr], 1           \n"
-               "   cacop 0xa, %[addr], 2           \n"
-               "   cacop 0xa, %[addr], 3           \n"
-               "   cacop 0xa, %[addr], 4           \n"
-               "   cacop 0xa, %[addr], 5           \n"
-               "   cacop 0xa, %[addr], 6           \n"
-               "   cacop 0xa, %[addr], 7           \n"
-               "   cacop 0xa, %[addr], 8           \n"
-               "   cacop 0xa, %[addr], 9           \n"
-               "   cacop 0xa, %[addr], 10          \n"
-               "   cacop 0xa, %[addr], 11          \n"
-               "   cacop 0xa, %[addr], 12          \n"
-               "   cacop 0xa, %[addr], 13          \n"
-               "   cacop 0xa, %[addr], 14          \n"
-               "   cacop 0xa, %[addr], 15          \n"
-               "   addi.w %[vsets], %[vsets], -1   \n"
-               "   addi.d %[addr], %[addr], 0x40   \n"
-               "   bnez   %[vsets], 2b             \n"
-               "   li.w   %[val], 0x7              \n" /* *state_addr = CPU_DEAD; */
-               "   st.w   %[val], %[state_addr], 0 \n"
-               "   dbar 0                          \n"
-               "   cacop 0x11, %[state_addr], 0    \n" /* flush entry of *state_addr */
-               : [addr] "=&r" (addr), [val] "=&r" (val)
-               : [state_addr] "r" (state_addr),
-                 [sets] "r" (cpu_data[smp_processor_id()].dcache.sets),
-                 [vsets] "r" (cpu_data[smp_processor_id()].vcache.sets));
-
+       idle_task_exit();
        local_irq_enable();
-       change_csr_ecfg(ECFG0_IM, ECFGF_IPI);
+       set_csr_ecfg(ECFGF_IPI);
+       __this_cpu_write(cpu_state, CPU_DEAD);
+
+       __smp_mb();
+       do {
+               __asm__ __volatile__("idle 0\n\t");
+               addr = iocsr_read64(LOONGARCH_IOCSR_MBUF0);
+       } while (addr == 0);
 
-       __asm__ __volatile__(
-               "   idle      0                     \n"
-               "   li.w      $t0, 0x1020           \n"
-               "   iocsrrd.d %[init_fn], $t0       \n" /* Get init PC */
-               : [init_fn] "=&r" (addr)
-               : /* No Input */
-               : "a0");
-       init_fn = __va(addr);
+       init_fn = (void *)TO_CACHE(addr);
+       iocsr_write32(0xffffffff, LOONGARCH_IOCSR_IPI_CLEAR);
 
        init_fn();
        unreachable();
 }
 
-void play_dead(void)
-{
-       int *state_addr;
-       unsigned int cpu = smp_processor_id();
-       void (*play_dead_uncached)(int *s);
-
-       idle_task_exit();
-       play_dead_uncached = (void *)TO_UNCACHE(__pa((unsigned long)loongson3_play_dead));
-       state_addr = &per_cpu(cpu_state, cpu);
-       mb();
-       play_dead_uncached(state_addr);
-}
-
-static int loongson3_enable_clock(unsigned int cpu)
-{
-       uint64_t core_id = cpu_data[cpu].core;
-       uint64_t package_id = cpu_data[cpu].package;
-
-       LOONGSON_FREQCTRL(package_id) |= 1 << (core_id * 4 + 3);
-
-       return 0;
-}
-
-static int loongson3_disable_clock(unsigned int cpu)
-{
-       uint64_t core_id = cpu_data[cpu].core;
-       uint64_t package_id = cpu_data[cpu].package;
-
-       LOONGSON_FREQCTRL(package_id) &= ~(1 << (core_id * 4 + 3));
-
-       return 0;
-}
-
-static int register_loongson3_notifier(void)
-{
-       return cpuhp_setup_state_nocalls(CPUHP_LOONGARCH_SOC_PREPARE,
-                                        "loongarch/loongson:prepare",
-                                        loongson3_enable_clock,
-                                        loongson3_disable_clock);
-}
-early_initcall(register_loongson3_notifier);
-
 #endif
 
 /*
index 53e2fa8..37e84ac 100644 (file)
@@ -24,8 +24,8 @@ SYM_FUNC_START(__switch_to)
        move    tp, a2
        cpu_restore_nonscratch a1
 
-       li.w    t0, _THREAD_SIZE - 32
-       PTR_ADD t0, t0, tp
+       li.w            t0, _THREAD_SIZE - 32
+       PTR_ADD         t0, t0, tp
        set_saved_sp    t0, t1, t2
 
        ldptr.d t1, a1, THREAD_CSRPRMD
index fe68238..79dc5ed 100644 (file)
@@ -123,6 +123,16 @@ void sync_counter(void)
        csr_write64(-init_timeval, LOONGARCH_CSR_CNTC);
 }
 
+static int get_timer_irq(void)
+{
+       struct irq_domain *d = irq_find_matching_fwnode(cpuintc_handle, DOMAIN_BUS_ANY);
+
+       if (d)
+               return irq_create_mapping(d, EXCCODE_TIMER - EXCCODE_INT_START);
+
+       return -EINVAL;
+}
+
 int constant_clockevent_init(void)
 {
        unsigned int irq;
@@ -132,7 +142,9 @@ int constant_clockevent_init(void)
        struct clock_event_device *cd;
        static int timer_irq_installed = 0;
 
-       irq = EXCCODE_TIMER - EXCCODE_INT_START;
+       irq = get_timer_irq();
+       if (irq < 0)
+               pr_err("Failed to map irq %d (timer)\n", irq);
 
        cd = &per_cpu(constant_clockevent_device, cpu);
 
index 25d9be5..16ba2b8 100644 (file)
@@ -32,7 +32,7 @@ SYM_FUNC_START(__clear_user)
 1:     st.b    zero, a0, 0
        addi.d  a0, a0, 1
        addi.d  a1, a1, -1
-       bgt     a1, zero, 1b
+       bgtz    a1, 1b
 
 2:     move    a0, a1
        jr      ra
index 9ae507f..97d2032 100644 (file)
@@ -35,7 +35,7 @@ SYM_FUNC_START(__copy_user)
        addi.d  a0, a0, 1
        addi.d  a1, a1, 1
        addi.d  a2, a2, -1
-       bgt     a2, zero, 1b
+       bgtz    a2, 1b
 
 3:     move    a0, a2
        jr      ra
index 5d85669..831d476 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/smp.h>
 #include <linux/timex.h>
 
-#include <asm/compiler.h>
 #include <asm/processor.h>
 
 void __delay(unsigned long cycles)
index ddc78ab..4c874a7 100644 (file)
 
        .align 5
 SYM_FUNC_START(clear_page)
-       lu12i.w  t0, 1 << (PAGE_SHIFT - 12)
-       add.d    t0, t0, a0
+       lu12i.w t0, 1 << (PAGE_SHIFT - 12)
+       add.d   t0, t0, a0
 1:
-       st.d     zero, a0, 0
-       st.d     zero, a0, 8
-       st.d     zero, a0, 16
-       st.d     zero, a0, 24
-       st.d     zero, a0, 32
-       st.d     zero, a0, 40
-       st.d     zero, a0, 48
-       st.d     zero, a0, 56
-       addi.d   a0,   a0, 128
-       st.d     zero, a0, -64
-       st.d     zero, a0, -56
-       st.d     zero, a0, -48
-       st.d     zero, a0, -40
-       st.d     zero, a0, -32
-       st.d     zero, a0, -24
-       st.d     zero, a0, -16
-       st.d     zero, a0, -8
-       bne      t0,   a0, 1b
+       st.d    zero, a0, 0
+       st.d    zero, a0, 8
+       st.d    zero, a0, 16
+       st.d    zero, a0, 24
+       st.d    zero, a0, 32
+       st.d    zero, a0, 40
+       st.d    zero, a0, 48
+       st.d    zero, a0, 56
+       addi.d  a0,   a0, 128
+       st.d    zero, a0, -64
+       st.d    zero, a0, -56
+       st.d    zero, a0, -48
+       st.d    zero, a0, -40
+       st.d    zero, a0, -32
+       st.d    zero, a0, -24
+       st.d    zero, a0, -16
+       st.d    zero, a0, -8
+       bne     t0,   a0, 1b
 
-       jirl     $r0, ra, 0
+       jr      ra
 SYM_FUNC_END(clear_page)
 EXPORT_SYMBOL(clear_page)
 
 .align 5
 SYM_FUNC_START(copy_page)
-       lu12i.w  t8, 1 << (PAGE_SHIFT - 12)
-       add.d    t8, t8, a0
+       lu12i.w t8, 1 << (PAGE_SHIFT - 12)
+       add.d   t8, t8, a0
 1:
-       ld.d     t0, a1,  0
-       ld.d     t1, a1,  8
-       ld.d     t2, a1,  16
-       ld.d     t3, a1,  24
-       ld.d     t4, a1,  32
-       ld.d     t5, a1,  40
-       ld.d     t6, a1,  48
-       ld.d     t7, a1,  56
+       ld.d    t0, a1, 0
+       ld.d    t1, a1, 8
+       ld.d    t2, a1, 16
+       ld.d    t3, a1, 24
+       ld.d    t4, a1, 32
+       ld.d    t5, a1, 40
+       ld.d    t6, a1, 48
+       ld.d    t7, a1, 56
 
-       st.d     t0, a0,  0
-       st.d     t1, a0,  8
-       ld.d     t0, a1,  64
-       ld.d     t1, a1,  72
-       st.d     t2, a0,  16
-       st.d     t3, a0,  24
-       ld.d     t2, a1,  80
-       ld.d     t3, a1,  88
-       st.d     t4, a0,  32
-       st.d     t5, a0,  40
-       ld.d     t4, a1,  96
-       ld.d     t5, a1,  104
-       st.d     t6, a0,  48
-       st.d     t7, a0,  56
-       ld.d     t6, a1,  112
-       ld.d     t7, a1,  120
-       addi.d   a0, a0,  128
-       addi.d   a1, a1,  128
+       st.d    t0, a0, 0
+       st.d    t1, a0, 8
+       ld.d    t0, a1, 64
+       ld.d    t1, a1, 72
+       st.d    t2, a0, 16
+       st.d    t3, a0, 24
+       ld.d    t2, a1, 80
+       ld.d    t3, a1, 88
+       st.d    t4, a0, 32
+       st.d    t5, a0, 40
+       ld.d    t4, a1, 96
+       ld.d    t5, a1, 104
+       st.d    t6, a0, 48
+       st.d    t7, a0, 56
+       ld.d    t6, a1, 112
+       ld.d    t7, a1, 120
+       addi.d  a0, a0, 128
+       addi.d  a1, a1, 128
 
-       st.d     t0, a0,  -64
-       st.d     t1, a0,  -56
-       st.d     t2, a0,  -48
-       st.d     t3, a0,  -40
-       st.d     t4, a0,  -32
-       st.d     t5, a0,  -24
-       st.d     t6, a0,  -16
-       st.d     t7, a0,  -8
+       st.d    t0, a0, -64
+       st.d    t1, a0, -56
+       st.d    t2, a0, -48
+       st.d    t3, a0, -40
+       st.d    t4, a0, -32
+       st.d    t5, a0, -24
+       st.d    t6, a0, -16
+       st.d    t7, a0, -8
 
-       bne      t8, a0, 1b
-       jirl     $r0, ra, 0
+       bne     t8, a0, 1b
+       jr      ra
 SYM_FUNC_END(copy_page)
 EXPORT_SYMBOL(copy_page)
index 7eee402..de19fa2 100644 (file)
@@ -18,7 +18,7 @@
        REG_S   a2, sp, PT_BVADDR
        li.w    a1, \write
        la.abs  t0, do_page_fault
-       jirl    ra, t0, 0
+       jirl    ra, t0, 0
        RESTORE_ALL_AND_RET
        SYM_FUNC_END(tlb_do_page_fault_\write)
        .endm
@@ -34,7 +34,7 @@ SYM_FUNC_START(handle_tlb_protect)
        csrrd   a2, LOONGARCH_CSR_BADV
        REG_S   a2, sp, PT_BVADDR
        la.abs  t0, do_page_fault
-       jirl    ra, t0, 0
+       jirl    ra, t0, 0
        RESTORE_ALL_AND_RET
 SYM_FUNC_END(handle_tlb_protect)
 
@@ -47,7 +47,7 @@ SYM_FUNC_START(handle_tlb_load)
         * The vmalloc handling is not in the hotpath.
         */
        csrrd   t0, LOONGARCH_CSR_BADV
-       blt     t0, $r0, vmalloc_load
+       bltz    t0, vmalloc_load
        csrrd   t1, LOONGARCH_CSR_PGDL
 
 vmalloc_done_load:
@@ -80,7 +80,7 @@ vmalloc_done_load:
         * see if we need to jump to huge tlb processing.
         */
        andi    t0, ra, _PAGE_HUGE
-       bne     t0, $r0, tlb_huge_update_load
+       bnez    t0, tlb_huge_update_load
 
        csrrd   t0, LOONGARCH_CSR_BADV
        srli.d  t0, t0, (PAGE_SHIFT + PTE_ORDER)
@@ -100,12 +100,12 @@ smp_pgtable_change_load:
 
        srli.d  ra, t0, _PAGE_PRESENT_SHIFT
        andi    ra, ra, 1
-       beq     ra, $r0, nopage_tlb_load
+       beqz    ra, nopage_tlb_load
 
        ori     t0, t0, _PAGE_VALID
 #ifdef CONFIG_SMP
        sc.d    t0, t1, 0
-       beq     t0, $r0, smp_pgtable_change_load
+       beqz    t0, smp_pgtable_change_load
 #else
        st.d    t0, t1, 0
 #endif
@@ -139,23 +139,23 @@ tlb_huge_update_load:
 #endif
        srli.d  ra, t0, _PAGE_PRESENT_SHIFT
        andi    ra, ra, 1
-       beq     ra, $r0, nopage_tlb_load
+       beqz    ra, nopage_tlb_load
        tlbsrch
 
        ori     t0, t0, _PAGE_VALID
 #ifdef CONFIG_SMP
        sc.d    t0, t1, 0
-       beq     t0, $r0, tlb_huge_update_load
+       beqz    t0, tlb_huge_update_load
        ld.d    t0, t1, 0
 #else
        st.d    t0, t1, 0
 #endif
-       addu16i.d       t1, $r0, -(CSR_TLBIDX_EHINV >> 16)
-       addi.d  ra, t1, 0
-       csrxchg ra, t1, LOONGARCH_CSR_TLBIDX
+       addu16i.d       t1, zero, -(CSR_TLBIDX_EHINV >> 16)
+       addi.d          ra, t1, 0
+       csrxchg         ra, t1, LOONGARCH_CSR_TLBIDX
        tlbwr
 
-       csrxchg $r0, t1, LOONGARCH_CSR_TLBIDX
+       csrxchg zero, t1, LOONGARCH_CSR_TLBIDX
 
        /*
         * A huge PTE describes an area the size of the
@@ -178,27 +178,27 @@ tlb_huge_update_load:
        addi.d  t0, ra, 0
 
        /* Convert to entrylo1 */
-       addi.d  t1, $r0, 1
+       addi.d  t1, zero, 1
        slli.d  t1, t1, (HPAGE_SHIFT - 1)
        add.d   t0, t0, t1
        csrwr   t0, LOONGARCH_CSR_TLBELO1
 
        /* Set huge page tlb entry size */
-       addu16i.d       t0, $r0, (CSR_TLBIDX_PS >> 16)
-       addu16i.d       t1, $r0, (PS_HUGE_SIZE << (CSR_TLBIDX_PS_SHIFT - 16))
+       addu16i.d       t0, zero, (CSR_TLBIDX_PS >> 16)
+       addu16i.d       t1, zero, (PS_HUGE_SIZE << (CSR_TLBIDX_PS_SHIFT - 16))
        csrxchg         t1, t0, LOONGARCH_CSR_TLBIDX
 
        tlbfill
 
-       addu16i.d       t0, $r0, (CSR_TLBIDX_PS >> 16)
-       addu16i.d       t1, $r0, (PS_DEFAULT_SIZE << (CSR_TLBIDX_PS_SHIFT - 16))
+       addu16i.d       t0, zero, (CSR_TLBIDX_PS >> 16)
+       addu16i.d       t1, zero, (PS_DEFAULT_SIZE << (CSR_TLBIDX_PS_SHIFT - 16))
        csrxchg         t1, t0, LOONGARCH_CSR_TLBIDX
 
 nopage_tlb_load:
        dbar    0
        csrrd   ra, EXCEPTION_KS2
        la.abs  t0, tlb_do_page_fault_0
-       jirl    $r0, t0, 0
+       jr      t0
 SYM_FUNC_END(handle_tlb_load)
 
 SYM_FUNC_START(handle_tlb_store)
@@ -210,7 +210,7 @@ SYM_FUNC_START(handle_tlb_store)
         * The vmalloc handling is not in the hotpath.
         */
        csrrd   t0, LOONGARCH_CSR_BADV
-       blt     t0, $r0, vmalloc_store
+       bltz    t0, vmalloc_store
        csrrd   t1, LOONGARCH_CSR_PGDL
 
 vmalloc_done_store:
@@ -244,7 +244,7 @@ vmalloc_done_store:
         * see if we need to jump to huge tlb processing.
         */
        andi    t0, ra, _PAGE_HUGE
-       bne     t0, $r0, tlb_huge_update_store
+       bnez    t0, tlb_huge_update_store
 
        csrrd   t0, LOONGARCH_CSR_BADV
        srli.d  t0, t0, (PAGE_SHIFT + PTE_ORDER)
@@ -265,12 +265,12 @@ smp_pgtable_change_store:
        srli.d  ra, t0, _PAGE_PRESENT_SHIFT
        andi    ra, ra, ((_PAGE_PRESENT | _PAGE_WRITE) >> _PAGE_PRESENT_SHIFT)
        xori    ra, ra, ((_PAGE_PRESENT | _PAGE_WRITE) >> _PAGE_PRESENT_SHIFT)
-       bne     ra, $r0, nopage_tlb_store
+       bnez    ra, nopage_tlb_store
 
        ori     t0, t0, (_PAGE_VALID | _PAGE_DIRTY | _PAGE_MODIFIED)
 #ifdef CONFIG_SMP
        sc.d    t0, t1, 0
-       beq     t0, $r0, smp_pgtable_change_store
+       beqz    t0, smp_pgtable_change_store
 #else
        st.d    t0, t1, 0
 #endif
@@ -306,24 +306,24 @@ tlb_huge_update_store:
        srli.d  ra, t0, _PAGE_PRESENT_SHIFT
        andi    ra, ra, ((_PAGE_PRESENT | _PAGE_WRITE) >> _PAGE_PRESENT_SHIFT)
        xori    ra, ra, ((_PAGE_PRESENT | _PAGE_WRITE) >> _PAGE_PRESENT_SHIFT)
-       bne     ra, $r0, nopage_tlb_store
+       bnez    ra, nopage_tlb_store
 
        tlbsrch
        ori     t0, t0, (_PAGE_VALID | _PAGE_DIRTY | _PAGE_MODIFIED)
 
 #ifdef CONFIG_SMP
        sc.d    t0, t1, 0
-       beq     t0, $r0, tlb_huge_update_store
+       beqz    t0, tlb_huge_update_store
        ld.d    t0, t1, 0
 #else
        st.d    t0, t1, 0
 #endif
-       addu16i.d       t1, $r0, -(CSR_TLBIDX_EHINV >> 16)
-       addi.d  ra, t1, 0
-       csrxchg ra, t1, LOONGARCH_CSR_TLBIDX
+       addu16i.d       t1, zero, -(CSR_TLBIDX_EHINV >> 16)
+       addi.d          ra, t1, 0
+       csrxchg         ra, t1, LOONGARCH_CSR_TLBIDX
        tlbwr
 
-       csrxchg $r0, t1, LOONGARCH_CSR_TLBIDX
+       csrxchg zero, t1, LOONGARCH_CSR_TLBIDX
        /*
         * A huge PTE describes an area the size of the
         * configured huge page size. This is twice the
@@ -345,28 +345,28 @@ tlb_huge_update_store:
        addi.d  t0, ra, 0
 
        /* Convert to entrylo1 */
-       addi.d  t1, $r0, 1
+       addi.d  t1, zero, 1
        slli.d  t1, t1, (HPAGE_SHIFT - 1)
        add.d   t0, t0, t1
        csrwr   t0, LOONGARCH_CSR_TLBELO1
 
        /* Set huge page tlb entry size */
-       addu16i.d       t0, $r0, (CSR_TLBIDX_PS >> 16)
-       addu16i.d       t1, $r0, (PS_HUGE_SIZE << (CSR_TLBIDX_PS_SHIFT - 16))
+       addu16i.d       t0, zero, (CSR_TLBIDX_PS >> 16)
+       addu16i.d       t1, zero, (PS_HUGE_SIZE << (CSR_TLBIDX_PS_SHIFT - 16))
        csrxchg         t1, t0, LOONGARCH_CSR_TLBIDX
 
        tlbfill
 
        /* Reset default page size */
-       addu16i.d       t0, $r0, (CSR_TLBIDX_PS >> 16)
-       addu16i.d       t1, $r0, (PS_DEFAULT_SIZE << (CSR_TLBIDX_PS_SHIFT - 16))
+       addu16i.d       t0, zero, (CSR_TLBIDX_PS >> 16)
+       addu16i.d       t1, zero, (PS_DEFAULT_SIZE << (CSR_TLBIDX_PS_SHIFT - 16))
        csrxchg         t1, t0, LOONGARCH_CSR_TLBIDX
 
 nopage_tlb_store:
        dbar    0
        csrrd   ra, EXCEPTION_KS2
        la.abs  t0, tlb_do_page_fault_1
-       jirl    $r0, t0, 0
+       jr      t0
 SYM_FUNC_END(handle_tlb_store)
 
 SYM_FUNC_START(handle_tlb_modify)
@@ -378,7 +378,7 @@ SYM_FUNC_START(handle_tlb_modify)
         * The vmalloc handling is not in the hotpath.
         */
        csrrd   t0, LOONGARCH_CSR_BADV
-       blt     t0, $r0, vmalloc_modify
+       bltz    t0, vmalloc_modify
        csrrd   t1, LOONGARCH_CSR_PGDL
 
 vmalloc_done_modify:
@@ -411,7 +411,7 @@ vmalloc_done_modify:
         * see if we need to jump to huge tlb processing.
         */
        andi    t0, ra, _PAGE_HUGE
-       bne     t0, $r0, tlb_huge_update_modify
+       bnez    t0, tlb_huge_update_modify
 
        csrrd   t0, LOONGARCH_CSR_BADV
        srli.d  t0, t0, (PAGE_SHIFT + PTE_ORDER)
@@ -431,12 +431,12 @@ smp_pgtable_change_modify:
 
        srli.d  ra, t0, _PAGE_WRITE_SHIFT
        andi    ra, ra, 1
-       beq     ra, $r0, nopage_tlb_modify
+       beqz    ra, nopage_tlb_modify
 
        ori     t0, t0, (_PAGE_VALID | _PAGE_DIRTY | _PAGE_MODIFIED)
 #ifdef CONFIG_SMP
        sc.d    t0, t1, 0
-       beq     t0, $r0, smp_pgtable_change_modify
+       beqz    t0, smp_pgtable_change_modify
 #else
        st.d    t0, t1, 0
 #endif
@@ -454,7 +454,7 @@ leave_modify:
        ertn
 #ifdef CONFIG_64BIT
 vmalloc_modify:
-       la.abs  t1, swapper_pg_dir
+       la.abs  t1, swapper_pg_dir
        b       vmalloc_done_modify
 #endif
 
@@ -471,14 +471,14 @@ tlb_huge_update_modify:
 
        srli.d  ra, t0, _PAGE_WRITE_SHIFT
        andi    ra, ra, 1
-       beq     ra, $r0, nopage_tlb_modify
+       beqz    ra, nopage_tlb_modify
 
        tlbsrch
        ori     t0, t0, (_PAGE_VALID | _PAGE_DIRTY | _PAGE_MODIFIED)
 
 #ifdef CONFIG_SMP
        sc.d    t0, t1, 0
-       beq     t0, $r0, tlb_huge_update_modify
+       beqz    t0, tlb_huge_update_modify
        ld.d    t0, t1, 0
 #else
        st.d    t0, t1, 0
@@ -504,28 +504,28 @@ tlb_huge_update_modify:
        addi.d  t0, ra, 0
 
        /* Convert to entrylo1 */
-       addi.d  t1, $r0, 1
+       addi.d  t1, zero, 1
        slli.d  t1, t1, (HPAGE_SHIFT - 1)
        add.d   t0, t0, t1
        csrwr   t0, LOONGARCH_CSR_TLBELO1
 
        /* Set huge page tlb entry size */
-       addu16i.d       t0, $r0, (CSR_TLBIDX_PS >> 16)
-       addu16i.d       t1, $r0, (PS_HUGE_SIZE << (CSR_TLBIDX_PS_SHIFT - 16))
-       csrxchg t1, t0, LOONGARCH_CSR_TLBIDX
+       addu16i.d       t0, zero, (CSR_TLBIDX_PS >> 16)
+       addu16i.d       t1, zero, (PS_HUGE_SIZE << (CSR_TLBIDX_PS_SHIFT - 16))
+       csrxchg         t1, t0, LOONGARCH_CSR_TLBIDX
 
        tlbwr
 
        /* Reset default page size */
-       addu16i.d       t0, $r0, (CSR_TLBIDX_PS >> 16)
-       addu16i.d       t1, $r0, (PS_DEFAULT_SIZE << (CSR_TLBIDX_PS_SHIFT - 16))
-       csrxchg t1, t0, LOONGARCH_CSR_TLBIDX
+       addu16i.d       t0, zero, (CSR_TLBIDX_PS >> 16)
+       addu16i.d       t1, zero, (PS_DEFAULT_SIZE << (CSR_TLBIDX_PS_SHIFT - 16))
+       csrxchg         t1, t0, LOONGARCH_CSR_TLBIDX
 
 nopage_tlb_modify:
        dbar    0
        csrrd   ra, EXCEPTION_KS2
        la.abs  t0, tlb_do_page_fault_1
-       jirl    $r0, t0, 0
+       jr      t0
 SYM_FUNC_END(handle_tlb_modify)
 
 SYM_FUNC_START(handle_tlb_refill)
index 6b6e167..92e4040 100644 (file)
@@ -21,6 +21,7 @@ ccflags-vdso += $(filter --target=%,$(KBUILD_CFLAGS))
 endif
 
 cflags-vdso := $(ccflags-vdso) \
+       -isystem $(shell $(CC) -print-file-name=include) \
        $(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \
        -O2 -g -fno-strict-aliasing -fno-common -fno-builtin -G0 \
        -fno-stack-protector -fno-jump-tables -DDISABLE_BRANCH_PROFILING \
index f3aa441..e0e9e31 100644 (file)
@@ -155,7 +155,7 @@ config M520x
        select COLDFIRE_PIT_TIMER
        select HAVE_CACHE_SPLIT
        help
-          Freescale Coldfire 5207/5208 processor support.
+         Freescale Coldfire 5207/5208 processor support.
 
 config M523x
        bool "MCF523x"
@@ -322,7 +322,6 @@ config COLDFIRE_SLTIMERS
 
 endif # COLDFIRE
 
-
 comment "Processor Specific Options"
 
 config M68KFPU_EMU
@@ -522,7 +521,7 @@ config CACHE_BOTH
          Split the ColdFire CPU cache, and use half as an instruction cache
          and half as a data cache.
 endchoice
-endif
+endif # HAVE_CACHE_SPLIT
 
 if HAVE_CACHE_CB
 choice
@@ -539,4 +538,4 @@ config CACHE_COPYBACK
        help
          The ColdFire CPU cache is set into Copy-back mode.
 endchoice
-endif
+endif # HAVE_CACHE_CB
index 11b306b..465e28b 100644 (file)
@@ -1,11 +1,11 @@
 # SPDX-License-Identifier: GPL-2.0
 
 config BOOTPARAM
-       bool 'Compiled-in Kernel Boot Parameter'
+       bool "Compiled-in Kernel Boot Parameter"
 
 config BOOTPARAM_STRING
-       string 'Kernel Boot Parameter'
-       default 'console=ttyS0,19200'
+       string "Kernel Boot Parameter"
+       default "console=ttyS0,19200"
        depends on BOOTPARAM
 
 config EARLY_PRINTK
index a104256..53c45cc 100644 (file)
@@ -161,10 +161,11 @@ config VIRT
        select RTC_CLASS
        select RTC_DRV_GOLDFISH
        select TTY
+       select VIRTIO_MENU
        select VIRTIO_MMIO
        help
          This options enable a pure virtual machine based on m68k,
-         VIRTIO MMIO devices and GOLDFISH interfaces (TTY, RTC, PIC)
+         VIRTIO MMIO devices and GOLDFISH interfaces (TTY, RTC, PIC).
 
 config PILOT
        bool
@@ -492,4 +493,4 @@ config ROMKERNEL
 
 endchoice
 
-endif
+endif # !MMU || COLDFIRE
index c181030..a6a886a 100644 (file)
@@ -10,8 +10,6 @@ CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_NET_NS is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_USERFAULTFD=y
-CONFIG_SLAB=y
 CONFIG_KEXEC=y
 CONFIG_BOOTINFO_PROC=y
 CONFIG_M68020=y
@@ -43,8 +41,9 @@ CONFIG_MQ_IOSCHED_KYBER=m
 CONFIG_IOSCHED_BFQ=m
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_BINFMT_MISC=m
+CONFIG_SLAB=y
 # CONFIG_COMPACTION is not set
-CONFIG_ZPOOL=m
+CONFIG_USERFAULTFD=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_DIAG=m
@@ -310,6 +309,7 @@ CONFIG_PARPORT_MFC3=m
 CONFIG_PARPORT_1284=y
 CONFIG_AMIGA_FLOPPY=y
 CONFIG_AMIGA_Z2RAM=y
+CONFIG_ZRAM=m
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_DRBD=m
 CONFIG_BLK_DEV_NBD=m
@@ -580,7 +580,7 @@ CONFIG_CRYPTO_MD4=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD160=m
 CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SM3=m
+CONFIG_CRYPTO_SM3_GENERIC=m
 CONFIG_CRYPTO_WP512=m
 CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_AES_TI=m
@@ -595,7 +595,7 @@ CONFIG_CRYPTO_FCRYPT=m
 CONFIG_CRYPTO_KHAZAD=m
 CONFIG_CRYPTO_SEED=m
 CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_SM4=m
+CONFIG_CRYPTO_SM4_GENERIC=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_LZO=m
@@ -648,11 +648,7 @@ CONFIG_TEST_BLACKHOLE_DEV=m
 CONFIG_FIND_BIT_BENCHMARK=m
 CONFIG_TEST_FIRMWARE=m
 CONFIG_TEST_SYSCTL=m
-CONFIG_BITFIELD_KUNIT=m
-CONFIG_RESOURCE_KUNIT_TEST=m
 CONFIG_LINEAR_RANGES_TEST=m
-CONFIG_CMDLINE_KUNIT_TEST=m
-CONFIG_BITS_TEST=m
 CONFIG_TEST_UDELAY=m
 CONFIG_TEST_STATIC_KEYS=m
 CONFIG_TEST_KMOD=m
index 4075564..bffd24c 100644 (file)
@@ -10,8 +10,6 @@ CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_NET_NS is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_USERFAULTFD=y
-CONFIG_SLAB=y
 CONFIG_KEXEC=y
 CONFIG_BOOTINFO_PROC=y
 CONFIG_M68020=y
@@ -39,8 +37,9 @@ CONFIG_MQ_IOSCHED_KYBER=m
 CONFIG_IOSCHED_BFQ=m
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_BINFMT_MISC=m
+CONFIG_SLAB=y
 # CONFIG_COMPACTION is not set
-CONFIG_ZPOOL=m
+CONFIG_USERFAULTFD=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_DIAG=m
@@ -300,6 +299,7 @@ CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_TEST_ASYNC_DRIVER_PROBE=m
 CONFIG_CONNECTOR=m
+CONFIG_ZRAM=m
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_DRBD=m
 CONFIG_BLK_DEV_NBD=m
@@ -537,7 +537,7 @@ CONFIG_CRYPTO_MD4=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD160=m
 CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SM3=m
+CONFIG_CRYPTO_SM3_GENERIC=m
 CONFIG_CRYPTO_WP512=m
 CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_AES_TI=m
@@ -552,7 +552,7 @@ CONFIG_CRYPTO_FCRYPT=m
 CONFIG_CRYPTO_KHAZAD=m
 CONFIG_CRYPTO_SEED=m
 CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_SM4=m
+CONFIG_CRYPTO_SM4_GENERIC=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_LZO=m
@@ -604,11 +604,7 @@ CONFIG_TEST_BLACKHOLE_DEV=m
 CONFIG_FIND_BIT_BENCHMARK=m
 CONFIG_TEST_FIRMWARE=m
 CONFIG_TEST_SYSCTL=m
-CONFIG_BITFIELD_KUNIT=m
-CONFIG_RESOURCE_KUNIT_TEST=m
 CONFIG_LINEAR_RANGES_TEST=m
-CONFIG_CMDLINE_KUNIT_TEST=m
-CONFIG_BITS_TEST=m
 CONFIG_TEST_UDELAY=m
 CONFIG_TEST_STATIC_KEYS=m
 CONFIG_TEST_KMOD=m
index be0d915..0013425 100644 (file)
@@ -10,8 +10,6 @@ CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_NET_NS is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_USERFAULTFD=y
-CONFIG_SLAB=y
 CONFIG_KEXEC=y
 CONFIG_BOOTINFO_PROC=y
 CONFIG_M68020=y
@@ -46,8 +44,9 @@ CONFIG_MQ_IOSCHED_KYBER=m
 CONFIG_IOSCHED_BFQ=m
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_BINFMT_MISC=m
+CONFIG_SLAB=y
 # CONFIG_COMPACTION is not set
-CONFIG_ZPOOL=m
+CONFIG_USERFAULTFD=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_DIAG=m
@@ -311,6 +310,7 @@ CONFIG_PARPORT=m
 CONFIG_PARPORT_ATARI=m
 CONFIG_PARPORT_1284=y
 CONFIG_ATARI_FLOPPY=y
+CONFIG_ZRAM=m
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_DRBD=m
 CONFIG_BLK_DEV_NBD=m
@@ -557,7 +557,7 @@ CONFIG_CRYPTO_MD4=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD160=m
 CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SM3=m
+CONFIG_CRYPTO_SM3_GENERIC=m
 CONFIG_CRYPTO_WP512=m
 CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_AES_TI=m
@@ -572,7 +572,7 @@ CONFIG_CRYPTO_FCRYPT=m
 CONFIG_CRYPTO_KHAZAD=m
 CONFIG_CRYPTO_SEED=m
 CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_SM4=m
+CONFIG_CRYPTO_SM4_GENERIC=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_LZO=m
@@ -625,11 +625,7 @@ CONFIG_TEST_BLACKHOLE_DEV=m
 CONFIG_FIND_BIT_BENCHMARK=m
 CONFIG_TEST_FIRMWARE=m
 CONFIG_TEST_SYSCTL=m
-CONFIG_BITFIELD_KUNIT=m
-CONFIG_RESOURCE_KUNIT_TEST=m
 CONFIG_LINEAR_RANGES_TEST=m
-CONFIG_CMDLINE_KUNIT_TEST=m
-CONFIG_BITS_TEST=m
 CONFIG_TEST_UDELAY=m
 CONFIG_TEST_STATIC_KEYS=m
 CONFIG_TEST_KMOD=m
index 9af0e2d..42d9696 100644 (file)
@@ -10,8 +10,6 @@ CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_NET_NS is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_USERFAULTFD=y
-CONFIG_SLAB=y
 CONFIG_KEXEC=y
 CONFIG_BOOTINFO_PROC=y
 CONFIG_M68040=y
@@ -36,8 +34,9 @@ CONFIG_MQ_IOSCHED_KYBER=m
 CONFIG_IOSCHED_BFQ=m
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_BINFMT_MISC=m
+CONFIG_SLAB=y
 # CONFIG_COMPACTION is not set
-CONFIG_ZPOOL=m
+CONFIG_USERFAULTFD=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_DIAG=m
@@ -297,6 +296,7 @@ CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_TEST_ASYNC_DRIVER_PROBE=m
 CONFIG_CONNECTOR=m
+CONFIG_ZRAM=m
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_DRBD=m
 CONFIG_BLK_DEV_NBD=m
@@ -529,7 +529,7 @@ CONFIG_CRYPTO_MD4=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD160=m
 CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SM3=m
+CONFIG_CRYPTO_SM3_GENERIC=m
 CONFIG_CRYPTO_WP512=m
 CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_AES_TI=m
@@ -544,7 +544,7 @@ CONFIG_CRYPTO_FCRYPT=m
 CONFIG_CRYPTO_KHAZAD=m
 CONFIG_CRYPTO_SEED=m
 CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_SM4=m
+CONFIG_CRYPTO_SM4_GENERIC=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_LZO=m
@@ -596,11 +596,7 @@ CONFIG_TEST_BLACKHOLE_DEV=m
 CONFIG_FIND_BIT_BENCHMARK=m
 CONFIG_TEST_FIRMWARE=m
 CONFIG_TEST_SYSCTL=m
-CONFIG_BITFIELD_KUNIT=m
-CONFIG_RESOURCE_KUNIT_TEST=m
 CONFIG_LINEAR_RANGES_TEST=m
-CONFIG_CMDLINE_KUNIT_TEST=m
-CONFIG_BITS_TEST=m
 CONFIG_TEST_UDELAY=m
 CONFIG_TEST_STATIC_KEYS=m
 CONFIG_TEST_KMOD=m
index 49341d6..97d6d9a 100644 (file)
@@ -10,8 +10,6 @@ CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_NET_NS is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_USERFAULTFD=y
-CONFIG_SLAB=y
 CONFIG_KEXEC=y
 CONFIG_BOOTINFO_PROC=y
 CONFIG_M68020=y
@@ -38,8 +36,9 @@ CONFIG_MQ_IOSCHED_KYBER=m
 CONFIG_IOSCHED_BFQ=m
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_BINFMT_MISC=m
+CONFIG_SLAB=y
 # CONFIG_COMPACTION is not set
-CONFIG_ZPOOL=m
+CONFIG_USERFAULTFD=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_DIAG=m
@@ -299,6 +298,7 @@ CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_TEST_ASYNC_DRIVER_PROBE=m
 CONFIG_CONNECTOR=m
+CONFIG_ZRAM=m
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_DRBD=m
 CONFIG_BLK_DEV_NBD=m
@@ -539,7 +539,7 @@ CONFIG_CRYPTO_MD4=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD160=m
 CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SM3=m
+CONFIG_CRYPTO_SM3_GENERIC=m
 CONFIG_CRYPTO_WP512=m
 CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_AES_TI=m
@@ -554,7 +554,7 @@ CONFIG_CRYPTO_FCRYPT=m
 CONFIG_CRYPTO_KHAZAD=m
 CONFIG_CRYPTO_SEED=m
 CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_SM4=m
+CONFIG_CRYPTO_SM4_GENERIC=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_LZO=m
@@ -606,11 +606,7 @@ CONFIG_TEST_BLACKHOLE_DEV=m
 CONFIG_FIND_BIT_BENCHMARK=m
 CONFIG_TEST_FIRMWARE=m
 CONFIG_TEST_SYSCTL=m
-CONFIG_BITFIELD_KUNIT=m
-CONFIG_RESOURCE_KUNIT_TEST=m
 CONFIG_LINEAR_RANGES_TEST=m
-CONFIG_CMDLINE_KUNIT_TEST=m
-CONFIG_BITS_TEST=m
 CONFIG_TEST_UDELAY=m
 CONFIG_TEST_STATIC_KEYS=m
 CONFIG_TEST_KMOD=m
index 92b33d5..8cbfc1c 100644 (file)
@@ -10,8 +10,6 @@ CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_NET_NS is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_USERFAULTFD=y
-CONFIG_SLAB=y
 CONFIG_KEXEC=y
 CONFIG_BOOTINFO_PROC=y
 CONFIG_M68020=y
@@ -37,8 +35,9 @@ CONFIG_MQ_IOSCHED_KYBER=m
 CONFIG_IOSCHED_BFQ=m
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_BINFMT_MISC=m
+CONFIG_SLAB=y
 # CONFIG_COMPACTION is not set
-CONFIG_ZPOOL=m
+CONFIG_USERFAULTFD=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_DIAG=m
@@ -302,6 +301,7 @@ CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_TEST_ASYNC_DRIVER_PROBE=m
 CONFIG_CONNECTOR=m
 CONFIG_BLK_DEV_SWIM=m
+CONFIG_ZRAM=m
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_DRBD=m
 CONFIG_BLK_DEV_NBD=m
@@ -559,7 +559,7 @@ CONFIG_CRYPTO_MD4=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD160=m
 CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SM3=m
+CONFIG_CRYPTO_SM3_GENERIC=m
 CONFIG_CRYPTO_WP512=m
 CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_AES_TI=m
@@ -574,7 +574,7 @@ CONFIG_CRYPTO_FCRYPT=m
 CONFIG_CRYPTO_KHAZAD=m
 CONFIG_CRYPTO_SEED=m
 CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_SM4=m
+CONFIG_CRYPTO_SM4_GENERIC=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_LZO=m
@@ -627,11 +627,7 @@ CONFIG_TEST_BLACKHOLE_DEV=m
 CONFIG_FIND_BIT_BENCHMARK=m
 CONFIG_TEST_FIRMWARE=m
 CONFIG_TEST_SYSCTL=m
-CONFIG_BITFIELD_KUNIT=m
-CONFIG_RESOURCE_KUNIT_TEST=m
 CONFIG_LINEAR_RANGES_TEST=m
-CONFIG_CMDLINE_KUNIT_TEST=m
-CONFIG_BITS_TEST=m
 CONFIG_TEST_UDELAY=m
 CONFIG_TEST_STATIC_KEYS=m
 CONFIG_TEST_KMOD=m
index 6aaa947..9f45fe6 100644 (file)
@@ -10,8 +10,6 @@ CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_NET_NS is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_USERFAULTFD=y
-CONFIG_SLAB=y
 CONFIG_KEXEC=y
 CONFIG_BOOTINFO_PROC=y
 CONFIG_M68020=y
@@ -57,8 +55,9 @@ CONFIG_MQ_IOSCHED_KYBER=m
 CONFIG_IOSCHED_BFQ=m
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_BINFMT_MISC=m
+CONFIG_SLAB=y
 # CONFIG_COMPACTION is not set
-CONFIG_ZPOOL=m
+CONFIG_USERFAULTFD=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_DIAG=m
@@ -331,6 +330,7 @@ CONFIG_AMIGA_FLOPPY=y
 CONFIG_ATARI_FLOPPY=y
 CONFIG_BLK_DEV_SWIM=m
 CONFIG_AMIGA_Z2RAM=y
+CONFIG_ZRAM=m
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_DRBD=m
 CONFIG_BLK_DEV_NBD=m
@@ -645,7 +645,7 @@ CONFIG_CRYPTO_MD4=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD160=m
 CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SM3=m
+CONFIG_CRYPTO_SM3_GENERIC=m
 CONFIG_CRYPTO_WP512=m
 CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_AES_TI=m
@@ -660,7 +660,7 @@ CONFIG_CRYPTO_FCRYPT=m
 CONFIG_CRYPTO_KHAZAD=m
 CONFIG_CRYPTO_SEED=m
 CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_SM4=m
+CONFIG_CRYPTO_SM4_GENERIC=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_LZO=m
@@ -713,11 +713,7 @@ CONFIG_TEST_BLACKHOLE_DEV=m
 CONFIG_FIND_BIT_BENCHMARK=m
 CONFIG_TEST_FIRMWARE=m
 CONFIG_TEST_SYSCTL=m
-CONFIG_BITFIELD_KUNIT=m
-CONFIG_RESOURCE_KUNIT_TEST=m
 CONFIG_LINEAR_RANGES_TEST=m
-CONFIG_CMDLINE_KUNIT_TEST=m
-CONFIG_BITS_TEST=m
 CONFIG_TEST_UDELAY=m
 CONFIG_TEST_STATIC_KEYS=m
 CONFIG_TEST_KMOD=m
index b62d65e..4736cfa 100644 (file)
@@ -10,8 +10,6 @@ CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_NET_NS is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_USERFAULTFD=y
-CONFIG_SLAB=y
 CONFIG_KEXEC=y
 CONFIG_BOOTINFO_PROC=y
 CONFIG_M68030=y
@@ -35,8 +33,9 @@ CONFIG_MQ_IOSCHED_KYBER=m
 CONFIG_IOSCHED_BFQ=m
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_BINFMT_MISC=m
+CONFIG_SLAB=y
 # CONFIG_COMPACTION is not set
-CONFIG_ZPOOL=m
+CONFIG_USERFAULTFD=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_DIAG=m
@@ -296,6 +295,7 @@ CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_TEST_ASYNC_DRIVER_PROBE=m
 CONFIG_CONNECTOR=m
+CONFIG_ZRAM=m
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_DRBD=m
 CONFIG_BLK_DEV_NBD=m
@@ -528,7 +528,7 @@ CONFIG_CRYPTO_MD4=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD160=m
 CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SM3=m
+CONFIG_CRYPTO_SM3_GENERIC=m
 CONFIG_CRYPTO_WP512=m
 CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_AES_TI=m
@@ -543,7 +543,7 @@ CONFIG_CRYPTO_FCRYPT=m
 CONFIG_CRYPTO_KHAZAD=m
 CONFIG_CRYPTO_SEED=m
 CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_SM4=m
+CONFIG_CRYPTO_SM4_GENERIC=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_LZO=m
@@ -595,11 +595,7 @@ CONFIG_TEST_BLACKHOLE_DEV=m
 CONFIG_FIND_BIT_BENCHMARK=m
 CONFIG_TEST_FIRMWARE=m
 CONFIG_TEST_SYSCTL=m
-CONFIG_BITFIELD_KUNIT=m
-CONFIG_RESOURCE_KUNIT_TEST=m
 CONFIG_LINEAR_RANGES_TEST=m
-CONFIG_CMDLINE_KUNIT_TEST=m
-CONFIG_BITS_TEST=m
 CONFIG_TEST_UDELAY=m
 CONFIG_TEST_STATIC_KEYS=m
 CONFIG_TEST_KMOD=m
index 8ecf261..638cd38 100644 (file)
@@ -10,8 +10,6 @@ CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_NET_NS is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_USERFAULTFD=y
-CONFIG_SLAB=y
 CONFIG_KEXEC=y
 CONFIG_BOOTINFO_PROC=y
 CONFIG_M68040=y
@@ -36,8 +34,9 @@ CONFIG_MQ_IOSCHED_KYBER=m
 CONFIG_IOSCHED_BFQ=m
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_BINFMT_MISC=m
+CONFIG_SLAB=y
 # CONFIG_COMPACTION is not set
-CONFIG_ZPOOL=m
+CONFIG_USERFAULTFD=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_DIAG=m
@@ -297,6 +296,7 @@ CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_TEST_ASYNC_DRIVER_PROBE=m
 CONFIG_CONNECTOR=m
+CONFIG_ZRAM=m
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_DRBD=m
 CONFIG_BLK_DEV_NBD=m
@@ -529,7 +529,7 @@ CONFIG_CRYPTO_MD4=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD160=m
 CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SM3=m
+CONFIG_CRYPTO_SM3_GENERIC=m
 CONFIG_CRYPTO_WP512=m
 CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_AES_TI=m
@@ -544,7 +544,7 @@ CONFIG_CRYPTO_FCRYPT=m
 CONFIG_CRYPTO_KHAZAD=m
 CONFIG_CRYPTO_SEED=m
 CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_SM4=m
+CONFIG_CRYPTO_SM4_GENERIC=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_LZO=m
@@ -596,11 +596,7 @@ CONFIG_TEST_BLACKHOLE_DEV=m
 CONFIG_FIND_BIT_BENCHMARK=m
 CONFIG_TEST_FIRMWARE=m
 CONFIG_TEST_SYSCTL=m
-CONFIG_BITFIELD_KUNIT=m
-CONFIG_RESOURCE_KUNIT_TEST=m
 CONFIG_LINEAR_RANGES_TEST=m
-CONFIG_CMDLINE_KUNIT_TEST=m
-CONFIG_BITS_TEST=m
 CONFIG_TEST_UDELAY=m
 CONFIG_TEST_STATIC_KEYS=m
 CONFIG_TEST_KMOD=m
index 7540d90..ec8b6bb 100644 (file)
@@ -10,8 +10,6 @@ CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_NET_NS is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_USERFAULTFD=y
-CONFIG_SLAB=y
 CONFIG_KEXEC=y
 CONFIG_BOOTINFO_PROC=y
 CONFIG_M68040=y
@@ -37,8 +35,9 @@ CONFIG_MQ_IOSCHED_KYBER=m
 CONFIG_IOSCHED_BFQ=m
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_BINFMT_MISC=m
+CONFIG_SLAB=y
 # CONFIG_COMPACTION is not set
-CONFIG_ZPOOL=m
+CONFIG_USERFAULTFD=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_DIAG=m
@@ -301,6 +300,7 @@ CONFIG_CONNECTOR=m
 CONFIG_PARPORT=m
 CONFIG_PARPORT_PC=m
 CONFIG_PARPORT_1284=y
+CONFIG_ZRAM=m
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_DRBD=m
 CONFIG_BLK_DEV_NBD=m
@@ -546,7 +546,7 @@ CONFIG_CRYPTO_MD4=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD160=m
 CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SM3=m
+CONFIG_CRYPTO_SM3_GENERIC=m
 CONFIG_CRYPTO_WP512=m
 CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_AES_TI=m
@@ -561,7 +561,7 @@ CONFIG_CRYPTO_FCRYPT=m
 CONFIG_CRYPTO_KHAZAD=m
 CONFIG_CRYPTO_SEED=m
 CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_SM4=m
+CONFIG_CRYPTO_SM4_GENERIC=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_LZO=m
@@ -614,11 +614,7 @@ CONFIG_TEST_BLACKHOLE_DEV=m
 CONFIG_FIND_BIT_BENCHMARK=m
 CONFIG_TEST_FIRMWARE=m
 CONFIG_TEST_SYSCTL=m
-CONFIG_BITFIELD_KUNIT=m
-CONFIG_RESOURCE_KUNIT_TEST=m
 CONFIG_LINEAR_RANGES_TEST=m
-CONFIG_CMDLINE_KUNIT_TEST=m
-CONFIG_BITS_TEST=m
 CONFIG_TEST_UDELAY=m
 CONFIG_TEST_STATIC_KEYS=m
 CONFIG_TEST_KMOD=m
index 832b459..7d8dc57 100644 (file)
@@ -10,8 +10,6 @@ CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_NET_NS is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_USERFAULTFD=y
-CONFIG_SLAB=y
 CONFIG_KEXEC=y
 CONFIG_BOOTINFO_PROC=y
 CONFIG_SUN3=y
@@ -33,8 +31,9 @@ CONFIG_MQ_IOSCHED_KYBER=m
 CONFIG_IOSCHED_BFQ=m
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_BINFMT_MISC=m
+CONFIG_SLAB=y
 # CONFIG_COMPACTION is not set
-CONFIG_ZPOOL=m
+CONFIG_USERFAULTFD=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_DIAG=m
@@ -294,6 +293,7 @@ CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_TEST_ASYNC_DRIVER_PROBE=m
 CONFIG_CONNECTOR=m
+CONFIG_ZRAM=m
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_DRBD=m
 CONFIG_BLK_DEV_NBD=m
@@ -528,7 +528,7 @@ CONFIG_CRYPTO_MD4=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD160=m
 CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SM3=m
+CONFIG_CRYPTO_SM3_GENERIC=m
 CONFIG_CRYPTO_WP512=m
 CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_AES_TI=m
@@ -543,7 +543,7 @@ CONFIG_CRYPTO_FCRYPT=m
 CONFIG_CRYPTO_KHAZAD=m
 CONFIG_CRYPTO_SEED=m
 CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_SM4=m
+CONFIG_CRYPTO_SM4_GENERIC=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_LZO=m
@@ -594,11 +594,7 @@ CONFIG_TEST_BLACKHOLE_DEV=m
 CONFIG_FIND_BIT_BENCHMARK=m
 CONFIG_TEST_FIRMWARE=m
 CONFIG_TEST_SYSCTL=m
-CONFIG_BITFIELD_KUNIT=m
-CONFIG_RESOURCE_KUNIT_TEST=m
 CONFIG_LINEAR_RANGES_TEST=m
-CONFIG_CMDLINE_KUNIT_TEST=m
-CONFIG_BITS_TEST=m
 CONFIG_TEST_UDELAY=m
 CONFIG_TEST_STATIC_KEYS=m
 CONFIG_TEST_KMOD=m
index 9171b68..96290ae 100644 (file)
@@ -10,8 +10,6 @@ CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_NET_NS is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_USERFAULTFD=y
-CONFIG_SLAB=y
 CONFIG_KEXEC=y
 CONFIG_BOOTINFO_PROC=y
 CONFIG_SUN3X=y
@@ -33,8 +31,9 @@ CONFIG_MQ_IOSCHED_KYBER=m
 CONFIG_IOSCHED_BFQ=m
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_BINFMT_MISC=m
+CONFIG_SLAB=y
 # CONFIG_COMPACTION is not set
-CONFIG_ZPOOL=m
+CONFIG_USERFAULTFD=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_DIAG=m
@@ -294,6 +293,7 @@ CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_TEST_ASYNC_DRIVER_PROBE=m
 CONFIG_CONNECTOR=m
+CONFIG_ZRAM=m
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_DRBD=m
 CONFIG_BLK_DEV_NBD=m
@@ -527,7 +527,7 @@ CONFIG_CRYPTO_MD4=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD160=m
 CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_SM3=m
+CONFIG_CRYPTO_SM3_GENERIC=m
 CONFIG_CRYPTO_WP512=m
 CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_AES_TI=m
@@ -542,7 +542,7 @@ CONFIG_CRYPTO_FCRYPT=m
 CONFIG_CRYPTO_KHAZAD=m
 CONFIG_CRYPTO_SEED=m
 CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_SM4=m
+CONFIG_CRYPTO_SM4_GENERIC=m
 CONFIG_CRYPTO_TEA=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_LZO=m
@@ -594,11 +594,7 @@ CONFIG_TEST_BLACKHOLE_DEV=m
 CONFIG_FIND_BIT_BENCHMARK=m
 CONFIG_TEST_FIRMWARE=m
 CONFIG_TEST_SYSCTL=m
-CONFIG_BITFIELD_KUNIT=m
-CONFIG_RESOURCE_KUNIT_TEST=m
 CONFIG_LINEAR_RANGES_TEST=m
-CONFIG_CMDLINE_KUNIT_TEST=m
-CONFIG_BITS_TEST=m
 CONFIG_TEST_UDELAY=m
 CONFIG_TEST_STATIC_KEYS=m
 CONFIG_TEST_KMOD=m
index 267b02c..a708fbd 100644 (file)
@@ -138,7 +138,7 @@ static int __init nfhd_init_one(int id, u32 blocks, u32 bsize)
        return 0;
 
 out_cleanup_disk:
-       blk_cleanup_disk(dev->disk);
+       put_disk(dev->disk);
 free_dev:
        kfree(dev);
 out:
@@ -180,7 +180,7 @@ static void __exit nfhd_exit(void)
        list_for_each_entry_safe(dev, next, &nfhd_list, list) {
                list_del(&dev->list);
                del_gendisk(dev->disk);
-               blk_cleanup_disk(dev->disk);
+               put_disk(dev->disk);
                kfree(dev);
        }
        unregister_blkdev(major_num, "nfhd");
index 51283db..87c2cd6 100644 (file)
@@ -510,7 +510,7 @@ static inline int fls(unsigned int x)
        return 32 - cnt;
 }
 
-static inline int __fls(int x)
+static inline unsigned long __fls(unsigned long x)
 {
        return fls(x) - 1;
 }
index ffeda9a..d86b400 100644 (file)
@@ -151,6 +151,7 @@ static inline void release_thread(struct task_struct *dead_task)
 }
 
 unsigned long __get_wchan(struct task_struct *p);
+void show_registers(struct pt_regs *regs);
 
 #define        KSTK_EIP(tsk)   \
     ({                 \
index e4db7e2..b091ee9 100644 (file)
 #define BI_VIRT_VIRTIO_BASE    0x8004
 #define BI_VIRT_CTRL_BASE      0x8005
 
+/*
+ * A random seed used to initialize the RNG. Record format:
+ *
+ *   - length       [ 2 bytes, 16-bit big endian ]
+ *   - seed data    [ `length` bytes, padded to preserve 2-byte alignment ]
+ */
+#define BI_VIRT_RNG_SEED       0x8006
+
 #define VIRT_BOOTI_VERSION     MK_BI_VERSION(2, 0)
 
 #endif /* _UAPI_ASM_M68K_BOOTINFO_MAC_H */
index 203d9cb..95ecf3a 100644 (file)
@@ -34,7 +34,7 @@
 struct bi_record {
        __be16 tag;                     /* tag ID */
        __be16 size;                    /* size of record (in bytes) */
-       __be32 data[0];                 /* data */
+       __be32 data[];                  /* data */
 };
 
 
@@ -168,7 +168,7 @@ struct bootversion {
        struct {
                __be32 machtype;
                __be32 version;
-       } machversions[0];
+       } machversions[];
 } __packed;
 
 #endif /* __ASSEMBLY__ */
index 59fc63f..5c8cba0 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/uaccess.h>
 #include <asm/traps.h>
 #include <asm/machdep.h>
+#include <asm/processor.h>
 #include <asm/siginfo.h>
 #include <asm/tlbflush.h>
 
index de156a0..010b3b5 100644 (file)
@@ -25,7 +25,7 @@
  *               check this.)
  * 990605 (jmt) - Rearranged things a bit wrt IOP detection; iop_present is
  *               gone, IOP base addresses are now in an array and the
- *               globally-visible functions take an IOP number instead of an
+ *               globally-visible functions take an IOP number instead of
  *               an actual base address.
  * 990610 (jmt) - Finished the message passing framework and it seems to work.
  *               Sending _definitely_ works; my adb-bus.c mods can send
@@ -66,7 +66,7 @@
  * a shared memory area in the IOP RAM. Each IOP has seven "channels"; each
  * channel is connected to a specific software driver on the IOP. For example
  * on the SCC IOP there is one channel for each serial port. Each channel has
- * an incoming and and outgoing message queue with a depth of one.
+ * an incoming and an outgoing message queue with a depth of one.
  *
  * A message is 32 bytes plus a state byte for the channel (MSG_IDLE, MSG_NEW,
  * MSG_RCVD, MSG_COMPLETE). To send a message you copy the message into the
index e357538..5cbaf6e 100644 (file)
 #include <asm/mac_baboon.h>
 #include <asm/hwtest.h>
 #include <asm/irq_regs.h>
-
-extern void show_registers(struct pt_regs *);
-
-irqreturn_t mac_nmi_handler(int, void *);
+#include <asm/processor.h>
 
 static unsigned int mac_irq_startup(struct irq_data *);
 static void mac_irq_shutdown(struct irq_data *);
@@ -142,6 +139,21 @@ static struct irq_chip mac_irq_chip = {
        .irq_shutdown   = mac_irq_shutdown,
 };
 
+static irqreturn_t mac_nmi_handler(int irq, void *dev_id)
+{
+       static volatile int in_nmi;
+
+       if (in_nmi)
+               return IRQ_HANDLED;
+       in_nmi = 1;
+
+       pr_info("Non-Maskable Interrupt\n");
+       show_registers(get_irq_regs());
+
+       in_nmi = 0;
+       return IRQ_HANDLED;
+}
+
 void __init mac_init_IRQ(void)
 {
        m68k_setup_irq_controller(&mac_irq_chip, handle_simple_irq, IRQ_USER,
@@ -254,18 +266,3 @@ static void mac_irq_shutdown(struct irq_data *data)
        else
                mac_irq_disable(data);
 }
-
-static volatile int in_nmi;
-
-irqreturn_t mac_nmi_handler(int irq, void *dev_id)
-{
-       if (in_nmi)
-               return IRQ_HANDLED;
-       in_nmi = 1;
-
-       pr_info("Non-Maskable Interrupt\n");
-       show_registers(get_irq_regs());
-
-       in_nmi = 0;
-       return IRQ_HANDLED;
-}
index a4991d2..9760e90 100644 (file)
@@ -30,11 +30,10 @@ drivers used by the Q40, apart from the very obvious (console etc.):
                     genrtc.c           # RTC
                char/joystick/*         # most of this should work, not
                                        # in default config.in
-               block/q40ide.c          # startup for ide
-                     ide*              # see Documentation/ide/ide.rst
-                     floppy.c          # normal PC driver, DMA emu in asm/floppy.h
+               block/floppy.c          # normal PC driver, DMA emu in asm/floppy.h
                                        # and arch/m68k/kernel/entry.S
                                        # see drivers/block/README.fd
+               ata/pata_falcon.c
                net/ne.c
                video/q40fb.c
                parport/*
index 6886a5d..d15057d 100644 (file)
@@ -32,7 +32,7 @@
  *            33   : frame int (50/200 Hz periodic timer)
  *            34   : sample int (10/20 KHz periodic timer)
  *
-*/
+ */
 
 static void q40_irq_handler(unsigned int, struct pt_regs *fp);
 static void q40_irq_enable(struct irq_data *data);
index 7ec2081..7321b3b 100644 (file)
@@ -211,7 +211,7 @@ void clear_context(unsigned long context)
 
      if(context) {
             if(!ctx_alloc[context])
-                    panic("clear_context: context not allocated\n");
+                    panic("%s: context not allocated\n", __func__);
 
             ctx_alloc[context]->context = SUN3_INVALID_CONTEXT;
             ctx_alloc[context] = (struct mm_struct *)0;
@@ -261,7 +261,7 @@ unsigned long get_free_context(struct mm_struct *mm)
                }
                // check to make sure one was really free...
                if(new == CONTEXTS_NUM)
-                       panic("get_free_context: failed to find free context");
+                       panic("%s: failed to find free context", __func__);
        }
 
        ctx_alloc[new] = mm;
@@ -369,16 +369,15 @@ int mmu_emu_handle_fault (unsigned long vaddr, int read_flag, int kernel_fault)
        }
 
 #ifdef DEBUG_MMU_EMU
-       pr_info("mmu_emu_handle_fault: vaddr=%lx type=%s crp=%p\n",
-               vaddr, read_flag ? "read" : "write", crp);
+       pr_info("%s: vaddr=%lx type=%s crp=%p\n", __func__, vaddr,
+               read_flag ? "read" : "write", crp);
 #endif
 
        segment = (vaddr >> SUN3_PMEG_SIZE_BITS) & 0x7FF;
        offset  = (vaddr >> SUN3_PTE_SIZE_BITS) & 0xF;
 
 #ifdef DEBUG_MMU_EMU
-       pr_info("mmu_emu_handle_fault: segment=%lx offset=%lx\n", segment,
-               offset);
+       pr_info("%s: segment=%lx offset=%lx\n", __func__, segment, offset);
 #endif
 
        pte = (pte_t *) pgd_val (*(crp + segment));
index 632ba20..4ab2294 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <linux/reboot.h>
 #include <linux/serial_core.h>
+#include <linux/random.h>
 #include <clocksource/timer-goldfish.h>
 
 #include <asm/bootinfo.h>
@@ -92,6 +93,16 @@ int __init virt_parse_bootinfo(const struct bi_record *record)
                data += 4;
                virt_bi_data.virtio.irq = be32_to_cpup(data);
                break;
+       case BI_VIRT_RNG_SEED: {
+               u16 len = be16_to_cpup(data);
+               add_bootloader_randomness(data + 2, len);
+               /*
+                * Zero the data to preserve forward secrecy, and zero the
+                * length to prevent kexec from using it.
+                */
+               memzero_explicit((void *)data, len + 2);
+               break;
+       }
        default:
                unknown = 1;
                break;
index 95818f9..896aa6e 100644 (file)
@@ -12,6 +12,7 @@
 #include <asm/hwtest.h>
 #include <asm/irq.h>
 #include <asm/irq_regs.h>
+#include <asm/processor.h>
 #include <asm/virt.h>
 
 #define GFPIC_REG_IRQ_PENDING           0x04
@@ -19,8 +20,6 @@
 #define GFPIC_REG_IRQ_DISABLE           0x0c
 #define GFPIC_REG_IRQ_ENABLE            0x10
 
-extern void show_registers(struct pt_regs *regs);
-
 static struct resource picres[6];
 static const char *picname[6] = {
        "goldfish_pic.0",
index cb820f1..1560c41 100644 (file)
@@ -8,20 +8,15 @@
 
 #define VIRTIO_BUS_NB  128
 
-static int __init virt_virtio_init(unsigned int id)
+static struct platform_device * __init virt_virtio_init(unsigned int id)
 {
        const struct resource res[] = {
                DEFINE_RES_MEM(virt_bi_data.virtio.mmio + id * 0x200, 0x200),
                DEFINE_RES_IRQ(virt_bi_data.virtio.irq + id),
        };
-       struct platform_device *pdev;
 
-       pdev = platform_device_register_simple("virtio-mmio", id,
+       return platform_device_register_simple("virtio-mmio", id,
                                               res, ARRAY_SIZE(res));
-       if (IS_ERR(pdev))
-               return PTR_ERR(pdev);
-
-       return 0;
 }
 
 static int __init virt_platform_init(void)
@@ -35,8 +30,10 @@ static int __init virt_platform_init(void)
                DEFINE_RES_MEM(virt_bi_data.rtc.mmio + 0x1000, 0x1000),
                DEFINE_RES_IRQ(virt_bi_data.rtc.irq + 1),
        };
-       struct platform_device *pdev;
+       struct platform_device *pdev1, *pdev2;
+       struct platform_device *pdevs[VIRTIO_BUS_NB];
        unsigned int i;
+       int ret = 0;
 
        if (!MACH_IS_VIRT)
                return -ENODEV;
@@ -44,29 +41,40 @@ static int __init virt_platform_init(void)
        /* We need this to have DMA'able memory provided to goldfish-tty */
        min_low_pfn = 0;
 
-       pdev = platform_device_register_simple("goldfish_tty",
-                                              PLATFORM_DEVID_NONE,
-                                              goldfish_tty_res,
-                                              ARRAY_SIZE(goldfish_tty_res));
-       if (IS_ERR(pdev))
-               return PTR_ERR(pdev);
+       pdev1 = platform_device_register_simple("goldfish_tty",
+                                               PLATFORM_DEVID_NONE,
+                                               goldfish_tty_res,
+                                               ARRAY_SIZE(goldfish_tty_res));
+       if (IS_ERR(pdev1))
+               return PTR_ERR(pdev1);
 
-       pdev = platform_device_register_simple("goldfish_rtc",
-                                              PLATFORM_DEVID_NONE,
-                                              goldfish_rtc_res,
-                                              ARRAY_SIZE(goldfish_rtc_res));
-       if (IS_ERR(pdev))
-               return PTR_ERR(pdev);
+       pdev2 = platform_device_register_simple("goldfish_rtc",
+                                               PLATFORM_DEVID_NONE,
+                                               goldfish_rtc_res,
+                                               ARRAY_SIZE(goldfish_rtc_res));
+       if (IS_ERR(pdev2)) {
+               ret = PTR_ERR(pdev2);
+               goto err_unregister_tty;
+       }
 
        for (i = 0; i < VIRTIO_BUS_NB; i++) {
-               int err;
-
-               err = virt_virtio_init(i);
-               if (err)
-                       return err;
+               pdevs[i] = virt_virtio_init(i);
+               if (IS_ERR(pdevs[i])) {
+                       ret = PTR_ERR(pdevs[i]);
+                       goto err_unregister_rtc_virtio;
+               }
        }
 
        return 0;
+
+err_unregister_rtc_virtio:
+       while (i > 0)
+               platform_device_unregister(pdevs[--i]);
+       platform_device_unregister(pdev2);
+err_unregister_tty:
+       platform_device_unregister(pdev1);
+
+       return ret;
 }
 
 arch_initcall(virt_platform_init);
index db09d45..9457894 100644 (file)
@@ -56,7 +56,7 @@ config MIPS
        select HAVE_ARCH_TRACEHOOK
        select HAVE_ARCH_TRANSPARENT_HUGEPAGE if CPU_SUPPORTS_HUGEPAGES
        select HAVE_ASM_MODVERSIONS
-       select HAVE_CONTEXT_TRACKING
+       select HAVE_CONTEXT_TRACKING_USER
        select HAVE_TIF_NOHZ
        select HAVE_C_RECORDMCOUNT
        select HAVE_DEBUG_KMEMLEAK
index 6cdcbf4..9cb9ed4 100644 (file)
@@ -263,7 +263,7 @@ static int next_cpu_for_irq(struct irq_data *data)
 
 #ifdef CONFIG_SMP
        int cpu;
-       struct cpumask *mask = irq_data_get_affinity_mask(data);
+       const struct cpumask *mask = irq_data_get_affinity_mask(data);
        int weight = cpumask_weight(mask);
        struct octeon_ciu_chip_data *cd = irq_data_get_irq_chip_data(data);
 
@@ -758,7 +758,7 @@ static void octeon_irq_cpu_offline_ciu(struct irq_data *data)
 {
        int cpu = smp_processor_id();
        cpumask_t new_affinity;
-       struct cpumask *mask = irq_data_get_affinity_mask(data);
+       const struct cpumask *mask = irq_data_get_affinity_mask(data);
 
        if (!cpumask_test_cpu(cpu, mask))
                return;
index 3185fd3..c5c6864 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef _ASM_MIPS_JUMP_LABEL_H
 #define _ASM_MIPS_JUMP_LABEL_H
 
+#define arch_jump_label_transform_static arch_jump_label_transform
+
 #ifndef __ASSEMBLY__
 
 #include <linux/types.h>
index 98ea977..67c15f3 100644 (file)
@@ -7,8 +7,9 @@
 #define NR_MIPS_CPU_IRQS       8
 #define NR_MAX_CHAINED_IRQS    40 /* Chained IRQs means those not directly used by devices */
 #define NR_IRQS                        (NR_IRQS_LEGACY + NR_MIPS_CPU_IRQS + NR_MAX_CHAINED_IRQS + 256)
-
+#define MAX_IO_PICS            1
 #define MIPS_CPU_IRQ_BASE      NR_IRQS_LEGACY
+#define GSI_MIN_CPU_IRQ                0
 
 #include <asm/mach-generic/irq.h>
 
index 2d3bf8e..6122ef9 100644 (file)
@@ -60,7 +60,7 @@ struct ucontext {
        sigset_t                uc_sigmask;
 
        /* Extended context structures may follow ucontext */
-       unsigned long long      uc_extcontext[0];
+       unsigned long long      uc_extcontext[];
 };
 
 #endif /* __MIPS_UAPI_ASM_UCONTEXT_H */
index 662c8db..71a882c 100644 (file)
@@ -88,3 +88,22 @@ void arch_jump_label_transform(struct jump_entry *e,
 
        mutex_unlock(&text_mutex);
 }
+
+#ifdef CONFIG_MODULES
+void jump_label_apply_nops(struct module *mod)
+{
+       struct jump_entry *iter_start = mod->jump_entries;
+       struct jump_entry *iter_stop = iter_start + mod->num_jump_entries;
+       struct jump_entry *iter;
+
+       /* if the module doesn't have jump label entries, just return */
+       if (iter_start == iter_stop)
+               return;
+
+       for (iter = iter_start; iter < iter_stop; iter++) {
+               /* Only write NOPs for arch_branch_static(). */
+               if (jump_label_init_type(iter) == JUMP_LABEL_NOP)
+                       arch_jump_label_transform(iter, JUMP_LABEL_NOP);
+       }
+}
+#endif
index 14f46d1..0c936cb 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/spinlock.h>
 #include <linux/jump_label.h>
 
+extern void jump_label_apply_nops(struct module *mod);
 
 struct mips_hi16 {
        struct mips_hi16 *next;
@@ -428,8 +429,8 @@ int module_finalize(const Elf_Ehdr *hdr,
        const Elf_Shdr *s;
        char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
 
-       /* Make jump label nops. */
-       jump_label_apply_nops(me);
+       if (IS_ENABLED(CONFIG_JUMP_LABEL))
+               jump_label_apply_nops(me);
 
        INIT_LIST_HEAD(&me->arch.dbe_list);
        for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
index 8ae15c2..c6ad6f8 100644 (file)
@@ -25,7 +25,7 @@ struct or1k_frameinfo {
 /*
  * Verify a frameinfo structure.  The return address should be a valid text
  * address.  The frame pointer may be null if its the last frame, otherwise
- * the frame pointer should point to a location in the stack after the the
+ * the frame pointer should point to a location in the stack after the
  * top of the next frame up.
  */
 static inline int or1k_frameinfo_valid(struct or1k_frameinfo *frameinfo)
index 5f2448d..fa40005 100644 (file)
@@ -10,6 +10,7 @@ config PARISC
        select ARCH_WANT_FRAME_POINTERS
        select ARCH_HAS_ELF_RANDOMIZE
        select ARCH_HAS_STRICT_KERNEL_RWX
+       select ARCH_HAS_STRICT_MODULE_RWX
        select ARCH_HAS_UBSAN_SANITIZE_ALL
        select ARCH_HAS_PTE_SPECIAL
        select ARCH_NO_SG_CHAIN
index d63a2ac..55d29c4 100644 (file)
@@ -12,7 +12,7 @@ static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
        pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
 }
 
-#if defined(CONFIG_STI_CONSOLE) || defined(CONFIG_FB_STI)
+#if defined(CONFIG_FB_STI)
 int fb_is_primary_device(struct fb_info *info);
 #else
 static inline int fb_is_primary_device(struct fb_info *info)
index 2673d57..94652e1 100644 (file)
@@ -224,8 +224,13 @@ int main(void)
        BLANK();
        DEFINE(ASM_SIGFRAME_SIZE, PARISC_RT_SIGFRAME_SIZE);
        DEFINE(SIGFRAME_CONTEXT_REGS, offsetof(struct rt_sigframe, uc.uc_mcontext) - PARISC_RT_SIGFRAME_SIZE);
+#ifdef CONFIG_64BIT
        DEFINE(ASM_SIGFRAME_SIZE32, PARISC_RT_SIGFRAME_SIZE32);
        DEFINE(SIGFRAME_CONTEXT_REGS32, offsetof(struct compat_rt_sigframe, uc.uc_mcontext) - PARISC_RT_SIGFRAME_SIZE32);
+#else
+       DEFINE(ASM_SIGFRAME_SIZE32, PARISC_RT_SIGFRAME_SIZE);
+       DEFINE(SIGFRAME_CONTEXT_REGS32, offsetof(struct rt_sigframe, uc.uc_mcontext) - PARISC_RT_SIGFRAME_SIZE);
+#endif
        BLANK();
        DEFINE(ICACHE_BASE, offsetof(struct pdc_cache_info, ic_base));
        DEFINE(ICACHE_STRIDE, offsetof(struct pdc_cache_info, ic_stride));
index c8a11fc..a9bc578 100644 (file)
@@ -722,7 +722,10 @@ void flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned lon
                return;
 
        if (parisc_requires_coherency()) {
-               flush_user_cache_page(vma, vmaddr);
+               if (vma->vm_flags & VM_SHARED)
+                       flush_data_cache();
+               else
+                       flush_user_cache_page(vma, vmaddr);
                return;
        }
 
index 0fe2d79..5ebb177 100644 (file)
@@ -315,7 +315,7 @@ unsigned long txn_affinity_addr(unsigned int irq, int cpu)
 {
 #ifdef CONFIG_SMP
        struct irq_data *d = irq_get_irq_data(irq);
-       cpumask_copy(irq_data_get_affinity_mask(d), cpumask_of(cpu));
+       irq_data_update_affinity(d, cpumask_of(cpu));
 #endif
 
        return per_cpu(cpu_data, cpu).txn_addr;
index d2f3cb1..e253b13 100644 (file)
@@ -42,14 +42,3 @@ void arch_jump_label_transform(struct jump_entry *entry,
 
        patch_text(addr, insn);
 }
-
-void arch_jump_label_transform_static(struct jump_entry *entry,
-                                     enum jump_label_type type)
-{
-       /*
-        * We use the architected NOP in arch_static_branch, so there's no
-        * need to patch an identical NOP over the top of it here. The core
-        * will call arch_jump_label_transform from a module notifier if the
-        * NOP needs to be replaced by a branch.
-        */
-}
index ed1e88a..bac581b 100644 (file)
@@ -146,7 +146,7 @@ static int emulate_ldw(struct pt_regs *regs, int toreg, int flop)
 "      depw    %%r0,31,2,%4\n"
 "1:    ldw     0(%%sr1,%4),%0\n"
 "2:    ldw     4(%%sr1,%4),%3\n"
-"      subi    32,%4,%2\n"
+"      subi    32,%2,%2\n"
 "      mtctl   %2,11\n"
 "      vshd    %0,%3,%0\n"
 "3:    \n"
index 494ca41..d41ddb3 100644 (file)
@@ -102,7 +102,7 @@ decode_fpu(unsigned int Fpu_register[], unsigned int trap_counts[])
      * that happen.  Want to keep this overhead low, but still provide
      * some information to the customer.  All exits from this routine
      * need to restore Fpu_register[0]
-    */
+     */
 
     bflags=(Fpu_register[0] & 0xf8000000);
     Fpu_register[0] &= 0x07ffffff;
index c2ce2e6..a4f8a52 100644 (file)
@@ -202,7 +202,7 @@ config PPC
        select HAVE_ARCH_SECCOMP_FILTER
        select HAVE_ARCH_TRACEHOOK
        select HAVE_ASM_MODVERSIONS
-       select HAVE_CONTEXT_TRACKING            if PPC64
+       select HAVE_CONTEXT_TRACKING_USER               if PPC64
        select HAVE_C_RECORDMCOUNT
        select HAVE_DEBUG_KMEMLEAK
        select HAVE_DEBUG_STACKOVERFLOW
@@ -256,6 +256,7 @@ config PPC
        select IRQ_FORCED_THREADING
        select MMU_GATHER_PAGE_SIZE
        select MMU_GATHER_RCU_TABLE_FREE
+       select MMU_GATHER_MERGE_VMAS
        select MODULES_USE_ELF_RELA
        select NEED_DMA_MAP_STATE               if PPC64 || NOT_COHERENT_CACHE
        select NEED_PER_CPU_EMBED_FIRST_CHUNK   if PPC64
@@ -281,6 +282,10 @@ config PPC
        # Please keep this list sorted alphabetically.
        #
 
+config PPC_LONG_DOUBLE_128
+       depends on PPC64
+       def_bool $(success,test "$(shell,echo __LONG_DOUBLE_128__ | $(CC) -E -P -)" = 1)
+
 config PPC_BARRIER_NOSPEC
        bool
        default y
@@ -358,6 +363,10 @@ config ARCH_SUSPEND_NONZERO_CPU
        def_bool y
        depends on PPC_POWERNV || PPC_PSERIES
 
+config ARCH_HAS_ADD_PAGES
+       def_bool y
+       depends on ARCH_ENABLE_MEMORY_HOTPLUG
+
 config PPC_DCR_NATIVE
        bool
 
@@ -1248,9 +1257,6 @@ config PHYSICAL_START
        default "0x00000000"
 endif
 
-config ARCH_RANDOM
-       def_bool n
-
 config PPC_LIB_RHEAP
        bool
 
index e8dfe9f..efab78a 100644 (file)
@@ -28,7 +28,7 @@
  * instructions per clock cycle using one 32/64 bit unit (SU1) and one 32
  * bit unit (SU2). One of these can be a memory access that is executed via
  * a single load and store unit (LSU). XTS-AES-256 takes ~780 operations per
- * 16 byte block block or 25 cycles per byte. Thus 768 bytes of input data
+ * 16 byte block or 25 cycles per byte. Thus 768 bytes of input data
  * will need an estimated maximum of 20,000 cycles. Headroom for cache misses
  * included. Even with the low end model clocked at 667 MHz this equals to a
  * critical time window of less than 30us. The value has been chosen to
index 9a53e29..0e365c5 100644 (file)
@@ -2,40 +2,19 @@
 #ifndef _ASM_POWERPC_ARCHRANDOM_H
 #define _ASM_POWERPC_ARCHRANDOM_H
 
-#ifdef CONFIG_ARCH_RANDOM
-
 #include <asm/machdep.h>
 
-static inline bool __must_check arch_get_random_long(unsigned long *v)
-{
-       return false;
-}
-
-static inline bool __must_check arch_get_random_int(unsigned int *v)
-{
-       return false;
-}
-
-static inline bool __must_check arch_get_random_seed_long(unsigned long *v)
+static inline size_t __must_check arch_get_random_longs(unsigned long *v, size_t max_longs)
 {
-       if (ppc_md.get_random_seed)
-               return ppc_md.get_random_seed(v);
-
-       return false;
+       return 0;
 }
 
-static inline bool __must_check arch_get_random_seed_int(unsigned int *v)
+static inline size_t __must_check arch_get_random_seed_longs(unsigned long *v, size_t max_longs)
 {
-       unsigned long val;
-       bool rc;
-
-       rc = arch_get_random_seed_long(&val);
-       if (rc)
-               *v = val;
-
-       return rc;
+       if (max_longs && ppc_md.get_random_seed && ppc_md.get_random_seed(v))
+               return 1;
+       return 0;
 }
-#endif /* CONFIG_ARCH_RANDOM */
 
 #ifdef CONFIG_PPC_POWERNV
 int powernv_hwrng_present(void);
diff --git a/arch/powerpc/include/asm/bpf_perf_event.h b/arch/powerpc/include/asm/bpf_perf_event.h
new file mode 100644 (file)
index 0000000..e8a7b4f
--- /dev/null
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_POWERPC_BPF_PERF_EVENT_H
+#define _ASM_POWERPC_BPF_PERF_EVENT_H
+
+#include <asm/ptrace.h>
+
+typedef struct user_pt_regs bpf_user_pt_regs_t;
+
+#endif /* _ASM_POWERPC_BPF_PERF_EVENT_H */
index f2682b2..4b63931 100644 (file)
@@ -2,7 +2,7 @@
 #ifndef _ASM_POWERPC_CONTEXT_TRACKING_H
 #define _ASM_POWERPC_CONTEXT_TRACKING_H
 
-#ifdef CONFIG_CONTEXT_TRACKING
+#ifdef CONFIG_CONTEXT_TRACKING_USER
 #define SCHEDULE_USER bl       schedule_user
 #else
 #define SCHEDULE_USER bl       schedule
index 2aefe14..d6f4edf 100644 (file)
@@ -98,6 +98,11 @@ void relocate_new_kernel(unsigned long indirection_page, unsigned long reboot_co
 
 void kexec_copy_flush(struct kimage *image);
 
+#if defined(CONFIG_CRASH_DUMP) && defined(CONFIG_PPC_RTAS)
+void crash_free_reserved_phys_range(unsigned long begin, unsigned long end);
+#define crash_free_reserved_phys_range crash_free_reserved_phys_range
+#endif
+
 #ifdef CONFIG_KEXEC_FILE
 extern const struct kexec_file_ops kexec_elf64_ops;
 
@@ -120,6 +125,15 @@ int setup_purgatory(struct kimage *image, const void *slave_code,
 #ifdef CONFIG_PPC64
 struct kexec_buf;
 
+int arch_kexec_kernel_image_probe(struct kimage *image, void *buf, unsigned long buf_len);
+#define arch_kexec_kernel_image_probe arch_kexec_kernel_image_probe
+
+int arch_kimage_file_post_load_cleanup(struct kimage *image);
+#define arch_kimage_file_post_load_cleanup arch_kimage_file_post_load_cleanup
+
+int arch_kexec_locate_mem_hole(struct kexec_buf *kbuf);
+#define arch_kexec_locate_mem_hole arch_kexec_locate_mem_hole
+
 int load_crashdump_segments_ppc64(struct kimage *image,
                                  struct kexec_buf *kbuf);
 int setup_purgatory_ppc64(struct kimage *image, const void *slave_code,
index 358d171..6c10020 100644 (file)
@@ -200,9 +200,7 @@ struct machdep_calls {
        ssize_t (*cpu_release)(const char *, size_t);
 #endif
 
-#ifdef CONFIG_ARCH_RANDOM
        int (*get_random_seed)(unsigned long *v);
-#endif
 };
 
 extern void e500_idle(void);
index 09a9ae5..b3de610 100644 (file)
@@ -19,8 +19,6 @@
 
 #include <linux/pagemap.h>
 
-#define tlb_start_vma(tlb, vma)        do { } while (0)
-#define tlb_end_vma(tlb, vma)  do { } while (0)
 #define __tlb_remove_tlb_entry __tlb_remove_tlb_entry
 
 #define tlb_flush tlb_flush
diff --git a/arch/powerpc/include/uapi/asm/bpf_perf_event.h b/arch/powerpc/include/uapi/asm/bpf_perf_event.h
deleted file mode 100644 (file)
index 5e1e648..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-#ifndef _UAPI__ASM_BPF_PERF_EVENT_H__
-#define _UAPI__ASM_BPF_PERF_EVENT_H__
-
-#include <asm/ptrace.h>
-
-typedef struct user_pt_regs bpf_user_pt_regs_t;
-
-#endif /* _UAPI__ASM_BPF_PERF_EVENT_H__ */
index f91f0f2..c8cf924 100644 (file)
@@ -20,6 +20,7 @@ CFLAGS_prom.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
 CFLAGS_prom_init.o += -fno-stack-protector
 CFLAGS_prom_init.o += -DDISABLE_BRANCH_PROFILING
 CFLAGS_prom_init.o += -ffreestanding
+CFLAGS_prom_init.o += $(call cc-option, -ftrivial-auto-var-init=uninitialized)
 
 ifdef CONFIG_FUNCTION_TRACER
 # Do not trace early boot code
index ee04338..0fbda89 100644 (file)
@@ -1855,7 +1855,7 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
                tm_reclaim_current(0);
 #endif
 
-       memset(regs->gpr, 0, sizeof(regs->gpr));
+       memset(&regs->gpr[1], 0, sizeof(regs->gpr) - sizeof(regs->gpr[0]));
        regs->ctr = 0;
        regs->link = 0;
        regs->xer = 0;
index 04694ec..13d6cb1 100644 (file)
@@ -2302,7 +2302,7 @@ static void __init prom_init_stdout(void)
 
 static int __init prom_find_machine_type(void)
 {
-       char compat[256];
+       static char compat[256] __prombss;
        int len, i = 0;
 #ifdef CONFIG_PPC64
        phandle rtas;
index b183ab9..dfa5f72 100644 (file)
@@ -13,7 +13,7 @@
 # If you really need to reference something from prom_init.o add
 # it to the list below:
 
-grep "^CONFIG_KASAN=y$" .config >/dev/null
+grep "^CONFIG_KASAN=y$" ${KCONFIG_CONFIG} >/dev/null
 if [ $? -eq 0 ]
 then
        MEM_FUNCS="__memcpy __memset"
index a6fce31..6931339 100644 (file)
@@ -1071,7 +1071,7 @@ static struct rtas_filter rtas_filters[] __ro_after_init = {
        { "get-time-of-day", -1, -1, -1, -1, -1 },
        { "ibm,get-vpd", -1, 0, -1, 1, 2 },
        { "ibm,lpar-perftools", -1, 2, 3, -1, -1 },
-       { "ibm,platform-dump", -1, 4, 5, -1, -1 },
+       { "ibm,platform-dump", -1, 4, 5, -1, -1 },              /* Special cased */
        { "ibm,read-slot-reset-state", -1, -1, -1, -1, -1 },
        { "ibm,scan-log-dump", -1, 0, 1, -1, -1 },
        { "ibm,set-dynamic-indicator", -1, 2, -1, -1, -1 },
@@ -1120,6 +1120,15 @@ static bool block_rtas_call(int token, int nargs,
                                size = 1;
 
                        end = base + size - 1;
+
+                       /*
+                        * Special case for ibm,platform-dump - NULL buffer
+                        * address is used to indicate end of dump processing
+                        */
+                       if (!strcmp(f->name, "ibm,platform-dump") &&
+                           base == 0)
+                               return false;
+
                        if (!in_rmo_buf(base, end))
                                goto err;
                }
index eb0077b..1a02629 100644 (file)
@@ -935,12 +935,6 @@ void __init setup_arch(char **cmdline_p)
        /* Print various info about the machine that has been gathered so far. */
        print_system_info();
 
-       /* Reserve large chunks of memory for use by CMA for KVM. */
-       kvm_cma_reserve();
-
-       /*  Reserve large chunks of memory for us by CMA for hugetlb */
-       gigantic_hugetlb_cma_reserve();
-
        klp_init_thread_info(&init_task);
 
        setup_initial_init_mm(_stext, _etext, _edata, _end);
@@ -955,6 +949,13 @@ void __init setup_arch(char **cmdline_p)
 
        initmem_init();
 
+       /*
+        * Reserve large chunks of memory for use by CMA for KVM and hugetlb. These must
+        * be called after initmem_init(), so that pageblock_order is initialised.
+        */
+       kvm_cma_reserve();
+       gigantic_hugetlb_cma_reserve();
+
        early_memtest(min_low_pfn << PAGE_SHIFT, max_low_pfn << PAGE_SHIFT);
 
        if (ppc_md.setup_arch)
index e08fb31..631062c 100644 (file)
@@ -1207,7 +1207,7 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
                break;
 #endif
        case H_RANDOM:
-               if (!arch_get_random_seed_long(&vcpu->arch.regs.gpr[4]))
+               if (!arch_get_random_seed_longs(&vcpu->arch.regs.gpr[4], 1))
                        ret = H_HARDWARE;
                break;
        case H_RPT_INVALIDATE:
index 52b7768..a97128a 100644 (file)
@@ -105,6 +105,37 @@ void __ref arch_remove_linear_mapping(u64 start, u64 size)
        vm_unmap_aliases();
 }
 
+/*
+ * After memory hotplug the variables max_pfn, max_low_pfn and high_memory need
+ * updating.
+ */
+static void update_end_of_memory_vars(u64 start, u64 size)
+{
+       unsigned long end_pfn = PFN_UP(start + size);
+
+       if (end_pfn > max_pfn) {
+               max_pfn = end_pfn;
+               max_low_pfn = end_pfn;
+               high_memory = (void *)__va(max_pfn * PAGE_SIZE - 1) + 1;
+       }
+}
+
+int __ref add_pages(int nid, unsigned long start_pfn, unsigned long nr_pages,
+                   struct mhp_params *params)
+{
+       int ret;
+
+       ret = __add_pages(nid, start_pfn, nr_pages, params);
+       if (ret)
+               return ret;
+
+       /* update max_pfn, max_low_pfn and high_memory */
+       update_end_of_memory_vars(start_pfn << PAGE_SHIFT,
+                                 nr_pages << PAGE_SHIFT);
+
+       return ret;
+}
+
 int __ref arch_add_memory(int nid, u64 start, u64 size,
                          struct mhp_params *params)
 {
@@ -115,7 +146,7 @@ int __ref arch_add_memory(int nid, u64 start, u64 size,
        rc = arch_create_linear_mapping(nid, start, size, params);
        if (rc)
                return rc;
-       rc = __add_pages(nid, start_pfn, nr_pages, params);
+       rc = add_pages(nid, start_pfn, nr_pages, params);
        if (rc)
                arch_remove_linear_mapping(start, size);
        return rc;
index 7d4368d..b80fc4a 100644 (file)
@@ -96,8 +96,8 @@ int __ref map_kernel_page(unsigned long ea, unsigned long pa, pgprot_t prot)
                pgdp = pgd_offset_k(ea);
                p4dp = p4d_offset(pgdp, ea);
                if (p4d_none(*p4dp)) {
-                       pmdp = early_alloc_pgtable(PMD_TABLE_SIZE);
-                       p4d_populate(&init_mm, p4dp, pmdp);
+                       pudp = early_alloc_pgtable(PUD_TABLE_SIZE);
+                       p4d_populate(&init_mm, p4dp, pudp);
                }
                pudp = pud_offset(p4dp, ea);
                if (pud_none(*pudp)) {
@@ -106,7 +106,7 @@ int __ref map_kernel_page(unsigned long ea, unsigned long pa, pgprot_t prot)
                }
                pmdp = pmd_offset(pudp, ea);
                if (!pmd_present(*pmdp)) {
-                       ptep = early_alloc_pgtable(PAGE_SIZE);
+                       ptep = early_alloc_pgtable(PTE_TABLE_SIZE);
                        pmd_populate_kernel(&init_mm, pmdp, ptep);
                }
                ptep = pte_offset_kernel(pmdp, ea);
index 5e320f4..6af443a 100644 (file)
@@ -6,7 +6,6 @@ config PPC_MICROWATT
        select PPC_ICS_NATIVE
        select PPC_ICP_NATIVE
        select PPC_UDBG_16550
-       select ARCH_RANDOM
        help
           This option enables support for FPGA-based Microwatt implementations.
 
diff --git a/arch/powerpc/platforms/microwatt/microwatt.h b/arch/powerpc/platforms/microwatt/microwatt.h
new file mode 100644 (file)
index 0000000..335417e
--- /dev/null
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _MICROWATT_H
+#define _MICROWATT_H
+
+void microwatt_rng_init(void);
+
+#endif /* _MICROWATT_H */
index 7bc4d1c..8ece87d 100644 (file)
@@ -11,6 +11,7 @@
 #include <asm/archrandom.h>
 #include <asm/cputable.h>
 #include <asm/machdep.h>
+#include "microwatt.h"
 
 #define DARN_ERR 0xFFFFFFFFFFFFFFFFul
 
@@ -29,7 +30,7 @@ static int microwatt_get_random_darn(unsigned long *v)
        return 1;
 }
 
-static __init int rng_init(void)
+void __init microwatt_rng_init(void)
 {
        unsigned long val;
        int i;
@@ -37,12 +38,7 @@ static __init int rng_init(void)
        for (i = 0; i < 10; i++) {
                if (microwatt_get_random_darn(&val)) {
                        ppc_md.get_random_seed = microwatt_get_random_darn;
-                       return 0;
+                       return;
                }
        }
-
-       pr_warn("Unable to use DARN for get_random_seed()\n");
-
-       return -EIO;
 }
-machine_subsys_initcall(, rng_init);
index 0b02603..6b32539 100644 (file)
@@ -16,6 +16,8 @@
 #include <asm/xics.h>
 #include <asm/udbg.h>
 
+#include "microwatt.h"
+
 static void __init microwatt_init_IRQ(void)
 {
        xics_init();
@@ -32,10 +34,16 @@ static int __init microwatt_populate(void)
 }
 machine_arch_initcall(microwatt, microwatt_populate);
 
+static void __init microwatt_setup_arch(void)
+{
+       microwatt_rng_init();
+}
+
 define_machine(microwatt) {
        .name                   = "microwatt",
        .probe                  = microwatt_probe,
        .init_IRQ               = microwatt_init_IRQ,
+       .setup_arch             = microwatt_setup_arch,
        .progress               = udbg_progress,
        .calibrate_decr         = generic_calibrate_decr,
 };
index 161dfe0..e1a05c5 100644 (file)
@@ -12,7 +12,6 @@ config PPC_POWERNV
        select EPAPR_BOOT
        select PPC_INDIRECT_PIO
        select PPC_UDBG_16550
-       select ARCH_RANDOM
        select CPU_FREQ
        select PPC_DOORBELL
        select MMU_NOTIFIER
index e297bf4..866efdc 100644 (file)
@@ -42,4 +42,6 @@ ssize_t memcons_copy(struct memcons *mc, char *to, loff_t pos, size_t count);
 u32 __init memcons_get_size(struct memcons *mc);
 struct memcons *__init memcons_init(struct device_node *node, const char *mc_prop_name);
 
+void pnv_rng_init(void);
+
 #endif /* _POWERNV_H */
index e3d44b3..3805ad1 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/smp.h>
+#include "powernv.h"
 
 #define DARN_ERR 0xFFFFFFFFFFFFFFFFul
 
@@ -28,7 +29,6 @@ struct powernv_rng {
 
 static DEFINE_PER_CPU(struct powernv_rng *, powernv_rng);
 
-
 int powernv_hwrng_present(void)
 {
        struct powernv_rng *rng;
@@ -98,9 +98,6 @@ static int __init initialise_darn(void)
                        return 0;
                }
        }
-
-       pr_warn("Unable to use DARN for get_random_seed()\n");
-
        return -EIO;
 }
 
@@ -163,32 +160,59 @@ static __init int rng_create(struct device_node *dn)
 
        rng_init_per_cpu(rng, dn);
 
-       pr_info_once("Registering arch random hook.\n");
-
        ppc_md.get_random_seed = powernv_get_random_long;
 
        return 0;
 }
 
-static __init int rng_init(void)
+static int __init pnv_get_random_long_early(unsigned long *v)
 {
        struct device_node *dn;
-       int rc;
-
-       for_each_compatible_node(dn, NULL, "ibm,power-rng") {
-               rc = rng_create(dn);
-               if (rc) {
-                       pr_err("Failed creating rng for %pOF (%d).\n",
-                               dn, rc);
-                       continue;
-               }
 
-               /* Create devices for hwrng driver */
-               of_platform_device_create(dn, NULL, NULL);
-       }
+       if (!slab_is_available())
+               return 0;
+
+       if (cmpxchg(&ppc_md.get_random_seed, pnv_get_random_long_early,
+                   NULL) != pnv_get_random_long_early)
+               return 0;
+
+       for_each_compatible_node(dn, NULL, "ibm,power-rng")
+               rng_create(dn);
+
+       if (!ppc_md.get_random_seed)
+               return 0;
+       return ppc_md.get_random_seed(v);
+}
 
-       initialise_darn();
+void __init pnv_rng_init(void)
+{
+       struct device_node *dn;
+
+       /* Prefer darn over the rest. */
+       if (!initialise_darn())
+               return;
+
+       dn = of_find_compatible_node(NULL, NULL, "ibm,power-rng");
+       if (dn)
+               ppc_md.get_random_seed = pnv_get_random_long_early;
+
+       of_node_put(dn);
+}
+
+static int __init pnv_rng_late_init(void)
+{
+       struct device_node *dn;
+       unsigned long v;
+
+       /* In case it wasn't called during init for some other reason. */
+       if (ppc_md.get_random_seed == pnv_get_random_long_early)
+               pnv_get_random_long_early(&v);
+
+       if (ppc_md.get_random_seed == powernv_get_random_long) {
+               for_each_compatible_node(dn, NULL, "ibm,power-rng")
+                       of_platform_device_create(dn, NULL, NULL);
+       }
 
        return 0;
 }
-machine_subsys_initcall(powernv, rng_init);
+machine_subsys_initcall(powernv, pnv_rng_late_init);
index 824c3ad..dac545a 100644 (file)
@@ -203,6 +203,8 @@ static void __init pnv_setup_arch(void)
        pnv_check_guarded_cores();
 
        /* XXX PMCS */
+
+       pnv_rng_init();
 }
 
 static void __init pnv_init(void)
index f7fd91d..f4a647c 100644 (file)
@@ -19,7 +19,6 @@ config PPC_PSERIES
        select PPC_UDBG_16550
        select PPC_DOORBELL
        select HOTPLUG_CPU
-       select ARCH_RANDOM
        select FORCE_SMP
        select SWIOTLB
        default y
index f5c916c..1d75b77 100644 (file)
@@ -122,4 +122,6 @@ void pseries_lpar_read_hblkrm_characteristics(void);
 static inline void pseries_lpar_read_hblkrm_characteristics(void) { }
 #endif
 
+void pseries_rng_init(void);
+
 #endif /* _PSERIES_PSERIES_H */
index 6268545..6ddfdea 100644 (file)
@@ -10,6 +10,7 @@
 #include <asm/archrandom.h>
 #include <asm/machdep.h>
 #include <asm/plpar_wrappers.h>
+#include "pseries.h"
 
 
 static int pseries_get_random_long(unsigned long *v)
@@ -24,19 +25,13 @@ static int pseries_get_random_long(unsigned long *v)
        return 0;
 }
 
-static __init int rng_init(void)
+void __init pseries_rng_init(void)
 {
        struct device_node *dn;
 
        dn = of_find_compatible_node(NULL, NULL, "ibm,random");
        if (!dn)
-               return -ENODEV;
-
-       pr_info("Registering arch random hook.\n");
-
+               return;
        ppc_md.get_random_seed = pseries_get_random_long;
-
        of_node_put(dn);
-       return 0;
 }
-machine_subsys_initcall(pseries, rng_init);
index afb0742..ee4f1db 100644 (file)
@@ -839,6 +839,7 @@ static void __init pSeries_setup_arch(void)
        }
 
        ppc_md.pcibios_root_bridge_prepare = pseries_root_bridge_prepare;
+       pseries_rng_init();
 }
 
 static void pseries_panic(char *str)
index 7d51286..d02911e 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/of_fdt.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/bitmap.h>
 #include <linux/cpumask.h>
 #include <linux/mm.h>
 #include <linux/delay.h>
@@ -57,7 +58,7 @@ static int __init xive_irq_bitmap_add(int base, int count)
        spin_lock_init(&xibm->lock);
        xibm->base = base;
        xibm->count = count;
-       xibm->bitmap = kzalloc(xibm->count, GFP_KERNEL);
+       xibm->bitmap = bitmap_zalloc(xibm->count, GFP_KERNEL);
        if (!xibm->bitmap) {
                kfree(xibm);
                return -ENOMEM;
@@ -75,7 +76,7 @@ static void xive_irq_bitmap_remove_all(void)
 
        list_for_each_entry_safe(xibm, tmp, &xive_irq_bitmaps, list) {
                list_del(&xibm->list);
-               kfree(xibm->bitmap);
+               bitmap_free(xibm->bitmap);
                kfree(xibm);
        }
 }
index 32ffef9..51713e0 100644 (file)
@@ -38,7 +38,7 @@ config RISCV
        select ARCH_SUPPORTS_ATOMIC_RMW
        select ARCH_SUPPORTS_DEBUG_PAGEALLOC if MMU
        select ARCH_SUPPORTS_HUGETLBFS if MMU
-       select ARCH_SUPPORTS_PAGE_TABLE_CHECK
+       select ARCH_SUPPORTS_PAGE_TABLE_CHECK if MMU
        select ARCH_USE_MEMTEST
        select ARCH_USE_QUEUED_RWLOCKS
        select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU
@@ -86,7 +86,7 @@ config RISCV
        select HAVE_ARCH_THREAD_STRUCT_WHITELIST
        select HAVE_ARCH_VMAP_STACK if MMU && 64BIT
        select HAVE_ASM_MODVERSIONS
-       select HAVE_CONTEXT_TRACKING
+       select HAVE_CONTEXT_TRACKING_USER
        select HAVE_DEBUG_KMEMLEAK
        select HAVE_DMA_CONTIGUOUS if MMU
        select HAVE_EBPF_JIT if MMU
index 34cf8a5..81029d4 100644 (file)
@@ -73,6 +73,7 @@ ifeq ($(CONFIG_PERF_EVENTS),y)
 endif
 
 KBUILD_CFLAGS_MODULE += $(call cc-option,-mno-relax)
+KBUILD_AFLAGS_MODULE += $(call as-option,-Wa$(comma)-mno-relax)
 
 # GCC versions that support the "-mstrict-align" option default to allowing
 # unaligned accesses.  While unaligned accesses are explicitly allowed in the
@@ -110,7 +111,7 @@ PHONY += vdso_install
 vdso_install:
        $(Q)$(MAKE) $(build)=arch/riscv/kernel/vdso $@
        $(if $(CONFIG_COMPAT),$(Q)$(MAKE) \
-               $(build)=arch/riscv/kernel/compat_vdso $@)
+               $(build)=arch/riscv/kernel/compat_vdso compat_$@)
 
 ifeq ($(KBUILD_EXTMOD),)
 ifeq ($(CONFIG_MMU),y)
index 039b92a..f72540b 100644 (file)
@@ -35,7 +35,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               key0 {
+               key {
                        label = "KEY0";
                        linux,code = <BTN_0>;
                        gpios = <&gpio0 10 GPIO_ACTIVE_LOW>;
index b9e30df..8abdbe2 100644 (file)
@@ -47,7 +47,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               boot {
+               key-boot {
                        label = "BOOT";
                        linux,code = <BTN_0>;
                        gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
index 8d23401..3c6df1e 100644 (file)
@@ -52,7 +52,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               boot {
+               key-boot {
                        label = "BOOT";
                        linux,code = <BTN_0>;
                        gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
index 24fd83b..03c9843 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               up {
+               key-up {
                        label = "UP";
                        linux,code = <BTN_1>;
                        gpios = <&gpio1_0 7 GPIO_ACTIVE_LOW>;
                };
 
-               press {
+               key-press {
                        label = "PRESS";
                        linux,code = <BTN_0>;
                        gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
                };
 
-               down {
+               key-down {
                        label = "DOWN";
                        linux,code = <BTN_2>;
                        gpios = <&gpio0 1 GPIO_ACTIVE_LOW>;
index 25341f3..7164ad0 100644 (file)
@@ -23,7 +23,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               boot {
+               key-boot {
                        label = "BOOT";
                        linux,code = <BTN_0>;
                        gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
index 3095d08..496d3b7 100644 (file)
@@ -50,6 +50,7 @@
                        riscv,isa = "rv64imafdc";
                        clocks = <&clkcfg CLK_CPU>;
                        tlb-split;
+                       next-level-cache = <&cctrllr>;
                        status = "okay";
 
                        cpu1_intc: interrupt-controller {
@@ -77,6 +78,7 @@
                        riscv,isa = "rv64imafdc";
                        clocks = <&clkcfg CLK_CPU>;
                        tlb-split;
+                       next-level-cache = <&cctrllr>;
                        status = "okay";
 
                        cpu2_intc: interrupt-controller {
                        riscv,isa = "rv64imafdc";
                        clocks = <&clkcfg CLK_CPU>;
                        tlb-split;
+                       next-level-cache = <&cctrllr>;
                        status = "okay";
 
                        cpu3_intc: interrupt-controller {
                        riscv,isa = "rv64imafdc";
                        clocks = <&clkcfg CLK_CPU>;
                        tlb-split;
+                       next-level-cache = <&cctrllr>;
                        status = "okay";
                        cpu4_intc: interrupt-controller {
                                #interrupt-cells = <1>;
index 672f02b..1031038 100644 (file)
@@ -111,6 +111,7 @@ void __init_or_module sifive_errata_patch_func(struct alt_entry *begin,
                        cpu_apply_errata |= tmp;
                }
        }
-       if (cpu_apply_errata != cpu_req_errata)
+       if (stage != RISCV_ALTERNATIVES_MODULE &&
+           cpu_apply_errata != cpu_req_errata)
                warn_miss_errata(cpu_req_errata - cpu_apply_errata);
 }
index 5c2aba5..dc42375 100644 (file)
@@ -175,7 +175,7 @@ static inline pud_t pfn_pud(unsigned long pfn, pgprot_t prot)
 
 static inline unsigned long _pud_pfn(pud_t pud)
 {
-       return pud_val(pud) >> _PAGE_PFN_SHIFT;
+       return __page_val_to_pfn(pud_val(pud));
 }
 
 static inline pmd_t *pud_pgtable(pud_t pud)
@@ -278,13 +278,13 @@ static inline p4d_t pfn_p4d(unsigned long pfn, pgprot_t prot)
 
 static inline unsigned long _p4d_pfn(p4d_t p4d)
 {
-       return p4d_val(p4d) >> _PAGE_PFN_SHIFT;
+       return __page_val_to_pfn(p4d_val(p4d));
 }
 
 static inline pud_t *p4d_pgtable(p4d_t p4d)
 {
        if (pgtable_l4_enabled)
-               return (pud_t *)pfn_to_virt(p4d_val(p4d) >> _PAGE_PFN_SHIFT);
+               return (pud_t *)pfn_to_virt(__page_val_to_pfn(p4d_val(p4d)));
 
        return (pud_t *)pud_pgtable((pud_t) { p4d_val(p4d) });
 }
@@ -292,7 +292,7 @@ static inline pud_t *p4d_pgtable(p4d_t p4d)
 
 static inline struct page *p4d_page(p4d_t p4d)
 {
-       return pfn_to_page(p4d_val(p4d) >> _PAGE_PFN_SHIFT);
+       return pfn_to_page(__page_val_to_pfn(p4d_val(p4d)));
 }
 
 #define pud_index(addr) (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1))
@@ -347,7 +347,7 @@ static inline void pgd_clear(pgd_t *pgd)
 static inline p4d_t *pgd_pgtable(pgd_t pgd)
 {
        if (pgtable_l5_enabled)
-               return (p4d_t *)pfn_to_virt(pgd_val(pgd) >> _PAGE_PFN_SHIFT);
+               return (p4d_t *)pfn_to_virt(__page_val_to_pfn(pgd_val(pgd)));
 
        return (p4d_t *)p4d_pgtable((p4d_t) { pgd_val(pgd) });
 }
@@ -355,7 +355,7 @@ static inline p4d_t *pgd_pgtable(pgd_t pgd)
 
 static inline struct page *pgd_page(pgd_t pgd)
 {
-       return pfn_to_page(pgd_val(pgd) >> _PAGE_PFN_SHIFT);
+       return pfn_to_page(__page_val_to_pfn(pgd_val(pgd)));
 }
 #define pgd_page(pgd)  pgd_page(pgd)
 
index 1d1be9d..5dbd661 100644 (file)
@@ -261,7 +261,7 @@ static inline pgd_t pfn_pgd(unsigned long pfn, pgprot_t prot)
 
 static inline unsigned long _pgd_pfn(pgd_t pgd)
 {
-       return pgd_val(pgd) >> _PAGE_PFN_SHIFT;
+       return __page_val_to_pfn(pgd_val(pgd));
 }
 
 static inline struct page *pmd_page(pmd_t pmd)
@@ -590,14 +590,14 @@ static inline pmd_t pmd_mkinvalid(pmd_t pmd)
        return __pmd(pmd_val(pmd) & ~(_PAGE_PRESENT|_PAGE_PROT_NONE));
 }
 
-#define __pmd_to_phys(pmd)  (pmd_val(pmd) >> _PAGE_PFN_SHIFT << PAGE_SHIFT)
+#define __pmd_to_phys(pmd)  (__page_val_to_pfn(pmd_val(pmd)) << PAGE_SHIFT)
 
 static inline unsigned long pmd_pfn(pmd_t pmd)
 {
        return ((__pmd_to_phys(pmd) & PMD_MASK) >> PAGE_SHIFT);
 }
 
-#define __pud_to_phys(pud)  (pud_val(pud) >> _PAGE_PFN_SHIFT << PAGE_SHIFT)
+#define __pud_to_phys(pud)  (__page_val_to_pfn(pud_val(pud)) << PAGE_SHIFT)
 
 static inline unsigned long pud_pfn(pud_t pud)
 {
index c71d659..33bb60a 100644 (file)
@@ -78,7 +78,7 @@ obj-$(CONFIG_SMP) += cpu_ops_sbi.o
 endif
 obj-$(CONFIG_HOTPLUG_CPU)      += cpu-hotplug.o
 obj-$(CONFIG_KGDB)             += kgdb.o
-obj-$(CONFIG_KEXEC)            += kexec_relocate.o crash_save_regs.o machine_kexec.o
+obj-$(CONFIG_KEXEC_CORE)       += kexec_relocate.o crash_save_regs.o machine_kexec.o
 obj-$(CONFIG_KEXEC_FILE)       += elf_kexec.o machine_kexec_file.o
 obj-$(CONFIG_CRASH_DUMP)       += crash_dump.o
 
index 9cb8509..0cb9499 100644 (file)
@@ -349,7 +349,7 @@ int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
 {
        const char *strtab, *name, *shstrtab;
        const Elf_Shdr *sechdrs;
-       Elf_Rela *relas;
+       Elf64_Rela *relas;
        int i, r_type;
 
        /* String & section header string table */
index 2e5b88c..b9eda3f 100644 (file)
@@ -111,12 +111,12 @@ _save_context:
        call __trace_hardirqs_off
 #endif
 
-#ifdef CONFIG_CONTEXT_TRACKING
-       /* If previous state is in user mode, call context_tracking_user_exit. */
+#ifdef CONFIG_CONTEXT_TRACKING_USER
+       /* If previous state is in user mode, call user_exit_callable(). */
        li   a0, SR_PP
        and a0, s1, a0
        bnez a0, skip_context_tracking
-       call context_tracking_user_exit
+       call user_exit_callable
 skip_context_tracking:
 #endif
 
@@ -176,7 +176,7 @@ handle_syscall:
         */
        csrs CSR_STATUS, SR_IE
 #endif
-#if defined(CONFIG_TRACE_IRQFLAGS) || defined(CONFIG_CONTEXT_TRACKING)
+#if defined(CONFIG_TRACE_IRQFLAGS) || defined(CONFIG_CONTEXT_TRACKING_USER)
        /* Recover a0 - a7 for system calls */
        REG_L a0, PT_A0(sp)
        REG_L a1, PT_A1(sp)
@@ -269,8 +269,8 @@ resume_userspace:
        andi s1, s0, _TIF_WORK_MASK
        bnez s1, work_pending
 
-#ifdef CONFIG_CONTEXT_TRACKING
-       call context_tracking_user_enter
+#ifdef CONFIG_CONTEXT_TRACKING_USER
+       call user_enter_callable
 #endif
 
        /* Save unwound kernel stack pointer in thread_info */
index 20e0905..e669475 100644 (file)
@@ -39,15 +39,3 @@ void arch_jump_label_transform(struct jump_entry *entry,
        patch_text_nosync(addr, &insn, sizeof(insn));
        mutex_unlock(&text_mutex);
 }
-
-void arch_jump_label_transform_static(struct jump_entry *entry,
-                                     enum jump_label_type type)
-{
-       /*
-        * We use the same instructions in the arch_static_branch and
-        * arch_static_branch_jump inline functions, so there's no
-        * need to patch them up here.
-        * The core will call arch_jump_label_transform  when those
-        * instructions need to be replaced.
-        */
-}
index 1c00695..9826073 100644 (file)
@@ -54,7 +54,7 @@ static inline unsigned long gstage_pte_index(gpa_t addr, u32 level)
 
 static inline unsigned long gstage_pte_page_vaddr(pte_t pte)
 {
-       return (unsigned long)pfn_to_virt(pte_val(pte) >> _PAGE_PFN_SHIFT);
+       return (unsigned long)pfn_to_virt(__page_val_to_pfn(pte_val(pte)));
 }
 
 static int gstage_page_size_to_level(unsigned long page_size, u32 *out_level)
index 7f4ad5e..f3455dc 100644 (file)
@@ -781,9 +781,11 @@ static void kvm_riscv_check_vcpu_requests(struct kvm_vcpu *vcpu)
 
        if (kvm_request_pending(vcpu)) {
                if (kvm_check_request(KVM_REQ_SLEEP, vcpu)) {
+                       kvm_vcpu_srcu_read_unlock(vcpu);
                        rcuwait_wait_event(wait,
                                (!vcpu->arch.power_off) && (!vcpu->arch.pause),
                                TASK_INTERRUPTIBLE);
+                       kvm_vcpu_srcu_read_lock(vcpu);
 
                        if (vcpu->arch.power_off || vcpu->arch.pause) {
                                /*
index 91c0b80..318fce7 100644 (file)
@@ -204,6 +204,7 @@ config S390
        select IOMMU_SUPPORT            if PCI
        select MMU_GATHER_NO_GATHER
        select MMU_GATHER_RCU_TABLE_FREE
+       select MMU_GATHER_MERGE_VMAS
        select MODULES_USE_ELF_RELA
        select NEED_DMA_MAP_STATE       if PCI
        select NEED_SG_DMA_LENGTH       if PCI
@@ -484,7 +485,6 @@ config KEXEC
 config KEXEC_FILE
        bool "kexec file based system call"
        select KEXEC_CORE
-       select BUILD_BIN2C
        depends on CRYPTO
        depends on CRYPTO_SHA256
        depends on CRYPTO_SHA256_S390
@@ -508,21 +508,6 @@ config KEXEC_SIG
          verification for the corresponding kernel image type being
          loaded in order for this to work.
 
-config ARCH_RANDOM
-       def_bool y
-       prompt "s390 architectural random number generation API"
-       help
-         Enable the s390 architectural random number generation API
-         to provide random data for all consumers within the Linux
-         kernel.
-
-         When enabled the arch_random_* functions declared in linux/random.h
-         are implemented. The implementation is based on the s390 CPACF
-         instruction subfunction TRNG which provides a real true random
-         number generator.
-
-         If unsure, say Y.
-
 config KERNEL_NOBP
        def_bool n
        prompt "Enable modified branch prediction for the kernel by default"
index 495c68a..4cb5d17 100644 (file)
@@ -82,7 +82,7 @@ endif
 
 ifdef CONFIG_EXPOLINE
   ifdef CONFIG_EXPOLINE_EXTERN
-    KBUILD_LDFLAGS_MODULE += arch/s390/lib/expoline.o
+    KBUILD_LDFLAGS_MODULE += arch/s390/lib/expoline/expoline.o
     CC_FLAGS_EXPOLINE := -mindirect-branch=thunk-extern
     CC_FLAGS_EXPOLINE += -mfunction-return=thunk-extern
   else
@@ -163,6 +163,12 @@ vdso_prepare: prepare0
        $(Q)$(MAKE) $(build)=arch/s390/kernel/vdso64 include/generated/vdso64-offsets.h
        $(if $(CONFIG_COMPAT),$(Q)$(MAKE) \
                $(build)=arch/s390/kernel/vdso32 include/generated/vdso32-offsets.h)
+
+ifdef CONFIG_EXPOLINE_EXTERN
+modules_prepare: expoline_prepare
+expoline_prepare:
+       $(Q)$(MAKE) $(build)=arch/s390/lib/expoline arch/s390/lib/expoline/expoline.o
+endif
 endif
 
 # Don't use tabs in echo arguments
index a87fcc4..f4976f6 100644 (file)
@@ -15,7 +15,6 @@ CONFIG_TUNE_ZEC12=y
 # CONFIG_COMPAT is not set
 CONFIG_NR_CPUS=2
 CONFIG_HZ_100=y
-# CONFIG_ARCH_RANDOM is not set
 # CONFIG_RELOCATABLE is not set
 # CONFIG_CHSC_SCH is not set
 # CONFIG_SCM_BUS is not set
index c63abfe..1b1cc47 100644 (file)
@@ -15,7 +15,7 @@ obj-$(CONFIG_CRYPTO_CHACHA_S390) += chacha_s390.o
 obj-$(CONFIG_S390_PRNG) += prng.o
 obj-$(CONFIG_CRYPTO_GHASH_S390) += ghash_s390.o
 obj-$(CONFIG_CRYPTO_CRC32_S390) += crc32-vx_s390.o
-obj-$(CONFIG_ARCH_RANDOM) += arch_random.o
+obj-y += arch_random.o
 
 crc32-vx_s390-y := crc32-vx.o crc32le-vx.o crc32be-vx.o
 chacha_s390-y := chacha-glue.o chacha-s390.o
index 56007c7..1f2d409 100644 (file)
  *
  * Copyright IBM Corp. 2017, 2020
  * Author(s): Harald Freudenberger
- *
- * The s390_arch_random_generate() function may be called from random.c
- * in interrupt context. So this implementation does the best to be very
- * fast. There is a buffer of random data which is asynchronously checked
- * and filled by a workqueue thread.
- * If there are enough bytes in the buffer the s390_arch_random_generate()
- * just delivers these bytes. Otherwise false is returned until the
- * worker thread refills the buffer.
- * The worker fills the rng buffer by pulling fresh entropy from the
- * high quality (but slow) true hardware random generator. This entropy
- * is then spread over the buffer with an pseudo random generator PRNG.
- * As the arch_get_random_seed_long() fetches 8 bytes and the calling
- * function add_interrupt_randomness() counts this as 1 bit entropy the
- * distribution needs to make sure there is in fact 1 bit entropy contained
- * in 8 bytes of the buffer. The current values pull 32 byte entropy
- * and scatter this into a 2048 byte buffer. So 8 byte in the buffer
- * will contain 1 bit of entropy.
- * The worker thread is rescheduled based on the charge level of the
- * buffer but at least with 500 ms delay to avoid too much CPU consumption.
- * So the max. amount of rng data delivered via arch_get_random_seed is
- * limited to 4k bytes per second.
  */
 
 #include <linux/kernel.h>
 #include <linux/atomic.h>
 #include <linux/random.h>
-#include <linux/slab.h>
 #include <linux/static_key.h>
-#include <linux/workqueue.h>
-#include <linux/moduleparam.h>
 #include <asm/cpacf.h>
 
 DEFINE_STATIC_KEY_FALSE(s390_arch_random_available);
 
 atomic64_t s390_arch_random_counter = ATOMIC64_INIT(0);
 EXPORT_SYMBOL(s390_arch_random_counter);
-
-#define ARCH_REFILL_TICKS (HZ/2)
-#define ARCH_PRNG_SEED_SIZE 32
-#define ARCH_RNG_BUF_SIZE 2048
-
-static DEFINE_SPINLOCK(arch_rng_lock);
-static u8 *arch_rng_buf;
-static unsigned int arch_rng_buf_idx;
-
-static void arch_rng_refill_buffer(struct work_struct *);
-static DECLARE_DELAYED_WORK(arch_rng_work, arch_rng_refill_buffer);
-
-bool s390_arch_random_generate(u8 *buf, unsigned int nbytes)
-{
-       /* max hunk is ARCH_RNG_BUF_SIZE */
-       if (nbytes > ARCH_RNG_BUF_SIZE)
-               return false;
-
-       /* lock rng buffer */
-       if (!spin_trylock(&arch_rng_lock))
-               return false;
-
-       /* try to resolve the requested amount of bytes from the buffer */
-       arch_rng_buf_idx -= nbytes;
-       if (arch_rng_buf_idx < ARCH_RNG_BUF_SIZE) {
-               memcpy(buf, arch_rng_buf + arch_rng_buf_idx, nbytes);
-               atomic64_add(nbytes, &s390_arch_random_counter);
-               spin_unlock(&arch_rng_lock);
-               return true;
-       }
-
-       /* not enough bytes in rng buffer, refill is done asynchronously */
-       spin_unlock(&arch_rng_lock);
-
-       return false;
-}
-EXPORT_SYMBOL(s390_arch_random_generate);
-
-static void arch_rng_refill_buffer(struct work_struct *unused)
-{
-       unsigned int delay = ARCH_REFILL_TICKS;
-
-       spin_lock(&arch_rng_lock);
-       if (arch_rng_buf_idx > ARCH_RNG_BUF_SIZE) {
-               /* buffer is exhausted and needs refill */
-               u8 seed[ARCH_PRNG_SEED_SIZE];
-               u8 prng_wa[240];
-               /* fetch ARCH_PRNG_SEED_SIZE bytes of entropy */
-               cpacf_trng(NULL, 0, seed, sizeof(seed));
-               /* blow this entropy up to ARCH_RNG_BUF_SIZE with PRNG */
-               memset(prng_wa, 0, sizeof(prng_wa));
-               cpacf_prno(CPACF_PRNO_SHA512_DRNG_SEED,
-                          &prng_wa, NULL, 0, seed, sizeof(seed));
-               cpacf_prno(CPACF_PRNO_SHA512_DRNG_GEN,
-                          &prng_wa, arch_rng_buf, ARCH_RNG_BUF_SIZE, NULL, 0);
-               arch_rng_buf_idx = ARCH_RNG_BUF_SIZE;
-       }
-       delay += (ARCH_REFILL_TICKS * arch_rng_buf_idx) / ARCH_RNG_BUF_SIZE;
-       spin_unlock(&arch_rng_lock);
-
-       /* kick next check */
-       queue_delayed_work(system_long_wq, &arch_rng_work, delay);
-}
-
-/*
- * Here follows the implementation of s390_arch_get_random_long().
- *
- * The random longs to be pulled by arch_get_random_long() are
- * prepared in an 4K buffer which is filled from the NIST 800-90
- * compliant s390 drbg. By default the random long buffer is refilled
- * 256 times before the drbg itself needs a reseed. The reseed of the
- * drbg is done with 32 bytes fetched from the high quality (but slow)
- * trng which is assumed to deliver 100% entropy. So the 32 * 8 = 256
- * bits of entropy are spread over 256 * 4KB = 1MB serving 131072
- * arch_get_random_long() invocations before reseeded.
- *
- * How often the 4K random long buffer is refilled with the drbg
- * before the drbg is reseeded can be adjusted. There is a module
- * parameter 's390_arch_rnd_long_drbg_reseed' accessible via
- *   /sys/module/arch_random/parameters/rndlong_drbg_reseed
- * or as kernel command line parameter
- *   arch_random.rndlong_drbg_reseed=<value>
- * This parameter tells how often the drbg fills the 4K buffer before
- * it is re-seeded by fresh entropy from the trng.
- * A value of 16 results in reseeding the drbg at every 16 * 4 KB = 64
- * KB with 32 bytes of fresh entropy pulled from the trng. So a value
- * of 16 would result in 256 bits entropy per 64 KB.
- * A value of 256 results in 1MB of drbg output before a reseed of the
- * drbg is done. So this would spread the 256 bits of entropy among 1MB.
- * Setting this parameter to 0 forces the reseed to take place every
- * time the 4K buffer is depleted, so the entropy rises to 256 bits
- * entropy per 4K or 0.5 bit entropy per arch_get_random_long().  With
- * setting this parameter to negative values all this effort is
- * disabled, arch_get_random long() returns false and thus indicating
- * that the arch_get_random_long() feature is disabled at all.
- */
-
-static unsigned long rndlong_buf[512];
-static DEFINE_SPINLOCK(rndlong_lock);
-static int rndlong_buf_index;
-
-static int rndlong_drbg_reseed = 256;
-module_param_named(rndlong_drbg_reseed, rndlong_drbg_reseed, int, 0600);
-MODULE_PARM_DESC(rndlong_drbg_reseed, "s390 arch_get_random_long() drbg reseed");
-
-static inline void refill_rndlong_buf(void)
-{
-       static u8 prng_ws[240];
-       static int drbg_counter;
-
-       if (--drbg_counter < 0) {
-               /* need to re-seed the drbg */
-               u8 seed[32];
-
-               /* fetch seed from trng */
-               cpacf_trng(NULL, 0, seed, sizeof(seed));
-               /* seed drbg */
-               memset(prng_ws, 0, sizeof(prng_ws));
-               cpacf_prno(CPACF_PRNO_SHA512_DRNG_SEED,
-                          &prng_ws, NULL, 0, seed, sizeof(seed));
-               /* re-init counter for drbg */
-               drbg_counter = rndlong_drbg_reseed;
-       }
-
-       /* fill the arch_get_random_long buffer from drbg */
-       cpacf_prno(CPACF_PRNO_SHA512_DRNG_GEN, &prng_ws,
-                  (u8 *) rndlong_buf, sizeof(rndlong_buf),
-                  NULL, 0);
-}
-
-bool s390_arch_get_random_long(unsigned long *v)
-{
-       bool rc = false;
-       unsigned long flags;
-
-       /* arch_get_random_long() disabled ? */
-       if (rndlong_drbg_reseed < 0)
-               return false;
-
-       /* try to lock the random long lock */
-       if (!spin_trylock_irqsave(&rndlong_lock, flags))
-               return false;
-
-       if (--rndlong_buf_index >= 0) {
-               /* deliver next long value from the buffer */
-               *v = rndlong_buf[rndlong_buf_index];
-               rc = true;
-               goto out;
-       }
-
-       /* buffer is depleted and needs refill */
-       if (in_interrupt()) {
-               /* delay refill in interrupt context to next caller */
-               rndlong_buf_index = 0;
-               goto out;
-       }
-
-       /* refill random long buffer */
-       refill_rndlong_buf();
-       rndlong_buf_index = ARRAY_SIZE(rndlong_buf);
-
-       /* and provide one random long */
-       *v = rndlong_buf[--rndlong_buf_index];
-       rc = true;
-
-out:
-       spin_unlock_irqrestore(&rndlong_lock, flags);
-       return rc;
-}
-EXPORT_SYMBOL(s390_arch_get_random_long);
-
-static int __init s390_arch_random_init(void)
-{
-       /* all the needed PRNO subfunctions available ? */
-       if (cpacf_query_func(CPACF_PRNO, CPACF_PRNO_TRNG) &&
-           cpacf_query_func(CPACF_PRNO, CPACF_PRNO_SHA512_DRNG_GEN)) {
-
-               /* alloc arch random working buffer */
-               arch_rng_buf = kmalloc(ARCH_RNG_BUF_SIZE, GFP_KERNEL);
-               if (!arch_rng_buf)
-                       return -ENOMEM;
-
-               /* kick worker queue job to fill the random buffer */
-               queue_delayed_work(system_long_wq,
-                                  &arch_rng_work, ARCH_REFILL_TICKS);
-
-               /* enable arch random to the outside world */
-               static_branch_enable(&s390_arch_random_available);
-       }
-
-       return 0;
-}
-arch_initcall(s390_arch_random_init);
index 5dc712f..1594049 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Kernel interface for the s390 arch_random_* functions
  *
- * Copyright IBM Corp. 2017, 2020
+ * Copyright IBM Corp. 2017, 2022
  *
  * Author: Harald Freudenberger <freude@de.ibm.com>
  *
 #ifndef _ASM_S390_ARCHRANDOM_H
 #define _ASM_S390_ARCHRANDOM_H
 
-#ifdef CONFIG_ARCH_RANDOM
-
 #include <linux/static_key.h>
+#include <linux/preempt.h>
 #include <linux/atomic.h>
+#include <asm/cpacf.h>
 
 DECLARE_STATIC_KEY_FALSE(s390_arch_random_available);
 extern atomic64_t s390_arch_random_counter;
 
-bool s390_arch_get_random_long(unsigned long *v);
-bool s390_arch_random_generate(u8 *buf, unsigned int nbytes);
-
-static inline bool __must_check arch_get_random_long(unsigned long *v)
-{
-       if (static_branch_likely(&s390_arch_random_available))
-               return s390_arch_get_random_long(v);
-       return false;
-}
-
-static inline bool __must_check arch_get_random_int(unsigned int *v)
+static inline size_t __must_check arch_get_random_longs(unsigned long *v, size_t max_longs)
 {
-       return false;
-}
-
-static inline bool __must_check arch_get_random_seed_long(unsigned long *v)
-{
-       if (static_branch_likely(&s390_arch_random_available)) {
-               return s390_arch_random_generate((u8 *)v, sizeof(*v));
-       }
-       return false;
+       return 0;
 }
 
-static inline bool __must_check arch_get_random_seed_int(unsigned int *v)
+static inline size_t __must_check arch_get_random_seed_longs(unsigned long *v, size_t max_longs)
 {
-       if (static_branch_likely(&s390_arch_random_available)) {
-               return s390_arch_random_generate((u8 *)v, sizeof(*v));
+       if (static_branch_likely(&s390_arch_random_available) &&
+           in_task()) {
+               cpacf_trng(NULL, 0, (u8 *)v, max_longs * sizeof(*v));
+               atomic64_add(max_longs * sizeof(*v), &s390_arch_random_counter);
+               return max_longs;
        }
-       return false;
+       return 0;
 }
 
-#endif /* CONFIG_ARCH_RANDOM */
 #endif /* _ASM_S390_ARCHRANDOM_H */
index 916cfcb..895f774 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/stringify.h>
 
 #define JUMP_LABEL_NOP_SIZE 6
-#define JUMP_LABEL_NOP_OFFSET 2
 
 #ifdef CONFIG_CC_IS_CLANG
 #define JUMP_LABEL_STATIC_KEY_CONSTRAINT "i"
 #endif
 
 /*
- * We use a brcl 0,2 instruction for jump labels at compile time so it
+ * We use a brcl 0,<offset> instruction for jump labels so it
  * can be easily distinguished from a hotpatch generated instruction.
  */
 static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
 {
-       asm_volatile_goto("0:   brcl    0,"__stringify(JUMP_LABEL_NOP_OFFSET)"\n"
+       asm_volatile_goto("0:   brcl 0,%l[label]\n"
                          ".pushsection __jump_table,\"aw\"\n"
                          ".balign      8\n"
                          ".long        0b-.,%l[label]-.\n"
index 649ecdc..1bd08eb 100644 (file)
@@ -85,6 +85,17 @@ struct kimage_arch {
 extern const struct kexec_file_ops s390_kexec_image_ops;
 extern const struct kexec_file_ops s390_kexec_elf_ops;
 
+#ifdef CONFIG_CRASH_DUMP
+void crash_free_reserved_phys_range(unsigned long begin, unsigned long end);
+#define crash_free_reserved_phys_range crash_free_reserved_phys_range
+
+void arch_kexec_protect_crashkres(void);
+#define arch_kexec_protect_crashkres arch_kexec_protect_crashkres
+
+void arch_kexec_unprotect_crashkres(void);
+#define arch_kexec_unprotect_crashkres arch_kexec_unprotect_crashkres
+#endif
+
 #ifdef CONFIG_KEXEC_FILE
 struct purgatory_info;
 int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
@@ -92,5 +103,8 @@ int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
                                     const Elf_Shdr *relsec,
                                     const Elf_Shdr *symtab);
 #define arch_kexec_apply_relocations_add arch_kexec_apply_relocations_add
+
+int arch_kimage_file_post_load_cleanup(struct kimage *image);
+#define arch_kimage_file_post_load_cleanup arch_kimage_file_post_load_cleanup
 #endif
 #endif /*_S390_KEXEC_H */
index d910d71..7e9e995 100644 (file)
@@ -2,8 +2,6 @@
 #ifndef _ASM_S390_NOSPEC_ASM_H
 #define _ASM_S390_NOSPEC_ASM_H
 
-#include <asm/alternative-asm.h>
-#include <asm/asm-offsets.h>
 #include <asm/dwarf.h>
 
 #ifdef __ASSEMBLY__
index 54ae2dc..2f983e0 100644 (file)
@@ -133,9 +133,9 @@ struct slibe {
  * @sb_count: number of storage blocks
  * @sba: storage block element addresses
  * @dcount: size of storage block elements
- * @user0: user defineable value
- * @res4: reserved paramater
- * @user1: user defineable value
+ * @user0: user definable value
+ * @res4: reserved parameter
+ * @user1: user definable value
  */
 struct qaob {
        u64 res0[6];
index fe6407f..3a5c8fb 100644 (file)
@@ -27,9 +27,6 @@ static inline void tlb_flush(struct mmu_gather *tlb);
 static inline bool __tlb_remove_page_size(struct mmu_gather *tlb,
                                          struct page *page, int page_size);
 
-#define tlb_start_vma(tlb, vma)                        do { } while (0)
-#define tlb_end_vma(tlb, vma)                  do { } while (0)
-
 #define tlb_flush tlb_flush
 #define pte_free_tlb pte_free_tlb
 #define pmd_free_tlb pmd_free_tlb
index 3d8284b..e56b9dd 100644 (file)
@@ -30,18 +30,18 @@ struct s390_ctrset_start {          /* Set CPUs to operate on */
 struct s390_ctrset_setdata {           /* Counter set data */
        __u32 set;                      /* Counter set number */
        __u32 no_cnts;                  /* # of counters stored in cv[] */
-       __u64 cv[0];                    /* Counter values (variable length) */
+       __u64 cv[];                     /* Counter values (variable length) */
 };
 
 struct s390_ctrset_cpudata {           /* Counter set data per CPU */
        __u32 cpu_nr;                   /* CPU number */
        __u32 no_sets;                  /* # of counters sets in data[] */
-       struct s390_ctrset_setdata data[0];
+       struct s390_ctrset_setdata data[];
 };
 
 struct s390_ctrset_read {              /* Structure to get all ctr sets */
        __u64 no_cpus;                  /* Total # of CPUs data taken from */
-       struct s390_ctrset_cpudata data[0];
+       struct s390_ctrset_cpudata data[];
 };
 
 #define S390_HWCTR_MAGIC       'C'     /* Random magic # for ioctls */
index 6bec000..e808bb8 100644 (file)
@@ -44,14 +44,8 @@ static void jump_label_bug(struct jump_entry *entry, struct insn *expected,
        panic("Corrupted kernel text");
 }
 
-static struct insn orignop = {
-       .opcode = 0xc004,
-       .offset = JUMP_LABEL_NOP_OFFSET >> 1,
-};
-
 static void jump_label_transform(struct jump_entry *entry,
-                                enum jump_label_type type,
-                                int init)
+                                enum jump_label_type type)
 {
        void *code = (void *)jump_entry_code(entry);
        struct insn old, new;
@@ -63,27 +57,22 @@ static void jump_label_transform(struct jump_entry *entry,
                jump_label_make_branch(entry, &old);
                jump_label_make_nop(entry, &new);
        }
-       if (init) {
-               if (memcmp(code, &orignop, sizeof(orignop)))
-                       jump_label_bug(entry, &orignop, &new);
-       } else {
-               if (memcmp(code, &old, sizeof(old)))
-                       jump_label_bug(entry, &old, &new);
-       }
+       if (memcmp(code, &old, sizeof(old)))
+               jump_label_bug(entry, &old, &new);
        s390_kernel_write(code, &new, sizeof(new));
 }
 
 void arch_jump_label_transform(struct jump_entry *entry,
                               enum jump_label_type type)
 {
-       jump_label_transform(entry, type, 0);
+       jump_label_transform(entry, type);
        text_poke_sync();
 }
 
 bool arch_jump_label_transform_queue(struct jump_entry *entry,
                                     enum jump_label_type type)
 {
-       jump_label_transform(entry, type, 0);
+       jump_label_transform(entry, type);
        return true;
 }
 
@@ -91,10 +80,3 @@ void arch_jump_label_transform_apply(void)
 {
        text_poke_sync();
 }
-
-void __init_or_module arch_jump_label_transform_static(struct jump_entry *entry,
-                                                      enum jump_label_type type)
-{
-       jump_label_transform(entry, type, 1);
-       text_poke_sync();
-}
index 8f43575..fc6d5f5 100644 (file)
@@ -31,6 +31,7 @@ int s390_verify_sig(const char *kernel, unsigned long kernel_len)
        const unsigned long marker_len = sizeof(MODULE_SIG_STRING) - 1;
        struct module_signature *ms;
        unsigned long sig_len;
+       int ret;
 
        /* Skip signature verification when not secure IPLed. */
        if (!ipl_secure_flag)
@@ -65,11 +66,18 @@ int s390_verify_sig(const char *kernel, unsigned long kernel_len)
                return -EBADMSG;
        }
 
-       return verify_pkcs7_signature(kernel, kernel_len,
-                                     kernel + kernel_len, sig_len,
-                                     VERIFY_USE_PLATFORM_KEYRING,
-                                     VERIFYING_MODULE_SIGNATURE,
-                                     NULL, NULL);
+       ret = verify_pkcs7_signature(kernel, kernel_len,
+                                    kernel + kernel_len, sig_len,
+                                    VERIFY_USE_SECONDARY_KEYRING,
+                                    VERIFYING_MODULE_SIGNATURE,
+                                    NULL, NULL);
+       if (ret == -ENOKEY && IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING))
+               ret = verify_pkcs7_signature(kernel, kernel_len,
+                                            kernel + kernel_len, sig_len,
+                                            VERIFY_USE_PLATFORM_KEYRING,
+                                            VERIFYING_MODULE_SIGNATURE,
+                                            NULL, NULL);
+       return ret;
 }
 #endif /* CONFIG_KEXEC_SIG */
 
index 26125a9..2d159b3 100644 (file)
@@ -548,6 +548,5 @@ int module_finalize(const Elf_Ehdr *hdr,
 #endif /* CONFIG_FUNCTION_TRACER */
        }
 
-       jump_label_apply_nops(me);
        return 0;
 }
index 8d91ecc..ebad41a 100644 (file)
@@ -875,6 +875,9 @@ static void __init setup_randomness(void)
        if (stsi(vmms, 3, 2, 2) == 0 && vmms->count)
                add_device_randomness(&vmms->vm, sizeof(vmms->vm[0]) * vmms->count);
        memblock_free(vmms, PAGE_SIZE);
+
+       if (cpacf_query_func(CPACF_PRNO, CPACF_PRNO_TRNG))
+               static_branch_enable(&s390_arch_random_available);
 }
 
 /*
index 5d415b3..580d2e3 100644 (file)
@@ -7,7 +7,6 @@ lib-y += delay.o string.o uaccess.o find.o spinlock.o
 obj-y += mem.o xor.o
 lib-$(CONFIG_KPROBES) += probes.o
 lib-$(CONFIG_UPROBES) += probes.o
-obj-$(CONFIG_EXPOLINE_EXTERN) += expoline.o
 obj-$(CONFIG_S390_KPROBES_SANITY_TEST) += test_kprobes_s390.o
 test_kprobes_s390-objs += test_kprobes_asm.o test_kprobes.o
 
@@ -22,3 +21,5 @@ obj-$(CONFIG_S390_MODULES_SANITY_TEST) += test_modules.o
 obj-$(CONFIG_S390_MODULES_SANITY_TEST_HELPERS) += test_modules_helpers.o
 
 lib-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
+
+obj-$(CONFIG_EXPOLINE_EXTERN) += expoline/
diff --git a/arch/s390/lib/expoline/Makefile b/arch/s390/lib/expoline/Makefile
new file mode 100644 (file)
index 0000000..854631d
--- /dev/null
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-y += expoline.o
index 360ada8..d237bc6 100644 (file)
@@ -48,7 +48,6 @@ OBJCOPYFLAGS_purgatory.ro += --remove-section='.note.*'
 $(obj)/purgatory.ro: $(obj)/purgatory $(obj)/purgatory.chk FORCE
                $(call if_changed,objcopy)
 
-$(obj)/kexec-purgatory.o: $(obj)/kexec-purgatory.S $(obj)/purgatory.ro FORCE
-       $(call if_changed_rule,as_o_S)
+$(obj)/kexec-purgatory.o: $(obj)/purgatory.ro
 
-obj-$(CONFIG_ARCH_HAS_KEXEC_PURGATORY) += kexec-purgatory.o
+obj-y += kexec-purgatory.o
index d90d29d..e699e2e 100644 (file)
@@ -29,8 +29,6 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_IPV6 is not set
-CONFIG_IRDA=y
-CONFIG_SH_SIR=y
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
index cf9a3ec..fba90e6 100644 (file)
@@ -271,8 +271,12 @@ static inline void __iomem *ioremap_prot(phys_addr_t offset, unsigned long size,
 #endif /* CONFIG_HAVE_IOREMAP_PROT */
 
 #else /* CONFIG_MMU */
-#define iounmap(addr)          do { } while (0)
-#define ioremap(offset, size)  ((void __iomem *)(unsigned long)(offset))
+static inline void __iomem *ioremap(phys_addr_t offset, size_t size)
+{
+       return (void __iomem *)(unsigned long)offset;
+}
+
+static inline void iounmap(volatile void __iomem *addr) { }
 #endif /* CONFIG_MMU */
 
 #define ioremap_uc     ioremap
index ef0f082..56269c2 100644 (file)
@@ -230,16 +230,17 @@ void migrate_irqs(void)
                struct irq_data *data = irq_get_irq_data(irq);
 
                if (irq_data_get_node(data) == cpu) {
-                       struct cpumask *mask = irq_data_get_affinity_mask(data);
+                       const struct cpumask *mask = irq_data_get_affinity_mask(data);
                        unsigned int newcpu = cpumask_any_and(mask,
                                                              cpu_online_mask);
                        if (newcpu >= nr_cpu_ids) {
                                pr_info_ratelimited("IRQ%u no longer affine to CPU%u\n",
                                                    irq, cpu);
 
-                               cpumask_setall(mask);
+                               irq_set_affinity(irq, cpu_all_mask);
+                       } else {
+                               irq_set_affinity(irq, mask);
                        }
-                       irq_set_affinity(irq, mask);
                }
        }
 }
index ba449c4..02f0a60 100644 (file)
@@ -67,11 +67,13 @@ config SPARC64
        select HAVE_KRETPROBES
        select HAVE_KPROBES
        select MMU_GATHER_RCU_TABLE_FREE if SMP
+       select MMU_GATHER_MERGE_VMAS
+       select MMU_GATHER_NO_FLUSH_CACHE
        select HAVE_ARCH_TRANSPARENT_HUGEPAGE
        select HAVE_DYNAMIC_FTRACE
        select HAVE_FTRACE_MCOUNT_RECORD
        select HAVE_SYSCALL_TRACEPOINTS
-       select HAVE_CONTEXT_TRACKING
+       select HAVE_CONTEXT_TRACKING_USER
        select HAVE_TIF_NOHZ
        select HAVE_DEBUG_KMEMLEAK
        select IOMMU_HELPER
index 779a5a0..3037187 100644 (file)
@@ -22,8 +22,6 @@ void smp_flush_tlb_mm(struct mm_struct *mm);
 void __flush_tlb_pending(unsigned long, unsigned long, unsigned long *);
 void flush_tlb_pending(void);
 
-#define tlb_start_vma(tlb, vma) do { } while (0)
-#define tlb_end_vma(tlb, vma)  do { } while (0)
 #define tlb_flush(tlb) flush_tlb_pending()
 
 /*
index df39580..66c45a2 100644 (file)
@@ -208,9 +208,6 @@ int module_finalize(const Elf_Ehdr *hdr,
                    const Elf_Shdr *sechdrs,
                    struct module *me)
 {
-       /* make jump label nops */
-       jump_label_apply_nops(me);
-
        do_patch_sections(hdr, sechdrs);
 
        /* Cheetah's I-cache is fully coherent.  */
index c5fd4b4..eef1027 100644 (file)
@@ -15,7 +15,7 @@
 #include <asm/visasm.h>
 #include <asm/processor.h>
 
-#ifdef CONFIG_CONTEXT_TRACKING
+#ifdef CONFIG_CONTEXT_TRACKING_USER
 # define SCHEDULE_USER schedule_user
 #else
 # define SCHEDULE_USER schedule
index c4344b6..eb2d2f0 100644 (file)
@@ -925,7 +925,7 @@ static int ubd_add(int n, char **error_out)
        return 0;
 
 out_cleanup_disk:
-       blk_cleanup_disk(disk);
+       put_disk(disk);
 out_cleanup_tags:
        blk_mq_free_tag_set(&ubd_dev->tag_set);
 out:
@@ -1032,7 +1032,7 @@ static int ubd_remove(int n, char **error_out)
        ubd_gendisk[n] = NULL;
        if(disk != NULL){
                del_gendisk(disk);
-               blk_cleanup_disk(disk);
+               put_disk(disk);
        }
 
        err = 0;
@@ -1262,7 +1262,7 @@ static void ubd_map_req(struct ubd *dev, struct io_thread_req *io_req,
        struct req_iterator iter;
        int i = 0;
        unsigned long byte_offset = io_req->offset;
-       int op = req_op(req);
+       enum req_op op = req_op(req);
 
        if (op == REQ_OP_WRITE_ZEROES || op == REQ_OP_DISCARD) {
                io_req->io_desc[0].buffer = NULL;
@@ -1325,7 +1325,7 @@ static int ubd_submit_request(struct ubd *dev, struct request *req)
        int segs = 0;
        struct io_thread_req *io_req;
        int ret;
-       int op = req_op(req);
+       enum req_op op = req_op(req);
 
        if (op == REQ_OP_FLUSH)
                segs = 0;
diff --git a/arch/um/include/asm/archrandom.h b/arch/um/include/asm/archrandom.h
new file mode 100644 (file)
index 0000000..24e16c9
--- /dev/null
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_UM_ARCHRANDOM_H__
+#define __ASM_UM_ARCHRANDOM_H__
+
+#include <linux/types.h>
+
+/* This is from <os.h>, but better not to #include that in a global header here. */
+ssize_t os_getrandom(void *buf, size_t len, unsigned int flags);
+
+static inline size_t __must_check arch_get_random_longs(unsigned long *v, size_t max_longs)
+{
+       ssize_t ret;
+
+       ret = os_getrandom(v, max_longs * sizeof(*v), 0);
+       if (ret < 0)
+               return 0;
+       return ret / sizeof(*v);
+}
+
+static inline size_t __must_check arch_get_random_seed_longs(unsigned long *v, size_t max_longs)
+{
+       return 0;
+}
+
+#endif
index 95af12e..cdbd965 100644 (file)
@@ -102,8 +102,8 @@ extern unsigned long uml_physmem;
  * casting is the right thing, but 32-bit UML can't have 64-bit virtual
  * addresses
  */
-#define __pa(virt) to_phys((void *) (unsigned long) (virt))
-#define __va(phys) to_virt((unsigned long) (phys))
+#define __pa(virt) uml_to_phys((void *) (unsigned long) (virt))
+#define __va(phys) uml_to_virt((unsigned long) (phys))
 
 #define phys_to_pfn(p) ((p) >> PAGE_SHIFT)
 #define pfn_to_phys(pfn) PFN_PHYS(pfn)
index 4862c91..98aacd5 100644 (file)
@@ -9,12 +9,12 @@
 extern int phys_mapping(unsigned long phys, unsigned long long *offset_out);
 
 extern unsigned long uml_physmem;
-static inline unsigned long to_phys(void *virt)
+static inline unsigned long uml_to_phys(void *virt)
 {
        return(((unsigned long) virt) - uml_physmem);
 }
 
-static inline void *to_virt(unsigned long phys)
+static inline void *uml_to_virt(unsigned long phys)
 {
        return((void *) uml_physmem + phys);
 }
index fafde1d..0df646c 100644 (file)
 #include <irq_user.h>
 #include <longjmp.h>
 #include <mm_id.h>
+/* This is to get size_t */
+#ifndef __UM_HOST__
+#include <linux/types.h>
+#else
+#include <sys/types.h>
+#endif
 
 #define CATCH_EINTR(expr) while ((errno = 0, ((expr) < 0)) && (errno == EINTR))
 
@@ -243,6 +249,7 @@ extern void stack_protections(unsigned long address);
 extern int raw(int fd);
 extern void setup_machinename(char *machine_out);
 extern void setup_hostinfo(char *buf, int len);
+extern ssize_t os_getrandom(void *buf, size_t len, unsigned int flags);
 extern void os_dump_core(void) __attribute__ ((noreturn));
 extern void um_early_printk(const char *s, unsigned int n);
 extern void os_fix_helper_signals(void);
index 0760e24..e0de60e 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/sched/task.h>
 #include <linux/kmsg_dump.h>
 #include <linux/suspend.h>
+#include <linux/random.h>
 
 #include <asm/processor.h>
 #include <asm/cpufeature.h>
@@ -406,6 +407,8 @@ int __init __weak read_initrd(void)
 
 void __init setup_arch(char **cmdline_p)
 {
+       u8 rng_seed[32];
+
        stack_protections((unsigned long) &init_thread_info);
        setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
        mem_total_pages(physmem_size, iomem_size, highmem);
@@ -416,6 +419,11 @@ void __init setup_arch(char **cmdline_p)
        strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
        *cmdline_p = command_line;
        setup_hostinfo(host_info, sizeof host_info);
+
+       if (os_getrandom(rng_seed, sizeof(rng_seed), 0) == sizeof(rng_seed)) {
+               add_bootloader_randomness(rng_seed, sizeof(rng_seed));
+               memzero_explicit(rng_seed, sizeof(rng_seed));
+       }
 }
 
 void __init check_bugs(void)
@@ -432,6 +440,10 @@ void apply_retpolines(s32 *start, s32 *end)
 {
 }
 
+void apply_returns(s32 *start, s32 *end)
+{
+}
+
 void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
 {
 }
index 87d3129..c316c99 100644 (file)
@@ -251,7 +251,7 @@ static int userspace_tramp(void *stack)
        signal(SIGTERM, SIG_DFL);
        signal(SIGWINCH, SIG_IGN);
 
-       fd = phys_mapping(to_phys(__syscall_stub_start), &offset);
+       fd = phys_mapping(uml_to_phys(__syscall_stub_start), &offset);
        addr = mmap64((void *) STUB_CODE, UM_KERN_PAGE_SIZE,
                      PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset);
        if (addr == MAP_FAILED) {
@@ -261,7 +261,7 @@ static int userspace_tramp(void *stack)
        }
 
        if (stack != NULL) {
-               fd = phys_mapping(to_phys(stack), &offset);
+               fd = phys_mapping(uml_to_phys(stack), &offset);
                addr = mmap((void *) STUB_DATA,
                            UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE,
                            MAP_FIXED | MAP_SHARED, fd, offset);
@@ -534,7 +534,7 @@ int copy_context_skas0(unsigned long new_stack, int pid)
        struct stub_data *data = (struct stub_data *) current_stack;
        struct stub_data *child_data = (struct stub_data *) new_stack;
        unsigned long long new_offset;
-       int new_fd = phys_mapping(to_phys((void *)new_stack), &new_offset);
+       int new_fd = phys_mapping(uml_to_phys((void *)new_stack), &new_offset);
 
        /*
         * prepare offset and fd of child's stack as argument for parent's
index 41297ec..fc0f2a9 100644 (file)
@@ -14,6 +14,7 @@
 #include <sys/wait.h>
 #include <sys/mman.h>
 #include <sys/utsname.h>
+#include <sys/random.h>
 #include <init.h>
 #include <os.h>
 
@@ -96,6 +97,11 @@ static inline void __attribute__ ((noreturn)) uml_abort(void)
                        exit(127);
 }
 
+ssize_t os_getrandom(void *buf, size_t len, unsigned int flags)
+{
+       return getrandom(buf, len, flags);
+}
+
 /*
  * UML helper threads must not handle SIGWINCH/INT/TERM
  */
index 677111a..f2e1d6c 100644 (file)
@@ -3,6 +3,4 @@ boot/compressed/vmlinux
 tools/test_get_len
 tools/insn_sanity
 tools/insn_decoder_test
-purgatory/kexec-purgatory.c
 purgatory/purgatory.ro
-
index be0b95e..fb5900e 100644 (file)
@@ -186,8 +186,8 @@ config X86
        select HAVE_ASM_MODVERSIONS
        select HAVE_CMPXCHG_DOUBLE
        select HAVE_CMPXCHG_LOCAL
-       select HAVE_CONTEXT_TRACKING            if X86_64
-       select HAVE_CONTEXT_TRACKING_OFFSTACK   if HAVE_CONTEXT_TRACKING
+       select HAVE_CONTEXT_TRACKING_USER               if X86_64
+       select HAVE_CONTEXT_TRACKING_USER_OFFSTACK      if HAVE_CONTEXT_TRACKING_USER
        select HAVE_C_RECORDMCOUNT
        select HAVE_OBJTOOL_MCOUNT              if HAVE_OBJTOOL
        select HAVE_BUILDTIME_MCOUNT_SORT
@@ -245,6 +245,7 @@ config X86
        select HAVE_PERF_REGS
        select HAVE_PERF_USER_STACK_DUMP
        select MMU_GATHER_RCU_TABLE_FREE        if PARAVIRT
+       select MMU_GATHER_MERGE_VMAS
        select HAVE_POSIX_CPU_TIMERS_TASK_WORK
        select HAVE_REGS_AND_STACK_ACCESS_API
        select HAVE_RELIABLE_STACKTRACE         if UNWINDER_ORC || STACK_VALIDATION
@@ -277,6 +278,7 @@ config X86
        select SYSCTL_EXCEPTION_TRACE
        select THREAD_INFO_IN_TASK
        select TRACE_IRQFLAGS_SUPPORT
+       select TRACE_IRQFLAGS_NMI_SUPPORT
        select USER_STACKTRACE_SUPPORT
        select VIRT_TO_BUS
        select HAVE_ARCH_KCSAN                  if X86_64
@@ -391,8 +393,8 @@ config PGTABLE_LEVELS
 
 config CC_HAS_SANE_STACKPROTECTOR
        bool
-       default $(success,$(srctree)/scripts/gcc-x86_64-has-stack-protector.sh $(CC)) if 64BIT
-       default $(success,$(srctree)/scripts/gcc-x86_32-has-stack-protector.sh $(CC))
+       default $(success,$(srctree)/scripts/gcc-x86_64-has-stack-protector.sh $(CC) $(CLANG_FLAGS)) if 64BIT
+       default $(success,$(srctree)/scripts/gcc-x86_32-has-stack-protector.sh $(CC) $(CLANG_FLAGS))
        help
          We have to make sure stack protector is unconditionally disabled if
          the compiler produces broken code or if it does not let us control
@@ -462,29 +464,6 @@ config GOLDFISH
        def_bool y
        depends on X86_GOLDFISH
 
-config RETPOLINE
-       bool "Avoid speculative indirect branches in kernel"
-       select OBJTOOL if HAVE_OBJTOOL
-       default y
-       help
-         Compile kernel with the retpoline compiler options to guard against
-         kernel-to-user data leaks by avoiding speculative indirect
-         branches. Requires a compiler with -mindirect-branch=thunk-extern
-         support for full protection. The kernel may run slower.
-
-config CC_HAS_SLS
-       def_bool $(cc-option,-mharden-sls=all)
-
-config SLS
-       bool "Mitigate Straight-Line-Speculation"
-       depends on CC_HAS_SLS && X86_64
-       select OBJTOOL if HAVE_OBJTOOL
-       default n
-       help
-         Compile the kernel with straight-line-speculation options to guard
-         against straight line speculation. The kernel image might be slightly
-         larger.
-
 config X86_CPU_RESCTRL
        bool "x86 CPU resource control support"
        depends on X86 && (CPU_SUP_INTEL || CPU_SUP_AMD)
@@ -1833,15 +1812,6 @@ config ARCH_USES_PG_UNCACHED
        def_bool y
        depends on X86_PAT
 
-config ARCH_RANDOM
-       def_bool y
-       prompt "x86 architectural random number generator" if EXPERT
-       help
-         Enable the x86 architectural RDRAND instruction
-         (Intel Bull Mountain technology) to generate random numbers.
-         If supported, this is a high bandwidth, cryptographically
-         secure hardware random number generator.
-
 config X86_UMIP
        def_bool y
        prompt "User Mode Instruction Prevention" if EXPERT
@@ -2032,7 +2002,7 @@ config KEXEC
 config KEXEC_FILE
        bool "kexec file based system call"
        select KEXEC_CORE
-       select BUILD_BIN2C
+       select HAVE_IMA_KEXEC if IMA
        depends on X86_64
        depends on CRYPTO=y
        depends on CRYPTO_SHA256=y
@@ -2453,6 +2423,91 @@ source "kernel/livepatch/Kconfig"
 
 endmenu
 
+config CC_HAS_SLS
+       def_bool $(cc-option,-mharden-sls=all)
+
+config CC_HAS_RETURN_THUNK
+       def_bool $(cc-option,-mfunction-return=thunk-extern)
+
+menuconfig SPECULATION_MITIGATIONS
+       bool "Mitigations for speculative execution vulnerabilities"
+       default y
+       help
+         Say Y here to enable options which enable mitigations for
+         speculative execution hardware vulnerabilities.
+
+         If you say N, all mitigations will be disabled. You really
+         should know what you are doing to say so.
+
+if SPECULATION_MITIGATIONS
+
+config PAGE_TABLE_ISOLATION
+       bool "Remove the kernel mapping in user mode"
+       default y
+       depends on (X86_64 || X86_PAE)
+       help
+         This feature reduces the number of hardware side channels by
+         ensuring that the majority of kernel addresses are not mapped
+         into userspace.
+
+         See Documentation/x86/pti.rst for more details.
+
+config RETPOLINE
+       bool "Avoid speculative indirect branches in kernel"
+       select OBJTOOL if HAVE_OBJTOOL
+       default y
+       help
+         Compile kernel with the retpoline compiler options to guard against
+         kernel-to-user data leaks by avoiding speculative indirect
+         branches. Requires a compiler with -mindirect-branch=thunk-extern
+         support for full protection. The kernel may run slower.
+
+config RETHUNK
+       bool "Enable return-thunks"
+       depends on RETPOLINE && CC_HAS_RETURN_THUNK
+       select OBJTOOL if HAVE_OBJTOOL
+       default y if X86_64
+       help
+         Compile the kernel with the return-thunks compiler option to guard
+         against kernel-to-user data leaks by avoiding return speculation.
+         Requires a compiler with -mfunction-return=thunk-extern
+         support for full protection. The kernel may run slower.
+
+config CPU_UNRET_ENTRY
+       bool "Enable UNRET on kernel entry"
+       depends on CPU_SUP_AMD && RETHUNK && X86_64
+       default y
+       help
+         Compile the kernel with support for the retbleed=unret mitigation.
+
+config CPU_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
+       bool "Enable IBRS on kernel entry"
+       depends on CPU_SUP_INTEL && X86_64
+       default y
+       help
+         Compile the kernel with support for the spectre_v2=ibrs mitigation.
+         This mitigates both spectre_v2 and retbleed at great cost to
+         performance.
+
+config SLS
+       bool "Mitigate Straight-Line-Speculation"
+       depends on CC_HAS_SLS && X86_64
+       select OBJTOOL if HAVE_OBJTOOL
+       default n
+       help
+         Compile the kernel with straight-line-speculation options to guard
+         against straight line speculation. The kernel image might be slightly
+         larger.
+
+endif
+
 config ARCH_HAS_ADD_PAGES
        def_bool y
        depends on ARCH_ENABLE_MEMORY_HOTPLUG
index 340399f..bdfe08f 100644 (file)
@@ -1,8 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
 
-config TRACE_IRQFLAGS_NMI_SUPPORT
-       def_bool y
-
 config EARLY_PRINTK_USB
        bool
 
index a74886a..7854685 100644 (file)
@@ -21,6 +21,13 @@ ifdef CONFIG_CC_IS_CLANG
 RETPOLINE_CFLAGS       := -mretpoline-external-thunk
 RETPOLINE_VDSO_CFLAGS  := -mretpoline
 endif
+
+ifdef CONFIG_RETHUNK
+RETHUNK_CFLAGS         := -mfunction-return=thunk-extern
+RETPOLINE_CFLAGS       += $(RETHUNK_CFLAGS)
+endif
+
+export RETHUNK_CFLAGS
 export RETPOLINE_CFLAGS
 export RETPOLINE_VDSO_CFLAGS
 
index 44c350d..d4a314c 100644 (file)
@@ -110,6 +110,7 @@ void kernel_add_identity_map(unsigned long start, unsigned long end)
 void initialize_identity_maps(void *rmode)
 {
        unsigned long cmdline;
+       struct setup_data *sd;
 
        /* Exclude the encryption mask from __PHYSICAL_MASK */
        physical_mask &= ~sme_me_mask;
@@ -163,6 +164,18 @@ void initialize_identity_maps(void *rmode)
        cmdline = get_cmd_line_ptr();
        kernel_add_identity_map(cmdline, cmdline + COMMAND_LINE_SIZE);
 
+       /*
+        * Also map the setup_data entries passed via boot_params in case they
+        * need to be accessed by uncompressed kernel via the identity mapping.
+        */
+       sd = (struct setup_data *)boot_params->hdr.setup_data;
+       while (sd) {
+               unsigned long sd_addr = (unsigned long)sd;
+
+               kernel_add_identity_map(sd_addr, sd_addr + sizeof(*sd) + sd->len);
+               sd = (struct setup_data *)sd->next;
+       }
+
        sev_prep_identity_maps(top_level_pgt);
 
        /* Load the new page-table. */
index 2831685..04d07ab 100644 (file)
@@ -61,14 +61,15 @@ sha256-ssse3-$(CONFIG_AS_SHA256_NI) += sha256_ni_asm.o
 obj-$(CONFIG_CRYPTO_SHA512_SSSE3) += sha512-ssse3.o
 sha512-ssse3-y := sha512-ssse3-asm.o sha512-avx-asm.o sha512-avx2-asm.o sha512_ssse3_glue.o
 
-obj-$(CONFIG_CRYPTO_BLAKE2S_X86) += blake2s-x86_64.o
-blake2s-x86_64-y := blake2s-shash.o
-obj-$(if $(CONFIG_CRYPTO_BLAKE2S_X86),y) += libblake2s-x86_64.o
+obj-$(CONFIG_CRYPTO_BLAKE2S_X86) += libblake2s-x86_64.o
 libblake2s-x86_64-y := blake2s-core.o blake2s-glue.o
 
 obj-$(CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL) += ghash-clmulni-intel.o
 ghash-clmulni-intel-y := ghash-clmulni-intel_asm.o ghash-clmulni-intel_glue.o
 
+obj-$(CONFIG_CRYPTO_POLYVAL_CLMUL_NI) += polyval-clmulni.o
+polyval-clmulni-y := polyval-clmulni_asm.o polyval-clmulni_glue.o
+
 obj-$(CONFIG_CRYPTO_CRC32C_INTEL) += crc32c-intel.o
 crc32c-intel-y := crc32c-intel_glue.o
 crc32c-intel-$(CONFIG_64BIT) += crc32c-pcl-intel-asm_64.o
index 43852ba..2402b94 100644 (file)
 
 #define VMOVDQ         vmovdqu
 
+/*
+ * Note: the "x" prefix in these aliases means "this is an xmm register".  The
+ * alias prefixes have no relation to XCTR where the "X" prefix means "XOR
+ * counter".
+ */
 #define xdata0         %xmm0
 #define xdata1         %xmm1
 #define xdata2         %xmm2
 #define xdata5         %xmm5
 #define xdata6         %xmm6
 #define xdata7         %xmm7
-#define xcounter       %xmm8
-#define xbyteswap      %xmm9
+#define xcounter       %xmm8   // CTR mode only
+#define xiv            %xmm8   // XCTR mode only
+#define xbyteswap      %xmm9   // CTR mode only
+#define xtmp           %xmm9   // XCTR mode only
 #define xkey0          %xmm10
 #define xkey4          %xmm11
 #define xkey8          %xmm12
@@ -45,7 +52,7 @@
 #define p_keys         %rdx
 #define p_out          %rcx
 #define num_bytes      %r8
-
+#define counter                %r9     // XCTR mode only
 #define tmp            %r10
 #define        DDQ_DATA        0
 #define        XDATA           1
@@ -102,7 +109,7 @@ ddq_add_8:
  * do_aes num_in_par load_keys key_len
  * This increments p_in, but not p_out
  */
-.macro do_aes b, k, key_len
+.macro do_aes b, k, key_len, xctr
        .set by, \b
        .set load_keys, \k
        .set klen, \key_len
@@ -111,29 +118,48 @@ ddq_add_8:
                vmovdqa 0*16(p_keys), xkey0
        .endif
 
-       vpshufb xbyteswap, xcounter, xdata0
-
-       .set i, 1
-       .rept (by - 1)
-               club XDATA, i
-               vpaddq  (ddq_add_1 + 16 * (i - 1))(%rip), xcounter, var_xdata
-               vptest  ddq_low_msk(%rip), var_xdata
-               jnz 1f
-               vpaddq  ddq_high_add_1(%rip), var_xdata, var_xdata
-               vpaddq  ddq_high_add_1(%rip), xcounter, xcounter
-               1:
-               vpshufb xbyteswap, var_xdata, var_xdata
-               .set i, (i +1)
-       .endr
+       .if \xctr
+               movq counter, xtmp
+               .set i, 0
+               .rept (by)
+                       club XDATA, i
+                       vpaddq  (ddq_add_1 + 16 * i)(%rip), xtmp, var_xdata
+                       .set i, (i +1)
+               .endr
+               .set i, 0
+               .rept (by)
+                       club    XDATA, i
+                       vpxor   xiv, var_xdata, var_xdata
+                       .set i, (i +1)
+               .endr
+       .else
+               vpshufb xbyteswap, xcounter, xdata0
+               .set i, 1
+               .rept (by - 1)
+                       club XDATA, i
+                       vpaddq  (ddq_add_1 + 16 * (i - 1))(%rip), xcounter, var_xdata
+                       vptest  ddq_low_msk(%rip), var_xdata
+                       jnz 1f
+                       vpaddq  ddq_high_add_1(%rip), var_xdata, var_xdata
+                       vpaddq  ddq_high_add_1(%rip), xcounter, xcounter
+                       1:
+                       vpshufb xbyteswap, var_xdata, var_xdata
+                       .set i, (i +1)
+               .endr
+       .endif
 
        vmovdqa 1*16(p_keys), xkeyA
 
        vpxor   xkey0, xdata0, xdata0
-       vpaddq  (ddq_add_1 + 16 * (by - 1))(%rip), xcounter, xcounter
-       vptest  ddq_low_msk(%rip), xcounter
-       jnz     1f
-       vpaddq  ddq_high_add_1(%rip), xcounter, xcounter
-       1:
+       .if \xctr
+               add $by, counter
+       .else
+               vpaddq  (ddq_add_1 + 16 * (by - 1))(%rip), xcounter, xcounter
+               vptest  ddq_low_msk(%rip), xcounter
+               jnz     1f
+               vpaddq  ddq_high_add_1(%rip), xcounter, xcounter
+               1:
+       .endif
 
        .set i, 1
        .rept (by - 1)
@@ -371,94 +397,99 @@ ddq_add_8:
        .endr
 .endm
 
-.macro do_aes_load val, key_len
-       do_aes \val, 1, \key_len
+.macro do_aes_load val, key_len, xctr
+       do_aes \val, 1, \key_len, \xctr
 .endm
 
-.macro do_aes_noload val, key_len
-       do_aes \val, 0, \key_len
+.macro do_aes_noload val, key_len, xctr
+       do_aes \val, 0, \key_len, \xctr
 .endm
 
 /* main body of aes ctr load */
 
-.macro do_aes_ctrmain key_len
+.macro do_aes_ctrmain key_len, xctr
        cmp     $16, num_bytes
-       jb      .Ldo_return2\key_len
+       jb      .Ldo_return2\xctr\key_len
 
-       vmovdqa byteswap_const(%rip), xbyteswap
-       vmovdqu (p_iv), xcounter
-       vpshufb xbyteswap, xcounter, xcounter
+       .if \xctr
+               shr     $4, counter
+               vmovdqu (p_iv), xiv
+       .else
+               vmovdqa byteswap_const(%rip), xbyteswap
+               vmovdqu (p_iv), xcounter
+               vpshufb xbyteswap, xcounter, xcounter
+       .endif
 
        mov     num_bytes, tmp
        and     $(7*16), tmp
-       jz      .Lmult_of_8_blks\key_len
+       jz      .Lmult_of_8_blks\xctr\key_len
 
        /* 1 <= tmp <= 7 */
        cmp     $(4*16), tmp
-       jg      .Lgt4\key_len
-       je      .Leq4\key_len
+       jg      .Lgt4\xctr\key_len
+       je      .Leq4\xctr\key_len
 
-.Llt4\key_len:
+.Llt4\xctr\key_len:
        cmp     $(2*16), tmp
-       jg      .Leq3\key_len
-       je      .Leq2\key_len
+       jg      .Leq3\xctr\key_len
+       je      .Leq2\xctr\key_len
 
-.Leq1\key_len:
-       do_aes_load     1, \key_len
+.Leq1\xctr\key_len:
+       do_aes_load     1, \key_len, \xctr
        add     $(1*16), p_out
        and     $(~7*16), num_bytes
-       jz      .Ldo_return2\key_len
-       jmp     .Lmain_loop2\key_len
+       jz      .Ldo_return2\xctr\key_len
+       jmp     .Lmain_loop2\xctr\key_len
 
-.Leq2\key_len:
-       do_aes_load     2, \key_len
+.Leq2\xctr\key_len:
+       do_aes_load     2, \key_len, \xctr
        add     $(2*16), p_out
        and     $(~7*16), num_bytes
-       jz      .Ldo_return2\key_len
-       jmp     .Lmain_loop2\key_len
+       jz      .Ldo_return2\xctr\key_len
+       jmp     .Lmain_loop2\xctr\key_len
 
 
-.Leq3\key_len:
-       do_aes_load     3, \key_len
+.Leq3\xctr\key_len:
+       do_aes_load     3, \key_len, \xctr
        add     $(3*16), p_out
        and     $(~7*16), num_bytes
-       jz      .Ldo_return2\key_len
-       jmp     .Lmain_loop2\key_len
+       jz      .Ldo_return2\xctr\key_len
+       jmp     .Lmain_loop2\xctr\key_len
 
-.Leq4\key_len:
-       do_aes_load     4, \key_len
+.Leq4\xctr\key_len:
+       do_aes_load     4, \key_len, \xctr
        add     $(4*16), p_out
        and     $(~7*16), num_bytes
-       jz      .Ldo_return2\key_len
-       jmp     .Lmain_loop2\key_len
+       jz      .Ldo_return2\xctr\key_len
+       jmp     .Lmain_loop2\xctr\key_len
 
-.Lgt4\key_len:
+.Lgt4\xctr\key_len:
        cmp     $(6*16), tmp
-       jg      .Leq7\key_len
-       je      .Leq6\key_len
+       jg      .Leq7\xctr\key_len
+       je      .Leq6\xctr\key_len
 
-.Leq5\key_len:
-       do_aes_load     5, \key_len
+.Leq5\xctr\key_len:
+       do_aes_load     5, \key_len, \xctr
        add     $(5*16), p_out
        and     $(~7*16), num_bytes
-       jz      .Ldo_return2\key_len
-       jmp     .Lmain_loop2\key_len
+       jz      .Ldo_return2\xctr\key_len
+       jmp     .Lmain_loop2\xctr\key_len
 
-.Leq6\key_len:
-       do_aes_load     6, \key_len
+.Leq6\xctr\key_len:
+       do_aes_load     6, \key_len, \xctr
        add     $(6*16), p_out
        and     $(~7*16), num_bytes
-       jz      .Ldo_return2\key_len
-       jmp     .Lmain_loop2\key_len
+       jz      .Ldo_return2\xctr\key_len
+       jmp     .Lmain_loop2\xctr\key_len
 
-.Leq7\key_len:
-       do_aes_load     7, \key_len
+.Leq7\xctr\key_len:
+       do_aes_load     7, \key_len, \xctr
        add     $(7*16), p_out
        and     $(~7*16), num_bytes
-       jz      .Ldo_return2\key_len
-       jmp     .Lmain_loop2\key_len
+       jz      .Ldo_return2\xctr\key_len
+       jmp     .Lmain_loop2\xctr\key_len
 
-.Lmult_of_8_blks\key_len:
+.Lmult_of_8_blks\xctr\key_len:
        .if (\key_len != KEY_128)
                vmovdqa 0*16(p_keys), xkey0
                vmovdqa 4*16(p_keys), xkey4
@@ -471,17 +502,19 @@ ddq_add_8:
                vmovdqa 9*16(p_keys), xkey12
        .endif
 .align 16
-.Lmain_loop2\key_len:
+.Lmain_loop2\xctr\key_len:
        /* num_bytes is a multiple of 8 and >0 */
-       do_aes_noload   8, \key_len
+       do_aes_noload   8, \key_len, \xctr
        add     $(8*16), p_out
        sub     $(8*16), num_bytes
-       jne     .Lmain_loop2\key_len
+       jne     .Lmain_loop2\xctr\key_len
 
-.Ldo_return2\key_len:
-       /* return updated IV */
-       vpshufb xbyteswap, xcounter, xcounter
-       vmovdqu xcounter, (p_iv)
+.Ldo_return2\xctr\key_len:
+       .if !\xctr
+               /* return updated IV */
+               vpshufb xbyteswap, xcounter, xcounter
+               vmovdqu xcounter, (p_iv)
+       .endif
        RET
 .endm
 
@@ -494,7 +527,7 @@ ddq_add_8:
  */
 SYM_FUNC_START(aes_ctr_enc_128_avx_by8)
        /* call the aes main loop */
-       do_aes_ctrmain KEY_128
+       do_aes_ctrmain KEY_128 0
 
 SYM_FUNC_END(aes_ctr_enc_128_avx_by8)
 
@@ -507,7 +540,7 @@ SYM_FUNC_END(aes_ctr_enc_128_avx_by8)
  */
 SYM_FUNC_START(aes_ctr_enc_192_avx_by8)
        /* call the aes main loop */
-       do_aes_ctrmain KEY_192
+       do_aes_ctrmain KEY_192 0
 
 SYM_FUNC_END(aes_ctr_enc_192_avx_by8)
 
@@ -520,6 +553,45 @@ SYM_FUNC_END(aes_ctr_enc_192_avx_by8)
  */
 SYM_FUNC_START(aes_ctr_enc_256_avx_by8)
        /* call the aes main loop */
-       do_aes_ctrmain KEY_256
+       do_aes_ctrmain KEY_256 0
 
 SYM_FUNC_END(aes_ctr_enc_256_avx_by8)
+
+/*
+ * routine to do AES128 XCTR enc/decrypt "by8"
+ * XMM registers are clobbered.
+ * Saving/restoring must be done at a higher level
+ * aes_xctr_enc_128_avx_by8(const u8 *in, const u8 *iv, const void *keys,
+ *     u8* out, unsigned int num_bytes, unsigned int byte_ctr)
+ */
+SYM_FUNC_START(aes_xctr_enc_128_avx_by8)
+       /* call the aes main loop */
+       do_aes_ctrmain KEY_128 1
+
+SYM_FUNC_END(aes_xctr_enc_128_avx_by8)
+
+/*
+ * routine to do AES192 XCTR enc/decrypt "by8"
+ * XMM registers are clobbered.
+ * Saving/restoring must be done at a higher level
+ * aes_xctr_enc_192_avx_by8(const u8 *in, const u8 *iv, const void *keys,
+ *     u8* out, unsigned int num_bytes, unsigned int byte_ctr)
+ */
+SYM_FUNC_START(aes_xctr_enc_192_avx_by8)
+       /* call the aes main loop */
+       do_aes_ctrmain KEY_192 1
+
+SYM_FUNC_END(aes_xctr_enc_192_avx_by8)
+
+/*
+ * routine to do AES256 XCTR enc/decrypt "by8"
+ * XMM registers are clobbered.
+ * Saving/restoring must be done at a higher level
+ * aes_xctr_enc_256_avx_by8(const u8 *in, const u8 *iv, const void *keys,
+ *     u8* out, unsigned int num_bytes, unsigned int byte_ctr)
+ */
+SYM_FUNC_START(aes_xctr_enc_256_avx_by8)
+       /* call the aes main loop */
+       do_aes_ctrmain KEY_256 1
+
+SYM_FUNC_END(aes_xctr_enc_256_avx_by8)
index 41901ba..a5b0cb3 100644 (file)
@@ -135,6 +135,20 @@ asmlinkage void aes_ctr_enc_192_avx_by8(const u8 *in, u8 *iv,
                void *keys, u8 *out, unsigned int num_bytes);
 asmlinkage void aes_ctr_enc_256_avx_by8(const u8 *in, u8 *iv,
                void *keys, u8 *out, unsigned int num_bytes);
+
+
+asmlinkage void aes_xctr_enc_128_avx_by8(const u8 *in, const u8 *iv,
+       const void *keys, u8 *out, unsigned int num_bytes,
+       unsigned int byte_ctr);
+
+asmlinkage void aes_xctr_enc_192_avx_by8(const u8 *in, const u8 *iv,
+       const void *keys, u8 *out, unsigned int num_bytes,
+       unsigned int byte_ctr);
+
+asmlinkage void aes_xctr_enc_256_avx_by8(const u8 *in, const u8 *iv,
+       const void *keys, u8 *out, unsigned int num_bytes,
+       unsigned int byte_ctr);
+
 /*
  * asmlinkage void aesni_gcm_init_avx_gen2()
  * gcm_data *my_ctx_data, context data
@@ -527,6 +541,59 @@ static int ctr_crypt(struct skcipher_request *req)
        return err;
 }
 
+static void aesni_xctr_enc_avx_tfm(struct crypto_aes_ctx *ctx, u8 *out,
+                                  const u8 *in, unsigned int len, u8 *iv,
+                                  unsigned int byte_ctr)
+{
+       if (ctx->key_length == AES_KEYSIZE_128)
+               aes_xctr_enc_128_avx_by8(in, iv, (void *)ctx, out, len,
+                                        byte_ctr);
+       else if (ctx->key_length == AES_KEYSIZE_192)
+               aes_xctr_enc_192_avx_by8(in, iv, (void *)ctx, out, len,
+                                        byte_ctr);
+       else
+               aes_xctr_enc_256_avx_by8(in, iv, (void *)ctx, out, len,
+                                        byte_ctr);
+}
+
+static int xctr_crypt(struct skcipher_request *req)
+{
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+       struct crypto_aes_ctx *ctx = aes_ctx(crypto_skcipher_ctx(tfm));
+       u8 keystream[AES_BLOCK_SIZE];
+       struct skcipher_walk walk;
+       unsigned int nbytes;
+       unsigned int byte_ctr = 0;
+       int err;
+       __le32 block[AES_BLOCK_SIZE / sizeof(__le32)];
+
+       err = skcipher_walk_virt(&walk, req, false);
+
+       while ((nbytes = walk.nbytes) > 0) {
+               kernel_fpu_begin();
+               if (nbytes & AES_BLOCK_MASK)
+                       aesni_xctr_enc_avx_tfm(ctx, walk.dst.virt.addr,
+                               walk.src.virt.addr, nbytes & AES_BLOCK_MASK,
+                               walk.iv, byte_ctr);
+               nbytes &= ~AES_BLOCK_MASK;
+               byte_ctr += walk.nbytes - nbytes;
+
+               if (walk.nbytes == walk.total && nbytes > 0) {
+                       memcpy(block, walk.iv, AES_BLOCK_SIZE);
+                       block[0] ^= cpu_to_le32(1 + byte_ctr / AES_BLOCK_SIZE);
+                       aesni_enc(ctx, keystream, (u8 *)block);
+                       crypto_xor_cpy(walk.dst.virt.addr + walk.nbytes -
+                                      nbytes, walk.src.virt.addr + walk.nbytes
+                                      - nbytes, keystream, nbytes);
+                       byte_ctr += nbytes;
+                       nbytes = 0;
+               }
+               kernel_fpu_end();
+               err = skcipher_walk_done(&walk, nbytes);
+       }
+       return err;
+}
+
 static int
 rfc4106_set_hash_subkey(u8 *hash_subkey, const u8 *key, unsigned int key_len)
 {
@@ -1051,6 +1118,33 @@ static
 struct simd_skcipher_alg *aesni_simd_skciphers[ARRAY_SIZE(aesni_skciphers)];
 
 #ifdef CONFIG_X86_64
+/*
+ * XCTR does not have a non-AVX implementation, so it must be enabled
+ * conditionally.
+ */
+static struct skcipher_alg aesni_xctr = {
+       .base = {
+               .cra_name               = "__xctr(aes)",
+               .cra_driver_name        = "__xctr-aes-aesni",
+               .cra_priority           = 400,
+               .cra_flags              = CRYPTO_ALG_INTERNAL,
+               .cra_blocksize          = 1,
+               .cra_ctxsize            = CRYPTO_AES_CTX_SIZE,
+               .cra_module             = THIS_MODULE,
+       },
+       .min_keysize    = AES_MIN_KEY_SIZE,
+       .max_keysize    = AES_MAX_KEY_SIZE,
+       .ivsize         = AES_BLOCK_SIZE,
+       .chunksize      = AES_BLOCK_SIZE,
+       .setkey         = aesni_skcipher_setkey,
+       .encrypt        = xctr_crypt,
+       .decrypt        = xctr_crypt,
+};
+
+static struct simd_skcipher_alg *aesni_simd_xctr;
+#endif /* CONFIG_X86_64 */
+
+#ifdef CONFIG_X86_64
 static int generic_gcmaes_set_key(struct crypto_aead *aead, const u8 *key,
                                  unsigned int key_len)
 {
@@ -1163,7 +1257,7 @@ static int __init aesni_init(void)
                static_call_update(aesni_ctr_enc_tfm, aesni_ctr_enc_avx_tfm);
                pr_info("AES CTR mode by8 optimization enabled\n");
        }
-#endif
+#endif /* CONFIG_X86_64 */
 
        err = crypto_register_alg(&aesni_cipher_alg);
        if (err)
@@ -1180,8 +1274,22 @@ static int __init aesni_init(void)
        if (err)
                goto unregister_skciphers;
 
+#ifdef CONFIG_X86_64
+       if (boot_cpu_has(X86_FEATURE_AVX))
+               err = simd_register_skciphers_compat(&aesni_xctr, 1,
+                                                    &aesni_simd_xctr);
+       if (err)
+               goto unregister_aeads;
+#endif /* CONFIG_X86_64 */
+
        return 0;
 
+#ifdef CONFIG_X86_64
+unregister_aeads:
+       simd_unregister_aeads(aesni_aeads, ARRAY_SIZE(aesni_aeads),
+                               aesni_simd_aeads);
+#endif /* CONFIG_X86_64 */
+
 unregister_skciphers:
        simd_unregister_skciphers(aesni_skciphers, ARRAY_SIZE(aesni_skciphers),
                                  aesni_simd_skciphers);
@@ -1197,6 +1305,10 @@ static void __exit aesni_exit(void)
        simd_unregister_skciphers(aesni_skciphers, ARRAY_SIZE(aesni_skciphers),
                                  aesni_simd_skciphers);
        crypto_unregister_alg(&aesni_cipher_alg);
+#ifdef CONFIG_X86_64
+       if (boot_cpu_has(X86_FEATURE_AVX))
+               simd_unregister_skciphers(&aesni_xctr, 1, &aesni_simd_xctr);
+#endif /* CONFIG_X86_64 */
 }
 
 late_initcall(aesni_init);
index 69853c1..aaba212 100644 (file)
@@ -4,7 +4,6 @@
  */
 
 #include <crypto/internal/blake2s.h>
-#include <crypto/internal/simd.h>
 
 #include <linux/types.h>
 #include <linux/jump_label.h>
@@ -33,7 +32,7 @@ void blake2s_compress(struct blake2s_state *state, const u8 *block,
        /* SIMD disables preemption, so relax after processing each page. */
        BUILD_BUG_ON(SZ_4K / BLAKE2S_BLOCK_SIZE < 8);
 
-       if (!static_branch_likely(&blake2s_use_ssse3) || !crypto_simd_usable()) {
+       if (!static_branch_likely(&blake2s_use_ssse3) || !may_use_simd()) {
                blake2s_compress_generic(state, block, nblocks, inc);
                return;
        }
diff --git a/arch/x86/crypto/blake2s-shash.c b/arch/x86/crypto/blake2s-shash.c
deleted file mode 100644 (file)
index 59ae28a..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0 OR MIT
-/*
- * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
- */
-
-#include <crypto/internal/blake2s.h>
-#include <crypto/internal/simd.h>
-#include <crypto/internal/hash.h>
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/sizes.h>
-
-#include <asm/cpufeature.h>
-#include <asm/processor.h>
-
-static int crypto_blake2s_update_x86(struct shash_desc *desc,
-                                    const u8 *in, unsigned int inlen)
-{
-       return crypto_blake2s_update(desc, in, inlen, false);
-}
-
-static int crypto_blake2s_final_x86(struct shash_desc *desc, u8 *out)
-{
-       return crypto_blake2s_final(desc, out, false);
-}
-
-#define BLAKE2S_ALG(name, driver_name, digest_size)                    \
-       {                                                               \
-               .base.cra_name          = name,                         \
-               .base.cra_driver_name   = driver_name,                  \
-               .base.cra_priority      = 200,                          \
-               .base.cra_flags         = CRYPTO_ALG_OPTIONAL_KEY,      \
-               .base.cra_blocksize     = BLAKE2S_BLOCK_SIZE,           \
-               .base.cra_ctxsize       = sizeof(struct blake2s_tfm_ctx), \
-               .base.cra_module        = THIS_MODULE,                  \
-               .digestsize             = digest_size,                  \
-               .setkey                 = crypto_blake2s_setkey,        \
-               .init                   = crypto_blake2s_init,          \
-               .update                 = crypto_blake2s_update_x86,    \
-               .final                  = crypto_blake2s_final_x86,     \
-               .descsize               = sizeof(struct blake2s_state), \
-       }
-
-static struct shash_alg blake2s_algs[] = {
-       BLAKE2S_ALG("blake2s-128", "blake2s-128-x86", BLAKE2S_128_HASH_SIZE),
-       BLAKE2S_ALG("blake2s-160", "blake2s-160-x86", BLAKE2S_160_HASH_SIZE),
-       BLAKE2S_ALG("blake2s-224", "blake2s-224-x86", BLAKE2S_224_HASH_SIZE),
-       BLAKE2S_ALG("blake2s-256", "blake2s-256-x86", BLAKE2S_256_HASH_SIZE),
-};
-
-static int __init blake2s_mod_init(void)
-{
-       if (IS_REACHABLE(CONFIG_CRYPTO_HASH) && boot_cpu_has(X86_FEATURE_SSSE3))
-               return crypto_register_shashes(blake2s_algs, ARRAY_SIZE(blake2s_algs));
-       return 0;
-}
-
-static void __exit blake2s_mod_exit(void)
-{
-       if (IS_REACHABLE(CONFIG_CRYPTO_HASH) && boot_cpu_has(X86_FEATURE_SSSE3))
-               crypto_unregister_shashes(blake2s_algs, ARRAY_SIZE(blake2s_algs));
-}
-
-module_init(blake2s_mod_init);
-module_exit(blake2s_mod_exit);
-
-MODULE_ALIAS_CRYPTO("blake2s-128");
-MODULE_ALIAS_CRYPTO("blake2s-128-x86");
-MODULE_ALIAS_CRYPTO("blake2s-160");
-MODULE_ALIAS_CRYPTO("blake2s-160-x86");
-MODULE_ALIAS_CRYPTO("blake2s-224");
-MODULE_ALIAS_CRYPTO("blake2s-224-x86");
-MODULE_ALIAS_CRYPTO("blake2s-256");
-MODULE_ALIAS_CRYPTO("blake2s-256-x86");
-MODULE_LICENSE("GPL v2");
index ba06322..019c64c 100644 (file)
@@ -144,7 +144,7 @@ static int cbc_encrypt(struct skcipher_request *req)
 
        err = skcipher_walk_virt(&walk, req, false);
 
-       while ((nbytes = walk.nbytes)) {
+       while (walk.nbytes) {
                nbytes = __cbc_encrypt(ctx, &walk);
                err = skcipher_walk_done(&walk, nbytes);
        }
@@ -225,7 +225,7 @@ static int cbc_decrypt(struct skcipher_request *req)
 
        err = skcipher_walk_virt(&walk, req, false);
 
-       while ((nbytes = walk.nbytes)) {
+       while (walk.nbytes) {
                nbytes = __cbc_decrypt(ctx, &walk);
                err = skcipher_walk_done(&walk, nbytes);
        }
diff --git a/arch/x86/crypto/polyval-clmulni_asm.S b/arch/x86/crypto/polyval-clmulni_asm.S
new file mode 100644 (file)
index 0000000..a6ebe4e
--- /dev/null
@@ -0,0 +1,321 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2021 Google LLC
+ */
+/*
+ * This is an efficient implementation of POLYVAL using intel PCLMULQDQ-NI
+ * instructions. It works on 8 blocks at a time, by precomputing the first 8
+ * keys powers h^8, ..., h^1 in the POLYVAL finite field. This precomputation
+ * allows us to split finite field multiplication into two steps.
+ *
+ * In the first step, we consider h^i, m_i as normal polynomials of degree less
+ * than 128. We then compute p(x) = h^8m_0 + ... + h^1m_7 where multiplication
+ * is simply polynomial multiplication.
+ *
+ * In the second step, we compute the reduction of p(x) modulo the finite field
+ * modulus g(x) = x^128 + x^127 + x^126 + x^121 + 1.
+ *
+ * This two step process is equivalent to computing h^8m_0 + ... + h^1m_7 where
+ * multiplication is finite field multiplication. The advantage is that the
+ * two-step process  only requires 1 finite field reduction for every 8
+ * polynomial multiplications. Further parallelism is gained by interleaving the
+ * multiplications and polynomial reductions.
+ */
+
+#include <linux/linkage.h>
+#include <asm/frame.h>
+
+#define STRIDE_BLOCKS 8
+
+#define GSTAR %xmm7
+#define PL %xmm8
+#define PH %xmm9
+#define TMP_XMM %xmm11
+#define LO %xmm12
+#define HI %xmm13
+#define MI %xmm14
+#define SUM %xmm15
+
+#define KEY_POWERS %rdi
+#define MSG %rsi
+#define BLOCKS_LEFT %rdx
+#define ACCUMULATOR %rcx
+#define TMP %rax
+
+.section    .rodata.cst16.gstar, "aM", @progbits, 16
+.align 16
+
+.Lgstar:
+       .quad 0xc200000000000000, 0xc200000000000000
+
+.text
+
+/*
+ * Performs schoolbook1_iteration on two lists of 128-bit polynomials of length
+ * count pointed to by MSG and KEY_POWERS.
+ */
+.macro schoolbook1 count
+       .set i, 0
+       .rept (\count)
+               schoolbook1_iteration i 0
+               .set i, (i +1)
+       .endr
+.endm
+
+/*
+ * Computes the product of two 128-bit polynomials at the memory locations
+ * specified by (MSG + 16*i) and (KEY_POWERS + 16*i) and XORs the components of
+ * the 256-bit product into LO, MI, HI.
+ *
+ * Given:
+ *   X = [X_1 : X_0]
+ *   Y = [Y_1 : Y_0]
+ *
+ * We compute:
+ *   LO += X_0 * Y_0
+ *   MI += X_0 * Y_1 + X_1 * Y_0
+ *   HI += X_1 * Y_1
+ *
+ * Later, the 256-bit result can be extracted as:
+ *   [HI_1 : HI_0 + MI_1 : LO_1 + MI_0 : LO_0]
+ * This step is done when computing the polynomial reduction for efficiency
+ * reasons.
+ *
+ * If xor_sum == 1, then also XOR the value of SUM into m_0.  This avoids an
+ * extra multiplication of SUM and h^8.
+ */
+.macro schoolbook1_iteration i xor_sum
+       movups (16*\i)(MSG), %xmm0
+       .if (\i == 0 && \xor_sum == 1)
+               pxor SUM, %xmm0
+       .endif
+       vpclmulqdq $0x01, (16*\i)(KEY_POWERS), %xmm0, %xmm2
+       vpclmulqdq $0x00, (16*\i)(KEY_POWERS), %xmm0, %xmm1
+       vpclmulqdq $0x10, (16*\i)(KEY_POWERS), %xmm0, %xmm3
+       vpclmulqdq $0x11, (16*\i)(KEY_POWERS), %xmm0, %xmm4
+       vpxor %xmm2, MI, MI
+       vpxor %xmm1, LO, LO
+       vpxor %xmm4, HI, HI
+       vpxor %xmm3, MI, MI
+.endm
+
+/*
+ * Performs the same computation as schoolbook1_iteration, except we expect the
+ * arguments to already be loaded into xmm0 and xmm1 and we set the result
+ * registers LO, MI, and HI directly rather than XOR'ing into them.
+ */
+.macro schoolbook1_noload
+       vpclmulqdq $0x01, %xmm0, %xmm1, MI
+       vpclmulqdq $0x10, %xmm0, %xmm1, %xmm2
+       vpclmulqdq $0x00, %xmm0, %xmm1, LO
+       vpclmulqdq $0x11, %xmm0, %xmm1, HI
+       vpxor %xmm2, MI, MI
+.endm
+
+/*
+ * Computes the 256-bit polynomial represented by LO, HI, MI. Stores
+ * the result in PL, PH.
+ *   [PH : PL] = [HI_1 : HI_0 + MI_1 : LO_1 + MI_0 : LO_0]
+ */
+.macro schoolbook2
+       vpslldq $8, MI, PL
+       vpsrldq $8, MI, PH
+       pxor LO, PL
+       pxor HI, PH
+.endm
+
+/*
+ * Computes the 128-bit reduction of PH : PL. Stores the result in dest.
+ *
+ * This macro computes p(x) mod g(x) where p(x) is in montgomery form and g(x) =
+ * x^128 + x^127 + x^126 + x^121 + 1.
+ *
+ * We have a 256-bit polynomial PH : PL = P_3 : P_2 : P_1 : P_0 that is the
+ * product of two 128-bit polynomials in Montgomery form.  We need to reduce it
+ * mod g(x).  Also, since polynomials in Montgomery form have an "extra" factor
+ * of x^128, this product has two extra factors of x^128.  To get it back into
+ * Montgomery form, we need to remove one of these factors by dividing by x^128.
+ *
+ * To accomplish both of these goals, we add multiples of g(x) that cancel out
+ * the low 128 bits P_1 : P_0, leaving just the high 128 bits. Since the low
+ * bits are zero, the polynomial division by x^128 can be done by right shifting.
+ *
+ * Since the only nonzero term in the low 64 bits of g(x) is the constant term,
+ * the multiple of g(x) needed to cancel out P_0 is P_0 * g(x).  The CPU can
+ * only do 64x64 bit multiplications, so split P_0 * g(x) into x^128 * P_0 +
+ * x^64 * g*(x) * P_0 + P_0, where g*(x) is bits 64-127 of g(x).  Adding this to
+ * the original polynomial gives P_3 : P_2 + P_0 + T_1 : P_1 + T_0 : 0, where T
+ * = T_1 : T_0 = g*(x) * P_0.  Thus, bits 0-63 got "folded" into bits 64-191.
+ *
+ * Repeating this same process on the next 64 bits "folds" bits 64-127 into bits
+ * 128-255, giving the answer in bits 128-255. This time, we need to cancel P_1
+ * + T_0 in bits 64-127. The multiple of g(x) required is (P_1 + T_0) * g(x) *
+ * x^64. Adding this to our previous computation gives P_3 + P_1 + T_0 + V_1 :
+ * P_2 + P_0 + T_1 + V_0 : 0 : 0, where V = V_1 : V_0 = g*(x) * (P_1 + T_0).
+ *
+ * So our final computation is:
+ *   T = T_1 : T_0 = g*(x) * P_0
+ *   V = V_1 : V_0 = g*(x) * (P_1 + T_0)
+ *   p(x) / x^{128} mod g(x) = P_3 + P_1 + T_0 + V_1 : P_2 + P_0 + T_1 + V_0
+ *
+ * The implementation below saves a XOR instruction by computing P_1 + T_0 : P_0
+ * + T_1 and XORing into dest, rather than separately XORing P_1 : P_0 and T_0 :
+ * T_1 into dest.  This allows us to reuse P_1 + T_0 when computing V.
+ */
+.macro montgomery_reduction dest
+       vpclmulqdq $0x00, PL, GSTAR, TMP_XMM    # TMP_XMM = T_1 : T_0 = P_0 * g*(x)
+       pshufd $0b01001110, TMP_XMM, TMP_XMM    # TMP_XMM = T_0 : T_1
+       pxor PL, TMP_XMM                        # TMP_XMM = P_1 + T_0 : P_0 + T_1
+       pxor TMP_XMM, PH                        # PH = P_3 + P_1 + T_0 : P_2 + P_0 + T_1
+       pclmulqdq $0x11, GSTAR, TMP_XMM         # TMP_XMM = V_1 : V_0 = V = [(P_1 + T_0) * g*(x)]
+       vpxor TMP_XMM, PH, \dest
+.endm
+
+/*
+ * Compute schoolbook multiplication for 8 blocks
+ * m_0h^8 + ... + m_7h^1
+ *
+ * If reduce is set, also computes the montgomery reduction of the
+ * previous full_stride call and XORs with the first message block.
+ * (m_0 + REDUCE(PL, PH))h^8 + ... + m_7h^1.
+ * I.e., the first multiplication uses m_0 + REDUCE(PL, PH) instead of m_0.
+ */
+.macro full_stride reduce
+       pxor LO, LO
+       pxor HI, HI
+       pxor MI, MI
+
+       schoolbook1_iteration 7 0
+       .if \reduce
+               vpclmulqdq $0x00, PL, GSTAR, TMP_XMM
+       .endif
+
+       schoolbook1_iteration 6 0
+       .if \reduce
+               pshufd $0b01001110, TMP_XMM, TMP_XMM
+       .endif
+
+       schoolbook1_iteration 5 0
+       .if \reduce
+               pxor PL, TMP_XMM
+       .endif
+
+       schoolbook1_iteration 4 0
+       .if \reduce
+               pxor TMP_XMM, PH
+       .endif
+
+       schoolbook1_iteration 3 0
+       .if \reduce
+               pclmulqdq $0x11, GSTAR, TMP_XMM
+       .endif
+
+       schoolbook1_iteration 2 0
+       .if \reduce
+               vpxor TMP_XMM, PH, SUM
+       .endif
+
+       schoolbook1_iteration 1 0
+
+       schoolbook1_iteration 0 1
+
+       addq $(8*16), MSG
+       schoolbook2
+.endm
+
+/*
+ * Process BLOCKS_LEFT blocks, where 0 < BLOCKS_LEFT < STRIDE_BLOCKS
+ */
+.macro partial_stride
+       mov BLOCKS_LEFT, TMP
+       shlq $4, TMP
+       addq $(16*STRIDE_BLOCKS), KEY_POWERS
+       subq TMP, KEY_POWERS
+
+       movups (MSG), %xmm0
+       pxor SUM, %xmm0
+       movaps (KEY_POWERS), %xmm1
+       schoolbook1_noload
+       dec BLOCKS_LEFT
+       addq $16, MSG
+       addq $16, KEY_POWERS
+
+       test $4, BLOCKS_LEFT
+       jz .Lpartial4BlocksDone
+       schoolbook1 4
+       addq $(4*16), MSG
+       addq $(4*16), KEY_POWERS
+.Lpartial4BlocksDone:
+       test $2, BLOCKS_LEFT
+       jz .Lpartial2BlocksDone
+       schoolbook1 2
+       addq $(2*16), MSG
+       addq $(2*16), KEY_POWERS
+.Lpartial2BlocksDone:
+       test $1, BLOCKS_LEFT
+       jz .LpartialDone
+       schoolbook1 1
+.LpartialDone:
+       schoolbook2
+       montgomery_reduction SUM
+.endm
+
+/*
+ * Perform montgomery multiplication in GF(2^128) and store result in op1.
+ *
+ * Computes op1*op2*x^{-128} mod x^128 + x^127 + x^126 + x^121 + 1
+ * If op1, op2 are in montgomery form, this computes the montgomery
+ * form of op1*op2.
+ *
+ * void clmul_polyval_mul(u8 *op1, const u8 *op2);
+ */
+SYM_FUNC_START(clmul_polyval_mul)
+       FRAME_BEGIN
+       vmovdqa .Lgstar(%rip), GSTAR
+       movups (%rdi), %xmm0
+       movups (%rsi), %xmm1
+       schoolbook1_noload
+       schoolbook2
+       montgomery_reduction SUM
+       movups SUM, (%rdi)
+       FRAME_END
+       RET
+SYM_FUNC_END(clmul_polyval_mul)
+
+/*
+ * Perform polynomial evaluation as specified by POLYVAL.  This computes:
+ *     h^n * accumulator + h^n * m_0 + ... + h^1 * m_{n-1}
+ * where n=nblocks, h is the hash key, and m_i are the message blocks.
+ *
+ * rdi - pointer to precomputed key powers h^8 ... h^1
+ * rsi - pointer to message blocks
+ * rdx - number of blocks to hash
+ * rcx - pointer to the accumulator
+ *
+ * void clmul_polyval_update(const struct polyval_tfm_ctx *keys,
+ *     const u8 *in, size_t nblocks, u8 *accumulator);
+ */
+SYM_FUNC_START(clmul_polyval_update)
+       FRAME_BEGIN
+       vmovdqa .Lgstar(%rip), GSTAR
+       movups (ACCUMULATOR), SUM
+       subq $STRIDE_BLOCKS, BLOCKS_LEFT
+       js .LstrideLoopExit
+       full_stride 0
+       subq $STRIDE_BLOCKS, BLOCKS_LEFT
+       js .LstrideLoopExitReduce
+.LstrideLoop:
+       full_stride 1
+       subq $STRIDE_BLOCKS, BLOCKS_LEFT
+       jns .LstrideLoop
+.LstrideLoopExitReduce:
+       montgomery_reduction SUM
+.LstrideLoopExit:
+       add $STRIDE_BLOCKS, BLOCKS_LEFT
+       jz .LskipPartial
+       partial_stride
+.LskipPartial:
+       movups SUM, (ACCUMULATOR)
+       FRAME_END
+       RET
+SYM_FUNC_END(clmul_polyval_update)
diff --git a/arch/x86/crypto/polyval-clmulni_glue.c b/arch/x86/crypto/polyval-clmulni_glue.c
new file mode 100644 (file)
index 0000000..b7664d0
--- /dev/null
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Glue code for POLYVAL using PCMULQDQ-NI
+ *
+ * Copyright (c) 2007 Nokia Siemens Networks - Mikko Herranen <mh1@iki.fi>
+ * Copyright (c) 2009 Intel Corp.
+ *   Author: Huang Ying <ying.huang@intel.com>
+ * Copyright 2021 Google LLC
+ */
+
+/*
+ * Glue code based on ghash-clmulni-intel_glue.c.
+ *
+ * This implementation of POLYVAL uses montgomery multiplication
+ * accelerated by PCLMULQDQ-NI to implement the finite field
+ * operations.
+ */
+
+#include <crypto/algapi.h>
+#include <crypto/internal/hash.h>
+#include <crypto/internal/simd.h>
+#include <crypto/polyval.h>
+#include <linux/crypto.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/cpu_device_id.h>
+#include <asm/simd.h>
+
+#define NUM_KEY_POWERS 8
+
+struct polyval_tfm_ctx {
+       /*
+        * These powers must be in the order h^8, ..., h^1.
+        */
+       u8 key_powers[NUM_KEY_POWERS][POLYVAL_BLOCK_SIZE];
+};
+
+struct polyval_desc_ctx {
+       u8 buffer[POLYVAL_BLOCK_SIZE];
+       u32 bytes;
+};
+
+asmlinkage void clmul_polyval_update(const struct polyval_tfm_ctx *keys,
+       const u8 *in, size_t nblocks, u8 *accumulator);
+asmlinkage void clmul_polyval_mul(u8 *op1, const u8 *op2);
+
+static void internal_polyval_update(const struct polyval_tfm_ctx *keys,
+       const u8 *in, size_t nblocks, u8 *accumulator)
+{
+       if (likely(crypto_simd_usable())) {
+               kernel_fpu_begin();
+               clmul_polyval_update(keys, in, nblocks, accumulator);
+               kernel_fpu_end();
+       } else {
+               polyval_update_non4k(keys->key_powers[NUM_KEY_POWERS-1], in,
+                       nblocks, accumulator);
+       }
+}
+
+static void internal_polyval_mul(u8 *op1, const u8 *op2)
+{
+       if (likely(crypto_simd_usable())) {
+               kernel_fpu_begin();
+               clmul_polyval_mul(op1, op2);
+               kernel_fpu_end();
+       } else {
+               polyval_mul_non4k(op1, op2);
+       }
+}
+
+static int polyval_x86_setkey(struct crypto_shash *tfm,
+                       const u8 *key, unsigned int keylen)
+{
+       struct polyval_tfm_ctx *tctx = crypto_shash_ctx(tfm);
+       int i;
+
+       if (keylen != POLYVAL_BLOCK_SIZE)
+               return -EINVAL;
+
+       memcpy(tctx->key_powers[NUM_KEY_POWERS-1], key, POLYVAL_BLOCK_SIZE);
+
+       for (i = NUM_KEY_POWERS-2; i >= 0; i--) {
+               memcpy(tctx->key_powers[i], key, POLYVAL_BLOCK_SIZE);
+               internal_polyval_mul(tctx->key_powers[i],
+                                    tctx->key_powers[i+1]);
+       }
+
+       return 0;
+}
+
+static int polyval_x86_init(struct shash_desc *desc)
+{
+       struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);
+
+       memset(dctx, 0, sizeof(*dctx));
+
+       return 0;
+}
+
+static int polyval_x86_update(struct shash_desc *desc,
+                        const u8 *src, unsigned int srclen)
+{
+       struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);
+       const struct polyval_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm);
+       u8 *pos;
+       unsigned int nblocks;
+       unsigned int n;
+
+       if (dctx->bytes) {
+               n = min(srclen, dctx->bytes);
+               pos = dctx->buffer + POLYVAL_BLOCK_SIZE - dctx->bytes;
+
+               dctx->bytes -= n;
+               srclen -= n;
+
+               while (n--)
+                       *pos++ ^= *src++;
+
+               if (!dctx->bytes)
+                       internal_polyval_mul(dctx->buffer,
+                                           tctx->key_powers[NUM_KEY_POWERS-1]);
+       }
+
+       while (srclen >= POLYVAL_BLOCK_SIZE) {
+               /* Allow rescheduling every 4K bytes. */
+               nblocks = min(srclen, 4096U) / POLYVAL_BLOCK_SIZE;
+               internal_polyval_update(tctx, src, nblocks, dctx->buffer);
+               srclen -= nblocks * POLYVAL_BLOCK_SIZE;
+               src += nblocks * POLYVAL_BLOCK_SIZE;
+       }
+
+       if (srclen) {
+               dctx->bytes = POLYVAL_BLOCK_SIZE - srclen;
+               pos = dctx->buffer;
+               while (srclen--)
+                       *pos++ ^= *src++;
+       }
+
+       return 0;
+}
+
+static int polyval_x86_final(struct shash_desc *desc, u8 *dst)
+{
+       struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);
+       const struct polyval_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm);
+
+       if (dctx->bytes) {
+               internal_polyval_mul(dctx->buffer,
+                                    tctx->key_powers[NUM_KEY_POWERS-1]);
+       }
+
+       memcpy(dst, dctx->buffer, POLYVAL_BLOCK_SIZE);
+
+       return 0;
+}
+
+static struct shash_alg polyval_alg = {
+       .digestsize     = POLYVAL_DIGEST_SIZE,
+       .init           = polyval_x86_init,
+       .update         = polyval_x86_update,
+       .final          = polyval_x86_final,
+       .setkey         = polyval_x86_setkey,
+       .descsize       = sizeof(struct polyval_desc_ctx),
+       .base           = {
+               .cra_name               = "polyval",
+               .cra_driver_name        = "polyval-clmulni",
+               .cra_priority           = 200,
+               .cra_blocksize          = POLYVAL_BLOCK_SIZE,
+               .cra_ctxsize            = sizeof(struct polyval_tfm_ctx),
+               .cra_module             = THIS_MODULE,
+       },
+};
+
+__maybe_unused static const struct x86_cpu_id pcmul_cpu_id[] = {
+       X86_MATCH_FEATURE(X86_FEATURE_PCLMULQDQ, NULL),
+       {}
+};
+MODULE_DEVICE_TABLE(x86cpu, pcmul_cpu_id);
+
+static int __init polyval_clmulni_mod_init(void)
+{
+       if (!x86_match_cpu(pcmul_cpu_id))
+               return -ENODEV;
+
+       if (!boot_cpu_has(X86_FEATURE_AVX))
+               return -ENODEV;
+
+       return crypto_register_shash(&polyval_alg);
+}
+
+static void __exit polyval_clmulni_mod_exit(void)
+{
+       crypto_unregister_shash(&polyval_alg);
+}
+
+module_init(polyval_clmulni_mod_init);
+module_exit(polyval_clmulni_mod_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("POLYVAL hash function accelerated by PCLMULQDQ-NI");
+MODULE_ALIAS_CRYPTO("polyval");
+MODULE_ALIAS_CRYPTO("polyval-clmulni");
index 7fec5dc..eeadbd7 100644 (file)
@@ -11,7 +11,7 @@ CFLAGS_REMOVE_common.o                = $(CC_FLAGS_FTRACE)
 
 CFLAGS_common.o                        += -fno-stack-protector
 
-obj-y                          := entry_$(BITS).o thunk_$(BITS).o syscall_$(BITS).o
+obj-y                          := entry.o entry_$(BITS).o thunk_$(BITS).o syscall_$(BITS).o
 obj-y                          += common.o
 
 obj-y                          += vdso/
index 29b36e9..f690762 100644 (file)
@@ -7,6 +7,8 @@
 #include <asm/asm-offsets.h>
 #include <asm/processor-flags.h>
 #include <asm/ptrace-abi.h>
+#include <asm/msr.h>
+#include <asm/nospec-branch.h>
 
 /*
 
@@ -283,6 +285,66 @@ For 32-bit we have the following conventions - kernel is built with
 #endif
 
 /*
+ * IBRS kernel mitigation for Spectre_v2.
+ *
+ * Assumes full context is established (PUSH_REGS, CR3 and GS) and it clobbers
+ * the regs it uses (AX, CX, DX). Must be called before the first RET
+ * instruction (NOTE! UNTRAIN_RET includes a RET instruction)
+ *
+ * The optional argument is used to save/restore the current value,
+ * which is used on the paranoid paths.
+ *
+ * Assumes x86_spec_ctrl_{base,current} to have SPEC_CTRL_IBRS set.
+ */
+.macro IBRS_ENTER save_reg
+#ifdef CONFIG_CPU_IBRS_ENTRY
+       ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_KERNEL_IBRS
+       movl    $MSR_IA32_SPEC_CTRL, %ecx
+
+.ifnb \save_reg
+       rdmsr
+       shl     $32, %rdx
+       or      %rdx, %rax
+       mov     %rax, \save_reg
+       test    $SPEC_CTRL_IBRS, %eax
+       jz      .Ldo_wrmsr_\@
+       lfence
+       jmp     .Lend_\@
+.Ldo_wrmsr_\@:
+.endif
+
+       movq    PER_CPU_VAR(x86_spec_ctrl_current), %rdx
+       movl    %edx, %eax
+       shr     $32, %rdx
+       wrmsr
+.Lend_\@:
+#endif
+.endm
+
+/*
+ * Similar to IBRS_ENTER, requires KERNEL GS,CR3 and clobbers (AX, CX, DX)
+ * regs. Must be called after the last RET.
+ */
+.macro IBRS_EXIT save_reg
+#ifdef CONFIG_CPU_IBRS_ENTRY
+       ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_KERNEL_IBRS
+       movl    $MSR_IA32_SPEC_CTRL, %ecx
+
+.ifnb \save_reg
+       mov     \save_reg, %rdx
+.else
+       movq    PER_CPU_VAR(x86_spec_ctrl_current), %rdx
+       andl    $(~SPEC_CTRL_IBRS), %edx
+.endif
+
+       movl    %edx, %eax
+       shr     $32, %rdx
+       wrmsr
+.Lend_\@:
+#endif
+.endm
+
+/*
  * Mitigate Spectre v1 for conditional swapgs code paths.
  *
  * FENCE_SWAPGS_USER_ENTRY is used in the user entry swapgs code path, to
diff --git a/arch/x86/entry/entry.S b/arch/x86/entry/entry.S
new file mode 100644 (file)
index 0000000..bfb7bcb
--- /dev/null
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Common place for both 32- and 64-bit entry routines.
+ */
+
+#include <linux/linkage.h>
+#include <asm/export.h>
+#include <asm/msr-index.h>
+
+.pushsection .noinstr.text, "ax"
+
+SYM_FUNC_START(entry_ibpb)
+       movl    $MSR_IA32_PRED_CMD, %ecx
+       movl    $PRED_CMD_IBPB, %eax
+       xorl    %edx, %edx
+       wrmsr
+       RET
+SYM_FUNC_END(entry_ibpb)
+/* For KVM */
+EXPORT_SYMBOL_GPL(entry_ibpb);
+
+.popsection
index 8874208..e309e71 100644 (file)
@@ -698,7 +698,6 @@ SYM_CODE_START(__switch_to_asm)
        movl    %ebx, PER_CPU_VAR(__stack_chk_guard)
 #endif
 
-#ifdef CONFIG_RETPOLINE
        /*
         * When switching from a shallower to a deeper call stack
         * the RSB may either underflow or use entries populated
@@ -707,7 +706,6 @@ SYM_CODE_START(__switch_to_asm)
         * speculative execution to prevent attack.
         */
        FILL_RETURN_BUFFER %ebx, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW
-#endif
 
        /* Restore flags or the incoming task to restore AC state. */
        popfl
index 4300ba4..9953d96 100644 (file)
@@ -85,7 +85,7 @@
  */
 
 SYM_CODE_START(entry_SYSCALL_64)
-       UNWIND_HINT_EMPTY
+       UNWIND_HINT_ENTRY
        ENDBR
 
        swapgs
@@ -112,6 +112,11 @@ SYM_INNER_LABEL(entry_SYSCALL_64_after_hwframe, SYM_L_GLOBAL)
        movq    %rsp, %rdi
        /* Sign extend the lower 32bit as syscall numbers are treated as int */
        movslq  %eax, %rsi
+
+       /* clobbers %rax, make sure it is after saving the syscall nr */
+       IBRS_ENTER
+       UNTRAIN_RET
+
        call    do_syscall_64           /* returns with IRQs disabled */
 
        /*
@@ -191,6 +196,7 @@ SYM_INNER_LABEL(entry_SYSCALL_64_after_hwframe, SYM_L_GLOBAL)
         * perf profiles. Nothing jumps here.
         */
 syscall_return_via_sysret:
+       IBRS_EXIT
        POP_REGS pop_rdi=0
 
        /*
@@ -249,7 +255,6 @@ SYM_FUNC_START(__switch_to_asm)
        movq    %rbx, PER_CPU_VAR(fixed_percpu_data) + stack_canary_offset
 #endif
 
-#ifdef CONFIG_RETPOLINE
        /*
         * When switching from a shallower to a deeper call stack
         * the RSB may either underflow or use entries populated
@@ -258,7 +263,6 @@ SYM_FUNC_START(__switch_to_asm)
         * speculative execution to prevent attack.
         */
        FILL_RETURN_BUFFER %r12, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW
-#endif
 
        /* restore callee-saved registers */
        popq    %r15
@@ -322,13 +326,13 @@ SYM_CODE_END(ret_from_fork)
 #endif
 .endm
 
-/* Save all registers in pt_regs */
-SYM_CODE_START_LOCAL(push_and_clear_regs)
+SYM_CODE_START_LOCAL(xen_error_entry)
        UNWIND_HINT_FUNC
        PUSH_AND_CLEAR_REGS save_ret=1
        ENCODE_FRAME_POINTER 8
+       UNTRAIN_RET
        RET
-SYM_CODE_END(push_and_clear_regs)
+SYM_CODE_END(xen_error_entry)
 
 /**
  * idtentry_body - Macro to emit code calling the C function
@@ -337,9 +341,6 @@ SYM_CODE_END(push_and_clear_regs)
  */
 .macro idtentry_body cfunc has_error_code:req
 
-       call push_and_clear_regs
-       UNWIND_HINT_REGS
-
        /*
         * Call error_entry() and switch to the task stack if from userspace.
         *
@@ -349,7 +350,7 @@ SYM_CODE_END(push_and_clear_regs)
         * switch the CR3.  So it can skip invoking error_entry().
         */
        ALTERNATIVE "call error_entry; movq %rax, %rsp", \
-               "", X86_FEATURE_XENPV
+                   "call xen_error_entry", X86_FEATURE_XENPV
 
        ENCODE_FRAME_POINTER
        UNWIND_HINT_REGS
@@ -612,6 +613,7 @@ __irqentry_text_end:
 
 SYM_CODE_START_LOCAL(common_interrupt_return)
 SYM_INNER_LABEL(swapgs_restore_regs_and_return_to_usermode, SYM_L_GLOBAL)
+       IBRS_EXIT
 #ifdef CONFIG_DEBUG_ENTRY
        /* Assert that pt_regs indicates user mode. */
        testb   $3, CS(%rsp)
@@ -897,6 +899,9 @@ SYM_CODE_END(xen_failsafe_callback)
  *              1 -> no SWAPGS on exit
  *
  *     Y        GSBASE value at entry, must be restored in paranoid_exit
+ *
+ * R14 - old CR3
+ * R15 - old SPEC_CTRL
  */
 SYM_CODE_START_LOCAL(paranoid_entry)
        UNWIND_HINT_FUNC
@@ -940,7 +945,7 @@ SYM_CODE_START_LOCAL(paranoid_entry)
         * is needed here.
         */
        SAVE_AND_SET_GSBASE scratch_reg=%rax save_reg=%rbx
-       RET
+       jmp .Lparanoid_gsbase_done
 
 .Lparanoid_entry_checkgs:
        /* EBX = 1 -> kernel GSBASE active, no restore required */
@@ -959,8 +964,16 @@ SYM_CODE_START_LOCAL(paranoid_entry)
        xorl    %ebx, %ebx
        swapgs
 .Lparanoid_kernel_gsbase:
-
        FENCE_SWAPGS_KERNEL_ENTRY
+.Lparanoid_gsbase_done:
+
+       /*
+        * Once we have CR3 and %GS setup save and set SPEC_CTRL. Just like
+        * CR3 above, keep the old value in a callee saved register.
+        */
+       IBRS_ENTER save_reg=%r15
+       UNTRAIN_RET
+
        RET
 SYM_CODE_END(paranoid_entry)
 
@@ -982,9 +995,19 @@ SYM_CODE_END(paranoid_entry)
  *              1 -> no SWAPGS on exit
  *
  *     Y        User space GSBASE, must be restored unconditionally
+ *
+ * R14 - old CR3
+ * R15 - old SPEC_CTRL
  */
 SYM_CODE_START_LOCAL(paranoid_exit)
        UNWIND_HINT_REGS
+
+       /*
+        * Must restore IBRS state before both CR3 and %GS since we need access
+        * to the per-CPU x86_spec_ctrl_shadow variable.
+        */
+       IBRS_EXIT save_reg=%r15
+
        /*
         * The order of operations is important. RESTORE_CR3 requires
         * kernel GSBASE.
@@ -1017,6 +1040,10 @@ SYM_CODE_END(paranoid_exit)
  */
 SYM_CODE_START_LOCAL(error_entry)
        UNWIND_HINT_FUNC
+
+       PUSH_AND_CLEAR_REGS save_ret=1
+       ENCODE_FRAME_POINTER 8
+
        testb   $3, CS+8(%rsp)
        jz      .Lerror_kernelspace
 
@@ -1028,9 +1055,12 @@ SYM_CODE_START_LOCAL(error_entry)
        FENCE_SWAPGS_USER_ENTRY
        /* We have user CR3.  Change to kernel CR3. */
        SWITCH_TO_KERNEL_CR3 scratch_reg=%rax
+       IBRS_ENTER
+       UNTRAIN_RET
 
        leaq    8(%rsp), %rdi                   /* arg0 = pt_regs pointer */
 .Lerror_entry_from_usermode_after_swapgs:
+
        /* Put us onto the real thread stack. */
        call    sync_regs
        RET
@@ -1065,6 +1095,7 @@ SYM_CODE_START_LOCAL(error_entry)
 .Lerror_entry_done_lfence:
        FENCE_SWAPGS_KERNEL_ENTRY
        leaq    8(%rsp), %rax                   /* return pt_regs pointer */
+       ANNOTATE_UNRET_END
        RET
 
 .Lbstep_iret:
@@ -1080,6 +1111,8 @@ SYM_CODE_START_LOCAL(error_entry)
        swapgs
        FENCE_SWAPGS_USER_ENTRY
        SWITCH_TO_KERNEL_CR3 scratch_reg=%rax
+       IBRS_ENTER
+       UNTRAIN_RET
 
        /*
         * Pretend that the exception came from user mode: set up pt_regs
@@ -1185,6 +1218,9 @@ SYM_CODE_START(asm_exc_nmi)
        PUSH_AND_CLEAR_REGS rdx=(%rdx)
        ENCODE_FRAME_POINTER
 
+       IBRS_ENTER
+       UNTRAIN_RET
+
        /*
         * At this point we no longer need to worry about stack damage
         * due to nesting -- we're on the normal thread stack and we're
@@ -1409,6 +1445,9 @@ end_repeat_nmi:
        movq    $-1, %rsi
        call    exc_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
 
index d105274..682338e 100644 (file)
@@ -4,7 +4,6 @@
  *
  * Copyright 2000-2002 Andi Kleen, SuSE Labs.
  */
-#include "calling.h"
 #include <asm/asm-offsets.h>
 #include <asm/current.h>
 #include <asm/errno.h>
 #include <asm/irqflags.h>
 #include <asm/asm.h>
 #include <asm/smap.h>
+#include <asm/nospec-branch.h>
 #include <linux/linkage.h>
 #include <linux/err.h>
 
+#include "calling.h"
+
        .section .entry.text, "ax"
 
 /*
@@ -47,7 +49,7 @@
  * 0(%ebp) arg6
  */
 SYM_CODE_START(entry_SYSENTER_compat)
-       UNWIND_HINT_EMPTY
+       UNWIND_HINT_ENTRY
        ENDBR
        /* Interrupts are off on entry. */
        swapgs
@@ -88,6 +90,9 @@ SYM_INNER_LABEL(entry_SYSENTER_compat_after_hwframe, SYM_L_GLOBAL)
 
        cld
 
+       IBRS_ENTER
+       UNTRAIN_RET
+
        /*
         * SYSENTER doesn't filter flags, so we need to clear NT and AC
         * ourselves.  To save a few cycles, we can check whether
@@ -174,7 +179,7 @@ SYM_CODE_END(entry_SYSENTER_compat)
  * 0(%esp) arg6
  */
 SYM_CODE_START(entry_SYSCALL_compat)
-       UNWIND_HINT_EMPTY
+       UNWIND_HINT_ENTRY
        ENDBR
        /* Interrupts are off on entry. */
        swapgs
@@ -203,6 +208,9 @@ SYM_INNER_LABEL(entry_SYSCALL_compat_after_hwframe, SYM_L_GLOBAL)
        PUSH_AND_CLEAR_REGS rcx=%rbp rax=$-ENOSYS
        UNWIND_HINT_REGS
 
+       IBRS_ENTER
+       UNTRAIN_RET
+
        movq    %rsp, %rdi
        call    do_fast_syscall_32
        /* XEN PV guests always use IRET path */
@@ -217,6 +225,8 @@ sysret32_from_system_call:
         */
        STACKLEAK_ERASE
 
+       IBRS_EXIT
+
        movq    RBX(%rsp), %rbx         /* pt_regs->rbx */
        movq    RBP(%rsp), %rbp         /* pt_regs->rbp */
        movq    EFLAGS(%rsp), %r11      /* pt_regs->flags (in r11) */
@@ -295,7 +305,7 @@ SYM_CODE_END(entry_SYSCALL_compat)
  * ebp  arg6
  */
 SYM_CODE_START(entry_INT80_compat)
-       UNWIND_HINT_EMPTY
+       UNWIND_HINT_ENTRY
        ENDBR
        /*
         * Interrupts are off on entry.
@@ -337,6 +347,9 @@ SYM_CODE_START(entry_INT80_compat)
 
        cld
 
+       IBRS_ENTER
+       UNTRAIN_RET
+
        movq    %rsp, %rdi
        call    do_int80_syscall_32
        jmp     swapgs_restore_regs_and_return_to_usermode
index c2a8b76..76cd790 100644 (file)
@@ -92,6 +92,7 @@ endif
 endif
 
 $(vobjs): KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_LTO) $(RANDSTRUCT_CFLAGS) $(GCC_PLUGINS_CFLAGS) $(RETPOLINE_CFLAGS),$(KBUILD_CFLAGS)) $(CFL)
+$(vobjs): KBUILD_AFLAGS += -DBUILD_VDSO
 
 #
 # vDSO code runs in userspace and -pg doesn't help with profiling anyway.
index 15e3515..ef2dd18 100644 (file)
@@ -19,17 +19,20 @@ __vsyscall_page:
 
        mov $__NR_gettimeofday, %rax
        syscall
-       RET
+       ret
+       int3
 
        .balign 1024, 0xcc
        mov $__NR_time, %rax
        syscall
-       RET
+       ret
+       int3
 
        .balign 1024, 0xcc
        mov $__NR_getcpu, %rax
        syscall
-       RET
+       ret
+       int3
 
        .balign 4096, 0xcc
 
index 0d04414..d568afc 100644 (file)
@@ -21,7 +21,6 @@
 #define NUM_COUNTERS_NB                4
 #define NUM_COUNTERS_L2                4
 #define NUM_COUNTERS_L3                6
-#define MAX_COUNTERS           6
 
 #define RDPMC_BASE_NB          6
 #define RDPMC_BASE_LLC         10
@@ -31,6 +30,7 @@
 #undef pr_fmt
 #define pr_fmt(fmt)    "amd_uncore: " fmt
 
+static int pmu_version;
 static int num_counters_llc;
 static int num_counters_nb;
 static bool l3_mask;
@@ -46,7 +46,7 @@ struct amd_uncore {
        u32 msr_base;
        cpumask_t *active_mask;
        struct pmu *pmu;
-       struct perf_event *events[MAX_COUNTERS];
+       struct perf_event **events;
        struct hlist_node node;
 };
 
@@ -158,6 +158,16 @@ out:
        hwc->event_base_rdpmc = uncore->rdpmc_base + hwc->idx;
        hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
 
+       /*
+        * The first four DF counters are accessible via RDPMC index 6 to 9
+        * followed by the L3 counters from index 10 to 15. For processors
+        * with more than four DF counters, the DF RDPMC assignments become
+        * discontiguous as the additional counters are accessible starting
+        * from index 16.
+        */
+       if (is_nb_event(event) && hwc->idx >= NUM_COUNTERS_NB)
+               hwc->event_base_rdpmc += NUM_COUNTERS_L3;
+
        if (flags & PERF_EF_START)
                amd_uncore_start(event, PERF_EF_RELOAD);
 
@@ -209,10 +219,14 @@ static int amd_uncore_event_init(struct perf_event *event)
 {
        struct amd_uncore *uncore;
        struct hw_perf_event *hwc = &event->hw;
+       u64 event_mask = AMD64_RAW_EVENT_MASK_NB;
 
        if (event->attr.type != event->pmu->type)
                return -ENOENT;
 
+       if (pmu_version >= 2 && is_nb_event(event))
+               event_mask = AMD64_PERFMON_V2_RAW_EVENT_MASK_NB;
+
        /*
         * NB and Last level cache counters (MSRs) are shared across all cores
         * that share the same NB / Last level cache.  On family 16h and below,
@@ -221,7 +235,7 @@ static int amd_uncore_event_init(struct perf_event *event)
         * out. So we do not support sampling and per-thread events via
         * CAP_NO_INTERRUPT, and we do not enable counter overflow interrupts:
         */
-       hwc->config = event->attr.config & AMD64_RAW_EVENT_MASK_NB;
+       hwc->config = event->attr.config & event_mask;
        hwc->idx = -1;
 
        if (event->cpu < 0)
@@ -247,6 +261,19 @@ static int amd_uncore_event_init(struct perf_event *event)
        return 0;
 }
 
+static umode_t
+amd_f17h_uncore_is_visible(struct kobject *kobj, struct attribute *attr, int i)
+{
+       return boot_cpu_data.x86 >= 0x17 && boot_cpu_data.x86 < 0x19 ?
+              attr->mode : 0;
+}
+
+static umode_t
+amd_f19h_uncore_is_visible(struct kobject *kobj, struct attribute *attr, int i)
+{
+       return boot_cpu_data.x86 >= 0x19 ? attr->mode : 0;
+}
+
 static ssize_t amd_uncore_attr_show_cpumask(struct device *dev,
                                            struct device_attribute *attr,
                                            char *buf)
@@ -287,8 +314,10 @@ static struct device_attribute format_attr_##_var =                        \
 
 DEFINE_UNCORE_FORMAT_ATTR(event12,     event,          "config:0-7,32-35");
 DEFINE_UNCORE_FORMAT_ATTR(event14,     event,          "config:0-7,32-35,59-60"); /* F17h+ DF */
+DEFINE_UNCORE_FORMAT_ATTR(event14v2,   event,          "config:0-7,32-37");       /* PerfMonV2 DF */
 DEFINE_UNCORE_FORMAT_ATTR(event8,      event,          "config:0-7");             /* F17h+ L3 */
-DEFINE_UNCORE_FORMAT_ATTR(umask,       umask,          "config:8-15");
+DEFINE_UNCORE_FORMAT_ATTR(umask8,      umask,          "config:8-15");
+DEFINE_UNCORE_FORMAT_ATTR(umask12,     umask,          "config:8-15,24-27");      /* PerfMonV2 DF */
 DEFINE_UNCORE_FORMAT_ATTR(coreid,      coreid,         "config:42-44");           /* F19h L3 */
 DEFINE_UNCORE_FORMAT_ATTR(slicemask,   slicemask,      "config:48-51");           /* F17h L3 */
 DEFINE_UNCORE_FORMAT_ATTR(threadmask8, threadmask,     "config:56-63");           /* F17h L3 */
@@ -297,20 +326,33 @@ DEFINE_UNCORE_FORMAT_ATTR(enallslices,    enallslices,    "config:46");              /* F19h L3
 DEFINE_UNCORE_FORMAT_ATTR(enallcores,  enallcores,     "config:47");              /* F19h L3 */
 DEFINE_UNCORE_FORMAT_ATTR(sliceid,     sliceid,        "config:48-50");           /* F19h L3 */
 
+/* Common DF and NB attributes */
 static struct attribute *amd_uncore_df_format_attr[] = {
-       &format_attr_event12.attr, /* event14 if F17h+ */
-       &format_attr_umask.attr,
+       &format_attr_event12.attr,      /* event */
+       &format_attr_umask8.attr,       /* umask */
        NULL,
 };
 
+/* Common L2 and L3 attributes */
 static struct attribute *amd_uncore_l3_format_attr[] = {
-       &format_attr_event12.attr, /* event8 if F17h+ */
-       &format_attr_umask.attr,
-       NULL, /* slicemask if F17h,     coreid if F19h */
-       NULL, /* threadmask8 if F17h,   enallslices if F19h */
-       NULL, /*                        enallcores if F19h */
-       NULL, /*                        sliceid if F19h */
-       NULL, /*                        threadmask2 if F19h */
+       &format_attr_event12.attr,      /* event */
+       &format_attr_umask8.attr,       /* umask */
+       NULL,                           /* threadmask */
+       NULL,
+};
+
+/* F17h unique L3 attributes */
+static struct attribute *amd_f17h_uncore_l3_format_attr[] = {
+       &format_attr_slicemask.attr,    /* slicemask */
+       NULL,
+};
+
+/* F19h unique L3 attributes */
+static struct attribute *amd_f19h_uncore_l3_format_attr[] = {
+       &format_attr_coreid.attr,       /* coreid */
+       &format_attr_enallslices.attr,  /* enallslices */
+       &format_attr_enallcores.attr,   /* enallcores */
+       &format_attr_sliceid.attr,      /* sliceid */
        NULL,
 };
 
@@ -324,6 +366,18 @@ static struct attribute_group amd_uncore_l3_format_group = {
        .attrs = amd_uncore_l3_format_attr,
 };
 
+static struct attribute_group amd_f17h_uncore_l3_format_group = {
+       .name = "format",
+       .attrs = amd_f17h_uncore_l3_format_attr,
+       .is_visible = amd_f17h_uncore_is_visible,
+};
+
+static struct attribute_group amd_f19h_uncore_l3_format_group = {
+       .name = "format",
+       .attrs = amd_f19h_uncore_l3_format_attr,
+       .is_visible = amd_f19h_uncore_is_visible,
+};
+
 static const struct attribute_group *amd_uncore_df_attr_groups[] = {
        &amd_uncore_attr_group,
        &amd_uncore_df_format_group,
@@ -336,6 +390,12 @@ static const struct attribute_group *amd_uncore_l3_attr_groups[] = {
        NULL,
 };
 
+static const struct attribute_group *amd_uncore_l3_attr_update[] = {
+       &amd_f17h_uncore_l3_format_group,
+       &amd_f19h_uncore_l3_format_group,
+       NULL,
+};
+
 static struct pmu amd_nb_pmu = {
        .task_ctx_nr    = perf_invalid_context,
        .attr_groups    = amd_uncore_df_attr_groups,
@@ -353,6 +413,7 @@ static struct pmu amd_nb_pmu = {
 static struct pmu amd_llc_pmu = {
        .task_ctx_nr    = perf_invalid_context,
        .attr_groups    = amd_uncore_l3_attr_groups,
+       .attr_update    = amd_uncore_l3_attr_update,
        .name           = "amd_l2",
        .event_init     = amd_uncore_event_init,
        .add            = amd_uncore_add,
@@ -370,11 +431,19 @@ static struct amd_uncore *amd_uncore_alloc(unsigned int cpu)
                        cpu_to_node(cpu));
 }
 
+static inline struct perf_event **
+amd_uncore_events_alloc(unsigned int num, unsigned int cpu)
+{
+       return kzalloc_node(sizeof(struct perf_event *) * num, GFP_KERNEL,
+                           cpu_to_node(cpu));
+}
+
 static int amd_uncore_cpu_up_prepare(unsigned int cpu)
 {
-       struct amd_uncore *uncore_nb = NULL, *uncore_llc;
+       struct amd_uncore *uncore_nb = NULL, *uncore_llc = NULL;
 
        if (amd_uncore_nb) {
+               *per_cpu_ptr(amd_uncore_nb, cpu) = NULL;
                uncore_nb = amd_uncore_alloc(cpu);
                if (!uncore_nb)
                        goto fail;
@@ -384,11 +453,15 @@ static int amd_uncore_cpu_up_prepare(unsigned int cpu)
                uncore_nb->msr_base = MSR_F15H_NB_PERF_CTL;
                uncore_nb->active_mask = &amd_nb_active_mask;
                uncore_nb->pmu = &amd_nb_pmu;
+               uncore_nb->events = amd_uncore_events_alloc(num_counters_nb, cpu);
+               if (!uncore_nb->events)
+                       goto fail;
                uncore_nb->id = -1;
                *per_cpu_ptr(amd_uncore_nb, cpu) = uncore_nb;
        }
 
        if (amd_uncore_llc) {
+               *per_cpu_ptr(amd_uncore_llc, cpu) = NULL;
                uncore_llc = amd_uncore_alloc(cpu);
                if (!uncore_llc)
                        goto fail;
@@ -398,6 +471,9 @@ static int amd_uncore_cpu_up_prepare(unsigned int cpu)
                uncore_llc->msr_base = MSR_F16H_L2I_PERF_CTL;
                uncore_llc->active_mask = &amd_llc_active_mask;
                uncore_llc->pmu = &amd_llc_pmu;
+               uncore_llc->events = amd_uncore_events_alloc(num_counters_llc, cpu);
+               if (!uncore_llc->events)
+                       goto fail;
                uncore_llc->id = -1;
                *per_cpu_ptr(amd_uncore_llc, cpu) = uncore_llc;
        }
@@ -405,9 +481,16 @@ static int amd_uncore_cpu_up_prepare(unsigned int cpu)
        return 0;
 
 fail:
-       if (amd_uncore_nb)
-               *per_cpu_ptr(amd_uncore_nb, cpu) = NULL;
-       kfree(uncore_nb);
+       if (uncore_nb) {
+               kfree(uncore_nb->events);
+               kfree(uncore_nb);
+       }
+
+       if (uncore_llc) {
+               kfree(uncore_llc->events);
+               kfree(uncore_llc);
+       }
+
        return -ENOMEM;
 }
 
@@ -540,8 +623,11 @@ static void uncore_dead(unsigned int cpu, struct amd_uncore * __percpu *uncores)
        if (cpu == uncore->cpu)
                cpumask_clear_cpu(cpu, uncore->active_mask);
 
-       if (!--uncore->refcnt)
+       if (!--uncore->refcnt) {
+               kfree(uncore->events);
                kfree(uncore);
+       }
+
        *per_cpu_ptr(uncores, cpu) = NULL;
 }
 
@@ -560,6 +646,7 @@ static int __init amd_uncore_init(void)
 {
        struct attribute **df_attr = amd_uncore_df_format_attr;
        struct attribute **l3_attr = amd_uncore_l3_format_attr;
+       union cpuid_0x80000022_ebx ebx;
        int ret = -ENODEV;
 
        if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD &&
@@ -569,6 +656,9 @@ static int __init amd_uncore_init(void)
        if (!boot_cpu_has(X86_FEATURE_TOPOEXT))
                return -ENODEV;
 
+       if (boot_cpu_has(X86_FEATURE_PERFMON_V2))
+               pmu_version = 2;
+
        num_counters_nb = NUM_COUNTERS_NB;
        num_counters_llc = NUM_COUNTERS_L2;
        if (boot_cpu_data.x86 >= 0x17) {
@@ -585,8 +675,12 @@ static int __init amd_uncore_init(void)
        }
 
        if (boot_cpu_has(X86_FEATURE_PERFCTR_NB)) {
-               if (boot_cpu_data.x86 >= 0x17)
+               if (pmu_version >= 2) {
+                       *df_attr++ = &format_attr_event14v2.attr;
+                       *df_attr++ = &format_attr_umask12.attr;
+               } else if (boot_cpu_data.x86 >= 0x17) {
                        *df_attr = &format_attr_event14.attr;
+               }
 
                amd_uncore_nb = alloc_percpu(struct amd_uncore *);
                if (!amd_uncore_nb) {
@@ -597,6 +691,11 @@ static int __init amd_uncore_init(void)
                if (ret)
                        goto fail_nb;
 
+               if (pmu_version >= 2) {
+                       ebx.full = cpuid_ebx(EXT_PERFMON_DEBUG_FEATURES);
+                       num_counters_nb = ebx.split.num_df_pmc;
+               }
+
                pr_info("%d %s %s counters detected\n", num_counters_nb,
                        boot_cpu_data.x86_vendor == X86_VENDOR_HYGON ?  "HYGON" : "",
                        amd_nb_pmu.name);
@@ -607,16 +706,11 @@ static int __init amd_uncore_init(void)
        if (boot_cpu_has(X86_FEATURE_PERFCTR_LLC)) {
                if (boot_cpu_data.x86 >= 0x19) {
                        *l3_attr++ = &format_attr_event8.attr;
-                       *l3_attr++ = &format_attr_umask.attr;
-                       *l3_attr++ = &format_attr_coreid.attr;
-                       *l3_attr++ = &format_attr_enallslices.attr;
-                       *l3_attr++ = &format_attr_enallcores.attr;
-                       *l3_attr++ = &format_attr_sliceid.attr;
+                       *l3_attr++ = &format_attr_umask8.attr;
                        *l3_attr++ = &format_attr_threadmask2.attr;
                } else if (boot_cpu_data.x86 >= 0x17) {
                        *l3_attr++ = &format_attr_event8.attr;
-                       *l3_attr++ = &format_attr_umask.attr;
-                       *l3_attr++ = &format_attr_slicemask.attr;
+                       *l3_attr++ = &format_attr_umask8.attr;
                        *l3_attr++ = &format_attr_threadmask8.attr;
                }
 
index 45024ab..bd8b988 100644 (file)
@@ -4141,6 +4141,8 @@ tnt_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
 {
        struct event_constraint *c;
 
+       c = intel_get_event_constraints(cpuc, idx, event);
+
        /*
         * :ppp means to do reduced skid PEBS,
         * which is available on PMC0 and fixed counter 0.
@@ -4153,8 +4155,6 @@ tnt_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
                return &counter0_constraint;
        }
 
-       c = intel_get_event_constraints(cpuc, idx, event);
-
        return c;
 }
 
@@ -6241,7 +6241,8 @@ __init int intel_pmu_init(void)
                x86_pmu.flags |= PMU_FL_INSTR_LATENCY;
                x86_pmu.flags |= PMU_FL_MEM_LOADS_AUX;
                x86_pmu.lbr_pt_coexist = true;
-               intel_pmu_pebs_data_source_skl(false);
+               intel_pmu_pebs_data_source_adl();
+               x86_pmu.pebs_latency_data = adl_latency_data_small;
                x86_pmu.num_topdown_events = 8;
                x86_pmu.update_topdown_event = adl_update_topdown_event;
                x86_pmu.set_topdown_event_period = adl_set_topdown_event_period;
index 376cc3d..ba60427 100644 (file)
@@ -94,15 +94,40 @@ void __init intel_pmu_pebs_data_source_nhm(void)
        pebs_data_source[0x07] = OP_LH | P(LVL, L3) | LEVEL(L3) | P(SNOOP, HITM);
 }
 
-void __init intel_pmu_pebs_data_source_skl(bool pmem)
+static void __init __intel_pmu_pebs_data_source_skl(bool pmem, u64 *data_source)
 {
        u64 pmem_or_l4 = pmem ? LEVEL(PMEM) : LEVEL(L4);
 
-       pebs_data_source[0x08] = OP_LH | pmem_or_l4 | P(SNOOP, HIT);
-       pebs_data_source[0x09] = OP_LH | pmem_or_l4 | REM | P(SNOOP, HIT);
-       pebs_data_source[0x0b] = OP_LH | LEVEL(RAM) | REM | P(SNOOP, NONE);
-       pebs_data_source[0x0c] = OP_LH | LEVEL(ANY_CACHE) | REM | P(SNOOPX, FWD);
-       pebs_data_source[0x0d] = OP_LH | LEVEL(ANY_CACHE) | REM | P(SNOOP, HITM);
+       data_source[0x08] = OP_LH | pmem_or_l4 | P(SNOOP, HIT);
+       data_source[0x09] = OP_LH | pmem_or_l4 | REM | P(SNOOP, HIT);
+       data_source[0x0b] = OP_LH | LEVEL(RAM) | REM | P(SNOOP, NONE);
+       data_source[0x0c] = OP_LH | LEVEL(ANY_CACHE) | REM | P(SNOOPX, FWD);
+       data_source[0x0d] = OP_LH | LEVEL(ANY_CACHE) | REM | P(SNOOP, HITM);
+}
+
+void __init intel_pmu_pebs_data_source_skl(bool pmem)
+{
+       __intel_pmu_pebs_data_source_skl(pmem, pebs_data_source);
+}
+
+static void __init intel_pmu_pebs_data_source_grt(u64 *data_source)
+{
+       data_source[0x05] = OP_LH | P(LVL, L3) | LEVEL(L3) | P(SNOOP, HIT);
+       data_source[0x06] = OP_LH | P(LVL, L3) | LEVEL(L3) | P(SNOOP, HITM);
+       data_source[0x08] = OP_LH | P(LVL, L3) | LEVEL(L3) | P(SNOOPX, FWD);
+}
+
+void __init intel_pmu_pebs_data_source_adl(void)
+{
+       u64 *data_source;
+
+       data_source = x86_pmu.hybrid_pmu[X86_HYBRID_PMU_CORE_IDX].pebs_data_source;
+       memcpy(data_source, pebs_data_source, sizeof(pebs_data_source));
+       __intel_pmu_pebs_data_source_skl(false, data_source);
+
+       data_source = x86_pmu.hybrid_pmu[X86_HYBRID_PMU_ATOM_IDX].pebs_data_source;
+       memcpy(data_source, pebs_data_source, sizeof(pebs_data_source));
+       intel_pmu_pebs_data_source_grt(data_source);
 }
 
 static u64 precise_store_data(u64 status)
@@ -171,7 +196,50 @@ static u64 precise_datala_hsw(struct perf_event *event, u64 status)
        return dse.val;
 }
 
-static u64 load_latency_data(u64 status)
+static inline void pebs_set_tlb_lock(u64 *val, bool tlb, bool lock)
+{
+       /*
+        * TLB access
+        * 0 = did not miss 2nd level TLB
+        * 1 = missed 2nd level TLB
+        */
+       if (tlb)
+               *val |= P(TLB, MISS) | P(TLB, L2);
+       else
+               *val |= P(TLB, HIT) | P(TLB, L1) | P(TLB, L2);
+
+       /* locked prefix */
+       if (lock)
+               *val |= P(LOCK, LOCKED);
+}
+
+/* Retrieve the latency data for e-core of ADL */
+u64 adl_latency_data_small(struct perf_event *event, u64 status)
+{
+       union intel_x86_pebs_dse dse;
+       u64 val;
+
+       WARN_ON_ONCE(hybrid_pmu(event->pmu)->cpu_type == hybrid_big);
+
+       dse.val = status;
+
+       val = hybrid_var(event->pmu, pebs_data_source)[dse.ld_dse];
+
+       /*
+        * For the atom core on ADL,
+        * bit 4: lock, bit 5: TLB access.
+        */
+       pebs_set_tlb_lock(&val, dse.ld_locked, dse.ld_stlb_miss);
+
+       if (dse.ld_data_blk)
+               val |= P(BLK, DATA);
+       else
+               val |= P(BLK, NA);
+
+       return val;
+}
+
+static u64 load_latency_data(struct perf_event *event, u64 status)
 {
        union intel_x86_pebs_dse dse;
        u64 val;
@@ -181,7 +249,7 @@ static u64 load_latency_data(u64 status)
        /*
         * use the mapping table for bit 0-3
         */
-       val = pebs_data_source[dse.ld_dse];
+       val = hybrid_var(event->pmu, pebs_data_source)[dse.ld_dse];
 
        /*
         * Nehalem models do not support TLB, Lock infos
@@ -190,21 +258,8 @@ static u64 load_latency_data(u64 status)
                val |= P(TLB, NA) | P(LOCK, NA);
                return val;
        }
-       /*
-        * bit 4: TLB access
-        * 0 = did not miss 2nd level TLB
-        * 1 = missed 2nd level TLB
-        */
-       if (dse.ld_stlb_miss)
-               val |= P(TLB, MISS) | P(TLB, L2);
-       else
-               val |= P(TLB, HIT) | P(TLB, L1) | P(TLB, L2);
 
-       /*
-        * bit 5: locked prefix
-        */
-       if (dse.ld_locked)
-               val |= P(LOCK, LOCKED);
+       pebs_set_tlb_lock(&val, dse.ld_stlb_miss, dse.ld_locked);
 
        /*
         * Ice Lake and earlier models do not support block infos.
@@ -233,7 +288,7 @@ static u64 load_latency_data(u64 status)
        return val;
 }
 
-static u64 store_latency_data(u64 status)
+static u64 store_latency_data(struct perf_event *event, u64 status)
 {
        union intel_x86_pebs_dse dse;
        u64 val;
@@ -243,23 +298,9 @@ static u64 store_latency_data(u64 status)
        /*
         * use the mapping table for bit 0-3
         */
-       val = pebs_data_source[dse.st_lat_dse];
+       val = hybrid_var(event->pmu, pebs_data_source)[dse.st_lat_dse];
 
-       /*
-        * bit 4: TLB access
-        * 0 = did not miss 2nd level TLB
-        * 1 = missed 2nd level TLB
-        */
-       if (dse.st_lat_stlb_miss)
-               val |= P(TLB, MISS) | P(TLB, L2);
-       else
-               val |= P(TLB, HIT) | P(TLB, L1) | P(TLB, L2);
-
-       /*
-        * bit 5: locked prefix
-        */
-       if (dse.st_lat_locked)
-               val |= P(LOCK, LOCKED);
+       pebs_set_tlb_lock(&val, dse.st_lat_stlb_miss, dse.st_lat_locked);
 
        val |= P(BLK, NA);
 
@@ -781,8 +822,8 @@ struct event_constraint intel_glm_pebs_event_constraints[] = {
 
 struct event_constraint intel_grt_pebs_event_constraints[] = {
        /* Allow all events as PEBS with no flags */
-       INTEL_PLD_CONSTRAINT(0x5d0, 0xf),
-       INTEL_PSD_CONSTRAINT(0x6d0, 0xf),
+       INTEL_HYBRID_LAT_CONSTRAINT(0x5d0, 0xf),
+       INTEL_HYBRID_LAT_CONSTRAINT(0x6d0, 0xf),
        EVENT_CONSTRAINT_END
 };
 
@@ -1443,9 +1484,11 @@ static u64 get_data_src(struct perf_event *event, u64 aux)
        bool fst = fl & (PERF_X86_EVENT_PEBS_ST | PERF_X86_EVENT_PEBS_HSW_PREC);
 
        if (fl & PERF_X86_EVENT_PEBS_LDLAT)
-               val = load_latency_data(aux);
+               val = load_latency_data(event, aux);
        else if (fl & PERF_X86_EVENT_PEBS_STLAT)
-               val = store_latency_data(aux);
+               val = store_latency_data(event, aux);
+       else if (fl & PERF_X86_EVENT_PEBS_LAT_HYBRID)
+               val = x86_pmu.pebs_latency_data(event, aux);
        else if (fst && (fl & PERF_X86_EVENT_PEBS_HSW_PREC))
                val = precise_datala_hsw(event, aux);
        else if (fst)
index 13179f3..4f70fb6 100644 (file)
@@ -278,9 +278,9 @@ enum {
 };
 
 /*
- * For formats with LBR_TSX flags (e.g. LBR_FORMAT_EIP_FLAGS2), bits 61:62 in
- * MSR_LAST_BRANCH_FROM_x are the TSX flags when TSX is supported, but when
- * TSX is not supported they have no consistent behavior:
+ * For format LBR_FORMAT_EIP_FLAGS2, bits 61:62 in MSR_LAST_BRANCH_FROM_x
+ * are the TSX flags when TSX is supported, but when TSX is not supported
+ * they have no consistent behavior:
  *
  *   - For wrmsr(), bits 61:62 are considered part of the sign extension.
  *   - For HW updates (branch captures) bits 61:62 are always OFF and are not
@@ -288,7 +288,7 @@ enum {
  *
  * Therefore, if:
  *
- *   1) LBR has TSX format
+ *   1) LBR format LBR_FORMAT_EIP_FLAGS2
  *   2) CPU has no TSX support enabled
  *
  * ... then any value passed to wrmsr() must be sign extended to 63 bits and any
@@ -300,7 +300,7 @@ static inline bool lbr_from_signext_quirk_needed(void)
        bool tsx_support = boot_cpu_has(X86_FEATURE_HLE) ||
                           boot_cpu_has(X86_FEATURE_RTM);
 
-       return !tsx_support && x86_pmu.lbr_has_tsx;
+       return !tsx_support;
 }
 
 static DEFINE_STATIC_KEY_FALSE(lbr_from_quirk_key);
@@ -1609,9 +1609,6 @@ void intel_pmu_lbr_init_hsw(void)
        x86_pmu.lbr_sel_map  = hsw_lbr_sel_map;
 
        x86_get_pmu(smp_processor_id())->task_ctx_cache = create_lbr_kmem_cache(size, 0);
-
-       if (lbr_from_signext_quirk_needed())
-               static_branch_enable(&lbr_from_quirk_key);
 }
 
 /* skylake */
@@ -1702,7 +1699,11 @@ void intel_pmu_lbr_init(void)
        switch (x86_pmu.intel_cap.lbr_format) {
        case LBR_FORMAT_EIP_FLAGS2:
                x86_pmu.lbr_has_tsx = 1;
-               fallthrough;
+               x86_pmu.lbr_from_flags = 1;
+               if (lbr_from_signext_quirk_needed())
+                       static_branch_enable(&lbr_from_quirk_key);
+               break;
+
        case LBR_FORMAT_EIP_FLAGS:
                x86_pmu.lbr_from_flags = 1;
                break;
index 21a5482..ca2f8bf 100644 (file)
@@ -84,6 +84,7 @@ static inline bool constraint_match(struct event_constraint *c, u64 ecode)
 #define PERF_X86_EVENT_TOPDOWN         0x04000 /* Count Topdown slots/metrics events */
 #define PERF_X86_EVENT_PEBS_STLAT      0x08000 /* st+stlat data address sampling */
 #define PERF_X86_EVENT_AMD_BRS         0x10000 /* AMD Branch Sampling */
+#define PERF_X86_EVENT_PEBS_LAT_HYBRID 0x20000 /* ld and st lat for hybrid */
 
 static inline bool is_topdown_count(struct perf_event *event)
 {
@@ -136,7 +137,8 @@ struct amd_nb {
        PERF_SAMPLE_DATA_SRC | PERF_SAMPLE_IDENTIFIER | \
        PERF_SAMPLE_TRANSACTION | PERF_SAMPLE_PHYS_ADDR | \
        PERF_SAMPLE_REGS_INTR | PERF_SAMPLE_REGS_USER | \
-       PERF_SAMPLE_PERIOD | PERF_SAMPLE_CODE_PAGE_SIZE)
+       PERF_SAMPLE_PERIOD | PERF_SAMPLE_CODE_PAGE_SIZE | \
+       PERF_SAMPLE_WEIGHT_TYPE)
 
 #define PEBS_GP_REGS                   \
        ((1ULL << PERF_REG_X86_AX)    | \
@@ -460,6 +462,10 @@ struct cpu_hw_events {
        __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \
                          HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_ST)
 
+#define INTEL_HYBRID_LAT_CONSTRAINT(c, n)      \
+       __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \
+                         HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LAT_HYBRID)
+
 /* Event constraint, but match on all event flags too. */
 #define INTEL_FLAGS_EVENT_CONSTRAINT(c, n) \
        EVENT_CONSTRAINT(c, n, ARCH_PERFMON_EVENTSEL_EVENT|X86_ALL_EVENT_FLAGS)
@@ -638,6 +644,8 @@ enum {
        x86_lbr_exclusive_max,
 };
 
+#define PERF_PEBS_DATA_SOURCE_MAX      0x10
+
 struct x86_hybrid_pmu {
        struct pmu                      pmu;
        const char                      *name;
@@ -665,6 +673,8 @@ struct x86_hybrid_pmu {
        unsigned int                    late_ack        :1,
                                        mid_ack         :1,
                                        enabled_ack     :1;
+
+       u64                             pebs_data_source[PERF_PEBS_DATA_SOURCE_MAX];
 };
 
 static __always_inline struct x86_hybrid_pmu *hybrid_pmu(struct pmu *pmu)
@@ -825,6 +835,7 @@ struct x86_pmu {
        void            (*drain_pebs)(struct pt_regs *regs, struct perf_sample_data *data);
        struct event_constraint *pebs_constraints;
        void            (*pebs_aliases)(struct perf_event *event);
+       u64             (*pebs_latency_data)(struct perf_event *event, u64 status);
        unsigned long   large_pebs_flags;
        u64             rtm_abort_event;
 
@@ -1392,6 +1403,8 @@ void intel_pmu_disable_bts(void);
 
 int intel_pmu_drain_bts_buffer(void);
 
+u64 adl_latency_data_small(struct perf_event *event, u64 status);
+
 extern struct event_constraint intel_core2_pebs_event_constraints[];
 
 extern struct event_constraint intel_atom_pebs_event_constraints[];
@@ -1499,6 +1512,8 @@ void intel_pmu_pebs_data_source_nhm(void);
 
 void intel_pmu_pebs_data_source_skl(bool pmem);
 
+void intel_pmu_pebs_data_source_adl(void);
+
 int intel_pmu_setup_lbr_filter(struct perf_event *event);
 
 void intel_pt_interrupt(void);
index 7e0f6be..42c70d2 100644 (file)
@@ -192,7 +192,7 @@ static void hv_irq_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
        struct pci_dev *dev;
        struct hv_interrupt_entry out_entry, *stored_entry;
        struct irq_cfg *cfg = irqd_cfg(data);
-       cpumask_t *affinity;
+       const cpumask_t *affinity;
        int cpu;
        u64 status;
 
index 9b10c8c..9542c58 100644 (file)
@@ -76,6 +76,7 @@ extern int alternatives_patched;
 extern void alternative_instructions(void);
 extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
 extern void apply_retpolines(s32 *start, s32 *end);
+extern void apply_returns(s32 *start, s32 *end);
 extern void apply_ibt_endbr(s32 *start, s32 *end);
 
 struct module;
index aabdbb5..f3eb098 100644 (file)
@@ -29,7 +29,10 @@ union ibs_fetch_ctl {
                        rand_en:1,      /* 57: random tagging enable */
                        fetch_l2_miss:1,/* 58: L2 miss for sampled fetch
                                         *      (needs IbsFetchComp) */
-                       reserved:5;     /* 59-63: reserved */
+                       l3_miss_only:1, /* 59: Collect L3 miss samples only */
+                       fetch_oc_miss:1,/* 60: Op cache miss for the sampled fetch */
+                       fetch_l3_miss:1,/* 61: L3 cache miss for the sampled fetch */
+                       reserved:2;     /* 62-63: reserved */
        };
 };
 
@@ -38,14 +41,14 @@ union ibs_op_ctl {
        __u64 val;
        struct {
                __u64   opmaxcnt:16,    /* 0-15: periodic op max. count */
-                       reserved0:1,    /* 16: reserved */
+                       l3_miss_only:1, /* 16: Collect L3 miss samples only */
                        op_en:1,        /* 17: op sampling enable */
                        op_val:1,       /* 18: op sample valid */
                        cnt_ctl:1,      /* 19: periodic op counter control */
                        opmaxcnt_ext:7, /* 20-26: upper 7 bits of periodic op maximum count */
-                       reserved1:5,    /* 27-31: reserved */
+                       reserved0:5,    /* 27-31: reserved */
                        opcurcnt:27,    /* 32-58: periodic op counter current count */
-                       reserved2:5;    /* 59-63: reserved */
+                       reserved1:5;    /* 59-63: reserved */
        };
 };
 
@@ -71,11 +74,12 @@ union ibs_op_data {
 union ibs_op_data2 {
        __u64 val;
        struct {
-               __u64   data_src:3,     /* 0-2: data source */
+               __u64   data_src_lo:3,  /* 0-2: data source low */
                        reserved0:1,    /* 3: reserved */
                        rmt_node:1,     /* 4: destination node */
                        cache_hit_st:1, /* 5: cache hit state */
-                       reserved1:57;   /* 5-63: reserved */
+                       data_src_hi:2,  /* 6-7: data source high */
+                       reserved1:56;   /* 8-63: reserved */
        };
 };
 
index ebc248e..02bae8e 100644 (file)
@@ -31,20 +31,6 @@ static inline bool __must_check rdrand_long(unsigned long *v)
        return false;
 }
 
-static inline bool __must_check rdrand_int(unsigned int *v)
-{
-       bool ok;
-       unsigned int retry = RDRAND_RETRY_LOOPS;
-       do {
-               asm volatile("rdrand %[out]"
-                            CC_SET(c)
-                            : CC_OUT(c) (ok), [out] "=r" (*v));
-               if (ok)
-                       return true;
-       } while (--retry);
-       return false;
-}
-
 static inline bool __must_check rdseed_long(unsigned long *v)
 {
        bool ok;
@@ -54,48 +40,23 @@ static inline bool __must_check rdseed_long(unsigned long *v)
        return ok;
 }
 
-static inline bool __must_check rdseed_int(unsigned int *v)
-{
-       bool ok;
-       asm volatile("rdseed %[out]"
-                    CC_SET(c)
-                    : CC_OUT(c) (ok), [out] "=r" (*v));
-       return ok;
-}
-
 /*
  * These are the generic interfaces; they must not be declared if the
- * stubs in <linux/random.h> are to be invoked,
- * i.e. CONFIG_ARCH_RANDOM is not defined.
+ * stubs in <linux/random.h> are to be invoked.
  */
-#ifdef CONFIG_ARCH_RANDOM
 
-static inline bool __must_check arch_get_random_long(unsigned long *v)
+static inline size_t __must_check arch_get_random_longs(unsigned long *v, size_t max_longs)
 {
-       return static_cpu_has(X86_FEATURE_RDRAND) ? rdrand_long(v) : false;
+       return max_longs && static_cpu_has(X86_FEATURE_RDRAND) && rdrand_long(v) ? 1 : 0;
 }
 
-static inline bool __must_check arch_get_random_int(unsigned int *v)
+static inline size_t __must_check arch_get_random_seed_longs(unsigned long *v, size_t max_longs)
 {
-       return static_cpu_has(X86_FEATURE_RDRAND) ? rdrand_int(v) : false;
+       return max_longs && static_cpu_has(X86_FEATURE_RDSEED) && rdseed_long(v) ? 1 : 0;
 }
 
-static inline bool __must_check arch_get_random_seed_long(unsigned long *v)
-{
-       return static_cpu_has(X86_FEATURE_RDSEED) ? rdseed_long(v) : false;
-}
-
-static inline bool __must_check arch_get_random_seed_int(unsigned int *v)
-{
-       return static_cpu_has(X86_FEATURE_RDSEED) ? rdseed_int(v) : false;
-}
-
-extern void x86_init_rdrand(struct cpuinfo_x86 *c);
-
-#else  /* !CONFIG_ARCH_RANDOM */
-
-static inline void x86_init_rdrand(struct cpuinfo_x86 *c) { }
-
-#endif  /* !CONFIG_ARCH_RANDOM */
+#ifndef CONFIG_UML
+void x86_init_rdrand(struct cpuinfo_x86 *c);
+#endif
 
 #endif /* ASM_X86_ARCHRANDOM_H */
index 03acc82..5fe7f6c 100644 (file)
 #define X86_FEATURE_PROC_FEEDBACK      ( 7*32+ 9) /* AMD ProcFeedbackInterface */
 #define X86_FEATURE_XCOMPACTED         ( 7*32+10) /* "" Use compacted XSTATE (XSAVES or XSAVEC) */
 #define X86_FEATURE_PTI                        ( 7*32+11) /* Kernel Page Table Isolation enabled */
-#define X86_FEATURE_RETPOLINE          ( 7*32+12) /* "" Generic Retpoline mitigation for Spectre variant 2 */
-#define X86_FEATURE_RETPOLINE_LFENCE   ( 7*32+13) /* "" Use LFENCE for Spectre variant 2 */
+#define X86_FEATURE_KERNEL_IBRS                ( 7*32+12) /* "" Set/clear IBRS on kernel entry/exit */
+#define X86_FEATURE_RSB_VMEXIT         ( 7*32+13) /* "" Fill RSB on VM-Exit */
 #define X86_FEATURE_INTEL_PPIN         ( 7*32+14) /* Intel Processor Inventory Number */
 #define X86_FEATURE_CDP_L2             ( 7*32+15) /* Code and Data Prioritization L2 */
 #define X86_FEATURE_MSR_SPEC_CTRL      ( 7*32+16) /* "" MSR SPEC_CTRL is implemented */
 #define X86_FEATURE_IBRS               ( 7*32+25) /* Indirect Branch Restricted Speculation */
 #define X86_FEATURE_IBPB               ( 7*32+26) /* Indirect Branch Prediction Barrier */
 #define X86_FEATURE_STIBP              ( 7*32+27) /* Single Thread Indirect Branch Predictors */
-#define X86_FEATURE_ZEN                        ( 7*32+28) /* "" CPU is AMD family 0x17 or above (Zen) */
+#define X86_FEATURE_ZEN                        (7*32+28) /* "" CPU based on Zen microarchitecture */
 #define X86_FEATURE_L1TF_PTEINV                ( 7*32+29) /* "" L1TF workaround PTE inversion */
 #define X86_FEATURE_IBRS_ENHANCED      ( 7*32+30) /* Enhanced IBRS */
 #define X86_FEATURE_MSR_IA32_FEAT_CTL  ( 7*32+31) /* "" MSR IA32_FEAT_CTL configured */
 #define X86_FEATURE_PER_THREAD_MBA     (11*32+ 7) /* "" Per-thread Memory Bandwidth Allocation */
 #define X86_FEATURE_SGX1               (11*32+ 8) /* "" Basic SGX */
 #define X86_FEATURE_SGX2               (11*32+ 9) /* "" SGX Enclave Dynamic Memory Management (EDMM) */
+#define X86_FEATURE_ENTRY_IBPB         (11*32+10) /* "" Issue an IBPB on kernel entry */
+#define X86_FEATURE_RRSBA_CTRL         (11*32+11) /* "" RET prediction control */
+#define X86_FEATURE_RETPOLINE          (11*32+12) /* "" Generic Retpoline mitigation for Spectre variant 2 */
+#define X86_FEATURE_RETPOLINE_LFENCE   (11*32+13) /* "" Use LFENCE for Spectre variant 2 */
+#define X86_FEATURE_RETHUNK            (11*32+14) /* "" Use REturn THUNK */
+#define X86_FEATURE_UNRET              (11*32+15) /* "" AMD BTB untrain return */
+#define X86_FEATURE_USE_IBPB_FW                (11*32+16) /* "" Use IBPB during runtime firmware calls */
 
 /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */
 #define X86_FEATURE_AVX_VNNI           (12*32+ 4) /* AVX VNNI instructions */
 #define X86_FEATURE_VIRT_SSBD          (13*32+25) /* Virtualized Speculative Store Bypass Disable */
 #define X86_FEATURE_AMD_SSB_NO         (13*32+26) /* "" Speculative Store Bypass is fixed in hardware. */
 #define X86_FEATURE_CPPC               (13*32+27) /* Collaborative Processor Performance Control */
+#define X86_FEATURE_BTC_NO             (13*32+29) /* "" Not vulnerable to Branch Type Confusion */
 #define X86_FEATURE_BRS                        (13*32+31) /* Branch Sampling available */
 
 /* Thermal and Power Management Leaf, CPUID level 0x00000006 (EAX), word 14 */
 #define X86_BUG_ITLB_MULTIHIT          X86_BUG(23) /* CPU may incur MCE during certain page attribute changes */
 #define X86_BUG_SRBDS                  X86_BUG(24) /* CPU may leak RNG bits if not mitigated */
 #define X86_BUG_MMIO_STALE_DATA                X86_BUG(25) /* CPU is affected by Processor MMIO Stale Data vulnerabilities */
+#define X86_BUG_RETBLEED               X86_BUG(26) /* CPU is affected by RETBleed */
 
 #endif /* _ASM_X86_CPUFEATURES_H */
index 36369e7..33d2cd0 100644 (file)
 # define DISABLE_PTI           (1 << (X86_FEATURE_PTI & 31))
 #endif
 
+#ifdef CONFIG_RETPOLINE
+# define DISABLE_RETPOLINE     0
+#else
+# define DISABLE_RETPOLINE     ((1 << (X86_FEATURE_RETPOLINE & 31)) | \
+                                (1 << (X86_FEATURE_RETPOLINE_LFENCE & 31)))
+#endif
+
+#ifdef CONFIG_RETHUNK
+# define DISABLE_RETHUNK       0
+#else
+# define DISABLE_RETHUNK       (1 << (X86_FEATURE_RETHUNK & 31))
+#endif
+
+#ifdef CONFIG_CPU_UNRET_ENTRY
+# define DISABLE_UNRET         0
+#else
+# define DISABLE_UNRET         (1 << (X86_FEATURE_UNRET & 31))
+#endif
+
 #ifdef CONFIG_INTEL_IOMMU_SVM
 # define DISABLE_ENQCMD                0
 #else
 #define DISABLED_MASK8 (DISABLE_TDX_GUEST)
 #define DISABLED_MASK9 (DISABLE_SGX)
 #define DISABLED_MASK10        0
-#define DISABLED_MASK11        0
+#define DISABLED_MASK11        (DISABLE_RETPOLINE|DISABLE_RETHUNK|DISABLE_UNRET)
 #define DISABLED_MASK12        0
 #define DISABLED_MASK13        0
 #define DISABLED_MASK14        0
index 6b0f31f..503a577 100644 (file)
@@ -164,4 +164,6 @@ static inline bool fpstate_is_confidential(struct fpu_guest *gfpu)
 /* prctl */
 extern long fpu_xstate_prctl(int option, unsigned long arg2);
 
+extern void fpu_idle_fpregs(void);
+
 #endif /* _ASM_X86_FPU_API_H */
index 6ad8d94..a3760ca 100644 (file)
@@ -186,6 +186,12 @@ extern int arch_kexec_post_alloc_pages(void *vaddr, unsigned int pages,
 extern void arch_kexec_pre_free_pages(void *vaddr, unsigned int pages);
 #define arch_kexec_pre_free_pages arch_kexec_pre_free_pages
 
+void arch_kexec_protect_crashkres(void);
+#define arch_kexec_protect_crashkres arch_kexec_protect_crashkres
+
+void arch_kexec_unprotect_crashkres(void);
+#define arch_kexec_unprotect_crashkres arch_kexec_unprotect_crashkres
+
 #ifdef CONFIG_KEXEC_FILE
 struct purgatory_info;
 int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
@@ -193,6 +199,12 @@ int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
                                     const Elf_Shdr *relsec,
                                     const Elf_Shdr *symtab);
 #define arch_kexec_apply_relocations_add arch_kexec_apply_relocations_add
+
+void *arch_kexec_kernel_image_load(struct kimage *image);
+#define arch_kexec_kernel_image_load arch_kexec_kernel_image_load
+
+int arch_kimage_file_post_load_cleanup(struct kimage *image);
+#define arch_kimage_file_post_load_cleanup arch_kimage_file_post_load_cleanup
 #endif
 #endif
 
index 85865f1..73ca200 100644 (file)
 #define __ALIGN_STR    __stringify(__ALIGN)
 #endif
 
+#if defined(CONFIG_RETHUNK) && !defined(__DISABLE_EXPORTS) && !defined(BUILD_VDSO)
+#define RET    jmp __x86_return_thunk
+#else /* CONFIG_RETPOLINE */
 #ifdef CONFIG_SLS
 #define RET    ret; int3
 #else
 #define RET    ret
 #endif
+#endif /* CONFIG_RETPOLINE */
 
 #else /* __ASSEMBLY__ */
 
+#if defined(CONFIG_RETHUNK) && !defined(__DISABLE_EXPORTS) && !defined(BUILD_VDSO)
+#define ASM_RET        "jmp __x86_return_thunk\n\t"
+#else /* CONFIG_RETPOLINE */
 #ifdef CONFIG_SLS
 #define ASM_RET        "ret; int3\n\t"
 #else
 #define ASM_RET        "ret\n\t"
 #endif
+#endif /* CONFIG_RETPOLINE */
 
 #endif /* __ASSEMBLY__ */
 
index d27e058..1ac0f9b 100644 (file)
@@ -51,6 +51,8 @@
 #define SPEC_CTRL_STIBP                        BIT(SPEC_CTRL_STIBP_SHIFT)      /* STIBP mask */
 #define SPEC_CTRL_SSBD_SHIFT           2          /* Speculative Store Bypass Disable bit */
 #define SPEC_CTRL_SSBD                 BIT(SPEC_CTRL_SSBD_SHIFT)       /* Speculative Store Bypass Disable */
+#define SPEC_CTRL_RRSBA_DIS_S_SHIFT    6          /* Disable RRSBA behavior */
+#define SPEC_CTRL_RRSBA_DIS_S          BIT(SPEC_CTRL_RRSBA_DIS_S_SHIFT)
 
 #define MSR_IA32_PRED_CMD              0x00000049 /* Prediction Command */
 #define PRED_CMD_IBPB                  BIT(0)     /* Indirect Branch Prediction Barrier */
@@ -93,6 +95,7 @@
 #define MSR_IA32_ARCH_CAPABILITIES     0x0000010a
 #define ARCH_CAP_RDCL_NO               BIT(0)  /* Not susceptible to Meltdown */
 #define ARCH_CAP_IBRS_ALL              BIT(1)  /* Enhanced IBRS support */
+#define ARCH_CAP_RSBA                  BIT(2)  /* RET may use alternative branch predictors */
 #define ARCH_CAP_SKIP_VMENTRY_L1DFLUSH BIT(3)  /* Skip L1D flush on vmentry */
 #define ARCH_CAP_SSB_NO                        BIT(4)  /*
                                                 * Not susceptible to Speculative Store Bypass
                                                 * bit available to control VERW
                                                 * behavior.
                                                 */
+#define ARCH_CAP_RRSBA                 BIT(19) /*
+                                                * Indicates RET may use predictors
+                                                * other than the RSB. With eIBRS
+                                                * enabled predictions in kernel mode
+                                                * are restricted to targets in
+                                                * kernel.
+                                                */
 
 #define MSR_IA32_FLUSH_CMD             0x0000010b
 #define L1D_FLUSH                      BIT(0)  /*
 #define MSR_TURBO_ACTIVATION_RATIO     0x0000064C
 
 #define MSR_PLATFORM_ENERGY_STATUS     0x0000064D
+#define MSR_SECONDARY_TURBO_RATIO_LIMIT        0x00000650
 
 #define MSR_PKG_WEIGHTED_CORE_C0_RES   0x00000658
 #define MSR_PKG_ANY_CORE_C0_RES                0x00000659
 /* Fam 17h MSRs */
 #define MSR_F17H_IRPERF                        0xc00000e9
 
+#define MSR_ZEN2_SPECTRAL_CHICKEN      0xc00110e3
+#define MSR_ZEN2_SPECTRAL_CHICKEN_BIT  BIT_ULL(1)
+
 /* Fam 16h MSRs */
 #define MSR_F16H_L2I_PERF_CTL          0xc0010230
 #define MSR_F16H_L2I_PERF_CTR          0xc0010231
index 29dd27b..3a8fdf8 100644 (file)
@@ -13,6 +13,7 @@
 #define MWAIT_SUBSTATE_SIZE            4
 #define MWAIT_HINT2CSTATE(hint)                (((hint) >> MWAIT_SUBSTATE_SIZE) & MWAIT_CSTATE_MASK)
 #define MWAIT_HINT2SUBSTATE(hint)      ((hint) & MWAIT_CSTATE_MASK)
+#define MWAIT_C1_SUBSTATE_MASK  0xf0
 
 #define CPUID_MWAIT_LEAF               5
 #define CPUID5_ECX_EXTENSIONS_SUPPORTED 0x1
index da251a5..cba9420 100644 (file)
@@ -11,6 +11,7 @@
 #include <asm/cpufeatures.h>
 #include <asm/msr-index.h>
 #include <asm/unwind_hints.h>
+#include <asm/percpu.h>
 
 #define RETPOLINE_THUNK_SIZE   32
 
 .endm
 
 /*
+ * (ab)use RETPOLINE_SAFE on RET to annotate away 'bare' RET instructions
+ * vs RETBleed validation.
+ */
+#define ANNOTATE_UNRET_SAFE ANNOTATE_RETPOLINE_SAFE
+
+/*
+ * Abuse ANNOTATE_RETPOLINE_SAFE on a NOP to indicate UNRET_END, should
+ * eventually turn into it's own annotation.
+ */
+.macro ANNOTATE_UNRET_END
+#ifdef CONFIG_DEBUG_ENTRY
+       ANNOTATE_RETPOLINE_SAFE
+       nop
+#endif
+.endm
+
+/*
+ * Equivalent to -mindirect-branch-cs-prefix; emit the 5 byte jmp/call
+ * to the retpoline thunk with a CS prefix when the register requires
+ * a RAX prefix byte to encode. Also see apply_retpolines().
+ */
+.macro __CS_PREFIX reg:req
+       .irp rs,r8,r9,r10,r11,r12,r13,r14,r15
+       .ifc \reg,\rs
+       .byte 0x2e
+       .endif
+       .endr
+.endm
+
+/*
  * JMP_NOSPEC and CALL_NOSPEC macros can be used instead of a simple
  * indirect jmp/call which may be susceptible to the Spectre variant 2
  * attack.
  */
 .macro JMP_NOSPEC reg:req
 #ifdef CONFIG_RETPOLINE
-       ALTERNATIVE_2 __stringify(ANNOTATE_RETPOLINE_SAFE; jmp *%\reg), \
-                     __stringify(jmp __x86_indirect_thunk_\reg), X86_FEATURE_RETPOLINE, \
-                     __stringify(lfence; ANNOTATE_RETPOLINE_SAFE; jmp *%\reg), X86_FEATURE_RETPOLINE_LFENCE
+       __CS_PREFIX \reg
+       jmp     __x86_indirect_thunk_\reg
 #else
        jmp     *%\reg
+       int3
 #endif
 .endm
 
 .macro CALL_NOSPEC reg:req
 #ifdef CONFIG_RETPOLINE
-       ALTERNATIVE_2 __stringify(ANNOTATE_RETPOLINE_SAFE; call *%\reg), \
-                     __stringify(call __x86_indirect_thunk_\reg), X86_FEATURE_RETPOLINE, \
-                     __stringify(lfence; ANNOTATE_RETPOLINE_SAFE; call *%\reg), X86_FEATURE_RETPOLINE_LFENCE
+       __CS_PREFIX \reg
+       call    __x86_indirect_thunk_\reg
 #else
        call    *%\reg
 #endif
   * monstrosity above, manually.
   */
 .macro FILL_RETURN_BUFFER reg:req nr:req ftr:req
-#ifdef CONFIG_RETPOLINE
        ALTERNATIVE "jmp .Lskip_rsb_\@", "", \ftr
        __FILL_RETURN_BUFFER(\reg,\nr,%_ASM_SP)
 .Lskip_rsb_\@:
+.endm
+
+#ifdef CONFIG_CPU_UNRET_ENTRY
+#define CALL_ZEN_UNTRAIN_RET   "call zen_untrain_ret"
+#else
+#define CALL_ZEN_UNTRAIN_RET   ""
+#endif
+
+/*
+ * Mitigate RETBleed for AMD/Hygon Zen uarch. Requires KERNEL CR3 because the
+ * return thunk isn't mapped into the userspace tables (then again, AMD
+ * typically has NO_MELTDOWN).
+ *
+ * While zen_untrain_ret() doesn't clobber anything but requires stack,
+ * entry_ibpb() will clobber AX, CX, DX.
+ *
+ * As such, this must be placed after every *SWITCH_TO_KERNEL_CR3 at a point
+ * where we have a stack but before any RET instruction.
+ */
+.macro UNTRAIN_RET
+#if defined(CONFIG_CPU_UNRET_ENTRY) || defined(CONFIG_CPU_IBPB_ENTRY)
+       ANNOTATE_UNRET_END
+       ALTERNATIVE_2 "",                                               \
+                     CALL_ZEN_UNTRAIN_RET, X86_FEATURE_UNRET,          \
+                     "call entry_ibpb", X86_FEATURE_ENTRY_IBPB
 #endif
 .endm
 
        _ASM_PTR " 999b\n\t"                                    \
        ".popsection\n\t"
 
-#ifdef CONFIG_RETPOLINE
-
 typedef u8 retpoline_thunk_t[RETPOLINE_THUNK_SIZE];
+extern retpoline_thunk_t __x86_indirect_thunk_array[];
+
+extern void __x86_return_thunk(void);
+extern void zen_untrain_ret(void);
+extern void entry_ibpb(void);
+
+#ifdef CONFIG_RETPOLINE
 
 #define GEN(reg) \
        extern retpoline_thunk_t __x86_indirect_thunk_ ## reg;
 #include <asm/GEN-for-each-reg.h>
 #undef GEN
 
-extern retpoline_thunk_t __x86_indirect_thunk_array[];
-
 #ifdef CONFIG_X86_64
 
 /*
@@ -193,6 +250,7 @@ enum spectre_v2_mitigation {
        SPECTRE_V2_EIBRS,
        SPECTRE_V2_EIBRS_RETPOLINE,
        SPECTRE_V2_EIBRS_LFENCE,
+       SPECTRE_V2_IBRS,
 };
 
 /* The indirect branch speculation control variants */
@@ -235,6 +293,9 @@ static inline void indirect_branch_prediction_barrier(void)
 
 /* The Intel SPEC CTRL MSR base value cache */
 extern u64 x86_spec_ctrl_base;
+DECLARE_PER_CPU(u64, x86_spec_ctrl_current);
+extern void write_spec_ctrl_current(u64 val, bool force);
+extern u64 spec_ctrl_current(void);
 
 /*
  * With retpoline, we must use IBRS to restrict branch prediction
@@ -244,18 +305,18 @@ extern u64 x86_spec_ctrl_base;
  */
 #define firmware_restrict_branch_speculation_start()                   \
 do {                                                                   \
-       u64 val = x86_spec_ctrl_base | SPEC_CTRL_IBRS;                  \
-                                                                       \
        preempt_disable();                                              \
-       alternative_msr_write(MSR_IA32_SPEC_CTRL, val,                  \
+       alternative_msr_write(MSR_IA32_SPEC_CTRL,                       \
+                             spec_ctrl_current() | SPEC_CTRL_IBRS,     \
                              X86_FEATURE_USE_IBRS_FW);                 \
+       alternative_msr_write(MSR_IA32_PRED_CMD, PRED_CMD_IBPB,         \
+                             X86_FEATURE_USE_IBPB_FW);                 \
 } while (0)
 
 #define firmware_restrict_branch_speculation_end()                     \
 do {                                                                   \
-       u64 val = x86_spec_ctrl_base;                                   \
-                                                                       \
-       alternative_msr_write(MSR_IA32_SPEC_CTRL, val,                  \
+       alternative_msr_write(MSR_IA32_SPEC_CTRL,                       \
+                             spec_ctrl_current(),                      \
                              X86_FEATURE_USE_IBRS_FW);                 \
        preempt_enable();                                               \
 } while (0)
index 409725e..34348ae 100644 (file)
 #define AMD64_RAW_EVENT_MASK_NB                \
        (AMD64_EVENTSEL_EVENT        |  \
         ARCH_PERFMON_EVENTSEL_UMASK)
+
+#define AMD64_PERFMON_V2_EVENTSEL_EVENT_NB     \
+       (AMD64_EVENTSEL_EVENT   |               \
+        GENMASK_ULL(37, 36))
+
+#define AMD64_PERFMON_V2_EVENTSEL_UMASK_NB     \
+       (ARCH_PERFMON_EVENTSEL_UMASK    |       \
+        GENMASK_ULL(27, 24))
+
+#define AMD64_PERFMON_V2_RAW_EVENT_MASK_NB             \
+       (AMD64_PERFMON_V2_EVENTSEL_EVENT_NB     |       \
+        AMD64_PERFMON_V2_EVENTSEL_UMASK_NB)
+
 #define AMD64_NUM_COUNTERS                             4
 #define AMD64_NUM_COUNTERS_CORE                                6
 #define AMD64_NUM_COUNTERS_NB                          4
@@ -194,6 +207,9 @@ union cpuid_0x80000022_ebx {
        struct {
                /* Number of Core Performance Counters */
                unsigned int    num_core_pmc:4;
+               unsigned int    reserved:6;
+               /* Number of Data Fabric Counters */
+               unsigned int    num_df_pmc:6;
        } split;
        unsigned int            full;
 };
index f8b9ee9..f37cbff 100644 (file)
@@ -120,6 +120,9 @@ void *extend_brk(size_t size, size_t align);
        static char __brk_##name[size]
 
 extern void probe_roms(void);
+
+void clear_bss(void);
+
 #ifdef __i386__
 
 asmlinkage void __init i386_start_kernel(void);
index 1951452..4a23e52 100644 (file)
@@ -72,7 +72,6 @@ static inline u64 lower_bits(u64 val, unsigned int bits)
 
 struct real_mode_header;
 enum stack_type;
-struct ghcb;
 
 /* Early IDT entry points for #VC handler */
 extern void vc_no_ghcb(void);
@@ -156,11 +155,7 @@ static __always_inline void sev_es_nmi_complete(void)
                __sev_es_nmi_complete();
 }
 extern int __init sev_es_efi_map_ghcbs(pgd_t *pgd);
-extern enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb,
-                                         bool set_ghcb_msr,
-                                         struct es_em_ctxt *ctxt,
-                                         u64 exit_code, u64 exit_info_1,
-                                         u64 exit_info_2);
+
 static inline int rmpadjust(unsigned long vaddr, bool rmp_psize, unsigned long attrs)
 {
        int rc;
index 45b18eb..35f709f 100644 (file)
@@ -295,6 +295,15 @@ static inline int enqcmds(void __iomem *dst, const void *src)
        return 0;
 }
 
+static inline void tile_release(void)
+{
+       /*
+        * Instruction opcode for TILERELEASE; supported in binutils
+        * version >= 2.36.
+        */
+       asm volatile(".byte 0xc4, 0xe2, 0x78, 0x49, 0xc0");
+}
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_X86_SPECIAL_INSNS_H */
index 2d8dacd..343b722 100644 (file)
  * relative displacement across sections.
  */
 
+/*
+ * The trampoline is 8 bytes and of the general form:
+ *
+ *   jmp.d32 \func
+ *   ud1 %esp, %ecx
+ *
+ * That trailing #UD provides both a speculation stop and serves as a unique
+ * 3 byte signature identifying static call trampolines. Also see tramp_ud[]
+ * and __static_call_fixup().
+ */
 #define __ARCH_DEFINE_STATIC_CALL_TRAMP(name, insns)                   \
        asm(".pushsection .static_call.text, \"ax\"             \n"     \
            ".align 4                                           \n"     \
@@ -28,7 +38,7 @@
            STATIC_CALL_TRAMP_STR(name) ":                      \n"     \
            ANNOTATE_NOENDBR                                            \
            insns "                                             \n"     \
-           ".byte 0x53, 0x43, 0x54                             \n"     \
+           ".byte 0x0f, 0xb9, 0xcc                             \n"     \
            ".type " STATIC_CALL_TRAMP_STR(name) ", @function   \n"     \
            ".size " STATIC_CALL_TRAMP_STR(name) ", . - " STATIC_CALL_TRAMP_STR(name) " \n" \
            ".popsection                                        \n")
 #define ARCH_DEFINE_STATIC_CALL_TRAMP(name, func)                      \
        __ARCH_DEFINE_STATIC_CALL_TRAMP(name, ".byte 0xe9; .long " #func " - (. + 4)")
 
+#ifdef CONFIG_RETHUNK
+#define ARCH_DEFINE_STATIC_CALL_NULL_TRAMP(name)                       \
+       __ARCH_DEFINE_STATIC_CALL_TRAMP(name, "jmp __x86_return_thunk")
+#else
 #define ARCH_DEFINE_STATIC_CALL_NULL_TRAMP(name)                       \
        __ARCH_DEFINE_STATIC_CALL_TRAMP(name, "ret; int3; nop; nop; nop")
+#endif
 
 #define ARCH_DEFINE_STATIC_CALL_RET0_TRAMP(name)                       \
        ARCH_DEFINE_STATIC_CALL_TRAMP(name, __static_call_return0)
@@ -48,4 +63,6 @@
            ".long " STATIC_CALL_KEY_STR(name) " - .            \n"     \
            ".popsection                                        \n")
 
+extern bool __static_call_fixup(void *tramp, u8 op, void *dest);
+
 #endif /* _ASM_STATIC_CALL_H */
index 1bfe979..580636c 100644 (file)
@@ -2,9 +2,6 @@
 #ifndef _ASM_X86_TLB_H
 #define _ASM_X86_TLB_H
 
-#define tlb_start_vma(tlb, vma) do { } while (0)
-#define tlb_end_vma(tlb, vma) do { } while (0)
-
 #define tlb_flush tlb_flush
 static inline void tlb_flush(struct mmu_gather *tlb);
 
index 4af5579..cda3118 100644 (file)
@@ -16,6 +16,7 @@
 void __flush_tlb_all(void);
 
 #define TLB_FLUSH_ALL  -1UL
+#define TLB_GENERATION_INVALID 0
 
 void cr4_update_irqsoff(unsigned long set, unsigned long clear);
 unsigned long cr4_read_shadow(void);
index 8b33674..f66fbe6 100644 (file)
@@ -8,7 +8,11 @@
 #ifdef __ASSEMBLY__
 
 .macro UNWIND_HINT_EMPTY
-       UNWIND_HINT sp_reg=ORC_REG_UNDEFINED type=UNWIND_HINT_TYPE_CALL end=1
+       UNWIND_HINT type=UNWIND_HINT_TYPE_CALL end=1
+.endm
+
+.macro UNWIND_HINT_ENTRY
+       UNWIND_HINT type=UNWIND_HINT_TYPE_ENTRY end=1
 .endm
 
 .macro UNWIND_HINT_REGS base=%rsp offset=0 indirect=0 extra=1 partial=0
        UNWIND_HINT sp_reg=ORC_REG_SP sp_offset=8 type=UNWIND_HINT_TYPE_FUNC
 .endm
 
+.macro UNWIND_HINT_SAVE
+       UNWIND_HINT type=UNWIND_HINT_TYPE_SAVE
+.endm
+
+.macro UNWIND_HINT_RESTORE
+       UNWIND_HINT type=UNWIND_HINT_TYPE_RESTORE
+.endm
+
 #else
 
 #define UNWIND_HINT_FUNC \
index bea5cdc..01d19fc 100644 (file)
 #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)
-
-/* SETUP_INDIRECT | max(SETUP_*) */
-#define SETUP_TYPE_MAX                 (SETUP_INDIRECT | SETUP_JAILHOUSE)
+#define SETUP_TYPE_MAX                 (SETUP_ENUM_MAX | SETUP_INDIRECT)
 
 /* ram_size flags */
 #define RAMDISK_IMAGE_START_MASK       0x07FF
@@ -52,7 +53,7 @@ struct setup_data {
        __u64 next;
        __u32 type;
        __u32 len;
-       __u8 data[0];
+       __u8 data[];
 };
 
 /* extensible setup indirect data node */
@@ -172,6 +173,14 @@ struct jailhouse_setup_data {
        } __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 2161480..ec53c9f 100644 (file)
@@ -198,13 +198,13 @@ struct kvm_msrs {
        __u32 nmsrs; /* number of msrs in entries */
        __u32 pad;
 
-       struct kvm_msr_entry entries[0];
+       struct kvm_msr_entry entries[];
 };
 
 /* for KVM_GET_MSR_INDEX_LIST */
 struct kvm_msr_list {
        __u32 nmsrs; /* number of msrs in entries */
-       __u32 indices[0];
+       __u32 indices[];
 };
 
 /* Maximum size of any access bitmap in bytes */
@@ -241,7 +241,7 @@ struct kvm_cpuid_entry {
 struct kvm_cpuid {
        __u32 nent;
        __u32 padding;
-       struct kvm_cpuid_entry entries[0];
+       struct kvm_cpuid_entry entries[];
 };
 
 struct kvm_cpuid_entry2 {
@@ -263,7 +263,7 @@ struct kvm_cpuid_entry2 {
 struct kvm_cpuid2 {
        __u32 nent;
        __u32 padding;
-       struct kvm_cpuid_entry2 entries[0];
+       struct kvm_cpuid_entry2 entries[];
 };
 
 /* for KVM_GET_PIT and KVM_SET_PIT */
@@ -389,7 +389,7 @@ struct kvm_xsave {
         * the contents of CPUID leaf 0xD on the host.
         */
        __u32 region[1024];
-       __u32 extra[0];
+       __u32 extra[];
 };
 
 #define KVM_MAX_XCRS   16
@@ -516,7 +516,7 @@ struct kvm_pmu_event_filter {
        __u32 fixed_counter_bitmap;
        __u32 flags;
        __u32 pad[4];
-       __u64 events[0];
+       __u64 events[];
 };
 
 #define KVM_PMU_EVENT_ALLOW 0
index 4c8b6ae..a20a5eb 100644 (file)
@@ -34,8 +34,6 @@ KASAN_SANITIZE_sev.o                                  := n
 # by several compilation units. To be safe, disable all instrumentation.
 KCSAN_SANITIZE := n
 
-OBJECT_FILES_NON_STANDARD_test_nx.o                    := y
-
 # If instrumentation of this dir is enabled, boot hangs during first second.
 # Probably could be more selective here, but note that files related to irqs,
 # boot, dumpstack/stacktrace, etc are either non-interesting or can lead to
index 8b8cbf2..8d8752b 100644 (file)
 
 /* Refer to drivers/acpi/cppc_acpi.c for the description of functions */
 
+bool cpc_supported_by_cpu(void)
+{
+       switch (boot_cpu_data.x86_vendor) {
+       case X86_VENDOR_AMD:
+       case X86_VENDOR_HYGON:
+               if (boot_cpu_data.x86 == 0x19 && ((boot_cpu_data.x86_model <= 0x0f) ||
+                   (boot_cpu_data.x86_model >= 0x20 && boot_cpu_data.x86_model <= 0x2f)))
+                       return true;
+               else if (boot_cpu_data.x86 == 0x17 &&
+                        boot_cpu_data.x86_model >= 0x70 && boot_cpu_data.x86_model <= 0x7f)
+                       return true;
+               return boot_cpu_has(X86_FEATURE_CPPC);
+       }
+       return false;
+}
+
 bool cpc_ffh_supported(void)
 {
        return true;
index e257f6c..62f6b8b 100644 (file)
@@ -115,6 +115,7 @@ static void __init_or_module add_nops(void *insns, unsigned int len)
 }
 
 extern s32 __retpoline_sites[], __retpoline_sites_end[];
+extern s32 __return_sites[], __return_sites_end[];
 extern s32 __ibt_endbr_seal[], __ibt_endbr_seal_end[];
 extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
 extern s32 __smp_locks[], __smp_locks_end[];
@@ -507,9 +508,78 @@ void __init_or_module noinline apply_retpolines(s32 *start, s32 *end)
        }
 }
 
+#ifdef CONFIG_RETHUNK
+/*
+ * Rewrite the compiler generated return thunk tail-calls.
+ *
+ * For example, convert:
+ *
+ *   JMP __x86_return_thunk
+ *
+ * into:
+ *
+ *   RET
+ */
+static int patch_return(void *addr, struct insn *insn, u8 *bytes)
+{
+       int i = 0;
+
+       if (cpu_feature_enabled(X86_FEATURE_RETHUNK))
+               return -1;
+
+       bytes[i++] = RET_INSN_OPCODE;
+
+       for (; i < insn->length;)
+               bytes[i++] = INT3_INSN_OPCODE;
+
+       return i;
+}
+
+void __init_or_module noinline apply_returns(s32 *start, s32 *end)
+{
+       s32 *s;
+
+       for (s = start; s < end; s++) {
+               void *dest = NULL, *addr = (void *)s + *s;
+               struct insn insn;
+               int len, ret;
+               u8 bytes[16];
+               u8 op;
+
+               ret = insn_decode_kernel(&insn, addr);
+               if (WARN_ON_ONCE(ret < 0))
+                       continue;
+
+               op = insn.opcode.bytes[0];
+               if (op == JMP32_INSN_OPCODE)
+                       dest = addr + insn.length + insn.immediate.value;
+
+               if (__static_call_fixup(addr, op, dest) ||
+                   WARN_ONCE(dest != &__x86_return_thunk,
+                             "missing return thunk: %pS-%pS: %*ph",
+                             addr, dest, 5, addr))
+                       continue;
+
+               DPRINTK("return thunk at: %pS (%px) len: %d to: %pS",
+                       addr, addr, insn.length,
+                       addr + insn.length + insn.immediate.value);
+
+               len = patch_return(addr, &insn, bytes);
+               if (len == insn.length) {
+                       DUMP_BYTES(((u8*)addr),  len, "%px: orig: ", addr);
+                       DUMP_BYTES(((u8*)bytes), len, "%px: repl: ", addr);
+                       text_poke_early(addr, bytes, len);
+               }
+       }
+}
+#else
+void __init_or_module noinline apply_returns(s32 *start, s32 *end) { }
+#endif /* CONFIG_RETHUNK */
+
 #else /* !CONFIG_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 */
 
@@ -860,6 +930,7 @@ void __init alternative_instructions(void)
         * those can rewrite the retpoline thunks.
         */
        apply_retpolines(__retpoline_sites, __retpoline_sites_end);
+       apply_returns(__return_sites, __return_sites_end);
 
        /*
         * Then patch alternatives, such that those paravirt calls that are in
index 190e0f7..4266b64 100644 (file)
 #define PCI_DEVICE_ID_AMD_17H_M10H_ROOT        0x15d0
 #define PCI_DEVICE_ID_AMD_17H_M30H_ROOT        0x1480
 #define PCI_DEVICE_ID_AMD_17H_M60H_ROOT        0x1630
+#define PCI_DEVICE_ID_AMD_17H_MA0H_ROOT        0x14b5
 #define PCI_DEVICE_ID_AMD_19H_M10H_ROOT        0x14a4
+#define PCI_DEVICE_ID_AMD_19H_M60H_ROOT        0x14d8
+#define PCI_DEVICE_ID_AMD_19H_M70H_ROOT        0x14e8
 #define PCI_DEVICE_ID_AMD_17H_DF_F4    0x1464
 #define PCI_DEVICE_ID_AMD_17H_M10H_DF_F4 0x15ec
 #define PCI_DEVICE_ID_AMD_17H_M30H_DF_F4 0x1494
 #define PCI_DEVICE_ID_AMD_17H_M60H_DF_F4 0x144c
 #define PCI_DEVICE_ID_AMD_17H_M70H_DF_F4 0x1444
+#define PCI_DEVICE_ID_AMD_17H_MA0H_DF_F4 0x1728
 #define PCI_DEVICE_ID_AMD_19H_DF_F4    0x1654
 #define PCI_DEVICE_ID_AMD_19H_M10H_DF_F4 0x14b1
 #define PCI_DEVICE_ID_AMD_19H_M40H_ROOT        0x14b5
 #define PCI_DEVICE_ID_AMD_19H_M40H_DF_F4 0x167d
 #define PCI_DEVICE_ID_AMD_19H_M50H_DF_F4 0x166e
+#define PCI_DEVICE_ID_AMD_19H_M60H_DF_F4 0x14e4
+#define PCI_DEVICE_ID_AMD_19H_M70H_DF_F4 0x14f4
 
 /* Protect the PCI config register pairs used for SMN. */
 static DEFINE_MUTEX(smn_mutex);
@@ -41,8 +47,11 @@ static const struct pci_device_id amd_root_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_ROOT) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M30H_ROOT) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M60H_ROOT) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_MA0H_ROOT) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M10H_ROOT) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M40H_ROOT) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M60H_ROOT) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M70H_ROOT) },
        {}
 };
 
@@ -61,12 +70,15 @@ static const struct pci_device_id amd_nb_misc_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F3) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M60H_DF_F3) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_MA0H_DF_F3) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F3) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_DF_F3) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M10H_DF_F3) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M40H_DF_F3) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M50H_DF_F3) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M60H_DF_F3) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M70H_DF_F3) },
        {}
 };
 
@@ -81,6 +93,7 @@ static const struct pci_device_id amd_nb_link_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F4) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M60H_DF_F4) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F4) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_MA0H_DF_F4) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_DF_F4) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M10H_DF_F4) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M40H_DF_F4) },
index 4373080..cb50589 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/suspend.h>
 #include <asm/tlbflush.h>
 #include <asm/tdx.h>
+#include "../kvm/vmx/vmx.h"
 
 #ifdef CONFIG_XEN
 #include <xen/interface/xen.h>
@@ -107,4 +108,9 @@ static void __used common(void)
        OFFSET(TSS_sp0, tss_struct, x86_tss.sp0);
        OFFSET(TSS_sp1, tss_struct, x86_tss.sp1);
        OFFSET(TSS_sp2, tss_struct, x86_tss.sp2);
+
+       if (IS_ENABLED(CONFIG_KVM_INTEL)) {
+               BLANK();
+               OFFSET(VMX_spec_ctrl, vcpu_vmx, spec_ctrl);
+       }
 }
index 0c0b097..48276c0 100644 (file)
@@ -808,7 +808,7 @@ static void clear_rdrand_cpuid_bit(struct cpuinfo_x86 *c)
                return;
 
        /*
-        * The nordrand option can clear X86_FEATURE_RDRAND, so check for
+        * The self-test can clear X86_FEATURE_RDRAND, so check for
         * RDRAND support using the CPUID function directly.
         */
        if (!(cpuid_ecx(1) & BIT(30)) || rdrand_force)
@@ -862,6 +862,28 @@ static void init_amd_bd(struct cpuinfo_x86 *c)
        clear_rdrand_cpuid_bit(c);
 }
 
+void init_spectral_chicken(struct cpuinfo_x86 *c)
+{
+#ifdef CONFIG_CPU_UNRET_ENTRY
+       u64 value;
+
+       /*
+        * On Zen2 we offer this chicken (bit) on the altar of Speculation.
+        *
+        * This suppresses speculation from the middle of a basic block, i.e. it
+        * suppresses non-branch predictions.
+        *
+        * We use STIBP as a heuristic to filter out Zen2 from the rest of F17H
+        */
+       if (!cpu_has(c, X86_FEATURE_HYPERVISOR) && cpu_has(c, X86_FEATURE_AMD_STIBP)) {
+               if (!rdmsrl_safe(MSR_ZEN2_SPECTRAL_CHICKEN, &value)) {
+                       value |= MSR_ZEN2_SPECTRAL_CHICKEN_BIT;
+                       wrmsrl_safe(MSR_ZEN2_SPECTRAL_CHICKEN, value);
+               }
+       }
+#endif
+}
+
 static void init_amd_zn(struct cpuinfo_x86 *c)
 {
        set_cpu_cap(c, X86_FEATURE_ZEN);
@@ -870,12 +892,21 @@ static void init_amd_zn(struct cpuinfo_x86 *c)
        node_reclaim_distance = 32;
 #endif
 
-       /*
-        * Fix erratum 1076: CPB feature bit not being set in CPUID.
-        * Always set it, except when running under a hypervisor.
-        */
-       if (!cpu_has(c, X86_FEATURE_HYPERVISOR) && !cpu_has(c, X86_FEATURE_CPB))
-               set_cpu_cap(c, X86_FEATURE_CPB);
+       /* Fix up CPUID bits, but only if not virtualised. */
+       if (!cpu_has(c, X86_FEATURE_HYPERVISOR)) {
+
+               /* Erratum 1076: CPB feature bit not being set in CPUID. */
+               if (!cpu_has(c, X86_FEATURE_CPB))
+                       set_cpu_cap(c, X86_FEATURE_CPB);
+
+               /*
+                * Zen3 (Fam19 model < 0x10) parts are not susceptible to
+                * Branch Type Confusion, but predate the allocation of the
+                * BTC_NO bit.
+                */
+               if (c->x86 == 0x19 && !cpu_has(c, X86_FEATURE_BTC_NO))
+                       set_cpu_cap(c, X86_FEATURE_BTC_NO);
+       }
 }
 
 static void init_amd(struct cpuinfo_x86 *c)
@@ -907,7 +938,8 @@ static void init_amd(struct cpuinfo_x86 *c)
        case 0x12: init_amd_ln(c); break;
        case 0x15: init_amd_bd(c); break;
        case 0x16: init_amd_jg(c); break;
-       case 0x17: fallthrough;
+       case 0x17: init_spectral_chicken(c);
+                  fallthrough;
        case 0x19: init_amd_zn(c); break;
        }
 
index 74c62cc..6761668 100644 (file)
@@ -38,6 +38,8 @@
 
 static void __init spectre_v1_select_mitigation(void);
 static void __init spectre_v2_select_mitigation(void);
+static void __init retbleed_select_mitigation(void);
+static void __init spectre_v2_user_select_mitigation(void);
 static void __init ssb_select_mitigation(void);
 static void __init l1tf_select_mitigation(void);
 static void __init mds_select_mitigation(void);
@@ -48,16 +50,40 @@ static void __init mmio_select_mitigation(void);
 static void __init srbds_select_mitigation(void);
 static void __init l1d_flush_select_mitigation(void);
 
-/* The base value of the SPEC_CTRL MSR that always has to be preserved. */
+/* The base value of the SPEC_CTRL MSR without task-specific bits set */
 u64 x86_spec_ctrl_base;
 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);
+
 static DEFINE_MUTEX(spec_ctrl_mutex);
 
 /*
- * The vendor and possibly platform specific bits which can be modified in
- * x86_spec_ctrl_base.
+ * Keep track of the SPEC_CTRL MSR value for the current task, which may differ
+ * from x86_spec_ctrl_base due to STIBP/SSB in __speculation_ctrl_update().
  */
-static u64 __ro_after_init x86_spec_ctrl_mask = SPEC_CTRL_IBRS;
+void write_spec_ctrl_current(u64 val, bool force)
+{
+       if (this_cpu_read(x86_spec_ctrl_current) == val)
+               return;
+
+       this_cpu_write(x86_spec_ctrl_current, val);
+
+       /*
+        * When KERNEL_IBRS this MSR is written on return-to-user, unless
+        * forced the update can be delayed until that time.
+        */
+       if (force || !cpu_feature_enabled(X86_FEATURE_KERNEL_IBRS))
+               wrmsrl(MSR_IA32_SPEC_CTRL, val);
+}
+
+u64 spec_ctrl_current(void)
+{
+       return this_cpu_read(x86_spec_ctrl_current);
+}
+EXPORT_SYMBOL_GPL(spec_ctrl_current);
 
 /*
  * AMD specific MSR info for Speculative Store Bypass control.
@@ -114,13 +140,21 @@ void __init check_bugs(void)
        if (boot_cpu_has(X86_FEATURE_MSR_SPEC_CTRL))
                rdmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
 
-       /* Allow STIBP in MSR_SPEC_CTRL if supported */
-       if (boot_cpu_has(X86_FEATURE_STIBP))
-               x86_spec_ctrl_mask |= SPEC_CTRL_STIBP;
-
        /* Select the proper CPU mitigations before patching alternatives: */
        spectre_v1_select_mitigation();
        spectre_v2_select_mitigation();
+       /*
+        * retbleed_select_mitigation() relies on the state set by
+        * spectre_v2_select_mitigation(); specifically it wants to know about
+        * spectre_v2=ibrs.
+        */
+       retbleed_select_mitigation();
+       /*
+        * spectre_v2_user_select_mitigation() relies on the state set by
+        * retbleed_select_mitigation(); specifically the STIBP selection is
+        * forced for UNRET.
+        */
+       spectre_v2_user_select_mitigation();
        ssb_select_mitigation();
        l1tf_select_mitigation();
        md_clear_select_mitigation();
@@ -161,31 +195,17 @@ void __init check_bugs(void)
 #endif
 }
 
+/*
+ * NOTE: This function is *only* called for SVM.  VMX spec_ctrl handling is
+ * done in vmenter.S.
+ */
 void
 x86_virt_spec_ctrl(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl, bool setguest)
 {
-       u64 msrval, guestval, hostval = x86_spec_ctrl_base;
+       u64 msrval, guestval = guest_spec_ctrl, hostval = spec_ctrl_current();
        struct thread_info *ti = current_thread_info();
 
-       /* Is MSR_SPEC_CTRL implemented ? */
        if (static_cpu_has(X86_FEATURE_MSR_SPEC_CTRL)) {
-               /*
-                * Restrict guest_spec_ctrl to supported values. Clear the
-                * modifiable bits in the host base value and or the
-                * modifiable bits from the guest value.
-                */
-               guestval = hostval & ~x86_spec_ctrl_mask;
-               guestval |= guest_spec_ctrl & x86_spec_ctrl_mask;
-
-               /* SSBD controlled in MSR_SPEC_CTRL */
-               if (static_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD) ||
-                   static_cpu_has(X86_FEATURE_AMD_SSBD))
-                       hostval |= ssbd_tif_to_spec_ctrl(ti->flags);
-
-               /* Conditional STIBP enabled? */
-               if (static_branch_unlikely(&switch_to_cond_stibp))
-                       hostval |= stibp_tif_to_spec_ctrl(ti->flags);
-
                if (hostval != guestval) {
                        msrval = setguest ? guestval : hostval;
                        wrmsrl(MSR_IA32_SPEC_CTRL, msrval);
@@ -752,12 +772,180 @@ static int __init nospectre_v1_cmdline(char *str)
 }
 early_param("nospectre_v1", nospectre_v1_cmdline);
 
-#undef pr_fmt
-#define pr_fmt(fmt)     "Spectre V2 : " fmt
-
 static enum spectre_v2_mitigation spectre_v2_enabled __ro_after_init =
        SPECTRE_V2_NONE;
 
+#undef pr_fmt
+#define pr_fmt(fmt)     "RETBleed: " fmt
+
+enum retbleed_mitigation {
+       RETBLEED_MITIGATION_NONE,
+       RETBLEED_MITIGATION_UNRET,
+       RETBLEED_MITIGATION_IBPB,
+       RETBLEED_MITIGATION_IBRS,
+       RETBLEED_MITIGATION_EIBRS,
+};
+
+enum retbleed_mitigation_cmd {
+       RETBLEED_CMD_OFF,
+       RETBLEED_CMD_AUTO,
+       RETBLEED_CMD_UNRET,
+       RETBLEED_CMD_IBPB,
+};
+
+static const char * const retbleed_strings[] = {
+       [RETBLEED_MITIGATION_NONE]      = "Vulnerable",
+       [RETBLEED_MITIGATION_UNRET]     = "Mitigation: untrained return thunk",
+       [RETBLEED_MITIGATION_IBPB]      = "Mitigation: IBPB",
+       [RETBLEED_MITIGATION_IBRS]      = "Mitigation: IBRS",
+       [RETBLEED_MITIGATION_EIBRS]     = "Mitigation: Enhanced IBRS",
+};
+
+static enum retbleed_mitigation retbleed_mitigation __ro_after_init =
+       RETBLEED_MITIGATION_NONE;
+static enum retbleed_mitigation_cmd retbleed_cmd __ro_after_init =
+       RETBLEED_CMD_AUTO;
+
+static int __ro_after_init retbleed_nosmt = false;
+
+static int __init retbleed_parse_cmdline(char *str)
+{
+       if (!str)
+               return -EINVAL;
+
+       while (str) {
+               char *next = strchr(str, ',');
+               if (next) {
+                       *next = 0;
+                       next++;
+               }
+
+               if (!strcmp(str, "off")) {
+                       retbleed_cmd = RETBLEED_CMD_OFF;
+               } else if (!strcmp(str, "auto")) {
+                       retbleed_cmd = RETBLEED_CMD_AUTO;
+               } else if (!strcmp(str, "unret")) {
+                       retbleed_cmd = RETBLEED_CMD_UNRET;
+               } else if (!strcmp(str, "ibpb")) {
+                       retbleed_cmd = RETBLEED_CMD_IBPB;
+               } else if (!strcmp(str, "nosmt")) {
+                       retbleed_nosmt = true;
+               } else {
+                       pr_err("Ignoring unknown retbleed option (%s).", str);
+               }
+
+               str = next;
+       }
+
+       return 0;
+}
+early_param("retbleed", retbleed_parse_cmdline);
+
+#define RETBLEED_UNTRAIN_MSG "WARNING: BTB untrained return thunk mitigation is only effective on AMD/Hygon!\n"
+#define RETBLEED_INTEL_MSG "WARNING: Spectre v2 mitigation leaves CPU vulnerable to RETBleed attacks, data leaks possible!\n"
+
+static void __init retbleed_select_mitigation(void)
+{
+       bool mitigate_smt = false;
+
+       if (!boot_cpu_has_bug(X86_BUG_RETBLEED) || cpu_mitigations_off())
+               return;
+
+       switch (retbleed_cmd) {
+       case RETBLEED_CMD_OFF:
+               return;
+
+       case RETBLEED_CMD_UNRET:
+               if (IS_ENABLED(CONFIG_CPU_UNRET_ENTRY)) {
+                       retbleed_mitigation = RETBLEED_MITIGATION_UNRET;
+               } else {
+                       pr_err("WARNING: kernel not compiled with CPU_UNRET_ENTRY.\n");
+                       goto do_cmd_auto;
+               }
+               break;
+
+       case RETBLEED_CMD_IBPB:
+               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)) {
+                       retbleed_mitigation = RETBLEED_MITIGATION_IBPB;
+               } else {
+                       pr_err("WARNING: kernel not compiled with CPU_IBPB_ENTRY.\n");
+                       goto do_cmd_auto;
+               }
+               break;
+
+do_cmd_auto:
+       case RETBLEED_CMD_AUTO:
+       default:
+               if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
+                   boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) {
+                       if (IS_ENABLED(CONFIG_CPU_UNRET_ENTRY))
+                               retbleed_mitigation = RETBLEED_MITIGATION_UNRET;
+                       else if (IS_ENABLED(CONFIG_CPU_IBPB_ENTRY) && boot_cpu_has(X86_FEATURE_IBPB))
+                               retbleed_mitigation = RETBLEED_MITIGATION_IBPB;
+               }
+
+               /*
+                * The Intel mitigation (IBRS or eIBRS) was already selected in
+                * spectre_v2_select_mitigation().  'retbleed_mitigation' will
+                * be set accordingly below.
+                */
+
+               break;
+       }
+
+       switch (retbleed_mitigation) {
+       case RETBLEED_MITIGATION_UNRET:
+               setup_force_cpu_cap(X86_FEATURE_RETHUNK);
+               setup_force_cpu_cap(X86_FEATURE_UNRET);
+
+               if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD &&
+                   boot_cpu_data.x86_vendor != X86_VENDOR_HYGON)
+                       pr_err(RETBLEED_UNTRAIN_MSG);
+
+               mitigate_smt = true;
+               break;
+
+       case RETBLEED_MITIGATION_IBPB:
+               setup_force_cpu_cap(X86_FEATURE_ENTRY_IBPB);
+               mitigate_smt = true;
+               break;
+
+       default:
+               break;
+       }
+
+       if (mitigate_smt && !boot_cpu_has(X86_FEATURE_STIBP) &&
+           (retbleed_nosmt || cpu_mitigations_auto_nosmt()))
+               cpu_smt_disable(false);
+
+       /*
+        * Let IBRS trump all on Intel without affecting the effects of the
+        * retbleed= cmdline option.
+        */
+       if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
+               switch (spectre_v2_enabled) {
+               case SPECTRE_V2_IBRS:
+                       retbleed_mitigation = RETBLEED_MITIGATION_IBRS;
+                       break;
+               case SPECTRE_V2_EIBRS:
+               case SPECTRE_V2_EIBRS_RETPOLINE:
+               case SPECTRE_V2_EIBRS_LFENCE:
+                       retbleed_mitigation = RETBLEED_MITIGATION_EIBRS;
+                       break;
+               default:
+                       pr_err(RETBLEED_INTEL_MSG);
+               }
+       }
+
+       pr_info("%s\n", retbleed_strings[retbleed_mitigation]);
+}
+
+#undef pr_fmt
+#define pr_fmt(fmt)     "Spectre V2 : " fmt
+
 static enum spectre_v2_user_mitigation spectre_v2_user_stibp __ro_after_init =
        SPECTRE_V2_USER_NONE;
 static enum spectre_v2_user_mitigation spectre_v2_user_ibpb __ro_after_init =
@@ -787,6 +975,7 @@ static inline const char *spectre_v2_module_string(void) { return ""; }
 #define SPECTRE_V2_LFENCE_MSG "WARNING: LFENCE mitigation is not recommended for this CPU, data leaks possible!\n"
 #define SPECTRE_V2_EIBRS_EBPF_MSG "WARNING: Unprivileged eBPF is enabled with eIBRS on, data leaks possible via Spectre v2 BHB attacks!\n"
 #define SPECTRE_V2_EIBRS_LFENCE_EBPF_SMT_MSG "WARNING: Unprivileged eBPF is enabled with eIBRS+LFENCE mitigation and SMT, data leaks possible via Spectre v2 BHB attacks!\n"
+#define SPECTRE_V2_IBRS_PERF_MSG "WARNING: IBRS mitigation selected on Enhanced IBRS CPU, this may cause unnecessary performance loss\n"
 
 #ifdef CONFIG_BPF_SYSCALL
 void unpriv_ebpf_notify(int new_state)
@@ -828,6 +1017,7 @@ enum spectre_v2_mitigation_cmd {
        SPECTRE_V2_CMD_EIBRS,
        SPECTRE_V2_CMD_EIBRS_RETPOLINE,
        SPECTRE_V2_CMD_EIBRS_LFENCE,
+       SPECTRE_V2_CMD_IBRS,
 };
 
 enum spectre_v2_user_cmd {
@@ -868,13 +1058,15 @@ static void __init spec_v2_user_print_cond(const char *reason, bool secure)
                pr_info("spectre_v2_user=%s forced on command line.\n", reason);
 }
 
+static __ro_after_init enum spectre_v2_mitigation_cmd spectre_v2_cmd;
+
 static enum spectre_v2_user_cmd __init
-spectre_v2_parse_user_cmdline(enum spectre_v2_mitigation_cmd v2_cmd)
+spectre_v2_parse_user_cmdline(void)
 {
        char arg[20];
        int ret, i;
 
-       switch (v2_cmd) {
+       switch (spectre_v2_cmd) {
        case SPECTRE_V2_CMD_NONE:
                return SPECTRE_V2_USER_CMD_NONE;
        case SPECTRE_V2_CMD_FORCE:
@@ -900,15 +1092,16 @@ spectre_v2_parse_user_cmdline(enum spectre_v2_mitigation_cmd v2_cmd)
        return SPECTRE_V2_USER_CMD_AUTO;
 }
 
-static inline bool spectre_v2_in_eibrs_mode(enum spectre_v2_mitigation mode)
+static inline bool spectre_v2_in_ibrs_mode(enum spectre_v2_mitigation mode)
 {
-       return (mode == SPECTRE_V2_EIBRS ||
-               mode == SPECTRE_V2_EIBRS_RETPOLINE ||
-               mode == SPECTRE_V2_EIBRS_LFENCE);
+       return mode == SPECTRE_V2_IBRS ||
+              mode == SPECTRE_V2_EIBRS ||
+              mode == SPECTRE_V2_EIBRS_RETPOLINE ||
+              mode == SPECTRE_V2_EIBRS_LFENCE;
 }
 
 static void __init
-spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
+spectre_v2_user_select_mitigation(void)
 {
        enum spectre_v2_user_mitigation mode = SPECTRE_V2_USER_NONE;
        bool smt_possible = IS_ENABLED(CONFIG_SMP);
@@ -921,7 +1114,7 @@ spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
            cpu_smt_control == CPU_SMT_NOT_SUPPORTED)
                smt_possible = false;
 
-       cmd = spectre_v2_parse_user_cmdline(v2_cmd);
+       cmd = spectre_v2_parse_user_cmdline();
        switch (cmd) {
        case SPECTRE_V2_USER_CMD_NONE:
                goto set_mode;
@@ -969,12 +1162,12 @@ spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
        }
 
        /*
-        * If no STIBP, enhanced IBRS is enabled or SMT impossible, STIBP is not
-        * required.
+        * If no STIBP, IBRS or enhanced IBRS is enabled, or SMT impossible,
+        * STIBP is not required.
         */
        if (!boot_cpu_has(X86_FEATURE_STIBP) ||
            !smt_possible ||
-           spectre_v2_in_eibrs_mode(spectre_v2_enabled))
+           spectre_v2_in_ibrs_mode(spectre_v2_enabled))
                return;
 
        /*
@@ -986,6 +1179,13 @@ spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
            boot_cpu_has(X86_FEATURE_AMD_STIBP_ALWAYS_ON))
                mode = SPECTRE_V2_USER_STRICT_PREFERRED;
 
+       if (retbleed_mitigation == RETBLEED_MITIGATION_UNRET) {
+               if (mode != SPECTRE_V2_USER_STRICT &&
+                   mode != SPECTRE_V2_USER_STRICT_PREFERRED)
+                       pr_info("Selecting STIBP always-on mode to complement retbleed mitigation\n");
+               mode = SPECTRE_V2_USER_STRICT_PREFERRED;
+       }
+
        spectre_v2_user_stibp = mode;
 
 set_mode:
@@ -999,6 +1199,7 @@ static const char * const spectre_v2_strings[] = {
        [SPECTRE_V2_EIBRS]                      = "Mitigation: Enhanced IBRS",
        [SPECTRE_V2_EIBRS_LFENCE]               = "Mitigation: Enhanced IBRS + LFENCE",
        [SPECTRE_V2_EIBRS_RETPOLINE]            = "Mitigation: Enhanced IBRS + Retpolines",
+       [SPECTRE_V2_IBRS]                       = "Mitigation: IBRS",
 };
 
 static const struct {
@@ -1016,6 +1217,7 @@ static const struct {
        { "eibrs,lfence",       SPECTRE_V2_CMD_EIBRS_LFENCE,      false },
        { "eibrs,retpoline",    SPECTRE_V2_CMD_EIBRS_RETPOLINE,   false },
        { "auto",               SPECTRE_V2_CMD_AUTO,              false },
+       { "ibrs",               SPECTRE_V2_CMD_IBRS,              false },
 };
 
 static void __init spec_v2_print_cond(const char *reason, bool secure)
@@ -1078,6 +1280,30 @@ 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)) {
+               pr_err("%s selected but not compiled in. Switching to AUTO select\n",
+                      mitigation_options[i].option);
+               return SPECTRE_V2_CMD_AUTO;
+       }
+
+       if (cmd == SPECTRE_V2_CMD_IBRS && boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) {
+               pr_err("%s selected but not Intel CPU. Switching to AUTO select\n",
+                      mitigation_options[i].option);
+               return SPECTRE_V2_CMD_AUTO;
+       }
+
+       if (cmd == SPECTRE_V2_CMD_IBRS && !boot_cpu_has(X86_FEATURE_IBRS)) {
+               pr_err("%s selected but CPU doesn't have IBRS. Switching to AUTO select\n",
+                      mitigation_options[i].option);
+               return SPECTRE_V2_CMD_AUTO;
+       }
+
+       if (cmd == SPECTRE_V2_CMD_IBRS && boot_cpu_has(X86_FEATURE_XENPV)) {
+               pr_err("%s selected but running as XenPV guest. Switching to AUTO select\n",
+                      mitigation_options[i].option);
+               return SPECTRE_V2_CMD_AUTO;
+       }
+
        spec_v2_print_cond(mitigation_options[i].option,
                           mitigation_options[i].secure);
        return cmd;
@@ -1093,6 +1319,22 @@ static enum spectre_v2_mitigation __init spectre_v2_select_retpoline(void)
        return SPECTRE_V2_RETPOLINE;
 }
 
+/* Disable in-kernel use of non-RSB RET predictors */
+static void __init spec_ctrl_disable_kernel_rrsba(void)
+{
+       u64 ia32_cap;
+
+       if (!boot_cpu_has(X86_FEATURE_RRSBA_CTRL))
+               return;
+
+       ia32_cap = x86_read_arch_cap_msr();
+
+       if (ia32_cap & ARCH_CAP_RRSBA) {
+               x86_spec_ctrl_base |= SPEC_CTRL_RRSBA_DIS_S;
+               write_spec_ctrl_current(x86_spec_ctrl_base, true);
+       }
+}
+
 static void __init spectre_v2_select_mitigation(void)
 {
        enum spectre_v2_mitigation_cmd cmd = spectre_v2_parse_cmdline();
@@ -1117,6 +1359,15 @@ static void __init spectre_v2_select_mitigation(void)
                        break;
                }
 
+               if (IS_ENABLED(CONFIG_CPU_IBRS_ENTRY) &&
+                   boot_cpu_has_bug(X86_BUG_RETBLEED) &&
+                   retbleed_cmd != RETBLEED_CMD_OFF &&
+                   boot_cpu_has(X86_FEATURE_IBRS) &&
+                   boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
+                       mode = SPECTRE_V2_IBRS;
+                       break;
+               }
+
                mode = spectre_v2_select_retpoline();
                break;
 
@@ -1133,6 +1384,10 @@ static void __init spectre_v2_select_mitigation(void)
                mode = spectre_v2_select_retpoline();
                break;
 
+       case SPECTRE_V2_CMD_IBRS:
+               mode = SPECTRE_V2_IBRS;
+               break;
+
        case SPECTRE_V2_CMD_EIBRS:
                mode = SPECTRE_V2_EIBRS;
                break;
@@ -1149,10 +1404,9 @@ static void __init spectre_v2_select_mitigation(void)
        if (mode == SPECTRE_V2_EIBRS && unprivileged_ebpf_enabled())
                pr_err(SPECTRE_V2_EIBRS_EBPF_MSG);
 
-       if (spectre_v2_in_eibrs_mode(mode)) {
-               /* Force it so VMEXIT will restore correctly */
+       if (spectre_v2_in_ibrs_mode(mode)) {
                x86_spec_ctrl_base |= SPEC_CTRL_IBRS;
-               wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
+               write_spec_ctrl_current(x86_spec_ctrl_base, true);
        }
 
        switch (mode) {
@@ -1160,6 +1414,12 @@ static void __init spectre_v2_select_mitigation(void)
        case SPECTRE_V2_EIBRS:
                break;
 
+       case SPECTRE_V2_IBRS:
+               setup_force_cpu_cap(X86_FEATURE_KERNEL_IBRS);
+               if (boot_cpu_has(X86_FEATURE_IBRS_ENHANCED))
+                       pr_warn(SPECTRE_V2_IBRS_PERF_MSG);
+               break;
+
        case SPECTRE_V2_LFENCE:
        case SPECTRE_V2_EIBRS_LFENCE:
                setup_force_cpu_cap(X86_FEATURE_RETPOLINE_LFENCE);
@@ -1171,43 +1431,117 @@ static void __init spectre_v2_select_mitigation(void)
                break;
        }
 
+       /*
+        * Disable alternate RSB predictions in kernel when indirect CALLs and
+        * JMPs gets protection against BHI and Intramode-BTI, but RET
+        * prediction from a non-RSB predictor is still a risk.
+        */
+       if (mode == SPECTRE_V2_EIBRS_LFENCE ||
+           mode == SPECTRE_V2_EIBRS_RETPOLINE ||
+           mode == SPECTRE_V2_RETPOLINE)
+               spec_ctrl_disable_kernel_rrsba();
+
        spectre_v2_enabled = mode;
        pr_info("%s\n", spectre_v2_strings[mode]);
 
        /*
-        * If spectre v2 protection has been enabled, unconditionally fill
-        * RSB during a context switch; this protects against two independent
-        * issues:
+        * If Spectre v2 protection has been enabled, fill the RSB during a
+        * context switch.  In general there are two types of RSB attacks
+        * across context switches, for which the CALLs/RETs may be unbalanced.
+        *
+        * 1) RSB underflow
+        *
+        *    Some Intel parts have "bottomless RSB".  When the RSB is empty,
+        *    speculated return targets may come from the branch predictor,
+        *    which could have a user-poisoned BTB or BHB entry.
         *
-        *      - RSB underflow (and switch to BTB) on Skylake+
-        *      - SpectreRSB variant of spectre v2 on X86_BUG_SPECTRE_V2 CPUs
+        *    AMD has it even worse: *all* returns are speculated from the BTB,
+        *    regardless of the state of the RSB.
+        *
+        *    When IBRS or eIBRS is enabled, the "user -> kernel" attack
+        *    scenario is mitigated by the IBRS branch prediction isolation
+        *    properties, so the RSB buffer filling wouldn't be necessary to
+        *    protect against this type of attack.
+        *
+        *    The "user -> user" attack scenario is mitigated by RSB filling.
+        *
+        * 2) Poisoned RSB entry
+        *
+        *    If the 'next' in-kernel return stack is shorter than 'prev',
+        *    'next' could be tricked into speculating with a user-poisoned RSB
+        *    entry.
+        *
+        *    The "user -> kernel" attack scenario is mitigated by SMEP and
+        *    eIBRS.
+        *
+        *    The "user -> user" scenario, also known as SpectreBHB, requires
+        *    RSB clearing.
+        *
+        * So to mitigate all cases, unconditionally fill RSB on context
+        * switches.
+        *
+        * FIXME: Is this pointless for retbleed-affected AMD?
         */
        setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW);
        pr_info("Spectre v2 / SpectreRSB mitigation: Filling RSB on context switch\n");
 
        /*
-        * Retpoline means the kernel is safe because it has no indirect
-        * branches. Enhanced IBRS protects firmware too, so, enable restricted
-        * speculation around firmware calls only when Enhanced IBRS isn't
-        * supported.
+        * Similar to context switches, there are two types of RSB attacks
+        * after vmexit:
+        *
+        * 1) RSB underflow
+        *
+        * 2) Poisoned RSB entry
+        *
+        * When retpoline is enabled, both are mitigated by filling/clearing
+        * the RSB.
+        *
+        * When IBRS is enabled, while #1 would be mitigated by the IBRS branch
+        * prediction isolation protections, RSB still needs to be cleared
+        * because of #2.  Note that SMEP provides no protection here, unlike
+        * user-space-poisoned RSB entries.
+        *
+        * eIBRS, on the other hand, has RSB-poisoning protections, so it
+        * doesn't need RSB clearing after vmexit.
+        */
+       if (boot_cpu_has(X86_FEATURE_RETPOLINE) ||
+           boot_cpu_has(X86_FEATURE_KERNEL_IBRS))
+               setup_force_cpu_cap(X86_FEATURE_RSB_VMEXIT);
+
+       /*
+        * Retpoline protects the kernel, but doesn't protect firmware.  IBRS
+        * and Enhanced IBRS protect firmware too, so enable IBRS around
+        * firmware calls only when IBRS / Enhanced IBRS aren't otherwise
+        * enabled.
         *
         * Use "mode" to check Enhanced IBRS instead of boot_cpu_has(), because
         * the user might select retpoline on the kernel command line and if
         * the CPU supports Enhanced IBRS, kernel might un-intentionally not
         * enable IBRS around firmware calls.
         */
-       if (boot_cpu_has(X86_FEATURE_IBRS) && !spectre_v2_in_eibrs_mode(mode)) {
+       if (boot_cpu_has_bug(X86_BUG_RETBLEED) &&
+           boot_cpu_has(X86_FEATURE_IBPB) &&
+           (boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
+            boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)) {
+
+               if (retbleed_cmd != RETBLEED_CMD_IBPB) {
+                       setup_force_cpu_cap(X86_FEATURE_USE_IBPB_FW);
+                       pr_info("Enabling Speculation Barrier for firmware calls\n");
+               }
+
+       } else if (boot_cpu_has(X86_FEATURE_IBRS) && !spectre_v2_in_ibrs_mode(mode)) {
                setup_force_cpu_cap(X86_FEATURE_USE_IBRS_FW);
                pr_info("Enabling Restricted Speculation for firmware calls\n");
        }
 
        /* Set up IBPB and STIBP depending on the general spectre V2 command */
-       spectre_v2_user_select_mitigation(cmd);
+       spectre_v2_cmd = cmd;
 }
 
 static void update_stibp_msr(void * __unused)
 {
-       wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
+       u64 val = spec_ctrl_current() | (x86_spec_ctrl_base & SPEC_CTRL_STIBP);
+       write_spec_ctrl_current(val, true);
 }
 
 /* Update x86_spec_ctrl_base in case SMT state changed. */
@@ -1424,16 +1758,6 @@ static enum ssb_mitigation __init __ssb_select_mitigation(void)
        }
 
        /*
-        * If SSBD is controlled by the SPEC_CTRL MSR, then set the proper
-        * bit in the mask to allow guests to use the mitigation even in the
-        * case where the host does not enable it.
-        */
-       if (static_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD) ||
-           static_cpu_has(X86_FEATURE_AMD_SSBD)) {
-               x86_spec_ctrl_mask |= SPEC_CTRL_SSBD;
-       }
-
-       /*
         * We have three CPU feature flags that are in play here:
         *  - X86_BUG_SPEC_STORE_BYPASS - CPU is susceptible.
         *  - X86_FEATURE_SSBD - CPU is able to turn off speculative store bypass
@@ -1450,7 +1774,7 @@ static enum ssb_mitigation __init __ssb_select_mitigation(void)
                        x86_amd_ssb_disable();
                } else {
                        x86_spec_ctrl_base |= SPEC_CTRL_SSBD;
-                       wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
+                       write_spec_ctrl_current(x86_spec_ctrl_base, true);
                }
        }
 
@@ -1701,7 +2025,7 @@ int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
 void x86_spec_ctrl_setup_ap(void)
 {
        if (boot_cpu_has(X86_FEATURE_MSR_SPEC_CTRL))
-               wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
+               write_spec_ctrl_current(x86_spec_ctrl_base, true);
 
        if (ssb_mode == SPEC_STORE_BYPASS_DISABLE)
                x86_amd_ssb_disable();
@@ -1938,7 +2262,7 @@ static ssize_t mmio_stale_data_show_state(char *buf)
 
 static char *stibp_state(void)
 {
-       if (spectre_v2_in_eibrs_mode(spectre_v2_enabled))
+       if (spectre_v2_in_ibrs_mode(spectre_v2_enabled))
                return "";
 
        switch (spectre_v2_user_stibp) {
@@ -1994,6 +2318,24 @@ static ssize_t srbds_show_state(char *buf)
        return sprintf(buf, "%s\n", srbds_strings[srbds_mitigation]);
 }
 
+static ssize_t retbleed_show_state(char *buf)
+{
+       if (retbleed_mitigation == RETBLEED_MITIGATION_UNRET) {
+           if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD &&
+               boot_cpu_data.x86_vendor != X86_VENDOR_HYGON)
+                   return sprintf(buf, "Vulnerable: untrained return thunk on non-Zen uarch\n");
+
+           return sprintf(buf, "%s; SMT %s\n",
+                          retbleed_strings[retbleed_mitigation],
+                          !sched_smt_active() ? "disabled" :
+                          spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT ||
+                          spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT_PREFERRED ?
+                          "enabled with STIBP protection" : "vulnerable");
+       }
+
+       return sprintf(buf, "%s\n", retbleed_strings[retbleed_mitigation]);
+}
+
 static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr,
                               char *buf, unsigned int bug)
 {
@@ -2039,6 +2381,9 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr
        case X86_BUG_MMIO_STALE_DATA:
                return mmio_stale_data_show_state(buf);
 
+       case X86_BUG_RETBLEED:
+               return retbleed_show_state(buf);
+
        default:
                break;
        }
@@ -2095,4 +2440,9 @@ ssize_t cpu_show_mmio_stale_data(struct device *dev, struct device_attribute *at
 {
        return cpu_show_common(dev, attr, buf, X86_BUG_MMIO_STALE_DATA);
 }
+
+ssize_t cpu_show_retbleed(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return cpu_show_common(dev, attr, buf, X86_BUG_RETBLEED);
+}
 #endif
index 4730b0a..736262a 100644 (file)
@@ -1205,48 +1205,60 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = {
        {}
 };
 
+#define VULNBL(vendor, family, model, blacklist)       \
+       X86_MATCH_VENDOR_FAM_MODEL(vendor, family, model, blacklist)
+
 #define VULNBL_INTEL_STEPPINGS(model, steppings, issues)                  \
        X86_MATCH_VENDOR_FAM_MODEL_STEPPINGS_FEATURE(INTEL, 6,             \
                                            INTEL_FAM6_##model, steppings, \
                                            X86_FEATURE_ANY, issues)
 
+#define VULNBL_AMD(family, blacklist)          \
+       VULNBL(AMD, family, X86_MODEL_ANY, blacklist)
+
+#define VULNBL_HYGON(family, blacklist)                \
+       VULNBL(HYGON, family, X86_MODEL_ANY, blacklist)
+
 #define SRBDS          BIT(0)
 /* CPU is affected by X86_BUG_MMIO_STALE_DATA */
 #define MMIO           BIT(1)
 /* CPU is affected by Shared Buffers Data Sampling (SBDS), a variant of X86_BUG_MMIO_STALE_DATA */
 #define MMIO_SBDS      BIT(2)
+/* CPU is affected by RETbleed, speculating where you would not expect it */
+#define RETBLEED       BIT(3)
 
 static const struct x86_cpu_id cpu_vuln_blacklist[] __initconst = {
        VULNBL_INTEL_STEPPINGS(IVYBRIDGE,       X86_STEPPING_ANY,               SRBDS),
        VULNBL_INTEL_STEPPINGS(HASWELL,         X86_STEPPING_ANY,               SRBDS),
        VULNBL_INTEL_STEPPINGS(HASWELL_L,       X86_STEPPING_ANY,               SRBDS),
        VULNBL_INTEL_STEPPINGS(HASWELL_G,       X86_STEPPING_ANY,               SRBDS),
-       VULNBL_INTEL_STEPPINGS(HASWELL_X,       BIT(2) | BIT(4),                MMIO),
-       VULNBL_INTEL_STEPPINGS(BROADWELL_D,     X86_STEPPINGS(0x3, 0x5),        MMIO),
+       VULNBL_INTEL_STEPPINGS(HASWELL_X,       X86_STEPPING_ANY,               MMIO),
+       VULNBL_INTEL_STEPPINGS(BROADWELL_D,     X86_STEPPING_ANY,               MMIO),
        VULNBL_INTEL_STEPPINGS(BROADWELL_G,     X86_STEPPING_ANY,               SRBDS),
        VULNBL_INTEL_STEPPINGS(BROADWELL_X,     X86_STEPPING_ANY,               MMIO),
        VULNBL_INTEL_STEPPINGS(BROADWELL,       X86_STEPPING_ANY,               SRBDS),
-       VULNBL_INTEL_STEPPINGS(SKYLAKE_L,       X86_STEPPINGS(0x3, 0x3),        SRBDS | MMIO),
-       VULNBL_INTEL_STEPPINGS(SKYLAKE_L,       X86_STEPPING_ANY,               SRBDS),
-       VULNBL_INTEL_STEPPINGS(SKYLAKE_X,       BIT(3) | BIT(4) | BIT(6) |
-                                               BIT(7) | BIT(0xB),              MMIO),
-       VULNBL_INTEL_STEPPINGS(SKYLAKE,         X86_STEPPINGS(0x3, 0x3),        SRBDS | MMIO),
-       VULNBL_INTEL_STEPPINGS(SKYLAKE,         X86_STEPPING_ANY,               SRBDS),
-       VULNBL_INTEL_STEPPINGS(KABYLAKE_L,      X86_STEPPINGS(0x9, 0xC),        SRBDS | MMIO),
-       VULNBL_INTEL_STEPPINGS(KABYLAKE_L,      X86_STEPPINGS(0x0, 0x8),        SRBDS),
-       VULNBL_INTEL_STEPPINGS(KABYLAKE,        X86_STEPPINGS(0x9, 0xD),        SRBDS | MMIO),
-       VULNBL_INTEL_STEPPINGS(KABYLAKE,        X86_STEPPINGS(0x0, 0x8),        SRBDS),
-       VULNBL_INTEL_STEPPINGS(ICELAKE_L,       X86_STEPPINGS(0x5, 0x5),        MMIO | MMIO_SBDS),
-       VULNBL_INTEL_STEPPINGS(ICELAKE_D,       X86_STEPPINGS(0x1, 0x1),        MMIO),
-       VULNBL_INTEL_STEPPINGS(ICELAKE_X,       X86_STEPPINGS(0x4, 0x6),        MMIO),
-       VULNBL_INTEL_STEPPINGS(COMETLAKE,       BIT(2) | BIT(3) | BIT(5),       MMIO | MMIO_SBDS),
-       VULNBL_INTEL_STEPPINGS(COMETLAKE_L,     X86_STEPPINGS(0x1, 0x1),        MMIO | MMIO_SBDS),
-       VULNBL_INTEL_STEPPINGS(COMETLAKE_L,     X86_STEPPINGS(0x0, 0x0),        MMIO),
-       VULNBL_INTEL_STEPPINGS(LAKEFIELD,       X86_STEPPINGS(0x1, 0x1),        MMIO | MMIO_SBDS),
-       VULNBL_INTEL_STEPPINGS(ROCKETLAKE,      X86_STEPPINGS(0x1, 0x1),        MMIO),
-       VULNBL_INTEL_STEPPINGS(ATOM_TREMONT,    X86_STEPPINGS(0x1, 0x1),        MMIO | MMIO_SBDS),
+       VULNBL_INTEL_STEPPINGS(SKYLAKE_L,       X86_STEPPING_ANY,               SRBDS | MMIO | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(SKYLAKE_X,       X86_STEPPING_ANY,               MMIO | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(SKYLAKE,         X86_STEPPING_ANY,               SRBDS | MMIO | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(KABYLAKE_L,      X86_STEPPING_ANY,               SRBDS | MMIO | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(KABYLAKE,        X86_STEPPING_ANY,               SRBDS | MMIO | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(CANNONLAKE_L,    X86_STEPPING_ANY,               RETBLEED),
+       VULNBL_INTEL_STEPPINGS(ICELAKE_L,       X86_STEPPING_ANY,               MMIO | MMIO_SBDS | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(ICELAKE_D,       X86_STEPPING_ANY,               MMIO),
+       VULNBL_INTEL_STEPPINGS(ICELAKE_X,       X86_STEPPING_ANY,               MMIO),
+       VULNBL_INTEL_STEPPINGS(COMETLAKE,       X86_STEPPING_ANY,               MMIO | MMIO_SBDS | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(COMETLAKE_L,     X86_STEPPINGS(0x0, 0x0),        MMIO | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(COMETLAKE_L,     X86_STEPPING_ANY,               MMIO | MMIO_SBDS | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(LAKEFIELD,       X86_STEPPING_ANY,               MMIO | MMIO_SBDS | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(ROCKETLAKE,      X86_STEPPING_ANY,               MMIO | RETBLEED),
+       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_STEPPINGS(0x0, 0x0),        MMIO | MMIO_SBDS),
+       VULNBL_INTEL_STEPPINGS(ATOM_TREMONT_L,  X86_STEPPING_ANY,               MMIO | MMIO_SBDS),
+
+       VULNBL_AMD(0x15, RETBLEED),
+       VULNBL_AMD(0x16, RETBLEED),
+       VULNBL_AMD(0x17, RETBLEED),
+       VULNBL_HYGON(0x18, RETBLEED),
        {}
 };
 
@@ -1348,6 +1360,11 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
            !arch_cap_mmio_immune(ia32_cap))
                setup_force_cpu_bug(X86_BUG_MMIO_STALE_DATA);
 
+       if (!cpu_has(c, X86_FEATURE_BTC_NO)) {
+               if (cpu_matches(cpu_vuln_blacklist, RETBLEED) || (ia32_cap & ARCH_CAP_RSBA))
+                       setup_force_cpu_bug(X86_BUG_RETBLEED);
+       }
+
        if (cpu_matches(cpu_vuln_whitelist, NO_MELTDOWN))
                return;
 
index 2a8e584..7c9b589 100644 (file)
@@ -61,6 +61,8 @@ static inline void tsx_init(void) { }
 static inline void tsx_ap_init(void) { }
 #endif /* CONFIG_CPU_SUP_INTEL */
 
+extern void init_spectral_chicken(struct cpuinfo_x86 *c);
+
 extern void get_cpu_cap(struct cpuinfo_x86 *c);
 extern void get_cpu_address_sizes(struct cpuinfo_x86 *c);
 extern void cpu_detect_cache_sizes(struct cpuinfo_x86 *c);
index 3fcdda4..21fd425 100644 (file)
@@ -302,6 +302,12 @@ static void init_hygon(struct cpuinfo_x86 *c)
        /* get apicid instead of initial apic id from cpuid */
        c->apicid = hard_smp_processor_id();
 
+       /*
+        * XXX someone from Hygon needs to confirm this DTRT
+        *
+       init_spectral_chicken(c);
+        */
+
        set_cpu_cap(c, X86_FEATURE_ZEN);
        set_cpu_cap(c, X86_FEATURE_CPB);
 
index fd5dead..663f6e6 100644 (file)
@@ -682,9 +682,9 @@ static void init_intel(struct cpuinfo_x86 *c)
                unsigned int l1, l2;
 
                rdmsr(MSR_IA32_MISC_ENABLE, l1, l2);
-               if (!(l1 & (1<<11)))
+               if (!(l1 & MSR_IA32_MISC_ENABLE_BTS_UNAVAIL))
                        set_cpu_cap(c, X86_FEATURE_BTS);
-               if (!(l1 & (1<<12)))
+               if (!(l1 & MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL))
                        set_cpu_cap(c, X86_FEATURE_PEBS);
        }
 
index 5fbd7ff..12cf2e7 100644 (file)
@@ -33,6 +33,8 @@
 
 #include "internal.h"
 
+static bool hw_injection_possible = true;
+
 /*
  * Collect all the MCi_XXX settings
  */
@@ -339,6 +341,8 @@ static int __set_inj(const char *buf)
 
        for (i = 0; i < N_INJ_TYPES; i++) {
                if (!strncmp(flags_options[i], buf, strlen(flags_options[i]))) {
+                       if (i > SW_INJ && !hw_injection_possible)
+                               continue;
                        inj_type = i;
                        return 0;
                }
@@ -717,11 +721,54 @@ static void __init debugfs_init(void)
                                    &i_mce, dfs_fls[i].fops);
 }
 
+static void check_hw_inj_possible(void)
+{
+       int cpu;
+       u8 bank;
+
+       /*
+        * This behavior exists only on SMCA systems though its not directly
+        * related to SMCA.
+        */
+       if (!cpu_feature_enabled(X86_FEATURE_SMCA))
+               return;
+
+       cpu = get_cpu();
+
+       for (bank = 0; bank < MAX_NR_BANKS; ++bank) {
+               u64 status = MCI_STATUS_VAL, ipid;
+
+               /* Check whether bank is populated */
+               rdmsrl(MSR_AMD64_SMCA_MCx_IPID(bank), ipid);
+               if (!ipid)
+                       continue;
+
+               toggle_hw_mce_inject(cpu, true);
+
+               wrmsrl_safe(mca_msr_reg(bank, MCA_STATUS), status);
+               rdmsrl_safe(mca_msr_reg(bank, MCA_STATUS), &status);
+
+               if (!status) {
+                       hw_injection_possible = false;
+                       pr_warn("Platform does not allow *hardware* error injection."
+                               "Try using APEI EINJ instead.\n");
+               }
+
+               toggle_hw_mce_inject(cpu, false);
+
+               break;
+       }
+
+       put_cpu();
+}
+
 static int __init inject_init(void)
 {
        if (!alloc_cpumask_var(&mce_inject_cpumask, GFP_KERNEL))
                return -ENOMEM;
 
+       check_hw_inj_possible();
+
        debugfs_init();
 
        register_nmi_handler(NMI_LOCAL, mce_raise_notify, 0, "mce_notify");
index 4ae0e60..7e03f5b 100644 (file)
@@ -211,7 +211,7 @@ noinstr u64 mce_rdmsrl(u32 msr);
 
 static __always_inline u32 mca_msr_reg(int bank, enum mca_msr reg)
 {
-       if (mce_flags.smca) {
+       if (cpu_feature_enabled(X86_FEATURE_SMCA)) {
                switch (reg) {
                case MCA_CTL:    return MSR_AMD64_SMCA_MCx_CTL(bank);
                case MCA_ADDR:   return MSR_AMD64_SMCA_MCx_ADDR(bank);
index c4be620..26a427f 100644 (file)
 #include <asm/archrandom.h>
 #include <asm/sections.h>
 
-static int __init x86_rdrand_setup(char *s)
-{
-       setup_clear_cpu_cap(X86_FEATURE_RDRAND);
-       setup_clear_cpu_cap(X86_FEATURE_RDSEED);
-       return 1;
-}
-__setup("nordrand", x86_rdrand_setup);
-
 /*
  * RDRAND has Built-In-Self-Test (BIST) that runs on every invocation.
- * Run the instruction a few times as a sanity check.
- * If it fails, it is simple to disable RDRAND here.
+ * Run the instruction a few times as a sanity check. Also make sure
+ * it's not outputting the same value over and over, which has happened
+ * as a result of past CPU bugs.
+ *
+ * If it fails, it is simple to disable RDRAND and RDSEED here.
  */
-#define SANITY_CHECK_LOOPS 8
 
-#ifdef CONFIG_ARCH_RANDOM
 void x86_init_rdrand(struct cpuinfo_x86 *c)
 {
-       unsigned int changed = 0;
-       unsigned long tmp, prev;
-       int i;
+       enum { SAMPLES = 8, MIN_CHANGE = 5 };
+       unsigned long sample, prev;
+       bool failure = false;
+       size_t i, changed;
 
        if (!cpu_has(c, X86_FEATURE_RDRAND))
                return;
 
-       for (i = 0; i < SANITY_CHECK_LOOPS; i++) {
-               if (!rdrand_long(&tmp)) {
-                       clear_cpu_cap(c, X86_FEATURE_RDRAND);
-                       pr_warn_once("rdrand: disabled\n");
-                       return;
+       for (changed = 0, i = 0; i < SAMPLES; ++i) {
+               if (!rdrand_long(&sample)) {
+                       failure = true;
+                       break;
                }
+               changed += i && sample != prev;
+               prev = sample;
        }
+       if (changed < MIN_CHANGE)
+               failure = true;
 
-       /*
-        * Stupid sanity-check whether RDRAND does *actually* generate
-        * some at least random-looking data.
-        */
-       prev = tmp;
-       for (i = 0; i < SANITY_CHECK_LOOPS; i++) {
-               if (rdrand_long(&tmp)) {
-                       if (prev != tmp)
-                               changed++;
-
-                       prev = tmp;
-               }
+       if (failure) {
+               clear_cpu_cap(c, X86_FEATURE_RDRAND);
+               clear_cpu_cap(c, X86_FEATURE_RDSEED);
+               pr_emerg("RDRAND is not reliable on this platform; disabling.\n");
        }
-
-       if (WARN_ON_ONCE(!changed))
-               pr_emerg(
-"RDRAND gives funky smelling output, might consider not using it by booting with \"nordrand\"");
-
 }
-#endif
index dbaa832..fd44b54 100644 (file)
@@ -27,6 +27,7 @@ static const struct cpuid_bit cpuid_bits[] = {
        { X86_FEATURE_APERFMPERF,       CPUID_ECX,  0, 0x00000006, 0 },
        { X86_FEATURE_EPB,              CPUID_ECX,  3, 0x00000006, 0 },
        { X86_FEATURE_INTEL_PPIN,       CPUID_EBX,  0, 0x00000007, 1 },
+       { X86_FEATURE_RRSBA_CTRL,       CPUID_EDX,  2, 0x00000007, 2 },
        { X86_FEATURE_CQM_LLC,          CPUID_EDX,  1, 0x0000000f, 0 },
        { X86_FEATURE_CQM_OCCUP_LLC,    CPUID_EDX,  0, 0x0000000f, 1 },
        { X86_FEATURE_CQM_MBM_TOTAL,    CPUID_EDX,  1, 0x0000000f, 1 },
index c04b933..02039ec 100644 (file)
@@ -476,8 +476,8 @@ static bool __init vmware_legacy_x2apic_available(void)
 {
        uint32_t eax, ebx, ecx, edx;
        VMWARE_CMD(GETVCPU_INFO, eax, ebx, ecx, edx);
-       return (eax & (1 << VMWARE_CMD_VCPU_RESERVED)) == 0 &&
-              (eax & (1 << VMWARE_CMD_LEGACY_X2APIC)) != 0;
+       return !(eax & BIT(VMWARE_CMD_VCPU_RESERVED)) &&
+               (eax & BIT(VMWARE_CMD_LEGACY_X2APIC));
 }
 
 #ifdef CONFIG_AMD_MEM_ENCRYPT
index f267205..9dac246 100644 (file)
@@ -1017,10 +1017,10 @@ 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 is supplied by kexec and does not need to be
-                * reserved.
+                * SETUP_EFI and SETUP_IMA are supplied by kexec and do not need
+                * to be reserved.
                 */
-               if (data->type != SETUP_EFI)
+               if (data->type != SETUP_EFI && data->type != SETUP_IMA)
                        e820__range_update_kexec(pa_data,
                                                 sizeof(*data) + data->len,
                                                 E820_TYPE_RAM, E820_TYPE_RESERVED_KERN);
index 4fe7af5..9417d5a 100644 (file)
@@ -100,7 +100,7 @@ static void init_espfix_random(void)
         * This is run before the entropy pools are initialized,
         * but this is hopefully better than nothing.
         */
-       if (!arch_get_random_long(&rand)) {
+       if (!arch_get_random_longs(&rand, 1)) {
                /* The constant is an arbitrary large prime */
                rand = rdtsc();
                rand *= 0xc345c6b72fd16123UL;
index 0531d6a..3b28c5b 100644 (file)
@@ -851,3 +851,17 @@ int fpu__exception_code(struct fpu *fpu, int trap_nr)
         */
        return 0;
 }
+
+/*
+ * Initialize register state that may prevent from entering low-power idle.
+ * This function will be invoked from the cpuidle driver only when needed.
+ */
+void fpu_idle_fpregs(void)
+{
+       /* Note: AMX_TILE being enabled implies XGETBV1 support */
+       if (cpu_feature_enabled(X86_FEATURE_AMX_TILE) &&
+           (xfeatures_in_use() & XFEATURE_MASK_XTILE)) {
+               tile_release();
+               fpregs_deactivate(&current->thread.fpu);
+       }
+}
index 5b4efc9..24b9fa8 100644 (file)
@@ -301,7 +301,7 @@ union ftrace_op_code_union {
        } __attribute__((packed));
 };
 
-#define RET_SIZE               1 + IS_ENABLED(CONFIG_SLS)
+#define RET_SIZE               (IS_ENABLED(CONFIG_RETPOLINE) ? 5 : 1 + IS_ENABLED(CONFIG_SLS))
 
 static unsigned long
 create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)
@@ -357,7 +357,10 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)
                goto fail;
 
        ip = trampoline + size;
-       memcpy(ip, retq, RET_SIZE);
+       if (cpu_feature_enabled(X86_FEATURE_RETHUNK))
+               __text_gen_insn(ip, JMP32_INSN_OPCODE, ip, &__x86_return_thunk, JMP32_INSN_SIZE);
+       else
+               memcpy(ip, retq, sizeof(retq));
 
        /* No need to test direct calls on created trampolines */
        if (ops->flags & FTRACE_OPS_FL_SAVE_REGS) {
index bd4a341..6a3cfaf 100644 (file)
@@ -426,10 +426,12 @@ void __init do_early_exception(struct pt_regs *regs, int trapnr)
 
 /* Don't add a printk in there. printk relies on the PDA which is not initialized 
    yet. */
-static void __init clear_bss(void)
+void __init clear_bss(void)
 {
        memset(__bss_start, 0,
               (unsigned long) __bss_stop - (unsigned long) __bss_start);
+       memset(__brk_base, 0,
+              (unsigned long) __brk_limit - (unsigned long) __brk_base);
 }
 
 static unsigned long get_cmd_line_ptr(void)
index eb8656b..9b7acc9 100644 (file)
@@ -23,6 +23,7 @@
 #include <asm/cpufeatures.h>
 #include <asm/percpu.h>
 #include <asm/nops.h>
+#include <asm/nospec-branch.h>
 #include <asm/bootparam.h>
 #include <asm/export.h>
 #include <asm/pgtable_32.h>
index 92c4afa..d860d43 100644 (file)
@@ -389,6 +389,8 @@ SYM_CODE_START_NOALIGN(vc_boot_ghcb)
        UNWIND_HINT_IRET_REGS offset=8
        ENDBR
 
+       ANNOTATE_UNRET_END
+
        /* Build pt_regs */
        PUSH_AND_CLEAR_REGS
 
@@ -448,6 +450,7 @@ SYM_CODE_END(early_idt_handler_array)
 
 SYM_CODE_START_LOCAL(early_idt_handler_common)
        UNWIND_HINT_IRET_REGS offset=16
+       ANNOTATE_UNRET_END
        /*
         * The stack is the hardware frame, an error code or zero, and the
         * vector number.
@@ -497,6 +500,8 @@ SYM_CODE_START_NOALIGN(vc_no_ghcb)
        UNWIND_HINT_IRET_REGS offset=8
        ENDBR
 
+       ANNOTATE_UNRET_END
+
        /* Build pt_regs */
        PUSH_AND_CLEAR_REGS
 
index 68f091b..f5b8ef0 100644 (file)
@@ -146,16 +146,3 @@ void arch_jump_label_transform_apply(void)
        text_poke_finish();
        mutex_unlock(&text_mutex);
 }
-
-static enum {
-       JL_STATE_START,
-       JL_STATE_NO_UPDATE,
-       JL_STATE_UPDATE,
-} jlstate __initdata_or_module = JL_STATE_START;
-
-__init_or_module void arch_jump_label_transform_static(struct jump_entry *entry,
-                                     enum jump_label_type type)
-{
-       if (jlstate == JL_STATE_UPDATE)
-               jump_label_transform(entry, type, 1);
-}
index 170d0fd..6b58610 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/efi.h>
-#include <linux/verification.h>
+#include <linux/random.h>
 
 #include <asm/bootparam.h>
 #include <asm/setup.h>
@@ -110,6 +110,26 @@ static int setup_e820_entries(struct boot_params *params)
        return 0;
 }
 
+enum { RNG_SEED_LENGTH = 32 };
+
+static void
+setup_rng_seed(struct boot_params *params, unsigned long params_load_addr,
+              unsigned int rng_seed_setup_data_offset)
+{
+       struct setup_data *sd = (void *)params + rng_seed_setup_data_offset;
+       unsigned long setup_data_phys;
+
+       if (!rng_is_initialized())
+               return;
+
+       sd->type = SETUP_RNG_SEED;
+       sd->len = RNG_SEED_LENGTH;
+       get_random_bytes(sd->data, RNG_SEED_LENGTH);
+       setup_data_phys = params_load_addr + rng_seed_setup_data_offset;
+       sd->next = params->hdr.setup_data;
+       params->hdr.setup_data = setup_data_phys;
+}
+
 #ifdef CONFIG_EFI
 static int setup_efi_info_memmap(struct boot_params *params,
                                  unsigned long params_load_addr,
@@ -186,11 +206,38 @@ setup_efi_state(struct boot_params *params, unsigned long params_load_addr,
 }
 #endif /* CONFIG_EFI */
 
+static void
+setup_ima_state(const struct kimage *image, struct boot_params *params,
+               unsigned long params_load_addr,
+               unsigned int ima_setup_data_offset)
+{
+#ifdef CONFIG_IMA_KEXEC
+       struct setup_data *sd = (void *)params + ima_setup_data_offset;
+       unsigned long setup_data_phys;
+       struct ima_setup_data *ima;
+
+       if (!image->ima_buffer_size)
+               return;
+
+       sd->type = SETUP_IMA;
+       sd->len = sizeof(*ima);
+
+       ima = (void *)sd + sizeof(struct setup_data);
+       ima->addr = image->ima_buffer_addr;
+       ima->size = image->ima_buffer_size;
+
+       /* Add setup data */
+       setup_data_phys = params_load_addr + ima_setup_data_offset;
+       sd->next = params->hdr.setup_data;
+       params->hdr.setup_data = setup_data_phys;
+#endif /* CONFIG_IMA_KEXEC */
+}
+
 static int
 setup_boot_parameters(struct kimage *image, struct boot_params *params,
                      unsigned long params_load_addr,
                      unsigned int efi_map_offset, unsigned int efi_map_sz,
-                     unsigned int efi_setup_data_offset)
+                     unsigned int setup_data_offset)
 {
        unsigned int nr_e820_entries;
        unsigned long long mem_k, start, end;
@@ -245,8 +292,22 @@ setup_boot_parameters(struct kimage *image, struct boot_params *params,
 #ifdef CONFIG_EFI
        /* Setup EFI state */
        setup_efi_state(params, params_load_addr, efi_map_offset, efi_map_sz,
-                       efi_setup_data_offset);
+                       setup_data_offset);
+       setup_data_offset += sizeof(struct setup_data) +
+                       sizeof(struct efi_setup_data);
 #endif
+
+       if (IS_ENABLED(CONFIG_IMA_KEXEC)) {
+               /* Setup IMA log buffer state */
+               setup_ima_state(image, params, params_load_addr,
+                               setup_data_offset);
+               setup_data_offset += sizeof(struct setup_data) +
+                                    sizeof(struct ima_setup_data);
+       }
+
+       /* Setup RNG seed */
+       setup_rng_seed(params, params_load_addr, setup_data_offset);
+
        /* Setup EDD info */
        memcpy(params->eddbuf, boot_params.eddbuf,
                                EDDMAXNR * sizeof(struct edd_info));
@@ -401,7 +462,13 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
        params_cmdline_sz = ALIGN(params_cmdline_sz, 16);
        kbuf.bufsz = params_cmdline_sz + ALIGN(efi_map_sz, 16) +
                                sizeof(struct setup_data) +
-                               sizeof(struct efi_setup_data);
+                               sizeof(struct efi_setup_data) +
+                               sizeof(struct setup_data) +
+                               RNG_SEED_LENGTH;
+
+       if (IS_ENABLED(CONFIG_IMA_KEXEC))
+               kbuf.bufsz += sizeof(struct setup_data) +
+                             sizeof(struct ima_setup_data);
 
        params = kzalloc(kbuf.bufsz, GFP_KERNEL);
        if (!params)
@@ -528,28 +595,11 @@ static int bzImage64_cleanup(void *loader_data)
        return 0;
 }
 
-#ifdef CONFIG_KEXEC_BZIMAGE_VERIFY_SIG
-static int bzImage64_verify_sig(const char *kernel, unsigned long kernel_len)
-{
-       int ret;
-
-       ret = verify_pefile_signature(kernel, kernel_len,
-                                     VERIFY_USE_SECONDARY_KEYRING,
-                                     VERIFYING_KEXEC_PE_SIGNATURE);
-       if (ret == -ENOKEY && IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING)) {
-               ret = verify_pefile_signature(kernel, kernel_len,
-                                             VERIFY_USE_PLATFORM_KEYRING,
-                                             VERIFYING_KEXEC_PE_SIGNATURE);
-       }
-       return ret;
-}
-#endif
-
 const struct kexec_file_ops kexec_bzImage64_ops = {
        .probe = bzImage64_probe,
        .load = bzImage64_load,
        .cleanup = bzImage64_cleanup,
 #ifdef CONFIG_KEXEC_BZIMAGE_VERIFY_SIG
-       .verify_sig = bzImage64_verify_sig,
+       .verify_sig = kexec_kernel_verify_pe_sig,
 #endif
 };
index b98ffcf..b1abf66 100644 (file)
@@ -253,7 +253,7 @@ int module_finalize(const Elf_Ehdr *hdr,
 {
        const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL,
                *para = NULL, *orc = NULL, *orc_ip = NULL,
-               *retpolines = NULL, *ibt_endbr = NULL;
+               *retpolines = NULL, *returns = NULL, *ibt_endbr = NULL;
        char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
 
        for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
@@ -271,6 +271,8 @@ int module_finalize(const Elf_Ehdr *hdr,
                        orc_ip = s;
                if (!strcmp(".retpoline_sites", secstrings + s->sh_name))
                        retpolines = s;
+               if (!strcmp(".return_sites", secstrings + s->sh_name))
+                       returns = s;
                if (!strcmp(".ibt_endbr_seal", secstrings + s->sh_name))
                        ibt_endbr = s;
        }
@@ -287,6 +289,10 @@ int module_finalize(const Elf_Ehdr *hdr,
                void *rseg = (void *)retpolines->sh_addr;
                apply_retpolines(rseg, rseg + retpolines->sh_size);
        }
+       if (returns) {
+               void *rseg = (void *)returns->sh_addr;
+               apply_returns(rseg, rseg + returns->sh_size);
+       }
        if (alt) {
                /* patch .altinstructions */
                void *aseg = (void *)alt->sh_addr;
@@ -304,9 +310,6 @@ int module_finalize(const Elf_Ehdr *hdr,
                                            tseg, tseg + text->sh_size);
        }
 
-       /* make jump label nops */
-       jump_label_apply_nops(me);
-
        if (orc && orc_ip)
                unwind_module_init(me, (void *)orc_ip->sh_addr, orc_ip->sh_size,
                                   (void *)orc->sh_addr, orc->sh_size);
index 6b07faa..23154d2 100644 (file)
@@ -27,6 +27,11 @@ static __init int register_e820_pmem(void)
         * simply here to trigger the module to load on demand.
         */
        pdev = platform_device_alloc("e820_pmem", -1);
-       return platform_device_add(pdev);
+
+       rc = platform_device_add(pdev);
+       if (rc)
+               platform_device_put(pdev);
+
+       return rc;
 }
 device_initcall(register_e820_pmem);
index 9b2772b..58a6ea4 100644 (file)
@@ -600,7 +600,7 @@ static __always_inline void __speculation_ctrl_update(unsigned long tifp,
        }
 
        if (updmsr)
-               wrmsrl(MSR_IA32_SPEC_CTRL, msr);
+               write_spec_ctrl_current(msr, false);
 }
 
 static unsigned long speculation_ctrl_update_tif(struct task_struct *tsk)
@@ -810,24 +810,43 @@ static void amd_e400_idle(void)
 }
 
 /*
- * Intel Core2 and older machines prefer MWAIT over HALT for C1.
- * We can't rely on cpuidle installing MWAIT, because it will not load
- * on systems that support only C1 -- so the boot default must be MWAIT.
+ * Prefer MWAIT over HALT if MWAIT is supported, MWAIT_CPUID leaf
+ * exists and whenever MONITOR/MWAIT extensions are present there is at
+ * least one C1 substate.
  *
- * Some AMD machines are the opposite, they depend on using HALT.
- *
- * So for default C1, which is used during boot until cpuidle loads,
- * use MWAIT-C1 on Intel HW that has it, else use HALT.
+ * 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)
 {
-       if (c->x86_vendor != X86_VENDOR_INTEL)
+       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 (!cpu_has(c, X86_FEATURE_MWAIT) || boot_cpu_has_bug(X86_BUG_MONITOR))
+       /* MWAIT is not supported on this platform. Fallback to HALT */
+       if (!cpu_has(c, X86_FEATURE_MWAIT))
                return 0;
 
-       return 1;
+       /* Monitor has a bug. Fallback to HALT */
+       if (boot_cpu_has_bug(X86_BUG_MONITOR))
+               return 0;
+
+       cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &edx);
+
+       /*
+        * If MWAIT extensions are not available, it is safe to use MWAIT
+        * with EAX=0, ECX=0.
+        */
+       if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED))
+               return 1;
+
+       /*
+        * If MWAIT extensions are available, there should be at least one
+        * MWAIT C1 substate present.
+        */
+       return (edx & MWAIT_C1_SUBSTATE_MASK);
 }
 
 /*
@@ -932,9 +951,8 @@ static int __init idle_setup(char *str)
        } else if (!strcmp(str, "nomwait")) {
                /*
                 * If the boot option of "idle=nomwait" is added,
-                * it means that mwait will be disabled for CPU C2/C3
-                * states. In such case it won't touch the variable
-                * of boot_option_idle_override.
+                * it means that mwait will be disabled for CPU C1/C2/C3
+                * states.
                 */
                boot_option_idle_override = IDLE_NOMWAIT;
        } else
index fcc8a76..c7c4b19 100644 (file)
@@ -7,10 +7,12 @@
 #include <linux/linkage.h>
 #include <asm/page_types.h>
 #include <asm/kexec.h>
+#include <asm/nospec-branch.h>
 #include <asm/processor-flags.h>
 
 /*
- * Must be relocatable PIC code callable as a C function
+ * Must be relocatable PIC code callable as a C function, in particular
+ * there must be a plain RET and not jump to return thunk.
  */
 
 #define PTR(x) (x << 2)
@@ -91,7 +93,9 @@ SYM_CODE_START_NOALIGN(relocate_kernel)
        movl    %edi, %eax
        addl    $(identity_mapped - relocate_kernel), %eax
        pushl   %eax
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 SYM_CODE_END(relocate_kernel)
 
 SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
@@ -159,12 +163,15 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
        xorl    %edx, %edx
        xorl    %esi, %esi
        xorl    %ebp, %ebp
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 1:
        popl    %edx
        movl    CP_PA_SWAP_PAGE(%edi), %esp
        addl    $PAGE_SIZE, %esp
 2:
+       ANNOTATE_RETPOLINE_SAFE
        call    *%edx
 
        /* get the re-entry point of the peer system */
@@ -190,7 +197,9 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
        movl    %edi, %eax
        addl    $(virtual_mapped - relocate_kernel), %eax
        pushl   %eax
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 SYM_CODE_END(identity_mapped)
 
 SYM_CODE_START_LOCAL_NOALIGN(virtual_mapped)
@@ -208,7 +217,9 @@ SYM_CODE_START_LOCAL_NOALIGN(virtual_mapped)
        popl    %edi
        popl    %esi
        popl    %ebx
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 SYM_CODE_END(virtual_mapped)
 
        /* Do the copies */
@@ -271,7 +282,9 @@ SYM_CODE_START_LOCAL_NOALIGN(swap_pages)
        popl    %edi
        popl    %ebx
        popl    %ebp
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 SYM_CODE_END(swap_pages)
 
        .globl kexec_control_code_size
index c1d8626..4809c0d 100644 (file)
@@ -13,7 +13,8 @@
 #include <asm/unwind_hints.h>
 
 /*
- * Must be relocatable PIC code callable as a C function
+ * Must be relocatable PIC code callable as a C function, in particular
+ * there must be a plain RET and not jump to return thunk.
  */
 
 #define PTR(x) (x << 3)
@@ -105,7 +106,9 @@ SYM_CODE_START_NOALIGN(relocate_kernel)
        /* jump to identity mapped page */
        addq    $(identity_mapped - relocate_kernel), %r8
        pushq   %r8
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 SYM_CODE_END(relocate_kernel)
 
 SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
@@ -200,7 +203,9 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
        xorl    %r14d, %r14d
        xorl    %r15d, %r15d
 
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 
 1:
        popq    %rdx
@@ -219,7 +224,9 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
        call    swap_pages
        movq    $virtual_mapped, %rax
        pushq   %rax
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 SYM_CODE_END(identity_mapped)
 
 SYM_CODE_START_LOCAL_NOALIGN(virtual_mapped)
@@ -241,7 +248,9 @@ SYM_CODE_START_LOCAL_NOALIGN(virtual_mapped)
        popq    %r12
        popq    %rbp
        popq    %rbx
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 SYM_CODE_END(virtual_mapped)
 
        /* Do the copies */
@@ -298,7 +307,9 @@ SYM_CODE_START_LOCAL_NOALIGN(swap_pages)
        lea     PAGE_SIZE(%rax), %rsi
        jmp     0b
 3:
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 SYM_CODE_END(swap_pages)
 
        .globl kexec_control_code_size
index bd6c6fd..216fee7 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/dma-map-ops.h>
 #include <linux/dmi.h>
 #include <linux/efi.h>
+#include <linux/ima.h>
 #include <linux/init_ohci1394_dma.h>
 #include <linux/initrd.h>
 #include <linux/iscsi_ibft.h>
@@ -23,6 +24,7 @@
 #include <linux/usb/xhci-dbgp.h>
 #include <linux/static_call.h>
 #include <linux/swiotlb.h>
+#include <linux/random.h>
 
 #include <uapi/linux/mount.h>
 
@@ -140,6 +142,11 @@ __visible unsigned long mmu_cr4_features __ro_after_init;
 __visible unsigned long mmu_cr4_features __ro_after_init = X86_CR4_PAE;
 #endif
 
+#ifdef CONFIG_IMA
+static phys_addr_t ima_kexec_buffer_phys;
+static size_t ima_kexec_buffer_size;
+#endif
+
 /* Boot loader ID and version as integers, for the benefit of proc_dointvec */
 int bootloader_type, bootloader_version;
 
@@ -330,6 +337,60 @@ static void __init reserve_initrd(void)
 }
 #endif /* CONFIG_BLK_DEV_INITRD */
 
+static void __init add_early_ima_buffer(u64 phys_addr)
+{
+#ifdef CONFIG_IMA
+       struct ima_setup_data *data;
+
+       data = early_memremap(phys_addr + sizeof(struct setup_data), sizeof(*data));
+       if (!data) {
+               pr_warn("setup: failed to memremap ima_setup_data entry\n");
+               return;
+       }
+
+       if (data->size) {
+               memblock_reserve(data->addr, data->size);
+               ima_kexec_buffer_phys = data->addr;
+               ima_kexec_buffer_size = data->size;
+       }
+
+       early_memunmap(data, sizeof(*data));
+#else
+       pr_warn("Passed IMA kexec data, but CONFIG_IMA not set. Ignoring.\n");
+#endif
+}
+
+#if defined(CONFIG_HAVE_IMA_KEXEC) && !defined(CONFIG_OF_FLATTREE)
+int __init ima_free_kexec_buffer(void)
+{
+       int rc;
+
+       if (!ima_kexec_buffer_size)
+               return -ENOENT;
+
+       rc = memblock_phys_free(ima_kexec_buffer_phys,
+                               ima_kexec_buffer_size);
+       if (rc)
+               return rc;
+
+       ima_kexec_buffer_phys = 0;
+       ima_kexec_buffer_size = 0;
+
+       return 0;
+}
+
+int __init ima_get_kexec_buffer(void **addr, size_t *size)
+{
+       if (!ima_kexec_buffer_size)
+               return -ENOENT;
+
+       *addr = __va(ima_kexec_buffer_phys);
+       *size = ima_kexec_buffer_size;
+
+       return 0;
+}
+#endif
+
 static void __init parse_setup_data(void)
 {
        struct setup_data *data;
@@ -355,6 +416,18 @@ static void __init parse_setup_data(void)
                case SETUP_EFI:
                        parse_efi_setup(pa_data, data_len);
                        break;
+               case SETUP_IMA:
+                       add_early_ima_buffer(pa_data);
+                       break;
+               case SETUP_RNG_SEED:
+                       data = early_memremap(pa_data, data_len);
+                       add_bootloader_randomness(data->data, data->len);
+                       /* Zero seed for forward secrecy. */
+                       memzero_explicit(data->data, data->len);
+                       /* Zero length in case we find ourselves back here by accident. */
+                       memzero_explicit(&data->len, sizeof(data->len));
+                       early_memunmap(data, data_len);
+                       break;
                default:
                        break;
                }
index b478edf..3a5b0c9 100644 (file)
@@ -219,9 +219,10 @@ static enum es_result verify_exception_info(struct ghcb *ghcb, struct es_em_ctxt
        return ES_VMM_ERROR;
 }
 
-enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb, bool set_ghcb_msr,
-                                  struct es_em_ctxt *ctxt, u64 exit_code,
-                                  u64 exit_info_1, u64 exit_info_2)
+static enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb,
+                                         struct es_em_ctxt *ctxt,
+                                         u64 exit_code, u64 exit_info_1,
+                                         u64 exit_info_2)
 {
        /* Fill in protocol and format specifiers */
        ghcb->protocol_version = ghcb_version;
@@ -231,14 +232,7 @@ enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb, bool set_ghcb_msr,
        ghcb_set_sw_exit_info_1(ghcb, exit_info_1);
        ghcb_set_sw_exit_info_2(ghcb, exit_info_2);
 
-       /*
-        * Hyper-V unenlightened guests use a paravisor for communicating and
-        * GHCB pages are being allocated and set up by that paravisor. Linux
-        * should not change the GHCB page's physical address.
-        */
-       if (set_ghcb_msr)
-               sev_es_wr_ghcb_msr(__pa(ghcb));
-
+       sev_es_wr_ghcb_msr(__pa(ghcb));
        VMGEXIT();
 
        return verify_exception_info(ghcb, ctxt);
@@ -795,7 +789,7 @@ static enum es_result vc_handle_ioio(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
                 */
                sw_scratch = __pa(ghcb) + offsetof(struct ghcb, shared_buffer);
                ghcb_set_sw_scratch(ghcb, sw_scratch);
-               ret = sev_es_ghcb_hv_call(ghcb, true, ctxt, SVM_EXIT_IOIO,
+               ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_IOIO,
                                          exit_info_1, exit_info_2);
                if (ret != ES_OK)
                        return ret;
@@ -837,8 +831,7 @@ static enum es_result vc_handle_ioio(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
 
                ghcb_set_rax(ghcb, rax);
 
-               ret = sev_es_ghcb_hv_call(ghcb, true, ctxt,
-                                         SVM_EXIT_IOIO, exit_info_1, 0);
+               ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_IOIO, exit_info_1, 0);
                if (ret != ES_OK)
                        return ret;
 
@@ -894,7 +887,7 @@ static enum es_result vc_handle_cpuid(struct ghcb *ghcb,
                /* xgetbv will cause #GP - use reset value for xcr0 */
                ghcb_set_xcr0(ghcb, 1);
 
-       ret = sev_es_ghcb_hv_call(ghcb, true, ctxt, SVM_EXIT_CPUID, 0, 0);
+       ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_CPUID, 0, 0);
        if (ret != ES_OK)
                return ret;
 
@@ -919,7 +912,7 @@ static enum es_result vc_handle_rdtsc(struct ghcb *ghcb,
        bool rdtscp = (exit_code == SVM_EXIT_RDTSCP);
        enum es_result ret;
 
-       ret = sev_es_ghcb_hv_call(ghcb, true, ctxt, exit_code, 0, 0);
+       ret = sev_es_ghcb_hv_call(ghcb, ctxt, exit_code, 0, 0);
        if (ret != ES_OK)
                return ret;
 
index c05f012..63dc626 100644 (file)
@@ -786,7 +786,7 @@ static int vmgexit_psc(struct snp_psc_desc *desc)
                ghcb_set_sw_scratch(ghcb, (u64)__pa(data));
 
                /* This will advance the shared buffer data points to. */
-               ret = sev_es_ghcb_hv_call(ghcb, true, &ctxt, SVM_VMGEXIT_PSC, 0, 0);
+               ret = sev_es_ghcb_hv_call(ghcb, &ctxt, SVM_VMGEXIT_PSC, 0, 0);
 
                /*
                 * Page State Change VMGEXIT can pass error code through
@@ -1212,8 +1212,7 @@ static enum es_result vc_handle_msr(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
                ghcb_set_rdx(ghcb, regs->dx);
        }
 
-       ret = sev_es_ghcb_hv_call(ghcb, true, ctxt, SVM_EXIT_MSR,
-                                 exit_info_1, 0);
+       ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_MSR, exit_info_1, 0);
 
        if ((ret == ES_OK) && (!exit_info_1)) {
                regs->ax = ghcb->save.rax;
@@ -1452,7 +1451,7 @@ static enum es_result vc_do_mmio(struct ghcb *ghcb, struct es_em_ctxt *ctxt,
 
        ghcb_set_sw_scratch(ghcb, ghcb_pa + offsetof(struct ghcb, shared_buffer));
 
-       return sev_es_ghcb_hv_call(ghcb, true, ctxt, exit_code, exit_info_1, exit_info_2);
+       return sev_es_ghcb_hv_call(ghcb, ctxt, exit_code, exit_info_1, exit_info_2);
 }
 
 /*
@@ -1628,7 +1627,7 @@ static enum es_result vc_handle_dr7_write(struct ghcb *ghcb,
 
        /* Using a value of 0 for ExitInfo1 means RAX holds the value */
        ghcb_set_rax(ghcb, val);
-       ret = sev_es_ghcb_hv_call(ghcb, true, ctxt, SVM_EXIT_WRITE_DR7, 0, 0);
+       ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_WRITE_DR7, 0, 0);
        if (ret != ES_OK)
                return ret;
 
@@ -1658,7 +1657,7 @@ static enum es_result vc_handle_dr7_read(struct ghcb *ghcb,
 static enum es_result vc_handle_wbinvd(struct ghcb *ghcb,
                                       struct es_em_ctxt *ctxt)
 {
-       return sev_es_ghcb_hv_call(ghcb, true, ctxt, SVM_EXIT_WBINVD, 0, 0);
+       return sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_WBINVD, 0, 0);
 }
 
 static enum es_result vc_handle_rdpmc(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
@@ -1667,7 +1666,7 @@ static enum es_result vc_handle_rdpmc(struct ghcb *ghcb, struct es_em_ctxt *ctxt
 
        ghcb_set_rcx(ghcb, ctxt->regs->cx);
 
-       ret = sev_es_ghcb_hv_call(ghcb, true, ctxt, SVM_EXIT_RDPMC, 0, 0);
+       ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_RDPMC, 0, 0);
        if (ret != ES_OK)
                return ret;
 
@@ -1708,7 +1707,7 @@ static enum es_result vc_handle_vmmcall(struct ghcb *ghcb,
        if (x86_platform.hyper.sev_es_hcall_prepare)
                x86_platform.hyper.sev_es_hcall_prepare(ghcb, ctxt->regs);
 
-       ret = sev_es_ghcb_hv_call(ghcb, true, ctxt, SVM_EXIT_VMMCALL, 0, 0);
+       ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_VMMCALL, 0, 0);
        if (ret != ES_OK)
                return ret;
 
@@ -2197,7 +2196,7 @@ int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, unsigned
                ghcb_set_rbx(ghcb, input->data_npages);
        }
 
-       ret = sev_es_ghcb_hv_call(ghcb, true, &ctxt, exit_code, input->req_gpa, input->resp_gpa);
+       ret = sev_es_ghcb_hv_call(ghcb, &ctxt, exit_code, input->req_gpa, input->resp_gpa);
        if (ret)
                goto e_put;
 
index aa72cef..aaaba85 100644 (file)
@@ -12,13 +12,21 @@ enum insn_type {
 };
 
 /*
+ * ud1 %esp, %ecx - a 3 byte #UD that is unique to trampolines, chosen such
+ * that there is no false-positive trampoline identification while also being a
+ * speculation stop.
+ */
+static const u8 tramp_ud[] = { 0x0f, 0xb9, 0xcc };
+
+/*
  * cs cs cs xorl %eax, %eax - a single 5 byte instruction that clears %[er]ax
  */
 static const u8 xor5rax[] = { 0x2e, 0x2e, 0x2e, 0x31, 0xc0 };
 
 static const u8 retinsn[] = { RET_INSN_OPCODE, 0xcc, 0xcc, 0xcc, 0xcc };
 
-static void __ref __static_call_transform(void *insn, enum insn_type type, void *func)
+static void __ref __static_call_transform(void *insn, enum insn_type type,
+                                         void *func, bool modinit)
 {
        const void *emulate = NULL;
        int size = CALL_INSN_SIZE;
@@ -43,14 +51,17 @@ static void __ref __static_call_transform(void *insn, enum insn_type type, void
                break;
 
        case RET:
-               code = &retinsn;
+               if (cpu_feature_enabled(X86_FEATURE_RETHUNK))
+                       code = text_gen_insn(JMP32_INSN_OPCODE, insn, &__x86_return_thunk);
+               else
+                       code = &retinsn;
                break;
        }
 
        if (memcmp(insn, code, size) == 0)
                return;
 
-       if (unlikely(system_state == SYSTEM_BOOTING))
+       if (system_state == SYSTEM_BOOTING || modinit)
                return text_poke_early(insn, code, size);
 
        text_poke_bp(insn, code, size, emulate);
@@ -60,7 +71,7 @@ static void __static_call_validate(void *insn, bool tail, bool tramp)
 {
        u8 opcode = *(u8 *)insn;
 
-       if (tramp && memcmp(insn+5, "SCT", 3)) {
+       if (tramp && memcmp(insn+5, tramp_ud, 3)) {
                pr_err("trampoline signature fail");
                BUG();
        }
@@ -104,14 +115,42 @@ void arch_static_call_transform(void *site, void *tramp, void *func, bool tail)
 
        if (tramp) {
                __static_call_validate(tramp, true, true);
-               __static_call_transform(tramp, __sc_insn(!func, true), func);
+               __static_call_transform(tramp, __sc_insn(!func, true), func, false);
        }
 
        if (IS_ENABLED(CONFIG_HAVE_STATIC_CALL_INLINE) && site) {
                __static_call_validate(site, tail, false);
-               __static_call_transform(site, __sc_insn(!func, tail), func);
+               __static_call_transform(site, __sc_insn(!func, tail), func, false);
        }
 
        mutex_unlock(&text_mutex);
 }
 EXPORT_SYMBOL_GPL(arch_static_call_transform);
+
+#ifdef CONFIG_RETHUNK
+/*
+ * This is called by apply_returns() to fix up static call trampolines,
+ * specifically ARCH_DEFINE_STATIC_CALL_NULL_TRAMP which is recorded as
+ * having a return trampoline.
+ *
+ * The problem is that static_call() is available before determining
+ * X86_FEATURE_RETHUNK and, by implication, running alternatives.
+ *
+ * This means that __static_call_transform() above can have overwritten the
+ * return trampoline and we now need to fix things up to be consistent.
+ */
+bool __static_call_fixup(void *tramp, u8 op, void *dest)
+{
+       if (memcmp(tramp+5, tramp_ud, 3)) {
+               /* Not a trampoline site, not our problem. */
+               return false;
+       }
+
+       mutex_lock(&text_mutex);
+       if (op == RET_INSN_OPCODE || dest == &__x86_return_thunk)
+               __static_call_transform(tramp, RET, NULL, true);
+       mutex_unlock(&text_mutex);
+
+       return true;
+}
+#endif
index 81aba71..15f2905 100644 (file)
@@ -141,7 +141,7 @@ SECTIONS
 
 #ifdef CONFIG_RETPOLINE
                __indirect_thunk_start = .;
-               *(.text.__x86.indirect_thunk)
+               *(.text.__x86.*)
                __indirect_thunk_end = .;
 #endif
        } :text =0xcccc
@@ -283,6 +283,13 @@ SECTIONS
                *(.retpoline_sites)
                __retpoline_sites_end = .;
        }
+
+       . = ALIGN(8);
+       .return_sites : AT(ADDR(.return_sites) - LOAD_OFFSET) {
+               __return_sites = .;
+               *(.return_sites)
+               __return_sites_end = .;
+       }
 #endif
 
 #ifdef CONFIG_X86_KERNEL_IBT
@@ -385,7 +392,7 @@ SECTIONS
        __end_of_kernel_reserve = .;
 
        . = ALIGN(PAGE_SIZE);
-       .brk (NOLOAD) : AT(ADDR(.brk) - LOAD_OFFSET) {
+       .brk : AT(ADDR(.brk) - LOAD_OFFSET) {
                __brk_base = .;
                . += 64 * 1024;         /* 64k alignment slop space */
                *(.bss..brk)            /* areas brk users have reserved */
index 89b11e7..f8382ab 100644 (file)
 #define X8(x...) X4(x), X4(x)
 #define X16(x...) X8(x), X8(x)
 
-#define NR_FASTOP (ilog2(sizeof(ulong)) + 1)
-#define FASTOP_SIZE (8 * (1 + HAS_KERNEL_IBT))
-
 struct opcode {
        u64 flags;
        u8 intercept;
@@ -306,9 +303,15 @@ static void invalidate_registers(struct x86_emulate_ctxt *ctxt)
  * Moreover, they are all exactly FASTOP_SIZE bytes long, so functions for
  * different operand sizes can be reached by calculation, rather than a jump
  * table (which would be bigger than the code).
+ *
+ * The 16 byte alignment, considering 5 bytes for the RET thunk, 3 for ENDBR
+ * and 1 for the straight line speculation INT3, leaves 7 bytes for the
+ * body of the function.  Currently none is larger than 4.
  */
 static int fastop(struct x86_emulate_ctxt *ctxt, fastop_t fop);
 
+#define FASTOP_SIZE    16
+
 #define __FOP_FUNC(name) \
        ".align " __stringify(FASTOP_SIZE) " \n\t" \
        ".type " name ", @function \n\t" \
@@ -325,13 +328,15 @@ static int fastop(struct x86_emulate_ctxt *ctxt, fastop_t fop);
 #define FOP_RET(name) \
        __FOP_RET(#name)
 
-#define FOP_START(op) \
+#define __FOP_START(op, align) \
        extern void em_##op(struct fastop *fake); \
        asm(".pushsection .text, \"ax\" \n\t" \
            ".global em_" #op " \n\t" \
-           ".align " __stringify(FASTOP_SIZE) " \n\t" \
+           ".align " __stringify(align) " \n\t" \
            "em_" #op ":\n\t"
 
+#define FOP_START(op) __FOP_START(op, FASTOP_SIZE)
+
 #define FOP_END \
            ".popsection")
 
@@ -435,17 +440,12 @@ static int fastop(struct x86_emulate_ctxt *ctxt, fastop_t fop);
 /*
  * Depending on .config the SETcc functions look like:
  *
- * ENDBR       [4 bytes; CONFIG_X86_KERNEL_IBT]
- * SETcc %al   [3 bytes]
- * RET         [1 byte]
- * INT3        [1 byte; CONFIG_SLS]
- *
- * Which gives possible sizes 4, 5, 8 or 9.  When rounded up to the
- * next power-of-two alignment they become 4, 8 or 16 resp.
+ * ENDBR                       [4 bytes; CONFIG_X86_KERNEL_IBT]
+ * SETcc %al                   [3 bytes]
+ * RET | JMP __x86_return_thunk        [1,5 bytes; CONFIG_RETHUNK]
+ * INT3                                [1 byte; CONFIG_SLS]
  */
-#define SETCC_LENGTH   (ENDBR_INSN_SIZE + 4 + IS_ENABLED(CONFIG_SLS))
-#define SETCC_ALIGN    (4 << IS_ENABLED(CONFIG_SLS) << HAS_KERNEL_IBT)
-static_assert(SETCC_LENGTH <= SETCC_ALIGN);
+#define SETCC_ALIGN    16
 
 #define FOP_SETCC(op) \
        ".align " __stringify(SETCC_ALIGN) " \n\t" \
@@ -453,9 +453,10 @@ static_assert(SETCC_LENGTH <= SETCC_ALIGN);
        #op ": \n\t" \
        ASM_ENDBR \
        #op " %al \n\t" \
-       __FOP_RET(#op)
+       __FOP_RET(#op) \
+       ".skip " __stringify(SETCC_ALIGN) " - (.-" #op "), 0xcc \n\t"
 
-FOP_START(setcc)
+__FOP_START(setcc, SETCC_ALIGN)
 FOP_SETCC(seto)
 FOP_SETCC(setno)
 FOP_SETCC(setc)
index dfaeb47..723f853 100644 (file)
@@ -111,6 +111,15 @@ SYM_FUNC_START(__svm_vcpu_run)
 #endif
 
        /*
+        * Mitigate RETBleed for AMD/Hygon Zen uarch. RET should be
+        * untrained as soon as we exit the VM and are back to the
+        * kernel. This should be done before re-enabling interrupts
+        * because interrupt handlers won't sanitize 'ret' if the return is
+        * from the kernel.
+        */
+       UNTRAIN_RET
+
+       /*
         * Clear all general purpose registers except RSP and RAX to prevent
         * speculative use of the guest's values, even those that are reloaded
         * via the stack.  In theory, an L1 cache miss when restoring registers
@@ -190,6 +199,15 @@ SYM_FUNC_START(__svm_sev_es_vcpu_run)
        FILL_RETURN_BUFFER %_ASM_AX, RSB_CLEAR_LOOPS, X86_FEATURE_RETPOLINE
 #endif
 
+       /*
+        * Mitigate RETBleed for AMD/Hygon Zen uarch. RET should be
+        * untrained as soon as we exit the VM and are back to the
+        * kernel. This should be done before re-enabling interrupts
+        * because interrupt handlers won't sanitize RET if the return is
+        * from the kernel.
+        */
+       UNTRAIN_RET
+
        pop %_ASM_BX
 
 #ifdef CONFIG_X86_64
index 3f430e2..c0e2482 100644 (file)
@@ -4,8 +4,8 @@
 
 #include <asm/vmx.h>
 
-#include "lapic.h"
-#include "x86.h"
+#include "../lapic.h"
+#include "../x86.h"
 
 extern bool __read_mostly enable_vpid;
 extern bool __read_mostly flexpriority_enabled;
index f5cb18e..ab135f9 100644 (file)
@@ -2278,7 +2278,6 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct loaded_vmcs *vmcs0
                                  SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY |
                                  SECONDARY_EXEC_APIC_REGISTER_VIRT |
                                  SECONDARY_EXEC_ENABLE_VMFUNC |
-                                 SECONDARY_EXEC_TSC_SCALING |
                                  SECONDARY_EXEC_DESC);
 
                if (nested_cpu_has(vmcs12,
@@ -3087,7 +3086,7 @@ static int nested_vmx_check_vmentry_hw(struct kvm_vcpu *vcpu)
        }
 
        vm_fail = __vmx_vcpu_run(vmx, (unsigned long *)&vcpu->arch.regs,
-                                vmx->loaded_vmcs->launched);
+                                __vmx_vcpu_run_flags(vmx));
 
        if (vmx->msr_autoload.host.nr)
                vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.host.nr);
diff --git a/arch/x86/kvm/vmx/run_flags.h b/arch/x86/kvm/vmx/run_flags.h
new file mode 100644 (file)
index 0000000..edc3f16
--- /dev/null
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#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)
+
+#endif /* __KVM_X86_VMX_RUN_FLAGS_H */
index 435c187..4182c7f 100644 (file)
@@ -1,10 +1,13 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 #include <linux/linkage.h>
 #include <asm/asm.h>
+#include <asm/asm-offsets.h>
 #include <asm/bitsperlong.h>
 #include <asm/kvm_vcpu_regs.h>
 #include <asm/nospec-branch.h>
+#include <asm/percpu.h>
 #include <asm/segment.h>
+#include "run_flags.h"
 
 #define WORD_SIZE (BITS_PER_LONG / 8)
 
 .section .noinstr.text, "ax"
 
 /**
- * vmx_vmenter - VM-Enter the current loaded VMCS
- *
- * %RFLAGS.ZF: !VMCS.LAUNCHED, i.e. controls VMLAUNCH vs. VMRESUME
- *
- * Returns:
- *     %RFLAGS.CF is set on VM-Fail Invalid
- *     %RFLAGS.ZF is set on VM-Fail Valid
- *     %RFLAGS.{CF,ZF} are cleared on VM-Success, i.e. VM-Exit
- *
- * Note that VMRESUME/VMLAUNCH fall-through and return directly if
- * they VM-Fail, whereas a successful VM-Enter + VM-Exit will jump
- * to vmx_vmexit.
- */
-SYM_FUNC_START_LOCAL(vmx_vmenter)
-       /* EFLAGS.ZF is set if VMCS.LAUNCHED == 0 */
-       je 2f
-
-1:     vmresume
-       RET
-
-2:     vmlaunch
-       RET
-
-3:     cmpb $0, kvm_rebooting
-       je 4f
-       RET
-4:     ud2
-
-       _ASM_EXTABLE(1b, 3b)
-       _ASM_EXTABLE(2b, 3b)
-
-SYM_FUNC_END(vmx_vmenter)
-
-/**
- * vmx_vmexit - Handle a VMX VM-Exit
- *
- * Returns:
- *     %RFLAGS.{CF,ZF} are cleared on VM-Success, i.e. VM-Exit
- *
- * This is vmx_vmenter's partner in crime.  On a VM-Exit, control will jump
- * here after hardware loads the host's state, i.e. this is the destination
- * referred to by VMCS.HOST_RIP.
- */
-SYM_FUNC_START(vmx_vmexit)
-#ifdef CONFIG_RETPOLINE
-       ALTERNATIVE "jmp .Lvmexit_skip_rsb", "", X86_FEATURE_RETPOLINE
-       /* Preserve guest's RAX, it's used to stuff the RSB. */
-       push %_ASM_AX
-
-       /* IMPORTANT: Stuff the RSB immediately after VM-Exit, before RET! */
-       FILL_RETURN_BUFFER %_ASM_AX, RSB_CLEAR_LOOPS, X86_FEATURE_RETPOLINE
-
-       /* Clear RFLAGS.CF and RFLAGS.ZF to preserve VM-Exit, i.e. !VM-Fail. */
-       or $1, %_ASM_AX
-
-       pop %_ASM_AX
-.Lvmexit_skip_rsb:
-#endif
-       RET
-SYM_FUNC_END(vmx_vmexit)
-
-/**
  * __vmx_vcpu_run - Run a vCPU via a transition to VMX guest mode
- * @vmx:       struct vcpu_vmx * (forwarded to vmx_update_host_rsp)
+ * @vmx:       struct vcpu_vmx *
  * @regs:      unsigned long * (to guest registers)
- * @launched:  %true if the VMCS has been launched
+ * @flags:     VMX_RUN_VMRESUME:       use VMRESUME instead of VMLAUNCH
+ *             VMX_RUN_SAVE_SPEC_CTRL: save guest SPEC_CTRL into vmx->spec_ctrl
  *
  * Returns:
  *     0 on VM-Exit, 1 on VM-Fail
@@ -115,24 +57,56 @@ SYM_FUNC_START(__vmx_vcpu_run)
 #endif
        push %_ASM_BX
 
+       /* Save @vmx for SPEC_CTRL handling */
+       push %_ASM_ARG1
+
+       /* Save @flags for SPEC_CTRL handling */
+       push %_ASM_ARG3
+
        /*
         * Save @regs, _ASM_ARG2 may be modified by vmx_update_host_rsp() and
         * @regs is needed after VM-Exit to save the guest's register values.
         */
        push %_ASM_ARG2
 
-       /* Copy @launched to BL, _ASM_ARG3 is volatile. */
+       /* Copy @flags to BL, _ASM_ARG3 is volatile. */
        mov %_ASM_ARG3B, %bl
 
-       /* Adjust RSP to account for the CALL to vmx_vmenter(). */
-       lea -WORD_SIZE(%_ASM_SP), %_ASM_ARG2
+       lea (%_ASM_SP), %_ASM_ARG2
        call vmx_update_host_rsp
 
+       ALTERNATIVE "jmp .Lspec_ctrl_done", "", X86_FEATURE_MSR_SPEC_CTRL
+
+       /*
+        * SPEC_CTRL handling: if the guest's SPEC_CTRL value differs from the
+        * host's, write the MSR.
+        *
+        * IMPORTANT: To avoid RSB underflow attacks and any other nastiness,
+        * there must not be any returns or indirect branches between this code
+        * and vmentry.
+        */
+       mov 2*WORD_SIZE(%_ASM_SP), %_ASM_DI
+       movl VMX_spec_ctrl(%_ASM_DI), %edi
+       movl PER_CPU_VAR(x86_spec_ctrl_current), %esi
+       cmp %edi, %esi
+       je .Lspec_ctrl_done
+       mov $MSR_IA32_SPEC_CTRL, %ecx
+       xor %edx, %edx
+       mov %edi, %eax
+       wrmsr
+
+.Lspec_ctrl_done:
+
+       /*
+        * Since vmentry is serializing on affected CPUs, there's no need for
+        * an LFENCE to stop speculation from skipping the wrmsr.
+        */
+
        /* Load @regs to RAX. */
        mov (%_ASM_SP), %_ASM_AX
 
        /* Check if vmlaunch or vmresume is needed */
-       testb %bl, %bl
+       testb $VMX_RUN_VMRESUME, %bl
 
        /* Load guest registers.  Don't clobber flags. */
        mov VCPU_RCX(%_ASM_AX), %_ASM_CX
@@ -154,11 +128,37 @@ SYM_FUNC_START(__vmx_vcpu_run)
        /* Load guest RAX.  This kills the @regs pointer! */
        mov VCPU_RAX(%_ASM_AX), %_ASM_AX
 
-       /* Enter guest mode */
-       call vmx_vmenter
+       /* Check EFLAGS.ZF from 'testb' above */
+       jz .Lvmlaunch
+
+       /*
+        * After a successful VMRESUME/VMLAUNCH, control flow "magically"
+        * resumes below at 'vmx_vmexit' due to the VMCS HOST_RIP setting.
+        * So this isn't a typical function and objtool needs to be told to
+        * save the unwind state here and restore it below.
+        */
+       UNWIND_HINT_SAVE
+
+/*
+ * If VMRESUME/VMLAUNCH and corresponding vmexit succeed, execution resumes at
+ * the 'vmx_vmexit' label below.
+ */
+.Lvmresume:
+       vmresume
+       jmp .Lvmfail
+
+.Lvmlaunch:
+       vmlaunch
+       jmp .Lvmfail
 
-       /* Jump on VM-Fail. */
-       jbe 2f
+       _ASM_EXTABLE(.Lvmresume, .Lfixup)
+       _ASM_EXTABLE(.Lvmlaunch, .Lfixup)
+
+SYM_INNER_LABEL(vmx_vmexit, SYM_L_GLOBAL)
+
+       /* Restore unwind state from before the VMRESUME/VMLAUNCH. */
+       UNWIND_HINT_RESTORE
+       ENDBR
 
        /* Temporarily save guest's RAX. */
        push %_ASM_AX
@@ -185,21 +185,23 @@ SYM_FUNC_START(__vmx_vcpu_run)
        mov %r15, VCPU_R15(%_ASM_AX)
 #endif
 
-       /* Clear RAX to indicate VM-Exit (as opposed to VM-Fail). */
-       xor %eax, %eax
+       /* Clear return value to indicate VM-Exit (as opposed to VM-Fail). */
+       xor %ebx, %ebx
 
+.Lclear_regs:
        /*
-        * Clear all general purpose registers except RSP and RAX to prevent
+        * Clear all general purpose registers except RSP and RBX to prevent
         * speculative use of the guest's values, even those that are reloaded
         * via the stack.  In theory, an L1 cache miss when restoring registers
         * could lead to speculative execution with the guest's values.
         * Zeroing XORs are dirt cheap, i.e. the extra paranoia is essentially
         * free.  RSP and RAX are exempt as RSP is restored by hardware during
-        * VM-Exit and RAX is explicitly loaded with 0 or 1 to return VM-Fail.
+        * VM-Exit and RBX is explicitly loaded with 0 or 1 to hold the return
+        * value.
         */
-1:     xor %ecx, %ecx
+       xor %eax, %eax
+       xor %ecx, %ecx
        xor %edx, %edx
-       xor %ebx, %ebx
        xor %ebp, %ebp
        xor %esi, %esi
        xor %edi, %edi
@@ -216,8 +218,30 @@ SYM_FUNC_START(__vmx_vcpu_run)
 
        /* "POP" @regs. */
        add $WORD_SIZE, %_ASM_SP
-       pop %_ASM_BX
 
+       /*
+        * IMPORTANT: RSB filling and SPEC_CTRL handling must be done before
+        * the first unbalanced RET after vmexit!
+        *
+        * For retpoline or IBRS, RSB filling is needed to prevent poisoned RSB
+        * entries and (in some cases) RSB underflow.
+        *
+        * eIBRS has its own protection against poisoned RSB, so it doesn't
+        * need the RSB filling sequence.  But it does need to be enabled
+        * before the first unbalanced RET.
+         */
+
+       FILL_RETURN_BUFFER %_ASM_CX, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_VMEXIT
+
+       pop %_ASM_ARG2  /* @flags */
+       pop %_ASM_ARG1  /* @vmx */
+
+       call vmx_spec_ctrl_restore_host
+
+       /* Put return value in AX */
+       mov %_ASM_BX, %_ASM_AX
+
+       pop %_ASM_BX
 #ifdef CONFIG_X86_64
        pop %r12
        pop %r13
@@ -230,9 +254,15 @@ SYM_FUNC_START(__vmx_vcpu_run)
        pop %_ASM_BP
        RET
 
-       /* VM-Fail.  Out-of-line to avoid a taken Jcc after VM-Exit. */
-2:     mov $1, %eax
-       jmp 1b
+.Lfixup:
+       cmpb $0, kvm_rebooting
+       jne .Lvmfail
+       ud2
+.Lvmfail:
+       /* VM-Fail: set return value to 1 */
+       mov $1, %_ASM_BX
+       jmp .Lclear_regs
+
 SYM_FUNC_END(__vmx_vcpu_run)
 
 
index 3a919e4..be7c193 100644 (file)
@@ -383,9 +383,9 @@ static __always_inline void vmx_disable_fb_clear(struct vcpu_vmx *vmx)
        if (!vmx->disable_fb_clear)
                return;
 
-       rdmsrl(MSR_IA32_MCU_OPT_CTRL, msr);
+       msr = __rdmsr(MSR_IA32_MCU_OPT_CTRL);
        msr |= FB_CLEAR_DIS;
-       wrmsrl(MSR_IA32_MCU_OPT_CTRL, msr);
+       native_wrmsrl(MSR_IA32_MCU_OPT_CTRL, msr);
        /* Cache the MSR value to avoid reading it later */
        vmx->msr_ia32_mcu_opt_ctrl = msr;
 }
@@ -396,7 +396,7 @@ static __always_inline void vmx_enable_fb_clear(struct vcpu_vmx *vmx)
                return;
 
        vmx->msr_ia32_mcu_opt_ctrl &= ~FB_CLEAR_DIS;
-       wrmsrl(MSR_IA32_MCU_OPT_CTRL, vmx->msr_ia32_mcu_opt_ctrl);
+       native_wrmsrl(MSR_IA32_MCU_OPT_CTRL, vmx->msr_ia32_mcu_opt_ctrl);
 }
 
 static void vmx_update_fb_clear_dis(struct kvm_vcpu *vcpu, struct vcpu_vmx *vmx)
@@ -839,6 +839,24 @@ static bool msr_write_intercepted(struct vcpu_vmx *vmx, u32 msr)
                                         MSR_IA32_SPEC_CTRL);
 }
 
+unsigned int __vmx_vcpu_run_flags(struct vcpu_vmx *vmx)
+{
+       unsigned int flags = 0;
+
+       if (vmx->loaded_vmcs->launched)
+               flags |= VMX_RUN_VMRESUME;
+
+       /*
+        * If writes to the SPEC_CTRL MSR aren't intercepted, the guest is free
+        * to change it directly without causing a vmexit.  In that case read
+        * it after vmexit and store it in vmx->spec_ctrl.
+        */
+       if (unlikely(!msr_write_intercepted(vmx, MSR_IA32_SPEC_CTRL)))
+               flags |= VMX_RUN_SAVE_SPEC_CTRL;
+
+       return flags;
+}
+
 static void clear_atomic_switch_msr_special(struct vcpu_vmx *vmx,
                unsigned long entry, unsigned long exit)
 {
@@ -6813,6 +6831,31 @@ void noinstr vmx_update_host_rsp(struct vcpu_vmx *vmx, unsigned long host_rsp)
        }
 }
 
+void noinstr vmx_spec_ctrl_restore_host(struct vcpu_vmx *vmx,
+                                       unsigned int flags)
+{
+       u64 hostval = this_cpu_read(x86_spec_ctrl_current);
+
+       if (!cpu_feature_enabled(X86_FEATURE_MSR_SPEC_CTRL))
+               return;
+
+       if (flags & VMX_RUN_SAVE_SPEC_CTRL)
+               vmx->spec_ctrl = __rdmsr(MSR_IA32_SPEC_CTRL);
+
+       /*
+        * If the guest/host SPEC_CTRL values differ, restore the host value.
+        *
+        * For legacy IBRS, the IBRS bit always needs to be written after
+        * transitioning from a less privileged predictor mode, regardless of
+        * whether the guest/host values differ.
+        */
+       if (cpu_feature_enabled(X86_FEATURE_KERNEL_IBRS) ||
+           vmx->spec_ctrl != hostval)
+               native_wrmsrl(MSR_IA32_SPEC_CTRL, hostval);
+
+       barrier_nospec();
+}
+
 static fastpath_t vmx_exit_handlers_fastpath(struct kvm_vcpu *vcpu)
 {
        switch (to_vmx(vcpu)->exit_reason.basic) {
@@ -6826,7 +6869,8 @@ static fastpath_t vmx_exit_handlers_fastpath(struct kvm_vcpu *vcpu)
 }
 
 static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu,
-                                       struct vcpu_vmx *vmx)
+                                       struct vcpu_vmx *vmx,
+                                       unsigned long flags)
 {
        guest_state_enter_irqoff();
 
@@ -6845,7 +6889,7 @@ static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu,
                native_write_cr2(vcpu->arch.cr2);
 
        vmx->fail = __vmx_vcpu_run(vmx, (unsigned long *)&vcpu->arch.regs,
-                                  vmx->loaded_vmcs->launched);
+                                  flags);
 
        vcpu->arch.cr2 = native_read_cr2();
 
@@ -6944,36 +6988,8 @@ static fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu)
 
        kvm_wait_lapic_expire(vcpu);
 
-       /*
-        * If this vCPU has touched SPEC_CTRL, restore the guest's value if
-        * it's non-zero. Since vmentry is serialising on affected CPUs, there
-        * is no need to worry about the conditional branch over the wrmsr
-        * being speculatively taken.
-        */
-       x86_spec_ctrl_set_guest(vmx->spec_ctrl, 0);
-
        /* The actual VMENTER/EXIT is in the .noinstr.text section. */
-       vmx_vcpu_enter_exit(vcpu, vmx);
-
-       /*
-        * We do not use IBRS in the kernel. If this vCPU has used the
-        * SPEC_CTRL MSR it may have left it on; save the value and
-        * turn it off. This is much more efficient than blindly adding
-        * it to the atomic save/restore list. Especially as the former
-        * (Saving guest MSRs on vmexit) doesn't even exist in KVM.
-        *
-        * For non-nested case:
-        * If the L01 MSR bitmap does not intercept the MSR, then we need to
-        * save it.
-        *
-        * For nested case:
-        * If the L02 MSR bitmap does not intercept the MSR, then we need to
-        * save it.
-        */
-       if (unlikely(!msr_write_intercepted(vmx, MSR_IA32_SPEC_CTRL)))
-               vmx->spec_ctrl = native_read_msr(MSR_IA32_SPEC_CTRL);
-
-       x86_spec_ctrl_restore_host(vmx->spec_ctrl, 0);
+       vmx_vcpu_enter_exit(vcpu, vmx, __vmx_vcpu_run_flags(vmx));
 
        /* All fields are clean at this point */
        if (static_branch_unlikely(&enable_evmcs)) {
index 8d2342e..1e7f945 100644 (file)
@@ -8,11 +8,12 @@
 #include <asm/intel_pt.h>
 
 #include "capabilities.h"
-#include "kvm_cache_regs.h"
+#include "../kvm_cache_regs.h"
 #include "posted_intr.h"
 #include "vmcs.h"
 #include "vmx_ops.h"
-#include "cpuid.h"
+#include "../cpuid.h"
+#include "run_flags.h"
 
 #define MSR_TYPE_R     1
 #define MSR_TYPE_W     2
@@ -404,7 +405,10 @@ void vmx_set_virtual_apic_mode(struct kvm_vcpu *vcpu);
 struct vmx_uret_msr *vmx_find_uret_msr(struct vcpu_vmx *vmx, u32 msr);
 void pt_update_intercept_for_msr(struct kvm_vcpu *vcpu);
 void vmx_update_host_rsp(struct vcpu_vmx *vmx, unsigned long host_rsp);
-bool __vmx_vcpu_run(struct vcpu_vmx *vmx, unsigned long *regs, bool launched);
+void vmx_spec_ctrl_restore_host(struct vcpu_vmx *vmx, unsigned int flags);
+unsigned int __vmx_vcpu_run_flags(struct vcpu_vmx *vmx);
+bool __vmx_vcpu_run(struct vcpu_vmx *vmx, unsigned long *regs,
+                   unsigned int flags);
 int vmx_find_loadstore_msr_slot(struct vmx_msrs *m, u32 msr);
 void vmx_ept_load_pdptrs(struct kvm_vcpu *vcpu);
 
index 5e7f412..5cfc49d 100644 (file)
@@ -8,7 +8,7 @@
 
 #include "evmcs.h"
 #include "vmcs.h"
-#include "x86.h"
+#include "../x86.h"
 
 asmlinkage void vmread_error(unsigned long field, bool fault);
 __attribute__((regparm(0))) void vmread_error_trampoline(unsigned long field,
index 1910e1e..e5fa335 100644 (file)
@@ -298,7 +298,7 @@ const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
        STATS_DESC_COUNTER(VCPU, directed_yield_successful),
        STATS_DESC_COUNTER(VCPU, preemption_reported),
        STATS_DESC_COUNTER(VCPU, preemption_other),
-       STATS_DESC_ICOUNTER(VCPU, guest_mode)
+       STATS_DESC_IBOOLEAN(VCPU, guest_mode)
 };
 
 const struct kvm_stats_header kvm_vcpu_stats_header = {
@@ -6029,6 +6029,11 @@ split_irqchip_unlock:
                r = 0;
                break;
        case KVM_CAP_X86_USER_SPACE_MSR:
+               r = -EINVAL;
+               if (cap->args[0] & ~(KVM_MSR_EXIT_REASON_INVAL |
+                                    KVM_MSR_EXIT_REASON_UNKNOWN |
+                                    KVM_MSR_EXIT_REASON_FILTER))
+                       break;
                kvm->arch.user_space_msr_mask = cap->args[0];
                r = 0;
                break;
@@ -6183,6 +6188,9 @@ static int kvm_vm_ioctl_set_msr_filter(struct kvm *kvm, void __user *argp)
        if (copy_from_user(&filter, user_msr_filter, sizeof(filter)))
                return -EFAULT;
 
+       if (filter.flags & ~KVM_MSR_FILTER_DEFAULT_DENY)
+               return -EINVAL;
+
        for (i = 0; i < ARRAY_SIZE(filter.ranges); i++)
                empty &= !filter.ranges[i].nmsrs;
 
@@ -9143,15 +9151,17 @@ static int kvm_pv_clock_pairing(struct kvm_vcpu *vcpu, gpa_t paddr,
  */
 static void kvm_pv_kick_cpu_op(struct kvm *kvm, int apicid)
 {
-       struct kvm_lapic_irq lapic_irq;
-
-       lapic_irq.shorthand = APIC_DEST_NOSHORT;
-       lapic_irq.dest_mode = APIC_DEST_PHYSICAL;
-       lapic_irq.level = 0;
-       lapic_irq.dest_id = apicid;
-       lapic_irq.msi_redir_hint = false;
+       /*
+        * All other fields are unused for APIC_DM_REMRD, but may be consumed by
+        * common code, e.g. for tracing. Defer initialization to the compiler.
+        */
+       struct kvm_lapic_irq lapic_irq = {
+               .delivery_mode = APIC_DM_REMRD,
+               .dest_mode = APIC_DEST_PHYSICAL,
+               .shorthand = APIC_DEST_NOSHORT,
+               .dest_id = apicid,
+       };
 
-       lapic_irq.delivery_mode = APIC_DM_REMRD;
        kvm_irq_delivery_to_apic(kvm, NULL, &lapic_irq, NULL);
 }
 
@@ -12631,9 +12641,9 @@ void kvm_arch_end_assignment(struct kvm *kvm)
 }
 EXPORT_SYMBOL_GPL(kvm_arch_end_assignment);
 
-bool kvm_arch_has_assigned_device(struct kvm *kvm)
+bool noinstr kvm_arch_has_assigned_device(struct kvm *kvm)
 {
-       return atomic_read(&kvm->arch.assigned_device_count);
+       return arch_atomic_read(&kvm->arch.assigned_device_count);
 }
 EXPORT_SYMBOL_GPL(kvm_arch_has_assigned_device);
 
index d83cba3..724bbf8 100644 (file)
@@ -39,7 +39,7 @@ SYM_FUNC_START(__memmove)
        /* FSRM implies ERMS => no length checks, do the copy directly */
 .Lmemmove_begin_forward:
        ALTERNATIVE "cmp $0x20, %rdx; jb 1f", "", X86_FEATURE_FSRM
-       ALTERNATIVE "", __stringify(movq %rdx, %rcx; rep movsb; RET), X86_FEATURE_ERMS
+       ALTERNATIVE "", "jmp .Lmemmove_erms", X86_FEATURE_ERMS
 
        /*
         * movsq instruction have many startup latency
@@ -205,6 +205,11 @@ SYM_FUNC_START(__memmove)
        movb %r11b, (%rdi)
 13:
        RET
+
+.Lmemmove_erms:
+       movq %rdx, %rcx
+       rep movsb
+       RET
 SYM_FUNC_END(__memmove)
 EXPORT_SYMBOL(__memmove)
 
index b2b2366..073289a 100644 (file)
@@ -33,9 +33,9 @@ SYM_INNER_LABEL(__x86_indirect_thunk_\reg, SYM_L_GLOBAL)
        UNWIND_HINT_EMPTY
        ANNOTATE_NOENDBR
 
-       ALTERNATIVE_2 __stringify(ANNOTATE_RETPOLINE_SAFE; jmp *%\reg), \
-                     __stringify(RETPOLINE \reg), X86_FEATURE_RETPOLINE, \
-                     __stringify(lfence; ANNOTATE_RETPOLINE_SAFE; jmp *%\reg; int3), X86_FEATURE_RETPOLINE_LFENCE
+       ALTERNATIVE_2 __stringify(RETPOLINE \reg), \
+                     __stringify(lfence; ANNOTATE_RETPOLINE_SAFE; jmp *%\reg; int3), X86_FEATURE_RETPOLINE_LFENCE, \
+                     __stringify(ANNOTATE_RETPOLINE_SAFE; jmp *%\reg), ALT_NOT(X86_FEATURE_RETPOLINE)
 
 .endm
 
@@ -67,3 +67,76 @@ SYM_CODE_END(__x86_indirect_thunk_array)
 #define GEN(reg) EXPORT_THUNK(reg)
 #include <asm/GEN-for-each-reg.h>
 #undef GEN
+
+/*
+ * This function name is magical and is used by -mfunction-return=thunk-extern
+ * for the compiler to generate JMPs to it.
+ */
+#ifdef CONFIG_RETHUNK
+
+       .section .text.__x86.return_thunk
+
+/*
+ * Safety details here pertain to the AMD Zen{1,2} microarchitecture:
+ * 1) The RET at __x86_return_thunk must be on a 64 byte boundary, for
+ *    alignment within the BTB.
+ * 2) The instruction at zen_untrain_ret must contain, and not
+ *    end with, the 0xc3 byte of the RET.
+ * 3) STIBP must be enabled, or SMT disabled, to prevent the sibling thread
+ *    from re-poisioning the BTB prediction.
+ */
+       .align 64
+       .skip 63, 0xcc
+SYM_FUNC_START_NOALIGN(zen_untrain_ret);
+
+       /*
+        * As executed from zen_untrain_ret, this is:
+        *
+        *   TEST $0xcc, %bl
+        *   LFENCE
+        *   JMP __x86_return_thunk
+        *
+        * Executing the TEST instruction has a side effect of evicting any BTB
+        * prediction (potentially attacker controlled) attached to the RET, as
+        * __x86_return_thunk + 1 isn't an instruction boundary at the moment.
+        */
+       .byte   0xf6
+
+       /*
+        * As executed from __x86_return_thunk, this is a plain RET.
+        *
+        * As part of the TEST above, RET is the ModRM byte, and INT3 the imm8.
+        *
+        * We subsequently jump backwards and architecturally execute the RET.
+        * This creates a correct BTB prediction (type=ret), but in the
+        * meantime we suffer Straight Line Speculation (because the type was
+        * no branch) which is halted by the INT3.
+        *
+        * With SMT enabled and STIBP active, a sibling thread cannot poison
+        * RET's prediction to a type of its choice, but can evict the
+        * prediction due to competitive sharing. If the prediction is
+        * evicted, __x86_return_thunk will suffer Straight Line Speculation
+        * which will be contained safely by the INT3.
+        */
+SYM_INNER_LABEL(__x86_return_thunk, SYM_L_GLOBAL)
+       ret
+       int3
+SYM_CODE_END(__x86_return_thunk)
+
+       /*
+        * Ensure the TEST decoding / BTB invalidation is complete.
+        */
+       lfence
+
+       /*
+        * Jump back and execute the RET in the middle of the TEST instruction.
+        * INT3 is for SLS protection.
+        */
+       jmp __x86_return_thunk
+       int3
+SYM_FUNC_END(zen_untrain_ret)
+__EXPORT_THUNK(zen_untrain_ret)
+
+EXPORT_SYMBOL(__x86_return_thunk)
+
+#endif /* CONFIG_RETHUNK */
index dba2197..331310c 100644 (file)
@@ -94,16 +94,18 @@ static bool ex_handler_copy(const struct exception_table_entry *fixup,
 static bool ex_handler_msr(const struct exception_table_entry *fixup,
                           struct pt_regs *regs, bool wrmsr, bool safe, int reg)
 {
-       if (!safe && wrmsr &&
-           pr_warn_once("unchecked MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x) at rIP: 0x%lx (%pS)\n",
-                        (unsigned int)regs->cx, (unsigned int)regs->dx,
-                        (unsigned int)regs->ax,  regs->ip, (void *)regs->ip))
+       if (__ONCE_LITE_IF(!safe && wrmsr)) {
+               pr_warn("unchecked MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x) at rIP: 0x%lx (%pS)\n",
+                       (unsigned int)regs->cx, (unsigned int)regs->dx,
+                       (unsigned int)regs->ax,  regs->ip, (void *)regs->ip);
                show_stack_regs(regs);
+       }
 
-       if (!safe && !wrmsr &&
-           pr_warn_once("unchecked MSR access error: RDMSR from 0x%x at rIP: 0x%lx (%pS)\n",
-                        (unsigned int)regs->cx, regs->ip, (void *)regs->ip))
+       if (__ONCE_LITE_IF(!safe && !wrmsr)) {
+               pr_warn("unchecked MSR access error: RDMSR from 0x%x at rIP: 0x%lx (%pS)\n",
+                       (unsigned int)regs->cx, regs->ip, (void *)regs->ip);
                show_stack_regs(regs);
+       }
 
        if (!wrmsr) {
                /* Pretend that the read succeeded and returned 0. */
index fad8faa..971977c 100644 (file)
@@ -1526,7 +1526,7 @@ DEFINE_IDTENTRY_RAW_ERRORCODE(exc_page_fault)
 
        /*
         * Entry handling for valid #PF from kernel mode is slightly
-        * different: RCU is already watching and rcu_irq_enter() must not
+        * different: RCU is already watching and ct_irq_enter() must not
         * be invoked because a kernel fault on a user space address might
         * sleep.
         *
index d8cfce2..82a042c 100644 (file)
@@ -77,10 +77,20 @@ static uint8_t __pte2cachemode_tbl[8] = {
        [__pte2cm_idx(_PAGE_PWT | _PAGE_PCD | _PAGE_PAT)] = _PAGE_CACHE_MODE_UC,
 };
 
-/* Check that the write-protect PAT entry is set for write-protect */
+/*
+ * Check that the write-protect PAT entry is set for write-protect.
+ * To do this without making assumptions how PAT has been set up (Xen has
+ * another layout than the kernel), translate the _PAGE_CACHE_MODE_WP cache
+ * mode via the __cachemode2pte_tbl[] into protection bits (those protection
+ * bits will select a cache mode of WP or better), and then translate the
+ * protection bits back into the cache mode using __pte2cm_idx() and the
+ * __pte2cachemode_tbl[] array. This will return the really used cache mode.
+ */
 bool x86_has_pat_wp(void)
 {
-       return __pte2cachemode_tbl[_PAGE_CACHE_MODE_WP] == _PAGE_CACHE_MODE_WP;
+       uint16_t prot = __cachemode2pte_tbl[_PAGE_CACHE_MODE_WP];
+
+       return __pte2cachemode_tbl[__pte2cm_idx(prot)] == _PAGE_CACHE_MODE_WP;
 }
 
 enum page_cache_mode pgprot2cachemode(pgprot_t pgprot)
@@ -846,7 +856,7 @@ int devmem_is_allowed(unsigned long pagenr)
 
        /*
         * This must follow RAM test, since System RAM is considered a
-        * restricted resource under CONFIG_STRICT_IOMEM.
+        * restricted resource under CONFIG_STRICT_DEVMEM.
         */
        if (iomem_is_exclusive(pagenr << PAGE_SHIFT)) {
                /* Low 1MB bypasses iomem restrictions. */
index 3d1dba0..9de3d90 100644 (file)
@@ -65,7 +65,10 @@ SYM_FUNC_START(sme_encrypt_execute)
        movq    %rbp, %rsp              /* Restore original stack pointer */
        pop     %rbp
 
-       RET
+       /* Offset to __x86_return_thunk would be wrong here */
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 SYM_FUNC_END(sme_encrypt_execute)
 
 SYM_FUNC_START(__enc_copy)
@@ -151,6 +154,9 @@ SYM_FUNC_START(__enc_copy)
        pop     %r12
        pop     %r15
 
-       RET
+       /* Offset to __x86_return_thunk would be wrong here */
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 .L__enc_copy_end:
 SYM_FUNC_END(__enc_copy)
index e44e938..7418c36 100644 (file)
@@ -110,7 +110,7 @@ int __arch_override_mprotect_pkey(struct vm_area_struct *vma, int prot, int pkey
        return vma_pkey(vma);
 }
 
-#define PKRU_AD_KEY(pkey)      (PKRU_AD_BIT << ((pkey) * PKRU_BITS_PER_PKEY))
+#define PKRU_AD_MASK(pkey)     (PKRU_AD_BIT << ((pkey) * PKRU_BITS_PER_PKEY))
 
 /*
  * Make the default PKRU value (at execve() time) as restrictive
@@ -118,11 +118,14 @@ int __arch_override_mprotect_pkey(struct vm_area_struct *vma, int prot, int pkey
  * in the process's lifetime will not accidentally get access
  * to data which is pkey-protected later on.
  */
-u32 init_pkru_value = PKRU_AD_KEY( 1) | PKRU_AD_KEY( 2) | PKRU_AD_KEY( 3) |
-                     PKRU_AD_KEY( 4) | PKRU_AD_KEY( 5) | PKRU_AD_KEY( 6) |
-                     PKRU_AD_KEY( 7) | PKRU_AD_KEY( 8) | PKRU_AD_KEY( 9) |
-                     PKRU_AD_KEY(10) | PKRU_AD_KEY(11) | PKRU_AD_KEY(12) |
-                     PKRU_AD_KEY(13) | PKRU_AD_KEY(14) | PKRU_AD_KEY(15);
+u32 init_pkru_value = PKRU_AD_MASK( 1) | PKRU_AD_MASK( 2) |
+                     PKRU_AD_MASK( 3) | PKRU_AD_MASK( 4) |
+                     PKRU_AD_MASK( 5) | PKRU_AD_MASK( 6) |
+                     PKRU_AD_MASK( 7) | PKRU_AD_MASK( 8) |
+                     PKRU_AD_MASK( 9) | PKRU_AD_MASK(10) |
+                     PKRU_AD_MASK(11) | PKRU_AD_MASK(12) |
+                     PKRU_AD_MASK(13) | PKRU_AD_MASK(14) |
+                     PKRU_AD_MASK(15);
 
 static ssize_t init_pkru_read_file(struct file *file, char __user *user_buf,
                             size_t count, loff_t *ppos)
index d400b6d..c1e31e9 100644 (file)
@@ -734,10 +734,10 @@ static void flush_tlb_func(void *info)
        const struct flush_tlb_info *f = info;
        struct mm_struct *loaded_mm = this_cpu_read(cpu_tlbstate.loaded_mm);
        u32 loaded_mm_asid = this_cpu_read(cpu_tlbstate.loaded_mm_asid);
-       u64 mm_tlb_gen = atomic64_read(&loaded_mm->context.tlb_gen);
        u64 local_tlb_gen = this_cpu_read(cpu_tlbstate.ctxs[loaded_mm_asid].tlb_gen);
        bool local = smp_processor_id() == f->initiating_cpu;
        unsigned long nr_invalidate = 0;
+       u64 mm_tlb_gen;
 
        /* This code cannot presently handle being reentered. */
        VM_WARN_ON(!irqs_disabled());
@@ -771,6 +771,23 @@ static void flush_tlb_func(void *info)
                return;
        }
 
+       if (unlikely(f->new_tlb_gen != TLB_GENERATION_INVALID &&
+                    f->new_tlb_gen <= local_tlb_gen)) {
+               /*
+                * The TLB is already up to date in respect to f->new_tlb_gen.
+                * While the core might be still behind mm_tlb_gen, checking
+                * mm_tlb_gen unnecessarily would have negative caching effects
+                * so avoid it.
+                */
+               return;
+       }
+
+       /*
+        * Defer mm_tlb_gen reading as long as possible to avoid cache
+        * contention.
+        */
+       mm_tlb_gen = atomic64_read(&loaded_mm->context.tlb_gen);
+
        if (unlikely(local_tlb_gen == mm_tlb_gen)) {
                /*
                 * There's nothing to do: we're already up to date.  This can
@@ -827,6 +844,12 @@ static void flush_tlb_func(void *info)
                /* Partial flush */
                unsigned long addr = f->start;
 
+               /* Partial flush cannot have invalid generations */
+               VM_WARN_ON(f->new_tlb_gen == TLB_GENERATION_INVALID);
+
+               /* Partial flush must have valid mm */
+               VM_WARN_ON(f->mm == NULL);
+
                nr_invalidate = (f->end - f->start) >> f->stride_shift;
 
                while (addr < f->end) {
@@ -1029,7 +1052,8 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end)
                struct flush_tlb_info *info;
 
                preempt_disable();
-               info = get_flush_tlb_info(NULL, start, end, 0, false, 0);
+               info = get_flush_tlb_info(NULL, start, end, 0, false,
+                                         TLB_GENERATION_INVALID);
 
                on_each_cpu(do_kernel_range_flush, info, 1);
 
@@ -1198,7 +1222,8 @@ void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch)
 
        int cpu = get_cpu();
 
-       info = get_flush_tlb_info(NULL, 0, TLB_FLUSH_ALL, 0, false, 0);
+       info = get_flush_tlb_info(NULL, 0, TLB_FLUSH_ALL, 0, false,
+                                 TLB_GENERATION_INVALID);
        /*
         * flush_tlb_multi() is not optimized for the common case in which only
         * a local TLB flush is needed. Optimize this use-case by calling
index c98b8c0..b808c9a 100644 (file)
@@ -412,16 +412,30 @@ static void emit_indirect_jump(u8 **pprog, int reg, u8 *ip)
 {
        u8 *prog = *pprog;
 
-#ifdef CONFIG_RETPOLINE
        if (cpu_feature_enabled(X86_FEATURE_RETPOLINE_LFENCE)) {
                EMIT_LFENCE();
                EMIT2(0xFF, 0xE0 + reg);
        } else if (cpu_feature_enabled(X86_FEATURE_RETPOLINE)) {
                OPTIMIZER_HIDE_VAR(reg);
                emit_jump(&prog, &__x86_indirect_thunk_array[reg], ip);
-       } else
-#endif
-       EMIT2(0xFF, 0xE0 + reg);
+       } else {
+               EMIT2(0xFF, 0xE0 + reg);
+       }
+
+       *pprog = prog;
+}
+
+static void emit_return(u8 **pprog, u8 *ip)
+{
+       u8 *prog = *pprog;
+
+       if (cpu_feature_enabled(X86_FEATURE_RETHUNK)) {
+               emit_jump(&prog, &__x86_return_thunk, ip);
+       } else {
+               EMIT1(0xC3);            /* ret */
+               if (IS_ENABLED(CONFIG_SLS))
+                       EMIT1(0xCC);    /* int3 */
+       }
 
        *pprog = prog;
 }
@@ -1686,7 +1700,7 @@ emit_jmp:
                        ctx->cleanup_addr = proglen;
                        pop_callee_regs(&prog, callee_regs_used);
                        EMIT1(0xC9);         /* leave */
-                       EMIT1(0xC3);         /* ret */
+                       emit_return(&prog, image + addrs[i - 1] + (prog - temp));
                        break;
 
                default:
@@ -2189,7 +2203,7 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i
        if (flags & BPF_TRAMP_F_SKIP_FRAME)
                /* skip our return address and return to parent */
                EMIT4(0x48, 0x83, 0xC4, 8); /* add rsp, 8 */
-       EMIT1(0xC3); /* ret */
+       emit_return(&prog, prog);
        /* Make sure the trampoline generation logic doesn't overflow */
        if (WARN_ON_ONCE(prog > (u8 *)image_end - BPF_INSN_SAFETY)) {
                ret = -EFAULT;
index 9ffe2ba..4e5257a 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/objtool.h>
 #include <asm/page_types.h>
 #include <asm/segment.h>
+#include <asm/nospec-branch.h>
 
        .text
        .code64
@@ -75,7 +76,9 @@ STACK_FRAME_NON_STANDARD __efi64_thunk
 1:     movq    0x20(%rsp), %rsp
        pop     %rbx
        pop     %rbp
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 
        .code32
 2:     pushl   $__KERNEL_CS
index ae53d54..31c634a 100644 (file)
@@ -73,12 +73,6 @@ $(obj)/purgatory.ro: $(PURGATORY_OBJS) FORCE
 $(obj)/purgatory.chk: $(obj)/purgatory.ro FORCE
                $(call if_changed,ld)
 
-targets += kexec-purgatory.c
+$(obj)/kexec-purgatory.o: $(obj)/purgatory.ro $(obj)/purgatory.chk
 
-quiet_cmd_bin2c = BIN2C   $@
-      cmd_bin2c = $(objtree)/scripts/bin2c kexec_purgatory < $< > $@
-
-$(obj)/kexec-purgatory.c: $(obj)/purgatory.ro $(obj)/purgatory.chk FORCE
-       $(call if_changed,bin2c)
-
-obj-$(CONFIG_KEXEC_FILE)       += kexec-purgatory.o
+obj-y += kexec-purgatory.o
diff --git a/arch/x86/purgatory/kexec-purgatory.S b/arch/x86/purgatory/kexec-purgatory.S
new file mode 100644 (file)
index 0000000..8530fe9
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+       .section .rodata, "a"
+
+       .align  8
+kexec_purgatory:
+       .globl  kexec_purgatory
+       .incbin "arch/x86/purgatory/purgatory.ro"
+.Lkexec_purgatory_end:
+
+       .align  8
+kexec_purgatory_size:
+       .globl  kexec_purgatory_size
+       .quad   .Lkexec_purgatory_end - kexec_purgatory
index e3297b1..70fb2ea 100644 (file)
@@ -1183,15 +1183,19 @@ static void __init xen_domu_set_legacy_features(void)
 extern void early_xen_iret_patch(void);
 
 /* First C function to be called on Xen boot */
-asmlinkage __visible void __init xen_start_kernel(void)
+asmlinkage __visible void __init xen_start_kernel(struct start_info *si)
 {
        struct physdev_set_iopl set_iopl;
        unsigned long initrd_start = 0;
        int rc;
 
-       if (!xen_start_info)
+       if (!si)
                return;
 
+       clear_bss();
+
+       xen_start_info = si;
+
        __text_gen_insn(&early_xen_iret_patch,
                        JMP32_INSN_OPCODE, &early_xen_iret_patch, &xen_iret,
                        JMP32_INSN_SIZE);
index 81aa46f..cfa99e8 100644 (file)
@@ -918,7 +918,7 @@ void xen_enable_sysenter(void)
        if (!boot_cpu_has(sysenter_feature))
                return;
 
-       ret = register_callback(CALLBACKTYPE_sysenter, xen_sysenter_target);
+       ret = register_callback(CALLBACKTYPE_sysenter, xen_entry_SYSENTER_compat);
        if(ret != 0)
                setup_clear_cpu_cap(sysenter_feature);
 }
@@ -927,7 +927,7 @@ void xen_enable_syscall(void)
 {
        int ret;
 
-       ret = register_callback(CALLBACKTYPE_syscall, xen_syscall_target);
+       ret = register_callback(CALLBACKTYPE_syscall, xen_entry_SYSCALL_64);
        if (ret != 0) {
                printk(KERN_ERR "Failed to set syscall callback: %d\n", ret);
                /* Pretty fatal; 64-bit userspace has no other
@@ -936,7 +936,7 @@ void xen_enable_syscall(void)
 
        if (boot_cpu_has(X86_FEATURE_SYSCALL32)) {
                ret = register_callback(CALLBACKTYPE_syscall32,
-                                       xen_syscall32_target);
+                                       xen_entry_SYSCALL_compat);
                if (ret != 0)
                        setup_clear_cpu_cap(X86_FEATURE_SYSCALL32);
        }
index caa9bc2..6b4fdf6 100644 (file)
@@ -121,7 +121,7 @@ SYM_FUNC_END(xen_read_cr2_direct);
 
 .macro xen_pv_trap name
 SYM_CODE_START(xen_\name)
-       UNWIND_HINT_EMPTY
+       UNWIND_HINT_ENTRY
        ENDBR
        pop %rcx
        pop %r11
@@ -234,8 +234,8 @@ SYM_CODE_END(xenpv_restore_regs_and_return_to_usermode)
  */
 
 /* Normal 64-bit system call target */
-SYM_CODE_START(xen_syscall_target)
-       UNWIND_HINT_EMPTY
+SYM_CODE_START(xen_entry_SYSCALL_64)
+       UNWIND_HINT_ENTRY
        ENDBR
        popq %rcx
        popq %r11
@@ -249,13 +249,13 @@ SYM_CODE_START(xen_syscall_target)
        movq $__USER_CS, 1*8(%rsp)
 
        jmp entry_SYSCALL_64_after_hwframe
-SYM_CODE_END(xen_syscall_target)
+SYM_CODE_END(xen_entry_SYSCALL_64)
 
 #ifdef CONFIG_IA32_EMULATION
 
 /* 32-bit compat syscall target */
-SYM_CODE_START(xen_syscall32_target)
-       UNWIND_HINT_EMPTY
+SYM_CODE_START(xen_entry_SYSCALL_compat)
+       UNWIND_HINT_ENTRY
        ENDBR
        popq %rcx
        popq %r11
@@ -269,11 +269,11 @@ SYM_CODE_START(xen_syscall32_target)
        movq $__USER32_CS, 1*8(%rsp)
 
        jmp entry_SYSCALL_compat_after_hwframe
-SYM_CODE_END(xen_syscall32_target)
+SYM_CODE_END(xen_entry_SYSCALL_compat)
 
 /* 32-bit compat sysenter target */
-SYM_CODE_START(xen_sysenter_target)
-       UNWIND_HINT_EMPTY
+SYM_CODE_START(xen_entry_SYSENTER_compat)
+       UNWIND_HINT_ENTRY
        ENDBR
        /*
         * NB: Xen is polite and clears TF from EFLAGS for us.  This means
@@ -291,19 +291,19 @@ SYM_CODE_START(xen_sysenter_target)
        movq $__USER32_CS, 1*8(%rsp)
 
        jmp entry_SYSENTER_compat_after_hwframe
-SYM_CODE_END(xen_sysenter_target)
+SYM_CODE_END(xen_entry_SYSENTER_compat)
 
 #else /* !CONFIG_IA32_EMULATION */
 
-SYM_CODE_START(xen_syscall32_target)
-SYM_CODE_START(xen_sysenter_target)
-       UNWIND_HINT_EMPTY
+SYM_CODE_START(xen_entry_SYSCALL_compat)
+SYM_CODE_START(xen_entry_SYSENTER_compat)
+       UNWIND_HINT_ENTRY
        ENDBR
        lea 16(%rsp), %rsp      /* strip %rcx, %r11 */
        mov $-ENOSYS, %rax
        pushq $0
        jmp hypercall_iret
-SYM_CODE_END(xen_sysenter_target)
-SYM_CODE_END(xen_syscall32_target)
+SYM_CODE_END(xen_entry_SYSENTER_compat)
+SYM_CODE_END(xen_entry_SYSCALL_compat)
 
 #endif /* CONFIG_IA32_EMULATION */
index 3a2cd93..ffaa621 100644 (file)
@@ -26,6 +26,7 @@ SYM_CODE_START(hypercall_page)
        .rept (PAGE_SIZE / 32)
                UNWIND_HINT_FUNC
                ANNOTATE_NOENDBR
+               ANNOTATE_UNRET_SAFE
                ret
                /*
                 * Xen will write the hypercall page, and sort out ENDBR.
@@ -48,15 +49,6 @@ SYM_CODE_START(startup_xen)
        ANNOTATE_NOENDBR
        cld
 
-       /* Clear .bss */
-       xor %eax,%eax
-       mov $__bss_start, %rdi
-       mov $__bss_stop, %rcx
-       sub %rdi, %rcx
-       shr $3, %rcx
-       rep stosq
-
-       mov %rsi, xen_start_info
        mov initial_stack(%rip), %rsp
 
        /* Set up %gs.
@@ -71,6 +63,7 @@ SYM_CODE_START(startup_xen)
        cdq
        wrmsr
 
+       mov     %rsi, %rdi
        call xen_start_kernel
 SYM_CODE_END(startup_xen)
        __FINIT
index fd0fec6..9a8bb97 100644 (file)
 /* These are code, but not functions.  Defined in entry.S */
 extern const char xen_failsafe_callback[];
 
-void xen_sysenter_target(void);
+void xen_entry_SYSENTER_compat(void);
 #ifdef CONFIG_X86_64
-void xen_syscall_target(void);
-void xen_syscall32_target(void);
+void xen_entry_SYSCALL_64(void);
+void xen_entry_SYSCALL_compat(void);
 #endif
 
 extern void *xen_initial_gdt;
index 0b0f017..7927fed 100644 (file)
@@ -33,7 +33,7 @@ config XTENSA
        select HAVE_ARCH_KCSAN
        select HAVE_ARCH_SECCOMP_FILTER
        select HAVE_ARCH_TRACEHOOK
-       select HAVE_CONTEXT_TRACKING
+       select HAVE_CONTEXT_TRACKING_USER
        select HAVE_DEBUG_KMEMLEAK
        select HAVE_DMA_CONTIGUOUS
        select HAVE_EXIT_THREAD
index e3eae64..272fff5 100644 (file)
@@ -455,10 +455,10 @@ KABI_W    or      a3, a3, a2
        abi_call        trace_hardirqs_off
 1:
 #endif
-#ifdef CONFIG_CONTEXT_TRACKING
+#ifdef CONFIG_CONTEXT_TRACKING_USER
        l32i            abi_tmp0, a1, PT_PS
        bbci.l          abi_tmp0, PS_UM_BIT, 1f
-       abi_call        context_tracking_user_exit
+       abi_call        user_exit_callable
 1:
 #endif
 
@@ -544,8 +544,8 @@ common_exception_return:
        j               .Lrestore_state
 
 .Lexit_tif_loop_user:
-#ifdef CONFIG_CONTEXT_TRACKING
-       abi_call        context_tracking_user_enter
+#ifdef CONFIG_CONTEXT_TRACKING_USER
+       abi_call        user_enter_callable
 #endif
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
        _bbci.l         abi_saved0, TIF_DB_DISABLED, 1f
@@ -2173,7 +2173,7 @@ ENDPROC(ret_from_kernel_thread)
 
 #ifdef CONFIG_HIBERNATION
 
-       .bss
+       .section        .bss, "aw"
        .align  4
 .Lsaved_regs:
 #if defined(__XTENSA_WINDOWED_ABI__)
index 529fe92..42f1060 100644 (file)
@@ -169,7 +169,7 @@ void migrate_irqs(void)
 
        for_each_active_irq(i) {
                struct irq_data *data = irq_get_irq_data(i);
-               struct cpumask *mask;
+               const struct cpumask *mask;
                unsigned int newcpu;
 
                if (irqd_is_per_cpu(data))
@@ -185,9 +185,10 @@ void migrate_irqs(void)
                        pr_info_ratelimited("IRQ%u no longer affine to CPU%u\n",
                                            i, cpu);
 
-                       cpumask_setall(mask);
+                       irq_set_affinity(i, cpu_all_mask);
+               } else {
+                       irq_set_affinity(i, mask);
                }
-               irq_set_affinity(i, mask);
        }
 }
 #endif /* CONFIG_HOTPLUG_CPU */
index e8ceb15..16b8a62 100644 (file)
@@ -154,6 +154,7 @@ static void __init calibrate_ccount(void)
        cpu = of_find_compatible_node(NULL, NULL, "cdns,xtensa-cpu");
        if (cpu) {
                clk = of_clk_get(cpu, 0);
+               of_node_put(cpu);
                if (!IS_ERR(clk)) {
                        ccount_freq = clk_get_rate(clk);
                        return;
index 4255b92..f50caaa 100644 (file)
@@ -290,7 +290,7 @@ static int __init simdisk_setup(struct simdisk *dev, int which,
        return 0;
 
 out_cleanup_disk:
-       blk_cleanup_disk(dev->gd);
+       put_disk(dev->gd);
 out:
        return err;
 }
@@ -344,7 +344,7 @@ static void simdisk_teardown(struct simdisk *dev, int which,
        simdisk_detach(dev);
        if (dev->gd) {
                del_gendisk(dev->gd);
-               blk_cleanup_disk(dev->gd);
+               put_disk(dev->gd);
        }
        remove_proc_entry(tmp, procdir);
 }
index 538e674..c79c1d0 100644 (file)
@@ -133,6 +133,7 @@ static int __init machine_setup(void)
 
        if ((eth = of_find_compatible_node(eth, NULL, "opencores,ethoc")))
                update_local_mac(eth);
+       of_node_put(eth);
        return 0;
 }
 arch_initcall(machine_setup);
index 50b17e2..444c5ab 100644 (file)
@@ -147,7 +147,6 @@ config BLK_CGROUP_FC_APPID
 config BLK_CGROUP_IOCOST
        bool "Enable support for cost model based cgroup IO controller"
        depends on BLK_CGROUP
-       select BLK_RQ_IO_DATA_LEN
        select BLK_RQ_ALLOC_TIME
        help
        Enabling this option enables the .weight interface for cost
index 5fe06c1..ce05175 100644 (file)
@@ -54,12 +54,10 @@ static void bdev_write_inode(struct block_device *bdev)
        while (inode->i_state & I_DIRTY) {
                spin_unlock(&inode->i_lock);
                ret = write_inode_now(inode, true);
-               if (ret) {
-                       char name[BDEVNAME_SIZE];
-                       pr_warn_ratelimited("VFS: Dirty inode writeback failed "
-                                           "for block device %s (err=%d).\n",
-                                           bdevname(bdev, name), ret);
-               }
+               if (ret)
+                       pr_warn_ratelimited(
+       "VFS: Dirty inode writeback failed for block device %pg (err=%d).\n",
+                               bdev, ret);
                spin_lock(&inode->i_lock);
        }
        spin_unlock(&inode->i_lock);
index 09574af..30b15a9 100644 (file)
@@ -220,46 +220,46 @@ void bfqg_stats_update_avg_queue_size(struct bfq_group *bfqg)
 }
 
 void bfqg_stats_update_io_add(struct bfq_group *bfqg, struct bfq_queue *bfqq,
-                             unsigned int op)
+                             blk_opf_t opf)
 {
-       blkg_rwstat_add(&bfqg->stats.queued, op, 1);
+       blkg_rwstat_add(&bfqg->stats.queued, opf, 1);
        bfqg_stats_end_empty_time(&bfqg->stats);
        if (!(bfqq == ((struct bfq_data *)bfqg->bfqd)->in_service_queue))
                bfqg_stats_set_start_group_wait_time(bfqg, bfqq_group(bfqq));
 }
 
-void bfqg_stats_update_io_remove(struct bfq_group *bfqg, unsigned int op)
+void bfqg_stats_update_io_remove(struct bfq_group *bfqg, blk_opf_t opf)
 {
-       blkg_rwstat_add(&bfqg->stats.queued, op, -1);
+       blkg_rwstat_add(&bfqg->stats.queued, opf, -1);
 }
 
-void bfqg_stats_update_io_merged(struct bfq_group *bfqg, unsigned int op)
+void bfqg_stats_update_io_merged(struct bfq_group *bfqg, blk_opf_t opf)
 {
-       blkg_rwstat_add(&bfqg->stats.merged, op, 1);
+       blkg_rwstat_add(&bfqg->stats.merged, opf, 1);
 }
 
 void bfqg_stats_update_completion(struct bfq_group *bfqg, u64 start_time_ns,
-                                 u64 io_start_time_ns, unsigned int op)
+                                 u64 io_start_time_ns, blk_opf_t opf)
 {
        struct bfqg_stats *stats = &bfqg->stats;
        u64 now = ktime_get_ns();
 
        if (now > io_start_time_ns)
-               blkg_rwstat_add(&stats->service_time, op,
+               blkg_rwstat_add(&stats->service_time, opf,
                                now - io_start_time_ns);
        if (io_start_time_ns > start_time_ns)
-               blkg_rwstat_add(&stats->wait_time, op,
+               blkg_rwstat_add(&stats->wait_time, opf,
                                io_start_time_ns - start_time_ns);
 }
 
 #else /* CONFIG_BFQ_CGROUP_DEBUG */
 
 void bfqg_stats_update_io_add(struct bfq_group *bfqg, struct bfq_queue *bfqq,
-                             unsigned int op) { }
-void bfqg_stats_update_io_remove(struct bfq_group *bfqg, unsigned int op) { }
-void bfqg_stats_update_io_merged(struct bfq_group *bfqg, unsigned int op) { }
+                             blk_opf_t opf) { }
+void bfqg_stats_update_io_remove(struct bfq_group *bfqg, blk_opf_t opf) { }
+void bfqg_stats_update_io_merged(struct bfq_group *bfqg, blk_opf_t opf) { }
 void bfqg_stats_update_completion(struct bfq_group *bfqg, u64 start_time_ns,
-                                 u64 io_start_time_ns, unsigned int op) { }
+                                 u64 io_start_time_ns, blk_opf_t opf) { }
 void bfqg_stats_update_dequeue(struct bfq_group *bfqg) { }
 void bfqg_stats_set_start_empty_time(struct bfq_group *bfqg) { }
 void bfqg_stats_update_idle_time(struct bfq_group *bfqg) { }
@@ -706,10 +706,10 @@ void bfq_bfqq_move(struct bfq_data *bfqd, struct bfq_queue *bfqq,
 }
 
 /**
- * __bfq_bic_change_cgroup - move @bic to @cgroup.
+ * __bfq_bic_change_cgroup - move @bic to @bfqg.
  * @bfqd: the queue descriptor.
  * @bic: the bic to move.
- * @blkcg: the blk-cgroup to move to.
+ * @bfqg: the group to move to.
  *
  * Move bic to blkcg, assuming that bfqd->lock is held; which makes
  * sure that the reference to cgroup is valid across the call (see
@@ -863,6 +863,7 @@ static void bfq_flush_idle_tree(struct bfq_service_tree *st)
  * @bfqd: the device data structure with the root group.
  * @entity: the entity to move, if entity is a leaf; or the parent entity
  *         of an active leaf entity to move, if entity is not a leaf.
+ * @ioprio_class: I/O priority class to reparent.
  */
 static void bfq_reparent_leaf_entity(struct bfq_data *bfqd,
                                     struct bfq_entity *entity,
@@ -892,6 +893,7 @@ static void bfq_reparent_leaf_entity(struct bfq_data *bfqd,
  * @bfqd: the device data structure with the root group.
  * @bfqg: the group to move from.
  * @st: the service tree to start the search from.
+ * @ioprio_class: I/O priority class to reparent.
  */
 static void bfq_reparent_active_queues(struct bfq_data *bfqd,
                                       struct bfq_group *bfqg,
@@ -1471,8 +1473,6 @@ struct bfq_group *bfqq_group(struct bfq_queue *bfqq)
        return bfqq->bfqd->root_group;
 }
 
-void bfqg_and_blkg_get(struct bfq_group *bfqg) {}
-
 void bfqg_and_blkg_put(struct bfq_group *bfqg) {}
 
 struct bfq_group *bfq_create_group_hierarchy(struct bfq_data *bfqd, int node)
index e6d7e6b..c740b41 100644 (file)
@@ -668,19 +668,19 @@ static bool bfqq_request_over_limit(struct bfq_queue *bfqq, int limit)
  * significantly affect service guarantees coming from the BFQ scheduling
  * algorithm.
  */
-static void bfq_limit_depth(unsigned int op, struct blk_mq_alloc_data *data)
+static void bfq_limit_depth(blk_opf_t opf, struct blk_mq_alloc_data *data)
 {
        struct bfq_data *bfqd = data->q->elevator->elevator_data;
        struct bfq_io_cq *bic = bfq_bic_lookup(data->q);
-       struct bfq_queue *bfqq = bic ? bic_to_bfqq(bic, op_is_sync(op)) : NULL;
+       struct bfq_queue *bfqq = bic ? bic_to_bfqq(bic, op_is_sync(opf)) : NULL;
        int depth;
        unsigned limit = data->q->nr_requests;
 
        /* Sync reads have full depth available */
-       if (op_is_sync(op) && !op_is_write(op)) {
+       if (op_is_sync(opf) && !op_is_write(opf)) {
                depth = 0;
        } else {
-               depth = bfqd->word_depths[!!bfqd->wr_busy_queues][op_is_sync(op)];
+               depth = bfqd->word_depths[!!bfqd->wr_busy_queues][op_is_sync(opf)];
                limit = (limit * depth) >> bfqd->full_depth_shift;
        }
 
@@ -693,7 +693,7 @@ static void bfq_limit_depth(unsigned int op, struct blk_mq_alloc_data *data)
                depth = 1;
 
        bfq_log(bfqd, "[%s] wr_busy %d sync %d depth %u",
-               __func__, bfqd->wr_busy_queues, op_is_sync(op), depth);
+               __func__, bfqd->wr_busy_queues, op_is_sync(opf), depth);
        if (depth)
                data->shallow_depth = depth;
 }
@@ -6104,7 +6104,7 @@ static bool __bfq_insert_request(struct bfq_data *bfqd, struct request *rq)
 static void bfq_update_insert_stats(struct request_queue *q,
                                    struct bfq_queue *bfqq,
                                    bool idle_timer_disabled,
-                                   unsigned int cmd_flags)
+                                   blk_opf_t cmd_flags)
 {
        if (!bfqq)
                return;
@@ -6129,7 +6129,7 @@ static void bfq_update_insert_stats(struct request_queue *q,
 static inline void bfq_update_insert_stats(struct request_queue *q,
                                           struct bfq_queue *bfqq,
                                           bool idle_timer_disabled,
-                                          unsigned int cmd_flags) {}
+                                          blk_opf_t cmd_flags) {}
 #endif /* CONFIG_BFQ_CGROUP_DEBUG */
 
 static struct bfq_queue *bfq_init_rq(struct request *rq);
@@ -6141,7 +6141,7 @@ static void bfq_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq,
        struct bfq_data *bfqd = q->elevator->elevator_data;
        struct bfq_queue *bfqq;
        bool idle_timer_disabled = false;
-       unsigned int cmd_flags;
+       blk_opf_t cmd_flags;
        LIST_HEAD(free);
 
 #ifdef CONFIG_BFQ_GROUP_IOSCHED
index ca8177d..ad8e513 100644 (file)
@@ -994,11 +994,11 @@ void bfq_put_async_queues(struct bfq_data *bfqd, struct bfq_group *bfqg);
 
 void bfqg_stats_update_legacy_io(struct request_queue *q, struct request *rq);
 void bfqg_stats_update_io_add(struct bfq_group *bfqg, struct bfq_queue *bfqq,
-                             unsigned int op);
-void bfqg_stats_update_io_remove(struct bfq_group *bfqg, unsigned int op);
-void bfqg_stats_update_io_merged(struct bfq_group *bfqg, unsigned int op);
+                             blk_opf_t opf);
+void bfqg_stats_update_io_remove(struct bfq_group *bfqg, blk_opf_t opf);
+void bfqg_stats_update_io_merged(struct bfq_group *bfqg, blk_opf_t opf);
 void bfqg_stats_update_completion(struct bfq_group *bfqg, u64 start_time_ns,
-                                 u64 io_start_time_ns, unsigned int op);
+                                 u64 io_start_time_ns, blk_opf_t opf);
 void bfqg_stats_update_dequeue(struct bfq_group *bfqg);
 void bfqg_stats_set_start_empty_time(struct bfq_group *bfqg);
 void bfqg_stats_update_idle_time(struct bfq_group *bfqg);
index f8eb340..983413c 100644 (file)
@@ -1360,6 +1360,8 @@ left:
 /**
  * __bfq_lookup_next_entity - return the first eligible entity in @st.
  * @st: the service tree.
+ * @in_service: whether or not there is an in-service entity for the sched_data
+ *     this active tree belongs to.
  *
  * If there is no in-service entity for the sched_data st belongs to,
  * then return the entity that will be set in service if:
@@ -1472,9 +1474,6 @@ static struct bfq_entity *bfq_lookup_next_entity(struct bfq_sched_data *sd,
                        break;
        }
 
-       if (!entity)
-               return NULL;
-
        return entity;
 }
 
index 51c99f2..6f9f883 100644 (file)
@@ -239,7 +239,7 @@ static void bio_free(struct bio *bio)
  * when IO has completed, or when the bio is released.
  */
 void bio_init(struct bio *bio, struct block_device *bdev, struct bio_vec *table,
-             unsigned short max_vecs, unsigned int opf)
+             unsigned short max_vecs, blk_opf_t opf)
 {
        bio->bi_next = NULL;
        bio->bi_bdev = bdev;
@@ -292,7 +292,7 @@ EXPORT_SYMBOL(bio_init);
  *   preserved are the ones that are initialized by bio_alloc_bioset(). See
  *   comment in struct bio.
  */
-void bio_reset(struct bio *bio, struct block_device *bdev, unsigned int opf)
+void bio_reset(struct bio *bio, struct block_device *bdev, blk_opf_t opf)
 {
        bio_uninit(bio);
        memset(bio, 0, BIO_RESET_BYTES);
@@ -341,7 +341,7 @@ void bio_chain(struct bio *bio, struct bio *parent)
 EXPORT_SYMBOL(bio_chain);
 
 struct bio *blk_next_bio(struct bio *bio, struct block_device *bdev,
-               unsigned int nr_pages, unsigned int opf, gfp_t gfp)
+               unsigned int nr_pages, blk_opf_t opf, gfp_t gfp)
 {
        struct bio *new = bio_alloc(bdev, nr_pages, opf, gfp);
 
@@ -409,7 +409,7 @@ static void punt_bios_to_rescuer(struct bio_set *bs)
 }
 
 static struct bio *bio_alloc_percpu_cache(struct block_device *bdev,
-               unsigned short nr_vecs, unsigned int opf, gfp_t gfp,
+               unsigned short nr_vecs, blk_opf_t opf, gfp_t gfp,
                struct bio_set *bs)
 {
        struct bio_alloc_cache *cache;
@@ -468,7 +468,7 @@ static struct bio *bio_alloc_percpu_cache(struct block_device *bdev,
  * Returns: Pointer to new bio on success, NULL on failure.
  */
 struct bio *bio_alloc_bioset(struct block_device *bdev, unsigned short nr_vecs,
-                            unsigned int opf, gfp_t gfp_mask,
+                            blk_opf_t opf, gfp_t gfp_mask,
                             struct bio_set *bs)
 {
        gfp_t saved_gfp = gfp_mask;
@@ -1033,7 +1033,7 @@ int bio_add_zone_append_page(struct bio *bio, struct page *page,
        if (WARN_ON_ONCE(bio_op(bio) != REQ_OP_ZONE_APPEND))
                return 0;
 
-       if (WARN_ON_ONCE(!blk_queue_is_zoned(q)))
+       if (WARN_ON_ONCE(!bdev_is_zoned(bio->bi_bdev)))
                return 0;
 
        return bio_add_hw_page(q, bio, page, len, offset,
@@ -1159,6 +1159,37 @@ static void bio_put_pages(struct page **pages, size_t size, size_t off)
                put_page(pages[i]);
 }
 
+static int bio_iov_add_page(struct bio *bio, struct page *page,
+               unsigned int len, unsigned int offset)
+{
+       bool same_page = false;
+
+       if (!__bio_try_merge_page(bio, page, len, offset, &same_page)) {
+               if (WARN_ON_ONCE(bio_full(bio, len)))
+                       return -EINVAL;
+               __bio_add_page(bio, page, len, offset);
+               return 0;
+       }
+
+       if (same_page)
+               put_page(page);
+       return 0;
+}
+
+static int bio_iov_add_zone_append_page(struct bio *bio, struct page *page,
+               unsigned int len, unsigned int offset)
+{
+       struct request_queue *q = bdev_get_queue(bio->bi_bdev);
+       bool same_page = false;
+
+       if (bio_add_hw_page(q, bio, page, len, offset,
+                       queue_max_zone_append_sectors(q), &same_page) != len)
+               return -EINVAL;
+       if (same_page)
+               put_page(page);
+       return 0;
+}
+
 #define PAGE_PTRS_PER_BVEC     (sizeof(struct bio_vec) / sizeof(struct page *))
 
 /**
@@ -1177,7 +1208,6 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
        unsigned short entries_left = bio->bi_max_vecs - bio->bi_vcnt;
        struct bio_vec *bv = bio->bi_io_vec + bio->bi_vcnt;
        struct page **pages = (struct page **)bv;
-       bool same_page = false;
        ssize_t size, left;
        unsigned len, i;
        size_t offset;
@@ -1186,82 +1216,43 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
         * Move page array up in the allocated memory for the bio vecs as far as
         * possible so that we can start filling biovecs from the beginning
         * without overwriting the temporary page array.
-       */
+        */
        BUILD_BUG_ON(PAGE_PTRS_PER_BVEC < 2);
        pages += entries_left * (PAGE_PTRS_PER_BVEC - 1);
 
-       size = iov_iter_get_pages(iter, pages, LONG_MAX, nr_pages, &offset);
-       if (unlikely(size <= 0))
-               return size ? size : -EFAULT;
-
-       for (left = size, i = 0; left > 0; left -= len, i++) {
-               struct page *page = pages[i];
-
-               len = min_t(size_t, PAGE_SIZE - offset, left);
-
-               if (__bio_try_merge_page(bio, page, len, offset, &same_page)) {
-                       if (same_page)
-                               put_page(page);
-               } else {
-                       if (WARN_ON_ONCE(bio_full(bio, len))) {
-                               bio_put_pages(pages + i, left, offset);
-                               return -EINVAL;
-                       }
-                       __bio_add_page(bio, page, len, offset);
-               }
-               offset = 0;
-       }
-
-       iov_iter_advance(iter, size);
-       return 0;
-}
-
-static int __bio_iov_append_get_pages(struct bio *bio, struct iov_iter *iter)
-{
-       unsigned short nr_pages = bio->bi_max_vecs - bio->bi_vcnt;
-       unsigned short entries_left = bio->bi_max_vecs - bio->bi_vcnt;
-       struct request_queue *q = bdev_get_queue(bio->bi_bdev);
-       unsigned int max_append_sectors = queue_max_zone_append_sectors(q);
-       struct bio_vec *bv = bio->bi_io_vec + bio->bi_vcnt;
-       struct page **pages = (struct page **)bv;
-       ssize_t size, left;
-       unsigned len, i;
-       size_t offset;
-       int ret = 0;
-
-       if (WARN_ON_ONCE(!max_append_sectors))
-               return 0;
-
        /*
-        * Move page array up in the allocated memory for the bio vecs as far as
-        * possible so that we can start filling biovecs from the beginning
-        * without overwriting the temporary page array.
+        * Each segment in the iov is required to be a block size multiple.
+        * However, we may not be able to get the entire segment if it spans
+        * more pages than bi_max_vecs allows, so we have to ALIGN_DOWN the
+        * result to ensure the bio's total size is correct. The remainder of
+        * the iov data will be picked up in the next bio iteration.
         */
-       BUILD_BUG_ON(PAGE_PTRS_PER_BVEC < 2);
-       pages += entries_left * (PAGE_PTRS_PER_BVEC - 1);
-
        size = iov_iter_get_pages(iter, pages, LONG_MAX, nr_pages, &offset);
+       if (size > 0)
+               size = ALIGN_DOWN(size, bdev_logical_block_size(bio->bi_bdev));
        if (unlikely(size <= 0))
                return size ? size : -EFAULT;
 
        for (left = size, i = 0; left > 0; left -= len, i++) {
                struct page *page = pages[i];
-               bool same_page = false;
+               int ret;
 
                len = min_t(size_t, PAGE_SIZE - offset, left);
-               if (bio_add_hw_page(q, bio, page, len, offset,
-                               max_append_sectors, &same_page) != len) {
+               if (bio_op(bio) == REQ_OP_ZONE_APPEND)
+                       ret = bio_iov_add_zone_append_page(bio, page, len,
+                                       offset);
+               else
+                       ret = bio_iov_add_page(bio, page, len, offset);
+
+               if (ret) {
                        bio_put_pages(pages + i, left, offset);
-                       ret = -EINVAL;
-                       break;
+                       return ret;
                }
-               if (same_page)
-                       put_page(page);
                offset = 0;
        }
 
-       iov_iter_advance(iter, size - left);
-       return ret;
+       iov_iter_advance(iter, size);
+       return 0;
 }
 
 /**
@@ -1298,10 +1289,7 @@ int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
        }
 
        do {
-               if (bio_op(bio) == REQ_OP_ZONE_APPEND)
-                       ret = __bio_iov_append_get_pages(bio, iter);
-               else
-                       ret = __bio_iov_iter_get_pages(bio, iter);
+               ret = __bio_iov_iter_get_pages(bio, iter);
        } while (!ret && iov_iter_count(iter) && !bio_full(bio, 0));
 
        /* don't account direct I/O as memory stall */
index 9f2723b..022527b 100644 (file)
@@ -59,20 +59,20 @@ void blkg_rwstat_recursive_sum(struct blkcg_gq *blkg, struct blkcg_policy *pol,
  * caller is responsible for synchronizing calls to this function.
  */
 static inline void blkg_rwstat_add(struct blkg_rwstat *rwstat,
-                                  unsigned int op, uint64_t val)
+                                  blk_opf_t opf, uint64_t val)
 {
        struct percpu_counter *cnt;
 
-       if (op_is_discard(op))
+       if (op_is_discard(opf))
                cnt = &rwstat->cpu_cnt[BLKG_RWSTAT_DISCARD];
-       else if (op_is_write(op))
+       else if (op_is_write(opf))
                cnt = &rwstat->cpu_cnt[BLKG_RWSTAT_WRITE];
        else
                cnt = &rwstat->cpu_cnt[BLKG_RWSTAT_READ];
 
        percpu_counter_add_batch(cnt, val, BLKG_STAT_CPU_BATCH);
 
-       if (op_is_sync(op))
+       if (op_is_sync(opf))
                cnt = &rwstat->cpu_cnt[BLKG_RWSTAT_SYNC];
        else
                cnt = &rwstat->cpu_cnt[BLKG_RWSTAT_ASYNC];
index 764e740..869af9d 100644 (file)
@@ -846,6 +846,21 @@ static void blkg_iostat_sub(struct blkg_iostat *dst, struct blkg_iostat *src)
        }
 }
 
+static void blkcg_iostat_update(struct blkcg_gq *blkg, struct blkg_iostat *cur,
+                               struct blkg_iostat *last)
+{
+       struct blkg_iostat delta;
+       unsigned long flags;
+
+       /* propagate percpu delta to global */
+       flags = u64_stats_update_begin_irqsave(&blkg->iostat.sync);
+       blkg_iostat_set(&delta, cur);
+       blkg_iostat_sub(&delta, last);
+       blkg_iostat_add(&blkg->iostat.cur, &delta);
+       blkg_iostat_add(last, &delta);
+       u64_stats_update_end_irqrestore(&blkg->iostat.sync, flags);
+}
+
 static void blkcg_rstat_flush(struct cgroup_subsys_state *css, int cpu)
 {
        struct blkcg *blkcg = css_to_blkcg(css);
@@ -860,8 +875,7 @@ static void blkcg_rstat_flush(struct cgroup_subsys_state *css, int cpu)
        hlist_for_each_entry_rcu(blkg, &blkcg->blkg_list, blkcg_node) {
                struct blkcg_gq *parent = blkg->parent;
                struct blkg_iostat_set *bisc = per_cpu_ptr(blkg->iostat_cpu, cpu);
-               struct blkg_iostat cur, delta;
-               unsigned long flags;
+               struct blkg_iostat cur;
                unsigned int seq;
 
                /* fetch the current per-cpu values */
@@ -870,23 +884,12 @@ static void blkcg_rstat_flush(struct cgroup_subsys_state *css, int cpu)
                        blkg_iostat_set(&cur, &bisc->cur);
                } while (u64_stats_fetch_retry(&bisc->sync, seq));
 
-               /* propagate percpu delta to global */
-               flags = u64_stats_update_begin_irqsave(&blkg->iostat.sync);
-               blkg_iostat_set(&delta, &cur);
-               blkg_iostat_sub(&delta, &bisc->last);
-               blkg_iostat_add(&blkg->iostat.cur, &delta);
-               blkg_iostat_add(&bisc->last, &delta);
-               u64_stats_update_end_irqrestore(&blkg->iostat.sync, flags);
+               blkcg_iostat_update(blkg, &cur, &bisc->last);
 
                /* propagate global delta to parent (unless that's root) */
-               if (parent && parent->parent) {
-                       flags = u64_stats_update_begin_irqsave(&parent->iostat.sync);
-                       blkg_iostat_set(&delta, &blkg->iostat.cur);
-                       blkg_iostat_sub(&delta, &blkg->iostat.last);
-                       blkg_iostat_add(&parent->iostat.cur, &delta);
-                       blkg_iostat_add(&blkg->iostat.last, &delta);
-                       u64_stats_update_end_irqrestore(&parent->iostat.sync, flags);
-               }
+               if (parent && parent->parent)
+                       blkcg_iostat_update(parent, &blkg->iostat.cur,
+                                           &blkg->iostat.last);
        }
 
        rcu_read_unlock();
@@ -1299,6 +1302,7 @@ int blkcg_init_queue(struct request_queue *q)
        ret = blk_iolatency_init(q);
        if (ret) {
                blk_throtl_exit(q);
+               blk_ioprio_exit(q);
                goto err_destroy_all;
        }
 
@@ -1529,6 +1533,18 @@ void blkcg_deactivate_policy(struct request_queue *q,
 }
 EXPORT_SYMBOL_GPL(blkcg_deactivate_policy);
 
+static void blkcg_free_all_cpd(struct blkcg_policy *pol)
+{
+       struct blkcg *blkcg;
+
+       list_for_each_entry(blkcg, &all_blkcgs, all_blkcgs_node) {
+               if (blkcg->cpd[pol->plid]) {
+                       pol->cpd_free_fn(blkcg->cpd[pol->plid]);
+                       blkcg->cpd[pol->plid] = NULL;
+               }
+       }
+}
+
 /**
  * blkcg_policy_register - register a blkcg policy
  * @pol: blkcg policy to register
@@ -1593,14 +1609,9 @@ int blkcg_policy_register(struct blkcg_policy *pol)
        return 0;
 
 err_free_cpds:
-       if (pol->cpd_free_fn) {
-               list_for_each_entry(blkcg, &all_blkcgs, all_blkcgs_node) {
-                       if (blkcg->cpd[pol->plid]) {
-                               pol->cpd_free_fn(blkcg->cpd[pol->plid]);
-                               blkcg->cpd[pol->plid] = NULL;
-                       }
-               }
-       }
+       if (pol->cpd_free_fn)
+               blkcg_free_all_cpd(pol);
+
        blkcg_policy[pol->plid] = NULL;
 err_unlock:
        mutex_unlock(&blkcg_pol_mutex);
@@ -1617,8 +1628,6 @@ EXPORT_SYMBOL_GPL(blkcg_policy_register);
  */
 void blkcg_policy_unregister(struct blkcg_policy *pol)
 {
-       struct blkcg *blkcg;
-
        mutex_lock(&blkcg_pol_register_mutex);
 
        if (WARN_ON(blkcg_policy[pol->plid] != pol))
@@ -1633,14 +1642,9 @@ void blkcg_policy_unregister(struct blkcg_policy *pol)
        /* remove cpds and unregister */
        mutex_lock(&blkcg_pol_mutex);
 
-       if (pol->cpd_free_fn) {
-               list_for_each_entry(blkcg, &all_blkcgs, all_blkcgs_node) {
-                       if (blkcg->cpd[pol->plid]) {
-                               pol->cpd_free_fn(blkcg->cpd[pol->plid]);
-                               blkcg->cpd[pol->plid] = NULL;
-                       }
-               }
-       }
+       if (pol->cpd_free_fn)
+               blkcg_free_all_cpd(pol);
+
        blkcg_policy[pol->plid] = NULL;
 
        mutex_unlock(&blkcg_pol_mutex);
@@ -1696,7 +1700,7 @@ static void blkcg_scale_delay(struct blkcg_gq *blkg, u64 now)
         * everybody is happy with their IO latencies.
         */
        if (time_before64(old + NSEC_PER_SEC, now) &&
-           atomic64_cmpxchg(&blkg->delay_start, old, now) == old) {
+           atomic64_try_cmpxchg(&blkg->delay_start, &old, now)) {
                u64 cur = atomic64_read(&blkg->delay_nsec);
                u64 sub = min_t(u64, blkg->last_delay, now - old);
                int cur_use = atomic_read(&blkg->use_delay);
index d4de0a3..d2724d1 100644 (file)
@@ -430,12 +430,8 @@ static inline int blkcg_unuse_delay(struct blkcg_gq *blkg)
         * then check to see if we were the last delay so we can drop the
         * congestion count on the cgroup.
         */
-       while (old) {
-               int cur = atomic_cmpxchg(&blkg->use_delay, old, old - 1);
-               if (cur == old)
-                       break;
-               old = cur;
-       }
+       while (old && !atomic_try_cmpxchg(&blkg->use_delay, &old, old - 1))
+               ;
 
        if (old == 0)
                return 0;
@@ -458,7 +454,7 @@ static inline void blkcg_set_delay(struct blkcg_gq *blkg, u64 delay)
        int old = atomic_read(&blkg->use_delay);
 
        /* We only want 1 person setting the congestion count for this blkg. */
-       if (!old && atomic_cmpxchg(&blkg->use_delay, old, -1) == old)
+       if (!old && atomic_try_cmpxchg(&blkg->use_delay, &old, -1))
                atomic_inc(&blkg->blkcg->css.cgroup->congestion_count);
 
        atomic64_set(&blkg->delay_nsec, delay);
@@ -475,7 +471,7 @@ static inline void blkcg_clear_delay(struct blkcg_gq *blkg)
        int old = atomic_read(&blkg->use_delay);
 
        /* We only want 1 person clearing the congestion count for this blkg. */
-       if (old && atomic_cmpxchg(&blkg->use_delay, old, 0) == old)
+       if (old && atomic_try_cmpxchg(&blkg->use_delay, &old, 0))
                atomic_dec(&blkg->blkcg->css.cgroup->congestion_count);
 }
 
index 27fb135..3d286a2 100644 (file)
@@ -136,7 +136,7 @@ static const char *const blk_op_name[] = {
  * string format. Useful in the debugging and tracing bio or request. For
  * invalid REQ_OP_XXX it returns string "UNKNOWN".
  */
-inline const char *blk_op_str(unsigned int op)
+inline const char *blk_op_str(enum req_op op)
 {
        const char *op_str = "UNKNOWN";
 
@@ -285,49 +285,6 @@ void blk_queue_start_drain(struct request_queue *q)
 }
 
 /**
- * blk_cleanup_queue - shutdown a request queue
- * @q: request queue to shutdown
- *
- * Mark @q DYING, drain all pending requests, mark @q DEAD, destroy and
- * put it.  All future requests will be failed immediately with -ENODEV.
- *
- * Context: can sleep
- */
-void blk_cleanup_queue(struct request_queue *q)
-{
-       /* cannot be called from atomic context */
-       might_sleep();
-
-       WARN_ON_ONCE(blk_queue_registered(q));
-
-       /* mark @q DYING, no new request or merges will be allowed afterwards */
-       blk_queue_flag_set(QUEUE_FLAG_DYING, q);
-       blk_queue_start_drain(q);
-
-       blk_queue_flag_set(QUEUE_FLAG_NOMERGES, q);
-       blk_queue_flag_set(QUEUE_FLAG_NOXMERGES, q);
-
-       /*
-        * Drain all requests queued before DYING marking. Set DEAD flag to
-        * prevent that blk_mq_run_hw_queues() accesses the hardware queues
-        * after draining finished.
-        */
-       blk_freeze_queue(q);
-
-       blk_queue_flag_set(QUEUE_FLAG_DEAD, q);
-
-       blk_sync_queue(q);
-       if (queue_is_mq(q)) {
-               blk_mq_cancel_work_sync(q);
-               blk_mq_exit_queue(q);
-       }
-
-       /* @q is and will stay empty, shutdown and put */
-       blk_put_queue(q);
-}
-EXPORT_SYMBOL(blk_cleanup_queue);
-
-/**
  * blk_queue_enter() - try to increase q->q_usage_counter
  * @q: request queue pointer
  * @flags: BLK_MQ_REQ_NOWAIT and/or BLK_MQ_REQ_PM
@@ -435,7 +392,7 @@ struct request_queue *blk_alloc_queue(int node_id, bool alloc_srcu)
 
        q->last_merge = NULL;
 
-       q->id = ida_simple_get(&blk_queue_ida, 0, 0, GFP_KERNEL);
+       q->id = ida_alloc(&blk_queue_ida, GFP_KERNEL);
        if (q->id < 0)
                goto fail_srcu;
 
@@ -485,7 +442,7 @@ fail_stats:
 fail_split:
        bioset_exit(&q->bio_split);
 fail_id:
-       ida_simple_remove(&blk_queue_ida, q->id);
+       ida_free(&blk_queue_ida, q->id);
 fail_srcu:
        if (alloc_srcu)
                cleanup_srcu_struct(q->srcu);
@@ -504,12 +461,10 @@ fail_q:
  */
 bool blk_get_queue(struct request_queue *q)
 {
-       if (likely(!blk_queue_dying(q))) {
-               __blk_get_queue(q);
-               return true;
-       }
-
-       return false;
+       if (unlikely(blk_queue_dying(q)))
+               return false;
+       kobject_get(&q->kobj);
+       return true;
 }
 EXPORT_SYMBOL(blk_get_queue);
 
@@ -608,16 +563,15 @@ static int blk_partition_remap(struct bio *bio)
 static inline blk_status_t blk_check_zone_append(struct request_queue *q,
                                                 struct bio *bio)
 {
-       sector_t pos = bio->bi_iter.bi_sector;
        int nr_sectors = bio_sectors(bio);
 
        /* Only applicable to zoned block devices */
-       if (!blk_queue_is_zoned(q))
+       if (!bdev_is_zoned(bio->bi_bdev))
                return BLK_STS_NOTSUPP;
 
        /* The bio sector must point to the start of a sequential zone */
-       if (pos & (blk_queue_zone_sectors(q) - 1) ||
-           !blk_queue_zone_is_seq(q, pos))
+       if (bio->bi_iter.bi_sector & (bdev_zone_sectors(bio->bi_bdev) - 1) ||
+           !bio_zone_is_seq(bio))
                return BLK_STS_IOERR;
 
        /*
@@ -762,7 +716,7 @@ void submit_bio_noacct(struct bio *bio)
 
        might_sleep();
 
-       plug = blk_mq_plug(q, bio);
+       plug = blk_mq_plug(bio);
        if (plug && plug->nowait)
                bio->bi_opf |= REQ_NOWAIT;
 
@@ -818,11 +772,11 @@ void submit_bio_noacct(struct bio *bio)
        case REQ_OP_ZONE_OPEN:
        case REQ_OP_ZONE_CLOSE:
        case REQ_OP_ZONE_FINISH:
-               if (!blk_queue_is_zoned(q))
+               if (!bdev_is_zoned(bio->bi_bdev))
                        goto not_supported;
                break;
        case REQ_OP_ZONE_RESET_ALL:
-               if (!blk_queue_is_zoned(q) || !blk_queue_zone_resetall(q))
+               if (!bdev_is_zoned(bio->bi_bdev) || !blk_queue_zone_resetall(q))
                        goto not_supported;
                break;
        case REQ_OP_WRITE_ZEROES:
@@ -987,7 +941,7 @@ void update_io_ticks(struct block_device *part, unsigned long now, bool end)
 again:
        stamp = READ_ONCE(part->bd_stamp);
        if (unlikely(time_after(now, stamp))) {
-               if (likely(cmpxchg(&part->bd_stamp, stamp, now) == stamp))
+               if (likely(try_cmpxchg(&part->bd_stamp, &stamp, now)))
                        __part_stat_add(part, io_ticks, end ? now - stamp : 1);
        }
        if (part->bd_partno) {
@@ -997,7 +951,7 @@ again:
 }
 
 unsigned long bdev_start_io_acct(struct block_device *bdev,
-                                unsigned int sectors, unsigned int op,
+                                unsigned int sectors, enum req_op op,
                                 unsigned long start_time)
 {
        const int sgrp = op_stat_group(op);
@@ -1038,7 +992,7 @@ unsigned long bio_start_io_acct(struct bio *bio)
 }
 EXPORT_SYMBOL_GPL(bio_start_io_acct);
 
-void bdev_end_io_acct(struct block_device *bdev, unsigned int op,
+void bdev_end_io_acct(struct block_device *bdev, enum req_op op,
                      unsigned long start_time)
 {
        const int sgrp = op_stat_group(op);
@@ -1247,7 +1201,7 @@ EXPORT_SYMBOL_GPL(blk_io_schedule);
 
 int __init blk_dev_init(void)
 {
-       BUILD_BUG_ON(REQ_OP_LAST >= (1 << REQ_OP_BITS));
+       BUILD_BUG_ON((__force u32)REQ_OP_LAST >= (1 << REQ_OP_BITS));
        BUILD_BUG_ON(REQ_OP_BITS + REQ_FLAG_BITS > 8 *
                        sizeof_field(struct request, cmd_flags));
        BUILD_BUG_ON(REQ_OP_BITS + REQ_FLAG_BITS > 8 *
index c689687..d20a0c6 100644 (file)
@@ -94,7 +94,7 @@ enum {
 };
 
 static void blk_kick_flush(struct request_queue *q,
-                          struct blk_flush_queue *fq, unsigned int flags);
+                          struct blk_flush_queue *fq, blk_opf_t flags);
 
 static inline struct blk_flush_queue *
 blk_get_flush_queue(struct request_queue *q, struct blk_mq_ctx *ctx)
@@ -173,7 +173,7 @@ static void blk_flush_complete_seq(struct request *rq,
 {
        struct request_queue *q = rq->q;
        struct list_head *pending = &fq->flush_queue[fq->flush_pending_idx];
-       unsigned int cmd_flags;
+       blk_opf_t cmd_flags;
 
        BUG_ON(rq->flush.seq & seq);
        rq->flush.seq |= seq;
@@ -290,7 +290,7 @@ bool is_flush_rq(struct request *rq)
  *
  */
 static void blk_kick_flush(struct request_queue *q, struct blk_flush_queue *fq,
-                          unsigned int flags)
+                          blk_opf_t flags)
 {
        struct list_head *pending = &fq->flush_queue[fq->flush_pending_idx];
        struct request *first_rq =
index 47c89e6..2bd1d31 100644 (file)
@@ -102,31 +102,18 @@ static struct kobj_type blk_ia_ranges_ktype = {
  * disk_register_independent_access_ranges - register with sysfs a set of
  *             independent access ranges
  * @disk:      Target disk
- * @new_iars:  New set of independent access ranges
  *
  * Register with sysfs a set of independent access ranges for @disk.
- * If @new_iars is not NULL, this set of ranges is registered and the old set
- * specified by q->ia_ranges is unregistered. Otherwise, q->ia_ranges is
- * registered if it is not already.
  */
-int disk_register_independent_access_ranges(struct gendisk *disk,
-                               struct blk_independent_access_ranges *new_iars)
+int disk_register_independent_access_ranges(struct gendisk *disk)
 {
+       struct blk_independent_access_ranges *iars = disk->ia_ranges;
        struct request_queue *q = disk->queue;
-       struct blk_independent_access_ranges *iars;
        int i, ret;
 
        lockdep_assert_held(&q->sysfs_dir_lock);
        lockdep_assert_held(&q->sysfs_lock);
 
-       /* If a new range set is specified, unregister the old one */
-       if (new_iars) {
-               if (q->ia_ranges)
-                       disk_unregister_independent_access_ranges(disk);
-               q->ia_ranges = new_iars;
-       }
-
-       iars = q->ia_ranges;
        if (!iars)
                return 0;
 
@@ -138,7 +125,7 @@ int disk_register_independent_access_ranges(struct gendisk *disk,
        ret = kobject_init_and_add(&iars->kobj, &blk_ia_ranges_ktype,
                                   &q->kobj, "%s", "independent_access_ranges");
        if (ret) {
-               q->ia_ranges = NULL;
+               disk->ia_ranges = NULL;
                kobject_put(&iars->kobj);
                return ret;
        }
@@ -164,7 +151,7 @@ int disk_register_independent_access_ranges(struct gendisk *disk,
 void disk_unregister_independent_access_ranges(struct gendisk *disk)
 {
        struct request_queue *q = disk->queue;
-       struct blk_independent_access_ranges *iars = q->ia_ranges;
+       struct blk_independent_access_ranges *iars = disk->ia_ranges;
        int i;
 
        lockdep_assert_held(&q->sysfs_dir_lock);
@@ -182,7 +169,7 @@ void disk_unregister_independent_access_ranges(struct gendisk *disk)
                kfree(iars);
        }
 
-       q->ia_ranges = NULL;
+       disk->ia_ranges = NULL;
 }
 
 static struct blk_independent_access_range *
@@ -210,6 +197,9 @@ static bool disk_check_ia_ranges(struct gendisk *disk,
        sector_t sector = 0;
        int i;
 
+       if (WARN_ON_ONCE(!iars->nr_ia_ranges))
+               return false;
+
        /*
         * While sorting the ranges in increasing LBA order, check that the
         * ranges do not overlap, that there are no sector holes and that all
@@ -242,7 +232,7 @@ static bool disk_check_ia_ranges(struct gendisk *disk,
 static bool disk_ia_ranges_changed(struct gendisk *disk,
                                   struct blk_independent_access_ranges *new)
 {
-       struct blk_independent_access_ranges *old = disk->queue->ia_ranges;
+       struct blk_independent_access_ranges *old = disk->ia_ranges;
        int i;
 
        if (!old)
@@ -298,25 +288,15 @@ void disk_set_independent_access_ranges(struct gendisk *disk,
 {
        struct request_queue *q = disk->queue;
 
-       if (WARN_ON_ONCE(iars && !iars->nr_ia_ranges)) {
+       mutex_lock(&q->sysfs_dir_lock);
+       mutex_lock(&q->sysfs_lock);
+       if (iars && !disk_check_ia_ranges(disk, iars)) {
                kfree(iars);
                iars = NULL;
        }
-
-       mutex_lock(&q->sysfs_dir_lock);
-       mutex_lock(&q->sysfs_lock);
-
-       if (iars) {
-               if (!disk_check_ia_ranges(disk, iars)) {
-                       kfree(iars);
-                       iars = NULL;
-                       goto reg;
-               }
-
-               if (!disk_ia_ranges_changed(disk, iars)) {
-                       kfree(iars);
-                       goto unlock;
-               }
+       if (iars && !disk_ia_ranges_changed(disk, iars)) {
+               kfree(iars);
+               goto unlock;
        }
 
        /*
@@ -324,17 +304,12 @@ void disk_set_independent_access_ranges(struct gendisk *disk,
         * revalidation. If that is the case, we need to unregister the old
         * set of independent access ranges and register the new set. If the
         * queue is not registered, registration of the device request queue
-        * will register the independent access ranges, so only swap in the
-        * new set and free the old one.
+        * will register the independent access ranges.
         */
-reg:
-       if (blk_queue_registered(q)) {
-               disk_register_independent_access_ranges(disk, iars);
-       } else {
-               swap(q->ia_ranges, iars);
-               kfree(iars);
-       }
-
+       disk_unregister_independent_access_ranges(disk);
+       disk->ia_ranges = iars;
+       if (blk_queue_registered(q))
+               disk_register_independent_access_ranges(disk);
 unlock:
        mutex_unlock(&q->sysfs_lock);
        mutex_unlock(&q->sysfs_dir_lock);
index df9cfe4..63fc020 100644 (file)
@@ -247,6 +247,8 @@ static struct io_context *alloc_io_context(gfp_t gfp_flags, int node)
        INIT_HLIST_HEAD(&ioc->icq_list);
        INIT_WORK(&ioc->release_work, ioc_release_fn);
 #endif
+       ioc->ioprio = IOPRIO_DEFAULT;
+
        return ioc;
 }
 
index 33a11ba..7936e5f 100644 (file)
@@ -2769,7 +2769,7 @@ static void ioc_rqos_done(struct rq_qos *rqos, struct request *rq)
        if (!ioc->enabled || !rq->alloc_time_ns || !rq->start_time_ns)
                return;
 
-       switch (req_op(rq) & REQ_OP_MASK) {
+       switch (req_op(rq)) {
        case REQ_OP_READ:
                pidx = QOS_RLAT;
                rw = READ;
@@ -2886,15 +2886,21 @@ static int blk_iocost_init(struct request_queue *q)
         * called before policy activation completion, can't assume that the
         * target bio has an iocg associated and need to test for NULL iocg.
         */
-       rq_qos_add(q, rqos);
+       ret = rq_qos_add(q, rqos);
+       if (ret)
+               goto err_free_ioc;
+
        ret = blkcg_activate_policy(q, &blkcg_policy_iocost);
-       if (ret) {
-               rq_qos_del(q, rqos);
-               free_percpu(ioc->pcpu_stat);
-               kfree(ioc);
-               return ret;
-       }
+       if (ret)
+               goto err_del_qos;
        return 0;
+
+err_del_qos:
+       rq_qos_del(q, rqos);
+err_free_ioc:
+       free_percpu(ioc->pcpu_stat);
+       kfree(ioc);
+       return ret;
 }
 
 static struct blkcg_policy_data *ioc_cpd_alloc(gfp_t gfp)
index 9568bf8..e285152 100644 (file)
@@ -401,7 +401,6 @@ static void check_scale_change(struct iolatency_grp *iolat)
        unsigned int cur_cookie;
        unsigned int our_cookie = atomic_read(&iolat->scale_cookie);
        u64 scale_lat;
-       unsigned int old;
        int direction = 0;
 
        if (lat_to_blkg(iolat)->parent == NULL)
@@ -422,11 +421,10 @@ static void check_scale_change(struct iolatency_grp *iolat)
        else
                return;
 
-       old = atomic_cmpxchg(&iolat->scale_cookie, our_cookie, cur_cookie);
-
-       /* Somebody beat us to the punch, just bail. */
-       if (old != our_cookie)
+       if (!atomic_try_cmpxchg(&iolat->scale_cookie, &our_cookie, cur_cookie)) {
+               /* Somebody beat us to the punch, just bail. */
                return;
+       }
 
        if (direction < 0 && iolat->min_lat_nsec) {
                u64 samples_thresh;
@@ -633,8 +631,8 @@ static void blkcg_iolatency_done_bio(struct rq_qos *rqos, struct bio *bio)
                        window_start = atomic64_read(&iolat->window_start);
                        if (now > window_start &&
                            (now - window_start) >= iolat->cur_win_nsec) {
-                               if (atomic64_cmpxchg(&iolat->window_start,
-                                            window_start, now) == window_start)
+                               if (atomic64_try_cmpxchg(&iolat->window_start,
+                                                        &window_start, now))
                                        iolatency_check_latencies(iolat, now);
                        }
                }
@@ -773,19 +771,23 @@ int blk_iolatency_init(struct request_queue *q)
        rqos->ops = &blkcg_iolatency_ops;
        rqos->q = q;
 
-       rq_qos_add(q, rqos);
-
+       ret = rq_qos_add(q, rqos);
+       if (ret)
+               goto err_free;
        ret = blkcg_activate_policy(q, &blkcg_policy_iolatency);
-       if (ret) {
-               rq_qos_del(q, rqos);
-               kfree(blkiolat);
-               return ret;
-       }
+       if (ret)
+               goto err_qos_del;
 
        timer_setup(&blkiolat->timer, blkiolatency_timer_fn, 0);
        INIT_WORK(&blkiolat->enable_work, blkiolatency_enable_work_fn);
 
        return 0;
+
+err_qos_del:
+       rq_qos_del(q, rqos);
+err_free:
+       kfree(blkiolat);
+       return ret;
 }
 
 static void iolatency_set_min_lat_nsec(struct blkcg_gq *blkg, u64 val)
index 79e797f..c00060a 100644 (file)
@@ -62,7 +62,6 @@ struct ioprio_blkg {
 struct ioprio_blkcg {
        struct blkcg_policy_data cpd;
        enum prio_policy         prio_policy;
-       bool                     prio_set;
 };
 
 static inline struct ioprio_blkg *pd_to_ioprio(struct blkg_policy_data *pd)
@@ -113,7 +112,6 @@ static ssize_t ioprio_set_prio_policy(struct kernfs_open_file *of, char *buf,
        if (ret < 0)
                return ret;
        blkcg->prio_policy = ret;
-       blkcg->prio_set = true;
        return nbytes;
 }
 
@@ -183,26 +181,20 @@ static struct blkcg_policy ioprio_policy = {
        .pd_free_fn     = ioprio_free_pd,
 };
 
-struct blk_ioprio {
-       struct rq_qos rqos;
-};
-
-static void blkcg_ioprio_track(struct rq_qos *rqos, struct request *rq,
-                              struct bio *bio)
+void blkcg_set_ioprio(struct bio *bio)
 {
        struct ioprio_blkcg *blkcg = ioprio_blkcg_from_bio(bio);
        u16 prio;
 
-       if (!blkcg->prio_set)
+       if (!blkcg || blkcg->prio_policy == POLICY_NO_CHANGE)
                return;
 
        /*
         * Except for IOPRIO_CLASS_NONE, higher I/O priority numbers
         * correspond to a lower priority. Hence, the max_t() below selects
         * the lower priority of bi_ioprio and the cgroup I/O priority class.
-        * If the cgroup policy has been set to POLICY_NO_CHANGE == 0, the
-        * bio I/O priority is not modified. If the bio I/O priority equals
-        * IOPRIO_CLASS_NONE, the cgroup I/O priority is assigned to the bio.
+        * If the bio I/O priority equals IOPRIO_CLASS_NONE, the cgroup I/O
+        * priority is assigned to the bio.
         */
        prio = max_t(u16, bio->bi_ioprio,
                        IOPRIO_PRIO_VALUE(blkcg->prio_policy, 0));
@@ -210,49 +202,14 @@ static void blkcg_ioprio_track(struct rq_qos *rqos, struct request *rq,
                bio->bi_ioprio = prio;
 }
 
-static void blkcg_ioprio_exit(struct rq_qos *rqos)
+void blk_ioprio_exit(struct request_queue *q)
 {
-       struct blk_ioprio *blkioprio_blkg =
-               container_of(rqos, typeof(*blkioprio_blkg), rqos);
-
-       blkcg_deactivate_policy(rqos->q, &ioprio_policy);
-       kfree(blkioprio_blkg);
+       blkcg_deactivate_policy(q, &ioprio_policy);
 }
 
-static struct rq_qos_ops blkcg_ioprio_ops = {
-       .track  = blkcg_ioprio_track,
-       .exit   = blkcg_ioprio_exit,
-};
-
 int blk_ioprio_init(struct request_queue *q)
 {
-       struct blk_ioprio *blkioprio_blkg;
-       struct rq_qos *rqos;
-       int ret;
-
-       blkioprio_blkg = kzalloc(sizeof(*blkioprio_blkg), GFP_KERNEL);
-       if (!blkioprio_blkg)
-               return -ENOMEM;
-
-       ret = blkcg_activate_policy(q, &ioprio_policy);
-       if (ret) {
-               kfree(blkioprio_blkg);
-               return ret;
-       }
-
-       rqos = &blkioprio_blkg->rqos;
-       rqos->id = RQ_QOS_IOPRIO;
-       rqos->ops = &blkcg_ioprio_ops;
-       rqos->q = q;
-
-       /*
-        * Registering the rq-qos policy after activating the blk-cgroup
-        * policy guarantees that ioprio_blkcg_from_bio(bio) != NULL in the
-        * rq-qos callbacks.
-        */
-       rq_qos_add(q, rqos);
-
-       return 0;
+       return blkcg_activate_policy(q, &ioprio_policy);
 }
 
 static int __init ioprio_init(void)
index a7785c2..5a1eb55 100644 (file)
@@ -6,14 +6,23 @@
 #include <linux/kconfig.h>
 
 struct request_queue;
+struct bio;
 
 #ifdef CONFIG_BLK_CGROUP_IOPRIO
 int blk_ioprio_init(struct request_queue *q);
+void blk_ioprio_exit(struct request_queue *q);
+void blkcg_set_ioprio(struct bio *bio);
 #else
 static inline int blk_ioprio_init(struct request_queue *q)
 {
        return 0;
 }
+static inline void blk_ioprio_exit(struct request_queue *q)
+{
+}
+static inline void blkcg_set_ioprio(struct bio *bio)
+{
+}
 #endif
 
 #endif /* _BLK_IOPRIO_H_ */
index 09b7e12..67e6dbc 100644 (file)
@@ -48,10 +48,8 @@ int __blkdev_issue_discard(struct block_device *bdev, sector_t sector,
 
        /* In case the discard granularity isn't set by buggy device driver */
        if (WARN_ON_ONCE(!bdev_discard_granularity(bdev))) {
-               char dev_name[BDEVNAME_SIZE];
-
-               bdevname(bdev, dev_name);
-               pr_err_ratelimited("%s: Error: discard_granularity is 0.\n", dev_name);
+               pr_err_ratelimited("%pg: Error: discard_granularity is 0.\n",
+                                  bdev);
                return -EOPNOTSUPP;
        }
 
index 7771dac..4c8a699 100644 (file)
@@ -164,18 +164,21 @@ static struct bio *blk_bio_write_zeroes_split(struct request_queue *q,
 static inline unsigned get_max_io_size(struct request_queue *q,
                                       struct bio *bio)
 {
-       unsigned sectors = blk_max_size_offset(q, bio->bi_iter.bi_sector, 0);
-       unsigned max_sectors = sectors;
        unsigned pbs = queue_physical_block_size(q) >> SECTOR_SHIFT;
        unsigned lbs = queue_logical_block_size(q) >> SECTOR_SHIFT;
-       unsigned start_offset = bio->bi_iter.bi_sector & (pbs - 1);
+       unsigned max_sectors = queue_max_sectors(q), start, end;
 
-       max_sectors += start_offset;
-       max_sectors &= ~(pbs - 1);
-       if (max_sectors > start_offset)
-               return max_sectors - start_offset;
+       if (q->limits.chunk_sectors) {
+               max_sectors = min(max_sectors,
+                       blk_chunk_sectors_left(bio->bi_iter.bi_sector,
+                                              q->limits.chunk_sectors));
+       }
 
-       return sectors & ~(lbs - 1);
+       start = bio->bi_iter.bi_sector & (pbs - 1);
+       end = (start + max_sectors) & ~(pbs - 1);
+       if (end > start)
+               return end - start;
+       return max_sectors & ~(lbs - 1);
 }
 
 static inline unsigned get_max_segment_size(const struct request_queue *q,
@@ -201,11 +204,11 @@ static inline unsigned get_max_segment_size(const struct request_queue *q,
  * @nsegs:    [in,out] Number of segments in the bio being built. Incremented
  *            by the number of segments from @bv that may be appended to that
  *            bio without exceeding @max_segs
- * @sectors:  [in,out] Number of sectors in the bio being built. Incremented
- *            by the number of sectors from @bv that may be appended to that
- *            bio without exceeding @max_sectors
+ * @bytes:    [in,out] Number of bytes in the bio being built. Incremented
+ *            by the number of bytes from @bv that may be appended to that
+ *            bio without exceeding @max_bytes
  * @max_segs: [in] upper bound for *@nsegs
- * @max_sectors: [in] upper bound for *@sectors
+ * @max_bytes: [in] upper bound for *@bytes
  *
  * When splitting a bio, it can happen that a bvec is encountered that is too
  * big to fit in a single segment and hence that it has to be split in the
@@ -216,10 +219,10 @@ static inline unsigned get_max_segment_size(const struct request_queue *q,
  */
 static bool bvec_split_segs(const struct request_queue *q,
                            const struct bio_vec *bv, unsigned *nsegs,
-                           unsigned *sectors, unsigned max_segs,
-                           unsigned max_sectors)
+                           unsigned *bytes, unsigned max_segs,
+                           unsigned max_bytes)
 {
-       unsigned max_len = (min(max_sectors, UINT_MAX >> 9) - *sectors) << 9;
+       unsigned max_len = min(max_bytes, UINT_MAX) - *bytes;
        unsigned len = min(bv->bv_len, max_len);
        unsigned total_len = 0;
        unsigned seg_size = 0;
@@ -237,7 +240,7 @@ static bool bvec_split_segs(const struct request_queue *q,
                        break;
        }
 
-       *sectors += total_len >> 9;
+       *bytes += total_len;
 
        /* tell the caller to split the bvec if it is too big to fit */
        return len > 0 || bv->bv_len > max_len;
@@ -269,8 +272,8 @@ static struct bio *blk_bio_segment_split(struct request_queue *q,
 {
        struct bio_vec bv, bvprv, *bvprvp = NULL;
        struct bvec_iter iter;
-       unsigned nsegs = 0, sectors = 0;
-       const unsigned max_sectors = get_max_io_size(q, bio);
+       unsigned nsegs = 0, bytes = 0;
+       const unsigned max_bytes = get_max_io_size(q, bio) << 9;
        const unsigned max_segs = queue_max_segments(q);
 
        bio_for_each_bvec(bv, bio, iter) {
@@ -282,12 +285,12 @@ static struct bio *blk_bio_segment_split(struct request_queue *q,
                        goto split;
 
                if (nsegs < max_segs &&
-                   sectors + (bv.bv_len >> 9) <= max_sectors &&
+                   bytes + bv.bv_len <= max_bytes &&
                    bv.bv_offset + bv.bv_len <= PAGE_SIZE) {
                        nsegs++;
-                       sectors += bv.bv_len >> 9;
-               } else if (bvec_split_segs(q, &bv, &nsegs, &sectors, max_segs,
-                                        max_sectors)) {
+                       bytes += bv.bv_len;
+               } else if (bvec_split_segs(q, &bv, &nsegs, &bytes, max_segs,
+                                          max_bytes)) {
                        goto split;
                }
 
@@ -301,12 +304,19 @@ split:
        *segs = nsegs;
 
        /*
+        * Individual bvecs might not be logical block aligned. Round down the
+        * split size so that each bio is properly block size aligned, even if
+        * we do not use the full hardware limits.
+        */
+       bytes = ALIGN_DOWN(bytes, queue_logical_block_size(q));
+
+       /*
         * Bio splitting may cause subtle trouble such as hang when doing sync
         * iopoll in direct IO routine. Given performance gain of iopoll for
         * big IO can be trival, disable iopoll when split needed.
         */
        bio_clear_polled(bio);
-       return bio_split(bio, sectors, GFP_NOIO, bs);
+       return bio_split(bio, bytes >> SECTOR_SHIFT, GFP_NOIO, bs);
 }
 
 /**
@@ -345,6 +355,7 @@ void __blk_queue_split(struct request_queue *q, struct bio **bio,
                /* there isn't chance to merge the splitted bio */
                split->bi_opf |= REQ_NOMERGE;
 
+               blkcg_bio_issue_init(split);
                bio_chain(split, *bio);
                trace_block_split(split, (*bio)->bi_iter.bi_sector);
                submit_bio_noacct(*bio);
@@ -375,7 +386,7 @@ EXPORT_SYMBOL(blk_queue_split);
 unsigned int blk_recalc_rq_segments(struct request *rq)
 {
        unsigned int nr_phys_segs = 0;
-       unsigned int nr_sectors = 0;
+       unsigned int bytes = 0;
        struct req_iterator iter;
        struct bio_vec bv;
 
@@ -395,10 +406,12 @@ unsigned int blk_recalc_rq_segments(struct request *rq)
                return 1;
        case REQ_OP_WRITE_ZEROES:
                return 0;
+       default:
+               break;
        }
 
        rq_for_each_bvec(bv, rq, iter)
-               bvec_split_segs(rq->q, &bv, &nr_phys_segs, &nr_sectors,
+               bvec_split_segs(rq->q, &bv, &nr_phys_segs, &bytes,
                                UINT_MAX, UINT_MAX);
        return nr_phys_segs;
 }
@@ -559,17 +572,18 @@ static inline unsigned int blk_rq_get_max_sectors(struct request *rq,
                                                  sector_t offset)
 {
        struct request_queue *q = rq->q;
+       unsigned int max_sectors;
 
        if (blk_rq_is_passthrough(rq))
                return q->limits.max_hw_sectors;
 
+       max_sectors = blk_queue_get_max_sectors(q, req_op(rq));
        if (!q->limits.chunk_sectors ||
            req_op(rq) == REQ_OP_DISCARD ||
            req_op(rq) == REQ_OP_SECURE_ERASE)
-               return blk_queue_get_max_sectors(q, req_op(rq));
-
-       return min(blk_max_size_offset(q, offset, 0),
-                       blk_queue_get_max_sectors(q, req_op(rq)));
+               return max_sectors;
+       return min(max_sectors,
+                  blk_chunk_sectors_left(offset, q->limits.chunk_sectors));
 }
 
 static inline int ll_new_hw_segment(struct request *req, struct bio *bio,
@@ -699,7 +713,7 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req,
  */
 void blk_rq_set_mixed_merge(struct request *rq)
 {
-       unsigned int ff = rq->cmd_flags & REQ_FAILFAST_MASK;
+       blk_opf_t ff = rq->cmd_flags & REQ_FAILFAST_MASK;
        struct bio *bio;
 
        if (rq->rq_flags & RQF_MIXED_MERGE)
@@ -915,7 +929,7 @@ enum bio_merge_status {
 static enum bio_merge_status bio_attempt_back_merge(struct request *req,
                struct bio *bio, unsigned int nr_segs)
 {
-       const int ff = bio->bi_opf & REQ_FAILFAST_MASK;
+       const blk_opf_t ff = bio->bi_opf & REQ_FAILFAST_MASK;
 
        if (!ll_back_merge_fn(req, bio, nr_segs))
                return BIO_MERGE_FAILED;
@@ -939,7 +953,7 @@ static enum bio_merge_status bio_attempt_back_merge(struct request *req,
 static enum bio_merge_status bio_attempt_front_merge(struct request *req,
                struct bio *bio, unsigned int nr_segs)
 {
-       const int ff = bio->bi_opf & REQ_FAILFAST_MASK;
+       const blk_opf_t ff = bio->bi_opf & REQ_FAILFAST_MASK;
 
        if (!ll_front_merge_fn(req, bio, nr_segs))
                return BIO_MERGE_FAILED;
@@ -1040,7 +1054,7 @@ bool blk_attempt_plug_merge(struct request_queue *q, struct bio *bio,
        struct blk_plug *plug;
        struct request *rq;
 
-       plug = blk_mq_plug(q, bio);
+       plug = blk_mq_plug(bio);
        if (!plug || rq_list_empty(plug->mq_list))
                return false;
 
index 038cb62..a77b099 100644 (file)
@@ -11,11 +11,11 @@ int queue_zone_wlock_show(void *data, struct seq_file *m)
        struct request_queue *q = data;
        unsigned int i;
 
-       if (!q->seq_zones_wlock)
+       if (!q->disk->seq_zones_wlock)
                return 0;
 
-       for (i = 0; i < q->nr_zones; i++)
-               if (test_bit(i, q->seq_zones_wlock))
+       for (i = 0; i < q->disk->nr_zones; i++)
+               if (test_bit(i, q->disk->seq_zones_wlock))
                        seq_printf(m, "%u\n", i);
 
        return 0;
index 4d1ce9e..8559cea 100644 (file)
@@ -116,7 +116,6 @@ static const char *const blk_queue_flag_name[] = {
        QUEUE_FLAG_NAME(NOXMERGES),
        QUEUE_FLAG_NAME(ADD_RANDOM),
        QUEUE_FLAG_NAME(SAME_FORCE),
-       QUEUE_FLAG_NAME(DEAD),
        QUEUE_FLAG_NAME(INIT_DONE),
        QUEUE_FLAG_NAME(STABLE_WRITES),
        QUEUE_FLAG_NAME(POLL),
@@ -151,11 +150,10 @@ static ssize_t queue_state_write(void *data, const char __user *buf,
        char opbuf[16] = { }, *op;
 
        /*
-        * The "state" attribute is removed after blk_cleanup_queue() has called
-        * blk_mq_free_queue(). Return if QUEUE_FLAG_DEAD has been set to avoid
-        * triggering a use-after-free.
+        * The "state" attribute is removed when the queue is removed.  Don't
+        * allow setting the state on a dying queue to avoid a use-after-free.
         */
-       if (blk_queue_dead(q))
+       if (blk_queue_dying(q))
                return -ENOENT;
 
        if (count >= sizeof(opbuf)) {
@@ -306,7 +304,7 @@ static const char *blk_mq_rq_state_name(enum mq_rq_state rq_state)
 int __blk_mq_debugfs_rq_show(struct seq_file *m, struct request *rq)
 {
        const struct blk_mq_ops *const mq_ops = rq->q->mq_ops;
-       const unsigned int op = req_op(rq);
+       const enum req_op op = req_op(rq);
        const char *op_str = blk_op_str(op);
 
        seq_printf(m, "%p {.op=", rq);
@@ -315,8 +313,8 @@ int __blk_mq_debugfs_rq_show(struct seq_file *m, struct request *rq)
        else
                seq_printf(m, "%s", op_str);
        seq_puts(m, ", .cmd_flags=");
-       blk_flags_show(m, rq->cmd_flags & ~REQ_OP_MASK, cmd_flag_name,
-                      ARRAY_SIZE(cmd_flag_name));
+       blk_flags_show(m, (__force unsigned int)(rq->cmd_flags & ~REQ_OP_MASK),
+                      cmd_flag_name, ARRAY_SIZE(cmd_flag_name));
        seq_puts(m, ", .rq_flags=");
        blk_flags_show(m, (__force unsigned int)rq->rq_flags, rqf_name,
                       ARRAY_SIZE(rqf_name));
@@ -377,7 +375,7 @@ struct show_busy_params {
  * e.g. due to a concurrent blk_mq_finish_request() call. Returns true to
  * keep iterating requests.
  */
-static bool hctx_show_busy_rq(struct request *rq, void *data, bool reserved)
+static bool hctx_show_busy_rq(struct request *rq, void *data)
 {
        const struct show_busy_params *params = data;
 
@@ -730,6 +728,9 @@ void blk_mq_debugfs_register_hctx(struct request_queue *q,
        char name[20];
        int i;
 
+       if (!q->debugfs_dir)
+               return;
+
        snprintf(name, sizeof(name), "hctx%u", hctx->queue_num);
        hctx->debugfs_dir = debugfs_create_dir(name, q->debugfs_dir);
 
index c084269..93997d2 100644 (file)
@@ -203,23 +203,6 @@ static int blk_mq_register_hctx(struct blk_mq_hw_ctx *hctx)
        return ret;
 }
 
-void blk_mq_unregister_dev(struct device *dev, struct request_queue *q)
-{
-       struct blk_mq_hw_ctx *hctx;
-       unsigned long i;
-
-       lockdep_assert_held(&q->sysfs_dir_lock);
-
-       queue_for_each_hw_ctx(q, hctx, i)
-               blk_mq_unregister_hctx(hctx);
-
-       kobject_uevent(q->mq_kobj, KOBJ_REMOVE);
-       kobject_del(q->mq_kobj);
-       kobject_put(&dev->kobj);
-
-       q->mq_sysfs_init_done = false;
-}
-
 void blk_mq_hctx_kobj_init(struct blk_mq_hw_ctx *hctx)
 {
        kobject_init(&hctx->kobj, &blk_mq_hw_ktype);
@@ -252,16 +235,16 @@ void blk_mq_sysfs_init(struct request_queue *q)
        }
 }
 
-int __blk_mq_register_dev(struct device *dev, struct request_queue *q)
+int blk_mq_sysfs_register(struct gendisk *disk)
 {
+       struct request_queue *q = disk->queue;
        struct blk_mq_hw_ctx *hctx;
        unsigned long i, j;
        int ret;
 
-       WARN_ON_ONCE(!q->kobj.parent);
        lockdep_assert_held(&q->sysfs_dir_lock);
 
-       ret = kobject_add(q->mq_kobj, kobject_get(&dev->kobj), "%s", "mq");
+       ret = kobject_add(q->mq_kobj, &disk_to_dev(disk)->kobj, "mq");
        if (ret < 0)
                goto out;
 
@@ -286,11 +269,27 @@ unreg:
 
        kobject_uevent(q->mq_kobj, KOBJ_REMOVE);
        kobject_del(q->mq_kobj);
-       kobject_put(&dev->kobj);
        return ret;
 }
 
-void blk_mq_sysfs_unregister(struct request_queue *q)
+void blk_mq_sysfs_unregister(struct gendisk *disk)
+{
+       struct request_queue *q = disk->queue;
+       struct blk_mq_hw_ctx *hctx;
+       unsigned long i;
+
+       lockdep_assert_held(&q->sysfs_dir_lock);
+
+       queue_for_each_hw_ctx(q, hctx, i)
+               blk_mq_unregister_hctx(hctx);
+
+       kobject_uevent(q->mq_kobj, KOBJ_REMOVE);
+       kobject_del(q->mq_kobj);
+
+       q->mq_sysfs_init_done = false;
+}
+
+void blk_mq_sysfs_unregister_hctxs(struct request_queue *q)
 {
        struct blk_mq_hw_ctx *hctx;
        unsigned long i;
@@ -306,7 +305,7 @@ unlock:
        mutex_unlock(&q->sysfs_dir_lock);
 }
 
-int blk_mq_sysfs_register(struct request_queue *q)
+int blk_mq_sysfs_register_hctxs(struct request_queue *q)
 {
        struct blk_mq_hw_ctx *hctx;
        unsigned long i;
index 2dcd738..8e3b36d 100644 (file)
@@ -37,29 +37,25 @@ static void blk_mq_update_wake_batch(struct blk_mq_tags *tags,
  * to get tag when first time, the other shared-tag users could reserve
  * budget for it.
  */
-bool __blk_mq_tag_busy(struct blk_mq_hw_ctx *hctx)
+void __blk_mq_tag_busy(struct blk_mq_hw_ctx *hctx)
 {
        unsigned int users;
 
        if (blk_mq_is_shared_tags(hctx->flags)) {
                struct request_queue *q = hctx->queue;
 
-               if (test_bit(QUEUE_FLAG_HCTX_ACTIVE, &q->queue_flags) ||
-                   test_and_set_bit(QUEUE_FLAG_HCTX_ACTIVE, &q->queue_flags)) {
-                       return true;
-               }
+               if (test_bit(QUEUE_FLAG_HCTX_ACTIVE, &q->queue_flags))
+                       return;
+               set_bit(QUEUE_FLAG_HCTX_ACTIVE, &q->queue_flags);
        } else {
-               if (test_bit(BLK_MQ_S_TAG_ACTIVE, &hctx->state) ||
-                   test_and_set_bit(BLK_MQ_S_TAG_ACTIVE, &hctx->state)) {
-                       return true;
-               }
+               if (test_bit(BLK_MQ_S_TAG_ACTIVE, &hctx->state))
+                       return;
+               set_bit(BLK_MQ_S_TAG_ACTIVE, &hctx->state);
        }
 
        users = atomic_inc_return(&hctx->tags->active_queues);
 
        blk_mq_update_wake_batch(hctx->tags, users);
-
-       return true;
 }
 
 /*
@@ -266,7 +262,6 @@ static bool bt_iter(struct sbitmap *bitmap, unsigned int bitnr, void *data)
        struct blk_mq_hw_ctx *hctx = iter_data->hctx;
        struct request_queue *q = iter_data->q;
        struct blk_mq_tag_set *set = q->tag_set;
-       bool reserved = iter_data->reserved;
        struct blk_mq_tags *tags;
        struct request *rq;
        bool ret = true;
@@ -276,7 +271,7 @@ static bool bt_iter(struct sbitmap *bitmap, unsigned int bitnr, void *data)
        else
                tags = hctx->tags;
 
-       if (!reserved)
+       if (!iter_data->reserved)
                bitnr += tags->nr_reserved_tags;
        /*
         * We can hit rq == NULL here, because the tagging functions
@@ -287,7 +282,7 @@ static bool bt_iter(struct sbitmap *bitmap, unsigned int bitnr, void *data)
                return true;
 
        if (rq->q == q && (!hctx || rq->mq_hctx == hctx))
-               ret = iter_data->fn(rq, iter_data->data, reserved);
+               ret = iter_data->fn(rq, iter_data->data);
        blk_mq_put_rq_ref(rq);
        return ret;
 }
@@ -337,12 +332,11 @@ static bool bt_tags_iter(struct sbitmap *bitmap, unsigned int bitnr, void *data)
 {
        struct bt_tags_iter_data *iter_data = data;
        struct blk_mq_tags *tags = iter_data->tags;
-       bool reserved = iter_data->flags & BT_TAG_ITER_RESERVED;
        struct request *rq;
        bool ret = true;
        bool iter_static_rqs = !!(iter_data->flags & BT_TAG_ITER_STATIC_RQS);
 
-       if (!reserved)
+       if (!(iter_data->flags & BT_TAG_ITER_RESERVED))
                bitnr += tags->nr_reserved_tags;
 
        /*
@@ -358,7 +352,7 @@ static bool bt_tags_iter(struct sbitmap *bitmap, unsigned int bitnr, void *data)
 
        if (!(iter_data->flags & BT_TAG_ITER_STARTED) ||
            blk_mq_request_started(rq))
-               ret = iter_data->fn(rq, iter_data->data, reserved);
+               ret = iter_data->fn(rq, iter_data->data);
        if (!iter_static_rqs)
                blk_mq_put_rq_ref(rq);
        return ret;
@@ -448,8 +442,7 @@ void blk_mq_tagset_busy_iter(struct blk_mq_tag_set *tagset,
 }
 EXPORT_SYMBOL(blk_mq_tagset_busy_iter);
 
-static bool blk_mq_tagset_count_completed_rqs(struct request *rq,
-               void *data, bool reserved)
+static bool blk_mq_tagset_count_completed_rqs(struct request *rq, void *data)
 {
        unsigned *count = data;
 
index 5668e28..91ff37e 100644 (file)
@@ -47,15 +47,13 @@ enum {
        BLK_MQ_TAG_MAX          = BLK_MQ_NO_TAG - 1,
 };
 
-extern bool __blk_mq_tag_busy(struct blk_mq_hw_ctx *);
+extern void __blk_mq_tag_busy(struct blk_mq_hw_ctx *);
 extern void __blk_mq_tag_idle(struct blk_mq_hw_ctx *);
 
-static inline bool blk_mq_tag_busy(struct blk_mq_hw_ctx *hctx)
+static inline void blk_mq_tag_busy(struct blk_mq_hw_ctx *hctx)
 {
-       if (!(hctx->flags & BLK_MQ_F_TAG_QUEUE_SHARED))
-               return false;
-
-       return __blk_mq_tag_busy(hctx);
+       if (hctx->flags & BLK_MQ_F_TAG_QUEUE_SHARED)
+               __blk_mq_tag_busy(hctx);
 }
 
 static inline void blk_mq_tag_idle(struct blk_mq_hw_ctx *hctx)
index 93d9d60..70177ee 100644 (file)
@@ -42,6 +42,7 @@
 #include "blk-stat.h"
 #include "blk-mq-sched.h"
 #include "blk-rq-qos.h"
+#include "blk-ioprio.h"
 
 static DEFINE_PER_CPU(struct llist_head, blk_cpu_done);
 
@@ -128,8 +129,7 @@ struct mq_inflight {
        unsigned int inflight[2];
 };
 
-static bool blk_mq_check_inflight(struct request *rq, void *priv,
-                                 bool reserved)
+static bool blk_mq_check_inflight(struct request *rq, void *priv)
 {
        struct mq_inflight *mi = priv;
 
@@ -474,6 +474,9 @@ retry:
        if (!(data->rq_flags & RQF_ELV))
                blk_mq_tag_busy(data->hctx);
 
+       if (data->flags & BLK_MQ_REQ_RESERVED)
+               data->rq_flags |= RQF_RESV;
+
        /*
         * Try batched alloc if we want more than 1 tag.
         */
@@ -507,13 +510,13 @@ retry:
                                        alloc_time_ns);
 }
 
-struct request *blk_mq_alloc_request(struct request_queue *q, unsigned int op,
+struct request *blk_mq_alloc_request(struct request_queue *q, blk_opf_t opf,
                blk_mq_req_flags_t flags)
 {
        struct blk_mq_alloc_data data = {
                .q              = q,
                .flags          = flags,
-               .cmd_flags      = op,
+               .cmd_flags      = opf,
                .nr_tags        = 1,
        };
        struct request *rq;
@@ -537,12 +540,12 @@ out_queue_exit:
 EXPORT_SYMBOL(blk_mq_alloc_request);
 
 struct request *blk_mq_alloc_request_hctx(struct request_queue *q,
-       unsigned int op, blk_mq_req_flags_t flags, unsigned int hctx_idx)
+       blk_opf_t opf, blk_mq_req_flags_t flags, unsigned int hctx_idx)
 {
        struct blk_mq_alloc_data data = {
                .q              = q,
                .flags          = flags,
-               .cmd_flags      = op,
+               .cmd_flags      = opf,
                .nr_tags        = 1,
        };
        u64 alloc_time_ns = 0;
@@ -588,6 +591,9 @@ struct request *blk_mq_alloc_request_hctx(struct request_queue *q,
        else
                data.rq_flags |= RQF_ELV;
 
+       if (flags & BLK_MQ_REQ_RESERVED)
+               data.rq_flags |= RQF_RESV;
+
        ret = -EWOULDBLOCK;
        tag = blk_mq_get_tag(&data);
        if (tag == BLK_MQ_NO_TAG)
@@ -654,7 +660,7 @@ void blk_dump_rq_flags(struct request *rq, char *msg)
 {
        printk(KERN_INFO "%s: dev %s: flags=%llx\n", msg,
                rq->q->disk ? rq->q->disk->disk_name : "?",
-               (unsigned long long) rq->cmd_flags);
+               (__force unsigned long long) rq->cmd_flags);
 
        printk(KERN_INFO "  sector %llu, nr/cnr %u/%u\n",
               (unsigned long long)blk_rq_pos(rq),
@@ -707,8 +713,9 @@ static void blk_print_req_error(struct request *req, blk_status_t status)
                "phys_seg %u prio class %u\n",
                blk_status_to_str(status),
                req->q->disk ? req->q->disk->disk_name : "?",
-               blk_rq_pos(req), req_op(req), blk_op_str(req_op(req)),
-               req->cmd_flags & ~REQ_OP_MASK,
+               blk_rq_pos(req), (__force u32)req_op(req),
+               blk_op_str(req_op(req)),
+               (__force u32)(req->cmd_flags & ~REQ_OP_MASK),
                req->nr_phys_segments,
                IOPRIO_PRIO_CLASS(req->ioprio));
 }
@@ -1393,8 +1400,7 @@ void blk_mq_delay_kick_requeue_list(struct request_queue *q,
 }
 EXPORT_SYMBOL(blk_mq_delay_kick_requeue_list);
 
-static bool blk_mq_rq_inflight(struct request *rq, void *priv,
-                              bool reserved)
+static bool blk_mq_rq_inflight(struct request *rq, void *priv)
 {
        /*
         * If we find a request that isn't idle we know the queue is busy
@@ -1420,13 +1426,13 @@ bool blk_mq_queue_inflight(struct request_queue *q)
 }
 EXPORT_SYMBOL_GPL(blk_mq_queue_inflight);
 
-static void blk_mq_rq_timed_out(struct request *req, bool reserved)
+static void blk_mq_rq_timed_out(struct request *req)
 {
        req->rq_flags |= RQF_TIMED_OUT;
        if (req->q->mq_ops->timeout) {
                enum blk_eh_timer_return ret;
 
-               ret = req->q->mq_ops->timeout(req, reserved);
+               ret = req->q->mq_ops->timeout(req);
                if (ret == BLK_EH_DONE)
                        return;
                WARN_ON_ONCE(ret != BLK_EH_RESET_TIMER);
@@ -1463,7 +1469,7 @@ void blk_mq_put_rq_ref(struct request *rq)
                __blk_mq_free_request(rq);
 }
 
-static bool blk_mq_check_expired(struct request *rq, void *priv, bool reserved)
+static bool blk_mq_check_expired(struct request *rq, void *priv)
 {
        unsigned long *next = priv;
 
@@ -1475,7 +1481,7 @@ static bool blk_mq_check_expired(struct request *rq, void *priv, bool reserved)
         * from blk_mq_check_expired().
         */
        if (blk_mq_req_expired(rq, next))
-               blk_mq_rq_timed_out(rq, reserved);
+               blk_mq_rq_timed_out(rq);
        return true;
 }
 
@@ -2085,14 +2091,10 @@ static void __blk_mq_delay_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async,
                return;
 
        if (!async && !(hctx->flags & BLK_MQ_F_BLOCKING)) {
-               int cpu = get_cpu();
-               if (cpumask_test_cpu(cpu, hctx->cpumask)) {
+               if (cpumask_test_cpu(raw_smp_processor_id(), hctx->cpumask)) {
                        __blk_mq_run_hw_queue(hctx);
-                       put_cpu();
                        return;
                }
-
-               put_cpu();
        }
 
        kblockd_mod_delayed_work_on(blk_mq_hctx_next_cpu(hctx), &hctx->run_work,
@@ -2156,7 +2158,7 @@ static struct blk_mq_hw_ctx *blk_mq_get_sq_hctx(struct request_queue *q)
         * just causes lock contention inside the scheduler and pointless cache
         * bouncing.
         */
-       struct blk_mq_hw_ctx *hctx = blk_mq_map_queue(q, 0, ctx);
+       struct blk_mq_hw_ctx *hctx = ctx->hctxs[HCTX_TYPE_DEFAULT];
 
        if (!blk_mq_hctx_stopped(hctx))
                return hctx;
@@ -2783,6 +2785,14 @@ static inline struct request *blk_mq_get_cached_request(struct request_queue *q,
        return rq;
 }
 
+static void bio_set_ioprio(struct bio *bio)
+{
+       /* Nobody set ioprio so far? Initialize it based on task's nice value */
+       if (IOPRIO_PRIO_CLASS(bio->bi_ioprio) == IOPRIO_CLASS_NONE)
+               bio->bi_ioprio = get_current_ioprio();
+       blkcg_set_ioprio(bio);
+}
+
 /**
  * blk_mq_submit_bio - Create and send a request to block device.
  * @bio: Bio pointer.
@@ -2799,7 +2809,7 @@ static inline struct request *blk_mq_get_cached_request(struct request_queue *q,
 void blk_mq_submit_bio(struct bio *bio)
 {
        struct request_queue *q = bdev_get_queue(bio->bi_bdev);
-       struct blk_plug *plug = blk_mq_plug(q, bio);
+       struct blk_plug *plug = blk_mq_plug(bio);
        const int is_sync = op_is_sync(bio->bi_opf);
        struct request *rq;
        unsigned int nr_segs = 1;
@@ -2812,6 +2822,8 @@ void blk_mq_submit_bio(struct bio *bio)
        if (!bio_integrity_prep(bio))
                return;
 
+       bio_set_ioprio(bio);
+
        rq = blk_mq_get_cached_request(q, plug, &bio, nr_segs);
        if (!rq) {
                if (!bio)
@@ -3276,7 +3288,7 @@ struct rq_iter_data {
        bool has_rq;
 };
 
-static bool blk_mq_has_request(struct request *rq, void *data, bool reserved)
+static bool blk_mq_has_request(struct request *rq, void *data)
 {
        struct rq_iter_data *iter_data = data;
 
@@ -3895,7 +3907,7 @@ static struct request_queue *blk_mq_init_queue_data(struct blk_mq_tag_set *set,
        q->queuedata = queuedata;
        ret = blk_mq_init_allocated_queue(set, q);
        if (ret) {
-               blk_cleanup_queue(q);
+               blk_put_queue(q);
                return ERR_PTR(ret);
        }
        return q;
@@ -3907,6 +3919,35 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set)
 }
 EXPORT_SYMBOL(blk_mq_init_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() and drops
+ * the initial reference.  All future requests will failed with -ENODEV.
+ *
+ * Context: can sleep
+ */
+void blk_mq_destroy_queue(struct request_queue *q)
+{
+       WARN_ON_ONCE(!queue_is_mq(q));
+       WARN_ON_ONCE(blk_queue_registered(q));
+
+       might_sleep();
+
+       blk_queue_flag_set(QUEUE_FLAG_DYING, q);
+       blk_queue_start_drain(q);
+       blk_freeze_queue(q);
+
+       blk_sync_queue(q);
+       blk_mq_cancel_work_sync(q);
+       blk_mq_exit_queue(q);
+
+       /* @q is and will stay empty, shutdown and put */
+       blk_put_queue(q);
+}
+EXPORT_SYMBOL(blk_mq_destroy_queue);
+
 struct gendisk *__blk_mq_alloc_disk(struct blk_mq_tag_set *set, void *queuedata,
                struct lock_class_key *lkclass)
 {
@@ -3919,13 +3960,23 @@ struct gendisk *__blk_mq_alloc_disk(struct blk_mq_tag_set *set, void *queuedata,
 
        disk = __alloc_disk_node(q, set->numa_node, lkclass);
        if (!disk) {
-               blk_cleanup_queue(q);
+               blk_mq_destroy_queue(q);
                return ERR_PTR(-ENOMEM);
        }
+       set_bit(GD_OWNS_QUEUE, &disk->state);
        return disk;
 }
 EXPORT_SYMBOL(__blk_mq_alloc_disk);
 
+struct gendisk *blk_mq_alloc_disk_for_queue(struct request_queue *q,
+               struct lock_class_key *lkclass)
+{
+       if (!blk_get_queue(q))
+               return NULL;
+       return __alloc_disk_node(q, NUMA_NO_NODE, lkclass);
+}
+EXPORT_SYMBOL(blk_mq_alloc_disk_for_queue);
+
 static struct blk_mq_hw_ctx *blk_mq_alloc_and_init_hctx(
                struct blk_mq_tag_set *set, struct request_queue *q,
                int hctx_idx, int node)
@@ -4513,7 +4564,7 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set,
 
        list_for_each_entry(q, &set->tag_list, tag_set_list) {
                blk_mq_debugfs_unregister_hctxs(q);
-               blk_mq_sysfs_unregister(q);
+               blk_mq_sysfs_unregister_hctxs(q);
        }
 
        prev_nr_hw_queues = set->nr_hw_queues;
@@ -4544,7 +4595,7 @@ fallback:
 
 reregister:
        list_for_each_entry(q, &set->tag_list, tag_set_list) {
-               blk_mq_sysfs_register(q);
+               blk_mq_sysfs_register_hctxs(q);
                blk_mq_debugfs_register_hctxs(q);
        }
 
index 2615bd5..8ca453a 100644 (file)
@@ -86,16 +86,16 @@ static inline struct blk_mq_hw_ctx *blk_mq_map_queue_type(struct request_queue *
        return xa_load(&q->hctx_table, q->tag_set->map[type].mq_map[cpu]);
 }
 
-static inline enum hctx_type blk_mq_get_hctx_type(unsigned int flags)
+static inline enum hctx_type blk_mq_get_hctx_type(blk_opf_t opf)
 {
        enum hctx_type type = HCTX_TYPE_DEFAULT;
 
        /*
         * The caller ensure that if REQ_POLLED, poll must be enabled.
         */
-       if (flags & REQ_POLLED)
+       if (opf & REQ_POLLED)
                type = HCTX_TYPE_POLL;
-       else if ((flags & REQ_OP_MASK) == REQ_OP_READ)
+       else if ((opf & REQ_OP_MASK) == REQ_OP_READ)
                type = HCTX_TYPE_READ;
        return type;
 }
@@ -103,14 +103,14 @@ static inline enum hctx_type blk_mq_get_hctx_type(unsigned int flags)
 /*
  * blk_mq_map_queue() - map (cmd_flags,type) to hardware queue
  * @q: request queue
- * @flags: request command flags
+ * @opf: operation type (REQ_OP_*) and flags (e.g. REQ_POLLED).
  * @ctx: software queue cpu ctx
  */
 static inline struct blk_mq_hw_ctx *blk_mq_map_queue(struct request_queue *q,
-                                                    unsigned int flags,
+                                                    blk_opf_t opf,
                                                     struct blk_mq_ctx *ctx)
 {
-       return ctx->hctxs[blk_mq_get_hctx_type(flags)];
+       return ctx->hctxs[blk_mq_get_hctx_type(opf)];
 }
 
 /*
@@ -118,9 +118,10 @@ static inline struct blk_mq_hw_ctx *blk_mq_map_queue(struct request_queue *q,
  */
 extern void blk_mq_sysfs_init(struct request_queue *q);
 extern void blk_mq_sysfs_deinit(struct request_queue *q);
-extern int __blk_mq_register_dev(struct device *dev, struct request_queue *q);
-extern int blk_mq_sysfs_register(struct request_queue *q);
-extern void blk_mq_sysfs_unregister(struct request_queue *q);
+int blk_mq_sysfs_register(struct gendisk *disk);
+void blk_mq_sysfs_unregister(struct gendisk *disk);
+int blk_mq_sysfs_register_hctxs(struct request_queue *q);
+void blk_mq_sysfs_unregister_hctxs(struct request_queue *q);
 extern void blk_mq_hctx_kobj_init(struct blk_mq_hw_ctx *hctx);
 void blk_mq_free_plug_rqs(struct blk_plug *plug);
 void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule);
@@ -151,7 +152,7 @@ struct blk_mq_alloc_data {
        struct request_queue *q;
        blk_mq_req_flags_t flags;
        unsigned int shallow_depth;
-       unsigned int cmd_flags;
+       blk_opf_t cmd_flags;
        req_flags_t rq_flags;
 
        /* allocate multiple requests/tags in one go */
@@ -293,7 +294,6 @@ static inline void blk_mq_clear_mq_map(struct blk_mq_queue_map *qmap)
 
 /*
  * blk_mq_plug() - Get caller context plug
- * @q: request queue
  * @bio : the bio being submitted by the caller context
  *
  * Plugging, by design, may delay the insertion of BIOs into the elevator in
@@ -304,23 +304,22 @@ static inline void blk_mq_clear_mq_map(struct blk_mq_queue_map *qmap)
  * order. While this is not a problem with regular block devices, this ordering
  * change can cause write BIO failures with zoned block devices as these
  * require sequential write patterns to zones. Prevent this from happening by
- * ignoring the plug state of a BIO issuing context if the target request queue
- * is for a zoned block device and the BIO to plug is a write operation.
+ * ignoring the plug state of a BIO issuing context if it is for a zoned block
+ * device and the BIO to plug is a write operation.
  *
  * Return current->plug if the bio can be plugged and NULL otherwise
  */
-static inline struct blk_plug *blk_mq_plug(struct request_queue *q,
-                                          struct bio *bio)
+static inline struct blk_plug *blk_mq_plug( struct bio *bio)
 {
+       /* Zoned block device write operation case: do not plug the BIO */
+       if (bdev_is_zoned(bio->bi_bdev) && op_is_write(bio_op(bio)))
+               return NULL;
+
        /*
         * For regular block devices or read operations, use the context plug
         * which may be NULL if blk_start_plug() was not executed.
         */
-       if (!blk_queue_is_zoned(q) || !op_is_write(bio_op(bio)))
-               return current->plug;
-
-       /* Zoned block device write operation case: do not plug the BIO */
-       return NULL;
+       return current->plug;
 }
 
 /* Free all requests on the list */
index d3a7569..88f0fe7 100644 (file)
@@ -10,16 +10,10 @@ static bool atomic_inc_below(atomic_t *v, unsigned int below)
 {
        unsigned int cur = atomic_read(v);
 
-       for (;;) {
-               unsigned int old;
-
+       do {
                if (cur >= below)
                        return false;
-               old = atomic_cmpxchg(v, cur, cur + 1);
-               if (old == cur)
-                       break;
-               cur = old;
-       }
+       } while (!atomic_try_cmpxchg(v, &cur, cur + 1));
 
        return true;
 }
index 0e46052..08b8565 100644 (file)
@@ -86,7 +86,7 @@ static inline void rq_wait_init(struct rq_wait *rq_wait)
        init_waitqueue_head(&rq_wait->wait);
 }
 
-static inline void rq_qos_add(struct request_queue *q, struct rq_qos *rqos)
+static inline int rq_qos_add(struct request_queue *q, struct rq_qos *rqos)
 {
        /*
         * No IO can be in-flight when adding rqos, so freeze queue, which
@@ -98,6 +98,8 @@ static inline void rq_qos_add(struct request_queue *q, struct rq_qos *rqos)
        blk_mq_freeze_queue(q);
 
        spin_lock_irq(&q->queue_lock);
+       if (rq_qos_id(q, rqos->id))
+               goto ebusy;
        rqos->next = q->rq_qos;
        q->rq_qos = rqos;
        spin_unlock_irq(&q->queue_lock);
@@ -109,6 +111,13 @@ static inline void rq_qos_add(struct request_queue *q, struct rq_qos *rqos)
                blk_mq_debugfs_register_rqos(rqos);
                mutex_unlock(&q->debugfs_mutex);
        }
+
+       return 0;
+ebusy:
+       spin_unlock_irq(&q->queue_lock);
+       blk_mq_unfreeze_queue(q);
+       return -EBUSY;
+
 }
 
 static inline void rq_qos_del(struct request_queue *q, struct rq_qos *rqos)
index 6ccceb4..8bb9eef 100644 (file)
@@ -893,18 +893,19 @@ static bool disk_has_partitions(struct gendisk *disk)
 }
 
 /**
- * blk_queue_set_zoned - configure a disk queue zoned model.
+ * disk_set_zoned - configure the zoned model for a disk
  * @disk:      the gendisk of the queue to configure
  * @model:     the zoned model to set
  *
- * Set the zoned model of the request queue of @disk according to @model.
+ * Set the zoned model of @disk to @model.
+ *
  * When @model is BLK_ZONED_HM (host managed), this should be called only
  * if zoned block device support is enabled (CONFIG_BLK_DEV_ZONED option).
  * If @model specifies BLK_ZONED_HA (host aware), the effective model used
  * depends on CONFIG_BLK_DEV_ZONED settings and on the existence of partitions
  * on the disk.
  */
-void blk_queue_set_zoned(struct gendisk *disk, enum blk_zoned_model model)
+void disk_set_zoned(struct gendisk *disk, enum blk_zoned_model model)
 {
        struct request_queue *q = disk->queue;
 
@@ -945,10 +946,10 @@ void blk_queue_set_zoned(struct gendisk *disk, enum blk_zoned_model model)
                blk_queue_zone_write_granularity(q,
                                                queue_logical_block_size(q));
        } else {
-               blk_queue_clear_zone_settings(q);
+               disk_clear_zone_settings(disk);
        }
 }
-EXPORT_SYMBOL_GPL(blk_queue_set_zoned);
+EXPORT_SYMBOL_GPL(disk_set_zoned);
 
 int bdev_alignment_offset(struct block_device *bdev)
 {
index 9b905e9..c030302 100644 (file)
@@ -274,6 +274,11 @@ static ssize_t queue_virt_boundary_mask_show(struct request_queue *q, char *page
        return queue_var_show(q->limits.virt_boundary_mask, page);
 }
 
+static ssize_t queue_dma_alignment_show(struct request_queue *q, char *page)
+{
+       return queue_var_show(queue_dma_alignment(q), page);
+}
+
 #define QUEUE_SYSFS_BIT_FNS(name, flag, neg)                           \
 static ssize_t                                                         \
 queue_##name##_show(struct request_queue *q, char *page)               \
@@ -320,17 +325,17 @@ static ssize_t queue_zoned_show(struct request_queue *q, char *page)
 
 static ssize_t queue_nr_zones_show(struct request_queue *q, char *page)
 {
-       return queue_var_show(blk_queue_nr_zones(q), page);
+       return queue_var_show(disk_nr_zones(q->disk), page);
 }
 
 static ssize_t queue_max_open_zones_show(struct request_queue *q, char *page)
 {
-       return queue_var_show(queue_max_open_zones(q), page);
+       return queue_var_show(bdev_max_open_zones(q->disk->part0), page);
 }
 
 static ssize_t queue_max_active_zones_show(struct request_queue *q, char *page)
 {
-       return queue_var_show(queue_max_active_zones(q), page);
+       return queue_var_show(bdev_max_active_zones(q->disk->part0), page);
 }
 
 static ssize_t queue_nomerges_show(struct request_queue *q, char *page)
@@ -606,6 +611,7 @@ QUEUE_RO_ENTRY(queue_dax, "dax");
 QUEUE_RW_ENTRY(queue_io_timeout, "io_timeout");
 QUEUE_RW_ENTRY(queue_wb_lat, "wbt_lat_usec");
 QUEUE_RO_ENTRY(queue_virt_boundary_mask, "virt_boundary_mask");
+QUEUE_RO_ENTRY(queue_dma_alignment, "dma_alignment");
 
 #ifdef CONFIG_BLK_DEV_THROTTLING_LOW
 QUEUE_RW_ENTRY(blk_throtl_sample_time, "throttle_sample_time");
@@ -667,6 +673,7 @@ static struct attribute *queue_attrs[] = {
        &blk_throtl_sample_time_entry.attr,
 #endif
        &queue_virt_boundary_mask_entry.attr,
+       &queue_dma_alignment_entry.attr,
        NULL,
 };
 
@@ -748,11 +755,6 @@ static void blk_free_queue_rcu(struct rcu_head *rcu_head)
  * decremented with blk_put_queue(). Once the refcount reaches 0 this function
  * is called.
  *
- * For drivers that have a request_queue on a gendisk and added with
- * __device_add_disk() the refcount to request_queue will reach 0 with
- * the last put_disk() called by the driver. For drivers which don't use
- * __device_add_disk() this happens with blk_cleanup_queue().
- *
  * Drivers exist which depend on the release of the request_queue to be
  * synchronous, it should not be deferred.
  *
@@ -774,8 +776,6 @@ static void blk_release_queue(struct kobject *kobj)
        blk_free_queue_stats(q->stats);
        kfree(q->poll_stat);
 
-       blk_queue_free_zone_bitmaps(q);
-
        if (queue_is_mq(q))
                blk_mq_release(q);
 
@@ -784,7 +784,7 @@ static void blk_release_queue(struct kobject *kobj)
        if (blk_queue_has_srcu(q))
                cleanup_srcu_struct(q->srcu);
 
-       ida_simple_remove(&blk_queue_ida, q->id);
+       ida_free(&blk_queue_ida, q->id);
        call_rcu(&q->rcu_head, blk_free_queue_rcu);
 }
 
@@ -793,7 +793,13 @@ static const struct sysfs_ops queue_sysfs_ops = {
        .store  = queue_attr_store,
 };
 
+static const struct attribute_group *blk_queue_attr_groups[] = {
+       &queue_attr_group,
+       NULL
+};
+
 struct kobj_type blk_queue_ktype = {
+       .default_groups = blk_queue_attr_groups,
        .sysfs_ops      = &queue_sysfs_ops,
        .release        = blk_release_queue,
 };
@@ -804,32 +810,17 @@ struct kobj_type blk_queue_ktype = {
  */
 int blk_register_queue(struct gendisk *disk)
 {
-       int ret;
-       struct device *dev = disk_to_dev(disk);
        struct request_queue *q = disk->queue;
-
-       ret = blk_trace_init_sysfs(dev);
-       if (ret)
-               return ret;
+       int ret;
 
        mutex_lock(&q->sysfs_dir_lock);
 
-       ret = kobject_add(&q->kobj, kobject_get(&dev->kobj), "%s", "queue");
-       if (ret < 0) {
-               blk_trace_remove_sysfs(dev);
-               goto unlock;
-       }
-
-       ret = sysfs_create_group(&q->kobj, &queue_attr_group);
-       if (ret) {
-               blk_trace_remove_sysfs(dev);
-               kobject_del(&q->kobj);
-               kobject_put(&dev->kobj);
+       ret = kobject_add(&q->kobj, &disk_to_dev(disk)->kobj, "queue");
+       if (ret < 0)
                goto unlock;
-       }
 
        if (queue_is_mq(q))
-               __blk_mq_register_dev(dev, q);
+               blk_mq_sysfs_register(disk);
        mutex_lock(&q->sysfs_lock);
 
        mutex_lock(&q->debugfs_mutex);
@@ -839,7 +830,7 @@ int blk_register_queue(struct gendisk *disk)
                blk_mq_debugfs_register(q);
        mutex_unlock(&q->debugfs_mutex);
 
-       ret = disk_register_independent_access_ranges(disk, NULL);
+       ret = disk_register_independent_access_ranges(disk);
        if (ret)
                goto put_dev;
 
@@ -888,8 +879,6 @@ put_dev:
        mutex_unlock(&q->sysfs_lock);
        mutex_unlock(&q->sysfs_dir_lock);
        kobject_del(&q->kobj);
-       blk_trace_remove_sysfs(dev);
-       kobject_put(&dev->kobj);
 
        return ret;
 }
@@ -927,9 +916,8 @@ void blk_unregister_queue(struct gendisk *disk)
         * structures that can be modified through sysfs.
         */
        if (queue_is_mq(q))
-               blk_mq_unregister_dev(disk_to_dev(disk), q);
+               blk_mq_sysfs_unregister(disk);
        blk_crypto_sysfs_unregister(q);
-       blk_trace_remove_sysfs(disk_to_dev(disk));
 
        mutex_lock(&q->sysfs_lock);
        elv_unregister_queue(q);
@@ -948,6 +936,4 @@ void blk_unregister_queue(struct gendisk *disk)
        q->sched_debugfs_dir = NULL;
        q->rqos_debugfs_dir = NULL;
        mutex_unlock(&q->debugfs_mutex);
-
-       kobject_put(&disk_to_dev(disk)->kobj);
 }
index 139b2d7..9f5fe62 100644 (file)
@@ -2203,8 +2203,9 @@ out_unlock:
 
 #ifdef CONFIG_BLK_DEV_THROTTLING_LOW
 static void throtl_track_latency(struct throtl_data *td, sector_t size,
-       int op, unsigned long time)
+                                enum req_op op, unsigned long time)
 {
+       const bool rw = op_is_write(op);
        struct latency_bucket *latency;
        int index;
 
@@ -2215,10 +2216,10 @@ static void throtl_track_latency(struct throtl_data *td, sector_t size,
 
        index = request_bucket_index(size);
 
-       latency = get_cpu_ptr(td->latency_buckets[op]);
+       latency = get_cpu_ptr(td->latency_buckets[rw]);
        latency[index].total_latency += time;
        latency[index].samples++;
-       put_cpu_ptr(td->latency_buckets[op]);
+       put_cpu_ptr(td->latency_buckets[rw]);
 }
 
 void blk_throtl_stat_add(struct request *rq, u64 time_ns)
index 0c119be..a998200 100644 (file)
@@ -451,7 +451,7 @@ static bool close_io(struct rq_wb *rwb)
 
 #define REQ_HIPRIO     (REQ_SYNC | REQ_META | REQ_PRIO)
 
-static inline unsigned int get_limit(struct rq_wb *rwb, unsigned long rw)
+static inline unsigned int get_limit(struct rq_wb *rwb, blk_opf_t opf)
 {
        unsigned int limit;
 
@@ -462,7 +462,7 @@ static inline unsigned int get_limit(struct rq_wb *rwb, unsigned long rw)
        if (!rwb_enabled(rwb))
                return UINT_MAX;
 
-       if ((rw & REQ_OP_MASK) == REQ_OP_DISCARD)
+       if ((opf & REQ_OP_MASK) == REQ_OP_DISCARD)
                return rwb->wb_background;
 
        /*
@@ -473,9 +473,9 @@ static inline unsigned int get_limit(struct rq_wb *rwb, unsigned long rw)
         * the idle limit, or go to normal if we haven't had competing
         * IO for a bit.
         */
-       if ((rw & REQ_HIPRIO) || wb_recent_wait(rwb) || current_is_kswapd())
+       if ((opf & REQ_HIPRIO) || wb_recent_wait(rwb) || current_is_kswapd())
                limit = rwb->rq_depth.max_depth;
-       else if ((rw & REQ_BACKGROUND) || close_io(rwb)) {
+       else if ((opf & REQ_BACKGROUND) || close_io(rwb)) {
                /*
                 * If less than 100ms since we completed unrelated IO,
                 * limit us to half the depth for background writeback.
@@ -490,13 +490,13 @@ static inline unsigned int get_limit(struct rq_wb *rwb, unsigned long rw)
 struct wbt_wait_data {
        struct rq_wb *rwb;
        enum wbt_flags wb_acct;
-       unsigned long rw;
+       blk_opf_t opf;
 };
 
 static bool wbt_inflight_cb(struct rq_wait *rqw, void *private_data)
 {
        struct wbt_wait_data *data = private_data;
-       return rq_wait_inc_below(rqw, get_limit(data->rwb, data->rw));
+       return rq_wait_inc_below(rqw, get_limit(data->rwb, data->opf));
 }
 
 static void wbt_cleanup_cb(struct rq_wait *rqw, void *private_data)
@@ -510,13 +510,13 @@ static void wbt_cleanup_cb(struct rq_wait *rqw, void *private_data)
  * the timer to kick off queuing again.
  */
 static void __wbt_wait(struct rq_wb *rwb, enum wbt_flags wb_acct,
-                      unsigned long rw)
+                      blk_opf_t opf)
 {
        struct rq_wait *rqw = get_rq_wait(rwb, wb_acct);
        struct wbt_wait_data data = {
                .rwb = rwb,
                .wb_acct = wb_acct,
-               .rw = rw,
+               .opf = opf,
        };
 
        rq_qos_wait(rqw, &data, wbt_inflight_cb, wbt_cleanup_cb);
@@ -670,7 +670,7 @@ u64 wbt_default_latency_nsec(struct request_queue *q)
 
 static int wbt_data_dir(const struct request *rq)
 {
-       const int op = req_op(rq);
+       const enum req_op op = req_op(rq);
 
        if (op == REQ_OP_READ)
                return READ;
@@ -820,6 +820,7 @@ int wbt_init(struct request_queue *q)
 {
        struct rq_wb *rwb;
        int i;
+       int ret;
 
        rwb = kzalloc(sizeof(*rwb), GFP_KERNEL);
        if (!rwb)
@@ -846,7 +847,10 @@ int wbt_init(struct request_queue *q)
        /*
         * Assign rwb and add the stats callback.
         */
-       rq_qos_add(q, &rwb->rqos);
+       ret = rq_qos_add(q, &rwb->rqos);
+       if (ret)
+               goto err_free;
+
        blk_stat_add_callback(q, rwb->cb);
 
        rwb->min_lat_nsec = wbt_default_latency_nsec(q);
@@ -855,4 +859,10 @@ int wbt_init(struct request_queue *q)
        wbt_set_write_cache(q, test_bit(QUEUE_FLAG_WC, &q->queue_flags));
 
        return 0;
+
+err_free:
+       blk_stat_free_callback(rwb->cb);
+       kfree(rwb);
+       return ret;
+
 }
index 38cd840..a264621 100644 (file)
@@ -57,10 +57,10 @@ EXPORT_SYMBOL_GPL(blk_zone_cond_str);
  */
 bool blk_req_needs_zone_write_lock(struct request *rq)
 {
-       if (!rq->q->seq_zones_wlock)
+       if (blk_rq_is_passthrough(rq))
                return false;
 
-       if (blk_rq_is_passthrough(rq))
+       if (!rq->q->disk->seq_zones_wlock)
                return false;
 
        switch (req_op(rq)) {
@@ -77,7 +77,7 @@ bool blk_req_zone_write_trylock(struct request *rq)
 {
        unsigned int zno = blk_rq_zone_no(rq);
 
-       if (test_and_set_bit(zno, rq->q->seq_zones_wlock))
+       if (test_and_set_bit(zno, rq->q->disk->seq_zones_wlock))
                return false;
 
        WARN_ON_ONCE(rq->rq_flags & RQF_ZONE_WRITE_LOCKED);
@@ -90,7 +90,7 @@ EXPORT_SYMBOL_GPL(blk_req_zone_write_trylock);
 void __blk_req_zone_write_lock(struct request *rq)
 {
        if (WARN_ON_ONCE(test_and_set_bit(blk_rq_zone_no(rq),
-                                         rq->q->seq_zones_wlock)))
+                                         rq->q->disk->seq_zones_wlock)))
                return;
 
        WARN_ON_ONCE(rq->rq_flags & RQF_ZONE_WRITE_LOCKED);
@@ -101,28 +101,29 @@ EXPORT_SYMBOL_GPL(__blk_req_zone_write_lock);
 void __blk_req_zone_write_unlock(struct request *rq)
 {
        rq->rq_flags &= ~RQF_ZONE_WRITE_LOCKED;
-       if (rq->q->seq_zones_wlock)
+       if (rq->q->disk->seq_zones_wlock)
                WARN_ON_ONCE(!test_and_clear_bit(blk_rq_zone_no(rq),
-                                                rq->q->seq_zones_wlock));
+                                                rq->q->disk->seq_zones_wlock));
 }
 EXPORT_SYMBOL_GPL(__blk_req_zone_write_unlock);
 
 /**
- * blkdev_nr_zones - Get number of zones
- * @disk:      Target gendisk
+ * bdev_nr_zones - Get number of zones
+ * @bdev:      Target device
  *
  * Return the total number of zones of a zoned block device.  For a block
  * device without zone capabilities, the number of zones is always 0.
  */
-unsigned int blkdev_nr_zones(struct gendisk *disk)
+unsigned int bdev_nr_zones(struct block_device *bdev)
 {
-       sector_t zone_sectors = blk_queue_zone_sectors(disk->queue);
+       sector_t zone_sectors = bdev_zone_sectors(bdev);
 
-       if (!blk_queue_is_zoned(disk->queue))
+       if (!bdev_is_zoned(bdev))
                return 0;
-       return (get_capacity(disk) + zone_sectors - 1) >> ilog2(zone_sectors);
+       return (bdev_nr_sectors(bdev) + zone_sectors - 1) >>
+               ilog2(zone_sectors);
 }
-EXPORT_SYMBOL_GPL(blkdev_nr_zones);
+EXPORT_SYMBOL_GPL(bdev_nr_zones);
 
 /**
  * blkdev_report_zones - Get zones information
@@ -149,8 +150,7 @@ int blkdev_report_zones(struct block_device *bdev, sector_t sector,
        struct gendisk *disk = bdev->bd_disk;
        sector_t capacity = get_capacity(disk);
 
-       if (!blk_queue_is_zoned(bdev_get_queue(bdev)) ||
-           WARN_ON_ONCE(!disk->fops->report_zones))
+       if (!bdev_is_zoned(bdev) || WARN_ON_ONCE(!disk->fops->report_zones))
                return -EOPNOTSUPP;
 
        if (!nr_zones || sector >= capacity)
@@ -189,27 +189,26 @@ 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)
 {
-       struct request_queue *q = bdev_get_queue(bdev);
-       sector_t capacity = get_capacity(bdev->bd_disk);
-       sector_t zone_sectors = blk_queue_zone_sectors(q);
+       struct gendisk *disk = bdev->bd_disk;
+       sector_t capacity = bdev_nr_sectors(bdev);
+       sector_t zone_sectors = bdev_zone_sectors(bdev);
        unsigned long *need_reset;
        struct bio *bio = NULL;
        sector_t sector = 0;
        int ret;
 
-       need_reset = blk_alloc_zone_bitmap(q->node, q->nr_zones);
+       need_reset = blk_alloc_zone_bitmap(disk->queue->node, disk->nr_zones);
        if (!need_reset)
                return -ENOMEM;
 
-       ret = bdev->bd_disk->fops->report_zones(bdev->bd_disk, 0,
-                               q->nr_zones, blk_zone_need_reset_cb,
-                               need_reset);
+       ret = disk->fops->report_zones(disk, 0, disk->nr_zones,
+                                      blk_zone_need_reset_cb, need_reset);
        if (ret < 0)
                goto out_free_need_reset;
 
        ret = 0;
        while (sector < capacity) {
-               if (!test_bit(blk_queue_zone_no(q, sector), need_reset)) {
+               if (!test_bit(disk_zone_no(disk, sector), need_reset)) {
                        sector += zone_sectors;
                        continue;
                }
@@ -257,18 +256,17 @@ static int blkdev_zone_reset_all(struct block_device *bdev, gfp_t gfp_mask)
  *    The operation to execute on each zone can be a zone reset, open, close
  *    or finish request.
  */
-int blkdev_zone_mgmt(struct block_device *bdev, enum req_opf op,
-                    sector_t sector, sector_t nr_sectors,
-                    gfp_t gfp_mask)
+int blkdev_zone_mgmt(struct block_device *bdev, enum req_op op,
+                    sector_t sector, sector_t nr_sectors, gfp_t gfp_mask)
 {
        struct request_queue *q = bdev_get_queue(bdev);
-       sector_t zone_sectors = blk_queue_zone_sectors(q);
-       sector_t capacity = get_capacity(bdev->bd_disk);
+       sector_t zone_sectors = bdev_zone_sectors(bdev);
+       sector_t capacity = bdev_nr_sectors(bdev);
        sector_t end_sector = sector + nr_sectors;
        struct bio *bio = NULL;
        int ret = 0;
 
-       if (!blk_queue_is_zoned(q))
+       if (!bdev_is_zoned(bdev))
                return -EOPNOTSUPP;
 
        if (bdev_read_only(bdev))
@@ -350,7 +348,7 @@ int blkdev_report_zones_ioctl(struct block_device *bdev, fmode_t mode,
        if (!q)
                return -ENXIO;
 
-       if (!blk_queue_is_zoned(q))
+       if (!bdev_is_zoned(bdev))
                return -ENOTTY;
 
        if (copy_from_user(&rep, argp, sizeof(struct blk_zone_report)))
@@ -398,7 +396,7 @@ int blkdev_zone_mgmt_ioctl(struct block_device *bdev, fmode_t mode,
        void __user *argp = (void __user *)arg;
        struct request_queue *q;
        struct blk_zone_range zrange;
-       enum req_opf op;
+       enum req_op op;
        int ret;
 
        if (!argp)
@@ -408,7 +406,7 @@ int blkdev_zone_mgmt_ioctl(struct block_device *bdev, fmode_t mode,
        if (!q)
                return -ENXIO;
 
-       if (!blk_queue_is_zoned(q))
+       if (!bdev_is_zoned(bdev))
                return -ENOTTY;
 
        if (!(mode & FMODE_WRITE))
@@ -450,12 +448,12 @@ fail:
        return ret;
 }
 
-void blk_queue_free_zone_bitmaps(struct request_queue *q)
+void disk_free_zone_bitmaps(struct gendisk *disk)
 {
-       kfree(q->conv_zones_bitmap);
-       q->conv_zones_bitmap = NULL;
-       kfree(q->seq_zones_wlock);
-       q->seq_zones_wlock = NULL;
+       kfree(disk->conv_zones_bitmap);
+       disk->conv_zones_bitmap = NULL;
+       kfree(disk->seq_zones_wlock);
+       disk->seq_zones_wlock = NULL;
 }
 
 struct blk_revalidate_zone_args {
@@ -605,15 +603,15 @@ int blk_revalidate_disk_zones(struct gendisk *disk,
        blk_mq_freeze_queue(q);
        if (ret > 0) {
                blk_queue_chunk_sectors(q, args.zone_sectors);
-               q->nr_zones = args.nr_zones;
-               swap(q->seq_zones_wlock, args.seq_zones_wlock);
-               swap(q->conv_zones_bitmap, args.conv_zones_bitmap);
+               disk->nr_zones = args.nr_zones;
+               swap(disk->seq_zones_wlock, args.seq_zones_wlock);
+               swap(disk->conv_zones_bitmap, args.conv_zones_bitmap);
                if (update_driver_data)
                        update_driver_data(disk);
                ret = 0;
        } else {
                pr_warn("%s: failed to revalidate zones\n", disk->disk_name);
-               blk_queue_free_zone_bitmaps(q);
+               disk_free_zone_bitmaps(disk);
        }
        blk_mq_unfreeze_queue(q);
 
@@ -623,16 +621,18 @@ int blk_revalidate_disk_zones(struct gendisk *disk,
 }
 EXPORT_SYMBOL_GPL(blk_revalidate_disk_zones);
 
-void blk_queue_clear_zone_settings(struct request_queue *q)
+void disk_clear_zone_settings(struct gendisk *disk)
 {
+       struct request_queue *q = disk->queue;
+
        blk_mq_freeze_queue(q);
 
-       blk_queue_free_zone_bitmaps(q);
+       disk_free_zone_bitmaps(disk);
        blk_queue_flag_clear(QUEUE_FLAG_ZONE_RESETALL, q);
        q->required_elevator_features &= ~ELEVATOR_F_ZBD_SEQ_WRITE;
-       q->nr_zones = 0;
-       q->max_open_zones = 0;
-       q->max_active_zones = 0;
+       disk->nr_zones = 0;
+       disk->max_open_zones = 0;
+       disk->max_active_zones = 0;
        q->limits.chunk_sectors = 0;
        q->limits.zone_write_granularity = 0;
        q->limits.max_zone_append_sectors = 0;
index 4340177..1d83b1d 100644 (file)
@@ -31,11 +31,6 @@ extern struct kmem_cache *blk_requestq_srcu_cachep;
 extern struct kobj_type blk_queue_ktype;
 extern struct ida blk_queue_ida;
 
-static inline void __blk_get_queue(struct request_queue *q)
-{
-       kobject_get(&q->kobj);
-}
-
 bool is_flush_rq(struct request *req);
 
 struct blk_flush_queue *blk_alloc_flush_queue(int node, int cmd_size,
@@ -159,6 +154,19 @@ static inline bool blk_discard_mergable(struct request *req)
        return false;
 }
 
+static inline unsigned int blk_queue_get_max_sectors(struct request_queue *q,
+                                                    enum req_op op)
+{
+       if (unlikely(op == REQ_OP_DISCARD || op == REQ_OP_SECURE_ERASE))
+               return min(q->limits.max_discard_sectors,
+                          UINT_MAX >> SECTOR_SHIFT);
+
+       if (unlikely(op == REQ_OP_WRITE_ZEROES))
+               return q->limits.max_write_zeroes_sectors;
+
+       return q->limits.max_sectors;
+}
+
 #ifdef CONFIG_BLK_DEV_INTEGRITY
 void blk_flush_integrity(void);
 bool __bio_integrity_endio(struct bio *);
@@ -392,11 +400,11 @@ static inline int blk_iolatency_init(struct request_queue *q) { return 0; }
 #endif
 
 #ifdef CONFIG_BLK_DEV_ZONED
-void blk_queue_free_zone_bitmaps(struct request_queue *q);
-void blk_queue_clear_zone_settings(struct request_queue *q);
+void disk_free_zone_bitmaps(struct gendisk *disk);
+void disk_clear_zone_settings(struct gendisk *disk);
 #else
-static inline void blk_queue_free_zone_bitmaps(struct request_queue *q) {}
-static inline void blk_queue_clear_zone_settings(struct request_queue *q) {}
+static inline void disk_free_zone_bitmaps(struct gendisk *disk) {}
+static inline void disk_clear_zone_settings(struct gendisk *disk) {}
 #endif
 
 int blk_alloc_ext_minor(void);
@@ -411,6 +419,9 @@ int bdev_resize_partition(struct gendisk *disk, int partno, sector_t start,
                sector_t length);
 void blk_drop_partitions(struct gendisk *disk);
 
+struct gendisk *__alloc_disk_node(struct request_queue *q, int node_id,
+               struct lock_class_key *lkclass);
+
 int bio_add_hw_page(struct request_queue *q, struct bio *bio,
                struct page *page, unsigned int len, unsigned int offset,
                unsigned int max_sectors, bool *same_page);
@@ -436,13 +447,14 @@ extern struct device_attribute dev_attr_events;
 extern struct device_attribute dev_attr_events_async;
 extern struct device_attribute dev_attr_events_poll_msecs;
 
+extern struct attribute_group blk_trace_attr_group;
+
 long blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg);
 long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg);
 
 extern const struct address_space_operations def_blk_aops;
 
-int disk_register_independent_access_ranges(struct gendisk *disk,
-                               struct blk_independent_access_ranges *new_iars);
+int disk_register_independent_access_ranges(struct gendisk *disk);
 void disk_unregister_independent_access_ranges(struct gendisk *disk);
 
 #ifdef CONFIG_FAIL_MAKE_REQUEST
index 8f7b6fe..c8f487a 100644 (file)
@@ -205,19 +205,26 @@ void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig)
        int rw = bio_data_dir(*bio_orig);
        struct bio_vec *to, from;
        struct bvec_iter iter;
-       unsigned i = 0;
+       unsigned i = 0, bytes = 0;
        bool bounce = false;
-       int sectors = 0;
+       int sectors;
 
        bio_for_each_segment(from, *bio_orig, iter) {
                if (i++ < BIO_MAX_VECS)
-                       sectors += from.bv_len >> 9;
+                       bytes += from.bv_len;
                if (PageHighMem(from.bv_page))
                        bounce = true;
        }
        if (!bounce)
                return;
 
+       /*
+        * Individual bvecs might not be logical block aligned. Round down
+        * the split size so that each bio is properly block size aligned,
+        * even if we do not use the full hardware limits.
+        */
+       sectors = ALIGN_DOWN(bytes, queue_logical_block_size(q)) >>
+                       SECTOR_SHIFT;
        if (sectors < bio_sectors(*bio_orig)) {
                bio = bio_split(*bio_orig, sectors, GFP_NOIO, &bounce_bio_split);
                bio_chain(bio, *bio_orig);
index acfe135..d6f5dcd 100644 (file)
@@ -324,14 +324,14 @@ void bsg_remove_queue(struct request_queue *q)
                        container_of(q->tag_set, struct bsg_set, tag_set);
 
                bsg_unregister_queue(bset->bd);
-               blk_cleanup_queue(q);
+               blk_mq_destroy_queue(q);
                blk_mq_free_tag_set(&bset->tag_set);
                kfree(bset);
        }
 }
 EXPORT_SYMBOL_GPL(bsg_remove_queue);
 
-static enum blk_eh_timer_return bsg_timeout(struct request *rq, bool reserved)
+static enum blk_eh_timer_return bsg_timeout(struct request *rq)
 {
        struct bsg_set *bset =
                container_of(rq->q->tag_set, struct bsg_set, tag_set);
@@ -399,7 +399,7 @@ struct request_queue *bsg_setup_queue(struct device *dev, const char *name,
 
        return q;
 out_cleanup_queue:
-       blk_cleanup_queue(q);
+       blk_mq_destroy_queue(q);
 out_queue:
        blk_mq_free_tag_set(set);
 out_tag_set:
index 16cd8bd..3f0593b 100644 (file)
@@ -34,7 +34,7 @@ struct elevator_mq_ops {
        int (*request_merge)(struct request_queue *q, struct request **, struct bio *);
        void (*request_merged)(struct request_queue *, struct request *, enum elv_merge);
        void (*requests_merged)(struct request_queue *, struct request *, struct request *);
-       void (*limit_depth)(unsigned int, struct blk_mq_alloc_data *);
+       void (*limit_depth)(blk_opf_t, struct blk_mq_alloc_data *);
        void (*prepare_request)(struct request *);
        void (*finish_request)(struct request *);
        void (*insert_requests)(struct blk_mq_hw_ctx *, struct list_head *, bool);
index 743fc46..92ee820 100644 (file)
@@ -32,14 +32,21 @@ static int blkdev_get_block(struct inode *inode, sector_t iblock,
        return 0;
 }
 
-static unsigned int dio_bio_write_op(struct kiocb *iocb)
+static blk_opf_t dio_bio_write_op(struct kiocb *iocb)
 {
-       unsigned int op = REQ_OP_WRITE | REQ_SYNC | REQ_IDLE;
+       blk_opf_t opf = REQ_OP_WRITE | REQ_SYNC | REQ_IDLE;
 
        /* avoid the need for a I/O completion work item */
        if (iocb->ki_flags & IOCB_DSYNC)
-               op |= REQ_FUA;
-       return op;
+               opf |= REQ_FUA;
+       return opf;
+}
+
+static bool blkdev_dio_unaligned(struct block_device *bdev, loff_t pos,
+                             struct iov_iter *iter)
+{
+       return pos & (bdev_logical_block_size(bdev) - 1) ||
+               !bdev_iter_is_aligned(bdev, iter);
 }
 
 #define DIO_INLINE_BIO_VECS 4
@@ -54,8 +61,7 @@ static ssize_t __blkdev_direct_IO_simple(struct kiocb *iocb,
        struct bio bio;
        ssize_t ret;
 
-       if ((pos | iov_iter_alignment(iter)) &
-           (bdev_logical_block_size(bdev) - 1))
+       if (blkdev_dio_unaligned(bdev, pos, iter))
                return -EINVAL;
 
        if (nr_pages <= DIO_INLINE_BIO_VECS)
@@ -169,12 +175,11 @@ static ssize_t __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
        struct blkdev_dio *dio;
        struct bio *bio;
        bool is_read = (iov_iter_rw(iter) == READ), is_sync;
-       unsigned int opf = is_read ? REQ_OP_READ : dio_bio_write_op(iocb);
+       blk_opf_t opf = is_read ? REQ_OP_READ : dio_bio_write_op(iocb);
        loff_t pos = iocb->ki_pos;
        int ret = 0;
 
-       if ((pos | iov_iter_alignment(iter)) &
-           (bdev_logical_block_size(bdev) - 1))
+       if (blkdev_dio_unaligned(bdev, pos, iter))
                return -EINVAL;
 
        if (iocb->ki_flags & IOCB_ALLOC_CACHE)
@@ -292,14 +297,13 @@ static ssize_t __blkdev_direct_IO_async(struct kiocb *iocb,
 {
        struct block_device *bdev = iocb->ki_filp->private_data;
        bool is_read = iov_iter_rw(iter) == READ;
-       unsigned int opf = is_read ? REQ_OP_READ : dio_bio_write_op(iocb);
+       blk_opf_t opf = is_read ? REQ_OP_READ : dio_bio_write_op(iocb);
        struct blkdev_dio *dio;
        struct bio *bio;
        loff_t pos = iocb->ki_pos;
        int ret = 0;
 
-       if ((pos | iov_iter_alignment(iter)) &
-           (bdev_logical_block_size(bdev) - 1))
+       if (blkdev_dio_unaligned(bdev, pos, iter))
                return -EINVAL;
 
        if (iocb->ki_flags & IOCB_ALLOC_CACHE)
index 278227b..e1d5b10 100644 (file)
@@ -101,29 +101,6 @@ bool set_capacity_and_notify(struct gendisk *disk, sector_t size)
 }
 EXPORT_SYMBOL_GPL(set_capacity_and_notify);
 
-/*
- * Format the device name of the indicated block device into the supplied buffer
- * and return a pointer to that same buffer for convenience.
- *
- * Note: do not use this in new code, use the %pg specifier to sprintf and
- * printk insted.
- */
-const char *bdevname(struct block_device *bdev, char *buf)
-{
-       struct gendisk *hd = bdev->bd_disk;
-       int partno = bdev->bd_partno;
-
-       if (!partno)
-               snprintf(buf, BDEVNAME_SIZE, "%s", hd->disk_name);
-       else if (isdigit(hd->disk_name[strlen(hd->disk_name)-1]))
-               snprintf(buf, BDEVNAME_SIZE, "%sp%d", hd->disk_name, partno);
-       else
-               snprintf(buf, BDEVNAME_SIZE, "%s%d", hd->disk_name, partno);
-
-       return buf;
-}
-EXPORT_SYMBOL(bdevname);
-
 static void part_stat_read_all(struct block_device *part,
                struct disk_stats *stat)
 {
@@ -617,6 +594,8 @@ void del_gendisk(struct gendisk *disk)
         * Fail any new I/O.
         */
        set_bit(GD_DEAD, &disk->state);
+       if (test_bit(GD_OWNS_QUEUE, &disk->state))
+               blk_queue_flag_set(QUEUE_FLAG_DYING, q);
        set_capacity(disk, 0);
 
        /*
@@ -663,11 +642,16 @@ void del_gendisk(struct gendisk *disk)
        blk_mq_unquiesce_queue(q);
 
        /*
-        * Allow using passthrough request again after the queue is torn down.
+        * If the disk does not own the queue, allow using passthrough requests
+        * again.  Else leave the queue frozen to fail all I/O.
         */
-       blk_queue_flag_clear(QUEUE_FLAG_INIT_DONE, q);
-       __blk_mq_unfreeze_queue(q, true);
-
+       if (!test_bit(GD_OWNS_QUEUE, &disk->state)) {
+               blk_queue_flag_clear(QUEUE_FLAG_INIT_DONE, q);
+               __blk_mq_unfreeze_queue(q, true);
+       } else {
+               if (queue_is_mq(q))
+                       blk_mq_exit_queue(q);
+       }
 }
 EXPORT_SYMBOL(del_gendisk);
 
@@ -1127,6 +1111,9 @@ static struct attribute_group disk_attr_group = {
 
 static const struct attribute_group *disk_attr_groups[] = {
        &disk_attr_group,
+#ifdef CONFIG_BLK_DEV_IO_TRACE
+       &blk_trace_attr_group,
+#endif
        NULL
 };
 
@@ -1151,10 +1138,23 @@ static void disk_release(struct device *dev)
        might_sleep();
        WARN_ON_ONCE(disk_live(disk));
 
+       /*
+        * To undo the all initialization from blk_mq_init_allocated_queue in
+        * case of a probe failure where add_disk is never called we have to
+        * call blk_mq_exit_queue here. We can't do this for the more common
+        * teardown case (yet) as the tagset can be gone by the time the disk
+        * is released once it was added.
+        */
+       if (queue_is_mq(disk->queue) &&
+           test_bit(GD_OWNS_QUEUE, &disk->state) &&
+           !test_bit(GD_ADDED, &disk->state))
+               blk_mq_exit_queue(disk->queue);
+
        blkcg_exit_queue(disk->queue);
 
        disk_release_events(disk);
        kfree(disk->random);
+       disk_free_zone_bitmaps(disk);
        xa_destroy(&disk->part_tbl);
 
        disk->queue->disk = NULL;
@@ -1338,9 +1338,6 @@ struct gendisk *__alloc_disk_node(struct request_queue *q, int node_id,
 {
        struct gendisk *disk;
 
-       if (!blk_get_queue(q))
-               return NULL;
-
        disk = kzalloc_node(sizeof(struct gendisk), GFP_KERNEL, node_id);
        if (!disk)
                goto out_put_queue;
@@ -1391,7 +1388,6 @@ out_put_queue:
        blk_put_queue(q);
        return NULL;
 }
-EXPORT_SYMBOL(__alloc_disk_node);
 
 struct gendisk *__blk_alloc_disk(int node, struct lock_class_key *lkclass)
 {
@@ -1404,9 +1400,10 @@ struct gendisk *__blk_alloc_disk(int node, struct lock_class_key *lkclass)
 
        disk = __alloc_disk_node(q, node, lkclass);
        if (!disk) {
-               blk_cleanup_queue(q);
+               blk_put_queue(q);
                return NULL;
        }
+       set_bit(GD_OWNS_QUEUE, &disk->state);
        return disk;
 }
 EXPORT_SYMBOL(__blk_alloc_disk);
@@ -1418,6 +1415,9 @@ EXPORT_SYMBOL(__blk_alloc_disk);
  * This decrements the refcount for the struct gendisk. When this reaches 0
  * we'll have disk_release() called.
  *
+ * Note: for blk-mq disk put_disk must be called before freeing the tag_set
+ * when handling probe errors (that is before add_disk() is called).
+ *
  * Context: Any context, but the last reference must not be dropped from
  *          atomic context.
  */
@@ -1428,22 +1428,6 @@ void put_disk(struct gendisk *disk)
 }
 EXPORT_SYMBOL(put_disk);
 
-/**
- * blk_cleanup_disk - shutdown a gendisk allocated by blk_alloc_disk
- * @disk: gendisk to shutdown
- *
- * Mark the queue hanging off @disk DYING, drain all pending requests, then mark
- * the queue DEAD, destroy and put it and the gendisk structure.
- *
- * Context: can sleep
- */
-void blk_cleanup_disk(struct gendisk *disk)
-{
-       blk_cleanup_queue(disk->queue);
-       put_disk(disk);
-}
-EXPORT_SYMBOL(blk_cleanup_disk);
-
 static void set_disk_ro_uevent(struct gendisk *gd, int ro)
 {
        char event[] = "DISK_RO=1";
index 46949f1..60121e8 100644 (file)
@@ -495,7 +495,7 @@ static int blkdev_common_ioctl(struct block_device *bdev, fmode_t mode,
        case BLKGETZONESZ:
                return put_uint(argp, bdev_zone_sectors(bdev));
        case BLKGETNRZONES:
-               return put_uint(argp, blkdev_nr_zones(bdev->bd_disk));
+               return put_uint(argp, bdev_nr_zones(bdev));
        case BLKROGET:
                return put_int(argp, bdev_read_only(bdev) != 0);
        case BLKSSZGET: /* get block device logical block size */
index 2fe068f..32a456b 100644 (file)
@@ -138,6 +138,32 @@ out:
        return ret;
 }
 
+/*
+ * If the task has set an I/O priority, use that. Otherwise, return
+ * the default I/O priority.
+ *
+ * Expected to be called for current task or with task_lock() held to keep
+ * io_context stable.
+ */
+int __get_task_ioprio(struct task_struct *p)
+{
+       struct io_context *ioc = p->io_context;
+       int prio;
+
+       if (p != current)
+               lockdep_assert_held(&p->alloc_lock);
+       if (ioc)
+               prio = ioc->ioprio;
+       else
+               prio = IOPRIO_DEFAULT;
+
+       if (IOPRIO_PRIO_CLASS(prio) == IOPRIO_CLASS_NONE)
+               prio = IOPRIO_PRIO_VALUE(task_nice_ioclass(p),
+                                        task_nice_ioprio(p));
+       return prio;
+}
+EXPORT_SYMBOL_GPL(__get_task_ioprio);
+
 static int get_task_ioprio(struct task_struct *p)
 {
        int ret;
@@ -145,22 +171,38 @@ static int get_task_ioprio(struct task_struct *p)
        ret = security_task_getioprio(p);
        if (ret)
                goto out;
-       ret = IOPRIO_DEFAULT;
+       task_lock(p);
+       ret = __get_task_ioprio(p);
+       task_unlock(p);
+out:
+       return ret;
+}
+
+/*
+ * Return raw IO priority value as set by userspace. We use this for
+ * ioprio_get(pid, IOPRIO_WHO_PROCESS) so that we keep historical behavior and
+ * also so that userspace can distinguish unset IO priority (which just gets
+ * overriden based on task's nice value) from IO priority set to some value.
+ */
+static int get_task_raw_ioprio(struct task_struct *p)
+{
+       int ret;
+
+       ret = security_task_getioprio(p);
+       if (ret)
+               goto out;
        task_lock(p);
        if (p->io_context)
                ret = p->io_context->ioprio;
+       else
+               ret = IOPRIO_DEFAULT;
        task_unlock(p);
 out:
        return ret;
 }
 
-int ioprio_best(unsigned short aprio, unsigned short bprio)
+static int ioprio_best(unsigned short aprio, unsigned short bprio)
 {
-       if (!ioprio_valid(aprio))
-               aprio = IOPRIO_DEFAULT;
-       if (!ioprio_valid(bprio))
-               bprio = IOPRIO_DEFAULT;
-
        return min(aprio, bprio);
 }
 
@@ -181,7 +223,7 @@ SYSCALL_DEFINE2(ioprio_get, int, which, int, who)
                        else
                                p = find_task_by_vpid(who);
                        if (p)
-                               ret = get_task_ioprio(p);
+                               ret = get_task_raw_ioprio(p);
                        break;
                case IOPRIO_WHO_PGRP:
                        if (!who)
index 8f7c745..b05357b 100644 (file)
@@ -195,9 +195,9 @@ struct kyber_hctx_data {
 static int kyber_domain_wake(wait_queue_entry_t *wait, unsigned mode, int flags,
                             void *key);
 
-static unsigned int kyber_sched_domain(unsigned int op)
+static unsigned int kyber_sched_domain(blk_opf_t opf)
 {
-       switch (op & REQ_OP_MASK) {
+       switch (opf & REQ_OP_MASK) {
        case REQ_OP_READ:
                return KYBER_READ;
        case REQ_OP_WRITE:
@@ -553,13 +553,13 @@ static void rq_clear_domain_token(struct kyber_queue_data *kqd,
        }
 }
 
-static void kyber_limit_depth(unsigned int op, struct blk_mq_alloc_data *data)
+static void kyber_limit_depth(blk_opf_t opf, struct blk_mq_alloc_data *data)
 {
        /*
         * We use the scheduler tags as per-hardware queue queueing tokens.
         * Async requests can be limited at this stage.
         */
-       if (!op_is_sync(op)) {
+       if (!op_is_sync(opf)) {
                struct kyber_queue_data *kqd = data->q->elevator->elevator_data;
 
                data->shallow_depth = kqd->async_depth;
index 1a9e835..5639921 100644 (file)
@@ -543,12 +543,12 @@ unlock:
  * Called by __blk_mq_alloc_request(). The shallow_depth value set by this
  * function is used by __blk_mq_get_tag().
  */
-static void dd_limit_depth(unsigned int op, struct blk_mq_alloc_data *data)
+static void dd_limit_depth(blk_opf_t opf, struct blk_mq_alloc_data *data)
 {
        struct deadline_data *dd = data->q->elevator->elevator_data;
 
        /* Do not throttle synchronous reads. */
-       if (op_is_sync(op) && !op_is_write(op))
+       if (op_is_sync(opf) && !op_is_write(opf))
                return;
 
        /*
index e103ad0..fc1d703 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/slab.h>
 #include <linux/ctype.h>
 #include <linux/vmalloc.h>
-#include <linux/blktrace_api.h>
 #include <linux/raid/detect.h>
 #include "check.h"
 
@@ -331,7 +330,7 @@ static struct block_device *add_partition(struct gendisk *disk, int partno,
        case BLK_ZONED_HA:
                pr_info("%s: disabling host aware zoned block device support due to partitions\n",
                        disk->disk_name);
-               blk_queue_set_zoned(disk, BLK_ZONED_NONE);
+               disk_set_zoned(disk, BLK_ZONED_NONE);
                break;
        case BLK_ZONED_NONE:
                break;
index 4767557..bf9b511 100644 (file)
@@ -43,6 +43,7 @@ config SYSTEM_TRUSTED_KEYRING
        bool "Provide system-wide ring of trusted keys"
        depends on KEYS
        depends on ASYMMETRIC_KEY_TYPE
+       depends on X509_CERTIFICATE_PARSER
        help
          Provide a system keyring to which trusted keys can be added.  Keys in
          the keyring are considered to be trusted.  Keys may be added at will
index 1d44893..bb427a8 100644 (file)
@@ -33,6 +33,27 @@ config CRYPTO_FIPS
          certification.  You should say no unless you know what
          this is.
 
+config CRYPTO_FIPS_NAME
+       string "FIPS Module Name"
+       default "Linux Kernel Cryptographic API"
+       depends on CRYPTO_FIPS
+       help
+         This option sets the FIPS Module name reported by the Crypto API via
+         the /proc/sys/crypto/fips_name file.
+
+config CRYPTO_FIPS_CUSTOM_VERSION
+       bool "Use Custom FIPS Module Version"
+       depends on CRYPTO_FIPS
+       default n
+
+config CRYPTO_FIPS_VERSION
+       string "FIPS Module Version"
+       default "(none)"
+       depends on CRYPTO_FIPS_CUSTOM_VERSION
+       help
+         This option provides the ability to override the FIPS Module Version.
+         By default the KERNELRELEASE value is used.
+
 config CRYPTO_ALGAPI
        tristate
        select CRYPTO_ALGAPI2
@@ -461,6 +482,15 @@ config CRYPTO_PCBC
          PCBC: Propagating Cipher Block Chaining mode
          This block cipher algorithm is required for RxRPC.
 
+config CRYPTO_XCTR
+       tristate
+       select CRYPTO_SKCIPHER
+       select CRYPTO_MANAGER
+       help
+         XCTR: XOR Counter mode. This blockcipher mode is a variant of CTR mode
+         using XORs and little-endian addition rather than big-endian arithmetic.
+         XCTR mode is used to implement HCTR2.
+
 config CRYPTO_XTS
        tristate "XTS support"
        select CRYPTO_SKCIPHER
@@ -524,6 +554,17 @@ config CRYPTO_ADIANTUM
 
          If unsure, say N.
 
+config CRYPTO_HCTR2
+       tristate "HCTR2 support"
+       select CRYPTO_XCTR
+       select CRYPTO_POLYVAL
+       select CRYPTO_MANAGER
+       help
+         HCTR2 is a length-preserving encryption mode for storage encryption that
+         is efficient on processors with instructions to accelerate AES and
+         carryless multiplication, e.g. x86 processors with AES-NI and CLMUL, and
+         ARM processors with the ARMv8 crypto extensions.
+
 config CRYPTO_ESSIV
        tristate "ESSIV support for block encryption"
        select CRYPTO_AUTHENC
@@ -666,6 +707,18 @@ config CRYPTO_CRC32_MIPS
          CRC32c and CRC32 CRC algorithms implemented using mips crypto
          instructions, when available.
 
+config CRYPTO_CRC32_S390
+       tristate "CRC-32 algorithms"
+       depends on S390
+       select CRYPTO_HASH
+       select CRC32
+       help
+         Select this option if you want to use hardware accelerated
+         implementations of CRC algorithms.  With this option, you
+         can optimize the computation of CRC-32 (IEEE 802.3 Ethernet)
+         and CRC-32C (Castagnoli).
+
+         It is available with IBM z13 or later.
 
 config CRYPTO_XXHASH
        tristate "xxHash hash algorithm"
@@ -692,26 +745,8 @@ config CRYPTO_BLAKE2B
 
          See https://blake2.net for further information.
 
-config CRYPTO_BLAKE2S
-       tristate "BLAKE2s digest algorithm"
-       select CRYPTO_LIB_BLAKE2S_GENERIC
-       select CRYPTO_HASH
-       help
-         Implementation of cryptographic hash function BLAKE2s
-         optimized for 8-32bit platforms and can produce digests of any size
-         between 1 to 32.  The keyed hash is also implemented.
-
-         This module provides the following algorithms:
-
-         - blake2s-128
-         - blake2s-160
-         - blake2s-224
-         - blake2s-256
-
-         See https://blake2.net for further information.
-
 config CRYPTO_BLAKE2S_X86
-       tristate "BLAKE2s digest algorithm (x86 accelerated version)"
+       bool "BLAKE2s digest algorithm (x86 accelerated version)"
        depends on X86 && 64BIT
        select CRYPTO_LIB_BLAKE2S_GENERIC
        select CRYPTO_ARCH_HAVE_LIB_BLAKE2S
@@ -765,6 +800,23 @@ config CRYPTO_GHASH
          GHASH is the hash function used in GCM (Galois/Counter Mode).
          It is not a general-purpose cryptographic hash function.
 
+config CRYPTO_POLYVAL
+       tristate
+       select CRYPTO_GF128MUL
+       select CRYPTO_HASH
+       help
+         POLYVAL is the hash function used in HCTR2.  It is not a general-purpose
+         cryptographic hash function.
+
+config CRYPTO_POLYVAL_CLMUL_NI
+       tristate "POLYVAL hash function (CLMUL-NI accelerated)"
+       depends on X86 && 64BIT
+       select CRYPTO_POLYVAL
+       help
+         This is the x86_64 CLMUL-NI accelerated implementation of POLYVAL. It is
+         used to efficiently implement HCTR2 on x86-64 processors that support
+         carry-less multiplication instructions.
+
 config CRYPTO_POLY1305
        tristate "Poly1305 authenticator algorithm"
        select CRYPTO_HASH
@@ -849,7 +901,7 @@ config CRYPTO_RMD160
 
          RIPEMD-160 is a 160-bit cryptographic hash function. It is intended
          to be used as a secure replacement for the 128-bit hash functions
-         MD4, MD5 and it's predecessor RIPEMD
+         MD4, MD5 and its predecessor RIPEMD
          (not to be confused with RIPEMD-128).
 
          It's speed is comparable to SHA1 and there are no known attacks
@@ -861,6 +913,7 @@ config CRYPTO_RMD160
 config CRYPTO_SHA1
        tristate "SHA1 digest algorithm"
        select CRYPTO_HASH
+       select CRYPTO_LIB_SHA1
        help
          SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
 
@@ -898,6 +951,16 @@ config CRYPTO_SHA512_SSSE3
          Extensions version 1 (AVX1), or Advanced Vector Extensions
          version 2 (AVX2) instructions, when available.
 
+config CRYPTO_SHA512_S390
+       tristate "SHA384 and SHA512 digest algorithm"
+       depends on S390
+       select CRYPTO_HASH
+       help
+         This is the s390 hardware accelerated implementation of the
+         SHA512 secure hash standard.
+
+         It is available as of z10.
+
 config CRYPTO_SHA1_OCTEON
        tristate "SHA1 digest algorithm (OCTEON)"
        depends on CPU_CAVIUM_OCTEON
@@ -930,6 +993,16 @@ config CRYPTO_SHA1_PPC_SPE
          SHA-1 secure hash standard (DFIPS 180-4) implemented
          using powerpc SPE SIMD instruction set.
 
+config CRYPTO_SHA1_S390
+       tristate "SHA1 digest algorithm"
+       depends on S390
+       select CRYPTO_HASH
+       help
+         This is the s390 hardware accelerated implementation of the
+         SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
+
+         It is available as of z990.
+
 config CRYPTO_SHA256
        tristate "SHA224 and SHA256 digest algorithm"
        select CRYPTO_HASH
@@ -970,6 +1043,16 @@ config CRYPTO_SHA256_SPARC64
          SHA-256 secure hash standard (DFIPS 180-2) implemented
          using sparc64 crypto instructions, when available.
 
+config CRYPTO_SHA256_S390
+       tristate "SHA256 digest algorithm"
+       depends on S390
+       select CRYPTO_HASH
+       help
+         This is the s390 hardware accelerated implementation of the
+         SHA256 secure hash standard (DFIPS 180-2).
+
+         It is available as of z9.
+
 config CRYPTO_SHA512
        tristate "SHA384 and SHA512 digest algorithms"
        select CRYPTO_HASH
@@ -1010,6 +1093,26 @@ config CRYPTO_SHA3
          References:
          http://keccak.noekeon.org/
 
+config CRYPTO_SHA3_256_S390
+       tristate "SHA3_224 and SHA3_256 digest algorithm"
+       depends on S390
+       select CRYPTO_HASH
+       help
+         This is the s390 hardware accelerated implementation of the
+         SHA3_256 secure hash standard.
+
+         It is available as of z14.
+
+config CRYPTO_SHA3_512_S390
+       tristate "SHA3_384 and SHA3_512 digest algorithm"
+       depends on S390
+       select CRYPTO_HASH
+       help
+         This is the s390 hardware accelerated implementation of the
+         SHA3_512 secure hash standard.
+
+         It is available as of z14.
+
 config CRYPTO_SM3
        tristate
 
@@ -1070,6 +1173,16 @@ config CRYPTO_GHASH_CLMUL_NI_INTEL
          This is the x86_64 CLMUL-NI accelerated implementation of
          GHASH, the hash function used in GCM (Galois/Counter mode).
 
+config CRYPTO_GHASH_S390
+       tristate "GHASH hash function"
+       depends on S390
+       select CRYPTO_HASH
+       help
+         This is the s390 hardware accelerated implementation of GHASH,
+         the hash function used in GCM (Galois/Counter mode).
+
+         It is available as of z196.
+
 comment "Ciphers"
 
 config CRYPTO_AES
@@ -1142,7 +1255,7 @@ config CRYPTO_AES_NI_INTEL
          In addition to AES cipher algorithm support, the acceleration
          for some popular block cipher mode is supported too, including
          ECB, CBC, LRW, XTS. The 64 bit version has additional
-         acceleration for CTR.
+         acceleration for CTR and XCTR.
 
 config CRYPTO_AES_SPARC64
        tristate "AES cipher algorithms (SPARC64)"
@@ -1185,6 +1298,23 @@ config CRYPTO_AES_PPC_SPE
          architecture specific assembler implementations that work on 1KB
          tables or 256 bytes S-boxes.
 
+config CRYPTO_AES_S390
+       tristate "AES cipher algorithms"
+       depends on S390
+       select CRYPTO_ALGAPI
+       select CRYPTO_SKCIPHER
+       help
+         This is the s390 hardware accelerated implementation of the
+         AES cipher algorithms (FIPS-197).
+
+         As of z9 the ECB and CBC modes are hardware accelerated
+         for 128 bit keys.
+         As of z10 the ECB and CBC modes are hardware accelerated
+         for all AES key sizes.
+         As of z196 the CTR mode is hardware accelerated for all AES
+         key sizes and XTS mode is hardware accelerated for 256 and
+         512 bit keys.
+
 config CRYPTO_ANUBIS
        tristate "Anubis cipher algorithm"
        depends on CRYPTO_USER_API_ENABLE_OBSOLETE
@@ -1415,6 +1545,19 @@ config CRYPTO_DES3_EDE_X86_64
          algorithm are provided; regular processing one input block and
          one that processes three blocks parallel.
 
+config CRYPTO_DES_S390
+       tristate "DES and Triple DES cipher algorithms"
+       depends on S390
+       select CRYPTO_ALGAPI
+       select CRYPTO_SKCIPHER
+       select CRYPTO_LIB_DES
+       help
+         This is the s390 hardware accelerated implementation of the
+         DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
+
+         As of z990 the ECB and CBC mode are hardware accelerated.
+         As of z196 the CTR mode is hardware accelerated.
+
 config CRYPTO_FCRYPT
        tristate "FCrypt cipher algorithm"
        select CRYPTO_ALGAPI
@@ -1474,6 +1617,18 @@ config CRYPTO_CHACHA_MIPS
        select CRYPTO_SKCIPHER
        select CRYPTO_ARCH_HAVE_LIB_CHACHA
 
+config CRYPTO_CHACHA_S390
+       tristate "ChaCha20 stream cipher"
+       depends on S390
+       select CRYPTO_SKCIPHER
+       select CRYPTO_LIB_CHACHA_GENERIC
+       select CRYPTO_ARCH_HAVE_LIB_CHACHA
+       help
+         This is the s390 SIMD implementation of the ChaCha20 stream
+         cipher (RFC 7539).
+
+         It is available as of z13.
+
 config CRYPTO_SEED
        tristate "SEED cipher algorithm"
        depends on CRYPTO_USER_API_ENABLE_OBSOLETE
@@ -1489,6 +1644,21 @@ config CRYPTO_SEED
          See also:
          <http://www.kisa.or.kr/kisa/seed/jsp/seed_eng.jsp>
 
+config CRYPTO_ARIA
+       tristate "ARIA cipher algorithm"
+       select CRYPTO_ALGAPI
+       help
+         ARIA cipher algorithm (RFC5794).
+
+         ARIA is a standard encryption algorithm of the Republic of Korea.
+         The ARIA specifies three key sizes and rounds.
+         128-bit: 12 rounds.
+         192-bit: 14 rounds.
+         256-bit: 16 rounds.
+
+         See also:
+         <https://seed.kisa.or.kr/kisa/algorithm/EgovAriaInfo.do>
+
 config CRYPTO_SERPENT
        tristate "Serpent cipher algorithm"
        select CRYPTO_ALGAPI
index ceaaa9f..167c004 100644 (file)
@@ -84,7 +84,6 @@ obj-$(CONFIG_CRYPTO_STREEBOG) += streebog_generic.o
 obj-$(CONFIG_CRYPTO_WP512) += wp512.o
 CFLAGS_wp512.o := $(call cc-option,-fno-schedule-insns)  # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79149
 obj-$(CONFIG_CRYPTO_BLAKE2B) += blake2b_generic.o
-obj-$(CONFIG_CRYPTO_BLAKE2S) += blake2s_generic.o
 obj-$(CONFIG_CRYPTO_GF128MUL) += gf128mul.o
 obj-$(CONFIG_CRYPTO_ECB) += ecb.o
 obj-$(CONFIG_CRYPTO_CBC) += cbc.o
@@ -94,6 +93,8 @@ obj-$(CONFIG_CRYPTO_CTS) += cts.o
 obj-$(CONFIG_CRYPTO_LRW) += lrw.o
 obj-$(CONFIG_CRYPTO_XTS) += xts.o
 obj-$(CONFIG_CRYPTO_CTR) += ctr.o
+obj-$(CONFIG_CRYPTO_XCTR) += xctr.o
+obj-$(CONFIG_CRYPTO_HCTR2) += hctr2.o
 obj-$(CONFIG_CRYPTO_KEYWRAP) += keywrap.o
 obj-$(CONFIG_CRYPTO_ADIANTUM) += adiantum.o
 obj-$(CONFIG_CRYPTO_NHPOLY1305) += nhpoly1305.o
@@ -147,6 +148,7 @@ obj-$(CONFIG_CRYPTO_TEA) += tea.o
 obj-$(CONFIG_CRYPTO_KHAZAD) += khazad.o
 obj-$(CONFIG_CRYPTO_ANUBIS) += anubis.o
 obj-$(CONFIG_CRYPTO_SEED) += seed.o
+obj-$(CONFIG_CRYPTO_ARIA) += aria.o
 obj-$(CONFIG_CRYPTO_CHACHA20) += chacha_generic.o
 obj-$(CONFIG_CRYPTO_POLY1305) += poly1305_generic.o
 obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
@@ -171,6 +173,7 @@ UBSAN_SANITIZE_jitterentropy.o = n
 jitterentropy_rng-y := jitterentropy.o jitterentropy-kcapi.o
 obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
 obj-$(CONFIG_CRYPTO_GHASH) += ghash-generic.o
+obj-$(CONFIG_CRYPTO_POLYVAL) += polyval-generic.o
 obj-$(CONFIG_CRYPTO_USER_API) += af_alg.o
 obj-$(CONFIG_CRYPTO_USER_API_HASH) += algif_hash.o
 obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o
diff --git a/crypto/aria.c b/crypto/aria.c
new file mode 100644 (file)
index 0000000..ac3dffa
--- /dev/null
@@ -0,0 +1,288 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Cryptographic API.
+ *
+ * ARIA Cipher Algorithm.
+ *
+ * Documentation of ARIA can be found in RFC 5794.
+ * Copyright (c) 2022 Taehee Yoo <ap420073@gmail.com>
+ *
+ * Information for ARIA
+ *     http://210.104.33.10/ARIA/index-e.html (English)
+ *     http://seed.kisa.or.kr/ (Korean)
+ *
+ * Public domain version is distributed above.
+ */
+
+#include <crypto/aria.h>
+
+static void aria_set_encrypt_key(struct aria_ctx *ctx, const u8 *in_key,
+                                unsigned int key_len)
+{
+       const __be32 *key = (const __be32 *)in_key;
+       u32 w0[4], w1[4], w2[4], w3[4];
+       u32 reg0, reg1, reg2, reg3;
+       const u32 *ck;
+       int rkidx = 0;
+
+       ck = &key_rc[(key_len - 16) / 8][0];
+
+       w0[0] = be32_to_cpu(key[0]);
+       w0[1] = be32_to_cpu(key[1]);
+       w0[2] = be32_to_cpu(key[2]);
+       w0[3] = be32_to_cpu(key[3]);
+
+       reg0 = w0[0] ^ ck[0];
+       reg1 = w0[1] ^ ck[1];
+       reg2 = w0[2] ^ ck[2];
+       reg3 = w0[3] ^ ck[3];
+
+       aria_subst_diff_odd(&reg0, &reg1, &reg2, &reg3);
+
+       if (key_len > 16) {
+               w1[0] = be32_to_cpu(key[4]);
+               w1[1] = be32_to_cpu(key[5]);
+               if (key_len > 24) {
+                       w1[2] = be32_to_cpu(key[6]);
+                       w1[3] = be32_to_cpu(key[7]);
+               } else {
+                       w1[2] = 0;
+                       w1[3] = 0;
+               }
+       } else {
+               w1[0] = 0;
+               w1[1] = 0;
+               w1[2] = 0;
+               w1[3] = 0;
+       }
+
+       w1[0] ^= reg0;
+       w1[1] ^= reg1;
+       w1[2] ^= reg2;
+       w1[3] ^= reg3;
+
+       reg0 = w1[0];
+       reg1 = w1[1];
+       reg2 = w1[2];
+       reg3 = w1[3];
+
+       reg0 ^= ck[4];
+       reg1 ^= ck[5];
+       reg2 ^= ck[6];
+       reg3 ^= ck[7];
+
+       aria_subst_diff_even(&reg0, &reg1, &reg2, &reg3);
+
+       reg0 ^= w0[0];
+       reg1 ^= w0[1];
+       reg2 ^= w0[2];
+       reg3 ^= w0[3];
+
+       w2[0] = reg0;
+       w2[1] = reg1;
+       w2[2] = reg2;
+       w2[3] = reg3;
+
+       reg0 ^= ck[8];
+       reg1 ^= ck[9];
+       reg2 ^= ck[10];
+       reg3 ^= ck[11];
+
+       aria_subst_diff_odd(&reg0, &reg1, &reg2, &reg3);
+
+       w3[0] = reg0 ^ w1[0];
+       w3[1] = reg1 ^ w1[1];
+       w3[2] = reg2 ^ w1[2];
+       w3[3] = reg3 ^ w1[3];
+
+       aria_gsrk(ctx->enc_key[rkidx], w0, w1, 19);
+       rkidx++;
+       aria_gsrk(ctx->enc_key[rkidx], w1, w2, 19);
+       rkidx++;
+       aria_gsrk(ctx->enc_key[rkidx], w2, w3, 19);
+       rkidx++;
+       aria_gsrk(ctx->enc_key[rkidx], w3, w0, 19);
+
+       rkidx++;
+       aria_gsrk(ctx->enc_key[rkidx], w0, w1, 31);
+       rkidx++;
+       aria_gsrk(ctx->enc_key[rkidx], w1, w2, 31);
+       rkidx++;
+       aria_gsrk(ctx->enc_key[rkidx], w2, w3, 31);
+       rkidx++;
+       aria_gsrk(ctx->enc_key[rkidx], w3, w0, 31);
+
+       rkidx++;
+       aria_gsrk(ctx->enc_key[rkidx], w0, w1, 67);
+       rkidx++;
+       aria_gsrk(ctx->enc_key[rkidx], w1, w2, 67);
+       rkidx++;
+       aria_gsrk(ctx->enc_key[rkidx], w2, w3, 67);
+       rkidx++;
+       aria_gsrk(ctx->enc_key[rkidx], w3, w0, 67);
+
+       rkidx++;
+       aria_gsrk(ctx->enc_key[rkidx], w0, w1, 97);
+       if (key_len > 16) {
+               rkidx++;
+               aria_gsrk(ctx->enc_key[rkidx], w1, w2, 97);
+               rkidx++;
+               aria_gsrk(ctx->enc_key[rkidx], w2, w3, 97);
+
+               if (key_len > 24) {
+                       rkidx++;
+                       aria_gsrk(ctx->enc_key[rkidx], w3, w0, 97);
+
+                       rkidx++;
+                       aria_gsrk(ctx->enc_key[rkidx], w0, w1, 109);
+               }
+       }
+}
+
+static void aria_set_decrypt_key(struct aria_ctx *ctx)
+{
+       int i;
+
+       for (i = 0; i < 4; i++) {
+               ctx->dec_key[0][i] = ctx->enc_key[ctx->rounds][i];
+               ctx->dec_key[ctx->rounds][i] = ctx->enc_key[0][i];
+       }
+
+       for (i = 1; i < ctx->rounds; i++) {
+               ctx->dec_key[i][0] = aria_m(ctx->enc_key[ctx->rounds - i][0]);
+               ctx->dec_key[i][1] = aria_m(ctx->enc_key[ctx->rounds - i][1]);
+               ctx->dec_key[i][2] = aria_m(ctx->enc_key[ctx->rounds - i][2]);
+               ctx->dec_key[i][3] = aria_m(ctx->enc_key[ctx->rounds - i][3]);
+
+               aria_diff_word(&ctx->dec_key[i][0], &ctx->dec_key[i][1],
+                              &ctx->dec_key[i][2], &ctx->dec_key[i][3]);
+               aria_diff_byte(&ctx->dec_key[i][1],
+                              &ctx->dec_key[i][2], &ctx->dec_key[i][3]);
+               aria_diff_word(&ctx->dec_key[i][0], &ctx->dec_key[i][1],
+                              &ctx->dec_key[i][2], &ctx->dec_key[i][3]);
+       }
+}
+
+static int aria_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+                       unsigned int key_len)
+{
+       struct aria_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       if (key_len != 16 && key_len != 24 && key_len != 32)
+               return -EINVAL;
+
+       ctx->key_length = key_len;
+       ctx->rounds = (key_len + 32) / 4;
+
+       aria_set_encrypt_key(ctx, in_key, key_len);
+       aria_set_decrypt_key(ctx);
+
+       return 0;
+}
+
+static void __aria_crypt(struct aria_ctx *ctx, u8 *out, const u8 *in,
+                        u32 key[][ARIA_RD_KEY_WORDS])
+{
+       const __be32 *src = (const __be32 *)in;
+       __be32 *dst = (__be32 *)out;
+       u32 reg0, reg1, reg2, reg3;
+       int rounds, rkidx = 0;
+
+       rounds = ctx->rounds;
+
+       reg0 = be32_to_cpu(src[0]);
+       reg1 = be32_to_cpu(src[1]);
+       reg2 = be32_to_cpu(src[2]);
+       reg3 = be32_to_cpu(src[3]);
+
+       aria_add_round_key(key[rkidx], &reg0, &reg1, &reg2, &reg3);
+       rkidx++;
+
+       aria_subst_diff_odd(&reg0, &reg1, &reg2, &reg3);
+       aria_add_round_key(key[rkidx], &reg0, &reg1, &reg2, &reg3);
+       rkidx++;
+
+       while ((rounds -= 2) > 0) {
+               aria_subst_diff_even(&reg0, &reg1, &reg2, &reg3);
+               aria_add_round_key(key[rkidx], &reg0, &reg1, &reg2, &reg3);
+               rkidx++;
+
+               aria_subst_diff_odd(&reg0, &reg1, &reg2, &reg3);
+               aria_add_round_key(key[rkidx], &reg0, &reg1, &reg2, &reg3);
+               rkidx++;
+       }
+
+       reg0 = key[rkidx][0] ^ make_u32((u8)(x1[get_u8(reg0, 0)]),
+                                       (u8)(x2[get_u8(reg0, 1)] >> 8),
+                                       (u8)(s1[get_u8(reg0, 2)]),
+                                       (u8)(s2[get_u8(reg0, 3)]));
+       reg1 = key[rkidx][1] ^ make_u32((u8)(x1[get_u8(reg1, 0)]),
+                                       (u8)(x2[get_u8(reg1, 1)] >> 8),
+                                       (u8)(s1[get_u8(reg1, 2)]),
+                                       (u8)(s2[get_u8(reg1, 3)]));
+       reg2 = key[rkidx][2] ^ make_u32((u8)(x1[get_u8(reg2, 0)]),
+                                       (u8)(x2[get_u8(reg2, 1)] >> 8),
+                                       (u8)(s1[get_u8(reg2, 2)]),
+                                       (u8)(s2[get_u8(reg2, 3)]));
+       reg3 = key[rkidx][3] ^ make_u32((u8)(x1[get_u8(reg3, 0)]),
+                                       (u8)(x2[get_u8(reg3, 1)] >> 8),
+                                       (u8)(s1[get_u8(reg3, 2)]),
+                                       (u8)(s2[get_u8(reg3, 3)]));
+
+       dst[0] = cpu_to_be32(reg0);
+       dst[1] = cpu_to_be32(reg1);
+       dst[2] = cpu_to_be32(reg2);
+       dst[3] = cpu_to_be32(reg3);
+}
+
+static void aria_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+       struct aria_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       __aria_crypt(ctx, out, in, ctx->enc_key);
+}
+
+static void aria_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+       struct aria_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       __aria_crypt(ctx, out, in, ctx->dec_key);
+}
+
+static struct crypto_alg aria_alg = {
+       .cra_name               =       "aria",
+       .cra_driver_name        =       "aria-generic",
+       .cra_priority           =       100,
+       .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
+       .cra_blocksize          =       ARIA_BLOCK_SIZE,
+       .cra_ctxsize            =       sizeof(struct aria_ctx),
+       .cra_alignmask          =       3,
+       .cra_module             =       THIS_MODULE,
+       .cra_u                  =       {
+               .cipher = {
+                       .cia_min_keysize        =       ARIA_MIN_KEY_SIZE,
+                       .cia_max_keysize        =       ARIA_MAX_KEY_SIZE,
+                       .cia_setkey             =       aria_set_key,
+                       .cia_encrypt            =       aria_encrypt,
+                       .cia_decrypt            =       aria_decrypt
+               }
+       }
+};
+
+static int __init aria_init(void)
+{
+       return crypto_register_alg(&aria_alg);
+}
+
+static void __exit aria_fini(void)
+{
+       crypto_unregister_alg(&aria_alg);
+}
+
+subsys_initcall(aria_init);
+module_exit(aria_fini);
+
+MODULE_DESCRIPTION("ARIA Cipher Algorithm");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Taehee Yoo <ap420073@gmail.com>");
+MODULE_ALIAS_CRYPTO("aria");
diff --git a/crypto/blake2s_generic.c b/crypto/blake2s_generic.c
deleted file mode 100644 (file)
index 5f96a21..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0 OR MIT
-/*
- * shash interface to the generic implementation of BLAKE2s
- *
- * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
- */
-
-#include <crypto/internal/blake2s.h>
-#include <crypto/internal/hash.h>
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-
-static int crypto_blake2s_update_generic(struct shash_desc *desc,
-                                        const u8 *in, unsigned int inlen)
-{
-       return crypto_blake2s_update(desc, in, inlen, true);
-}
-
-static int crypto_blake2s_final_generic(struct shash_desc *desc, u8 *out)
-{
-       return crypto_blake2s_final(desc, out, true);
-}
-
-#define BLAKE2S_ALG(name, driver_name, digest_size)                    \
-       {                                                               \
-               .base.cra_name          = name,                         \
-               .base.cra_driver_name   = driver_name,                  \
-               .base.cra_priority      = 100,                          \
-               .base.cra_flags         = CRYPTO_ALG_OPTIONAL_KEY,      \
-               .base.cra_blocksize     = BLAKE2S_BLOCK_SIZE,           \
-               .base.cra_ctxsize       = sizeof(struct blake2s_tfm_ctx), \
-               .base.cra_module        = THIS_MODULE,                  \
-               .digestsize             = digest_size,                  \
-               .setkey                 = crypto_blake2s_setkey,        \
-               .init                   = crypto_blake2s_init,          \
-               .update                 = crypto_blake2s_update_generic, \
-               .final                  = crypto_blake2s_final_generic, \
-               .descsize               = sizeof(struct blake2s_state), \
-       }
-
-static struct shash_alg blake2s_algs[] = {
-       BLAKE2S_ALG("blake2s-128", "blake2s-128-generic",
-                   BLAKE2S_128_HASH_SIZE),
-       BLAKE2S_ALG("blake2s-160", "blake2s-160-generic",
-                   BLAKE2S_160_HASH_SIZE),
-       BLAKE2S_ALG("blake2s-224", "blake2s-224-generic",
-                   BLAKE2S_224_HASH_SIZE),
-       BLAKE2S_ALG("blake2s-256", "blake2s-256-generic",
-                   BLAKE2S_256_HASH_SIZE),
-};
-
-static int __init blake2s_mod_init(void)
-{
-       return crypto_register_shashes(blake2s_algs, ARRAY_SIZE(blake2s_algs));
-}
-
-static void __exit blake2s_mod_exit(void)
-{
-       crypto_unregister_shashes(blake2s_algs, ARRAY_SIZE(blake2s_algs));
-}
-
-subsys_initcall(blake2s_mod_init);
-module_exit(blake2s_mod_exit);
-
-MODULE_ALIAS_CRYPTO("blake2s-128");
-MODULE_ALIAS_CRYPTO("blake2s-128-generic");
-MODULE_ALIAS_CRYPTO("blake2s-160");
-MODULE_ALIAS_CRYPTO("blake2s-160-generic");
-MODULE_ALIAS_CRYPTO("blake2s-224");
-MODULE_ALIAS_CRYPTO("blake2s-224-generic");
-MODULE_ALIAS_CRYPTO("blake2s-256");
-MODULE_ALIAS_CRYPTO("blake2s-256-generic");
-MODULE_LICENSE("GPL v2");
index 7b1d8ca..b05d3c7 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/sysctl.h>
 #include <linux/notifier.h>
+#include <generated/utsrelease.h>
 
 int fips_enabled;
 EXPORT_SYMBOL_GPL(fips_enabled);
@@ -30,13 +31,37 @@ static int fips_enable(char *str)
 
 __setup("fips=", fips_enable);
 
+#define FIPS_MODULE_NAME CONFIG_CRYPTO_FIPS_NAME
+#ifdef CONFIG_CRYPTO_FIPS_CUSTOM_VERSION
+#define FIPS_MODULE_VERSION CONFIG_CRYPTO_FIPS_VERSION
+#else
+#define FIPS_MODULE_VERSION UTS_RELEASE
+#endif
+
+static char fips_name[] = FIPS_MODULE_NAME;
+static char fips_version[] = FIPS_MODULE_VERSION;
+
 static struct ctl_table crypto_sysctl_table[] = {
        {
-               .procname       = "fips_enabled",
-               .data           = &fips_enabled,
-               .maxlen         = sizeof(int),
-               .mode           = 0444,
-               .proc_handler   = proc_dointvec
+               .procname       = "fips_enabled",
+               .data           = &fips_enabled,
+               .maxlen         = sizeof(int),
+               .mode           = 0444,
+               .proc_handler   = proc_dointvec
+       },
+       {
+               .procname       = "fips_name",
+               .data           = &fips_name,
+               .maxlen         = 64,
+               .mode           = 0444,
+               .proc_handler   = proc_dostring
+       },
+       {
+               .procname       = "fips_version",
+               .data           = &fips_version,
+               .maxlen         = 64,
+               .mode           = 0444,
+               .proc_handler   = proc_dostring
        },
        {}
 };
diff --git a/crypto/hctr2.c b/crypto/hctr2.c
new file mode 100644 (file)
index 0000000..7d00a3b
--- /dev/null
@@ -0,0 +1,581 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * HCTR2 length-preserving encryption mode
+ *
+ * Copyright 2021 Google LLC
+ */
+
+
+/*
+ * HCTR2 is a length-preserving encryption mode that is efficient on
+ * processors with instructions to accelerate AES and carryless
+ * multiplication, e.g. x86 processors with AES-NI and CLMUL, and ARM
+ * processors with the ARMv8 crypto extensions.
+ *
+ * For more details, see the paper: "Length-preserving encryption with HCTR2"
+ * (https://eprint.iacr.org/2021/1441.pdf)
+ */
+
+#include <crypto/internal/cipher.h>
+#include <crypto/internal/hash.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/polyval.h>
+#include <crypto/scatterwalk.h>
+#include <linux/module.h>
+
+#define BLOCKCIPHER_BLOCK_SIZE         16
+
+/*
+ * The specification allows variable-length tweaks, but Linux's crypto API
+ * currently only allows algorithms to support a single length.  The "natural"
+ * tweak length for HCTR2 is 16, since that fits into one POLYVAL block for
+ * the best performance.  But longer tweaks are useful for fscrypt, to avoid
+ * needing to derive per-file keys.  So instead we use two blocks, or 32 bytes.
+ */
+#define TWEAK_SIZE             32
+
+struct hctr2_instance_ctx {
+       struct crypto_cipher_spawn blockcipher_spawn;
+       struct crypto_skcipher_spawn xctr_spawn;
+       struct crypto_shash_spawn polyval_spawn;
+};
+
+struct hctr2_tfm_ctx {
+       struct crypto_cipher *blockcipher;
+       struct crypto_skcipher *xctr;
+       struct crypto_shash *polyval;
+       u8 L[BLOCKCIPHER_BLOCK_SIZE];
+       int hashed_tweak_offset;
+       /*
+        * This struct is allocated with extra space for two exported hash
+        * states.  Since the hash state size is not known at compile-time, we
+        * can't add these to the struct directly.
+        *
+        * hashed_tweaklen_divisible;
+        * hashed_tweaklen_remainder;
+        */
+};
+
+struct hctr2_request_ctx {
+       u8 first_block[BLOCKCIPHER_BLOCK_SIZE];
+       u8 xctr_iv[BLOCKCIPHER_BLOCK_SIZE];
+       struct scatterlist *bulk_part_dst;
+       struct scatterlist *bulk_part_src;
+       struct scatterlist sg_src[2];
+       struct scatterlist sg_dst[2];
+       /*
+        * Sub-request sizes are unknown at compile-time, so they need to go
+        * after the members with known sizes.
+        */
+       union {
+               struct shash_desc hash_desc;
+               struct skcipher_request xctr_req;
+       } u;
+       /*
+        * This struct is allocated with extra space for one exported hash
+        * state.  Since the hash state size is not known at compile-time, we
+        * can't add it to the struct directly.
+        *
+        * hashed_tweak;
+        */
+};
+
+static inline u8 *hctr2_hashed_tweaklen(const struct hctr2_tfm_ctx *tctx,
+                                       bool has_remainder)
+{
+       u8 *p = (u8 *)tctx + sizeof(*tctx);
+
+       if (has_remainder) /* For messages not a multiple of block length */
+               p += crypto_shash_statesize(tctx->polyval);
+       return p;
+}
+
+static inline u8 *hctr2_hashed_tweak(const struct hctr2_tfm_ctx *tctx,
+                                    struct hctr2_request_ctx *rctx)
+{
+       return (u8 *)rctx + tctx->hashed_tweak_offset;
+}
+
+/*
+ * The input data for each HCTR2 hash step begins with a 16-byte block that
+ * contains the tweak length and a flag that indicates whether the input is evenly
+ * divisible into blocks.  Since this implementation only supports one tweak
+ * length, we precompute the two hash states resulting from hashing the two
+ * possible values of this initial block.  This reduces by one block the amount of
+ * data that needs to be hashed for each encryption/decryption
+ *
+ * These precomputed hashes are stored in hctr2_tfm_ctx.
+ */
+static int hctr2_hash_tweaklen(struct hctr2_tfm_ctx *tctx, bool has_remainder)
+{
+       SHASH_DESC_ON_STACK(shash, tfm->polyval);
+       __le64 tweak_length_block[2];
+       int err;
+
+       shash->tfm = tctx->polyval;
+       memset(tweak_length_block, 0, sizeof(tweak_length_block));
+
+       tweak_length_block[0] = cpu_to_le64(TWEAK_SIZE * 8 * 2 + 2 + has_remainder);
+       err = crypto_shash_init(shash);
+       if (err)
+               return err;
+       err = crypto_shash_update(shash, (u8 *)tweak_length_block,
+                                 POLYVAL_BLOCK_SIZE);
+       if (err)
+               return err;
+       return crypto_shash_export(shash, hctr2_hashed_tweaklen(tctx, has_remainder));
+}
+
+static int hctr2_setkey(struct crypto_skcipher *tfm, const u8 *key,
+                       unsigned int keylen)
+{
+       struct hctr2_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
+       u8 hbar[BLOCKCIPHER_BLOCK_SIZE];
+       int err;
+
+       crypto_cipher_clear_flags(tctx->blockcipher, CRYPTO_TFM_REQ_MASK);
+       crypto_cipher_set_flags(tctx->blockcipher,
+                               crypto_skcipher_get_flags(tfm) &
+                               CRYPTO_TFM_REQ_MASK);
+       err = crypto_cipher_setkey(tctx->blockcipher, key, keylen);
+       if (err)
+               return err;
+
+       crypto_skcipher_clear_flags(tctx->xctr, CRYPTO_TFM_REQ_MASK);
+       crypto_skcipher_set_flags(tctx->xctr,
+                                 crypto_skcipher_get_flags(tfm) &
+                                 CRYPTO_TFM_REQ_MASK);
+       err = crypto_skcipher_setkey(tctx->xctr, key, keylen);
+       if (err)
+               return err;
+
+       memset(hbar, 0, sizeof(hbar));
+       crypto_cipher_encrypt_one(tctx->blockcipher, hbar, hbar);
+
+       memset(tctx->L, 0, sizeof(tctx->L));
+       tctx->L[0] = 0x01;
+       crypto_cipher_encrypt_one(tctx->blockcipher, tctx->L, tctx->L);
+
+       crypto_shash_clear_flags(tctx->polyval, CRYPTO_TFM_REQ_MASK);
+       crypto_shash_set_flags(tctx->polyval, crypto_skcipher_get_flags(tfm) &
+                              CRYPTO_TFM_REQ_MASK);
+       err = crypto_shash_setkey(tctx->polyval, hbar, BLOCKCIPHER_BLOCK_SIZE);
+       if (err)
+               return err;
+       memzero_explicit(hbar, sizeof(hbar));
+
+       return hctr2_hash_tweaklen(tctx, true) ?: hctr2_hash_tweaklen(tctx, false);
+}
+
+static int hctr2_hash_tweak(struct skcipher_request *req)
+{
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+       const struct hctr2_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
+       struct hctr2_request_ctx *rctx = skcipher_request_ctx(req);
+       struct shash_desc *hash_desc = &rctx->u.hash_desc;
+       int err;
+       bool has_remainder = req->cryptlen % POLYVAL_BLOCK_SIZE;
+
+       hash_desc->tfm = tctx->polyval;
+       err = crypto_shash_import(hash_desc, hctr2_hashed_tweaklen(tctx, has_remainder));
+       if (err)
+               return err;
+       err = crypto_shash_update(hash_desc, req->iv, TWEAK_SIZE);
+       if (err)
+               return err;
+
+       // Store the hashed tweak, since we need it when computing both
+       // H(T || N) and H(T || V).
+       return crypto_shash_export(hash_desc, hctr2_hashed_tweak(tctx, rctx));
+}
+
+static int hctr2_hash_message(struct skcipher_request *req,
+                             struct scatterlist *sgl,
+                             u8 digest[POLYVAL_DIGEST_SIZE])
+{
+       static const u8 padding[BLOCKCIPHER_BLOCK_SIZE] = { 0x1 };
+       struct hctr2_request_ctx *rctx = skcipher_request_ctx(req);
+       struct shash_desc *hash_desc = &rctx->u.hash_desc;
+       const unsigned int bulk_len = req->cryptlen - BLOCKCIPHER_BLOCK_SIZE;
+       struct sg_mapping_iter miter;
+       unsigned int remainder = bulk_len % BLOCKCIPHER_BLOCK_SIZE;
+       int i;
+       int err = 0;
+       int n = 0;
+
+       sg_miter_start(&miter, sgl, sg_nents(sgl),
+                      SG_MITER_FROM_SG | SG_MITER_ATOMIC);
+       for (i = 0; i < bulk_len; i += n) {
+               sg_miter_next(&miter);
+               n = min_t(unsigned int, miter.length, bulk_len - i);
+               err = crypto_shash_update(hash_desc, miter.addr, n);
+               if (err)
+                       break;
+       }
+       sg_miter_stop(&miter);
+
+       if (err)
+               return err;
+
+       if (remainder) {
+               err = crypto_shash_update(hash_desc, padding,
+                                         BLOCKCIPHER_BLOCK_SIZE - remainder);
+               if (err)
+                       return err;
+       }
+       return crypto_shash_final(hash_desc, digest);
+}
+
+static int hctr2_finish(struct skcipher_request *req)
+{
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+       const struct hctr2_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
+       struct hctr2_request_ctx *rctx = skcipher_request_ctx(req);
+       u8 digest[POLYVAL_DIGEST_SIZE];
+       struct shash_desc *hash_desc = &rctx->u.hash_desc;
+       int err;
+
+       // U = UU ^ H(T || V)
+       // or M = MM ^ H(T || N)
+       hash_desc->tfm = tctx->polyval;
+       err = crypto_shash_import(hash_desc, hctr2_hashed_tweak(tctx, rctx));
+       if (err)
+               return err;
+       err = hctr2_hash_message(req, rctx->bulk_part_dst, digest);
+       if (err)
+               return err;
+       crypto_xor(rctx->first_block, digest, BLOCKCIPHER_BLOCK_SIZE);
+
+       // Copy U (or M) into dst scatterlist
+       scatterwalk_map_and_copy(rctx->first_block, req->dst,
+                                0, BLOCKCIPHER_BLOCK_SIZE, 1);
+       return 0;
+}
+
+static void hctr2_xctr_done(struct crypto_async_request *areq,
+                                   int err)
+{
+       struct skcipher_request *req = areq->data;
+
+       if (!err)
+               err = hctr2_finish(req);
+
+       skcipher_request_complete(req, err);
+}
+
+static int hctr2_crypt(struct skcipher_request *req, bool enc)
+{
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+       const struct hctr2_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
+       struct hctr2_request_ctx *rctx = skcipher_request_ctx(req);
+       u8 digest[POLYVAL_DIGEST_SIZE];
+       int bulk_len = req->cryptlen - BLOCKCIPHER_BLOCK_SIZE;
+       int err;
+
+       // Requests must be at least one block
+       if (req->cryptlen < BLOCKCIPHER_BLOCK_SIZE)
+               return -EINVAL;
+
+       // Copy M (or U) into a temporary buffer
+       scatterwalk_map_and_copy(rctx->first_block, req->src,
+                                0, BLOCKCIPHER_BLOCK_SIZE, 0);
+
+       // Create scatterlists for N and V
+       rctx->bulk_part_src = scatterwalk_ffwd(rctx->sg_src, req->src,
+                                              BLOCKCIPHER_BLOCK_SIZE);
+       rctx->bulk_part_dst = scatterwalk_ffwd(rctx->sg_dst, req->dst,
+                                              BLOCKCIPHER_BLOCK_SIZE);
+
+       // MM = M ^ H(T || N)
+       // or UU = U ^ H(T || V)
+       err = hctr2_hash_tweak(req);
+       if (err)
+               return err;
+       err = hctr2_hash_message(req, rctx->bulk_part_src, digest);
+       if (err)
+               return err;
+       crypto_xor(digest, rctx->first_block, BLOCKCIPHER_BLOCK_SIZE);
+
+       // UU = E(MM)
+       // or MM = D(UU)
+       if (enc)
+               crypto_cipher_encrypt_one(tctx->blockcipher, rctx->first_block,
+                                         digest);
+       else
+               crypto_cipher_decrypt_one(tctx->blockcipher, rctx->first_block,
+                                         digest);
+
+       // S = MM ^ UU ^ L
+       crypto_xor(digest, rctx->first_block, BLOCKCIPHER_BLOCK_SIZE);
+       crypto_xor_cpy(rctx->xctr_iv, digest, tctx->L, BLOCKCIPHER_BLOCK_SIZE);
+
+       // V = XCTR(S, N)
+       // or N = XCTR(S, V)
+       skcipher_request_set_tfm(&rctx->u.xctr_req, tctx->xctr);
+       skcipher_request_set_crypt(&rctx->u.xctr_req, rctx->bulk_part_src,
+                                  rctx->bulk_part_dst, bulk_len,
+                                  rctx->xctr_iv);
+       skcipher_request_set_callback(&rctx->u.xctr_req,
+                                     req->base.flags,
+                                     hctr2_xctr_done, req);
+       return crypto_skcipher_encrypt(&rctx->u.xctr_req) ?:
+               hctr2_finish(req);
+}
+
+static int hctr2_encrypt(struct skcipher_request *req)
+{
+       return hctr2_crypt(req, true);
+}
+
+static int hctr2_decrypt(struct skcipher_request *req)
+{
+       return hctr2_crypt(req, false);
+}
+
+static int hctr2_init_tfm(struct crypto_skcipher *tfm)
+{
+       struct skcipher_instance *inst = skcipher_alg_instance(tfm);
+       struct hctr2_instance_ctx *ictx = skcipher_instance_ctx(inst);
+       struct hctr2_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
+       struct crypto_skcipher *xctr;
+       struct crypto_cipher *blockcipher;
+       struct crypto_shash *polyval;
+       unsigned int subreq_size;
+       int err;
+
+       xctr = crypto_spawn_skcipher(&ictx->xctr_spawn);
+       if (IS_ERR(xctr))
+               return PTR_ERR(xctr);
+
+       blockcipher = crypto_spawn_cipher(&ictx->blockcipher_spawn);
+       if (IS_ERR(blockcipher)) {
+               err = PTR_ERR(blockcipher);
+               goto err_free_xctr;
+       }
+
+       polyval = crypto_spawn_shash(&ictx->polyval_spawn);
+       if (IS_ERR(polyval)) {
+               err = PTR_ERR(polyval);
+               goto err_free_blockcipher;
+       }
+
+       tctx->xctr = xctr;
+       tctx->blockcipher = blockcipher;
+       tctx->polyval = polyval;
+
+       BUILD_BUG_ON(offsetofend(struct hctr2_request_ctx, u) !=
+                                sizeof(struct hctr2_request_ctx));
+       subreq_size = max(sizeof_field(struct hctr2_request_ctx, u.hash_desc) +
+                         crypto_shash_descsize(polyval),
+                         sizeof_field(struct hctr2_request_ctx, u.xctr_req) +
+                         crypto_skcipher_reqsize(xctr));
+
+       tctx->hashed_tweak_offset = offsetof(struct hctr2_request_ctx, u) +
+                                   subreq_size;
+       crypto_skcipher_set_reqsize(tfm, tctx->hashed_tweak_offset +
+                                   crypto_shash_statesize(polyval));
+       return 0;
+
+err_free_blockcipher:
+       crypto_free_cipher(blockcipher);
+err_free_xctr:
+       crypto_free_skcipher(xctr);
+       return err;
+}
+
+static void hctr2_exit_tfm(struct crypto_skcipher *tfm)
+{
+       struct hctr2_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
+
+       crypto_free_cipher(tctx->blockcipher);
+       crypto_free_skcipher(tctx->xctr);
+       crypto_free_shash(tctx->polyval);
+}
+
+static void hctr2_free_instance(struct skcipher_instance *inst)
+{
+       struct hctr2_instance_ctx *ictx = skcipher_instance_ctx(inst);
+
+       crypto_drop_cipher(&ictx->blockcipher_spawn);
+       crypto_drop_skcipher(&ictx->xctr_spawn);
+       crypto_drop_shash(&ictx->polyval_spawn);
+       kfree(inst);
+}
+
+static int hctr2_create_common(struct crypto_template *tmpl,
+                              struct rtattr **tb,
+                              const char *xctr_name,
+                              const char *polyval_name)
+{
+       u32 mask;
+       struct skcipher_instance *inst;
+       struct hctr2_instance_ctx *ictx;
+       struct skcipher_alg *xctr_alg;
+       struct crypto_alg *blockcipher_alg;
+       struct shash_alg *polyval_alg;
+       char blockcipher_name[CRYPTO_MAX_ALG_NAME];
+       int len;
+       int err;
+
+       err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SKCIPHER, &mask);
+       if (err)
+               return err;
+
+       inst = kzalloc(sizeof(*inst) + sizeof(*ictx), GFP_KERNEL);
+       if (!inst)
+               return -ENOMEM;
+       ictx = skcipher_instance_ctx(inst);
+
+       /* Stream cipher, xctr(block_cipher) */
+       err = crypto_grab_skcipher(&ictx->xctr_spawn,
+                                  skcipher_crypto_instance(inst),
+                                  xctr_name, 0, mask);
+       if (err)
+               goto err_free_inst;
+       xctr_alg = crypto_spawn_skcipher_alg(&ictx->xctr_spawn);
+
+       err = -EINVAL;
+       if (strncmp(xctr_alg->base.cra_name, "xctr(", 5))
+               goto err_free_inst;
+       len = strscpy(blockcipher_name, xctr_alg->base.cra_name + 5,
+                     sizeof(blockcipher_name));
+       if (len < 1)
+               goto err_free_inst;
+       if (blockcipher_name[len - 1] != ')')
+               goto err_free_inst;
+       blockcipher_name[len - 1] = 0;
+
+       /* Block cipher, e.g. "aes" */
+       err = crypto_grab_cipher(&ictx->blockcipher_spawn,
+                                skcipher_crypto_instance(inst),
+                                blockcipher_name, 0, mask);
+       if (err)
+               goto err_free_inst;
+       blockcipher_alg = crypto_spawn_cipher_alg(&ictx->blockcipher_spawn);
+
+       /* Require blocksize of 16 bytes */
+       err = -EINVAL;
+       if (blockcipher_alg->cra_blocksize != BLOCKCIPHER_BLOCK_SIZE)
+               goto err_free_inst;
+
+       /* Polyval ε-∆U hash function */
+       err = crypto_grab_shash(&ictx->polyval_spawn,
+                               skcipher_crypto_instance(inst),
+                               polyval_name, 0, mask);
+       if (err)
+               goto err_free_inst;
+       polyval_alg = crypto_spawn_shash_alg(&ictx->polyval_spawn);
+
+       /* Ensure Polyval is being used */
+       err = -EINVAL;
+       if (strcmp(polyval_alg->base.cra_name, "polyval") != 0)
+               goto err_free_inst;
+
+       /* Instance fields */
+
+       err = -ENAMETOOLONG;
+       if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, "hctr2(%s)",
+                    blockcipher_alg->cra_name) >= CRYPTO_MAX_ALG_NAME)
+               goto err_free_inst;
+       if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+                    "hctr2_base(%s,%s)",
+                    xctr_alg->base.cra_driver_name,
+                    polyval_alg->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
+               goto err_free_inst;
+
+       inst->alg.base.cra_blocksize = BLOCKCIPHER_BLOCK_SIZE;
+       inst->alg.base.cra_ctxsize = sizeof(struct hctr2_tfm_ctx) +
+                                    polyval_alg->statesize * 2;
+       inst->alg.base.cra_alignmask = xctr_alg->base.cra_alignmask |
+                                      polyval_alg->base.cra_alignmask;
+       /*
+        * The hash function is called twice, so it is weighted higher than the
+        * xctr and blockcipher.
+        */
+       inst->alg.base.cra_priority = (2 * xctr_alg->base.cra_priority +
+                                      4 * polyval_alg->base.cra_priority +
+                                      blockcipher_alg->cra_priority) / 7;
+
+       inst->alg.setkey = hctr2_setkey;
+       inst->alg.encrypt = hctr2_encrypt;
+       inst->alg.decrypt = hctr2_decrypt;
+       inst->alg.init = hctr2_init_tfm;
+       inst->alg.exit = hctr2_exit_tfm;
+       inst->alg.min_keysize = crypto_skcipher_alg_min_keysize(xctr_alg);
+       inst->alg.max_keysize = crypto_skcipher_alg_max_keysize(xctr_alg);
+       inst->alg.ivsize = TWEAK_SIZE;
+
+       inst->free = hctr2_free_instance;
+
+       err = skcipher_register_instance(tmpl, inst);
+       if (err) {
+err_free_inst:
+               hctr2_free_instance(inst);
+       }
+       return err;
+}
+
+static int hctr2_create_base(struct crypto_template *tmpl, struct rtattr **tb)
+{
+       const char *xctr_name;
+       const char *polyval_name;
+
+       xctr_name = crypto_attr_alg_name(tb[1]);
+       if (IS_ERR(xctr_name))
+               return PTR_ERR(xctr_name);
+
+       polyval_name = crypto_attr_alg_name(tb[2]);
+       if (IS_ERR(polyval_name))
+               return PTR_ERR(polyval_name);
+
+       return hctr2_create_common(tmpl, tb, xctr_name, polyval_name);
+}
+
+static int hctr2_create(struct crypto_template *tmpl, struct rtattr **tb)
+{
+       const char *blockcipher_name;
+       char xctr_name[CRYPTO_MAX_ALG_NAME];
+
+       blockcipher_name = crypto_attr_alg_name(tb[1]);
+       if (IS_ERR(blockcipher_name))
+               return PTR_ERR(blockcipher_name);
+
+       if (snprintf(xctr_name, CRYPTO_MAX_ALG_NAME, "xctr(%s)",
+                   blockcipher_name) >= CRYPTO_MAX_ALG_NAME)
+               return -ENAMETOOLONG;
+
+       return hctr2_create_common(tmpl, tb, xctr_name, "polyval");
+}
+
+static struct crypto_template hctr2_tmpls[] = {
+       {
+               /* hctr2_base(xctr_name, polyval_name) */
+               .name = "hctr2_base",
+               .create = hctr2_create_base,
+               .module = THIS_MODULE,
+       }, {
+               /* hctr2(blockcipher_name) */
+               .name = "hctr2",
+               .create = hctr2_create,
+               .module = THIS_MODULE,
+       }
+};
+
+static int __init hctr2_module_init(void)
+{
+       return crypto_register_templates(hctr2_tmpls, ARRAY_SIZE(hctr2_tmpls));
+}
+
+static void __exit hctr2_module_exit(void)
+{
+       return crypto_unregister_templates(hctr2_tmpls,
+                                          ARRAY_SIZE(hctr2_tmpls));
+}
+
+subsys_initcall(hctr2_module_init);
+module_exit(hctr2_module_exit);
+
+MODULE_DESCRIPTION("HCTR2 length-preserving encryption mode");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS_CRYPTO("hctr2");
+MODULE_IMPORT_NS(CRYPTO_INTERNAL);
diff --git a/crypto/polyval-generic.c b/crypto/polyval-generic.c
new file mode 100644 (file)
index 0000000..16bfa69
--- /dev/null
@@ -0,0 +1,245 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * POLYVAL: hash function for HCTR2.
+ *
+ * Copyright (c) 2007 Nokia Siemens Networks - Mikko Herranen <mh1@iki.fi>
+ * Copyright (c) 2009 Intel Corp.
+ *   Author: Huang Ying <ying.huang@intel.com>
+ * Copyright 2021 Google LLC
+ */
+
+/*
+ * Code based on crypto/ghash-generic.c
+ *
+ * POLYVAL is a keyed hash function similar to GHASH. POLYVAL uses a different
+ * modulus for finite field multiplication which makes hardware accelerated
+ * implementations on little-endian machines faster. POLYVAL is used in the
+ * kernel to implement HCTR2, but was originally specified for AES-GCM-SIV
+ * (RFC 8452).
+ *
+ * For more information see:
+ * Length-preserving encryption with HCTR2:
+ *   https://eprint.iacr.org/2021/1441.pdf
+ * AES-GCM-SIV: Nonce Misuse-Resistant Authenticated Encryption:
+ *   https://datatracker.ietf.org/doc/html/rfc8452
+ *
+ * Like GHASH, POLYVAL is not a cryptographic hash function and should
+ * not be used outside of crypto modes explicitly designed to use POLYVAL.
+ *
+ * This implementation uses a convenient trick involving the GHASH and POLYVAL
+ * fields. This trick allows multiplication in the POLYVAL field to be
+ * implemented by using multiplication in the GHASH field as a subroutine. An
+ * element of the POLYVAL field can be converted to an element of the GHASH
+ * field by computing x*REVERSE(a), where REVERSE reverses the byte-ordering of
+ * a. Similarly, an element of the GHASH field can be converted back to the
+ * POLYVAL field by computing REVERSE(x^{-1}*a). For more information, see:
+ * https://datatracker.ietf.org/doc/html/rfc8452#appendix-A
+ *
+ * By using this trick, we do not need to implement the POLYVAL field for the
+ * generic implementation.
+ *
+ * Warning: this generic implementation is not intended to be used in practice
+ * and is not constant time. For practical use, a hardware accelerated
+ * implementation of POLYVAL should be used instead.
+ *
+ */
+
+#include <asm/unaligned.h>
+#include <crypto/algapi.h>
+#include <crypto/gf128mul.h>
+#include <crypto/polyval.h>
+#include <crypto/internal/hash.h>
+#include <linux/crypto.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+struct polyval_tfm_ctx {
+       struct gf128mul_4k *gf128;
+};
+
+struct polyval_desc_ctx {
+       union {
+               u8 buffer[POLYVAL_BLOCK_SIZE];
+               be128 buffer128;
+       };
+       u32 bytes;
+};
+
+static void copy_and_reverse(u8 dst[POLYVAL_BLOCK_SIZE],
+                            const u8 src[POLYVAL_BLOCK_SIZE])
+{
+       u64 a = get_unaligned((const u64 *)&src[0]);
+       u64 b = get_unaligned((const u64 *)&src[8]);
+
+       put_unaligned(swab64(a), (u64 *)&dst[8]);
+       put_unaligned(swab64(b), (u64 *)&dst[0]);
+}
+
+/*
+ * Performs multiplication in the POLYVAL field using the GHASH field as a
+ * subroutine.  This function is used as a fallback for hardware accelerated
+ * implementations when simd registers are unavailable.
+ *
+ * Note: This function is not used for polyval-generic, instead we use the 4k
+ * lookup table implementation for finite field multiplication.
+ */
+void polyval_mul_non4k(u8 *op1, const u8 *op2)
+{
+       be128 a, b;
+
+       // Assume one argument is in Montgomery form and one is not.
+       copy_and_reverse((u8 *)&a, op1);
+       copy_and_reverse((u8 *)&b, op2);
+       gf128mul_x_lle(&a, &a);
+       gf128mul_lle(&a, &b);
+       copy_and_reverse(op1, (u8 *)&a);
+}
+EXPORT_SYMBOL_GPL(polyval_mul_non4k);
+
+/*
+ * Perform a POLYVAL update using non4k multiplication.  This function is used
+ * as a fallback for hardware accelerated implementations when simd registers
+ * are unavailable.
+ *
+ * Note: This function is not used for polyval-generic, instead we use the 4k
+ * lookup table implementation of finite field multiplication.
+ */
+void polyval_update_non4k(const u8 *key, const u8 *in,
+                         size_t nblocks, u8 *accumulator)
+{
+       while (nblocks--) {
+               crypto_xor(accumulator, in, POLYVAL_BLOCK_SIZE);
+               polyval_mul_non4k(accumulator, key);
+               in += POLYVAL_BLOCK_SIZE;
+       }
+}
+EXPORT_SYMBOL_GPL(polyval_update_non4k);
+
+static int polyval_setkey(struct crypto_shash *tfm,
+                         const u8 *key, unsigned int keylen)
+{
+       struct polyval_tfm_ctx *ctx = crypto_shash_ctx(tfm);
+       be128 k;
+
+       if (keylen != POLYVAL_BLOCK_SIZE)
+               return -EINVAL;
+
+       gf128mul_free_4k(ctx->gf128);
+
+       BUILD_BUG_ON(sizeof(k) != POLYVAL_BLOCK_SIZE);
+       copy_and_reverse((u8 *)&k, key);
+       gf128mul_x_lle(&k, &k);
+
+       ctx->gf128 = gf128mul_init_4k_lle(&k);
+       memzero_explicit(&k, POLYVAL_BLOCK_SIZE);
+
+       if (!ctx->gf128)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static int polyval_init(struct shash_desc *desc)
+{
+       struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);
+
+       memset(dctx, 0, sizeof(*dctx));
+
+       return 0;
+}
+
+static int polyval_update(struct shash_desc *desc,
+                        const u8 *src, unsigned int srclen)
+{
+       struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);
+       const struct polyval_tfm_ctx *ctx = crypto_shash_ctx(desc->tfm);
+       u8 *pos;
+       u8 tmp[POLYVAL_BLOCK_SIZE];
+       int n;
+
+       if (dctx->bytes) {
+               n = min(srclen, dctx->bytes);
+               pos = dctx->buffer + dctx->bytes - 1;
+
+               dctx->bytes -= n;
+               srclen -= n;
+
+               while (n--)
+                       *pos-- ^= *src++;
+
+               if (!dctx->bytes)
+                       gf128mul_4k_lle(&dctx->buffer128, ctx->gf128);
+       }
+
+       while (srclen >= POLYVAL_BLOCK_SIZE) {
+               copy_and_reverse(tmp, src);
+               crypto_xor(dctx->buffer, tmp, POLYVAL_BLOCK_SIZE);
+               gf128mul_4k_lle(&dctx->buffer128, ctx->gf128);
+               src += POLYVAL_BLOCK_SIZE;
+               srclen -= POLYVAL_BLOCK_SIZE;
+       }
+
+       if (srclen) {
+               dctx->bytes = POLYVAL_BLOCK_SIZE - srclen;
+               pos = dctx->buffer + POLYVAL_BLOCK_SIZE - 1;
+               while (srclen--)
+                       *pos-- ^= *src++;
+       }
+
+       return 0;
+}
+
+static int polyval_final(struct shash_desc *desc, u8 *dst)
+{
+       struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);
+       const struct polyval_tfm_ctx *ctx = crypto_shash_ctx(desc->tfm);
+
+       if (dctx->bytes)
+               gf128mul_4k_lle(&dctx->buffer128, ctx->gf128);
+       copy_and_reverse(dst, dctx->buffer);
+       return 0;
+}
+
+static void polyval_exit_tfm(struct crypto_tfm *tfm)
+{
+       struct polyval_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       gf128mul_free_4k(ctx->gf128);
+}
+
+static struct shash_alg polyval_alg = {
+       .digestsize     = POLYVAL_DIGEST_SIZE,
+       .init           = polyval_init,
+       .update         = polyval_update,
+       .final          = polyval_final,
+       .setkey         = polyval_setkey,
+       .descsize       = sizeof(struct polyval_desc_ctx),
+       .base           = {
+               .cra_name               = "polyval",
+               .cra_driver_name        = "polyval-generic",
+               .cra_priority           = 100,
+               .cra_blocksize          = POLYVAL_BLOCK_SIZE,
+               .cra_ctxsize            = sizeof(struct polyval_tfm_ctx),
+               .cra_module             = THIS_MODULE,
+               .cra_exit               = polyval_exit_tfm,
+       },
+};
+
+static int __init polyval_mod_init(void)
+{
+       return crypto_register_shash(&polyval_alg);
+}
+
+static void __exit polyval_mod_exit(void)
+{
+       crypto_unregister_shash(&polyval_alg);
+}
+
+subsys_initcall(polyval_mod_init);
+module_exit(polyval_mod_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("POLYVAL hash function");
+MODULE_ALIAS_CRYPTO("polyval");
+MODULE_ALIAS_CRYPTO("polyval-generic");
index 39e0417..0e555ee 100644 (file)
@@ -17,6 +17,11 @@ struct rsa_mpi_key {
        MPI n;
        MPI e;
        MPI d;
+       MPI p;
+       MPI q;
+       MPI dp;
+       MPI dq;
+       MPI qinv;
 };
 
 /*
@@ -35,16 +40,49 @@ static int _rsa_enc(const struct rsa_mpi_key *key, MPI c, MPI m)
 
 /*
  * RSADP function [RFC3447 sec 5.1.2]
- * m = c^d mod n;
+ * m_1 = c^dP mod p;
+ * m_2 = c^dQ mod q;
+ * h = (m_1 - m_2) * qInv mod p;
+ * m = m_2 + q * h;
  */
-static int _rsa_dec(const struct rsa_mpi_key *key, MPI m, MPI c)
+static int _rsa_dec_crt(const struct rsa_mpi_key *key, MPI m_or_m1_or_h, MPI c)
 {
+       MPI m2, m12_or_qh;
+       int ret = -ENOMEM;
+
        /* (1) Validate 0 <= c < n */
        if (mpi_cmp_ui(c, 0) < 0 || mpi_cmp(c, key->n) >= 0)
                return -EINVAL;
 
-       /* (2) m = c^d mod n */
-       return mpi_powm(m, c, key->d, key->n);
+       m2 = mpi_alloc(0);
+       m12_or_qh = mpi_alloc(0);
+       if (!m2 || !m12_or_qh)
+               goto err_free_mpi;
+
+       /* (2i) m_1 = c^dP mod p */
+       ret = mpi_powm(m_or_m1_or_h, c, key->dp, key->p);
+       if (ret)
+               goto err_free_mpi;
+
+       /* (2i) m_2 = c^dQ mod q */
+       ret = mpi_powm(m2, c, key->dq, key->q);
+       if (ret)
+               goto err_free_mpi;
+
+       /* (2iii) h = (m_1 - m_2) * qInv mod p */
+       mpi_sub(m12_or_qh, m_or_m1_or_h, m2);
+       mpi_mulm(m_or_m1_or_h, m12_or_qh, key->qinv, key->p);
+
+       /* (2iv) m = m_2 + q * h */
+       mpi_mul(m12_or_qh, key->q, m_or_m1_or_h);
+       mpi_addm(m_or_m1_or_h, m2, m12_or_qh, key->n);
+
+       ret = 0;
+
+err_free_mpi:
+       mpi_free(m12_or_qh);
+       mpi_free(m2);
+       return ret;
 }
 
 static inline struct rsa_mpi_key *rsa_get_key(struct crypto_akcipher *tfm)
@@ -112,7 +150,7 @@ static int rsa_dec(struct akcipher_request *req)
        if (!c)
                goto err_free_m;
 
-       ret = _rsa_dec(pkey, m, c);
+       ret = _rsa_dec_crt(pkey, m, c);
        if (ret)
                goto err_free_c;
 
@@ -134,9 +172,19 @@ static void rsa_free_mpi_key(struct rsa_mpi_key *key)
        mpi_free(key->d);
        mpi_free(key->e);
        mpi_free(key->n);
+       mpi_free(key->p);
+       mpi_free(key->q);
+       mpi_free(key->dp);
+       mpi_free(key->dq);
+       mpi_free(key->qinv);
        key->d = NULL;
        key->e = NULL;
        key->n = NULL;
+       key->p = NULL;
+       key->q = NULL;
+       key->dp = NULL;
+       key->dq = NULL;
+       key->qinv = NULL;
 }
 
 static int rsa_check_key_length(unsigned int len)
@@ -217,6 +265,26 @@ static int rsa_set_priv_key(struct crypto_akcipher *tfm, const void *key,
        if (!mpi_key->n)
                goto err;
 
+       mpi_key->p = mpi_read_raw_data(raw_key.p, raw_key.p_sz);
+       if (!mpi_key->p)
+               goto err;
+
+       mpi_key->q = mpi_read_raw_data(raw_key.q, raw_key.q_sz);
+       if (!mpi_key->q)
+               goto err;
+
+       mpi_key->dp = mpi_read_raw_data(raw_key.dp, raw_key.dp_sz);
+       if (!mpi_key->dp)
+               goto err;
+
+       mpi_key->dq = mpi_read_raw_data(raw_key.dq, raw_key.dq_sz);
+       if (!mpi_key->dq)
+               goto err;
+
+       mpi_key->qinv = mpi_read_raw_data(raw_key.qinv, raw_key.qinv_sz);
+       if (!mpi_key->qinv)
+               goto err;
+
        if (rsa_check_key_length(mpi_get_size(mpi_key->n) << 3)) {
                rsa_free_mpi_key(mpi_key);
                return -EINVAL;
index 2bacf83..59eb8ec 100644 (file)
@@ -58,7 +58,7 @@
  */
 static unsigned int sec;
 
-static char *alg = NULL;
+static char *alg;
 static u32 type;
 static u32 mask;
 static int mode;
@@ -71,7 +71,7 @@ static const char *check[] = {
        "blowfish", "twofish", "serpent", "sha384", "sha512", "md4", "aes",
        "cast6", "arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea",
        "khazad", "wp512", "wp384", "wp256", "xeta",  "fcrypt",
-       "camellia", "seed", "rmd160",
+       "camellia", "seed", "rmd160", "aria",
        "lzo", "lzo-rle", "cts", "sha3-224", "sha3-256", "sha3-384",
        "sha3-512", "streebog256", "streebog512",
        NULL
@@ -1556,6 +1556,7 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb)
                ret += tcrypt_test("rfc3686(ctr(aes))");
                ret += tcrypt_test("ofb(aes)");
                ret += tcrypt_test("cfb(aes)");
+               ret += tcrypt_test("xctr(aes)");
                break;
 
        case 11:
@@ -1669,10 +1670,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb)
                ret += tcrypt_test("rmd160");
                break;
 
-       case 41:
-               ret += tcrypt_test("blake2s-256");
-               break;
-
        case 42:
                ret += tcrypt_test("blake2b-512");
                break;
@@ -1729,6 +1726,14 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb)
                ret += tcrypt_test("ccm(sm4)");
                break;
 
+       case 57:
+               ret += tcrypt_test("polyval");
+               break;
+
+       case 58:
+               ret += tcrypt_test("gcm(aria)");
+               break;
+
        case 100:
                ret += tcrypt_test("hmac(md5)");
                break;
@@ -1865,6 +1870,12 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb)
                ret += tcrypt_test("cfb(sm4)");
                ret += tcrypt_test("ctr(sm4)");
                break;
+       case 192:
+               ret += tcrypt_test("ecb(aria)");
+               ret += tcrypt_test("cbc(aria)");
+               ret += tcrypt_test("cfb(aria)");
+               ret += tcrypt_test("ctr(aria)");
+               break;
        case 200:
                test_cipher_speed("ecb(aes)", ENCRYPT, sec, NULL, 0,
                                speed_template_16_24_32);
@@ -2186,6 +2197,37 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb)
                                   16, 16, aead_speed_template_19, num_mb);
                break;
 
+       case 226:
+               test_cipher_speed("hctr2(aes)", ENCRYPT, sec, NULL,
+                                 0, speed_template_32);
+               break;
+
+       case 227:
+               test_cipher_speed("ecb(aria)", ENCRYPT, sec, NULL, 0,
+                                 speed_template_16_24_32);
+               test_cipher_speed("ecb(aria)", DECRYPT, sec, NULL, 0,
+                                 speed_template_16_24_32);
+               test_cipher_speed("cbc(aria)", ENCRYPT, sec, NULL, 0,
+                                 speed_template_16_24_32);
+               test_cipher_speed("cbc(aria)", DECRYPT, sec, NULL, 0,
+                                 speed_template_16_24_32);
+               test_cipher_speed("cfb(aria)", ENCRYPT, sec, NULL, 0,
+                                 speed_template_16_24_32);
+               test_cipher_speed("cfb(aria)", DECRYPT, sec, NULL, 0,
+                                 speed_template_16_24_32);
+               test_cipher_speed("ctr(aria)", ENCRYPT, sec, NULL, 0,
+                                 speed_template_16_24_32);
+               test_cipher_speed("ctr(aria)", DECRYPT, sec, NULL, 0,
+                                 speed_template_16_24_32);
+               break;
+
+       case 228:
+               test_aead_speed("gcm(aria)", ENCRYPT, sec,
+                               NULL, 0, 16, 8, speed_template_16_24_32);
+               test_aead_speed("gcm(aria)", DECRYPT, sec,
+                               NULL, 0, 16, 8, speed_template_16_24_32);
+               break;
+
        case 300:
                if (alg) {
                        test_hash_speed(alg, sec, generic_hash_speed_template);
@@ -2240,10 +2282,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb)
                test_hash_speed("rmd160", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
                fallthrough;
-       case 316:
-               test_hash_speed("blake2s-256", sec, generic_hash_speed_template);
-               if (mode > 300 && mode < 400) break;
-               fallthrough;
        case 317:
                test_hash_speed("blake2b-512", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
@@ -2352,10 +2390,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb)
                test_ahash_speed("rmd160", sec, generic_hash_speed_template);
                if (mode > 400 && mode < 500) break;
                fallthrough;
-       case 416:
-               test_ahash_speed("blake2s-256", sec, generic_hash_speed_template);
-               if (mode > 400 && mode < 500) break;
-               fallthrough;
        case 417:
                test_ahash_speed("blake2b-512", sec, generic_hash_speed_template);
                if (mode > 400 && mode < 500) break;
index 5801a8f..5349ffe 100644 (file)
@@ -4376,30 +4376,6 @@ static const struct alg_test_desc alg_test_descs[] = {
                        .hash = __VECS(blake2b_512_tv_template)
                }
        }, {
-               .alg = "blake2s-128",
-               .test = alg_test_hash,
-               .suite = {
-                       .hash = __VECS(blakes2s_128_tv_template)
-               }
-       }, {
-               .alg = "blake2s-160",
-               .test = alg_test_hash,
-               .suite = {
-                       .hash = __VECS(blakes2s_160_tv_template)
-               }
-       }, {
-               .alg = "blake2s-224",
-               .test = alg_test_hash,
-               .suite = {
-                       .hash = __VECS(blakes2s_224_tv_template)
-               }
-       }, {
-               .alg = "blake2s-256",
-               .test = alg_test_hash,
-               .suite = {
-                       .hash = __VECS(blakes2s_256_tv_template)
-               }
-       }, {
                .alg = "cbc(aes)",
                .test = alg_test_skcipher,
                .fips_allowed = 1,
@@ -4413,6 +4389,12 @@ static const struct alg_test_desc alg_test_descs[] = {
                        .cipher = __VECS(anubis_cbc_tv_template)
                },
        }, {
+               .alg = "cbc(aria)",
+               .test = alg_test_skcipher,
+               .suite = {
+                       .cipher = __VECS(aria_cbc_tv_template)
+               },
+       }, {
                .alg = "cbc(blowfish)",
                .test = alg_test_skcipher,
                .suite = {
@@ -4530,6 +4512,12 @@ static const struct alg_test_desc alg_test_descs[] = {
                        .cipher = __VECS(aes_cfb_tv_template)
                },
        }, {
+               .alg = "cfb(aria)",
+               .test = alg_test_skcipher,
+               .suite = {
+                       .cipher = __VECS(aria_cfb_tv_template)
+               },
+       }, {
                .alg = "cfb(sm4)",
                .test = alg_test_skcipher,
                .suite = {
@@ -4599,6 +4587,12 @@ static const struct alg_test_desc alg_test_descs[] = {
                        .cipher = __VECS(aes_ctr_tv_template)
                }
        }, {
+               .alg = "ctr(aria)",
+               .test = alg_test_skcipher,
+               .suite = {
+                       .cipher = __VECS(aria_ctr_tv_template)
+               }
+       }, {
                .alg = "ctr(blowfish)",
                .test = alg_test_skcipher,
                .suite = {
@@ -4859,6 +4853,12 @@ static const struct alg_test_desc alg_test_descs[] = {
                        .cipher = __VECS(arc4_tv_template)
                }
        }, {
+               .alg = "ecb(aria)",
+               .test = alg_test_skcipher,
+               .suite = {
+                       .cipher = __VECS(aria_tv_template)
+               }
+       }, {
                .alg = "ecb(blowfish)",
                .test = alg_test_skcipher,
                .suite = {
@@ -5075,6 +5075,13 @@ static const struct alg_test_desc alg_test_descs[] = {
                        .aead = __VECS(aes_gcm_tv_template)
                }
        }, {
+               .alg = "gcm(aria)",
+               .generic_driver = "gcm_base(ctr(aria-generic),ghash-generic)",
+               .test = alg_test_aead,
+               .suite = {
+                       .aead = __VECS(aria_gcm_tv_template)
+               }
+       }, {
                .alg = "gcm(sm4)",
                .generic_driver = "gcm_base(ctr(sm4-generic),ghash-generic)",
                .test = alg_test_aead,
@@ -5089,6 +5096,14 @@ static const struct alg_test_desc alg_test_descs[] = {
                        .hash = __VECS(ghash_tv_template)
                }
        }, {
+               .alg = "hctr2(aes)",
+               .generic_driver =
+                   "hctr2_base(xctr(aes-generic),polyval-generic)",
+               .test = alg_test_skcipher,
+               .suite = {
+                       .cipher = __VECS(aes_hctr2_tv_template)
+               }
+       }, {
                .alg = "hmac(md5)",
                .test = alg_test_hash,
                .suite = {
@@ -5343,6 +5358,12 @@ static const struct alg_test_desc alg_test_descs[] = {
                        .hash = __VECS(poly1305_tv_template)
                }
        }, {
+               .alg = "polyval",
+               .test = alg_test_hash,
+               .suite = {
+                       .hash = __VECS(polyval_tv_template)
+               }
+       }, {
                .alg = "rfc3686(ctr(aes))",
                .test = alg_test_skcipher,
                .fips_allowed = 1,
@@ -5549,6 +5570,12 @@ static const struct alg_test_desc alg_test_descs[] = {
                        .cipher = __VECS(xchacha20_tv_template)
                },
        }, {
+               .alg = "xctr(aes)",
+               .test = alg_test_skcipher,
+               .suite = {
+                       .cipher = __VECS(aes_xctr_tv_template)
+               }
+       }, {
                .alg = "xts(aes)",
                .generic_driver = "xts(ecb(aes-generic))",
                .test = alg_test_skcipher,
index 4d7449f..d6088e2 100644 (file)
@@ -185,8 +185,8 @@ static const struct akcipher_testvec rsa_tv_template[] = {
        {
 #ifndef CONFIG_CRYPTO_FIPS
        .key =
-       "\x30\x81\x9A" /* sequence of 154 bytes */
-       "\x02\x01\x01" /* version - integer of 1 byte */
+       "\x30\x82\x01\x38" /* sequence of 312 bytes */
+       "\x02\x01\x00" /* version - integer of 1 byte */
        "\x02\x41" /* modulus - integer of 65 bytes */
        "\x00\xAA\x36\xAB\xCE\x88\xAC\xFD\xFF\x55\x52\x3C\x7F\xC4\x52\x3F"
        "\x90\xEF\xA0\x0D\xF3\x77\x4A\x25\x9F\x2E\x62\xB4\xC5\xD9\x9C\xB5"
@@ -199,24 +199,37 @@ static const struct akcipher_testvec rsa_tv_template[] = {
        "\xC2\xCD\x2D\xFF\x43\x40\x98\xCD\x20\xD8\xA1\x38\xD0\x90\xBF\x64"
        "\x79\x7C\x3F\xA7\xA2\xCD\xCB\x3C\xD1\xE0\xBD\xBA\x26\x54\xB4\xF9"
        "\xDF\x8E\x8A\xE5\x9D\x73\x3D\x9F\x33\xB3\x01\x62\x4A\xFD\x1D\x51"
-       "\x02\x01\x00" /* prime1 - integer of 1 byte */
-       "\x02\x01\x00" /* prime2 - integer of 1 byte */
-       "\x02\x01\x00" /* exponent1 - integer of 1 byte */
-       "\x02\x01\x00" /* exponent2 - integer of 1 byte */
-       "\x02\x01\x00", /* coefficient - integer of 1 byte */
+       "\x02\x21" /* prime1 - integer of 33 bytes */
+       "\x00\xD8\x40\xB4\x16\x66\xB4\x2E\x92\xEA\x0D\xA3\xB4\x32\x04\xB5"
+       "\xCF\xCE\x33\x52\x52\x4D\x04\x16\xA5\xA4\x41\xE7\x00\xAF\x46\x12"
+       "\x0D"
+       "\x02\x21" /* prime2 - integer of 33 bytes */
+       "\x00\xC9\x7F\xB1\xF0\x27\xF4\x53\xF6\x34\x12\x33\xEA\xAA\xD1\xD9"
+       "\x35\x3F\x6C\x42\xD0\x88\x66\xB1\xD0\x5A\x0F\x20\x35\x02\x8B\x9D"
+       "\x89"
+       "\x02\x20" /* exponent1 - integer of 32 bytes */
+       "\x59\x0B\x95\x72\xA2\xC2\xA9\xC4\x06\x05\x9D\xC2\xAB\x2F\x1D\xAF"
+       "\xEB\x7E\x8B\x4F\x10\xA7\x54\x9E\x8E\xED\xF5\xB4\xFC\xE0\x9E\x05"
+       "\x02\x21" /* exponent2 - integer of 33 bytes */
+       "\x00\x8E\x3C\x05\x21\xFE\x15\xE0\xEA\x06\xA3\x6F\xF0\xF1\x0C\x99"
+       "\x52\xC3\x5B\x7A\x75\x14\xFD\x32\x38\xB8\x0A\xAD\x52\x98\x62\x8D"
+       "\x51"
+       "\x02\x20" /* coefficient - integer of 32 bytes */
+       "\x36\x3F\xF7\x18\x9D\xA8\xE9\x0B\x1D\x34\x1F\x71\xD0\x9B\x76\xA8"
+       "\xA9\x43\xE1\x1D\x10\xB2\x4D\x24\x9F\x2D\xEA\xFE\xF8\x0C\x18\x26",
        .m = "\x54\x85\x9b\x34\x2c\x49\xea\x2a",
        .c =
        "\x63\x1c\xcd\x7b\xe1\x7e\xe4\xde\xc9\xa8\x89\xa1\x74\xcb\x3c\x63"
        "\x7d\x24\xec\x83\xc3\x15\xe4\x7f\x73\x05\x34\xd1\xec\x22\xbb\x8a"
        "\x5e\x32\x39\x6d\xc1\x1d\x7d\x50\x3b\x9f\x7a\xad\xf0\x2e\x25\x53"
        "\x9f\x6e\xbd\x4c\x55\x84\x0c\x9b\xcf\x1a\x4b\x51\x1e\x9e\x0c\x06",
-       .key_len = 157,
+       .key_len = 316,
        .m_size = 8,
        .c_size = 64,
        }, {
        .key =
-       "\x30\x82\x01\x1D" /* sequence of 285 bytes */
-       "\x02\x01\x01" /* version - integer of 1 byte */
+       "\x30\x82\x02\x5B" /* sequence of 603 bytes */
+       "\x02\x01\x00" /* version - integer of 1 byte */
        "\x02\x81\x81" /* modulus - integer of 129 bytes */
        "\x00\xBB\xF8\x2F\x09\x06\x82\xCE\x9C\x23\x38\xAC\x2B\x9D\xA8\x71"
        "\xF7\x36\x8D\x07\xEE\xD4\x10\x43\xA4\x40\xD6\xB6\xF0\x74\x54\xF5"
@@ -238,12 +251,35 @@ static const struct akcipher_testvec rsa_tv_template[] = {
        "\x93\x99\x26\xED\x4F\x74\xA1\x3E\xDD\xFB\xE1\xA1\xCE\xCC\x48\x94"
        "\xAF\x94\x28\xC2\xB7\xB8\x88\x3F\xE4\x46\x3A\x4B\xC8\x5B\x1C\xB3"
        "\xC1"
-       "\x02\x01\x00" /* prime1 - integer of 1 byte */
-       "\x02\x01\x00" /* prime2 - integer of 1 byte */
-       "\x02\x01\x00" /* exponent1 - integer of 1 byte */
-       "\x02\x01\x00" /* exponent2 - integer of 1 byte */
-       "\x02\x01\x00", /* coefficient - integer of 1 byte */
-       .key_len = 289,
+       "\x02\x41" /* prime1 - integer of 65 bytes */
+       "\x00\xEE\xCF\xAE\x81\xB1\xB9\xB3\xC9\x08\x81\x0B\x10\xA1\xB5\x60"
+       "\x01\x99\xEB\x9F\x44\xAE\xF4\xFD\xA4\x93\xB8\x1A\x9E\x3D\x84\xF6"
+       "\x32\x12\x4E\xF0\x23\x6E\x5D\x1E\x3B\x7E\x28\xFA\xE7\xAA\x04\x0A"
+       "\x2D\x5B\x25\x21\x76\x45\x9D\x1F\x39\x75\x41\xBA\x2A\x58\xFB\x65"
+       "\x99"
+       "\x02\x41" /* prime2 - integer of 65 bytes */
+       "\x00\xC9\x7F\xB1\xF0\x27\xF4\x53\xF6\x34\x12\x33\xEA\xAA\xD1\xD9"
+       "\x35\x3F\x6C\x42\xD0\x88\x66\xB1\xD0\x5A\x0F\x20\x35\x02\x8B\x9D"
+       "\x86\x98\x40\xB4\x16\x66\xB4\x2E\x92\xEA\x0D\xA3\xB4\x32\x04\xB5"
+       "\xCF\xCE\x33\x52\x52\x4D\x04\x16\xA5\xA4\x41\xE7\x00\xAF\x46\x15"
+       "\x03"
+       "\x02\x40" /* exponent1 - integer of 64 bytes */
+       "\x54\x49\x4C\xA6\x3E\xBA\x03\x37\xE4\xE2\x40\x23\xFC\xD6\x9A\x5A"
+       "\xEB\x07\xDD\xDC\x01\x83\xA4\xD0\xAC\x9B\x54\xB0\x51\xF2\xB1\x3E"
+       "\xD9\x49\x09\x75\xEA\xB7\x74\x14\xFF\x59\xC1\xF7\x69\x2E\x9A\x2E"
+       "\x20\x2B\x38\xFC\x91\x0A\x47\x41\x74\xAD\xC9\x3C\x1F\x67\xC9\x81"
+       "\x02\x40" /* exponent2 - integer of 64 bytes */
+       "\x47\x1E\x02\x90\xFF\x0A\xF0\x75\x03\x51\xB7\xF8\x78\x86\x4C\xA9"
+       "\x61\xAD\xBD\x3A\x8A\x7E\x99\x1C\x5C\x05\x56\xA9\x4C\x31\x46\xA7"
+       "\xF9\x80\x3F\x8F\x6F\x8A\xE3\x42\xE9\x31\xFD\x8A\xE4\x7A\x22\x0D"
+       "\x1B\x99\xA4\x95\x84\x98\x07\xFE\x39\xF9\x24\x5A\x98\x36\xDA\x3D"
+       "\x02\x41" /* coefficient - integer of 65 bytes */
+       "\x00\xB0\x6C\x4F\xDA\xBB\x63\x01\x19\x8D\x26\x5B\xDB\xAE\x94\x23"
+       "\xB3\x80\xF2\x71\xF7\x34\x53\x88\x50\x93\x07\x7F\xCD\x39\xE2\x11"
+       "\x9F\xC9\x86\x32\x15\x4F\x58\x83\xB1\x67\xA9\x67\xBF\x40\x2B\x4E"
+       "\x9E\x2E\x0F\x96\x56\xE6\x98\xEA\x36\x66\xED\xFB\x25\x79\x80\x39"
+       "\xF7",
+       .key_len = 607,
        .m = "\x54\x85\x9b\x34\x2c\x49\xea\x2a",
        .c =
        "\x74\x1b\x55\xac\x47\xb5\x08\x0a\x6e\x2b\x2d\xf7\x94\xb8\x8a\x95"
@@ -259,8 +295,8 @@ static const struct akcipher_testvec rsa_tv_template[] = {
        }, {
 #endif
        .key =
-       "\x30\x82\x02\x20" /* sequence of 544 bytes */
-       "\x02\x01\x01" /* version - integer of 1 byte */
+       "\x30\x82\x04\xA3" /* sequence of 1187 bytes */
+       "\x02\x01\x00" /* version - integer of 1 byte */
        "\x02\x82\x01\x01\x00" /* modulus - integer of 256 bytes */
        "\xDB\x10\x1A\xC2\xA3\xF1\xDC\xFF\x13\x6B\xED\x44\xDF\xF0\x02\x6D"
        "\x13\xC7\x88\xDA\x70\x6B\x54\xF1\xE8\x27\xDC\xC3\x0F\x99\x6A\xFA"
@@ -296,12 +332,55 @@ static const struct akcipher_testvec rsa_tv_template[] = {
        "\x62\xFF\xE9\x46\xB8\xD8\x44\xDB\xA5\xCC\x31\x54\x34\xCE\x3E\x82"
        "\xD6\xBF\x7A\x0B\x64\x21\x6D\x88\x7E\x5B\x45\x12\x1E\x63\x8D\x49"
        "\xA7\x1D\xD9\x1E\x06\xCD\xE8\xBA\x2C\x8C\x69\x32\xEA\xBE\x60\x71"
-       "\x02\x01\x00" /* prime1 - integer of 1 byte */
-       "\x02\x01\x00" /* prime2 - integer of 1 byte */
-       "\x02\x01\x00" /* exponent1 - integer of 1 byte */
-       "\x02\x01\x00" /* exponent2 - integer of 1 byte */
-       "\x02\x01\x00", /* coefficient - integer of 1 byte */
-       .key_len = 548,
+       "\x02\x81\x81" /* prime1 - integer of 129 bytes */
+       "\x00\xFA\xAC\xE1\x37\x5E\x32\x11\x34\xC6\x72\x58\x2D\x91\x06\x3E"
+       "\x77\xE7\x11\x21\xCD\x4A\xF8\xA4\x3F\x0F\xEF\x31\xE3\xF3\x55\xA0"
+       "\xB9\xAC\xB6\xCB\xBB\x41\xD0\x32\x81\x9A\x8F\x7A\x99\x30\x77\x6C"
+       "\x68\x27\xE2\x96\xB5\x72\xC9\xC3\xD4\x42\xAA\xAA\xCA\x95\x8F\xFF"
+       "\xC9\x9B\x52\x34\x30\x1D\xCF\xFE\xCF\x3C\x56\x68\x6E\xEF\xE7\x6C"
+       "\xD7\xFB\x99\xF5\x4A\xA5\x21\x1F\x2B\xEA\x93\xE8\x98\x26\xC4\x6E"
+       "\x42\x21\x5E\xA0\xA1\x2A\x58\x35\xBB\x10\xE7\xBA\x27\x0A\x3B\xB3"
+       "\xAF\xE2\x75\x36\x04\xAC\x56\xA0\xAB\x52\xDE\xCE\xDD\x2C\x28\x77"
+       "\x03"
+       "\x02\x81\x81" /* prime2 - integer of 129 bytes */
+       "\x00\xDF\xB7\x52\xB6\xD7\xC0\xE2\x96\xE7\xC9\xFE\x5D\x71\x5A\xC4"
+       "\x40\x96\x2F\xE5\x87\xEA\xF3\xA5\x77\x11\x67\x3C\x8D\x56\x08\xA7"
+       "\xB5\x67\xFA\x37\xA8\xB8\xCF\x61\xE8\x63\xD8\x38\x06\x21\x2B\x92"
+       "\x09\xA6\x39\x3A\xEA\xA8\xB4\x45\x4B\x36\x10\x4C\xE4\x00\x66\x71"
+       "\x65\xF8\x0B\x94\x59\x4F\x8C\xFD\xD5\x34\xA2\xE7\x62\x84\x0A\xA7"
+       "\xBB\xDB\xD9\x8A\xCD\x05\xE1\xCC\x57\x7B\xF1\xF1\x1F\x11\x9D\xBA"
+       "\x3E\x45\x18\x99\x1B\x41\x64\x43\xEE\x97\x5D\x77\x13\x5B\x74\x69"
+       "\x73\x87\x95\x05\x07\xBE\x45\x07\x17\x7E\x4A\x69\x22\xF3\xDB\x05"
+       "\x39"
+       "\x02\x81\x80" /* exponent1 - integer of 128 bytes */
+       "\x5E\xD8\xDC\xDA\x53\x44\xC4\x67\xE0\x92\x51\x34\xE4\x83\xA5\x4D"
+       "\x3E\xDB\xA7\x9B\x82\xBB\x73\x81\xFC\xE8\x77\x4B\x15\xBE\x17\x73"
+       "\x49\x9B\x5C\x98\xBC\xBD\x26\xEF\x0C\xE9\x2E\xED\x19\x7E\x86\x41"
+       "\x1E\x9E\x48\x81\xDD\x2D\xE4\x6F\xC2\xCD\xCA\x93\x9E\x65\x7E\xD5"
+       "\xEC\x73\xFD\x15\x1B\xA2\xA0\x7A\x0F\x0D\x6E\xB4\x53\x07\x90\x92"
+       "\x64\x3B\x8B\xA9\x33\xB3\xC5\x94\x9B\x4C\x5D\x9C\x7C\x46\xA4\xA5"
+       "\x56\xF4\xF3\xF8\x27\x0A\x7B\x42\x0D\x92\x70\x47\xE7\x42\x51\xA9"
+       "\xC2\x18\xB1\x58\xB1\x50\x91\xB8\x61\x41\xB6\xA9\xCE\xD4\x7C\xBB"
+       "\x02\x81\x80" /* exponent2 - integer of 128 bytes */
+       "\x54\x09\x1F\x0F\x03\xD8\xB6\xC5\x0C\xE8\xB9\x9E\x0C\x38\x96\x43"
+       "\xD4\xA6\xC5\x47\xDB\x20\x0E\xE5\xBD\x29\xD4\x7B\x1A\xF8\x41\x57"
+       "\x49\x69\x9A\x82\xCC\x79\x4A\x43\xEB\x4D\x8B\x2D\xF2\x43\xD5\xA5"
+       "\xBE\x44\xFD\x36\xAC\x8C\x9B\x02\xF7\x9A\x03\xE8\x19\xA6\x61\xAE"
+       "\x76\x10\x93\x77\x41\x04\xAB\x4C\xED\x6A\xCC\x14\x1B\x99\x8D\x0C"
+       "\x6A\x37\x3B\x86\x6C\x51\x37\x5B\x1D\x79\xF2\xA3\x43\x10\xC6\xA7"
+       "\x21\x79\x6D\xF9\xE9\x04\x6A\xE8\x32\xFF\xAE\xFD\x1C\x7B\x8C\x29"
+       "\x13\xA3\x0C\xB2\xAD\xEC\x6C\x0F\x8D\x27\x12\x7B\x48\xB2\xDB\x31"
+       "\x02\x81\x81" /* coefficient - integer of 129 bytes */
+       "\x00\x8D\x1B\x05\xCA\x24\x1F\x0C\x53\x19\x52\x74\x63\x21\xFA\x78"
+       "\x46\x79\xAF\x5C\xDE\x30\xA4\x6C\x20\x38\xE6\x97\x39\xB8\x7A\x70"
+       "\x0D\x8B\x6C\x6D\x13\x74\xD5\x1C\xDE\xA9\xF4\x60\x37\xFE\x68\x77"
+       "\x5E\x0B\x4E\x5E\x03\x31\x30\xDF\xD6\xAE\x85\xD0\x81\xBB\x61\xC7"
+       "\xB1\x04\x5A\xC4\x6D\x56\x1C\xD9\x64\xE7\x85\x7F\x88\x91\xC9\x60"
+       "\x28\x05\xE2\xC6\x24\x8F\xDD\x61\x64\xD8\x09\xDE\x7E\xD3\x4A\x61"
+       "\x1A\xD3\x73\x58\x4B\xD8\xA0\x54\x25\x48\x83\x6F\x82\x6C\xAF\x36"
+       "\x51\x2A\x5D\x14\x2F\x41\x25\x00\xDD\xF8\xF3\x95\xFE\x31\x25\x50"
+       "\x12",
+       .key_len = 1191,
        .m = "\x54\x85\x9b\x34\x2c\x49\xea\x2a",
        .c =
        "\xb2\x97\x76\xb4\xae\x3e\x38\x3c\x7e\x64\x1f\xcc\xa2\x7f\xf6\xbe"
@@ -1152,7 +1231,7 @@ static const struct akcipher_testvec ecrdsa_tv_template[] = {
 static const struct akcipher_testvec pkcs1pad_rsa_tv_template[] = {
        {
        .key =
-       "\x30\x82\x03\x1f\x02\x01\x00\x02\x82\x01\x01\x00\xd7\x1e\x77\x82"
+       "\x30\x82\x04\xa5\x02\x01\x00\x02\x82\x01\x01\x00\xd7\x1e\x77\x82"
        "\x8c\x92\x31\xe7\x69\x02\xa2\xd5\x5c\x78\xde\xa2\x0c\x8f\xfe\x28"
        "\x59\x31\xdf\x40\x9c\x60\x61\x06\xb9\x2f\x62\x40\x80\x76\xcb\x67"
        "\x4a\xb5\x59\x56\x69\x17\x07\xfa\xf9\x4c\xbd\x6c\x37\x7a\x46\x7d"
@@ -1168,42 +1247,66 @@ static const struct akcipher_testvec pkcs1pad_rsa_tv_template[] = {
        "\x9e\x49\x63\x6e\x02\xc1\xc9\x3a\x9b\xa5\x22\x1b\x07\x95\xd6\x10"
        "\x02\x50\xfd\xfd\xd1\x9b\xbe\xab\xc2\xc0\x74\xd7\xec\x00\xfb\x11"
        "\x71\xcb\x7a\xdc\x81\x79\x9f\x86\x68\x46\x63\x82\x4d\xb7\xf1\xe6"
-       "\x16\x6f\x42\x63\xf4\x94\xa0\xca\x33\xcc\x75\x13\x02\x82\x01\x00"
-       "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-       "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-       "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-       "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-       "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-       "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-       "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-       "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-       "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-       "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-       "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-       "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-       "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-       "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-       "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-       "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01"
-       "\x02\x82\x01\x00\x62\xb5\x60\x31\x4f\x3f\x66\x16\xc1\x60\xac\x47"
-       "\x2a\xff\x6b\x69\x00\x4a\xb2\x5c\xe1\x50\xb9\x18\x74\xa8\xe4\xdc"
-       "\xa8\xec\xcd\x30\xbb\xc1\xc6\xe3\xc6\xac\x20\x2a\x3e\x5e\x8b\x12"
-       "\xe6\x82\x08\x09\x38\x0b\xab\x7c\xb3\xcc\x9c\xce\x97\x67\xdd\xef"
-       "\x95\x40\x4e\x92\xe2\x44\xe9\x1d\xc1\x14\xfd\xa9\xb1\xdc\x71\x9c"
-       "\x46\x21\xbd\x58\x88\x6e\x22\x15\x56\xc1\xef\xe0\xc9\x8d\xe5\x80"
-       "\x3e\xda\x7e\x93\x0f\x52\xf6\xf5\xc1\x91\x90\x9e\x42\x49\x4f\x8d"
-       "\x9c\xba\x38\x83\xe9\x33\xc2\x50\x4f\xec\xc2\xf0\xa8\xb7\x6e\x28"
-       "\x25\x56\x6b\x62\x67\xfe\x08\xf1\x56\xe5\x6f\x0e\x99\xf1\xe5\x95"
-       "\x7b\xef\xeb\x0a\x2c\x92\x97\x57\x23\x33\x36\x07\xdd\xfb\xae\xf1"
-       "\xb1\xd8\x33\xb7\x96\x71\x42\x36\xc5\xa4\xa9\x19\x4b\x1b\x52\x4c"
-       "\x50\x69\x91\xf0\x0e\xfa\x80\x37\x4b\xb5\xd0\x2f\xb7\x44\x0d\xd4"
-       "\xf8\x39\x8d\xab\x71\x67\x59\x05\x88\x3d\xeb\x48\x48\x33\x88\x4e"
-       "\xfe\xf8\x27\x1b\xd6\x55\x60\x5e\x48\xb7\x6d\x9a\xa8\x37\xf9\x7a"
-       "\xde\x1b\xcd\x5d\x1a\x30\xd4\xe9\x9e\x5b\x3c\x15\xf8\x9c\x1f\xda"
-       "\xd1\x86\x48\x55\xce\x83\xee\x8e\x51\xc7\xde\x32\x12\x47\x7d\x46"
-       "\xb8\x35\xdf\x41\x02\x01\x00\x02\x01\x00\x02\x01\x00\x02\x01\x00"
-       "\x02\x01\x00",
-       .key_len = 803,
+       "\x16\x6f\x42\x63\xf4\x94\xa0\xca\x33\xcc\x75\x13\x02\x03\x01\x00"
+       "\x01\x02\x82\x01\x00\x62\xb5\x60\x31\x4f\x3f\x66\x16\xc1\x60\xac"
+       "\x47\x2a\xff\x6b\x69\x00\x4a\xb2\x5c\xe1\x50\xb9\x18\x74\xa8\xe4"
+       "\xdc\xa8\xec\xcd\x30\xbb\xc1\xc6\xe3\xc6\xac\x20\x2a\x3e\x5e\x8b"
+       "\x12\xe6\x82\x08\x09\x38\x0b\xab\x7c\xb3\xcc\x9c\xce\x97\x67\xdd"
+       "\xef\x95\x40\x4e\x92\xe2\x44\xe9\x1d\xc1\x14\xfd\xa9\xb1\xdc\x71"
+       "\x9c\x46\x21\xbd\x58\x88\x6e\x22\x15\x56\xc1\xef\xe0\xc9\x8d\xe5"
+       "\x80\x3e\xda\x7e\x93\x0f\x52\xf6\xf5\xc1\x91\x90\x9e\x42\x49\x4f"
+       "\x8d\x9c\xba\x38\x83\xe9\x33\xc2\x50\x4f\xec\xc2\xf0\xa8\xb7\x6e"
+       "\x28\x25\x56\x6b\x62\x67\xfe\x08\xf1\x56\xe5\x6f\x0e\x99\xf1\xe5"
+       "\x95\x7b\xef\xeb\x0a\x2c\x92\x97\x57\x23\x33\x36\x07\xdd\xfb\xae"
+       "\xf1\xb1\xd8\x33\xb7\x96\x71\x42\x36\xc5\xa4\xa9\x19\x4b\x1b\x52"
+       "\x4c\x50\x69\x91\xf0\x0e\xfa\x80\x37\x4b\xb5\xd0\x2f\xb7\x44\x0d"
+       "\xd4\xf8\x39\x8d\xab\x71\x67\x59\x05\x88\x3d\xeb\x48\x48\x33\x88"
+       "\x4e\xfe\xf8\x27\x1b\xd6\x55\x60\x5e\x48\xb7\x6d\x9a\xa8\x37\xf9"
+       "\x7a\xde\x1b\xcd\x5d\x1a\x30\xd4\xe9\x9e\x5b\x3c\x15\xf8\x9c\x1f"
+       "\xda\xd1\x86\x48\x55\xce\x83\xee\x8e\x51\xc7\xde\x32\x12\x47\x7d"
+       "\x46\xb8\x35\xdf\x41\x02\x81\x81\x00\xe4\x4c\xae\xde\x16\xfd\x9f"
+       "\x83\x55\x5b\x84\x4a\xcf\x1c\xf1\x37\x95\xad\xca\x29\x7f\x2d\x6e"
+       "\x32\x81\xa4\x2b\x26\x14\x96\x1d\x40\x05\xec\x0c\xaf\x3f\x2c\x6f"
+       "\x2c\xe8\xbf\x1d\xee\xd0\xb3\xef\x7c\x5b\x9e\x88\x4f\x2a\x8b\x0e"
+       "\x4a\xbd\xb7\x8c\xfa\x10\x0e\x3b\xda\x68\xad\x41\x2b\xe4\x96\xfa"
+       "\x7f\x80\x52\x5f\x07\x9f\x0e\x3b\x5e\x96\x45\x1a\x13\x2b\x94\xce"
+       "\x1f\x07\x69\x85\x35\xfc\x69\x63\x5b\xf8\xf8\x3f\xce\x9d\x40\x1e"
+       "\x7c\xad\xfb\x9e\xce\xe0\x01\xf8\xef\x59\x5d\xdc\x00\x79\xab\x8a"
+       "\x3f\x80\xa2\x76\x32\x94\xa9\xea\x65\x02\x81\x81\x00\xf1\x38\x60"
+       "\x90\x0d\x0c\x2e\x3d\x34\xe5\x90\xea\x21\x43\x1f\x68\x63\x16\x7b"
+       "\x25\x8d\xde\x82\x2b\x52\xf8\xa3\xfd\x0f\x39\xe7\xe9\x5e\x32\x75"
+       "\x15\x7d\xd0\xc9\xce\x06\xe5\xfb\xa9\xcb\x22\xe5\xdb\x49\x09\xf2"
+       "\xe6\xb7\xa5\xa7\x75\x2e\x91\x2d\x2b\x5d\xf1\x48\x61\x45\x43\xd7"
+       "\xbd\xfc\x11\x73\xb5\x11\x9f\xb2\x18\x3a\x6f\x36\xa7\xc2\xd3\x18"
+       "\x4d\xf0\xc5\x1f\x70\x8c\x9b\xc5\x1d\x95\xa8\x5a\x9e\x8c\xb1\x4b"
+       "\x6a\x2a\x84\x76\x2c\xd8\x4f\x47\xb0\x81\x84\x02\x45\xf0\x85\xf8"
+       "\x0c\x6d\xa7\x0c\x4d\x2c\xb2\x5b\x81\x70\xfd\x6e\x17\x02\x81\x81"
+       "\x00\x8d\x07\xc5\xfa\x92\x4f\x48\xcb\xd3\xdd\xfe\x02\x4c\xa1\x7f"
+       "\x6d\xab\xfc\x38\xe7\x9b\x95\xcf\xfe\x49\x51\xc6\x09\xf7\x2b\xa8"
+       "\x94\x15\x54\x75\x9d\x88\xb4\x05\x55\xc3\xcd\xd4\x4a\xe4\x08\x53"
+       "\xc8\x09\xbd\x0c\x4d\x83\x65\x75\x85\xbc\x5e\xf8\x2a\xbd\xe2\x5d"
+       "\x1d\x16\x0e\xf9\x34\x89\x38\xaf\x34\x36\x6c\x2c\x22\x44\x22\x81"
+       "\x90\x73\xd9\xea\x3a\xaf\x70\x74\x48\x7c\xc6\xb5\xb0\xdc\xe5\xa9"
+       "\xa8\x76\x4b\xbc\xf7\x00\xf3\x4c\x22\x0f\x44\x62\x1d\x40\x0a\x57"
+       "\xe2\x5b\xdd\x7c\x7b\x9a\xad\xda\x70\x52\x21\x8a\x4c\xc2\xc3\x98"
+       "\x75\x02\x81\x81\x00\xed\x24\x5c\xa2\x21\x81\xa1\x0f\xa1\x2a\x33"
+       "\x0e\x49\xc7\x00\x60\x92\x51\x6e\x9d\x9b\xdc\x6d\x22\x04\x7e\xd6"
+       "\x51\x19\x9f\xf6\xe3\x91\x2c\x8f\xb8\xa2\x29\x19\xcc\x47\x31\xdf"
+       "\xf8\xab\xf0\xd2\x02\x83\xca\x99\x16\xc2\xe2\xc3\x3f\x4b\x99\x83"
+       "\xcb\x87\x9e\x86\x66\xc2\x3e\x91\x21\x80\x66\xf3\xd6\xc5\xcd\xb6"
+       "\xbb\x64\xef\x22\xcf\x48\x94\x58\xe7\x7e\xd5\x7c\x34\x1c\xb7\xa2"
+       "\xd0\x93\xe9\x9f\xb5\x11\x61\xd7\x5f\x37\x0f\x64\x52\x70\x11\x78"
+       "\xcc\x08\x77\xeb\xf8\x30\x1e\xb4\x9e\x1b\x4a\xc7\xa8\x33\x51\xe0"
+       "\xed\xdf\x53\xf6\xdf\x02\x81\x81\x00\x86\xd9\x4c\xee\x65\x61\xc1"
+       "\x19\xa9\xd5\x74\x9b\xd5\xca\xf6\x83\x2b\x06\xb4\x20\xfe\x45\x29"
+       "\xe8\xe3\xfa\xe1\x4f\x28\x8e\x63\x2f\x74\xc3\x3a\x5c\x9a\xf5\x9e"
+       "\x0e\x0d\xc5\xfe\xa0\x4c\x00\xce\x7b\xa4\x19\x17\x59\xaf\x13\x3a"
+       "\x03\x8f\x54\xf5\x60\x39\x2e\xd9\x06\xb3\x7c\xd6\x90\x06\x41\x77"
+       "\xf3\x93\xe1\x7a\x01\x41\xc1\x8f\xfe\x4c\x88\x39\xdb\xde\x71\x9e"
+       "\x58\xd1\x49\x50\x80\xb2\x5a\x4f\x69\x8b\xb8\xfe\x63\xd4\x42\x3d"
+       "\x37\x61\xa8\x4c\xff\xb6\x99\x4c\xf4\x51\xe0\x44\xaa\x69\x79\x3f"
+       "\x81\xa4\x61\x3d\x26\xe9\x04\x52\x64",
+       .key_len = 1193,
        /*
         * m is SHA256 hash of following message:
         * "\x49\x41\xbe\x0a\x0c\xc9\xf6\x35\x51\xe4\x27\x56\x13\x71\x4b\xd0"
@@ -26457,6 +26560,2866 @@ static const struct cipher_testvec seed_tv_template[] = {
        }
 };
 
+/*
+ * ARIA test vectors
+ */
+static const struct cipher_testvec aria_tv_template[] = {
+       {
+               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+               .klen   = 16,
+               .ptext  = "\x00\x11\x22\x33\x44\x55\x66\x77"
+                         "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+               .ctext  = "\xd7\x18\xfb\xd6\xab\x64\x4c\x73"
+                         "\x9d\xa9\x5f\x3b\xe6\x45\x17\x78",
+               .len    = 16,
+       }, {
+               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17",
+               .klen   = 24,
+               .ptext  = "\x00\x11\x22\x33\x44\x55\x66\x77"
+                         "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+               .ctext  = "\x26\x44\x9c\x18\x05\xdb\xe7\xaa"
+                         "\x25\xa4\x68\xce\x26\x3a\x9e\x79",
+               .len    = 16,
+       }, {
+               .key    = "\x00\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",
+               .klen   = 32,
+               .ptext  = "\x00\x11\x22\x33\x44\x55\x66\x77"
+                         "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+               .ctext  = "\xf9\x2b\xd7\xc7\x9f\xb7\x2e\x2f"
+                         "\x2b\x8f\x80\xc1\x97\x2d\x24\xfc",
+               .len    = 16,
+       }
+};
+
+static const struct cipher_testvec aria_cbc_tv_template[] = {
+       {
+               .key    = "\x7c\x95\x0d\x07\xe6\x14\x98\x92"
+                         "\x07\xac\x22\x41\x4d\x23\x27\x37",
+               .klen   = 16,
+               .iv     = "\x9d\xd5\x62\xce\x3d\x07\xd9\x89"
+                         "\xf2\x78\x19\x4b\x65\x39\xc3\xc6",
+               .ptext  = "\xcb\xbf\x47\x35\xc5\x37\xf0\x4e"
+                         "\x85\x19\x21\x72\x33\x00\xde\x28",
+               .ctext  = "\xf4\x80\x89\x89\x4a\x37\xda\x98"
+                         "\x80\x52\x74\x75\xd9\xef\x58\xff",
+               .len    = 16,
+       }, {
+               .key    = "\x8f\xb9\x8d\xc9\xd7\x99\xfe\x7d"
+                         "\xeb\x14\xaa\x65\xaf\x8c\x38\x1a",
+               .klen   = 16,
+               .iv     = "\xb1\x67\x46\x57\x0c\x64\x65\xf2"
+                         "\x8c\x2f\x65\x11\x12\x33\xd4\x9a",
+               .ptext  = "\x3a\xaf\xc1\xeb\x3c\x0c\xc5\xcc"
+                         "\x10\x6e\x45\xa1\xd6\x89\xf1\xe5"
+                         "\x74\xb6\x90\xd3\x81\x45\x00\x66"
+                         "\x62\x15\x78\x84\xb2\x63\x11\x76",
+               .ctext  = "\x3d\x7d\x3a\xeb\x23\x85\x3e\x72"
+                         "\x12\x45\xbb\x5b\x42\x99\xec\xa0"
+                         "\xa2\xbe\x75\xd6\xb1\xd8\xea\x6f"
+                         "\x97\xfe\xfd\xcc\xfc\x08\x38\x00",
+               .len    = 32,
+       }, {
+               .key    = "\xe8\xe0\x85\x9c\x33\x06\x36\x5f"
+                         "\xa9\xab\x72\x66\xa1\xd7\xf5\x0d",
+               .klen   = 16,
+               .iv     = "\x5d\xd3\xaf\x13\xed\x82\xc8\x92"
+                         "\x4f\xf4\xe2\x35\xdb\x39\x9e\xa5",
+               .ptext  = "\xdf\x73\x61\x44\x86\x2f\x58\x1e"
+                         "\xfe\xf6\xb9\x1d\xd9\x1e\x4c\x7c"
+                         "\xb4\xe6\x2b\x7d\x17\xc3\xc6\x5f"
+                         "\x9d\xf4\x29\x8a\x55\x5c\x82\x0e"
+                         "\x67\x91\xdd\x4b\xfb\x31\x33\xf1"
+                         "\x56\x75\xa3\x2c\x46\x08\xff\x18",
+               .ctext  = "\x85\x07\x8c\x88\x70\x7b\x39\xb8"
+                         "\xfd\x1d\xa1\xd0\x89\x5f\x3f\x85"
+                         "\x18\x5a\xde\x64\xbd\x54\xd5\x67"
+                         "\xd1\x27\x4c\x98\x82\x76\xea\x22"
+                         "\x52\x98\x79\xb4\x1d\xe8\x16\xd0"
+                         "\xc6\xea\xf7\xbb\x38\x89\xf2\x5d",
+               .len    = 48,
+       }, {
+               .key    = "\xc1\x19\x8a\x7b\xc9\xaf\x00\xb3"
+                         "\x92\x3c\xd7\xed\xe7\x76\xc5\x98",
+               .klen   = 16,
+               .iv     = "\xca\x62\x82\x1a\x5b\xb1\xcf\xc1"
+                         "\xfb\x50\xb7\xfc\xb0\x3b\x15\xcb",
+               .ptext  = "\xcb\x92\x56\x74\xc9\xee\x80\x78"
+                         "\x78\xf5\x73\xc5\x5b\x2c\x70\x2d"
+                         "\x4e\x0d\xd7\x17\x6d\x5a\x35\x74"
+                         "\x33\xb0\x7d\xf5\xdf\x5f\x96\x7b"
+                         "\x1c\x79\x16\xd0\xe0\x29\x4e\x94"
+                         "\x95\x46\x86\x7a\x77\x28\x89\xb4"
+                         "\x3d\xbb\x65\xab\xfb\xd1\x6c\xf4"
+                         "\x47\xbd\x7e\x7f\x9b\x1d\x8b\x12",
+               .ctext  = "\x69\xd2\x56\xdf\xa8\x1a\x97\xbd"
+                         "\x69\xb5\xbb\x6b\x29\x1d\x5f\x0f"
+                         "\xdf\x5f\x63\xc0\x83\x0b\xd7\xb1"
+                         "\x31\x2d\xbf\x73\xe1\xe5\x5d\x0e"
+                         "\x0c\x8d\xc4\x8a\xa9\xbd\x5f\xc7"
+                         "\xb5\x61\xa0\x2b\x90\x64\x1a\xde"
+                         "\xd2\xe1\x61\xb9\xce\xf4\x0b\x1c"
+                         "\x9c\x43\x69\x6d\xb2\x32\x98\x44",
+               .len    = 64,
+       }, {
+               .key    = "\xfa\xf7\x53\xf6\xd6\x08\x70\xf1"
+                         "\x32\x58\x97\x74\x04\x12\x1b\x14",
+               .klen   = 16,
+               .iv     = "\xdd\x93\xb2\x3e\xcb\xc1\x7c\x27"
+                         "\x7f\x9e\x41\x03\xab\x1d\xfb\x77",
+               .ptext  = "\xae\x34\x94\x50\x73\x32\xf0\x75"
+                         "\x96\x53\x2e\x1a\xc9\x91\x2b\x37"
+                         "\x77\xbe\x48\x39\xa7\xd0\x6e\xf7"
+                         "\x22\x7c\x4f\xe7\xd8\x06\xee\x92"
+                         "\x80\x57\x61\x45\x7f\x50\xd5\x0a"
+                         "\x0b\x5e\xd4\xd6\x90\x4e\xc3\x04"
+                         "\x52\x63\xaf\x02\x55\xa6\x49\x4b"
+                         "\x7a\x7e\x2e\x95\xea\x80\x6c\x4b"
+                         "\xb7\x88\x42\x3d\xc1\x09\x28\x97"
+                         "\xd7\xa1\x0f\x0f\x1f\xf1\xea\x63",
+               .ctext  = "\x6b\x83\x00\xf1\x79\xb2\x23\xbf"
+                         "\x17\x26\x8a\xef\xd3\xe1\x0e\x82"
+                         "\x5b\xc7\xde\x3e\x39\x72\x2d\xb0"
+                         "\xad\x25\x3b\xe6\x3b\x9f\xe9\x4b"
+                         "\x6e\xe8\x77\xf5\x9d\x7d\x00\xae"
+                         "\x73\x7b\x81\xff\xe3\x55\x8e\x90"
+                         "\xdf\xe4\xcd\xd5\xdc\x16\x8b\x7a"
+                         "\xe5\x04\x92\x18\xff\xcc\x63\x1b"
+                         "\x53\xf3\x26\x44\x5c\x48\x1d\xa2"
+                         "\x1f\x3f\xe0\x8b\x8f\x6f\xc2\x38",
+               .len    = 80,
+       }, {
+               .key    = "\xb8\xab\x6d\x03\x9d\xec\x15\x0a"
+                         "\xcd\xcd\x68\x73\xa9\x35\x7e\x8a",
+               .klen   = 16,
+               .iv     = "\x9d\xf1\xc0\xa0\x02\x06\xf0\x03"
+                         "\x43\x45\x6a\x2e\x3f\x21\xa9\x3c",
+               .ptext  = "\xef\xbe\x0c\xa3\x49\x4a\xda\x1e"
+                         "\x64\x90\x85\xeb\xdc\xca\x2b\x37"
+                         "\x78\xb7\x62\xd7\x0a\xee\x35\x38"
+                         "\x97\x72\x6a\x99\xb8\x86\x07\x77"
+                         "\x40\xc3\x14\x49\x1f\x67\xa1\x6e"
+                         "\x87\xf0\x0b\x64\x4d\xea\x7c\x3a"
+                         "\x91\x05\xb1\x48\xa1\x6a\x00\x1d"
+                         "\x1b\x4f\x99\xb9\x52\xc9\x0c\xfd"
+                         "\xf3\xe2\x0b\x5f\xe9\xec\x71\xe2"
+                         "\x7d\x15\x84\x46\xc2\x3b\x77\x7b"
+                         "\x30\x01\x34\x5c\x8f\x22\x58\x9a"
+                         "\x17\x05\x7e\xf6\xd5\x92\xc0\xb4",
+               .ctext  = "\x79\x50\x9b\x34\xd7\x22\x9a\x72"
+                         "\x61\xd7\xd8\xa9\xdb\xcf\x2f\xb0"
+                         "\x81\x11\xe3\xed\xa0\xe4\xbd\x8d"
+                         "\xe6\xf2\x52\x52\x40\xec\x9f\x3b"
+                         "\xd4\x48\xc6\xdf\xfd\x36\x90\x8a"
+                         "\x2f\x3b\xb0\xfb\xf4\x2b\x99\xa5"
+                         "\xb2\x39\xc7\x52\x57\x2b\xbc\xd7"
+                         "\x3f\x06\x10\x15\x2e\xf7\xaa\x79"
+                         "\xd6\x6a\xe5\x4e\x2d\x0f\x5f\xaf"
+                         "\xf9\x5a\x63\x28\x33\xf0\x85\x8a"
+                         "\x06\x45\xce\x73\xaa\x96\x1d\xcc"
+                         "\x6e\xb9\x25\xb8\x4c\xfe\xeb\x64",
+               .len    = 96,
+       }, {
+               .key    = "\x50\x45\x7b\x4c\x6d\x80\x53\x62"
+                         "\x90\x26\x77\xf8\x04\x65\x26\xe3",
+               .klen   = 16,
+               .iv     = "\x9d\xd3\x73\x7b\x9b\xbd\x45\x97"
+                         "\xd2\xbb\xa1\xb9\x08\x88\x2c\x85",
+               .ptext  = "\x9f\x11\xeb\x78\x74\xcc\x4e\xd6"
+                         "\x06\x4b\x6d\xe4\xdb\x11\x91\x58"
+                         "\x1f\xa4\xf6\x0e\x8f\xe4\xcf\xfc"
+                         "\x95\x9a\x8b\x68\xb4\x54\x57\x58"
+                         "\x27\x71\xe4\x4b\xc5\x78\x6a\x26"
+                         "\x28\xae\xed\x71\x0e\xe7\xbf\xc3"
+                         "\xff\x9c\x46\x7b\x31\x3e\xff\xb1"
+                         "\xa8\xca\xc3\x6d\xa1\x9e\x49\x16"
+                         "\x31\x8b\xed\x2d\x2a\x2b\xaf\x3b"
+                         "\x3e\x74\x7f\x07\x67\x8e\xb8\x0d"
+                         "\x86\xe2\xea\x2c\x4a\x74\xdc\x9f"
+                         "\x53\x72\xd1\x2e\x97\x0d\x0b\xa5"
+                         "\x05\x87\x8e\x86\x69\x8d\x26\xfb"
+                         "\x90\xc8\xab\x0e\xac\xaf\x84\x1c",
+               .ctext  = "\x3c\x91\xab\x71\xe4\x77\x3e\xb0"
+                         "\x7f\x20\x2e\xd0\xe1\xbe\xfd\x3c"
+                         "\x06\x6c\x36\x75\x46\x27\xfd\x2d"
+                         "\xba\x0f\xf0\x3c\x6d\x1e\x4b\x20"
+                         "\xe9\x5e\x30\xd8\x03\xc6\xa0\x86"
+                         "\xa8\xc7\xa4\x7f\x0e\x1f\x35\x55"
+                         "\x24\x53\x02\xd5\x77\x30\x73\xdc"
+                         "\xa5\xaf\x19\x92\x5b\x36\x86\x0e"
+                         "\xcf\xf2\x5c\x00\xde\x92\xbf\x89"
+                         "\x76\x46\xd5\x26\xb1\x8d\xa4\xef"
+                         "\x61\x7e\x78\xb4\x68\xf5\x5b\x1d"
+                         "\x39\x65\x32\x3a\xad\xff\x8b\x37"
+                         "\x60\xc2\x8a\xaf\x48\x96\x8b\x9f"
+                         "\x12\x6c\x70\x77\x95\xf3\x58\xb0",
+               .len    = 112,
+       }, {
+               .key    = "\xf9\x9f\x6a\x87\xa1\x2d\x6e\xac"
+                         "\xde\xbb\x3e\x15\x5e\x49\xa4\xef",
+               .klen   = 16,
+               .iv     = "\xeb\x8e\x4f\xbe\x4b\x47\xd6\x4f"
+                         "\x65\xd0\xfa\xee\xa6\xf1\x2c\xda",
+               .ptext  = "\xa3\xfa\x4f\xf6\x00\x12\xbe\xc1"
+                         "\x90\xcc\x91\x88\xbd\xfb\x1c\xdb"
+                         "\x2b\xc8\xb9\x3d\x98\x01\xc8\x1f"
+                         "\x07\xb4\xf3\x10\x1d\xfd\xb7\x2e"
+                         "\xcb\x1c\x1f\xe0\x2d\xca\xd3\xc7"
+                         "\xb2\xce\x52\xf1\x7e\xcb\x7c\x50"
+                         "\x0c\x5c\x53\x6b\x18\x62\x02\x54"
+                         "\xbc\x9d\x1f\xda\xd9\x7a\x2d\xff"
+                         "\xb8\x2c\x65\xad\xf1\xfe\xb6\xa4"
+                         "\x8c\xe8\x0a\xb7\x67\x60\xcb\x38"
+                         "\xd7\x72\xa5\xb1\x92\x13\x8e\xd4"
+                         "\xcd\xb3\x04\xb5\xa1\x11\x96\x37"
+                         "\xb3\x53\xa6\xc4\x14\x56\x6d\x42"
+                         "\x66\x43\x40\x42\x41\x63\x11\x7a"
+                         "\xd5\x34\x38\x75\xd0\xbc\x74\x89"
+                         "\x82\x1d\x2c\x0a\x3e\x6a\xfb\xbd",
+               .ctext  = "\x09\x58\xf3\x22\xe5\x10\xf6\x3d"
+                         "\xba\xb1\xfa\x5a\x16\xfe\xc5\x32"
+                         "\x3d\x34\x59\x2e\x81\xde\x99\x2f"
+                         "\xeb\x6a\x97\x86\x1f\x47\x8d\xe6"
+                         "\x87\x79\x0e\xfe\xa4\xca\x09\xdc"
+                         "\x24\x9b\xbb\xb1\x90\x33\xce\xd7"
+                         "\x62\xfd\xfd\xa3\x65\x50\x07\x7c"
+                         "\x4c\xa2\x10\xc7\x32\x0a\x0d\x5e"
+                         "\x22\x29\x40\x71\xe5\xcc\x3a\x5b"
+                         "\x5b\x53\x51\xa5\x5b\xc1\x76\x05"
+                         "\x84\x6e\xe3\x58\x2b\xf2\x28\x76"
+                         "\x5c\x66\x90\xfe\x63\x30\x1c\x45"
+                         "\x26\x34\x80\xfe\x76\x87\x5b\xb1"
+                         "\x63\x10\x09\xf6\x9d\x35\xcb\xee"
+                         "\x3c\x60\x9d\x77\x5b\x36\x70\x09"
+                         "\x4b\x63\x63\x90\x97\x3a\x6c\x8a",
+               .len    = 128,
+       }, {
+               .key    = "\x04\xb9\x6c\x8f\x5e\x79\x02\x87"
+                         "\x88\x06\x7c\xfa\xd3\x7b\x56\xfe",
+               .klen   = 16,
+               .iv     = "\x4b\xc8\x93\x20\x98\x04\xba\x5a"
+                         "\x22\x04\x1f\x3f\x79\x2c\x63\x79",
+               .ptext  = "\xf3\x85\x3e\x75\x97\x10\x7c\x5d"
+                         "\x39\x5a\x46\x47\xe7\x51\xa3\xac"
+                         "\x84\x56\x3f\x1b\xb3\x93\x6a\x2e"
+                         "\xf7\x8f\x63\xbe\x18\xff\xd7\x53"
+                         "\xc8\xe0\xa5\xde\x86\xc2\xe4\xab"
+                         "\xc3\x67\x27\x91\x43\x8c\xff\x6c"
+                         "\xc7\x07\xc2\xcd\xe9\x12\x8b\xef"
+                         "\x47\xe7\x82\xed\xe3\x8d\x5e\x33"
+                         "\xca\xf1\x28\x32\xf4\x38\x41\x59"
+                         "\x6c\x54\xa6\x40\xb0\xd5\x73\x26"
+                         "\x5b\x02\xa6\x9d\x01\x29\x26\x84"
+                         "\x5b\x33\x04\x36\xa4\x7b\x00\x01"
+                         "\x42\xe1\x4f\xda\xa9\x1a\x9b\x4e"
+                         "\x7d\x4a\x4c\xbc\xf6\xd4\x06\xc2"
+                         "\x89\x70\x72\xf5\xc5\x7f\x42\xd5"
+                         "\x7b\x9c\x6f\x00\x21\x74\xc5\xa5"
+                         "\x78\xd7\xa2\x3c\x6d\x0f\xfb\x74"
+                         "\x3d\x70\x9f\x6d\xdd\x30\xc0\x28",
+               .ctext  = "\xc0\x49\x98\xb9\xf6\x58\xeb\x56"
+                         "\x36\x76\x7a\x40\x7c\x27\x80\x62"
+                         "\xe3\xcb\x9c\x87\x2c\x03\xc2\x0c"
+                         "\x82\x00\x50\xd2\xe4\x61\x4d\x54"
+                         "\x88\x10\x6f\x0a\xb4\x25\x57\xba"
+                         "\xf0\x07\xe3\x55\x06\xb3\x72\xe9"
+                         "\x2f\x9f\x1e\x50\xa8\x15\x69\x71"
+                         "\xe3\xe5\x50\x32\xe5\xe0\x47\x0f"
+                         "\x3a\xaa\x7d\xc0\x09\x0e\xdb\x1a"
+                         "\xae\xb6\xa5\x87\x63\xd6\xbe\x8b"
+                         "\xb2\x3d\x10\x1e\xb3\x68\xcf\x8a"
+                         "\xe5\xa8\x89\xa9\xfe\x79\x13\x77"
+                         "\xc4\x3f\x6f\x9f\xdd\x76\x5b\xf2"
+                         "\x05\x67\x8a\x58\xb4\x31\xac\x64"
+                         "\x6f\xc4\xc1\x6b\x08\x79\x3f\xe5"
+                         "\x1c\x9a\x66\x3f\x7d\x1f\x18\xb1"
+                         "\x07\xa5\x7b\x4f\x2c\x43\x33\x84"
+                         "\xab\x1b\xc0\x7d\x49\x2f\x27\x9b",
+               .len    = 144,
+       }, {
+               .key    = "\x99\x79\xaf\x3c\xfb\xbd\xe7\xca"
+                         "\xee\x4a\x4d\xb2\x23\x1e\xb6\x07",
+               .klen   = 16,
+               .iv     = "\xb4\xfc\xaa\xc1\x08\xbf\x68\xb2"
+                         "\xf6\xef\x29\xbc\x2d\x92\xa9\x40",
+               .ptext  = "\xd3\x44\xe4\xd9\x6c\x8a\x1d\x4b"
+                         "\xfe\x64\x25\xb6\x72\x21\xda\x10"
+                         "\x3e\x77\xee\xd1\x41\xd3\xea\xf0"
+                         "\xee\xee\x72\x0f\xad\xa1\xca\xf3"
+                         "\x7e\xfa\x99\x36\xe0\x8f\xed\x40"
+                         "\xf1\x12\x80\x73\xd6\x26\x3a\xa6"
+                         "\x5d\x71\xf6\xd5\xe1\xf3\x89\x16"
+                         "\x6f\x96\x00\xcf\x26\x06\x2a\x27"
+                         "\xe4\xc2\x57\xba\x1f\x74\x5e\x91"
+                         "\x10\x7e\xe5\x51\x17\xd5\xdc\xb2"
+                         "\x5b\x12\x4b\x33\xb1\xc6\x4e\x0d"
+                         "\xbf\x0e\x5d\x65\x61\x68\xd1\xc5"
+                         "\x4b\xc5\xa4\xcd\xf0\xe0\x79\x26"
+                         "\xa3\xcd\xdc\xb8\xfc\xd5\xca\x1d"
+                         "\x7e\x81\x74\x55\x76\xf5\x40\xbb"
+                         "\x26\x7f\x11\x37\x23\x70\xc8\xb6"
+                         "\xfc\x2b\x0b\xd7\x1c\x7b\x45\xe7"
+                         "\xf2\x2a\xed\x10\x4f\xcf\x0c\xcd"
+                         "\x0f\xe7\xf9\xa1\xfb\x27\x67\x09"
+                         "\xee\x11\xa2\xaf\x37\xc6\x16\xe0",
+               .ctext  = "\x60\xce\x9a\xdb\xb2\xe8\xa2\x64"
+                         "\x35\x9c\x5b\x97\x21\x9b\x95\x89"
+                         "\x7b\x89\x15\x01\x97\x8b\xec\x9b"
+                         "\xb9\xce\x7d\xb9\x9d\xcc\xd0\xa0"
+                         "\xda\x39\x5d\xfd\xb9\x51\xe7\x2f"
+                         "\xe7\x9b\x73\x1b\x07\xfb\xfd\xbb"
+                         "\xce\x84\x68\x76\x12\xc9\x6c\x38"
+                         "\xc0\xdc\x67\x96\x5e\x63\xcf\xe5"
+                         "\x57\x84\x7a\x14\x8c\xab\x38\x94"
+                         "\x1c\x27\xc3\xe0\x03\x58\xfe\x98"
+                         "\x97\xfc\x96\xba\x65\x87\x1e\x44"
+                         "\xf8\x00\x91\x6a\x14\x05\xf3\xf9"
+                         "\x8e\x3e\x7a\x3c\x41\x96\x15\x4f"
+                         "\xa8\xc0\x73\x1f\x1b\xeb\xaf\xec"
+                         "\xc4\x5a\x35\xed\x42\x2f\x47\xea"
+                         "\xfd\x2f\x29\xf6\x0f\x58\x8b\x3d"
+                         "\x15\x81\xe3\xa4\xa6\x5f\x33\x33"
+                         "\xe9\x0d\x06\x4f\x7f\x89\x2c\x3d"
+                         "\x18\x45\x1f\xd1\xc5\x74\xf7\x52"
+                         "\x2f\x9b\x72\x3d\x1f\xad\x12\x1b",
+               .len    = 160,
+       }, {
+               .key    = "\x7f\x92\xd5\x06\x30\x6b\xc0\x23"
+                         "\x87\xa8\x8e\x6d\xc7\xc5\xd7\xf1"
+                         "\x5f\xce\x89\xb3\xd5\x7f\x7f\xf0",
+               .klen   = 24,
+               .iv     = "\xfd\xab\x56\xa6\x6e\xda\x7c\x57"
+                         "\x36\x36\x89\x09\xcd\xa8\xd3\x91",
+               .ptext  = "\x48\x3e\x3c\x11\xcf\xd0\x4f\xc0"
+                         "\x51\xe3\x8c\xe9\x76\xcd\xff\x37",
+               .ctext  = "\x2d\x8f\x39\x71\x0a\x2c\xc9\x93"
+                         "\xb6\x1a\x5c\x53\x06\x4d\xaa\xcf",
+               .len    = 16,
+       }, {
+               .key    = "\xd6\x1a\x18\x2f\x68\x2f\xb6\xfe"
+                         "\x3d\x2d\x85\x75\x6e\x18\x8a\x52"
+                         "\x53\x39\xfc\xc1\xf5\xc0\x56\x22",
+               .klen   = 24,
+               .iv     = "\xc6\xae\xaa\x0d\x90\xf2\x38\x93"
+                         "\xac\xd2\x3f\xc7\x74\x8d\x13\x7e",
+               .ptext  = "\xfa\x3f\x70\x52\xfb\x04\x0e\xed"
+                         "\x0e\x60\x75\x84\x21\xdf\x13\xa1"
+                         "\x26\xf8\x8c\x26\x0a\x37\x51\x8f"
+                         "\xe7\x9c\x74\x77\x7a\x3e\xbb\x5d",
+               .ctext  = "\xc1\x53\x86\xf8\x60\x5d\x72\x59"
+                         "\x7e\xdf\xc8\xdb\x85\xd6\x9f\x2a"
+                         "\xa1\xda\xe5\x85\x78\x4f\x1b\x6f"
+                         "\x58\xf3\x2b\xff\x34\xe4\x97\x4e",
+               .len    = 32,
+       }, {
+               .key    = "\xd7\x33\xf3\xa9\x5b\xb4\x86\xea"
+                         "\xe3\x7d\x50\x62\x3b\x73\xaf\xc4"
+                         "\xda\x89\xd9\x3c\xcc\xe4\x73\xb0",
+               .klen   = 24,
+               .iv     = "\xef\x3e\x5f\x46\x62\x88\xd5\x26"
+                         "\x3b\xd3\xb5\x81\x78\x70\x1b\xd2",
+               .ptext  = "\x39\x56\x34\x63\x2c\xc5\x51\x13"
+                         "\x48\x29\x3a\x58\xbe\x41\xc5\x80"
+                         "\x2c\x80\xa7\x3c\x14\xb4\x89\x5e"
+                         "\x8e\xe5\x5f\xe2\x39\x80\xf5\x2b"
+                         "\x77\xb5\xca\x90\xda\x1d\x22\x17"
+                         "\xd9\xa0\x57\x80\xc8\x96\x70\x86",
+               .ctext  = "\x25\x5f\x66\x15\xb5\x62\xfb\x55"
+                         "\xb3\x77\xa1\x7d\x03\xba\x86\x0a"
+                         "\x0d\x5b\xbb\x06\xe9\xe2\xa8\x41"
+                         "\xa3\x58\xd6\x4b\xcb\x7f\xd0\x15"
+                         "\x3b\x02\x74\x5d\x4c\x4c\xb0\xa5"
+                         "\x06\xc9\x59\x53\x2a\x36\xeb\x59",
+               .len    = 48,
+       }, {
+               .key    = "\x07\x2c\xf4\x61\x79\x09\x01\x8f"
+                         "\x37\x32\x98\xd4\x86\x2b\x3b\x80"
+                         "\x07\x60\xba\xf0\x2e\xc3\x4a\x57",
+               .klen   = 24,
+               .iv     = "\xf5\xb5\xd7\xbf\xd2\x2a\x9b\x4a"
+                         "\xe6\x08\xf0\xbe\x77\xd1\x62\x40",
+               .ptext  = "\xa0\x82\x09\x60\x47\xbb\x16\x56"
+                         "\x50\x1f\xab\x8b\x10\xfe\xf0\x5c"
+                         "\x05\x32\x63\x1a\xc4\x46\x6f\x55"
+                         "\x32\xde\x41\x5a\xf7\x52\xd7\xfa"
+                         "\x30\x9d\x59\x8d\x64\x76\xad\x37"
+                         "\xba\xbc\x46\x6a\x69\x17\x3c\xac"
+                         "\x6f\xdd\xa2\x9b\x86\x32\x14\x2e"
+                         "\x54\x74\x8f\x3d\xe2\xd6\x85\x44",
+               .ctext  = "\x91\x02\xa9\xd3\x4b\x9a\x8f\xe6"
+                         "\x9f\xe4\x51\x57\xc9\x42\xda\x68"
+                         "\xca\xf6\x54\x51\x90\xec\x20\x2e"
+                         "\xab\x25\x6c\xd9\x8b\x99\xa6\x1c"
+                         "\x72\xc9\x01\xd6\xbc\x2b\x26\x78"
+                         "\x42\x00\x84\x0a\xdd\xa8\xd9\xb5"
+                         "\xc6\xc8\x30\xb6\xab\xea\x71\x84"
+                         "\xb2\x57\x97\x32\xdb\x35\x23\xd8",
+               .len    = 64,
+       }, {
+               .key    = "\x4f\x4a\x31\x64\xc6\xa5\x29\xaa"
+                         "\xad\xfd\x32\x94\x1f\x56\x57\xd1"
+                         "\x9d\x7e\x3d\x49\x00\x36\xb1\x5d",
+               .klen   = 24,
+               .iv     = "\xb2\x92\x83\x70\x1e\xa3\x97\xa6"
+                         "\x65\x53\x39\xeb\x53\x8f\xb1\x38",
+               .ptext  = "\x91\xac\x17\x11\x1c\x03\x69\x53"
+                         "\xf5\xdf\xdb\x2c\x1b\x9a\x6e\x6b"
+                         "\xb6\x02\xc4\xfa\x95\x01\x33\xa8"
+                         "\xda\x7e\x18\x2c\xf4\x7e\x6e\x67"
+                         "\xce\x8f\x9f\xea\x46\x66\x99\xb8"
+                         "\xe1\xc7\x25\x4d\xbd\xa5\x74\xdf"
+                         "\xc7\x8b\xfb\xe3\x2d\x3a\x82\xd3"
+                         "\x17\x94\x77\x2f\x92\xb8\x87\xc2"
+                         "\xcc\x6f\x70\x26\x87\xc7\x10\x8a"
+                         "\xc8\xfd\xc2\xb3\xcf\xa0\xeb\x41",
+               .ctext  = "\x28\x23\x3a\x4a\x18\xb7\xb6\x05"
+                         "\xd4\x1b\x6a\x9e\xa7\xf2\x38\x01"
+                         "\x78\xd3\xb0\x1b\x95\x68\x59\xf1"
+                         "\xc0\xed\x30\x46\x2e\xb9\xa6\xdc"
+                         "\xde\xef\xa6\x85\x19\xfc\x4d\x36"
+                         "\x5d\x24\x92\x62\x75\x32\x76\x6d"
+                         "\x6d\xa9\x07\xe1\x4f\x59\x84\x1a"
+                         "\x68\x9a\x07\x48\xd3\x86\xf6\xf1"
+                         "\x5b\xf9\x35\xec\x7c\xaf\x47\x13"
+                         "\x9c\xc9\x33\x12\x10\x2f\x94\x8a",
+               .len    = 80,
+       }, {
+               .key    = "\x4c\xf4\xd0\x34\xd0\x95\xab\xae"
+                         "\x82\x5c\xfd\xfa\x13\x86\x25\xce"
+                         "\xf4\x13\x32\xcd\xc6\x6d\xf6\x50",
+               .klen   = 24,
+               .iv     = "\x12\x4a\x5b\x66\x3a\xd3\xfb\x1a"
+                         "\xaf\x06\xea\xf4\x65\x59\xd6\xc2",
+               .ptext  = "\x84\xa0\x53\x97\x61\x30\x70\x15"
+                         "\xac\x45\x8e\xe8\xeb\xa1\x72\x93"
+                         "\x26\x76\x98\x6f\xe4\x86\xca\xf0"
+                         "\x57\x89\xf2\x2b\xd4\xcf\x2d\x95"
+                         "\x86\x26\x20\x0e\x62\xfe\x8f\x1e"
+                         "\x5d\xcb\x2b\x7e\xdd\xab\xac\xda"
+                         "\x6e\x49\x20\xd5\xb7\x01\x83\x4e"
+                         "\xac\x45\x8f\xe1\x05\x3f\xd5\xb1"
+                         "\xee\xb7\x0d\x65\x00\x38\xab\x71"
+                         "\x70\x6e\xb3\x97\x86\xd3\xcd\xad"
+                         "\x51\x8b\x9c\xa0\x9a\x8b\x4c\xb9"
+                         "\x16\x01\x6a\x1f\xdf\xf0\xf9\x9e",
+               .ctext  = "\x38\x5b\x16\xef\xb8\x8c\x74\x7a"
+                         "\x55\x17\x71\xa7\x7d\x34\xd7\x6a"
+                         "\xc6\x31\x55\x6f\xbb\x61\xf4\x12"
+                         "\x81\x8c\x91\x0d\x10\xdb\xd5\x22"
+                         "\x77\x36\x32\xb6\x77\xb1\x5e\x21"
+                         "\xb5\xec\xf9\x64\x04\x90\x6f\xc6"
+                         "\x8a\x86\x23\xb5\xfe\xa4\xb6\x84"
+                         "\x91\xa1\x60\xe3\xd7\xf3\xb9\xda"
+                         "\x96\x23\x4a\xb3\xab\x75\x84\x04"
+                         "\x15\x1a\xbb\xe8\x02\x1e\x80\x7c"
+                         "\xc1\x93\x01\x0f\x5c\x4a\xde\x85"
+                         "\xbb\x93\x05\x66\x53\x74\x40\x56",
+               .len    = 96,
+       }, {
+               .key    = "\x25\x1b\xc2\xa6\x21\x25\xeb\x97"
+                         "\x4b\xf6\xcb\x3b\xcd\x61\xfd\x94"
+                         "\x37\x03\xb3\xd9\x74\x6e\x4d\xbb",
+               .klen   = 24,
+               .iv     = "\xfd\x87\x2b\xec\x4c\x2c\xbf\xe2"
+                         "\x94\x1a\xe6\xd9\xaf\x0e\x78\x17",
+               .ptext  = "\x58\x2b\x1d\x73\x9a\x9c\x63\x18"
+                         "\x88\x7a\x0e\x87\x2f\xf0\xb0\xdb"
+                         "\xc9\x9d\x79\x51\x34\x39\x4f\x07"
+                         "\xa2\x7c\x21\x04\x91\x3b\x79\x79"
+                         "\xfe\xd5\x51\x46\xd5\xcd\x28\xc0"
+                         "\xad\xb8\x55\xb2\xb2\x5a\x9a\xa2"
+                         "\xe2\x0c\xfc\x55\x7d\x60\xd2\x95"
+                         "\xb6\x08\x1d\x31\xaf\xf4\x17\x46"
+                         "\xa4\xbb\x0f\xbd\x67\x3c\x73\x15"
+                         "\x0c\x85\x2f\x62\xe5\xf4\x35\x96"
+                         "\xb1\x9b\x5d\x00\x10\xe9\x70\x12"
+                         "\x3a\x87\x7f\x67\xf1\x81\x7a\x05"
+                         "\xb4\xa6\xfe\xdf\x36\x31\x6d\x9e"
+                         "\x0e\xa9\x44\xa0\xb0\x05\xa9\x41",
+               .ctext  = "\x4b\x56\xe0\xc2\x65\x2f\x7c\x6f"
+                         "\xee\x22\xeb\x34\x1c\xa5\xb7\xc8"
+                         "\x35\xd7\x51\xfd\x6a\xf4\xdd\xc3"
+                         "\x38\xf4\xfc\x9d\x2e\xc2\x77\xb7"
+                         "\x93\x8e\x8c\xb3\x44\x9b\xaf\xbb"
+                         "\x99\xb9\xa8\x38\x1c\xfe\x63\xfb"
+                         "\x1f\xa0\xaa\x35\x29\x7b\x87\x49"
+                         "\x8e\x93\xa5\xb8\x5a\x85\x37\xa7"
+                         "\x67\x69\x49\xbd\xc3\xfa\x89\x1c"
+                         "\xf5\x60\x9b\xe7\x71\x96\x95\xd9"
+                         "\x0b\x98\xe6\x74\x1d\xa3\xd9\x89"
+                         "\x03\xe4\xf6\x66\xb3\x73\xb1\xac"
+                         "\x9f\xee\x8f\xc2\x96\xcc\x97\x78"
+                         "\x1b\x96\x63\x64\x00\x9c\x2d\x29",
+               .len    = 112,
+       }, {
+               .key    = "\x9c\x14\x44\x5a\xd5\x1c\x50\x08"
+                         "\x95\xc2\xf2\xaf\x3f\x29\xc9\x3e"
+                         "\x95\x5e\xc6\xb4\x2b\xf4\x3e\xe3",
+               .klen   = 24,
+               .iv     = "\x1b\xeb\x3d\x73\xfb\xd7\x1e\x2b"
+                         "\x0c\x3d\x58\x6c\xb4\x41\x9b\xfe",
+               .ptext  = "\x2f\x7e\x1c\x10\x81\x36\x2d\x79"
+                         "\xaf\xab\x10\x44\x2e\xcc\x0d\x6c"
+                         "\x9c\x14\xc2\xe4\xae\xb0\xbb\xda"
+                         "\x6a\xe0\x42\x3d\x96\x9f\x78\x7d"
+                         "\x70\x86\xa5\x92\x9f\xee\xcd\x3f"
+                         "\x6a\x55\x84\x98\x28\x03\x02\xc2"
+                         "\xf7\xec\x7a\xfa\xb1\xd9\xa8\xd8"
+                         "\x1c\xc3\xaa\xd5\x61\x7f\x10\x0c"
+                         "\xc0\xa1\x36\x3d\x81\x9a\xd2\x17"
+                         "\x2e\x23\xc9\xb7\xff\xdf\x47\x6c"
+                         "\x96\x3b\x0e\xbd\xec\x9a\x0e\xad"
+                         "\x8c\xaf\x36\x3d\xff\x29\x8b\x33"
+                         "\x87\x96\x77\x1a\x10\x81\x63\x8a"
+                         "\x63\xde\x88\xa9\x9d\xa9\x01\xf2"
+                         "\xdf\xc9\x25\x35\x48\x3a\x15\xdf"
+                         "\x20\x6b\x91\x7c\x56\xe5\x10\x7a",
+               .ctext  = "\x4d\x35\x70\xf1\x25\x02\x1d\x7f"
+                         "\x9e\x0f\x5b\x4b\x65\xab\xcc\x6b"
+                         "\x62\xab\x2b\xfa\xc0\x66\xee\x56"
+                         "\xb4\x66\x95\x22\x84\x39\xd8\x3f"
+                         "\x74\xba\x4f\x3f\xcd\xef\xcf\xf6"
+                         "\x76\xeb\x9e\x8a\xec\x9c\x31\xa0"
+                         "\x3e\x0c\xf9\xfa\x57\x90\xb4\x02"
+                         "\xac\xc8\x28\xda\xa0\x05\xb7\x7e"
+                         "\x75\x9c\x79\x36\xa9\x2f\x1a\x36"
+                         "\x56\x77\xda\x74\xc7\xb3\xdf\xf3"
+                         "\xb9\x83\x10\xf3\x6b\xe1\xdf\xcb"
+                         "\x11\x70\xb1\xa0\x68\x48\x26\x95"
+                         "\x10\x91\x94\xf3\xe9\x82\xb4\x8a"
+                         "\xaa\xde\xf8\x9f\xce\x82\x47\x18"
+                         "\x37\x5d\xda\x34\x74\x4d\x36\xbd"
+                         "\xa5\x6c\xa4\xb3\x70\xad\x00\xbd",
+               .len    = 128,
+       }, {
+               .key    = "\x2d\x2e\x0f\x30\x32\xed\xa9\x1f"
+                         "\x71\x4e\x68\x77\xe8\xa8\x5b\xdd"
+                         "\x3c\x5e\x68\x6b\xab\x03\xe4\xf8",
+               .klen   = 24,
+               .iv     = "\x42\xc1\x61\x9a\x50\xfb\xc7\x6a"
+                         "\x1a\x31\xa7\x87\xd0\x24\xcb\x5e",
+               .ptext  = "\xc0\x3b\x12\x28\xca\x26\x7b\xb3"
+                         "\x14\xc1\x7f\x66\xff\x3b\xa4\x80"
+                         "\x59\x77\x4f\xa0\xd4\xb2\xd9\x8a"
+                         "\xb6\x67\xe6\x28\xd3\x6f\xf2\xcf"
+                         "\xb8\x6d\x2d\xc4\x2a\x69\x89\xff"
+                         "\xcf\xbb\x11\x2e\x2a\x2b\x7c\xfd"
+                         "\xcd\x56\x02\x95\xc9\x54\x6e\x62"
+                         "\x6a\x97\x75\x1a\x21\x16\x46\xfb"
+                         "\xc2\xab\x62\x54\xef\xba\xae\x46"
+                         "\xd4\x14\xc6\xcc\x16\x1b\x95\xf9"
+                         "\x05\x26\x23\x81\x19\x27\xad\x7b"
+                         "\x9c\x8b\xfb\x65\xa4\x61\xee\x69"
+                         "\x44\xbf\x59\xde\x03\x61\x11\x12"
+                         "\x8d\x94\x48\x47\xa9\x52\x16\xfb"
+                         "\x6b\xaf\x59\x6d\xab\x74\xbf\x5c"
+                         "\xb6\x09\x21\x12\x42\x98\x13\xa1"
+                         "\xa8\x6f\xb9\x6d\x4d\xa6\xdc\xea"
+                         "\x61\x02\x3c\xa7\xcd\x1a\x28\x8c",
+               .ctext  = "\xa1\x4a\x83\xb2\xe0\xef\x3d\x94"
+                         "\xa4\x34\x66\x93\xb4\x89\x4e\x12"
+                         "\xe5\x61\xc9\xea\xe0\x16\x96\x1a"
+                         "\x3e\x94\x20\x81\xd4\x12\x7f\xf4"
+                         "\xb8\x3f\xc9\xe2\x99\xb5\x0f\x9e"
+                         "\x71\x86\x4f\x13\x78\x4e\xf1\x51"
+                         "\xd4\x7d\x6e\x47\x31\x9a\xd8\xf7"
+                         "\xb9\xb1\x17\xd0\xbd\xbf\x72\x86"
+                         "\xb4\x58\x85\xf0\x05\x67\xc4\x00"
+                         "\xca\xcb\xa7\x1a\x1d\x88\x29\xf4"
+                         "\xe2\xf6\xdd\x5a\x3e\x5a\xbb\x29"
+                         "\x48\x5a\x4a\x18\xcd\x5c\xf1\x09"
+                         "\x5b\xbe\x1a\x43\x12\xc5\x6e\x6e"
+                         "\x5e\x6d\x3b\x22\xf7\x58\xbd\xc8"
+                         "\xb1\x04\xaf\x44\x9c\x2b\x98\x5a"
+                         "\x14\xb7\x35\xb8\x9a\xce\x32\x28"
+                         "\x1f\x8d\x08\x8a\xb9\x82\xf0\xa5"
+                         "\x6a\x37\x29\xb6\x29\x3a\x53\x5e",
+               .len    = 144,
+       }, {
+               .key    = "\x66\xb8\x4d\x60\x67\x82\xcc\x8d"
+                         "\x1e\xda\x8f\x28\xe5\x02\xdc\x2c"
+                         "\x54\x84\x2a\x06\xb5\xd1\x34\x57",
+               .klen   = 24,
+               .iv     = "\xb8\x28\x4d\xf5\x69\xb9\xf3\x33"
+                         "\x5e\x0b\xa6\x62\x35\x9b\xfb\x97",
+               .ptext  = "\x3e\xc6\xec\xaf\x74\xe8\x72\x91"
+                         "\xb2\xc6\x56\xb3\x23\x29\x43\xe0"
+                         "\xfb\xcc\x21\x38\x64\x78\x9e\x78"
+                         "\xbb\x6e\x0d\x7b\xfd\x05\x74\x01"
+                         "\x7c\x94\xe0\xb0\xd7\x92\xfc\x58"
+                         "\x28\xfc\xe2\x7b\x7f\xf7\x31\x0d"
+                         "\x90\xb7\x60\x78\xa8\x9f\x52\xe3"
+                         "\xe6\xaa\x2a\xb4\xa7\x09\x60\x53"
+                         "\x42\x0e\x15\x31\xf6\x48\xa3\x0a"
+                         "\x20\xf0\x79\x67\xb1\x83\x26\x66"
+                         "\xe0\xb1\xb3\xbd\x1c\x76\x36\xfd"
+                         "\x45\x87\xa4\x14\x1b\xef\xe7\x16"
+                         "\xf7\xfa\x30\x3d\xb9\x52\x8f\x2e"
+                         "\x01\x68\xc1\x7d\xa2\x15\x49\x74"
+                         "\x53\x82\xc2\x10\xa8\x45\x73\x4d"
+                         "\x41\xcc\x24\xa3\x42\xff\x30\xd1"
+                         "\x02\x21\xdc\xd9\x08\xf7\xe7\x4c"
+                         "\x33\x2d\x62\xc7\x38\xf5\xc2\xbe"
+                         "\x52\xf1\x34\x78\x34\x53\x30\x5b"
+                         "\x43\x43\x51\x6a\x02\x81\x64\x0c",
+               .ctext  = "\xd9\xed\xc8\xc7\x66\xcd\x06\xc5"
+                         "\xc1\x25\x9b\xf5\x14\x71\x1d\x69"
+                         "\xc9\x7c\x04\x40\xab\xc0\x44\xf4"
+                         "\xa1\xe6\x57\x8b\x35\x62\x4e\x3f"
+                         "\xce\x4a\x99\xcd\x95\xc4\xd1\xf3"
+                         "\xbc\x25\xa2\x18\xe6\xd1\xf7\xc0"
+                         "\x13\x98\x60\x4c\x5c\xb1\x4f\x7a"
+                         "\xbc\x45\x12\x52\xe8\x71\xb0\xf1"
+                         "\x18\xef\x6f\x8a\x63\x35\x17\xae"
+                         "\x90\x31\x41\x9d\xf4\xdc\x35\xcc"
+                         "\x49\x72\x10\x11\x3b\xe3\x40\x7a"
+                         "\x8e\x21\x39\xd0\x5b\x82\xb1\xe9"
+                         "\x0c\x37\x5a\x7c\x11\xcb\x96\xd9"
+                         "\xd4\x1c\x47\x4b\x70\xcb\xca\x08"
+                         "\x5f\x71\xe9\x48\xf6\x29\xd8\xbb"
+                         "\x5c\xad\x9b\x23\x9f\x62\xaf\xef"
+                         "\x8e\xd8\x99\x1d\x60\xad\xc3\x6f"
+                         "\xed\x06\x1a\xec\xfa\xc0\x0f\x0d"
+                         "\xb7\x00\x02\x45\x7c\x94\x23\xb6"
+                         "\xd7\x26\x6a\x16\x62\xc4\xd9\xee",
+               .len    = 160,
+       }, {
+               .key    = "\x7f\x92\xd5\x06\x30\x6b\xc0\x23"
+                         "\x87\xa8\x8e\x6d\xc7\xc5\xd7\xf1"
+                         "\x5f\xce\x89\xb3\xd5\x7f\x7f\xf0"
+                         "\xfd\xab\x56\xa6\x6e\xda\x7c\x57",
+               .klen   = 32,
+               .iv     = "\x36\x36\x89\x09\xcd\xa8\xd3\x91"
+                         "\x48\x3e\x3c\x11\xcf\xd0\x4f\xc0",
+               .ptext  = "\x51\xe3\x8c\xe9\x76\xcd\xff\x37"
+                         "\xd6\x1a\x18\x2f\x68\x2f\xb6\xfe",
+               .ctext  = "\x05\x31\x46\x6d\xb8\xf4\x92\x64"
+                         "\x46\xfd\x0d\x96\x60\x01\xd7\x94",
+               .len    = 16,
+       }, {
+               .key    = "\x3d\x2d\x85\x75\x6e\x18\x8a\x52"
+                         "\x53\x39\xfc\xc1\xf5\xc0\x56\x22"
+                         "\xc6\xae\xaa\x0d\x90\xf2\x38\x93"
+                         "\xac\xd2\x3f\xc7\x74\x8d\x13\x7e",
+               .klen   = 32,
+               .iv     = "\xfa\x3f\x70\x52\xfb\x04\x0e\xed"
+                         "\x0e\x60\x75\x84\x21\xdf\x13\xa1",
+               .ptext  = "\x26\xf8\x8c\x26\x0a\x37\x51\x8f"
+                         "\xe7\x9c\x74\x77\x7a\x3e\xbb\x5d"
+                         "\xd7\x33\xf3\xa9\x5b\xb4\x86\xea"
+                         "\xe3\x7d\x50\x62\x3b\x73\xaf\xc4",
+               .ctext  = "\x24\x36\xe4\x14\xb7\xe1\x56\x8a"
+                         "\xf3\xc5\xaf\x0e\xa7\xeb\xbd\xcd"
+                         "\x2d\xe9\xd7\x19\xae\x24\x5d\x3b"
+                         "\x1d\xfb\xdc\x21\xb3\x1a\x37\x0b",
+               .len    = 32,
+       }, {
+               .key    = "\xda\x89\xd9\x3c\xcc\xe4\x73\xb0"
+                         "\xef\x3e\x5f\x46\x62\x88\xd5\x26"
+                         "\x3b\xd3\xb5\x81\x78\x70\x1b\xd2"
+                         "\x39\x56\x34\x63\x2c\xc5\x51\x13",
+               .klen   = 32,
+               .iv     = "\x48\x29\x3a\x58\xbe\x41\xc5\x80"
+                         "\x2c\x80\xa7\x3c\x14\xb4\x89\x5e",
+               .ptext  = "\x8e\xe5\x5f\xe2\x39\x80\xf5\x2b"
+                         "\x77\xb5\xca\x90\xda\x1d\x22\x17"
+                         "\xd9\xa0\x57\x80\xc8\x96\x70\x86"
+                         "\x07\x2c\xf4\x61\x79\x09\x01\x8f"
+                         "\x37\x32\x98\xd4\x86\x2b\x3b\x80"
+                         "\x07\x60\xba\xf0\x2e\xc3\x4a\x57",
+               .ctext  = "\x2e\x73\x60\xec\xd3\x95\x78\xe8"
+                         "\x0f\x98\x1a\xc2\x92\x49\x0b\x49"
+                         "\x71\x42\xf4\xb0\xaa\x8b\xf8\x53"
+                         "\x16\xab\x6d\x74\xc0\xda\xab\xcd"
+                         "\x85\x52\x11\x20\x2c\x59\x16\x00"
+                         "\x26\x47\x4a\xea\x08\x5f\x38\x68",
+               .len    = 48,
+       }, {
+               .key    = "\xf5\xb5\xd7\xbf\xd2\x2a\x9b\x4a"
+                         "\xe6\x08\xf0\xbe\x77\xd1\x62\x40"
+                         "\xa0\x82\x09\x60\x47\xbb\x16\x56"
+                         "\x50\x1f\xab\x8b\x10\xfe\xf0\x5c",
+               .klen   = 32,
+               .iv     = "\x05\x32\x63\x1a\xc4\x46\x6f\x55"
+                         "\x32\xde\x41\x5a\xf7\x52\xd7\xfa",
+               .ptext  = "\x30\x9d\x59\x8d\x64\x76\xad\x37"
+                         "\xba\xbc\x46\x6a\x69\x17\x3c\xac"
+                         "\x6f\xdd\xa2\x9b\x86\x32\x14\x2e"
+                         "\x54\x74\x8f\x3d\xe2\xd6\x85\x44"
+                         "\x4f\x4a\x31\x64\xc6\xa5\x29\xaa"
+                         "\xad\xfd\x32\x94\x1f\x56\x57\xd1"
+                         "\x9d\x7e\x3d\x49\x00\x36\xb1\x5d"
+                         "\xb2\x92\x83\x70\x1e\xa3\x97\xa6",
+               .ctext  = "\xfb\xd3\xc3\x8b\xf7\x89\xcc\x31"
+                         "\xb1\x7f\xc3\x91\xdc\x04\xc6\xd7"
+                         "\x33\xbd\xe0\xee\x0c\xd5\x70\xed"
+                         "\x1b\x1d\xad\x49\x6f\x5c\xa1\x68"
+                         "\xd7\x03\xc9\x65\xa7\x90\x30\x2b"
+                         "\x26\xeb\xf4\x7a\xac\xcc\x03\xe1"
+                         "\x6a\xe5\xdb\x23\x10\x8a\xcd\x70"
+                         "\x39\x4d\x7a\xc9\xcd\x62\xd1\x65",
+               .len    = 64,
+       }, {
+               .key    = "\x65\x53\x39\xeb\x53\x8f\xb1\x38"
+                         "\x91\xac\x17\x11\x1c\x03\x69\x53"
+                         "\xf5\xdf\xdb\x2c\x1b\x9a\x6e\x6b"
+                         "\xb6\x02\xc4\xfa\x95\x01\x33\xa8",
+               .klen   = 32,
+               .iv     = "\xda\x7e\x18\x2c\xf4\x7e\x6e\x67"
+                         "\xce\x8f\x9f\xea\x46\x66\x99\xb8",
+               .ptext  = "\xe1\xc7\x25\x4d\xbd\xa5\x74\xdf"
+                         "\xc7\x8b\xfb\xe3\x2d\x3a\x82\xd3"
+                         "\x17\x94\x77\x2f\x92\xb8\x87\xc2"
+                         "\xcc\x6f\x70\x26\x87\xc7\x10\x8a"
+                         "\xc8\xfd\xc2\xb3\xcf\xa0\xeb\x41"
+                         "\x4c\xf4\xd0\x34\xd0\x95\xab\xae"
+                         "\x82\x5c\xfd\xfa\x13\x86\x25\xce"
+                         "\xf4\x13\x32\xcd\xc6\x6d\xf6\x50"
+                         "\x12\x4a\x5b\x66\x3a\xd3\xfb\x1a"
+                         "\xaf\x06\xea\xf4\x65\x59\xd6\xc2",
+               .ctext  = "\xa2\x51\x28\xc2\x5e\x58\x1c\xaf"
+                         "\x84\x92\x1c\xe1\x92\xf0\xf9\x9e"
+                         "\xf2\xb3\xc6\x2b\x34\xd2\x8d\xa0"
+                         "\xb3\xd7\x87\x56\xeb\xd9\x32\x6a"
+                         "\xca\x90\x28\x26\x49\x34\xca\x41"
+                         "\xce\xc5\x9e\xd6\xfe\x57\x71\x3c"
+                         "\x98\xaf\xdd\xfc\x7d\xdf\x26\x7e"
+                         "\xb7\x9c\xd5\x15\xe5\x81\x7a\x4f"
+                         "\x4f\x4f\xe5\x77\xf2\x2e\x67\x68"
+                         "\x52\xc1\xac\x28\x2c\x88\xf4\x38",
+               .len    = 80,
+       }, {
+               .key    = "\x84\xa0\x53\x97\x61\x30\x70\x15"
+                         "\xac\x45\x8e\xe8\xeb\xa1\x72\x93"
+                         "\x26\x76\x98\x6f\xe4\x86\xca\xf0"
+                         "\x57\x89\xf2\x2b\xd4\xcf\x2d\x95",
+               .klen   = 32,
+               .iv     = "\x86\x26\x20\x0e\x62\xfe\x8f\x1e"
+                         "\x5d\xcb\x2b\x7e\xdd\xab\xac\xda",
+               .ptext  = "\x6e\x49\x20\xd5\xb7\x01\x83\x4e"
+                         "\xac\x45\x8f\xe1\x05\x3f\xd5\xb1"
+                         "\xee\xb7\x0d\x65\x00\x38\xab\x71"
+                         "\x70\x6e\xb3\x97\x86\xd3\xcd\xad"
+                         "\x51\x8b\x9c\xa0\x9a\x8b\x4c\xb9"
+                         "\x16\x01\x6a\x1f\xdf\xf0\xf9\x9e"
+                         "\x25\x1b\xc2\xa6\x21\x25\xeb\x97"
+                         "\x4b\xf6\xcb\x3b\xcd\x61\xfd\x94"
+                         "\x37\x03\xb3\xd9\x74\x6e\x4d\xbb"
+                         "\xfd\x87\x2b\xec\x4c\x2c\xbf\xe2"
+                         "\x94\x1a\xe6\xd9\xaf\x0e\x78\x17"
+                         "\x58\x2b\x1d\x73\x9a\x9c\x63\x18",
+               .ctext  = "\xd1\xce\xbe\xe0\x4a\x6e\x6d\x7f"
+                         "\x89\x19\x28\xb1\xca\xe8\xc1\x9c"
+                         "\x8c\x0b\x7d\x63\xfe\xff\x3d\xf4"
+                         "\x65\x9e\xd6\xe7\x2f\x5a\xc1\x31"
+                         "\x1e\xe7\x59\x27\x54\x92\xcc\xaa"
+                         "\x5b\x3d\xeb\xe7\x96\xc1\x49\x54"
+                         "\x18\xf3\x14\xaa\x56\x03\x28\x53"
+                         "\xaa\x0a\x91\xdf\x92\x96\x9b\x06"
+                         "\x1a\x24\x02\x09\xe7\xa6\xdc\x75"
+                         "\xeb\x00\x1d\xf5\xf2\xa7\x4a\x9d"
+                         "\x75\x80\xb7\x47\x63\xfc\xad\x18"
+                         "\x85\x5f\xfc\x64\x03\x72\x38\xe7",
+               .len    = 96,
+       }, {
+               .key    = "\x88\x7a\x0e\x87\x2f\xf0\xb0\xdb"
+                         "\xc9\x9d\x79\x51\x34\x39\x4f\x07"
+                         "\xa2\x7c\x21\x04\x91\x3b\x79\x79"
+                         "\xfe\xd5\x51\x46\xd5\xcd\x28\xc0",
+               .klen   = 32,
+               .iv     = "\xad\xb8\x55\xb2\xb2\x5a\x9a\xa2"
+                         "\xe2\x0c\xfc\x55\x7d\x60\xd2\x95",
+               .ptext  = "\xb6\x08\x1d\x31\xaf\xf4\x17\x46"
+                         "\xa4\xbb\x0f\xbd\x67\x3c\x73\x15"
+                         "\x0c\x85\x2f\x62\xe5\xf4\x35\x96"
+                         "\xb1\x9b\x5d\x00\x10\xe9\x70\x12"
+                         "\x3a\x87\x7f\x67\xf1\x81\x7a\x05"
+                         "\xb4\xa6\xfe\xdf\x36\x31\x6d\x9e"
+                         "\x0e\xa9\x44\xa0\xb0\x05\xa9\x41"
+                         "\x9c\x14\x44\x5a\xd5\x1c\x50\x08"
+                         "\x95\xc2\xf2\xaf\x3f\x29\xc9\x3e"
+                         "\x95\x5e\xc6\xb4\x2b\xf4\x3e\xe3"
+                         "\x1b\xeb\x3d\x73\xfb\xd7\x1e\x2b"
+                         "\x0c\x3d\x58\x6c\xb4\x41\x9b\xfe"
+                         "\x2f\x7e\x1c\x10\x81\x36\x2d\x79"
+                         "\xaf\xab\x10\x44\x2e\xcc\x0d\x6c",
+               .ctext  = "\x0b\x07\xdc\x6a\x47\x45\xd2\xb0"
+                         "\xa3\xf2\x42\x2f\xa4\x79\x6b\x4c"
+                         "\x53\x9c\x8a\x2f\x48\x9c\xf2\x89"
+                         "\x73\x8b\xdd\x97\xde\x41\x06\xc8"
+                         "\x8a\x30\x7a\xa9\x90\x4a\x43\xd0"
+                         "\xd5\xee\x16\x51\x44\xda\xe4\xb8"
+                         "\xe8\x5f\x6f\xef\x84\xf3\x44\x43"
+                         "\xbd\xdc\xc3\xdf\x65\x2b\xaf\xf6"
+                         "\xfe\xd0\x4a\x5b\x30\x47\x8c\xaf"
+                         "\x8d\xed\x2d\x91\xa1\x03\x9a\x80"
+                         "\x58\xdd\xaa\x8f\x3b\x6b\x39\x10"
+                         "\xe5\x92\xbc\xac\xaa\x25\xa1\x13"
+                         "\x7e\xaa\x03\x83\x05\x83\x11\xfe"
+                         "\x19\x5f\x04\x01\x48\x00\x3b\x58",
+               .len    = 112,
+       }, {
+               .key    = "\x9c\x14\xc2\xe4\xae\xb0\xbb\xda"
+                         "\x6a\xe0\x42\x3d\x96\x9f\x78\x7d"
+                         "\x70\x86\xa5\x92\x9f\xee\xcd\x3f"
+                         "\x6a\x55\x84\x98\x28\x03\x02\xc2",
+               .klen   = 32,
+               .iv     = "\xf7\xec\x7a\xfa\xb1\xd9\xa8\xd8"
+                         "\x1c\xc3\xaa\xd5\x61\x7f\x10\x0c",
+               .ptext  = "\xc0\xa1\x36\x3d\x81\x9a\xd2\x17"
+                         "\x2e\x23\xc9\xb7\xff\xdf\x47\x6c"
+                         "\x96\x3b\x0e\xbd\xec\x9a\x0e\xad"
+                         "\x8c\xaf\x36\x3d\xff\x29\x8b\x33"
+                         "\x87\x96\x77\x1a\x10\x81\x63\x8a"
+                         "\x63\xde\x88\xa9\x9d\xa9\x01\xf2"
+                         "\xdf\xc9\x25\x35\x48\x3a\x15\xdf"
+                         "\x20\x6b\x91\x7c\x56\xe5\x10\x7a"
+                         "\x2d\x2e\x0f\x30\x32\xed\xa9\x1f"
+                         "\x71\x4e\x68\x77\xe8\xa8\x5b\xdd"
+                         "\x3c\x5e\x68\x6b\xab\x03\xe4\xf8"
+                         "\x42\xc1\x61\x9a\x50\xfb\xc7\x6a"
+                         "\x1a\x31\xa7\x87\xd0\x24\xcb\x5e"
+                         "\xc0\x3b\x12\x28\xca\x26\x7b\xb3"
+                         "\x14\xc1\x7f\x66\xff\x3b\xa4\x80"
+                         "\x59\x77\x4f\xa0\xd4\xb2\xd9\x8a",
+               .ctext  = "\xfe\xba\x8f\x68\x47\x55\xaa\x61"
+                         "\x48\xdd\xf3\x7c\xc4\xdc\xa6\x93"
+                         "\x4e\x72\x3f\xc7\xd0\x2b\x9b\xac"
+                         "\xc1\xb5\x95\xf8\x8e\x75\x62\x0c"
+                         "\x05\x6a\x90\x76\x35\xed\x73\xf2"
+                         "\x0f\x44\x3d\xaf\xd4\x00\xeb\x1d"
+                         "\xad\x27\xf2\x2f\x55\x65\x91\x0f"
+                         "\xe4\x04\x9c\xfb\x8a\x18\x22\x8e"
+                         "\x21\xbe\x93\x09\xdd\x3e\x93\x34"
+                         "\x60\x82\xcd\xff\x42\x10\xed\x43"
+                         "\x3a\x4b\xb8\x5c\x6c\xa8\x9e\x1c"
+                         "\x95\x6a\x17\xa7\xa3\xe0\x7d\xdb"
+                         "\x6e\xca\xaf\xc1\x1f\xb2\x86\x15"
+                         "\xf0\xc1\x55\x72\xf2\x74\x44\xeb"
+                         "\x09\x09\x83\x8b\x2c\xc9\x63\x13"
+                         "\x99\xe3\xe1\x4b\x5c\xf7\xb1\x04",
+               .len    = 128,
+       }, {
+               .key    = "\xb6\x67\xe6\x28\xd3\x6f\xf2\xcf"
+                         "\xb8\x6d\x2d\xc4\x2a\x69\x89\xff"
+                         "\xcf\xbb\x11\x2e\x2a\x2b\x7c\xfd"
+                         "\xcd\x56\x02\x95\xc9\x54\x6e\x62",
+               .klen   = 32,
+               .iv     = "\x6a\x97\x75\x1a\x21\x16\x46\xfb"
+                         "\xc2\xab\x62\x54\xef\xba\xae\x46",
+               .ptext  = "\xd4\x14\xc6\xcc\x16\x1b\x95\xf9"
+                         "\x05\x26\x23\x81\x19\x27\xad\x7b"
+                         "\x9c\x8b\xfb\x65\xa4\x61\xee\x69"
+                         "\x44\xbf\x59\xde\x03\x61\x11\x12"
+                         "\x8d\x94\x48\x47\xa9\x52\x16\xfb"
+                         "\x6b\xaf\x59\x6d\xab\x74\xbf\x5c"
+                         "\xb6\x09\x21\x12\x42\x98\x13\xa1"
+                         "\xa8\x6f\xb9\x6d\x4d\xa6\xdc\xea"
+                         "\x61\x02\x3c\xa7\xcd\x1a\x28\x8c"
+                         "\x66\xb8\x4d\x60\x67\x82\xcc\x8d"
+                         "\x1e\xda\x8f\x28\xe5\x02\xdc\x2c"
+                         "\x54\x84\x2a\x06\xb5\xd1\x34\x57"
+                         "\xb8\x28\x4d\xf5\x69\xb9\xf3\x33"
+                         "\x5e\x0b\xa6\x62\x35\x9b\xfb\x97"
+                         "\x3e\xc6\xec\xaf\x74\xe8\x72\x91"
+                         "\xb2\xc6\x56\xb3\x23\x29\x43\xe0"
+                         "\xfb\xcc\x21\x38\x64\x78\x9e\x78"
+                         "\xbb\x6e\x0d\x7b\xfd\x05\x74\x01",
+               .ctext  = "\xa5\x19\x33\xad\x2d\x1a\x7b\x34"
+                         "\xb0\x21\x68\x0e\x20\x11\x7a\x37"
+                         "\xef\x35\x33\x64\x31\x0a\x42\x77"
+                         "\x2c\x7f\x1a\x34\xd6\x93\x2d\xe9"
+                         "\x26\xb9\x15\xec\x4f\x83\xbd\x48"
+                         "\x5b\xe9\x63\xea\x10\x3b\xec\xfb"
+                         "\xb0\x5e\x81\x90\xf0\x07\x43\xc4"
+                         "\xda\x54\x69\x98\x13\x5d\x93\x16"
+                         "\xca\x06\x81\x64\x36\xbe\x36\xa2"
+                         "\xd4\xd8\x48\x63\xc7\x53\x39\x93"
+                         "\x6d\x6b\xd6\x49\x00\x72\x5e\x02"
+                         "\xc7\x88\x61\x0f\x10\x88\xd4\x9e"
+                         "\x17\x81\xa4\xdc\x43\x4e\x83\x43"
+                         "\xd4\xc3\xd7\x25\x9a\xd4\x76\xde"
+                         "\x88\xe3\x98\x5a\x0e\x80\x23\xfb"
+                         "\x49\xb3\x83\xf6\xb9\x16\x00\x06"
+                         "\xa5\x06\x24\x17\x65\xbb\x68\xa9"
+                         "\x56\x6d\xeb\xcd\x3c\x14\xd2\x64",
+               .len    = 144,
+       }, {
+               .key    = "\x7c\x94\xe0\xb0\xd7\x92\xfc\x58"
+                         "\x28\xfc\xe2\x7b\x7f\xf7\x31\x0d"
+                         "\x90\xb7\x60\x78\xa8\x9f\x52\xe3"
+                         "\xe6\xaa\x2a\xb4\xa7\x09\x60\x53",
+               .klen   = 32,
+               .iv     = "\x42\x0e\x15\x31\xf6\x48\xa3\x0a"
+                         "\x20\xf0\x79\x67\xb1\x83\x26\x66",
+               .ptext  = "\xe0\xb1\xb3\xbd\x1c\x76\x36\xfd"
+                         "\x45\x87\xa4\x14\x1b\xef\xe7\x16"
+                         "\xf7\xfa\x30\x3d\xb9\x52\x8f\x2e"
+                         "\x01\x68\xc1\x7d\xa2\x15\x49\x74"
+                         "\x53\x82\xc2\x10\xa8\x45\x73\x4d"
+                         "\x41\xcc\x24\xa3\x42\xff\x30\xd1"
+                         "\x02\x21\xdc\xd9\x08\xf7\xe7\x4c"
+                         "\x33\x2d\x62\xc7\x38\xf5\xc2\xbe"
+                         "\x52\xf1\x34\x78\x34\x53\x30\x5b"
+                         "\x43\x43\x51\x6a\x02\x81\x64\x0c"
+                         "\xcd\x4b\xbf\x0f\xcb\x81\xd4\xec"
+                         "\x1e\x07\x05\x4d\x5c\x6b\xba\xcc"
+                         "\x43\xc7\xb1\xfe\xa8\xe9\x96\xb0"
+                         "\xb1\xb2\xd4\x70\x44\xbc\xaa\x50"
+                         "\xbf\x3f\x81\xe6\xea\x36\x7d\x97"
+                         "\x2a\xbd\x52\x16\xf7\xbe\x59\x27"
+                         "\x8f\xcc\xe3\xa9\xec\x4f\xcd\xd3"
+                         "\xf4\xe2\x54\xbe\xf1\xf9\x2b\x23"
+                         "\x40\xc7\xcb\x67\x4d\x5f\x0b\xd4"
+                         "\xbf\x19\xf0\x2a\xef\x37\xc6\x56",
+               .ctext  = "\x0a\x69\xd8\x67\x33\x2a\x2f\xa9"
+                         "\x26\x79\x65\xd6\x75\x1e\x98\xe8"
+                         "\x52\x56\x32\xbf\x67\x71\xf4\x01"
+                         "\xb1\x6f\xef\xf9\xc9\xad\xb3\x49"
+                         "\x7a\x4f\x24\x9a\xae\x06\x62\x26"
+                         "\x3e\xe4\xa7\x6f\x5a\xbf\xe9\x52"
+                         "\x13\x01\x74\x8b\x6e\xb1\x65\x24"
+                         "\xaa\x8d\xbb\x54\x21\x20\x60\xa4"
+                         "\xb7\xa5\xf9\x4e\x7b\xf5\x0b\x70"
+                         "\xd2\xb9\xdc\x9b\xdb\x2c\xb2\x43"
+                         "\xf7\x71\x30\xa5\x13\x6f\x16\x75"
+                         "\xd0\xdf\x72\xae\xe4\xed\xc1\xa3"
+                         "\x81\xe0\xd5\xc0\x0e\x62\xe8\xe5"
+                         "\x86\x2c\x37\xde\xf8\xb0\x21\xe4"
+                         "\xcd\xa6\x76\x9b\xa1\x56\xd3\x67"
+                         "\x70\x69\xd6\x5d\xc7\x65\x19\x59"
+                         "\x43\x9c\xca\x32\xe9\xd1\x48\x92"
+                         "\x71\x79\x87\x73\x24\xcb\xc0\x0f"
+                         "\x23\x3b\x8f\x51\x8a\xb3\x3a\x9c"
+                         "\x74\xa4\x19\xa7\xe4\x4f\x6b\x32",
+               .len    = 160,
+       }
+};
+
+static const struct cipher_testvec aria_ctr_tv_template[] = {
+       {
+               .key    = "\x7f\x92\xd5\x06\x30\x6b\xc0\x23"
+                         "\x87\xa8\x8e\x6d\xc7\xc5\xd7\xf1",
+               .klen   = 16,
+               .iv     = "\x5f\xce\x89\xb3\xd5\x7f\x7f\xf0"
+                         "\xfd\xab\x56\xa6\x6e\xda\x7c\x57",
+               .ptext  = "\x36\x36\x89\x09\xcd\xa8\xd3\x91"
+                         "\x48\x3e\x3c\x11\xcf\xd0\x4f\xc0",
+               .ctext  = "\x19\x28\xb5\xf2\x1c\xbc\xf8\xaf"
+                         "\xb9\xae\x1b\x23\x4f\xe1\x6e\x40",
+               .len    = 16,
+       }, {
+               .key    = "\x51\xe3\x8c\xe9\x76\xcd\xff\x37"
+                         "\xd6\x1a\x18\x2f\x68\x2f\xb6\xfe",
+               .klen   = 16,
+               .iv     = "\x3d\x2d\x85\x75\x6e\x18\x8a\x52"
+                         "\x53\x39\xfc\xc1\xf5\xc0\x56\x22",
+               .ptext  = "\xc6\xae\xaa\x0d\x90\xf2\x38\x93"
+                         "\xac\xd2\x3f\xc7\x74\x8d\x13\x7e"
+                         "\xfa\x3f\x70\x52\xfb\x04\x0e\xed"
+                         "\x0e\x60\x75\x84\x21\xdf\x13\xa1",
+               .ctext  = "\x3f\x8c\xa9\x19\xd6\xb4\xfb\xed"
+                         "\x9c\x6d\xaa\x1b\xe1\xc1\xe6\xa8"
+                         "\xa9\x0a\x63\xd3\xa2\x1e\x6b\xa8"
+                         "\x52\x97\x1e\x81\x34\x6f\x98\x0e",
+               .len    = 32,
+       }, {
+               .key    = "\x26\xf8\x8c\x26\x0a\x37\x51\x8f"
+                         "\xe7\x9c\x74\x77\x7a\x3e\xbb\x5d",
+               .klen   = 16,
+               .iv     = "\xd7\x33\xf3\xa9\x5b\xb4\x86\xea"
+                         "\xe3\x7d\x50\x62\x3b\x73\xaf\xc4",
+               .ptext  = "\xda\x89\xd9\x3c\xcc\xe4\x73\xb0"
+                         "\xef\x3e\x5f\x46\x62\x88\xd5\x26"
+                         "\x3b\xd3\xb5\x81\x78\x70\x1b\xd2"
+                         "\x39\x56\x34\x63\x2c\xc5\x51\x13"
+                         "\x48\x29\x3a\x58\xbe\x41\xc5\x80"
+                         "\x2c\x80\xa7\x3c\x14\xb4\x89\x5e",
+               .ctext  = "\x28\xd8\xa7\xf8\x74\x98\x00\xfc"
+                         "\xd6\x48\xad\xbd\xbe\x3f\x0e\x7b"
+                         "\x3d\x46\xfd\xde\x3e\x4f\x12\x43"
+                         "\xac\x85\xda\xff\x70\x24\x44\x9d"
+                         "\x1e\xf8\x9f\x30\xba\xca\xe0\x97"
+                         "\x03\x6d\xe1\x1d\xc7\x21\x79\x37",
+               .len    = 48,
+       }, {
+               .key    = "\x8e\xe5\x5f\xe2\x39\x80\xf5\x2b"
+                         "\x77\xb5\xca\x90\xda\x1d\x22\x17",
+               .klen   = 16,
+               .iv     = "\xd9\xa0\x57\x80\xc8\x96\x70\x86"
+                         "\x07\x2c\xf4\x61\x79\x09\x01\x8f",
+               .ptext  = "\x37\x32\x98\xd4\x86\x2b\x3b\x80"
+                         "\x07\x60\xba\xf0\x2e\xc3\x4a\x57"
+                         "\xf5\xb5\xd7\xbf\xd2\x2a\x9b\x4a"
+                         "\xe6\x08\xf0\xbe\x77\xd1\x62\x40"
+                         "\xa0\x82\x09\x60\x47\xbb\x16\x56"
+                         "\x50\x1f\xab\x8b\x10\xfe\xf0\x5c"
+                         "\x05\x32\x63\x1a\xc4\x46\x6f\x55"
+                         "\x32\xde\x41\x5a\xf7\x52\xd7\xfa",
+               .ctext  = "\x29\x31\x55\xd2\xe5\x0b\x81\x39"
+                         "\xf9\xbc\x63\xe2\xfa\x26\x99\xde"
+                         "\xde\x18\x93\x68\x81\x7b\x0a\x4d"
+                         "\xf6\x03\xe1\xee\xf9\x0e\x1f\xe8"
+                         "\xa8\x80\x81\x46\xdc\x24\x43\x3f"
+                         "\xff\xfe\x8c\x3e\x17\x0a\x6d\xa2"
+                         "\x47\x55\x62\xa0\x03\x4e\x48\x67"
+                         "\xa2\x64\xc0\x9b\x6c\xa4\xfd\x6a",
+               .len    = 64,
+       }, {
+               .key    = "\x30\x9d\x59\x8d\x64\x76\xad\x37"
+                         "\xba\xbc\x46\x6a\x69\x17\x3c\xac",
+               .klen   = 16,
+               .iv     = "\x6f\xdd\xa2\x9b\x86\x32\x14\x2e"
+                         "\x54\x74\x8f\x3d\xe2\xd6\x85\x44",
+               .ptext  = "\x4f\x4a\x31\x64\xc6\xa5\x29\xaa"
+                         "\xad\xfd\x32\x94\x1f\x56\x57\xd1"
+                         "\x9d\x7e\x3d\x49\x00\x36\xb1\x5d"
+                         "\xb2\x92\x83\x70\x1e\xa3\x97\xa6"
+                         "\x65\x53\x39\xeb\x53\x8f\xb1\x38"
+                         "\x91\xac\x17\x11\x1c\x03\x69\x53"
+                         "\xf5\xdf\xdb\x2c\x1b\x9a\x6e\x6b"
+                         "\xb6\x02\xc4\xfa\x95\x01\x33\xa8"
+                         "\xda\x7e\x18\x2c\xf4\x7e\x6e\x67"
+                         "\xce\x8f\x9f\xea\x46\x66\x99\xb8",
+               .ctext  = "\x38\xbc\xf5\x9d\x0e\x26\xa6\x18"
+                         "\x95\x0b\x23\x54\x09\xa1\xf9\x46"
+                         "\x12\xf1\x42\x57\xa1\xaa\x52\xfa"
+                         "\x8a\xbd\xf2\x03\x63\x4e\xbc\xf7"
+                         "\x21\xea\xed\xca\xdd\x42\x41\x94"
+                         "\xe4\x6c\x07\x06\x19\x59\x30\xff"
+                         "\x8c\x9d\x51\xbf\x2c\x2e\x5b\xa5"
+                         "\x7d\x11\xec\x6b\x21\x08\x12\x18"
+                         "\xe4\xdf\x5a\xfd\xa6\x5f\xee\x2f"
+                         "\x5c\x24\xb7\xea\xc1\xcd\x6d\x68",
+               .len    = 80,
+       }, {
+               .key    = "\xe1\xc7\x25\x4d\xbd\xa5\x74\xdf"
+                         "\xc7\x8b\xfb\xe3\x2d\x3a\x82\xd3",
+               .klen   = 16,
+               .iv     = "\x17\x94\x77\x2f\x92\xb8\x87\xc2"
+                         "\xcc\x6f\x70\x26\x87\xc7\x10\x8a",
+               .ptext  = "\xc8\xfd\xc2\xb3\xcf\xa0\xeb\x41"
+                         "\x4c\xf4\xd0\x34\xd0\x95\xab\xae"
+                         "\x82\x5c\xfd\xfa\x13\x86\x25\xce"
+                         "\xf4\x13\x32\xcd\xc6\x6d\xf6\x50"
+                         "\x12\x4a\x5b\x66\x3a\xd3\xfb\x1a"
+                         "\xaf\x06\xea\xf4\x65\x59\xd6\xc2"
+                         "\x84\xa0\x53\x97\x61\x30\x70\x15"
+                         "\xac\x45\x8e\xe8\xeb\xa1\x72\x93"
+                         "\x26\x76\x98\x6f\xe4\x86\xca\xf0"
+                         "\x57\x89\xf2\x2b\xd4\xcf\x2d\x95"
+                         "\x86\x26\x20\x0e\x62\xfe\x8f\x1e"
+                         "\x5d\xcb\x2b\x7e\xdd\xab\xac\xda",
+               .ctext  = "\xdf\x79\x58\x30\x6f\x47\x12\x78"
+                         "\x04\xb2\x0b\x1a\x62\x22\xe2\x9f"
+                         "\xfe\xc2\xf5\x6d\x9e\x0e\x2e\x56"
+                         "\x76\x01\x7f\x25\x8f\x6e\xc5\xf3"
+                         "\x91\xff\xcd\x67\xc6\xae\x0b\x01"
+                         "\x4d\x5f\x40\x25\x88\xc5\xe0\x3d"
+                         "\x37\x62\x12\x58\xfe\xc5\x4a\x21"
+                         "\x4a\x86\x8d\x94\xdd\xfd\xe6\xf6"
+                         "\x1e\xa6\x78\x4f\x90\x66\xda\xe4"
+                         "\x4e\x64\xa8\x05\xc6\xd8\x7d\xfb"
+                         "\xac\xc9\x1d\x14\xb5\xb0\xfa\x9c"
+                         "\xe8\x84\xef\x87\xbe\xb4\x2a\x87",
+               .len    = 96,
+       }, {
+               .key    = "\x6e\x49\x20\xd5\xb7\x01\x83\x4e"
+                         "\xac\x45\x8f\xe1\x05\x3f\xd5\xb1",
+               .klen   = 16,
+               .iv     = "\xee\xb7\x0d\x65\x00\x38\xab\x71"
+                         "\x70\x6e\xb3\x97\x86\xd3\xcd\xad",
+               .ptext  = "\x51\x8b\x9c\xa0\x9a\x8b\x4c\xb9"
+                         "\x16\x01\x6a\x1f\xdf\xf0\xf9\x9e"
+                         "\x25\x1b\xc2\xa6\x21\x25\xeb\x97"
+                         "\x4b\xf6\xcb\x3b\xcd\x61\xfd\x94"
+                         "\x37\x03\xb3\xd9\x74\x6e\x4d\xbb"
+                         "\xfd\x87\x2b\xec\x4c\x2c\xbf\xe2"
+                         "\x94\x1a\xe6\xd9\xaf\x0e\x78\x17"
+                         "\x58\x2b\x1d\x73\x9a\x9c\x63\x18"
+                         "\x88\x7a\x0e\x87\x2f\xf0\xb0\xdb"
+                         "\xc9\x9d\x79\x51\x34\x39\x4f\x07"
+                         "\xa2\x7c\x21\x04\x91\x3b\x79\x79"
+                         "\xfe\xd5\x51\x46\xd5\xcd\x28\xc0"
+                         "\xad\xb8\x55\xb2\xb2\x5a\x9a\xa2"
+                         "\xe2\x0c\xfc\x55\x7d\x60\xd2\x95",
+               .ctext  = "\xe4\x25\x0d\x22\xeb\xbe\x5e\x90"
+                         "\x01\xe5\xae\xc9\x94\xbd\x93\x89"
+                         "\x5f\x98\xf1\x46\x6a\x50\x3b\xa2"
+                         "\x79\xd9\xe4\x9c\x9a\xde\xf2\x8c"
+                         "\x25\x49\x4c\xda\xb4\x2c\x76\xab"
+                         "\x0a\xa8\x51\xaf\xc0\x62\x1b\xe9"
+                         "\xe9\x7a\x35\x6a\x4b\x1f\x48\x00"
+                         "\xeb\x24\x1d\x5e\xdd\x06\x09\x23"
+                         "\x2a\xfa\x8f\x3b\x3e\x9e\x14\x6f"
+                         "\x2a\x3c\xef\x6d\x73\x67\xdd\x6c"
+                         "\xc8\xa5\x57\xc8\x02\xb6\x9a\xe8"
+                         "\x8d\xcf\x10\xfa\x3e\x9c\x4d\xeb"
+                         "\x44\xd2\x05\x31\x40\x94\x77\x87"
+                         "\xf0\x83\xb5\xd2\x2a\x9c\xbc\xe4",
+               .len    = 112,
+       }, {
+               .key    = "\xb6\x08\x1d\x31\xaf\xf4\x17\x46"
+                         "\xa4\xbb\x0f\xbd\x67\x3c\x73\x15",
+               .klen   = 16,
+               .iv     = "\x0c\x85\x2f\x62\xe5\xf4\x35\x96"
+                         "\xb1\x9b\x5d\x00\x10\xe9\x70\x12",
+               .ptext  = "\x3a\x87\x7f\x67\xf1\x81\x7a\x05"
+                         "\xb4\xa6\xfe\xdf\x36\x31\x6d\x9e"
+                         "\x0e\xa9\x44\xa0\xb0\x05\xa9\x41"
+                         "\x9c\x14\x44\x5a\xd5\x1c\x50\x08"
+                         "\x95\xc2\xf2\xaf\x3f\x29\xc9\x3e"
+                         "\x95\x5e\xc6\xb4\x2b\xf4\x3e\xe3"
+                         "\x1b\xeb\x3d\x73\xfb\xd7\x1e\x2b"
+                         "\x0c\x3d\x58\x6c\xb4\x41\x9b\xfe"
+                         "\x2f\x7e\x1c\x10\x81\x36\x2d\x79"
+                         "\xaf\xab\x10\x44\x2e\xcc\x0d\x6c"
+                         "\x9c\x14\xc2\xe4\xae\xb0\xbb\xda"
+                         "\x6a\xe0\x42\x3d\x96\x9f\x78\x7d"
+                         "\x70\x86\xa5\x92\x9f\xee\xcd\x3f"
+                         "\x6a\x55\x84\x98\x28\x03\x02\xc2"
+                         "\xf7\xec\x7a\xfa\xb1\xd9\xa8\xd8"
+                         "\x1c\xc3\xaa\xd5\x61\x7f\x10\x0c",
+               .ctext  = "\xa7\x4c\x96\x55\x7c\x07\xce\xb2"
+                         "\x6f\x63\x9f\xc6\x8b\x6f\xc6\x4a"
+                         "\x2c\x47\x8d\x99\xdf\x65\x75\x96"
+                         "\xb7\x1d\x50\x5b\x57\x4a\x69\xcc"
+                         "\xc9\x3a\x18\x8a\xd1\xab\x70\x4a"
+                         "\xa3\x13\x80\xdd\x48\xc0\x6a\x7d"
+                         "\x21\xa8\x22\x06\x32\x47\xc0\x16"
+                         "\x1f\x9a\xc0\x21\x33\x66\xf2\xd8"
+                         "\x69\x79\xae\x02\x82\x3f\xaf\xa6"
+                         "\x98\xdb\xcd\x2a\xe5\x12\x39\x80"
+                         "\x8a\xc1\x73\x99\xe5\xe4\x17\xe3"
+                         "\x56\xc2\x43\xa6\x41\x6b\xb2\xa4"
+                         "\x9f\x81\xc4\xe9\xf4\x29\x65\x50"
+                         "\x69\x81\x80\x4b\x86\xab\x5e\x30"
+                         "\xd0\x81\x9d\x6f\x24\x59\x42\xc7"
+                         "\x6d\x5e\x41\xb8\xf5\x99\xc2\xae",
+               .len    = 128,
+       }, {
+               .key    = "\xc0\xa1\x36\x3d\x81\x9a\xd2\x17"
+                         "\x2e\x23\xc9\xb7\xff\xdf\x47\x6c",
+               .klen   = 16,
+               .iv     = "\x96\x3b\x0e\xbd\xec\x9a\x0e\xad"
+                         "\x8c\xaf\x36\x3d\xff\x29\x8b\x33",
+               .ptext  = "\x87\x96\x77\x1a\x10\x81\x63\x8a"
+                         "\x63\xde\x88\xa9\x9d\xa9\x01\xf2"
+                         "\xdf\xc9\x25\x35\x48\x3a\x15\xdf"
+                         "\x20\x6b\x91\x7c\x56\xe5\x10\x7a"
+                         "\x2d\x2e\x0f\x30\x32\xed\xa9\x1f"
+                         "\x71\x4e\x68\x77\xe8\xa8\x5b\xdd"
+                         "\x3c\x5e\x68\x6b\xab\x03\xe4\xf8"
+                         "\x42\xc1\x61\x9a\x50\xfb\xc7\x6a"
+                         "\x1a\x31\xa7\x87\xd0\x24\xcb\x5e"
+                         "\xc0\x3b\x12\x28\xca\x26\x7b\xb3"
+                         "\x14\xc1\x7f\x66\xff\x3b\xa4\x80"
+                         "\x59\x77\x4f\xa0\xd4\xb2\xd9\x8a"
+                         "\xb6\x67\xe6\x28\xd3\x6f\xf2\xcf"
+                         "\xb8\x6d\x2d\xc4\x2a\x69\x89\xff"
+                         "\xcf\xbb\x11\x2e\x2a\x2b\x7c\xfd"
+                         "\xcd\x56\x02\x95\xc9\x54\x6e\x62"
+                         "\x6a\x97\x75\x1a\x21\x16\x46\xfb"
+                         "\xc2\xab\x62\x54\xef\xba\xae\x46",
+               .ctext  = "\x11\x7f\xea\x49\xaf\x24\x52\xa2"
+                         "\xde\x60\x99\x58\x23\xf9\x9e\x91"
+                         "\x73\xd5\x9a\xcb\xdd\x10\xcd\x68"
+                         "\xb8\x9e\xef\xa4\xe9\x2d\xf0\x27"
+                         "\x44\xd4\x9a\xd6\xb6\x9c\x7a\xec"
+                         "\x17\x17\xea\xa7\x8e\xa8\x40\x6b"
+                         "\x43\x3d\x50\x59\x0f\x74\x1b\x9e"
+                         "\x03\xed\x4f\x2f\xb8\xda\xef\xc3"
+                         "\x3f\x29\xb3\xf4\x5c\xcd\xce\x3c"
+                         "\xba\xfb\xc6\xd1\x1d\x6f\x61\x3a"
+                         "\x2b\xbd\xde\x30\xc5\x53\xe0\x6e"
+                         "\xbe\xae\x2f\x81\x13\x0f\xd2\xd5"
+                         "\x14\xda\xd3\x60\x9c\xf8\x00\x86"
+                         "\xe9\x97\x3e\x05\xb3\x95\xb3\x21"
+                         "\x1f\x3c\x56\xef\xcb\x32\x49\x5c"
+                         "\x89\xf1\x34\xe4\x8d\x7f\xde\x01"
+                         "\x1f\xd9\x25\x6d\x34\x1d\x6b\x71"
+                         "\xc9\xa9\xd6\x14\x1a\xf1\x44\x59",
+               .len    = 144,
+       }, {
+               .key    = "\xd4\x14\xc6\xcc\x16\x1b\x95\xf9"
+                         "\x05\x26\x23\x81\x19\x27\xad\x7b",
+               .klen   = 16,
+               .iv     = "\x9c\x8b\xfb\x65\xa4\x61\xee\x69"
+                         "\x44\xbf\x59\xde\x03\x61\x11\x12",
+               .ptext  = "\x8d\x94\x48\x47\xa9\x52\x16\xfb"
+                         "\x6b\xaf\x59\x6d\xab\x74\xbf\x5c"
+                         "\xb6\x09\x21\x12\x42\x98\x13\xa1"
+                         "\xa8\x6f\xb9\x6d\x4d\xa6\xdc\xea"
+                         "\x61\x02\x3c\xa7\xcd\x1a\x28\x8c"
+                         "\x66\xb8\x4d\x60\x67\x82\xcc\x8d"
+                         "\x1e\xda\x8f\x28\xe5\x02\xdc\x2c"
+                         "\x54\x84\x2a\x06\xb5\xd1\x34\x57"
+                         "\xb8\x28\x4d\xf5\x69\xb9\xf3\x33"
+                         "\x5e\x0b\xa6\x62\x35\x9b\xfb\x97"
+                         "\x3e\xc6\xec\xaf\x74\xe8\x72\x91"
+                         "\xb2\xc6\x56\xb3\x23\x29\x43\xe0"
+                         "\xfb\xcc\x21\x38\x64\x78\x9e\x78"
+                         "\xbb\x6e\x0d\x7b\xfd\x05\x74\x01"
+                         "\x7c\x94\xe0\xb0\xd7\x92\xfc\x58"
+                         "\x28\xfc\xe2\x7b\x7f\xf7\x31\x0d"
+                         "\x90\xb7\x60\x78\xa8\x9f\x52\xe3"
+                         "\xe6\xaa\x2a\xb4\xa7\x09\x60\x53"
+                         "\x42\x0e\x15\x31\xf6\x48\xa3\x0a"
+                         "\x20\xf0\x79\x67\xb1\x83\x26\x66",
+               .ctext  = "\x5b\xc0\xe8\x17\xa4\xf9\xea\xce"
+                         "\x9e\xf9\xe0\xb1\xac\x37\xe9\x41"
+                         "\x0b\x57\xc6\x55\x54\x50\xfa\xa9"
+                         "\x60\xaf\x7a\x4e\x98\x56\xde\x81"
+                         "\x14\xfc\xac\x21\x81\x3e\xf4\x0f"
+                         "\x40\x92\x30\xa8\x16\x88\x1a\xc3"
+                         "\xf1\x39\xbd\x0a\xb9\x44\xc8\x67"
+                         "\x8c\xaa\x2b\x45\x8b\x5b\x7b\x24"
+                         "\xd5\xd8\x9e\xd3\x59\xa5\xd7\x69"
+                         "\xdf\xf4\x50\xf9\x5f\x4f\x44\x1f"
+                         "\x2c\x75\x68\x6e\x3a\xa8\xae\x4b"
+                         "\x84\xf0\x42\x6c\xc0\x3c\x42\xaf"
+                         "\x87\x2b\x89\xe9\x51\x69\x16\x63"
+                         "\xc5\x62\x13\x05\x4c\xb2\xa9\x69"
+                         "\x01\x14\x73\x88\x8e\x41\x47\xb6"
+                         "\x68\x74\xbc\xe9\xad\xda\x94\xa1"
+                         "\x0c\x12\x8e\xd4\x38\x15\x02\x97"
+                         "\x27\x72\x4d\xdf\x61\xcc\x86\x3d"
+                         "\xd6\x32\x4a\xc3\xa9\x4c\x35\x4f"
+                         "\x5b\x91\x7d\x5c\x79\x59\xb3\xd5",
+               .len    = 160,
+       }, {
+               .key    = "\x7f\x92\xd5\x06\x30\x6b\xc0\x23"
+                         "\x87\xa8\x8e\x6d\xc7\xc5\xd7\xf1"
+                         "\x5f\xce\x89\xb3\xd5\x7f\x7f\xf0",
+               .klen   = 24,
+               .iv     = "\xfd\xab\x56\xa6\x6e\xda\x7c\x57"
+                         "\x36\x36\x89\x09\xcd\xa8\xd3\x91",
+               .ptext  = "\x48\x3e\x3c\x11\xcf\xd0\x4f\xc0"
+                         "\x51\xe3\x8c\xe9\x76\xcd\xff\x37",
+               .ctext  = "\xa4\x12\x2f\xc4\xf0\x6d\xd9\x46"
+                         "\xe4\xe6\xd1\x0b\x6d\x14\xf0\x8f",
+               .len    = 16,
+       }, {
+               .key    = "\xd6\x1a\x18\x2f\x68\x2f\xb6\xfe"
+                         "\x3d\x2d\x85\x75\x6e\x18\x8a\x52"
+                         "\x53\x39\xfc\xc1\xf5\xc0\x56\x22",
+               .klen   = 24,
+               .iv     = "\xc6\xae\xaa\x0d\x90\xf2\x38\x93"
+                         "\xac\xd2\x3f\xc7\x74\x8d\x13\x7e",
+               .ptext  = "\xfa\x3f\x70\x52\xfb\x04\x0e\xed"
+                         "\x0e\x60\x75\x84\x21\xdf\x13\xa1"
+                         "\x26\xf8\x8c\x26\x0a\x37\x51\x8f"
+                         "\xe7\x9c\x74\x77\x7a\x3e\xbb\x5d",
+               .ctext  = "\x80\x2b\xf0\x88\xb9\x4b\x8d\xf5"
+                         "\xc3\x0e\x15\x5b\xea\x5d\x5b\xa8"
+                         "\x07\x95\x78\x72\xc0\xb9\xbf\x25"
+                         "\x33\x22\xd1\x05\x56\x46\x62\x25",
+               .len    = 32,
+       }, {
+               .key    = "\xd7\x33\xf3\xa9\x5b\xb4\x86\xea"
+                         "\xe3\x7d\x50\x62\x3b\x73\xaf\xc4"
+                         "\xda\x89\xd9\x3c\xcc\xe4\x73\xb0",
+               .klen   = 24,
+               .iv     = "\xef\x3e\x5f\x46\x62\x88\xd5\x26"
+                         "\x3b\xd3\xb5\x81\x78\x70\x1b\xd2",
+               .ptext  = "\x39\x56\x34\x63\x2c\xc5\x51\x13"
+                         "\x48\x29\x3a\x58\xbe\x41\xc5\x80"
+                         "\x2c\x80\xa7\x3c\x14\xb4\x89\x5e"
+                         "\x8e\xe5\x5f\xe2\x39\x80\xf5\x2b"
+                         "\x77\xb5\xca\x90\xda\x1d\x22\x17"
+                         "\xd9\xa0\x57\x80\xc8\x96\x70\x86",
+               .ctext  = "\x65\x01\x3c\xb0\xac\x4c\x63\xb6"
+                         "\xe7\xf1\xf4\x61\x35\xf4\x36\xde"
+                         "\x7f\x85\xba\x41\xa8\xb0\x27\x11"
+                         "\x86\x2c\x71\x16\x05\x1d\xcf\x70"
+                         "\x35\xef\x23\x17\xfc\xed\x3f\x1a"
+                         "\x8e\xb3\xe5\xdb\x90\xb4\xb8\x35",
+               .len    = 48,
+       }, {
+               .key    = "\x07\x2c\xf4\x61\x79\x09\x01\x8f"
+                         "\x37\x32\x98\xd4\x86\x2b\x3b\x80"
+                         "\x07\x60\xba\xf0\x2e\xc3\x4a\x57",
+               .klen   = 24,
+               .iv     = "\xf5\xb5\xd7\xbf\xd2\x2a\x9b\x4a"
+                         "\xe6\x08\xf0\xbe\x77\xd1\x62\x40",
+               .ptext  = "\xa0\x82\x09\x60\x47\xbb\x16\x56"
+                         "\x50\x1f\xab\x8b\x10\xfe\xf0\x5c"
+                         "\x05\x32\x63\x1a\xc4\x46\x6f\x55"
+                         "\x32\xde\x41\x5a\xf7\x52\xd7\xfa"
+                         "\x30\x9d\x59\x8d\x64\x76\xad\x37"
+                         "\xba\xbc\x46\x6a\x69\x17\x3c\xac"
+                         "\x6f\xdd\xa2\x9b\x86\x32\x14\x2e"
+                         "\x54\x74\x8f\x3d\xe2\xd6\x85\x44",
+               .ctext  = "\x5a\xfb\xb1\x2c\x6e\xe5\xb8\xe0"
+                         "\x80\xb6\x77\xa8\xfe\x10\x3a\x99"
+                         "\x00\x8e\x30\x23\x7d\x50\x87\xda"
+                         "\xc6\x46\x73\x37\x8b\xf1\xab\x26"
+                         "\x2d\xa8\x0c\xa8\x9e\x77\xee\xfc"
+                         "\x78\x4f\x03\x0f\xeb\xc6\x03\x34"
+                         "\xb9\x9c\x4f\x59\x55\xc5\x99\x47"
+                         "\xd4\x7e\xe8\x06\x43\x5f\xa1\x6b",
+               .len    = 64,
+       }, {
+               .key    = "\x4f\x4a\x31\x64\xc6\xa5\x29\xaa"
+                         "\xad\xfd\x32\x94\x1f\x56\x57\xd1"
+                         "\x9d\x7e\x3d\x49\x00\x36\xb1\x5d",
+               .klen   = 24,
+               .iv     = "\xb2\x92\x83\x70\x1e\xa3\x97\xa6"
+                         "\x65\x53\x39\xeb\x53\x8f\xb1\x38",
+               .ptext  = "\x91\xac\x17\x11\x1c\x03\x69\x53"
+                         "\xf5\xdf\xdb\x2c\x1b\x9a\x6e\x6b"
+                         "\xb6\x02\xc4\xfa\x95\x01\x33\xa8"
+                         "\xda\x7e\x18\x2c\xf4\x7e\x6e\x67"
+                         "\xce\x8f\x9f\xea\x46\x66\x99\xb8"
+                         "\xe1\xc7\x25\x4d\xbd\xa5\x74\xdf"
+                         "\xc7\x8b\xfb\xe3\x2d\x3a\x82\xd3"
+                         "\x17\x94\x77\x2f\x92\xb8\x87\xc2"
+                         "\xcc\x6f\x70\x26\x87\xc7\x10\x8a"
+                         "\xc8\xfd\xc2\xb3\xcf\xa0\xeb\x41",
+               .ctext  = "\xc9\x5f\xe0\x60\x61\x38\x7e\x79"
+                         "\x52\x68\x64\x8f\x55\x9b\x6b\x72"
+                         "\xbf\x09\xef\x2f\xb2\x92\xbb\xa3"
+                         "\xe1\x6a\xeb\xe6\x4e\x7c\x5d\xe0"
+                         "\x6a\x4b\xd0\x57\x3b\x28\x8a\x83"
+                         "\x75\xd4\x5a\x2e\xd1\x9a\x57\xe3"
+                         "\xc5\x43\x36\xde\x02\xac\x2c\x75"
+                         "\xea\x33\x3a\x7e\x5d\xb8\xf6\x12"
+                         "\x42\xbd\x06\x8a\x09\x6b\xd6\xb6"
+                         "\x25\x59\xcd\xbd\x17\xeb\x69\xb3",
+               .len    = 80,
+       }, {
+               .key    = "\x4c\xf4\xd0\x34\xd0\x95\xab\xae"
+                         "\x82\x5c\xfd\xfa\x13\x86\x25\xce"
+                         "\xf4\x13\x32\xcd\xc6\x6d\xf6\x50",
+               .klen   = 24,
+               .iv     = "\x12\x4a\x5b\x66\x3a\xd3\xfb\x1a"
+                         "\xaf\x06\xea\xf4\x65\x59\xd6\xc2",
+               .ptext  = "\x84\xa0\x53\x97\x61\x30\x70\x15"
+                         "\xac\x45\x8e\xe8\xeb\xa1\x72\x93"
+                         "\x26\x76\x98\x6f\xe4\x86\xca\xf0"
+                         "\x57\x89\xf2\x2b\xd4\xcf\x2d\x95"
+                         "\x86\x26\x20\x0e\x62\xfe\x8f\x1e"
+                         "\x5d\xcb\x2b\x7e\xdd\xab\xac\xda"
+                         "\x6e\x49\x20\xd5\xb7\x01\x83\x4e"
+                         "\xac\x45\x8f\xe1\x05\x3f\xd5\xb1"
+                         "\xee\xb7\x0d\x65\x00\x38\xab\x71"
+                         "\x70\x6e\xb3\x97\x86\xd3\xcd\xad"
+                         "\x51\x8b\x9c\xa0\x9a\x8b\x4c\xb9"
+                         "\x16\x01\x6a\x1f\xdf\xf0\xf9\x9e",
+               .ctext  = "\x03\x2c\x39\x24\x99\xb5\xf6\x79"
+                         "\x91\x89\xb7\xf8\x89\x68\x37\x9d"
+                         "\xe7\x4d\x7d\x1c\x36\xae\x98\xd2"
+                         "\xbf\x2a\xa4\x30\x38\x30\xe7\x5d"
+                         "\xbb\x00\x09\x40\x34\xa4\xef\x82"
+                         "\x23\xca\x0e\xb3\x71\x80\x29\x0a"
+                         "\xa9\x0b\x26\x65\x9a\x12\xbf\x18"
+                         "\xfb\xf8\xe4\xc2\x62\x57\x18\xfb"
+                         "\x1e\x98\xea\x5b\xf6\xd6\x7c\x52"
+                         "\x7a\xba\x0e\x6a\x54\x19\xb6\xfa"
+                         "\xe5\xd7\x60\x40\xb0\x1a\xf1\x09"
+                         "\x70\x96\x23\x49\x98\xfc\x79\xd2",
+               .len    = 96,
+       }, {
+               .key    = "\x25\x1b\xc2\xa6\x21\x25\xeb\x97"
+                         "\x4b\xf6\xcb\x3b\xcd\x61\xfd\x94"
+                         "\x37\x03\xb3\xd9\x74\x6e\x4d\xbb",
+               .klen   = 24,
+               .iv     = "\xfd\x87\x2b\xec\x4c\x2c\xbf\xe2"
+                         "\x94\x1a\xe6\xd9\xaf\x0e\x78\x17",
+               .ptext  = "\x58\x2b\x1d\x73\x9a\x9c\x63\x18"
+                         "\x88\x7a\x0e\x87\x2f\xf0\xb0\xdb"
+                         "\xc9\x9d\x79\x51\x34\x39\x4f\x07"
+                         "\xa2\x7c\x21\x04\x91\x3b\x79\x79"
+                         "\xfe\xd5\x51\x46\xd5\xcd\x28\xc0"
+                         "\xad\xb8\x55\xb2\xb2\x5a\x9a\xa2"
+                         "\xe2\x0c\xfc\x55\x7d\x60\xd2\x95"
+                         "\xb6\x08\x1d\x31\xaf\xf4\x17\x46"
+                         "\xa4\xbb\x0f\xbd\x67\x3c\x73\x15"
+                         "\x0c\x85\x2f\x62\xe5\xf4\x35\x96"
+                         "\xb1\x9b\x5d\x00\x10\xe9\x70\x12"
+                         "\x3a\x87\x7f\x67\xf1\x81\x7a\x05"
+                         "\xb4\xa6\xfe\xdf\x36\x31\x6d\x9e"
+                         "\x0e\xa9\x44\xa0\xb0\x05\xa9\x41",
+               .ctext  = "\xd4\x9a\x04\x54\x05\xd2\xe6\x3f"
+                         "\xb0\xa4\x36\x5e\x1e\x9c\x35\xb0"
+                         "\xa6\x62\x35\x47\xf4\x4d\x08\x9e"
+                         "\x1c\x22\x91\x8e\x7f\x00\xa6\x3e"
+                         "\x0a\x04\x42\x0f\xc4\xa6\x5d\xe2"
+                         "\x49\x4c\x61\x12\xea\x9d\x7d\x7c"
+                         "\xfa\x93\x74\x6b\x79\x8c\xdb\xc6"
+                         "\x47\xf6\xea\x84\x3e\x97\x7d\x87"
+                         "\x40\x38\x92\xc7\x44\xef\xdf\x63"
+                         "\x29\xe4\x5b\x3a\x87\x22\xa1\x3f"
+                         "\x2b\x31\xb1\xa4\x0d\xea\xf3\x0b"
+                         "\xd7\x4f\xb6\x9c\xba\x40\xa3\x2f"
+                         "\x21\x2b\x05\xe4\xca\xef\x87\x04"
+                         "\xe6\xd0\x29\x2c\x29\x26\x57\xcd",
+               .len    = 112,
+       }, {
+               .key    = "\x9c\x14\x44\x5a\xd5\x1c\x50\x08"
+                         "\x95\xc2\xf2\xaf\x3f\x29\xc9\x3e"
+                         "\x95\x5e\xc6\xb4\x2b\xf4\x3e\xe3",
+               .klen   = 24,
+               .iv     = "\x1b\xeb\x3d\x73\xfb\xd7\x1e\x2b"
+                         "\x0c\x3d\x58\x6c\xb4\x41\x9b\xfe",
+               .ptext  = "\x2f\x7e\x1c\x10\x81\x36\x2d\x79"
+                         "\xaf\xab\x10\x44\x2e\xcc\x0d\x6c"
+                         "\x9c\x14\xc2\xe4\xae\xb0\xbb\xda"
+                         "\x6a\xe0\x42\x3d\x96\x9f\x78\x7d"
+                         "\x70\x86\xa5\x92\x9f\xee\xcd\x3f"
+                         "\x6a\x55\x84\x98\x28\x03\x02\xc2"
+                         "\xf7\xec\x7a\xfa\xb1\xd9\xa8\xd8"
+                         "\x1c\xc3\xaa\xd5\x61\x7f\x10\x0c"
+                         "\xc0\xa1\x36\x3d\x81\x9a\xd2\x17"
+                         "\x2e\x23\xc9\xb7\xff\xdf\x47\x6c"
+                         "\x96\x3b\x0e\xbd\xec\x9a\x0e\xad"
+                         "\x8c\xaf\x36\x3d\xff\x29\x8b\x33"
+                         "\x87\x96\x77\x1a\x10\x81\x63\x8a"
+                         "\x63\xde\x88\xa9\x9d\xa9\x01\xf2"
+                         "\xdf\xc9\x25\x35\x48\x3a\x15\xdf"
+                         "\x20\x6b\x91\x7c\x56\xe5\x10\x7a",
+               .ctext  = "\xbc\x57\x2a\x88\x0a\xd0\x06\x4f"
+                         "\xdb\x7b\x03\x9f\x97\x1a\x20\xfe"
+                         "\xdb\xdc\x8e\x7b\x68\x13\xc8\xf5"
+                         "\x06\xe3\xe0\x7e\xd3\x51\x21\x86"
+                         "\x4f\x32\xdb\x78\xe3\x26\xbe\x34"
+                         "\x52\x4c\x4e\x6b\x85\x52\x63\x8b"
+                         "\x8c\x5c\x0e\x33\xf5\xa3\x88\x2d"
+                         "\x04\xdc\x01\x2d\xbe\xa1\x48\x6d"
+                         "\x50\xf4\x16\xb1\xd7\x4d\x1e\x99"
+                         "\xa8\x1d\x54\xcb\x13\xf9\x85\x51"
+                         "\x18\x9f\xef\x45\x62\x5d\x48\xe5"
+                         "\x0c\x54\xf7\x7b\x33\x18\xce\xb0"
+                         "\xd5\x82\x1b\xe2\x91\xae\xdc\x09"
+                         "\xe2\x97\xa8\x27\x13\x78\xc6\xb8"
+                         "\x20\x06\x1a\x71\x5a\xb3\xbc\x1b"
+                         "\x69\x1f\xcd\x57\x70\xa7\x1e\x35",
+               .len    = 128,
+       }, {
+               .key    = "\x2d\x2e\x0f\x30\x32\xed\xa9\x1f"
+                         "\x71\x4e\x68\x77\xe8\xa8\x5b\xdd"
+                         "\x3c\x5e\x68\x6b\xab\x03\xe4\xf8",
+               .klen   = 24,
+               .iv     = "\x42\xc1\x61\x9a\x50\xfb\xc7\x6a"
+                         "\x1a\x31\xa7\x87\xd0\x24\xcb\x5e",
+               .ptext  = "\xc0\x3b\x12\x28\xca\x26\x7b\xb3"
+                         "\x14\xc1\x7f\x66\xff\x3b\xa4\x80"
+                         "\x59\x77\x4f\xa0\xd4\xb2\xd9\x8a"
+                         "\xb6\x67\xe6\x28\xd3\x6f\xf2\xcf"
+                         "\xb8\x6d\x2d\xc4\x2a\x69\x89\xff"
+                         "\xcf\xbb\x11\x2e\x2a\x2b\x7c\xfd"
+                         "\xcd\x56\x02\x95\xc9\x54\x6e\x62"
+                         "\x6a\x97\x75\x1a\x21\x16\x46\xfb"
+                         "\xc2\xab\x62\x54\xef\xba\xae\x46"
+                         "\xd4\x14\xc6\xcc\x16\x1b\x95\xf9"
+                         "\x05\x26\x23\x81\x19\x27\xad\x7b"
+                         "\x9c\x8b\xfb\x65\xa4\x61\xee\x69"
+                         "\x44\xbf\x59\xde\x03\x61\x11\x12"
+                         "\x8d\x94\x48\x47\xa9\x52\x16\xfb"
+                         "\x6b\xaf\x59\x6d\xab\x74\xbf\x5c"
+                         "\xb6\x09\x21\x12\x42\x98\x13\xa1"
+                         "\xa8\x6f\xb9\x6d\x4d\xa6\xdc\xea"
+                         "\x61\x02\x3c\xa7\xcd\x1a\x28\x8c",
+               .ctext  = "\xd7\xb4\xfc\xcc\x1f\xf7\xfc\x7d"
+                         "\x69\xfa\xcb\x01\x60\xf3\x5a\x14"
+                         "\x88\xf7\xea\x43\xaa\x47\xf1\x8a"
+                         "\x4e\xd0\x3c\x50\x58\x35\x95\x21"
+                         "\x5f\xcc\x73\x0b\x97\xa0\x2c\x6b"
+                         "\x70\x4d\x3d\xa8\x21\xbe\xfc\xec"
+                         "\xb6\x55\xf0\x48\x2b\x11\xcc\x4b"
+                         "\xda\xf7\x09\xd9\x18\x7b\x4f\x00"
+                         "\x76\x40\xe0\x7d\x33\xcf\x4f\x77"
+                         "\x91\x97\x63\xfa\x72\xba\x5c\x3d"
+                         "\xcf\x2e\xb8\x19\x56\x4a\xa5\x02"
+                         "\xc3\xb1\x80\xa8\x57\x03\x32\x57"
+                         "\xa8\xe1\x65\xf7\xd3\x52\xc5\xcf"
+                         "\x55\x1e\x34\xe3\x77\xab\x83\xdb"
+                         "\xaf\xd3\x8a\xcc\x96\x1c\xc9\x73"
+                         "\xd9\x0b\xb6\x4c\x31\xac\x2c\x82"
+                         "\xb8\xb4\xc8\xe1\xa5\x71\xcc\xb3"
+                         "\x7e\x85\xb8\xfa\x6b\xef\x41\x24",
+               .len    = 144,
+       }, {
+               .key    = "\x66\xb8\x4d\x60\x67\x82\xcc\x8d"
+                         "\x1e\xda\x8f\x28\xe5\x02\xdc\x2c"
+                         "\x54\x84\x2a\x06\xb5\xd1\x34\x57",
+               .klen   = 24,
+               .iv     = "\xb8\x28\x4d\xf5\x69\xb9\xf3\x33"
+                         "\x5e\x0b\xa6\x62\x35\x9b\xfb\x97",
+               .ptext  = "\x3e\xc6\xec\xaf\x74\xe8\x72\x91"
+                         "\xb2\xc6\x56\xb3\x23\x29\x43\xe0"
+                         "\xfb\xcc\x21\x38\x64\x78\x9e\x78"
+                         "\xbb\x6e\x0d\x7b\xfd\x05\x74\x01"
+                         "\x7c\x94\xe0\xb0\xd7\x92\xfc\x58"
+                         "\x28\xfc\xe2\x7b\x7f\xf7\x31\x0d"
+                         "\x90\xb7\x60\x78\xa8\x9f\x52\xe3"
+                         "\xe6\xaa\x2a\xb4\xa7\x09\x60\x53"
+                         "\x42\x0e\x15\x31\xf6\x48\xa3\x0a"
+                         "\x20\xf0\x79\x67\xb1\x83\x26\x66"
+                         "\xe0\xb1\xb3\xbd\x1c\x76\x36\xfd"
+                         "\x45\x87\xa4\x14\x1b\xef\xe7\x16"
+                         "\xf7\xfa\x30\x3d\xb9\x52\x8f\x2e"
+                         "\x01\x68\xc1\x7d\xa2\x15\x49\x74"
+                         "\x53\x82\xc2\x10\xa8\x45\x73\x4d"
+                         "\x41\xcc\x24\xa3\x42\xff\x30\xd1"
+                         "\x02\x21\xdc\xd9\x08\xf7\xe7\x4c"
+                         "\x33\x2d\x62\xc7\x38\xf5\xc2\xbe"
+                         "\x52\xf1\x34\x78\x34\x53\x30\x5b"
+                         "\x43\x43\x51\x6a\x02\x81\x64\x0c",
+               .ctext  = "\x71\xf6\x96\x02\x07\x71\x1a\x08"
+                         "\x7c\xfe\x33\xc4\xc9\xbe\xe2\xed"
+                         "\xf8\x46\x69\xce\x1b\xdc\xd3\x05"
+                         "\x7a\xec\x26\x4d\x27\x2a\x49\x36"
+                         "\x85\xe1\x5d\xd3\x91\xd7\x68\xb8"
+                         "\x55\xa5\x27\x55\x2d\xc1\x78\x27"
+                         "\x0c\x49\x0a\x24\x3b\x76\x3f\x5f"
+                         "\x29\x1c\x37\x2f\x30\xfc\x50\xcb"
+                         "\xe2\x54\x26\x7d\x97\xa7\xf3\x58"
+                         "\x15\xe1\x4c\xeb\x35\xc9\xd1\x1e"
+                         "\x7e\x7d\xa0\xe5\x62\xa5\x2d\xf6"
+                         "\x77\xb0\xef\x13\x55\xb4\x66\x2c"
+                         "\x3b\x50\x1b\x4d\xc2\x64\xce\xc6"
+                         "\xfe\xf2\xad\xfe\x26\x73\x36\x66"
+                         "\x0c\x2f\x10\x35\x97\x3c\x9c\x98"
+                         "\xc1\x90\xa8\x82\xd7\xc6\x31\x68"
+                         "\xcf\x77\xa8\x5b\xdf\xf9\x5a\x8e"
+                         "\x84\xb5\x0b\x6e\x5b\xec\x36\x89"
+                         "\x0b\xb1\xbf\xb9\x70\x02\x5c\x22"
+                         "\xc3\xd5\xc1\xc6\xfd\x07\xdb\x70",
+               .len    = 160,
+       }, {
+               .key    = "\x82\x8e\x9e\x06\x7b\xc2\xe9\xb3"
+                         "\x06\xa3\xfa\x99\x42\x67\x87\xac"
+                         "\x21\xc7\xb0\x98\x6c\xf8\x26\x57"
+                         "\x08\xdd\x92\x02\x77\x7b\x35\xe7",
+               .klen   = 32,
+               .iv     = "\xa1\xad\xcb\xdd\xd5\x19\xb6\xd4"
+                         "\x0b\x62\x58\xb0\x6c\xa0\xc1\x58",
+               .ptext  = "\x14\x0d\x8a\x09\x16\x00\x00\xf1"
+                         "\xc0\x20\x86\xf9\x21\xd1\x34\xe2",
+               .ctext  = "\x05\xe3\x34\xaf\x6c\x83\x14\x8b"
+                         "\x9d\x1c\xd6\x87\x74\x91\xdf\x17",
+               .len    = 16,
+       }, {
+               .key    = "\xc9\xf3\xc4\x93\xd0\xcc\xaf\xb1"
+                         "\x1a\x42\x93\x71\xd8\x4e\xd8\xaa"
+                         "\x52\xad\x93\x2f\xe5\xd9\xaa\x5b"
+                         "\x47\x37\x3a\xed\x13\x92\x35\x16",
+               .klen   = 32,
+               .iv     = "\x81\xc8\x50\xd1\x74\xc3\x1c\x73"
+                         "\xbb\xab\x72\x83\x90\x5a\x15\xcb",
+               .ptext  = "\x65\x11\x93\xaf\xe1\x69\x6c\xbe"
+                         "\x25\x8c\x76\x87\x53\xa4\x80\xae"
+                         "\x51\x94\x36\x3f\xca\xe7\x45\x41"
+                         "\x76\x05\xbf\x8f\x9c\xad\xc0\xe3",
+               .ctext  = "\x6b\x00\x6e\x49\x7a\x6d\xe3\x04"
+                         "\x4e\xf7\x9f\x8a\x1f\x14\xbd\xb1"
+                         "\x51\xbf\x13\x9f\x29\x95\x51\x16"
+                         "\xd0\x23\x9a\x1a\x45\xc2\xc3\xd1",
+               .len    = 32,
+       }, {
+               .key    = "\xd5\x9f\x52\x34\x12\x99\x8e\x42"
+                         "\xe0\x85\x04\x6f\xeb\xf1\x5d\xd0"
+                         "\xc1\xbf\x3f\x84\xd9\x1e\x71\x44"
+                         "\xd4\xb9\x40\x3c\x02\x2e\x21\x19",
+               .klen   = 32,
+               .iv     = "\x28\xc1\x97\x64\x81\x52\x57\x0e"
+                         "\x02\x8c\xab\x4c\xe2\x60\x14\xa5",
+               .ptext  = "\x5a\xb1\x33\x48\xaa\x51\xe9\xa4"
+                         "\x5c\x2d\xbe\x33\xcc\xc4\x7f\x96"
+                         "\xe8\xde\x2b\xe7\x35\x7a\x11\x4b"
+                         "\x13\x08\x32\xc6\x41\xd8\xec\x54"
+                         "\xa3\xd3\xda\x35\x43\x69\xf6\x88"
+                         "\x97\xca\x00\x1b\x02\x59\x24\x82",
+               .ctext  = "\x03\xaf\x76\xbd\x5e\x5b\xca\xc0"
+                         "\xae\x44\xa2\x2f\xc2\x76\x2f\x50"
+                         "\xfa\x94\x94\x5a\x48\x9d\x9c\x38"
+                         "\xc9\x75\xc9\xb2\x56\x0a\x2d\x91"
+                         "\xb8\xe8\x4e\xaa\xcb\x51\x9b\x6a"
+                         "\x20\x9b\x2b\xc5\xb0\x18\x9d\x01",
+               .len    = 48,
+       }, {
+               .key    = "\x9c\x5d\xd7\x66\x36\xfa\x02\x20"
+                         "\x99\x61\x62\x86\x0f\x43\x2e\x05"
+                         "\x25\x8b\xfb\xf1\xae\x4c\xde\x18"
+                         "\x0b\xf8\xd0\x9d\xaa\xd4\x56\x04",
+               .klen   = 32,
+               .iv     = "\xcd\xa8\x61\x89\x8d\xbb\x72\xb6"
+                         "\x1e\xfe\x03\x34\x54\x88\x23\xe2",
+               .ptext  = "\x66\x42\x60\x24\xf3\xe4\xe9\x7e"
+                         "\x42\x20\xf4\x61\xce\x1c\x5e\x44"
+                         "\x02\x26\x91\xf7\x41\xa4\xab\x34"
+                         "\x29\x49\xdd\x78\x19\x8f\x10\x10"
+                         "\xf0\x61\xcf\x77\x18\x17\x61\xdf"
+                         "\xc4\xa8\x35\x0e\x75\x1b\x84\x6b"
+                         "\xc3\x3f\x31\x59\x5a\x9c\xf4\xc3"
+                         "\x43\xa9\xb7\xf8\x65\x40\x40\xba",
+               .ctext  = "\xb6\x41\x55\x8f\xeb\x16\x1e\x4c"
+                         "\x81\xa0\x85\x6c\xf0\x07\xa5\x2a"
+                         "\x19\x91\xed\x3e\xd6\x30\x8c\xca"
+                         "\x5d\x0f\x58\xca\xd2\x8a\xac\xa2"
+                         "\x2b\x86\x4f\xb5\x85\x4d\xac\x6d"
+                         "\xe5\x39\x1b\x02\x23\x89\x4e\x4f"
+                         "\x02\x00\xe8\x1b\x40\x85\x21\x2b"
+                         "\xc6\xb1\x98\xed\x70\xb3\xf8\xc3",
+               .len    = 64,
+       }, {
+               .key    = "\x4b\x4e\x11\x91\x27\xcf\x8c\x66"
+                         "\x17\xfa\x5b\x4c\xa8\xb8\x0f\xa1"
+                         "\x99\x5b\x07\x56\xe1\x8d\x94\x8b"
+                         "\xf2\x86\x5a\x5f\x40\x83\xfa\x06",
+               .klen   = 32,
+               .iv     = "\xfd\x73\xee\x1c\x27\xf3\xb4\x38"
+                         "\xc5\x7c\x2e\xc5\x6e\xdb\x49\x0d",
+               .ptext  = "\x0a\xe2\xdd\x97\xdd\x5e\xd4\xb3"
+                         "\xc1\x49\x8f\x53\xb2\x40\x85\x1c"
+                         "\x90\x37\x2d\xbd\x21\x6b\x1f\x80"
+                         "\x56\x98\x76\x1e\xcf\x6c\x78\xd8"
+                         "\xa0\x3c\x79\xc3\x56\xf7\xfc\x64"
+                         "\x35\x58\x1c\x7c\xc4\x5f\x2a\x25"
+                         "\x8c\x01\x98\x1e\x1c\x1f\x15\x64"
+                         "\x50\xb5\xfa\x02\xd3\x54\xe5\x29"
+                         "\xe3\xd2\xa3\x83\x54\x40\x54\xc5"
+                         "\xd8\x1c\xc9\x84\x7d\xc8\x31\x49",
+               .ctext  = "\x53\x2a\xa8\xa0\x15\xaf\x2f\xc4"
+                         "\x7d\x31\xb4\x61\x80\x5f\xd1\xb6"
+                         "\x7c\xca\x86\xb9\x28\x6e\xb6\x2b"
+                         "\xe3\x4b\x7e\xea\xb3\x4f\xa2\xa2"
+                         "\x4e\x8f\xbe\x22\x66\xb3\x92\xbc"
+                         "\x70\x91\xaf\xa6\x09\x5d\xe2\x05"
+                         "\x38\x62\xd3\x6e\x07\x63\x91\xad"
+                         "\x48\x5a\x42\xe7\xdc\x0d\xb1\xe3"
+                         "\x92\x88\x64\xee\x93\xaa\xaf\x31"
+                         "\x68\x57\x35\x8d\x54\x2c\xfa\xb1",
+               .len    = 80,
+       }, {
+               .key    = "\x77\x3b\xf5\xe7\x20\xf7\xe0\x0c"
+                         "\x3d\x3a\x83\x17\x83\x79\xd8\x29"
+                         "\x5a\x0a\x25\x7f\xe0\x21\x23\xff"
+                         "\x31\xfd\x60\x10\xe6\x63\xe2\xaf",
+               .klen   = 32,
+               .iv     = "\xdb\x4c\x0d\xc0\x36\xdb\xc7\xa1"
+                         "\xa4\x91\xd9\x05\xe6\xc4\x98\x00",
+               .ptext  = "\x8d\x4d\xc6\x5e\x01\x82\xb3\x39"
+                         "\xc8\x64\xa7\xcb\x05\x19\x84\x80"
+                         "\x3f\x9c\xa8\x4f\x64\xb3\x11\x4b"
+                         "\x0e\x21\xc4\x75\x04\x1d\x6f\xd5"
+                         "\x04\x04\x4d\xc9\xc0\x4b\x4a\x9c"
+                         "\x26\xb7\x68\x5a\xe4\xd0\x61\xe3"
+                         "\x2c\x93\x8e\x3f\xb4\x67\x07\x31"
+                         "\x02\x52\x0c\x0f\xe6\x6d\xa3\xd0"
+                         "\x48\x95\x83\x67\x23\x64\x31\x50"
+                         "\xd2\x5f\x69\x68\x8b\x71\xbf\x01"
+                         "\x29\x99\x86\x36\x2e\xdf\xf1\x7c"
+                         "\x08\x8c\x78\x7a\x93\x9a\x7d\x1b",
+               .ctext  = "\x92\x90\x48\x2f\x3a\x6b\x68\x43"
+                         "\x28\x9b\x7d\x1e\x46\x28\xd8\x58"
+                         "\xd9\x1e\x44\xd7\x24\x91\x65\xb1"
+                         "\x15\xde\xc4\x63\xf1\xb1\x34\x9e"
+                         "\xae\x8c\x51\x94\xc5\x22\x65\x8d"
+                         "\x3d\x85\xf5\x34\x5f\x04\x68\x95"
+                         "\xf2\x66\x62\xbb\xc8\x3f\xe4\x0a"
+                         "\x8a\xb2\x70\xc0\x77\xd5\x96\xef"
+                         "\x9e\x39\x3a\x3e\x0d\x2b\xf9\xfe"
+                         "\xa9\xbc\x00\xba\xc5\x43\xd7\x70"
+                         "\x2f\xef\x1e\x1e\x93\xc2\x5d\xf1"
+                         "\xb5\x50\xb8\xf5\xee\xf4\x26\x6f",
+               .len    = 96,
+       }, {
+               .key    = "\xe0\x6a\x30\xe1\x35\xb5\xb0\x7c"
+                         "\x54\xc5\x73\x9b\x00\xe5\xe7\x02"
+                         "\xbe\x16\x59\xdc\xd9\x03\x17\x53"
+                         "\xa8\x37\xd1\x5f\x13\x8e\x45\xdb",
+               .klen   = 32,
+               .iv     = "\x54\xe9\x1c\xde\xfb\x26\x0e\x48"
+                         "\x35\x50\x4d\x9b\x4d\x12\x21\x0d",
+               .ptext  = "\x73\x72\xcf\xdb\xbd\xbc\xc0\xdf"
+                         "\x6b\xbb\xdf\x65\x6f\x2f\x43\x3b"
+                         "\x2d\x7c\x0e\x07\x7f\xa0\x95\xdd"
+                         "\xfc\x67\xc1\x11\x7a\xe2\xb5\x4a"
+                         "\xd1\x15\xb0\xd8\xe2\xf0\x35\x48"
+                         "\xd8\x81\x6a\x35\xae\x67\xbf\x61"
+                         "\xf2\x8a\xcf\x04\xc8\x09\x8b\x63"
+                         "\x31\x74\x95\xa5\x8d\x3c\xea\xe2"
+                         "\x5f\x67\xc4\x7e\x51\x88\xbf\xb5"
+                         "\x78\xef\x3a\x76\xd8\x1d\x00\x75"
+                         "\x2b\x7b\x28\x7c\xde\x4b\x39\x01"
+                         "\x5d\xde\x92\xfe\x90\x07\x09\xfd"
+                         "\xa5\xd1\xd3\x72\x11\x6d\xa4\x4e"
+                         "\xd1\x6e\x16\xd1\xf6\x39\x4f\xa0",
+               .ctext  = "\x3b\xc5\xee\xfc\x05\xaf\xa6\xb7"
+                         "\xfe\x12\x24\x79\x31\xad\x32\xb5"
+                         "\xfb\x71\x9b\x02\xad\xf4\x94\x20"
+                         "\x25\x7b\xdb\xdf\x97\x99\xca\xea"
+                         "\xc4\xed\x32\x26\x6b\xc8\xd4\x7b"
+                         "\x5b\x55\xfa\xf9\x5b\xab\x88\xdb"
+                         "\x48\xfe\x67\xd5\x5a\x47\x81\x4e"
+                         "\x3e\x1e\x83\xca\x1d\x04\xe1\xb5"
+                         "\x6c\x1b\xbd\xf2\x2d\xf1\xae\x75"
+                         "\x09\x6a\xf8\xb2\xc3\x27\xee\x08"
+                         "\x66\x94\x72\xc0\x2b\x12\x47\x23"
+                         "\x4d\xde\xb4\xca\xf7\x66\xca\x14"
+                         "\xe7\x68\x1b\xfb\x48\x70\x3e\x4c"
+                         "\x43\xbb\x88\x32\x25\xff\x77\x6a",
+               .len    = 112,
+       }, {
+               .key    = "\x60\xb6\xde\x17\xca\x4c\xe7\xe0"
+                         "\x07\x0d\x80\xc5\x8a\x2d\x5a\xc2"
+                         "\x2c\xb9\xa4\x5f\x2a\x85\x2c\x3d"
+                         "\x6d\x67\xc8\xee\x0f\xa2\xf4\x09",
+               .klen   = 32,
+               .iv     = "\x1a\xa5\xbc\x7e\x93\xf6\xdd\x28"
+                         "\xb7\x69\x27\xa1\x84\x95\x25\x5a",
+               .ptext  = "\x7b\x88\x00\xeb\xa5\xba\xa1\xa7"
+                         "\xd4\x40\x16\x74\x2b\x42\x37\xda"
+                         "\xe0\xaf\x89\x59\x41\x2f\x62\x00"
+                         "\xf5\x5a\x4e\x3b\x85\x27\xb2\xed"
+                         "\x1b\xa7\xaf\xbe\x89\xf3\x49\xb7"
+                         "\x8c\x63\xc9\x0c\x52\x00\x5f\x38"
+                         "\x3b\x3c\x0c\x4f\xdd\xe1\xbf\x90"
+                         "\x4a\x48\xbf\x3a\x95\xcb\x48\xa2"
+                         "\x92\x7c\x79\x81\xde\x18\x6e\x92"
+                         "\x1f\x36\xa9\x5d\x8d\xc4\xb6\x4d"
+                         "\xb2\xb4\x0e\x09\x6d\xf3\x3d\x01"
+                         "\x3d\x9b\x40\x47\xbc\x69\x31\xa1"
+                         "\x6a\x71\x26\xdc\xac\x10\x56\x63"
+                         "\x15\x23\x7d\x10\xe3\x76\x82\x41"
+                         "\xcd\x80\x57\x2f\xfc\x4d\x22\x7b"
+                         "\x57\xbb\x9a\x0a\x03\xe9\xb3\x13",
+               .ctext  = "\x37\x0d\x47\x21\xbc\x28\x0b\xf7"
+                         "\x85\x5f\x60\x57\xf2\x7f\x92\x20"
+                         "\x5f\xa7\xf6\xf4\xa6\xf5\xdf\x1e"
+                         "\xae\x8e\xeb\x97\xfc\xce\x6a\x25"
+                         "\x6d\x6a\x5b\xd1\x99\xf6\x27\x77"
+                         "\x52\x0c\xf1\xd7\x94\xa0\x67\x5d"
+                         "\x60\x35\xb0\x6d\x01\x45\x52\xc8"
+                         "\x05\xd8\x7f\x69\xaf\x8e\x68\x05"
+                         "\xa8\xa5\x24\x2f\x95\xef\xf1\xd2"
+                         "\x8c\x45\x12\xc5\x7a\xcf\xbb\x99"
+                         "\x25\xaa\xa3\x9b\x3f\xf1\xfc\x9d"
+                         "\xfa\x2c\x26\x9b\x92\x47\x61\x6b"
+                         "\x63\x1e\x41\x67\xcb\xb7\x0f\x52"
+                         "\x70\xd4\x0d\x7e\xef\x34\xa2\x75"
+                         "\x4f\x6a\x55\x9c\x2b\x4a\x02\xdd"
+                         "\x96\x5d\xcb\xca\x45\xa1\xec\xaa",
+               .len    = 128,
+       }, {
+               .key    = "\x2a\xed\x7d\x76\xfc\xc5\x49\x50"
+                         "\xf4\x90\x0f\xcc\x5d\xff\x0c\x3c"
+                         "\x14\x06\xaf\x68\x8f\xd7\xb6\x25"
+                         "\x1e\x10\x95\x2a\x71\x33\x17\x20",
+               .klen   = 32,
+               .iv     = "\x5b\x58\x47\xf8\xd5\x1e\x91\x81"
+                         "\x46\xe7\x25\x3a\x02\x45\x9c\x65",
+               .ptext  = "\x10\xaf\xde\x5c\x30\x79\x43\x28"
+                         "\x1c\x03\xf8\x50\x0f\x30\xa5\xef"
+                         "\x84\x19\x4c\x09\x40\x03\x75\x1f"
+                         "\x92\x8f\x88\x01\xda\x31\x7a\xe4"
+                         "\x48\xe3\xab\xb4\xe6\x1b\x0f\xac"
+                         "\xd9\xfa\x8d\x23\xe4\xc6\xa4\xa9"
+                         "\x2d\x9a\x54\x52\x44\x5c\x3c\x52"
+                         "\x61\xf0\x00\xca\xed\xab\xed\xe2"
+                         "\x44\x0b\xe0\x18\xba\xa5\x63\xd8"
+                         "\xdc\x5e\x1a\x4c\xf8\xde\x5e\x75"
+                         "\xdf\x42\x27\x7b\xe9\x11\x2f\x41"
+                         "\x3a\x72\x54\x3d\x44\x9c\x3e\x87"
+                         "\x8d\x8d\x43\x2f\xb2\xff\x87\xd4"
+                         "\xad\x98\x68\x72\x53\x61\x19\x7c"
+                         "\x20\x79\x8c\x2b\x37\x0b\x96\x15"
+                         "\xa5\x7d\x4e\x01\xe6\xea\xb6\xfa"
+                         "\xaa\xd3\x9d\xa2\xd9\x11\xc3\xc9"
+                         "\xd4\x0e\x3f\x3e\xfe\x35\x1e\xe5",
+               .ctext  = "\xb0\x2b\x75\x5f\x33\x1b\x05\x49"
+                         "\x06\xf1\x43\x91\xc2\x85\xfa\xac"
+                         "\x3f\x47\xf3\x89\x73\xb2\x0e\xa4"
+                         "\x30\xcb\x87\x39\x53\x5d\x36\x89"
+                         "\x77\xd9\x17\x01\x95\xa6\xe9\x71"
+                         "\x51\x53\xd9\x4f\xa6\xc2\x79\x3d"
+                         "\x2e\x50\x90\x52\x0d\x27\x1a\x46"
+                         "\xf1\xe8\x6e\x7e\x7b\x32\xe5\x22"
+                         "\x22\x1f\xba\x5e\xcf\x25\x6b\x26"
+                         "\x76\xf0\xca\x8e\xdd\x5b\xd3\x09"
+                         "\x6f\x82\x08\x56\x1f\x51\x72\x57"
+                         "\xca\xd1\x60\x07\xfb\x9f\x71\x54"
+                         "\x0f\xf6\x48\x71\xfa\x8f\xcb\xdd"
+                         "\xce\xd3\x16\xcd\xae\x0e\x67\x5e"
+                         "\xea\x8d\xa2\x4a\x4f\x11\xc8\xc8"
+                         "\x2f\x04\xfe\xa8\x2a\x07\x1c\xb1"
+                         "\x77\x39\xda\x8b\xd9\x5c\x94\x6c"
+                         "\x4d\x4d\x13\x51\x6f\x07\x06\x5b",
+               .len    = 144,
+       }, {
+               .key    = "\x7b\xa7\x4d\x0a\x37\x30\xb9\xf5"
+                         "\x2a\x79\xb4\xbf\xdb\x7f\x9b\x64"
+                         "\x23\x43\xb5\x18\x34\xc4\x5f\xdf"
+                         "\xd9\x2a\x66\x58\x00\x44\xb5\xd9",
+               .klen   = 32,
+               .iv     = "\x75\x34\x30\xc1\xf0\x69\xdf\x0a"
+                         "\x52\xce\x4f\x1e\x2c\x41\x35\xec",
+               .ptext  = "\x81\x47\x55\x3a\xcd\xfe\xa2\x3d"
+                         "\x45\x53\xa7\x67\x61\x74\x25\x80"
+                         "\x98\x89\xfe\xf8\x6a\x9f\x51\x7c"
+                         "\xa4\xe4\xe7\xc7\xe0\x1a\xce\xbb"
+                         "\x4b\x46\x43\xb0\xab\xa8\xd6\x0c"
+                         "\xa0\xf0\xc8\x13\x29\xaf\xb8\x01"
+                         "\x6b\x0c\x7e\x56\xae\xb8\x58\x72"
+                         "\xa9\x24\x44\x61\xff\xf1\xac\xf8"
+                         "\x09\xa8\x48\x21\xd6\xab\x41\x73"
+                         "\x70\x6b\x92\x06\x61\xdc\xb4\x85"
+                         "\x76\x26\x7a\x84\xc3\x9e\x3a\x14"
+                         "\xe7\xf4\x2d\x95\x92\xad\x18\xcc"
+                         "\x44\xd4\x2c\x36\x57\xed\x2b\x9b"
+                         "\x3f\x2b\xcd\xe5\x11\xe3\x62\x33"
+                         "\x42\x3f\xb8\x2a\xb1\x37\x3f\x8b"
+                         "\xe8\xbd\x6b\x0b\x9f\x38\x5a\x5f"
+                         "\x82\x34\xb7\x96\x35\x58\xde\xab"
+                         "\x94\x98\x41\x5b\x3f\xac\x0a\x34"
+                         "\x56\xc0\x02\xef\x81\x6d\xb1\xff"
+                         "\x34\xe8\xc7\x6a\x31\x79\xba\xd8",
+               .ctext  = "\x4e\x00\x7c\x52\x45\x76\xf9\x3d"
+                         "\x1a\xd1\x72\xbc\xb9\x0f\xa9\xfb"
+                         "\x0e\x5b\xe2\x3c\xc7\xae\x92\xf6"
+                         "\xb8\x0b\x0a\x95\x40\xe9\x7f\xe0"
+                         "\x54\x10\xf9\xf6\x23\x1f\x51\xc8"
+                         "\x16\x8b\x2e\x79\xe1\x8c\x0b\x43"
+                         "\xe5\xeb\xb5\x9d\x1e\xc3\x28\x07"
+                         "\x5c\x8d\xb1\xe7\x80\xd3\xce\x62"
+                         "\x8d\xf8\x31\x1f\x29\x8b\x90\xee"
+                         "\xe5\xc3\xfa\x16\xc4\xf0\xc3\x99"
+                         "\xe9\x5e\x19\xba\x37\xb8\xc0\x87"
+                         "\xb5\xc6\xc9\x31\xcb\x6e\x30\xce"
+                         "\x03\x1d\xfe\xce\x08\x32\x00\xeb"
+                         "\x86\xc4\xfb\x48\x01\xda\x93\x73"
+                         "\xcc\xb7\xae\x4e\x94\x20\xeb\xc7"
+                         "\xe3\x33\x4c\xeb\xed\xe2\xfc\x86"
+                         "\x0e\x73\x32\xf9\x1b\xf3\x25\xf3"
+                         "\x74\xad\xd1\xf4\x2c\x45\xa4\xfd"
+                         "\x52\x40\xa2\x4e\xa5\x62\xf6\x02"
+                         "\xbb\xb0\xe3\x23\x86\x67\xb8\xf6",
+               .len    = 160,
+       }
+};
+
+static const struct cipher_testvec aria_cfb_tv_template[] = {
+       {
+               .key    = "\x7f\x92\xd5\x06\x30\x6b\xc0\x23"
+                         "\x87\xa8\x8e\x6d\xc7\xc5\xd7\xf1",
+               .klen   = 16,
+               .iv     = "\x5f\xce\x89\xb3\xd5\x7f\x7f\xf0"
+                         "\xfd\xab\x56\xa6\x6e\xda\x7c\x57",
+               .ptext  = "\x36\x36\x89\x09\xcd\xa8\xd3\x91"
+                         "\x48\x3e\x3c\x11\xcf\xd0\x4f\xc0",
+               .ctext  = "\x19\x28\xb5\xf2\x1c\xbc\xf8\xaf"
+                         "\xb9\xae\x1b\x23\x4f\xe1\x6e\x40",
+       }, {
+               .key    = "\x51\xe3\x8c\xe9\x76\xcd\xff\x37"
+                         "\xd6\x1a\x18\x2f\x68\x2f\xb6\xfe",
+               .klen   = 16,
+               .iv     = "\x3d\x2d\x85\x75\x6e\x18\x8a\x52"
+                         "\x53\x39\xfc\xc1\xf5\xc0\x56\x22",
+               .ptext  = "\xc6\xae\xaa\x0d\x90\xf2\x38\x93"
+                         "\xac\xd2\x3f\xc7\x74\x8d\x13\x7e"
+                         "\xfa\x3f\x70\x52\xfb\x04\x0e\xed"
+                         "\x0e\x60\x75\x84\x21\xdf\x13\xa1",
+               .ctext  = "\x3f\x8c\xa9\x19\xd6\xb4\xfb\xed"
+                         "\x9c\x6d\xaa\x1b\xe1\xc1\xe6\xa8"
+                         "\x47\x35\x7d\xa3\x96\x7d\x53\x60"
+                         "\xa9\x33\x9c\x34\xae\x7d\x7c\x74",
+               .len    = 32,
+       }, {
+               .key    = "\x26\xf8\x8c\x26\x0a\x37\x51\x8f"
+                         "\xe7\x9c\x74\x77\x7a\x3e\xbb\x5d",
+               .klen   = 16,
+               .iv     = "\xd7\x33\xf3\xa9\x5b\xb4\x86\xea"
+                         "\xe3\x7d\x50\x62\x3b\x73\xaf\xc4",
+               .ptext  = "\xda\x89\xd9\x3c\xcc\xe4\x73\xb0"
+                         "\xef\x3e\x5f\x46\x62\x88\xd5\x26"
+                         "\x3b\xd3\xb5\x81\x78\x70\x1b\xd2"
+                         "\x39\x56\x34\x63\x2c\xc5\x51\x13"
+                         "\x48\x29\x3a\x58\xbe\x41\xc5\x80"
+                         "\x2c\x80\xa7\x3c\x14\xb4\x89\x5e",
+               .ctext  = "\x28\xd8\xa7\xf8\x74\x98\x00\xfc"
+                         "\xd6\x48\xad\xbd\xbe\x3f\x0e\x7b"
+                         "\xa3\xec\x03\x6a\xfb\xc9\x01\x83"
+                         "\xb3\x2f\xda\x5e\x66\xa0\xc3\xec"
+                         "\xe9\xd4\x72\x2a\xa2\x90\x41\xcf"
+                         "\xde\x30\x79\xc3\x82\x10\x51\xe1",
+               .len    = 48,
+       }, {
+               .key    = "\x8e\xe5\x5f\xe2\x39\x80\xf5\x2b"
+                         "\x77\xb5\xca\x90\xda\x1d\x22\x17",
+               .klen   = 16,
+               .iv     = "\xd9\xa0\x57\x80\xc8\x96\x70\x86"
+                         "\x07\x2c\xf4\x61\x79\x09\x01\x8f",
+               .ptext  = "\x37\x32\x98\xd4\x86\x2b\x3b\x80"
+                         "\x07\x60\xba\xf0\x2e\xc3\x4a\x57"
+                         "\xf5\xb5\xd7\xbf\xd2\x2a\x9b\x4a"
+                         "\xe6\x08\xf0\xbe\x77\xd1\x62\x40"
+                         "\xa0\x82\x09\x60\x47\xbb\x16\x56"
+                         "\x50\x1f\xab\x8b\x10\xfe\xf0\x5c"
+                         "\x05\x32\x63\x1a\xc4\x46\x6f\x55"
+                         "\x32\xde\x41\x5a\xf7\x52\xd7\xfa",
+               .ctext  = "\x29\x31\x55\xd2\xe5\x0b\x81\x39"
+                         "\xf9\xbc\x63\xe2\xfa\x26\x99\xde"
+                         "\x5c\xd3\x0a\x56\xe5\xfc\x83\xdd"
+                         "\xab\x26\x90\x7d\xa8\x0f\x01\xa6"
+                         "\x0e\x01\xdc\x1f\xfa\xa7\xdd\x09"
+                         "\xf9\xbf\x12\xf4\xc6\x9f\xbd\x57"
+                         "\x23\x68\x54\x0f\xe0\xcf\x1c\x6d"
+                         "\xe1\x5e\x0b\x4a\x1e\x71\x1d\xaa",
+               .len    = 64,
+       }, {
+               .key    = "\x30\x9d\x59\x8d\x64\x76\xad\x37"
+                         "\xba\xbc\x46\x6a\x69\x17\x3c\xac",
+               .klen   = 16,
+               .iv     = "\x6f\xdd\xa2\x9b\x86\x32\x14\x2e"
+                         "\x54\x74\x8f\x3d\xe2\xd6\x85\x44",
+               .ptext  = "\x4f\x4a\x31\x64\xc6\xa5\x29\xaa"
+                         "\xad\xfd\x32\x94\x1f\x56\x57\xd1"
+                         "\x9d\x7e\x3d\x49\x00\x36\xb1\x5d"
+                         "\xb2\x92\x83\x70\x1e\xa3\x97\xa6"
+                         "\x65\x53\x39\xeb\x53\x8f\xb1\x38"
+                         "\x91\xac\x17\x11\x1c\x03\x69\x53"
+                         "\xf5\xdf\xdb\x2c\x1b\x9a\x6e\x6b"
+                         "\xb6\x02\xc4\xfa\x95\x01\x33\xa8"
+                         "\xda\x7e\x18\x2c\xf4\x7e\x6e\x67"
+                         "\xce\x8f\x9f\xea\x46\x66\x99\xb8",
+               .ctext  = "\x38\xbc\xf5\x9d\x0e\x26\xa6\x18"
+                         "\x95\x0b\x23\x54\x09\xa1\xf9\x46"
+                         "\x7a\x31\xa0\xd7\x4a\xec\xb3\x10"
+                         "\x8a\x8e\x99\x78\x6c\x6e\x76\xf2"
+                         "\x63\x8a\x3b\x90\xaa\xd5\x64\x65"
+                         "\x5a\x52\xb0\x36\x4c\xce\xed\xc7"
+                         "\x51\x3c\x06\xb0\xee\x54\xec\x10"
+                         "\xc0\x5f\xfd\xa9\x44\x9a\x29\x32"
+                         "\x19\x79\x7d\x2b\x14\x26\x96\x13"
+                         "\x9d\xa5\x61\xbd\xb6\x72\x37\x26",
+               .len    = 80,
+       }, {
+               .key    = "\xe1\xc7\x25\x4d\xbd\xa5\x74\xdf"
+                         "\xc7\x8b\xfb\xe3\x2d\x3a\x82\xd3",
+               .klen   = 16,
+               .iv     = "\x17\x94\x77\x2f\x92\xb8\x87\xc2"
+                         "\xcc\x6f\x70\x26\x87\xc7\x10\x8a",
+               .ptext  = "\xc8\xfd\xc2\xb3\xcf\xa0\xeb\x41"
+                         "\x4c\xf4\xd0\x34\xd0\x95\xab\xae"
+                         "\x82\x5c\xfd\xfa\x13\x86\x25\xce"
+                         "\xf4\x13\x32\xcd\xc6\x6d\xf6\x50"
+                         "\x12\x4a\x5b\x66\x3a\xd3\xfb\x1a"
+                         "\xaf\x06\xea\xf4\x65\x59\xd6\xc2"
+                         "\x84\xa0\x53\x97\x61\x30\x70\x15"
+                         "\xac\x45\x8e\xe8\xeb\xa1\x72\x93"
+                         "\x26\x76\x98\x6f\xe4\x86\xca\xf0"
+                         "\x57\x89\xf2\x2b\xd4\xcf\x2d\x95"
+                         "\x86\x26\x20\x0e\x62\xfe\x8f\x1e"
+                         "\x5d\xcb\x2b\x7e\xdd\xab\xac\xda",
+               .ctext  = "\xdf\x79\x58\x30\x6f\x47\x12\x78"
+                         "\x04\xb2\x0b\x1a\x62\x22\xe2\x9f"
+                         "\xfe\x90\x50\x41\x1b\x6a\x6a\x9c"
+                         "\x4e\x77\x8f\xca\xd1\x68\x31\xcd"
+                         "\x41\x82\xa5\x5b\xc0\x08\x2b\x37"
+                         "\x62\xec\x95\xf1\x56\x12\x38\x66"
+                         "\x84\x82\x72\xda\x00\x21\x96\x82"
+                         "\x33\xd4\x99\xaa\xb9\xeb\xd5\xc3"
+                         "\x2b\xa8\xf7\xdc\x13\x0e\x21\x9f"
+                         "\x4b\xf9\x42\x58\xa8\x39\x10\xd5"
+                         "\x86\xa5\xc6\x78\x3b\x34\x05\x03"
+                         "\x54\x43\x2b\x80\xa9\x53\x4d\x0e",
+               .len    = 96,
+       }, {
+               .key    = "\x6e\x49\x20\xd5\xb7\x01\x83\x4e"
+                         "\xac\x45\x8f\xe1\x05\x3f\xd5\xb1",
+               .klen   = 16,
+               .iv     = "\xee\xb7\x0d\x65\x00\x38\xab\x71"
+                         "\x70\x6e\xb3\x97\x86\xd3\xcd\xad",
+               .ptext  = "\x51\x8b\x9c\xa0\x9a\x8b\x4c\xb9"
+                         "\x16\x01\x6a\x1f\xdf\xf0\xf9\x9e"
+                         "\x25\x1b\xc2\xa6\x21\x25\xeb\x97"
+                         "\x4b\xf6\xcb\x3b\xcd\x61\xfd\x94"
+                         "\x37\x03\xb3\xd9\x74\x6e\x4d\xbb"
+                         "\xfd\x87\x2b\xec\x4c\x2c\xbf\xe2"
+                         "\x94\x1a\xe6\xd9\xaf\x0e\x78\x17"
+                         "\x58\x2b\x1d\x73\x9a\x9c\x63\x18"
+                         "\x88\x7a\x0e\x87\x2f\xf0\xb0\xdb"
+                         "\xc9\x9d\x79\x51\x34\x39\x4f\x07"
+                         "\xa2\x7c\x21\x04\x91\x3b\x79\x79"
+                         "\xfe\xd5\x51\x46\xd5\xcd\x28\xc0"
+                         "\xad\xb8\x55\xb2\xb2\x5a\x9a\xa2"
+                         "\xe2\x0c\xfc\x55\x7d\x60\xd2\x95",
+               .ctext  = "\xe4\x25\x0d\x22\xeb\xbe\x5e\x90"
+                         "\x01\xe5\xae\xc9\x94\xbd\x93\x89"
+                         "\x5e\x5a\x5a\x2f\xf6\xdf\xf8\x16"
+                         "\xd3\xb2\xed\x29\x51\xe2\x75\xb0"
+                         "\x1a\x48\xb5\xe6\xd3\x58\x40\xc7"
+                         "\x6f\x6f\xcf\x57\x82\x43\x5a\x36"
+                         "\xef\x27\xe1\x34\x85\x01\xec\x98"
+                         "\x00\xbd\x94\x6f\x12\x39\xa8\x13"
+                         "\xfe\x3c\x39\xc0\xc6\xe1\xcc\x05"
+                         "\x0e\xd5\xc9\xda\xbd\xdd\xdb\xaa"
+                         "\x5a\xaa\x8e\xe8\xa8\x0a\xc5\x18"
+                         "\xb4\x1d\x13\x81\xc9\xc4\xaa\x61"
+                         "\xa9\xbd\xaa\x03\x12\x93\xbb\xed"
+                         "\x0c\x6e\xbd\x1c\x05\x16\x8a\x59",
+               .len    = 112,
+       }, {
+               .key    = "\xb6\x08\x1d\x31\xaf\xf4\x17\x46"
+                         "\xa4\xbb\x0f\xbd\x67\x3c\x73\x15",
+               .klen   = 16,
+               .iv     = "\x0c\x85\x2f\x62\xe5\xf4\x35\x96"
+                         "\xb1\x9b\x5d\x00\x10\xe9\x70\x12",
+               .ptext  = "\x3a\x87\x7f\x67\xf1\x81\x7a\x05"
+                         "\xb4\xa6\xfe\xdf\x36\x31\x6d\x9e"
+                         "\x0e\xa9\x44\xa0\xb0\x05\xa9\x41"
+                         "\x9c\x14\x44\x5a\xd5\x1c\x50\x08"
+                         "\x95\xc2\xf2\xaf\x3f\x29\xc9\x3e"
+                         "\x95\x5e\xc6\xb4\x2b\xf4\x3e\xe3"
+                         "\x1b\xeb\x3d\x73\xfb\xd7\x1e\x2b"
+                         "\x0c\x3d\x58\x6c\xb4\x41\x9b\xfe"
+                         "\x2f\x7e\x1c\x10\x81\x36\x2d\x79"
+                         "\xaf\xab\x10\x44\x2e\xcc\x0d\x6c"
+                         "\x9c\x14\xc2\xe4\xae\xb0\xbb\xda"
+                         "\x6a\xe0\x42\x3d\x96\x9f\x78\x7d"
+                         "\x70\x86\xa5\x92\x9f\xee\xcd\x3f"
+                         "\x6a\x55\x84\x98\x28\x03\x02\xc2"
+                         "\xf7\xec\x7a\xfa\xb1\xd9\xa8\xd8"
+                         "\x1c\xc3\xaa\xd5\x61\x7f\x10\x0c",
+               .ctext  = "\xa7\x4c\x96\x55\x7c\x07\xce\xb2"
+                         "\x6f\x63\x9f\xc6\x8b\x6f\xc6\x4a"
+                         "\x85\xf2\x4b\xdf\x62\x0c\x6c\x8d"
+                         "\x13\x5d\xd3\x40\x58\xa6\xf9\x03"
+                         "\xd9\xf2\x48\x4e\x12\x64\x9a\x55"
+                         "\xa2\xa3\xd0\x19\xe5\x5b\xaa\x62"
+                         "\x7b\xe9\x2a\x23\xab\xb5\xa6\xcf"
+                         "\x53\x59\x70\xc6\xb8\x92\x12\x3b"
+                         "\x93\x68\x24\xba\x7d\xd6\xc0\x5b"
+                         "\x06\x2e\x7f\x2e\x32\x5d\x42\x9c"
+                         "\x13\x8e\x92\x3c\x99\x20\x32\x2b"
+                         "\x4a\x41\xb2\x4a\x81\xe8\x6e\x7f"
+                         "\x5b\x8e\xca\x4d\xd7\x29\x96\xde"
+                         "\x30\x9c\xa6\x84\x90\xe7\xc2\xae"
+                         "\xf4\x7e\x73\x32\x4c\x25\xec\xef"
+                         "\x58\x69\x63\x3f\x4e\x71\x4b\x1c",
+               .len    = 128,
+       }, {
+               .key    = "\xc0\xa1\x36\x3d\x81\x9a\xd2\x17"
+                         "\x2e\x23\xc9\xb7\xff\xdf\x47\x6c",
+               .klen   = 16,
+               .iv     = "\x96\x3b\x0e\xbd\xec\x9a\x0e\xad"
+                         "\x8c\xaf\x36\x3d\xff\x29\x8b\x33",
+               .ptext  = "\x87\x96\x77\x1a\x10\x81\x63\x8a"
+                         "\x63\xde\x88\xa9\x9d\xa9\x01\xf2"
+                         "\xdf\xc9\x25\x35\x48\x3a\x15\xdf"
+                         "\x20\x6b\x91\x7c\x56\xe5\x10\x7a"
+                         "\x2d\x2e\x0f\x30\x32\xed\xa9\x1f"
+                         "\x71\x4e\x68\x77\xe8\xa8\x5b\xdd"
+                         "\x3c\x5e\x68\x6b\xab\x03\xe4\xf8"
+                         "\x42\xc1\x61\x9a\x50\xfb\xc7\x6a"
+                         "\x1a\x31\xa7\x87\xd0\x24\xcb\x5e"
+                         "\xc0\x3b\x12\x28\xca\x26\x7b\xb3"
+                         "\x14\xc1\x7f\x66\xff\x3b\xa4\x80"
+                         "\x59\x77\x4f\xa0\xd4\xb2\xd9\x8a"
+                         "\xb6\x67\xe6\x28\xd3\x6f\xf2\xcf"
+                         "\xb8\x6d\x2d\xc4\x2a\x69\x89\xff"
+                         "\xcf\xbb\x11\x2e\x2a\x2b\x7c\xfd"
+                         "\xcd\x56\x02\x95\xc9\x54\x6e\x62"
+                         "\x6a\x97\x75\x1a\x21\x16\x46\xfb"
+                         "\xc2\xab\x62\x54\xef\xba\xae\x46",
+               .ctext  = "\x11\x7f\xea\x49\xaf\x24\x52\xa2"
+                         "\xde\x60\x99\x58\x23\xf9\x9e\x91"
+                         "\x94\x52\x31\xa3\x28\x07\x14\xad"
+                         "\x00\x24\x4a\x4a\xe7\x18\xd7\x24"
+                         "\xcc\x8b\x66\x53\x82\x65\x31\xa5"
+                         "\x54\x76\x59\x0b\x69\x6f\x90\x2c"
+                         "\x8d\xa5\x2b\x61\x05\x80\xfb\xe0"
+                         "\xf9\x6e\xaf\xb9\xc4\x15\x67\xcc"
+                         "\x15\xce\xa0\xc0\xf2\xae\xa6\x15"
+                         "\x24\x9a\xe5\xcb\x09\x42\xcf\x41"
+                         "\x95\xa4\x8d\xbf\xe8\xb8\x40\xcd"
+                         "\xb0\x33\x2c\xb3\xc4\xdd\xf9\x45"
+                         "\xda\xb2\xeb\xb3\xf8\xfa\x7f\xe3"
+                         "\xc0\x3a\x98\xe7\x17\x4a\x0c\x60"
+                         "\xb2\x22\xba\x3b\x21\x85\x27\x56"
+                         "\xe0\xb2\xf7\x2a\x59\xb1\x56\x20"
+                         "\x0b\xa9\x13\x73\xe0\x6f\x61\x32"
+                         "\xa5\x38\x14\xb3\xe3\xaa\x70\x44",
+               .len    = 144,
+       }, {
+               .key    = "\xd4\x14\xc6\xcc\x16\x1b\x95\xf9"
+                         "\x05\x26\x23\x81\x19\x27\xad\x7b",
+               .klen   = 16,
+               .iv     = "\x9c\x8b\xfb\x65\xa4\x61\xee\x69"
+                         "\x44\xbf\x59\xde\x03\x61\x11\x12",
+               .ptext  = "\x8d\x94\x48\x47\xa9\x52\x16\xfb"
+                         "\x6b\xaf\x59\x6d\xab\x74\xbf\x5c"
+                         "\xb6\x09\x21\x12\x42\x98\x13\xa1"
+                         "\xa8\x6f\xb9\x6d\x4d\xa6\xdc\xea"
+                         "\x61\x02\x3c\xa7\xcd\x1a\x28\x8c"
+                         "\x66\xb8\x4d\x60\x67\x82\xcc\x8d"
+                         "\x1e\xda\x8f\x28\xe5\x02\xdc\x2c"
+                         "\x54\x84\x2a\x06\xb5\xd1\x34\x57"
+                         "\xb8\x28\x4d\xf5\x69\xb9\xf3\x33"
+                         "\x5e\x0b\xa6\x62\x35\x9b\xfb\x97"
+                         "\x3e\xc6\xec\xaf\x74\xe8\x72\x91"
+                         "\xb2\xc6\x56\xb3\x23\x29\x43\xe0"
+                         "\xfb\xcc\x21\x38\x64\x78\x9e\x78"
+                         "\xbb\x6e\x0d\x7b\xfd\x05\x74\x01"
+                         "\x7c\x94\xe0\xb0\xd7\x92\xfc\x58"
+                         "\x28\xfc\xe2\x7b\x7f\xf7\x31\x0d"
+                         "\x90\xb7\x60\x78\xa8\x9f\x52\xe3"
+                         "\xe6\xaa\x2a\xb4\xa7\x09\x60\x53"
+                         "\x42\x0e\x15\x31\xf6\x48\xa3\x0a"
+                         "\x20\xf0\x79\x67\xb1\x83\x26\x66",
+               .ctext  = "\x5b\xc0\xe8\x17\xa4\xf9\xea\xce"
+                         "\x9e\xf9\xe0\xb1\xac\x37\xe9\x41"
+                         "\xc8\x06\xf9\x1c\x1a\xfc\xe8\x7a"
+                         "\x38\xf2\x80\x66\xc2\x70\x59\x4e"
+                         "\xe0\x32\x5b\x27\x39\xf5\xfb\x03"
+                         "\xc8\xaf\xd6\x7e\x57\xc7\xc6\x71"
+                         "\xd9\xd0\x48\x39\xb1\x0d\xa8\x1a"
+                         "\x23\x8a\x3d\x05\xe2\x90\x7e\x18"
+                         "\xd7\x20\x04\x3b\x82\x76\x3f\xaa"
+                         "\xc2\x89\xb6\x9e\x14\x2f\x46\xcd"
+                         "\x51\x9b\xa8\x7b\x62\x7b\x9c\x17"
+                         "\xc4\xe1\x8b\x3f\xb5\x4d\xac\x66"
+                         "\x49\xf6\xb6\x4c\x3e\x16\x46\xb0"
+                         "\xca\x04\xef\x72\x5c\x03\x0a\xe5"
+                         "\x2f\x4e\x36\x38\x36\x9f\xf4\xe2"
+                         "\x81\x7a\x4c\xdf\x36\x27\xd5\x9d"
+                         "\x03\xad\x1d\x3a\xe9\x2a\x99\xb0"
+                         "\x2c\xba\x13\x75\xc8\x37\x97\x11"
+                         "\xf4\x15\x0f\xb7\x75\x26\xa1\x14"
+                         "\x79\xec\x1f\xab\xd2\x10\x8c\x5f",
+               .len    = 160,
+       }, {
+               .key    = "\x7f\x92\xd5\x06\x30\x6b\xc0\x23"
+                         "\x87\xa8\x8e\x6d\xc7\xc5\xd7\xf1"
+                         "\x5f\xce\x89\xb3\xd5\x7f\x7f\xf0",
+               .klen   = 24,
+               .iv     = "\xfd\xab\x56\xa6\x6e\xda\x7c\x57"
+                         "\x36\x36\x89\x09\xcd\xa8\xd3\x91",
+               .ptext  = "\x48\x3e\x3c\x11\xcf\xd0\x4f\xc0"
+                         "\x51\xe3\x8c\xe9\x76\xcd\xff\x37",
+               .ctext  = "\xa4\x12\x2f\xc4\xf0\x6d\xd9\x46"
+                         "\xe4\xe6\xd1\x0b\x6d\x14\xf0\x8f",
+               .len    = 16,
+       }, {
+               .key    = "\xd6\x1a\x18\x2f\x68\x2f\xb6\xfe"
+                         "\x3d\x2d\x85\x75\x6e\x18\x8a\x52"
+                         "\x53\x39\xfc\xc1\xf5\xc0\x56\x22",
+               .klen   = 24,
+               .iv     = "\xc6\xae\xaa\x0d\x90\xf2\x38\x93"
+                         "\xac\xd2\x3f\xc7\x74\x8d\x13\x7e",
+               .ptext  = "\xfa\x3f\x70\x52\xfb\x04\x0e\xed"
+                         "\x0e\x60\x75\x84\x21\xdf\x13\xa1"
+                         "\x26\xf8\x8c\x26\x0a\x37\x51\x8f"
+                         "\xe7\x9c\x74\x77\x7a\x3e\xbb\x5d",
+               .ctext  = "\x80\x2b\xf0\x88\xb9\x4b\x8d\xf5"
+                         "\xc3\x0e\x15\x5b\xea\x5d\x5b\xa8"
+                         "\x52\xe7\x83\x3c\xa1\x51\x1c\x1f"
+                         "\x38\xd9\x7c\x88\x3c\x3a\xcd\x3e",
+               .len    = 32,
+       }, {
+               .key    = "\xd7\x33\xf3\xa9\x5b\xb4\x86\xea"
+                         "\xe3\x7d\x50\x62\x3b\x73\xaf\xc4"
+                         "\xda\x89\xd9\x3c\xcc\xe4\x73\xb0",
+               .klen   = 24,
+               .iv     = "\xef\x3e\x5f\x46\x62\x88\xd5\x26"
+                         "\x3b\xd3\xb5\x81\x78\x70\x1b\xd2",
+               .ptext  = "\x39\x56\x34\x63\x2c\xc5\x51\x13"
+                         "\x48\x29\x3a\x58\xbe\x41\xc5\x80"
+                         "\x2c\x80\xa7\x3c\x14\xb4\x89\x5e"
+                         "\x8e\xe5\x5f\xe2\x39\x80\xf5\x2b"
+                         "\x77\xb5\xca\x90\xda\x1d\x22\x17"
+                         "\xd9\xa0\x57\x80\xc8\x96\x70\x86",
+               .ctext  = "\x65\x01\x3c\xb0\xac\x4c\x63\xb6"
+                         "\xe7\xf1\xf4\x61\x35\xf4\x36\xde"
+                         "\xeb\x0f\x8c\x34\xd1\x78\xb4\x00"
+                         "\xb2\xc1\x7c\x28\xb2\xb7\xbb\xa3"
+                         "\xc6\xb7\x27\xf7\x6d\x56\x79\xfa"
+                         "\x61\x57\xba\x30\x6f\x56\xe9\x8c",
+               .len    = 48,
+       }, {
+               .key    = "\x07\x2c\xf4\x61\x79\x09\x01\x8f"
+                         "\x37\x32\x98\xd4\x86\x2b\x3b\x80"
+                         "\x07\x60\xba\xf0\x2e\xc3\x4a\x57",
+               .klen   = 24,
+               .iv     = "\xf5\xb5\xd7\xbf\xd2\x2a\x9b\x4a"
+                         "\xe6\x08\xf0\xbe\x77\xd1\x62\x40",
+               .ptext  = "\xa0\x82\x09\x60\x47\xbb\x16\x56"
+                         "\x50\x1f\xab\x8b\x10\xfe\xf0\x5c"
+                         "\x05\x32\x63\x1a\xc4\x46\x6f\x55"
+                         "\x32\xde\x41\x5a\xf7\x52\xd7\xfa"
+                         "\x30\x9d\x59\x8d\x64\x76\xad\x37"
+                         "\xba\xbc\x46\x6a\x69\x17\x3c\xac"
+                         "\x6f\xdd\xa2\x9b\x86\x32\x14\x2e"
+                         "\x54\x74\x8f\x3d\xe2\xd6\x85\x44",
+               .ctext  = "\x5a\xfb\xb1\x2c\x6e\xe5\xb8\xe0"
+                         "\x80\xb6\x77\xa8\xfe\x10\x3a\x99"
+                         "\xbf\xc0\x2a\xfe\x6f\x38\xf2\x1d"
+                         "\x53\x6c\x05\x83\xb1\x13\x00\x87"
+                         "\x92\x92\x42\x70\xcf\x9f\xf7\x8f"
+                         "\x53\x55\x18\x6f\x35\x68\x35\x50"
+                         "\x3a\xc8\x45\x3e\xa3\xf1\x33\x2e"
+                         "\xa1\x65\x42\xe2\x6d\x31\x8c\x4b",
+               .len    = 64,
+       }, {
+               .key    = "\x4f\x4a\x31\x64\xc6\xa5\x29\xaa"
+                         "\xad\xfd\x32\x94\x1f\x56\x57\xd1"
+                         "\x9d\x7e\x3d\x49\x00\x36\xb1\x5d",
+               .klen   = 24,
+               .iv     = "\xb2\x92\x83\x70\x1e\xa3\x97\xa6"
+                         "\x65\x53\x39\xeb\x53\x8f\xb1\x38",
+               .ptext  = "\x91\xac\x17\x11\x1c\x03\x69\x53"
+                         "\xf5\xdf\xdb\x2c\x1b\x9a\x6e\x6b"
+                         "\xb6\x02\xc4\xfa\x95\x01\x33\xa8"
+                         "\xda\x7e\x18\x2c\xf4\x7e\x6e\x67"
+                         "\xce\x8f\x9f\xea\x46\x66\x99\xb8"
+                         "\xe1\xc7\x25\x4d\xbd\xa5\x74\xdf"
+                         "\xc7\x8b\xfb\xe3\x2d\x3a\x82\xd3"
+                         "\x17\x94\x77\x2f\x92\xb8\x87\xc2"
+                         "\xcc\x6f\x70\x26\x87\xc7\x10\x8a"
+                         "\xc8\xfd\xc2\xb3\xcf\xa0\xeb\x41",
+               .ctext  = "\xc9\x5f\xe0\x60\x61\x38\x7e\x79"
+                         "\x52\x68\x64\x8f\x55\x9b\x6b\x72"
+                         "\xa5\x17\x61\xb7\xce\x02\xa9\xa4"
+                         "\x5c\x73\x45\x33\xd1\x07\x5e\xdc"
+                         "\xe5\xbe\xa7\xde\x69\xa0\x97\x98"
+                         "\x02\xef\xa4\x67\x51\x60\x69\x4f"
+                         "\x03\xf5\xa8\x5f\x03\x69\xbc\xc2"
+                         "\x34\x59\x7e\xd4\xd2\xb3\x32\x2f"
+                         "\x0c\xb4\x37\xca\xc4\xc7\x93\xf4"
+                         "\xa4\xab\x01\x3f\x91\x29\x55\x98",
+               .len    = 80,
+       }, {
+               .key    = "\x4c\xf4\xd0\x34\xd0\x95\xab\xae"
+                         "\x82\x5c\xfd\xfa\x13\x86\x25\xce"
+                         "\xf4\x13\x32\xcd\xc6\x6d\xf6\x50",
+               .klen   = 24,
+               .iv     = "\x12\x4a\x5b\x66\x3a\xd3\xfb\x1a"
+                         "\xaf\x06\xea\xf4\x65\x59\xd6\xc2",
+               .ptext  = "\x84\xa0\x53\x97\x61\x30\x70\x15"
+                         "\xac\x45\x8e\xe8\xeb\xa1\x72\x93"
+                         "\x26\x76\x98\x6f\xe4\x86\xca\xf0"
+                         "\x57\x89\xf2\x2b\xd4\xcf\x2d\x95"
+                         "\x86\x26\x20\x0e\x62\xfe\x8f\x1e"
+                         "\x5d\xcb\x2b\x7e\xdd\xab\xac\xda"
+                         "\x6e\x49\x20\xd5\xb7\x01\x83\x4e"
+                         "\xac\x45\x8f\xe1\x05\x3f\xd5\xb1"
+                         "\xee\xb7\x0d\x65\x00\x38\xab\x71"
+                         "\x70\x6e\xb3\x97\x86\xd3\xcd\xad"
+                         "\x51\x8b\x9c\xa0\x9a\x8b\x4c\xb9"
+                         "\x16\x01\x6a\x1f\xdf\xf0\xf9\x9e",
+               .ctext  = "\x03\x2c\x39\x24\x99\xb5\xf6\x79"
+                         "\x91\x89\xb7\xf8\x89\x68\x37\x9d"
+                         "\xa2\x80\x95\x74\x87\x64\xb9\xeb"
+                         "\x85\x28\x92\x9a\x6e\xd3\x3b\x50"
+                         "\x4c\x80\x5b\xe4\xf2\x7e\xda\x2a"
+                         "\xd4\xf8\xcb\xe3\x6f\xdf\xae\x0e"
+                         "\xc5\x6c\x0b\x49\x2e\x29\x1c\xf2"
+                         "\x3f\x44\x44\x12\x67\xa6\xff\x44"
+                         "\xe0\xec\xd8\xf7\x32\xde\x21\x15"
+                         "\xab\x8f\x98\x4d\xed\xb0\x42\xfd"
+                         "\x83\x94\xe2\xcc\x69\x6d\xe8\xdb"
+                         "\x62\x93\x1f\xd0\xf4\x8c\x62\xc0",
+               .len    = 96,
+       }, {
+               .key    = "\x25\x1b\xc2\xa6\x21\x25\xeb\x97"
+                         "\x4b\xf6\xcb\x3b\xcd\x61\xfd\x94"
+                         "\x37\x03\xb3\xd9\x74\x6e\x4d\xbb",
+               .klen   = 24,
+               .iv     = "\xfd\x87\x2b\xec\x4c\x2c\xbf\xe2"
+                         "\x94\x1a\xe6\xd9\xaf\x0e\x78\x17",
+               .ptext  = "\x58\x2b\x1d\x73\x9a\x9c\x63\x18"
+                         "\x88\x7a\x0e\x87\x2f\xf0\xb0\xdb"
+                         "\xc9\x9d\x79\x51\x34\x39\x4f\x07"
+                         "\xa2\x7c\x21\x04\x91\x3b\x79\x79"
+                         "\xfe\xd5\x51\x46\xd5\xcd\x28\xc0"
+                         "\xad\xb8\x55\xb2\xb2\x5a\x9a\xa2"
+                         "\xe2\x0c\xfc\x55\x7d\x60\xd2\x95"
+                         "\xb6\x08\x1d\x31\xaf\xf4\x17\x46"
+                         "\xa4\xbb\x0f\xbd\x67\x3c\x73\x15"
+                         "\x0c\x85\x2f\x62\xe5\xf4\x35\x96"
+                         "\xb1\x9b\x5d\x00\x10\xe9\x70\x12"
+                         "\x3a\x87\x7f\x67\xf1\x81\x7a\x05"
+                         "\xb4\xa6\xfe\xdf\x36\x31\x6d\x9e"
+                         "\x0e\xa9\x44\xa0\xb0\x05\xa9\x41",
+               .ctext  = "\xd4\x9a\x04\x54\x05\xd2\xe6\x3f"
+                         "\xb0\xa4\x36\x5e\x1e\x9c\x35\xb0"
+                         "\xc0\x89\xbd\x1c\xaa\x45\xa6\xc8"
+                         "\x16\x68\x4a\x06\x93\x67\x88\xd7"
+                         "\x72\x6e\x48\x0a\x17\xa3\x52\x8b"
+                         "\x96\x5f\x41\xf6\x17\x64\x55\x8b"
+                         "\xac\xce\xf6\x8c\xce\xd2\xd4\xd4"
+                         "\x8d\x92\x32\xe0\x0d\xb4\xf7\x4a"
+                         "\x90\xaf\x7b\x85\x21\x46\x2e\xa6"
+                         "\x9e\xac\x0d\x22\xf2\x26\xf6\xd3"
+                         "\x27\xcd\x59\xa0\xe2\xbb\x22\xcd"
+                         "\x35\xb6\x28\x45\x0a\x46\xb0\x3a"
+                         "\xac\x3e\xd3\x5b\xc6\x54\xa2\xa3"
+                         "\x6d\xbb\xb3\xcd\xc5\x64\x62\x92",
+               .len    = 112,
+       }, {
+               .key    = "\x9c\x14\x44\x5a\xd5\x1c\x50\x08"
+                         "\x95\xc2\xf2\xaf\x3f\x29\xc9\x3e"
+                         "\x95\x5e\xc6\xb4\x2b\xf4\x3e\xe3",
+               .klen   = 24,
+               .iv     = "\x1b\xeb\x3d\x73\xfb\xd7\x1e\x2b"
+                         "\x0c\x3d\x58\x6c\xb4\x41\x9b\xfe",
+               .ptext  = "\x2f\x7e\x1c\x10\x81\x36\x2d\x79"
+                         "\xaf\xab\x10\x44\x2e\xcc\x0d\x6c"
+                         "\x9c\x14\xc2\xe4\xae\xb0\xbb\xda"
+                         "\x6a\xe0\x42\x3d\x96\x9f\x78\x7d"
+                         "\x70\x86\xa5\x92\x9f\xee\xcd\x3f"
+                         "\x6a\x55\x84\x98\x28\x03\x02\xc2"
+                         "\xf7\xec\x7a\xfa\xb1\xd9\xa8\xd8"
+                         "\x1c\xc3\xaa\xd5\x61\x7f\x10\x0c"
+                         "\xc0\xa1\x36\x3d\x81\x9a\xd2\x17"
+                         "\x2e\x23\xc9\xb7\xff\xdf\x47\x6c"
+                         "\x96\x3b\x0e\xbd\xec\x9a\x0e\xad"
+                         "\x8c\xaf\x36\x3d\xff\x29\x8b\x33"
+                         "\x87\x96\x77\x1a\x10\x81\x63\x8a"
+                         "\x63\xde\x88\xa9\x9d\xa9\x01\xf2"
+                         "\xdf\xc9\x25\x35\x48\x3a\x15\xdf"
+                         "\x20\x6b\x91\x7c\x56\xe5\x10\x7a",
+               .ctext  = "\xbc\x57\x2a\x88\x0a\xd0\x06\x4f"
+                         "\xdb\x7b\x03\x9f\x97\x1a\x20\xfe"
+                         "\x15\x91\xb4\xed\x5d\x78\x89\x2a"
+                         "\x67\x6b\x9c\x47\x36\xc2\x80\x0e"
+                         "\x03\x8d\x6f\xfc\x94\xc7\xc5\xc2"
+                         "\xeb\x43\x74\x5d\xfe\xc4\x5a\xa1"
+                         "\x80\x51\x8a\x63\xd1\x27\x1b\x0a"
+                         "\x88\x2c\xc4\x7f\x1a\xa3\x28\xe5"
+                         "\xfd\xd0\x8a\xd4\x36\xa6\x19\xd5"
+                         "\xff\x41\x7a\x8b\x6e\x9a\x97\x14"
+                         "\x2a\xc8\xd0\xb8\xa3\x8e\x64\x32"
+                         "\xb7\x2d\x76\x9b\x3b\xe2\x3f\x91"
+                         "\xb4\x64\xbf\x59\x67\x14\xc3\xf5"
+                         "\xa8\x92\x4b\x85\xdf\x80\xcb\xb5"
+                         "\xc7\x80\xf9\x4a\xbc\xed\x67\x5a"
+                         "\x0b\x58\x65\x1f\xc9\x6e\x9b\x0a",
+               .len    = 128,
+       }, {
+               .key    = "\x2d\x2e\x0f\x30\x32\xed\xa9\x1f"
+                         "\x71\x4e\x68\x77\xe8\xa8\x5b\xdd"
+                         "\x3c\x5e\x68\x6b\xab\x03\xe4\xf8",
+               .klen   = 24,
+               .iv     = "\x42\xc1\x61\x9a\x50\xfb\xc7\x6a"
+                         "\x1a\x31\xa7\x87\xd0\x24\xcb\x5e",
+               .ptext  = "\xc0\x3b\x12\x28\xca\x26\x7b\xb3"
+                         "\x14\xc1\x7f\x66\xff\x3b\xa4\x80"
+                         "\x59\x77\x4f\xa0\xd4\xb2\xd9\x8a"
+                         "\xb6\x67\xe6\x28\xd3\x6f\xf2\xcf"
+                         "\xb8\x6d\x2d\xc4\x2a\x69\x89\xff"
+                         "\xcf\xbb\x11\x2e\x2a\x2b\x7c\xfd"
+                         "\xcd\x56\x02\x95\xc9\x54\x6e\x62"
+                         "\x6a\x97\x75\x1a\x21\x16\x46\xfb"
+                         "\xc2\xab\x62\x54\xef\xba\xae\x46"
+                         "\xd4\x14\xc6\xcc\x16\x1b\x95\xf9"
+                         "\x05\x26\x23\x81\x19\x27\xad\x7b"
+                         "\x9c\x8b\xfb\x65\xa4\x61\xee\x69"
+                         "\x44\xbf\x59\xde\x03\x61\x11\x12"
+                         "\x8d\x94\x48\x47\xa9\x52\x16\xfb"
+                         "\x6b\xaf\x59\x6d\xab\x74\xbf\x5c"
+                         "\xb6\x09\x21\x12\x42\x98\x13\xa1"
+                         "\xa8\x6f\xb9\x6d\x4d\xa6\xdc\xea"
+                         "\x61\x02\x3c\xa7\xcd\x1a\x28\x8c",
+               .ctext  = "\xd7\xb4\xfc\xcc\x1f\xf7\xfc\x7d"
+                         "\x69\xfa\xcb\x01\x60\xf3\x5a\x14"
+                         "\xfe\x8c\x4e\xfa\x09\xb5\x0d\xda"
+                         "\xff\xdd\xba\xdf\xa3\x6b\x3a\x87"
+                         "\x21\xbb\xf8\x62\x14\x22\xdd\x9b"
+                         "\x92\x23\xaa\xd7\xcc\xb2\x15\xd0"
+                         "\xbd\x81\x95\x24\xc2\xc6\x53\x5b"
+                         "\xf7\x3c\xa0\xf7\x36\xbc\xbf\xf3"
+                         "\xfc\x1c\x6e\xe0\x71\x8d\xa1\x3d"
+                         "\x8e\x1a\xc5\xba\xd5\x68\xd4\x7a"
+                         "\xe0\x4f\x0a\x14\x89\x0b\xa6\x2f"
+                         "\x18\xc5\x38\x76\xf1\xe7\x5c\xae"
+                         "\x7a\xbb\x27\x1c\xf0\x7c\x6c\x14"
+                         "\x07\xb7\x49\x6e\x29\x04\x38\x31"
+                         "\x91\xe8\x1d\x0f\xfc\x3b\xb8\x20"
+                         "\x58\x64\x11\xa1\xf5\xba\xa3\x62"
+                         "\x92\xcf\x44\x63\x2c\xe8\x10\xb5"
+                         "\xf0\x97\x86\xcb\x5f\xc1\x80\x7a",
+               .len    = 144,
+       }, {
+               .key    = "\x66\xb8\x4d\x60\x67\x82\xcc\x8d"
+                         "\x1e\xda\x8f\x28\xe5\x02\xdc\x2c"
+                         "\x54\x84\x2a\x06\xb5\xd1\x34\x57",
+               .klen   = 24,
+               .iv     = "\xb8\x28\x4d\xf5\x69\xb9\xf3\x33"
+                         "\x5e\x0b\xa6\x62\x35\x9b\xfb\x97",
+               .ptext  = "\x3e\xc6\xec\xaf\x74\xe8\x72\x91"
+                         "\xb2\xc6\x56\xb3\x23\x29\x43\xe0"
+                         "\xfb\xcc\x21\x38\x64\x78\x9e\x78"
+                         "\xbb\x6e\x0d\x7b\xfd\x05\x74\x01"
+                         "\x7c\x94\xe0\xb0\xd7\x92\xfc\x58"
+                         "\x28\xfc\xe2\x7b\x7f\xf7\x31\x0d"
+                         "\x90\xb7\x60\x78\xa8\x9f\x52\xe3"
+                         "\xe6\xaa\x2a\xb4\xa7\x09\x60\x53"
+                         "\x42\x0e\x15\x31\xf6\x48\xa3\x0a"
+                         "\x20\xf0\x79\x67\xb1\x83\x26\x66"
+                         "\xe0\xb1\xb3\xbd\x1c\x76\x36\xfd"
+                         "\x45\x87\xa4\x14\x1b\xef\xe7\x16"
+                         "\xf7\xfa\x30\x3d\xb9\x52\x8f\x2e"
+                         "\x01\x68\xc1\x7d\xa2\x15\x49\x74"
+                         "\x53\x82\xc2\x10\xa8\x45\x73\x4d"
+                         "\x41\xcc\x24\xa3\x42\xff\x30\xd1"
+                         "\x02\x21\xdc\xd9\x08\xf7\xe7\x4c"
+                         "\x33\x2d\x62\xc7\x38\xf5\xc2\xbe"
+                         "\x52\xf1\x34\x78\x34\x53\x30\x5b"
+                         "\x43\x43\x51\x6a\x02\x81\x64\x0c",
+               .ctext  = "\x71\xf6\x96\x02\x07\x71\x1a\x08"
+                         "\x7c\xfe\x33\xc4\xc9\xbe\xe2\xed"
+                         "\xd0\xcc\x5d\x27\x75\xb4\x5d\x8d"
+                         "\x24\x03\xe4\x96\x31\x94\x0e\x38"
+                         "\x14\x4f\xad\x16\x58\x0d\x73\xdc"
+                         "\xbe\x5b\xcb\x38\xeb\x4d\xbc\x9a"
+                         "\x44\x69\x7a\x12\x91\x14\x52\xfa"
+                         "\xd2\xa2\xc5\x66\xd7\xaf\x4d\xb9"
+                         "\xb1\x58\x24\x10\xde\x6a\xee\x7e"
+                         "\x45\xf3\x76\xea\x47\x8a\xe6\x96"
+                         "\x41\xf2\x96\x2d\x3c\xec\xcf\xc6"
+                         "\x1d\xf4\x26\xc0\xea\x90\x27\x6e"
+                         "\x87\xef\xb5\x39\x38\xdb\xad\xbf"
+                         "\x57\x9a\x1d\xbc\x1d\xe5\x16\x91"
+                         "\x41\x45\xbe\x67\x6c\x42\x0f\xad"
+                         "\xcf\xfb\xcd\xf1\x4c\xd8\x73\xe7"
+                         "\x24\x3b\xd7\x03\xeb\xd1\xb1\x1b"
+                         "\x7d\xc9\x3d\x34\xd7\xb8\x69\x03"
+                         "\x76\x95\x32\x26\xed\x88\x76\x89"
+                         "\x13\xc6\xc8\xa6\x60\xf9\x73\x4d",
+               .len    = 160,
+       }, {
+               .key    = "\x82\x8e\x9e\x06\x7b\xc2\xe9\xb3"
+                         "\x06\xa3\xfa\x99\x42\x67\x87\xac"
+                         "\x21\xc7\xb0\x98\x6c\xf8\x26\x57"
+                         "\x08\xdd\x92\x02\x77\x7b\x35\xe7",
+               .klen   = 32,
+               .iv     = "\xa1\xad\xcb\xdd\xd5\x19\xb6\xd4"
+                         "\x0b\x62\x58\xb0\x6c\xa0\xc1\x58",
+               .ptext  = "\x14\x0d\x8a\x09\x16\x00\x00\xf1"
+                         "\xc0\x20\x86\xf9\x21\xd1\x34\xe2",
+               .ctext  = "\x05\xe3\x34\xaf\x6c\x83\x14\x8b"
+                         "\x9d\x1c\xd6\x87\x74\x91\xdf\x17",
+               .len    = 16,
+       }, {
+               .key    = "\xc9\xf3\xc4\x93\xd0\xcc\xaf\xb1"
+                         "\x1a\x42\x93\x71\xd8\x4e\xd8\xaa"
+                         "\x52\xad\x93\x2f\xe5\xd9\xaa\x5b"
+                         "\x47\x37\x3a\xed\x13\x92\x35\x16",
+               .klen   = 32,
+               .iv     = "\x81\xc8\x50\xd1\x74\xc3\x1c\x73"
+                         "\xbb\xab\x72\x83\x90\x5a\x15\xcb",
+               .ptext  = "\x65\x11\x93\xaf\xe1\x69\x6c\xbe"
+                         "\x25\x8c\x76\x87\x53\xa4\x80\xae"
+                         "\x51\x94\x36\x3f\xca\xe7\x45\x41"
+                         "\x76\x05\xbf\x8f\x9c\xad\xc0\xe3",
+               .ctext  = "\x6B\x00\x6E\x49\x7A\x6D\xE3\x04"
+                         "\x4E\xF7\x9F\x8A\x1F\x14\xBD\xB1"
+                         "\xD3\x5D\xA4\x30\x26\x85\x85\xEF"
+                         "\x12\xBC\xC7\xA1\x65\x82\xA7\x74",
+               .len    = 32,
+       }, {
+               .key    = "\xd5\x9f\x52\x34\x12\x99\x8e\x42"
+                         "\xe0\x85\x04\x6f\xeb\xf1\x5d\xd0"
+                         "\xc1\xbf\x3f\x84\xd9\x1e\x71\x44"
+                         "\xd4\xb9\x40\x3c\x02\x2e\x21\x19",
+               .klen   = 32,
+               .iv     = "\x28\xc1\x97\x64\x81\x52\x57\x0e"
+                         "\x02\x8c\xab\x4c\xe2\x60\x14\xa5",
+               .ptext  = "\x5a\xb1\x33\x48\xaa\x51\xe9\xa4"
+                         "\x5c\x2d\xbe\x33\xcc\xc4\x7f\x96"
+                         "\xe8\xde\x2b\xe7\x35\x7a\x11\x4b"
+                         "\x13\x08\x32\xc6\x41\xd8\xec\x54"
+                         "\xa3\xd3\xda\x35\x43\x69\xf6\x88"
+                         "\x97\xca\x00\x1b\x02\x59\x24\x82",
+               .ctext  = "\x03\xaf\x76\xbd\x5e\x5b\xca\xc0"
+                         "\xae\x44\xa2\x2f\xc2\x76\x2f\x50"
+                         "\x6a\x73\x28\xf2\xba\xe8\xb2\xb8"
+                         "\x43\x61\x41\x92\xff\xac\xcb\xa6"
+                         "\x84\x31\xe3\x34\xd0\x37\x81\xab"
+                         "\x2b\x0e\x97\x3c\x4a\x2d\xa4\x83",
+               .len    = 48,
+       }, {
+               .key    = "\x9c\x5d\xd7\x66\x36\xfa\x02\x20"
+                         "\x99\x61\x62\x86\x0f\x43\x2e\x05"
+                         "\x25\x8b\xfb\xf1\xae\x4c\xde\x18"
+                         "\x0b\xf8\xd0\x9d\xaa\xd4\x56\x04",
+               .klen   = 32,
+               .iv     = "\xcd\xa8\x61\x89\x8d\xbb\x72\xb6"
+                         "\x1e\xfe\x03\x34\x54\x88\x23\xe2",
+               .ptext  = "\x66\x42\x60\x24\xf3\xe4\xe9\x7e"
+                         "\x42\x20\xf4\x61\xce\x1c\x5e\x44"
+                         "\x02\x26\x91\xf7\x41\xa4\xab\x34"
+                         "\x29\x49\xdd\x78\x19\x8f\x10\x10"
+                         "\xf0\x61\xcf\x77\x18\x17\x61\xdf"
+                         "\xc4\xa8\x35\x0e\x75\x1b\x84\x6b"
+                         "\xc3\x3f\x31\x59\x5a\x9c\xf4\xc3"
+                         "\x43\xa9\xb7\xf8\x65\x40\x40\xba",
+               .ctext  = "\xb6\x41\x55\x8f\xeb\x16\x1e\x4c"
+                         "\x81\xa0\x85\x6c\xf0\x07\xa5\x2a"
+                         "\x12\x0f\x1d\xb2\xaa\xba\x85\x0f"
+                         "\xa6\x27\x1a\x91\xa6\xc5\x8c\x2a"
+                         "\xde\x8d\x3a\xa9\x8b\xcf\x24\xf1"
+                         "\x82\x51\x6b\xc8\x01\xd7\x7b\x89"
+                         "\x6c\xfc\xb1\x96\x6c\xa2\xd7\x1f"
+                         "\x4b\x7a\xd9\x8d\x34\xaa\xa0\x8a",
+               .len    = 64,
+       }, {
+               .key    = "\x4b\x4e\x11\x91\x27\xcf\x8c\x66"
+                         "\x17\xfa\x5b\x4c\xa8\xb8\x0f\xa1"
+                         "\x99\x5b\x07\x56\xe1\x8d\x94\x8b"
+                         "\xf2\x86\x5a\x5f\x40\x83\xfa\x06",
+               .klen   = 32,
+               .iv     = "\xfd\x73\xee\x1c\x27\xf3\xb4\x38"
+                         "\xc5\x7c\x2e\xc5\x6e\xdb\x49\x0d",
+               .ptext  = "\x0a\xe2\xdd\x97\xdd\x5e\xd4\xb3"
+                         "\xc1\x49\x8f\x53\xb2\x40\x85\x1c"
+                         "\x90\x37\x2d\xbd\x21\x6b\x1f\x80"
+                         "\x56\x98\x76\x1e\xcf\x6c\x78\xd8"
+                         "\xa0\x3c\x79\xc3\x56\xf7\xfc\x64"
+                         "\x35\x58\x1c\x7c\xc4\x5f\x2a\x25"
+                         "\x8c\x01\x98\x1e\x1c\x1f\x15\x64"
+                         "\x50\xb5\xfa\x02\xd3\x54\xe5\x29"
+                         "\xe3\xd2\xa3\x83\x54\x40\x54\xc5"
+                         "\xd8\x1c\xc9\x84\x7d\xc8\x31\x49",
+               .ctext  = "\x53\x2a\xa8\xa0\x15\xaf\x2f\xc4"
+                         "\x7d\x31\xb4\x61\x80\x5f\xd1\xb6"
+                         "\xa4\x29\x40\x72\x1b\xb2\x96\xb7"
+                         "\x4d\x5e\x5b\x53\x44\xa4\xf1\xe9"
+                         "\xf0\x27\x2f\x26\x84\x66\x13\xa4"
+                         "\xb2\x19\x55\xb1\x18\xf3\x69\xfd"
+                         "\xb0\x2f\x08\x3f\xa5\x41\xe2\x34"
+                         "\x5e\x63\x57\x0e\xef\x17\x78\xbc"
+                         "\xc3\x65\x7c\xbe\x6b\xa3\xa3\xef"
+                         "\x58\x05\x30\x5a\x08\xbd\xf7\x0e",
+               .len    = 80,
+       }, {
+               .key    = "\x77\x3b\xf5\xe7\x20\xf7\xe0\x0c"
+                         "\x3d\x3a\x83\x17\x83\x79\xd8\x29"
+                         "\x5a\x0a\x25\x7f\xe0\x21\x23\xff"
+                         "\x31\xfd\x60\x10\xe6\x63\xe2\xaf",
+               .klen   = 32,
+               .iv     = "\xdb\x4c\x0d\xc0\x36\xdb\xc7\xa1"
+                         "\xa4\x91\xd9\x05\xe6\xc4\x98\x00",
+               .ptext  = "\x8d\x4d\xc6\x5e\x01\x82\xb3\x39"
+                         "\xc8\x64\xa7\xcb\x05\x19\x84\x80"
+                         "\x3f\x9c\xa8\x4f\x64\xb3\x11\x4b"
+                         "\x0e\x21\xc4\x75\x04\x1d\x6f\xd5"
+                         "\x04\x04\x4d\xc9\xc0\x4b\x4a\x9c"
+                         "\x26\xb7\x68\x5a\xe4\xd0\x61\xe3"
+                         "\x2c\x93\x8e\x3f\xb4\x67\x07\x31"
+                         "\x02\x52\x0c\x0f\xe6\x6d\xa3\xd0"
+                         "\x48\x95\x83\x67\x23\x64\x31\x50"
+                         "\xd2\x5f\x69\x68\x8b\x71\xbf\x01"
+                         "\x29\x99\x86\x36\x2e\xdf\xf1\x7c"
+                         "\x08\x8c\x78\x7a\x93\x9a\x7d\x1b",
+               .ctext  = "\x92\x90\x48\x2f\x3a\x6b\x68\x43"
+                         "\x28\x9b\x7d\x1e\x46\x28\xd8\x58"
+                         "\x0f\x47\x8b\xb5\x83\x35\x35\x3e"
+                         "\xdf\x59\x3d\xb3\x47\xfc\xfc\x52"
+                         "\x86\xeb\xb3\x58\x54\xd5\x0a\xb4"
+                         "\xad\xbd\x5c\x09\xfc\x08\xc2\x01"
+                         "\x5e\x9b\x30\x11\xc4\x40\x2e\x32"
+                         "\x9c\xa0\xf1\xfd\xae\xd4\x75\x5e"
+                         "\x52\xd9\x19\x4d\xc1\xd4\xb6\x19"
+                         "\x88\xfb\x29\x17\x15\xbb\x60\xd6"
+                         "\x5a\xe9\x82\x89\xaf\x30\x4e\xd4"
+                         "\x47\xde\x86\x88\x95\x4c\x13\x59",
+               .len    = 96,
+       }, {
+               .key    = "\xe0\x6a\x30\xe1\x35\xb5\xb0\x7c"
+                         "\x54\xc5\x73\x9b\x00\xe5\xe7\x02"
+                         "\xbe\x16\x59\xdc\xd9\x03\x17\x53"
+                         "\xa8\x37\xd1\x5f\x13\x8e\x45\xdb",
+               .klen   = 32,
+               .iv     = "\x54\xe9\x1c\xde\xfb\x26\x0e\x48"
+                         "\x35\x50\x4d\x9b\x4d\x12\x21\x0d",
+               .ptext  = "\x73\x72\xcf\xdb\xbd\xbc\xc0\xdf"
+                         "\x6b\xbb\xdf\x65\x6f\x2f\x43\x3b"
+                         "\x2d\x7c\x0e\x07\x7f\xa0\x95\xdd"
+                         "\xfc\x67\xc1\x11\x7a\xe2\xb5\x4a"
+                         "\xd1\x15\xb0\xd8\xe2\xf0\x35\x48"
+                         "\xd8\x81\x6a\x35\xae\x67\xbf\x61"
+                         "\xf2\x8a\xcf\x04\xc8\x09\x8b\x63"
+                         "\x31\x74\x95\xa5\x8d\x3c\xea\xe2"
+                         "\x5f\x67\xc4\x7e\x51\x88\xbf\xb5"
+                         "\x78\xef\x3a\x76\xd8\x1d\x00\x75"
+                         "\x2b\x7b\x28\x7c\xde\x4b\x39\x01"
+                         "\x5d\xde\x92\xfe\x90\x07\x09\xfd"
+                         "\xa5\xd1\xd3\x72\x11\x6d\xa4\x4e"
+                         "\xd1\x6e\x16\xd1\xf6\x39\x4f\xa0",
+               .ctext  = "\x3b\xc5\xee\xfc\x05\xaf\xa6\xb7"
+                         "\xfe\x12\x24\x79\x31\xad\x32\xb5"
+                         "\x64\x5a\x17\xc9\xbf\x1f\xdc\xce"
+                         "\x8d\x73\x00\x71\xd9\xfb\xd2\xe6"
+                         "\xc3\x54\xb4\xf3\x36\xe8\x89\x12"
+                         "\x5a\x32\x0b\xa6\xec\x5f\x89\xe7"
+                         "\xe8\x34\x92\xa6\xce\xde\x8f\xf9"
+                         "\x4f\xda\xed\x61\x8e\xb2\x81\xbe"
+                         "\xf2\x15\x85\xbe\xa1\x5f\x19\x85"
+                         "\x71\x7e\xda\x46\x59\xed\x5d\xb0"
+                         "\xd9\x68\x97\xe0\xcd\x1d\x1b\x65"
+                         "\xf5\xc9\x44\xe2\xb4\x42\x17\x7c"
+                         "\xe7\x58\xf3\x2f\xcf\xbe\x5c\x66"
+                         "\xaa\xd3\x61\xa5\x9a\x79\xbb\xa0",
+               .len    = 112,
+       }, {
+               .key    = "\x60\xb6\xde\x17\xca\x4c\xe7\xe0"
+                         "\x07\x0d\x80\xc5\x8a\x2d\x5a\xc2"
+                         "\x2c\xb9\xa4\x5f\x2a\x85\x2c\x3d"
+                         "\x6d\x67\xc8\xee\x0f\xa2\xf4\x09",
+               .klen   = 32,
+               .iv     = "\x1a\xa5\xbc\x7e\x93\xf6\xdd\x28"
+                         "\xb7\x69\x27\xa1\x84\x95\x25\x5a",
+               .ptext  = "\x7b\x88\x00\xeb\xa5\xba\xa1\xa7"
+                         "\xd4\x40\x16\x74\x2b\x42\x37\xda"
+                         "\xe0\xaf\x89\x59\x41\x2f\x62\x00"
+                         "\xf5\x5a\x4e\x3b\x85\x27\xb2\xed"
+                         "\x1b\xa7\xaf\xbe\x89\xf3\x49\xb7"
+                         "\x8c\x63\xc9\x0c\x52\x00\x5f\x38"
+                         "\x3b\x3c\x0c\x4f\xdd\xe1\xbf\x90"
+                         "\x4a\x48\xbf\x3a\x95\xcb\x48\xa2"
+                         "\x92\x7c\x79\x81\xde\x18\x6e\x92"
+                         "\x1f\x36\xa9\x5d\x8d\xc4\xb6\x4d"
+                         "\xb2\xb4\x0e\x09\x6d\xf3\x3d\x01"
+                         "\x3d\x9b\x40\x47\xbc\x69\x31\xa1"
+                         "\x6a\x71\x26\xdc\xac\x10\x56\x63"
+                         "\x15\x23\x7d\x10\xe3\x76\x82\x41"
+                         "\xcd\x80\x57\x2f\xfc\x4d\x22\x7b"
+                         "\x57\xbb\x9a\x0a\x03\xe9\xb3\x13",
+               .ctext  = "\x37\x0d\x47\x21\xbc\x28\x0b\xf7"
+                         "\x85\x5f\x60\x57\xf2\x7f\x92\x20"
+                         "\x53\x1a\xbf\xd1\x7f\x8c\x39\x29"
+                         "\x0e\x18\xab\x0c\x00\x92\xd3\x68"
+                         "\x60\x56\x3b\x00\xef\xf8\x02\xfa"
+                         "\xcb\x92\x1a\x91\xe1\xf0\x4f\x8a"
+                         "\xc6\x4f\x65\x16\x71\x8b\x5d\xd5"
+                         "\x79\xa9\x6d\x68\x1b\x59\xe7\x2a"
+                         "\x1c\xd0\x5d\xfb\x06\x3b\x15\x72"
+                         "\xa8\xd1\x59\x9a\xb2\x6c\xf2\xd5"
+                         "\x19\xef\xde\x03\x4c\x75\x65\x38"
+                         "\x5b\xda\xc9\xf0\x44\x99\xb2\x6e"
+                         "\x78\xfb\x85\x5a\x92\x91\x1a\x0a"
+                         "\x13\x0c\x1b\x1c\xbe\xbe\x46\x6e"
+                         "\x73\xff\xc2\x6e\xb9\x06\x16\x7e"
+                         "\xf6\xc0\x01\x30\x34\x56\x46\x55",
+               .len    = 128,
+       }, {
+               .key    = "\x2a\xed\x7d\x76\xfc\xc5\x49\x50"
+                         "\xf4\x90\x0f\xcc\x5d\xff\x0c\x3c"
+                         "\x14\x06\xaf\x68\x8f\xd7\xb6\x25"
+                         "\x1e\x10\x95\x2a\x71\x33\x17\x20",
+               .klen   = 32,
+               .iv     = "\x5b\x58\x47\xf8\xd5\x1e\x91\x81"
+                         "\x46\xe7\x25\x3a\x02\x45\x9c\x65",
+               .ptext  = "\x10\xaf\xde\x5c\x30\x79\x43\x28"
+                         "\x1c\x03\xf8\x50\x0f\x30\xa5\xef"
+                         "\x84\x19\x4c\x09\x40\x03\x75\x1f"
+                         "\x92\x8f\x88\x01\xda\x31\x7a\xe4"
+                         "\x48\xe3\xab\xb4\xe6\x1b\x0f\xac"
+                         "\xd9\xfa\x8d\x23\xe4\xc6\xa4\xa9"
+                         "\x2d\x9a\x54\x52\x44\x5c\x3c\x52"
+                         "\x61\xf0\x00\xca\xed\xab\xed\xe2"
+                         "\x44\x0b\xe0\x18\xba\xa5\x63\xd8"
+                         "\xdc\x5e\x1a\x4c\xf8\xde\x5e\x75"
+                         "\xdf\x42\x27\x7b\xe9\x11\x2f\x41"
+                         "\x3a\x72\x54\x3d\x44\x9c\x3e\x87"
+                         "\x8d\x8d\x43\x2f\xb2\xff\x87\xd4"
+                         "\xad\x98\x68\x72\x53\x61\x19\x7c"
+                         "\x20\x79\x8c\x2b\x37\x0b\x96\x15"
+                         "\xa5\x7d\x4e\x01\xe6\xea\xb6\xfa"
+                         "\xaa\xd3\x9d\xa2\xd9\x11\xc3\xc9"
+                         "\xd4\x0e\x3f\x3e\xfe\x35\x1e\xe5",
+               .ctext  = "\xb0\x2b\x75\x5f\x33\x1b\x05\x49"
+                         "\x06\xf1\x43\x91\xc2\x85\xfa\xac"
+                         "\x74\xd5\x8c\xc9\x47\x6e\x5a\xf6"
+                         "\x69\x33\x4c\xcb\x2f\x36\x4b\x41"
+                         "\xec\x05\x69\xab\x7f\x42\xc9\xd2"
+                         "\x26\x64\x51\x9e\x3d\x65\x35\xf0"
+                         "\x8d\x5e\x8a\xb1\xee\xdf\x1a\x98"
+                         "\x36\xd2\x37\x49\x5b\xe2\x57\x00"
+                         "\x1d\x72\x7e\xe8\x38\x11\x83\x15"
+                         "\xc7\x4e\x65\xa4\x2c\x9e\x6a\x3e"
+                         "\xb4\x78\x3f\xe9\x91\x5d\x06\xa9"
+                         "\xf1\xfc\x6b\x08\xe5\x2b\x2a\x99"
+                         "\x65\xa7\x2e\x47\xf9\xc2\xb1\x8b"
+                         "\x88\x2f\xb7\x62\x84\x63\x94\x00"
+                         "\x49\xa7\xd0\x2b\x54\x7a\x69\xb3"
+                         "\x04\x66\xfc\x97\x40\x92\xd1\xb8"
+                         "\xb4\x2a\x9e\xdb\x31\xcd\x48\x84"
+                         "\x29\x3b\x02\xac\xb8\x54\x95\xb4",
+               .len    = 144,
+       }, {
+               .key    = "\x7b\xa7\x4d\x0a\x37\x30\xb9\xf5"
+                         "\x2a\x79\xb4\xbf\xdb\x7f\x9b\x64"
+                         "\x23\x43\xb5\x18\x34\xc4\x5f\xdf"
+                         "\xd9\x2a\x66\x58\x00\x44\xb5\xd9",
+               .klen   = 32,
+               .iv     = "\x75\x34\x30\xc1\xf0\x69\xdf\x0a"
+                         "\x52\xce\x4f\x1e\x2c\x41\x35\xec",
+               .ptext  = "\x81\x47\x55\x3a\xcd\xfe\xa2\x3d"
+                         "\x45\x53\xa7\x67\x61\x74\x25\x80"
+                         "\x98\x89\xfe\xf8\x6a\x9f\x51\x7c"
+                         "\xa4\xe4\xe7\xc7\xe0\x1a\xce\xbb"
+                         "\x4b\x46\x43\xb0\xab\xa8\xd6\x0c"
+                         "\xa0\xf0\xc8\x13\x29\xaf\xb8\x01"
+                         "\x6b\x0c\x7e\x56\xae\xb8\x58\x72"
+                         "\xa9\x24\x44\x61\xff\xf1\xac\xf8"
+                         "\x09\xa8\x48\x21\xd6\xab\x41\x73"
+                         "\x70\x6b\x92\x06\x61\xdc\xb4\x85"
+                         "\x76\x26\x7a\x84\xc3\x9e\x3a\x14"
+                         "\xe7\xf4\x2d\x95\x92\xad\x18\xcc"
+                         "\x44\xd4\x2c\x36\x57\xed\x2b\x9b"
+                         "\x3f\x2b\xcd\xe5\x11\xe3\x62\x33"
+                         "\x42\x3f\xb8\x2a\xb1\x37\x3f\x8b"
+                         "\xe8\xbd\x6b\x0b\x9f\x38\x5a\x5f"
+                         "\x82\x34\xb7\x96\x35\x58\xde\xab"
+                         "\x94\x98\x41\x5b\x3f\xac\x0a\x34"
+                         "\x56\xc0\x02\xef\x81\x6d\xb1\xff"
+                         "\x34\xe8\xc7\x6a\x31\x79\xba\xd8",
+               .ctext  = "\x4e\x00\x7c\x52\x45\x76\xf9\x3d"
+                         "\x1a\xd1\x72\xbc\xb9\x0f\xa9\xfb"
+                         "\x0a\xf5\xe8\x11\x66\x8b\xad\x68"
+                         "\x5a\x2e\xbf\x09\x33\x9d\xb6\x67"
+                         "\xe5\xcb\x0a\xe0\xac\xed\x73\x4b"
+                         "\xbb\x15\xde\xd8\xab\x33\x28\x5f"
+                         "\x96\x07\x3c\x28\x79\x88\x84\xc7"
+                         "\x13\xf7\x0d\xa5\x97\x3b\xd9\xb1"
+                         "\xf2\x65\xb0\xac\xbb\x8a\x97\xd1"
+                         "\x70\x3a\x91\x65\xc8\x39\x04\xe7"
+                         "\x1a\x9c\x80\x65\x2b\x69\x4b\xdc"
+                         "\xdc\xc7\xf1\x31\xda\xab\xb4\xd7"
+                         "\x46\x2e\x1d\xc9\x2e\xe9\x46\xec"
+                         "\xa4\xa1\x91\x6b\x4a\x09\xf9\x39"
+                         "\x7b\x7d\x6d\xf5\x43\x7f\xcc\x74"
+                         "\x96\xfa\x48\xd0\xe1\x74\x24\xd0"
+                         "\x19\x22\x24\x84\x2b\x12\x10\x46"
+                         "\x90\xbd\xa9\x93\xb7\xf7\x36\xd4"
+                         "\x48\xc7\x32\x83\x8c\xa9\xcd\x5a"
+                         "\x2f\x05\x33\xc1\x5b\x50\x70\xc4",
+               .len    = 160,
+       }
+};
+
+static const struct aead_testvec aria_gcm_tv_template[] = {
+       {
+               .key    = "\xe9\x1e\x5e\x75\xda\x65\x55\x4a"
+                         "\x48\x18\x1f\x38\x46\x34\x95\x62",
+               .klen   = 16,
+               .iv     = "\x00\x00\x20\xe8\xf5\xeb\x00\x00"
+                         "\x00\x00\x31\x5e",
+               .assoc  = "\x80\x08\x31\x5e\xbf\x2e\x6f\xe0"
+                         "\x20\xe8\xf5\xeb",
+               .alen   = 12,
+               .ptext  = "\xf5\x7a\xf5\xfd\x4a\xe1\x95\x62"
+                         "\x97\x6e\xc5\x7a\x5a\x7a\xd5\x5a"
+                         "\x5a\xf5\xc5\xe5\xc5\xfd\xf5\xc5"
+                         "\x5a\xd5\x7a\x4a\x72\x72\xd5\x72"
+                         "\x62\xe9\x72\x95\x66\xed\x66\xe9"
+                         "\x7a\xc5\x4a\x4a\x5a\x7a\xd5\xe1"
+                         "\x5a\xe5\xfd\xd5\xfd\x5a\xc5\xd5"
+                         "\x6a\xe5\x6a\xd5\xc5\x72\xd5\x4a"
+                         "\xe5\x4a\xc5\x5a\x95\x6a\xfd\x6a"
+                         "\xed\x5a\x4a\xc5\x62\x95\x7a\x95"
+                         "\x16\x99\x16\x91\xd5\x72\xfd\x14"
+                         "\xe9\x7a\xe9\x62\xed\x7a\x9f\x4a"
+                         "\x95\x5a\xf5\x72\xe1\x62\xf5\x7a"
+                         "\x95\x66\x66\xe1\x7a\xe1\xf5\x4a"
+                         "\x95\xf5\x66\xd5\x4a\x66\xe1\x6e"
+                         "\x4a\xfd\x6a\x9f\x7a\xe1\xc5\xc5"
+                         "\x5a\xe5\xd5\x6a\xfd\xe9\x16\xc5"
+                         "\xe9\x4a\x6e\xc5\x66\x95\xe1\x4a"
+                         "\xfd\xe1\x14\x84\x16\xe9\x4a\xd5"
+                         "\x7a\xc5\x14\x6e\xd5\x9d\x1c\xc5",
+               .plen   = 160,
+               .ctext  = "\x4d\x8a\x9a\x06\x75\x55\x0c\x70"
+                         "\x4b\x17\xd8\xc9\xdd\xc8\x1a\x5c"
+                         "\xd6\xf7\xda\x34\xf2\xfe\x1b\x3d"
+                         "\xb7\xcb\x3d\xfb\x96\x97\x10\x2e"
+                         "\xa0\xf3\xc1\xfc\x2d\xbc\x87\x3d"
+                         "\x44\xbc\xee\xae\x8e\x44\x42\x97"
+                         "\x4b\xa2\x1f\xf6\x78\x9d\x32\x72"
+                         "\x61\x3f\xb9\x63\x1a\x7c\xf3\xf1"
+                         "\x4b\xac\xbe\xb4\x21\x63\x3a\x90"
+                         "\xff\xbe\x58\xc2\xfa\x6b\xdc\xa5"
+                         "\x34\xf1\x0d\x0d\xe0\x50\x2c\xe1"
+                         "\xd5\x31\xb6\x33\x6e\x58\x87\x82"
+                         "\x78\x53\x1e\x5c\x22\xbc\x6c\x85"
+                         "\xbb\xd7\x84\xd7\x8d\x9e\x68\x0a"
+                         "\xa1\x90\x31\xaa\xf8\x91\x01\xd6"
+                         "\x69\xd7\xa3\x96\x5c\x1f\x7e\x16"
+                         "\x22\x9d\x74\x63\xe0\x53\x5f\x4e"
+                         "\x25\x3f\x5d\x18\x18\x7d\x40\xb8"
+                         "\xae\x0f\x56\x4b\xd9\x70\xb5\xe7"
+                         "\xe2\xad\xfb\x21\x1e\x89\xa9\x53"
+                         "\x5a\xba\xce\x3f\x37\xf5\xa7\x36"
+                         "\xf4\xbe\x98\x4b\xbf\xfb\xed\xc1",
+               .clen   = 176,
+       }, {
+               .key    = "\x0c\x5f\xfd\x37\xa1\x1e\xdc\x42"
+                         "\xc3\x25\x28\x7f\xc0\x60\x4f\x2e"
+                         "\x3e\x8c\xd5\x67\x1a\x00\xfe\x32"
+                         "\x16\xaa\x5e\xb1\x05\x78\x3b\x54",
+               .klen   = 32,
+               .iv     = "\x00\x00\x20\xe8\xf5\xeb\x00\x00"
+                         "\x00\x00\x31\x5e",
+               .assoc  = "\x80\x08\x31\x5e\xbf\x2e\x6f\xe0"
+                         "\x20\xe8\xf5\xeb",
+               .alen   = 12,
+               .ptext  = "\xf5\x7a\xf5\xfd\x4a\xe1\x95\x62"
+                         "\x97\x6e\xc5\x7a\x5a\x7a\xd5\x5a"
+                         "\x5a\xf5\xc5\xe5\xc5\xfd\xf5\xc5"
+                         "\x5a\xd5\x7a\x4a\x72\x72\xd5\x72"
+                         "\x62\xe9\x72\x95\x66\xed\x66\xe9"
+                         "\x7a\xc5\x4a\x4a\x5a\x7a\xd5\xe1"
+                         "\x5a\xe5\xfd\xd5\xfd\x5a\xc5\xd5"
+                         "\x6a\xe5\x6a\xd5\xc5\x72\xd5\x4a"
+                         "\xe5\x4a\xc5\x5a\x95\x6a\xfd\x6a"
+                         "\xed\x5a\x4a\xc5\x62\x95\x7a\x95"
+                         "\x16\x99\x16\x91\xd5\x72\xfd\x14"
+                         "\xe9\x7a\xe9\x62\xed\x7a\x9f\x4a"
+                         "\x95\x5a\xf5\x72\xe1\x62\xf5\x7a"
+                         "\x95\x66\x66\xe1\x7a\xe1\xf5\x4a"
+                         "\x95\xf5\x66\xd5\x4a\x66\xe1\x6e"
+                         "\x4a\xfd\x6a\x9f\x7a\xe1\xc5\xc5"
+                         "\x5a\xe5\xd5\x6a\xfd\xe9\x16\xc5"
+                         "\xe9\x4a\x6e\xc5\x66\x95\xe1\x4a"
+                         "\xfd\xe1\x14\x84\x16\xe9\x4a\xd5"
+                         "\x7a\xc5\x14\x6e\xd5\x9d\x1c\xc5",
+               .plen   = 160,
+               .ctext  = "\x6f\x9e\x4b\xcb\xc8\xc8\x5f\xc0"
+                         "\x12\x8f\xb1\xe4\xa0\xa2\x0c\xb9"
+                         "\x93\x2f\xf7\x45\x81\xf5\x4f\xc0"
+                         "\x13\xdd\x05\x4b\x19\xf9\x93\x71"
+                         "\x42\x5b\x35\x2d\x97\xd3\xf3\x37"
+                         "\xb9\x0b\x63\xd1\xb0\x82\xad\xee"
+                         "\xea\x9d\x2d\x73\x91\x89\x7d\x59"
+                         "\x1b\x98\x5e\x55\xfb\x50\xcb\x53"
+                         "\x50\xcf\x7d\x38\xdc\x27\xdd\xa1"
+                         "\x27\xc0\x78\xa1\x49\xc8\xeb\x98"
+                         "\x08\x3d\x66\x36\x3a\x46\xe3\x72"
+                         "\x6a\xf2\x17\xd3\xa0\x02\x75\xad"
+                         "\x5b\xf7\x72\xc7\x61\x0e\xa4\xc2"
+                         "\x30\x06\x87\x8f\x0e\xe6\x9a\x83"
+                         "\x97\x70\x31\x69\xa4\x19\x30\x3f"
+                         "\x40\xb7\x2e\x45\x73\x71\x4d\x19"
+                         "\xe2\x69\x7d\xf6\x1e\x7c\x72\x52"
+                         "\xe5\xab\xc6\xba\xde\x87\x6a\xc4"
+                         "\x96\x1b\xfa\xc4\xd5\xe8\x67\xaf"
+                         "\xca\x35\x1a\x48\xae\xd5\x28\x22"
+                         "\xe2\x10\xd6\xce\xd2\xcf\x43\x0f"
+                         "\xf8\x41\x47\x29\x15\xe7\xef\x48",
+               .clen   = 176,
+       }
+};
+
 static const struct cipher_testvec chacha20_tv_template[] = {
        { /* RFC7539 A.2. Test Vector #1 */
                .key    = "\x00\x00\x00\x00\x00\x00\x00\x00"
@@ -34034,221 +36997,1540 @@ static const struct hash_testvec blake2b_512_tv_template[] = {{
                          0xae, 0x15, 0x81, 0x15, 0xd0, 0x88, 0xa0, 0x3c, },
 }};
 
-static const struct hash_testvec blakes2s_128_tv_template[] = {{
-       .digest = (u8[]){ 0x64, 0x55, 0x0d, 0x6f, 0xfe, 0x2c, 0x0a, 0x01,
-                         0xa1, 0x4a, 0xba, 0x1e, 0xad, 0xe0, 0x20, 0x0c, },
-}, {
-       .plaintext = blake2_ordered_sequence,
-       .psize = 64,
-       .digest = (u8[]){ 0xdc, 0x66, 0xca, 0x8f, 0x03, 0x86, 0x58, 0x01,
-                         0xb0, 0xff, 0xe0, 0x6e, 0xd8, 0xa1, 0xa9, 0x0e, },
-}, {
-       .ksize = 16,
-       .key = blake2_ordered_sequence,
-       .plaintext = blake2_ordered_sequence,
-       .psize = 1,
-       .digest = (u8[]){ 0x88, 0x1e, 0x42, 0xe7, 0xbb, 0x35, 0x80, 0x82,
-                         0x63, 0x7c, 0x0a, 0x0f, 0xd7, 0xec, 0x6c, 0x2f, },
-}, {
-       .ksize = 32,
-       .key = blake2_ordered_sequence,
-       .plaintext = blake2_ordered_sequence,
-       .psize = 7,
-       .digest = (u8[]){ 0xcf, 0x9e, 0x07, 0x2a, 0xd5, 0x22, 0xf2, 0xcd,
-                         0xa2, 0xd8, 0x25, 0x21, 0x80, 0x86, 0x73, 0x1c, },
-}, {
-       .ksize = 1,
-       .key = "B",
-       .plaintext = blake2_ordered_sequence,
-       .psize = 15,
-       .digest = (u8[]){ 0xf6, 0x33, 0x5a, 0x2c, 0x22, 0xa0, 0x64, 0xb2,
-                         0xb6, 0x3f, 0xeb, 0xbc, 0xd1, 0xc3, 0xe5, 0xb2, },
-}, {
-       .ksize = 16,
-       .key = blake2_ordered_sequence,
-       .plaintext = blake2_ordered_sequence,
-       .psize = 247,
-       .digest = (u8[]){ 0x72, 0x66, 0x49, 0x60, 0xf9, 0x4a, 0xea, 0xbe,
-                         0x1f, 0xf4, 0x60, 0xce, 0xb7, 0x81, 0xcb, 0x09, },
-}, {
-       .ksize = 32,
-       .key = blake2_ordered_sequence,
-       .plaintext = blake2_ordered_sequence,
-       .psize = 256,
-       .digest = (u8[]){ 0xd5, 0xa4, 0x0e, 0xc3, 0x16, 0xc7, 0x51, 0xa6,
-                         0x3c, 0xd0, 0xd9, 0x11, 0x57, 0xfa, 0x1e, 0xbb, },
-}};
+/*
+ * Test vectors generated using https://github.com/google/hctr2
+ */
+static const struct cipher_testvec aes_xctr_tv_template[] = {
+       {
+               .key    = "\x9c\x8d\xc4\xbd\x71\x36\xdc\x82"
+                         "\x7c\xa1\xca\xa3\x23\x5a\xdb\xa4",
+               .iv     = "\x8d\xe7\xa5\x6a\x95\x86\x42\xde"
+                         "\xba\xea\x6e\x69\x03\x33\x86\x0f",
+               .ptext  = "\xbd",
+               .ctext  = "\xb9",
+               .klen   = 16,
+               .len    = 1,
+       },
+       {
+               .key    = "\xbc\x1b\x12\x0c\x3f\x18\xcc\x1f"
+                         "\x5a\x1d\xab\x81\xa8\x68\x7c\x63",
+               .iv     = "\x22\xc1\xdd\x25\x0b\x18\xcb\xa5"
+                         "\x4a\xda\x15\x07\x73\xd9\x88\x10",
+               .ptext  = "\x24\x6e\x64\xc6\x15\x26\x9c\xda"
+                         "\x2a\x4b\x57\x12\xff\x7c\xd6\xb5",
+               .ctext  = "\xd6\x47\x8d\x58\x92\xb2\x84\xf9"
+                         "\xb7\xee\x0d\x98\xa1\x39\x4d\x8f",
+               .klen   = 16,
+               .len    = 16,
+       },
+       {
+               .key    = "\x44\x03\xbf\x4c\x30\xf0\xa7\xd6"
+                         "\xbd\x54\xbb\x66\x8e\xa6\x0e\x8a",
+               .iv     = "\xe6\xf7\x26\xdf\x8c\x3c\xaa\x88"
+                         "\xce\xc1\xbd\x43\x3b\x09\x62\xad",
+               .ptext  = "\x3c\xe3\x46\xb9\x8f\x9d\x3f\x8d"
+                         "\xef\xf2\x53\xab\x24\xe2\x29\x08"
+                         "\xf8\x7e\x1d\xa6\x6d\x86\x7d\x60"
+                         "\x97\x63\x93\x29\x71\x94\xb4",
+               .ctext  = "\xd4\xa3\xc6\xb8\xc1\x6f\x70\x1a"
+                         "\x52\x0c\xed\x4c\xaf\x51\x56\x23"
+                         "\x48\x45\x07\x10\x34\xc5\xba\x71"
+                         "\xe5\xf8\x1e\xd8\xcb\xa6\xe7",
+               .klen   = 16,
+               .len    = 31,
+       },
+       {
+               .key    = "\x5b\x17\x30\x94\x19\x31\xa1\xae"
+                         "\x24\x8e\x42\x1e\x82\xe6\xec\xb8",
+               .iv     = "\xd1\x2e\xb9\xb8\xf8\x49\xeb\x68"
+                         "\x06\xeb\x65\x33\x34\xa2\xeb\xf0",
+               .ptext  = "\x19\x75\xec\x59\x60\x1b\x7a\x3e"
+                         "\x62\x46\x87\xf0\xde\xab\x81\x36"
+                         "\x63\x53\x11\xa0\x1f\xce\x25\x85"
+                         "\x49\x6b\x28\xfa\x1c\x92\xe5\x18"
+                         "\x38\x14\x00\x79\xf2\x9e\xeb\xfc"
+                         "\x36\xa7\x6b\xe1\xe5\xcf\x04\x48"
+                         "\x44\x6d\xbd\x64\xb3\xcb\x78\x05"
+                         "\x8d\x7f\x9a\xaf\x3c\xcf\x6c\x45"
+                         "\x6c\x7c\x46\x4c\xa8\xc0\x1e\xe4"
+                         "\x33\xa5\x7b\xbb\x26\xd9\xc0\x32"
+                         "\x9d\x8a\xb3\xf3\x3d\x52\xe6\x48"
+                         "\x4c\x9b\x4c\x6e\xa4\xa3\xad\x66"
+                         "\x56\x48\xd5\x98\x3a\x93\xc4\x85"
+                         "\xe9\x89\xca\xa6\xc1\xc8\xe7\xf8"
+                         "\xc3\xe9\xef\xbe\x77\xe6\xd1\x3a"
+                         "\xa6\x99\xc8\x2d\xdf\x40\x0f\x44",
+               .ctext  = "\xc6\x1a\x01\x1a\x00\xba\x04\xff"
+                         "\x10\xd1\x7e\x5d\xad\x91\xde\x8c"
+                         "\x08\x55\x95\xae\xd7\x22\x77\x40"
+                         "\xf0\x33\x1b\x51\xef\xfe\x3d\x67"
+                         "\xdf\xc4\x9f\x39\x47\x67\x93\xab"
+                         "\xaa\x37\x55\xfe\x41\xe0\xba\xcd"
+                         "\x25\x02\x7c\x61\x51\xa1\xcc\x72"
+                         "\x7a\x20\x26\xb9\x06\x68\xbd\x19"
+                         "\xc5\x2e\x1b\x75\x4a\x40\xb2\xd2"
+                         "\xc4\xee\xd8\x5b\xa4\x55\x7d\x25"
+                         "\xfc\x01\x4d\x6f\x0a\xfd\x37\x5d"
+                         "\x3e\x67\xc0\x35\x72\x53\x7b\xe2"
+                         "\xd6\x19\x5b\x92\x6c\x3a\x8c\x2a"
+                         "\xe2\xc2\xa2\x4f\x2a\xf2\xb5\x15"
+                         "\x65\xc5\x8d\x97\xf9\xbf\x8c\x98"
+                         "\xe4\x50\x1a\xf2\x76\x55\x07\x49",
+               .klen   = 16,
+               .len    = 128,
+       },
+       {
+               .key    = "\x17\xa6\x01\x3d\x5d\xd6\xef\x2d"
+                         "\x69\x8f\x4c\x54\x5b\xae\x43\xf0",
+               .iv     = "\xa9\x1b\x47\x60\x26\x82\xf7\x1c"
+                         "\x80\xf8\x88\xdd\xfb\x44\xd9\xda",
+               .ptext  = "\xf7\x67\xcd\xa6\x04\x65\x53\x99"
+                         "\x90\x5c\xa2\x56\x74\xd7\x9d\xf2"
+                         "\x0b\x03\x7f\x4e\xa7\x84\x72\x2b"
+                         "\xf0\xa5\xbf\xe6\x9a\x62\x3a\xfe"
+                         "\x69\x5c\x93\x79\x23\x86\x64\x85"
+                         "\xeb\x13\xb1\x5a\xd5\x48\x39\xa0"
+                         "\x70\xfb\x06\x9a\xd7\x12\x5a\xb9"
+                         "\xbe\xed\x2c\x81\x64\xf7\xcf\x80"
+                         "\xee\xe6\x28\x32\x2d\x37\x4c\x32"
+                         "\xf4\x1f\x23\x21\xe9\xc8\xc9\xbf"
+                         "\x54\xbc\xcf\xb4\xc2\x65\x39\xdf"
+                         "\xa5\xfb\x14\x11\xed\x62\x38\xcf"
+                         "\x9b\x58\x11\xdd\xe9\xbd\x37\x57"
+                         "\x75\x4c\x9e\xd5\x67\x0a\x48\xc6"
+                         "\x0d\x05\x4e\xb1\x06\xd7\xec\x2e"
+                         "\x9e\x59\xde\x4f\xab\x38\xbb\xe5"
+                         "\x87\x04\x5a\x2c\x2a\xa2\x8f\x3c"
+                         "\xe7\xe1\x46\xa9\x49\x9f\x24\xad"
+                         "\x2d\xb0\x55\x40\x64\xd5\xda\x7e"
+                         "\x1e\x77\xb8\x29\x72\x73\xc3\x84"
+                         "\xcd\xf3\x94\x90\x58\x76\xc9\x2c"
+                         "\x2a\xad\x56\xde\x33\x18\xb6\x3b"
+                         "\x10\xe9\xe9\x8d\xf0\xa9\x7f\x05"
+                         "\xf7\xb5\x8c\x13\x7e\x11\x3d\x1e"
+                         "\x02\xbb\x5b\xea\x69\xff\x85\xcf"
+                         "\x6a\x18\x97\x45\xe3\x96\xba\x4d"
+                         "\x2d\x7a\x70\x78\x15\x2c\xe9\xdc"
+                         "\x4e\x09\x92\x57\x04\xd8\x0b\xa6"
+                         "\x20\x71\x76\x47\x76\x96\x89\xa0"
+                         "\xd9\x29\xa2\x5a\x06\xdb\x56\x39"
+                         "\x60\x33\x59\x04\x95\x89\xf6\x18"
+                         "\x1d\x70\x75\x85\x3a\xb7\x6e",
+               .ctext  = "\xe1\xe7\x3f\xd3\x6a\xb9\x2f\x64"
+                         "\x37\xc5\xa4\xe9\xca\x0a\xa1\xd6"
+                         "\xea\x7d\x39\xe5\xe6\xcc\x80\x54"
+                         "\x74\x31\x2a\x04\x33\x79\x8c\x8e"
+                         "\x4d\x47\x84\x28\x27\x9b\x3c\x58"
+                         "\x54\x58\x20\x4f\x70\x01\x52\x5b"
+                         "\xac\x95\x61\x49\x5f\xef\xba\xce"
+                         "\xd7\x74\x56\xe7\xbb\xe0\x3c\xd0"
+                         "\x7f\xa9\x23\x57\x33\x2a\xf6\xcb"
+                         "\xbe\x42\x14\x95\xa8\xf9\x7a\x7e"
+                         "\x12\x53\x3a\xe2\x13\xfe\x2d\x89"
+                         "\xeb\xac\xd7\xa8\xa5\xf8\x27\xf3"
+                         "\x74\x9a\x65\x63\xd1\x98\x3a\x7e"
+                         "\x27\x7b\xc0\x20\x00\x4d\xf4\xe5"
+                         "\x7b\x69\xa6\xa8\x06\x50\x85\xb6"
+                         "\x7f\xac\x7f\xda\x1f\xf5\x37\x56"
+                         "\x9b\x2f\xd3\x86\x6b\x70\xbd\x0e"
+                         "\x55\x9a\x9d\x4b\x08\xb5\x5b\x7b"
+                         "\xd4\x7c\xb4\x71\x49\x92\x4a\x1e"
+                         "\xed\x6d\x11\x09\x47\x72\x32\x6a"
+                         "\x97\x53\x36\xaf\xf3\x06\x06\x2c"
+                         "\x69\xf1\x59\x00\x36\x95\x28\x2a"
+                         "\xb6\xcd\x10\x21\x84\x73\x5c\x96"
+                         "\x86\x14\x2c\x3d\x02\xdb\x53\x9a"
+                         "\x61\xde\xea\x99\x84\x7a\x27\xf6"
+                         "\xf7\xc8\x49\x73\x4b\xb8\xeb\xd3"
+                         "\x41\x33\xdd\x09\x68\xe2\x64\xb8"
+                         "\x5f\x75\x74\x97\x91\x54\xda\xc2"
+                         "\x73\x2c\x1e\x5a\x84\x48\x01\x1a"
+                         "\x0d\x8b\x0a\xdf\x07\x2e\xee\x77"
+                         "\x1d\x17\x41\x7a\xc9\x33\x63\xfa"
+                         "\x9f\xc3\x74\x57\x5f\x03\x4c",
+               .klen   = 16,
+               .len    = 255,
+       },
+       {
+               .key    = "\xe5\xf1\x48\x2e\x88\xdb\xc7\x28"
+                         "\xa2\x55\x5d\x2f\x90\x02\xdc\xd3"
+                         "\xf5\xd3\x9e\x87\xd5\x58\x30\x4a",
+               .iv     = "\xa6\x40\x39\xf9\x63\x6c\x2d\xd4"
+                         "\x1b\x71\x05\xa4\x88\x86\x11\xd3",
+               .ptext  = "\xb6\x06\xae\x15\x11\x96\xc1\x44"
+                         "\x44\xc2\x98\xf9\xa8\x0a\x0b",
+               .ctext  = "\x27\x3b\x68\x40\xa9\x5e\x74\x6b"
+                         "\x74\x67\x18\xf9\x37\xed\xed",
+               .klen   = 24,
+               .len    = 15,
+       },
+       {
+               .key    = "\xc8\xa0\x27\x67\x04\x3f\xed\xa5"
+                         "\xb4\x0c\x51\x91\x2d\x27\x77\x33"
+                         "\xa5\xfc\x2a\x9f\x78\xd8\x1c\x68",
+               .iv     = "\x83\x99\x1a\xe2\x84\xca\xa9\x16"
+                         "\x8d\xc4\x2d\x1b\x67\xc8\x86\x21",
+               .ptext  = "\xd6\x22\x85\xb8\x5d\x7e\x26\x2e"
+                         "\xbe\x04\x9d\x0c\x03\x91\x45\x4a"
+                         "\x36",
+               .ctext  = "\x0f\x44\xa9\x62\x72\xec\x12\x26"
+                         "\x3a\xc6\x83\x26\x62\x5e\xb7\x13"
+                         "\x05",
+               .klen   = 24,
+               .len    = 17,
+       },
+       {
+               .key    = "\xc5\x87\x18\x09\x0a\x4e\x66\x3e"
+                         "\x50\x90\x19\x93\xc0\x33\xcf\x80"
+                         "\x3a\x36\x6b\x6c\x43\xd7\xe4\x93",
+               .iv     = "\xdd\x0b\x75\x1f\xee\x2f\xb4\x52"
+                         "\x10\x82\x1f\x79\x8a\xa4\x9b\x87",
+               .ptext  = "\x56\xf9\x13\xce\x9f\x30\x10\x11"
+                         "\x1b\x59\xfd\x39\x5a\x29\xa3\x44"
+                         "\x78\x97\x8c\xf6\x99\x6d\x26\xf1"
+                         "\x32\x60\x6a\xeb\x04\x47\x29\x4c"
+                         "\x7e\x14\xef\x4d\x55\x29\xfe\x36"
+                         "\x37\xcf\x0b\x6e\xf3\xce\x15\xd2",
+               .ctext  = "\x8f\x98\xe1\x5a\x7f\xfe\xc7\x05"
+                         "\x76\xb0\xd5\xde\x90\x52\x2b\xa8"
+                         "\xf3\x6e\x3c\x77\xa5\x33\x63\xdd"
+                         "\x6f\x62\x12\xb0\x80\x10\xc1\x28"
+                         "\x58\xe5\xd6\x24\x44\x04\x55\xf3"
+                         "\x6d\x94\xcb\x2c\x7e\x7a\x85\x79",
+               .klen   = 24,
+               .len    = 48,
+       },
+       {
+               .key    = "\x84\x9b\xe8\x10\x4c\xb3\xd1\x7a"
+                         "\xb3\xab\x4e\x6f\x90\x12\x07\xf8"
+                         "\xef\xde\x42\x09\xbf\x34\x95\xb2",
+               .iv     = "\x66\x62\xf9\x48\x9d\x17\xf7\xdf"
+                         "\x06\x67\xf4\x6d\xf2\xbc\xa2\xe5",
+               .ptext  = "\x2f\xd6\x16\x6b\xf9\x4b\x44\x14"
+                         "\x90\x93\xe5\xfd\x05\xaa\x00\x26"
+                         "\xbd\xab\x11\xb8\xf0\xcb\x11\x72"
+                         "\xdd\xc5\x15\x4f\x4e\x1b\xf8\xc9"
+                         "\x8f\x4a\xd5\x69\xf8\x9e\xfb\x05"
+                         "\x8a\x37\x46\xfe\xfa\x58\x9b\x0e"
+                         "\x72\x90\x9a\x06\xa5\x42\xf4\x7c"
+                         "\x35\xd5\x64\x70\x72\x67\xfc\x8b"
+                         "\xab\x5a\x2f\x64\x9b\xa1\xec\xe7"
+                         "\xe6\x92\x69\xdb\x62\xa4\xe7\x44"
+                         "\x88\x28\xd4\x52\x64\x19\xa9\xd7"
+                         "\x0c\x00\xe6\xe7\xc1\x28\xc1\xf5"
+                         "\x72\xc5\xfa\x09\x22\x2e\xf4\x82"
+                         "\xa3\xdc\xc1\x68\xf9\x29\x55\x8d"
+                         "\x04\x67\x13\xa6\x52\x04\x3c\x0c"
+                         "\x14\xf2\x87\x23\x61\xab\x82\xcb"
+                         "\x49\x5b\x6b\xd4\x4f\x0d\xd4\x95"
+                         "\x82\xcd\xe3\x69\x47\x1b\x31\x73"
+                         "\x73\x77\xc1\x53\x7d\x43\x5e\x4a"
+                         "\x80\x3a\xca\x9c\xc7\x04\x1a\x31"
+                         "\x8e\xe6\x76\x7f\xe1\xb3\xd0\x57"
+                         "\xa2\xb2\xf6\x09\x51\xc9\x6d\xbc"
+                         "\x79\xed\x57\x50\x36\xd2\x93\xa4"
+                         "\x40\x5d\xac\x3a\x3b\xb6\x2d\x89"
+                         "\x78\xa2\xbd\x23\xec\x35\x06\xf0"
+                         "\xa8\xc8\xc9\xb0\xe3\x28\x2b\xba"
+                         "\x70\xa0\xfe\xed\x13\xc4\xd7\x90"
+                         "\xb1\x6a\xe0\xe1\x30\x71\x15\xd0"
+                         "\xe2\xb3\xa6\x4e\xb0\x01\xf9\xe7"
+                         "\x59\xc6\x1e\xed\x46\x2b\xe3\xa8"
+                         "\x22\xeb\x7f\x1c\xd9\xcd\xe0\xa6"
+                         "\x72\x42\x2c\x06\x75\xbb\xb7\x6b"
+                         "\xca\x49\x5e\xa1\x47\x8d\x9e\xfe"
+                         "\x60\xcc\x34\x95\x8e\xfa\x1e\x3e"
+                         "\x85\x4b\x03\x54\xea\x34\x1c\x41"
+                         "\x90\x45\xa6\xbe\xcf\x58\x4f\xca"
+                         "\x2c\x79\xc0\x3e\x8f\xd7\x3b\xd4"
+                         "\x55\x74\xa8\xe1\x57\x09\xbf\xab"
+                         "\x2c\xf9\xe4\xdd\x17\x99\x57\x60"
+                         "\x4b\x88\x2a\x7f\x43\x86\xb9\x9a"
+                         "\x60\xbf\x4c\xcf\x9b\x41\xb8\x99"
+                         "\x69\x15\x4f\x91\x4d\xeb\xdf\x6f"
+                         "\xcc\x4c\xf9\x6f\xf2\x33\x23\xe7"
+                         "\x02\x44\xaa\xa2\xfa\xb1\x39\xa5"
+                         "\xff\x88\xf5\x37\x02\x33\x24\xfc"
+                         "\x79\x11\x4c\x94\xc2\x31\x87\x9c"
+                         "\x53\x19\x99\x32\xe4\xde\x18\xf4"
+                         "\x8f\xe2\xe8\xa3\xfb\x0b\xaa\x7c"
+                         "\xdb\x83\x0f\xf6\xc0\x8a\x9b\xcd"
+                         "\x7b\x16\x05\x5b\xe4\xb4\x34\x03"
+                         "\xe3\x8f\xc9\x4b\x56\x84\x2a\x4c"
+                         "\x36\x72\x3c\x84\x4f\xba\xa2\x7f"
+                         "\xf7\x1b\xba\x4d\x8a\xb8\x5d\x51"
+                         "\x36\xfb\xef\x23\x18\x6f\x33\x2d"
+                         "\xbb\x06\x24\x8e\x33\x98\x6e\xcd"
+                         "\x63\x11\x18\x6b\xcc\x1b\x66\xb9"
+                         "\x38\x8d\x06\x8d\x98\x1a\xef\xaa"
+                         "\x35\x4a\x90\xfa\xb1\xd3\xcc\x11"
+                         "\x50\x4c\x54\x18\x60\x5d\xe4\x11"
+                         "\xfc\x19\xe1\x53\x20\x5c\xe7\xef"
+                         "\x8a\x2b\xa8\x82\x51\x5f\x5d\x43"
+                         "\x34\xe5\xcf\x7b\x1b\x6f\x81\x19"
+                         "\xb7\xdf\xa8\x9e\x81\x89\x5f\x33"
+                         "\x69\xaf\xde\x89\x68\x88\xf0\x71",
+               .ctext  = "\xab\x15\x46\x5b\xed\x4f\xa8\xac"
+                         "\xbf\x31\x30\x84\x55\xa4\xb8\x98"
+                         "\x79\xba\xa0\x15\xa4\x55\x20\xec"
+                         "\xf9\x94\x71\xe6\x6a\x6f\xee\x87"
+                         "\x2e\x3a\xa2\x95\xae\x6e\x56\x09"
+                         "\xe9\xc0\x0f\xe2\xc6\xb7\x30\xa9"
+                         "\x73\x8e\x59\x7c\xfd\xe3\x71\xf7"
+                         "\xae\x8b\x91\xab\x5e\x36\xe9\xa8"
+                         "\xff\x17\xfa\xa2\x94\x93\x11\x42"
+                         "\x67\x96\x99\xc5\xf0\xad\x2a\x57"
+                         "\xf9\xa6\x70\x4a\xdf\x71\xff\xc0"
+                         "\xe2\xaf\x9a\xae\x57\x58\x13\x3b"
+                         "\x2d\xf1\xc7\x8f\xdb\x8a\xcc\xce"
+                         "\x53\x1a\x69\x55\x39\xc8\xbe\xc3"
+                         "\x2d\xb1\x03\xd9\xa3\x99\xf4\x8d"
+                         "\xd9\x2d\x27\xae\xa5\xe7\x77\x7f"
+                         "\xbb\x88\x84\xea\xfa\x19\x3f\x44"
+                         "\x61\x21\x8a\x1f\xbe\xac\x60\xb4"
+                         "\xaf\xe9\x00\xab\xef\x3c\x53\x56"
+                         "\xcd\x4b\x53\xd8\x9b\xfe\x88\x23"
+                         "\x5b\x85\x76\x08\xec\xd1\x6e\x4a"
+                         "\x87\xa4\x7d\x29\x4e\x4f\x3f\xc9"
+                         "\xa4\xab\x63\xea\xdd\xef\x9f\x79"
+                         "\x38\x18\x7d\x90\x90\xf9\x12\x57"
+                         "\x1d\x89\xea\xfe\xd4\x47\x45\x32"
+                         "\x6a\xf6\xe7\xde\x22\x7e\xee\xc1"
+                         "\xbc\x2d\xc3\xbb\xe5\xd4\x13\xac"
+                         "\x63\xff\x5b\xb1\x05\x96\xd5\xf3"
+                         "\x07\x9a\x62\xb6\x30\xea\x7d\x1e"
+                         "\xee\x75\x0a\x1b\xcc\x6e\x4d\xa7"
+                         "\xf7\x4d\x74\xd8\x60\x32\x5e\xd0"
+                         "\x93\xd7\x19\x90\x4e\x26\xdb\xe4"
+                         "\x5e\xd4\xa8\xb9\x76\xba\x56\x91"
+                         "\xc4\x75\x04\x1e\xc2\x77\x24\x6f"
+                         "\xf9\xe8\x4a\xec\x7f\x86\x95\xb3"
+                         "\x5c\x2c\x97\xab\xf0\xf7\x74\x5b"
+                         "\x0b\xc2\xda\x42\x40\x34\x16\xed"
+                         "\x06\xc1\x25\x53\x17\x0d\x81\x4e"
+                         "\xe6\xf2\x0f\x6d\x94\x3c\x90\x7a"
+                         "\xae\x20\xe9\x3f\xf8\x18\x67\x6a"
+                         "\x49\x1e\x41\xb6\x46\xab\xc8\xa7"
+                         "\xcb\x19\x96\xf5\x99\xc0\x66\x3e"
+                         "\x77\xcf\x73\x52\x83\x2a\xe2\x48"
+                         "\x27\x6c\xeb\xe7\xe7\xc4\xd5\x6a"
+                         "\x40\x67\xbc\xbf\x6b\x3c\xf3\xbb"
+                         "\x51\x5e\x31\xac\x03\x81\xab\x61"
+                         "\xfa\xa5\xa6\x7d\x8b\xc3\x8a\x75"
+                         "\x28\x7a\x71\x9c\xac\x8f\x76\xfc"
+                         "\xf9\x6c\x5d\x9b\xd7\xf6\x36\x2d"
+                         "\x61\xd5\x61\xaa\xdd\x01\xfc\x57"
+                         "\x91\x10\xcd\xcd\x6d\x27\x63\x24"
+                         "\x67\x46\x7a\xbb\x61\x56\x39\xb1"
+                         "\xd6\x79\xfe\x77\xca\xd6\x73\x59"
+                         "\x6e\x58\x11\x90\x03\x26\x74\x2a"
+                         "\xfa\x52\x12\x47\xfb\x12\xeb\x3e"
+                         "\x88\xf0\x52\x6c\xc0\x54\x7a\x88"
+                         "\x8c\xe5\xde\x9e\xba\xb9\xf2\xe1"
+                         "\x97\x2e\x5c\xbd\xf4\x13\x7e\xf3"
+                         "\xc4\xe1\x87\xa5\x35\xfa\x7c\x71"
+                         "\x1a\xc9\xf4\xa8\x57\xe2\x5a\x6b"
+                         "\x14\xe0\x73\xaf\x56\x6b\xa0\x00"
+                         "\x9e\x5f\x64\xac\x00\xfb\xc4\x92"
+                         "\xe5\xe2\x8a\xb2\x9e\x75\x49\x85"
+                         "\x25\x66\xa5\x1a\xf9\x7d\x1d\x60",
+               .klen   = 24,
+               .len    = 512,
+       },
+       {
+               .key    = "\x05\x60\x3a\x7e\x60\x90\x46\x18"
+                         "\x6c\x60\xba\xeb\x12\xd7\xbe\xd1"
+                         "\xd3\xf6\x10\x46\x9d\xf1\x0c\xb4"
+                         "\x73\xe3\x93\x27\xa8\x2c\x13\xaa",
+               .iv     = "\xf5\x96\xd1\xb6\xcb\x44\xd8\xd0"
+                         "\x3e\xdb\x92\x80\x08\x94\xcd\xd3",
+               .ptext  = "\x78",
+               .ctext  = "\xc5",
+               .klen   = 32,
+               .len    = 1,
+       },
+       {
+               .key    = "\x35\xca\x38\xf3\xd9\xd6\x34\xef"
+                         "\xcd\xee\xa3\x26\x86\xba\xfb\x45"
+                         "\x01\xfa\x52\x67\xff\xc5\x9d\xaa"
+                         "\x64\x9a\x05\xbb\x85\x20\xa7\xf2",
+               .iv     = "\xe3\xda\xf5\xff\x42\x59\x87\x86"
+                         "\xee\x7b\xd6\xb4\x6a\x25\x44\xff",
+               .ptext  = "\x44\x67\x1e\x04\x53\xd2\x4b\xd9"
+                         "\x96\x33\x07\x54\xe4\x8e\x20",
+               .ctext  = "\xcc\x55\x40\x79\x47\x5c\x8b\xa6"
+                         "\xca\x7b\x9f\x50\xe3\x21\xea",
+               .klen   = 32,
+               .len    = 15,
+       },
+       {
+               .key    = "\xaf\xd9\x14\x14\xd5\xdb\xc9\xce"
+                         "\x76\x5c\x5a\xbf\x43\x05\x29\x24"
+                         "\xc4\x13\x68\xcc\xe8\x37\xbd\xb9"
+                         "\x41\x20\xf5\x53\x48\xd0\xa2\xd6",
+               .iv     = "\xa7\xb4\x00\x08\x79\x10\xae\xf5"
+                         "\x02\xbf\x85\xb2\x69\x4c\xc6\x04",
+               .ptext  = "\xac\x6a\xa8\x0c\xb0\x84\xbf\x4c"
+                         "\xae\x94\x20\x58\x7e\x00\x93\x89",
+               .ctext  = "\xd5\xaa\xe2\xe9\x86\x4c\x95\x4e"
+                         "\xde\xb6\x15\xcb\xdc\x1f\x13\x38",
+               .klen   = 32,
+               .len    = 16,
+       },
+       {
+               .key    = "\xed\xe3\x8b\xe7\x1c\x17\xbf\x4a"
+                         "\x02\xe2\xfc\x76\xac\xf5\x3c\x00"
+                         "\x5d\xdc\xfc\x83\xeb\x45\xb4\xcb"
+                         "\x59\x62\x60\xec\x69\x9c\x16\x45",
+               .iv     = "\xe4\x0e\x2b\x90\xd2\xfa\x94\x2e"
+                         "\x10\xe5\x64\x2b\x97\x28\x15\xc7",
+               .ptext  = "\xe6\x53\xff\x60\x0e\xc4\x51\xe4"
+                         "\x93\x4d\xe5\x55\xc5\xd9\xad\x48"
+                         "\x52",
+               .ctext  = "\xba\x25\x28\xf5\xcf\x31\x91\x80"
+                         "\xda\x2b\x95\x5f\x20\xcb\xfb\x9f"
+                         "\xc6",
+               .klen   = 32,
+               .len    = 17,
+       },
+       {
+               .key    = "\x77\x5c\xc0\x73\x9a\x64\x97\x91"
+                         "\x2f\xee\xe0\x20\xc2\x04\x59\x2e"
+                         "\x97\xd2\xa7\x70\xb3\xb0\x21\x6b"
+                         "\x8f\xbf\xb8\x51\xa8\xea\x0f\x62",
+               .iv     = "\x31\x8e\x1f\xcd\xfd\x23\xeb\x7f"
+                         "\x8a\x1f\x1b\x23\x53\x27\x44\xe5",
+               .ptext  = "\xcd\xff\x8c\x9b\x94\x5a\x51\x3f"
+                         "\x40\x93\x56\x93\x66\x39\x63\x1f"
+                         "\xbf\xe6\xa4\xfa\xbe\x79\x93\x03"
+                         "\xf5\x66\x74\x16\xfc\xe4\xce",
+               .ctext  = "\x8b\xd3\xc3\xce\x66\xf8\x66\x4c"
+                         "\xad\xd6\xf5\x0f\xd8\x99\x5a\x75"
+                         "\xa1\x3c\xab\x0b\x21\x36\x57\x72"
+                         "\x88\x29\xe9\xea\x4a\x8d\xe9",
+               .klen   = 32,
+               .len    = 31,
+       },
+       {
+               .key    = "\xa1\x2f\x4d\xde\xfe\xa1\xff\xa8"
+                         "\x73\xdd\xe3\xe2\x95\xfc\xea\x9c"
+                         "\xd0\x80\x42\x0c\xb8\x43\x3e\x99"
+                         "\x39\x38\x0a\x8c\xe8\x45\x3a\x7b",
+               .iv     = "\x32\xc4\x6f\xb1\x14\x43\xd1\x87"
+                         "\xe2\x6f\x5a\x58\x02\x36\x7e\x2a",
+               .ptext  = "\x9e\x5c\x1e\xf1\xd6\x7d\x09\x57"
+                         "\x18\x48\x55\xda\x7d\x44\xf9\x6d"
+                         "\xac\xcd\x59\xbb\x10\xa2\x94\x67"
+                         "\xd1\x6f\xfe\x6b\x4a\x11\xe8\x04"
+                         "\x09\x26\x4f\x8d\x5d\xa1\x7b\x42"
+                         "\xf9\x4b\x66\x76\x38\x12\xfe\xfe",
+               .ctext  = "\x42\xbc\xa7\x64\x15\x9a\x04\x71"
+                         "\x2c\x5f\x94\xba\x89\x3a\xad\xbc"
+                         "\x87\xb3\xf4\x09\x4f\x57\x06\x18"
+                         "\xdc\x84\x20\xf7\x64\x85\xca\x3b"
+                         "\xab\xe6\x33\x56\x34\x60\x5d\x4b"
+                         "\x2e\x16\x13\xd4\x77\xde\x2d\x2b",
+               .klen   = 32,
+               .len    = 48,
+       },
+       {
+               .key    = "\xfb\xf5\xb7\x3d\xa6\x95\x42\xbf"
+                         "\xd2\x94\x6c\x74\x0f\xbc\x5a\x28"
+                         "\x35\x3c\x51\x58\x84\xfb\x7d\x11"
+                         "\x16\x1e\x00\x97\x37\x08\xb7\x16",
+               .iv     = "\x9b\x53\x57\x40\xe6\xd9\xa7\x27"
+                         "\x78\xd4\x9b\xd2\x29\x1d\x24\xa9",
+               .ptext  = "\x8b\x02\x60\x0a\x3e\xb7\x10\x59"
+                         "\xc3\xac\xd5\x2a\x75\x81\xf2\xdb"
+                         "\x55\xca\x65\x86\x44\xfb\xfe\x91"
+                         "\x26\xbb\x45\xb2\x46\x22\x3e\x08"
+                         "\xa2\xbf\x46\xcb\x68\x7d\x45\x7b"
+                         "\xa1\x6a\x3c\x6e\x25\xeb\xed\x31"
+                         "\x7a\x8b\x47\xf9\xde\xec\x3d\x87"
+                         "\x09\x20\x2e\xfa\xba\x8b\x9b\xc5"
+                         "\x6c\x25\x9c\x9d\x2a\xe8\xab\x90"
+                         "\x3f\x86\xee\x61\x13\x21\xd4\xde"
+                         "\xe1\x0c\x95\xfc\x5c\x8a\x6e\x0a"
+                         "\x73\xcf\x08\x69\x44\x4e\xde\x25"
+                         "\xaf\xaa\x56\x04\xc4\xb3\x60\x44"
+                         "\x3b\x8b\x3d\xee\xae\x42\x4b\xd2"
+                         "\x9a\x6c\xa0\x8e\x52\x06\xb2\xd1"
+                         "\x5d\x38\x30\x6d\x27\x9b\x1a\xd8",
+               .ctext  = "\xa3\x78\x33\x78\x95\x95\x97\x07"
+                         "\x53\xa3\xa1\x5b\x18\x32\x27\xf7"
+                         "\x09\x12\x53\x70\x83\xb5\x6a\x9f"
+                         "\x26\x6d\x10\x0d\xe0\x1c\xe6\x2b"
+                         "\x70\x00\xdc\xa1\x60\xef\x1b\xee"
+                         "\xc5\xa5\x51\x17\xae\xcc\xf2\xed"
+                         "\xc4\x60\x07\xdf\xd5\x7a\xe9\x90"
+                         "\x3c\x9f\x96\x5d\x72\x65\x5d\xef"
+                         "\xd0\x94\x32\xc4\x85\x90\x78\xa1"
+                         "\x2e\x64\xf6\xee\x8e\x74\x3f\x20"
+                         "\x2f\x12\x3b\x3d\xd5\x39\x8e\x5a"
+                         "\xf9\x8f\xce\x94\x5d\x82\x18\x66"
+                         "\x14\xaf\x4c\xfe\xe0\x91\xc3\x4a"
+                         "\x85\xcf\xe7\xe8\xf7\xcb\xf0\x31"
+                         "\x88\x7d\xc9\x5b\x71\x9d\x5f\xd2"
+                         "\xfa\xed\xa6\x24\xda\xbb\xb1\x84",
+               .klen   = 32,
+               .len    = 128,
+       },
+       {
+               .key    = "\x32\x37\x2b\x8f\x7b\xb1\x23\x79"
+                         "\x05\x52\xde\x05\xf1\x68\x3f\x6c"
+                         "\xa4\xae\xbc\x21\xc2\xc6\xf0\xbd"
+                         "\x0f\x20\xb7\xa4\xc5\x05\x7b\x64",
+               .iv     = "\xff\x26\x4e\x67\x48\xdd\xcf\xfe"
+                         "\x42\x09\x04\x98\x5f\x1e\xfa\x80",
+               .ptext  = "\x99\xdc\x3b\x19\x41\xf9\xff\x6e"
+                         "\x76\xb5\x03\xfa\x61\xed\xf8\x44"
+                         "\x70\xb9\xf0\x83\x80\x6e\x31\x77"
+                         "\x77\xe4\xc7\xb4\x77\x02\xab\x91"
+                         "\x82\xc6\xf8\x7c\x46\x61\x03\x69"
+                         "\x09\xa0\xf7\x12\xb7\x81\x6c\xa9"
+                         "\x10\x5c\xbb\x55\xb3\x44\xed\xb5"
+                         "\xa2\x52\x48\x71\x90\x5d\xda\x40"
+                         "\x0b\x7f\x4a\x11\x6d\xa7\x3d\x8e"
+                         "\x1b\xcd\x9d\x4e\x75\x8b\x7d\x87"
+                         "\xe5\x39\x34\x32\x1e\xe6\x8d\x51"
+                         "\xd4\x1f\xe3\x1d\x50\xa0\x22\x37"
+                         "\x7c\xb0\xd9\xfb\xb6\xb2\x16\xf6"
+                         "\x6d\x26\xa0\x4e\x8c\x6a\xe6\xb6"
+                         "\xbe\x4c\x7c\xe3\x88\x10\x18\x90"
+                         "\x11\x50\x19\x90\xe7\x19\x3f\xd0"
+                         "\x31\x15\x0f\x06\x96\xfe\xa7\x7b"
+                         "\xc3\x32\x88\x69\xa4\x12\xe3\x64"
+                         "\x02\x30\x17\x74\x6c\x88\x7c\x9b"
+                         "\xd6\x6d\x75\xdf\x11\x86\x70\x79"
+                         "\x48\x7d\x34\x3e\x33\x58\x07\x8b"
+                         "\xd2\x50\xac\x35\x15\x45\x05\xb4"
+                         "\x4d\x31\x97\x19\x87\x23\x4b\x87"
+                         "\x53\xdc\xa9\x19\x78\xf1\xbf\x35"
+                         "\x30\x04\x14\xd4\xcf\xb2\x8c\x87"
+                         "\x7d\xdb\x69\xc9\xcd\xfe\x40\x3e"
+                         "\x8d\x66\x5b\x61\xe5\xf0\x2d\x87"
+                         "\x93\x3a\x0c\x2b\x04\x98\x05\xc2"
+                         "\x56\x4d\xc4\x6c\xcd\x7a\x98\x7e"
+                         "\xe2\x2d\x79\x07\x91\x9f\xdf\x2f"
+                         "\x72\xc9\x8f\xcb\x0b\x87\x1b\xb7"
+                         "\x04\x86\xcb\x47\xfa\x5d\x03",
+               .ctext  = "\x0b\x00\xf7\xf2\xc8\x6a\xba\x9a"
+                         "\x0a\x97\x18\x7a\x00\xa0\xdb\xf4"
+                         "\x5e\x8e\x4a\xb7\xe0\x51\xf1\x75"
+                         "\x17\x8b\xb4\xf1\x56\x11\x05\x9f"
+                         "\x2f\x2e\xba\x67\x04\xe1\xb4\xa5"
+                         "\xfc\x7c\x8c\xad\xc6\xb9\xd1\x64"
+                         "\xca\xbd\x5d\xaf\xdb\x65\x48\x4f"
+                         "\x1b\xb3\x94\x5c\x0b\xd0\xee\xcd"
+                         "\xb5\x7f\x43\x8a\xd8\x8b\x66\xde"
+                         "\xd2\x9c\x13\x65\xa4\x47\xa7\x03"
+                         "\xc5\xa1\x46\x8f\x2f\x84\xbc\xef"
+                         "\x48\x9d\x9d\xb5\xbd\x43\xff\xd2"
+                         "\xd2\x7a\x5a\x13\xbf\xb4\xf6\x05"
+                         "\x17\xcd\x01\x12\xf0\x35\x27\x96"
+                         "\xf4\xc1\x65\xf7\x69\xef\x64\x1b"
+                         "\x6e\x4a\xe8\x77\xce\x83\x01\xb7"
+                         "\x60\xe6\x45\x2a\xcd\x41\x4a\xb5"
+                         "\x8e\xcc\x45\x93\xf1\xd6\x64\x5f"
+                         "\x32\x60\xe4\x29\x4a\x82\x6c\x86"
+                         "\x16\xe4\xcc\xdb\x5f\xc8\x11\xa6"
+                         "\xfe\x88\xd6\xc3\xe5\x5c\xbb\x67"
+                         "\xec\xa5\x7b\xf5\xa8\x4f\x77\x25"
+                         "\x5d\x0c\x2a\x99\xf9\xb9\xd1\xae"
+                         "\x3c\x83\x2a\x93\x9b\x66\xec\x68"
+                         "\x2c\x93\x02\x8a\x8a\x1e\x2f\x50"
+                         "\x09\x37\x19\x5c\x2a\x3a\xc2\xcb"
+                         "\xcb\x89\x82\x81\xb7\xbb\xef\x73"
+                         "\x8b\xc9\xae\x42\x96\xef\x70\xc0"
+                         "\x89\xc7\x3e\x6a\x26\xc3\xe4\x39"
+                         "\x53\xa9\xcf\x63\x7d\x05\xf3\xff"
+                         "\x52\x04\xf6\x7f\x23\x96\xe9\xf7"
+                         "\xff\xd6\x50\xa3\x0e\x20\x71",
+               .klen   = 32,
+               .len    = 255,
+       },
+       {
+               .key    = "\x39\x5f\xf4\x9c\x90\x3a\x9a\x25"
+                         "\x15\x11\x79\x39\xed\x26\x5e\xf6"
+                         "\xda\xcf\x33\x4f\x82\x97\xab\x10"
+                         "\xc1\x55\x48\x82\x80\xa8\x02\xb2",
+               .iv     = "\x82\x60\xd9\x06\xeb\x40\x99\x76"
+                         "\x08\xc5\xa4\x83\x45\xb8\x38\x5a",
+               .ptext  = "\xa1\xa8\xac\xac\x08\xaf\x8f\x84"
+                         "\xbf\xcc\x79\x31\x5e\x61\x01\xd1"
+                         "\x4d\x5f\x9b\xcd\x91\x92\x9a\xa1"
+                         "\x99\x0d\x49\xb2\xd7\xfd\x25\x93"
+                         "\x51\x96\xbd\x91\x8b\x08\xf1\xc6"
+                         "\x0d\x17\xf6\xef\xfd\xd2\x78\x16"
+                         "\xc8\x08\x27\x7b\xca\x98\xc6\x12"
+                         "\x86\x11\xdb\xd5\x08\x3d\x5a\x2c"
+                         "\xcf\x15\x0e\x9b\x42\x78\xeb\x1f"
+                         "\x52\xbc\xd7\x5a\x8a\x33\x6c\x14"
+                         "\xfc\x61\xad\x2e\x1e\x03\x66\xea"
+                         "\x79\x0e\x88\x88\xde\x93\xe3\x81"
+                         "\xb5\xc4\x1c\xe6\x9c\x08\x18\x8e"
+                         "\xa0\x87\xda\xe6\xf8\xcb\x30\x44"
+                         "\x2d\x4e\xc0\xa3\x60\xf9\x62\x7b"
+                         "\x4b\xd5\x61\x6d\xe2\x67\x95\x54"
+                         "\x10\xd1\xca\x22\xe8\xb6\xb1\x3a"
+                         "\x2d\xd7\x35\x5b\x22\x88\x55\x67"
+                         "\x3d\x83\x8f\x07\x98\xa8\xf2\xcf"
+                         "\x04\xb7\x9e\x52\xca\xe0\x98\x72"
+                         "\x5c\xc1\x00\xd4\x1f\x2c\x61\xf3"
+                         "\xe8\x40\xaf\x4a\xee\x66\x41\xa0"
+                         "\x02\x77\x29\x30\x65\x59\x4b\x20"
+                         "\x7b\x0d\x80\x97\x27\x7f\xd5\x90"
+                         "\xbb\x9d\x76\x90\xe5\x43\x43\x72"
+                         "\xd0\xd4\x14\x75\x66\xb3\xb6\xaf"
+                         "\x09\xe4\x23\xb0\x62\xad\x17\x28"
+                         "\x39\x26\xab\xf5\xf7\x5c\xb6\x33"
+                         "\xbd\x27\x09\x5b\x29\xe4\x40\x0b"
+                         "\xc1\x26\x32\xdb\x9a\xdf\xf9\x5a"
+                         "\xae\x03\x2c\xa4\x40\x84\x9a\xb7"
+                         "\x4e\x47\xa8\x0f\x23\xc7\xbb\xcf"
+                         "\x2b\xf2\x32\x6c\x35\x6a\x91\xba"
+                         "\x0e\xea\xa2\x8b\x2f\xbd\xb5\xea"
+                         "\x6e\xbc\xb5\x4b\x03\xb3\x86\xe0"
+                         "\x86\xcf\xba\xcb\x38\x2c\x32\xa6"
+                         "\x6d\xe5\x28\xa6\xad\xd2\x7f\x73"
+                         "\x43\x14\xf8\xb1\x99\x12\x2d\x2b"
+                         "\xdf\xcd\xf2\x81\x43\x94\xdf\xb1"
+                         "\x17\xc9\x33\xa6\x3d\xef\x96\xb8"
+                         "\xd6\x0d\x00\xec\x49\x66\x85\x5d"
+                         "\x44\x62\x12\x04\x55\x5c\x48\xd3"
+                         "\xbd\x73\xac\x54\x8f\xbf\x97\x8e"
+                         "\x85\xfd\xc2\xa1\x25\x32\x38\x6a"
+                         "\x1f\xac\x57\x3c\x4f\x56\x73\xf2"
+                         "\x1d\xb6\x48\x68\xc7\x0c\xe7\x60"
+                         "\xd2\x8e\x4d\xfb\xc7\x20\x7b\xb7"
+                         "\x45\x28\x12\xc6\x26\xae\xea\x7c"
+                         "\x5d\xe2\x46\xb5\xae\xe1\xc3\x98"
+                         "\x6f\x72\xd5\xa2\xfd\xed\x40\xfd"
+                         "\xf9\xdf\x61\xec\x45\x2c\x15\xe0"
+                         "\x1e\xbb\xde\x71\x37\x5f\x73\xc2"
+                         "\x11\xcc\x6e\x6d\xe1\xb5\x1b\xd2"
+                         "\x2a\xdd\x19\x8a\xc2\xe1\xa0\xa4"
+                         "\x26\xeb\xb2\x2c\x4f\x77\x52\xf1"
+                         "\x42\x72\x6c\xad\xd7\x78\x5d\x72"
+                         "\xc9\x16\x26\x25\x1b\x4c\xe6\x58"
+                         "\x79\x57\xb5\x06\x15\x4f\xe5\xba"
+                         "\xa2\x7f\x2d\x5b\x87\x8a\x44\x70"
+                         "\xec\xc7\xef\x84\xae\x60\xa2\x61"
+                         "\x86\xe9\x18\xcd\x28\xc4\xa4\xf5"
+                         "\xbc\x84\xb8\x86\xa0\xba\xf1\xf1"
+                         "\x08\x3b\x32\x75\x35\x22\x7a\x65"
+                         "\xca\x48\xe8\xef\x6e\xe2\x8e\x00",
+               .ctext  = "\x2f\xae\xd8\x67\xeb\x15\xde\x75"
+                         "\x53\xa3\x0e\x5a\xcf\x1c\xbe\xea"
+                         "\xde\xf9\xcf\xc2\x9f\xfd\x0f\x44"
+                         "\xc0\xe0\x7a\x76\x1d\xcb\x4a\xf8"
+                         "\x35\xd6\xe3\x95\x98\x6b\x3f\x89"
+                         "\xc4\xe6\xb6\x6f\xe1\x8b\x39\x4b"
+                         "\x1c\x6c\x77\xe4\xe1\x8a\xbc\x61"
+                         "\x00\x6a\xb1\x37\x2f\x45\xe6\x04"
+                         "\x52\x0b\xfc\x1e\x32\xc1\xd8\x9d"
+                         "\xfa\xdd\x67\x5c\xe0\x75\x83\xd0"
+                         "\x21\x9e\x02\xea\xc0\x7f\xc0\x29"
+                         "\xb3\x6c\xa5\x97\xb3\x29\x82\x1a"
+                         "\x94\xa5\xb4\xb6\x49\xe5\xa5\xad"
+                         "\x95\x40\x52\x7c\x84\x88\xa4\xa8"
+                         "\x26\xe4\xd9\x5d\x41\xf2\x93\x7b"
+                         "\xa4\x48\x1b\x66\x91\xb9\x7c\xc2"
+                         "\x99\x29\xdf\xd8\x30\xac\xd4\x47"
+                         "\x42\xa0\x14\x87\x67\xb8\xfd\x0b"
+                         "\x1e\xcb\x5e\x5c\x9a\xc2\x04\x8b"
+                         "\x17\x29\x9d\x99\x7f\x86\x4c\xe2"
+                         "\x5c\x96\xa6\x0f\xb6\x47\x33\x5c"
+                         "\xe4\x50\x49\xd5\x4f\x92\x0b\x9a"
+                         "\xbc\x52\x4c\x41\xf5\xc9\x3e\x76"
+                         "\x55\x55\xd4\xdc\x71\x14\x23\xfc"
+                         "\x5f\xd5\x08\xde\xa0\xf7\x28\xc0"
+                         "\xe1\x61\xac\x64\x66\xf6\xd1\x31"
+                         "\xe4\xa4\xa9\xed\xbc\xad\x4f\x3b"
+                         "\x59\xb9\x48\x1b\xe7\xb1\x6f\xc6"
+                         "\xba\x40\x1c\x0b\xe7\x2f\x31\x65"
+                         "\x85\xf5\xe9\x14\x0a\x31\xf5\xf3"
+                         "\xc0\x1c\x20\x35\x73\x38\x0f\x8e"
+                         "\x39\xf0\x68\xae\x08\x9c\x87\x4b"
+                         "\x42\xfc\x22\x17\xee\x96\x51\x2a"
+                         "\xd8\x57\x5a\x35\xea\x72\x74\xfc"
+                         "\xb3\x0e\x69\x9a\xe1\x4f\x24\x90"
+                         "\xc5\x4b\xe5\xd7\xe3\x82\x2f\xc5"
+                         "\x62\x46\x3e\xab\x72\x4e\xe0\xf3"
+                         "\x90\x09\x4c\xb2\xe1\xe8\xa0\xf5"
+                         "\x46\x40\x2b\x47\x85\x3c\x21\x90"
+                         "\x3d\xad\x25\x5a\x36\xdf\xe5\xbc"
+                         "\x7e\x80\x4d\x53\x77\xf1\x79\xa6"
+                         "\xec\x22\x80\x88\x68\xd6\x2d\x8b"
+                         "\x3e\xf7\x52\xc7\x2a\x20\x42\x5c"
+                         "\xed\x99\x4f\x32\x80\x00\x7e\x73"
+                         "\xd7\x6d\x7f\x7d\x42\x54\x4a\xfe"
+                         "\xff\x6f\x61\xca\x2a\xbb\x4f\xeb"
+                         "\x4f\xe4\x4e\xaf\x2c\x4f\x82\xcd"
+                         "\xa1\xa7\x11\xb3\x34\x33\xcf\x32"
+                         "\x63\x0e\x24\x3a\x35\xbe\x06\xd5"
+                         "\x17\xcb\x02\x30\x33\x6e\x8c\x49"
+                         "\x40\x6e\x34\x8c\x07\xd4\x3e\xe6"
+                         "\xaf\x78\x6d\x8c\x10\x5f\x21\x58"
+                         "\x49\x26\xc5\xaf\x0d\x7d\xd4\xaf"
+                         "\xcd\x5b\xa1\xe3\xf6\x39\x1c\x9b"
+                         "\x8e\x00\xa1\xa7\x9e\x17\x4a\xc0"
+                         "\x54\x56\x9e\xcf\xcf\x88\x79\x8d"
+                         "\x50\xf7\x56\x8e\x0a\x73\x46\x6b"
+                         "\xc3\xb9\x9b\x6c\x7d\xc4\xc8\xb6"
+                         "\x03\x5f\x30\x62\x7d\xe6\xdb\x15"
+                         "\xe1\x39\x02\x8c\xff\xda\xc8\x43"
+                         "\xf2\xa9\xbf\x00\xe7\x3a\x61\x89"
+                         "\xdf\xb0\xca\x7d\x8c\x8a\x6a\x9f"
+                         "\x18\x89\x3d\x39\xac\x36\x6f\x05"
+                         "\x1f\xb5\xda\x00\xea\xe1\x51\x21",
+               .klen   = 32,
+               .len    = 512,
+       },
 
-static const struct hash_testvec blakes2s_160_tv_template[] = {{
-       .plaintext = blake2_ordered_sequence,
-       .psize = 7,
-       .digest = (u8[]){ 0xb4, 0xf2, 0x03, 0x49, 0x37, 0xed, 0xb1, 0x3e,
-                         0x5b, 0x2a, 0xca, 0x64, 0x82, 0x74, 0xf6, 0x62,
-                         0xe3, 0xf2, 0x84, 0xff, },
-}, {
-       .plaintext = blake2_ordered_sequence,
-       .psize = 256,
-       .digest = (u8[]){ 0xaa, 0x56, 0x9b, 0xdc, 0x98, 0x17, 0x75, 0xf2,
-                         0xb3, 0x68, 0x83, 0xb7, 0x9b, 0x8d, 0x48, 0xb1,
-                         0x9b, 0x2d, 0x35, 0x05, },
-}, {
-       .ksize = 1,
-       .key = "B",
-       .digest = (u8[]){ 0x50, 0x16, 0xe7, 0x0c, 0x01, 0xd0, 0xd3, 0xc3,
-                         0xf4, 0x3e, 0xb1, 0x6e, 0x97, 0xa9, 0x4e, 0xd1,
-                         0x79, 0x65, 0x32, 0x93, },
-}, {
-       .ksize = 32,
-       .key = blake2_ordered_sequence,
-       .plaintext = blake2_ordered_sequence,
-       .psize = 1,
-       .digest = (u8[]){ 0x1c, 0x2b, 0xcd, 0x9a, 0x68, 0xca, 0x8c, 0x71,
-                         0x90, 0x29, 0x6c, 0x54, 0xfa, 0x56, 0x4a, 0xef,
-                         0xa2, 0x3a, 0x56, 0x9c, },
-}, {
-       .ksize = 16,
-       .key = blake2_ordered_sequence,
-       .plaintext = blake2_ordered_sequence,
-       .psize = 15,
-       .digest = (u8[]){ 0x36, 0xc3, 0x5f, 0x9a, 0xdc, 0x7e, 0xbf, 0x19,
-                         0x68, 0xaa, 0xca, 0xd8, 0x81, 0xbf, 0x09, 0x34,
-                         0x83, 0x39, 0x0f, 0x30, },
-}, {
-       .ksize = 1,
-       .key = "B",
-       .plaintext = blake2_ordered_sequence,
-       .psize = 64,
-       .digest = (u8[]){ 0x86, 0x80, 0x78, 0xa4, 0x14, 0xec, 0x03, 0xe5,
-                         0xb6, 0x9a, 0x52, 0x0e, 0x42, 0xee, 0x39, 0x9d,
-                         0xac, 0xa6, 0x81, 0x63, },
-}, {
-       .ksize = 32,
-       .key = blake2_ordered_sequence,
-       .plaintext = blake2_ordered_sequence,
-       .psize = 247,
-       .digest = (u8[]){ 0x2d, 0xd8, 0xd2, 0x53, 0x66, 0xfa, 0xa9, 0x01,
-                         0x1c, 0x9c, 0xaf, 0xa3, 0xe2, 0x9d, 0x9b, 0x10,
-                         0x0a, 0xf6, 0x73, 0xe8, },
-}};
+};
 
-static const struct hash_testvec blakes2s_224_tv_template[] = {{
-       .plaintext = blake2_ordered_sequence,
-       .psize = 1,
-       .digest = (u8[]){ 0x61, 0xb9, 0x4e, 0xc9, 0x46, 0x22, 0xa3, 0x91,
-                         0xd2, 0xae, 0x42, 0xe6, 0x45, 0x6c, 0x90, 0x12,
-                         0xd5, 0x80, 0x07, 0x97, 0xb8, 0x86, 0x5a, 0xfc,
-                         0x48, 0x21, 0x97, 0xbb, },
-}, {
-       .plaintext = blake2_ordered_sequence,
-       .psize = 247,
-       .digest = (u8[]){ 0x9e, 0xda, 0xc7, 0x20, 0x2c, 0xd8, 0x48, 0x2e,
-                         0x31, 0x94, 0xab, 0x46, 0x6d, 0x94, 0xd8, 0xb4,
-                         0x69, 0xcd, 0xae, 0x19, 0x6d, 0x9e, 0x41, 0xcc,
-                         0x2b, 0xa4, 0xd5, 0xf6, },
-}, {
-       .ksize = 16,
-       .key = blake2_ordered_sequence,
-       .digest = (u8[]){ 0x32, 0xc0, 0xac, 0xf4, 0x3b, 0xd3, 0x07, 0x9f,
-                         0xbe, 0xfb, 0xfa, 0x4d, 0x6b, 0x4e, 0x56, 0xb3,
-                         0xaa, 0xd3, 0x27, 0xf6, 0x14, 0xbf, 0xb9, 0x32,
-                         0xa7, 0x19, 0xfc, 0xb8, },
-}, {
-       .ksize = 1,
-       .key = "B",
-       .plaintext = blake2_ordered_sequence,
-       .psize = 7,
-       .digest = (u8[]){ 0x73, 0xad, 0x5e, 0x6d, 0xb9, 0x02, 0x8e, 0x76,
-                         0xf2, 0x66, 0x42, 0x4b, 0x4c, 0xfa, 0x1f, 0xe6,
-                         0x2e, 0x56, 0x40, 0xe5, 0xa2, 0xb0, 0x3c, 0xe8,
-                         0x7b, 0x45, 0xfe, 0x05, },
-}, {
-       .ksize = 32,
-       .key = blake2_ordered_sequence,
-       .plaintext = blake2_ordered_sequence,
-       .psize = 15,
-       .digest = (u8[]){ 0x16, 0x60, 0xfb, 0x92, 0x54, 0xb3, 0x6e, 0x36,
-                         0x81, 0xf4, 0x16, 0x41, 0xc3, 0x3d, 0xd3, 0x43,
-                         0x84, 0xed, 0x10, 0x6f, 0x65, 0x80, 0x7a, 0x3e,
-                         0x25, 0xab, 0xc5, 0x02, },
-}, {
-       .ksize = 16,
-       .key = blake2_ordered_sequence,
-       .plaintext = blake2_ordered_sequence,
-       .psize = 64,
-       .digest = (u8[]){ 0xca, 0xaa, 0x39, 0x67, 0x9c, 0xf7, 0x6b, 0xc7,
-                         0xb6, 0x82, 0xca, 0x0e, 0x65, 0x36, 0x5b, 0x7c,
-                         0x24, 0x00, 0xfa, 0x5f, 0xda, 0x06, 0x91, 0x93,
-                         0x6a, 0x31, 0x83, 0xb5, },
-}, {
-       .ksize = 1,
-       .key = "B",
-       .plaintext = blake2_ordered_sequence,
-       .psize = 256,
-       .digest = (u8[]){ 0x90, 0x02, 0x26, 0xb5, 0x06, 0x9c, 0x36, 0x86,
-                         0x94, 0x91, 0x90, 0x1e, 0x7d, 0x2a, 0x71, 0xb2,
-                         0x48, 0xb5, 0xe8, 0x16, 0xfd, 0x64, 0x33, 0x45,
-                         0xb3, 0xd7, 0xec, 0xcc, },
-}};
+/*
+ * Test vectors generated using https://github.com/google/hctr2
+ *
+ * To ensure compatibility with RFC 8452, some tests were sourced from
+ * https://datatracker.ietf.org/doc/html/rfc8452
+ */
+static const struct hash_testvec polyval_tv_template[] = {
+       { // From RFC 8452
+               .key    = "\x31\x07\x28\xd9\x91\x1f\x1f\x38"
+                         "\x37\xb2\x43\x16\xc3\xfa\xb9\xa0",
+               .plaintext      = "\x65\x78\x61\x6d\x70\x6c\x65\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x48\x65\x6c\x6c\x6f\x20\x77\x6f"
+                         "\x72\x6c\x64\x00\x00\x00\x00\x00"
+                         "\x38\x00\x00\x00\x00\x00\x00\x00"
+                         "\x58\x00\x00\x00\x00\x00\x00\x00",
+               .digest = "\xad\x7f\xcf\x0b\x51\x69\x85\x16"
+                         "\x62\x67\x2f\x3c\x5f\x95\x13\x8f",
+               .psize  = 48,
+               .ksize  = 16,
+       },
+       { // From RFC 8452
+               .key    = "\xd9\xb3\x60\x27\x96\x94\x94\x1a"
+                         "\xc5\xdb\xc6\x98\x7a\xda\x73\x77",
+               .plaintext      = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .digest = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .psize  = 16,
+               .ksize  = 16,
+       },
+       { // From RFC 8452
+               .key    = "\xd9\xb3\x60\x27\x96\x94\x94\x1a"
+                         "\xc5\xdb\xc6\x98\x7a\xda\x73\x77",
+               .plaintext      = "\x01\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x40\x00\x00\x00\x00\x00\x00\x00",
+               .digest = "\xeb\x93\xb7\x74\x09\x62\xc5\xe4"
+                         "\x9d\x2a\x90\xa7\xdc\x5c\xec\x74",
+               .psize  = 32,
+               .ksize  = 16,
+       },
+       { // From RFC 8452
+               .key    = "\xd9\xb3\x60\x27\x96\x94\x94\x1a"
+                         "\xc5\xdb\xc6\x98\x7a\xda\x73\x77",
+               .plaintext      = "\x01\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x02\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x03\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x80\x01\x00\x00\x00\x00\x00\x00",
+               .digest = "\x81\x38\x87\x46\xbc\x22\xd2\x6b"
+                         "\x2a\xbc\x3d\xcb\x15\x75\x42\x22",
+               .psize  = 64,
+               .ksize  = 16,
+       },
+       { // From RFC 8452
+               .key    = "\xd9\xb3\x60\x27\x96\x94\x94\x1a"
+                         "\xc5\xdb\xc6\x98\x7a\xda\x73\x77",
+               .plaintext      = "\x01\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x02\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x03\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x04\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x02\x00\x00\x00\x00\x00\x00",
+               .digest = "\x1e\x39\xb6\xd3\x34\x4d\x34\x8f"
+                         "\x60\x44\xf8\x99\x35\xd1\xcf\x78",
+               .psize  = 80,
+               .ksize  = 16,
+       },
+       { // From RFC 8452
+               .key    = "\xd9\xb3\x60\x27\x96\x94\x94\x1a"
+                         "\xc5\xdb\xc6\x98\x7a\xda\x73\x77",
+               .plaintext      = "\x01\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x02\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x03\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x04\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x05\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x08\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x02\x00\x00\x00\x00\x00\x00",
+               .digest = "\xff\xcd\x05\xd5\x77\x0f\x34\xad"
+                         "\x92\x67\xf0\xa5\x99\x94\xb1\x5a",
+               .psize  = 96,
+               .ksize  = 16,
+       },
+       { // Random ( 1)
+               .key    = "\x90\xcc\xac\xee\xba\xd7\xd4\x68"
+                         "\x98\xa6\x79\x70\xdf\x66\x15\x6c",
+               .plaintext      = "",
+               .digest = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .psize  = 0,
+               .ksize  = 16,
+       },
+       { // Random ( 1)
+               .key    = "\xc1\x45\x71\xf0\x30\x07\x94\xe7"
+                         "\x3a\xdd\xe4\xc6\x19\x2d\x02\xa2",
+               .plaintext      = "\xc1\x5d\x47\xc7\x4c\x7c\x5e\x07"
+                         "\x85\x14\x8f\x79\xcc\x73\x83\xf7"
+                         "\x35\xb8\xcb\x73\x61\xf0\x53\x31"
+                         "\xbf\x84\xde\xb6\xde\xaf\xb0\xb8"
+                         "\xb7\xd9\x11\x91\x89\xfd\x1e\x4c"
+                         "\x84\x4a\x1f\x2a\x87\xa4\xaf\x62"
+                         "\x8d\x7d\x58\xf6\x43\x35\xfc\x53"
+                         "\x8f\x1a\xf6\x12\xe1\x13\x3f\x66"
+                         "\x91\x4b\x13\xd6\x45\xfb\xb0\x7a"
+                         "\xe0\x8b\x8e\x99\xf7\x86\x46\x37"
+                         "\xd1\x22\x9e\x52\xf3\x3f\xd9\x75"
+                         "\x2c\x2c\xc6\xbb\x0e\x08\x14\x29"
+                         "\xe8\x50\x2f\xd8\xbe\xf4\xe9\x69"
+                         "\x4a\xee\xf7\xae\x15\x65\x35\x1e",
+               .digest = "\x00\x4f\x5d\xe9\x3b\xc0\xd6\x50"
+                         "\x3e\x38\x73\x86\xc6\xda\xca\x7f",
+               .psize  = 112,
+               .ksize  = 16,
+       },
+       { // Random ( 1)
+               .key    = "\x37\xbe\x68\x16\x50\xb9\x4e\xb0"
+                         "\x47\xde\xe2\xbd\xde\xe4\x48\x09",
+               .plaintext      = "\x87\xfc\x68\x9f\xff\xf2\x4a\x1e"
+                         "\x82\x3b\x73\x8f\xc1\xb2\x1b\x7a"
+                         "\x6c\x4f\x81\xbc\x88\x9b\x6c\xa3"
+                         "\x9c\xc2\xa5\xbc\x14\x70\x4c\x9b"
+                         "\x0c\x9f\x59\x92\x16\x4b\x91\x3d"
+                         "\x18\x55\x22\x68\x12\x8c\x63\xb2"
+                         "\x51\xcb\x85\x4b\xd2\xae\x0b\x1c"
+                         "\x5d\x28\x9d\x1d\xb1\xc8\xf0\x77"
+                         "\xe9\xb5\x07\x4e\x06\xc8\xee\xf8"
+                         "\x1b\xed\x72\x2a\x55\x7d\x16\xc9"
+                         "\xf2\x54\xe7\xe9\xe0\x44\x5b\x33"
+                         "\xb1\x49\xee\xff\x43\xfb\x82\xcd"
+                         "\x4a\x70\x78\x81\xa4\x34\x36\xe8"
+                         "\x4c\x28\x54\xa6\x6c\xc3\x6b\x78"
+                         "\xe7\xc0\x5d\xc6\x5d\x81\xab\x70"
+                         "\x08\x86\xa1\xfd\xf4\x77\x55\xfd"
+                         "\xa3\xe9\xe2\x1b\xdf\x99\xb7\x80"
+                         "\xf9\x0a\x4f\x72\x4a\xd3\xaf\xbb"
+                         "\xb3\x3b\xeb\x08\x58\x0f\x79\xce"
+                         "\xa5\x99\x05\x12\x34\xd4\xf4\x86"
+                         "\x37\x23\x1d\xc8\x49\xc0\x92\xae"
+                         "\xa6\xac\x9b\x31\x55\xed\x15\xc6"
+                         "\x05\x17\x37\x8d\x90\x42\xe4\x87"
+                         "\x89\x62\x88\x69\x1c\x6a\xfd\xe3"
+                         "\x00\x2b\x47\x1a\x73\xc1\x51\xc2"
+                         "\xc0\x62\x74\x6a\x9e\xb2\xe5\x21"
+                         "\xbe\x90\xb5\xb0\x50\xca\x88\x68"
+                         "\xe1\x9d\x7a\xdf\x6c\xb7\xb9\x98"
+                         "\xee\x28\x62\x61\x8b\xd1\x47\xf9"
+                         "\x04\x7a\x0b\x5d\xcd\x2b\x65\xf5"
+                         "\x12\xa3\xfe\x1a\xaa\x2c\x78\x42"
+                         "\xb8\xbe\x7d\x74\xeb\x59\xba\xba",
+               .digest = "\xae\x11\xd4\x60\x2a\x5f\x9e\x42"
+                         "\x89\x04\xc2\x34\x8d\x55\x94\x0a",
+               .psize  = 256,
+               .ksize  = 16,
+       },
 
-static const struct hash_testvec blakes2s_256_tv_template[] = {{
-       .plaintext = blake2_ordered_sequence,
-       .psize = 15,
-       .digest = (u8[]){ 0xd9, 0x7c, 0x82, 0x8d, 0x81, 0x82, 0xa7, 0x21,
-                         0x80, 0xa0, 0x6a, 0x78, 0x26, 0x83, 0x30, 0x67,
-                         0x3f, 0x7c, 0x4e, 0x06, 0x35, 0x94, 0x7c, 0x04,
-                         0xc0, 0x23, 0x23, 0xfd, 0x45, 0xc0, 0xa5, 0x2d, },
-}, {
-       .ksize = 32,
-       .key = blake2_ordered_sequence,
-       .digest = (u8[]){ 0x48, 0xa8, 0x99, 0x7d, 0xa4, 0x07, 0x87, 0x6b,
-                         0x3d, 0x79, 0xc0, 0xd9, 0x23, 0x25, 0xad, 0x3b,
-                         0x89, 0xcb, 0xb7, 0x54, 0xd8, 0x6a, 0xb7, 0x1a,
-                         0xee, 0x04, 0x7a, 0xd3, 0x45, 0xfd, 0x2c, 0x49, },
-}, {
-       .ksize = 1,
-       .key = "B",
-       .plaintext = blake2_ordered_sequence,
-       .psize = 1,
-       .digest = (u8[]){ 0x22, 0x27, 0xae, 0xaa, 0x6e, 0x81, 0x56, 0x03,
-                         0xa7, 0xe3, 0xa1, 0x18, 0xa5, 0x9a, 0x2c, 0x18,
-                         0xf4, 0x63, 0xbc, 0x16, 0x70, 0xf1, 0xe7, 0x4b,
-                         0x00, 0x6d, 0x66, 0x16, 0xae, 0x9e, 0x74, 0x4e, },
-}, {
-       .ksize = 16,
-       .key = blake2_ordered_sequence,
-       .plaintext = blake2_ordered_sequence,
-       .psize = 7,
-       .digest = (u8[]){ 0x58, 0x5d, 0xa8, 0x60, 0x1c, 0xa4, 0xd8, 0x03,
-                         0x86, 0x86, 0x84, 0x64, 0xd7, 0xa0, 0x8e, 0x15,
-                         0x2f, 0x05, 0xa2, 0x1b, 0xbc, 0xef, 0x7a, 0x34,
-                         0xb3, 0xc5, 0xbc, 0x4b, 0xf0, 0x32, 0xeb, 0x12, },
-}, {
-       .ksize = 32,
-       .key = blake2_ordered_sequence,
-       .plaintext = blake2_ordered_sequence,
-       .psize = 64,
-       .digest = (u8[]){ 0x89, 0x75, 0xb0, 0x57, 0x7f, 0xd3, 0x55, 0x66,
-                         0xd7, 0x50, 0xb3, 0x62, 0xb0, 0x89, 0x7a, 0x26,
-                         0xc3, 0x99, 0x13, 0x6d, 0xf0, 0x7b, 0xab, 0xab,
-                         0xbd, 0xe6, 0x20, 0x3f, 0xf2, 0x95, 0x4e, 0xd4, },
-}, {
-       .ksize = 1,
-       .key = "B",
-       .plaintext = blake2_ordered_sequence,
-       .psize = 247,
-       .digest = (u8[]){ 0x2e, 0x74, 0x1c, 0x1d, 0x03, 0xf4, 0x9d, 0x84,
-                         0x6f, 0xfc, 0x86, 0x32, 0x92, 0x49, 0x7e, 0x66,
-                         0xd7, 0xc3, 0x10, 0x88, 0xfe, 0x28, 0xb3, 0xe0,
-                         0xbf, 0x50, 0x75, 0xad, 0x8e, 0xa4, 0xe6, 0xb2, },
-}, {
-       .ksize = 16,
-       .key = blake2_ordered_sequence,
-       .plaintext = blake2_ordered_sequence,
-       .psize = 256,
-       .digest = (u8[]){ 0xb9, 0xd2, 0x81, 0x0e, 0x3a, 0xb1, 0x62, 0x9b,
-                         0xad, 0x44, 0x05, 0xf4, 0x92, 0x2e, 0x99, 0xc1,
-                         0x4a, 0x47, 0xbb, 0x5b, 0x6f, 0xb2, 0x96, 0xed,
-                         0xd5, 0x06, 0xb5, 0x3a, 0x7c, 0x7a, 0x65, 0x1d, },
-}};
+};
+
+/*
+ * Test vectors generated using https://github.com/google/hctr2
+ */
+static const struct cipher_testvec aes_hctr2_tv_template[] = {
+       {
+               .key    = "\xe1\x15\x66\x3c\x8d\xc6\x3a\xff"
+                         "\xef\x41\xd7\x47\xa2\xcc\x8a\xba",
+               .iv     = "\xc3\xbe\x2a\xcb\xb5\x39\x86\xf1"
+                         "\x91\xad\x6c\xf4\xde\x74\x45\x63"
+                         "\x5c\x7a\xd5\xcc\x8b\x76\xef\x0e"
+                         "\xcf\x2c\x60\x69\x37\xfd\x07\x96",
+               .ptext  = "\x65\x75\xae\xd3\xe2\xbc\x43\x5c"
+                         "\xb3\x1a\xd8\x05\xc3\xd0\x56\x29",
+               .ctext  = "\x11\x91\xea\x74\x58\xcc\xd5\xa2"
+                         "\xd0\x55\x9e\x3d\xfe\x7f\xc8\xfe",
+               .klen   = 16,
+               .len    = 16,
+       },
+       {
+               .key    = "\xe7\xd1\x77\x48\x76\x0b\xcd\x34"
+                         "\x2a\x2d\xe7\x74\xca\x11\x9c\xae",
+               .iv     = "\x71\x1c\x49\x62\xd9\x5b\x50\x5e"
+                         "\x68\x87\xbc\xf6\x89\xff\xed\x30"
+                         "\xe4\xe5\xbd\xb6\x10\x4f\x9f\x66"
+                         "\x28\x06\x5a\xf4\x27\x35\xcd\xe5",
+               .ptext  = "\x87\x03\x8f\x06\xa8\x61\x54\xda"
+                         "\x01\x45\xd4\x01\xef\x4a\x22\xcf"
+                         "\x78\x15\x9f\xbd\x64\xbd\x2c\xb9"
+                         "\x40\x1d\x72\xae\x53\x63\xa5",
+               .ctext  = "\x4e\xa1\x05\x27\xb8\x45\xe4\xa1"
+                         "\xbb\x30\xb4\xa6\x12\x74\x63\xd6"
+                         "\x17\xc9\xcc\x2f\x18\x64\xe0\x06"
+                         "\x0a\xa0\xff\x72\x10\x7b\x22",
+               .klen   = 16,
+               .len    = 31,
+       },
+       {
+               .key    = "\x59\x65\x3b\x1d\x43\x5e\xc0\xae"
+                         "\xb8\x9d\x9b\xdd\x22\x03\xbf\xca",
+               .iv     = "\xec\x95\xfa\x5a\xcf\x5e\xd2\x93"
+                         "\xa3\xb5\xe5\xbe\xf3\x01\x7b\x01"
+                         "\xd1\xca\x6c\x06\x82\xf0\xbd\x67"
+                         "\xd9\x6c\xa4\xdc\xb4\x38\x0f\x74",
+               .ptext  = "\x45\xdf\x75\x87\xbc\x72\xce\x55"
+                         "\xc9\xfa\xcb\xfc\x9f\x40\x82\x2b"
+                         "\xc6\x4f\x4f\x5b\x8b\x3b\x6d\x67"
+                         "\xa6\x93\x62\x89\x8c\x19\xf4\xe3"
+                         "\x08\x92\x9c\xc9\x47\x2c\x6e\xd0"
+                         "\xa3\x02\x2b\xdb\x2c\xf2\x8d\x46"
+                         "\xcd\xb0\x9d\x26\x63\x4c\x40\x6b"
+                         "\x79\x43\xe5\xce\x42\xa8\xec\x3b"
+                         "\x5b\xd0\xea\xa4\xe6\xdb\x66\x55"
+                         "\x7a\x76\xec\xab\x7d\x2a\x2b\xbd"
+                         "\xa9\xab\x22\x64\x1a\xa1\xae\x84"
+                         "\x86\x79\x67\xe9\xb2\x50\xbe\x12"
+                         "\x2f\xb2\x14\xf0\xdb\x71\xd8\xa7"
+                         "\x41\x8a\x88\xa0\x6a\x6e\x9d\x2a"
+                         "\xfa\x11\x37\x40\x32\x09\x4c\x47"
+                         "\x41\x07\x31\x85\x3d\xa8\xf7\x64",
+               .ctext  = "\x2d\x4b\x9f\x93\xca\x5a\x48\x26"
+                         "\x01\xcc\x54\xe4\x31\x50\x12\xf0"
+                         "\x49\xff\x59\x42\x68\xbd\x87\x8f"
+                         "\x9e\x62\x96\xcd\xb9\x24\x57\xa4"
+                         "\x0b\x7b\xf5\x2e\x0e\xa8\x65\x07"
+                         "\xab\x05\xd5\xca\xe7\x9c\x6c\x34"
+                         "\x5d\x42\x34\xa4\x62\xe9\x75\x48"
+                         "\x3d\x9e\x8f\xfa\x42\xe9\x75\x08"
+                         "\x4e\x54\x91\x2b\xbd\x11\x0f\x8e"
+                         "\xf0\x82\xf5\x24\xf1\xc4\xfc\xae"
+                         "\x42\x54\x7f\xce\x15\xa8\xb2\x33"
+                         "\xc0\x86\xb6\x2b\xe8\x44\xce\x1f"
+                         "\x68\x57\x66\x94\x6e\xad\xeb\xf3"
+                         "\x30\xf8\x11\xbd\x60\x00\xc6\xd5"
+                         "\x4c\x81\xf1\x20\x2b\x4a\x5b\x99"
+                         "\x79\x3b\xc9\x5c\x74\x23\xe6\x5d",
+               .klen   = 16,
+               .len    = 128,
+       },
+       {
+               .key    = "\x3e\x08\x5d\x64\x6c\x98\xec\xec"
+                         "\x70\x0e\x0d\xa1\x41\x20\x99\x82",
+               .iv     = "\x11\xb7\x77\x91\x0d\x99\xd9\x8d"
+                         "\x35\x3a\xf7\x14\x6b\x09\x37\xe5"
+                         "\xad\x51\xf6\xc3\x96\x4b\x64\x56"
+                         "\xa8\xbd\x81\xcc\xbe\x94\xaf\xe4",
+               .ptext  = "\xff\x8d\xb9\xc0\xe3\x69\xb3\xb2"
+                         "\x8b\x11\x26\xb3\x11\xec\xfb\xb9"
+                         "\x9c\xc1\x71\xd6\xe3\x26\x0e\xe0"
+                         "\x68\x40\x60\xb9\x3a\x63\x56\x8a"
+                         "\x9e\xc1\xf0\x10\xb1\x64\x32\x70"
+                         "\xf8\xcd\xc6\xc4\x49\x4c\xe1\xce"
+                         "\xf3\xe1\x03\xf8\x35\xae\xe0\x5e"
+                         "\xef\x5f\xbc\x41\x75\x26\x13\xcc"
+                         "\x37\x85\xdf\xc0\x5d\xa6\x47\x98"
+                         "\xf1\x97\x52\x58\x04\xe6\xb5\x01"
+                         "\xc0\xb8\x17\x6d\x74\xbd\x9a\xdf"
+                         "\xa4\x37\x94\x86\xb0\x13\x83\x28"
+                         "\xc9\xa2\x07\x3f\xb5\xb2\x72\x40"
+                         "\x0e\x60\xdf\x57\x07\xb7\x2c\x66"
+                         "\x10\x3f\x8d\xdd\x30\x0a\x47\xd5"
+                         "\xe8\x9d\xfb\xa1\xaf\x53\xd7\x05"
+                         "\xc7\xd2\xba\xe7\x2c\xa0\xbf\xb8"
+                         "\xd1\x93\xe7\x41\x82\xa3\x41\x3a"
+                         "\xaf\x12\xd6\xf8\x34\xda\x92\x46"
+                         "\xad\xa2\x2f\xf6\x7e\x46\x96\xd8"
+                         "\x03\xf3\x49\x64\xde\xd8\x06\x8b"
+                         "\xa0\xbc\x63\x35\x38\xb6\x6b\xda"
+                         "\x5b\x50\x3f\x13\xa5\x84\x1b\x1b"
+                         "\x66\x89\x95\xb7\xc2\x16\x3c\xe9"
+                         "\x24\xb0\x8c\x6f\x49\xef\xf7\x28"
+                         "\x6a\x24\xfd\xbe\x25\xe2\xb4\x90"
+                         "\x77\x44\x08\xb8\xda\xd2\xde\x2c"
+                         "\xa0\x57\x45\x57\x29\x47\x6b\x89"
+                         "\x4a\xf6\xa7\x2a\xc3\x9e\x7b\xc8"
+                         "\xfd\x9f\x89\xab\xee\x6d\xa3\xb4"
+                         "\x23\x90\x7a\xe9\x89\xa0\xc7\xb3"
+                         "\x17\x41\x87\x91\xfc\x97\x42",
+               .ctext  = "\xfc\x9b\x96\x66\xc4\x82\x2a\x4a"
+                         "\xb1\x24\xba\xc7\x78\x5f\x79\xc1"
+                         "\x57\x2e\x47\x29\x4d\x7b\xd2\x9a"
+                         "\xbd\xc6\xc1\x26\x7b\x8e\x3f\x5d"
+                         "\xd4\xb4\x9f\x6a\x02\x24\x4a\xad"
+                         "\x0c\x00\x1b\xdf\x92\xc5\x8a\xe1"
+                         "\x77\x79\xcc\xd5\x20\xbf\x83\xf4"
+                         "\x4b\xad\x11\xbf\xdb\x47\x65\x70"
+                         "\x43\xf3\x65\xdf\xb7\xdc\xb2\xb9"
+                         "\xaa\x3f\xb3\xdf\x79\x69\x0d\xa0"
+                         "\x86\x1c\xba\x48\x0b\x01\xc1\x88"
+                         "\xdf\x03\xb1\x06\x3c\x1d\x56\xa1"
+                         "\x8e\x98\xc1\xa6\x95\xa2\x5b\x72"
+                         "\x76\x59\xd2\x26\x25\xcd\xef\x7c"
+                         "\xc9\x60\xea\x43\xd1\x12\x8a\x8a"
+                         "\x63\x12\x78\xcb\x2f\x88\x1e\x88"
+                         "\x78\x59\xde\xba\x4d\x2c\x78\x61"
+                         "\x75\x37\x54\xfd\x80\xc7\x5e\x98"
+                         "\xcf\x14\x62\x8e\xfb\x72\xee\x4d"
+                         "\x9f\xaf\x8b\x09\xe5\x21\x0a\x91"
+                         "\x8f\x88\x87\xd5\xb1\x84\xab\x18"
+                         "\x08\x57\xed\x72\x35\xa6\x0e\xc6"
+                         "\xff\xcb\xfe\x2c\x48\x39\x14\x44"
+                         "\xba\x59\x32\x3a\x2d\xc4\x5f\xcb"
+                         "\xbe\x68\x8e\x7b\xee\x21\xa4\x32"
+                         "\x11\xa0\x99\xfd\x90\xde\x59\x43"
+                         "\xeb\xed\xd5\x87\x68\x46\xc6\xde"
+                         "\x0b\x07\x17\x59\x6a\xab\xca\x15"
+                         "\x65\x02\x01\xb6\x71\x8c\x3b\xaa"
+                         "\x18\x3b\x30\xae\x38\x5b\x2c\x74"
+                         "\xd4\xee\x4a\xfc\xf7\x1b\x09\xd4"
+                         "\xda\x8b\x1d\x5d\x6f\x21\x6c",
+               .klen   = 16,
+               .len    = 255,
+       },
+       {
+               .key    = "\x24\xf6\xe1\x62\xe5\xaf\x99\xda"
+                         "\x84\xec\x41\xb0\xa3\x0b\xd5\xa8"
+                         "\xa0\x3e\x7b\xa6\xdd\x6c\x8f\xa8",
+               .iv     = "\x7f\x80\x24\x62\x32\xdd\xab\x66"
+                         "\xf2\x87\x29\x24\xec\xd2\x4b\x9f"
+                         "\x0c\x33\x52\xd9\xe0\xcc\x6e\xe4"
+                         "\x90\x85\x43\x97\xc4\x62\x14\x33",
+               .ptext  = "\xef\x58\xe7\x7f\xa9\xd9\xb8\xd7"
+                         "\xa2\x91\x97\x07\x27\x9e\xba\xe8"
+                         "\xaa",
+               .ctext  = "\xd7\xc3\x81\x91\xf2\x40\x17\x73"
+                         "\x3e\x3b\x1c\x2a\x8e\x11\x9c\x17"
+                         "\xf1",
+               .klen   = 24,
+               .len    = 17,
+       },
+       {
+               .key    = "\xbf\xaf\xd7\x67\x8c\x47\xcf\x21"
+                         "\x8a\xa5\xdd\x32\x25\x47\xbe\x4f"
+                         "\xf1\x3a\x0b\xa6\xaa\x2d\xcf\x09",
+               .iv     = "\xd9\xe8\xf0\x92\x4e\xfc\x1d\xf2"
+                         "\x81\x37\x7c\x8f\xf1\x59\x09\x20"
+                         "\xf4\x46\x51\x86\x4f\x54\x8b\x32"
+                         "\x58\xd1\x99\x8b\x8c\x03\xeb\x5d",
+               .ptext  = "\xcd\x64\x90\xf9\x7c\xe5\x0e\x5a"
+                         "\x75\xe7\x8e\x39\x86\xec\x20\x43"
+                         "\x8a\x49\x09\x15\x47\xf4\x3c\x89"
+                         "\x21\xeb\xcf\x4e\xcf\x91\xb5\x40"
+                         "\xcd\xe5\x4d\x5c\x6f\xf2\xd2\x80"
+                         "\xfa\xab\xb3\x76\x9f\x7f\x84\x0a",
+               .ctext  = "\x44\x98\x64\x15\xb7\x0b\x80\xa3"
+                         "\xb9\xca\x23\xff\x3b\x0b\x68\x74"
+                         "\xbb\x3e\x20\x19\x9f\x28\x71\x2a"
+                         "\x48\x3c\x7c\xe2\xef\xb5\x10\xac"
+                         "\x82\x9f\xcd\x08\x8f\x6b\x16\x6f"
+                         "\xc3\xbb\x07\xfb\x3c\xb0\x1b\x27",
+               .klen   = 24,
+               .len    = 48,
+       },
+       {
+               .key    = "\xb8\x35\xa2\x5f\x86\xbb\x82\x99"
+                         "\x27\xeb\x01\x3f\x92\xaf\x80\x24"
+                         "\x4c\x66\xa2\x89\xff\x2e\xa2\x25",
+               .iv     = "\x0a\x1d\x96\xd3\xe0\xe8\x0c\x9b"
+                         "\x9d\x6f\x21\x97\xc2\x17\xdb\x39"
+                         "\x3f\xd8\x64\x48\x80\x04\xee\x43"
+                         "\x02\xce\x88\xe2\x81\x81\x5f\x81",
+               .ptext  = "\xb8\xf9\x16\x8b\x25\x68\xd0\x9c"
+                         "\xd2\x28\xac\xa8\x79\xc2\x30\xc1"
+                         "\x31\xde\x1c\x37\x1b\xa2\xb5\xe6"
+                         "\xf0\xd0\xf8\x9c\x7f\xc6\x46\x07"
+                         "\x5c\xc3\x06\xe4\xf0\x02\xec\xf8"
+                         "\x59\x7c\xc2\x5d\xf8\x0c\x21\xae"
+                         "\x9e\x82\xb1\x1a\x5f\x78\x44\x15"
+                         "\x00\xa7\x2e\x52\xc5\x98\x98\x35"
+                         "\x03\xae\xd0\x8e\x07\x57\xe2\x5a"
+                         "\x17\xbf\x52\x40\x54\x5b\x74\xe5"
+                         "\x2d\x35\xaf\x9e\x37\xf7\x7e\x4a"
+                         "\x8c\x9e\xa1\xdc\x40\xb4\x5b\x36"
+                         "\xdc\x3a\x68\xe6\xb7\x35\x0b\x8a"
+                         "\x90\xec\x74\x8f\x09\x9a\x7f\x02"
+                         "\x4d\x03\x46\x35\x62\xb1\xbd\x08"
+                         "\x3f\x54\x2a\x10\x0b\xdc\x69\xaf"
+                         "\x25\x3a\x0c\x5f\xe0\x51\xe7\x11"
+                         "\xb7\x00\xab\xbb\x9a\xb0\xdc\x4d"
+                         "\xc3\x7d\x1a\x6e\xd1\x09\x52\xbd"
+                         "\x6b\x43\x55\x22\x3a\x78\x14\x7d"
+                         "\x79\xfd\x8d\xfc\x9b\x1d\x0f\xa2"
+                         "\xc7\xb9\xf8\x87\xd5\x96\x50\x61"
+                         "\xa7\x5e\x1e\x57\x97\xe0\xad\x2f"
+                         "\x93\xe6\xe8\x83\xec\x85\x26\x5e"
+                         "\xd9\x2a\x15\xe0\xe9\x09\x25\xa1"
+                         "\x77\x2b\x88\xdc\xa4\xa5\x48\xb6"
+                         "\xf7\xcc\xa6\xa9\xba\xf3\x42\x5c"
+                         "\x70\x9d\xe9\x29\xc1\xf1\x33\xdd"
+                         "\x56\x48\x17\x86\x14\x51\x5c\x10"
+                         "\xab\xfd\xd3\x26\x8c\x21\xf5\x93"
+                         "\x1b\xeb\x47\x97\x73\xbb\x88\x10"
+                         "\xf3\xfe\xf5\xde\xf3\x2e\x05\x46"
+                         "\x1c\x0d\xa3\x10\x48\x9c\x71\x16"
+                         "\x78\x33\x4d\x0a\x74\x3b\xe9\x34"
+                         "\x0b\xa7\x0e\x9e\x61\xe9\xe9\xfd"
+                         "\x85\xa0\xcb\x19\xfd\x7c\x33\xe3"
+                         "\x0e\xce\xc2\x6f\x9d\xa4\x2d\x77"
+                         "\xfd\xad\xee\x5e\x08\x3e\xd7\xf5"
+                         "\xfb\xc3\xd7\x93\x96\x08\x96\xca"
+                         "\x58\x81\x16\x9b\x98\x0a\xe2\xef"
+                         "\x7f\xda\x40\xe4\x1f\x46\x9e\x67"
+                         "\x2b\x84\xcb\x42\xc4\xd6\x6a\xcf"
+                         "\x2d\xb2\x33\xc0\x56\xb3\x35\x6f"
+                         "\x29\x36\x8f\x6a\x5b\xec\xd5\x4f"
+                         "\xa0\x70\xff\xb6\x5b\xde\x6a\x93"
+                         "\x20\x3c\xe2\x76\x7a\xef\x3c\x79"
+                         "\x31\x65\xce\x3a\x0e\xd0\xbe\xa8"
+                         "\x21\x95\xc7\x2b\x62\x8e\x67\xdd"
+                         "\x20\x79\xe4\xe5\x01\x15\xc0\xec"
+                         "\x0f\xd9\x23\xc8\xca\xdf\xd4\x7d"
+                         "\x1d\xf8\x64\x4f\x56\xb1\x83\xa7"
+                         "\x43\xbe\xfc\xcf\xc2\x8c\x33\xda"
+                         "\x36\xd0\x52\xef\x9e\x9e\x88\xf4"
+                         "\xa8\x21\x0f\xaa\xee\x8d\xa0\x24"
+                         "\x4d\xcb\xb1\x72\x07\xf0\xc2\x06"
+                         "\x60\x65\x85\x84\x2c\x60\xcf\x61"
+                         "\xe7\x56\x43\x5b\x2b\x50\x74\xfa"
+                         "\xdb\x4e\xea\x88\xd4\xb3\x83\x8f"
+                         "\x6f\x97\x4b\x57\x7a\x64\x64\xae"
+                         "\x0a\x37\x66\xc5\x03\xad\xb5\xf9"
+                         "\x08\xb0\x3a\x74\xde\x97\x51\xff"
+                         "\x48\x4f\x5c\xa4\xf8\x7a\xb4\x05"
+                         "\x27\x70\x52\x86\x1b\x78\xfc\x18"
+                         "\x06\x27\xa9\x62\xf7\xda\xd2\x8e",
+               .ctext  = "\x3b\xe1\xdb\xb3\xc5\x9a\xde\x69"
+                         "\x58\x05\xcc\xeb\x02\x51\x78\x4a"
+                         "\xac\x28\xe9\xed\xd1\xc9\x15\x7d"
+                         "\x33\x7d\xc1\x47\x12\x41\x11\xf8"
+                         "\x4a\x2c\xb7\xa3\x41\xbe\x59\xf7"
+                         "\x22\xdb\x2c\xda\x9c\x00\x61\x9b"
+                         "\x73\xb3\x0b\x84\x2b\xc1\xf3\x80"
+                         "\x84\xeb\x19\x60\x80\x09\xe1\xcd"
+                         "\x16\x3a\x20\x23\xc4\x82\x4f\xba"
+                         "\x3b\x8e\x55\xd7\xa9\x0b\x75\xd0"
+                         "\xda\xce\xd2\xee\x7e\x4b\x7f\x65"
+                         "\x4d\x28\xc5\xd3\x15\x2c\x40\x96"
+                         "\x52\xd4\x18\x61\x2b\xe7\x83\xec"
+                         "\x89\x62\x9c\x4c\x50\xe6\xe2\xbb"
+                         "\x25\xa1\x0f\xa7\xb0\xb4\xb2\xde"
+                         "\x54\x20\xae\xa3\x56\xa5\x26\x4c"
+                         "\xd5\xcc\xe5\xcb\x28\x44\xb1\xef"
+                         "\x67\x2e\x93\x6d\x00\x88\x83\x9a"
+                         "\xf2\x1c\x48\x38\xec\x1a\x24\x90"
+                         "\x73\x0a\xdb\xe8\xce\x95\x7a\x2c"
+                         "\x8c\xe9\xb7\x07\x1d\xb3\xa3\x20"
+                         "\xbe\xad\x61\x84\xac\xde\x76\xb5"
+                         "\xa6\x28\x29\x47\x63\xc4\xfc\x13"
+                         "\x3f\x71\xfb\x58\x37\x34\x82\xed"
+                         "\x9e\x05\x19\x1f\xc1\x67\xc1\xab"
+                         "\xf5\xfd\x7c\xea\xfa\xa4\xf8\x0a"
+                         "\xac\x4c\x92\xdf\x65\x73\xd7\xdb"
+                         "\xed\x2c\xe0\x84\x5f\x57\x8c\x76"
+                         "\x3e\x05\xc0\xc3\x68\x96\x95\x0b"
+                         "\x88\x97\xfe\x2e\x99\xd5\xc2\xb9"
+                         "\x53\x9f\xf3\x32\x10\x1f\x1f\x5d"
+                         "\xdf\x21\x95\x70\x91\xe8\xa1\x3e"
+                         "\x19\x3e\xb6\x0b\xa8\xdb\xf8\xd4"
+                         "\x54\x27\xb8\xab\x5d\x78\x0c\xe6"
+                         "\xb7\x08\xee\xa4\xb6\x6b\xeb\x5a"
+                         "\x89\x69\x2b\xbd\xd4\x21\x5b\xbf"
+                         "\x79\xbb\x0f\xff\xdb\x23\x9a\xeb"
+                         "\x8d\xf2\xc4\x39\xb4\x90\x77\x6f"
+                         "\x68\xe2\xb8\xf3\xf1\x65\x4f\xd5"
+                         "\x24\x80\x06\xaf\x7c\x8d\x15\x0c"
+                         "\xfd\x56\xe5\xe3\x01\xa5\xf7\x1c"
+                         "\x31\xd6\xa2\x01\x1e\x59\xf9\xa9"
+                         "\x42\xd5\xc2\x34\xda\x25\xde\xc6"
+                         "\x5d\x38\xef\xd1\x4c\xc1\xd9\x1b"
+                         "\x98\xfd\xcd\x57\x6f\xfd\x46\x91"
+                         "\x90\x3d\x52\x2b\x2c\x7d\xcf\x71"
+                         "\xcf\xd1\x77\x23\x71\x36\xb1\xce"
+                         "\xc7\x5d\xf0\x5b\x44\x3d\x43\x71"
+                         "\xac\xb8\xa0\x6a\xea\x89\x5c\xff"
+                         "\x81\x73\xd4\x83\xd1\xc9\xe9\xe2"
+                         "\xa8\xa6\x0f\x36\xe6\xaa\x57\xd4"
+                         "\x27\xd2\xc9\xda\x94\x02\x1f\xfb"
+                         "\xe1\xa1\x07\xbe\xe1\x1b\x15\x94"
+                         "\x1e\xac\x2f\x57\xbb\x41\x22\xaf"
+                         "\x60\x5e\xcc\x66\xcb\x16\x62\xab"
+                         "\xb8\x7c\x99\xf4\x84\x93\x0c\xc2"
+                         "\xa2\x49\xe4\xfd\x17\x55\xe1\xa6"
+                         "\x8d\x5b\xc6\x1b\xc8\xac\xec\x11"
+                         "\x33\xcf\xb0\xe8\xc7\x28\x4f\xb2"
+                         "\x5c\xa6\xe2\x71\xab\x80\x0a\xa7"
+                         "\x5c\x59\x50\x9f\x7a\x32\xb7\xe5"
+                         "\x24\x9a\x8e\x25\x21\x2e\xb7\x18"
+                         "\xd0\xf2\xe7\x27\x6f\xda\xc1\x00"
+                         "\xd9\xa6\x03\x59\xac\x4b\xcb\xba",
+               .klen   = 24,
+               .len    = 512,
+       },
+       {
+               .key    = "\x9e\xeb\xb2\x49\x3c\x1c\xf5\xf4"
+                         "\x6a\x99\xc2\xc4\xdf\xb1\xf4\xdd"
+                         "\x75\x20\x57\xea\x2c\x4f\xcd\xb2"
+                         "\xa5\x3d\x7b\x49\x1e\xab\xfd\x0f",
+               .iv     = "\xdf\x63\xd4\xab\xd2\x49\xf3\xd8"
+                         "\x33\x81\x37\x60\x7d\xfa\x73\x08"
+                         "\xd8\x49\x6d\x80\xe8\x2f\x62\x54"
+                         "\xeb\x0e\xa9\x39\x5b\x45\x7f\x8a",
+               .ptext  = "\x67\xc9\xf2\x30\x84\x41\x8e\x43"
+                         "\xfb\xf3\xb3\x3e\x79\x36\x7f\xe8",
+               .ctext  = "\x27\x38\x78\x47\x16\xd9\x71\x35"
+                         "\x2e\x7e\xdd\x7e\x43\x3c\xb8\x40",
+               .klen   = 32,
+               .len    = 16,
+       },
+       {
+               .key    = "\x93\xfa\x7e\xe2\x0e\x67\xc4\x39"
+                         "\xe7\xca\x47\x95\x68\x9d\x5e\x5a"
+                         "\x7c\x26\x19\xab\xc6\xca\x6a\x4c"
+                         "\x45\xa6\x96\x42\xae\x6c\xff\xe7",
+               .iv     = "\xea\x82\x47\x95\x3b\x22\xa1\x3a"
+                         "\x6a\xca\x24\x4c\x50\x7e\x23\xcd"
+                         "\x0e\x50\xe5\x41\xb6\x65\x29\xd8"
+                         "\x30\x23\x00\xd2\x54\xa7\xd6\x56",
+               .ptext  = "\xdb\x1f\x1f\xec\xad\x83\x6e\x5d"
+                         "\x19\xa5\xf6\x3b\xb4\x93\x5a\x57"
+                         "\x6f",
+               .ctext  = "\xf1\x46\x6e\x9d\xb3\x01\xf0\x6b"
+                         "\xc2\xac\x57\x88\x48\x6d\x40\x72"
+                         "\x68",
+               .klen   = 32,
+               .len    = 17,
+       },
+       {
+               .key    = "\x36\x2b\x57\x97\xf8\x5d\xcd\x99"
+                         "\x5f\x1a\x5a\x44\x1d\x92\x0f\x27"
+                         "\xcc\x16\xd7\x2b\x85\x63\x99\xd3"
+                         "\xba\x96\xa1\xdb\xd2\x60\x68\xda",
+               .iv     = "\xef\x58\x69\xb1\x2c\x5e\x9a\x47"
+                         "\x24\xc1\xb1\x69\xe1\x12\x93\x8f"
+                         "\x43\x3d\x6d\x00\xdb\x5e\xd8\xd9"
+                         "\x12\x9a\xfe\xd9\xff\x2d\xaa\xc4",
+               .ptext  = "\x5e\xa8\x68\x19\x85\x98\x12\x23"
+                         "\x26\x0a\xcc\xdb\x0a\x04\xb9\xdf"
+                         "\x4d\xb3\x48\x7b\xb0\xe3\xc8\x19"
+                         "\x43\x5a\x46\x06\x94\x2d\xf2",
+               .ctext  = "\xdb\xfd\xc8\x03\xd0\xec\xc1\xfe"
+                         "\xbd\x64\x37\xb8\x82\x43\x62\x4e"
+                         "\x7e\x54\xa3\xe2\x24\xa7\x27\xe8"
+                         "\xa4\xd5\xb3\x6c\xb2\x26\xb4",
+               .klen   = 32,
+               .len    = 31,
+       },
+       {
+               .key    = "\x03\x65\x03\x6e\x4d\xe6\xe8\x4e"
+                         "\x8b\xbe\x22\x19\x48\x31\xee\xd9"
+                         "\xa0\x91\x21\xbe\x62\x89\xde\x78"
+                         "\xd9\xb0\x36\xa3\x3c\xce\x43\xd5",
+               .iv     = "\xa9\xc3\x4b\xe7\x0f\xfc\x6d\xbf"
+                         "\x56\x27\x21\x1c\xfc\xd6\x04\x10"
+                         "\x5f\x43\xe2\x30\x35\x29\x6c\x10"
+                         "\x90\xf1\xbf\x61\xed\x0f\x8a\x91",
+               .ptext  = "\x07\xaa\x02\x26\xb4\x98\x11\x5e"
+                         "\x33\x41\x21\x51\x51\x63\x2c\x72"
+                         "\x00\xab\x32\xa7\x1c\xc8\x3c\x9c"
+                         "\x25\x0e\x8b\x9a\xdf\x85\xed\x2d"
+                         "\xf4\xf2\xbc\x55\xca\x92\x6d\x22"
+                         "\xfd\x22\x3b\x42\x4c\x0b\x74\xec",
+               .ctext  = "\x7b\xb1\x43\x6d\xd8\x72\x6c\xf6"
+                         "\x67\x6a\x00\xc4\xf1\xf0\xf5\xa4"
+                         "\xfc\x60\x91\xab\x46\x0b\x15\xfc"
+                         "\xd7\xc1\x28\x15\xa1\xfc\xf7\x68"
+                         "\x8e\xcc\x27\x62\x00\x64\x56\x72"
+                         "\xa6\x17\xd7\x3f\x67\x80\x10\x58",
+               .klen   = 32,
+               .len    = 48,
+       },
+       {
+               .key    = "\xa5\x28\x24\x34\x1a\x3c\xd8\xf7"
+                         "\x05\x91\x8f\xee\x85\x1f\x35\x7f"
+                         "\x80\x3d\xfc\x9b\x94\xf6\xfc\x9e"
+                         "\x19\x09\x00\xa9\x04\x31\x4f\x11",
+               .iv     = "\xa1\xba\x49\x95\xff\x34\x6d\xb8"
+                         "\xcd\x87\x5d\x5e\xfd\xea\x85\xdb"
+                         "\x8a\x7b\x5e\xb2\x5d\x57\xdd\x62"
+                         "\xac\xa9\x8c\x41\x42\x94\x75\xb7",
+               .ptext  = "\x69\xb4\xe8\x8c\x37\xe8\x67\x82"
+                         "\xf1\xec\x5d\x04\xe5\x14\x91\x13"
+                         "\xdf\xf2\x87\x1b\x69\x81\x1d\x71"
+                         "\x70\x9e\x9c\x3b\xde\x49\x70\x11"
+                         "\xa0\xa3\xdb\x0d\x54\x4f\x66\x69"
+                         "\xd7\xdb\x80\xa7\x70\x92\x68\xce"
+                         "\x81\x04\x2c\xc6\xab\xae\xe5\x60"
+                         "\x15\xe9\x6f\xef\xaa\x8f\xa7\xa7"
+                         "\x63\x8f\xf2\xf0\x77\xf1\xa8\xea"
+                         "\xe1\xb7\x1f\x9e\xab\x9e\x4b\x3f"
+                         "\x07\x87\x5b\x6f\xcd\xa8\xaf\xb9"
+                         "\xfa\x70\x0b\x52\xb8\xa8\xa7\x9e"
+                         "\x07\x5f\xa6\x0e\xb3\x9b\x79\x13"
+                         "\x79\xc3\x3e\x8d\x1c\x2c\x68\xc8"
+                         "\x51\x1d\x3c\x7b\x7d\x79\x77\x2a"
+                         "\x56\x65\xc5\x54\x23\x28\xb0\x03",
+               .ctext  = "\xeb\xf9\x98\x86\x3c\x40\x9f\x16"
+                         "\x84\x01\xf9\x06\x0f\xeb\x3c\xa9"
+                         "\x4c\xa4\x8e\x5d\xc3\x8d\xe5\xd3"
+                         "\xae\xa6\xe6\xcc\xd6\x2d\x37\x4f"
+                         "\x99\xc8\xa3\x21\x46\xb8\x69\xf2"
+                         "\xe3\x14\x89\xd7\xb9\xf5\x9e\x4e"
+                         "\x07\x93\x6f\x78\x8e\x6b\xea\x8f"
+                         "\xfb\x43\xb8\x3e\x9b\x4c\x1d\x7e"
+                         "\x20\x9a\xc5\x87\xee\xaf\xf6\xf9"
+                         "\x46\xc5\x18\x8a\xe8\x69\xe7\x96"
+                         "\x52\x55\x5f\x00\x1e\x1a\xdc\xcc"
+                         "\x13\xa5\xee\xff\x4b\x27\xca\xdc"
+                         "\x10\xa6\x48\x76\x98\x43\x94\xa3"
+                         "\xc7\xe2\xc9\x65\x9b\x08\x14\x26"
+                         "\x1d\x68\xfb\x15\x0a\x33\x49\x84"
+                         "\x84\x33\x5a\x1b\x24\x46\x31\x92",
+               .klen   = 32,
+               .len    = 128,
+       },
+       {
+               .key    = "\x36\x45\x11\xa2\x98\x5f\x96\x7c"
+                         "\xc6\xb4\x94\x31\x0a\x67\x09\x32"
+                         "\x6c\x6f\x6f\x00\xf0\x17\xcb\xac"
+                         "\xa5\xa9\x47\x9e\x2e\x85\x2f\xfa",
+               .iv     = "\x28\x88\xaa\x9b\x59\x3b\x1e\x97"
+                         "\x82\xe5\x5c\x9e\x6d\x14\x11\x19"
+                         "\x6e\x38\x8f\xd5\x40\x2b\xca\xf9"
+                         "\x7b\x4c\xe4\xa3\xd0\xd2\x8a\x13",
+               .ptext  = "\x95\xd2\xf7\x71\x1b\xca\xa5\x86"
+                         "\xd9\x48\x01\x93\x2f\x79\x55\x29"
+                         "\x71\x13\x15\x0e\xe6\x12\xbc\x4d"
+                         "\x8a\x31\xe3\x40\x2a\xc6\x5e\x0d"
+                         "\x68\xbb\x4a\x62\x8d\xc7\x45\x77"
+                         "\xd2\xb8\xc7\x1d\xf1\xd2\x5d\x97"
+                         "\xcf\xac\x52\xe5\x32\x77\xb6\xda"
+                         "\x30\x85\xcf\x2b\x98\xe9\xaa\x34"
+                         "\x62\xb5\x23\x9e\xb7\xa6\xd4\xe0"
+                         "\xb4\x58\x18\x8c\x4d\xde\x4d\x01"
+                         "\x83\x89\x24\xca\xfb\x11\xd4\x82"
+                         "\x30\x7a\x81\x35\xa0\xb4\xd4\xb6"
+                         "\x84\xea\x47\x91\x8c\x19\x86\x25"
+                         "\xa6\x06\x8d\x78\xe6\xed\x87\xeb"
+                         "\xda\xea\x73\x7c\xbf\x66\xb8\x72"
+                         "\xe3\x0a\xb8\x0c\xcb\x1a\x73\xf1"
+                         "\xa7\xca\x0a\xde\x57\x2b\xbd\x2b"
+                         "\xeb\x8b\x24\x38\x22\xd3\x0e\x1f"
+                         "\x17\xa0\x84\x98\x31\x77\xfd\x34"
+                         "\x6a\x4e\x3d\x84\x4c\x0e\xfb\xed"
+                         "\xc8\x2a\x51\xfa\xd8\x73\x21\x8a"
+                         "\xdb\xb5\xfe\x1f\xee\xc4\xe8\x65"
+                         "\x54\x84\xdd\x96\x6d\xfd\xd3\x31"
+                         "\x77\x36\x52\x6b\x80\x4f\x9e\xb4"
+                         "\xa2\x55\xbf\x66\x41\x49\x4e\x87"
+                         "\xa7\x0c\xca\xe7\xa5\xc5\xf6\x6f"
+                         "\x27\x56\xe2\x48\x22\xdd\x5f\x59"
+                         "\x3c\xf1\x9f\x83\xe5\x2d\xfb\x71"
+                         "\xad\xd1\xae\x1b\x20\x5c\x47\xb7"
+                         "\x3b\xd3\x14\xce\x81\x42\xb1\x0a"
+                         "\xf0\x49\xfa\xc2\xe7\x86\xbf\xcd"
+                         "\xb0\x95\x9f\x8f\x79\x41\x54",
+               .ctext  = "\xf6\x57\x51\xc4\x25\x61\x2d\xfa"
+                         "\xd6\xd9\x3f\x9a\x81\x51\xdd\x8e"
+                         "\x3d\xe7\xaa\x2d\xb1\xda\xc8\xa6"
+                         "\x9d\xaa\x3c\xab\x62\xf2\x80\xc3"
+                         "\x2c\xe7\x58\x72\x1d\x44\xc5\x28"
+                         "\x7f\xb4\xf9\xbc\x9c\xb2\xab\x8e"
+                         "\xfa\xd1\x4d\x72\xd9\x79\xf5\xa0"
+                         "\x24\x3e\x90\x25\x31\x14\x38\x45"
+                         "\x59\xc8\xf6\xe2\xc6\xf6\xc1\xa7"
+                         "\xb2\xf8\xa7\xa9\x2b\x6f\x12\x3a"
+                         "\xb0\x81\xa4\x08\x57\x59\xb1\x56"
+                         "\x4c\x8f\x18\x55\x33\x5f\xd6\x6a"
+                         "\xc6\xa0\x4b\xd6\x6b\x64\x3e\x9e"
+                         "\xfd\x66\x16\xe2\xdb\xeb\x5f\xb3"
+                         "\x50\x50\x3e\xde\x8d\x72\x76\x01"
+                         "\xbe\xcc\xc9\x52\x09\x2d\x8d\xe7"
+                         "\xd6\xc3\x66\xdb\x36\x08\xd1\x77"
+                         "\xc8\x73\x46\x26\x24\x29\xbf\x68"
+                         "\x2d\x2a\x99\x43\x56\x55\xe4\x93"
+                         "\xaf\xae\x4d\xe7\x55\x4a\xc0\x45"
+                         "\x26\xeb\x3b\x12\x90\x7c\xdc\xd1"
+                         "\xd5\x6f\x0a\xd0\xa9\xd7\x4b\x89"
+                         "\x0b\x07\xd8\x86\xad\xa1\xc4\x69"
+                         "\x1f\x5e\x8b\xc4\x9e\x91\x41\x25"
+                         "\x56\x98\x69\x78\x3a\x9e\xae\x91"
+                         "\xd8\xd9\xfa\xfb\xff\x81\x25\x09"
+                         "\xfc\xed\x2d\x87\xbc\x04\x62\x97"
+                         "\x35\xe1\x26\xc2\x46\x1c\xcf\xd7"
+                         "\x14\xed\x02\x09\xa5\xb2\xb6\xaa"
+                         "\x27\x4e\x61\xb3\x71\x6b\x47\x16"
+                         "\xb7\xe8\xd4\xaf\x52\xeb\x6a\x6b"
+                         "\xdb\x4c\x65\x21\x9e\x1c\x36",
+               .klen   = 32,
+               .len    = 255,
+       },
+       {
+               .key    = "\xd3\x81\x72\x18\x23\xff\x6f\x4a"
+                         "\x25\x74\x29\x0d\x51\x8a\x0e\x13"
+                         "\xc1\x53\x5d\x30\x8d\xee\x75\x0d"
+                         "\x14\xd6\x69\xc9\x15\xa9\x0c\x60",
+               .iv     = "\x65\x9b\xd4\xa8\x7d\x29\x1d\xf4"
+                         "\xc4\xd6\x9b\x6a\x28\xab\x64\xe2"
+                         "\x62\x81\x97\xc5\x81\xaa\xf9\x44"
+                         "\xc1\x72\x59\x82\xaf\x16\xc8\x2c",
+               .ptext  = "\xc7\x6b\x52\x6a\x10\xf0\xcc\x09"
+                         "\xc1\x12\x1d\x6d\x21\xa6\x78\xf5"
+                         "\x05\xa3\x69\x60\x91\x36\x98\x57"
+                         "\xba\x0c\x14\xcc\xf3\x2d\x73\x03"
+                         "\xc6\xb2\x5f\xc8\x16\x27\x37\x5d"
+                         "\xd0\x0b\x87\xb2\x50\x94\x7b\x58"
+                         "\x04\xf4\xe0\x7f\x6e\x57\x8e\xc9"
+                         "\x41\x84\xc1\xb1\x7e\x4b\x91\x12"
+                         "\x3a\x8b\x5d\x50\x82\x7b\xcb\xd9"
+                         "\x9a\xd9\x4e\x18\x06\x23\x9e\xd4"
+                         "\xa5\x20\x98\xef\xb5\xda\xe5\xc0"
+                         "\x8a\x6a\x83\x77\x15\x84\x1e\xae"
+                         "\x78\x94\x9d\xdf\xb7\xd1\xea\x67"
+                         "\xaa\xb0\x14\x15\xfa\x67\x21\x84"
+                         "\xd3\x41\x2a\xce\xba\x4b\x4a\xe8"
+                         "\x95\x62\xa9\x55\xf0\x80\xad\xbd"
+                         "\xab\xaf\xdd\x4f\xa5\x7c\x13\x36"
+                         "\xed\x5e\x4f\x72\xad\x4b\xf1\xd0"
+                         "\x88\x4e\xec\x2c\x88\x10\x5e\xea"
+                         "\x12\xc0\x16\x01\x29\xa3\xa0\x55"
+                         "\xaa\x68\xf3\xe9\x9d\x3b\x0d\x3b"
+                         "\x6d\xec\xf8\xa0\x2d\xf0\x90\x8d"
+                         "\x1c\xe2\x88\xd4\x24\x71\xf9\xb3"
+                         "\xc1\x9f\xc5\xd6\x76\x70\xc5\x2e"
+                         "\x9c\xac\xdb\x90\xbd\x83\x72\xba"
+                         "\x6e\xb5\xa5\x53\x83\xa9\xa5\xbf"
+                         "\x7d\x06\x0e\x3c\x2a\xd2\x04\xb5"
+                         "\x1e\x19\x38\x09\x16\xd2\x82\x1f"
+                         "\x75\x18\x56\xb8\x96\x0b\xa6\xf9"
+                         "\xcf\x62\xd9\x32\x5d\xa9\xd7\x1d"
+                         "\xec\xe4\xdf\x1b\xbe\xf1\x36\xee"
+                         "\xe3\x7b\xb5\x2f\xee\xf8\x53\x3d"
+                         "\x6a\xb7\x70\xa9\xfc\x9c\x57\x25"
+                         "\xf2\x89\x10\xd3\xb8\xa8\x8c\x30"
+                         "\xae\x23\x4f\x0e\x13\x66\x4f\xe1"
+                         "\xb6\xc0\xe4\xf8\xef\x93\xbd\x6e"
+                         "\x15\x85\x6b\xe3\x60\x81\x1d\x68"
+                         "\xd7\x31\x87\x89\x09\xab\xd5\x96"
+                         "\x1d\xf3\x6d\x67\x80\xca\x07\x31"
+                         "\x5d\xa7\xe4\xfb\x3e\xf2\x9b\x33"
+                         "\x52\x18\xc8\x30\xfe\x2d\xca\x1e"
+                         "\x79\x92\x7a\x60\x5c\xb6\x58\x87"
+                         "\xa4\x36\xa2\x67\x92\x8b\xa4\xb7"
+                         "\xf1\x86\xdf\xdc\xc0\x7e\x8f\x63"
+                         "\xd2\xa2\xdc\x78\xeb\x4f\xd8\x96"
+                         "\x47\xca\xb8\x91\xf9\xf7\x94\x21"
+                         "\x5f\x9a\x9f\x5b\xb8\x40\x41\x4b"
+                         "\x66\x69\x6a\x72\xd0\xcb\x70\xb7"
+                         "\x93\xb5\x37\x96\x05\x37\x4f\xe5"
+                         "\x8c\xa7\x5a\x4e\x8b\xb7\x84\xea"
+                         "\xc7\xfc\x19\x6e\x1f\x5a\xa1\xac"
+                         "\x18\x7d\x52\x3b\xb3\x34\x62\x99"
+                         "\xe4\x9e\x31\x04\x3f\xc0\x8d\x84"
+                         "\x17\x7c\x25\x48\x52\x67\x11\x27"
+                         "\x67\xbb\x5a\x85\xca\x56\xb2\x5c"
+                         "\xe6\xec\xd5\x96\x3d\x15\xfc\xfb"
+                         "\x22\x25\xf4\x13\xe5\x93\x4b\x9a"
+                         "\x77\xf1\x52\x18\xfa\x16\x5e\x49"
+                         "\x03\x45\xa8\x08\xfa\xb3\x41\x92"
+                         "\x79\x50\x33\xca\xd0\xd7\x42\x55"
+                         "\xc3\x9a\x0c\x4e\xd9\xa4\x3c\x86"
+                         "\x80\x9f\x53\xd1\xa4\x2e\xd1\xbc"
+                         "\xf1\x54\x6e\x93\xa4\x65\x99\x8e"
+                         "\xdf\x29\xc0\x64\x63\x07\xbb\xea",
+               .ctext  = "\x9f\x72\x87\xc7\x17\xfb\x20\x15"
+                         "\x65\xb3\x55\xa8\x1c\x8e\x52\x32"
+                         "\xb1\x82\x8d\xbf\xb5\x9f\x10\x0a"
+                         "\xe8\x0c\x70\x62\xef\x89\xb6\x1f"
+                         "\x73\xcc\xe4\xcc\x7a\x3a\x75\x4a"
+                         "\x26\xe7\xf5\xd7\x7b\x17\x39\x2d"
+                         "\xd2\x27\x6e\xf9\x2f\x9e\xe2\xf6"
+                         "\xfa\x16\xc2\xf2\x49\x26\xa7\x5b"
+                         "\xe7\xca\x25\x0e\x45\xa0\x34\xc2"
+                         "\x9a\x37\x79\x7e\x7c\x58\x18\x94"
+                         "\x10\xa8\x7c\x48\xa9\xd7\x63\x89"
+                         "\x9e\x61\x4d\x26\x34\xd9\xf0\xb1"
+                         "\x2d\x17\x2c\x6f\x7c\x35\x0e\xbe"
+                         "\x77\x71\x7c\x17\x5b\xab\x70\xdb"
+                         "\x2f\x54\x0f\xa9\xc8\xf4\xf5\xab"
+                         "\x52\x04\x3a\xb8\x03\xa7\xfd\x57"
+                         "\x45\x5e\xbc\x77\xe1\xee\x79\x8c"
+                         "\x58\x7b\x1f\xf7\x75\xde\x68\x17"
+                         "\x98\x85\x8a\x18\x5c\xd2\x39\x78"
+                         "\x7a\x6f\x26\x6e\xe1\x13\x91\xdd"
+                         "\xdf\x0e\x6e\x67\xcc\x51\x53\xd8"
+                         "\x17\x5e\xce\xa7\xe4\xaf\xfa\xf3"
+                         "\x4f\x9f\x01\x9b\x04\xe7\xfc\xf9"
+                         "\x6a\xdc\x1d\x0c\x9a\xaa\x3a\x7a"
+                         "\x73\x03\xdf\xbf\x3b\x82\xbe\xb0"
+                         "\xb4\xa4\xcf\x07\xd7\xde\x71\x25"
+                         "\xc5\x10\xee\x0a\x15\x96\x8b\x4f"
+                         "\xfe\xb8\x28\xbd\x4a\xcd\xeb\x9f"
+                         "\x5d\x00\xc1\xee\xe8\x16\x44\xec"
+                         "\xe9\x7b\xd6\x85\x17\x29\xcf\x58"
+                         "\x20\xab\xf7\xce\x6b\xe7\x71\x7d"
+                         "\x4f\xa8\xb0\xe9\x7d\x70\xd6\x0b"
+                         "\x2e\x20\xb1\x1a\x63\x37\xaa\x2c"
+                         "\x94\xee\xd5\xf6\x58\x2a\xf4\x7a"
+                         "\x4c\xba\xf5\xe9\x3c\x6f\x95\x13"
+                         "\x5f\x96\x81\x5b\xb5\x62\xf2\xd7"
+                         "\x8d\xbe\xa1\x31\x51\xe6\xfe\xc9"
+                         "\x07\x7d\x0f\x00\x3a\x66\x8c\x4b"
+                         "\x94\xaa\xe5\x56\xde\xcd\x74\xa7"
+                         "\x48\x67\x6f\xed\xc9\x6a\xef\xaf"
+                         "\x9a\xb7\xae\x60\xfa\xc0\x37\x39"
+                         "\xa5\x25\xe5\x22\xea\x82\x55\x68"
+                         "\x3e\x30\xc3\x5a\xb6\x29\x73\x7a"
+                         "\xb6\xfb\x34\xee\x51\x7c\x54\xe5"
+                         "\x01\x4d\x72\x25\x32\x4a\xa3\x68"
+                         "\x80\x9a\x89\xc5\x11\x66\x4c\x8c"
+                         "\x44\x50\xbe\xd7\xa0\xee\xa6\xbb"
+                         "\x92\x0c\xe6\xd7\x83\x51\xb1\x69"
+                         "\x63\x40\xf3\xf4\x92\x84\xc4\x38"
+                         "\x29\xfb\xb4\x84\xa0\x19\x75\x16"
+                         "\x60\xbf\x0a\x9c\x89\xee\xad\xb4"
+                         "\x43\xf9\x71\x39\x45\x7c\x24\x83"
+                         "\x30\xbb\xee\x28\xb0\x86\x7b\xec"
+                         "\x93\xc1\xbf\xb9\x97\x1b\x96\xef"
+                         "\xee\x58\x35\x61\x12\x19\xda\x25"
+                         "\x77\xe5\x80\x1a\x31\x27\x9b\xe4"
+                         "\xda\x8b\x7e\x51\x4d\xcb\x01\x19"
+                         "\x4f\xdc\x92\x1a\x17\xd5\x6b\xf4"
+                         "\x50\xe3\x06\xe4\x76\x9f\x65\x00"
+                         "\xbd\x7a\xe2\x64\x26\xf2\xe4\x7e"
+                         "\x40\xf2\x80\xab\x62\xd5\xef\x23"
+                         "\x8b\xfb\x6f\x24\x6e\x9b\x66\x0e"
+                         "\xf4\x1c\x24\x1e\x1d\x26\x95\x09"
+                         "\x94\x3c\xb2\xb6\x02\xa7\xd9\x9a",
+               .klen   = 32,
+               .len    = 512,
+       },
+
+};
 
 #endif /* _CRYPTO_TESTMGR_H */
index d23fa53..f921f30 100644 (file)
@@ -298,7 +298,7 @@ static const u32 mds[4][256] = {
  * multiplication is inefficient without hardware support.  To multiply
  * faster, I make use of the fact x is a generator for the nonzero elements,
  * so that every element p of GF(2)[x]/w(x) is either 0 or equal to (x)^n for
- * some n in 0..254.  Note that that caret is exponentiation in GF(2^8),
+ * some n in 0..254.  Note that caret is exponentiation in GF(2^8),
  * *not* polynomial notation.  So if I want to compute pq where p and q are
  * in GF(2^8), I can just say:
  *    1. if p=0 or q=0 then pq=0
diff --git a/crypto/xctr.c b/crypto/xctr.c
new file mode 100644 (file)
index 0000000..5c00147
--- /dev/null
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * XCTR: XOR Counter mode - Adapted from ctr.c
+ *
+ * (C) Copyright IBM Corp. 2007 - Joy Latten <latten@us.ibm.com>
+ * Copyright 2021 Google LLC
+ */
+
+/*
+ * XCTR mode is a blockcipher mode of operation used to implement HCTR2. XCTR is
+ * closely related to the CTR mode of operation; the main difference is that CTR
+ * generates the keystream using E(CTR + IV) whereas XCTR generates the
+ * keystream using E(CTR ^ IV). This allows implementations to avoid dealing
+ * with multi-limb integers (as is required in CTR mode). XCTR is also specified
+ * using little-endian arithmetic which makes it slightly faster on LE machines.
+ *
+ * See the HCTR2 paper for more details:
+ *     Length-preserving encryption with HCTR2
+ *      (https://eprint.iacr.org/2021/1441.pdf)
+ */
+
+#include <crypto/algapi.h>
+#include <crypto/internal/cipher.h>
+#include <crypto/internal/skcipher.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+/* For now this implementation is limited to 16-byte blocks for simplicity */
+#define XCTR_BLOCKSIZE 16
+
+static void crypto_xctr_crypt_final(struct skcipher_walk *walk,
+                                  struct crypto_cipher *tfm, u32 byte_ctr)
+{
+       u8 keystream[XCTR_BLOCKSIZE];
+       const u8 *src = walk->src.virt.addr;
+       u8 *dst = walk->dst.virt.addr;
+       unsigned int nbytes = walk->nbytes;
+       __le32 ctr32 = cpu_to_le32(byte_ctr / XCTR_BLOCKSIZE + 1);
+
+       crypto_xor(walk->iv, (u8 *)&ctr32, sizeof(ctr32));
+       crypto_cipher_encrypt_one(tfm, keystream, walk->iv);
+       crypto_xor_cpy(dst, keystream, src, nbytes);
+       crypto_xor(walk->iv, (u8 *)&ctr32, sizeof(ctr32));
+}
+
+static int crypto_xctr_crypt_segment(struct skcipher_walk *walk,
+                                   struct crypto_cipher *tfm, u32 byte_ctr)
+{
+       void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
+                  crypto_cipher_alg(tfm)->cia_encrypt;
+       const u8 *src = walk->src.virt.addr;
+       u8 *dst = walk->dst.virt.addr;
+       unsigned int nbytes = walk->nbytes;
+       __le32 ctr32 = cpu_to_le32(byte_ctr / XCTR_BLOCKSIZE + 1);
+
+       do {
+               crypto_xor(walk->iv, (u8 *)&ctr32, sizeof(ctr32));
+               fn(crypto_cipher_tfm(tfm), dst, walk->iv);
+               crypto_xor(dst, src, XCTR_BLOCKSIZE);
+               crypto_xor(walk->iv, (u8 *)&ctr32, sizeof(ctr32));
+
+               le32_add_cpu(&ctr32, 1);
+
+               src += XCTR_BLOCKSIZE;
+               dst += XCTR_BLOCKSIZE;
+       } while ((nbytes -= XCTR_BLOCKSIZE) >= XCTR_BLOCKSIZE);
+
+       return nbytes;
+}
+
+static int crypto_xctr_crypt_inplace(struct skcipher_walk *walk,
+                                   struct crypto_cipher *tfm, u32 byte_ctr)
+{
+       void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
+                  crypto_cipher_alg(tfm)->cia_encrypt;
+       unsigned long alignmask = crypto_cipher_alignmask(tfm);
+       unsigned int nbytes = walk->nbytes;
+       u8 *data = walk->src.virt.addr;
+       u8 tmp[XCTR_BLOCKSIZE + MAX_CIPHER_ALIGNMASK];
+       u8 *keystream = PTR_ALIGN(tmp + 0, alignmask + 1);
+       __le32 ctr32 = cpu_to_le32(byte_ctr / XCTR_BLOCKSIZE + 1);
+
+       do {
+               crypto_xor(walk->iv, (u8 *)&ctr32, sizeof(ctr32));
+               fn(crypto_cipher_tfm(tfm), keystream, walk->iv);
+               crypto_xor(data, keystream, XCTR_BLOCKSIZE);
+               crypto_xor(walk->iv, (u8 *)&ctr32, sizeof(ctr32));
+
+               le32_add_cpu(&ctr32, 1);
+
+               data += XCTR_BLOCKSIZE;
+       } while ((nbytes -= XCTR_BLOCKSIZE) >= XCTR_BLOCKSIZE);
+
+       return nbytes;
+}
+
+static int crypto_xctr_crypt(struct skcipher_request *req)
+{
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+       struct crypto_cipher *cipher = skcipher_cipher_simple(tfm);
+       struct skcipher_walk walk;
+       unsigned int nbytes;
+       int err;
+       u32 byte_ctr = 0;
+
+       err = skcipher_walk_virt(&walk, req, false);
+
+       while (walk.nbytes >= XCTR_BLOCKSIZE) {
+               if (walk.src.virt.addr == walk.dst.virt.addr)
+                       nbytes = crypto_xctr_crypt_inplace(&walk, cipher,
+                                                          byte_ctr);
+               else
+                       nbytes = crypto_xctr_crypt_segment(&walk, cipher,
+                                                          byte_ctr);
+
+               byte_ctr += walk.nbytes - nbytes;
+               err = skcipher_walk_done(&walk, nbytes);
+       }
+
+       if (walk.nbytes) {
+               crypto_xctr_crypt_final(&walk, cipher, byte_ctr);
+               err = skcipher_walk_done(&walk, 0);
+       }
+
+       return err;
+}
+
+static int crypto_xctr_create(struct crypto_template *tmpl, struct rtattr **tb)
+{
+       struct skcipher_instance *inst;
+       struct crypto_alg *alg;
+       int err;
+
+       inst = skcipher_alloc_instance_simple(tmpl, tb);
+       if (IS_ERR(inst))
+               return PTR_ERR(inst);
+
+       alg = skcipher_ialg_simple(inst);
+
+       /* Block size must be 16 bytes. */
+       err = -EINVAL;
+       if (alg->cra_blocksize != XCTR_BLOCKSIZE)
+               goto out_free_inst;
+
+       /* XCTR mode is a stream cipher. */
+       inst->alg.base.cra_blocksize = 1;
+
+       /*
+        * To simplify the implementation, configure the skcipher walk to only
+        * give a partial block at the very end, never earlier.
+        */
+       inst->alg.chunksize = alg->cra_blocksize;
+
+       inst->alg.encrypt = crypto_xctr_crypt;
+       inst->alg.decrypt = crypto_xctr_crypt;
+
+       err = skcipher_register_instance(tmpl, inst);
+       if (err) {
+out_free_inst:
+               inst->free(inst);
+       }
+
+       return err;
+}
+
+static struct crypto_template crypto_xctr_tmpl = {
+       .name = "xctr",
+       .create = crypto_xctr_create,
+       .module = THIS_MODULE,
+};
+
+static int __init crypto_xctr_module_init(void)
+{
+       return crypto_register_template(&crypto_xctr_tmpl);
+}
+
+static void __exit crypto_xctr_module_exit(void)
+{
+       crypto_unregister_template(&crypto_xctr_tmpl);
+}
+
+subsys_initcall(crypto_xctr_module_init);
+module_exit(crypto_xctr_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("XCTR block cipher mode of operation");
+MODULE_ALIAS_CRYPTO("xctr");
+MODULE_IMPORT_NS(CRYPTO_INTERNAL);
index 1e34f84..9b51c56 100644 (file)
@@ -210,7 +210,7 @@ config ACPI_TINY_POWER_BUTTON_SIGNAL
 
 config ACPI_VIDEO
        tristate "Video"
-       depends on X86 && BACKLIGHT_CLASS_DEVICE
+       depends on BACKLIGHT_CLASS_DEVICE
        depends on INPUT
        select THERMAL
        help
@@ -255,7 +255,6 @@ config ACPI_DOCK
 
 config ACPI_CPU_FREQ_PSS
        bool
-       select THERMAL
 
 config ACPI_PROCESSOR_CSTATE
        def_bool y
@@ -287,6 +286,7 @@ config ACPI_PROCESSOR
        depends on X86 || IA64 || ARM64 || LOONGARCH
        select ACPI_PROCESSOR_IDLE
        select ACPI_CPU_FREQ_PSS if X86 || IA64 || LOONGARCH
+       select THERMAL
        default y
        help
          This driver adds support for the ACPI Processor package. It is required
index b5a8d3e..0002eec 100644 (file)
@@ -109,10 +109,9 @@ obj-$(CONFIG_ACPI_PPTT)    += pptt.o
 obj-$(CONFIG_ACPI_PFRUT)       += pfr_update.o pfr_telemetry.o
 
 # processor has its own "processor." module_param namespace
-processor-y                    := processor_driver.o
+processor-y                    := processor_driver.o processor_thermal.o
 processor-$(CONFIG_ACPI_PROCESSOR_IDLE) += processor_idle.o
-processor-$(CONFIG_ACPI_CPU_FREQ_PSS)  += processor_throttling.o       \
-       processor_thermal.o
+processor-$(CONFIG_ACPI_CPU_FREQ_PSS)  += processor_throttling.o
 processor-$(CONFIG_CPU_FREQ)   += processor_perflib.o
 
 obj-$(CONFIG_ACPI_PROCESSOR_AGGREGATOR) += acpi_pad.o
index 48e5059..50540d4 100644 (file)
@@ -109,17 +109,11 @@ static void lpit_update_residency(struct lpit_residency_info *info,
                if (!info->iomem_addr)
                        return;
 
-               if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0))
-                       return;
-
                /* Silently fail, if cpuidle attribute group is not present */
                sysfs_add_file_to_group(&cpu_subsys.dev_root->kobj,
                                        &dev_attr_low_power_idle_system_residency_us.attr,
                                        "cpuidle");
        } else if (info->gaddr.space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) {
-               if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0))
-                       return;
-
                /* Silently fail, if cpuidle attribute group is not present */
                sysfs_add_file_to_group(&cpu_subsys.dev_root->kobj,
                                        &dev_attr_low_power_idle_cpu_residency_us.attr,
index fbe0756..c4d4d21 100644 (file)
@@ -422,6 +422,9 @@ static int register_device_clock(struct acpi_device *adev,
        if (!lpss_clk_dev)
                lpt_register_clock_device();
 
+       if (IS_ERR(lpss_clk_dev))
+               return PTR_ERR(lpss_clk_dev);
+
        clk_data = platform_get_drvdata(lpss_clk_dev);
        if (!clk_data)
                return -ENODEV;
index e07782b..5cbe219 100644 (file)
@@ -73,6 +73,7 @@ module_param(device_id_scheme, bool, 0444);
 static int only_lcd = -1;
 module_param(only_lcd, int, 0444);
 
+static bool may_report_brightness_keys;
 static int register_count;
 static DEFINE_MUTEX(register_count_mutex);
 static DEFINE_MUTEX(video_list_lock);
@@ -1149,24 +1150,25 @@ acpi_video_get_device_type(struct acpi_video_bus *video,
        return 0;
 }
 
-static int
-acpi_video_bus_get_one_device(struct acpi_device *device,
-                             struct acpi_video_bus *video)
+static int acpi_video_bus_get_one_device(struct acpi_device *device, void *arg)
 {
-       unsigned long long device_id;
-       int status, device_type;
-       struct acpi_video_device *data;
+       struct acpi_video_bus *video = arg;
        struct acpi_video_device_attrib *attribute;
+       struct acpi_video_device *data;
+       unsigned long long device_id;
+       acpi_status status;
+       int device_type;
 
-       status =
-           acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
-       /* Some device omits _ADR, we skip them instead of fail */
+       status = acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
+       /* Skip devices without _ADR instead of failing. */
        if (ACPI_FAILURE(status))
-               return 0;
+               goto exit;
 
        data = kzalloc(sizeof(struct acpi_video_device), GFP_KERNEL);
-       if (!data)
+       if (!data) {
+               dev_dbg(&device->dev, "Cannot attach\n");
                return -ENOMEM;
+       }
 
        strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME);
        strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
@@ -1222,11 +1224,16 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
        acpi_video_device_bind(video, data);
        acpi_video_device_find_cap(data);
 
+       if (data->cap._BCM && data->cap._BCL)
+               may_report_brightness_keys = true;
+
        mutex_lock(&video->device_list_lock);
        list_add_tail(&data->entry, &video->video_device_list);
        mutex_unlock(&video->device_list_lock);
 
-       return status;
+exit:
+       video->child_count++;
+       return 0;
 }
 
 /*
@@ -1538,9 +1545,6 @@ static int
 acpi_video_bus_get_devices(struct acpi_video_bus *video,
                           struct acpi_device *device)
 {
-       int status = 0;
-       struct acpi_device *dev;
-
        /*
         * There are systems where video module known to work fine regardless
         * of broken _DOD and ignoring returned value here doesn't cause
@@ -1548,16 +1552,7 @@ acpi_video_bus_get_devices(struct acpi_video_bus *video,
         */
        acpi_video_device_enumerate(video);
 
-       list_for_each_entry(dev, &device->children, node) {
-
-               status = acpi_video_bus_get_one_device(dev, video);
-               if (status) {
-                       dev_err(&dev->dev, "Can't attach device\n");
-                       break;
-               }
-               video->child_count++;
-       }
-       return status;
+       return acpi_dev_for_each_child(device, acpi_video_bus_get_one_device, video);
 }
 
 /* acpi_video interface */
@@ -1689,6 +1684,9 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
                break;
        }
 
+       if (keycode)
+               may_report_brightness_keys = true;
+
        acpi_notifier_call_chain(device, event, 0);
 
        if (keycode && (report_key_events & REPORT_BRIGHTNESS_KEY_EVENTS)) {
@@ -2249,6 +2247,7 @@ void acpi_video_unregister(void)
        if (register_count) {
                acpi_bus_unregister_driver(&acpi_video_bus);
                register_count = 0;
+               may_report_brightness_keys = false;
        }
        mutex_unlock(&register_count_mutex);
 }
@@ -2270,13 +2269,7 @@ void acpi_video_unregister_backlight(void)
 
 bool acpi_video_handles_brightness_key_presses(void)
 {
-       bool have_video_busses;
-
-       mutex_lock(&video_list_lock);
-       have_video_busses = !list_empty(&video_bus_head);
-       mutex_unlock(&video_list_lock);
-
-       return have_video_busses &&
+       return may_report_brightness_keys &&
               (report_key_events & REPORT_BRIGHTNESS_KEY_EVENTS);
 }
 EXPORT_SYMBOL(acpi_video_handles_brightness_key_presses);
index 33b7fbb..9f49272 100644 (file)
@@ -3,7 +3,7 @@
  * apei-base.c - ACPI Platform Error Interface (APEI) supporting
  * infrastructure
  *
- * APEI allows to report errors (for example from the chipset) to the
+ * APEI allows to report errors (for example from the chipset) to
  * the operating system. This improves NMI handling especially. In
  * addition it supports error serialization and error injection.
  *
index 598fd19..45973aa 100644 (file)
 
 #undef pr_fmt
 #define pr_fmt(fmt) "BERT: " fmt
+
+#define ACPI_BERT_PRINT_MAX_RECORDS 5
 #define ACPI_BERT_PRINT_MAX_LEN 1024
 
 static int bert_disable;
 
+/*
+ * Print "all" the error records in the BERT table, but avoid huge spam to
+ * the console if the BIOS included oversize records, or too many records.
+ * Skipping some records here does not lose anything because the full
+ * data is available to user tools in:
+ *     /sys/firmware/acpi/tables/data/BERT
+ */
 static void __init bert_print_all(struct acpi_bert_region *region,
                                  unsigned int region_len)
 {
        struct acpi_hest_generic_status *estatus =
                (struct acpi_hest_generic_status *)region;
        int remain = region_len;
+       int printed = 0, skipped = 0;
        u32 estatus_len;
 
        while (remain >= sizeof(struct acpi_bert_region)) {
@@ -46,24 +56,26 @@ static void __init bert_print_all(struct acpi_bert_region *region,
                if (remain < estatus_len) {
                        pr_err(FW_BUG "Truncated status block (length: %u).\n",
                               estatus_len);
-                       return;
+                       break;
                }
 
                /* No more error records. */
                if (!estatus->block_status)
-                       return;
+                       break;
 
                if (cper_estatus_check(estatus)) {
                        pr_err(FW_BUG "Invalid error record.\n");
-                       return;
+                       break;
                }
 
-               pr_info_once("Error records from previous boot:\n");
-               if (region_len < ACPI_BERT_PRINT_MAX_LEN)
+               if (estatus_len < ACPI_BERT_PRINT_MAX_LEN &&
+                   printed < ACPI_BERT_PRINT_MAX_RECORDS) {
+                       pr_info_once("Error records from previous boot:\n");
                        cper_estatus_print(KERN_INFO HW_ERR, estatus);
-               else
-                       pr_info_once("Max print length exceeded, table data is available at:\n"
-                                    "/sys/firmware/acpi/tables/data/BERT");
+                       printed++;
+               } else {
+                       skipped++;
+               }
 
                /*
                 * Because the boot error source is "one-time polled" type,
@@ -75,6 +87,9 @@ static void __init bert_print_all(struct acpi_bert_region *region,
                estatus = (void *)estatus + estatus_len;
                remain -= estatus_len;
        }
+
+       if (skipped)
+               pr_info(HW_ERR "Skipped %d error records\n", skipped);
 }
 
 static int __init setup_bert_disable(char *str)
index d4326ec..6b58337 100644 (file)
@@ -546,6 +546,8 @@ static int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
                                != REGION_INTERSECTS) &&
             (region_intersects(base_addr, size, IORESOURCE_MEM, IORES_DESC_PERSISTENT_MEMORY)
                                != REGION_INTERSECTS) &&
+            (region_intersects(base_addr, size, IORESOURCE_MEM, IORES_DESC_SOFT_RESERVED)
+                               != REGION_INTERSECTS) &&
             !arch_is_platform_page(base_addr)))
                return -EINVAL;
 
index 86fa61a..c0d20d9 100644 (file)
@@ -298,7 +298,7 @@ EXPORT_SYMBOL_GPL(osc_cpc_flexible_adr_space_confirmed);
 bool osc_sb_native_usb4_support_confirmed;
 EXPORT_SYMBOL_GPL(osc_sb_native_usb4_support_confirmed);
 
-bool osc_sb_cppc_not_supported;
+bool osc_sb_cppc2_support_acked;
 
 static u8 sb_uuid_str[] = "0811B06E-4A27-44F9-8D60-3CBBC22E7B48";
 static void acpi_bus_osc_negotiate_platform_control(void)
@@ -358,11 +358,6 @@ static void acpi_bus_osc_negotiate_platform_control(void)
                return;
        }
 
-#ifdef CONFIG_ACPI_CPPC_LIB
-       osc_sb_cppc_not_supported = !(capbuf_ret[OSC_SUPPORT_DWORD] &
-                       (OSC_SB_CPC_SUPPORT | OSC_SB_CPCV2_SUPPORT));
-#endif
-
        /*
         * Now run _OSC again with query flag clear and with the caps
         * supported by both the OS and the platform.
@@ -376,6 +371,10 @@ static void acpi_bus_osc_negotiate_platform_control(void)
 
        capbuf_ret = context.ret.pointer;
        if (context.ret.length > OSC_SUPPORT_DWORD) {
+#ifdef CONFIG_ACPI_CPPC_LIB
+               osc_sb_cppc2_support_acked = capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_CPCV2_SUPPORT;
+#endif
+
                osc_sb_apei_support_acked =
                        capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_APEI_SUPPORT;
                osc_pc_lpi_support_confirmed =
@@ -465,7 +464,6 @@ out_free:
 static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
 {
        struct acpi_device *adev;
-       struct acpi_driver *driver;
        u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
        bool hotplug_event = false;
 
@@ -517,10 +515,13 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
        if (!adev)
                goto err;
 
-       driver = adev->driver;
-       if (driver && driver->ops.notify &&
-           (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS))
-               driver->ops.notify(adev, type);
+       if (adev->dev.driver) {
+               struct acpi_driver *driver = to_acpi_driver(adev->dev.driver);
+
+               if (driver && driver->ops.notify &&
+                   (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS))
+                       driver->ops.notify(adev, type);
+       }
 
        if (!hotplug_event) {
                acpi_bus_put_acpi_device(adev);
@@ -539,8 +540,9 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
 static void acpi_notify_device(acpi_handle handle, u32 event, void *data)
 {
        struct acpi_device *device = data;
+       struct acpi_driver *acpi_drv = to_acpi_driver(device->dev.driver);
 
-       device->driver->ops.notify(device, event);
+       acpi_drv->ops.notify(device, event);
 }
 
 static void acpi_notify_device_fixed(void *data)
@@ -1033,8 +1035,6 @@ static int acpi_device_probe(struct device *dev)
        if (ret)
                return ret;
 
-       acpi_dev->driver = acpi_drv;
-
        pr_debug("Driver [%s] successfully bound to device [%s]\n",
                 acpi_drv->name, acpi_dev->pnp.bus_id);
 
@@ -1044,7 +1044,6 @@ static int acpi_device_probe(struct device *dev)
                        if (acpi_drv->ops.remove)
                                acpi_drv->ops.remove(acpi_dev);
 
-                       acpi_dev->driver = NULL;
                        acpi_dev->driver_data = NULL;
                        return ret;
                }
@@ -1060,15 +1059,14 @@ static int acpi_device_probe(struct device *dev)
 static void acpi_device_remove(struct device *dev)
 {
        struct acpi_device *acpi_dev = to_acpi_device(dev);
-       struct acpi_driver *acpi_drv = acpi_dev->driver;
+       struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver);
+
+       if (acpi_drv->ops.notify)
+               acpi_device_remove_notify_handler(acpi_dev);
+
+       if (acpi_drv->ops.remove)
+               acpi_drv->ops.remove(acpi_dev);
 
-       if (acpi_drv) {
-               if (acpi_drv->ops.notify)
-                       acpi_device_remove_notify_handler(acpi_dev);
-               if (acpi_drv->ops.remove)
-                       acpi_drv->ops.remove(acpi_dev);
-       }
-       acpi_dev->driver = NULL;
        acpi_dev->driver_data = NULL;
 
        put_device(dev);
@@ -1102,6 +1100,7 @@ static int acpi_dev_for_one_check(struct device *dev, void *context)
 
        return adwc->fn(to_acpi_device(dev), adwc->data);
 }
+EXPORT_SYMBOL_GPL(acpi_dev_for_each_child);
 
 int acpi_dev_for_each_child(struct acpi_device *adev,
                            int (*fn)(struct acpi_device *, void *), void *data)
@@ -1114,6 +1113,18 @@ int acpi_dev_for_each_child(struct acpi_device *adev,
        return device_for_each_child(&adev->dev, &adwc, acpi_dev_for_one_check);
 }
 
+int acpi_dev_for_each_child_reverse(struct acpi_device *adev,
+                                   int (*fn)(struct acpi_device *, void *),
+                                   void *data)
+{
+       struct acpi_dev_walk_context adwc = {
+               .fn = fn,
+               .data = data,
+       };
+
+       return device_for_each_child_reverse(&adev->dev, &adwc, acpi_dev_for_one_check);
+}
+
 /* --------------------------------------------------------------------------
                              Initialization/Cleanup
    -------------------------------------------------------------------------- */
@@ -1145,6 +1156,9 @@ static int __init acpi_bus_init_irq(void)
        case ACPI_IRQ_MODEL_PLATFORM:
                message = "platform specific model";
                break;
+       case ACPI_IRQ_MODEL_LPIC:
+               message = "LPIC";
+               break;
        default:
                pr_info("Unknown interrupt routing model\n");
                return -ENODEV;
@@ -1400,6 +1414,7 @@ static int __init acpi_init(void)
 
        pci_mmcfg_late_init();
        acpi_iort_init();
+       acpi_viot_early_init();
        acpi_hest_init();
        acpi_ghes_init();
        acpi_scan_init();
index ccaa647..5b7e3b9 100644 (file)
@@ -23,17 +23,18 @@ static const struct acpi_device_id container_device_ids[] = {
 
 #ifdef CONFIG_ACPI_CONTAINER
 
-static int acpi_container_offline(struct container_dev *cdev)
+static int check_offline(struct acpi_device *adev, void *not_used)
 {
-       struct acpi_device *adev = ACPI_COMPANION(&cdev->dev);
-       struct acpi_device *child;
+       if (acpi_scan_is_offline(adev, false))
+               return 0;
 
-       /* Check all of the dependent devices' physical companions. */
-       list_for_each_entry(child, &adev->children, node)
-               if (!acpi_scan_is_offline(child, false))
-                       return -EBUSY;
+       return -EBUSY;
+}
 
-       return 0;
+static int acpi_container_offline(struct container_dev *cdev)
+{
+       /* Check all of the dependent devices' physical companions. */
+       return acpi_dev_for_each_child(ACPI_COMPANION(&cdev->dev), check_offline, NULL);
 }
 
 static void acpi_container_release(struct device *dev)
index 903528f..1e15a9f 100644 (file)
@@ -578,6 +578,19 @@ bool __weak cpc_ffh_supported(void)
 }
 
 /**
+ * cpc_supported_by_cpu() - check if CPPC is supported by CPU
+ *
+ * Check if the architectural support for CPPC is present even
+ * if the _OSC hasn't prescribed it
+ *
+ * Return: true for supported, false for not supported
+ */
+bool __weak cpc_supported_by_cpu(void)
+{
+       return false;
+}
+
+/**
  * pcc_data_alloc() - Allocate the pcc_data memory for pcc subspace
  *
  * Check and allocate the cppc_pcc_data memory.
@@ -605,33 +618,6 @@ static int pcc_data_alloc(int pcc_ss_id)
        return 0;
 }
 
-/* Check if CPPC revision + num_ent combination is supported */
-static bool is_cppc_supported(int revision, int num_ent)
-{
-       int expected_num_ent;
-
-       switch (revision) {
-       case CPPC_V2_REV:
-               expected_num_ent = CPPC_V2_NUM_ENT;
-               break;
-       case CPPC_V3_REV:
-               expected_num_ent = CPPC_V3_NUM_ENT;
-               break;
-       default:
-               pr_debug("Firmware exports unsupported CPPC revision: %d\n",
-                       revision);
-               return false;
-       }
-
-       if (expected_num_ent != num_ent) {
-               pr_debug("Firmware exports %d entries. Expected: %d for CPPC rev:%d\n",
-                       num_ent, expected_num_ent, revision);
-               return false;
-       }
-
-       return true;
-}
-
 /*
  * An example CPC table looks like the following.
  *
@@ -684,8 +670,11 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
        acpi_status status;
        int ret = -ENODATA;
 
-       if (osc_sb_cppc_not_supported)
-               return -ENODEV;
+       if (!osc_sb_cppc2_support_acked) {
+               pr_debug("CPPC v2 _OSC not acked\n");
+               if (!cpc_supported_by_cpu())
+                       return -ENODEV;
+       }
 
        /* Parse the ACPI _CPC table for this CPU. */
        status = acpi_evaluate_object_typed(handle, "_CPC", NULL, &output,
@@ -717,7 +706,6 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
                         cpc_obj->type, pr->id);
                goto out_free;
        }
-       cpc_ptr->num_entries = num_ent;
 
        /* Second entry should be revision. */
        cpc_obj = &out_obj->package.elements[1];
@@ -728,10 +716,32 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
                         cpc_obj->type, pr->id);
                goto out_free;
        }
-       cpc_ptr->version = cpc_rev;
 
-       if (!is_cppc_supported(cpc_rev, num_ent))
+       if (cpc_rev < CPPC_V2_REV) {
+               pr_debug("Unsupported _CPC Revision (%d) for CPU:%d\n", cpc_rev,
+                        pr->id);
                goto out_free;
+       }
+
+       /*
+        * Disregard _CPC if the number of entries in the return pachage is not
+        * as expected, but support future revisions being proper supersets of
+        * the v3 and only causing more entries to be returned by _CPC.
+        */
+       if ((cpc_rev == CPPC_V2_REV && num_ent != CPPC_V2_NUM_ENT) ||
+           (cpc_rev == CPPC_V3_REV && num_ent != CPPC_V3_NUM_ENT) ||
+           (cpc_rev > CPPC_V3_REV && num_ent <= CPPC_V3_NUM_ENT)) {
+               pr_debug("Unexpected number of _CPC return package entries (%d) for CPU:%d\n",
+                        num_ent, pr->id);
+               goto out_free;
+       }
+       if (cpc_rev > CPPC_V3_REV) {
+               num_ent = CPPC_V3_NUM_ENT;
+               cpc_rev = CPPC_V3_REV;
+       }
+
+       cpc_ptr->num_entries = num_ent;
+       cpc_ptr->version = cpc_rev;
 
        /* Iterate through remaining entries in _CPC */
        for (i = 2; i < num_ent; i++) {
@@ -766,7 +776,8 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
 
                                        if (!osc_cpc_flexible_adr_space_confirmed) {
                                                pr_debug("Flexible address space capability not supported\n");
-                                               goto out_free;
+                                               if (!cpc_supported_by_cpu())
+                                                       goto out_free;
                                        }
 
                                        addr = ioremap(gas_t->address, gas_t->bit_width/8);
@@ -793,7 +804,8 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
                                }
                                if (!osc_cpc_flexible_adr_space_confirmed) {
                                        pr_debug("Flexible address space capability not supported\n");
-                                       goto out_free;
+                                       if (!cpc_supported_by_cpu())
+                                               goto out_free;
                                }
                        } else {
                                if (gas_t->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE || !cpc_ffh_supported()) {
index 130b5f4..9dce124 100644 (file)
@@ -369,6 +369,28 @@ int acpi_device_fix_up_power(struct acpi_device *device)
 }
 EXPORT_SYMBOL_GPL(acpi_device_fix_up_power);
 
+static int fix_up_power_if_applicable(struct acpi_device *adev, void *not_used)
+{
+       if (adev->status.present && adev->status.enabled)
+               acpi_device_fix_up_power(adev);
+
+       return 0;
+}
+
+/**
+ * acpi_device_fix_up_power_extended - Force device and its children into D0.
+ * @adev: Parent device object whose power state is to be fixed up.
+ *
+ * Call acpi_device_fix_up_power() for @adev and its children so long as they
+ * are reported as present and enabled.
+ */
+void acpi_device_fix_up_power_extended(struct acpi_device *adev)
+{
+       acpi_device_fix_up_power(adev);
+       acpi_dev_for_each_child(adev, fix_up_power_if_applicable, NULL);
+}
+EXPORT_SYMBOL_GPL(acpi_device_fix_up_power_extended);
+
 int acpi_device_update_power(struct acpi_device *device, int *state_p)
 {
        int state;
index d5d6403..120873d 100644 (file)
@@ -376,7 +376,7 @@ eject_store(struct device *d, struct device_attribute *attr,
                return -EINVAL;
 
        if ((!acpi_device->handler || !acpi_device->handler->hotplug.enabled)
-           && !acpi_device->driver)
+           && !d->driver)
                return -ENODEV;
 
        status = acpi_get_type(acpi_device->handle, &not_used);
index a1b871a..c95e535 100644 (file)
@@ -180,7 +180,6 @@ static struct workqueue_struct *ec_wq;
 static struct workqueue_struct *ec_query_wq;
 
 static int EC_FLAGS_CORRECT_ECDT; /* Needs ECDT port address correction */
-static int EC_FLAGS_IGNORE_DSDT_GPE; /* Needs ECDT GPE as correction setting */
 static int EC_FLAGS_TRUST_DSDT_GPE; /* Needs DSDT GPE as correction setting */
 static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
 
@@ -1407,24 +1406,16 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
        if (ec->data_addr == 0 || ec->command_addr == 0)
                return AE_OK;
 
-       if (boot_ec && boot_ec_is_ecdt && EC_FLAGS_IGNORE_DSDT_GPE) {
-               /*
-                * Always inherit the GPE number setting from the ECDT
-                * EC.
-                */
-               ec->gpe = boot_ec->gpe;
-       } else {
-               /* Get GPE bit assignment (EC events). */
-               /* TODO: Add support for _GPE returning a package */
-               status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp);
-               if (ACPI_SUCCESS(status))
-                       ec->gpe = tmp;
+       /* Get GPE bit assignment (EC events). */
+       /* TODO: Add support for _GPE returning a package */
+       status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp);
+       if (ACPI_SUCCESS(status))
+               ec->gpe = tmp;
+       /*
+        * Errors are non-fatal, allowing for ACPI Reduced Hardware
+        * platforms which use GpioInt instead of GPE.
+        */
 
-               /*
-                * Errors are non-fatal, allowing for ACPI Reduced Hardware
-                * platforms which use GpioInt instead of GPE.
-                */
-       }
        /* Use the global lock for all EC transactions? */
        tmp = 0;
        acpi_evaluate_integer(handle, "_GLK", NULL, &tmp);
@@ -1626,15 +1617,18 @@ static int acpi_ec_add(struct acpi_device *device)
                }
 
                if (boot_ec && ec->command_addr == boot_ec->command_addr &&
-                   ec->data_addr == boot_ec->data_addr &&
-                   !EC_FLAGS_TRUST_DSDT_GPE) {
+                   ec->data_addr == boot_ec->data_addr) {
                        /*
-                        * Trust PNP0C09 namespace location rather than
-                        * ECDT ID. But trust ECDT GPE rather than _GPE
-                        * because of ASUS quirks, so do not change
-                        * boot_ec->gpe to ec->gpe.
+                        * Trust PNP0C09 namespace location rather than ECDT ID.
+                        * But trust ECDT GPE rather than _GPE because of ASUS
+                        * quirks. So do not change boot_ec->gpe to ec->gpe,
+                        * except when the TRUST_DSDT_GPE quirk is set.
                         */
                        boot_ec->handle = ec->handle;
+
+                       if (EC_FLAGS_TRUST_DSDT_GPE)
+                               boot_ec->gpe = ec->gpe;
+
                        acpi_handle_debug(ec->handle, "duplicated.\n");
                        acpi_ec_free(ec);
                        ec = boot_ec;
@@ -1862,68 +1856,40 @@ static int ec_honor_dsdt_gpe(const struct dmi_system_id *id)
        return 0;
 }
 
-/*
- * Some DSDTs contain wrong GPE setting.
- * Asus FX502VD/VE, GL702VMK, X550VXK, X580VD
- * https://bugzilla.kernel.org/show_bug.cgi?id=195651
- */
-static int ec_honor_ecdt_gpe(const struct dmi_system_id *id)
-{
-       pr_debug("Detected system needing ignore DSDT GPE setting.\n");
-       EC_FLAGS_IGNORE_DSDT_GPE = 1;
-       return 0;
-}
-
 static const struct dmi_system_id ec_dmi_table[] __initconst = {
        {
-       ec_correct_ecdt, "MSI MS-171F", {
-       DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star"),
-       DMI_MATCH(DMI_PRODUCT_NAME, "MS-171F"),}, NULL},
-       {
-       ec_honor_ecdt_gpe, "ASUS FX502VD", {
-       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-       DMI_MATCH(DMI_PRODUCT_NAME, "FX502VD"),}, NULL},
-       {
-       ec_honor_ecdt_gpe, "ASUS FX502VE", {
-       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-       DMI_MATCH(DMI_PRODUCT_NAME, "FX502VE"),}, NULL},
-       {
-       ec_honor_ecdt_gpe, "ASUS GL702VMK", {
-       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-       DMI_MATCH(DMI_PRODUCT_NAME, "GL702VMK"),}, NULL},
-       {
-       ec_honor_ecdt_gpe, "ASUSTeK COMPUTER INC. X505BA", {
-       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-       DMI_MATCH(DMI_PRODUCT_NAME, "X505BA"),}, NULL},
-       {
-       ec_honor_ecdt_gpe, "ASUSTeK COMPUTER INC. X505BP", {
-       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-       DMI_MATCH(DMI_PRODUCT_NAME, "X505BP"),}, NULL},
-       {
-       ec_honor_ecdt_gpe, "ASUSTeK COMPUTER INC. X542BA", {
-       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-       DMI_MATCH(DMI_PRODUCT_NAME, "X542BA"),}, NULL},
-       {
-       ec_honor_ecdt_gpe, "ASUSTeK COMPUTER INC. X542BP", {
-       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-       DMI_MATCH(DMI_PRODUCT_NAME, "X542BP"),}, NULL},
-       {
-       ec_honor_ecdt_gpe, "ASUS X550VXK", {
-       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-       DMI_MATCH(DMI_PRODUCT_NAME, "X550VXK"),}, NULL},
-       {
-       ec_honor_ecdt_gpe, "ASUS X580VD", {
-       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-       DMI_MATCH(DMI_PRODUCT_NAME, "X580VD"),}, NULL},
+               /*
+                * MSI MS-171F
+                * https://bugzilla.kernel.org/show_bug.cgi?id=12461
+                */
+               .callback = ec_correct_ecdt,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MS-171F"),
+               },
+       },
        {
-       /* https://bugzilla.kernel.org/show_bug.cgi?id=209989 */
-       ec_honor_dsdt_gpe, "HP Pavilion Gaming Laptop 15-cx0xxx", {
-       DMI_MATCH(DMI_SYS_VENDOR, "HP"),
-       DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion Gaming Laptop 15-cx0xxx"),}, NULL},
+               /*
+                * HP Pavilion Gaming Laptop 15-cx0xxx
+                * https://bugzilla.kernel.org/show_bug.cgi?id=209989
+                */
+               .callback = ec_honor_dsdt_gpe,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "HP"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion Gaming Laptop 15-cx0xxx"),
+               },
+       },
        {
-       ec_clear_on_resume, "Samsung hardware", {
-       DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL},
-       {},
+               /*
+                * Samsung hardware
+                * https://bugzilla.kernel.org/show_bug.cgi?id=44161
+                */
+               .callback = ec_clear_on_resume,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+               },
+       },
+       {}
 };
 
 void __init acpi_ec_ecdt_probe(void)
@@ -2201,28 +2167,18 @@ static int acpi_ec_init_workqueues(void)
 
 static const struct dmi_system_id acpi_ec_no_wakeup[] = {
        {
-               .ident = "Thinkpad X1 Carbon 6th",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
                        DMI_MATCH(DMI_PRODUCT_FAMILY, "Thinkpad X1 Carbon 6th"),
                },
        },
        {
-               .ident = "ThinkPad X1 Carbon 6th",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_FAMILY, "ThinkPad X1 Carbon 6th"),
-               },
-       },
-       {
-               .ident = "ThinkPad X1 Yoga 3rd",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
                        DMI_MATCH(DMI_PRODUCT_FAMILY, "ThinkPad X1 Yoga 3rd"),
                },
        },
        {
-               .ident = "HP ZHAN 66 Pro",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "HP"),
                        DMI_MATCH(DMI_PRODUCT_FAMILY, "103C_5336AN HP ZHAN 66 Pro"),
index 8d76911..204fe94 100644 (file)
@@ -77,12 +77,22 @@ static struct acpi_bus_type *acpi_get_bus_type(struct device *dev)
 #define FIND_CHILD_MIN_SCORE   1
 #define FIND_CHILD_MAX_SCORE   2
 
+static int match_any(struct acpi_device *adev, void *not_used)
+{
+       return 1;
+}
+
+static bool acpi_dev_has_children(struct acpi_device *adev)
+{
+       return acpi_dev_for_each_child(adev, match_any, NULL) > 0;
+}
+
 static int find_child_checks(struct acpi_device *adev, bool check_children)
 {
        unsigned long long sta;
        acpi_status status;
 
-       if (check_children && list_empty(&adev->children))
+       if (check_children && !acpi_dev_has_children(adev))
                return -ENODEV;
 
        status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta);
@@ -105,54 +115,97 @@ static int find_child_checks(struct acpi_device *adev, bool check_children)
        return FIND_CHILD_MAX_SCORE;
 }
 
-struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
-                                          u64 address, bool check_children)
-{
-       struct acpi_device *adev, *ret = NULL;
-       int ret_score = 0;
-
-       if (!parent)
-               return NULL;
+struct find_child_walk_data {
+       struct acpi_device *adev;
+       u64 address;
+       int score;
+       bool check_sta;
+       bool check_children;
+};
 
-       list_for_each_entry(adev, &parent->children, node) {
-               acpi_bus_address addr = acpi_device_adr(adev);
-               int score;
+static int check_one_child(struct acpi_device *adev, void *data)
+{
+       struct find_child_walk_data *wd = data;
+       int score;
 
-               if (!adev->pnp.type.bus_address || addr != address)
-                       continue;
+       if (!adev->pnp.type.bus_address || acpi_device_adr(adev) != wd->address)
+               return 0;
 
-               if (!ret) {
-                       /* This is the first matching object.  Save it. */
-                       ret = adev;
-                       continue;
-               }
+       if (!wd->adev) {
                /*
-                * There is more than one matching device object with the same
-                * _ADR value.  That really is unexpected, so we are kind of
-                * beyond the scope of the spec here.  We have to choose which
-                * one to return, though.
-                *
-                * First, check if the previously found object is good enough
-                * and return it if so.  Second, do the same for the object that
-                * we've just found.
+                * This is the first matching object, so save it.  If it is not
+                * necessary to look for any other matching objects, stop the
+                * search.
                 */
-               if (!ret_score) {
-                       ret_score = find_child_checks(ret, check_children);
-                       if (ret_score == FIND_CHILD_MAX_SCORE)
-                               return ret;
-               }
-               score = find_child_checks(adev, check_children);
-               if (score == FIND_CHILD_MAX_SCORE) {
-                       return adev;
-               } else if (score > ret_score) {
-                       ret = adev;
-                       ret_score = score;
-               }
+               wd->adev = adev;
+               return !(wd->check_sta || wd->check_children);
        }
-       return ret;
+
+       /*
+        * There is more than one matching device object with the same _ADR
+        * value.  That really is unexpected, so we are kind of beyond the scope
+        * of the spec here.  We have to choose which one to return, though.
+        *
+        * First, get the score for the previously found object and terminate
+        * the walk if it is maximum.
+       */
+       if (!wd->score) {
+               score = find_child_checks(wd->adev, wd->check_children);
+               if (score == FIND_CHILD_MAX_SCORE)
+                       return 1;
+
+               wd->score = score;
+       }
+       /*
+        * Second, if the object that has just been found has a better score,
+        * replace the previously found one with it and terminate the walk if
+        * the new score is maximum.
+        */
+       score = find_child_checks(adev, wd->check_children);
+       if (score > wd->score) {
+               wd->adev = adev;
+               if (score == FIND_CHILD_MAX_SCORE)
+                       return 1;
+
+               wd->score = score;
+       }
+
+       /* Continue, because there may be better matches. */
+       return 0;
+}
+
+static struct acpi_device *acpi_find_child(struct acpi_device *parent,
+                                          u64 address, bool check_children,
+                                          bool check_sta)
+{
+       struct find_child_walk_data wd = {
+               .address = address,
+               .check_children = check_children,
+               .check_sta = check_sta,
+               .adev = NULL,
+               .score = 0,
+       };
+
+       if (parent)
+               acpi_dev_for_each_child(parent, check_one_child, &wd);
+
+       return wd.adev;
+}
+
+struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
+                                          u64 address, bool check_children)
+{
+       return acpi_find_child(parent, address, check_children, true);
 }
 EXPORT_SYMBOL_GPL(acpi_find_child_device);
 
+struct acpi_device *acpi_find_child_by_adr(struct acpi_device *adev,
+                                          acpi_bus_address adr)
+{
+       return acpi_find_child(adev, adr, false, false);
+}
+EXPORT_SYMBOL_GPL(acpi_find_child_by_adr);
+
 static void acpi_physnode_link_name(char *buf, unsigned int node_id)
 {
        if (node_id > 0)
index c68e694..dabe45e 100644 (file)
@@ -12,7 +12,8 @@
 
 enum acpi_irq_model_id acpi_irq_model;
 
-static struct fwnode_handle *acpi_gsi_domain_id;
+static struct fwnode_handle *(*acpi_get_gsi_domain_id)(u32 gsi);
+static u32 (*acpi_gsi_to_irq_fallback)(u32 gsi);
 
 /**
  * acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI
@@ -26,14 +27,18 @@ static struct fwnode_handle *acpi_gsi_domain_id;
  */
 int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
 {
-       struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
-                                                       DOMAIN_BUS_ANY);
+       struct irq_domain *d;
 
+       d = irq_find_matching_fwnode(acpi_get_gsi_domain_id(gsi),
+                                       DOMAIN_BUS_ANY);
        *irq = irq_find_mapping(d, gsi);
        /*
-        * *irq == 0 means no mapping, that should
-        * be reported as a failure
+        * *irq == 0 means no mapping, that should be reported as a
+        * failure, unless there is an arch-specific fallback handler.
         */
+       if (!*irq && acpi_gsi_to_irq_fallback)
+               *irq = acpi_gsi_to_irq_fallback(gsi);
+
        return (*irq > 0) ? 0 : -EINVAL;
 }
 EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
@@ -53,12 +58,12 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger,
 {
        struct irq_fwspec fwspec;
 
-       if (WARN_ON(!acpi_gsi_domain_id)) {
+       fwspec.fwnode = acpi_get_gsi_domain_id(gsi);
+       if (WARN_ON(!fwspec.fwnode)) {
                pr_warn("GSI: No registered irqchip, giving up\n");
                return -EINVAL;
        }
 
-       fwspec.fwnode = acpi_gsi_domain_id;
        fwspec.param[0] = gsi;
        fwspec.param[1] = acpi_dev_get_irq_type(trigger, polarity);
        fwspec.param_count = 2;
@@ -73,13 +78,14 @@ EXPORT_SYMBOL_GPL(acpi_register_gsi);
  */
 void acpi_unregister_gsi(u32 gsi)
 {
-       struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
-                                                       DOMAIN_BUS_ANY);
+       struct irq_domain *d;
        int irq;
 
        if (WARN_ON(acpi_irq_model == ACPI_IRQ_MODEL_GIC && gsi < 16))
                return;
 
+       d = irq_find_matching_fwnode(acpi_get_gsi_domain_id(gsi),
+                                    DOMAIN_BUS_ANY);
        irq = irq_find_mapping(d, gsi);
        irq_dispose_mapping(irq);
 }
@@ -97,7 +103,8 @@ EXPORT_SYMBOL_GPL(acpi_unregister_gsi);
  * The referenced device fwhandle or NULL on failure
  */
 static struct fwnode_handle *
-acpi_get_irq_source_fwhandle(const struct acpi_resource_source *source)
+acpi_get_irq_source_fwhandle(const struct acpi_resource_source *source,
+                            u32 gsi)
 {
        struct fwnode_handle *result;
        struct acpi_device *device;
@@ -105,7 +112,7 @@ acpi_get_irq_source_fwhandle(const struct acpi_resource_source *source)
        acpi_status status;
 
        if (!source->string_length)
-               return acpi_gsi_domain_id;
+               return acpi_get_gsi_domain_id(gsi);
 
        status = acpi_get_handle(NULL, source->string_ptr, &handle);
        if (WARN_ON(ACPI_FAILURE(status)))
@@ -194,7 +201,7 @@ static acpi_status acpi_irq_parse_one_cb(struct acpi_resource *ares,
                        ctx->index -= irq->interrupt_count;
                        return AE_OK;
                }
-               fwnode = acpi_gsi_domain_id;
+               fwnode = acpi_get_gsi_domain_id(irq->interrupts[ctx->index]);
                acpi_irq_parse_one_match(fwnode, irq->interrupts[ctx->index],
                                         irq->triggering, irq->polarity,
                                         irq->shareable, ctx);
@@ -207,7 +214,8 @@ static acpi_status acpi_irq_parse_one_cb(struct acpi_resource *ares,
                        ctx->index -= eirq->interrupt_count;
                        return AE_OK;
                }
-               fwnode = acpi_get_irq_source_fwhandle(&eirq->resource_source);
+               fwnode = acpi_get_irq_source_fwhandle(&eirq->resource_source,
+                                                     eirq->interrupts[ctx->index]);
                acpi_irq_parse_one_match(fwnode, eirq->interrupts[ctx->index],
                                         eirq->triggering, eirq->polarity,
                                         eirq->shareable, ctx);
@@ -291,10 +299,20 @@ EXPORT_SYMBOL_GPL(acpi_irq_get);
  *          GSI interrupts
  */
 void __init acpi_set_irq_model(enum acpi_irq_model_id model,
-                              struct fwnode_handle *fwnode)
+                              struct fwnode_handle *(*fn)(u32))
 {
        acpi_irq_model = model;
-       acpi_gsi_domain_id = fwnode;
+       acpi_get_gsi_domain_id = fn;
+}
+
+/**
+ * acpi_set_gsi_to_irq_fallback - Register a GSI transfer
+ * callback to fallback to arch specified implementation.
+ * @fn: arch-specific fallback handler
+ */
+void __init acpi_set_gsi_to_irq_fallback(u32 (*fn)(u32))
+{
+       acpi_gsi_to_irq_fallback = fn;
 }
 
 /**
@@ -312,8 +330,14 @@ struct irq_domain *acpi_irq_create_hierarchy(unsigned int flags,
                                             const struct irq_domain_ops *ops,
                                             void *host_data)
 {
-       struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
-                                                       DOMAIN_BUS_ANY);
+       struct irq_domain *d;
+
+       /* This only works for the GIC model... */
+       if (acpi_irq_model != ACPI_IRQ_MODEL_GIC)
+               return NULL;
+
+       d = irq_find_matching_fwnode(acpi_get_gsi_domain_id(0),
+                                    DOMAIN_BUS_ANY);
 
        if (!d)
                return NULL;
index 5864705..aa1038b 100644 (file)
@@ -95,7 +95,7 @@ static acpi_status acpi_pci_link_check_possible(struct acpi_resource *resource,
        case ACPI_RESOURCE_TYPE_IRQ:
                {
                        struct acpi_resource_irq *p = &resource->data.irq;
-                       if (!p || !p->interrupt_count) {
+                       if (!p->interrupt_count) {
                                acpi_handle_debug(handle,
                                                  "Blank _PRS IRQ resource\n");
                                return AE_OK;
@@ -121,7 +121,7 @@ static acpi_status acpi_pci_link_check_possible(struct acpi_resource *resource,
                {
                        struct acpi_resource_extended_irq *p =
                            &resource->data.extended_irq;
-                       if (!p || !p->interrupt_count) {
+                       if (!p->interrupt_count) {
                                acpi_handle_debug(handle,
                                                  "Blank _PRS EXT IRQ resource\n");
                                return AE_OK;
@@ -182,7 +182,7 @@ static acpi_status acpi_pci_link_check_current(struct acpi_resource *resource,
        case ACPI_RESOURCE_TYPE_IRQ:
                {
                        struct acpi_resource_irq *p = &resource->data.irq;
-                       if (!p || !p->interrupt_count) {
+                       if (!p->interrupt_count) {
                                /*
                                 * IRQ descriptors may have no IRQ# bits set,
                                 * particularly those w/ _STA disabled
@@ -197,7 +197,7 @@ static acpi_status acpi_pci_link_check_current(struct acpi_resource *resource,
                {
                        struct acpi_resource_extended_irq *p =
                            &resource->data.extended_irq;
-                       if (!p || !p->interrupt_count) {
+                       if (!p->interrupt_count) {
                                /*
                                 * extended IRQ descriptors must
                                 * return at least 1 IRQ
index 368a9ed..1278969 100644 (file)
@@ -139,75 +139,17 @@ static int acpi_soft_cpu_dead(unsigned int cpu)
 }
 
 #ifdef CONFIG_ACPI_CPU_FREQ_PSS
-static int acpi_pss_perf_init(struct acpi_processor *pr,
-               struct acpi_device *device)
+static void acpi_pss_perf_init(struct acpi_processor *pr)
 {
-       int result = 0;
-
        acpi_processor_ppc_has_changed(pr, 0);
 
        acpi_processor_get_throttling_info(pr);
 
        if (pr->flags.throttling)
                pr->flags.limit = 1;
-
-       pr->cdev = thermal_cooling_device_register("Processor", device,
-                                                  &processor_cooling_ops);
-       if (IS_ERR(pr->cdev)) {
-               result = PTR_ERR(pr->cdev);
-               return result;
-       }
-
-       dev_dbg(&device->dev, "registered as cooling_device%d\n",
-               pr->cdev->id);
-
-       result = sysfs_create_link(&device->dev.kobj,
-                                  &pr->cdev->device.kobj,
-                                  "thermal_cooling");
-       if (result) {
-               dev_err(&device->dev,
-                       "Failed to create sysfs link 'thermal_cooling'\n");
-               goto err_thermal_unregister;
-       }
-
-       result = sysfs_create_link(&pr->cdev->device.kobj,
-                                  &device->dev.kobj,
-                                  "device");
-       if (result) {
-               dev_err(&pr->cdev->device,
-                       "Failed to create sysfs link 'device'\n");
-               goto err_remove_sysfs_thermal;
-       }
-
-       return 0;
-
- err_remove_sysfs_thermal:
-       sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
- err_thermal_unregister:
-       thermal_cooling_device_unregister(pr->cdev);
-
-       return result;
-}
-
-static void acpi_pss_perf_exit(struct acpi_processor *pr,
-               struct acpi_device *device)
-{
-       if (pr->cdev) {
-               sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
-               sysfs_remove_link(&pr->cdev->device.kobj, "device");
-               thermal_cooling_device_unregister(pr->cdev);
-               pr->cdev = NULL;
-       }
 }
 #else
-static inline int acpi_pss_perf_init(struct acpi_processor *pr,
-               struct acpi_device *device)
-{
-       return 0;
-}
-
-static inline void acpi_pss_perf_exit(struct acpi_processor *pr,
-               struct acpi_device *device) {}
+static inline void acpi_pss_perf_init(struct acpi_processor *pr) {}
 #endif /* CONFIG_ACPI_CPU_FREQ_PSS */
 
 static int __acpi_processor_start(struct acpi_device *device)
@@ -229,7 +171,9 @@ static int __acpi_processor_start(struct acpi_device *device)
        if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver)
                acpi_processor_power_init(pr);
 
-       result = acpi_pss_perf_init(pr, device);
+       acpi_pss_perf_init(pr);
+
+       result = acpi_processor_thermal_init(pr, device);
        if (result)
                goto err_power_exit;
 
@@ -239,7 +183,7 @@ static int __acpi_processor_start(struct acpi_device *device)
                return 0;
 
        result = -ENODEV;
-       acpi_pss_perf_exit(pr, device);
+       acpi_processor_thermal_exit(pr, device);
 
 err_power_exit:
        acpi_processor_power_exit(pr);
@@ -277,10 +221,10 @@ static int acpi_processor_stop(struct device *dev)
                return 0;
        acpi_processor_power_exit(pr);
 
-       acpi_pss_perf_exit(pr, device);
-
        acpi_cppc_processor_exit(pr);
 
+       acpi_processor_thermal_exit(pr, device);
+
        return 0;
 }
 
index 6a5572a..16a1663 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/minmax.h>
 #include <linux/perf_event.h>
 #include <acpi/processor.h>
+#include <linux/context_tracking.h>
 
 /*
  * Include the apic definitions for x86 to have the APIC timer related defines
@@ -607,7 +608,7 @@ static DEFINE_RAW_SPINLOCK(c3_lock);
  * @cx: Target state context
  * @index: index of target state
  */
-static int acpi_idle_enter_bm(struct cpuidle_driver *drv,
+static int __cpuidle acpi_idle_enter_bm(struct cpuidle_driver *drv,
                               struct acpi_processor *pr,
                               struct acpi_processor_cx *cx,
                               int index)
@@ -647,11 +648,11 @@ static int acpi_idle_enter_bm(struct cpuidle_driver *drv,
                raw_spin_unlock(&c3_lock);
        }
 
-       rcu_idle_enter();
+       ct_idle_enter();
 
        acpi_idle_do_entry(cx);
 
-       rcu_idle_exit();
+       ct_idle_exit();
 
        /* Re-enable bus master arbitration */
        if (dis_bm) {
@@ -664,7 +665,7 @@ static int acpi_idle_enter_bm(struct cpuidle_driver *drv,
        return index;
 }
 
-static int acpi_idle_enter(struct cpuidle_device *dev,
+static int __cpuidle acpi_idle_enter(struct cpuidle_device *dev,
                           struct cpuidle_driver *drv, int index)
 {
        struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu);
@@ -693,7 +694,7 @@ static int acpi_idle_enter(struct cpuidle_device *dev,
        return index;
 }
 
-static int acpi_idle_enter_s2idle(struct cpuidle_device *dev,
+static int __cpuidle acpi_idle_enter_s2idle(struct cpuidle_device *dev,
                                  struct cpuidle_driver *drv, int index)
 {
        struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu);
index d8b2dfc..db6ac54 100644 (file)
@@ -266,3 +266,57 @@ const struct thermal_cooling_device_ops processor_cooling_ops = {
        .get_cur_state = processor_get_cur_state,
        .set_cur_state = processor_set_cur_state,
 };
+
+int acpi_processor_thermal_init(struct acpi_processor *pr,
+                               struct acpi_device *device)
+{
+       int result = 0;
+
+       pr->cdev = thermal_cooling_device_register("Processor", device,
+                                                  &processor_cooling_ops);
+       if (IS_ERR(pr->cdev)) {
+               result = PTR_ERR(pr->cdev);
+               return result;
+       }
+
+       dev_dbg(&device->dev, "registered as cooling_device%d\n",
+               pr->cdev->id);
+
+       result = sysfs_create_link(&device->dev.kobj,
+                                  &pr->cdev->device.kobj,
+                                  "thermal_cooling");
+       if (result) {
+               dev_err(&device->dev,
+                       "Failed to create sysfs link 'thermal_cooling'\n");
+               goto err_thermal_unregister;
+       }
+
+       result = sysfs_create_link(&pr->cdev->device.kobj,
+                                  &device->dev.kobj,
+                                  "device");
+       if (result) {
+               dev_err(&pr->cdev->device,
+                       "Failed to create sysfs link 'device'\n");
+               goto err_remove_sysfs_thermal;
+       }
+
+       return 0;
+
+err_remove_sysfs_thermal:
+       sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
+err_thermal_unregister:
+       thermal_cooling_device_unregister(pr->cdev);
+
+       return result;
+}
+
+void acpi_processor_thermal_exit(struct acpi_processor *pr,
+                                struct acpi_device *device)
+{
+       if (pr->cdev) {
+               sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
+               sysfs_remove_link(&pr->cdev->device.kobj, "device");
+               thermal_cooling_device_unregister(pr->cdev);
+               pr->cdev = NULL;
+       }
+}
index d317381..e764f9a 100644 (file)
@@ -1012,6 +1012,22 @@ static int acpi_node_prop_read(const struct fwnode_handle *fwnode,
                                   propname, proptype, val, nval);
 }
 
+static int stop_on_next(struct acpi_device *adev, void *data)
+{
+       struct acpi_device **ret_p = data;
+
+       if (!*ret_p) {
+               *ret_p = adev;
+               return 1;
+       }
+
+       /* Skip until the "previous" object is found. */
+       if (*ret_p == adev)
+               *ret_p = NULL;
+
+       return 0;
+}
+
 /**
  * acpi_get_next_subnode - Return the next child node handle for a fwnode
  * @fwnode: Firmware node to find the next child node for.
@@ -1020,35 +1036,22 @@ static int acpi_node_prop_read(const struct fwnode_handle *fwnode,
 struct fwnode_handle *acpi_get_next_subnode(const struct fwnode_handle *fwnode,
                                            struct fwnode_handle *child)
 {
-       const struct acpi_device *adev = to_acpi_device_node(fwnode);
-       const struct list_head *head;
-       struct list_head *next;
+       struct acpi_device *adev = to_acpi_device_node(fwnode);
 
        if ((!child || is_acpi_device_node(child)) && adev) {
-               struct acpi_device *child_adev;
+               struct acpi_device *child_adev = to_acpi_device_node(child);
 
-               head = &adev->children;
-               if (list_empty(head))
-                       goto nondev;
+               acpi_dev_for_each_child(adev, stop_on_next, &child_adev);
+               if (child_adev)
+                       return acpi_fwnode_handle(child_adev);
 
-               if (child) {
-                       adev = to_acpi_device_node(child);
-                       next = adev->node.next;
-                       if (next == head) {
-                               child = NULL;
-                               goto nondev;
-                       }
-                       child_adev = list_entry(next, struct acpi_device, node);
-               } else {
-                       child_adev = list_first_entry(head, struct acpi_device,
-                                                     node);
-               }
-               return acpi_fwnode_handle(child_adev);
+               child = NULL;
        }
 
- nondev:
        if (!child || is_acpi_data_node(child)) {
                const struct acpi_data_node *data = to_acpi_data_node(fwnode);
+               const struct list_head *head;
+               struct list_head *next;
                struct acpi_data_node *dn;
 
                /*
index c2d4947..510cdec 100644 (file)
@@ -416,6 +416,16 @@ static bool acpi_dev_irq_override(u32 gsi, u8 triggering, u8 polarity,
 {
        int i;
 
+#ifdef CONFIG_X86
+       /*
+        * IRQ override isn't needed on modern AMD Zen systems and
+        * this override breaks active low IRQs on AMD Ryzen 6000 and
+        * newer systems. Skip it.
+        */
+       if (boot_cpu_has(X86_FEATURE_ZEN))
+               return false;
+#endif
+
        for (i = 0; i < ARRAY_SIZE(skip_override_table); i++) {
                const struct irq_override_cmp *entry = &skip_override_table[i];
 
index 762b61f..b100e6c 100644 (file)
@@ -334,10 +334,9 @@ static int acpi_scan_device_check(struct acpi_device *adev)
        return error;
 }
 
-static int acpi_scan_bus_check(struct acpi_device *adev)
+static int acpi_scan_bus_check(struct acpi_device *adev, void *not_used)
 {
        struct acpi_scan_handler *handler = adev->handler;
-       struct acpi_device *child;
        int error;
 
        acpi_bus_get_status(adev);
@@ -353,19 +352,14 @@ static int acpi_scan_bus_check(struct acpi_device *adev)
                dev_warn(&adev->dev, "Namespace scan failure\n");
                return error;
        }
-       list_for_each_entry(child, &adev->children, node) {
-               error = acpi_scan_bus_check(child);
-               if (error)
-                       return error;
-       }
-       return 0;
+       return acpi_dev_for_each_child(adev, acpi_scan_bus_check, NULL);
 }
 
 static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type)
 {
        switch (type) {
        case ACPI_NOTIFY_BUS_CHECK:
-               return acpi_scan_bus_check(adev);
+               return acpi_scan_bus_check(adev, NULL);
        case ACPI_NOTIFY_DEVICE_CHECK:
                return acpi_scan_device_check(adev);
        case ACPI_NOTIFY_EJECT_REQUEST:
@@ -471,8 +465,6 @@ static void acpi_device_del(struct acpi_device *device)
        struct acpi_device_bus_id *acpi_device_bus_id;
 
        mutex_lock(&acpi_device_lock);
-       if (device->parent)
-               list_del(&device->node);
 
        list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node)
                if (!strcmp(acpi_device_bus_id->bus_id,
@@ -488,6 +480,7 @@ static void acpi_device_del(struct acpi_device *device)
                }
 
        list_del(&device->wakeup_list);
+
        mutex_unlock(&acpi_device_lock);
 
        acpi_power_add_remove_device(device, false);
@@ -680,8 +673,6 @@ static int __acpi_device_add(struct acpi_device *device,
         * -------
         * Link this device to its parent and siblings.
         */
-       INIT_LIST_HEAD(&device->children);
-       INIT_LIST_HEAD(&device->node);
        INIT_LIST_HEAD(&device->wakeup_list);
        INIT_LIST_HEAD(&device->physical_node_list);
        INIT_LIST_HEAD(&device->del_list);
@@ -721,9 +712,6 @@ static int __acpi_device_add(struct acpi_device *device,
                list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list);
        }
 
-       if (device->parent)
-               list_add_tail(&device->node, &device->parent->children);
-
        if (device->wakeup.flags.valid)
                list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list);
 
@@ -752,9 +740,6 @@ static int __acpi_device_add(struct acpi_device *device,
 err:
        mutex_lock(&acpi_device_lock);
 
-       if (device->parent)
-               list_del(&device->node);
-
        list_del(&device->wakeup_list);
 
 err_unlock:
@@ -2187,9 +2172,8 @@ static int acpi_scan_attach_handler(struct acpi_device *device)
        return ret;
 }
 
-static void acpi_bus_attach(struct acpi_device *device, bool first_pass)
+static int acpi_bus_attach(struct acpi_device *device, void *first_pass)
 {
-       struct acpi_device *child;
        bool skip = !first_pass && device->flags.visited;
        acpi_handle ejd;
        int ret;
@@ -2206,7 +2190,7 @@ static void acpi_bus_attach(struct acpi_device *device, bool first_pass)
                device->flags.initialized = false;
                acpi_device_clear_enumerated(device);
                device->flags.power_manageable = 0;
-               return;
+               return 0;
        }
        if (device->handler)
                goto ok;
@@ -2224,7 +2208,7 @@ static void acpi_bus_attach(struct acpi_device *device, bool first_pass)
 
        ret = acpi_scan_attach_handler(device);
        if (ret < 0)
-               return;
+               return 0;
 
        device->flags.match_driver = true;
        if (ret > 0 && !device->flags.enumeration_by_parent) {
@@ -2234,19 +2218,20 @@ static void acpi_bus_attach(struct acpi_device *device, bool first_pass)
 
        ret = device_attach(&device->dev);
        if (ret < 0)
-               return;
+               return 0;
 
        if (device->pnp.type.platform_id || device->flags.enumeration_by_parent)
                acpi_default_enumeration(device);
        else
                acpi_device_set_enumerated(device);
 
- ok:
-       list_for_each_entry(child, &device->children, node)
-               acpi_bus_attach(child, first_pass);
+ok:
+       acpi_dev_for_each_child(device, acpi_bus_attach, first_pass);
 
        if (!skip && device->handler && device->handler->hotplug.notify_online)
                device->handler->hotplug.notify_online(device);
+
+       return 0;
 }
 
 static int acpi_dev_get_first_consumer_dev_cb(struct acpi_dep_data *dep, void *data)
@@ -2274,7 +2259,7 @@ static void acpi_scan_clear_dep_fn(struct work_struct *work)
        cdw = container_of(work, struct acpi_scan_clear_dep_work, work);
 
        acpi_scan_lock_acquire();
-       acpi_bus_attach(cdw->adev, true);
+       acpi_bus_attach(cdw->adev, (void *)true);
        acpi_scan_lock_release();
 
        acpi_dev_put(cdw->adev);
@@ -2432,7 +2417,7 @@ int acpi_bus_scan(acpi_handle handle)
        if (!device)
                return -ENODEV;
 
-       acpi_bus_attach(device, true);
+       acpi_bus_attach(device, (void *)true);
 
        if (!acpi_bus_scan_second_pass)
                return 0;
@@ -2446,25 +2431,17 @@ int acpi_bus_scan(acpi_handle handle)
                                    acpi_bus_check_add_2, NULL, NULL,
                                    (void **)&device);
 
-       acpi_bus_attach(device, false);
+       acpi_bus_attach(device, NULL);
 
        return 0;
 }
 EXPORT_SYMBOL(acpi_bus_scan);
 
-/**
- * acpi_bus_trim - Detach scan handlers and drivers from ACPI device objects.
- * @adev: Root of the ACPI namespace scope to walk.
- *
- * Must be called under acpi_scan_lock.
- */
-void acpi_bus_trim(struct acpi_device *adev)
+static int acpi_bus_trim_one(struct acpi_device *adev, void *not_used)
 {
        struct acpi_scan_handler *handler = adev->handler;
-       struct acpi_device *child;
 
-       list_for_each_entry_reverse(child, &adev->children, node)
-               acpi_bus_trim(child);
+       acpi_dev_for_each_child_reverse(adev, acpi_bus_trim_one, NULL);
 
        adev->flags.match_driver = false;
        if (handler) {
@@ -2482,6 +2459,19 @@ void acpi_bus_trim(struct acpi_device *adev)
        acpi_device_set_power(adev, ACPI_STATE_D3_COLD);
        adev->flags.initialized = false;
        acpi_device_clear_enumerated(adev);
+
+       return 0;
+}
+
+/**
+ * acpi_bus_trim - Detach scan handlers and drivers from ACPI device objects.
+ * @adev: Root of the ACPI namespace scope to walk.
+ *
+ * Must be called under acpi_scan_lock.
+ */
+void acpi_bus_trim(struct acpi_device *adev)
+{
+       acpi_bus_trim_one(adev, NULL);
 }
 EXPORT_SYMBOL_GPL(acpi_bus_trim);
 
index 04ea156..ad4b298 100644 (file)
@@ -360,6 +360,14 @@ static const struct dmi_system_id acpisleep_dmi_table[] __initconst = {
                DMI_MATCH(DMI_PRODUCT_NAME, "80E3"),
                },
        },
+       {
+       .callback = init_nvs_save_s3,
+       .ident = "Lenovo G40-45",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "80E1"),
+               },
+       },
        /*
         * ThinkPad X1 Tablet(2016) cannot do suspend-to-idle using
         * the Low Power S0 Idle firmware interface (see
@@ -816,6 +824,9 @@ static const struct platform_s2idle_ops acpi_s2idle_ops = {
 
 void __weak acpi_s2idle_setup(void)
 {
+       if (acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)
+               pr_info("Efficient low-power S0 idle declared\n");
+
        s2idle_set_ops(&acpi_s2idle_ops);
 }
 
index becc198..5d7f380 100644 (file)
@@ -349,6 +349,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        },
        {
         .callback = video_detect_force_native,
+        /* Dell Inspiron N4010 */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron N4010"),
+               },
+       },
+       {
+        .callback = video_detect_force_native,
         /* Dell Vostro V131 */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
@@ -430,7 +438,6 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        .callback = video_detect_force_native,
        .ident = "Clevo NL5xRU",
        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
                DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"),
                },
        },
@@ -438,59 +445,75 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        .callback = video_detect_force_native,
        .ident = "Clevo NL5xRU",
        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"),
-               DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"),
+               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+               DMI_MATCH(DMI_BOARD_NAME, "AURA1501"),
                },
        },
        {
        .callback = video_detect_force_native,
        .ident = "Clevo NL5xRU",
        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Notebook"),
-               DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"),
+               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+               DMI_MATCH(DMI_BOARD_NAME, "EDUBOOK1502"),
                },
        },
        {
        .callback = video_detect_force_native,
-       .ident = "Clevo NL5xRU",
+       .ident = "Clevo NL5xNU",
        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
-               DMI_MATCH(DMI_BOARD_NAME, "AURA1501"),
+               DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"),
                },
        },
+       /*
+        * The TongFang PF5PU1G, PF4NU1F, PF5NU1G, and PF5LUXG/TUXEDO BA15 Gen10,
+        * Pulse 14/15 Gen1, and Pulse 15 Gen2 have the same problem as the Clevo
+        * NL5xRU and NL5xNU/TUXEDO Aura 15 Gen1 and Gen2. See the description
+        * above.
+        */
        {
        .callback = video_detect_force_native,
-       .ident = "Clevo NL5xRU",
+       .ident = "TongFang PF5PU1G",
        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
-               DMI_MATCH(DMI_BOARD_NAME, "EDUBOOK1502"),
+               DMI_MATCH(DMI_BOARD_NAME, "PF5PU1G"),
                },
        },
        {
        .callback = video_detect_force_native,
-       .ident = "Clevo NL5xNU",
+       .ident = "TongFang PF4NU1F",
+       .matches = {
+               DMI_MATCH(DMI_BOARD_NAME, "PF4NU1F"),
+               },
+       },
+       {
+       .callback = video_detect_force_native,
+       .ident = "TongFang PF4NU1F",
        .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
-               DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"),
+               DMI_MATCH(DMI_BOARD_NAME, "PULSE1401"),
                },
        },
        {
        .callback = video_detect_force_native,
-       .ident = "Clevo NL5xNU",
+       .ident = "TongFang PF5NU1G",
        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"),
-               DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"),
+               DMI_MATCH(DMI_BOARD_NAME, "PF5NU1G"),
                },
        },
        {
        .callback = video_detect_force_native,
-       .ident = "Clevo NL5xNU",
+       .ident = "TongFang PF5NU1G",
        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Notebook"),
-               DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"),
+               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+               DMI_MATCH(DMI_BOARD_NAME, "PULSE1501"),
+               },
+       },
+       {
+       .callback = video_detect_force_native,
+       .ident = "TongFang PF5LUXG",
+       .matches = {
+               DMI_MATCH(DMI_BOARD_NAME, "PF5LUXG"),
                },
        },
-
        /*
         * Desktops which falsely report a backlight and which our heuristics
         * for this do not catch.
index d225632..647f11c 100644 (file)
@@ -249,6 +249,26 @@ err_free:
 }
 
 /**
+ * acpi_viot_early_init - Test the presence of VIOT and enable ACS
+ *
+ * If the VIOT does exist, ACS must be enabled. This cannot be
+ * done in acpi_viot_init() which is called after the bus scan
+ */
+void __init acpi_viot_early_init(void)
+{
+#ifdef CONFIG_PCI
+       acpi_status status;
+       struct acpi_table_header *hdr;
+
+       status = acpi_get_table(ACPI_SIG_VIOT, 0, &hdr);
+       if (ACPI_FAILURE(status))
+               return;
+       pci_request_acs();
+       acpi_put_table(hdr);
+#endif
+}
+
+/**
  * acpi_viot_init - Parse the VIOT table
  *
  * Parse the VIOT table, prepare the list of endpoints to be used during DMA
@@ -319,12 +339,6 @@ static int viot_pci_dev_iommu_init(struct pci_dev *pdev, u16 dev_id, void *data)
                        epid = ((domain_nr - ep->segment_start) << 16) +
                                dev_id - ep->bdf_start + ep->endpoint_id;
 
-                       /*
-                        * If we found a PCI range managed by the viommu, we're
-                        * the one that has to request ACS.
-                        */
-                       pci_request_acs();
-
                        return viot_dev_iommu_init(&pdev->dev, ep->viommu,
                                                   epid);
                }
index 2963229..f9ac12b 100644 (file)
@@ -369,9 +369,6 @@ static int lps0_device_attach(struct acpi_device *adev,
        if (lps0_device_handle)
                return 0;
 
-       if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0))
-               return 0;
-
        if (acpi_s2idle_vendor_amd()) {
                /* AMD0004, AMD0005, AMDI0005:
                 * - Should use rev_id 0x0
@@ -397,7 +394,9 @@ static int lps0_device_attach(struct acpi_device *adev,
                        lps0_dsm_func_mask = (lps0_dsm_func_mask << 1) | 0x1;
                        acpi_handle_debug(adev->handle, "_DSM UUID %s: Adjusted function mask: 0x%x\n",
                                          ACPI_LPS0_DSM_UUID_AMD, lps0_dsm_func_mask);
-               } else if (lps0_dsm_func_mask_microsoft > 0 && !strcmp(hid, "AMDI0007")) {
+               } else if (lps0_dsm_func_mask_microsoft > 0 &&
+                               (!strcmp(hid, "AMDI0007") ||
+                                !strcmp(hid, "AMDI0008"))) {
                        lps0_dsm_func_mask_microsoft = -EINVAL;
                        acpi_handle_debug(adev->handle, "_DSM Using AMD method\n");
                }
@@ -419,11 +418,15 @@ static int lps0_device_attach(struct acpi_device *adev,
                lpi_device_get_constraints();
 
        /*
-        * Use suspend-to-idle by default if the default suspend mode was not
-        * set from the command line.
+        * Use suspend-to-idle by default if ACPI_FADT_LOW_POWER_S0 is set in
+        * the FADT and the default suspend mode was not set from the command
+        * line.
         */
-       if (mem_sleep_default > PM_SUSPEND_MEM && !acpi_sleep_default_s3)
+       if ((acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0) &&
+           mem_sleep_default > PM_SUSPEND_MEM && !acpi_sleep_default_s3) {
                mem_sleep_current = PM_SUSPEND_TO_IDLE;
+               pr_info("Low-power S0 idle used by default for system suspend\n");
+       }
 
        /*
         * Some LPS0 systems, like ASUS Zenbook UX430UNR/i7-8550U, require the
index 0e3ed5e..0cb2032 100644 (file)
@@ -493,13 +493,8 @@ static int amba_device_try_add(struct amba_device *dev, struct resource *parent)
                goto skip_probe;
 
        ret = amba_read_periphid(dev);
-       if (ret) {
-               if (ret != -EPROBE_DEFER) {
-                       amba_device_put(dev);
-                       goto err_out;
-               }
+       if (ret)
                goto err_release;
-       }
 
 skip_probe:
        ret = device_add(&dev->dev);
@@ -546,6 +541,7 @@ static int amba_deferred_retry(void)
                        continue;
 
                list_del_init(&ddev->node);
+               amba_device_put(ddev->dev);
                kfree(ddev);
        }
 
index bb45a9c..1c9f4fb 100644 (file)
@@ -148,7 +148,7 @@ config SATA_AHCI_PLATFORM
 config AHCI_BRCM
        tristate "Broadcom AHCI SATA support"
        depends on ARCH_BRCMSTB || BMIPS_GENERIC || ARCH_BCM_NSP || \
-                  ARCH_BCM_63XX || COMPILE_TEST
+                  ARCH_BCMBCA || COMPILE_TEST
        select SATA_HOST
        help
          This option enables support for the AHCI SATA3 controller found on
index 6725931..c2c3238 100644 (file)
@@ -90,7 +90,7 @@ static void cs5535_set_piomode(struct ata_port *ap, struct ata_device *adev)
        static const u16 pio_cmd_timings[5] = {
                0xF7F4, 0x53F3, 0x13F1, 0x5131, 0x1131
        };
-       u32 reg, dummy;
+       u32 reg, __maybe_unused dummy;
        struct ata_device *pair = ata_dev_pair(adev);
 
        int mode = adev->pio_mode - XFER_PIO_0;
@@ -129,7 +129,7 @@ static void cs5535_set_dmamode(struct ata_port *ap, struct ata_device *adev)
        static const u32 mwdma_timings[3] = {
                0x7F0FFFF3, 0x7F035352, 0x7F024241
        };
-       u32 reg, dummy;
+       u32 reg, __maybe_unused dummy;
        int mode = adev->dma_mode;
 
        rdmsr(ATAC_CH0D0_DMA + 2 * adev->devno, reg, dummy);
index 7cd789c..460d6f1 100644 (file)
@@ -486,7 +486,18 @@ static void device_link_release_fn(struct work_struct *work)
        /* Ensure that all references to the link object have been dropped. */
        device_link_synchronize_removal();
 
-       pm_runtime_release_supplier(link, true);
+       pm_runtime_release_supplier(link);
+       /*
+        * If supplier_preactivated is set, the link has been dropped between
+        * the pm_runtime_get_suppliers() and pm_runtime_put_suppliers() calls
+        * in __driver_probe_device().  In that case, drop the supplier's
+        * PM-runtime usage counter to remove the reference taken by
+        * pm_runtime_get_suppliers().
+        */
+       if (link->supplier_preactivated)
+               pm_runtime_put_noidle(link->supplier);
+
+       pm_request_idle(link->supplier);
 
        put_device(link->consumer);
        put_device(link->supplier);
index a97776e..4c98849 100644 (file)
@@ -570,6 +570,12 @@ ssize_t __weak cpu_show_mmio_stale_data(struct device *dev,
        return sysfs_emit(buf, "Not affected\n");
 }
 
+ssize_t __weak cpu_show_retbleed(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       return sysfs_emit(buf, "Not affected\n");
+}
+
 static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL);
 static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL);
 static DEVICE_ATTR(spectre_v2, 0444, cpu_show_spectre_v2, NULL);
@@ -580,6 +586,7 @@ static DEVICE_ATTR(tsx_async_abort, 0444, cpu_show_tsx_async_abort, NULL);
 static DEVICE_ATTR(itlb_multihit, 0444, cpu_show_itlb_multihit, NULL);
 static DEVICE_ATTR(srbds, 0444, cpu_show_srbds, NULL);
 static DEVICE_ATTR(mmio_stale_data, 0444, cpu_show_mmio_stale_data, NULL);
+static DEVICE_ATTR(retbleed, 0444, cpu_show_retbleed, NULL);
 
 static struct attribute *cpu_root_vulnerabilities_attrs[] = {
        &dev_attr_meltdown.attr,
@@ -592,6 +599,7 @@ static struct attribute *cpu_root_vulnerabilities_attrs[] = {
        &dev_attr_itlb_multihit.attr,
        &dev_attr_srbds.attr,
        &dev_attr_mmio_stale_data.attr,
+       &dev_attr_retbleed.attr,
        NULL
 };
 
index 084d67f..bc60c9c 100644 (file)
@@ -558,7 +558,7 @@ static ssize_t hard_offline_page_store(struct device *dev,
        if (kstrtoull(buf, 0, &pfn) < 0)
                return -EINVAL;
        pfn >>= PAGE_SHIFT;
-       ret = memory_failure(pfn, 0);
+       ret = memory_failure(pfn, MF_SW_SIMULATED);
        if (ret == -EOPNOTSUPP)
                ret = 0;
        return ret ? ret : count;
index 739e52c..55a10e6 100644 (file)
@@ -222,6 +222,9 @@ static void genpd_debug_remove(struct generic_pm_domain *genpd)
 {
        struct dentry *d;
 
+       if (!genpd_debugfs_dir)
+               return;
+
        d = debugfs_lookup(genpd->name, genpd_debugfs_dir);
        debugfs_remove(d);
 }
index 676dc72..997be3a 100644 (file)
@@ -308,13 +308,10 @@ static int rpm_get_suppliers(struct device *dev)
 /**
  * pm_runtime_release_supplier - Drop references to device link's supplier.
  * @link: Target device link.
- * @check_idle: Whether or not to check if the supplier device is idle.
  *
- * Drop all runtime PM references associated with @link to its supplier device
- * and if @check_idle is set, check if that device is idle (and so it can be
- * suspended).
+ * Drop all runtime PM references associated with @link to its supplier device.
  */
-void pm_runtime_release_supplier(struct device_link *link, bool check_idle)
+void pm_runtime_release_supplier(struct device_link *link)
 {
        struct device *supplier = link->supplier;
 
@@ -327,9 +324,6 @@ void pm_runtime_release_supplier(struct device_link *link, bool check_idle)
        while (refcount_dec_not_one(&link->rpm_active) &&
               atomic_read(&supplier->power.usage_count) > 0)
                pm_runtime_put_noidle(supplier);
-
-       if (check_idle)
-               pm_request_idle(supplier);
 }
 
 static void __rpm_put_suppliers(struct device *dev, bool try_to_suspend)
@@ -337,8 +331,11 @@ static void __rpm_put_suppliers(struct device *dev, bool try_to_suspend)
        struct device_link *link;
 
        list_for_each_entry_rcu(link, &dev->links.suppliers, c_node,
-                               device_links_read_lock_held())
-               pm_runtime_release_supplier(link, try_to_suspend);
+                               device_links_read_lock_held()) {
+               pm_runtime_release_supplier(link);
+               if (try_to_suspend)
+                       pm_request_idle(link->supplier);
+       }
 }
 
 static void rpm_put_suppliers(struct device *dev)
@@ -1771,7 +1768,6 @@ void pm_runtime_get_suppliers(struct device *dev)
                if (link->flags & DL_FLAG_PM_RUNTIME) {
                        link->supplier_preactivated = true;
                        pm_runtime_get_sync(link->supplier);
-                       refcount_inc(&link->rpm_active);
                }
 
        device_links_read_unlock(idx);
@@ -1791,19 +1787,8 @@ void pm_runtime_put_suppliers(struct device *dev)
        list_for_each_entry_rcu(link, &dev->links.suppliers, c_node,
                                device_links_read_lock_held())
                if (link->supplier_preactivated) {
-                       bool put;
-
                        link->supplier_preactivated = false;
-
-                       spin_lock_irq(&dev->power.lock);
-
-                       put = pm_runtime_status_suspended(dev) &&
-                             refcount_dec_not_one(&link->rpm_active);
-
-                       spin_unlock_irq(&dev->power.lock);
-
-                       if (put)
-                               pm_runtime_put(link->supplier);
+                       pm_runtime_put(link->supplier);
                }
 
        device_links_read_unlock(idx);
@@ -1838,7 +1823,8 @@ void pm_runtime_drop_link(struct device_link *link)
                return;
 
        pm_runtime_drop_link_count(link->consumer);
-       pm_runtime_release_supplier(link, true);
+       pm_runtime_release_supplier(link);
+       pm_request_idle(link->supplier);
 }
 
 static bool pm_runtime_need_not_resume(struct device *dev)
@@ -1876,10 +1862,13 @@ int pm_runtime_force_suspend(struct device *dev)
 
        callback = RPM_GET_CALLBACK(dev, runtime_suspend);
 
+       dev_pm_enable_wake_irq_check(dev, true);
        ret = callback ? callback(dev) : 0;
        if (ret)
                goto err;
 
+       dev_pm_enable_wake_irq_complete(dev);
+
        /*
         * If the device can stay in suspend after the system-wide transition
         * to the working state that will follow, drop the children counter of
@@ -1896,6 +1885,7 @@ int pm_runtime_force_suspend(struct device *dev)
        return 0;
 
 err:
+       dev_pm_disable_wake_irq_check(dev, true);
        pm_runtime_enable(dev);
        return ret;
 }
@@ -1929,9 +1919,11 @@ int pm_runtime_force_resume(struct device *dev)
 
        callback = RPM_GET_CALLBACK(dev, runtime_resume);
 
+       dev_pm_disable_wake_irq_check(dev, false);
        ret = callback ? callback(dev) : 0;
        if (ret) {
                pm_runtime_set_suspended(dev);
+               dev_pm_enable_wake_irq_check(dev, false);
                goto out;
        }
 
index 11a4ffe..e3befa2 100644 (file)
@@ -501,36 +501,6 @@ void device_set_wakeup_capable(struct device *dev, bool capable)
 EXPORT_SYMBOL_GPL(device_set_wakeup_capable);
 
 /**
- * device_init_wakeup - Device wakeup initialization.
- * @dev: Device to handle.
- * @enable: Whether or not to enable @dev as a wakeup device.
- *
- * By default, most devices should leave wakeup disabled.  The exceptions are
- * devices that everyone expects to be wakeup sources: keyboards, power buttons,
- * possibly network interfaces, etc.  Also, devices that don't generate their
- * own wakeup requests but merely forward requests from one bus to another
- * (like PCI bridges) should have wakeup enabled by default.
- */
-int device_init_wakeup(struct device *dev, bool enable)
-{
-       int ret = 0;
-
-       if (!dev)
-               return -EINVAL;
-
-       if (enable) {
-               device_set_wakeup_capable(dev, true);
-               ret = device_wakeup_enable(dev);
-       } else {
-               device_wakeup_disable(dev);
-               device_set_wakeup_capable(dev, false);
-       }
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(device_init_wakeup);
-
-/**
  * device_set_wakeup_enable - Enable or disable a device to wake up the system.
  * @dev: Device to handle.
  * @enable: enable/disable flag
index d0f5bc8..362e043 100644 (file)
@@ -133,6 +133,12 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
                return -EINVAL;
        }
 
+       if (config->num_reg_defaults && !config->reg_defaults) {
+               dev_err(map->dev,
+                       "Register defaults number are set without the reg!\n");
+               return -EINVAL;
+       }
+
        for (i = 0; i < config->num_reg_defaults; i++)
                if (config->reg_defaults[i].reg % map->reg_stride)
                        return -EINVAL;
@@ -495,7 +501,8 @@ EXPORT_SYMBOL_GPL(regcache_drop_region);
 void regcache_cache_only(struct regmap *map, bool enable)
 {
        map->lock(map->lock_arg);
-       WARN_ON(map->cache_bypass && enable);
+       WARN_ON(map->cache_type != REGCACHE_NONE &&
+               map->cache_bypass && enable);
        map->cache_only = enable;
        trace_regmap_cache_only(map, enable);
        map->unlock(map->lock_arg);
@@ -531,7 +538,7 @@ EXPORT_SYMBOL_GPL(regcache_mark_dirty);
  * @enable: flag if changes should not be written to the cache
  *
  * When a register map is marked with the cache bypass option, writes
- * to the register map API will only update the hardware and not the
+ * to the register map API will only update the hardware and not
  * the cache directly.  This is useful when syncing the cache back to
  * the hardware.
  */
index a6db605..4ef9488 100644 (file)
@@ -30,6 +30,9 @@ struct regmap_irq_chip_data {
        int irq;
        int wake_count;
 
+       unsigned int mask_base;
+       unsigned int unmask_base;
+
        void *status_reg_buf;
        unsigned int *main_status_buf;
        unsigned int *status_buf;
@@ -39,33 +42,15 @@ struct regmap_irq_chip_data {
        unsigned int *type_buf;
        unsigned int *type_buf_def;
        unsigned int **virt_buf;
+       unsigned int **config_buf;
 
        unsigned int irq_reg_stride;
-       unsigned int type_reg_stride;
 
-       bool clear_status:1;
-};
+       unsigned int (*get_irq_reg)(struct regmap_irq_chip_data *data,
+                                   unsigned int base, int index);
 
-static int sub_irq_reg(struct regmap_irq_chip_data *data,
-                      unsigned int base_reg, int i)
-{
-       const struct regmap_irq_chip *chip = data->chip;
-       struct regmap *map = data->map;
-       struct regmap_irq_sub_irq_map *subreg;
-       unsigned int offset;
-       int reg = 0;
-
-       if (!chip->sub_reg_offsets || !chip->not_fixed_stride) {
-               /* Assume linear mapping */
-               reg = base_reg + (i * map->reg_stride * data->irq_reg_stride);
-       } else {
-               subreg = &chip->sub_reg_offsets[i];
-               offset = subreg->offset[0];
-               reg = base_reg + offset;
-       }
-
-       return reg;
-}
+       unsigned int clear_status:1;
+};
 
 static inline const
 struct regmap_irq *irq_to_regmap_irq(struct regmap_irq_chip_data *data,
@@ -74,21 +59,25 @@ struct regmap_irq *irq_to_regmap_irq(struct regmap_irq_chip_data *data,
        return &data->chip->irqs[irq];
 }
 
-static void regmap_irq_lock(struct irq_data *data)
+static bool regmap_irq_can_bulk_read_status(struct regmap_irq_chip_data *data)
 {
-       struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
+       struct regmap *map = data->map;
 
-       mutex_lock(&d->lock);
+       /*
+        * While possible that a user-defined ->get_irq_reg() callback might
+        * be linear enough to support bulk reads, most of the time it won't.
+        * Therefore only allow them if the default callback is being used.
+        */
+       return data->irq_reg_stride == 1 && map->reg_stride == 1 &&
+              data->get_irq_reg == regmap_irq_get_irq_reg_linear &&
+              !map->use_single_read;
 }
 
-static int regmap_irq_update_bits(struct regmap_irq_chip_data *d,
-                                 unsigned int reg, unsigned int mask,
-                                 unsigned int val)
+static void regmap_irq_lock(struct irq_data *data)
 {
-       if (d->chip->mask_writeonly)
-               return regmap_write_bits(d->map, reg, mask, val);
-       else
-               return regmap_update_bits(d->map, reg, mask, val);
+       struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
+
+       mutex_lock(&d->lock);
 }
 
 static void regmap_irq_sync_unlock(struct irq_data *data)
@@ -97,7 +86,6 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
        struct regmap *map = d->map;
        int i, j, ret;
        u32 reg;
-       u32 unmask_offset;
        u32 val;
 
        if (d->chip->runtime_pm) {
@@ -109,7 +97,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
 
        if (d->clear_status) {
                for (i = 0; i < d->chip->num_regs; i++) {
-                       reg = sub_irq_reg(d, d->chip->status_base, i);
+                       reg = d->get_irq_reg(d, d->chip->status_base, i);
 
                        ret = regmap_read(map, reg, &val);
                        if (ret)
@@ -126,44 +114,32 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
         * suppress pointless writes.
         */
        for (i = 0; i < d->chip->num_regs; i++) {
-               if (!d->chip->mask_base)
-                       continue;
+               if (d->mask_base) {
+                       reg = d->get_irq_reg(d, d->mask_base, i);
+                       ret = regmap_update_bits(d->map, reg,
+                                       d->mask_buf_def[i], d->mask_buf[i]);
+                       if (ret)
+                               dev_err(d->map->dev, "Failed to sync masks in %x\n",
+                                       reg);
+               }
 
-               reg = sub_irq_reg(d, d->chip->mask_base, i);
-               if (d->chip->mask_invert) {
-                       ret = regmap_irq_update_bits(d, reg,
-                                        d->mask_buf_def[i], ~d->mask_buf[i]);
-               } else if (d->chip->unmask_base) {
-                       /* set mask with mask_base register */
-                       ret = regmap_irq_update_bits(d, reg,
+               if (d->unmask_base) {
+                       reg = d->get_irq_reg(d, d->unmask_base, i);
+                       ret = regmap_update_bits(d->map, reg,
                                        d->mask_buf_def[i], ~d->mask_buf[i]);
-                       if (ret < 0)
-                               dev_err(d->map->dev,
-                                       "Failed to sync unmasks in %x\n",
+                       if (ret)
+                               dev_err(d->map->dev, "Failed to sync masks in %x\n",
                                        reg);
-                       unmask_offset = d->chip->unmask_base -
-                                                       d->chip->mask_base;
-                       /* clear mask with unmask_base register */
-                       ret = regmap_irq_update_bits(d,
-                                       reg + unmask_offset,
-                                       d->mask_buf_def[i],
-                                       d->mask_buf[i]);
-               } else {
-                       ret = regmap_irq_update_bits(d, reg,
-                                        d->mask_buf_def[i], d->mask_buf[i]);
                }
-               if (ret != 0)
-                       dev_err(d->map->dev, "Failed to sync masks in %x\n",
-                               reg);
 
-               reg = sub_irq_reg(d, d->chip->wake_base, i);
+               reg = d->get_irq_reg(d, d->chip->wake_base, i);
                if (d->wake_buf) {
                        if (d->chip->wake_invert)
-                               ret = regmap_irq_update_bits(d, reg,
+                               ret = regmap_update_bits(d->map, reg,
                                                         d->mask_buf_def[i],
                                                         ~d->wake_buf[i]);
                        else
-                               ret = regmap_irq_update_bits(d, reg,
+                               ret = regmap_update_bits(d->map, reg,
                                                         d->mask_buf_def[i],
                                                         d->wake_buf[i]);
                        if (ret != 0)
@@ -180,7 +156,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
                 * it'll be ignored in irq handler, then may introduce irq storm
                 */
                if (d->mask_buf[i] && (d->chip->ack_base || d->chip->use_ack)) {
-                       reg = sub_irq_reg(d, d->chip->ack_base, i);
+                       reg = d->get_irq_reg(d, d->chip->ack_base, i);
 
                        /* some chips ack by write 0 */
                        if (d->chip->ack_invert)
@@ -204,12 +180,12 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
                for (i = 0; i < d->chip->num_type_reg; i++) {
                        if (!d->type_buf_def[i])
                                continue;
-                       reg = sub_irq_reg(d, d->chip->type_base, i);
+                       reg = d->get_irq_reg(d, d->chip->type_base, i);
                        if (d->chip->type_invert)
-                               ret = regmap_irq_update_bits(d, reg,
+                               ret = regmap_update_bits(d->map, reg,
                                        d->type_buf_def[i], ~d->type_buf[i]);
                        else
-                               ret = regmap_irq_update_bits(d, reg,
+                               ret = regmap_update_bits(d->map, reg,
                                        d->type_buf_def[i], d->type_buf[i]);
                        if (ret != 0)
                                dev_err(d->map->dev, "Failed to sync type in %x\n",
@@ -220,8 +196,8 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
        if (d->chip->num_virt_regs) {
                for (i = 0; i < d->chip->num_virt_regs; i++) {
                        for (j = 0; j < d->chip->num_regs; j++) {
-                               reg = sub_irq_reg(d, d->chip->virt_reg_base[i],
-                                                 j);
+                               reg = d->get_irq_reg(d, d->chip->virt_reg_base[i],
+                                                    j);
                                ret = regmap_write(map, reg, d->virt_buf[i][j]);
                                if (ret != 0)
                                        dev_err(d->map->dev,
@@ -231,6 +207,17 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
                }
        }
 
+       for (i = 0; i < d->chip->num_config_bases; i++) {
+               for (j = 0; j < d->chip->num_config_regs; j++) {
+                       reg = d->get_irq_reg(d, d->chip->config_base[i], j);
+                       ret = regmap_write(map, reg, d->config_buf[i][j]);
+                       if (ret)
+                               dev_err(d->map->dev,
+                                       "Failed to write config %x: %d\n",
+                                       reg, ret);
+               }
+       }
+
        if (d->chip->runtime_pm)
                pm_runtime_put(map->dev);
 
@@ -253,22 +240,19 @@ static void regmap_irq_enable(struct irq_data *data)
        struct regmap *map = d->map;
        const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
        unsigned int reg = irq_data->reg_offset / map->reg_stride;
-       unsigned int mask, type;
-
-       type = irq_data->type.type_falling_val | irq_data->type.type_rising_val;
+       unsigned int mask;
 
        /*
         * The type_in_mask flag means that the underlying hardware uses
-        * separate mask bits for rising and falling edge interrupts, but
-        * we want to make them into a single virtual interrupt with
-        * configurable edge.
+        * separate mask bits for each interrupt trigger type, but we want
+        * to have a single logical interrupt with a configurable type.
         *
-        * If the interrupt we're enabling defines the falling or rising
-        * masks then instead of using the regular mask bits for this
-        * interrupt, use the value previously written to the type buffer
-        * at the corresponding offset in regmap_irq_set_type().
+        * If the interrupt we're enabling defines any supported types
+        * then instead of using the regular mask bits for this interrupt,
+        * use the value previously written to the type buffer at the
+        * corresponding offset in regmap_irq_set_type().
         */
-       if (d->chip->type_in_mask && type)
+       if (d->chip->type_in_mask && irq_data->type.types_supported)
                mask = d->type_buf[reg] & irq_data->mask;
        else
                mask = irq_data->mask;
@@ -293,7 +277,7 @@ static int regmap_irq_set_type(struct irq_data *data, unsigned int type)
        struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
        struct regmap *map = d->map;
        const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
-       int reg;
+       int reg, ret;
        const struct regmap_irq_type *t = &irq_data->type;
 
        if ((t->types_supported & type) != type)
@@ -333,9 +317,19 @@ static int regmap_irq_set_type(struct irq_data *data, unsigned int type)
                return -EINVAL;
        }
 
-       if (d->chip->set_type_virt)
-               return d->chip->set_type_virt(d->virt_buf, type, data->hwirq,
-                                             reg);
+       if (d->chip->set_type_virt) {
+               ret = d->chip->set_type_virt(d->virt_buf, type, data->hwirq,
+                                            reg);
+               if (ret)
+                       return ret;
+       }
+
+       if (d->chip->set_type_config) {
+               ret = d->chip->set_type_config(d->config_buf, type,
+                                              irq_data, reg);
+               if (ret)
+                       return ret;
+       }
 
        return 0;
 }
@@ -376,14 +370,17 @@ static inline int read_sub_irq_data(struct regmap_irq_chip_data *data,
        const struct regmap_irq_chip *chip = data->chip;
        struct regmap *map = data->map;
        struct regmap_irq_sub_irq_map *subreg;
+       unsigned int reg;
        int i, ret = 0;
 
        if (!chip->sub_reg_offsets) {
-               /* Assume linear mapping */
-               ret = regmap_read(map, chip->status_base +
-                                 (b * map->reg_stride * data->irq_reg_stride),
-                                  &data->status_buf[b]);
+               reg = data->get_irq_reg(data, chip->status_base, b);
+               ret = regmap_read(map, reg, &data->status_buf[b]);
        } else {
+               /*
+                * Note we can't use ->get_irq_reg() here because the offsets
+                * in 'subreg' are *not* interchangeable with indices.
+                */
                subreg = &chip->sub_reg_offsets[b];
                for (i = 0; i < subreg->num_regs; i++) {
                        unsigned int offset = subreg->offset[i];
@@ -449,10 +446,18 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
                 * sake of simplicity. and add bulk reads only if needed
                 */
                for (i = 0; i < chip->num_main_regs; i++) {
-                       ret = regmap_read(map, chip->main_status +
-                                 (i * map->reg_stride
-                                  * data->irq_reg_stride),
-                                 &data->main_status_buf[i]);
+                       /*
+                        * For not_fixed_stride, don't use ->get_irq_reg().
+                        * It would produce an incorrect result.
+                        */
+                       if (data->chip->not_fixed_stride)
+                               reg = chip->main_status +
+                                       i * map->reg_stride * data->irq_reg_stride;
+                       else
+                               reg = data->get_irq_reg(data,
+                                                       chip->main_status, i);
+
+                       ret = regmap_read(map, reg, &data->main_status_buf[i]);
                        if (ret) {
                                dev_err(map->dev,
                                        "Failed to read IRQ status %d\n",
@@ -481,8 +486,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
                        }
 
                }
-       } else if (!map->use_single_read && map->reg_stride == 1 &&
-                  data->irq_reg_stride == 1) {
+       } else if (regmap_irq_can_bulk_read_status(data)) {
 
                u8 *buf8 = data->status_reg_buf;
                u16 *buf16 = data->status_reg_buf;
@@ -518,7 +522,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
 
        } else {
                for (i = 0; i < data->chip->num_regs; i++) {
-                       unsigned int reg = sub_irq_reg(data,
+                       unsigned int reg = data->get_irq_reg(data,
                                        data->chip->status_base, i);
                        ret = regmap_read(map, reg, &data->status_buf[i]);
 
@@ -546,7 +550,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
                data->status_buf[i] &= ~data->mask_buf[i];
 
                if (data->status_buf[i] && (chip->ack_base || chip->use_ack)) {
-                       reg = sub_irq_reg(data, data->chip->ack_base, i);
+                       reg = data->get_irq_reg(data, data->chip->ack_base, i);
 
                        if (chip->ack_invert)
                                ret = regmap_write(map, reg,
@@ -607,6 +611,91 @@ static const struct irq_domain_ops regmap_domain_ops = {
 };
 
 /**
+ * regmap_irq_get_irq_reg_linear() - Linear IRQ register mapping callback.
+ * @data: Data for the &struct regmap_irq_chip
+ * @base: Base register
+ * @index: Register index
+ *
+ * Returns the register address corresponding to the given @base and @index
+ * by the formula ``base + index * regmap_stride * irq_reg_stride``.
+ */
+unsigned int regmap_irq_get_irq_reg_linear(struct regmap_irq_chip_data *data,
+                                          unsigned int base, int index)
+{
+       const struct regmap_irq_chip *chip = data->chip;
+       struct regmap *map = data->map;
+
+       /*
+        * FIXME: This is for backward compatibility and should be removed
+        * when not_fixed_stride is dropped (it's only used by qcom-pm8008).
+        */
+       if (chip->not_fixed_stride && chip->sub_reg_offsets) {
+               struct regmap_irq_sub_irq_map *subreg;
+
+               subreg = &chip->sub_reg_offsets[0];
+               return base + subreg->offset[0];
+       }
+
+       return base + index * map->reg_stride * data->irq_reg_stride;
+}
+EXPORT_SYMBOL_GPL(regmap_irq_get_irq_reg_linear);
+
+/**
+ * regmap_irq_set_type_config_simple() - Simple IRQ type configuration callback.
+ * @buf: Buffer containing configuration register values, this is a 2D array of
+ *       `num_config_bases` rows, each of `num_config_regs` elements.
+ * @type: The requested IRQ type.
+ * @irq_data: The IRQ being configured.
+ * @idx: Index of the irq's config registers within each array `buf[i]`
+ *
+ * This is a &struct regmap_irq_chip->set_type_config callback suitable for
+ * chips with one config register. Register values are updated according to
+ * the &struct regmap_irq_type data associated with an IRQ.
+ */
+int regmap_irq_set_type_config_simple(unsigned int **buf, unsigned int type,
+                                     const struct regmap_irq *irq_data, int idx)
+{
+       const struct regmap_irq_type *t = &irq_data->type;
+
+       if (t->type_reg_mask)
+               buf[0][idx] &= ~t->type_reg_mask;
+       else
+               buf[0][idx] &= ~(t->type_falling_val |
+                                t->type_rising_val |
+                                t->type_level_low_val |
+                                t->type_level_high_val);
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_FALLING:
+               buf[0][idx] |= t->type_falling_val;
+               break;
+
+       case IRQ_TYPE_EDGE_RISING:
+               buf[0][idx] |= t->type_rising_val;
+               break;
+
+       case IRQ_TYPE_EDGE_BOTH:
+               buf[0][idx] |= (t->type_falling_val |
+                               t->type_rising_val);
+               break;
+
+       case IRQ_TYPE_LEVEL_HIGH:
+               buf[0][idx] |= t->type_level_high_val;
+               break;
+
+       case IRQ_TYPE_LEVEL_LOW:
+               buf[0][idx] |= t->type_level_low_val;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(regmap_irq_set_type_config_simple);
+
+/**
  * regmap_add_irq_chip_fwnode() - Use standard regmap IRQ controller handling
  *
  * @fwnode: The firmware node where the IRQ domain should be added to.
@@ -634,7 +723,6 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
        int ret = -ENOMEM;
        int num_type_reg;
        u32 reg;
-       u32 unmask_offset;
 
        if (chip->num_regs <= 0)
                return -EINVAL;
@@ -651,11 +739,19 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
        }
 
        if (chip->not_fixed_stride) {
+               dev_warn(map->dev, "not_fixed_stride is deprecated; use ->get_irq_reg() instead");
+
                for (i = 0; i < chip->num_regs; i++)
                        if (chip->sub_reg_offsets[i].num_regs != 1)
                                return -EINVAL;
        }
 
+       if (chip->num_type_reg)
+               dev_warn(map->dev, "type registers are deprecated; use config registers instead");
+
+       if (chip->num_virt_regs || chip->virt_reg_base || chip->set_type_virt)
+               dev_warn(map->dev, "virtual registers are deprecated; use config registers instead");
+
        if (irq_base) {
                irq_base = irq_alloc_descs(irq_base, 0, chip->num_irqs, 0);
                if (irq_base < 0) {
@@ -671,30 +767,30 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
 
        if (chip->num_main_regs) {
                d->main_status_buf = kcalloc(chip->num_main_regs,
-                                            sizeof(unsigned int),
+                                            sizeof(*d->main_status_buf),
                                             GFP_KERNEL);
 
                if (!d->main_status_buf)
                        goto err_alloc;
        }
 
-       d->status_buf = kcalloc(chip->num_regs, sizeof(unsigned int),
+       d->status_buf = kcalloc(chip->num_regs, sizeof(*d->status_buf),
                                GFP_KERNEL);
        if (!d->status_buf)
                goto err_alloc;
 
-       d->mask_buf = kcalloc(chip->num_regs, sizeof(unsigned int),
+       d->mask_buf = kcalloc(chip->num_regs, sizeof(*d->mask_buf),
                              GFP_KERNEL);
        if (!d->mask_buf)
                goto err_alloc;
 
-       d->mask_buf_def = kcalloc(chip->num_regs, sizeof(unsigned int),
+       d->mask_buf_def = kcalloc(chip->num_regs, sizeof(*d->mask_buf_def),
                                  GFP_KERNEL);
        if (!d->mask_buf_def)
                goto err_alloc;
 
        if (chip->wake_base) {
-               d->wake_buf = kcalloc(chip->num_regs, sizeof(unsigned int),
+               d->wake_buf = kcalloc(chip->num_regs, sizeof(*d->wake_buf),
                                      GFP_KERNEL);
                if (!d->wake_buf)
                        goto err_alloc;
@@ -703,11 +799,11 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
        num_type_reg = chip->type_in_mask ? chip->num_regs : chip->num_type_reg;
        if (num_type_reg) {
                d->type_buf_def = kcalloc(num_type_reg,
-                                         sizeof(unsigned int), GFP_KERNEL);
+                                         sizeof(*d->type_buf_def), GFP_KERNEL);
                if (!d->type_buf_def)
                        goto err_alloc;
 
-               d->type_buf = kcalloc(num_type_reg, sizeof(unsigned int),
+               d->type_buf = kcalloc(num_type_reg, sizeof(*d->type_buf),
                                      GFP_KERNEL);
                if (!d->type_buf)
                        goto err_alloc;
@@ -724,13 +820,31 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
 
                for (i = 0; i < chip->num_virt_regs; i++) {
                        d->virt_buf[i] = kcalloc(chip->num_regs,
-                                                sizeof(unsigned int),
+                                                sizeof(**d->virt_buf),
                                                 GFP_KERNEL);
                        if (!d->virt_buf[i])
                                goto err_alloc;
                }
        }
 
+       if (chip->num_config_bases && chip->num_config_regs) {
+               /*
+                * Create config_buf[num_config_bases][num_config_regs]
+                */
+               d->config_buf = kcalloc(chip->num_config_bases,
+                                       sizeof(*d->config_buf), GFP_KERNEL);
+               if (!d->config_buf)
+                       goto err_alloc;
+
+               for (i = 0; i < chip->num_config_regs; i++) {
+                       d->config_buf[i] = kcalloc(chip->num_config_regs,
+                                                  sizeof(**d->config_buf),
+                                                  GFP_KERNEL);
+                       if (!d->config_buf[i])
+                               goto err_alloc;
+               }
+       }
+
        d->irq_chip = regmap_irq_chip;
        d->irq_chip.name = chip->name;
        d->irq = irq;
@@ -738,18 +852,53 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
        d->chip = chip;
        d->irq_base = irq_base;
 
+       if (chip->mask_base && chip->unmask_base &&
+           !chip->mask_unmask_non_inverted) {
+               /*
+                * Chips that specify both mask_base and unmask_base used to
+                * get inverted mask behavior by default, with no way to ask
+                * for the normal, non-inverted behavior. This "inverted by
+                * default" behavior is deprecated, but we have to support it
+                * until existing drivers have been fixed.
+                *
+                * Existing drivers should be updated by swapping mask_base
+                * and unmask_base and setting mask_unmask_non_inverted=true.
+                * New drivers should always set the flag.
+                */
+               dev_warn(map->dev, "mask_base and unmask_base are inverted, please fix it");
+
+               /* Might as well warn about mask_invert while we're at it... */
+               if (chip->mask_invert)
+                       dev_warn(map->dev, "mask_invert=true ignored");
+
+               d->mask_base = chip->unmask_base;
+               d->unmask_base = chip->mask_base;
+       } else if (chip->mask_invert) {
+               /*
+                * Swap the roles of mask_base and unmask_base if the bits are
+                * inverted. This is deprecated, drivers should use unmask_base
+                * directly.
+                */
+               dev_warn(map->dev, "mask_invert=true is deprecated; please switch to unmask_base");
+
+               d->mask_base = chip->unmask_base;
+               d->unmask_base = chip->mask_base;
+       } else {
+               d->mask_base = chip->mask_base;
+               d->unmask_base = chip->unmask_base;
+       }
+
        if (chip->irq_reg_stride)
                d->irq_reg_stride = chip->irq_reg_stride;
        else
                d->irq_reg_stride = 1;
 
-       if (chip->type_reg_stride)
-               d->type_reg_stride = chip->type_reg_stride;
+       if (chip->get_irq_reg)
+               d->get_irq_reg = chip->get_irq_reg;
        else
-               d->type_reg_stride = 1;
+               d->get_irq_reg = regmap_irq_get_irq_reg_linear;
 
-       if (!map->use_single_read && map->reg_stride == 1 &&
-           d->irq_reg_stride == 1) {
+       if (regmap_irq_can_bulk_read_status(d)) {
                d->status_reg_buf = kmalloc_array(chip->num_regs,
                                                  map->format.val_bytes,
                                                  GFP_KERNEL);
@@ -766,35 +915,34 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
        /* Mask all the interrupts by default */
        for (i = 0; i < chip->num_regs; i++) {
                d->mask_buf[i] = d->mask_buf_def[i];
-               if (!chip->mask_base)
-                       continue;
 
-               reg = sub_irq_reg(d, d->chip->mask_base, i);
+               if (d->mask_base) {
+                       reg = d->get_irq_reg(d, d->mask_base, i);
+                       ret = regmap_update_bits(d->map, reg,
+                                       d->mask_buf_def[i], d->mask_buf[i]);
+                       if (ret) {
+                               dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
+                                       reg, ret);
+                               goto err_alloc;
+                       }
+               }
 
-               if (chip->mask_invert)
-                       ret = regmap_irq_update_bits(d, reg,
-                                        d->mask_buf[i], ~d->mask_buf[i]);
-               else if (d->chip->unmask_base) {
-                       unmask_offset = d->chip->unmask_base -
-                                       d->chip->mask_base;
-                       ret = regmap_irq_update_bits(d,
-                                       reg + unmask_offset,
-                                       d->mask_buf[i],
-                                       d->mask_buf[i]);
-               } else
-                       ret = regmap_irq_update_bits(d, reg,
-                                        d->mask_buf[i], d->mask_buf[i]);
-               if (ret != 0) {
-                       dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
-                               reg, ret);
-                       goto err_alloc;
+               if (d->unmask_base) {
+                       reg = d->get_irq_reg(d, d->unmask_base, i);
+                       ret = regmap_update_bits(d->map, reg,
+                                       d->mask_buf_def[i], ~d->mask_buf[i]);
+                       if (ret) {
+                               dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
+                                       reg, ret);
+                               goto err_alloc;
+                       }
                }
 
                if (!chip->init_ack_masked)
                        continue;
 
                /* Ack masked but set interrupts */
-               reg = sub_irq_reg(d, d->chip->status_base, i);
+               reg = d->get_irq_reg(d, d->chip->status_base, i);
                ret = regmap_read(map, reg, &d->status_buf[i]);
                if (ret != 0) {
                        dev_err(map->dev, "Failed to read IRQ status: %d\n",
@@ -806,7 +954,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
                        d->status_buf[i] = ~d->status_buf[i];
 
                if (d->status_buf[i] && (chip->ack_base || chip->use_ack)) {
-                       reg = sub_irq_reg(d, d->chip->ack_base, i);
+                       reg = d->get_irq_reg(d, d->chip->ack_base, i);
                        if (chip->ack_invert)
                                ret = regmap_write(map, reg,
                                        ~(d->status_buf[i] & d->mask_buf[i]));
@@ -831,14 +979,14 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
        if (d->wake_buf) {
                for (i = 0; i < chip->num_regs; i++) {
                        d->wake_buf[i] = d->mask_buf_def[i];
-                       reg = sub_irq_reg(d, d->chip->wake_base, i);
+                       reg = d->get_irq_reg(d, d->chip->wake_base, i);
 
                        if (chip->wake_invert)
-                               ret = regmap_irq_update_bits(d, reg,
+                               ret = regmap_update_bits(d->map, reg,
                                                         d->mask_buf_def[i],
                                                         0);
                        else
-                               ret = regmap_irq_update_bits(d, reg,
+                               ret = regmap_update_bits(d->map, reg,
                                                         d->mask_buf_def[i],
                                                         d->wake_buf[i]);
                        if (ret != 0) {
@@ -851,7 +999,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
 
        if (chip->num_type_reg && !chip->type_in_mask) {
                for (i = 0; i < chip->num_type_reg; ++i) {
-                       reg = sub_irq_reg(d, d->chip->type_base, i);
+                       reg = d->get_irq_reg(d, d->chip->type_base, i);
 
                        ret = regmap_read(map, reg, &d->type_buf_def[i]);
 
@@ -907,6 +1055,11 @@ err_alloc:
                        kfree(d->virt_buf[i]);
                kfree(d->virt_buf);
        }
+       if (d->config_buf) {
+               for (i = 0; i < chip->num_config_bases; i++)
+                       kfree(d->config_buf[i]);
+               kfree(d->config_buf);
+       }
        kfree(d);
        return ret;
 }
@@ -947,7 +1100,7 @@ EXPORT_SYMBOL_GPL(regmap_add_irq_chip);
 void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
 {
        unsigned int virq;
-       int hwirq;
+       int i, hwirq;
 
        if (!d)
                return;
@@ -977,6 +1130,11 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
        kfree(d->mask_buf);
        kfree(d->status_reg_buf);
        kfree(d->status_buf);
+       if (d->config_buf) {
+               for (i = 0; i < d->chip->num_config_bases; i++)
+                       kfree(d->config_buf[i]);
+               kfree(d->config_buf);
+       }
        kfree(d);
 }
 EXPORT_SYMBOL_GPL(regmap_del_irq_chip);
index c3517cc..fee221c 100644 (file)
@@ -882,6 +882,8 @@ struct regmap *__regmap_init(struct device *dev,
 
        if (config && config->read && config->write) {
                map->reg_read  = _regmap_bus_read;
+               if (config->reg_update_bits)
+                       map->reg_update_bits = config->reg_update_bits;
 
                /* Bulk read/write */
                map->read = config->read;
@@ -1298,6 +1300,9 @@ static void regmap_field_init(struct regmap_field *rm_field,
        rm_field->reg = reg_field.reg;
        rm_field->shift = reg_field.lsb;
        rm_field->mask = GENMASK(reg_field.msb, reg_field.lsb);
+
+       WARN_ONCE(rm_field->mask == 0, "invalid empty mask defined\n");
+
        rm_field->id_size = reg_field.id_size;
        rm_field->id_offset = reg_field.id_offset;
 }
@@ -2219,6 +2224,28 @@ int regmap_field_update_bits_base(struct regmap_field *field,
 EXPORT_SYMBOL_GPL(regmap_field_update_bits_base);
 
 /**
+ * regmap_field_test_bits() - Check if all specified bits are set in a
+ *                            register field.
+ *
+ * @field: Register field to operate on
+ * @bits: Bits to test
+ *
+ * Returns -1 if the underlying regmap_field_read() fails, 0 if at least one of the
+ * tested bits is not set and 1 if all tested bits are set.
+ */
+int regmap_field_test_bits(struct regmap_field *field, unsigned int bits)
+{
+       unsigned int val, ret;
+
+       ret = regmap_field_read(field, &val);
+       if (ret)
+               return ret;
+
+       return (val & bits) == bits;
+}
+EXPORT_SYMBOL_GPL(regmap_field_test_bits);
+
+/**
  * regmap_fields_update_bits_base() - Perform a read/modify/write cycle a
  *                                    register field with port ID
  *
index fdb81f2..e19fcab 100644 (file)
@@ -408,6 +408,15 @@ config BLK_DEV_RBD
 
          If unsure, say N.
 
+config BLK_DEV_UBLK
+       tristate "Userspace block driver (Experimental)"
+       select IO_URING
+       help
+         io_uring based userspace block driver. Together with ublk server, ublk
+         has been working well, but interface with userspace or command data
+         definition isn't finalized yet, and might change according to future
+         requirement, so mark is as experimental now.
+
 source "drivers/block/rnbd/Kconfig"
 
 endif # BLK_DEV
index 934a9c7..be63135 100644 (file)
@@ -39,4 +39,6 @@ obj-$(CONFIG_BLK_DEV_RNBD)    += rnbd/
 
 obj-$(CONFIG_BLK_DEV_NULL_BLK) += null_blk/
 
+obj-$(CONFIG_BLK_DEV_UBLK)                     += ublk_drv.o
+
 swim_mod-y     := swim.o swim_asm.o
index 5a566f2..4c8b2ba 100644 (file)
@@ -1802,7 +1802,7 @@ static int fd_alloc_disk(int drive, int system)
        unit[drive].gendisk[system] = disk;
        err = add_disk(disk);
        if (err)
-               blk_cleanup_disk(disk);
+               put_disk(disk);
        return err;
 }
 
index 348adf3..12b3ca8 100644 (file)
@@ -427,7 +427,7 @@ aoeblk_gdalloc(void *vp)
        return;
 
 out_disk_cleanup:
-       blk_cleanup_disk(gd);
+       put_disk(gd);
 err_tagset:
        blk_mq_free_tag_set(set);
 err_mempool:
index b381d1c..3523dd8 100644 (file)
@@ -277,7 +277,7 @@ freedev(struct aoedev *d)
        if (d->gd) {
                aoedisk_rm_debugfs(d);
                del_gendisk(d->gd);
-               blk_cleanup_disk(d->gd);
+               put_disk(d->gd);
                blk_mq_free_tag_set(&d->tag_set);
        }
        t = d->targets;
index e232cc4..9deb4df 100644 (file)
@@ -2031,7 +2031,7 @@ static void ataflop_probe(dev_t dev)
        return;
 
 cleanup_disk:
-       blk_cleanup_disk(unit[drive].disk[type]);
+       put_disk(unit[drive].disk[type]);
        unit[drive].disk[type] = NULL;
 }
 
@@ -2045,7 +2045,6 @@ static void atari_floppy_cleanup(void)
                        if (!unit[i].disk[type])
                                continue;
                        del_gendisk(unit[i].disk[type]);
-                       blk_cleanup_queue(unit[i].disk[type]->queue);
                        put_disk(unit[i].disk[type]);
                }
                blk_mq_free_tag_set(&unit[i].tag_set);
@@ -2064,7 +2063,7 @@ static void atari_cleanup_floppy_disk(struct atari_floppy_struct *fs)
                        continue;
                if (fs->registered[type])
                        del_gendisk(fs->disk[type]);
-               blk_cleanup_disk(fs->disk[type]);
+               put_disk(fs->disk[type]);
        }
        blk_mq_free_tag_set(&fs->tag_set);
 }
index 6e3f2f0..859499c 100644 (file)
@@ -256,7 +256,7 @@ static void copy_from_brd(void *dst, struct brd_device *brd,
  * Process a single bvec of a bio.
  */
 static int brd_do_bvec(struct brd_device *brd, struct page *page,
-                       unsigned int len, unsigned int off, unsigned int op,
+                       unsigned int len, unsigned int off, enum req_op op,
                        sector_t sector)
 {
        void *mem;
@@ -310,7 +310,7 @@ static void brd_submit_bio(struct bio *bio)
 }
 
 static int brd_rw_page(struct block_device *bdev, sector_t sector,
-                      struct page *page, unsigned int op)
+                      struct page *page, enum req_op op)
 {
        struct brd_device *brd = bdev->bd_disk->private_data;
        int err;
@@ -419,7 +419,7 @@ static int brd_alloc(int i)
        return 0;
 
 out_cleanup_disk:
-       blk_cleanup_disk(disk);
+       put_disk(disk);
 out_free_dev:
        list_del(&brd->brd_list);
        kfree(brd);
@@ -439,7 +439,7 @@ static void brd_cleanup(void)
 
        list_for_each_entry_safe(brd, next, &brd_devices, brd_list) {
                del_gendisk(brd->brd_disk);
-               blk_cleanup_disk(brd->brd_disk);
+               put_disk(brd->brd_disk);
                brd_free_pages(brd);
                list_del(&brd->brd_list);
                kfree(brd);
index f5bcded..e27478a 100644 (file)
@@ -124,12 +124,13 @@ void wait_until_done_or_force_detached(struct drbd_device *device, struct drbd_b
 
 static int _drbd_md_sync_page_io(struct drbd_device *device,
                                 struct drbd_backing_dev *bdev,
-                                sector_t sector, int op)
+                                sector_t sector, enum req_op op)
 {
        struct bio *bio;
        /* we do all our meta data IO in aligned 4k blocks. */
        const int size = 4096;
-       int err, op_flags = 0;
+       int err;
+       blk_opf_t op_flags = 0;
 
        device->md_io.done = 0;
        device->md_io.error = -ENODEV;
@@ -174,7 +175,7 @@ static int _drbd_md_sync_page_io(struct drbd_device *device,
 }
 
 int drbd_md_sync_page_io(struct drbd_device *device, struct drbd_backing_dev *bdev,
-                        sector_t sector, int op)
+                        sector_t sector, enum req_op op)
 {
        int err;
        D_ASSERT(device, atomic_read(&device->md_io.in_use) == 1);
@@ -385,7 +386,7 @@ static int __al_write_transaction(struct drbd_device *device, struct al_transact
                write_al_updates = rcu_dereference(device->ldev->disk_conf)->al_updates;
                rcu_read_unlock();
                if (write_al_updates) {
-                       if (drbd_md_sync_page_io(device, device->ldev, sector, WRITE)) {
+                       if (drbd_md_sync_page_io(device, device->ldev, sector, REQ_OP_WRITE)) {
                                err = -EIO;
                                drbd_chk_io_error(device, 1, DRBD_META_IO_ERROR);
                        } else {
index 9e060e4..603f682 100644 (file)
@@ -977,7 +977,7 @@ static void drbd_bm_endio(struct bio *bio)
 static void bm_page_io_async(struct drbd_bm_aio_ctx *ctx, int page_nr) __must_hold(local)
 {
        struct drbd_device *device = ctx->device;
-       unsigned int op = (ctx->flags & BM_AIO_READ) ? REQ_OP_READ : REQ_OP_WRITE;
+       enum req_op op = ctx->flags & BM_AIO_READ ? REQ_OP_READ : REQ_OP_WRITE;
        struct bio *bio = bio_alloc_bioset(device->ldev->md_bdev, 1, op,
                                           GFP_NOIO, &drbd_md_io_bio_set);
        struct drbd_bitmap *b = device->bitmap;
index 4d3efaa..f15f2f0 100644 (file)
@@ -1495,7 +1495,7 @@ extern int drbd_resync_finished(struct drbd_device *device);
 extern void *drbd_md_get_buffer(struct drbd_device *device, const char *intent);
 extern void drbd_md_put_buffer(struct drbd_device *device);
 extern int drbd_md_sync_page_io(struct drbd_device *device,
-               struct drbd_backing_dev *bdev, sector_t sector, int op);
+               struct drbd_backing_dev *bdev, sector_t sector, enum req_op op);
 extern void drbd_ov_out_of_sync_found(struct drbd_device *, sector_t, int);
 extern void wait_until_done_or_force_detached(struct drbd_device *device,
                struct drbd_backing_dev *bdev, unsigned int *done);
@@ -1547,8 +1547,7 @@ extern bool drbd_rs_c_min_rate_throttle(struct drbd_device *device);
 extern bool drbd_rs_should_slow_down(struct drbd_device *device, sector_t sector,
                bool throttle_if_app_is_waiting);
 extern int drbd_submit_peer_request(struct drbd_device *,
-                                   struct drbd_peer_request *, const unsigned,
-                                   const unsigned, const int);
+                                   struct drbd_peer_request *, blk_opf_t, int);
 extern int drbd_free_peer_reqs(struct drbd_device *, struct list_head *);
 extern struct drbd_peer_request *drbd_alloc_peer_req(struct drbd_peer_device *, u64,
                                                     sector_t, unsigned int,
index 2887350..f3e4db1 100644 (file)
@@ -2207,7 +2207,7 @@ void drbd_destroy_device(struct kref *kref)
        if (device->bitmap) /* should no longer be there. */
                drbd_bm_cleanup(device);
        __free_page(device->md_io.page);
-       blk_cleanup_disk(device->vdisk);
+       put_disk(device->vdisk);
        kfree(device->rs_plan_s);
 
        /* not for_each_connection(connection, resource):
@@ -2807,7 +2807,7 @@ out_no_minor_idr:
 out_no_bitmap:
        __free_page(device->md_io.page);
 out_no_io_page:
-       blk_cleanup_disk(disk);
+       put_disk(disk);
 out_no_disk:
        kref_put(&resource->kref, drbd_destroy_resource);
        kfree(device);
index 6762be5..af4c7d6 100644 (file)
@@ -1621,8 +1621,7 @@ static void drbd_issue_peer_discard_or_zero_out(struct drbd_device *device, stru
 /* TODO allocate from our own bio_set. */
 int drbd_submit_peer_request(struct drbd_device *device,
                             struct drbd_peer_request *peer_req,
-                            const unsigned op, const unsigned op_flags,
-                            const int fault_type)
+                            const blk_opf_t opf, const int fault_type)
 {
        struct bio *bios = NULL;
        struct bio *bio;
@@ -1668,8 +1667,7 @@ int drbd_submit_peer_request(struct drbd_device *device,
         * generated bio, but a bio allocated on behalf of the peer.
         */
 next_bio:
-       bio = bio_alloc(device->ldev->backing_bdev, nr_pages, op | op_flags,
-                       GFP_NOIO);
+       bio = bio_alloc(device->ldev->backing_bdev, nr_pages, opf, GFP_NOIO);
        /* > peer_req->i.sector, unless this is the first bio */
        bio->bi_iter.bi_sector = sector;
        bio->bi_private = peer_req;
@@ -2060,7 +2058,7 @@ static int recv_resync_read(struct drbd_peer_device *peer_device, sector_t secto
        spin_unlock_irq(&device->resource->req_lock);
 
        atomic_add(pi->size >> 9, &device->rs_sect_ev);
-       if (drbd_submit_peer_request(device, peer_req, REQ_OP_WRITE, 0,
+       if (drbd_submit_peer_request(device, peer_req, REQ_OP_WRITE,
                                     DRBD_FAULT_RS_WR) == 0)
                return 0;
 
@@ -2383,14 +2381,14 @@ static int wait_for_and_update_peer_seq(struct drbd_peer_device *peer_device, co
 /* see also bio_flags_to_wire()
  * DRBD_REQ_*, because we need to semantically map the flags to data packet
  * flags and back. We may replicate to other kernel versions. */
-static unsigned long wire_flags_to_bio_flags(u32 dpf)
+static blk_opf_t wire_flags_to_bio_flags(u32 dpf)
 {
        return  (dpf & DP_RW_SYNC ? REQ_SYNC : 0) |
                (dpf & DP_FUA ? REQ_FUA : 0) |
                (dpf & DP_FLUSH ? REQ_PREFLUSH : 0);
 }
 
-static unsigned long wire_flags_to_bio_op(u32 dpf)
+static enum req_op wire_flags_to_bio_op(u32 dpf)
 {
        if (dpf & DP_ZEROES)
                return REQ_OP_WRITE_ZEROES;
@@ -2543,7 +2541,8 @@ static int receive_Data(struct drbd_connection *connection, struct packet_info *
        struct drbd_peer_request *peer_req;
        struct p_data *p = pi->data;
        u32 peer_seq = be32_to_cpu(p->seq_num);
-       int op, op_flags;
+       enum req_op op;
+       blk_opf_t op_flags;
        u32 dp_flags;
        int err, tp;
 
@@ -2681,7 +2680,7 @@ static int receive_Data(struct drbd_connection *connection, struct packet_info *
                peer_req->flags |= EE_CALL_AL_COMPLETE_IO;
        }
 
-       err = drbd_submit_peer_request(device, peer_req, op, op_flags,
+       err = drbd_submit_peer_request(device, peer_req, op | op_flags,
                                       DRBD_FAULT_DT_WR);
        if (!err)
                return 0;
@@ -2979,7 +2978,7 @@ submit_for_resync:
 submit:
        update_receiver_timing_details(connection, drbd_submit_peer_request);
        inc_unacked(device);
-       if (drbd_submit_peer_request(device, peer_req, REQ_OP_READ, 0,
+       if (drbd_submit_peer_request(device, peer_req, REQ_OP_READ,
                                     fault_type) == 0)
                return 0;
 
@@ -4951,7 +4950,7 @@ static int receive_rs_deallocated(struct drbd_connection *connection, struct pac
 
        if (get_ldev(device)) {
                struct drbd_peer_request *peer_req;
-               const int op = REQ_OP_WRITE_ZEROES;
+               const enum req_op op = REQ_OP_WRITE_ZEROES;
 
                peer_req = drbd_alloc_peer_req(peer_device, ID_SYNCER, sector,
                                               size, 0, GFP_NOIO);
@@ -4969,7 +4968,8 @@ static int receive_rs_deallocated(struct drbd_connection *connection, struct pac
                spin_unlock_irq(&device->resource->req_lock);
 
                atomic_add(pi->size >> 9, &device->rs_sect_ev);
-               err = drbd_submit_peer_request(device, peer_req, op, 0, DRBD_FAULT_RS_WR);
+               err = drbd_submit_peer_request(device, peer_req, op,
+                                              DRBD_FAULT_RS_WR);
 
                if (err) {
                        spin_lock_irq(&device->resource->req_lock);
index e64bcfb..6d8dd14 100644 (file)
@@ -523,16 +523,14 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m,
 
 static void drbd_report_io_error(struct drbd_device *device, struct drbd_request *req)
 {
-        char b[BDEVNAME_SIZE];
-
        if (!__ratelimit(&drbd_ratelimit_state))
                return;
 
-       drbd_warn(device, "local %s IO error sector %llu+%u on %s\n",
+       drbd_warn(device, "local %s IO error sector %llu+%u on %pg\n",
                        (req->rq_state & RQ_WRITE) ? "WRITE" : "READ",
                        (unsigned long long)req->i.sector,
                        req->i.size >> 9,
-                       bdevname(device->ldev->backing_bdev, b));
+                       device->ldev->backing_bdev);
 }
 
 /* Helper for HANDED_OVER_TO_NETWORK.
index af3051d..0bb1a90 100644 (file)
@@ -405,7 +405,7 @@ static int read_for_csum(struct drbd_peer_device *peer_device, sector_t sector,
        spin_unlock_irq(&device->resource->req_lock);
 
        atomic_add(size >> 9, &device->rs_sect_ev);
-       if (drbd_submit_peer_request(device, peer_req, REQ_OP_READ, 0,
+       if (drbd_submit_peer_request(device, peer_req, REQ_OP_READ,
                                     DRBD_FAULT_RS_RD) == 0)
                return 0;
 
index 015841f..ccad3d7 100644 (file)
@@ -2859,7 +2859,7 @@ static blk_status_t floppy_queue_rq(struct blk_mq_hw_ctx *hctx,
        if (WARN(atomic_read(&usage_count) == 0,
                 "warning: usage count=0, current_req=%p sect=%ld flags=%llx\n",
                 current_req, (long)blk_rq_pos(current_req),
-                (unsigned long long) current_req->cmd_flags))
+                (__force unsigned long long) current_req->cmd_flags))
                return BLK_STS_IOERR;
 
        if (test_and_set_bit(0, &fdc_busy)) {
@@ -4557,7 +4557,7 @@ out:
        return;
 
 cleanup_disk:
-       blk_cleanup_disk(disks[drive][type]);
+       put_disk(disks[drive][type]);
        disks[drive][type] = NULL;
        mutex_unlock(&floppy_probe_lock);
 }
@@ -4753,7 +4753,7 @@ out_put_disk:
                if (!disks[drive][0])
                        break;
                del_timer_sync(&motor_off_timer[drive]);
-               blk_cleanup_disk(disks[drive][0]);
+               put_disk(disks[drive][0]);
                blk_mq_free_tag_set(&tag_sets[drive]);
        }
        return err;
@@ -4985,7 +4985,7 @@ static void __exit floppy_module_exit(void)
                }
                for (i = 0; i < ARRAY_SIZE(floppy_type); i++) {
                        if (disks[drive][i])
-                               blk_cleanup_disk(disks[drive][i]);
+                               put_disk(disks[drive][i]);
                }
                blk_mq_free_tag_set(&tag_sets[drive]);
        }
index 084f9b8..e3c0ba9 100644 (file)
@@ -2040,7 +2040,7 @@ static int loop_add(int i)
        return i;
 
 out_cleanup_disk:
-       blk_cleanup_disk(disk);
+       put_disk(disk);
 out_cleanup_tags:
        blk_mq_free_tag_set(&lo->tag_set);
 out_free_idr:
@@ -2057,7 +2057,6 @@ static void loop_remove(struct loop_device *lo)
 {
        /* Make this loop device unreachable from pathname. */
        del_gendisk(lo->lo_disk);
-       blk_cleanup_queue(lo->lo_disk->queue);
        blk_mq_free_tag_set(&lo->tag_set);
 
        mutex_lock(&loop_ctl_mutex);
index 27386a5..562725d 100644 (file)
 /* Device instance number, incremented each time a device is probed. */
 static int instance;
 
-static LIST_HEAD(online_list);
-static LIST_HEAD(removing_list);
-static DEFINE_SPINLOCK(dev_lock);
-
 /*
  * Global variable used to hold the major block device number
  * allocated in mtip_init().
  */
 static int mtip_major;
 static struct dentry *dfs_parent;
-static struct dentry *dfs_device_status;
 
 static u32 cpu_use[NR_CPUS];
 
@@ -146,11 +141,8 @@ static bool mtip_check_surprise_removal(struct driver_data *dd)
        pci_read_config_word(dd->pdev, 0x00, &vendor_id);
        if (vendor_id == 0xFFFF) {
                dd->sr = true;
-               if (dd->queue)
-                       blk_queue_flag_set(QUEUE_FLAG_DEAD, dd->queue);
-               else
-                       dev_warn(&dd->pdev->dev,
-                               "%s: dd->queue is NULL\n", __func__);
+               if (dd->disk)
+                       blk_mark_disk_dead(dd->disk);
                return true; /* device removed */
        }
 
@@ -2170,106 +2162,6 @@ static const struct attribute_group *mtip_disk_attr_groups[] = {
        NULL,
 };
 
-/* debugsfs entries */
-
-static ssize_t show_device_status(struct device_driver *drv, char *buf)
-{
-       int size = 0;
-       struct driver_data *dd, *tmp;
-       unsigned long flags;
-       char id_buf[42];
-       u16 status = 0;
-
-       spin_lock_irqsave(&dev_lock, flags);
-       size += sprintf(&buf[size], "Devices Present:\n");
-       list_for_each_entry_safe(dd, tmp, &online_list, online_list) {
-               if (dd->pdev) {
-                       if (dd->port &&
-                           dd->port->identify &&
-                           dd->port->identify_valid) {
-                               strlcpy(id_buf,
-                                       (char *) (dd->port->identify + 10), 21);
-                               status = *(dd->port->identify + 141);
-                       } else {
-                               memset(id_buf, 0, 42);
-                               status = 0;
-                       }
-
-                       if (dd->port &&
-                           test_bit(MTIP_PF_REBUILD_BIT, &dd->port->flags)) {
-                               size += sprintf(&buf[size],
-                                       " device %s %s (ftl rebuild %d %%)\n",
-                                       dev_name(&dd->pdev->dev),
-                                       id_buf,
-                                       status);
-                       } else {
-                               size += sprintf(&buf[size],
-                                       " device %s %s\n",
-                                       dev_name(&dd->pdev->dev),
-                                       id_buf);
-                       }
-               }
-       }
-
-       size += sprintf(&buf[size], "Devices Being Removed:\n");
-       list_for_each_entry_safe(dd, tmp, &removing_list, remove_list) {
-               if (dd->pdev) {
-                       if (dd->port &&
-                           dd->port->identify &&
-                           dd->port->identify_valid) {
-                               strlcpy(id_buf,
-                                       (char *) (dd->port->identify+10), 21);
-                               status = *(dd->port->identify + 141);
-                       } else {
-                               memset(id_buf, 0, 42);
-                               status = 0;
-                       }
-
-                       if (dd->port &&
-                           test_bit(MTIP_PF_REBUILD_BIT, &dd->port->flags)) {
-                               size += sprintf(&buf[size],
-                                       " device %s %s (ftl rebuild %d %%)\n",
-                                       dev_name(&dd->pdev->dev),
-                                       id_buf,
-                                       status);
-                       } else {
-                               size += sprintf(&buf[size],
-                                       " device %s %s\n",
-                                       dev_name(&dd->pdev->dev),
-                                       id_buf);
-                       }
-               }
-       }
-       spin_unlock_irqrestore(&dev_lock, flags);
-
-       return size;
-}
-
-static ssize_t mtip_hw_read_device_status(struct file *f, char __user *ubuf,
-                                               size_t len, loff_t *offset)
-{
-       int size = *offset;
-       char *buf;
-       int rv = 0;
-
-       if (!len || *offset)
-               return 0;
-
-       buf = kzalloc(MTIP_DFS_MAX_BUF_SIZE, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       size += show_device_status(NULL, buf);
-
-       *offset = size <= len ? size : len;
-       size = copy_to_user(ubuf, buf, *offset);
-       if (size)
-               rv = -EFAULT;
-
-       kfree(buf);
-       return rv ? rv : *offset;
-}
-
 static ssize_t mtip_hw_read_registers(struct file *f, char __user *ubuf,
                                  size_t len, loff_t *offset)
 {
@@ -2363,13 +2255,6 @@ static ssize_t mtip_hw_read_flags(struct file *f, char __user *ubuf,
        return rv ? rv : *offset;
 }
 
-static const struct file_operations mtip_device_status_fops = {
-       .owner  = THIS_MODULE,
-       .open   = simple_open,
-       .read   = mtip_hw_read_device_status,
-       .llseek = no_llseek,
-};
-
 static const struct file_operations mtip_regs_fops = {
        .owner  = THIS_MODULE,
        .open   = simple_open,
@@ -2556,7 +2441,7 @@ static void mtip_softirq_done_fn(struct request *rq)
        blk_mq_end_request(rq, cmd->status);
 }
 
-static bool mtip_abort_cmd(struct request *req, void *data, bool reserved)
+static bool mtip_abort_cmd(struct request *req, void *data)
 {
        struct mtip_cmd *cmd = blk_mq_rq_to_pdu(req);
        struct driver_data *dd = data;
@@ -2569,7 +2454,7 @@ static bool mtip_abort_cmd(struct request *req, void *data, bool reserved)
        return true;
 }
 
-static bool mtip_queue_cmd(struct request *req, void *data, bool reserved)
+static bool mtip_queue_cmd(struct request *req, void *data)
 {
        struct driver_data *dd = data;
 
@@ -3297,26 +3182,12 @@ static int mtip_block_getgeo(struct block_device *dev,
        return 0;
 }
 
-static int mtip_block_open(struct block_device *dev, fmode_t mode)
+static void mtip_block_free_disk(struct gendisk *disk)
 {
-       struct driver_data *dd;
+       struct driver_data *dd = disk->private_data;
 
-       if (dev && dev->bd_disk) {
-               dd = (struct driver_data *) dev->bd_disk->private_data;
-
-               if (dd) {
-                       if (test_bit(MTIP_DDF_REMOVAL_BIT,
-                                                       &dd->dd_flag)) {
-                               return -ENODEV;
-                       }
-                       return 0;
-               }
-       }
-       return -ENODEV;
-}
-
-static void mtip_block_release(struct gendisk *disk, fmode_t mode)
-{
+       ida_free(&rssd_index_ida, dd->index);
+       kfree(dd);
 }
 
 /*
@@ -3326,13 +3197,12 @@ static void mtip_block_release(struct gendisk *disk, fmode_t mode)
  * layer.
  */
 static const struct block_device_operations mtip_block_ops = {
-       .open           = mtip_block_open,
-       .release        = mtip_block_release,
        .ioctl          = mtip_block_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = mtip_block_compat_ioctl,
 #endif
        .getgeo         = mtip_block_getgeo,
+       .free_disk      = mtip_block_free_disk,
        .owner          = THIS_MODULE
 };
 
@@ -3487,12 +3357,11 @@ static int mtip_init_cmd(struct blk_mq_tag_set *set, struct request *rq,
        return 0;
 }
 
-static enum blk_eh_timer_return mtip_cmd_timeout(struct request *req,
-                                                               bool reserved)
+static enum blk_eh_timer_return mtip_cmd_timeout(struct request *req)
 {
        struct driver_data *dd = req->q->queuedata;
 
-       if (reserved) {
+       if (blk_mq_is_reserved_rq(req)) {
                struct mtip_cmd *cmd = blk_mq_rq_to_pdu(req);
 
                cmd->status = BLK_STS_TIMEOUT;
@@ -3664,7 +3533,7 @@ init_hw_cmds_error:
 disk_index_error:
        ida_free(&rssd_index_ida, index);
 ida_get_error:
-       blk_cleanup_disk(dd->disk);
+       put_disk(dd->disk);
 block_queue_alloc_init_error:
        blk_mq_free_tag_set(&dd->tags);
 block_queue_alloc_tag_error:
@@ -3673,72 +3542,6 @@ protocol_init_error:
        return rv;
 }
 
-static bool mtip_no_dev_cleanup(struct request *rq, void *data, bool reserv)
-{
-       struct mtip_cmd *cmd = blk_mq_rq_to_pdu(rq);
-
-       cmd->status = BLK_STS_IOERR;
-       blk_mq_complete_request(rq);
-       return true;
-}
-
-/*
- * Block layer deinitialization function.
- *
- * Called by the PCI layer as each P320 device is removed.
- *
- * @dd Pointer to the driver data structure.
- *
- * return value
- *     0
- */
-static int mtip_block_remove(struct driver_data *dd)
-{
-       mtip_hw_debugfs_exit(dd);
-
-       if (dd->mtip_svc_handler) {
-               set_bit(MTIP_PF_SVC_THD_STOP_BIT, &dd->port->flags);
-               wake_up_interruptible(&dd->port->svc_wait);
-               kthread_stop(dd->mtip_svc_handler);
-       }
-
-       if (!dd->sr) {
-               /*
-                * Explicitly wait here for IOs to quiesce,
-                * as mtip_standby_drive usually won't wait for IOs.
-                */
-               if (!mtip_quiesce_io(dd->port, MTIP_QUIESCE_IO_TIMEOUT_MS))
-                       mtip_standby_drive(dd);
-       }
-       else
-               dev_info(&dd->pdev->dev, "device %s surprise removal\n",
-                                               dd->disk->disk_name);
-
-       blk_freeze_queue_start(dd->queue);
-       blk_mq_quiesce_queue(dd->queue);
-       blk_mq_tagset_busy_iter(&dd->tags, mtip_no_dev_cleanup, dd);
-       blk_mq_unquiesce_queue(dd->queue);
-
-       if (dd->disk) {
-               if (test_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag))
-                       del_gendisk(dd->disk);
-               if (dd->disk->queue) {
-                       blk_cleanup_queue(dd->queue);
-                       blk_mq_free_tag_set(&dd->tags);
-                       dd->queue = NULL;
-               }
-               put_disk(dd->disk);
-       }
-       dd->disk  = NULL;
-
-       ida_free(&rssd_index_ida, dd->index);
-
-       /* De-initialize the protocol layer. */
-       mtip_hw_exit(dd);
-
-       return 0;
-}
-
 /*
  * Function called by the PCI layer when just before the
  * machine shuts down.
@@ -3755,23 +3558,14 @@ static int mtip_block_shutdown(struct driver_data *dd)
 {
        mtip_hw_shutdown(dd);
 
-       /* Delete our gendisk structure, and cleanup the blk queue. */
-       if (dd->disk) {
-               dev_info(&dd->pdev->dev,
-                       "Shutting down %s ...\n", dd->disk->disk_name);
+       dev_info(&dd->pdev->dev,
+               "Shutting down %s ...\n", dd->disk->disk_name);
 
-               if (test_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag))
-                       del_gendisk(dd->disk);
-               if (dd->disk->queue) {
-                       blk_cleanup_queue(dd->queue);
-                       blk_mq_free_tag_set(&dd->tags);
-               }
-               put_disk(dd->disk);
-               dd->disk  = NULL;
-               dd->queue = NULL;
-       }
+       if (test_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag))
+               del_gendisk(dd->disk);
 
-       ida_free(&rssd_index_ida, dd->index);
+       blk_mq_free_tag_set(&dd->tags);
+       put_disk(dd->disk);
        return 0;
 }
 
@@ -3905,7 +3699,6 @@ static int mtip_pci_probe(struct pci_dev *pdev,
        const struct cpumask *node_mask;
        int cpu, i = 0, j = 0;
        int my_node = NUMA_NO_NODE;
-       unsigned long flags;
 
        /* Allocate memory for this devices private data. */
        my_node = pcibus_to_node(pdev->bus);
@@ -3952,9 +3745,6 @@ static int mtip_pci_probe(struct pci_dev *pdev,
        dd->pdev        = pdev;
        dd->numa_node   = my_node;
 
-       INIT_LIST_HEAD(&dd->online_list);
-       INIT_LIST_HEAD(&dd->remove_list);
-
        memset(dd->workq_name, 0, 32);
        snprintf(dd->workq_name, 31, "mtipq%d", dd->instance);
 
@@ -4047,11 +3837,6 @@ static int mtip_pci_probe(struct pci_dev *pdev,
        else
                rv = 0; /* device in rebuild state, return 0 from probe */
 
-       /* Add to online list even if in ftl rebuild */
-       spin_lock_irqsave(&dev_lock, flags);
-       list_add(&dd->online_list, &online_list);
-       spin_unlock_irqrestore(&dev_lock, flags);
-
        goto done;
 
 block_initialize_err:
@@ -4085,14 +3870,7 @@ done:
 static void mtip_pci_remove(struct pci_dev *pdev)
 {
        struct driver_data *dd = pci_get_drvdata(pdev);
-       unsigned long flags, to;
-
-       set_bit(MTIP_DDF_REMOVAL_BIT, &dd->dd_flag);
-
-       spin_lock_irqsave(&dev_lock, flags);
-       list_del_init(&dd->online_list);
-       list_add(&dd->remove_list, &removing_list);
-       spin_unlock_irqrestore(&dev_lock, flags);
+       unsigned long to;
 
        mtip_check_surprise_removal(dd);
        synchronize_irq(dd->pdev->irq);
@@ -4109,11 +3887,35 @@ static void mtip_pci_remove(struct pci_dev *pdev)
                        "Completion workers still active!\n");
        }
 
-       blk_mark_disk_dead(dd->disk);
        set_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag);
 
-       /* Clean up the block layer. */
-       mtip_block_remove(dd);
+       if (test_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag))
+               del_gendisk(dd->disk);
+
+       mtip_hw_debugfs_exit(dd);
+
+       if (dd->mtip_svc_handler) {
+               set_bit(MTIP_PF_SVC_THD_STOP_BIT, &dd->port->flags);
+               wake_up_interruptible(&dd->port->svc_wait);
+               kthread_stop(dd->mtip_svc_handler);
+       }
+
+       if (!dd->sr) {
+               /*
+                * Explicitly wait here for IOs to quiesce,
+                * as mtip_standby_drive usually won't wait for IOs.
+                */
+               if (!mtip_quiesce_io(dd->port, MTIP_QUIESCE_IO_TIMEOUT_MS))
+                       mtip_standby_drive(dd);
+       }
+       else
+               dev_info(&dd->pdev->dev, "device %s surprise removal\n",
+                                               dd->disk->disk_name);
+
+       blk_mq_free_tag_set(&dd->tags);
+
+       /* De-initialize the protocol layer. */
+       mtip_hw_exit(dd);
 
        if (dd->isr_workq) {
                destroy_workqueue(dd->isr_workq);
@@ -4124,14 +3926,10 @@ static void mtip_pci_remove(struct pci_dev *pdev)
 
        pci_disable_msi(pdev);
 
-       spin_lock_irqsave(&dev_lock, flags);
-       list_del_init(&dd->remove_list);
-       spin_unlock_irqrestore(&dev_lock, flags);
-
-       kfree(dd);
-
        pcim_iounmap_regions(pdev, 1 << MTIP_ABAR);
        pci_set_drvdata(pdev, NULL);
+
+       put_disk(dd->disk);
 }
 
 /*
@@ -4250,15 +4048,6 @@ static int __init mtip_init(void)
                pr_warn("Error creating debugfs parent\n");
                dfs_parent = NULL;
        }
-       if (dfs_parent) {
-               dfs_device_status = debugfs_create_file("device_status",
-                                       0444, dfs_parent, NULL,
-                                       &mtip_device_status_fops);
-               if (IS_ERR_OR_NULL(dfs_device_status)) {
-                       pr_err("Error creating device_status node\n");
-                       dfs_device_status = NULL;
-               }
-       }
 
        /* Register our PCI operations. */
        error = pci_register_driver(&mtip_pci_driver);
index 6816beb..f7328f1 100644 (file)
@@ -149,7 +149,6 @@ enum {
        MTIP_DDF_RESUME_BIT         = 6,
        MTIP_DDF_INIT_DONE_BIT      = 7,
        MTIP_DDF_REBUILD_FAILED_BIT = 8,
-       MTIP_DDF_REMOVAL_BIT        = 9,
 
        MTIP_DDF_STOP_IO      = ((1 << MTIP_DDF_REMOVE_PENDING_BIT) |
                                (1 << MTIP_DDF_SEC_LOCK_BIT) |
@@ -462,10 +461,6 @@ struct driver_data {
 
        int isr_binding;
 
-       struct list_head online_list; /* linkage for online list */
-
-       struct list_head remove_list; /* linkage for removing list */
-
        int unal_qdepth; /* qdepth of unaligned IO queue */
 };
 
index e094d2b..d914156 100644 (file)
@@ -157,7 +157,7 @@ static int __init n64cart_probe(struct platform_device *pdev)
        return 0;
 
 out_cleanup_disk:
-       blk_cleanup_disk(disk);
+       put_disk(disk);
 out:
        return err;
 }
index 07f3c13..f5d098a 100644 (file)
@@ -250,7 +250,7 @@ static void nbd_dev_remove(struct nbd_device *nbd)
        struct gendisk *disk = nbd->disk;
 
        del_gendisk(disk);
-       blk_cleanup_disk(disk);
+       put_disk(disk);
        blk_mq_free_tag_set(&nbd->tag_set);
 
        /*
@@ -393,8 +393,7 @@ static u32 req_to_nbd_cmd_type(struct request *req)
        }
 }
 
-static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req,
-                                                bool reserved)
+static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req)
 {
        struct nbd_cmd *cmd = blk_mq_rq_to_pdu(req);
        struct nbd_device *nbd = cmd->nbd;
@@ -880,7 +879,7 @@ static void recv_work(struct work_struct *work)
        kfree(args);
 }
 
-static bool nbd_clear_req(struct request *req, void *data, bool reserved)
+static bool nbd_clear_req(struct request *req, void *data)
 {
        struct nbd_cmd *cmd = blk_mq_rq_to_pdu(req);
 
@@ -1833,7 +1832,7 @@ static struct nbd_device *nbd_dev_add(int index, unsigned int refs)
 out_free_work:
        destroy_workqueue(nbd->recv_workq);
 out_err_disk:
-       blk_cleanup_disk(disk);
+       put_disk(disk);
 out_free_idr:
        mutex_lock(&nbd_index_mutex);
        idr_remove(&nbd_index_idr, index);
index 6b67088..8b224ed 100644 (file)
@@ -1310,7 +1310,7 @@ static inline blk_status_t null_handle_badblocks(struct nullb_cmd *cmd,
 }
 
 static inline blk_status_t null_handle_memory_backed(struct nullb_cmd *cmd,
-                                                    enum req_opf op,
+                                                    enum req_op op,
                                                     sector_t sector,
                                                     sector_t nr_sectors)
 {
@@ -1381,9 +1381,8 @@ static inline void nullb_complete_cmd(struct nullb_cmd *cmd)
        }
 }
 
-blk_status_t null_process_cmd(struct nullb_cmd *cmd,
-                             enum req_opf op, sector_t sector,
-                             unsigned int nr_sectors)
+blk_status_t null_process_cmd(struct nullb_cmd *cmd, enum req_op op,
+                             sector_t sector, unsigned int nr_sectors)
 {
        struct nullb_device *dev = cmd->nq->dev;
        blk_status_t ret;
@@ -1401,7 +1400,7 @@ blk_status_t null_process_cmd(struct nullb_cmd *cmd,
 }
 
 static blk_status_t null_handle_cmd(struct nullb_cmd *cmd, sector_t sector,
-                                   sector_t nr_sectors, enum req_opf op)
+                                   sector_t nr_sectors, enum req_op op)
 {
        struct nullb_device *dev = cmd->nq->dev;
        struct nullb *nullb = dev->nullb;
@@ -1578,7 +1577,7 @@ static int null_poll(struct blk_mq_hw_ctx *hctx, struct io_comp_batch *iob)
        return nr;
 }
 
-static enum blk_eh_timer_return null_timeout_rq(struct request *rq, bool res)
+static enum blk_eh_timer_return null_timeout_rq(struct request *rq)
 {
        struct blk_mq_hw_ctx *hctx = rq->mq_hctx;
        struct nullb_cmd *cmd = blk_mq_rq_to_pdu(rq);
@@ -1737,7 +1736,7 @@ static void null_del_dev(struct nullb *nullb)
                null_restart_queue_async(nullb);
        }
 
-       blk_cleanup_disk(nullb->disk);
+       put_disk(nullb->disk);
        if (dev->queue_mode == NULL_Q_MQ &&
            nullb->tag_set == &nullb->__tag_set)
                blk_mq_free_tag_set(nullb->tag_set);
@@ -2082,7 +2081,7 @@ static int null_add_dev(struct nullb_device *dev)
 out_cleanup_zone:
        null_free_zoned_dev(dev);
 out_cleanup_disk:
-       blk_cleanup_disk(nullb->disk);
+       put_disk(nullb->disk);
 out_cleanup_tags:
        if (dev->queue_mode == NULL_Q_MQ && nullb->tag_set == &nullb->__tag_set)
                blk_mq_free_tag_set(nullb->tag_set);
index 8359b43..6fbf0a1 100644 (file)
@@ -136,9 +136,8 @@ struct nullb {
 
 blk_status_t null_handle_discard(struct nullb_device *dev, sector_t sector,
                                 sector_t nr_sectors);
-blk_status_t null_process_cmd(struct nullb_cmd *cmd,
-                             enum req_opf op, sector_t sector,
-                             unsigned int nr_sectors);
+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);
@@ -146,9 +145,8 @@ 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,
                      unsigned int nr_zones, report_zones_cb cb, void *data);
-blk_status_t null_process_zoned_cmd(struct nullb_cmd *cmd,
-                                   enum req_opf op, sector_t sector,
-                                   sector_t nr_sectors);
+blk_status_t null_process_zoned_cmd(struct nullb_cmd *cmd, enum req_op op,
+                                   sector_t sector, sector_t nr_sectors);
 size_t null_zone_valid_read_len(struct nullb *nullb,
                                sector_t sector, unsigned int len);
 #else
@@ -164,7 +162,7 @@ static inline int null_register_zoned_dev(struct nullb *nullb)
 }
 static inline void null_free_zoned_dev(struct nullb_device *dev) {}
 static inline blk_status_t null_process_zoned_cmd(struct nullb_cmd *cmd,
-                       enum req_opf op, sector_t sector, sector_t nr_sectors)
+                       enum req_op op, sector_t sector, sector_t nr_sectors)
 {
        return BLK_STS_NOTSUPP;
 }
index 86d6c12..6b2b370 100644 (file)
@@ -36,7 +36,7 @@ TRACE_EVENT(nullb_zone_op,
            TP_ARGS(cmd, zone_no, zone_cond),
            TP_STRUCT__entry(
                __array(char, disk, DISK_NAME_LEN)
-               __field(enum req_opf, op)
+               __field(enum req_op, op)
                __field(unsigned int, zone_no)
                __field(unsigned int, zone_cond)
            ),
index 2fdd7b2..55a69e4 100644 (file)
@@ -159,7 +159,7 @@ int null_register_zoned_dev(struct nullb *nullb)
        struct nullb_device *dev = nullb->dev;
        struct request_queue *q = nullb->q;
 
-       blk_queue_set_zoned(nullb->disk, BLK_ZONED_HM);
+       disk_set_zoned(nullb->disk, BLK_ZONED_HM);
        blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, q);
        blk_queue_required_elevator_features(q, ELEVATOR_F_ZBD_SEQ_WRITE);
 
@@ -170,12 +170,12 @@ int null_register_zoned_dev(struct nullb *nullb)
                        return ret;
        } else {
                blk_queue_chunk_sectors(q, dev->zone_size_sects);
-               q->nr_zones = blkdev_nr_zones(nullb->disk);
+               nullb->disk->nr_zones = bdev_nr_zones(nullb->disk->part0);
        }
 
        blk_queue_max_zone_append_sectors(q, dev->zone_size_sects);
-       blk_queue_max_open_zones(q, dev->zone_max_open);
-       blk_queue_max_active_zones(q, dev->zone_max_active);
+       disk_set_max_open_zones(nullb->disk, dev->zone_max_open);
+       disk_set_max_active_zones(nullb->disk, dev->zone_max_active);
 
        return 0;
 }
@@ -600,7 +600,7 @@ static blk_status_t null_reset_zone(struct nullb_device *dev,
        return BLK_STS_OK;
 }
 
-static blk_status_t null_zone_mgmt(struct nullb_cmd *cmd, enum req_opf op,
+static blk_status_t null_zone_mgmt(struct nullb_cmd *cmd, enum req_op op,
                                   sector_t sector)
 {
        struct nullb_device *dev = cmd->nq->dev;
@@ -653,7 +653,7 @@ static blk_status_t null_zone_mgmt(struct nullb_cmd *cmd, enum req_opf op,
        return ret;
 }
 
-blk_status_t null_process_zoned_cmd(struct nullb_cmd *cmd, enum req_opf op,
+blk_status_t null_process_zoned_cmd(struct nullb_cmd *cmd, enum req_op op,
                                    sector_t sector, sector_t nr_sectors)
 {
        struct nullb_device *dev;
index f462ad6..a5ab407 100644 (file)
@@ -956,7 +956,7 @@ out_unreg_cdrom:
 out_pi_release:
        pi_release(cd->pi);
 out_free_disk:
-       blk_cleanup_disk(cd->disk);
+       put_disk(cd->disk);
 out_free_tag_set:
        blk_mq_free_tag_set(&cd->tag_set);
        return ret;
@@ -1029,7 +1029,7 @@ static void __exit pcd_exit(void)
                unregister_cdrom(&cd->info);
                del_gendisk(cd->disk);
                pi_release(cd->pi);
-               blk_cleanup_disk(cd->disk);
+               put_disk(cd->disk);
 
                blk_mq_free_tag_set(&cd->tag_set);
        }
index 3637c38..f8a75bc 100644 (file)
@@ -501,6 +501,8 @@ static enum action do_pd_io_start(void)
                        return do_pd_read_start();
                else
                        return do_pd_write_start();
+       default:
+               break;
        }
        return Fail;
 }
@@ -943,7 +945,7 @@ static int pd_probe_drive(struct pd_unit *disk, int autoprobe, int port,
                goto cleanup_disk;
        return 0;
 cleanup_disk:
-       blk_cleanup_disk(disk->gd);
+       put_disk(disk->gd);
 put_disk:
        put_disk(p);
        disk->gd = NULL;
@@ -1018,7 +1020,7 @@ static void __exit pd_exit(void)
                if (p) {
                        disk->gd = NULL;
                        del_gendisk(p);
-                       blk_cleanup_disk(p);
+                       put_disk(p);
                        blk_mq_free_tag_set(&disk->tag_set);
                        pi_release(disk->pi);
                }
index 292e9a4..eec1b9f 100644 (file)
@@ -975,7 +975,7 @@ static int __init pf_init_unit(struct pf_unit *pf, bool autoprobe, int port,
 out_pi_release:
        pi_release(pf->pi);
 out_free_disk:
-       blk_cleanup_disk(pf->disk);
+       put_disk(pf->disk);
 out_free_tag_set:
        blk_mq_free_tag_set(&pf->tag_set);
        return ret;
@@ -1044,7 +1044,7 @@ static void __exit pf_exit(void)
                if (!pf->present)
                        continue;
                del_gendisk(pf->disk);
-               blk_cleanup_disk(pf->disk);
+               put_disk(pf->disk);
                blk_mq_free_tag_set(&pf->tag_set);
                pi_release(pf->pi);
        }
index 7890933..01a15db 100644 (file)
@@ -2460,11 +2460,9 @@ static int pkt_seq_show(struct seq_file *m, void *p)
 {
        struct pktcdvd_device *pd = m->private;
        char *msg;
-       char bdev_buf[BDEVNAME_SIZE];
        int states[PACKET_NUM_STATES];
 
-       seq_printf(m, "Writer %s mapped to %s:\n", pd->name,
-                  bdevname(pd->bdev, bdev_buf));
+       seq_printf(m, "Writer %s mapped to %pg:\n", pd->name, pd->bdev);
 
        seq_printf(m, "\nSettings:\n");
        seq_printf(m, "\tpacket size:\t\t%dkB\n", pd->settings.size / 2);
@@ -2521,7 +2519,6 @@ static int pkt_seq_show(struct seq_file *m, void *p)
 static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
 {
        int i;
-       char b[BDEVNAME_SIZE];
        struct block_device *bdev;
        struct scsi_device *sdev;
 
@@ -2534,8 +2531,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
                if (!pd2)
                        continue;
                if (pd2->bdev->bd_dev == dev) {
-                       pkt_err(pd, "%s already setup\n",
-                               bdevname(pd2->bdev, b));
+                       pkt_err(pd, "%pg already setup\n", pd2->bdev);
                        return -EBUSY;
                }
                if (pd2->pkt_dev == dev) {
@@ -2570,7 +2566,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
        }
 
        proc_create_single_data(pd->name, 0, pkt_proc, pkt_seq_show, pd);
-       pkt_dbg(1, pd, "writer mapped to %s\n", bdevname(bdev, b));
+       pkt_dbg(1, pd, "writer mapped to %pg\n", bdev);
        return 0;
 
 out_mem:
@@ -2733,7 +2729,7 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
        return 0;
 
 out_mem2:
-       blk_cleanup_disk(disk);
+       put_disk(disk);
 out_mem:
        mempool_exit(&pd->rb_pool);
        kfree(pd);
@@ -2783,7 +2779,7 @@ static int pkt_remove_dev(dev_t pkt_dev)
        pkt_dbg(1, pd, "writer unmapped\n");
 
        del_gendisk(pd->disk);
-       blk_cleanup_disk(pd->disk);
+       put_disk(pd->disk);
 
        mempool_exit(&pd->rb_pool);
        kfree(pd);
index 3054adf..36d7b36 100644 (file)
@@ -473,7 +473,7 @@ static int ps3disk_probe(struct ps3_system_bus_device *_dev)
 
        return 0;
 fail_cleanup_disk:
-       blk_cleanup_disk(gendisk);
+       put_disk(gendisk);
 fail_free_tag_set:
        blk_mq_free_tag_set(&priv->tag_set);
 fail_teardown:
@@ -500,7 +500,7 @@ static void ps3disk_remove(struct ps3_system_bus_device *_dev)
                    &ps3disk_mask);
        mutex_unlock(&ps3disk_mask_mutex);
        del_gendisk(priv->gendisk);
-       blk_cleanup_disk(priv->gendisk);
+       put_disk(priv->gendisk);
        blk_mq_free_tag_set(&priv->tag_set);
        dev_notice(&dev->sbd.core, "Synchronizing disk cache\n");
        ps3disk_sync_cache(dev);
index 4f90819..d1e0fef 100644 (file)
@@ -761,7 +761,7 @@ static int ps3vram_probe(struct ps3_system_bus_device *dev)
        return 0;
 
 out_cleanup_disk:
-       blk_cleanup_disk(gendisk);
+       put_disk(gendisk);
 out_cache_cleanup:
        remove_proc_entry(DEVICE_NAME, NULL);
        ps3vram_cache_cleanup(dev);
@@ -792,7 +792,7 @@ static void ps3vram_remove(struct ps3_system_bus_device *dev)
        struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
 
        del_gendisk(priv->gendisk);
-       blk_cleanup_disk(priv->gendisk);
+       put_disk(priv->gendisk);
        remove_proc_entry(DEVICE_NAME, NULL);
        ps3vram_cache_cleanup(dev);
        iounmap(priv->reports);
index ef9bc62..0d8ec2f 100644 (file)
@@ -4729,7 +4729,7 @@ static blk_status_t rbd_queue_rq(struct blk_mq_hw_ctx *hctx,
 
 static void rbd_free_disk(struct rbd_device *rbd_dev)
 {
-       blk_cleanup_disk(rbd_dev->disk);
+       put_disk(rbd_dev->disk);
        blk_mq_free_tag_set(&rbd_dev->tag_set);
        rbd_dev->disk = NULL;
 }
index 409c76b..b8d9e28 100644 (file)
@@ -1408,7 +1408,7 @@ static int rnbd_clt_setup_gen_disk(struct rnbd_clt_dev *dev, int idx)
        blk_queue_flag_set(QUEUE_FLAG_NONROT, dev->queue);
        err = add_disk(dev->gd);
        if (err)
-               blk_cleanup_disk(dev->gd);
+               put_disk(dev->gd);
 
        return err;
 }
@@ -1630,7 +1630,7 @@ put_sess:
 static void destroy_gen_disk(struct rnbd_clt_dev *dev)
 {
        del_gendisk(dev->gd);
-       blk_cleanup_disk(dev->gd);
+       put_disk(dev->gd);
 }
 
 static void destroy_sysfs(struct rnbd_clt_dev *dev,
@@ -1755,7 +1755,7 @@ static void rnbd_destroy_sessions(void)
                list_for_each_entry_safe(dev, tn, &sess->devs_list, list) {
                        /*
                         * Here unmap happens in parallel for only one reason:
-                        * blk_cleanup_queue() takes around half a second, so
+                        * del_gendisk() takes around half a second, so
                         * on huge amount of devices the whole module unload
                         * procedure takes minutes.
                         */
index bfb08dd..ea7ac8b 100644 (file)
@@ -229,9 +229,9 @@ static inline bool rnbd_flags_supported(u32 flags)
        return true;
 }
 
-static inline u32 rnbd_to_bio_flags(u32 rnbd_opf)
+static inline blk_opf_t rnbd_to_bio_flags(u32 rnbd_opf)
 {
-       u32 bio_opf;
+       blk_opf_t bio_opf;
 
        switch (rnbd_op(rnbd_opf)) {
        case RNBD_OP_READ:
@@ -286,7 +286,8 @@ static inline u32 rq_to_rnbd_flags(struct request *rq)
                break;
        default:
                WARN(1, "Unknown request type %d (flags %llu)\n",
-                    req_op(rq), (unsigned long long)rq->cmd_flags);
+                    (__force u32)req_op(rq),
+                    (__force unsigned long long)rq->cmd_flags);
                rnbd_opf = 0;
        }
 
index c5d0a03..c63017f 100644 (file)
@@ -28,7 +28,6 @@ struct rnbd_dev *rnbd_dev_open(const char *path, fmode_t flags)
                goto err;
 
        dev->blk_open_flags = flags;
-       bdevname(dev->bdev, dev->name);
 
        return dev;
 
index 4309e52..8407d12 100644 (file)
@@ -15,7 +15,6 @@
 struct rnbd_dev {
        struct block_device     *bdev;
        fmode_t                 blk_open_flags;
-       char                    name[BDEVNAME_SIZE];
 };
 
 /**
index feaa76c..297a692 100644 (file)
@@ -38,14 +38,13 @@ static struct kobj_type dev_ktype = {
 };
 
 int rnbd_srv_create_dev_sysfs(struct rnbd_srv_dev *dev,
-                              struct block_device *bdev,
-                              const char *dev_name)
+                              struct block_device *bdev)
 {
        struct kobject *bdev_kobj;
        int ret;
 
        ret = kobject_init_and_add(&dev->dev_kobj, &dev_ktype,
-                                  rnbd_devs_kobj, dev_name);
+                                  rnbd_devs_kobj, "%pg", bdev);
        if (ret) {
                kobject_put(&dev->dev_kobj);
                return ret;
index beaef43..0713014 100644 (file)
@@ -419,7 +419,7 @@ static struct rnbd_srv_sess_dev
        return sess_dev;
 }
 
-static struct rnbd_srv_dev *rnbd_srv_init_srv_dev(const char *id)
+static struct rnbd_srv_dev *rnbd_srv_init_srv_dev(struct block_device *bdev)
 {
        struct rnbd_srv_dev *dev;
 
@@ -427,7 +427,7 @@ static struct rnbd_srv_dev *rnbd_srv_init_srv_dev(const char *id)
        if (!dev)
                return ERR_PTR(-ENOMEM);
 
-       strscpy(dev->id, id, sizeof(dev->id));
+       snprintf(dev->id, sizeof(dev->id), "%pg", bdev);
        kref_init(&dev->kref);
        INIT_LIST_HEAD(&dev->sess_dev_list);
        mutex_init(&dev->lock);
@@ -512,7 +512,7 @@ rnbd_srv_get_or_create_srv_dev(struct rnbd_dev *rnbd_dev,
        int ret;
        struct rnbd_srv_dev *new_dev, *dev;
 
-       new_dev = rnbd_srv_init_srv_dev(rnbd_dev->name);
+       new_dev = rnbd_srv_init_srv_dev(rnbd_dev->bdev);
        if (IS_ERR(new_dev))
                return new_dev;
 
@@ -758,8 +758,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, rnbd_dev->bdev,
-                                                rnbd_dev->name);
+               ret = rnbd_srv_create_dev_sysfs(srv_dev, rnbd_dev->bdev);
                if (ret) {
                        mutex_unlock(&srv_dev->lock);
                        rnbd_srv_err(srv_sess_dev,
index be2ae48..6926f90 100644 (file)
@@ -68,8 +68,7 @@ void rnbd_srv_sess_dev_force_close(struct rnbd_srv_sess_dev *sess_dev,
 /* rnbd-srv-sysfs.c */
 
 int rnbd_srv_create_dev_sysfs(struct rnbd_srv_dev *dev,
-                             struct block_device *bdev,
-                             const char *dir_name);
+                             struct block_device *bdev);
 void rnbd_srv_destroy_dev_sysfs(struct rnbd_srv_dev *dev);
 int rnbd_srv_create_dev_session_sysfs(struct rnbd_srv_sess_dev *sess_dev);
 void rnbd_srv_destroy_dev_session_sysfs(struct rnbd_srv_sess_dev *sess_dev);
index dd0a1a6..fb855da 100644 (file)
@@ -886,7 +886,7 @@ static int probe_disk(struct vdc_port *port)
        return 0;
 
 out_cleanup_disk:
-       blk_cleanup_disk(g);
+       put_disk(g);
 out_free_tag:
        blk_mq_free_tag_set(&port->tag_set);
        return err;
@@ -1070,7 +1070,7 @@ static void vdc_port_remove(struct vio_dev *vdev)
                del_timer_sync(&port->vio.timer);
 
                del_gendisk(port->disk);
-               blk_cleanup_disk(port->disk);
+               put_disk(port->disk);
                blk_mq_free_tag_set(&port->tag_set);
 
                vdc_free_tx_ring(port);
index fef65a1..42b4b68 100644 (file)
@@ -783,7 +783,7 @@ static void swim_cleanup_floppy_disk(struct floppy_state *fs)
        if (fs->registered)
                del_gendisk(fs->disk);
 
-       blk_cleanup_disk(disk);
+       put_disk(disk);
        blk_mq_free_tag_set(&fs->tag_set);
 }
 
index 6c39f2c..da811a7 100644 (file)
@@ -1238,7 +1238,7 @@ static int swim3_attach(struct macio_dev *mdev,
        return 0;
 
 out_cleanup_disk:
-       blk_cleanup_disk(disk);
+       put_disk(disk);
 out_free_tag_set:
        blk_mq_free_tag_set(&fs->tag_set);
 out_unregister:
index 63b4f64..0e1a484 100644 (file)
@@ -1377,7 +1377,7 @@ static void carm_free_disk(struct carm_host *host, unsigned int port_no)
 
        if (host->state > HST_DEV_ACTIVATE)
                del_gendisk(disk);
-       blk_cleanup_disk(disk);
+       put_disk(disk);
 }
 
 static int carm_init_shm(struct carm_host *host)
@@ -1536,7 +1536,7 @@ err_out_free_majors:
                clear_bit(0, &carm_major_alloc);
        else if (host->major == 161)
                clear_bit(1, &carm_major_alloc);
-       blk_cleanup_queue(host->oob_q);
+       blk_mq_destroy_queue(host->oob_q);
        blk_mq_free_tag_set(&host->tag_set);
 err_out_dma_free:
        dma_free_coherent(&pdev->dev, CARM_SHM_SIZE, host->shm, host->shm_dma);
@@ -1570,7 +1570,7 @@ static void carm_remove_one (struct pci_dev *pdev)
                clear_bit(0, &carm_major_alloc);
        else if (host->major == 161)
                clear_bit(1, &carm_major_alloc);
-       blk_cleanup_queue(host->oob_q);
+       blk_mq_destroy_queue(host->oob_q);
        blk_mq_free_tag_set(&host->tag_set);
        dma_free_coherent(&pdev->dev, CARM_SHM_SIZE, host->shm, host->shm_dma);
        iounmap(host->mmio);
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
new file mode 100644 (file)
index 0000000..3f19069
--- /dev/null
@@ -0,0 +1,1545 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Userspace block device - block device which IO is handled from userspace
+ *
+ * Take full use of io_uring passthrough command for communicating with
+ * ublk userspace daemon(ublksrvd) for handling basic IO request.
+ *
+ * Copyright 2022 Ming Lei <ming.lei@redhat.com>
+ *
+ * (part of code stolen from loop.c)
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include <linux/file.h>
+#include <linux/stat.h>
+#include <linux/errno.h>
+#include <linux/major.h>
+#include <linux/wait.h>
+#include <linux/blkdev.h>
+#include <linux/init.h>
+#include <linux/swap.h>
+#include <linux/slab.h>
+#include <linux/compat.h>
+#include <linux/mutex.h>
+#include <linux/writeback.h>
+#include <linux/completion.h>
+#include <linux/highmem.h>
+#include <linux/sysfs.h>
+#include <linux/miscdevice.h>
+#include <linux/falloc.h>
+#include <linux/uio.h>
+#include <linux/ioprio.h>
+#include <linux/sched/mm.h>
+#include <linux/uaccess.h>
+#include <linux/cdev.h>
+#include <linux/io_uring.h>
+#include <linux/blk-mq.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <asm/page.h>
+#include <linux/task_work.h>
+#include <uapi/linux/ublk_cmd.h>
+
+#define UBLK_MINORS            (1U << MINORBITS)
+
+/* All UBLK_F_* have to be included into UBLK_F_ALL */
+#define UBLK_F_ALL (UBLK_F_SUPPORT_ZERO_COPY | UBLK_F_URING_CMD_COMP_IN_TASK)
+
+struct ublk_rq_data {
+       struct callback_head work;
+};
+
+struct ublk_uring_cmd_pdu {
+       struct request *req;
+};
+
+/*
+ * io command is active: sqe cmd is received, and its cqe isn't done
+ *
+ * If the flag is set, the io command is owned by ublk driver, and waited
+ * for incoming blk-mq request from the ublk block device.
+ *
+ * If the flag is cleared, the io command will be completed, and owned by
+ * ublk server.
+ */
+#define UBLK_IO_FLAG_ACTIVE    0x01
+
+/*
+ * IO command is completed via cqe, and it is being handled by ublksrv, and
+ * not committed yet
+ *
+ * Basically exclusively with UBLK_IO_FLAG_ACTIVE, so can be served for
+ * cross verification
+ */
+#define UBLK_IO_FLAG_OWNED_BY_SRV 0x02
+
+/*
+ * IO command is aborted, so this flag is set in case of
+ * !UBLK_IO_FLAG_ACTIVE.
+ *
+ * After this flag is observed, any pending or new incoming request
+ * associated with this io command will be failed immediately
+ */
+#define UBLK_IO_FLAG_ABORTED 0x04
+
+struct ublk_io {
+       /* userspace buffer address from io cmd */
+       __u64   addr;
+       unsigned int flags;
+       int res;
+
+       struct io_uring_cmd *cmd;
+};
+
+struct ublk_queue {
+       int q_id;
+       int q_depth;
+
+       unsigned long flags;
+       struct task_struct      *ubq_daemon;
+       char *io_cmd_buf;
+
+       unsigned long io_addr;  /* mapped vm address */
+       unsigned int max_io_sz;
+       bool abort_work_pending;
+       unsigned short nr_io_ready;     /* how many ios setup */
+       struct ublk_device *dev;
+       struct ublk_io ios[0];
+};
+
+#define UBLK_DAEMON_MONITOR_PERIOD     (5 * HZ)
+
+struct ublk_device {
+       struct gendisk          *ub_disk;
+
+       char    *__queues;
+
+       unsigned short  queue_size;
+       unsigned short  bs_shift;
+       struct ublksrv_ctrl_dev_info    dev_info;
+
+       struct blk_mq_tag_set   tag_set;
+
+       struct cdev             cdev;
+       struct device           cdev_dev;
+
+#define UB_STATE_OPEN          0
+#define UB_STATE_USED          1
+       unsigned long           state;
+       int                     ub_number;
+
+       struct mutex            mutex;
+
+       spinlock_t              mm_lock;
+       struct mm_struct        *mm;
+
+       struct completion       completion;
+       unsigned int            nr_queues_ready;
+       atomic_t                nr_aborted_queues;
+
+       /*
+        * Our ubq->daemon may be killed without any notification, so
+        * monitor each queue's daemon periodically
+        */
+       struct delayed_work     monitor_work;
+       struct work_struct      stop_work;
+};
+
+static dev_t ublk_chr_devt;
+static struct class *ublk_chr_class;
+
+static DEFINE_IDR(ublk_index_idr);
+static DEFINE_SPINLOCK(ublk_idr_lock);
+static wait_queue_head_t ublk_idr_wq;  /* wait until one idr is freed */
+
+static DEFINE_MUTEX(ublk_ctl_mutex);
+
+static struct miscdevice ublk_misc;
+
+static inline bool ublk_can_use_task_work(const struct ublk_queue *ubq)
+{
+       if (IS_BUILTIN(CONFIG_BLK_DEV_UBLK) &&
+                       !(ubq->flags & UBLK_F_URING_CMD_COMP_IN_TASK))
+               return true;
+       return false;
+}
+
+static 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)
+{
+       put_device(&ub->cdev_dev);
+}
+
+static inline struct ublk_queue *ublk_get_queue(struct ublk_device *dev,
+               int qid)
+{
+       return (struct ublk_queue *)&(dev->__queues[qid * dev->queue_size]);
+}
+
+static inline bool ublk_rq_has_data(const struct request *rq)
+{
+       return rq->bio && bio_has_data(rq->bio);
+}
+
+static inline struct ublksrv_io_desc *ublk_get_iod(struct ublk_queue *ubq,
+               int tag)
+{
+       return (struct ublksrv_io_desc *)
+               &(ubq->io_cmd_buf[tag * sizeof(struct ublksrv_io_desc)]);
+}
+
+static inline char *ublk_queue_cmd_buf(struct ublk_device *ub, int q_id)
+{
+       return ublk_get_queue(ub, q_id)->io_cmd_buf;
+}
+
+static inline int ublk_queue_cmd_buf_size(struct ublk_device *ub, int q_id)
+{
+       struct ublk_queue *ubq = ublk_get_queue(ub, q_id);
+
+       return round_up(ubq->q_depth * sizeof(struct ublksrv_io_desc),
+                       PAGE_SIZE);
+}
+
+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);
+}
+
+static const struct block_device_operations ub_fops = {
+       .owner =        THIS_MODULE,
+       .free_disk =    ublk_free_disk,
+};
+
+#define UBLK_MAX_PIN_PAGES     32
+
+struct ublk_map_data {
+       const struct ublk_queue *ubq;
+       const struct request *rq;
+       const struct ublk_io *io;
+       unsigned max_bytes;
+};
+
+struct ublk_io_iter {
+       struct page *pages[UBLK_MAX_PIN_PAGES];
+       unsigned pg_off;        /* offset in the 1st page in pages */
+       int nr_pages;           /* how many page pointers in pages */
+       struct bio *bio;
+       struct bvec_iter iter;
+};
+
+static inline unsigned ublk_copy_io_pages(struct ublk_io_iter *data,
+               unsigned max_bytes, bool to_vm)
+{
+       const unsigned total = min_t(unsigned, max_bytes,
+                       PAGE_SIZE - data->pg_off +
+                       ((data->nr_pages - 1) << PAGE_SHIFT));
+       unsigned done = 0;
+       unsigned pg_idx = 0;
+
+       while (done < total) {
+               struct bio_vec bv = bio_iter_iovec(data->bio, data->iter);
+               const unsigned int bytes = min3(bv.bv_len, total - done,
+                               (unsigned)(PAGE_SIZE - data->pg_off));
+               void *bv_buf = bvec_kmap_local(&bv);
+               void *pg_buf = kmap_local_page(data->pages[pg_idx]);
+
+               if (to_vm)
+                       memcpy(pg_buf + data->pg_off, bv_buf, bytes);
+               else
+                       memcpy(bv_buf, pg_buf + data->pg_off, bytes);
+
+               kunmap_local(pg_buf);
+               kunmap_local(bv_buf);
+
+               /* advance page array */
+               data->pg_off += bytes;
+               if (data->pg_off == PAGE_SIZE) {
+                       pg_idx += 1;
+                       data->pg_off = 0;
+               }
+
+               done += bytes;
+
+               /* advance bio */
+               bio_advance_iter_single(data->bio, &data->iter, bytes);
+               if (!data->iter.bi_size) {
+                       data->bio = data->bio->bi_next;
+                       if (data->bio == NULL)
+                               break;
+                       data->iter = data->bio->bi_iter;
+               }
+       }
+
+       return done;
+}
+
+static inline int ublk_copy_user_pages(struct ublk_map_data *data,
+               bool to_vm)
+{
+       const unsigned int gup_flags = to_vm ? FOLL_WRITE : 0;
+       const unsigned long start_vm = data->io->addr;
+       unsigned int done = 0;
+       struct ublk_io_iter iter = {
+               .pg_off = start_vm & (PAGE_SIZE - 1),
+               .bio    = data->rq->bio,
+               .iter   = data->rq->bio->bi_iter,
+       };
+       const unsigned int nr_pages = round_up(data->max_bytes +
+                       (start_vm & (PAGE_SIZE - 1)), PAGE_SIZE) >> PAGE_SHIFT;
+
+       while (done < nr_pages) {
+               const unsigned to_pin = min_t(unsigned, UBLK_MAX_PIN_PAGES,
+                               nr_pages - done);
+               unsigned i, len;
+
+               iter.nr_pages = get_user_pages_fast(start_vm +
+                               (done << PAGE_SHIFT), to_pin, gup_flags,
+                               iter.pages);
+               if (iter.nr_pages <= 0)
+                       return done == 0 ? iter.nr_pages : done;
+               len = ublk_copy_io_pages(&iter, data->max_bytes, to_vm);
+               for (i = 0; i < iter.nr_pages; i++) {
+                       if (to_vm)
+                               set_page_dirty(iter.pages[i]);
+                       put_page(iter.pages[i]);
+               }
+               data->max_bytes -= len;
+               done += iter.nr_pages;
+       }
+
+       return done;
+}
+
+static int ublk_map_io(const struct ublk_queue *ubq, const struct request *req,
+               struct ublk_io *io)
+{
+       const unsigned int rq_bytes = blk_rq_bytes(req);
+       /*
+        * no zero copy, we delay copy WRITE request data into ublksrv
+        * context and the big benefit is that pinning pages in current
+        * context is pretty fast, see ublk_pin_user_pages
+        */
+       if (req_op(req) != REQ_OP_WRITE && req_op(req) != REQ_OP_FLUSH)
+               return rq_bytes;
+
+       if (ublk_rq_has_data(req)) {
+               struct ublk_map_data data = {
+                       .ubq    =       ubq,
+                       .rq     =       req,
+                       .io     =       io,
+                       .max_bytes =    rq_bytes,
+               };
+
+               ublk_copy_user_pages(&data, true);
+
+               return rq_bytes - data.max_bytes;
+       }
+       return rq_bytes;
+}
+
+static int ublk_unmap_io(const struct ublk_queue *ubq,
+               const struct request *req,
+               struct ublk_io *io)
+{
+       const unsigned int rq_bytes = blk_rq_bytes(req);
+
+       if (req_op(req) == REQ_OP_READ && ublk_rq_has_data(req)) {
+               struct ublk_map_data data = {
+                       .ubq    =       ubq,
+                       .rq     =       req,
+                       .io     =       io,
+                       .max_bytes =    io->res,
+               };
+
+               WARN_ON_ONCE(io->res > rq_bytes);
+
+               ublk_copy_user_pages(&data, false);
+
+               return io->res - data.max_bytes;
+       }
+       return rq_bytes;
+}
+
+static inline unsigned int ublk_req_build_flags(struct request *req)
+{
+       unsigned flags = 0;
+
+       if (req->cmd_flags & REQ_FAILFAST_DEV)
+               flags |= UBLK_IO_F_FAILFAST_DEV;
+
+       if (req->cmd_flags & REQ_FAILFAST_TRANSPORT)
+               flags |= UBLK_IO_F_FAILFAST_TRANSPORT;
+
+       if (req->cmd_flags & REQ_FAILFAST_DRIVER)
+               flags |= UBLK_IO_F_FAILFAST_DRIVER;
+
+       if (req->cmd_flags & REQ_META)
+               flags |= UBLK_IO_F_META;
+
+       if (req->cmd_flags & REQ_FUA)
+               flags |= UBLK_IO_F_FUA;
+
+       if (req->cmd_flags & REQ_NOUNMAP)
+               flags |= UBLK_IO_F_NOUNMAP;
+
+       if (req->cmd_flags & REQ_SWAP)
+               flags |= UBLK_IO_F_SWAP;
+
+       return flags;
+}
+
+static blk_status_t ublk_setup_iod(struct ublk_queue *ubq, struct request *req)
+{
+       struct ublksrv_io_desc *iod = ublk_get_iod(ubq, req->tag);
+       struct ublk_io *io = &ubq->ios[req->tag];
+       u32 ublk_op;
+
+       switch (req_op(req)) {
+       case REQ_OP_READ:
+               ublk_op = UBLK_IO_OP_READ;
+               break;
+       case REQ_OP_WRITE:
+               ublk_op = UBLK_IO_OP_WRITE;
+               break;
+       case REQ_OP_FLUSH:
+               ublk_op = UBLK_IO_OP_FLUSH;
+               break;
+       case REQ_OP_DISCARD:
+               ublk_op = UBLK_IO_OP_DISCARD;
+               break;
+       case REQ_OP_WRITE_ZEROES:
+               ublk_op = UBLK_IO_OP_WRITE_ZEROES;
+               break;
+       default:
+               return BLK_STS_IOERR;
+       }
+
+       /* need to translate since kernel may change */
+       iod->op_flags = ublk_op | ublk_req_build_flags(req);
+       iod->nr_sectors = blk_rq_sectors(req);
+       iod->start_sector = blk_rq_pos(req);
+       iod->addr = io->addr;
+
+       return BLK_STS_OK;
+}
+
+static inline struct ublk_uring_cmd_pdu *ublk_get_uring_cmd_pdu(
+               struct io_uring_cmd *ioucmd)
+{
+       return (struct ublk_uring_cmd_pdu *)&ioucmd->pdu;
+}
+
+static bool ubq_daemon_is_dying(struct ublk_queue *ubq)
+{
+       return ubq->ubq_daemon->flags & PF_EXITING;
+}
+
+/* todo: handle partial completion */
+static void ublk_complete_rq(struct request *req)
+{
+       struct ublk_queue *ubq = req->mq_hctx->driver_data;
+       struct ublk_io *io = &ubq->ios[req->tag];
+       unsigned int unmapped_bytes;
+
+       /* failed read IO if nothing is read */
+       if (!io->res && req_op(req) == REQ_OP_READ)
+               io->res = -EIO;
+
+       if (io->res < 0) {
+               blk_mq_end_request(req, errno_to_blk_status(io->res));
+               return;
+       }
+
+       /*
+        * FLUSH or DISCARD usually won't return bytes returned, so end them
+        * directly.
+        *
+        * Both the two needn't unmap.
+        */
+       if (req_op(req) != REQ_OP_READ && req_op(req) != REQ_OP_WRITE) {
+               blk_mq_end_request(req, BLK_STS_OK);
+               return;
+       }
+
+       /* for READ request, writing data in iod->addr to rq buffers */
+       unmapped_bytes = ublk_unmap_io(ubq, req, io);
+
+       /*
+        * Extremely impossible since we got data filled in just before
+        *
+        * Re-read simply for this unlikely case.
+        */
+       if (unlikely(unmapped_bytes < io->res))
+               io->res = unmapped_bytes;
+
+       if (blk_update_request(req, BLK_STS_OK, io->res))
+               blk_mq_requeue_request(req, true);
+       else
+               __blk_mq_end_request(req, BLK_STS_OK);
+}
+
+/*
+ * __ublk_fail_req() may be called from abort context or ->ubq_daemon
+ * context during exiting, so lock is required.
+ *
+ * Also aborting may not be started yet, keep in mind that one failed
+ * request may be issued by block layer again.
+ */
+static void __ublk_fail_req(struct ublk_io *io, struct request *req)
+{
+       WARN_ON_ONCE(io->flags & UBLK_IO_FLAG_ACTIVE);
+
+       if (!(io->flags & UBLK_IO_FLAG_ABORTED)) {
+               io->flags |= UBLK_IO_FLAG_ABORTED;
+               blk_mq_end_request(req, BLK_STS_IOERR);
+       }
+}
+
+#define UBLK_REQUEUE_DELAY_MS  3
+
+static inline void __ublk_rq_task_work(struct request *req)
+{
+       struct ublk_queue *ubq = req->mq_hctx->driver_data;
+       struct ublk_device *ub = ubq->dev;
+       int tag = req->tag;
+       struct ublk_io *io = &ubq->ios[tag];
+       bool task_exiting = current != ubq->ubq_daemon ||
+               (current->flags & PF_EXITING);
+       unsigned int mapped_bytes;
+
+       pr_devel("%s: complete: op %d, qid %d tag %d io_flags %x addr %llx\n",
+                       __func__, io->cmd->cmd_op, ubq->q_id, req->tag, io->flags,
+                       ublk_get_iod(ubq, req->tag)->addr);
+
+       if (unlikely(task_exiting)) {
+               blk_mq_end_request(req, BLK_STS_IOERR);
+               mod_delayed_work(system_wq, &ub->monitor_work, 0);
+               return;
+       }
+
+       mapped_bytes = ublk_map_io(ubq, req, io);
+
+       /* partially mapped, update io descriptor */
+       if (unlikely(mapped_bytes != blk_rq_bytes(req))) {
+               /*
+                * Nothing mapped, retry until we succeed.
+                *
+                * We may never succeed in mapping any bytes here because
+                * of OOM. TODO: reserve one buffer with single page pinned
+                * for providing forward progress guarantee.
+                */
+               if (unlikely(!mapped_bytes)) {
+                       blk_mq_requeue_request(req, false);
+                       blk_mq_delay_kick_requeue_list(req->q,
+                                       UBLK_REQUEUE_DELAY_MS);
+                       return;
+               }
+
+               ublk_get_iod(ubq, req->tag)->nr_sectors =
+                       mapped_bytes >> 9;
+       }
+
+       /* mark this cmd owned by ublksrv */
+       io->flags |= UBLK_IO_FLAG_OWNED_BY_SRV;
+
+       /*
+        * clear ACTIVE since we are done with this sqe/cmd slot
+        * We can only accept io cmd in case of being not active.
+        */
+       io->flags &= ~UBLK_IO_FLAG_ACTIVE;
+
+       /* tell ublksrv one io request is coming */
+       io_uring_cmd_done(io->cmd, UBLK_IO_RES_OK, 0);
+}
+
+static void ublk_rq_task_work_cb(struct io_uring_cmd *cmd)
+{
+       struct ublk_uring_cmd_pdu *pdu = ublk_get_uring_cmd_pdu(cmd);
+
+       __ublk_rq_task_work(pdu->req);
+}
+
+static void ublk_rq_task_work_fn(struct callback_head *work)
+{
+       struct ublk_rq_data *data = container_of(work,
+                       struct ublk_rq_data, work);
+       struct request *req = blk_mq_rq_from_pdu(data);
+
+       __ublk_rq_task_work(req);
+}
+
+static blk_status_t ublk_queue_rq(struct blk_mq_hw_ctx *hctx,
+               const struct blk_mq_queue_data *bd)
+{
+       struct ublk_queue *ubq = hctx->driver_data;
+       struct request *rq = bd->rq;
+       blk_status_t res;
+
+       /* fill iod to slot in io cmd buffer */
+       res = ublk_setup_iod(ubq, rq);
+       if (unlikely(res != BLK_STS_OK))
+               return BLK_STS_IOERR;
+
+       blk_mq_start_request(bd->rq);
+
+       if (unlikely(ubq_daemon_is_dying(ubq))) {
+ fail:
+               mod_delayed_work(system_wq, &ubq->dev->monitor_work, 0);
+               return BLK_STS_IOERR;
+       }
+
+       if (ublk_can_use_task_work(ubq)) {
+               struct ublk_rq_data *data = blk_mq_rq_to_pdu(rq);
+               enum task_work_notify_mode notify_mode = bd->last ?
+                       TWA_SIGNAL_NO_IPI : TWA_NONE;
+
+               if (task_work_add(ubq->ubq_daemon, &data->work, notify_mode))
+                       goto fail;
+       } else {
+               struct io_uring_cmd *cmd = ubq->ios[rq->tag].cmd;
+               struct ublk_uring_cmd_pdu *pdu = ublk_get_uring_cmd_pdu(cmd);
+
+               pdu->req = rq;
+               io_uring_cmd_complete_in_task(cmd, ublk_rq_task_work_cb);
+       }
+
+       return BLK_STS_OK;
+}
+
+static void ublk_commit_rqs(struct blk_mq_hw_ctx *hctx)
+{
+       struct ublk_queue *ubq = hctx->driver_data;
+
+       if (ublk_can_use_task_work(ubq))
+               __set_notify_signal(ubq->ubq_daemon);
+}
+
+static int ublk_init_hctx(struct blk_mq_hw_ctx *hctx, void *driver_data,
+               unsigned int hctx_idx)
+{
+       struct ublk_device *ub = driver_data;
+       struct ublk_queue *ubq = ublk_get_queue(ub, hctx->queue_num);
+
+       hctx->driver_data = ubq;
+       return 0;
+}
+
+static int ublk_init_rq(struct blk_mq_tag_set *set, struct request *req,
+               unsigned int hctx_idx, unsigned int numa_node)
+{
+       struct ublk_rq_data *data = blk_mq_rq_to_pdu(req);
+
+       init_task_work(&data->work, ublk_rq_task_work_fn);
+       return 0;
+}
+
+static const struct blk_mq_ops ublk_mq_ops = {
+       .queue_rq       = ublk_queue_rq,
+       .commit_rqs     = ublk_commit_rqs,
+       .init_hctx      = ublk_init_hctx,
+       .init_request   = ublk_init_rq,
+};
+
+static int ublk_ch_open(struct inode *inode, struct file *filp)
+{
+       struct ublk_device *ub = container_of(inode->i_cdev,
+                       struct ublk_device, cdev);
+
+       if (test_and_set_bit(UB_STATE_OPEN, &ub->state))
+               return -EBUSY;
+       filp->private_data = ub;
+       return 0;
+}
+
+static int ublk_ch_release(struct inode *inode, struct file *filp)
+{
+       struct ublk_device *ub = filp->private_data;
+
+       clear_bit(UB_STATE_OPEN, &ub->state);
+       return 0;
+}
+
+/* map pre-allocated per-queue cmd buffer to ublksrv daemon */
+static int ublk_ch_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct ublk_device *ub = filp->private_data;
+       size_t sz = vma->vm_end - vma->vm_start;
+       unsigned max_sz = UBLK_MAX_QUEUE_DEPTH * sizeof(struct ublksrv_io_desc);
+       unsigned long pfn, end, phys_off = vma->vm_pgoff << PAGE_SHIFT;
+       int q_id, ret = 0;
+
+       spin_lock(&ub->mm_lock);
+       if (!ub->mm)
+               ub->mm = current->mm;
+       if (current->mm != ub->mm)
+               ret = -EINVAL;
+       spin_unlock(&ub->mm_lock);
+
+       if (ret)
+               return ret;
+
+       if (vma->vm_flags & VM_WRITE)
+               return -EPERM;
+
+       end = UBLKSRV_CMD_BUF_OFFSET + ub->dev_info.nr_hw_queues * max_sz;
+       if (phys_off < UBLKSRV_CMD_BUF_OFFSET || phys_off >= end)
+               return -EINVAL;
+
+       q_id = (phys_off - UBLKSRV_CMD_BUF_OFFSET) / max_sz;
+       pr_devel("%s: qid %d, pid %d, addr %lx pg_off %lx sz %lu\n",
+                       __func__, q_id, current->pid, vma->vm_start,
+                       phys_off, (unsigned long)sz);
+
+       if (sz != ublk_queue_cmd_buf_size(ub, q_id))
+               return -EINVAL;
+
+       pfn = virt_to_phys(ublk_queue_cmd_buf(ub, q_id)) >> PAGE_SHIFT;
+       return remap_pfn_range(vma, vma->vm_start, pfn, sz, vma->vm_page_prot);
+}
+
+static void ublk_commit_completion(struct ublk_device *ub,
+               struct ublksrv_io_cmd *ub_cmd)
+{
+       u32 qid = ub_cmd->q_id, tag = ub_cmd->tag;
+       struct ublk_queue *ubq = ublk_get_queue(ub, qid);
+       struct ublk_io *io = &ubq->ios[tag];
+       struct request *req;
+
+       /* now this cmd slot is owned by nbd driver */
+       io->flags &= ~UBLK_IO_FLAG_OWNED_BY_SRV;
+       io->res = ub_cmd->result;
+
+       /* find the io request and complete */
+       req = blk_mq_tag_to_rq(ub->tag_set.tags[qid], tag);
+
+       if (req && likely(!blk_should_fake_timeout(req->q)))
+               ublk_complete_rq(req);
+}
+
+/*
+ * When ->ubq_daemon is exiting, either new request is ended immediately,
+ * or any queued io command is drained, so it is safe to abort queue
+ * lockless
+ */
+static void ublk_abort_queue(struct ublk_device *ub, struct ublk_queue *ubq)
+{
+       int i;
+
+       if (!ublk_get_device(ub))
+               return;
+
+       for (i = 0; i < ubq->q_depth; i++) {
+               struct ublk_io *io = &ubq->ios[i];
+
+               if (!(io->flags & UBLK_IO_FLAG_ACTIVE)) {
+                       struct request *rq;
+
+                       /*
+                        * Either we fail the request or ublk_rq_task_work_fn
+                        * will do it
+                        */
+                       rq = blk_mq_tag_to_rq(ub->tag_set.tags[ubq->q_id], i);
+                       if (rq)
+                               __ublk_fail_req(io, rq);
+               }
+       }
+       ublk_put_device(ub);
+}
+
+static void ublk_daemon_monitor_work(struct work_struct *work)
+{
+       struct ublk_device *ub =
+               container_of(work, struct ublk_device, monitor_work.work);
+       int i;
+
+       for (i = 0; i < ub->dev_info.nr_hw_queues; i++) {
+               struct ublk_queue *ubq = ublk_get_queue(ub, i);
+
+               if (ubq_daemon_is_dying(ubq)) {
+                       schedule_work(&ub->stop_work);
+
+                       /* abort queue is for making forward progress */
+                       ublk_abort_queue(ub, ubq);
+               }
+       }
+
+       /*
+        * We can't schedule monitor work after ublk_remove() is started.
+        *
+        * No need ub->mutex, monitor work are canceled after state is marked
+        * as DEAD, so DEAD state is observed reliably.
+        */
+       if (ub->dev_info.state != UBLK_S_DEV_DEAD)
+               schedule_delayed_work(&ub->monitor_work,
+                               UBLK_DAEMON_MONITOR_PERIOD);
+}
+
+static void ublk_cancel_queue(struct ublk_queue *ubq)
+{
+       int i;
+
+       for (i = 0; i < ubq->q_depth; i++) {
+               struct ublk_io *io = &ubq->ios[i];
+
+               if (io->flags & UBLK_IO_FLAG_ACTIVE)
+                       io_uring_cmd_done(io->cmd, UBLK_IO_RES_ABORT, 0);
+       }
+}
+
+/* Cancel all pending commands, must be called after del_gendisk() returns */
+static void ublk_cancel_dev(struct ublk_device *ub)
+{
+       int i;
+
+       for (i = 0; i < ub->dev_info.nr_hw_queues; i++)
+               ublk_cancel_queue(ublk_get_queue(ub, i));
+}
+
+static void ublk_stop_dev(struct ublk_device *ub)
+{
+       mutex_lock(&ub->mutex);
+       if (ub->dev_info.state != UBLK_S_DEV_LIVE)
+               goto unlock;
+
+       del_gendisk(ub->ub_disk);
+       ub->dev_info.state = UBLK_S_DEV_DEAD;
+       ub->dev_info.ublksrv_pid = -1;
+       ublk_cancel_dev(ub);
+       put_disk(ub->ub_disk);
+       ub->ub_disk = NULL;
+ unlock:
+       mutex_unlock(&ub->mutex);
+       cancel_delayed_work_sync(&ub->monitor_work);
+}
+
+static inline bool ublk_queue_ready(struct ublk_queue *ubq)
+{
+       return ubq->nr_io_ready == ubq->q_depth;
+}
+
+/* device can only be started after all IOs are ready */
+static void ublk_mark_io_ready(struct ublk_device *ub, struct ublk_queue *ubq)
+{
+       mutex_lock(&ub->mutex);
+       ubq->nr_io_ready++;
+       if (ublk_queue_ready(ubq)) {
+               ubq->ubq_daemon = current;
+               get_task_struct(ubq->ubq_daemon);
+               ub->nr_queues_ready++;
+       }
+       if (ub->nr_queues_ready == ub->dev_info.nr_hw_queues)
+               complete_all(&ub->completion);
+       mutex_unlock(&ub->mutex);
+}
+
+static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
+{
+       struct ublksrv_io_cmd *ub_cmd = (struct ublksrv_io_cmd *)cmd->cmd;
+       struct ublk_device *ub = cmd->file->private_data;
+       struct ublk_queue *ubq;
+       struct ublk_io *io;
+       u32 cmd_op = cmd->cmd_op;
+       unsigned tag = ub_cmd->tag;
+       int ret = -EINVAL;
+
+       pr_devel("%s: received: cmd op %d queue %d tag %d result %d\n",
+                       __func__, cmd->cmd_op, ub_cmd->q_id, tag,
+                       ub_cmd->result);
+
+       if (!(issue_flags & IO_URING_F_SQE128))
+               goto out;
+
+       if (ub_cmd->q_id >= ub->dev_info.nr_hw_queues)
+               goto out;
+
+       ubq = ublk_get_queue(ub, ub_cmd->q_id);
+       if (!ubq || ub_cmd->q_id != ubq->q_id)
+               goto out;
+
+       if (ubq->ubq_daemon && ubq->ubq_daemon != current)
+               goto out;
+
+       if (tag >= ubq->q_depth)
+               goto out;
+
+       io = &ubq->ios[tag];
+
+       /* there is pending io cmd, something must be wrong */
+       if (io->flags & UBLK_IO_FLAG_ACTIVE) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       switch (cmd_op) {
+       case UBLK_IO_FETCH_REQ:
+               /* UBLK_IO_FETCH_REQ is only allowed before queue is setup */
+               if (ublk_queue_ready(ubq)) {
+                       ret = -EBUSY;
+                       goto out;
+               }
+               /*
+                * The io is being handled by server, so COMMIT_RQ is expected
+                * instead of FETCH_REQ
+                */
+               if (io->flags & UBLK_IO_FLAG_OWNED_BY_SRV)
+                       goto out;
+               /* FETCH_RQ has to provide IO buffer */
+               if (!ub_cmd->addr)
+                       goto out;
+               io->cmd = cmd;
+               io->flags |= UBLK_IO_FLAG_ACTIVE;
+               io->addr = ub_cmd->addr;
+
+               ublk_mark_io_ready(ub, ubq);
+               break;
+       case UBLK_IO_COMMIT_AND_FETCH_REQ:
+               /* FETCH_RQ has to provide IO buffer */
+               if (!ub_cmd->addr)
+                       goto out;
+               if (!(io->flags & UBLK_IO_FLAG_OWNED_BY_SRV))
+                       goto out;
+               io->addr = ub_cmd->addr;
+               io->flags |= UBLK_IO_FLAG_ACTIVE;
+               io->cmd = cmd;
+               ublk_commit_completion(ub, ub_cmd);
+               break;
+       default:
+               goto out;
+       }
+       return -EIOCBQUEUED;
+
+ out:
+       io_uring_cmd_done(cmd, ret, 0);
+       pr_devel("%s: complete: cmd op %d, tag %d ret %x io_flags %x\n",
+                       __func__, cmd_op, tag, ret, io->flags);
+       return -EIOCBQUEUED;
+}
+
+static const struct file_operations ublk_ch_fops = {
+       .owner = THIS_MODULE,
+       .open = ublk_ch_open,
+       .release = ublk_ch_release,
+       .llseek = no_llseek,
+       .uring_cmd = ublk_ch_uring_cmd,
+       .mmap = ublk_ch_mmap,
+};
+
+static void ublk_deinit_queue(struct ublk_device *ub, int q_id)
+{
+       int size = ublk_queue_cmd_buf_size(ub, q_id);
+       struct ublk_queue *ubq = ublk_get_queue(ub, q_id);
+
+       if (ubq->ubq_daemon)
+               put_task_struct(ubq->ubq_daemon);
+       if (ubq->io_cmd_buf)
+               free_pages((unsigned long)ubq->io_cmd_buf, get_order(size));
+}
+
+static int ublk_init_queue(struct ublk_device *ub, int q_id)
+{
+       struct ublk_queue *ubq = ublk_get_queue(ub, q_id);
+       gfp_t gfp_flags = GFP_KERNEL | __GFP_ZERO;
+       void *ptr;
+       int size;
+
+       ubq->flags = ub->dev_info.flags;
+       ubq->q_id = q_id;
+       ubq->q_depth = ub->dev_info.queue_depth;
+       size = ublk_queue_cmd_buf_size(ub, q_id);
+
+       ptr = (void *) __get_free_pages(gfp_flags, get_order(size));
+       if (!ptr)
+               return -ENOMEM;
+
+       ubq->io_cmd_buf = ptr;
+       ubq->dev = ub;
+       return 0;
+}
+
+static void ublk_deinit_queues(struct ublk_device *ub)
+{
+       int nr_queues = ub->dev_info.nr_hw_queues;
+       int i;
+
+       if (!ub->__queues)
+               return;
+
+       for (i = 0; i < nr_queues; i++)
+               ublk_deinit_queue(ub, i);
+       kfree(ub->__queues);
+}
+
+static int ublk_init_queues(struct ublk_device *ub)
+{
+       int nr_queues = ub->dev_info.nr_hw_queues;
+       int depth = ub->dev_info.queue_depth;
+       int ubq_size = sizeof(struct ublk_queue) + depth * sizeof(struct ublk_io);
+       int i, ret = -ENOMEM;
+
+       ub->queue_size = ubq_size;
+       ub->__queues = kcalloc(nr_queues, ubq_size, GFP_KERNEL);
+       if (!ub->__queues)
+               return ret;
+
+       for (i = 0; i < nr_queues; i++) {
+               if (ublk_init_queue(ub, i))
+                       goto fail;
+       }
+
+       init_completion(&ub->completion);
+       return 0;
+
+ fail:
+       ublk_deinit_queues(ub);
+       return ret;
+}
+
+static int ublk_alloc_dev_number(struct ublk_device *ub, int idx)
+{
+       int i = idx;
+       int err;
+
+       spin_lock(&ublk_idr_lock);
+       /* allocate id, if @id >= 0, we're requesting that specific id */
+       if (i >= 0) {
+               err = idr_alloc(&ublk_index_idr, ub, i, i + 1, GFP_NOWAIT);
+               if (err == -ENOSPC)
+                       err = -EEXIST;
+       } else {
+               err = idr_alloc(&ublk_index_idr, ub, 0, 0, GFP_NOWAIT);
+       }
+       spin_unlock(&ublk_idr_lock);
+
+       if (err >= 0)
+               ub->ub_number = err;
+
+       return err;
+}
+
+static void ublk_free_dev_number(struct ublk_device *ub)
+{
+       spin_lock(&ublk_idr_lock);
+       idr_remove(&ublk_index_idr, ub->ub_number);
+       wake_up_all(&ublk_idr_wq);
+       spin_unlock(&ublk_idr_lock);
+}
+
+static void ublk_cdev_rel(struct device *dev)
+{
+       struct ublk_device *ub = container_of(dev, struct ublk_device, cdev_dev);
+
+       blk_mq_free_tag_set(&ub->tag_set);
+       ublk_deinit_queues(ub);
+       ublk_free_dev_number(ub);
+       mutex_destroy(&ub->mutex);
+       kfree(ub);
+}
+
+static int ublk_add_chdev(struct ublk_device *ub)
+{
+       struct device *dev = &ub->cdev_dev;
+       int minor = ub->ub_number;
+       int ret;
+
+       dev->parent = ublk_misc.this_device;
+       dev->devt = MKDEV(MAJOR(ublk_chr_devt), minor);
+       dev->class = ublk_chr_class;
+       dev->release = ublk_cdev_rel;
+       device_initialize(dev);
+
+       ret = dev_set_name(dev, "ublkc%d", minor);
+       if (ret)
+               goto fail;
+
+       cdev_init(&ub->cdev, &ublk_ch_fops);
+       ret = cdev_device_add(&ub->cdev, dev);
+       if (ret)
+               goto fail;
+       return 0;
+ fail:
+       put_device(dev);
+       return ret;
+}
+
+static void ublk_stop_work_fn(struct work_struct *work)
+{
+       struct ublk_device *ub =
+               container_of(work, struct ublk_device, stop_work);
+
+       ublk_stop_dev(ub);
+}
+
+/* align maximum I/O size to PAGE_SIZE */
+static void ublk_align_max_io_size(struct ublk_device *ub)
+{
+       unsigned int max_rq_bytes = ub->dev_info.rq_max_blocks << ub->bs_shift;
+
+       ub->dev_info.rq_max_blocks =
+               round_down(max_rq_bytes, PAGE_SIZE) >> ub->bs_shift;
+}
+
+static int ublk_add_tag_set(struct ublk_device *ub)
+{
+       ub->tag_set.ops = &ublk_mq_ops;
+       ub->tag_set.nr_hw_queues = ub->dev_info.nr_hw_queues;
+       ub->tag_set.queue_depth = ub->dev_info.queue_depth;
+       ub->tag_set.numa_node = NUMA_NO_NODE;
+       ub->tag_set.cmd_size = sizeof(struct ublk_rq_data);
+       ub->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
+       ub->tag_set.driver_data = ub;
+       return blk_mq_alloc_tag_set(&ub->tag_set);
+}
+
+static void ublk_remove(struct ublk_device *ub)
+{
+       ublk_stop_dev(ub);
+       cancel_work_sync(&ub->stop_work);
+       cdev_device_del(&ub->cdev, &ub->cdev_dev);
+       put_device(&ub->cdev_dev);
+}
+
+static struct ublk_device *ublk_get_device_from_id(int idx)
+{
+       struct ublk_device *ub = NULL;
+
+       if (idx < 0)
+               return NULL;
+
+       spin_lock(&ublk_idr_lock);
+       ub = idr_find(&ublk_index_idr, idx);
+       if (ub)
+               ub = ublk_get_device(ub);
+       spin_unlock(&ublk_idr_lock);
+
+       return ub;
+}
+
+static int ublk_ctrl_start_dev(struct io_uring_cmd *cmd)
+{
+       struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd;
+       int ublksrv_pid = (int)header->data[0];
+       unsigned long dev_blocks = header->data[1];
+       struct ublk_device *ub;
+       struct gendisk *disk;
+       int ret = -EINVAL;
+
+       if (ublksrv_pid <= 0)
+               return -EINVAL;
+
+       ub = ublk_get_device_from_id(header->dev_id);
+       if (!ub)
+               return -EINVAL;
+
+       wait_for_completion_interruptible(&ub->completion);
+
+       schedule_delayed_work(&ub->monitor_work, UBLK_DAEMON_MONITOR_PERIOD);
+
+       mutex_lock(&ub->mutex);
+       if (ub->dev_info.state == UBLK_S_DEV_LIVE ||
+           test_bit(UB_STATE_USED, &ub->state)) {
+               ret = -EEXIST;
+               goto out_unlock;
+       }
+
+       /* We may get disk size updated */
+       if (dev_blocks)
+               ub->dev_info.dev_blocks = dev_blocks;
+
+       disk = blk_mq_alloc_disk(&ub->tag_set, ub);
+       if (IS_ERR(disk)) {
+               ret = PTR_ERR(disk);
+               goto out_unlock;
+       }
+       sprintf(disk->disk_name, "ublkb%d", ub->ub_number);
+       disk->fops = &ub_fops;
+       disk->private_data = ub;
+
+       blk_queue_logical_block_size(disk->queue, ub->dev_info.block_size);
+       blk_queue_physical_block_size(disk->queue, ub->dev_info.block_size);
+       blk_queue_io_min(disk->queue, ub->dev_info.block_size);
+       blk_queue_max_hw_sectors(disk->queue,
+               ub->dev_info.rq_max_blocks << (ub->bs_shift - 9));
+       disk->queue->limits.discard_granularity = PAGE_SIZE;
+       blk_queue_max_discard_sectors(disk->queue, UINT_MAX >> 9);
+       blk_queue_max_write_zeroes_sectors(disk->queue, UINT_MAX >> 9);
+
+       set_capacity(disk, ub->dev_info.dev_blocks << (ub->bs_shift - 9));
+
+       ub->dev_info.ublksrv_pid = ublksrv_pid;
+       ub->ub_disk = disk;
+       get_device(&ub->cdev_dev);
+       ret = add_disk(disk);
+       if (ret) {
+               put_disk(disk);
+               goto out_unlock;
+       }
+       set_bit(UB_STATE_USED, &ub->state);
+       ub->dev_info.state = UBLK_S_DEV_LIVE;
+out_unlock:
+       mutex_unlock(&ub->mutex);
+       ublk_put_device(ub);
+       return ret;
+}
+
+static int ublk_ctrl_get_queue_affinity(struct io_uring_cmd *cmd)
+{
+       struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd;
+       void __user *argp = (void __user *)(unsigned long)header->addr;
+       struct ublk_device *ub;
+       cpumask_var_t cpumask;
+       unsigned long queue;
+       unsigned int retlen;
+       unsigned int i;
+       int ret = -EINVAL;
+       
+       if (header->len * BITS_PER_BYTE < nr_cpu_ids)
+               return -EINVAL;
+       if (header->len & (sizeof(unsigned long)-1))
+               return -EINVAL;
+       if (!header->addr)
+               return -EINVAL;
+
+       ub = ublk_get_device_from_id(header->dev_id);
+       if (!ub)
+               return -EINVAL;
+
+       queue = header->data[0];
+       if (queue >= ub->dev_info.nr_hw_queues)
+               goto out_put_device;
+
+       ret = -ENOMEM;
+       if (!zalloc_cpumask_var(&cpumask, GFP_KERNEL))
+               goto out_put_device;
+
+       for_each_possible_cpu(i) {
+               if (ub->tag_set.map[HCTX_TYPE_DEFAULT].mq_map[i] == queue)
+                       cpumask_set_cpu(i, cpumask);
+       }
+
+       ret = -EFAULT;
+       retlen = min_t(unsigned short, header->len, cpumask_size());
+       if (copy_to_user(argp, cpumask, retlen))
+               goto out_free_cpumask;
+       if (retlen != header->len &&
+           clear_user(argp + retlen, header->len - retlen))
+               goto out_free_cpumask;
+
+       ret = 0;
+out_free_cpumask:
+       free_cpumask_var(cpumask);
+out_put_device:
+       ublk_put_device(ub);
+       return ret;
+}
+
+static inline void ublk_dump_dev_info(struct ublksrv_ctrl_dev_info *info)
+{
+       pr_devel("%s: dev id %d flags %llx\n", __func__,
+                       info->dev_id, info->flags);
+       pr_devel("\t nr_hw_queues %d queue_depth %d block size %d dev_capacity %lld\n",
+                       info->nr_hw_queues, info->queue_depth,
+                       info->block_size, info->dev_blocks);
+}
+
+static int ublk_ctrl_add_dev(struct io_uring_cmd *cmd)
+{
+       struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd;
+       void __user *argp = (void __user *)(unsigned long)header->addr;
+       struct ublksrv_ctrl_dev_info info;
+       struct ublk_device *ub;
+       int ret = -EINVAL;
+
+       if (header->len < sizeof(info) || !header->addr)
+               return -EINVAL;
+       if (header->queue_id != (u16)-1) {
+               pr_warn("%s: queue_id is wrong %x\n",
+                       __func__, header->queue_id);
+               return -EINVAL;
+       }
+       if (copy_from_user(&info, argp, sizeof(info)))
+               return -EFAULT;
+       ublk_dump_dev_info(&info);
+       if (header->dev_id != info.dev_id) {
+               pr_warn("%s: dev id not match %u %u\n",
+                       __func__, header->dev_id, info.dev_id);
+               return -EINVAL;
+       }
+
+       ret = mutex_lock_killable(&ublk_ctl_mutex);
+       if (ret)
+               return ret;
+
+       ret = -ENOMEM;
+       ub = kzalloc(sizeof(*ub), GFP_KERNEL);
+       if (!ub)
+               goto out_unlock;
+       mutex_init(&ub->mutex);
+       spin_lock_init(&ub->mm_lock);
+       INIT_WORK(&ub->stop_work, ublk_stop_work_fn);
+       INIT_DELAYED_WORK(&ub->monitor_work, ublk_daemon_monitor_work);
+
+       ret = ublk_alloc_dev_number(ub, header->dev_id);
+       if (ret < 0)
+               goto out_free_ub;
+
+       memcpy(&ub->dev_info, &info, sizeof(info));
+
+       /* update device id */
+       ub->dev_info.dev_id = ub->ub_number;
+
+       /*
+        * 64bit flags will be copied back to userspace as feature
+        * negotiation result, so have to clear flags which driver
+        * doesn't support yet, then userspace can get correct flags
+        * (features) to handle.
+        */
+       ub->dev_info.flags &= UBLK_F_ALL;
+
+       /* We are not ready to support zero copy */
+       ub->dev_info.flags &= ~UBLK_F_SUPPORT_ZERO_COPY;
+
+       ub->bs_shift = ilog2(ub->dev_info.block_size);
+       ub->dev_info.nr_hw_queues = min_t(unsigned int,
+                       ub->dev_info.nr_hw_queues, nr_cpu_ids);
+       ublk_align_max_io_size(ub);
+
+       ret = ublk_init_queues(ub);
+       if (ret)
+               goto out_free_dev_number;
+
+       ret = ublk_add_tag_set(ub);
+       if (ret)
+               goto out_deinit_queues;
+
+       ret = -EFAULT;
+       if (copy_to_user(argp, &ub->dev_info, sizeof(info)))
+               goto out_free_tag_set;
+
+       /*
+        * Add the char dev so that ublksrv daemon can be setup.
+        * ublk_add_chdev() will cleanup everything if it fails.
+        */
+       ret = ublk_add_chdev(ub);
+       goto out_unlock;
+
+out_free_tag_set:
+       blk_mq_free_tag_set(&ub->tag_set);
+out_deinit_queues:
+       ublk_deinit_queues(ub);
+out_free_dev_number:
+       ublk_free_dev_number(ub);
+out_free_ub:
+       mutex_destroy(&ub->mutex);
+       kfree(ub);
+out_unlock:
+       mutex_unlock(&ublk_ctl_mutex);
+       return ret;
+}
+
+static inline bool ublk_idr_freed(int id)
+{
+       void *ptr;
+
+       spin_lock(&ublk_idr_lock);
+       ptr = idr_find(&ublk_index_idr, id);
+       spin_unlock(&ublk_idr_lock);
+
+       return ptr == NULL;
+}
+
+static int ublk_ctrl_del_dev(int idx)
+{
+       struct ublk_device *ub;
+       int ret;
+
+       ret = mutex_lock_killable(&ublk_ctl_mutex);
+       if (ret)
+               return ret;
+
+       ub = ublk_get_device_from_id(idx);
+       if (ub) {
+               ublk_remove(ub);
+               ublk_put_device(ub);
+               ret = 0;
+       } else {
+               ret = -ENODEV;
+       }
+
+       /*
+        * Wait until the idr is removed, then it can be reused after
+        * DEL_DEV command is returned.
+        */
+       if (!ret)
+               wait_event(ublk_idr_wq, ublk_idr_freed(idx));
+       mutex_unlock(&ublk_ctl_mutex);
+
+       return ret;
+}
+
+static inline void ublk_ctrl_cmd_dump(struct io_uring_cmd *cmd)
+{
+       struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd;
+
+       pr_devel("%s: cmd_op %x, dev id %d qid %d data %llx buf %llx len %u\n",
+                       __func__, cmd->cmd_op, header->dev_id, header->queue_id,
+                       header->data[0], header->addr, header->len);
+}
+
+static int ublk_ctrl_stop_dev(struct io_uring_cmd *cmd)
+{
+       struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd;
+       struct ublk_device *ub;
+
+       ub = ublk_get_device_from_id(header->dev_id);
+       if (!ub)
+               return -EINVAL;
+
+       ublk_stop_dev(ub);
+       cancel_work_sync(&ub->stop_work);
+
+       ublk_put_device(ub);
+       return 0;
+}
+
+static int ublk_ctrl_get_dev_info(struct io_uring_cmd *cmd)
+{
+       struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd;
+       void __user *argp = (void __user *)(unsigned long)header->addr;
+       struct ublk_device *ub;
+       int ret = 0;
+
+       if (header->len < sizeof(struct ublksrv_ctrl_dev_info) || !header->addr)
+               return -EINVAL;
+
+       ub = ublk_get_device_from_id(header->dev_id);
+       if (!ub)
+               return -EINVAL;
+
+       if (copy_to_user(argp, &ub->dev_info, sizeof(ub->dev_info)))
+               ret = -EFAULT;
+       ublk_put_device(ub);
+
+       return ret;
+}
+
+static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd,
+               unsigned int issue_flags)
+{
+       struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd;
+       int ret = -EINVAL;
+
+       ublk_ctrl_cmd_dump(cmd);
+
+       if (!(issue_flags & IO_URING_F_SQE128))
+               goto out;
+
+       ret = -EPERM;
+       if (!capable(CAP_SYS_ADMIN))
+               goto out;
+
+       ret = -ENODEV;
+       switch (cmd->cmd_op) {
+       case UBLK_CMD_START_DEV:
+               ret = ublk_ctrl_start_dev(cmd);
+               break;
+       case UBLK_CMD_STOP_DEV:
+               ret = ublk_ctrl_stop_dev(cmd);
+               break;
+       case UBLK_CMD_GET_DEV_INFO:
+               ret = ublk_ctrl_get_dev_info(cmd);
+               break;
+       case UBLK_CMD_ADD_DEV:
+               ret = ublk_ctrl_add_dev(cmd);
+               break;
+       case UBLK_CMD_DEL_DEV:
+               ret = ublk_ctrl_del_dev(header->dev_id);
+               break;
+       case UBLK_CMD_GET_QUEUE_AFFINITY:
+               ret = ublk_ctrl_get_queue_affinity(cmd);
+               break;
+       default:
+               break;
+       }
+ out:
+       io_uring_cmd_done(cmd, ret, 0);
+       pr_devel("%s: cmd done ret %d cmd_op %x, dev id %d qid %d\n",
+                       __func__, ret, cmd->cmd_op, header->dev_id, header->queue_id);
+       return -EIOCBQUEUED;
+}
+
+static const struct file_operations ublk_ctl_fops = {
+       .open           = nonseekable_open,
+       .uring_cmd      = ublk_ctrl_uring_cmd,
+       .owner          = THIS_MODULE,
+       .llseek         = noop_llseek,
+};
+
+static struct miscdevice ublk_misc = {
+       .minor          = MISC_DYNAMIC_MINOR,
+       .name           = "ublk-control",
+       .fops           = &ublk_ctl_fops,
+};
+
+static int __init ublk_init(void)
+{
+       int ret;
+
+       init_waitqueue_head(&ublk_idr_wq);
+
+       ret = misc_register(&ublk_misc);
+       if (ret)
+               return ret;
+
+       ret = alloc_chrdev_region(&ublk_chr_devt, 0, UBLK_MINORS, "ublk-char");
+       if (ret)
+               goto unregister_mis;
+
+       ublk_chr_class = class_create(THIS_MODULE, "ublk-char");
+       if (IS_ERR(ublk_chr_class)) {
+               ret = PTR_ERR(ublk_chr_class);
+               goto free_chrdev_region;
+       }
+       return 0;
+
+free_chrdev_region:
+       unregister_chrdev_region(ublk_chr_devt, UBLK_MINORS);
+unregister_mis:
+       misc_deregister(&ublk_misc);
+       return ret;
+}
+
+static void __exit ublk_exit(void)
+{
+       struct ublk_device *ub;
+       int id;
+
+       class_destroy(ublk_chr_class);
+
+       misc_deregister(&ublk_misc);
+
+       idr_for_each_entry(&ublk_index_idr, ub, id)
+               ublk_remove(ub);
+
+       idr_destroy(&ublk_index_idr);
+       unregister_chrdev_region(ublk_chr_devt, UBLK_MINORS);
+}
+
+module_init(ublk_init);
+module_exit(ublk_exit);
+
+MODULE_AUTHOR("Ming Lei <ming.lei@redhat.com>");
+MODULE_LICENSE("GPL");
index 6fc7850..d7d72e8 100644 (file)
@@ -1089,7 +1089,7 @@ static int virtblk_probe(struct virtio_device *vdev)
        return 0;
 
 out_cleanup_disk:
-       blk_cleanup_disk(vblk->disk);
+       put_disk(vblk->disk);
 out_free_tags:
        blk_mq_free_tag_set(&vblk->tag_set);
 out_free_vq:
@@ -1111,7 +1111,6 @@ static void virtblk_remove(struct virtio_device *vdev)
        flush_work(&vblk->config_work);
 
        del_gendisk(vblk->disk);
-       blk_cleanup_queue(vblk->disk->queue);
        blk_mq_free_tag_set(&vblk->tag_set);
 
        mutex_lock(&vblk->vdev_mutex);
index a97f2bf..a5cf7f1 100644 (file)
@@ -442,7 +442,7 @@ static void free_req(struct xen_blkif_ring *ring, struct pending_req *req)
  * Routines for managing virtual block devices (vbds).
  */
 static int xen_vbd_translate(struct phys_req *req, struct xen_blkif *blkif,
-                            int operation)
+                            enum req_op operation)
 {
        struct xen_vbd *vbd = &blkif->vbd;
        int rc = -EACCES;
@@ -1193,8 +1193,8 @@ static int dispatch_rw_block_io(struct xen_blkif_ring *ring,
        struct bio *bio = NULL;
        struct bio **biolist = pending_req->biolist;
        int i, nbio = 0;
-       int operation;
-       int operation_flags = 0;
+       enum req_op operation;
+       blk_opf_t operation_flags = 0;
        struct blk_plug plug;
        bool drain = false;
        struct grant_page **pages = pending_req->segments;
index 33f04ef..dc48298 100644 (file)
@@ -152,6 +152,10 @@ static unsigned int xen_blkif_max_ring_order;
 module_param_named(max_ring_page_order, xen_blkif_max_ring_order, int, 0444);
 MODULE_PARM_DESC(max_ring_page_order, "Maximum order of pages to be used for the shared ring");
 
+static bool __read_mostly xen_blkif_trusted = true;
+module_param_named(trusted, xen_blkif_trusted, bool, 0644);
+MODULE_PARM_DESC(trusted, "Is the backend trusted");
+
 #define BLK_RING_SIZE(info)    \
        __CONST_RING_SIZE(blkif, XEN_PAGE_SIZE * (info)->nr_ring_pages)
 
@@ -210,6 +214,7 @@ struct blkfront_info
        unsigned int feature_discard:1;
        unsigned int feature_secdiscard:1;
        unsigned int feature_persistent:1;
+       unsigned int bounce:1;
        unsigned int discard_granularity;
        unsigned int discard_alignment;
        /* Number of 4KB segments handled */
@@ -310,8 +315,8 @@ static int fill_grant_buffer(struct blkfront_ring_info *rinfo, int num)
                if (!gnt_list_entry)
                        goto out_of_memory;
 
-               if (info->feature_persistent) {
-                       granted_page = alloc_page(GFP_NOIO);
+               if (info->bounce) {
+                       granted_page = alloc_page(GFP_NOIO | __GFP_ZERO);
                        if (!granted_page) {
                                kfree(gnt_list_entry);
                                goto out_of_memory;
@@ -330,7 +335,7 @@ out_of_memory:
        list_for_each_entry_safe(gnt_list_entry, n,
                                 &rinfo->grants, node) {
                list_del(&gnt_list_entry->node);
-               if (info->feature_persistent)
+               if (info->bounce)
                        __free_page(gnt_list_entry->page);
                kfree(gnt_list_entry);
                i--;
@@ -376,7 +381,7 @@ static struct grant *get_grant(grant_ref_t *gref_head,
        /* Assign a gref to this page */
        gnt_list_entry->gref = gnttab_claim_grant_reference(gref_head);
        BUG_ON(gnt_list_entry->gref == -ENOSPC);
-       if (info->feature_persistent)
+       if (info->bounce)
                grant_foreign_access(gnt_list_entry, info);
        else {
                /* Grant access to the GFN passed by the caller */
@@ -400,7 +405,7 @@ static struct grant *get_indirect_grant(grant_ref_t *gref_head,
        /* Assign a gref to this page */
        gnt_list_entry->gref = gnttab_claim_grant_reference(gref_head);
        BUG_ON(gnt_list_entry->gref == -ENOSPC);
-       if (!info->feature_persistent) {
+       if (!info->bounce) {
                struct page *indirect_page;
 
                /* Fetch a pre-allocated page to use for indirect grefs */
@@ -703,7 +708,7 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri
                .grant_idx = 0,
                .segments = NULL,
                .rinfo = rinfo,
-               .need_copy = rq_data_dir(req) && info->feature_persistent,
+               .need_copy = rq_data_dir(req) && info->bounce,
        };
 
        /*
@@ -981,11 +986,12 @@ static void xlvbd_flush(struct blkfront_info *info)
 {
        blk_queue_write_cache(info->rq, info->feature_flush ? true : false,
                              info->feature_fua ? true : false);
-       pr_info("blkfront: %s: %s %s %s %s %s\n",
+       pr_info("blkfront: %s: %s %s %s %s %s %s %s\n",
                info->gd->disk_name, flush_info(info),
                "persistent grants:", info->feature_persistent ?
                "enabled;" : "disabled;", "indirect descriptors:",
-               info->max_indirect_segments ? "enabled;" : "disabled;");
+               info->max_indirect_segments ? "enabled;" : "disabled;",
+               "bounce buffer:", info->bounce ? "enabled" : "disabled;");
 }
 
 static int xen_translate_vdev(int vdevice, int *minor, unsigned int *offset)
@@ -1207,7 +1213,7 @@ static void blkif_free_ring(struct blkfront_ring_info *rinfo)
        if (!list_empty(&rinfo->indirect_pages)) {
                struct page *indirect_page, *n;
 
-               BUG_ON(info->feature_persistent);
+               BUG_ON(info->bounce);
                list_for_each_entry_safe(indirect_page, n, &rinfo->indirect_pages, lru) {
                        list_del(&indirect_page->lru);
                        __free_page(indirect_page);
@@ -1224,7 +1230,7 @@ static void blkif_free_ring(struct blkfront_ring_info *rinfo)
                                                          NULL);
                                rinfo->persistent_gnts_c--;
                        }
-                       if (info->feature_persistent)
+                       if (info->bounce)
                                __free_page(persistent_gnt->page);
                        kfree(persistent_gnt);
                }
@@ -1245,7 +1251,7 @@ static void blkif_free_ring(struct blkfront_ring_info *rinfo)
                for (j = 0; j < segs; j++) {
                        persistent_gnt = rinfo->shadow[i].grants_used[j];
                        gnttab_end_foreign_access(persistent_gnt->gref, NULL);
-                       if (info->feature_persistent)
+                       if (info->bounce)
                                __free_page(persistent_gnt->page);
                        kfree(persistent_gnt);
                }
@@ -1428,7 +1434,7 @@ static int blkif_completion(unsigned long *id,
        data.s = s;
        num_sg = s->num_sg;
 
-       if (bret->operation == BLKIF_OP_READ && info->feature_persistent) {
+       if (bret->operation == BLKIF_OP_READ && info->bounce) {
                for_each_sg(s->sg, sg, num_sg, i) {
                        BUG_ON(sg->offset + sg->length > PAGE_SIZE);
 
@@ -1487,7 +1493,7 @@ static int blkif_completion(unsigned long *id,
                                 * Add the used indirect page back to the list of
                                 * available pages for indirect grefs.
                                 */
-                               if (!info->feature_persistent) {
+                               if (!info->bounce) {
                                        indirect_page = s->indirect_grants[i]->page;
                                        list_add(&indirect_page->lru, &rinfo->indirect_pages);
                                }
@@ -1764,6 +1770,10 @@ static int talk_to_blkback(struct xenbus_device *dev,
        if (!info)
                return -ENODEV;
 
+       /* Check if backend is trusted. */
+       info->bounce = !xen_blkif_trusted ||
+                      !xenbus_read_unsigned(dev->nodename, "trusted", 1);
+
        max_page_order = xenbus_read_unsigned(info->xbdev->otherend,
                                              "max-ring-page-order", 0);
        ring_page_order = min(xen_blkif_max_ring_order, max_page_order);
@@ -2173,17 +2183,18 @@ static int blkfront_setup_indirect(struct blkfront_ring_info *rinfo)
        if (err)
                goto out_of_memory;
 
-       if (!info->feature_persistent && info->max_indirect_segments) {
+       if (!info->bounce && info->max_indirect_segments) {
                /*
-                * We are using indirect descriptors but not persistent
-                * grants, we need to allocate a set of pages that can be
+                * We are using indirect descriptors but don't have a bounce
+                * buffer, we need to allocate a set of pages that can be
                 * used for mapping indirect grefs
                 */
                int num = INDIRECT_GREFS(grants) * BLK_RING_SIZE(info);
 
                BUG_ON(!list_empty(&rinfo->indirect_pages));
                for (i = 0; i < num; i++) {
-                       struct page *indirect_page = alloc_page(GFP_KERNEL);
+                       struct page *indirect_page = alloc_page(GFP_KERNEL |
+                                                               __GFP_ZERO);
                        if (!indirect_page)
                                goto out_of_memory;
                        list_add(&indirect_page->lru, &rinfo->indirect_pages);
@@ -2276,6 +2287,8 @@ static void blkfront_gather_backend_features(struct blkfront_info *info)
                info->feature_persistent =
                        !!xenbus_read_unsigned(info->xbdev->otherend,
                                               "feature-persistent", 0);
+       if (info->feature_persistent)
+               info->bounce = true;
 
        indirect_segments = xenbus_read_unsigned(info->xbdev->otherend,
                                        "feature-max-indirect-segments", 0);
@@ -2384,7 +2397,7 @@ static void blkfront_connect(struct blkfront_info *info)
 
        err = device_add_disk(&info->xbdev->dev, info->gd, NULL);
        if (err) {
-               blk_cleanup_disk(info->gd);
+               put_disk(info->gd);
                blk_mq_free_tag_set(&info->tag_set);
                info->rq = NULL;
                goto fail;
@@ -2469,7 +2482,7 @@ static int blkfront_remove(struct xenbus_device *xbdev)
        blkif_free(info, 0);
        if (info->gd) {
                xlbd_release_minors(info->gd->first_minor, info->gd->minors);
-               blk_cleanup_disk(info->gd);
+               put_disk(info->gd);
                blk_mq_free_tag_set(&info->tag_set);
        }
 
@@ -2547,6 +2560,13 @@ static void blkfront_delay_work(struct work_struct *work)
        struct blkfront_info *info;
        bool need_schedule_work = false;
 
+       /*
+        * Note that when using bounce buffers but not persistent grants
+        * there's no need to run blkfront_delay_work because grants are
+        * revoked in blkif_completion or else an error is reported and the
+        * connection is closed.
+        */
+
        mutex_lock(&blkfront_mutex);
 
        list_for_each_entry(info, &info_list, info_list) {
index 7a6ed83..c1e85f3 100644 (file)
@@ -337,7 +337,7 @@ static int z2ram_register_disk(int minor)
        z2ram_gendisk[minor] = disk;
        err = add_disk(disk);
        if (err)
-               blk_cleanup_disk(disk);
+               put_disk(disk);
        return err;
 }
 
@@ -384,7 +384,6 @@ static void __exit z2_exit(void)
 
        for (i = 0; i < Z2MINOR_COUNT; i++) {
                del_gendisk(z2ram_gendisk[i]);
-               blk_cleanup_queue(z2ram_gendisk[i]->queue);
                put_disk(z2ram_gendisk[i]);
        }
        blk_mq_free_tag_set(&tag_set);
index b8549c6..4abeb26 100644 (file)
@@ -1523,7 +1523,7 @@ static void zram_bio_discard(struct zram *zram, u32 index,
  * Returns 1 if IO request was successfully submitted.
  */
 static int zram_bvec_rw(struct zram *zram, struct bio_vec *bvec, u32 index,
-                       int offset, unsigned int op, struct bio *bio)
+                       int offset, enum req_op op, struct bio *bio)
 {
        int ret;
 
@@ -1631,7 +1631,7 @@ static void zram_slot_free_notify(struct block_device *bdev,
 }
 
 static int zram_rw_page(struct block_device *bdev, sector_t sector,
-                      struct page *page, unsigned int op)
+                      struct page *page, enum req_op op)
 {
        int offset, ret;
        u32 index;
@@ -1957,7 +1957,7 @@ static int zram_add(void)
        return device_id;
 
 out_cleanup_disk:
-       blk_cleanup_disk(zram->disk);
+       put_disk(zram->disk);
 out_free_idr:
        idr_remove(&zram_index_idr, device_id);
 out_free_dev:
@@ -2008,7 +2008,7 @@ static int zram_remove(struct zram *zram)
         */
        zram_reset_device(zram);
 
-       blk_cleanup_disk(zram->disk);
+       put_disk(zram->disk);
        kfree(zram);
        return 0;
 }
index b25ff94..63b1b4a 100644 (file)
@@ -175,10 +175,9 @@ static int bt1_apb_request_rst(struct bt1_apb *apb)
        int ret;
 
        apb->prst = devm_reset_control_get_optional_exclusive(apb->dev, "prst");
-       if (IS_ERR(apb->prst)) {
-               dev_warn(apb->dev, "Couldn't get reset control line\n");
-               return PTR_ERR(apb->prst);
-       }
+       if (IS_ERR(apb->prst))
+               return dev_err_probe(apb->dev, PTR_ERR(apb->prst),
+                                    "Couldn't get reset control line\n");
 
        ret = reset_control_deassert(apb->prst);
        if (ret)
@@ -199,10 +198,9 @@ static int bt1_apb_request_clk(struct bt1_apb *apb)
        int ret;
 
        apb->pclk = devm_clk_get(apb->dev, "pclk");
-       if (IS_ERR(apb->pclk)) {
-               dev_err(apb->dev, "Couldn't get APB clock descriptor\n");
-               return PTR_ERR(apb->pclk);
-       }
+       if (IS_ERR(apb->pclk))
+               return dev_err_probe(apb->dev, PTR_ERR(apb->pclk),
+                                    "Couldn't get APB clock descriptor\n");
 
        ret = clk_prepare_enable(apb->pclk);
        if (ret) {
index e7a6744..70e49a6 100644 (file)
@@ -135,10 +135,9 @@ static int bt1_axi_request_rst(struct bt1_axi *axi)
        int ret;
 
        axi->arst = devm_reset_control_get_optional_exclusive(axi->dev, "arst");
-       if (IS_ERR(axi->arst)) {
-               dev_warn(axi->dev, "Couldn't get reset control line\n");
-               return PTR_ERR(axi->arst);
-       }
+       if (IS_ERR(axi->arst))
+               return dev_err_probe(axi->dev, PTR_ERR(axi->arst),
+                                    "Couldn't get reset control line\n");
 
        ret = reset_control_deassert(axi->arst);
        if (ret)
@@ -159,10 +158,9 @@ static int bt1_axi_request_clk(struct bt1_axi *axi)
        int ret;
 
        axi->aclk = devm_clk_get(axi->dev, "aclk");
-       if (IS_ERR(axi->aclk)) {
-               dev_err(axi->dev, "Couldn't get AXI Interconnect clock\n");
-               return PTR_ERR(axi->aclk);
-       }
+       if (IS_ERR(axi->aclk))
+               return dev_err_probe(axi->dev, PTR_ERR(axi->aclk),
+                                    "Couldn't get AXI Interconnect clock\n");
 
        ret = clk_prepare_enable(axi->aclk);
        if (ret) {
index 378f5d6..2e56480 100644 (file)
@@ -379,7 +379,7 @@ static void hisi_lpc_acpi_fixup_child_resource(struct device *hostdev,
 
 /*
  * hisi_lpc_acpi_set_io_res - set the resources for a child
- * @child: the device node to be updated the I/O resource
+ * @adev: ACPI companion of the device node to be updated the I/O resource
  * @hostdev: the device node associated with host controller
  * @res: double pointer to be set to the address of translated resources
  * @num_res: pointer to variable to hold the number of translated resources
@@ -390,31 +390,24 @@ static void hisi_lpc_acpi_fixup_child_resource(struct device *hostdev,
  * host-relative address resource.  This function will return the translated
  * logical PIO addresses for each child devices resources.
  */
-static int hisi_lpc_acpi_set_io_res(struct device *child,
+static int hisi_lpc_acpi_set_io_res(struct acpi_device *adev,
                                    struct device *hostdev,
                                    const struct resource **res, int *num_res)
 {
-       struct acpi_device *adev;
-       struct acpi_device *host;
+       struct acpi_device *host = to_acpi_device(adev->dev.parent);
        struct resource_entry *rentry;
        LIST_HEAD(resource_list);
        struct resource *resources;
        int count;
        int i;
 
-       if (!child || !hostdev)
-               return -EINVAL;
-
-       host = to_acpi_device(hostdev);
-       adev = to_acpi_device(child);
-
        if (!adev->status.present) {
-               dev_dbg(child, "device is not present\n");
+               dev_dbg(&adev->dev, "device is not present\n");
                return -EIO;
        }
 
        if (acpi_device_enumerated(adev)) {
-               dev_dbg(child, "has been enumerated\n");
+               dev_dbg(&adev->dev, "has been enumerated\n");
                return -EIO;
        }
 
@@ -425,7 +418,7 @@ static int hisi_lpc_acpi_set_io_res(struct device *child,
         */
        count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
        if (count <= 0) {
-               dev_dbg(child, "failed to get resources\n");
+               dev_dbg(&adev->dev, "failed to get resources\n");
                return count ? count : -EIO;
        }
 
@@ -454,7 +447,7 @@ static int hisi_lpc_acpi_set_io_res(struct device *child,
                        continue;
                ret = hisi_lpc_acpi_xlat_io_res(adev, host, &resources[i]);
                if (ret) {
-                       dev_err(child, "translate IO range %pR failed (%d)\n",
+                       dev_err(&adev->dev, "translate IO range %pR failed (%d)\n",
                                &resources[i], ret);
                        return ret;
                }
@@ -471,6 +464,12 @@ static int hisi_lpc_acpi_remove_subdev(struct device *dev, void *unused)
        return 0;
 }
 
+static int hisi_lpc_acpi_clear_enumerated(struct acpi_device *adev, void *not_used)
+{
+       acpi_device_clear_enumerated(adev);
+       return 0;
+}
+
 struct hisi_lpc_acpi_cell {
        const char *hid;
        const char *name;
@@ -480,115 +479,114 @@ struct hisi_lpc_acpi_cell {
 
 static void hisi_lpc_acpi_remove(struct device *hostdev)
 {
-       struct acpi_device *adev = ACPI_COMPANION(hostdev);
-       struct acpi_device *child;
-
        device_for_each_child(hostdev, NULL, hisi_lpc_acpi_remove_subdev);
-
-       list_for_each_entry(child, &adev->children, node)
-               acpi_device_clear_enumerated(child);
+       acpi_dev_for_each_child(ACPI_COMPANION(hostdev),
+                               hisi_lpc_acpi_clear_enumerated, NULL);
 }
 
-/*
- * hisi_lpc_acpi_probe - probe children for ACPI FW
- * @hostdev: LPC host device pointer
- *
- * Returns 0 when successful, and a negative value for failure.
- *
- * Create a platform device per child, fixing up the resources
- * from bus addresses to Logical PIO addresses.
- *
- */
-static int hisi_lpc_acpi_probe(struct device *hostdev)
+static int hisi_lpc_acpi_add_child(struct acpi_device *child, void *data)
 {
-       struct acpi_device *adev = ACPI_COMPANION(hostdev);
-       struct acpi_device *child;
+       const char *hid = acpi_device_hid(child);
+       struct device *hostdev = data;
+       const struct hisi_lpc_acpi_cell *cell;
+       struct platform_device *pdev;
+       const struct resource *res;
+       bool found = false;
+       int num_res;
        int ret;
 
-       /* Only consider the children of the host */
-       list_for_each_entry(child, &adev->children, node) {
-               const char *hid = acpi_device_hid(child);
-               const struct hisi_lpc_acpi_cell *cell;
-               struct platform_device *pdev;
-               const struct resource *res;
-               bool found = false;
-               int num_res;
-
-               ret = hisi_lpc_acpi_set_io_res(&child->dev, &adev->dev, &res,
-                                              &num_res);
-               if (ret) {
-                       dev_warn(hostdev, "set resource fail (%d)\n", ret);
-                       goto fail;
-               }
+       ret = hisi_lpc_acpi_set_io_res(child, hostdev, &res, &num_res);
+       if (ret) {
+               dev_warn(hostdev, "set resource fail (%d)\n", ret);
+               return ret;
+       }
 
-               cell = (struct hisi_lpc_acpi_cell []){
-                       /* ipmi */
-                       {
-                               .hid = "IPI0001",
-                               .name = "hisi-lpc-ipmi",
-                       },
-                       /* 8250-compatible uart */
-                       {
-                               .hid = "HISI1031",
-                               .name = "serial8250",
-                               .pdata = (struct plat_serial8250_port []) {
-                                       {
-                                               .iobase = res->start,
-                                               .uartclk = 1843200,
-                                               .iotype = UPIO_PORT,
-                                               .flags = UPF_BOOT_AUTOCONF,
-                                       },
-                                       {}
+       cell = (struct hisi_lpc_acpi_cell []){
+               /* ipmi */
+               {
+                       .hid = "IPI0001",
+                       .name = "hisi-lpc-ipmi",
+               },
+               /* 8250-compatible uart */
+               {
+                       .hid = "HISI1031",
+                       .name = "serial8250",
+                       .pdata = (struct plat_serial8250_port []) {
+                               {
+                                       .iobase = res->start,
+                                       .uartclk = 1843200,
+                                       .iotype = UPIO_PORT,
+                                       .flags = UPF_BOOT_AUTOCONF,
                                },
-                               .pdata_size = 2 *
-                                       sizeof(struct plat_serial8250_port),
+                               {}
                        },
-                       {}
-               };
-
-               for (; cell && cell->name; cell++) {
-                       if (!strcmp(cell->hid, hid)) {
-                               found = true;
-                               break;
-                       }
-               }
-
-               if (!found) {
-                       dev_warn(hostdev,
-                                "could not find cell for child device (%s), discarding\n",
-                                hid);
-                       continue;
+                       .pdata_size = 2 *
+                               sizeof(struct plat_serial8250_port),
+               },
+               {}
+       };
+
+       for (; cell && cell->name; cell++) {
+               if (!strcmp(cell->hid, hid)) {
+                       found = true;
+                       break;
                }
+       }
 
-               pdev = platform_device_alloc(cell->name, PLATFORM_DEVID_AUTO);
-               if (!pdev) {
-                       ret = -ENOMEM;
-                       goto fail;
-               }
+       if (!found) {
+               dev_warn(hostdev,
+                        "could not find cell for child device (%s), discarding\n",
+                        hid);
+               return 0;
+       }
 
-               pdev->dev.parent = hostdev;
-               ACPI_COMPANION_SET(&pdev->dev, child);
+       pdev = platform_device_alloc(cell->name, PLATFORM_DEVID_AUTO);
+       if (!pdev)
+               return -ENOMEM;
 
-               ret = platform_device_add_resources(pdev, res, num_res);
-               if (ret)
-                       goto fail;
+       pdev->dev.parent = hostdev;
+       ACPI_COMPANION_SET(&pdev->dev, child);
 
-               ret = platform_device_add_data(pdev, cell->pdata,
-                                              cell->pdata_size);
-               if (ret)
-                       goto fail;
+       ret = platform_device_add_resources(pdev, res, num_res);
+       if (ret)
+               goto fail;
 
-               ret = platform_device_add(pdev);
-               if (ret)
-                       goto fail;
+       ret = platform_device_add_data(pdev, cell->pdata, cell->pdata_size);
+       if (ret)
+               goto fail;
 
-               acpi_device_set_enumerated(child);
-       }
+       ret = platform_device_add(pdev);
+       if (ret)
+               goto fail;
 
+       acpi_device_set_enumerated(child);
        return 0;
 
 fail:
-       hisi_lpc_acpi_remove(hostdev);
+       platform_device_put(pdev);
+       return ret;
+}
+
+/*
+ * hisi_lpc_acpi_probe - probe children for ACPI FW
+ * @hostdev: LPC host device pointer
+ *
+ * Returns 0 when successful, and a negative value for failure.
+ *
+ * Create a platform device per child, fixing up the resources
+ * from bus addresses to Logical PIO addresses.
+ *
+ */
+static int hisi_lpc_acpi_probe(struct device *hostdev)
+{
+       int ret;
+
+       /* Only consider the children of the host */
+       ret = acpi_dev_for_each_child(ACPI_COMPANION(hostdev),
+                                     hisi_lpc_acpi_add_child, hostdev);
+       if (ret)
+               hisi_lpc_acpi_remove(hostdev);
+
        return ret;
 }
 
index 8e78b37..ceded57 100644 (file)
@@ -817,7 +817,7 @@ probe_fail_free_irqs:
        free_irq(HW_EVENT_GDROM_DMA, &gd);
        free_irq(HW_EVENT_GDROM_CMD, &gd);
 probe_fail_cleanup_disk:
-       blk_cleanup_disk(gd.disk);
+       put_disk(gd.disk);
 probe_fail_free_tag_set:
        blk_mq_free_tag_set(&gd.tag_set);
 probe_fail_free_cd_info:
@@ -831,7 +831,6 @@ probe_fail_no_mem:
 
 static int remove_gdrom(struct platform_device *devptr)
 {
-       blk_cleanup_queue(gd.gdrom_rq);
        blk_mq_free_tag_set(&gd.tag_set);
        free_irq(HW_EVENT_GDROM_CMD, &gd);
        free_irq(HW_EVENT_GDROM_DMA, &gd);
index 0b6c036..30192e1 100644 (file)
@@ -431,7 +431,6 @@ config ADI
 config RANDOM_TRUST_CPU
        bool "Initialize RNG using CPU RNG instructions"
        default y
-       depends on ARCH_RANDOM
        help
          Initialize the RNG using random numbers supplied by the CPU's
          RNG instructions (e.g. RDRAND), if supported and available. These
index b3f2d55..3da8e85 100644 (file)
@@ -87,7 +87,7 @@ config HW_RANDOM_BA431
 config HW_RANDOM_BCM2835
        tristate "Broadcom BCM2835/BCM63xx Random Number Generator support"
        depends on ARCH_BCM2835 || ARCH_BCM_NSP || ARCH_BCM_5301X || \
-                  ARCH_BCM_63XX || BCM63XX || BMIPS_GENERIC || COMPILE_TEST
+                  ARCH_BCMBCA || BCM63XX || BMIPS_GENERIC || COMPILE_TEST
        default HW_RANDOM
        help
          This driver provides kernel-side support for the Random Number
index 2beaa35..488808d 100644 (file)
@@ -108,7 +108,6 @@ static ssize_t trng_counter_show(struct device *dev,
 {
        u64 dev_counter = atomic64_read(&trng_dev_counter);
        u64 hwrng_counter = atomic64_read(&trng_hwrng_counter);
-#if IS_ENABLED(CONFIG_ARCH_RANDOM)
        u64 arch_counter = atomic64_read(&s390_arch_random_counter);
 
        return sysfs_emit(buf,
@@ -118,14 +117,6 @@ static ssize_t trng_counter_show(struct device *dev,
                        "total: %llu\n",
                        dev_counter, hwrng_counter, arch_counter,
                        dev_counter + hwrng_counter + arch_counter);
-#else
-       return sysfs_emit(buf,
-                       "trng:  %llu\n"
-                       "hwrng: %llu\n"
-                       "total: %llu\n",
-                       dev_counter, hwrng_counter,
-                       dev_counter + hwrng_counter);
-#endif
 }
 static DEVICE_ATTR(byte_counter, 0444, trng_counter_show, NULL);
 
index 7444cc1..a9a0a3b 100644 (file)
@@ -145,7 +145,7 @@ static int via_rng_init(struct hwrng *rng)
        }
 
        /* Control the RNG via MSR.  Tread lightly and pay very close
-        * close attention to values written, as the reserved fields
+        * attention to values written, as the reserved fields
         * are documented to be "undefined and unpredictable"; but it
         * does not say to write them as zero, so I make a guess that
         * we restore the values we find in the register.
index e3dd1dd..d44832e 100644 (file)
@@ -229,7 +229,7 @@ static void crng_reseed(void)
 
 /*
  * This generates a ChaCha block using the provided key, and then
- * immediately overwites that key with half the block. It returns
+ * immediately overwrites that key with half the block. It returns
  * the resultant ChaCha state to the user, along with the second
  * half of the block containing 32 bytes of random data that may
  * be used; random_data_len may not be greater than 32.
@@ -596,12 +596,20 @@ static void extract_entropy(void *buf, size_t len)
                unsigned long rdseed[32 / sizeof(long)];
                size_t counter;
        } block;
-       size_t i;
+       size_t i, longs;
 
-       for (i = 0; i < ARRAY_SIZE(block.rdseed); ++i) {
-               if (!arch_get_random_seed_long(&block.rdseed[i]) &&
-                   !arch_get_random_long(&block.rdseed[i]))
-                       block.rdseed[i] = random_get_entropy();
+       for (i = 0; i < ARRAY_SIZE(block.rdseed);) {
+               longs = arch_get_random_seed_longs(&block.rdseed[i], ARRAY_SIZE(block.rdseed) - i);
+               if (longs) {
+                       i += longs;
+                       continue;
+               }
+               longs = arch_get_random_longs(&block.rdseed[i], ARRAY_SIZE(block.rdseed) - i);
+               if (longs) {
+                       i += longs;
+                       continue;
+               }
+               block.rdseed[i++] = random_get_entropy();
        }
 
        spin_lock_irqsave(&input_pool.lock, flags);
@@ -643,10 +651,10 @@ static void __cold _credit_init_bits(size_t bits)
 
        add = min_t(size_t, bits, POOL_BITS);
 
+       orig = READ_ONCE(input_pool.init_bits);
        do {
-               orig = READ_ONCE(input_pool.init_bits);
                new = min_t(unsigned int, POOL_BITS, orig + add);
-       } while (cmpxchg(&input_pool.init_bits, orig, new) != orig);
+       } while (!try_cmpxchg(&input_pool.init_bits, &orig, new));
 
        if (orig < POOL_READY_BITS && new >= POOL_READY_BITS) {
                crng_reseed(); /* Sets crng_init to CRNG_READY under base_crng.lock. */
@@ -776,22 +784,31 @@ static struct notifier_block pm_notifier = { .notifier_call = random_pm_notifica
 int __init random_init(const char *command_line)
 {
        ktime_t now = ktime_get_real();
-       unsigned int i, arch_bits;
-       unsigned long entropy;
+       size_t i, longs, arch_bits;
+       unsigned long entropy[BLAKE2S_BLOCK_SIZE / sizeof(long)];
 
 #if defined(LATENT_ENTROPY_PLUGIN)
        static const u8 compiletime_seed[BLAKE2S_BLOCK_SIZE] __initconst __latent_entropy;
        _mix_pool_bytes(compiletime_seed, sizeof(compiletime_seed));
 #endif
 
-       for (i = 0, arch_bits = BLAKE2S_BLOCK_SIZE * 8;
-            i < BLAKE2S_BLOCK_SIZE; i += sizeof(entropy)) {
-               if (!arch_get_random_seed_long_early(&entropy) &&
-                   !arch_get_random_long_early(&entropy)) {
-                       entropy = random_get_entropy();
-                       arch_bits -= sizeof(entropy) * 8;
+       for (i = 0, arch_bits = sizeof(entropy) * 8; i < ARRAY_SIZE(entropy);) {
+               longs = arch_get_random_seed_longs(entropy, ARRAY_SIZE(entropy) - i);
+               if (longs) {
+                       _mix_pool_bytes(entropy, sizeof(*entropy) * longs);
+                       i += longs;
+                       continue;
                }
-               _mix_pool_bytes(&entropy, sizeof(entropy));
+               longs = arch_get_random_longs(entropy, ARRAY_SIZE(entropy) - i);
+               if (longs) {
+                       _mix_pool_bytes(entropy, sizeof(*entropy) * longs);
+                       i += longs;
+                       continue;
+               }
+               entropy[0] = random_get_entropy();
+               _mix_pool_bytes(entropy, sizeof(*entropy));
+               arch_bits -= sizeof(*entropy) * 8;
+               ++i;
        }
        _mix_pool_bytes(&now, sizeof(now));
        _mix_pool_bytes(utsname(), sizeof(*(utsname())));
@@ -1174,7 +1191,7 @@ static void __cold entropy_timer(struct timer_list *timer)
  */
 static void __cold try_to_generate_entropy(void)
 {
-       enum { NUM_TRIAL_SAMPLES = 8192, MAX_SAMPLES_PER_BIT = 32 };
+       enum { NUM_TRIAL_SAMPLES = 8192, MAX_SAMPLES_PER_BIT = HZ / 30 };
        struct entropy_timer_state stack;
        unsigned int i, num_different = 0;
        unsigned long last = random_get_entropy();
index cdbc7d7..2fbeb71 100644 (file)
@@ -2,3 +2,4 @@ CONFIG_KUNIT=y
 CONFIG_COMMON_CLK=y
 CONFIG_CLK_KUNIT_TEST=y
 CONFIG_CLK_GATE_KUNIT_TEST=y
+CONFIG_UML_PCI_OVER_VIRTIO=n
index ec738f7..77266af 100644 (file)
@@ -22,9 +22,9 @@ config CLK_BCM2835
 
 config CLK_BCM_63XX
        bool "Broadcom BCM63xx clock support"
-       depends on ARCH_BCM_63XX || COMPILE_TEST
+       depends on ARCH_BCMBCA || COMPILE_TEST
        select COMMON_CLK_IPROC
-       default ARCH_BCM_63XX
+       default ARCH_BCMBCA
        help
          Enable common clock framework support for Broadcom BCM63xx DSL SoCs
          based on the ARM architecture
index d1535ac..81cb909 100644 (file)
@@ -213,7 +213,7 @@ static int lan966x_gate_clk_register(struct device *dev,
 
                hw_data->hws[i] =
                        devm_clk_hw_register_gate(dev, clk_gate_desc[idx].name,
-                                                 "lan966x", 0, base,
+                                                 "lan966x", 0, gate_base,
                                                  clk_gate_desc[idx].bit_idx,
                                                  0, &clk_gate_lock);
 
index 0408701..e893815 100644 (file)
@@ -111,6 +111,7 @@ int stm32_rcc_reset_init(struct device *dev, const struct of_device_id *match,
        if (!reset_data)
                return -ENOMEM;
 
+       spin_lock_init(&reset_data->lock);
        reset_data->membase = base;
        reset_data->rcdev.owner = THIS_MODULE;
        reset_data->rcdev.ops = &stm32_reset_ops;
index 29a8c71..b7962e5 100644 (file)
@@ -138,6 +138,7 @@ static struct ccu_common *sun50i_h6_r_ccu_clks[] = {
        &r_apb2_rsb_clk.common,
        &r_apb1_ir_clk.common,
        &r_apb1_w1_clk.common,
+       &r_apb1_rtc_clk.common,
        &ir_clk.common,
        &w1_clk.common,
 };
index 3c0ee10..4f2bb73 100644 (file)
@@ -22,7 +22,7 @@ config CLKEVT_I8253
 config I8253_LOCK
        bool
 
-config OMAP_DM_TIMER
+config OMAP_DM_SYSTIMER
        bool
        select TIMER_OF
 
@@ -56,6 +56,13 @@ config DIGICOLOR_TIMER
        help
          Enables the support for the digicolor timer driver.
 
+config OMAP_DM_TIMER
+       bool "OMAP dual-mode timer driver" if ARCH_K3 || COMPILE_TEST
+       default y if ARCH_K3
+       select TIMER_OF
+       help
+         Enables the support for the TI dual-mode timer driver.
+
 config DW_APB_TIMER
        bool "DW APB timer driver" if COMPILE_TEST
        help
@@ -150,6 +157,14 @@ config TEGRA_TIMER
        help
          Enables support for the Tegra driver.
 
+config TEGRA186_TIMER
+       bool "NVIDIA Tegra186 timer driver"
+       depends on ARCH_TEGRA || COMPILE_TEST
+       depends on WATCHDOG && WATCHDOG_CORE
+       help
+         Enables support for the timers and watchdogs found on NVIDIA
+         Tegra186 and later SoCs.
+
 config VT8500_TIMER
        bool "VT8500 timer driver" if COMPILE_TEST
        depends on HAS_IOMEM
@@ -367,7 +382,7 @@ config ARM_GT_INITIAL_PRESCALER_VAL
        depends on ARM_GLOBAL_TIMER
        help
          When the ARM global timer initializes, its current rate is declared
-         to the kernel and maintained forever. Should it's parent clock
+         to the kernel and maintained forever. Should its parent clock
          change, the driver tries to fix the timer's internal prescaler.
          On some machs (i.e. Zynq) the initial prescaler value thus poses
          bounds about how much the parent clock is allowed to decrease or
index 6ca6400..64ab547 100644 (file)
@@ -18,7 +18,7 @@ obj-$(CONFIG_CLKSRC_MMIO)     += mmio.o
 obj-$(CONFIG_DAVINCI_TIMER)    += timer-davinci.o
 obj-$(CONFIG_DIGICOLOR_TIMER)  += timer-digicolor.o
 obj-$(CONFIG_OMAP_DM_TIMER)    += timer-ti-dm.o
-obj-$(CONFIG_OMAP_DM_TIMER)    += timer-ti-dm-systimer.o
+obj-$(CONFIG_OMAP_DM_SYSTIMER) += timer-ti-dm-systimer.o
 obj-$(CONFIG_DW_APB_TIMER)     += dw_apb_timer.o
 obj-$(CONFIG_DW_APB_TIMER_OF)  += dw_apb_timer_of.o
 obj-$(CONFIG_FTTMR010_TIMER)   += timer-fttmr010.o
@@ -36,6 +36,7 @@ obj-$(CONFIG_SUN4I_TIMER)     += timer-sun4i.o
 obj-$(CONFIG_SUN5I_HSTIMER)    += timer-sun5i.o
 obj-$(CONFIG_MESON6_TIMER)     += timer-meson6.o
 obj-$(CONFIG_TEGRA_TIMER)      += timer-tegra.o
+obj-$(CONFIG_TEGRA186_TIMER)   += timer-tegra186.o
 obj-$(CONFIG_VT8500_TIMER)     += timer-vt8500.o
 obj-$(CONFIG_NSPIRE_TIMER)     += timer-zevio.o
 obj-$(CONFIG_BCM_KONA_TIMER)   += bcm_kona_timer.o
index dd0956a..64dcb08 100644 (file)
@@ -981,6 +981,14 @@ static const struct of_device_id sh_cmt_of_table[] __maybe_unused = {
                .compatible = "renesas,rcar-gen3-cmt1",
                .data = &sh_cmt_info[SH_CMT1_RCAR_GEN2]
        },
+       {
+               .compatible = "renesas,rcar-gen4-cmt0",
+               .data = &sh_cmt_info[SH_CMT0_RCAR_GEN2]
+       },
+       {
+               .compatible = "renesas,rcar-gen4-cmt1",
+               .data = &sh_cmt_info[SH_CMT1_RCAR_GEN2]
+       },
        { }
 };
 MODULE_DEVICE_TABLE(of, sh_cmt_of_table);
index 7bcb4a3..d5b29fd 100644 (file)
 
 #define TIMER_SYNC_TICKS        (3)
 
+/* cpux mcusys wrapper */
+#define CPUX_CON_REG           0x0
+#define CPUX_IDX_REG           0x4
+
+/* cpux */
+#define CPUX_IDX_GLOBAL_CTRL   0x0
+ #define CPUX_ENABLE           BIT(0)
+ #define CPUX_CLK_DIV_MASK     GENMASK(10, 8)
+ #define CPUX_CLK_DIV1         BIT(8)
+ #define CPUX_CLK_DIV2         BIT(9)
+ #define CPUX_CLK_DIV4         BIT(10)
+#define CPUX_IDX_GLOBAL_IRQ    0x30
+
 /* gpt */
 #define GPT_IRQ_EN_REG          0x00
 #define GPT_IRQ_ENABLE(val)     BIT((val) - 1)
 
 static void __iomem *gpt_sched_reg __read_mostly;
 
+static u32 mtk_cpux_readl(u32 reg_idx, struct timer_of *to)
+{
+       writel(reg_idx, timer_of_base(to) + CPUX_IDX_REG);
+       return readl(timer_of_base(to) + CPUX_CON_REG);
+}
+
+static void mtk_cpux_writel(u32 val, u32 reg_idx, struct timer_of *to)
+{
+       writel(reg_idx, timer_of_base(to) + CPUX_IDX_REG);
+       writel(val, timer_of_base(to) + CPUX_CON_REG);
+}
+
+static void mtk_cpux_set_irq(struct timer_of *to, bool enable)
+{
+       const unsigned long *irq_mask = cpumask_bits(cpu_possible_mask);
+       u32 val;
+
+       val = mtk_cpux_readl(CPUX_IDX_GLOBAL_IRQ, to);
+
+       if (enable)
+               val |= *irq_mask;
+       else
+               val &= ~(*irq_mask);
+
+       mtk_cpux_writel(val, CPUX_IDX_GLOBAL_IRQ, to);
+}
+
+static int mtk_cpux_clkevt_shutdown(struct clock_event_device *clkevt)
+{
+       /* Clear any irq */
+       mtk_cpux_set_irq(to_timer_of(clkevt), false);
+
+       /*
+        * Disabling CPUXGPT timer will crash the platform, especially
+        * if Trusted Firmware is using it (usually, for sleep states),
+        * so we only mask the IRQ and call it a day.
+        */
+       return 0;
+}
+
+static int mtk_cpux_clkevt_resume(struct clock_event_device *clkevt)
+{
+       mtk_cpux_set_irq(to_timer_of(clkevt), true);
+       return 0;
+}
+
 static void mtk_syst_ack_irq(struct timer_of *to)
 {
        /* Clear and disable interrupt */
@@ -281,6 +340,60 @@ static struct timer_of to = {
        },
 };
 
+static int __init mtk_cpux_init(struct device_node *node)
+{
+       static struct timer_of to_cpux;
+       u32 freq, val;
+       int ret;
+
+       /*
+        * There are per-cpu interrupts for the CPUX General Purpose Timer
+        * but since this timer feeds the AArch64 System Timer we can rely
+        * on the CPU timer PPIs as well, so we don't declare TIMER_OF_IRQ.
+        */
+       to_cpux.flags = TIMER_OF_BASE | TIMER_OF_CLOCK;
+       to_cpux.clkevt.name = "mtk-cpuxgpt";
+       to_cpux.clkevt.rating = 10;
+       to_cpux.clkevt.cpumask = cpu_possible_mask;
+       to_cpux.clkevt.set_state_shutdown = mtk_cpux_clkevt_shutdown;
+       to_cpux.clkevt.tick_resume = mtk_cpux_clkevt_resume;
+
+       /* If this fails, bad things are about to happen... */
+       ret = timer_of_init(node, &to_cpux);
+       if (ret) {
+               WARN(1, "Cannot start CPUX timers.\n");
+               return ret;
+       }
+
+       /*
+        * Check if we're given a clock with the right frequency for this
+        * timer, otherwise warn but keep going with the setup anyway, as
+        * that makes it possible to still boot the kernel, even though
+        * it may not work correctly (random lockups, etc).
+        * The reason behind this is that having an early UART may not be
+        * possible for everyone and this gives a chance to retrieve kmsg
+        * for eventual debugging even on consumer devices.
+        */
+       freq = timer_of_rate(&to_cpux);
+       if (freq > 13000000)
+               WARN(1, "Requested unsupported timer frequency %u\n", freq);
+
+       /* Clock input is 26MHz, set DIV2 to achieve 13MHz clock */
+       val = mtk_cpux_readl(CPUX_IDX_GLOBAL_CTRL, &to_cpux);
+       val &= ~CPUX_CLK_DIV_MASK;
+       val |= CPUX_CLK_DIV2;
+       mtk_cpux_writel(val, CPUX_IDX_GLOBAL_CTRL, &to_cpux);
+
+       /* Enable all CPUXGPT timers */
+       val = mtk_cpux_readl(CPUX_IDX_GLOBAL_CTRL, &to_cpux);
+       mtk_cpux_writel(val | CPUX_ENABLE, CPUX_IDX_GLOBAL_CTRL, &to_cpux);
+
+       clockevents_config_and_register(&to_cpux.clkevt, timer_of_rate(&to_cpux),
+                                       TIMER_SYNC_TICKS, 0xffffffff);
+
+       return 0;
+}
+
 static int __init mtk_syst_init(struct device_node *node)
 {
        int ret;
@@ -339,3 +452,4 @@ static int __init mtk_gpt_init(struct device_node *node)
 }
 TIMER_OF_DECLARE(mtk_mt6577, "mediatek,mt6577-timer", mtk_gpt_init);
 TIMER_OF_DECLARE(mtk_mt6765, "mediatek,mt6765-timer", mtk_syst_init);
+TIMER_OF_DECLARE(mtk_mt6795, "mediatek,mt6795-systimer", mtk_cpux_init);
index abce83d..d5f1436 100644 (file)
@@ -61,7 +61,7 @@ struct mchp_pit64b_timer {
 };
 
 /**
- * mchp_pit64b_clkevt - PIT64B clockevent data structure
+ * struct mchp_pit64b_clkevt - PIT64B clockevent data structure
  * @timer: PIT64B timer
  * @clkevt: clockevent
  */
@@ -75,7 +75,7 @@ struct mchp_pit64b_clkevt {
                struct mchp_pit64b_clkevt, clkevt))
 
 /**
- * mchp_pit64b_clksrc - PIT64B clocksource data structure
+ * struct mchp_pit64b_clksrc - PIT64B clocksource data structure
  * @timer: PIT64B timer
  * @clksrc: clocksource
  */
@@ -173,7 +173,8 @@ static int mchp_pit64b_clkevt_shutdown(struct clock_event_device *cedev)
 {
        struct mchp_pit64b_timer *timer = clkevt_to_mchp_pit64b_timer(cedev);
 
-       writel_relaxed(MCHP_PIT64B_CR_SWRST, timer->base + MCHP_PIT64B_CR);
+       if (!clockevent_state_detached(cedev))
+               mchp_pit64b_suspend(timer);
 
        return 0;
 }
@@ -182,35 +183,37 @@ static int mchp_pit64b_clkevt_set_periodic(struct clock_event_device *cedev)
 {
        struct mchp_pit64b_timer *timer = clkevt_to_mchp_pit64b_timer(cedev);
 
+       if (clockevent_state_shutdown(cedev))
+               mchp_pit64b_resume(timer);
+
        mchp_pit64b_reset(timer, mchp_pit64b_ce_cycles, MCHP_PIT64B_MR_CONT,
                          MCHP_PIT64B_IER_PERIOD);
 
        return 0;
 }
 
-static int mchp_pit64b_clkevt_set_next_event(unsigned long evt,
-                                            struct clock_event_device *cedev)
+static int mchp_pit64b_clkevt_set_oneshot(struct clock_event_device *cedev)
 {
        struct mchp_pit64b_timer *timer = clkevt_to_mchp_pit64b_timer(cedev);
 
-       mchp_pit64b_reset(timer, evt, MCHP_PIT64B_MR_ONE_SHOT,
+       if (clockevent_state_shutdown(cedev))
+               mchp_pit64b_resume(timer);
+
+       mchp_pit64b_reset(timer, mchp_pit64b_ce_cycles, MCHP_PIT64B_MR_ONE_SHOT,
                          MCHP_PIT64B_IER_PERIOD);
 
        return 0;
 }
 
-static void mchp_pit64b_clkevt_suspend(struct clock_event_device *cedev)
+static int mchp_pit64b_clkevt_set_next_event(unsigned long evt,
+                                            struct clock_event_device *cedev)
 {
        struct mchp_pit64b_timer *timer = clkevt_to_mchp_pit64b_timer(cedev);
 
-       mchp_pit64b_suspend(timer);
-}
-
-static void mchp_pit64b_clkevt_resume(struct clock_event_device *cedev)
-{
-       struct mchp_pit64b_timer *timer = clkevt_to_mchp_pit64b_timer(cedev);
+       mchp_pit64b_reset(timer, evt, MCHP_PIT64B_MR_ONE_SHOT,
+                         MCHP_PIT64B_IER_PERIOD);
 
-       mchp_pit64b_resume(timer);
+       return 0;
 }
 
 static irqreturn_t mchp_pit64b_interrupt(int irq, void *dev_id)
@@ -242,8 +245,10 @@ static void __init mchp_pit64b_pres_compute(u32 *pres, u32 clk_rate,
 }
 
 /**
- * mchp_pit64b_init_mode - prepare PIT64B mode register value to be used at
- *                        runtime; this includes prescaler and SGCLK bit
+ * mchp_pit64b_init_mode() - prepare PIT64B mode register value to be used at
+ *                          runtime; this includes prescaler and SGCLK bit
+ * @timer: pointer to pit64b timer to init
+ * @max_rate: maximum rate that timer's clock could use
  *
  * PIT64B timer may be fed by gclk or pclk. When gclk is used its rate has to
  * be at least 3 times lower that pclk's rate. pclk rate is fixed, gclk rate
@@ -341,6 +346,7 @@ static int __init mchp_pit64b_init_clksrc(struct mchp_pit64b_timer *timer,
        if (!cs)
                return -ENOMEM;
 
+       mchp_pit64b_resume(timer);
        mchp_pit64b_reset(timer, ULLONG_MAX, MCHP_PIT64B_MR_CONT, 0);
 
        mchp_pit64b_cs_base = timer->base;
@@ -362,8 +368,7 @@ static int __init mchp_pit64b_init_clksrc(struct mchp_pit64b_timer *timer,
                pr_debug("clksrc: Failed to register PIT64B clocksource!\n");
 
                /* Stop timer. */
-               writel_relaxed(MCHP_PIT64B_CR_SWRST,
-                              timer->base + MCHP_PIT64B_CR);
+               mchp_pit64b_suspend(timer);
                kfree(cs);
 
                return ret;
@@ -395,9 +400,8 @@ static int __init mchp_pit64b_init_clkevt(struct mchp_pit64b_timer *timer,
        ce->clkevt.rating = 150;
        ce->clkevt.set_state_shutdown = mchp_pit64b_clkevt_shutdown;
        ce->clkevt.set_state_periodic = mchp_pit64b_clkevt_set_periodic;
+       ce->clkevt.set_state_oneshot = mchp_pit64b_clkevt_set_oneshot;
        ce->clkevt.set_next_event = mchp_pit64b_clkevt_set_next_event;
-       ce->clkevt.suspend = mchp_pit64b_clkevt_suspend;
-       ce->clkevt.resume = mchp_pit64b_clkevt_resume;
        ce->clkevt.cpumask = cpumask_of(0);
        ce->clkevt.irq = irq;
 
@@ -448,19 +452,10 @@ static int __init mchp_pit64b_dt_init_timer(struct device_node *node,
        if (ret)
                goto irq_unmap;
 
-       ret = clk_prepare_enable(timer.pclk);
-       if (ret)
-               goto irq_unmap;
-
-       if (timer.mode & MCHP_PIT64B_MR_SGCLK) {
-               ret = clk_prepare_enable(timer.gclk);
-               if (ret)
-                       goto pclk_unprepare;
-
+       if (timer.mode & MCHP_PIT64B_MR_SGCLK)
                clk_rate = clk_get_rate(timer.gclk);
-       } else {
+       else
                clk_rate = clk_get_rate(timer.pclk);
-       }
        clk_rate = clk_rate / (MCHP_PIT64B_MODE_TO_PRES(timer.mode) + 1);
 
        if (clkevt)
@@ -469,15 +464,10 @@ static int __init mchp_pit64b_dt_init_timer(struct device_node *node,
                ret = mchp_pit64b_init_clksrc(&timer, clk_rate);
 
        if (ret)
-               goto gclk_unprepare;
+               goto irq_unmap;
 
        return 0;
 
-gclk_unprepare:
-       if (timer.mode & MCHP_PIT64B_MR_SGCLK)
-               clk_disable_unprepare(timer.gclk);
-pclk_unprepare:
-       clk_disable_unprepare(timer.pclk);
 irq_unmap:
        irq_dispose_mapping(irq);
 io_unmap:
index bb6ea6c..94dc6e4 100644 (file)
@@ -128,7 +128,7 @@ static void sun4i_timer_clear_interrupt(void __iomem *base)
 
 static irqreturn_t sun4i_timer_interrupt(int irq, void *dev_id)
 {
-       struct clock_event_device *evt = (struct clock_event_device *)dev_id;
+       struct clock_event_device *evt = dev_id;
        struct timer_of *to = to_timer_of(evt);
 
        sun4i_timer_clear_interrupt(timer_of_base(to));
index 85900f7..7d5fa90 100644 (file)
@@ -142,7 +142,7 @@ static int sun5i_clkevt_next_event(unsigned long evt,
 
 static irqreturn_t sun5i_timer_interrupt(int irq, void *dev_id)
 {
-       struct sun5i_timer_clkevt *ce = (struct sun5i_timer_clkevt *)dev_id;
+       struct sun5i_timer_clkevt *ce = dev_id;
 
        writel(0x1, ce->timer.base + TIMER_IRQ_ST_REG);
        ce->clkevt.event_handler(&ce->clkevt);
diff --git a/drivers/clocksource/timer-tegra186.c b/drivers/clocksource/timer-tegra186.c
new file mode 100644 (file)
index 0000000..ea74288
--- /dev/null
@@ -0,0 +1,514 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2019-2020 NVIDIA Corporation. All rights reserved.
+ */
+
+#include <linux/clocksource.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/watchdog.h>
+
+/* shared registers */
+#define TKETSC0 0x000
+#define TKETSC1 0x004
+#define TKEUSEC 0x008
+#define TKEOSC  0x00c
+
+#define TKEIE(x) (0x100 + ((x) * 4))
+#define  TKEIE_WDT_MASK(x, y) ((y) << (16 + 4 * (x)))
+
+/* timer registers */
+#define TMRCR 0x000
+#define  TMRCR_ENABLE BIT(31)
+#define  TMRCR_PERIODIC BIT(30)
+#define  TMRCR_PTV(x) ((x) & 0x0fffffff)
+
+#define TMRSR 0x004
+#define  TMRSR_INTR_CLR BIT(30)
+
+#define TMRCSSR 0x008
+#define  TMRCSSR_SRC_USEC (0 << 0)
+
+/* watchdog registers */
+#define WDTCR 0x000
+#define  WDTCR_SYSTEM_POR_RESET_ENABLE BIT(16)
+#define  WDTCR_SYSTEM_DEBUG_RESET_ENABLE BIT(15)
+#define  WDTCR_REMOTE_INT_ENABLE BIT(14)
+#define  WDTCR_LOCAL_FIQ_ENABLE BIT(13)
+#define  WDTCR_LOCAL_INT_ENABLE BIT(12)
+#define  WDTCR_PERIOD_MASK (0xff << 4)
+#define  WDTCR_PERIOD(x) (((x) & 0xff) << 4)
+#define  WDTCR_TIMER_SOURCE_MASK 0xf
+#define  WDTCR_TIMER_SOURCE(x) ((x) & 0xf)
+
+#define WDTCMDR 0x008
+#define  WDTCMDR_DISABLE_COUNTER BIT(1)
+#define  WDTCMDR_START_COUNTER BIT(0)
+
+#define WDTUR 0x00c
+#define  WDTUR_UNLOCK_PATTERN 0x0000c45a
+
+struct tegra186_timer_soc {
+       unsigned int num_timers;
+       unsigned int num_wdts;
+};
+
+struct tegra186_tmr {
+       struct tegra186_timer *parent;
+       void __iomem *regs;
+       unsigned int index;
+       unsigned int hwirq;
+};
+
+struct tegra186_wdt {
+       struct watchdog_device base;
+
+       void __iomem *regs;
+       unsigned int index;
+       bool locked;
+
+       struct tegra186_tmr *tmr;
+};
+
+static inline struct tegra186_wdt *to_tegra186_wdt(struct watchdog_device *wdd)
+{
+       return container_of(wdd, struct tegra186_wdt, base);
+}
+
+struct tegra186_timer {
+       const struct tegra186_timer_soc *soc;
+       struct device *dev;
+       void __iomem *regs;
+
+       struct tegra186_wdt *wdt;
+       struct clocksource usec;
+       struct clocksource tsc;
+       struct clocksource osc;
+};
+
+static void tmr_writel(struct tegra186_tmr *tmr, u32 value, unsigned int offset)
+{
+       writel_relaxed(value, tmr->regs + offset);
+}
+
+static void wdt_writel(struct tegra186_wdt *wdt, u32 value, unsigned int offset)
+{
+       writel_relaxed(value, wdt->regs + offset);
+}
+
+static u32 wdt_readl(struct tegra186_wdt *wdt, unsigned int offset)
+{
+       return readl_relaxed(wdt->regs + offset);
+}
+
+static struct tegra186_tmr *tegra186_tmr_create(struct tegra186_timer *tegra,
+                                               unsigned int index)
+{
+       unsigned int offset = 0x10000 + index * 0x10000;
+       struct tegra186_tmr *tmr;
+
+       tmr = devm_kzalloc(tegra->dev, sizeof(*tmr), GFP_KERNEL);
+       if (!tmr)
+               return ERR_PTR(-ENOMEM);
+
+       tmr->parent = tegra;
+       tmr->regs = tegra->regs + offset;
+       tmr->index = index;
+       tmr->hwirq = 0;
+
+       return tmr;
+}
+
+static const struct watchdog_info tegra186_wdt_info = {
+       .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
+       .identity = "NVIDIA Tegra186 WDT",
+};
+
+static void tegra186_wdt_disable(struct tegra186_wdt *wdt)
+{
+       /* unlock and disable the watchdog */
+       wdt_writel(wdt, WDTUR_UNLOCK_PATTERN, WDTUR);
+       wdt_writel(wdt, WDTCMDR_DISABLE_COUNTER, WDTCMDR);
+
+       /* disable timer */
+       tmr_writel(wdt->tmr, 0, TMRCR);
+}
+
+static void tegra186_wdt_enable(struct tegra186_wdt *wdt)
+{
+       struct tegra186_timer *tegra = wdt->tmr->parent;
+       u32 value;
+
+       /* unmask hardware IRQ, this may have been lost across powergate */
+       value = TKEIE_WDT_MASK(wdt->index, 1);
+       writel(value, tegra->regs + TKEIE(wdt->tmr->hwirq));
+
+       /* clear interrupt */
+       tmr_writel(wdt->tmr, TMRSR_INTR_CLR, TMRSR);
+
+       /* select microsecond source */
+       tmr_writel(wdt->tmr, TMRCSSR_SRC_USEC, TMRCSSR);
+
+       /* configure timer (system reset happens on the fifth expiration) */
+       value = TMRCR_PTV(wdt->base.timeout * USEC_PER_SEC / 5) |
+               TMRCR_PERIODIC | TMRCR_ENABLE;
+       tmr_writel(wdt->tmr, value, TMRCR);
+
+       if (!wdt->locked) {
+               value = wdt_readl(wdt, WDTCR);
+
+               /* select the proper timer source */
+               value &= ~WDTCR_TIMER_SOURCE_MASK;
+               value |= WDTCR_TIMER_SOURCE(wdt->tmr->index);
+
+               /* single timer period since that's already configured */
+               value &= ~WDTCR_PERIOD_MASK;
+               value |= WDTCR_PERIOD(1);
+
+               /* enable local interrupt for WDT petting */
+               value |= WDTCR_LOCAL_INT_ENABLE;
+
+               /* enable local FIQ and remote interrupt for debug dump */
+               if (0)
+                       value |= WDTCR_REMOTE_INT_ENABLE |
+                                WDTCR_LOCAL_FIQ_ENABLE;
+
+               /* enable system debug reset (doesn't properly reboot) */
+               if (0)
+                       value |= WDTCR_SYSTEM_DEBUG_RESET_ENABLE;
+
+               /* enable system POR reset */
+               value |= WDTCR_SYSTEM_POR_RESET_ENABLE;
+
+               wdt_writel(wdt, value, WDTCR);
+       }
+
+       wdt_writel(wdt, WDTCMDR_START_COUNTER, WDTCMDR);
+}
+
+static int tegra186_wdt_start(struct watchdog_device *wdd)
+{
+       struct tegra186_wdt *wdt = to_tegra186_wdt(wdd);
+
+       tegra186_wdt_enable(wdt);
+
+       return 0;
+}
+
+static int tegra186_wdt_stop(struct watchdog_device *wdd)
+{
+       struct tegra186_wdt *wdt = to_tegra186_wdt(wdd);
+
+       tegra186_wdt_disable(wdt);
+
+       return 0;
+}
+
+static int tegra186_wdt_ping(struct watchdog_device *wdd)
+{
+       struct tegra186_wdt *wdt = to_tegra186_wdt(wdd);
+
+       tegra186_wdt_disable(wdt);
+       tegra186_wdt_enable(wdt);
+
+       return 0;
+}
+
+static int tegra186_wdt_set_timeout(struct watchdog_device *wdd,
+                                   unsigned int timeout)
+{
+       struct tegra186_wdt *wdt = to_tegra186_wdt(wdd);
+
+       if (watchdog_active(&wdt->base))
+               tegra186_wdt_disable(wdt);
+
+       wdt->base.timeout = timeout;
+
+       if (watchdog_active(&wdt->base))
+               tegra186_wdt_enable(wdt);
+
+       return 0;
+}
+
+static const struct watchdog_ops tegra186_wdt_ops = {
+       .owner = THIS_MODULE,
+       .start = tegra186_wdt_start,
+       .stop = tegra186_wdt_stop,
+       .ping = tegra186_wdt_ping,
+       .set_timeout = tegra186_wdt_set_timeout,
+};
+
+static struct tegra186_wdt *tegra186_wdt_create(struct tegra186_timer *tegra,
+                                               unsigned int index)
+{
+       unsigned int offset = 0x10000, source;
+       struct tegra186_wdt *wdt;
+       u32 value;
+       int err;
+
+       offset += tegra->soc->num_timers * 0x10000 + index * 0x10000;
+
+       wdt = devm_kzalloc(tegra->dev, sizeof(*wdt), GFP_KERNEL);
+       if (!wdt)
+               return ERR_PTR(-ENOMEM);
+
+       wdt->regs = tegra->regs + offset;
+       wdt->index = index;
+
+       /* read the watchdog configuration since it might be locked down */
+       value = wdt_readl(wdt, WDTCR);
+
+       if (value & WDTCR_LOCAL_INT_ENABLE)
+               wdt->locked = true;
+
+       source = value & WDTCR_TIMER_SOURCE_MASK;
+
+       wdt->tmr = tegra186_tmr_create(tegra, source);
+       if (IS_ERR(wdt->tmr))
+               return ERR_CAST(wdt->tmr);
+
+       wdt->base.info = &tegra186_wdt_info;
+       wdt->base.ops = &tegra186_wdt_ops;
+       wdt->base.min_timeout = 1;
+       wdt->base.max_timeout = 255;
+       wdt->base.parent = tegra->dev;
+
+       err = watchdog_init_timeout(&wdt->base, 5, tegra->dev);
+       if (err < 0) {
+               dev_err(tegra->dev, "failed to initialize timeout: %d\n", err);
+               return ERR_PTR(err);
+       }
+
+       err = devm_watchdog_register_device(tegra->dev, &wdt->base);
+       if (err < 0) {
+               dev_err(tegra->dev, "failed to register WDT: %d\n", err);
+               return ERR_PTR(err);
+       }
+
+       return wdt;
+}
+
+static u64 tegra186_timer_tsc_read(struct clocksource *cs)
+{
+       struct tegra186_timer *tegra = container_of(cs, struct tegra186_timer,
+                                                   tsc);
+       u32 hi, lo, ss;
+
+       hi = readl_relaxed(tegra->regs + TKETSC1);
+
+       /*
+        * The 56-bit value of the TSC is spread across two registers that are
+        * not synchronized. In order to read them atomically, ensure that the
+        * high 24 bits match before and after reading the low 32 bits.
+        */
+       do {
+               /* snapshot the high 24 bits */
+               ss = hi;
+
+               lo = readl_relaxed(tegra->regs + TKETSC0);
+               hi = readl_relaxed(tegra->regs + TKETSC1);
+       } while (hi != ss);
+
+       return (u64)hi << 32 | lo;
+}
+
+static int tegra186_timer_tsc_init(struct tegra186_timer *tegra)
+{
+       tegra->tsc.name = "tsc";
+       tegra->tsc.rating = 300;
+       tegra->tsc.read = tegra186_timer_tsc_read;
+       tegra->tsc.mask = CLOCKSOURCE_MASK(56);
+       tegra->tsc.flags = CLOCK_SOURCE_IS_CONTINUOUS;
+
+       return clocksource_register_hz(&tegra->tsc, 31250000);
+}
+
+static u64 tegra186_timer_osc_read(struct clocksource *cs)
+{
+       struct tegra186_timer *tegra = container_of(cs, struct tegra186_timer,
+                                                   osc);
+
+       return readl_relaxed(tegra->regs + TKEOSC);
+}
+
+static int tegra186_timer_osc_init(struct tegra186_timer *tegra)
+{
+       tegra->osc.name = "osc";
+       tegra->osc.rating = 300;
+       tegra->osc.read = tegra186_timer_osc_read;
+       tegra->osc.mask = CLOCKSOURCE_MASK(32);
+       tegra->osc.flags = CLOCK_SOURCE_IS_CONTINUOUS;
+
+       return clocksource_register_hz(&tegra->osc, 38400000);
+}
+
+static u64 tegra186_timer_usec_read(struct clocksource *cs)
+{
+       struct tegra186_timer *tegra = container_of(cs, struct tegra186_timer,
+                                                   usec);
+
+       return readl_relaxed(tegra->regs + TKEUSEC);
+}
+
+static int tegra186_timer_usec_init(struct tegra186_timer *tegra)
+{
+       tegra->usec.name = "usec";
+       tegra->usec.rating = 300;
+       tegra->usec.read = tegra186_timer_usec_read;
+       tegra->usec.mask = CLOCKSOURCE_MASK(32);
+       tegra->usec.flags = CLOCK_SOURCE_IS_CONTINUOUS;
+
+       return clocksource_register_hz(&tegra->usec, USEC_PER_SEC);
+}
+
+static irqreturn_t tegra186_timer_irq(int irq, void *data)
+{
+       struct tegra186_timer *tegra = data;
+
+       if (watchdog_active(&tegra->wdt->base)) {
+               tegra186_wdt_disable(tegra->wdt);
+               tegra186_wdt_enable(tegra->wdt);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int tegra186_timer_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct tegra186_timer *tegra;
+       unsigned int irq;
+       int err;
+
+       tegra = devm_kzalloc(dev, sizeof(*tegra), GFP_KERNEL);
+       if (!tegra)
+               return -ENOMEM;
+
+       tegra->soc = of_device_get_match_data(dev);
+       dev_set_drvdata(dev, tegra);
+       tegra->dev = dev;
+
+       tegra->regs = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(tegra->regs))
+               return PTR_ERR(tegra->regs);
+
+       err = platform_get_irq(pdev, 0);
+       if (err < 0)
+               return err;
+
+       irq = err;
+
+       /* create a watchdog using a preconfigured timer */
+       tegra->wdt = tegra186_wdt_create(tegra, 0);
+       if (IS_ERR(tegra->wdt)) {
+               err = PTR_ERR(tegra->wdt);
+               dev_err(dev, "failed to create WDT: %d\n", err);
+               return err;
+       }
+
+       err = tegra186_timer_tsc_init(tegra);
+       if (err < 0) {
+               dev_err(dev, "failed to register TSC counter: %d\n", err);
+               return err;
+       }
+
+       err = tegra186_timer_osc_init(tegra);
+       if (err < 0) {
+               dev_err(dev, "failed to register OSC counter: %d\n", err);
+               goto unregister_tsc;
+       }
+
+       err = tegra186_timer_usec_init(tegra);
+       if (err < 0) {
+               dev_err(dev, "failed to register USEC counter: %d\n", err);
+               goto unregister_osc;
+       }
+
+       err = devm_request_irq(dev, irq, tegra186_timer_irq, 0,
+                              "tegra186-timer", tegra);
+       if (err < 0) {
+               dev_err(dev, "failed to request IRQ#%u: %d\n", irq, err);
+               goto unregister_usec;
+       }
+
+       return 0;
+
+unregister_usec:
+       clocksource_unregister(&tegra->usec);
+unregister_osc:
+       clocksource_unregister(&tegra->osc);
+unregister_tsc:
+       clocksource_unregister(&tegra->tsc);
+       return err;
+}
+
+static int tegra186_timer_remove(struct platform_device *pdev)
+{
+       struct tegra186_timer *tegra = platform_get_drvdata(pdev);
+
+       clocksource_unregister(&tegra->usec);
+       clocksource_unregister(&tegra->osc);
+       clocksource_unregister(&tegra->tsc);
+
+       return 0;
+}
+
+static int __maybe_unused tegra186_timer_suspend(struct device *dev)
+{
+       struct tegra186_timer *tegra = dev_get_drvdata(dev);
+
+       if (watchdog_active(&tegra->wdt->base))
+               tegra186_wdt_disable(tegra->wdt);
+
+       return 0;
+}
+
+static int __maybe_unused tegra186_timer_resume(struct device *dev)
+{
+       struct tegra186_timer *tegra = dev_get_drvdata(dev);
+
+       if (watchdog_active(&tegra->wdt->base))
+               tegra186_wdt_enable(tegra->wdt);
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(tegra186_timer_pm_ops, tegra186_timer_suspend,
+                        tegra186_timer_resume);
+
+static const struct tegra186_timer_soc tegra186_timer = {
+       .num_timers = 10,
+       .num_wdts = 3,
+};
+
+static const struct tegra186_timer_soc tegra234_timer = {
+       .num_timers = 16,
+       .num_wdts = 3,
+};
+
+static const struct of_device_id tegra186_timer_of_match[] = {
+       { .compatible = "nvidia,tegra186-timer", .data = &tegra186_timer },
+       { .compatible = "nvidia,tegra234-timer", .data = &tegra234_timer },
+       { }
+};
+MODULE_DEVICE_TABLE(of, tegra186_timer_of_match);
+
+static struct platform_driver tegra186_wdt_driver = {
+       .driver = {
+               .name = "tegra186-timer",
+               .pm = &tegra186_timer_pm_ops,
+               .of_match_table = tegra186_timer_of_match,
+       },
+       .probe = tegra186_timer_probe,
+       .remove = tegra186_timer_remove,
+};
+module_platform_driver(tegra186_wdt_driver);
+
+MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
+MODULE_DESCRIPTION("NVIDIA Tegra186 timers driver");
+MODULE_LICENSE("GPL v2");
index c194e8f..469f7c9 100644 (file)
@@ -44,6 +44,121 @@ enum {
        REQUEST_BY_NODE,
 };
 
+static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
+                                               int posted)
+{
+       if (posted)
+               while (readl_relaxed(timer->pend) & (reg >> WPSHIFT))
+                       cpu_relax();
+
+       return readl_relaxed(timer->func_base + (reg & 0xff));
+}
+
+static inline void __omap_dm_timer_write(struct omap_dm_timer *timer,
+                                       u32 reg, u32 val, int posted)
+{
+       if (posted)
+               while (readl_relaxed(timer->pend) & (reg >> WPSHIFT))
+                       cpu_relax();
+
+       writel_relaxed(val, timer->func_base + (reg & 0xff));
+}
+
+static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)
+{
+       u32 tidr;
+
+       /* Assume v1 ip if bits [31:16] are zero */
+       tidr = readl_relaxed(timer->io_base);
+       if (!(tidr >> 16)) {
+               timer->revision = 1;
+               timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET;
+               timer->irq_ena = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET;
+               timer->irq_dis = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET;
+               timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET;
+               timer->func_base = timer->io_base;
+       } else {
+               timer->revision = 2;
+               timer->irq_stat = timer->io_base + OMAP_TIMER_V2_IRQSTATUS;
+               timer->irq_ena = timer->io_base + OMAP_TIMER_V2_IRQENABLE_SET;
+               timer->irq_dis = timer->io_base + OMAP_TIMER_V2_IRQENABLE_CLR;
+               timer->pend = timer->io_base +
+                       _OMAP_TIMER_WRITE_PEND_OFFSET +
+                               OMAP_TIMER_V2_FUNC_OFFSET;
+               timer->func_base = timer->io_base + OMAP_TIMER_V2_FUNC_OFFSET;
+       }
+}
+
+/*
+ * __omap_dm_timer_enable_posted - enables write posted mode
+ * @timer:      pointer to timer instance handle
+ *
+ * Enables the write posted mode for the timer. When posted mode is enabled
+ * writes to certain timer registers are immediately acknowledged by the
+ * internal bus and hence prevents stalling the CPU waiting for the write to
+ * complete. Enabling this feature can improve performance for writing to the
+ * timer registers.
+ */
+static inline void __omap_dm_timer_enable_posted(struct omap_dm_timer *timer)
+{
+       if (timer->posted)
+               return;
+
+       if (timer->errata & OMAP_TIMER_ERRATA_I103_I767) {
+               timer->posted = OMAP_TIMER_NONPOSTED;
+               __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG, 0, 0);
+               return;
+       }
+
+       __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG,
+                             OMAP_TIMER_CTRL_POSTED, 0);
+       timer->context.tsicr = OMAP_TIMER_CTRL_POSTED;
+       timer->posted = OMAP_TIMER_POSTED;
+}
+
+static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer,
+                                       int posted, unsigned long rate)
+{
+       u32 l;
+
+       l = __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted);
+       if (l & OMAP_TIMER_CTRL_ST) {
+               l &= ~0x1;
+               __omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, l, posted);
+#ifdef CONFIG_ARCH_OMAP2PLUS
+               /* Readback to make sure write has completed */
+               __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted);
+               /*
+                * Wait for functional clock period x 3.5 to make sure that
+                * timer is stopped
+                */
+               udelay(3500000 / rate + 1);
+#endif
+       }
+
+       /* Ack possibly pending interrupt */
+       writel_relaxed(OMAP_TIMER_INT_OVERFLOW, timer->irq_stat);
+}
+
+static inline void __omap_dm_timer_int_enable(struct omap_dm_timer *timer,
+                                               unsigned int value)
+{
+       writel_relaxed(value, timer->irq_ena);
+       __omap_dm_timer_write(timer, OMAP_TIMER_WAKEUP_EN_REG, value, 0);
+}
+
+static inline unsigned int
+__omap_dm_timer_read_counter(struct omap_dm_timer *timer, int posted)
+{
+       return __omap_dm_timer_read(timer, OMAP_TIMER_COUNTER_REG, posted);
+}
+
+static inline void __omap_dm_timer_write_status(struct omap_dm_timer *timer,
+                                               unsigned int value)
+{
+       writel_relaxed(value, timer->irq_stat);
+}
+
 /**
  * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode
  * @timer:      timer pointer over which read operation to perform
@@ -921,6 +1036,10 @@ static const struct dmtimer_platform_data omap3plus_pdata = {
        .timer_ops = &dmtimer_ops,
 };
 
+static const struct dmtimer_platform_data am6_pdata = {
+       .timer_ops = &dmtimer_ops,
+};
+
 static const struct of_device_id omap_timer_match[] = {
        {
                .compatible = "ti,omap2420-timer",
@@ -949,6 +1068,10 @@ static const struct of_device_id omap_timer_match[] = {
                .compatible = "ti,dm816-timer",
                .data = &omap3plus_pdata,
        },
+       {
+               .compatible = "ti,am654-timer",
+               .data = &am6_pdata,
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, omap_timer_match);
index c3038cd..2a84fc6 100644 (file)
@@ -268,7 +268,7 @@ config LOONGSON2_CPUFREQ
          This option adds a CPUFreq driver for loongson processors which
          support software configurable cpu frequency.
 
-         Loongson2F and it's successors support this feature.
+         Loongson2F and its successors support this feature.
 
          If in doubt, say N.
 
index 3d514b8..1bb2b90 100644 (file)
@@ -78,6 +78,8 @@ static bool boost_state(unsigned int cpu)
 
        switch (boot_cpu_data.x86_vendor) {
        case X86_VENDOR_INTEL:
+       case X86_VENDOR_CENTAUR:
+       case X86_VENDOR_ZHAOXIN:
                rdmsr_on_cpu(cpu, MSR_IA32_MISC_ENABLE, &lo, &hi);
                msr = lo | ((u64)hi << 32);
                return !(msr & MSR_IA32_MISC_ENABLE_TURBO_DISABLE);
@@ -97,6 +99,8 @@ static int boost_set_msr(bool enable)
 
        switch (boot_cpu_data.x86_vendor) {
        case X86_VENDOR_INTEL:
+       case X86_VENDOR_CENTAUR:
+       case X86_VENDOR_ZHAOXIN:
                msr_addr = MSR_IA32_MISC_ENABLE;
                msr_mask = MSR_IA32_MISC_ENABLE_TURBO_DISABLE;
                break;
index 7be38bc..9ac75c1 100644 (file)
@@ -566,6 +566,28 @@ static int amd_pstate_cpu_exit(struct cpufreq_policy *policy)
        return 0;
 }
 
+static int amd_pstate_cpu_resume(struct cpufreq_policy *policy)
+{
+       int ret;
+
+       ret = amd_pstate_enable(true);
+       if (ret)
+               pr_err("failed to enable amd-pstate during resume, return %d\n", ret);
+
+       return ret;
+}
+
+static int amd_pstate_cpu_suspend(struct cpufreq_policy *policy)
+{
+       int ret;
+
+       ret = amd_pstate_enable(false);
+       if (ret)
+               pr_err("failed to disable amd-pstate during suspend, return %d\n", ret);
+
+       return ret;
+}
+
 /* Sysfs attributes */
 
 /*
@@ -636,6 +658,8 @@ static struct cpufreq_driver amd_pstate_driver = {
        .target         = amd_pstate_target,
        .init           = amd_pstate_cpu_init,
        .exit           = amd_pstate_cpu_exit,
+       .suspend        = amd_pstate_cpu_suspend,
+       .resume         = amd_pstate_cpu_resume,
        .set_boost      = amd_pstate_set_boost,
        .name           = "amd-pstate",
        .attr           = amd_pstate_attr,
index 96de153..2c96de3 100644 (file)
@@ -127,6 +127,7 @@ static const struct of_device_id blocklist[] __initconst = {
        { .compatible = "mediatek,mt8173", },
        { .compatible = "mediatek,mt8176", },
        { .compatible = "mediatek,mt8183", },
+       { .compatible = "mediatek,mt8186", },
        { .compatible = "mediatek,mt8365", },
        { .compatible = "mediatek,mt8516", },
 
index 2cad427..954eef2 100644 (file)
@@ -843,12 +843,14 @@ ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf)
        unsigned int cpu;
 
        for_each_cpu(cpu, mask) {
-               if (i)
-                       i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), " ");
-               i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), "%u", cpu);
+               i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), "%u ", cpu);
                if (i >= (PAGE_SIZE - 5))
                        break;
        }
+
+       /* Remove the extra space at the end */
+       i--;
+
        i += sprintf(&buf[i], "\n");
        return i;
 }
@@ -971,21 +973,10 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr,
        if (!fattr->store)
                return -EIO;
 
-       /*
-        * cpus_read_trylock() is used here to work around a circular lock
-        * dependency problem with respect to the cpufreq_register_driver().
-        */
-       if (!cpus_read_trylock())
-               return -EBUSY;
-
-       if (cpu_online(policy->cpu)) {
-               down_write(&policy->rwsem);
-               if (likely(!policy_is_inactive(policy)))
-                       ret = fattr->store(policy, buf, count);
-               up_write(&policy->rwsem);
-       }
-
-       cpus_read_unlock();
+       down_write(&policy->rwsem);
+       if (likely(!policy_is_inactive(policy)))
+               ret = fattr->store(policy, buf, count);
+       up_write(&policy->rwsem);
 
        return ret;
 }
@@ -1282,6 +1273,13 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
        unsigned long flags;
        int cpu;
 
+       /*
+        * The callers must ensure the policy is inactive by now, to avoid any
+        * races with show()/store() callbacks.
+        */
+       if (unlikely(!policy_is_inactive(policy)))
+               pr_warn("%s: Freeing active policy\n", __func__);
+
        /* Remove policy from list */
        write_lock_irqsave(&cpufreq_driver_lock, flags);
        list_del(&policy->policy_list);
@@ -1536,8 +1534,6 @@ out_destroy_policy:
        for_each_cpu(j, policy->real_cpus)
                remove_cpu_dev_symlink(policy, j, get_cpu_device(j));
 
-       cpumask_clear(policy->cpus);
-
 out_offline_policy:
        if (cpufreq_driver->offline)
                cpufreq_driver->offline(policy);
@@ -1547,6 +1543,7 @@ out_exit_policy:
                cpufreq_driver->exit(policy);
 
 out_free_policy:
+       cpumask_clear(policy->cpus);
        up_write(&policy->rwsem);
 
        cpufreq_policy_free(policy);
index e8fbf97..c52d19d 100644 (file)
@@ -416,10 +416,13 @@ static struct dbs_governor od_dbs_gov = {
 static void od_set_powersave_bias(unsigned int powersave_bias)
 {
        unsigned int cpu;
-       cpumask_t done;
+       cpumask_var_t done;
+
+       if (!alloc_cpumask_var(&done, GFP_KERNEL))
+               return;
 
        default_powersave_bias = powersave_bias;
-       cpumask_clear(&done);
+       cpumask_clear(done);
 
        cpus_read_lock();
        for_each_online_cpu(cpu) {
@@ -428,7 +431,7 @@ static void od_set_powersave_bias(unsigned int powersave_bias)
                struct dbs_data *dbs_data;
                struct od_dbs_tuners *od_tuners;
 
-               if (cpumask_test_cpu(cpu, &done))
+               if (cpumask_test_cpu(cpu, done))
                        continue;
 
                policy = cpufreq_cpu_get_raw(cpu);
@@ -439,13 +442,15 @@ static void od_set_powersave_bias(unsigned int powersave_bias)
                if (!policy_dbs)
                        continue;
 
-               cpumask_or(&done, &done, policy->cpus);
+               cpumask_or(done, done, policy->cpus);
 
                dbs_data = policy_dbs->dbs_data;
                od_tuners = dbs_data->tuners;
                od_tuners->powersave_bias = default_powersave_bias;
        }
        cpus_read_unlock();
+
+       free_cpumask_var(done);
 }
 
 void od_register_powersave_bias_handler(unsigned int (*f)
index 813cccb..f0e0a35 100644 (file)
@@ -51,7 +51,7 @@ static const u16 cpufreq_mtk_offsets[REG_ARRAY_SIZE] = {
 };
 
 static int __maybe_unused
-mtk_cpufreq_get_cpu_power(struct device *cpu_dev, unsigned long *mW,
+mtk_cpufreq_get_cpu_power(struct device *cpu_dev, unsigned long *uW,
                          unsigned long *KHz)
 {
        struct mtk_cpufreq_data *data;
@@ -71,8 +71,9 @@ mtk_cpufreq_get_cpu_power(struct device *cpu_dev, unsigned long *mW,
        i--;
 
        *KHz = data->table[i].frequency;
-       *mW = readl_relaxed(data->reg_bases[REG_EM_POWER_TBL] +
-                           i * LUT_ROW_SIZE) / 1000;
+       /* Provide micro-Watts value to the Energy Model */
+       *uW = readl_relaxed(data->reg_bases[REG_EM_POWER_TBL] +
+                           i * LUT_ROW_SIZE);
 
        return 0;
 }
index 37a1eb2..76f6b38 100644 (file)
@@ -439,9 +439,13 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
 
        /* Both presence and absence of sram regulator are valid cases. */
        info->sram_reg = regulator_get_optional(cpu_dev, "sram");
-       if (IS_ERR(info->sram_reg))
+       if (IS_ERR(info->sram_reg)) {
+               ret = PTR_ERR(info->sram_reg);
+               if (ret == -EPROBE_DEFER)
+                       goto out_free_resources;
+
                info->sram_reg = NULL;
-       else {
+       else {
                ret = regulator_enable(info->sram_reg);
                if (ret) {
                        dev_warn(cpu_dev, "cpu%d: failed to enable vsram\n", cpu);
index 20f64a8..4b8ee20 100644 (file)
@@ -470,6 +470,10 @@ static int pmac_cpufreq_init_MacRISC3(struct device_node *cpunode)
        if (slew_done_gpio_np)
                slew_done_gpio = read_gpio(slew_done_gpio_np);
 
+       of_node_put(volt_gpio_np);
+       of_node_put(freq_gpio_np);
+       of_node_put(slew_done_gpio_np);
+
        /* If we use the frequency GPIOs, calculate the min/max speeds based
         * on the bus frequencies
         */
index 0253731..36c7958 100644 (file)
@@ -442,6 +442,9 @@ static int qcom_cpufreq_hw_cpu_online(struct cpufreq_policy *policy)
        struct platform_device *pdev = cpufreq_get_driver_data();
        int ret;
 
+       if (data->throttle_irq <= 0)
+               return 0;
+
        ret = irq_set_affinity_hint(data->throttle_irq, policy->cpus);
        if (ret)
                dev_err(&pdev->dev, "Failed to set CPU affinity of %s[%d]\n",
@@ -469,6 +472,9 @@ static int qcom_cpufreq_hw_cpu_offline(struct cpufreq_policy *policy)
 
 static void qcom_cpufreq_hw_lmh_exit(struct qcom_cpufreq_data *data)
 {
+       if (data->throttle_irq <= 0)
+               return;
+
        free_irq(data->throttle_irq, data);
 }
 
index 6b6b20d..573b417 100644 (file)
@@ -275,6 +275,7 @@ static int qoriq_cpufreq_probe(struct platform_device *pdev)
 
        np = of_find_matching_node(NULL, qoriq_cpufreq_blacklist);
        if (np) {
+               of_node_put(np);
                dev_info(&pdev->dev, "Disabling due to erratum A-008083");
                return -ENODEV;
        }
index 6d2a4cf..513a071 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/slab.h>
 #include <linux/scmi_protocol.h>
 #include <linux/types.h>
+#include <linux/units.h>
 
 struct scmi_data {
        int domain_id;
@@ -99,6 +100,7 @@ static int __maybe_unused
 scmi_get_cpu_power(struct device *cpu_dev, unsigned long *power,
                   unsigned long *KHz)
 {
+       enum scmi_power_scale power_scale = perf_ops->power_scale_get(ph);
        unsigned long Hz;
        int ret, domain;
 
@@ -112,6 +114,10 @@ scmi_get_cpu_power(struct device *cpu_dev, unsigned long *power,
        if (ret)
                return ret;
 
+       /* Convert the power to uW if it is mW (ignore bogoW) */
+       if (power_scale == SCMI_POWER_MILLIWATTS)
+               *power *= MICROWATT_PER_MILLIWATT;
+
        /* The EM framework specifies the frequency in KHz. */
        *KHz = Hz / 1000;
 
@@ -249,8 +255,9 @@ static int scmi_cpufreq_exit(struct cpufreq_policy *policy)
 static void scmi_cpufreq_register_em(struct cpufreq_policy *policy)
 {
        struct em_data_callback em_cb = EM_DATA_CB(scmi_get_cpu_power);
-       bool power_scale_mw = perf_ops->power_scale_mw_get(ph);
+       enum scmi_power_scale power_scale = perf_ops->power_scale_get(ph);
        struct scmi_data *priv = policy->driver_data;
+       bool em_power_scale = false;
 
        /*
         * This callback will be called for each policy, but we don't need to
@@ -262,9 +269,13 @@ static void scmi_cpufreq_register_em(struct cpufreq_policy *policy)
        if (!priv->nr_opp)
                return;
 
+       if (power_scale == SCMI_POWER_MILLIWATTS
+           || power_scale == SCMI_POWER_MICROWATTS)
+               em_power_scale = true;
+
        em_dev_register_perf_domain(get_cpu_device(policy->cpu), priv->nr_opp,
                                    &em_cb, priv->opp_shared_cpus,
-                                   power_scale_mw);
+                                   em_power_scale);
 }
 
 static struct cpufreq_driver scmi_cpufreq_driver = {
index be7f512..747aa53 100644 (file)
@@ -3,7 +3,8 @@
 # ARM CPU Idle drivers
 #
 config ARM_CPUIDLE
-       bool "Generic ARM/ARM64 CPU idle Driver"
+       bool "Generic ARM CPU idle Driver"
+       depends on ARM
        select DT_IDLE_STATES
        select CPU_IDLE_MULTIPLE_DRIVERS
        help
index 540105c..57bc3e3 100644 (file)
@@ -69,12 +69,12 @@ static int __psci_enter_domain_idle_state(struct cpuidle_device *dev,
                return -1;
 
        /* Do runtime PM to manage a hierarchical CPU toplogy. */
-       rcu_irq_enter_irqson();
+       ct_irq_enter_irqson();
        if (s2idle)
                dev_pm_genpd_suspend(pd_dev);
        else
                pm_runtime_put_sync_suspend(pd_dev);
-       rcu_irq_exit_irqson();
+       ct_irq_exit_irqson();
 
        state = psci_get_domain_state();
        if (!state)
@@ -82,12 +82,12 @@ static int __psci_enter_domain_idle_state(struct cpuidle_device *dev,
 
        ret = psci_cpu_suspend_enter(state) ? -1 : idx;
 
-       rcu_irq_enter_irqson();
+       ct_irq_enter_irqson();
        if (s2idle)
                dev_pm_genpd_resume(pd_dev);
        else
                pm_runtime_get_sync(pd_dev);
-       rcu_irq_exit_irqson();
+       ct_irq_exit_irqson();
 
        cpu_pm_exit();
 
index 1151e5e..862a287 100644 (file)
@@ -116,12 +116,12 @@ static int __sbi_enter_domain_idle_state(struct cpuidle_device *dev,
                return -1;
 
        /* Do runtime PM to manage a hierarchical CPU toplogy. */
-       rcu_irq_enter_irqson();
+       ct_irq_enter_irqson();
        if (s2idle)
                dev_pm_genpd_suspend(pd_dev);
        else
                pm_runtime_put_sync_suspend(pd_dev);
-       rcu_irq_exit_irqson();
+       ct_irq_exit_irqson();
 
        if (sbi_is_domain_state_available())
                state = sbi_get_domain_state();
@@ -130,12 +130,12 @@ static int __sbi_enter_domain_idle_state(struct cpuidle_device *dev,
 
        ret = sbi_suspend(state) ? -1 : idx;
 
-       rcu_irq_enter_irqson();
+       ct_irq_enter_irqson();
        if (s2idle)
                dev_pm_genpd_resume(pd_dev);
        else
                pm_runtime_get_sync(pd_dev);
-       rcu_irq_exit_irqson();
+       ct_irq_exit_irqson();
 
        cpu_pm_exit();
 
index ef2ea1b..62dd956 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/suspend.h>
 #include <linux/tick.h>
 #include <linux/mmu_context.h>
+#include <linux/context_tracking.h>
 #include <trace/events/power.h>
 
 #include "cpuidle.h"
@@ -150,12 +151,12 @@ static void enter_s2idle_proper(struct cpuidle_driver *drv,
         */
        stop_critical_timings();
        if (!(target_state->flags & CPUIDLE_FLAG_RCU_IDLE))
-               rcu_idle_enter();
+               ct_idle_enter();
        target_state->enter_s2idle(dev, drv, index);
        if (WARN_ON_ONCE(!irqs_disabled()))
                local_irq_disable();
        if (!(target_state->flags & CPUIDLE_FLAG_RCU_IDLE))
-               rcu_idle_exit();
+               ct_idle_exit();
        tick_unfreeze();
        start_critical_timings();
 
@@ -233,10 +234,10 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
 
        stop_critical_timings();
        if (!(target_state->flags & CPUIDLE_FLAG_RCU_IDLE))
-               rcu_idle_enter();
+               ct_idle_enter();
        entered_state = target_state->enter(dev, drv, index);
        if (!(target_state->flags & CPUIDLE_FLAG_RCU_IDLE))
-               rcu_idle_exit();
+               ct_idle_exit();
        start_critical_timings();
 
        sched_clock_idle_wakeup_event();
index cb2a96e..1dff3a5 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/sched.h>
 #include <linux/module.h>
 #include <linux/kvm_para.h>
+#include <trace/events/power.h>
 
 static unsigned int guest_halt_poll_ns __read_mostly = 200000;
 module_param(guest_halt_poll_ns, uint, 0644);
@@ -90,6 +91,7 @@ static void adjust_poll_limit(struct cpuidle_device *dev, u64 block_ns)
                if (val > guest_halt_poll_ns)
                        val = guest_halt_poll_ns;
 
+               trace_guest_halt_poll_ns_grow(val, dev->poll_limit_ns);
                dev->poll_limit_ns = val;
        } else if (block_ns > guest_halt_poll_ns &&
                   guest_halt_poll_allow_shrink) {
@@ -100,6 +102,7 @@ static void adjust_poll_limit(struct cpuidle_device *dev, u64 block_ns)
                        val = 0;
                else
                        val /= shrink;
+               trace_guest_halt_poll_ns_shrink(val, dev->poll_limit_ns);
                dev->poll_limit_ns = val;
        }
 }
index ee99c02..3e6aa31 100644 (file)
@@ -133,98 +133,6 @@ config CRYPTO_PAES_S390
          Select this option if you want to use the paes cipher
          for example to use protected key encrypted devices.
 
-config CRYPTO_SHA1_S390
-       tristate "SHA1 digest algorithm"
-       depends on S390
-       select CRYPTO_HASH
-       help
-         This is the s390 hardware accelerated implementation of the
-         SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
-
-         It is available as of z990.
-
-config CRYPTO_SHA256_S390
-       tristate "SHA256 digest algorithm"
-       depends on S390
-       select CRYPTO_HASH
-       help
-         This is the s390 hardware accelerated implementation of the
-         SHA256 secure hash standard (DFIPS 180-2).
-
-         It is available as of z9.
-
-config CRYPTO_SHA512_S390
-       tristate "SHA384 and SHA512 digest algorithm"
-       depends on S390
-       select CRYPTO_HASH
-       help
-         This is the s390 hardware accelerated implementation of the
-         SHA512 secure hash standard.
-
-         It is available as of z10.
-
-config CRYPTO_SHA3_256_S390
-       tristate "SHA3_224 and SHA3_256 digest algorithm"
-       depends on S390
-       select CRYPTO_HASH
-       help
-         This is the s390 hardware accelerated implementation of the
-         SHA3_256 secure hash standard.
-
-         It is available as of z14.
-
-config CRYPTO_SHA3_512_S390
-       tristate "SHA3_384 and SHA3_512 digest algorithm"
-       depends on S390
-       select CRYPTO_HASH
-       help
-         This is the s390 hardware accelerated implementation of the
-         SHA3_512 secure hash standard.
-
-         It is available as of z14.
-
-config CRYPTO_DES_S390
-       tristate "DES and Triple DES cipher algorithms"
-       depends on S390
-       select CRYPTO_ALGAPI
-       select CRYPTO_SKCIPHER
-       select CRYPTO_LIB_DES
-       help
-         This is the s390 hardware accelerated implementation of the
-         DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
-
-         As of z990 the ECB and CBC mode are hardware accelerated.
-         As of z196 the CTR mode is hardware accelerated.
-
-config CRYPTO_AES_S390
-       tristate "AES cipher algorithms"
-       depends on S390
-       select CRYPTO_ALGAPI
-       select CRYPTO_SKCIPHER
-       help
-         This is the s390 hardware accelerated implementation of the
-         AES cipher algorithms (FIPS-197).
-
-         As of z9 the ECB and CBC modes are hardware accelerated
-         for 128 bit keys.
-         As of z10 the ECB and CBC modes are hardware accelerated
-         for all AES key sizes.
-         As of z196 the CTR mode is hardware accelerated for all AES
-         key sizes and XTS mode is hardware accelerated for 256 and
-         512 bit keys.
-
-config CRYPTO_CHACHA_S390
-       tristate "ChaCha20 stream cipher"
-       depends on S390
-       select CRYPTO_SKCIPHER
-       select CRYPTO_LIB_CHACHA_GENERIC
-       select CRYPTO_ARCH_HAVE_LIB_CHACHA
-       help
-         This is the s390 SIMD implementation of the ChaCha20 stream
-         cipher (RFC 7539).
-
-         It is available as of z13.
-
 config S390_PRNG
        tristate "Pseudo random number generator device driver"
        depends on S390
@@ -238,29 +146,6 @@ config S390_PRNG
 
          It is available as of z9.
 
-config CRYPTO_GHASH_S390
-       tristate "GHASH hash function"
-       depends on S390
-       select CRYPTO_HASH
-       help
-         This is the s390 hardware accelerated implementation of GHASH,
-         the hash function used in GCM (Galois/Counter mode).
-
-         It is available as of z196.
-
-config CRYPTO_CRC32_S390
-       tristate "CRC-32 algorithms"
-       depends on S390
-       select CRYPTO_HASH
-       select CRC32
-       help
-         Select this option if you want to use hardware accelerated
-         implementations of CRC algorithms.  With this option, you
-         can optimize the computation of CRC-32 (IEEE 802.3 Ethernet)
-         and CRC-32C (Castagnoli).
-
-         It is available with IBM z13 or later.
-
 config CRYPTO_DEV_NIAGARA2
        tristate "Niagara2 Stream Processing Unit driver"
        select CRYPTO_LIB_DES
index 5bb9501..910d675 100644 (file)
@@ -170,6 +170,7 @@ dma_iv_error:
        while (i >= 0) {
                dma_unmap_single(ss->dev, rctx->p_iv[i], ivsize, DMA_TO_DEVICE);
                memzero_explicit(sf->iv[i], ivsize);
+               i--;
        }
        return err;
 }
index 98593a0..ac2329e 100644 (file)
@@ -528,25 +528,33 @@ static int allocate_flows(struct sun8i_ss_dev *ss)
 
                ss->flows[i].biv = devm_kmalloc(ss->dev, AES_BLOCK_SIZE,
                                                GFP_KERNEL | GFP_DMA);
-               if (!ss->flows[i].biv)
+               if (!ss->flows[i].biv) {
+                       err = -ENOMEM;
                        goto error_engine;
+               }
 
                for (j = 0; j < MAX_SG; j++) {
                        ss->flows[i].iv[j] = devm_kmalloc(ss->dev, AES_BLOCK_SIZE,
                                                          GFP_KERNEL | GFP_DMA);
-                       if (!ss->flows[i].iv[j])
+                       if (!ss->flows[i].iv[j]) {
+                               err = -ENOMEM;
                                goto error_engine;
+                       }
                }
 
                /* the padding could be up to two block. */
                ss->flows[i].pad = devm_kmalloc(ss->dev, MAX_PAD_SIZE,
                                                GFP_KERNEL | GFP_DMA);
-               if (!ss->flows[i].pad)
+               if (!ss->flows[i].pad) {
+                       err = -ENOMEM;
                        goto error_engine;
+               }
                ss->flows[i].result = devm_kmalloc(ss->dev, SHA256_DIGEST_SIZE,
                                                   GFP_KERNEL | GFP_DMA);
-               if (!ss->flows[i].result)
+               if (!ss->flows[i].result) {
+                       err = -ENOMEM;
                        goto error_engine;
+               }
 
                ss->flows[i].engine = crypto_engine_alloc_init(ss->dev, true);
                if (!ss->flows[i].engine) {
index ac417a6..36a82b2 100644 (file)
@@ -30,8 +30,8 @@ static int sun8i_ss_hashkey(struct sun8i_ss_hash_tfm_ctx *tfmctx, const u8 *key,
        int ret = 0;
 
        xtfm = crypto_alloc_shash("sha1", 0, CRYPTO_ALG_NEED_FALLBACK);
-       if (!xtfm)
-               return -ENOMEM;
+       if (IS_ERR(xtfm))
+               return PTR_ERR(xtfm);
 
        len = sizeof(*sdesc) + crypto_shash_descsize(xtfm);
        sdesc = kmalloc(len, GFP_KERNEL);
@@ -586,7 +586,8 @@ retry:
                        rctx->t_dst[k + 1].len = rctx->t_dst[k].len;
                }
                addr_xpad = dma_map_single(ss->dev, tfmctx->ipad, bs, DMA_TO_DEVICE);
-               if (dma_mapping_error(ss->dev, addr_xpad)) {
+               err = dma_mapping_error(ss->dev, addr_xpad);
+               if (err) {
                        dev_err(ss->dev, "Fail to create DMA mapping of ipad\n");
                        goto err_dma_xpad;
                }
@@ -612,7 +613,8 @@ retry:
                        goto err_dma_result;
                }
                addr_xpad = dma_map_single(ss->dev, tfmctx->opad, bs, DMA_TO_DEVICE);
-               if (dma_mapping_error(ss->dev, addr_xpad)) {
+               err = dma_mapping_error(ss->dev, addr_xpad);
+               if (err) {
                        dev_err(ss->dev, "Fail to create DMA mapping of opad\n");
                        goto err_dma_xpad;
                }
index 8278d98..280f4b0 100644 (file)
@@ -1378,6 +1378,7 @@ static int crypto4xx_probe(struct platform_device *ofdev)
        struct resource res;
        struct device *dev = &ofdev->dev;
        struct crypto4xx_core_device *core_dev;
+       struct device_node *np;
        u32 pvr;
        bool is_revb = true;
 
@@ -1385,29 +1386,36 @@ static int crypto4xx_probe(struct platform_device *ofdev)
        if (rc)
                return -ENODEV;
 
-       if (of_find_compatible_node(NULL, NULL, "amcc,ppc460ex-crypto")) {
+       np = of_find_compatible_node(NULL, NULL, "amcc,ppc460ex-crypto");
+       if (np) {
                mtdcri(SDR0, PPC460EX_SDR0_SRST,
                       mfdcri(SDR0, PPC460EX_SDR0_SRST) | PPC460EX_CE_RESET);
                mtdcri(SDR0, PPC460EX_SDR0_SRST,
                       mfdcri(SDR0, PPC460EX_SDR0_SRST) & ~PPC460EX_CE_RESET);
-       } else if (of_find_compatible_node(NULL, NULL,
-                       "amcc,ppc405ex-crypto")) {
-               mtdcri(SDR0, PPC405EX_SDR0_SRST,
-                      mfdcri(SDR0, PPC405EX_SDR0_SRST) | PPC405EX_CE_RESET);
-               mtdcri(SDR0, PPC405EX_SDR0_SRST,
-                      mfdcri(SDR0, PPC405EX_SDR0_SRST) & ~PPC405EX_CE_RESET);
-               is_revb = false;
-       } else if (of_find_compatible_node(NULL, NULL,
-                       "amcc,ppc460sx-crypto")) {
-               mtdcri(SDR0, PPC460SX_SDR0_SRST,
-                      mfdcri(SDR0, PPC460SX_SDR0_SRST) | PPC460SX_CE_RESET);
-               mtdcri(SDR0, PPC460SX_SDR0_SRST,
-                      mfdcri(SDR0, PPC460SX_SDR0_SRST) & ~PPC460SX_CE_RESET);
        } else {
-               printk(KERN_ERR "Crypto Function Not supported!\n");
-               return -EINVAL;
+               np = of_find_compatible_node(NULL, NULL, "amcc,ppc405ex-crypto");
+               if (np) {
+                       mtdcri(SDR0, PPC405EX_SDR0_SRST,
+                                  mfdcri(SDR0, PPC405EX_SDR0_SRST) | PPC405EX_CE_RESET);
+                       mtdcri(SDR0, PPC405EX_SDR0_SRST,
+                                  mfdcri(SDR0, PPC405EX_SDR0_SRST) & ~PPC405EX_CE_RESET);
+                       is_revb = false;
+               } else {
+                       np = of_find_compatible_node(NULL, NULL, "amcc,ppc460sx-crypto");
+                       if (np) {
+                               mtdcri(SDR0, PPC460SX_SDR0_SRST,
+                                       mfdcri(SDR0, PPC460SX_SDR0_SRST) | PPC460SX_CE_RESET);
+                               mtdcri(SDR0, PPC460SX_SDR0_SRST,
+                                       mfdcri(SDR0, PPC460SX_SDR0_SRST) & ~PPC460SX_CE_RESET);
+                       } else {
+                               printk(KERN_ERR "Crypto Function Not supported!\n");
+                               return -EINVAL;
+                       }
+               }
        }
 
+       of_node_put(np);
+
        core_dev = kzalloc(sizeof(struct crypto4xx_core_device), GFP_KERNEL);
        if (!core_dev)
                return -ENOMEM;
index f72c6b3..886bf25 100644 (file)
@@ -2669,8 +2669,7 @@ static int atmel_aes_remove(struct platform_device *pdev)
        struct atmel_aes_dev *aes_dd;
 
        aes_dd = platform_get_drvdata(pdev);
-       if (!aes_dd)
-               return -ENODEV;
+
        spin_lock(&atmel_aes.lock);
        list_del(&aes_dd->list);
        spin_unlock(&atmel_aes.lock);
index 59a5727..a4b13d3 100644 (file)
@@ -349,8 +349,16 @@ static int atmel_ecc_remove(struct i2c_client *client)
 
        /* Return EBUSY if i2c client already allocated. */
        if (atomic_read(&i2c_priv->tfm_count)) {
-               dev_err(&client->dev, "Device is busy\n");
-               return -EBUSY;
+               /*
+                * After we return here, the memory backing the device is freed.
+                * That happens no matter what the return value of this function
+                * is because in the Linux device model there is no error
+                * handling for unbinding a driver.
+                * If there is still some action pending, it probably involves
+                * accessing the freed memory.
+                */
+               dev_emerg(&client->dev, "Device is busy, expect memory corruption.\n");
+               return 0;
        }
 
        crypto_unregister_kpp(&atmel_ecdh_nist_p256);
index d162811..ca4b019 100644 (file)
@@ -2666,11 +2666,8 @@ err_tasklet_kill:
 
 static int atmel_sha_remove(struct platform_device *pdev)
 {
-       struct atmel_sha_dev *sha_dd;
+       struct atmel_sha_dev *sha_dd = platform_get_drvdata(pdev);
 
-       sha_dd = platform_get_drvdata(pdev);
-       if (!sha_dd)
-               return -ENODEV;
        spin_lock(&atmel_sha.lock);
        list_del(&sha_dd->list);
        spin_unlock(&atmel_sha.lock);
index 9fd7b8e..8b7bc10 100644 (file)
@@ -1263,11 +1263,8 @@ err_tasklet_kill:
 
 static int atmel_tdes_remove(struct platform_device *pdev)
 {
-       struct atmel_tdes_dev *tdes_dd;
+       struct atmel_tdes_dev *tdes_dd = platform_get_drvdata(pdev);
 
-       tdes_dd = platform_get_drvdata(pdev);
-       if (!tdes_dd)
-               return -ENODEV;
        spin_lock(&atmel_tdes.lock);
        list_del(&tdes_dd->list);
        spin_unlock(&atmel_tdes.lock);
index 6753f0e..4482cb1 100644 (file)
@@ -29,7 +29,7 @@
                                 SHA512_DIGEST_SIZE * 2)
 
 /*
- * This is a cache of buffers, from which the users of CAAM QI driver
+ * This is a cache of buffers, from which the users of CAAM QI driver
  * can allocate short buffers. It's speedier than doing kmalloc on the hotpath.
  * NOTE: A more elegant solution would be to have some headroom in the frames
  *       being processed. This can be added by the dpaa2-eth driver. This would
@@ -5083,8 +5083,9 @@ static int __cold dpaa2_dpseci_setup(struct fsl_mc_device *ls_dev)
 
                ppriv->net_dev.dev = *dev;
                INIT_LIST_HEAD(&ppriv->net_dev.napi_list);
-               netif_napi_add(&ppriv->net_dev, &ppriv->napi, dpaa2_dpseci_poll,
-                              DPAA2_CAAM_NAPI_WEIGHT);
+               netif_napi_add_tx_weight(&ppriv->net_dev, &ppriv->napi,
+                                        dpaa2_dpseci_poll,
+                                        DPAA2_CAAM_NAPI_WEIGHT);
        }
 
        return 0;
index 78383d7..6195645 100644 (file)
@@ -22,7 +22,7 @@
  * @ctx_len: size of Context Register
  * @import_ctx: true if previous Context Register needs to be restored
  *              must be true for ahash update and final
- *              must be false for for ahash first and digest
+ *              must be false for ahash first and digest
  * @era: SEC Era
  */
 void cnstr_shdsc_ahash(u32 * const desc, struct alginfo *adata, u32 state,
index 8163f5d..c36f273 100644 (file)
@@ -75,7 +75,7 @@ bool caam_congested __read_mostly;
 EXPORT_SYMBOL(caam_congested);
 
 /*
- * This is a cache of buffers, from which the users of CAAM QI driver
+ * This is a cache of buffers, from which the users of CAAM QI driver
  * can allocate short (CAAM_QI_MEMCACHE_SIZE) buffers. It's faster than
  * doing malloc on the hotpath.
  * NOTE: A more elegant solution would be to have some headroom in the frames
@@ -749,8 +749,8 @@ int caam_qi_init(struct platform_device *caam_pdev)
                net_dev->dev = *qidev;
                INIT_LIST_HEAD(&net_dev->napi_list);
 
-               netif_napi_add(net_dev, irqtask, caam_qi_poll,
-                              CAAM_NAPI_WEIGHT);
+               netif_napi_add_tx_weight(net_dev, irqtask, caam_qi_poll,
+                                        CAAM_NAPI_WEIGHT);
 
                napi_enable(irqtask);
        }
index 96bc963..8ec6edc 100644 (file)
@@ -265,7 +265,7 @@ union cptx_pf_exe_bist_status {
  *     big-endian format in memory.
  *  iqb_ldwb:1 [7:7](R/W) Instruction load don't write back.
  *     0 = The hardware issues NCB transient load (LDT) towards the cache,
- *     which if the line hits and is is dirty will cause the line to be
+ *     which if the line hits and it is dirty will cause the line to be
  *     written back before being replaced.
  *     1 = The hardware issues NCB LDWB read-and-invalidate command towards
  *     the cache when fetching the last word of instructions; as a result the
index a5d9123..83350e2 100644 (file)
@@ -366,7 +366,7 @@ struct ccp_device {
 
        /* Master lists that all cmds are queued on. Because there can be
         * more than one CCP command queue that can process a cmd a separate
-        * backlog list is neeeded so that the backlog completion call
+        * backlog list is needed so that the backlog completion call
         * completes before the cmd is available for execution.
         */
        spinlock_t cmd_lock ____cacheline_aligned;
index 799b476..9f588c9 100644 (file)
@@ -503,7 +503,7 @@ static int __sev_platform_shutdown_locked(int *error)
        struct sev_device *sev = psp_master->sev_data;
        int ret;
 
-       if (sev->state == SEV_STATE_UNINIT)
+       if (!sev || sev->state == SEV_STATE_UNINIT)
                return 0;
 
        ret = __sev_do_cmd_locked(SEV_CMD_SHUTDOWN, NULL, error);
@@ -577,6 +577,8 @@ static int sev_ioctl_do_platform_status(struct sev_issue_cmd *argp)
        struct sev_user_data_status data;
        int ret;
 
+       memset(&data, 0, sizeof(data));
+
        ret = __sev_do_cmd_locked(SEV_CMD_PLATFORM_STATUS, &data, &argp->error);
        if (ret)
                return ret;
@@ -630,7 +632,7 @@ static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp, bool writable)
        if (input.length > SEV_FW_BLOB_MAX_SIZE)
                return -EFAULT;
 
-       blob = kmalloc(input.length, GFP_KERNEL);
+       blob = kzalloc(input.length, GFP_KERNEL);
        if (!blob)
                return -ENOMEM;
 
@@ -854,7 +856,7 @@ static int sev_ioctl_do_get_id2(struct sev_issue_cmd *argp)
        input_address = (void __user *)input.address;
 
        if (input.address && input.length) {
-               id_blob = kmalloc(input.length, GFP_KERNEL);
+               id_blob = kzalloc(input.length, GFP_KERNEL);
                if (!id_blob)
                        return -ENOMEM;
 
@@ -973,14 +975,14 @@ static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp, bool writable)
        if (input.cert_chain_len > SEV_FW_BLOB_MAX_SIZE)
                return -EFAULT;
 
-       pdh_blob = kmalloc(input.pdh_cert_len, GFP_KERNEL);
+       pdh_blob = kzalloc(input.pdh_cert_len, GFP_KERNEL);
        if (!pdh_blob)
                return -ENOMEM;
 
        data.pdh_cert_address = __psp_pa(pdh_blob);
        data.pdh_cert_len = input.pdh_cert_len;
 
-       cert_blob = kmalloc(input.cert_chain_len, GFP_KERNEL);
+       cert_blob = kzalloc(input.cert_chain_len, GFP_KERNEL);
        if (!cert_blob) {
                ret = -ENOMEM;
                goto e_free_pdh;
index b5970ae..792d6da 100644 (file)
@@ -429,6 +429,12 @@ static const struct sp_dev_vdata dev_vdata[] = {
                .psp_vdata = &pspv2,
 #endif
        },
+       {       /* 6 */
+               .bar = 2,
+#ifdef CONFIG_CRYPTO_DEV_SP_PSP
+               .psp_vdata = &pspv3,
+#endif
+       },
 };
 static const struct pci_device_id sp_pci_table[] = {
        { PCI_VDEVICE(AMD, 0x1537), (kernel_ulong_t)&dev_vdata[0] },
@@ -438,6 +444,7 @@ static const struct pci_device_id sp_pci_table[] = {
        { PCI_VDEVICE(AMD, 0x15DF), (kernel_ulong_t)&dev_vdata[4] },
        { PCI_VDEVICE(AMD, 0x1649), (kernel_ulong_t)&dev_vdata[4] },
        { PCI_VDEVICE(AMD, 0x14CA), (kernel_ulong_t)&dev_vdata[5] },
+       { PCI_VDEVICE(AMD, 0x15C7), (kernel_ulong_t)&dev_vdata[6] },
        /* Last entry must be zero */
        { 0, }
 };
index 9dba52f..7d79a87 100644 (file)
@@ -85,17 +85,9 @@ static int sp_get_irqs(struct sp_device *sp)
        struct sp_platform *sp_platform = sp->dev_specific;
        struct device *dev = sp->dev;
        struct platform_device *pdev = to_platform_device(dev);
-       unsigned int i, count;
        int ret;
 
-       for (i = 0, count = 0; i < pdev->num_resources; i++) {
-               struct resource *res = &pdev->resource[i];
-
-               if (resource_type(res) == IORESOURCE_IRQ)
-                       count++;
-       }
-
-       sp_platform->irq_count = count;
+       sp_platform->irq_count = platform_irq_count(pdev);
 
        ret = platform_get_irq(pdev, 0);
        if (ret < 0) {
@@ -104,7 +96,7 @@ static int sp_get_irqs(struct sp_device *sp)
        }
 
        sp->psp_irq = ret;
-       if (count == 1) {
+       if (sp_platform->irq_count == 1) {
                sp->ccp_irq = ret;
        } else {
                ret = platform_get_irq(pdev, 1);
index 7d1bee8..cadead1 100644 (file)
@@ -372,17 +372,10 @@ static int init_cc_resources(struct platform_device *plat_dev)
                dev->dma_mask = &dev->coherent_dma_mask;
 
        dma_mask = DMA_BIT_MASK(DMA_BIT_MASK_LEN);
-       while (dma_mask > 0x7fffffffUL) {
-               if (dma_supported(dev, dma_mask)) {
-                       rc = dma_set_coherent_mask(dev, dma_mask);
-                       if (!rc)
-                               break;
-               }
-               dma_mask >>= 1;
-       }
-
+       rc = dma_set_coherent_mask(dev, dma_mask);
        if (rc) {
-               dev_err(dev, "Failed in dma_set_mask, mask=%llx\n", dma_mask);
+               dev_err(dev, "Failed in dma_set_coherent_mask, mask=%llx\n",
+                       dma_mask);
                return rc;
        }
 
index d5421b0..6124fbb 100644 (file)
@@ -41,6 +41,7 @@ static int cc_pm_resume(struct device *dev)
        /* wait for Cryptocell reset completion */
        if (!cc_wait_for_reset_completion(drvdata)) {
                dev_err(dev, "Cryptocell reset not completed");
+               clk_disable_unprepare(drvdata->clk);
                return -EBUSY;
        }
 
@@ -48,6 +49,7 @@ static int cc_pm_resume(struct device *dev)
        rc = init_cc_regs(drvdata);
        if (rc) {
                dev_err(dev, "init_cc_regs (%x)\n", rc);
+               clk_disable_unprepare(drvdata->clk);
                return rc;
        }
        /* check if tee fips error occurred during power down */
index 97d54c1..3ba6f15 100644 (file)
@@ -252,7 +252,7 @@ static int hpre_prepare_dma_buf(struct hpre_asym_request *hpre_req,
        if (unlikely(shift < 0))
                return -EINVAL;
 
-       ptr = dma_alloc_coherent(dev, ctx->key_sz, tmp, GFP_KERNEL);
+       ptr = dma_alloc_coherent(dev, ctx->key_sz, tmp, GFP_ATOMIC);
        if (unlikely(!ptr))
                return -ENOMEM;
 
index b4ca2eb..ad83c19 100644 (file)
@@ -877,13 +877,6 @@ static void qm_pm_put_sync(struct hisi_qm *qm)
        pm_runtime_put_autosuspend(dev);
 }
 
-static struct hisi_qp *qm_to_hisi_qp(struct hisi_qm *qm, struct qm_eqe *eqe)
-{
-       u16 cqn = le32_to_cpu(eqe->dw0) & QM_EQE_CQN_MASK;
-
-       return &qm->qp_array[cqn];
-}
-
 static void qm_cq_head_update(struct hisi_qp *qp)
 {
        if (qp->qp_status.cq_head == QM_Q_DEPTH - 1) {
@@ -894,47 +887,37 @@ static void qm_cq_head_update(struct hisi_qp *qp)
        }
 }
 
-static void qm_poll_qp(struct hisi_qp *qp, struct hisi_qm *qm)
+static void qm_poll_req_cb(struct hisi_qp *qp)
 {
-       if (unlikely(atomic_read(&qp->qp_status.flags) == QP_STOP))
-               return;
-
-       if (qp->event_cb) {
-               qp->event_cb(qp);
-               return;
-       }
-
-       if (qp->req_cb) {
-               struct qm_cqe *cqe = qp->cqe + qp->qp_status.cq_head;
-
-               while (QM_CQE_PHASE(cqe) == qp->qp_status.cqc_phase) {
-                       dma_rmb();
-                       qp->req_cb(qp, qp->sqe + qm->sqe_size *
-                                  le16_to_cpu(cqe->sq_head));
-                       qm_cq_head_update(qp);
-                       cqe = qp->cqe + qp->qp_status.cq_head;
-                       qm_db(qm, qp->qp_id, QM_DOORBELL_CMD_CQ,
-                             qp->qp_status.cq_head, 0);
-                       atomic_dec(&qp->qp_status.used);
-               }
+       struct qm_cqe *cqe = qp->cqe + qp->qp_status.cq_head;
+       struct hisi_qm *qm = qp->qm;
 
-               /* set c_flag */
+       while (QM_CQE_PHASE(cqe) == qp->qp_status.cqc_phase) {
+               dma_rmb();
+               qp->req_cb(qp, qp->sqe + qm->sqe_size *
+                          le16_to_cpu(cqe->sq_head));
+               qm_cq_head_update(qp);
+               cqe = qp->cqe + qp->qp_status.cq_head;
                qm_db(qm, qp->qp_id, QM_DOORBELL_CMD_CQ,
-                     qp->qp_status.cq_head, 1);
+                     qp->qp_status.cq_head, 0);
+               atomic_dec(&qp->qp_status.used);
        }
+
+       /* set c_flag */
+       qm_db(qm, qp->qp_id, QM_DOORBELL_CMD_CQ, qp->qp_status.cq_head, 1);
 }
 
-static void qm_work_process(struct work_struct *work)
+static int qm_get_complete_eqe_num(struct hisi_qm_poll_data *poll_data)
 {
-       struct hisi_qm *qm = container_of(work, struct hisi_qm, work);
+       struct hisi_qm *qm = poll_data->qm;
        struct qm_eqe *eqe = qm->eqe + qm->status.eq_head;
-       struct hisi_qp *qp;
        int eqe_num = 0;
+       u16 cqn;
 
        while (QM_EQE_PHASE(eqe) == qm->status.eqc_phase) {
+               cqn = le32_to_cpu(eqe->dw0) & QM_EQE_CQN_MASK;
+               poll_data->qp_finish_id[eqe_num] = cqn;
                eqe_num++;
-               qp = qm_to_hisi_qp(qm, eqe);
-               qm_poll_qp(qp, qm);
 
                if (qm->status.eq_head == QM_EQ_DEPTH - 1) {
                        qm->status.eqc_phase = !qm->status.eqc_phase;
@@ -945,37 +928,70 @@ static void qm_work_process(struct work_struct *work)
                        qm->status.eq_head++;
                }
 
-               if (eqe_num == QM_EQ_DEPTH / 2 - 1) {
-                       eqe_num = 0;
-                       qm_db(qm, 0, QM_DOORBELL_CMD_EQ, qm->status.eq_head, 0);
-               }
+               if (eqe_num == (QM_EQ_DEPTH >> 1) - 1)
+                       break;
        }
 
        qm_db(qm, 0, QM_DOORBELL_CMD_EQ, qm->status.eq_head, 0);
+
+       return eqe_num;
 }
 
-static irqreturn_t do_qm_irq(int irq, void *data)
+static void qm_work_process(struct work_struct *work)
 {
-       struct hisi_qm *qm = (struct hisi_qm *)data;
+       struct hisi_qm_poll_data *poll_data =
+               container_of(work, struct hisi_qm_poll_data, work);
+       struct hisi_qm *qm = poll_data->qm;
+       struct hisi_qp *qp;
+       int eqe_num, i;
 
-       /* the workqueue created by device driver of QM */
-       if (qm->wq)
-               queue_work(qm->wq, &qm->work);
-       else
-               schedule_work(&qm->work);
+       /* Get qp id of completed tasks and re-enable the interrupt. */
+       eqe_num = qm_get_complete_eqe_num(poll_data);
+       for (i = eqe_num - 1; i >= 0; i--) {
+               qp = &qm->qp_array[poll_data->qp_finish_id[i]];
+               if (unlikely(atomic_read(&qp->qp_status.flags) == QP_STOP))
+                       continue;
 
-       return IRQ_HANDLED;
+               if (qp->event_cb) {
+                       qp->event_cb(qp);
+                       continue;
+               }
+
+               if (likely(qp->req_cb))
+                       qm_poll_req_cb(qp);
+       }
+}
+
+static bool do_qm_irq(struct hisi_qm *qm)
+{
+       struct qm_eqe *eqe = qm->eqe + qm->status.eq_head;
+       struct hisi_qm_poll_data *poll_data;
+       u16 cqn;
+
+       if (!readl(qm->io_base + QM_VF_EQ_INT_SOURCE))
+               return false;
+
+       if (QM_EQE_PHASE(eqe) == qm->status.eqc_phase) {
+               cqn = le32_to_cpu(eqe->dw0) & QM_EQE_CQN_MASK;
+               poll_data = &qm->poll_data[cqn];
+               queue_work(qm->wq, &poll_data->work);
+
+               return true;
+       }
+
+       return false;
 }
 
 static irqreturn_t qm_irq(int irq, void *data)
 {
        struct hisi_qm *qm = data;
+       bool ret;
 
-       if (readl(qm->io_base + QM_VF_EQ_INT_SOURCE))
-               return do_qm_irq(irq, data);
+       ret = do_qm_irq(qm);
+       if (ret)
+               return IRQ_HANDLED;
 
        atomic64_inc(&qm->debug.dfx.err_irq_cnt);
-       dev_err(&qm->pdev->dev, "invalid int source\n");
        qm_db(qm, 0, QM_DOORBELL_CMD_EQ, qm->status.eq_head, 0);
 
        return IRQ_NONE;
@@ -3134,11 +3150,8 @@ static int qm_stop_qp_nolock(struct hisi_qp *qp)
        if (ret)
                dev_err(dev, "Failed to drain out data for stopping!\n");
 
-       if (qp->qm->wq)
-               flush_workqueue(qp->qm->wq);
-       else
-               flush_work(&qp->qm->work);
 
+       flush_workqueue(qp->qm->wq);
        if (unlikely(qp->is_resetting && atomic_read(&qp->qp_status.used)))
                qp_stop_fail_cb(qp);
 
@@ -3557,8 +3570,10 @@ static void hisi_qp_memory_uninit(struct hisi_qm *qm, int num)
        for (i = num - 1; i >= 0; i--) {
                qdma = &qm->qp_array[i].qdma;
                dma_free_coherent(dev, qdma->size, qdma->va, qdma->dma);
+               kfree(qm->poll_data[i].qp_finish_id);
        }
 
+       kfree(qm->poll_data);
        kfree(qm->qp_array);
 }
 
@@ -3567,12 +3582,18 @@ static int hisi_qp_memory_init(struct hisi_qm *qm, size_t dma_size, int id)
        struct device *dev = &qm->pdev->dev;
        size_t off = qm->sqe_size * QM_Q_DEPTH;
        struct hisi_qp *qp;
+       int ret = -ENOMEM;
+
+       qm->poll_data[id].qp_finish_id = kcalloc(qm->qp_num, sizeof(u16),
+                                                GFP_KERNEL);
+       if (!qm->poll_data[id].qp_finish_id)
+               return -ENOMEM;
 
        qp = &qm->qp_array[id];
        qp->qdma.va = dma_alloc_coherent(dev, dma_size, &qp->qdma.dma,
                                         GFP_KERNEL);
        if (!qp->qdma.va)
-               return -ENOMEM;
+               goto err_free_qp_finish_id;
 
        qp->sqe = qp->qdma.va;
        qp->sqe_dma = qp->qdma.dma;
@@ -3583,6 +3604,10 @@ static int hisi_qp_memory_init(struct hisi_qm *qm, size_t dma_size, int id)
        qp->qp_id = id;
 
        return 0;
+
+err_free_qp_finish_id:
+       kfree(qm->poll_data[id].qp_finish_id);
+       return ret;
 }
 
 static void hisi_qm_pre_init(struct hisi_qm *qm)
@@ -3672,6 +3697,26 @@ static void qm_last_regs_uninit(struct hisi_qm *qm)
        debug->qm_last_words = NULL;
 }
 
+static void hisi_qm_unint_work(struct hisi_qm *qm)
+{
+       destroy_workqueue(qm->wq);
+}
+
+static void hisi_qm_memory_uninit(struct hisi_qm *qm)
+{
+       struct device *dev = &qm->pdev->dev;
+
+       hisi_qp_memory_uninit(qm, qm->qp_num);
+       if (qm->qdma.va) {
+               hisi_qm_cache_wb(qm);
+               dma_free_coherent(dev, qm->qdma.size,
+                                 qm->qdma.va, qm->qdma.dma);
+       }
+
+       idr_destroy(&qm->qp_idr);
+       kfree(qm->factor);
+}
+
 /**
  * hisi_qm_uninit() - Uninitialize qm.
  * @qm: The qm needed uninit.
@@ -3680,13 +3725,10 @@ static void qm_last_regs_uninit(struct hisi_qm *qm)
  */
 void hisi_qm_uninit(struct hisi_qm *qm)
 {
-       struct pci_dev *pdev = qm->pdev;
-       struct device *dev = &pdev->dev;
-
        qm_last_regs_uninit(qm);
 
        qm_cmd_uninit(qm);
-       kfree(qm->factor);
+       hisi_qm_unint_work(qm);
        down_write(&qm->qps_lock);
 
        if (!qm_avail_state(qm, QM_CLOSE)) {
@@ -3694,14 +3736,7 @@ void hisi_qm_uninit(struct hisi_qm *qm)
                return;
        }
 
-       hisi_qp_memory_uninit(qm, qm->qp_num);
-       idr_destroy(&qm->qp_idr);
-
-       if (qm->qdma.va) {
-               hisi_qm_cache_wb(qm);
-               dma_free_coherent(dev, qm->qdma.size,
-                                 qm->qdma.va, qm->qdma.dma);
-       }
+       hisi_qm_memory_uninit(qm);
        hisi_qm_set_state(qm, QM_NOT_READY);
        up_write(&qm->qps_lock);
 
@@ -6018,14 +6053,28 @@ err_disable_pcidev:
        return ret;
 }
 
-static void hisi_qm_init_work(struct hisi_qm *qm)
+static int hisi_qm_init_work(struct hisi_qm *qm)
 {
-       INIT_WORK(&qm->work, qm_work_process);
+       int i;
+
+       for (i = 0; i < qm->qp_num; i++)
+               INIT_WORK(&qm->poll_data[i].work, qm_work_process);
+
        if (qm->fun_type == QM_HW_PF)
                INIT_WORK(&qm->rst_work, hisi_qm_controller_reset);
 
        if (qm->ver > QM_HW_V2)
                INIT_WORK(&qm->cmd_process, qm_cmd_process);
+
+       qm->wq = alloc_workqueue("%s", WQ_HIGHPRI | WQ_MEM_RECLAIM |
+                                WQ_UNBOUND, num_online_cpus(),
+                                pci_name(qm->pdev));
+       if (!qm->wq) {
+               pci_err(qm->pdev, "failed to alloc workqueue!\n");
+               return -ENOMEM;
+       }
+
+       return 0;
 }
 
 static int hisi_qp_alloc_memory(struct hisi_qm *qm)
@@ -6038,11 +6087,18 @@ static int hisi_qp_alloc_memory(struct hisi_qm *qm)
        if (!qm->qp_array)
                return -ENOMEM;
 
+       qm->poll_data = kcalloc(qm->qp_num, sizeof(struct hisi_qm_poll_data), GFP_KERNEL);
+       if (!qm->poll_data) {
+               kfree(qm->qp_array);
+               return -ENOMEM;
+       }
+
        /* one more page for device or qp statuses */
        qp_dma_size = qm->sqe_size * QM_Q_DEPTH +
                      sizeof(struct qm_cqe) * QM_Q_DEPTH;
        qp_dma_size = PAGE_ALIGN(qp_dma_size) + PAGE_SIZE;
        for (i = 0; i < qm->qp_num; i++) {
+               qm->poll_data[i].qm = qm;
                ret = hisi_qp_memory_init(qm, qp_dma_size, i);
                if (ret)
                        goto err_init_qp_mem;
@@ -6176,7 +6232,10 @@ int hisi_qm_init(struct hisi_qm *qm)
        if (ret)
                goto err_alloc_uacce;
 
-       hisi_qm_init_work(qm);
+       ret = hisi_qm_init_work(qm);
+       if (ret)
+               goto err_free_qm_memory;
+
        qm_cmd_init(qm);
        atomic_set(&qm->status.flags, QM_INIT);
 
@@ -6184,6 +6243,8 @@ int hisi_qm_init(struct hisi_qm *qm)
 
        return 0;
 
+err_free_qm_memory:
+       hisi_qm_memory_uninit(qm);
 err_alloc_uacce:
        if (qm->use_sva) {
                uacce_remove(qm->uacce);
index 0a3c8f0..490e154 100644 (file)
@@ -449,7 +449,7 @@ static void sec_skcipher_alg_callback(struct sec_bd_info *sec_resp,
                 */
        }
 
-       mutex_lock(&ctx->queue->queuelock);
+       spin_lock_bh(&ctx->queue->queuelock);
        /* Put the IV in place for chained cases */
        switch (ctx->cipher_alg) {
        case SEC_C_AES_CBC_128:
@@ -509,7 +509,7 @@ static void sec_skcipher_alg_callback(struct sec_bd_info *sec_resp,
                        list_del(&backlog_req->backlog_head);
                }
        }
-       mutex_unlock(&ctx->queue->queuelock);
+       spin_unlock_bh(&ctx->queue->queuelock);
 
        mutex_lock(&sec_req->lock);
        list_del(&sec_req_el->head);
@@ -798,7 +798,7 @@ static int sec_alg_skcipher_crypto(struct skcipher_request *skreq,
         */
 
        /* Grab a big lock for a long time to avoid concurrency issues */
-       mutex_lock(&queue->queuelock);
+       spin_lock_bh(&queue->queuelock);
 
        /*
         * Can go on to queue if we have space in either:
@@ -814,15 +814,15 @@ static int sec_alg_skcipher_crypto(struct skcipher_request *skreq,
                ret = -EBUSY;
                if ((skreq->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
                        list_add_tail(&sec_req->backlog_head, &ctx->backlog);
-                       mutex_unlock(&queue->queuelock);
+                       spin_unlock_bh(&queue->queuelock);
                        goto out;
                }
 
-               mutex_unlock(&queue->queuelock);
+               spin_unlock_bh(&queue->queuelock);
                goto err_free_elements;
        }
        ret = sec_send_request(sec_req, queue);
-       mutex_unlock(&queue->queuelock);
+       spin_unlock_bh(&queue->queuelock);
        if (ret)
                goto err_free_elements;
 
@@ -881,7 +881,7 @@ static int sec_alg_skcipher_init(struct crypto_skcipher *tfm)
        if (IS_ERR(ctx->queue))
                return PTR_ERR(ctx->queue);
 
-       mutex_init(&ctx->queue->queuelock);
+       spin_lock_init(&ctx->queue->queuelock);
        ctx->queue->havesoftqueue = false;
 
        return 0;
index c8de1b5..e758513 100644 (file)
@@ -892,7 +892,7 @@ bool sec_queue_can_enqueue(struct sec_queue *queue, int num)
 static void sec_queue_hw_init(struct sec_queue *queue)
 {
        sec_queue_ar_alloc(queue, SEC_QUEUE_AR_FROCE_NOALLOC);
-       sec_queue_aw_alloc(queue, SEC_QUEUE_AR_FROCE_NOALLOC);
+       sec_queue_aw_alloc(queue, SEC_QUEUE_AW_FROCE_NOALLOC);
        sec_queue_ar_pkgattr(queue, 1);
        sec_queue_aw_pkgattr(queue, 1);
 
index 179a825..e2a50bf 100644 (file)
@@ -347,7 +347,7 @@ struct sec_queue {
        DECLARE_BITMAP(unprocessed, SEC_QUEUE_LEN);
        DECLARE_KFIFO_PTR(softqueue, typeof(struct sec_request_el *));
        bool havesoftqueue;
-       struct mutex queuelock;
+       spinlock_t queuelock;
        void *shadow[SEC_QUEUE_LEN];
 };
 
index c2e9b01..d2a0bc9 100644 (file)
@@ -119,7 +119,7 @@ struct sec_qp_ctx {
        struct idr req_idr;
        struct sec_alg_res res[QM_Q_DEPTH];
        struct sec_ctx *ctx;
-       struct mutex req_lock;
+       spinlock_t req_lock;
        struct list_head backlog;
        struct hisi_acc_sgl_pool *c_in_pool;
        struct hisi_acc_sgl_pool *c_out_pool;
@@ -143,10 +143,10 @@ struct sec_ctx {
        /* Threshold for fake busy, trigger to return -EBUSY to user */
        u32 fake_req_limit;
 
-       /* Currrent cyclic index to select a queue for encipher */
+       /* Current cyclic index to select a queue for encipher */
        atomic_t enc_qcyclic;
 
-        /* Currrent cyclic index to select a queue for decipher */
+        /* Current cyclic index to select a queue for decipher */
        atomic_t dec_qcyclic;
 
        enum sec_alg_type alg_type;
index 6eebe73..77c9f13 100644 (file)
@@ -127,11 +127,11 @@ static int sec_alloc_req_id(struct sec_req *req, struct sec_qp_ctx *qp_ctx)
 {
        int req_id;
 
-       mutex_lock(&qp_ctx->req_lock);
+       spin_lock_bh(&qp_ctx->req_lock);
 
        req_id = idr_alloc_cyclic(&qp_ctx->req_idr, NULL,
                                  0, QM_Q_DEPTH, GFP_ATOMIC);
-       mutex_unlock(&qp_ctx->req_lock);
+       spin_unlock_bh(&qp_ctx->req_lock);
        if (unlikely(req_id < 0)) {
                dev_err(req->ctx->dev, "alloc req id fail!\n");
                return req_id;
@@ -156,9 +156,9 @@ static void sec_free_req_id(struct sec_req *req)
        qp_ctx->req_list[req_id] = NULL;
        req->qp_ctx = NULL;
 
-       mutex_lock(&qp_ctx->req_lock);
+       spin_lock_bh(&qp_ctx->req_lock);
        idr_remove(&qp_ctx->req_idr, req_id);
-       mutex_unlock(&qp_ctx->req_lock);
+       spin_unlock_bh(&qp_ctx->req_lock);
 }
 
 static u8 pre_parse_finished_bd(struct bd_status *status, void *resp)
@@ -273,7 +273,7 @@ static int sec_bd_send(struct sec_ctx *ctx, struct sec_req *req)
            !(req->flag & CRYPTO_TFM_REQ_MAY_BACKLOG))
                return -EBUSY;
 
-       mutex_lock(&qp_ctx->req_lock);
+       spin_lock_bh(&qp_ctx->req_lock);
        ret = hisi_qp_send(qp_ctx->qp, &req->sec_sqe);
 
        if (ctx->fake_req_limit <=
@@ -281,10 +281,10 @@ static int sec_bd_send(struct sec_ctx *ctx, struct sec_req *req)
                list_add_tail(&req->backlog_head, &qp_ctx->backlog);
                atomic64_inc(&ctx->sec->debug.dfx.send_cnt);
                atomic64_inc(&ctx->sec->debug.dfx.send_busy_cnt);
-               mutex_unlock(&qp_ctx->req_lock);
+               spin_unlock_bh(&qp_ctx->req_lock);
                return -EBUSY;
        }
-       mutex_unlock(&qp_ctx->req_lock);
+       spin_unlock_bh(&qp_ctx->req_lock);
 
        if (unlikely(ret == -EBUSY))
                return -ENOBUFS;
@@ -487,7 +487,7 @@ static int sec_create_qp_ctx(struct hisi_qm *qm, struct sec_ctx *ctx,
 
        qp->req_cb = sec_req_cb;
 
-       mutex_init(&qp_ctx->req_lock);
+       spin_lock_init(&qp_ctx->req_lock);
        idr_init(&qp_ctx->req_idr);
        INIT_LIST_HEAD(&qp_ctx->backlog);
 
@@ -620,7 +620,7 @@ static int sec_auth_init(struct sec_ctx *ctx)
 {
        struct sec_auth_ctx *a_ctx = &ctx->a_ctx;
 
-       a_ctx->a_key = dma_alloc_coherent(ctx->dev, SEC_MAX_KEY_SIZE,
+       a_ctx->a_key = dma_alloc_coherent(ctx->dev, SEC_MAX_AKEY_SIZE,
                                          &a_ctx->a_key_dma, GFP_KERNEL);
        if (!a_ctx->a_key)
                return -ENOMEM;
@@ -632,8 +632,8 @@ static void sec_auth_uninit(struct sec_ctx *ctx)
 {
        struct sec_auth_ctx *a_ctx = &ctx->a_ctx;
 
-       memzero_explicit(a_ctx->a_key, SEC_MAX_KEY_SIZE);
-       dma_free_coherent(ctx->dev, SEC_MAX_KEY_SIZE,
+       memzero_explicit(a_ctx->a_key, SEC_MAX_AKEY_SIZE);
+       dma_free_coherent(ctx->dev, SEC_MAX_AKEY_SIZE,
                          a_ctx->a_key, a_ctx->a_key_dma);
 }
 
@@ -1382,7 +1382,7 @@ static struct sec_req *sec_back_req_clear(struct sec_ctx *ctx,
 {
        struct sec_req *backlog_req = NULL;
 
-       mutex_lock(&qp_ctx->req_lock);
+       spin_lock_bh(&qp_ctx->req_lock);
        if (ctx->fake_req_limit >=
            atomic_read(&qp_ctx->qp->qp_status.used) &&
            !list_empty(&qp_ctx->backlog)) {
@@ -1390,7 +1390,7 @@ static struct sec_req *sec_back_req_clear(struct sec_ctx *ctx,
                                typeof(*backlog_req), backlog_head);
                list_del(&backlog_req->backlog_head);
        }
-       mutex_unlock(&qp_ctx->req_lock);
+       spin_unlock_bh(&qp_ctx->req_lock);
 
        return backlog_req;
 }
index 5e039b5..d033f63 100644 (file)
@@ -7,6 +7,7 @@
 #define SEC_AIV_SIZE           12
 #define SEC_IV_SIZE            24
 #define SEC_MAX_KEY_SIZE       64
+#define SEC_MAX_AKEY_SIZE      128
 #define SEC_COMM_SCENE         0
 #define SEC_MIN_BLOCK_SZ       1
 
index 4d85d2c..2c0be91 100644 (file)
@@ -508,16 +508,17 @@ static int sec_engine_init(struct hisi_qm *qm)
 
        writel(SEC_SAA_ENABLE, qm->io_base + SEC_SAA_EN_REG);
 
-       /* HW V2 enable sm4 extra mode, as ctr/ecb */
-       if (qm->ver < QM_HW_V3)
+       if (qm->ver < QM_HW_V3) {
+               /* HW V2 enable sm4 extra mode, as ctr/ecb */
                writel_relaxed(SEC_BD_ERR_CHK_EN0,
                               qm->io_base + SEC_BD_ERR_CHK_EN_REG0);
 
-       /* Enable sm4 xts mode multiple iv */
-       writel_relaxed(SEC_BD_ERR_CHK_EN1,
-                      qm->io_base + SEC_BD_ERR_CHK_EN_REG1);
-       writel_relaxed(SEC_BD_ERR_CHK_EN3,
-                      qm->io_base + SEC_BD_ERR_CHK_EN_REG3);
+               /* HW V2 enable sm4 xts mode multiple iv */
+               writel_relaxed(SEC_BD_ERR_CHK_EN1,
+                              qm->io_base + SEC_BD_ERR_CHK_EN_REG1);
+               writel_relaxed(SEC_BD_ERR_CHK_EN3,
+                              qm->io_base + SEC_BD_ERR_CHK_EN_REG3);
+       }
 
        /* config endian */
        sec_set_endian(qm);
@@ -1002,8 +1003,6 @@ static int sec_pf_probe_init(struct sec_dev *sec)
 
 static int sec_qm_init(struct hisi_qm *qm, struct pci_dev *pdev)
 {
-       int ret;
-
        qm->pdev = pdev;
        qm->ver = pdev->revision;
        qm->algs = "cipher\ndigest\naead";
@@ -1029,25 +1028,7 @@ static int sec_qm_init(struct hisi_qm *qm, struct pci_dev *pdev)
                qm->qp_num = SEC_QUEUE_NUM_V1 - SEC_PF_DEF_Q_NUM;
        }
 
-       /*
-        * WQ_HIGHPRI: SEC request must be low delayed,
-        * so need a high priority workqueue.
-        * WQ_UNBOUND: SEC task is likely with long
-        * running CPU intensive workloads.
-        */
-       qm->wq = alloc_workqueue("%s", WQ_HIGHPRI | WQ_MEM_RECLAIM |
-                                WQ_UNBOUND, num_online_cpus(),
-                                pci_name(qm->pdev));
-       if (!qm->wq) {
-               pci_err(qm->pdev, "fail to alloc workqueue\n");
-               return -ENOMEM;
-       }
-
-       ret = hisi_qm_init(qm);
-       if (ret)
-               destroy_workqueue(qm->wq);
-
-       return ret;
+       return hisi_qm_init(qm);
 }
 
 static void sec_qm_uninit(struct hisi_qm *qm)
@@ -1078,8 +1059,6 @@ static int sec_probe_init(struct sec_dev *sec)
 static void sec_probe_uninit(struct hisi_qm *qm)
 {
        hisi_qm_dev_err_uninit(qm);
-
-       destroy_workqueue(qm->wq);
 }
 
 static void sec_iommu_used_check(struct sec_dev *sec)
index 829f2ca..97e500d 100644 (file)
@@ -185,7 +185,7 @@ static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
        struct hisi_trng *trng;
        int currsize = 0;
        u32 val = 0;
-       u32 ret;
+       int ret;
 
        trng = container_of(rng, struct hisi_trng, rng);
 
index 6786951..ad35434 100644 (file)
@@ -2,6 +2,7 @@
 /* Copyright (c) 2019 HiSilicon Limited. */
 #include <crypto/internal/acompress.h>
 #include <linux/bitfield.h>
+#include <linux/bitmap.h>
 #include <linux/dma-mapping.h>
 #include <linux/scatterlist.h>
 #include "zip.h"
@@ -606,8 +607,7 @@ static int hisi_zip_create_req_q(struct hisi_zip_ctx *ctx)
                req_q = &ctx->qp_ctx[i].req_q;
                req_q->size = QM_Q_DEPTH;
 
-               req_q->req_bitmap = kcalloc(BITS_TO_LONGS(req_q->size),
-                                           sizeof(long), GFP_KERNEL);
+               req_q->req_bitmap = bitmap_zalloc(req_q->size, GFP_KERNEL);
                if (!req_q->req_bitmap) {
                        ret = -ENOMEM;
                        if (i == 0)
@@ -631,11 +631,11 @@ static int hisi_zip_create_req_q(struct hisi_zip_ctx *ctx)
        return 0;
 
 err_free_loop1:
-       kfree(ctx->qp_ctx[HZIP_QPC_DECOMP].req_q.req_bitmap);
+       bitmap_free(ctx->qp_ctx[HZIP_QPC_DECOMP].req_q.req_bitmap);
 err_free_loop0:
        kfree(ctx->qp_ctx[HZIP_QPC_COMP].req_q.q);
 err_free_bitmap:
-       kfree(ctx->qp_ctx[HZIP_QPC_COMP].req_q.req_bitmap);
+       bitmap_free(ctx->qp_ctx[HZIP_QPC_COMP].req_q.req_bitmap);
        return ret;
 }
 
@@ -645,7 +645,7 @@ static void hisi_zip_release_req_q(struct hisi_zip_ctx *ctx)
 
        for (i = 0; i < HZIP_CTX_Q_NUM; i++) {
                kfree(ctx->qp_ctx[i].req_q.q);
-               kfree(ctx->qp_ctx[i].req_q.req_bitmap);
+               bitmap_free(ctx->qp_ctx[i].req_q.req_bitmap);
        }
 }
 
index 9c925e9..c3303d9 100644 (file)
@@ -990,8 +990,6 @@ static int hisi_zip_pf_probe_init(struct hisi_zip *hisi_zip)
 
 static int hisi_zip_qm_init(struct hisi_qm *qm, struct pci_dev *pdev)
 {
-       int ret;
-
        qm->pdev = pdev;
        qm->ver = pdev->revision;
        if (pdev->revision >= QM_HW_V3)
@@ -1021,25 +1019,12 @@ static int hisi_zip_qm_init(struct hisi_qm *qm, struct pci_dev *pdev)
                qm->qp_num = HZIP_QUEUE_NUM_V1 - HZIP_PF_DEF_Q_NUM;
        }
 
-       qm->wq = alloc_workqueue("%s", WQ_HIGHPRI | WQ_MEM_RECLAIM |
-                                WQ_UNBOUND, num_online_cpus(),
-                                pci_name(qm->pdev));
-       if (!qm->wq) {
-               pci_err(qm->pdev, "fail to alloc workqueue\n");
-               return -ENOMEM;
-       }
-
-       ret = hisi_qm_init(qm);
-       if (ret)
-               destroy_workqueue(qm->wq);
-
-       return ret;
+       return hisi_qm_init(qm);
 }
 
 static void hisi_zip_qm_uninit(struct hisi_qm *qm)
 {
        hisi_qm_uninit(qm);
-       destroy_workqueue(qm->wq);
 }
 
 static int hisi_zip_probe_init(struct hisi_zip *hisi_zip)
index 9b1a158..ad0d8c4 100644 (file)
@@ -1831,6 +1831,8 @@ static const struct of_device_id safexcel_of_match_table[] = {
        {},
 };
 
+MODULE_DEVICE_TABLE(of, safexcel_of_match_table);
+
 static struct platform_driver  crypto_safexcel = {
        .probe          = safexcel_probe,
        .remove         = safexcel_remove,
index ce1e611..797ff91 100644 (file)
@@ -497,15 +497,15 @@ struct result_data_desc {
        u32 packet_length:17;
        u32 error_code:15;
 
-       u8 bypass_length:4;
-       u8 e15:1;
-       u16 rsvd0;
-       u8 hash_bytes:1;
-       u8 hash_length:6;
-       u8 generic_bytes:1;
-       u8 checksum:1;
-       u8 next_header:1;
-       u8 length:1;
+       u32 bypass_length:4;
+       u32 e15:1;
+       u32 rsvd0:16;
+       u32 hash_bytes:1;
+       u32 hash_length:6;
+       u32 generic_bytes:1;
+       u32 checksum:1;
+       u32 next_header:1;
+       u32 length:1;
 
        u16 application_id;
        u16 rsvd1;
index 5d0785d..2269df1 100644 (file)
@@ -976,8 +976,6 @@ static int kmb_ocs_ecc_remove(struct platform_device *pdev)
        struct ocs_ecc_dev *ecc_dev;
 
        ecc_dev = platform_get_drvdata(pdev);
-       if (!ecc_dev)
-               return -ENODEV;
 
        crypto_unregister_kpp(&ocs_ecdh_p384);
        crypto_unregister_kpp(&ocs_ecdh_p256);
index bb02e0d..7503f6b 100644 (file)
@@ -51,11 +51,47 @@ static const struct devlink_param otx2_cpt_dl_params[] = {
                             NULL),
 };
 
-static int otx2_cpt_devlink_info_get(struct devlink *devlink,
+static int otx2_cpt_dl_info_firmware_version_put(struct devlink_info_req *req,
+                                                struct otx2_cpt_eng_grp_info grp[],
+                                                const char *ver_name, int eng_type)
+{
+       struct otx2_cpt_engs_rsvd *eng;
+       int i;
+
+       for (i = 0; i < OTX2_CPT_MAX_ENGINE_GROUPS; i++) {
+               eng = find_engines_by_type(&grp[i], eng_type);
+               if (eng)
+                       return devlink_info_version_running_put(req, ver_name,
+                                                               eng->ucode->ver_str);
+       }
+
+       return 0;
+}
+
+static int otx2_cpt_devlink_info_get(struct devlink *dl,
                                     struct devlink_info_req *req,
                                     struct netlink_ext_ack *extack)
 {
-       return devlink_info_driver_name_put(req, "rvu_cptpf");
+       struct otx2_cpt_devlink *cpt_dl = devlink_priv(dl);
+       struct otx2_cptpf_dev *cptpf = cpt_dl->cptpf;
+       int err;
+
+       err = devlink_info_driver_name_put(req, "rvu_cptpf");
+       if (err)
+               return err;
+
+       err = otx2_cpt_dl_info_firmware_version_put(req, cptpf->eng_grps.grp,
+                                                   "fw.ae", OTX2_CPT_AE_TYPES);
+       if (err)
+               return err;
+
+       err = otx2_cpt_dl_info_firmware_version_put(req, cptpf->eng_grps.grp,
+                                                   "fw.se", OTX2_CPT_SE_TYPES);
+       if (err)
+               return err;
+
+       return otx2_cpt_dl_info_firmware_version_put(req, cptpf->eng_grps.grp,
+                                                   "fw.ie", OTX2_CPT_IE_TYPES);
 }
 
 static const struct devlink_ops otx2_cpt_devlink_ops = {
index 9cba2f7..f10050f 100644 (file)
@@ -476,7 +476,7 @@ release_fw:
        return ret;
 }
 
-static struct otx2_cpt_engs_rsvd *find_engines_by_type(
+struct otx2_cpt_engs_rsvd *find_engines_by_type(
                                        struct otx2_cpt_eng_grp_info *eng_grp,
                                        int eng_type)
 {
@@ -1605,7 +1605,10 @@ int otx2_cpt_dl_custom_egrp_create(struct otx2_cptpf_dev *cptpf,
                if (!strncasecmp(val, "se", 2) && strchr(val, ':')) {
                        if (has_se || ucode_idx)
                                goto err_print;
-                       tmp = strim(strsep(&val, ":"));
+                       tmp = strsep(&val, ":");
+                       if (!tmp)
+                               goto err_print;
+                       tmp = strim(tmp);
                        if (!val)
                                goto err_print;
                        if (strlen(tmp) != 2)
@@ -1617,7 +1620,10 @@ int otx2_cpt_dl_custom_egrp_create(struct otx2_cptpf_dev *cptpf,
                } else if (!strncasecmp(val, "ae", 2) && strchr(val, ':')) {
                        if (has_ae || ucode_idx)
                                goto err_print;
-                       tmp = strim(strsep(&val, ":"));
+                       tmp = strsep(&val, ":");
+                       if (!tmp)
+                               goto err_print;
+                       tmp = strim(tmp);
                        if (!val)
                                goto err_print;
                        if (strlen(tmp) != 2)
@@ -1629,7 +1635,10 @@ int otx2_cpt_dl_custom_egrp_create(struct otx2_cptpf_dev *cptpf,
                } else if (!strncasecmp(val, "ie", 2) && strchr(val, ':')) {
                        if (has_ie || ucode_idx)
                                goto err_print;
-                       tmp = strim(strsep(&val, ":"));
+                       tmp = strsep(&val, ":");
+                       if (!tmp)
+                               goto err_print;
+                       tmp = strim(tmp);
                        if (!val)
                                goto err_print;
                        if (strlen(tmp) != 2)
index 8f4d4e5..e69320a 100644 (file)
@@ -166,4 +166,7 @@ int otx2_cpt_dl_custom_egrp_create(struct otx2_cptpf_dev *cptpf,
 int otx2_cpt_dl_custom_egrp_delete(struct otx2_cptpf_dev *cptpf,
                                   struct devlink_param_gset_ctx *ctx);
 void otx2_cpt_print_uc_dbg_info(struct otx2_cptpf_dev *cptpf);
+struct otx2_cpt_engs_rsvd *find_engines_by_type(
+                                       struct otx2_cpt_eng_grp_info *eng_grp,
+                                       int eng_type);
 #endif /* __OTX2_CPTPF_UCODE_H */
index f418817..f34c75a 100644 (file)
@@ -75,7 +75,7 @@ static int (*nx842_powernv_exec)(const unsigned char *in,
 /**
  * setup_indirect_dde - Setup an indirect DDE
  *
- * The DDE is setup with the the DDE count, byte count, and address of
+ * The DDE is setup with the DDE count, byte count, and address of
  * first direct DDE in the list.
  */
 static void setup_indirect_dde(struct data_descriptor_entry *dde,
index 7584a34..3ea334b 100644 (file)
@@ -1208,10 +1208,13 @@ static struct vio_driver nx842_vio_driver = {
 static int __init nx842_pseries_init(void)
 {
        struct nx842_devdata *new_devdata;
+       struct device_node *np;
        int ret;
 
-       if (!of_find_compatible_node(NULL, NULL, "ibm,compression"))
+       np = of_find_compatible_node(NULL, NULL, "ibm,compression");
+       if (!np)
                return -ENODEV;
+       of_node_put(np);
 
        RCU_INIT_POINTER(devdata, NULL);
        new_devdata = kzalloc(sizeof(*new_devdata), GFP_KERNEL);
index 581211a..67a99c7 100644 (file)
@@ -1261,9 +1261,6 @@ static int omap_aes_remove(struct platform_device *pdev)
        struct aead_alg *aalg;
        int i, j;
 
-       if (!dd)
-               return -ENODEV;
-
        spin_lock_bh(&list_lock);
        list_del(&dd->list);
        spin_unlock_bh(&list_lock);
@@ -1279,7 +1276,6 @@ static int omap_aes_remove(struct platform_device *pdev)
                aalg = &dd->pdata->aead_algs_info->algs_list[i];
                crypto_unregister_aead(aalg);
                dd->pdata->aead_algs_info->registered--;
-
        }
 
        crypto_engine_exit(dd->engine);
index 538aff8..f783769 100644 (file)
@@ -1091,9 +1091,6 @@ static int omap_des_remove(struct platform_device *pdev)
        struct omap_des_dev *dd = platform_get_drvdata(pdev);
        int i, j;
 
-       if (!dd)
-               return -ENODEV;
-
        spin_lock_bh(&list_lock);
        list_del(&dd->list);
        spin_unlock_bh(&list_lock);
@@ -1106,7 +1103,6 @@ static int omap_des_remove(struct platform_device *pdev)
        tasklet_kill(&dd->done_task);
        omap_des_dma_cleanup(dd);
        pm_runtime_disable(dd->dev);
-       dd = NULL;
 
        return 0;
 }
index 4b37dc6..655a7f5 100644 (file)
@@ -2197,8 +2197,7 @@ static int omap_sham_remove(struct platform_device *pdev)
        int i, j;
 
        dd = platform_get_drvdata(pdev);
-       if (!dd)
-               return -ENODEV;
+
        spin_lock_bh(&sham.lock);
        list_del(&dd->list);
        spin_unlock_bh(&sham.lock);
index 4b90c0f..1220cc8 100644 (file)
@@ -17,7 +17,7 @@ config CRYPTO_DEV_QAT
 
 config CRYPTO_DEV_QAT_DH895xCC
        tristate "Support for Intel(R) DH895xCC"
-       depends on X86 && PCI
+       depends on PCI && (!CPU_BIG_ENDIAN || COMPILE_TEST)
        select CRYPTO_DEV_QAT
        help
          Support for Intel(R) DH895xcc with Intel(R) QuickAssist Technology
@@ -28,7 +28,7 @@ config CRYPTO_DEV_QAT_DH895xCC
 
 config CRYPTO_DEV_QAT_C3XXX
        tristate "Support for Intel(R) C3XXX"
-       depends on X86 && PCI
+       depends on PCI && (!CPU_BIG_ENDIAN || COMPILE_TEST)
        select CRYPTO_DEV_QAT
        help
          Support for Intel(R) C3xxx with Intel(R) QuickAssist Technology
@@ -39,7 +39,7 @@ config CRYPTO_DEV_QAT_C3XXX
 
 config CRYPTO_DEV_QAT_C62X
        tristate "Support for Intel(R) C62X"
-       depends on X86 && PCI
+       depends on PCI && (!CPU_BIG_ENDIAN || COMPILE_TEST)
        select CRYPTO_DEV_QAT
        help
          Support for Intel(R) C62x with Intel(R) QuickAssist Technology
@@ -50,7 +50,7 @@ config CRYPTO_DEV_QAT_C62X
 
 config CRYPTO_DEV_QAT_4XXX
        tristate "Support for Intel(R) QAT_4XXX"
-       depends on X86 && PCI
+       depends on PCI && (!CPU_BIG_ENDIAN || COMPILE_TEST)
        select CRYPTO_DEV_QAT
        help
          Support for Intel(R) QuickAssist Technology QAT_4xxx
@@ -61,7 +61,7 @@ config CRYPTO_DEV_QAT_4XXX
 
 config CRYPTO_DEV_QAT_DH895xCCVF
        tristate "Support for Intel(R) DH895xCC Virtual Function"
-       depends on X86 && PCI
+       depends on PCI && (!CPU_BIG_ENDIAN || COMPILE_TEST)
        select PCI_IOV
        select CRYPTO_DEV_QAT
 
@@ -74,7 +74,7 @@ config CRYPTO_DEV_QAT_DH895xCCVF
 
 config CRYPTO_DEV_QAT_C3XXXVF
        tristate "Support for Intel(R) C3XXX Virtual Function"
-       depends on X86 && PCI
+       depends on PCI && (!CPU_BIG_ENDIAN || COMPILE_TEST)
        select PCI_IOV
        select CRYPTO_DEV_QAT
        help
@@ -86,7 +86,7 @@ config CRYPTO_DEV_QAT_C3XXXVF
 
 config CRYPTO_DEV_QAT_C62XVF
        tristate "Support for Intel(R) C62X Virtual Function"
-       depends on X86 && PCI
+       depends on PCI && (!CPU_BIG_ENDIAN || COMPILE_TEST)
        select PCI_IOV
        select CRYPTO_DEV_QAT
        help
index fb5970a..fda5f69 100644 (file)
@@ -357,6 +357,7 @@ void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data)
        hw_data->ring_pair_reset = adf_gen4_ring_pair_reset;
        hw_data->enable_pm = adf_gen4_enable_pm;
        hw_data->handle_pm_interrupt = adf_gen4_handle_pm_interrupt;
+       hw_data->dev_config = adf_crypto_dev_config;
 
        adf_gen4_init_hw_csr_ops(&hw_data->csr_ops);
        adf_gen4_init_pf_pfvf_ops(&hw_data->pfvf_ops);
index 1034752..9d49248 100644 (file)
@@ -70,5 +70,6 @@ enum icp_qat_4xxx_slice_mask {
 
 void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data);
 void adf_clean_hw_data_4xxx(struct adf_hw_device_data *hw_data);
+int adf_crypto_dev_config(struct adf_accel_dev *accel_dev);
 
 #endif
index 181fa1c..2f21256 100644 (file)
@@ -53,7 +53,7 @@ static int adf_cfg_dev_init(struct adf_accel_dev *accel_dev)
        return 0;
 }
 
-static int adf_crypto_dev_config(struct adf_accel_dev *accel_dev)
+int adf_crypto_dev_config(struct adf_accel_dev *accel_dev)
 {
        char key[ADF_CFG_MAX_KEY_LEN_IN_BYTES];
        int banks = GET_MAX_BANKS(accel_dev);
@@ -289,6 +289,10 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto out_err_disable_aer;
        }
 
+       ret = adf_sysfs_init(accel_dev);
+       if (ret)
+               goto out_err_disable_aer;
+
        ret = adf_crypto_dev_config(accel_dev);
        if (ret)
                goto out_err_disable_aer;
index 04f058a..80919cf 100644 (file)
@@ -10,6 +10,7 @@ intel_qat-objs := adf_cfg.o \
        adf_transport.o \
        adf_admin.o \
        adf_hw_arbiter.o \
+       adf_sysfs.o \
        adf_gen2_hw_data.o \
        adf_gen4_hw_data.o \
        adf_gen4_pm.o \
index ede6458..0a55a4f 100644 (file)
@@ -199,6 +199,7 @@ struct adf_hw_device_data {
        char *(*uof_get_name)(struct adf_accel_dev *accel_dev, u32 obj_num);
        u32 (*uof_get_num_objs)(void);
        u32 (*uof_get_ae_mask)(struct adf_accel_dev *accel_dev, u32 obj_num);
+       int (*dev_config)(struct adf_accel_dev *accel_dev);
        struct adf_pfvf_ops pfvf_ops;
        struct adf_hw_csr_ops csr_ops;
        const char *fw_name;
index b5b208c..e61b3e1 100644 (file)
@@ -128,6 +128,24 @@ static void adf_cfg_keyval_add(struct adf_cfg_key_val *new,
        list_add_tail(&new->list, &sec->param_head);
 }
 
+static void adf_cfg_keyval_remove(const char *key, struct adf_cfg_section *sec)
+{
+       struct list_head *head = &sec->param_head;
+       struct list_head *list_ptr, *tmp;
+
+       list_for_each_prev_safe(list_ptr, tmp, head) {
+               struct adf_cfg_key_val *ptr =
+                       list_entry(list_ptr, struct adf_cfg_key_val, list);
+
+               if (strncmp(ptr->key, key, sizeof(ptr->key)))
+                       continue;
+
+               list_del(list_ptr);
+               kfree(ptr);
+               break;
+       }
+}
+
 static void adf_cfg_keyval_del_all(struct list_head *head)
 {
        struct list_head *list_ptr, *tmp;
@@ -208,7 +226,8 @@ static int adf_cfg_key_val_get(struct adf_accel_dev *accel_dev,
  * @type: Type - string, int or address
  *
  * Function adds configuration key - value entry in the appropriate section
- * in the given acceleration device
+ * in the given acceleration device. If the key exists already, the value
+ * is updated.
  * To be used by QAT device specific drivers.
  *
  * Return: 0 on success, error code otherwise.
@@ -222,6 +241,8 @@ int adf_cfg_add_key_value_param(struct adf_accel_dev *accel_dev,
        struct adf_cfg_key_val *key_val;
        struct adf_cfg_section *section = adf_cfg_sec_find(accel_dev,
                                                           section_name);
+       char temp_val[ADF_CFG_MAX_VAL_LEN_IN_BYTES];
+
        if (!section)
                return -EFAULT;
 
@@ -246,6 +267,24 @@ int adf_cfg_add_key_value_param(struct adf_accel_dev *accel_dev,
                return -EINVAL;
        }
        key_val->type = type;
+
+       /* Add the key-value pair as below policy:
+        * 1. if the key doesn't exist, add it;
+        * 2. if the key already exists with a different value then update it
+        *    to the new value (the key is deleted and the newly created
+        *    key_val containing the new value is added to the database);
+        * 3. if the key exists with the same value, then return without doing
+        *    anything (the newly created key_val is freed).
+        */
+       if (!adf_cfg_key_val_get(accel_dev, section_name, key, temp_val)) {
+               if (strncmp(temp_val, key_val->val, sizeof(temp_val))) {
+                       adf_cfg_keyval_remove(key, section);
+               } else {
+                       kfree(key_val);
+                       return 0;
+               }
+       }
+
        down_write(&cfg->lock);
        adf_cfg_keyval_add(key_val, section);
        up_write(&cfg->lock);
index 0464fa2..7bb477c 100644 (file)
@@ -49,11 +49,6 @@ struct service_hndl {
        struct list_head list;
 };
 
-static inline int get_current_node(void)
-{
-       return topology_physical_package_id(raw_smp_processor_id());
-}
-
 int adf_service_register(struct service_hndl *service);
 int adf_service_unregister(struct service_hndl *service);
 
@@ -61,6 +56,7 @@ int adf_dev_init(struct adf_accel_dev *accel_dev);
 int adf_dev_start(struct adf_accel_dev *accel_dev);
 void adf_dev_stop(struct adf_accel_dev *accel_dev);
 void adf_dev_shutdown(struct adf_accel_dev *accel_dev);
+int adf_dev_shutdown_cache_cfg(struct adf_accel_dev *accel_dev);
 
 void adf_devmgr_update_class_index(struct adf_hw_device_data *hw_data);
 void adf_clean_vf_map(bool);
@@ -132,6 +128,8 @@ void adf_vf_isr_resource_free(struct adf_accel_dev *accel_dev);
 
 int adf_pfvf_comms_disabled(struct adf_accel_dev *accel_dev);
 
+int adf_sysfs_init(struct adf_accel_dev *accel_dev);
+
 int qat_hal_init(struct adf_accel_dev *accel_dev);
 void qat_hal_deinit(struct icp_qat_fw_loader_handle *handle);
 int qat_hal_start(struct icp_qat_fw_loader_handle *handle);
index c2c718f..33a9a46 100644 (file)
@@ -363,3 +363,29 @@ int adf_dev_restarted_notify(struct adf_accel_dev *accel_dev)
        }
        return 0;
 }
+
+int adf_dev_shutdown_cache_cfg(struct adf_accel_dev *accel_dev)
+{
+       char services[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = {0};
+       int ret;
+
+       ret = adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC,
+                                     ADF_SERVICES_ENABLED, services);
+
+       adf_dev_stop(accel_dev);
+       adf_dev_shutdown(accel_dev);
+
+       if (!ret) {
+               ret = adf_cfg_section_add(accel_dev, ADF_GENERAL_SEC);
+               if (ret)
+                       return ret;
+
+               ret = adf_cfg_add_key_value_param(accel_dev, ADF_GENERAL_SEC,
+                                                 ADF_SERVICES_ENABLED,
+                                                 services, ADF_STR);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
index f38b2ff..b2db1d7 100644 (file)
@@ -120,32 +120,6 @@ void adf_disable_sriov(struct adf_accel_dev *accel_dev)
 }
 EXPORT_SYMBOL_GPL(adf_disable_sriov);
 
-static int adf_sriov_prepare_restart(struct adf_accel_dev *accel_dev)
-{
-       char services[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = {0};
-       int ret;
-
-       ret = adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC,
-                                     ADF_SERVICES_ENABLED, services);
-
-       adf_dev_stop(accel_dev);
-       adf_dev_shutdown(accel_dev);
-
-       if (!ret) {
-               ret = adf_cfg_section_add(accel_dev, ADF_GENERAL_SEC);
-               if (ret)
-                       return ret;
-
-               ret = adf_cfg_add_key_value_param(accel_dev, ADF_GENERAL_SEC,
-                                                 ADF_SERVICES_ENABLED,
-                                                 services, ADF_STR);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-
 /**
  * adf_sriov_configure() - Enable SRIOV for the device
  * @pdev:  Pointer to PCI device.
@@ -185,7 +159,7 @@ int adf_sriov_configure(struct pci_dev *pdev, int numvfs)
                        return -EBUSY;
                }
 
-               ret = adf_sriov_prepare_restart(accel_dev);
+               ret = adf_dev_shutdown_cache_cfg(accel_dev);
                if (ret)
                        return ret;
        }
diff --git a/drivers/crypto/qat/qat_common/adf_sysfs.c b/drivers/crypto/qat/qat_common/adf_sysfs.c
new file mode 100644 (file)
index 0000000..e8b078e
--- /dev/null
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only)
+/* Copyright(c) 2022 Intel Corporation */
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include "adf_accel_devices.h"
+#include "adf_cfg.h"
+#include "adf_common_drv.h"
+
+static const char * const state_operations[] = {
+       [DEV_DOWN] = "down",
+       [DEV_UP] = "up",
+};
+
+static ssize_t state_show(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       struct adf_accel_dev *accel_dev;
+       char *state;
+
+       accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev));
+       if (!accel_dev)
+               return -EINVAL;
+
+       state = adf_dev_started(accel_dev) ? "up" : "down";
+       return sysfs_emit(buf, "%s\n", state);
+}
+
+static ssize_t state_store(struct device *dev, struct device_attribute *attr,
+                          const char *buf, size_t count)
+{
+       struct adf_accel_dev *accel_dev;
+       u32 accel_id;
+       int ret;
+
+       accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev));
+       if (!accel_dev)
+               return -EINVAL;
+
+       accel_id = accel_dev->accel_id;
+
+       if (adf_devmgr_in_reset(accel_dev) || adf_dev_in_use(accel_dev)) {
+               dev_info(dev, "Device qat_dev%d is busy\n", accel_id);
+               return -EBUSY;
+       }
+
+       ret = sysfs_match_string(state_operations, buf);
+       if (ret < 0)
+               return ret;
+
+       switch (ret) {
+       case DEV_DOWN:
+               if (!adf_dev_started(accel_dev)) {
+                       dev_info(dev, "Device qat_dev%d already down\n",
+                                accel_id);
+                       return -EINVAL;
+               }
+
+               dev_info(dev, "Stopping device qat_dev%d\n", accel_id);
+
+               ret = adf_dev_shutdown_cache_cfg(accel_dev);
+               if (ret < 0)
+                       return -EINVAL;
+
+               break;
+       case DEV_UP:
+               if (adf_dev_started(accel_dev)) {
+                       dev_info(dev, "Device qat_dev%d already up\n",
+                                accel_id);
+                       return -EINVAL;
+               }
+
+               dev_info(dev, "Starting device qat_dev%d\n", accel_id);
+
+               ret = GET_HW_DATA(accel_dev)->dev_config(accel_dev);
+               if (!ret)
+                       ret = adf_dev_init(accel_dev);
+               if (!ret)
+                       ret = adf_dev_start(accel_dev);
+
+               if (ret < 0) {
+                       dev_err(dev, "Failed to start device qat_dev%d\n",
+                               accel_id);
+                       adf_dev_shutdown_cache_cfg(accel_dev);
+                       return ret;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return count;
+}
+
+static const char * const services_operations[] = {
+       ADF_CFG_CY,
+       ADF_CFG_DC,
+};
+
+static ssize_t cfg_services_show(struct device *dev, struct device_attribute *attr,
+                                char *buf)
+{
+       char services[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = {0};
+       struct adf_accel_dev *accel_dev;
+       int ret;
+
+       accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev));
+       if (!accel_dev)
+               return -EINVAL;
+
+       ret = adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC,
+                                     ADF_SERVICES_ENABLED, services);
+       if (ret)
+               return ret;
+
+       return sysfs_emit(buf, "%s\n", services);
+}
+
+static int adf_sysfs_update_dev_config(struct adf_accel_dev *accel_dev,
+                                      const char *services)
+{
+       return adf_cfg_add_key_value_param(accel_dev, ADF_GENERAL_SEC,
+                                          ADF_SERVICES_ENABLED, services,
+                                          ADF_STR);
+}
+
+static ssize_t cfg_services_store(struct device *dev, struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       struct adf_hw_device_data *hw_data;
+       struct adf_accel_dev *accel_dev;
+       int ret;
+
+       ret = sysfs_match_string(services_operations, buf);
+       if (ret < 0)
+               return ret;
+
+       accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev));
+       if (!accel_dev)
+               return -EINVAL;
+
+       if (adf_dev_started(accel_dev)) {
+               dev_info(dev, "Device qat_dev%d must be down to reconfigure the service.\n",
+                        accel_dev->accel_id);
+               return -EINVAL;
+       }
+
+       ret = adf_sysfs_update_dev_config(accel_dev, services_operations[ret]);
+       if (ret < 0)
+               return ret;
+
+       hw_data = GET_HW_DATA(accel_dev);
+
+       /* Update capabilities mask after change in configuration.
+        * A call to this function is required as capabilities are, at the
+        * moment, tied to configuration
+        */
+       hw_data->accel_capabilities_mask = hw_data->get_accel_cap(accel_dev);
+       if (!hw_data->accel_capabilities_mask)
+               return -EINVAL;
+
+       return count;
+}
+
+static DEVICE_ATTR_RW(state);
+static DEVICE_ATTR_RW(cfg_services);
+
+static struct attribute *qat_attrs[] = {
+       &dev_attr_state.attr,
+       &dev_attr_cfg_services.attr,
+       NULL,
+};
+
+static struct attribute_group qat_group = {
+       .attrs = qat_attrs,
+       .name = "qat",
+};
+
+int adf_sysfs_init(struct adf_accel_dev *accel_dev)
+{
+       int ret;
+
+       ret = devm_device_add_group(&GET_DEV(accel_dev), &qat_group);
+       if (ret) {
+               dev_err(&GET_DEV(accel_dev),
+                       "Failed to create qat attribute group: %d\n", ret);
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(adf_sysfs_init);
index 148edbe..fb45fa8 100644 (file)
@@ -605,7 +605,7 @@ static int qat_alg_aead_newkey(struct crypto_aead *tfm, const u8 *key,
 {
        struct qat_alg_aead_ctx *ctx = crypto_aead_ctx(tfm);
        struct qat_crypto_instance *inst = NULL;
-       int node = get_current_node();
+       int node = numa_node_id();
        struct device *dev;
        int ret;
 
@@ -1065,7 +1065,7 @@ static int qat_alg_skcipher_newkey(struct qat_alg_skcipher_ctx *ctx,
 {
        struct qat_crypto_instance *inst = NULL;
        struct device *dev;
-       int node = get_current_node();
+       int node = numa_node_id();
        int ret;
 
        inst = qat_crypto_get_instance_node(node);
index 16d97db..095ed2a 100644 (file)
@@ -489,7 +489,7 @@ static int qat_dh_init_tfm(struct crypto_kpp *tfm)
 {
        struct qat_dh_ctx *ctx = kpp_tfm_ctx(tfm);
        struct qat_crypto_instance *inst =
-                       qat_crypto_get_instance_node(get_current_node());
+                       qat_crypto_get_instance_node(numa_node_id());
 
        if (!inst)
                return -EINVAL;
@@ -1225,7 +1225,7 @@ static int qat_rsa_init_tfm(struct crypto_akcipher *tfm)
 {
        struct qat_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
        struct qat_crypto_instance *inst =
-                       qat_crypto_get_instance_node(get_current_node());
+                       qat_crypto_get_instance_node(numa_node_id());
 
        if (!inst)
                return -EINVAL;
index 7717e9e..b79e49a 100644 (file)
@@ -2321,9 +2321,6 @@ static int s5p_aes_remove(struct platform_device *pdev)
        struct s5p_aes_dev *pdata = platform_get_drvdata(pdev);
        int i;
 
-       if (!pdata)
-               return -ENODEV;
-
        for (i = 0; i < ARRAY_SIZE(algs); i++)
                crypto_unregister_skcipher(&algs[i]);
 
index 6957a12..f4bc06c 100644 (file)
@@ -86,7 +86,6 @@ struct sa_match_data {
        u8 priv;
        u8 priv_id;
        u32 supported_algos;
-       bool skip_engine_control;
 };
 
 static struct device *sa_k3_dev;
@@ -2361,7 +2360,15 @@ static int sa_link_child(struct device *dev, void *data)
 static struct sa_match_data am654_match_data = {
        .priv = 1,
        .priv_id = 1,
-       .supported_algos = GENMASK(SA_ALG_AUTHENC_SHA256_AES, 0),
+       .supported_algos = BIT(SA_ALG_CBC_AES) |
+                          BIT(SA_ALG_EBC_AES) |
+                          BIT(SA_ALG_CBC_DES3) |
+                          BIT(SA_ALG_ECB_DES3) |
+                          BIT(SA_ALG_SHA1) |
+                          BIT(SA_ALG_SHA256) |
+                          BIT(SA_ALG_SHA512) |
+                          BIT(SA_ALG_AUTHENC_SHA1_AES) |
+                          BIT(SA_ALG_AUTHENC_SHA256_AES),
 };
 
 static struct sa_match_data am64_match_data = {
@@ -2372,7 +2379,6 @@ static struct sa_match_data am64_match_data = {
                           BIT(SA_ALG_SHA256) |
                           BIT(SA_ALG_SHA512) |
                           BIT(SA_ALG_AUTHENC_SHA256_AES),
-       .skip_engine_control = true,
 };
 
 static const struct of_device_id of_match[] = {
@@ -2390,6 +2396,7 @@ static int sa_ul_probe(struct platform_device *pdev)
        struct device_node *node = dev->of_node;
        static void __iomem *saul_base;
        struct sa_crypto_data *dev_data;
+       u32 status, val;
        int ret;
 
        dev_data = devm_kzalloc(dev, sizeof(*dev_data), GFP_KERNEL);
@@ -2426,13 +2433,13 @@ static int sa_ul_probe(struct platform_device *pdev)
 
        spin_lock_init(&dev_data->scid_lock);
 
-       if (!dev_data->match_data->skip_engine_control) {
-               u32 val = SA_EEC_ENCSS_EN | SA_EEC_AUTHSS_EN | SA_EEC_CTXCACH_EN |
-                         SA_EEC_CPPI_PORT_IN_EN | SA_EEC_CPPI_PORT_OUT_EN |
-                         SA_EEC_TRNG_EN;
-
+       val = SA_EEC_ENCSS_EN | SA_EEC_AUTHSS_EN | SA_EEC_CTXCACH_EN |
+             SA_EEC_CPPI_PORT_IN_EN | SA_EEC_CPPI_PORT_OUT_EN |
+             SA_EEC_TRNG_EN;
+       status = readl_relaxed(saul_base + SA_ENGINE_STATUS);
+       /* Only enable engines if all are not already enabled */
+       if (val & ~status)
                writel_relaxed(val, saul_base + SA_ENGINE_ENABLE_CONTROL);
-       }
 
        sa_register_algos(dev_data);
 
index ed66d1f..92bf972 100644 (file)
@@ -16,6 +16,7 @@
 #include <crypto/sha1.h>
 #include <crypto/sha2.h>
 
+#define SA_ENGINE_STATUS               0x0008
 #define SA_ENGINE_ENABLE_CONTROL       0x1000
 
 struct sa_tfm_ctx;
index 265ef3e..f104e8a 100644 (file)
@@ -421,7 +421,7 @@ static int hash_get_device_data(struct hash_ctx *ctx,
  * @keylen:            The lengt of the key.
  *
  * Note! This function DOES NOT write to the NBLW registry, even though
- * specified in the the hw design spec. Either due to incorrect info in the
+ * specified in the hw design spec. Either due to incorrect info in the
  * spec or due to a bug in the hw.
  */
 static void hash_hw_write_key(struct hash_device_data *device_data,
index 5bc5710..77eca20 100644 (file)
@@ -23,6 +23,7 @@
 #include <crypto/internal/hash.h>
 #include <crypto/internal/simd.h>
 #include <crypto/b128ops.h>
+#include "aesp8-ppc.h"
 
 void gcm_init_p8(u128 htable[16], const u64 Xi[2]);
 void gcm_gmult_p8(u64 Xi[2], const u128 htable[16]);
index 09bba18..041e633 100644 (file)
@@ -16,7 +16,7 @@
 # details see https://www.openssl.org/~appro/cryptogams/.
 # ====================================================================
 #
-# GHASH for for PowerISA v2.07.
+# GHASH for PowerISA v2.07.
 #
 # July 2014
 #
index 0e89a7a..bfc8ee8 100644 (file)
@@ -197,7 +197,7 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
        else
                cxld->target_type = CXL_DECODER_ACCELERATOR;
 
-       if (is_cxl_endpoint(to_cxl_port(cxld->dev.parent)))
+       if (is_endpoint_decoder(&cxld->dev))
                return 0;
 
        target_list.value =
index 54f4347..cbf23be 100644 (file)
@@ -355,11 +355,13 @@ static int cxl_to_mem_cmd(struct cxl_mem_command *mem_cmd,
                return -EBUSY;
 
        /* Check the input buffer is the expected size */
-       if (info->size_in != send_cmd->in.size)
+       if ((info->size_in != CXL_VARIABLE_PAYLOAD) &&
+           (info->size_in != send_cmd->in.size))
                return -ENOMEM;
 
        /* Check the output buffer is at least large enough */
-       if (send_cmd->out.size < info->size_out)
+       if ((info->size_out != CXL_VARIABLE_PAYLOAD) &&
+           (send_cmd->out.size < info->size_out))
                return -ENOMEM;
 
        *mem_cmd = (struct cxl_mem_command) {
index ea60abd..dbce99b 100644 (file)
@@ -272,7 +272,7 @@ static const struct device_type cxl_decoder_root_type = {
        .groups = cxl_decoder_root_attribute_groups,
 };
 
-static bool is_endpoint_decoder(struct device *dev)
+bool is_endpoint_decoder(struct device *dev)
 {
        return dev->type == &cxl_decoder_endpoint_type;
 }
index 140dc32..6799b27 100644 (file)
@@ -340,6 +340,7 @@ struct cxl_dport *cxl_find_dport_by_dev(struct cxl_port *port,
 
 struct cxl_decoder *to_cxl_decoder(struct device *dev);
 bool is_root_decoder(struct device *dev);
+bool is_endpoint_decoder(struct device *dev);
 bool is_cxl_decoder(struct device *dev);
 struct cxl_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
                                           unsigned int nr_targets);
index 60d10ee..7df0b05 100644 (file)
@@ -300,13 +300,13 @@ struct cxl_mbox_identify {
 } __packed;
 
 struct cxl_mbox_get_lsa {
-       u32 offset;
-       u32 length;
+       __le32 offset;
+       __le32 length;
 } __packed;
 
 struct cxl_mbox_set_lsa {
-       u32 offset;
-       u32 reserved;
+       __le32 offset;
+       __le32 reserved;
        u8 data[];
 } __packed;
 
index c310f1f..a979d0b 100644 (file)
@@ -29,6 +29,7 @@ static int create_endpoint(struct cxl_memdev *cxlmd,
 {
        struct cxl_dev_state *cxlds = cxlmd->cxlds;
        struct cxl_port *endpoint;
+       int rc;
 
        endpoint = devm_cxl_add_port(&parent_port->dev, &cxlmd->dev,
                                     cxlds->component_reg_phys, parent_port);
@@ -37,13 +38,17 @@ static int create_endpoint(struct cxl_memdev *cxlmd,
 
        dev_dbg(&cxlmd->dev, "add: %s\n", dev_name(&endpoint->dev));
 
+       rc = cxl_endpoint_autoremove(cxlmd, endpoint);
+       if (rc)
+               return rc;
+
        if (!endpoint->dev.driver) {
                dev_err(&cxlmd->dev, "%s failed probe\n",
                        dev_name(&endpoint->dev));
                return -ENXIO;
        }
 
-       return cxl_endpoint_autoremove(cxlmd, endpoint);
+       return 0;
 }
 
 static void enable_suspend(void *data)
index bbeef91..0aaa70b 100644 (file)
@@ -108,8 +108,8 @@ static int cxl_pmem_get_config_data(struct cxl_dev_state *cxlds,
                return -EINVAL;
 
        get_lsa = (struct cxl_mbox_get_lsa) {
-               .offset = cmd->in_offset,
-               .length = cmd->in_length,
+               .offset = cpu_to_le32(cmd->in_offset),
+               .length = cpu_to_le32(cmd->in_length),
        };
 
        rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_GET_LSA, &get_lsa,
@@ -139,7 +139,7 @@ static int cxl_pmem_set_config_data(struct cxl_dev_state *cxlds,
                return -ENOMEM;
 
        *set_lsa = (struct cxl_mbox_set_lsa) {
-               .offset = cmd->in_offset,
+               .offset = cpu_to_le32(cmd->in_offset),
        };
        memcpy(set_lsa->data, cmd->in_buf, cmd->in_length);
 
index 87eb2b8..9754d8b 100644 (file)
@@ -120,6 +120,16 @@ config ARM_TEGRA_DEVFREQ
          It reads ACTMON counters of memory controllers and adjusts the
          operating frequencies and voltages with OPP support.
 
+config ARM_MEDIATEK_CCI_DEVFREQ
+       tristate "MEDIATEK CCI DEVFREQ Driver"
+       depends on ARM_MEDIATEK_CPUFREQ || COMPILE_TEST
+       select DEVFREQ_GOV_PASSIVE
+       help
+         This adds a devfreq driver for MediaTek Cache Coherent Interconnect
+         which is shared the same regulators with the cpu cluster. It can track
+         buck voltages and update a proper CCI frequency. Use the notification
+         to get the regulator status.
+
 config ARM_RK3399_DMC_DEVFREQ
        tristate "ARM RK3399 DMC DEVFREQ Driver"
        depends on (ARCH_ROCKCHIP && HAVE_ARM_SMCCC) || \
index 0b6be92..bf40d04 100644 (file)
@@ -11,6 +11,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE)     += governor_passive.o
 obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ)   += exynos-bus.o
 obj-$(CONFIG_ARM_IMX_BUS_DEVFREQ)      += imx-bus.o
 obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ)   += imx8m-ddrc.o
+obj-$(CONFIG_ARM_MEDIATEK_CCI_DEVFREQ) += mtk-cci-devfreq.o
 obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ)   += rk3399_dmc.o
 obj-$(CONFIG_ARM_SUN8I_A33_MBUS_DEVFREQ)       += sun8i-a33-mbus.o
 obj-$(CONFIG_ARM_TEGRA_DEVFREQ)                += tegra30-devfreq.o
index 01474da..63347a5 100644 (file)
@@ -123,7 +123,7 @@ void devfreq_get_freq_range(struct devfreq *devfreq,
                            unsigned long *min_freq,
                            unsigned long *max_freq)
 {
-       unsigned long *freq_table = devfreq->profile->freq_table;
+       unsigned long *freq_table = devfreq->freq_table;
        s32 qos_min_freq, qos_max_freq;
 
        lockdep_assert_held(&devfreq->lock);
@@ -133,11 +133,11 @@ void devfreq_get_freq_range(struct devfreq *devfreq,
         * The devfreq drivers can initialize this in either ascending or
         * descending order and devfreq core supports both.
         */
-       if (freq_table[0] < freq_table[devfreq->profile->max_state - 1]) {
+       if (freq_table[0] < freq_table[devfreq->max_state - 1]) {
                *min_freq = freq_table[0];
-               *max_freq = freq_table[devfreq->profile->max_state - 1];
+               *max_freq = freq_table[devfreq->max_state - 1];
        } else {
-               *min_freq = freq_table[devfreq->profile->max_state - 1];
+               *min_freq = freq_table[devfreq->max_state - 1];
                *max_freq = freq_table[0];
        }
 
@@ -169,8 +169,8 @@ static int devfreq_get_freq_level(struct devfreq *devfreq, unsigned long freq)
 {
        int lev;
 
-       for (lev = 0; lev < devfreq->profile->max_state; lev++)
-               if (freq == devfreq->profile->freq_table[lev])
+       for (lev = 0; lev < devfreq->max_state; lev++)
+               if (freq == devfreq->freq_table[lev])
                        return lev;
 
        return -EINVAL;
@@ -178,7 +178,6 @@ static int devfreq_get_freq_level(struct devfreq *devfreq, unsigned long freq)
 
 static int set_freq_table(struct devfreq *devfreq)
 {
-       struct devfreq_dev_profile *profile = devfreq->profile;
        struct dev_pm_opp *opp;
        unsigned long freq;
        int i, count;
@@ -188,25 +187,22 @@ static int set_freq_table(struct devfreq *devfreq)
        if (count <= 0)
                return -EINVAL;
 
-       profile->max_state = count;
-       profile->freq_table = devm_kcalloc(devfreq->dev.parent,
-                                       profile->max_state,
-                                       sizeof(*profile->freq_table),
-                                       GFP_KERNEL);
-       if (!profile->freq_table) {
-               profile->max_state = 0;
+       devfreq->max_state = count;
+       devfreq->freq_table = devm_kcalloc(devfreq->dev.parent,
+                                          devfreq->max_state,
+                                          sizeof(*devfreq->freq_table),
+                                          GFP_KERNEL);
+       if (!devfreq->freq_table)
                return -ENOMEM;
-       }
 
-       for (i = 0, freq = 0; i < profile->max_state; i++, freq++) {
+       for (i = 0, freq = 0; i < devfreq->max_state; i++, freq++) {
                opp = dev_pm_opp_find_freq_ceil(devfreq->dev.parent, &freq);
                if (IS_ERR(opp)) {
-                       devm_kfree(devfreq->dev.parent, profile->freq_table);
-                       profile->max_state = 0;
+                       devm_kfree(devfreq->dev.parent, devfreq->freq_table);
                        return PTR_ERR(opp);
                }
                dev_pm_opp_put(opp);
-               profile->freq_table[i] = freq;
+               devfreq->freq_table[i] = freq;
        }
 
        return 0;
@@ -246,7 +242,7 @@ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
 
        if (lev != prev_lev) {
                devfreq->stats.trans_table[
-                       (prev_lev * devfreq->profile->max_state) + lev]++;
+                       (prev_lev * devfreq->max_state) + lev]++;
                devfreq->stats.total_trans++;
        }
 
@@ -700,6 +696,8 @@ static int qos_notifier_call(struct devfreq *devfreq)
 /**
  * qos_min_notifier_call() - Callback for QoS min_freq changes.
  * @nb:                Should be devfreq->nb_min
+ * @val:       not used
+ * @ptr:       not used
  */
 static int qos_min_notifier_call(struct notifier_block *nb,
                                         unsigned long val, void *ptr)
@@ -710,6 +708,8 @@ static int qos_min_notifier_call(struct notifier_block *nb,
 /**
  * qos_max_notifier_call() - Callback for QoS max_freq changes.
  * @nb:                Should be devfreq->nb_max
+ * @val:       not used
+ * @ptr:       not used
  */
 static int qos_max_notifier_call(struct notifier_block *nb,
                                         unsigned long val, void *ptr)
@@ -835,6 +835,9 @@ struct devfreq *devfreq_add_device(struct device *dev,
                if (err < 0)
                        goto err_dev;
                mutex_lock(&devfreq->lock);
+       } else {
+               devfreq->freq_table = devfreq->profile->freq_table;
+               devfreq->max_state = devfreq->profile->max_state;
        }
 
        devfreq->scaling_min_freq = find_available_min_freq(devfreq);
@@ -870,8 +873,8 @@ struct devfreq *devfreq_add_device(struct device *dev,
 
        devfreq->stats.trans_table = devm_kzalloc(&devfreq->dev,
                        array3_size(sizeof(unsigned int),
-                                   devfreq->profile->max_state,
-                                   devfreq->profile->max_state),
+                                   devfreq->max_state,
+                                   devfreq->max_state),
                        GFP_KERNEL);
        if (!devfreq->stats.trans_table) {
                mutex_unlock(&devfreq->lock);
@@ -880,7 +883,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
        }
 
        devfreq->stats.time_in_state = devm_kcalloc(&devfreq->dev,
-                       devfreq->profile->max_state,
+                       devfreq->max_state,
                        sizeof(*devfreq->stats.time_in_state),
                        GFP_KERNEL);
        if (!devfreq->stats.time_in_state) {
@@ -932,8 +935,9 @@ struct devfreq *devfreq_add_device(struct device *dev,
        err = devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_START,
                                                NULL);
        if (err) {
-               dev_err(dev, "%s: Unable to start governor for the device\n",
-                       __func__);
+               dev_err_probe(dev, err,
+                       "%s: Unable to start governor for the device\n",
+                        __func__);
                goto err_init;
        }
        create_sysfs_files(devfreq, devfreq->governor);
@@ -1665,9 +1669,9 @@ static ssize_t available_frequencies_show(struct device *d,
 
        mutex_lock(&df->lock);
 
-       for (i = 0; i < df->profile->max_state; i++)
+       for (i = 0; i < df->max_state; i++)
                count += scnprintf(&buf[count], (PAGE_SIZE - count - 2),
-                               "%lu ", df->profile->freq_table[i]);
+                               "%lu ", df->freq_table[i]);
 
        mutex_unlock(&df->lock);
        /* Truncate the trailing space */
@@ -1690,7 +1694,7 @@ static ssize_t trans_stat_show(struct device *dev,
 
        if (!df->profile)
                return -EINVAL;
-       max_state = df->profile->max_state;
+       max_state = df->max_state;
 
        if (max_state == 0)
                return sprintf(buf, "Not Supported.\n");
@@ -1707,19 +1711,17 @@ static ssize_t trans_stat_show(struct device *dev,
        len += sprintf(buf + len, "           :");
        for (i = 0; i < max_state; i++)
                len += sprintf(buf + len, "%10lu",
-                               df->profile->freq_table[i]);
+                               df->freq_table[i]);
 
        len += sprintf(buf + len, "   time(ms)\n");
 
        for (i = 0; i < max_state; i++) {
-               if (df->profile->freq_table[i]
-                                       == df->previous_freq) {
+               if (df->freq_table[i] == df->previous_freq)
                        len += sprintf(buf + len, "*");
-               } else {
+               else
                        len += sprintf(buf + len, " ");
-               }
-               len += sprintf(buf + len, "%10lu:",
-                               df->profile->freq_table[i]);
+
+               len += sprintf(buf + len, "%10lu:", df->freq_table[i]);
                for (j = 0; j < max_state; j++)
                        len += sprintf(buf + len, "%10u",
                                df->stats.trans_table[(i * max_state) + j]);
@@ -1743,7 +1745,7 @@ static ssize_t trans_stat_store(struct device *dev,
        if (!df->profile)
                return -EINVAL;
 
-       if (df->profile->max_state == 0)
+       if (df->max_state == 0)
                return count;
 
        err = kstrtoint(buf, 10, &value);
@@ -1751,11 +1753,11 @@ static ssize_t trans_stat_store(struct device *dev,
                return -EINVAL;
 
        mutex_lock(&df->lock);
-       memset(df->stats.time_in_state, 0, (df->profile->max_state *
+       memset(df->stats.time_in_state, 0, (df->max_state *
                                        sizeof(*df->stats.time_in_state)));
        memset(df->stats.trans_table, 0, array3_size(sizeof(unsigned int),
-                                       df->profile->max_state,
-                                       df->profile->max_state));
+                                       df->max_state,
+                                       df->max_state));
        df->stats.total_trans = 0;
        df->stats.last_update = get_jiffies_64();
        mutex_unlock(&df->lock);
index 9b849d7..a443e7c 100644 (file)
@@ -519,15 +519,19 @@ static int of_get_devfreq_events(struct device_node *np,
 
        count = of_get_child_count(events_np);
        desc = devm_kcalloc(dev, count, sizeof(*desc), GFP_KERNEL);
-       if (!desc)
+       if (!desc) {
+               of_node_put(events_np);
                return -ENOMEM;
+       }
        info->num_events = count;
 
        of_id = of_match_device(exynos_ppmu_id_match, dev);
        if (of_id)
                info->ppmu_type = (enum exynos_ppmu_type)of_id->data;
-       else
+       else {
+               of_node_put(events_np);
                return -EINVAL;
+       }
 
        j = 0;
        for_each_child_of_node(events_np, node) {
index e689101..f7dcc44 100644 (file)
@@ -447,9 +447,9 @@ static int exynos_bus_probe(struct platform_device *pdev)
                }
        }
 
-       max_state = bus->devfreq->profile->max_state;
-       min_freq = (bus->devfreq->profile->freq_table[0] / 1000);
-       max_freq = (bus->devfreq->profile->freq_table[max_state - 1] / 1000);
+       max_state = bus->devfreq->max_state;
+       min_freq = (bus->devfreq->freq_table[0] / 1000);
+       max_freq = (bus->devfreq->freq_table[max_state - 1] / 1000);
        pr_info("exynos-bus: new bus device registered: %s (%6ld KHz ~ %6ld KHz)\n",
                        dev_name(dev), min_freq, max_freq);
 
index 72c6797..953cf9a 100644 (file)
@@ -1,4 +1,4 @@
-       // SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * linux/drivers/devfreq/governor_passive.c
  *
 #include <linux/slab.h>
 #include <linux/device.h>
 #include <linux/devfreq.h>
+#include <linux/units.h>
 #include "governor.h"
 
-#define HZ_PER_KHZ     1000
-
 static struct devfreq_cpu_data *
 get_parent_cpu_data(struct devfreq_passive_data *p_data,
                    struct cpufreq_policy *policy)
@@ -34,6 +33,20 @@ get_parent_cpu_data(struct devfreq_passive_data *p_data,
        return NULL;
 }
 
+static void delete_parent_cpu_data(struct devfreq_passive_data *p_data)
+{
+       struct devfreq_cpu_data *parent_cpu_data, *tmp;
+
+       list_for_each_entry_safe(parent_cpu_data, tmp, &p_data->cpu_data_list, node) {
+               list_del(&parent_cpu_data->node);
+
+               if (parent_cpu_data->opp_table)
+                       dev_pm_opp_put_opp_table(parent_cpu_data->opp_table);
+
+               kfree(parent_cpu_data);
+       }
+}
+
 static unsigned long get_target_freq_by_required_opp(struct device *p_dev,
                                                struct opp_table *p_opp_table,
                                                struct opp_table *opp_table,
@@ -131,18 +144,18 @@ static int get_target_freq_with_devfreq(struct devfreq *devfreq,
                goto out;
 
        /* Use interpolation if required opps is not available */
-       for (i = 0; i < parent_devfreq->profile->max_state; i++)
-               if (parent_devfreq->profile->freq_table[i] == *freq)
+       for (i = 0; i < parent_devfreq->max_state; i++)
+               if (parent_devfreq->freq_table[i] == *freq)
                        break;
 
-       if (i == parent_devfreq->profile->max_state)
+       if (i == parent_devfreq->max_state)
                return -EINVAL;
 
-       if (i < devfreq->profile->max_state) {
-               child_freq = devfreq->profile->freq_table[i];
+       if (i < devfreq->max_state) {
+               child_freq = devfreq->freq_table[i];
        } else {
-               count = devfreq->profile->max_state;
-               child_freq = devfreq->profile->freq_table[count - 1];
+               count = devfreq->max_state;
+               child_freq = devfreq->freq_table[count - 1];
        }
 
 out:
@@ -222,8 +235,7 @@ static int cpufreq_passive_unregister_notifier(struct devfreq *devfreq)
 {
        struct devfreq_passive_data *p_data
                        = (struct devfreq_passive_data *)devfreq->data;
-       struct devfreq_cpu_data *parent_cpu_data;
-       int cpu, ret = 0;
+       int ret;
 
        if (p_data->nb.notifier_call) {
                ret = cpufreq_unregister_notifier(&p_data->nb,
@@ -232,27 +244,9 @@ static int cpufreq_passive_unregister_notifier(struct devfreq *devfreq)
                        return ret;
        }
 
-       for_each_possible_cpu(cpu) {
-               struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
-               if (!policy) {
-                       ret = -EINVAL;
-                       continue;
-               }
-
-               parent_cpu_data = get_parent_cpu_data(p_data, policy);
-               if (!parent_cpu_data) {
-                       cpufreq_cpu_put(policy);
-                       continue;
-               }
+       delete_parent_cpu_data(p_data);
 
-               list_del(&parent_cpu_data->node);
-               if (parent_cpu_data->opp_table)
-                       dev_pm_opp_put_opp_table(parent_cpu_data->opp_table);
-               kfree(parent_cpu_data);
-               cpufreq_cpu_put(policy);
-       }
-
-       return ret;
+       return 0;
 }
 
 static int cpufreq_passive_register_notifier(struct devfreq *devfreq)
@@ -336,7 +330,6 @@ err_free_cpu_data:
 err_put_policy:
        cpufreq_cpu_put(policy);
 err:
-       WARN_ON(cpufreq_passive_unregister_notifier(devfreq));
 
        return ret;
 }
@@ -407,8 +400,7 @@ static int devfreq_passive_event_handler(struct devfreq *devfreq,
        if (!p_data)
                return -EINVAL;
 
-       if (!p_data->this)
-               p_data->this = devfreq;
+       p_data->this = devfreq;
 
        switch (event) {
        case DEVFREQ_GOV_START:
index f3f6e25..f87067f 100644 (file)
@@ -59,7 +59,7 @@ static int imx_bus_init_icc(struct device *dev)
        struct imx_bus *priv = dev_get_drvdata(dev);
        const char *icc_driver_name;
 
-       if (!of_get_property(dev->of_node, "#interconnect-cells", 0))
+       if (!of_get_property(dev->of_node, "#interconnect-cells", NULL))
                return 0;
        if (!IS_ENABLED(CONFIG_INTERCONNECT_IMX)) {
                dev_warn(dev, "imx interconnect drivers disabled\n");
diff --git a/drivers/devfreq/mtk-cci-devfreq.c b/drivers/devfreq/mtk-cci-devfreq.c
new file mode 100644 (file)
index 0000000..71abb3f
--- /dev/null
@@ -0,0 +1,440 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 MediaTek Inc.
+ */
+
+#include <linux/clk.h>
+#include <linux/devfreq.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_opp.h>
+#include <linux/regulator/consumer.h>
+
+struct mtk_ccifreq_platform_data {
+       int min_volt_shift;
+       int max_volt_shift;
+       int proc_max_volt;
+       int sram_min_volt;
+       int sram_max_volt;
+};
+
+struct mtk_ccifreq_drv {
+       struct device *dev;
+       struct devfreq *devfreq;
+       struct regulator *proc_reg;
+       struct regulator *sram_reg;
+       struct clk *cci_clk;
+       struct clk *inter_clk;
+       int inter_voltage;
+       unsigned long pre_freq;
+       /* Avoid race condition for regulators between notify and policy */
+       struct mutex reg_lock;
+       struct notifier_block opp_nb;
+       const struct mtk_ccifreq_platform_data *soc_data;
+       int vtrack_max;
+};
+
+static int mtk_ccifreq_set_voltage(struct mtk_ccifreq_drv *drv, int new_voltage)
+{
+       const struct mtk_ccifreq_platform_data *soc_data = drv->soc_data;
+       struct device *dev = drv->dev;
+       int pre_voltage, pre_vsram, new_vsram, vsram, voltage, ret;
+       int retry_max = drv->vtrack_max;
+
+       if (!drv->sram_reg) {
+               ret = regulator_set_voltage(drv->proc_reg, new_voltage,
+                                           drv->soc_data->proc_max_volt);
+               return ret;
+       }
+
+       pre_voltage = regulator_get_voltage(drv->proc_reg);
+       if (pre_voltage < 0) {
+               dev_err(dev, "invalid vproc value: %d\n", pre_voltage);
+               return pre_voltage;
+       }
+
+       pre_vsram = regulator_get_voltage(drv->sram_reg);
+       if (pre_vsram < 0) {
+               dev_err(dev, "invalid vsram value: %d\n", pre_vsram);
+               return pre_vsram;
+       }
+
+       new_vsram = clamp(new_voltage + soc_data->min_volt_shift,
+                         soc_data->sram_min_volt, soc_data->sram_max_volt);
+
+       do {
+               if (pre_voltage <= new_voltage) {
+                       vsram = clamp(pre_voltage + soc_data->max_volt_shift,
+                                     soc_data->sram_min_volt, new_vsram);
+                       ret = regulator_set_voltage(drv->sram_reg, vsram,
+                                                   soc_data->sram_max_volt);
+                       if (ret)
+                               return ret;
+
+                       if (vsram == soc_data->sram_max_volt ||
+                           new_vsram == soc_data->sram_min_volt)
+                               voltage = new_voltage;
+                       else
+                               voltage = vsram - soc_data->min_volt_shift;
+
+                       ret = regulator_set_voltage(drv->proc_reg, voltage,
+                                                   soc_data->proc_max_volt);
+                       if (ret) {
+                               regulator_set_voltage(drv->sram_reg, pre_vsram,
+                                                     soc_data->sram_max_volt);
+                               return ret;
+                       }
+               } else if (pre_voltage > new_voltage) {
+                       voltage = max(new_voltage,
+                                     pre_vsram - soc_data->max_volt_shift);
+                       ret = regulator_set_voltage(drv->proc_reg, voltage,
+                                                   soc_data->proc_max_volt);
+                       if (ret)
+                               return ret;
+
+                       if (voltage == new_voltage)
+                               vsram = new_vsram;
+                       else
+                               vsram = max(new_vsram,
+                                           voltage + soc_data->min_volt_shift);
+
+                       ret = regulator_set_voltage(drv->sram_reg, vsram,
+                                                   soc_data->sram_max_volt);
+                       if (ret) {
+                               regulator_set_voltage(drv->proc_reg, pre_voltage,
+                                                     soc_data->proc_max_volt);
+                               return ret;
+                       }
+               }
+
+               pre_voltage = voltage;
+               pre_vsram = vsram;
+
+               if (--retry_max < 0) {
+                       dev_err(dev,
+                               "over loop count, failed to set voltage\n");
+                       return -EINVAL;
+               }
+       } while (voltage != new_voltage || vsram != new_vsram);
+
+       return 0;
+}
+
+static int mtk_ccifreq_target(struct device *dev, unsigned long *freq,
+                             u32 flags)
+{
+       struct mtk_ccifreq_drv *drv = dev_get_drvdata(dev);
+       struct clk *cci_pll = clk_get_parent(drv->cci_clk);
+       struct dev_pm_opp *opp;
+       unsigned long opp_rate;
+       int voltage, pre_voltage, inter_voltage, target_voltage, ret;
+
+       if (!drv)
+               return -EINVAL;
+
+       if (drv->pre_freq == *freq)
+               return 0;
+
+       inter_voltage = drv->inter_voltage;
+
+       opp_rate = *freq;
+       opp = devfreq_recommended_opp(dev, &opp_rate, 1);
+       if (IS_ERR(opp)) {
+               dev_err(dev, "failed to find opp for freq: %ld\n", opp_rate);
+               return PTR_ERR(opp);
+       }
+
+       mutex_lock(&drv->reg_lock);
+
+       voltage = dev_pm_opp_get_voltage(opp);
+       dev_pm_opp_put(opp);
+
+       pre_voltage = regulator_get_voltage(drv->proc_reg);
+       if (pre_voltage < 0) {
+               dev_err(dev, "invalid vproc value: %d\n", pre_voltage);
+               ret = pre_voltage;
+               goto out_unlock;
+       }
+
+       /* scale up: set voltage first then freq. */
+       target_voltage = max(inter_voltage, voltage);
+       if (pre_voltage <= target_voltage) {
+               ret = mtk_ccifreq_set_voltage(drv, target_voltage);
+               if (ret) {
+                       dev_err(dev, "failed to scale up voltage\n");
+                       goto out_restore_voltage;
+               }
+       }
+
+       /* switch the cci clock to intermediate clock source. */
+       ret = clk_set_parent(drv->cci_clk, drv->inter_clk);
+       if (ret) {
+               dev_err(dev, "failed to re-parent cci clock\n");
+               goto out_restore_voltage;
+       }
+
+       /* set the original clock to target rate. */
+       ret = clk_set_rate(cci_pll, *freq);
+       if (ret) {
+               dev_err(dev, "failed to set cci pll rate: %d\n", ret);
+               clk_set_parent(drv->cci_clk, cci_pll);
+               goto out_restore_voltage;
+       }
+
+       /* switch the cci clock back to the original clock source. */
+       ret = clk_set_parent(drv->cci_clk, cci_pll);
+       if (ret) {
+               dev_err(dev, "failed to re-parent cci clock\n");
+               mtk_ccifreq_set_voltage(drv, inter_voltage);
+               goto out_unlock;
+       }
+
+       /*
+        * If the new voltage is lower than the intermediate voltage or the
+        * original voltage, scale down to the new voltage.
+        */
+       if (voltage < inter_voltage || voltage < pre_voltage) {
+               ret = mtk_ccifreq_set_voltage(drv, voltage);
+               if (ret) {
+                       dev_err(dev, "failed to scale down voltage\n");
+                       goto out_unlock;
+               }
+       }
+
+       drv->pre_freq = *freq;
+       mutex_unlock(&drv->reg_lock);
+
+       return 0;
+
+out_restore_voltage:
+       mtk_ccifreq_set_voltage(drv, pre_voltage);
+
+out_unlock:
+       mutex_unlock(&drv->reg_lock);
+       return ret;
+}
+
+static int mtk_ccifreq_opp_notifier(struct notifier_block *nb,
+                                   unsigned long event, void *data)
+{
+       struct dev_pm_opp *opp = data;
+       struct mtk_ccifreq_drv *drv;
+       unsigned long freq, volt;
+
+       drv = container_of(nb, struct mtk_ccifreq_drv, opp_nb);
+
+       if (event == OPP_EVENT_ADJUST_VOLTAGE) {
+               freq = dev_pm_opp_get_freq(opp);
+
+               mutex_lock(&drv->reg_lock);
+               /* current opp item is changed */
+               if (freq == drv->pre_freq) {
+                       volt = dev_pm_opp_get_voltage(opp);
+                       mtk_ccifreq_set_voltage(drv, volt);
+               }
+               mutex_unlock(&drv->reg_lock);
+       }
+
+       return 0;
+}
+
+static struct devfreq_dev_profile mtk_ccifreq_profile = {
+       .target = mtk_ccifreq_target,
+};
+
+static int mtk_ccifreq_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct mtk_ccifreq_drv *drv;
+       struct devfreq_passive_data *passive_data;
+       struct dev_pm_opp *opp;
+       unsigned long rate, opp_volt;
+       int ret;
+
+       drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
+       if (!drv)
+               return -ENOMEM;
+
+       drv->dev = dev;
+       drv->soc_data = (const struct mtk_ccifreq_platform_data *)
+                               of_device_get_match_data(&pdev->dev);
+       mutex_init(&drv->reg_lock);
+       platform_set_drvdata(pdev, drv);
+
+       drv->cci_clk = devm_clk_get(dev, "cci");
+       if (IS_ERR(drv->cci_clk)) {
+               ret = PTR_ERR(drv->cci_clk);
+               return dev_err_probe(dev, ret, "failed to get cci clk\n");
+       }
+
+       drv->inter_clk = devm_clk_get(dev, "intermediate");
+       if (IS_ERR(drv->inter_clk)) {
+               ret = PTR_ERR(drv->inter_clk);
+               return dev_err_probe(dev, ret,
+                                    "failed to get intermediate clk\n");
+       }
+
+       drv->proc_reg = devm_regulator_get_optional(dev, "proc");
+       if (IS_ERR(drv->proc_reg)) {
+               ret = PTR_ERR(drv->proc_reg);
+               return dev_err_probe(dev, ret,
+                                    "failed to get proc regulator\n");
+       }
+
+       ret = regulator_enable(drv->proc_reg);
+       if (ret) {
+               dev_err(dev, "failed to enable proc regulator\n");
+               return ret;
+       }
+
+       drv->sram_reg = devm_regulator_get_optional(dev, "sram");
+       if (IS_ERR(drv->sram_reg))
+               drv->sram_reg = NULL;
+       else {
+               ret = regulator_enable(drv->sram_reg);
+               if (ret) {
+                       dev_err(dev, "failed to enable sram regulator\n");
+                       goto out_free_resources;
+               }
+       }
+
+       /*
+        * We assume min voltage is 0 and tracking target voltage using
+        * min_volt_shift for each iteration.
+        * The retry_max is 3 times of expected iteration count.
+        */
+       drv->vtrack_max = 3 * DIV_ROUND_UP(max(drv->soc_data->sram_max_volt,
+                                              drv->soc_data->proc_max_volt),
+                                          drv->soc_data->min_volt_shift);
+
+       ret = clk_prepare_enable(drv->cci_clk);
+       if (ret)
+               goto out_free_resources;
+
+       ret = dev_pm_opp_of_add_table(dev);
+       if (ret) {
+               dev_err(dev, "failed to add opp table: %d\n", ret);
+               goto out_disable_cci_clk;
+       }
+
+       rate = clk_get_rate(drv->inter_clk);
+       opp = dev_pm_opp_find_freq_ceil(dev, &rate);
+       if (IS_ERR(opp)) {
+               ret = PTR_ERR(opp);
+               dev_err(dev, "failed to get intermediate opp: %d\n", ret);
+               goto out_remove_opp_table;
+       }
+       drv->inter_voltage = dev_pm_opp_get_voltage(opp);
+       dev_pm_opp_put(opp);
+
+       rate = U32_MAX;
+       opp = dev_pm_opp_find_freq_floor(drv->dev, &rate);
+       if (IS_ERR(opp)) {
+               dev_err(dev, "failed to get opp\n");
+               ret = PTR_ERR(opp);
+               goto out_remove_opp_table;
+       }
+
+       opp_volt = dev_pm_opp_get_voltage(opp);
+       dev_pm_opp_put(opp);
+       ret = mtk_ccifreq_set_voltage(drv, opp_volt);
+       if (ret) {
+               dev_err(dev, "failed to scale to highest voltage %lu in proc_reg\n",
+                       opp_volt);
+               goto out_remove_opp_table;
+       }
+
+       passive_data = devm_kzalloc(dev, sizeof(*passive_data), GFP_KERNEL);
+       if (!passive_data) {
+               ret = -ENOMEM;
+               goto out_remove_opp_table;
+       }
+
+       passive_data->parent_type = CPUFREQ_PARENT_DEV;
+       drv->devfreq = devm_devfreq_add_device(dev, &mtk_ccifreq_profile,
+                                              DEVFREQ_GOV_PASSIVE,
+                                              passive_data);
+       if (IS_ERR(drv->devfreq)) {
+               ret = -EPROBE_DEFER;
+               dev_err(dev, "failed to add devfreq device: %ld\n",
+                       PTR_ERR(drv->devfreq));
+               goto out_remove_opp_table;
+       }
+
+       drv->opp_nb.notifier_call = mtk_ccifreq_opp_notifier;
+       ret = dev_pm_opp_register_notifier(dev, &drv->opp_nb);
+       if (ret) {
+               dev_err(dev, "failed to register opp notifier: %d\n", ret);
+               goto out_remove_opp_table;
+       }
+       return 0;
+
+out_remove_opp_table:
+       dev_pm_opp_of_remove_table(dev);
+
+out_disable_cci_clk:
+       clk_disable_unprepare(drv->cci_clk);
+
+out_free_resources:
+       if (regulator_is_enabled(drv->proc_reg))
+               regulator_disable(drv->proc_reg);
+       if (drv->sram_reg && regulator_is_enabled(drv->sram_reg))
+               regulator_disable(drv->sram_reg);
+
+       return ret;
+}
+
+static int mtk_ccifreq_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct mtk_ccifreq_drv *drv;
+
+       drv = platform_get_drvdata(pdev);
+
+       dev_pm_opp_unregister_notifier(dev, &drv->opp_nb);
+       dev_pm_opp_of_remove_table(dev);
+       clk_disable_unprepare(drv->cci_clk);
+       regulator_disable(drv->proc_reg);
+       if (drv->sram_reg)
+               regulator_disable(drv->sram_reg);
+
+       return 0;
+}
+
+static const struct mtk_ccifreq_platform_data mt8183_platform_data = {
+       .min_volt_shift = 100000,
+       .max_volt_shift = 200000,
+       .proc_max_volt = 1150000,
+};
+
+static const struct mtk_ccifreq_platform_data mt8186_platform_data = {
+       .min_volt_shift = 100000,
+       .max_volt_shift = 250000,
+       .proc_max_volt = 1118750,
+       .sram_min_volt = 850000,
+       .sram_max_volt = 1118750,
+};
+
+static const struct of_device_id mtk_ccifreq_machines[] = {
+       { .compatible = "mediatek,mt8183-cci", .data = &mt8183_platform_data },
+       { .compatible = "mediatek,mt8186-cci", .data = &mt8186_platform_data },
+       { },
+};
+MODULE_DEVICE_TABLE(of, mtk_ccifreq_machines);
+
+static struct platform_driver mtk_ccifreq_platdrv = {
+       .probe  = mtk_ccifreq_probe,
+       .remove = mtk_ccifreq_remove,
+       .driver = {
+               .name = "mtk-ccifreq",
+               .of_match_table = mtk_ccifreq_machines,
+       },
+};
+module_platform_driver(mtk_ccifreq_platdrv);
+
+MODULE_DESCRIPTION("MediaTek CCI devfreq driver");
+MODULE_AUTHOR("Jia-Wei Chang <jia-wei.chang@mediatek.com>");
+MODULE_LICENSE("GPL v2");
index 65ecf17..585a95f 100644 (file)
@@ -922,8 +922,10 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
 
        devfreq = devm_devfreq_add_device(&pdev->dev, &tegra_devfreq_profile,
                                          "tegra_actmon", NULL);
-       if (IS_ERR(devfreq))
+       if (IS_ERR(devfreq)) {
+               dev_err(&pdev->dev, "Failed to add device: %pe\n", devfreq);
                return PTR_ERR(devfreq);
+       }
 
        return 0;
 }
index 0cce6e4..205acb2 100644 (file)
@@ -343,7 +343,7 @@ void dma_resv_replace_fences(struct dma_resv *obj, uint64_t context,
                if (old->context != context)
                        continue;
 
-               dma_resv_list_set(list, i, replacement, usage);
+               dma_resv_list_set(list, i, dma_fence_get(replacement), usage);
                dma_fence_put(old);
        }
 }
index 3e9d726..7b3e603 100644 (file)
@@ -1900,6 +1900,11 @@ static int at_xdmac_alloc_chan_resources(struct dma_chan *chan)
        for (i = 0; i < init_nr_desc_per_channel; i++) {
                desc = at_xdmac_alloc_desc(chan, GFP_KERNEL);
                if (!desc) {
+                       if (i == 0) {
+                               dev_warn(chan2dev(chan),
+                                        "can't allocate any descriptors\n");
+                               return -EIO;
+                       }
                        dev_warn(chan2dev(chan),
                                "only %d descriptors have been allocated\n", i);
                        break;
index 0a2168a..f696246 100644 (file)
@@ -675,16 +675,10 @@ static int dmatest_func(void *data)
        /*
         * src and dst buffers are freed by ourselves below
         */
-       if (params->polled) {
+       if (params->polled)
                flags = DMA_CTRL_ACK;
-       } else {
-               if (dma_has_cap(DMA_INTERRUPT, dev->cap_mask)) {
-                       flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
-               } else {
-                       pr_err("Channel does not support interrupt!\n");
-                       goto err_pq_array;
-               }
-       }
+       else
+               flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
 
        ktime = ktime_get();
        while (!(kthread_should_stop() ||
@@ -912,7 +906,6 @@ error_unmap_continue:
        runtime = ktime_to_us(ktime);
 
        ret = 0;
-err_pq_array:
        kfree(dma_pq);
 err_srcs_array:
        kfree(srcs);
index e9c9bcb..c741da0 100644 (file)
@@ -1164,8 +1164,9 @@ static int dma_chan_pause(struct dma_chan *dchan)
                        BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT;
                axi_dma_iowrite32(chan->chip, DMAC_CHEN, val);
        } else {
-               val = BIT(chan->id) << DMAC_CHAN_SUSP2_SHIFT |
-                     BIT(chan->id) << DMAC_CHAN_SUSP2_WE_SHIFT;
+               val = axi_dma_ioread32(chan->chip, DMAC_CHSUSPREG);
+               val |= BIT(chan->id) << DMAC_CHAN_SUSP2_SHIFT |
+                       BIT(chan->id) << DMAC_CHAN_SUSP2_WE_SHIFT;
                axi_dma_iowrite32(chan->chip, DMAC_CHSUSPREG, val);
        }
 
@@ -1190,12 +1191,13 @@ static inline void axi_chan_resume(struct axi_dma_chan *chan)
 {
        u32 val;
 
-       val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
        if (chan->chip->dw->hdata->reg_map_8_channels) {
+               val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
                val &= ~(BIT(chan->id) << DMAC_CHAN_SUSP_SHIFT);
                val |=  (BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT);
                axi_dma_iowrite32(chan->chip, DMAC_CHEN, val);
        } else {
+               val = axi_dma_ioread32(chan->chip, DMAC_CHSUSPREG);
                val &= ~(BIT(chan->id) << DMAC_CHAN_SUSP2_SHIFT);
                val |=  (BIT(chan->id) << DMAC_CHAN_SUSP2_WE_SHIFT);
                axi_dma_iowrite32(chan->chip, DMAC_CHSUSPREG, val);
index ff0ea60..5a8cc52 100644 (file)
@@ -716,10 +716,7 @@ static void idxd_device_wqs_clear_state(struct idxd_device *idxd)
                struct idxd_wq *wq = idxd->wqs[i];
 
                mutex_lock(&wq->wq_lock);
-               if (wq->state == IDXD_WQ_ENABLED) {
-                       idxd_wq_disable_cleanup(wq);
-                       wq->state = IDXD_WQ_DISABLED;
-               }
+               idxd_wq_disable_cleanup(wq);
                idxd_wq_device_reset_cleanup(wq);
                mutex_unlock(&wq->wq_lock);
        }
index 355fb3e..aa34782 100644 (file)
@@ -512,15 +512,16 @@ static int idxd_probe(struct idxd_device *idxd)
        dev_dbg(dev, "IDXD reset complete\n");
 
        if (IS_ENABLED(CONFIG_INTEL_IDXD_SVM) && sva) {
-               if (iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA))
+               if (iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA)) {
                        dev_warn(dev, "Unable to turn on user SVA feature.\n");
-               else
+               } else {
                        set_bit(IDXD_FLAG_USER_PASID_ENABLED, &idxd->flags);
 
-               if (idxd_enable_system_pasid(idxd))
-                       dev_warn(dev, "No in-kernel DMA with PASID.\n");
-               else
-                       set_bit(IDXD_FLAG_PASID_ENABLED, &idxd->flags);
+                       if (idxd_enable_system_pasid(idxd))
+                               dev_warn(dev, "No in-kernel DMA with PASID.\n");
+                       else
+                               set_bit(IDXD_FLAG_PASID_ENABLED, &idxd->flags);
+               }
        } else if (!sva) {
                dev_warn(dev, "User forced SVA off via module param.\n");
        }
index 8535018..f37a276 100644 (file)
@@ -891,7 +891,7 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
         * SDMA stops cyclic channel when DMA request triggers a channel and no SDMA
         * owned buffer is available (i.e. BD_DONE was set too late).
         */
-       if (!is_sdma_channel_enabled(sdmac->sdma, sdmac->channel)) {
+       if (sdmac->desc && !is_sdma_channel_enabled(sdmac->sdma, sdmac->channel)) {
                dev_warn(sdmac->sdma->dev, "restart cyclic channel %d\n", sdmac->channel);
                sdma_enable_channel(sdmac->sdma, sdmac->channel);
        }
@@ -2346,7 +2346,7 @@ MODULE_DESCRIPTION("i.MX SDMA driver");
 #if IS_ENABLED(CONFIG_SOC_IMX6Q)
 MODULE_FIRMWARE("imx/sdma/sdma-imx6q.bin");
 #endif
-#if IS_ENABLED(CONFIG_SOC_IMX7D)
+#if IS_ENABLED(CONFIG_SOC_IMX7D) || IS_ENABLED(CONFIG_SOC_IMX8M)
 MODULE_FIRMWARE("imx/sdma/sdma-imx7d.bin");
 #endif
 MODULE_LICENSE("GPL");
index efe8bd3..9b9184f 100644 (file)
@@ -1593,11 +1593,12 @@ static int intel_ldma_probe(struct platform_device *pdev)
        d->core_clk = devm_clk_get_optional(dev, NULL);
        if (IS_ERR(d->core_clk))
                return PTR_ERR(d->core_clk);
-       clk_prepare_enable(d->core_clk);
 
        d->rst = devm_reset_control_get_optional(dev, NULL);
        if (IS_ERR(d->rst))
                return PTR_ERR(d->rst);
+
+       clk_prepare_enable(d->core_clk);
        reset_control_deassert(d->rst);
 
        ret = devm_add_action_or_reset(dev, ldma_clk_disable, d);
index 858400e..09915a5 100644 (file)
@@ -2589,7 +2589,7 @@ static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch)
 
        /* If the DMAC pool is empty, alloc new */
        if (!desc) {
-               DEFINE_SPINLOCK(lock);
+               static DEFINE_SPINLOCK(lock);
                LIST_HEAD(pool);
 
                if (!add_desc(&pool, &lock, GFP_ATOMIC, 1))
index 87f6ca1..2ff787d 100644 (file)
@@ -558,14 +558,6 @@ static int bam_alloc_chan(struct dma_chan *chan)
        return 0;
 }
 
-static int bam_pm_runtime_get_sync(struct device *dev)
-{
-       if (pm_runtime_enabled(dev))
-               return pm_runtime_get_sync(dev);
-
-       return 0;
-}
-
 /**
  * bam_free_chan - Frees dma resources associated with specific channel
  * @chan: specified channel
@@ -581,7 +573,7 @@ static void bam_free_chan(struct dma_chan *chan)
        unsigned long flags;
        int ret;
 
-       ret = bam_pm_runtime_get_sync(bdev->dev);
+       ret = pm_runtime_get_sync(bdev->dev);
        if (ret < 0)
                return;
 
@@ -784,7 +776,7 @@ static int bam_pause(struct dma_chan *chan)
        unsigned long flag;
        int ret;
 
-       ret = bam_pm_runtime_get_sync(bdev->dev);
+       ret = pm_runtime_get_sync(bdev->dev);
        if (ret < 0)
                return ret;
 
@@ -810,7 +802,7 @@ static int bam_resume(struct dma_chan *chan)
        unsigned long flag;
        int ret;
 
-       ret = bam_pm_runtime_get_sync(bdev->dev);
+       ret = pm_runtime_get_sync(bdev->dev);
        if (ret < 0)
                return ret;
 
@@ -919,7 +911,7 @@ static irqreturn_t bam_dma_irq(int irq, void *data)
        if (srcs & P_IRQ)
                tasklet_schedule(&bdev->task);
 
-       ret = bam_pm_runtime_get_sync(bdev->dev);
+       ret = pm_runtime_get_sync(bdev->dev);
        if (ret < 0)
                return IRQ_NONE;
 
@@ -1037,7 +1029,7 @@ static void bam_start_dma(struct bam_chan *bchan)
        if (!vd)
                return;
 
-       ret = bam_pm_runtime_get_sync(bdev->dev);
+       ret = pm_runtime_get_sync(bdev->dev);
        if (ret < 0)
                return;
 
@@ -1374,11 +1366,6 @@ static int bam_dma_probe(struct platform_device *pdev)
        if (ret)
                goto err_unregister_dma;
 
-       if (!bdev->bamclk) {
-               pm_runtime_disable(&pdev->dev);
-               return 0;
-       }
-
        pm_runtime_irq_safe(&pdev->dev);
        pm_runtime_set_autosuspend_delay(&pdev->dev, BAM_DMA_AUTOSUSPEND_DELAY);
        pm_runtime_use_autosuspend(&pdev->dev);
@@ -1462,10 +1449,8 @@ static int __maybe_unused bam_dma_suspend(struct device *dev)
 {
        struct bam_device *bdev = dev_get_drvdata(dev);
 
-       if (bdev->bamclk) {
-               pm_runtime_force_suspend(dev);
-               clk_unprepare(bdev->bamclk);
-       }
+       pm_runtime_force_suspend(dev);
+       clk_unprepare(bdev->bamclk);
 
        return 0;
 }
@@ -1475,13 +1460,11 @@ static int __maybe_unused bam_dma_resume(struct device *dev)
        struct bam_device *bdev = dev_get_drvdata(dev);
        int ret;
 
-       if (bdev->bamclk) {
-               ret = clk_prepare(bdev->bamclk);
-               if (ret)
-                       return ret;
+       ret = clk_prepare(bdev->bamclk);
+       if (ret)
+               return ret;
 
-               pm_runtime_force_resume(dev);
-       }
+       pm_runtime_force_resume(dev);
 
        return 0;
 }
index 71d24fc..f744ddb 100644 (file)
@@ -245,6 +245,7 @@ static void *ti_dra7_xbar_route_allocate(struct of_phandle_args *dma_spec,
        if (dma_spec->args[0] >= xbar->xbar_requests) {
                dev_err(&pdev->dev, "Invalid XBAR request number: %d\n",
                        dma_spec->args[0]);
+               put_device(&pdev->dev);
                return ERR_PTR(-EINVAL);
        }
 
@@ -252,12 +253,14 @@ static void *ti_dra7_xbar_route_allocate(struct of_phandle_args *dma_spec,
        dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0);
        if (!dma_spec->np) {
                dev_err(&pdev->dev, "Can't get DMA master\n");
+               put_device(&pdev->dev);
                return ERR_PTR(-EINVAL);
        }
 
        map = kzalloc(sizeof(*map), GFP_KERNEL);
        if (!map) {
                of_node_put(dma_spec->np);
+               put_device(&pdev->dev);
                return ERR_PTR(-ENOMEM);
        }
 
@@ -268,6 +271,8 @@ static void *ti_dra7_xbar_route_allocate(struct of_phandle_args *dma_spec,
                mutex_unlock(&xbar->mutex);
                dev_err(&pdev->dev, "Run out of free DMA requests\n");
                kfree(map);
+               of_node_put(dma_spec->np);
+               put_device(&pdev->dev);
                return ERR_PTR(-ENOMEM);
        }
        set_bit(map->xbar_out, xbar->dma_inuse);
index 59b0bed..c8fa7dc 100644 (file)
@@ -103,9 +103,14 @@ static void dimm_setup_label(struct dimm_info *dimm, u16 handle)
 
        dmi_memdev_name(handle, &bank, &device);
 
-       /* both strings must be non-zero */
-       if (bank && *bank && device && *device)
-               snprintf(dimm->label, sizeof(dimm->label), "%s %s", bank, device);
+       /*
+        * Set to a NULL string when both bank and device are zero. In this case,
+        * the label assigned by default will be preserved.
+        */
+       snprintf(dimm->label, sizeof(dimm->label), "%s%s%s",
+                (bank && *bank) ? bank : "",
+                (bank && *bank && device && *device) ? " " : "",
+                (device && *device) ? device : "");
 }
 
 static void assign_dmi_dimm_info(struct dimm_info *dimm, struct memdev_dmi_entry *entry)
index 1cee64b..f7d37c2 100644 (file)
@@ -514,6 +514,28 @@ static void handle_error(struct mem_ctl_info *mci, struct synps_ecc_status *p)
        memset(p, 0, sizeof(*p));
 }
 
+static void enable_intr(struct synps_edac_priv *priv)
+{
+       /* Enable UE/CE Interrupts */
+       if (priv->p_data->quirks & DDR_ECC_INTR_SELF_CLEAR)
+               writel(DDR_UE_MASK | DDR_CE_MASK,
+                      priv->baseaddr + ECC_CLR_OFST);
+       else
+               writel(DDR_QOSUE_MASK | DDR_QOSCE_MASK,
+                      priv->baseaddr + DDR_QOS_IRQ_EN_OFST);
+
+}
+
+static void disable_intr(struct synps_edac_priv *priv)
+{
+       /* Disable UE/CE Interrupts */
+       if (priv->p_data->quirks & DDR_ECC_INTR_SELF_CLEAR)
+               writel(0x0, priv->baseaddr + ECC_CLR_OFST);
+       else
+               writel(DDR_QOSUE_MASK | DDR_QOSCE_MASK,
+                      priv->baseaddr + DDR_QOS_IRQ_DB_OFST);
+}
+
 /**
  * intr_handler - Interrupt Handler for ECC interrupts.
  * @irq:        IRQ number.
@@ -555,6 +577,9 @@ static irqreturn_t intr_handler(int irq, void *dev_id)
        /* v3.0 of the controller does not have this register */
        if (!(priv->p_data->quirks & DDR_ECC_INTR_SELF_CLEAR))
                writel(regval, priv->baseaddr + DDR_QOS_IRQ_STAT_OFST);
+       else
+               enable_intr(priv);
+
        return IRQ_HANDLED;
 }
 
@@ -837,25 +862,6 @@ static void mc_init(struct mem_ctl_info *mci, struct platform_device *pdev)
        init_csrows(mci);
 }
 
-static void enable_intr(struct synps_edac_priv *priv)
-{
-       /* Enable UE/CE Interrupts */
-       if (priv->p_data->quirks & DDR_ECC_INTR_SELF_CLEAR)
-               writel(DDR_UE_MASK | DDR_CE_MASK,
-                      priv->baseaddr + ECC_CLR_OFST);
-       else
-               writel(DDR_QOSUE_MASK | DDR_QOSCE_MASK,
-                      priv->baseaddr + DDR_QOS_IRQ_EN_OFST);
-
-}
-
-static void disable_intr(struct synps_edac_priv *priv)
-{
-       /* Disable UE/CE Interrupts */
-       writel(DDR_QOSUE_MASK | DDR_QOSCE_MASK,
-                       priv->baseaddr + DDR_QOS_IRQ_DB_OFST);
-}
-
 static int setup_irq(struct mem_ctl_info *mci,
                     struct platform_device *pdev)
 {
index 1e7b7fe..a14f654 100644 (file)
@@ -149,4 +149,16 @@ config ARM_SCMI_POWER_DOMAIN
          will be called scmi_pm_domain. Note this may needed early in boot
          before rootfs may be available.
 
+config ARM_SCMI_POWER_CONTROL
+       tristate "SCMI system power control driver"
+       depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
+       help
+         This enables System Power control logic which binds system shutdown or
+         reboot actions to SCMI System Power notifications generated by SCP
+         firmware.
+
+         This driver can also be built as a module.  If so, the module will be
+         called scmi_power_control. Note this may needed early in boot to catch
+         early shutdown/reboot SCMI requests.
+
 endmenu
index 8d4afad..9ea86f8 100644 (file)
@@ -7,11 +7,12 @@ scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_SMC) += smc.o
 scmi-transport-$(CONFIG_ARM_SCMI_HAVE_MSG) += msg.o
 scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_VIRTIO) += virtio.o
 scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_OPTEE) += optee.o
-scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o system.o voltage.o
+scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o system.o voltage.o powercap.o
 scmi-module-objs := $(scmi-bus-y) $(scmi-driver-y) $(scmi-protocols-y) \
                    $(scmi-transport-y)
 obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-module.o
 obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o
+obj-$(CONFIG_ARM_SCMI_POWER_CONTROL) += scmi_power_control.o
 
 ifeq ($(CONFIG_THUMB2_KERNEL)$(CONFIG_CC_IS_CLANG),yy)
 # The use of R7 in the SMCCC conflicts with the compiler's use of R7 as a frame
index 20fba73..a52f084 100644 (file)
@@ -36,7 +36,7 @@ struct scmi_msg_resp_base_attributes {
 
 struct scmi_msg_resp_base_discover_agent {
        __le32 agent_id;
-       u8 name[SCMI_MAX_STR_SIZE];
+       u8 name[SCMI_SHORT_NAME_MAX_SIZE];
 };
 
 
@@ -119,7 +119,7 @@ scmi_base_vendor_id_get(const struct scmi_protocol_handle *ph, bool sub_vendor)
 
        ret = ph->xops->do_xfer(ph, t);
        if (!ret)
-               memcpy(vendor_id, t->rx.buf, size);
+               strscpy(vendor_id, t->rx.buf, size);
 
        ph->xops->xfer_put(ph, t);
 
@@ -221,11 +221,17 @@ scmi_base_implementation_list_get(const struct scmi_protocol_handle *ph,
                calc_list_sz = (1 + (loop_num_ret - 1) / sizeof(u32)) *
                                sizeof(u32);
                if (calc_list_sz != real_list_sz) {
-                       dev_err(dev,
-                               "Malformed reply - real_sz:%zd  calc_sz:%u\n",
-                               real_list_sz, calc_list_sz);
-                       ret = -EPROTO;
-                       break;
+                       dev_warn(dev,
+                                "Malformed reply - real_sz:%zd  calc_sz:%u  (loop_num_ret:%d)\n",
+                                real_list_sz, calc_list_sz, loop_num_ret);
+                       /*
+                        * Bail out if the expected list size is bigger than the
+                        * total payload size of the received reply.
+                        */
+                       if (calc_list_sz > real_list_sz) {
+                               ret = -EPROTO;
+                               break;
+                       }
                }
 
                for (loop = 0; loop < loop_num_ret; loop++)
@@ -270,7 +276,7 @@ static int scmi_base_discover_agent_get(const struct scmi_protocol_handle *ph,
        ret = ph->xops->do_xfer(ph, t);
        if (!ret) {
                agent_info = t->rx.buf;
-               strlcpy(name, agent_info->name, SCMI_MAX_STR_SIZE);
+               strscpy(name, agent_info->name, SCMI_SHORT_NAME_MAX_SIZE);
        }
 
        ph->xops->xfer_put(ph, t);
@@ -369,7 +375,7 @@ static int scmi_base_protocol_init(const struct scmi_protocol_handle *ph)
        int id, ret;
        u8 *prot_imp;
        u32 version;
-       char name[SCMI_MAX_STR_SIZE];
+       char name[SCMI_SHORT_NAME_MAX_SIZE];
        struct device *dev = ph->dev;
        struct scmi_revision_info *rev = scmi_revision_area_get(ph);
 
index f6fe723..d4e2310 100644 (file)
@@ -181,7 +181,7 @@ scmi_device_create(struct device_node *np, struct device *parent, int protocol,
                return NULL;
        }
 
-       id = ida_simple_get(&scmi_bus_id, 1, 0, GFP_KERNEL);
+       id = ida_alloc_min(&scmi_bus_id, 1, GFP_KERNEL);
        if (id < 0) {
                kfree_const(scmi_dev->name);
                kfree(scmi_dev);
@@ -204,7 +204,7 @@ scmi_device_create(struct device_node *np, struct device *parent, int protocol,
 put_dev:
        kfree_const(scmi_dev->name);
        put_device(&scmi_dev->dev);
-       ida_simple_remove(&scmi_bus_id, id);
+       ida_free(&scmi_bus_id, id);
        return NULL;
 }
 
@@ -212,7 +212,7 @@ void scmi_device_destroy(struct scmi_device *scmi_dev)
 {
        kfree_const(scmi_dev->name);
        scmi_handle_put(scmi_dev->handle);
-       ida_simple_remove(&scmi_bus_id, scmi_dev->id);
+       ida_free(&scmi_bus_id, scmi_dev->id);
        device_unregister(&scmi_dev->dev);
 }
 
index 4d36a9a..3ed7ae0 100644 (file)
@@ -153,7 +153,7 @@ static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,
        if (!ret) {
                u32 latency = 0;
                attributes = le32_to_cpu(attr->attributes);
-               strlcpy(clk->name, attr->name, SCMI_MAX_STR_SIZE);
+               strscpy(clk->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE);
                /* clock_enable_latency field is present only since SCMI v3.1 */
                if (PROTOCOL_REV_MAJOR(version) >= 0x2)
                        latency = le32_to_cpu(attr->clock_enable_latency);
@@ -194,6 +194,7 @@ static int rate_cmp_func(const void *_r1, const void *_r2)
 }
 
 struct scmi_clk_ipriv {
+       struct device *dev;
        u32 clk_id;
        struct scmi_clock_info *clk;
 };
@@ -223,6 +224,29 @@ iter_clk_describe_update_state(struct scmi_iterator_state *st,
        st->num_returned = NUM_RETURNED(flags);
        p->clk->rate_discrete = RATE_DISCRETE(flags);
 
+       /* Warn about out of spec replies ... */
+       if (!p->clk->rate_discrete &&
+           (st->num_returned != 3 || st->num_remaining != 0)) {
+               dev_warn(p->dev,
+                        "Out-of-spec CLOCK_DESCRIBE_RATES reply for %s - returned:%d remaining:%d rx_len:%zd\n",
+                        p->clk->name, st->num_returned, st->num_remaining,
+                        st->rx_len);
+
+               /*
+                * A known quirk: a triplet is returned but num_returned != 3
+                * Check for a safe payload size and fix.
+                */
+               if (st->num_returned != 3 && st->num_remaining == 0 &&
+                   st->rx_len == sizeof(*r) + sizeof(__le32) * 2 * 3) {
+                       st->num_returned = 3;
+                       st->num_remaining = 0;
+               } else {
+                       dev_err(p->dev,
+                               "Cannot fix out-of-spec reply !\n");
+                       return -EPROTO;
+               }
+       }
+
        return 0;
 }
 
@@ -255,7 +279,6 @@ iter_clk_describe_process_response(const struct scmi_protocol_handle *ph,
 
                *rate = RATE_TO_U64(r->rate[st->loop_idx]);
                p->clk->list.num_rates++;
-               //XXX dev_dbg(ph->dev, "Rate %llu Hz\n", *rate);
        }
 
        return ret;
@@ -266,9 +289,7 @@ scmi_clock_describe_rates_get(const struct scmi_protocol_handle *ph, u32 clk_id,
                              struct scmi_clock_info *clk)
 {
        int ret;
-
        void *iter;
-       struct scmi_msg_clock_describe_rates *msg;
        struct scmi_iterator_ops ops = {
                .prepare_message = iter_clk_describe_prepare_message,
                .update_state = iter_clk_describe_update_state,
@@ -277,11 +298,13 @@ scmi_clock_describe_rates_get(const struct scmi_protocol_handle *ph, u32 clk_id,
        struct scmi_clk_ipriv cpriv = {
                .clk_id = clk_id,
                .clk = clk,
+               .dev = ph->dev,
        };
 
        iter = ph->hops->iter_response_init(ph, &ops, SCMI_MAX_NUM_RATES,
                                            CLOCK_DESCRIBE_RATES,
-                                           sizeof(*msg), &cpriv);
+                                           sizeof(struct scmi_msg_clock_describe_rates),
+                                           &cpriv);
        if (IS_ERR(iter))
                return PTR_ERR(iter);
 
index c1922bd..609ebed 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/export.h>
 #include <linux/idr.h>
 #include <linux/io.h>
+#include <linux/io-64-nonatomic-hi-lo.h>
 #include <linux/kernel.h>
 #include <linux/ktime.h>
 #include <linux/hashtable.h>
@@ -60,6 +61,11 @@ static atomic_t transfer_last_id;
 static DEFINE_IDR(scmi_requested_devices);
 static DEFINE_MUTEX(scmi_requested_devices_mtx);
 
+/* Track globally the creation of SCMI SystemPower related devices */
+static bool scmi_syspower_registered;
+/* Protect access to scmi_syspower_registered */
+static DEFINE_MUTEX(scmi_syspower_mtx);
+
 struct scmi_requested_dev {
        const struct scmi_device_id *id_table;
        struct list_head node;
@@ -660,6 +666,11 @@ static void scmi_handle_notification(struct scmi_chan_info *cinfo,
                smp_store_mb(xfer->priv, priv);
        info->desc->ops->fetch_notification(cinfo, info->desc->max_msg_size,
                                            xfer);
+
+       trace_scmi_msg_dump(xfer->hdr.protocol_id, xfer->hdr.id, "NOTI",
+                           xfer->hdr.seq, xfer->hdr.status,
+                           xfer->rx.buf, xfer->rx.len);
+
        scmi_notify(cinfo->handle, xfer->hdr.protocol_id,
                    xfer->hdr.id, xfer->rx.buf, xfer->rx.len, ts);
 
@@ -694,6 +705,12 @@ static void scmi_handle_response(struct scmi_chan_info *cinfo,
                smp_store_mb(xfer->priv, priv);
        info->desc->ops->fetch_response(cinfo, xfer);
 
+       trace_scmi_msg_dump(xfer->hdr.protocol_id, xfer->hdr.id,
+                           xfer->hdr.type == MSG_TYPE_DELAYED_RESP ?
+                           "DLYD" : "RESP",
+                           xfer->hdr.seq, xfer->hdr.status,
+                           xfer->rx.buf, xfer->rx.len);
+
        trace_scmi_rx_done(xfer->transfer_id, xfer->hdr.id,
                           xfer->hdr.protocol_id, xfer->hdr.seq,
                           xfer->hdr.type);
@@ -827,6 +844,12 @@ static int scmi_wait_for_message_response(struct scmi_chan_info *cinfo,
                                xfer->state = SCMI_XFER_RESP_OK;
                        }
                        spin_unlock_irqrestore(&xfer->lock, flags);
+
+                       /* Trace polled replies. */
+                       trace_scmi_msg_dump(xfer->hdr.protocol_id, xfer->hdr.id,
+                                           "RESP",
+                                           xfer->hdr.seq, xfer->hdr.status,
+                                           xfer->rx.buf, xfer->rx.len);
                }
        } else {
                /* And we wait for the response. */
@@ -903,6 +926,10 @@ static int do_xfer(const struct scmi_protocol_handle *ph,
                return ret;
        }
 
+       trace_scmi_msg_dump(xfer->hdr.protocol_id, xfer->hdr.id, "CMND",
+                           xfer->hdr.seq, xfer->hdr.status,
+                           xfer->tx.buf, xfer->tx.len);
+
        ret = scmi_wait_for_message_response(cinfo, xfer);
        if (!ret && xfer->hdr.status)
                ret = scmi_to_linux_errno(xfer->hdr.status);
@@ -1223,6 +1250,7 @@ static int scmi_iterator_run(void *iter)
                if (ret)
                        break;
 
+               st->rx_len = i->t->rx.len;
                ret = iops->update_state(st, i->resp, i->priv);
                if (ret)
                        break;
@@ -1258,10 +1286,174 @@ out:
        return ret;
 }
 
+struct scmi_msg_get_fc_info {
+       __le32 domain;
+       __le32 message_id;
+};
+
+struct scmi_msg_resp_desc_fc {
+       __le32 attr;
+#define SUPPORTS_DOORBELL(x)           ((x) & BIT(0))
+#define DOORBELL_REG_WIDTH(x)          FIELD_GET(GENMASK(2, 1), (x))
+       __le32 rate_limit;
+       __le32 chan_addr_low;
+       __le32 chan_addr_high;
+       __le32 chan_size;
+       __le32 db_addr_low;
+       __le32 db_addr_high;
+       __le32 db_set_lmask;
+       __le32 db_set_hmask;
+       __le32 db_preserve_lmask;
+       __le32 db_preserve_hmask;
+};
+
+static void
+scmi_common_fastchannel_init(const struct scmi_protocol_handle *ph,
+                            u8 describe_id, u32 message_id, u32 valid_size,
+                            u32 domain, void __iomem **p_addr,
+                            struct scmi_fc_db_info **p_db)
+{
+       int ret;
+       u32 flags;
+       u64 phys_addr;
+       u8 size;
+       void __iomem *addr;
+       struct scmi_xfer *t;
+       struct scmi_fc_db_info *db = NULL;
+       struct scmi_msg_get_fc_info *info;
+       struct scmi_msg_resp_desc_fc *resp;
+       const struct scmi_protocol_instance *pi = ph_to_pi(ph);
+
+       if (!p_addr) {
+               ret = -EINVAL;
+               goto err_out;
+       }
+
+       ret = ph->xops->xfer_get_init(ph, describe_id,
+                                     sizeof(*info), sizeof(*resp), &t);
+       if (ret)
+               goto err_out;
+
+       info = t->tx.buf;
+       info->domain = cpu_to_le32(domain);
+       info->message_id = cpu_to_le32(message_id);
+
+       /*
+        * Bail out on error leaving fc_info addresses zeroed; this includes
+        * the case in which the requested domain/message_id does NOT support
+        * fastchannels at all.
+        */
+       ret = ph->xops->do_xfer(ph, t);
+       if (ret)
+               goto err_xfer;
+
+       resp = t->rx.buf;
+       flags = le32_to_cpu(resp->attr);
+       size = le32_to_cpu(resp->chan_size);
+       if (size != valid_size) {
+               ret = -EINVAL;
+               goto err_xfer;
+       }
+
+       phys_addr = le32_to_cpu(resp->chan_addr_low);
+       phys_addr |= (u64)le32_to_cpu(resp->chan_addr_high) << 32;
+       addr = devm_ioremap(ph->dev, phys_addr, size);
+       if (!addr) {
+               ret = -EADDRNOTAVAIL;
+               goto err_xfer;
+       }
+
+       *p_addr = addr;
+
+       if (p_db && SUPPORTS_DOORBELL(flags)) {
+               db = devm_kzalloc(ph->dev, sizeof(*db), GFP_KERNEL);
+               if (!db) {
+                       ret = -ENOMEM;
+                       goto err_db;
+               }
+
+               size = 1 << DOORBELL_REG_WIDTH(flags);
+               phys_addr = le32_to_cpu(resp->db_addr_low);
+               phys_addr |= (u64)le32_to_cpu(resp->db_addr_high) << 32;
+               addr = devm_ioremap(ph->dev, phys_addr, size);
+               if (!addr) {
+                       ret = -EADDRNOTAVAIL;
+                       goto err_db_mem;
+               }
+
+               db->addr = addr;
+               db->width = size;
+               db->set = le32_to_cpu(resp->db_set_lmask);
+               db->set |= (u64)le32_to_cpu(resp->db_set_hmask) << 32;
+               db->mask = le32_to_cpu(resp->db_preserve_lmask);
+               db->mask |= (u64)le32_to_cpu(resp->db_preserve_hmask) << 32;
+
+               *p_db = db;
+       }
+
+       ph->xops->xfer_put(ph, t);
+
+       dev_dbg(ph->dev,
+               "Using valid FC for protocol %X [MSG_ID:%u / RES_ID:%u]\n",
+               pi->proto->id, message_id, domain);
+
+       return;
+
+err_db_mem:
+       devm_kfree(ph->dev, db);
+
+err_db:
+       *p_addr = NULL;
+
+err_xfer:
+       ph->xops->xfer_put(ph, t);
+
+err_out:
+       dev_warn(ph->dev,
+                "Failed to get FC for protocol %X [MSG_ID:%u / RES_ID:%u] - ret:%d. Using regular messaging.\n",
+                pi->proto->id, message_id, domain, ret);
+}
+
+#define SCMI_PROTO_FC_RING_DB(w)                       \
+do {                                                   \
+       u##w val = 0;                                   \
+                                                       \
+       if (db->mask)                                   \
+               val = ioread##w(db->addr) & db->mask;   \
+       iowrite##w((u##w)db->set | val, db->addr);      \
+} while (0)
+
+static void scmi_common_fastchannel_db_ring(struct scmi_fc_db_info *db)
+{
+       if (!db || !db->addr)
+               return;
+
+       if (db->width == 1)
+               SCMI_PROTO_FC_RING_DB(8);
+       else if (db->width == 2)
+               SCMI_PROTO_FC_RING_DB(16);
+       else if (db->width == 4)
+               SCMI_PROTO_FC_RING_DB(32);
+       else /* db->width == 8 */
+#ifdef CONFIG_64BIT
+               SCMI_PROTO_FC_RING_DB(64);
+#else
+       {
+               u64 val = 0;
+
+               if (db->mask)
+                       val = ioread64_hi_lo(db->addr) & db->mask;
+               iowrite64_hi_lo(db->set | val, db->addr);
+       }
+#endif
+}
+
 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,
+       .fastchannel_init = scmi_common_fastchannel_init,
+       .fastchannel_db_ring = scmi_common_fastchannel_db_ring,
 };
 
 /**
@@ -1496,6 +1688,30 @@ static void scmi_devm_release_protocol(struct device *dev, void *res)
        scmi_protocol_release(dres->handle, dres->protocol_id);
 }
 
+static struct scmi_protocol_instance __must_check *
+scmi_devres_protocol_instance_get(struct scmi_device *sdev, u8 protocol_id)
+{
+       struct scmi_protocol_instance *pi;
+       struct scmi_protocol_devres *dres;
+
+       dres = devres_alloc(scmi_devm_release_protocol,
+                           sizeof(*dres), GFP_KERNEL);
+       if (!dres)
+               return ERR_PTR(-ENOMEM);
+
+       pi = scmi_get_protocol_instance(sdev->handle, protocol_id);
+       if (IS_ERR(pi)) {
+               devres_free(dres);
+               return pi;
+       }
+
+       dres->handle = sdev->handle;
+       dres->protocol_id = protocol_id;
+       devres_add(&sdev->dev, dres);
+
+       return pi;
+}
+
 /**
  * scmi_devm_protocol_get  - Devres managed get protocol operations and handle
  * @sdev: A reference to an scmi_device whose embedded struct device is to
@@ -1519,32 +1735,47 @@ scmi_devm_protocol_get(struct scmi_device *sdev, u8 protocol_id,
                       struct scmi_protocol_handle **ph)
 {
        struct scmi_protocol_instance *pi;
-       struct scmi_protocol_devres *dres;
-       struct scmi_handle *handle = sdev->handle;
 
        if (!ph)
                return ERR_PTR(-EINVAL);
 
-       dres = devres_alloc(scmi_devm_release_protocol,
-                           sizeof(*dres), GFP_KERNEL);
-       if (!dres)
-               return ERR_PTR(-ENOMEM);
-
-       pi = scmi_get_protocol_instance(handle, protocol_id);
-       if (IS_ERR(pi)) {
-               devres_free(dres);
+       pi = scmi_devres_protocol_instance_get(sdev, protocol_id);
+       if (IS_ERR(pi))
                return pi;
-       }
-
-       dres->handle = handle;
-       dres->protocol_id = protocol_id;
-       devres_add(&sdev->dev, dres);
 
        *ph = &pi->ph;
 
        return pi->proto->ops;
 }
 
+/**
+ * scmi_devm_protocol_acquire  - Devres managed helper to get hold of a protocol
+ * @sdev: A reference to an scmi_device whose embedded struct device is to
+ *       be used for devres accounting.
+ * @protocol_id: The protocol being requested.
+ *
+ * Get hold of a protocol accounting for its usage, possibly triggering its
+ * initialization but without getting access to its protocol specific operations
+ * and handle.
+ *
+ * Being a devres based managed method, protocol hold will be automatically
+ * released, and possibly de-initialized on last user, once the SCMI driver
+ * owning the scmi_device is unbound from it.
+ *
+ * Return: 0 on SUCCESS
+ */
+static int __must_check scmi_devm_protocol_acquire(struct scmi_device *sdev,
+                                                  u8 protocol_id)
+{
+       struct scmi_protocol_instance *pi;
+
+       pi = scmi_devres_protocol_instance_get(sdev, protocol_id);
+       if (IS_ERR(pi))
+               return PTR_ERR(pi);
+
+       return 0;
+}
+
 static int scmi_devm_protocol_match(struct device *dev, void *res, void *data)
 {
        struct scmi_protocol_devres *dres = res;
@@ -1848,21 +2079,39 @@ scmi_get_protocol_device(struct device_node *np, struct scmi_info *info,
        if (sdev)
                return sdev;
 
+       mutex_lock(&scmi_syspower_mtx);
+       if (prot_id == SCMI_PROTOCOL_SYSTEM && scmi_syspower_registered) {
+               dev_warn(info->dev,
+                        "SCMI SystemPower protocol device must be unique !\n");
+               mutex_unlock(&scmi_syspower_mtx);
+
+               return NULL;
+       }
+
        pr_debug("Creating SCMI device (%s) for protocol %x\n", name, prot_id);
 
        sdev = scmi_device_create(np, info->dev, prot_id, name);
        if (!sdev) {
                dev_err(info->dev, "failed to create %d protocol device\n",
                        prot_id);
+               mutex_unlock(&scmi_syspower_mtx);
+
                return NULL;
        }
 
        if (scmi_txrx_setup(info, &sdev->dev, prot_id)) {
                dev_err(&sdev->dev, "failed to setup transport\n");
                scmi_device_destroy(sdev);
+               mutex_unlock(&scmi_syspower_mtx);
+
                return NULL;
        }
 
+       if (prot_id == SCMI_PROTOCOL_SYSTEM)
+               scmi_syspower_registered = true;
+
+       mutex_unlock(&scmi_syspower_mtx);
+
        return sdev;
 }
 
@@ -2131,6 +2380,7 @@ static int scmi_probe(struct platform_device *pdev)
        handle = &info->handle;
        handle->dev = info->dev;
        handle->version = &info->version;
+       handle->devm_protocol_acquire = scmi_devm_protocol_acquire;
        handle->devm_protocol_get = scmi_devm_protocol_get;
        handle->devm_protocol_put = scmi_devm_protocol_put;
 
@@ -2400,6 +2650,7 @@ static int __init scmi_driver_init(void)
        scmi_sensors_register();
        scmi_voltage_register();
        scmi_system_register();
+       scmi_powercap_register();
 
        return platform_driver_register(&scmi_driver);
 }
@@ -2416,6 +2667,7 @@ static void __exit scmi_driver_exit(void)
        scmi_sensors_unregister();
        scmi_voltage_unregister();
        scmi_system_unregister();
+       scmi_powercap_unregister();
 
        scmi_bus_exit();
 
index b503c22..8abace5 100644 (file)
@@ -117,6 +117,7 @@ struct scmi_optee_channel {
        u32 channel_id;
        u32 tee_session;
        u32 caps;
+       u32 rx_len;
        struct mutex mu;
        struct scmi_chan_info *cinfo;
        union {
@@ -302,6 +303,9 @@ static int invoke_process_msg_channel(struct scmi_optee_channel *channel, size_t
                return -EIO;
        }
 
+       /* Save response size */
+       channel->rx_len = param[2].u.memref.size;
+
        return 0;
 }
 
@@ -353,6 +357,7 @@ static int setup_dynamic_shmem(struct device *dev, struct scmi_optee_channel *ch
        shbuf = tee_shm_get_va(channel->tee_shm, 0);
        memset(shbuf, 0, msg_size);
        channel->req.msg = shbuf;
+       channel->rx_len = msg_size;
 
        return 0;
 }
@@ -508,7 +513,7 @@ static void scmi_optee_fetch_response(struct scmi_chan_info *cinfo,
        struct scmi_optee_channel *channel = cinfo->transport_info;
 
        if (channel->tee_shm)
-               msg_fetch_response(channel->req.msg, SCMI_OPTEE_MAX_MSG_SIZE, xfer);
+               msg_fetch_response(channel->req.msg, channel->rx_len, xfer);
        else
                shmem_fetch_response(channel->req.shmem, xfer);
 }
index 8f4051a..ecf5c4d 100644 (file)
 #include <linux/bits.h>
 #include <linux/of.h>
 #include <linux/io.h>
-#include <linux/io-64-nonatomic-hi-lo.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/pm_opp.h>
 #include <linux/scmi_protocol.h>
 #include <linux/sort.h>
 
+#include <trace/events/scmi.h>
+
 #include "protocols.h"
 #include "notify.h"
 
@@ -35,6 +36,12 @@ enum scmi_performance_protocol_cmd {
        PERF_DOMAIN_NAME_GET = 0xc,
 };
 
+enum {
+       PERF_FC_LEVEL,
+       PERF_FC_LIMIT,
+       PERF_FC_MAX,
+};
+
 struct scmi_opp {
        u32 perf;
        u32 power;
@@ -115,43 +122,6 @@ struct scmi_msg_resp_perf_describe_levels {
        } opp[];
 };
 
-struct scmi_perf_get_fc_info {
-       __le32 domain;
-       __le32 message_id;
-};
-
-struct scmi_msg_resp_perf_desc_fc {
-       __le32 attr;
-#define SUPPORTS_DOORBELL(x)           ((x) & BIT(0))
-#define DOORBELL_REG_WIDTH(x)          FIELD_GET(GENMASK(2, 1), (x))
-       __le32 rate_limit;
-       __le32 chan_addr_low;
-       __le32 chan_addr_high;
-       __le32 chan_size;
-       __le32 db_addr_low;
-       __le32 db_addr_high;
-       __le32 db_set_lmask;
-       __le32 db_set_hmask;
-       __le32 db_preserve_lmask;
-       __le32 db_preserve_hmask;
-};
-
-struct scmi_fc_db_info {
-       int width;
-       u64 set;
-       u64 mask;
-       void __iomem *addr;
-};
-
-struct scmi_fc_info {
-       void __iomem *level_set_addr;
-       void __iomem *limit_set_addr;
-       void __iomem *level_get_addr;
-       void __iomem *limit_get_addr;
-       struct scmi_fc_db_info *level_set_db;
-       struct scmi_fc_db_info *limit_set_db;
-};
-
 struct perf_dom_info {
        bool set_limits;
        bool set_perf;
@@ -170,8 +140,7 @@ struct perf_dom_info {
 struct scmi_perf_info {
        u32 version;
        int num_domains;
-       bool power_scale_mw;
-       bool power_scale_uw;
+       enum scmi_power_scale power_scale;
        u64 stats_addr;
        u32 stats_size;
        struct perf_dom_info *dom_info;
@@ -201,9 +170,13 @@ static int scmi_perf_attributes_get(const struct scmi_protocol_handle *ph,
                u16 flags = le16_to_cpu(attr->flags);
 
                pi->num_domains = le16_to_cpu(attr->num_domains);
-               pi->power_scale_mw = POWER_SCALE_IN_MILLIWATT(flags);
+
+               if (POWER_SCALE_IN_MILLIWATT(flags))
+                       pi->power_scale = SCMI_POWER_MILLIWATTS;
                if (PROTOCOL_REV_MAJOR(pi->version) >= 0x3)
-                       pi->power_scale_uw = POWER_SCALE_IN_MICROWATT(flags);
+                       if (POWER_SCALE_IN_MICROWATT(flags))
+                               pi->power_scale = SCMI_POWER_MICROWATTS;
+
                pi->stats_addr = le32_to_cpu(attr->stats_addr_low) |
                                (u64)le32_to_cpu(attr->stats_addr_high) << 32;
                pi->stats_size = le32_to_cpu(attr->stats_size);
@@ -252,7 +225,7 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
                        dom_info->mult_factor =
                                        (dom_info->sustained_freq_khz * 1000) /
                                        dom_info->sustained_perf_level;
-               strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE);
+               strscpy(dom_info->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE);
        }
 
        ph->xops->xfer_put(ph, t);
@@ -332,7 +305,6 @@ scmi_perf_describe_levels_get(const struct scmi_protocol_handle *ph, u32 domain,
 {
        int ret;
        void *iter;
-       struct scmi_msg_perf_describe_levels *msg;
        struct scmi_iterator_ops ops = {
                .prepare_message = iter_perf_levels_prepare_message,
                .update_state = iter_perf_levels_update_state,
@@ -345,7 +317,8 @@ scmi_perf_describe_levels_get(const struct scmi_protocol_handle *ph, u32 domain,
 
        iter = ph->hops->iter_response_init(ph, &ops, MAX_OPPS,
                                            PERF_DESCRIBE_LEVELS,
-                                           sizeof(*msg), &ppriv);
+                                           sizeof(struct scmi_msg_perf_describe_levels),
+                                           &ppriv);
        if (IS_ERR(iter))
                return PTR_ERR(iter);
 
@@ -360,40 +333,6 @@ scmi_perf_describe_levels_get(const struct scmi_protocol_handle *ph, u32 domain,
        return ret;
 }
 
-#define SCMI_PERF_FC_RING_DB(w)                                \
-do {                                                   \
-       u##w val = 0;                                   \
-                                                       \
-       if (db->mask)                                   \
-               val = ioread##w(db->addr) & db->mask;   \
-       iowrite##w((u##w)db->set | val, db->addr);      \
-} while (0)
-
-static void scmi_perf_fc_ring_db(struct scmi_fc_db_info *db)
-{
-       if (!db || !db->addr)
-               return;
-
-       if (db->width == 1)
-               SCMI_PERF_FC_RING_DB(8);
-       else if (db->width == 2)
-               SCMI_PERF_FC_RING_DB(16);
-       else if (db->width == 4)
-               SCMI_PERF_FC_RING_DB(32);
-       else /* db->width == 8 */
-#ifdef CONFIG_64BIT
-               SCMI_PERF_FC_RING_DB(64);
-#else
-       {
-               u64 val = 0;
-
-               if (db->mask)
-                       val = ioread64_hi_lo(db->addr) & db->mask;
-               iowrite64_hi_lo(db->set | val, db->addr);
-       }
-#endif
-}
-
 static int scmi_perf_mb_limits_set(const struct scmi_protocol_handle *ph,
                                   u32 domain, u32 max_perf, u32 min_perf)
 {
@@ -426,10 +365,14 @@ static int scmi_perf_limits_set(const struct scmi_protocol_handle *ph,
        if (PROTOCOL_REV_MAJOR(pi->version) >= 0x3 && !max_perf && !min_perf)
                return -EINVAL;
 
-       if (dom->fc_info && dom->fc_info->limit_set_addr) {
-               iowrite32(max_perf, dom->fc_info->limit_set_addr);
-               iowrite32(min_perf, dom->fc_info->limit_set_addr + 4);
-               scmi_perf_fc_ring_db(dom->fc_info->limit_set_db);
+       if (dom->fc_info && dom->fc_info[PERF_FC_LIMIT].set_addr) {
+               struct scmi_fc_info *fci = &dom->fc_info[PERF_FC_LIMIT];
+
+               trace_scmi_fc_call(SCMI_PROTOCOL_PERF, PERF_LIMITS_SET,
+                                  domain, min_perf, max_perf);
+               iowrite32(max_perf, fci->set_addr);
+               iowrite32(min_perf, fci->set_addr + 4);
+               ph->hops->fastchannel_db_ring(fci->set_db);
                return 0;
        }
 
@@ -468,9 +411,13 @@ static int scmi_perf_limits_get(const struct scmi_protocol_handle *ph,
        struct scmi_perf_info *pi = ph->get_priv(ph);
        struct perf_dom_info *dom = pi->dom_info + domain;
 
-       if (dom->fc_info && dom->fc_info->limit_get_addr) {
-               *max_perf = ioread32(dom->fc_info->limit_get_addr);
-               *min_perf = ioread32(dom->fc_info->limit_get_addr + 4);
+       if (dom->fc_info && dom->fc_info[PERF_FC_LIMIT].get_addr) {
+               struct scmi_fc_info *fci = &dom->fc_info[PERF_FC_LIMIT];
+
+               *max_perf = ioread32(fci->get_addr);
+               *min_perf = ioread32(fci->get_addr + 4);
+               trace_scmi_fc_call(SCMI_PROTOCOL_PERF, PERF_LIMITS_GET,
+                                  domain, *min_perf, *max_perf);
                return 0;
        }
 
@@ -505,9 +452,13 @@ static int scmi_perf_level_set(const struct scmi_protocol_handle *ph,
        struct scmi_perf_info *pi = ph->get_priv(ph);
        struct perf_dom_info *dom = pi->dom_info + domain;
 
-       if (dom->fc_info && dom->fc_info->level_set_addr) {
-               iowrite32(level, dom->fc_info->level_set_addr);
-               scmi_perf_fc_ring_db(dom->fc_info->level_set_db);
+       if (dom->fc_info && dom->fc_info[PERF_FC_LEVEL].set_addr) {
+               struct scmi_fc_info *fci = &dom->fc_info[PERF_FC_LEVEL];
+
+               trace_scmi_fc_call(SCMI_PROTOCOL_PERF, PERF_LEVEL_SET,
+                                  domain, level, 0);
+               iowrite32(level, fci->set_addr);
+               ph->hops->fastchannel_db_ring(fci->set_db);
                return 0;
        }
 
@@ -542,8 +493,10 @@ static int scmi_perf_level_get(const struct scmi_protocol_handle *ph,
        struct scmi_perf_info *pi = ph->get_priv(ph);
        struct perf_dom_info *dom = pi->dom_info + domain;
 
-       if (dom->fc_info && dom->fc_info->level_get_addr) {
-               *level = ioread32(dom->fc_info->level_get_addr);
+       if (dom->fc_info && dom->fc_info[PERF_FC_LEVEL].get_addr) {
+               *level = ioread32(dom->fc_info[PERF_FC_LEVEL].get_addr);
+               trace_scmi_fc_call(SCMI_PROTOCOL_PERF, PERF_LEVEL_GET,
+                                  domain, *level, 0);
                return 0;
        }
 
@@ -572,100 +525,33 @@ static int scmi_perf_level_limits_notify(const struct scmi_protocol_handle *ph,
        return ret;
 }
 
-static bool scmi_perf_fc_size_is_valid(u32 msg, u32 size)
-{
-       if ((msg == PERF_LEVEL_GET || msg == PERF_LEVEL_SET) && size == 4)
-               return true;
-       if ((msg == PERF_LIMITS_GET || msg == PERF_LIMITS_SET) && size == 8)
-               return true;
-       return false;
-}
-
-static void
-scmi_perf_domain_desc_fc(const struct scmi_protocol_handle *ph, u32 domain,
-                        u32 message_id, void __iomem **p_addr,
-                        struct scmi_fc_db_info **p_db)
-{
-       int ret;
-       u32 flags;
-       u64 phys_addr;
-       u8 size;
-       void __iomem *addr;
-       struct scmi_xfer *t;
-       struct scmi_fc_db_info *db;
-       struct scmi_perf_get_fc_info *info;
-       struct scmi_msg_resp_perf_desc_fc *resp;
-
-       if (!p_addr)
-               return;
-
-       ret = ph->xops->xfer_get_init(ph, PERF_DESCRIBE_FASTCHANNEL,
-                                     sizeof(*info), sizeof(*resp), &t);
-       if (ret)
-               return;
-
-       info = t->tx.buf;
-       info->domain = cpu_to_le32(domain);
-       info->message_id = cpu_to_le32(message_id);
-
-       ret = ph->xops->do_xfer(ph, t);
-       if (ret)
-               goto err_xfer;
-
-       resp = t->rx.buf;
-       flags = le32_to_cpu(resp->attr);
-       size = le32_to_cpu(resp->chan_size);
-       if (!scmi_perf_fc_size_is_valid(message_id, size))
-               goto err_xfer;
-
-       phys_addr = le32_to_cpu(resp->chan_addr_low);
-       phys_addr |= (u64)le32_to_cpu(resp->chan_addr_high) << 32;
-       addr = devm_ioremap(ph->dev, phys_addr, size);
-       if (!addr)
-               goto err_xfer;
-       *p_addr = addr;
-
-       if (p_db && SUPPORTS_DOORBELL(flags)) {
-               db = devm_kzalloc(ph->dev, sizeof(*db), GFP_KERNEL);
-               if (!db)
-                       goto err_xfer;
-
-               size = 1 << DOORBELL_REG_WIDTH(flags);
-               phys_addr = le32_to_cpu(resp->db_addr_low);
-               phys_addr |= (u64)le32_to_cpu(resp->db_addr_high) << 32;
-               addr = devm_ioremap(ph->dev, phys_addr, size);
-               if (!addr)
-                       goto err_xfer;
-
-               db->addr = addr;
-               db->width = size;
-               db->set = le32_to_cpu(resp->db_set_lmask);
-               db->set |= (u64)le32_to_cpu(resp->db_set_hmask) << 32;
-               db->mask = le32_to_cpu(resp->db_preserve_lmask);
-               db->mask |= (u64)le32_to_cpu(resp->db_preserve_hmask) << 32;
-               *p_db = db;
-       }
-err_xfer:
-       ph->xops->xfer_put(ph, t);
-}
-
 static void scmi_perf_domain_init_fc(const struct scmi_protocol_handle *ph,
                                     u32 domain, struct scmi_fc_info **p_fc)
 {
        struct scmi_fc_info *fc;
 
-       fc = devm_kzalloc(ph->dev, sizeof(*fc), GFP_KERNEL);
+       fc = devm_kcalloc(ph->dev, PERF_FC_MAX, sizeof(*fc), GFP_KERNEL);
        if (!fc)
                return;
 
-       scmi_perf_domain_desc_fc(ph, domain, PERF_LEVEL_SET,
-                                &fc->level_set_addr, &fc->level_set_db);
-       scmi_perf_domain_desc_fc(ph, domain, PERF_LEVEL_GET,
-                                &fc->level_get_addr, NULL);
-       scmi_perf_domain_desc_fc(ph, domain, PERF_LIMITS_SET,
-                                &fc->limit_set_addr, &fc->limit_set_db);
-       scmi_perf_domain_desc_fc(ph, domain, PERF_LIMITS_GET,
-                                &fc->limit_get_addr, NULL);
+       ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
+                                  PERF_LEVEL_SET, 4, domain,
+                                  &fc[PERF_FC_LEVEL].set_addr,
+                                  &fc[PERF_FC_LEVEL].set_db);
+
+       ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
+                                  PERF_LEVEL_GET, 4, domain,
+                                  &fc[PERF_FC_LEVEL].get_addr, NULL);
+
+       ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
+                                  PERF_LIMITS_SET, 8, domain,
+                                  &fc[PERF_FC_LIMIT].set_addr,
+                                  &fc[PERF_FC_LIMIT].set_db);
+
+       ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
+                                  PERF_LIMITS_GET, 8, domain,
+                                  &fc[PERF_FC_LIMIT].get_addr, NULL);
+
        *p_fc = fc;
 }
 
@@ -789,14 +675,15 @@ static bool scmi_fast_switch_possible(const struct scmi_protocol_handle *ph,
 
        dom = pi->dom_info + scmi_dev_domain_id(dev);
 
-       return dom->fc_info && dom->fc_info->level_set_addr;
+       return dom->fc_info && dom->fc_info[PERF_FC_LEVEL].set_addr;
 }
 
-static bool scmi_power_scale_mw_get(const struct scmi_protocol_handle *ph)
+static enum scmi_power_scale
+scmi_power_scale_get(const struct scmi_protocol_handle *ph)
 {
        struct scmi_perf_info *pi = ph->get_priv(ph);
 
-       return pi->power_scale_mw;
+       return pi->power_scale;
 }
 
 static const struct scmi_perf_proto_ops perf_proto_ops = {
@@ -811,7 +698,7 @@ static const struct scmi_perf_proto_ops perf_proto_ops = {
        .freq_get = scmi_dvfs_freq_get,
        .est_power_get = scmi_dvfs_est_power_get,
        .fast_switch_possible = scmi_fast_switch_possible,
-       .power_scale_mw_get = scmi_power_scale_mw_get,
+       .power_scale_get = scmi_power_scale_get,
 };
 
 static int scmi_perf_set_notify_enabled(const struct scmi_protocol_handle *ph,
index 964882c..356e836 100644 (file)
@@ -122,7 +122,7 @@ scmi_power_domain_attributes_get(const struct scmi_protocol_handle *ph,
                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);
-               strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE);
+               strscpy(dom_info->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE);
        }
        ph->xops->xfer_put(ph, t);
 
diff --git a/drivers/firmware/arm_scmi/powercap.c b/drivers/firmware/arm_scmi/powercap.c
new file mode 100644 (file)
index 0000000..83b90bd
--- /dev/null
@@ -0,0 +1,866 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * System Control and Management Interface (SCMI) Powercap Protocol
+ *
+ * Copyright (C) 2022 ARM Ltd.
+ */
+
+#define pr_fmt(fmt) "SCMI Notifications POWERCAP - " fmt
+
+#include <linux/bitfield.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/scmi_protocol.h>
+
+#include <trace/events/scmi.h>
+
+#include "protocols.h"
+#include "notify.h"
+
+enum scmi_powercap_protocol_cmd {
+       POWERCAP_DOMAIN_ATTRIBUTES = 0x3,
+       POWERCAP_CAP_GET = 0x4,
+       POWERCAP_CAP_SET = 0x5,
+       POWERCAP_PAI_GET = 0x6,
+       POWERCAP_PAI_SET = 0x7,
+       POWERCAP_DOMAIN_NAME_GET = 0x8,
+       POWERCAP_MEASUREMENTS_GET = 0x9,
+       POWERCAP_CAP_NOTIFY = 0xa,
+       POWERCAP_MEASUREMENTS_NOTIFY = 0xb,
+       POWERCAP_DESCRIBE_FASTCHANNEL = 0xc,
+};
+
+enum {
+       POWERCAP_FC_CAP,
+       POWERCAP_FC_PAI,
+       POWERCAP_FC_MAX,
+};
+
+struct scmi_msg_resp_powercap_domain_attributes {
+       __le32 attributes;
+#define SUPPORTS_POWERCAP_CAP_CHANGE_NOTIFY(x)         ((x) & BIT(31))
+#define SUPPORTS_POWERCAP_MEASUREMENTS_CHANGE_NOTIFY(x)        ((x) & BIT(30))
+#define SUPPORTS_ASYNC_POWERCAP_CAP_SET(x)             ((x) & BIT(29))
+#define SUPPORTS_EXTENDED_NAMES(x)                     ((x) & BIT(28))
+#define SUPPORTS_POWERCAP_CAP_CONFIGURATION(x)         ((x) & BIT(27))
+#define SUPPORTS_POWERCAP_MONITORING(x)                        ((x) & BIT(26))
+#define SUPPORTS_POWERCAP_PAI_CONFIGURATION(x)         ((x) & BIT(25))
+#define SUPPORTS_POWERCAP_FASTCHANNELS(x)              ((x) & BIT(22))
+#define POWERCAP_POWER_UNIT(x)                         \
+               (FIELD_GET(GENMASK(24, 23), (x)))
+#define        SUPPORTS_POWER_UNITS_MW(x)                      \
+               (POWERCAP_POWER_UNIT(x) == 0x2)
+#define        SUPPORTS_POWER_UNITS_UW(x)                      \
+               (POWERCAP_POWER_UNIT(x) == 0x1)
+       u8 name[SCMI_SHORT_NAME_MAX_SIZE];
+       __le32 min_pai;
+       __le32 max_pai;
+       __le32 pai_step;
+       __le32 min_power_cap;
+       __le32 max_power_cap;
+       __le32 power_cap_step;
+       __le32 sustainable_power;
+       __le32 accuracy;
+       __le32 parent_id;
+};
+
+struct scmi_msg_powercap_set_cap_or_pai {
+       __le32 domain;
+       __le32 flags;
+#define CAP_SET_ASYNC          BIT(1)
+#define CAP_SET_IGNORE_DRESP   BIT(0)
+       __le32 value;
+};
+
+struct scmi_msg_resp_powercap_cap_set_complete {
+       __le32 domain;
+       __le32 power_cap;
+};
+
+struct scmi_msg_resp_powercap_meas_get {
+       __le32 power;
+       __le32 pai;
+};
+
+struct scmi_msg_powercap_notify_cap {
+       __le32 domain;
+       __le32 notify_enable;
+};
+
+struct scmi_msg_powercap_notify_thresh {
+       __le32 domain;
+       __le32 notify_enable;
+       __le32 power_thresh_low;
+       __le32 power_thresh_high;
+};
+
+struct scmi_powercap_cap_changed_notify_payld {
+       __le32 agent_id;
+       __le32 domain_id;
+       __le32 power_cap;
+       __le32 pai;
+};
+
+struct scmi_powercap_meas_changed_notify_payld {
+       __le32 agent_id;
+       __le32 domain_id;
+       __le32 power;
+};
+
+struct scmi_powercap_state {
+       bool meas_notif_enabled;
+       u64 thresholds;
+#define THRESH_LOW(p, id)                              \
+       (lower_32_bits((p)->states[(id)].thresholds))
+#define THRESH_HIGH(p, id)                             \
+       (upper_32_bits((p)->states[(id)].thresholds))
+};
+
+struct powercap_info {
+       u32 version;
+       int num_domains;
+       struct scmi_powercap_state *states;
+       struct scmi_powercap_info *powercaps;
+};
+
+static enum scmi_powercap_protocol_cmd evt_2_cmd[] = {
+       POWERCAP_CAP_NOTIFY,
+       POWERCAP_MEASUREMENTS_NOTIFY,
+};
+
+static int scmi_powercap_notify(const struct scmi_protocol_handle *ph,
+                               u32 domain, int message_id, bool enable);
+
+static int
+scmi_powercap_attributes_get(const struct scmi_protocol_handle *ph,
+                            struct powercap_info *pi)
+{
+       int ret;
+       struct scmi_xfer *t;
+
+       ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0,
+                                     sizeof(u32), &t);
+       if (ret)
+               return ret;
+
+       ret = ph->xops->do_xfer(ph, t);
+       if (!ret) {
+               u32 attributes;
+
+               attributes = get_unaligned_le32(t->rx.buf);
+               pi->num_domains = FIELD_GET(GENMASK(15, 0), attributes);
+       }
+
+       ph->xops->xfer_put(ph, t);
+       return ret;
+}
+
+static inline int
+scmi_powercap_validate(unsigned int min_val, unsigned int max_val,
+                      unsigned int step_val, bool configurable)
+{
+       if (!min_val || !max_val)
+               return -EPROTO;
+
+       if ((configurable && min_val == max_val) ||
+           (!configurable && min_val != max_val))
+               return -EPROTO;
+
+       if (min_val != max_val && !step_val)
+               return -EPROTO;
+
+       return 0;
+}
+
+static int
+scmi_powercap_domain_attributes_get(const struct scmi_protocol_handle *ph,
+                                   struct powercap_info *pinfo, u32 domain)
+{
+       int ret;
+       u32 flags;
+       struct scmi_xfer *t;
+       struct scmi_powercap_info *dom_info = pinfo->powercaps + domain;
+       struct scmi_msg_resp_powercap_domain_attributes *resp;
+
+       ret = ph->xops->xfer_get_init(ph, POWERCAP_DOMAIN_ATTRIBUTES,
+                                     sizeof(domain), sizeof(*resp), &t);
+       if (ret)
+               return ret;
+
+       put_unaligned_le32(domain, t->tx.buf);
+       resp = t->rx.buf;
+
+       ret = ph->xops->do_xfer(ph, t);
+       if (!ret) {
+               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);
+               dom_info->async_powercap_cap_set =
+                       SUPPORTS_ASYNC_POWERCAP_CAP_SET(flags);
+               dom_info->powercap_cap_config =
+                       SUPPORTS_POWERCAP_CAP_CONFIGURATION(flags);
+               dom_info->powercap_monitoring =
+                       SUPPORTS_POWERCAP_MONITORING(flags);
+               dom_info->powercap_pai_config =
+                       SUPPORTS_POWERCAP_PAI_CONFIGURATION(flags);
+               dom_info->powercap_scale_mw =
+                       SUPPORTS_POWER_UNITS_MW(flags);
+               dom_info->powercap_scale_uw =
+                       SUPPORTS_POWER_UNITS_UW(flags);
+               dom_info->fastchannels =
+                       SUPPORTS_POWERCAP_FASTCHANNELS(flags);
+
+               strscpy(dom_info->name, resp->name, SCMI_SHORT_NAME_MAX_SIZE);
+
+               dom_info->min_pai = le32_to_cpu(resp->min_pai);
+               dom_info->max_pai = le32_to_cpu(resp->max_pai);
+               dom_info->pai_step = le32_to_cpu(resp->pai_step);
+               ret = scmi_powercap_validate(dom_info->min_pai,
+                                            dom_info->max_pai,
+                                            dom_info->pai_step,
+                                            dom_info->powercap_pai_config);
+               if (ret) {
+                       dev_err(ph->dev,
+                               "Platform reported inconsistent PAI config for domain %d - %s\n",
+                               dom_info->id, dom_info->name);
+                       goto clean;
+               }
+
+               dom_info->min_power_cap = le32_to_cpu(resp->min_power_cap);
+               dom_info->max_power_cap = le32_to_cpu(resp->max_power_cap);
+               dom_info->power_cap_step = le32_to_cpu(resp->power_cap_step);
+               ret = scmi_powercap_validate(dom_info->min_power_cap,
+                                            dom_info->max_power_cap,
+                                            dom_info->power_cap_step,
+                                            dom_info->powercap_cap_config);
+               if (ret) {
+                       dev_err(ph->dev,
+                               "Platform reported inconsistent CAP config for domain %d - %s\n",
+                               dom_info->id, dom_info->name);
+                       goto clean;
+               }
+
+               dom_info->sustainable_power =
+                       le32_to_cpu(resp->sustainable_power);
+               dom_info->accuracy = le32_to_cpu(resp->accuracy);
+
+               dom_info->parent_id = le32_to_cpu(resp->parent_id);
+               if (dom_info->parent_id != SCMI_POWERCAP_ROOT_ZONE_ID &&
+                   (dom_info->parent_id >= pinfo->num_domains ||
+                    dom_info->parent_id == dom_info->id)) {
+                       dev_err(ph->dev,
+                               "Platform reported inconsistent parent ID for domain %d - %s\n",
+                               dom_info->id, dom_info->name);
+                       ret = -ENODEV;
+               }
+       }
+
+clean:
+       ph->xops->xfer_put(ph, t);
+
+       /*
+        * If supported overwrite short name with the extended one;
+        * on error just carry on and use already provided short name.
+        */
+       if (!ret && SUPPORTS_EXTENDED_NAMES(flags))
+               ph->hops->extended_name_get(ph, POWERCAP_DOMAIN_NAME_GET,
+                                           domain, dom_info->name,
+                                           SCMI_MAX_STR_SIZE);
+
+       return ret;
+}
+
+static int scmi_powercap_num_domains_get(const struct scmi_protocol_handle *ph)
+{
+       struct powercap_info *pi = ph->get_priv(ph);
+
+       return pi->num_domains;
+}
+
+static const struct scmi_powercap_info *
+scmi_powercap_dom_info_get(const struct scmi_protocol_handle *ph, u32 domain_id)
+{
+       struct powercap_info *pi = ph->get_priv(ph);
+
+       if (domain_id >= pi->num_domains)
+               return NULL;
+
+       return pi->powercaps + domain_id;
+}
+
+static int scmi_powercap_xfer_cap_get(const struct scmi_protocol_handle *ph,
+                                     u32 domain_id, u32 *power_cap)
+{
+       int ret;
+       struct scmi_xfer *t;
+
+       ret = ph->xops->xfer_get_init(ph, POWERCAP_CAP_GET, sizeof(u32),
+                                     sizeof(u32), &t);
+       if (ret)
+               return ret;
+
+       put_unaligned_le32(domain_id, t->tx.buf);
+       ret = ph->xops->do_xfer(ph, t);
+       if (!ret)
+               *power_cap = get_unaligned_le32(t->rx.buf);
+
+       ph->xops->xfer_put(ph, t);
+
+       return ret;
+}
+
+static int scmi_powercap_cap_get(const struct scmi_protocol_handle *ph,
+                                u32 domain_id, u32 *power_cap)
+{
+       struct scmi_powercap_info *dom;
+       struct powercap_info *pi = ph->get_priv(ph);
+
+       if (!power_cap || domain_id >= pi->num_domains)
+               return -EINVAL;
+
+       dom = pi->powercaps + domain_id;
+       if (dom->fc_info && dom->fc_info[POWERCAP_FC_CAP].get_addr) {
+               *power_cap = ioread32(dom->fc_info[POWERCAP_FC_CAP].get_addr);
+               trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_CAP_GET,
+                                  domain_id, *power_cap, 0);
+               return 0;
+       }
+
+       return scmi_powercap_xfer_cap_get(ph, domain_id, power_cap);
+}
+
+static int scmi_powercap_xfer_cap_set(const struct scmi_protocol_handle *ph,
+                                     const struct scmi_powercap_info *pc,
+                                     u32 power_cap, bool ignore_dresp)
+{
+       int ret;
+       struct scmi_xfer *t;
+       struct scmi_msg_powercap_set_cap_or_pai *msg;
+
+       ret = ph->xops->xfer_get_init(ph, POWERCAP_CAP_SET,
+                                     sizeof(*msg), 0, &t);
+       if (ret)
+               return ret;
+
+       msg = t->tx.buf;
+       msg->domain = cpu_to_le32(pc->id);
+       msg->flags =
+               cpu_to_le32(FIELD_PREP(CAP_SET_ASYNC, !!pc->async_powercap_cap_set) |
+                           FIELD_PREP(CAP_SET_IGNORE_DRESP, !!ignore_dresp));
+       msg->value = cpu_to_le32(power_cap);
+
+       if (!pc->async_powercap_cap_set || ignore_dresp) {
+               ret = ph->xops->do_xfer(ph, t);
+       } else {
+               ret = ph->xops->do_xfer_with_response(ph, t);
+               if (!ret) {
+                       struct scmi_msg_resp_powercap_cap_set_complete *resp;
+
+                       resp = t->rx.buf;
+                       if (le32_to_cpu(resp->domain) == pc->id)
+                               dev_dbg(ph->dev,
+                                       "Powercap ID %d CAP set async to %u\n",
+                                       pc->id,
+                                       get_unaligned_le32(&resp->power_cap));
+                       else
+                               ret = -EPROTO;
+               }
+       }
+
+       ph->xops->xfer_put(ph, t);
+       return ret;
+}
+
+static int scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
+                                u32 domain_id, u32 power_cap,
+                                bool ignore_dresp)
+{
+       const struct scmi_powercap_info *pc;
+
+       pc = scmi_powercap_dom_info_get(ph, domain_id);
+       if (!pc || !pc->powercap_cap_config || !power_cap ||
+           power_cap < pc->min_power_cap ||
+           power_cap > pc->max_power_cap)
+               return -EINVAL;
+
+       if (pc->fc_info && pc->fc_info[POWERCAP_FC_CAP].set_addr) {
+               struct scmi_fc_info *fci = &pc->fc_info[POWERCAP_FC_CAP];
+
+               iowrite32(power_cap, fci->set_addr);
+               ph->hops->fastchannel_db_ring(fci->set_db);
+               trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_CAP_SET,
+                                  domain_id, power_cap, 0);
+               return 0;
+       }
+
+       return scmi_powercap_xfer_cap_set(ph, pc, power_cap, ignore_dresp);
+}
+
+static int scmi_powercap_xfer_pai_get(const struct scmi_protocol_handle *ph,
+                                     u32 domain_id, u32 *pai)
+{
+       int ret;
+       struct scmi_xfer *t;
+
+       ret = ph->xops->xfer_get_init(ph, POWERCAP_PAI_GET, sizeof(u32),
+                                     sizeof(u32), &t);
+       if (ret)
+               return ret;
+
+       put_unaligned_le32(domain_id, t->tx.buf);
+       ret = ph->xops->do_xfer(ph, t);
+       if (!ret)
+               *pai = get_unaligned_le32(t->rx.buf);
+
+       ph->xops->xfer_put(ph, t);
+
+       return ret;
+}
+
+static int scmi_powercap_pai_get(const struct scmi_protocol_handle *ph,
+                                u32 domain_id, u32 *pai)
+{
+       struct scmi_powercap_info *dom;
+       struct powercap_info *pi = ph->get_priv(ph);
+
+       if (!pai || domain_id >= pi->num_domains)
+               return -EINVAL;
+
+       dom = pi->powercaps + domain_id;
+       if (dom->fc_info && dom->fc_info[POWERCAP_FC_PAI].get_addr) {
+               *pai = ioread32(dom->fc_info[POWERCAP_FC_PAI].get_addr);
+               trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_PAI_GET,
+                                  domain_id, *pai, 0);
+               return 0;
+       }
+
+       return scmi_powercap_xfer_pai_get(ph, domain_id, pai);
+}
+
+static int scmi_powercap_xfer_pai_set(const struct scmi_protocol_handle *ph,
+                                     u32 domain_id, u32 pai)
+{
+       int ret;
+       struct scmi_xfer *t;
+       struct scmi_msg_powercap_set_cap_or_pai *msg;
+
+       ret = ph->xops->xfer_get_init(ph, POWERCAP_PAI_SET,
+                                     sizeof(*msg), 0, &t);
+       if (ret)
+               return ret;
+
+       msg = t->tx.buf;
+       msg->domain = cpu_to_le32(domain_id);
+       msg->flags = cpu_to_le32(0);
+       msg->value = cpu_to_le32(pai);
+
+       ret = ph->xops->do_xfer(ph, t);
+
+       ph->xops->xfer_put(ph, t);
+       return ret;
+}
+
+static int scmi_powercap_pai_set(const struct scmi_protocol_handle *ph,
+                                u32 domain_id, u32 pai)
+{
+       const struct scmi_powercap_info *pc;
+
+       pc = scmi_powercap_dom_info_get(ph, domain_id);
+       if (!pc || !pc->powercap_pai_config || !pai ||
+           pai < pc->min_pai || pai > pc->max_pai)
+               return -EINVAL;
+
+       if (pc->fc_info && pc->fc_info[POWERCAP_FC_PAI].set_addr) {
+               struct scmi_fc_info *fci = &pc->fc_info[POWERCAP_FC_PAI];
+
+               trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_PAI_SET,
+                                  domain_id, pai, 0);
+               iowrite32(pai, fci->set_addr);
+               ph->hops->fastchannel_db_ring(fci->set_db);
+               return 0;
+       }
+
+       return scmi_powercap_xfer_pai_set(ph, domain_id, pai);
+}
+
+static int scmi_powercap_measurements_get(const struct scmi_protocol_handle *ph,
+                                         u32 domain_id, u32 *average_power,
+                                         u32 *pai)
+{
+       int ret;
+       struct scmi_xfer *t;
+       struct scmi_msg_resp_powercap_meas_get *resp;
+       const struct scmi_powercap_info *pc;
+
+       pc = scmi_powercap_dom_info_get(ph, domain_id);
+       if (!pc || !pc->powercap_monitoring || !pai || !average_power)
+               return -EINVAL;
+
+       ret = ph->xops->xfer_get_init(ph, POWERCAP_MEASUREMENTS_GET,
+                                     sizeof(u32), sizeof(*resp), &t);
+       if (ret)
+               return ret;
+
+       resp = t->rx.buf;
+       put_unaligned_le32(domain_id, t->tx.buf);
+       ret = ph->xops->do_xfer(ph, t);
+       if (!ret) {
+               *average_power = le32_to_cpu(resp->power);
+               *pai = le32_to_cpu(resp->pai);
+       }
+
+       ph->xops->xfer_put(ph, t);
+       return ret;
+}
+
+static int
+scmi_powercap_measurements_threshold_get(const struct scmi_protocol_handle *ph,
+                                        u32 domain_id, u32 *power_thresh_low,
+                                        u32 *power_thresh_high)
+{
+       struct powercap_info *pi = ph->get_priv(ph);
+
+       if (!power_thresh_low || !power_thresh_high ||
+           domain_id >= pi->num_domains)
+               return -EINVAL;
+
+       *power_thresh_low =  THRESH_LOW(pi, domain_id);
+       *power_thresh_high = THRESH_HIGH(pi, domain_id);
+
+       return 0;
+}
+
+static int
+scmi_powercap_measurements_threshold_set(const struct scmi_protocol_handle *ph,
+                                        u32 domain_id, u32 power_thresh_low,
+                                        u32 power_thresh_high)
+{
+       int ret = 0;
+       struct powercap_info *pi = ph->get_priv(ph);
+
+       if (domain_id >= pi->num_domains ||
+           power_thresh_low > power_thresh_high)
+               return -EINVAL;
+
+       /* Anything to do ? */
+       if (THRESH_LOW(pi, domain_id) == power_thresh_low &&
+           THRESH_HIGH(pi, domain_id) == power_thresh_high)
+               return ret;
+
+       pi->states[domain_id].thresholds =
+               (FIELD_PREP(GENMASK_ULL(31, 0), power_thresh_low) |
+                FIELD_PREP(GENMASK_ULL(63, 32), power_thresh_high));
+
+       /* Update thresholds if notification already enabled */
+       if (pi->states[domain_id].meas_notif_enabled)
+               ret = scmi_powercap_notify(ph, domain_id,
+                                          POWERCAP_MEASUREMENTS_NOTIFY,
+                                          true);
+
+       return ret;
+}
+
+static const struct scmi_powercap_proto_ops powercap_proto_ops = {
+       .num_domains_get = scmi_powercap_num_domains_get,
+       .info_get = scmi_powercap_dom_info_get,
+       .cap_get = scmi_powercap_cap_get,
+       .cap_set = scmi_powercap_cap_set,
+       .pai_get = scmi_powercap_pai_get,
+       .pai_set = scmi_powercap_pai_set,
+       .measurements_get = scmi_powercap_measurements_get,
+       .measurements_threshold_set = scmi_powercap_measurements_threshold_set,
+       .measurements_threshold_get = scmi_powercap_measurements_threshold_get,
+};
+
+static void scmi_powercap_domain_init_fc(const struct scmi_protocol_handle *ph,
+                                        u32 domain, struct scmi_fc_info **p_fc)
+{
+       struct scmi_fc_info *fc;
+
+       fc = devm_kcalloc(ph->dev, POWERCAP_FC_MAX, sizeof(*fc), GFP_KERNEL);
+       if (!fc)
+               return;
+
+       ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
+                                  POWERCAP_CAP_SET, 4, domain,
+                                  &fc[POWERCAP_FC_CAP].set_addr,
+                                  &fc[POWERCAP_FC_CAP].set_db);
+
+       ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
+                                  POWERCAP_CAP_GET, 4, domain,
+                                  &fc[POWERCAP_FC_CAP].get_addr, NULL);
+
+       ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
+                                  POWERCAP_PAI_SET, 4, domain,
+                                  &fc[POWERCAP_FC_PAI].set_addr,
+                                  &fc[POWERCAP_FC_PAI].set_db);
+
+       ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
+                                  POWERCAP_PAI_GET, 4, domain,
+                                  &fc[POWERCAP_FC_PAI].get_addr, NULL);
+
+       *p_fc = fc;
+}
+
+static int scmi_powercap_notify(const struct scmi_protocol_handle *ph,
+                               u32 domain, int message_id, bool enable)
+{
+       int ret;
+       struct scmi_xfer *t;
+
+       switch (message_id) {
+       case POWERCAP_CAP_NOTIFY:
+       {
+               struct scmi_msg_powercap_notify_cap *notify;
+
+               ret = ph->xops->xfer_get_init(ph, message_id,
+                                             sizeof(*notify), 0, &t);
+               if (ret)
+                       return ret;
+
+               notify = t->tx.buf;
+               notify->domain = cpu_to_le32(domain);
+               notify->notify_enable = cpu_to_le32(enable ? BIT(0) : 0);
+               break;
+       }
+       case POWERCAP_MEASUREMENTS_NOTIFY:
+       {
+               u32 low, high;
+               struct scmi_msg_powercap_notify_thresh *notify;
+
+               /*
+                * Note that we have to pick the most recently configured
+                * thresholds to build a proper POWERCAP_MEASUREMENTS_NOTIFY
+                * enable request and we fail, complaining, if no thresholds
+                * were ever set, since this is an indication the API has been
+                * used wrongly.
+                */
+               ret = scmi_powercap_measurements_threshold_get(ph, domain,
+                                                              &low, &high);
+               if (ret)
+                       return ret;
+
+               if (enable && !low && !high) {
+                       dev_err(ph->dev,
+                               "Invalid Measurements Notify thresholds: %u/%u\n",
+                               low, high);
+                       return -EINVAL;
+               }
+
+               ret = ph->xops->xfer_get_init(ph, message_id,
+                                             sizeof(*notify), 0, &t);
+               if (ret)
+                       return ret;
+
+               notify = t->tx.buf;
+               notify->domain = cpu_to_le32(domain);
+               notify->notify_enable = cpu_to_le32(enable ? BIT(0) : 0);
+               notify->power_thresh_low = cpu_to_le32(low);
+               notify->power_thresh_high = cpu_to_le32(high);
+               break;
+       }
+       default:
+               return -EINVAL;
+       }
+
+       ret = ph->xops->do_xfer(ph, t);
+
+       ph->xops->xfer_put(ph, t);
+       return ret;
+}
+
+static int
+scmi_powercap_set_notify_enabled(const struct scmi_protocol_handle *ph,
+                                u8 evt_id, u32 src_id, bool enable)
+{
+       int ret, cmd_id;
+       struct powercap_info *pi = ph->get_priv(ph);
+
+       if (evt_id >= ARRAY_SIZE(evt_2_cmd) || src_id >= pi->num_domains)
+               return -EINVAL;
+
+       cmd_id = evt_2_cmd[evt_id];
+       ret = scmi_powercap_notify(ph, src_id, cmd_id, enable);
+       if (ret)
+               pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",
+                        evt_id, src_id, ret);
+       else if (cmd_id == POWERCAP_MEASUREMENTS_NOTIFY)
+               /*
+                * On success save the current notification enabled state, so
+                * as to be able to properly update the notification thresholds
+                * when they are modified on a domain for which measurement
+                * notifications were currently enabled.
+                *
+                * This is needed because the SCMI Notification core machinery
+                * and API does not support passing per-notification custom
+                * arguments at callback registration time.
+                *
+                * Note that this can be done here with a simple flag since the
+                * SCMI core Notifications code takes care of keeping proper
+                * per-domain enables refcounting, so that this helper function
+                * will be called only once (for enables) when the first user
+                * registers a callback on this domain and once more (disable)
+                * when the last user de-registers its callback.
+                */
+               pi->states[src_id].meas_notif_enabled = enable;
+
+       return ret;
+}
+
+static void *
+scmi_powercap_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)
+{
+       void *rep = NULL;
+
+       switch (evt_id) {
+       case SCMI_EVENT_POWERCAP_CAP_CHANGED:
+       {
+               const struct scmi_powercap_cap_changed_notify_payld *p = payld;
+               struct scmi_powercap_cap_changed_report *r = report;
+
+               if (sizeof(*p) != payld_sz)
+                       break;
+
+               r->timestamp = timestamp;
+               r->agent_id = le32_to_cpu(p->agent_id);
+               r->domain_id = le32_to_cpu(p->domain_id);
+               r->power_cap = le32_to_cpu(p->power_cap);
+               r->pai = le32_to_cpu(p->pai);
+               *src_id = r->domain_id;
+               rep = r;
+               break;
+       }
+       case SCMI_EVENT_POWERCAP_MEASUREMENTS_CHANGED:
+       {
+               const struct scmi_powercap_meas_changed_notify_payld *p = payld;
+               struct scmi_powercap_meas_changed_report *r = report;
+
+               if (sizeof(*p) != payld_sz)
+                       break;
+
+               r->timestamp = timestamp;
+               r->agent_id = le32_to_cpu(p->agent_id);
+               r->domain_id = le32_to_cpu(p->domain_id);
+               r->power = le32_to_cpu(p->power);
+               *src_id = r->domain_id;
+               rep = r;
+               break;
+       }
+       default:
+               break;
+       }
+
+       return rep;
+}
+
+static int
+scmi_powercap_get_num_sources(const struct scmi_protocol_handle *ph)
+{
+       struct powercap_info *pi = ph->get_priv(ph);
+
+       if (!pi)
+               return -EINVAL;
+
+       return pi->num_domains;
+}
+
+static const struct scmi_event powercap_events[] = {
+       {
+               .id = SCMI_EVENT_POWERCAP_CAP_CHANGED,
+               .max_payld_sz =
+                       sizeof(struct scmi_powercap_cap_changed_notify_payld),
+               .max_report_sz =
+                       sizeof(struct scmi_powercap_cap_changed_report),
+       },
+       {
+               .id = SCMI_EVENT_POWERCAP_MEASUREMENTS_CHANGED,
+               .max_payld_sz =
+                       sizeof(struct scmi_powercap_meas_changed_notify_payld),
+               .max_report_sz =
+                       sizeof(struct scmi_powercap_meas_changed_report),
+       },
+};
+
+static const struct scmi_event_ops powercap_event_ops = {
+       .get_num_sources = scmi_powercap_get_num_sources,
+       .set_notify_enabled = scmi_powercap_set_notify_enabled,
+       .fill_custom_report = scmi_powercap_fill_custom_report,
+};
+
+static const struct scmi_protocol_events powercap_protocol_events = {
+       .queue_sz = SCMI_PROTO_QUEUE_SZ,
+       .ops = &powercap_event_ops,
+       .evts = powercap_events,
+       .num_events = ARRAY_SIZE(powercap_events),
+};
+
+static int
+scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph)
+{
+       int domain, ret;
+       u32 version;
+       struct powercap_info *pinfo;
+
+       ret = ph->xops->version_get(ph, &version);
+       if (ret)
+               return ret;
+
+       dev_dbg(ph->dev, "Powercap Version %d.%d\n",
+               PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+
+       pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
+       if (!pinfo)
+               return -ENOMEM;
+
+       ret = scmi_powercap_attributes_get(ph, pinfo);
+       if (ret)
+               return ret;
+
+       pinfo->powercaps = devm_kcalloc(ph->dev, pinfo->num_domains,
+                                       sizeof(*pinfo->powercaps),
+                                       GFP_KERNEL);
+       if (!pinfo->powercaps)
+               return -ENOMEM;
+
+       /*
+        * Note that any failure in retrieving any domain attribute leads to
+        * the whole Powercap protocol initialization failure: this way the
+        * reported Powercap domains are all assured, when accessed, to be well
+        * formed and correlated by sane parent-child relationship (if any).
+        */
+       for (domain = 0; domain < pinfo->num_domains; domain++) {
+               ret = scmi_powercap_domain_attributes_get(ph, pinfo, domain);
+               if (ret)
+                       return ret;
+
+               if (pinfo->powercaps[domain].fastchannels)
+                       scmi_powercap_domain_init_fc(ph, domain,
+                                                    &pinfo->powercaps[domain].fc_info);
+       }
+
+       pinfo->states = devm_kcalloc(ph->dev, pinfo->num_domains,
+                                    sizeof(*pinfo->states), GFP_KERNEL);
+       if (!pinfo->states)
+               return -ENOMEM;
+
+       pinfo->version = version;
+
+       return ph->set_priv(ph, pinfo);
+}
+
+static const struct scmi_protocol scmi_powercap = {
+       .id = SCMI_PROTOCOL_POWERCAP,
+       .owner = THIS_MODULE,
+       .instance_init = &scmi_powercap_protocol_init,
+       .ops = &powercap_proto_ops,
+       .events = &powercap_protocol_events,
+};
+
+DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(powercap, scmi_powercap)
index 73304af..2f3bf69 100644 (file)
@@ -24,8 +24,6 @@
 
 #include <asm/unaligned.h>
 
-#define SCMI_SHORT_NAME_MAX_SIZE       16
-
 #define PROTOCOL_REV_MINOR_MASK        GENMASK(15, 0)
 #define PROTOCOL_REV_MAJOR_MASK        GENMASK(31, 16)
 #define PROTOCOL_REV_MAJOR(x)  ((u16)(FIELD_GET(PROTOCOL_REV_MAJOR_MASK, (x))))
@@ -181,6 +179,8 @@ struct scmi_protocol_handle {
  * @max_resources: Maximum acceptable number of items, configured by the caller
  *                depending on the underlying resources that it is querying.
  * @loop_idx: The iterator loop index in the current multi-part reply.
+ * @rx_len: Size in bytes of the currenly processed message; it can be used by
+ *         the user of the iterator to verify a reply size.
  * @priv: Optional pointer to some additional state-related private data setup
  *       by the caller during the iterations.
  */
@@ -190,6 +190,7 @@ struct scmi_iterator_state {
        unsigned int num_remaining;
        unsigned int max_resources;
        unsigned int loop_idx;
+       size_t rx_len;
        void *priv;
 };
 
@@ -214,6 +215,19 @@ struct scmi_iterator_ops {
                                struct scmi_iterator_state *st, void *priv);
 };
 
+struct scmi_fc_db_info {
+       int width;
+       u64 set;
+       u64 mask;
+       void __iomem *addr;
+};
+
+struct scmi_fc_info {
+       void __iomem *set_addr;
+       void __iomem *get_addr;
+       struct scmi_fc_db_info *set_db;
+};
+
 /**
  * struct scmi_proto_helpers_ops  - References to common protocol helpers
  * @extended_name_get: A common helper function to retrieve extended naming
@@ -229,6 +243,9 @@ struct scmi_iterator_ops {
  *                     provided in @ops.
  * @iter_response_run: A common helper to trigger the run of a previously
  *                    initialized iterator.
+ * @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.
  */
 struct scmi_proto_helpers_ops {
        int (*extended_name_get)(const struct scmi_protocol_handle *ph,
@@ -238,6 +255,12 @@ struct scmi_proto_helpers_ops {
                                    unsigned int max_resources, u8 msg_id,
                                    size_t tx_size, void *priv);
        int (*iter_response_run)(void *iter);
+       void (*fastchannel_init)(const struct scmi_protocol_handle *ph,
+                                u8 describe_id, u32 message_id,
+                                u32 valid_size, u32 domain,
+                                void __iomem **p_addr,
+                                struct scmi_fc_db_info **p_db);
+       void (*fastchannel_db_ring)(struct scmi_fc_db_info *db);
 };
 
 /**
@@ -314,5 +337,6 @@ DECLARE_SCMI_REGISTER_UNREGISTER(reset);
 DECLARE_SCMI_REGISTER_UNREGISTER(sensors);
 DECLARE_SCMI_REGISTER_UNREGISTER(voltage);
 DECLARE_SCMI_REGISTER_UNREGISTER(system);
+DECLARE_SCMI_REGISTER_UNREGISTER(powercap);
 
 #endif /* _SCMI_PROTOCOLS_H */
index a420a91..673f3eb 100644 (file)
@@ -116,7 +116,7 @@ scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph,
                dom_info->latency_us = le32_to_cpu(attr->latency);
                if (dom_info->latency_us == U32_MAX)
                        dom_info->latency_us = 0;
-               strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE);
+               strscpy(dom_info->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE);
        }
 
        ph->xops->xfer_put(ph, t);
diff --git a/drivers/firmware/arm_scmi/scmi_power_control.c b/drivers/firmware/arm_scmi/scmi_power_control.c
new file mode 100644 (file)
index 0000000..6eb7d2a
--- /dev/null
@@ -0,0 +1,362 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SCMI Generic SystemPower Control driver.
+ *
+ * Copyright (C) 2020-2022 ARM Ltd.
+ */
+/*
+ * In order to handle platform originated SCMI SystemPower requests (like
+ * shutdowns or cold/warm resets) we register an SCMI Notification notifier
+ * block to react when such SCMI SystemPower events are emitted by platform.
+ *
+ * Once such a notification is received we act accordingly to perform the
+ * required system transition depending on the kind of request.
+ *
+ * Graceful requests are routed to userspace through the same API methods
+ * (orderly_poweroff/reboot()) used by ACPI when handling ACPI Shutdown bus
+ * events.
+ *
+ * Direct forceful requests are not supported since are not meant to be sent
+ * by the SCMI platform to an OSPM like Linux.
+ *
+ * Additionally, graceful request notifications can carry an optional timeout
+ * field stating the maximum amount of time allowed by the platform for
+ * completion after which they are converted to forceful ones: the assumption
+ * here is that even graceful requests can be upper-bound by a maximum final
+ * timeout strictly enforced by the platform itself which can ultimately cut
+ * the power off at will anytime; in order to avoid such extreme scenario, we
+ * track progress of graceful requests through the means of a reboot notifier
+ * converting timed-out graceful requests to forceful ones, so at least we
+ * try to perform a clean sync and shutdown/restart before the power is cut.
+ *
+ * Given the peculiar nature of SCMI SystemPower protocol, that is being in
+ * charge of triggering system wide shutdown/reboot events, there should be
+ * only one SCMI platform actively emitting SystemPower events.
+ * For this reason the SCMI core takes care to enforce the creation of one
+ * single unique device associated to the SCMI System Power protocol; no matter
+ * how many SCMI platforms are defined on the system, only one can be designated
+ * to support System Power: as a consequence this driver will never be probed
+ * more than once.
+ *
+ * For similar reasons as soon as the first valid SystemPower is received by
+ * this driver and the shutdown/reboot is started, any further notification
+ * possibly emitted by the platform will be ignored.
+ */
+
+#include <linux/math.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/printk.h>
+#include <linux/reboot.h>
+#include <linux/scmi_protocol.h>
+#include <linux/slab.h>
+#include <linux/time64.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+
+#ifndef MODULE
+#include <linux/fs.h>
+#endif
+
+enum scmi_syspower_state {
+       SCMI_SYSPOWER_IDLE,
+       SCMI_SYSPOWER_IN_PROGRESS,
+       SCMI_SYSPOWER_REBOOTING
+};
+
+/**
+ * struct scmi_syspower_conf  -  Common configuration
+ *
+ * @dev: A reference device
+ * @state: Current SystemPower state
+ * @state_mtx: @state related mutex
+ * @required_transition: The requested transition as decribed in the received
+ *                      SCMI SystemPower notification
+ * @userspace_nb: The notifier_block registered against the SCMI SystemPower
+ *               notification to start the needed userspace interactions.
+ * @reboot_nb: A notifier_block optionally used to track reboot progress
+ * @forceful_work: A worker used to trigger a forceful transition once a
+ *                graceful has timed out.
+ */
+struct scmi_syspower_conf {
+       struct device *dev;
+       enum scmi_syspower_state state;
+       /* Protect access to state */
+       struct mutex state_mtx;
+       enum scmi_system_events required_transition;
+
+       struct notifier_block userspace_nb;
+       struct notifier_block reboot_nb;
+
+       struct delayed_work forceful_work;
+};
+
+#define userspace_nb_to_sconf(x)       \
+       container_of(x, struct scmi_syspower_conf, userspace_nb)
+
+#define reboot_nb_to_sconf(x)          \
+       container_of(x, struct scmi_syspower_conf, reboot_nb)
+
+#define dwork_to_sconf(x)              \
+       container_of(x, struct scmi_syspower_conf, forceful_work)
+
+/**
+ * scmi_reboot_notifier  - A reboot notifier to catch an ongoing successful
+ * system transition
+ * @nb: Reference to the related notifier block
+ * @reason: The reason for the ongoing reboot
+ * @__unused: The cmd being executed on a restart request (unused)
+ *
+ * When an ongoing system transition is detected, compatible with the one
+ * requested by SCMI, cancel the delayed work.
+ *
+ * Return: NOTIFY_OK in any case
+ */
+static int scmi_reboot_notifier(struct notifier_block *nb,
+                               unsigned long reason, void *__unused)
+{
+       struct scmi_syspower_conf *sc = reboot_nb_to_sconf(nb);
+
+       mutex_lock(&sc->state_mtx);
+       switch (reason) {
+       case SYS_HALT:
+       case SYS_POWER_OFF:
+               if (sc->required_transition == SCMI_SYSTEM_SHUTDOWN)
+                       sc->state = SCMI_SYSPOWER_REBOOTING;
+               break;
+       case SYS_RESTART:
+               if (sc->required_transition == SCMI_SYSTEM_COLDRESET ||
+                   sc->required_transition == SCMI_SYSTEM_WARMRESET)
+                       sc->state = SCMI_SYSPOWER_REBOOTING;
+               break;
+       default:
+               break;
+       }
+
+       if (sc->state == SCMI_SYSPOWER_REBOOTING) {
+               dev_dbg(sc->dev, "Reboot in progress...cancel delayed work.\n");
+               cancel_delayed_work_sync(&sc->forceful_work);
+       }
+       mutex_unlock(&sc->state_mtx);
+
+       return NOTIFY_OK;
+}
+
+/**
+ * scmi_request_forceful_transition  - Request forceful SystemPower transition
+ * @sc: A reference to the configuration data
+ *
+ * Initiates the required SystemPower transition without involving userspace:
+ * just trigger the action at the kernel level after issuing an emergency
+ * sync. (if possible at all)
+ */
+static inline void
+scmi_request_forceful_transition(struct scmi_syspower_conf *sc)
+{
+       dev_dbg(sc->dev, "Serving forceful request:%d\n",
+               sc->required_transition);
+
+#ifndef MODULE
+       emergency_sync();
+#endif
+       switch (sc->required_transition) {
+       case SCMI_SYSTEM_SHUTDOWN:
+               kernel_power_off();
+               break;
+       case SCMI_SYSTEM_COLDRESET:
+       case SCMI_SYSTEM_WARMRESET:
+               kernel_restart(NULL);
+               break;
+       default:
+               break;
+       }
+}
+
+static void scmi_forceful_work_func(struct work_struct *work)
+{
+       struct scmi_syspower_conf *sc;
+       struct delayed_work *dwork;
+
+       if (system_state > SYSTEM_RUNNING)
+               return;
+
+       dwork = to_delayed_work(work);
+       sc = dwork_to_sconf(dwork);
+
+       dev_dbg(sc->dev, "Graceful request timed out...forcing !\n");
+       mutex_lock(&sc->state_mtx);
+       /* avoid deadlock by unregistering reboot notifier first */
+       unregister_reboot_notifier(&sc->reboot_nb);
+       if (sc->state == SCMI_SYSPOWER_IN_PROGRESS)
+               scmi_request_forceful_transition(sc);
+       mutex_unlock(&sc->state_mtx);
+}
+
+/**
+ * scmi_request_graceful_transition  - Request graceful SystemPower transition
+ * @sc: A reference to the configuration data
+ * @timeout_ms: The desired timeout to wait for the shutdown to complete before
+ *             system is forcibly shutdown.
+ *
+ * Initiates the required SystemPower transition, requesting userspace
+ * co-operation: it uses the same orderly_ methods used by ACPI Shutdown event
+ * processing.
+ *
+ * Takes care also to register a reboot notifier and to schedule a delayed work
+ * in order to detect if userspace actions are taking too long and in such a
+ * case to trigger a forceful transition.
+ */
+static void scmi_request_graceful_transition(struct scmi_syspower_conf *sc,
+                                            unsigned int timeout_ms)
+{
+       unsigned int adj_timeout_ms = 0;
+
+       if (timeout_ms) {
+               int ret;
+
+               sc->reboot_nb.notifier_call = &scmi_reboot_notifier;
+               ret = register_reboot_notifier(&sc->reboot_nb);
+               if (!ret) {
+                       /* Wait only up to 75% of the advertised timeout */
+                       adj_timeout_ms = mult_frac(timeout_ms, 3, 4);
+                       INIT_DELAYED_WORK(&sc->forceful_work,
+                                         scmi_forceful_work_func);
+                       schedule_delayed_work(&sc->forceful_work,
+                                             msecs_to_jiffies(adj_timeout_ms));
+               } else {
+                       /* Carry on best effort even without a reboot notifier */
+                       dev_warn(sc->dev,
+                                "Cannot register reboot notifier !\n");
+               }
+       }
+
+       dev_dbg(sc->dev,
+               "Serving graceful req:%d (timeout_ms:%u  adj_timeout_ms:%u)\n",
+               sc->required_transition, timeout_ms, adj_timeout_ms);
+
+       switch (sc->required_transition) {
+       case SCMI_SYSTEM_SHUTDOWN:
+               /*
+                * When triggered early at boot-time the 'orderly' call will
+                * partially fail due to the lack of userspace itself, but
+                * the force=true argument will start anyway a successful
+                * forced shutdown.
+                */
+               orderly_poweroff(true);
+               break;
+       case SCMI_SYSTEM_COLDRESET:
+       case SCMI_SYSTEM_WARMRESET:
+               orderly_reboot();
+               break;
+       default:
+               break;
+       }
+}
+
+/**
+ * scmi_userspace_notifier  - Notifier callback to act on SystemPower
+ * Notifications
+ * @nb: Reference to the related notifier block
+ * @event: The SystemPower notification event id
+ * @data: The SystemPower event report
+ *
+ * This callback is in charge of decoding the received SystemPower report
+ * and act accordingly triggering a graceful or forceful system transition.
+ *
+ * Note that once a valid SCMI SystemPower event starts being served, any
+ * other following SystemPower notification received from the same SCMI
+ * instance (handle) will be ignored.
+ *
+ * Return: NOTIFY_OK once a valid SystemPower event has been successfully
+ * processed.
+ */
+static int scmi_userspace_notifier(struct notifier_block *nb,
+                                  unsigned long event, void *data)
+{
+       struct scmi_system_power_state_notifier_report *er = data;
+       struct scmi_syspower_conf *sc = userspace_nb_to_sconf(nb);
+
+       if (er->system_state >= SCMI_SYSTEM_POWERUP) {
+               dev_err(sc->dev, "Ignoring unsupported system_state: 0x%X\n",
+                       er->system_state);
+               return NOTIFY_DONE;
+       }
+
+       if (!SCMI_SYSPOWER_IS_REQUEST_GRACEFUL(er->flags)) {
+               dev_err(sc->dev, "Ignoring forceful notification.\n");
+               return NOTIFY_DONE;
+       }
+
+       /*
+        * Bail out if system is already shutting down or an SCMI SystemPower
+        * requested is already being served.
+        */
+       if (system_state > SYSTEM_RUNNING)
+               return NOTIFY_DONE;
+       mutex_lock(&sc->state_mtx);
+       if (sc->state != SCMI_SYSPOWER_IDLE) {
+               dev_dbg(sc->dev,
+                       "Transition already in progress...ignore.\n");
+               mutex_unlock(&sc->state_mtx);
+               return NOTIFY_DONE;
+       }
+       sc->state = SCMI_SYSPOWER_IN_PROGRESS;
+       mutex_unlock(&sc->state_mtx);
+
+       sc->required_transition = er->system_state;
+
+       /* Leaving a trace in logs of who triggered the shutdown/reboot. */
+       dev_info(sc->dev, "Serving shutdown/reboot request: %d\n",
+                sc->required_transition);
+
+       scmi_request_graceful_transition(sc, er->timeout);
+
+       return NOTIFY_OK;
+}
+
+static int scmi_syspower_probe(struct scmi_device *sdev)
+{
+       int ret;
+       struct scmi_syspower_conf *sc;
+       struct scmi_handle *handle = sdev->handle;
+
+       if (!handle)
+               return -ENODEV;
+
+       ret = handle->devm_protocol_acquire(sdev, SCMI_PROTOCOL_SYSTEM);
+       if (ret)
+               return ret;
+
+       sc = devm_kzalloc(&sdev->dev, sizeof(*sc), GFP_KERNEL);
+       if (!sc)
+               return -ENOMEM;
+
+       sc->state = SCMI_SYSPOWER_IDLE;
+       mutex_init(&sc->state_mtx);
+       sc->required_transition = SCMI_SYSTEM_MAX;
+       sc->userspace_nb.notifier_call = &scmi_userspace_notifier;
+       sc->dev = &sdev->dev;
+
+       return handle->notify_ops->devm_event_notifier_register(sdev,
+                                                          SCMI_PROTOCOL_SYSTEM,
+                                        SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER,
+                                                      NULL, &sc->userspace_nb);
+}
+
+static const struct scmi_device_id scmi_id_table[] = {
+       { SCMI_PROTOCOL_SYSTEM, "syspower" },
+       { },
+};
+MODULE_DEVICE_TABLE(scmi, scmi_id_table);
+
+static struct scmi_driver scmi_system_power_driver = {
+       .name = "scmi-system-power",
+       .probe = scmi_syspower_probe,
+       .id_table = scmi_id_table,
+};
+module_scmi_driver(scmi_system_power_driver);
+
+MODULE_AUTHOR("Cristian Marussi <cristian.marussi@arm.com>");
+MODULE_DESCRIPTION("ARM SCMI SystemPower Control driver");
+MODULE_LICENSE("GPL");
index 21e0ce8..7288c61 100644 (file)
@@ -338,7 +338,6 @@ static int scmi_sensor_update_intervals(const struct scmi_protocol_handle *ph,
                                        struct scmi_sensor_info *s)
 {
        void *iter;
-       struct scmi_msg_sensor_list_update_intervals *msg;
        struct scmi_iterator_ops ops = {
                .prepare_message = iter_intervals_prepare_message,
                .update_state = iter_intervals_update_state,
@@ -351,22 +350,28 @@ static int scmi_sensor_update_intervals(const struct scmi_protocol_handle *ph,
 
        iter = ph->hops->iter_response_init(ph, &ops, s->intervals.count,
                                            SENSOR_LIST_UPDATE_INTERVALS,
-                                           sizeof(*msg), &upriv);
+                                           sizeof(struct scmi_msg_sensor_list_update_intervals),
+                                           &upriv);
        if (IS_ERR(iter))
                return PTR_ERR(iter);
 
        return ph->hops->iter_response_run(iter);
 }
 
+struct scmi_apriv {
+       bool any_axes_support_extended_names;
+       struct scmi_sensor_info *s;
+};
+
 static void iter_axes_desc_prepare_message(void *message,
                                           const unsigned int desc_index,
                                           const void *priv)
 {
        struct scmi_msg_sensor_axis_description_get *msg = message;
-       const struct scmi_sensor_info *s = priv;
+       const struct scmi_apriv *apriv = priv;
 
        /* Set the number of sensors to be skipped/already read */
-       msg->id = cpu_to_le32(s->id);
+       msg->id = cpu_to_le32(apriv->s->id);
        msg->axis_desc_index = cpu_to_le32(desc_index);
 }
 
@@ -393,19 +398,21 @@ iter_axes_desc_process_response(const struct scmi_protocol_handle *ph,
        u32 attrh, attrl;
        struct scmi_sensor_axis_info *a;
        size_t dsize = SCMI_MSG_RESP_AXIS_DESCR_BASE_SZ;
-       struct scmi_sensor_info *s = priv;
+       struct scmi_apriv *apriv = priv;
        const struct scmi_axis_descriptor *adesc = st->priv;
 
        attrl = le32_to_cpu(adesc->attributes_low);
+       if (SUPPORTS_EXTENDED_AXIS_NAMES(attrl))
+               apriv->any_axes_support_extended_names = true;
 
-       a = &s->axis[st->desc_index + st->loop_idx];
+       a = &apriv->s->axis[st->desc_index + st->loop_idx];
        a->id = le32_to_cpu(adesc->id);
        a->extended_attrs = SUPPORTS_EXTEND_ATTRS(attrl);
 
        attrh = le32_to_cpu(adesc->attributes_high);
        a->scale = S32_EXT(SENSOR_SCALE(attrh));
        a->type = SENSOR_TYPE(attrh);
-       strscpy(a->name, adesc->name, SCMI_MAX_STR_SIZE);
+       strscpy(a->name, adesc->name, SCMI_SHORT_NAME_MAX_SIZE);
 
        if (a->extended_attrs) {
                unsigned int ares = le32_to_cpu(adesc->resolution);
@@ -444,10 +451,19 @@ iter_axes_extended_name_process_response(const struct scmi_protocol_handle *ph,
                                         void *priv)
 {
        struct scmi_sensor_axis_info *a;
-       const struct scmi_sensor_info *s = priv;
+       const struct scmi_apriv *apriv = priv;
        struct scmi_sensor_axis_name_descriptor *adesc = st->priv;
+       u32 axis_id = le32_to_cpu(adesc->axis_id);
 
-       a = &s->axis[st->desc_index + st->loop_idx];
+       if (axis_id >= st->max_resources)
+               return -EPROTO;
+
+       /*
+        * Pick the corresponding descriptor based on the axis_id embedded
+        * in the reply since the list of axes supporting extended names
+        * can be a subset of all the axes.
+        */
+       a = &apriv->s->axis[axis_id];
        strscpy(a->name, adesc->name, SCMI_MAX_STR_SIZE);
        st->priv = ++adesc;
 
@@ -458,21 +474,36 @@ static int
 scmi_sensor_axis_extended_names_get(const struct scmi_protocol_handle *ph,
                                    struct scmi_sensor_info *s)
 {
+       int ret;
        void *iter;
-       struct scmi_msg_sensor_axis_description_get *msg;
        struct scmi_iterator_ops ops = {
                .prepare_message = iter_axes_desc_prepare_message,
                .update_state = iter_axes_extended_name_update_state,
                .process_response = iter_axes_extended_name_process_response,
        };
+       struct scmi_apriv apriv = {
+               .any_axes_support_extended_names = false,
+               .s = s,
+       };
 
        iter = ph->hops->iter_response_init(ph, &ops, s->num_axis,
                                            SENSOR_AXIS_NAME_GET,
-                                           sizeof(*msg), s);
+                                           sizeof(struct scmi_msg_sensor_axis_description_get),
+                                           &apriv);
        if (IS_ERR(iter))
                return PTR_ERR(iter);
 
-       return ph->hops->iter_response_run(iter);
+       /*
+        * Do not cause whole protocol initialization failure when failing to
+        * get extended names for axes.
+        */
+       ret = ph->hops->iter_response_run(iter);
+       if (ret)
+               dev_warn(ph->dev,
+                        "Failed to get axes extended names for %s (ret:%d).\n",
+                        s->name, ret);
+
+       return 0;
 }
 
 static int scmi_sensor_axis_description(const struct scmi_protocol_handle *ph,
@@ -481,12 +512,15 @@ static int scmi_sensor_axis_description(const struct scmi_protocol_handle *ph,
 {
        int ret;
        void *iter;
-       struct scmi_msg_sensor_axis_description_get *msg;
        struct scmi_iterator_ops ops = {
                .prepare_message = iter_axes_desc_prepare_message,
                .update_state = iter_axes_desc_update_state,
                .process_response = iter_axes_desc_process_response,
        };
+       struct scmi_apriv apriv = {
+               .any_axes_support_extended_names = false,
+               .s = s,
+       };
 
        s->axis = devm_kcalloc(ph->dev, s->num_axis,
                               sizeof(*s->axis), GFP_KERNEL);
@@ -495,7 +529,8 @@ static int scmi_sensor_axis_description(const struct scmi_protocol_handle *ph,
 
        iter = ph->hops->iter_response_init(ph, &ops, s->num_axis,
                                            SENSOR_AXIS_DESCRIPTION_GET,
-                                           sizeof(*msg), s);
+                                           sizeof(struct scmi_msg_sensor_axis_description_get),
+                                           &apriv);
        if (IS_ERR(iter))
                return PTR_ERR(iter);
 
@@ -503,7 +538,8 @@ static int scmi_sensor_axis_description(const struct scmi_protocol_handle *ph,
        if (ret)
                return ret;
 
-       if (PROTOCOL_REV_MAJOR(version) >= 0x3)
+       if (PROTOCOL_REV_MAJOR(version) >= 0x3 &&
+           apriv.any_axes_support_extended_names)
                ret = scmi_sensor_axis_extended_names_get(ph, s);
 
        return ret;
@@ -598,7 +634,7 @@ iter_sens_descr_process_response(const struct scmi_protocol_handle *ph,
                            SUPPORTS_AXIS(attrh) ?
                            SENSOR_AXIS_NUMBER(attrh) : 0,
                            SCMI_MAX_NUM_SENSOR_AXIS);
-       strscpy(s->name, sdesc->name, SCMI_MAX_STR_SIZE);
+       strscpy(s->name, sdesc->name, SCMI_SHORT_NAME_MAX_SIZE);
 
        /*
         * If supported overwrite short name with the extended
index 220e399..9383d75 100644 (file)
@@ -27,10 +27,12 @@ struct scmi_system_power_state_notifier_payld {
        __le32 agent_id;
        __le32 flags;
        __le32 system_state;
+       __le32 timeout;
 };
 
 struct scmi_system_info {
        u32 version;
+       bool graceful_timeout_supported;
 };
 
 static int scmi_system_request_notify(const struct scmi_protocol_handle *ph,
@@ -72,17 +74,27 @@ scmi_system_fill_custom_report(const struct scmi_protocol_handle *ph,
                               const void *payld, size_t payld_sz,
                               void *report, u32 *src_id)
 {
+       size_t expected_sz;
        const struct scmi_system_power_state_notifier_payld *p = payld;
        struct scmi_system_power_state_notifier_report *r = report;
+       struct scmi_system_info *pinfo = ph->get_priv(ph);
 
+       expected_sz = pinfo->graceful_timeout_supported ?
+                       sizeof(*p) : sizeof(*p) - sizeof(__le32);
        if (evt_id != SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER ||
-           sizeof(*p) != payld_sz)
+           payld_sz != expected_sz)
                return NULL;
 
        r->timestamp = timestamp;
        r->agent_id = le32_to_cpu(p->agent_id);
        r->flags = le32_to_cpu(p->flags);
        r->system_state = le32_to_cpu(p->system_state);
+       if (pinfo->graceful_timeout_supported &&
+           r->system_state == SCMI_SYSTEM_SHUTDOWN &&
+           SCMI_SYSPOWER_IS_REQUEST_GRACEFUL(r->flags))
+               r->timeout = le32_to_cpu(p->timeout);
+       else
+               r->timeout = 0x00;
        *src_id = 0;
 
        return r;
@@ -129,6 +141,9 @@ static int scmi_system_protocol_init(const struct scmi_protocol_handle *ph)
                return -ENOMEM;
 
        pinfo->version = version;
+       if (PROTOCOL_REV_MAJOR(pinfo->version) >= 0x2)
+               pinfo->graceful_timeout_supported = true;
+
        return ph->set_priv(ph, pinfo);
 }
 
index 9d195d8..eaa8d94 100644 (file)
@@ -180,7 +180,6 @@ static int scmi_voltage_levels_get(const struct scmi_protocol_handle *ph,
 {
        int ret;
        void *iter;
-       struct scmi_msg_cmd_describe_levels *msg;
        struct scmi_iterator_ops ops = {
                .prepare_message = iter_volt_levels_prepare_message,
                .update_state = iter_volt_levels_update_state,
@@ -193,7 +192,8 @@ static int scmi_voltage_levels_get(const struct scmi_protocol_handle *ph,
 
        iter = ph->hops->iter_response_init(ph, &ops, v->num_levels,
                                            VOLTAGE_DESCRIBE_LEVELS,
-                                           sizeof(*msg), &vpriv);
+                                           sizeof(struct scmi_msg_cmd_describe_levels),
+                                           &vpriv);
        if (IS_ERR(iter))
                return PTR_ERR(iter);
 
@@ -225,15 +225,14 @@ static int scmi_voltage_descriptors_get(const struct scmi_protocol_handle *ph,
 
                /* Retrieve domain attributes at first ... */
                put_unaligned_le32(dom, td->tx.buf);
-               ret = ph->xops->do_xfer(ph, td);
                /* Skip domain on comms error */
-               if (ret)
+               if (ph->xops->do_xfer(ph, td))
                        continue;
 
                v = vinfo->domains + dom;
                v->id = dom;
                attributes = le32_to_cpu(resp_dom->attr);
-               strlcpy(v->name, resp_dom->name, SCMI_MAX_STR_SIZE);
+               strscpy(v->name, resp_dom->name, SCMI_SHORT_NAME_MAX_SIZE);
 
                /*
                 * If supported overwrite short name with the extended one;
@@ -249,12 +248,8 @@ static int scmi_voltage_descriptors_get(const struct scmi_protocol_handle *ph,
                                v->async_level_set = true;
                }
 
-               ret = scmi_voltage_levels_get(ph, v);
                /* Skip invalid voltage descriptors */
-               if (ret)
-                       continue;
-
-               ph->xops->reset_rx_to_maxsz(ph, td);
+               scmi_voltage_levels_get(ph, v);
        }
 
        ph->xops->xfer_put(ph, td);
index ddf0b9f..435d0e2 100644 (file)
@@ -815,7 +815,7 @@ static int scpi_init_versions(struct scpi_drvinfo *info)
                info->firmware_version = le32_to_cpu(caps.platform_version);
        }
        /* Ignore error if not implemented */
-       if (scpi_info->is_legacy && ret == -EOPNOTSUPP)
+       if (info->is_legacy && ret == -EOPNOTSUPP)
                return 0;
 
        return ret;
@@ -913,13 +913,14 @@ static int scpi_probe(struct platform_device *pdev)
        struct resource res;
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
+       struct scpi_drvinfo *scpi_drvinfo;
 
-       scpi_info = devm_kzalloc(dev, sizeof(*scpi_info), GFP_KERNEL);
-       if (!scpi_info)
+       scpi_drvinfo = devm_kzalloc(dev, sizeof(*scpi_drvinfo), GFP_KERNEL);
+       if (!scpi_drvinfo)
                return -ENOMEM;
 
        if (of_match_device(legacy_scpi_of_match, &pdev->dev))
-               scpi_info->is_legacy = true;
+               scpi_drvinfo->is_legacy = true;
 
        count = of_count_phandle_with_args(np, "mboxes", "#mbox-cells");
        if (count < 0) {
@@ -927,19 +928,19 @@ static int scpi_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       scpi_info->channels = devm_kcalloc(dev, count, sizeof(struct scpi_chan),
-                                          GFP_KERNEL);
-       if (!scpi_info->channels)
+       scpi_drvinfo->channels =
+               devm_kcalloc(dev, count, sizeof(struct scpi_chan), GFP_KERNEL);
+       if (!scpi_drvinfo->channels)
                return -ENOMEM;
 
-       ret = devm_add_action(dev, scpi_free_channels, scpi_info);
+       ret = devm_add_action(dev, scpi_free_channels, scpi_drvinfo);
        if (ret)
                return ret;
 
-       for (; scpi_info->num_chans < count; scpi_info->num_chans++) {
+       for (; scpi_drvinfo->num_chans < count; scpi_drvinfo->num_chans++) {
                resource_size_t size;
-               int idx = scpi_info->num_chans;
-               struct scpi_chan *pchan = scpi_info->channels + idx;
+               int idx = scpi_drvinfo->num_chans;
+               struct scpi_chan *pchan = scpi_drvinfo->channels + idx;
                struct mbox_client *cl = &pchan->cl;
                struct device_node *shmem = of_parse_phandle(np, "shmem", idx);
 
@@ -986,45 +987,53 @@ static int scpi_probe(struct platform_device *pdev)
                return ret;
        }
 
-       scpi_info->commands = scpi_std_commands;
+       scpi_drvinfo->commands = scpi_std_commands;
 
-       platform_set_drvdata(pdev, scpi_info);
+       platform_set_drvdata(pdev, scpi_drvinfo);
 
-       if (scpi_info->is_legacy) {
+       if (scpi_drvinfo->is_legacy) {
                /* Replace with legacy variants */
                scpi_ops.clk_set_val = legacy_scpi_clk_set_val;
-               scpi_info->commands = scpi_legacy_commands;
+               scpi_drvinfo->commands = scpi_legacy_commands;
 
                /* Fill priority bitmap */
                for (idx = 0; idx < ARRAY_SIZE(legacy_hpriority_cmds); idx++)
                        set_bit(legacy_hpriority_cmds[idx],
-                               scpi_info->cmd_priority);
+                               scpi_drvinfo->cmd_priority);
        }
 
-       ret = scpi_init_versions(scpi_info);
+       scpi_info = scpi_drvinfo;
+
+       ret = scpi_init_versions(scpi_drvinfo);
        if (ret) {
                dev_err(dev, "incorrect or no SCP firmware found\n");
+               scpi_info = NULL;
                return ret;
        }
 
-       if (scpi_info->is_legacy && !scpi_info->protocol_version &&
-           !scpi_info->firmware_version)
+       if (scpi_drvinfo->is_legacy && !scpi_drvinfo->protocol_version &&
+           !scpi_drvinfo->firmware_version)
                dev_info(dev, "SCP Protocol legacy pre-1.0 firmware\n");
        else
                dev_info(dev, "SCP Protocol %lu.%lu Firmware %lu.%lu.%lu version\n",
                         FIELD_GET(PROTO_REV_MAJOR_MASK,
-                                  scpi_info->protocol_version),
+                                  scpi_drvinfo->protocol_version),
                         FIELD_GET(PROTO_REV_MINOR_MASK,
-                                  scpi_info->protocol_version),
+                                  scpi_drvinfo->protocol_version),
                         FIELD_GET(FW_REV_MAJOR_MASK,
-                                  scpi_info->firmware_version),
+                                  scpi_drvinfo->firmware_version),
                         FIELD_GET(FW_REV_MINOR_MASK,
-                                  scpi_info->firmware_version),
+                                  scpi_drvinfo->firmware_version),
                         FIELD_GET(FW_REV_PATCH_MASK,
-                                  scpi_info->firmware_version));
-       scpi_info->scpi_ops = &scpi_ops;
+                                  scpi_drvinfo->firmware_version));
+
+       scpi_drvinfo->scpi_ops = &scpi_ops;
 
-       return devm_of_platform_populate(dev);
+       ret = devm_of_platform_populate(dev);
+       if (ret)
+               scpi_info = NULL;
+
+       return ret;
 }
 
 static const struct of_device_id scpi_of_match[] = {
index 73089a2..ceae84c 100644 (file)
@@ -6,7 +6,7 @@
 #include <linux/efi.h>
 #include <linux/reboot.h>
 
-static void (*orig_pm_power_off)(void);
+static struct sys_off_handler *efi_sys_off_handler;
 
 int efi_reboot_quirk_mode = -1;
 
@@ -51,15 +51,11 @@ bool __weak efi_poweroff_required(void)
        return false;
 }
 
-static void efi_power_off(void)
+static int efi_power_off(struct sys_off_data *data)
 {
        efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL);
-       /*
-        * The above call should not return, if it does fall back to
-        * the original power off method (typically ACPI poweroff).
-        */
-       if (orig_pm_power_off)
-               orig_pm_power_off();
+
+       return NOTIFY_DONE;
 }
 
 static int __init efi_shutdown_init(void)
@@ -68,8 +64,13 @@ static int __init efi_shutdown_init(void)
                return -ENODEV;
 
        if (efi_poweroff_required()) {
-               orig_pm_power_off = pm_power_off;
-               pm_power_off = efi_power_off;
+               /* SYS_OFF_PRIO_FIRMWARE + 1 so that it runs before acpi_power_off */
+               efi_sys_off_handler =
+                       register_sys_off_handler(SYS_OFF_MODE_POWER_OFF,
+                                                SYS_OFF_PRIO_FIRMWARE + 1,
+                                                efi_power_off, NULL);
+               if (IS_ERR(efi_sys_off_handler))
+                       return PTR_ERR(efi_sys_off_handler);
        }
 
        return 0;
index 1829ba2..9f918b9 100644 (file)
@@ -120,6 +120,9 @@ static void __scm_legacy_do(const struct arm_smccc_args *smc,
 /**
  * scm_legacy_call() - Sends a command to the SCM and waits for the command to
  * finish processing.
+ * @dev:       device
+ * @desc:      descriptor structure containing arguments and return values
+ * @res:        results from SMC call
  *
  * A note on cache maintenance:
  * Note that any buffers that are expected to be accessed by the secure world
@@ -211,6 +214,7 @@ out:
 /**
  * scm_legacy_call_atomic() - Send an atomic SCM command with up to 5 arguments
  * and 3 return values
+ * @unused: device, legacy argument, not used, can be NULL
  * @desc: SCM call descriptor containing arguments
  * @res:  SCM call return values
  *
index 3163660..cdbfe54 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/cpumask.h>
 #include <linux/export.h>
 #include <linux/dma-mapping.h>
+#include <linux/interconnect.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/qcom_scm.h>
@@ -31,8 +32,13 @@ struct qcom_scm {
        struct clk *core_clk;
        struct clk *iface_clk;
        struct clk *bus_clk;
+       struct icc_path *path;
        struct reset_controller_dev reset;
 
+       /* control access to the interconnect path */
+       struct mutex scm_bw_lock;
+       int scm_vote_count;
+
        u64 dload_mode_addr;
 };
 
@@ -99,6 +105,42 @@ static void qcom_scm_clk_disable(void)
        clk_disable_unprepare(__scm->bus_clk);
 }
 
+static int qcom_scm_bw_enable(void)
+{
+       int ret = 0;
+
+       if (!__scm->path)
+               return 0;
+
+       if (IS_ERR(__scm->path))
+               return -EINVAL;
+
+       mutex_lock(&__scm->scm_bw_lock);
+       if (!__scm->scm_vote_count) {
+               ret = icc_set_bw(__scm->path, 0, UINT_MAX);
+               if (ret < 0) {
+                       dev_err(__scm->dev, "failed to set bandwidth request\n");
+                       goto err_bw;
+               }
+       }
+       __scm->scm_vote_count++;
+err_bw:
+       mutex_unlock(&__scm->scm_bw_lock);
+
+       return ret;
+}
+
+static void qcom_scm_bw_disable(void)
+{
+       if (IS_ERR_OR_NULL(__scm->path))
+               return;
+
+       mutex_lock(&__scm->scm_bw_lock);
+       if (__scm->scm_vote_count-- == 1)
+               icc_set_bw(__scm->path, 0, 0);
+       mutex_unlock(&__scm->scm_bw_lock);
+}
+
 enum qcom_scm_convention qcom_scm_convention = SMC_CONVENTION_UNKNOWN;
 static DEFINE_SPINLOCK(scm_query_lock);
 
@@ -444,10 +486,15 @@ int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size,
        if (ret)
                goto out;
 
+       ret = qcom_scm_bw_enable();
+       if (ret)
+               return ret;
+
        desc.args[1] = mdata_phys;
 
        ret = qcom_scm_call(__scm->dev, &desc, &res);
 
+       qcom_scm_bw_disable();
        qcom_scm_clk_disable();
 
 out:
@@ -507,7 +554,12 @@ int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size)
        if (ret)
                return ret;
 
+       ret = qcom_scm_bw_enable();
+       if (ret)
+               return ret;
+
        ret = qcom_scm_call(__scm->dev, &desc, &res);
+       qcom_scm_bw_disable();
        qcom_scm_clk_disable();
 
        return ret ? : res.result[0];
@@ -537,7 +589,12 @@ int qcom_scm_pas_auth_and_reset(u32 peripheral)
        if (ret)
                return ret;
 
+       ret = qcom_scm_bw_enable();
+       if (ret)
+               return ret;
+
        ret = qcom_scm_call(__scm->dev, &desc, &res);
+       qcom_scm_bw_disable();
        qcom_scm_clk_disable();
 
        return ret ? : res.result[0];
@@ -566,8 +623,13 @@ int qcom_scm_pas_shutdown(u32 peripheral)
        if (ret)
                return ret;
 
+       ret = qcom_scm_bw_enable();
+       if (ret)
+               return ret;
+
        ret = qcom_scm_call(__scm->dev, &desc, &res);
 
+       qcom_scm_bw_disable();
        qcom_scm_clk_disable();
 
        return ret ? : res.result[0];
@@ -1277,8 +1339,15 @@ static int qcom_scm_probe(struct platform_device *pdev)
        if (ret < 0)
                return ret;
 
+       mutex_init(&scm->scm_bw_lock);
+
        clks = (unsigned long)of_device_get_match_data(&pdev->dev);
 
+       scm->path = devm_of_icc_get(&pdev->dev, NULL);
+       if (IS_ERR(scm->path))
+               return dev_err_probe(&pdev->dev, PTR_ERR(scm->path),
+                                    "failed to acquire interconnect path\n");
+
        scm->core_clk = devm_clk_get(&pdev->dev, "core");
        if (IS_ERR(scm->core_clk)) {
                if (PTR_ERR(scm->core_clk) == -EPROBE_DEFER)
@@ -1337,7 +1406,7 @@ static int qcom_scm_probe(struct platform_device *pdev)
 
        /*
         * If requested enable "download mode", from this point on warmboot
-        * will cause the the boot stages to enter download mode, unless
+        * will cause the boot stages to enter download mode, unless
         * disabled below by a clean shutdown/reboot.
         */
        if (download_mode)
index 2bfbb05..1f276f1 100644 (file)
 #include <linux/screen_info.h>
 #include <linux/sysfb.h>
 
+static struct platform_device *pd;
+static DEFINE_MUTEX(disable_lock);
+static bool disabled;
+
+static bool sysfb_unregister(void)
+{
+       if (IS_ERR_OR_NULL(pd))
+               return false;
+
+       platform_device_unregister(pd);
+       pd = NULL;
+
+       return true;
+}
+
+/**
+ * sysfb_disable() - disable the Generic System Framebuffers support
+ *
+ * This disables the registration of system framebuffer devices that match the
+ * generic drivers that make use of the system framebuffer set up by firmware.
+ *
+ * It also unregisters a device if this was already registered by sysfb_init().
+ *
+ * Context: The function can sleep. A @disable_lock mutex is acquired to serialize
+ *          against sysfb_init(), that registers a system framebuffer device.
+ */
+void sysfb_disable(void)
+{
+       mutex_lock(&disable_lock);
+       sysfb_unregister();
+       disabled = true;
+       mutex_unlock(&disable_lock);
+}
+EXPORT_SYMBOL_GPL(sysfb_disable);
+
 static __init int sysfb_init(void)
 {
        struct screen_info *si = &screen_info;
        struct simplefb_platform_data mode;
-       struct platform_device *pd;
        const char *name;
        bool compatible;
-       int ret;
+       int ret = 0;
+
+       mutex_lock(&disable_lock);
+       if (disabled)
+               goto unlock_mutex;
 
        /* try to create a simple-framebuffer device */
        compatible = sysfb_parse_mode(si, &mode);
        if (compatible) {
-               ret = sysfb_create_simplefb(si, &mode);
-               if (!ret)
-                       return 0;
+               pd = sysfb_create_simplefb(si, &mode);
+               if (!IS_ERR(pd))
+                       goto unlock_mutex;
        }
 
        /* if the FB is incompatible, create a legacy framebuffer device */
@@ -60,8 +98,10 @@ static __init int sysfb_init(void)
                name = "platform-framebuffer";
 
        pd = platform_device_alloc(name, 0);
-       if (!pd)
-               return -ENOMEM;
+       if (!pd) {
+               ret = -ENOMEM;
+               goto unlock_mutex;
+       }
 
        sysfb_apply_efi_quirks(pd);
 
@@ -73,9 +113,11 @@ static __init int sysfb_init(void)
        if (ret)
                goto err;
 
-       return 0;
+       goto unlock_mutex;
 err:
        platform_device_put(pd);
+unlock_mutex:
+       mutex_unlock(&disable_lock);
        return ret;
 }
 
index bda8712..a353e27 100644 (file)
@@ -57,8 +57,8 @@ __init bool sysfb_parse_mode(const struct screen_info *si,
        return false;
 }
 
-__init int sysfb_create_simplefb(const struct screen_info *si,
-                                const struct simplefb_platform_data *mode)
+__init struct platform_device *sysfb_create_simplefb(const struct screen_info *si,
+                                                    const struct simplefb_platform_data *mode)
 {
        struct platform_device *pd;
        struct resource res;
@@ -76,7 +76,7 @@ __init int sysfb_create_simplefb(const struct screen_info *si,
                base |= (u64)si->ext_lfb_base << 32;
        if (!base || (u64)(resource_size_t)base != base) {
                printk(KERN_DEBUG "sysfb: inaccessible VRAM base\n");
-               return -EINVAL;
+               return ERR_PTR(-EINVAL);
        }
 
        /*
@@ -93,7 +93,7 @@ __init int sysfb_create_simplefb(const struct screen_info *si,
        length = mode->height * mode->stride;
        if (length > size) {
                printk(KERN_WARNING "sysfb: VRAM smaller than advertised\n");
-               return -EINVAL;
+               return ERR_PTR(-EINVAL);
        }
        length = PAGE_ALIGN(length);
 
@@ -104,11 +104,11 @@ __init int sysfb_create_simplefb(const struct screen_info *si,
        res.start = base;
        res.end = res.start + length - 1;
        if (res.end <= res.start)
-               return -EINVAL;
+               return ERR_PTR(-EINVAL);
 
        pd = platform_device_alloc("simple-framebuffer", 0);
        if (!pd)
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
 
        sysfb_apply_efi_quirks(pd);
 
@@ -124,10 +124,10 @@ __init int sysfb_create_simplefb(const struct screen_info *si,
        if (ret)
                goto err_put_device;
 
-       return 0;
+       return pd;
 
 err_put_device:
        platform_device_put(pd);
 
-       return ret;
+       return ERR_PTR(ret);
 }
index fd89899..0c440af 100644 (file)
@@ -474,7 +474,7 @@ static int bpmp_populate_debugfs_inband(struct tegra_bpmp *bpmp,
                        mode |= attrs & DEBUGFS_S_IWUSR ? 0200 : 0;
                        dentry = debugfs_create_file(name, mode, parent, bpmp,
                                                     &bpmp_debug_fops);
-                       if (!dentry) {
+                       if (IS_ERR(dentry)) {
                                err = -ENOMEM;
                                goto out;
                        }
@@ -725,7 +725,7 @@ static int bpmp_populate_dir(struct tegra_bpmp *bpmp, struct seqbuf *seqbuf,
 
                if (t & DEBUGFS_S_ISDIR) {
                        dentry = debugfs_create_dir(name, parent);
-                       if (!dentry)
+                       if (IS_ERR(dentry))
                                return -ENOMEM;
                        err = bpmp_populate_dir(bpmp, seqbuf, dentry, depth+1);
                        if (err < 0)
@@ -738,7 +738,7 @@ static int bpmp_populate_dir(struct tegra_bpmp *bpmp, struct seqbuf *seqbuf,
                        dentry = debugfs_create_file(name, mode,
                                                     parent, bpmp,
                                                     &debugfs_fops);
-                       if (!dentry)
+                       if (IS_ERR(dentry))
                                return -ENOMEM;
                }
        }
@@ -788,11 +788,11 @@ int tegra_bpmp_init_debugfs(struct tegra_bpmp *bpmp)
                return 0;
 
        root = debugfs_create_dir("bpmp", NULL);
-       if (!root)
+       if (IS_ERR(root))
                return -ENOMEM;
 
        bpmp->debugfs_mirror = debugfs_create_dir("debug", root);
-       if (!bpmp->debugfs_mirror) {
+       if (IS_ERR(bpmp->debugfs_mirror)) {
                err = -ENOMEM;
                goto out;
        }
index 5654c5e..037db21 100644 (file)
@@ -201,7 +201,7 @@ static ssize_t __tegra_bpmp_channel_read(struct tegra_bpmp_channel *channel,
        int err;
 
        if (data && size > 0)
-               memcpy(data, channel->ib->data, size);
+               memcpy_fromio(data, channel->ib->data, size);
 
        err = tegra_bpmp_ack_response(channel);
        if (err < 0)
@@ -245,7 +245,7 @@ static ssize_t __tegra_bpmp_channel_write(struct tegra_bpmp_channel *channel,
        channel->ob->flags = flags;
 
        if (data && size > 0)
-               memcpy(channel->ob->data, data, size);
+               memcpy_toio(channel->ob->data, data, size);
 
        return tegra_bpmp_post_request(channel);
 }
@@ -420,7 +420,7 @@ void tegra_bpmp_mrq_return(struct tegra_bpmp_channel *channel, int code,
        channel->ob->code = code;
 
        if (data && size > 0)
-               memcpy(channel->ob->data, data, size);
+               memcpy_toio(channel->ob->data, data, size);
 
        err = tegra_bpmp_post_response(channel);
        if (WARN_ON(err < 0))
index 7977a49..d1f6528 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Xilinx Zynq MPSoC Firmware layer
  *
- *  Copyright (C) 2014-2021 Xilinx, Inc.
+ *  Copyright (C) 2014-2022 Xilinx, Inc.
  *
  *  Michal Simek <michal.simek@xilinx.com>
  *  Davorin Mista <davorin.mista@aggios.com>
@@ -340,6 +340,20 @@ int zynqmp_pm_invoke_fn(u32 pm_api_id, u32 arg0, u32 arg1,
 static u32 pm_api_version;
 static u32 pm_tz_version;
 
+int zynqmp_pm_register_sgi(u32 sgi_num, u32 reset)
+{
+       int ret;
+
+       ret = zynqmp_pm_invoke_fn(TF_A_PM_REGISTER_SGI, sgi_num, reset, 0, 0,
+                                 NULL);
+       if (!ret)
+               return ret;
+
+       /* try old implementation as fallback strategy if above fails */
+       return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_REGISTER_SGI, sgi_num,
+                                  reset, NULL);
+}
+
 /**
  * zynqmp_pm_get_api_version() - Get version number of PMU PM firmware
  * @version:   Returned version value
index b2c90bd..52d7b8d 100644 (file)
@@ -550,15 +550,12 @@ static struct irq_chip msc313_gpio_irqchip = {
  * so we need to provide the fwspec. Essentially gpiochip_populate_parent_fwspec_twocell
  * that puts GIC_SPI into the first cell.
  */
-static void *msc313_gpio_populate_parent_fwspec(struct gpio_chip *gc,
-                                            unsigned int parent_hwirq,
-                                            unsigned int parent_type)
+static int msc313_gpio_populate_parent_fwspec(struct gpio_chip *gc,
+                                             union gpio_irq_fwspec *gfwspec,
+                                             unsigned int parent_hwirq,
+                                             unsigned int parent_type)
 {
-       struct irq_fwspec *fwspec;
-
-       fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL);
-       if (!fwspec)
-               return NULL;
+       struct irq_fwspec *fwspec = &gfwspec->fwspec;
 
        fwspec->fwnode = gc->irq.parent_domain->fwnode;
        fwspec->param_count = 3;
@@ -566,7 +563,7 @@ static void *msc313_gpio_populate_parent_fwspec(struct gpio_chip *gc,
        fwspec->param[1] = parent_hwirq;
        fwspec->param[2] = parent_type;
 
-       return fwspec;
+       return 0;
 }
 
 static int msc313e_gpio_child_to_parent_hwirq(struct gpio_chip *chip,
index 08bc52c..ecd7d16 100644 (file)
@@ -351,6 +351,9 @@ static const struct regmap_config pca953x_i2c_regmap = {
        .reg_bits = 8,
        .val_bits = 8,
 
+       .use_single_read = true,
+       .use_single_write = true,
+
        .readable_reg = pca953x_readable_register,
        .writeable_reg = pca953x_writeable_register,
        .volatile_reg = pca953x_volatile_register,
@@ -906,15 +909,18 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
 static int device_pca95xx_init(struct pca953x_chip *chip, u32 invert)
 {
        DECLARE_BITMAP(val, MAX_LINE);
+       u8 regaddr;
        int ret;
 
-       ret = regcache_sync_region(chip->regmap, chip->regs->output,
-                                  chip->regs->output + NBANK(chip));
+       regaddr = pca953x_recalc_addr(chip, chip->regs->output, 0);
+       ret = regcache_sync_region(chip->regmap, regaddr,
+                                  regaddr + NBANK(chip) - 1);
        if (ret)
                goto out;
 
-       ret = regcache_sync_region(chip->regmap, chip->regs->direction,
-                                  chip->regs->direction + NBANK(chip));
+       regaddr = pca953x_recalc_addr(chip, chip->regs->direction, 0);
+       ret = regcache_sync_region(chip->regmap, regaddr,
+                                  regaddr + NBANK(chip) - 1);
        if (ret)
                goto out;
 
@@ -1127,14 +1133,14 @@ static int pca953x_regcache_sync(struct device *dev)
         * sync these registers first and only then sync the rest.
         */
        regaddr = pca953x_recalc_addr(chip, chip->regs->direction, 0);
-       ret = regcache_sync_region(chip->regmap, regaddr, regaddr + NBANK(chip));
+       ret = regcache_sync_region(chip->regmap, regaddr, regaddr + NBANK(chip) - 1);
        if (ret) {
                dev_err(dev, "Failed to sync GPIO dir registers: %d\n", ret);
                return ret;
        }
 
        regaddr = pca953x_recalc_addr(chip, chip->regs->output, 0);
-       ret = regcache_sync_region(chip->regmap, regaddr, regaddr + NBANK(chip));
+       ret = regcache_sync_region(chip->regmap, regaddr, regaddr + NBANK(chip) - 1);
        if (ret) {
                dev_err(dev, "Failed to sync GPIO out registers: %d\n", ret);
                return ret;
@@ -1144,7 +1150,7 @@ static int pca953x_regcache_sync(struct device *dev)
        if (chip->driver_data & PCA_PCAL) {
                regaddr = pca953x_recalc_addr(chip, PCAL953X_IN_LATCH, 0);
                ret = regcache_sync_region(chip->regmap, regaddr,
-                                          regaddr + NBANK(chip));
+                                          regaddr + NBANK(chip) - 1);
                if (ret) {
                        dev_err(dev, "Failed to sync INT latch registers: %d\n",
                                ret);
@@ -1153,7 +1159,7 @@ static int pca953x_regcache_sync(struct device *dev)
 
                regaddr = pca953x_recalc_addr(chip, PCAL953X_INT_MASK, 0);
                ret = regcache_sync_region(chip->regmap, regaddr,
-                                          regaddr + NBANK(chip));
+                                          regaddr + NBANK(chip) - 1);
                if (ret) {
                        dev_err(dev, "Failed to sync INT mask registers: %d\n",
                                ret);
index 9810983..1020c2f 100644 (file)
@@ -991,28 +991,22 @@ static struct configfs_attribute *gpio_sim_device_config_attrs[] = {
 };
 
 struct gpio_sim_chip_name_ctx {
-       struct gpio_sim_device *dev;
+       struct fwnode_handle *swnode;
        char *page;
 };
 
 static int gpio_sim_emit_chip_name(struct device *dev, void *data)
 {
        struct gpio_sim_chip_name_ctx *ctx = data;
-       struct fwnode_handle *swnode;
-       struct gpio_sim_bank *bank;
 
        /* This would be the sysfs device exported in /sys/class/gpio. */
        if (dev->class)
                return 0;
 
-       swnode = dev_fwnode(dev);
+       if (device_match_fwnode(dev, ctx->swnode))
+               return sprintf(ctx->page, "%s\n", dev_name(dev));
 
-       list_for_each_entry(bank, &ctx->dev->bank_list, siblings) {
-               if (bank->swnode == swnode)
-                       return sprintf(ctx->page, "%s\n", dev_name(dev));
-       }
-
-       return -ENODATA;
+       return 0;
 }
 
 static ssize_t gpio_sim_bank_config_chip_name_show(struct config_item *item,
@@ -1020,7 +1014,7 @@ static ssize_t gpio_sim_bank_config_chip_name_show(struct config_item *item,
 {
        struct gpio_sim_bank *bank = to_gpio_sim_bank(item);
        struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank);
-       struct gpio_sim_chip_name_ctx ctx = { dev, page };
+       struct gpio_sim_chip_name_ctx ctx = { bank->swnode, page };
        int ret;
 
        mutex_lock(&dev->lock);
index ff2d2a1..e4fb4cb 100644 (file)
@@ -443,15 +443,12 @@ static int tegra_gpio_child_to_parent_hwirq(struct gpio_chip *chip,
        return 0;
 }
 
-static void *tegra_gpio_populate_parent_fwspec(struct gpio_chip *chip,
-                                              unsigned int parent_hwirq,
-                                              unsigned int parent_type)
+static int tegra_gpio_populate_parent_fwspec(struct gpio_chip *chip,
+                                            union gpio_irq_fwspec *gfwspec,
+                                            unsigned int parent_hwirq,
+                                            unsigned int parent_type)
 {
-       struct irq_fwspec *fwspec;
-
-       fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL);
-       if (!fwspec)
-               return NULL;
+       struct irq_fwspec *fwspec = &gfwspec->fwspec;
 
        fwspec->fwnode = chip->irq.parent_domain->fwnode;
        fwspec->param_count = 3;
@@ -459,7 +456,7 @@ static void *tegra_gpio_populate_parent_fwspec(struct gpio_chip *chip,
        fwspec->param[1] = parent_hwirq;
        fwspec->param[2] = parent_type;
 
-       return fwspec;
+       return 0;
 }
 
 #ifdef CONFIG_PM_SLEEP
index de28a68..54d9fa7 100644 (file)
@@ -621,16 +621,13 @@ static int tegra186_gpio_irq_domain_translate(struct irq_domain *domain,
        return 0;
 }
 
-static void *tegra186_gpio_populate_parent_fwspec(struct gpio_chip *chip,
-                                                unsigned int parent_hwirq,
-                                                unsigned int parent_type)
+static int tegra186_gpio_populate_parent_fwspec(struct gpio_chip *chip,
+                                               union gpio_irq_fwspec *gfwspec,
+                                               unsigned int parent_hwirq,
+                                               unsigned int parent_type)
 {
        struct tegra_gpio *gpio = gpiochip_get_data(chip);
-       struct irq_fwspec *fwspec;
-
-       fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL);
-       if (!fwspec)
-               return NULL;
+       struct irq_fwspec *fwspec = &gfwspec->fwspec;
 
        fwspec->fwnode = chip->irq.parent_domain->fwnode;
        fwspec->param_count = 3;
@@ -638,7 +635,7 @@ static void *tegra186_gpio_populate_parent_fwspec(struct gpio_chip *chip,
        fwspec->param[1] = parent_hwirq;
        fwspec->param[2] = parent_type;
 
-       return fwspec;
+       return 0;
 }
 
 static int tegra186_gpio_child_to_parent_hwirq(struct gpio_chip *chip,
index 9f66dea..cc62c6e 100644 (file)
@@ -15,8 +15,6 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/spinlock.h>
-#include <asm-generic/msi.h>
-
 
 #define GPIO_RX_DAT    0x0
 #define GPIO_TX_SET    0x8
@@ -408,18 +406,15 @@ static int thunderx_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
        return 0;
 }
 
-static void *thunderx_gpio_populate_parent_alloc_info(struct gpio_chip *chip,
-                                                     unsigned int parent_hwirq,
-                                                     unsigned int parent_type)
+static int thunderx_gpio_populate_parent_alloc_info(struct gpio_chip *chip,
+                                                   union gpio_irq_fwspec *gfwspec,
+                                                   unsigned int parent_hwirq,
+                                                   unsigned int parent_type)
 {
-       msi_alloc_info_t *info;
-
-       info = kmalloc(sizeof(*info), GFP_KERNEL);
-       if (!info)
-               return NULL;
+       msi_alloc_info_t *info = &gfwspec->msiinfo;
 
        info->hwirq = parent_hwirq;
-       return info;
+       return 0;
 }
 
 static int thunderx_gpio_probe(struct pci_dev *pdev,
index 23cddb2..9db42f6 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_irq.h>
+#include <linux/pinctrl/consumer.h>
 
 #define VF610_GPIO_PER_PORT            32
 
index e6534ea..5e108ba 100644 (file)
@@ -103,15 +103,12 @@ static int visconti_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
        return -EINVAL;
 }
 
-static void *visconti_gpio_populate_parent_fwspec(struct gpio_chip *chip,
-                                                 unsigned int parent_hwirq,
-                                                 unsigned int parent_type)
+static int visconti_gpio_populate_parent_fwspec(struct gpio_chip *chip,
+                                               union gpio_irq_fwspec *gfwspec,
+                                               unsigned int parent_hwirq,
+                                               unsigned int parent_type)
 {
-       struct irq_fwspec *fwspec;
-
-       fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL);
-       if (!fwspec)
-               return NULL;
+       struct irq_fwspec *fwspec = &gfwspec->fwspec;
 
        fwspec->fwnode = chip->irq.parent_domain->fwnode;
        fwspec->param_count = 3;
@@ -119,7 +116,7 @@ static void *visconti_gpio_populate_parent_fwspec(struct gpio_chip *chip,
        fwspec->param[1] = parent_hwirq;
        fwspec->param[2] = parent_type;
 
-       return fwspec;
+       return 0;
 }
 
 static int visconti_gpio_probe(struct platform_device *pdev)
index b6d3a57..7f8e2fe 100644 (file)
@@ -99,7 +99,7 @@ static inline void xgpio_set_value32(unsigned long *map, int bit, u32 v)
        const unsigned long offset = (bit % BITS_PER_LONG) & BIT(5);
 
        map[index] &= ~(0xFFFFFFFFul << offset);
-       map[index] |= v << offset;
+       map[index] |= (unsigned long)v << offset;
 }
 
 static inline int xgpio_regoffset(struct xgpio_instance *chip, int ch)
index f5aa5f9..b26e643 100644 (file)
@@ -421,6 +421,10 @@ out_free_lh:
  * @work: the worker that implements software debouncing
  * @sw_debounced: flag indicating if the software debouncer is active
  * @level: the current debounced physical level of the line
+ * @hdesc: the Hardware Timestamp Engine (HTE) descriptor
+ * @raw_level: the line level at the time of event
+ * @total_discard_seq: the running counter of the discarded events
+ * @last_seqno: the last sequence number before debounce period expires
  */
 struct line {
        struct gpio_desc *desc;
@@ -1460,11 +1464,12 @@ static ssize_t linereq_read(struct file *file,
 static void linereq_free(struct linereq *lr)
 {
        unsigned int i;
-       bool hte;
+       bool hte = false;
 
        for (i = 0; i < lr->num_lines; i++) {
-               hte = !!test_bit(FLAG_EVENT_CLOCK_HTE,
-                                &lr->lines[i].desc->flags);
+               if (lr->lines[i].desc)
+                       hte = !!test_bit(FLAG_EVENT_CLOCK_HTE,
+                                        &lr->lines[i].desc->flags);
                edge_detector_stop(&lr->lines[i], hte);
                if (lr->lines[i].desc)
                        gpiod_free(lr->lines[i].desc);
index 9535f48..68d9f95 100644 (file)
@@ -1107,7 +1107,7 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d,
        irq_hw_number_t hwirq;
        unsigned int type = IRQ_TYPE_NONE;
        struct irq_fwspec *fwspec = data;
-       void *parent_arg;
+       union gpio_irq_fwspec gpio_parent_fwspec = {};
        unsigned int parent_hwirq;
        unsigned int parent_type;
        struct gpio_irq_chip *girq = &gc->irq;
@@ -1147,14 +1147,15 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d,
        irq_set_probe(irq);
 
        /* This parent only handles asserted level IRQs */
-       parent_arg = girq->populate_parent_alloc_arg(gc, parent_hwirq, parent_type);
-       if (!parent_arg)
-               return -ENOMEM;
+       ret = girq->populate_parent_alloc_arg(gc, &gpio_parent_fwspec,
+                                             parent_hwirq, parent_type);
+       if (ret)
+               return ret;
 
        chip_dbg(gc, "alloc_irqs_parent for %d parent hwirq %d\n",
                  irq, parent_hwirq);
        irq_set_lockdep_class(irq, gc->irq.lock_key, gc->irq.request_key);
-       ret = irq_domain_alloc_irqs_parent(d, irq, 1, parent_arg);
+       ret = irq_domain_alloc_irqs_parent(d, irq, 1, &gpio_parent_fwspec);
        /*
         * If the parent irqdomain is msi, the interrupts have already
         * been allocated, so the EEXIST is good.
@@ -1166,7 +1167,6 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d,
                         "failed to allocate parent hwirq %d for hwirq %lu\n",
                         parent_hwirq, hwirq);
 
-       kfree(parent_arg);
        return ret;
 }
 
@@ -1181,15 +1181,18 @@ static void gpiochip_hierarchy_setup_domain_ops(struct irq_domain_ops *ops)
        ops->activate = gpiochip_irq_domain_activate;
        ops->deactivate = gpiochip_irq_domain_deactivate;
        ops->alloc = gpiochip_hierarchy_irq_domain_alloc;
-       ops->free = irq_domain_free_irqs_common;
 
        /*
-        * We only allow overriding the translate() function for
+        * We only allow overriding the translate() and free() functions for
         * hierarchical chips, and this should only be done if the user
-        * really need something other than 1:1 translation.
+        * really need something other than 1:1 translation for translate()
+        * callback and free if user wants to free up any resources which
+        * were allocated during callbacks, for example populate_parent_alloc_arg.
         */
        if (!ops->translate)
                ops->translate = gpiochip_hierarchy_irq_domain_translate;
+       if (!ops->free)
+               ops->free = irq_domain_free_irqs_common;
 }
 
 static int gpiochip_hierarchy_add_domain(struct gpio_chip *gc)
@@ -1230,34 +1233,28 @@ static bool gpiochip_hierarchy_is_hierarchical(struct gpio_chip *gc)
        return !!gc->irq.parent_domain;
 }
 
-void *gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *gc,
-                                            unsigned int parent_hwirq,
-                                            unsigned int parent_type)
+int gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *gc,
+                                           union gpio_irq_fwspec *gfwspec,
+                                           unsigned int parent_hwirq,
+                                           unsigned int parent_type)
 {
-       struct irq_fwspec *fwspec;
-
-       fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL);
-       if (!fwspec)
-               return NULL;
+       struct irq_fwspec *fwspec = &gfwspec->fwspec;
 
        fwspec->fwnode = gc->irq.parent_domain->fwnode;
        fwspec->param_count = 2;
        fwspec->param[0] = parent_hwirq;
        fwspec->param[1] = parent_type;
 
-       return fwspec;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(gpiochip_populate_parent_fwspec_twocell);
 
-void *gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *gc,
-                                             unsigned int parent_hwirq,
-                                             unsigned int parent_type)
+int gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *gc,
+                                            union gpio_irq_fwspec *gfwspec,
+                                            unsigned int parent_hwirq,
+                                            unsigned int parent_type)
 {
-       struct irq_fwspec *fwspec;
-
-       fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL);
-       if (!fwspec)
-               return NULL;
+       struct irq_fwspec *fwspec = &gfwspec->fwspec;
 
        fwspec->fwnode = gc->irq.parent_domain->fwnode;
        fwspec->param_count = 4;
@@ -1266,7 +1263,7 @@ void *gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *gc,
        fwspec->param[2] = 0;
        fwspec->param[3] = parent_type;
 
-       return fwspec;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(gpiochip_populate_parent_fwspec_fourcell);
 
index e88c497..f65656d 100644 (file)
@@ -256,7 +256,6 @@ config DRM_AMDGPU
        select HWMON
        select BACKLIGHT_CLASS_DEVICE
        select INTERVAL_TREE
-       select DRM_BUDDY
        help
          Choose this option if you have a recent AMD Radeon graphics card.
 
index 1f8161c..3b1c675 100644 (file)
@@ -714,7 +714,8 @@ int amdgpu_amdkfd_flush_gpu_tlb_pasid(struct amdgpu_device *adev,
 {
        bool all_hub = false;
 
-       if (adev->family == AMDGPU_FAMILY_AI)
+       if (adev->family == AMDGPU_FAMILY_AI ||
+           adev->family == AMDGPU_FAMILY_RV)
                all_hub = true;
 
        return amdgpu_gmc_flush_gpu_tlb_pasid(adev, pasid, flush_type, all_hub);
index 6b6d46e..4608599 100644 (file)
@@ -1364,16 +1364,10 @@ void amdgpu_amdkfd_gpuvm_destroy_cb(struct amdgpu_device *adev,
                                    struct amdgpu_vm *vm)
 {
        struct amdkfd_process_info *process_info = vm->process_info;
-       struct amdgpu_bo *pd = vm->root.bo;
 
        if (!process_info)
                return;
 
-       /* Release eviction fence from PD */
-       amdgpu_bo_reserve(pd, false);
-       amdgpu_bo_fence(pd, NULL, false);
-       amdgpu_bo_unreserve(pd);
-
        /* Update process info */
        mutex_lock(&process_info->lock);
        process_info->n_vms--;
index 714178f..2168163 100644 (file)
@@ -40,7 +40,7 @@ static void amdgpu_bo_list_free_rcu(struct rcu_head *rcu)
 {
        struct amdgpu_bo_list *list = container_of(rcu, struct amdgpu_bo_list,
                                                   rhead);
-
+       mutex_destroy(&list->bo_list_mutex);
        kvfree(list);
 }
 
@@ -136,6 +136,7 @@ int amdgpu_bo_list_create(struct amdgpu_device *adev, struct drm_file *filp,
 
        trace_amdgpu_cs_bo_status(list->num_entries, total_size);
 
+       mutex_init(&list->bo_list_mutex);
        *result = list;
        return 0;
 
index 529d52a..9caea16 100644 (file)
@@ -47,6 +47,10 @@ struct amdgpu_bo_list {
        struct amdgpu_bo *oa_obj;
        unsigned first_userptr;
        unsigned num_entries;
+
+       /* Protect access during command submission.
+        */
+       struct mutex bo_list_mutex;
 };
 
 int amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id,
index b28af04..d8f1335 100644 (file)
@@ -519,6 +519,8 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
                        return r;
        }
 
+       mutex_lock(&p->bo_list->bo_list_mutex);
+
        /* One for TTM and one for the CS job */
        amdgpu_bo_list_for_each_entry(e, p->bo_list)
                e->tv.num_shared = 2;
@@ -651,6 +653,7 @@ out_free_user_pages:
                        kvfree(e->user_pages);
                        e->user_pages = NULL;
                }
+               mutex_unlock(&p->bo_list->bo_list_mutex);
        }
        return r;
 }
@@ -690,9 +693,11 @@ static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error,
 {
        unsigned i;
 
-       if (error && backoff)
+       if (error && backoff) {
                ttm_eu_backoff_reservation(&parser->ticket,
                                           &parser->validated);
+               mutex_unlock(&parser->bo_list->bo_list_mutex);
+       }
 
        for (i = 0; i < parser->num_post_deps; i++) {
                drm_syncobj_put(parser->post_deps[i].syncobj);
@@ -832,12 +837,16 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
                        continue;
 
                r = amdgpu_vm_bo_update(adev, bo_va, false);
-               if (r)
+               if (r) {
+                       mutex_unlock(&p->bo_list->bo_list_mutex);
                        return r;
+               }
 
                r = amdgpu_sync_fence(&p->job->sync, bo_va->last_pt_update);
-               if (r)
+               if (r) {
+                       mutex_unlock(&p->bo_list->bo_list_mutex);
                        return r;
+               }
        }
 
        r = amdgpu_vm_handle_moved(adev, vm);
@@ -1278,6 +1287,7 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
 
        ttm_eu_fence_buffer_objects(&p->ticket, &p->validated, p->fence);
        mutex_unlock(&p->adev->notifier_lock);
+       mutex_unlock(&p->bo_list->bo_list_mutex);
 
        return 0;
 
index 625424f..58df107 100644 (file)
@@ -5164,7 +5164,7 @@ int amdgpu_device_gpu_recover_imp(struct amdgpu_device *adev,
                 */
                amdgpu_unregister_gpu_instance(tmp_adev);
 
-               drm_fb_helper_set_suspend_unlocked(adev_to_drm(adev)->fb_helper, true);
+               drm_fb_helper_set_suspend_unlocked(adev_to_drm(tmp_adev)->fb_helper, true);
 
                /* disable ras on ALL IPs */
                if (!need_emergency_restart &&
index 17c9bbe..4dfd672 100644 (file)
@@ -1528,6 +1528,21 @@ bool amdgpu_crtc_get_scanout_position(struct drm_crtc *crtc,
                                                  stime, etime, mode);
 }
 
+static bool
+amdgpu_display_robj_is_fb(struct amdgpu_device *adev, struct amdgpu_bo *robj)
+{
+       struct drm_device *dev = adev_to_drm(adev);
+       struct drm_fb_helper *fb_helper = dev->fb_helper;
+
+       if (!fb_helper || !fb_helper->buffer)
+               return false;
+
+       if (gem_to_amdgpu_bo(fb_helper->buffer->gem) != robj)
+               return false;
+
+       return true;
+}
+
 int amdgpu_display_suspend_helper(struct amdgpu_device *adev)
 {
        struct drm_device *dev = adev_to_drm(adev);
@@ -1563,10 +1578,12 @@ int amdgpu_display_suspend_helper(struct amdgpu_device *adev)
                        continue;
                }
                robj = gem_to_amdgpu_bo(fb->obj[0]);
-               r = amdgpu_bo_reserve(robj, true);
-               if (r == 0) {
-                       amdgpu_bo_unpin(robj);
-                       amdgpu_bo_unreserve(robj);
+               if (!amdgpu_display_robj_is_fb(adev, robj)) {
+                       r = amdgpu_bo_reserve(robj, true);
+                       if (r == 0) {
+                               amdgpu_bo_unpin(robj);
+                               amdgpu_bo_unreserve(robj);
+                       }
                }
        }
        return 0;
index b4cf871..89011ba 100644 (file)
@@ -320,6 +320,7 @@ int amdgpu_irq_init(struct amdgpu_device *adev)
        if (!amdgpu_device_has_dc_support(adev)) {
                if (!adev->enable_virtual_display)
                        /* Disable vblank IRQs aggressively for power-saving */
+                       /* XXX: can this be enabled for DC? */
                        adev_to_drm(adev)->vblank_disable_immediate = true;
 
                r = drm_vblank_init(adev_to_drm(adev), adev->mode_info.num_crtc);
index 6546552..acfa207 100644 (file)
 #include <drm/ttm/ttm_resource.h>
 #include <drm/ttm/ttm_range_manager.h>
 
-#include "amdgpu_vram_mgr.h"
-
 /* state back for walking over vram_mgr and gtt_mgr allocations */
 struct amdgpu_res_cursor {
        uint64_t                start;
        uint64_t                size;
        uint64_t                remaining;
-       void                    *node;
-       uint32_t                mem_type;
+       struct drm_mm_node      *node;
 };
 
 /**
@@ -55,63 +52,27 @@ static inline void amdgpu_res_first(struct ttm_resource *res,
                                    uint64_t start, uint64_t size,
                                    struct amdgpu_res_cursor *cur)
 {
-       struct drm_buddy_block *block;
-       struct list_head *head, *next;
        struct drm_mm_node *node;
 
-       if (!res)
-               goto fallback;
-
-       BUG_ON(start + size > res->num_pages << PAGE_SHIFT);
-
-       cur->mem_type = res->mem_type;
-
-       switch (cur->mem_type) {
-       case TTM_PL_VRAM:
-               head = &to_amdgpu_vram_mgr_resource(res)->blocks;
-
-               block = list_first_entry_or_null(head,
-                                                struct drm_buddy_block,
-                                                link);
-               if (!block)
-                       goto fallback;
-
-               while (start >= amdgpu_vram_mgr_block_size(block)) {
-                       start -= amdgpu_vram_mgr_block_size(block);
-
-                       next = block->link.next;
-                       if (next != head)
-                               block = list_entry(next, struct drm_buddy_block, link);
-               }
-
-               cur->start = amdgpu_vram_mgr_block_start(block) + start;
-               cur->size = min(amdgpu_vram_mgr_block_size(block) - start, size);
-               cur->remaining = size;
-               cur->node = block;
-               break;
-       case TTM_PL_TT:
-               node = to_ttm_range_mgr_node(res)->mm_nodes;
-               while (start >= node->size << PAGE_SHIFT)
-                       start -= node++->size << PAGE_SHIFT;
-
-               cur->start = (node->start << PAGE_SHIFT) + start;
-               cur->size = min((node->size << PAGE_SHIFT) - start, size);
+       if (!res || res->mem_type == TTM_PL_SYSTEM) {
+               cur->start = start;
+               cur->size = size;
                cur->remaining = size;
-               cur->node = node;
-               break;
-       default:
-               goto fallback;
+               cur->node = NULL;
+               WARN_ON(res && start + size > res->num_pages << PAGE_SHIFT);
+               return;
        }
 
-       return;
+       BUG_ON(start + size > res->num_pages << PAGE_SHIFT);
 
-fallback:
-       cur->start = start;
-       cur->size = size;
+       node = to_ttm_range_mgr_node(res)->mm_nodes;
+       while (start >= node->size << PAGE_SHIFT)
+               start -= node++->size << PAGE_SHIFT;
+
+       cur->start = (node->start << PAGE_SHIFT) + start;
+       cur->size = min((node->size << PAGE_SHIFT) - start, size);
        cur->remaining = size;
-       cur->node = NULL;
-       WARN_ON(res && start + size > res->num_pages << PAGE_SHIFT);
-       return;
+       cur->node = node;
 }
 
 /**
@@ -124,9 +85,7 @@ fallback:
  */
 static inline void amdgpu_res_next(struct amdgpu_res_cursor *cur, uint64_t size)
 {
-       struct drm_buddy_block *block;
-       struct drm_mm_node *node;
-       struct list_head *next;
+       struct drm_mm_node *node = cur->node;
 
        BUG_ON(size > cur->remaining);
 
@@ -140,27 +99,9 @@ static inline void amdgpu_res_next(struct amdgpu_res_cursor *cur, uint64_t size)
                return;
        }
 
-       switch (cur->mem_type) {
-       case TTM_PL_VRAM:
-               block = cur->node;
-
-               next = block->link.next;
-               block = list_entry(next, struct drm_buddy_block, link);
-
-               cur->node = block;
-               cur->start = amdgpu_vram_mgr_block_start(block);
-               cur->size = min(amdgpu_vram_mgr_block_size(block), cur->remaining);
-               break;
-       case TTM_PL_TT:
-               node = cur->node;
-
-               cur->node = ++node;
-               cur->start = node->start << PAGE_SHIFT;
-               cur->size = min(node->size << PAGE_SHIFT, cur->remaining);
-               break;
-       default:
-               return;
-       }
+       cur->node = ++node;
+       cur->start = node->start << PAGE_SHIFT;
+       cur->size = min(node->size << PAGE_SHIFT, cur->remaining);
 }
 
 #endif
index 6a70818..9120ae8 100644 (file)
@@ -26,7 +26,6 @@
 
 #include <linux/dma-direction.h>
 #include <drm/gpu_scheduler.h>
-#include "amdgpu_vram_mgr.h"
 #include "amdgpu.h"
 
 #define AMDGPU_PL_GDS          (TTM_PL_PRIV + 0)
 
 #define AMDGPU_POISON  0xd0bed0be
 
+struct amdgpu_vram_mgr {
+       struct ttm_resource_manager manager;
+       struct drm_mm mm;
+       spinlock_t lock;
+       struct list_head reservations_pending;
+       struct list_head reserved_pages;
+       atomic64_t vis_usage;
+};
+
 struct amdgpu_gtt_mgr {
        struct ttm_resource_manager manager;
        struct drm_mm mm;
index 576849e..108e8e8 100644 (file)
@@ -496,7 +496,8 @@ static int amdgpu_vkms_sw_init(void *handle)
        adev_to_drm(adev)->mode_config.max_height = YRES_MAX;
 
        adev_to_drm(adev)->mode_config.preferred_depth = 24;
-       adev_to_drm(adev)->mode_config.prefer_shadow = 1;
+       /* disable prefer shadow for now due to hibernation issues */
+       adev_to_drm(adev)->mode_config.prefer_shadow = 0;
 
        adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base;
 
index 49e4092..0a76116 100644 (file)
 #include "atom.h"
 
 struct amdgpu_vram_reservation {
-       u64 start;
-       u64 size;
-       struct list_head allocated;
-       struct list_head blocks;
+       struct list_head node;
+       struct drm_mm_node mm_node;
 };
 
 static inline struct amdgpu_vram_mgr *
@@ -188,18 +186,18 @@ const struct attribute_group amdgpu_vram_mgr_attr_group = {
 };
 
 /**
- * amdgpu_vram_mgr_vis_size - Calculate visible block size
+ * amdgpu_vram_mgr_vis_size - Calculate visible node size
  *
  * @adev: amdgpu_device pointer
- * @block: DRM BUDDY block structure
+ * @node: MM node structure
  *
- * Calculate how many bytes of the DRM BUDDY block are inside visible VRAM
+ * Calculate how many bytes of the MM node are inside visible VRAM
  */
 static u64 amdgpu_vram_mgr_vis_size(struct amdgpu_device *adev,
-                                   struct drm_buddy_block *block)
+                                   struct drm_mm_node *node)
 {
-       u64 start = amdgpu_vram_mgr_block_start(block);
-       u64 end = start + amdgpu_vram_mgr_block_size(block);
+       uint64_t start = node->start << PAGE_SHIFT;
+       uint64_t end = (node->size + node->start) << PAGE_SHIFT;
 
        if (start >= adev->gmc.visible_vram_size)
                return 0;
@@ -220,9 +218,9 @@ u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo)
 {
        struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
        struct ttm_resource *res = bo->tbo.resource;
-       struct amdgpu_vram_mgr_resource *vres = to_amdgpu_vram_mgr_resource(res);
-       struct drm_buddy_block *block;
-       u64 usage = 0;
+       unsigned pages = res->num_pages;
+       struct drm_mm_node *mm;
+       u64 usage;
 
        if (amdgpu_gmc_vram_full_visible(&adev->gmc))
                return amdgpu_bo_size(bo);
@@ -230,8 +228,9 @@ u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo)
        if (res->start >= adev->gmc.visible_vram_size >> PAGE_SHIFT)
                return 0;
 
-       list_for_each_entry(block, &vres->blocks, link)
-               usage += amdgpu_vram_mgr_vis_size(adev, block);
+       mm = &container_of(res, struct ttm_range_mgr_node, base)->mm_nodes[0];
+       for (usage = 0; pages; pages -= mm->size, mm++)
+               usage += amdgpu_vram_mgr_vis_size(adev, mm);
 
        return usage;
 }
@@ -241,30 +240,23 @@ static void amdgpu_vram_mgr_do_reserve(struct ttm_resource_manager *man)
 {
        struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
        struct amdgpu_device *adev = to_amdgpu_device(mgr);
-       struct drm_buddy *mm = &mgr->mm;
+       struct drm_mm *mm = &mgr->mm;
        struct amdgpu_vram_reservation *rsv, *temp;
-       struct drm_buddy_block *block;
        uint64_t vis_usage;
 
-       list_for_each_entry_safe(rsv, temp, &mgr->reservations_pending, blocks) {
-               if (drm_buddy_alloc_blocks(mm, rsv->start, rsv->start + rsv->size,
-                                          rsv->size, mm->chunk_size, &rsv->allocated,
-                                          DRM_BUDDY_RANGE_ALLOCATION))
-                       continue;
-
-               block = amdgpu_vram_mgr_first_block(&rsv->allocated);
-               if (!block)
+       list_for_each_entry_safe(rsv, temp, &mgr->reservations_pending, node) {
+               if (drm_mm_reserve_node(mm, &rsv->mm_node))
                        continue;
 
                dev_dbg(adev->dev, "Reservation 0x%llx - %lld, Succeeded\n",
-                       rsv->start, rsv->size);
+                       rsv->mm_node.start, rsv->mm_node.size);
 
-               vis_usage = amdgpu_vram_mgr_vis_size(adev, block);
+               vis_usage = amdgpu_vram_mgr_vis_size(adev, &rsv->mm_node);
                atomic64_add(vis_usage, &mgr->vis_usage);
                spin_lock(&man->bdev->lru_lock);
-               man->usage += rsv->size;
+               man->usage += rsv->mm_node.size << PAGE_SHIFT;
                spin_unlock(&man->bdev->lru_lock);
-               list_move(&rsv->blocks, &mgr->reserved_pages);
+               list_move(&rsv->node, &mgr->reserved_pages);
        }
 }
 
@@ -286,16 +278,14 @@ int amdgpu_vram_mgr_reserve_range(struct amdgpu_vram_mgr *mgr,
        if (!rsv)
                return -ENOMEM;
 
-       INIT_LIST_HEAD(&rsv->allocated);
-       INIT_LIST_HEAD(&rsv->blocks);
+       INIT_LIST_HEAD(&rsv->node);
+       rsv->mm_node.start = start >> PAGE_SHIFT;
+       rsv->mm_node.size = size >> PAGE_SHIFT;
 
-       rsv->start = start;
-       rsv->size = size;
-
-       mutex_lock(&mgr->lock);
-       list_add_tail(&rsv->blocks, &mgr->reservations_pending);
+       spin_lock(&mgr->lock);
+       list_add_tail(&rsv->node, &mgr->reservations_pending);
        amdgpu_vram_mgr_do_reserve(&mgr->manager);
-       mutex_unlock(&mgr->lock);
+       spin_unlock(&mgr->lock);
 
        return 0;
 }
@@ -317,19 +307,19 @@ int amdgpu_vram_mgr_query_page_status(struct amdgpu_vram_mgr *mgr,
        struct amdgpu_vram_reservation *rsv;
        int ret;
 
-       mutex_lock(&mgr->lock);
+       spin_lock(&mgr->lock);
 
-       list_for_each_entry(rsv, &mgr->reservations_pending, blocks) {
-               if (rsv->start <= start &&
-                   (start < (rsv->start + rsv->size))) {
+       list_for_each_entry(rsv, &mgr->reservations_pending, node) {
+               if ((rsv->mm_node.start <= start) &&
+                   (start < (rsv->mm_node.start + rsv->mm_node.size))) {
                        ret = -EBUSY;
                        goto out;
                }
        }
 
-       list_for_each_entry(rsv, &mgr->reserved_pages, blocks) {
-               if (rsv->start <= start &&
-                   (start < (rsv->start + rsv->size))) {
+       list_for_each_entry(rsv, &mgr->reserved_pages, node) {
+               if ((rsv->mm_node.start <= start) &&
+                   (start < (rsv->mm_node.start + rsv->mm_node.size))) {
                        ret = 0;
                        goto out;
                }
@@ -337,11 +327,33 @@ int amdgpu_vram_mgr_query_page_status(struct amdgpu_vram_mgr *mgr,
 
        ret = -ENOENT;
 out:
-       mutex_unlock(&mgr->lock);
+       spin_unlock(&mgr->lock);
        return ret;
 }
 
 /**
+ * amdgpu_vram_mgr_virt_start - update virtual start address
+ *
+ * @mem: ttm_resource to update
+ * @node: just allocated node
+ *
+ * Calculate a virtual BO start address to easily check if everything is CPU
+ * accessible.
+ */
+static void amdgpu_vram_mgr_virt_start(struct ttm_resource *mem,
+                                      struct drm_mm_node *node)
+{
+       unsigned long start;
+
+       start = node->start + node->size;
+       if (start > mem->num_pages)
+               start -= mem->num_pages;
+       else
+               start = 0;
+       mem->start = max(mem->start, start);
+}
+
+/**
  * amdgpu_vram_mgr_new - allocate new ranges
  *
  * @man: TTM memory type manager
@@ -356,44 +368,46 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
                               const struct ttm_place *place,
                               struct ttm_resource **res)
 {
-       u64 vis_usage = 0, max_bytes, cur_size, min_block_size;
+       unsigned long lpfn, num_nodes, pages_per_node, pages_left, pages;
        struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
        struct amdgpu_device *adev = to_amdgpu_device(mgr);
-       struct amdgpu_vram_mgr_resource *vres;
-       u64 size, remaining_size, lpfn, fpfn;
-       struct drm_buddy *mm = &mgr->mm;
-       struct drm_buddy_block *block;
-       unsigned long pages_per_block;
+       uint64_t vis_usage = 0, mem_bytes, max_bytes;
+       struct ttm_range_mgr_node *node;
+       struct drm_mm *mm = &mgr->mm;
+       enum drm_mm_insert_mode mode;
+       unsigned i;
        int r;
 
-       lpfn = place->lpfn << PAGE_SHIFT;
+       lpfn = place->lpfn;
        if (!lpfn)
-               lpfn = man->size;
-
-       fpfn = place->fpfn << PAGE_SHIFT;
+               lpfn = man->size >> PAGE_SHIFT;
 
        max_bytes = adev->gmc.mc_vram_size;
        if (tbo->type != ttm_bo_type_kernel)
                max_bytes -= AMDGPU_VM_RESERVED_VRAM;
 
+       mem_bytes = tbo->base.size;
        if (place->flags & TTM_PL_FLAG_CONTIGUOUS) {
-               pages_per_block = ~0ul;
+               pages_per_node = ~0ul;
+               num_nodes = 1;
        } else {
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
-               pages_per_block = HPAGE_PMD_NR;
+               pages_per_node = HPAGE_PMD_NR;
 #else
                /* default to 2MB */
-               pages_per_block = 2UL << (20UL - PAGE_SHIFT);
+               pages_per_node = 2UL << (20UL - PAGE_SHIFT);
 #endif
-               pages_per_block = max_t(uint32_t, pages_per_block,
-                                       tbo->page_alignment);
+               pages_per_node = max_t(uint32_t, pages_per_node,
+                                      tbo->page_alignment);
+               num_nodes = DIV_ROUND_UP_ULL(PFN_UP(mem_bytes), pages_per_node);
        }
 
-       vres = kzalloc(sizeof(*vres), GFP_KERNEL);
-       if (!vres)
+       node = kvmalloc(struct_size(node, mm_nodes, num_nodes),
+                       GFP_KERNEL | __GFP_ZERO);
+       if (!node)
                return -ENOMEM;
 
-       ttm_resource_init(tbo, place, &vres->base);
+       ttm_resource_init(tbo, place, &node->base);
 
        /* bail out quickly if there's likely not enough VRAM for this BO */
        if (ttm_resource_manager_usage(man) > max_bytes) {
@@ -401,130 +415,66 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
                goto error_fini;
        }
 
-       INIT_LIST_HEAD(&vres->blocks);
-
+       mode = DRM_MM_INSERT_BEST;
        if (place->flags & TTM_PL_FLAG_TOPDOWN)
-               vres->flags |= DRM_BUDDY_TOPDOWN_ALLOCATION;
-
-       if (fpfn || lpfn != man->size)
-               /* Allocate blocks in desired range */
-               vres->flags |= DRM_BUDDY_RANGE_ALLOCATION;
-
-       remaining_size = vres->base.num_pages << PAGE_SHIFT;
-
-       mutex_lock(&mgr->lock);
-       while (remaining_size) {
-               if (tbo->page_alignment)
-                       min_block_size = tbo->page_alignment << PAGE_SHIFT;
-               else
-                       min_block_size = mgr->default_page_size;
-
-               BUG_ON(min_block_size < mm->chunk_size);
-
-               /* Limit maximum size to 2GiB due to SG table limitations */
-               size = min(remaining_size, 2ULL << 30);
-
-               if (size >= pages_per_block << PAGE_SHIFT)
-                       min_block_size = pages_per_block << PAGE_SHIFT;
-
-               cur_size = size;
-
-               if (fpfn + size != place->lpfn << PAGE_SHIFT) {
-                       /*
-                        * Except for actual range allocation, modify the size and
-                        * min_block_size conforming to continuous flag enablement
-                        */
-                       if (place->flags & TTM_PL_FLAG_CONTIGUOUS) {
-                               size = roundup_pow_of_two(size);
-                               min_block_size = size;
-                       /*
-                        * Modify the size value if size is not
-                        * aligned with min_block_size
-                        */
-                       } else if (!IS_ALIGNED(size, min_block_size)) {
-                               size = round_up(size, min_block_size);
+               mode = DRM_MM_INSERT_HIGH;
+
+       pages_left = node->base.num_pages;
+
+       /* Limit maximum size to 2GB due to SG table limitations */
+       pages = min(pages_left, 2UL << (30 - PAGE_SHIFT));
+
+       i = 0;
+       spin_lock(&mgr->lock);
+       while (pages_left) {
+               uint32_t alignment = tbo->page_alignment;
+
+               if (pages >= pages_per_node)
+                       alignment = pages_per_node;
+
+               r = drm_mm_insert_node_in_range(mm, &node->mm_nodes[i], pages,
+                                               alignment, 0, place->fpfn,
+                                               lpfn, mode);
+               if (unlikely(r)) {
+                       if (pages > pages_per_node) {
+                               if (is_power_of_2(pages))
+                                       pages = pages / 2;
+                               else
+                                       pages = rounddown_pow_of_two(pages);
+                               continue;
                        }
+                       goto error_free;
                }
 
-               r = drm_buddy_alloc_blocks(mm, fpfn,
-                                          lpfn,
-                                          size,
-                                          min_block_size,
-                                          &vres->blocks,
-                                          vres->flags);
-               if (unlikely(r))
-                       goto error_free_blocks;
-
-               if (size > remaining_size)
-                       remaining_size = 0;
-               else
-                       remaining_size -= size;
-       }
-       mutex_unlock(&mgr->lock);
-
-       if (cur_size != size) {
-               struct drm_buddy_block *block;
-               struct list_head *trim_list;
-               u64 original_size;
-               LIST_HEAD(temp);
-
-               trim_list = &vres->blocks;
-               original_size = vres->base.num_pages << PAGE_SHIFT;
-
-               /*
-                * If size value is rounded up to min_block_size, trim the last
-                * block to the required size
-                */
-               if (!list_is_singular(&vres->blocks)) {
-                       block = list_last_entry(&vres->blocks, typeof(*block), link);
-                       list_move_tail(&block->link, &temp);
-                       trim_list = &temp;
-                       /*
-                        * Compute the original_size value by subtracting the
-                        * last block size with (aligned size - original size)
-                        */
-                       original_size = amdgpu_vram_mgr_block_size(block) - (size - cur_size);
-               }
+               vis_usage += amdgpu_vram_mgr_vis_size(adev, &node->mm_nodes[i]);
+               amdgpu_vram_mgr_virt_start(&node->base, &node->mm_nodes[i]);
+               pages_left -= pages;
+               ++i;
 
-               mutex_lock(&mgr->lock);
-               drm_buddy_block_trim(mm,
-                                    original_size,
-                                    trim_list);
-               mutex_unlock(&mgr->lock);
-
-               if (!list_empty(&temp))
-                       list_splice_tail(trim_list, &vres->blocks);
-       }
-
-       list_for_each_entry(block, &vres->blocks, link)
-               vis_usage += amdgpu_vram_mgr_vis_size(adev, block);
-
-       block = amdgpu_vram_mgr_first_block(&vres->blocks);
-       if (!block) {
-               r = -EINVAL;
-               goto error_fini;
+               if (pages > pages_left)
+                       pages = pages_left;
        }
+       spin_unlock(&mgr->lock);
 
-       vres->base.start = amdgpu_vram_mgr_block_start(block) >> PAGE_SHIFT;
-
-       if (amdgpu_is_vram_mgr_blocks_contiguous(&vres->blocks))
-               vres->base.placement |= TTM_PL_FLAG_CONTIGUOUS;
+       if (i == 1)
+               node->base.placement |= TTM_PL_FLAG_CONTIGUOUS;
 
        if (adev->gmc.xgmi.connected_to_cpu)
-               vres->base.bus.caching = ttm_cached;
+               node->base.bus.caching = ttm_cached;
        else
-               vres->base.bus.caching = ttm_write_combined;
+               node->base.bus.caching = ttm_write_combined;
 
        atomic64_add(vis_usage, &mgr->vis_usage);
-       *res = &vres->base;
+       *res = &node->base;
        return 0;
 
-error_free_blocks:
-       drm_buddy_free_list(mm, &vres->blocks);
-       mutex_unlock(&mgr->lock);
+error_free:
+       while (i--)
+               drm_mm_remove_node(&node->mm_nodes[i]);
+       spin_unlock(&mgr->lock);
 error_fini:
-       ttm_resource_fini(man, &vres->base);
-       kfree(vres);
+       ttm_resource_fini(man, &node->base);
+       kvfree(node);
 
        return r;
 }
@@ -540,26 +490,27 @@ error_fini:
 static void amdgpu_vram_mgr_del(struct ttm_resource_manager *man,
                                struct ttm_resource *res)
 {
-       struct amdgpu_vram_mgr_resource *vres = to_amdgpu_vram_mgr_resource(res);
+       struct ttm_range_mgr_node *node = to_ttm_range_mgr_node(res);
        struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
        struct amdgpu_device *adev = to_amdgpu_device(mgr);
-       struct drm_buddy *mm = &mgr->mm;
-       struct drm_buddy_block *block;
        uint64_t vis_usage = 0;
+       unsigned i, pages;
 
-       mutex_lock(&mgr->lock);
-       list_for_each_entry(block, &vres->blocks, link)
-               vis_usage += amdgpu_vram_mgr_vis_size(adev, block);
+       spin_lock(&mgr->lock);
+       for (i = 0, pages = res->num_pages; pages;
+            pages -= node->mm_nodes[i].size, ++i) {
+               struct drm_mm_node *mm = &node->mm_nodes[i];
 
+               drm_mm_remove_node(mm);
+               vis_usage += amdgpu_vram_mgr_vis_size(adev, mm);
+       }
        amdgpu_vram_mgr_do_reserve(man);
-
-       drm_buddy_free_list(mm, &vres->blocks);
-       mutex_unlock(&mgr->lock);
+       spin_unlock(&mgr->lock);
 
        atomic64_sub(vis_usage, &mgr->vis_usage);
 
        ttm_resource_fini(man, res);
-       kfree(vres);
+       kvfree(node);
 }
 
 /**
@@ -591,7 +542,7 @@ int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev,
        if (!*sgt)
                return -ENOMEM;
 
-       /* Determine the number of DRM_BUDDY blocks to export */
+       /* Determine the number of DRM_MM nodes to export */
        amdgpu_res_first(res, offset, length, &cursor);
        while (cursor.remaining) {
                num_entries++;
@@ -607,10 +558,10 @@ int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev,
                sg->length = 0;
 
        /*
-        * Walk down DRM_BUDDY blocks to populate scatterlist nodes
-        * @note: Use iterator api to get first the DRM_BUDDY block
+        * Walk down DRM_MM nodes to populate scatterlist nodes
+        * @note: Use iterator api to get first the DRM_MM node
         * and the number of bytes from it. Access the following
-        * DRM_BUDDY block(s) if more buffer needs to exported
+        * DRM_MM node(s) if more buffer needs to exported
         */
        amdgpu_res_first(res, offset, length, &cursor);
        for_each_sgtable_sg((*sgt), sg, i) {
@@ -697,22 +648,13 @@ static void amdgpu_vram_mgr_debug(struct ttm_resource_manager *man,
                                  struct drm_printer *printer)
 {
        struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
-       struct drm_buddy *mm = &mgr->mm;
-       struct drm_buddy_block *block;
 
        drm_printf(printer, "  vis usage:%llu\n",
                   amdgpu_vram_mgr_vis_usage(mgr));
 
-       mutex_lock(&mgr->lock);
-       drm_printf(printer, "default_page_size: %lluKiB\n",
-                  mgr->default_page_size >> 10);
-
-       drm_buddy_print(mm, printer);
-
-       drm_printf(printer, "reserved:\n");
-       list_for_each_entry(block, &mgr->reserved_pages, link)
-               drm_buddy_block_print(mm, block, printer);
-       mutex_unlock(&mgr->lock);
+       spin_lock(&mgr->lock);
+       drm_mm_print(&mgr->mm, printer);
+       spin_unlock(&mgr->lock);
 }
 
 static const struct ttm_resource_manager_func amdgpu_vram_mgr_func = {
@@ -732,21 +674,16 @@ int amdgpu_vram_mgr_init(struct amdgpu_device *adev)
 {
        struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr;
        struct ttm_resource_manager *man = &mgr->manager;
-       int err;
 
        ttm_resource_manager_init(man, &adev->mman.bdev,
                                  adev->gmc.real_vram_size);
 
        man->func = &amdgpu_vram_mgr_func;
 
-       err = drm_buddy_init(&mgr->mm, man->size, PAGE_SIZE);
-       if (err)
-               return err;
-
-       mutex_init(&mgr->lock);
+       drm_mm_init(&mgr->mm, 0, man->size >> PAGE_SHIFT);
+       spin_lock_init(&mgr->lock);
        INIT_LIST_HEAD(&mgr->reservations_pending);
        INIT_LIST_HEAD(&mgr->reserved_pages);
-       mgr->default_page_size = PAGE_SIZE;
 
        ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, &mgr->manager);
        ttm_resource_manager_set_used(man, true);
@@ -774,16 +711,16 @@ void amdgpu_vram_mgr_fini(struct amdgpu_device *adev)
        if (ret)
                return;
 
-       mutex_lock(&mgr->lock);
-       list_for_each_entry_safe(rsv, temp, &mgr->reservations_pending, blocks)
+       spin_lock(&mgr->lock);
+       list_for_each_entry_safe(rsv, temp, &mgr->reservations_pending, node)
                kfree(rsv);
 
-       list_for_each_entry_safe(rsv, temp, &mgr->reserved_pages, blocks) {
-               drm_buddy_free_list(&mgr->mm, &rsv->blocks);
+       list_for_each_entry_safe(rsv, temp, &mgr->reserved_pages, node) {
+               drm_mm_remove_node(&rsv->mm_node);
                kfree(rsv);
        }
-       drm_buddy_fini(&mgr->mm);
-       mutex_unlock(&mgr->lock);
+       drm_mm_takedown(&mgr->mm);
+       spin_unlock(&mgr->lock);
 
        ttm_resource_manager_cleanup(man);
        ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, NULL);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h
deleted file mode 100644 (file)
index 9a2db87..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/* SPDX-License-Identifier: MIT
- * Copyright 2021 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#ifndef __AMDGPU_VRAM_MGR_H__
-#define __AMDGPU_VRAM_MGR_H__
-
-#include <drm/drm_buddy.h>
-
-struct amdgpu_vram_mgr {
-       struct ttm_resource_manager manager;
-       struct drm_buddy mm;
-       /* protects access to buffer objects */
-       struct mutex lock;
-       struct list_head reservations_pending;
-       struct list_head reserved_pages;
-       atomic64_t vis_usage;
-       u64 default_page_size;
-};
-
-struct amdgpu_vram_mgr_resource {
-       struct ttm_resource base;
-       struct list_head blocks;
-       unsigned long flags;
-};
-
-static inline u64 amdgpu_vram_mgr_block_start(struct drm_buddy_block *block)
-{
-       return drm_buddy_block_offset(block);
-}
-
-static inline u64 amdgpu_vram_mgr_block_size(struct drm_buddy_block *block)
-{
-       return PAGE_SIZE << drm_buddy_block_order(block);
-}
-
-static inline struct drm_buddy_block *
-amdgpu_vram_mgr_first_block(struct list_head *list)
-{
-       return list_first_entry_or_null(list, struct drm_buddy_block, link);
-}
-
-static inline bool amdgpu_is_vram_mgr_blocks_contiguous(struct list_head *head)
-{
-       struct drm_buddy_block *block;
-       u64 start, size;
-
-       block = amdgpu_vram_mgr_first_block(head);
-       if (!block)
-               return false;
-
-       while (head != block->link.next) {
-               start = amdgpu_vram_mgr_block_start(block);
-               size = amdgpu_vram_mgr_block_size(block);
-
-               block = list_entry(block->link.next, struct drm_buddy_block, link);
-               if (start + size != amdgpu_vram_mgr_block_start(block))
-                       return false;
-       }
-
-       return true;
-}
-
-static inline struct amdgpu_vram_mgr_resource *
-to_amdgpu_vram_mgr_resource(struct ttm_resource *res)
-{
-       return container_of(res, struct amdgpu_vram_mgr_resource, base);
-}
-
-#endif
index 288fce7..9c964cd 100644 (file)
@@ -2796,7 +2796,8 @@ static int dce_v10_0_sw_init(void *handle)
        adev_to_drm(adev)->mode_config.max_height = 16384;
 
        adev_to_drm(adev)->mode_config.preferred_depth = 24;
-       adev_to_drm(adev)->mode_config.prefer_shadow = 1;
+       /* disable prefer shadow for now due to hibernation issues */
+       adev_to_drm(adev)->mode_config.prefer_shadow = 0;
 
        adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true;
 
index cbe5250..e0ad9f2 100644 (file)
@@ -2914,7 +2914,8 @@ static int dce_v11_0_sw_init(void *handle)
        adev_to_drm(adev)->mode_config.max_height = 16384;
 
        adev_to_drm(adev)->mode_config.preferred_depth = 24;
-       adev_to_drm(adev)->mode_config.prefer_shadow = 1;
+       /* disable prefer shadow for now due to hibernation issues */
+       adev_to_drm(adev)->mode_config.prefer_shadow = 0;
 
        adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true;
 
index 982855e..3caf6f3 100644 (file)
@@ -2673,7 +2673,8 @@ static int dce_v6_0_sw_init(void *handle)
        adev_to_drm(adev)->mode_config.max_width = 16384;
        adev_to_drm(adev)->mode_config.max_height = 16384;
        adev_to_drm(adev)->mode_config.preferred_depth = 24;
-       adev_to_drm(adev)->mode_config.prefer_shadow = 1;
+       /* disable prefer shadow for now due to hibernation issues */
+       adev_to_drm(adev)->mode_config.prefer_shadow = 0;
        adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true;
        adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base;
 
index 8444074..7c75df5 100644 (file)
@@ -2693,7 +2693,8 @@ static int dce_v8_0_sw_init(void *handle)
        adev_to_drm(adev)->mode_config.max_height = 16384;
 
        adev_to_drm(adev)->mode_config.preferred_depth = 24;
-       adev_to_drm(adev)->mode_config.prefer_shadow = 1;
+       /* disable prefer shadow for now due to hibernation issues */
+       adev_to_drm(adev)->mode_config.prefer_shadow = 0;
 
        adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true;
 
index bf42004..a08769c 100644 (file)
@@ -184,6 +184,8 @@ static void kfd_device_info_init(struct kfd_dev *kfd,
                        /* Navi2x+, Navi1x+ */
                        if (gc_version == IP_VERSION(10, 3, 6))
                                kfd->device_info.no_atomic_fw_version = 14;
+                       else if (gc_version == IP_VERSION(10, 3, 7))
+                               kfd->device_info.no_atomic_fw_version = 3;
                        else if (gc_version >= IP_VERSION(10, 3, 0))
                                kfd->device_info.no_atomic_fw_version = 92;
                        else if (gc_version >= IP_VERSION(10, 1, 1))
index b4029c0..ec6771e 100644 (file)
@@ -6,7 +6,7 @@ config DRM_AMD_DC
        bool "AMD DC - Enable new display engine"
        default y
        select SND_HDA_COMPONENT if SND_HDA_CORE
-       select DRM_AMD_DC_DCN if (X86 || PPC64) && !(KCOV_INSTRUMENT_ALL && KCOV_ENABLE_COMPARISONS)
+       select DRM_AMD_DC_DCN if (X86 || PPC_LONG_DOUBLE_128) && !(KCOV_INSTRUMENT_ALL && KCOV_ENABLE_COMPARISONS)
        help
          Choose this option if you want to use the new display engine
          support for AMDGPU. This adds required support for Vega and
index 39b425d..3087dd1 100644 (file)
@@ -72,6 +72,7 @@
 #include <linux/pci.h>
 #include <linux/firmware.h>
 #include <linux/component.h>
+#include <linux/dmi.h>
 
 #include <drm/display/drm_dp_mst_helper.h>
 #include <drm/display/drm_hdmi_helper.h>
@@ -462,6 +463,26 @@ static void dm_pflip_high_irq(void *interrupt_params)
                     vrr_active, (int) !e);
 }
 
+static void dm_crtc_handle_vblank(struct amdgpu_crtc *acrtc)
+{
+       struct drm_crtc *crtc = &acrtc->base;
+       struct drm_device *dev = crtc->dev;
+       unsigned long flags;
+
+       drm_crtc_handle_vblank(crtc);
+
+       spin_lock_irqsave(&dev->event_lock, flags);
+
+       /* Send completion event for cursor-only commits */
+       if (acrtc->event && acrtc->pflip_status != AMDGPU_FLIP_SUBMITTED) {
+               drm_crtc_send_vblank_event(crtc, acrtc->event);
+               drm_crtc_vblank_put(crtc);
+               acrtc->event = NULL;
+       }
+
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
 static void dm_vupdate_high_irq(void *interrupt_params)
 {
        struct common_irq_params *irq_params = interrupt_params;
@@ -500,7 +521,7 @@ static void dm_vupdate_high_irq(void *interrupt_params)
                 * if a pageflip happened inside front-porch.
                 */
                if (vrr_active) {
-                       drm_crtc_handle_vblank(&acrtc->base);
+                       dm_crtc_handle_vblank(acrtc);
 
                        /* BTR processing for pre-DCE12 ASICs */
                        if (acrtc->dm_irq_params.stream &&
@@ -552,7 +573,7 @@ static void dm_crtc_high_irq(void *interrupt_params)
         * to dm_vupdate_high_irq after end of front-porch.
         */
        if (!vrr_active)
-               drm_crtc_handle_vblank(&acrtc->base);
+               dm_crtc_handle_vblank(acrtc);
 
        /**
         * Following stuff must happen at start of vblank, for crc
@@ -1382,6 +1403,41 @@ static bool dm_should_disable_stutter(struct pci_dev *pdev)
        return false;
 }
 
+static const struct dmi_system_id hpd_disconnect_quirk_table[] = {
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3660"),
+               },
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3260"),
+               },
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3460"),
+               },
+       },
+       {}
+};
+
+static void retrieve_dmi_info(struct amdgpu_display_manager *dm)
+{
+       const struct dmi_system_id *dmi_id;
+
+       dm->aux_hpd_discon_quirk = false;
+
+       dmi_id = dmi_first_match(hpd_disconnect_quirk_table);
+       if (dmi_id) {
+               dm->aux_hpd_discon_quirk = true;
+               DRM_INFO("aux_hpd_discon_quirk attached\n");
+       }
+}
+
 static int amdgpu_dm_init(struct amdgpu_device *adev)
 {
        struct dc_init_data init_data;
@@ -1508,6 +1564,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
        }
 
        INIT_LIST_HEAD(&adev->dm.da_list);
+
+       retrieve_dmi_info(&adev->dm);
+
        /* Display Core create. */
        adev->dm.dc = dc_create(&init_data);
 
@@ -1594,7 +1653,7 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
 #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
        adev->dm.crc_rd_wrk = amdgpu_dm_crtc_secure_display_create_work();
 #endif
-       if (dc_enable_dmub_notifications(adev->dm.dc)) {
+       if (dc_is_dmub_outbox_supported(adev->dm.dc)) {
                init_completion(&adev->dm.dmub_aux_transfer_done);
                adev->dm.dmub_notify = kzalloc(sizeof(struct dmub_notification), GFP_KERNEL);
                if (!adev->dm.dmub_notify) {
@@ -1630,6 +1689,13 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
                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))
+               dc_enable_dmub_outbox(adev->dm.dc);
+
        /* create fake encoders for MST */
        dm_dp_create_fake_mst_encoders(adev);
 
@@ -2619,9 +2685,6 @@ static int dm_resume(void *handle)
                 */
                link_enc_cfg_copy(adev->dm.dc->current_state, dc_state);
 
-               if (dc_enable_dmub_notifications(adev->dm.dc))
-                       amdgpu_dm_outbox_init(adev);
-
                r = dm_dmub_hw_init(adev);
                if (r)
                        DRM_ERROR("DMUB interface failed to initialize: status=%d\n", r);
@@ -2639,6 +2702,11 @@ static int dm_resume(void *handle)
                        }
                }
 
+               if (dc_is_dmub_outbox_supported(adev->dm.dc)) {
+                       amdgpu_dm_outbox_init(adev);
+                       dc_enable_dmub_outbox(adev->dm.dc);
+               }
+
                WARN_ON(!dc_commit_state(dm->dc, dc_state));
 
                dm_gpureset_commit_state(dm->cached_dc_state, dm);
@@ -2660,13 +2728,15 @@ static int dm_resume(void *handle)
        /* TODO: Remove dc_state->dccg, use dc->dccg directly. */
        dc_resource_state_construct(dm->dc, dm_state->context);
 
-       /* Re-enable outbox interrupts for DPIA. */
-       if (dc_enable_dmub_notifications(adev->dm.dc))
-               amdgpu_dm_outbox_init(adev);
-
        /* Before powering on DC we need to re-initialize DMUB. */
        dm_dmub_hw_resume(adev);
 
+       /* Re-enable outbox interrupts for DPIA. */
+       if (dc_is_dmub_outbox_supported(adev->dm.dc)) {
+               amdgpu_dm_outbox_init(adev);
+               dc_enable_dmub_outbox(adev->dm.dc);
+       }
+
        /* power on hardware */
        dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D0);
 
@@ -3822,7 +3892,8 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev)
        adev_to_drm(adev)->mode_config.max_height = 16384;
 
        adev_to_drm(adev)->mode_config.preferred_depth = 24;
-       adev_to_drm(adev)->mode_config.prefer_shadow = 1;
+       /* disable prefer shadow for now due to hibernation issues */
+       adev_to_drm(adev)->mode_config.prefer_shadow = 0;
        /* indicates support for immediate flip */
        adev_to_drm(adev)->mode_config.async_page_flip = true;
 
@@ -4259,9 +4330,6 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
                }
        }
 
-       /* Disable vblank IRQs aggressively for power-saving. */
-       adev_to_drm(adev)->vblank_disable_immediate = true;
-
        /* loops over all connectors on the board */
        for (i = 0; i < link_cnt; i++) {
                struct dc_link *link = NULL;
@@ -5409,7 +5477,7 @@ fill_blending_from_plane_state(const struct drm_plane_state *plane_state,
                        }
                }
 
-               if (per_pixel_alpha && plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE)
+               if (*per_pixel_alpha && plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE)
                        *pre_multiplied_alpha = false;
        }
 
@@ -9137,6 +9205,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
        struct amdgpu_bo *abo;
        uint32_t target_vblank, last_flip_vblank;
        bool vrr_active = amdgpu_dm_vrr_active(acrtc_state);
+       bool cursor_update = false;
        bool pflip_present = false;
        struct {
                struct dc_surface_update surface_updates[MAX_SURFACES];
@@ -9172,8 +9241,13 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
                struct dm_plane_state *dm_new_plane_state = to_dm_plane_state(new_plane_state);
 
                /* Cursor plane is handled after stream updates */
-               if (plane->type == DRM_PLANE_TYPE_CURSOR)
+               if (plane->type == DRM_PLANE_TYPE_CURSOR) {
+                       if ((fb && crtc == pcrtc) ||
+                           (old_plane_state->fb && old_plane_state->crtc == pcrtc))
+                               cursor_update = true;
+
                        continue;
+               }
 
                if (!fb || !crtc || pcrtc != crtc)
                        continue;
@@ -9336,6 +9410,17 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
                                bundle->stream_update.vrr_infopacket =
                                        &acrtc_state->stream->vrr_infopacket;
                }
+       } else if (cursor_update && acrtc_state->active_planes > 0 &&
+                  !acrtc_state->force_dpms_off &&
+                  acrtc_attach->base.state->event) {
+               drm_crtc_vblank_get(pcrtc);
+
+               spin_lock_irqsave(&pcrtc->dev->event_lock, flags);
+
+               acrtc_attach->event = acrtc_attach->base.state->event;
+               acrtc_attach->base.state->event = NULL;
+
+               spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags);
        }
 
        /* Update the planes if changed or disable if we don't have any. */
index aa34c00..e80ef93 100644 (file)
@@ -540,6 +540,14 @@ struct amdgpu_display_manager {
         * last successfully applied backlight values.
         */
        u32 actual_brightness[AMDGPU_DM_MAX_NUM_EDP];
+
+       /**
+        * @aux_hpd_discon_quirk:
+        *
+        * quirk for hpd discon while aux is on-going.
+        * occurred on certain intel platform
+        */
+       bool aux_hpd_discon_quirk;
 };
 
 enum dsc_clock_force_state {
index 9221b66..2b9b095 100644 (file)
@@ -56,6 +56,8 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux,
        ssize_t result = 0;
        struct aux_payload payload;
        enum aux_return_code_type operation_result;
+       struct amdgpu_device *adev;
+       struct ddc_service *ddc;
 
        if (WARN_ON(msg->size > 16))
                return -E2BIG;
@@ -74,6 +76,21 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux,
        result = dc_link_aux_transfer_raw(TO_DM_AUX(aux)->ddc_service, &payload,
                                      &operation_result);
 
+       /*
+        * w/a on certain intel platform where hpd is unexpected to pull low during
+        * 1st sideband message transaction by return AUX_RET_ERROR_HPD_DISCON
+        * aux transaction is succuess in such case, therefore bypass the error
+        */
+       ddc = TO_DM_AUX(aux)->ddc_service;
+       adev = ddc->ctx->driver_context;
+       if (adev->dm.aux_hpd_discon_quirk) {
+               if (msg->address == DP_SIDEBAND_MSG_DOWN_REQ_BASE &&
+                       operation_result == AUX_RET_ERROR_HPD_DISCON) {
+                       result = 0;
+                       operation_result = AUX_RET_SUCCESS;
+               }
+       }
+
        if (payload.write && result >= 0)
                result = msg->size;
 
index 6774dd8..3fe3fba 100644 (file)
@@ -1117,12 +1117,13 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
         * on certain displays, such as the Sharp 4k. 36bpp is needed
         * to support SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 and
         * SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616 with actual > 10 bpc
-        * precision on at least DCN display engines. However, at least
-        * Carrizo with DCE_VERSION_11_0 does not like 36 bpp lb depth,
-        * so use only 30 bpp on DCE_VERSION_11_0. Testing with DCE 11.2 and 8.3
-        * did not show such problems, so this seems to be the exception.
+        * precision on DCN display engines, but apparently not for DCE, as
+        * far as testing on DCE-11.2 and DCE-8 showed. Various DCE parts have
+        * problems: Carrizo with DCE_VERSION_11_0 does not like 36 bpp lb depth,
+        * neither do DCE-8 at 4k resolution, or DCE-11.2 (broken identify pixel
+        * passthrough). Therefore only use 36 bpp on DCN where it is actually needed.
         */
-       if (plane_state->ctx->dce_version > DCE_VERSION_11_0)
+       if (plane_state->ctx->dce_version > DCE_VERSION_MAX)
                pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_36BPP;
        else
                pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;
index 5f8809f..2fbd292 100644 (file)
@@ -1228,6 +1228,8 @@ int smu_v11_0_set_fan_speed_rpm(struct smu_context *smu,
        uint32_t crystal_clock_freq = 2500;
        uint32_t tach_period;
 
+       if (speed == 0)
+               return -EINVAL;
        /*
         * To prevent from possible overheat, some ASICs may have requirement
         * for minimum fan speed:
index b2675c7..4b503c5 100644 (file)
@@ -74,22 +74,6 @@ static int fsl_ldb_attach(struct drm_bridge *bridge,
                                 bridge, flags);
 }
 
-static int fsl_ldb_atomic_check(struct drm_bridge *bridge,
-                               struct drm_bridge_state *bridge_state,
-                               struct drm_crtc_state *crtc_state,
-                               struct drm_connector_state *conn_state)
-{
-       /* Invert DE signal polarity. */
-       bridge_state->input_bus_cfg.flags &= ~(DRM_BUS_FLAG_DE_LOW |
-                                              DRM_BUS_FLAG_DE_HIGH);
-       if (bridge_state->output_bus_cfg.flags & DRM_BUS_FLAG_DE_LOW)
-               bridge_state->input_bus_cfg.flags |= DRM_BUS_FLAG_DE_HIGH;
-       else if (bridge_state->output_bus_cfg.flags & DRM_BUS_FLAG_DE_HIGH)
-               bridge_state->input_bus_cfg.flags |= DRM_BUS_FLAG_DE_LOW;
-
-       return 0;
-}
-
 static void fsl_ldb_atomic_enable(struct drm_bridge *bridge,
                                  struct drm_bridge_state *old_bridge_state)
 {
@@ -153,7 +137,7 @@ static void fsl_ldb_atomic_enable(struct drm_bridge *bridge,
        reg = LDB_CTRL_CH0_ENABLE;
 
        if (fsl_ldb->lvds_dual_link)
-               reg |= LDB_CTRL_CH1_ENABLE;
+               reg |= LDB_CTRL_CH1_ENABLE | LDB_CTRL_SPLIT_MODE;
 
        if (lvds_format_24bpp) {
                reg |= LDB_CTRL_CH0_DATA_WIDTH;
@@ -233,7 +217,7 @@ fsl_ldb_mode_valid(struct drm_bridge *bridge,
 {
        struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
 
-       if (mode->clock > (fsl_ldb->lvds_dual_link ? 80000 : 160000))
+       if (mode->clock > (fsl_ldb->lvds_dual_link ? 160000 : 80000))
                return MODE_CLOCK_HIGH;
 
        return MODE_OK;
@@ -241,7 +225,6 @@ fsl_ldb_mode_valid(struct drm_bridge *bridge,
 
 static const struct drm_bridge_funcs funcs = {
        .attach = fsl_ldb_attach,
-       .atomic_check = fsl_ldb_atomic_check,
        .atomic_enable = fsl_ldb_atomic_enable,
        .atomic_disable = fsl_ldb_atomic_disable,
        .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
index 74bd4a7..059fd71 100644 (file)
@@ -329,7 +329,20 @@ int drm_aperture_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
                                                     const struct drm_driver *req_driver)
 {
        resource_size_t base, size;
-       int bar, ret = 0;
+       int bar, ret;
+
+       /*
+        * WARNING: Apparently we must kick fbdev drivers before vgacon,
+        * otherwise the vga fbdev driver falls over.
+        */
+#if IS_REACHABLE(CONFIG_FB)
+       ret = remove_conflicting_pci_framebuffers(pdev, req_driver->name);
+       if (ret)
+               return ret;
+#endif
+       ret = vga_remove_vgacon(pdev);
+       if (ret)
+               return ret;
 
        for (bar = 0; bar < PCI_STD_NUM_BARS; ++bar) {
                if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
@@ -339,15 +352,6 @@ int drm_aperture_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
                drm_aperture_detach_drivers(base, size);
        }
 
-       /*
-        * WARNING: Apparently we must kick fbdev drivers before vgacon,
-        * otherwise the vga fbdev driver falls over.
-        */
-#if IS_REACHABLE(CONFIG_FB)
-       ret = remove_conflicting_pci_framebuffers(pdev, req_driver->name);
-#endif
-       if (ret == 0)
-               ret = vga_remove_vgacon(pdev);
-       return ret;
+       return 0;
 }
 EXPORT_SYMBOL(drm_aperture_remove_conflicting_pci_framebuffers);
index d5962a3..e5fc875 100644 (file)
@@ -64,8 +64,13 @@ int drm_gem_ttm_vmap(struct drm_gem_object *gem,
                     struct iosys_map *map)
 {
        struct ttm_buffer_object *bo = drm_gem_ttm_of_gem(gem);
+       int ret;
+
+       dma_resv_lock(gem->resv, NULL);
+       ret = ttm_bo_vmap(bo, map);
+       dma_resv_unlock(gem->resv);
 
-       return ttm_bo_vmap(bo, map);
+       return ret;
 }
 EXPORT_SYMBOL(drm_gem_ttm_vmap);
 
@@ -82,7 +87,9 @@ void drm_gem_ttm_vunmap(struct drm_gem_object *gem,
 {
        struct ttm_buffer_object *bo = drm_gem_ttm_of_gem(gem);
 
+       dma_resv_lock(gem->resv, NULL);
        ttm_bo_vunmap(bo, map);
+       dma_resv_unlock(gem->resv);
 }
 EXPORT_SYMBOL(drm_gem_ttm_vunmap);
 
index df87ba9..d4e0f2e 100644 (file)
@@ -286,6 +286,21 @@ static const struct dmi_system_id orientation_data[] = {
                  DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X9"),
                },
                .driver_data = (void *)&lcd1200x1920_rightside_up,
+       }, {    /* Lenovo Yoga Tablet 2 830F / 830L */
+               .matches = {
+                /*
+                 * Note this also matches the Lenovo Yoga Tablet 2 1050F/L
+                 * since that uses the same mainboard. The resolution match
+                 * will limit this to only matching on the 830F/L. Neither has
+                 * any external video outputs so those are not a concern.
+                 */
+                DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp."),
+                DMI_MATCH(DMI_PRODUCT_NAME, "VALLEYVIEW C0 PLATFORM"),
+                DMI_MATCH(DMI_BOARD_NAME, "BYT-T FFD8"),
+                /* Partial match on beginning of BIOS version */
+                DMI_MATCH(DMI_BIOS_VERSION, "BLADE_21"),
+               },
+               .driver_data = (void *)&lcd1200x1920_rightside_up,
        }, {    /* OneGX1 Pro */
                .matches = {
                  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SYSTEM_MANUFACTURER"),
index 061b277..14d2a64 100644 (file)
@@ -839,6 +839,7 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo
        ret = drm_connector_init(dev, connector, &intel_dp_mst_connector_funcs,
                                 DRM_MODE_CONNECTOR_DisplayPort);
        if (ret) {
+               drm_dp_mst_put_port_malloc(port);
                intel_connector_free(intel_connector);
                return NULL;
        }
index ab4c5ab..321af10 100644 (file)
@@ -933,8 +933,9 @@ static int set_proto_ctx_param(struct drm_i915_file_private *fpriv,
        case I915_CONTEXT_PARAM_PERSISTENCE:
                if (args->size)
                        ret = -EINVAL;
-               ret = proto_context_set_persistence(fpriv->dev_priv, pc,
-                                                   args->value);
+               else
+                       ret = proto_context_set_persistence(fpriv->dev_priv, pc,
+                                                           args->value);
                break;
 
        case I915_CONTEXT_PARAM_PROTECTED_CONTENT:
index 3e5d605..1674b0c 100644 (file)
@@ -35,12 +35,12 @@ bool i915_gem_cpu_write_needs_clflush(struct drm_i915_gem_object *obj)
        if (obj->cache_dirty)
                return false;
 
-       if (!(obj->cache_coherent & I915_BO_CACHE_COHERENT_FOR_WRITE))
-               return true;
-
        if (IS_DGFX(i915))
                return false;
 
+       if (!(obj->cache_coherent & I915_BO_CACHE_COHERENT_FOR_WRITE))
+               return true;
+
        /* Currently in use by HW (display engine)? Keep flushed. */
        return i915_gem_object_is_framebuffer(obj);
 }
index f46ee16..a4fb577 100644 (file)
@@ -60,6 +60,8 @@ __i915_gem_object_create_region(struct intel_memory_region *mem,
        if (page_size)
                default_page_size = page_size;
 
+       /* We should be able to fit a page within an sg entry */
+       GEM_BUG_ON(overflows_type(default_page_size, u32));
        GEM_BUG_ON(!is_power_of_2_u64(default_page_size));
        GEM_BUG_ON(default_page_size < PAGE_SIZE);
 
index 4c25d9b..8f1bb6a 100644 (file)
@@ -620,10 +620,15 @@ i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
                         struct ttm_resource *res)
 {
        struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
+       u32 page_alignment;
 
        if (!i915_ttm_gtt_binds_lmem(res))
                return i915_ttm_tt_get_st(bo->ttm);
 
+       page_alignment = bo->page_alignment << PAGE_SHIFT;
+       if (!page_alignment)
+               page_alignment = obj->mm.region->min_page_size;
+
        /*
         * If CPU mapping differs, we need to add the ttm_tt pages to
         * the resulting st. Might make sense for GGTT.
@@ -634,7 +639,8 @@ i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
                        struct i915_refct_sgt *rsgt;
 
                        rsgt = intel_region_ttm_resource_to_rsgt(obj->mm.region,
-                                                                res);
+                                                                res,
+                                                                page_alignment);
                        if (IS_ERR(rsgt))
                                return rsgt;
 
@@ -643,7 +649,8 @@ i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
                return i915_refct_sgt_get(obj->ttm.cached_io_rsgt);
        }
 
-       return intel_region_ttm_resource_to_rsgt(obj->mm.region, res);
+       return intel_region_ttm_resource_to_rsgt(obj->mm.region, res,
+                                                page_alignment);
 }
 
 static int i915_ttm_truncate(struct drm_i915_gem_object *obj)
index 319936f..e6e01c2 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/jiffies.h>
 
 #include "gt/intel_engine.h"
+#include "gt/intel_rps.h"
 
 #include "i915_gem_ioctls.h"
 #include "i915_gem_object.h"
@@ -31,6 +32,37 @@ i915_gem_object_wait_fence(struct dma_fence *fence,
                                      timeout);
 }
 
+static void
+i915_gem_object_boost(struct dma_resv *resv, unsigned int flags)
+{
+       struct dma_resv_iter cursor;
+       struct dma_fence *fence;
+
+       /*
+        * Prescan all fences for potential boosting before we begin waiting.
+        *
+        * When we wait, we wait on outstanding fences serially. If the
+        * dma-resv contains a sequence such as 1:1, 1:2 instead of a reduced
+        * form 1:2, then as we look at each wait in turn we see that each
+        * request is currently executing and not worthy of boosting. But if
+        * we only happen to look at the final fence in the sequence (because
+        * of request coalescing or splitting between read/write arrays by
+        * the iterator), then we would boost. As such our decision to boost
+        * or not is delicately balanced on the order we wait on fences.
+        *
+        * So instead of looking for boosts sequentially, look for all boosts
+        * upfront and then wait on the outstanding fences.
+        */
+
+       dma_resv_iter_begin(&cursor, resv,
+                           dma_resv_usage_rw(flags & I915_WAIT_ALL));
+       dma_resv_for_each_fence_unlocked(&cursor, fence)
+               if (dma_fence_is_i915(fence) &&
+                   !i915_request_started(to_request(fence)))
+                       intel_rps_boost(to_request(fence));
+       dma_resv_iter_end(&cursor);
+}
+
 static long
 i915_gem_object_wait_reservation(struct dma_resv *resv,
                                 unsigned int flags,
@@ -40,6 +72,8 @@ i915_gem_object_wait_reservation(struct dma_resv *resv,
        struct dma_fence *fence;
        long ret = timeout ?: 1;
 
+       i915_gem_object_boost(resv, flags);
+
        dma_resv_iter_begin(&cursor, resv,
                            dma_resv_usage_rw(flags & I915_WAIT_ALL));
        dma_resv_for_each_fence_unlocked(&cursor, fence) {
index 09f8254..44e7339 100644 (file)
@@ -273,10 +273,17 @@ struct intel_context {
                u8 child_index;
                /** @guc: GuC specific members for parallel submission */
                struct {
-                       /** @wqi_head: head pointer in work queue */
+                       /** @wqi_head: cached head pointer in work queue */
                        u16 wqi_head;
-                       /** @wqi_tail: tail pointer in work queue */
+                       /** @wqi_tail: cached tail pointer in work queue */
                        u16 wqi_tail;
+                       /** @wq_head: pointer to the actual head in work queue */
+                       u32 *wq_head;
+                       /** @wq_tail: pointer to the actual head in work queue */
+                       u32 *wq_tail;
+                       /** @wq_status: pointer to the status in work queue */
+                       u32 *wq_status;
+
                        /**
                         * @parent_page: page in context state (ce->state) used
                         * by parent for work queue, process descriptor
index 1431f1e..04e435b 100644 (file)
@@ -201,6 +201,8 @@ int intel_ring_submission_setup(struct intel_engine_cs *engine);
 int intel_engine_stop_cs(struct intel_engine_cs *engine);
 void intel_engine_cancel_stop_cs(struct intel_engine_cs *engine);
 
+void intel_engine_wait_for_pending_mi_fw(struct intel_engine_cs *engine);
+
 void intel_engine_set_hwsp_writemask(struct intel_engine_cs *engine, u32 mask);
 
 u64 intel_engine_get_active_head(const struct intel_engine_cs *engine);
index 14c6ddb..5b6ce10 100644 (file)
@@ -1282,10 +1282,10 @@ static int __intel_engine_stop_cs(struct intel_engine_cs *engine,
        intel_uncore_write_fw(uncore, mode, _MASKED_BIT_ENABLE(STOP_RING));
 
        /*
-        * Wa_22011802037 : gen12, Prior to doing a reset, ensure CS is
+        * Wa_22011802037 : gen11, gen12, Prior to doing a reset, ensure CS is
         * stopped, set ring stop bit and prefetch disable bit to halt CS
         */
-       if (GRAPHICS_VER(engine->i915) == 12)
+       if (IS_GRAPHICS_VER(engine->i915, 11, 12))
                intel_uncore_write_fw(uncore, RING_MODE_GEN7(engine->mmio_base),
                                      _MASKED_BIT_ENABLE(GEN12_GFX_PREFETCH_DISABLE));
 
@@ -1308,6 +1308,18 @@ int intel_engine_stop_cs(struct intel_engine_cs *engine)
                return -ENODEV;
 
        ENGINE_TRACE(engine, "\n");
+       /*
+        * TODO: Find out why occasionally stopping the CS times out. Seen
+        * especially with gem_eio tests.
+        *
+        * Occasionally trying to stop the cs times out, but does not adversely
+        * affect functionality. The timeout is set as a config parameter that
+        * defaults to 100ms. In most cases the follow up operation is to wait
+        * for pending MI_FORCE_WAKES. The assumption is that this timeout is
+        * sufficient for any pending MI_FORCEWAKEs to complete. Once root
+        * caused, the caller must check and handle the return from this
+        * function.
+        */
        if (__intel_engine_stop_cs(engine, 1000, stop_timeout(engine))) {
                ENGINE_TRACE(engine,
                             "timed out on STOP_RING -> IDLE; HEAD:%04x, TAIL:%04x\n",
@@ -1334,6 +1346,78 @@ void intel_engine_cancel_stop_cs(struct intel_engine_cs *engine)
        ENGINE_WRITE_FW(engine, RING_MI_MODE, _MASKED_BIT_DISABLE(STOP_RING));
 }
 
+static u32 __cs_pending_mi_force_wakes(struct intel_engine_cs *engine)
+{
+       static const i915_reg_t _reg[I915_NUM_ENGINES] = {
+               [RCS0] = MSG_IDLE_CS,
+               [BCS0] = MSG_IDLE_BCS,
+               [VCS0] = MSG_IDLE_VCS0,
+               [VCS1] = MSG_IDLE_VCS1,
+               [VCS2] = MSG_IDLE_VCS2,
+               [VCS3] = MSG_IDLE_VCS3,
+               [VCS4] = MSG_IDLE_VCS4,
+               [VCS5] = MSG_IDLE_VCS5,
+               [VCS6] = MSG_IDLE_VCS6,
+               [VCS7] = MSG_IDLE_VCS7,
+               [VECS0] = MSG_IDLE_VECS0,
+               [VECS1] = MSG_IDLE_VECS1,
+               [VECS2] = MSG_IDLE_VECS2,
+               [VECS3] = MSG_IDLE_VECS3,
+               [CCS0] = MSG_IDLE_CS,
+               [CCS1] = MSG_IDLE_CS,
+               [CCS2] = MSG_IDLE_CS,
+               [CCS3] = MSG_IDLE_CS,
+       };
+       u32 val;
+
+       if (!_reg[engine->id].reg) {
+               drm_err(&engine->i915->drm,
+                       "MSG IDLE undefined for engine id %u\n", engine->id);
+               return 0;
+       }
+
+       val = intel_uncore_read(engine->uncore, _reg[engine->id]);
+
+       /* bits[29:25] & bits[13:9] >> shift */
+       return (val & (val >> 16) & MSG_IDLE_FW_MASK) >> MSG_IDLE_FW_SHIFT;
+}
+
+static void __gpm_wait_for_fw_complete(struct intel_gt *gt, u32 fw_mask)
+{
+       int ret;
+
+       /* Ensure GPM receives fw up/down after CS is stopped */
+       udelay(1);
+
+       /* Wait for forcewake request to complete in GPM */
+       ret =  __intel_wait_for_register_fw(gt->uncore,
+                                           GEN9_PWRGT_DOMAIN_STATUS,
+                                           fw_mask, fw_mask, 5000, 0, NULL);
+
+       /* Ensure CS receives fw ack from GPM */
+       udelay(1);
+
+       if (ret)
+               GT_TRACE(gt, "Failed to complete pending forcewake %d\n", ret);
+}
+
+/*
+ * Wa_22011802037:gen12: In addition to stopping the cs, we need to wait for any
+ * pending MI_FORCE_WAKEUP requests that the CS has initiated to complete. The
+ * pending status is indicated by bits[13:9] (masked by bits[29:25]) in the
+ * MSG_IDLE register. There's one MSG_IDLE register per reset domain. Since we
+ * are concerned only with the gt reset here, we use a logical OR of pending
+ * forcewakeups from all reset domains and then wait for them to complete by
+ * querying PWRGT_DOMAIN_STATUS.
+ */
+void intel_engine_wait_for_pending_mi_fw(struct intel_engine_cs *engine)
+{
+       u32 fw_pending = __cs_pending_mi_force_wakes(engine);
+
+       if (fw_pending)
+               __gpm_wait_for_fw_complete(engine->gt, fw_pending);
+}
+
 static u32
 read_subslice_reg(const struct intel_engine_cs *engine,
                  int slice, int subslice, i915_reg_t reg)
index 86f7a9a..0627fa1 100644 (file)
@@ -661,6 +661,16 @@ static inline void execlists_schedule_out(struct i915_request *rq)
        i915_request_put(rq);
 }
 
+static u32 map_i915_prio_to_lrc_desc_prio(int prio)
+{
+       if (prio > I915_PRIORITY_NORMAL)
+               return GEN12_CTX_PRIORITY_HIGH;
+       else if (prio < I915_PRIORITY_NORMAL)
+               return GEN12_CTX_PRIORITY_LOW;
+       else
+               return GEN12_CTX_PRIORITY_NORMAL;
+}
+
 static u64 execlists_update_context(struct i915_request *rq)
 {
        struct intel_context *ce = rq->context;
@@ -669,7 +679,7 @@ static u64 execlists_update_context(struct i915_request *rq)
 
        desc = ce->lrc.desc;
        if (rq->engine->flags & I915_ENGINE_HAS_EU_PRIORITY)
-               desc |= lrc_desc_priority(rq_prio(rq));
+               desc |= map_i915_prio_to_lrc_desc_prio(rq_prio(rq));
 
        /*
         * WaIdleLiteRestore:bdw,skl
@@ -2958,6 +2968,13 @@ static void execlists_reset_prepare(struct intel_engine_cs *engine)
        ring_set_paused(engine, 1);
        intel_engine_stop_cs(engine);
 
+       /*
+        * Wa_22011802037:gen11/gen12: In addition to stopping the cs, we need
+        * to wait for any pending mi force wakeups
+        */
+       if (IS_GRAPHICS_VER(engine->i915, 11, 12))
+               intel_engine_wait_for_pending_mi_fw(engine);
+
        engine->execlists.reset_ccid = active_ccid(engine);
 }
 
index 51a0fe6..531af6a 100644 (file)
@@ -1209,6 +1209,20 @@ void intel_gt_invalidate_tlbs(struct intel_gt *gt)
        mutex_lock(&gt->tlb_invalidate_lock);
        intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL);
 
+       spin_lock_irq(&uncore->lock); /* serialise invalidate with GT reset */
+
+       for_each_engine(engine, gt, id) {
+               struct reg_and_bit rb;
+
+               rb = get_reg_and_bit(engine, regs == gen8_regs, regs, num);
+               if (!i915_mmio_reg_offset(rb.reg))
+                       continue;
+
+               intel_uncore_write_fw(uncore, rb.reg, rb.bit);
+       }
+
+       spin_unlock_irq(&uncore->lock);
+
        for_each_engine(engine, gt, id) {
                /*
                 * HW architecture suggest typical invalidation time at 40us,
@@ -1223,7 +1237,6 @@ void intel_gt_invalidate_tlbs(struct intel_gt *gt)
                if (!i915_mmio_reg_offset(rb.reg))
                        continue;
 
-               intel_uncore_write_fw(uncore, rb.reg, rb.bit);
                if (__intel_wait_for_register_fw(uncore,
                                                 rb.reg, rb.bit, 0,
                                                 timeout_us, timeout_ms,
index 31be734..a390f08 100644 (file)
@@ -111,16 +111,6 @@ enum {
 #define XEHP_SW_COUNTER_SHIFT                  58
 #define XEHP_SW_COUNTER_WIDTH                  6
 
-static inline u32 lrc_desc_priority(int prio)
-{
-       if (prio > I915_PRIORITY_NORMAL)
-               return GEN12_CTX_PRIORITY_HIGH;
-       else if (prio < I915_PRIORITY_NORMAL)
-               return GEN12_CTX_PRIORITY_LOW;
-       else
-               return GEN12_CTX_PRIORITY_NORMAL;
-}
-
 static inline void lrc_runtime_start(struct intel_context *ce)
 {
        struct intel_context_stats *stats = &ce->stats;
index a5338c3..c68d36f 100644 (file)
@@ -300,9 +300,9 @@ static int gen6_hw_domain_reset(struct intel_gt *gt, u32 hw_domain_mask)
        return err;
 }
 
-static int gen6_reset_engines(struct intel_gt *gt,
-                             intel_engine_mask_t engine_mask,
-                             unsigned int retry)
+static int __gen6_reset_engines(struct intel_gt *gt,
+                               intel_engine_mask_t engine_mask,
+                               unsigned int retry)
 {
        struct intel_engine_cs *engine;
        u32 hw_mask;
@@ -321,6 +321,20 @@ static int gen6_reset_engines(struct intel_gt *gt,
        return gen6_hw_domain_reset(gt, hw_mask);
 }
 
+static int gen6_reset_engines(struct intel_gt *gt,
+                             intel_engine_mask_t engine_mask,
+                             unsigned int retry)
+{
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&gt->uncore->lock, flags);
+       ret = __gen6_reset_engines(gt, engine_mask, retry);
+       spin_unlock_irqrestore(&gt->uncore->lock, flags);
+
+       return ret;
+}
+
 static struct intel_engine_cs *find_sfc_paired_vecs_engine(struct intel_engine_cs *engine)
 {
        int vecs_id;
@@ -487,9 +501,9 @@ static void gen11_unlock_sfc(struct intel_engine_cs *engine)
        rmw_clear_fw(uncore, sfc_lock.lock_reg, sfc_lock.lock_bit);
 }
 
-static int gen11_reset_engines(struct intel_gt *gt,
-                              intel_engine_mask_t engine_mask,
-                              unsigned int retry)
+static int __gen11_reset_engines(struct intel_gt *gt,
+                                intel_engine_mask_t engine_mask,
+                                unsigned int retry)
 {
        struct intel_engine_cs *engine;
        intel_engine_mask_t tmp;
@@ -583,8 +597,11 @@ static int gen8_reset_engines(struct intel_gt *gt,
        struct intel_engine_cs *engine;
        const bool reset_non_ready = retry >= 1;
        intel_engine_mask_t tmp;
+       unsigned long flags;
        int ret;
 
+       spin_lock_irqsave(&gt->uncore->lock, flags);
+
        for_each_engine_masked(engine, gt, engine_mask, tmp) {
                ret = gen8_engine_reset_prepare(engine);
                if (ret && !reset_non_ready)
@@ -612,17 +629,19 @@ static int gen8_reset_engines(struct intel_gt *gt,
         * This is best effort, so ignore any error from the initial reset.
         */
        if (IS_DG2(gt->i915) && engine_mask == ALL_ENGINES)
-               gen11_reset_engines(gt, gt->info.engine_mask, 0);
+               __gen11_reset_engines(gt, gt->info.engine_mask, 0);
 
        if (GRAPHICS_VER(gt->i915) >= 11)
-               ret = gen11_reset_engines(gt, engine_mask, retry);
+               ret = __gen11_reset_engines(gt, engine_mask, retry);
        else
-               ret = gen6_reset_engines(gt, engine_mask, retry);
+               ret = __gen6_reset_engines(gt, engine_mask, retry);
 
 skip_reset:
        for_each_engine_masked(engine, gt, engine_mask, tmp)
                gen8_engine_reset_cancel(engine);
 
+       spin_unlock_irqrestore(&gt->uncore->lock, flags);
+
        return ret;
 }
 
index 8b2c11d..1109088 100644 (file)
@@ -176,8 +176,8 @@ static int live_lrc_layout(void *arg)
                        continue;
 
                hw = shmem_pin_map(engine->default_state);
-               if (IS_ERR(hw)) {
-                       err = PTR_ERR(hw);
+               if (!hw) {
+                       err = -ENOMEM;
                        break;
                }
                hw += LRC_STATE_OFFSET / sizeof(*hw);
@@ -365,8 +365,8 @@ static int live_lrc_fixed(void *arg)
                        continue;
 
                hw = shmem_pin_map(engine->default_state);
-               if (IS_ERR(hw)) {
-                       err = PTR_ERR(hw);
+               if (!hw) {
+                       err = -ENOMEM;
                        break;
                }
                hw += LRC_STATE_OFFSET / sizeof(*hw);
index 4ef9990..29ef8af 100644 (file)
@@ -122,6 +122,9 @@ enum intel_guc_action {
        INTEL_GUC_ACTION_SCHED_CONTEXT_MODE_DONE = 0x1002,
        INTEL_GUC_ACTION_SCHED_ENGINE_MODE_SET = 0x1003,
        INTEL_GUC_ACTION_SCHED_ENGINE_MODE_DONE = 0x1004,
+       INTEL_GUC_ACTION_V69_SET_CONTEXT_PRIORITY = 0x1005,
+       INTEL_GUC_ACTION_V69_SET_CONTEXT_EXECUTION_QUANTUM = 0x1006,
+       INTEL_GUC_ACTION_V69_SET_CONTEXT_PREEMPTION_TIMEOUT = 0x1007,
        INTEL_GUC_ACTION_CONTEXT_RESET_NOTIFICATION = 0x1008,
        INTEL_GUC_ACTION_ENGINE_FAILURE_NOTIFICATION = 0x1009,
        INTEL_GUC_ACTION_HOST2GUC_UPDATE_CONTEXT_POLICIES = 0x100B,
index 2c4ad4a..8c6885f 100644 (file)
@@ -310,8 +310,8 @@ static u32 guc_ctl_wa_flags(struct intel_guc *guc)
        if (IS_DG2(gt->i915))
                flags |= GUC_WA_DUAL_QUEUE;
 
-       /* Wa_22011802037: graphics version 12 */
-       if (GRAPHICS_VER(gt->i915) == 12)
+       /* Wa_22011802037: graphics version 11/12 */
+       if (IS_GRAPHICS_VER(gt->i915, 11, 12))
                flags |= GUC_WA_PRE_PARSER;
 
        /* Wa_16011777198:dg2 */
index 966e69a..9feda10 100644 (file)
@@ -170,6 +170,11 @@ struct intel_guc {
        /** @ads_engine_usage_size: size of engine usage in the ADS */
        u32 ads_engine_usage_size;
 
+       /** @lrc_desc_pool_v69: object allocated to hold the GuC LRC descriptor pool */
+       struct i915_vma *lrc_desc_pool_v69;
+       /** @lrc_desc_pool_vaddr_v69: contents of the GuC LRC descriptor pool */
+       void *lrc_desc_pool_vaddr_v69;
+
        /**
         * @context_lookup: used to resolve intel_context from guc_id, if a
         * context is present in this structure it is registered with the GuC
index 42cb7a9..89a7e5e 100644 (file)
@@ -203,6 +203,20 @@ struct guc_wq_item {
        u32 fence_id;
 } __packed;
 
+struct guc_process_desc_v69 {
+       u32 stage_id;
+       u64 db_base_addr;
+       u32 head;
+       u32 tail;
+       u32 error_offset;
+       u64 wq_base_addr;
+       u32 wq_size_bytes;
+       u32 wq_status;
+       u32 engine_presence;
+       u32 priority;
+       u32 reserved[36];
+} __packed;
+
 struct guc_sched_wq_desc {
        u32 head;
        u32 tail;
@@ -227,6 +241,37 @@ struct guc_ctxt_registration_info {
 };
 #define CONTEXT_REGISTRATION_FLAG_KMD  BIT(0)
 
+/* Preempt to idle on quantum expiry */
+#define CONTEXT_POLICY_FLAG_PREEMPT_TO_IDLE_V69        BIT(0)
+
+/*
+ * GuC Context registration descriptor.
+ * FIXME: This is only required to exist during context registration.
+ * The current 1:1 between guc_lrc_desc and LRCs for the lifetime of the LRC
+ * is not required.
+ */
+struct guc_lrc_desc_v69 {
+       u32 hw_context_desc;
+       u32 slpm_perf_mode_hint;        /* SPLC v1 only */
+       u32 slpm_freq_hint;
+       u32 engine_submit_mask;         /* In logical space */
+       u8 engine_class;
+       u8 reserved0[3];
+       u32 priority;
+       u32 process_desc;
+       u32 wq_addr;
+       u32 wq_size;
+       u32 context_flags;              /* CONTEXT_REGISTRATION_* */
+       /* Time for one workload to execute. (in micro seconds) */
+       u32 execution_quantum;
+       /* Time to wait for a preemption request to complete before issuing a
+        * reset. (in micro seconds).
+        */
+       u32 preemption_timeout;
+       u32 policy_flags;               /* CONTEXT_POLICY_* */
+       u32 reserved1[19];
+} __packed;
+
 /* 32-bit KLV structure as used by policy updates and others */
 struct guc_klv_generic_dw_t {
        u32 kl;
index 1726f0f..2d9f5f1 100644 (file)
@@ -414,12 +414,15 @@ struct sync_semaphore {
 };
 
 struct parent_scratch {
-       struct guc_sched_wq_desc wq_desc;
+       union guc_descs {
+               struct guc_sched_wq_desc wq_desc;
+               struct guc_process_desc_v69 pdesc;
+       } descs;
 
        struct sync_semaphore go;
        struct sync_semaphore join[MAX_ENGINE_INSTANCE + 1];
 
-       u8 unused[WQ_OFFSET - sizeof(struct guc_sched_wq_desc) -
+       u8 unused[WQ_OFFSET - sizeof(union guc_descs) -
                sizeof(struct sync_semaphore) * (MAX_ENGINE_INSTANCE + 2)];
 
        u32 wq[WQ_SIZE / sizeof(u32)];
@@ -456,17 +459,23 @@ __get_parent_scratch(struct intel_context *ce)
                   LRC_STATE_OFFSET) / sizeof(u32)));
 }
 
+static struct guc_process_desc_v69 *
+__get_process_desc_v69(struct intel_context *ce)
+{
+       struct parent_scratch *ps = __get_parent_scratch(ce);
+
+       return &ps->descs.pdesc;
+}
+
 static struct guc_sched_wq_desc *
-__get_wq_desc(struct intel_context *ce)
+__get_wq_desc_v70(struct intel_context *ce)
 {
        struct parent_scratch *ps = __get_parent_scratch(ce);
 
-       return &ps->wq_desc;
+       return &ps->descs.wq_desc;
 }
 
-static u32 *get_wq_pointer(struct guc_sched_wq_desc *wq_desc,
-                          struct intel_context *ce,
-                          u32 wqi_size)
+static u32 *get_wq_pointer(struct intel_context *ce, u32 wqi_size)
 {
        /*
         * Check for space in work queue. Caching a value of head pointer in
@@ -476,7 +485,7 @@ static u32 *get_wq_pointer(struct guc_sched_wq_desc *wq_desc,
 #define AVAILABLE_SPACE        \
        CIRC_SPACE(ce->parallel.guc.wqi_tail, ce->parallel.guc.wqi_head, WQ_SIZE)
        if (wqi_size > AVAILABLE_SPACE) {
-               ce->parallel.guc.wqi_head = READ_ONCE(wq_desc->head);
+               ce->parallel.guc.wqi_head = READ_ONCE(*ce->parallel.guc.wq_head);
 
                if (wqi_size > AVAILABLE_SPACE)
                        return NULL;
@@ -495,11 +504,55 @@ static inline struct intel_context *__get_context(struct intel_guc *guc, u32 id)
        return ce;
 }
 
+static struct guc_lrc_desc_v69 *__get_lrc_desc_v69(struct intel_guc *guc, u32 index)
+{
+       struct guc_lrc_desc_v69 *base = guc->lrc_desc_pool_vaddr_v69;
+
+       if (!base)
+               return NULL;
+
+       GEM_BUG_ON(index >= GUC_MAX_CONTEXT_ID);
+
+       return &base[index];
+}
+
+static int guc_lrc_desc_pool_create_v69(struct intel_guc *guc)
+{
+       u32 size;
+       int ret;
+
+       size = PAGE_ALIGN(sizeof(struct guc_lrc_desc_v69) *
+                         GUC_MAX_CONTEXT_ID);
+       ret = intel_guc_allocate_and_map_vma(guc, size, &guc->lrc_desc_pool_v69,
+                                            (void **)&guc->lrc_desc_pool_vaddr_v69);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static void guc_lrc_desc_pool_destroy_v69(struct intel_guc *guc)
+{
+       if (!guc->lrc_desc_pool_vaddr_v69)
+               return;
+
+       guc->lrc_desc_pool_vaddr_v69 = NULL;
+       i915_vma_unpin_and_release(&guc->lrc_desc_pool_v69, I915_VMA_RELEASE_MAP);
+}
+
 static inline bool guc_submission_initialized(struct intel_guc *guc)
 {
        return guc->submission_initialized;
 }
 
+static inline void _reset_lrc_desc_v69(struct intel_guc *guc, u32 id)
+{
+       struct guc_lrc_desc_v69 *desc = __get_lrc_desc_v69(guc, id);
+
+       if (desc)
+               memset(desc, 0, sizeof(*desc));
+}
+
 static inline bool ctx_id_mapped(struct intel_guc *guc, u32 id)
 {
        return __get_context(guc, id);
@@ -526,6 +579,8 @@ static inline void clr_ctx_id_mapping(struct intel_guc *guc, u32 id)
        if (unlikely(!guc_submission_initialized(guc)))
                return;
 
+       _reset_lrc_desc_v69(guc, id);
+
        /*
         * xarray API doesn't have xa_erase_irqsave wrapper, so calling
         * the lower level functions directly.
@@ -611,7 +666,7 @@ int intel_guc_wait_for_idle(struct intel_guc *guc, long timeout)
                                              true, timeout);
 }
 
-static int guc_context_policy_init(struct intel_context *ce, bool loop);
+static int guc_context_policy_init_v70(struct intel_context *ce, bool loop);
 static int try_context_registration(struct intel_context *ce, bool loop);
 
 static int __guc_add_request(struct intel_guc *guc, struct i915_request *rq)
@@ -639,7 +694,7 @@ static int __guc_add_request(struct intel_guc *guc, struct i915_request *rq)
        GEM_BUG_ON(context_guc_id_invalid(ce));
 
        if (context_policy_required(ce)) {
-               err = guc_context_policy_init(ce, false);
+               err = guc_context_policy_init_v70(ce, false);
                if (err)
                        return err;
        }
@@ -737,9 +792,7 @@ static u32 wq_space_until_wrap(struct intel_context *ce)
        return (WQ_SIZE - ce->parallel.guc.wqi_tail);
 }
 
-static void write_wqi(struct guc_sched_wq_desc *wq_desc,
-                     struct intel_context *ce,
-                     u32 wqi_size)
+static void write_wqi(struct intel_context *ce, u32 wqi_size)
 {
        BUILD_BUG_ON(!is_power_of_2(WQ_SIZE));
 
@@ -750,13 +803,12 @@ static void write_wqi(struct guc_sched_wq_desc *wq_desc,
 
        ce->parallel.guc.wqi_tail = (ce->parallel.guc.wqi_tail + wqi_size) &
                (WQ_SIZE - 1);
-       WRITE_ONCE(wq_desc->tail, ce->parallel.guc.wqi_tail);
+       WRITE_ONCE(*ce->parallel.guc.wq_tail, ce->parallel.guc.wqi_tail);
 }
 
 static int guc_wq_noop_append(struct intel_context *ce)
 {
-       struct guc_sched_wq_desc *wq_desc = __get_wq_desc(ce);
-       u32 *wqi = get_wq_pointer(wq_desc, ce, wq_space_until_wrap(ce));
+       u32 *wqi = get_wq_pointer(ce, wq_space_until_wrap(ce));
        u32 len_dw = wq_space_until_wrap(ce) / sizeof(u32) - 1;
 
        if (!wqi)
@@ -775,7 +827,6 @@ static int __guc_wq_item_append(struct i915_request *rq)
 {
        struct intel_context *ce = request_to_scheduling_context(rq);
        struct intel_context *child;
-       struct guc_sched_wq_desc *wq_desc = __get_wq_desc(ce);
        unsigned int wqi_size = (ce->parallel.number_children + 4) *
                sizeof(u32);
        u32 *wqi;
@@ -795,7 +846,7 @@ static int __guc_wq_item_append(struct i915_request *rq)
                        return ret;
        }
 
-       wqi = get_wq_pointer(wq_desc, ce, wqi_size);
+       wqi = get_wq_pointer(ce, wqi_size);
        if (!wqi)
                return -EBUSY;
 
@@ -810,7 +861,7 @@ static int __guc_wq_item_append(struct i915_request *rq)
        for_each_child(ce, child)
                *wqi++ = child->ring->tail / sizeof(u64);
 
-       write_wqi(wq_desc, ce, wqi_size);
+       write_wqi(ce, wqi_size);
 
        return 0;
 }
@@ -1527,87 +1578,18 @@ static void guc_reset_state(struct intel_context *ce, u32 head, bool scrub)
        lrc_update_regs(ce, engine, head);
 }
 
-static u32 __cs_pending_mi_force_wakes(struct intel_engine_cs *engine)
-{
-       static const i915_reg_t _reg[I915_NUM_ENGINES] = {
-               [RCS0] = MSG_IDLE_CS,
-               [BCS0] = MSG_IDLE_BCS,
-               [VCS0] = MSG_IDLE_VCS0,
-               [VCS1] = MSG_IDLE_VCS1,
-               [VCS2] = MSG_IDLE_VCS2,
-               [VCS3] = MSG_IDLE_VCS3,
-               [VCS4] = MSG_IDLE_VCS4,
-               [VCS5] = MSG_IDLE_VCS5,
-               [VCS6] = MSG_IDLE_VCS6,
-               [VCS7] = MSG_IDLE_VCS7,
-               [VECS0] = MSG_IDLE_VECS0,
-               [VECS1] = MSG_IDLE_VECS1,
-               [VECS2] = MSG_IDLE_VECS2,
-               [VECS3] = MSG_IDLE_VECS3,
-               [CCS0] = MSG_IDLE_CS,
-               [CCS1] = MSG_IDLE_CS,
-               [CCS2] = MSG_IDLE_CS,
-               [CCS3] = MSG_IDLE_CS,
-       };
-       u32 val;
-
-       if (!_reg[engine->id].reg)
-               return 0;
-
-       val = intel_uncore_read(engine->uncore, _reg[engine->id]);
-
-       /* bits[29:25] & bits[13:9] >> shift */
-       return (val & (val >> 16) & MSG_IDLE_FW_MASK) >> MSG_IDLE_FW_SHIFT;
-}
-
-static void __gpm_wait_for_fw_complete(struct intel_gt *gt, u32 fw_mask)
-{
-       int ret;
-
-       /* Ensure GPM receives fw up/down after CS is stopped */
-       udelay(1);
-
-       /* Wait for forcewake request to complete in GPM */
-       ret =  __intel_wait_for_register_fw(gt->uncore,
-                                           GEN9_PWRGT_DOMAIN_STATUS,
-                                           fw_mask, fw_mask, 5000, 0, NULL);
-
-       /* Ensure CS receives fw ack from GPM */
-       udelay(1);
-
-       if (ret)
-               GT_TRACE(gt, "Failed to complete pending forcewake %d\n", ret);
-}
-
-/*
- * Wa_22011802037:gen12: In addition to stopping the cs, we need to wait for any
- * pending MI_FORCE_WAKEUP requests that the CS has initiated to complete. The
- * pending status is indicated by bits[13:9] (masked by bits[ 29:25]) in the
- * MSG_IDLE register. There's one MSG_IDLE register per reset domain. Since we
- * are concerned only with the gt reset here, we use a logical OR of pending
- * forcewakeups from all reset domains and then wait for them to complete by
- * querying PWRGT_DOMAIN_STATUS.
- */
 static void guc_engine_reset_prepare(struct intel_engine_cs *engine)
 {
-       u32 fw_pending;
-
-       if (GRAPHICS_VER(engine->i915) != 12)
+       if (!IS_GRAPHICS_VER(engine->i915, 11, 12))
                return;
 
-       /*
-        * Wa_22011802037
-        * TODO: Occasionally trying to stop the cs times out, but does not
-        * adversely affect functionality. The timeout is set as a config
-        * parameter that defaults to 100ms. Assuming that this timeout is
-        * sufficient for any pending MI_FORCEWAKEs to complete, ignore the
-        * timeout returned here until it is root caused.
-        */
        intel_engine_stop_cs(engine);
 
-       fw_pending = __cs_pending_mi_force_wakes(engine);
-       if (fw_pending)
-               __gpm_wait_for_fw_complete(engine->gt, fw_pending);
+       /*
+        * Wa_22011802037:gen11/gen12: In addition to stopping the cs, we need
+        * to wait for any pending mi force wakeups
+        */
+       intel_engine_wait_for_pending_mi_fw(engine);
 }
 
 static void guc_reset_nop(struct intel_engine_cs *engine)
@@ -1868,20 +1850,34 @@ static void reset_fail_worker_func(struct work_struct *w);
 int intel_guc_submission_init(struct intel_guc *guc)
 {
        struct intel_gt *gt = guc_to_gt(guc);
+       int ret;
 
        if (guc->submission_initialized)
                return 0;
 
+       if (guc->fw.major_ver_found < 70) {
+               ret = guc_lrc_desc_pool_create_v69(guc);
+               if (ret)
+                       return ret;
+       }
+
        guc->submission_state.guc_ids_bitmap =
                bitmap_zalloc(NUMBER_MULTI_LRC_GUC_ID(guc), GFP_KERNEL);
-       if (!guc->submission_state.guc_ids_bitmap)
-               return -ENOMEM;
+       if (!guc->submission_state.guc_ids_bitmap) {
+               ret = -ENOMEM;
+               goto destroy_pool;
+       }
 
        guc->timestamp.ping_delay = (POLL_TIME_CLKS / gt->clock_frequency + 1) * HZ;
        guc->timestamp.shift = gpm_timestamp_shift(gt);
        guc->submission_initialized = true;
 
        return 0;
+
+destroy_pool:
+       guc_lrc_desc_pool_destroy_v69(guc);
+
+       return ret;
 }
 
 void intel_guc_submission_fini(struct intel_guc *guc)
@@ -1890,6 +1886,7 @@ void intel_guc_submission_fini(struct intel_guc *guc)
                return;
 
        guc_flush_destroyed_contexts(guc);
+       guc_lrc_desc_pool_destroy_v69(guc);
        i915_sched_engine_put(guc->sched_engine);
        bitmap_free(guc->submission_state.guc_ids_bitmap);
        guc->submission_initialized = false;
@@ -2147,10 +2144,34 @@ static void unpin_guc_id(struct intel_guc *guc, struct intel_context *ce)
        spin_unlock_irqrestore(&guc->submission_state.lock, flags);
 }
 
-static int __guc_action_register_multi_lrc(struct intel_guc *guc,
-                                          struct intel_context *ce,
-                                          struct guc_ctxt_registration_info *info,
-                                          bool loop)
+static int __guc_action_register_multi_lrc_v69(struct intel_guc *guc,
+                                              struct intel_context *ce,
+                                              u32 guc_id,
+                                              u32 offset,
+                                              bool loop)
+{
+       struct intel_context *child;
+       u32 action[4 + MAX_ENGINE_INSTANCE];
+       int len = 0;
+
+       GEM_BUG_ON(ce->parallel.number_children > MAX_ENGINE_INSTANCE);
+
+       action[len++] = INTEL_GUC_ACTION_REGISTER_CONTEXT_MULTI_LRC;
+       action[len++] = guc_id;
+       action[len++] = ce->parallel.number_children + 1;
+       action[len++] = offset;
+       for_each_child(ce, child) {
+               offset += sizeof(struct guc_lrc_desc_v69);
+               action[len++] = offset;
+       }
+
+       return guc_submission_send_busy_loop(guc, action, len, 0, loop);
+}
+
+static int __guc_action_register_multi_lrc_v70(struct intel_guc *guc,
+                                              struct intel_context *ce,
+                                              struct guc_ctxt_registration_info *info,
+                                              bool loop)
 {
        struct intel_context *child;
        u32 action[13 + (MAX_ENGINE_INSTANCE * 2)];
@@ -2190,9 +2211,24 @@ static int __guc_action_register_multi_lrc(struct intel_guc *guc,
        return guc_submission_send_busy_loop(guc, action, len, 0, loop);
 }
 
-static int __guc_action_register_context(struct intel_guc *guc,
-                                        struct guc_ctxt_registration_info *info,
-                                        bool loop)
+static int __guc_action_register_context_v69(struct intel_guc *guc,
+                                            u32 guc_id,
+                                            u32 offset,
+                                            bool loop)
+{
+       u32 action[] = {
+               INTEL_GUC_ACTION_REGISTER_CONTEXT,
+               guc_id,
+               offset,
+       };
+
+       return guc_submission_send_busy_loop(guc, action, ARRAY_SIZE(action),
+                                            0, loop);
+}
+
+static int __guc_action_register_context_v70(struct intel_guc *guc,
+                                            struct guc_ctxt_registration_info *info,
+                                            bool loop)
 {
        u32 action[] = {
                INTEL_GUC_ACTION_REGISTER_CONTEXT,
@@ -2213,24 +2249,52 @@ static int __guc_action_register_context(struct intel_guc *guc,
                                             0, loop);
 }
 
-static void prepare_context_registration_info(struct intel_context *ce,
-                                             struct guc_ctxt_registration_info *info);
+static void prepare_context_registration_info_v69(struct intel_context *ce);
+static void prepare_context_registration_info_v70(struct intel_context *ce,
+                                                 struct guc_ctxt_registration_info *info);
 
-static int register_context(struct intel_context *ce, bool loop)
+static int
+register_context_v69(struct intel_guc *guc, struct intel_context *ce, bool loop)
+{
+       u32 offset = intel_guc_ggtt_offset(guc, guc->lrc_desc_pool_v69) +
+               ce->guc_id.id * sizeof(struct guc_lrc_desc_v69);
+
+       prepare_context_registration_info_v69(ce);
+
+       if (intel_context_is_parent(ce))
+               return __guc_action_register_multi_lrc_v69(guc, ce, ce->guc_id.id,
+                                                          offset, loop);
+       else
+               return __guc_action_register_context_v69(guc, ce->guc_id.id,
+                                                        offset, loop);
+}
+
+static int
+register_context_v70(struct intel_guc *guc, struct intel_context *ce, bool loop)
 {
        struct guc_ctxt_registration_info info;
+
+       prepare_context_registration_info_v70(ce, &info);
+
+       if (intel_context_is_parent(ce))
+               return __guc_action_register_multi_lrc_v70(guc, ce, &info, loop);
+       else
+               return __guc_action_register_context_v70(guc, &info, loop);
+}
+
+static int register_context(struct intel_context *ce, bool loop)
+{
        struct intel_guc *guc = ce_to_guc(ce);
        int ret;
 
        GEM_BUG_ON(intel_context_is_child(ce));
        trace_intel_context_register(ce);
 
-       prepare_context_registration_info(ce, &info);
-
-       if (intel_context_is_parent(ce))
-               ret = __guc_action_register_multi_lrc(guc, ce, &info, loop);
+       if (guc->fw.major_ver_found >= 70)
+               ret = register_context_v70(guc, ce, loop);
        else
-               ret = __guc_action_register_context(guc, &info, loop);
+               ret = register_context_v69(guc, ce, loop);
+
        if (likely(!ret)) {
                unsigned long flags;
 
@@ -2238,7 +2302,8 @@ static int register_context(struct intel_context *ce, bool loop)
                set_context_registered(ce);
                spin_unlock_irqrestore(&ce->guc_state.lock, flags);
 
-               guc_context_policy_init(ce, loop);
+               if (guc->fw.major_ver_found >= 70)
+                       guc_context_policy_init_v70(ce, loop);
        }
 
        return ret;
@@ -2335,7 +2400,7 @@ static int __guc_context_set_context_policies(struct intel_guc *guc,
                                        0, loop);
 }
 
-static int guc_context_policy_init(struct intel_context *ce, bool loop)
+static int guc_context_policy_init_v70(struct intel_context *ce, bool loop)
 {
        struct intel_engine_cs *engine = ce->engine;
        struct intel_guc *guc = &engine->gt->uc.guc;
@@ -2394,8 +2459,108 @@ static int guc_context_policy_init(struct intel_context *ce, bool loop)
        return ret;
 }
 
-static void prepare_context_registration_info(struct intel_context *ce,
-                                             struct guc_ctxt_registration_info *info)
+static void guc_context_policy_init_v69(struct intel_engine_cs *engine,
+                                       struct guc_lrc_desc_v69 *desc)
+{
+       desc->policy_flags = 0;
+
+       if (engine->flags & I915_ENGINE_WANT_FORCED_PREEMPTION)
+               desc->policy_flags |= CONTEXT_POLICY_FLAG_PREEMPT_TO_IDLE_V69;
+
+       /* NB: For both of these, zero means disabled. */
+       desc->execution_quantum = engine->props.timeslice_duration_ms * 1000;
+       desc->preemption_timeout = engine->props.preempt_timeout_ms * 1000;
+}
+
+static u32 map_guc_prio_to_lrc_desc_prio(u8 prio)
+{
+       /*
+        * this matches the mapping we do in map_i915_prio_to_guc_prio()
+        * (e.g. prio < I915_PRIORITY_NORMAL maps to GUC_CLIENT_PRIORITY_NORMAL)
+        */
+       switch (prio) {
+       default:
+               MISSING_CASE(prio);
+               fallthrough;
+       case GUC_CLIENT_PRIORITY_KMD_NORMAL:
+               return GEN12_CTX_PRIORITY_NORMAL;
+       case GUC_CLIENT_PRIORITY_NORMAL:
+               return GEN12_CTX_PRIORITY_LOW;
+       case GUC_CLIENT_PRIORITY_HIGH:
+       case GUC_CLIENT_PRIORITY_KMD_HIGH:
+               return GEN12_CTX_PRIORITY_HIGH;
+       }
+}
+
+static void prepare_context_registration_info_v69(struct intel_context *ce)
+{
+       struct intel_engine_cs *engine = ce->engine;
+       struct intel_guc *guc = &engine->gt->uc.guc;
+       u32 ctx_id = ce->guc_id.id;
+       struct guc_lrc_desc_v69 *desc;
+       struct intel_context *child;
+
+       GEM_BUG_ON(!engine->mask);
+
+       /*
+        * Ensure LRC + CT vmas are is same region as write barrier is done
+        * based on CT vma region.
+        */
+       GEM_BUG_ON(i915_gem_object_is_lmem(guc->ct.vma->obj) !=
+                  i915_gem_object_is_lmem(ce->ring->vma->obj));
+
+       desc = __get_lrc_desc_v69(guc, ctx_id);
+       desc->engine_class = engine_class_to_guc_class(engine->class);
+       desc->engine_submit_mask = engine->logical_mask;
+       desc->hw_context_desc = ce->lrc.lrca;
+       desc->priority = ce->guc_state.prio;
+       desc->context_flags = CONTEXT_REGISTRATION_FLAG_KMD;
+       guc_context_policy_init_v69(engine, desc);
+
+       /*
+        * If context is a parent, we need to register a process descriptor
+        * describing a work queue and register all child contexts.
+        */
+       if (intel_context_is_parent(ce)) {
+               struct guc_process_desc_v69 *pdesc;
+
+               ce->parallel.guc.wqi_tail = 0;
+               ce->parallel.guc.wqi_head = 0;
+
+               desc->process_desc = i915_ggtt_offset(ce->state) +
+                       __get_parent_scratch_offset(ce);
+               desc->wq_addr = i915_ggtt_offset(ce->state) +
+                       __get_wq_offset(ce);
+               desc->wq_size = WQ_SIZE;
+
+               pdesc = __get_process_desc_v69(ce);
+               memset(pdesc, 0, sizeof(*(pdesc)));
+               pdesc->stage_id = ce->guc_id.id;
+               pdesc->wq_base_addr = desc->wq_addr;
+               pdesc->wq_size_bytes = desc->wq_size;
+               pdesc->wq_status = WQ_STATUS_ACTIVE;
+
+               ce->parallel.guc.wq_head = &pdesc->head;
+               ce->parallel.guc.wq_tail = &pdesc->tail;
+               ce->parallel.guc.wq_status = &pdesc->wq_status;
+
+               for_each_child(ce, child) {
+                       desc = __get_lrc_desc_v69(guc, child->guc_id.id);
+
+                       desc->engine_class =
+                               engine_class_to_guc_class(engine->class);
+                       desc->hw_context_desc = child->lrc.lrca;
+                       desc->priority = ce->guc_state.prio;
+                       desc->context_flags = CONTEXT_REGISTRATION_FLAG_KMD;
+                       guc_context_policy_init_v69(engine, desc);
+               }
+
+               clear_children_join_go_memory(ce);
+       }
+}
+
+static void prepare_context_registration_info_v70(struct intel_context *ce,
+                                                 struct guc_ctxt_registration_info *info)
 {
        struct intel_engine_cs *engine = ce->engine;
        struct intel_guc *guc = &engine->gt->uc.guc;
@@ -2420,6 +2585,8 @@ static void prepare_context_registration_info(struct intel_context *ce,
         */
        info->hwlrca_lo = lower_32_bits(ce->lrc.lrca);
        info->hwlrca_hi = upper_32_bits(ce->lrc.lrca);
+       if (engine->flags & I915_ENGINE_HAS_EU_PRIORITY)
+               info->hwlrca_lo |= map_guc_prio_to_lrc_desc_prio(ce->guc_state.prio);
        info->flags = CONTEXT_REGISTRATION_FLAG_KMD;
 
        /*
@@ -2443,10 +2610,14 @@ static void prepare_context_registration_info(struct intel_context *ce,
                info->wq_base_hi = upper_32_bits(wq_base_offset);
                info->wq_size = WQ_SIZE;
 
-               wq_desc = __get_wq_desc(ce);
+               wq_desc = __get_wq_desc_v70(ce);
                memset(wq_desc, 0, sizeof(*wq_desc));
                wq_desc->wq_status = WQ_STATUS_ACTIVE;
 
+               ce->parallel.guc.wq_head = &wq_desc->head;
+               ce->parallel.guc.wq_tail = &wq_desc->tail;
+               ce->parallel.guc.wq_status = &wq_desc->wq_status;
+
                clear_children_join_go_memory(ce);
        }
 }
@@ -2761,11 +2932,21 @@ static void __guc_context_set_preemption_timeout(struct intel_guc *guc,
                                                 u16 guc_id,
                                                 u32 preemption_timeout)
 {
-       struct context_policy policy;
+       if (guc->fw.major_ver_found >= 70) {
+               struct context_policy policy;
 
-       __guc_context_policy_start_klv(&policy, guc_id);
-       __guc_context_policy_add_preemption_timeout(&policy, preemption_timeout);
-       __guc_context_set_context_policies(guc, &policy, true);
+               __guc_context_policy_start_klv(&policy, guc_id);
+               __guc_context_policy_add_preemption_timeout(&policy, preemption_timeout);
+               __guc_context_set_context_policies(guc, &policy, true);
+       } else {
+               u32 action[] = {
+                       INTEL_GUC_ACTION_V69_SET_CONTEXT_PREEMPTION_TIMEOUT,
+                       guc_id,
+                       preemption_timeout
+               };
+
+               intel_guc_send_busy_loop(guc, action, ARRAY_SIZE(action), 0, true);
+       }
 }
 
 static void guc_context_ban(struct intel_context *ce, struct i915_request *rq)
@@ -3013,11 +3194,21 @@ static int guc_context_alloc(struct intel_context *ce)
 static void __guc_context_set_prio(struct intel_guc *guc,
                                   struct intel_context *ce)
 {
-       struct context_policy policy;
+       if (guc->fw.major_ver_found >= 70) {
+               struct context_policy policy;
 
-       __guc_context_policy_start_klv(&policy, ce->guc_id.id);
-       __guc_context_policy_add_priority(&policy, ce->guc_state.prio);
-       __guc_context_set_context_policies(guc, &policy, true);
+               __guc_context_policy_start_klv(&policy, ce->guc_id.id);
+               __guc_context_policy_add_priority(&policy, ce->guc_state.prio);
+               __guc_context_set_context_policies(guc, &policy, true);
+       } else {
+               u32 action[] = {
+                       INTEL_GUC_ACTION_V69_SET_CONTEXT_PRIORITY,
+                       ce->guc_id.id,
+                       ce->guc_state.prio,
+               };
+
+               guc_submission_send_busy_loop(guc, action, ARRAY_SIZE(action), 0, true);
+       }
 }
 
 static void guc_context_set_prio(struct intel_guc *guc,
@@ -4527,17 +4718,19 @@ void intel_guc_submission_print_context_info(struct intel_guc *guc,
                guc_log_context_priority(p, ce);
 
                if (intel_context_is_parent(ce)) {
-                       struct guc_sched_wq_desc *wq_desc = __get_wq_desc(ce);
                        struct intel_context *child;
 
                        drm_printf(p, "\t\tNumber children: %u\n",
                                   ce->parallel.number_children);
-                       drm_printf(p, "\t\tWQI Head: %u\n",
-                                  READ_ONCE(wq_desc->head));
-                       drm_printf(p, "\t\tWQI Tail: %u\n",
-                                  READ_ONCE(wq_desc->tail));
-                       drm_printf(p, "\t\tWQI Status: %u\n\n",
-                                  READ_ONCE(wq_desc->wq_status));
+
+                       if (ce->parallel.guc.wq_status) {
+                               drm_printf(p, "\t\tWQI Head: %u\n",
+                                          READ_ONCE(*ce->parallel.guc.wq_head));
+                               drm_printf(p, "\t\tWQI Tail: %u\n",
+                                          READ_ONCE(*ce->parallel.guc.wq_tail));
+                               drm_printf(p, "\t\tWQI Status: %u\n\n",
+                                          READ_ONCE(*ce->parallel.guc.wq_status));
+                       }
 
                        if (ce->engine->emit_bb_start ==
                            emit_bb_start_parent_no_preempt_mid_batch) {
index f0d7b57..703f42b 100644 (file)
@@ -70,6 +70,10 @@ void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw,
        fw_def(BROXTON,      0, guc_def(bxt,  70, 1, 1)) \
        fw_def(SKYLAKE,      0, guc_def(skl,  70, 1, 1))
 
+#define INTEL_GUC_FIRMWARE_DEFS_FALLBACK(fw_def, guc_def) \
+       fw_def(ALDERLAKE_P,  0, guc_def(adlp, 69, 0, 3)) \
+       fw_def(ALDERLAKE_S,  0, guc_def(tgl,  69, 0, 3))
+
 #define INTEL_HUC_FIRMWARE_DEFS(fw_def, huc_def) \
        fw_def(ALDERLAKE_P,  0, huc_def(tgl,  7, 9, 3)) \
        fw_def(ALDERLAKE_S,  0, huc_def(tgl,  7, 9, 3)) \
@@ -105,6 +109,7 @@ void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw,
        MODULE_FIRMWARE(uc_);
 
 INTEL_GUC_FIRMWARE_DEFS(INTEL_UC_MODULE_FW, MAKE_GUC_FW_PATH)
+INTEL_GUC_FIRMWARE_DEFS_FALLBACK(INTEL_UC_MODULE_FW, MAKE_GUC_FW_PATH)
 INTEL_HUC_FIRMWARE_DEFS(INTEL_UC_MODULE_FW, MAKE_HUC_FW_PATH)
 
 /* The below structs and macros are used to iterate across the list of blobs */
@@ -149,6 +154,9 @@ __uc_fw_auto_select(struct drm_i915_private *i915, struct intel_uc_fw *uc_fw)
        static const struct uc_fw_platform_requirement blobs_guc[] = {
                INTEL_GUC_FIRMWARE_DEFS(MAKE_FW_LIST, GUC_FW_BLOB)
        };
+       static const struct uc_fw_platform_requirement blobs_guc_fallback[] = {
+               INTEL_GUC_FIRMWARE_DEFS_FALLBACK(MAKE_FW_LIST, GUC_FW_BLOB)
+       };
        static const struct uc_fw_platform_requirement blobs_huc[] = {
                INTEL_HUC_FIRMWARE_DEFS(MAKE_FW_LIST, HUC_FW_BLOB)
        };
@@ -162,6 +170,15 @@ __uc_fw_auto_select(struct drm_i915_private *i915, struct intel_uc_fw *uc_fw)
        u8 rev = INTEL_REVID(i915);
        int i;
 
+       /*
+        * The only difference between the ADL GuC FWs is the HWConfig support.
+        * ADL-N does not support HWConfig, so we should use the same binary as
+        * ADL-S, otherwise the GuC might attempt to fetch a config table that
+        * does not exist.
+        */
+       if (IS_ADLP_N(i915))
+               p = INTEL_ALDERLAKE_S;
+
        GEM_BUG_ON(uc_fw->type >= ARRAY_SIZE(blobs_all));
        fw_blobs = blobs_all[uc_fw->type].blobs;
        fw_count = blobs_all[uc_fw->type].count;
@@ -170,12 +187,29 @@ __uc_fw_auto_select(struct drm_i915_private *i915, struct intel_uc_fw *uc_fw)
                if (p == fw_blobs[i].p && rev >= fw_blobs[i].rev) {
                        const struct uc_fw_blob *blob = &fw_blobs[i].blob;
                        uc_fw->path = blob->path;
+                       uc_fw->wanted_path = blob->path;
                        uc_fw->major_ver_wanted = blob->major;
                        uc_fw->minor_ver_wanted = blob->minor;
                        break;
                }
        }
 
+       if (uc_fw->type == INTEL_UC_FW_TYPE_GUC) {
+               const struct uc_fw_platform_requirement *blobs = blobs_guc_fallback;
+               u32 count = ARRAY_SIZE(blobs_guc_fallback);
+
+               for (i = 0; i < count && p <= blobs[i].p; i++) {
+                       if (p == blobs[i].p && rev >= blobs[i].rev) {
+                               const struct uc_fw_blob *blob = &blobs[i].blob;
+
+                               uc_fw->fallback.path = blob->path;
+                               uc_fw->fallback.major_ver = blob->major;
+                               uc_fw->fallback.minor_ver = blob->minor;
+                               break;
+                       }
+               }
+       }
+
        /* make sure the list is ordered as expected */
        if (IS_ENABLED(CONFIG_DRM_I915_SELFTEST)) {
                for (i = 1; i < fw_count; i++) {
@@ -329,7 +363,24 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw)
        __force_fw_fetch_failures(uc_fw, -EINVAL);
        __force_fw_fetch_failures(uc_fw, -ESTALE);
 
-       err = request_firmware(&fw, uc_fw->path, dev);
+       err = firmware_request_nowarn(&fw, uc_fw->path, dev);
+       if (err && !intel_uc_fw_is_overridden(uc_fw) && uc_fw->fallback.path) {
+               err = firmware_request_nowarn(&fw, uc_fw->fallback.path, dev);
+               if (!err) {
+                       drm_notice(&i915->drm,
+                                  "%s firmware %s is recommended, but only %s was found\n",
+                                  intel_uc_fw_type_repr(uc_fw->type),
+                                  uc_fw->wanted_path,
+                                  uc_fw->fallback.path);
+                       drm_info(&i915->drm,
+                                "Consider updating your linux-firmware pkg or downloading from %s\n",
+                                INTEL_UC_FIRMWARE_URL);
+
+                       uc_fw->path = uc_fw->fallback.path;
+                       uc_fw->major_ver_wanted = uc_fw->fallback.major_ver;
+                       uc_fw->minor_ver_wanted = uc_fw->fallback.minor_ver;
+               }
+       }
        if (err)
                goto fail;
 
@@ -428,8 +479,8 @@ fail:
                                  INTEL_UC_FIRMWARE_MISSING :
                                  INTEL_UC_FIRMWARE_ERROR);
 
-       drm_notice(&i915->drm, "%s firmware %s: fetch failed with error %d\n",
-                  intel_uc_fw_type_repr(uc_fw->type), uc_fw->path, err);
+       i915_probe_error(i915, "%s firmware %s: fetch failed with error %d\n",
+                        intel_uc_fw_type_repr(uc_fw->type), uc_fw->path, err);
        drm_info(&i915->drm, "%s firmware(s) can be downloaded from %s\n",
                 intel_uc_fw_type_repr(uc_fw->type), INTEL_UC_FIRMWARE_URL);
 
@@ -787,7 +838,13 @@ size_t intel_uc_fw_copy_rsa(struct intel_uc_fw *uc_fw, void *dst, u32 max_len)
 void intel_uc_fw_dump(const struct intel_uc_fw *uc_fw, struct drm_printer *p)
 {
        drm_printf(p, "%s firmware: %s\n",
-                  intel_uc_fw_type_repr(uc_fw->type), uc_fw->path);
+                  intel_uc_fw_type_repr(uc_fw->type), uc_fw->wanted_path);
+       if (uc_fw->fallback.path) {
+               drm_printf(p, "%s firmware fallback: %s\n",
+                          intel_uc_fw_type_repr(uc_fw->type), uc_fw->fallback.path);
+               drm_printf(p, "fallback selected: %s\n",
+                          str_yes_no(uc_fw->path == uc_fw->fallback.path));
+       }
        drm_printf(p, "\tstatus: %s\n",
                   intel_uc_fw_status_repr(uc_fw->status));
        drm_printf(p, "\tversion: wanted %u.%u, found %u.%u\n",
index 3229018..562acdf 100644 (file)
@@ -74,6 +74,7 @@ struct intel_uc_fw {
                const enum intel_uc_fw_status status;
                enum intel_uc_fw_status __status; /* no accidental overwrites */
        };
+       const char *wanted_path;
        const char *path;
        bool user_overridden;
        size_t size;
@@ -98,6 +99,12 @@ struct intel_uc_fw {
        u16 major_ver_found;
        u16 minor_ver_found;
 
+       struct {
+               const char *path;
+               u16 major_ver;
+               u16 minor_ver;
+       } fallback;
+
        u32 rsa_size;
        u32 ucode_size;
 
index b9eb75a..1c35a41 100644 (file)
@@ -3117,9 +3117,9 @@ void intel_gvt_update_reg_whitelist(struct intel_vgpu *vgpu)
                        continue;
 
                vaddr = shmem_pin_map(engine->default_state);
-               if (IS_ERR(vaddr)) {
-                       gvt_err("failed to map %s->default state, err:%zd\n",
-                               engine->name, PTR_ERR(vaddr));
+               if (!vaddr) {
+                       gvt_err("failed to map %s->default state\n",
+                               engine->name);
                        return;
                }
 
index 90b0ce5..1041b53 100644 (file)
@@ -530,6 +530,7 @@ mask_err:
 static int i915_driver_hw_probe(struct drm_i915_private *dev_priv)
 {
        struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev);
+       struct pci_dev *root_pdev;
        int ret;
 
        if (i915_inject_probe_failure(dev_priv))
@@ -641,6 +642,15 @@ static int i915_driver_hw_probe(struct drm_i915_private *dev_priv)
 
        intel_bw_init_hw(dev_priv);
 
+       /*
+        * FIXME: Temporary hammer to avoid freezing the machine on our DGFX
+        * This should be totally removed when we handle the pci states properly
+        * on runtime PM and on s2idle cases.
+        */
+       root_pdev = pcie_find_root_port(pdev);
+       if (root_pdev)
+               pci_d3cold_disable(root_pdev);
+
        return 0;
 
 err_msi:
@@ -664,11 +674,16 @@ err_perf:
 static void i915_driver_hw_remove(struct drm_i915_private *dev_priv)
 {
        struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev);
+       struct pci_dev *root_pdev;
 
        i915_perf_fini(dev_priv);
 
        if (pdev->msi_enabled)
                pci_disable_msi(pdev);
+
+       root_pdev = pcie_find_root_port(pdev);
+       if (root_pdev)
+               pci_d3cold_enable(root_pdev);
 }
 
 /**
@@ -1193,14 +1208,6 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation)
                goto out;
        }
 
-       /*
-        * FIXME: Temporary hammer to avoid freezing the machine on our DGFX
-        * This should be totally removed when we handle the pci states properly
-        * on runtime PM and on s2idle cases.
-        */
-       if (suspend_to_idle(dev_priv))
-               pci_d3cold_disable(pdev);
-
        pci_disable_device(pdev);
        /*
         * During hibernation on some platforms the BIOS may try to access
@@ -1365,8 +1372,6 @@ static int i915_drm_resume_early(struct drm_device *dev)
 
        pci_set_master(pdev);
 
-       pci_d3cold_enable(pdev);
-
        disable_rpm_wakeref_asserts(&dev_priv->runtime_pm);
 
        ret = vlv_resume_prepare(dev_priv, false);
@@ -1543,7 +1548,6 @@ static int intel_runtime_suspend(struct device *kdev)
 {
        struct drm_i915_private *dev_priv = kdev_to_i915(kdev);
        struct intel_runtime_pm *rpm = &dev_priv->runtime_pm;
-       struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev);
        int ret;
 
        if (drm_WARN_ON_ONCE(&dev_priv->drm, !HAS_RUNTIME_PM(dev_priv)))
@@ -1589,12 +1593,6 @@ static int intel_runtime_suspend(struct device *kdev)
                drm_err(&dev_priv->drm,
                        "Unclaimed access detected prior to suspending\n");
 
-       /*
-        * FIXME: Temporary hammer to avoid freezing the machine on our DGFX
-        * This should be totally removed when we handle the pci states properly
-        * on runtime PM and on s2idle cases.
-        */
-       pci_d3cold_disable(pdev);
        rpm->suspended = true;
 
        /*
@@ -1633,7 +1631,6 @@ static int intel_runtime_resume(struct device *kdev)
 {
        struct drm_i915_private *dev_priv = kdev_to_i915(kdev);
        struct intel_runtime_pm *rpm = &dev_priv->runtime_pm;
-       struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev);
        int ret;
 
        if (drm_WARN_ON_ONCE(&dev_priv->drm, !HAS_RUNTIME_PM(dev_priv)))
@@ -1646,7 +1643,6 @@ static int intel_runtime_resume(struct device *kdev)
 
        intel_opregion_notify_adapter(dev_priv, PCI_D0);
        rpm->suspended = false;
-       pci_d3cold_enable(pdev);
        if (intel_uncore_unclaimed_mmio(&dev_priv->uncore))
                drm_dbg(&dev_priv->drm,
                        "Unclaimed access during suspend, bios?\n");
index 159571b..dcc0818 100644 (file)
@@ -68,6 +68,7 @@ void i915_refct_sgt_init(struct i915_refct_sgt *rsgt, size_t size)
  * drm_mm_node
  * @node: The drm_mm_node.
  * @region_start: An offset to add to the dma addresses of the sg list.
+ * @page_alignment: Required page alignment for each sg entry. Power of two.
  *
  * Create a struct sg_table, initializing it from a struct drm_mm_node,
  * taking a maximum segment length into account, splitting into segments
@@ -77,22 +78,25 @@ void i915_refct_sgt_init(struct i915_refct_sgt *rsgt, size_t size)
  * error code cast to an error pointer on failure.
  */
 struct i915_refct_sgt *i915_rsgt_from_mm_node(const struct drm_mm_node *node,
-                                             u64 region_start)
+                                             u64 region_start,
+                                             u32 page_alignment)
 {
-       const u64 max_segment = SZ_1G; /* Do we have a limit on this? */
-       u64 segment_pages = max_segment >> PAGE_SHIFT;
+       const u32 max_segment = round_down(UINT_MAX, page_alignment);
+       const u32 segment_pages = max_segment >> PAGE_SHIFT;
        u64 block_size, offset, prev_end;
        struct i915_refct_sgt *rsgt;
        struct sg_table *st;
        struct scatterlist *sg;
 
+       GEM_BUG_ON(!max_segment);
+
        rsgt = kmalloc(sizeof(*rsgt), GFP_KERNEL);
        if (!rsgt)
                return ERR_PTR(-ENOMEM);
 
        i915_refct_sgt_init(rsgt, node->size << PAGE_SHIFT);
        st = &rsgt->table;
-       if (sg_alloc_table(st, DIV_ROUND_UP(node->size, segment_pages),
+       if (sg_alloc_table(st, DIV_ROUND_UP_ULL(node->size, segment_pages),
                           GFP_KERNEL)) {
                i915_refct_sgt_put(rsgt);
                return ERR_PTR(-ENOMEM);
@@ -112,12 +116,14 @@ struct i915_refct_sgt *i915_rsgt_from_mm_node(const struct drm_mm_node *node,
                                sg = __sg_next(sg);
 
                        sg_dma_address(sg) = region_start + offset;
+                       GEM_BUG_ON(!IS_ALIGNED(sg_dma_address(sg),
+                                              page_alignment));
                        sg_dma_len(sg) = 0;
                        sg->length = 0;
                        st->nents++;
                }
 
-               len = min(block_size, max_segment - sg->length);
+               len = min_t(u64, block_size, max_segment - sg->length);
                sg->length += len;
                sg_dma_len(sg) += len;
 
@@ -138,6 +144,7 @@ struct i915_refct_sgt *i915_rsgt_from_mm_node(const struct drm_mm_node *node,
  * i915_buddy_block list
  * @res: The struct i915_ttm_buddy_resource.
  * @region_start: An offset to add to the dma addresses of the sg list.
+ * @page_alignment: Required page alignment for each sg entry. Power of two.
  *
  * Create a struct sg_table, initializing it from struct i915_buddy_block list,
  * taking a maximum segment length into account, splitting into segments
@@ -147,11 +154,12 @@ struct i915_refct_sgt *i915_rsgt_from_mm_node(const struct drm_mm_node *node,
  * error code cast to an error pointer on failure.
  */
 struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res,
-                                                    u64 region_start)
+                                                    u64 region_start,
+                                                    u32 page_alignment)
 {
        struct i915_ttm_buddy_resource *bman_res = to_ttm_buddy_resource(res);
        const u64 size = res->num_pages << PAGE_SHIFT;
-       const u64 max_segment = rounddown(UINT_MAX, PAGE_SIZE);
+       const u32 max_segment = round_down(UINT_MAX, page_alignment);
        struct drm_buddy *mm = bman_res->mm;
        struct list_head *blocks = &bman_res->blocks;
        struct drm_buddy_block *block;
@@ -161,6 +169,7 @@ struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res,
        resource_size_t prev_end;
 
        GEM_BUG_ON(list_empty(blocks));
+       GEM_BUG_ON(!max_segment);
 
        rsgt = kmalloc(sizeof(*rsgt), GFP_KERNEL);
        if (!rsgt)
@@ -191,12 +200,14 @@ struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res,
                                        sg = __sg_next(sg);
 
                                sg_dma_address(sg) = region_start + offset;
+                               GEM_BUG_ON(!IS_ALIGNED(sg_dma_address(sg),
+                                                      page_alignment));
                                sg_dma_len(sg) = 0;
                                sg->length = 0;
                                st->nents++;
                        }
 
-                       len = min(block_size, max_segment - sg->length);
+                       len = min_t(u64, block_size, max_segment - sg->length);
                        sg->length += len;
                        sg_dma_len(sg) += len;
 
index 12c6a16..9ddb3e7 100644 (file)
@@ -213,9 +213,11 @@ static inline void __i915_refct_sgt_init(struct i915_refct_sgt *rsgt,
 void i915_refct_sgt_init(struct i915_refct_sgt *rsgt, size_t size);
 
 struct i915_refct_sgt *i915_rsgt_from_mm_node(const struct drm_mm_node *node,
-                                             u64 region_start);
+                                             u64 region_start,
+                                             u32 page_alignment);
 
 struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res,
-                                                    u64 region_start);
+                                                    u64 region_start,
+                                                    u32 page_alignment);
 
 #endif
index 0bffb70..04d12f2 100644 (file)
@@ -1637,10 +1637,10 @@ static void force_unbind(struct i915_vma *vma)
        GEM_BUG_ON(drm_mm_node_allocated(&vma->node));
 }
 
-static void release_references(struct i915_vma *vma, bool vm_ddestroy)
+static void release_references(struct i915_vma *vma, struct intel_gt *gt,
+                              bool vm_ddestroy)
 {
        struct drm_i915_gem_object *obj = vma->obj;
-       struct intel_gt *gt = vma->vm->gt;
 
        GEM_BUG_ON(i915_vma_is_active(vma));
 
@@ -1695,11 +1695,12 @@ void i915_vma_destroy_locked(struct i915_vma *vma)
 
        force_unbind(vma);
        list_del_init(&vma->vm_link);
-       release_references(vma, false);
+       release_references(vma, vma->vm->gt, false);
 }
 
 void i915_vma_destroy(struct i915_vma *vma)
 {
+       struct intel_gt *gt;
        bool vm_ddestroy;
 
        mutex_lock(&vma->vm->mutex);
@@ -1707,8 +1708,11 @@ void i915_vma_destroy(struct i915_vma *vma)
        list_del_init(&vma->vm_link);
        vm_ddestroy = vma->vm_ddestroy;
        vma->vm_ddestroy = false;
+
+       /* vma->vm may be freed when releasing vma->vm->mutex. */
+       gt = vma->vm->gt;
        mutex_unlock(&vma->vm->mutex);
-       release_references(vma, vm_ddestroy);
+       release_references(vma, gt, vm_ddestroy);
 }
 
 void i915_vma_parked(struct intel_gt *gt)
index 62ff774..575d67b 100644 (file)
@@ -152,6 +152,7 @@ int intel_region_ttm_fini(struct intel_memory_region *mem)
  * Convert an opaque TTM resource manager resource to a refcounted sg_table.
  * @mem: The memory region.
  * @res: The resource manager resource obtained from the TTM resource manager.
+ * @page_alignment: Required page alignment for each sg entry. Power of two.
  *
  * The gem backends typically use sg-tables for operations on the underlying
  * io_memory. So provide a way for the backends to translate the
@@ -161,16 +162,19 @@ int intel_region_ttm_fini(struct intel_memory_region *mem)
  */
 struct i915_refct_sgt *
 intel_region_ttm_resource_to_rsgt(struct intel_memory_region *mem,
-                                 struct ttm_resource *res)
+                                 struct ttm_resource *res,
+                                 u32 page_alignment)
 {
        if (mem->is_range_manager) {
                struct ttm_range_mgr_node *range_node =
                        to_ttm_range_mgr_node(res);
 
                return i915_rsgt_from_mm_node(&range_node->mm_nodes[0],
-                                             mem->region.start);
+                                             mem->region.start,
+                                             page_alignment);
        } else {
-               return i915_rsgt_from_buddy_resource(res, mem->region.start);
+               return i915_rsgt_from_buddy_resource(res, mem->region.start,
+                                                    page_alignment);
        }
 }
 
index cf9d86d..5bb8d8b 100644 (file)
@@ -24,7 +24,8 @@ int intel_region_ttm_fini(struct intel_memory_region *mem);
 
 struct i915_refct_sgt *
 intel_region_ttm_resource_to_rsgt(struct intel_memory_region *mem,
-                                 struct ttm_resource *res);
+                                 struct ttm_resource *res,
+                                 u32 page_alignment);
 
 void intel_region_ttm_resource_free(struct intel_memory_region *mem,
                                    struct ttm_resource *res);
index 8633bec..ab9f17f 100644 (file)
@@ -742,7 +742,7 @@ static int pot_hole(struct i915_address_space *vm,
                u64 addr;
 
                for (addr = round_up(hole_start + min_alignment, step) - min_alignment;
-                    addr <= round_down(hole_end - (2 * min_alignment), step) - min_alignment;
+                    hole_end > addr && hole_end - addr >= 2 * min_alignment;
                     addr += step) {
                        err = i915_vma_pin(vma, 0, 0, addr | flags);
                        if (err) {
index 73eb53e..3b18e59 100644 (file)
@@ -451,7 +451,6 @@ out_put:
 
 static int igt_mock_max_segment(void *arg)
 {
-       const unsigned int max_segment = rounddown(UINT_MAX, PAGE_SIZE);
        struct intel_memory_region *mem = arg;
        struct drm_i915_private *i915 = mem->i915;
        struct i915_ttm_buddy_resource *res;
@@ -460,7 +459,10 @@ static int igt_mock_max_segment(void *arg)
        struct drm_buddy *mm;
        struct list_head *blocks;
        struct scatterlist *sg;
+       I915_RND_STATE(prng);
        LIST_HEAD(objects);
+       unsigned int max_segment;
+       unsigned int ps;
        u64 size;
        int err = 0;
 
@@ -472,7 +474,13 @@ static int igt_mock_max_segment(void *arg)
         */
 
        size = SZ_8G;
-       mem = mock_region_create(i915, 0, size, PAGE_SIZE, 0, 0);
+       ps = PAGE_SIZE;
+       if (i915_prandom_u64_state(&prng) & 1)
+               ps = SZ_64K; /* For something like DG2 */
+
+       max_segment = round_down(UINT_MAX, ps);
+
+       mem = mock_region_create(i915, 0, size, ps, 0, 0);
        if (IS_ERR(mem))
                return PTR_ERR(mem);
 
@@ -498,12 +506,21 @@ static int igt_mock_max_segment(void *arg)
        }
 
        for (sg = obj->mm.pages->sgl; sg; sg = sg_next(sg)) {
+               dma_addr_t daddr = sg_dma_address(sg);
+
                if (sg->length > max_segment) {
                        pr_err("%s: Created an oversized scatterlist entry, %u > %u\n",
                               __func__, sg->length, max_segment);
                        err = -EINVAL;
                        goto out_close;
                }
+
+               if (!IS_ALIGNED(daddr, ps)) {
+                       pr_err("%s: Created an unaligned scatterlist entry, addr=%pa, ps=%u\n",
+                              __func__,  &daddr, ps);
+                       err = -EINVAL;
+                       goto out_close;
+               }
        }
 
 out_close:
index 670557c..bac21fe 100644 (file)
@@ -33,7 +33,8 @@ static int mock_region_get_pages(struct drm_i915_gem_object *obj)
                return PTR_ERR(obj->mm.res);
 
        obj->mm.rsgt = intel_region_ttm_resource_to_rsgt(obj->mm.region,
-                                                        obj->mm.res);
+                                                        obj->mm.res,
+                                                        obj->mm.region->min_page_size);
        if (IS_ERR(obj->mm.rsgt)) {
                err = PTR_ERR(obj->mm.rsgt);
                goto err_free_resource;
index c849533..3f5750c 100644 (file)
@@ -207,6 +207,7 @@ struct dcss_dev *dcss_dev_create(struct device *dev, bool hdmi_output)
 
        ret = dcss_submodules_init(dcss);
        if (ret) {
+               of_node_put(dcss->of_port);
                dev_err(dev, "submodules initialization failed\n");
                goto clks_err;
        }
@@ -237,6 +238,8 @@ void dcss_dev_destroy(struct dcss_dev *dcss)
                dcss_clocks_disable(dcss);
        }
 
+       of_node_put(dcss->of_port);
+
        pm_runtime_disable(dcss->dev);
 
        dcss_submodules_stop(dcss);
index 3a462e3..a1b8c45 100644 (file)
@@ -1251,12 +1251,13 @@ static void dpu_encoder_vblank_callback(struct drm_encoder *drm_enc,
        DPU_ATRACE_BEGIN("encoder_vblank_callback");
        dpu_enc = to_dpu_encoder_virt(drm_enc);
 
+       atomic_inc(&phy_enc->vsync_cnt);
+
        spin_lock_irqsave(&dpu_enc->enc_spinlock, lock_flags);
        if (dpu_enc->crtc)
                dpu_crtc_vblank_callback(dpu_enc->crtc);
        spin_unlock_irqrestore(&dpu_enc->enc_spinlock, lock_flags);
 
-       atomic_inc(&phy_enc->vsync_cnt);
        DPU_ATRACE_END("encoder_vblank_callback");
 }
 
index 59da348..0ec809a 100644 (file)
@@ -252,11 +252,6 @@ static int dpu_encoder_phys_wb_atomic_check(
        DPU_DEBUG("[atomic_check:%d, \"%s\",%d,%d]\n",
                        phys_enc->wb_idx, mode->name, mode->hdisplay, mode->vdisplay);
 
-       if (!conn_state->writeback_job || !conn_state->writeback_job->fb)
-               return 0;
-
-       fb = conn_state->writeback_job->fb;
-
        if (!conn_state || !conn_state->connector) {
                DPU_ERROR("invalid connector state\n");
                return -EINVAL;
@@ -267,6 +262,11 @@ static int dpu_encoder_phys_wb_atomic_check(
                return -EINVAL;
        }
 
+       if (!conn_state->writeback_job || !conn_state->writeback_job->fb)
+               return 0;
+
+       fb = conn_state->writeback_job->fb;
+
        DPU_DEBUG("[fb_id:%u][fb:%u,%u]\n", fb->base.id,
                        fb->width, fb->height);
 
index ec26855..239c8e3 100644 (file)
@@ -316,6 +316,8 @@ static void dp_display_unbind(struct device *dev, struct device *master,
 
        dp_power_client_deinit(dp->power);
        dp_aux_unregister(dp->aux);
+       dp->drm_dev = NULL;
+       dp->aux->drm_dev = NULL;
        priv->dp[dp->id] = NULL;
 }
 
index 3c3a0cf..c9e4aeb 100644 (file)
@@ -928,7 +928,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
                                                    INT_MAX, GFP_KERNEL);
        }
        if (submit->fence_id < 0) {
-               ret = submit->fence_id = 0;
+               ret = submit->fence_id;
                submit->fence_id = 0;
        }
 
index 7ba66ad..1635661 100644 (file)
@@ -680,7 +680,11 @@ nouveau_dmem_migrate_vma(struct nouveau_drm *drm,
                goto out_free_dma;
 
        for (i = 0; i < npages; i += max) {
-               args.end = start + (max << PAGE_SHIFT);
+               if (args.start + (max << PAGE_SHIFT) > end)
+                       args.end = end;
+               else
+                       args.end = args.start + (max << PAGE_SHIFT);
+
                ret = migrate_vma_setup(&args);
                if (ret)
                        goto out_free_pfns;
index c960144..a189982 100644 (file)
@@ -713,7 +713,7 @@ static int generic_edp_panel_probe(struct device *dev, struct panel_edp *panel)
        of_property_read_u32(dev->of_node, "hpd-reliable-delay-ms", &reliable_ms);
        desc->delay.hpd_reliable = reliable_ms;
        of_property_read_u32(dev->of_node, "hpd-absent-delay-ms", &absent_ms);
-       desc->delay.hpd_reliable = absent_ms;
+       desc->delay.hpd_absent = absent_ms;
 
        /* Power the panel on so we can read the EDID */
        ret = pm_runtime_get_sync(dev);
index 087e69b..b1e6d23 100644 (file)
@@ -433,8 +433,8 @@ static int panfrost_ioctl_madvise(struct drm_device *dev, void *data,
 
        if (args->retained) {
                if (args->madv == PANFROST_MADV_DONTNEED)
-                       list_add_tail(&bo->base.madv_list,
-                                     &pfdev->shrinker_list);
+                       list_move_tail(&bo->base.madv_list,
+                                      &pfdev->shrinker_list);
                else if (args->madv == PANFROST_MADV_WILLNEED)
                        list_del_init(&bo->base.madv_list);
        }
index d3f82b2..b285a80 100644 (file)
@@ -518,7 +518,7 @@ err_map:
 err_pages:
        drm_gem_shmem_put_pages(&bo->base);
 err_bo:
-       drm_gem_object_put(&bo->base.base);
+       panfrost_gem_mapping_put(bomapping);
        return ret;
 }
 
index 67d38f5..13ed33e 100644 (file)
 #include <drm/drm_probe_helper.h>
 #include <drm/drm_vblank.h>
 
+#if defined(CONFIG_ARM_DMA_USE_IOMMU)
+#include <asm/dma-iommu.h>
+#else
+#define arm_iommu_detach_device(...)   ({ })
+#define arm_iommu_release_mapping(...) ({ })
+#define to_dma_iommu_mapping(dev) NULL
+#endif
+
 #include "rockchip_drm_drv.h"
 #include "rockchip_drm_fb.h"
 #include "rockchip_drm_gem.h"
@@ -49,6 +57,15 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
        if (!private->domain)
                return 0;
 
+       if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) {
+               struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
+
+               if (mapping) {
+                       arm_iommu_detach_device(dev);
+                       arm_iommu_release_mapping(mapping);
+               }
+       }
+
        ret = iommu_attach_device(private->domain, dev);
        if (ret) {
                DRM_DEV_ERROR(dev, "Failed to attach iommu device\n");
index 191c560..6b25b2f 100644 (file)
@@ -190,7 +190,7 @@ long drm_sched_entity_flush(struct drm_sched_entity *entity, long timeout)
 }
 EXPORT_SYMBOL(drm_sched_entity_flush);
 
-static void drm_sched_entity_kill_jobs_irq_work(struct irq_work *wrk)
+static void drm_sched_entity_kill_jobs_work(struct work_struct *wrk)
 {
        struct drm_sched_job *job = container_of(wrk, typeof(*job), work);
 
@@ -207,8 +207,8 @@ static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f,
        struct drm_sched_job *job = container_of(cb, struct drm_sched_job,
                                                 finish_cb);
 
-       init_irq_work(&job->work, drm_sched_entity_kill_jobs_irq_work);
-       irq_work_queue(&job->work);
+       INIT_WORK(&job->work, drm_sched_entity_kill_jobs_work);
+       schedule_work(&job->work);
 }
 
 static struct dma_fence *
index 0839444..f4886e6 100644 (file)
@@ -350,7 +350,7 @@ static int ssd130x_init(struct ssd130x_device *ssd130x)
 
        /* Set precharge period in number of ticks from the internal clock */
        precharge = (SSD130X_SET_PRECHARGE_PERIOD1_SET(ssd130x->prechargep1) |
-                    SSD130X_SET_PRECHARGE_PERIOD1_SET(ssd130x->prechargep2));
+                    SSD130X_SET_PRECHARGE_PERIOD2_SET(ssd130x->prechargep2));
        ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_PRECHARGE_PERIOD, precharge);
        if (ret < 0)
                return ret;
index 768242a..5422363 100644 (file)
@@ -627,7 +627,7 @@ static const struct drm_connector_funcs simpledrm_connector_funcs = {
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
-static int
+static enum drm_mode_status
 simpledrm_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe,
                                    const struct drm_display_mode *mode)
 {
index c7f5adb..79a7418 100644 (file)
 
 void vc4_perfmon_get(struct vc4_perfmon *perfmon)
 {
-       struct vc4_dev *vc4 = perfmon->dev;
+       struct vc4_dev *vc4;
 
+       if (!perfmon)
+               return;
+
+       vc4 = perfmon->dev;
        if (WARN_ON_ONCE(vc4->is_vc5))
                return;
 
-       if (perfmon)
-               refcount_inc(&perfmon->refcnt);
+       refcount_inc(&perfmon->refcnt);
 }
 
 void vc4_perfmon_put(struct vc4_perfmon *perfmon)
index 590d3d5..e70d961 100644 (file)
@@ -100,6 +100,7 @@ config SENSORS_AD7418
 config SENSORS_ADM1021
        tristate "Analog Devices ADM1021 and compatibles"
        depends on I2C
+       depends on SENSORS_LM90=n
        help
          If you say yes here you get support for Analog Devices ADM1021
          and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A,
@@ -256,13 +257,13 @@ config SENSORS_AHT10
          will be called aht10.
 
 config SENSORS_AQUACOMPUTER_D5NEXT
-       tristate "Aquacomputer D5 Next, Octo, Farbwerk, and Farbwerk 360"
+       tristate "Aquacomputer D5 Next, Octo, Quadro, Farbwerk, and Farbwerk 360"
        depends on USB_HID
        select CRC16
        help
          If you say yes here you get support for sensors and fans of
-         the Aquacomputer D5 Next watercooling pump, Octo fan
-         controller, Farbwerk and Farbwerk 360 RGB controllers, where
+         the Aquacomputer D5 Next watercooling pump, Octo and Quadro fan
+         controllers, Farbwerk and Farbwerk 360 RGB controllers, where
          available.
 
          This driver can also be built as a module. If so, the module
@@ -381,7 +382,7 @@ config SENSORS_ARM_SCPI
 
 config SENSORS_ASB100
        tristate "Asus ASB100 Bach"
-       depends on X86 && I2C
+       depends on (X86 || COMPILE_TEST) && I2C
        select HWMON_VID
        help
          If you say yes here you get support for the ASB100 Bach sensor
@@ -626,7 +627,7 @@ config SENSORS_MC13783_ADC
 
 config SENSORS_FSCHMD
        tristate "Fujitsu Siemens Computers sensor chips"
-       depends on X86 && I2C
+       depends on (X86 || COMPILE_TEST) && I2C
        help
          If you say yes here you get support for the following Fujitsu
          Siemens Computers (FSC) sensor chips: Poseidon, Scylla, Hermes,
@@ -1102,6 +1103,7 @@ config SENSORS_MAX6639
 config SENSORS_MAX6642
        tristate "Maxim MAX6642 sensor chip"
        depends on I2C
+       depends on SENSORS_LM90=n
        help
          If you say yes here you get support for MAX6642 sensor chip.
          MAX6642 is a SMBus-Compatible Remote/Local Temperature Sensor
@@ -1357,12 +1359,15 @@ config SENSORS_LM90
        tristate "National Semiconductor LM90 and compatibles"
        depends on I2C
        help
-         If you say yes here you get support for National Semiconductor LM90,
-         LM86, LM89 and LM99, Analog Devices ADM1032, ADT7461, and ADT7461A,
-         Maxim MAX6646, MAX6647, MAX6648, MAX6649, MAX6654, MAX6657, MAX6658,
-         MAX6659, MAX6680, MAX6681, MAX6692, MAX6695, MAX6696,
-         ON Semiconductor NCT1008, Winbond/Nuvoton W83L771W/G/AWG/ASG,
-         Philips SA56004, GMT G781, Texas Instruments TMP451 and TMP461
+         If you say yes here you get support for National Semiconductor LM84,
+         LM90, LM86, LM89 and LM99, Analog Devices ADM1020, ADM2021, ADM1021A,
+         ADM1023, ADM1032, ADT7461, ADT7461A, ADT7481, ADT7482, and ADT7483A,
+         Maxim MAX1617, MAX6642, MAX6646, MAX6647, MAX6648, MAX6649, MAX6654,
+         MAX6657, MAX6658, MAX6659, MAX6680, MAX6681, MAX6692, MAX6695,
+         MAX6696,
+         ON Semiconductor NCT1008, NCT210, NCT72, NCT214, NCT218,
+         Winbond/Nuvoton W83L771W/G/AWG/ASG,
+         Philips NE1618, SA56004, GMT G781, Texas Instruments TMP451 and TMP461
          sensor chips.
 
          This driver can also be built as a module. If so, the module
index a0e69f7..6643055 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- * hwmon driver for Aquacomputer devices (D5 Next, Farbwerk, Farbwerk 360, Octo)
+ * hwmon driver for Aquacomputer devices (D5 Next, Farbwerk, Farbwerk 360, Octo,
+ * Quadro)
  *
  * Aquacomputer devices send HID reports (with ID 0x01) every second to report
  * sensor values.
 
 #define USB_VENDOR_ID_AQUACOMPUTER     0x0c70
 #define USB_PRODUCT_ID_FARBWERK                0xf00a
+#define USB_PRODUCT_ID_QUADRO          0xf00d
 #define USB_PRODUCT_ID_D5NEXT          0xf00e
 #define USB_PRODUCT_ID_FARBWERK360     0xf010
 #define USB_PRODUCT_ID_OCTO            0xf011
 
-enum kinds { d5next, farbwerk, farbwerk360, octo };
+enum kinds { d5next, farbwerk, farbwerk360, octo, quadro };
 
 static const char *const aqc_device_names[] = {
        [d5next] = "d5next",
        [farbwerk] = "farbwerk",
        [farbwerk360] = "farbwerk360",
-       [octo] = "octo"
+       [octo] = "octo",
+       [quadro] = "quadro"
 };
 
 #define DRIVER_NAME                    "aquacomputer_d5next"
@@ -54,60 +57,61 @@ static u8 secondary_ctrl_report[] = {
        0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x34, 0xC6
 };
 
-/* Register offsets for the D5 Next pump */
-#define D5NEXT_POWER_CYCLES            24
-
-#define D5NEXT_COOLANT_TEMP            87
-
-#define D5NEXT_PUMP_SPEED              116
-#define D5NEXT_FAN_SPEED               103
-
-#define D5NEXT_PUMP_POWER              114
-#define D5NEXT_FAN_POWER               101
-
-#define D5NEXT_PUMP_VOLTAGE            110
-#define D5NEXT_FAN_VOLTAGE             97
-#define D5NEXT_5V_VOLTAGE              57
+/* Register offsets for all Aquacomputer devices */
+#define AQC_TEMP_SENSOR_SIZE           0x02
+#define AQC_TEMP_SENSOR_DISCONNECTED   0x7FFF
+#define AQC_FAN_PERCENT_OFFSET         0x00
+#define AQC_FAN_VOLTAGE_OFFSET         0x02
+#define AQC_FAN_CURRENT_OFFSET         0x04
+#define AQC_FAN_POWER_OFFSET           0x06
+#define AQC_FAN_SPEED_OFFSET           0x08
 
-#define D5NEXT_PUMP_CURRENT            112
-#define D5NEXT_FAN_CURRENT             99
+/* Register offsets for the D5 Next pump */
+#define D5NEXT_POWER_CYCLES            0x18
+#define D5NEXT_COOLANT_TEMP            0x57
+#define D5NEXT_NUM_FANS                        2
+#define D5NEXT_NUM_SENSORS             1
+#define D5NEXT_PUMP_OFFSET             0x6c
+#define D5NEXT_FAN_OFFSET              0x5f
+#define D5NEXT_5V_VOLTAGE              0x39
+#define D5NEXT_12V_VOLTAGE             0x37
+#define D5NEXT_CTRL_REPORT_SIZE                0x329
+static u8 d5next_sensor_fan_offsets[] = { D5NEXT_PUMP_OFFSET, D5NEXT_FAN_OFFSET };
+
+/* Pump and fan speed registers in D5 Next control report (from 0-100%) */
+static u16 d5next_ctrl_fan_offsets[] = { 0x97, 0x42 };
 
 /* Register offsets for the Farbwerk RGB controller */
 #define FARBWERK_NUM_SENSORS           4
 #define FARBWERK_SENSOR_START          0x2f
-#define FARBWERK_SENSOR_SIZE           0x02
-#define FARBWERK_SENSOR_DISCONNECTED   0x7FFF
 
 /* Register offsets for the Farbwerk 360 RGB controller */
 #define FARBWERK360_NUM_SENSORS                4
 #define FARBWERK360_SENSOR_START       0x32
-#define FARBWERK360_SENSOR_SIZE                0x02
-#define FARBWERK360_SENSOR_DISCONNECTED        0x7FFF
 
 /* Register offsets for the Octo fan controller */
 #define OCTO_POWER_CYCLES              0x18
 #define OCTO_NUM_FANS                  8
-#define OCTO_FAN_PERCENT_OFFSET                0x00
-#define OCTO_FAN_VOLTAGE_OFFSET                0x02
-#define OCTO_FAN_CURRENT_OFFSET                0x04
-#define OCTO_FAN_POWER_OFFSET          0x06
-#define OCTO_FAN_SPEED_OFFSET          0x08
-
-static u8 octo_sensor_fan_offsets[] = { 0x7D, 0x8A, 0x97, 0xA4, 0xB1, 0xBE, 0xCB, 0xD8 };
-
 #define OCTO_NUM_SENSORS               4
 #define OCTO_SENSOR_START              0x3D
-#define OCTO_SENSOR_SIZE               0x02
-#define OCTO_SENSOR_DISCONNECTED       0x7FFF
-
-#define OCTO_CTRL_REPORT_SIZE                  0x65F
-#define OCTO_CTRL_REPORT_CHECKSUM_OFFSET       0x65D
-#define OCTO_CTRL_REPORT_CHECKSUM_START                0x01
-#define OCTO_CTRL_REPORT_CHECKSUM_LENGTH       0x65C
+#define OCTO_CTRL_REPORT_SIZE          0x65F
+static u8 octo_sensor_fan_offsets[] = { 0x7D, 0x8A, 0x97, 0xA4, 0xB1, 0xBE, 0xCB, 0xD8 };
 
 /* Fan speed registers in Octo control report (from 0-100%) */
 static u16 octo_ctrl_fan_offsets[] = { 0x5B, 0xB0, 0x105, 0x15A, 0x1AF, 0x204, 0x259, 0x2AE };
 
+/* Register offsets for the Quadro fan controller */
+#define QUADRO_POWER_CYCLES            0x18
+#define QUADRO_NUM_FANS                        4
+#define QUADRO_NUM_SENSORS             4
+#define QUADRO_SENSOR_START            0x34
+#define QUADRO_CTRL_REPORT_SIZE                0x3c1
+#define QUADRO_FLOW_SENSOR_OFFSET      0x6e
+static u8 quadro_sensor_fan_offsets[] = { 0x70, 0x7D, 0x8A, 0x97 };
+
+/* Fan speed registers in Quadro control report (from 0-100%) */
+static u16 quadro_ctrl_fan_offsets[] = { 0x36, 0x8b, 0xe0, 0x135 };
+
 /* Labels for D5 Next */
 static const char *const label_d5next_temp[] = {
        "Coolant temp"
@@ -126,7 +130,8 @@ static const char *const label_d5next_power[] = {
 static const char *const label_d5next_voltages[] = {
        "Pump voltage",
        "Fan voltage",
-       "+5V voltage"
+       "+5V voltage",
+       "+12V voltage"
 };
 
 static const char *const label_d5next_current[] = {
@@ -134,7 +139,7 @@ static const char *const label_d5next_current[] = {
        "Fan current"
 };
 
-/* Labels for Farbwerk, Farbwerk 360 and Octo temperature sensors */
+/* Labels for Farbwerk, Farbwerk 360 and Octo and Quadro temperature sensors */
 static const char *const label_temp_sensors[] = {
        "Sensor 1",
        "Sensor 2",
@@ -142,7 +147,7 @@ static const char *const label_temp_sensors[] = {
        "Sensor 4"
 };
 
-/* Labels for Octo */
+/* Labels for Octo and Quadro (except speed) */
 static const char *const label_fan_speed[] = {
        "Fan 1 speed",
        "Fan 2 speed",
@@ -187,6 +192,15 @@ static const char *const label_fan_current[] = {
        "Fan 8 current"
 };
 
+/* Labels for Quadro fan speeds */
+static const char *const label_quadro_speeds[] = {
+       "Fan 1 speed",
+       "Fan 2 speed",
+       "Fan 3 speed",
+       "Fan 4 speed",
+       "Flow speed [dL/h]"
+};
+
 struct aqc_data {
        struct hid_device *hdev;
        struct device *hwmon_dev;
@@ -201,11 +215,19 @@ struct aqc_data {
        int checksum_length;
        int checksum_offset;
 
+       int num_fans;
+       u8 *fan_sensor_offsets;
+       u16 *fan_ctrl_offsets;
+       int num_temp_sensors;
+       int temp_sensor_start_offset;
+       u16 power_cycle_count_offset;
+       u8 flow_sensor_offset;
+
        /* General info, same across all devices */
        u32 serial_number[2];
        u16 firmware_version;
 
-       /* How many times the device was powered on */
+       /* How many times the device was powered on, if available */
        u32 power_cycles;
 
        /* Sensor values */
@@ -323,56 +345,47 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
 
        switch (type) {
        case hwmon_temp:
-               switch (priv->kind) {
-               case d5next:
-                       if (channel == 0)
-                               return 0444;
-                       break;
-               case farbwerk:
-               case farbwerk360:
-               case octo:
+               if (channel < priv->num_temp_sensors)
                        return 0444;
-               default:
-                       break;
-               }
                break;
        case hwmon_pwm:
-               switch (priv->kind) {
-               case octo:
+               if (priv->fan_ctrl_offsets && channel < priv->num_fans) {
                        switch (attr) {
                        case hwmon_pwm_input:
                                return 0644;
                        default:
                                break;
                        }
-                       break;
-               default:
-                       break;
                }
                break;
        case hwmon_fan:
-       case hwmon_power:
-       case hwmon_curr:
                switch (priv->kind) {
-               case d5next:
-                       if (channel < 2)
+               case quadro:
+                       /* Special case to support flow sensor */
+                       if (channel < priv->num_fans + 1)
                                return 0444;
                        break;
-               case octo:
-                       return 0444;
                default:
+                       if (channel < priv->num_fans)
+                               return 0444;
                        break;
                }
                break;
+       case hwmon_power:
+       case hwmon_curr:
+               if (channel < priv->num_fans)
+                       return 0444;
+               break;
        case hwmon_in:
                switch (priv->kind) {
                case d5next:
-                       if (channel < 3)
+                       /* Special case to support +5V and +12V voltage sensors */
+                       if (channel < priv->num_fans + 2)
                                return 0444;
                        break;
-               case octo:
-                       return 0444;
                default:
+                       if (channel < priv->num_fans)
+                               return 0444;
                        break;
                }
                break;
@@ -406,16 +419,12 @@ static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
                *val = priv->power_input[channel];
                break;
        case hwmon_pwm:
-               switch (priv->kind) {
-               case octo:
-                       ret = aqc_get_ctrl_val(priv, octo_ctrl_fan_offsets[channel]);
+               if (priv->fan_ctrl_offsets) {
+                       ret = aqc_get_ctrl_val(priv, priv->fan_ctrl_offsets[channel]);
                        if (ret < 0)
                                return ret;
 
                        *val = aqc_percent_to_pwm(ret);
-                       break;
-               default:
-                       break;
                }
                break;
        case hwmon_in:
@@ -469,19 +478,15 @@ static int aqc_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
        case hwmon_pwm:
                switch (attr) {
                case hwmon_pwm_input:
-                       switch (priv->kind) {
-                       case octo:
+                       if (priv->fan_ctrl_offsets) {
                                pwm_value = aqc_pwm_to_percent(val);
                                if (pwm_value < 0)
                                        return pwm_value;
 
-                               ret = aqc_set_ctrl_val(priv, octo_ctrl_fan_offsets[channel],
+                               ret = aqc_set_ctrl_val(priv, priv->fan_ctrl_offsets[channel],
                                                       pwm_value);
                                if (ret < 0)
                                        return ret;
-                               break;
-                       default:
-                               break;
                        }
                        break;
                default:
@@ -576,76 +581,42 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
        priv->serial_number[1] = get_unaligned_be16(data + SERIAL_SECOND_PART);
        priv->firmware_version = get_unaligned_be16(data + FIRMWARE_VERSION);
 
-       /* Sensor readings */
-       switch (priv->kind) {
-       case d5next:
-               priv->power_cycles = get_unaligned_be32(data + D5NEXT_POWER_CYCLES);
-
-               priv->temp_input[0] = get_unaligned_be16(data + D5NEXT_COOLANT_TEMP) * 10;
+       /* Temperature sensor readings */
+       for (i = 0; i < priv->num_temp_sensors; i++) {
+               sensor_value = get_unaligned_be16(data +
+                                                 priv->temp_sensor_start_offset +
+                                                 i * AQC_TEMP_SENSOR_SIZE);
+               if (sensor_value == AQC_TEMP_SENSOR_DISCONNECTED)
+                       priv->temp_input[i] = -ENODATA;
+               else
+                       priv->temp_input[i] = sensor_value * 10;
+       }
 
-               priv->speed_input[0] = get_unaligned_be16(data + D5NEXT_PUMP_SPEED);
-               priv->speed_input[1] = get_unaligned_be16(data + D5NEXT_FAN_SPEED);
+       /* Fan speed and related readings */
+       for (i = 0; i < priv->num_fans; i++) {
+               priv->speed_input[i] =
+                   get_unaligned_be16(data + priv->fan_sensor_offsets[i] + AQC_FAN_SPEED_OFFSET);
+               priv->power_input[i] =
+                   get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
+                                      AQC_FAN_POWER_OFFSET) * 10000;
+               priv->voltage_input[i] =
+                   get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
+                                      AQC_FAN_VOLTAGE_OFFSET) * 10;
+               priv->current_input[i] =
+                   get_unaligned_be16(data + priv->fan_sensor_offsets[i] + AQC_FAN_CURRENT_OFFSET);
+       }
 
-               priv->power_input[0] = get_unaligned_be16(data + D5NEXT_PUMP_POWER) * 10000;
-               priv->power_input[1] = get_unaligned_be16(data + D5NEXT_FAN_POWER) * 10000;
+       if (priv->power_cycle_count_offset != 0)
+               priv->power_cycles = get_unaligned_be32(data + priv->power_cycle_count_offset);
 
-               priv->voltage_input[0] = get_unaligned_be16(data + D5NEXT_PUMP_VOLTAGE) * 10;
-               priv->voltage_input[1] = get_unaligned_be16(data + D5NEXT_FAN_VOLTAGE) * 10;
+       /* Special-case sensor readings */
+       switch (priv->kind) {
+       case d5next:
                priv->voltage_input[2] = get_unaligned_be16(data + D5NEXT_5V_VOLTAGE) * 10;
-
-               priv->current_input[0] = get_unaligned_be16(data + D5NEXT_PUMP_CURRENT);
-               priv->current_input[1] = get_unaligned_be16(data + D5NEXT_FAN_CURRENT);
-               break;
-       case farbwerk:
-               /* Temperature sensor readings */
-               for (i = 0; i < FARBWERK_NUM_SENSORS; i++) {
-                       sensor_value = get_unaligned_be16(data + FARBWERK_SENSOR_START +
-                                                         i * FARBWERK_SENSOR_SIZE);
-                       if (sensor_value == FARBWERK_SENSOR_DISCONNECTED)
-                               priv->temp_input[i] = -ENODATA;
-                       else
-                               priv->temp_input[i] = sensor_value * 10;
-               }
-               break;
-       case farbwerk360:
-               /* Temperature sensor readings */
-               for (i = 0; i < FARBWERK360_NUM_SENSORS; i++) {
-                       sensor_value = get_unaligned_be16(data + FARBWERK360_SENSOR_START +
-                                                         i * FARBWERK360_SENSOR_SIZE);
-                       if (sensor_value == FARBWERK360_SENSOR_DISCONNECTED)
-                               priv->temp_input[i] = -ENODATA;
-                       else
-                               priv->temp_input[i] = sensor_value * 10;
-               }
+               priv->voltage_input[3] = get_unaligned_be16(data + D5NEXT_12V_VOLTAGE) * 10;
                break;
-       case octo:
-               priv->power_cycles = get_unaligned_be32(data + OCTO_POWER_CYCLES);
-
-               /* Fan speed and related readings */
-               for (i = 0; i < OCTO_NUM_FANS; i++) {
-                       priv->speed_input[i] =
-                           get_unaligned_be16(data + octo_sensor_fan_offsets[i] +
-                                              OCTO_FAN_SPEED_OFFSET);
-                       priv->power_input[i] =
-                           get_unaligned_be16(data + octo_sensor_fan_offsets[i] +
-                                              OCTO_FAN_POWER_OFFSET) * 10000;
-                       priv->voltage_input[i] =
-                           get_unaligned_be16(data + octo_sensor_fan_offsets[i] +
-                                              OCTO_FAN_VOLTAGE_OFFSET) * 10;
-                       priv->current_input[i] =
-                           get_unaligned_be16(data + octo_sensor_fan_offsets[i] +
-                                              OCTO_FAN_CURRENT_OFFSET);
-               }
-
-               /* Temperature sensor readings */
-               for (i = 0; i < OCTO_NUM_SENSORS; i++) {
-                       sensor_value = get_unaligned_be16(data + OCTO_SENSOR_START +
-                                                         i * OCTO_SENSOR_SIZE);
-                       if (sensor_value == OCTO_SENSOR_DISCONNECTED)
-                               priv->temp_input[i] = -ENODATA;
-                       else
-                               priv->temp_input[i] = sensor_value * 10;
-               }
+       case quadro:
+               priv->speed_input[4] = get_unaligned_be16(data + priv->flow_sensor_offset);
                break;
        default:
                break;
@@ -699,14 +670,8 @@ static void aqc_debugfs_init(struct aqc_data *priv)
        debugfs_create_file("serial_number", 0444, priv->debugfs, priv, &serial_number_fops);
        debugfs_create_file("firmware_version", 0444, priv->debugfs, priv, &firmware_version_fops);
 
-       switch (priv->kind) {
-       case d5next:
-       case octo:
+       if (priv->power_cycle_count_offset != 0)
                debugfs_create_file("power_cycles", 0444, priv->debugfs, priv, &power_cycles_fops);
-               break;
-       default:
-               break;
-       }
 }
 
 #else
@@ -747,6 +712,14 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
        case USB_PRODUCT_ID_D5NEXT:
                priv->kind = d5next;
 
+               priv->num_fans = D5NEXT_NUM_FANS;
+               priv->fan_sensor_offsets = d5next_sensor_fan_offsets;
+               priv->fan_ctrl_offsets = d5next_ctrl_fan_offsets;
+               priv->num_temp_sensors = D5NEXT_NUM_SENSORS;
+               priv->temp_sensor_start_offset = D5NEXT_COOLANT_TEMP;
+               priv->power_cycle_count_offset = D5NEXT_POWER_CYCLES;
+               priv->buffer_size = D5NEXT_CTRL_REPORT_SIZE;
+
                priv->temp_label = label_d5next_temp;
                priv->speed_label = label_d5next_speeds;
                priv->power_label = label_d5next_power;
@@ -756,19 +729,29 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
        case USB_PRODUCT_ID_FARBWERK:
                priv->kind = farbwerk;
 
+               priv->num_fans = 0;
+               priv->num_temp_sensors = FARBWERK_NUM_SENSORS;
+               priv->temp_sensor_start_offset = FARBWERK_SENSOR_START;
                priv->temp_label = label_temp_sensors;
                break;
        case USB_PRODUCT_ID_FARBWERK360:
                priv->kind = farbwerk360;
 
+               priv->num_fans = 0;
+               priv->num_temp_sensors = FARBWERK360_NUM_SENSORS;
+               priv->temp_sensor_start_offset = FARBWERK360_SENSOR_START;
                priv->temp_label = label_temp_sensors;
                break;
        case USB_PRODUCT_ID_OCTO:
                priv->kind = octo;
+
+               priv->num_fans = OCTO_NUM_FANS;
+               priv->fan_sensor_offsets = octo_sensor_fan_offsets;
+               priv->fan_ctrl_offsets = octo_ctrl_fan_offsets;
+               priv->num_temp_sensors = OCTO_NUM_SENSORS;
+               priv->temp_sensor_start_offset = OCTO_SENSOR_START;
+               priv->power_cycle_count_offset = OCTO_POWER_CYCLES;
                priv->buffer_size = OCTO_CTRL_REPORT_SIZE;
-               priv->checksum_start = OCTO_CTRL_REPORT_CHECKSUM_START;
-               priv->checksum_length = OCTO_CTRL_REPORT_CHECKSUM_LENGTH;
-               priv->checksum_offset = OCTO_CTRL_REPORT_CHECKSUM_OFFSET;
 
                priv->temp_label = label_temp_sensors;
                priv->speed_label = label_fan_speed;
@@ -776,10 +759,34 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
                priv->voltage_label = label_fan_voltage;
                priv->current_label = label_fan_current;
                break;
+       case USB_PRODUCT_ID_QUADRO:
+               priv->kind = quadro;
+
+               priv->num_fans = QUADRO_NUM_FANS;
+               priv->fan_sensor_offsets = quadro_sensor_fan_offsets;
+               priv->fan_ctrl_offsets = quadro_ctrl_fan_offsets;
+               priv->num_temp_sensors = QUADRO_NUM_SENSORS;
+               priv->temp_sensor_start_offset = QUADRO_SENSOR_START;
+               priv->power_cycle_count_offset = QUADRO_POWER_CYCLES;
+               priv->buffer_size = QUADRO_CTRL_REPORT_SIZE;
+               priv->flow_sensor_offset = QUADRO_FLOW_SENSOR_OFFSET;
+
+               priv->temp_label = label_temp_sensors;
+               priv->speed_label = label_quadro_speeds;
+               priv->power_label = label_fan_power;
+               priv->voltage_label = label_fan_voltage;
+               priv->current_label = label_fan_current;
+               break;
        default:
                break;
        }
 
+       if (priv->buffer_size != 0) {
+               priv->checksum_start = 0x01;
+               priv->checksum_length = priv->buffer_size - 3;
+               priv->checksum_offset = priv->buffer_size - 2;
+       }
+
        priv->name = aqc_device_names[priv->kind];
 
        priv->buffer = devm_kzalloc(&hdev->dev, priv->buffer_size, GFP_KERNEL);
@@ -825,6 +832,7 @@ static const struct hid_device_id aqc_table[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_FARBWERK) },
        { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_FARBWERK360) },
        { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_OCTO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_QUADRO) },
        { }
 };
 
index 3cb88d6..d11f674 100644 (file)
  * 11: reserved.
  */
 #define M_TACH_MODE 0x02 /* 10b */
-#define M_TACH_UNIT 0x0210
+#define M_TACH_UNIT 0x0420
 #define INIT_FAN_CTRL 0xFF
 
 /* How long we sleep in us while waiting for an RPM result. */
index 3633ab6..61a4684 100644 (file)
@@ -54,6 +54,10 @@ static char *mutex_path_override;
 /* ACPI mutex for locking access to the EC for the firmware */
 #define ASUS_HW_ACCESS_MUTEX_ASMX      "\\AMW0.ASMX"
 
+#define ASUS_HW_ACCESS_MUTEX_RMTW_ASMX "\\RMTW.ASMX"
+
+#define ASUS_HW_ACCESS_MUTEX_SB_PCI0_SBRG_SIO1_MUT0 "\\_SB_.PCI0.SBRG.SIO1.MUT0"
+
 #define MAX_IDENTICAL_BOARD_VARIATIONS 3
 
 /* Moniker for the ACPI global lock (':' is not allowed in ASL identifiers) */
@@ -119,6 +123,18 @@ enum ec_sensors {
        ec_sensor_temp_water_in,
        /* "Water_Out" temperature sensor reading [℃] */
        ec_sensor_temp_water_out,
+       /* "Water_Block_In" temperature sensor reading [℃] */
+       ec_sensor_temp_water_block_in,
+       /* "Water_Block_Out" temperature sensor reading [℃] */
+       ec_sensor_temp_water_block_out,
+       /* "T_sensor_2" temperature sensor reading [℃] */
+       ec_sensor_temp_t_sensor_2,
+       /* "Extra_1" temperature sensor reading [℃] */
+       ec_sensor_temp_sensor_extra_1,
+       /* "Extra_2" temperature sensor reading [℃] */
+       ec_sensor_temp_sensor_extra_2,
+       /* "Extra_3" temperature sensor reading [℃] */
+       ec_sensor_temp_sensor_extra_3,
 };
 
 #define SENSOR_TEMP_CHIPSET BIT(ec_sensor_temp_chipset)
@@ -134,11 +150,19 @@ enum ec_sensors {
 #define SENSOR_CURR_CPU BIT(ec_sensor_curr_cpu)
 #define SENSOR_TEMP_WATER_IN BIT(ec_sensor_temp_water_in)
 #define SENSOR_TEMP_WATER_OUT BIT(ec_sensor_temp_water_out)
+#define SENSOR_TEMP_WATER_BLOCK_IN BIT(ec_sensor_temp_water_block_in)
+#define SENSOR_TEMP_WATER_BLOCK_OUT BIT(ec_sensor_temp_water_block_out)
+#define SENSOR_TEMP_T_SENSOR_2 BIT(ec_sensor_temp_t_sensor_2)
+#define SENSOR_TEMP_SENSOR_EXTRA_1 BIT(ec_sensor_temp_sensor_extra_1)
+#define SENSOR_TEMP_SENSOR_EXTRA_2 BIT(ec_sensor_temp_sensor_extra_2)
+#define SENSOR_TEMP_SENSOR_EXTRA_3 BIT(ec_sensor_temp_sensor_extra_3)
 
 enum board_family {
        family_unknown,
        family_amd_400_series,
        family_amd_500_series,
+       family_intel_300_series,
+       family_intel_600_series
 };
 
 /* All the known sensors for ASUS EC controllers */
@@ -195,12 +219,53 @@ static const struct ec_sensor_info sensors_family_amd_500[] = {
                EC_SENSOR("Water_In", hwmon_temp, 1, 0x01, 0x00),
        [ec_sensor_temp_water_out] =
                EC_SENSOR("Water_Out", hwmon_temp, 1, 0x01, 0x01),
+       [ec_sensor_temp_water_block_in] =
+               EC_SENSOR("Water_Block_In", hwmon_temp, 1, 0x01, 0x02),
+       [ec_sensor_temp_water_block_out] =
+               EC_SENSOR("Water_Block_Out", hwmon_temp, 1, 0x01, 0x03),
+       [ec_sensor_temp_sensor_extra_1] =
+               EC_SENSOR("Extra_1", hwmon_temp, 1, 0x01, 0x09),
+       [ec_sensor_temp_t_sensor_2] =
+               EC_SENSOR("T_sensor_2", hwmon_temp, 1, 0x01, 0x0a),
+       [ec_sensor_temp_sensor_extra_2] =
+               EC_SENSOR("Extra_2", hwmon_temp, 1, 0x01, 0x0b),
+       [ec_sensor_temp_sensor_extra_3] =
+               EC_SENSOR("Extra_3", hwmon_temp, 1, 0x01, 0x0c),
+};
+
+static const struct ec_sensor_info sensors_family_intel_300[] = {
+       [ec_sensor_temp_chipset] =
+               EC_SENSOR("Chipset", hwmon_temp, 1, 0x00, 0x3a),
+       [ec_sensor_temp_cpu] = EC_SENSOR("CPU", hwmon_temp, 1, 0x00, 0x3b),
+       [ec_sensor_temp_mb] =
+               EC_SENSOR("Motherboard", hwmon_temp, 1, 0x00, 0x3c),
+       [ec_sensor_temp_t_sensor] =
+               EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x3d),
+       [ec_sensor_temp_vrm] = EC_SENSOR("VRM", hwmon_temp, 1, 0x00, 0x3e),
+       [ec_sensor_fan_cpu_opt] =
+               EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xb0),
+       [ec_sensor_fan_vrm_hs] = EC_SENSOR("VRM HS", hwmon_fan, 2, 0x00, 0xb2),
+       [ec_sensor_fan_water_flow] =
+               EC_SENSOR("Water_Flow", hwmon_fan, 2, 0x00, 0xbc),
+       [ec_sensor_temp_water_in] =
+               EC_SENSOR("Water_In", hwmon_temp, 1, 0x01, 0x00),
+       [ec_sensor_temp_water_out] =
+               EC_SENSOR("Water_Out", hwmon_temp, 1, 0x01, 0x01),
+};
+
+static const struct ec_sensor_info sensors_family_intel_600[] = {
+       [ec_sensor_temp_t_sensor] =
+               EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x3d),
+       [ec_sensor_temp_vrm] = EC_SENSOR("VRM", hwmon_temp, 1, 0x00, 0x3e),
 };
 
 /* Shortcuts for common combinations */
 #define SENSOR_SET_TEMP_CHIPSET_CPU_MB                                         \
        (SENSOR_TEMP_CHIPSET | SENSOR_TEMP_CPU | SENSOR_TEMP_MB)
 #define SENSOR_SET_TEMP_WATER (SENSOR_TEMP_WATER_IN | SENSOR_TEMP_WATER_OUT)
+#define SENSOR_SET_WATER_BLOCK                                                 \
+       (SENSOR_TEMP_WATER_BLOCK_IN | SENSOR_TEMP_WATER_BLOCK_OUT)
+
 
 struct ec_board_info {
        const char *board_names[MAX_IDENTICAL_BOARD_VARIATIONS];
@@ -273,6 +338,18 @@ static const struct ec_board_info board_info[] = {
                .family = family_amd_500_series,
        },
        {
+               .board_names = {
+                       "ROG MAXIMUS XI HERO",
+                       "ROG MAXIMUS XI HERO (WI-FI)",
+               },
+               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
+                       SENSOR_TEMP_T_SENSOR |
+                       SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER |
+                       SENSOR_FAN_CPU_OPT | SENSOR_FAN_WATER_FLOW,
+               .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
+               .family = family_intel_300_series,
+       },
+       {
                .board_names = {"ROG CROSSHAIR VIII IMPACT"},
                .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
                        SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM |
@@ -324,12 +401,31 @@ static const struct ec_board_info board_info[] = {
        },
        {
                .board_names = {"ROG STRIX X570-I GAMING"},
-               .sensors = SENSOR_TEMP_T_SENSOR | SENSOR_FAN_VRM_HS |
-                       SENSOR_FAN_CHIPSET | SENSOR_CURR_CPU |
-                       SENSOR_IN_CPU_CORE,
+               .sensors = SENSOR_TEMP_CHIPSET | SENSOR_TEMP_VRM |
+                       SENSOR_TEMP_T_SENSOR |
+                       SENSOR_FAN_VRM_HS | SENSOR_FAN_CHIPSET |
+                       SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,
                .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
                .family = family_amd_500_series,
        },
+       {
+               .board_names = {"ROG STRIX Z690-A GAMING WIFI D4"},
+               .sensors = SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM,
+               .mutex_path = ASUS_HW_ACCESS_MUTEX_RMTW_ASMX,
+               .family = family_intel_600_series,
+       },
+       {
+               .board_names = {"ROG ZENITH II EXTREME"},
+               .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_T_SENSOR |
+                       SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER |
+                       SENSOR_FAN_CPU_OPT | SENSOR_FAN_CHIPSET | SENSOR_FAN_VRM_HS |
+                       SENSOR_FAN_WATER_FLOW | SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE |
+                       SENSOR_SET_WATER_BLOCK |
+                       SENSOR_TEMP_T_SENSOR_2 | SENSOR_TEMP_SENSOR_EXTRA_1 |
+                       SENSOR_TEMP_SENSOR_EXTRA_2 | SENSOR_TEMP_SENSOR_EXTRA_3,
+               .mutex_path = ASUS_HW_ACCESS_MUTEX_SB_PCI0_SBRG_SIO1_MUT0,
+               .family = family_amd_500_series,
+       },
        {}
 };
 
@@ -799,6 +895,12 @@ static int __init asus_ec_probe(struct platform_device *pdev)
        case family_amd_500_series:
                ec_data->sensors_info = sensors_family_amd_500;
                break;
+       case family_intel_300_series:
+               ec_data->sensors_info = sensors_family_intel_300;
+               break;
+       case family_intel_600_series:
+               ec_data->sensors_info = sensors_family_intel_600;
+               break;
        default:
                dev_err(dev, "Unknown board family: %d",
                        ec_data->board_info->family);
index 9e935e3..6e8a908 100644 (file)
@@ -514,22 +514,20 @@ static int asus_wmi_configure_sensor_setup(struct device *dev,
        int i, idx;
        int err;
 
-       temp_sensor = devm_kcalloc(dev, 1, sizeof(*temp_sensor), GFP_KERNEL);
-       if (!temp_sensor)
-               return -ENOMEM;
-
        for (i = 0; i < sensor_data->wmi.sensor_count; i++) {
-               err = asus_wmi_sensor_info(i, temp_sensor);
+               struct asus_wmi_sensor_info sensor;
+
+               err = asus_wmi_sensor_info(i, &sensor);
                if (err)
                        return err;
 
-               switch (temp_sensor->data_type) {
+               switch (sensor.data_type) {
                case TEMPERATURE_C:
                case VOLTAGE:
                case CURRENT:
                case FAN_RPM:
                case WATER_FLOW:
-                       type = asus_data_types[temp_sensor->data_type];
+                       type = asus_data_types[sensor.data_type];
                        if (!nr_count[type])
                                nr_types++;
                        nr_count[type]++;
index 071aa6f..7f8d95d 100644 (file)
@@ -130,7 +130,7 @@ struct smm_regs {
        unsigned int edx;
        unsigned int esi;
        unsigned int edi;
-} __packed;
+};
 
 static const char * const temp_labels[] = {
        "CPU",
@@ -175,77 +175,35 @@ static int i8k_smm_func(void *par)
        struct smm_regs *regs = par;
        int eax = regs->eax;
        int ebx = regs->ebx;
+       unsigned char carry;
        long long duration;
-       int rc;
 
        /* SMM requires CPU 0 */
        if (smp_processor_id() != 0)
                return -EBUSY;
 
-#if defined(CONFIG_X86_64)
-       asm volatile("pushq %%rax\n\t"
-               "movl 0(%%rax),%%edx\n\t"
-               "pushq %%rdx\n\t"
-               "movl 4(%%rax),%%ebx\n\t"
-               "movl 8(%%rax),%%ecx\n\t"
-               "movl 12(%%rax),%%edx\n\t"
-               "movl 16(%%rax),%%esi\n\t"
-               "movl 20(%%rax),%%edi\n\t"
-               "popq %%rax\n\t"
-               "out %%al,$0xb2\n\t"
-               "out %%al,$0x84\n\t"
-               "xchgq %%rax,(%%rsp)\n\t"
-               "movl %%ebx,4(%%rax)\n\t"
-               "movl %%ecx,8(%%rax)\n\t"
-               "movl %%edx,12(%%rax)\n\t"
-               "movl %%esi,16(%%rax)\n\t"
-               "movl %%edi,20(%%rax)\n\t"
-               "popq %%rdx\n\t"
-               "movl %%edx,0(%%rax)\n\t"
-               "pushfq\n\t"
-               "popq %%rax\n\t"
-               "andl $1,%%eax\n"
-               : "=a"(rc)
-               :    "a"(regs)
-               :    "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
-#else
-       asm volatile("pushl %%eax\n\t"
-           "movl 0(%%eax),%%edx\n\t"
-           "push %%edx\n\t"
-           "movl 4(%%eax),%%ebx\n\t"
-           "movl 8(%%eax),%%ecx\n\t"
-           "movl 12(%%eax),%%edx\n\t"
-           "movl 16(%%eax),%%esi\n\t"
-           "movl 20(%%eax),%%edi\n\t"
-           "popl %%eax\n\t"
-           "out %%al,$0xb2\n\t"
-           "out %%al,$0x84\n\t"
-           "xchgl %%eax,(%%esp)\n\t"
-           "movl %%ebx,4(%%eax)\n\t"
-           "movl %%ecx,8(%%eax)\n\t"
-           "movl %%edx,12(%%eax)\n\t"
-           "movl %%esi,16(%%eax)\n\t"
-           "movl %%edi,20(%%eax)\n\t"
-           "popl %%edx\n\t"
-           "movl %%edx,0(%%eax)\n\t"
-           "lahf\n\t"
-           "shrl $8,%%eax\n\t"
-           "andl $1,%%eax\n"
-           : "=a"(rc)
-           :    "a"(regs)
-           :    "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
-#endif
-       if (rc != 0 || (regs->eax & 0xffff) == 0xffff || regs->eax == eax)
-               rc = -EINVAL;
+       asm volatile("out %%al,$0xb2\n\t"
+                    "out %%al,$0x84\n\t"
+                    "setc %0\n"
+                    : "=mr" (carry),
+                      "+a" (regs->eax),
+                      "+b" (regs->ebx),
+                      "+c" (regs->ecx),
+                      "+d" (regs->edx),
+                      "+S" (regs->esi),
+                      "+D" (regs->edi));
 
        duration = ktime_us_delta(ktime_get(), calltime);
-       pr_debug("smm(0x%.4x 0x%.4x) = 0x%.4x  (took %7lld usecs)\n", eax, ebx,
-                (rc ? 0xffff : regs->eax & 0xffff), duration);
+       pr_debug("smm(0x%.4x 0x%.4x) = 0x%.4x carry: %d (took %7lld usecs)\n",
+                eax, ebx, regs->eax & 0xffff, carry, duration);
 
        if (duration > DELL_SMM_MAX_DURATION)
                pr_warn_once("SMM call took %lld usecs!\n", duration);
 
-       return rc;
+       if (carry || (regs->eax & 0xffff) == 0xffff || regs->eax == eax)
+               return -EINVAL;
+
+       return 0;
 }
 
 /*
@@ -1132,6 +1090,13 @@ static const struct i8k_config_data i8k_config_data[] __initconst = {
 
 static const struct dmi_system_id i8k_dmi_table[] __initconst = {
        {
+               .ident = "Dell G5 5590",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "G5 5590"),
+               },
+       },
+       {
                .ident = "Dell Inspiron",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"),
@@ -1365,6 +1330,14 @@ static const struct dmi_system_id i8k_whitelist_fan_control[] __initconst = {
                },
                .driver_data = (void *)&i8k_fan_control_data[I8K_FAN_34A3_35A3],
        },
+       {
+               .ident = "Dell XPS 13 7390",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "XPS 13 7390"),
+               },
+               .driver_data = (void *)&i8k_fan_control_data[I8K_FAN_34A3_35A3],
+       },
        { }
 };
 
index 1eb3710..5bac2b0 100644 (file)
@@ -621,3 +621,4 @@ module_exit(drivetemp_exit);
 MODULE_AUTHOR("Guenter Roeck <linus@roeck-us.net>");
 MODULE_DESCRIPTION("Hard drive temperature monitor");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:drivetemp");
index 6830e02..19b6c64 100644 (file)
@@ -49,6 +49,7 @@
 #define SIO_F81768D_ID         0x1210  /* Chipset ID */
 #define SIO_F81865_ID          0x0704  /* Chipset ID */
 #define SIO_F81866_ID          0x1010  /* Chipset ID */
+#define SIO_F71858AD_ID                0x0903  /* Chipset ID */
 #define SIO_F81966_ID          0x1502  /* Chipset ID */
 
 #define REGION_LENGTH          8
@@ -2638,6 +2639,7 @@ static int __init f71882fg_find(int sioaddr, struct f71882fg_sio_data *sio_data)
                sio_data->type = f71808a;
                break;
        case SIO_F71858_ID:
+       case SIO_F71858AD_ID:
                sio_data->type = f71858fg;
                break;
        case SIO_F71862_ID:
index 1fe3741..d64be48 100644 (file)
@@ -269,10 +269,13 @@ gsc_hwmon_get_devtree_pdata(struct device *dev)
        /* fan controller base address */
        fan = of_find_compatible_node(dev->parent->of_node, NULL, "gw,gsc-fan");
        if (fan && of_property_read_u32(fan, "reg", &pdata->fan_base)) {
+               of_node_put(fan);
                dev_err(dev, "fan node without base\n");
                return ERR_PTR(-EINVAL);
        }
 
+       of_node_put(fan);
+
        /* allocate structures for channels and count instances of each type */
        device_for_each_child_node(dev, child) {
                if (fwnode_property_read_string(child, "label", &ch->name)) {
index 5c4cf74..157e232 100644 (file)
@@ -550,7 +550,7 @@ static int aem_init_aem1_inst(struct aem_ipmi_data *probe, u8 module_handle)
 
        res = platform_device_add(data->pdev);
        if (res)
-               goto ipmi_err;
+               goto dev_add_err;
 
        platform_set_drvdata(data->pdev, data);
 
@@ -598,7 +598,9 @@ hwmon_reg_err:
        ipmi_destroy_user(data->ipmi.user);
 ipmi_err:
        platform_set_drvdata(data->pdev, NULL);
-       platform_device_unregister(data->pdev);
+       platform_device_del(data->pdev);
+dev_add_err:
+       platform_device_put(data->pdev);
 dev_err:
        ida_free(&aem_ida, data->id);
 id_err:
@@ -690,7 +692,7 @@ static int aem_init_aem2_inst(struct aem_ipmi_data *probe,
 
        res = platform_device_add(data->pdev);
        if (res)
-               goto ipmi_err;
+               goto dev_add_err;
 
        platform_set_drvdata(data->pdev, data);
 
@@ -738,7 +740,9 @@ hwmon_reg_err:
        ipmi_destroy_user(data->ipmi.user);
 ipmi_err:
        platform_set_drvdata(data->pdev, NULL);
-       platform_device_unregister(data->pdev);
+       platform_device_del(data->pdev);
+dev_add_err:
+       platform_device_put(data->pdev);
 dev_err:
        ida_free(&aem_ida, data->id);
 id_err:
index 4e239bd..5a9d47a 100644 (file)
@@ -428,6 +428,10 @@ static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                        data->ccd_offset = 0x154;
                        k10temp_get_ccd_support(pdev, data, 8);
                        break;
+               case 0xa0 ... 0xaf:
+                       data->ccd_offset = 0x300;
+                       k10temp_get_ccd_support(pdev, data, 8);
+                       break;
                }
        } else if (boot_cpu_data.x86 == 0x19) {
                data->temp_adjust_mask = ZEN_CUR_TEMP_RANGE_SEL_MASK;
@@ -445,6 +449,11 @@ static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                        data->ccd_offset = 0x300;
                        k10temp_get_ccd_support(pdev, data, 8);
                        break;
+               case 0x60 ... 0x6f:
+               case 0x70 ... 0x7f:
+                       data->ccd_offset = 0x308;
+                       k10temp_get_ccd_support(pdev, data, 8);
+                       break;
                case 0x10 ... 0x1f:
                case 0xa0 ... 0xaf:
                        data->ccd_offset = 0x300;
@@ -489,10 +498,13 @@ static const struct pci_device_id k10temp_id_table[] = {
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M60H_DF_F3) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F3) },
+       { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_MA0H_DF_F3) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_DF_F3) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_M10H_DF_F3) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_M40H_DF_F3) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_M50H_DF_F3) },
+       { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_M60H_DF_F3) },
+       { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_M70H_DF_F3) },
        { PCI_VDEVICE(HYGON, PCI_DEVICE_ID_AMD_17H_DF_F3) },
        {}
 };
index a398171..b803ada 100644 (file)
@@ -11,7 +11,8 @@
  * which contains this code, we don't worry about the wasted space.
  */
 
-#include <linux/kernel.h>
+#include <linux/minmax.h>
+#include <linux/types.h>
 
 /* straight from the datasheet */
 #define LM75_TEMP_MIN (-55000)
index 3820f0e..03d07da 100644 (file)
@@ -42,7 +42,8 @@
  * accordingly, and is done during initialization. Extended precision is only
  * available at conversion rates of 1 Hz and slower. Note that extended
  * precision is not enabled by default, as this driver initializes all chips
- * to 2 Hz by design.
+ * to 2 Hz by design. The driver also supports MAX6690, which is practically
+ * identical to MAX6654.
  *
  * This driver also supports the MAX6646, MAX6647, MAX6648, MAX6649 and
  * MAX6692 chips made by Maxim.  These are again similar to the LM86,
  * and extended mode. They are mostly compatible with LM90 except for a data
  * format difference for the temperature value registers.
  *
+ * This driver also supports ADT7481, ADT7482, and ADT7483 from Analog Devices
+ * / ON Semiconductor. The chips are similar to ADT7461 but support two external
+ * temperature sensors.
+ *
+ * This driver also supports NCT72, NCT214, and NCT218 from ON Semiconductor.
+ * The chips are similar to ADT7461/ADT7461A but have full PEC support
+ * (undocumented).
+ *
  * This driver also supports the SA56004 from Philips. This device is
  * pin-compatible with the LM86, the ED/EDP parts are also address-compatible.
  *
  * They are mostly compatible with ADT7461 except for local temperature
  * low byte register and max conversion rate.
  *
+ * This driver also supports MAX1617 and various clones such as G767
+ * and NE1617. Such clones will be detected as MAX1617.
+ *
+ * This driver also supports NE1618 from Philips. It is similar to NE1617
+ * but supports 11 bit external temperature values.
+ *
  * Since the LM90 was the first chipset supported by this driver, most
  * comments will refer to this chipset, but are actually general and
  * concern all supported chipsets, unless mentioned otherwise.
  */
 
-#include <linux/module.h>
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
 #include <linux/init.h>
-#include <linux/slab.h>
+#include <linux/interrupt.h>
 #include <linux/jiffies.h>
-#include <linux/i2c.h>
 #include <linux/hwmon.h>
-#include <linux/err.h>
+#include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/of_device.h>
-#include <linux/sysfs.h>
-#include <linux/interrupt.h>
 #include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+
+/* The maximum number of channels currently supported */
+#define MAX_CHANNELS   3
 
 /*
  * Addresses to scan
@@ -112,119 +132,131 @@ static const unsigned short normal_i2c[] = {
        0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x48, 0x49, 0x4a, 0x4b, 0x4c,
        0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
 
-enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
-       max6646, w83l771, max6696, sa56004, g781, tmp451, tmp461, max6654 };
+enum chips { adm1023, adm1032, adt7461, adt7461a, adt7481,
+       g781, lm84, lm90, lm99,
+       max1617, max6642, max6646, max6648, max6654, max6657, max6659, max6680, max6696,
+       nct210, nct72, ne1618, sa56004, tmp451, tmp461, w83l771,
+};
 
 /*
  * The LM90 registers
  */
 
-#define LM90_REG_R_MAN_ID              0xFE
-#define LM90_REG_R_CHIP_ID             0xFF
-#define LM90_REG_R_CONFIG1             0x03
-#define LM90_REG_W_CONFIG1             0x09
-#define LM90_REG_R_CONFIG2             0xBF
-#define LM90_REG_W_CONFIG2             0xBF
-#define LM90_REG_R_CONVRATE            0x04
-#define LM90_REG_W_CONVRATE            0x0A
-#define LM90_REG_R_STATUS              0x02
-#define LM90_REG_R_LOCAL_TEMP          0x00
-#define LM90_REG_R_LOCAL_HIGH          0x05
-#define LM90_REG_W_LOCAL_HIGH          0x0B
-#define LM90_REG_R_LOCAL_LOW           0x06
-#define LM90_REG_W_LOCAL_LOW           0x0C
-#define LM90_REG_R_LOCAL_CRIT          0x20
-#define LM90_REG_W_LOCAL_CRIT          0x20
-#define LM90_REG_R_REMOTE_TEMPH                0x01
-#define LM90_REG_R_REMOTE_TEMPL                0x10
-#define LM90_REG_R_REMOTE_OFFSH                0x11
-#define LM90_REG_W_REMOTE_OFFSH                0x11
-#define LM90_REG_R_REMOTE_OFFSL                0x12
-#define LM90_REG_W_REMOTE_OFFSL                0x12
-#define LM90_REG_R_REMOTE_HIGHH                0x07
-#define LM90_REG_W_REMOTE_HIGHH                0x0D
-#define LM90_REG_R_REMOTE_HIGHL                0x13
-#define LM90_REG_W_REMOTE_HIGHL                0x13
-#define LM90_REG_R_REMOTE_LOWH         0x08
-#define LM90_REG_W_REMOTE_LOWH         0x0E
-#define LM90_REG_R_REMOTE_LOWL         0x14
-#define LM90_REG_W_REMOTE_LOWL         0x14
-#define LM90_REG_R_REMOTE_CRIT         0x19
-#define LM90_REG_W_REMOTE_CRIT         0x19
-#define LM90_REG_R_TCRIT_HYST          0x21
-#define LM90_REG_W_TCRIT_HYST          0x21
+#define LM90_REG_MAN_ID                        0xFE
+#define LM90_REG_CHIP_ID               0xFF
+#define LM90_REG_CONFIG1               0x03
+#define LM90_REG_CONFIG2               0xBF
+#define LM90_REG_CONVRATE              0x04
+#define LM90_REG_STATUS                        0x02
+#define LM90_REG_LOCAL_TEMP            0x00
+#define LM90_REG_LOCAL_HIGH            0x05
+#define LM90_REG_LOCAL_LOW             0x06
+#define LM90_REG_LOCAL_CRIT            0x20
+#define LM90_REG_REMOTE_TEMPH          0x01
+#define LM90_REG_REMOTE_TEMPL          0x10
+#define LM90_REG_REMOTE_OFFSH          0x11
+#define LM90_REG_REMOTE_OFFSL          0x12
+#define LM90_REG_REMOTE_HIGHH          0x07
+#define LM90_REG_REMOTE_HIGHL          0x13
+#define LM90_REG_REMOTE_LOWH           0x08
+#define LM90_REG_REMOTE_LOWL           0x14
+#define LM90_REG_REMOTE_CRIT           0x19
+#define LM90_REG_TCRIT_HYST            0x21
 
 /* MAX6646/6647/6649/6654/6657/6658/6659/6695/6696 registers */
 
-#define MAX6657_REG_R_LOCAL_TEMPL      0x11
-#define MAX6696_REG_R_STATUS2          0x12
-#define MAX6659_REG_R_REMOTE_EMERG     0x16
-#define MAX6659_REG_W_REMOTE_EMERG     0x16
-#define MAX6659_REG_R_LOCAL_EMERG      0x17
-#define MAX6659_REG_W_LOCAL_EMERG      0x17
+#define MAX6657_REG_LOCAL_TEMPL                0x11
+#define MAX6696_REG_STATUS2            0x12
+#define MAX6659_REG_REMOTE_EMERG       0x16
+#define MAX6659_REG_LOCAL_EMERG                0x17
 
 /*  SA56004 registers */
 
-#define SA56004_REG_R_LOCAL_TEMPL 0x22
+#define SA56004_REG_LOCAL_TEMPL                0x22
 
 #define LM90_MAX_CONVRATE_MS   16000   /* Maximum conversion rate in ms */
 
 /* TMP451/TMP461 registers */
-#define TMP451_REG_R_LOCAL_TEMPL       0x15
+#define TMP451_REG_LOCAL_TEMPL         0x15
 #define TMP451_REG_CONALERT            0x22
 
 #define TMP461_REG_CHEN                        0x16
 #define TMP461_REG_DFC                 0x24
 
-/*
- * Device flags
- */
-#define LM90_FLAG_ADT7461_EXT  (1 << 0) /* ADT7461 extended mode       */
+/* ADT7481 registers */
+#define ADT7481_REG_STATUS2            0x23
+#define ADT7481_REG_CONFIG2            0x24
+
+#define ADT7481_REG_MAN_ID             0x3e
+#define ADT7481_REG_CHIP_ID            0x3d
+
 /* Device features */
-#define LM90_HAVE_OFFSET       (1 << 1) /* temperature offset register */
-#define LM90_HAVE_REM_LIMIT_EXT        (1 << 3) /* extended remote limit       */
-#define LM90_HAVE_EMERGENCY    (1 << 4) /* 3rd upper (emergency) limit */
-#define LM90_HAVE_EMERGENCY_ALARM (1 << 5)/* emergency alarm           */
-#define LM90_HAVE_TEMP3                (1 << 6) /* 3rd temperature sensor      */
-#define LM90_HAVE_BROKEN_ALERT (1 << 7) /* Broken alert                */
-#define LM90_HAVE_EXTENDED_TEMP        (1 << 8) /* extended temperature support*/
-#define LM90_PAUSE_FOR_CONFIG  (1 << 9) /* Pause conversion for config */
-#define LM90_HAVE_CRIT         (1 << 10)/* Chip supports CRIT/OVERT register   */
-#define LM90_HAVE_CRIT_ALRM_SWP        (1 << 11)/* critical alarm bits swapped */
+#define LM90_HAVE_EXTENDED_TEMP        BIT(0)  /* extended temperature support */
+#define LM90_HAVE_OFFSET       BIT(1)  /* temperature offset register  */
+#define LM90_HAVE_UNSIGNED_TEMP        BIT(2)  /* temperatures are unsigned    */
+#define LM90_HAVE_REM_LIMIT_EXT        BIT(3)  /* extended remote limit        */
+#define LM90_HAVE_EMERGENCY    BIT(4)  /* 3rd upper (emergency) limit  */
+#define LM90_HAVE_EMERGENCY_ALARM BIT(5)/* emergency alarm             */
+#define LM90_HAVE_TEMP3                BIT(6)  /* 3rd temperature sensor       */
+#define LM90_HAVE_BROKEN_ALERT BIT(7)  /* Broken alert                 */
+#define LM90_PAUSE_FOR_CONFIG  BIT(8)  /* Pause conversion for config  */
+#define LM90_HAVE_CRIT         BIT(9)  /* Chip supports CRIT/OVERT register    */
+#define LM90_HAVE_CRIT_ALRM_SWP        BIT(10) /* critical alarm bits swapped  */
+#define LM90_HAVE_PEC          BIT(11) /* Chip supports PEC            */
+#define LM90_HAVE_PARTIAL_PEC  BIT(12) /* Partial PEC support (adm1032)*/
+#define LM90_HAVE_ALARMS       BIT(13) /* Create 'alarms' attribute    */
+#define LM90_HAVE_EXT_UNSIGNED BIT(14) /* extended unsigned temperature*/
+#define LM90_HAVE_LOW          BIT(15) /* low limits                   */
+#define LM90_HAVE_CONVRATE     BIT(16) /* conversion rate              */
+#define LM90_HAVE_REMOTE_EXT   BIT(17) /* extended remote temperature  */
+#define LM90_HAVE_FAULTQUEUE   BIT(18) /* configurable samples count   */
 
 /* LM90 status */
-#define LM90_STATUS_LTHRM      (1 << 0) /* local THERM limit tripped */
-#define LM90_STATUS_RTHRM      (1 << 1) /* remote THERM limit tripped */
-#define LM90_STATUS_ROPEN      (1 << 2) /* remote is an open circuit */
-#define LM90_STATUS_RLOW       (1 << 3) /* remote low temp limit tripped */
-#define LM90_STATUS_RHIGH      (1 << 4) /* remote high temp limit tripped */
-#define LM90_STATUS_LLOW       (1 << 5) /* local low temp limit tripped */
-#define LM90_STATUS_LHIGH      (1 << 6) /* local high temp limit tripped */
-#define LM90_STATUS_BUSY       (1 << 7) /* conversion is ongoing */
-
-#define MAX6696_STATUS2_R2THRM (1 << 1) /* remote2 THERM limit tripped */
-#define MAX6696_STATUS2_R2OPEN (1 << 2) /* remote2 is an open circuit */
-#define MAX6696_STATUS2_R2LOW  (1 << 3) /* remote2 low temp limit tripped */
-#define MAX6696_STATUS2_R2HIGH (1 << 4) /* remote2 high temp limit tripped */
-#define MAX6696_STATUS2_ROT2   (1 << 5) /* remote emergency limit tripped */
-#define MAX6696_STATUS2_R2OT2  (1 << 6) /* remote2 emergency limit tripped */
-#define MAX6696_STATUS2_LOT2   (1 << 7) /* local emergency limit tripped */
+#define LM90_STATUS_LTHRM      BIT(0)  /* local THERM limit tripped */
+#define LM90_STATUS_RTHRM      BIT(1)  /* remote THERM limit tripped */
+#define LM90_STATUS_ROPEN      BIT(2)  /* remote is an open circuit */
+#define LM90_STATUS_RLOW       BIT(3)  /* remote low temp limit tripped */
+#define LM90_STATUS_RHIGH      BIT(4)  /* remote high temp limit tripped */
+#define LM90_STATUS_LLOW       BIT(5)  /* local low temp limit tripped */
+#define LM90_STATUS_LHIGH      BIT(6)  /* local high temp limit tripped */
+#define LM90_STATUS_BUSY       BIT(7)  /* conversion is ongoing */
+
+/* MAX6695/6696 and ADT7481 2nd status register */
+#define MAX6696_STATUS2_R2THRM BIT(1)  /* remote2 THERM limit tripped */
+#define MAX6696_STATUS2_R2OPEN BIT(2)  /* remote2 is an open circuit */
+#define MAX6696_STATUS2_R2LOW  BIT(3)  /* remote2 low temp limit tripped */
+#define MAX6696_STATUS2_R2HIGH BIT(4)  /* remote2 high temp limit tripped */
+#define MAX6696_STATUS2_ROT2   BIT(5)  /* remote emergency limit tripped */
+#define MAX6696_STATUS2_R2OT2  BIT(6)  /* remote2 emergency limit tripped */
+#define MAX6696_STATUS2_LOT2   BIT(7)  /* local emergency limit tripped */
 
 /*
  * Driver data (common to all clients)
  */
 
 static const struct i2c_device_id lm90_id[] = {
+       { "adm1020", max1617 },
+       { "adm1021", max1617 },
+       { "adm1023", adm1023 },
        { "adm1032", adm1032 },
+       { "adt7421", adt7461a },
        { "adt7461", adt7461 },
-       { "adt7461a", adt7461 },
+       { "adt7461a", adt7461a },
+       { "adt7481", adt7481 },
+       { "adt7482", adt7481 },
+       { "adt7483a", adt7481 },
        { "g781", g781 },
+       { "gl523sm", max1617 },
+       { "lm84", lm84 },
+       { "lm86", lm90 },
+       { "lm89", lm90 },
        { "lm90", lm90 },
-       { "lm86", lm86 },
-       { "lm89", lm86 },
        { "lm99", lm99 },
+       { "max1617", max1617 },
+       { "max6642", max6642 },
        { "max6646", max6646 },
        { "max6647", max6646 },
+       { "max6648", max6648 },
        { "max6649", max6646 },
        { "max6654", max6654 },
        { "max6657", max6657 },
@@ -232,11 +264,20 @@ static const struct i2c_device_id lm90_id[] = {
        { "max6659", max6659 },
        { "max6680", max6680 },
        { "max6681", max6680 },
+       { "max6690", max6654 },
+       { "max6692", max6648 },
        { "max6695", max6696 },
        { "max6696", max6696 },
-       { "nct1008", adt7461 },
+       { "mc1066", max1617 },
+       { "nct1008", adt7461a },
+       { "nct210", nct210 },
+       { "nct214", nct72 },
+       { "nct218", nct72 },
+       { "nct72", nct72 },
+       { "ne1618", ne1618 },
        { "w83l771", w83l771 },
        { "sa56004", sa56004 },
+       { "thmc10", max1617 },
        { "tmp451", tmp451 },
        { "tmp461", tmp461 },
        { }
@@ -254,7 +295,11 @@ static const struct of_device_id __maybe_unused lm90_of_match[] = {
        },
        {
                .compatible = "adi,adt7461a",
-               .data = (void *)adt7461
+               .data = (void *)adt7461a
+       },
+       {
+               .compatible = "adi,adt7481",
+               .data = (void *)adt7481
        },
        {
                .compatible = "gmt,g781",
@@ -266,11 +311,11 @@ static const struct of_device_id __maybe_unused lm90_of_match[] = {
        },
        {
                .compatible = "national,lm86",
-               .data = (void *)lm86
+               .data = (void *)lm90
        },
        {
                .compatible = "national,lm89",
-               .data = (void *)lm86
+               .data = (void *)lm90
        },
        {
                .compatible = "national,lm99",
@@ -322,7 +367,19 @@ static const struct of_device_id __maybe_unused lm90_of_match[] = {
        },
        {
                .compatible = "onnn,nct1008",
-               .data = (void *)adt7461
+               .data = (void *)adt7461a
+       },
+       {
+               .compatible = "onnn,nct214",
+               .data = (void *)nct72
+       },
+       {
+               .compatible = "onnn,nct218",
+               .data = (void *)nct72
+       },
+       {
+               .compatible = "onnn,nct72",
+               .data = (void *)nct72
        },
        {
                .compatible = "winbond,w83l771",
@@ -352,115 +409,252 @@ struct lm90_params {
        u16 alert_alarms;       /* Which alarm bits trigger ALERT# */
                                /* Upper 8 bits for max6695/96 */
        u8 max_convrate;        /* Maximum conversion rate register value */
+       u8 resolution;          /* 16-bit resolution (default 11 bit) */
+       u8 reg_status2;         /* 2nd status register (optional) */
        u8 reg_local_ext;       /* Extended local temp register (optional) */
+       u8 faultqueue_mask;     /* fault queue bit mask */
+       u8 faultqueue_depth;    /* fault queue depth if mask is used */
 };
 
 static const struct lm90_params lm90_params[] = {
+       [adm1023] = {
+               .flags = LM90_HAVE_ALARMS | LM90_HAVE_OFFSET | LM90_HAVE_BROKEN_ALERT
+                 | LM90_HAVE_REM_LIMIT_EXT | LM90_HAVE_LOW | LM90_HAVE_CONVRATE
+                 | LM90_HAVE_REMOTE_EXT,
+               .alert_alarms = 0x7c,
+               .resolution = 8,
+               .max_convrate = 7,
+       },
        [adm1032] = {
                .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
-                 | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_CRIT,
+                 | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_CRIT
+                 | LM90_HAVE_PARTIAL_PEC | LM90_HAVE_ALARMS
+                 | LM90_HAVE_LOW | LM90_HAVE_CONVRATE | LM90_HAVE_REMOTE_EXT
+                 | LM90_HAVE_FAULTQUEUE,
                .alert_alarms = 0x7c,
                .max_convrate = 10,
        },
        [adt7461] = {
+               /*
+                * Standard temperature range is supposed to be unsigned,
+                * but that does not match reality. Negative temperatures
+                * are always reported.
+                */
+               .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
+                 | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP
+                 | LM90_HAVE_CRIT | LM90_HAVE_PARTIAL_PEC
+                 | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE
+                 | LM90_HAVE_REMOTE_EXT | LM90_HAVE_FAULTQUEUE,
+               .alert_alarms = 0x7c,
+               .max_convrate = 10,
+               .resolution = 10,
+       },
+       [adt7461a] = {
                .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
                  | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP
-                 | LM90_HAVE_CRIT,
+                 | LM90_HAVE_CRIT | LM90_HAVE_PEC | LM90_HAVE_ALARMS
+                 | LM90_HAVE_LOW | LM90_HAVE_CONVRATE | LM90_HAVE_REMOTE_EXT
+                 | LM90_HAVE_FAULTQUEUE,
                .alert_alarms = 0x7c,
                .max_convrate = 10,
        },
+       [adt7481] = {
+               .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
+                 | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP
+                 | LM90_HAVE_UNSIGNED_TEMP | LM90_HAVE_PEC
+                 | LM90_HAVE_TEMP3 | LM90_HAVE_CRIT | LM90_HAVE_LOW
+                 | LM90_HAVE_CONVRATE | LM90_HAVE_REMOTE_EXT
+                 | LM90_HAVE_FAULTQUEUE,
+               .alert_alarms = 0x1c7c,
+               .max_convrate = 11,
+               .resolution = 10,
+               .reg_status2 = ADT7481_REG_STATUS2,
+       },
        [g781] = {
                .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
-                 | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_CRIT,
+                 | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_CRIT
+                 | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE
+                 | LM90_HAVE_REMOTE_EXT | LM90_HAVE_FAULTQUEUE,
                .alert_alarms = 0x7c,
                .max_convrate = 7,
        },
-       [lm86] = {
-               .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
-                 | LM90_HAVE_CRIT,
-               .alert_alarms = 0x7b,
-               .max_convrate = 9,
+       [lm84] = {
+               .flags = LM90_HAVE_ALARMS,
+               .resolution = 8,
        },
        [lm90] = {
                .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
-                 | LM90_HAVE_CRIT,
+                 | LM90_HAVE_CRIT | LM90_HAVE_ALARMS | LM90_HAVE_LOW
+                 | LM90_HAVE_CONVRATE | LM90_HAVE_REMOTE_EXT
+                 | LM90_HAVE_FAULTQUEUE,
                .alert_alarms = 0x7b,
                .max_convrate = 9,
+               .faultqueue_mask = BIT(0),
+               .faultqueue_depth = 3,
        },
        [lm99] = {
                .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
-                 | LM90_HAVE_CRIT,
+                 | LM90_HAVE_CRIT | LM90_HAVE_ALARMS | LM90_HAVE_LOW
+                 | LM90_HAVE_CONVRATE | LM90_HAVE_REMOTE_EXT
+                 | LM90_HAVE_FAULTQUEUE,
                .alert_alarms = 0x7b,
                .max_convrate = 9,
+               .faultqueue_mask = BIT(0),
+               .faultqueue_depth = 3,
+       },
+       [max1617] = {
+               .flags = LM90_HAVE_CONVRATE | LM90_HAVE_BROKEN_ALERT |
+                 LM90_HAVE_LOW | LM90_HAVE_ALARMS,
+               .alert_alarms = 0x78,
+               .resolution = 8,
+               .max_convrate = 7,
+       },
+       [max6642] = {
+               .flags = LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXT_UNSIGNED
+                 | LM90_HAVE_REMOTE_EXT | LM90_HAVE_FAULTQUEUE,
+               .alert_alarms = 0x50,
+               .resolution = 10,
+               .reg_local_ext = MAX6657_REG_LOCAL_TEMPL,
+               .faultqueue_mask = BIT(4),
+               .faultqueue_depth = 2,
        },
        [max6646] = {
-               .flags = LM90_HAVE_CRIT | LM90_HAVE_BROKEN_ALERT,
+               .flags = LM90_HAVE_CRIT | LM90_HAVE_BROKEN_ALERT
+                 | LM90_HAVE_EXT_UNSIGNED | LM90_HAVE_ALARMS | LM90_HAVE_LOW
+                 | LM90_HAVE_CONVRATE | LM90_HAVE_REMOTE_EXT,
                .alert_alarms = 0x7c,
                .max_convrate = 6,
-               .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
+               .reg_local_ext = MAX6657_REG_LOCAL_TEMPL,
+       },
+       [max6648] = {
+               .flags = LM90_HAVE_UNSIGNED_TEMP | LM90_HAVE_CRIT
+                 | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_LOW
+                 | LM90_HAVE_CONVRATE | LM90_HAVE_REMOTE_EXT,
+               .alert_alarms = 0x7c,
+               .max_convrate = 6,
+               .reg_local_ext = MAX6657_REG_LOCAL_TEMPL,
        },
        [max6654] = {
-               .flags = LM90_HAVE_BROKEN_ALERT,
+               .flags = LM90_HAVE_BROKEN_ALERT | LM90_HAVE_ALARMS | LM90_HAVE_LOW
+                 | LM90_HAVE_CONVRATE | LM90_HAVE_REMOTE_EXT,
                .alert_alarms = 0x7c,
                .max_convrate = 7,
-               .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
+               .reg_local_ext = MAX6657_REG_LOCAL_TEMPL,
        },
        [max6657] = {
-               .flags = LM90_PAUSE_FOR_CONFIG | LM90_HAVE_CRIT,
+               .flags = LM90_PAUSE_FOR_CONFIG | LM90_HAVE_CRIT
+                 | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE
+                 | LM90_HAVE_REMOTE_EXT,
                .alert_alarms = 0x7c,
                .max_convrate = 8,
-               .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
+               .reg_local_ext = MAX6657_REG_LOCAL_TEMPL,
        },
        [max6659] = {
-               .flags = LM90_HAVE_EMERGENCY | LM90_HAVE_CRIT,
+               .flags = LM90_HAVE_EMERGENCY | LM90_HAVE_CRIT
+                 | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE
+                 | LM90_HAVE_REMOTE_EXT,
                .alert_alarms = 0x7c,
                .max_convrate = 8,
-               .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
+               .reg_local_ext = MAX6657_REG_LOCAL_TEMPL,
        },
        [max6680] = {
+               /*
+                * Apparent temperatures of 128 degrees C or higher are reported
+                * and treated as negative temperatures (meaning min_alarm will
+                * be set).
+                */
                .flags = LM90_HAVE_OFFSET | LM90_HAVE_CRIT
-                 | LM90_HAVE_CRIT_ALRM_SWP | LM90_HAVE_BROKEN_ALERT,
+                 | LM90_HAVE_CRIT_ALRM_SWP | LM90_HAVE_BROKEN_ALERT
+                 | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE
+                 | LM90_HAVE_REMOTE_EXT,
                .alert_alarms = 0x7c,
                .max_convrate = 7,
        },
        [max6696] = {
                .flags = LM90_HAVE_EMERGENCY
-                 | LM90_HAVE_EMERGENCY_ALARM | LM90_HAVE_TEMP3 | LM90_HAVE_CRIT,
+                 | LM90_HAVE_EMERGENCY_ALARM | LM90_HAVE_TEMP3 | LM90_HAVE_CRIT
+                 | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE
+                 | LM90_HAVE_REMOTE_EXT | LM90_HAVE_FAULTQUEUE,
                .alert_alarms = 0x1c7c,
                .max_convrate = 6,
-               .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
+               .reg_status2 = MAX6696_REG_STATUS2,
+               .reg_local_ext = MAX6657_REG_LOCAL_TEMPL,
+               .faultqueue_mask = BIT(5),
+               .faultqueue_depth = 4,
+       },
+       [nct72] = {
+               .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
+                 | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP
+                 | LM90_HAVE_CRIT | LM90_HAVE_PEC | LM90_HAVE_UNSIGNED_TEMP
+                 | LM90_HAVE_LOW | LM90_HAVE_CONVRATE | LM90_HAVE_REMOTE_EXT
+                 | LM90_HAVE_FAULTQUEUE,
+               .alert_alarms = 0x7c,
+               .max_convrate = 10,
+               .resolution = 10,
+       },
+       [nct210] = {
+               .flags = LM90_HAVE_ALARMS | LM90_HAVE_BROKEN_ALERT
+                 | LM90_HAVE_REM_LIMIT_EXT | LM90_HAVE_LOW | LM90_HAVE_CONVRATE
+                 | LM90_HAVE_REMOTE_EXT,
+               .alert_alarms = 0x7c,
+               .resolution = 11,
+               .max_convrate = 7,
+       },
+       [ne1618] = {
+               .flags = LM90_PAUSE_FOR_CONFIG | LM90_HAVE_BROKEN_ALERT
+                 | LM90_HAVE_LOW | LM90_HAVE_CONVRATE | LM90_HAVE_REMOTE_EXT,
+               .alert_alarms = 0x7c,
+               .resolution = 11,
+               .max_convrate = 7,
        },
        [w83l771] = {
-               .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT | LM90_HAVE_CRIT,
+               .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT | LM90_HAVE_CRIT
+                 | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE
+                 | LM90_HAVE_REMOTE_EXT,
                .alert_alarms = 0x7c,
                .max_convrate = 8,
        },
        [sa56004] = {
-               .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT | LM90_HAVE_CRIT,
+               /*
+                * Apparent temperatures of 128 degrees C or higher are reported
+                * and treated as negative temperatures (meaning min_alarm will
+                * be set).
+                */
+               .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT | LM90_HAVE_CRIT
+                 | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE
+                 | LM90_HAVE_REMOTE_EXT | LM90_HAVE_FAULTQUEUE,
                .alert_alarms = 0x7b,
                .max_convrate = 9,
-               .reg_local_ext = SA56004_REG_R_LOCAL_TEMPL,
+               .reg_local_ext = SA56004_REG_LOCAL_TEMPL,
+               .faultqueue_mask = BIT(0),
+               .faultqueue_depth = 3,
        },
        [tmp451] = {
                .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
-                 | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP | LM90_HAVE_CRIT,
+                 | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP | LM90_HAVE_CRIT
+                 | LM90_HAVE_UNSIGNED_TEMP | LM90_HAVE_ALARMS | LM90_HAVE_LOW
+                 | LM90_HAVE_CONVRATE | LM90_HAVE_REMOTE_EXT | LM90_HAVE_FAULTQUEUE,
                .alert_alarms = 0x7c,
                .max_convrate = 9,
-               .reg_local_ext = TMP451_REG_R_LOCAL_TEMPL,
+               .resolution = 12,
+               .reg_local_ext = TMP451_REG_LOCAL_TEMPL,
        },
        [tmp461] = {
                .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
-                 | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP | LM90_HAVE_CRIT,
+                 | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP | LM90_HAVE_CRIT
+                 | LM90_HAVE_ALARMS | LM90_HAVE_LOW | LM90_HAVE_CONVRATE
+                 | LM90_HAVE_REMOTE_EXT | LM90_HAVE_FAULTQUEUE,
                .alert_alarms = 0x7c,
                .max_convrate = 9,
-               .reg_local_ext = TMP451_REG_R_LOCAL_TEMPL,
+               .resolution = 12,
+               .reg_local_ext = TMP451_REG_LOCAL_TEMPL,
        },
 };
 
 /*
- * TEMP8 register index
+ * temperature register index
  */
-enum lm90_temp8_reg_index {
+enum lm90_temp_reg_index {
        LOCAL_LOW = 0,
        LOCAL_HIGH,
        LOCAL_CRIT,
@@ -469,14 +663,8 @@ enum lm90_temp8_reg_index {
        REMOTE_EMERG,   /* max6659 and max6695/96 */
        REMOTE2_CRIT,   /* max6695/96 only */
        REMOTE2_EMERG,  /* max6695/96 only */
-       TEMP8_REG_NUM
-};
 
-/*
- * TEMP11 register index
- */
-enum lm90_temp11_reg_index {
-       REMOTE_TEMP = 0,
+       REMOTE_TEMP,
        REMOTE_LOW,
        REMOTE_HIGH,
        REMOTE_OFFSET,  /* except max6646, max6657/58/59, and max6695/96 */
@@ -484,7 +672,9 @@ enum lm90_temp11_reg_index {
        REMOTE2_TEMP,   /* max6695/96 only */
        REMOTE2_LOW,    /* max6695/96 only */
        REMOTE2_HIGH,   /* max6695/96 only */
-       TEMP11_REG_NUM
+       REMOTE2_OFFSET,
+
+       TEMP_REG_NUM
 };
 
 /*
@@ -494,13 +684,20 @@ enum lm90_temp11_reg_index {
 struct lm90_data {
        struct i2c_client *client;
        struct device *hwmon_dev;
-       u32 channel_config[4];
+       u32 chip_config[2];
+       u32 channel_config[MAX_CHANNELS + 1];
+       const char *channel_label[MAX_CHANNELS];
+       struct hwmon_channel_info chip_info;
        struct hwmon_channel_info temp_info;
        const struct hwmon_channel_info *info[3];
        struct hwmon_chip_info chip;
        struct mutex update_lock;
+       struct delayed_work alert_work;
+       struct work_struct report_work;
        bool valid;             /* true if register values are valid */
+       bool alarms_valid;      /* true if status register values are valid */
        unsigned long last_updated; /* in jiffies */
+       unsigned long alarms_updated; /* in jiffies */
        int kind;
        u32 flags;
 
@@ -509,16 +706,23 @@ struct lm90_data {
        u8 config;              /* Current configuration register value */
        u8 config_orig;         /* Original configuration register value */
        u8 convrate_orig;       /* Original conversion rate register value */
+       u8 resolution;          /* temperature resolution in bit */
        u16 alert_alarms;       /* Which alarm bits trigger ALERT# */
                                /* Upper 8 bits for max6695/96 */
        u8 max_convrate;        /* Maximum conversion rate */
+       u8 reg_status2;         /* 2nd status register (optional) */
        u8 reg_local_ext;       /* local extension register offset */
+       u8 reg_remote_ext;      /* remote temperature low byte */
+       u8 faultqueue_mask;     /* fault queue mask */
+       u8 faultqueue_depth;    /* fault queue mask */
 
        /* registers values */
-       s8 temp8[TEMP8_REG_NUM];
-       s16 temp11[TEMP11_REG_NUM];
+       u16 temp[TEMP_REG_NUM];
        u8 temp_hyst;
-       u16 alarms; /* bitvector (upper 8 bits for max6695/96) */
+       u8 conalert;
+       u16 reported_alarms;    /* alarms reported as sysfs/udev events */
+       u16 current_alarms;     /* current alarms, reported by chip */
+       u16 alarms;             /* alarms not yet reported to user */
 };
 
 /*
@@ -526,10 +730,10 @@ struct lm90_data {
  */
 
 /*
- * The ADM1032 supports PEC but not on write byte transactions, so we need
+ * If the chip supports PEC but not on write byte transactions, we need
  * to explicitly ask for a transaction without PEC.
  */
-static inline s32 adm1032_write_byte(struct i2c_client *client, u8 value)
+static inline s32 lm90_write_no_pec(struct i2c_client *client, u8 value)
 {
        return i2c_smbus_xfer(client->adapter, client->addr,
                              client->flags & ~I2C_CLIENT_PEC,
@@ -538,47 +742,96 @@ static inline s32 adm1032_write_byte(struct i2c_client *client, u8 value)
 
 /*
  * It is assumed that client->update_lock is held (unless we are in
- * detection or initialization steps). This matters when PEC is enabled,
- * because we don't want the address pointer to change between the write
- * byte and the read byte transactions.
+ * detection or initialization steps). This matters when PEC is enabled
+ * for chips with partial PEC support, because we don't want the address
+ * pointer to change between the write byte and the read byte transactions.
  */
 static int lm90_read_reg(struct i2c_client *client, u8 reg)
 {
+       struct lm90_data *data = i2c_get_clientdata(client);
+       bool partial_pec = (client->flags & I2C_CLIENT_PEC) &&
+                       (data->flags & LM90_HAVE_PARTIAL_PEC);
        int err;
 
-       if (client->flags & I2C_CLIENT_PEC) {
-               err = adm1032_write_byte(client, reg);
-               if (err >= 0)
-                       err = i2c_smbus_read_byte(client);
-       } else
-               err = i2c_smbus_read_byte_data(client, reg);
+       if (partial_pec) {
+               err = lm90_write_no_pec(client, reg);
+               if (err)
+                       return err;
+               return i2c_smbus_read_byte(client);
+       }
+       return i2c_smbus_read_byte_data(client, reg);
+}
 
-       return err;
+/*
+ * Return register write address
+ *
+ * The write address for registers 0x03 .. 0x08 is the read address plus 6.
+ * For other registers the write address matches the read address.
+ */
+static u8 lm90_write_reg_addr(u8 reg)
+{
+       if (reg >= LM90_REG_CONFIG1 && reg <= LM90_REG_REMOTE_LOWH)
+               return reg + 6;
+       return reg;
+}
+
+/*
+ * Write into LM90 register.
+ * Convert register address to write address if needed, then execute the
+ * operation.
+ */
+static int lm90_write_reg(struct i2c_client *client, u8 reg, u8 val)
+{
+       return i2c_smbus_write_byte_data(client, lm90_write_reg_addr(reg), val);
+}
+
+/*
+ * Write into 16-bit LM90 register.
+ * Convert register addresses to write address if needed, then execute the
+ * operation.
+ */
+static int lm90_write16(struct i2c_client *client, u8 regh, u8 regl, u16 val)
+{
+       int ret;
+
+       ret = lm90_write_reg(client, regh, val >> 8);
+       if (ret < 0 || !regl)
+               return ret;
+       return lm90_write_reg(client, regl, val & 0xff);
 }
 
-static int lm90_read16(struct i2c_client *client, u8 regh, u8 regl)
+static int lm90_read16(struct i2c_client *client, u8 regh, u8 regl,
+                      bool is_volatile)
 {
        int oldh, newh, l;
 
-       /*
-        * There is a trick here. We have to read two registers to have the
-        * sensor temperature, but we have to beware a conversion could occur
-        * between the readings. The datasheet says we should either use
-        * the one-shot conversion register, which we don't want to do
-        * (disables hardware monitoring) or monitor the busy bit, which is
-        * impossible (we can't read the values and monitor that bit at the
-        * exact same time). So the solution used here is to read the high
-        * byte once, then the low byte, then the high byte again. If the new
-        * high byte matches the old one, then we have a valid reading. Else
-        * we have to read the low byte again, and now we believe we have a
-        * correct reading.
-        */
        oldh = lm90_read_reg(client, regh);
        if (oldh < 0)
                return oldh;
+
+       if (!regl)
+               return oldh << 8;
+
        l = lm90_read_reg(client, regl);
        if (l < 0)
                return l;
+
+       if (!is_volatile)
+               return (oldh << 8) | l;
+
+       /*
+        * For volatile registers we have to use a trick.
+        * We have to read two registers to have the sensor temperature,
+        * but we have to beware a conversion could occur between the
+        * readings. The datasheet says we should either use
+        * the one-shot conversion register, which we don't want to do
+        * (disables hardware monitoring) or monitor the busy bit, which is
+        * impossible (we can't read the values and monitor that bit at the
+        * exact same time). So the solution used here is to read the high
+        * the high byte again. If the new high byte matches the old one,
+        * then we have a valid reading. Otherwise we have to read the low
+        * byte again, and now we believe we have a correct reading.
+        */
        newh = lm90_read_reg(client, regh);
        if (newh < 0)
                return newh;
@@ -595,9 +848,7 @@ static int lm90_update_confreg(struct lm90_data *data, u8 config)
        if (data->config != config) {
                int err;
 
-               err = i2c_smbus_write_byte_data(data->client,
-                                               LM90_REG_W_CONFIG1,
-                                               config);
+               err = lm90_write_reg(data->client, LM90_REG_CONFIG1, config);
                if (err)
                        return err;
                data->config = config;
@@ -613,18 +864,14 @@ static int lm90_update_confreg(struct lm90_data *data, u8 config)
  * various registers have different meanings as a result of selecting a
  * non-default remote channel.
  */
-static int lm90_select_remote_channel(struct lm90_data *data, int channel)
+static int lm90_select_remote_channel(struct lm90_data *data, bool second)
 {
-       int err = 0;
+       u8 config = data->config & ~0x08;
 
-       if (data->kind == max6696) {
-               u8 config = data->config & ~0x08;
+       if (second)
+               config |= 0x08;
 
-               if (channel)
-                       config |= 0x08;
-               err = lm90_update_confreg(data, config);
-       }
-       return err;
+       return lm90_update_confreg(data, config);
 }
 
 static int lm90_write_convrate(struct lm90_data *data, int val)
@@ -640,7 +887,7 @@ static int lm90_write_convrate(struct lm90_data *data, int val)
        }
 
        /* Set conv rate */
-       err = i2c_smbus_write_byte_data(data->client, LM90_REG_W_CONVRATE, val);
+       err = lm90_write_reg(data->client, LM90_REG_CONVRATE, val);
 
        /* Revert change to config */
        lm90_update_confreg(data, config);
@@ -673,6 +920,26 @@ static int lm90_set_convrate(struct i2c_client *client, struct lm90_data *data,
        return err;
 }
 
+static int lm90_set_faultqueue(struct i2c_client *client,
+                              struct lm90_data *data, int val)
+{
+       int err;
+
+       if (data->faultqueue_mask) {
+               err = lm90_update_confreg(data, val <= data->faultqueue_depth / 2 ?
+                                         data->config & ~data->faultqueue_mask :
+                                         data->config | data->faultqueue_mask);
+       } else {
+               static const u8 values[4] = {0, 2, 6, 0x0e};
+
+               data->conalert = (data->conalert & 0xf1) | values[val - 1];
+               err = lm90_write_reg(data->client, TMP451_REG_CONALERT,
+                                    data->conalert);
+       }
+
+       return err;
+}
+
 static int lm90_update_limits(struct device *dev)
 {
        struct lm90_data *data = dev_get_drvdata(dev);
@@ -680,97 +947,260 @@ static int lm90_update_limits(struct device *dev)
        int val;
 
        if (data->flags & LM90_HAVE_CRIT) {
-               val = lm90_read_reg(client, LM90_REG_R_LOCAL_CRIT);
+               val = lm90_read_reg(client, LM90_REG_LOCAL_CRIT);
                if (val < 0)
                        return val;
-               data->temp8[LOCAL_CRIT] = val;
+               data->temp[LOCAL_CRIT] = val << 8;
 
-               val = lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT);
+               val = lm90_read_reg(client, LM90_REG_REMOTE_CRIT);
                if (val < 0)
                        return val;
-               data->temp8[REMOTE_CRIT] = val;
+               data->temp[REMOTE_CRIT] = val << 8;
 
-               val = lm90_read_reg(client, LM90_REG_R_TCRIT_HYST);
+               val = lm90_read_reg(client, LM90_REG_TCRIT_HYST);
                if (val < 0)
                        return val;
                data->temp_hyst = val;
        }
-
-       val = lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH);
-       if (val < 0)
-               return val;
-       data->temp11[REMOTE_LOW] = val << 8;
-
-       if (data->flags & LM90_HAVE_REM_LIMIT_EXT) {
-               val = lm90_read_reg(client, LM90_REG_R_REMOTE_LOWL);
+       if ((data->flags & LM90_HAVE_FAULTQUEUE) && !data->faultqueue_mask) {
+               val = lm90_read_reg(client, TMP451_REG_CONALERT);
                if (val < 0)
                        return val;
-               data->temp11[REMOTE_LOW] |= val;
+               data->conalert = val;
        }
 
-       val = lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH);
+       val = lm90_read16(client, LM90_REG_REMOTE_LOWH,
+                         (data->flags & LM90_HAVE_REM_LIMIT_EXT) ? LM90_REG_REMOTE_LOWL : 0,
+                         false);
        if (val < 0)
                return val;
-       data->temp11[REMOTE_HIGH] = val << 8;
+       data->temp[REMOTE_LOW] = val;
 
-       if (data->flags & LM90_HAVE_REM_LIMIT_EXT) {
-               val = lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHL);
-               if (val < 0)
-                       return val;
-               data->temp11[REMOTE_HIGH] |= val;
-       }
+       val = lm90_read16(client, LM90_REG_REMOTE_HIGHH,
+                         (data->flags & LM90_HAVE_REM_LIMIT_EXT) ? LM90_REG_REMOTE_HIGHL : 0,
+                         false);
+       if (val < 0)
+               return val;
+       data->temp[REMOTE_HIGH] = val;
 
        if (data->flags & LM90_HAVE_OFFSET) {
-               val = lm90_read16(client, LM90_REG_R_REMOTE_OFFSH,
-                                 LM90_REG_R_REMOTE_OFFSL);
+               val = lm90_read16(client, LM90_REG_REMOTE_OFFSH,
+                                 LM90_REG_REMOTE_OFFSL, false);
                if (val < 0)
                        return val;
-               data->temp11[REMOTE_OFFSET] = val;
+               data->temp[REMOTE_OFFSET] = val;
        }
 
        if (data->flags & LM90_HAVE_EMERGENCY) {
-               val = lm90_read_reg(client, MAX6659_REG_R_LOCAL_EMERG);
+               val = lm90_read_reg(client, MAX6659_REG_LOCAL_EMERG);
                if (val < 0)
                        return val;
-               data->temp8[LOCAL_EMERG] = val;
+               data->temp[LOCAL_EMERG] = val << 8;
 
-               val = lm90_read_reg(client, MAX6659_REG_R_REMOTE_EMERG);
+               val = lm90_read_reg(client, MAX6659_REG_REMOTE_EMERG);
                if (val < 0)
                        return val;
-               data->temp8[REMOTE_EMERG] = val;
+               data->temp[REMOTE_EMERG] = val << 8;
        }
 
-       if (data->kind == max6696) {
-               val = lm90_select_remote_channel(data, 1);
+       if (data->flags & LM90_HAVE_TEMP3) {
+               val = lm90_select_remote_channel(data, true);
                if (val < 0)
                        return val;
 
-               val = lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT);
+               val = lm90_read_reg(client, LM90_REG_REMOTE_CRIT);
                if (val < 0)
                        return val;
-               data->temp8[REMOTE2_CRIT] = val;
+               data->temp[REMOTE2_CRIT] = val << 8;
+
+               if (data->flags & LM90_HAVE_EMERGENCY) {
+                       val = lm90_read_reg(client, MAX6659_REG_REMOTE_EMERG);
+                       if (val < 0)
+                               return val;
+                       data->temp[REMOTE2_EMERG] = val << 8;
+               }
 
-               val = lm90_read_reg(client, MAX6659_REG_R_REMOTE_EMERG);
+               val = lm90_read_reg(client, LM90_REG_REMOTE_LOWH);
                if (val < 0)
                        return val;
-               data->temp8[REMOTE2_EMERG] = val;
+               data->temp[REMOTE2_LOW] = val << 8;
 
-               val = lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH);
+               val = lm90_read_reg(client, LM90_REG_REMOTE_HIGHH);
                if (val < 0)
                        return val;
-               data->temp11[REMOTE2_LOW] = val << 8;
+               data->temp[REMOTE2_HIGH] = val << 8;
+
+               if (data->flags & LM90_HAVE_OFFSET) {
+                       val = lm90_read16(client, LM90_REG_REMOTE_OFFSH,
+                                         LM90_REG_REMOTE_OFFSL, false);
+                       if (val < 0)
+                               return val;
+                       data->temp[REMOTE2_OFFSET] = val;
+               }
+
+               lm90_select_remote_channel(data, false);
+       }
+
+       return 0;
+}
+
+static void lm90_report_alarms(struct work_struct *work)
+{
+       struct lm90_data *data = container_of(work, struct lm90_data, report_work);
+       u16 cleared_alarms, new_alarms, current_alarms;
+       struct device *hwmon_dev = data->hwmon_dev;
+       struct device *dev = &data->client->dev;
+       int st, st2;
+
+       current_alarms = data->current_alarms;
+       cleared_alarms = data->reported_alarms & ~current_alarms;
+       new_alarms = current_alarms & ~data->reported_alarms;
+
+       if (!cleared_alarms && !new_alarms)
+               return;
+
+       st = new_alarms & 0xff;
+       st2 = new_alarms >> 8;
+
+       if ((st & (LM90_STATUS_LLOW | LM90_STATUS_LHIGH | LM90_STATUS_LTHRM)) ||
+           (st2 & MAX6696_STATUS2_LOT2))
+               dev_dbg(dev, "temp%d out of range, please check!\n", 1);
+       if ((st & (LM90_STATUS_RLOW | LM90_STATUS_RHIGH | LM90_STATUS_RTHRM)) ||
+           (st2 & MAX6696_STATUS2_ROT2))
+               dev_dbg(dev, "temp%d out of range, please check!\n", 2);
+       if (st & LM90_STATUS_ROPEN)
+               dev_dbg(dev, "temp%d diode open, please check!\n", 2);
+       if (st2 & (MAX6696_STATUS2_R2LOW | MAX6696_STATUS2_R2HIGH |
+                  MAX6696_STATUS2_R2THRM | MAX6696_STATUS2_R2OT2))
+               dev_dbg(dev, "temp%d out of range, please check!\n", 3);
+       if (st2 & MAX6696_STATUS2_R2OPEN)
+               dev_dbg(dev, "temp%d diode open, please check!\n", 3);
+
+       st |= cleared_alarms & 0xff;
+       st2 |= cleared_alarms >> 8;
+
+       if (st & LM90_STATUS_LLOW)
+               hwmon_notify_event(hwmon_dev, hwmon_temp, hwmon_temp_min_alarm, 0);
+       if (st & LM90_STATUS_RLOW)
+               hwmon_notify_event(hwmon_dev, hwmon_temp, hwmon_temp_min_alarm, 1);
+       if (st2 & MAX6696_STATUS2_R2LOW)
+               hwmon_notify_event(hwmon_dev, hwmon_temp, hwmon_temp_min_alarm, 2);
+
+       if (st & LM90_STATUS_LHIGH)
+               hwmon_notify_event(hwmon_dev, hwmon_temp, hwmon_temp_max_alarm, 0);
+       if (st & LM90_STATUS_RHIGH)
+               hwmon_notify_event(hwmon_dev, hwmon_temp, hwmon_temp_max_alarm, 1);
+       if (st2 & MAX6696_STATUS2_R2HIGH)
+               hwmon_notify_event(hwmon_dev, hwmon_temp, hwmon_temp_max_alarm, 2);
+
+       if (st & LM90_STATUS_LTHRM)
+               hwmon_notify_event(hwmon_dev, hwmon_temp, hwmon_temp_crit_alarm, 0);
+       if (st & LM90_STATUS_RTHRM)
+               hwmon_notify_event(hwmon_dev, hwmon_temp, hwmon_temp_crit_alarm, 1);
+       if (st2 & MAX6696_STATUS2_R2THRM)
+               hwmon_notify_event(hwmon_dev, hwmon_temp, hwmon_temp_crit_alarm, 2);
+
+       if (st2 & MAX6696_STATUS2_LOT2)
+               hwmon_notify_event(hwmon_dev, hwmon_temp, hwmon_temp_emergency_alarm, 0);
+       if (st2 & MAX6696_STATUS2_ROT2)
+               hwmon_notify_event(hwmon_dev, hwmon_temp, hwmon_temp_emergency_alarm, 1);
+       if (st2 & MAX6696_STATUS2_R2OT2)
+               hwmon_notify_event(hwmon_dev, hwmon_temp, hwmon_temp_emergency_alarm, 2);
+
+       data->reported_alarms = current_alarms;
+}
+
+static int lm90_update_alarms_locked(struct lm90_data *data, bool force)
+{
+       if (force || !data->alarms_valid ||
+           time_after(jiffies, data->alarms_updated + msecs_to_jiffies(data->update_interval))) {
+               struct i2c_client *client = data->client;
+               bool check_enable;
+               u16 alarms;
+               int val;
+
+               data->alarms_valid = false;
 
-               val = lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH);
+               val = lm90_read_reg(client, LM90_REG_STATUS);
                if (val < 0)
                        return val;
-               data->temp11[REMOTE2_HIGH] = val << 8;
+               alarms = val & ~LM90_STATUS_BUSY;
 
-               lm90_select_remote_channel(data, 0);
-       }
+               if (data->reg_status2) {
+                       val = lm90_read_reg(client, data->reg_status2);
+                       if (val < 0)
+                               return val;
+                       alarms |= val << 8;
+               }
+               /*
+                * If the update is forced (called from interrupt or alert
+                * handler) and alarm data is valid, the alarms may have been
+                * updated after the last update interval, and the status
+                * register may still be cleared. Only add additional alarms
+                * in this case. Alarms will be cleared later if appropriate.
+                */
+               if (force && data->alarms_valid)
+                       data->current_alarms |= alarms;
+               else
+                       data->current_alarms = alarms;
+               data->alarms |= alarms;
+
+               check_enable = (client->irq || !(data->config_orig & 0x80)) &&
+                       (data->config & 0x80);
 
+               if (force || check_enable)
+                       schedule_work(&data->report_work);
+
+               /*
+                * Re-enable ALERT# output if it was originally enabled, relevant
+                * alarms are all clear, and alerts are currently disabled.
+                * Otherwise (re)schedule worker if needed.
+                */
+               if (check_enable) {
+                       if (!(data->current_alarms & data->alert_alarms)) {
+                               dev_dbg(&client->dev, "Re-enabling ALERT#\n");
+                               lm90_update_confreg(data, data->config & ~0x80);
+                               /*
+                                * We may have been called from the update handler.
+                                * If so, the worker, if scheduled, is no longer
+                                * needed. Cancel it. Don't synchronize because
+                                * it may already be running.
+                                */
+                               cancel_delayed_work(&data->alert_work);
+                       } else {
+                               schedule_delayed_work(&data->alert_work,
+                                       max_t(int, HZ, msecs_to_jiffies(data->update_interval)));
+                       }
+               }
+               data->alarms_updated = jiffies;
+               data->alarms_valid = true;
+       }
        return 0;
 }
 
+static int lm90_update_alarms(struct lm90_data *data, bool force)
+{
+       int err;
+
+       mutex_lock(&data->update_lock);
+       err = lm90_update_alarms_locked(data, force);
+       mutex_unlock(&data->update_lock);
+
+       return err;
+}
+
+static void lm90_alert_work(struct work_struct *__work)
+{
+       struct delayed_work *delayed_work = container_of(__work, struct delayed_work, work);
+       struct lm90_data *data = container_of(delayed_work, struct lm90_data, alert_work);
+
+       /* Nothing to do if alerts are enabled */
+       if (!(data->config & 0x80))
+               return;
+
+       lm90_update_alarms(data, true);
+}
+
 static int lm90_update_device(struct device *dev)
 {
        struct lm90_data *data = dev_get_drvdata(dev);
@@ -791,71 +1221,46 @@ static int lm90_update_device(struct device *dev)
 
                data->valid = false;
 
-               val = lm90_read_reg(client, LM90_REG_R_LOCAL_LOW);
+               val = lm90_read_reg(client, LM90_REG_LOCAL_LOW);
                if (val < 0)
                        return val;
-               data->temp8[LOCAL_LOW] = val;
+               data->temp[LOCAL_LOW] = val << 8;
 
-               val = lm90_read_reg(client, LM90_REG_R_LOCAL_HIGH);
+               val = lm90_read_reg(client, LM90_REG_LOCAL_HIGH);
                if (val < 0)
                        return val;
-               data->temp8[LOCAL_HIGH] = val;
+               data->temp[LOCAL_HIGH] = val << 8;
 
-               if (data->reg_local_ext) {
-                       val = lm90_read16(client, LM90_REG_R_LOCAL_TEMP,
-                                         data->reg_local_ext);
-                       if (val < 0)
-                               return val;
-                       data->temp11[LOCAL_TEMP] = val;
-               } else {
-                       val = lm90_read_reg(client, LM90_REG_R_LOCAL_TEMP);
-                       if (val < 0)
-                               return val;
-                       data->temp11[LOCAL_TEMP] = val << 8;
-               }
-               val = lm90_read16(client, LM90_REG_R_REMOTE_TEMPH,
-                                 LM90_REG_R_REMOTE_TEMPL);
+               val = lm90_read16(client, LM90_REG_LOCAL_TEMP,
+                                 data->reg_local_ext, true);
                if (val < 0)
                        return val;
-               data->temp11[REMOTE_TEMP] = val;
-
-               val = lm90_read_reg(client, LM90_REG_R_STATUS);
+               data->temp[LOCAL_TEMP] = val;
+               val = lm90_read16(client, LM90_REG_REMOTE_TEMPH,
+                                 data->reg_remote_ext, true);
                if (val < 0)
                        return val;
-               data->alarms = val & ~LM90_STATUS_BUSY;
+               data->temp[REMOTE_TEMP] = val;
 
-               if (data->kind == max6696) {
-                       val = lm90_select_remote_channel(data, 1);
+               if (data->flags & LM90_HAVE_TEMP3) {
+                       val = lm90_select_remote_channel(data, true);
                        if (val < 0)
                                return val;
 
-                       val = lm90_read16(client, LM90_REG_R_REMOTE_TEMPH,
-                                         LM90_REG_R_REMOTE_TEMPL);
+                       val = lm90_read16(client, LM90_REG_REMOTE_TEMPH,
+                                         data->reg_remote_ext, true);
                        if (val < 0) {
-                               lm90_select_remote_channel(data, 0);
+                               lm90_select_remote_channel(data, false);
                                return val;
                        }
-                       data->temp11[REMOTE2_TEMP] = val;
+                       data->temp[REMOTE2_TEMP] = val;
 
-                       lm90_select_remote_channel(data, 0);
-
-                       val = lm90_read_reg(client, MAX6696_REG_R_STATUS2);
-                       if (val < 0)
-                               return val;
-                       data->alarms |= val << 8;
+                       lm90_select_remote_channel(data, false);
                }
 
-               /*
-                * Re-enable ALERT# output if it was originally enabled and
-                * relevant alarms are all clear
-                */
-               if ((client->irq || !(data->config_orig & 0x80)) &&
-                   !(data->alarms & data->alert_alarms)) {
-                       if (data->config & 0x80) {
-                               dev_dbg(&client->dev, "Re-enabling ALERT#\n");
-                               lm90_update_confreg(data, data->config & ~0x80);
-                       }
-               }
+               val = lm90_update_alarms_locked(data, false);
+               if (val < 0)
+                       return val;
 
                data->last_updated = jiffies;
                data->valid = true;
@@ -864,355 +1269,247 @@ static int lm90_update_device(struct device *dev)
        return 0;
 }
 
-/*
- * Conversions
- * For local temperatures and limits, critical limits and the hysteresis
- * value, the LM90 uses signed 8-bit values with LSB = 1 degree Celsius.
- * For remote temperatures and limits, it uses signed 11-bit values with
- * LSB = 0.125 degree Celsius, left-justified in 16-bit registers.  Some
- * Maxim chips use unsigned values.
- */
-
-static inline int temp_from_s8(s8 val)
+/* pec used for devices with PEC support */
+static ssize_t pec_show(struct device *dev, struct device_attribute *dummy,
+                       char *buf)
 {
-       return val * 1000;
-}
+       struct i2c_client *client = to_i2c_client(dev);
 
-static inline int temp_from_u8(u8 val)
-{
-       return val * 1000;
+       return sprintf(buf, "%d\n", !!(client->flags & I2C_CLIENT_PEC));
 }
 
-static inline int temp_from_s16(s16 val)
+static ssize_t pec_store(struct device *dev, struct device_attribute *dummy,
+                        const char *buf, size_t count)
 {
-       return val / 32 * 125;
-}
+       struct i2c_client *client = to_i2c_client(dev);
+       long val;
+       int err;
 
-static inline int temp_from_u16(u16 val)
-{
-       return val / 32 * 125;
-}
+       err = kstrtol(buf, 10, &val);
+       if (err < 0)
+               return err;
 
-static s8 temp_to_s8(long val)
-{
-       if (val <= -128000)
-               return -128;
-       if (val >= 127000)
-               return 127;
-       if (val < 0)
-               return (val - 500) / 1000;
-       return (val + 500) / 1000;
-}
+       switch (val) {
+       case 0:
+               client->flags &= ~I2C_CLIENT_PEC;
+               break;
+       case 1:
+               client->flags |= I2C_CLIENT_PEC;
+               break;
+       default:
+               return -EINVAL;
+       }
 
-static u8 temp_to_u8(long val)
-{
-       if (val <= 0)
-               return 0;
-       if (val >= 255000)
-               return 255;
-       return (val + 500) / 1000;
-}
-
-static s16 temp_to_s16(long val)
-{
-       if (val <= -128000)
-               return 0x8000;
-       if (val >= 127875)
-               return 0x7FE0;
-       if (val < 0)
-               return (val - 62) / 125 * 32;
-       return (val + 62) / 125 * 32;
-}
-
-static u8 hyst_to_reg(long val)
-{
-       if (val <= 0)
-               return 0;
-       if (val >= 30500)
-               return 31;
-       return (val + 500) / 1000;
-}
-
-/*
- * ADT7461 in compatibility mode is almost identical to LM90 except that
- * attempts to write values that are outside the range 0 < temp < 127 are
- * treated as the boundary value.
- *
- * ADT7461 in "extended mode" operation uses unsigned integers offset by
- * 64 (e.g., 0 -> -64 degC).  The range is restricted to -64..191 degC.
- */
-static inline int temp_from_u8_adt7461(struct lm90_data *data, u8 val)
-{
-       if (data->flags & LM90_FLAG_ADT7461_EXT)
-               return (val - 64) * 1000;
-       return temp_from_s8(val);
+       return count;
 }
 
-static inline int temp_from_u16_adt7461(struct lm90_data *data, u16 val)
-{
-       if (data->flags & LM90_FLAG_ADT7461_EXT)
-               return (val - 0x4000) / 64 * 250;
-       return temp_from_s16(val);
-}
+static DEVICE_ATTR_RW(pec);
 
-static u8 temp_to_u8_adt7461(struct lm90_data *data, long val)
+static int lm90_temp_get_resolution(struct lm90_data *data, int index)
 {
-       if (data->flags & LM90_FLAG_ADT7461_EXT) {
-               if (val <= -64000)
-                       return 0;
-               if (val >= 191000)
-                       return 0xFF;
-               return (val + 500 + 64000) / 1000;
+       switch (index) {
+       case REMOTE_TEMP:
+               if (data->reg_remote_ext)
+                       return data->resolution;
+               return 8;
+       case REMOTE_OFFSET:
+       case REMOTE2_OFFSET:
+       case REMOTE2_TEMP:
+               return data->resolution;
+       case LOCAL_TEMP:
+               if (data->reg_local_ext)
+                       return data->resolution;
+               return 8;
+       case REMOTE_LOW:
+       case REMOTE_HIGH:
+       case REMOTE2_LOW:
+       case REMOTE2_HIGH:
+               if (data->flags & LM90_HAVE_REM_LIMIT_EXT)
+                       return data->resolution;
+               return 8;
+       default:
+               return 8;
        }
-       if (val <= 0)
-               return 0;
-       if (val >= 127000)
-               return 127;
-       return (val + 500) / 1000;
 }
 
-static u16 temp_to_u16_adt7461(struct lm90_data *data, long val)
+static int lm90_temp_from_reg(u32 flags, u16 regval, u8 resolution)
 {
-       if (data->flags & LM90_FLAG_ADT7461_EXT) {
-               if (val <= -64000)
-                       return 0;
-               if (val >= 191750)
-                       return 0xFFC0;
-               return (val + 64000 + 125) / 250 * 64;
-       }
-       if (val <= 0)
-               return 0;
-       if (val >= 127750)
-               return 0x7FC0;
-       return (val + 125) / 250 * 64;
-}
+       int val;
 
-/* pec used for ADM1032 only */
-static ssize_t pec_show(struct device *dev, struct device_attribute *dummy,
-                       char *buf)
-{
-       struct i2c_client *client = to_i2c_client(dev);
+       if (flags & LM90_HAVE_EXTENDED_TEMP)
+               val = regval - 0x4000;
+       else if (flags & (LM90_HAVE_UNSIGNED_TEMP | LM90_HAVE_EXT_UNSIGNED))
+               val = regval;
+       else
+               val = (s16)regval;
 
-       return sprintf(buf, "%d\n", !!(client->flags & I2C_CLIENT_PEC));
+       return ((val >> (16 - resolution)) * 1000) >> (resolution - 8);
 }
 
-static ssize_t pec_store(struct device *dev, struct device_attribute *dummy,
-                        const char *buf, size_t count)
+static int lm90_get_temp(struct lm90_data *data, int index, int channel)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       long val;
-       int err;
+       int temp = lm90_temp_from_reg(data->flags, data->temp[index],
+                                     lm90_temp_get_resolution(data, index));
 
-       err = kstrtol(buf, 10, &val);
-       if (err < 0)
-               return err;
-
-       switch (val) {
-       case 0:
-               client->flags &= ~I2C_CLIENT_PEC;
-               break;
-       case 1:
-               client->flags |= I2C_CLIENT_PEC;
-               break;
-       default:
-               return -EINVAL;
-       }
+       /* +16 degrees offset for remote temperature on LM99 */
+       if (data->kind == lm99 && channel)
+               temp += 16000;
 
-       return count;
+       return temp;
 }
 
-static DEVICE_ATTR_RW(pec);
-
-static int lm90_get_temp11(struct lm90_data *data, int index)
+static u16 lm90_temp_to_reg(u32 flags, long val, u8 resolution)
 {
-       s16 temp11 = data->temp11[index];
-       int temp;
-
-       if (data->flags & LM90_HAVE_EXTENDED_TEMP)
-               temp = temp_from_u16_adt7461(data, temp11);
-       else if (data->kind == max6646)
-               temp = temp_from_u16(temp11);
-       else
-               temp = temp_from_s16(temp11);
-
-       /* +16 degrees offset for temp2 for the LM99 */
-       if (data->kind == lm99 && index <= 2)
-               temp += 16000;
+       int fraction = resolution > 8 ?
+                       1000 - DIV_ROUND_CLOSEST(1000, BIT(resolution - 8)) : 0;
+
+       if (flags & LM90_HAVE_EXTENDED_TEMP) {
+               val = clamp_val(val, -64000, 191000 + fraction);
+               val += 64000;
+       } else if (flags & LM90_HAVE_EXT_UNSIGNED) {
+               val = clamp_val(val, 0, 255000 + fraction);
+       } else if (flags & LM90_HAVE_UNSIGNED_TEMP) {
+               val = clamp_val(val, 0, 127000 + fraction);
+       } else {
+               val = clamp_val(val, -128000, 127000 + fraction);
+       }
 
-       return temp;
+       return DIV_ROUND_CLOSEST(val << (resolution - 8), 1000) << (16 - resolution);
 }
 
-static int lm90_set_temp11(struct lm90_data *data, int index, long val)
+static int lm90_set_temp(struct lm90_data *data, int index, int channel, long val)
 {
-       static struct reg {
-               u8 high;
-               u8 low;
-       } reg[] = {
-       [REMOTE_LOW] = { LM90_REG_W_REMOTE_LOWH, LM90_REG_W_REMOTE_LOWL },
-       [REMOTE_HIGH] = { LM90_REG_W_REMOTE_HIGHH, LM90_REG_W_REMOTE_HIGHL },
-       [REMOTE_OFFSET] = { LM90_REG_W_REMOTE_OFFSH, LM90_REG_W_REMOTE_OFFSL },
-       [REMOTE2_LOW] = { LM90_REG_W_REMOTE_LOWH, LM90_REG_W_REMOTE_LOWL },
-       [REMOTE2_HIGH] = { LM90_REG_W_REMOTE_HIGHH, LM90_REG_W_REMOTE_HIGHL }
+       static const u8 regs[] = {
+               [LOCAL_LOW] = LM90_REG_LOCAL_LOW,
+               [LOCAL_HIGH] = LM90_REG_LOCAL_HIGH,
+               [LOCAL_CRIT] = LM90_REG_LOCAL_CRIT,
+               [REMOTE_CRIT] = LM90_REG_REMOTE_CRIT,
+               [LOCAL_EMERG] = MAX6659_REG_LOCAL_EMERG,
+               [REMOTE_EMERG] = MAX6659_REG_REMOTE_EMERG,
+               [REMOTE2_CRIT] = LM90_REG_REMOTE_CRIT,
+               [REMOTE2_EMERG] = MAX6659_REG_REMOTE_EMERG,
+               [REMOTE_LOW] = LM90_REG_REMOTE_LOWH,
+               [REMOTE_HIGH] = LM90_REG_REMOTE_HIGHH,
+               [REMOTE2_LOW] = LM90_REG_REMOTE_LOWH,
+               [REMOTE2_HIGH] = LM90_REG_REMOTE_HIGHH,
        };
        struct i2c_client *client = data->client;
-       struct reg *regp = &reg[index];
+       u8 regh = regs[index];
+       u8 regl = 0;
        int err;
 
-       /* +16 degrees offset for temp2 for the LM99 */
-       if (data->kind == lm99 && index <= 2) {
+       if (channel && (data->flags & LM90_HAVE_REM_LIMIT_EXT)) {
+               if (index == REMOTE_LOW || index == REMOTE2_LOW)
+                       regl = LM90_REG_REMOTE_LOWL;
+               else if (index == REMOTE_HIGH || index == REMOTE2_HIGH)
+                       regl = LM90_REG_REMOTE_HIGHL;
+       }
+
+       /* +16 degrees offset for remote temperature on LM99 */
+       if (data->kind == lm99 && channel) {
                /* prevent integer underflow */
                val = max(val, -128000l);
                val -= 16000;
        }
 
-       if (data->flags & LM90_HAVE_EXTENDED_TEMP)
-               data->temp11[index] = temp_to_u16_adt7461(data, val);
-       else if (data->kind == max6646)
-               data->temp11[index] = temp_to_u8(val) << 8;
-       else if (data->flags & LM90_HAVE_REM_LIMIT_EXT)
-               data->temp11[index] = temp_to_s16(val);
-       else
-               data->temp11[index] = temp_to_s8(val) << 8;
+       data->temp[index] = lm90_temp_to_reg(data->flags, val,
+                                            lm90_temp_get_resolution(data, index));
 
-       lm90_select_remote_channel(data, index >= 3);
-       err = i2c_smbus_write_byte_data(client, regp->high,
-                                 data->temp11[index] >> 8);
-       if (err < 0)
-               return err;
-       if (data->flags & LM90_HAVE_REM_LIMIT_EXT)
-               err = i2c_smbus_write_byte_data(client, regp->low,
-                                               data->temp11[index] & 0xff);
+       if (channel > 1)
+               lm90_select_remote_channel(data, true);
+
+       err = lm90_write16(client, regh, regl, data->temp[index]);
+
+       if (channel > 1)
+               lm90_select_remote_channel(data, false);
 
-       lm90_select_remote_channel(data, 0);
        return err;
 }
 
-static int lm90_get_temp8(struct lm90_data *data, int index)
+static int lm90_get_temphyst(struct lm90_data *data, int index, int channel)
 {
-       s8 temp8 = data->temp8[index];
-       int temp;
+       int temp = lm90_get_temp(data, index, channel);
 
-       if (data->flags & LM90_HAVE_EXTENDED_TEMP)
-               temp = temp_from_u8_adt7461(data, temp8);
-       else if (data->kind == max6646)
-               temp = temp_from_u8(temp8);
-       else
-               temp = temp_from_s8(temp8);
-
-       /* +16 degrees offset for temp2 for the LM99 */
-       if (data->kind == lm99 && index == 3)
-               temp += 16000;
-
-       return temp;
+       return temp - data->temp_hyst * 1000;
 }
 
-static int lm90_set_temp8(struct lm90_data *data, int index, long val)
+static int lm90_set_temphyst(struct lm90_data *data, long val)
 {
-       static const u8 reg[TEMP8_REG_NUM] = {
-               LM90_REG_W_LOCAL_LOW,
-               LM90_REG_W_LOCAL_HIGH,
-               LM90_REG_W_LOCAL_CRIT,
-               LM90_REG_W_REMOTE_CRIT,
-               MAX6659_REG_W_LOCAL_EMERG,
-               MAX6659_REG_W_REMOTE_EMERG,
-               LM90_REG_W_REMOTE_CRIT,
-               MAX6659_REG_W_REMOTE_EMERG,
-       };
-       struct i2c_client *client = data->client;
-       int err;
+       int temp = lm90_get_temp(data, LOCAL_CRIT, 0);
 
-       /* +16 degrees offset for temp2 for the LM99 */
-       if (data->kind == lm99 && index == 3) {
-               /* prevent integer underflow */
-               val = max(val, -128000l);
-               val -= 16000;
-       }
+       /* prevent integer overflow/underflow */
+       val = clamp_val(val, -128000l, 255000l);
+       data->temp_hyst = clamp_val(DIV_ROUND_CLOSEST(temp - val, 1000), 0, 31);
 
-       if (data->flags & LM90_HAVE_EXTENDED_TEMP)
-               data->temp8[index] = temp_to_u8_adt7461(data, val);
-       else if (data->kind == max6646)
-               data->temp8[index] = temp_to_u8(val);
-       else
-               data->temp8[index] = temp_to_s8(val);
+       return lm90_write_reg(data->client, LM90_REG_TCRIT_HYST, data->temp_hyst);
+}
 
-       lm90_select_remote_channel(data, index >= 6);
-       err = i2c_smbus_write_byte_data(client, reg[index], data->temp8[index]);
-       lm90_select_remote_channel(data, 0);
+static int lm90_get_temp_offset(struct lm90_data *data, int index)
+{
+       int res = lm90_temp_get_resolution(data, index);
 
-       return err;
+       return lm90_temp_from_reg(0, data->temp[index], res);
 }
 
-static int lm90_get_temphyst(struct lm90_data *data, int index)
+static int lm90_set_temp_offset(struct lm90_data *data, int index, int channel, long val)
 {
-       int temp;
+       int err;
 
-       if (data->flags & LM90_HAVE_EXTENDED_TEMP)
-               temp = temp_from_u8_adt7461(data, data->temp8[index]);
-       else if (data->kind == max6646)
-               temp = temp_from_u8(data->temp8[index]);
-       else
-               temp = temp_from_s8(data->temp8[index]);
+       val = lm90_temp_to_reg(0, val, lm90_temp_get_resolution(data, index));
 
-       /* +16 degrees offset for temp2 for the LM99 */
-       if (data->kind == lm99 && index == 3)
-               temp += 16000;
+       /* For ADT7481 we can use the same registers for remote channel 1 and 2 */
+       if (channel > 1)
+               lm90_select_remote_channel(data, true);
 
-       return temp - temp_from_s8(data->temp_hyst);
-}
+       err = lm90_write16(data->client, LM90_REG_REMOTE_OFFSH, LM90_REG_REMOTE_OFFSL, val);
 
-static int lm90_set_temphyst(struct lm90_data *data, long val)
-{
-       struct i2c_client *client = data->client;
-       int temp;
-       int err;
+       if (channel > 1)
+               lm90_select_remote_channel(data, false);
 
-       if (data->flags & LM90_HAVE_EXTENDED_TEMP)
-               temp = temp_from_u8_adt7461(data, data->temp8[LOCAL_CRIT]);
-       else if (data->kind == max6646)
-               temp = temp_from_u8(data->temp8[LOCAL_CRIT]);
-       else
-               temp = temp_from_s8(data->temp8[LOCAL_CRIT]);
+       if (err)
+               return err;
 
-       /* prevent integer overflow/underflow */
-       val = clamp_val(val, -128000l, 255000l);
+       data->temp[index] = val;
 
-       data->temp_hyst = hyst_to_reg(temp - val);
-       err = i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST,
-                                       data->temp_hyst);
-       return err;
+       return 0;
 }
 
-static const u8 lm90_temp_index[3] = {
+static const u8 lm90_temp_index[MAX_CHANNELS] = {
        LOCAL_TEMP, REMOTE_TEMP, REMOTE2_TEMP
 };
 
-static const u8 lm90_temp_min_index[3] = {
+static const u8 lm90_temp_min_index[MAX_CHANNELS] = {
        LOCAL_LOW, REMOTE_LOW, REMOTE2_LOW
 };
 
-static const u8 lm90_temp_max_index[3] = {
+static const u8 lm90_temp_max_index[MAX_CHANNELS] = {
        LOCAL_HIGH, REMOTE_HIGH, REMOTE2_HIGH
 };
 
-static const u8 lm90_temp_crit_index[3] = {
+static const u8 lm90_temp_crit_index[MAX_CHANNELS] = {
        LOCAL_CRIT, REMOTE_CRIT, REMOTE2_CRIT
 };
 
-static const u8 lm90_temp_emerg_index[3] = {
+static const u8 lm90_temp_emerg_index[MAX_CHANNELS] = {
        LOCAL_EMERG, REMOTE_EMERG, REMOTE2_EMERG
 };
 
-static const u8 lm90_min_alarm_bits[3] = { 5, 3, 11 };
-static const u8 lm90_max_alarm_bits[3] = { 6, 4, 12 };
-static const u8 lm90_crit_alarm_bits[3] = { 0, 1, 9 };
-static const u8 lm90_crit_alarm_bits_swapped[3] = { 1, 0, 9 };
-static const u8 lm90_emergency_alarm_bits[3] = { 15, 13, 14 };
-static const u8 lm90_fault_bits[3] = { 0, 2, 10 };
+static const s8 lm90_temp_offset_index[MAX_CHANNELS] = {
+       -1, REMOTE_OFFSET, REMOTE2_OFFSET
+};
+
+static const u16 lm90_min_alarm_bits[MAX_CHANNELS] = { BIT(5), BIT(3), BIT(11) };
+static const u16 lm90_max_alarm_bits[MAX_CHANNELS] = { BIT(6), BIT(4), BIT(12) };
+static const u16 lm90_crit_alarm_bits[MAX_CHANNELS] = { BIT(0), BIT(1), BIT(9) };
+static const u16 lm90_crit_alarm_bits_swapped[MAX_CHANNELS] = { BIT(1), BIT(0), BIT(9) };
+static const u16 lm90_emergency_alarm_bits[MAX_CHANNELS] = { BIT(15), BIT(13), BIT(14) };
+static const u16 lm90_fault_bits[MAX_CHANNELS] = { BIT(0), BIT(2), BIT(10) };
 
 static int lm90_temp_read(struct device *dev, u32 attr, int channel, long *val)
 {
        struct lm90_data *data = dev_get_drvdata(dev);
        int err;
+       u16 bit;
 
        mutex_lock(&data->update_lock);
        err = lm90_update_device(dev);
@@ -1222,56 +1519,57 @@ static int lm90_temp_read(struct device *dev, u32 attr, int channel, long *val)
 
        switch (attr) {
        case hwmon_temp_input:
-               *val = lm90_get_temp11(data, lm90_temp_index[channel]);
+               *val = lm90_get_temp(data, lm90_temp_index[channel], channel);
                break;
        case hwmon_temp_min_alarm:
-               *val = (data->alarms >> lm90_min_alarm_bits[channel]) & 1;
-               break;
        case hwmon_temp_max_alarm:
-               *val = (data->alarms >> lm90_max_alarm_bits[channel]) & 1;
-               break;
        case hwmon_temp_crit_alarm:
-               if (data->flags & LM90_HAVE_CRIT_ALRM_SWP)
-                       *val = (data->alarms >> lm90_crit_alarm_bits_swapped[channel]) & 1;
-               else
-                       *val = (data->alarms >> lm90_crit_alarm_bits[channel]) & 1;
-               break;
        case hwmon_temp_emergency_alarm:
-               *val = (data->alarms >> lm90_emergency_alarm_bits[channel]) & 1;
-               break;
        case hwmon_temp_fault:
-               *val = (data->alarms >> lm90_fault_bits[channel]) & 1;
+               switch (attr) {
+               case hwmon_temp_min_alarm:
+                       bit = lm90_min_alarm_bits[channel];
+                       break;
+               case hwmon_temp_max_alarm:
+                       bit = lm90_max_alarm_bits[channel];
+                       break;
+               case hwmon_temp_crit_alarm:
+                       if (data->flags & LM90_HAVE_CRIT_ALRM_SWP)
+                               bit = lm90_crit_alarm_bits_swapped[channel];
+                       else
+                               bit = lm90_crit_alarm_bits[channel];
+                       break;
+               case hwmon_temp_emergency_alarm:
+                       bit = lm90_emergency_alarm_bits[channel];
+                       break;
+               case hwmon_temp_fault:
+                       bit = lm90_fault_bits[channel];
+                       break;
+               }
+               *val = !!(data->alarms & bit);
+               data->alarms &= ~bit;
+               data->alarms |= data->current_alarms;
                break;
        case hwmon_temp_min:
-               if (channel == 0)
-                       *val = lm90_get_temp8(data,
-                                             lm90_temp_min_index[channel]);
-               else
-                       *val = lm90_get_temp11(data,
-                                              lm90_temp_min_index[channel]);
+               *val = lm90_get_temp(data, lm90_temp_min_index[channel], channel);
                break;
        case hwmon_temp_max:
-               if (channel == 0)
-                       *val = lm90_get_temp8(data,
-                                             lm90_temp_max_index[channel]);
-               else
-                       *val = lm90_get_temp11(data,
-                                              lm90_temp_max_index[channel]);
+               *val = lm90_get_temp(data, lm90_temp_max_index[channel], channel);
                break;
        case hwmon_temp_crit:
-               *val = lm90_get_temp8(data, lm90_temp_crit_index[channel]);
+               *val = lm90_get_temp(data, lm90_temp_crit_index[channel], channel);
                break;
        case hwmon_temp_crit_hyst:
-               *val = lm90_get_temphyst(data, lm90_temp_crit_index[channel]);
+               *val = lm90_get_temphyst(data, lm90_temp_crit_index[channel], channel);
                break;
        case hwmon_temp_emergency:
-               *val = lm90_get_temp8(data, lm90_temp_emerg_index[channel]);
+               *val = lm90_get_temp(data, lm90_temp_emerg_index[channel], channel);
                break;
        case hwmon_temp_emergency_hyst:
-               *val = lm90_get_temphyst(data, lm90_temp_emerg_index[channel]);
+               *val = lm90_get_temphyst(data, lm90_temp_emerg_index[channel], channel);
                break;
        case hwmon_temp_offset:
-               *val = lm90_get_temp11(data, REMOTE_OFFSET);
+               *val = lm90_get_temp_offset(data, lm90_temp_offset_index[channel]);
                break;
        default:
                return -EOPNOTSUPP;
@@ -1292,36 +1590,27 @@ static int lm90_temp_write(struct device *dev, u32 attr, int channel, long val)
 
        switch (attr) {
        case hwmon_temp_min:
-               if (channel == 0)
-                       err = lm90_set_temp8(data,
-                                             lm90_temp_min_index[channel],
-                                             val);
-               else
-                       err = lm90_set_temp11(data,
-                                             lm90_temp_min_index[channel],
-                                             val);
+               err = lm90_set_temp(data, lm90_temp_min_index[channel],
+                                   channel, val);
                break;
        case hwmon_temp_max:
-               if (channel == 0)
-                       err = lm90_set_temp8(data,
-                                            lm90_temp_max_index[channel],
-                                            val);
-               else
-                       err = lm90_set_temp11(data,
-                                             lm90_temp_max_index[channel],
-                                             val);
+               err = lm90_set_temp(data, lm90_temp_max_index[channel],
+                                   channel, val);
                break;
        case hwmon_temp_crit:
-               err = lm90_set_temp8(data, lm90_temp_crit_index[channel], val);
+               err = lm90_set_temp(data, lm90_temp_crit_index[channel],
+                                   channel, val);
                break;
        case hwmon_temp_crit_hyst:
                err = lm90_set_temphyst(data, val);
                break;
        case hwmon_temp_emergency:
-               err = lm90_set_temp8(data, lm90_temp_emerg_index[channel], val);
+               err = lm90_set_temp(data, lm90_temp_emerg_index[channel],
+                                   channel, val);
                break;
        case hwmon_temp_offset:
-               err = lm90_set_temp11(data, REMOTE_OFFSET, val);
+               err = lm90_set_temp_offset(data, lm90_temp_offset_index[channel],
+                                          channel, val);
                break;
        default:
                err = -EOPNOTSUPP;
@@ -1343,6 +1632,7 @@ static umode_t lm90_temp_is_visible(const void *data, u32 attr, int channel)
        case hwmon_temp_emergency_alarm:
        case hwmon_temp_emergency_hyst:
        case hwmon_temp_fault:
+       case hwmon_temp_label:
                return 0444;
        case hwmon_temp_min:
        case hwmon_temp_max:
@@ -1377,6 +1667,28 @@ static int lm90_chip_read(struct device *dev, u32 attr, int channel, long *val)
        case hwmon_chip_alarms:
                *val = data->alarms;
                break;
+       case hwmon_chip_temp_samples:
+               if (data->faultqueue_mask) {
+                       *val = (data->config & data->faultqueue_mask) ?
+                               data->faultqueue_depth : 1;
+               } else {
+                       switch (data->conalert & 0x0e) {
+                       case 0x0:
+                       default:
+                               *val = 1;
+                               break;
+                       case 0x2:
+                               *val = 2;
+                               break;
+                       case 0x6:
+                               *val = 3;
+                               break;
+                       case 0xe:
+                               *val = 4;
+                               break;
+                       }
+               }
+               break;
        default:
                return -EOPNOTSUPP;
        }
@@ -1401,6 +1713,9 @@ static int lm90_chip_write(struct device *dev, u32 attr, int channel, long val)
                err = lm90_set_convrate(client, data,
                                        clamp_val(val, 0, 100000));
                break;
+       case hwmon_chip_temp_samples:
+               err = lm90_set_faultqueue(client, data, clamp_val(val, 1, 4));
+               break;
        default:
                err = -EOPNOTSUPP;
                break;
@@ -1415,6 +1730,7 @@ static umode_t lm90_chip_is_visible(const void *data, u32 attr, int channel)
 {
        switch (attr) {
        case hwmon_chip_update_interval:
+       case hwmon_chip_temp_samples:
                return 0644;
        case hwmon_chip_alarms:
                return 0444;
@@ -1436,6 +1752,16 @@ static int lm90_read(struct device *dev, enum hwmon_sensor_types type,
        }
 }
 
+static int lm90_read_string(struct device *dev, enum hwmon_sensor_types type,
+                           u32 attr, int channel, const char **str)
+{
+       struct lm90_data *data = dev_get_drvdata(dev);
+
+       *str = data->channel_label[channel];
+
+       return 0;
+}
+
 static int lm90_write(struct device *dev, enum hwmon_sensor_types type,
                      u32 attr, int channel, long val)
 {
@@ -1462,125 +1788,359 @@ static umode_t lm90_is_visible(const void *data, enum hwmon_sensor_types type,
        }
 }
 
-/* Return 0 if detection is successful, -ENODEV otherwise */
-static int lm90_detect(struct i2c_client *client,
-                      struct i2c_board_info *info)
+static const char *lm90_detect_lm84(struct i2c_client *client)
 {
-       struct i2c_adapter *adapter = client->adapter;
+       static const u8 regs[] = {
+               LM90_REG_STATUS, LM90_REG_LOCAL_TEMP, LM90_REG_LOCAL_HIGH,
+               LM90_REG_REMOTE_TEMPH, LM90_REG_REMOTE_HIGHH
+       };
+       int status = i2c_smbus_read_byte_data(client, LM90_REG_STATUS);
+       int reg1, reg2, reg3, reg4;
+       bool nonzero = false;
+       u8 ff = 0xff;
+       int i;
+
+       if (status < 0 || (status & 0xab))
+               return NULL;
+
+       /*
+        * For LM84, undefined registers return the most recent value.
+        * Repeat several times, each time checking against a different
+        * (presumably) existing register.
+        */
+       for (i = 0; i < ARRAY_SIZE(regs); i++) {
+               reg1 = i2c_smbus_read_byte_data(client, regs[i]);
+               reg2 = i2c_smbus_read_byte_data(client, LM90_REG_REMOTE_TEMPL);
+               reg3 = i2c_smbus_read_byte_data(client, LM90_REG_LOCAL_LOW);
+               reg4 = i2c_smbus_read_byte_data(client, LM90_REG_REMOTE_LOWH);
+
+               if (reg1 < 0)
+                       return NULL;
+
+               /* If any register has a different value, this is not an LM84 */
+               if (reg2 != reg1 || reg3 != reg1 || reg4 != reg1)
+                       return NULL;
+
+               nonzero |= reg1 || reg2 || reg3 || reg4;
+               ff &= reg1;
+       }
+       /*
+        * If all registers always returned 0 or 0xff, all bets are off,
+        * and we can not make any predictions about the chip type.
+        */
+       return nonzero && ff != 0xff ? "lm84" : NULL;
+}
+
+static const char *lm90_detect_max1617(struct i2c_client *client, int config1)
+{
+       int status = i2c_smbus_read_byte_data(client, LM90_REG_STATUS);
+       int llo, rlo, lhi, rhi;
+
+       if (status < 0 || (status & 0x03))
+               return NULL;
+
+       if (config1 & 0x3f)
+               return NULL;
+
+       /*
+        * Fail if unsupported registers return anything but 0xff.
+        * The calling code already checked man_id and chip_id.
+        * A byte read operation repeats the most recent read operation
+        * and should also return 0xff.
+        */
+       if (i2c_smbus_read_byte_data(client, LM90_REG_REMOTE_TEMPL) != 0xff ||
+           i2c_smbus_read_byte_data(client, MAX6657_REG_LOCAL_TEMPL) != 0xff ||
+           i2c_smbus_read_byte_data(client, LM90_REG_REMOTE_LOWL) != 0xff ||
+           i2c_smbus_read_byte(client) != 0xff)
+               return NULL;
+
+       llo = i2c_smbus_read_byte_data(client, LM90_REG_LOCAL_LOW);
+       rlo = i2c_smbus_read_byte_data(client, LM90_REG_REMOTE_LOWH);
+
+       lhi = i2c_smbus_read_byte_data(client, LM90_REG_LOCAL_HIGH);
+       rhi = i2c_smbus_read_byte_data(client, LM90_REG_REMOTE_HIGHH);
+
+       if (llo < 0 || rlo < 0)
+               return NULL;
+
+       /*
+        * A byte read operation repeats the most recent read and should
+        * return the same value.
+        */
+       if (i2c_smbus_read_byte(client) != rhi)
+               return NULL;
+
+       /*
+        * The following two checks are marginal since the checked values
+        * are strictly speaking valid.
+        */
+
+       /* fail for negative high limits; this also catches read errors */
+       if ((s8)lhi < 0 || (s8)rhi < 0)
+               return NULL;
+
+       /* fail if low limits are larger than or equal to high limits */
+       if ((s8)llo >= lhi || (s8)rlo >= rhi)
+               return NULL;
+
+       if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+               /*
+                * Word read operations return 0xff in second byte
+                */
+               if (i2c_smbus_read_word_data(client, LM90_REG_REMOTE_TEMPL) !=
+                                               0xffff)
+                       return NULL;
+               if (i2c_smbus_read_word_data(client, LM90_REG_CONFIG1) !=
+                                               (config1 | 0xff00))
+                       return NULL;
+               if (i2c_smbus_read_word_data(client, LM90_REG_LOCAL_HIGH) !=
+                                               (lhi | 0xff00))
+                       return NULL;
+       }
+
+       return "max1617";
+}
+
+static const char *lm90_detect_national(struct i2c_client *client, int chip_id,
+                                       int config1, int convrate)
+{
+       int config2 = i2c_smbus_read_byte_data(client, LM90_REG_CONFIG2);
        int address = client->addr;
        const char *name = NULL;
-       int man_id, chip_id, config1, config2, convrate;
 
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return -ENODEV;
+       if (config2 < 0)
+               return NULL;
 
-       /* detection and identification */
-       man_id = i2c_smbus_read_byte_data(client, LM90_REG_R_MAN_ID);
-       chip_id = i2c_smbus_read_byte_data(client, LM90_REG_R_CHIP_ID);
-       config1 = i2c_smbus_read_byte_data(client, LM90_REG_R_CONFIG1);
-       convrate = i2c_smbus_read_byte_data(client, LM90_REG_R_CONVRATE);
-       if (man_id < 0 || chip_id < 0 || config1 < 0 || convrate < 0)
-               return -ENODEV;
+       if ((config1 & 0x2a) || (config2 & 0xf8) || convrate > 0x09)
+               return NULL;
 
-       if (man_id == 0x01 || man_id == 0x5C || man_id == 0xA1) {
-               config2 = i2c_smbus_read_byte_data(client, LM90_REG_R_CONFIG2);
-               if (config2 < 0)
-                       return -ENODEV;
+       if (address != 0x4c && address != 0x4d)
+               return NULL;
+
+       switch (chip_id & 0xf0) {
+       case 0x10:      /* LM86 */
+               if (address == 0x4c)
+                       name = "lm86";
+               break;
+       case 0x20:      /* LM90 */
+               if (address == 0x4c)
+                       name = "lm90";
+               break;
+       case 0x30:      /* LM89/LM99 */
+               name = "lm99";  /* detect LM89 as LM99 */
+               break;
+       default:
+               break;
        }
 
-       if ((address == 0x4C || address == 0x4D)
-        && man_id == 0x01) { /* National Semiconductor */
-               if ((config1 & 0x2A) == 0x00
-                && (config2 & 0xF8) == 0x00
-                && convrate <= 0x09) {
-                       if (address == 0x4C
-                        && (chip_id & 0xF0) == 0x20) { /* LM90 */
-                               name = "lm90";
-                       } else
-                       if ((chip_id & 0xF0) == 0x30) { /* LM89/LM99 */
-                               name = "lm99";
-                               dev_info(&adapter->dev,
-                                        "Assuming LM99 chip at 0x%02x\n",
-                                        address);
-                               dev_info(&adapter->dev,
-                                        "If it is an LM89, instantiate it "
-                                        "with the new_device sysfs "
-                                        "interface\n");
-                       } else
-                       if (address == 0x4C
-                        && (chip_id & 0xF0) == 0x10) { /* LM86 */
-                               name = "lm86";
-                       }
-               }
-       } else
-       if ((address == 0x4C || address == 0x4D)
-        && man_id == 0x41) { /* Analog Devices */
-               if ((chip_id & 0xF0) == 0x40 /* ADM1032 */
-                && (config1 & 0x3F) == 0x00
-                && convrate <= 0x0A) {
+       return name;
+}
+
+static const char *lm90_detect_on(struct i2c_client *client, int chip_id, int config1,
+                                 int convrate)
+{
+       int address = client->addr;
+       const char *name = NULL;
+
+       switch (chip_id) {
+       case 0xca:              /* NCT218 */
+               if ((address == 0x4c || address == 0x4d) && !(config1 & 0x1b) &&
+                   convrate <= 0x0a)
+                       name = "nct218";
+               break;
+       default:
+               break;
+       }
+       return name;
+}
+
+static const char *lm90_detect_analog(struct i2c_client *client, bool common_address,
+                                     int chip_id, int config1, int convrate)
+{
+       int status = i2c_smbus_read_byte_data(client, LM90_REG_STATUS);
+       int config2 = i2c_smbus_read_byte_data(client, ADT7481_REG_CONFIG2);
+       int man_id2 = i2c_smbus_read_byte_data(client, ADT7481_REG_MAN_ID);
+       int chip_id2 = i2c_smbus_read_byte_data(client, ADT7481_REG_CHIP_ID);
+       int address = client->addr;
+       const char *name = NULL;
+
+       if (status < 0 || config2 < 0 || man_id2 < 0 || chip_id2 < 0)
+               return NULL;
+
+       /*
+        * The following chips should be detected by this function. Known
+        * register values are listed. Registers 0x3d .. 0x3e are undocumented
+        * for most of the chips, yet appear to return a well defined value.
+        * Register 0xff is undocumented for some of the chips. Register 0x3f
+        * is undocumented for all chips, but also returns a well defined value.
+        * Values are as reported from real chips unless mentioned otherwise.
+        * The code below checks values for registers 0x3d, 0x3e, and 0xff,
+        * but not for register 0x3f.
+        *
+        * Chip                 Register
+        *              3d      3e      3f      fe      ff      Notes
+        * ----------------------------------------------------------
+        * adm1020      00      00      00      41      39
+        * adm1021      00      00      00      41      03
+        * adm1021a     00      00      00      41      3c
+        * adm1023      00      00      00      41      3c      same as adm1021a
+        * adm1032      00      00      00      41      42
+        *
+        * adt7421      21      41      04      41      04
+        * adt7461      00      00      00      41      51
+        * adt7461a     61      41      05      41      57
+        * adt7481      81      41      02      41      62
+        * adt7482      -       -       -       41      65      datasheet
+        *              82      41      05      41      75      real chip
+        * adt7483      83      41      04      41      94
+        *
+        * nct72        61      41      07      41      55
+        * nct210       00      00      00      41      3f
+        * nct214       61      41      08      41      5a
+        * nct1008      -       -       -       41      57      datasheet rev. 3
+        *              61      41      06      41      54      real chip
+        *
+        * nvt210       -       -       -       41      -       datasheet
+        * nvt211       -       -       -       41      -       datasheet
+        */
+       switch (chip_id) {
+       case 0x00 ... 0x03:     /* ADM1021 */
+       case 0x05 ... 0x0f:
+               if (man_id2 == 0x00 && chip_id2 == 0x00 && common_address &&
+                   !(status & 0x03) && !(config1 & 0x3f) && !(convrate & 0xf8))
+                       name = "adm1021";
+               break;
+       case 0x04:              /* ADT7421 (undocumented) */
+               if (man_id2 == 0x41 && chip_id2 == 0x21 &&
+                   (address == 0x4c || address == 0x4d) &&
+                   (config1 & 0x0b) == 0x08 && convrate <= 0x0a)
+                       name = "adt7421";
+               break;
+       case 0x30 ... 0x38:     /* ADM1021A, ADM1023 */
+       case 0x3a ... 0x3e:
+               /*
+                * ADM1021A and compatible chips will be mis-detected as
+                * ADM1023. Chips labeled 'ADM1021A' and 'ADM1023' were both
+                * found to have a Chip ID of 0x3c.
+                * ADM1021A does not officially support low byte registers
+                * (0x12 .. 0x14), but a chip labeled ADM1021A does support it.
+                * Official support for the temperature offset high byte
+                * register (0x11) was added to revision F of the ADM1021A
+                * datasheet.
+                * It is currently unknown if there is a means to distinguish
+                * ADM1021A from ADM1023, and/or if revisions of ADM1021A exist
+                * which differ in functionality from ADM1023.
+                */
+               if (man_id2 == 0x00 && chip_id2 == 0x00 && common_address &&
+                   !(status & 0x03) && !(config1 & 0x3f) && !(convrate & 0xf8))
+                       name = "adm1023";
+               break;
+       case 0x39:              /* ADM1020 (undocumented) */
+               if (man_id2 == 0x00 && chip_id2 == 0x00 &&
+                   (address == 0x4c || address == 0x4d || address == 0x4e) &&
+                   !(status & 0x03) && !(config1 & 0x3f) && !(convrate & 0xf8))
+                       name = "adm1020";
+               break;
+       case 0x3f:              /* NCT210 */
+               if (man_id2 == 0x00 && chip_id2 == 0x00 && common_address &&
+                   !(status & 0x03) && !(config1 & 0x3f) && !(convrate & 0xf8))
+                       name = "nct210";
+               break;
+       case 0x40 ... 0x4f:     /* ADM1032 */
+               if (man_id2 == 0x00 && chip_id2 == 0x00 &&
+                   (address == 0x4c || address == 0x4d) && !(config1 & 0x3f) &&
+                   convrate <= 0x0a)
                        name = "adm1032";
-                       /*
-                        * The ADM1032 supports PEC, but only if combined
-                        * transactions are not used.
-                        */
-                       if (i2c_check_functionality(adapter,
-                                                   I2C_FUNC_SMBUS_BYTE))
-                               info->flags |= I2C_CLIENT_PEC;
-               } else
-               if (chip_id == 0x51 /* ADT7461 */
-                && (config1 & 0x1B) == 0x00
-                && convrate <= 0x0A) {
+               break;
+       case 0x51:      /* ADT7461 */
+               if (man_id2 == 0x00 && chip_id2 == 0x00 &&
+                   (address == 0x4c || address == 0x4d) && !(config1 & 0x1b) &&
+                   convrate <= 0x0a)
                        name = "adt7461";
-               } else
-               if (chip_id == 0x57 /* ADT7461A, NCT1008 */
-                && (config1 & 0x1B) == 0x00
-                && convrate <= 0x0A) {
+               break;
+       case 0x54:      /* NCT1008 */
+               if (man_id2 == 0x41 && chip_id2 == 0x61 &&
+                   (address == 0x4c || address == 0x4d) && !(config1 & 0x1b) &&
+                   convrate <= 0x0a)
+                       name = "nct1008";
+               break;
+       case 0x55:      /* NCT72 */
+               if (man_id2 == 0x41 && chip_id2 == 0x61 &&
+                   (address == 0x4c || address == 0x4d) && !(config1 & 0x1b) &&
+                   convrate <= 0x0a)
+                       name = "nct72";
+               break;
+       case 0x57:      /* ADT7461A, NCT1008 (datasheet rev. 3) */
+               if (man_id2 == 0x41 && chip_id2 == 0x61 &&
+                   (address == 0x4c || address == 0x4d) && !(config1 & 0x1b) &&
+                   convrate <= 0x0a)
                        name = "adt7461a";
+               break;
+       case 0x5a:      /* NCT214 */
+               if (man_id2 == 0x41 && chip_id2 == 0x61 &&
+                   common_address && !(config1 & 0x1b) && convrate <= 0x0a)
+                       name = "nct214";
+               break;
+       case 0x62:      /* ADT7481, undocumented */
+               if (man_id2 == 0x41 && chip_id2 == 0x81 &&
+                   (address == 0x4b || address == 0x4c) && !(config1 & 0x10) &&
+                   !(config2 & 0x7f) && (convrate & 0x0f) <= 0x0b) {
+                       name = "adt7481";
                }
-       } else
-       if (man_id == 0x4D) { /* Maxim */
-               int emerg, emerg2, status2;
+               break;
+       case 0x65:      /* ADT7482, datasheet */
+       case 0x75:      /* ADT7482, real chip */
+               if (man_id2 == 0x41 && chip_id2 == 0x82 &&
+                   address == 0x4c && !(config1 & 0x10) && !(config2 & 0x7f) &&
+                   convrate <= 0x0a)
+                       name = "adt7482";
+               break;
+       case 0x94:      /* ADT7483 */
+               if (man_id2 == 0x41 && chip_id2 == 0x83 &&
+                   common_address &&
+                   ((address >= 0x18 && address <= 0x1a) ||
+                    (address >= 0x29 && address <= 0x2b) ||
+                    (address >= 0x4c && address <= 0x4e)) &&
+                   !(config1 & 0x10) && !(config2 & 0x7f) && convrate <= 0x0a)
+                       name = "adt7483a";
+               break;
+       default:
+               break;
+       }
+
+       return name;
+}
+
+static const char *lm90_detect_maxim(struct i2c_client *client, bool common_address,
+                                    int chip_id, int config1, int convrate)
+{
+       int man_id, emerg, emerg2, status2;
+       int address = client->addr;
+       const char *name = NULL;
+
+       switch (chip_id) {
+       case 0x01:
+               if (!common_address)
+                       break;
 
                /*
-                * We read MAX6659_REG_R_REMOTE_EMERG twice, and re-read
-                * LM90_REG_R_MAN_ID in between. If MAX6659_REG_R_REMOTE_EMERG
+                * We read MAX6659_REG_REMOTE_EMERG twice, and re-read
+                * LM90_REG_MAN_ID in between. If MAX6659_REG_REMOTE_EMERG
                 * exists, both readings will reflect the same value. Otherwise,
                 * the readings will be different.
                 */
                emerg = i2c_smbus_read_byte_data(client,
-                                                MAX6659_REG_R_REMOTE_EMERG);
+                                                MAX6659_REG_REMOTE_EMERG);
                man_id = i2c_smbus_read_byte_data(client,
-                                                 LM90_REG_R_MAN_ID);
+                                                 LM90_REG_MAN_ID);
                emerg2 = i2c_smbus_read_byte_data(client,
-                                                 MAX6659_REG_R_REMOTE_EMERG);
+                                                 MAX6659_REG_REMOTE_EMERG);
                status2 = i2c_smbus_read_byte_data(client,
-                                                  MAX6696_REG_R_STATUS2);
+                                                  MAX6696_REG_STATUS2);
                if (emerg < 0 || man_id < 0 || emerg2 < 0 || status2 < 0)
-                       return -ENODEV;
+                       return NULL;
 
                /*
-                * The MAX6657, MAX6658 and MAX6659 do NOT have a chip_id
-                * register. Reading from that address will return the last
-                * read value, which in our case is those of the man_id
-                * register. Likewise, the config1 register seems to lack a
-                * low nibble, so the value will be those of the previous
-                * read, so in our case those of the man_id register.
-                * MAX6659 has a third set of upper temperature limit registers.
-                * Those registers also return values on MAX6657 and MAX6658,
-                * thus the only way to detect MAX6659 is by its address.
-                * For this reason it will be mis-detected as MAX6657 if its
-                * address is 0x4C.
-                */
-               if (chip_id == man_id
-                && (address == 0x4C || address == 0x4D || address == 0x4E)
-                && (config1 & 0x1F) == (man_id & 0x0F)
-                && convrate <= 0x09) {
-                       if (address == 0x4C)
-                               name = "max6657";
-                       else
-                               name = "max6659";
-               } else
-               /*
                 * Even though MAX6695 and MAX6696 do not have a chip ID
                 * register, reading it returns 0x01. Bit 4 of the config1
                 * register is unused and should return zero when read. Bit 0 of
@@ -1591,90 +2151,288 @@ static int lm90_detect(struct i2c_client *client,
                 * limit registers. We can detect those chips by checking if
                 * one of those registers exists.
                 */
-               if (chip_id == 0x01
-                && (config1 & 0x10) == 0x00
-                && (status2 & 0x01) == 0x00
-                && emerg == emerg2
-                && convrate <= 0x07) {
+               if (!(config1 & 0x10) && !(status2 & 0x01) && emerg == emerg2 &&
+                   convrate <= 0x07)
                        name = "max6696";
-               } else
                /*
                 * The chip_id register of the MAX6680 and MAX6681 holds the
                 * revision of the chip. The lowest bit of the config1 register
                 * is unused and should return zero when read, so should the
-                * second to last bit of config1 (software reset).
+                * second to last bit of config1 (software reset). Register
+                * address 0x12 (LM90_REG_REMOTE_OFFSL) exists for this chip and
+                * should differ from emerg2, and emerg2 should match man_id
+                * since it does not exist.
                 */
-               if (chip_id == 0x01
-                && (config1 & 0x03) == 0x00
-                && convrate <= 0x07) {
+               else if (!(config1 & 0x03) && convrate <= 0x07 &&
+                        emerg2 == man_id && emerg2 != status2)
                        name = "max6680";
-               } else
                /*
-                * The chip_id register of the MAX6646/6647/6649 holds the
-                * revision of the chip. The lowest 6 bits of the config1
-                * register are unused and should return zero when read.
+                * MAX1617A does not have any extended registers (register
+                * address 0x10 or higher) except for manufacturer and
+                * device ID registers. Unlike other chips of this series,
+                * unsupported registers were observed to return a fixed value
+                * of 0x01.
+                * Note: Multiple chips with different markings labeled as
+                * "MAX1617" (no "A") were observed to report manufacturer ID
+                * 0x4d and device ID 0x01. It is unknown if other variants of
+                * MAX1617/MAX617A with different behavior exist. The detection
+                * code below works for those chips.
                 */
-               if (chip_id == 0x59
-                && (config1 & 0x3f) == 0x00
-                && convrate <= 0x07) {
-                       name = "max6646";
-               } else
+               else if (!(config1 & 0x03f) && convrate <= 0x07 &&
+                        emerg == 0x01 && emerg2 == 0x01 && status2 == 0x01)
+                       name = "max1617";
+               break;
+       case 0x08:
                /*
                 * The chip_id of the MAX6654 holds the revision of the chip.
                 * The lowest 3 bits of the config1 register are unused and
                 * should return zero when read.
                 */
-               if (chip_id == 0x08
-                && (config1 & 0x07) == 0x00
-                && convrate <= 0x07) {
+               if (common_address && !(config1 & 0x07) && convrate <= 0x07)
                        name = "max6654";
+               break;
+       case 0x09:
+               /*
+                * The chip_id of the MAX6690 holds the revision of the chip.
+                * The lowest 3 bits of the config1 register are unused and
+                * should return zero when read.
+                * Note that MAX6654 and MAX6690 are practically the same chips.
+                * The only diference is the rated accuracy. Rev. 1 of the
+                * MAX6690 datasheet lists a chip ID of 0x08, and a chip labeled
+                * MAX6654 was observed to have a chip ID of 0x09.
+                */
+               if (common_address && !(config1 & 0x07) && convrate <= 0x07)
+                       name = "max6690";
+               break;
+       case 0x4d:
+               /*
+                * MAX6642, MAX6657, MAX6658 and MAX6659 do NOT have a chip_id
+                * register. Reading from that address will return the last
+                * read value, which in our case is those of the man_id
+                * register, or 0x4d.
+                * MAX6642 does not have a conversion rate register, nor low
+                * limit registers. Reading from those registers returns the
+                * last read value.
+                *
+                * For MAX6657, MAX6658 and MAX6659, the config1 register lacks
+                * a low nibble, so the value will be those of the previous
+                * read, so in our case again those of the man_id register.
+                * MAX6659 has a third set of upper temperature limit registers.
+                * Those registers also return values on MAX6657 and MAX6658,
+                * thus the only way to detect MAX6659 is by its address.
+                * For this reason it will be mis-detected as MAX6657 if its
+                * address is 0x4c.
+                */
+               if (address >= 0x48 && address <= 0x4f && config1 == convrate &&
+                   !(config1 & 0x0f)) {
+                       int regval;
+
+                       /*
+                        * We know that this is not a MAX6657/58/59 because its
+                        * configuration register has the wrong value and it does
+                        * not appear to have a conversion rate register.
+                        */
+
+                       /* re-read manufacturer ID to have a good baseline */
+                       if (i2c_smbus_read_byte_data(client, LM90_REG_MAN_ID) != 0x4d)
+                               break;
+
+                       /* check various non-existing registers */
+                       if (i2c_smbus_read_byte_data(client, LM90_REG_CONVRATE) != 0x4d ||
+                           i2c_smbus_read_byte_data(client, LM90_REG_LOCAL_LOW) != 0x4d ||
+                           i2c_smbus_read_byte_data(client, LM90_REG_REMOTE_LOWH) != 0x4d)
+                               break;
+
+                       /* check for unused status register bits */
+                       regval = i2c_smbus_read_byte_data(client, LM90_REG_STATUS);
+                       if (regval < 0 || (regval & 0x2b))
+                               break;
+
+                       /* re-check unsupported registers */
+                       if (i2c_smbus_read_byte_data(client, LM90_REG_CONVRATE) != regval ||
+                           i2c_smbus_read_byte_data(client, LM90_REG_LOCAL_LOW) != regval ||
+                           i2c_smbus_read_byte_data(client, LM90_REG_REMOTE_LOWH) != regval)
+                               break;
+
+                       name = "max6642";
+               } else if ((address == 0x4c || address == 0x4d || address == 0x4e) &&
+                          (config1 & 0x1f) == 0x0d && convrate <= 0x09) {
+                       if (address == 0x4c)
+                               name = "max6657";
+                       else
+                               name = "max6659";
                }
-       } else
-       if (address == 0x4C
-        && man_id == 0x5C) { /* Winbond/Nuvoton */
-               if ((config1 & 0x2A) == 0x00
-                && (config2 & 0xF8) == 0x00) {
-                       if (chip_id == 0x01 /* W83L771W/G */
-                        && convrate <= 0x09) {
-                               name = "w83l771";
-                       } else
-                       if ((chip_id & 0xFE) == 0x10 /* W83L771AWG/ASG */
-                        && convrate <= 0x08) {
-                               name = "w83l771";
+               break;
+       case 0x59:
+               /*
+                * The chip_id register of the MAX6646/6647/6649 holds the
+                * revision of the chip. The lowest 6 bits of the config1
+                * register are unused and should return zero when read.
+                * The I2C address of MAX6648/6692 is fixed at 0x4c.
+                * MAX6646 is at address 0x4d, MAX6647 is at address 0x4e,
+                * and MAX6649 is at address 0x4c. A slight difference between
+                * the two sets of chips is that the remote temperature register
+                * reports different values if the DXP pin is open or shorted.
+                * We can use that information to help distinguish between the
+                * chips. MAX6648 will be mis-detected as MAX6649 if the remote
+                * diode is connected, but there isn't really anything we can
+                * do about that.
+                */
+               if (!(config1 & 0x3f) && convrate <= 0x07) {
+                       int temp;
+
+                       switch (address) {
+                       case 0x4c:
+                               /*
+                                * MAX6649 reports an external temperature
+                                * value of 0xff if DXP is open or shorted.
+                                * MAX6648 reports 0x80 in that case.
+                                */
+                               temp = i2c_smbus_read_byte_data(client,
+                                                               LM90_REG_REMOTE_TEMPH);
+                               if (temp == 0x80)
+                                       name = "max6648";
+                               else
+                                       name = "max6649";
+                               break;
+                       case 0x4d:
+                               name = "max6646";
+                               break;
+                       case 0x4e:
+                               name = "max6647";
+                               break;
+                       default:
+                               break;
                        }
                }
-       } else
-       if (address >= 0x48 && address <= 0x4F
-        && man_id == 0xA1) { /*  NXP Semiconductor/Philips */
-               if (chip_id == 0x00
-                && (config1 & 0x2A) == 0x00
-                && (config2 & 0xFE) == 0x00
-                && convrate <= 0x09) {
-                       name = "sa56004";
+               break;
+       default:
+               break;
+       }
+
+       return name;
+}
+
+static const char *lm90_detect_nuvoton(struct i2c_client *client, int chip_id,
+                                      int config1, int convrate)
+{
+       int config2 = i2c_smbus_read_byte_data(client, LM90_REG_CONFIG2);
+       int address = client->addr;
+       const char *name = NULL;
+
+       if (config2 < 0)
+               return ERR_PTR(-ENODEV);
+
+       if (address == 0x4c && !(config1 & 0x2a) && !(config2 & 0xf8)) {
+               if (chip_id == 0x01 && convrate <= 0x09) {
+                       /* W83L771W/G */
+                       name = "w83l771";
+               } else if ((chip_id & 0xfe) == 0x10 && convrate <= 0x08) {
+                       /* W83L771AWG/ASG */
+                       name = "w83l771";
                }
-       } else
-       if ((address == 0x4C || address == 0x4D)
-        && man_id == 0x47) { /* GMT */
-               if (chip_id == 0x01 /* G781 */
-                && (config1 & 0x3F) == 0x00
-                && convrate <= 0x08)
-                       name = "g781";
-       } else
-       if (man_id == 0x55 && chip_id == 0x00 &&
-           (config1 & 0x1B) == 0x00 && convrate <= 0x09) {
+       }
+       return name;
+}
+
+static const char *lm90_detect_nxp(struct i2c_client *client, bool common_address,
+                                  int chip_id, int config1, int convrate)
+{
+       int address = client->addr;
+       const char *name = NULL;
+       int config2;
+
+       switch (chip_id) {
+       case 0x00:
+               config2 = i2c_smbus_read_byte_data(client, LM90_REG_CONFIG2);
+               if (config2 < 0)
+                       return NULL;
+               if (address >= 0x48 && address <= 0x4f &&
+                   !(config1 & 0x2a) && !(config2 & 0xfe) && convrate <= 0x09)
+                       name = "sa56004";
+               break;
+       case 0x80:
+               if (common_address && !(config1 & 0x3f) && convrate <= 0x07)
+                       name = "ne1618";
+               break;
+       default:
+               break;
+       }
+       return name;
+}
+
+static const char *lm90_detect_gmt(struct i2c_client *client, int chip_id,
+                                  int config1, int convrate)
+{
+       int address = client->addr;
+
+       /*
+        * According to the datasheet, G781 is supposed to be at I2C Address
+        * 0x4c and have a chip ID of 0x01. G781-1 is supposed to be at I2C
+        * address 0x4d and have a chip ID of 0x03. However, when support
+        * for G781 was added, chips at 0x4c and 0x4d were found to have a
+        * chip ID of 0x01. A G781-1 at I2C address 0x4d was now found with
+        * chip ID 0x03.
+        * To avoid detection failures, accept chip ID 0x01 and 0x03 at both
+        * addresses.
+        * G784 reports manufacturer ID 0x47 and chip ID 0x01. A public
+        * datasheet is not available. Extensive testing suggests that
+        * the chip appears to be fully compatible with G781.
+        * Available register dumps show that G751 also reports manufacturer
+        * ID 0x47 and chip ID 0x01 even though that chip does not officially
+        * support those registers. This makes chip detection somewhat
+        * vulnerable. To improve detection quality, read the offset low byte
+        * and alert fault queue registers and verify that only expected bits
+        * are set.
+        */
+       if ((chip_id == 0x01 || chip_id == 0x03) &&
+           (address == 0x4c || address == 0x4d) &&
+           !(config1 & 0x3f) && convrate <= 0x08) {
+               int reg;
+
+               reg = i2c_smbus_read_byte_data(client, LM90_REG_REMOTE_OFFSL);
+               if (reg < 0 || reg & 0x1f)
+                       return NULL;
+               reg = i2c_smbus_read_byte_data(client, TMP451_REG_CONALERT);
+               if (reg < 0 || reg & 0xf1)
+                       return NULL;
+
+               return "g781";
+       }
+
+       return NULL;
+}
+
+static const char *lm90_detect_ti49(struct i2c_client *client, bool common_address,
+                                   int chip_id, int config1, int convrate)
+{
+       if (common_address && chip_id == 0x00 && !(config1 & 0x3f) && !(convrate & 0xf8)) {
+               /* THMC10: Unsupported registers return 0xff */
+               if (i2c_smbus_read_byte_data(client, LM90_REG_REMOTE_TEMPL) == 0xff &&
+                   i2c_smbus_read_byte_data(client, LM90_REG_REMOTE_CRIT) == 0xff)
+                       return "thmc10";
+       }
+       return NULL;
+}
+
+static const char *lm90_detect_ti(struct i2c_client *client, int chip_id,
+                                 int config1, int convrate)
+{
+       int address = client->addr;
+       const char *name = NULL;
+
+       if (chip_id == 0x00 && !(config1 & 0x1b) && convrate <= 0x09) {
                int local_ext, conalert, chen, dfc;
 
                local_ext = i2c_smbus_read_byte_data(client,
-                                                    TMP451_REG_R_LOCAL_TEMPL);
+                                                    TMP451_REG_LOCAL_TEMPL);
                conalert = i2c_smbus_read_byte_data(client,
                                                    TMP451_REG_CONALERT);
                chen = i2c_smbus_read_byte_data(client, TMP461_REG_CHEN);
                dfc = i2c_smbus_read_byte_data(client, TMP461_REG_DFC);
 
-               if ((local_ext & 0x0F) == 0x00 &&
-                   (conalert & 0xf1) == 0x01 &&
-                   (chen & 0xfc) == 0x00 &&
-                   (dfc & 0xfc) == 0x00) {
+               if (!(local_ext & 0x0f) && (conalert & 0xf1) == 0x01 &&
+                   (chen & 0xfc) == 0x00 && (dfc & 0xfc) == 0x00) {
                        if (address == 0x4c && !(chen & 0x03))
                                name = "tmp451";
                        else if (address >= 0x48 && address <= 0x4f)
@@ -1682,10 +2440,110 @@ static int lm90_detect(struct i2c_client *client,
                }
        }
 
-       if (!name) { /* identification failed */
+       return name;
+}
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int lm90_detect(struct i2c_client *client, struct i2c_board_info *info)
+{
+       struct i2c_adapter *adapter = client->adapter;
+       int man_id, chip_id, config1, convrate, lhigh;
+       const char *name = NULL;
+       int address = client->addr;
+       bool common_address =
+                       (address >= 0x18 && address <= 0x1a) ||
+                       (address >= 0x29 && address <= 0x2b) ||
+                       (address >= 0x4c && address <= 0x4e);
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       /*
+        * Get well defined register value for chips with neither man_id nor
+        * chip_id registers.
+        */
+       lhigh = i2c_smbus_read_byte_data(client, LM90_REG_LOCAL_HIGH);
+
+       /* detection and identification */
+       man_id = i2c_smbus_read_byte_data(client, LM90_REG_MAN_ID);
+       chip_id = i2c_smbus_read_byte_data(client, LM90_REG_CHIP_ID);
+       config1 = i2c_smbus_read_byte_data(client, LM90_REG_CONFIG1);
+       convrate = i2c_smbus_read_byte_data(client, LM90_REG_CONVRATE);
+       if (man_id < 0 || chip_id < 0 || config1 < 0 || convrate < 0 || lhigh < 0)
+               return -ENODEV;
+
+       /* Bail out immediately if all register report the same value */
+       if (lhigh == man_id && lhigh == chip_id && lhigh == config1 && lhigh == convrate)
+               return -ENODEV;
+
+       /*
+        * If reading man_id and chip_id both return the same value as lhigh,
+        * the chip may not support those registers and return the most recent read
+        * value. Check again with a different register and handle accordingly.
+        */
+       if (man_id == lhigh && chip_id == lhigh) {
+               convrate = i2c_smbus_read_byte_data(client, LM90_REG_CONVRATE);
+               man_id = i2c_smbus_read_byte_data(client, LM90_REG_MAN_ID);
+               chip_id = i2c_smbus_read_byte_data(client, LM90_REG_CHIP_ID);
+               if (convrate < 0 || man_id < 0 || chip_id < 0)
+                       return -ENODEV;
+               if (man_id == convrate && chip_id == convrate)
+                       man_id = -1;
+       }
+       switch (man_id) {
+       case -1:        /* Chip does not support man_id / chip_id */
+               if (common_address && !convrate && !(config1 & 0x7f))
+                       name = lm90_detect_lm84(client);
+               break;
+       case 0x01:      /* National Semiconductor */
+               name = lm90_detect_national(client, chip_id, config1, convrate);
+               break;
+       case 0x1a:      /* ON */
+               name = lm90_detect_on(client, chip_id, config1, convrate);
+               break;
+       case 0x23:      /* Genesys Logic */
+               if (common_address && !(config1 & 0x3f) && !(convrate & 0xf8))
+                       name = "gl523sm";
+               break;
+       case 0x41:      /* Analog Devices */
+               name = lm90_detect_analog(client, common_address, chip_id, config1,
+                                         convrate);
+               break;
+       case 0x47:      /* GMT */
+               name = lm90_detect_gmt(client, chip_id, config1, convrate);
+               break;
+       case 0x49:      /* TI */
+               name = lm90_detect_ti49(client, common_address, chip_id, config1, convrate);
+               break;
+       case 0x4d:      /* Maxim Integrated */
+               name = lm90_detect_maxim(client, common_address, chip_id,
+                                        config1, convrate);
+               break;
+       case 0x54:      /* ON MC1066, Microchip TC1068, TCM1617 (originally TelCom) */
+               if (common_address && !(config1 & 0x3f) && !(convrate & 0xf8))
+                       name = "mc1066";
+               break;
+       case 0x55:      /* TI */
+               name = lm90_detect_ti(client, chip_id, config1, convrate);
+               break;
+       case 0x5c:      /* Winbond/Nuvoton */
+               name = lm90_detect_nuvoton(client, chip_id, config1, convrate);
+               break;
+       case 0xa1:      /*  NXP Semiconductor/Philips */
+               name = lm90_detect_nxp(client, common_address, chip_id, config1, convrate);
+               break;
+       case 0xff:      /* MAX1617, G767, NE1617 */
+               if (common_address && chip_id == 0xff && convrate < 8)
+                       name = lm90_detect_max1617(client, config1);
+               break;
+       default:
+               break;
+       }
+
+       if (!name) {    /* identification failed */
                dev_dbg(&adapter->dev,
-                       "Unsupported chip at 0x%02x (man_id=0x%02X, "
-                       "chip_id=0x%02X)\n", address, man_id, chip_id);
+                       "Unsupported chip at 0x%02x (man_id=0x%02X, chip_id=0x%02X)\n",
+                       client->addr, man_id, chip_id);
                return -ENODEV;
        }
 
@@ -1699,10 +2557,13 @@ static void lm90_restore_conf(void *_data)
        struct lm90_data *data = _data;
        struct i2c_client *client = data->client;
 
+       cancel_delayed_work_sync(&data->alert_work);
+       cancel_work_sync(&data->report_work);
+
        /* Restore initial configuration */
-       lm90_write_convrate(data, data->convrate_orig);
-       i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
-                                 data->config_orig);
+       if (data->flags & LM90_HAVE_CONVRATE)
+               lm90_write_convrate(data, data->convrate_orig);
+       lm90_write_reg(client, LM90_REG_CONFIG1, data->config_orig);
 }
 
 static int lm90_init_client(struct i2c_client *client, struct lm90_data *data)
@@ -1710,35 +2571,39 @@ static int lm90_init_client(struct i2c_client *client, struct lm90_data *data)
        struct device_node *np = client->dev.of_node;
        int config, convrate;
 
-       convrate = lm90_read_reg(client, LM90_REG_R_CONVRATE);
-       if (convrate < 0)
-               return convrate;
-       data->convrate_orig = convrate;
+       if (data->flags & LM90_HAVE_CONVRATE) {
+               convrate = lm90_read_reg(client, LM90_REG_CONVRATE);
+               if (convrate < 0)
+                       return convrate;
+               data->convrate_orig = convrate;
+               lm90_set_convrate(client, data, 500); /* 500ms; 2Hz conversion rate */
+       } else {
+               data->update_interval = 500;
+       }
 
        /*
         * Start the conversions.
         */
-       config = lm90_read_reg(client, LM90_REG_R_CONFIG1);
+       config = lm90_read_reg(client, LM90_REG_CONFIG1);
        if (config < 0)
                return config;
        data->config_orig = config;
        data->config = config;
 
-       lm90_set_convrate(client, data, 500); /* 500ms; 2Hz conversion rate */
-
        /* Check Temperature Range Select */
        if (data->flags & LM90_HAVE_EXTENDED_TEMP) {
                if (of_property_read_bool(np, "ti,extended-range-enable"))
                        config |= 0x04;
-
-               if (config & 0x04)
-                       data->flags |= LM90_FLAG_ADT7461_EXT;
+               if (!(config & 0x04))
+                       data->flags &= ~LM90_HAVE_EXTENDED_TEMP;
        }
 
        /*
         * Put MAX6680/MAX8881 into extended resolution (bit 0x10,
         * 0.125 degree resolution) and range (0x08, extend range
         * to -64 degree) mode for the remote temperature sensor.
+        * Note that expeciments with an actual chip do not show a difference
+        * if bit 3 is set or not.
         */
        if (data->kind == max6680)
                config |= 0x18;
@@ -1753,9 +2618,9 @@ static int lm90_init_client(struct i2c_client *client, struct lm90_data *data)
                config |= 0x20;
 
        /*
-        * Select external channel 0 for max6695/96
+        * Select external channel 0 for devices with three sensors
         */
-       if (data->kind == max6696)
+       if (data->flags & LM90_HAVE_TEMP3)
                config &= ~0x08;
 
        /*
@@ -1771,73 +2636,23 @@ static int lm90_init_client(struct i2c_client *client, struct lm90_data *data)
        return devm_add_action_or_reset(&client->dev, lm90_restore_conf, data);
 }
 
-static bool lm90_is_tripped(struct i2c_client *client, u16 *status)
+static bool lm90_is_tripped(struct i2c_client *client)
 {
        struct lm90_data *data = i2c_get_clientdata(client);
-       int st, st2 = 0;
+       int ret;
 
-       st = lm90_read_reg(client, LM90_REG_R_STATUS);
-       if (st < 0)
+       ret = lm90_update_alarms(data, true);
+       if (ret < 0)
                return false;
 
-       if (data->kind == max6696) {
-               st2 = lm90_read_reg(client, MAX6696_REG_R_STATUS2);
-               if (st2 < 0)
-                       return false;
-       }
-
-       *status = st | (st2 << 8);
-
-       if ((st & 0x7f) == 0 && (st2 & 0xfe) == 0)
-               return false;
-
-       if ((st & (LM90_STATUS_LLOW | LM90_STATUS_LHIGH | LM90_STATUS_LTHRM)) ||
-           (st2 & MAX6696_STATUS2_LOT2))
-               dev_dbg(&client->dev,
-                       "temp%d out of range, please check!\n", 1);
-       if ((st & (LM90_STATUS_RLOW | LM90_STATUS_RHIGH | LM90_STATUS_RTHRM)) ||
-           (st2 & MAX6696_STATUS2_ROT2))
-               dev_dbg(&client->dev,
-                       "temp%d out of range, please check!\n", 2);
-       if (st & LM90_STATUS_ROPEN)
-               dev_dbg(&client->dev,
-                       "temp%d diode open, please check!\n", 2);
-       if (st2 & (MAX6696_STATUS2_R2LOW | MAX6696_STATUS2_R2HIGH |
-                  MAX6696_STATUS2_R2THRM | MAX6696_STATUS2_R2OT2))
-               dev_dbg(&client->dev,
-                       "temp%d out of range, please check!\n", 3);
-       if (st2 & MAX6696_STATUS2_R2OPEN)
-               dev_dbg(&client->dev,
-                       "temp%d diode open, please check!\n", 3);
-
-       if (st & LM90_STATUS_LLOW)
-               hwmon_notify_event(data->hwmon_dev, hwmon_temp,
-                                  hwmon_temp_min_alarm, 0);
-       if (st & LM90_STATUS_RLOW)
-               hwmon_notify_event(data->hwmon_dev, hwmon_temp,
-                                  hwmon_temp_min_alarm, 1);
-       if (st2 & MAX6696_STATUS2_R2LOW)
-               hwmon_notify_event(data->hwmon_dev, hwmon_temp,
-                                  hwmon_temp_min_alarm, 2);
-       if (st & LM90_STATUS_LHIGH)
-               hwmon_notify_event(data->hwmon_dev, hwmon_temp,
-                                  hwmon_temp_max_alarm, 0);
-       if (st & LM90_STATUS_RHIGH)
-               hwmon_notify_event(data->hwmon_dev, hwmon_temp,
-                                  hwmon_temp_max_alarm, 1);
-       if (st2 & MAX6696_STATUS2_R2HIGH)
-               hwmon_notify_event(data->hwmon_dev, hwmon_temp,
-                                  hwmon_temp_max_alarm, 2);
-
-       return true;
+       return !!data->current_alarms;
 }
 
 static irqreturn_t lm90_irq_thread(int irq, void *dev_id)
 {
        struct i2c_client *client = dev_id;
-       u16 status;
 
-       if (lm90_is_tripped(client, &status))
+       if (lm90_is_tripped(client))
                return IRQ_HANDLED;
        else
                return IRQ_NONE;
@@ -1853,10 +2668,79 @@ static void lm90_regulator_disable(void *regulator)
        regulator_disable(regulator);
 }
 
+static int lm90_probe_channel_from_dt(struct i2c_client *client,
+                                     struct device_node *child,
+                                     struct lm90_data *data)
+{
+       u32 id;
+       s32 val;
+       int err;
+       struct device *dev = &client->dev;
+
+       err = of_property_read_u32(child, "reg", &id);
+       if (err) {
+               dev_err(dev, "missing reg property of %pOFn\n", child);
+               return err;
+       }
+
+       if (id >= MAX_CHANNELS) {
+               dev_err(dev, "invalid reg property value %d in %pOFn\n", id, child);
+               return -EINVAL;
+       }
+
+       err = of_property_read_string(child, "label", &data->channel_label[id]);
+       if (err == -ENODATA || err == -EILSEQ) {
+               dev_err(dev, "invalid label property in %pOFn\n", child);
+               return err;
+       }
+
+       if (data->channel_label[id])
+               data->channel_config[id] |= HWMON_T_LABEL;
+
+       err = of_property_read_s32(child, "temperature-offset-millicelsius", &val);
+       if (!err) {
+               if (id == 0) {
+                       dev_err(dev, "temperature-offset-millicelsius can't be set for internal channel\n");
+                       return -EINVAL;
+               }
+
+               err = lm90_set_temp_offset(data, lm90_temp_offset_index[id], id, val);
+               if (err) {
+                       dev_err(dev, "can't set temperature offset %d for channel %d (%d)\n",
+                               val, id, err);
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+static int lm90_parse_dt_channel_info(struct i2c_client *client,
+                                     struct lm90_data *data)
+{
+       int err;
+       struct device_node *child;
+       struct device *dev = &client->dev;
+       const struct device_node *np = dev->of_node;
+
+       for_each_child_of_node(np, child) {
+               if (strcmp(child->name, "channel"))
+                       continue;
+
+               err = lm90_probe_channel_from_dt(client, child, data);
+               if (err) {
+                       of_node_put(child);
+                       return err;
+               }
+       }
+
+       return 0;
+}
 
 static const struct hwmon_ops lm90_ops = {
        .is_visible = lm90_is_visible,
        .read = lm90_read,
+       .read_string = lm90_read_string,
        .write = lm90_write,
 };
 
@@ -1891,41 +2775,63 @@ static int lm90_probe(struct i2c_client *client)
        data->client = client;
        i2c_set_clientdata(client, data);
        mutex_init(&data->update_lock);
+       INIT_DELAYED_WORK(&data->alert_work, lm90_alert_work);
+       INIT_WORK(&data->report_work, lm90_report_alarms);
 
        /* Set the device type */
        if (client->dev.of_node)
                data->kind = (enum chips)of_device_get_match_data(&client->dev);
        else
                data->kind = i2c_match_id(lm90_id, client)->driver_data;
-       if (data->kind == adm1032) {
-               if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
-                       client->flags &= ~I2C_CLIENT_PEC;
-       }
 
        /*
         * Different devices have different alarm bits triggering the
         * ALERT# output
         */
        data->alert_alarms = lm90_params[data->kind].alert_alarms;
+       data->resolution = lm90_params[data->kind].resolution ? : 11;
 
        /* Set chip capabilities */
        data->flags = lm90_params[data->kind].flags;
 
+       if ((data->flags & (LM90_HAVE_PEC | LM90_HAVE_PARTIAL_PEC)) &&
+           !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_PEC))
+               data->flags &= ~(LM90_HAVE_PEC | LM90_HAVE_PARTIAL_PEC);
+
+       if ((data->flags & LM90_HAVE_PARTIAL_PEC) &&
+           !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
+               data->flags &= ~LM90_HAVE_PARTIAL_PEC;
+
        data->chip.ops = &lm90_ops;
        data->chip.info = data->info;
 
-       data->info[0] = HWMON_CHANNEL_INFO(chip,
-               HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL | HWMON_C_ALARMS);
+       data->info[0] = &data->chip_info;
+       info = &data->chip_info;
+       info->type = hwmon_chip;
+       info->config = data->chip_config;
+
+       data->chip_config[0] = HWMON_C_REGISTER_TZ;
+       if (data->flags & LM90_HAVE_ALARMS)
+               data->chip_config[0] |= HWMON_C_ALARMS;
+       if (data->flags & LM90_HAVE_CONVRATE)
+               data->chip_config[0] |= HWMON_C_UPDATE_INTERVAL;
+       if (data->flags & LM90_HAVE_FAULTQUEUE)
+               data->chip_config[0] |= HWMON_C_TEMP_SAMPLES;
        data->info[1] = &data->temp_info;
 
        info = &data->temp_info;
        info->type = hwmon_temp;
        info->config = data->channel_config;
 
-       data->channel_config[0] = HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
-               HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM;
-       data->channel_config[1] = HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
-               HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM | HWMON_T_FAULT;
+       data->channel_config[0] = HWMON_T_INPUT | HWMON_T_MAX |
+               HWMON_T_MAX_ALARM;
+       data->channel_config[1] = HWMON_T_INPUT | HWMON_T_MAX |
+               HWMON_T_MAX_ALARM | HWMON_T_FAULT;
+
+       if (data->flags & LM90_HAVE_LOW) {
+               data->channel_config[0] |= HWMON_T_MIN | HWMON_T_MIN_ALARM;
+               data->channel_config[1] |= HWMON_T_MIN | HWMON_T_MIN_ALARM;
+       }
 
        if (data->flags & LM90_HAVE_CRIT) {
                data->channel_config[0] |= HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_CRIT_HYST;
@@ -1951,17 +2857,35 @@ static int lm90_probe(struct i2c_client *client)
                data->channel_config[2] = HWMON_T_INPUT |
                        HWMON_T_MIN | HWMON_T_MAX |
                        HWMON_T_CRIT | HWMON_T_CRIT_HYST |
-                       HWMON_T_EMERGENCY | HWMON_T_EMERGENCY_HYST |
                        HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM |
-                       HWMON_T_CRIT_ALARM | HWMON_T_EMERGENCY_ALARM |
-                       HWMON_T_FAULT;
+                       HWMON_T_CRIT_ALARM | HWMON_T_FAULT;
+               if (data->flags & LM90_HAVE_EMERGENCY) {
+                       data->channel_config[2] |= HWMON_T_EMERGENCY |
+                               HWMON_T_EMERGENCY_HYST;
+               }
+               if (data->flags & LM90_HAVE_EMERGENCY_ALARM)
+                       data->channel_config[2] |= HWMON_T_EMERGENCY_ALARM;
+               if (data->flags & LM90_HAVE_OFFSET)
+                       data->channel_config[2] |= HWMON_T_OFFSET;
        }
 
+       data->faultqueue_mask = lm90_params[data->kind].faultqueue_mask;
+       data->faultqueue_depth = lm90_params[data->kind].faultqueue_depth;
        data->reg_local_ext = lm90_params[data->kind].reg_local_ext;
+       if (data->flags & LM90_HAVE_REMOTE_EXT)
+               data->reg_remote_ext = LM90_REG_REMOTE_TEMPL;
+       data->reg_status2 = lm90_params[data->kind].reg_status2;
 
        /* Set maximum conversion rate */
        data->max_convrate = lm90_params[data->kind].max_convrate;
 
+       /* Parse device-tree channel information */
+       if (client->dev.of_node) {
+               err = lm90_parse_dt_channel_info(client, data);
+               if (err)
+                       return err;
+       }
+
        /* Initialize the LM90 chip */
        err = lm90_init_client(client, data);
        if (err < 0) {
@@ -1973,7 +2897,7 @@ static int lm90_probe(struct i2c_client *client)
         * The 'pec' attribute is attached to the i2c device and thus created
         * separately.
         */
-       if (client->flags & I2C_CLIENT_PEC) {
+       if (data->flags & (LM90_HAVE_PEC | LM90_HAVE_PARTIAL_PEC)) {
                err = device_create_file(dev, &dev_attr_pec);
                if (err)
                        return err;
@@ -2007,12 +2931,10 @@ static int lm90_probe(struct i2c_client *client)
 static void lm90_alert(struct i2c_client *client, enum i2c_alert_protocol type,
                       unsigned int flag)
 {
-       u16 alarms;
-
        if (type != I2C_PROTOCOL_SMBUS_ALERT)
                return;
 
-       if (lm90_is_tripped(client, &alarms)) {
+       if (lm90_is_tripped(client)) {
                /*
                 * Disable ALERT# output, because these chips don't implement
                 * SMBus alert correctly; they should only hold the alert line
@@ -2021,9 +2943,13 @@ static void lm90_alert(struct i2c_client *client, enum i2c_alert_protocol type,
                struct lm90_data *data = i2c_get_clientdata(client);
 
                if ((data->flags & LM90_HAVE_BROKEN_ALERT) &&
-                   (alarms & data->alert_alarms)) {
-                       dev_dbg(&client->dev, "Disabling ALERT#\n");
-                       lm90_update_confreg(data, data->config | 0x80);
+                   (data->current_alarms & data->alert_alarms)) {
+                       if (!(data->config & 0x80)) {
+                               dev_dbg(&client->dev, "Disabling ALERT#\n");
+                               lm90_update_confreg(data, data->config | 0x80);
+                       }
+                       schedule_delayed_work(&data->alert_work,
+                               max_t(int, HZ, msecs_to_jiffies(data->update_interval)));
                }
        } else {
                dev_dbg(&client->dev, "Everything OK\n");
index ce27807..e093b19 100644 (file)
@@ -7,7 +7,7 @@
  * Reworked by Sven Schuchmann <schuchmann@schleissheimer.de>
  * DT support added by Clemens Gruber <clemens.gruber@pqgruber.com>
  *
- * This driver export the value of analog input voltage to sysfs, the
+ * This driver exports the value of analog input voltage to sysfs, the
  * voltage unit is mV. Through the sysfs interface, lm-sensors tool
  * can also display the input voltage.
  */
@@ -45,19 +45,29 @@ enum chips {
  * Client data (each client gets its own)
  */
 struct mcp3021_data {
-       struct device *hwmon_dev;
+       struct i2c_client *client;
        u32 vdd;        /* supply and reference voltage in millivolt */
        u16 sar_shift;
        u16 sar_mask;
        u8 output_res;
 };
 
-static int mcp3021_read16(struct i2c_client *client)
+static inline u16 volts_from_reg(struct mcp3021_data *data, u16 val)
 {
-       struct mcp3021_data *data = i2c_get_clientdata(client);
-       int ret;
-       u16 reg;
+       return DIV_ROUND_CLOSEST(data->vdd * val, 1 << data->output_res);
+}
+
+static int mcp3021_read(struct device *dev, enum hwmon_sensor_types type,
+                       u32 attr, int channel, long *val)
+{
+       struct mcp3021_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        __be16 buf;
+       u16 reg;
+       int ret;
+
+       if (type != hwmon_in)
+               return -EOPNOTSUPP;
 
        ret = i2c_master_recv(client, (char *)&buf, 2);
        if (ret < 0)
@@ -74,39 +84,46 @@ static int mcp3021_read16(struct i2c_client *client)
         */
        reg = (reg >> data->sar_shift) & data->sar_mask;
 
-       return reg;
-}
+       *val = volts_from_reg(data, reg);
 
-static inline u16 volts_from_reg(struct mcp3021_data *data, u16 val)
-{
-       return DIV_ROUND_CLOSEST(data->vdd * val, 1 << data->output_res);
+       return 0;
 }
 
-static ssize_t in0_input_show(struct device *dev,
-                             struct device_attribute *attr, char *buf)
+static umode_t mcp3021_is_visible(const void *_data,
+                                 enum hwmon_sensor_types type,
+                                 u32 attr, int channel)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct mcp3021_data *data = i2c_get_clientdata(client);
-       int reg, in_input;
+       if (type != hwmon_in)
+               return 0;
 
-       reg = mcp3021_read16(client);
-       if (reg < 0)
-               return reg;
+       if (attr != hwmon_in_input)
+               return 0;
 
-       in_input = volts_from_reg(data, reg);
-
-       return sprintf(buf, "%d\n", in_input);
+       return 0444;
 }
 
-static DEVICE_ATTR_RO(in0_input);
+static const struct hwmon_channel_info *mcp3021_info[] = {
+       HWMON_CHANNEL_INFO(in, HWMON_I_INPUT),
+       NULL
+};
+
+static const struct hwmon_ops mcp3021_hwmon_ops = {
+       .is_visible = mcp3021_is_visible,
+       .read = mcp3021_read,
+};
+
+static const struct hwmon_chip_info mcp3021_chip_info = {
+       .ops = &mcp3021_hwmon_ops,
+       .info = mcp3021_info,
+};
 
 static const struct i2c_device_id mcp3021_id[];
 
 static int mcp3021_probe(struct i2c_client *client)
 {
-       int err;
        struct mcp3021_data *data = NULL;
        struct device_node *np = client->dev.of_node;
+       struct device *hwmon_dev;
 
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
                return -ENODEV;
@@ -147,34 +164,17 @@ static int mcp3021_probe(struct i2c_client *client)
                break;
        }
 
+       data->client = client;
+
        if (data->vdd > MCP3021_VDD_REF_MAX || data->vdd < MCP3021_VDD_REF_MIN)
                return -EINVAL;
 
-       err = sysfs_create_file(&client->dev.kobj, &dev_attr_in0_input.attr);
-       if (err)
-               return err;
-
-       data->hwmon_dev = hwmon_device_register(&client->dev);
-       if (IS_ERR(data->hwmon_dev)) {
-               err = PTR_ERR(data->hwmon_dev);
-               goto exit_remove;
-       }
-
-       return 0;
-
-exit_remove:
-       sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr);
-       return err;
-}
-
-static int mcp3021_remove(struct i2c_client *client)
-{
-       struct mcp3021_data *data = i2c_get_clientdata(client);
-
-       hwmon_device_unregister(data->hwmon_dev);
-       sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr);
-
-       return 0;
+       hwmon_dev = devm_hwmon_device_register_with_info(&client->dev,
+                                                        client->name,
+                                                        data,
+                                                        &mcp3021_chip_info,
+                                                        NULL);
+       return PTR_ERR_OR_ZERO(hwmon_dev);
 }
 
 static const struct i2c_device_id mcp3021_id[] = {
@@ -199,7 +199,6 @@ static struct i2c_driver mcp3021_driver = {
                .of_match_table = of_match_ptr(of_mcp3021_match),
        },
        .probe_new = mcp3021_probe,
-       .remove = mcp3021_remove,
        .id_table = mcp3021_id,
 };
 
index 6d46c94..ab30437 100644 (file)
@@ -1083,6 +1083,7 @@ static const char * const asus_wmi_boards[] = {
        "TUF GAMING B550M-PLUS",
        "TUF GAMING B550M-PLUS (WI-FI)",
        "TUF GAMING B550-PLUS",
+       "TUF GAMING B550-PLUS WIFI II",
        "TUF GAMING B550-PRO",
        "TUF GAMING X570-PLUS",
        "TUF GAMING X570-PLUS (WI-FI)",
@@ -1200,10 +1201,8 @@ static int __init sensors_nct6775_platform_init(void)
 exit_device_put:
        platform_device_put(pdev[i]);
 exit_device_unregister:
-       while (--i >= 0) {
-               if (pdev[i])
-                       platform_device_unregister(pdev[i]);
-       }
+       while (i--)
+               platform_device_unregister(pdev[i]);
 exit_unregister:
        platform_driver_unregister(&nct6775_driver);
        return err;
@@ -1213,10 +1212,8 @@ static void __exit sensors_nct6775_platform_exit(void)
 {
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(pdev); i++) {
-               if (pdev[i])
-                       platform_device_unregister(pdev[i]);
-       }
+       for (i = 0; i < ARRAY_SIZE(pdev); i++)
+               platform_device_unregister(pdev[i]);
        platform_driver_unregister(&nct6775_driver);
 }
 
index ea070b9..45407b1 100644 (file)
@@ -145,7 +145,7 @@ static int occ_poll(struct occ *occ)
        cmd[6] = 0;                     /* checksum lsb */
 
        /* mutex should already be locked if necessary */
-       rc = occ->send_cmd(occ, cmd, sizeof(cmd));
+       rc = occ->send_cmd(occ, cmd, sizeof(cmd), &occ->resp, sizeof(occ->resp));
        if (rc) {
                occ->last_error = rc;
                if (occ->error_count++ > OCC_ERROR_COUNT_THRESHOLD)
@@ -182,6 +182,7 @@ static int occ_set_user_power_cap(struct occ *occ, u16 user_power_cap)
 {
        int rc;
        u8 cmd[8];
+       u8 resp[8];
        __be16 user_power_cap_be = cpu_to_be16(user_power_cap);
 
        cmd[0] = 0;     /* sequence number */
@@ -198,7 +199,7 @@ static int occ_set_user_power_cap(struct occ *occ, u16 user_power_cap)
        if (rc)
                return rc;
 
-       rc = occ->send_cmd(occ, cmd, sizeof(cmd));
+       rc = occ->send_cmd(occ, cmd, sizeof(cmd), resp, sizeof(resp));
 
        mutex_unlock(&occ->lock);
 
@@ -728,18 +729,14 @@ static ssize_t occ_show_extended(struct device *dev,
                        rc = sysfs_emit(buf, "%u",
                                        get_unaligned_be32(&extn->sensor_id));
                } else {
-                       rc = sysfs_emit(buf, "%02x%02x%02x%02x\n",
-                                       extn->name[0], extn->name[1],
-                                       extn->name[2], extn->name[3]);
+                       rc = sysfs_emit(buf, "%4phN\n", extn->name);
                }
                break;
        case 1:
                rc = sysfs_emit(buf, "%02x\n", extn->flags);
                break;
        case 2:
-               rc = sysfs_emit(buf, "%02x%02x%02x%02x%02x%02x\n",
-                               extn->data[0], extn->data[1], extn->data[2],
-                               extn->data[3], extn->data[4], extn->data[5]);
+               rc = sysfs_emit(buf, "%6phN\n", extn->data);
                break;
        default:
                return -EINVAL;
index 64d5ec7..7ac4b2f 100644 (file)
@@ -96,7 +96,8 @@ struct occ {
 
        int powr_sample_time_us;        /* average power sample time */
        u8 poll_cmd_data;               /* to perform OCC poll command */
-       int (*send_cmd)(struct occ *occ, u8 *cmd, size_t len);
+       int (*send_cmd)(struct occ *occ, u8 *cmd, size_t len, void *resp,
+                       size_t resp_len);
 
        unsigned long next_update;
        struct mutex lock;              /* lock OCC access */
index da39ea2..b221be1 100644 (file)
@@ -111,7 +111,8 @@ static int p8_i2c_occ_putscom_be(struct i2c_client *client, u32 address,
                                      be32_to_cpu(data1));
 }
 
-static int p8_i2c_occ_send_cmd(struct occ *occ, u8 *cmd, size_t len)
+static int p8_i2c_occ_send_cmd(struct occ *occ, u8 *cmd, size_t len,
+                              void *resp, size_t resp_len)
 {
        int i, rc;
        unsigned long start;
@@ -120,7 +121,7 @@ static int p8_i2c_occ_send_cmd(struct occ *occ, u8 *cmd, size_t len)
        const long wait_time = msecs_to_jiffies(OCC_CMD_IN_PRG_WAIT_MS);
        struct p8_i2c_occ *ctx = to_p8_i2c_occ(occ);
        struct i2c_client *client = ctx->client;
-       struct occ_response *resp = &occ->resp;
+       struct occ_response *or = (struct occ_response *)resp;
 
        start = jiffies;
 
@@ -151,7 +152,7 @@ static int p8_i2c_occ_send_cmd(struct occ *occ, u8 *cmd, size_t len)
                        return rc;
 
                /* wait for OCC */
-               if (resp->return_status == OCC_RESP_CMD_IN_PRG) {
+               if (or->return_status == OCC_RESP_CMD_IN_PRG) {
                        rc = -EALREADY;
 
                        if (time_after(jiffies, start + timeout))
@@ -163,7 +164,7 @@ static int p8_i2c_occ_send_cmd(struct occ *occ, u8 *cmd, size_t len)
        } while (rc);
 
        /* check the OCC response */
-       switch (resp->return_status) {
+       switch (or->return_status) {
        case OCC_RESP_CMD_IN_PRG:
                rc = -ETIMEDOUT;
                break;
@@ -192,8 +193,8 @@ static int p8_i2c_occ_send_cmd(struct occ *occ, u8 *cmd, size_t len)
        if (rc < 0)
                return rc;
 
-       data_length = get_unaligned_be16(&resp->data_length);
-       if (data_length > OCC_RESP_DATA_BYTES)
+       data_length = get_unaligned_be16(&or->data_length);
+       if ((data_length + 7) > resp_len)
                return -EMSGSIZE;
 
        /* fetch the rest of the response data */
index 42fc7b9..c1e0a1d 100644 (file)
@@ -55,8 +55,7 @@ static bool p9_sbe_occ_save_ffdc(struct p9_sbe_occ *ctx, const void *resp,
        mutex_lock(&ctx->sbe_error_lock);
        if (!ctx->sbe_error) {
                if (resp_len > ctx->ffdc_size) {
-                       if (ctx->ffdc)
-                               kvfree(ctx->ffdc);
+                       kvfree(ctx->ffdc);
                        ctx->ffdc = kvmalloc(resp_len, GFP_KERNEL);
                        if (!ctx->ffdc) {
                                ctx->ffdc_len = 0;
@@ -78,11 +77,10 @@ done:
        return notify;
 }
 
-static int p9_sbe_occ_send_cmd(struct occ *occ, u8 *cmd, size_t len)
+static int p9_sbe_occ_send_cmd(struct occ *occ, u8 *cmd, size_t len,
+                              void *resp, size_t resp_len)
 {
-       struct occ_response *resp = &occ->resp;
        struct p9_sbe_occ *ctx = to_p9_sbe_occ(occ);
-       size_t resp_len = sizeof(*resp);
        int rc;
 
        rc = fsi_occ_submit(ctx->sbe, cmd, len, resp, &resp_len);
@@ -96,7 +94,7 @@ static int p9_sbe_occ_send_cmd(struct occ *occ, u8 *cmd, size_t len)
                return rc;
        }
 
-       switch (resp->return_status) {
+       switch (((struct occ_response *)resp)->return_status) {
        case OCC_RESP_CMD_IN_PRG:
                rc = -ETIMEDOUT;
                break;
@@ -171,8 +169,7 @@ static int p9_sbe_occ_remove(struct platform_device *pdev)
        ctx->sbe = NULL;
        occ_shutdown(occ);
 
-       if (ctx->ffdc)
-               kvfree(ctx->ffdc);
+       kvfree(ctx->ffdc);
 
        return 0;
 }
index dfae76d..951e4a9 100644 (file)
@@ -181,6 +181,15 @@ config SENSORS_LM25066_REGULATOR
          If you say yes here you get regulator support for National
          Semiconductor LM25066, LM5064, and LM5066.
 
+config SENSORS_LT7182S
+       tristate "Analog Devices LT7182S"
+       help
+         If you say yes here you get hardware monitoring support for Analog
+         Devices LT7182S.
+
+         This driver can also be built as a module. If so, the module will
+         be called lt7182s.
+
 config SENSORS_LTC2978
        tristate "Linear Technologies LTC2978 and compatibles"
        help
index 4678fba..e2fe86f 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_SENSORS_IR38064) += ir38064.o
 obj-$(CONFIG_SENSORS_IRPS5401) += irps5401.o
 obj-$(CONFIG_SENSORS_ISL68137) += isl68137.o
 obj-$(CONFIG_SENSORS_LM25066)  += lm25066.o
+obj-$(CONFIG_SENSORS_LT7182S)  += lt7182s.o
 obj-$(CONFIG_SENSORS_LTC2978)  += ltc2978.o
 obj-$(CONFIG_SENSORS_LTC3815)  += ltc3815.o
 obj-$(CONFIG_SENSORS_MAX15301) += max15301.o
diff --git a/drivers/hwmon/pmbus/lt7182s.c b/drivers/hwmon/pmbus/lt7182s.c
new file mode 100644 (file)
index 0000000..4cfe476
--- /dev/null
@@ -0,0 +1,195 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Hardware monitoring driver for Analog Devices LT7182S
+ *
+ * Copyright (c) 2022 Guenter Roeck
+ *
+ */
+
+#include <linux/bits.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include "pmbus.h"
+
+#define LT7182S_NUM_PAGES      2
+
+#define MFR_READ_EXTVCC                0xcd
+#define MFR_READ_ITH           0xce
+#define MFR_CONFIG_ALL_LT7182S 0xd1
+#define MFR_IOUT_PEAK          0xd7
+#define MFR_ADC_CONTROL_LT7182S 0xd8
+
+#define MFR_DEBUG_TELEMETRY    BIT(0)
+
+#define MFR_VOUT_PEAK          0xdd
+#define MFR_VIN_PEAK           0xde
+#define MFR_TEMPERATURE_1_PEAK 0xdf
+#define MFR_CLEAR_PEAKS                0xe3
+
+#define MFR_CONFIG_IEEE                BIT(8)
+
+static int lt7182s_read_word_data(struct i2c_client *client, int page, int phase, int reg)
+{
+       int ret;
+
+       switch (reg) {
+       case PMBUS_VIRT_READ_VMON:
+               if (page == 0 || page == 1)
+                       ret = pmbus_read_word_data(client, page, phase, MFR_READ_ITH);
+               else
+                       ret = pmbus_read_word_data(client, 0, phase, MFR_READ_EXTVCC);
+               break;
+       case PMBUS_VIRT_READ_IOUT_MAX:
+               ret = pmbus_read_word_data(client, page, phase, MFR_IOUT_PEAK);
+               break;
+       case PMBUS_VIRT_READ_VOUT_MAX:
+               ret = pmbus_read_word_data(client, page, phase, MFR_VOUT_PEAK);
+               break;
+       case PMBUS_VIRT_READ_VIN_MAX:
+               ret = pmbus_read_word_data(client, page, phase, MFR_VIN_PEAK);
+               break;
+       case PMBUS_VIRT_READ_TEMP_MAX:
+               ret = pmbus_read_word_data(client, page, phase, MFR_TEMPERATURE_1_PEAK);
+               break;
+       case PMBUS_VIRT_RESET_VIN_HISTORY:
+               ret = (page == 0) ? 0 : -ENODATA;
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
+static int lt7182s_write_word_data(struct i2c_client *client, int page, int reg, u16 word)
+{
+       int ret;
+
+       switch (reg) {
+       case PMBUS_VIRT_RESET_VIN_HISTORY:
+               ret = pmbus_write_byte(client, 0, MFR_CLEAR_PEAKS);
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
+static struct pmbus_driver_info lt7182s_info = {
+       .pages = LT7182S_NUM_PAGES,
+       .format[PSC_VOLTAGE_IN] = linear,
+       .format[PSC_VOLTAGE_OUT] = linear,
+       .format[PSC_CURRENT_IN] = linear,
+       .format[PSC_CURRENT_OUT] = linear,
+       .format[PSC_TEMPERATURE] = linear,
+       .format[PSC_POWER] = linear,
+       .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT |
+         PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_POUT |
+         PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT |
+         PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP,
+       .func[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT |
+         PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_POUT |
+         PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT |
+         PMBUS_HAVE_STATUS_INPUT,
+       .read_word_data = lt7182s_read_word_data,
+       .write_word_data = lt7182s_write_word_data,
+};
+
+static int lt7182s_probe(struct i2c_client *client)
+{
+       struct device *dev = &client->dev;
+       struct pmbus_driver_info *info;
+       u8 buf[I2C_SMBUS_BLOCK_MAX + 1];
+       int ret;
+
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_READ_BYTE_DATA |
+                                    I2C_FUNC_SMBUS_READ_WORD_DATA |
+                                    I2C_FUNC_SMBUS_READ_BLOCK_DATA))
+               return -ENODEV;
+
+       ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
+       if (ret < 0) {
+               dev_err(dev, "Failed to read PMBUS_MFR_ID\n");
+               return ret;
+       }
+       if (ret != 3 || strncmp(buf, "ADI", 3)) {
+               buf[ret] = '\0';
+               dev_err(dev, "Manufacturer '%s' not supported\n", buf);
+               return -ENODEV;
+       }
+
+       ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);
+       if (ret < 0) {
+               dev_err(dev, "Failed to read PMBUS_MFR_MODEL\n");
+               return ret;
+       }
+       if (ret != 7 || strncmp(buf, "LT7182S", 7)) {
+               buf[ret] = '\0';
+               dev_err(dev, "Model '%s' not supported\n", buf);
+               return -ENODEV;
+       }
+
+       info = devm_kmemdup(dev, &lt7182s_info,
+                           sizeof(struct pmbus_driver_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       /* Set data format to IEEE754 if configured */
+       ret = i2c_smbus_read_word_data(client, MFR_CONFIG_ALL_LT7182S);
+       if (ret < 0)
+               return ret;
+       if (ret & MFR_CONFIG_IEEE) {
+               info->format[PSC_VOLTAGE_IN] = ieee754;
+               info->format[PSC_VOLTAGE_OUT] = ieee754;
+               info->format[PSC_CURRENT_IN] = ieee754;
+               info->format[PSC_CURRENT_OUT] = ieee754;
+               info->format[PSC_TEMPERATURE] = ieee754;
+               info->format[PSC_POWER] = ieee754;
+       }
+
+       /* Enable VMON output if configured */
+       ret = i2c_smbus_read_byte_data(client, MFR_ADC_CONTROL_LT7182S);
+       if (ret < 0)
+               return ret;
+       if (ret & MFR_DEBUG_TELEMETRY) {
+               info->pages = 3;
+               info->func[0] |= PMBUS_HAVE_VMON;
+               info->func[1] |= PMBUS_HAVE_VMON;
+               info->func[2] = PMBUS_HAVE_VMON;
+       }
+
+       return pmbus_do_probe(client, info);
+}
+
+static const struct i2c_device_id lt7182s_id[] = {
+       { "lt7182s", 0 },
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, lt7182s_id);
+
+static const struct of_device_id __maybe_unused lt7182s_of_match[] = {
+       { .compatible = "adi,lt7182s" },
+       {}
+};
+
+static struct i2c_driver lt7182s_driver = {
+       .driver = {
+               .name = "lt7182s",
+               .of_match_table = of_match_ptr(lt7182s_of_match),
+       },
+       .probe_new = lt7182s_probe,
+       .id_table = lt7182s_id,
+};
+
+module_i2c_driver(lt7182s_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("PMBus driver for Analog Devices LT7182S");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
index 531aa67..6d25927 100644 (file)
@@ -562,7 +562,24 @@ static const struct i2c_device_id ltc2978_id[] = {
 MODULE_DEVICE_TABLE(i2c, ltc2978_id);
 
 #if IS_ENABLED(CONFIG_SENSORS_LTC2978_REGULATOR)
+#define LTC2978_ADC_RES        0xFFFF
+#define LTC2978_N_ADC  122
+#define LTC2978_MAX_UV (LTC2978_ADC_RES * LTC2978_N_ADC)
+#define LTC2978_UV_STEP        1000
+#define LTC2978_N_VOLTAGES     ((LTC2978_MAX_UV / LTC2978_UV_STEP) + 1)
+
 static const struct regulator_desc ltc2978_reg_desc[] = {
+       PMBUS_REGULATOR_STEP("vout", 0, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
+       PMBUS_REGULATOR_STEP("vout", 1, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
+       PMBUS_REGULATOR_STEP("vout", 2, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
+       PMBUS_REGULATOR_STEP("vout", 3, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
+       PMBUS_REGULATOR_STEP("vout", 4, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
+       PMBUS_REGULATOR_STEP("vout", 5, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
+       PMBUS_REGULATOR_STEP("vout", 6, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
+       PMBUS_REGULATOR_STEP("vout", 7, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
+};
+
+static const struct regulator_desc ltc2978_reg_desc_default[] = {
        PMBUS_REGULATOR("vout", 0),
        PMBUS_REGULATOR("vout", 1),
        PMBUS_REGULATOR("vout", 2),
@@ -839,10 +856,29 @@ static int ltc2978_probe(struct i2c_client *client)
 
 #if IS_ENABLED(CONFIG_SENSORS_LTC2978_REGULATOR)
        info->num_regulators = info->pages;
-       info->reg_desc = ltc2978_reg_desc;
-       if (info->num_regulators > ARRAY_SIZE(ltc2978_reg_desc)) {
-               dev_err(&client->dev, "num_regulators too large!");
-               info->num_regulators = ARRAY_SIZE(ltc2978_reg_desc);
+       switch (data->id) {
+       case ltc2972:
+       case ltc2974:
+       case ltc2975:
+       case ltc2977:
+       case ltc2978:
+       case ltc2979:
+       case ltc2980:
+       case ltm2987:
+               info->reg_desc = ltc2978_reg_desc;
+               if (info->num_regulators > ARRAY_SIZE(ltc2978_reg_desc)) {
+                       dev_warn(&client->dev, "num_regulators too large!");
+                       info->num_regulators = ARRAY_SIZE(ltc2978_reg_desc);
+               }
+               break;
+       default:
+               info->reg_desc = ltc2978_reg_desc_default;
+               if (info->num_regulators > ARRAY_SIZE(ltc2978_reg_desc_default)) {
+                       dev_warn(&client->dev, "num_regulators too large!");
+                       info->num_regulators =
+                           ARRAY_SIZE(ltc2978_reg_desc_default);
+               }
+               break;
        }
 #endif
 
index c031a97..7daaf0c 100644 (file)
@@ -406,7 +406,7 @@ enum pmbus_sensor_classes {
 #define PMBUS_PHASE_VIRTUAL    BIT(30) /* Phases on this page are virtual */
 #define PMBUS_PAGE_VIRTUAL     BIT(31) /* Page is virtual */
 
-enum pmbus_data_format { linear = 0, direct, vid };
+enum pmbus_data_format { linear = 0, ieee754, direct, vid };
 enum vrm_version { vr11 = 0, vr12, vr13, imvp9, amd625mv };
 
 struct pmbus_driver_info {
@@ -463,8 +463,8 @@ struct pmbus_driver_info {
 
 extern const struct regulator_ops pmbus_regulator_ops;
 
-/* Macro for filling in array of struct regulator_desc */
-#define PMBUS_REGULATOR(_name, _id)                            \
+/* Macros for filling in array of struct regulator_desc */
+#define PMBUS_REGULATOR_STEP(_name, _id, _voltages, _step)  \
        [_id] = {                                               \
                .name = (_name # _id),                          \
                .supply_name = "vin",                           \
@@ -474,8 +474,12 @@ extern const struct regulator_ops pmbus_regulator_ops;
                .ops = &pmbus_regulator_ops,                    \
                .type = REGULATOR_VOLTAGE,                      \
                .owner = THIS_MODULE,                           \
+               .n_voltages = _voltages,                        \
+               .uV_step = _step,                               \
        }
 
+#define PMBUS_REGULATOR(_name, _id)    PMBUS_REGULATOR_STEP(_name, _id, 0, 0)
+
 /* Function declarations */
 
 void pmbus_clear_cache(struct i2c_client *client);
index 0291202..f10bac8 100644 (file)
@@ -104,6 +104,9 @@ struct pmbus_data {
 
        s16 currpage;   /* current page, -1 for unknown/unset */
        s16 currphase;  /* current phase, 0xff for all, -1 for unknown/unset */
+
+       int vout_low[PMBUS_PAGES];      /* voltage low margin */
+       int vout_high[PMBUS_PAGES];     /* voltage high margin */
 };
 
 struct pmbus_debugfs_entry {
@@ -441,6 +444,18 @@ int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg,
 }
 EXPORT_SYMBOL_NS_GPL(pmbus_update_byte_data, PMBUS);
 
+static int pmbus_read_block_data(struct i2c_client *client, int page, u8 reg,
+                                char *data_buf)
+{
+       int rv;
+
+       rv = pmbus_set_page(client, page, 0xff);
+       if (rv < 0)
+               return rv;
+
+       return i2c_smbus_read_block_data(client, reg, data_buf);
+}
+
 static struct pmbus_sensor *pmbus_find_sensor(struct pmbus_data *data, int page,
                                              int reg)
 {
@@ -578,6 +593,22 @@ bool pmbus_check_word_register(struct i2c_client *client, int page, int reg)
 }
 EXPORT_SYMBOL_NS_GPL(pmbus_check_word_register, PMBUS);
 
+static bool __maybe_unused pmbus_check_block_register(struct i2c_client *client,
+                                                     int page, int reg)
+{
+       int rv;
+       struct pmbus_data *data = i2c_get_clientdata(client);
+       char data_buf[I2C_SMBUS_BLOCK_MAX + 2];
+
+       rv = pmbus_read_block_data(client, page, reg, data_buf);
+       if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK))
+               rv = pmbus_check_status_cml(client);
+       if (rv < 0 && (data->flags & PMBUS_READ_STATUS_AFTER_FAILED_CHECK))
+               data->read_status(client, -1);
+       pmbus_clear_fault_page(client, -1);
+       return rv >= 0;
+}
+
 const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client *client)
 {
        struct pmbus_data *data = i2c_get_clientdata(client);
@@ -612,6 +643,66 @@ static void pmbus_update_sensor_data(struct i2c_client *client, struct pmbus_sen
 }
 
 /*
+ * Convert ieee754 sensor values to milli- or micro-units
+ * depending on sensor type.
+ *
+ * ieee754 data format:
+ *     bit 15:         sign
+ *     bit 10..14:     exponent
+ *     bit 0..9:       mantissa
+ * exponent=0:
+ *     v=(−1)^signbit * 2^(−14) * 0.significantbits
+ * exponent=1..30:
+ *     v=(−1)^signbit * 2^(exponent - 15) * 1.significantbits
+ * exponent=31:
+ *     v=NaN
+ *
+ * Add the number mantissa bits into the calculations for simplicity.
+ * To do that, add '10' to the exponent. By doing that, we can just add
+ * 0x400 to normal values and get the expected result.
+ */
+static long pmbus_reg2data_ieee754(struct pmbus_data *data,
+                                  struct pmbus_sensor *sensor)
+{
+       int exponent;
+       bool sign;
+       long val;
+
+       /* only support half precision for now */
+       sign = sensor->data & 0x8000;
+       exponent = (sensor->data >> 10) & 0x1f;
+       val = sensor->data & 0x3ff;
+
+       if (exponent == 0) {                    /* subnormal */
+               exponent = -(14 + 10);
+       } else if (exponent ==  0x1f) {         /* NaN, convert to min/max */
+               exponent = 0;
+               val = 65504;
+       } else {
+               exponent -= (15 + 10);          /* normal */
+               val |= 0x400;
+       }
+
+       /* scale result to milli-units for all sensors except fans */
+       if (sensor->class != PSC_FAN)
+               val = val * 1000L;
+
+       /* scale result to micro-units for power sensors */
+       if (sensor->class == PSC_POWER)
+               val = val * 1000L;
+
+       if (exponent >= 0)
+               val <<= exponent;
+       else
+               val >>= -exponent;
+
+       if (sign)
+               val = -val;
+
+       return val;
+}
+
+/*
  * Convert linear sensor values to milli- or micro-units
  * depending on sensor type.
  */
@@ -741,6 +832,9 @@ static s64 pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor)
        case vid:
                val = pmbus_reg2data_vid(data, sensor);
                break;
+       case ieee754:
+               val = pmbus_reg2data_ieee754(data, sensor);
+               break;
        case linear:
        default:
                val = pmbus_reg2data_linear(data, sensor);
@@ -749,8 +843,72 @@ static s64 pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor)
        return val;
 }
 
-#define MAX_MANTISSA   (1023 * 1000)
-#define MIN_MANTISSA   (511 * 1000)
+#define MAX_IEEE_MANTISSA      (0x7ff * 1000)
+#define MIN_IEEE_MANTISSA      (0x400 * 1000)
+
+static u16 pmbus_data2reg_ieee754(struct pmbus_data *data,
+                                 struct pmbus_sensor *sensor, long val)
+{
+       u16 exponent = (15 + 10);
+       long mantissa;
+       u16 sign = 0;
+
+       /* simple case */
+       if (val == 0)
+               return 0;
+
+       if (val < 0) {
+               sign = 0x8000;
+               val = -val;
+       }
+
+       /* Power is in uW. Convert to mW before converting. */
+       if (sensor->class == PSC_POWER)
+               val = DIV_ROUND_CLOSEST(val, 1000L);
+
+       /*
+        * For simplicity, convert fan data to milli-units
+        * before calculating the exponent.
+        */
+       if (sensor->class == PSC_FAN)
+               val = val * 1000;
+
+       /* Reduce large mantissa until it fits into 10 bit */
+       while (val > MAX_IEEE_MANTISSA && exponent < 30) {
+               exponent++;
+               val >>= 1;
+       }
+       /*
+        * Increase small mantissa to generate valid 'normal'
+        * number
+        */
+       while (val < MIN_IEEE_MANTISSA && exponent > 1) {
+               exponent--;
+               val <<= 1;
+       }
+
+       /* Convert mantissa from milli-units to units */
+       mantissa = DIV_ROUND_CLOSEST(val, 1000);
+
+       /*
+        * Ensure that the resulting number is within range.
+        * Valid range is 0x400..0x7ff, where bit 10 reflects
+        * the implied high bit in normalized ieee754 numbers.
+        * Set the range to 0x400..0x7ff to reflect this.
+        * The upper bit is then removed by the mask against
+        * 0x3ff in the final assignment.
+        */
+       if (mantissa > 0x7ff)
+               mantissa = 0x7ff;
+       else if (mantissa < 0x400)
+               mantissa = 0x400;
+
+       /* Convert to sign, 5 bit exponent, 10 bit mantissa */
+       return sign | (mantissa & 0x3ff) | ((exponent << 10) & 0x7c00);
+}
+
+#define MAX_LIN_MANTISSA       (1023 * 1000)
+#define MIN_LIN_MANTISSA       (511 * 1000)
 
 static u16 pmbus_data2reg_linear(struct pmbus_data *data,
                                 struct pmbus_sensor *sensor, s64 val)
@@ -796,12 +954,12 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data,
                val = val * 1000LL;
 
        /* Reduce large mantissa until it fits into 10 bit */
-       while (val >= MAX_MANTISSA && exponent < 15) {
+       while (val >= MAX_LIN_MANTISSA && exponent < 15) {
                exponent++;
                val >>= 1;
        }
        /* Increase small mantissa to improve precision */
-       while (val < MIN_MANTISSA && exponent > -15) {
+       while (val < MIN_LIN_MANTISSA && exponent > -15) {
                exponent--;
                val <<= 1;
        }
@@ -875,6 +1033,9 @@ static u16 pmbus_data2reg(struct pmbus_data *data,
        case vid:
                regval = pmbus_data2reg_vid(data, sensor, val);
                break;
+       case ieee754:
+               regval = pmbus_data2reg_ieee754(data, sensor, val);
+               break;
        case linear:
        default:
                regval = pmbus_data2reg_linear(data, sensor, val);
@@ -2369,6 +2530,10 @@ static int pmbus_identify_common(struct i2c_client *client,
                        if (data->info->format[PSC_VOLTAGE_OUT] != direct)
                                return -ENODEV;
                        break;
+               case 3: /* ieee 754 half precision */
+                       if (data->info->format[PSC_VOLTAGE_OUT] != ieee754)
+                               return -ENODEV;
+                       break;
                default:
                        return -ENODEV;
                }
@@ -2388,6 +2553,42 @@ static int pmbus_read_status_word(struct i2c_client *client, int page)
        return _pmbus_read_word_data(client, page, 0xff, PMBUS_STATUS_WORD);
 }
 
+/* PEC attribute support */
+
+static ssize_t pec_show(struct device *dev, struct device_attribute *dummy,
+                       char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       return sysfs_emit(buf, "%d\n", !!(client->flags & I2C_CLIENT_PEC));
+}
+
+static ssize_t pec_store(struct device *dev, struct device_attribute *dummy,
+                        const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       bool enable;
+       int err;
+
+       err = kstrtobool(buf, &enable);
+       if (err < 0)
+               return err;
+
+       if (enable)
+               client->flags |= I2C_CLIENT_PEC;
+       else
+               client->flags &= ~I2C_CLIENT_PEC;
+
+       return count;
+}
+
+static DEVICE_ATTR_RW(pec);
+
+static void pmbus_remove_pec(void *dev)
+{
+       device_remove_file(dev, &dev_attr_pec);
+}
+
 static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
                             struct pmbus_driver_info *info)
 {
@@ -2474,6 +2675,20 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
                        return ret;
        }
 
+       if (client->flags & I2C_CLIENT_PEC) {
+               /*
+                * If I2C_CLIENT_PEC is set here, both the I2C adapter and the
+                * chip support PEC. Add 'pec' attribute to client device to let
+                * the user control it.
+                */
+               ret = device_create_file(dev, &dev_attr_pec);
+               if (ret)
+                       return ret;
+               ret = devm_add_action_or_reset(dev, pmbus_remove_pec, dev);
+               if (ret)
+                       return ret;
+       }
+
        return 0;
 }
 
@@ -2636,6 +2851,58 @@ static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned
        return 0;
 }
 
+static int pmbus_regulator_get_low_margin(struct i2c_client *client, int page)
+{
+       struct pmbus_data *data = i2c_get_clientdata(client);
+       struct pmbus_sensor s = {
+               .page = page,
+               .class = PSC_VOLTAGE_OUT,
+               .convert = true,
+               .data = -1,
+       };
+
+       if (!data->vout_low[page]) {
+               if (pmbus_check_word_register(client, page, PMBUS_MFR_VOUT_MIN))
+                       s.data = _pmbus_read_word_data(client, page, 0xff,
+                                                      PMBUS_MFR_VOUT_MIN);
+               if (s.data < 0) {
+                       s.data = _pmbus_read_word_data(client, page, 0xff,
+                                                      PMBUS_VOUT_MARGIN_LOW);
+                       if (s.data < 0)
+                               return s.data;
+               }
+               data->vout_low[page] = pmbus_reg2data(data, &s);
+       }
+
+       return data->vout_low[page];
+}
+
+static int pmbus_regulator_get_high_margin(struct i2c_client *client, int page)
+{
+       struct pmbus_data *data = i2c_get_clientdata(client);
+       struct pmbus_sensor s = {
+               .page = page,
+               .class = PSC_VOLTAGE_OUT,
+               .convert = true,
+               .data = -1,
+       };
+
+       if (!data->vout_high[page]) {
+               if (pmbus_check_word_register(client, page, PMBUS_MFR_VOUT_MAX))
+                       s.data = _pmbus_read_word_data(client, page, 0xff,
+                                                      PMBUS_MFR_VOUT_MAX);
+               if (s.data < 0) {
+                       s.data = _pmbus_read_word_data(client, page, 0xff,
+                                                      PMBUS_VOUT_MARGIN_HIGH);
+                       if (s.data < 0)
+                               return s.data;
+               }
+               data->vout_high[page] = pmbus_reg2data(data, &s);
+       }
+
+       return data->vout_high[page];
+}
+
 static int pmbus_regulator_get_voltage(struct regulator_dev *rdev)
 {
        struct device *dev = rdev_get_dev(rdev);
@@ -2671,24 +2938,13 @@ static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv,
 
        *selector = 0;
 
-       if (pmbus_check_word_register(client, s.page, PMBUS_MFR_VOUT_MIN))
-               s.data = _pmbus_read_word_data(client, s.page, 0xff, PMBUS_MFR_VOUT_MIN);
-       if (s.data < 0) {
-               s.data = _pmbus_read_word_data(client, s.page, 0xff, PMBUS_VOUT_MARGIN_LOW);
-               if (s.data < 0)
-                       return s.data;
-       }
-       low = pmbus_reg2data(data, &s);
+       low = pmbus_regulator_get_low_margin(client, s.page);
+       if (low < 0)
+               return low;
 
-       s.data = -1;
-       if (pmbus_check_word_register(client, s.page, PMBUS_MFR_VOUT_MAX))
-               s.data = _pmbus_read_word_data(client, s.page, 0xff, PMBUS_MFR_VOUT_MAX);
-       if (s.data < 0) {
-               s.data = _pmbus_read_word_data(client, s.page, 0xff, PMBUS_VOUT_MARGIN_HIGH);
-               if (s.data < 0)
-                       return s.data;
-       }
-       high = pmbus_reg2data(data, &s);
+       high = pmbus_regulator_get_high_margin(client, s.page);
+       if (high < 0)
+               return high;
 
        /* Make sure we are within margins */
        if (low > val)
@@ -2701,6 +2957,35 @@ static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv,
        return _pmbus_write_word_data(client, s.page, PMBUS_VOUT_COMMAND, (u16)val);
 }
 
+static int pmbus_regulator_list_voltage(struct regulator_dev *rdev,
+                                        unsigned int selector)
+{
+       struct device *dev = rdev_get_dev(rdev);
+       struct i2c_client *client = to_i2c_client(dev->parent);
+       int val, low, high;
+
+       if (selector >= rdev->desc->n_voltages ||
+           selector < rdev->desc->linear_min_sel)
+               return -EINVAL;
+
+       selector -= rdev->desc->linear_min_sel;
+       val = DIV_ROUND_CLOSEST(rdev->desc->min_uV +
+                               (rdev->desc->uV_step * selector), 1000); /* convert to mV */
+
+       low = pmbus_regulator_get_low_margin(client, rdev_get_id(rdev));
+       if (low < 0)
+               return low;
+
+       high = pmbus_regulator_get_high_margin(client, rdev_get_id(rdev));
+       if (high < 0)
+               return high;
+
+       if (val >= low && val <= high)
+               return val * 1000; /* unit is uV */
+
+       return 0;
+}
+
 const struct regulator_ops pmbus_regulator_ops = {
        .enable = pmbus_regulator_enable,
        .disable = pmbus_regulator_disable,
@@ -2708,6 +2993,7 @@ const struct regulator_ops pmbus_regulator_ops = {
        .get_error_flags = pmbus_regulator_get_error_flags,
        .get_voltage = pmbus_regulator_get_voltage,
        .set_voltage = pmbus_regulator_set_voltage,
+       .list_voltage = pmbus_regulator_list_voltage,
 };
 EXPORT_SYMBOL_NS_GPL(pmbus_regulator_ops, PMBUS);
 
@@ -2782,41 +3068,33 @@ static int pmbus_debugfs_get_status(void *data, u64 *val)
 DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops_status, pmbus_debugfs_get_status,
                         NULL, "0x%04llx\n");
 
-static int pmbus_debugfs_get_pec(void *data, u64 *val)
-{
-       struct i2c_client *client = data;
-
-       *val = !!(client->flags & I2C_CLIENT_PEC);
-
-       return 0;
-}
-
-static int pmbus_debugfs_set_pec(void *data, u64 val)
+static ssize_t pmbus_debugfs_mfr_read(struct file *file, char __user *buf,
+                                      size_t count, loff_t *ppos)
 {
        int rc;
-       struct i2c_client *client = data;
-
-       if (!val) {
-               client->flags &= ~I2C_CLIENT_PEC;
-               return 0;
-       }
-
-       if (val != 1)
-               return -EINVAL;
+       struct pmbus_debugfs_entry *entry = file->private_data;
+       char data[I2C_SMBUS_BLOCK_MAX + 2] = { 0 };
 
-       rc = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY);
+       rc = pmbus_read_block_data(entry->client, entry->page, entry->reg,
+                                  data);
        if (rc < 0)
                return rc;
 
-       if (!(rc & PB_CAPABILITY_ERROR_CHECK))
-               return -EOPNOTSUPP;
+       /* Add newline at the end of a read data */
+       data[rc] = '\n';
 
-       client->flags |= I2C_CLIENT_PEC;
+       /* Include newline into the length */
+       rc += 1;
 
-       return 0;
+       return simple_read_from_buffer(buf, count, ppos, data, rc);
 }
-DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops_pec, pmbus_debugfs_get_pec,
-                        pmbus_debugfs_set_pec, "%llu\n");
+
+static const struct file_operations pmbus_debugfs_ops_mfr = {
+       .llseek = noop_llseek,
+       .read = pmbus_debugfs_mfr_read,
+       .write = NULL,
+       .open = simple_open,
+};
 
 static void pmbus_remove_debugfs(void *data)
 {
@@ -2846,16 +3124,80 @@ static int pmbus_init_debugfs(struct i2c_client *client,
                return -ENODEV;
        }
 
-       /* Allocate the max possible entries we need. */
+       /*
+        * Allocate the max possible entries we need.
+        * 6 entries device-specific
+        * 10 entries page-specific
+        */
        entries = devm_kcalloc(data->dev,
-                              data->info->pages * 10, sizeof(*entries),
+                              6 + data->info->pages * 10, sizeof(*entries),
                               GFP_KERNEL);
        if (!entries)
                return -ENOMEM;
 
-       debugfs_create_file("pec", 0664, data->debugfs, client,
-                           &pmbus_debugfs_ops_pec);
-
+       /*
+        * Add device-specific entries.
+        * Please note that the PMBUS standard allows all registers to be
+        * page-specific.
+        * To reduce the number of debugfs entries for devices with many pages
+        * assume that values of the following registers are the same for all
+        * pages and report values only for page 0.
+        */
+       if (pmbus_check_block_register(client, 0, PMBUS_MFR_ID)) {
+               entries[idx].client = client;
+               entries[idx].page = 0;
+               entries[idx].reg = PMBUS_MFR_ID;
+               debugfs_create_file("mfr_id", 0444, data->debugfs,
+                                   &entries[idx++],
+                                   &pmbus_debugfs_ops_mfr);
+       }
+
+       if (pmbus_check_block_register(client, 0, PMBUS_MFR_MODEL)) {
+               entries[idx].client = client;
+               entries[idx].page = 0;
+               entries[idx].reg = PMBUS_MFR_MODEL;
+               debugfs_create_file("mfr_model", 0444, data->debugfs,
+                                   &entries[idx++],
+                                   &pmbus_debugfs_ops_mfr);
+       }
+
+       if (pmbus_check_block_register(client, 0, PMBUS_MFR_REVISION)) {
+               entries[idx].client = client;
+               entries[idx].page = 0;
+               entries[idx].reg = PMBUS_MFR_REVISION;
+               debugfs_create_file("mfr_revision", 0444, data->debugfs,
+                                   &entries[idx++],
+                                   &pmbus_debugfs_ops_mfr);
+       }
+
+       if (pmbus_check_block_register(client, 0, PMBUS_MFR_LOCATION)) {
+               entries[idx].client = client;
+               entries[idx].page = 0;
+               entries[idx].reg = PMBUS_MFR_LOCATION;
+               debugfs_create_file("mfr_location", 0444, data->debugfs,
+                                   &entries[idx++],
+                                   &pmbus_debugfs_ops_mfr);
+       }
+
+       if (pmbus_check_block_register(client, 0, PMBUS_MFR_DATE)) {
+               entries[idx].client = client;
+               entries[idx].page = 0;
+               entries[idx].reg = PMBUS_MFR_DATE;
+               debugfs_create_file("mfr_date", 0444, data->debugfs,
+                                   &entries[idx++],
+                                   &pmbus_debugfs_ops_mfr);
+       }
+
+       if (pmbus_check_block_register(client, 0, PMBUS_MFR_SERIAL)) {
+               entries[idx].client = client;
+               entries[idx].page = 0;
+               entries[idx].reg = PMBUS_MFR_SERIAL;
+               debugfs_create_file("mfr_serial", 0444, data->debugfs,
+                                   &entries[idx++],
+                                   &pmbus_debugfs_ops_mfr);
+       }
+
+       /* Add page specific entries */
        for (i = 0; i < data->info->pages; ++i) {
                /* Check accessibility of status register if it's not page 0 */
                if (!i || pmbus_check_status_register(client, i)) {
index 6bc3273..3ad375a 100644 (file)
@@ -148,7 +148,7 @@ static int ucd9200_probe(struct i2c_client *client)
         * This only affects the READ_IOUT and READ_TEMPERATURE2 registers.
         * READ_IOUT will return the sum of currents of all phases of a rail,
         * and READ_TEMPERATURE2 will return the maximum temperature detected
-        * for the the phases of the rail.
+        * for the phases of the rail.
         */
        for (i = 0; i < info->pages; i++) {
                /*
index 3ece53a..de3a088 100644 (file)
@@ -523,6 +523,28 @@ static int __init sch56xx_device_add(int address, const char *name)
        return PTR_ERR_OR_ZERO(sch56xx_pdev);
 }
 
+static const struct dmi_system_id sch56xx_dmi_override_table[] __initconst = {
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS W380"),
+               },
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO P710"),
+               },
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO E9900"),
+               },
+       },
+       { }
+};
+
 /* For autoloading only */
 static const struct dmi_system_id sch56xx_dmi_table[] __initconst = {
        {
@@ -543,16 +565,18 @@ static int __init sch56xx_init(void)
                if (!dmi_check_system(sch56xx_dmi_table))
                        return -ENODEV;
 
-               /*
-                * Some machines like the Esprimo P720 and Esprimo C700 have
-                * onboard devices named " Antiope"/" Theseus" instead of
-                * "Antiope"/"Theseus", so we need to check for both.
-                */
-               if (!dmi_find_device(DMI_DEV_TYPE_OTHER, "Antiope", NULL) &&
-                   !dmi_find_device(DMI_DEV_TYPE_OTHER, " Antiope", NULL) &&
-                   !dmi_find_device(DMI_DEV_TYPE_OTHER, "Theseus", NULL) &&
-                   !dmi_find_device(DMI_DEV_TYPE_OTHER, " Theseus", NULL))
-                       return -ENODEV;
+               if (!dmi_check_system(sch56xx_dmi_override_table)) {
+                       /*
+                        * Some machines like the Esprimo P720 and Esprimo C700 have
+                        * onboard devices named " Antiope"/" Theseus" instead of
+                        * "Antiope"/"Theseus", so we need to check for both.
+                        */
+                       if (!dmi_find_device(DMI_DEV_TYPE_OTHER, "Antiope", NULL) &&
+                           !dmi_find_device(DMI_DEV_TYPE_OTHER, " Antiope", NULL) &&
+                           !dmi_find_device(DMI_DEV_TYPE_OTHER, "Theseus", NULL) &&
+                           !dmi_find_device(DMI_DEV_TYPE_OTHER, " Theseus", NULL))
+                               return -ENODEV;
+               }
        }
 
        /*
index 7f4a639..ae4d142 100644 (file)
@@ -1020,25 +1020,20 @@ err_release_reg:
 static int sht15_remove(struct platform_device *pdev)
 {
        struct sht15_data *data = platform_get_drvdata(pdev);
+       int ret;
 
-       /*
-        * Make sure any reads from the device are done and
-        * prevent new ones beginning
-        */
-       mutex_lock(&data->read_lock);
-       if (sht15_soft_reset(data)) {
-               mutex_unlock(&data->read_lock);
-               return -EFAULT;
-       }
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
+
+       ret = sht15_soft_reset(data);
+       if (ret)
+               dev_err(&pdev->dev, "Failed to reset device (%pe)\n", ERR_PTR(ret));
+
        if (!IS_ERR(data->reg)) {
                regulator_unregister_notifier(data->reg, &data->nb);
                regulator_disable(data->reg);
        }
 
-       mutex_unlock(&data->read_lock);
-
        return 0;
 }
 
index 8bd6435..42762e8 100644 (file)
@@ -140,7 +140,8 @@ static int tps23861_read_temp(struct tps23861_data *data, long *val)
 static int tps23861_read_voltage(struct tps23861_data *data, int channel,
                                 long *val)
 {
-       unsigned int regval;
+       __le16 regval;
+       long raw_val;
        int err;
 
        if (channel < TPS23861_NUM_PORTS) {
@@ -155,7 +156,8 @@ static int tps23861_read_voltage(struct tps23861_data *data, int channel,
        if (err < 0)
                return err;
 
-       *val = (FIELD_GET(VOLTAGE_CURRENT_MASK, regval) * VOLTAGE_LSB) / 1000;
+       raw_val = le16_to_cpu(regval);
+       *val = (FIELD_GET(VOLTAGE_CURRENT_MASK, raw_val) * VOLTAGE_LSB) / 1000;
 
        return 0;
 }
@@ -163,8 +165,9 @@ static int tps23861_read_voltage(struct tps23861_data *data, int channel,
 static int tps23861_read_current(struct tps23861_data *data, int channel,
                                 long *val)
 {
-       unsigned int current_lsb;
-       unsigned int regval;
+       long raw_val, current_lsb;
+       __le16 regval;
+
        int err;
 
        if (data->shunt_resistor == SHUNT_RESISTOR_DEFAULT)
@@ -178,7 +181,8 @@ static int tps23861_read_current(struct tps23861_data *data, int channel,
        if (err < 0)
                return err;
 
-       *val = (FIELD_GET(VOLTAGE_CURRENT_MASK, regval) * current_lsb) / 1000000;
+       raw_val = le16_to_cpu(regval);
+       *val = (FIELD_GET(VOLTAGE_CURRENT_MASK, raw_val) * current_lsb) / 1000000;
 
        return 0;
 }
index a1bae59..708a67c 100644 (file)
@@ -486,7 +486,7 @@ config I2C_BCM_KONA
 
 config I2C_BRCMSTB
        tristate "BRCM Settop/DSL I2C controller"
-       depends on ARCH_BCM2835 || ARCH_BCM4908 || ARCH_BCM_63XX || \
+       depends on ARCH_BCM2835 || ARCH_BCM4908 || ARCH_BCMBCA || \
                   ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST
        default y
        help
index b4c1ad1..630cfa4 100644 (file)
@@ -388,9 +388,9 @@ static irqreturn_t cdns_i2c_slave_isr(void *ptr)
  */
 static irqreturn_t cdns_i2c_master_isr(void *ptr)
 {
-       unsigned int isr_status, avail_bytes, updatetx;
+       unsigned int isr_status, avail_bytes;
        unsigned int bytes_to_send;
-       bool hold_quirk;
+       bool updatetx;
        struct cdns_i2c *id = ptr;
        /* Signal completion only after everything is updated */
        int done_flag = 0;
@@ -410,11 +410,7 @@ static irqreturn_t cdns_i2c_master_isr(void *ptr)
         * Check if transfer size register needs to be updated again for a
         * large data receive operation.
         */
-       updatetx = 0;
-       if (id->recv_count > id->curr_recv_count)
-               updatetx = 1;
-
-       hold_quirk = (id->quirks & CDNS_I2C_BROKEN_HOLD_BIT) && updatetx;
+       updatetx = id->recv_count > id->curr_recv_count;
 
        /* When receiving, handle data interrupt and completion interrupt */
        if (id->p_recv_buf &&
@@ -445,7 +441,7 @@ static irqreturn_t cdns_i2c_master_isr(void *ptr)
                                break;
                        }
 
-                       if (cdns_is_holdquirk(id, hold_quirk))
+                       if (cdns_is_holdquirk(id, updatetx))
                                break;
                }
 
@@ -456,7 +452,7 @@ static irqreturn_t cdns_i2c_master_isr(void *ptr)
                 * maintain transfer size non-zero while performing a large
                 * receive operation.
                 */
-               if (cdns_is_holdquirk(id, hold_quirk)) {
+               if (cdns_is_holdquirk(id, updatetx)) {
                        /* wait while fifo is full */
                        while (cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET) !=
                               (id->curr_recv_count - CDNS_I2C_FIFO_DEPTH))
@@ -478,22 +474,6 @@ static irqreturn_t cdns_i2c_master_isr(void *ptr)
                                                  CDNS_I2C_XFER_SIZE_OFFSET);
                                id->curr_recv_count = id->recv_count;
                        }
-               } else if (id->recv_count && !hold_quirk &&
-                                               !id->curr_recv_count) {
-
-                       /* Set the slave address in address register*/
-                       cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK,
-                                               CDNS_I2C_ADDR_OFFSET);
-
-                       if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) {
-                               cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
-                                               CDNS_I2C_XFER_SIZE_OFFSET);
-                               id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE;
-                       } else {
-                               cdns_i2c_writereg(id->recv_count,
-                                               CDNS_I2C_XFER_SIZE_OFFSET);
-                               id->curr_recv_count = id->recv_count;
-                       }
                }
 
                /* Clear hold (if not repeated start) and signal completion */
@@ -1338,6 +1318,7 @@ static int cdns_i2c_probe(struct platform_device *pdev)
        return 0;
 
 err_clk_dis:
+       clk_notifier_unregister(id->clk, &id->clk_rate_change_nb);
        clk_disable_unprepare(id->clk);
        pm_runtime_disable(&pdev->dev);
        pm_runtime_set_suspended(&pdev->dev);
index e9e2db6..78fb1a4 100644 (file)
@@ -66,7 +66,7 @@
 
 /* IMX I2C registers:
  * the I2C register offset is different between SoCs,
- * to provid support for all these chips, split the
+ * to provide support for all these chips, split the
  * register offset into a fixed base address and a
  * variable shift value, then the full register offset
  * will be calculated by
index 56aa424..815cc56 100644 (file)
@@ -49,7 +49,7 @@
 #define MLXCPLD_LPCI2C_NACK_IND                2
 
 #define MLXCPLD_I2C_FREQ_1000KHZ_SET   0x04
-#define MLXCPLD_I2C_FREQ_400KHZ_SET    0x0c
+#define MLXCPLD_I2C_FREQ_400KHZ_SET    0x0e
 #define MLXCPLD_I2C_FREQ_100KHZ_SET    0x42
 
 enum mlxcpld_i2c_frequency {
index ac8e7d6..39cb1b7 100644 (file)
@@ -161,7 +161,6 @@ static const char *piix4_aux_port_name_sb800 = " port 1";
 
 struct sb800_mmio_cfg {
        void __iomem *addr;
-       struct resource *res;
        bool use_mmio;
 };
 
@@ -179,13 +178,11 @@ static int piix4_sb800_region_request(struct device *dev,
                                      struct sb800_mmio_cfg *mmio_cfg)
 {
        if (mmio_cfg->use_mmio) {
-               struct resource *res;
                void __iomem *addr;
 
-               res = request_mem_region_muxed(SB800_PIIX4_FCH_PM_ADDR,
-                                              SB800_PIIX4_FCH_PM_SIZE,
-                                              "sb800_piix4_smb");
-               if (!res) {
+               if (!request_mem_region_muxed(SB800_PIIX4_FCH_PM_ADDR,
+                                             SB800_PIIX4_FCH_PM_SIZE,
+                                             "sb800_piix4_smb")) {
                        dev_err(dev,
                                "SMBus base address memory region 0x%x already in use.\n",
                                SB800_PIIX4_FCH_PM_ADDR);
@@ -195,12 +192,12 @@ static int piix4_sb800_region_request(struct device *dev,
                addr = ioremap(SB800_PIIX4_FCH_PM_ADDR,
                               SB800_PIIX4_FCH_PM_SIZE);
                if (!addr) {
-                       release_resource(res);
+                       release_mem_region(SB800_PIIX4_FCH_PM_ADDR,
+                                          SB800_PIIX4_FCH_PM_SIZE);
                        dev_err(dev, "SMBus base address mapping failed.\n");
                        return -ENOMEM;
                }
 
-               mmio_cfg->res = res;
                mmio_cfg->addr = addr;
 
                return 0;
@@ -222,7 +219,8 @@ static void piix4_sb800_region_release(struct device *dev,
 {
        if (mmio_cfg->use_mmio) {
                iounmap(mmio_cfg->addr);
-               release_resource(mmio_cfg->res);
+               release_mem_region(SB800_PIIX4_FCH_PM_ADDR,
+                                  SB800_PIIX4_FCH_PM_SIZE);
                return;
        }
 
index 424ef47..3e10171 100644 (file)
 #include <linux/tick.h>
 #include <trace/events/power.h>
 #include <linux/sched.h>
+#include <linux/sched/smt.h>
 #include <linux/notifier.h>
 #include <linux/cpu.h>
 #include <linux/moduleparam.h>
 #include <asm/cpu_device_id.h>
 #include <asm/intel-family.h>
+#include <asm/nospec-branch.h>
 #include <asm/mwait.h>
 #include <asm/msr.h>
+#include <asm/fpu/api.h>
 
 #define INTEL_IDLE_VERSION "0.5.1"
 
@@ -106,6 +109,17 @@ static unsigned int mwait_substates __initdata;
 #define CPUIDLE_FLAG_ALWAYS_ENABLE     BIT(15)
 
 /*
+ * Disable IBRS across idle (when KERNEL_IBRS), is exclusive vs IRQ_ENABLE
+ * above.
+ */
+#define CPUIDLE_FLAG_IBRS              BIT(16)
+
+/*
+ * Initialize large xstate for the C6-state entrance.
+ */
+#define CPUIDLE_FLAG_INIT_XSTATE       BIT(17)
+
+/*
  * MWAIT takes an 8-bit "hint" in EAX "suggesting"
  * the C-state (top nibble) and sub-state (bottom nibble)
  * 0x00 means "MWAIT(C1)", 0x10 means "MWAIT(C2)" etc.
@@ -154,11 +168,42 @@ static __cpuidle int intel_idle_irq(struct cpuidle_device *dev,
 
        raw_local_irq_enable();
        ret = __intel_idle(dev, drv, index);
-       raw_local_irq_disable();
+
+       /*
+        * The lockdep hardirqs state may be changed to 'on' with timer
+        * tick interrupt followed by __do_softirq(). Use local_irq_disable()
+        * to keep the hardirqs state correct.
+        */
+       local_irq_disable();
+
+       return ret;
+}
+
+static __cpuidle int intel_idle_ibrs(struct cpuidle_device *dev,
+                                    struct cpuidle_driver *drv, int index)
+{
+       bool smt_active = sched_smt_active();
+       u64 spec_ctrl = spec_ctrl_current();
+       int ret;
+
+       if (smt_active)
+               wrmsrl(MSR_IA32_SPEC_CTRL, 0);
+
+       ret = __intel_idle(dev, drv, index);
+
+       if (smt_active)
+               wrmsrl(MSR_IA32_SPEC_CTRL, spec_ctrl);
 
        return ret;
 }
 
+static __cpuidle int intel_idle_xstate(struct cpuidle_device *dev,
+                                      struct cpuidle_driver *drv, int index)
+{
+       fpu_idle_fpregs();
+       return __intel_idle(dev, drv, index);
+}
+
 /**
  * intel_idle_s2idle - Ask the processor to enter the given idle state.
  * @dev: cpuidle device of the target CPU.
@@ -174,8 +219,12 @@ static __cpuidle int intel_idle_irq(struct cpuidle_device *dev,
 static __cpuidle int intel_idle_s2idle(struct cpuidle_device *dev,
                                       struct cpuidle_driver *drv, int index)
 {
-       unsigned long eax = flg2MWAIT(drv->states[index].flags);
        unsigned long ecx = 1; /* break on interrupt flag */
+       struct cpuidle_state *state = &drv->states[index];
+       unsigned long eax = flg2MWAIT(state->flags);
+
+       if (state->flags & CPUIDLE_FLAG_INIT_XSTATE)
+               fpu_idle_fpregs();
 
        mwait_idle_with_hints(eax, ecx);
 
@@ -680,7 +729,7 @@ static struct cpuidle_state skl_cstates[] __initdata = {
        {
                .name = "C6",
                .desc = "MWAIT 0x20",
-               .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
+               .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS,
                .exit_latency = 85,
                .target_residency = 200,
                .enter = &intel_idle,
@@ -688,7 +737,7 @@ static struct cpuidle_state skl_cstates[] __initdata = {
        {
                .name = "C7s",
                .desc = "MWAIT 0x33",
-               .flags = MWAIT2flg(0x33) | CPUIDLE_FLAG_TLB_FLUSHED,
+               .flags = MWAIT2flg(0x33) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS,
                .exit_latency = 124,
                .target_residency = 800,
                .enter = &intel_idle,
@@ -696,7 +745,7 @@ static struct cpuidle_state skl_cstates[] __initdata = {
        {
                .name = "C8",
                .desc = "MWAIT 0x40",
-               .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED,
+               .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS,
                .exit_latency = 200,
                .target_residency = 800,
                .enter = &intel_idle,
@@ -704,7 +753,7 @@ static struct cpuidle_state skl_cstates[] __initdata = {
        {
                .name = "C9",
                .desc = "MWAIT 0x50",
-               .flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TLB_FLUSHED,
+               .flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS,
                .exit_latency = 480,
                .target_residency = 5000,
                .enter = &intel_idle,
@@ -712,7 +761,7 @@ static struct cpuidle_state skl_cstates[] __initdata = {
        {
                .name = "C10",
                .desc = "MWAIT 0x60",
-               .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED,
+               .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS,
                .exit_latency = 890,
                .target_residency = 5000,
                .enter = &intel_idle,
@@ -741,7 +790,7 @@ static struct cpuidle_state skx_cstates[] __initdata = {
        {
                .name = "C6",
                .desc = "MWAIT 0x20",
-               .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
+               .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS,
                .exit_latency = 133,
                .target_residency = 600,
                .enter = &intel_idle,
@@ -879,16 +928,6 @@ static struct cpuidle_state adl_l_cstates[] __initdata = {
                .enter = NULL }
 };
 
-/*
- * On Sapphire Rapids Xeon C1 has to be disabled if C1E is enabled, and vice
- * versa. On SPR C1E is enabled only if "C1E promotion" bit is set in
- * MSR_IA32_POWER_CTL. But in this case there effectively no C1, because C1
- * requests are promoted to C1E. If the "C1E promotion" bit is cleared, then
- * both C1 and C1E requests end up with C1, so there is effectively no C1E.
- *
- * By default we enable C1 and disable C1E by marking it with
- * 'CPUIDLE_FLAG_UNUSABLE'.
- */
 static struct cpuidle_state spr_cstates[] __initdata = {
        {
                .name = "C1",
@@ -901,8 +940,7 @@ static struct cpuidle_state spr_cstates[] __initdata = {
        {
                .name = "C1E",
                .desc = "MWAIT 0x01",
-               .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE |
-                                          CPUIDLE_FLAG_UNUSABLE,
+               .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE,
                .exit_latency = 2,
                .target_residency = 4,
                .enter = &intel_idle,
@@ -910,7 +948,8 @@ static struct cpuidle_state spr_cstates[] __initdata = {
        {
                .name = "C6",
                .desc = "MWAIT 0x20",
-               .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
+               .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED |
+                                          CPUIDLE_FLAG_INIT_XSTATE,
                .exit_latency = 290,
                .target_residency = 800,
                .enter = &intel_idle,
@@ -1724,17 +1763,6 @@ static void __init spr_idle_state_table_update(void)
 {
        unsigned long long msr;
 
-       /* Check if user prefers C1E over C1. */
-       if ((preferred_states_mask & BIT(2)) &&
-           !(preferred_states_mask & BIT(1))) {
-               /* Disable C1 and enable C1E. */
-               spr_cstates[0].flags |= CPUIDLE_FLAG_UNUSABLE;
-               spr_cstates[1].flags &= ~CPUIDLE_FLAG_UNUSABLE;
-
-               /* Enable C1E using the "C1E promotion" bit. */
-               c1e_promotion = C1E_PROMOTION_ENABLE;
-       }
-
        /*
         * By default, the C6 state assumes the worst-case scenario of package
         * C6. However, if PC6 is disabled, we update the numbers to match
@@ -1819,6 +1847,15 @@ static void __init intel_idle_init_cstates_icpu(struct cpuidle_driver *drv)
                if (cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_IRQ_ENABLE)
                        drv->states[drv->state_count].enter = intel_idle_irq;
 
+               if (cpu_feature_enabled(X86_FEATURE_KERNEL_IBRS) &&
+                   cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_IBRS) {
+                       WARN_ON_ONCE(cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_IRQ_ENABLE);
+                       drv->states[drv->state_count].enter = intel_idle_ibrs;
+               }
+
+               if (cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_INIT_XSTATE)
+                       drv->states[drv->state_count].enter = intel_idle_xstate;
+
                if ((disabled_states_mask & BIT(drv->state_count)) ||
                    ((icpu->use_acpi || force_use_acpi) &&
                     intel_idle_off_by_default(mwait_hint) &&
index 1c107d6..b985e0d 100644 (file)
@@ -1252,8 +1252,10 @@ struct ib_cm_id *ib_cm_insert_listen(struct ib_device *device,
                return ERR_CAST(cm_id_priv);
 
        err = cm_init_listen(cm_id_priv, service_id, 0);
-       if (err)
+       if (err) {
+               ib_destroy_cm_id(&cm_id_priv->id);
                return ERR_PTR(err);
+       }
 
        spin_lock_irq(&cm_id_priv->lock);
        listen_id_priv = cm_insert_listen(cm_id_priv, cm_handler);
index 638bf4a..646fa86 100644 (file)
@@ -4231,10 +4231,6 @@ void irdma_cm_teardown_connections(struct irdma_device *iwdev, u32 *ipaddr,
        struct irdma_cm_node *cm_node;
        struct list_head teardown_list;
        struct ib_qp_attr attr;
-       struct irdma_sc_vsi *vsi = &iwdev->vsi;
-       struct irdma_sc_qp *sc_qp;
-       struct irdma_qp *qp;
-       int i;
 
        INIT_LIST_HEAD(&teardown_list);
 
@@ -4251,52 +4247,6 @@ void irdma_cm_teardown_connections(struct irdma_device *iwdev, u32 *ipaddr,
                        irdma_cm_disconn(cm_node->iwqp);
                irdma_rem_ref_cm_node(cm_node);
        }
-       if (!iwdev->roce_mode)
-               return;
-
-       INIT_LIST_HEAD(&teardown_list);
-       for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++) {
-               mutex_lock(&vsi->qos[i].qos_mutex);
-               list_for_each_safe (list_node, list_core_temp,
-                                   &vsi->qos[i].qplist) {
-                       u32 qp_ip[4];
-
-                       sc_qp = container_of(list_node, struct irdma_sc_qp,
-                                            list);
-                       if (sc_qp->qp_uk.qp_type != IRDMA_QP_TYPE_ROCE_RC)
-                               continue;
-
-                       qp = sc_qp->qp_uk.back_qp;
-                       if (!disconnect_all) {
-                               if (nfo->ipv4)
-                                       qp_ip[0] = qp->udp_info.local_ipaddr[3];
-                               else
-                                       memcpy(qp_ip,
-                                              &qp->udp_info.local_ipaddr[0],
-                                              sizeof(qp_ip));
-                       }
-
-                       if (disconnect_all ||
-                           (nfo->vlan_id == (qp->udp_info.vlan_tag & VLAN_VID_MASK) &&
-                            !memcmp(qp_ip, ipaddr, nfo->ipv4 ? 4 : 16))) {
-                               spin_lock(&iwdev->rf->qptable_lock);
-                               if (iwdev->rf->qp_table[sc_qp->qp_uk.qp_id]) {
-                                       irdma_qp_add_ref(&qp->ibqp);
-                                       list_add(&qp->teardown_entry,
-                                                &teardown_list);
-                               }
-                               spin_unlock(&iwdev->rf->qptable_lock);
-                       }
-               }
-               mutex_unlock(&vsi->qos[i].qos_mutex);
-       }
-
-       list_for_each_safe (list_node, list_core_temp, &teardown_list) {
-               qp = container_of(list_node, struct irdma_qp, teardown_entry);
-               attr.qp_state = IB_QPS_ERR;
-               irdma_modify_qp_roce(&qp->ibqp, &attr, IB_QP_STATE, NULL);
-               irdma_qp_rem_ref(&qp->ibqp);
-       }
 }
 
 /**
index e46fc11..50299f5 100644 (file)
@@ -201,6 +201,7 @@ void i40iw_init_hw(struct irdma_sc_dev *dev)
        dev->hw_attrs.uk_attrs.max_hw_read_sges = I40IW_MAX_SGE_RD;
        dev->hw_attrs.max_hw_device_pages = I40IW_MAX_PUSH_PAGE_COUNT;
        dev->hw_attrs.uk_attrs.max_hw_inline = I40IW_MAX_INLINE_DATA_SIZE;
+       dev->hw_attrs.page_size_cap = SZ_4K | SZ_2M;
        dev->hw_attrs.max_hw_ird = I40IW_MAX_IRD_SIZE;
        dev->hw_attrs.max_hw_ord = I40IW_MAX_ORD_SIZE;
        dev->hw_attrs.max_hw_wqes = I40IW_MAX_WQ_ENTRIES;
index cf53b17..5986fd9 100644 (file)
@@ -139,6 +139,7 @@ void icrdma_init_hw(struct irdma_sc_dev *dev)
        dev->cqp_db = dev->hw_regs[IRDMA_CQPDB];
        dev->cq_ack_db = dev->hw_regs[IRDMA_CQACK];
        dev->irq_ops = &icrdma_irq_ops;
+       dev->hw_attrs.page_size_cap = SZ_4K | SZ_2M | SZ_1G;
        dev->hw_attrs.max_hw_ird = ICRDMA_MAX_IRD_SIZE;
        dev->hw_attrs.max_hw_ord = ICRDMA_MAX_ORD_SIZE;
        dev->hw_attrs.max_stat_inst = ICRDMA_MAX_STATS_COUNT;
index 46c1233..4789e85 100644 (file)
@@ -127,6 +127,7 @@ struct irdma_hw_attrs {
        u64 max_hw_outbound_msg_size;
        u64 max_hw_inbound_msg_size;
        u64 max_mr_size;
+       u64 page_size_cap;
        u32 min_hw_qp_id;
        u32 min_hw_aeq_size;
        u32 max_hw_aeq_size;
index c4412ec..96135a2 100644 (file)
@@ -32,7 +32,7 @@ static int irdma_query_device(struct ib_device *ibdev,
        props->vendor_part_id = pcidev->device;
 
        props->hw_ver = rf->pcidev->revision;
-       props->page_size_cap = SZ_4K | SZ_2M | SZ_1G;
+       props->page_size_cap = hw_attrs->page_size_cap;
        props->max_mr_size = hw_attrs->max_mr_size;
        props->max_qp = rf->max_qp - rf->used_qps;
        props->max_qp_wr = hw_attrs->max_qp_wr;
@@ -2781,7 +2781,7 @@ static struct ib_mr *irdma_reg_user_mr(struct ib_pd *pd, u64 start, u64 len,
 
        if (req.reg_type == IRDMA_MEMREG_TYPE_MEM) {
                iwmr->page_size = ib_umem_find_best_pgsz(region,
-                                                        SZ_4K | SZ_2M | SZ_1G,
+                                                        iwdev->rf->sc_dev.hw_attrs.page_size_cap,
                                                         virt);
                if (unlikely(!iwmr->page_size)) {
                        kfree(iwmr);
index 8def88c..db9ef3e 100644 (file)
@@ -418,6 +418,7 @@ struct qedr_qp {
        u32 sq_psn;
        u32 qkey;
        u32 dest_qp_num;
+       u8 timeout;
 
        /* Relevant to qps created from kernel space only (ULPs) */
        u8 prev_wqe_size;
index f0f43b6..03ed7c0 100644 (file)
@@ -2613,6 +2613,8 @@ int qedr_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
                                        1 << max_t(int, attr->timeout - 8, 0);
                else
                        qp_params.ack_timeout = 0;
+
+               qp->timeout = attr->timeout;
        }
 
        if (attr_mask & IB_QP_RETRY_CNT) {
@@ -2772,7 +2774,7 @@ int qedr_query_qp(struct ib_qp *ibqp,
        rdma_ah_set_dgid_raw(&qp_attr->ah_attr, &params.dgid.bytes[0]);
        rdma_ah_set_port_num(&qp_attr->ah_attr, 1);
        rdma_ah_set_sl(&qp_attr->ah_attr, 0);
-       qp_attr->timeout = params.timeout;
+       qp_attr->timeout = qp->timeout;
        qp_attr->rnr_retry = params.rnr_retry;
        qp_attr->retry_cnt = params.retry_cnt;
        qp_attr->min_rnr_timer = params.min_rnr_nak_timer;
index 6058abf..7720ea2 100644 (file)
@@ -1282,8 +1282,7 @@ struct srp_terminate_context {
        int scsi_result;
 };
 
-static bool srp_terminate_cmd(struct scsi_cmnd *scmnd, void *context_ptr,
-                             bool reserved)
+static bool srp_terminate_cmd(struct scsi_cmnd *scmnd, void *context_ptr)
 {
        struct srp_terminate_context *context = context_ptr;
        struct srp_target_port *target = context->srp_target;
index 3ad9870..aa45a9f 100644 (file)
@@ -900,6 +900,11 @@ static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)
        } else {
                dev_warn(dev, "Unexpected ACPI resources: gpio_count %d, gpio_int_idx %d\n",
                         ts->gpio_count, ts->gpio_int_idx);
+               /*
+                * On some devices _PS0 does a reset for us and
+                * sometimes this is necessary for things to work.
+                */
+               acpi_device_fix_up_power(ACPI_COMPANION(dev));
                return -EINVAL;
        }
 
index 43c521f..3dda6ea 100644 (file)
@@ -1654,6 +1654,9 @@ static int usbtouch_probe(struct usb_interface *intf,
        if (id->driver_info == DEVTYPE_IGNORE)
                return -ENODEV;
 
+       if (id->driver_info >= ARRAY_SIZE(usbtouch_dev_info))
+               return -ENODEV;
+
        endpoint = usbtouch_get_input_endpoint(intf->cur_altsetting);
        if (!endpoint)
                return -ENXIO;
index 2757c77..f51ab56 100644 (file)
@@ -758,7 +758,9 @@ batt_err:
 
 static int wm97xx_mfd_remove(struct platform_device *pdev)
 {
-       return wm97xx_remove(&pdev->dev);
+       wm97xx_remove(&pdev->dev);
+
+       return 0;
 }
 
 static int __maybe_unused wm97xx_suspend(struct device *dev)
index e285a22..51bd66a 100644 (file)
@@ -194,7 +194,7 @@ hyperv_root_ir_compose_msi_msg(struct irq_data *irq_data, struct msi_msg *msg)
        u32 vector;
        struct irq_cfg *cfg;
        int ioapic_id;
-       struct cpumask *affinity;
+       const struct cpumask *affinity;
        int cpu;
        struct hv_interrupt_entry entry;
        struct hyperv_root_ir_data *data = irq_data->chip_data;
index 592c1e1..9699ca1 100644 (file)
@@ -382,7 +382,7 @@ static int dmar_pci_bus_notifier(struct notifier_block *nb,
 
 static struct notifier_block dmar_pci_bus_nb = {
        .notifier_call = dmar_pci_bus_notifier,
-       .priority = INT_MIN,
+       .priority = 1,
 };
 
 static struct dmar_drhd_unit *
index 4401659..5c0dce7 100644 (file)
@@ -320,30 +320,6 @@ EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped);
 DEFINE_SPINLOCK(device_domain_lock);
 static LIST_HEAD(device_domain_list);
 
-/*
- * Iterate over elements in device_domain_list and call the specified
- * callback @fn against each element.
- */
-int for_each_device_domain(int (*fn)(struct device_domain_info *info,
-                                    void *data), void *data)
-{
-       int ret = 0;
-       unsigned long flags;
-       struct device_domain_info *info;
-
-       spin_lock_irqsave(&device_domain_lock, flags);
-       list_for_each_entry(info, &device_domain_list, global) {
-               ret = fn(info, data);
-               if (ret) {
-                       spin_unlock_irqrestore(&device_domain_lock, flags);
-                       return ret;
-               }
-       }
-       spin_unlock_irqrestore(&device_domain_lock, flags);
-
-       return 0;
-}
-
 const struct iommu_ops intel_iommu_ops;
 
 static bool translation_pre_enabled(struct intel_iommu *iommu)
index cb4c1d0..17cad7c 100644 (file)
@@ -86,54 +86,6 @@ void vcmd_free_pasid(struct intel_iommu *iommu, u32 pasid)
 /*
  * Per device pasid table management:
  */
-static inline void
-device_attach_pasid_table(struct device_domain_info *info,
-                         struct pasid_table *pasid_table)
-{
-       info->pasid_table = pasid_table;
-       list_add(&info->table, &pasid_table->dev);
-}
-
-static inline void
-device_detach_pasid_table(struct device_domain_info *info,
-                         struct pasid_table *pasid_table)
-{
-       info->pasid_table = NULL;
-       list_del(&info->table);
-}
-
-struct pasid_table_opaque {
-       struct pasid_table      **pasid_table;
-       int                     segment;
-       int                     bus;
-       int                     devfn;
-};
-
-static int search_pasid_table(struct device_domain_info *info, void *opaque)
-{
-       struct pasid_table_opaque *data = opaque;
-
-       if (info->iommu->segment == data->segment &&
-           info->bus == data->bus &&
-           info->devfn == data->devfn &&
-           info->pasid_table) {
-               *data->pasid_table = info->pasid_table;
-               return 1;
-       }
-
-       return 0;
-}
-
-static int get_alias_pasid_table(struct pci_dev *pdev, u16 alias, void *opaque)
-{
-       struct pasid_table_opaque *data = opaque;
-
-       data->segment = pci_domain_nr(pdev->bus);
-       data->bus = PCI_BUS_NUM(alias);
-       data->devfn = alias & 0xff;
-
-       return for_each_device_domain(&search_pasid_table, data);
-}
 
 /*
  * Allocate a pasid table for @dev. It should be called in a
@@ -143,28 +95,18 @@ int intel_pasid_alloc_table(struct device *dev)
 {
        struct device_domain_info *info;
        struct pasid_table *pasid_table;
-       struct pasid_table_opaque data;
        struct page *pages;
        u32 max_pasid = 0;
-       int ret, order;
-       int size;
+       int order, size;
 
        might_sleep();
        info = dev_iommu_priv_get(dev);
        if (WARN_ON(!info || !dev_is_pci(dev) || info->pasid_table))
                return -EINVAL;
 
-       /* DMA alias device already has a pasid table, use it: */
-       data.pasid_table = &pasid_table;
-       ret = pci_for_each_dma_alias(to_pci_dev(dev),
-                                    &get_alias_pasid_table, &data);
-       if (ret)
-               goto attach_out;
-
        pasid_table = kzalloc(sizeof(*pasid_table), GFP_KERNEL);
        if (!pasid_table)
                return -ENOMEM;
-       INIT_LIST_HEAD(&pasid_table->dev);
 
        if (info->pasid_supported)
                max_pasid = min_t(u32, pci_max_pasids(to_pci_dev(dev)),
@@ -182,9 +124,7 @@ int intel_pasid_alloc_table(struct device *dev)
        pasid_table->table = page_address(pages);
        pasid_table->order = order;
        pasid_table->max_pasid = 1 << (order + PAGE_SHIFT + 3);
-
-attach_out:
-       device_attach_pasid_table(info, pasid_table);
+       info->pasid_table = pasid_table;
 
        return 0;
 }
@@ -202,10 +142,7 @@ void intel_pasid_free_table(struct device *dev)
                return;
 
        pasid_table = info->pasid_table;
-       device_detach_pasid_table(info, pasid_table);
-
-       if (!list_empty(&pasid_table->dev))
-               return;
+       info->pasid_table = NULL;
 
        /* Free scalable mode PASID directory tables: */
        dir = pasid_table->table;
index 583ea67..bf5b937 100644 (file)
@@ -74,7 +74,6 @@ struct pasid_table {
        void                    *table;         /* pasid table pointer */
        int                     order;          /* page order of pasid table */
        u32                     max_pasid;      /* max pasid */
-       struct list_head        dev;            /* device list */
 };
 
 /* Get PRESENT bit of a PASID directory entry. */
index 1f23a6b..66b9fa4 100644 (file)
@@ -8,7 +8,7 @@ config IRQCHIP
 config ARM_GIC
        bool
        select IRQ_DOMAIN_HIERARCHY
-       select GENERIC_IRQ_EFFECTIVE_AFF_MASK
+       select GENERIC_IRQ_EFFECTIVE_AFF_MASK if SMP
 
 config ARM_GIC_PM
        bool
@@ -34,7 +34,7 @@ config ARM_GIC_V3
        bool
        select IRQ_DOMAIN_HIERARCHY
        select PARTITION_PERCPU
-       select GENERIC_IRQ_EFFECTIVE_AFF_MASK
+       select GENERIC_IRQ_EFFECTIVE_AFF_MASK if SMP
 
 config ARM_GIC_V3_ITS
        bool
@@ -76,7 +76,7 @@ config ARMADA_370_XP_IRQ
        bool
        select GENERIC_IRQ_CHIP
        select PCI_MSI if PCI
-       select GENERIC_IRQ_EFFECTIVE_AFF_MASK
+       select GENERIC_IRQ_EFFECTIVE_AFF_MASK if SMP
 
 config ALPINE_MSI
        bool
@@ -112,7 +112,7 @@ config BCM6345_L1_IRQ
        bool
        select GENERIC_IRQ_CHIP
        select IRQ_DOMAIN
-       select GENERIC_IRQ_EFFECTIVE_AFF_MASK
+       select GENERIC_IRQ_EFFECTIVE_AFF_MASK if SMP
 
 config BCM7038_L1_IRQ
        tristate "Broadcom STB 7038-style L1/L2 interrupt controller driver"
@@ -120,7 +120,7 @@ config BCM7038_L1_IRQ
        default ARCH_BRCMSTB || BMIPS_GENERIC
        select GENERIC_IRQ_CHIP
        select IRQ_DOMAIN
-       select GENERIC_IRQ_EFFECTIVE_AFF_MASK
+       select GENERIC_IRQ_EFFECTIVE_AFF_MASK if SMP
 
 config BCM7120_L2_IRQ
        tristate "Broadcom STB 7120-style L2 interrupt controller driver"
@@ -177,9 +177,9 @@ config MADERA_IRQ
 config IRQ_MIPS_CPU
        bool
        select GENERIC_IRQ_CHIP
-       select GENERIC_IRQ_IPI if SYS_SUPPORTS_MULTITHREADING
+       select GENERIC_IRQ_IPI if SMP && SYS_SUPPORTS_MULTITHREADING
        select IRQ_DOMAIN
-       select GENERIC_IRQ_EFFECTIVE_AFF_MASK
+       select GENERIC_IRQ_EFFECTIVE_AFF_MASK if SMP
 
 config CLPS711X_IRQCHIP
        bool
@@ -242,6 +242,14 @@ config RENESAS_RZA1_IRQC
          Enable support for the Renesas RZ/A1 Interrupt Controller, to use up
          to 8 external interrupts with configurable sense select.
 
+config RENESAS_RZG2L_IRQC
+       bool "Renesas RZ/G2L (and alike SoC) IRQC support" if COMPILE_TEST
+       select GENERIC_IRQ_CHIP
+       select IRQ_DOMAIN_HIERARCHY
+       help
+         Enable support for the Renesas RZ/G2L (and alike SoC) Interrupt Controller
+         for external devices.
+
 config SL28CPLD_INTC
        bool "Kontron sl28cpld IRQ controller"
        depends on MFD_SL28CPLD=y || COMPILE_TEST
@@ -294,11 +302,11 @@ config VERSATILE_FPGA_IRQ_NR
 config XTENSA_MX
        bool
        select IRQ_DOMAIN
-       select GENERIC_IRQ_EFFECTIVE_AFF_MASK
+       select GENERIC_IRQ_EFFECTIVE_AFF_MASK if SMP
 
 config XILINX_INTC
        bool "Xilinx Interrupt Controller IP"
-       depends on OF
+       depends on OF_ADDRESS
        select IRQ_DOMAIN
        help
          Support for the Xilinx Interrupt Controller IP core.
@@ -322,7 +330,8 @@ config KEYSTONE_IRQ
 
 config MIPS_GIC
        bool
-       select GENERIC_IRQ_IPI
+       select GENERIC_IRQ_IPI if SMP
+       select IRQ_DOMAIN_HIERARCHY
        select MIPS_CM
 
 config INGENIC_IRQ
@@ -530,6 +539,7 @@ config SIFIVE_PLIC
        bool "SiFive Platform-Level Interrupt Controller"
        depends on RISCV
        select IRQ_DOMAIN_HIERARCHY
+       select GENERIC_IRQ_EFFECTIVE_AFF_MASK if SMP
        help
           This enables support for the PLIC chip found in SiFive (and
           potentially other) RISC-V systems.  The PLIC controls devices
@@ -546,6 +556,16 @@ config EXYNOS_IRQ_COMBINER
          Say yes here to add support for the IRQ combiner devices embedded
          in Samsung Exynos chips.
 
+config IRQ_LOONGARCH_CPU
+       bool
+       select GENERIC_IRQ_CHIP
+       select IRQ_DOMAIN
+       select GENERIC_IRQ_EFFECTIVE_AFF_MASK
+       help
+         Support for the LoongArch CPU Interrupt Controller. For details of
+         irq chip hierarchy on LoongArch platforms please read the document
+         Documentation/loongarch/irq-chip-model.rst.
+
 config LOONGSON_LIOINTC
        bool "Loongson Local I/O Interrupt Controller"
        depends on MACH_LOONGSON64
@@ -555,6 +575,16 @@ config LOONGSON_LIOINTC
        help
          Support for the Loongson Local I/O Interrupt Controller.
 
+config LOONGSON_EIOINTC
+       bool "Loongson Extend I/O Interrupt Controller"
+       depends on LOONGARCH
+       depends on MACH_LOONGSON64
+       default MACH_LOONGSON64
+       select IRQ_DOMAIN_HIERARCHY
+       select GENERIC_IRQ_CHIP
+       help
+         Support for the Loongson3 Extend I/O Interrupt Vector Controller.
+
 config LOONGSON_HTPIC
        bool "Loongson3 HyperTransport PIC Controller"
        depends on MACH_LOONGSON64 && MIPS
@@ -574,7 +604,7 @@ config LOONGSON_HTVEC
 
 config LOONGSON_PCH_PIC
        bool "Loongson PCH PIC Controller"
-       depends on MACH_LOONGSON64 || COMPILE_TEST
+       depends on MACH_LOONGSON64
        default MACH_LOONGSON64
        select IRQ_DOMAIN_HIERARCHY
        select IRQ_FASTEOI_HIERARCHY_HANDLERS
@@ -583,7 +613,7 @@ config LOONGSON_PCH_PIC
 
 config LOONGSON_PCH_MSI
        bool "Loongson PCH MSI Controller"
-       depends on MACH_LOONGSON64 || COMPILE_TEST
+       depends on MACH_LOONGSON64
        depends on PCI
        default MACH_LOONGSON64
        select IRQ_DOMAIN_HIERARCHY
@@ -591,6 +621,14 @@ config LOONGSON_PCH_MSI
        help
          Support for the Loongson PCH MSI Controller.
 
+config LOONGSON_PCH_LPC
+       bool "Loongson PCH LPC Controller"
+       depends on MACH_LOONGSON64
+       default (MACH_LOONGSON64 && LOONGARCH)
+       select IRQ_DOMAIN_HIERARCHY
+       help
+         Support for the Loongson PCH LPC Controller.
+
 config MST_IRQ
        bool "MStar Interrupt Controller"
        depends on ARCH_MEDIATEK || ARCH_MSTARV7 || COMPILE_TEST
@@ -627,4 +665,13 @@ config MCHP_EIC
        help
          Support for Microchip External Interrupt Controller.
 
+config SUNPLUS_SP7021_INTC
+       bool "Sunplus SP7021 interrupt controller" if COMPILE_TEST
+       default SOC_SP7021
+       help
+         Support for the Sunplus SP7021 Interrupt Controller IP core.
+         SP7021 SoC has 2 Chips: C-Chip & P-Chip. This is used as a
+         chained controller, routing all interrupt source in P-Chip to
+         the primary controller on C-Chip.
+
 endmenu
index 5b67450..b6acbca 100644 (file)
@@ -51,6 +51,7 @@ obj-$(CONFIG_RDA_INTC)                        += irq-rda-intc.o
 obj-$(CONFIG_RENESAS_INTC_IRQPIN)      += irq-renesas-intc-irqpin.o
 obj-$(CONFIG_RENESAS_IRQC)             += irq-renesas-irqc.o
 obj-$(CONFIG_RENESAS_RZA1_IRQC)                += irq-renesas-rza1.o
+obj-$(CONFIG_RENESAS_RZG2L_IRQC)       += irq-renesas-rzg2l.o
 obj-$(CONFIG_VERSATILE_FPGA_IRQ)       += irq-versatile-fpga.o
 obj-$(CONFIG_ARCH_NSPIRE)              += irq-zevio.o
 obj-$(CONFIG_ARCH_VT8500)              += irq-vt8500.o
@@ -103,11 +104,14 @@ obj-$(CONFIG_LS1X_IRQ)                    += irq-ls1x.o
 obj-$(CONFIG_TI_SCI_INTR_IRQCHIP)      += irq-ti-sci-intr.o
 obj-$(CONFIG_TI_SCI_INTA_IRQCHIP)      += irq-ti-sci-inta.o
 obj-$(CONFIG_TI_PRUSS_INTC)            += irq-pruss-intc.o
+obj-$(CONFIG_IRQ_LOONGARCH_CPU)                += irq-loongarch-cpu.o
 obj-$(CONFIG_LOONGSON_LIOINTC)         += irq-loongson-liointc.o
+obj-$(CONFIG_LOONGSON_EIOINTC)         += irq-loongson-eiointc.o
 obj-$(CONFIG_LOONGSON_HTPIC)           += irq-loongson-htpic.o
 obj-$(CONFIG_LOONGSON_HTVEC)           += irq-loongson-htvec.o
 obj-$(CONFIG_LOONGSON_PCH_PIC)         += irq-loongson-pch-pic.o
 obj-$(CONFIG_LOONGSON_PCH_MSI)         += irq-loongson-pch-msi.o
+obj-$(CONFIG_LOONGSON_PCH_LPC)         += irq-loongson-pch-lpc.o
 obj-$(CONFIG_MST_IRQ)                  += irq-mst-intc.o
 obj-$(CONFIG_SL28CPLD_INTC)            += irq-sl28cpld.o
 obj-$(CONFIG_MACH_REALTEK_RTL)         += irq-realtek-rtl.o
@@ -115,3 +119,4 @@ obj-$(CONFIG_WPCM450_AIC)           += irq-wpcm450-aic.o
 obj-$(CONFIG_IRQ_IDT3243X)             += irq-idt3243x.o
 obj-$(CONFIG_APPLE_AIC)                        += irq-apple-aic.o
 obj-$(CONFIG_MCHP_EIC)                 += irq-mchp-eic.o
+obj-$(CONFIG_SUNPLUS_SP7021_INTC)      += irq-sp7021-intc.o
index 5ac8318..1c2813a 100644 (file)
 #define AIC_TMR_EL02_PHYS      AIC_TMR_GUEST_PHYS
 #define AIC_TMR_EL02_VIRT      AIC_TMR_GUEST_VIRT
 
-DEFINE_STATIC_KEY_TRUE(use_fast_ipi);
+static DEFINE_STATIC_KEY_TRUE(use_fast_ipi);
 
 struct aic_info {
        int version;
index 142a743..6899e37 100644 (file)
@@ -216,11 +216,11 @@ static int bcm6345_l1_set_affinity(struct irq_data *d,
                enabled = intc->cpus[old_cpu]->enable_cache[word] & mask;
                if (enabled)
                        __bcm6345_l1_mask(d);
-               cpumask_copy(irq_data_get_affinity_mask(d), dest);
+               irq_data_update_affinity(d, dest);
                if (enabled)
                        __bcm6345_l1_unmask(d);
        } else {
-               cpumask_copy(irq_data_get_affinity_mask(d), dest);
+               irq_data_update_affinity(d, dest);
        }
        raw_spin_unlock_irqrestore(&intc->lock, flags);
 
index 5c1cf90..262658f 100644 (file)
@@ -1783,7 +1783,7 @@ static void gic_enable_nmi_support(void)
         * the security state of the GIC (controlled by the GICD_CTRL.DS bit)
         * and if Group 0 interrupts can be delivered to Linux in the non-secure
         * world as FIQs (controlled by the SCR_EL3.FIQ bit). These affect the
-        * the ICC_PMR_EL1 register and the priority that software assigns to
+        * ICC_PMR_EL1 register and the priority that software assigns to
         * interrupts:
         *
         * GICD_CTRL.DS | SCR_EL3.FIQ | ICC_PMR_EL1 | Group 1 priority
@@ -2042,15 +2042,40 @@ static void __init gic_of_setup_kvm_info(struct device_node *node)
        vgic_set_kvm_info(&gic_v3_kvm_info);
 }
 
+static void gic_request_region(resource_size_t base, resource_size_t size,
+                              const char *name)
+{
+       if (!request_mem_region(base, size, name))
+               pr_warn_once(FW_BUG "%s region %pa has overlapping address\n",
+                            name, &base);
+}
+
+static void __iomem *gic_of_iomap(struct device_node *node, int idx,
+                                 const char *name, struct resource *res)
+{
+       void __iomem *base;
+       int ret;
+
+       ret = of_address_to_resource(node, idx, res);
+       if (ret)
+               return IOMEM_ERR_PTR(ret);
+
+       gic_request_region(res->start, resource_size(res), name);
+       base = of_iomap(node, idx);
+
+       return base ?: IOMEM_ERR_PTR(-ENOMEM);
+}
+
 static int __init gic_of_init(struct device_node *node, struct device_node *parent)
 {
        void __iomem *dist_base;
        struct redist_region *rdist_regs;
+       struct resource res;
        u64 redist_stride;
        u32 nr_redist_regions;
        int err, i;
 
-       dist_base = of_io_request_and_map(node, 0, "GICD");
+       dist_base = gic_of_iomap(node, 0, "GICD", &res);
        if (IS_ERR(dist_base)) {
                pr_err("%pOF: unable to map gic dist registers\n", node);
                return PTR_ERR(dist_base);
@@ -2073,12 +2098,8 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
        }
 
        for (i = 0; i < nr_redist_regions; i++) {
-               struct resource res;
-               int ret;
-
-               ret = of_address_to_resource(node, 1 + i, &res);
-               rdist_regs[i].redist_base = of_io_request_and_map(node, 1 + i, "GICR");
-               if (ret || IS_ERR(rdist_regs[i].redist_base)) {
+               rdist_regs[i].redist_base = gic_of_iomap(node, 1 + i, "GICR", &res);
+               if (IS_ERR(rdist_regs[i].redist_base)) {
                        pr_err("%pOF: couldn't map region %d\n", node, i);
                        err = -ENODEV;
                        goto out_unmap_rdist;
@@ -2151,7 +2172,7 @@ gic_acpi_parse_madt_redist(union acpi_subtable_headers *header,
                pr_err("Couldn't map GICR region @%llx\n", redist->base_address);
                return -ENOMEM;
        }
-       request_mem_region(redist->base_address, redist->length, "GICR");
+       gic_request_region(redist->base_address, redist->length, "GICR");
 
        gic_acpi_register_redist(redist->base_address, redist_base);
        return 0;
@@ -2174,7 +2195,7 @@ gic_acpi_parse_madt_gicc(union acpi_subtable_headers *header,
        redist_base = ioremap(gicc->gicr_base_address, size);
        if (!redist_base)
                return -ENOMEM;
-       request_mem_region(gicc->gicr_base_address, size, "GICR");
+       gic_request_region(gicc->gicr_base_address, size, "GICR");
 
        gic_acpi_register_redist(gicc->gicr_base_address, redist_base);
        return 0;
@@ -2360,11 +2381,17 @@ static void __init gic_acpi_setup_kvm_info(void)
        vgic_set_kvm_info(&gic_v3_kvm_info);
 }
 
+static struct fwnode_handle *gsi_domain_handle;
+
+static struct fwnode_handle *gic_v3_get_gsi_domain_id(u32 gsi)
+{
+       return gsi_domain_handle;
+}
+
 static int __init
 gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end)
 {
        struct acpi_madt_generic_distributor *dist;
-       struct fwnode_handle *domain_handle;
        size_t size;
        int i, err;
 
@@ -2376,7 +2403,7 @@ gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end)
                pr_err("Unable to map GICD registers\n");
                return -ENOMEM;
        }
-       request_mem_region(dist->base_address, ACPI_GICV3_DIST_MEM_SIZE, "GICD");
+       gic_request_region(dist->base_address, ACPI_GICV3_DIST_MEM_SIZE, "GICD");
 
        err = gic_validate_dist_version(acpi_data.dist_base);
        if (err) {
@@ -2396,18 +2423,18 @@ gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end)
        if (err)
                goto out_redist_unmap;
 
-       domain_handle = irq_domain_alloc_fwnode(&dist->base_address);
-       if (!domain_handle) {
+       gsi_domain_handle = irq_domain_alloc_fwnode(&dist->base_address);
+       if (!gsi_domain_handle) {
                err = -ENOMEM;
                goto out_redist_unmap;
        }
 
        err = gic_init_bases(acpi_data.dist_base, acpi_data.redist_regs,
-                            acpi_data.nr_redist_regions, 0, domain_handle);
+                            acpi_data.nr_redist_regions, 0, gsi_domain_handle);
        if (err)
                goto out_fwhandle_free;
 
-       acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle);
+       acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v3_get_gsi_domain_id);
 
        if (static_branch_likely(&supports_deactivate_key))
                gic_acpi_setup_kvm_info();
@@ -2415,7 +2442,7 @@ gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end)
        return 0;
 
 out_fwhandle_free:
-       irq_domain_free_fwnode(domain_handle);
+       irq_domain_free_fwnode(gsi_domain_handle);
 out_redist_unmap:
        for (i = 0; i < acpi_data.nr_redist_regions; i++)
                if (acpi_data.redist_regs[i].redist_base)
index 820404c..4c7bae0 100644 (file)
@@ -1682,11 +1682,17 @@ static void __init gic_acpi_setup_kvm_info(void)
        vgic_set_kvm_info(&gic_v2_kvm_info);
 }
 
+static struct fwnode_handle *gsi_domain_handle;
+
+static struct fwnode_handle *gic_v2_get_gsi_domain_id(u32 gsi)
+{
+       return gsi_domain_handle;
+}
+
 static int __init gic_v2_acpi_init(union acpi_subtable_headers *header,
                                   const unsigned long end)
 {
        struct acpi_madt_generic_distributor *dist;
-       struct fwnode_handle *domain_handle;
        struct gic_chip_data *gic = &gic_data[0];
        int count, ret;
 
@@ -1724,22 +1730,22 @@ static int __init gic_v2_acpi_init(union acpi_subtable_headers *header,
        /*
         * Initialize GIC instance zero (no multi-GIC support).
         */
-       domain_handle = irq_domain_alloc_fwnode(&dist->base_address);
-       if (!domain_handle) {
+       gsi_domain_handle = irq_domain_alloc_fwnode(&dist->base_address);
+       if (!gsi_domain_handle) {
                pr_err("Unable to allocate domain handle\n");
                gic_teardown(gic);
                return -ENOMEM;
        }
 
-       ret = __gic_init_bases(gic, domain_handle);
+       ret = __gic_init_bases(gic, gsi_domain_handle);
        if (ret) {
                pr_err("Failed to initialise GIC\n");
-               irq_domain_free_fwnode(domain_handle);
+               irq_domain_free_fwnode(gsi_domain_handle);
                gic_teardown(gic);
                return ret;
        }
 
-       acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle);
+       acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v2_get_gsi_domain_id);
 
        if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
                gicv2m_init(NULL, gic_data[0].domain);
diff --git a/drivers/irqchip/irq-loongarch-cpu.c b/drivers/irqchip/irq-loongarch-cpu.c
new file mode 100644 (file)
index 0000000..327f3ab
--- /dev/null
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+
+#include <asm/loongarch.h>
+#include <asm/setup.h>
+
+static struct irq_domain *irq_domain;
+struct fwnode_handle *cpuintc_handle;
+
+static u32 lpic_gsi_to_irq(u32 gsi)
+{
+       /* Only pch irqdomain transferring is required for LoongArch. */
+       if (gsi >= GSI_MIN_PCH_IRQ && gsi <= GSI_MAX_PCH_IRQ)
+               return acpi_register_gsi(NULL, gsi, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_HIGH);
+
+       return 0;
+}
+
+static struct fwnode_handle *lpic_get_gsi_domain_id(u32 gsi)
+{
+       int id;
+       struct fwnode_handle *domain_handle = NULL;
+
+       switch (gsi) {
+       case GSI_MIN_CPU_IRQ ... GSI_MAX_CPU_IRQ:
+               if (liointc_handle)
+                       domain_handle = liointc_handle;
+               break;
+
+       case GSI_MIN_LPC_IRQ ... GSI_MAX_LPC_IRQ:
+               if (pch_lpc_handle)
+                       domain_handle = pch_lpc_handle;
+               break;
+
+       case GSI_MIN_PCH_IRQ ... GSI_MAX_PCH_IRQ:
+               id = find_pch_pic(gsi);
+               if (id >= 0 && pch_pic_handle[id])
+                       domain_handle = pch_pic_handle[id];
+               break;
+       }
+
+       return domain_handle;
+}
+
+static void mask_loongarch_irq(struct irq_data *d)
+{
+       clear_csr_ecfg(ECFGF(d->hwirq));
+}
+
+static void unmask_loongarch_irq(struct irq_data *d)
+{
+       set_csr_ecfg(ECFGF(d->hwirq));
+}
+
+static struct irq_chip cpu_irq_controller = {
+       .name           = "CPUINTC",
+       .irq_mask       = mask_loongarch_irq,
+       .irq_unmask     = unmask_loongarch_irq,
+};
+
+static void handle_cpu_irq(struct pt_regs *regs)
+{
+       int hwirq;
+       unsigned int estat = read_csr_estat() & CSR_ESTAT_IS;
+
+       while ((hwirq = ffs(estat))) {
+               estat &= ~BIT(hwirq - 1);
+               generic_handle_domain_irq(irq_domain, hwirq - 1);
+       }
+}
+
+static int loongarch_cpu_intc_map(struct irq_domain *d, unsigned int irq,
+                            irq_hw_number_t hwirq)
+{
+       irq_set_noprobe(irq);
+       irq_set_chip_and_handler(irq, &cpu_irq_controller, handle_percpu_irq);
+
+       return 0;
+}
+
+static const struct irq_domain_ops loongarch_cpu_intc_irq_domain_ops = {
+       .map = loongarch_cpu_intc_map,
+       .xlate = irq_domain_xlate_onecell,
+};
+
+static int __init
+liointc_parse_madt(union acpi_subtable_headers *header,
+                      const unsigned long end)
+{
+       struct acpi_madt_lio_pic *liointc_entry = (struct acpi_madt_lio_pic *)header;
+
+       return liointc_acpi_init(irq_domain, liointc_entry);
+}
+
+static int __init
+eiointc_parse_madt(union acpi_subtable_headers *header,
+                      const unsigned long end)
+{
+       struct acpi_madt_eio_pic *eiointc_entry = (struct acpi_madt_eio_pic *)header;
+
+       return eiointc_acpi_init(irq_domain, eiointc_entry);
+}
+
+static int __init acpi_cascade_irqdomain_init(void)
+{
+       acpi_table_parse_madt(ACPI_MADT_TYPE_LIO_PIC,
+                             liointc_parse_madt, 0);
+       acpi_table_parse_madt(ACPI_MADT_TYPE_EIO_PIC,
+                             eiointc_parse_madt, 0);
+       return 0;
+}
+
+static int __init cpuintc_acpi_init(union acpi_subtable_headers *header,
+                                  const unsigned long end)
+{
+       if (irq_domain)
+               return 0;
+
+       /* Mask interrupts. */
+       clear_csr_ecfg(ECFG0_IM);
+       clear_csr_estat(ESTATF_IP);
+
+       cpuintc_handle = irq_domain_alloc_fwnode(NULL);
+       irq_domain = irq_domain_create_linear(cpuintc_handle, EXCCODE_INT_NUM,
+                                       &loongarch_cpu_intc_irq_domain_ops, NULL);
+
+       if (!irq_domain)
+               panic("Failed to add irqdomain for LoongArch CPU");
+
+       set_handle_irq(&handle_cpu_irq);
+       acpi_set_irq_model(ACPI_IRQ_MODEL_LPIC, lpic_get_gsi_domain_id);
+       acpi_set_gsi_to_irq_fallback(lpic_gsi_to_irq);
+       acpi_cascade_irqdomain_init();
+
+       return 0;
+}
+
+IRQCHIP_ACPI_DECLARE(cpuintc_v1, ACPI_MADT_TYPE_CORE_PIC,
+               NULL, ACPI_MADT_CORE_PIC_VERSION_V1, cpuintc_acpi_init);
diff --git a/drivers/irqchip/irq-loongson-eiointc.c b/drivers/irqchip/irq-loongson-eiointc.c
new file mode 100644 (file)
index 0000000..80d8ca6
--- /dev/null
@@ -0,0 +1,395 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Loongson Extend I/O Interrupt Controller support
+ *
+ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
+ */
+
+#define pr_fmt(fmt) "eiointc: " fmt
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+
+#define EIOINTC_REG_NODEMAP    0x14a0
+#define EIOINTC_REG_IPMAP      0x14c0
+#define EIOINTC_REG_ENABLE     0x1600
+#define EIOINTC_REG_BOUNCE     0x1680
+#define EIOINTC_REG_ISR                0x1800
+#define EIOINTC_REG_ROUTE      0x1c00
+
+#define VEC_REG_COUNT          4
+#define VEC_COUNT_PER_REG      64
+#define VEC_COUNT              (VEC_REG_COUNT * VEC_COUNT_PER_REG)
+#define VEC_REG_IDX(irq_id)    ((irq_id) / VEC_COUNT_PER_REG)
+#define VEC_REG_BIT(irq_id)     ((irq_id) % VEC_COUNT_PER_REG)
+#define EIOINTC_ALL_ENABLE     0xffffffff
+
+#define MAX_EIO_NODES          (NR_CPUS / CORES_PER_EIO_NODE)
+
+static int nr_pics;
+
+struct eiointc_priv {
+       u32                     node;
+       nodemask_t              node_map;
+       cpumask_t               cpuspan_map;
+       struct fwnode_handle    *domain_handle;
+       struct irq_domain       *eiointc_domain;
+};
+
+static struct eiointc_priv *eiointc_priv[MAX_IO_PICS];
+
+static void eiointc_enable(void)
+{
+       uint64_t misc;
+
+       misc = iocsr_read64(LOONGARCH_IOCSR_MISC_FUNC);
+       misc |= IOCSR_MISC_FUNC_EXT_IOI_EN;
+       iocsr_write64(misc, LOONGARCH_IOCSR_MISC_FUNC);
+}
+
+static int cpu_to_eio_node(int cpu)
+{
+       return cpu_logical_map(cpu) / CORES_PER_EIO_NODE;
+}
+
+static void eiointc_set_irq_route(int pos, unsigned int cpu, unsigned int mnode, nodemask_t *node_map)
+{
+       int i, node, cpu_node, route_node;
+       unsigned char coremap;
+       uint32_t pos_off, data, data_byte, data_mask;
+
+       pos_off = pos & ~3;
+       data_byte = pos & 3;
+       data_mask = ~BIT_MASK(data_byte) & 0xf;
+
+       /* Calculate node and coremap of target irq */
+       cpu_node = cpu_logical_map(cpu) / CORES_PER_EIO_NODE;
+       coremap = BIT(cpu_logical_map(cpu) % CORES_PER_EIO_NODE);
+
+       for_each_online_cpu(i) {
+               node = cpu_to_eio_node(i);
+               if (!node_isset(node, *node_map))
+                       continue;
+
+               /* EIO node 0 is in charge of inter-node interrupt dispatch */
+               route_node = (node == mnode) ? cpu_node : node;
+               data = ((coremap | (route_node << 4)) << (data_byte * 8));
+               csr_any_send(EIOINTC_REG_ROUTE + pos_off, data, data_mask, node * CORES_PER_EIO_NODE);
+       }
+}
+
+static DEFINE_RAW_SPINLOCK(affinity_lock);
+
+static int eiointc_set_irq_affinity(struct irq_data *d, const struct cpumask *affinity, bool force)
+{
+       unsigned int cpu;
+       unsigned long flags;
+       uint32_t vector, regaddr;
+       struct cpumask intersect_affinity;
+       struct eiointc_priv *priv = d->domain->host_data;
+
+       raw_spin_lock_irqsave(&affinity_lock, flags);
+
+       cpumask_and(&intersect_affinity, affinity, cpu_online_mask);
+       cpumask_and(&intersect_affinity, &intersect_affinity, &priv->cpuspan_map);
+
+       if (cpumask_empty(&intersect_affinity)) {
+               raw_spin_unlock_irqrestore(&affinity_lock, flags);
+               return -EINVAL;
+       }
+       cpu = cpumask_first(&intersect_affinity);
+
+       vector = d->hwirq;
+       regaddr = EIOINTC_REG_ENABLE + ((vector >> 5) << 2);
+
+       /* Mask target vector */
+       csr_any_send(regaddr, EIOINTC_ALL_ENABLE & (~BIT(vector & 0x1F)), 0x0, 0);
+       /* Set route for target vector */
+       eiointc_set_irq_route(vector, cpu, priv->node, &priv->node_map);
+       /* Unmask target vector */
+       csr_any_send(regaddr, EIOINTC_ALL_ENABLE, 0x0, 0);
+
+       irq_data_update_effective_affinity(d, cpumask_of(cpu));
+
+       raw_spin_unlock_irqrestore(&affinity_lock, flags);
+
+       return IRQ_SET_MASK_OK;
+}
+
+static int eiointc_index(int node)
+{
+       int i;
+
+       for (i = 0; i < nr_pics; i++) {
+               if (node_isset(node, eiointc_priv[i]->node_map))
+                       return i;
+       }
+
+       return -1;
+}
+
+static int eiointc_router_init(unsigned int cpu)
+{
+       int i, bit;
+       uint32_t data;
+       uint32_t node = cpu_to_eio_node(cpu);
+       uint32_t index = eiointc_index(node);
+
+       if (index < 0) {
+               pr_err("Error: invalid nodemap!\n");
+               return -1;
+       }
+
+       if ((cpu_logical_map(cpu) % CORES_PER_EIO_NODE) == 0) {
+               eiointc_enable();
+
+               for (i = 0; i < VEC_COUNT / 32; i++) {
+                       data = (((1 << (i * 2 + 1)) << 16) | (1 << (i * 2)));
+                       iocsr_write32(data, EIOINTC_REG_NODEMAP + i * 4);
+               }
+
+               for (i = 0; i < VEC_COUNT / 32 / 4; i++) {
+                       bit = BIT(1 + index); /* Route to IP[1 + index] */
+                       data = bit | (bit << 8) | (bit << 16) | (bit << 24);
+                       iocsr_write32(data, EIOINTC_REG_IPMAP + i * 4);
+               }
+
+               for (i = 0; i < VEC_COUNT / 4; i++) {
+                       /* Route to Node-0 Core-0 */
+                       if (index == 0)
+                               bit = BIT(cpu_logical_map(0));
+                       else
+                               bit = (eiointc_priv[index]->node << 4) | 1;
+
+                       data = bit | (bit << 8) | (bit << 16) | (bit << 24);
+                       iocsr_write32(data, EIOINTC_REG_ROUTE + i * 4);
+               }
+
+               for (i = 0; i < VEC_COUNT / 32; i++) {
+                       data = 0xffffffff;
+                       iocsr_write32(data, EIOINTC_REG_ENABLE + i * 4);
+                       iocsr_write32(data, EIOINTC_REG_BOUNCE + i * 4);
+               }
+       }
+
+       return 0;
+}
+
+static void eiointc_irq_dispatch(struct irq_desc *desc)
+{
+       int i;
+       u64 pending;
+       bool handled = false;
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+       struct eiointc_priv *priv = irq_desc_get_handler_data(desc);
+
+       chained_irq_enter(chip, desc);
+
+       for (i = 0; i < VEC_REG_COUNT; i++) {
+               pending = iocsr_read64(EIOINTC_REG_ISR + (i << 3));
+               iocsr_write64(pending, EIOINTC_REG_ISR + (i << 3));
+               while (pending) {
+                       int bit = __ffs(pending);
+                       int irq = bit + VEC_COUNT_PER_REG * i;
+
+                       generic_handle_domain_irq(priv->eiointc_domain, irq);
+                       pending &= ~BIT(bit);
+                       handled = true;
+               }
+       }
+
+       if (!handled)
+               spurious_interrupt();
+
+       chained_irq_exit(chip, desc);
+}
+
+static void eiointc_ack_irq(struct irq_data *d)
+{
+}
+
+static void eiointc_mask_irq(struct irq_data *d)
+{
+}
+
+static void eiointc_unmask_irq(struct irq_data *d)
+{
+}
+
+static struct irq_chip eiointc_irq_chip = {
+       .name                   = "EIOINTC",
+       .irq_ack                = eiointc_ack_irq,
+       .irq_mask               = eiointc_mask_irq,
+       .irq_unmask             = eiointc_unmask_irq,
+       .irq_set_affinity       = eiointc_set_irq_affinity,
+};
+
+static int eiointc_domain_alloc(struct irq_domain *domain, unsigned int virq,
+                               unsigned int nr_irqs, void *arg)
+{
+       int ret;
+       unsigned int i, type;
+       unsigned long hwirq = 0;
+       struct eiointc *priv = domain->host_data;
+
+       ret = irq_domain_translate_onecell(domain, arg, &hwirq, &type);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < nr_irqs; i++) {
+               irq_domain_set_info(domain, virq + i, hwirq + i, &eiointc_irq_chip,
+                                       priv, handle_edge_irq, NULL, NULL);
+       }
+
+       return 0;
+}
+
+static void eiointc_domain_free(struct irq_domain *domain, unsigned int virq,
+                               unsigned int nr_irqs)
+{
+       int i;
+
+       for (i = 0; i < nr_irqs; i++) {
+               struct irq_data *d = irq_domain_get_irq_data(domain, virq + i);
+
+               irq_set_handler(virq + i, NULL);
+               irq_domain_reset_irq_data(d);
+       }
+}
+
+static const struct irq_domain_ops eiointc_domain_ops = {
+       .translate      = irq_domain_translate_onecell,
+       .alloc          = eiointc_domain_alloc,
+       .free           = eiointc_domain_free,
+};
+
+static void acpi_set_vec_parent(int node, struct irq_domain *parent, struct acpi_vector_group *vec_group)
+{
+       int i;
+
+       if (cpu_has_flatmode)
+               node = cpu_to_node(node * CORES_PER_EIO_NODE);
+
+       for (i = 0; i < MAX_IO_PICS; i++) {
+               if (node == vec_group[i].node) {
+                       vec_group[i].parent = parent;
+                       return;
+               }
+       }
+}
+
+struct irq_domain *acpi_get_vec_parent(int node, struct acpi_vector_group *vec_group)
+{
+       int i;
+
+       for (i = 0; i < MAX_IO_PICS; i++) {
+               if (node == vec_group[i].node)
+                       return vec_group[i].parent;
+       }
+       return NULL;
+}
+
+static int __init
+pch_pic_parse_madt(union acpi_subtable_headers *header,
+                      const unsigned long end)
+{
+       struct acpi_madt_bio_pic *pchpic_entry = (struct acpi_madt_bio_pic *)header;
+       unsigned int node = (pchpic_entry->address >> 44) & 0xf;
+       struct irq_domain *parent = acpi_get_vec_parent(node, pch_group);
+
+       if (parent)
+               return pch_pic_acpi_init(parent, pchpic_entry);
+
+       return -EINVAL;
+}
+
+static int __init
+pch_msi_parse_madt(union acpi_subtable_headers *header,
+                      const unsigned long end)
+{
+       struct acpi_madt_msi_pic *pchmsi_entry = (struct acpi_madt_msi_pic *)header;
+       struct irq_domain *parent = acpi_get_vec_parent(eiointc_priv[nr_pics - 1]->node, msi_group);
+
+       if (parent)
+               return pch_msi_acpi_init(parent, pchmsi_entry);
+
+       return -EINVAL;
+}
+
+static int __init acpi_cascade_irqdomain_init(void)
+{
+       acpi_table_parse_madt(ACPI_MADT_TYPE_BIO_PIC,
+                             pch_pic_parse_madt, 0);
+       acpi_table_parse_madt(ACPI_MADT_TYPE_MSI_PIC,
+                             pch_msi_parse_madt, 1);
+       return 0;
+}
+
+int __init eiointc_acpi_init(struct irq_domain *parent,
+                                    struct acpi_madt_eio_pic *acpi_eiointc)
+{
+       int i, parent_irq;
+       unsigned long node_map;
+       struct eiointc_priv *priv;
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->domain_handle = irq_domain_alloc_fwnode((phys_addr_t *)acpi_eiointc);
+       if (!priv->domain_handle) {
+               pr_err("Unable to allocate domain handle\n");
+               goto out_free_priv;
+       }
+
+       priv->node = acpi_eiointc->node;
+       node_map = acpi_eiointc->node_map ? : -1ULL;
+
+       for_each_possible_cpu(i) {
+               if (node_map & (1ULL << cpu_to_eio_node(i))) {
+                       node_set(cpu_to_eio_node(i), priv->node_map);
+                       cpumask_or(&priv->cpuspan_map, &priv->cpuspan_map, cpumask_of(i));
+               }
+       }
+
+       /* Setup IRQ domain */
+       priv->eiointc_domain = irq_domain_create_linear(priv->domain_handle, VEC_COUNT,
+                                       &eiointc_domain_ops, priv);
+       if (!priv->eiointc_domain) {
+               pr_err("loongson-eiointc: cannot add IRQ domain\n");
+               goto out_free_handle;
+       }
+
+       eiointc_priv[nr_pics++] = priv;
+
+       eiointc_router_init(0);
+
+       parent_irq = irq_create_mapping(parent, acpi_eiointc->cascade);
+       irq_set_chained_handler_and_data(parent_irq, eiointc_irq_dispatch, priv);
+
+       cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_LOONGARCH_STARTING,
+                                 "irqchip/loongarch/intc:starting",
+                                 eiointc_router_init, NULL);
+
+       acpi_set_vec_parent(acpi_eiointc->node, priv->eiointc_domain, pch_group);
+       acpi_set_vec_parent(acpi_eiointc->node, priv->eiointc_domain, msi_group);
+       acpi_cascade_irqdomain_init();
+
+       return 0;
+
+out_free_handle:
+       irq_domain_free_fwnode(priv->domain_handle);
+       priv->domain_handle = NULL;
+out_free_priv:
+       kfree(priv);
+
+       return -ENOMEM;
+}
index 8d05d8b..c4f3c88 100644 (file)
@@ -23,7 +23,7 @@
 #endif
 
 #define LIOINTC_CHIP_IRQ       32
-#define LIOINTC_NUM_PARENT 4
+#define LIOINTC_NUM_PARENT     4
 #define LIOINTC_NUM_CORES      4
 
 #define LIOINTC_INTC_CHIP_START        0x20
@@ -58,6 +58,8 @@ struct liointc_priv {
        bool                            has_lpc_irq_errata;
 };
 
+struct fwnode_handle *liointc_handle;
+
 static void liointc_chained_handle_irq(struct irq_desc *desc)
 {
        struct liointc_handler_data *handler = irq_desc_get_handler_data(desc);
@@ -153,97 +155,79 @@ static void liointc_resume(struct irq_chip_generic *gc)
        irq_gc_unlock_irqrestore(gc, flags);
 }
 
-static const char * const parent_names[] = {"int0", "int1", "int2", "int3"};
-static const char * const core_reg_names[] = {"isr0", "isr1", "isr2", "isr3"};
+static int parent_irq[LIOINTC_NUM_PARENT];
+static u32 parent_int_map[LIOINTC_NUM_PARENT];
+static const char *const parent_names[] = {"int0", "int1", "int2", "int3"};
+static const char *const core_reg_names[] = {"isr0", "isr1", "isr2", "isr3"};
 
-static void __iomem *liointc_get_reg_byname(struct device_node *node,
-                                               const char *name)
+static int liointc_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
+                            const u32 *intspec, unsigned int intsize,
+                            unsigned long *out_hwirq, unsigned int *out_type)
 {
-       int index = of_property_match_string(node, "reg-names", name);
-
-       if (index < 0)
-               return NULL;
-
-       return of_iomap(node, index);
+       if (WARN_ON(intsize < 1))
+               return -EINVAL;
+       *out_hwirq = intspec[0] - GSI_MIN_CPU_IRQ;
+       *out_type = IRQ_TYPE_NONE;
+       return 0;
 }
 
-static int __init liointc_of_init(struct device_node *node,
-                                 struct device_node *parent)
+static const struct irq_domain_ops acpi_irq_gc_ops = {
+       .map    = irq_map_generic_chip,
+       .unmap  = irq_unmap_generic_chip,
+       .xlate  = liointc_domain_xlate,
+};
+
+static int liointc_init(phys_addr_t addr, unsigned long size, int revision,
+               struct fwnode_handle *domain_handle, struct device_node *node)
 {
+       int i, err;
+       void __iomem *base;
+       struct irq_chip_type *ct;
        struct irq_chip_generic *gc;
        struct irq_domain *domain;
-       struct irq_chip_type *ct;
        struct liointc_priv *priv;
-       void __iomem *base;
-       u32 of_parent_int_map[LIOINTC_NUM_PARENT];
-       int parent_irq[LIOINTC_NUM_PARENT];
-       bool have_parent = FALSE;
-       int sz, i, err = 0;
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
-       if (of_device_is_compatible(node, "loongson,liointc-2.0")) {
-               base = liointc_get_reg_byname(node, "main");
-               if (!base) {
-                       err = -ENODEV;
-                       goto out_free_priv;
-               }
+       base = ioremap(addr, size);
+       if (!base)
+               goto out_free_priv;
 
-               for (i = 0; i < LIOINTC_NUM_CORES; i++)
-                       priv->core_isr[i] = liointc_get_reg_byname(node, core_reg_names[i]);
-               if (!priv->core_isr[0]) {
-                       err = -ENODEV;
-                       goto out_iounmap_base;
-               }
-       } else {
-               base = of_iomap(node, 0);
-               if (!base) {
-                       err = -ENODEV;
-                       goto out_free_priv;
-               }
+       for (i = 0; i < LIOINTC_NUM_CORES; i++)
+               priv->core_isr[i] = base + LIOINTC_REG_INTC_STATUS;
 
-               for (i = 0; i < LIOINTC_NUM_CORES; i++)
-                       priv->core_isr[i] = base + LIOINTC_REG_INTC_STATUS;
-       }
+       for (i = 0; i < LIOINTC_NUM_PARENT; i++)
+               priv->handler[i].parent_int_map = parent_int_map[i];
 
-       for (i = 0; i < LIOINTC_NUM_PARENT; i++) {
-               parent_irq[i] = of_irq_get_byname(node, parent_names[i]);
-               if (parent_irq[i] > 0)
-                       have_parent = TRUE;
-       }
-       if (!have_parent) {
-               err = -ENODEV;
-               goto out_iounmap_isr;
-       }
+       if (revision > 1) {
+               for (i = 0; i < LIOINTC_NUM_CORES; i++) {
+                       int index = of_property_match_string(node,
+                                       "reg-names", core_reg_names[i]);
 
-       sz = of_property_read_variable_u32_array(node,
-                                               "loongson,parent_int_map",
-                                               &of_parent_int_map[0],
-                                               LIOINTC_NUM_PARENT,
-                                               LIOINTC_NUM_PARENT);
-       if (sz < 4) {
-               pr_err("loongson-liointc: No parent_int_map\n");
-               err = -ENODEV;
-               goto out_iounmap_isr;
-       }
+                       if (index < 0)
+                               return -EINVAL;
 
-       for (i = 0; i < LIOINTC_NUM_PARENT; i++)
-               priv->handler[i].parent_int_map = of_parent_int_map[i];
+                       priv->core_isr[i] = of_iomap(node, index);
+               }
+       }
 
        /* Setup IRQ domain */
-       domain = irq_domain_add_linear(node, 32,
+       if (!acpi_disabled)
+               domain = irq_domain_create_linear(domain_handle, LIOINTC_CHIP_IRQ,
+                                       &acpi_irq_gc_ops, priv);
+       else
+               domain = irq_domain_create_linear(domain_handle, LIOINTC_CHIP_IRQ,
                                        &irq_generic_chip_ops, priv);
        if (!domain) {
                pr_err("loongson-liointc: cannot add IRQ domain\n");
-               err = -EINVAL;
-               goto out_iounmap_isr;
+               goto out_iounmap;
        }
 
-       err = irq_alloc_domain_generic_chips(domain, 32, 1,
-                                       node->full_name, handle_level_irq,
-                                       IRQ_NOPROBE, 0, 0);
+       err = irq_alloc_domain_generic_chips(domain, LIOINTC_CHIP_IRQ, 1,
+                                       (node ? node->full_name : "LIOINTC"),
+                                       handle_level_irq, 0, IRQ_NOPROBE, 0);
        if (err) {
                pr_err("loongson-liointc: unable to register IRQ domain\n");
                goto out_free_domain;
@@ -299,24 +283,93 @@ static int __init liointc_of_init(struct device_node *node,
                                liointc_chained_handle_irq, &priv->handler[i]);
        }
 
+       liointc_handle = domain_handle;
        return 0;
 
 out_free_domain:
        irq_domain_remove(domain);
-out_iounmap_isr:
-       for (i = 0; i < LIOINTC_NUM_CORES; i++) {
-               if (!priv->core_isr[i])
-                       continue;
-               iounmap(priv->core_isr[i]);
-       }
-out_iounmap_base:
+out_iounmap:
        iounmap(base);
 out_free_priv:
        kfree(priv);
 
-       return err;
+       return -EINVAL;
+}
+
+#ifdef CONFIG_OF
+
+static int __init liointc_of_init(struct device_node *node,
+                                 struct device_node *parent)
+{
+       bool have_parent = FALSE;
+       int sz, i, index, revision, err = 0;
+       struct resource res;
+
+       if (!of_device_is_compatible(node, "loongson,liointc-2.0")) {
+               index = 0;
+               revision = 1;
+       } else {
+               index = of_property_match_string(node, "reg-names", "main");
+               revision = 2;
+       }
+
+       if (of_address_to_resource(node, index, &res))
+               return -EINVAL;
+
+       for (i = 0; i < LIOINTC_NUM_PARENT; i++) {
+               parent_irq[i] = of_irq_get_byname(node, parent_names[i]);
+               if (parent_irq[i] > 0)
+                       have_parent = TRUE;
+       }
+       if (!have_parent)
+               return -ENODEV;
+
+       sz = of_property_read_variable_u32_array(node,
+                                               "loongson,parent_int_map",
+                                               &parent_int_map[0],
+                                               LIOINTC_NUM_PARENT,
+                                               LIOINTC_NUM_PARENT);
+       if (sz < 4) {
+               pr_err("loongson-liointc: No parent_int_map\n");
+               return -ENODEV;
+       }
+
+       err = liointc_init(res.start, resource_size(&res),
+                       revision, of_node_to_fwnode(node), node);
+       if (err < 0)
+               return err;
+
+       return 0;
 }
 
 IRQCHIP_DECLARE(loongson_liointc_1_0, "loongson,liointc-1.0", liointc_of_init);
 IRQCHIP_DECLARE(loongson_liointc_1_0a, "loongson,liointc-1.0a", liointc_of_init);
 IRQCHIP_DECLARE(loongson_liointc_2_0, "loongson,liointc-2.0", liointc_of_init);
+
+#endif
+
+#ifdef CONFIG_ACPI
+int __init liointc_acpi_init(struct irq_domain *parent, struct acpi_madt_lio_pic *acpi_liointc)
+{
+       int ret;
+       struct fwnode_handle *domain_handle;
+
+       parent_int_map[0] = acpi_liointc->cascade_map[0];
+       parent_int_map[1] = acpi_liointc->cascade_map[1];
+
+       parent_irq[0] = irq_create_mapping(parent, acpi_liointc->cascade[0]);
+       parent_irq[1] = irq_create_mapping(parent, acpi_liointc->cascade[1]);
+
+       domain_handle = irq_domain_alloc_fwnode((phys_addr_t *)acpi_liointc);
+       if (!domain_handle) {
+               pr_err("Unable to allocate domain handle\n");
+               return -ENOMEM;
+       }
+       ret = liointc_init(acpi_liointc->address, acpi_liointc->size,
+                          1, domain_handle, NULL);
+       if (ret)
+               irq_domain_free_fwnode(domain_handle);
+
+       return ret;
+}
+#endif
diff --git a/drivers/irqchip/irq-loongson-pch-lpc.c b/drivers/irqchip/irq-loongson-pch-lpc.c
new file mode 100644 (file)
index 0000000..bf23249
--- /dev/null
@@ -0,0 +1,205 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Loongson LPC Interrupt Controller support
+ *
+ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
+ */
+
+#define pr_fmt(fmt) "lpc: " fmt
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+
+/* Registers */
+#define LPC_INT_CTL            0x00
+#define LPC_INT_ENA            0x04
+#define LPC_INT_STS            0x08
+#define LPC_INT_CLR            0x0c
+#define LPC_INT_POL            0x10
+#define LPC_COUNT              16
+
+/* LPC_INT_CTL */
+#define LPC_INT_CTL_EN         BIT(31)
+
+struct pch_lpc {
+       void __iomem            *base;
+       struct irq_domain       *lpc_domain;
+       raw_spinlock_t          lpc_lock;
+       u32                     saved_reg_ctl;
+       u32                     saved_reg_ena;
+       u32                     saved_reg_pol;
+};
+
+struct fwnode_handle *pch_lpc_handle;
+
+static void lpc_irq_ack(struct irq_data *d)
+{
+       unsigned long flags;
+       struct pch_lpc *priv = d->domain->host_data;
+
+       raw_spin_lock_irqsave(&priv->lpc_lock, flags);
+       writel(0x1 << d->hwirq, priv->base + LPC_INT_CLR);
+       raw_spin_unlock_irqrestore(&priv->lpc_lock, flags);
+}
+
+static void lpc_irq_mask(struct irq_data *d)
+{
+       unsigned long flags;
+       struct pch_lpc *priv = d->domain->host_data;
+
+       raw_spin_lock_irqsave(&priv->lpc_lock, flags);
+       writel(readl(priv->base + LPC_INT_ENA) & (~(0x1 << (d->hwirq))),
+                       priv->base + LPC_INT_ENA);
+       raw_spin_unlock_irqrestore(&priv->lpc_lock, flags);
+}
+
+static void lpc_irq_unmask(struct irq_data *d)
+{
+       unsigned long flags;
+       struct pch_lpc *priv = d->domain->host_data;
+
+       raw_spin_lock_irqsave(&priv->lpc_lock, flags);
+       writel(readl(priv->base + LPC_INT_ENA) | (0x1 << (d->hwirq)),
+                       priv->base + LPC_INT_ENA);
+       raw_spin_unlock_irqrestore(&priv->lpc_lock, flags);
+}
+
+static int lpc_irq_set_type(struct irq_data *d, unsigned int type)
+{
+       u32 val;
+       u32 mask = 0x1 << (d->hwirq);
+       struct pch_lpc *priv = d->domain->host_data;
+
+       if (!(type & IRQ_TYPE_LEVEL_MASK))
+               return 0;
+
+       val = readl(priv->base + LPC_INT_POL);
+
+       if (type == IRQ_TYPE_LEVEL_HIGH)
+               val |= mask;
+       else
+               val &= ~mask;
+
+       writel(val, priv->base + LPC_INT_POL);
+
+       return 0;
+}
+
+static const struct irq_chip pch_lpc_irq_chip = {
+       .name                   = "PCH LPC",
+       .irq_mask               = lpc_irq_mask,
+       .irq_unmask             = lpc_irq_unmask,
+       .irq_ack                = lpc_irq_ack,
+       .irq_set_type           = lpc_irq_set_type,
+       .flags                  = IRQCHIP_SKIP_SET_WAKE,
+};
+
+static void lpc_irq_dispatch(struct irq_desc *desc)
+{
+       u32 pending, bit;
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+       struct pch_lpc *priv = irq_desc_get_handler_data(desc);
+
+       chained_irq_enter(chip, desc);
+
+       pending = readl(priv->base + LPC_INT_ENA);
+       pending &= readl(priv->base + LPC_INT_STS);
+       if (!pending)
+               spurious_interrupt();
+
+       while (pending) {
+               bit = __ffs(pending);
+
+               generic_handle_domain_irq(priv->lpc_domain, bit);
+               pending &= ~BIT(bit);
+       }
+       chained_irq_exit(chip, desc);
+}
+
+static int pch_lpc_map(struct irq_domain *d, unsigned int irq,
+                       irq_hw_number_t hw)
+{
+       irq_set_chip_and_handler(irq, &pch_lpc_irq_chip, handle_level_irq);
+       return 0;
+}
+
+static const struct irq_domain_ops pch_lpc_domain_ops = {
+       .map            = pch_lpc_map,
+       .translate      = irq_domain_translate_twocell,
+};
+
+static void pch_lpc_reset(struct pch_lpc *priv)
+{
+       /* Enable the LPC interrupt, bit31: en  bit30: edge */
+       writel(LPC_INT_CTL_EN, priv->base + LPC_INT_CTL);
+       writel(0, priv->base + LPC_INT_ENA);
+       /* Clear all 18-bit interrpt bit */
+       writel(GENMASK(17, 0), priv->base + LPC_INT_CLR);
+}
+
+static int pch_lpc_disabled(struct pch_lpc *priv)
+{
+       return (readl(priv->base + LPC_INT_ENA) == 0xffffffff) &&
+                       (readl(priv->base + LPC_INT_STS) == 0xffffffff);
+}
+
+int __init pch_lpc_acpi_init(struct irq_domain *parent,
+                                       struct acpi_madt_lpc_pic *acpi_pchlpc)
+{
+       int parent_irq;
+       struct pch_lpc *priv;
+       struct irq_fwspec fwspec;
+       struct fwnode_handle *irq_handle;
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       raw_spin_lock_init(&priv->lpc_lock);
+
+       priv->base = ioremap(acpi_pchlpc->address, acpi_pchlpc->size);
+       if (!priv->base)
+               goto free_priv;
+
+       if (pch_lpc_disabled(priv)) {
+               pr_err("Failed to get LPC status\n");
+               goto iounmap_base;
+       }
+
+       irq_handle = irq_domain_alloc_named_fwnode("lpcintc");
+       if (!irq_handle) {
+               pr_err("Unable to allocate domain handle\n");
+               goto iounmap_base;
+       }
+
+       priv->lpc_domain = irq_domain_create_linear(irq_handle, LPC_COUNT,
+                                       &pch_lpc_domain_ops, priv);
+       if (!priv->lpc_domain) {
+               pr_err("Failed to create IRQ domain\n");
+               goto free_irq_handle;
+       }
+       pch_lpc_reset(priv);
+
+       fwspec.fwnode = parent->fwnode;
+       fwspec.param[0] = acpi_pchlpc->cascade + GSI_MIN_PCH_IRQ;
+       fwspec.param[1] = IRQ_TYPE_LEVEL_HIGH;
+       fwspec.param_count = 2;
+       parent_irq = irq_create_fwspec_mapping(&fwspec);
+       irq_set_chained_handler_and_data(parent_irq, lpc_irq_dispatch, priv);
+
+       pch_lpc_handle = irq_handle;
+       return 0;
+
+free_irq_handle:
+       irq_domain_free_fwnode(irq_handle);
+iounmap_base:
+       iounmap(priv->base);
+free_priv:
+       kfree(priv);
+
+       return -ENOMEM;
+}
index e3801c4..d0e8551 100644 (file)
@@ -15,6 +15,8 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 
+static int nr_pics;
+
 struct pch_msi_data {
        struct mutex    msi_map_lock;
        phys_addr_t     doorbell;
@@ -23,6 +25,8 @@ struct pch_msi_data {
        unsigned long   *msi_map;
 };
 
+static struct fwnode_handle *pch_msi_handle[MAX_IO_PICS];
+
 static void pch_msi_mask_msi_irq(struct irq_data *d)
 {
        pci_msi_mask_irq(d);
@@ -154,12 +158,12 @@ static const struct irq_domain_ops pch_msi_middle_domain_ops = {
 };
 
 static int pch_msi_init_domains(struct pch_msi_data *priv,
-                               struct device_node *node,
-                               struct irq_domain *parent)
+                               struct irq_domain *parent,
+                               struct fwnode_handle *domain_handle)
 {
        struct irq_domain *middle_domain, *msi_domain;
 
-       middle_domain = irq_domain_create_linear(of_node_to_fwnode(node),
+       middle_domain = irq_domain_create_linear(domain_handle,
                                                priv->num_irqs,
                                                &pch_msi_middle_domain_ops,
                                                priv);
@@ -171,7 +175,7 @@ static int pch_msi_init_domains(struct pch_msi_data *priv,
        middle_domain->parent = parent;
        irq_domain_update_bus_token(middle_domain, DOMAIN_BUS_NEXUS);
 
-       msi_domain = pci_msi_create_irq_domain(of_node_to_fwnode(node),
+       msi_domain = pci_msi_create_irq_domain(domain_handle,
                                               &pch_msi_domain_info,
                                               middle_domain);
        if (!msi_domain) {
@@ -183,19 +187,11 @@ static int pch_msi_init_domains(struct pch_msi_data *priv,
        return 0;
 }
 
-static int pch_msi_init(struct device_node *node,
-                           struct device_node *parent)
+static int pch_msi_init(phys_addr_t msg_address, int irq_base, int irq_count,
+                       struct irq_domain *parent_domain, struct fwnode_handle *domain_handle)
 {
-       struct pch_msi_data *priv;
-       struct irq_domain *parent_domain;
-       struct resource res;
        int ret;
-
-       parent_domain = irq_find_host(parent);
-       if (!parent_domain) {
-               pr_err("Failed to find the parent domain\n");
-               return -ENXIO;
-       }
+       struct pch_msi_data *priv;
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv)
@@ -203,48 +199,95 @@ static int pch_msi_init(struct device_node *node,
 
        mutex_init(&priv->msi_map_lock);
 
-       ret = of_address_to_resource(node, 0, &res);
-       if (ret) {
-               pr_err("Failed to allocate resource\n");
-               goto err_priv;
-       }
-
-       priv->doorbell = res.start;
-
-       if (of_property_read_u32(node, "loongson,msi-base-vec",
-                               &priv->irq_first)) {
-               pr_err("Unable to parse MSI vec base\n");
-               ret = -EINVAL;
-               goto err_priv;
-       }
-
-       if (of_property_read_u32(node, "loongson,msi-num-vecs",
-                               &priv->num_irqs)) {
-               pr_err("Unable to parse MSI vec number\n");
-               ret = -EINVAL;
-               goto err_priv;
-       }
+       priv->doorbell = msg_address;
+       priv->irq_first = irq_base;
+       priv->num_irqs = irq_count;
 
        priv->msi_map = bitmap_zalloc(priv->num_irqs, GFP_KERNEL);
-       if (!priv->msi_map) {
-               ret = -ENOMEM;
+       if (!priv->msi_map)
                goto err_priv;
-       }
 
        pr_debug("Registering %d MSIs, starting at %d\n",
                 priv->num_irqs, priv->irq_first);
 
-       ret = pch_msi_init_domains(priv, node, parent_domain);
+       ret = pch_msi_init_domains(priv, parent_domain, domain_handle);
        if (ret)
                goto err_map;
 
+       pch_msi_handle[nr_pics++] = domain_handle;
        return 0;
 
 err_map:
        bitmap_free(priv->msi_map);
 err_priv:
        kfree(priv);
-       return ret;
+
+       return -EINVAL;
+}
+
+#ifdef CONFIG_OF
+static int pch_msi_of_init(struct device_node *node, struct device_node *parent)
+{
+       int err;
+       int irq_base, irq_count;
+       struct resource res;
+       struct irq_domain *parent_domain;
+
+       parent_domain = irq_find_host(parent);
+       if (!parent_domain) {
+               pr_err("Failed to find the parent domain\n");
+               return -ENXIO;
+       }
+
+       if (of_address_to_resource(node, 0, &res)) {
+               pr_err("Failed to allocate resource\n");
+               return -EINVAL;
+       }
+
+       if (of_property_read_u32(node, "loongson,msi-base-vec", &irq_base)) {
+               pr_err("Unable to parse MSI vec base\n");
+               return -EINVAL;
+       }
+
+       if (of_property_read_u32(node, "loongson,msi-num-vecs", &irq_count)) {
+               pr_err("Unable to parse MSI vec number\n");
+               return -EINVAL;
+       }
+
+       err = pch_msi_init(res.start, irq_base, irq_count, parent_domain, of_node_to_fwnode(node));
+       if (err < 0)
+               return err;
+
+       return 0;
 }
 
-IRQCHIP_DECLARE(pch_msi, "loongson,pch-msi-1.0", pch_msi_init);
+IRQCHIP_DECLARE(pch_msi, "loongson,pch-msi-1.0", pch_msi_of_init);
+#endif
+
+#ifdef CONFIG_ACPI
+struct fwnode_handle *get_pch_msi_handle(int pci_segment)
+{
+       int i;
+
+       for (i = 0; i < MAX_IO_PICS; i++) {
+               if (msi_group[i].pci_segment == pci_segment)
+                       return pch_msi_handle[i];
+       }
+       return NULL;
+}
+
+int __init pch_msi_acpi_init(struct irq_domain *parent,
+                                       struct acpi_madt_msi_pic *acpi_pchmsi)
+{
+       int ret;
+       struct fwnode_handle *domain_handle;
+
+       domain_handle = irq_domain_alloc_fwnode((phys_addr_t *)acpi_pchmsi);
+       ret = pch_msi_init(acpi_pchmsi->msg_address, acpi_pchmsi->start,
+                               acpi_pchmsi->count, parent, domain_handle);
+       if (ret < 0)
+               irq_domain_free_fwnode(domain_handle);
+
+       return ret;
+}
+#endif
index a4eb8a2..b6f1392 100644 (file)
 #define PIC_REG_IDX(irq_id)    ((irq_id) / PIC_COUNT_PER_REG)
 #define PIC_REG_BIT(irq_id)    ((irq_id) % PIC_COUNT_PER_REG)
 
+static int nr_pics;
+
 struct pch_pic {
        void __iomem            *base;
        struct irq_domain       *pic_domain;
        u32                     ht_vec_base;
        raw_spinlock_t          pic_lock;
+       u32                     vec_count;
+       u32                     gsi_base;
 };
 
+static struct pch_pic *pch_pic_priv[MAX_IO_PICS];
+
+struct fwnode_handle *pch_pic_handle[MAX_IO_PICS];
+
+int find_pch_pic(u32 gsi)
+{
+       int i;
+
+       /* Find the PCH_PIC that manages this GSI. */
+       for (i = 0; i < MAX_IO_PICS; i++) {
+               struct pch_pic *priv = pch_pic_priv[i];
+
+               if (!priv)
+                       return -1;
+
+               if (gsi >= priv->gsi_base && gsi < (priv->gsi_base + priv->vec_count))
+                       return i;
+       }
+
+       pr_err("ERROR: Unable to locate PCH_PIC for GSI %d\n", gsi);
+       return -1;
+}
+
 static void pch_pic_bitset(struct pch_pic *priv, int offset, int bit)
 {
        u32 reg;
@@ -139,6 +166,28 @@ static struct irq_chip pch_pic_irq_chip = {
        .irq_set_type           = pch_pic_set_type,
 };
 
+static int pch_pic_domain_translate(struct irq_domain *d,
+                                       struct irq_fwspec *fwspec,
+                                       unsigned long *hwirq,
+                                       unsigned int *type)
+{
+       struct pch_pic *priv = d->host_data;
+       struct device_node *of_node = to_of_node(fwspec->fwnode);
+
+       if (fwspec->param_count < 1)
+               return -EINVAL;
+
+       if (of_node) {
+               *hwirq = fwspec->param[0] + priv->ht_vec_base;
+               *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
+       } else {
+               *hwirq = fwspec->param[0] - priv->gsi_base;
+               *type = IRQ_TYPE_NONE;
+       }
+
+       return 0;
+}
+
 static int pch_pic_alloc(struct irq_domain *domain, unsigned int virq,
                              unsigned int nr_irqs, void *arg)
 {
@@ -149,13 +198,13 @@ static int pch_pic_alloc(struct irq_domain *domain, unsigned int virq,
        struct irq_fwspec parent_fwspec;
        struct pch_pic *priv = domain->host_data;
 
-       err = irq_domain_translate_twocell(domain, fwspec, &hwirq, &type);
+       err = pch_pic_domain_translate(domain, fwspec, &hwirq, &type);
        if (err)
                return err;
 
        parent_fwspec.fwnode = domain->parent->fwnode;
        parent_fwspec.param_count = 1;
-       parent_fwspec.param[0] = hwirq + priv->ht_vec_base;
+       parent_fwspec.param[0] = hwirq;
 
        err = irq_domain_alloc_irqs_parent(domain, virq, 1, &parent_fwspec);
        if (err)
@@ -170,7 +219,7 @@ static int pch_pic_alloc(struct irq_domain *domain, unsigned int virq,
 }
 
 static const struct irq_domain_ops pch_pic_domain_ops = {
-       .translate      = irq_domain_translate_twocell,
+       .translate      = pch_pic_domain_translate,
        .alloc          = pch_pic_alloc,
        .free           = irq_domain_free_irqs_parent,
 };
@@ -180,7 +229,7 @@ static void pch_pic_reset(struct pch_pic *priv)
        int i;
 
        for (i = 0; i < PIC_COUNT; i++) {
-               /* Write vectored ID */
+               /* Write vector ID */
                writeb(priv->ht_vec_base + i, priv->base + PCH_INT_HTVEC(i));
                /* Hardcode route to HT0 Lo */
                writeb(1, priv->base + PCH_INT_ROUTE(i));
@@ -198,50 +247,37 @@ static void pch_pic_reset(struct pch_pic *priv)
        }
 }
 
-static int pch_pic_of_init(struct device_node *node,
-                               struct device_node *parent)
+static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base,
+                       struct irq_domain *parent_domain, struct fwnode_handle *domain_handle,
+                       u32 gsi_base)
 {
        struct pch_pic *priv;
-       struct irq_domain *parent_domain;
-       int err;
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
        raw_spin_lock_init(&priv->pic_lock);
-       priv->base = of_iomap(node, 0);
-       if (!priv->base) {
-               err = -ENOMEM;
+       priv->base = ioremap(addr, size);
+       if (!priv->base)
                goto free_priv;
-       }
 
-       parent_domain = irq_find_host(parent);
-       if (!parent_domain) {
-               pr_err("Failed to find the parent domain\n");
-               err = -ENXIO;
-               goto iounmap_base;
-       }
-
-       if (of_property_read_u32(node, "loongson,pic-base-vec",
-                               &priv->ht_vec_base)) {
-               pr_err("Failed to determine pic-base-vec\n");
-               err = -EINVAL;
-               goto iounmap_base;
-       }
+       priv->ht_vec_base = vec_base;
+       priv->vec_count = ((readq(priv->base) >> 48) & 0xff) + 1;
+       priv->gsi_base = gsi_base;
 
        priv->pic_domain = irq_domain_create_hierarchy(parent_domain, 0,
-                                                      PIC_COUNT,
-                                                      of_node_to_fwnode(node),
-                                                      &pch_pic_domain_ops,
-                                                      priv);
+                                               priv->vec_count, domain_handle,
+                                               &pch_pic_domain_ops, priv);
+
        if (!priv->pic_domain) {
                pr_err("Failed to create IRQ domain\n");
-               err = -ENOMEM;
                goto iounmap_base;
        }
 
        pch_pic_reset(priv);
+       pch_pic_handle[nr_pics] = domain_handle;
+       pch_pic_priv[nr_pics++] = priv;
 
        return 0;
 
@@ -250,7 +286,86 @@ iounmap_base:
 free_priv:
        kfree(priv);
 
-       return err;
+       return -EINVAL;
+}
+
+#ifdef CONFIG_OF
+
+static int pch_pic_of_init(struct device_node *node,
+                               struct device_node *parent)
+{
+       int err, vec_base;
+       struct resource res;
+       struct irq_domain *parent_domain;
+
+       if (of_address_to_resource(node, 0, &res))
+               return -EINVAL;
+
+       parent_domain = irq_find_host(parent);
+       if (!parent_domain) {
+               pr_err("Failed to find the parent domain\n");
+               return -ENXIO;
+       }
+
+       if (of_property_read_u32(node, "loongson,pic-base-vec", &vec_base)) {
+               pr_err("Failed to determine pic-base-vec\n");
+               return -EINVAL;
+       }
+
+       err = pch_pic_init(res.start, resource_size(&res), vec_base,
+                               parent_domain, of_node_to_fwnode(node), 0);
+       if (err < 0)
+               return err;
+
+       return 0;
 }
 
 IRQCHIP_DECLARE(pch_pic, "loongson,pch-pic-1.0", pch_pic_of_init);
+
+#endif
+
+#ifdef CONFIG_ACPI
+static int __init
+pch_lpc_parse_madt(union acpi_subtable_headers *header,
+                      const unsigned long end)
+{
+       struct acpi_madt_lpc_pic *pchlpc_entry = (struct acpi_madt_lpc_pic *)header;
+
+       return pch_lpc_acpi_init(pch_pic_priv[0]->pic_domain, pchlpc_entry);
+}
+
+static int __init acpi_cascade_irqdomain_init(void)
+{
+       acpi_table_parse_madt(ACPI_MADT_TYPE_LPC_PIC,
+                             pch_lpc_parse_madt, 0);
+       return 0;
+}
+
+int __init pch_pic_acpi_init(struct irq_domain *parent,
+                                       struct acpi_madt_bio_pic *acpi_pchpic)
+{
+       int ret, vec_base;
+       struct fwnode_handle *domain_handle;
+
+       vec_base = acpi_pchpic->gsi_base - GSI_MIN_PCH_IRQ;
+
+       domain_handle = irq_domain_alloc_fwnode((phys_addr_t *)acpi_pchpic);
+       if (!domain_handle) {
+               pr_err("Unable to allocate domain handle\n");
+               return -ENOMEM;
+       }
+
+       ret = pch_pic_init(acpi_pchpic->address, acpi_pchpic->size,
+                               vec_base, parent, domain_handle, acpi_pchpic->gsi_base);
+
+       if (ret < 0) {
+               irq_domain_free_fwnode(domain_handle);
+               return ret;
+       }
+
+       if (acpi_pchpic->id == 0)
+               acpi_cascade_irqdomain_init();
+
+       return ret;
+}
+#endif
index ff89b36..1ba0f15 100644 (file)
@@ -52,13 +52,15 @@ static DEFINE_PER_CPU_READ_MOSTLY(unsigned long[GIC_MAX_LONGS], pcpu_masks);
 
 static DEFINE_SPINLOCK(gic_lock);
 static struct irq_domain *gic_irq_domain;
-static struct irq_domain *gic_ipi_domain;
 static int gic_shared_intrs;
 static unsigned int gic_cpu_pin;
 static unsigned int timer_cpu_pin;
 static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller;
+
+#ifdef CONFIG_GENERIC_IRQ_IPI
 static DECLARE_BITMAP(ipi_resrv, GIC_MAX_INTRS);
 static DECLARE_BITMAP(ipi_available, GIC_MAX_INTRS);
+#endif /* CONFIG_GENERIC_IRQ_IPI */
 
 static struct gic_all_vpes_chip_data {
        u32     map;
@@ -472,9 +474,11 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
        u32 map;
 
        if (hwirq >= GIC_SHARED_HWIRQ_BASE) {
+#ifdef CONFIG_GENERIC_IRQ_IPI
                /* verify that shared irqs don't conflict with an IPI irq */
                if (test_bit(GIC_HWIRQ_TO_SHARED(hwirq), ipi_resrv))
                        return -EBUSY;
+#endif /* CONFIG_GENERIC_IRQ_IPI */
 
                err = irq_domain_set_hwirq_and_chip(d, virq, hwirq,
                                                    &gic_level_irq_controller,
@@ -567,6 +571,8 @@ static const struct irq_domain_ops gic_irq_domain_ops = {
        .map = gic_irq_domain_map,
 };
 
+#ifdef CONFIG_GENERIC_IRQ_IPI
+
 static int gic_ipi_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
                                const u32 *intspec, unsigned int intsize,
                                irq_hw_number_t *out_hwirq,
@@ -670,6 +676,48 @@ static const struct irq_domain_ops gic_ipi_domain_ops = {
        .match = gic_ipi_domain_match,
 };
 
+static int gic_register_ipi_domain(struct device_node *node)
+{
+       struct irq_domain *gic_ipi_domain;
+       unsigned int v[2], num_ipis;
+
+       gic_ipi_domain = irq_domain_add_hierarchy(gic_irq_domain,
+                                                 IRQ_DOMAIN_FLAG_IPI_PER_CPU,
+                                                 GIC_NUM_LOCAL_INTRS + gic_shared_intrs,
+                                                 node, &gic_ipi_domain_ops, NULL);
+       if (!gic_ipi_domain) {
+               pr_err("Failed to add IPI domain");
+               return -ENXIO;
+       }
+
+       irq_domain_update_bus_token(gic_ipi_domain, DOMAIN_BUS_IPI);
+
+       if (node &&
+           !of_property_read_u32_array(node, "mti,reserved-ipi-vectors", v, 2)) {
+               bitmap_set(ipi_resrv, v[0], v[1]);
+       } else {
+               /*
+                * Reserve 2 interrupts per possible CPU/VP for use as IPIs,
+                * meeting the requirements of arch/mips SMP.
+                */
+               num_ipis = 2 * num_possible_cpus();
+               bitmap_set(ipi_resrv, gic_shared_intrs - num_ipis, num_ipis);
+       }
+
+       bitmap_copy(ipi_available, ipi_resrv, GIC_MAX_INTRS);
+
+       return 0;
+}
+
+#else /* !CONFIG_GENERIC_IRQ_IPI */
+
+static inline int gic_register_ipi_domain(struct device_node *node)
+{
+       return 0;
+}
+
+#endif /* !CONFIG_GENERIC_IRQ_IPI */
+
 static int gic_cpu_startup(unsigned int cpu)
 {
        /* Enable or disable EIC */
@@ -688,11 +736,12 @@ static int gic_cpu_startup(unsigned int cpu)
 static int __init gic_of_init(struct device_node *node,
                              struct device_node *parent)
 {
-       unsigned int cpu_vec, i, gicconfig, v[2], num_ipis;
+       unsigned int cpu_vec, i, gicconfig;
        unsigned long reserved;
        phys_addr_t gic_base;
        struct resource res;
        size_t gic_len;
+       int ret;
 
        /* Find the first available CPU vector. */
        i = 0;
@@ -734,6 +783,10 @@ static int __init gic_of_init(struct device_node *node,
        }
 
        mips_gic_base = ioremap(gic_base, gic_len);
+       if (!mips_gic_base) {
+               pr_err("Failed to ioremap gic_base\n");
+               return -ENOMEM;
+       }
 
        gicconfig = read_gic_config();
        gic_shared_intrs = FIELD_GET(GIC_CONFIG_NUMINTERRUPTS, gicconfig);
@@ -780,30 +833,9 @@ static int __init gic_of_init(struct device_node *node,
                return -ENXIO;
        }
 
-       gic_ipi_domain = irq_domain_add_hierarchy(gic_irq_domain,
-                                                 IRQ_DOMAIN_FLAG_IPI_PER_CPU,
-                                                 GIC_NUM_LOCAL_INTRS + gic_shared_intrs,
-                                                 node, &gic_ipi_domain_ops, NULL);
-       if (!gic_ipi_domain) {
-               pr_err("Failed to add IPI domain");
-               return -ENXIO;
-       }
-
-       irq_domain_update_bus_token(gic_ipi_domain, DOMAIN_BUS_IPI);
-
-       if (node &&
-           !of_property_read_u32_array(node, "mti,reserved-ipi-vectors", v, 2)) {
-               bitmap_set(ipi_resrv, v[0], v[1]);
-       } else {
-               /*
-                * Reserve 2 interrupts per possible CPU/VP for use as IPIs,
-                * meeting the requirements of arch/mips SMP.
-                */
-               num_ipis = 2 * num_possible_cpus();
-               bitmap_set(ipi_resrv, gic_shared_intrs - num_ipis, num_ipis);
-       }
-
-       bitmap_copy(ipi_available, ipi_resrv, GIC_MAX_INTRS);
+       ret = gic_register_ipi_domain(node);
+       if (ret)
+               return ret;
 
        board_bind_eic_interrupt = &gic_bind_eic_interrupt;
 
index 49b47e7..f289ccd 100644 (file)
@@ -66,7 +66,6 @@ static struct or1k_pic_dev or1k_pic_level = {
                .name = "or1k-PIC-level",
                .irq_unmask = or1k_pic_unmask,
                .irq_mask = or1k_pic_mask,
-               .irq_mask_ack = or1k_pic_mask_ack,
        },
        .handle = handle_level_irq,
        .flags = IRQ_LEVEL | IRQ_NOPROBE,
diff --git a/drivers/irqchip/irq-renesas-rzg2l.c b/drivers/irqchip/irq-renesas-rzg2l.c
new file mode 100644 (file)
index 0000000..25fd8ee
--- /dev/null
@@ -0,0 +1,393 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas RZ/G2L IRQC Driver
+ *
+ * Copyright (C) 2022 Renesas Electronics Corporation.
+ *
+ * Author: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/spinlock.h>
+
+#define IRQC_IRQ_START                 1
+#define IRQC_IRQ_COUNT                 8
+#define IRQC_TINT_START                        (IRQC_IRQ_START + IRQC_IRQ_COUNT)
+#define IRQC_TINT_COUNT                        32
+#define IRQC_NUM_IRQ                   (IRQC_TINT_START + IRQC_TINT_COUNT)
+
+#define ISCR                           0x10
+#define IITSR                          0x14
+#define TSCR                           0x20
+#define TITSR0                         0x24
+#define TITSR1                         0x28
+#define TITSR0_MAX_INT                 16
+#define TITSEL_WIDTH                   0x2
+#define TSSR(n)                                (0x30 + ((n) * 4))
+#define TIEN                           BIT(7)
+#define TSSEL_SHIFT(n)                 (8 * (n))
+#define TSSEL_MASK                     GENMASK(7, 0)
+#define IRQ_MASK                       0x3
+
+#define TSSR_OFFSET(n)                 ((n) % 4)
+#define TSSR_INDEX(n)                  ((n) / 4)
+
+#define TITSR_TITSEL_EDGE_RISING       0
+#define TITSR_TITSEL_EDGE_FALLING      1
+#define TITSR_TITSEL_LEVEL_HIGH                2
+#define TITSR_TITSEL_LEVEL_LOW         3
+
+#define IITSR_IITSEL(n, sense)         ((sense) << ((n) * 2))
+#define IITSR_IITSEL_LEVEL_LOW         0
+#define IITSR_IITSEL_EDGE_FALLING      1
+#define IITSR_IITSEL_EDGE_RISING       2
+#define IITSR_IITSEL_EDGE_BOTH         3
+#define IITSR_IITSEL_MASK(n)           IITSR_IITSEL((n), 3)
+
+#define TINT_EXTRACT_HWIRQ(x)           FIELD_GET(GENMASK(15, 0), (x))
+#define TINT_EXTRACT_GPIOINT(x)         FIELD_GET(GENMASK(31, 16), (x))
+
+struct rzg2l_irqc_priv {
+       void __iomem *base;
+       struct irq_fwspec fwspec[IRQC_NUM_IRQ];
+       raw_spinlock_t lock;
+};
+
+static struct rzg2l_irqc_priv *irq_data_to_priv(struct irq_data *data)
+{
+       return data->domain->host_data;
+}
+
+static void rzg2l_irq_eoi(struct irq_data *d)
+{
+       unsigned int hw_irq = irqd_to_hwirq(d) - IRQC_IRQ_START;
+       struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
+       u32 bit = BIT(hw_irq);
+       u32 reg;
+
+       reg = readl_relaxed(priv->base + ISCR);
+       if (reg & bit)
+               writel_relaxed(reg & ~bit, priv->base + ISCR);
+}
+
+static void rzg2l_tint_eoi(struct irq_data *d)
+{
+       unsigned int hw_irq = irqd_to_hwirq(d) - IRQC_TINT_START;
+       struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
+       u32 bit = BIT(hw_irq);
+       u32 reg;
+
+       reg = readl_relaxed(priv->base + TSCR);
+       if (reg & bit)
+               writel_relaxed(reg & ~bit, priv->base + TSCR);
+}
+
+static void rzg2l_irqc_eoi(struct irq_data *d)
+{
+       struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
+       unsigned int hw_irq = irqd_to_hwirq(d);
+
+       raw_spin_lock(&priv->lock);
+       if (hw_irq >= IRQC_IRQ_START && hw_irq <= IRQC_IRQ_COUNT)
+               rzg2l_irq_eoi(d);
+       else if (hw_irq >= IRQC_TINT_START && hw_irq < IRQC_NUM_IRQ)
+               rzg2l_tint_eoi(d);
+       raw_spin_unlock(&priv->lock);
+       irq_chip_eoi_parent(d);
+}
+
+static void rzg2l_irqc_irq_disable(struct irq_data *d)
+{
+       unsigned int hw_irq = irqd_to_hwirq(d);
+
+       if (hw_irq >= IRQC_TINT_START && hw_irq < IRQC_NUM_IRQ) {
+               struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
+               u32 offset = hw_irq - IRQC_TINT_START;
+               u32 tssr_offset = TSSR_OFFSET(offset);
+               u8 tssr_index = TSSR_INDEX(offset);
+               u32 reg;
+
+               raw_spin_lock(&priv->lock);
+               reg = readl_relaxed(priv->base + TSSR(tssr_index));
+               reg &= ~(TSSEL_MASK << tssr_offset);
+               writel_relaxed(reg, priv->base + TSSR(tssr_index));
+               raw_spin_unlock(&priv->lock);
+       }
+       irq_chip_disable_parent(d);
+}
+
+static void rzg2l_irqc_irq_enable(struct irq_data *d)
+{
+       unsigned int hw_irq = irqd_to_hwirq(d);
+
+       if (hw_irq >= IRQC_TINT_START && hw_irq < IRQC_NUM_IRQ) {
+               struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
+               unsigned long tint = (uintptr_t)d->chip_data;
+               u32 offset = hw_irq - IRQC_TINT_START;
+               u32 tssr_offset = TSSR_OFFSET(offset);
+               u8 tssr_index = TSSR_INDEX(offset);
+               u32 reg;
+
+               raw_spin_lock(&priv->lock);
+               reg = readl_relaxed(priv->base + TSSR(tssr_index));
+               reg |= (TIEN | tint) << TSSEL_SHIFT(tssr_offset);
+               writel_relaxed(reg, priv->base + TSSR(tssr_index));
+               raw_spin_unlock(&priv->lock);
+       }
+       irq_chip_enable_parent(d);
+}
+
+static int rzg2l_irq_set_type(struct irq_data *d, unsigned int type)
+{
+       unsigned int hw_irq = irqd_to_hwirq(d) - IRQC_IRQ_START;
+       struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
+       u16 sense, tmp;
+
+       switch (type & IRQ_TYPE_SENSE_MASK) {
+       case IRQ_TYPE_LEVEL_LOW:
+               sense = IITSR_IITSEL_LEVEL_LOW;
+               break;
+
+       case IRQ_TYPE_EDGE_FALLING:
+               sense = IITSR_IITSEL_EDGE_FALLING;
+               break;
+
+       case IRQ_TYPE_EDGE_RISING:
+               sense = IITSR_IITSEL_EDGE_RISING;
+               break;
+
+       case IRQ_TYPE_EDGE_BOTH:
+               sense = IITSR_IITSEL_EDGE_BOTH;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       raw_spin_lock(&priv->lock);
+       tmp = readl_relaxed(priv->base + IITSR);
+       tmp &= ~IITSR_IITSEL_MASK(hw_irq);
+       tmp |= IITSR_IITSEL(hw_irq, sense);
+       writel_relaxed(tmp, priv->base + IITSR);
+       raw_spin_unlock(&priv->lock);
+
+       return 0;
+}
+
+static int rzg2l_tint_set_edge(struct irq_data *d, unsigned int type)
+{
+       struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
+       unsigned int hwirq = irqd_to_hwirq(d);
+       u32 titseln = hwirq - IRQC_TINT_START;
+       u32 offset;
+       u8 sense;
+       u32 reg;
+
+       switch (type & IRQ_TYPE_SENSE_MASK) {
+       case IRQ_TYPE_EDGE_RISING:
+               sense = TITSR_TITSEL_EDGE_RISING;
+               break;
+
+       case IRQ_TYPE_EDGE_FALLING:
+               sense = TITSR_TITSEL_EDGE_FALLING;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       offset = TITSR0;
+       if (titseln >= TITSR0_MAX_INT) {
+               titseln -= TITSR0_MAX_INT;
+               offset = TITSR1;
+       }
+
+       raw_spin_lock(&priv->lock);
+       reg = readl_relaxed(priv->base + offset);
+       reg &= ~(IRQ_MASK << (titseln * TITSEL_WIDTH));
+       reg |= sense << (titseln * TITSEL_WIDTH);
+       writel_relaxed(reg, priv->base + offset);
+       raw_spin_unlock(&priv->lock);
+
+       return 0;
+}
+
+static int rzg2l_irqc_set_type(struct irq_data *d, unsigned int type)
+{
+       unsigned int hw_irq = irqd_to_hwirq(d);
+       int ret = -EINVAL;
+
+       if (hw_irq >= IRQC_IRQ_START && hw_irq <= IRQC_IRQ_COUNT)
+               ret = rzg2l_irq_set_type(d, type);
+       else if (hw_irq >= IRQC_TINT_START && hw_irq < IRQC_NUM_IRQ)
+               ret = rzg2l_tint_set_edge(d, type);
+       if (ret)
+               return ret;
+
+       return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH);
+}
+
+static const struct irq_chip irqc_chip = {
+       .name                   = "rzg2l-irqc",
+       .irq_eoi                = rzg2l_irqc_eoi,
+       .irq_mask               = irq_chip_mask_parent,
+       .irq_unmask             = irq_chip_unmask_parent,
+       .irq_disable            = rzg2l_irqc_irq_disable,
+       .irq_enable             = rzg2l_irqc_irq_enable,
+       .irq_get_irqchip_state  = irq_chip_get_parent_state,
+       .irq_set_irqchip_state  = irq_chip_set_parent_state,
+       .irq_retrigger          = irq_chip_retrigger_hierarchy,
+       .irq_set_type           = rzg2l_irqc_set_type,
+       .flags                  = IRQCHIP_MASK_ON_SUSPEND |
+                                 IRQCHIP_SET_TYPE_MASKED |
+                                 IRQCHIP_SKIP_SET_WAKE,
+};
+
+static int rzg2l_irqc_alloc(struct irq_domain *domain, unsigned int virq,
+                           unsigned int nr_irqs, void *arg)
+{
+       struct rzg2l_irqc_priv *priv = domain->host_data;
+       unsigned long tint = 0;
+       irq_hw_number_t hwirq;
+       unsigned int type;
+       int ret;
+
+       ret = irq_domain_translate_twocell(domain, arg, &hwirq, &type);
+       if (ret)
+               return ret;
+
+       /*
+        * For TINT interrupts ie where pinctrl driver is child of irqc domain
+        * the hwirq and TINT are encoded in fwspec->param[0].
+        * hwirq for TINT range from 9-40, hwirq is embedded 0-15 bits and TINT
+        * from 16-31 bits. TINT from the pinctrl driver needs to be programmed
+        * in IRQC registers to enable a given gpio pin as interrupt.
+        */
+       if (hwirq > IRQC_IRQ_COUNT) {
+               tint = TINT_EXTRACT_GPIOINT(hwirq);
+               hwirq = TINT_EXTRACT_HWIRQ(hwirq);
+
+               if (hwirq < IRQC_TINT_START)
+                       return -EINVAL;
+       }
+
+       if (hwirq > (IRQC_NUM_IRQ - 1))
+               return -EINVAL;
+
+       ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, &irqc_chip,
+                                           (void *)(uintptr_t)tint);
+       if (ret)
+               return ret;
+
+       return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &priv->fwspec[hwirq]);
+}
+
+static const struct irq_domain_ops rzg2l_irqc_domain_ops = {
+       .alloc = rzg2l_irqc_alloc,
+       .free = irq_domain_free_irqs_common,
+       .translate = irq_domain_translate_twocell,
+};
+
+static int rzg2l_irqc_parse_interrupts(struct rzg2l_irqc_priv *priv,
+                                      struct device_node *np)
+{
+       struct of_phandle_args map;
+       unsigned int i;
+       int ret;
+
+       for (i = 0; i < IRQC_NUM_IRQ; i++) {
+               ret = of_irq_parse_one(np, i, &map);
+               if (ret)
+                       return ret;
+               of_phandle_args_to_fwspec(np, map.args, map.args_count,
+                                         &priv->fwspec[i]);
+       }
+
+       return 0;
+}
+
+static int rzg2l_irqc_init(struct device_node *node, struct device_node *parent)
+{
+       struct irq_domain *irq_domain, *parent_domain;
+       struct platform_device *pdev;
+       struct reset_control *resetn;
+       struct rzg2l_irqc_priv *priv;
+       int ret;
+
+       pdev = of_find_device_by_node(node);
+       if (!pdev)
+               return -ENODEV;
+
+       parent_domain = irq_find_host(parent);
+       if (!parent_domain) {
+               dev_err(&pdev->dev, "cannot find parent domain\n");
+               return -ENODEV;
+       }
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->base = devm_of_iomap(&pdev->dev, pdev->dev.of_node, 0, NULL);
+       if (IS_ERR(priv->base))
+               return PTR_ERR(priv->base);
+
+       ret = rzg2l_irqc_parse_interrupts(priv, node);
+       if (ret) {
+               dev_err(&pdev->dev, "cannot parse interrupts: %d\n", ret);
+               return ret;
+       }
+
+       resetn = devm_reset_control_get_exclusive(&pdev->dev, NULL);
+       if (IS_ERR(resetn))
+               return PTR_ERR(resetn);
+
+       ret = reset_control_deassert(resetn);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to deassert resetn pin, %d\n", ret);
+               return ret;
+       }
+
+       pm_runtime_enable(&pdev->dev);
+       ret = pm_runtime_resume_and_get(&pdev->dev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "pm_runtime_resume_and_get failed: %d\n", ret);
+               goto pm_disable;
+       }
+
+       raw_spin_lock_init(&priv->lock);
+
+       irq_domain = irq_domain_add_hierarchy(parent_domain, 0, IRQC_NUM_IRQ,
+                                             node, &rzg2l_irqc_domain_ops,
+                                             priv);
+       if (!irq_domain) {
+               dev_err(&pdev->dev, "failed to add irq domain\n");
+               ret = -ENOMEM;
+               goto pm_put;
+       }
+
+       return 0;
+
+pm_put:
+       pm_runtime_put(&pdev->dev);
+pm_disable:
+       pm_runtime_disable(&pdev->dev);
+       reset_control_assert(resetn);
+       return ret;
+}
+
+IRQCHIP_PLATFORM_DRIVER_BEGIN(rzg2l_irqc)
+IRQCHIP_MATCH("renesas,rzg2l-irqc", rzg2l_irqc_init)
+IRQCHIP_PLATFORM_DRIVER_END(rzg2l_irqc)
+MODULE_AUTHOR("Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>");
+MODULE_DESCRIPTION("Renesas RZ/G2L IRQC Driver");
+MODULE_LICENSE("GPL");
index bb87e4c..ba49381 100644 (file)
 #define        PLIC_DISABLE_THRESHOLD          0x7
 #define        PLIC_ENABLE_THRESHOLD           0
 
+#define PLIC_QUIRK_EDGE_INTERRUPT      0
+
 struct plic_priv {
        struct cpumask lmask;
        struct irq_domain *irqdomain;
        void __iomem *regs;
+       unsigned long plic_quirks;
 };
 
 struct plic_handler {
@@ -81,6 +84,8 @@ static int plic_parent_irq __ro_after_init;
 static bool plic_cpuhp_setup_done __ro_after_init;
 static DEFINE_PER_CPU(struct plic_handler, plic_handlers);
 
+static int plic_irq_set_type(struct irq_data *d, unsigned int type);
+
 static void __plic_toggle(void __iomem *enable_base, int hwirq, int enable)
 {
        u32 __iomem *reg = enable_base + (hwirq / 32) * sizeof(u32);
@@ -103,37 +108,43 @@ static inline void plic_irq_toggle(const struct cpumask *mask,
                                   struct irq_data *d, int enable)
 {
        int cpu;
-       struct plic_priv *priv = irq_data_get_irq_chip_data(d);
 
-       writel(enable, priv->regs + PRIORITY_BASE + d->hwirq * PRIORITY_PER_ID);
        for_each_cpu(cpu, mask) {
                struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu);
 
-               if (handler->present &&
-                   cpumask_test_cpu(cpu, &handler->priv->lmask))
-                       plic_toggle(handler, d->hwirq, enable);
+               plic_toggle(handler, d->hwirq, enable);
        }
 }
 
+static void plic_irq_enable(struct irq_data *d)
+{
+       plic_irq_toggle(irq_data_get_effective_affinity_mask(d), d, 1);
+}
+
+static void plic_irq_disable(struct irq_data *d)
+{
+       plic_irq_toggle(irq_data_get_effective_affinity_mask(d), d, 0);
+}
+
 static void plic_irq_unmask(struct irq_data *d)
 {
-       struct cpumask amask;
-       unsigned int cpu;
        struct plic_priv *priv = irq_data_get_irq_chip_data(d);
 
-       cpumask_and(&amask, &priv->lmask, cpu_online_mask);
-       cpu = cpumask_any_and(irq_data_get_affinity_mask(d),
-                                          &amask);
-       if (WARN_ON_ONCE(cpu >= nr_cpu_ids))
-               return;
-       plic_irq_toggle(cpumask_of(cpu), d, 1);
+       writel(1, priv->regs + PRIORITY_BASE + d->hwirq * PRIORITY_PER_ID);
 }
 
 static void plic_irq_mask(struct irq_data *d)
 {
        struct plic_priv *priv = irq_data_get_irq_chip_data(d);
 
-       plic_irq_toggle(&priv->lmask, d, 0);
+       writel(0, priv->regs + PRIORITY_BASE + d->hwirq * PRIORITY_PER_ID);
+}
+
+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);
 }
 
 #ifdef CONFIG_SMP
@@ -154,38 +165,68 @@ static int plic_set_affinity(struct irq_data *d,
        if (cpu >= nr_cpu_ids)
                return -EINVAL;
 
-       plic_irq_toggle(&priv->lmask, d, 0);
-       plic_irq_toggle(cpumask_of(cpu), d, !irqd_irq_masked(d));
+       plic_irq_disable(d);
 
        irq_data_update_effective_affinity(d, cpumask_of(cpu));
 
+       if (!irqd_irq_disabled(d))
+               plic_irq_enable(d);
+
        return IRQ_SET_MASK_OK_DONE;
 }
 #endif
 
-static void plic_irq_eoi(struct irq_data *d)
-{
-       struct plic_handler *handler = this_cpu_ptr(&plic_handlers);
-
-       if (irqd_irq_masked(d)) {
-               plic_irq_unmask(d);
-               writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM);
-               plic_irq_mask(d);
-       } else {
-               writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM);
-       }
-}
+static struct irq_chip plic_edge_chip = {
+       .name           = "SiFive PLIC",
+       .irq_enable     = plic_irq_enable,
+       .irq_disable    = plic_irq_disable,
+       .irq_ack        = plic_irq_eoi,
+       .irq_mask       = plic_irq_mask,
+       .irq_unmask     = plic_irq_unmask,
+#ifdef CONFIG_SMP
+       .irq_set_affinity = plic_set_affinity,
+#endif
+       .irq_set_type   = plic_irq_set_type,
+       .flags          = IRQCHIP_AFFINITY_PRE_STARTUP,
+};
 
 static struct irq_chip plic_chip = {
        .name           = "SiFive PLIC",
+       .irq_enable     = plic_irq_enable,
+       .irq_disable    = plic_irq_disable,
        .irq_mask       = plic_irq_mask,
        .irq_unmask     = plic_irq_unmask,
        .irq_eoi        = plic_irq_eoi,
 #ifdef CONFIG_SMP
        .irq_set_affinity = plic_set_affinity,
 #endif
+       .irq_set_type   = plic_irq_set_type,
+       .flags          = IRQCHIP_AFFINITY_PRE_STARTUP,
 };
 
+static int plic_irq_set_type(struct irq_data *d, unsigned int type)
+{
+       struct plic_priv *priv = irq_data_get_irq_chip_data(d);
+
+       if (!test_bit(PLIC_QUIRK_EDGE_INTERRUPT, &priv->plic_quirks))
+               return IRQ_SET_MASK_OK_NOCOPY;
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+               irq_set_chip_handler_name_locked(d, &plic_edge_chip,
+                                                handle_edge_irq, NULL);
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               irq_set_chip_handler_name_locked(d, &plic_chip,
+                                                handle_fasteoi_irq, NULL);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return IRQ_SET_MASK_OK;
+}
+
 static int plic_irqdomain_map(struct irq_domain *d, unsigned int irq,
                              irq_hw_number_t hwirq)
 {
@@ -198,6 +239,19 @@ static int plic_irqdomain_map(struct irq_domain *d, unsigned int irq,
        return 0;
 }
 
+static int plic_irq_domain_translate(struct irq_domain *d,
+                                    struct irq_fwspec *fwspec,
+                                    unsigned long *hwirq,
+                                    unsigned int *type)
+{
+       struct plic_priv *priv = d->host_data;
+
+       if (test_bit(PLIC_QUIRK_EDGE_INTERRUPT, &priv->plic_quirks))
+               return irq_domain_translate_twocell(d, fwspec, hwirq, type);
+
+       return irq_domain_translate_onecell(d, fwspec, hwirq, type);
+}
+
 static int plic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
                                 unsigned int nr_irqs, void *arg)
 {
@@ -206,7 +260,7 @@ static int plic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
        unsigned int type;
        struct irq_fwspec *fwspec = arg;
 
-       ret = irq_domain_translate_onecell(domain, fwspec, &hwirq, &type);
+       ret = plic_irq_domain_translate(domain, fwspec, &hwirq, &type);
        if (ret)
                return ret;
 
@@ -220,7 +274,7 @@ static int plic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
 }
 
 static const struct irq_domain_ops plic_irqdomain_ops = {
-       .translate      = irq_domain_translate_onecell,
+       .translate      = plic_irq_domain_translate,
        .alloc          = plic_irq_domain_alloc,
        .free           = irq_domain_free_irqs_top,
 };
@@ -281,8 +335,9 @@ static int plic_starting_cpu(unsigned int cpu)
        return 0;
 }
 
-static int __init plic_init(struct device_node *node,
-               struct device_node *parent)
+static int __init __plic_init(struct device_node *node,
+                             struct device_node *parent,
+                             unsigned long plic_quirks)
 {
        int error = 0, nr_contexts, nr_handlers = 0, i;
        u32 nr_irqs;
@@ -293,6 +348,8 @@ static int __init plic_init(struct device_node *node,
        if (!priv)
                return -ENOMEM;
 
+       priv->plic_quirks = plic_quirks;
+
        priv->regs = of_iomap(node, 0);
        if (WARN_ON(!priv->regs)) {
                error = -EIO;
@@ -382,8 +439,11 @@ static int __init plic_init(struct device_node *node,
                        i * CONTEXT_ENABLE_SIZE;
                handler->priv = priv;
 done:
-               for (hwirq = 1; hwirq <= nr_irqs; hwirq++)
+               for (hwirq = 1; hwirq <= nr_irqs; hwirq++) {
                        plic_toggle(handler, hwirq, 0);
+                       writel(1, priv->regs + PRIORITY_BASE +
+                                 hwirq * PRIORITY_PER_ID);
+               }
                nr_handlers++;
        }
 
@@ -410,6 +470,20 @@ out_free_priv:
        return error;
 }
 
+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 */
-IRQCHIP_DECLARE(thead_c900_plic, "thead,c900-plic", plic_init); /* for firmware driver */
+
+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);
diff --git a/drivers/irqchip/irq-sp7021-intc.c b/drivers/irqchip/irq-sp7021-intc.c
new file mode 100644 (file)
index 0000000..bed78d1
--- /dev/null
@@ -0,0 +1,278 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * Copyright (C) Sunplus Technology Co., Ltd.
+ *       All rights reserved.
+ */
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/io.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#define SP_INTC_HWIRQ_MIN      0
+#define SP_INTC_HWIRQ_MAX      223
+
+#define SP_INTC_NR_IRQS                (SP_INTC_HWIRQ_MAX - SP_INTC_HWIRQ_MIN + 1)
+#define SP_INTC_NR_GROUPS      DIV_ROUND_UP(SP_INTC_NR_IRQS, 32)
+#define SP_INTC_REG_SIZE       (SP_INTC_NR_GROUPS * 4)
+
+/* REG_GROUP_0 regs */
+#define REG_INTR_TYPE          (sp_intc.g0)
+#define REG_INTR_POLARITY      (REG_INTR_TYPE     + SP_INTC_REG_SIZE)
+#define REG_INTR_PRIORITY      (REG_INTR_POLARITY + SP_INTC_REG_SIZE)
+#define REG_INTR_MASK          (REG_INTR_PRIORITY + SP_INTC_REG_SIZE)
+
+/* REG_GROUP_1 regs */
+#define REG_INTR_CLEAR         (sp_intc.g1)
+#define REG_MASKED_EXT1                (REG_INTR_CLEAR    + SP_INTC_REG_SIZE)
+#define REG_MASKED_EXT0                (REG_MASKED_EXT1   + SP_INTC_REG_SIZE)
+#define REG_INTR_GROUP         (REG_INTR_CLEAR    + 31 * 4)
+
+#define GROUP_MASK             (BIT(SP_INTC_NR_GROUPS) - 1)
+#define GROUP_SHIFT_EXT1       (0)
+#define GROUP_SHIFT_EXT0       (8)
+
+/*
+ * When GPIO_INT0~7 set to edge trigger, doesn't work properly.
+ * WORKAROUND: change it to level trigger, and toggle the polarity
+ * at ACK/Handler to make the HW work.
+ */
+#define GPIO_INT0_HWIRQ                120
+#define GPIO_INT7_HWIRQ                127
+#define IS_GPIO_INT(irq)                                       \
+({                                                             \
+       u32 i = irq;                                            \
+       (i >= GPIO_INT0_HWIRQ) && (i <= GPIO_INT7_HWIRQ);       \
+})
+
+/* index of states */
+enum {
+       _IS_EDGE = 0,
+       _IS_LOW,
+       _IS_ACTIVE
+};
+
+#define STATE_BIT(irq, idx)            (((irq) - GPIO_INT0_HWIRQ) * 3 + (idx))
+#define ASSIGN_STATE(irq, idx, v)      assign_bit(STATE_BIT(irq, idx), sp_intc.states, v)
+#define TEST_STATE(irq, idx)           test_bit(STATE_BIT(irq, idx), sp_intc.states)
+
+static struct sp_intctl {
+       /*
+        * REG_GROUP_0: include type/polarity/priority/mask regs.
+        * REG_GROUP_1: include clear/masked_ext0/masked_ext1/group regs.
+        */
+       void __iomem *g0; // REG_GROUP_0 base
+       void __iomem *g1; // REG_GROUP_1 base
+
+       struct irq_domain *domain;
+       raw_spinlock_t lock;
+
+       /*
+        * store GPIO_INT states
+        * each interrupt has 3 states: is_edge, is_low, is_active
+        */
+       DECLARE_BITMAP(states, (GPIO_INT7_HWIRQ - GPIO_INT0_HWIRQ + 1) * 3);
+} sp_intc;
+
+static struct irq_chip sp_intc_chip;
+
+static void sp_intc_assign_bit(u32 hwirq, void __iomem *base, bool value)
+{
+       u32 offset, mask;
+       unsigned long flags;
+       void __iomem *reg;
+
+       offset = (hwirq / 32) * 4;
+       reg = base + offset;
+
+       raw_spin_lock_irqsave(&sp_intc.lock, flags);
+       mask = readl_relaxed(reg);
+       if (value)
+               mask |= BIT(hwirq % 32);
+       else
+               mask &= ~BIT(hwirq % 32);
+       writel_relaxed(mask, reg);
+       raw_spin_unlock_irqrestore(&sp_intc.lock, flags);
+}
+
+static void sp_intc_ack_irq(struct irq_data *d)
+{
+       u32 hwirq = d->hwirq;
+
+       if (unlikely(IS_GPIO_INT(hwirq) && TEST_STATE(hwirq, _IS_EDGE))) { // WORKAROUND
+               sp_intc_assign_bit(hwirq, REG_INTR_POLARITY, !TEST_STATE(hwirq, _IS_LOW));
+               ASSIGN_STATE(hwirq, _IS_ACTIVE, true);
+       }
+
+       sp_intc_assign_bit(hwirq, REG_INTR_CLEAR, 1);
+}
+
+static void sp_intc_mask_irq(struct irq_data *d)
+{
+       sp_intc_assign_bit(d->hwirq, REG_INTR_MASK, 0);
+}
+
+static void sp_intc_unmask_irq(struct irq_data *d)
+{
+       sp_intc_assign_bit(d->hwirq, REG_INTR_MASK, 1);
+}
+
+static int sp_intc_set_type(struct irq_data *d, unsigned int type)
+{
+       u32 hwirq = d->hwirq;
+       bool is_edge = !(type & IRQ_TYPE_LEVEL_MASK);
+       bool is_low = (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_EDGE_FALLING);
+
+       irq_set_handler_locked(d, is_edge ? handle_edge_irq : handle_level_irq);
+
+       if (unlikely(IS_GPIO_INT(hwirq) && is_edge)) { // WORKAROUND
+               /* store states */
+               ASSIGN_STATE(hwirq, _IS_EDGE, is_edge);
+               ASSIGN_STATE(hwirq, _IS_LOW, is_low);
+               ASSIGN_STATE(hwirq, _IS_ACTIVE, false);
+               /* change to level */
+               is_edge = false;
+       }
+
+       sp_intc_assign_bit(hwirq, REG_INTR_TYPE, is_edge);
+       sp_intc_assign_bit(hwirq, REG_INTR_POLARITY, is_low);
+
+       return 0;
+}
+
+static int sp_intc_get_ext_irq(int ext_num)
+{
+       void __iomem *base = ext_num ? REG_MASKED_EXT1 : REG_MASKED_EXT0;
+       u32 shift = ext_num ? GROUP_SHIFT_EXT1 : GROUP_SHIFT_EXT0;
+       u32 groups;
+       u32 pending_group;
+       u32 group;
+       u32 pending_irq;
+
+       groups = readl_relaxed(REG_INTR_GROUP);
+       pending_group = (groups >> shift) & GROUP_MASK;
+       if (!pending_group)
+               return -1;
+
+       group = fls(pending_group) - 1;
+       pending_irq = readl_relaxed(base + group * 4);
+       if (!pending_irq)
+               return -1;
+
+       return (group * 32) + fls(pending_irq) - 1;
+}
+
+static void sp_intc_handle_ext_cascaded(struct irq_desc *desc)
+{
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+       int ext_num = (uintptr_t)irq_desc_get_handler_data(desc);
+       int hwirq;
+
+       chained_irq_enter(chip, desc);
+
+       while ((hwirq = sp_intc_get_ext_irq(ext_num)) >= 0) {
+               if (unlikely(IS_GPIO_INT(hwirq) && TEST_STATE(hwirq, _IS_ACTIVE))) { // WORKAROUND
+                       ASSIGN_STATE(hwirq, _IS_ACTIVE, false);
+                       sp_intc_assign_bit(hwirq, REG_INTR_POLARITY, TEST_STATE(hwirq, _IS_LOW));
+               } else {
+                       generic_handle_domain_irq(sp_intc.domain, hwirq);
+               }
+       }
+
+       chained_irq_exit(chip, desc);
+}
+
+static struct irq_chip sp_intc_chip = {
+       .name = "sp_intc",
+       .irq_ack = sp_intc_ack_irq,
+       .irq_mask = sp_intc_mask_irq,
+       .irq_unmask = sp_intc_unmask_irq,
+       .irq_set_type = sp_intc_set_type,
+};
+
+static int sp_intc_irq_domain_map(struct irq_domain *domain,
+                                 unsigned int irq, irq_hw_number_t hwirq)
+{
+       irq_set_chip_and_handler(irq, &sp_intc_chip, handle_level_irq);
+       irq_set_chip_data(irq, &sp_intc_chip);
+       irq_set_noprobe(irq);
+
+       return 0;
+}
+
+static const struct irq_domain_ops sp_intc_dm_ops = {
+       .xlate = irq_domain_xlate_twocell,
+       .map = sp_intc_irq_domain_map,
+};
+
+static int sp_intc_irq_map(struct device_node *node, int i)
+{
+       unsigned int irq;
+
+       irq = irq_of_parse_and_map(node, i);
+       if (!irq)
+               return -ENOENT;
+
+       irq_set_chained_handler_and_data(irq, sp_intc_handle_ext_cascaded, (void *)(uintptr_t)i);
+
+       return 0;
+}
+
+static int __init sp_intc_init_dt(struct device_node *node, struct device_node *parent)
+{
+       int i, ret;
+
+       sp_intc.g0 = of_iomap(node, 0);
+       if (!sp_intc.g0)
+               return -ENXIO;
+
+       sp_intc.g1 = of_iomap(node, 1);
+       if (!sp_intc.g1) {
+               ret = -ENXIO;
+               goto out_unmap0;
+       }
+
+       ret = sp_intc_irq_map(node, 0); // EXT_INT0
+       if (ret)
+               goto out_unmap1;
+
+       ret = sp_intc_irq_map(node, 1); // EXT_INT1
+       if (ret)
+               goto out_unmap1;
+
+       /* initial regs */
+       for (i = 0; i < SP_INTC_NR_GROUPS; i++) {
+               /* all mask */
+               writel_relaxed(0, REG_INTR_MASK + i * 4);
+               /* all edge */
+               writel_relaxed(~0, REG_INTR_TYPE + i * 4);
+               /* all high-active */
+               writel_relaxed(0, REG_INTR_POLARITY + i * 4);
+               /* all EXT_INT0 */
+               writel_relaxed(~0, REG_INTR_PRIORITY + i * 4);
+               /* all clear */
+               writel_relaxed(~0, REG_INTR_CLEAR + i * 4);
+       }
+
+       sp_intc.domain = irq_domain_add_linear(node, SP_INTC_NR_IRQS,
+                                              &sp_intc_dm_ops, &sp_intc);
+       if (!sp_intc.domain) {
+               ret = -ENOMEM;
+               goto out_unmap1;
+       }
+
+       raw_spin_lock_init(&sp_intc.lock);
+
+       return 0;
+
+out_unmap1:
+       iounmap(sp_intc.g1);
+out_unmap0:
+       iounmap(sp_intc.g0);
+
+       return ret;
+}
+
+IRQCHIP_DECLARE(sp_intc, "sunplus,sp7021-intc", sp_intc_init_dt);
index 9d18f47..a73763d 100644 (file)
@@ -34,21 +34,15 @@ struct stm32_exti_bank {
        u32 swier_ofst;
        u32 rpr_ofst;
        u32 fpr_ofst;
+       u32 trg_ofst;
 };
 
 #define UNDEF_REG ~0
 
-struct stm32_desc_irq {
-       u32 exti;
-       u32 irq_parent;
-       struct irq_chip *chip;
-};
-
 struct stm32_exti_drv_data {
        const struct stm32_exti_bank **exti_banks;
-       const struct stm32_desc_irq *desc_irqs;
+       const u8 *desc_irqs;
        u32 bank_nr;
-       u32 irq_nr;
 };
 
 struct stm32_exti_chip_data {
@@ -78,6 +72,7 @@ static const struct stm32_exti_bank stm32f4xx_exti_b1 = {
        .swier_ofst     = 0x10,
        .rpr_ofst       = 0x14,
        .fpr_ofst       = UNDEF_REG,
+       .trg_ofst       = UNDEF_REG,
 };
 
 static const struct stm32_exti_bank *stm32f4xx_exti_banks[] = {
@@ -97,6 +92,7 @@ static const struct stm32_exti_bank stm32h7xx_exti_b1 = {
        .swier_ofst     = 0x08,
        .rpr_ofst       = 0x88,
        .fpr_ofst       = UNDEF_REG,
+       .trg_ofst       = UNDEF_REG,
 };
 
 static const struct stm32_exti_bank stm32h7xx_exti_b2 = {
@@ -107,6 +103,7 @@ static const struct stm32_exti_bank stm32h7xx_exti_b2 = {
        .swier_ofst     = 0x28,
        .rpr_ofst       = 0x98,
        .fpr_ofst       = UNDEF_REG,
+       .trg_ofst       = UNDEF_REG,
 };
 
 static const struct stm32_exti_bank stm32h7xx_exti_b3 = {
@@ -117,6 +114,7 @@ static const struct stm32_exti_bank stm32h7xx_exti_b3 = {
        .swier_ofst     = 0x48,
        .rpr_ofst       = 0xA8,
        .fpr_ofst       = UNDEF_REG,
+       .trg_ofst       = UNDEF_REG,
 };
 
 static const struct stm32_exti_bank *stm32h7xx_exti_banks[] = {
@@ -132,32 +130,35 @@ static const struct stm32_exti_drv_data stm32h7xx_drv_data = {
 
 static const struct stm32_exti_bank stm32mp1_exti_b1 = {
        .imr_ofst       = 0x80,
-       .emr_ofst       = 0x84,
+       .emr_ofst       = UNDEF_REG,
        .rtsr_ofst      = 0x00,
        .ftsr_ofst      = 0x04,
        .swier_ofst     = 0x08,
        .rpr_ofst       = 0x0C,
        .fpr_ofst       = 0x10,
+       .trg_ofst       = 0x3EC,
 };
 
 static const struct stm32_exti_bank stm32mp1_exti_b2 = {
        .imr_ofst       = 0x90,
-       .emr_ofst       = 0x94,
+       .emr_ofst       = UNDEF_REG,
        .rtsr_ofst      = 0x20,
        .ftsr_ofst      = 0x24,
        .swier_ofst     = 0x28,
        .rpr_ofst       = 0x2C,
        .fpr_ofst       = 0x30,
+       .trg_ofst       = 0x3E8,
 };
 
 static const struct stm32_exti_bank stm32mp1_exti_b3 = {
        .imr_ofst       = 0xA0,
-       .emr_ofst       = 0xA4,
+       .emr_ofst       = UNDEF_REG,
        .rtsr_ofst      = 0x40,
        .ftsr_ofst      = 0x44,
        .swier_ofst     = 0x48,
        .rpr_ofst       = 0x4C,
        .fpr_ofst       = 0x50,
+       .trg_ofst       = 0x3E4,
 };
 
 static const struct stm32_exti_bank *stm32mp1_exti_banks[] = {
@@ -169,126 +170,114 @@ static const struct stm32_exti_bank *stm32mp1_exti_banks[] = {
 static struct irq_chip stm32_exti_h_chip;
 static struct irq_chip stm32_exti_h_chip_direct;
 
-static const struct stm32_desc_irq stm32mp1_desc_irq[] = {
-       { .exti = 0, .irq_parent = 6, .chip = &stm32_exti_h_chip },
-       { .exti = 1, .irq_parent = 7, .chip = &stm32_exti_h_chip },
-       { .exti = 2, .irq_parent = 8, .chip = &stm32_exti_h_chip },
-       { .exti = 3, .irq_parent = 9, .chip = &stm32_exti_h_chip },
-       { .exti = 4, .irq_parent = 10, .chip = &stm32_exti_h_chip },
-       { .exti = 5, .irq_parent = 23, .chip = &stm32_exti_h_chip },
-       { .exti = 6, .irq_parent = 64, .chip = &stm32_exti_h_chip },
-       { .exti = 7, .irq_parent = 65, .chip = &stm32_exti_h_chip },
-       { .exti = 8, .irq_parent = 66, .chip = &stm32_exti_h_chip },
-       { .exti = 9, .irq_parent = 67, .chip = &stm32_exti_h_chip },
-       { .exti = 10, .irq_parent = 40, .chip = &stm32_exti_h_chip },
-       { .exti = 11, .irq_parent = 42, .chip = &stm32_exti_h_chip },
-       { .exti = 12, .irq_parent = 76, .chip = &stm32_exti_h_chip },
-       { .exti = 13, .irq_parent = 77, .chip = &stm32_exti_h_chip },
-       { .exti = 14, .irq_parent = 121, .chip = &stm32_exti_h_chip },
-       { .exti = 15, .irq_parent = 127, .chip = &stm32_exti_h_chip },
-       { .exti = 16, .irq_parent = 1, .chip = &stm32_exti_h_chip },
-       { .exti = 19, .irq_parent = 3, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 21, .irq_parent = 31, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 22, .irq_parent = 33, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 23, .irq_parent = 72, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 24, .irq_parent = 95, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 25, .irq_parent = 107, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 26, .irq_parent = 37, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 27, .irq_parent = 38, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 28, .irq_parent = 39, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 29, .irq_parent = 71, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 30, .irq_parent = 52, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 31, .irq_parent = 53, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 32, .irq_parent = 82, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 33, .irq_parent = 83, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 47, .irq_parent = 93, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 48, .irq_parent = 138, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 50, .irq_parent = 139, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 52, .irq_parent = 140, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 53, .irq_parent = 141, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 54, .irq_parent = 135, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 61, .irq_parent = 100, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 65, .irq_parent = 144, .chip = &stm32_exti_h_chip },
-       { .exti = 68, .irq_parent = 143, .chip = &stm32_exti_h_chip },
-       { .exti = 70, .irq_parent = 62, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 73, .irq_parent = 129, .chip = &stm32_exti_h_chip },
+#define EXTI_INVALID_IRQ       U8_MAX
+#define STM32MP1_DESC_IRQ_SIZE (ARRAY_SIZE(stm32mp1_exti_banks) * IRQS_PER_BANK)
+
+static const u8 stm32mp1_desc_irq[] = {
+       /* default value */
+       [0 ... (STM32MP1_DESC_IRQ_SIZE - 1)] = EXTI_INVALID_IRQ,
+
+       [0] = 6,
+       [1] = 7,
+       [2] = 8,
+       [3] = 9,
+       [4] = 10,
+       [5] = 23,
+       [6] = 64,
+       [7] = 65,
+       [8] = 66,
+       [9] = 67,
+       [10] = 40,
+       [11] = 42,
+       [12] = 76,
+       [13] = 77,
+       [14] = 121,
+       [15] = 127,
+       [16] = 1,
+       [19] = 3,
+       [21] = 31,
+       [22] = 33,
+       [23] = 72,
+       [24] = 95,
+       [25] = 107,
+       [26] = 37,
+       [27] = 38,
+       [28] = 39,
+       [29] = 71,
+       [30] = 52,
+       [31] = 53,
+       [32] = 82,
+       [33] = 83,
+       [47] = 93,
+       [48] = 138,
+       [50] = 139,
+       [52] = 140,
+       [53] = 141,
+       [54] = 135,
+       [61] = 100,
+       [65] = 144,
+       [68] = 143,
+       [70] = 62,
+       [73] = 129,
 };
 
-static const struct stm32_desc_irq stm32mp13_desc_irq[] = {
-       { .exti = 0, .irq_parent = 6, .chip = &stm32_exti_h_chip },
-       { .exti = 1, .irq_parent = 7, .chip = &stm32_exti_h_chip },
-       { .exti = 2, .irq_parent = 8, .chip = &stm32_exti_h_chip },
-       { .exti = 3, .irq_parent = 9, .chip = &stm32_exti_h_chip },
-       { .exti = 4, .irq_parent = 10, .chip = &stm32_exti_h_chip },
-       { .exti = 5, .irq_parent = 24, .chip = &stm32_exti_h_chip },
-       { .exti = 6, .irq_parent = 65, .chip = &stm32_exti_h_chip },
-       { .exti = 7, .irq_parent = 66, .chip = &stm32_exti_h_chip },
-       { .exti = 8, .irq_parent = 67, .chip = &stm32_exti_h_chip },
-       { .exti = 9, .irq_parent = 68, .chip = &stm32_exti_h_chip },
-       { .exti = 10, .irq_parent = 41, .chip = &stm32_exti_h_chip },
-       { .exti = 11, .irq_parent = 43, .chip = &stm32_exti_h_chip },
-       { .exti = 12, .irq_parent = 77, .chip = &stm32_exti_h_chip },
-       { .exti = 13, .irq_parent = 78, .chip = &stm32_exti_h_chip },
-       { .exti = 14, .irq_parent = 106, .chip = &stm32_exti_h_chip },
-       { .exti = 15, .irq_parent = 109, .chip = &stm32_exti_h_chip },
-       { .exti = 16, .irq_parent = 1, .chip = &stm32_exti_h_chip },
-       { .exti = 19, .irq_parent = 3, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 21, .irq_parent = 32, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 22, .irq_parent = 34, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 23, .irq_parent = 73, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 24, .irq_parent = 93, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 25, .irq_parent = 114, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 26, .irq_parent = 38, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 27, .irq_parent = 39, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 28, .irq_parent = 40, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 29, .irq_parent = 72, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 30, .irq_parent = 53, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 31, .irq_parent = 54, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 32, .irq_parent = 83, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 33, .irq_parent = 84, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 44, .irq_parent = 96, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 47, .irq_parent = 92, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 48, .irq_parent = 116, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 50, .irq_parent = 117, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 52, .irq_parent = 118, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 53, .irq_parent = 119, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 68, .irq_parent = 63, .chip = &stm32_exti_h_chip_direct },
-       { .exti = 70, .irq_parent = 98, .chip = &stm32_exti_h_chip_direct },
+static const u8 stm32mp13_desc_irq[] = {
+       /* default value */
+       [0 ... (STM32MP1_DESC_IRQ_SIZE - 1)] = EXTI_INVALID_IRQ,
+
+       [0] = 6,
+       [1] = 7,
+       [2] = 8,
+       [3] = 9,
+       [4] = 10,
+       [5] = 24,
+       [6] = 65,
+       [7] = 66,
+       [8] = 67,
+       [9] = 68,
+       [10] = 41,
+       [11] = 43,
+       [12] = 77,
+       [13] = 78,
+       [14] = 106,
+       [15] = 109,
+       [16] = 1,
+       [19] = 3,
+       [21] = 32,
+       [22] = 34,
+       [23] = 73,
+       [24] = 93,
+       [25] = 114,
+       [26] = 38,
+       [27] = 39,
+       [28] = 40,
+       [29] = 72,
+       [30] = 53,
+       [31] = 54,
+       [32] = 83,
+       [33] = 84,
+       [44] = 96,
+       [47] = 92,
+       [48] = 116,
+       [50] = 117,
+       [52] = 118,
+       [53] = 119,
+       [68] = 63,
+       [70] = 98,
 };
 
 static const struct stm32_exti_drv_data stm32mp1_drv_data = {
        .exti_banks = stm32mp1_exti_banks,
        .bank_nr = ARRAY_SIZE(stm32mp1_exti_banks),
        .desc_irqs = stm32mp1_desc_irq,
-       .irq_nr = ARRAY_SIZE(stm32mp1_desc_irq),
 };
 
 static const struct stm32_exti_drv_data stm32mp13_drv_data = {
        .exti_banks = stm32mp1_exti_banks,
        .bank_nr = ARRAY_SIZE(stm32mp1_exti_banks),
        .desc_irqs = stm32mp13_desc_irq,
-       .irq_nr = ARRAY_SIZE(stm32mp13_desc_irq),
 };
 
-static const struct
-stm32_desc_irq *stm32_exti_get_desc(const struct stm32_exti_drv_data *drv_data,
-                                   irq_hw_number_t hwirq)
-{
-       const struct stm32_desc_irq *desc = NULL;
-       int i;
-
-       if (!drv_data->desc_irqs)
-               return NULL;
-
-       for (i = 0; i < drv_data->irq_nr; i++) {
-               desc = &drv_data->desc_irqs[i];
-               if (desc->exti == hwirq)
-                       break;
-       }
-
-       return desc;
-}
-
 static unsigned long stm32_exti_pending(struct irq_chip_generic *gc)
 {
        struct stm32_exti_chip_data *chip_data = gc->private;
@@ -614,7 +603,7 @@ static int stm32_exti_h_set_affinity(struct irq_data *d,
        if (d->parent_data->chip)
                return irq_chip_set_affinity_parent(d, dest, force);
 
-       return -EINVAL;
+       return IRQ_SET_MASK_OK_DONE;
 }
 
 static int __maybe_unused stm32_exti_h_suspend(void)
@@ -691,8 +680,8 @@ static struct irq_chip stm32_exti_h_chip_direct = {
        .name                   = "stm32-exti-h-direct",
        .irq_eoi                = irq_chip_eoi_parent,
        .irq_ack                = irq_chip_ack_parent,
-       .irq_mask               = irq_chip_mask_parent,
-       .irq_unmask             = irq_chip_unmask_parent,
+       .irq_mask               = stm32_exti_h_mask,
+       .irq_unmask             = stm32_exti_h_unmask,
        .irq_retrigger          = irq_chip_retrigger_hierarchy,
        .irq_set_type           = irq_chip_set_type_parent,
        .irq_set_wake           = stm32_exti_h_set_wake,
@@ -706,28 +695,36 @@ static int stm32_exti_h_domain_alloc(struct irq_domain *dm,
 {
        struct stm32_exti_host_data *host_data = dm->host_data;
        struct stm32_exti_chip_data *chip_data;
-       const struct stm32_desc_irq *desc;
+       u8 desc_irq;
        struct irq_fwspec *fwspec = data;
        struct irq_fwspec p_fwspec;
        irq_hw_number_t hwirq;
        int bank;
+       u32 event_trg;
+       struct irq_chip *chip;
 
        hwirq = fwspec->param[0];
+       if (hwirq >= host_data->drv_data->bank_nr * IRQS_PER_BANK)
+               return -EINVAL;
+
        bank  = hwirq / IRQS_PER_BANK;
        chip_data = &host_data->chips_data[bank];
 
+       event_trg = readl_relaxed(host_data->base + chip_data->reg_bank->trg_ofst);
+       chip = (event_trg & BIT(hwirq % IRQS_PER_BANK)) ?
+              &stm32_exti_h_chip : &stm32_exti_h_chip_direct;
+
+       irq_domain_set_hwirq_and_chip(dm, virq, hwirq, chip, chip_data);
 
-       desc = stm32_exti_get_desc(host_data->drv_data, hwirq);
-       if (!desc)
+       if (!host_data->drv_data || !host_data->drv_data->desc_irqs)
                return -EINVAL;
 
-       irq_domain_set_hwirq_and_chip(dm, virq, hwirq, desc->chip,
-                                     chip_data);
-       if (desc->irq_parent) {
+       desc_irq = host_data->drv_data->desc_irqs[hwirq];
+       if (desc_irq != EXTI_INVALID_IRQ) {
                p_fwspec.fwnode = dm->parent->fwnode;
                p_fwspec.param_count = 3;
                p_fwspec.param[0] = GIC_SPI;
-               p_fwspec.param[1] = desc->irq_parent;
+               p_fwspec.param[1] = desc_irq;
                p_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH;
 
                return irq_domain_alloc_irqs_parent(dm, virq, 1, &p_fwspec);
@@ -792,7 +789,8 @@ stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data,
         * clear registers to avoid residue
         */
        writel_relaxed(0, base + stm32_bank->imr_ofst);
-       writel_relaxed(0, base + stm32_bank->emr_ofst);
+       if (stm32_bank->emr_ofst != UNDEF_REG)
+               writel_relaxed(0, base + stm32_bank->emr_ofst);
 
        pr_info("%pOF: bank%d\n", node, bank_idx);
 
index 0454b08..84291e3 100644 (file)
@@ -5,7 +5,7 @@
 
 dm-mod-y       += dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.o \
                   dm-ioctl.o dm-io.o dm-kcopyd.o dm-sysfs.o dm-stats.o \
-                  dm-rq.o
+                  dm-rq.o dm-io-rewind.o
 dm-multipath-y += dm-path-selector.o dm-mpath.o
 dm-historical-service-time-y += dm-ps-historical-service-time.o
 dm-io-affinity-y += dm-ps-io-affinity.o
@@ -83,6 +83,7 @@ obj-$(CONFIG_DM_LOG_WRITES)   += dm-log-writes.o
 obj-$(CONFIG_DM_INTEGRITY)     += dm-integrity.o
 obj-$(CONFIG_DM_ZONED)         += dm-zoned.o
 obj-$(CONFIG_DM_WRITECACHE)    += dm-writecache.o
+obj-$(CONFIG_SECURITY_LOADPIN_VERITY)  += dm-verity-loadpin.o
 
 ifeq ($(CONFIG_DM_INIT),y)
 dm-mod-objs                    += dm-init.o
index 3563d15..ba3909b 100644 (file)
@@ -414,8 +414,8 @@ static void uuid_io_unlock(struct closure *cl)
        up(&c->uuid_write_mutex);
 }
 
-static void uuid_io(struct cache_set *c, int op, unsigned long op_flags,
-                   struct bkey *k, struct closure *parent)
+static void uuid_io(struct cache_set *c, blk_opf_t opf, struct bkey *k,
+                   struct closure *parent)
 {
        struct closure *cl = &c->uuid_write;
        struct uuid_entry *u;
@@ -429,22 +429,22 @@ static void uuid_io(struct cache_set *c, int op, unsigned long op_flags,
        for (i = 0; i < KEY_PTRS(k); i++) {
                struct bio *bio = bch_bbio_alloc(c);
 
-               bio->bi_opf = REQ_SYNC | REQ_META | op_flags;
+               bio->bi_opf = opf | REQ_SYNC | REQ_META;
                bio->bi_iter.bi_size = KEY_SIZE(k) << 9;
 
                bio->bi_end_io  = uuid_endio;
                bio->bi_private = cl;
-               bio_set_op_attrs(bio, op, REQ_SYNC|REQ_META|op_flags);
                bch_bio_map(bio, c->uuids);
 
                bch_submit_bbio(bio, c, k, i);
 
-               if (op != REQ_OP_WRITE)
+               if ((opf & REQ_OP_MASK) != REQ_OP_WRITE)
                        break;
        }
 
        bch_extent_to_text(buf, sizeof(buf), k);
-       pr_debug("%s UUIDs at %s\n", op == REQ_OP_WRITE ? "wrote" : "read", buf);
+       pr_debug("%s UUIDs at %s\n", (opf & REQ_OP_MASK) == REQ_OP_WRITE ?
+                "wrote" : "read", buf);
 
        for (u = c->uuids; u < c->uuids + c->nr_uuids; u++)
                if (!bch_is_zero(u->uuid, 16))
@@ -463,7 +463,7 @@ static char *uuid_read(struct cache_set *c, struct jset *j, struct closure *cl)
                return "bad uuid pointer";
 
        bkey_copy(&c->uuid_bucket, k);
-       uuid_io(c, REQ_OP_READ, 0, k, cl);
+       uuid_io(c, REQ_OP_READ, k, cl);
 
        if (j->version < BCACHE_JSET_VERSION_UUIDv1) {
                struct uuid_entry_v0    *u0 = (void *) c->uuids;
@@ -511,7 +511,7 @@ static int __uuid_write(struct cache_set *c)
 
        size =  meta_bucket_pages(&ca->sb) * PAGE_SECTORS;
        SET_KEY_SIZE(&k.key, size);
-       uuid_io(c, REQ_OP_WRITE, 0, &k.key, &cl);
+       uuid_io(c, REQ_OP_WRITE, &k.key, &cl);
        closure_sync(&cl);
 
        /* Only one bucket used for uuid write */
@@ -587,8 +587,7 @@ static void prio_endio(struct bio *bio)
        closure_put(&ca->prio);
 }
 
-static void prio_io(struct cache *ca, uint64_t bucket, int op,
-                   unsigned long op_flags)
+static void prio_io(struct cache *ca, uint64_t bucket, blk_opf_t opf)
 {
        struct closure *cl = &ca->prio;
        struct bio *bio = bch_bbio_alloc(ca->set);
@@ -601,7 +600,7 @@ static void prio_io(struct cache *ca, uint64_t bucket, int op,
 
        bio->bi_end_io  = prio_endio;
        bio->bi_private = ca;
-       bio_set_op_attrs(bio, op, REQ_SYNC|REQ_META|op_flags);
+       bio->bi_opf = opf | REQ_SYNC | REQ_META;
        bch_bio_map(bio, ca->disk_buckets);
 
        closure_bio_submit(ca->set, bio, &ca->prio);
@@ -661,7 +660,7 @@ int bch_prio_write(struct cache *ca, bool wait)
                BUG_ON(bucket == -1);
 
                mutex_unlock(&ca->set->bucket_lock);
-               prio_io(ca, bucket, REQ_OP_WRITE, 0);
+               prio_io(ca, bucket, REQ_OP_WRITE);
                mutex_lock(&ca->set->bucket_lock);
 
                ca->prio_buckets[i] = bucket;
@@ -705,7 +704,7 @@ static int prio_read(struct cache *ca, uint64_t bucket)
                        ca->prio_last_buckets[bucket_nr] = bucket;
                        bucket_nr++;
 
-                       prio_io(ca, bucket, REQ_OP_READ, 0);
+                       prio_io(ca, bucket, REQ_OP_READ);
 
                        if (p->csum !=
                            bch_crc64(&p->magic, meta_bucket_bytes(&ca->sb) - 8)) {
@@ -884,7 +883,7 @@ static void bcache_device_free(struct bcache_device *d)
        if (disk) {
                ida_simple_remove(&bcache_device_idx,
                                  first_minor_to_idx(disk->first_minor));
-               blk_cleanup_disk(disk);
+               put_disk(disk);
        }
 
        bioset_exit(&d->bio_split);
index 5ffa1dc..dc01ce3 100644 (file)
@@ -577,13 +577,12 @@ static void dmio_complete(unsigned long error, void *context)
        b->end_io(b, unlikely(error != 0) ? BLK_STS_IOERR : 0);
 }
 
-static void use_dmio(struct dm_buffer *b, int rw, sector_t sector,
+static void use_dmio(struct dm_buffer *b, enum req_op op, sector_t sector,
                     unsigned n_sectors, unsigned offset)
 {
        int r;
        struct dm_io_request io_req = {
-               .bi_op = rw,
-               .bi_op_flags = 0,
+               .bi_opf = op,
                .notify.fn = dmio_complete,
                .notify.context = b,
                .client = b->c->dm_io,
@@ -616,7 +615,7 @@ static void bio_complete(struct bio *bio)
        b->end_io(b, status);
 }
 
-static void use_bio(struct dm_buffer *b, int rw, sector_t sector,
+static void use_bio(struct dm_buffer *b, enum req_op op, sector_t sector,
                    unsigned n_sectors, unsigned offset)
 {
        struct bio *bio;
@@ -630,10 +629,10 @@ static void use_bio(struct dm_buffer *b, int rw, sector_t sector,
        bio = bio_kmalloc(vec_size, GFP_NOWAIT | __GFP_NORETRY | __GFP_NOWARN);
        if (!bio) {
 dmio:
-               use_dmio(b, rw, sector, n_sectors, offset);
+               use_dmio(b, op, sector, n_sectors, offset);
                return;
        }
-       bio_init(bio, b->c->bdev, bio->bi_inline_vecs, vec_size, rw);
+       bio_init(bio, b->c->bdev, bio->bi_inline_vecs, vec_size, op);
        bio->bi_iter.bi_sector = sector;
        bio->bi_end_io = bio_complete;
        bio->bi_private = b;
@@ -669,7 +668,8 @@ static inline sector_t block_to_sector(struct dm_bufio_client *c, sector_t block
        return sector;
 }
 
-static void submit_io(struct dm_buffer *b, int rw, void (*end_io)(struct dm_buffer *, blk_status_t))
+static void submit_io(struct dm_buffer *b, enum req_op op,
+                     void (*end_io)(struct dm_buffer *, blk_status_t))
 {
        unsigned n_sectors;
        sector_t sector;
@@ -679,7 +679,7 @@ static void submit_io(struct dm_buffer *b, int rw, void (*end_io)(struct dm_buff
 
        sector = block_to_sector(b->c, b->block);
 
-       if (rw != REQ_OP_WRITE) {
+       if (op != REQ_OP_WRITE) {
                n_sectors = b->c->block_size >> SECTOR_SHIFT;
                offset = 0;
        } else {
@@ -698,9 +698,9 @@ static void submit_io(struct dm_buffer *b, int rw, void (*end_io)(struct dm_buff
        }
 
        if (b->data_mode != DATA_MODE_VMALLOC)
-               use_bio(b, rw, sector, n_sectors, offset);
+               use_bio(b, op, sector, n_sectors, offset);
        else
-               use_dmio(b, rw, sector, n_sectors, offset);
+               use_dmio(b, op, sector, n_sectors, offset);
 }
 
 /*----------------------------------------------------------------
@@ -1341,8 +1341,7 @@ EXPORT_SYMBOL_GPL(dm_bufio_write_dirty_buffers);
 int dm_bufio_issue_flush(struct dm_bufio_client *c)
 {
        struct dm_io_request io_req = {
-               .bi_op = REQ_OP_WRITE,
-               .bi_op_flags = REQ_PREFLUSH | REQ_SYNC,
+               .bi_opf = REQ_OP_WRITE | REQ_PREFLUSH | REQ_SYNC,
                .mem.type = DM_IO_KMEM,
                .mem.ptr.addr = NULL,
                .client = c->dm_io,
@@ -1365,8 +1364,7 @@ EXPORT_SYMBOL_GPL(dm_bufio_issue_flush);
 int dm_bufio_issue_discard(struct dm_bufio_client *c, sector_t block, sector_t count)
 {
        struct dm_io_request io_req = {
-               .bi_op = REQ_OP_DISCARD,
-               .bi_op_flags = REQ_SYNC,
+               .bi_opf = REQ_OP_DISCARD | REQ_SYNC,
                .mem.type = DM_IO_KMEM,
                .mem.ptr.addr = NULL,
                .client = c->dm_io,
index 179ed5b..0905f2c 100644 (file)
@@ -131,7 +131,7 @@ void dm_cache_dump(struct dm_cache_metadata *cmd);
  * hints will be lost.
  *
  * The hints are indexed by the cblock, but many policies will not
- * neccessarily have a fast way of accessing efficiently via cblock.  So
+ * necessarily have a fast way of accessing efficiently via cblock.  So
  * rather than querying the policy for each cblock, we let it walk its data
  * structures and fill in the hints in whatever order it wishes.
  */
index 28c5de8..54a8d5c 100644 (file)
@@ -2775,7 +2775,7 @@ static int load_mapping(void *context, dm_oblock_t oblock, dm_cblock_t cblock,
 
 /*
  * The discard block size in the on disk metadata is not
- * neccessarily the same as we're currently using.  So we have to
+ * necessarily the same as we're currently using.  So we have to
  * be careful to only set the discarded attribute if we know it
  * covers a complete block of the new size.
  */
index c954ff9..6c6bd24 100644 (file)
@@ -22,6 +22,8 @@
 
 #define DM_RESERVED_MAX_IOS            1024
 
+struct dm_io;
+
 struct dm_kobject_holder {
        struct kobject kobj;
        struct completion completion;
@@ -91,6 +93,14 @@ struct mapped_device {
        spinlock_t deferred_lock;
        struct bio_list deferred;
 
+       /*
+        * requeue work context is needed for cloning one new bio
+        * to represent the dm_io to be requeued, since each
+        * dm_io may point to the original bio from FS.
+        */
+       struct work_struct requeue_work;
+       struct dm_io *requeue_list;
+
        void *interface_ptr;
 
        /*
@@ -216,6 +226,13 @@ struct dm_table {
 #endif
 };
 
+static inline struct dm_target *dm_table_get_target(struct dm_table *t,
+                                                   unsigned int index)
+{
+       BUG_ON(index >= t->num_targets);
+       return t->targets + index;
+}
+
 /*
  * One of these is allocated per clone bio.
  */
@@ -230,6 +247,9 @@ struct dm_target_io {
        sector_t old_sector;
        struct bio clone;
 };
+#define DM_TARGET_IO_BIO_OFFSET (offsetof(struct dm_target_io, clone))
+#define DM_IO_BIO_OFFSET \
+       (offsetof(struct dm_target_io, clone) + offsetof(struct dm_io, tio))
 
 /*
  * dm_target_io flags
@@ -272,7 +292,6 @@ struct dm_io {
        atomic_t io_count;
        struct mapped_device *md;
 
-       struct bio *split_bio;
        /* The three fields represent mapped part of original bio */
        struct bio *orig_bio;
        unsigned int sector_offset; /* offset to end of orig_bio */
@@ -300,6 +319,8 @@ static inline void dm_io_set_flag(struct dm_io *io, unsigned int bit)
        io->flags |= (1U << bit);
 }
 
+void dm_io_rewind(struct dm_io *io, struct bio_set *bs);
+
 static inline struct completion *dm_get_completion_from_kobject(struct kobject *kobj)
 {
        return &container_of(kobj, struct dm_kobject_holder, kobj)->completion;
index 0221fa6..223e8e1 100644 (file)
@@ -61,7 +61,8 @@ static inline bool __ebs_check_bs(unsigned int bs)
  *
  * copy blocks between bufio blocks and bio vector's (partial/overlapping) pages.
  */
-static int __ebs_rw_bvec(struct ebs_c *ec, int rw, struct bio_vec *bv, struct bvec_iter *iter)
+static int __ebs_rw_bvec(struct ebs_c *ec, enum req_op op, struct bio_vec *bv,
+                        struct bvec_iter *iter)
 {
        int r = 0;
        unsigned char *ba, *pa;
@@ -81,7 +82,7 @@ static int __ebs_rw_bvec(struct ebs_c *ec, int rw, struct bio_vec *bv, struct bv
                cur_len = min(dm_bufio_get_block_size(ec->bufio) - buf_off, bv_len);
 
                /* Avoid reading for writes in case bio vector's page overwrites block completely. */
-               if (rw == READ || buf_off || bv_len < dm_bufio_get_block_size(ec->bufio))
+               if (op == REQ_OP_READ || buf_off || bv_len < dm_bufio_get_block_size(ec->bufio))
                        ba = dm_bufio_read(ec->bufio, block, &b);
                else
                        ba = dm_bufio_new(ec->bufio, block, &b);
@@ -95,7 +96,7 @@ static int __ebs_rw_bvec(struct ebs_c *ec, int rw, struct bio_vec *bv, struct bv
                } else {
                        /* Copy data to/from bio to buffer if read/new was successful above. */
                        ba += buf_off;
-                       if (rw == READ) {
+                       if (op == REQ_OP_READ) {
                                memcpy(pa, ba, cur_len);
                                flush_dcache_page(bv->bv_page);
                        } else {
@@ -117,14 +118,14 @@ static int __ebs_rw_bvec(struct ebs_c *ec, int rw, struct bio_vec *bv, struct bv
 }
 
 /* READ/WRITE: iterate bio vector's copying between (partial) pages and bufio blocks. */
-static int __ebs_rw_bio(struct ebs_c *ec, int rw, struct bio *bio)
+static int __ebs_rw_bio(struct ebs_c *ec, enum req_op op, struct bio *bio)
 {
        int r = 0, rr;
        struct bio_vec bv;
        struct bvec_iter iter;
 
        bio_for_each_bvec(bv, bio, iter) {
-               rr = __ebs_rw_bvec(ec, rw, &bv, &iter);
+               rr = __ebs_rw_bvec(ec, op, &bv, &iter);
                if (rr)
                        r = rr;
        }
@@ -205,10 +206,10 @@ static void __ebs_process_bios(struct work_struct *ws)
        bio_list_for_each(bio, &bios) {
                r = -EIO;
                if (bio_op(bio) == REQ_OP_READ)
-                       r = __ebs_rw_bio(ec, READ, bio);
+                       r = __ebs_rw_bio(ec, REQ_OP_READ, bio);
                else if (bio_op(bio) == REQ_OP_WRITE) {
                        write = true;
-                       r = __ebs_rw_bio(ec, WRITE, bio);
+                       r = __ebs_rw_bio(ec, REQ_OP_WRITE, bio);
                } else if (bio_op(bio) == REQ_OP_DISCARD) {
                        __ebs_forget_bio(ec, bio);
                        r = __ebs_discard_bio(ec, bio);
index f2305eb..89fa7a6 100644 (file)
@@ -32,7 +32,7 @@ struct flakey_c {
        unsigned corrupt_bio_byte;
        unsigned corrupt_bio_rw;
        unsigned corrupt_bio_value;
-       unsigned corrupt_bio_flags;
+       blk_opf_t corrupt_bio_flags;
 };
 
 enum feature_flag_bits {
@@ -145,7 +145,11 @@ static int parse_features(struct dm_arg_set *as, struct flakey_c *fc,
                        /*
                         * Only corrupt bios with these flags set.
                         */
-                       r = dm_read_arg(_args + 3, as, &fc->corrupt_bio_flags, &ti->error);
+                       BUILD_BUG_ON(sizeof(fc->corrupt_bio_flags) !=
+                                    sizeof(unsigned int));
+                       r = dm_read_arg(_args + 3, as,
+                               (__force unsigned *)&fc->corrupt_bio_flags,
+                               &ti->error);
                        if (r)
                                return r;
                        argc--;
index 1842d3a..a1bd7cd 100644 (file)
@@ -208,7 +208,7 @@ void dm_ima_measure_on_table_load(struct dm_table *table, unsigned int status_fl
        if (!target_data_buf)
                goto error;
 
-       num_targets = dm_table_get_num_targets(table);
+       num_targets = table->num_targets;
 
        if (dm_ima_alloc_and_copy_device_data(table->md, &device_data_buf, num_targets, noio))
                goto error;
@@ -237,9 +237,6 @@ void dm_ima_measure_on_table_load(struct dm_table *table, unsigned int status_fl
        for (i = 0; i < num_targets; i++) {
                struct dm_target *ti = dm_table_get_target(table, i);
 
-               if (!ti)
-                       goto error;
-
                last_target_measured = 0;
 
                /*
index 3d5a0ce..c60f9b2 100644 (file)
@@ -298,7 +298,7 @@ struct dm_integrity_io {
        struct work_struct work;
 
        struct dm_integrity_c *ic;
-       enum req_opf op;
+       enum req_op op;
        bool fua;
 
        struct dm_integrity_range range;
@@ -551,14 +551,14 @@ static int sb_mac(struct dm_integrity_c *ic, bool wr)
        return 0;
 }
 
-static int sync_rw_sb(struct dm_integrity_c *ic, int op, int op_flags)
+static int sync_rw_sb(struct dm_integrity_c *ic, blk_opf_t opf)
 {
        struct dm_io_request io_req;
        struct dm_io_region io_loc;
+       const enum req_op op = opf & REQ_OP_MASK;
        int r;
 
-       io_req.bi_op = op;
-       io_req.bi_op_flags = op_flags;
+       io_req.bi_opf = opf;
        io_req.mem.type = DM_IO_KMEM;
        io_req.mem.ptr.addr = ic->sb;
        io_req.notify.fn = NULL;
@@ -1050,8 +1050,9 @@ static void complete_journal_io(unsigned long error, void *context)
        complete_journal_op(comp);
 }
 
-static void rw_journal_sectors(struct dm_integrity_c *ic, int op, int op_flags,
-                              unsigned sector, unsigned n_sectors, struct journal_completion *comp)
+static void rw_journal_sectors(struct dm_integrity_c *ic, blk_opf_t opf,
+                              unsigned sector, unsigned n_sectors,
+                              struct journal_completion *comp)
 {
        struct dm_io_request io_req;
        struct dm_io_region io_loc;
@@ -1067,8 +1068,7 @@ static void rw_journal_sectors(struct dm_integrity_c *ic, int op, int op_flags,
        pl_index = sector >> (PAGE_SHIFT - SECTOR_SHIFT);
        pl_offset = (sector << SECTOR_SHIFT) & (PAGE_SIZE - 1);
 
-       io_req.bi_op = op;
-       io_req.bi_op_flags = op_flags;
+       io_req.bi_opf = opf;
        io_req.mem.type = DM_IO_PAGE_LIST;
        if (ic->journal_io)
                io_req.mem.ptr.pl = &ic->journal_io[pl_index];
@@ -1088,7 +1088,8 @@ static void rw_journal_sectors(struct dm_integrity_c *ic, int op, int op_flags,
 
        r = dm_io(&io_req, 1, &io_loc, NULL);
        if (unlikely(r)) {
-               dm_integrity_io_error(ic, op == REQ_OP_READ ? "reading journal" : "writing journal", r);
+               dm_integrity_io_error(ic, (opf & REQ_OP_MASK) == REQ_OP_READ ?
+                                     "reading journal" : "writing journal", r);
                if (comp) {
                        WARN_ONCE(1, "asynchronous dm_io failed: %d", r);
                        complete_journal_io(-1UL, comp);
@@ -1096,15 +1097,16 @@ static void rw_journal_sectors(struct dm_integrity_c *ic, int op, int op_flags,
        }
 }
 
-static void rw_journal(struct dm_integrity_c *ic, int op, int op_flags, unsigned section,
-                      unsigned n_sections, struct journal_completion *comp)
+static void rw_journal(struct dm_integrity_c *ic, blk_opf_t opf,
+                      unsigned section, unsigned n_sections,
+                      struct journal_completion *comp)
 {
        unsigned sector, n_sectors;
 
        sector = section * ic->journal_section_sectors;
        n_sectors = n_sections * ic->journal_section_sectors;
 
-       rw_journal_sectors(ic, op, op_flags, sector, n_sectors, comp);
+       rw_journal_sectors(ic, opf, sector, n_sectors, comp);
 }
 
 static void write_journal(struct dm_integrity_c *ic, unsigned commit_start, unsigned commit_sections)
@@ -1129,7 +1131,7 @@ static void write_journal(struct dm_integrity_c *ic, unsigned commit_start, unsi
                        for (i = 0; i < commit_sections; i++)
                                rw_section_mac(ic, commit_start + i, true);
                }
-               rw_journal(ic, REQ_OP_WRITE, REQ_FUA | REQ_SYNC, commit_start,
+               rw_journal(ic, REQ_OP_WRITE | REQ_FUA | REQ_SYNC, commit_start,
                           commit_sections, &io_comp);
        } else {
                unsigned to_end;
@@ -1141,7 +1143,8 @@ static void write_journal(struct dm_integrity_c *ic, unsigned commit_start, unsi
                        crypt_comp_1.in_flight = (atomic_t)ATOMIC_INIT(0);
                        encrypt_journal(ic, true, commit_start, to_end, &crypt_comp_1);
                        if (try_wait_for_completion(&crypt_comp_1.comp)) {
-                               rw_journal(ic, REQ_OP_WRITE, REQ_FUA, commit_start, to_end, &io_comp);
+                               rw_journal(ic, REQ_OP_WRITE | REQ_FUA,
+                                          commit_start, to_end, &io_comp);
                                reinit_completion(&crypt_comp_1.comp);
                                crypt_comp_1.in_flight = (atomic_t)ATOMIC_INIT(0);
                                encrypt_journal(ic, true, 0, commit_sections - to_end, &crypt_comp_1);
@@ -1152,17 +1155,17 @@ static void write_journal(struct dm_integrity_c *ic, unsigned commit_start, unsi
                                crypt_comp_2.in_flight = (atomic_t)ATOMIC_INIT(0);
                                encrypt_journal(ic, true, 0, commit_sections - to_end, &crypt_comp_2);
                                wait_for_completion_io(&crypt_comp_1.comp);
-                               rw_journal(ic, REQ_OP_WRITE, REQ_FUA, commit_start, to_end, &io_comp);
+                               rw_journal(ic, REQ_OP_WRITE | REQ_FUA, commit_start, to_end, &io_comp);
                                wait_for_completion_io(&crypt_comp_2.comp);
                        }
                } else {
                        for (i = 0; i < to_end; i++)
                                rw_section_mac(ic, commit_start + i, true);
-                       rw_journal(ic, REQ_OP_WRITE, REQ_FUA, commit_start, to_end, &io_comp);
+                       rw_journal(ic, REQ_OP_WRITE | REQ_FUA, commit_start, to_end, &io_comp);
                        for (i = 0; i < commit_sections - to_end; i++)
                                rw_section_mac(ic, i, true);
                }
-               rw_journal(ic, REQ_OP_WRITE, REQ_FUA, 0, commit_sections - to_end, &io_comp);
+               rw_journal(ic, REQ_OP_WRITE | REQ_FUA, 0, commit_sections - to_end, &io_comp);
        }
 
        wait_for_completion_io(&io_comp.comp);
@@ -1188,8 +1191,7 @@ static void copy_from_journal(struct dm_integrity_c *ic, unsigned section, unsig
        pl_index = sector >> (PAGE_SHIFT - SECTOR_SHIFT);
        pl_offset = (sector << SECTOR_SHIFT) & (PAGE_SIZE - 1);
 
-       io_req.bi_op = REQ_OP_WRITE;
-       io_req.bi_op_flags = 0;
+       io_req.bi_opf = REQ_OP_WRITE;
        io_req.mem.type = DM_IO_PAGE_LIST;
        io_req.mem.ptr.pl = &ic->journal[pl_index];
        io_req.mem.offset = pl_offset;
@@ -1516,8 +1518,7 @@ static void dm_integrity_flush_buffers(struct dm_integrity_c *ic, bool flush_dat
        if (!ic->meta_dev)
                flush_data = false;
        if (flush_data) {
-               fr.io_req.bi_op = REQ_OP_WRITE,
-               fr.io_req.bi_op_flags = REQ_PREFLUSH | REQ_SYNC,
+               fr.io_req.bi_opf = REQ_OP_WRITE | REQ_PREFLUSH | REQ_SYNC,
                fr.io_req.mem.type = DM_IO_KMEM,
                fr.io_req.mem.ptr.addr = NULL,
                fr.io_req.notify.fn = flush_notify,
@@ -2626,7 +2627,7 @@ static void recalc_write_super(struct dm_integrity_c *ic)
        if (dm_integrity_failed(ic))
                return;
 
-       r = sync_rw_sb(ic, REQ_OP_WRITE, 0);
+       r = sync_rw_sb(ic, REQ_OP_WRITE);
        if (unlikely(r))
                dm_integrity_io_error(ic, "writing superblock", r);
 }
@@ -2706,8 +2707,7 @@ next_chunk:
        if (unlikely(dm_integrity_failed(ic)))
                goto err;
 
-       io_req.bi_op = REQ_OP_READ;
-       io_req.bi_op_flags = 0;
+       io_req.bi_opf = REQ_OP_READ;
        io_req.mem.type = DM_IO_VMA;
        io_req.mem.ptr.addr = ic->recalc_buffer;
        io_req.notify.fn = NULL;
@@ -2800,7 +2800,7 @@ static void bitmap_block_work(struct work_struct *w)
        if (bio_list_empty(&waiting))
                return;
 
-       rw_journal_sectors(ic, REQ_OP_WRITE, REQ_FUA | REQ_SYNC,
+       rw_journal_sectors(ic, REQ_OP_WRITE | REQ_FUA | REQ_SYNC,
                           bbs->idx * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT),
                           BITMAP_BLOCK_SIZE >> SECTOR_SHIFT, NULL);
 
@@ -2846,7 +2846,7 @@ static void bitmap_flush_work(struct work_struct *work)
        block_bitmap_op(ic, ic->journal, 0, limit, BITMAP_OP_CLEAR);
        block_bitmap_op(ic, ic->may_write_bitmap, 0, limit, BITMAP_OP_CLEAR);
 
-       rw_journal_sectors(ic, REQ_OP_WRITE, REQ_FUA | REQ_SYNC, 0,
+       rw_journal_sectors(ic, REQ_OP_WRITE | REQ_FUA | REQ_SYNC, 0,
                           ic->n_bitmap_blocks * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), NULL);
 
        spin_lock_irq(&ic->endio_wait.lock);
@@ -2918,7 +2918,7 @@ static void replay_journal(struct dm_integrity_c *ic)
 
        if (!ic->just_formatted) {
                DEBUG_print("reading journal\n");
-               rw_journal(ic, REQ_OP_READ, 0, 0, ic->journal_sections, NULL);
+               rw_journal(ic, REQ_OP_READ, 0, ic->journal_sections, NULL);
                if (ic->journal_io)
                        DEBUG_bytes(lowmem_page_address(ic->journal_io[0].page), 64, "read journal");
                if (ic->journal_io) {
@@ -3113,7 +3113,7 @@ static void dm_integrity_postsuspend(struct dm_target *ti)
                /* set to 0 to test bitmap replay code */
                init_journal(ic, 0, ic->journal_sections, 0);
                ic->sb->flags &= ~cpu_to_le32(SB_FLAG_DIRTY_BITMAP);
-               r = sync_rw_sb(ic, REQ_OP_WRITE, REQ_FUA);
+               r = sync_rw_sb(ic, REQ_OP_WRITE | REQ_FUA);
                if (unlikely(r))
                        dm_integrity_io_error(ic, "writing superblock", r);
 #endif
@@ -3136,23 +3136,23 @@ static void dm_integrity_resume(struct dm_target *ti)
                if (ic->provided_data_sectors > old_provided_data_sectors &&
                    ic->mode == 'B' &&
                    ic->sb->log2_blocks_per_bitmap_bit == ic->log2_blocks_per_bitmap_bit) {
-                       rw_journal_sectors(ic, REQ_OP_READ, 0, 0,
+                       rw_journal_sectors(ic, REQ_OP_READ, 0,
                                           ic->n_bitmap_blocks * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), NULL);
                        block_bitmap_op(ic, ic->journal, old_provided_data_sectors,
                                        ic->provided_data_sectors - old_provided_data_sectors, BITMAP_OP_SET);
-                       rw_journal_sectors(ic, REQ_OP_WRITE, REQ_FUA | REQ_SYNC, 0,
+                       rw_journal_sectors(ic, REQ_OP_WRITE | REQ_FUA | REQ_SYNC, 0,
                                           ic->n_bitmap_blocks * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), NULL);
                }
 
                ic->sb->provided_data_sectors = cpu_to_le64(ic->provided_data_sectors);
-               r = sync_rw_sb(ic, REQ_OP_WRITE, REQ_FUA);
+               r = sync_rw_sb(ic, REQ_OP_WRITE | REQ_FUA);
                if (unlikely(r))
                        dm_integrity_io_error(ic, "writing superblock", r);
        }
 
        if (ic->sb->flags & cpu_to_le32(SB_FLAG_DIRTY_BITMAP)) {
                DEBUG_print("resume dirty_bitmap\n");
-               rw_journal_sectors(ic, REQ_OP_READ, 0, 0,
+               rw_journal_sectors(ic, REQ_OP_READ, 0,
                                   ic->n_bitmap_blocks * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), NULL);
                if (ic->mode == 'B') {
                        if (ic->sb->log2_blocks_per_bitmap_bit == ic->log2_blocks_per_bitmap_bit &&
@@ -3171,7 +3171,7 @@ static void dm_integrity_resume(struct dm_target *ti)
                                block_bitmap_op(ic, ic->recalc_bitmap, 0, ic->provided_data_sectors, BITMAP_OP_SET);
                                block_bitmap_op(ic, ic->may_write_bitmap, 0, ic->provided_data_sectors, BITMAP_OP_SET);
                                block_bitmap_op(ic, ic->journal, 0, ic->provided_data_sectors, BITMAP_OP_SET);
-                               rw_journal_sectors(ic, REQ_OP_WRITE, REQ_FUA | REQ_SYNC, 0,
+                               rw_journal_sectors(ic, REQ_OP_WRITE | REQ_FUA | REQ_SYNC, 0,
                                                   ic->n_bitmap_blocks * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), NULL);
                                ic->sb->flags |= cpu_to_le32(SB_FLAG_RECALCULATING);
                                ic->sb->recalc_sector = cpu_to_le64(0);
@@ -3187,7 +3187,7 @@ static void dm_integrity_resume(struct dm_target *ti)
                        replay_journal(ic);
                        ic->sb->flags &= ~cpu_to_le32(SB_FLAG_DIRTY_BITMAP);
                }
-               r = sync_rw_sb(ic, REQ_OP_WRITE, REQ_FUA);
+               r = sync_rw_sb(ic, REQ_OP_WRITE | REQ_FUA);
                if (unlikely(r))
                        dm_integrity_io_error(ic, "writing superblock", r);
        } else {
@@ -3199,7 +3199,7 @@ static void dm_integrity_resume(struct dm_target *ti)
                if (ic->mode == 'B') {
                        ic->sb->flags |= cpu_to_le32(SB_FLAG_DIRTY_BITMAP);
                        ic->sb->log2_blocks_per_bitmap_bit = ic->log2_blocks_per_bitmap_bit;
-                       r = sync_rw_sb(ic, REQ_OP_WRITE, REQ_FUA);
+                       r = sync_rw_sb(ic, REQ_OP_WRITE | REQ_FUA);
                        if (unlikely(r))
                                dm_integrity_io_error(ic, "writing superblock", r);
 
@@ -3215,7 +3215,7 @@ static void dm_integrity_resume(struct dm_target *ti)
                                block_bitmap_op(ic, ic->may_write_bitmap, le64_to_cpu(ic->sb->recalc_sector),
                                                ic->provided_data_sectors - le64_to_cpu(ic->sb->recalc_sector), BITMAP_OP_SET);
                        }
-                       rw_journal_sectors(ic, REQ_OP_WRITE, REQ_FUA | REQ_SYNC, 0,
+                       rw_journal_sectors(ic, REQ_OP_WRITE | REQ_FUA | REQ_SYNC, 0,
                                           ic->n_bitmap_blocks * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), NULL);
                }
        }
@@ -4256,7 +4256,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
                goto bad;
        }
 
-       r = sync_rw_sb(ic, REQ_OP_READ, 0);
+       r = sync_rw_sb(ic, REQ_OP_READ);
        if (r) {
                ti->error = "Error reading superblock";
                goto bad;
@@ -4500,7 +4500,7 @@ try_smaller_buffer:
                        ti->error = "Error initializing journal";
                        goto bad;
                }
-               r = sync_rw_sb(ic, REQ_OP_WRITE, REQ_FUA);
+               r = sync_rw_sb(ic, REQ_OP_WRITE | REQ_FUA);
                if (r) {
                        ti->error = "Error initializing superblock";
                        goto bad;
diff --git a/drivers/md/dm-io-rewind.c b/drivers/md/dm-io-rewind.c
new file mode 100644 (file)
index 0000000..0db53cc
--- /dev/null
@@ -0,0 +1,166 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2022 Red Hat, Inc.
+ */
+
+#include <linux/bio.h>
+#include <linux/blk-crypto.h>
+#include <linux/blk-integrity.h>
+
+#include "dm-core.h"
+
+static inline bool dm_bvec_iter_rewind(const struct bio_vec *bv,
+                                      struct bvec_iter *iter,
+                                      unsigned int bytes)
+{
+       int idx;
+
+       iter->bi_size += bytes;
+       if (bytes <= iter->bi_bvec_done) {
+               iter->bi_bvec_done -= bytes;
+               return true;
+       }
+
+       bytes -= iter->bi_bvec_done;
+       idx = iter->bi_idx - 1;
+
+       while (idx >= 0 && bytes && bytes > bv[idx].bv_len) {
+               bytes -= bv[idx].bv_len;
+               idx--;
+       }
+
+       if (WARN_ONCE(idx < 0 && bytes,
+                     "Attempted to rewind iter beyond bvec's boundaries\n")) {
+               iter->bi_size -= bytes;
+               iter->bi_bvec_done = 0;
+               iter->bi_idx = 0;
+               return false;
+       }
+
+       iter->bi_idx = idx;
+       iter->bi_bvec_done = bv[idx].bv_len - bytes;
+       return true;
+}
+
+#if defined(CONFIG_BLK_DEV_INTEGRITY)
+
+/**
+ * dm_bio_integrity_rewind - Rewind integrity vector
+ * @bio:       bio whose integrity vector to update
+ * @bytes_done:        number of data bytes to rewind
+ *
+ * Description: This function calculates how many integrity bytes the
+ * number of completed data bytes correspond to and rewind the
+ * integrity vector accordingly.
+ */
+static void dm_bio_integrity_rewind(struct bio *bio, unsigned int bytes_done)
+{
+       struct bio_integrity_payload *bip = bio_integrity(bio);
+       struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
+       unsigned bytes = bio_integrity_bytes(bi, bytes_done >> 9);
+
+       bip->bip_iter.bi_sector -= bio_integrity_intervals(bi, bytes_done >> 9);
+       dm_bvec_iter_rewind(bip->bip_vec, &bip->bip_iter, bytes);
+}
+
+#else /* CONFIG_BLK_DEV_INTEGRITY */
+
+static inline void dm_bio_integrity_rewind(struct bio *bio,
+                                          unsigned int bytes_done)
+{
+       return;
+}
+
+#endif
+
+#if defined(CONFIG_BLK_INLINE_ENCRYPTION)
+
+/* Decrements @dun by @dec, treating @dun as a multi-limb integer. */
+static void dm_bio_crypt_dun_decrement(u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE],
+                                      unsigned int dec)
+{
+       int i;
+
+       for (i = 0; dec && i < BLK_CRYPTO_DUN_ARRAY_SIZE; i++) {
+               u64 prev = dun[i];
+
+               dun[i] -= dec;
+               if (dun[i] > prev)
+                       dec = 1;
+               else
+                       dec = 0;
+       }
+}
+
+static void dm_bio_crypt_rewind(struct bio *bio, unsigned int bytes)
+{
+       struct bio_crypt_ctx *bc = bio->bi_crypt_context;
+
+       dm_bio_crypt_dun_decrement(bc->bc_dun,
+                                  bytes >> bc->bc_key->data_unit_size_bits);
+}
+
+#else /* CONFIG_BLK_INLINE_ENCRYPTION */
+
+static inline void dm_bio_crypt_rewind(struct bio *bio, unsigned int bytes)
+{
+       return;
+}
+
+#endif
+
+static inline void dm_bio_rewind_iter(const struct bio *bio,
+                                     struct bvec_iter *iter, unsigned int bytes)
+{
+       iter->bi_sector -= bytes >> 9;
+
+       /* No advance means no rewind */
+       if (bio_no_advance_iter(bio))
+               iter->bi_size += bytes;
+       else
+               dm_bvec_iter_rewind(bio->bi_io_vec, iter, bytes);
+}
+
+/**
+ * dm_bio_rewind - update ->bi_iter of @bio by rewinding @bytes.
+ * @bio: bio to rewind
+ * @bytes: how many bytes to rewind
+ *
+ * WARNING:
+ * Caller must ensure that @bio has a fixed end sector, to allow
+ * rewinding from end of bio and restoring its original position.
+ * Caller is also responsibile for restoring bio's size.
+ */
+static void dm_bio_rewind(struct bio *bio, unsigned bytes)
+{
+       if (bio_integrity(bio))
+               dm_bio_integrity_rewind(bio, bytes);
+
+       if (bio_has_crypt_ctx(bio))
+               dm_bio_crypt_rewind(bio, bytes);
+
+       dm_bio_rewind_iter(bio, &bio->bi_iter, bytes);
+}
+
+void dm_io_rewind(struct dm_io *io, struct bio_set *bs)
+{
+       struct bio *orig = io->orig_bio;
+       struct bio *new_orig = bio_alloc_clone(orig->bi_bdev, orig,
+                                              GFP_NOIO, bs);
+       /*
+        * dm_bio_rewind can restore to previous position since the
+        * end sector is fixed for original bio, but we still need
+        * to restore bio's size manually (using io->sectors).
+        */
+       dm_bio_rewind(new_orig, ((io->sector_offset << 9) -
+                                orig->bi_iter.bi_size));
+       bio_trim(new_orig, 0, io->sectors);
+
+       bio_chain(new_orig, orig);
+       /*
+        * __bi_remaining was increased (by dm_split_and_process_bio),
+        * so must drop the one added in bio_chain.
+        */
+       atomic_dec(&orig->__bi_remaining);
+       io->orig_bio = new_orig;
+}
index e4b95ea..7835645 100644 (file)
@@ -293,7 +293,7 @@ static void km_dp_init(struct dpages *dp, void *data)
 /*-----------------------------------------------------------------
  * IO routines that accept a list of pages.
  *---------------------------------------------------------------*/
-static void do_region(int op, int op_flags, unsigned region,
+static void do_region(const blk_opf_t opf, unsigned region,
                      struct dm_io_region *where, struct dpages *dp,
                      struct io *io)
 {
@@ -306,6 +306,7 @@ static void do_region(int op, int op_flags, unsigned region,
        struct request_queue *q = bdev_get_queue(where->bdev);
        sector_t num_sectors;
        unsigned int special_cmd_max_sectors;
+       const enum req_op op = opf & REQ_OP_MASK;
 
        /*
         * Reject unsupported discard and write same requests.
@@ -339,8 +340,8 @@ static void do_region(int op, int op_flags, unsigned region,
                                                (PAGE_SIZE >> SECTOR_SHIFT)));
                }
 
-               bio = bio_alloc_bioset(where->bdev, num_bvecs, op | op_flags,
-                                      GFP_NOIO, &io->client->bios);
+               bio = bio_alloc_bioset(where->bdev, num_bvecs, opf, GFP_NOIO,
+                                      &io->client->bios);
                bio->bi_iter.bi_sector = where->sector + (where->count - remaining);
                bio->bi_end_io = endio;
                store_io_and_region_in_bio(bio, io, region);
@@ -368,7 +369,7 @@ static void do_region(int op, int op_flags, unsigned region,
        } while (remaining);
 }
 
-static void dispatch_io(int op, int op_flags, unsigned int num_regions,
+static void dispatch_io(blk_opf_t opf, unsigned int num_regions,
                        struct dm_io_region *where, struct dpages *dp,
                        struct io *io, int sync)
 {
@@ -378,7 +379,7 @@ static void dispatch_io(int op, int op_flags, unsigned int num_regions,
        BUG_ON(num_regions > DM_IO_MAX_REGIONS);
 
        if (sync)
-               op_flags |= REQ_SYNC;
+               opf |= REQ_SYNC;
 
        /*
         * For multiple regions we need to be careful to rewind
@@ -386,8 +387,8 @@ static void dispatch_io(int op, int op_flags, unsigned int num_regions,
         */
        for (i = 0; i < num_regions; i++) {
                *dp = old_pages;
-               if (where[i].count || (op_flags & REQ_PREFLUSH))
-                       do_region(op, op_flags, i, where + i, dp, io);
+               if (where[i].count || (opf & REQ_PREFLUSH))
+                       do_region(opf, i, where + i, dp, io);
        }
 
        /*
@@ -411,13 +412,13 @@ static void sync_io_complete(unsigned long error, void *context)
 }
 
 static int sync_io(struct dm_io_client *client, unsigned int num_regions,
-                  struct dm_io_region *where, int op, int op_flags,
-                  struct dpages *dp, unsigned long *error_bits)
+                  struct dm_io_region *where, blk_opf_t opf, struct dpages *dp,
+                  unsigned long *error_bits)
 {
        struct io *io;
        struct sync_io sio;
 
-       if (num_regions > 1 && !op_is_write(op)) {
+       if (num_regions > 1 && !op_is_write(opf)) {
                WARN_ON(1);
                return -EIO;
        }
@@ -434,7 +435,7 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions,
        io->vma_invalidate_address = dp->vma_invalidate_address;
        io->vma_invalidate_size = dp->vma_invalidate_size;
 
-       dispatch_io(op, op_flags, num_regions, where, dp, io, 1);
+       dispatch_io(opf, num_regions, where, dp, io, 1);
 
        wait_for_completion_io(&sio.wait);
 
@@ -445,12 +446,12 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions,
 }
 
 static int async_io(struct dm_io_client *client, unsigned int num_regions,
-                   struct dm_io_region *where, int op, int op_flags,
+                   struct dm_io_region *where, blk_opf_t opf,
                    struct dpages *dp, io_notify_fn fn, void *context)
 {
        struct io *io;
 
-       if (num_regions > 1 && !op_is_write(op)) {
+       if (num_regions > 1 && !op_is_write(opf)) {
                WARN_ON(1);
                fn(1, context);
                return -EIO;
@@ -466,7 +467,7 @@ static int async_io(struct dm_io_client *client, unsigned int num_regions,
        io->vma_invalidate_address = dp->vma_invalidate_address;
        io->vma_invalidate_size = dp->vma_invalidate_size;
 
-       dispatch_io(op, op_flags, num_regions, where, dp, io, 0);
+       dispatch_io(opf, num_regions, where, dp, io, 0);
        return 0;
 }
 
@@ -489,7 +490,7 @@ static int dp_init(struct dm_io_request *io_req, struct dpages *dp,
 
        case DM_IO_VMA:
                flush_kernel_vmap_range(io_req->mem.ptr.vma, size);
-               if (io_req->bi_op == REQ_OP_READ) {
+               if ((io_req->bi_opf & REQ_OP_MASK) == REQ_OP_READ) {
                        dp->vma_invalidate_address = io_req->mem.ptr.vma;
                        dp->vma_invalidate_size = size;
                }
@@ -519,11 +520,10 @@ int dm_io(struct dm_io_request *io_req, unsigned num_regions,
 
        if (!io_req->notify.fn)
                return sync_io(io_req->client, num_regions, where,
-                              io_req->bi_op, io_req->bi_op_flags, &dp,
-                              sync_error_bits);
+                              io_req->bi_opf, &dp, sync_error_bits);
 
-       return async_io(io_req->client, num_regions, where, io_req->bi_op,
-                       io_req->bi_op_flags, &dp, io_req->notify.fn,
+       return async_io(io_req->client, num_regions, where,
+                       io_req->bi_opf, &dp, io_req->notify.fn,
                        io_req->notify.context);
 }
 EXPORT_SYMBOL(dm_io);
index 87310fc..98976aa 100644 (file)
@@ -832,7 +832,7 @@ static void __dev_status(struct mapped_device *md, struct dm_ioctl *param)
                if (!(param->flags & DM_QUERY_INACTIVE_TABLE_FLAG)) {
                        if (get_disk_ro(disk))
                                param->flags |= DM_READONLY_FLAG;
-                       param->target_count = dm_table_get_num_targets(table);
+                       param->target_count = table->num_targets;
                }
 
                param->flags |= DM_ACTIVE_PRESENT_FLAG;
@@ -845,7 +845,7 @@ static void __dev_status(struct mapped_device *md, struct dm_ioctl *param)
                if (table) {
                        if (!(dm_table_get_mode(table) & FMODE_WRITE))
                                param->flags |= DM_READONLY_FLAG;
-                       param->target_count = dm_table_get_num_targets(table);
+                       param->target_count = table->num_targets;
                }
                dm_put_live_table(md, srcu_idx);
        }
@@ -1248,7 +1248,7 @@ static void retrieve_status(struct dm_table *table,
                type = STATUSTYPE_INFO;
 
        /* Get all the target info */
-       num_targets = dm_table_get_num_targets(table);
+       num_targets = table->num_targets;
        for (i = 0; i < num_targets; i++) {
                struct dm_target *ti = dm_table_get_target(table, i);
                size_t l;
index 37b03ab..4d3bbbe 100644 (file)
@@ -219,7 +219,7 @@ static struct page_list *alloc_pl(gfp_t gfp)
        if (!pl)
                return NULL;
 
-       pl->page = alloc_page(gfp);
+       pl->page = alloc_page(gfp | __GFP_HIGHMEM);
        if (!pl->page) {
                kfree(pl);
                return NULL;
@@ -350,9 +350,9 @@ struct kcopyd_job {
        unsigned long write_err;
 
        /*
-        * Either READ or WRITE
+        * REQ_OP_READ, REQ_OP_WRITE or REQ_OP_WRITE_ZEROES.
         */
-       int rw;
+       enum req_op op;
        struct dm_io_region source;
 
        /*
@@ -418,7 +418,8 @@ static struct kcopyd_job *pop_io_job(struct list_head *jobs,
         * constraint and sequential writes that are at the right position.
         */
        list_for_each_entry(job, jobs, list) {
-               if (job->rw == READ || !(job->flags & BIT(DM_KCOPYD_WRITE_SEQ))) {
+               if (job->op == REQ_OP_READ ||
+                   !(job->flags & BIT(DM_KCOPYD_WRITE_SEQ))) {
                        list_del(&job->list);
                        return job;
                }
@@ -518,7 +519,7 @@ static void complete_io(unsigned long error, void *context)
        io_job_finish(kc->throttle);
 
        if (error) {
-               if (op_is_write(job->rw))
+               if (op_is_write(job->op))
                        job->write_err |= error;
                else
                        job->read_err = 1;
@@ -530,11 +531,11 @@ static void complete_io(unsigned long error, void *context)
                }
        }
 
-       if (op_is_write(job->rw))
+       if (op_is_write(job->op))
                push(&kc->complete_jobs, job);
 
        else {
-               job->rw = WRITE;
+               job->op = REQ_OP_WRITE;
                push(&kc->io_jobs, job);
        }
 
@@ -549,8 +550,7 @@ static int run_io_job(struct kcopyd_job *job)
 {
        int r;
        struct dm_io_request io_req = {
-               .bi_op = job->rw,
-               .bi_op_flags = 0,
+               .bi_opf = job->op,
                .mem.type = DM_IO_PAGE_LIST,
                .mem.ptr.pl = job->pages,
                .mem.offset = 0,
@@ -571,7 +571,7 @@ static int run_io_job(struct kcopyd_job *job)
 
        io_job_start(job->kc->throttle);
 
-       if (job->rw == READ)
+       if (job->op == REQ_OP_READ)
                r = dm_io(&io_req, 1, &job->source, NULL);
        else
                r = dm_io(&io_req, job->num_dests, job->dests, NULL);
@@ -614,7 +614,7 @@ static int process_jobs(struct list_head *jobs, struct dm_kcopyd_client *kc,
 
                if (r < 0) {
                        /* error this rogue job */
-                       if (op_is_write(job->rw))
+                       if (op_is_write(job->op))
                                job->write_err = (unsigned long) -1L;
                        else
                                job->read_err = 1;
@@ -817,7 +817,7 @@ void dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
        if (from) {
                job->source = *from;
                job->pages = NULL;
-               job->rw = READ;
+               job->op = REQ_OP_READ;
        } else {
                memset(&job->source, 0, sizeof job->source);
                job->source.count = job->dests[0].count;
@@ -826,10 +826,10 @@ void dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
                /*
                 * Use WRITE ZEROES to optimize zeroing if all dests support it.
                 */
-               job->rw = REQ_OP_WRITE_ZEROES;
+               job->op = REQ_OP_WRITE_ZEROES;
                for (i = 0; i < job->num_dests; i++)
                        if (!bdev_write_zeroes_sectors(job->dests[i].bdev)) {
-                               job->rw = WRITE;
+                               job->op = REQ_OP_WRITE;
                                break;
                        }
        }
index 0c6620e..cf10fa6 100644 (file)
@@ -291,10 +291,9 @@ static void header_from_disk(struct log_header_core *core, struct log_header_dis
        core->nr_regions = le64_to_cpu(disk->nr_regions);
 }
 
-static int rw_header(struct log_c *lc, int op)
+static int rw_header(struct log_c *lc, enum req_op op)
 {
-       lc->io_req.bi_op = op;
-       lc->io_req.bi_op_flags = 0;
+       lc->io_req.bi_opf = op;
 
        return dm_io(&lc->io_req, 1, &lc->header_location, NULL);
 }
@@ -307,8 +306,7 @@ static int flush_header(struct log_c *lc)
                .count = 0,
        };
 
-       lc->io_req.bi_op = REQ_OP_WRITE;
-       lc->io_req.bi_op_flags = REQ_PREFLUSH;
+       lc->io_req.bi_opf = REQ_OP_WRITE | REQ_PREFLUSH;
 
        return dm_io(&lc->io_req, 1, &null_location, NULL);
 }
index 9526ccb..1ec17c3 100644 (file)
@@ -1001,12 +1001,13 @@ static int validate_region_size(struct raid_set *rs, unsigned long region_size)
 static int validate_raid_redundancy(struct raid_set *rs)
 {
        unsigned int i, rebuild_cnt = 0;
-       unsigned int rebuilds_per_group = 0, copies;
+       unsigned int rebuilds_per_group = 0, copies, raid_disks;
        unsigned int group_size, last_group_start;
 
-       for (i = 0; i < rs->md.raid_disks; i++)
-               if (!test_bit(In_sync, &rs->dev[i].rdev.flags) ||
-                   !rs->dev[i].rdev.sb_page)
+       for (i = 0; i < rs->raid_disks; i++)
+               if (!test_bit(FirstUse, &rs->dev[i].rdev.flags) &&
+                   ((!test_bit(In_sync, &rs->dev[i].rdev.flags) ||
+                     !rs->dev[i].rdev.sb_page)))
                        rebuild_cnt++;
 
        switch (rs->md.level) {
@@ -1046,8 +1047,9 @@ static int validate_raid_redundancy(struct raid_set *rs)
                 *          A    A    B    B    C
                 *          C    D    D    E    E
                 */
+               raid_disks = min(rs->raid_disks, rs->md.raid_disks);
                if (__is_raid10_near(rs->md.new_layout)) {
-                       for (i = 0; i < rs->md.raid_disks; i++) {
+                       for (i = 0; i < raid_disks; i++) {
                                if (!(i % copies))
                                        rebuilds_per_group = 0;
                                if ((!rs->dev[i].rdev.sb_page ||
@@ -1070,10 +1072,10 @@ static int validate_raid_redundancy(struct raid_set *rs)
                 * results in the need to treat the last (potentially larger)
                 * set differently.
                 */
-               group_size = (rs->md.raid_disks / copies);
-               last_group_start = (rs->md.raid_disks / group_size) - 1;
+               group_size = (raid_disks / copies);
+               last_group_start = (raid_disks / group_size) - 1;
                last_group_start *= group_size;
-               for (i = 0; i < rs->md.raid_disks; i++) {
+               for (i = 0; i < raid_disks; i++) {
                        if (!(i % copies) && !(i > last_group_start))
                                rebuilds_per_group = 0;
                        if ((!rs->dev[i].rdev.sb_page ||
@@ -1367,7 +1369,7 @@ static int parse_raid_params(struct raid_set *rs, struct dm_arg_set *as,
                        }
                        rs->md.bitmap_info.daemon_sleep = value;
                } else if (!strcasecmp(key, dm_raid_arg_name_by_flag(CTR_FLAG_DATA_OFFSET))) {
-                       /* Userspace passes new data_offset after having extended the the data image LV */
+                       /* Userspace passes new data_offset after having extended the data image LV */
                        if (test_and_set_bit(__CTR_FLAG_DATA_OFFSET, &rs->ctr_flags)) {
                                rs->ti->error = "Only one data_offset argument pair allowed";
                                return -EINVAL;
@@ -1588,7 +1590,7 @@ static sector_t __rdev_sectors(struct raid_set *rs)
 {
        int i;
 
-       for (i = 0; i < rs->md.raid_disks; i++) {
+       for (i = 0; i < rs->raid_disks; i++) {
                struct md_rdev *rdev = &rs->dev[i].rdev;
 
                if (!test_bit(Journal, &rdev->flags) &&
@@ -2036,7 +2038,7 @@ static int read_disk_sb(struct md_rdev *rdev, int size, bool force_reload)
 
        rdev->sb_loaded = 0;
 
-       if (!sync_page_io(rdev, 0, size, rdev->sb_page, REQ_OP_READ, 0, true)) {
+       if (!sync_page_io(rdev, 0, size, rdev->sb_page, REQ_OP_READ, true)) {
                DMERR("Failed to read superblock of device at position %d",
                      rdev->raid_disk);
                md_error(rdev->mddev, rdev);
@@ -3095,6 +3097,7 @@ static int raid_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        INIT_WORK(&rs->md.event_work, do_table_event);
        ti->private = rs;
        ti->num_flush_bios = 1;
+       ti->needs_bio_set_dev = true;
 
        /* Restore any requested new layout for conversion decision */
        rs_config_restore(rs, &rs_layout);
@@ -3507,7 +3510,7 @@ static void raid_status(struct dm_target *ti, status_type_t type,
 {
        struct raid_set *rs = ti->private;
        struct mddev *mddev = &rs->md;
-       struct r5conf *conf = mddev->private;
+       struct r5conf *conf = rs_is_raid456(rs) ? mddev->private : NULL;
        int i, max_nr_stripes = conf ? conf->max_nr_stripes : 0;
        unsigned long recovery;
        unsigned int raid_param_cnt = 1; /* at least 1 for chunksize */
@@ -3766,13 +3769,13 @@ static int raid_iterate_devices(struct dm_target *ti,
        unsigned int i;
        int r = 0;
 
-       for (i = 0; !r && i < rs->md.raid_disks; i++)
-               if (rs->dev[i].data_dev)
-                       r = fn(ti,
-                                rs->dev[i].data_dev,
-                                0, /* No offset on data devs */
-                                rs->md.dev_sectors,
-                                data);
+       for (i = 0; !r && i < rs->raid_disks; i++) {
+               if (rs->dev[i].data_dev) {
+                       r = fn(ti, rs->dev[i].data_dev,
+                              0, /* No offset on data devs */
+                              rs->md.dev_sectors, data);
+               }
+       }
 
        return r;
 }
@@ -3817,7 +3820,7 @@ static void attempt_restore_of_faulty_devices(struct raid_set *rs)
 
        memset(cleared_failed_devices, 0, sizeof(cleared_failed_devices));
 
-       for (i = 0; i < mddev->raid_disks; i++) {
+       for (i = 0; i < rs->raid_disks; i++) {
                r = &rs->dev[i].rdev;
                /* HM FIXME: enhance journal device recovery processing */
                if (test_bit(Journal, &r->flags))
index 8811d48..06a38dc 100644 (file)
@@ -260,8 +260,7 @@ static int mirror_flush(struct dm_target *ti)
        struct dm_io_region io[MAX_NR_MIRRORS];
        struct mirror *m;
        struct dm_io_request io_req = {
-               .bi_op = REQ_OP_WRITE,
-               .bi_op_flags = REQ_PREFLUSH | REQ_SYNC,
+               .bi_opf = REQ_OP_WRITE | REQ_PREFLUSH | REQ_SYNC,
                .mem.type = DM_IO_KMEM,
                .mem.ptr.addr = NULL,
                .client = ms->io_client,
@@ -535,8 +534,7 @@ static void read_async_bio(struct mirror *m, struct bio *bio)
 {
        struct dm_io_region io;
        struct dm_io_request io_req = {
-               .bi_op = REQ_OP_READ,
-               .bi_op_flags = 0,
+               .bi_opf = REQ_OP_READ,
                .mem.type = DM_IO_BIO,
                .mem.ptr.bio = bio,
                .notify.fn = read_callback,
@@ -648,9 +646,9 @@ static void do_write(struct mirror_set *ms, struct bio *bio)
        unsigned int i;
        struct dm_io_region io[MAX_NR_MIRRORS], *dest = io;
        struct mirror *m;
+       blk_opf_t op_flags = bio->bi_opf & (REQ_FUA | REQ_PREFLUSH);
        struct dm_io_request io_req = {
-               .bi_op = REQ_OP_WRITE,
-               .bi_op_flags = bio->bi_opf & (REQ_FUA | REQ_PREFLUSH),
+               .bi_opf = REQ_OP_WRITE | op_flags,
                .mem.type = DM_IO_BIO,
                .mem.ptr.bio = bio,
                .notify.fn = write_callback,
@@ -659,7 +657,7 @@ static void do_write(struct mirror_set *ms, struct bio *bio)
        };
 
        if (bio_op(bio) == REQ_OP_DISCARD) {
-               io_req.bi_op = REQ_OP_DISCARD;
+               io_req.bi_opf = REQ_OP_DISCARD | op_flags;
                io_req.mem.type = DM_IO_KMEM;
                io_req.mem.ptr.addr = NULL;
        }
index a83b98a..4f49bbc 100644 (file)
@@ -43,7 +43,6 @@ unsigned dm_get_reserved_rq_based_ios(void)
        return __dm_get_module_param(&reserved_rq_based_ios,
                                     RESERVED_REQUEST_BASED_IOS, DM_RESERVED_MAX_IOS);
 }
-EXPORT_SYMBOL_GPL(dm_get_reserved_rq_based_ios);
 
 static unsigned dm_get_blk_mq_nr_hw_queues(void)
 {
index 3bb5cff..f46f930 100644 (file)
@@ -226,8 +226,8 @@ static void do_metadata(struct work_struct *work)
 /*
  * Read or write a chunk aligned and sized block of data from a device.
  */
-static int chunk_io(struct pstore *ps, void *area, chunk_t chunk, int op,
-                   int op_flags, int metadata)
+static int chunk_io(struct pstore *ps, void *area, chunk_t chunk, blk_opf_t opf,
+                   int metadata)
 {
        struct dm_io_region where = {
                .bdev = dm_snap_cow(ps->store->snap)->bdev,
@@ -235,8 +235,7 @@ static int chunk_io(struct pstore *ps, void *area, chunk_t chunk, int op,
                .count = ps->store->chunk_size,
        };
        struct dm_io_request io_req = {
-               .bi_op = op,
-               .bi_op_flags = op_flags,
+               .bi_opf = opf,
                .mem.type = DM_IO_VMA,
                .mem.ptr.vma = area,
                .client = ps->io_client,
@@ -282,11 +281,11 @@ static void skip_metadata(struct pstore *ps)
  * Read or write a metadata area.  Remembering to skip the first
  * chunk which holds the header.
  */
-static int area_io(struct pstore *ps, int op, int op_flags)
+static int area_io(struct pstore *ps, blk_opf_t opf)
 {
        chunk_t chunk = area_location(ps, ps->current_area);
 
-       return chunk_io(ps, ps->area, chunk, op, op_flags, 0);
+       return chunk_io(ps, ps->area, chunk, opf, 0);
 }
 
 static void zero_memory_area(struct pstore *ps)
@@ -297,7 +296,7 @@ static void zero_memory_area(struct pstore *ps)
 static int zero_disk_area(struct pstore *ps, chunk_t area)
 {
        return chunk_io(ps, ps->zero_area, area_location(ps, area),
-                       REQ_OP_WRITE, 0, 0);
+                       REQ_OP_WRITE, 0);
 }
 
 static int read_header(struct pstore *ps, int *new_snapshot)
@@ -329,7 +328,7 @@ static int read_header(struct pstore *ps, int *new_snapshot)
        if (r)
                return r;
 
-       r = chunk_io(ps, ps->header_area, 0, REQ_OP_READ, 0, 1);
+       r = chunk_io(ps, ps->header_area, 0, REQ_OP_READ, 1);
        if (r)
                goto bad;
 
@@ -390,7 +389,7 @@ static int write_header(struct pstore *ps)
        dh->version = cpu_to_le32(ps->version);
        dh->chunk_size = cpu_to_le32(ps->store->chunk_size);
 
-       return chunk_io(ps, ps->header_area, 0, REQ_OP_WRITE, 0, 1);
+       return chunk_io(ps, ps->header_area, 0, REQ_OP_WRITE, 1);
 }
 
 /*
@@ -734,8 +733,8 @@ static void persistent_commit_exception(struct dm_exception_store *store,
        /*
         * Commit exceptions to disk.
         */
-       if (ps->valid && area_io(ps, REQ_OP_WRITE,
-                                REQ_PREFLUSH | REQ_FUA | REQ_SYNC))
+       if (ps->valid && area_io(ps, REQ_OP_WRITE | REQ_PREFLUSH | REQ_FUA |
+                                REQ_SYNC))
                ps->valid = 0;
 
        /*
@@ -775,7 +774,7 @@ static int persistent_prepare_merge(struct dm_exception_store *store,
                        return 0;
 
                ps->current_area--;
-               r = area_io(ps, REQ_OP_READ, 0);
+               r = area_io(ps, REQ_OP_READ);
                if (r < 0)
                        return r;
                ps->current_committed = ps->exceptions_per_area;
@@ -812,7 +811,7 @@ static int persistent_commit_merge(struct dm_exception_store *store,
        for (i = 0; i < nr_merged; i++)
                clear_exception(ps, ps->current_committed - 1 - i);
 
-       r = area_io(ps, REQ_OP_WRITE, REQ_PREFLUSH | REQ_FUA);
+       r = area_io(ps, REQ_OP_WRITE | REQ_PREFLUSH | REQ_FUA);
        if (r < 0)
                return r;
 
index 0d336b5..d1c2f84 100644 (file)
@@ -2026,7 +2026,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)
        /*
         * Write to snapshot - higher level takes care of RW/RO
         * flags so we should only get this if we are
-        * writeable.
+        * writable.
         */
        if (bio_data_dir(bio) == WRITE) {
                pe = __lookup_pending_exception(s, chunk);
index bd539af..332f96b 100644 (file)
@@ -6,6 +6,7 @@
  */
 
 #include "dm-core.h"
+#include "dm-rq.h"
 
 #include <linux/module.h>
 #include <linux/vmalloc.h>
@@ -174,8 +175,6 @@ static void dm_table_destroy_crypto_profile(struct dm_table *t);
 
 void dm_table_destroy(struct dm_table *t)
 {
-       unsigned int i;
-
        if (!t)
                return;
 
@@ -184,13 +183,13 @@ void dm_table_destroy(struct dm_table *t)
                kvfree(t->index[t->depth - 2]);
 
        /* free the targets */
-       for (i = 0; i < t->num_targets; i++) {
-               struct dm_target *tgt = t->targets + i;
+       for (unsigned int i = 0; i < t->num_targets; i++) {
+               struct dm_target *ti = dm_table_get_target(t, i);
 
-               if (tgt->type->dtr)
-                       tgt->type->dtr(tgt);
+               if (ti->type->dtr)
+                       ti->type->dtr(ti);
 
-               dm_put_target_type(tgt->type);
+               dm_put_target_type(ti->type);
        }
 
        kvfree(t->highs);
@@ -450,14 +449,14 @@ EXPORT_SYMBOL(dm_put_device);
 /*
  * Checks to see if the target joins onto the end of the table.
  */
-static int adjoin(struct dm_table *table, struct dm_target *ti)
+static int adjoin(struct dm_table *t, struct dm_target *ti)
 {
        struct dm_target *prev;
 
-       if (!table->num_targets)
+       if (!t->num_targets)
                return !ti->begin;
 
-       prev = &table->targets[table->num_targets - 1];
+       prev = &t->targets[t->num_targets - 1];
        return (ti->begin == (prev->begin + prev->len));
 }
 
@@ -564,8 +563,8 @@ int dm_split_args(int *argc, char ***argvp, char *input)
  * two or more targets, the size of each piece it gets split into must
  * be compatible with the logical_block_size of the target processing it.
  */
-static int validate_hardware_logical_block_alignment(struct dm_table *table,
-                                                struct queue_limits *limits)
+static int validate_hardware_logical_block_alignment(struct dm_table *t,
+                                                    struct queue_limits *limits)
 {
        /*
         * This function uses arithmetic modulo the logical_block_size
@@ -587,13 +586,13 @@ static int validate_hardware_logical_block_alignment(struct dm_table *table,
 
        struct dm_target *ti;
        struct queue_limits ti_limits;
-       unsigned i;
+       unsigned int i;
 
        /*
         * Check each entry in the table in turn.
         */
-       for (i = 0; i < dm_table_get_num_targets(table); i++) {
-               ti = dm_table_get_target(table, i);
+       for (i = 0; i < t->num_targets; i++) {
+               ti = dm_table_get_target(t, i);
 
                blk_set_stacking_limits(&ti_limits);
 
@@ -621,7 +620,7 @@ static int validate_hardware_logical_block_alignment(struct dm_table *table,
        if (remaining) {
                DMWARN("%s: table line %u (start sect %llu len %llu) "
                       "not aligned to h/w logical block size %u",
-                      dm_device_name(table->md), i,
+                      dm_device_name(t->md), i,
                       (unsigned long long) ti->begin,
                       (unsigned long long) ti->len,
                       limits->logical_block_size);
@@ -636,7 +635,7 @@ int dm_table_add_target(struct dm_table *t, const char *type,
 {
        int r = -EINVAL, argc;
        char **argv;
-       struct dm_target *tgt;
+       struct dm_target *ti;
 
        if (t->singleton) {
                DMERR("%s: target type %s must appear alone in table",
@@ -646,87 +645,87 @@ int dm_table_add_target(struct dm_table *t, const char *type,
 
        BUG_ON(t->num_targets >= t->num_allocated);
 
-       tgt = t->targets + t->num_targets;
-       memset(tgt, 0, sizeof(*tgt));
+       ti = t->targets + t->num_targets;
+       memset(ti, 0, sizeof(*ti));
 
        if (!len) {
                DMERR("%s: zero-length target", dm_device_name(t->md));
                return -EINVAL;
        }
 
-       tgt->type = dm_get_target_type(type);
-       if (!tgt->type) {
+       ti->type = dm_get_target_type(type);
+       if (!ti->type) {
                DMERR("%s: %s: unknown target type", dm_device_name(t->md), type);
                return -EINVAL;
        }
 
-       if (dm_target_needs_singleton(tgt->type)) {
+       if (dm_target_needs_singleton(ti->type)) {
                if (t->num_targets) {
-                       tgt->error = "singleton target type must appear alone in table";
+                       ti->error = "singleton target type must appear alone in table";
                        goto bad;
                }
                t->singleton = true;
        }
 
-       if (dm_target_always_writeable(tgt->type) && !(t->mode & FMODE_WRITE)) {
-               tgt->error = "target type may not be included in a read-only table";
+       if (dm_target_always_writeable(ti->type) && !(t->mode & FMODE_WRITE)) {
+               ti->error = "target type may not be included in a read-only table";
                goto bad;
        }
 
        if (t->immutable_target_type) {
-               if (t->immutable_target_type != tgt->type) {
-                       tgt->error = "immutable target type cannot be mixed with other target types";
+               if (t->immutable_target_type != ti->type) {
+                       ti->error = "immutable target type cannot be mixed with other target types";
                        goto bad;
                }
-       } else if (dm_target_is_immutable(tgt->type)) {
+       } else if (dm_target_is_immutable(ti->type)) {
                if (t->num_targets) {
-                       tgt->error = "immutable target type cannot be mixed with other target types";
+                       ti->error = "immutable target type cannot be mixed with other target types";
                        goto bad;
                }
-               t->immutable_target_type = tgt->type;
+               t->immutable_target_type = ti->type;
        }
 
-       if (dm_target_has_integrity(tgt->type))
+       if (dm_target_has_integrity(ti->type))
                t->integrity_added = 1;
 
-       tgt->table = t;
-       tgt->begin = start;
-       tgt->len = len;
-       tgt->error = "Unknown error";
+       ti->table = t;
+       ti->begin = start;
+       ti->len = len;
+       ti->error = "Unknown error";
 
        /*
         * Does this target adjoin the previous one ?
         */
-       if (!adjoin(t, tgt)) {
-               tgt->error = "Gap in table";
+       if (!adjoin(t, ti)) {
+               ti->error = "Gap in table";
                goto bad;
        }
 
        r = dm_split_args(&argc, &argv, params);
        if (r) {
-               tgt->error = "couldn't split parameters";
+               ti->error = "couldn't split parameters";
                goto bad;
        }
 
-       r = tgt->type->ctr(tgt, argc, argv);
+       r = ti->type->ctr(ti, argc, argv);
        kfree(argv);
        if (r)
                goto bad;
 
-       t->highs[t->num_targets++] = tgt->begin + tgt->len - 1;
+       t->highs[t->num_targets++] = ti->begin + ti->len - 1;
 
-       if (!tgt->num_discard_bios && tgt->discards_supported)
+       if (!ti->num_discard_bios && ti->discards_supported)
                DMWARN("%s: %s: ignoring discards_supported because num_discard_bios is zero.",
                       dm_device_name(t->md), type);
 
-       if (tgt->limit_swap_bios && !static_key_enabled(&swap_bios_enabled.key))
+       if (ti->limit_swap_bios && !static_key_enabled(&swap_bios_enabled.key))
                static_branch_enable(&swap_bios_enabled);
 
        return 0;
 
  bad:
-       DMERR("%s: %s: %s (%pe)", dm_device_name(t->md), type, tgt->error, ERR_PTR(r));
-       dm_put_target_type(tgt->type);
+       DMERR("%s: %s: %s (%pe)", dm_device_name(t->md), type, ti->error, ERR_PTR(r));
+       dm_put_target_type(ti->type);
        return r;
 }
 
@@ -825,14 +824,11 @@ static int device_not_dax_synchronous_capable(struct dm_target *ti, struct dm_de
 }
 
 static bool dm_table_supports_dax(struct dm_table *t,
-                          iterate_devices_callout_fn iterate_fn)
+                                 iterate_devices_callout_fn iterate_fn)
 {
-       struct dm_target *ti;
-       unsigned i;
-
        /* Ensure that all targets support DAX. */
-       for (i = 0; i < dm_table_get_num_targets(t); i++) {
-               ti = dm_table_get_target(t, i);
+       for (unsigned int i = 0; i < t->num_targets; i++) {
+               struct dm_target *ti = dm_table_get_target(t, i);
 
                if (!ti->type->direct_access)
                        return false;
@@ -860,9 +856,8 @@ static int device_is_rq_stackable(struct dm_target *ti, struct dm_dev *dev,
 
 static int dm_table_determine_type(struct dm_table *t)
 {
-       unsigned i;
        unsigned bio_based = 0, request_based = 0, hybrid = 0;
-       struct dm_target *tgt;
+       struct dm_target *ti;
        struct list_head *devices = dm_table_get_devices(t);
        enum dm_queue_mode live_md_type = dm_get_md_type(t->md);
 
@@ -876,11 +871,11 @@ static int dm_table_determine_type(struct dm_table *t)
                goto verify_rq_based;
        }
 
-       for (i = 0; i < t->num_targets; i++) {
-               tgt = t->targets + i;
-               if (dm_target_hybrid(tgt))
+       for (unsigned int i = 0; i < t->num_targets; i++) {
+               ti = dm_table_get_target(t, i);
+               if (dm_target_hybrid(ti))
                        hybrid = 1;
-               else if (dm_target_request_based(tgt))
+               else if (dm_target_request_based(ti))
                        request_based = 1;
                else
                        bio_based = 1;
@@ -942,18 +937,18 @@ verify_rq_based:
                return 0;
        }
 
-       tgt = dm_table_get_immutable_target(t);
-       if (!tgt) {
+       ti = dm_table_get_immutable_target(t);
+       if (!ti) {
                DMERR("table load rejected: immutable target is required");
                return -EINVAL;
-       } else if (tgt->max_io_len) {
+       } else if (ti->max_io_len) {
                DMERR("table load rejected: immutable target that splits IO is not supported");
                return -EINVAL;
        }
 
        /* Non-request-stackable devices can't be used for request-based dm */
-       if (!tgt->type->iterate_devices ||
-           !tgt->type->iterate_devices(tgt, device_is_rq_stackable, NULL)) {
+       if (!ti->type->iterate_devices ||
+           !ti->type->iterate_devices(ti, device_is_rq_stackable, NULL)) {
                DMERR("table load rejected: including non-request-stackable devices");
                return -EINVAL;
        }
@@ -983,11 +978,9 @@ struct dm_target *dm_table_get_immutable_target(struct dm_table *t)
 
 struct dm_target *dm_table_get_wildcard_target(struct dm_table *t)
 {
-       struct dm_target *ti;
-       unsigned i;
+       for (unsigned int i = 0; i < t->num_targets; i++) {
+               struct dm_target *ti = dm_table_get_target(t, i);
 
-       for (i = 0; i < dm_table_get_num_targets(t); i++) {
-               ti = dm_table_get_target(t, i);
                if (dm_target_is_wildcard(ti->type))
                        return ti;
        }
@@ -1010,32 +1003,56 @@ static bool dm_table_supports_poll(struct dm_table *t);
 static int dm_table_alloc_md_mempools(struct dm_table *t, struct mapped_device *md)
 {
        enum dm_queue_mode type = dm_table_get_type(t);
-       unsigned per_io_data_size = 0;
-       unsigned min_pool_size = 0;
-       struct dm_target *ti;
-       unsigned i;
-       bool poll_supported = false;
+       unsigned int per_io_data_size = 0, front_pad, io_front_pad;
+       unsigned int min_pool_size = 0, pool_size;
+       struct dm_md_mempools *pools;
 
        if (unlikely(type == DM_TYPE_NONE)) {
                DMWARN("no table type is set, can't allocate mempools");
                return -EINVAL;
        }
 
-       if (__table_type_bio_based(type)) {
-               for (i = 0; i < t->num_targets; i++) {
-                       ti = t->targets + i;
-                       per_io_data_size = max(per_io_data_size, ti->per_io_data_size);
-                       min_pool_size = max(min_pool_size, ti->num_flush_bios);
-               }
-               poll_supported = dm_table_supports_poll(t);
+       pools = kzalloc_node(sizeof(*pools), GFP_KERNEL, md->numa_node_id);
+       if (!pools)
+               return -ENOMEM;
+
+       if (type == DM_TYPE_REQUEST_BASED) {
+               pool_size = dm_get_reserved_rq_based_ios();
+               front_pad = offsetof(struct dm_rq_clone_bio_info, clone);
+               goto init_bs;
        }
 
-       t->mempools = dm_alloc_md_mempools(md, type, per_io_data_size, min_pool_size,
-                                          t->integrity_supported, poll_supported);
-       if (!t->mempools)
-               return -ENOMEM;
+       for (unsigned int i = 0; i < t->num_targets; i++) {
+               struct dm_target *ti = dm_table_get_target(t, i);
 
+               per_io_data_size = max(per_io_data_size, ti->per_io_data_size);
+               min_pool_size = max(min_pool_size, ti->num_flush_bios);
+       }
+       pool_size = max(dm_get_reserved_bio_based_ios(), min_pool_size);
+       front_pad = roundup(per_io_data_size,
+               __alignof__(struct dm_target_io)) + DM_TARGET_IO_BIO_OFFSET;
+
+       io_front_pad = roundup(per_io_data_size,
+               __alignof__(struct dm_io)) + DM_IO_BIO_OFFSET;
+       if (bioset_init(&pools->io_bs, pool_size, io_front_pad,
+                       dm_table_supports_poll(t) ? BIOSET_PERCPU_CACHE : 0))
+               goto out_free_pools;
+       if (t->integrity_supported &&
+           bioset_integrity_create(&pools->io_bs, pool_size))
+               goto out_free_pools;
+init_bs:
+       if (bioset_init(&pools->bs, pool_size, front_pad, 0))
+               goto out_free_pools;
+       if (t->integrity_supported &&
+           bioset_integrity_create(&pools->bs, pool_size))
+               goto out_free_pools;
+
+       t->mempools = pools;
        return 0;
+
+out_free_pools:
+       dm_free_md_mempools(pools);
+       return -ENOMEM;
 }
 
 static int setup_indexes(struct dm_table *t)
@@ -1100,10 +1117,10 @@ static struct gendisk * dm_table_get_integrity_disk(struct dm_table *t)
        struct list_head *devices = dm_table_get_devices(t);
        struct dm_dev_internal *dd = NULL;
        struct gendisk *prev_disk = NULL, *template_disk = NULL;
-       unsigned i;
 
-       for (i = 0; i < dm_table_get_num_targets(t); i++) {
+       for (unsigned int i = 0; i < t->num_targets; i++) {
                struct dm_target *ti = dm_table_get_target(t, i);
+
                if (!dm_target_passes_integrity(ti->type))
                        goto no_integrity;
        }
@@ -1217,18 +1234,19 @@ static int dm_keyslot_evict(struct blk_crypto_profile *profile,
        struct dm_keyslot_evict_args args = { key };
        struct dm_table *t;
        int srcu_idx;
-       int i;
-       struct dm_target *ti;
 
        t = dm_get_live_table(md, &srcu_idx);
        if (!t)
                return 0;
-       for (i = 0; i < dm_table_get_num_targets(t); i++) {
-               ti = dm_table_get_target(t, i);
+
+       for (unsigned int i = 0; i < t->num_targets; i++) {
+               struct dm_target *ti = dm_table_get_target(t, i);
+
                if (!ti->type->iterate_devices)
                        continue;
                ti->type->iterate_devices(ti, dm_keyslot_evict_callback, &args);
        }
+
        dm_put_live_table(md, srcu_idx);
        return args.err;
 }
@@ -1277,7 +1295,6 @@ static int dm_table_construct_crypto_profile(struct dm_table *t)
 {
        struct dm_crypto_profile *dmcp;
        struct blk_crypto_profile *profile;
-       struct dm_target *ti;
        unsigned int i;
        bool empty_profile = true;
 
@@ -1293,8 +1310,8 @@ static int dm_table_construct_crypto_profile(struct dm_table *t)
        memset(profile->modes_supported, 0xFF,
               sizeof(profile->modes_supported));
 
-       for (i = 0; i < dm_table_get_num_targets(t); i++) {
-               ti = dm_table_get_target(t, i);
+       for (i = 0; i < t->num_targets; i++) {
+               struct dm_target *ti = dm_table_get_target(t, i);
 
                if (!dm_target_passes_crypto(ti->type)) {
                        blk_crypto_intersect_capabilities(profile, NULL);
@@ -1444,14 +1461,6 @@ inline sector_t dm_table_get_size(struct dm_table *t)
 }
 EXPORT_SYMBOL(dm_table_get_size);
 
-struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index)
-{
-       if (index >= t->num_targets)
-               return NULL;
-
-       return t->targets + index;
-}
-
 /*
  * Search the btree for the correct target.
  *
@@ -1512,11 +1521,8 @@ static int device_not_poll_capable(struct dm_target *ti, struct dm_dev *dev,
 static bool dm_table_any_dev_attr(struct dm_table *t,
                                  iterate_devices_callout_fn func, void *data)
 {
-       struct dm_target *ti;
-       unsigned int i;
-
-       for (i = 0; i < dm_table_get_num_targets(t); i++) {
-               ti = dm_table_get_target(t, i);
+       for (unsigned int i = 0; i < t->num_targets; i++) {
+               struct dm_target *ti = dm_table_get_target(t, i);
 
                if (ti->type->iterate_devices &&
                    ti->type->iterate_devices(ti, func, data))
@@ -1538,11 +1544,8 @@ static int count_device(struct dm_target *ti, struct dm_dev *dev,
 
 static bool dm_table_supports_poll(struct dm_table *t)
 {
-       struct dm_target *ti;
-       unsigned i = 0;
-
-       while (i < dm_table_get_num_targets(t)) {
-               ti = dm_table_get_target(t, i++);
+       for (unsigned int i = 0; i < t->num_targets; i++) {
+               struct dm_target *ti = dm_table_get_target(t, i);
 
                if (!ti->type->iterate_devices ||
                    ti->type->iterate_devices(ti, device_not_poll_capable, NULL))
@@ -1558,18 +1561,15 @@ static bool dm_table_supports_poll(struct dm_table *t)
  * Returns false if the result is unknown because a target doesn't
  * support iterate_devices.
  */
-bool dm_table_has_no_data_devices(struct dm_table *table)
+bool dm_table_has_no_data_devices(struct dm_table *t)
 {
-       struct dm_target *ti;
-       unsigned i, num_devices;
-
-       for (i = 0; i < dm_table_get_num_targets(table); i++) {
-               ti = dm_table_get_target(table, i);
+       for (unsigned int i = 0; i < t->num_targets; i++) {
+               struct dm_target *ti = dm_table_get_target(t, i);
+               unsigned num_devices = 0;
 
                if (!ti->type->iterate_devices)
                        return false;
 
-               num_devices = 0;
                ti->type->iterate_devices(ti, count_device, &num_devices);
                if (num_devices)
                        return false;
@@ -1597,11 +1597,8 @@ static int device_not_zoned_model(struct dm_target *ti, struct dm_dev *dev,
 static bool dm_table_supports_zoned_model(struct dm_table *t,
                                          enum blk_zoned_model zoned_model)
 {
-       struct dm_target *ti;
-       unsigned i;
-
-       for (i = 0; i < dm_table_get_num_targets(t); i++) {
-               ti = dm_table_get_target(t, i);
+       for (unsigned int i = 0; i < t->num_targets; i++) {
+               struct dm_target *ti = dm_table_get_target(t, i);
 
                if (dm_target_supports_zoned_hm(ti->type)) {
                        if (!ti->type->iterate_devices ||
@@ -1620,13 +1617,11 @@ static bool dm_table_supports_zoned_model(struct dm_table *t,
 static int device_not_matches_zone_sectors(struct dm_target *ti, struct dm_dev *dev,
                                           sector_t start, sector_t len, void *data)
 {
-       struct request_queue *q = bdev_get_queue(dev->bdev);
        unsigned int *zone_sectors = data;
 
-       if (!blk_queue_is_zoned(q))
+       if (!bdev_is_zoned(dev->bdev))
                return 0;
-
-       return blk_queue_zone_sectors(q) != *zone_sectors;
+       return bdev_zone_sectors(dev->bdev) != *zone_sectors;
 }
 
 /*
@@ -1634,16 +1629,16 @@ static int device_not_matches_zone_sectors(struct dm_target *ti, struct dm_dev *
  * zone sectors, if the destination device is a zoned block device, it shall
  * have the specified zone_sectors.
  */
-static int validate_hardware_zoned_model(struct dm_table *table,
+static int validate_hardware_zoned_model(struct dm_table *t,
                                         enum blk_zoned_model zoned_model,
                                         unsigned int zone_sectors)
 {
        if (zoned_model == BLK_ZONED_NONE)
                return 0;
 
-       if (!dm_table_supports_zoned_model(table, zoned_model)) {
+       if (!dm_table_supports_zoned_model(t, zoned_model)) {
                DMERR("%s: zoned model is not consistent across all devices",
-                     dm_device_name(table->md));
+                     dm_device_name(t->md));
                return -EINVAL;
        }
 
@@ -1651,9 +1646,9 @@ static int validate_hardware_zoned_model(struct dm_table *table,
        if (!zone_sectors || !is_power_of_2(zone_sectors))
                return -EINVAL;
 
-       if (dm_table_any_dev_attr(table, device_not_matches_zone_sectors, &zone_sectors)) {
+       if (dm_table_any_dev_attr(t, device_not_matches_zone_sectors, &zone_sectors)) {
                DMERR("%s: zone sectors is not consistent across all zoned devices",
-                     dm_device_name(table->md));
+                     dm_device_name(t->md));
                return -EINVAL;
        }
 
@@ -1663,21 +1658,19 @@ static int validate_hardware_zoned_model(struct dm_table *table,
 /*
  * Establish the new table's queue_limits and validate them.
  */
-int dm_calculate_queue_limits(struct dm_table *table,
+int dm_calculate_queue_limits(struct dm_table *t,
                              struct queue_limits *limits)
 {
-       struct dm_target *ti;
        struct queue_limits ti_limits;
-       unsigned i;
        enum blk_zoned_model zoned_model = BLK_ZONED_NONE;
        unsigned int zone_sectors = 0;
 
        blk_set_stacking_limits(limits);
 
-       for (i = 0; i < dm_table_get_num_targets(table); i++) {
-               blk_set_stacking_limits(&ti_limits);
+       for (unsigned int i = 0; i < t->num_targets; i++) {
+               struct dm_target *ti = dm_table_get_target(t, i);
 
-               ti = dm_table_get_target(table, i);
+               blk_set_stacking_limits(&ti_limits);
 
                if (!ti->type->iterate_devices)
                        goto combine_limits;
@@ -1718,7 +1711,7 @@ combine_limits:
                        DMWARN("%s: adding target device "
                               "(start sect %llu len %llu) "
                               "caused an alignment inconsistency",
-                              dm_device_name(table->md),
+                              dm_device_name(t->md),
                               (unsigned long long) ti->begin,
                               (unsigned long long) ti->len);
        }
@@ -1738,10 +1731,10 @@ combine_limits:
                zoned_model = limits->zoned;
                zone_sectors = limits->chunk_sectors;
        }
-       if (validate_hardware_zoned_model(table, zoned_model, zone_sectors))
+       if (validate_hardware_zoned_model(t, zoned_model, zone_sectors))
                return -EINVAL;
 
-       return validate_hardware_logical_block_alignment(table, limits);
+       return validate_hardware_logical_block_alignment(t, limits);
 }
 
 /*
@@ -1785,17 +1778,14 @@ static int device_flush_capable(struct dm_target *ti, struct dm_dev *dev,
 
 static bool dm_table_supports_flush(struct dm_table *t, unsigned long flush)
 {
-       struct dm_target *ti;
-       unsigned i;
-
        /*
         * Require at least one underlying device to support flushes.
         * t->devices includes internal dm devices such as mirror logs
         * so we need to use iterate_devices here, which targets
         * supporting flushes must provide.
         */
-       for (i = 0; i < dm_table_get_num_targets(t); i++) {
-               ti = dm_table_get_target(t, i);
+       for (unsigned int i = 0; i < t->num_targets; i++) {
+               struct dm_target *ti = dm_table_get_target(t, i);
 
                if (!ti->num_flush_bios)
                        continue;
@@ -1849,11 +1839,8 @@ static int device_not_write_zeroes_capable(struct dm_target *ti, struct dm_dev *
 
 static bool dm_table_supports_write_zeroes(struct dm_table *t)
 {
-       struct dm_target *ti;
-       unsigned i = 0;
-
-       while (i < dm_table_get_num_targets(t)) {
-               ti = dm_table_get_target(t, i++);
+       for (unsigned int i = 0; i < t->num_targets; i++) {
+               struct dm_target *ti = dm_table_get_target(t, i);
 
                if (!ti->num_write_zeroes_bios)
                        return false;
@@ -1876,11 +1863,8 @@ static int device_not_nowait_capable(struct dm_target *ti, struct dm_dev *dev,
 
 static bool dm_table_supports_nowait(struct dm_table *t)
 {
-       struct dm_target *ti;
-       unsigned i = 0;
-
-       while (i < dm_table_get_num_targets(t)) {
-               ti = dm_table_get_target(t, i++);
+       for (unsigned int i = 0; i < t->num_targets; i++) {
+               struct dm_target *ti = dm_table_get_target(t, i);
 
                if (!dm_target_supports_nowait(ti->type))
                        return false;
@@ -1901,11 +1885,8 @@ static int device_not_discard_capable(struct dm_target *ti, struct dm_dev *dev,
 
 static bool dm_table_supports_discards(struct dm_table *t)
 {
-       struct dm_target *ti;
-       unsigned i;
-
-       for (i = 0; i < dm_table_get_num_targets(t); i++) {
-               ti = dm_table_get_target(t, i);
+       for (unsigned int i = 0; i < t->num_targets; i++) {
+               struct dm_target *ti = dm_table_get_target(t, i);
 
                if (!ti->num_discard_bios)
                        return false;
@@ -1933,11 +1914,8 @@ static int device_not_secure_erase_capable(struct dm_target *ti,
 
 static bool dm_table_supports_secure_erase(struct dm_table *t)
 {
-       struct dm_target *ti;
-       unsigned int i;
-
-       for (i = 0; i < dm_table_get_num_targets(t); i++) {
-               ti = dm_table_get_target(t, i);
+       for (unsigned int i = 0; i < t->num_targets; i++) {
+               struct dm_target *ti = dm_table_get_target(t, i);
 
                if (!ti->num_secure_erase_bios)
                        return false;
@@ -2067,11 +2045,6 @@ int dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
        return 0;
 }
 
-unsigned int dm_table_get_num_targets(struct dm_table *t)
-{
-       return t->num_targets;
-}
-
 struct list_head *dm_table_get_devices(struct dm_table *t)
 {
        return &t->devices;
@@ -2091,12 +2064,11 @@ enum suspend_mode {
 
 static void suspend_targets(struct dm_table *t, enum suspend_mode mode)
 {
-       int i = t->num_targets;
-       struct dm_target *ti = t->targets;
-
        lockdep_assert_held(&t->md->suspend_lock);
 
-       while (i--) {
+       for (unsigned int i = 0; i < t->num_targets; i++) {
+               struct dm_target *ti = dm_table_get_target(t, i);
+
                switch (mode) {
                case PRESUSPEND:
                        if (ti->type->presuspend)
@@ -2111,7 +2083,6 @@ static void suspend_targets(struct dm_table *t, enum suspend_mode mode)
                                ti->type->postsuspend(ti);
                        break;
                }
-               ti++;
        }
 }
 
@@ -2141,12 +2112,13 @@ void dm_table_postsuspend_targets(struct dm_table *t)
 
 int dm_table_resume_targets(struct dm_table *t)
 {
-       int i, r = 0;
+       unsigned int i;
+       int r = 0;
 
        lockdep_assert_held(&t->md->suspend_lock);
 
        for (i = 0; i < t->num_targets; i++) {
-               struct dm_target *ti = t->targets + i;
+               struct dm_target *ti = dm_table_get_target(t, i);
 
                if (!ti->type->preresume)
                        continue;
@@ -2160,7 +2132,7 @@ int dm_table_resume_targets(struct dm_table *t)
        }
 
        for (i = 0; i < t->num_targets; i++) {
-               struct dm_target *ti = t->targets + i;
+               struct dm_target *ti = dm_table_get_target(t, i);
 
                if (ti->type->resume)
                        ti->type->resume(ti);
index 2db7030..a27395c 100644 (file)
@@ -2045,10 +2045,13 @@ int dm_pool_register_metadata_threshold(struct dm_pool_metadata *pmd,
                                        dm_sm_threshold_fn fn,
                                        void *context)
 {
-       int r;
+       int r = -EINVAL;
 
        pmd_write_lock_in_core(pmd);
-       r = dm_sm_register_threshold_callback(pmd->metadata_sm, threshold, fn, context);
+       if (!pmd->fail_io) {
+               r = dm_sm_register_threshold_callback(pmd->metadata_sm,
+                                                     threshold, fn, context);
+       }
        pmd_write_unlock(pmd);
 
        return r;
index 84c083f..e76c96c 100644 (file)
@@ -3375,8 +3375,10 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
                                                calc_metadata_threshold(pt),
                                                metadata_low_callback,
                                                pool);
-       if (r)
+       if (r) {
+               ti->error = "Error registering metadata threshold";
                goto out_flags_changed;
+       }
 
        dm_pool_register_pre_commit_callback(pool->pmd,
                                             metadata_pre_commit_callback, pool);
diff --git a/drivers/md/dm-verity-loadpin.c b/drivers/md/dm-verity-loadpin.c
new file mode 100644 (file)
index 0000000..387ec43
--- /dev/null
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/list.h>
+#include <linux/kernel.h>
+#include <linux/dm-verity-loadpin.h>
+
+#include "dm.h"
+#include "dm-core.h"
+#include "dm-verity.h"
+
+#define DM_MSG_PREFIX  "verity-loadpin"
+
+LIST_HEAD(dm_verity_loadpin_trusted_root_digests);
+
+static bool is_trusted_verity_target(struct dm_target *ti)
+{
+       u8 *root_digest;
+       unsigned int digest_size;
+       struct dm_verity_loadpin_trusted_root_digest *trd;
+       bool trusted = false;
+
+       if (!dm_is_verity_target(ti))
+               return false;
+
+       if (dm_verity_get_root_digest(ti, &root_digest, &digest_size))
+               return false;
+
+       list_for_each_entry(trd, &dm_verity_loadpin_trusted_root_digests, node) {
+               if ((trd->len == digest_size) &&
+                   !memcmp(trd->data, root_digest, digest_size)) {
+                       trusted = true;
+                       break;
+               }
+       }
+
+       kfree(root_digest);
+
+       return trusted;
+}
+
+/*
+ * Determines whether the file system of a superblock is located on
+ * a verity device that is trusted by LoadPin.
+ */
+bool dm_verity_loadpin_is_bdev_trusted(struct block_device *bdev)
+{
+       struct mapped_device *md;
+       struct dm_table *table;
+       struct dm_target *ti;
+       int srcu_idx;
+       bool trusted = false;
+
+       if (list_empty(&dm_verity_loadpin_trusted_root_digests))
+               return false;
+
+       md = dm_get_md(bdev->bd_dev);
+       if (!md)
+               return false;
+
+       table = dm_get_live_table(md, &srcu_idx);
+
+       if (table->num_targets != 1)
+               goto out;
+
+       ti = dm_table_get_target(table, 0);
+
+       if (is_trusted_verity_target(ti))
+               trusted = true;
+
+out:
+       dm_put_live_table(md, srcu_idx);
+       dm_put(md);
+
+       return trusted;
+}
index d6dbd47..4fd853a 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/reboot.h>
 #include <linux/scatterlist.h>
+#include <linux/string.h>
 
 #define DM_MSG_PREFIX                  "verity"
 
@@ -527,11 +528,10 @@ static int verity_verify_io(struct dm_verity_io *io)
                        if (v->validated_blocks)
                                set_bit(cur_block, v->validated_blocks);
                        continue;
-               }
-               else if (verity_fec_decode(v, io, DM_VERITY_BLOCK_TYPE_DATA,
-                                          cur_block, NULL, &start) == 0)
+               } else if (verity_fec_decode(v, io, DM_VERITY_BLOCK_TYPE_DATA,
+                                          cur_block, NULL, &start) == 0) {
                        continue;
-               else {
+               else {
                        if (bio->bi_status) {
                                /*
                                 * Error correction failed; Just return error
@@ -1310,10 +1310,40 @@ bad:
        return r;
 }
 
+/*
+ * Check whether a DM target is a verity target.
+ */
+bool dm_is_verity_target(struct dm_target *ti)
+{
+       return ti->type->module == THIS_MODULE;
+}
+
+/*
+ * Get the root digest of a verity target.
+ *
+ * Returns a copy of the root digest, the caller is responsible for
+ * freeing the memory of the digest.
+ */
+int dm_verity_get_root_digest(struct dm_target *ti, u8 **root_digest, unsigned int *digest_size)
+{
+       struct dm_verity *v = ti->private;
+
+       if (!dm_is_verity_target(ti))
+               return -EINVAL;
+
+       *root_digest = kmemdup(v->root_digest, v->digest_size, GFP_KERNEL);
+       if (*root_digest == NULL)
+               return -ENOMEM;
+
+       *digest_size = v->digest_size;
+
+       return 0;
+}
+
 static struct target_type verity_target = {
        .name           = "verity",
        .features       = DM_TARGET_IMMUTABLE,
-       .version        = {1, 8, 0},
+       .version        = {1, 8, 1},
        .module         = THIS_MODULE,
        .ctr            = verity_ctr,
        .dtr            = verity_dtr,
index 4e769d1..c832cc3 100644 (file)
@@ -129,4 +129,8 @@ extern int verity_hash(struct dm_verity *v, struct ahash_request *req,
 extern int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io,
                                 sector_t block, u8 *digest, bool *is_zero);
 
+extern bool dm_is_verity_target(struct dm_target *ti);
+extern int dm_verity_get_root_digest(struct dm_target *ti, u8 **root_digest,
+                                    unsigned int *digest_size);
+
 #endif /* DM_VERITY_H */
index d74c5a7..1fc161d 100644 (file)
@@ -22,7 +22,7 @@
 
 #define HIGH_WATERMARK                 50
 #define LOW_WATERMARK                  45
-#define MAX_WRITEBACK_JOBS             0
+#define MAX_WRITEBACK_JOBS             min(0x10000000 / PAGE_SIZE, totalram_pages() / 16)
 #define ENDIO_LATENCY                  16
 #define WRITEBACK_LATENCY              64
 #define AUTOCOMMIT_BLOCKS_SSD          65536
@@ -523,8 +523,7 @@ static void ssd_commit_flushed(struct dm_writecache *wc, bool wait_for_ios)
 
                region.sector += wc->start_sector;
                atomic_inc(&endio.count);
-               req.bi_op = REQ_OP_WRITE;
-               req.bi_op_flags = REQ_SYNC;
+               req.bi_opf = REQ_OP_WRITE | REQ_SYNC;
                req.mem.type = DM_IO_VMA;
                req.mem.ptr.vma = (char *)wc->memory_map + (size_t)i * BITMAP_GRANULARITY;
                req.client = wc->dm_io;
@@ -562,8 +561,7 @@ static void ssd_commit_superblock(struct dm_writecache *wc)
 
        region.sector += wc->start_sector;
 
-       req.bi_op = REQ_OP_WRITE;
-       req.bi_op_flags = REQ_SYNC | REQ_FUA;
+       req.bi_opf = REQ_OP_WRITE | REQ_SYNC | REQ_FUA;
        req.mem.type = DM_IO_VMA;
        req.mem.ptr.vma = (char *)wc->memory_map;
        req.client = wc->dm_io;
@@ -592,8 +590,7 @@ static void writecache_disk_flush(struct dm_writecache *wc, struct dm_dev *dev)
        region.bdev = dev->bdev;
        region.sector = 0;
        region.count = 0;
-       req.bi_op = REQ_OP_WRITE;
-       req.bi_op_flags = REQ_PREFLUSH;
+       req.bi_opf = REQ_OP_WRITE | REQ_PREFLUSH;
        req.mem.type = DM_IO_KMEM;
        req.mem.ptr.addr = NULL;
        req.client = wc->dm_io;
@@ -981,8 +978,7 @@ static int writecache_read_metadata(struct dm_writecache *wc, sector_t n_sectors
        region.bdev = wc->ssd_dev->bdev;
        region.sector = wc->start_sector;
        region.count = n_sectors;
-       req.bi_op = REQ_OP_READ;
-       req.bi_op_flags = REQ_SYNC;
+       req.bi_opf = REQ_OP_READ | REQ_SYNC;
        req.mem.type = DM_IO_VMA;
        req.mem.ptr.vma = (char *)wc->memory_map;
        req.client = wc->dm_io;
@@ -1329,8 +1325,8 @@ enum wc_map_op {
        WC_MAP_ERROR,
 };
 
-static enum wc_map_op writecache_map_remap_origin(struct dm_writecache *wc, struct bio *bio,
-                                                 struct wc_entry *e)
+static void writecache_map_remap_origin(struct dm_writecache *wc, struct bio *bio,
+                                       struct wc_entry *e)
 {
        if (e) {
                sector_t next_boundary =
@@ -1338,8 +1334,6 @@ static enum wc_map_op writecache_map_remap_origin(struct dm_writecache *wc, stru
                if (next_boundary < bio->bi_iter.bi_size >> SECTOR_SHIFT)
                        dm_accept_partial_bio(bio, next_boundary);
        }
-
-       return WC_MAP_REMAP_ORIGIN;
 }
 
 static enum wc_map_op writecache_map_read(struct dm_writecache *wc, struct bio *bio)
@@ -1366,14 +1360,16 @@ read_next_block:
                        map_op = WC_MAP_REMAP;
                }
        } else {
-               map_op = writecache_map_remap_origin(wc, bio, e);
+               writecache_map_remap_origin(wc, bio, e);
+               wc->stats.reads += (bio->bi_iter.bi_size - wc->block_size) >> wc->block_size_bits;
+               map_op = WC_MAP_REMAP_ORIGIN;
        }
 
        return map_op;
 }
 
-static enum wc_map_op writecache_bio_copy_ssd(struct dm_writecache *wc, struct bio *bio,
-                                             struct wc_entry *e, bool search_used)
+static void writecache_bio_copy_ssd(struct dm_writecache *wc, struct bio *bio,
+                                   struct wc_entry *e, bool search_used)
 {
        unsigned bio_size = wc->block_size;
        sector_t start_cache_sec = cache_sector(wc, e);
@@ -1413,14 +1409,15 @@ static enum wc_map_op writecache_bio_copy_ssd(struct dm_writecache *wc, struct b
        bio->bi_iter.bi_sector = start_cache_sec;
        dm_accept_partial_bio(bio, bio_size >> SECTOR_SHIFT);
 
+       wc->stats.writes += bio->bi_iter.bi_size >> wc->block_size_bits;
+       wc->stats.writes_allocate += (bio->bi_iter.bi_size - wc->block_size) >> wc->block_size_bits;
+
        if (unlikely(wc->uncommitted_blocks >= wc->autocommit_blocks)) {
                wc->uncommitted_blocks = 0;
                queue_work(wc->writeback_wq, &wc->flush_work);
        } else {
                writecache_schedule_autocommit(wc);
        }
-
-       return WC_MAP_REMAP;
 }
 
 static enum wc_map_op writecache_map_write(struct dm_writecache *wc, struct bio *bio)
@@ -1430,9 +1427,10 @@ static enum wc_map_op writecache_map_write(struct dm_writecache *wc, struct bio
        do {
                bool found_entry = false;
                bool search_used = false;
-               wc->stats.writes++;
-               if (writecache_has_error(wc))
+               if (writecache_has_error(wc)) {
+                       wc->stats.writes += bio->bi_iter.bi_size >> wc->block_size_bits;
                        return WC_MAP_ERROR;
+               }
                e = writecache_find_entry(wc, bio->bi_iter.bi_sector, 0);
                if (e) {
                        if (!writecache_entry_is_committed(wc, e)) {
@@ -1456,9 +1454,11 @@ static enum wc_map_op writecache_map_write(struct dm_writecache *wc, struct bio
                if (unlikely(!e)) {
                        if (!WC_MODE_PMEM(wc) && !found_entry) {
 direct_write:
-                               wc->stats.writes_around++;
                                e = writecache_find_entry(wc, bio->bi_iter.bi_sector, WFE_RETURN_FOLLOWING);
-                               return writecache_map_remap_origin(wc, bio, e);
+                               writecache_map_remap_origin(wc, bio, e);
+                               wc->stats.writes_around += bio->bi_iter.bi_size >> wc->block_size_bits;
+                               wc->stats.writes += bio->bi_iter.bi_size >> wc->block_size_bits;
+                               return WC_MAP_REMAP_ORIGIN;
                        }
                        wc->stats.writes_blocked_on_freelist++;
                        writecache_wait_on_freelist(wc);
@@ -1469,10 +1469,13 @@ direct_write:
                wc->uncommitted_blocks++;
                wc->stats.writes_allocate++;
 bio_copy:
-               if (WC_MODE_PMEM(wc))
+               if (WC_MODE_PMEM(wc)) {
                        bio_copy_block(wc, bio, memory_data(wc, e));
-               else
-                       return writecache_bio_copy_ssd(wc, bio, e, search_used);
+                       wc->stats.writes++;
+               } else {
+                       writecache_bio_copy_ssd(wc, bio, e, search_used);
+                       return WC_MAP_REMAP;
+               }
        } while (bio->bi_iter.bi_size);
 
        if (unlikely(bio->bi_opf & REQ_FUA || wc->uncommitted_blocks >= wc->autocommit_blocks))
@@ -1507,7 +1510,7 @@ static enum wc_map_op writecache_map_flush(struct dm_writecache *wc, struct bio
 
 static enum wc_map_op writecache_map_discard(struct dm_writecache *wc, struct bio *bio)
 {
-       wc->stats.discards++;
+       wc->stats.discards += bio->bi_iter.bi_size >> wc->block_size_bits;
 
        if (writecache_has_error(wc))
                return WC_MAP_ERROR;
index 3e7b1fe..3dafc0e 100644 (file)
@@ -139,13 +139,11 @@ bool dm_is_zone_write(struct mapped_device *md, struct bio *bio)
 
 void dm_cleanup_zoned_dev(struct mapped_device *md)
 {
-       struct request_queue *q = md->queue;
-
-       if (q) {
-               kfree(q->conv_zones_bitmap);
-               q->conv_zones_bitmap = NULL;
-               kfree(q->seq_zones_wlock);
-               q->seq_zones_wlock = NULL;
+       if (md->disk) {
+               kfree(md->disk->conv_zones_bitmap);
+               md->disk->conv_zones_bitmap = NULL;
+               kfree(md->disk->seq_zones_wlock);
+               md->disk->seq_zones_wlock = NULL;
        }
 
        kvfree(md->zwp_offset);
@@ -179,31 +177,31 @@ static int dm_zone_revalidate_cb(struct blk_zone *zone, unsigned int idx,
                                 void *data)
 {
        struct mapped_device *md = data;
-       struct request_queue *q = md->queue;
+       struct gendisk *disk = md->disk;
 
        switch (zone->type) {
        case BLK_ZONE_TYPE_CONVENTIONAL:
-               if (!q->conv_zones_bitmap) {
-                       q->conv_zones_bitmap =
-                               kcalloc(BITS_TO_LONGS(q->nr_zones),
+               if (!disk->conv_zones_bitmap) {
+                       disk->conv_zones_bitmap =
+                               kcalloc(BITS_TO_LONGS(disk->nr_zones),
                                        sizeof(unsigned long), GFP_NOIO);
-                       if (!q->conv_zones_bitmap)
+                       if (!disk->conv_zones_bitmap)
                                return -ENOMEM;
                }
-               set_bit(idx, q->conv_zones_bitmap);
+               set_bit(idx, disk->conv_zones_bitmap);
                break;
        case BLK_ZONE_TYPE_SEQWRITE_REQ:
        case BLK_ZONE_TYPE_SEQWRITE_PREF:
-               if (!q->seq_zones_wlock) {
-                       q->seq_zones_wlock =
-                               kcalloc(BITS_TO_LONGS(q->nr_zones),
+               if (!disk->seq_zones_wlock) {
+                       disk->seq_zones_wlock =
+                               kcalloc(BITS_TO_LONGS(disk->nr_zones),
                                        sizeof(unsigned long), GFP_NOIO);
-                       if (!q->seq_zones_wlock)
+                       if (!disk->seq_zones_wlock)
                                return -ENOMEM;
                }
                if (!md->zwp_offset) {
                        md->zwp_offset =
-                               kvcalloc(q->nr_zones, sizeof(unsigned int),
+                               kvcalloc(disk->nr_zones, sizeof(unsigned int),
                                         GFP_KERNEL);
                        if (!md->zwp_offset)
                                return -ENOMEM;
@@ -228,7 +226,7 @@ static int dm_zone_revalidate_cb(struct blk_zone *zone, unsigned int idx,
  */
 static int dm_revalidate_zones(struct mapped_device *md, struct dm_table *t)
 {
-       struct request_queue *q = md->queue;
+       struct gendisk *disk = md->disk;
        unsigned int noio_flag;
        int ret;
 
@@ -236,7 +234,7 @@ static int dm_revalidate_zones(struct mapped_device *md, struct dm_table *t)
         * Check if something changed. If yes, cleanup the current resources
         * and reallocate everything.
         */
-       if (!q->nr_zones || q->nr_zones != md->nr_zones)
+       if (!disk->nr_zones || disk->nr_zones != md->nr_zones)
                dm_cleanup_zoned_dev(md);
        if (md->nr_zones)
                return 0;
@@ -246,17 +244,17 @@ static int dm_revalidate_zones(struct mapped_device *md, struct dm_table *t)
         * operations in this context are done as if GFP_NOIO was specified.
         */
        noio_flag = memalloc_noio_save();
-       ret = dm_blk_do_report_zones(md, t, 0, q->nr_zones,
+       ret = dm_blk_do_report_zones(md, t, 0, disk->nr_zones,
                                     dm_zone_revalidate_cb, md);
        memalloc_noio_restore(noio_flag);
        if (ret < 0)
                goto err;
-       if (ret != q->nr_zones) {
+       if (ret != disk->nr_zones) {
                ret = -EIO;
                goto err;
        }
 
-       md->nr_zones = q->nr_zones;
+       md->nr_zones = disk->nr_zones;
 
        return 0;
 
@@ -270,16 +268,13 @@ static int device_not_zone_append_capable(struct dm_target *ti,
                                          struct dm_dev *dev, sector_t start,
                                          sector_t len, void *data)
 {
-       return !blk_queue_is_zoned(bdev_get_queue(dev->bdev));
+       return !bdev_is_zoned(dev->bdev);
 }
 
 static bool dm_table_supports_zone_append(struct dm_table *t)
 {
-       struct dm_target *ti;
-       unsigned int i;
-
-       for (i = 0; i < dm_table_get_num_targets(t); i++) {
-               ti = dm_table_get_target(t, i);
+       for (unsigned int i = 0; i < t->num_targets; i++) {
+               struct dm_target *ti = dm_table_get_target(t, i);
 
                if (ti->emulate_zone_append)
                        return false;
@@ -301,7 +296,7 @@ int dm_set_zones_restrictions(struct dm_table *t, struct request_queue *q)
         * correct value to be exposed in sysfs queue/nr_zones.
         */
        WARN_ON_ONCE(queue_is_mq(q));
-       q->nr_zones = blkdev_nr_zones(md->disk);
+       md->disk->nr_zones = bdev_nr_zones(md->disk->part0);
 
        /* Check if zone append is natively supported */
        if (dm_table_supports_zone_append(t)) {
@@ -334,7 +329,7 @@ static int dm_update_zone_wp_offset_cb(struct blk_zone *zone, unsigned int idx,
 static int dm_update_zone_wp_offset(struct mapped_device *md, unsigned int zno,
                                    unsigned int *wp_ofst)
 {
-       sector_t sector = zno * blk_queue_zone_sectors(md->queue);
+       sector_t sector = zno * bdev_zone_sectors(md->disk->part0);
        unsigned int noio_flag;
        struct dm_table *t;
        int srcu_idx, ret;
@@ -361,7 +356,7 @@ static int dm_update_zone_wp_offset(struct mapped_device *md, unsigned int zno,
 }
 
 struct orig_bio_details {
-       unsigned int op;
+       enum req_op op;
        unsigned int nr_sectors;
 };
 
@@ -373,7 +368,7 @@ struct orig_bio_details {
 static bool dm_zone_map_bio_begin(struct mapped_device *md,
                                  unsigned int zno, struct bio *clone)
 {
-       sector_t zsectors = blk_queue_zone_sectors(md->queue);
+       sector_t zsectors = bdev_zone_sectors(md->disk->part0);
        unsigned int zwp_offset = READ_ONCE(md->zwp_offset[zno]);
 
        /*
@@ -443,7 +438,7 @@ static blk_status_t dm_zone_map_bio_end(struct mapped_device *md, unsigned int z
                return BLK_STS_OK;
        case REQ_OP_ZONE_FINISH:
                WRITE_ONCE(md->zwp_offset[zno],
-                          blk_queue_zone_sectors(md->queue));
+                          bdev_zone_sectors(md->disk->part0));
                return BLK_STS_OK;
        case REQ_OP_WRITE_ZEROES:
        case REQ_OP_WRITE:
@@ -466,26 +461,26 @@ static blk_status_t dm_zone_map_bio_end(struct mapped_device *md, unsigned int z
        }
 }
 
-static inline void dm_zone_lock(struct request_queue *q,
-                               unsigned int zno, struct bio *clone)
+static inline void dm_zone_lock(struct gendisk *disk, unsigned int zno,
+                               struct bio *clone)
 {
        if (WARN_ON_ONCE(bio_flagged(clone, BIO_ZONE_WRITE_LOCKED)))
                return;
 
-       wait_on_bit_lock_io(q->seq_zones_wlock, zno, TASK_UNINTERRUPTIBLE);
+       wait_on_bit_lock_io(disk->seq_zones_wlock, zno, TASK_UNINTERRUPTIBLE);
        bio_set_flag(clone, BIO_ZONE_WRITE_LOCKED);
 }
 
-static inline void dm_zone_unlock(struct request_queue *q,
-                                 unsigned int zno, struct bio *clone)
+static inline void dm_zone_unlock(struct gendisk *disk, unsigned int zno,
+                                 struct bio *clone)
 {
        if (!bio_flagged(clone, BIO_ZONE_WRITE_LOCKED))
                return;
 
-       WARN_ON_ONCE(!test_bit(zno, q->seq_zones_wlock));
-       clear_bit_unlock(zno, q->seq_zones_wlock);
+       WARN_ON_ONCE(!test_bit(zno, disk->seq_zones_wlock));
+       clear_bit_unlock(zno, disk->seq_zones_wlock);
        smp_mb__after_atomic();
-       wake_up_bit(q->seq_zones_wlock, zno);
+       wake_up_bit(disk->seq_zones_wlock, zno);
 
        bio_clear_flag(clone, BIO_ZONE_WRITE_LOCKED);
 }
@@ -520,7 +515,6 @@ int dm_zone_map_bio(struct dm_target_io *tio)
        struct dm_io *io = tio->io;
        struct dm_target *ti = tio->ti;
        struct mapped_device *md = io->md;
-       struct request_queue *q = md->queue;
        struct bio *clone = &tio->clone;
        struct orig_bio_details orig_bio_details;
        unsigned int zno;
@@ -536,7 +530,7 @@ int dm_zone_map_bio(struct dm_target_io *tio)
 
        /* Lock the target zone */
        zno = bio_zone_no(clone);
-       dm_zone_lock(q, zno, clone);
+       dm_zone_lock(md->disk, zno, clone);
 
        orig_bio_details.nr_sectors = bio_sectors(clone);
        orig_bio_details.op = bio_op(clone);
@@ -546,7 +540,7 @@ int dm_zone_map_bio(struct dm_target_io *tio)
         * both valid, and if the bio is a zone append, remap it to a write.
         */
        if (!dm_zone_map_bio_begin(md, zno, clone)) {
-               dm_zone_unlock(q, zno, clone);
+               dm_zone_unlock(md->disk, zno, clone);
                return DM_MAPIO_KILL;
        }
 
@@ -570,12 +564,12 @@ int dm_zone_map_bio(struct dm_target_io *tio)
                sts = dm_zone_map_bio_end(md, zno, &orig_bio_details,
                                          *tio->len_ptr);
                if (sts != BLK_STS_OK)
-                       dm_zone_unlock(q, zno, clone);
+                       dm_zone_unlock(md->disk, zno, clone);
                break;
        case DM_MAPIO_REQUEUE:
        case DM_MAPIO_KILL:
        default:
-               dm_zone_unlock(q, zno, clone);
+               dm_zone_unlock(md->disk, zno, clone);
                sts = BLK_STS_IOERR;
                break;
        }
@@ -592,7 +586,7 @@ int dm_zone_map_bio(struct dm_target_io *tio)
 void dm_zone_endio(struct dm_io *io, struct bio *clone)
 {
        struct mapped_device *md = io->md;
-       struct request_queue *q = md->queue;
+       struct gendisk *disk = md->disk;
        struct bio *orig_bio = io->orig_bio;
        unsigned int zwp_offset;
        unsigned int zno;
@@ -608,7 +602,8 @@ void dm_zone_endio(struct dm_io *io, struct bio *clone)
                 */
                if (clone->bi_status == BLK_STS_OK &&
                    bio_op(clone) == REQ_OP_ZONE_APPEND) {
-                       sector_t mask = (sector_t)blk_queue_zone_sectors(q) - 1;
+                       sector_t mask =
+                               (sector_t)bdev_zone_sectors(disk->part0) - 1;
 
                        orig_bio->bi_iter.bi_sector +=
                                clone->bi_iter.bi_sector & mask;
@@ -649,5 +644,5 @@ void dm_zone_endio(struct dm_io *io, struct bio *clone)
                                zwp_offset - bio_sectors(orig_bio);
        }
 
-       dm_zone_unlock(q, zno, clone);
+       dm_zone_unlock(disk, zno, clone);
 }
index d1ea661..34db364 100644 (file)
@@ -737,7 +737,7 @@ static int dmz_write_mblock(struct dmz_metadata *zmd, struct dmz_mblock *mblk,
 /*
  * Read/write a metadata block.
  */
-static int dmz_rdwr_block(struct dmz_dev *dev, int op,
+static int dmz_rdwr_block(struct dmz_dev *dev, enum req_op op,
                          sector_t block, struct page *page)
 {
        struct bio *bio;
@@ -2045,7 +2045,8 @@ struct dm_zone *dmz_get_zone_for_reclaim(struct dmz_metadata *zmd,
  * allocated and used to map the chunk.
  * The zone returned will be set to the active state.
  */
-struct dm_zone *dmz_get_chunk_mapping(struct dmz_metadata *zmd, unsigned int chunk, int op)
+struct dm_zone *dmz_get_chunk_mapping(struct dmz_metadata *zmd,
+                                     unsigned int chunk, enum req_op op)
 {
        struct dmz_mblock *dmap_mblk = zmd->map_mblk[chunk >> DMZ_MAP_ENTRIES_SHIFT];
        struct dmz_map *dmap = (struct dmz_map *) dmap_mblk->data;
index 0ec5d8b..95b132b 100644 (file)
@@ -764,8 +764,7 @@ static void dmz_put_zoned_device(struct dm_target *ti)
 static int dmz_fixup_devices(struct dm_target *ti)
 {
        struct dmz_target *dmz = ti->private;
-       struct dmz_dev *reg_dev, *zoned_dev;
-       struct request_queue *q;
+       struct dmz_dev *reg_dev = NULL;
        sector_t zone_nr_sectors = 0;
        int i;
 
@@ -780,32 +779,32 @@ static int dmz_fixup_devices(struct dm_target *ti)
                        return -EINVAL;
                }
                for (i = 1; i < dmz->nr_ddevs; i++) {
-                       zoned_dev = &dmz->dev[i];
+                       struct dmz_dev *zoned_dev = &dmz->dev[i];
+                       struct block_device *bdev = zoned_dev->bdev;
+
                        if (zoned_dev->flags & DMZ_BDEV_REGULAR) {
                                ti->error = "Secondary disk is not a zoned device";
                                return -EINVAL;
                        }
-                       q = bdev_get_queue(zoned_dev->bdev);
                        if (zone_nr_sectors &&
-                           zone_nr_sectors != blk_queue_zone_sectors(q)) {
+                           zone_nr_sectors != bdev_zone_sectors(bdev)) {
                                ti->error = "Zone nr sectors mismatch";
                                return -EINVAL;
                        }
-                       zone_nr_sectors = blk_queue_zone_sectors(q);
+                       zone_nr_sectors = bdev_zone_sectors(bdev);
                        zoned_dev->zone_nr_sectors = zone_nr_sectors;
-                       zoned_dev->nr_zones =
-                               blkdev_nr_zones(zoned_dev->bdev->bd_disk);
+                       zoned_dev->nr_zones = bdev_nr_zones(bdev);
                }
        } else {
-               reg_dev = NULL;
-               zoned_dev = &dmz->dev[0];
+               struct dmz_dev *zoned_dev = &dmz->dev[0];
+               struct block_device *bdev = zoned_dev->bdev;
+
                if (zoned_dev->flags & DMZ_BDEV_REGULAR) {
                        ti->error = "Disk is not a zoned device";
                        return -EINVAL;
                }
-               q = bdev_get_queue(zoned_dev->bdev);
-               zoned_dev->zone_nr_sectors = blk_queue_zone_sectors(q);
-               zoned_dev->nr_zones = blkdev_nr_zones(zoned_dev->bdev->bd_disk);
+               zoned_dev->zone_nr_sectors = bdev_zone_sectors(bdev);
+               zoned_dev->nr_zones = bdev_nr_zones(bdev);
        }
 
        if (reg_dev) {
index a02744a..265494d 100644 (file)
@@ -248,7 +248,7 @@ struct dm_zone *dmz_get_zone_for_reclaim(struct dmz_metadata *zmd,
                                         unsigned int dev_idx, bool idle);
 
 struct dm_zone *dmz_get_chunk_mapping(struct dmz_metadata *zmd,
-                                     unsigned int chunk, int op);
+                                     unsigned int chunk, enum req_op op);
 void dmz_put_chunk_mapping(struct dmz_metadata *zmd, struct dm_zone *zone);
 struct dm_zone *dmz_get_chunk_buffer(struct dmz_metadata *zmd,
                                     struct dm_zone *dzone);
index 2b75f1e..99642f6 100644 (file)
@@ -88,10 +88,6 @@ struct clone_info {
        bool submit_as_polled:1;
 };
 
-#define DM_TARGET_IO_BIO_OFFSET (offsetof(struct dm_target_io, clone))
-#define DM_IO_BIO_OFFSET \
-       (offsetof(struct dm_target_io, clone) + offsetof(struct dm_io, tio))
-
 static inline struct dm_target_io *clone_to_tio(struct bio *clone)
 {
        return container_of(clone, struct dm_target_io, clone);
@@ -415,7 +411,7 @@ static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 static int dm_prepare_ioctl(struct mapped_device *md, int *srcu_idx,
                            struct block_device **bdev)
 {
-       struct dm_target *tgt;
+       struct dm_target *ti;
        struct dm_table *map;
        int r;
 
@@ -426,17 +422,17 @@ retry:
                return r;
 
        /* We only support devices that have a single target */
-       if (dm_table_get_num_targets(map) != 1)
+       if (map->num_targets != 1)
                return r;
 
-       tgt = dm_table_get_target(map, 0);
-       if (!tgt->type->prepare_ioctl)
+       ti = dm_table_get_target(map, 0);
+       if (!ti->type->prepare_ioctl)
                return r;
 
        if (dm_suspended_md(md))
                return -EAGAIN;
 
-       r = tgt->type->prepare_ioctl(tgt, bdev);
+       r = ti->type->prepare_ioctl(ti, bdev);
        if (r == -ENOTCONN && !fatal_signal_pending(current)) {
                dm_put_live_table(md, *srcu_idx);
                msleep(10);
@@ -578,9 +574,6 @@ static struct dm_io *alloc_io(struct mapped_device *md, struct bio *bio)
        struct bio *clone;
 
        clone = bio_alloc_clone(NULL, bio, GFP_NOIO, &md->mempools->io_bs);
-       /* Set default bdev, but target must bio_set_dev() before issuing IO */
-       clone->bi_bdev = md->disk->part0;
-
        tio = clone_to_tio(clone);
        tio->flags = 0;
        dm_tio_set_flag(tio, DM_TIO_INSIDE_DM_IO);
@@ -594,7 +587,6 @@ static struct dm_io *alloc_io(struct mapped_device *md, struct bio *bio)
        atomic_set(&io->io_count, 2);
        this_cpu_inc(*md->pending_io);
        io->orig_bio = bio;
-       io->split_bio = NULL;
        io->md = md;
        spin_lock_init(&io->lock);
        io->start_time = jiffies;
@@ -614,6 +606,7 @@ static void free_io(struct dm_io *io)
 static struct bio *alloc_tio(struct clone_info *ci, struct dm_target *ti,
                             unsigned target_bio_nr, unsigned *len, gfp_t gfp_mask)
 {
+       struct mapped_device *md = ci->io->md;
        struct dm_target_io *tio;
        struct bio *clone;
 
@@ -623,14 +616,10 @@ static struct bio *alloc_tio(struct clone_info *ci, struct dm_target *ti,
                /* alloc_io() already initialized embedded clone */
                clone = &tio->clone;
        } else {
-               struct mapped_device *md = ci->io->md;
-
                clone = bio_alloc_clone(NULL, ci->bio, gfp_mask,
                                        &md->mempools->bs);
                if (!clone)
                        return NULL;
-               /* Set default bdev, but target must bio_set_dev() before issuing IO */
-               clone->bi_bdev = md->disk->part0;
 
                /* REQ_DM_POLL_LIST shouldn't be inherited */
                clone->bi_opf &= ~REQ_DM_POLL_LIST;
@@ -646,6 +635,11 @@ static struct bio *alloc_tio(struct clone_info *ci, struct dm_target *ti,
        tio->len_ptr = len;
        tio->old_sector = 0;
 
+       /* Set default bdev, but target must bio_set_dev() before issuing IO */
+       clone->bi_bdev = md->disk->part0;
+       if (unlikely(ti->needs_bio_set_dev))
+               bio_set_dev(clone, md->disk->part0);
+
        if (len) {
                clone->bi_iter.bi_size = to_bytes(*len);
                if (bio_integrity(clone))
@@ -716,7 +710,7 @@ static void dm_put_live_table_fast(struct mapped_device *md) __releases(RCU)
 }
 
 static inline struct dm_table *dm_get_live_table_bio(struct mapped_device *md,
-                                                    int *srcu_idx, unsigned bio_opf)
+                                       int *srcu_idx, blk_opf_t bio_opf)
 {
        if (bio_opf & REQ_NOWAIT)
                return dm_get_live_table_fast(md);
@@ -725,7 +719,7 @@ static inline struct dm_table *dm_get_live_table_bio(struct mapped_device *md,
 }
 
 static inline void dm_put_live_table_bio(struct mapped_device *md, int srcu_idx,
-                                        unsigned bio_opf)
+                                        blk_opf_t bio_opf)
 {
        if (bio_opf & REQ_NOWAIT)
                dm_put_live_table_fast(md);
@@ -884,22 +878,63 @@ static int __noflush_suspending(struct mapped_device *md)
        return test_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);
 }
 
-static void dm_io_complete(struct dm_io *io)
+static void dm_requeue_add_io(struct dm_io *io, bool first_stage)
 {
-       blk_status_t io_error;
        struct mapped_device *md = io->md;
-       struct bio *bio = io->split_bio ? io->split_bio : io->orig_bio;
 
-       if (io->status == BLK_STS_DM_REQUEUE) {
+       if (first_stage) {
+               struct dm_io *next = md->requeue_list;
+
+               md->requeue_list = io;
+               io->next = next;
+       } else {
+               bio_list_add_head(&md->deferred, io->orig_bio);
+       }
+}
+
+static void dm_kick_requeue(struct mapped_device *md, bool first_stage)
+{
+       if (first_stage)
+               queue_work(md->wq, &md->requeue_work);
+       else
+               queue_work(md->wq, &md->work);
+}
+
+/*
+ * Return true if the dm_io's original bio is requeued.
+ * io->status is updated with error if requeue disallowed.
+ */
+static bool dm_handle_requeue(struct dm_io *io, bool first_stage)
+{
+       struct bio *bio = io->orig_bio;
+       bool handle_requeue = (io->status == BLK_STS_DM_REQUEUE);
+       bool handle_polled_eagain = ((io->status == BLK_STS_AGAIN) &&
+                                    (bio->bi_opf & REQ_POLLED));
+       struct mapped_device *md = io->md;
+       bool requeued = false;
+
+       if (handle_requeue || handle_polled_eagain) {
                unsigned long flags;
+
+               if (bio->bi_opf & REQ_POLLED) {
+                       /*
+                        * Upper layer won't help us poll split bio
+                        * (io->orig_bio may only reflect a subset of the
+                        * pre-split original) so clear REQ_POLLED.
+                        */
+                       bio_clear_polled(bio);
+               }
+
                /*
-                * Target requested pushing back the I/O.
+                * Target requested pushing back the I/O or
+                * polled IO hit BLK_STS_AGAIN.
                 */
                spin_lock_irqsave(&md->deferred_lock, flags);
-               if (__noflush_suspending(md) &&
-                   !WARN_ON_ONCE(dm_is_zone_write(md, bio))) {
-                       /* NOTE early return due to BLK_STS_DM_REQUEUE below */
-                       bio_list_add_head(&md->deferred, bio);
+               if ((__noflush_suspending(md) &&
+                    !WARN_ON_ONCE(dm_is_zone_write(md, bio))) ||
+                   handle_polled_eagain || first_stage) {
+                       dm_requeue_add_io(io, first_stage);
+                       requeued = true;
                } else {
                        /*
                         * noflush suspend was interrupted or this is
@@ -910,6 +945,23 @@ static void dm_io_complete(struct dm_io *io)
                spin_unlock_irqrestore(&md->deferred_lock, flags);
        }
 
+       if (requeued)
+               dm_kick_requeue(md, first_stage);
+
+       return requeued;
+}
+
+static void __dm_io_complete(struct dm_io *io, bool first_stage)
+{
+       struct bio *bio = io->orig_bio;
+       struct mapped_device *md = io->md;
+       blk_status_t io_error;
+       bool requeued;
+
+       requeued = dm_handle_requeue(io, first_stage);
+       if (requeued && first_stage)
+               return;
+
        io_error = io->status;
        if (dm_io_flagged(io, DM_IO_ACCOUNTED))
                dm_end_io_acct(io);
@@ -929,23 +981,9 @@ static void dm_io_complete(struct dm_io *io)
        if (unlikely(wq_has_sleeper(&md->wait)))
                wake_up(&md->wait);
 
-       if (io_error == BLK_STS_DM_REQUEUE || io_error == BLK_STS_AGAIN) {
-               if (bio->bi_opf & REQ_POLLED) {
-                       /*
-                        * Upper layer won't help us poll split bio (io->orig_bio
-                        * may only reflect a subset of the pre-split original)
-                        * so clear REQ_POLLED in case of requeue.
-                        */
-                       bio_clear_polled(bio);
-                       if (io_error == BLK_STS_AGAIN) {
-                               /* io_uring doesn't handle BLK_STS_AGAIN (yet) */
-                               queue_io(md, bio);
-                               return;
-                       }
-               }
-               if (io_error == BLK_STS_DM_REQUEUE)
-                       return;
-       }
+       /* Return early if the original bio was requeued */
+       if (requeued)
+               return;
 
        if (bio_is_flush_with_data(bio)) {
                /*
@@ -962,6 +1000,58 @@ static void dm_io_complete(struct dm_io *io)
        }
 }
 
+static void dm_wq_requeue_work(struct work_struct *work)
+{
+       struct mapped_device *md = container_of(work, struct mapped_device,
+                                               requeue_work);
+       unsigned long flags;
+       struct dm_io *io;
+
+       /* reuse deferred lock to simplify dm_handle_requeue */
+       spin_lock_irqsave(&md->deferred_lock, flags);
+       io = md->requeue_list;
+       md->requeue_list = NULL;
+       spin_unlock_irqrestore(&md->deferred_lock, flags);
+
+       while (io) {
+               struct dm_io *next = io->next;
+
+               dm_io_rewind(io, &md->queue->bio_split);
+
+               io->next = NULL;
+               __dm_io_complete(io, false);
+               io = next;
+       }
+}
+
+/*
+ * Two staged requeue:
+ *
+ * 1) io->orig_bio points to the real original bio, and the part mapped to
+ *    this io must be requeued, instead of other parts of the original bio.
+ *
+ * 2) io->orig_bio points to new cloned bio which matches the requeued dm_io.
+ */
+static void dm_io_complete(struct dm_io *io)
+{
+       bool first_requeue;
+
+       /*
+        * Only dm_io that has been split needs two stage requeue, otherwise
+        * we may run into long bio clone chain during suspend and OOM could
+        * be triggered.
+        *
+        * Also flush data dm_io won't be marked as DM_IO_WAS_SPLIT, so they
+        * also aren't handled via the first stage requeue.
+        */
+       if (dm_io_flagged(io, DM_IO_WAS_SPLIT))
+               first_requeue = true;
+       else
+               first_requeue = false;
+
+       __dm_io_complete(io, first_requeue);
+}
+
 /*
  * Decrements the number of outstanding ios that a bio has been
  * cloned into, completing the original io if necc.
@@ -1033,7 +1123,7 @@ static void clone_endio(struct bio *bio)
        }
 
        if (static_branch_unlikely(&zoned_enabled) &&
-           unlikely(blk_queue_is_zoned(bdev_get_queue(bio->bi_bdev))))
+           unlikely(bdev_is_zoned(bio->bi_bdev)))
                dm_zone_endio(io, bio);
 
        if (endio) {
@@ -1086,23 +1176,18 @@ static sector_t max_io_len(struct dm_target *ti, sector_t sector)
 {
        sector_t target_offset = dm_target_offset(ti, sector);
        sector_t len = max_io_len_target_boundary(ti, target_offset);
-       sector_t max_len;
 
        /*
         * Does the target need to split IO even further?
         * - varied (per target) IO splitting is a tenet of DM; this
         *   explains why stacked chunk_sectors based splitting via
-        *   blk_max_size_offset() isn't possible here. So pass in
-        *   ti->max_io_len to override stacked chunk_sectors.
+        *   blk_queue_split() isn't possible here.
         */
-       if (ti->max_io_len) {
-               max_len = blk_max_size_offset(ti->table->md->queue,
-                                             target_offset, ti->max_io_len);
-               if (len > max_len)
-                       len = max_len;
-       }
-
-       return len;
+       if (!ti->max_io_len)
+               return len;
+       return min_t(sector_t, len,
+               min(queue_max_sectors(ti->table->md->queue),
+                   blk_chunk_sectors_left(target_offset, ti->max_io_len)));
 }
 
 int dm_set_target_max_io_len(struct dm_target *ti, sector_t len)
@@ -1245,6 +1330,7 @@ out:
 void dm_accept_partial_bio(struct bio *bio, unsigned n_sectors)
 {
        struct dm_target_io *tio = clone_to_tio(bio);
+       struct dm_io *io = tio->io;
        unsigned bio_sectors = bio_sectors(bio);
 
        BUG_ON(dm_tio_flagged(tio, DM_TIO_IS_DUPLICATE_BIO));
@@ -1260,8 +1346,9 @@ void dm_accept_partial_bio(struct bio *bio, unsigned n_sectors)
         * __split_and_process_bio() may have already saved mapped part
         * for accounting but it is being reduced so update accordingly.
         */
-       dm_io_set_flag(tio->io, DM_IO_WAS_SPLIT);
-       tio->io->sectors = n_sectors;
+       dm_io_set_flag(io, DM_IO_WAS_SPLIT);
+       io->sectors = n_sectors;
+       io->sector_offset = bio_sectors(io->orig_bio);
 }
 EXPORT_SYMBOL_GPL(dm_accept_partial_bio);
 
@@ -1384,17 +1471,7 @@ static void setup_split_accounting(struct clone_info *ci, unsigned len)
                 */
                dm_io_set_flag(io, DM_IO_WAS_SPLIT);
                io->sectors = len;
-       }
-
-       if (static_branch_unlikely(&stats_enabled) &&
-           unlikely(dm_stats_used(&io->md->stats))) {
-               /*
-                * Save bi_sector in terms of its offset from end of
-                * original bio, only needed for DM-stats' benefit.
-                * - saved regardless of whether split needed so that
-                *   dm_accept_partial_bio() doesn't need to.
-                */
-               io->sector_offset = bio_end_sector(ci->bio) - ci->sector;
+               io->sector_offset = bio_sectors(ci->bio);
        }
 }
 
@@ -1428,11 +1505,11 @@ static void alloc_multiple_bios(struct bio_list *blist, struct clone_info *ci,
 }
 
 static int __send_duplicate_bios(struct clone_info *ci, struct dm_target *ti,
-                                 unsigned num_bios, unsigned *len)
+                                unsigned int num_bios, unsigned *len)
 {
        struct bio_list blist = BIO_EMPTY_LIST;
        struct bio *clone;
-       int ret = 0;
+       unsigned int ret = 0;
 
        switch (num_bios) {
        case 0:
@@ -1460,8 +1537,7 @@ static int __send_duplicate_bios(struct clone_info *ci, struct dm_target *ti,
 
 static void __send_empty_flush(struct clone_info *ci)
 {
-       unsigned target_nr = 0;
-       struct dm_target *ti;
+       struct dm_table *t = ci->map;
        struct bio flush_bio;
 
        /*
@@ -1476,8 +1552,9 @@ static void __send_empty_flush(struct clone_info *ci)
        ci->sector_count = 0;
        ci->io->tio.clone.bi_iter.bi_size = 0;
 
-       while ((ti = dm_table_get_target(ci->map, target_nr++))) {
-               int bios;
+       for (unsigned int i = 0; i < t->num_targets; i++) {
+               unsigned int bios;
+               struct dm_target *ti = dm_table_get_target(t, i);
 
                atomic_add(ti->num_flush_bios, &ci->io->io_count);
                bios = __send_duplicate_bios(ci, ti, ti->num_flush_bios, NULL);
@@ -1497,7 +1574,7 @@ static void __send_changing_extent_only(struct clone_info *ci, struct dm_target
                                        unsigned num_bios)
 {
        unsigned len;
-       int bios;
+       unsigned int bios;
 
        len = min_t(sector_t, ci->sector_count,
                    max_io_len_target_boundary(ti, dm_target_offset(ti, ci->sector)));
@@ -1516,7 +1593,7 @@ static void __send_changing_extent_only(struct clone_info *ci, struct dm_target
 
 static bool is_abnormal_io(struct bio *bio)
 {
-       unsigned int op = bio_op(bio);
+       enum req_op op = bio_op(bio);
 
        if (op != REQ_OP_READ && op != REQ_OP_WRITE && op != REQ_OP_FLUSH) {
                switch (op) {
@@ -1547,6 +1624,8 @@ static blk_status_t __process_abnormal_io(struct clone_info *ci,
        case REQ_OP_WRITE_ZEROES:
                num_bios = ti->num_write_zeroes_bios;
                break;
+       default:
+               break;
        }
 
        /*
@@ -1628,7 +1707,7 @@ static blk_status_t __split_and_process_bio(struct clone_info *ci)
         * Only support bio polling for normal IO, and the target io is
         * exactly inside the dm_io instance (verified in dm_poll_dm_io)
         */
-       ci->submit_as_polled = ci->bio->bi_opf & REQ_POLLED;
+       ci->submit_as_polled = !!(ci->bio->bi_opf & REQ_POLLED);
 
        len = min_t(sector_t, max_io_len(ti, ci->sector), ci->sector_count);
        setup_split_accounting(ci, len);
@@ -1694,11 +1773,9 @@ static void dm_split_and_process_bio(struct mapped_device *md,
         * Remainder must be passed to submit_bio_noacct() so it gets handled
         * *after* bios already submitted have been completely processed.
         */
-       WARN_ON_ONCE(!dm_io_flagged(io, DM_IO_WAS_SPLIT));
-       io->split_bio = bio_split(bio, io->sectors, GFP_NOIO,
-                                 &md->queue->bio_split);
-       bio_chain(io->split_bio, bio);
-       trace_block_split(io->split_bio, bio->bi_iter.bi_sector);
+       bio_trim(bio, io->sectors, ci.sector_count);
+       trace_block_split(bio, bio->bi_iter.bi_sector);
+       bio_inc_remaining(bio);
        submit_bio_noacct(bio);
 out:
        /*
@@ -1725,7 +1802,7 @@ static void dm_submit_bio(struct bio *bio)
        struct mapped_device *md = bio->bi_bdev->bd_disk->private_data;
        int srcu_idx;
        struct dm_table *map;
-       unsigned bio_opf = bio->bi_opf;
+       blk_opf_t bio_opf = bio->bi_opf;
 
        map = dm_get_live_table_bio(md, &srcu_idx, bio_opf);
 
@@ -1899,7 +1976,7 @@ static void cleanup_mapped_device(struct mapped_device *md)
                        del_gendisk(md->disk);
                }
                dm_queue_destroy_crypto_profile(md->queue);
-               blk_cleanup_disk(md->disk);
+               put_disk(md->disk);
        }
 
        if (md->pending_io) {
@@ -1974,9 +2051,11 @@ static struct mapped_device *alloc_dev(int minor)
 
        init_waitqueue_head(&md->wait);
        INIT_WORK(&md->work, dm_wq_work);
+       INIT_WORK(&md->requeue_work, dm_wq_requeue_work);
        init_waitqueue_head(&md->eventq);
        init_completion(&md->kobj_holder.completion);
 
+       md->requeue_list = NULL;
        md->swap_bios = get_swap_bios();
        sema_init(&md->swap_bios_semaphore, md->swap_bios);
        mutex_init(&md->swap_bios_lock);
@@ -2983,54 +3062,6 @@ int dm_noflush_suspending(struct dm_target *ti)
 }
 EXPORT_SYMBOL_GPL(dm_noflush_suspending);
 
-struct dm_md_mempools *dm_alloc_md_mempools(struct mapped_device *md, enum dm_queue_mode type,
-                                           unsigned per_io_data_size, unsigned min_pool_size,
-                                           bool integrity, bool poll)
-{
-       struct dm_md_mempools *pools = kzalloc_node(sizeof(*pools), GFP_KERNEL, md->numa_node_id);
-       unsigned int pool_size = 0;
-       unsigned int front_pad, io_front_pad;
-       int ret;
-
-       if (!pools)
-               return NULL;
-
-       switch (type) {
-       case DM_TYPE_BIO_BASED:
-       case DM_TYPE_DAX_BIO_BASED:
-               pool_size = max(dm_get_reserved_bio_based_ios(), min_pool_size);
-               front_pad = roundup(per_io_data_size, __alignof__(struct dm_target_io)) + DM_TARGET_IO_BIO_OFFSET;
-               io_front_pad = roundup(per_io_data_size,  __alignof__(struct dm_io)) + DM_IO_BIO_OFFSET;
-               ret = bioset_init(&pools->io_bs, pool_size, io_front_pad, poll ? BIOSET_PERCPU_CACHE : 0);
-               if (ret)
-                       goto out;
-               if (integrity && bioset_integrity_create(&pools->io_bs, pool_size))
-                       goto out;
-               break;
-       case DM_TYPE_REQUEST_BASED:
-               pool_size = max(dm_get_reserved_rq_based_ios(), min_pool_size);
-               front_pad = offsetof(struct dm_rq_clone_bio_info, clone);
-               /* per_io_data_size is used for blk-mq pdu at queue allocation */
-               break;
-       default:
-               BUG();
-       }
-
-       ret = bioset_init(&pools->bs, pool_size, front_pad, 0);
-       if (ret)
-               goto out;
-
-       if (integrity && bioset_integrity_create(&pools->bs, pool_size))
-               goto out;
-
-       return pools;
-
-out:
-       dm_free_md_mempools(pools);
-
-       return NULL;
-}
-
 void dm_free_md_mempools(struct dm_md_mempools *pools)
 {
        if (!pools)
@@ -3046,11 +3077,14 @@ struct dm_pr {
        u64     old_key;
        u64     new_key;
        u32     flags;
+       bool    abort;
        bool    fail_early;
+       int     ret;
+       enum pr_type type;
 };
 
 static int dm_call_pr(struct block_device *bdev, iterate_devices_callout_fn fn,
-                     void *data)
+                     struct dm_pr *pr)
 {
        struct mapped_device *md = bdev->bd_disk->private_data;
        struct dm_table *table;
@@ -3062,15 +3096,21 @@ static int dm_call_pr(struct block_device *bdev, iterate_devices_callout_fn fn,
                goto out;
 
        /* We only support devices that have a single target */
-       if (dm_table_get_num_targets(table) != 1)
+       if (table->num_targets != 1)
                goto out;
        ti = dm_table_get_target(table, 0);
 
+       if (dm_suspended_md(md)) {
+               ret = -EAGAIN;
+               goto out;
+       }
+
        ret = -EINVAL;
        if (!ti->type->iterate_devices)
                goto out;
 
-       ret = ti->type->iterate_devices(ti, fn, data);
+       ti->type->iterate_devices(ti, fn, pr);
+       ret = 0;
 out:
        dm_put_live_table(md, srcu_idx);
        return ret;
@@ -3084,10 +3124,24 @@ static int __dm_pr_register(struct dm_target *ti, struct dm_dev *dev,
 {
        struct dm_pr *pr = data;
        const struct pr_ops *ops = dev->bdev->bd_disk->fops->pr_ops;
+       int ret;
 
-       if (!ops || !ops->pr_register)
-               return -EOPNOTSUPP;
-       return ops->pr_register(dev->bdev, pr->old_key, pr->new_key, pr->flags);
+       if (!ops || !ops->pr_register) {
+               pr->ret = -EOPNOTSUPP;
+               return -1;
+       }
+
+       ret = ops->pr_register(dev->bdev, pr->old_key, pr->new_key, pr->flags);
+       if (!ret)
+               return 0;
+
+       if (!pr->ret)
+               pr->ret = ret;
+
+       if (pr->fail_early)
+               return -1;
+
+       return 0;
 }
 
 static int dm_pr_register(struct block_device *bdev, u64 old_key, u64 new_key,
@@ -3098,82 +3152,145 @@ static int dm_pr_register(struct block_device *bdev, u64 old_key, u64 new_key,
                .new_key        = new_key,
                .flags          = flags,
                .fail_early     = true,
+               .ret            = 0,
        };
        int ret;
 
        ret = dm_call_pr(bdev, __dm_pr_register, &pr);
-       if (ret && new_key) {
-               /* unregister all paths if we failed to register any path */
-               pr.old_key = new_key;
-               pr.new_key = 0;
-               pr.flags = 0;
-               pr.fail_early = false;
-               dm_call_pr(bdev, __dm_pr_register, &pr);
+       if (ret) {
+               /* Didn't even get to register a path */
+               return ret;
        }
 
+       if (!pr.ret)
+               return 0;
+       ret = pr.ret;
+
+       if (!new_key)
+               return ret;
+
+       /* unregister all paths if we failed to register any path */
+       pr.old_key = new_key;
+       pr.new_key = 0;
+       pr.flags = 0;
+       pr.fail_early = false;
+       (void) dm_call_pr(bdev, __dm_pr_register, &pr);
        return ret;
 }
 
+
+static int __dm_pr_reserve(struct dm_target *ti, struct dm_dev *dev,
+                          sector_t start, sector_t len, void *data)
+{
+       struct dm_pr *pr = data;
+       const struct pr_ops *ops = dev->bdev->bd_disk->fops->pr_ops;
+
+       if (!ops || !ops->pr_reserve) {
+               pr->ret = -EOPNOTSUPP;
+               return -1;
+       }
+
+       pr->ret = ops->pr_reserve(dev->bdev, pr->old_key, pr->type, pr->flags);
+       if (!pr->ret)
+               return -1;
+
+       return 0;
+}
+
 static int dm_pr_reserve(struct block_device *bdev, u64 key, enum pr_type type,
                         u32 flags)
 {
-       struct mapped_device *md = bdev->bd_disk->private_data;
-       const struct pr_ops *ops;
-       int r, srcu_idx;
+       struct dm_pr pr = {
+               .old_key        = key,
+               .flags          = flags,
+               .type           = type,
+               .fail_early     = false,
+               .ret            = 0,
+       };
+       int ret;
 
-       r = dm_prepare_ioctl(md, &srcu_idx, &bdev);
-       if (r < 0)
-               goto out;
+       ret = dm_call_pr(bdev, __dm_pr_reserve, &pr);
+       if (ret)
+               return ret;
 
-       ops = bdev->bd_disk->fops->pr_ops;
-       if (ops && ops->pr_reserve)
-               r = ops->pr_reserve(bdev, key, type, flags);
-       else
-               r = -EOPNOTSUPP;
-out:
-       dm_unprepare_ioctl(md, srcu_idx);
-       return r;
+       return pr.ret;
+}
+
+/*
+ * If there is a non-All Registrants type of reservation, the release must be
+ * sent down the holding path. For the cases where there is no reservation or
+ * the path is not the holder the device will also return success, so we must
+ * try each path to make sure we got the correct path.
+ */
+static int __dm_pr_release(struct dm_target *ti, struct dm_dev *dev,
+                          sector_t start, sector_t len, void *data)
+{
+       struct dm_pr *pr = data;
+       const struct pr_ops *ops = dev->bdev->bd_disk->fops->pr_ops;
+
+       if (!ops || !ops->pr_release) {
+               pr->ret = -EOPNOTSUPP;
+               return -1;
+       }
+
+       pr->ret = ops->pr_release(dev->bdev, pr->old_key, pr->type);
+       if (pr->ret)
+               return -1;
+
+       return 0;
 }
 
 static int dm_pr_release(struct block_device *bdev, u64 key, enum pr_type type)
 {
-       struct mapped_device *md = bdev->bd_disk->private_data;
-       const struct pr_ops *ops;
-       int r, srcu_idx;
+       struct dm_pr pr = {
+               .old_key        = key,
+               .type           = type,
+               .fail_early     = false,
+       };
+       int ret;
 
-       r = dm_prepare_ioctl(md, &srcu_idx, &bdev);
-       if (r < 0)
-               goto out;
+       ret = dm_call_pr(bdev, __dm_pr_release, &pr);
+       if (ret)
+               return ret;
 
-       ops = bdev->bd_disk->fops->pr_ops;
-       if (ops && ops->pr_release)
-               r = ops->pr_release(bdev, key, type);
-       else
-               r = -EOPNOTSUPP;
-out:
-       dm_unprepare_ioctl(md, srcu_idx);
-       return r;
+       return pr.ret;
+}
+
+static int __dm_pr_preempt(struct dm_target *ti, struct dm_dev *dev,
+                          sector_t start, sector_t len, void *data)
+{
+       struct dm_pr *pr = data;
+       const struct pr_ops *ops = dev->bdev->bd_disk->fops->pr_ops;
+
+       if (!ops || !ops->pr_preempt) {
+               pr->ret = -EOPNOTSUPP;
+               return -1;
+       }
+
+       pr->ret = ops->pr_preempt(dev->bdev, pr->old_key, pr->new_key, pr->type,
+                                 pr->abort);
+       if (!pr->ret)
+               return -1;
+
+       return 0;
 }
 
 static int dm_pr_preempt(struct block_device *bdev, u64 old_key, u64 new_key,
                         enum pr_type type, bool abort)
 {
-       struct mapped_device *md = bdev->bd_disk->private_data;
-       const struct pr_ops *ops;
-       int r, srcu_idx;
+       struct dm_pr pr = {
+               .new_key        = new_key,
+               .old_key        = old_key,
+               .type           = type,
+               .fail_early     = false,
+       };
+       int ret;
 
-       r = dm_prepare_ioctl(md, &srcu_idx, &bdev);
-       if (r < 0)
-               goto out;
+       ret = dm_call_pr(bdev, __dm_pr_preempt, &pr);
+       if (ret)
+               return ret;
 
-       ops = bdev->bd_disk->fops->pr_ops;
-       if (ops && ops->pr_preempt)
-               r = ops->pr_preempt(bdev, old_key, new_key, type, abort);
-       else
-               r = -EOPNOTSUPP;
-out:
-       dm_unprepare_ioctl(md, srcu_idx);
-       return r;
+       return pr.ret;
 }
 
 static int dm_pr_clear(struct block_device *bdev, u64 key)
index a8405ce..5201df0 100644 (file)
@@ -53,7 +53,6 @@ struct dm_io;
  *---------------------------------------------------------------*/
 void dm_table_event_callback(struct dm_table *t,
                             void (*fn)(void *), void *context);
-struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index);
 struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector);
 bool dm_table_has_no_data_devices(struct dm_table *table);
 int dm_calculate_queue_limits(struct dm_table *table,
@@ -218,9 +217,6 @@ void dm_kcopyd_exit(void);
 /*
  * Mempool operations
  */
-struct dm_md_mempools *dm_alloc_md_mempools(struct mapped_device *md, enum dm_queue_mode type,
-                                           unsigned per_io_data_size, unsigned min_pool_size,
-                                           bool integrity, bool poll);
 void dm_free_md_mempools(struct dm_md_mempools *pools);
 
 /*
index d87f674..bf6dffa 100644 (file)
@@ -165,7 +165,7 @@ static int read_sb_page(struct mddev *mddev, loff_t offset,
 
                if (sync_page_io(rdev, target,
                                 roundup(size, bdev_logical_block_size(rdev->bdev)),
-                                page, REQ_OP_READ, 0, true)) {
+                                page, REQ_OP_READ, true)) {
                        page->index = index;
                        return 0;
                }
@@ -302,7 +302,7 @@ static void write_page(struct bitmap *bitmap, struct page *page, int wait)
                        atomic_inc(&bitmap->pending_writes);
                        set_buffer_locked(bh);
                        set_buffer_mapped(bh);
-                       submit_bh(REQ_OP_WRITE, REQ_SYNC, bh);
+                       submit_bh(REQ_OP_WRITE | REQ_SYNC, bh);
                        bh = bh->b_this_page;
                }
 
@@ -394,7 +394,7 @@ static int read_page(struct file *file, unsigned long index,
                        atomic_inc(&bitmap->pending_writes);
                        set_buffer_locked(bh);
                        set_buffer_mapped(bh);
-                       submit_bh(REQ_OP_READ, 0, bh);
+                       submit_bh(REQ_OP_READ, bh);
                }
                blk_cur++;
                bh = bh->b_this_page;
index c7ecb0b..4df78e3 100644 (file)
@@ -993,15 +993,15 @@ int md_super_wait(struct mddev *mddev)
 }
 
 int sync_page_io(struct md_rdev *rdev, sector_t sector, int size,
-                struct page *page, int op, int op_flags, bool metadata_op)
+                struct page *page, blk_opf_t opf, bool metadata_op)
 {
        struct bio bio;
        struct bio_vec bvec;
 
        if (metadata_op && rdev->meta_bdev)
-               bio_init(&bio, rdev->meta_bdev, &bvec, 1, op | op_flags);
+               bio_init(&bio, rdev->meta_bdev, &bvec, 1, opf);
        else
-               bio_init(&bio, rdev->bdev, &bvec, 1, op | op_flags);
+               bio_init(&bio, rdev->bdev, &bvec, 1, opf);
 
        if (metadata_op)
                bio.bi_iter.bi_sector = sector + rdev->sb_start;
@@ -1024,7 +1024,7 @@ static int read_disk_sb(struct md_rdev *rdev, int size)
        if (rdev->sb_loaded)
                return 0;
 
-       if (!sync_page_io(rdev, 0, size, rdev->sb_page, REQ_OP_READ, 0, true))
+       if (!sync_page_io(rdev, 0, size, rdev->sb_page, REQ_OP_READ, true))
                goto fail;
        rdev->sb_loaded = 1;
        return 0;
@@ -1722,7 +1722,7 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_
                        return -EINVAL;
                bb_sector = (long long)offset;
                if (!sync_page_io(rdev, bb_sector, sectors << 9,
-                                 rdev->bb_page, REQ_OP_READ, 0, true))
+                                 rdev->bb_page, REQ_OP_READ, true))
                        return -EIO;
                bbp = (__le64 *)page_address(rdev->bb_page);
                rdev->badblocks.shift = sb->bblog_shift;
@@ -2438,7 +2438,7 @@ static int bind_rdev_to_array(struct md_rdev *rdev, struct mddev *mddev)
                        mdname(mddev), mddev->max_disks);
                return -EBUSY;
        }
-       bdevname(rdev->bdev,b);
+       snprintf(b, sizeof(b), "%pg", rdev->bdev);
        strreplace(b, '/', '!');
 
        rdev->mddev = mddev;
@@ -5579,7 +5579,7 @@ static void md_free(struct kobject *ko)
 
        if (mddev->gendisk) {
                del_gendisk(mddev->gendisk);
-               blk_cleanup_disk(mddev->gendisk);
+               put_disk(mddev->gendisk);
        }
        percpu_ref_exit(&mddev->writes_pending);
 
@@ -5718,7 +5718,7 @@ static int md_alloc(dev_t dev, char *name)
 out_del_gendisk:
        del_gendisk(disk);
 out_cleanup_disk:
-       blk_cleanup_disk(disk);
+       put_disk(disk);
 out_unlock_disks_mutex:
        mutex_unlock(&disks_mutex);
        mddev_put(mddev);
index cf2cbb1..b4f84b2 100644 (file)
@@ -738,8 +738,7 @@ extern void md_super_write(struct mddev *mddev, struct md_rdev *rdev,
                           sector_t sector, int size, struct page *page);
 extern int md_super_wait(struct mddev *mddev);
 extern int sync_page_io(struct md_rdev *rdev, sector_t sector, int size,
-                       struct page *page, int op, int op_flags,
-                       bool metadata_op);
+               struct page *page, blk_opf_t opf, bool metadata_op);
 extern void md_do_sync(struct md_thread *thread);
 extern void md_new_event(void);
 extern void md_allow_write(struct mddev *mddev);
index 258d4eb..05d8438 100644 (file)
@@ -1220,8 +1220,8 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
        struct raid1_info *mirror;
        struct bio *read_bio;
        struct bitmap *bitmap = mddev->bitmap;
-       const int op = bio_op(bio);
-       const unsigned long do_sync = (bio->bi_opf & REQ_SYNC);
+       const enum req_op op = bio_op(bio);
+       const blk_opf_t do_sync = bio->bi_opf & REQ_SYNC;
        int max_sectors;
        int rdisk;
        bool r1bio_existed = !!r1_bio;
@@ -1240,7 +1240,7 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
                rcu_read_lock();
                rdev = rcu_dereference(conf->mirrors[r1_bio->read_disk].rdev);
                if (rdev)
-                       bdevname(rdev->bdev, b);
+                       snprintf(b, sizeof(b), "%pg", rdev->bdev);
                else
                        strcpy(b, "???");
                rcu_read_unlock();
@@ -1988,9 +1988,9 @@ static void end_sync_write(struct bio *bio)
 }
 
 static int r1_sync_page_io(struct md_rdev *rdev, sector_t sector,
-                           int sectors, struct page *page, int rw)
+                          int sectors, struct page *page, int rw)
 {
-       if (sync_page_io(rdev, sector, sectors << 9, page, rw, 0, false))
+       if (sync_page_io(rdev, sector, sectors << 9, page, rw, false))
                /* success */
                return 1;
        if (rw == WRITE) {
@@ -2057,7 +2057,7 @@ static int fix_sync_read_error(struct r1bio *r1_bio)
                                rdev = conf->mirrors[d].rdev;
                                if (sync_page_io(rdev, sect, s<<9,
                                                 pages[idx],
-                                                REQ_OP_READ, 0, false)) {
+                                                REQ_OP_READ, false)) {
                                        success = 1;
                                        break;
                                }
@@ -2305,7 +2305,7 @@ static void fix_read_error(struct r1conf *conf, int read_disk,
                                atomic_inc(&rdev->nr_pending);
                                rcu_read_unlock();
                                if (sync_page_io(rdev, sect, s<<9,
-                                        conf->tmppage, REQ_OP_READ, 0, false))
+                                        conf->tmppage, REQ_OP_READ, false))
                                        success = 1;
                                rdev_dec_pending(rdev, mddev);
                                if (success)
index d589f82..2654595 100644 (file)
@@ -1136,8 +1136,8 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
 {
        struct r10conf *conf = mddev->private;
        struct bio *read_bio;
-       const int op = bio_op(bio);
-       const unsigned long do_sync = (bio->bi_opf & REQ_SYNC);
+       const enum req_op op = bio_op(bio);
+       const blk_opf_t do_sync = bio->bi_opf & REQ_SYNC;
        int max_sectors;
        struct md_rdev *rdev;
        char b[BDEVNAME_SIZE];
@@ -1164,7 +1164,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
                disk = r10_bio->devs[slot].devnum;
                err_rdev = rcu_dereference(conf->mirrors[disk].rdev);
                if (err_rdev)
-                       bdevname(err_rdev->bdev, b);
+                       snprintf(b, sizeof(b), "%pg", err_rdev->bdev);
                else {
                        strcpy(b, "???");
                        /* This never gets dereferenced */
@@ -1230,9 +1230,9 @@ static void raid10_write_one_disk(struct mddev *mddev, struct r10bio *r10_bio,
                                  struct bio *bio, bool replacement,
                                  int n_copy)
 {
-       const int op = bio_op(bio);
-       const unsigned long do_sync = (bio->bi_opf & REQ_SYNC);
-       const unsigned long do_fua = (bio->bi_opf & REQ_FUA);
+       const enum req_op op = bio_op(bio);
+       const blk_opf_t do_sync = bio->bi_opf & REQ_SYNC;
+       const blk_opf_t do_fua = bio->bi_opf & REQ_FUA;
        unsigned long flags;
        struct blk_plug_cb *cb;
        struct raid1_plug_cb *plug = NULL;
@@ -2512,7 +2512,7 @@ static void fix_recovery_read_error(struct r10bio *r10_bio)
                                  addr,
                                  s << 9,
                                  pages[idx],
-                                 REQ_OP_READ, 0, false);
+                                 REQ_OP_READ, false);
                if (ok) {
                        rdev = conf->mirrors[dw].rdev;
                        addr = r10_bio->devs[1].addr + sect;
@@ -2520,7 +2520,7 @@ static void fix_recovery_read_error(struct r10bio *r10_bio)
                                          addr,
                                          s << 9,
                                          pages[idx],
-                                         REQ_OP_WRITE, 0, false);
+                                         REQ_OP_WRITE, false);
                        if (!ok) {
                                set_bit(WriteErrorSeen, &rdev->flags);
                                if (!test_and_set_bit(WantReplacement,
@@ -2644,7 +2644,7 @@ static int r10_sync_page_io(struct md_rdev *rdev, sector_t sector,
        if (is_badblock(rdev, sector, sectors, &first_bad, &bad_sectors)
            && (rw == READ || test_bit(WriteErrorSeen, &rdev->flags)))
                return -1;
-       if (sync_page_io(rdev, sector, sectors << 9, page, rw, 0, false))
+       if (sync_page_io(rdev, sector, sectors << 9, page, rw, false))
                /* success */
                return 1;
        if (rw == WRITE) {
@@ -2726,7 +2726,7 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
                                                       sect,
                                                       s<<9,
                                                       conf->tmppage,
-                                                      REQ_OP_READ, 0, false);
+                                                      REQ_OP_READ, false);
                                rdev_dec_pending(rdev, mddev);
                                rcu_read_lock();
                                if (success)
@@ -5107,7 +5107,7 @@ static int handle_reshape_read_error(struct mddev *mddev,
                                               addr,
                                               s << 9,
                                               pages[idx],
-                                              REQ_OP_READ, 0, false);
+                                              REQ_OP_READ, false);
                        rdev_dec_pending(rdev, mddev);
                        rcu_read_lock();
                        if (success)
index 83c184e..6f2dd73 100644 (file)
@@ -1788,7 +1788,7 @@ static int r5l_log_write_empty_meta_block(struct r5l_log *log, sector_t pos,
        mb = page_address(page);
        mb->checksum = cpu_to_le32(crc32c_le(log->uuid_checksum,
                                             mb, PAGE_SIZE));
-       if (!sync_page_io(log->rdev, pos, PAGE_SIZE, page, REQ_OP_WRITE,
+       if (!sync_page_io(log->rdev, pos, PAGE_SIZE, page, REQ_OP_WRITE |
                          REQ_SYNC | REQ_FUA, false)) {
                __free_page(page);
                return -EIO;
@@ -1898,7 +1898,7 @@ r5l_recovery_replay_one_stripe(struct r5conf *conf,
                        atomic_inc(&rdev->nr_pending);
                        rcu_read_unlock();
                        sync_page_io(rdev, sh->sector, PAGE_SIZE,
-                                    sh->dev[disk_index].page, REQ_OP_WRITE, 0,
+                                    sh->dev[disk_index].page, REQ_OP_WRITE,
                                     false);
                        rdev_dec_pending(rdev, rdev->mddev);
                        rcu_read_lock();
@@ -1908,7 +1908,7 @@ r5l_recovery_replay_one_stripe(struct r5conf *conf,
                        atomic_inc(&rrdev->nr_pending);
                        rcu_read_unlock();
                        sync_page_io(rrdev, sh->sector, PAGE_SIZE,
-                                    sh->dev[disk_index].page, REQ_OP_WRITE, 0,
+                                    sh->dev[disk_index].page, REQ_OP_WRITE,
                                     false);
                        rdev_dec_pending(rrdev, rrdev->mddev);
                        rcu_read_lock();
@@ -2394,7 +2394,7 @@ r5c_recovery_rewrite_data_only_stripes(struct r5l_log *log,
                                                  PAGE_SIZE));
                                kunmap_atomic(addr);
                                sync_page_io(log->rdev, write_pos, PAGE_SIZE,
-                                            dev->page, REQ_OP_WRITE, 0, false);
+                                            dev->page, REQ_OP_WRITE, false);
                                write_pos = r5l_ring_add(log, write_pos,
                                                         BLOCK_SECTORS);
                                offset += sizeof(__le32) +
@@ -2406,7 +2406,7 @@ r5c_recovery_rewrite_data_only_stripes(struct r5l_log *log,
                mb->checksum = cpu_to_le32(crc32c_le(log->uuid_checksum,
                                                     mb, PAGE_SIZE));
                sync_page_io(log->rdev, ctx->pos, PAGE_SIZE, page,
-                            REQ_OP_WRITE, REQ_SYNC | REQ_FUA, false);
+                            REQ_OP_WRITE | REQ_SYNC | REQ_FUA, false);
                sh->log_start = ctx->pos;
                list_add_tail(&sh->r5c, &log->stripe_in_journal_list);
                atomic_inc(&log->stripe_in_journal_count);
@@ -2971,7 +2971,7 @@ static int r5l_load_log(struct r5l_log *log)
        if (!page)
                return -ENOMEM;
 
-       if (!sync_page_io(rdev, cp, PAGE_SIZE, page, REQ_OP_READ, 0, false)) {
+       if (!sync_page_io(rdev, cp, PAGE_SIZE, page, REQ_OP_READ, false)) {
                ret = -EIO;
                goto ioerr;
        }
index 0a2e480..98988cb 100644 (file)
@@ -897,7 +897,7 @@ static int ppl_recover_entry(struct ppl_log *log, struct ppl_header_entry *e,
                                 __func__, indent, "", rdev->bdev,
                                 (unsigned long long)sector);
                        if (!sync_page_io(rdev, sector, block_size, page2,
-                                       REQ_OP_READ, 0, false)) {
+                                       REQ_OP_READ, false)) {
                                md_error(mddev, rdev);
                                pr_debug("%s:%*s read failed!\n", __func__,
                                         indent, "");
@@ -919,7 +919,7 @@ static int ppl_recover_entry(struct ppl_log *log, struct ppl_header_entry *e,
                                 (unsigned long long)(ppl_sector + i));
                        if (!sync_page_io(log->rdev,
                                        ppl_sector - log->rdev->data_offset + i,
-                                       block_size, page2, REQ_OP_READ, 0,
+                                       block_size, page2, REQ_OP_READ,
                                        false)) {
                                pr_debug("%s:%*s read failed!\n", __func__,
                                         indent, "");
@@ -946,7 +946,7 @@ static int ppl_recover_entry(struct ppl_log *log, struct ppl_header_entry *e,
                         (unsigned long long)parity_sector,
                         parity_rdev->bdev);
                if (!sync_page_io(parity_rdev, parity_sector, block_size,
-                               page1, REQ_OP_WRITE, 0, false)) {
+                                 page1, REQ_OP_WRITE, false)) {
                        pr_debug("%s:%*s parity write error!\n", __func__,
                                 indent, "");
                        md_error(mddev, parity_rdev);
@@ -998,7 +998,7 @@ static int ppl_recover(struct ppl_log *log, struct ppl_header *pplhdr,
                        int s = pp_size > PAGE_SIZE ? PAGE_SIZE : pp_size;
 
                        if (!sync_page_io(rdev, sector - rdev->data_offset,
-                                       s, page, REQ_OP_READ, 0, false)) {
+                                       s, page, REQ_OP_READ, false)) {
                                md_error(mddev, rdev);
                                ret = -EIO;
                                goto out;
@@ -1062,7 +1062,7 @@ static int ppl_write_empty_header(struct ppl_log *log)
 
        if (!sync_page_io(rdev, rdev->ppl.sector - rdev->data_offset,
                          PPL_HEADER_SIZE, page, REQ_OP_WRITE | REQ_SYNC |
-                         REQ_FUA, 0, false)) {
+                         REQ_FUA, false)) {
                md_error(rdev->mddev, rdev);
                ret = -EIO;
        }
@@ -1100,7 +1100,7 @@ static int ppl_load_distributed(struct ppl_log *log)
                if (!sync_page_io(rdev,
                                  rdev->ppl.sector - rdev->data_offset +
                                  pplhdr_offset, PAGE_SIZE, page, REQ_OP_READ,
-                                 0, false)) {
+                                 false)) {
                        md_error(mddev, rdev);
                        ret = -EIO;
                        /* if not able to read - don't recover any PPL */
index 5d09256..5cabdbb 100644 (file)
@@ -1082,7 +1082,8 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
        should_defer = conf->batch_bio_dispatch && conf->group_cnt;
 
        for (i = disks; i--; ) {
-               int op, op_flags = 0;
+               enum req_op op;
+               blk_opf_t op_flags = 0;
                int replace_only = 0;
                struct bio *bi, *rbi;
                struct md_rdev *rdev, *rrdev = NULL;
@@ -7304,7 +7305,9 @@ static struct r5conf *setup_conf(struct mddev *mddev)
                goto abort;
        conf->mddev = mddev;
 
-       if ((conf->stripe_hashtbl = kzalloc(PAGE_SIZE, GFP_KERNEL)) == NULL)
+       ret = -ENOMEM;
+       conf->stripe_hashtbl = kzalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!conf->stripe_hashtbl)
                goto abort;
 
        /* We init hash_locks[0] separately to that it can be used
@@ -7933,7 +7936,7 @@ static int raid5_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
        int err = 0;
        int number = rdev->raid_disk;
        struct md_rdev __rcu **rdevp;
-       struct disk_info *p = conf->disks + number;
+       struct disk_info *p;
        struct md_rdev *tmp;
 
        print_raid5_conf(conf);
@@ -7952,6 +7955,9 @@ static int raid5_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
                log_exit(conf);
                return 0;
        }
+       if (unlikely(number >= conf->pool_size))
+               return 0;
+       p = conf->disks + number;
        if (rdev == rcu_access_pointer(p->rdev))
                rdevp = &p->rdev;
        else if (rdev == rcu_access_pointer(p->replacement))
@@ -8062,6 +8068,7 @@ static int raid5_add_disk(struct mddev *mddev, struct md_rdev *rdev)
         */
        if (rdev->saved_raid_disk >= 0 &&
            rdev->saved_raid_disk >= first &&
+           rdev->saved_raid_disk <= last &&
            conf->disks[rdev->saved_raid_disk].rdev == NULL)
                first = rdev->saved_raid_disk;
 
index b7800b3..ac1a411 100644 (file)
@@ -105,6 +105,7 @@ config TI_EMIF
 config OMAP_GPMC
        tristate "Texas Instruments OMAP SoC GPMC driver"
        depends on OF_ADDRESS
+       depends on ARCH_OMAP2PLUS || ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST
        select GPIOLIB
        help
          This driver is for the General Purpose Memory Controller (GPMC)
index 86a3d34..d7cb7ea 100644 (file)
 /* SMI COMMON */
 #define SMI_L1LEN                      0x100
 
+#define SMI_L1_ARB                     0x200
 #define SMI_BUS_SEL                    0x220
 #define SMI_BUS_LARB_SHIFT(larbid)     ((larbid) << 1)
 /* All are MMU0 defaultly. Only specialize mmu1 here. */
 #define F_MMU1_LARB(larbid)            (0x1 << SMI_BUS_LARB_SHIFT(larbid))
 
+#define SMI_READ_FIFO_TH               0x230
 #define SMI_M4U_TH                     0x234
 #define SMI_FIFO_TH1                   0x238
 #define SMI_FIFO_TH2                   0x23c
@@ -360,6 +362,7 @@ static const struct of_device_id mtk_smi_larb_of_ids[] = {
        {.compatible = "mediatek,mt2701-smi-larb", .data = &mtk_smi_larb_mt2701},
        {.compatible = "mediatek,mt2712-smi-larb", .data = &mtk_smi_larb_mt2712},
        {.compatible = "mediatek,mt6779-smi-larb", .data = &mtk_smi_larb_mt6779},
+       {.compatible = "mediatek,mt6795-smi-larb", .data = &mtk_smi_larb_mt8173},
        {.compatible = "mediatek,mt8167-smi-larb", .data = &mtk_smi_larb_mt8167},
        {.compatible = "mediatek,mt8173-smi-larb", .data = &mtk_smi_larb_mt8173},
        {.compatible = "mediatek,mt8183-smi-larb", .data = &mtk_smi_larb_mt8183},
@@ -404,13 +407,16 @@ static int mtk_smi_device_link_common(struct device *dev, struct device **com_de
        of_node_put(smi_com_node);
        if (smi_com_pdev) {
                /* smi common is the supplier, Make sure it is ready before */
-               if (!platform_get_drvdata(smi_com_pdev))
+               if (!platform_get_drvdata(smi_com_pdev)) {
+                       put_device(&smi_com_pdev->dev);
                        return -EPROBE_DEFER;
+               }
                smi_com_dev = &smi_com_pdev->dev;
                link = device_link_add(dev, smi_com_dev,
                                       DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS);
                if (!link) {
                        dev_err(dev, "Unable to link smi-common dev\n");
+                       put_device(&smi_com_pdev->dev);
                        return -ENODEV;
                }
                *com_dev = smi_com_dev;
@@ -541,6 +547,13 @@ static struct platform_driver mtk_smi_larb_driver = {
        }
 };
 
+static const struct mtk_smi_reg_pair mtk_smi_common_mt6795_init[SMI_COMMON_INIT_REGS_NR] = {
+       {SMI_L1_ARB, 0x1b},
+       {SMI_M4U_TH, 0xce810c85},
+       {SMI_FIFO_TH1, 0x43214c8},
+       {SMI_READ_FIFO_TH, 0x191f},
+};
+
 static const struct mtk_smi_reg_pair mtk_smi_common_mt8195_init[SMI_COMMON_INIT_REGS_NR] = {
        {SMI_L1LEN, 0xb},
        {SMI_M4U_TH, 0xe100e10},
@@ -565,6 +578,12 @@ static const struct mtk_smi_common_plat mtk_smi_common_mt6779 = {
                    F_MMU1_LARB(5) | F_MMU1_LARB(6) | F_MMU1_LARB(7),
 };
 
+static const struct mtk_smi_common_plat mtk_smi_common_mt6795 = {
+       .type     = MTK_SMI_GEN2,
+       .bus_sel  = F_MMU1_LARB(0),
+       .init     = mtk_smi_common_mt6795_init,
+};
+
 static const struct mtk_smi_common_plat mtk_smi_common_mt8183 = {
        .type     = MTK_SMI_GEN2,
        .has_gals = true,
@@ -609,6 +628,7 @@ static const struct of_device_id mtk_smi_common_of_ids[] = {
        {.compatible = "mediatek,mt2701-smi-common", .data = &mtk_smi_common_gen1},
        {.compatible = "mediatek,mt2712-smi-common", .data = &mtk_smi_common_gen2},
        {.compatible = "mediatek,mt6779-smi-common", .data = &mtk_smi_common_mt6779},
+       {.compatible = "mediatek,mt6795-smi-common", .data = &mtk_smi_common_mt6795},
        {.compatible = "mediatek,mt8167-smi-common", .data = &mtk_smi_common_gen2},
        {.compatible = "mediatek,mt8173-smi-common", .data = &mtk_smi_common_gen2},
        {.compatible = "mediatek,mt8183-smi-common", .data = &mtk_smi_common_mt8183},
index 4733e78..c491cd5 100644 (file)
@@ -1187,33 +1187,39 @@ static int of_get_dram_timings(struct exynos5_dmc *dmc)
 
        dmc->timing_row = devm_kmalloc_array(dmc->dev, TIMING_COUNT,
                                             sizeof(u32), GFP_KERNEL);
-       if (!dmc->timing_row)
-               return -ENOMEM;
+       if (!dmc->timing_row) {
+               ret = -ENOMEM;
+               goto put_node;
+       }
 
        dmc->timing_data = devm_kmalloc_array(dmc->dev, TIMING_COUNT,
                                              sizeof(u32), GFP_KERNEL);
-       if (!dmc->timing_data)
-               return -ENOMEM;
+       if (!dmc->timing_data) {
+               ret = -ENOMEM;
+               goto put_node;
+       }
 
        dmc->timing_power = devm_kmalloc_array(dmc->dev, TIMING_COUNT,
                                               sizeof(u32), GFP_KERNEL);
-       if (!dmc->timing_power)
-               return -ENOMEM;
+       if (!dmc->timing_power) {
+               ret = -ENOMEM;
+               goto put_node;
+       }
 
        dmc->timings = of_lpddr3_get_ddr_timings(np_ddr, dmc->dev,
                                                 DDR_TYPE_LPDDR3,
                                                 &dmc->timings_arr_size);
        if (!dmc->timings) {
-               of_node_put(np_ddr);
                dev_warn(dmc->dev, "could not get timings from DT\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto put_node;
        }
 
        dmc->min_tck = of_lpddr3_get_min_tck(np_ddr, dmc->dev);
        if (!dmc->min_tck) {
-               of_node_put(np_ddr);
                dev_warn(dmc->dev, "could not get tck from DT\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto put_node;
        }
 
        /* Sorted array of OPPs with frequency ascending */
@@ -1227,13 +1233,14 @@ static int of_get_dram_timings(struct exynos5_dmc *dmc)
                                             clk_period_ps);
        }
 
-       of_node_put(np_ddr);
 
        /* Take the highest frequency's timings as 'bypass' */
        dmc->bypass_timing_row = dmc->timing_row[idx - 1];
        dmc->bypass_timing_data = dmc->timing_data[idx - 1];
        dmc->bypass_timing_power = dmc->timing_power[idx - 1];
 
+put_node:
+       of_node_put(np_ddr);
        return ret;
 }
 
index e23ebd4..a9e8fd9 100644 (file)
 
 static const struct tegra_mc_client tegra234_mc_clients[] = {
        {
+               .id = TEGRA234_MEMORY_CLIENT_MGBEARD,
+               .name = "mgbeard",
+               .sid = TEGRA234_SID_MGBE,
+               .regs = {
+                       .sid = {
+                               .override = 0x2c0,
+                               .security = 0x2c4,
+                       },
+               },
+       }, {
+               .id = TEGRA234_MEMORY_CLIENT_MGBEBRD,
+               .name = "mgbebrd",
+               .sid = TEGRA234_SID_MGBE_VF1,
+               .regs = {
+                       .sid = {
+                               .override = 0x2c8,
+                               .security = 0x2cc,
+                       },
+               },
+       }, {
+               .id = TEGRA234_MEMORY_CLIENT_MGBECRD,
+               .name = "mgbecrd",
+               .sid = TEGRA234_SID_MGBE_VF2,
+               .regs = {
+                       .sid = {
+                               .override = 0x2d0,
+                               .security = 0x2d4,
+                       },
+               },
+       }, {
+               .id = TEGRA234_MEMORY_CLIENT_MGBEDRD,
+               .name = "mgbedrd",
+               .sid = TEGRA234_SID_MGBE_VF3,
+               .regs = {
+                       .sid = {
+                               .override = 0x2d8,
+                               .security = 0x2dc,
+                       },
+               },
+       }, {
+               .id = TEGRA234_MEMORY_CLIENT_MGBEAWR,
+               .name = "mgbeawr",
+               .sid = TEGRA234_SID_MGBE,
+               .regs = {
+                       .sid = {
+                               .override = 0x2e0,
+                               .security = 0x2e4,
+                       },
+               },
+       }, {
+               .id = TEGRA234_MEMORY_CLIENT_MGBEBWR,
+               .name = "mgbebwr",
+               .sid = TEGRA234_SID_MGBE_VF1,
+               .regs = {
+                       .sid = {
+                               .override = 0x2f8,
+                               .security = 0x2fc,
+                       },
+               },
+       }, {
+               .id = TEGRA234_MEMORY_CLIENT_MGBECWR,
+               .name = "mgbecwr",
+               .sid = TEGRA234_SID_MGBE_VF2,
+               .regs = {
+                       .sid = {
+                               .override = 0x308,
+                               .security = 0x30c,
+                       },
+               },
+       }, {
                .id = TEGRA234_MEMORY_CLIENT_SDMMCRAB,
                .name = "sdmmcrab",
                .sid = TEGRA234_SID_SDMMC4,
@@ -21,6 +91,16 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
                        },
                },
        }, {
+               .id = TEGRA234_MEMORY_CLIENT_MGBEDWR,
+               .name = "mgbedwr",
+               .sid = TEGRA234_SID_MGBE_VF3,
+               .regs = {
+                       .sid = {
+                               .override = 0x328,
+                               .security = 0x32c,
+                       },
+               },
+       }, {
                .id = TEGRA234_MEMORY_CLIENT_SDMMCWAB,
                .name = "sdmmcwab",
                .sid = TEGRA234_SID_SDMMC4,
index 3993bdd..ed9a683 100644 (file)
@@ -2129,7 +2129,7 @@ static int msb_init_disk(struct memstick_dev *card)
        return 0;
 
 out_cleanup_disk:
-       blk_cleanup_disk(msb->disk);
+       put_disk(msb->disk);
 out_free_tag_set:
        blk_mq_free_tag_set(&msb->tag_set);
 out_release_id:
@@ -2187,7 +2187,6 @@ static void msb_remove(struct memstick_dev *card)
 
        /* Remove the disk */
        del_gendisk(msb->disk);
-       blk_cleanup_queue(msb->queue);
        blk_mq_free_tag_set(&msb->tag_set);
        msb->queue = NULL;
 
index 725ba74..61cf75d 100644 (file)
@@ -1209,7 +1209,7 @@ static int mspro_block_init_disk(struct memstick_dev *card)
        return 0;
 
 out_cleanup_disk:
-       blk_cleanup_disk(msb->disk);
+       put_disk(msb->disk);
 out_free_tag_set:
        blk_mq_free_tag_set(&msb->tag_set);
 out_release_id:
@@ -1294,7 +1294,6 @@ static void mspro_block_remove(struct memstick_dev *card)
        del_gendisk(msb->disk);
        dev_dbg(&card->dev, "mspro block remove\n");
 
-       blk_cleanup_queue(msb->queue);
        blk_mq_free_tag_set(&msb->tag_set);
        msb->queue = NULL;
 
index 42fe67f..49cd1f0 100644 (file)
@@ -25,9 +25,52 @@ static const struct mfd_cell bcm2835_power_devs[] = {
        { .name = "bcm2835-power" },
 };
 
+static int bcm2835_pm_get_pdata(struct platform_device *pdev,
+                               struct bcm2835_pm *pm)
+{
+       if (of_find_property(pm->dev->of_node, "reg-names", NULL)) {
+               struct resource *res;
+
+               pm->base = devm_platform_ioremap_resource_byname(pdev, "pm");
+               if (IS_ERR(pm->base))
+                       return PTR_ERR(pm->base);
+
+               res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "asb");
+               if (res) {
+                       pm->asb = devm_ioremap_resource(&pdev->dev, res);
+                       if (IS_ERR(pm->asb))
+                               pm->asb = NULL;
+               }
+
+               res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                                   "rpivid_asb");
+               if (res) {
+                       pm->rpivid_asb = devm_ioremap_resource(&pdev->dev, res);
+                       if (IS_ERR(pm->rpivid_asb))
+                               pm->rpivid_asb = NULL;
+               }
+
+               return 0;
+       }
+
+       /* If no 'reg-names' property is found we can assume we're using old DTB. */
+       pm->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(pm->base))
+               return PTR_ERR(pm->base);
+
+       pm->asb = devm_platform_ioremap_resource(pdev, 1);
+       if (IS_ERR(pm->asb))
+               pm->asb = NULL;
+
+       pm->rpivid_asb = devm_platform_ioremap_resource(pdev, 2);
+       if (IS_ERR(pm->rpivid_asb))
+               pm->rpivid_asb = NULL;
+
+       return 0;
+}
+
 static int bcm2835_pm_probe(struct platform_device *pdev)
 {
-       struct resource *res;
        struct device *dev = &pdev->dev;
        struct bcm2835_pm *pm;
        int ret;
@@ -39,10 +82,9 @@ static int bcm2835_pm_probe(struct platform_device *pdev)
 
        pm->dev = dev;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       pm->base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(pm->base))
-               return PTR_ERR(pm->base);
+       ret = bcm2835_pm_get_pdata(pdev, pm);
+       if (ret)
+               return ret;
 
        ret = devm_mfd_add_devices(dev, -1,
                                   bcm2835_pm_devs, ARRAY_SIZE(bcm2835_pm_devs),
@@ -50,30 +92,22 @@ static int bcm2835_pm_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       /* We'll use the presence of the AXI ASB regs in the
+       /*
+        * We'll use the presence of the AXI ASB regs in the
         * bcm2835-pm binding as the key for whether we can reference
         * the full PM register range and support power domains.
         */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       if (res) {
-               pm->asb = devm_ioremap_resource(dev, res);
-               if (IS_ERR(pm->asb))
-                       return PTR_ERR(pm->asb);
-
-               ret = devm_mfd_add_devices(dev, -1,
-                                          bcm2835_power_devs,
-                                          ARRAY_SIZE(bcm2835_power_devs),
-                                          NULL, 0, NULL);
-               if (ret)
-                       return ret;
-       }
-
+       if (pm->asb)
+               return devm_mfd_add_devices(dev, -1, bcm2835_power_devs,
+                                           ARRAY_SIZE(bcm2835_power_devs),
+                                           NULL, 0, NULL);
        return 0;
 }
 
 static const struct of_device_id bcm2835_pm_of_match[] = {
        { .compatible = "brcm,bcm2835-pm-wdt", },
        { .compatible = "brcm,bcm2835-pm", },
+       { .compatible = "brcm,bcm2711-pm", },
        {},
 };
 MODULE_DEVICE_TABLE(of, bcm2835_pm_of_match);
index 684a011..8b05820 100644 (file)
@@ -60,12 +60,29 @@ int mfd_cell_disable(struct platform_device *pdev)
 EXPORT_SYMBOL(mfd_cell_disable);
 
 #if IS_ENABLED(CONFIG_ACPI)
+struct match_ids_walk_data {
+       struct acpi_device_id *ids;
+       struct acpi_device *adev;
+};
+
+static int match_device_ids(struct acpi_device *adev, void *data)
+{
+       struct match_ids_walk_data *wd = data;
+
+       if (!acpi_match_device_ids(adev, wd->ids)) {
+               wd->adev = adev;
+               return 1;
+       }
+
+       return 0;
+}
+
 static void mfd_acpi_add_device(const struct mfd_cell *cell,
                                struct platform_device *pdev)
 {
        const struct mfd_cell_acpi_match *match = cell->acpi_match;
-       struct acpi_device *parent, *child;
        struct acpi_device *adev = NULL;
+       struct acpi_device *parent;
 
        parent = ACPI_COMPANION(pdev->dev.parent);
        if (!parent)
@@ -83,14 +100,14 @@ static void mfd_acpi_add_device(const struct mfd_cell *cell,
        if (match) {
                if (match->pnpid) {
                        struct acpi_device_id ids[2] = {};
+                       struct match_ids_walk_data wd = {
+                               .adev = NULL,
+                               .ids = ids,
+                       };
 
                        strlcpy(ids[0].id, match->pnpid, sizeof(ids[0].id));
-                       list_for_each_entry(child, &parent->children, node) {
-                               if (!acpi_match_device_ids(child, ids)) {
-                                       adev = child;
-                                       break;
-                               }
-                       }
+                       acpi_dev_for_each_child(parent, match_device_ids, &wd);
+                       adev = wd.adev;
                } else {
                        adev = acpi_find_child_device(parent, match->adr, false);
                }
index 1ef9b61..f150d87 100644 (file)
@@ -631,16 +631,20 @@ static int rtsx_usb_probe(struct usb_interface *intf,
 
        ucr->pusb_dev = usb_dev;
 
-       ucr->iobuf = usb_alloc_coherent(ucr->pusb_dev, IOBUF_SIZE,
-                       GFP_KERNEL, &ucr->iobuf_dma);
-       if (!ucr->iobuf)
+       ucr->cmd_buf = kmalloc(IOBUF_SIZE, GFP_KERNEL);
+       if (!ucr->cmd_buf)
                return -ENOMEM;
 
+       ucr->rsp_buf = kmalloc(IOBUF_SIZE, GFP_KERNEL);
+       if (!ucr->rsp_buf) {
+               ret = -ENOMEM;
+               goto out_free_cmd_buf;
+       }
+
        usb_set_intfdata(intf, ucr);
 
        ucr->vendor_id = id->idVendor;
        ucr->product_id = id->idProduct;
-       ucr->cmd_buf = ucr->rsp_buf = ucr->iobuf;
 
        mutex_init(&ucr->dev_mutex);
 
@@ -668,8 +672,11 @@ static int rtsx_usb_probe(struct usb_interface *intf,
 
 out_init_fail:
        usb_set_intfdata(ucr->pusb_intf, NULL);
-       usb_free_coherent(ucr->pusb_dev, IOBUF_SIZE, ucr->iobuf,
-                       ucr->iobuf_dma);
+       kfree(ucr->rsp_buf);
+       ucr->rsp_buf = NULL;
+out_free_cmd_buf:
+       kfree(ucr->cmd_buf);
+       ucr->cmd_buf = NULL;
        return ret;
 }
 
@@ -682,8 +689,12 @@ static void rtsx_usb_disconnect(struct usb_interface *intf)
        mfd_remove_devices(&intf->dev);
 
        usb_set_intfdata(ucr->pusb_intf, NULL);
-       usb_free_coherent(ucr->pusb_dev, IOBUF_SIZE, ucr->iobuf,
-                       ucr->iobuf_dma);
+
+       kfree(ucr->cmd_buf);
+       ucr->cmd_buf = NULL;
+
+       kfree(ucr->rsp_buf);
+       ucr->rsp_buf = NULL;
 }
 
 #ifdef CONFIG_PM
index c9c56fd..bdffc65 100644 (file)
@@ -80,10 +80,9 @@ static int at25_ee_read(void *priv, unsigned int offset,
        struct at25_data *at25 = priv;
        char *buf = val;
        size_t max_chunk = spi_max_transfer_size(at25->spi);
-       size_t num_msgs = DIV_ROUND_UP(count, max_chunk);
-       size_t nr_bytes = 0;
-       unsigned int msg_offset;
-       size_t msg_count;
+       unsigned int msg_offset = offset;
+       size_t bytes_left = count;
+       size_t segment;
        u8                      *cp;
        ssize_t                 status;
        struct spi_transfer     t[2];
@@ -97,9 +96,8 @@ static int at25_ee_read(void *priv, unsigned int offset,
        if (unlikely(!count))
                return -EINVAL;
 
-       msg_offset = (unsigned int)offset;
-       msg_count = min(count, max_chunk);
-       while (num_msgs) {
+       do {
+               segment = min(bytes_left, max_chunk);
                cp = at25->command;
 
                instr = AT25_READ;
@@ -131,8 +129,8 @@ static int at25_ee_read(void *priv, unsigned int offset,
                t[0].len = at25->addrlen + 1;
                spi_message_add_tail(&t[0], &m);
 
-               t[1].rx_buf = buf + nr_bytes;
-               t[1].len = msg_count;
+               t[1].rx_buf = buf;
+               t[1].len = segment;
                spi_message_add_tail(&t[1], &m);
 
                status = spi_sync(at25->spi, &m);
@@ -142,10 +140,10 @@ static int at25_ee_read(void *priv, unsigned int offset,
                if (status)
                        return status;
 
-               --num_msgs;
-               msg_offset += msg_count;
-               nr_bytes += msg_count;
-       }
+               msg_offset += segment;
+               buf += segment;
+               bytes_left -= segment;
+       } while (bytes_left > 0);
 
        dev_dbg(&at25->spi->dev, "read %zu bytes at %d\n",
                count, offset);
@@ -229,7 +227,7 @@ static int at25_ee_write(void *priv, unsigned int off, void *val, size_t count)
        do {
                unsigned long   timeout, retries;
                unsigned        segment;
-               unsigned        offset = (unsigned) off;
+               unsigned        offset = off;
                u8              *cp = bounce;
                int             sr;
                u8              instr;
index 2e0aa74..95ef971 100644 (file)
@@ -13,10 +13,13 @@ lkdtm-$(CONFIG_LKDTM)               += cfi.o
 lkdtm-$(CONFIG_LKDTM)          += fortify.o
 lkdtm-$(CONFIG_PPC_64S_HASH_MMU)       += powerpc.o
 
-KASAN_SANITIZE_rodata.o                := n
 KASAN_SANITIZE_stackleak.o     := n
-KCOV_INSTRUMENT_rodata.o       := n
-CFLAGS_REMOVE_rodata.o         += $(CC_FLAGS_LTO)
+
+KASAN_SANITIZE_rodata.o                        := n
+KCSAN_SANITIZE_rodata.o                        := n
+KCOV_INSTRUMENT_rodata.o               := n
+OBJECT_FILES_NON_STANDARD_rodata.o     := y
+CFLAGS_REMOVE_rodata.o                 += $(CC_FLAGS_LTO) $(RETHUNK_CFLAGS)
 
 OBJCOPYFLAGS :=
 OBJCOPYFLAGS_rodata_objcopy.o  := \
index 009239a..48821f4 100644 (file)
@@ -29,7 +29,7 @@ struct lkdtm_list {
 #if defined(CONFIG_FRAME_WARN) && (CONFIG_FRAME_WARN > 0)
 #define REC_STACK_SIZE (_AC(CONFIG_FRAME_WARN, UL) / 2)
 #else
-#define REC_STACK_SIZE (THREAD_SIZE / 8)
+#define REC_STACK_SIZE (THREAD_SIZE / 8UL)
 #endif
 #define REC_NUM_DEFAULT ((THREAD_SIZE / REC_STACK_SIZE) * 2)
 
index f4a1281..e08e22f 100644 (file)
@@ -2505,11 +2505,11 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
                dev_set_drvdata(&card->dev, md);
        ret = device_add_disk(md->parent, md->disk, mmc_disk_attr_groups);
        if (ret)
-               goto err_cleanup_queue;
+               goto err_put_disk;
        return md;
 
- err_cleanup_queue:
-       blk_cleanup_queue(md->disk->queue);
+ err_put_disk:
+       put_disk(md->disk);
        blk_mq_free_tag_set(&md->queue.tag_set);
  err_kfree:
        kfree(md);
index fa5324c..fefaa90 100644 (file)
@@ -116,8 +116,7 @@ static enum blk_eh_timer_return mmc_cqe_timed_out(struct request *req)
        }
 }
 
-static enum blk_eh_timer_return mmc_mq_timed_out(struct request *req,
-                                                bool reserved)
+static enum blk_eh_timer_return mmc_mq_timed_out(struct request *req)
 {
        struct request_queue *q = req->q;
        struct mmc_queue *mq = q->queuedata;
@@ -494,7 +493,6 @@ void mmc_cleanup_queue(struct mmc_queue *mq)
        if (blk_queue_quiesced(q))
                blk_mq_unquiesce_queue(q);
 
-       blk_cleanup_queue(q);
        blk_mq_free_tag_set(&mq->tag_set);
 
        /*
index d614497..10c5639 100644 (file)
@@ -169,8 +169,9 @@ config MMC_SDHCI_OF_ASPEED
          If unsure, say N.
 
 config MMC_SDHCI_OF_ASPEED_TEST
-       bool "Tests for the ASPEED SDHCI driver"
-       depends on MMC_SDHCI_OF_ASPEED && KUNIT=y
+       bool "Tests for the ASPEED SDHCI driver" if !KUNIT_ALL_TESTS
+       depends on MMC_SDHCI_OF_ASPEED && KUNIT
+       default KUNIT_ALL_TESTS
        help
          Enable KUnit tests for the ASPEED SDHCI driver. Select this
          option only if you will boot the kernel for the purpose of running
index c0350e9..4cca4c9 100644 (file)
@@ -775,8 +775,8 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        const struct sdhci_acpi_slot *slot;
-       struct acpi_device *device, *child;
        const struct dmi_system_id *id;
+       struct acpi_device *device;
        struct sdhci_acpi_host *c;
        struct sdhci_host *host;
        struct resource *iomem;
@@ -796,10 +796,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
        slot = sdhci_acpi_get_slot(device);
 
        /* Power on the SDHCI controller and its children */
-       acpi_device_fix_up_power(device);
-       list_for_each_entry(child, &device->children, node)
-               if (child->status.present && child->status.enabled)
-                       acpi_device_fix_up_power(child);
+       acpi_device_fix_up_power_extended(device);
 
        if (sdhci_acpi_byt_defer(dev))
                return -EPROBE_DEFER;
index 1ed4f86..ecb5026 100644 (file)
@@ -96,10 +96,4 @@ static struct kunit_suite aspeed_sdhci_test_suite = {
        .test_cases = aspeed_sdhci_test_cases,
 };
 
-static struct kunit_suite *aspeed_sdc_test_suite_array[] = {
-       &aspeed_sdhci_test_suite,
-       NULL,
-};
-
-static struct kunit_suite **aspeed_sdc_test_suites
-       __used __section(".kunit_test_suites") = aspeed_sdc_test_suite_array;
+kunit_test_suite(aspeed_sdhci_test_suite);
index 6e4e132..ba6677b 100644 (file)
@@ -606,25 +606,6 @@ static struct platform_driver aspeed_sdc_driver = {
 
 #if defined(CONFIG_MMC_SDHCI_OF_ASPEED_TEST)
 #include "sdhci-of-aspeed-test.c"
-
-static inline int aspeed_sdc_tests_init(void)
-{
-       return __kunit_test_suites_init(aspeed_sdc_test_suites);
-}
-
-static inline void aspeed_sdc_tests_exit(void)
-{
-       __kunit_test_suites_exit(aspeed_sdc_test_suites);
-}
-#else
-static inline int aspeed_sdc_tests_init(void)
-{
-       return 0;
-}
-
-static inline void aspeed_sdc_tests_exit(void)
-{
-}
 #endif
 
 static int __init aspeed_sdc_init(void)
@@ -637,18 +618,7 @@ static int __init aspeed_sdc_init(void)
 
        rc = platform_driver_register(&aspeed_sdc_driver);
        if (rc < 0)
-               goto cleanup_sdhci;
-
-       rc = aspeed_sdc_tests_init();
-       if (rc < 0) {
-               platform_driver_unregister(&aspeed_sdc_driver);
-               goto cleanup_sdhci;
-       }
-
-       return 0;
-
-cleanup_sdhci:
-       platform_driver_unregister(&aspeed_sdhci_driver);
+               platform_driver_unregister(&aspeed_sdhci_driver);
 
        return rc;
 }
@@ -656,8 +626,6 @@ module_init(aspeed_sdc_init);
 
 static void __exit aspeed_sdc_exit(void)
 {
-       aspeed_sdc_tests_exit();
-
        platform_driver_unregister(&aspeed_sdc_driver);
        platform_driver_unregister(&aspeed_sdhci_driver);
 }
index 86e867f..033be55 100644 (file)
@@ -1298,8 +1298,9 @@ static int sdhci_omap_probe(struct platform_device *pdev)
        /*
         * omap_device_pm_domain has callbacks to enable the main
         * functional clock, interface clock and also configure the
-        * SYSCONFIG register of omap devices. The callback will be invoked
-        * as part of pm_runtime_get_sync.
+        * SYSCONFIG register to clear any boot loader set voltage
+        * capabilities before calling sdhci_setup_host(). The
+        * callback will be invoked as part of pm_runtime_get_sync.
         */
        pm_runtime_use_autosuspend(dev);
        pm_runtime_set_autosuspend_delay(dev, 50);
@@ -1441,7 +1442,8 @@ static int __maybe_unused sdhci_omap_runtime_suspend(struct device *dev)
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host);
 
-       sdhci_runtime_suspend_host(host);
+       if (omap_host->con != -EINVAL)
+               sdhci_runtime_suspend_host(host);
 
        sdhci_omap_context_save(omap_host);
 
@@ -1458,10 +1460,10 @@ static int __maybe_unused sdhci_omap_runtime_resume(struct device *dev)
 
        pinctrl_pm_select_default_state(dev);
 
-       if (omap_host->con != -EINVAL)
+       if (omap_host->con != -EINVAL) {
                sdhci_omap_context_restore(omap_host);
-
-       sdhci_runtime_resume_host(host, 0);
+               sdhci_runtime_resume_host(host, 0);
+       }
 
        return 0;
 }
index ed53276..622b7de 100644 (file)
@@ -1240,16 +1240,11 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
 #ifdef CONFIG_ACPI
 static void intel_mrfld_mmc_fix_up_power_slot(struct sdhci_pci_slot *slot)
 {
-       struct acpi_device *device, *child;
+       struct acpi_device *device;
 
        device = ACPI_COMPANION(&slot->chip->pdev->dev);
-       if (!device)
-               return;
-
-       acpi_device_fix_up_power(device);
-       list_for_each_entry(child, &device->children, node)
-               if (child->status.present && child->status.enabled)
-                       acpi_device_fix_up_power(child);
+       if (device)
+               acpi_device_fix_up_power_extended(device);
 }
 #else
 static inline void intel_mrfld_mmc_fix_up_power_slot(struct sdhci_pci_slot *slot) {}
index f731721..60b2227 100644 (file)
@@ -29,7 +29,7 @@ static void blktrans_dev_release(struct kref *kref)
        struct mtd_blktrans_dev *dev =
                container_of(kref, struct mtd_blktrans_dev, ref);
 
-       blk_cleanup_disk(dev->disk);
+       put_disk(dev->disk);
        blk_mq_free_tag_set(dev->tag_set);
        kfree(dev->tag_set);
        list_del(&dev->list);
@@ -398,7 +398,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
        return 0;
 
 out_cleanup_disk:
-       blk_cleanup_disk(new->disk);
+       put_disk(new->disk);
 out_free_tag_set:
        blk_mq_free_tag_set(new->tag_set);
 out_kfree_tag_set:
index 889e403..93da236 100644 (file)
@@ -850,9 +850,10 @@ static int gpmi_nfc_compute_timings(struct gpmi_nand_data *this,
        unsigned int tRP_ps;
        bool use_half_period;
        int sample_delay_ps, sample_delay_factor;
-       u16 busy_timeout_cycles;
+       unsigned int busy_timeout_cycles;
        u8 wrn_dly_sel;
        unsigned long clk_rate, min_rate;
+       u64 busy_timeout_ps;
 
        if (sdr->tRC_min >= 30000) {
                /* ONFI non-EDO modes [0-3] */
@@ -885,7 +886,8 @@ static int gpmi_nfc_compute_timings(struct gpmi_nand_data *this,
        addr_setup_cycles = TO_CYCLES(sdr->tALS_min, period_ps);
        data_setup_cycles = TO_CYCLES(sdr->tDS_min, period_ps);
        data_hold_cycles = TO_CYCLES(sdr->tDH_min, period_ps);
-       busy_timeout_cycles = TO_CYCLES(sdr->tWB_max + sdr->tR_max, period_ps);
+       busy_timeout_ps = max(sdr->tBERS_max, sdr->tPROG_max);
+       busy_timeout_cycles = TO_CYCLES(busy_timeout_ps, period_ps);
 
        hw->timing0 = BF_GPMI_TIMING0_ADDRESS_SETUP(addr_setup_cycles) |
                      BF_GPMI_TIMING0_DATA_HOLD(data_hold_cycles) |
index a78fdf3..4cf67a2 100644 (file)
@@ -467,7 +467,7 @@ out_destroy_wq:
 out_remove_minor:
        idr_remove(&ubiblock_minor_idr, gd->first_minor);
 out_cleanup_disk:
-       blk_cleanup_disk(dev->gd);
+       put_disk(dev->gd);
 out_free_tags:
        blk_mq_free_tag_set(&dev->tag_set);
 out_free_dev:
@@ -486,7 +486,7 @@ static void ubiblock_cleanup(struct ubiblock *dev)
        destroy_workqueue(dev->wq);
        /* Finally destroy the blk queue */
        dev_info(disk_to_dev(dev->gd), "released");
-       blk_cleanup_disk(dev->gd);
+       put_disk(dev->gd);
        blk_mq_free_tag_set(&dev->tag_set);
        idr_remove(&ubiblock_minor_idr, dev->gd->first_minor);
 }
index b2a4f99..8c1eeb5 100644 (file)
@@ -94,6 +94,7 @@ config WIREGUARD
        select CRYPTO_CURVE25519_NEON if ARM && KERNEL_MODE_NEON
        select CRYPTO_CHACHA_MIPS if CPU_MIPS32_R2
        select CRYPTO_POLY1305_MIPS if MIPS
+       select CRYPTO_CHACHA_S390 if S390
        help
          WireGuard is a secure, fast, and easy to use replacement for IPSec
          that uses modern cryptography and clever networking tricks. It's
index be2719a..e019526 100644 (file)
@@ -563,7 +563,7 @@ static struct sk_buff *amt_build_igmp_gq(struct amt_dev *amt)
        ihv3->nsrcs     = 0;
        ihv3->resv      = 0;
        ihv3->suppress  = false;
-       ihv3->qrv       = amt->net->ipv4.sysctl_igmp_qrv;
+       ihv3->qrv       = READ_ONCE(amt->net->ipv4.sysctl_igmp_qrv);
        ihv3->csum      = 0;
        csum            = &ihv3->csum;
        csum_start      = (void *)ihv3;
@@ -577,14 +577,14 @@ static struct sk_buff *amt_build_igmp_gq(struct amt_dev *amt)
        return skb;
 }
 
-static void __amt_update_gw_status(struct amt_dev *amt, enum amt_status status,
-                                  bool validate)
+static void amt_update_gw_status(struct amt_dev *amt, enum amt_status status,
+                                bool validate)
 {
        if (validate && amt->status >= status)
                return;
        netdev_dbg(amt->dev, "Update GW status %s -> %s",
                   status_str[amt->status], status_str[status]);
-       amt->status = status;
+       WRITE_ONCE(amt->status, status);
 }
 
 static void __amt_update_relay_status(struct amt_tunnel_list *tunnel,
@@ -600,14 +600,6 @@ static void __amt_update_relay_status(struct amt_tunnel_list *tunnel,
        tunnel->status = status;
 }
 
-static void amt_update_gw_status(struct amt_dev *amt, enum amt_status status,
-                                bool validate)
-{
-       spin_lock_bh(&amt->lock);
-       __amt_update_gw_status(amt, status, validate);
-       spin_unlock_bh(&amt->lock);
-}
-
 static void amt_update_relay_status(struct amt_tunnel_list *tunnel,
                                    enum amt_status status, bool validate)
 {
@@ -700,9 +692,7 @@ static void amt_send_discovery(struct amt_dev *amt)
        if (unlikely(net_xmit_eval(err)))
                amt->dev->stats.tx_errors++;
 
-       spin_lock_bh(&amt->lock);
-       __amt_update_gw_status(amt, AMT_STATUS_SENT_DISCOVERY, true);
-       spin_unlock_bh(&amt->lock);
+       amt_update_gw_status(amt, AMT_STATUS_SENT_DISCOVERY, true);
 out:
        rcu_read_unlock();
 }
@@ -900,6 +890,28 @@ static void amt_send_mld_gq(struct amt_dev *amt, struct amt_tunnel_list *tunnel)
 }
 #endif
 
+static bool amt_queue_event(struct amt_dev *amt, enum amt_event event,
+                           struct sk_buff *skb)
+{
+       int index;
+
+       spin_lock_bh(&amt->lock);
+       if (amt->nr_events >= AMT_MAX_EVENTS) {
+               spin_unlock_bh(&amt->lock);
+               return 1;
+       }
+
+       index = (amt->event_idx + amt->nr_events) % AMT_MAX_EVENTS;
+       amt->events[index].event = event;
+       amt->events[index].skb = skb;
+       amt->nr_events++;
+       amt->event_idx %= AMT_MAX_EVENTS;
+       queue_work(amt_wq, &amt->event_wq);
+       spin_unlock_bh(&amt->lock);
+
+       return 0;
+}
+
 static void amt_secret_work(struct work_struct *work)
 {
        struct amt_dev *amt = container_of(to_delayed_work(work),
@@ -913,58 +925,72 @@ static void amt_secret_work(struct work_struct *work)
                         msecs_to_jiffies(AMT_SECRET_TIMEOUT));
 }
 
-static void amt_discovery_work(struct work_struct *work)
+static void amt_event_send_discovery(struct amt_dev *amt)
 {
-       struct amt_dev *amt = container_of(to_delayed_work(work),
-                                          struct amt_dev,
-                                          discovery_wq);
-
-       spin_lock_bh(&amt->lock);
        if (amt->status > AMT_STATUS_SENT_DISCOVERY)
                goto out;
        get_random_bytes(&amt->nonce, sizeof(__be32));
-       spin_unlock_bh(&amt->lock);
 
        amt_send_discovery(amt);
-       spin_lock_bh(&amt->lock);
 out:
        mod_delayed_work(amt_wq, &amt->discovery_wq,
                         msecs_to_jiffies(AMT_DISCOVERY_TIMEOUT));
-       spin_unlock_bh(&amt->lock);
 }
 
-static void amt_req_work(struct work_struct *work)
+static void amt_discovery_work(struct work_struct *work)
 {
        struct amt_dev *amt = container_of(to_delayed_work(work),
                                           struct amt_dev,
-                                          req_wq);
+                                          discovery_wq);
+
+       if (amt_queue_event(amt, AMT_EVENT_SEND_DISCOVERY, NULL))
+               mod_delayed_work(amt_wq, &amt->discovery_wq,
+                                msecs_to_jiffies(AMT_DISCOVERY_TIMEOUT));
+}
+
+static void amt_event_send_request(struct amt_dev *amt)
+{
        u32 exp;
 
-       spin_lock_bh(&amt->lock);
        if (amt->status < AMT_STATUS_RECEIVED_ADVERTISEMENT)
                goto out;
 
        if (amt->req_cnt > AMT_MAX_REQ_COUNT) {
                netdev_dbg(amt->dev, "Gateway is not ready");
                amt->qi = AMT_INIT_REQ_TIMEOUT;
-               amt->ready4 = false;
-               amt->ready6 = false;
+               WRITE_ONCE(amt->ready4, false);
+               WRITE_ONCE(amt->ready6, false);
                amt->remote_ip = 0;
-               __amt_update_gw_status(amt, AMT_STATUS_INIT, false);
+               amt_update_gw_status(amt, AMT_STATUS_INIT, false);
                amt->req_cnt = 0;
+               amt->nonce = 0;
                goto out;
        }
-       spin_unlock_bh(&amt->lock);
+
+       if (!amt->req_cnt) {
+               WRITE_ONCE(amt->ready4, false);
+               WRITE_ONCE(amt->ready6, false);
+               get_random_bytes(&amt->nonce, sizeof(__be32));
+       }
 
        amt_send_request(amt, false);
        amt_send_request(amt, true);
-       spin_lock_bh(&amt->lock);
-       __amt_update_gw_status(amt, AMT_STATUS_SENT_REQUEST, true);
+       amt_update_gw_status(amt, AMT_STATUS_SENT_REQUEST, true);
        amt->req_cnt++;
 out:
        exp = min_t(u32, (1 * (1 << amt->req_cnt)), AMT_MAX_REQ_TIMEOUT);
        mod_delayed_work(amt_wq, &amt->req_wq, msecs_to_jiffies(exp * 1000));
-       spin_unlock_bh(&amt->lock);
+}
+
+static void amt_req_work(struct work_struct *work)
+{
+       struct amt_dev *amt = container_of(to_delayed_work(work),
+                                          struct amt_dev,
+                                          req_wq);
+
+       if (amt_queue_event(amt, AMT_EVENT_SEND_REQUEST, NULL))
+               mod_delayed_work(amt_wq, &amt->req_wq,
+                                msecs_to_jiffies(100));
 }
 
 static bool amt_send_membership_update(struct amt_dev *amt,
@@ -1220,7 +1246,8 @@ static netdev_tx_t amt_dev_xmit(struct sk_buff *skb, struct net_device *dev)
                /* Gateway only passes IGMP/MLD packets */
                if (!report)
                        goto free;
-               if ((!v6 && !amt->ready4) || (v6 && !amt->ready6))
+               if ((!v6 && !READ_ONCE(amt->ready4)) ||
+                   (v6 && !READ_ONCE(amt->ready6)))
                        goto free;
                if (amt_send_membership_update(amt, skb,  v6))
                        goto free;
@@ -2236,6 +2263,10 @@ static bool amt_advertisement_handler(struct amt_dev *amt, struct sk_buff *skb)
            ipv4_is_zeronet(amta->ip4))
                return true;
 
+       if (amt->status != AMT_STATUS_SENT_DISCOVERY ||
+           amt->nonce != amta->nonce)
+               return true;
+
        amt->remote_ip = amta->ip4;
        netdev_dbg(amt->dev, "advertised remote ip = %pI4\n", &amt->remote_ip);
        mod_delayed_work(amt_wq, &amt->req_wq, 0);
@@ -2251,6 +2282,9 @@ static bool amt_multicast_data_handler(struct amt_dev *amt, struct sk_buff *skb)
        struct ethhdr *eth;
        struct iphdr *iph;
 
+       if (READ_ONCE(amt->status) != AMT_STATUS_SENT_UPDATE)
+               return true;
+
        hdr_size = sizeof(*amtmd) + sizeof(struct udphdr);
        if (!pskb_may_pull(skb, hdr_size))
                return true;
@@ -2325,6 +2359,9 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
        if (amtmq->reserved || amtmq->version)
                return true;
 
+       if (amtmq->nonce != amt->nonce)
+               return true;
+
        hdr_size -= sizeof(*eth);
        if (iptunnel_pull_header(skb, hdr_size, htons(ETH_P_TEB), false))
                return true;
@@ -2339,6 +2376,9 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
 
        iph = ip_hdr(skb);
        if (iph->version == 4) {
+               if (READ_ONCE(amt->ready4))
+                       return true;
+
                if (!pskb_may_pull(skb, sizeof(*iph) + AMT_IPHDR_OPTS +
                                   sizeof(*ihv3)))
                        return true;
@@ -2349,12 +2389,10 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
                ihv3 = skb_pull(skb, sizeof(*iph) + AMT_IPHDR_OPTS);
                skb_reset_transport_header(skb);
                skb_push(skb, sizeof(*iph) + AMT_IPHDR_OPTS);
-               spin_lock_bh(&amt->lock);
-               amt->ready4 = true;
+               WRITE_ONCE(amt->ready4, true);
                amt->mac = amtmq->response_mac;
                amt->req_cnt = 0;
                amt->qi = ihv3->qqic;
-               spin_unlock_bh(&amt->lock);
                skb->protocol = htons(ETH_P_IP);
                eth->h_proto = htons(ETH_P_IP);
                ip_eth_mc_map(iph->daddr, eth->h_dest);
@@ -2363,6 +2401,9 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
                struct mld2_query *mld2q;
                struct ipv6hdr *ip6h;
 
+               if (READ_ONCE(amt->ready6))
+                       return true;
+
                if (!pskb_may_pull(skb, sizeof(*ip6h) + AMT_IP6HDR_OPTS +
                                   sizeof(*mld2q)))
                        return true;
@@ -2374,12 +2415,10 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
                mld2q = skb_pull(skb, sizeof(*ip6h) + AMT_IP6HDR_OPTS);
                skb_reset_transport_header(skb);
                skb_push(skb, sizeof(*ip6h) + AMT_IP6HDR_OPTS);
-               spin_lock_bh(&amt->lock);
-               amt->ready6 = true;
+               WRITE_ONCE(amt->ready6, true);
                amt->mac = amtmq->response_mac;
                amt->req_cnt = 0;
                amt->qi = mld2q->mld2q_qqic;
-               spin_unlock_bh(&amt->lock);
                skb->protocol = htons(ETH_P_IPV6);
                eth->h_proto = htons(ETH_P_IPV6);
                ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest);
@@ -2392,12 +2431,14 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
        skb->pkt_type = PACKET_MULTICAST;
        skb->ip_summed = CHECKSUM_NONE;
        len = skb->len;
+       local_bh_disable();
        if (__netif_rx(skb) == NET_RX_SUCCESS) {
                amt_update_gw_status(amt, AMT_STATUS_RECEIVED_QUERY, true);
                dev_sw_netstats_rx_add(amt->dev, len);
        } else {
                amt->dev->stats.rx_dropped++;
        }
+       local_bh_enable();
 
        return false;
 }
@@ -2638,7 +2679,9 @@ static bool amt_request_handler(struct amt_dev *amt, struct sk_buff *skb)
                if (tunnel->ip4 == iph->saddr)
                        goto send;
 
+       spin_lock_bh(&amt->lock);
        if (amt->nr_tunnels >= amt->max_tunnels) {
+               spin_unlock_bh(&amt->lock);
                icmp_ndo_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
                return true;
        }
@@ -2646,8 +2689,10 @@ static bool amt_request_handler(struct amt_dev *amt, struct sk_buff *skb)
        tunnel = kzalloc(sizeof(*tunnel) +
                         (sizeof(struct hlist_head) * amt->hash_buckets),
                         GFP_ATOMIC);
-       if (!tunnel)
+       if (!tunnel) {
+               spin_unlock_bh(&amt->lock);
                return true;
+       }
 
        tunnel->source_port = udph->source;
        tunnel->ip4 = iph->saddr;
@@ -2660,10 +2705,9 @@ static bool amt_request_handler(struct amt_dev *amt, struct sk_buff *skb)
 
        INIT_DELAYED_WORK(&tunnel->gc_wq, amt_tunnel_expire);
 
-       spin_lock_bh(&amt->lock);
        list_add_tail_rcu(&tunnel->list, &amt->tunnel_list);
        tunnel->key = amt->key;
-       amt_update_relay_status(tunnel, AMT_STATUS_RECEIVED_REQUEST, true);
+       __amt_update_relay_status(tunnel, AMT_STATUS_RECEIVED_REQUEST, true);
        amt->nr_tunnels++;
        mod_delayed_work(amt_wq, &tunnel->gc_wq,
                         msecs_to_jiffies(amt_gmi(amt)));
@@ -2688,6 +2732,38 @@ send:
        return false;
 }
 
+static void amt_gw_rcv(struct amt_dev *amt, struct sk_buff *skb)
+{
+       int type = amt_parse_type(skb);
+       int err = 1;
+
+       if (type == -1)
+               goto drop;
+
+       if (amt->mode == AMT_MODE_GATEWAY) {
+               switch (type) {
+               case AMT_MSG_ADVERTISEMENT:
+                       err = amt_advertisement_handler(amt, skb);
+                       break;
+               case AMT_MSG_MEMBERSHIP_QUERY:
+                       err = amt_membership_query_handler(amt, skb);
+                       if (!err)
+                               return;
+                       break;
+               default:
+                       netdev_dbg(amt->dev, "Invalid type of Gateway\n");
+                       break;
+               }
+       }
+drop:
+       if (err) {
+               amt->dev->stats.rx_dropped++;
+               kfree_skb(skb);
+       } else {
+               consume_skb(skb);
+       }
+}
+
 static int amt_rcv(struct sock *sk, struct sk_buff *skb)
 {
        struct amt_dev *amt;
@@ -2719,8 +2795,12 @@ static int amt_rcv(struct sock *sk, struct sk_buff *skb)
                                err = true;
                                goto drop;
                        }
-                       err = amt_advertisement_handler(amt, skb);
-                       break;
+                       if (amt_queue_event(amt, AMT_EVENT_RECEIVE, skb)) {
+                               netdev_dbg(amt->dev, "AMT Event queue full\n");
+                               err = true;
+                               goto drop;
+                       }
+                       goto out;
                case AMT_MSG_MULTICAST_DATA:
                        if (iph->saddr != amt->remote_ip) {
                                netdev_dbg(amt->dev, "Invalid Relay IP\n");
@@ -2738,11 +2818,12 @@ static int amt_rcv(struct sock *sk, struct sk_buff *skb)
                                err = true;
                                goto drop;
                        }
-                       err = amt_membership_query_handler(amt, skb);
-                       if (err)
+                       if (amt_queue_event(amt, AMT_EVENT_RECEIVE, skb)) {
+                               netdev_dbg(amt->dev, "AMT Event queue full\n");
+                               err = true;
                                goto drop;
-                       else
-                               goto out;
+                       }
+                       goto out;
                default:
                        err = true;
                        netdev_dbg(amt->dev, "Invalid type of Gateway\n");
@@ -2780,6 +2861,46 @@ out:
        return 0;
 }
 
+static void amt_event_work(struct work_struct *work)
+{
+       struct amt_dev *amt = container_of(work, struct amt_dev, event_wq);
+       struct sk_buff *skb;
+       u8 event;
+       int i;
+
+       for (i = 0; i < AMT_MAX_EVENTS; i++) {
+               spin_lock_bh(&amt->lock);
+               if (amt->nr_events == 0) {
+                       spin_unlock_bh(&amt->lock);
+                       return;
+               }
+               event = amt->events[amt->event_idx].event;
+               skb = amt->events[amt->event_idx].skb;
+               amt->events[amt->event_idx].event = AMT_EVENT_NONE;
+               amt->events[amt->event_idx].skb = NULL;
+               amt->nr_events--;
+               amt->event_idx++;
+               amt->event_idx %= AMT_MAX_EVENTS;
+               spin_unlock_bh(&amt->lock);
+
+               switch (event) {
+               case AMT_EVENT_RECEIVE:
+                       amt_gw_rcv(amt, skb);
+                       break;
+               case AMT_EVENT_SEND_DISCOVERY:
+                       amt_event_send_discovery(amt);
+                       break;
+               case AMT_EVENT_SEND_REQUEST:
+                       amt_event_send_request(amt);
+                       break;
+               default:
+                       if (skb)
+                               kfree_skb(skb);
+                       break;
+               }
+       }
+}
+
 static int amt_err_lookup(struct sock *sk, struct sk_buff *skb)
 {
        struct amt_dev *amt;
@@ -2804,7 +2925,7 @@ static int amt_err_lookup(struct sock *sk, struct sk_buff *skb)
                break;
        case AMT_MSG_REQUEST:
        case AMT_MSG_MEMBERSHIP_UPDATE:
-               if (amt->status >= AMT_STATUS_RECEIVED_ADVERTISEMENT)
+               if (READ_ONCE(amt->status) >= AMT_STATUS_RECEIVED_ADVERTISEMENT)
                        mod_delayed_work(amt_wq, &amt->req_wq, 0);
                break;
        default:
@@ -2867,6 +2988,8 @@ static int amt_dev_open(struct net_device *dev)
 
        amt->ready4 = false;
        amt->ready6 = false;
+       amt->event_idx = 0;
+       amt->nr_events = 0;
 
        err = amt_socket_create(amt);
        if (err)
@@ -2874,6 +2997,7 @@ static int amt_dev_open(struct net_device *dev)
 
        amt->req_cnt = 0;
        amt->remote_ip = 0;
+       amt->nonce = 0;
        get_random_bytes(&amt->key, sizeof(siphash_key_t));
 
        amt->status = AMT_STATUS_INIT;
@@ -2892,6 +3016,8 @@ static int amt_dev_stop(struct net_device *dev)
        struct amt_dev *amt = netdev_priv(dev);
        struct amt_tunnel_list *tunnel, *tmp;
        struct socket *sock;
+       struct sk_buff *skb;
+       int i;
 
        cancel_delayed_work_sync(&amt->req_wq);
        cancel_delayed_work_sync(&amt->discovery_wq);
@@ -2904,6 +3030,15 @@ static int amt_dev_stop(struct net_device *dev)
        if (sock)
                udp_tunnel_sock_release(sock);
 
+       cancel_work_sync(&amt->event_wq);
+       for (i = 0; i < AMT_MAX_EVENTS; i++) {
+               skb = amt->events[i].skb;
+               if (skb)
+                       kfree_skb(skb);
+               amt->events[i].event = AMT_EVENT_NONE;
+               amt->events[i].skb = NULL;
+       }
+
        amt->ready4 = false;
        amt->ready6 = false;
        amt->req_cnt = 0;
@@ -3095,7 +3230,7 @@ static int amt_newlink(struct net *net, struct net_device *dev,
                goto err;
        }
        if (amt->mode == AMT_MODE_RELAY) {
-               amt->qrv = amt->net->ipv4.sysctl_igmp_qrv;
+               amt->qrv = READ_ONCE(amt->net->ipv4.sysctl_igmp_qrv);
                amt->qri = 10;
                dev->needed_headroom = amt->stream_dev->needed_headroom +
                                       AMT_RELAY_HLEN;
@@ -3146,8 +3281,8 @@ static int amt_newlink(struct net *net, struct net_device *dev,
        INIT_DELAYED_WORK(&amt->discovery_wq, amt_discovery_work);
        INIT_DELAYED_WORK(&amt->req_wq, amt_req_work);
        INIT_DELAYED_WORK(&amt->secret_wq, amt_secret_work);
+       INIT_WORK(&amt->event_wq, amt_event_work);
        INIT_LIST_HEAD(&amt->tunnel_list);
-
        return 0;
 err:
        dev_put(amt->stream_dev);
@@ -3280,7 +3415,7 @@ static int __init amt_init(void)
        if (err < 0)
                goto unregister_notifier;
 
-       amt_wq = alloc_workqueue("amt", WQ_UNBOUND, 1);
+       amt_wq = alloc_workqueue("amt", WQ_UNBOUND, 0);
        if (!amt_wq) {
                err = -ENOMEM;
                goto rtnl_unregister;
index a86b1f7..d7fb33c 100644 (file)
@@ -2228,7 +2228,8 @@ void bond_3ad_unbind_slave(struct slave *slave)
                                temp_aggregator->num_of_ports--;
                                if (__agg_active_ports(temp_aggregator) == 0) {
                                        select_new_active_agg = temp_aggregator->is_active;
-                                       ad_clear_agg(temp_aggregator);
+                                       if (temp_aggregator->num_of_ports == 0)
+                                               ad_clear_agg(temp_aggregator);
                                        if (select_new_active_agg) {
                                                slave_info(bond->dev, slave->dev, "Removing an active aggregator\n");
                                                /* select new active aggregator */
index 303c8d3..007d43e 100644 (file)
@@ -1302,12 +1302,12 @@ int bond_alb_initialize(struct bonding *bond, int rlb_enabled)
                return res;
 
        if (rlb_enabled) {
-               bond->alb_info.rlb_enabled = 1;
                res = rlb_initialize(bond);
                if (res) {
                        tlb_deinitialize(bond);
                        return res;
                }
+               bond->alb_info.rlb_enabled = 1;
        } else {
                bond->alb_info.rlb_enabled = 0;
        }
index 5458f57..0b0f234 100644 (file)
@@ -722,13 +722,21 @@ static int cfv_probe(struct virtio_device *vdev)
        /* Carrier is off until netdevice is opened */
        netif_carrier_off(netdev);
 
+       /* serialize netdev register + virtio_device_ready() with ndo_open() */
+       rtnl_lock();
+
        /* register Netdev */
-       err = register_netdev(netdev);
+       err = register_netdevice(netdev);
        if (err) {
+               rtnl_unlock();
                dev_err(&vdev->dev, "Unable to register netdev (%d)\n", err);
                goto err;
        }
 
+       virtio_device_ready(vdev);
+
+       rtnl_unlock();
+
        debugfs_init(cfv);
 
        return 0;
index 76df480..4c47c10 100644 (file)
@@ -1646,7 +1646,6 @@ static int grcan_probe(struct platform_device *ofdev)
         */
        sysid_parent = of_find_node_by_path("/ambapp0");
        if (sysid_parent) {
-               of_node_get(sysid_parent);
                err = of_property_read_u32(sysid_parent, "systemid", &sysid);
                if (!err && ((sysid & GRLIB_VERSION_MASK) >=
                             GRCAN_TXBUG_SAFE_GRLIB_VERSION))
index 5d0c82d..7931f9c 100644 (file)
@@ -529,7 +529,7 @@ static int m_can_read_fifo(struct net_device *dev, u32 rxfs)
        /* acknowledge rx fifo 0 */
        m_can_write(cdev, M_CAN_RXF0A, fgi);
 
-       timestamp = FIELD_GET(RX_BUF_RXTS_MASK, fifo_header.dlc);
+       timestamp = FIELD_GET(RX_BUF_RXTS_MASK, fifo_header.dlc) << 16;
 
        m_can_receive_skb(cdev, skb, timestamp);
 
@@ -1030,7 +1030,7 @@ static int m_can_echo_tx_event(struct net_device *dev)
                }
 
                msg_mark = FIELD_GET(TX_EVENT_MM_MASK, txe);
-               timestamp = FIELD_GET(TX_EVENT_TXTS_MASK, txe);
+               timestamp = FIELD_GET(TX_EVENT_TXTS_MASK, txe) << 16;
 
                /* ack txe element */
                m_can_write(cdev, M_CAN_TXEFA, FIELD_PREP(TXEFA_EFAI_MASK,
@@ -1351,7 +1351,9 @@ static void m_can_chip_config(struct net_device *dev)
        /* enable internal timestamp generation, with a prescalar of 16. The
         * prescalar is applied to the nominal bit timing
         */
-       m_can_write(cdev, M_CAN_TSCC, FIELD_PREP(TSCC_TCP_MASK, 0xf));
+       m_can_write(cdev, M_CAN_TSCC,
+                   FIELD_PREP(TSCC_TCP_MASK, 0xf) |
+                   FIELD_PREP(TSCC_TSS_MASK, TSCC_TSS_INTERNAL));
 
        m_can_config_endisable(cdev, false);
 
index 40a1144..cb0321e 100644 (file)
@@ -1332,7 +1332,10 @@ static void rcar_canfd_set_bittiming(struct net_device *dev)
                cfg = (RCANFD_DCFG_DTSEG1(gpriv, tseg1) | RCANFD_DCFG_DBRP(brp) |
                       RCANFD_DCFG_DSJW(sjw) | RCANFD_DCFG_DTSEG2(gpriv, tseg2));
 
-               rcar_canfd_write(priv->base, RCANFD_F_DCFG(ch), cfg);
+               if (is_v3u(gpriv))
+                       rcar_canfd_write(priv->base, RCANFD_V3U_DCFG(ch), cfg);
+               else
+                       rcar_canfd_write(priv->base, RCANFD_F_DCFG(ch), cfg);
                netdev_dbg(priv->ndev, "drate: brp %u, sjw %u, tseg1 %u, tseg2 %u\n",
                           brp, sjw, tseg1, tseg2);
        } else {
@@ -1840,6 +1843,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)
                of_child = of_get_child_by_name(pdev->dev.of_node, name);
                if (of_child && of_device_is_available(of_child))
                        channels_mask |= BIT(i);
+               of_node_put(of_child);
        }
 
        if (chip_id != RENESAS_RZG2L) {
index b212523..bc65185 100644 (file)
@@ -12,6 +12,7 @@
 // Copyright (c) 2019 Martin Sperl <kernel@martin.sperl.org>
 //
 
+#include <asm/unaligned.h>
 #include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/device.h>
@@ -1650,6 +1651,7 @@ static int mcp251xfd_stop(struct net_device *ndev)
        netif_stop_queue(ndev);
        set_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
        hrtimer_cancel(&priv->rx_irq_timer);
+       hrtimer_cancel(&priv->tx_irq_timer);
        mcp251xfd_chip_interrupts_disable(priv);
        free_irq(ndev->irq, priv);
        can_rx_offload_disable(&priv->offload);
@@ -1688,8 +1690,8 @@ static int mcp251xfd_register_chip_detect(struct mcp251xfd_priv *priv)
        u32 osc;
        int err;
 
-       /* The OSC_LPMEN is only supported on MCP2518FD, so use it to
-        * autodetect the model.
+       /* The OSC_LPMEN is only supported on MCP2518FD and MCP251863,
+        * so use it to autodetect the model.
         */
        err = regmap_update_bits(priv->map_reg, MCP251XFD_REG_OSC,
                                 MCP251XFD_REG_OSC_LPMEN,
@@ -1701,10 +1703,18 @@ static int mcp251xfd_register_chip_detect(struct mcp251xfd_priv *priv)
        if (err)
                return err;
 
-       if (osc & MCP251XFD_REG_OSC_LPMEN)
-               devtype_data = &mcp251xfd_devtype_data_mcp2518fd;
-       else
+       if (osc & MCP251XFD_REG_OSC_LPMEN) {
+               /* We cannot distinguish between MCP2518FD and
+                * MCP251863. If firmware specifies MCP251863, keep
+                * it, otherwise set to MCP2518FD.
+                */
+               if (mcp251xfd_is_251863(priv))
+                       devtype_data = &mcp251xfd_devtype_data_mcp251863;
+               else
+                       devtype_data = &mcp251xfd_devtype_data_mcp2518fd;
+       } else {
                devtype_data = &mcp251xfd_devtype_data_mcp2517fd;
+       }
 
        if (!mcp251xfd_is_251XFD(priv) &&
            priv->devtype_data.model != devtype_data->model) {
@@ -1777,7 +1787,7 @@ mcp251xfd_register_get_dev_id(const struct mcp251xfd_priv *priv, u32 *dev_id,
        xfer[0].len = sizeof(buf_tx->cmd);
        xfer[0].speed_hz = priv->spi_max_speed_hz_slow;
        xfer[1].rx_buf = buf_rx->data;
-       xfer[1].len = sizeof(dev_id);
+       xfer[1].len = sizeof(*dev_id);
        xfer[1].speed_hz = priv->spi_max_speed_hz_fast;
 
        mcp251xfd_spi_cmd_read_nocrc(&buf_tx->cmd, MCP251XFD_REG_DEVID);
@@ -1786,7 +1796,7 @@ mcp251xfd_register_get_dev_id(const struct mcp251xfd_priv *priv, u32 *dev_id,
        if (err)
                goto out_kfree_buf_tx;
 
-       *dev_id = be32_to_cpup((__be32 *)buf_rx->data);
+       *dev_id = get_unaligned_le32(buf_rx->data);
        *effective_speed_hz_slow = xfer[0].effective_speed_hz;
        *effective_speed_hz_fast = xfer[1].effective_speed_hz;
 
index 217510c..92b7bc7 100644 (file)
@@ -334,19 +334,21 @@ mcp251xfd_regmap_crc_read(void *context,
                 * register. It increments once per SYS clock tick,
                 * which is 20 or 40 MHz.
                 *
-                * Observation shows that if the lowest byte (which is
-                * transferred first on the SPI bus) of that register
-                * is 0x00 or 0x80 the calculated CRC doesn't always
-                * match the transferred one.
+                * Observation on the mcp2518fd shows that if the
+                * lowest byte (which is transferred first on the SPI
+                * bus) of that register is 0x00 or 0x80 the
+                * calculated CRC doesn't always match the transferred
+                * one. On the mcp2517fd this problem is not limited
+                * to the first byte being 0x00 or 0x80.
                 *
                 * If the highest bit in the lowest byte is flipped
                 * the transferred CRC matches the calculated one. We
-                * assume for now the CRC calculation in the chip
-                * works on wrong data and the transferred data is
-                * correct.
+                * assume for now the CRC operates on the correct
+                * data.
                 */
                if (reg == MCP251XFD_REG_TBC &&
-                   (buf_rx->data[0] == 0x0 || buf_rx->data[0] == 0x80)) {
+                   ((buf_rx->data[0] & 0xf8) == 0x0 ||
+                    (buf_rx->data[0] & 0xf8) == 0x80)) {
                        /* Flip highest bit in lowest byte of le32 */
                        buf_rx->data[0] ^= 0x80;
 
@@ -356,10 +358,8 @@ mcp251xfd_regmap_crc_read(void *context,
                                                                  val_len);
                        if (!err) {
                                /* If CRC is now correct, assume
-                                * transferred data was OK, flip bit
-                                * back to original value.
+                                * flipped data is OK.
                                 */
-                               buf_rx->data[0] ^= 0x80;
                                goto out;
                        }
                }
index b29ba91..d3a658b 100644 (file)
@@ -268,6 +268,8 @@ struct gs_can {
 
        struct usb_anchor tx_submitted;
        atomic_t active_tx_urbs;
+       void *rxbuf[GS_MAX_RX_URBS];
+       dma_addr_t rxbuf_dma[GS_MAX_RX_URBS];
 };
 
 /* usb interface struct */
@@ -742,6 +744,7 @@ static int gs_can_open(struct net_device *netdev)
                for (i = 0; i < GS_MAX_RX_URBS; i++) {
                        struct urb *urb;
                        u8 *buf;
+                       dma_addr_t buf_dma;
 
                        /* alloc rx urb */
                        urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -752,7 +755,7 @@ static int gs_can_open(struct net_device *netdev)
                        buf = usb_alloc_coherent(dev->udev,
                                                 dev->parent->hf_size_rx,
                                                 GFP_KERNEL,
-                                                &urb->transfer_dma);
+                                                &buf_dma);
                        if (!buf) {
                                netdev_err(netdev,
                                           "No memory left for USB buffer\n");
@@ -760,6 +763,8 @@ static int gs_can_open(struct net_device *netdev)
                                return -ENOMEM;
                        }
 
+                       urb->transfer_dma = buf_dma;
+
                        /* fill, anchor, and submit rx urb */
                        usb_fill_bulk_urb(urb,
                                          dev->udev,
@@ -781,10 +786,17 @@ static int gs_can_open(struct net_device *netdev)
                                           "usb_submit failed (err=%d)\n", rc);
 
                                usb_unanchor_urb(urb);
+                               usb_free_coherent(dev->udev,
+                                                 sizeof(struct gs_host_frame),
+                                                 buf,
+                                                 buf_dma);
                                usb_free_urb(urb);
                                break;
                        }
 
+                       dev->rxbuf[i] = buf;
+                       dev->rxbuf_dma[i] = buf_dma;
+
                        /* Drop reference,
                         * USB core will take care of freeing it
                         */
@@ -842,13 +854,20 @@ static int gs_can_close(struct net_device *netdev)
        int rc;
        struct gs_can *dev = netdev_priv(netdev);
        struct gs_usb *parent = dev->parent;
+       unsigned int i;
 
        netif_stop_queue(netdev);
 
        /* Stop polling */
        parent->active_channels--;
-       if (!parent->active_channels)
+       if (!parent->active_channels) {
                usb_kill_anchored_urbs(&parent->rx_submitted);
+               for (i = 0; i < GS_MAX_RX_URBS; i++)
+                       usb_free_coherent(dev->udev,
+                                         sizeof(struct gs_host_frame),
+                                         dev->rxbuf[i],
+                                         dev->rxbuf_dma[i]);
+       }
 
        /* Stop sending URBs */
        usb_kill_anchored_urbs(&dev->tx_submitted);
index 3a49257..eefcbe3 100644 (file)
 #define KVASER_USB_RX_BUFFER_SIZE              3072
 #define KVASER_USB_MAX_NET_DEVICES             5
 
-/* USB devices features */
-#define KVASER_USB_HAS_SILENT_MODE             BIT(0)
-#define KVASER_USB_HAS_TXRX_ERRORS             BIT(1)
+/* Kvaser USB device quirks */
+#define KVASER_USB_QUIRK_HAS_SILENT_MODE       BIT(0)
+#define KVASER_USB_QUIRK_HAS_TXRX_ERRORS       BIT(1)
+#define KVASER_USB_QUIRK_IGNORE_CLK_FREQ       BIT(2)
 
 /* Device capabilities */
 #define KVASER_USB_CAP_BERR_CAP                        0x01
@@ -65,12 +66,7 @@ struct kvaser_usb_dev_card_data_hydra {
 struct kvaser_usb_dev_card_data {
        u32 ctrlmode_supported;
        u32 capabilities;
-       union {
-               struct {
-                       enum kvaser_usb_leaf_family family;
-               } leaf;
-               struct kvaser_usb_dev_card_data_hydra hydra;
-       };
+       struct kvaser_usb_dev_card_data_hydra hydra;
 };
 
 /* Context for an outstanding, not yet ACKed, transmission */
@@ -83,7 +79,7 @@ struct kvaser_usb {
        struct usb_device *udev;
        struct usb_interface *intf;
        struct kvaser_usb_net_priv *nets[KVASER_USB_MAX_NET_DEVICES];
-       const struct kvaser_usb_dev_ops *ops;
+       const struct kvaser_usb_driver_info *driver_info;
        const struct kvaser_usb_dev_cfg *cfg;
 
        struct usb_endpoint_descriptor *bulk_in, *bulk_out;
@@ -165,6 +161,12 @@ struct kvaser_usb_dev_ops {
                                  u16 transid);
 };
 
+struct kvaser_usb_driver_info {
+       u32 quirks;
+       enum kvaser_usb_leaf_family family;
+       const struct kvaser_usb_dev_ops *ops;
+};
+
 struct kvaser_usb_dev_cfg {
        const struct can_clock clock;
        const unsigned int timestamp_freq;
@@ -184,4 +186,7 @@ int kvaser_usb_send_cmd_async(struct kvaser_usb_net_priv *priv, void *cmd,
                              int len);
 
 int kvaser_usb_can_rx_over_error(struct net_device *netdev);
+
+extern const struct can_bittiming_const kvaser_usb_flexc_bittiming_const;
+
 #endif /* KVASER_USB_H */
index e67658b..f211bfc 100644 (file)
@@ -61,8 +61,6 @@
 #define USB_USBCAN_R_V2_PRODUCT_ID             294
 #define USB_LEAF_LIGHT_R_V2_PRODUCT_ID         295
 #define USB_LEAF_LIGHT_HS_V2_OEM2_PRODUCT_ID   296
-#define USB_LEAF_PRODUCT_ID_END \
-       USB_LEAF_LIGHT_HS_V2_OEM2_PRODUCT_ID
 
 /* Kvaser USBCan-II devices product ids */
 #define USB_USBCAN_REVB_PRODUCT_ID             2
 #define USB_USBCAN_PRO_4HS_PRODUCT_ID          276
 #define USB_HYBRID_CANLIN_PRODUCT_ID           277
 #define USB_HYBRID_PRO_CANLIN_PRODUCT_ID       278
-#define USB_HYDRA_PRODUCT_ID_END \
-       USB_HYBRID_PRO_CANLIN_PRODUCT_ID
 
-static inline bool kvaser_is_leaf(const struct usb_device_id *id)
-{
-       return (id->idProduct >= USB_LEAF_DEVEL_PRODUCT_ID &&
-               id->idProduct <= USB_CAN_R_PRODUCT_ID) ||
-               (id->idProduct >= USB_LEAF_LITE_V2_PRODUCT_ID &&
-                id->idProduct <= USB_LEAF_PRODUCT_ID_END);
-}
+static const struct kvaser_usb_driver_info kvaser_usb_driver_info_hydra = {
+       .quirks = 0,
+       .ops = &kvaser_usb_hydra_dev_ops,
+};
 
-static inline bool kvaser_is_usbcan(const struct usb_device_id *id)
-{
-       return id->idProduct >= USB_USBCAN_REVB_PRODUCT_ID &&
-              id->idProduct <= USB_MEMORATOR_PRODUCT_ID;
-}
+static const struct kvaser_usb_driver_info kvaser_usb_driver_info_usbcan = {
+       .quirks = KVASER_USB_QUIRK_HAS_TXRX_ERRORS |
+                 KVASER_USB_QUIRK_HAS_SILENT_MODE,
+       .family = KVASER_USBCAN,
+       .ops = &kvaser_usb_leaf_dev_ops,
+};
 
-static inline bool kvaser_is_hydra(const struct usb_device_id *id)
-{
-       return id->idProduct >= USB_BLACKBIRD_V2_PRODUCT_ID &&
-              id->idProduct <= USB_HYDRA_PRODUCT_ID_END;
-}
+static const struct kvaser_usb_driver_info kvaser_usb_driver_info_leaf = {
+       .quirks = KVASER_USB_QUIRK_IGNORE_CLK_FREQ,
+       .family = KVASER_LEAF,
+       .ops = &kvaser_usb_leaf_dev_ops,
+};
+
+static const struct kvaser_usb_driver_info kvaser_usb_driver_info_leaf_err = {
+       .quirks = KVASER_USB_QUIRK_HAS_TXRX_ERRORS |
+                 KVASER_USB_QUIRK_IGNORE_CLK_FREQ,
+       .family = KVASER_LEAF,
+       .ops = &kvaser_usb_leaf_dev_ops,
+};
+
+static const struct kvaser_usb_driver_info kvaser_usb_driver_info_leaf_err_listen = {
+       .quirks = KVASER_USB_QUIRK_HAS_TXRX_ERRORS |
+                 KVASER_USB_QUIRK_HAS_SILENT_MODE |
+                 KVASER_USB_QUIRK_IGNORE_CLK_FREQ,
+       .family = KVASER_LEAF,
+       .ops = &kvaser_usb_leaf_dev_ops,
+};
+
+static const struct kvaser_usb_driver_info kvaser_usb_driver_info_leafimx = {
+       .quirks = 0,
+       .ops = &kvaser_usb_leaf_dev_ops,
+};
 
 static const struct usb_device_id kvaser_usb_table[] = {
-       /* Leaf USB product IDs */
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID) },
+       /* Leaf M32C USB product IDs */
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LS_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_SWC_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LIN_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_LS_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_SWC_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_DEVEL_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSHS_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_UPRO_HSHS_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_GI_PRODUCT_ID) },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_GI_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_OBDII_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSLS_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_CH_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_SPRO_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_MERCURY_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_LEAF_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_CAN_R_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_2HS_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_2HS_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_R_V2_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_R_V2_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM2_PRODUCT_ID) },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
+
+       /* Leaf i.MX28 USB product IDs */
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_2HS_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_2HS_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_R_V2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_R_V2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
 
        /* USBCANII USB product IDs */
        { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN2_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_usbcan },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_REVB_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_usbcan },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMORATOR_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_usbcan },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_VCI2_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_usbcan },
 
        /* Minihydra USB product IDs */
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_V2_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_PRO_5HS_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_5HS_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_4HS_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_HS_V2_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_2HS_V2_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_2HS_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_PRO_2HS_V2_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_2CANLIN_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_USBCAN_PRO_2HS_V2_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_MEMO_PRO_2HS_V2_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_PRO_2CANLIN_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_U100_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_U100P_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_U100S_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_4HS_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_CANLIN_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_PRO_CANLIN_PRODUCT_ID) },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_V2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_PRO_5HS_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_5HS_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_4HS_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_HS_V2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_2HS_V2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_2HS_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_PRO_2HS_V2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_2CANLIN_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_USBCAN_PRO_2HS_V2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_MEMO_PRO_2HS_V2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_PRO_2CANLIN_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_U100_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_U100P_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_U100S_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_4HS_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_CANLIN_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_PRO_CANLIN_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
        { }
 };
 MODULE_DEVICE_TABLE(usb, kvaser_usb_table);
@@ -285,6 +320,7 @@ int kvaser_usb_can_rx_over_error(struct net_device *netdev)
 static void kvaser_usb_read_bulk_callback(struct urb *urb)
 {
        struct kvaser_usb *dev = urb->context;
+       const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
        int err;
        unsigned int i;
 
@@ -301,8 +337,8 @@ static void kvaser_usb_read_bulk_callback(struct urb *urb)
                goto resubmit_urb;
        }
 
-       dev->ops->dev_read_bulk_callback(dev, urb->transfer_buffer,
-                                        urb->actual_length);
+       ops->dev_read_bulk_callback(dev, urb->transfer_buffer,
+                                   urb->actual_length);
 
 resubmit_urb:
        usb_fill_bulk_urb(urb, dev->udev,
@@ -396,6 +432,7 @@ static int kvaser_usb_open(struct net_device *netdev)
 {
        struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
        struct kvaser_usb *dev = priv->dev;
+       const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
        int err;
 
        err = open_candev(netdev);
@@ -406,11 +443,11 @@ static int kvaser_usb_open(struct net_device *netdev)
        if (err)
                goto error;
 
-       err = dev->ops->dev_set_opt_mode(priv);
+       err = ops->dev_set_opt_mode(priv);
        if (err)
                goto error;
 
-       err = dev->ops->dev_start_chip(priv);
+       err = ops->dev_start_chip(priv);
        if (err) {
                netdev_warn(netdev, "Cannot start device, error %d\n", err);
                goto error;
@@ -467,22 +504,23 @@ static int kvaser_usb_close(struct net_device *netdev)
 {
        struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
        struct kvaser_usb *dev = priv->dev;
+       const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
        int err;
 
        netif_stop_queue(netdev);
 
-       err = dev->ops->dev_flush_queue(priv);
+       err = ops->dev_flush_queue(priv);
        if (err)
                netdev_warn(netdev, "Cannot flush queue, error %d\n", err);
 
-       if (dev->ops->dev_reset_chip) {
-               err = dev->ops->dev_reset_chip(dev, priv->channel);
+       if (ops->dev_reset_chip) {
+               err = ops->dev_reset_chip(dev, priv->channel);
                if (err)
                        netdev_warn(netdev, "Cannot reset card, error %d\n",
                                    err);
        }
 
-       err = dev->ops->dev_stop_chip(priv);
+       err = ops->dev_stop_chip(priv);
        if (err)
                netdev_warn(netdev, "Cannot stop device, error %d\n", err);
 
@@ -521,6 +559,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
 {
        struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
        struct kvaser_usb *dev = priv->dev;
+       const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
        struct net_device_stats *stats = &netdev->stats;
        struct kvaser_usb_tx_urb_context *context = NULL;
        struct urb *urb;
@@ -563,8 +602,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
                goto freeurb;
        }
 
-       buf = dev->ops->dev_frame_to_cmd(priv, skb, &cmd_len,
-                                        context->echo_index);
+       buf = ops->dev_frame_to_cmd(priv, skb, &cmd_len, context->echo_index);
        if (!buf) {
                stats->tx_dropped++;
                dev_kfree_skb(skb);
@@ -648,15 +686,16 @@ static void kvaser_usb_remove_interfaces(struct kvaser_usb *dev)
        }
 }
 
-static int kvaser_usb_init_one(struct kvaser_usb *dev,
-                              const struct usb_device_id *id, int channel)
+static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel)
 {
        struct net_device *netdev;
        struct kvaser_usb_net_priv *priv;
+       const struct kvaser_usb_driver_info *driver_info = dev->driver_info;
+       const struct kvaser_usb_dev_ops *ops = driver_info->ops;
        int err;
 
-       if (dev->ops->dev_reset_chip) {
-               err = dev->ops->dev_reset_chip(dev, channel);
+       if (ops->dev_reset_chip) {
+               err = ops->dev_reset_chip(dev, channel);
                if (err)
                        return err;
        }
@@ -685,20 +724,19 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev,
        priv->can.state = CAN_STATE_STOPPED;
        priv->can.clock.freq = dev->cfg->clock.freq;
        priv->can.bittiming_const = dev->cfg->bittiming_const;
-       priv->can.do_set_bittiming = dev->ops->dev_set_bittiming;
-       priv->can.do_set_mode = dev->ops->dev_set_mode;
-       if ((id->driver_info & KVASER_USB_HAS_TXRX_ERRORS) ||
+       priv->can.do_set_bittiming = ops->dev_set_bittiming;
+       priv->can.do_set_mode = ops->dev_set_mode;
+       if ((driver_info->quirks & KVASER_USB_QUIRK_HAS_TXRX_ERRORS) ||
            (priv->dev->card_data.capabilities & KVASER_USB_CAP_BERR_CAP))
-               priv->can.do_get_berr_counter = dev->ops->dev_get_berr_counter;
-       if (id->driver_info & KVASER_USB_HAS_SILENT_MODE)
+               priv->can.do_get_berr_counter = ops->dev_get_berr_counter;
+       if (driver_info->quirks & KVASER_USB_QUIRK_HAS_SILENT_MODE)
                priv->can.ctrlmode_supported |= CAN_CTRLMODE_LISTENONLY;
 
        priv->can.ctrlmode_supported |= dev->card_data.ctrlmode_supported;
 
        if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) {
                priv->can.data_bittiming_const = dev->cfg->data_bittiming_const;
-               priv->can.do_set_data_bittiming =
-                                       dev->ops->dev_set_data_bittiming;
+               priv->can.do_set_data_bittiming = ops->dev_set_data_bittiming;
        }
 
        netdev->flags |= IFF_ECHO;
@@ -729,29 +767,22 @@ static int kvaser_usb_probe(struct usb_interface *intf,
        struct kvaser_usb *dev;
        int err;
        int i;
+       const struct kvaser_usb_driver_info *driver_info;
+       const struct kvaser_usb_dev_ops *ops;
+
+       driver_info = (const struct kvaser_usb_driver_info *)id->driver_info;
+       if (!driver_info)
+               return -ENODEV;
 
        dev = devm_kzalloc(&intf->dev, sizeof(*dev), GFP_KERNEL);
        if (!dev)
                return -ENOMEM;
 
-       if (kvaser_is_leaf(id)) {
-               dev->card_data.leaf.family = KVASER_LEAF;
-               dev->ops = &kvaser_usb_leaf_dev_ops;
-       } else if (kvaser_is_usbcan(id)) {
-               dev->card_data.leaf.family = KVASER_USBCAN;
-               dev->ops = &kvaser_usb_leaf_dev_ops;
-       } else if (kvaser_is_hydra(id)) {
-               dev->ops = &kvaser_usb_hydra_dev_ops;
-       } else {
-               dev_err(&intf->dev,
-                       "Product ID (%d) is not a supported Kvaser USB device\n",
-                       id->idProduct);
-               return -ENODEV;
-       }
-
        dev->intf = intf;
+       dev->driver_info = driver_info;
+       ops = driver_info->ops;
 
-       err = dev->ops->dev_setup_endpoints(dev);
+       err = ops->dev_setup_endpoints(dev);
        if (err) {
                dev_err(&intf->dev, "Cannot get usb endpoint(s)");
                return err;
@@ -765,22 +796,22 @@ static int kvaser_usb_probe(struct usb_interface *intf,
 
        dev->card_data.ctrlmode_supported = 0;
        dev->card_data.capabilities = 0;
-       err = dev->ops->dev_init_card(dev);
+       err = ops->dev_init_card(dev);
        if (err) {
                dev_err(&intf->dev,
                        "Failed to initialize card, error %d\n", err);
                return err;
        }
 
-       err = dev->ops->dev_get_software_info(dev);
+       err = ops->dev_get_software_info(dev);
        if (err) {
                dev_err(&intf->dev,
                        "Cannot get software info, error %d\n", err);
                return err;
        }
 
-       if (dev->ops->dev_get_software_details) {
-               err = dev->ops->dev_get_software_details(dev);
+       if (ops->dev_get_software_details) {
+               err = ops->dev_get_software_details(dev);
                if (err) {
                        dev_err(&intf->dev,
                                "Cannot get software details, error %d\n", err);
@@ -798,14 +829,14 @@ static int kvaser_usb_probe(struct usb_interface *intf,
 
        dev_dbg(&intf->dev, "Max outstanding tx = %d URBs\n", dev->max_tx_urbs);
 
-       err = dev->ops->dev_get_card_info(dev);
+       err = ops->dev_get_card_info(dev);
        if (err) {
                dev_err(&intf->dev, "Cannot get card info, error %d\n", err);
                return err;
        }
 
-       if (dev->ops->dev_get_capabilities) {
-               err = dev->ops->dev_get_capabilities(dev);
+       if (ops->dev_get_capabilities) {
+               err = ops->dev_get_capabilities(dev);
                if (err) {
                        dev_err(&intf->dev,
                                "Cannot get capabilities, error %d\n", err);
@@ -815,7 +846,7 @@ static int kvaser_usb_probe(struct usb_interface *intf,
        }
 
        for (i = 0; i < dev->nchannels; i++) {
-               err = kvaser_usb_init_one(dev, id, i);
+               err = kvaser_usb_init_one(dev, i);
                if (err) {
                        kvaser_usb_remove_interfaces(dev);
                        return err;
index a26823c..5d70844 100644 (file)
@@ -375,7 +375,7 @@ static const struct can_bittiming_const kvaser_usb_hydra_kcan_bittiming_c = {
        .brp_inc = 1,
 };
 
-static const struct can_bittiming_const kvaser_usb_hydra_flexc_bittiming_c = {
+const struct can_bittiming_const kvaser_usb_flexc_bittiming_const = {
        .name = "kvaser_usb_flex",
        .tseg1_min = 4,
        .tseg1_max = 16,
@@ -2052,7 +2052,7 @@ static const struct kvaser_usb_dev_cfg kvaser_usb_hydra_dev_cfg_flexc = {
                .freq = 24 * MEGA /* Hz */,
        },
        .timestamp_freq = 1,
-       .bittiming_const = &kvaser_usb_hydra_flexc_bittiming_c,
+       .bittiming_const = &kvaser_usb_flexc_bittiming_const,
 };
 
 static const struct kvaser_usb_dev_cfg kvaser_usb_hydra_dev_cfg_rt = {
index c805b99..cc809ec 100644 (file)
 #define USBCAN_ERROR_STATE_RX_ERROR    BIT(1)
 #define USBCAN_ERROR_STATE_BUSERROR    BIT(2)
 
-/* bittiming parameters */
-#define KVASER_USB_TSEG1_MIN           1
-#define KVASER_USB_TSEG1_MAX           16
-#define KVASER_USB_TSEG2_MIN           1
-#define KVASER_USB_TSEG2_MAX           8
-#define KVASER_USB_SJW_MAX             4
-#define KVASER_USB_BRP_MIN             1
-#define KVASER_USB_BRP_MAX             64
-#define KVASER_USB_BRP_INC             1
-
 /* ctrl modes */
 #define KVASER_CTRL_MODE_NORMAL                1
 #define KVASER_CTRL_MODE_SILENT                2
@@ -343,48 +333,68 @@ struct kvaser_usb_err_summary {
        };
 };
 
-static const struct can_bittiming_const kvaser_usb_leaf_bittiming_const = {
-       .name = "kvaser_usb",
-       .tseg1_min = KVASER_USB_TSEG1_MIN,
-       .tseg1_max = KVASER_USB_TSEG1_MAX,
-       .tseg2_min = KVASER_USB_TSEG2_MIN,
-       .tseg2_max = KVASER_USB_TSEG2_MAX,
-       .sjw_max = KVASER_USB_SJW_MAX,
-       .brp_min = KVASER_USB_BRP_MIN,
-       .brp_max = KVASER_USB_BRP_MAX,
-       .brp_inc = KVASER_USB_BRP_INC,
+static const struct can_bittiming_const kvaser_usb_leaf_m16c_bittiming_const = {
+       .name = "kvaser_usb_ucii",
+       .tseg1_min = 4,
+       .tseg1_max = 16,
+       .tseg2_min = 2,
+       .tseg2_max = 8,
+       .sjw_max = 4,
+       .brp_min = 1,
+       .brp_max = 16,
+       .brp_inc = 1,
+};
+
+static const struct can_bittiming_const kvaser_usb_leaf_m32c_bittiming_const = {
+       .name = "kvaser_usb_leaf",
+       .tseg1_min = 3,
+       .tseg1_max = 16,
+       .tseg2_min = 2,
+       .tseg2_max = 8,
+       .sjw_max = 4,
+       .brp_min = 2,
+       .brp_max = 128,
+       .brp_inc = 2,
 };
 
-static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_8mhz = {
+static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_usbcan_dev_cfg = {
        .clock = {
                .freq = 8 * MEGA /* Hz */,
        },
        .timestamp_freq = 1,
-       .bittiming_const = &kvaser_usb_leaf_bittiming_const,
+       .bittiming_const = &kvaser_usb_leaf_m16c_bittiming_const,
+};
+
+static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_m32c_dev_cfg = {
+       .clock = {
+               .freq = 16 * MEGA /* Hz */,
+       },
+       .timestamp_freq = 1,
+       .bittiming_const = &kvaser_usb_leaf_m32c_bittiming_const,
 };
 
-static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_16mhz = {
+static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_16mhz = {
        .clock = {
                .freq = 16 * MEGA /* Hz */,
        },
        .timestamp_freq = 1,
-       .bittiming_const = &kvaser_usb_leaf_bittiming_const,
+       .bittiming_const = &kvaser_usb_flexc_bittiming_const,
 };
 
-static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_24mhz = {
+static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_24mhz = {
        .clock = {
                .freq = 24 * MEGA /* Hz */,
        },
        .timestamp_freq = 1,
-       .bittiming_const = &kvaser_usb_leaf_bittiming_const,
+       .bittiming_const = &kvaser_usb_flexc_bittiming_const,
 };
 
-static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_32mhz = {
+static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_32mhz = {
        .clock = {
                .freq = 32 * MEGA /* Hz */,
        },
        .timestamp_freq = 1,
-       .bittiming_const = &kvaser_usb_leaf_bittiming_const,
+       .bittiming_const = &kvaser_usb_flexc_bittiming_const,
 };
 
 static void *
@@ -404,7 +414,7 @@ kvaser_usb_leaf_frame_to_cmd(const struct kvaser_usb_net_priv *priv,
                                      sizeof(struct kvaser_cmd_tx_can);
                cmd->u.tx_can.channel = priv->channel;
 
-               switch (dev->card_data.leaf.family) {
+               switch (dev->driver_info->family) {
                case KVASER_LEAF:
                        cmd_tx_can_flags = &cmd->u.tx_can.leaf.flags;
                        break;
@@ -524,16 +534,23 @@ static void kvaser_usb_leaf_get_software_info_leaf(struct kvaser_usb *dev,
        dev->fw_version = le32_to_cpu(softinfo->fw_version);
        dev->max_tx_urbs = le16_to_cpu(softinfo->max_outstanding_tx);
 
-       switch (sw_options & KVASER_USB_LEAF_SWOPTION_FREQ_MASK) {
-       case KVASER_USB_LEAF_SWOPTION_FREQ_16_MHZ_CLK:
-               dev->cfg = &kvaser_usb_leaf_dev_cfg_16mhz;
-               break;
-       case KVASER_USB_LEAF_SWOPTION_FREQ_24_MHZ_CLK:
-               dev->cfg = &kvaser_usb_leaf_dev_cfg_24mhz;
-               break;
-       case KVASER_USB_LEAF_SWOPTION_FREQ_32_MHZ_CLK:
-               dev->cfg = &kvaser_usb_leaf_dev_cfg_32mhz;
-               break;
+       if (dev->driver_info->quirks & KVASER_USB_QUIRK_IGNORE_CLK_FREQ) {
+               /* Firmware expects bittiming parameters calculated for 16MHz
+                * clock, regardless of the actual clock
+                */
+               dev->cfg = &kvaser_usb_leaf_m32c_dev_cfg;
+       } else {
+               switch (sw_options & KVASER_USB_LEAF_SWOPTION_FREQ_MASK) {
+               case KVASER_USB_LEAF_SWOPTION_FREQ_16_MHZ_CLK:
+                       dev->cfg = &kvaser_usb_leaf_imx_dev_cfg_16mhz;
+                       break;
+               case KVASER_USB_LEAF_SWOPTION_FREQ_24_MHZ_CLK:
+                       dev->cfg = &kvaser_usb_leaf_imx_dev_cfg_24mhz;
+                       break;
+               case KVASER_USB_LEAF_SWOPTION_FREQ_32_MHZ_CLK:
+                       dev->cfg = &kvaser_usb_leaf_imx_dev_cfg_32mhz;
+                       break;
+               }
        }
 }
 
@@ -550,7 +567,7 @@ static int kvaser_usb_leaf_get_software_info_inner(struct kvaser_usb *dev)
        if (err)
                return err;
 
-       switch (dev->card_data.leaf.family) {
+       switch (dev->driver_info->family) {
        case KVASER_LEAF:
                kvaser_usb_leaf_get_software_info_leaf(dev, &cmd.u.leaf.softinfo);
                break;
@@ -558,7 +575,7 @@ static int kvaser_usb_leaf_get_software_info_inner(struct kvaser_usb *dev)
                dev->fw_version = le32_to_cpu(cmd.u.usbcan.softinfo.fw_version);
                dev->max_tx_urbs =
                        le16_to_cpu(cmd.u.usbcan.softinfo.max_outstanding_tx);
-               dev->cfg = &kvaser_usb_leaf_dev_cfg_8mhz;
+               dev->cfg = &kvaser_usb_leaf_usbcan_dev_cfg;
                break;
        }
 
@@ -597,7 +614,7 @@ static int kvaser_usb_leaf_get_card_info(struct kvaser_usb *dev)
 
        dev->nchannels = cmd.u.cardinfo.nchannels;
        if (dev->nchannels > KVASER_USB_MAX_NET_DEVICES ||
-           (dev->card_data.leaf.family == KVASER_USBCAN &&
+           (dev->driver_info->family == KVASER_USBCAN &&
             dev->nchannels > MAX_USBCAN_NET_DEVICES))
                return -EINVAL;
 
@@ -730,7 +747,7 @@ kvaser_usb_leaf_rx_error_update_can_state(struct kvaser_usb_net_priv *priv,
            new_state < CAN_STATE_BUS_OFF)
                priv->can.can_stats.restarts++;
 
-       switch (dev->card_data.leaf.family) {
+       switch (dev->driver_info->family) {
        case KVASER_LEAF:
                if (es->leaf.error_factor) {
                        priv->can.can_stats.bus_error++;
@@ -809,7 +826,7 @@ static void kvaser_usb_leaf_rx_error(const struct kvaser_usb *dev,
                }
        }
 
-       switch (dev->card_data.leaf.family) {
+       switch (dev->driver_info->family) {
        case KVASER_LEAF:
                if (es->leaf.error_factor) {
                        cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
@@ -999,7 +1016,7 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev,
        stats = &priv->netdev->stats;
 
        if ((cmd->u.rx_can_header.flag & MSG_FLAG_ERROR_FRAME) &&
-           (dev->card_data.leaf.family == KVASER_LEAF &&
+           (dev->driver_info->family == KVASER_LEAF &&
             cmd->id == CMD_LEAF_LOG_MESSAGE)) {
                kvaser_usb_leaf_leaf_rx_error(dev, cmd);
                return;
@@ -1015,7 +1032,7 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev,
                return;
        }
 
-       switch (dev->card_data.leaf.family) {
+       switch (dev->driver_info->family) {
        case KVASER_LEAF:
                rx_data = cmd->u.leaf.rx_can.data;
                break;
@@ -1030,7 +1047,7 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev,
                return;
        }
 
-       if (dev->card_data.leaf.family == KVASER_LEAF && cmd->id ==
+       if (dev->driver_info->family == KVASER_LEAF && cmd->id ==
            CMD_LEAF_LOG_MESSAGE) {
                cf->can_id = le32_to_cpu(cmd->u.leaf.log_message.id);
                if (cf->can_id & KVASER_EXTENDED_FRAME)
@@ -1128,14 +1145,14 @@ static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev,
                break;
 
        case CMD_LEAF_LOG_MESSAGE:
-               if (dev->card_data.leaf.family != KVASER_LEAF)
+               if (dev->driver_info->family != KVASER_LEAF)
                        goto warn;
                kvaser_usb_leaf_rx_can_msg(dev, cmd);
                break;
 
        case CMD_CHIP_STATE_EVENT:
        case CMD_CAN_ERROR_EVENT:
-               if (dev->card_data.leaf.family == KVASER_LEAF)
+               if (dev->driver_info->family == KVASER_LEAF)
                        kvaser_usb_leaf_leaf_rx_error(dev, cmd);
                else
                        kvaser_usb_leaf_usbcan_rx_error(dev, cmd);
@@ -1147,12 +1164,12 @@ static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev,
 
        /* Ignored commands */
        case CMD_USBCAN_CLOCK_OVERFLOW_EVENT:
-               if (dev->card_data.leaf.family != KVASER_USBCAN)
+               if (dev->driver_info->family != KVASER_USBCAN)
                        goto warn;
                break;
 
        case CMD_FLUSH_QUEUE_REPLY:
-               if (dev->card_data.leaf.family != KVASER_LEAF)
+               if (dev->driver_info->family != KVASER_LEAF)
                        goto warn;
                break;
 
index 8a3b7b1..e179d31 100644 (file)
@@ -258,7 +258,7 @@ static const struct can_bittiming_const xcan_bittiming_const_canfd2 = {
        .tseg2_min = 1,
        .tseg2_max = 128,
        .sjw_max = 128,
-       .brp_min = 2,
+       .brp_min = 1,
        .brp_max = 256,
        .brp_inc = 1,
 };
@@ -271,7 +271,7 @@ static const struct can_bittiming_const xcan_data_bittiming_const_canfd2 = {
        .tseg2_min = 1,
        .tseg2_max = 16,
        .sjw_max = 16,
-       .brp_min = 2,
+       .brp_min = 1,
        .brp_max = 256,
        .brp_inc = 1,
 };
index 87e81c6..be0edfa 100644 (file)
@@ -878,6 +878,11 @@ static void bcm_sf2_sw_mac_link_up(struct dsa_switch *ds, int port,
                if (duplex == DUPLEX_FULL)
                        reg |= DUPLX_MODE;
 
+               if (tx_pause)
+                       reg |= TXFLOW_CNTL;
+               if (rx_pause)
+                       reg |= RXFLOW_CNTL;
+
                core_writel(priv, reg, offset);
        }
 
index 2572c60..b28baab 100644 (file)
@@ -300,6 +300,7 @@ static int hellcreek_led_setup(struct hellcreek *hellcreek)
        const char *label, *state;
        int ret = -EINVAL;
 
+       of_node_get(hellcreek->dev->of_node);
        leds = of_find_node_by_name(hellcreek->dev->of_node, "leds");
        if (!leds) {
                dev_err(hellcreek->dev, "No LEDs specified in device tree!\n");
index 9ca8c8d..92a500e 100644 (file)
@@ -1038,18 +1038,21 @@ int ksz_switch_register(struct ksz_device *dev,
                ports = of_get_child_by_name(dev->dev->of_node, "ethernet-ports");
                if (!ports)
                        ports = of_get_child_by_name(dev->dev->of_node, "ports");
-               if (ports)
+               if (ports) {
                        for_each_available_child_of_node(ports, port) {
                                if (of_property_read_u32(port, "reg",
                                                         &port_num))
                                        continue;
                                if (!(dev->port_mask & BIT(port_num))) {
                                        of_node_put(port);
+                                       of_node_put(ports);
                                        return -EINVAL;
                                }
                                of_get_phy_mode(port,
                                                &dev->ports[port_num].interface);
                        }
+                       of_node_put(ports);
+               }
                dev->synclko_125 = of_property_read_bool(dev->dev->of_node,
                                                         "microchip,synclko-125");
                dev->synclko_disable = of_property_read_bool(dev->dev->of_node,
index 570d020..9c27b9b 100644 (file)
@@ -1886,6 +1886,8 @@ static void vsc9959_psfp_sgi_table_del(struct ocelot *ocelot,
 static void vsc9959_psfp_counters_get(struct ocelot *ocelot, u32 index,
                                      struct felix_stream_filter_counters *counters)
 {
+       mutex_lock(&ocelot->stats_lock);
+
        ocelot_rmw(ocelot, SYS_STAT_CFG_STAT_VIEW(index),
                   SYS_STAT_CFG_STAT_VIEW_M,
                   SYS_STAT_CFG);
@@ -1900,6 +1902,8 @@ static void vsc9959_psfp_counters_get(struct ocelot *ocelot, u32 index,
                     SYS_STAT_CFG_STAT_VIEW(index) |
                     SYS_STAT_CFG_STAT_CLEAR_SHOT(0x10),
                     SYS_STAT_CFG);
+
+       mutex_unlock(&ocelot->stats_lock);
 }
 
 static int vsc9959_psfp_filter_add(struct ocelot *ocelot, int port,
index 72b6fc1..698c7d1 100644 (file)
@@ -3382,12 +3382,28 @@ static const struct of_device_id sja1105_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, sja1105_dt_ids);
 
+static const struct spi_device_id sja1105_spi_ids[] = {
+       { "sja1105e" },
+       { "sja1105t" },
+       { "sja1105p" },
+       { "sja1105q" },
+       { "sja1105r" },
+       { "sja1105s" },
+       { "sja1110a" },
+       { "sja1110b" },
+       { "sja1110c" },
+       { "sja1110d" },
+       { },
+};
+MODULE_DEVICE_TABLE(spi, sja1105_spi_ids);
+
 static struct spi_driver sja1105_driver = {
        .driver = {
                .name  = "sja1105",
                .owner = THIS_MODULE,
                .of_match_table = of_match_ptr(sja1105_dt_ids),
        },
+       .id_table = sja1105_spi_ids,
        .probe  = sja1105_probe,
        .remove = sja1105_remove,
        .shutdown = sja1105_shutdown,
index 3110895..97a92e6 100644 (file)
@@ -205,10 +205,20 @@ static const struct of_device_id vsc73xx_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, vsc73xx_of_match);
 
+static const struct spi_device_id vsc73xx_spi_ids[] = {
+       { "vsc7385" },
+       { "vsc7388" },
+       { "vsc7395" },
+       { "vsc7398" },
+       { },
+};
+MODULE_DEVICE_TABLE(spi, vsc73xx_spi_ids);
+
 static struct spi_driver vsc73xx_spi_driver = {
        .probe = vsc73xx_spi_probe,
        .remove = vsc73xx_spi_remove,
        .shutdown = vsc73xx_spi_shutdown,
+       .id_table = vsc73xx_spi_ids,
        .driver = {
                .name = "vsc73xx-spi",
                .of_match_table = vsc73xx_of_match,
index 8318339..8647125 100644 (file)
@@ -379,7 +379,7 @@ static void aq_pci_shutdown(struct pci_dev *pdev)
        }
 }
 
-static int aq_suspend_common(struct device *dev, bool deep)
+static int aq_suspend_common(struct device *dev)
 {
        struct aq_nic_s *nic = pci_get_drvdata(to_pci_dev(dev));
 
@@ -392,17 +392,15 @@ static int aq_suspend_common(struct device *dev, bool deep)
        if (netif_running(nic->ndev))
                aq_nic_stop(nic);
 
-       if (deep) {
-               aq_nic_deinit(nic, !nic->aq_hw->aq_nic_cfg->wol);
-               aq_nic_set_power(nic);
-       }
+       aq_nic_deinit(nic, !nic->aq_hw->aq_nic_cfg->wol);
+       aq_nic_set_power(nic);
 
        rtnl_unlock();
 
        return 0;
 }
 
-static int atl_resume_common(struct device *dev, bool deep)
+static int atl_resume_common(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct aq_nic_s *nic;
@@ -415,11 +413,6 @@ static int atl_resume_common(struct device *dev, bool deep)
        pci_set_power_state(pdev, PCI_D0);
        pci_restore_state(pdev);
 
-       if (deep) {
-               /* Reinitialize Nic/Vecs objects */
-               aq_nic_deinit(nic, !nic->aq_hw->aq_nic_cfg->wol);
-       }
-
        if (netif_running(nic->ndev)) {
                ret = aq_nic_init(nic);
                if (ret)
@@ -444,22 +437,22 @@ err_exit:
 
 static int aq_pm_freeze(struct device *dev)
 {
-       return aq_suspend_common(dev, true);
+       return aq_suspend_common(dev);
 }
 
 static int aq_pm_suspend_poweroff(struct device *dev)
 {
-       return aq_suspend_common(dev, true);
+       return aq_suspend_common(dev);
 }
 
 static int aq_pm_thaw(struct device *dev)
 {
-       return atl_resume_common(dev, true);
+       return atl_resume_common(dev);
 }
 
 static int aq_pm_resume_restore(struct device *dev)
 {
-       return atl_resume_common(dev, true);
+       return atl_resume_common(dev);
 }
 
 static const struct dev_pm_ops aq_pm_ops = {
index 56b46b8..cf9b005 100644 (file)
@@ -7790,7 +7790,7 @@ hwrm_dbg_qcaps_exit:
 
 static int bnxt_hwrm_queue_qportcfg(struct bnxt *bp);
 
-static int bnxt_hwrm_func_qcaps(struct bnxt *bp)
+int bnxt_hwrm_func_qcaps(struct bnxt *bp)
 {
        int rc;
 
@@ -10065,7 +10065,8 @@ static int bnxt_hwrm_if_change(struct bnxt *bp, bool up)
 
        if (flags & FUNC_DRV_IF_CHANGE_RESP_FLAGS_RESC_CHANGE)
                resc_reinit = true;
-       if (flags & FUNC_DRV_IF_CHANGE_RESP_FLAGS_HOT_FW_RESET_DONE)
+       if (flags & FUNC_DRV_IF_CHANGE_RESP_FLAGS_HOT_FW_RESET_DONE ||
+           test_bit(BNXT_STATE_FW_RESET_DET, &bp->state))
                fw_reset = true;
        else
                bnxt_remap_fw_health_regs(bp);
index a1dca8c..075c620 100644 (file)
@@ -2314,6 +2314,7 @@ int bnxt_cancel_reservations(struct bnxt *bp, bool fw_reset);
 int bnxt_hwrm_alloc_wol_fltr(struct bnxt *bp);
 int bnxt_hwrm_free_wol_fltr(struct bnxt *bp);
 int bnxt_hwrm_func_resc_qcaps(struct bnxt *bp, bool all);
+int bnxt_hwrm_func_qcaps(struct bnxt *bp);
 int bnxt_hwrm_fw_set_time(struct bnxt *);
 int bnxt_open_nic(struct bnxt *, bool, bool);
 int bnxt_half_open_nic(struct bnxt *bp);
index 3528ce9..6b3d4f4 100644 (file)
@@ -979,9 +979,11 @@ static int bnxt_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
        if (rc)
                return rc;
 
-       rc = bnxt_dl_livepatch_info_put(bp, req, BNXT_FW_SRT_PATCH);
-       if (rc)
-               return rc;
+       if (BNXT_CHIP_P5(bp)) {
+               rc = bnxt_dl_livepatch_info_put(bp, req, BNXT_FW_SRT_PATCH);
+               if (rc)
+                       return rc;
+       }
        return bnxt_dl_livepatch_info_put(bp, req, BNXT_FW_CRT_PATCH);
 
 }
index 562f8f6..7f3c087 100644 (file)
@@ -76,14 +76,23 @@ static int bnxt_refclk_read(struct bnxt *bp, struct ptp_system_timestamp *sts,
                            u64 *ns)
 {
        struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
+       u32 high_before, high_now, low;
 
        if (test_bit(BNXT_STATE_IN_FW_RESET, &bp->state))
                return -EIO;
 
+       high_before = readl(bp->bar0 + ptp->refclk_mapped_regs[1]);
        ptp_read_system_prets(sts);
-       *ns = readl(bp->bar0 + ptp->refclk_mapped_regs[0]);
+       low = readl(bp->bar0 + ptp->refclk_mapped_regs[0]);
        ptp_read_system_postts(sts);
-       *ns |= (u64)readl(bp->bar0 + ptp->refclk_mapped_regs[1]) << 32;
+       high_now = readl(bp->bar0 + ptp->refclk_mapped_regs[1]);
+       if (high_now != high_before) {
+               ptp_read_system_prets(sts);
+               low = readl(bp->bar0 + ptp->refclk_mapped_regs[0]);
+               ptp_read_system_postts(sts);
+       }
+       *ns = ((u64)high_now << 32) | low;
+
        return 0;
 }
 
index ddf2f39..a1a2c7a 100644 (file)
@@ -823,8 +823,10 @@ static int bnxt_sriov_enable(struct bnxt *bp, int *num_vfs)
                goto err_out2;
 
        rc = pci_enable_sriov(bp->pdev, *num_vfs);
-       if (rc)
+       if (rc) {
+               bnxt_ulp_sriov_cfg(bp, 0);
                goto err_out2;
+       }
 
        return 0;
 
@@ -832,6 +834,9 @@ err_out2:
        /* Free the resources reserved for various VF's */
        bnxt_hwrm_func_vf_resource_free(bp, *num_vfs);
 
+       /* Restore the max resources */
+       bnxt_hwrm_func_qcaps(bp);
+
 err_out1:
        bnxt_free_vf_resources(bp);
 
index f02fe90..f53387e 100644 (file)
@@ -28,7 +28,7 @@ struct bnxt_sw_tx_bd *bnxt_xmit_bd(struct bnxt *bp,
                                   struct xdp_buff *xdp)
 {
        struct skb_shared_info *sinfo;
-       struct bnxt_sw_tx_bd *tx_buf, *first_buf;
+       struct bnxt_sw_tx_bd *tx_buf;
        struct tx_bd *txbd;
        int num_frags = 0;
        u32 flags;
@@ -43,13 +43,14 @@ struct bnxt_sw_tx_bd *bnxt_xmit_bd(struct bnxt *bp,
        /* fill up the first buffer */
        prod = txr->tx_prod;
        tx_buf = &txr->tx_buf_ring[prod];
-       first_buf = tx_buf;
        tx_buf->nr_frags = num_frags;
        if (xdp)
                tx_buf->page = virt_to_head_page(xdp->data);
 
        txbd = &txr->tx_desc_ring[TX_RING(prod)][TX_IDX(prod)];
-       flags = ((len) << TX_BD_LEN_SHIFT) | ((num_frags + 1) << TX_BD_FLAGS_BD_CNT_SHIFT);
+       flags = (len << TX_BD_LEN_SHIFT) |
+               ((num_frags + 1) << TX_BD_FLAGS_BD_CNT_SHIFT) |
+               bnxt_lhint_arr[len >> 9];
        txbd->tx_bd_len_flags_type = cpu_to_le32(flags);
        txbd->tx_bd_opaque = prod;
        txbd->tx_bd_haddr = cpu_to_le64(mapping);
@@ -82,7 +83,6 @@ struct bnxt_sw_tx_bd *bnxt_xmit_bd(struct bnxt *bp,
 
                flags = frag_len << TX_BD_LEN_SHIFT;
                txbd->tx_bd_len_flags_type = cpu_to_le32(flags);
-               txbd->tx_bd_opaque = prod;
                txbd->tx_bd_haddr = cpu_to_le64(frag_mapping);
 
                len = frag_len;
@@ -96,7 +96,7 @@ struct bnxt_sw_tx_bd *bnxt_xmit_bd(struct bnxt *bp,
        prod = NEXT_TX(prod);
        txr->tx_prod = prod;
 
-       return first_buf;
+       return tx_buf;
 }
 
 static void __bnxt_xmit_xdp(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
index 4af5561..ddfe920 100644 (file)
@@ -1236,8 +1236,8 @@ static struct sock *chtls_recv_sock(struct sock *lsk,
        csk->sndbuf = newsk->sk_sndbuf;
        csk->smac_idx = ((struct port_info *)netdev_priv(ndev))->smt_idx;
        RCV_WSCALE(tp) = select_rcv_wscale(tcp_full_space(newsk),
-                                          sock_net(newsk)->
-                                               ipv4.sysctl_tcp_window_scaling,
+                                          READ_ONCE(sock_net(newsk)->
+                                                    ipv4.sysctl_tcp_window_scaling),
                                           tp->window_clamp);
        neigh_release(n);
        inet_inherit_port(&tcp_hashinfo, lsk, newsk);
@@ -1384,7 +1384,7 @@ static void chtls_pass_accept_request(struct sock *sk,
 #endif
        }
        if (req->tcpopt.wsf <= 14 &&
-           sock_net(sk)->ipv4.sysctl_tcp_window_scaling) {
+           READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_window_scaling)) {
                inet_rsk(oreq)->wscale_ok = 1;
                inet_rsk(oreq)->snd_wscale = req->tcpopt.wsf;
        }
@@ -1392,7 +1392,7 @@ static void chtls_pass_accept_request(struct sock *sk,
        th_ecn = tcph->ece && tcph->cwr;
        if (th_ecn) {
                ect = !INET_ECN_is_not_ect(ip_dsfield);
-               ecn_ok = sock_net(sk)->ipv4.sysctl_tcp_ecn;
+               ecn_ok = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_ecn);
                if ((!ect && ecn_ok) || tcp_ca_needs_ecn(sk))
                        inet_rsk(oreq)->ecn_ok = 1;
        }
index 528eb0f..b4f5e57 100644 (file)
@@ -2287,7 +2287,7 @@ err:
 
 /* Uses sync mcc */
 int be_cmd_read_port_transceiver_data(struct be_adapter *adapter,
-                                     u8 page_num, u8 *data)
+                                     u8 page_num, u32 off, u32 len, u8 *data)
 {
        struct be_dma_mem cmd;
        struct be_mcc_wrb *wrb;
@@ -2321,10 +2321,10 @@ int be_cmd_read_port_transceiver_data(struct be_adapter *adapter,
        req->port = cpu_to_le32(adapter->hba_port_num);
        req->page_num = cpu_to_le32(page_num);
        status = be_mcc_notify_wait(adapter);
-       if (!status) {
+       if (!status && len > 0) {
                struct be_cmd_resp_port_type *resp = cmd.va;
 
-               memcpy(data, resp->page_data, PAGE_DATA_LEN);
+               memcpy(data, resp->page_data + off, len);
        }
 err:
        mutex_unlock(&adapter->mcc_lock);
@@ -2415,7 +2415,7 @@ int be_cmd_query_cable_type(struct be_adapter *adapter)
        int status;
 
        status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
-                                                  page_data);
+                                                  0, PAGE_DATA_LEN, page_data);
        if (!status) {
                switch (adapter->phy.interface_type) {
                case PHY_TYPE_QSFP:
@@ -2440,7 +2440,7 @@ int be_cmd_query_sfp_info(struct be_adapter *adapter)
        int status;
 
        status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
-                                                  page_data);
+                                                  0, PAGE_DATA_LEN, page_data);
        if (!status) {
                strlcpy(adapter->phy.vendor_name, page_data +
                        SFP_VENDOR_NAME_OFFSET, SFP_VENDOR_NAME_LEN - 1);
index db1f3b9..e2085c6 100644 (file)
@@ -2427,7 +2427,7 @@ int be_cmd_set_beacon_state(struct be_adapter *adapter, u8 port_num, u8 beacon,
 int be_cmd_get_beacon_state(struct be_adapter *adapter, u8 port_num,
                            u32 *state);
 int be_cmd_read_port_transceiver_data(struct be_adapter *adapter,
-                                     u8 page_num, u8 *data);
+                                     u8 page_num, u32 off, u32 len, u8 *data);
 int be_cmd_query_cable_type(struct be_adapter *adapter);
 int be_cmd_query_sfp_info(struct be_adapter *adapter);
 int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd,
index dfa7843..bd0df18 100644 (file)
@@ -1344,7 +1344,7 @@ static int be_get_module_info(struct net_device *netdev,
                return -EOPNOTSUPP;
 
        status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
-                                                  page_data);
+                                                  0, PAGE_DATA_LEN, page_data);
        if (!status) {
                if (!page_data[SFP_PLUS_SFF_8472_COMP]) {
                        modinfo->type = ETH_MODULE_SFF_8079;
@@ -1362,25 +1362,32 @@ static int be_get_module_eeprom(struct net_device *netdev,
 {
        struct be_adapter *adapter = netdev_priv(netdev);
        int status;
+       u32 begin, end;
 
        if (!check_privilege(adapter, MAX_PRIVILEGES))
                return -EOPNOTSUPP;
 
-       status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
-                                                  data);
-       if (status)
-               goto err;
+       begin = eeprom->offset;
+       end = eeprom->offset + eeprom->len;
+
+       if (begin < PAGE_DATA_LEN) {
+               status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0, begin,
+                                                          min_t(u32, end, PAGE_DATA_LEN) - begin,
+                                                          data);
+               if (status)
+                       goto err;
+
+               data += PAGE_DATA_LEN - begin;
+               begin = PAGE_DATA_LEN;
+       }
 
-       if (eeprom->offset + eeprom->len > PAGE_DATA_LEN) {
-               status = be_cmd_read_port_transceiver_data(adapter,
-                                                          TR_PAGE_A2,
-                                                          data +
-                                                          PAGE_DATA_LEN);
+       if (end > PAGE_DATA_LEN) {
+               status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A2,
+                                                          begin - PAGE_DATA_LEN,
+                                                          end - begin, data);
                if (status)
                        goto err;
        }
-       if (eeprom->offset)
-               memcpy(data, data + eeprom->offset, eeprom->len);
 err:
        return be_cmd_status(status);
 }
index 5231818..c036637 100644 (file)
@@ -1764,6 +1764,19 @@ cleanup_clk:
        return rc;
 }
 
+static bool ftgmac100_has_child_node(struct device_node *np, const char *name)
+{
+       struct device_node *child_np = of_get_child_by_name(np, name);
+       bool ret = false;
+
+       if (child_np) {
+               ret = true;
+               of_node_put(child_np);
+       }
+
+       return ret;
+}
+
 static int ftgmac100_probe(struct platform_device *pdev)
 {
        struct resource *res;
@@ -1883,7 +1896,7 @@ static int ftgmac100_probe(struct platform_device *pdev)
 
                /* Display what we found */
                phy_attached_info(phy);
-       } else if (np && !of_get_child_by_name(np, "mdio")) {
+       } else if (np && !ftgmac100_has_child_node(np, "mdio")) {
                /* Support legacy ASPEED devicetree descriptions that decribe a
                 * MAC with an embedded MDIO controller but have no "mdio"
                 * child node. Automatically scan the MDIO bus for available
index 0f6a549..29a6c2e 100644 (file)
@@ -142,6 +142,7 @@ static void *fun_run_xdp(struct funeth_rxq *q, skb_frag_t *frags, void *buf_va,
                         int ref_ok, struct funeth_txq *xdp_q)
 {
        struct bpf_prog *xdp_prog;
+       struct xdp_frame *xdpf;
        struct xdp_buff xdp;
        u32 act;
 
@@ -163,7 +164,9 @@ static void *fun_run_xdp(struct funeth_rxq *q, skb_frag_t *frags, void *buf_va,
        case XDP_TX:
                if (unlikely(!ref_ok))
                        goto pass;
-               if (!fun_xdp_tx(xdp_q, xdp.data, xdp.data_end - xdp.data))
+
+               xdpf = xdp_convert_buff_to_frame(&xdp);
+               if (!xdpf || !fun_xdp_tx(xdp_q, xdpf))
                        goto xdp_error;
                FUN_QSTAT_INC(q, xdp_tx);
                q->xdp_flush |= FUN_XDP_FLUSH_TX;
index ff6e292..2f6698b 100644 (file)
@@ -466,7 +466,7 @@ static unsigned int fun_xdpq_clean(struct funeth_txq *q, unsigned int budget)
 
                do {
                        fun_xdp_unmap(q, reclaim_idx);
-                       page_frag_free(q->info[reclaim_idx].vaddr);
+                       xdp_return_frame(q->info[reclaim_idx].xdpf);
 
                        trace_funeth_tx_free(q, reclaim_idx, 1, head);
 
@@ -479,11 +479,11 @@ static unsigned int fun_xdpq_clean(struct funeth_txq *q, unsigned int budget)
        return npkts;
 }
 
-bool fun_xdp_tx(struct funeth_txq *q, void *data, unsigned int len)
+bool fun_xdp_tx(struct funeth_txq *q, struct xdp_frame *xdpf)
 {
        struct fun_eth_tx_req *req;
        struct fun_dataop_gl *gle;
-       unsigned int idx;
+       unsigned int idx, len;
        dma_addr_t dma;
 
        if (fun_txq_avail(q) < FUN_XDP_CLEAN_THRES)
@@ -494,7 +494,8 @@ bool fun_xdp_tx(struct funeth_txq *q, void *data, unsigned int len)
                return false;
        }
 
-       dma = dma_map_single(q->dma_dev, data, len, DMA_TO_DEVICE);
+       len = xdpf->len;
+       dma = dma_map_single(q->dma_dev, xdpf->data, len, DMA_TO_DEVICE);
        if (unlikely(dma_mapping_error(q->dma_dev, dma))) {
                FUN_QSTAT_INC(q, tx_map_err);
                return false;
@@ -514,7 +515,7 @@ bool fun_xdp_tx(struct funeth_txq *q, void *data, unsigned int len)
        gle = (struct fun_dataop_gl *)req->dataop.imm;
        fun_dataop_gl_init(gle, 0, 0, len, dma);
 
-       q->info[idx].vaddr = data;
+       q->info[idx].xdpf = xdpf;
 
        u64_stats_update_begin(&q->syncp);
        q->stats.tx_bytes += len;
@@ -545,12 +546,9 @@ int fun_xdp_xmit_frames(struct net_device *dev, int n,
        if (unlikely(q_idx >= fp->num_xdpqs))
                return -ENXIO;
 
-       for (q = xdpqs[q_idx], i = 0; i < n; i++) {
-               const struct xdp_frame *xdpf = frames[i];
-
-               if (!fun_xdp_tx(q, xdpf->data, xdpf->len))
+       for (q = xdpqs[q_idx], i = 0; i < n; i++)
+               if (!fun_xdp_tx(q, frames[i]))
                        break;
-       }
 
        if (unlikely(flags & XDP_XMIT_FLUSH))
                fun_txq_wr_db(q);
@@ -577,7 +575,7 @@ static void fun_xdpq_purge(struct funeth_txq *q)
                unsigned int idx = q->cons_cnt & q->mask;
 
                fun_xdp_unmap(q, idx);
-               page_frag_free(q->info[idx].vaddr);
+               xdp_return_frame(q->info[idx].xdpf);
                q->cons_cnt++;
        }
 }
index 04c9f91..8708e28 100644 (file)
@@ -95,8 +95,8 @@ struct funeth_txq_stats {  /* per Tx queue SW counters */
 
 struct funeth_tx_info {      /* per Tx descriptor state */
        union {
-               struct sk_buff *skb; /* associated packet */
-               void *vaddr;         /* start address for XDP */
+               struct sk_buff *skb;    /* associated packet (sk_buff path) */
+               struct xdp_frame *xdpf; /* associated XDP frame (XDP path) */
        };
 };
 
@@ -245,7 +245,7 @@ static inline int fun_irq_node(const struct fun_irq *p)
 int fun_rxq_napi_poll(struct napi_struct *napi, int budget);
 int fun_txq_napi_poll(struct napi_struct *napi, int budget);
 netdev_tx_t fun_start_xmit(struct sk_buff *skb, struct net_device *netdev);
-bool fun_xdp_tx(struct funeth_txq *q, void *data, unsigned int len);
+bool fun_xdp_tx(struct funeth_txq *q, struct xdp_frame *xdpf);
 int fun_xdp_xmit_frames(struct net_device *dev, int n,
                        struct xdp_frame **frames, u32 flags);
 
index 7e7fe5b..5ab7c0f 100644 (file)
@@ -5981,6 +5981,15 @@ static int ibmvnic_reset_init(struct ibmvnic_adapter *adapter, bool reset)
                        release_sub_crqs(adapter, 0);
                        rc = init_sub_crqs(adapter);
                } else {
+                       /* no need to reinitialize completely, but we do
+                        * need to clean up transmits that were in flight
+                        * when we processed the reset.  Failure to do so
+                        * will confound the upper layer, usually TCP, by
+                        * creating the illusion of transmits that are
+                        * awaiting completion.
+                        */
+                       clean_tx_pools(adapter);
+
                        rc = reset_sub_crq_queues(adapter);
                }
        } else {
index 13382df..bcf680e 100644 (file)
@@ -630,7 +630,6 @@ struct e1000_phy_info {
        bool disable_polarity_correction;
        bool is_mdix;
        bool polarity_correction;
-       bool reset_disable;
        bool speed_downgraded;
        bool autoneg_wait_to_complete;
 };
index e6c8e6d..9466f65 100644 (file)
@@ -2050,10 +2050,6 @@ static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
        bool blocked = false;
        int i = 0;
 
-       /* Check the PHY (LCD) reset flag */
-       if (hw->phy.reset_disable)
-               return true;
-
        while ((blocked = !(er32(FWSM) & E1000_ICH_FWSM_RSPCIPHY)) &&
               (i++ < 30))
                usleep_range(10000, 11000);
index 638a3dd..2504b11 100644 (file)
 #define I217_CGFREG_ENABLE_MTA_RESET   0x0002
 #define I217_MEMPWR                    PHY_REG(772, 26)
 #define I217_MEMPWR_DISABLE_SMB_RELEASE        0x0010
-#define I217_MEMPWR_MOEM               0x1000
 
 /* Receive Address Initial CRC Calculation */
 #define E1000_PCH_RAICC(_n)    (0x05F50 + ((_n) * 4))
index fa06f68..f172994 100644 (file)
@@ -6494,6 +6494,10 @@ static void e1000e_s0ix_exit_flow(struct e1000_adapter *adapter)
 
        if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID &&
            hw->mac.type >= e1000_pch_adp) {
+               /* Keep the GPT clock enabled for CSME */
+               mac_data = er32(FEXTNVM);
+               mac_data |= BIT(3);
+               ew32(FEXTNVM, mac_data);
                /* Request ME unconfigure the device from S0ix */
                mac_data = er32(H2ME);
                mac_data &= ~E1000_H2ME_START_DPG;
@@ -6987,21 +6991,8 @@ static __maybe_unused int e1000e_pm_suspend(struct device *dev)
        struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev));
        struct e1000_adapter *adapter = netdev_priv(netdev);
        struct pci_dev *pdev = to_pci_dev(dev);
-       struct e1000_hw *hw = &adapter->hw;
-       u16 phy_data;
        int rc;
 
-       if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID &&
-           hw->mac.type >= e1000_pch_adp) {
-               /* Mask OEM Bits / Gig Disable / Restart AN (772_26[12] = 1) */
-               e1e_rphy(hw, I217_MEMPWR, &phy_data);
-               phy_data |= I217_MEMPWR_MOEM;
-               e1e_wphy(hw, I217_MEMPWR, phy_data);
-
-               /* Disable LCD reset */
-               hw->phy.reset_disable = true;
-       }
-
        e1000e_flush_lpic(pdev);
 
        e1000e_pm_freeze(dev);
@@ -7023,8 +7014,6 @@ static __maybe_unused int e1000e_pm_resume(struct device *dev)
        struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev));
        struct e1000_adapter *adapter = netdev_priv(netdev);
        struct pci_dev *pdev = to_pci_dev(dev);
-       struct e1000_hw *hw = &adapter->hw;
-       u16 phy_data;
        int rc;
 
        /* Introduce S0ix implementation */
@@ -7035,17 +7024,6 @@ static __maybe_unused int e1000e_pm_resume(struct device *dev)
        if (rc)
                return rc;
 
-       if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID &&
-           hw->mac.type >= e1000_pch_adp) {
-               /* Unmask OEM Bits / Gig Disable / Restart AN 772_26[12] = 0 */
-               e1e_rphy(hw, I217_MEMPWR, &phy_data);
-               phy_data &= ~I217_MEMPWR_MOEM;
-               e1e_wphy(hw, I217_MEMPWR, phy_data);
-
-               /* Enable LCD reset */
-               hw->phy.reset_disable = false;
-       }
-
        return e1000e_pm_thaw(dev);
 }
 
index 18558a0..407fe8f 100644 (file)
@@ -37,6 +37,7 @@
 #include <net/tc_act/tc_mirred.h>
 #include <net/udp_tunnel.h>
 #include <net/xdp_sock.h>
+#include <linux/bitfield.h>
 #include "i40e_type.h"
 #include "i40e_prototype.h"
 #include <linux/net/intel/i40e_client.h>
@@ -1092,6 +1093,21 @@ static inline void i40e_write_fd_input_set(struct i40e_pf *pf,
                          (u32)(val & 0xFFFFFFFFULL));
 }
 
+/**
+ * i40e_get_pf_count - get PCI PF count.
+ * @hw: pointer to a hw.
+ *
+ * Reports the function number of the highest PCI physical
+ * function plus 1 as it is loaded from the NVM.
+ *
+ * Return: PCI PF count.
+ **/
+static inline u32 i40e_get_pf_count(struct i40e_hw *hw)
+{
+       return FIELD_GET(I40E_GLGEN_PCIFCNCNT_PCIPFCNT_MASK,
+                        rd32(hw, I40E_GLGEN_PCIFCNCNT));
+}
+
 /* needed by i40e_ethtool.c */
 int i40e_up(struct i40e_vsi *vsi);
 void i40e_down(struct i40e_vsi *vsi);
index 72576bb..685556e 100644 (file)
@@ -551,6 +551,47 @@ void i40e_pf_reset_stats(struct i40e_pf *pf)
 }
 
 /**
+ * i40e_compute_pci_to_hw_id - compute index form PCI function.
+ * @vsi: ptr to the VSI to read from.
+ * @hw: ptr to the hardware info.
+ **/
+static u32 i40e_compute_pci_to_hw_id(struct i40e_vsi *vsi, struct i40e_hw *hw)
+{
+       int pf_count = i40e_get_pf_count(hw);
+
+       if (vsi->type == I40E_VSI_SRIOV)
+               return (hw->port * BIT(7)) / pf_count + vsi->vf_id;
+
+       return hw->port + BIT(7);
+}
+
+/**
+ * i40e_stat_update64 - read and update a 64 bit stat from the chip.
+ * @hw: ptr to the hardware info.
+ * @hireg: the high 32 bit reg to read.
+ * @loreg: the low 32 bit reg to read.
+ * @offset_loaded: has the initial offset been loaded yet.
+ * @offset: ptr to current offset value.
+ * @stat: ptr to the stat.
+ *
+ * Since the device stats are not reset at PFReset, they will not
+ * be zeroed when the driver starts.  We'll save the first values read
+ * and use them as offsets to be subtracted from the raw values in order
+ * to report stats that count from zero.
+ **/
+static void i40e_stat_update64(struct i40e_hw *hw, u32 hireg, u32 loreg,
+                              bool offset_loaded, u64 *offset, u64 *stat)
+{
+       u64 new_data;
+
+       new_data = rd64(hw, loreg);
+
+       if (!offset_loaded || new_data < *offset)
+               *offset = new_data;
+       *stat = new_data - *offset;
+}
+
+/**
  * i40e_stat_update48 - read and update a 48 bit stat from the chip
  * @hw: ptr to the hardware info
  * @hireg: the high 32 bit reg to read
@@ -622,6 +663,34 @@ static void i40e_stat_update_and_clear32(struct i40e_hw *hw, u32 reg, u64 *stat)
 }
 
 /**
+ * i40e_stats_update_rx_discards - update rx_discards.
+ * @vsi: ptr to the VSI to be updated.
+ * @hw: ptr to the hardware info.
+ * @stat_idx: VSI's stat_counter_idx.
+ * @offset_loaded: ptr to the VSI's stat_offsets_loaded.
+ * @stat_offset: ptr to stat_offset to store first read of specific register.
+ * @stat: ptr to VSI's stat to be updated.
+ **/
+static void
+i40e_stats_update_rx_discards(struct i40e_vsi *vsi, struct i40e_hw *hw,
+                             int stat_idx, bool offset_loaded,
+                             struct i40e_eth_stats *stat_offset,
+                             struct i40e_eth_stats *stat)
+{
+       u64 rx_rdpc, rx_rxerr;
+
+       i40e_stat_update32(hw, I40E_GLV_RDPC(stat_idx), offset_loaded,
+                          &stat_offset->rx_discards, &rx_rdpc);
+       i40e_stat_update64(hw,
+                          I40E_GL_RXERR1H(i40e_compute_pci_to_hw_id(vsi, hw)),
+                          I40E_GL_RXERR1L(i40e_compute_pci_to_hw_id(vsi, hw)),
+                          offset_loaded, &stat_offset->rx_discards_other,
+                          &rx_rxerr);
+
+       stat->rx_discards = rx_rdpc + rx_rxerr;
+}
+
+/**
  * i40e_update_eth_stats - Update VSI-specific ethernet statistics counters.
  * @vsi: the VSI to be updated
  **/
@@ -680,6 +749,10 @@ void i40e_update_eth_stats(struct i40e_vsi *vsi)
                           I40E_GLV_BPTCL(stat_idx),
                           vsi->stat_offsets_loaded,
                           &oes->tx_broadcast, &es->tx_broadcast);
+
+       i40e_stats_update_rx_discards(vsi, hw, stat_idx,
+                                     vsi->stat_offsets_loaded, oes, es);
+
        vsi->stat_offsets_loaded = true;
 }
 
@@ -1852,11 +1925,15 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi,
                 * non-zero req_queue_pairs says that user requested a new
                 * queue count via ethtool's set_channels, so use this
                 * value for queues distribution across traffic classes
+                * We need at least one queue pair for the interface
+                * to be usable as we see in else statement.
                 */
                if (vsi->req_queue_pairs > 0)
                        vsi->num_queue_pairs = vsi->req_queue_pairs;
                else if (pf->flags & I40E_FLAG_MSIX_ENABLED)
                        vsi->num_queue_pairs = pf->num_lan_msix;
+               else
+                       vsi->num_queue_pairs = 1;
        }
 
        /* Number of queues per enabled TC */
@@ -10577,7 +10654,7 @@ static int i40e_reset(struct i40e_pf *pf)
  **/
 static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
 {
-       int old_recovery_mode_bit = test_bit(__I40E_RECOVERY_MODE, pf->state);
+       const bool is_recovery_mode_reported = i40e_check_recovery_mode(pf);
        struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
        struct i40e_hw *hw = &pf->hw;
        i40e_status ret;
@@ -10585,13 +10662,11 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
        int v;
 
        if (test_bit(__I40E_EMP_RESET_INTR_RECEIVED, pf->state) &&
-           i40e_check_recovery_mode(pf)) {
+           is_recovery_mode_reported)
                i40e_set_ethtool_ops(pf->vsi[pf->lan_vsi]->netdev);
-       }
 
        if (test_bit(__I40E_DOWN, pf->state) &&
-           !test_bit(__I40E_RECOVERY_MODE, pf->state) &&
-           !old_recovery_mode_bit)
+           !test_bit(__I40E_RECOVERY_MODE, pf->state))
                goto clear_recovery;
        dev_dbg(&pf->pdev->dev, "Rebuilding internal switch\n");
 
@@ -10618,13 +10693,12 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
         * accordingly with regard to resources initialization
         * and deinitialization
         */
-       if (test_bit(__I40E_RECOVERY_MODE, pf->state) ||
-           old_recovery_mode_bit) {
+       if (test_bit(__I40E_RECOVERY_MODE, pf->state)) {
                if (i40e_get_capabilities(pf,
                                          i40e_aqc_opc_list_func_capabilities))
                        goto end_unlock;
 
-               if (test_bit(__I40E_RECOVERY_MODE, pf->state)) {
+               if (is_recovery_mode_reported) {
                        /* we're staying in recovery mode so we'll reinitialize
                         * misc vector here
                         */
index 1908eed..7339003 100644 (file)
 #define I40E_GLGEN_MSRWD_MDIWRDATA_SHIFT 0
 #define I40E_GLGEN_MSRWD_MDIRDDATA_SHIFT 16
 #define I40E_GLGEN_MSRWD_MDIRDDATA_MASK I40E_MASK(0xFFFF, I40E_GLGEN_MSRWD_MDIRDDATA_SHIFT)
+#define I40E_GLGEN_PCIFCNCNT                0x001C0AB4 /* Reset: PCIR */
+#define I40E_GLGEN_PCIFCNCNT_PCIPFCNT_SHIFT 0
+#define I40E_GLGEN_PCIFCNCNT_PCIPFCNT_MASK  I40E_MASK(0x1F, I40E_GLGEN_PCIFCNCNT_PCIPFCNT_SHIFT)
+#define I40E_GLGEN_PCIFCNCNT_PCIVFCNT_SHIFT 16
+#define I40E_GLGEN_PCIFCNCNT_PCIVFCNT_MASK  I40E_MASK(0xFF, I40E_GLGEN_PCIFCNCNT_PCIVFCNT_SHIFT)
 #define I40E_GLGEN_RSTAT 0x000B8188 /* Reset: POR */
 #define I40E_GLGEN_RSTAT_DEVSTATE_SHIFT 0
 #define I40E_GLGEN_RSTAT_DEVSTATE_MASK I40E_MASK(0x3, I40E_GLGEN_RSTAT_DEVSTATE_SHIFT)
 #define I40E_VFQF_HKEY1_MAX_INDEX 12
 #define I40E_VFQF_HLUT1(_i, _VF) (0x00220000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...15, _VF=0...127 */ /* Reset: CORER */
 #define I40E_VFQF_HLUT1_MAX_INDEX 15
+#define I40E_GL_RXERR1H(_i)             (0x00318004 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */
+#define I40E_GL_RXERR1H_MAX_INDEX       143
+#define I40E_GL_RXERR1H_RXERR1H_SHIFT   0
+#define I40E_GL_RXERR1H_RXERR1H_MASK    I40E_MASK(0xFFFFFFFF, I40E_GL_RXERR1H_RXERR1H_SHIFT)
+#define I40E_GL_RXERR1L(_i)             (0x00318000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */
+#define I40E_GL_RXERR1L_MAX_INDEX       143
+#define I40E_GL_RXERR1L_RXERR1L_SHIFT   0
+#define I40E_GL_RXERR1L_RXERR1L_MASK    I40E_MASK(0xFFFFFFFF, I40E_GL_RXERR1L_RXERR1L_SHIFT)
 #define I40E_GLPRT_BPRCH(_i) (0x003005E4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */
 #define I40E_GLPRT_BPRCL(_i) (0x003005E0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */
 #define I40E_GLPRT_BPTCH(_i) (0x00300A04 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */
index 36a4ca1..7b3f30b 100644 (file)
@@ -1172,6 +1172,7 @@ struct i40e_eth_stats {
        u64 tx_broadcast;               /* bptc */
        u64 tx_discards;                /* tdpc */
        u64 tx_errors;                  /* tepc */
+       u64 rx_discards_other;          /* rxerr1 */
 };
 
 /* Statistics collected per VEB per TC */
index 033ea71..86b0f21 100644 (file)
@@ -2147,6 +2147,10 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg)
                /* VFs only use TC 0 */
                vfres->vsi_res[0].qset_handle
                                          = le16_to_cpu(vsi->info.qs_handle[0]);
+               if (!(vf->driver_caps & VIRTCHNL_VF_OFFLOAD_USO) && !vf->pf_set_mac) {
+                       i40e_del_mac_filter(vsi, vf->default_lan_addr.addr);
+                       eth_zero_addr(vf->default_lan_addr.addr);
+               }
                ether_addr_copy(vfres->vsi_res[0].default_mac_addr,
                                vf->default_lan_addr.addr);
        }
index 49aed3e..0ea0361 100644 (file)
@@ -64,7 +64,6 @@ struct iavf_vsi {
        u16 id;
        DECLARE_BITMAP(state, __IAVF_VSI_STATE_SIZE__);
        int base_vector;
-       u16 work_limit;
        u16 qs_handle;
        void *priv;     /* client driver data reference. */
 };
@@ -159,8 +158,12 @@ struct iavf_vlan {
 struct iavf_vlan_filter {
        struct list_head list;
        struct iavf_vlan vlan;
-       bool remove;            /* filter needs to be removed */
-       bool add;               /* filter needs to be added */
+       struct {
+               u8 is_new_vlan:1;       /* filter is new, wait for PF answer */
+               u8 remove:1;            /* filter needs to be removed */
+               u8 add:1;               /* filter needs to be added */
+               u8 padding:5;
+       };
 };
 
 #define IAVF_MAX_TRAFFIC_CLASS 4
@@ -461,6 +464,10 @@ static inline const char *iavf_state_str(enum iavf_state_t state)
                return "__IAVF_INIT_VERSION_CHECK";
        case __IAVF_INIT_GET_RESOURCES:
                return "__IAVF_INIT_GET_RESOURCES";
+       case __IAVF_INIT_EXTENDED_CAPS:
+               return "__IAVF_INIT_EXTENDED_CAPS";
+       case __IAVF_INIT_CONFIG_ADAPTER:
+               return "__IAVF_INIT_CONFIG_ADAPTER";
        case __IAVF_INIT_SW:
                return "__IAVF_INIT_SW";
        case __IAVF_INIT_FAILED:
@@ -520,6 +527,7 @@ int iavf_get_vf_config(struct iavf_adapter *adapter);
 int iavf_get_vf_vlan_v2_caps(struct iavf_adapter *adapter);
 int iavf_send_vf_offload_vlan_v2_msg(struct iavf_adapter *adapter);
 void iavf_set_queue_vlan_tag_loc(struct iavf_adapter *adapter);
+u16 iavf_get_num_vlans_added(struct iavf_adapter *adapter);
 void iavf_irq_enable(struct iavf_adapter *adapter, bool flush);
 void iavf_configure_queues(struct iavf_adapter *adapter);
 void iavf_deconfigure_queues(struct iavf_adapter *adapter);
index 3bb5671..e535d4c 100644 (file)
@@ -692,12 +692,8 @@ static int __iavf_get_coalesce(struct net_device *netdev,
                               struct ethtool_coalesce *ec, int queue)
 {
        struct iavf_adapter *adapter = netdev_priv(netdev);
-       struct iavf_vsi *vsi = &adapter->vsi;
        struct iavf_ring *rx_ring, *tx_ring;
 
-       ec->tx_max_coalesced_frames = vsi->work_limit;
-       ec->rx_max_coalesced_frames = vsi->work_limit;
-
        /* Rx and Tx usecs per queue value. If user doesn't specify the
         * queue, return queue 0's value to represent.
         */
@@ -825,12 +821,8 @@ static int __iavf_set_coalesce(struct net_device *netdev,
                               struct ethtool_coalesce *ec, int queue)
 {
        struct iavf_adapter *adapter = netdev_priv(netdev);
-       struct iavf_vsi *vsi = &adapter->vsi;
        int i;
 
-       if (ec->tx_max_coalesced_frames_irq || ec->rx_max_coalesced_frames_irq)
-               vsi->work_limit = ec->tx_max_coalesced_frames_irq;
-
        if (ec->rx_coalesce_usecs == 0) {
                if (ec->use_adaptive_rx_coalesce)
                        netif_info(adapter, drv, netdev, "rx-usecs=0, need to disable adaptive-rx for a complete disable\n");
@@ -1969,8 +1961,6 @@ static int iavf_set_rxfh(struct net_device *netdev, const u32 *indir,
 
 static const struct ethtool_ops iavf_ethtool_ops = {
        .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
-                                    ETHTOOL_COALESCE_MAX_FRAMES |
-                                    ETHTOOL_COALESCE_MAX_FRAMES_IRQ |
                                     ETHTOOL_COALESCE_USE_ADAPTIVE,
        .get_drvinfo            = iavf_get_drvinfo,
        .get_link               = ethtool_op_get_link,
index f3ecb3b..2e2c153 100644 (file)
@@ -843,7 +843,7 @@ static void iavf_restore_filters(struct iavf_adapter *adapter)
  * iavf_get_num_vlans_added - get number of VLANs added
  * @adapter: board private structure
  */
-static u16 iavf_get_num_vlans_added(struct iavf_adapter *adapter)
+u16 iavf_get_num_vlans_added(struct iavf_adapter *adapter)
 {
        return bitmap_weight(adapter->vsi.active_cvlans, VLAN_N_VID) +
                bitmap_weight(adapter->vsi.active_svlans, VLAN_N_VID);
@@ -906,11 +906,6 @@ static int iavf_vlan_rx_add_vid(struct net_device *netdev,
        if (!iavf_add_vlan(adapter, IAVF_VLAN(vid, be16_to_cpu(proto))))
                return -ENOMEM;
 
-       if (proto == cpu_to_be16(ETH_P_8021Q))
-               set_bit(vid, adapter->vsi.active_cvlans);
-       else
-               set_bit(vid, adapter->vsi.active_svlans);
-
        return 0;
 }
 
@@ -2245,7 +2240,6 @@ int iavf_parse_vf_resource_msg(struct iavf_adapter *adapter)
 
        adapter->vsi.back = adapter;
        adapter->vsi.base_vector = 1;
-       adapter->vsi.work_limit = IAVF_DEFAULT_IRQ_WORK;
        vsi->netdev = adapter->netdev;
        vsi->qs_handle = adapter->vsi_res->qset_handle;
        if (adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_RSS_PF) {
@@ -2956,6 +2950,9 @@ continue_reset:
        adapter->aq_required |= IAVF_FLAG_AQ_ADD_CLOUD_FILTER;
        iavf_misc_irq_enable(adapter);
 
+       bitmap_clear(adapter->vsi.active_cvlans, 0, VLAN_N_VID);
+       bitmap_clear(adapter->vsi.active_svlans, 0, VLAN_N_VID);
+
        mod_delayed_work(iavf_wq, &adapter->watchdog_task, 2);
 
        /* We were running when the reset started, so we need to restore some
index 978f651..06d1879 100644 (file)
@@ -194,7 +194,7 @@ static bool iavf_clean_tx_irq(struct iavf_vsi *vsi,
        struct iavf_tx_buffer *tx_buf;
        struct iavf_tx_desc *tx_desc;
        unsigned int total_bytes = 0, total_packets = 0;
-       unsigned int budget = vsi->work_limit;
+       unsigned int budget = IAVF_DEFAULT_IRQ_WORK;
 
        tx_buf = &tx_ring->tx_bi[i];
        tx_desc = IAVF_TX_DESC(tx_ring, i);
@@ -1285,11 +1285,10 @@ static struct iavf_rx_buffer *iavf_get_rx_buffer(struct iavf_ring *rx_ring,
 {
        struct iavf_rx_buffer *rx_buffer;
 
-       if (!size)
-               return NULL;
-
        rx_buffer = &rx_ring->rx_bi[rx_ring->next_to_clean];
        prefetchw(rx_buffer->page);
+       if (!size)
+               return rx_buffer;
 
        /* we are reusing so sync this buffer for CPU use */
        dma_sync_single_range_for_cpu(rx_ring->dev,
index 782450d..1603e99 100644 (file)
@@ -627,6 +627,33 @@ static void iavf_mac_add_reject(struct iavf_adapter *adapter)
 }
 
 /**
+ * iavf_vlan_add_reject
+ * @adapter: adapter structure
+ *
+ * Remove VLAN filters from list based on PF response.
+ **/
+static void iavf_vlan_add_reject(struct iavf_adapter *adapter)
+{
+       struct iavf_vlan_filter *f, *ftmp;
+
+       spin_lock_bh(&adapter->mac_vlan_list_lock);
+       list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
+               if (f->is_new_vlan) {
+                       if (f->vlan.tpid == ETH_P_8021Q)
+                               clear_bit(f->vlan.vid,
+                                         adapter->vsi.active_cvlans);
+                       else
+                               clear_bit(f->vlan.vid,
+                                         adapter->vsi.active_svlans);
+
+                       list_del(&f->list);
+                       kfree(f);
+               }
+       }
+       spin_unlock_bh(&adapter->mac_vlan_list_lock);
+}
+
+/**
  * iavf_add_vlans
  * @adapter: adapter structure
  *
@@ -683,6 +710,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter)
                                vvfl->vlan_id[i] = f->vlan.vid;
                                i++;
                                f->add = false;
+                               f->is_new_vlan = true;
                                if (i == count)
                                        break;
                        }
@@ -695,10 +723,18 @@ void iavf_add_vlans(struct iavf_adapter *adapter)
                iavf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_VLAN, (u8 *)vvfl, len);
                kfree(vvfl);
        } else {
+               u16 max_vlans = adapter->vlan_v2_caps.filtering.max_filters;
+               u16 current_vlans = iavf_get_num_vlans_added(adapter);
                struct virtchnl_vlan_filter_list_v2 *vvfl_v2;
 
                adapter->current_op = VIRTCHNL_OP_ADD_VLAN_V2;
 
+               if ((count + current_vlans) > max_vlans &&
+                   current_vlans < max_vlans) {
+                       count = max_vlans - iavf_get_num_vlans_added(adapter);
+                       more = true;
+               }
+
                len = sizeof(*vvfl_v2) + ((count - 1) *
                                          sizeof(struct virtchnl_vlan_filter));
                if (len > IAVF_MAX_AQ_BUF_SIZE) {
@@ -725,6 +761,9 @@ void iavf_add_vlans(struct iavf_adapter *adapter)
                                        &adapter->vlan_v2_caps.filtering.filtering_support;
                                struct virtchnl_vlan *vlan;
 
+                               if (i == count)
+                                       break;
+
                                /* give priority over outer if it's enabled */
                                if (filtering_support->outer)
                                        vlan = &vvfl_v2->filters[i].outer;
@@ -736,8 +775,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter)
 
                                i++;
                                f->add = false;
-                               if (i == count)
-                                       break;
+                               f->is_new_vlan = true;
                        }
                }
 
@@ -2080,6 +2118,11 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
                         */
                        iavf_netdev_features_vlan_strip_set(netdev, true);
                        break;
+               case VIRTCHNL_OP_ADD_VLAN_V2:
+                       iavf_vlan_add_reject(adapter);
+                       dev_warn(&adapter->pdev->dev, "Failed to add VLAN filter, error %s\n",
+                                iavf_stat_str(&adapter->hw, v_retval));
+                       break;
                default:
                        dev_err(&adapter->pdev->dev, "PF returned error %d (%s) to our request %d\n",
                                v_retval, iavf_stat_str(&adapter->hw, v_retval),
@@ -2332,6 +2375,24 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
                spin_unlock_bh(&adapter->adv_rss_lock);
                }
                break;
+       case VIRTCHNL_OP_ADD_VLAN_V2: {
+               struct iavf_vlan_filter *f;
+
+               spin_lock_bh(&adapter->mac_vlan_list_lock);
+               list_for_each_entry(f, &adapter->vlan_filter_list, list) {
+                       if (f->is_new_vlan) {
+                               f->is_new_vlan = false;
+                               if (f->vlan.tpid == ETH_P_8021Q)
+                                       set_bit(f->vlan.vid,
+                                               adapter->vsi.active_cvlans);
+                               else
+                                       set_bit(f->vlan.vid,
+                                               adapter->vsi.active_svlans);
+                       }
+               }
+               spin_unlock_bh(&adapter->mac_vlan_list_lock);
+               }
+               break;
        case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING:
                /* PF enabled vlan strip on this VF.
                 * Update netdev->features if needed to be in sync with ethtool.
index 61dd2f1..b41bc3d 100644 (file)
@@ -5,6 +5,7 @@
 #define _ICE_DEVIDS_H_
 
 /* Device IDs */
+#define ICE_DEV_ID_E822_SI_DFLT         0x1888
 /* Intel(R) Ethernet Connection E823-L for backplane */
 #define ICE_DEV_ID_E823L_BACKPLANE     0x124C
 /* Intel(R) Ethernet Connection E823-L for SFP */
index 3991d62..3337314 100644 (file)
@@ -814,6 +814,8 @@ void ice_devlink_destroy_vf_port(struct ice_vf *vf)
        devlink_port_unregister(devlink_port);
 }
 
+#define ICE_DEVLINK_READ_BLK_SIZE (1024 * 1024)
+
 /**
  * ice_devlink_nvm_snapshot - Capture a snapshot of the NVM flash contents
  * @devlink: the devlink instance
@@ -840,8 +842,9 @@ static int ice_devlink_nvm_snapshot(struct devlink *devlink,
        struct ice_pf *pf = devlink_priv(devlink);
        struct device *dev = ice_pf_to_dev(pf);
        struct ice_hw *hw = &pf->hw;
-       void *nvm_data;
-       u32 nvm_size;
+       u8 *nvm_data, *tmp, i;
+       u32 nvm_size, left;
+       s8 num_blks;
        int status;
 
        nvm_size = hw->flash.flash_size;
@@ -849,26 +852,44 @@ static int ice_devlink_nvm_snapshot(struct devlink *devlink,
        if (!nvm_data)
                return -ENOMEM;
 
-       status = ice_acquire_nvm(hw, ICE_RES_READ);
-       if (status) {
-               dev_dbg(dev, "ice_acquire_nvm failed, err %d aq_err %d\n",
-                       status, hw->adminq.sq_last_status);
-               NL_SET_ERR_MSG_MOD(extack, "Failed to acquire NVM semaphore");
-               vfree(nvm_data);
-               return status;
-       }
 
-       status = ice_read_flat_nvm(hw, 0, &nvm_size, nvm_data, false);
-       if (status) {
-               dev_dbg(dev, "ice_read_flat_nvm failed after reading %u bytes, err %d aq_err %d\n",
-                       nvm_size, status, hw->adminq.sq_last_status);
-               NL_SET_ERR_MSG_MOD(extack, "Failed to read NVM contents");
+       num_blks = DIV_ROUND_UP(nvm_size, ICE_DEVLINK_READ_BLK_SIZE);
+       tmp = nvm_data;
+       left = nvm_size;
+
+       /* Some systems take longer to read the NVM than others which causes the
+        * FW to reclaim the NVM lock before the entire NVM has been read. Fix
+        * this by breaking the reads of the NVM into smaller chunks that will
+        * probably not take as long. This has some overhead since we are
+        * increasing the number of AQ commands, but it should always work
+        */
+       for (i = 0; i < num_blks; i++) {
+               u32 read_sz = min_t(u32, ICE_DEVLINK_READ_BLK_SIZE, left);
+
+               status = ice_acquire_nvm(hw, ICE_RES_READ);
+               if (status) {
+                       dev_dbg(dev, "ice_acquire_nvm failed, err %d aq_err %d\n",
+                               status, hw->adminq.sq_last_status);
+                       NL_SET_ERR_MSG_MOD(extack, "Failed to acquire NVM semaphore");
+                       vfree(nvm_data);
+                       return -EIO;
+               }
+
+               status = ice_read_flat_nvm(hw, i * ICE_DEVLINK_READ_BLK_SIZE,
+                                          &read_sz, tmp, false);
+               if (status) {
+                       dev_dbg(dev, "ice_read_flat_nvm failed after reading %u bytes, err %d aq_err %d\n",
+                               read_sz, status, hw->adminq.sq_last_status);
+                       NL_SET_ERR_MSG_MOD(extack, "Failed to read NVM contents");
+                       ice_release_nvm(hw);
+                       vfree(nvm_data);
+                       return -EIO;
+               }
                ice_release_nvm(hw);
-               vfree(nvm_data);
-               return status;
-       }
 
-       ice_release_nvm(hw);
+               tmp += read_sz;
+               left -= read_sz;
+       }
 
        *data = nvm_data;
 
index 70335f6..4efa5e5 100644 (file)
@@ -658,7 +658,8 @@ static int ice_lbtest_receive_frames(struct ice_rx_ring *rx_ring)
                rx_desc = ICE_RX_DESC(rx_ring, i);
 
                if (!(rx_desc->wb.status_error0 &
-                   cpu_to_le16(ICE_TX_DESC_CMD_EOP | ICE_TX_DESC_CMD_RS)))
+                   (cpu_to_le16(BIT(ICE_RX_FLEX_DESC_STATUS0_DD_S)) |
+                    cpu_to_le16(BIT(ICE_RX_FLEX_DESC_STATUS0_EOF_S)))))
                        continue;
 
                rx_buf = &rx_ring->rx_buf[i];
index 665a344..3dc5662 100644 (file)
@@ -736,7 +736,87 @@ static int ice_finalize_update(struct pldmfw *context)
        return 0;
 }
 
-static const struct pldmfw_ops ice_fwu_ops = {
+struct ice_pldm_pci_record_id {
+       u32 vendor;
+       u32 device;
+       u32 subsystem_vendor;
+       u32 subsystem_device;
+};
+
+/**
+ * ice_op_pci_match_record - Check if a PCI device matches the record
+ * @context: PLDM fw update structure
+ * @record: list of records extracted from the PLDM image
+ *
+ * Determine if the PCI device associated with this device matches the record
+ * data provided.
+ *
+ * Searches the descriptor TLVs and extracts the relevant descriptor data into
+ * a pldm_pci_record_id. This is then compared against the PCI device ID
+ * information.
+ *
+ * Returns: true if the device matches the record, false otherwise.
+ */
+static bool
+ice_op_pci_match_record(struct pldmfw *context, struct pldmfw_record *record)
+{
+       struct pci_dev *pdev = to_pci_dev(context->dev);
+       struct ice_pldm_pci_record_id id = {
+               .vendor = PCI_ANY_ID,
+               .device = PCI_ANY_ID,
+               .subsystem_vendor = PCI_ANY_ID,
+               .subsystem_device = PCI_ANY_ID,
+       };
+       struct pldmfw_desc_tlv *desc;
+
+       list_for_each_entry(desc, &record->descs, entry) {
+               u16 value;
+               int *ptr;
+
+               switch (desc->type) {
+               case PLDM_DESC_ID_PCI_VENDOR_ID:
+                       ptr = &id.vendor;
+                       break;
+               case PLDM_DESC_ID_PCI_DEVICE_ID:
+                       ptr = &id.device;
+                       break;
+               case PLDM_DESC_ID_PCI_SUBVENDOR_ID:
+                       ptr = &id.subsystem_vendor;
+                       break;
+               case PLDM_DESC_ID_PCI_SUBDEV_ID:
+                       ptr = &id.subsystem_device;
+                       break;
+               default:
+                       /* Skip unrelated TLVs */
+                       continue;
+               }
+
+               value = get_unaligned_le16(desc->data);
+               /* A value of zero for one of the descriptors is sometimes
+                * used when the record should ignore this field when matching
+                * device. For example if the record applies to any subsystem
+                * device or vendor.
+                */
+               if (value)
+                       *ptr = value;
+               else
+                       *ptr = PCI_ANY_ID;
+       }
+
+       /* the E822 device can have a generic device ID so check for that */
+       if ((id.vendor == PCI_ANY_ID || id.vendor == pdev->vendor) &&
+           (id.device == PCI_ANY_ID || id.device == pdev->device ||
+           id.device == ICE_DEV_ID_E822_SI_DFLT) &&
+           (id.subsystem_vendor == PCI_ANY_ID ||
+           id.subsystem_vendor == pdev->subsystem_vendor) &&
+           (id.subsystem_device == PCI_ANY_ID ||
+           id.subsystem_device == pdev->subsystem_device))
+               return true;
+
+       return false;
+}
+
+static const struct pldmfw_ops ice_fwu_ops_e810 = {
        .match_record = &pldmfw_op_pci_match_record,
        .send_package_data = &ice_send_package_data,
        .send_component_table = &ice_send_component_table,
@@ -744,6 +824,14 @@ static const struct pldmfw_ops ice_fwu_ops = {
        .finalize_update = &ice_finalize_update,
 };
 
+static const struct pldmfw_ops ice_fwu_ops_e822 = {
+       .match_record = &ice_op_pci_match_record,
+       .send_package_data = &ice_send_package_data,
+       .send_component_table = &ice_send_component_table,
+       .flash_component = &ice_flash_component,
+       .finalize_update = &ice_finalize_update,
+};
+
 /**
  * ice_get_pending_updates - Check if the component has a pending update
  * @pf: the PF driver structure
@@ -921,7 +1009,11 @@ int ice_devlink_flash_update(struct devlink *devlink,
 
        memset(&priv, 0, sizeof(priv));
 
-       priv.context.ops = &ice_fwu_ops;
+       /* the E822 device needs a slightly different ops */
+       if (hw->mac_type == ICE_MAC_GENERIC)
+               priv.context.ops = &ice_fwu_ops_e822;
+       else
+               priv.context.ops = &ice_fwu_ops_e810;
        priv.context.dev = dev;
        priv.extack = extack;
        priv.pf = pf;
index c1ac2f7..9f02b60 100644 (file)
@@ -4656,6 +4656,8 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
                ice_set_safe_mode_caps(hw);
        }
 
+       hw->ucast_shared = true;
+
        err = ice_init_pf(pf);
        if (err) {
                dev_err(dev, "ice_init_pf failed: %d\n", err);
@@ -5413,6 +5415,7 @@ static const struct pci_device_id ice_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_10G_BASE_T), 0 },
        { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_1GBE), 0 },
        { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_QSFP), 0 },
+       { PCI_VDEVICE(INTEL, ICE_DEV_ID_E822_SI_DFLT), 0 },
        /* required last entry */
        { 0, }
 };
@@ -6010,10 +6013,12 @@ int ice_vsi_cfg(struct ice_vsi *vsi)
        if (vsi->netdev) {
                ice_set_rx_mode(vsi->netdev);
 
-               err = ice_vsi_vlan_setup(vsi);
+               if (vsi->type != ICE_VSI_LB) {
+                       err = ice_vsi_vlan_setup(vsi);
 
-               if (err)
-                       return err;
+                       if (err)
+                               return err;
+               }
        }
        ice_vsi_cfg_dcb_rings(vsi);
 
index bb1721f..f4907a3 100644 (file)
@@ -1310,39 +1310,6 @@ out_put_vf:
 }
 
 /**
- * ice_unicast_mac_exists - check if the unicast MAC exists on the PF's switch
- * @pf: PF used to reference the switch's rules
- * @umac: unicast MAC to compare against existing switch rules
- *
- * Return true on the first/any match, else return false
- */
-static bool ice_unicast_mac_exists(struct ice_pf *pf, u8 *umac)
-{
-       struct ice_sw_recipe *mac_recipe_list =
-               &pf->hw.switch_info->recp_list[ICE_SW_LKUP_MAC];
-       struct ice_fltr_mgmt_list_entry *list_itr;
-       struct list_head *rule_head;
-       struct mutex *rule_lock; /* protect MAC filter list access */
-
-       rule_head = &mac_recipe_list->filt_rules;
-       rule_lock = &mac_recipe_list->filt_rule_lock;
-
-       mutex_lock(rule_lock);
-       list_for_each_entry(list_itr, rule_head, list_entry) {
-               u8 *existing_mac = &list_itr->fltr_info.l_data.mac.mac_addr[0];
-
-               if (ether_addr_equal(existing_mac, umac)) {
-                       mutex_unlock(rule_lock);
-                       return true;
-               }
-       }
-
-       mutex_unlock(rule_lock);
-
-       return false;
-}
-
-/**
  * ice_set_vf_mac
  * @netdev: network interface device structure
  * @vf_id: VF identifier
@@ -1376,13 +1343,6 @@ int ice_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
        if (ret)
                goto out_put_vf;
 
-       if (ice_unicast_mac_exists(pf, mac)) {
-               netdev_err(netdev, "Unicast MAC %pM already exists on this PF. Preventing setting VF %u unicast MAC address to %pM\n",
-                          mac, vf_id, mac);
-               ret = -EINVAL;
-               goto out_put_vf;
-       }
-
        mutex_lock(&vf->cfg_lock);
 
        /* VF is notified of its new MAC via the PF's response to the
index 3f8b727..836dce8 100644 (file)
@@ -1751,11 +1751,13 @@ int ice_tx_csum(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
 
        protocol = vlan_get_protocol(skb);
 
-       if (eth_p_mpls(protocol))
+       if (eth_p_mpls(protocol)) {
                ip.hdr = skb_inner_network_header(skb);
-       else
+               l4.hdr = skb_checksum_start(skb);
+       } else {
                ip.hdr = skb_network_header(skb);
-       l4.hdr = skb_checksum_start(skb);
+               l4.hdr = skb_transport_header(skb);
+       }
 
        /* compute outer L2 header size */
        l2_len = ip.hdr - skb->data;
index 4547bc1..24188ec 100644 (file)
@@ -2948,7 +2948,8 @@ ice_vc_validate_add_vlan_filter_list(struct ice_vsi *vsi,
                                     struct virtchnl_vlan_filtering_caps *vfc,
                                     struct virtchnl_vlan_filter_list_v2 *vfl)
 {
-       u16 num_requested_filters = vsi->num_vlan + vfl->num_elements;
+       u16 num_requested_filters = ice_vsi_num_non_zero_vlans(vsi) +
+               vfl->num_elements;
 
        if (num_requested_filters > vfc->max_filters)
                return false;
index ae17af4..a5ebee7 100644 (file)
@@ -6171,6 +6171,9 @@ u32 igc_rd32(struct igc_hw *hw, u32 reg)
        u8 __iomem *hw_addr = READ_ONCE(hw->hw_addr);
        u32 value = 0;
 
+       if (IGC_REMOVED(hw_addr))
+               return ~value;
+
        value = readl(&hw_addr[reg]);
 
        /* reads should not return all F's */
index e197a33..026c3b6 100644 (file)
@@ -306,7 +306,8 @@ u32 igc_rd32(struct igc_hw *hw, u32 reg);
 #define wr32(reg, val) \
 do { \
        u8 __iomem *hw_addr = READ_ONCE((hw)->hw_addr); \
-       writel((val), &hw_addr[(reg)]); \
+       if (!IGC_REMOVED(hw_addr)) \
+               writel((val), &hw_addr[(reg)]); \
 } while (0)
 
 #define rd32(reg) (igc_rd32(hw, reg))
@@ -318,4 +319,6 @@ do { \
 
 #define array_rd32(reg, offset) (igc_rd32(hw, (reg) + ((offset) << 2)))
 
+#define IGC_REMOVED(h) unlikely(!(h))
+
 #endif
index 921a4d9..8813b4d 100644 (file)
@@ -779,6 +779,7 @@ struct ixgbe_adapter {
 #ifdef CONFIG_IXGBE_IPSEC
        struct ixgbe_ipsec *ipsec;
 #endif /* CONFIG_IXGBE_IPSEC */
+       spinlock_t vfs_lock;
 };
 
 static inline int ixgbe_determine_xdp_q_idx(int cpu)
index 77c2e70..55f91c9 100644 (file)
@@ -6403,6 +6403,9 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter,
        /* n-tuple support exists, always init our spinlock */
        spin_lock_init(&adapter->fdir_perfect_lock);
 
+       /* init spinlock to avoid concurrency of VF resources */
+       spin_lock_init(&adapter->vfs_lock);
+
 #ifdef CONFIG_IXGBE_DCB
        ixgbe_init_dcb(adapter);
 #endif
index d4e63f0..a1e69c7 100644 (file)
@@ -205,10 +205,13 @@ void ixgbe_enable_sriov(struct ixgbe_adapter *adapter, unsigned int max_vfs)
 int ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
 {
        unsigned int num_vfs = adapter->num_vfs, vf;
+       unsigned long flags;
        int rss;
 
+       spin_lock_irqsave(&adapter->vfs_lock, flags);
        /* set num VFs to 0 to prevent access to vfinfo */
        adapter->num_vfs = 0;
+       spin_unlock_irqrestore(&adapter->vfs_lock, flags);
 
        /* put the reference to all of the vf devices */
        for (vf = 0; vf < num_vfs; ++vf) {
@@ -1355,8 +1358,10 @@ static void ixgbe_rcv_ack_from_vf(struct ixgbe_adapter *adapter, u32 vf)
 void ixgbe_msg_task(struct ixgbe_adapter *adapter)
 {
        struct ixgbe_hw *hw = &adapter->hw;
+       unsigned long flags;
        u32 vf;
 
+       spin_lock_irqsave(&adapter->vfs_lock, flags);
        for (vf = 0; vf < adapter->num_vfs; vf++) {
                /* process any reset requests */
                if (!ixgbe_check_for_rst(hw, vf))
@@ -1370,6 +1375,7 @@ void ixgbe_msg_task(struct ixgbe_adapter *adapter)
                if (!ixgbe_check_for_ack(hw, vf))
                        ixgbe_rcv_ack_from_vf(adapter, vf);
        }
+       spin_unlock_irqrestore(&adapter->vfs_lock, flags);
 }
 
 static inline void ixgbe_ping_vf(struct ixgbe_adapter *adapter, int vf)
index cc51149..3d5d39a 100644 (file)
@@ -52,7 +52,7 @@
 
 #define    CN93_SDP_EPF_RINFO_SRN(val)           ((val) & 0xFF)
 #define    CN93_SDP_EPF_RINFO_RPVF(val)          (((val) >> 32) & 0xF)
-#define    CN93_SDP_EPF_RINFO_NVFS(val)          (((val) >> 48) && 0xFF)
+#define    CN93_SDP_EPF_RINFO_NVFS(val)          (((val) >> 48) & 0xFF)
 
 /* SDP Function select */
 #define    CN93_SDP_FUNC_SEL_EPF_BIT_POS         8
index 28b1994..e64318c 100644 (file)
@@ -28,6 +28,9 @@
 #define MAX_RATE_EXPONENT              0x0FULL
 #define MAX_RATE_MANTISSA              0xFFULL
 
+#define CN10K_MAX_BURST_MANTISSA       0x7FFFULL
+#define CN10K_MAX_BURST_SIZE           8453888ULL
+
 /* Bitfields in NIX_TLX_PIR register */
 #define TLX_RATE_MANTISSA              GENMASK_ULL(8, 1)
 #define TLX_RATE_EXPONENT              GENMASK_ULL(12, 9)
@@ -35,6 +38,9 @@
 #define TLX_BURST_MANTISSA             GENMASK_ULL(36, 29)
 #define TLX_BURST_EXPONENT             GENMASK_ULL(40, 37)
 
+#define CN10K_TLX_BURST_MANTISSA       GENMASK_ULL(43, 29)
+#define CN10K_TLX_BURST_EXPONENT       GENMASK_ULL(47, 44)
+
 struct otx2_tc_flow_stats {
        u64 bytes;
        u64 pkts;
@@ -77,33 +83,42 @@ int otx2_tc_alloc_ent_bitmap(struct otx2_nic *nic)
 }
 EXPORT_SYMBOL(otx2_tc_alloc_ent_bitmap);
 
-static void otx2_get_egress_burst_cfg(u32 burst, u32 *burst_exp,
-                                     u32 *burst_mantissa)
+static void otx2_get_egress_burst_cfg(struct otx2_nic *nic, u32 burst,
+                                     u32 *burst_exp, u32 *burst_mantissa)
 {
+       int max_burst, max_mantissa;
        unsigned int tmp;
 
+       if (is_dev_otx2(nic->pdev)) {
+               max_burst = MAX_BURST_SIZE;
+               max_mantissa = MAX_BURST_MANTISSA;
+       } else {
+               max_burst = CN10K_MAX_BURST_SIZE;
+               max_mantissa = CN10K_MAX_BURST_MANTISSA;
+       }
+
        /* Burst is calculated as
         * ((256 + BURST_MANTISSA) << (1 + BURST_EXPONENT)) / 256
         * Max supported burst size is 130,816 bytes.
         */
-       burst = min_t(u32, burst, MAX_BURST_SIZE);
+       burst = min_t(u32, burst, max_burst);
        if (burst) {
                *burst_exp = ilog2(burst) ? ilog2(burst) - 1 : 0;
                tmp = burst - rounddown_pow_of_two(burst);
-               if (burst < MAX_BURST_MANTISSA)
+               if (burst < max_mantissa)
                        *burst_mantissa = tmp * 2;
                else
                        *burst_mantissa = tmp / (1ULL << (*burst_exp - 7));
        } else {
                *burst_exp = MAX_BURST_EXPONENT;
-               *burst_mantissa = MAX_BURST_MANTISSA;
+               *burst_mantissa = max_mantissa;
        }
 }
 
-static void otx2_get_egress_rate_cfg(u32 maxrate, u32 *exp,
+static void otx2_get_egress_rate_cfg(u64 maxrate, u32 *exp,
                                     u32 *mantissa, u32 *div_exp)
 {
-       unsigned int tmp;
+       u64 tmp;
 
        /* Rate calculation by hardware
         *
@@ -132,21 +147,44 @@ static void otx2_get_egress_rate_cfg(u32 maxrate, u32 *exp,
        }
 }
 
-static int otx2_set_matchall_egress_rate(struct otx2_nic *nic, u32 burst, u32 maxrate)
+static u64 otx2_get_txschq_rate_regval(struct otx2_nic *nic,
+                                      u64 maxrate, u32 burst)
 {
-       struct otx2_hw *hw = &nic->hw;
-       struct nix_txschq_config *req;
        u32 burst_exp, burst_mantissa;
        u32 exp, mantissa, div_exp;
+       u64 regval = 0;
+
+       /* Get exponent and mantissa values from the desired rate */
+       otx2_get_egress_burst_cfg(nic, burst, &burst_exp, &burst_mantissa);
+       otx2_get_egress_rate_cfg(maxrate, &exp, &mantissa, &div_exp);
+
+       if (is_dev_otx2(nic->pdev)) {
+               regval = FIELD_PREP(TLX_BURST_EXPONENT, (u64)burst_exp) |
+                               FIELD_PREP(TLX_BURST_MANTISSA, (u64)burst_mantissa) |
+                               FIELD_PREP(TLX_RATE_DIVIDER_EXPONENT, div_exp) |
+                               FIELD_PREP(TLX_RATE_EXPONENT, exp) |
+                               FIELD_PREP(TLX_RATE_MANTISSA, mantissa) | BIT_ULL(0);
+       } else {
+               regval = FIELD_PREP(CN10K_TLX_BURST_EXPONENT, (u64)burst_exp) |
+                               FIELD_PREP(CN10K_TLX_BURST_MANTISSA, (u64)burst_mantissa) |
+                               FIELD_PREP(TLX_RATE_DIVIDER_EXPONENT, div_exp) |
+                               FIELD_PREP(TLX_RATE_EXPONENT, exp) |
+                               FIELD_PREP(TLX_RATE_MANTISSA, mantissa) | BIT_ULL(0);
+       }
+
+       return regval;
+}
+
+static int otx2_set_matchall_egress_rate(struct otx2_nic *nic,
+                                        u32 burst, u64 maxrate)
+{
+       struct otx2_hw *hw = &nic->hw;
+       struct nix_txschq_config *req;
        int txschq, err;
 
        /* All SQs share the same TL4, so pick the first scheduler */
        txschq = hw->txschq_list[NIX_TXSCH_LVL_TL4][0];
 
-       /* Get exponent and mantissa values from the desired rate */
-       otx2_get_egress_burst_cfg(burst, &burst_exp, &burst_mantissa);
-       otx2_get_egress_rate_cfg(maxrate, &exp, &mantissa, &div_exp);
-
        mutex_lock(&nic->mbox.lock);
        req = otx2_mbox_alloc_msg_nix_txschq_cfg(&nic->mbox);
        if (!req) {
@@ -157,11 +195,7 @@ static int otx2_set_matchall_egress_rate(struct otx2_nic *nic, u32 burst, u32 ma
        req->lvl = NIX_TXSCH_LVL_TL4;
        req->num_regs = 1;
        req->reg[0] = NIX_AF_TL4X_PIR(txschq);
-       req->regval[0] = FIELD_PREP(TLX_BURST_EXPONENT, burst_exp) |
-                        FIELD_PREP(TLX_BURST_MANTISSA, burst_mantissa) |
-                        FIELD_PREP(TLX_RATE_DIVIDER_EXPONENT, div_exp) |
-                        FIELD_PREP(TLX_RATE_EXPONENT, exp) |
-                        FIELD_PREP(TLX_RATE_MANTISSA, mantissa) | BIT_ULL(0);
+       req->regval[0] = otx2_get_txschq_rate_regval(nic, maxrate, burst);
 
        err = otx2_sync_mbox_msg(&nic->mbox);
        mutex_unlock(&nic->mbox.lock);
@@ -230,7 +264,7 @@ static int otx2_tc_egress_matchall_install(struct otx2_nic *nic,
        struct netlink_ext_ack *extack = cls->common.extack;
        struct flow_action *actions = &cls->rule->action;
        struct flow_action_entry *entry;
-       u32 rate;
+       u64 rate;
        int err;
 
        err = otx2_tc_validate_flow(nic, actions, extack);
@@ -256,7 +290,7 @@ static int otx2_tc_egress_matchall_install(struct otx2_nic *nic,
                }
                /* Convert bytes per second to Mbps */
                rate = entry->police.rate_bytes_ps * 8;
-               rate = max_t(u32, rate / 1000000, 1);
+               rate = max_t(u64, rate / 1000000, 1);
                err = otx2_set_matchall_egress_rate(nic, entry->police.burst, rate);
                if (err)
                        return err;
@@ -614,21 +648,27 @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node,
 
                flow_spec->dport = match.key->dst;
                flow_mask->dport = match.mask->dst;
-               if (ip_proto == IPPROTO_UDP)
-                       req->features |= BIT_ULL(NPC_DPORT_UDP);
-               else if (ip_proto == IPPROTO_TCP)
-                       req->features |= BIT_ULL(NPC_DPORT_TCP);
-               else if (ip_proto == IPPROTO_SCTP)
-                       req->features |= BIT_ULL(NPC_DPORT_SCTP);
+
+               if (flow_mask->dport) {
+                       if (ip_proto == IPPROTO_UDP)
+                               req->features |= BIT_ULL(NPC_DPORT_UDP);
+                       else if (ip_proto == IPPROTO_TCP)
+                               req->features |= BIT_ULL(NPC_DPORT_TCP);
+                       else if (ip_proto == IPPROTO_SCTP)
+                               req->features |= BIT_ULL(NPC_DPORT_SCTP);
+               }
 
                flow_spec->sport = match.key->src;
                flow_mask->sport = match.mask->src;
-               if (ip_proto == IPPROTO_UDP)
-                       req->features |= BIT_ULL(NPC_SPORT_UDP);
-               else if (ip_proto == IPPROTO_TCP)
-                       req->features |= BIT_ULL(NPC_SPORT_TCP);
-               else if (ip_proto == IPPROTO_SCTP)
-                       req->features |= BIT_ULL(NPC_SPORT_SCTP);
+
+               if (flow_mask->sport) {
+                       if (ip_proto == IPPROTO_UDP)
+                               req->features |= BIT_ULL(NPC_SPORT_UDP);
+                       else if (ip_proto == IPPROTO_TCP)
+                               req->features |= BIT_ULL(NPC_SPORT_TCP);
+                       else if (ip_proto == IPPROTO_SCTP)
+                               req->features |= BIT_ULL(NPC_SPORT_SCTP);
+               }
        }
 
        return otx2_tc_parse_actions(nic, &rule->action, req, f, node);
index d43e503..4d93ad6 100644 (file)
@@ -167,12 +167,12 @@ static int prestera_flower_parse_meta(struct prestera_acl_rule *rule,
        }
        port = netdev_priv(ingress_dev);
 
-       mask = htons(0x1FFF);
-       key = htons(port->hw_id);
+       mask = htons(0x1FFF << 3);
+       key = htons(port->hw_id << 3);
        rule_match_set(r_match->key, SYS_PORT, key);
        rule_match_set(r_match->mask, SYS_PORT, mask);
 
-       mask = htons(0x1FF);
+       mask = htons(0x3FF);
        key = htons(port->dev_id);
        rule_match_set(r_match->key, SYS_DEV, key);
        rule_match_set(r_match->mask, SYS_DEV, mask);
index 3754d8a..3c8116f 100644 (file)
@@ -588,6 +588,7 @@ err_router_lib_init:
 
 void prestera_router_fini(struct prestera_switch *sw)
 {
+       unregister_fib_notifier(&init_net, &sw->router->fib_nb);
        unregister_inetaddr_notifier(&sw->router->inetaddr_nb);
        unregister_inetaddr_validator_notifier(&sw->router->inetaddr_valid_nb);
        rhashtable_destroy(&sw->router->kern_fib_cache_ht);
index 90e7dfd..5d457bc 100644 (file)
@@ -93,6 +93,9 @@ mtk_flow_get_wdma_info(struct net_device *dev, const u8 *addr, struct mtk_wdma_i
        };
        struct net_device_path path = {};
 
+       if (!ctx.dev)
+               return -ENODEV;
+
        memcpy(ctx.daddr, addr, sizeof(ctx.daddr));
 
        if (!IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED))
index 8f0cd31..29be2fc 100644 (file)
@@ -651,7 +651,7 @@ mtk_wed_tx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs)
         * WDMA RX.
         */
 
-       BUG_ON(idx > ARRAY_SIZE(dev->tx_ring));
+       BUG_ON(idx >= ARRAY_SIZE(dev->tx_ring));
 
        if (mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE))
                return -ENOMEM;
index 25f51f8..ba171c7 100644 (file)
@@ -76,6 +76,7 @@ struct mlx5_tc_ct_priv {
        struct mlx5_ct_fs *fs;
        struct mlx5_ct_fs_ops *fs_ops;
        spinlock_t ht_lock; /* protects ft entries */
+       struct workqueue_struct *wq;
 
        struct mlx5_tc_ct_debugfs debugfs;
 };
@@ -941,14 +942,11 @@ static void mlx5_tc_ct_entry_del_work(struct work_struct *work)
 static void
 __mlx5_tc_ct_entry_put(struct mlx5_ct_entry *entry)
 {
-       struct mlx5e_priv *priv;
-
        if (!refcount_dec_and_test(&entry->refcnt))
                return;
 
-       priv = netdev_priv(entry->ct_priv->netdev);
        INIT_WORK(&entry->work, mlx5_tc_ct_entry_del_work);
-       queue_work(priv->wq, &entry->work);
+       queue_work(entry->ct_priv->wq, &entry->work);
 }
 
 static struct mlx5_ct_counter *
@@ -1759,19 +1757,16 @@ mlx5_tc_ct_flush_ft_entry(void *ptr, void *arg)
 static void
 mlx5_tc_ct_del_ft_cb(struct mlx5_tc_ct_priv *ct_priv, struct mlx5_ct_ft *ft)
 {
-       struct mlx5e_priv *priv;
-
        if (!refcount_dec_and_test(&ft->refcount))
                return;
 
+       flush_workqueue(ct_priv->wq);
        nf_flow_table_offload_del_cb(ft->nf_ft,
                                     mlx5_tc_ct_block_flow_offload, ft);
        rhashtable_remove_fast(&ct_priv->zone_ht, &ft->node, zone_params);
        rhashtable_free_and_destroy(&ft->ct_entries_ht,
                                    mlx5_tc_ct_flush_ft_entry,
                                    ct_priv);
-       priv = netdev_priv(ct_priv->netdev);
-       flush_workqueue(priv->wq);
        mlx5_tc_ct_free_pre_ct_tables(ft);
        mapping_remove(ct_priv->zone_mapping, ft->zone_restore_id);
        kfree(ft);
@@ -2176,6 +2171,12 @@ mlx5_tc_ct_init(struct mlx5e_priv *priv, struct mlx5_fs_chains *chains,
        if (rhashtable_init(&ct_priv->ct_tuples_nat_ht, &tuples_nat_ht_params))
                goto err_ct_tuples_nat_ht;
 
+       ct_priv->wq = alloc_ordered_workqueue("mlx5e_ct_priv_wq", 0);
+       if (!ct_priv->wq) {
+               err = -ENOMEM;
+               goto err_wq;
+       }
+
        err = mlx5_tc_ct_fs_init(ct_priv);
        if (err)
                goto err_init_fs;
@@ -2184,6 +2185,8 @@ mlx5_tc_ct_init(struct mlx5e_priv *priv, struct mlx5_fs_chains *chains,
        return ct_priv;
 
 err_init_fs:
+       destroy_workqueue(ct_priv->wq);
+err_wq:
        rhashtable_destroy(&ct_priv->ct_tuples_nat_ht);
 err_ct_tuples_nat_ht:
        rhashtable_destroy(&ct_priv->ct_tuples_ht);
@@ -2213,6 +2216,7 @@ mlx5_tc_ct_clean(struct mlx5_tc_ct_priv *ct_priv)
        if (!ct_priv)
                return;
 
+       destroy_workqueue(ct_priv->wq);
        mlx5_ct_tc_remove_dbgfs(ct_priv);
        chains = ct_priv->chains;
 
index 0bb0633..27483aa 100644 (file)
@@ -231,8 +231,7 @@ mlx5e_set_ktls_rx_priv_ctx(struct tls_context *tls_ctx,
        struct mlx5e_ktls_offload_context_rx **ctx =
                __tls_driver_ctx(tls_ctx, TLS_OFFLOAD_CTX_DIR_RX);
 
-       BUILD_BUG_ON(sizeof(struct mlx5e_ktls_offload_context_rx *) >
-                    TLS_OFFLOAD_CONTEXT_SIZE_RX);
+       BUILD_BUG_ON(sizeof(priv_rx) > TLS_DRIVER_STATE_SIZE_RX);
 
        *ctx = priv_rx;
 }
index 4b6f0d1..f239fb2 100644 (file)
@@ -68,8 +68,7 @@ mlx5e_set_ktls_tx_priv_ctx(struct tls_context *tls_ctx,
        struct mlx5e_ktls_offload_context_tx **ctx =
                __tls_driver_ctx(tls_ctx, TLS_OFFLOAD_CTX_DIR_TX);
 
-       BUILD_BUG_ON(sizeof(struct mlx5e_ktls_offload_context_tx *) >
-                    TLS_OFFLOAD_CONTEXT_SIZE_TX);
+       BUILD_BUG_ON(sizeof(priv_tx) > TLS_DRIVER_STATE_SIZE_TX);
 
        *ctx = priv_tx;
 }
index 57fa048..1e87bb2 100644 (file)
@@ -688,7 +688,7 @@ static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(vnic_env)
        u32 in[MLX5_ST_SZ_DW(query_vnic_env_in)] = {};
        struct mlx5_core_dev *mdev = priv->mdev;
 
-       if (!MLX5_CAP_GEN(priv->mdev, nic_receive_steering_discard))
+       if (!mlx5e_stats_grp_vnic_env_num_stats(priv))
                return;
 
        MLX5_SET(query_vnic_env_in, in, opcode, MLX5_CMD_OP_QUERY_VNIC_ENV);
index 34bf11c..9ca2c87 100644 (file)
@@ -3793,7 +3793,7 @@ static bool is_lag_dev(struct mlx5e_priv *priv,
 
 static bool is_multiport_eligible(struct mlx5e_priv *priv, struct net_device *out_dev)
 {
-       if (mlx5e_eswitch_uplink_rep(out_dev) &&
+       if (same_hw_reps(priv, out_dev) &&
            MLX5_CAP_PORT_SELECTION(priv->mdev, port_select_flow_table) &&
            MLX5_CAP_GEN(priv->mdev, create_lag_when_not_master_up))
                return true;
@@ -4529,13 +4529,6 @@ static int mlx5e_policer_validate(const struct flow_action *action,
                return -EOPNOTSUPP;
        }
 
-       if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
-           act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
-               NL_SET_ERR_MSG_MOD(extack,
-                                  "Offload not supported when conform action is not pipe or ok");
-               return -EOPNOTSUPP;
-       }
-
        if (act->police.notexceed.act_id == FLOW_ACTION_ACCEPT &&
            !flow_action_is_last_entry(action, act)) {
                NL_SET_ERR_MSG_MOD(extack,
@@ -4586,6 +4579,12 @@ static int scan_tc_matchall_fdb_actions(struct mlx5e_priv *priv,
        flow_action_for_each(i, act, flow_action) {
                switch (act->id) {
                case FLOW_ACTION_POLICE:
+                       if (act->police.notexceed.act_id != FLOW_ACTION_CONTINUE) {
+                               NL_SET_ERR_MSG_MOD(extack,
+                                                  "Offload not supported when conform action is not continue");
+                               return -EOPNOTSUPP;
+                       }
+
                        err = mlx5e_policer_validate(flow_action, act, extack);
                        if (err)
                                return err;
index 50d14ce..9a7250b 100644 (file)
@@ -341,6 +341,26 @@ static void mlx5e_tx_check_stop(struct mlx5e_txqsq *sq)
        }
 }
 
+static void mlx5e_tx_flush(struct mlx5e_txqsq *sq)
+{
+       struct mlx5e_tx_wqe_info *wi;
+       struct mlx5e_tx_wqe *wqe;
+       u16 pi;
+
+       /* Must not be called when a MPWQE session is active but empty. */
+       mlx5e_tx_mpwqe_ensure_complete(sq);
+
+       pi = mlx5_wq_cyc_ctr2ix(&sq->wq, sq->pc);
+       wi = &sq->db.wqe_info[pi];
+
+       *wi = (struct mlx5e_tx_wqe_info) {
+               .num_wqebbs = 1,
+       };
+
+       wqe = mlx5e_post_nop(&sq->wq, sq->sqn, &sq->pc);
+       mlx5e_notify_hw(&sq->wq, sq->pc, sq->uar_map, &wqe->ctrl);
+}
+
 static inline void
 mlx5e_txwqe_complete(struct mlx5e_txqsq *sq, struct sk_buff *skb,
                     const struct mlx5e_tx_attr *attr,
@@ -459,6 +479,7 @@ mlx5e_sq_xmit_wqe(struct mlx5e_txqsq *sq, struct sk_buff *skb,
 err_drop:
        stats->dropped++;
        dev_kfree_skb_any(skb);
+       mlx5e_tx_flush(sq);
 }
 
 static bool mlx5e_tx_skb_supports_mpwqe(struct sk_buff *skb, struct mlx5e_tx_attr *attr)
@@ -560,6 +581,13 @@ mlx5e_sq_xmit_mpwqe(struct mlx5e_txqsq *sq, struct sk_buff *skb,
        struct mlx5_wqe_ctrl_seg *cseg;
        struct mlx5e_xmit_data txd;
 
+       txd.data = skb->data;
+       txd.len = skb->len;
+
+       txd.dma_addr = dma_map_single(sq->pdev, txd.data, txd.len, DMA_TO_DEVICE);
+       if (unlikely(dma_mapping_error(sq->pdev, txd.dma_addr)))
+               goto err_unmap;
+
        if (!mlx5e_tx_mpwqe_session_is_active(sq)) {
                mlx5e_tx_mpwqe_session_start(sq, eseg);
        } else if (!mlx5e_tx_mpwqe_same_eseg(sq, eseg)) {
@@ -569,18 +597,9 @@ mlx5e_sq_xmit_mpwqe(struct mlx5e_txqsq *sq, struct sk_buff *skb,
 
        sq->stats->xmit_more += xmit_more;
 
-       txd.data = skb->data;
-       txd.len = skb->len;
-
-       txd.dma_addr = dma_map_single(sq->pdev, txd.data, txd.len, DMA_TO_DEVICE);
-       if (unlikely(dma_mapping_error(sq->pdev, txd.dma_addr)))
-               goto err_unmap;
        mlx5e_dma_push(sq, txd.dma_addr, txd.len, MLX5E_DMA_MAP_SINGLE);
-
        mlx5e_skb_fifo_push(&sq->db.skb_fifo, skb);
-
        mlx5e_tx_mpwqe_add_dseg(sq, &txd);
-
        mlx5e_tx_skb_update_hwts_flags(skb);
 
        if (unlikely(mlx5e_tx_mpwqe_is_full(&sq->mpwqe, sq->max_sq_mpw_wqebbs))) {
@@ -602,6 +621,7 @@ err_unmap:
        mlx5e_dma_unmap_wqe_err(sq, 1);
        sq->stats->dropped++;
        dev_kfree_skb_any(skb);
+       mlx5e_tx_flush(sq);
 }
 
 void mlx5e_tx_mpwqe_ensure_complete(struct mlx5e_txqsq *sq)
@@ -1006,5 +1026,6 @@ void mlx5i_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb,
 err_drop:
        stats->dropped++;
        dev_kfree_skb_any(skb);
+       mlx5e_tx_flush(sq);
 }
 #endif
index 9d17206..fabe49a 100644 (file)
@@ -11,6 +11,7 @@
 #include "mlx5_core.h"
 #include "eswitch.h"
 #include "fs_core.h"
+#include "fs_ft_pool.h"
 #include "esw/qos.h"
 
 enum {
@@ -95,8 +96,7 @@ static int esw_create_legacy_fdb_table(struct mlx5_eswitch *esw)
        if (!flow_group_in)
                return -ENOMEM;
 
-       table_size = BIT(MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size));
-       ft_attr.max_fte = table_size;
+       ft_attr.max_fte = POOL_NEXT_SIZE;
        ft_attr.prio = LEGACY_FDB_PRIO;
        fdb = mlx5_create_flow_table(root_ns, &ft_attr);
        if (IS_ERR(fdb)) {
@@ -105,6 +105,7 @@ static int esw_create_legacy_fdb_table(struct mlx5_eswitch *esw)
                goto out;
        }
        esw->fdb_table.legacy.fdb = fdb;
+       table_size = fdb->max_fte;
 
        /* Addresses group : Full match unicast/multicast addresses */
        MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
index 15e41dc..b8feaf0 100644 (file)
@@ -44,7 +44,7 @@ static int port_sel_mode_show(struct seq_file *file, void *priv)
        ldev = dev->priv.lag;
        mutex_lock(&ldev->lock);
        if (__mlx5_lag_is_active(ldev))
-               mode = mlx5_get_str_port_sel_mode(ldev);
+               mode = mlx5_get_str_port_sel_mode(ldev->mode, ldev->mode_flags);
        else
                ret = -EINVAL;
        mutex_unlock(&ldev->lock);
@@ -72,6 +72,7 @@ static int state_show(struct seq_file *file, void *priv)
 static int flags_show(struct seq_file *file, void *priv)
 {
        struct mlx5_core_dev *dev = file->private;
+       bool fdb_sel_mode_native;
        struct mlx5_lag *ldev;
        bool shared_fdb;
        bool lag_active;
@@ -79,14 +80,21 @@ static int flags_show(struct seq_file *file, void *priv)
        ldev = dev->priv.lag;
        mutex_lock(&ldev->lock);
        lag_active = __mlx5_lag_is_active(ldev);
-       if (lag_active)
-               shared_fdb = test_bit(MLX5_LAG_MODE_FLAG_SHARED_FDB, &ldev->mode_flags);
+       if (!lag_active)
+               goto unlock;
+
+       shared_fdb = test_bit(MLX5_LAG_MODE_FLAG_SHARED_FDB, &ldev->mode_flags);
+       fdb_sel_mode_native = test_bit(MLX5_LAG_MODE_FLAG_FDB_SEL_MODE_NATIVE,
+                                      &ldev->mode_flags);
 
+unlock:
        mutex_unlock(&ldev->lock);
        if (!lag_active)
                return -EINVAL;
 
        seq_printf(file, "%s:%s\n", "shared_fdb", shared_fdb ? "on" : "off");
+       seq_printf(file, "%s:%s\n", "fdb_selection_mode",
+                  fdb_sel_mode_native ? "native" : "affinity");
        return 0;
 }
 
index 2a8fc54..5d41e19 100644 (file)
@@ -68,14 +68,15 @@ static int get_port_sel_mode(enum mlx5_lag_mode mode, unsigned long flags)
 static int mlx5_cmd_create_lag(struct mlx5_core_dev *dev, u8 *ports, int mode,
                               unsigned long flags)
 {
-       bool shared_fdb = test_bit(MLX5_LAG_MODE_FLAG_SHARED_FDB, &flags);
+       bool fdb_sel_mode = test_bit(MLX5_LAG_MODE_FLAG_FDB_SEL_MODE_NATIVE,
+                                    &flags);
        int port_sel_mode = get_port_sel_mode(mode, flags);
        u32 in[MLX5_ST_SZ_DW(create_lag_in)] = {};
        void *lag_ctx;
 
        lag_ctx = MLX5_ADDR_OF(create_lag_in, in, ctx);
        MLX5_SET(create_lag_in, in, opcode, MLX5_CMD_OP_CREATE_LAG);
-       MLX5_SET(lagc, lag_ctx, fdb_selection_mode, shared_fdb);
+       MLX5_SET(lagc, lag_ctx, fdb_selection_mode, fdb_sel_mode);
        if (port_sel_mode == MLX5_LAG_PORT_SELECT_MODE_QUEUE_AFFINITY) {
                MLX5_SET(lagc, lag_ctx, tx_remap_affinity_1, ports[0]);
                MLX5_SET(lagc, lag_ctx, tx_remap_affinity_2, ports[1]);
@@ -471,8 +472,13 @@ static int mlx5_lag_set_flags(struct mlx5_lag *ldev, enum mlx5_lag_mode mode,
        bool roce_lag = mode == MLX5_LAG_MODE_ROCE;
 
        *flags = 0;
-       if (shared_fdb)
+       if (shared_fdb) {
                set_bit(MLX5_LAG_MODE_FLAG_SHARED_FDB, flags);
+               set_bit(MLX5_LAG_MODE_FLAG_FDB_SEL_MODE_NATIVE, flags);
+       }
+
+       if (mode == MLX5_LAG_MODE_MPESW)
+               set_bit(MLX5_LAG_MODE_FLAG_FDB_SEL_MODE_NATIVE, flags);
 
        if (roce_lag)
                return mlx5_lag_set_port_sel_mode_roce(ldev, flags);
@@ -481,9 +487,9 @@ static int mlx5_lag_set_flags(struct mlx5_lag *ldev, enum mlx5_lag_mode mode,
        return 0;
 }
 
-char *mlx5_get_str_port_sel_mode(struct mlx5_lag *ldev)
+char *mlx5_get_str_port_sel_mode(enum mlx5_lag_mode mode, unsigned long flags)
 {
-       int port_sel_mode = get_port_sel_mode(ldev->mode, ldev->mode_flags);
+       int port_sel_mode = get_port_sel_mode(mode, flags);
 
        switch (port_sel_mode) {
        case MLX5_LAG_PORT_SELECT_MODE_QUEUE_AFFINITY: return "queue_affinity";
@@ -507,7 +513,7 @@ static int mlx5_create_lag(struct mlx5_lag *ldev,
        if (tracker)
                mlx5_lag_print_mapping(dev0, ldev, tracker, flags);
        mlx5_core_info(dev0, "shared_fdb:%d mode:%s\n",
-                      shared_fdb, mlx5_get_str_port_sel_mode(ldev));
+                      shared_fdb, mlx5_get_str_port_sel_mode(mode, flags));
 
        err = mlx5_cmd_create_lag(dev0, ldev->v2p_map, mode, flags);
        if (err) {
index c81b173..ce2ce8c 100644 (file)
@@ -24,6 +24,7 @@ enum {
 enum {
        MLX5_LAG_MODE_FLAG_HASH_BASED,
        MLX5_LAG_MODE_FLAG_SHARED_FDB,
+       MLX5_LAG_MODE_FLAG_FDB_SEL_MODE_NATIVE,
 };
 
 enum mlx5_lag_mode {
@@ -114,7 +115,7 @@ bool mlx5_shared_fdb_supported(struct mlx5_lag *ldev);
 void mlx5_lag_del_mpesw_rule(struct mlx5_core_dev *dev);
 int mlx5_lag_add_mpesw_rule(struct mlx5_core_dev *dev);
 
-char *mlx5_get_str_port_sel_mode(struct mlx5_lag *ldev);
+char *mlx5_get_str_port_sel_mode(enum mlx5_lag_mode mode, unsigned long flags);
 void mlx5_infer_tx_enabled(struct lag_tracker *tracker, u8 num_ports,
                           u8 *ports, int *num_enabled);
 
index ee4b25a..f643202 100644 (file)
@@ -41,7 +41,6 @@ void mlx5_lag_del_mpesw_rule(struct mlx5_core_dev *dev)
 int mlx5_lag_add_mpesw_rule(struct mlx5_core_dev *dev)
 {
        struct mlx5_lag *ldev = dev->priv.lag;
-       bool shared_fdb;
        int err = 0;
 
        if (!ldev)
@@ -55,8 +54,8 @@ int mlx5_lag_add_mpesw_rule(struct mlx5_core_dev *dev)
                err = -EINVAL;
                goto out;
        }
-       shared_fdb = mlx5_shared_fdb_supported(ldev);
-       err = mlx5_activate_lag(ldev, NULL, MLX5_LAG_MODE_MPESW, shared_fdb);
+
+       err = mlx5_activate_lag(ldev, NULL, MLX5_LAG_MODE_MPESW, false);
        if (err)
                mlx5_core_warn(dev, "Failed to create LAG in MPESW mode (%d)\n", err);
 
index 9dbb573..ce33dbd 100644 (file)
@@ -4415,6 +4415,8 @@ static int mlxsw_sp_nexthop4_init(struct mlxsw_sp *mlxsw_sp,
        return 0;
 
 err_nexthop_neigh_init:
+       list_del(&nh->router_list_node);
+       mlxsw_sp_nexthop_counter_free(mlxsw_sp, nh);
        mlxsw_sp_nexthop_remove(mlxsw_sp, nh);
        return err;
 }
@@ -5382,7 +5384,7 @@ static bool mlxsw_sp_fi_is_gateway(const struct mlxsw_sp *mlxsw_sp,
 {
        const struct fib_nh *nh = fib_info_nh(fi, 0);
 
-       return nh->fib_nh_scope == RT_SCOPE_LINK ||
+       return nh->fib_nh_gw_family ||
               mlxsw_sp_nexthop4_ipip_type(mlxsw_sp, nh, NULL);
 }
 
@@ -6740,6 +6742,7 @@ static int mlxsw_sp_nexthop6_init(struct mlxsw_sp *mlxsw_sp,
                                  const struct fib6_info *rt)
 {
        struct net_device *dev = rt->fib6_nh->fib_nh_dev;
+       int err;
 
        nh->nhgi = nh_grp->nhgi;
        nh->nh_weight = rt->fib6_nh->fib_nh_weight;
@@ -6755,7 +6758,16 @@ static int mlxsw_sp_nexthop6_init(struct mlxsw_sp *mlxsw_sp,
                return 0;
        nh->ifindex = dev->ifindex;
 
-       return mlxsw_sp_nexthop_type_init(mlxsw_sp, nh, dev);
+       err = mlxsw_sp_nexthop_type_init(mlxsw_sp, nh, dev);
+       if (err)
+               goto err_nexthop_type_init;
+
+       return 0;
+
+err_nexthop_type_init:
+       list_del(&nh->router_list_node);
+       mlxsw_sp_nexthop_counter_free(mlxsw_sp, nh);
+       return err;
 }
 
 static void mlxsw_sp_nexthop6_fini(struct mlxsw_sp *mlxsw_sp,
@@ -10312,7 +10324,7 @@ static void mlxsw_sp_mp4_hash_init(struct mlxsw_sp *mlxsw_sp,
        unsigned long *fields = config->fields;
        u32 hash_fields;
 
-       switch (net->ipv4.sysctl_fib_multipath_hash_policy) {
+       switch (READ_ONCE(net->ipv4.sysctl_fib_multipath_hash_policy)) {
        case 0:
                mlxsw_sp_mp4_hash_outer_addr(config);
                break;
@@ -10330,7 +10342,7 @@ static void mlxsw_sp_mp4_hash_init(struct mlxsw_sp *mlxsw_sp,
                mlxsw_sp_mp_hash_inner_l3(config);
                break;
        case 3:
-               hash_fields = net->ipv4.sysctl_fib_multipath_hash_fields;
+               hash_fields = READ_ONCE(net->ipv4.sysctl_fib_multipath_hash_fields);
                /* Outer */
                MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV4_EN_NOT_TCP_NOT_UDP);
                MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV4_EN_TCP_UDP);
@@ -10511,13 +10523,14 @@ static int mlxsw_sp_dscp_init(struct mlxsw_sp *mlxsw_sp)
 static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
 {
        struct net *net = mlxsw_sp_net(mlxsw_sp);
-       bool usp = net->ipv4.sysctl_ip_fwd_update_priority;
        char rgcr_pl[MLXSW_REG_RGCR_LEN];
        u64 max_rifs;
+       bool usp;
 
        if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_RIFS))
                return -EIO;
        max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
+       usp = READ_ONCE(net->ipv4.sysctl_ip_fwd_update_priority);
 
        mlxsw_reg_rgcr_pack(rgcr_pl, true, true);
        mlxsw_reg_rgcr_max_router_interfaces_set(rgcr_pl, max_rifs);
index 005e56e..5893770 100644 (file)
@@ -75,6 +75,9 @@ static int __lan966x_mac_learn(struct lan966x *lan966x, int pgid,
                               unsigned int vid,
                               enum macaccess_entry_type type)
 {
+       int ret;
+
+       spin_lock(&lan966x->mac_lock);
        lan966x_mac_select(lan966x, mac, vid);
 
        /* Issue a write command */
@@ -86,7 +89,10 @@ static int __lan966x_mac_learn(struct lan966x *lan966x, int pgid,
               ANA_MACACCESS_MAC_TABLE_CMD_SET(MACACCESS_CMD_LEARN),
               lan966x, ANA_MACACCESS);
 
-       return lan966x_mac_wait_for_completion(lan966x);
+       ret = lan966x_mac_wait_for_completion(lan966x);
+       spin_unlock(&lan966x->mac_lock);
+
+       return ret;
 }
 
 /* The mask of the front ports is encoded inside the mac parameter via a call
@@ -113,11 +119,13 @@ int lan966x_mac_learn(struct lan966x *lan966x, int port,
        return __lan966x_mac_learn(lan966x, port, false, mac, vid, type);
 }
 
-int lan966x_mac_forget(struct lan966x *lan966x,
-                      const unsigned char mac[ETH_ALEN],
-                      unsigned int vid,
-                      enum macaccess_entry_type type)
+static int lan966x_mac_forget_locked(struct lan966x *lan966x,
+                                    const unsigned char mac[ETH_ALEN],
+                                    unsigned int vid,
+                                    enum macaccess_entry_type type)
 {
+       lockdep_assert_held(&lan966x->mac_lock);
+
        lan966x_mac_select(lan966x, mac, vid);
 
        /* Issue a forget command */
@@ -128,6 +136,20 @@ int lan966x_mac_forget(struct lan966x *lan966x,
        return lan966x_mac_wait_for_completion(lan966x);
 }
 
+int lan966x_mac_forget(struct lan966x *lan966x,
+                      const unsigned char mac[ETH_ALEN],
+                      unsigned int vid,
+                      enum macaccess_entry_type type)
+{
+       int ret;
+
+       spin_lock(&lan966x->mac_lock);
+       ret = lan966x_mac_forget_locked(lan966x, mac, vid, type);
+       spin_unlock(&lan966x->mac_lock);
+
+       return ret;
+}
+
 int lan966x_mac_cpu_learn(struct lan966x *lan966x, const char *addr, u16 vid)
 {
        return lan966x_mac_learn(lan966x, PGID_CPU, addr, vid, ENTRYTYPE_LOCKED);
@@ -161,7 +183,7 @@ static struct lan966x_mac_entry *lan966x_mac_alloc_entry(const unsigned char *ma
 {
        struct lan966x_mac_entry *mac_entry;
 
-       mac_entry = kzalloc(sizeof(*mac_entry), GFP_KERNEL);
+       mac_entry = kzalloc(sizeof(*mac_entry), GFP_ATOMIC);
        if (!mac_entry)
                return NULL;
 
@@ -179,7 +201,6 @@ static struct lan966x_mac_entry *lan966x_mac_find_entry(struct lan966x *lan966x,
        struct lan966x_mac_entry *res = NULL;
        struct lan966x_mac_entry *mac_entry;
 
-       spin_lock(&lan966x->mac_lock);
        list_for_each_entry(mac_entry, &lan966x->mac_entries, list) {
                if (mac_entry->vid == vid &&
                    ether_addr_equal(mac, mac_entry->mac) &&
@@ -188,7 +209,6 @@ static struct lan966x_mac_entry *lan966x_mac_find_entry(struct lan966x *lan966x,
                        break;
                }
        }
-       spin_unlock(&lan966x->mac_lock);
 
        return res;
 }
@@ -231,8 +251,11 @@ int lan966x_mac_add_entry(struct lan966x *lan966x, struct lan966x_port *port,
 {
        struct lan966x_mac_entry *mac_entry;
 
-       if (lan966x_mac_lookup(lan966x, addr, vid, ENTRYTYPE_NORMAL))
+       spin_lock(&lan966x->mac_lock);
+       if (lan966x_mac_lookup(lan966x, addr, vid, ENTRYTYPE_NORMAL)) {
+               spin_unlock(&lan966x->mac_lock);
                return 0;
+       }
 
        /* In case the entry already exists, don't add it again to SW,
         * just update HW, but we need to look in the actual HW because
@@ -241,21 +264,25 @@ int lan966x_mac_add_entry(struct lan966x *lan966x, struct lan966x_port *port,
         * add the entry but without the extern_learn flag.
         */
        mac_entry = lan966x_mac_find_entry(lan966x, addr, vid, port->chip_port);
-       if (mac_entry)
-               return lan966x_mac_learn(lan966x, port->chip_port,
-                                        addr, vid, ENTRYTYPE_LOCKED);
+       if (mac_entry) {
+               spin_unlock(&lan966x->mac_lock);
+               goto mac_learn;
+       }
 
        mac_entry = lan966x_mac_alloc_entry(addr, vid, port->chip_port);
-       if (!mac_entry)
+       if (!mac_entry) {
+               spin_unlock(&lan966x->mac_lock);
                return -ENOMEM;
+       }
 
-       spin_lock(&lan966x->mac_lock);
        list_add_tail(&mac_entry->list, &lan966x->mac_entries);
        spin_unlock(&lan966x->mac_lock);
 
-       lan966x_mac_learn(lan966x, port->chip_port, addr, vid, ENTRYTYPE_LOCKED);
        lan966x_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED, addr, vid, port->dev);
 
+mac_learn:
+       lan966x_mac_learn(lan966x, port->chip_port, addr, vid, ENTRYTYPE_LOCKED);
+
        return 0;
 }
 
@@ -269,8 +296,9 @@ int lan966x_mac_del_entry(struct lan966x *lan966x, const unsigned char *addr,
                                 list) {
                if (mac_entry->vid == vid &&
                    ether_addr_equal(addr, mac_entry->mac)) {
-                       lan966x_mac_forget(lan966x, mac_entry->mac, mac_entry->vid,
-                                          ENTRYTYPE_LOCKED);
+                       lan966x_mac_forget_locked(lan966x, mac_entry->mac,
+                                                 mac_entry->vid,
+                                                 ENTRYTYPE_LOCKED);
 
                        list_del(&mac_entry->list);
                        kfree(mac_entry);
@@ -288,8 +316,8 @@ void lan966x_mac_purge_entries(struct lan966x *lan966x)
        spin_lock(&lan966x->mac_lock);
        list_for_each_entry_safe(mac_entry, tmp, &lan966x->mac_entries,
                                 list) {
-               lan966x_mac_forget(lan966x, mac_entry->mac, mac_entry->vid,
-                                  ENTRYTYPE_LOCKED);
+               lan966x_mac_forget_locked(lan966x, mac_entry->mac,
+                                         mac_entry->vid, ENTRYTYPE_LOCKED);
 
                list_del(&mac_entry->list);
                kfree(mac_entry);
@@ -325,10 +353,13 @@ static void lan966x_mac_irq_process(struct lan966x *lan966x, u32 row,
 {
        struct lan966x_mac_entry *mac_entry, *tmp;
        unsigned char mac[ETH_ALEN] __aligned(2);
+       struct list_head mac_deleted_entries;
        u32 dest_idx;
        u32 column;
        u16 vid;
 
+       INIT_LIST_HEAD(&mac_deleted_entries);
+
        spin_lock(&lan966x->mac_lock);
        list_for_each_entry_safe(mac_entry, tmp, &lan966x->mac_entries, list) {
                bool found = false;
@@ -362,20 +393,26 @@ static void lan966x_mac_irq_process(struct lan966x *lan966x, u32 row,
                }
 
                if (!found) {
-                       /* Notify the bridge that the entry doesn't exist
-                        * anymore in the HW and remove the entry from the SW
-                        * list
-                        */
-                       lan966x_mac_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE,
-                                             mac_entry->mac, mac_entry->vid,
-                                             lan966x->ports[mac_entry->port_index]->dev);
-
                        list_del(&mac_entry->list);
-                       kfree(mac_entry);
+                       /* Move the entry from SW list to a tmp list such that
+                        * it would be deleted later
+                        */
+                       list_add_tail(&mac_entry->list, &mac_deleted_entries);
                }
        }
        spin_unlock(&lan966x->mac_lock);
 
+       list_for_each_entry_safe(mac_entry, tmp, &mac_deleted_entries, list) {
+               /* Notify the bridge that the entry doesn't exist
+                * anymore in the HW
+                */
+               lan966x_mac_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE,
+                                     mac_entry->mac, mac_entry->vid,
+                                     lan966x->ports[mac_entry->port_index]->dev);
+               list_del(&mac_entry->list);
+               kfree(mac_entry);
+       }
+
        /* Now go to the list of columns and see if any entry was not in the SW
         * list, then that means that the entry is new so it needs to notify the
         * bridge.
@@ -396,13 +433,20 @@ static void lan966x_mac_irq_process(struct lan966x *lan966x, u32 row,
                if (WARN_ON(dest_idx >= lan966x->num_phys_ports))
                        continue;
 
+               spin_lock(&lan966x->mac_lock);
+               mac_entry = lan966x_mac_find_entry(lan966x, mac, vid, dest_idx);
+               if (mac_entry) {
+                       spin_unlock(&lan966x->mac_lock);
+                       continue;
+               }
+
                mac_entry = lan966x_mac_alloc_entry(mac, vid, dest_idx);
-               if (!mac_entry)
+               if (!mac_entry) {
+                       spin_unlock(&lan966x->mac_lock);
                        return;
+               }
 
                mac_entry->row = row;
-
-               spin_lock(&lan966x->mac_lock);
                list_add_tail(&mac_entry->list, &lan966x->mac_entries);
                spin_unlock(&lan966x->mac_lock);
 
@@ -424,6 +468,7 @@ irqreturn_t lan966x_mac_irq_handler(struct lan966x *lan966x)
               lan966x, ANA_MACTINDX);
 
        while (1) {
+               spin_lock(&lan966x->mac_lock);
                lan_rmw(ANA_MACACCESS_MAC_TABLE_CMD_SET(MACACCESS_CMD_SYNC_GET_NEXT),
                        ANA_MACACCESS_MAC_TABLE_CMD,
                        lan966x, ANA_MACACCESS);
@@ -447,12 +492,15 @@ irqreturn_t lan966x_mac_irq_handler(struct lan966x *lan966x)
                        stop = false;
 
                if (column == LAN966X_MAC_COLUMNS - 1 &&
-                   index == 0 && stop)
+                   index == 0 && stop) {
+                       spin_unlock(&lan966x->mac_lock);
                        break;
+               }
 
                entry[column].mach = lan_rd(lan966x, ANA_MACHDATA);
                entry[column].macl = lan_rd(lan966x, ANA_MACLDATA);
                entry[column].maca = lan_rd(lan966x, ANA_MACACCESS);
+               spin_unlock(&lan966x->mac_lock);
 
                /* Once all the columns are read process them */
                if (column == LAN966X_MAC_COLUMNS - 1) {
index 5784c41..1d6e3b6 100644 (file)
@@ -994,7 +994,7 @@ static int lan966x_probe(struct platform_device *pdev)
        struct fwnode_handle *ports, *portnp;
        struct lan966x *lan966x;
        u8 mac_addr[ETH_ALEN];
-       int err, i;
+       int err;
 
        lan966x = devm_kzalloc(&pdev->dev, sizeof(*lan966x), GFP_KERNEL);
        if (!lan966x)
@@ -1025,11 +1025,7 @@ static int lan966x_probe(struct platform_device *pdev)
        if (err)
                return dev_err_probe(&pdev->dev, err, "Reset failed");
 
-       i = 0;
-       fwnode_for_each_available_child_node(ports, portnp)
-               ++i;
-
-       lan966x->num_phys_ports = i;
+       lan966x->num_phys_ports = NUM_PHYS_PORTS;
        lan966x->ports = devm_kcalloc(&pdev->dev, lan966x->num_phys_ports,
                                      sizeof(struct lan966x_port *),
                                      GFP_KERNEL);
index 3b86ddd..2787055 100644 (file)
@@ -34,6 +34,7 @@
 /* Reserved amount for (SRC, PRIO) at index 8*SRC + PRIO */
 #define QSYS_Q_RSRV                    95
 
+#define NUM_PHYS_PORTS                 8
 #define CPU_PORT                       8
 
 /* Reserved PGIDs */
index 3429660..5edc8b7 100644 (file)
@@ -396,6 +396,9 @@ static int sparx5_handle_port_mdb_add(struct net_device *dev,
        u32 mact_entry;
        int res, err;
 
+       if (!sparx5_netdevice_check(dev))
+               return -EOPNOTSUPP;
+
        if (netif_is_bridge_master(v->obj.orig_dev)) {
                sparx5_mact_learn(spx5, PGID_CPU, v->addr, v->vid);
                return 0;
@@ -466,6 +469,9 @@ static int sparx5_handle_port_mdb_del(struct net_device *dev,
        u32 mact_entry, res, pgid_entry[3];
        int err;
 
+       if (!sparx5_netdevice_check(dev))
+               return -EOPNOTSUPP;
+
        if (netif_is_bridge_master(v->obj.orig_dev)) {
                sparx5_mact_forget(spx5, v->addr, v->vid);
                return 0;
index 083fddd..8e3894c 100644 (file)
@@ -94,19 +94,18 @@ static void ocelot_fdma_activate_chan(struct ocelot *ocelot, dma_addr_t dma,
        ocelot_fdma_writel(ocelot, MSCC_FDMA_CH_ACTIVATE, BIT(chan));
 }
 
+static u32 ocelot_fdma_read_ch_safe(struct ocelot *ocelot)
+{
+       return ocelot_fdma_readl(ocelot, MSCC_FDMA_CH_SAFE);
+}
+
 static int ocelot_fdma_wait_chan_safe(struct ocelot *ocelot, int chan)
 {
-       unsigned long timeout;
        u32 safe;
 
-       timeout = jiffies + usecs_to_jiffies(OCELOT_FDMA_CH_SAFE_TIMEOUT_US);
-       do {
-               safe = ocelot_fdma_readl(ocelot, MSCC_FDMA_CH_SAFE);
-               if (safe & BIT(chan))
-                       return 0;
-       } while (time_after(jiffies, timeout));
-
-       return -ETIMEDOUT;
+       return readx_poll_timeout_atomic(ocelot_fdma_read_ch_safe, ocelot, safe,
+                                        safe & BIT(chan), 0,
+                                        OCELOT_FDMA_CH_SAFE_TIMEOUT_US);
 }
 
 static void ocelot_fdma_dcb_set_data(struct ocelot_fdma_dcb *dcb,
index e31f8fb..df2ab5c 100644 (file)
@@ -4233,7 +4233,7 @@ static void nfp_bpf_opt_ldst_gather(struct nfp_prog *nfp_prog)
                        }
 
                        /* If the chain is ended by an load/store pair then this
-                        * could serve as the new head of the the next chain.
+                        * could serve as the new head of the next chain.
                         */
                        if (curr_pair_is_memcpy(meta1, meta2)) {
                                head_ld_meta = meta1;
index 0147de4..ffb6f6d 100644 (file)
@@ -474,7 +474,7 @@ nfp_fl_set_tun(struct nfp_app *app, struct nfp_fl_set_tun *set_tun,
                        set_tun->ttl = ip4_dst_hoplimit(&rt->dst);
                        ip_rt_put(rt);
                } else {
-                       set_tun->ttl = net->ipv4.sysctl_ip_default_ttl;
+                       set_tun->ttl = READ_ONCE(net->ipv4.sysctl_ip_default_ttl);
                }
        }
 
index 6bf3ec4..97dcf8d 100644 (file)
@@ -447,7 +447,8 @@ void nfp_tun_unlink_and_update_nn_entries(struct nfp_app *app,
 
 static void
 nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app,
-                   void *flow, struct neighbour *neigh, bool is_ipv6)
+                   void *flow, struct neighbour *neigh, bool is_ipv6,
+                   bool override)
 {
        bool neigh_invalid = !(neigh->nud_state & NUD_VALID) || neigh->dead;
        size_t neigh_size = is_ipv6 ? sizeof(struct nfp_tun_neigh_v6) :
@@ -546,6 +547,13 @@ nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app,
                if (nn_entry->flow)
                        list_del(&nn_entry->list_head);
                kfree(nn_entry);
+       } else if (nn_entry && !neigh_invalid && override) {
+               mtype = is_ipv6 ? NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6 :
+                               NFP_FLOWER_CMSG_TYPE_TUN_NEIGH;
+               nfp_tun_link_predt_entries(app, nn_entry);
+               nfp_flower_xmit_tun_conf(app, mtype, neigh_size,
+                                        nn_entry->payload,
+                                        GFP_ATOMIC);
        }
 
        spin_unlock_bh(&priv->predt_lock);
@@ -610,7 +618,7 @@ nfp_tun_neigh_event_handler(struct notifier_block *nb, unsigned long event,
 
                        dst_release(dst);
                }
-               nfp_tun_write_neigh(n->dev, app, &flow6, n, true);
+               nfp_tun_write_neigh(n->dev, app, &flow6, n, true, false);
 #else
                return NOTIFY_DONE;
 #endif /* CONFIG_IPV6 */
@@ -633,7 +641,7 @@ nfp_tun_neigh_event_handler(struct notifier_block *nb, unsigned long event,
 
                        ip_rt_put(rt);
                }
-               nfp_tun_write_neigh(n->dev, app, &flow4, n, false);
+               nfp_tun_write_neigh(n->dev, app, &flow4, n, false, false);
        }
 #else
        return NOTIFY_DONE;
@@ -676,7 +684,7 @@ void nfp_tunnel_request_route_v4(struct nfp_app *app, struct sk_buff *skb)
        ip_rt_put(rt);
        if (!n)
                goto fail_rcu_unlock;
-       nfp_tun_write_neigh(n->dev, app, &flow, n, false);
+       nfp_tun_write_neigh(n->dev, app, &flow, n, false, true);
        neigh_release(n);
        rcu_read_unlock();
        return;
@@ -718,7 +726,7 @@ void nfp_tunnel_request_route_v6(struct nfp_app *app, struct sk_buff *skb)
        if (!n)
                goto fail_rcu_unlock;
 
-       nfp_tun_write_neigh(n->dev, app, &flow, n, true);
+       nfp_tun_write_neigh(n->dev, app, &flow, n, true, true);
        neigh_release(n);
        rcu_read_unlock();
        return;
index e509d6d..805071d 100644 (file)
@@ -125,17 +125,18 @@ nfp_nfdk_tx_csum(struct nfp_net_dp *dp, struct nfp_net_r_vector *r_vec,
 
 static int
 nfp_nfdk_tx_maybe_close_block(struct nfp_net_tx_ring *tx_ring,
-                             unsigned int nr_frags, struct sk_buff *skb)
+                             struct sk_buff *skb)
 {
        unsigned int n_descs, wr_p, nop_slots;
        const skb_frag_t *frag, *fend;
        struct nfp_nfdk_tx_desc *txd;
+       unsigned int nr_frags;
        unsigned int wr_idx;
        int err;
 
 recount_descs:
        n_descs = nfp_nfdk_headlen_to_segs(skb_headlen(skb));
-
+       nr_frags = skb_shinfo(skb)->nr_frags;
        frag = skb_shinfo(skb)->frags;
        fend = frag + nr_frags;
        for (; frag < fend; frag++)
@@ -281,10 +282,13 @@ netdev_tx_t nfp_nfdk_tx(struct sk_buff *skb, struct net_device *netdev)
        if (unlikely((int)metadata < 0))
                goto err_flush;
 
-       nr_frags = skb_shinfo(skb)->nr_frags;
-       if (nfp_nfdk_tx_maybe_close_block(tx_ring, nr_frags, skb))
+       if (nfp_nfdk_tx_maybe_close_block(tx_ring, skb))
                goto err_flush;
 
+       /* nr_frags will change after skb_linearize so we get nr_frags after
+        * nfp_nfdk_tx_maybe_close_block function
+        */
+       nr_frags = skb_shinfo(skb)->nr_frags;
        /* DMA map all */
        wr_idx = D_IDX(tx_ring, tx_ring->wr_p);
        txd = &tx_ring->ktxds[wr_idx];
@@ -310,7 +314,16 @@ netdev_tx_t nfp_nfdk_tx(struct sk_buff *skb, struct net_device *netdev)
 
        /* FIELD_PREP() implicitly truncates to chunk */
        dma_len -= 1;
-       dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN_HEAD, dma_len) |
+
+       /* We will do our best to pass as much data as we can in descriptor
+        * and we need to make sure the first descriptor includes whole head
+        * since there is limitation in firmware side. Sometimes the value of
+        * dma_len bitwise and NFDK_DESC_TX_DMA_LEN_HEAD will less than
+        * headlen.
+        */
+       dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN_HEAD,
+                              dma_len > NFDK_DESC_TX_DMA_LEN_HEAD ?
+                              NFDK_DESC_TX_DMA_LEN_HEAD : dma_len) |
                    FIELD_PREP(NFDK_DESC_TX_TYPE_HEAD, type);
 
        txd->dma_len_type = cpu_to_le16(dlen_type);
@@ -925,7 +938,9 @@ nfp_nfdk_tx_xdp_buf(struct nfp_net_dp *dp, struct nfp_net_rx_ring *rx_ring,
 
        /* FIELD_PREP() implicitly truncates to chunk */
        dma_len -= 1;
-       dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN_HEAD, dma_len) |
+       dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN_HEAD,
+                              dma_len > NFDK_DESC_TX_DMA_LEN_HEAD ?
+                              NFDK_DESC_TX_DMA_LEN_HEAD : dma_len) |
                    FIELD_PREP(NFDK_DESC_TX_TYPE_HEAD, type);
 
        txd->dma_len_type = cpu_to_le16(dlen_type);
@@ -1303,7 +1318,7 @@ nfp_nfdk_ctrl_tx_one(struct nfp_net *nn, struct nfp_net_r_vector *r_vec,
                                   skb_push(skb, 4));
        }
 
-       if (nfp_nfdk_tx_maybe_close_block(tx_ring, 0, skb))
+       if (nfp_nfdk_tx_maybe_close_block(tx_ring, skb))
                goto err_free;
 
        /* DMA map all */
@@ -1328,7 +1343,9 @@ nfp_nfdk_ctrl_tx_one(struct nfp_net *nn, struct nfp_net_r_vector *r_vec,
        txbuf++;
 
        dma_len -= 1;
-       dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN_HEAD, dma_len) |
+       dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN_HEAD,
+                              dma_len > NFDK_DESC_TX_DMA_LEN_HEAD ?
+                              NFDK_DESC_TX_DMA_LEN_HEAD : dma_len) |
                    FIELD_PREP(NFDK_DESC_TX_TYPE_HEAD, type);
 
        txd->dma_len_type = cpu_to_le16(dlen_type);
index 3098d66..1b7fdb4 100644 (file)
@@ -4190,7 +4190,6 @@ static void rtl8169_tso_csum_v1(struct sk_buff *skb, u32 *opts)
 static bool rtl8169_tso_csum_v2(struct rtl8169_private *tp,
                                struct sk_buff *skb, u32 *opts)
 {
-       u32 transport_offset = (u32)skb_transport_offset(skb);
        struct skb_shared_info *shinfo = skb_shinfo(skb);
        u32 mss = shinfo->gso_size;
 
@@ -4207,7 +4206,7 @@ static bool rtl8169_tso_csum_v2(struct rtl8169_private *tp,
                        WARN_ON_ONCE(1);
                }
 
-               opts[0] |= transport_offset << GTTCPHO_SHIFT;
+               opts[0] |= skb_transport_offset(skb) << GTTCPHO_SHIFT;
                opts[1] |= mss << TD1_MSS_SHIFT;
        } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
                u8 ip_protocol;
@@ -4235,7 +4234,7 @@ static bool rtl8169_tso_csum_v2(struct rtl8169_private *tp,
                else
                        WARN_ON_ONCE(1);
 
-               opts[1] |= transport_offset << TCPHO_SHIFT;
+               opts[1] |= skb_transport_offset(skb) << TCPHO_SHIFT;
        } else {
                unsigned int padto = rtl_quirk_packet_padto(tp, skb);
 
@@ -4402,14 +4401,13 @@ static netdev_features_t rtl8169_features_check(struct sk_buff *skb,
                                                struct net_device *dev,
                                                netdev_features_t features)
 {
-       int transport_offset = skb_transport_offset(skb);
        struct rtl8169_private *tp = netdev_priv(dev);
 
        if (skb_is_gso(skb)) {
                if (tp->mac_version == RTL_GIGA_MAC_VER_34)
                        features = rtl8168evl_fix_tso(skb, features);
 
-               if (transport_offset > GTTCPHO_MAX &&
+               if (skb_transport_offset(skb) > GTTCPHO_MAX &&
                    rtl_chip_supports_csum_v2(tp))
                        features &= ~NETIF_F_ALL_TSO;
        } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
@@ -4420,7 +4418,7 @@ static netdev_features_t rtl8169_features_check(struct sk_buff *skb,
                if (rtl_quirk_packet_padto(tp, skb))
                        features &= ~NETIF_F_CSUM_MASK;
 
-               if (transport_offset > TCPHO_MAX &&
+               if (skb_transport_offset(skb) > TCPHO_MAX &&
                    rtl_chip_supports_csum_v2(tp))
                        features &= ~NETIF_F_CSUM_MASK;
        }
index 186cb28..8b62ce2 100644 (file)
@@ -1932,7 +1932,10 @@ static int efx_ef10_try_update_nic_stats_vf(struct efx_nic *efx)
 
        efx_update_sw_stats(efx, stats);
 out:
+       /* releasing a DMA coherent buffer with BH disabled can panic */
+       spin_unlock_bh(&efx->stats_lock);
        efx_nic_free_buffer(efx, &stats_buf);
+       spin_lock_bh(&efx->stats_lock);
        return rc;
 }
 
index 7f5aa4a..92550c7 100644 (file)
@@ -408,8 +408,9 @@ fail1:
 static int efx_ef10_pci_sriov_disable(struct efx_nic *efx, bool force)
 {
        struct pci_dev *dev = efx->pci_dev;
+       struct efx_ef10_nic_data *nic_data = efx->nic_data;
        unsigned int vfs_assigned = pci_vfs_assigned(dev);
-       int rc = 0;
+       int i, rc = 0;
 
        if (vfs_assigned && !force) {
                netif_info(efx, drv, efx->net_dev, "VFs are assigned to guests; "
@@ -417,10 +418,13 @@ static int efx_ef10_pci_sriov_disable(struct efx_nic *efx, bool force)
                return -EBUSY;
        }
 
-       if (!vfs_assigned)
+       if (!vfs_assigned) {
+               for (i = 0; i < efx->vf_count; i++)
+                       nic_data->vf[i].pci_dev = NULL;
                pci_disable_sriov(dev);
-       else
+       } else {
                rc = -EBUSY;
+       }
 
        efx_ef10_sriov_free_vf_vswitching(efx);
        efx->vf_count = 0;
index 4625f85..10ad0b9 100644 (file)
@@ -1100,7 +1100,29 @@ static void efx_ptp_xmit_skb_queue(struct efx_nic *efx, struct sk_buff *skb)
 
        tx_queue = efx_channel_get_tx_queue(ptp_data->channel, type);
        if (tx_queue && tx_queue->timestamping) {
+               /* This code invokes normal driver TX code which is always
+                * protected from softirqs when called from generic TX code,
+                * which in turn disables preemption. Look at __dev_queue_xmit
+                * which uses rcu_read_lock_bh disabling preemption for RCU
+                * plus disabling softirqs. We do not need RCU reader
+                * protection here.
+                *
+                * Although it is theoretically safe for current PTP TX/RX code
+                * running without disabling softirqs, there are three good
+                * reasond for doing so:
+                *
+                *      1) The code invoked is mainly implemented for non-PTP
+                *         packets and it is always executed with softirqs
+                *         disabled.
+                *      2) This being a single PTP packet, better to not
+                *         interrupt its processing by softirqs which can lead
+                *         to high latencies.
+                *      3) netdev_xmit_more checks preemption is disabled and
+                *         triggers a BUG_ON if not.
+                */
+               local_bh_disable();
                efx_enqueue_skb(tx_queue, skb);
+               local_bh_enable();
        } else {
                WARN_ONCE(1, "PTP channel has no timestamped tx queue\n");
                dev_kfree_skb_any(skb);
index a0654e8..0329caf 100644 (file)
@@ -1515,14 +1515,14 @@ static void epic_remove_one(struct pci_dev *pdev)
        struct net_device *dev = pci_get_drvdata(pdev);
        struct epic_private *ep = netdev_priv(dev);
 
+       unregister_netdev(dev);
        dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, ep->tx_ring,
                          ep->tx_ring_dma);
        dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, ep->rx_ring,
                          ep->rx_ring_dma);
-       unregister_netdev(dev);
        pci_iounmap(pdev, ep->ioaddr);
-       pci_release_regions(pdev);
        free_netdev(dev);
+       pci_release_regions(pdev);
        pci_disable_device(pdev);
        /* pci_power_off(pdev, -1); */
 }
index bc91fd8..358fc26 100644 (file)
@@ -361,6 +361,7 @@ bypass_clk_reset_gpio:
        data->fix_mac_speed = tegra_eqos_fix_speed;
        data->init = tegra_eqos_init;
        data->bsp_priv = eqos;
+       data->sph_disable = 1;
 
        err = tegra_eqos_init(pdev, eqos);
        if (err < 0)
index 9a6d819..378b4dd 100644 (file)
@@ -273,7 +273,8 @@ static int ingenic_mac_probe(struct platform_device *pdev)
                        mac->tx_delay = tx_delay_ps * 1000;
                } else {
                        dev_err(&pdev->dev, "Invalid TX clock delay: %dps\n", tx_delay_ps);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto err_remove_config_dt;
                }
        }
 
@@ -283,7 +284,8 @@ static int ingenic_mac_probe(struct platform_device *pdev)
                        mac->rx_delay = rx_delay_ps * 1000;
                } else {
                        dev_err(&pdev->dev, "Invalid RX clock delay: %dps\n", rx_delay_ps);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto err_remove_config_dt;
                }
        }
 
index 38fe77d..3fe720c 100644 (file)
@@ -298,6 +298,11 @@ static void get_arttime(struct mii_bus *mii, int intel_adhoc_addr,
        *art_time = ns;
 }
 
+static int stmmac_cross_ts_isr(struct stmmac_priv *priv)
+{
+       return (readl(priv->ioaddr + GMAC_INT_STATUS) & GMAC_INT_TSIE);
+}
+
 static int intel_crosststamp(ktime_t *device,
                             struct system_counterval_t *system,
                             void *ctx)
@@ -313,8 +318,6 @@ static int intel_crosststamp(ktime_t *device,
        u32 num_snapshot;
        u32 gpio_value;
        u32 acr_value;
-       int ret;
-       u32 v;
        int i;
 
        if (!boot_cpu_has(X86_FEATURE_ART))
@@ -328,6 +331,8 @@ static int intel_crosststamp(ktime_t *device,
        if (priv->plat->ext_snapshot_en)
                return -EBUSY;
 
+       priv->plat->int_snapshot_en = 1;
+
        mutex_lock(&priv->aux_ts_lock);
        /* Enable Internal snapshot trigger */
        acr_value = readl(ptpaddr + PTP_ACR);
@@ -347,6 +352,7 @@ static int intel_crosststamp(ktime_t *device,
                break;
        default:
                mutex_unlock(&priv->aux_ts_lock);
+               priv->plat->int_snapshot_en = 0;
                return -EINVAL;
        }
        writel(acr_value, ptpaddr + PTP_ACR);
@@ -368,13 +374,12 @@ static int intel_crosststamp(ktime_t *device,
        gpio_value |= GMAC_GPO1;
        writel(gpio_value, ioaddr + GMAC_GPIO_STATUS);
 
-       /* Poll for time sync operation done */
-       ret = readl_poll_timeout(priv->ioaddr + GMAC_INT_STATUS, v,
-                                (v & GMAC_INT_TSIE), 100, 10000);
-
-       if (ret == -ETIMEDOUT) {
-               pr_err("%s: Wait for time sync operation timeout\n", __func__);
-               return ret;
+       /* Time sync done Indication - Interrupt method */
+       if (!wait_event_interruptible_timeout(priv->tstamp_busy_wait,
+                                             stmmac_cross_ts_isr(priv),
+                                             HZ / 100)) {
+               priv->plat->int_snapshot_en = 0;
+               return -ETIMEDOUT;
        }
 
        num_snapshot = (readl(ioaddr + GMAC_TIMESTAMP_STATUS) &
@@ -392,6 +397,7 @@ static int intel_crosststamp(ktime_t *device,
        }
 
        system->cycles *= intel_priv->crossts_adj;
+       priv->plat->int_snapshot_en = 0;
 
        return 0;
 }
@@ -576,6 +582,7 @@ static int intel_mgbe_common_data(struct pci_dev *pdev,
 
        plat->has_crossts = true;
        plat->crosststamp = intel_crosststamp;
+       plat->int_snapshot_en = 0;
 
        /* Setup MSI vector offset specific to Intel mGbE controller */
        plat->msi_mac_vec = 29;
index 6ff88df..d42e1af 100644 (file)
@@ -576,32 +576,7 @@ static int mediatek_dwmac_init(struct platform_device *pdev, void *priv)
                }
        }
 
-       ret = clk_bulk_prepare_enable(variant->num_clks, plat->clks);
-       if (ret) {
-               dev_err(plat->dev, "failed to enable clks, err = %d\n", ret);
-               return ret;
-       }
-
-       ret = clk_prepare_enable(plat->rmii_internal_clk);
-       if (ret) {
-               dev_err(plat->dev, "failed to enable rmii internal clk, err = %d\n", ret);
-               goto err_clk;
-       }
-
        return 0;
-
-err_clk:
-       clk_bulk_disable_unprepare(variant->num_clks, plat->clks);
-       return ret;
-}
-
-static void mediatek_dwmac_exit(struct platform_device *pdev, void *priv)
-{
-       struct mediatek_dwmac_plat_data *plat = priv;
-       const struct mediatek_dwmac_variant *variant = plat->variant;
-
-       clk_disable_unprepare(plat->rmii_internal_clk);
-       clk_bulk_disable_unprepare(variant->num_clks, plat->clks);
 }
 
 static int mediatek_dwmac_clks_config(void *priv, bool enabled)
@@ -643,7 +618,6 @@ static int mediatek_dwmac_common_data(struct platform_device *pdev,
        plat->addr64 = priv_plat->variant->dma_bit_mask;
        plat->bsp_priv = priv_plat;
        plat->init = mediatek_dwmac_init;
-       plat->exit = mediatek_dwmac_exit;
        plat->clks_config = mediatek_dwmac_clks_config;
        if (priv_plat->variant->dwmac_fix_mac_speed)
                plat->fix_mac_speed = priv_plat->variant->dwmac_fix_mac_speed;
@@ -712,13 +686,33 @@ static int mediatek_dwmac_probe(struct platform_device *pdev)
        mediatek_dwmac_common_data(pdev, plat_dat, priv_plat);
        mediatek_dwmac_init(pdev, priv_plat);
 
+       ret = mediatek_dwmac_clks_config(priv_plat, true);
+       if (ret)
+               goto err_remove_config_dt;
+
        ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
-       if (ret) {
-               stmmac_remove_config_dt(pdev, plat_dat);
-               return ret;
-       }
+       if (ret)
+               goto err_drv_probe;
 
        return 0;
+
+err_drv_probe:
+       mediatek_dwmac_clks_config(priv_plat, false);
+err_remove_config_dt:
+       stmmac_remove_config_dt(pdev, plat_dat);
+
+       return ret;
+}
+
+static int mediatek_dwmac_remove(struct platform_device *pdev)
+{
+       struct mediatek_dwmac_plat_data *priv_plat = get_stmmac_bsp_priv(&pdev->dev);
+       int ret;
+
+       ret = stmmac_pltfr_remove(pdev);
+       mediatek_dwmac_clks_config(priv_plat, false);
+
+       return ret;
 }
 
 static const struct of_device_id mediatek_dwmac_match[] = {
@@ -733,7 +727,7 @@ MODULE_DEVICE_TABLE(of, mediatek_dwmac_match);
 
 static struct platform_driver mediatek_dwmac_driver = {
        .probe  = mediatek_dwmac_probe,
-       .remove = stmmac_pltfr_remove,
+       .remove = mediatek_dwmac_remove,
        .driver = {
                .name           = "dwmac-mediatek",
                .pm             = &stmmac_pltfr_pm_ops,
index 462ca7e..71dad40 100644 (file)
 #define        GMAC_PCS_IRQ_DEFAULT    (GMAC_INT_RGSMIIS | GMAC_INT_PCS_LINK | \
                                 GMAC_INT_PCS_ANE)
 
-#define        GMAC_INT_DEFAULT_ENABLE (GMAC_INT_PMT_EN | GMAC_INT_LPI_EN)
+#define        GMAC_INT_DEFAULT_ENABLE (GMAC_INT_PMT_EN | GMAC_INT_LPI_EN | \
+                                GMAC_INT_TSIE)
 
 enum dwmac4_irq_status {
        time_stamp_irq = 0x00001000,
index fd41db6..d8f1fbc 100644 (file)
@@ -23,6 +23,7 @@
 static void dwmac4_core_init(struct mac_device_info *hw,
                             struct net_device *dev)
 {
+       struct stmmac_priv *priv = netdev_priv(dev);
        void __iomem *ioaddr = hw->pcsr;
        u32 value = readl(ioaddr + GMAC_CONFIG);
 
@@ -58,6 +59,9 @@ static void dwmac4_core_init(struct mac_device_info *hw,
                value |= GMAC_INT_FPE_EN;
 
        writel(value, ioaddr + GMAC_INT_EN);
+
+       if (GMAC_INT_DEFAULT_ENABLE & GMAC_INT_TSIE)
+               init_waitqueue_head(&priv->tstamp_busy_wait);
 }
 
 static void dwmac4_rx_queue_enable(struct mac_device_info *hw,
@@ -219,6 +223,9 @@ static void dwmac4_map_mtl_dma(struct mac_device_info *hw, u32 queue, u32 chan)
        if (queue == 0 || queue == 4) {
                value &= ~MTL_RXQ_DMA_Q04MDMACH_MASK;
                value |= MTL_RXQ_DMA_Q04MDMACH(chan);
+       } else if (queue > 4) {
+               value &= ~MTL_RXQ_DMA_QXMDMACH_MASK(queue - 4);
+               value |= MTL_RXQ_DMA_QXMDMACH(chan, queue - 4);
        } else {
                value &= ~MTL_RXQ_DMA_QXMDMACH_MASK(queue);
                value |= MTL_RXQ_DMA_QXMDMACH(chan, queue);
index 57970ae..f9e8396 100644 (file)
@@ -266,6 +266,7 @@ struct stmmac_priv {
        rwlock_t ptp_lock;
        /* Protects auxiliary snapshot registers from concurrent access. */
        struct mutex aux_ts_lock;
+       wait_queue_head_t tstamp_busy_wait;
 
        void __iomem *mmcaddr;
        void __iomem *ptpaddr;
index abfb3cd..9c3055e 100644 (file)
@@ -803,14 +803,6 @@ static int stmmac_ethtool_op_set_eee(struct net_device *dev,
                netdev_warn(priv->dev,
                            "Setting EEE tx-lpi is not supported\n");
 
-       if (priv->hw->xpcs) {
-               ret = xpcs_config_eee(priv->hw->xpcs,
-                                     priv->plat->mult_fact_100ns,
-                                     edata->eee_enabled);
-               if (ret)
-                       return ret;
-       }
-
        if (!edata->eee_enabled)
                stmmac_disable_eee_mode(priv);
 
index 92d3294..764832f 100644 (file)
@@ -179,6 +179,11 @@ static void timestamp_interrupt(struct stmmac_priv *priv)
        u64 ptp_time;
        int i;
 
+       if (priv->plat->int_snapshot_en) {
+               wake_up(&priv->tstamp_busy_wait);
+               return;
+       }
+
        tsync_int = readl(priv->ioaddr + GMAC_INT_STATUS) & GMAC_INT_TSIE;
 
        if (!tsync_int)
index d1a7cf4..c5f3363 100644 (file)
@@ -834,19 +834,10 @@ int stmmac_init_tstamp_counter(struct stmmac_priv *priv, u32 systime_flags)
        struct timespec64 now;
        u32 sec_inc = 0;
        u64 temp = 0;
-       int ret;
 
        if (!(priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp))
                return -EOPNOTSUPP;
 
-       ret = clk_prepare_enable(priv->plat->clk_ptp_ref);
-       if (ret < 0) {
-               netdev_warn(priv->dev,
-                           "failed to enable PTP reference clock: %pe\n",
-                           ERR_PTR(ret));
-               return ret;
-       }
-
        stmmac_config_hw_tstamping(priv, priv->ptpaddr, systime_flags);
        priv->systime_flags = systime_flags;
 
@@ -3270,6 +3261,14 @@ static int stmmac_hw_setup(struct net_device *dev, bool ptp_register)
 
        stmmac_mmc_setup(priv);
 
+       if (ptp_register) {
+               ret = clk_prepare_enable(priv->plat->clk_ptp_ref);
+               if (ret < 0)
+                       netdev_warn(priv->dev,
+                                   "failed to enable PTP reference clock: %pe\n",
+                                   ERR_PTR(ret));
+       }
+
        ret = stmmac_init_ptp(priv);
        if (ret == -EOPNOTSUPP)
                netdev_info(priv->dev, "PTP not supported by HW\n");
@@ -7213,8 +7212,6 @@ int stmmac_dvr_remove(struct device *dev)
        netdev_info(priv->dev, "%s: removing driver", __func__);
 
        pm_runtime_get_sync(dev);
-       pm_runtime_disable(dev);
-       pm_runtime_put_noidle(dev);
 
        stmmac_stop_all_dma(priv);
        stmmac_mac_set(priv, priv->ioaddr, false);
@@ -7241,6 +7238,9 @@ int stmmac_dvr_remove(struct device *dev)
        mutex_destroy(&priv->lock);
        bitmap_free(priv->af_xdp_zc_qps);
 
+       pm_runtime_disable(dev);
+       pm_runtime_put_noidle(dev);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(stmmac_dvr_remove);
index 11e1055..9f5cac4 100644 (file)
@@ -815,7 +815,13 @@ static int __maybe_unused stmmac_pltfr_noirq_resume(struct device *dev)
                if (ret)
                        return ret;
 
-               stmmac_init_tstamp_counter(priv, priv->systime_flags);
+               ret = clk_prepare_enable(priv->plat->clk_ptp_ref);
+               if (ret < 0) {
+                       netdev_warn(priv->dev,
+                                   "failed to enable PTP reference clock: %pe\n",
+                                   ERR_PTR(ret));
+                       return ret;
+               }
        }
 
        return 0;
index e45fb19..4d11980 100644 (file)
@@ -175,11 +175,10 @@ static int stmmac_enable(struct ptp_clock_info *ptp,
        struct stmmac_priv *priv =
            container_of(ptp, struct stmmac_priv, ptp_clock_ops);
        void __iomem *ptpaddr = priv->ptpaddr;
-       void __iomem *ioaddr = priv->hw->pcsr;
        struct stmmac_pps_cfg *cfg;
-       u32 intr_value, acr_value;
        int ret = -EOPNOTSUPP;
        unsigned long flags;
+       u32 acr_value;
 
        switch (rq->type) {
        case PTP_CLK_REQ_PEROUT:
@@ -213,19 +212,10 @@ static int stmmac_enable(struct ptp_clock_info *ptp,
                        netdev_dbg(priv->dev, "Auxiliary Snapshot %d enabled.\n",
                                   priv->plat->ext_snapshot_num >>
                                   PTP_ACR_ATSEN_SHIFT);
-                       /* Enable Timestamp Interrupt */
-                       intr_value = readl(ioaddr + GMAC_INT_EN);
-                       intr_value |= GMAC_INT_TSIE;
-                       writel(intr_value, ioaddr + GMAC_INT_EN);
-
                } else {
                        netdev_dbg(priv->dev, "Auxiliary Snapshot %d disabled.\n",
                                   priv->plat->ext_snapshot_num >>
                                   PTP_ACR_ATSEN_SHIFT);
-                       /* Disable Timestamp Interrupt */
-                       intr_value = readl(ioaddr + GMAC_INT_EN);
-                       intr_value &= ~GMAC_INT_TSIE;
-                       writel(intr_value, ioaddr + GMAC_INT_EN);
                }
                writel(acr_value, ptpaddr + PTP_ACR);
                mutex_unlock(&priv->aux_ts_lock);
index 77e5dff..8594ee8 100644 (file)
@@ -545,43 +545,24 @@ static int try_next_permutation(struct happy_meal *hp, void __iomem *tregs)
 
 static void display_link_mode(struct happy_meal *hp, void __iomem *tregs)
 {
-       printk(KERN_INFO "%s: Link is up using ", hp->dev->name);
-       if (hp->tcvr_type == external)
-               printk("external ");
-       else
-               printk("internal ");
-       printk("transceiver at ");
        hp->sw_lpa = happy_meal_tcvr_read(hp, tregs, MII_LPA);
-       if (hp->sw_lpa & (LPA_100HALF | LPA_100FULL)) {
-               if (hp->sw_lpa & LPA_100FULL)
-                       printk("100Mb/s, Full Duplex.\n");
-               else
-                       printk("100Mb/s, Half Duplex.\n");
-       } else {
-               if (hp->sw_lpa & LPA_10FULL)
-                       printk("10Mb/s, Full Duplex.\n");
-               else
-                       printk("10Mb/s, Half Duplex.\n");
-       }
+
+       netdev_info(hp->dev,
+                   "Link is up using %s transceiver at %dMb/s, %s Duplex.\n",
+                   hp->tcvr_type == external ? "external" : "internal",
+                   hp->sw_lpa & (LPA_100HALF | LPA_100FULL) ? 100 : 10,
+                   hp->sw_lpa & (LPA_100FULL | LPA_10FULL) ? "Full" : "Half");
 }
 
 static void display_forced_link_mode(struct happy_meal *hp, void __iomem *tregs)
 {
-       printk(KERN_INFO "%s: Link has been forced up using ", hp->dev->name);
-       if (hp->tcvr_type == external)
-               printk("external ");
-       else
-               printk("internal ");
-       printk("transceiver at ");
        hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR);
-       if (hp->sw_bmcr & BMCR_SPEED100)
-               printk("100Mb/s, ");
-       else
-               printk("10Mb/s, ");
-       if (hp->sw_bmcr & BMCR_FULLDPLX)
-               printk("Full Duplex.\n");
-       else
-               printk("Half Duplex.\n");
+
+       netdev_info(hp->dev,
+                   "Link has been forced up using %s transceiver at %dMb/s, %s Duplex.\n",
+                   hp->tcvr_type == external ? "external" : "internal",
+                   hp->sw_bmcr & BMCR_SPEED100 ? 100 : 10,
+                   hp->sw_bmcr & BMCR_FULLDPLX ? "Full" : "Half");
 }
 
 static int set_happy_link_modes(struct happy_meal *hp, void __iomem *tregs)
index fb92d4c..f4a6b59 100644 (file)
@@ -2467,7 +2467,6 @@ static int am65_cpsw_nuss_register_devlink(struct am65_cpsw_common *common)
                                port->port_id, ret);
                        goto dl_port_unreg;
                }
-               devlink_port_type_eth_set(dl_port, port->ndev);
        }
        devlink_register(common->devlink);
        return ret;
@@ -2511,6 +2510,7 @@ static void am65_cpsw_unregister_devlink(struct am65_cpsw_common *common)
 static int am65_cpsw_nuss_register_ndevs(struct am65_cpsw_common *common)
 {
        struct device *dev = common->dev;
+       struct devlink_port *dl_port;
        struct am65_cpsw_port *port;
        int ret = 0, i;
 
@@ -2527,6 +2527,10 @@ static int am65_cpsw_nuss_register_ndevs(struct am65_cpsw_common *common)
                return ret;
        }
 
+       ret = am65_cpsw_nuss_register_devlink(common);
+       if (ret)
+               return ret;
+
        for (i = 0; i < common->port_num; i++) {
                port = &common->ports[i];
 
@@ -2539,25 +2543,24 @@ static int am65_cpsw_nuss_register_ndevs(struct am65_cpsw_common *common)
                                i, ret);
                        goto err_cleanup_ndev;
                }
+
+               dl_port = &port->devlink_port;
+               devlink_port_type_eth_set(dl_port, port->ndev);
        }
 
        ret = am65_cpsw_register_notifiers(common);
        if (ret)
                goto err_cleanup_ndev;
 
-       ret = am65_cpsw_nuss_register_devlink(common);
-       if (ret)
-               goto clean_unregister_notifiers;
-
        /* can't auto unregister ndev using devm_add_action() due to
         * devres release sequence in DD core for DMA
         */
 
        return 0;
-clean_unregister_notifiers:
-       am65_cpsw_unregister_notifiers(common);
+
 err_cleanup_ndev:
        am65_cpsw_nuss_cleanup_ndev(common);
+       am65_cpsw_unregister_devlink(common);
 
        return ret;
 }
index 3233d14..495e85a 100644 (file)
@@ -214,7 +214,7 @@ struct ipa_init_modem_driver_req {
 
 /* The response to a IPA_QMI_INIT_DRIVER request begins with a standard
  * QMI response, but contains other information as well.  Currently we
- * simply wait for the the INIT_DRIVER transaction to complete and
+ * simply wait for the INIT_DRIVER transaction to complete and
  * ignore any other data that might be returned.
  */
 struct ipa_init_modem_driver_rsp {
index 817577e..f354fad 100644 (file)
@@ -243,6 +243,7 @@ static struct macsec_cb *macsec_skb_cb(struct sk_buff *skb)
 #define DEFAULT_SEND_SCI true
 #define DEFAULT_ENCRYPT false
 #define DEFAULT_ENCODING_SA 0
+#define MACSEC_XPN_MAX_REPLAY_WINDOW (((1 << 30) - 1))
 
 static bool send_sci(const struct macsec_secy *secy)
 {
@@ -1697,7 +1698,7 @@ static bool validate_add_rxsa(struct nlattr **attrs)
                return false;
 
        if (attrs[MACSEC_SA_ATTR_PN] &&
-           *(u64 *)nla_data(attrs[MACSEC_SA_ATTR_PN]) == 0)
+           nla_get_u64(attrs[MACSEC_SA_ATTR_PN]) == 0)
                return false;
 
        if (attrs[MACSEC_SA_ATTR_ACTIVE]) {
@@ -1753,7 +1754,8 @@ static int macsec_add_rxsa(struct sk_buff *skb, struct genl_info *info)
        }
 
        pn_len = secy->xpn ? MACSEC_XPN_PN_LEN : MACSEC_DEFAULT_PN_LEN;
-       if (nla_len(tb_sa[MACSEC_SA_ATTR_PN]) != pn_len) {
+       if (tb_sa[MACSEC_SA_ATTR_PN] &&
+           nla_len(tb_sa[MACSEC_SA_ATTR_PN]) != pn_len) {
                pr_notice("macsec: nl: add_rxsa: bad pn length: %d != %d\n",
                          nla_len(tb_sa[MACSEC_SA_ATTR_PN]), pn_len);
                rtnl_unlock();
@@ -1769,7 +1771,7 @@ static int macsec_add_rxsa(struct sk_buff *skb, struct genl_info *info)
                if (nla_len(tb_sa[MACSEC_SA_ATTR_SALT]) != MACSEC_SALT_LEN) {
                        pr_notice("macsec: nl: add_rxsa: bad salt length: %d != %d\n",
                                  nla_len(tb_sa[MACSEC_SA_ATTR_SALT]),
-                                 MACSEC_SA_ATTR_SALT);
+                                 MACSEC_SALT_LEN);
                        rtnl_unlock();
                        return -EINVAL;
                }
@@ -1842,7 +1844,7 @@ static int macsec_add_rxsa(struct sk_buff *skb, struct genl_info *info)
        return 0;
 
 cleanup:
-       kfree(rx_sa);
+       macsec_rxsa_put(rx_sa);
        rtnl_unlock();
        return err;
 }
@@ -1939,7 +1941,7 @@ static bool validate_add_txsa(struct nlattr **attrs)
        if (nla_get_u8(attrs[MACSEC_SA_ATTR_AN]) >= MACSEC_NUM_AN)
                return false;
 
-       if (nla_get_u32(attrs[MACSEC_SA_ATTR_PN]) == 0)
+       if (nla_get_u64(attrs[MACSEC_SA_ATTR_PN]) == 0)
                return false;
 
        if (attrs[MACSEC_SA_ATTR_ACTIVE]) {
@@ -2011,7 +2013,7 @@ static int macsec_add_txsa(struct sk_buff *skb, struct genl_info *info)
                if (nla_len(tb_sa[MACSEC_SA_ATTR_SALT]) != MACSEC_SALT_LEN) {
                        pr_notice("macsec: nl: add_txsa: bad salt length: %d != %d\n",
                                  nla_len(tb_sa[MACSEC_SA_ATTR_SALT]),
-                                 MACSEC_SA_ATTR_SALT);
+                                 MACSEC_SALT_LEN);
                        rtnl_unlock();
                        return -EINVAL;
                }
@@ -2085,7 +2087,7 @@ static int macsec_add_txsa(struct sk_buff *skb, struct genl_info *info)
 
 cleanup:
        secy->operational = was_operational;
-       kfree(tx_sa);
+       macsec_txsa_put(tx_sa);
        rtnl_unlock();
        return err;
 }
@@ -2293,7 +2295,7 @@ static bool validate_upd_sa(struct nlattr **attrs)
        if (nla_get_u8(attrs[MACSEC_SA_ATTR_AN]) >= MACSEC_NUM_AN)
                return false;
 
-       if (attrs[MACSEC_SA_ATTR_PN] && nla_get_u32(attrs[MACSEC_SA_ATTR_PN]) == 0)
+       if (attrs[MACSEC_SA_ATTR_PN] && nla_get_u64(attrs[MACSEC_SA_ATTR_PN]) == 0)
                return false;
 
        if (attrs[MACSEC_SA_ATTR_ACTIVE]) {
@@ -3745,9 +3747,6 @@ static int macsec_changelink_common(struct net_device *dev,
                secy->operational = tx_sa && tx_sa->active;
        }
 
-       if (data[IFLA_MACSEC_WINDOW])
-               secy->replay_window = nla_get_u32(data[IFLA_MACSEC_WINDOW]);
-
        if (data[IFLA_MACSEC_ENCRYPT])
                tx_sc->encrypt = !!nla_get_u8(data[IFLA_MACSEC_ENCRYPT]);
 
@@ -3793,6 +3792,16 @@ static int macsec_changelink_common(struct net_device *dev,
                }
        }
 
+       if (data[IFLA_MACSEC_WINDOW]) {
+               secy->replay_window = nla_get_u32(data[IFLA_MACSEC_WINDOW]);
+
+               /* IEEE 802.1AEbw-2013 10.7.8 - maximum replay window
+                * for XPN cipher suites */
+               if (secy->xpn &&
+                   secy->replay_window > MACSEC_XPN_MAX_REPLAY_WINDOW)
+                       return -EINVAL;
+       }
+
        return 0;
 }
 
@@ -3822,7 +3831,7 @@ static int macsec_changelink(struct net_device *dev, struct nlattr *tb[],
 
        ret = macsec_changelink_common(dev, data);
        if (ret)
-               return ret;
+               goto cleanup;
 
        /* If h/w offloading is available, propagate to the device */
        if (macsec_is_offloaded(macsec)) {
index 4cfd05c..d25fbb9 100644 (file)
@@ -896,7 +896,7 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
         */
        ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS);
        if (ret < 0)
-               return false;
+               return ret;
 
        if (ret & DW_VR_MII_C37_ANSGM_SP_LNKSTS) {
                int speed_value;
index 4578963..0f1e617 100644 (file)
@@ -88,8 +88,10 @@ static void asix_ax88772a_link_change_notify(struct phy_device *phydev)
        /* Reset PHY, otherwise MII_LPA will provide outdated information.
         * This issue is reproducible only with some link partner PHYs
         */
-       if (phydev->state == PHY_NOLINK && phydev->drv->soft_reset)
-               phydev->drv->soft_reset(phydev);
+       if (phydev->state == PHY_NOLINK) {
+               phy_init_hw(phydev);
+               phy_start_aneg(phydev);
+       }
 }
 
 static struct phy_driver asix_driver[] = {
index e6ad3a4..8549e0e 100644 (file)
@@ -229,9 +229,7 @@ static int dp83822_config_intr(struct phy_device *phydev)
                if (misr_status < 0)
                        return misr_status;
 
-               misr_status |= (DP83822_RX_ERR_HF_INT_EN |
-                               DP83822_FALSE_CARRIER_HF_INT_EN |
-                               DP83822_LINK_STAT_INT_EN |
+               misr_status |= (DP83822_LINK_STAT_INT_EN |
                                DP83822_ENERGY_DET_INT_EN |
                                DP83822_LINK_QUAL_INT_EN);
 
index ef62f35..8d3ee3a 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 #include <linux/atomic.h>
+#include <linux/suspend.h>
 #include <net/netlink.h>
 #include <net/genetlink.h>
 #include <net/sock.h>
@@ -976,6 +977,28 @@ static irqreturn_t phy_interrupt(int irq, void *phy_dat)
        struct phy_driver *drv = phydev->drv;
        irqreturn_t ret;
 
+       /* Wakeup interrupts may occur during a system sleep transition.
+        * Postpone handling until the PHY has resumed.
+        */
+       if (IS_ENABLED(CONFIG_PM_SLEEP) && phydev->irq_suspended) {
+               struct net_device *netdev = phydev->attached_dev;
+
+               if (netdev) {
+                       struct device *parent = netdev->dev.parent;
+
+                       if (netdev->wol_enabled)
+                               pm_system_wakeup();
+                       else if (device_may_wakeup(&netdev->dev))
+                               pm_wakeup_dev_event(&netdev->dev, 0, true);
+                       else if (parent && device_may_wakeup(parent))
+                               pm_wakeup_dev_event(parent, 0, true);
+               }
+
+               phydev->irq_rerun = 1;
+               disable_irq_nosync(irq);
+               return IRQ_HANDLED;
+       }
+
        mutex_lock(&phydev->lock);
        ret = drv->handle_interrupt(phydev);
        mutex_unlock(&phydev->lock);
index 431a871..46acddd 100644 (file)
@@ -278,6 +278,15 @@ static __maybe_unused int mdio_bus_phy_suspend(struct device *dev)
        if (phydev->mac_managed_pm)
                return 0;
 
+       /* Wakeup interrupts may occur during the system sleep transition when
+        * the PHY is inaccessible. Set flag to postpone handling until the PHY
+        * has resumed. Wait for concurrent interrupt handler to complete.
+        */
+       if (phy_interrupt_is_valid(phydev)) {
+               phydev->irq_suspended = 1;
+               synchronize_irq(phydev->irq);
+       }
+
        /* We must stop the state machine manually, otherwise it stops out of
         * control, possibly with the phydev->lock held. Upon resume, netdev
         * may call phy routines that try to grab the same lock, and that may
@@ -315,6 +324,20 @@ static __maybe_unused int mdio_bus_phy_resume(struct device *dev)
        if (ret < 0)
                return ret;
 no_resume:
+       if (phy_interrupt_is_valid(phydev)) {
+               phydev->irq_suspended = 0;
+               synchronize_irq(phydev->irq);
+
+               /* Rerun interrupts which were postponed by phy_interrupt()
+                * because they occurred during the system sleep transition.
+                */
+               if (phydev->irq_rerun) {
+                       phydev->irq_rerun = 0;
+                       enable_irq(phydev->irq);
+                       irq_wake_thread(phydev->irq, phydev);
+               }
+       }
+
        if (phydev->attached_dev && phydev->adjust_link)
                phy_start_machine(phydev);
 
index 9a5d5a1..e7b0e12 100644 (file)
@@ -2516,7 +2516,7 @@ static int sfp_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, sfp);
 
-       err = devm_add_action(sfp->dev, sfp_cleanup, sfp);
+       err = devm_add_action_or_reset(sfp->dev, sfp_cleanup, sfp);
        if (err < 0)
                return err;
 
index ff22b6b..36803d9 100644 (file)
@@ -450,6 +450,7 @@ static int bcm5421_init(struct mii_phy* phy)
                int can_low_power = 1;
                if (np == NULL || of_get_property(np, "no-autolowpower", NULL))
                        can_low_power = 0;
+               of_node_put(np);
                if (can_low_power) {
                        /* Enable automatic low-power */
                        sungem_phy_write(phy, 0x1c, 0x9002);
index 87a635a..259b2b8 100644 (file)
@@ -273,6 +273,12 @@ static void tun_napi_init(struct tun_struct *tun, struct tun_file *tfile,
        }
 }
 
+static void tun_napi_enable(struct tun_file *tfile)
+{
+       if (tfile->napi_enabled)
+               napi_enable(&tfile->napi);
+}
+
 static void tun_napi_disable(struct tun_file *tfile)
 {
        if (tfile->napi_enabled)
@@ -634,7 +640,8 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
        tun = rtnl_dereference(tfile->tun);
 
        if (tun && clean) {
-               tun_napi_disable(tfile);
+               if (!tfile->detached)
+                       tun_napi_disable(tfile);
                tun_napi_del(tfile);
        }
 
@@ -653,8 +660,10 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
                if (clean) {
                        RCU_INIT_POINTER(tfile->tun, NULL);
                        sock_put(&tfile->sk);
-               } else
+               } else {
                        tun_disable_queue(tun, tfile);
+                       tun_napi_disable(tfile);
+               }
 
                synchronize_net();
                tun_flow_delete_by_queue(tun, tun->numqueues + 1);
@@ -727,6 +736,7 @@ static void tun_detach_all(struct net_device *dev)
                sock_put(&tfile->sk);
        }
        list_for_each_entry_safe(tfile, tmp, &tun->disabled, next) {
+               tun_napi_del(tfile);
                tun_enable_queue(tfile);
                tun_queue_purge(tfile);
                xdp_rxq_info_unreg(&tfile->xdp_rxq);
@@ -807,6 +817,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file,
 
        if (tfile->detached) {
                tun_enable_queue(tfile);
+               tun_napi_enable(tfile);
        } else {
                sock_hold(&tfile->sk);
                tun_napi_init(tun, tfile, napi, napi_frags);
index 2c81236..45d3cc5 100644 (file)
         AX_MEDIUM_RE)
 
 #define AX88772_MEDIUM_DEFAULT \
-       (AX_MEDIUM_FD | AX_MEDIUM_RFC | \
-        AX_MEDIUM_TFC | AX_MEDIUM_PS | \
+       (AX_MEDIUM_FD | AX_MEDIUM_PS | \
         AX_MEDIUM_AC | AX_MEDIUM_RE)
 
 /* AX88772 & AX88178 RX_CTL values */
index 632fa6c..b4a1b7a 100644 (file)
@@ -431,6 +431,7 @@ void asix_adjust_link(struct net_device *netdev)
 
        asix_write_medium_mode(dev, mode, 0);
        phy_print_status(phydev);
+       usbnet_link_change(dev, phydev->link, 0);
 }
 
 int asix_write_gpio(struct usbnet *dev, u16 value, int sleep, int in_pm)
index 4704ed6..ac2d400 100644 (file)
@@ -1472,6 +1472,42 @@ static int ax88179_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
         * are bundled into this buffer and where we can find an array of
         * per-packet metadata (which contains elements encoded into u16).
         */
+
+       /* SKB contents for current firmware:
+        *   <packet 1> <padding>
+        *   ...
+        *   <packet N> <padding>
+        *   <per-packet metadata entry 1> <dummy header>
+        *   ...
+        *   <per-packet metadata entry N> <dummy header>
+        *   <padding2> <rx_hdr>
+        *
+        * where:
+        *   <packet N> contains pkt_len bytes:
+        *              2 bytes of IP alignment pseudo header
+        *              packet received
+        *   <per-packet metadata entry N> contains 4 bytes:
+        *              pkt_len and fields AX_RXHDR_*
+        *   <padding>  0-7 bytes to terminate at
+        *              8 bytes boundary (64-bit).
+        *   <padding2> 4 bytes to make rx_hdr terminate at
+        *              8 bytes boundary (64-bit)
+        *   <dummy-header> contains 4 bytes:
+        *              pkt_len=0 and AX_RXHDR_DROP_ERR
+        *   <rx-hdr>   contains 4 bytes:
+        *              pkt_cnt and hdr_off (offset of
+        *                <per-packet metadata entry 1>)
+        *
+        * pkt_cnt is number of entrys in the per-packet metadata.
+        * In current firmware there is 2 entrys per packet.
+        * The first points to the packet and the
+        *  second is a dummy header.
+        * This was done probably to align fields in 64-bit and
+        *  maintain compatibility with old firmware.
+        * This code assumes that <dummy header> and <padding2> are
+        *  optional.
+        */
+
        if (skb->len < 4)
                return 0;
        skb_trim(skb, skb->len - 4);
@@ -1485,51 +1521,66 @@ static int ax88179_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
        /* Make sure that the bounds of the metadata array are inside the SKB
         * (and in front of the counter at the end).
         */
-       if (pkt_cnt * 2 + hdr_off > skb->len)
+       if (pkt_cnt * 4 + hdr_off > skb->len)
                return 0;
        pkt_hdr = (u32 *)(skb->data + hdr_off);
 
        /* Packets must not overlap the metadata array */
        skb_trim(skb, hdr_off);
 
-       for (; ; pkt_cnt--, pkt_hdr++) {
+       for (; pkt_cnt > 0; pkt_cnt--, pkt_hdr++) {
+               u16 pkt_len_plus_padd;
                u16 pkt_len;
 
                le32_to_cpus(pkt_hdr);
                pkt_len = (*pkt_hdr >> 16) & 0x1fff;
+               pkt_len_plus_padd = (pkt_len + 7) & 0xfff8;
 
-               if (pkt_len > skb->len)
+               /* Skip dummy header used for alignment
+                */
+               if (pkt_len == 0)
+                       continue;
+
+               if (pkt_len_plus_padd > skb->len)
                        return 0;
 
                /* Check CRC or runt packet */
-               if (((*pkt_hdr & (AX_RXHDR_CRC_ERR | AX_RXHDR_DROP_ERR)) == 0) &&
-                   pkt_len >= 2 + ETH_HLEN) {
-                       bool last = (pkt_cnt == 0);
-
-                       if (last) {
-                               ax_skb = skb;
-                       } else {
-                               ax_skb = skb_clone(skb, GFP_ATOMIC);
-                               if (!ax_skb)
-                                       return 0;
-                       }
-                       ax_skb->len = pkt_len;
-                       /* Skip IP alignment pseudo header */
-                       skb_pull(ax_skb, 2);
-                       skb_set_tail_pointer(ax_skb, ax_skb->len);
-                       ax_skb->truesize = pkt_len + sizeof(struct sk_buff);
-                       ax88179_rx_checksum(ax_skb, pkt_hdr);
+               if ((*pkt_hdr & (AX_RXHDR_CRC_ERR | AX_RXHDR_DROP_ERR)) ||
+                   pkt_len < 2 + ETH_HLEN) {
+                       dev->net->stats.rx_errors++;
+                       skb_pull(skb, pkt_len_plus_padd);
+                       continue;
+               }
 
-                       if (last)
-                               return 1;
+               /* last packet */
+               if (pkt_len_plus_padd == skb->len) {
+                       skb_trim(skb, pkt_len);
 
-                       usbnet_skb_return(dev, ax_skb);
+                       /* Skip IP alignment pseudo header */
+                       skb_pull(skb, 2);
+
+                       skb->truesize = SKB_TRUESIZE(pkt_len_plus_padd);
+                       ax88179_rx_checksum(skb, pkt_hdr);
+                       return 1;
                }
 
-               /* Trim this packet away from the SKB */
-               if (!skb_pull(skb, (pkt_len + 7) & 0xFFF8))
+               ax_skb = skb_clone(skb, GFP_ATOMIC);
+               if (!ax_skb)
                        return 0;
+               skb_trim(ax_skb, pkt_len);
+
+               /* Skip IP alignment pseudo header */
+               skb_pull(ax_skb, 2);
+
+               skb->truesize = pkt_len_plus_padd +
+                               SKB_DATA_ALIGN(sizeof(struct sk_buff));
+               ax88179_rx_checksum(ax_skb, pkt_hdr);
+               usbnet_skb_return(dev, ax_skb);
+
+               skb_pull(skb, pkt_len_plus_padd);
        }
+
+       return 0;
 }
 
 static struct sk_buff *
index e7fe9c0..1a376ed 100644 (file)
@@ -781,7 +781,7 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id
                        intf->altsetting->desc.bInterfaceNumber, 1)) {
                dev_err(dev, "Can't set altsetting 1.\n");
                ret = -EIO;
-               goto fail_mem;;
+               goto fail_mem;
        }
 
        netdev = alloc_etherdev(sizeof(struct catc));
index 7389d6e..0f6efaa 100644 (file)
@@ -32,7 +32,7 @@
 #define NETNEXT_VERSION                "12"
 
 /* Information for net */
-#define NET_VERSION            "12"
+#define NET_VERSION            "13"
 
 #define DRIVER_VERSION         "v1." NETNEXT_VERSION "." NET_VERSION
 #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
@@ -2156,7 +2156,7 @@ static inline void rtl_rx_vlan_tag(struct rx_desc *desc, struct sk_buff *skb)
 }
 
 static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc,
-                        struct sk_buff *skb, u32 len, u32 transport_offset)
+                        struct sk_buff *skb, u32 len)
 {
        u32 mss = skb_shinfo(skb)->gso_size;
        u32 opts1, opts2 = 0;
@@ -2167,6 +2167,8 @@ static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc,
        opts1 = len | TX_FS | TX_LS;
 
        if (mss) {
+               u32 transport_offset = (u32)skb_transport_offset(skb);
+
                if (transport_offset > GTTCPHO_MAX) {
                        netif_warn(tp, tx_err, tp->netdev,
                                   "Invalid transport offset 0x%x for TSO\n",
@@ -2197,6 +2199,7 @@ static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc,
                opts1 |= transport_offset << GTTCPHO_SHIFT;
                opts2 |= min(mss, MSS_MAX) << MSS_SHIFT;
        } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+               u32 transport_offset = (u32)skb_transport_offset(skb);
                u8 ip_protocol;
 
                if (transport_offset > TCPHO_MAX) {
@@ -2260,7 +2263,6 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
                struct tx_desc *tx_desc;
                struct sk_buff *skb;
                unsigned int len;
-               u32 offset;
 
                skb = __skb_dequeue(&skb_head);
                if (!skb)
@@ -2276,9 +2278,7 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
                tx_data = tx_agg_align(tx_data);
                tx_desc = (struct tx_desc *)tx_data;
 
-               offset = (u32)skb_transport_offset(skb);
-
-               if (r8152_tx_csum(tp, tx_desc, skb, skb->len, offset)) {
+               if (r8152_tx_csum(tp, tx_desc, skb, skb->len)) {
                        r8152_csum_workaround(tp, skb, &skb_head);
                        continue;
                }
@@ -2759,9 +2759,9 @@ rtl8152_features_check(struct sk_buff *skb, struct net_device *dev,
 {
        u32 mss = skb_shinfo(skb)->gso_size;
        int max_offset = mss ? GTTCPHO_MAX : TCPHO_MAX;
-       int offset = skb_transport_offset(skb);
 
-       if ((mss || skb->ip_summed == CHECKSUM_PARTIAL) && offset > max_offset)
+       if ((mss || skb->ip_summed == CHECKSUM_PARTIAL) &&
+           skb_transport_offset(skb) > max_offset)
                features &= ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
        else if ((skb->len + sizeof(struct tx_desc)) > agg_buf_sz)
                features &= ~NETIF_F_GSO_MASK;
@@ -5917,7 +5917,8 @@ static void r8153_enter_oob(struct r8152 *tp)
 
        wait_oob_link_list_ready(tp);
 
-       ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, mtu_to_size(tp->netdev->mtu));
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, 1522);
+       ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, MTPS_DEFAULT);
 
        switch (tp->version) {
        case RTL_VER_03:
@@ -5953,6 +5954,10 @@ static void r8153_enter_oob(struct r8152 *tp)
        ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB;
        ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
 
+       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
+       ocp_data |= MCU_BORW_EN;
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
+
        rxdy_gated_en(tp, false);
 
        ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
@@ -6555,6 +6560,9 @@ static void rtl8156_down(struct r8152 *tp)
        rtl_disable(tp);
        rtl_reset_bmu(tp);
 
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, 1522);
+       ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, MTPS_DEFAULT);
+
        /* Clear teredo wake event. bit[15:8] is the teredo wakeup
         * type. Set it to zero. bits[7:0] are the W1C bits about
         * the events. Set them to all 1 to clear them.
@@ -6565,6 +6573,10 @@ static void rtl8156_down(struct r8152 *tp)
        ocp_data |= NOW_IS_OOB;
        ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
 
+       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
+       ocp_data |= MCU_BORW_EN;
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
+
        rtl_rx_vlan_en(tp, true);
        rxdy_gated_en(tp, false);
 
index 1cb6dab..78a9275 100644 (file)
@@ -2004,7 +2004,7 @@ static int __usbnet_read_cmd(struct usbnet *dev, u8 cmd, u8 reqtype,
                   cmd, reqtype, value, index, size);
 
        if (size) {
-               buf = kmalloc(size, GFP_KERNEL);
+               buf = kmalloc(size, GFP_NOIO);
                if (!buf)
                        goto out;
        }
@@ -2036,7 +2036,7 @@ static int __usbnet_write_cmd(struct usbnet *dev, u8 cmd, u8 reqtype,
                   cmd, reqtype, value, index, size);
 
        if (data) {
-               buf = kmemdup(data, size, GFP_KERNEL);
+               buf = kmemdup(data, size, GFP_NOIO);
                if (!buf)
                        goto out;
        } else {
@@ -2137,7 +2137,7 @@ static void usbnet_async_cmd_cb(struct urb *urb)
 int usbnet_write_cmd_async(struct usbnet *dev, u8 cmd, u8 reqtype,
                           u16 value, u16 index, const void *data, u16 size)
 {
-       struct usb_ctrlrequest *req = NULL;
+       struct usb_ctrlrequest *req;
        struct urb *urb;
        int err = -ENOMEM;
        void *buf = NULL;
@@ -2155,7 +2155,7 @@ int usbnet_write_cmd_async(struct usbnet *dev, u8 cmd, u8 reqtype,
                if (!buf) {
                        netdev_err(dev->net, "Error allocating buffer"
                                   " in %s!\n", __func__);
-                       goto fail_free;
+                       goto fail_free_urb;
                }
        }
 
@@ -2179,14 +2179,21 @@ int usbnet_write_cmd_async(struct usbnet *dev, u8 cmd, u8 reqtype,
        if (err < 0) {
                netdev_err(dev->net, "Error submitting the control"
                           " message: status=%d\n", err);
-               goto fail_free;
+               goto fail_free_all;
        }
        return 0;
 
+fail_free_all:
+       kfree(req);
 fail_free_buf:
        kfree(buf);
-fail_free:
-       kfree(req);
+       /*
+        * avoid a double free
+        * needed because the flag can be set only
+        * after filling the URB
+        */
+       urb->transfer_flags = 0;
+fail_free_urb:
        usb_free_urb(urb);
 fail:
        return err;
index 969a679..ec8e1b3 100644 (file)
@@ -242,9 +242,15 @@ struct virtnet_info {
        /* Packet virtio header size */
        u8 hdr_len;
 
-       /* Work struct for refilling if we run low on memory. */
+       /* Work struct for delayed refilling if we run low on memory. */
        struct delayed_work refill;
 
+       /* Is delayed refill enabled? */
+       bool refill_enabled;
+
+       /* The lock to synchronize the access to refill_enabled */
+       spinlock_t refill_lock;
+
        /* Work struct for config space updates */
        struct work_struct config_work;
 
@@ -348,6 +354,20 @@ static struct page *get_a_page(struct receive_queue *rq, gfp_t gfp_mask)
        return p;
 }
 
+static void enable_delayed_refill(struct virtnet_info *vi)
+{
+       spin_lock_bh(&vi->refill_lock);
+       vi->refill_enabled = true;
+       spin_unlock_bh(&vi->refill_lock);
+}
+
+static void disable_delayed_refill(struct virtnet_info *vi)
+{
+       spin_lock_bh(&vi->refill_lock);
+       vi->refill_enabled = false;
+       spin_unlock_bh(&vi->refill_lock);
+}
+
 static void virtqueue_napi_schedule(struct napi_struct *napi,
                                    struct virtqueue *vq)
 {
@@ -1527,8 +1547,12 @@ static int virtnet_receive(struct receive_queue *rq, int budget,
        }
 
        if (rq->vq->num_free > min((unsigned int)budget, virtqueue_get_vring_size(rq->vq)) / 2) {
-               if (!try_fill_recv(vi, rq, GFP_ATOMIC))
-                       schedule_delayed_work(&vi->refill, 0);
+               if (!try_fill_recv(vi, rq, GFP_ATOMIC)) {
+                       spin_lock(&vi->refill_lock);
+                       if (vi->refill_enabled)
+                               schedule_delayed_work(&vi->refill, 0);
+                       spin_unlock(&vi->refill_lock);
+               }
        }
 
        u64_stats_update_begin(&rq->stats.syncp);
@@ -1651,6 +1675,8 @@ static int virtnet_open(struct net_device *dev)
        struct virtnet_info *vi = netdev_priv(dev);
        int i, err;
 
+       enable_delayed_refill(vi);
+
        for (i = 0; i < vi->max_queue_pairs; i++) {
                if (i < vi->curr_queue_pairs)
                        /* Make sure we have some buffers: if oom use wq. */
@@ -2033,6 +2059,8 @@ static int virtnet_close(struct net_device *dev)
        struct virtnet_info *vi = netdev_priv(dev);
        int i;
 
+       /* Make sure NAPI doesn't schedule refill work */
+       disable_delayed_refill(vi);
        /* Make sure refill_work doesn't re-enable napi! */
        cancel_delayed_work_sync(&vi->refill);
 
@@ -2792,6 +2820,8 @@ static int virtnet_restore_up(struct virtio_device *vdev)
 
        virtio_device_ready(vdev);
 
+       enable_delayed_refill(vi);
+
        if (netif_running(vi->dev)) {
                err = virtnet_open(vi->dev);
                if (err)
@@ -3535,6 +3565,7 @@ static int virtnet_probe(struct virtio_device *vdev)
        vdev->priv = vi;
 
        INIT_WORK(&vi->config_work, virtnet_config_changed_work);
+       spin_lock_init(&vi->refill_lock);
 
        /* If we can receive ANY GSO packets, we must allocate large ones. */
        if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) ||
@@ -3642,14 +3673,20 @@ static int virtnet_probe(struct virtio_device *vdev)
        if (vi->has_rss || vi->has_rss_hash_report)
                virtnet_init_default_rss(vi);
 
-       err = register_netdev(dev);
+       /* serialize netdev register + virtio_device_ready() with ndo_open() */
+       rtnl_lock();
+
+       err = register_netdevice(dev);
        if (err) {
                pr_debug("virtio_net: registering device failed\n");
+               rtnl_unlock();
                goto free_failover;
        }
 
        virtio_device_ready(vdev);
 
+       rtnl_unlock();
+
        err = virtnet_cpu_notif_add(vi);
        if (err) {
                pr_debug("virtio_net: registering cpu notifier failed\n");
index 84d1c70..7b1dc19 100644 (file)
@@ -3822,7 +3822,8 @@ ath11k_wmi_obss_color_collision_event(struct ath11k_base *ab, struct sk_buff *sk
 
        switch (ev->evt_type) {
        case WMI_BSS_COLOR_COLLISION_DETECTION:
-               ieeee80211_obss_color_collision_notify(arvif->vif, ev->obss_color_bitmap);
+               ieeee80211_obss_color_collision_notify(arvif->vif, ev->obss_color_bitmap,
+                                                      GFP_KERNEL);
                ath11k_dbg(ab, ATH11K_DBG_WMI,
                           "OBSS color collision detected vdev:%d, event:%d, bitmap:%08llx\n",
                           ev->vdev_id, ev->evt_type, ev->obss_color_bitmap);
index 2f746eb..6f83af8 100644 (file)
@@ -4912,6 +4912,8 @@ static int hwsim_virtio_probe(struct virtio_device *vdev)
        if (err)
                return err;
 
+       virtio_device_ready(vdev);
+
        err = fill_vq(hwsim_vqs[HWSIM_VQ_RX]);
        if (err)
                goto out_remove;
index c02be4a..7db627f 100644 (file)
@@ -1233,9 +1233,6 @@ struct rtw_chip_info {
        const struct wiphy_wowlan_support *wowlan_stub;
        const u8 max_sched_scan_ssids;
 
-       /* for 8821c set channel */
-       u32 ch_param[3];
-
        /* coex paras */
        u32 coex_para_ver;
        u8 bt_desired_ver;
@@ -1937,6 +1934,9 @@ struct rtw_hal {
 
        enum rtw_sar_bands sar_band;
        struct rtw_sar sar;
+
+       /* for 8821c set channel */
+       u32 ch_param[3];
 };
 
 struct rtw_path_div {
index ffee39e..488a7dd 100644 (file)
@@ -125,6 +125,7 @@ static void rtw8821c_phy_bf_init(struct rtw_dev *rtwdev)
 
 static void rtw8821c_phy_set_param(struct rtw_dev *rtwdev)
 {
+       struct rtw_hal *hal = &rtwdev->hal;
        u8 crystal_cap, val;
 
        /* power on BB/RF domain */
@@ -159,9 +160,9 @@ static void rtw8821c_phy_set_param(struct rtw_dev *rtwdev)
 
        /* post init after header files config */
        rtw_write32_set(rtwdev, REG_RXPSEL, BIT_RX_PSEL_RST);
-       rtwdev->chip->ch_param[0] = rtw_read32_mask(rtwdev, REG_TXSF2, MASKDWORD);
-       rtwdev->chip->ch_param[1] = rtw_read32_mask(rtwdev, REG_TXSF6, MASKDWORD);
-       rtwdev->chip->ch_param[2] = rtw_read32_mask(rtwdev, REG_TXFILTER, MASKDWORD);
+       hal->ch_param[0] = rtw_read32_mask(rtwdev, REG_TXSF2, MASKDWORD);
+       hal->ch_param[1] = rtw_read32_mask(rtwdev, REG_TXSF6, MASKDWORD);
+       hal->ch_param[2] = rtw_read32_mask(rtwdev, REG_TXFILTER, MASKDWORD);
 
        rtw_phy_init(rtwdev);
        rtwdev->dm_info.cck_pd_default = rtw_read8(rtwdev, REG_CSRATIO) & 0x1f;
@@ -351,6 +352,7 @@ static void rtw8821c_set_channel_rxdfir(struct rtw_dev *rtwdev, u8 bw)
 static void rtw8821c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw,
                                    u8 primary_ch_idx)
 {
+       struct rtw_hal *hal = &rtwdev->hal;
        u32 val32;
 
        if (channel <= 14) {
@@ -367,11 +369,11 @@ static void rtw8821c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw,
                        rtw_write32_mask(rtwdev, REG_TXFILTER, MASKDWORD, 0x00003667);
                } else {
                        rtw_write32_mask(rtwdev, REG_TXSF2, MASKDWORD,
-                                        rtwdev->chip->ch_param[0]);
+                                        hal->ch_param[0]);
                        rtw_write32_mask(rtwdev, REG_TXSF6, MASKLWORD,
-                                        rtwdev->chip->ch_param[1] & MASKLWORD);
+                                        hal->ch_param[1] & MASKLWORD);
                        rtw_write32_mask(rtwdev, REG_TXFILTER, MASKDWORD,
-                                        rtwdev->chip->ch_param[2]);
+                                        hal->ch_param[2]);
                }
        } else if (channel > 35) {
                rtw_write32_mask(rtwdev, REG_ENTXCCK, BIT(18), 0x1);
index dbac4c0..a033540 100644 (file)
@@ -495,6 +495,7 @@ void xenvif_rx_action(struct xenvif_queue *queue)
        queue->rx_copy.completed = &completed_skbs;
 
        while (xenvif_rx_ring_slots_available(queue) &&
+              !skb_queue_empty(&queue->rx_queue) &&
               work_done < RX_BATCH_SIZE) {
                xenvif_rx_skb(queue);
                work_done++;
index 8c0b954..2409007 100644 (file)
@@ -66,6 +66,10 @@ module_param_named(max_queues, xennet_max_queues, uint, 0644);
 MODULE_PARM_DESC(max_queues,
                 "Maximum number of queues per virtual interface");
 
+static bool __read_mostly xennet_trusted = true;
+module_param_named(trusted, xennet_trusted, bool, 0644);
+MODULE_PARM_DESC(trusted, "Is the backend trusted");
+
 #define XENNET_TIMEOUT  (5 * HZ)
 
 static const struct ethtool_ops xennet_ethtool_ops;
@@ -173,6 +177,9 @@ struct netfront_info {
        /* Is device behaving sane? */
        bool broken;
 
+       /* Should skbs be bounced into a zeroed buffer? */
+       bool bounce;
+
        atomic_t rx_gso_checksum_fixup;
 };
 
@@ -271,7 +278,8 @@ static struct sk_buff *xennet_alloc_one_rx_buffer(struct netfront_queue *queue)
        if (unlikely(!skb))
                return NULL;
 
-       page = page_pool_dev_alloc_pages(queue->page_pool);
+       page = page_pool_alloc_pages(queue->page_pool,
+                                    GFP_ATOMIC | __GFP_NOWARN | __GFP_ZERO);
        if (unlikely(!page)) {
                kfree_skb(skb);
                return NULL;
@@ -665,6 +673,33 @@ static int xennet_xdp_xmit(struct net_device *dev, int n,
        return nxmit;
 }
 
+struct sk_buff *bounce_skb(const struct sk_buff *skb)
+{
+       unsigned int headerlen = skb_headroom(skb);
+       /* Align size to allocate full pages and avoid contiguous data leaks */
+       unsigned int size = ALIGN(skb_end_offset(skb) + skb->data_len,
+                                 XEN_PAGE_SIZE);
+       struct sk_buff *n = alloc_skb(size, GFP_ATOMIC | __GFP_ZERO);
+
+       if (!n)
+               return NULL;
+
+       if (!IS_ALIGNED((uintptr_t)n->head, XEN_PAGE_SIZE)) {
+               WARN_ONCE(1, "misaligned skb allocated\n");
+               kfree_skb(n);
+               return NULL;
+       }
+
+       /* Set the data pointer */
+       skb_reserve(n, headerlen);
+       /* Set the tail pointer and length */
+       skb_put(n, skb->len);
+
+       BUG_ON(skb_copy_bits(skb, -headerlen, n->head, headerlen + skb->len));
+
+       skb_copy_header(n, skb);
+       return n;
+}
 
 #define MAX_XEN_SKB_FRAGS (65536 / XEN_PAGE_SIZE + 1)
 
@@ -718,9 +753,13 @@ static netdev_tx_t xennet_start_xmit(struct sk_buff *skb, struct net_device *dev
 
        /* The first req should be at least ETH_HLEN size or the packet will be
         * dropped by netback.
+        *
+        * If the backend is not trusted bounce all data to zeroed pages to
+        * avoid exposing contiguous data on the granted page not belonging to
+        * the skb.
         */
-       if (unlikely(PAGE_SIZE - offset < ETH_HLEN)) {
-               nskb = skb_copy(skb, GFP_ATOMIC);
+       if (np->bounce || unlikely(PAGE_SIZE - offset < ETH_HLEN)) {
+               nskb = bounce_skb(skb);
                if (!nskb)
                        goto drop;
                dev_consume_skb_any(skb);
@@ -1053,8 +1092,10 @@ static int xennet_get_responses(struct netfront_queue *queue,
                        }
                }
                rcu_read_unlock();
-next:
+
                __skb_queue_tail(list, skb);
+
+next:
                if (!(rx->flags & XEN_NETRXF_more_data))
                        break;
 
@@ -2214,6 +2255,10 @@ static int talk_to_netback(struct xenbus_device *dev,
 
        info->netdev->irq = 0;
 
+       /* Check if backend is trusted. */
+       info->bounce = !xennet_trusted ||
+                      !xenbus_read_unsigned(dev->nodename, "trusted", 1);
+
        /* Check if backend supports multiple queues */
        max_queues = xenbus_read_unsigned(info->xbdev->otherend,
                                          "multi-queue-max-queues", 1);
@@ -2381,6 +2426,9 @@ static int xennet_connect(struct net_device *dev)
                return err;
        if (np->netback_has_xdp_headroom)
                pr_info("backend supports XDP headroom\n");
+       if (np->bounce)
+               dev_info(&np->xbdev->dev,
+                        "bouncing transmitted data to zeroed pages\n");
 
        /* talk_to_netback() sets the correct number of queues */
        num_queues = dev->real_num_tx_queues;
index ceef81d..01329b9 100644 (file)
@@ -167,9 +167,9 @@ static int nfcmrvl_i2c_parse_dt(struct device_node *node,
                pdata->irq_polarity = IRQF_TRIGGER_RISING;
 
        ret = irq_of_parse_and_map(node, 0);
-       if (ret < 0) {
-               pr_err("Unable to get irq, error: %d\n", ret);
-               return ret;
+       if (!ret) {
+               pr_err("Unable to get irq\n");
+               return -EINVAL;
        }
        pdata->irq = ret;
 
index a38e2fc..ad3359a 100644 (file)
@@ -115,9 +115,9 @@ static int nfcmrvl_spi_parse_dt(struct device_node *node,
        }
 
        ret = irq_of_parse_and_map(node, 0);
-       if (ret < 0) {
-               pr_err("Unable to get irq, error: %d\n", ret);
-               return ret;
+       if (!ret) {
+               pr_err("Unable to get irq\n");
+               return -EINVAL;
        }
        pdata->irq = ret;
 
index 7e451c1..ae2ba08 100644 (file)
@@ -122,7 +122,9 @@ static int nxp_nci_i2c_fw_read(struct nxp_nci_i2c_phy *phy,
        skb_put_data(*skb, &header, NXP_NCI_FW_HDR_LEN);
 
        r = i2c_master_recv(client, skb_put(*skb, frame_len), frame_len);
-       if (r != frame_len) {
+       if (r < 0) {
+               goto fw_read_exit_free_skb;
+       } else if (r != frame_len) {
                nfc_err(&client->dev,
                        "Invalid frame length: %u (expected %zu)\n",
                        r, frame_len);
@@ -162,8 +164,13 @@ static int nxp_nci_i2c_nci_read(struct nxp_nci_i2c_phy *phy,
 
        skb_put_data(*skb, (void *)&header, NCI_CTRL_HDR_SIZE);
 
+       if (!header.plen)
+               return 0;
+
        r = i2c_master_recv(client, skb_put(*skb, header.plen), header.plen);
-       if (r != header.plen) {
+       if (r < 0) {
+               goto nci_read_exit_free_skb;
+       } else if (r != header.plen) {
                nfc_err(&client->dev,
                        "Invalid frame payload length: %u (expected %u)\n",
                        r, header.plen);
index 9613e54..0297b78 100644 (file)
@@ -1422,7 +1422,7 @@ static int btt_write_pg(struct btt *btt, struct bio_integrity_payload *bip,
 
 static int btt_do_bvec(struct btt *btt, struct bio_integrity_payload *bip,
                        struct page *page, unsigned int len, unsigned int off,
-                       unsigned int op, sector_t sector)
+                       enum req_op op, sector_t sector)
 {
        int ret;
 
@@ -1483,7 +1483,7 @@ static void btt_submit_bio(struct bio *bio)
 }
 
 static int btt_rw_page(struct block_device *bdev, sector_t sector,
-               struct page *page, unsigned int op)
+               struct page *page, enum req_op op)
 {
        struct btt *btt = bdev->bd_disk->private_data;
        int rc;
@@ -1548,14 +1548,14 @@ static int btt_blk_init(struct btt *btt)
        return 0;
 
 out_cleanup_disk:
-       blk_cleanup_disk(btt->btt_disk);
+       put_disk(btt->btt_disk);
        return rc;
 }
 
 static void btt_blk_cleanup(struct btt *btt)
 {
        del_gendisk(btt->btt_disk);
-       blk_cleanup_disk(btt->btt_disk);
+       put_disk(btt->btt_disk);
 }
 
 /**
index a4fc17d..b38d035 100644 (file)
@@ -176,8 +176,8 @@ static int nvdimm_clear_badblocks_region(struct device *dev, void *data)
        ndr_end = nd_region->ndr_start + nd_region->ndr_size - 1;
 
        /* make sure we are in the region */
-       if (ctx->phys < nd_region->ndr_start
-                       || (ctx->phys + ctx->cleared) > ndr_end)
+       if (ctx->phys < nd_region->ndr_start ||
+           (ctx->phys + ctx->cleared - 1) > ndr_end)
                return 0;
 
        sector = (ctx->phys - nd_region->ndr_start) / 512;
index 629d10f..f36efcc 100644 (file)
@@ -239,7 +239,7 @@ static void pmem_submit_bio(struct bio *bio)
 }
 
 static int pmem_rw_page(struct block_device *bdev, sector_t sector,
-                      struct page *page, unsigned int op)
+                      struct page *page, enum req_op op)
 {
        struct pmem_device *pmem = bdev->bd_disk->private_data;
        blk_status_t rc;
@@ -450,7 +450,7 @@ static void pmem_release_disk(void *__pmem)
        put_dax(pmem->dax_dev);
        del_gendisk(pmem->disk);
 
-       blk_cleanup_disk(pmem->disk);
+       put_disk(pmem->disk);
 }
 
 static int pmem_attach_disk(struct device *dev,
@@ -596,7 +596,7 @@ out_cleanup_dax:
        kill_dax(pmem->dax_dev);
        put_dax(pmem->dax_dev);
 out:
-       blk_cleanup_disk(pmem->disk);
+       put_disk(pmem->disk);
        return rc;
 }
 
index d702d7d..5c352d5 100644 (file)
@@ -862,8 +862,7 @@ static void apple_nvme_disable(struct apple_nvme *anv, bool shutdown)
        }
 }
 
-static enum blk_eh_timer_return apple_nvme_timeout(struct request *req,
-                                                  bool reserved)
+static enum blk_eh_timer_return apple_nvme_timeout(struct request *req)
 {
        struct apple_nvme_iod *iod = blk_mq_rq_to_pdu(req);
        struct apple_nvme_queue *q = iod->q;
@@ -1502,7 +1501,7 @@ static int apple_nvme_probe(struct platform_device *pdev)
 
        if (!blk_get_queue(anv->ctrl.admin_q)) {
                nvme_start_admin_queue(&anv->ctrl);
-               blk_cleanup_queue(anv->ctrl.admin_q);
+               blk_mq_destroy_queue(anv->ctrl.admin_q);
                anv->ctrl.admin_q = NULL;
                ret = -ENODEV;
                goto put_dev;
index b3d9c29..2533b88 100644 (file)
@@ -418,7 +418,7 @@ blk_status_t nvme_host_path_error(struct request *req)
 }
 EXPORT_SYMBOL_GPL(nvme_host_path_error);
 
-bool nvme_cancel_request(struct request *req, void *data, bool reserved)
+bool nvme_cancel_request(struct request *req, void *data)
 {
        dev_dbg_ratelimited(((struct nvme_ctrl *) data)->device,
                                "Cancelling I/O %d", req->tag);
@@ -3786,7 +3786,7 @@ static int nvme_add_ns_cdev(struct nvme_ns *ns)
 }
 
 static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ctrl *ctrl,
-               unsigned nsid, struct nvme_ns_ids *ids)
+               unsigned nsid, struct nvme_ns_ids *ids, bool is_shared)
 {
        struct nvme_ns_head *head;
        size_t size = sizeof(*head);
@@ -3810,6 +3810,7 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ctrl *ctrl,
        head->subsys = ctrl->subsys;
        head->ns_id = nsid;
        head->ids = *ids;
+       head->shared = is_shared;
        kref_init(&head->ref);
 
        if (head->ids.csi) {
@@ -3891,12 +3892,11 @@ static int nvme_init_ns_head(struct nvme_ns *ns, unsigned nsid,
                                nsid);
                        goto out_unlock;
                }
-               head = nvme_alloc_ns_head(ctrl, nsid, ids);
+               head = nvme_alloc_ns_head(ctrl, nsid, ids, is_shared);
                if (IS_ERR(head)) {
                        ret = PTR_ERR(head);
                        goto out_unlock;
                }
-               head->shared = is_shared;
        } else {
                ret = -EINVAL;
                if (!is_shared || !head->shared) {
@@ -4061,7 +4061,7 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid,
        mutex_unlock(&ctrl->subsys->lock);
        nvme_put_ns_head(ns->head);
  out_cleanup_disk:
-       blk_cleanup_disk(disk);
+       put_disk(disk);
  out_free_ns:
        kfree(ns);
  out_free_id:
@@ -4103,7 +4103,6 @@ static void nvme_ns_remove(struct nvme_ns *ns)
        if (!nvme_ns_head_multipath(ns->head))
                nvme_cdev_del(&ns->cdev, &ns->cdev_device);
        del_gendisk(ns->disk);
-       blk_cleanup_queue(ns->queue);
 
        down_write(&ns->ctrl->namespaces_rwsem);
        list_del_init(&ns->list);
@@ -4595,6 +4594,8 @@ void nvme_stop_ctrl(struct nvme_ctrl *ctrl)
        nvme_stop_failfast_work(ctrl);
        flush_work(&ctrl->async_event_work);
        cancel_work_sync(&ctrl->fw_act_work);
+       if (ctrl->ops->stop_ctrl)
+               ctrl->ops->stop_ctrl(ctrl);
 }
 EXPORT_SYMBOL_GPL(nvme_stop_ctrl);
 
index 3c778bb..9987797 100644 (file)
@@ -2392,7 +2392,7 @@ nvme_fc_ctrl_free(struct kref *ref)
        unsigned long flags;
 
        if (ctrl->ctrl.tagset) {
-               blk_cleanup_queue(ctrl->ctrl.connect_q);
+               blk_mq_destroy_queue(ctrl->ctrl.connect_q);
                blk_mq_free_tag_set(&ctrl->tag_set);
        }
 
@@ -2402,8 +2402,8 @@ nvme_fc_ctrl_free(struct kref *ref)
        spin_unlock_irqrestore(&ctrl->rport->lock, flags);
 
        nvme_start_admin_queue(&ctrl->ctrl);
-       blk_cleanup_queue(ctrl->ctrl.admin_q);
-       blk_cleanup_queue(ctrl->ctrl.fabrics_q);
+       blk_mq_destroy_queue(ctrl->ctrl.admin_q);
+       blk_mq_destroy_queue(ctrl->ctrl.fabrics_q);
        blk_mq_free_tag_set(&ctrl->admin_tag_set);
 
        kfree(ctrl->queues);
@@ -2456,8 +2456,7 @@ nvme_fc_nvme_ctrl_freed(struct nvme_ctrl *nctrl)
  * status. The done path will return the io request back to the block
  * layer with an error status.
  */
-static bool
-nvme_fc_terminate_exchange(struct request *req, void *data, bool reserved)
+static bool nvme_fc_terminate_exchange(struct request *req, void *data)
 {
        struct nvme_ctrl *nctrl = data;
        struct nvme_fc_ctrl *ctrl = to_fc_ctrl(nctrl);
@@ -2565,8 +2564,7 @@ nvme_fc_error_recovery(struct nvme_fc_ctrl *ctrl, char *errmsg)
        nvme_reset_ctrl(&ctrl->ctrl);
 }
 
-static enum blk_eh_timer_return
-nvme_fc_timeout(struct request *rq, bool reserved)
+static enum blk_eh_timer_return nvme_fc_timeout(struct request *rq)
 {
        struct nvme_fc_fcp_op *op = blk_mq_rq_to_pdu(rq);
        struct nvme_fc_ctrl *ctrl = op->ctrl;
@@ -2953,7 +2951,7 @@ nvme_fc_create_io_queues(struct nvme_fc_ctrl *ctrl)
 out_delete_hw_queues:
        nvme_fc_delete_hw_io_queues(ctrl);
 out_cleanup_blk_queue:
-       blk_cleanup_queue(ctrl->ctrl.connect_q);
+       blk_mq_destroy_queue(ctrl->ctrl.connect_q);
 out_free_tag_set:
        blk_mq_free_tag_set(&ctrl->tag_set);
        nvme_fc_free_io_queues(ctrl);
@@ -3642,9 +3640,9 @@ fail_ctrl:
        return ERR_PTR(-EIO);
 
 out_cleanup_admin_q:
-       blk_cleanup_queue(ctrl->ctrl.admin_q);
+       blk_mq_destroy_queue(ctrl->ctrl.admin_q);
 out_cleanup_fabrics_q:
-       blk_cleanup_queue(ctrl->ctrl.fabrics_q);
+       blk_mq_destroy_queue(ctrl->ctrl.fabrics_q);
 out_free_admin_tag_set:
        blk_mq_free_tag_set(&ctrl->admin_tag_set);
 out_free_queues:
index a2e89db..27614be 100644 (file)
@@ -68,7 +68,7 @@ static struct request *nvme_alloc_user_request(struct request_queue *q,
                struct nvme_command *cmd, void __user *ubuffer,
                unsigned bufflen, void __user *meta_buffer, unsigned meta_len,
                u32 meta_seed, void **metap, unsigned timeout, bool vec,
-               unsigned int rq_flags, blk_mq_req_flags_t blk_flags)
+               blk_opf_t rq_flags, blk_mq_req_flags_t blk_flags)
 {
        bool write = nvme_is_write(cmd);
        struct nvme_ns *ns = q->queuedata;
@@ -407,7 +407,7 @@ static int nvme_uring_cmd_io(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
        struct nvme_uring_data d;
        struct nvme_command c;
        struct request *req;
-       unsigned int rq_flags = 0;
+       blk_opf_t rq_flags = 0;
        blk_mq_req_flags_t blk_flags = 0;
        void *meta = NULL;
 
index d3e2440..f26640c 100644 (file)
@@ -830,7 +830,7 @@ void nvme_mpath_add_disk(struct nvme_ns *ns, struct nvme_id_ns *id)
                                   ns->head->disk->queue);
 #ifdef CONFIG_BLK_DEV_ZONED
        if (blk_queue_is_zoned(ns->queue) && ns->head->disk)
-               ns->head->disk->queue->nr_zones = ns->queue->nr_zones;
+               ns->head->disk->nr_zones = ns->disk->nr_zones;
 #endif
 }
 
@@ -853,7 +853,7 @@ void nvme_mpath_remove_disk(struct nvme_ns_head *head)
        /* make sure all pending bios are cleaned up */
        kblockd_schedule_work(&head->requeue_work);
        flush_work(&head->requeue_work);
-       blk_cleanup_disk(head->disk);
+       put_disk(head->disk);
 }
 
 void nvme_mpath_init_ctrl(struct nvme_ctrl *ctrl)
index 0da94b2..7e0a925 100644 (file)
@@ -502,6 +502,7 @@ struct nvme_ctrl_ops {
        void (*free_ctrl)(struct nvme_ctrl *ctrl);
        void (*submit_async_event)(struct nvme_ctrl *ctrl);
        void (*delete_ctrl)(struct nvme_ctrl *ctrl);
+       void (*stop_ctrl)(struct nvme_ctrl *ctrl);
        int (*get_address)(struct nvme_ctrl *ctrl, char *buf, int size);
        void (*print_device_info)(struct nvme_ctrl *ctrl);
 };
@@ -697,7 +698,7 @@ static __always_inline void nvme_complete_batch(struct io_comp_batch *iob,
 }
 
 blk_status_t nvme_host_path_error(struct request *req);
-bool nvme_cancel_request(struct request *req, void *data, bool reserved);
+bool nvme_cancel_request(struct request *req, void *data);
 void nvme_cancel_tagset(struct nvme_ctrl *ctrl);
 void nvme_cancel_admin_tagset(struct nvme_ctrl *ctrl);
 bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
@@ -733,7 +734,7 @@ void nvme_wait_freeze(struct nvme_ctrl *ctrl);
 int nvme_wait_freeze_timeout(struct nvme_ctrl *ctrl, long timeout);
 void nvme_start_freeze(struct nvme_ctrl *ctrl);
 
-static inline unsigned int nvme_req_op(struct nvme_command *cmd)
+static inline enum req_op nvme_req_op(struct nvme_command *cmd)
 {
        return nvme_is_write(cmd) ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN;
 }
index d7b24ee..7e7d480 100644 (file)
@@ -1344,7 +1344,7 @@ static void nvme_warn_reset(struct nvme_dev *dev, u32 csts)
                 "Try \"nvme_core.default_ps_max_latency_us=0 pcie_aspm=off\" and report a bug\n");
 }
 
-static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved)
+static enum blk_eh_timer_return nvme_timeout(struct request *req)
 {
        struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
        struct nvme_queue *nvmeq = iod->nvmeq;
@@ -1760,7 +1760,7 @@ static void nvme_dev_remove_admin(struct nvme_dev *dev)
                 * queue to flush these to completion.
                 */
                nvme_start_admin_queue(&dev->ctrl);
-               blk_cleanup_queue(dev->ctrl.admin_q);
+               blk_mq_destroy_queue(dev->ctrl.admin_q);
                blk_mq_free_tag_set(&dev->admin_tagset);
        }
 }
@@ -2690,8 +2690,13 @@ static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown)
        struct pci_dev *pdev = to_pci_dev(dev->dev);
 
        mutex_lock(&dev->shutdown_lock);
-       if (pci_device_is_present(pdev) && pci_is_enabled(pdev)) {
-               u32 csts = readl(dev->bar + NVME_REG_CSTS);
+       if (pci_is_enabled(pdev)) {
+               u32 csts;
+
+               if (pci_device_is_present(pdev))
+                       csts = readl(dev->bar + NVME_REG_CSTS);
+               else
+                       csts = ~0;
 
                if (dev->ctrl.state == NVME_CTRL_LIVE ||
                    dev->ctrl.state == NVME_CTRL_RESETTING) {
@@ -3465,12 +3470,16 @@ static const struct pci_device_id nvme_id_table[] = {
        { PCI_DEVICE(0x1987, 0x5012),   /* Phison E12 */
                .driver_data = NVME_QUIRK_BOGUS_NID, },
        { PCI_DEVICE(0x1987, 0x5016),   /* Phison E16 */
-               .driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN, },
+               .driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN |
+                               NVME_QUIRK_BOGUS_NID, },
        { PCI_DEVICE(0x1b4b, 0x1092),   /* Lexar 256 GB SSD */
                .driver_data = NVME_QUIRK_NO_NS_DESC_LIST |
                                NVME_QUIRK_IGNORE_DEV_SUBNQN, },
+       { PCI_DEVICE(0x1cc1, 0x33f8),   /* ADATA IM2P33F8ABR1 1 TB */
+               .driver_data = NVME_QUIRK_BOGUS_NID, },
        { PCI_DEVICE(0x10ec, 0x5762),   /* ADATA SX6000LNP */
-               .driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN, },
+               .driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN |
+                               NVME_QUIRK_BOGUS_NID, },
        { PCI_DEVICE(0x1cc1, 0x8201),   /* ADATA SX8200PNP 512GB */
                .driver_data = NVME_QUIRK_NO_DEEPEST_PS |
                                NVME_QUIRK_IGNORE_DEV_SUBNQN, },
@@ -3506,6 +3515,8 @@ static const struct pci_device_id nvme_id_table[] = {
                .driver_data = NVME_QUIRK_BOGUS_NID, },
        { PCI_DEVICE(0x1e49, 0x0041),   /* ZHITAI TiPro7000 NVMe SSD */
                .driver_data = NVME_QUIRK_NO_DEEPEST_PS, },
+       { PCI_DEVICE(0xc0a9, 0x540a),   /* Crucial P2 */
+               .driver_data = NVME_QUIRK_BOGUS_NID, },
        { PCI_DEVICE(PCI_VENDOR_ID_AMAZON, 0x0061),
                .driver_data = NVME_QUIRK_DMA_ADDRESS_BITS_48, },
        { PCI_DEVICE(PCI_VENDOR_ID_AMAZON, 0x0065),
index f2a5e1e..4665aeb 100644 (file)
@@ -840,8 +840,8 @@ static void nvme_rdma_destroy_admin_queue(struct nvme_rdma_ctrl *ctrl,
                bool remove)
 {
        if (remove) {
-               blk_cleanup_queue(ctrl->ctrl.admin_q);
-               blk_cleanup_queue(ctrl->ctrl.fabrics_q);
+               blk_mq_destroy_queue(ctrl->ctrl.admin_q);
+               blk_mq_destroy_queue(ctrl->ctrl.fabrics_q);
                blk_mq_free_tag_set(ctrl->ctrl.admin_tagset);
        }
        if (ctrl->async_event_sqe.data) {
@@ -935,10 +935,10 @@ out_stop_queue:
        nvme_cancel_admin_tagset(&ctrl->ctrl);
 out_cleanup_queue:
        if (new)
-               blk_cleanup_queue(ctrl->ctrl.admin_q);
+               blk_mq_destroy_queue(ctrl->ctrl.admin_q);
 out_cleanup_fabrics_q:
        if (new)
-               blk_cleanup_queue(ctrl->ctrl.fabrics_q);
+               blk_mq_destroy_queue(ctrl->ctrl.fabrics_q);
 out_free_tagset:
        if (new)
                blk_mq_free_tag_set(ctrl->ctrl.admin_tagset);
@@ -957,7 +957,7 @@ static void nvme_rdma_destroy_io_queues(struct nvme_rdma_ctrl *ctrl,
                bool remove)
 {
        if (remove) {
-               blk_cleanup_queue(ctrl->ctrl.connect_q);
+               blk_mq_destroy_queue(ctrl->ctrl.connect_q);
                blk_mq_free_tag_set(ctrl->ctrl.tagset);
        }
        nvme_rdma_free_io_queues(ctrl);
@@ -1012,7 +1012,7 @@ out_wait_freeze_timed_out:
 out_cleanup_connect_q:
        nvme_cancel_tagset(&ctrl->ctrl);
        if (new)
-               blk_cleanup_queue(ctrl->ctrl.connect_q);
+               blk_mq_destroy_queue(ctrl->ctrl.connect_q);
 out_free_tag_set:
        if (new)
                blk_mq_free_tag_set(ctrl->ctrl.tagset);
@@ -1048,6 +1048,14 @@ static void nvme_rdma_teardown_io_queues(struct nvme_rdma_ctrl *ctrl,
        }
 }
 
+static void nvme_rdma_stop_ctrl(struct nvme_ctrl *nctrl)
+{
+       struct nvme_rdma_ctrl *ctrl = to_rdma_ctrl(nctrl);
+
+       cancel_work_sync(&ctrl->err_work);
+       cancel_delayed_work_sync(&ctrl->reconnect_work);
+}
+
 static void nvme_rdma_free_ctrl(struct nvme_ctrl *nctrl)
 {
        struct nvme_rdma_ctrl *ctrl = to_rdma_ctrl(nctrl);
@@ -2013,8 +2021,7 @@ static void nvme_rdma_complete_timed_out(struct request *rq)
        nvmf_complete_timed_out_request(rq);
 }
 
-static enum blk_eh_timer_return
-nvme_rdma_timeout(struct request *rq, bool reserved)
+static enum blk_eh_timer_return nvme_rdma_timeout(struct request *rq)
 {
        struct nvme_rdma_request *req = blk_mq_rq_to_pdu(rq);
        struct nvme_rdma_queue *queue = req->queue;
@@ -2252,9 +2259,6 @@ static const struct blk_mq_ops nvme_rdma_admin_mq_ops = {
 
 static void nvme_rdma_shutdown_ctrl(struct nvme_rdma_ctrl *ctrl, bool shutdown)
 {
-       cancel_work_sync(&ctrl->err_work);
-       cancel_delayed_work_sync(&ctrl->reconnect_work);
-
        nvme_rdma_teardown_io_queues(ctrl, shutdown);
        nvme_stop_admin_queue(&ctrl->ctrl);
        if (shutdown)
@@ -2304,6 +2308,7 @@ static const struct nvme_ctrl_ops nvme_rdma_ctrl_ops = {
        .submit_async_event     = nvme_rdma_submit_async_event,
        .delete_ctrl            = nvme_rdma_delete_ctrl,
        .get_address            = nvmf_get_address,
+       .stop_ctrl              = nvme_rdma_stop_ctrl,
 };
 
 /*
index bb67538..b95ee85 100644 (file)
@@ -1180,8 +1180,7 @@ done:
        } else if (ret < 0) {
                dev_err(queue->ctrl->ctrl.device,
                        "failed to send request %d\n", ret);
-               if (ret != -EPIPE && ret != -ECONNRESET)
-                       nvme_tcp_fail_request(queue->request);
+               nvme_tcp_fail_request(queue->request);
                nvme_tcp_done_send_req(queue);
        }
        return ret;
@@ -1885,7 +1884,7 @@ static void nvme_tcp_destroy_io_queues(struct nvme_ctrl *ctrl, bool remove)
 {
        nvme_tcp_stop_io_queues(ctrl);
        if (remove) {
-               blk_cleanup_queue(ctrl->connect_q);
+               blk_mq_destroy_queue(ctrl->connect_q);
                blk_mq_free_tag_set(ctrl->tagset);
        }
        nvme_tcp_free_io_queues(ctrl);
@@ -1940,7 +1939,7 @@ out_wait_freeze_timed_out:
 out_cleanup_connect_q:
        nvme_cancel_tagset(ctrl);
        if (new)
-               blk_cleanup_queue(ctrl->connect_q);
+               blk_mq_destroy_queue(ctrl->connect_q);
 out_free_tag_set:
        if (new)
                blk_mq_free_tag_set(ctrl->tagset);
@@ -1953,8 +1952,8 @@ static void nvme_tcp_destroy_admin_queue(struct nvme_ctrl *ctrl, bool remove)
 {
        nvme_tcp_stop_queue(ctrl, 0);
        if (remove) {
-               blk_cleanup_queue(ctrl->admin_q);
-               blk_cleanup_queue(ctrl->fabrics_q);
+               blk_mq_destroy_queue(ctrl->admin_q);
+               blk_mq_destroy_queue(ctrl->fabrics_q);
                blk_mq_free_tag_set(ctrl->admin_tagset);
        }
        nvme_tcp_free_admin_queue(ctrl);
@@ -2012,10 +2011,10 @@ out_stop_queue:
        nvme_cancel_admin_tagset(ctrl);
 out_cleanup_queue:
        if (new)
-               blk_cleanup_queue(ctrl->admin_q);
+               blk_mq_destroy_queue(ctrl->admin_q);
 out_cleanup_fabrics_q:
        if (new)
-               blk_cleanup_queue(ctrl->fabrics_q);
+               blk_mq_destroy_queue(ctrl->fabrics_q);
 out_free_tagset:
        if (new)
                blk_mq_free_tag_set(ctrl->admin_tagset);
@@ -2194,9 +2193,6 @@ static void nvme_tcp_error_recovery_work(struct work_struct *work)
 
 static void nvme_tcp_teardown_ctrl(struct nvme_ctrl *ctrl, bool shutdown)
 {
-       cancel_work_sync(&to_tcp_ctrl(ctrl)->err_work);
-       cancel_delayed_work_sync(&to_tcp_ctrl(ctrl)->connect_work);
-
        nvme_tcp_teardown_io_queues(ctrl, shutdown);
        nvme_stop_admin_queue(ctrl);
        if (shutdown)
@@ -2236,6 +2232,12 @@ out_fail:
        nvme_tcp_reconnect_or_remove(ctrl);
 }
 
+static void nvme_tcp_stop_ctrl(struct nvme_ctrl *ctrl)
+{
+       cancel_work_sync(&to_tcp_ctrl(ctrl)->err_work);
+       cancel_delayed_work_sync(&to_tcp_ctrl(ctrl)->connect_work);
+}
+
 static void nvme_tcp_free_ctrl(struct nvme_ctrl *nctrl)
 {
        struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl);
@@ -2321,8 +2323,7 @@ static void nvme_tcp_complete_timed_out(struct request *rq)
        nvmf_complete_timed_out_request(rq);
 }
 
-static enum blk_eh_timer_return
-nvme_tcp_timeout(struct request *rq, bool reserved)
+static enum blk_eh_timer_return nvme_tcp_timeout(struct request *rq)
 {
        struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq);
        struct nvme_ctrl *ctrl = &req->queue->ctrl->ctrl;
@@ -2557,6 +2558,7 @@ static const struct nvme_ctrl_ops nvme_tcp_ctrl_ops = {
        .submit_async_event     = nvme_tcp_submit_async_event,
        .delete_ctrl            = nvme_tcp_delete_ctrl,
        .get_address            = nvmf_get_address,
+       .stop_ctrl              = nvme_tcp_stop_ctrl,
 };
 
 static bool
index b5f8525..37c7f4c 100644 (file)
@@ -69,7 +69,7 @@ TRACE_EVENT(nvme_setup_cmd,
                __entry->metadata = !!blk_integrity_rq(req);
                __entry->fctype = cmd->fabrics.fctype;
                __assign_disk_name(__entry->disk, req->q->disk);
-               memcpy(__entry->cdw10, &cmd->common.cdw10,
+               memcpy(__entry->cdw10, &cmd->common.cdws,
                        sizeof(__entry->cdw10));
            ),
            TP_printk("nvme%d: %sqid=%d, cmdid=%u, nsid=%u, flags=0x%x, meta=0x%x, cmd=(%s %s)",
index 9f81beb..12316ab 100644 (file)
@@ -109,10 +109,10 @@ int nvme_update_zone_info(struct nvme_ns *ns, unsigned lbaf)
                goto free_data;
        }
 
-       blk_queue_set_zoned(ns->disk, BLK_ZONED_HM);
+       disk_set_zoned(ns->disk, BLK_ZONED_HM);
        blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, q);
-       blk_queue_max_open_zones(q, le32_to_cpu(id->mor) + 1);
-       blk_queue_max_active_zones(q, le32_to_cpu(id->mar) + 1);
+       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);
 free_data:
        kfree(id);
        return status;
index e44b298..ff77c3d 100644 (file)
@@ -773,11 +773,31 @@ static ssize_t nvmet_passthru_io_timeout_store(struct config_item *item,
 }
 CONFIGFS_ATTR(nvmet_passthru_, io_timeout);
 
+static ssize_t nvmet_passthru_clear_ids_show(struct config_item *item,
+               char *page)
+{
+       return sprintf(page, "%u\n", to_subsys(item->ci_parent)->clear_ids);
+}
+
+static ssize_t nvmet_passthru_clear_ids_store(struct config_item *item,
+               const char *page, size_t count)
+{
+       struct nvmet_subsys *subsys = to_subsys(item->ci_parent);
+       unsigned int clear_ids;
+
+       if (kstrtouint(page, 0, &clear_ids))
+               return -EINVAL;
+       subsys->clear_ids = clear_ids;
+       return count;
+}
+CONFIGFS_ATTR(nvmet_passthru_, clear_ids);
+
 static struct configfs_attribute *nvmet_passthru_attrs[] = {
        &nvmet_passthru_attr_device_path,
        &nvmet_passthru_attr_enable,
        &nvmet_passthru_attr_admin_timeout,
        &nvmet_passthru_attr_io_timeout,
+       &nvmet_passthru_attr_clear_ids,
        NULL,
 };
 
index 90e7532..c27660a 100644 (file)
@@ -1374,6 +1374,12 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn,
        ctrl->port = req->port;
        ctrl->ops = req->ops;
 
+#ifdef CONFIG_NVME_TARGET_PASSTHRU
+       /* By default, set loop targets to clear IDS by default */
+       if (ctrl->port->disc_addr.trtype == NVMF_TRTYPE_LOOP)
+               subsys->clear_ids = 1;
+#endif
+
        INIT_WORK(&ctrl->async_event_work, nvmet_async_event_work);
        INIT_LIST_HEAD(&ctrl->async_events);
        INIT_RADIX_TREE(&ctrl->p2p_ns_map, GFP_KERNEL);
index 27a7250..2dc1c10 100644 (file)
@@ -246,7 +246,8 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req)
        struct scatterlist *sg;
        struct blk_plug plug;
        sector_t sector;
-       int op, i, rc;
+       blk_opf_t opf;
+       int i, rc;
        struct sg_mapping_iter prot_miter;
        unsigned int iter_flags;
        unsigned int total_len = nvmet_rw_data_len(req) + req->metadata_len;
@@ -260,26 +261,26 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req)
        }
 
        if (req->cmd->rw.opcode == nvme_cmd_write) {
-               op = REQ_OP_WRITE | REQ_SYNC | REQ_IDLE;
+               opf = REQ_OP_WRITE | REQ_SYNC | REQ_IDLE;
                if (req->cmd->rw.control & cpu_to_le16(NVME_RW_FUA))
-                       op |= REQ_FUA;
+                       opf |= REQ_FUA;
                iter_flags = SG_MITER_TO_SG;
        } else {
-               op = REQ_OP_READ;
+               opf = REQ_OP_READ;
                iter_flags = SG_MITER_FROM_SG;
        }
 
        if (is_pci_p2pdma_page(sg_page(req->sg)))
-               op |= REQ_NOMERGE;
+               opf |= REQ_NOMERGE;
 
        sector = nvmet_lba_to_sect(req->ns, req->cmd->rw.slba);
 
        if (nvmet_use_inline_bvec(req)) {
                bio = &req->b.inline_bio;
                bio_init(bio, req->ns->bdev, req->inline_bvec,
-                        ARRAY_SIZE(req->inline_bvec), op);
+                        ARRAY_SIZE(req->inline_bvec), opf);
        } else {
-               bio = bio_alloc(req->ns->bdev, bio_max_segs(sg_cnt), op,
+               bio = bio_alloc(req->ns->bdev, bio_max_segs(sg_cnt), opf,
                                GFP_KERNEL);
        }
        bio->bi_iter.bi_sector = sector;
@@ -306,7 +307,7 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req)
                        }
 
                        bio = bio_alloc(req->ns->bdev, bio_max_segs(sg_cnt),
-                                       op, GFP_KERNEL);
+                                       opf, GFP_KERNEL);
                        bio->bi_iter.bi_sector = sector;
 
                        bio_chain(bio, prev);
index 59024af..0f5c77e 100644 (file)
@@ -266,8 +266,8 @@ static void nvme_loop_destroy_admin_queue(struct nvme_loop_ctrl *ctrl)
        if (!test_and_clear_bit(NVME_LOOP_Q_LIVE, &ctrl->queues[0].flags))
                return;
        nvmet_sq_destroy(&ctrl->queues[0].nvme_sq);
-       blk_cleanup_queue(ctrl->ctrl.admin_q);
-       blk_cleanup_queue(ctrl->ctrl.fabrics_q);
+       blk_mq_destroy_queue(ctrl->ctrl.admin_q);
+       blk_mq_destroy_queue(ctrl->ctrl.fabrics_q);
        blk_mq_free_tag_set(&ctrl->admin_tag_set);
 }
 
@@ -283,7 +283,7 @@ static void nvme_loop_free_ctrl(struct nvme_ctrl *nctrl)
        mutex_unlock(&nvme_loop_ctrl_mutex);
 
        if (nctrl->tagset) {
-               blk_cleanup_queue(ctrl->ctrl.connect_q);
+               blk_mq_destroy_queue(ctrl->ctrl.connect_q);
                blk_mq_free_tag_set(&ctrl->tag_set);
        }
        kfree(ctrl->queues);
@@ -410,9 +410,9 @@ static int nvme_loop_configure_admin_queue(struct nvme_loop_ctrl *ctrl)
 
 out_cleanup_queue:
        clear_bit(NVME_LOOP_Q_LIVE, &ctrl->queues[0].flags);
-       blk_cleanup_queue(ctrl->ctrl.admin_q);
+       blk_mq_destroy_queue(ctrl->ctrl.admin_q);
 out_cleanup_fabrics_q:
-       blk_cleanup_queue(ctrl->ctrl.fabrics_q);
+       blk_mq_destroy_queue(ctrl->ctrl.fabrics_q);
 out_free_tagset:
        blk_mq_free_tag_set(&ctrl->admin_tag_set);
 out_free_sq:
@@ -554,7 +554,7 @@ static int nvme_loop_create_io_queues(struct nvme_loop_ctrl *ctrl)
        return 0;
 
 out_cleanup_connect_q:
-       blk_cleanup_queue(ctrl->ctrl.connect_q);
+       blk_mq_destroy_queue(ctrl->ctrl.connect_q);
 out_free_tagset:
        blk_mq_free_tag_set(&ctrl->tag_set);
 out_destroy_queues:
index 6981875..2b3e571 100644 (file)
@@ -249,6 +249,7 @@ struct nvmet_subsys {
        struct config_group     passthru_group;
        unsigned int            admin_timeout;
        unsigned int            io_timeout;
+       unsigned int            clear_ids;
 #endif /* CONFIG_NVME_TARGET_PASSTHRU */
 
 #ifdef CONFIG_BLK_DEV_ZONED
index b1f7efa..6f39a29 100644 (file)
@@ -30,6 +30,53 @@ void nvmet_passthrough_override_cap(struct nvmet_ctrl *ctrl)
                ctrl->cap &= ~(1ULL << 43);
 }
 
+static u16 nvmet_passthru_override_id_descs(struct nvmet_req *req)
+{
+       struct nvmet_ctrl *ctrl = req->sq->ctrl;
+       u16 status = NVME_SC_SUCCESS;
+       int pos, len;
+       bool csi_seen = false;
+       void *data;
+       u8 csi;
+
+       if (!ctrl->subsys->clear_ids)
+               return status;
+
+       data = kzalloc(NVME_IDENTIFY_DATA_SIZE, GFP_KERNEL);
+       if (!data)
+               return NVME_SC_INTERNAL;
+
+       status = nvmet_copy_from_sgl(req, 0, data, NVME_IDENTIFY_DATA_SIZE);
+       if (status)
+               goto out_free;
+
+       for (pos = 0; pos < NVME_IDENTIFY_DATA_SIZE; pos += len) {
+               struct nvme_ns_id_desc *cur = data + pos;
+
+               if (cur->nidl == 0)
+                       break;
+               if (cur->nidt == NVME_NIDT_CSI) {
+                       memcpy(&csi, cur + 1, NVME_NIDT_CSI_LEN);
+                       csi_seen = true;
+                       break;
+               }
+               len = sizeof(struct nvme_ns_id_desc) + cur->nidl;
+       }
+
+       memset(data, 0, NVME_IDENTIFY_DATA_SIZE);
+       if (csi_seen) {
+               struct nvme_ns_id_desc *cur = data;
+
+               cur->nidt = NVME_NIDT_CSI;
+               cur->nidl = NVME_NIDT_CSI_LEN;
+               memcpy(cur + 1, &csi, NVME_NIDT_CSI_LEN);
+       }
+       status = nvmet_copy_to_sgl(req, 0, data, NVME_IDENTIFY_DATA_SIZE);
+out_free:
+       kfree(data);
+       return status;
+}
+
 static u16 nvmet_passthru_override_id_ctrl(struct nvmet_req *req)
 {
        struct nvmet_ctrl *ctrl = req->sq->ctrl;
@@ -152,6 +199,11 @@ static u16 nvmet_passthru_override_id_ns(struct nvmet_req *req)
         */
        id->mc = 0;
 
+       if (req->sq->ctrl->subsys->clear_ids) {
+               memset(id->nguid, 0, NVME_NIDT_NGUID_LEN);
+               memset(id->eui64, 0, NVME_NIDT_EUI64_LEN);
+       }
+
        status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id));
 
 out_free:
@@ -176,6 +228,9 @@ static void nvmet_passthru_execute_cmd_work(struct work_struct *w)
                case NVME_ID_CNS_NS:
                        nvmet_passthru_override_id_ns(req);
                        break;
+               case NVME_ID_CNS_NS_DESC_LIST:
+                       nvmet_passthru_override_id_descs(req);
+                       break;
                }
        } else if (status < 0)
                status = NVME_SC_INTERNAL;
index 2793554..0a95425 100644 (file)
@@ -405,7 +405,7 @@ err:
        return NVME_SC_INTERNAL;
 }
 
-static void nvmet_tcp_send_ddgst(struct ahash_request *hash,
+static void nvmet_tcp_calc_ddgst(struct ahash_request *hash,
                struct nvmet_tcp_cmd *cmd)
 {
        ahash_request_set_crypt(hash, cmd->req.sg,
@@ -413,23 +413,6 @@ static void nvmet_tcp_send_ddgst(struct ahash_request *hash,
        crypto_ahash_digest(hash);
 }
 
-static void nvmet_tcp_recv_ddgst(struct ahash_request *hash,
-               struct nvmet_tcp_cmd *cmd)
-{
-       struct scatterlist sg;
-       struct kvec *iov;
-       int i;
-
-       crypto_ahash_init(hash);
-       for (i = 0, iov = cmd->iov; i < cmd->nr_mapped; i++, iov++) {
-               sg_init_one(&sg, iov->iov_base, iov->iov_len);
-               ahash_request_set_crypt(hash, &sg, NULL, iov->iov_len);
-               crypto_ahash_update(hash);
-       }
-       ahash_request_set_crypt(hash, NULL, (void *)&cmd->exp_ddgst, 0);
-       crypto_ahash_final(hash);
-}
-
 static void nvmet_setup_c2h_data_pdu(struct nvmet_tcp_cmd *cmd)
 {
        struct nvme_tcp_data_pdu *pdu = cmd->data_pdu;
@@ -454,7 +437,7 @@ static void nvmet_setup_c2h_data_pdu(struct nvmet_tcp_cmd *cmd)
 
        if (queue->data_digest) {
                pdu->hdr.flags |= NVME_TCP_F_DDGST;
-               nvmet_tcp_send_ddgst(queue->snd_hash, cmd);
+               nvmet_tcp_calc_ddgst(queue->snd_hash, cmd);
        }
 
        if (cmd->queue->hdr_digest) {
@@ -1137,7 +1120,7 @@ static void nvmet_tcp_prep_recv_ddgst(struct nvmet_tcp_cmd *cmd)
 {
        struct nvmet_tcp_queue *queue = cmd->queue;
 
-       nvmet_tcp_recv_ddgst(queue->rcv_hash, cmd);
+       nvmet_tcp_calc_ddgst(queue->rcv_hash, cmd);
        queue->offset = 0;
        queue->left = NVME_TCP_DIGEST_LENGTH;
        queue->rcv_state = NVMET_TCP_RECV_DDGST;
index 82b61ac..c7ef69f 100644 (file)
@@ -57,10 +57,10 @@ bool nvmet_bdev_zns_enable(struct nvmet_ns *ns)
         * zones, reject the device. Otherwise, use report zones to detect if
         * the device has conventional zones.
         */
-       if (ns->bdev->bd_disk->queue->conv_zones_bitmap)
+       if (ns->bdev->bd_disk->conv_zones_bitmap)
                return false;
 
-       ret = blkdev_report_zones(ns->bdev, 0, blkdev_nr_zones(bd_disk),
+       ret = blkdev_report_zones(ns->bdev, 0, bdev_nr_zones(ns->bdev),
                                  validate_conv_zones_cb, NULL);
        if (ret < 0)
                return false;
@@ -241,7 +241,7 @@ static unsigned long nvmet_req_nr_zones_from_slba(struct nvmet_req *req)
 {
        unsigned int sect = nvmet_lba_to_sect(req->ns, req->cmd->zmr.slba);
 
-       return blkdev_nr_zones(req->ns->bdev->bd_disk) -
+       return bdev_nr_zones(req->ns->bdev) -
                (sect >> ilog2(bdev_zone_sectors(req->ns->bdev)));
 }
 
@@ -308,7 +308,7 @@ void nvmet_bdev_execute_zone_mgmt_recv(struct nvmet_req *req)
        queue_work(zbd_wq, &req->z.zmgmt_work);
 }
 
-static inline enum req_opf zsa_req_op(u8 zsa)
+static inline enum req_op zsa_req_op(u8 zsa)
 {
        switch (zsa) {
        case NVME_ZONE_OPEN:
@@ -386,7 +386,7 @@ static int zmgmt_send_scan_cb(struct blk_zone *z, unsigned i, void *d)
 static u16 nvmet_bdev_zone_mgmt_emulate_all(struct nvmet_req *req)
 {
        struct block_device *bdev = req->ns->bdev;
-       unsigned int nr_zones = blkdev_nr_zones(bdev->bd_disk);
+       unsigned int nr_zones = bdev_nr_zones(bdev);
        struct request_queue *q = bdev_get_queue(bdev);
        struct bio *bio = NULL;
        sector_t sector = 0;
@@ -413,8 +413,8 @@ static u16 nvmet_bdev_zone_mgmt_emulate_all(struct nvmet_req *req)
                ret = 0;
        }
 
-       while (sector < get_capacity(bdev->bd_disk)) {
-               if (test_bit(blk_queue_zone_no(q, sector), d.zbitmap)) {
+       while (sector < bdev_nr_sectors(bdev)) {
+               if (test_bit(disk_zone_no(bdev->bd_disk, sector), d.zbitmap)) {
                        bio = blk_next_bio(bio, bdev, 0,
                                zsa_req_op(req->cmd->zms.zsa) | REQ_SYNC,
                                GFP_KERNEL);
@@ -422,7 +422,7 @@ static u16 nvmet_bdev_zone_mgmt_emulate_all(struct nvmet_req *req)
                        /* This may take a while, so be nice to others */
                        cond_resched();
                }
-               sector += blk_queue_zone_sectors(q);
+               sector += bdev_zone_sectors(bdev);
        }
 
        if (bio) {
@@ -465,7 +465,7 @@ static void nvmet_bdev_zmgmt_send_work(struct work_struct *w)
 {
        struct nvmet_req *req = container_of(w, struct nvmet_req, z.zmgmt_work);
        sector_t sect = nvmet_lba_to_sect(req->ns, req->cmd->zms.slba);
-       enum req_opf op = zsa_req_op(req->cmd->zms.zsa);
+       enum req_op op = zsa_req_op(req->cmd->zms.zsa);
        struct block_device *bdev = req->ns->bdev;
        sector_t zone_sectors = bdev_zone_sectors(bdev);
        u16 status = NVME_SC_SUCCESS;
@@ -525,7 +525,7 @@ static void nvmet_bdev_zone_append_bio_done(struct bio *bio)
 void nvmet_bdev_execute_zone_append(struct nvmet_req *req)
 {
        sector_t sect = nvmet_lba_to_sect(req->ns, req->cmd->rw.slba);
-       const unsigned int op = REQ_OP_ZONE_APPEND | REQ_SYNC | REQ_IDLE;
+       const blk_opf_t opf = REQ_OP_ZONE_APPEND | REQ_SYNC | REQ_IDLE;
        u16 status = NVME_SC_SUCCESS;
        unsigned int total_len = 0;
        struct scatterlist *sg;
@@ -556,9 +556,9 @@ void nvmet_bdev_execute_zone_append(struct nvmet_req *req)
        if (nvmet_use_inline_bvec(req)) {
                bio = &req->z.inline_bio;
                bio_init(bio, req->ns->bdev, req->inline_bvec,
-                        ARRAY_SIZE(req->inline_bvec), op);
+                        ARRAY_SIZE(req->inline_bvec), opf);
        } else {
-               bio = bio_alloc(req->ns->bdev, req->sg_cnt, op, GFP_KERNEL);
+               bio = bio_alloc(req->ns->bdev, req->sg_cnt, opf, GFP_KERNEL);
        }
 
        bio->bi_end_io = nvmet_bdev_zone_append_bio_done;
index 8d374cc..f2e58dd 100644 (file)
@@ -9,6 +9,7 @@
  *  Copyright (C) 2016  IBM Corporation
  */
 
+#include <linux/ima.h>
 #include <linux/kernel.h>
 #include <linux/kexec.h>
 #include <linux/memblock.h>
@@ -115,6 +116,7 @@ static int do_get_kexec_buffer(const void *prop, int len, unsigned long *addr,
        return 0;
 }
 
+#ifdef CONFIG_HAVE_IMA_KEXEC
 /**
  * ima_get_kexec_buffer - get IMA buffer from the previous kernel
  * @addr:      On successful return, set to point to the buffer contents.
@@ -122,16 +124,13 @@ static int do_get_kexec_buffer(const void *prop, int len, unsigned long *addr,
  *
  * Return: 0 on success, negative errno on error.
  */
-int ima_get_kexec_buffer(void **addr, size_t *size)
+int __init ima_get_kexec_buffer(void **addr, size_t *size)
 {
        int ret, len;
        unsigned long tmp_addr;
        size_t tmp_size;
        const void *prop;
 
-       if (!IS_ENABLED(CONFIG_HAVE_IMA_KEXEC))
-               return -ENOTSUPP;
-
        prop = of_get_property(of_chosen, "linux,ima-kexec-buffer", &len);
        if (!prop)
                return -ENOENT;
@@ -149,16 +148,13 @@ int ima_get_kexec_buffer(void **addr, size_t *size)
 /**
  * ima_free_kexec_buffer - free memory used by the IMA buffer
  */
-int ima_free_kexec_buffer(void)
+int __init ima_free_kexec_buffer(void)
 {
        int ret;
        unsigned long addr;
        size_t size;
        struct property *prop;
 
-       if (!IS_ENABLED(CONFIG_HAVE_IMA_KEXEC))
-               return -ENOTSUPP;
-
        prop = of_find_property(of_chosen, "linux,ima-kexec-buffer", NULL);
        if (!prop)
                return -ENOENT;
@@ -173,6 +169,7 @@ int ima_free_kexec_buffer(void)
 
        return memblock_phys_free(addr, size);
 }
+#endif
 
 /**
  * remove_ima_buffer - remove the IMA buffer property and reservation from @fdt
index 3039492..eb89c9a 100644 (file)
@@ -1443,12 +1443,12 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_of_node);
  * It provides the power used by @dev at @kHz if it is the frequency of an
  * existing OPP, or at the frequency of the first OPP above @kHz otherwise
  * (see dev_pm_opp_find_freq_ceil()). This function updates @kHz to the ceiled
- * frequency and @mW to the associated power.
+ * frequency and @uW to the associated power.
  *
  * Returns 0 on success or a proper -EINVAL value in case of error.
  */
 static int __maybe_unused
-_get_dt_power(struct device *dev, unsigned long *mW, unsigned long *kHz)
+_get_dt_power(struct device *dev, unsigned long *uW, unsigned long *kHz)
 {
        struct dev_pm_opp *opp;
        unsigned long opp_freq, opp_power;
@@ -1465,7 +1465,7 @@ _get_dt_power(struct device *dev, unsigned long *mW, unsigned long *kHz)
                return -EINVAL;
 
        *kHz = opp_freq / 1000;
-       *mW = opp_power / 1000;
+       *uW = opp_power;
 
        return 0;
 }
@@ -1475,14 +1475,14 @@ _get_dt_power(struct device *dev, unsigned long *mW, unsigned long *kHz)
  * This computes the power estimated by @dev at @kHz if it is the frequency
  * of an existing OPP, or at the frequency of the first OPP above @kHz otherwise
  * (see dev_pm_opp_find_freq_ceil()). This function updates @kHz to the ceiled
- * frequency and @mW to the associated power. The power is estimated as
+ * frequency and @uW to the associated power. The power is estimated as
  * P = C * V^2 * f with C being the device's capacitance and V and f
  * respectively the voltage and frequency of the OPP.
  *
  * Returns -EINVAL if the power calculation failed because of missing
  * parameters, 0 otherwise.
  */
-static int __maybe_unused _get_power(struct device *dev, unsigned long *mW,
+static int __maybe_unused _get_power(struct device *dev, unsigned long *uW,
                                     unsigned long *kHz)
 {
        struct dev_pm_opp *opp;
@@ -1512,9 +1512,10 @@ static int __maybe_unused _get_power(struct device *dev, unsigned long *mW,
                return -EINVAL;
 
        tmp = (u64)cap * mV * mV * (Hz / 1000000);
-       do_div(tmp, 1000000000);
+       /* Provide power in micro-Watts */
+       do_div(tmp, 1000000);
 
-       *mW = (unsigned long)tmp;
+       *uW = (unsigned long)tmp;
        *kHz = Hz / 1000;
 
        return 0;
index 8a3b0c3..3a8c986 100644 (file)
@@ -677,7 +677,7 @@ static int iosapic_set_affinity_irq(struct irq_data *d,
        if (dest_cpu < 0)
                return -1;
 
-       cpumask_copy(irq_data_get_affinity_mask(d), cpumask_of(dest_cpu));
+       irq_data_update_affinity(d, cpumask_of(dest_cpu));
        vi->txn_addr = txn_affinity_addr(d->irq, dest_cpu);
 
        spin_lock_irqsave(&iosapic_lock, flags);
index db814f7..e7c6f66 100644 (file)
@@ -642,7 +642,7 @@ static void hv_arch_irq_unmask(struct irq_data *data)
        struct hv_retarget_device_interrupt *params;
        struct tran_int_desc *int_desc;
        struct hv_pcibus_device *hbus;
-       struct cpumask *dest;
+       const struct cpumask *dest;
        cpumask_var_t tmp;
        struct pci_bus *pbus;
        struct pci_dev *pdev;
@@ -1613,7 +1613,7 @@ out:
 }
 
 static u32 hv_compose_msi_req_v1(
-       struct pci_create_interrupt *int_pkt, struct cpumask *affinity,
+       struct pci_create_interrupt *int_pkt, const struct cpumask *affinity,
        u32 slot, u8 vector, u8 vector_count)
 {
        int_pkt->message_type.type = PCI_CREATE_INTERRUPT_MESSAGE;
@@ -1635,13 +1635,13 @@ static u32 hv_compose_msi_req_v1(
  * Create MSI w/ dummy vCPU set targeting just one vCPU, overwritten
  * by subsequent retarget in hv_irq_unmask().
  */
-static int hv_compose_msi_req_get_cpu(struct cpumask *affinity)
+static int hv_compose_msi_req_get_cpu(const struct cpumask *affinity)
 {
        return cpumask_first_and(affinity, cpu_online_mask);
 }
 
 static u32 hv_compose_msi_req_v2(
-       struct pci_create_interrupt2 *int_pkt, struct cpumask *affinity,
+       struct pci_create_interrupt2 *int_pkt, const struct cpumask *affinity,
        u32 slot, u8 vector, u8 vector_count)
 {
        int cpu;
@@ -1660,7 +1660,7 @@ static u32 hv_compose_msi_req_v2(
 }
 
 static u32 hv_compose_msi_req_v3(
-       struct pci_create_interrupt3 *int_pkt, struct cpumask *affinity,
+       struct pci_create_interrupt3 *int_pkt, const struct cpumask *affinity,
        u32 slot, u32 vector, u8 vector_count)
 {
        int cpu;
@@ -1697,7 +1697,7 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
        struct hv_pci_dev *hpdev;
        struct pci_bus *pbus;
        struct pci_dev *pdev;
-       struct cpumask *dest;
+       const struct cpumask *dest;
        struct compose_comp_ctxt comp;
        struct tran_int_desc *int_desc;
        struct msi_desc *msi_desc;
index 96e09fa..03b1309 100644 (file)
@@ -1139,7 +1139,7 @@ static void cci_pmu_start(struct perf_event *event, int pmu_flags)
 
        /*
         * To handle interrupt latency, we always reprogram the period
-        * regardlesss of PERF_EF_RELOAD.
+        * regardless of PERF_EF_RELOAD.
         */
        if (pmu_flags & PERF_EF_RELOAD)
                WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
@@ -1261,7 +1261,7 @@ static int validate_group(struct perf_event *event)
                 */
                .used_mask = mask,
        };
-       memset(mask, 0, BITS_TO_LONGS(cci_pmu->num_cntrs) * sizeof(unsigned long));
+       bitmap_zero(mask, cci_pmu->num_cntrs);
 
        if (!validate_event(event->pmu, &fake_pmu, leader))
                return -EINVAL;
@@ -1629,10 +1629,9 @@ static struct cci_pmu *cci_pmu_alloc(struct device *dev)
                                             GFP_KERNEL);
        if (!cci_pmu->hw_events.events)
                return ERR_PTR(-ENOMEM);
-       cci_pmu->hw_events.used_mask = devm_kcalloc(dev,
-                                               BITS_TO_LONGS(CCI_PMU_MAX_HW_CNTRS(model)),
-                                               sizeof(*cci_pmu->hw_events.used_mask),
-                                               GFP_KERNEL);
+       cci_pmu->hw_events.used_mask = devm_bitmap_zalloc(dev,
+                                                         CCI_PMU_MAX_HW_CNTRS(model),
+                                                         GFP_KERNEL);
        if (!cci_pmu->hw_events.used_mask)
                return ERR_PTR(-ENOMEM);
 
index 40b352e..728d13d 100644 (file)
@@ -1250,7 +1250,7 @@ static int arm_ccn_pmu_init(struct arm_ccn *ccn)
        ccn->dt.cmp_mask[CCN_IDX_MASK_OPCODE].h = ~(0x1f << 9);
 
        /* Get a convenient /sys/event_source/devices/ name */
-       ccn->dt.id = ida_simple_get(&arm_ccn_pmu_ida, 0, 0, GFP_KERNEL);
+       ccn->dt.id = ida_alloc(&arm_ccn_pmu_ida, GFP_KERNEL);
        if (ccn->dt.id == 0) {
                name = "ccn";
        } else {
@@ -1312,7 +1312,7 @@ error_pmu_register:
                                            &ccn->dt.node);
 error_set_affinity:
 error_choose_name:
-       ida_simple_remove(&arm_ccn_pmu_ida, ccn->dt.id);
+       ida_free(&arm_ccn_pmu_ida, ccn->dt.id);
        for (i = 0; i < ccn->num_xps; i++)
                writel(0, ccn->xp[i].base + CCN_XP_DT_CONTROL);
        writel(0, ccn->dt.base + CCN_DT_PMCR);
@@ -1329,7 +1329,7 @@ static void arm_ccn_pmu_cleanup(struct arm_ccn *ccn)
                writel(0, ccn->xp[i].base + CCN_XP_DT_CONTROL);
        writel(0, ccn->dt.base + CCN_DT_PMCR);
        perf_pmu_unregister(&ccn->dt.pmu);
-       ida_simple_remove(&arm_ccn_pmu_ida, ccn->dt.id);
+       ida_free(&arm_ccn_pmu_ida, ccn->dt.id);
 }
 
 static int arm_ccn_for_each_valid_region(struct arm_ccn *ccn,
index db670b2..b65a7d9 100644 (file)
 #include <asm/mmu.h>
 #include <asm/sysreg.h>
 
+/*
+ * Cache if the event is allowed to trace Context information.
+ * This allows us to perform the check, i.e, perfmon_capable(),
+ * in the context of the event owner, once, during the event_init().
+ */
+#define SPE_PMU_HW_FLAGS_CX                    BIT(0)
+
+static void set_spe_event_has_cx(struct perf_event *event)
+{
+       if (IS_ENABLED(CONFIG_PID_IN_CONTEXTIDR) && perfmon_capable())
+               event->hw.flags |= SPE_PMU_HW_FLAGS_CX;
+}
+
+static bool get_spe_event_has_cx(struct perf_event *event)
+{
+       return !!(event->hw.flags & SPE_PMU_HW_FLAGS_CX);
+}
+
 #define ARM_SPE_BUF_PAD_BYTE                   0
 
 struct arm_spe_pmu_buf {
@@ -272,7 +290,7 @@ static u64 arm_spe_event_to_pmscr(struct perf_event *event)
        if (!attr->exclude_kernel)
                reg |= BIT(SYS_PMSCR_EL1_E1SPE_SHIFT);
 
-       if (IS_ENABLED(CONFIG_PID_IN_CONTEXTIDR) && perfmon_capable())
+       if (get_spe_event_has_cx(event))
                reg |= BIT(SYS_PMSCR_EL1_CX_SHIFT);
 
        return reg;
@@ -709,10 +727,10 @@ static int arm_spe_pmu_event_init(struct perf_event *event)
            !(spe_pmu->features & SPE_PMU_FEAT_FILT_LAT))
                return -EOPNOTSUPP;
 
+       set_spe_event_has_cx(event);
        reg = arm_spe_event_to_pmscr(event);
        if (!perfmon_capable() &&
            (reg & (BIT(SYS_PMSCR_EL1_PA_SHIFT) |
-                   BIT(SYS_PMSCR_EL1_CX_SHIFT) |
                    BIT(SYS_PMSCR_EL1_PCT_SHIFT))))
                return -EACCES;
 
index b1b2a55..8e058e0 100644 (file)
@@ -611,7 +611,7 @@ static int ddr_perf_init(struct ddr_pmu *pmu, void __iomem *base,
                .dev = dev,
        };
 
-       pmu->id = ida_simple_get(&ddr_ida, 0, 0, GFP_KERNEL);
+       pmu->id = ida_alloc(&ddr_ida, GFP_KERNEL);
        return pmu->id;
 }
 
@@ -765,7 +765,7 @@ ddr_perf_err:
 cpuhp_instance_err:
        cpuhp_remove_multi_state(pmu->cpuhp_state);
 cpuhp_state_err:
-       ida_simple_remove(&ddr_ida, pmu->id);
+       ida_free(&ddr_ida, pmu->id);
        dev_warn(&pdev->dev, "i.MX8 DDR Perf PMU failed (%d), disabled\n", ret);
        return ret;
 }
@@ -779,7 +779,7 @@ static int ddr_perf_remove(struct platform_device *pdev)
 
        perf_pmu_unregister(&pmu->pmu);
 
-       ida_simple_remove(&ddr_ida, pmu->id);
+       ida_free(&ddr_ida, pmu->id);
        return 0;
 }
 
index 5546218..171bfc1 100644 (file)
@@ -14,3 +14,13 @@ config HISI_PCIE_PMU
          RCiEP devices.
          Adds the PCIe PMU into perf events system for monitoring latency,
          bandwidth etc.
+
+config HNS3_PMU
+       tristate "HNS3 PERF PMU"
+       depends on ARM64 || COMPILE_TEST
+       depends on PCI
+       help
+         Provide support for HNS3 performance monitoring unit (PMU) RCiEP
+         devices.
+         Adds the HNS3 PMU into perf events system for monitoring latency,
+         bandwidth etc.
index 6be8351..4d2c9ab 100644 (file)
@@ -4,3 +4,4 @@ obj-$(CONFIG_HISI_PMU) += hisi_uncore_pmu.o hisi_uncore_l3c_pmu.o \
                          hisi_uncore_pa_pmu.o hisi_uncore_cpa_pmu.o
 
 obj-$(CONFIG_HISI_PCIE_PMU) += hisi_pcie_pmu.o
+obj-$(CONFIG_HNS3_PMU) += hns3_pmu.o
index 62299ab..50d0c0a 100644 (file)
@@ -516,21 +516,7 @@ static int hisi_ddrc_pmu_probe(struct platform_device *pdev)
                                      "hisi_sccl%u_ddrc%u", ddrc_pmu->sccl_id,
                                      ddrc_pmu->index_id);
 
-       ddrc_pmu->pmu = (struct pmu) {
-               .name           = name,
-               .module         = THIS_MODULE,
-               .task_ctx_nr    = perf_invalid_context,
-               .event_init     = hisi_uncore_pmu_event_init,
-               .pmu_enable     = hisi_uncore_pmu_enable,
-               .pmu_disable    = hisi_uncore_pmu_disable,
-               .add            = hisi_uncore_pmu_add,
-               .del            = hisi_uncore_pmu_del,
-               .start          = hisi_uncore_pmu_start,
-               .stop           = hisi_uncore_pmu_stop,
-               .read           = hisi_uncore_pmu_read,
-               .attr_groups    = ddrc_pmu->pmu_events.attr_groups,
-               .capabilities   = PERF_PMU_CAP_NO_EXCLUDE,
-       };
+       hisi_pmu_init(&ddrc_pmu->pmu, name, ddrc_pmu->pmu_events.attr_groups, THIS_MODULE);
 
        ret = perf_pmu_register(&ddrc_pmu->pmu, name, -1);
        if (ret) {
index 3935131..13017b3 100644 (file)
@@ -519,21 +519,7 @@ static int hisi_hha_pmu_probe(struct platform_device *pdev)
 
        name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_hha%u",
                              hha_pmu->sccl_id, hha_pmu->index_id);
-       hha_pmu->pmu = (struct pmu) {
-               .name           = name,
-               .module         = THIS_MODULE,
-               .task_ctx_nr    = perf_invalid_context,
-               .event_init     = hisi_uncore_pmu_event_init,
-               .pmu_enable     = hisi_uncore_pmu_enable,
-               .pmu_disable    = hisi_uncore_pmu_disable,
-               .add            = hisi_uncore_pmu_add,
-               .del            = hisi_uncore_pmu_del,
-               .start          = hisi_uncore_pmu_start,
-               .stop           = hisi_uncore_pmu_stop,
-               .read           = hisi_uncore_pmu_read,
-               .attr_groups    = hha_pmu->pmu_events.attr_groups,
-               .capabilities   = PERF_PMU_CAP_NO_EXCLUDE,
-       };
+       hisi_pmu_init(&hha_pmu->pmu, name, hha_pmu->pmu_events.attr_groups, THIS_MODULE);
 
        ret = perf_pmu_register(&hha_pmu->pmu, name, -1);
        if (ret) {
index 560ab96..2995f36 100644 (file)
@@ -557,21 +557,7 @@ static int hisi_l3c_pmu_probe(struct platform_device *pdev)
         */
        name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_l3c%u",
                              l3c_pmu->sccl_id, l3c_pmu->ccl_id);
-       l3c_pmu->pmu = (struct pmu) {
-               .name           = name,
-               .module         = THIS_MODULE,
-               .task_ctx_nr    = perf_invalid_context,
-               .event_init     = hisi_uncore_pmu_event_init,
-               .pmu_enable     = hisi_uncore_pmu_enable,
-               .pmu_disable    = hisi_uncore_pmu_disable,
-               .add            = hisi_uncore_pmu_add,
-               .del            = hisi_uncore_pmu_del,
-               .start          = hisi_uncore_pmu_start,
-               .stop           = hisi_uncore_pmu_stop,
-               .read           = hisi_uncore_pmu_read,
-               .attr_groups    = l3c_pmu->pmu_events.attr_groups,
-               .capabilities   = PERF_PMU_CAP_NO_EXCLUDE,
-       };
+       hisi_pmu_init(&l3c_pmu->pmu, name, l3c_pmu->pmu_events.attr_groups, THIS_MODULE);
 
        ret = perf_pmu_register(&l3c_pmu->pmu, name, -1);
        if (ret) {
index a0ee84d..47d3cc9 100644 (file)
@@ -412,21 +412,7 @@ static int hisi_pa_pmu_probe(struct platform_device *pdev)
                return ret;
        }
 
-       pa_pmu->pmu = (struct pmu) {
-               .module         = THIS_MODULE,
-               .task_ctx_nr    = perf_invalid_context,
-               .event_init     = hisi_uncore_pmu_event_init,
-               .pmu_enable     = hisi_uncore_pmu_enable,
-               .pmu_disable    = hisi_uncore_pmu_disable,
-               .add            = hisi_uncore_pmu_add,
-               .del            = hisi_uncore_pmu_del,
-               .start          = hisi_uncore_pmu_start,
-               .stop           = hisi_uncore_pmu_stop,
-               .read           = hisi_uncore_pmu_read,
-               .attr_groups    = pa_pmu->pmu_events.attr_groups,
-               .capabilities   = PERF_PMU_CAP_NO_EXCLUDE,
-       };
-
+       hisi_pmu_init(&pa_pmu->pmu, name, pa_pmu->pmu_events.attr_groups, THIS_MODULE);
        ret = perf_pmu_register(&pa_pmu->pmu, name, -1);
        if (ret) {
                dev_err(pa_pmu->dev, "PMU register failed, ret = %d\n", ret);
index 980b9ee..fbc8a93 100644 (file)
@@ -531,4 +531,22 @@ int hisi_uncore_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
 }
 EXPORT_SYMBOL_GPL(hisi_uncore_pmu_offline_cpu);
 
+void hisi_pmu_init(struct pmu *pmu, const char *name,
+               const struct attribute_group **attr_groups, struct module *module)
+{
+       pmu->name               = name;
+       pmu->module             = module;
+       pmu->task_ctx_nr        = perf_invalid_context;
+       pmu->event_init         = hisi_uncore_pmu_event_init;
+       pmu->pmu_enable         = hisi_uncore_pmu_enable;
+       pmu->pmu_disable        = hisi_uncore_pmu_disable;
+       pmu->add                = hisi_uncore_pmu_add;
+       pmu->del                = hisi_uncore_pmu_del;
+       pmu->start              = hisi_uncore_pmu_start;
+       pmu->stop               = hisi_uncore_pmu_stop;
+       pmu->read               = hisi_uncore_pmu_read;
+       pmu->attr_groups        = attr_groups;
+}
+EXPORT_SYMBOL_GPL(hisi_pmu_init);
+
 MODULE_LICENSE("GPL v2");
index 96eedda..b59de33 100644 (file)
@@ -121,4 +121,6 @@ ssize_t hisi_uncore_pmu_identifier_attr_show(struct device *dev,
 int hisi_uncore_pmu_init_irq(struct hisi_pmu *hisi_pmu,
                             struct platform_device *pdev);
 
+void hisi_pmu_init(struct pmu *pmu, const char *name,
+               const struct attribute_group **attr_groups, struct module *module);
 #endif /* __HISI_UNCORE_PMU_H__ */
index 6aedc30..b9c79f1 100644 (file)
@@ -445,20 +445,7 @@ static int hisi_sllc_pmu_probe(struct platform_device *pdev)
                return ret;
        }
 
-       sllc_pmu->pmu = (struct pmu) {
-               .module         = THIS_MODULE,
-               .task_ctx_nr    = perf_invalid_context,
-               .event_init     = hisi_uncore_pmu_event_init,
-               .pmu_enable     = hisi_uncore_pmu_enable,
-               .pmu_disable    = hisi_uncore_pmu_disable,
-               .add            = hisi_uncore_pmu_add,
-               .del            = hisi_uncore_pmu_del,
-               .start          = hisi_uncore_pmu_start,
-               .stop           = hisi_uncore_pmu_stop,
-               .read           = hisi_uncore_pmu_read,
-               .attr_groups    = sllc_pmu->pmu_events.attr_groups,
-               .capabilities   = PERF_PMU_CAP_NO_EXCLUDE,
-       };
+       hisi_pmu_init(&sllc_pmu->pmu, name, sllc_pmu->pmu_events.attr_groups, THIS_MODULE);
 
        ret = perf_pmu_register(&sllc_pmu->pmu, name, -1);
        if (ret) {
diff --git a/drivers/perf/hisilicon/hns3_pmu.c b/drivers/perf/hisilicon/hns3_pmu.c
new file mode 100644 (file)
index 0000000..e0457d8
--- /dev/null
@@ -0,0 +1,1671 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * This driver adds support for HNS3 PMU iEP device. Related perf events are
+ * bandwidth, latency, packet rate, interrupt rate etc.
+ *
+ * Copyright (C) 2022 HiSilicon Limited
+ */
+#include <linux/bitfield.h>
+#include <linux/bitmap.h>
+#include <linux/bug.h>
+#include <linux/cpuhotplug.h>
+#include <linux/cpumask.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/io-64-nonatomic-hi-lo.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/pci-epf.h>
+#include <linux/perf_event.h>
+#include <linux/smp.h>
+
+/* registers offset address */
+#define HNS3_PMU_REG_GLOBAL_CTRL               0x0000
+#define HNS3_PMU_REG_CLOCK_FREQ                        0x0020
+#define HNS3_PMU_REG_BDF                       0x0fe0
+#define HNS3_PMU_REG_VERSION                   0x0fe4
+#define HNS3_PMU_REG_DEVICE_ID                 0x0fe8
+
+#define HNS3_PMU_REG_EVENT_OFFSET              0x1000
+#define HNS3_PMU_REG_EVENT_SIZE                        0x1000
+#define HNS3_PMU_REG_EVENT_CTRL_LOW            0x00
+#define HNS3_PMU_REG_EVENT_CTRL_HIGH           0x04
+#define HNS3_PMU_REG_EVENT_INTR_STATUS         0x08
+#define HNS3_PMU_REG_EVENT_INTR_MASK           0x0c
+#define HNS3_PMU_REG_EVENT_COUNTER             0x10
+#define HNS3_PMU_REG_EVENT_EXT_COUNTER         0x18
+#define HNS3_PMU_REG_EVENT_QID_CTRL            0x28
+#define HNS3_PMU_REG_EVENT_QID_PARA            0x2c
+
+#define HNS3_PMU_FILTER_SUPPORT_GLOBAL         BIT(0)
+#define HNS3_PMU_FILTER_SUPPORT_PORT           BIT(1)
+#define HNS3_PMU_FILTER_SUPPORT_PORT_TC                BIT(2)
+#define HNS3_PMU_FILTER_SUPPORT_FUNC           BIT(3)
+#define HNS3_PMU_FILTER_SUPPORT_FUNC_QUEUE     BIT(4)
+#define HNS3_PMU_FILTER_SUPPORT_FUNC_INTR      BIT(5)
+
+#define HNS3_PMU_FILTER_ALL_TC                 0xf
+#define HNS3_PMU_FILTER_ALL_QUEUE              0xffff
+
+#define HNS3_PMU_CTRL_SUBEVENT_S               4
+#define HNS3_PMU_CTRL_FILTER_MODE_S            24
+
+#define HNS3_PMU_GLOBAL_START                  BIT(0)
+
+#define HNS3_PMU_EVENT_STATUS_RESET            BIT(11)
+#define HNS3_PMU_EVENT_EN                      BIT(12)
+#define HNS3_PMU_EVENT_OVERFLOW_RESTART                BIT(15)
+
+#define HNS3_PMU_QID_PARA_FUNC_S               0
+#define HNS3_PMU_QID_PARA_QUEUE_S              16
+
+#define HNS3_PMU_QID_CTRL_REQ_ENABLE           BIT(0)
+#define HNS3_PMU_QID_CTRL_DONE                 BIT(1)
+#define HNS3_PMU_QID_CTRL_MISS                 BIT(2)
+
+#define HNS3_PMU_INTR_MASK_OVERFLOW            BIT(1)
+
+#define HNS3_PMU_MAX_HW_EVENTS                 8
+
+/*
+ * Each hardware event contains two registers (counter and ext_counter) for
+ * bandwidth, packet rate, latency and interrupt rate. These two registers will
+ * be triggered to run at the same when a hardware event is enabled. The meaning
+ * of counter and ext_counter of different event type are different, their
+ * meaning show as follow:
+ *
+ * +----------------+------------------+---------------+
+ * |   event type   |     counter      |  ext_counter  |
+ * +----------------+------------------+---------------+
+ * | bandwidth      | byte number      | cycle number  |
+ * +----------------+------------------+---------------+
+ * | packet rate    | packet number    | cycle number  |
+ * +----------------+------------------+---------------+
+ * | latency        | cycle number     | packet number |
+ * +----------------+------------------+---------------+
+ * | interrupt rate | interrupt number | cycle number  |
+ * +----------------+------------------+---------------+
+ *
+ * The cycle number indicates increment of counter of hardware timer, the
+ * frequency of hardware timer can be read from hw_clk_freq file.
+ *
+ * Performance of each hardware event is calculated by: counter / ext_counter.
+ *
+ * Since processing of data is preferred to be done in userspace, we expose
+ * ext_counter as a separate event for userspace and use bit 16 to indicate it.
+ * For example, event 0x00001 and 0x10001 are actually one event for hardware
+ * because bit 0-15 are same. If the bit 16 of one event is 0 means to read
+ * counter register, otherwise means to read ext_counter register.
+ */
+/* bandwidth events */
+#define HNS3_PMU_EVT_BW_SSU_EGU_BYTE_NUM               0x00001
+#define HNS3_PMU_EVT_BW_SSU_EGU_TIME                   0x10001
+#define HNS3_PMU_EVT_BW_SSU_RPU_BYTE_NUM               0x00002
+#define HNS3_PMU_EVT_BW_SSU_RPU_TIME                   0x10002
+#define HNS3_PMU_EVT_BW_SSU_ROCE_BYTE_NUM              0x00003
+#define HNS3_PMU_EVT_BW_SSU_ROCE_TIME                  0x10003
+#define HNS3_PMU_EVT_BW_ROCE_SSU_BYTE_NUM              0x00004
+#define HNS3_PMU_EVT_BW_ROCE_SSU_TIME                  0x10004
+#define HNS3_PMU_EVT_BW_TPU_SSU_BYTE_NUM               0x00005
+#define HNS3_PMU_EVT_BW_TPU_SSU_TIME                   0x10005
+#define HNS3_PMU_EVT_BW_RPU_RCBRX_BYTE_NUM             0x00006
+#define HNS3_PMU_EVT_BW_RPU_RCBRX_TIME                 0x10006
+#define HNS3_PMU_EVT_BW_RCBTX_TXSCH_BYTE_NUM           0x00008
+#define HNS3_PMU_EVT_BW_RCBTX_TXSCH_TIME               0x10008
+#define HNS3_PMU_EVT_BW_WR_FBD_BYTE_NUM                        0x00009
+#define HNS3_PMU_EVT_BW_WR_FBD_TIME                    0x10009
+#define HNS3_PMU_EVT_BW_WR_EBD_BYTE_NUM                        0x0000a
+#define HNS3_PMU_EVT_BW_WR_EBD_TIME                    0x1000a
+#define HNS3_PMU_EVT_BW_RD_FBD_BYTE_NUM                        0x0000b
+#define HNS3_PMU_EVT_BW_RD_FBD_TIME                    0x1000b
+#define HNS3_PMU_EVT_BW_RD_EBD_BYTE_NUM                        0x0000c
+#define HNS3_PMU_EVT_BW_RD_EBD_TIME                    0x1000c
+#define HNS3_PMU_EVT_BW_RD_PAY_M0_BYTE_NUM             0x0000d
+#define HNS3_PMU_EVT_BW_RD_PAY_M0_TIME                 0x1000d
+#define HNS3_PMU_EVT_BW_RD_PAY_M1_BYTE_NUM             0x0000e
+#define HNS3_PMU_EVT_BW_RD_PAY_M1_TIME                 0x1000e
+#define HNS3_PMU_EVT_BW_WR_PAY_M0_BYTE_NUM             0x0000f
+#define HNS3_PMU_EVT_BW_WR_PAY_M0_TIME                 0x1000f
+#define HNS3_PMU_EVT_BW_WR_PAY_M1_BYTE_NUM             0x00010
+#define HNS3_PMU_EVT_BW_WR_PAY_M1_TIME                 0x10010
+
+/* packet rate events */
+#define HNS3_PMU_EVT_PPS_IGU_SSU_PACKET_NUM            0x00100
+#define HNS3_PMU_EVT_PPS_IGU_SSU_TIME                  0x10100
+#define HNS3_PMU_EVT_PPS_SSU_EGU_PACKET_NUM            0x00101
+#define HNS3_PMU_EVT_PPS_SSU_EGU_TIME                  0x10101
+#define HNS3_PMU_EVT_PPS_SSU_RPU_PACKET_NUM            0x00102
+#define HNS3_PMU_EVT_PPS_SSU_RPU_TIME                  0x10102
+#define HNS3_PMU_EVT_PPS_SSU_ROCE_PACKET_NUM           0x00103
+#define HNS3_PMU_EVT_PPS_SSU_ROCE_TIME                 0x10103
+#define HNS3_PMU_EVT_PPS_ROCE_SSU_PACKET_NUM           0x00104
+#define HNS3_PMU_EVT_PPS_ROCE_SSU_TIME                 0x10104
+#define HNS3_PMU_EVT_PPS_TPU_SSU_PACKET_NUM            0x00105
+#define HNS3_PMU_EVT_PPS_TPU_SSU_TIME                  0x10105
+#define HNS3_PMU_EVT_PPS_RPU_RCBRX_PACKET_NUM          0x00106
+#define HNS3_PMU_EVT_PPS_RPU_RCBRX_TIME                        0x10106
+#define HNS3_PMU_EVT_PPS_RCBTX_TPU_PACKET_NUM          0x00107
+#define HNS3_PMU_EVT_PPS_RCBTX_TPU_TIME                        0x10107
+#define HNS3_PMU_EVT_PPS_RCBTX_TXSCH_PACKET_NUM                0x00108
+#define HNS3_PMU_EVT_PPS_RCBTX_TXSCH_TIME              0x10108
+#define HNS3_PMU_EVT_PPS_WR_FBD_PACKET_NUM             0x00109
+#define HNS3_PMU_EVT_PPS_WR_FBD_TIME                   0x10109
+#define HNS3_PMU_EVT_PPS_WR_EBD_PACKET_NUM             0x0010a
+#define HNS3_PMU_EVT_PPS_WR_EBD_TIME                   0x1010a
+#define HNS3_PMU_EVT_PPS_RD_FBD_PACKET_NUM             0x0010b
+#define HNS3_PMU_EVT_PPS_RD_FBD_TIME                   0x1010b
+#define HNS3_PMU_EVT_PPS_RD_EBD_PACKET_NUM             0x0010c
+#define HNS3_PMU_EVT_PPS_RD_EBD_TIME                   0x1010c
+#define HNS3_PMU_EVT_PPS_RD_PAY_M0_PACKET_NUM          0x0010d
+#define HNS3_PMU_EVT_PPS_RD_PAY_M0_TIME                        0x1010d
+#define HNS3_PMU_EVT_PPS_RD_PAY_M1_PACKET_NUM          0x0010e
+#define HNS3_PMU_EVT_PPS_RD_PAY_M1_TIME                        0x1010e
+#define HNS3_PMU_EVT_PPS_WR_PAY_M0_PACKET_NUM          0x0010f
+#define HNS3_PMU_EVT_PPS_WR_PAY_M0_TIME                        0x1010f
+#define HNS3_PMU_EVT_PPS_WR_PAY_M1_PACKET_NUM          0x00110
+#define HNS3_PMU_EVT_PPS_WR_PAY_M1_TIME                        0x10110
+#define HNS3_PMU_EVT_PPS_NICROH_TX_PRE_PACKET_NUM      0x00111
+#define HNS3_PMU_EVT_PPS_NICROH_TX_PRE_TIME            0x10111
+#define HNS3_PMU_EVT_PPS_NICROH_RX_PRE_PACKET_NUM      0x00112
+#define HNS3_PMU_EVT_PPS_NICROH_RX_PRE_TIME            0x10112
+
+/* latency events */
+#define HNS3_PMU_EVT_DLY_TX_PUSH_TIME                  0x00202
+#define HNS3_PMU_EVT_DLY_TX_PUSH_PACKET_NUM            0x10202
+#define HNS3_PMU_EVT_DLY_TX_TIME                       0x00204
+#define HNS3_PMU_EVT_DLY_TX_PACKET_NUM                 0x10204
+#define HNS3_PMU_EVT_DLY_SSU_TX_NIC_TIME               0x00206
+#define HNS3_PMU_EVT_DLY_SSU_TX_NIC_PACKET_NUM         0x10206
+#define HNS3_PMU_EVT_DLY_SSU_TX_ROCE_TIME              0x00207
+#define HNS3_PMU_EVT_DLY_SSU_TX_ROCE_PACKET_NUM                0x10207
+#define HNS3_PMU_EVT_DLY_SSU_RX_NIC_TIME               0x00208
+#define HNS3_PMU_EVT_DLY_SSU_RX_NIC_PACKET_NUM         0x10208
+#define HNS3_PMU_EVT_DLY_SSU_RX_ROCE_TIME              0x00209
+#define HNS3_PMU_EVT_DLY_SSU_RX_ROCE_PACKET_NUM                0x10209
+#define HNS3_PMU_EVT_DLY_RPU_TIME                      0x0020e
+#define HNS3_PMU_EVT_DLY_RPU_PACKET_NUM                        0x1020e
+#define HNS3_PMU_EVT_DLY_TPU_TIME                      0x0020f
+#define HNS3_PMU_EVT_DLY_TPU_PACKET_NUM                        0x1020f
+#define HNS3_PMU_EVT_DLY_RPE_TIME                      0x00210
+#define HNS3_PMU_EVT_DLY_RPE_PACKET_NUM                        0x10210
+#define HNS3_PMU_EVT_DLY_TPE_TIME                      0x00211
+#define HNS3_PMU_EVT_DLY_TPE_PACKET_NUM                        0x10211
+#define HNS3_PMU_EVT_DLY_TPE_PUSH_TIME                 0x00212
+#define HNS3_PMU_EVT_DLY_TPE_PUSH_PACKET_NUM           0x10212
+#define HNS3_PMU_EVT_DLY_WR_FBD_TIME                   0x00213
+#define HNS3_PMU_EVT_DLY_WR_FBD_PACKET_NUM             0x10213
+#define HNS3_PMU_EVT_DLY_WR_EBD_TIME                   0x00214
+#define HNS3_PMU_EVT_DLY_WR_EBD_PACKET_NUM             0x10214
+#define HNS3_PMU_EVT_DLY_RD_FBD_TIME                   0x00215
+#define HNS3_PMU_EVT_DLY_RD_FBD_PACKET_NUM             0x10215
+#define HNS3_PMU_EVT_DLY_RD_EBD_TIME                   0x00216
+#define HNS3_PMU_EVT_DLY_RD_EBD_PACKET_NUM             0x10216
+#define HNS3_PMU_EVT_DLY_RD_PAY_M0_TIME                        0x00217
+#define HNS3_PMU_EVT_DLY_RD_PAY_M0_PACKET_NUM          0x10217
+#define HNS3_PMU_EVT_DLY_RD_PAY_M1_TIME                        0x00218
+#define HNS3_PMU_EVT_DLY_RD_PAY_M1_PACKET_NUM          0x10218
+#define HNS3_PMU_EVT_DLY_WR_PAY_M0_TIME                        0x00219
+#define HNS3_PMU_EVT_DLY_WR_PAY_M0_PACKET_NUM          0x10219
+#define HNS3_PMU_EVT_DLY_WR_PAY_M1_TIME                        0x0021a
+#define HNS3_PMU_EVT_DLY_WR_PAY_M1_PACKET_NUM          0x1021a
+#define HNS3_PMU_EVT_DLY_MSIX_WRITE_TIME               0x0021c
+#define HNS3_PMU_EVT_DLY_MSIX_WRITE_PACKET_NUM         0x1021c
+
+/* interrupt rate events */
+#define HNS3_PMU_EVT_PPS_MSIX_NIC_INTR_NUM             0x00300
+#define HNS3_PMU_EVT_PPS_MSIX_NIC_TIME                 0x10300
+
+/* filter mode supported by each bandwidth event */
+#define HNS3_PMU_FILTER_BW_SSU_EGU             0x07
+#define HNS3_PMU_FILTER_BW_SSU_RPU             0x1f
+#define HNS3_PMU_FILTER_BW_SSU_ROCE            0x0f
+#define HNS3_PMU_FILTER_BW_ROCE_SSU            0x0f
+#define HNS3_PMU_FILTER_BW_TPU_SSU             0x1f
+#define HNS3_PMU_FILTER_BW_RPU_RCBRX           0x11
+#define HNS3_PMU_FILTER_BW_RCBTX_TXSCH         0x11
+#define HNS3_PMU_FILTER_BW_WR_FBD              0x1b
+#define HNS3_PMU_FILTER_BW_WR_EBD              0x11
+#define HNS3_PMU_FILTER_BW_RD_FBD              0x01
+#define HNS3_PMU_FILTER_BW_RD_EBD              0x1b
+#define HNS3_PMU_FILTER_BW_RD_PAY_M0           0x01
+#define HNS3_PMU_FILTER_BW_RD_PAY_M1           0x01
+#define HNS3_PMU_FILTER_BW_WR_PAY_M0           0x01
+#define HNS3_PMU_FILTER_BW_WR_PAY_M1           0x01
+
+/* filter mode supported by each packet rate event */
+#define HNS3_PMU_FILTER_PPS_IGU_SSU            0x07
+#define HNS3_PMU_FILTER_PPS_SSU_EGU            0x07
+#define HNS3_PMU_FILTER_PPS_SSU_RPU            0x1f
+#define HNS3_PMU_FILTER_PPS_SSU_ROCE           0x0f
+#define HNS3_PMU_FILTER_PPS_ROCE_SSU           0x0f
+#define HNS3_PMU_FILTER_PPS_TPU_SSU            0x1f
+#define HNS3_PMU_FILTER_PPS_RPU_RCBRX          0x11
+#define HNS3_PMU_FILTER_PPS_RCBTX_TPU          0x1f
+#define HNS3_PMU_FILTER_PPS_RCBTX_TXSCH                0x11
+#define HNS3_PMU_FILTER_PPS_WR_FBD             0x1b
+#define HNS3_PMU_FILTER_PPS_WR_EBD             0x11
+#define HNS3_PMU_FILTER_PPS_RD_FBD             0x01
+#define HNS3_PMU_FILTER_PPS_RD_EBD             0x1b
+#define HNS3_PMU_FILTER_PPS_RD_PAY_M0          0x01
+#define HNS3_PMU_FILTER_PPS_RD_PAY_M1          0x01
+#define HNS3_PMU_FILTER_PPS_WR_PAY_M0          0x01
+#define HNS3_PMU_FILTER_PPS_WR_PAY_M1          0x01
+#define HNS3_PMU_FILTER_PPS_NICROH_TX_PRE      0x01
+#define HNS3_PMU_FILTER_PPS_NICROH_RX_PRE      0x01
+
+/* filter mode supported by each latency event */
+#define HNS3_PMU_FILTER_DLY_TX_PUSH            0x01
+#define HNS3_PMU_FILTER_DLY_TX                 0x01
+#define HNS3_PMU_FILTER_DLY_SSU_TX_NIC         0x07
+#define HNS3_PMU_FILTER_DLY_SSU_TX_ROCE                0x07
+#define HNS3_PMU_FILTER_DLY_SSU_RX_NIC         0x07
+#define HNS3_PMU_FILTER_DLY_SSU_RX_ROCE                0x07
+#define HNS3_PMU_FILTER_DLY_RPU                        0x11
+#define HNS3_PMU_FILTER_DLY_TPU                        0x1f
+#define HNS3_PMU_FILTER_DLY_RPE                        0x01
+#define HNS3_PMU_FILTER_DLY_TPE                        0x0b
+#define HNS3_PMU_FILTER_DLY_TPE_PUSH           0x1b
+#define HNS3_PMU_FILTER_DLY_WR_FBD             0x1b
+#define HNS3_PMU_FILTER_DLY_WR_EBD             0x11
+#define HNS3_PMU_FILTER_DLY_RD_FBD             0x01
+#define HNS3_PMU_FILTER_DLY_RD_EBD             0x1b
+#define HNS3_PMU_FILTER_DLY_RD_PAY_M0          0x01
+#define HNS3_PMU_FILTER_DLY_RD_PAY_M1          0x01
+#define HNS3_PMU_FILTER_DLY_WR_PAY_M0          0x01
+#define HNS3_PMU_FILTER_DLY_WR_PAY_M1          0x01
+#define HNS3_PMU_FILTER_DLY_MSIX_WRITE         0x01
+
+/* filter mode supported by each interrupt rate event */
+#define HNS3_PMU_FILTER_INTR_MSIX_NIC          0x01
+
+enum hns3_pmu_hw_filter_mode {
+       HNS3_PMU_HW_FILTER_GLOBAL,
+       HNS3_PMU_HW_FILTER_PORT,
+       HNS3_PMU_HW_FILTER_PORT_TC,
+       HNS3_PMU_HW_FILTER_FUNC,
+       HNS3_PMU_HW_FILTER_FUNC_QUEUE,
+       HNS3_PMU_HW_FILTER_FUNC_INTR,
+};
+
+struct hns3_pmu_event_attr {
+       u32 event;
+       u16 filter_support;
+};
+
+struct hns3_pmu {
+       struct perf_event *hw_events[HNS3_PMU_MAX_HW_EVENTS];
+       struct hlist_node node;
+       struct pci_dev *pdev;
+       struct pmu pmu;
+       void __iomem *base;
+       int irq;
+       int on_cpu;
+       u32 identifier;
+       u32 hw_clk_freq; /* hardware clock frequency of PMU */
+       /* maximum and minimum bdf allowed by PMU */
+       u16 bdf_min;
+       u16 bdf_max;
+};
+
+#define to_hns3_pmu(p)  (container_of((p), struct hns3_pmu, pmu))
+
+#define GET_PCI_DEVFN(bdf)  ((bdf) & 0xff)
+
+#define FILTER_CONDITION_PORT(port) ((1 << (port)) & 0xff)
+#define FILTER_CONDITION_PORT_TC(port, tc) (((port) << 3) | ((tc) & 0x07))
+#define FILTER_CONDITION_FUNC_INTR(func, intr) (((intr) << 8) | (func))
+
+#define HNS3_PMU_FILTER_ATTR(_name, _config, _start, _end)               \
+       static inline u64 hns3_pmu_get_##_name(struct perf_event *event) \
+       {                                                                \
+               return FIELD_GET(GENMASK_ULL(_end, _start),              \
+                                event->attr._config);                   \
+       }
+
+HNS3_PMU_FILTER_ATTR(subevent, config, 0, 7);
+HNS3_PMU_FILTER_ATTR(event_type, config, 8, 15);
+HNS3_PMU_FILTER_ATTR(ext_counter_used, config, 16, 16);
+HNS3_PMU_FILTER_ATTR(port, config1, 0, 3);
+HNS3_PMU_FILTER_ATTR(tc, config1, 4, 7);
+HNS3_PMU_FILTER_ATTR(bdf, config1, 8, 23);
+HNS3_PMU_FILTER_ATTR(queue, config1, 24, 39);
+HNS3_PMU_FILTER_ATTR(intr, config1, 40, 51);
+HNS3_PMU_FILTER_ATTR(global, config1, 52, 52);
+
+#define HNS3_BW_EVT_BYTE_NUM(_name)    (&(struct hns3_pmu_event_attr) {\
+       HNS3_PMU_EVT_BW_##_name##_BYTE_NUM,                             \
+       HNS3_PMU_FILTER_BW_##_name})
+#define HNS3_BW_EVT_TIME(_name)                (&(struct hns3_pmu_event_attr) {\
+       HNS3_PMU_EVT_BW_##_name##_TIME,                                 \
+       HNS3_PMU_FILTER_BW_##_name})
+#define HNS3_PPS_EVT_PACKET_NUM(_name) (&(struct hns3_pmu_event_attr) {\
+       HNS3_PMU_EVT_PPS_##_name##_PACKET_NUM,                          \
+       HNS3_PMU_FILTER_PPS_##_name})
+#define HNS3_PPS_EVT_TIME(_name)       (&(struct hns3_pmu_event_attr) {\
+       HNS3_PMU_EVT_PPS_##_name##_TIME,                                \
+       HNS3_PMU_FILTER_PPS_##_name})
+#define HNS3_DLY_EVT_TIME(_name)       (&(struct hns3_pmu_event_attr) {\
+       HNS3_PMU_EVT_DLY_##_name##_TIME,                                \
+       HNS3_PMU_FILTER_DLY_##_name})
+#define HNS3_DLY_EVT_PACKET_NUM(_name) (&(struct hns3_pmu_event_attr) {\
+       HNS3_PMU_EVT_DLY_##_name##_PACKET_NUM,                          \
+       HNS3_PMU_FILTER_DLY_##_name})
+#define HNS3_INTR_EVT_INTR_NUM(_name)  (&(struct hns3_pmu_event_attr) {\
+       HNS3_PMU_EVT_PPS_##_name##_INTR_NUM,                            \
+       HNS3_PMU_FILTER_INTR_##_name})
+#define HNS3_INTR_EVT_TIME(_name)      (&(struct hns3_pmu_event_attr) {\
+       HNS3_PMU_EVT_PPS_##_name##_TIME,                                \
+       HNS3_PMU_FILTER_INTR_##_name})
+
+static ssize_t hns3_pmu_format_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       struct dev_ext_attribute *eattr;
+
+       eattr = container_of(attr, struct dev_ext_attribute, attr);
+
+       return sysfs_emit(buf, "%s\n", (char *)eattr->var);
+}
+
+static ssize_t hns3_pmu_event_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct hns3_pmu_event_attr *event;
+       struct dev_ext_attribute *eattr;
+
+       eattr = container_of(attr, struct dev_ext_attribute, attr);
+       event = eattr->var;
+
+       return sysfs_emit(buf, "config=0x%x\n", event->event);
+}
+
+static ssize_t hns3_pmu_filter_mode_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       struct hns3_pmu_event_attr *event;
+       struct dev_ext_attribute *eattr;
+       int len;
+
+       eattr = container_of(attr, struct dev_ext_attribute, attr);
+       event = eattr->var;
+
+       len = sysfs_emit_at(buf, 0, "filter mode supported: ");
+       if (event->filter_support & HNS3_PMU_FILTER_SUPPORT_GLOBAL)
+               len += sysfs_emit_at(buf, len, "global ");
+       if (event->filter_support & HNS3_PMU_FILTER_SUPPORT_PORT)
+               len += sysfs_emit_at(buf, len, "port ");
+       if (event->filter_support & HNS3_PMU_FILTER_SUPPORT_PORT_TC)
+               len += sysfs_emit_at(buf, len, "port-tc ");
+       if (event->filter_support & HNS3_PMU_FILTER_SUPPORT_FUNC)
+               len += sysfs_emit_at(buf, len, "func ");
+       if (event->filter_support & HNS3_PMU_FILTER_SUPPORT_FUNC_QUEUE)
+               len += sysfs_emit_at(buf, len, "func-queue ");
+       if (event->filter_support & HNS3_PMU_FILTER_SUPPORT_FUNC_INTR)
+               len += sysfs_emit_at(buf, len, "func-intr ");
+
+       len += sysfs_emit_at(buf, len, "\n");
+
+       return len;
+}
+
+#define HNS3_PMU_ATTR(_name, _func, _config)                           \
+       (&((struct dev_ext_attribute[]) {                               \
+               { __ATTR(_name, 0444, _func, NULL), (void *)_config }   \
+       })[0].attr.attr)
+
+#define HNS3_PMU_FORMAT_ATTR(_name, _format) \
+       HNS3_PMU_ATTR(_name, hns3_pmu_format_show, (void *)_format)
+#define HNS3_PMU_EVENT_ATTR(_name, _event) \
+       HNS3_PMU_ATTR(_name, hns3_pmu_event_show, (void *)_event)
+#define HNS3_PMU_FLT_MODE_ATTR(_name, _event) \
+       HNS3_PMU_ATTR(_name, hns3_pmu_filter_mode_show, (void *)_event)
+
+#define HNS3_PMU_BW_EVT_PAIR(_name, _macro) \
+       HNS3_PMU_EVENT_ATTR(_name##_byte_num, HNS3_BW_EVT_BYTE_NUM(_macro)), \
+       HNS3_PMU_EVENT_ATTR(_name##_time, HNS3_BW_EVT_TIME(_macro))
+#define HNS3_PMU_PPS_EVT_PAIR(_name, _macro) \
+       HNS3_PMU_EVENT_ATTR(_name##_packet_num, HNS3_PPS_EVT_PACKET_NUM(_macro)), \
+       HNS3_PMU_EVENT_ATTR(_name##_time, HNS3_PPS_EVT_TIME(_macro))
+#define HNS3_PMU_DLY_EVT_PAIR(_name, _macro) \
+       HNS3_PMU_EVENT_ATTR(_name##_time, HNS3_DLY_EVT_TIME(_macro)), \
+       HNS3_PMU_EVENT_ATTR(_name##_packet_num, HNS3_DLY_EVT_PACKET_NUM(_macro))
+#define HNS3_PMU_INTR_EVT_PAIR(_name, _macro) \
+       HNS3_PMU_EVENT_ATTR(_name##_intr_num, HNS3_INTR_EVT_INTR_NUM(_macro)), \
+       HNS3_PMU_EVENT_ATTR(_name##_time, HNS3_INTR_EVT_TIME(_macro))
+
+#define HNS3_PMU_BW_FLT_MODE_PAIR(_name, _macro) \
+       HNS3_PMU_FLT_MODE_ATTR(_name##_byte_num, HNS3_BW_EVT_BYTE_NUM(_macro)), \
+       HNS3_PMU_FLT_MODE_ATTR(_name##_time, HNS3_BW_EVT_TIME(_macro))
+#define HNS3_PMU_PPS_FLT_MODE_PAIR(_name, _macro) \
+       HNS3_PMU_FLT_MODE_ATTR(_name##_packet_num, HNS3_PPS_EVT_PACKET_NUM(_macro)), \
+       HNS3_PMU_FLT_MODE_ATTR(_name##_time, HNS3_PPS_EVT_TIME(_macro))
+#define HNS3_PMU_DLY_FLT_MODE_PAIR(_name, _macro) \
+       HNS3_PMU_FLT_MODE_ATTR(_name##_time, HNS3_DLY_EVT_TIME(_macro)), \
+       HNS3_PMU_FLT_MODE_ATTR(_name##_packet_num, HNS3_DLY_EVT_PACKET_NUM(_macro))
+#define HNS3_PMU_INTR_FLT_MODE_PAIR(_name, _macro) \
+       HNS3_PMU_FLT_MODE_ATTR(_name##_intr_num, HNS3_INTR_EVT_INTR_NUM(_macro)), \
+       HNS3_PMU_FLT_MODE_ATTR(_name##_time, HNS3_INTR_EVT_TIME(_macro))
+
+static u8 hns3_pmu_hw_filter_modes[] = {
+       HNS3_PMU_HW_FILTER_GLOBAL,
+       HNS3_PMU_HW_FILTER_PORT,
+       HNS3_PMU_HW_FILTER_PORT_TC,
+       HNS3_PMU_HW_FILTER_FUNC,
+       HNS3_PMU_HW_FILTER_FUNC_QUEUE,
+       HNS3_PMU_HW_FILTER_FUNC_INTR,
+};
+
+#define HNS3_PMU_SET_HW_FILTER(_hwc, _mode) \
+       ((_hwc)->addr_filters = (void *)&hns3_pmu_hw_filter_modes[(_mode)])
+
+static ssize_t identifier_show(struct device *dev,
+                              struct device_attribute *attr, char *buf)
+{
+       struct hns3_pmu *hns3_pmu = to_hns3_pmu(dev_get_drvdata(dev));
+
+       return sysfs_emit(buf, "0x%x\n", hns3_pmu->identifier);
+}
+static DEVICE_ATTR_RO(identifier);
+
+static ssize_t cpumask_show(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+{
+       struct hns3_pmu *hns3_pmu = to_hns3_pmu(dev_get_drvdata(dev));
+
+       return sysfs_emit(buf, "%d\n", hns3_pmu->on_cpu);
+}
+static DEVICE_ATTR_RO(cpumask);
+
+static ssize_t bdf_min_show(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+{
+       struct hns3_pmu *hns3_pmu = to_hns3_pmu(dev_get_drvdata(dev));
+       u16 bdf = hns3_pmu->bdf_min;
+
+       return sysfs_emit(buf, "%02x:%02x.%x\n", PCI_BUS_NUM(bdf),
+                         PCI_SLOT(bdf), PCI_FUNC(bdf));
+}
+static DEVICE_ATTR_RO(bdf_min);
+
+static ssize_t bdf_max_show(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+{
+       struct hns3_pmu *hns3_pmu = to_hns3_pmu(dev_get_drvdata(dev));
+       u16 bdf = hns3_pmu->bdf_max;
+
+       return sysfs_emit(buf, "%02x:%02x.%x\n", PCI_BUS_NUM(bdf),
+                         PCI_SLOT(bdf), PCI_FUNC(bdf));
+}
+static DEVICE_ATTR_RO(bdf_max);
+
+static ssize_t hw_clk_freq_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct hns3_pmu *hns3_pmu = to_hns3_pmu(dev_get_drvdata(dev));
+
+       return sysfs_emit(buf, "%u\n", hns3_pmu->hw_clk_freq);
+}
+static DEVICE_ATTR_RO(hw_clk_freq);
+
+static struct attribute *hns3_pmu_events_attr[] = {
+       /* bandwidth events */
+       HNS3_PMU_BW_EVT_PAIR(bw_ssu_egu, SSU_EGU),
+       HNS3_PMU_BW_EVT_PAIR(bw_ssu_rpu, SSU_RPU),
+       HNS3_PMU_BW_EVT_PAIR(bw_ssu_roce, SSU_ROCE),
+       HNS3_PMU_BW_EVT_PAIR(bw_roce_ssu, ROCE_SSU),
+       HNS3_PMU_BW_EVT_PAIR(bw_tpu_ssu, TPU_SSU),
+       HNS3_PMU_BW_EVT_PAIR(bw_rpu_rcbrx, RPU_RCBRX),
+       HNS3_PMU_BW_EVT_PAIR(bw_rcbtx_txsch, RCBTX_TXSCH),
+       HNS3_PMU_BW_EVT_PAIR(bw_wr_fbd, WR_FBD),
+       HNS3_PMU_BW_EVT_PAIR(bw_wr_ebd, WR_EBD),
+       HNS3_PMU_BW_EVT_PAIR(bw_rd_fbd, RD_FBD),
+       HNS3_PMU_BW_EVT_PAIR(bw_rd_ebd, RD_EBD),
+       HNS3_PMU_BW_EVT_PAIR(bw_rd_pay_m0, RD_PAY_M0),
+       HNS3_PMU_BW_EVT_PAIR(bw_rd_pay_m1, RD_PAY_M1),
+       HNS3_PMU_BW_EVT_PAIR(bw_wr_pay_m0, WR_PAY_M0),
+       HNS3_PMU_BW_EVT_PAIR(bw_wr_pay_m1, WR_PAY_M1),
+
+       /* packet rate events */
+       HNS3_PMU_PPS_EVT_PAIR(pps_igu_ssu, IGU_SSU),
+       HNS3_PMU_PPS_EVT_PAIR(pps_ssu_egu, SSU_EGU),
+       HNS3_PMU_PPS_EVT_PAIR(pps_ssu_rpu, SSU_RPU),
+       HNS3_PMU_PPS_EVT_PAIR(pps_ssu_roce, SSU_ROCE),
+       HNS3_PMU_PPS_EVT_PAIR(pps_roce_ssu, ROCE_SSU),
+       HNS3_PMU_PPS_EVT_PAIR(pps_tpu_ssu, TPU_SSU),
+       HNS3_PMU_PPS_EVT_PAIR(pps_rpu_rcbrx, RPU_RCBRX),
+       HNS3_PMU_PPS_EVT_PAIR(pps_rcbtx_tpu, RCBTX_TPU),
+       HNS3_PMU_PPS_EVT_PAIR(pps_rcbtx_txsch, RCBTX_TXSCH),
+       HNS3_PMU_PPS_EVT_PAIR(pps_wr_fbd, WR_FBD),
+       HNS3_PMU_PPS_EVT_PAIR(pps_wr_ebd, WR_EBD),
+       HNS3_PMU_PPS_EVT_PAIR(pps_rd_fbd, RD_FBD),
+       HNS3_PMU_PPS_EVT_PAIR(pps_rd_ebd, RD_EBD),
+       HNS3_PMU_PPS_EVT_PAIR(pps_rd_pay_m0, RD_PAY_M0),
+       HNS3_PMU_PPS_EVT_PAIR(pps_rd_pay_m1, RD_PAY_M1),
+       HNS3_PMU_PPS_EVT_PAIR(pps_wr_pay_m0, WR_PAY_M0),
+       HNS3_PMU_PPS_EVT_PAIR(pps_wr_pay_m1, WR_PAY_M1),
+       HNS3_PMU_PPS_EVT_PAIR(pps_intr_nicroh_tx_pre, NICROH_TX_PRE),
+       HNS3_PMU_PPS_EVT_PAIR(pps_intr_nicroh_rx_pre, NICROH_RX_PRE),
+
+       /* latency events */
+       HNS3_PMU_DLY_EVT_PAIR(dly_tx_push_to_mac, TX_PUSH),
+       HNS3_PMU_DLY_EVT_PAIR(dly_tx_normal_to_mac, TX),
+       HNS3_PMU_DLY_EVT_PAIR(dly_ssu_tx_th_nic, SSU_TX_NIC),
+       HNS3_PMU_DLY_EVT_PAIR(dly_ssu_tx_th_roce, SSU_TX_ROCE),
+       HNS3_PMU_DLY_EVT_PAIR(dly_ssu_rx_th_nic, SSU_RX_NIC),
+       HNS3_PMU_DLY_EVT_PAIR(dly_ssu_rx_th_roce, SSU_RX_ROCE),
+       HNS3_PMU_DLY_EVT_PAIR(dly_rpu, RPU),
+       HNS3_PMU_DLY_EVT_PAIR(dly_tpu, TPU),
+       HNS3_PMU_DLY_EVT_PAIR(dly_rpe, RPE),
+       HNS3_PMU_DLY_EVT_PAIR(dly_tpe_normal, TPE),
+       HNS3_PMU_DLY_EVT_PAIR(dly_tpe_push, TPE_PUSH),
+       HNS3_PMU_DLY_EVT_PAIR(dly_wr_fbd, WR_FBD),
+       HNS3_PMU_DLY_EVT_PAIR(dly_wr_ebd, WR_EBD),
+       HNS3_PMU_DLY_EVT_PAIR(dly_rd_fbd, RD_FBD),
+       HNS3_PMU_DLY_EVT_PAIR(dly_rd_ebd, RD_EBD),
+       HNS3_PMU_DLY_EVT_PAIR(dly_rd_pay_m0, RD_PAY_M0),
+       HNS3_PMU_DLY_EVT_PAIR(dly_rd_pay_m1, RD_PAY_M1),
+       HNS3_PMU_DLY_EVT_PAIR(dly_wr_pay_m0, WR_PAY_M0),
+       HNS3_PMU_DLY_EVT_PAIR(dly_wr_pay_m1, WR_PAY_M1),
+       HNS3_PMU_DLY_EVT_PAIR(dly_msix_write, MSIX_WRITE),
+
+       /* interrupt rate events */
+       HNS3_PMU_INTR_EVT_PAIR(pps_intr_msix_nic, MSIX_NIC),
+
+       NULL
+};
+
+static struct attribute *hns3_pmu_filter_mode_attr[] = {
+       /* bandwidth events */
+       HNS3_PMU_BW_FLT_MODE_PAIR(bw_ssu_egu, SSU_EGU),
+       HNS3_PMU_BW_FLT_MODE_PAIR(bw_ssu_rpu, SSU_RPU),
+       HNS3_PMU_BW_FLT_MODE_PAIR(bw_ssu_roce, SSU_ROCE),
+       HNS3_PMU_BW_FLT_MODE_PAIR(bw_roce_ssu, ROCE_SSU),
+       HNS3_PMU_BW_FLT_MODE_PAIR(bw_tpu_ssu, TPU_SSU),
+       HNS3_PMU_BW_FLT_MODE_PAIR(bw_rpu_rcbrx, RPU_RCBRX),
+       HNS3_PMU_BW_FLT_MODE_PAIR(bw_rcbtx_txsch, RCBTX_TXSCH),
+       HNS3_PMU_BW_FLT_MODE_PAIR(bw_wr_fbd, WR_FBD),
+       HNS3_PMU_BW_FLT_MODE_PAIR(bw_wr_ebd, WR_EBD),
+       HNS3_PMU_BW_FLT_MODE_PAIR(bw_rd_fbd, RD_FBD),
+       HNS3_PMU_BW_FLT_MODE_PAIR(bw_rd_ebd, RD_EBD),
+       HNS3_PMU_BW_FLT_MODE_PAIR(bw_rd_pay_m0, RD_PAY_M0),
+       HNS3_PMU_BW_FLT_MODE_PAIR(bw_rd_pay_m1, RD_PAY_M1),
+       HNS3_PMU_BW_FLT_MODE_PAIR(bw_wr_pay_m0, WR_PAY_M0),
+       HNS3_PMU_BW_FLT_MODE_PAIR(bw_wr_pay_m1, WR_PAY_M1),
+
+       /* packet rate events */
+       HNS3_PMU_PPS_FLT_MODE_PAIR(pps_igu_ssu, IGU_SSU),
+       HNS3_PMU_PPS_FLT_MODE_PAIR(pps_ssu_egu, SSU_EGU),
+       HNS3_PMU_PPS_FLT_MODE_PAIR(pps_ssu_rpu, SSU_RPU),
+       HNS3_PMU_PPS_FLT_MODE_PAIR(pps_ssu_roce, SSU_ROCE),
+       HNS3_PMU_PPS_FLT_MODE_PAIR(pps_roce_ssu, ROCE_SSU),
+       HNS3_PMU_PPS_FLT_MODE_PAIR(pps_tpu_ssu, TPU_SSU),
+       HNS3_PMU_PPS_FLT_MODE_PAIR(pps_rpu_rcbrx, RPU_RCBRX),
+       HNS3_PMU_PPS_FLT_MODE_PAIR(pps_rcbtx_tpu, RCBTX_TPU),
+       HNS3_PMU_PPS_FLT_MODE_PAIR(pps_rcbtx_txsch, RCBTX_TXSCH),
+       HNS3_PMU_PPS_FLT_MODE_PAIR(pps_wr_fbd, WR_FBD),
+       HNS3_PMU_PPS_FLT_MODE_PAIR(pps_wr_ebd, WR_EBD),
+       HNS3_PMU_PPS_FLT_MODE_PAIR(pps_rd_fbd, RD_FBD),
+       HNS3_PMU_PPS_FLT_MODE_PAIR(pps_rd_ebd, RD_EBD),
+       HNS3_PMU_PPS_FLT_MODE_PAIR(pps_rd_pay_m0, RD_PAY_M0),
+       HNS3_PMU_PPS_FLT_MODE_PAIR(pps_rd_pay_m1, RD_PAY_M1),
+       HNS3_PMU_PPS_FLT_MODE_PAIR(pps_wr_pay_m0, WR_PAY_M0),
+       HNS3_PMU_PPS_FLT_MODE_PAIR(pps_wr_pay_m1, WR_PAY_M1),
+       HNS3_PMU_PPS_FLT_MODE_PAIR(pps_intr_nicroh_tx_pre, NICROH_TX_PRE),
+       HNS3_PMU_PPS_FLT_MODE_PAIR(pps_intr_nicroh_rx_pre, NICROH_RX_PRE),
+
+       /* latency events */
+       HNS3_PMU_DLY_FLT_MODE_PAIR(dly_tx_push_to_mac, TX_PUSH),
+       HNS3_PMU_DLY_FLT_MODE_PAIR(dly_tx_normal_to_mac, TX),
+       HNS3_PMU_DLY_FLT_MODE_PAIR(dly_ssu_tx_th_nic, SSU_TX_NIC),
+       HNS3_PMU_DLY_FLT_MODE_PAIR(dly_ssu_tx_th_roce, SSU_TX_ROCE),
+       HNS3_PMU_DLY_FLT_MODE_PAIR(dly_ssu_rx_th_nic, SSU_RX_NIC),
+       HNS3_PMU_DLY_FLT_MODE_PAIR(dly_ssu_rx_th_roce, SSU_RX_ROCE),
+       HNS3_PMU_DLY_FLT_MODE_PAIR(dly_rpu, RPU),
+       HNS3_PMU_DLY_FLT_MODE_PAIR(dly_tpu, TPU),
+       HNS3_PMU_DLY_FLT_MODE_PAIR(dly_rpe, RPE),
+       HNS3_PMU_DLY_FLT_MODE_PAIR(dly_tpe_normal, TPE),
+       HNS3_PMU_DLY_FLT_MODE_PAIR(dly_tpe_push, TPE_PUSH),
+       HNS3_PMU_DLY_FLT_MODE_PAIR(dly_wr_fbd, WR_FBD),
+       HNS3_PMU_DLY_FLT_MODE_PAIR(dly_wr_ebd, WR_EBD),
+       HNS3_PMU_DLY_FLT_MODE_PAIR(dly_rd_fbd, RD_FBD),
+       HNS3_PMU_DLY_FLT_MODE_PAIR(dly_rd_ebd, RD_EBD),
+       HNS3_PMU_DLY_FLT_MODE_PAIR(dly_rd_pay_m0, RD_PAY_M0),
+       HNS3_PMU_DLY_FLT_MODE_PAIR(dly_rd_pay_m1, RD_PAY_M1),
+       HNS3_PMU_DLY_FLT_MODE_PAIR(dly_wr_pay_m0, WR_PAY_M0),
+       HNS3_PMU_DLY_FLT_MODE_PAIR(dly_wr_pay_m1, WR_PAY_M1),
+       HNS3_PMU_DLY_FLT_MODE_PAIR(dly_msix_write, MSIX_WRITE),
+
+       /* interrupt rate events */
+       HNS3_PMU_INTR_FLT_MODE_PAIR(pps_intr_msix_nic, MSIX_NIC),
+
+       NULL
+};
+
+static struct attribute_group hns3_pmu_events_group = {
+       .name = "events",
+       .attrs = hns3_pmu_events_attr,
+};
+
+static struct attribute_group hns3_pmu_filter_mode_group = {
+       .name = "filtermode",
+       .attrs = hns3_pmu_filter_mode_attr,
+};
+
+static struct attribute *hns3_pmu_format_attr[] = {
+       HNS3_PMU_FORMAT_ATTR(subevent, "config:0-7"),
+       HNS3_PMU_FORMAT_ATTR(event_type, "config:8-15"),
+       HNS3_PMU_FORMAT_ATTR(ext_counter_used, "config:16"),
+       HNS3_PMU_FORMAT_ATTR(port, "config1:0-3"),
+       HNS3_PMU_FORMAT_ATTR(tc, "config1:4-7"),
+       HNS3_PMU_FORMAT_ATTR(bdf, "config1:8-23"),
+       HNS3_PMU_FORMAT_ATTR(queue, "config1:24-39"),
+       HNS3_PMU_FORMAT_ATTR(intr, "config1:40-51"),
+       HNS3_PMU_FORMAT_ATTR(global, "config1:52"),
+       NULL
+};
+
+static struct attribute_group hns3_pmu_format_group = {
+       .name = "format",
+       .attrs = hns3_pmu_format_attr,
+};
+
+static struct attribute *hns3_pmu_cpumask_attrs[] = {
+       &dev_attr_cpumask.attr,
+       NULL
+};
+
+static struct attribute_group hns3_pmu_cpumask_attr_group = {
+       .attrs = hns3_pmu_cpumask_attrs,
+};
+
+static struct attribute *hns3_pmu_identifier_attrs[] = {
+       &dev_attr_identifier.attr,
+       NULL
+};
+
+static struct attribute_group hns3_pmu_identifier_attr_group = {
+       .attrs = hns3_pmu_identifier_attrs,
+};
+
+static struct attribute *hns3_pmu_bdf_range_attrs[] = {
+       &dev_attr_bdf_min.attr,
+       &dev_attr_bdf_max.attr,
+       NULL
+};
+
+static struct attribute_group hns3_pmu_bdf_range_attr_group = {
+       .attrs = hns3_pmu_bdf_range_attrs,
+};
+
+static struct attribute *hns3_pmu_hw_clk_freq_attrs[] = {
+       &dev_attr_hw_clk_freq.attr,
+       NULL
+};
+
+static struct attribute_group hns3_pmu_hw_clk_freq_attr_group = {
+       .attrs = hns3_pmu_hw_clk_freq_attrs,
+};
+
+static const struct attribute_group *hns3_pmu_attr_groups[] = {
+       &hns3_pmu_events_group,
+       &hns3_pmu_filter_mode_group,
+       &hns3_pmu_format_group,
+       &hns3_pmu_cpumask_attr_group,
+       &hns3_pmu_identifier_attr_group,
+       &hns3_pmu_bdf_range_attr_group,
+       &hns3_pmu_hw_clk_freq_attr_group,
+       NULL
+};
+
+static u32 hns3_pmu_get_event(struct perf_event *event)
+{
+       return hns3_pmu_get_ext_counter_used(event) << 16 |
+              hns3_pmu_get_event_type(event) << 8 |
+              hns3_pmu_get_subevent(event);
+}
+
+static u32 hns3_pmu_get_real_event(struct perf_event *event)
+{
+       return hns3_pmu_get_event_type(event) << 8 |
+              hns3_pmu_get_subevent(event);
+}
+
+static u32 hns3_pmu_get_offset(u32 offset, u32 idx)
+{
+       return offset + HNS3_PMU_REG_EVENT_OFFSET +
+              HNS3_PMU_REG_EVENT_SIZE * idx;
+}
+
+static u32 hns3_pmu_readl(struct hns3_pmu *hns3_pmu, u32 reg_offset, u32 idx)
+{
+       u32 offset = hns3_pmu_get_offset(reg_offset, idx);
+
+       return readl(hns3_pmu->base + offset);
+}
+
+static void hns3_pmu_writel(struct hns3_pmu *hns3_pmu, u32 reg_offset, u32 idx,
+                           u32 val)
+{
+       u32 offset = hns3_pmu_get_offset(reg_offset, idx);
+
+       writel(val, hns3_pmu->base + offset);
+}
+
+static u64 hns3_pmu_readq(struct hns3_pmu *hns3_pmu, u32 reg_offset, u32 idx)
+{
+       u32 offset = hns3_pmu_get_offset(reg_offset, idx);
+
+       return readq(hns3_pmu->base + offset);
+}
+
+static void hns3_pmu_writeq(struct hns3_pmu *hns3_pmu, u32 reg_offset, u32 idx,
+                           u64 val)
+{
+       u32 offset = hns3_pmu_get_offset(reg_offset, idx);
+
+       writeq(val, hns3_pmu->base + offset);
+}
+
+static bool hns3_pmu_cmp_event(struct perf_event *target,
+                              struct perf_event *event)
+{
+       return hns3_pmu_get_real_event(target) == hns3_pmu_get_real_event(event);
+}
+
+static int hns3_pmu_find_related_event_idx(struct hns3_pmu *hns3_pmu,
+                                          struct perf_event *event)
+{
+       struct perf_event *sibling;
+       int hw_event_used = 0;
+       int idx;
+
+       for (idx = 0; idx < HNS3_PMU_MAX_HW_EVENTS; idx++) {
+               sibling = hns3_pmu->hw_events[idx];
+               if (!sibling)
+                       continue;
+
+               hw_event_used++;
+
+               if (!hns3_pmu_cmp_event(sibling, event))
+                       continue;
+
+               /* Related events is used in group */
+               if (sibling->group_leader == event->group_leader)
+                       return idx;
+       }
+
+       /* No related event and all hardware events are used up */
+       if (hw_event_used >= HNS3_PMU_MAX_HW_EVENTS)
+               return -EBUSY;
+
+       /* No related event and there is extra hardware events can be use */
+       return -ENOENT;
+}
+
+static int hns3_pmu_get_event_idx(struct hns3_pmu *hns3_pmu)
+{
+       int idx;
+
+       for (idx = 0; idx < HNS3_PMU_MAX_HW_EVENTS; idx++) {
+               if (!hns3_pmu->hw_events[idx])
+                       return idx;
+       }
+
+       return -EBUSY;
+}
+
+static bool hns3_pmu_valid_bdf(struct hns3_pmu *hns3_pmu, u16 bdf)
+{
+       struct pci_dev *pdev;
+
+       if (bdf < hns3_pmu->bdf_min || bdf > hns3_pmu->bdf_max) {
+               pci_err(hns3_pmu->pdev, "Invalid EP device: %#x!\n", bdf);
+               return false;
+       }
+
+       pdev = pci_get_domain_bus_and_slot(pci_domain_nr(hns3_pmu->pdev->bus),
+                                          PCI_BUS_NUM(bdf),
+                                          GET_PCI_DEVFN(bdf));
+       if (!pdev) {
+               pci_err(hns3_pmu->pdev, "Nonexistent EP device: %#x!\n", bdf);
+               return false;
+       }
+
+       pci_dev_put(pdev);
+       return true;
+}
+
+static void hns3_pmu_set_qid_para(struct hns3_pmu *hns3_pmu, u32 idx, u16 bdf,
+                                 u16 queue)
+{
+       u32 val;
+
+       val = GET_PCI_DEVFN(bdf);
+       val |= (u32)queue << HNS3_PMU_QID_PARA_QUEUE_S;
+       hns3_pmu_writel(hns3_pmu, HNS3_PMU_REG_EVENT_QID_PARA, idx, val);
+}
+
+static bool hns3_pmu_qid_req_start(struct hns3_pmu *hns3_pmu, u32 idx)
+{
+       bool queue_id_valid = false;
+       u32 reg_qid_ctrl, val;
+       int err;
+
+       /* enable queue id request */
+       hns3_pmu_writel(hns3_pmu, HNS3_PMU_REG_EVENT_QID_CTRL, idx,
+                       HNS3_PMU_QID_CTRL_REQ_ENABLE);
+
+       reg_qid_ctrl = hns3_pmu_get_offset(HNS3_PMU_REG_EVENT_QID_CTRL, idx);
+       err = readl_poll_timeout(hns3_pmu->base + reg_qid_ctrl, val,
+                                val & HNS3_PMU_QID_CTRL_DONE, 1, 1000);
+       if (err == -ETIMEDOUT) {
+               pci_err(hns3_pmu->pdev, "QID request timeout!\n");
+               goto out;
+       }
+
+       queue_id_valid = !(val & HNS3_PMU_QID_CTRL_MISS);
+
+out:
+       /* disable qid request and clear status */
+       hns3_pmu_writel(hns3_pmu, HNS3_PMU_REG_EVENT_QID_CTRL, idx, 0);
+
+       return queue_id_valid;
+}
+
+static bool hns3_pmu_valid_queue(struct hns3_pmu *hns3_pmu, u32 idx, u16 bdf,
+                                u16 queue)
+{
+       hns3_pmu_set_qid_para(hns3_pmu, idx, bdf, queue);
+
+       return hns3_pmu_qid_req_start(hns3_pmu, idx);
+}
+
+static struct hns3_pmu_event_attr *hns3_pmu_get_pmu_event(u32 event)
+{
+       struct hns3_pmu_event_attr *pmu_event;
+       struct dev_ext_attribute *eattr;
+       struct device_attribute *dattr;
+       struct attribute *attr;
+       u32 i;
+
+       for (i = 0; i < ARRAY_SIZE(hns3_pmu_events_attr) - 1; i++) {
+               attr = hns3_pmu_events_attr[i];
+               dattr = container_of(attr, struct device_attribute, attr);
+               eattr = container_of(dattr, struct dev_ext_attribute, attr);
+               pmu_event = eattr->var;
+
+               if (event == pmu_event->event)
+                       return pmu_event;
+       }
+
+       return NULL;
+}
+
+static int hns3_pmu_set_func_mode(struct perf_event *event,
+                                 struct hns3_pmu *hns3_pmu)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       u16 bdf = hns3_pmu_get_bdf(event);
+
+       if (!hns3_pmu_valid_bdf(hns3_pmu, bdf))
+               return -ENOENT;
+
+       HNS3_PMU_SET_HW_FILTER(hwc, HNS3_PMU_HW_FILTER_FUNC);
+
+       return 0;
+}
+
+static int hns3_pmu_set_func_queue_mode(struct perf_event *event,
+                                       struct hns3_pmu *hns3_pmu)
+{
+       u16 queue_id = hns3_pmu_get_queue(event);
+       struct hw_perf_event *hwc = &event->hw;
+       u16 bdf = hns3_pmu_get_bdf(event);
+
+       if (!hns3_pmu_valid_bdf(hns3_pmu, bdf))
+               return -ENOENT;
+
+       if (!hns3_pmu_valid_queue(hns3_pmu, hwc->idx, bdf, queue_id)) {
+               pci_err(hns3_pmu->pdev, "Invalid queue: %u\n", queue_id);
+               return -ENOENT;
+       }
+
+       HNS3_PMU_SET_HW_FILTER(hwc, HNS3_PMU_HW_FILTER_FUNC_QUEUE);
+
+       return 0;
+}
+
+static bool
+hns3_pmu_is_enabled_global_mode(struct perf_event *event,
+                               struct hns3_pmu_event_attr *pmu_event)
+{
+       u8 global = hns3_pmu_get_global(event);
+
+       if (!(pmu_event->filter_support & HNS3_PMU_FILTER_SUPPORT_GLOBAL))
+               return false;
+
+       return global;
+}
+
+static bool hns3_pmu_is_enabled_func_mode(struct perf_event *event,
+                                         struct hns3_pmu_event_attr *pmu_event)
+{
+       u16 queue_id = hns3_pmu_get_queue(event);
+       u16 bdf = hns3_pmu_get_bdf(event);
+
+       if (!(pmu_event->filter_support & HNS3_PMU_FILTER_SUPPORT_FUNC))
+               return false;
+       else if (queue_id != HNS3_PMU_FILTER_ALL_QUEUE)
+               return false;
+
+       return bdf;
+}
+
+static bool
+hns3_pmu_is_enabled_func_queue_mode(struct perf_event *event,
+                                   struct hns3_pmu_event_attr *pmu_event)
+{
+       u16 queue_id = hns3_pmu_get_queue(event);
+       u16 bdf = hns3_pmu_get_bdf(event);
+
+       if (!(pmu_event->filter_support & HNS3_PMU_FILTER_SUPPORT_FUNC_QUEUE))
+               return false;
+       else if (queue_id == HNS3_PMU_FILTER_ALL_QUEUE)
+               return false;
+
+       return bdf;
+}
+
+static bool hns3_pmu_is_enabled_port_mode(struct perf_event *event,
+                                         struct hns3_pmu_event_attr *pmu_event)
+{
+       u8 tc_id = hns3_pmu_get_tc(event);
+
+       if (!(pmu_event->filter_support & HNS3_PMU_FILTER_SUPPORT_PORT))
+               return false;
+
+       return tc_id == HNS3_PMU_FILTER_ALL_TC;
+}
+
+static bool
+hns3_pmu_is_enabled_port_tc_mode(struct perf_event *event,
+                                struct hns3_pmu_event_attr *pmu_event)
+{
+       u8 tc_id = hns3_pmu_get_tc(event);
+
+       if (!(pmu_event->filter_support & HNS3_PMU_FILTER_SUPPORT_PORT_TC))
+               return false;
+
+       return tc_id != HNS3_PMU_FILTER_ALL_TC;
+}
+
+static bool
+hns3_pmu_is_enabled_func_intr_mode(struct perf_event *event,
+                                  struct hns3_pmu *hns3_pmu,
+                                  struct hns3_pmu_event_attr *pmu_event)
+{
+       u16 bdf = hns3_pmu_get_bdf(event);
+
+       if (!(pmu_event->filter_support & HNS3_PMU_FILTER_SUPPORT_FUNC_INTR))
+               return false;
+
+       return hns3_pmu_valid_bdf(hns3_pmu, bdf);
+}
+
+static int hns3_pmu_select_filter_mode(struct perf_event *event,
+                                      struct hns3_pmu *hns3_pmu)
+{
+       u32 event_id = hns3_pmu_get_event(event);
+       struct hw_perf_event *hwc = &event->hw;
+       struct hns3_pmu_event_attr *pmu_event;
+
+       pmu_event = hns3_pmu_get_pmu_event(event_id);
+       if (!pmu_event) {
+               pci_err(hns3_pmu->pdev, "Invalid pmu event\n");
+               return -ENOENT;
+       }
+
+       if (hns3_pmu_is_enabled_global_mode(event, pmu_event)) {
+               HNS3_PMU_SET_HW_FILTER(hwc, HNS3_PMU_HW_FILTER_GLOBAL);
+               return 0;
+       }
+
+       if (hns3_pmu_is_enabled_func_mode(event, pmu_event))
+               return hns3_pmu_set_func_mode(event, hns3_pmu);
+
+       if (hns3_pmu_is_enabled_func_queue_mode(event, pmu_event))
+               return hns3_pmu_set_func_queue_mode(event, hns3_pmu);
+
+       if (hns3_pmu_is_enabled_port_mode(event, pmu_event)) {
+               HNS3_PMU_SET_HW_FILTER(hwc, HNS3_PMU_HW_FILTER_PORT);
+               return 0;
+       }
+
+       if (hns3_pmu_is_enabled_port_tc_mode(event, pmu_event)) {
+               HNS3_PMU_SET_HW_FILTER(hwc, HNS3_PMU_HW_FILTER_PORT_TC);
+               return 0;
+       }
+
+       if (hns3_pmu_is_enabled_func_intr_mode(event, hns3_pmu, pmu_event)) {
+               HNS3_PMU_SET_HW_FILTER(hwc, HNS3_PMU_HW_FILTER_FUNC_INTR);
+               return 0;
+       }
+
+       return -ENOENT;
+}
+
+static bool hns3_pmu_validate_event_group(struct perf_event *event)
+{
+       struct perf_event *sibling, *leader = event->group_leader;
+       struct perf_event *event_group[HNS3_PMU_MAX_HW_EVENTS];
+       int counters = 1;
+       int num;
+
+       event_group[0] = leader;
+       if (!is_software_event(leader)) {
+               if (leader->pmu != event->pmu)
+                       return false;
+
+               if (leader != event && !hns3_pmu_cmp_event(leader, event))
+                       event_group[counters++] = event;
+       }
+
+       for_each_sibling_event(sibling, event->group_leader) {
+               if (is_software_event(sibling))
+                       continue;
+
+               if (sibling->pmu != event->pmu)
+                       return false;
+
+               for (num = 0; num < counters; num++) {
+                       if (hns3_pmu_cmp_event(event_group[num], sibling))
+                               break;
+               }
+
+               if (num == counters)
+                       event_group[counters++] = sibling;
+       }
+
+       return counters <= HNS3_PMU_MAX_HW_EVENTS;
+}
+
+static u32 hns3_pmu_get_filter_condition(struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       u16 intr_id = hns3_pmu_get_intr(event);
+       u8 port_id = hns3_pmu_get_port(event);
+       u16 bdf = hns3_pmu_get_bdf(event);
+       u8 tc_id = hns3_pmu_get_tc(event);
+       u8 filter_mode;
+
+       filter_mode = *(u8 *)hwc->addr_filters;
+       switch (filter_mode) {
+       case HNS3_PMU_HW_FILTER_PORT:
+               return FILTER_CONDITION_PORT(port_id);
+       case HNS3_PMU_HW_FILTER_PORT_TC:
+               return FILTER_CONDITION_PORT_TC(port_id, tc_id);
+       case HNS3_PMU_HW_FILTER_FUNC:
+       case HNS3_PMU_HW_FILTER_FUNC_QUEUE:
+               return GET_PCI_DEVFN(bdf);
+       case HNS3_PMU_HW_FILTER_FUNC_INTR:
+               return FILTER_CONDITION_FUNC_INTR(GET_PCI_DEVFN(bdf), intr_id);
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static void hns3_pmu_config_filter(struct perf_event *event)
+{
+       struct hns3_pmu *hns3_pmu = to_hns3_pmu(event->pmu);
+       u8 event_type = hns3_pmu_get_event_type(event);
+       u8 subevent_id = hns3_pmu_get_subevent(event);
+       u16 queue_id = hns3_pmu_get_queue(event);
+       struct hw_perf_event *hwc = &event->hw;
+       u8 filter_mode = *(u8 *)hwc->addr_filters;
+       u16 bdf = hns3_pmu_get_bdf(event);
+       u32 idx = hwc->idx;
+       u32 val;
+
+       val = event_type;
+       val |= subevent_id << HNS3_PMU_CTRL_SUBEVENT_S;
+       val |= filter_mode << HNS3_PMU_CTRL_FILTER_MODE_S;
+       val |= HNS3_PMU_EVENT_OVERFLOW_RESTART;
+       hns3_pmu_writel(hns3_pmu, HNS3_PMU_REG_EVENT_CTRL_LOW, idx, val);
+
+       val = hns3_pmu_get_filter_condition(event);
+       hns3_pmu_writel(hns3_pmu, HNS3_PMU_REG_EVENT_CTRL_HIGH, idx, val);
+
+       if (filter_mode == HNS3_PMU_HW_FILTER_FUNC_QUEUE)
+               hns3_pmu_set_qid_para(hns3_pmu, idx, bdf, queue_id);
+}
+
+static void hns3_pmu_enable_counter(struct hns3_pmu *hns3_pmu,
+                                   struct hw_perf_event *hwc)
+{
+       u32 idx = hwc->idx;
+       u32 val;
+
+       val = hns3_pmu_readl(hns3_pmu, HNS3_PMU_REG_EVENT_CTRL_LOW, idx);
+       val |= HNS3_PMU_EVENT_EN;
+       hns3_pmu_writel(hns3_pmu, HNS3_PMU_REG_EVENT_CTRL_LOW, idx, val);
+}
+
+static void hns3_pmu_disable_counter(struct hns3_pmu *hns3_pmu,
+                                    struct hw_perf_event *hwc)
+{
+       u32 idx = hwc->idx;
+       u32 val;
+
+       val = hns3_pmu_readl(hns3_pmu, HNS3_PMU_REG_EVENT_CTRL_LOW, idx);
+       val &= ~HNS3_PMU_EVENT_EN;
+       hns3_pmu_writel(hns3_pmu, HNS3_PMU_REG_EVENT_CTRL_LOW, idx, val);
+}
+
+static void hns3_pmu_enable_intr(struct hns3_pmu *hns3_pmu,
+                                struct hw_perf_event *hwc)
+{
+       u32 idx = hwc->idx;
+       u32 val;
+
+       val = hns3_pmu_readl(hns3_pmu, HNS3_PMU_REG_EVENT_INTR_MASK, idx);
+       val &= ~HNS3_PMU_INTR_MASK_OVERFLOW;
+       hns3_pmu_writel(hns3_pmu, HNS3_PMU_REG_EVENT_INTR_MASK, idx, val);
+}
+
+static void hns3_pmu_disable_intr(struct hns3_pmu *hns3_pmu,
+                                 struct hw_perf_event *hwc)
+{
+       u32 idx = hwc->idx;
+       u32 val;
+
+       val = hns3_pmu_readl(hns3_pmu, HNS3_PMU_REG_EVENT_INTR_MASK, idx);
+       val |= HNS3_PMU_INTR_MASK_OVERFLOW;
+       hns3_pmu_writel(hns3_pmu, HNS3_PMU_REG_EVENT_INTR_MASK, idx, val);
+}
+
+static void hns3_pmu_clear_intr_status(struct hns3_pmu *hns3_pmu, u32 idx)
+{
+       u32 val;
+
+       val = hns3_pmu_readl(hns3_pmu, HNS3_PMU_REG_EVENT_CTRL_LOW, idx);
+       val |= HNS3_PMU_EVENT_STATUS_RESET;
+       hns3_pmu_writel(hns3_pmu, HNS3_PMU_REG_EVENT_CTRL_LOW, idx, val);
+
+       val = hns3_pmu_readl(hns3_pmu, HNS3_PMU_REG_EVENT_CTRL_LOW, idx);
+       val &= ~HNS3_PMU_EVENT_STATUS_RESET;
+       hns3_pmu_writel(hns3_pmu, HNS3_PMU_REG_EVENT_CTRL_LOW, idx, val);
+}
+
+static u64 hns3_pmu_read_counter(struct perf_event *event)
+{
+       struct hns3_pmu *hns3_pmu = to_hns3_pmu(event->pmu);
+
+       return hns3_pmu_readq(hns3_pmu, event->hw.event_base, event->hw.idx);
+}
+
+static void hns3_pmu_write_counter(struct perf_event *event, u64 value)
+{
+       struct hns3_pmu *hns3_pmu = to_hns3_pmu(event->pmu);
+       u32 idx = event->hw.idx;
+
+       hns3_pmu_writeq(hns3_pmu, HNS3_PMU_REG_EVENT_COUNTER, idx, value);
+       hns3_pmu_writeq(hns3_pmu, HNS3_PMU_REG_EVENT_EXT_COUNTER, idx, value);
+}
+
+static void hns3_pmu_init_counter(struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       local64_set(&hwc->prev_count, 0);
+       hns3_pmu_write_counter(event, 0);
+}
+
+static int hns3_pmu_event_init(struct perf_event *event)
+{
+       struct hns3_pmu *hns3_pmu = to_hns3_pmu(event->pmu);
+       struct hw_perf_event *hwc = &event->hw;
+       int idx;
+       int ret;
+
+       if (event->attr.type != event->pmu->type)
+               return -ENOENT;
+
+       /* Sampling is not supported */
+       if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
+               return -EOPNOTSUPP;
+
+       event->cpu = hns3_pmu->on_cpu;
+
+       idx = hns3_pmu_get_event_idx(hns3_pmu);
+       if (idx < 0) {
+               pci_err(hns3_pmu->pdev, "Up to %u events are supported!\n",
+                       HNS3_PMU_MAX_HW_EVENTS);
+               return -EBUSY;
+       }
+
+       hwc->idx = idx;
+
+       ret = hns3_pmu_select_filter_mode(event, hns3_pmu);
+       if (ret) {
+               pci_err(hns3_pmu->pdev, "Invalid filter, ret = %d.\n", ret);
+               return ret;
+       }
+
+       if (!hns3_pmu_validate_event_group(event)) {
+               pci_err(hns3_pmu->pdev, "Invalid event group.\n");
+               return -EINVAL;
+       }
+
+       if (hns3_pmu_get_ext_counter_used(event))
+               hwc->event_base = HNS3_PMU_REG_EVENT_EXT_COUNTER;
+       else
+               hwc->event_base = HNS3_PMU_REG_EVENT_COUNTER;
+
+       return 0;
+}
+
+static void hns3_pmu_read(struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       u64 new_cnt, prev_cnt, delta;
+
+       do {
+               prev_cnt = local64_read(&hwc->prev_count);
+               new_cnt = hns3_pmu_read_counter(event);
+       } while (local64_cmpxchg(&hwc->prev_count, prev_cnt, new_cnt) !=
+                prev_cnt);
+
+       delta = new_cnt - prev_cnt;
+       local64_add(delta, &event->count);
+}
+
+static void hns3_pmu_start(struct perf_event *event, int flags)
+{
+       struct hns3_pmu *hns3_pmu = to_hns3_pmu(event->pmu);
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED)))
+               return;
+
+       WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
+       hwc->state = 0;
+
+       hns3_pmu_config_filter(event);
+       hns3_pmu_init_counter(event);
+       hns3_pmu_enable_intr(hns3_pmu, hwc);
+       hns3_pmu_enable_counter(hns3_pmu, hwc);
+
+       perf_event_update_userpage(event);
+}
+
+static void hns3_pmu_stop(struct perf_event *event, int flags)
+{
+       struct hns3_pmu *hns3_pmu = to_hns3_pmu(event->pmu);
+       struct hw_perf_event *hwc = &event->hw;
+
+       hns3_pmu_disable_counter(hns3_pmu, hwc);
+       hns3_pmu_disable_intr(hns3_pmu, hwc);
+
+       WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
+       hwc->state |= PERF_HES_STOPPED;
+
+       if (hwc->state & PERF_HES_UPTODATE)
+               return;
+
+       /* Read hardware counter and update the perf counter statistics */
+       hns3_pmu_read(event);
+       hwc->state |= PERF_HES_UPTODATE;
+}
+
+static int hns3_pmu_add(struct perf_event *event, int flags)
+{
+       struct hns3_pmu *hns3_pmu = to_hns3_pmu(event->pmu);
+       struct hw_perf_event *hwc = &event->hw;
+       int idx;
+
+       hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
+
+       /* Check all working events to find a related event. */
+       idx = hns3_pmu_find_related_event_idx(hns3_pmu, event);
+       if (idx < 0 && idx != -ENOENT)
+               return idx;
+
+       /* Current event shares an enabled hardware event with related event */
+       if (idx >= 0 && idx < HNS3_PMU_MAX_HW_EVENTS) {
+               hwc->idx = idx;
+               goto start_count;
+       }
+
+       idx = hns3_pmu_get_event_idx(hns3_pmu);
+       if (idx < 0)
+               return idx;
+
+       hwc->idx = idx;
+       hns3_pmu->hw_events[idx] = event;
+
+start_count:
+       if (flags & PERF_EF_START)
+               hns3_pmu_start(event, PERF_EF_RELOAD);
+
+       return 0;
+}
+
+static void hns3_pmu_del(struct perf_event *event, int flags)
+{
+       struct hns3_pmu *hns3_pmu = to_hns3_pmu(event->pmu);
+       struct hw_perf_event *hwc = &event->hw;
+
+       hns3_pmu_stop(event, PERF_EF_UPDATE);
+       hns3_pmu->hw_events[hwc->idx] = NULL;
+       perf_event_update_userpage(event);
+}
+
+static void hns3_pmu_enable(struct pmu *pmu)
+{
+       struct hns3_pmu *hns3_pmu = to_hns3_pmu(pmu);
+       u32 val;
+
+       val = readl(hns3_pmu->base + HNS3_PMU_REG_GLOBAL_CTRL);
+       val |= HNS3_PMU_GLOBAL_START;
+       writel(val, hns3_pmu->base + HNS3_PMU_REG_GLOBAL_CTRL);
+}
+
+static void hns3_pmu_disable(struct pmu *pmu)
+{
+       struct hns3_pmu *hns3_pmu = to_hns3_pmu(pmu);
+       u32 val;
+
+       val = readl(hns3_pmu->base + HNS3_PMU_REG_GLOBAL_CTRL);
+       val &= ~HNS3_PMU_GLOBAL_START;
+       writel(val, hns3_pmu->base + HNS3_PMU_REG_GLOBAL_CTRL);
+}
+
+static int hns3_pmu_alloc_pmu(struct pci_dev *pdev, struct hns3_pmu *hns3_pmu)
+{
+       u16 device_id;
+       char *name;
+       u32 val;
+
+       hns3_pmu->base = pcim_iomap_table(pdev)[BAR_2];
+       if (!hns3_pmu->base) {
+               pci_err(pdev, "ioremap failed\n");
+               return -ENOMEM;
+       }
+
+       hns3_pmu->hw_clk_freq = readl(hns3_pmu->base + HNS3_PMU_REG_CLOCK_FREQ);
+
+       val = readl(hns3_pmu->base + HNS3_PMU_REG_BDF);
+       hns3_pmu->bdf_min = val & 0xffff;
+       hns3_pmu->bdf_max = val >> 16;
+
+       val = readl(hns3_pmu->base + HNS3_PMU_REG_DEVICE_ID);
+       device_id = val & 0xffff;
+       name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hns3_pmu_sicl_%u", device_id);
+       if (!name)
+               return -ENOMEM;
+
+       hns3_pmu->pdev = pdev;
+       hns3_pmu->on_cpu = -1;
+       hns3_pmu->identifier = readl(hns3_pmu->base + HNS3_PMU_REG_VERSION);
+       hns3_pmu->pmu = (struct pmu) {
+               .name           = name,
+               .module         = THIS_MODULE,
+               .event_init     = hns3_pmu_event_init,
+               .pmu_enable     = hns3_pmu_enable,
+               .pmu_disable    = hns3_pmu_disable,
+               .add            = hns3_pmu_add,
+               .del            = hns3_pmu_del,
+               .start          = hns3_pmu_start,
+               .stop           = hns3_pmu_stop,
+               .read           = hns3_pmu_read,
+               .task_ctx_nr    = perf_invalid_context,
+               .attr_groups    = hns3_pmu_attr_groups,
+               .capabilities   = PERF_PMU_CAP_NO_EXCLUDE,
+       };
+
+       return 0;
+}
+
+static irqreturn_t hns3_pmu_irq(int irq, void *data)
+{
+       struct hns3_pmu *hns3_pmu = data;
+       u32 intr_status, idx;
+
+       for (idx = 0; idx < HNS3_PMU_MAX_HW_EVENTS; idx++) {
+               intr_status = hns3_pmu_readl(hns3_pmu,
+                                            HNS3_PMU_REG_EVENT_INTR_STATUS,
+                                            idx);
+
+               /*
+                * As each counter will restart from 0 when it is overflowed,
+                * extra processing is no need, just clear interrupt status.
+                */
+               if (intr_status)
+                       hns3_pmu_clear_intr_status(hns3_pmu, idx);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int hns3_pmu_online_cpu(unsigned int cpu, struct hlist_node *node)
+{
+       struct hns3_pmu *hns3_pmu;
+
+       hns3_pmu = hlist_entry_safe(node, struct hns3_pmu, node);
+       if (!hns3_pmu)
+               return -ENODEV;
+
+       if (hns3_pmu->on_cpu == -1) {
+               hns3_pmu->on_cpu = cpu;
+               irq_set_affinity(hns3_pmu->irq, cpumask_of(cpu));
+       }
+
+       return 0;
+}
+
+static int hns3_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
+{
+       struct hns3_pmu *hns3_pmu;
+       unsigned int target;
+
+       hns3_pmu = hlist_entry_safe(node, struct hns3_pmu, node);
+       if (!hns3_pmu)
+               return -ENODEV;
+
+       /* Nothing to do if this CPU doesn't own the PMU */
+       if (hns3_pmu->on_cpu != cpu)
+               return 0;
+
+       /* Choose a new CPU from all online cpus */
+       target = cpumask_any_but(cpu_online_mask, cpu);
+       if (target >= nr_cpu_ids)
+               return 0;
+
+       perf_pmu_migrate_context(&hns3_pmu->pmu, cpu, target);
+       hns3_pmu->on_cpu = target;
+       irq_set_affinity(hns3_pmu->irq, cpumask_of(target));
+
+       return 0;
+}
+
+static void hns3_pmu_free_irq(void *data)
+{
+       struct pci_dev *pdev = data;
+
+       pci_free_irq_vectors(pdev);
+}
+
+static int hns3_pmu_irq_register(struct pci_dev *pdev,
+                                struct hns3_pmu *hns3_pmu)
+{
+       int irq, ret;
+
+       ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
+       if (ret < 0) {
+               pci_err(pdev, "failed to enable MSI vectors, ret = %d.\n", ret);
+               return ret;
+       }
+
+       ret = devm_add_action(&pdev->dev, hns3_pmu_free_irq, pdev);
+       if (ret) {
+               pci_err(pdev, "failed to add free irq action, ret = %d.\n", ret);
+               return ret;
+       }
+
+       irq = pci_irq_vector(pdev, 0);
+       ret = devm_request_irq(&pdev->dev, irq, hns3_pmu_irq, 0,
+                              hns3_pmu->pmu.name, hns3_pmu);
+       if (ret) {
+               pci_err(pdev, "failed to register irq, ret = %d.\n", ret);
+               return ret;
+       }
+
+       hns3_pmu->irq = irq;
+
+       return 0;
+}
+
+static int hns3_pmu_init_pmu(struct pci_dev *pdev, struct hns3_pmu *hns3_pmu)
+{
+       int ret;
+
+       ret = hns3_pmu_alloc_pmu(pdev, hns3_pmu);
+       if (ret)
+               return ret;
+
+       ret = hns3_pmu_irq_register(pdev, hns3_pmu);
+       if (ret)
+               return ret;
+
+       ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HNS3_PMU_ONLINE,
+                                      &hns3_pmu->node);
+       if (ret) {
+               pci_err(pdev, "failed to register hotplug, ret = %d.\n", ret);
+               return ret;
+       }
+
+       ret = perf_pmu_register(&hns3_pmu->pmu, hns3_pmu->pmu.name, -1);
+       if (ret) {
+               pci_err(pdev, "failed to register perf PMU, ret = %d.\n", ret);
+               cpuhp_state_remove_instance(CPUHP_AP_PERF_ARM_HNS3_PMU_ONLINE,
+                                           &hns3_pmu->node);
+       }
+
+       return ret;
+}
+
+static void hns3_pmu_uninit_pmu(struct pci_dev *pdev)
+{
+       struct hns3_pmu *hns3_pmu = pci_get_drvdata(pdev);
+
+       perf_pmu_unregister(&hns3_pmu->pmu);
+       cpuhp_state_remove_instance(CPUHP_AP_PERF_ARM_HNS3_PMU_ONLINE,
+                                   &hns3_pmu->node);
+}
+
+static int hns3_pmu_init_dev(struct pci_dev *pdev)
+{
+       int ret;
+
+       ret = pcim_enable_device(pdev);
+       if (ret) {
+               pci_err(pdev, "failed to enable pci device, ret = %d.\n", ret);
+               return ret;
+       }
+
+       ret = pcim_iomap_regions(pdev, BIT(BAR_2), "hns3_pmu");
+       if (ret < 0) {
+               pci_err(pdev, "failed to request pci region, ret = %d.\n", ret);
+               return ret;
+       }
+
+       pci_set_master(pdev);
+
+       return 0;
+}
+
+static int hns3_pmu_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+       struct hns3_pmu *hns3_pmu;
+       int ret;
+
+       hns3_pmu = devm_kzalloc(&pdev->dev, sizeof(*hns3_pmu), GFP_KERNEL);
+       if (!hns3_pmu)
+               return -ENOMEM;
+
+       ret = hns3_pmu_init_dev(pdev);
+       if (ret)
+               return ret;
+
+       ret = hns3_pmu_init_pmu(pdev, hns3_pmu);
+       if (ret) {
+               pci_clear_master(pdev);
+               return ret;
+       }
+
+       pci_set_drvdata(pdev, hns3_pmu);
+
+       return ret;
+}
+
+static void hns3_pmu_remove(struct pci_dev *pdev)
+{
+       hns3_pmu_uninit_pmu(pdev);
+       pci_clear_master(pdev);
+       pci_set_drvdata(pdev, NULL);
+}
+
+static const struct pci_device_id hns3_pmu_ids[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, 0xa22b) },
+       { 0, }
+};
+MODULE_DEVICE_TABLE(pci, hns3_pmu_ids);
+
+static struct pci_driver hns3_pmu_driver = {
+       .name = "hns3_pmu",
+       .id_table = hns3_pmu_ids,
+       .probe = hns3_pmu_probe,
+       .remove = hns3_pmu_remove,
+};
+
+static int __init hns3_pmu_module_init(void)
+{
+       int ret;
+
+       ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HNS3_PMU_ONLINE,
+                                     "AP_PERF_ARM_HNS3_PMU_ONLINE",
+                                     hns3_pmu_online_cpu,
+                                     hns3_pmu_offline_cpu);
+       if (ret) {
+               pr_err("failed to setup HNS3 PMU hotplug, ret = %d.\n", ret);
+               return ret;
+       }
+
+       ret = pci_register_driver(&hns3_pmu_driver);
+       if (ret) {
+               pr_err("failed to register pci driver, ret = %d.\n", ret);
+               cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HNS3_PMU_ONLINE);
+       }
+
+       return ret;
+}
+module_init(hns3_pmu_module_init);
+
+static void __exit hns3_pmu_module_exit(void)
+{
+       pci_unregister_driver(&hns3_pmu_driver);
+       cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HNS3_PMU_ONLINE);
+}
+module_exit(hns3_pmu_module_exit);
+
+MODULE_DESCRIPTION("HNS3 PMU driver");
+MODULE_LICENSE("GPL v2");
index 282d3a0..69c3050 100644 (file)
@@ -2,10 +2,6 @@
 /* Marvell CN10K LLC-TAD perf driver
  *
  * Copyright (C) 2021 Marvell
- *
- * 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
- * published by the Free Software Foundation.
  */
 
 #define pr_fmt(fmt) "tad_pmu: " fmt
@@ -18,9 +14,9 @@
 #include <linux/perf_event.h>
 #include <linux/platform_device.h>
 
-#define TAD_PFC_OFFSET         0x0
+#define TAD_PFC_OFFSET         0x800
 #define TAD_PFC(counter)       (TAD_PFC_OFFSET | (counter << 3))
-#define TAD_PRF_OFFSET         0x100
+#define TAD_PRF_OFFSET         0x900
 #define TAD_PRF(counter)       (TAD_PRF_OFFSET | (counter << 3))
 #define TAD_PRF_CNTSEL_MASK    0xFF
 #define TAD_MAX_COUNTERS       8
@@ -100,9 +96,7 @@ static void tad_pmu_event_counter_start(struct perf_event *event, int flags)
         * which sets TAD()_PRF()[CNTSEL] != 0
         */
        for (i = 0; i < tad_pmu->region_cnt; i++) {
-               reg_val = readq_relaxed(tad_pmu->regions[i].base +
-                                       TAD_PRF(counter_idx));
-               reg_val |= (event_idx & 0xFF);
+               reg_val = event_idx & 0xFF;
                writeq_relaxed(reg_val, tad_pmu->regions[i].base +
                               TAD_PRF(counter_idx));
        }
index b2b8d20..2c96183 100644 (file)
@@ -121,7 +121,7 @@ u64 riscv_pmu_event_update(struct perf_event *event)
        return delta;
 }
 
-static void riscv_pmu_stop(struct perf_event *event, int flags)
+void riscv_pmu_stop(struct perf_event *event, int flags)
 {
        struct hw_perf_event *hwc = &event->hw;
        struct riscv_pmu *rvpmu = to_riscv_pmu(event->pmu);
@@ -175,7 +175,7 @@ int riscv_pmu_event_set_period(struct perf_event *event)
        return overflow;
 }
 
-static void riscv_pmu_start(struct perf_event *event, int flags)
+void riscv_pmu_start(struct perf_event *event, int flags)
 {
        struct hw_perf_event *hwc = &event->hw;
        struct riscv_pmu *rvpmu = to_riscv_pmu(event->pmu);
index dca3537..79a3de5 100644 (file)
 #include <linux/irqdomain.h>
 #include <linux/of_irq.h>
 #include <linux/of.h>
+#include <linux/cpu_pm.h>
 
 #include <asm/sbi.h>
 #include <asm/hwcap.h>
 
+PMU_FORMAT_ATTR(event, "config:0-47");
+PMU_FORMAT_ATTR(firmware, "config:63");
+
+static struct attribute *riscv_arch_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_firmware.attr,
+       NULL,
+};
+
+static struct attribute_group riscv_pmu_format_group = {
+       .name = "format",
+       .attrs = riscv_arch_formats_attr,
+};
+
+static const struct attribute_group *riscv_pmu_attr_groups[] = {
+       &riscv_pmu_format_group,
+       NULL,
+};
+
 union sbi_pmu_ctr_info {
        unsigned long value;
        struct {
@@ -666,12 +686,15 @@ static int pmu_sbi_setup_irqs(struct riscv_pmu *pmu, struct platform_device *pde
                child = of_get_compatible_child(cpu, "riscv,cpu-intc");
                if (!child) {
                        pr_err("Failed to find INTC node\n");
+                       of_node_put(cpu);
                        return -ENODEV;
                }
                domain = irq_find_host(child);
                of_node_put(child);
-               if (domain)
+               if (domain) {
+                       of_node_put(cpu);
                        break;
+               }
        }
        if (!domain) {
                pr_err("Failed to find INTC IRQ root domain\n");
@@ -693,6 +716,73 @@ static int pmu_sbi_setup_irqs(struct riscv_pmu *pmu, struct platform_device *pde
        return 0;
 }
 
+#ifdef CONFIG_CPU_PM
+static int riscv_pm_pmu_notify(struct notifier_block *b, unsigned long cmd,
+                               void *v)
+{
+       struct riscv_pmu *rvpmu = container_of(b, struct riscv_pmu, riscv_pm_nb);
+       struct cpu_hw_events *cpuc = this_cpu_ptr(rvpmu->hw_events);
+       int enabled = bitmap_weight(cpuc->used_hw_ctrs, RISCV_MAX_COUNTERS);
+       struct perf_event *event;
+       int idx;
+
+       if (!enabled)
+               return NOTIFY_OK;
+
+       for (idx = 0; idx < RISCV_MAX_COUNTERS; idx++) {
+               event = cpuc->events[idx];
+               if (!event)
+                       continue;
+
+               switch (cmd) {
+               case CPU_PM_ENTER:
+                       /*
+                        * Stop and update the counter
+                        */
+                       riscv_pmu_stop(event, PERF_EF_UPDATE);
+                       break;
+               case CPU_PM_EXIT:
+               case CPU_PM_ENTER_FAILED:
+                       /*
+                        * Restore and enable the counter.
+                        *
+                        * Requires RCU read locking to be functional,
+                        * wrap the call within RCU_NONIDLE to make the
+                        * RCU subsystem aware this cpu is not idle from
+                        * an RCU perspective for the riscv_pmu_start() call
+                        * duration.
+                        */
+                       RCU_NONIDLE(riscv_pmu_start(event, PERF_EF_RELOAD));
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return NOTIFY_OK;
+}
+
+static int riscv_pm_pmu_register(struct riscv_pmu *pmu)
+{
+       pmu->riscv_pm_nb.notifier_call = riscv_pm_pmu_notify;
+       return cpu_pm_register_notifier(&pmu->riscv_pm_nb);
+}
+
+static void riscv_pm_pmu_unregister(struct riscv_pmu *pmu)
+{
+       cpu_pm_unregister_notifier(&pmu->riscv_pm_nb);
+}
+#else
+static inline int riscv_pm_pmu_register(struct riscv_pmu *pmu) { return 0; }
+static inline void riscv_pm_pmu_unregister(struct riscv_pmu *pmu) { }
+#endif
+
+static void riscv_pmu_destroy(struct riscv_pmu *pmu)
+{
+       riscv_pm_pmu_unregister(pmu);
+       cpuhp_state_remove_instance(CPUHP_AP_PERF_RISCV_STARTING, &pmu->node);
+}
+
 static int pmu_sbi_device_probe(struct platform_device *pdev)
 {
        struct riscv_pmu *pmu = NULL;
@@ -720,6 +810,7 @@ static int pmu_sbi_device_probe(struct platform_device *pdev)
                pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT;
                pmu->pmu.capabilities |= PERF_PMU_CAP_NO_EXCLUDE;
        }
+       pmu->pmu.attr_groups = riscv_pmu_attr_groups;
        pmu->num_counters = num_counters;
        pmu->ctr_start = pmu_sbi_ctr_start;
        pmu->ctr_stop = pmu_sbi_ctr_stop;
@@ -733,14 +824,19 @@ static int pmu_sbi_device_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       ret = riscv_pm_pmu_register(pmu);
+       if (ret)
+               goto out_unregister;
+
        ret = perf_pmu_register(&pmu->pmu, "cpu", PERF_TYPE_RAW);
-       if (ret) {
-               cpuhp_state_remove_instance(CPUHP_AP_PERF_RISCV_STARTING, &pmu->node);
-               return ret;
-       }
+       if (ret)
+               goto out_unregister;
 
        return 0;
 
+out_unregister:
+       riscv_pmu_destroy(pmu);
+
 out_free:
        kfree(pmu);
        return ret;
index 849c420..93a6a8e 100644 (file)
@@ -83,7 +83,7 @@ config PHY_NS2_USB_DRD
 config PHY_BRCM_SATA
        tristate "Broadcom SATA PHY driver"
        depends on ARCH_BRCMSTB || ARCH_BCM_IPROC || BMIPS_GENERIC || \
-                  ARCH_BCM_63XX || COMPILE_TEST
+                  ARCH_BCMBCA || COMPILE_TEST
        depends on OF
        select GENERIC_PHY
        default ARCH_BCM_IPROC
index f52960d..bff144c 100644 (file)
@@ -32,7 +32,7 @@ config DEBUG_PINCTRL
          Say Y here to add some extra checks and diagnostics to PINCTRL calls.
 
 config PINCTRL_AMD
-       tristate "AMD GPIO pin control"
+       bool "AMD GPIO pin control"
        depends on HAS_IOMEM
        depends on ACPI || COMPILE_TEST
        select GPIOLIB
index c94e24a..83d47ff 100644 (file)
@@ -236,11 +236,11 @@ int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
                const struct aspeed_sig_expr **funcs;
                const struct aspeed_sig_expr ***prios;
 
-               pr_debug("Muxing pin %s for %s\n", pdesc->name, pfunc->name);
-
                if (!pdesc)
                        return -EINVAL;
 
+               pr_debug("Muxing pin %s for %s\n", pdesc->name, pfunc->name);
+
                prios = pdesc->prios;
 
                if (!prios)
index c0630f6..417e41b 100644 (file)
@@ -239,6 +239,7 @@ static const struct pinctrl_pin_desc imx93_pinctrl_pads[] = {
 static const struct imx_pinctrl_soc_info imx93_pinctrl_info = {
        .pins = imx93_pinctrl_pads,
        .npins = ARRAY_SIZE(imx93_pinctrl_pads),
+       .flags = ZERO_OFFSET_VALID,
        .gpr_compatible = "fsl,imx93-iomuxc-gpr",
 };
 
index a140b6b..bcde042 100644 (file)
@@ -102,7 +102,7 @@ struct armada_37xx_pinctrl {
        struct device                   *dev;
        struct gpio_chip                gpio_chip;
        struct irq_chip                 irq_chip;
-       spinlock_t                      irq_lock;
+       raw_spinlock_t                  irq_lock;
        struct pinctrl_desc             pctl;
        struct pinctrl_dev              *pctl_dev;
        struct armada_37xx_pin_group    *groups;
@@ -523,9 +523,9 @@ static void armada_37xx_irq_ack(struct irq_data *d)
        unsigned long flags;
 
        armada_37xx_irq_update_reg(&reg, d);
-       spin_lock_irqsave(&info->irq_lock, flags);
+       raw_spin_lock_irqsave(&info->irq_lock, flags);
        writel(d->mask, info->base + reg);
-       spin_unlock_irqrestore(&info->irq_lock, flags);
+       raw_spin_unlock_irqrestore(&info->irq_lock, flags);
 }
 
 static void armada_37xx_irq_mask(struct irq_data *d)
@@ -536,10 +536,10 @@ static void armada_37xx_irq_mask(struct irq_data *d)
        unsigned long flags;
 
        armada_37xx_irq_update_reg(&reg, d);
-       spin_lock_irqsave(&info->irq_lock, flags);
+       raw_spin_lock_irqsave(&info->irq_lock, flags);
        val = readl(info->base + reg);
        writel(val & ~d->mask, info->base + reg);
-       spin_unlock_irqrestore(&info->irq_lock, flags);
+       raw_spin_unlock_irqrestore(&info->irq_lock, flags);
 }
 
 static void armada_37xx_irq_unmask(struct irq_data *d)
@@ -550,10 +550,10 @@ static void armada_37xx_irq_unmask(struct irq_data *d)
        unsigned long flags;
 
        armada_37xx_irq_update_reg(&reg, d);
-       spin_lock_irqsave(&info->irq_lock, flags);
+       raw_spin_lock_irqsave(&info->irq_lock, flags);
        val = readl(info->base + reg);
        writel(val | d->mask, info->base + reg);
-       spin_unlock_irqrestore(&info->irq_lock, flags);
+       raw_spin_unlock_irqrestore(&info->irq_lock, flags);
 }
 
 static int armada_37xx_irq_set_wake(struct irq_data *d, unsigned int on)
@@ -564,14 +564,14 @@ static int armada_37xx_irq_set_wake(struct irq_data *d, unsigned int on)
        unsigned long flags;
 
        armada_37xx_irq_update_reg(&reg, d);
-       spin_lock_irqsave(&info->irq_lock, flags);
+       raw_spin_lock_irqsave(&info->irq_lock, flags);
        val = readl(info->base + reg);
        if (on)
                val |= (BIT(d->hwirq % GPIO_PER_REG));
        else
                val &= ~(BIT(d->hwirq % GPIO_PER_REG));
        writel(val, info->base + reg);
-       spin_unlock_irqrestore(&info->irq_lock, flags);
+       raw_spin_unlock_irqrestore(&info->irq_lock, flags);
 
        return 0;
 }
@@ -583,7 +583,7 @@ static int armada_37xx_irq_set_type(struct irq_data *d, unsigned int type)
        u32 val, reg = IRQ_POL;
        unsigned long flags;
 
-       spin_lock_irqsave(&info->irq_lock, flags);
+       raw_spin_lock_irqsave(&info->irq_lock, flags);
        armada_37xx_irq_update_reg(&reg, d);
        val = readl(info->base + reg);
        switch (type) {
@@ -607,11 +607,11 @@ static int armada_37xx_irq_set_type(struct irq_data *d, unsigned int type)
                break;
        }
        default:
-               spin_unlock_irqrestore(&info->irq_lock, flags);
+               raw_spin_unlock_irqrestore(&info->irq_lock, flags);
                return -EINVAL;
        }
        writel(val, info->base + reg);
-       spin_unlock_irqrestore(&info->irq_lock, flags);
+       raw_spin_unlock_irqrestore(&info->irq_lock, flags);
 
        return 0;
 }
@@ -626,7 +626,7 @@ static int armada_37xx_edge_both_irq_swap_pol(struct armada_37xx_pinctrl *info,
 
        regmap_read(info->regmap, INPUT_VAL + 4*reg_idx, &l);
 
-       spin_lock_irqsave(&info->irq_lock, flags);
+       raw_spin_lock_irqsave(&info->irq_lock, flags);
        p = readl(info->base + IRQ_POL + 4 * reg_idx);
        if ((p ^ l) & (1 << bit_num)) {
                /*
@@ -647,7 +647,7 @@ static int armada_37xx_edge_both_irq_swap_pol(struct armada_37xx_pinctrl *info,
                ret = -1;
        }
 
-       spin_unlock_irqrestore(&info->irq_lock, flags);
+       raw_spin_unlock_irqrestore(&info->irq_lock, flags);
        return ret;
 }
 
@@ -664,11 +664,11 @@ static void armada_37xx_irq_handler(struct irq_desc *desc)
                u32 status;
                unsigned long flags;
 
-               spin_lock_irqsave(&info->irq_lock, flags);
+               raw_spin_lock_irqsave(&info->irq_lock, flags);
                status = readl_relaxed(info->base + IRQ_STATUS + 4 * i);
                /* Manage only the interrupt that was enabled */
                status &= readl_relaxed(info->base + IRQ_EN + 4 * i);
-               spin_unlock_irqrestore(&info->irq_lock, flags);
+               raw_spin_unlock_irqrestore(&info->irq_lock, flags);
                while (status) {
                        u32 hwirq = ffs(status) - 1;
                        u32 virq = irq_find_mapping(d, hwirq +
@@ -695,12 +695,12 @@ static void armada_37xx_irq_handler(struct irq_desc *desc)
 
 update_status:
                        /* Update status in case a new IRQ appears */
-                       spin_lock_irqsave(&info->irq_lock, flags);
+                       raw_spin_lock_irqsave(&info->irq_lock, flags);
                        status = readl_relaxed(info->base +
                                               IRQ_STATUS + 4 * i);
                        /* Manage only the interrupt that was enabled */
                        status &= readl_relaxed(info->base + IRQ_EN + 4 * i);
-                       spin_unlock_irqrestore(&info->irq_lock, flags);
+                       raw_spin_unlock_irqrestore(&info->irq_lock, flags);
                }
        }
        chained_irq_exit(chip, desc);
@@ -731,7 +731,7 @@ static int armada_37xx_irqchip_register(struct platform_device *pdev,
        struct device *dev = &pdev->dev;
        unsigned int i, nr_irq_parent;
 
-       spin_lock_init(&info->irq_lock);
+       raw_spin_lock_init(&info->irq_lock);
 
        nr_irq_parent = of_irq_count(np);
        if (!nr_irq_parent) {
@@ -1107,25 +1107,40 @@ static const struct of_device_id armada_37xx_pinctrl_of_match[] = {
        { },
 };
 
+static const struct regmap_config armada_37xx_pinctrl_regmap_config = {
+       .reg_bits = 32,
+       .val_bits = 32,
+       .reg_stride = 4,
+       .use_raw_spinlock = true,
+};
+
 static int __init armada_37xx_pinctrl_probe(struct platform_device *pdev)
 {
        struct armada_37xx_pinctrl *info;
        struct device *dev = &pdev->dev;
-       struct device_node *np = dev->of_node;
        struct regmap *regmap;
+       void __iomem *base;
        int ret;
 
+       base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+       if (IS_ERR(base)) {
+               dev_err(dev, "failed to ioremap base address: %pe\n", base);
+               return PTR_ERR(base);
+       }
+
+       regmap = devm_regmap_init_mmio(dev, base,
+                                      &armada_37xx_pinctrl_regmap_config);
+       if (IS_ERR(regmap)) {
+               dev_err(dev, "failed to create regmap: %pe\n", regmap);
+               return PTR_ERR(regmap);
+       }
+
        info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
 
        info->dev = dev;
-
-       regmap = syscon_node_to_regmap(np);
-       if (IS_ERR(regmap))
-               return dev_err_probe(dev, PTR_ERR(regmap), "cannot get regmap\n");
        info->regmap = regmap;
-
        info->data = of_device_get_match_data(dev);
 
        ret = armada_37xx_pinctrl_register(pdev, info);
index 5f4a8c5..771dd1f 100644 (file)
 #define ocelot_clrsetbits(addr, clear, set) \
        writel((readl(addr) & ~(clear)) | (set), (addr))
 
-/* PINCONFIG bits (sparx5 only) */
 enum {
        PINCONF_BIAS,
        PINCONF_SCHMITT,
        PINCONF_DRIVE_STRENGTH,
 };
 
-#define BIAS_PD_BIT BIT(4)
-#define BIAS_PU_BIT BIT(3)
-#define BIAS_BITS   (BIAS_PD_BIT|BIAS_PU_BIT)
-#define SCHMITT_BIT BIT(2)
-#define DRIVE_BITS  GENMASK(1, 0)
-
 /* GPIO standard registers */
 #define OCELOT_GPIO_OUT_SET    0x0
 #define OCELOT_GPIO_OUT_CLR    0x4
@@ -321,6 +314,13 @@ struct ocelot_pin_caps {
        unsigned char a_functions[OCELOT_FUNC_PER_PIN]; /* Additional functions */
 };
 
+struct ocelot_pincfg_data {
+       u8 pd_bit;
+       u8 pu_bit;
+       u8 drive_bits;
+       u8 schmitt_bit;
+};
+
 struct ocelot_pinctrl {
        struct device *dev;
        struct pinctrl_dev *pctl;
@@ -328,10 +328,16 @@ struct ocelot_pinctrl {
        struct regmap *map;
        struct regmap *pincfg;
        struct pinctrl_desc *desc;
+       const struct ocelot_pincfg_data *pincfg_data;
        struct ocelot_pmx_func func[FUNC_MAX];
        u8 stride;
 };
 
+struct ocelot_match_data {
+       struct pinctrl_desc desc;
+       struct ocelot_pincfg_data pincfg_data;
+};
+
 #define LUTON_P(p, f0, f1)                                             \
 static struct ocelot_pin_caps luton_pin_##p = {                                \
        .pin = p,                                                       \
@@ -1325,24 +1331,27 @@ static int ocelot_hw_get_value(struct ocelot_pinctrl *info,
        int ret = -EOPNOTSUPP;
 
        if (info->pincfg) {
+               const struct ocelot_pincfg_data *opd = info->pincfg_data;
                u32 regcfg;
 
-               ret = regmap_read(info->pincfg, pin, &regcfg);
+               ret = regmap_read(info->pincfg,
+                                 pin * regmap_get_reg_stride(info->pincfg),
+                                 &regcfg);
                if (ret)
                        return ret;
 
                ret = 0;
                switch (reg) {
                case PINCONF_BIAS:
-                       *val = regcfg & BIAS_BITS;
+                       *val = regcfg & (opd->pd_bit | opd->pu_bit);
                        break;
 
                case PINCONF_SCHMITT:
-                       *val = regcfg & SCHMITT_BIT;
+                       *val = regcfg & opd->schmitt_bit;
                        break;
 
                case PINCONF_DRIVE_STRENGTH:
-                       *val = regcfg & DRIVE_BITS;
+                       *val = regcfg & opd->drive_bits;
                        break;
 
                default:
@@ -1359,14 +1368,18 @@ static int ocelot_pincfg_clrsetbits(struct ocelot_pinctrl *info, u32 regaddr,
        u32 val;
        int ret;
 
-       ret = regmap_read(info->pincfg, regaddr, &val);
+       ret = regmap_read(info->pincfg,
+                         regaddr * regmap_get_reg_stride(info->pincfg),
+                         &val);
        if (ret)
                return ret;
 
        val &= ~clrbits;
        val |= setbits;
 
-       ret = regmap_write(info->pincfg, regaddr, val);
+       ret = regmap_write(info->pincfg,
+                          regaddr * regmap_get_reg_stride(info->pincfg),
+                          val);
 
        return ret;
 }
@@ -1379,23 +1392,27 @@ static int ocelot_hw_set_value(struct ocelot_pinctrl *info,
        int ret = -EOPNOTSUPP;
 
        if (info->pincfg) {
+               const struct ocelot_pincfg_data *opd = info->pincfg_data;
 
                ret = 0;
                switch (reg) {
                case PINCONF_BIAS:
-                       ret = ocelot_pincfg_clrsetbits(info, pin, BIAS_BITS,
+                       ret = ocelot_pincfg_clrsetbits(info, pin,
+                                                      opd->pd_bit | opd->pu_bit,
                                                       val);
                        break;
 
                case PINCONF_SCHMITT:
-                       ret = ocelot_pincfg_clrsetbits(info, pin, SCHMITT_BIT,
+                       ret = ocelot_pincfg_clrsetbits(info, pin,
+                                                      opd->schmitt_bit,
                                                       val);
                        break;
 
                case PINCONF_DRIVE_STRENGTH:
                        if (val <= 3)
                                ret = ocelot_pincfg_clrsetbits(info, pin,
-                                                              DRIVE_BITS, val);
+                                                              opd->drive_bits,
+                                                              val);
                        else
                                ret = -EINVAL;
                        break;
@@ -1425,17 +1442,20 @@ static int ocelot_pinconf_get(struct pinctrl_dev *pctldev,
                if (param == PIN_CONFIG_BIAS_DISABLE)
                        val = (val == 0);
                else if (param == PIN_CONFIG_BIAS_PULL_DOWN)
-                       val = (val & BIAS_PD_BIT ? true : false);
+                       val = !!(val & info->pincfg_data->pd_bit);
                else    /* PIN_CONFIG_BIAS_PULL_UP */
-                       val = (val & BIAS_PU_BIT ? true : false);
+                       val = !!(val & info->pincfg_data->pu_bit);
                break;
 
        case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+               if (!info->pincfg_data->schmitt_bit)
+                       return -EOPNOTSUPP;
+
                err = ocelot_hw_get_value(info, pin, PINCONF_SCHMITT, &val);
                if (err)
                        return err;
 
-               val = (val & SCHMITT_BIT ? true : false);
+               val = !!(val & info->pincfg_data->schmitt_bit);
                break;
 
        case PIN_CONFIG_DRIVE_STRENGTH:
@@ -1479,6 +1499,7 @@ static int ocelot_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
                              unsigned long *configs, unsigned int num_configs)
 {
        struct ocelot_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+       const struct ocelot_pincfg_data *opd = info->pincfg_data;
        u32 param, arg, p;
        int cfg, err = 0;
 
@@ -1491,8 +1512,8 @@ static int ocelot_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
                case PIN_CONFIG_BIAS_PULL_UP:
                case PIN_CONFIG_BIAS_PULL_DOWN:
                        arg = (param == PIN_CONFIG_BIAS_DISABLE) ? 0 :
-                       (param == PIN_CONFIG_BIAS_PULL_UP) ? BIAS_PU_BIT :
-                       BIAS_PD_BIT;
+                             (param == PIN_CONFIG_BIAS_PULL_UP) ?
+                               opd->pu_bit : opd->pd_bit;
 
                        err = ocelot_hw_set_value(info, pin, PINCONF_BIAS, arg);
                        if (err)
@@ -1501,7 +1522,10 @@ static int ocelot_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
                        break;
 
                case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
-                       arg = arg ? SCHMITT_BIT : 0;
+                       if (!opd->schmitt_bit)
+                               return -EOPNOTSUPP;
+
+                       arg = arg ? opd->schmitt_bit : 0;
                        err = ocelot_hw_set_value(info, pin, PINCONF_SCHMITT,
                                                  arg);
                        if (err)
@@ -1562,69 +1586,94 @@ static const struct pinctrl_ops ocelot_pctl_ops = {
        .dt_free_map = pinconf_generic_dt_free_map,
 };
 
-static struct pinctrl_desc luton_desc = {
-       .name = "luton-pinctrl",
-       .pins = luton_pins,
-       .npins = ARRAY_SIZE(luton_pins),
-       .pctlops = &ocelot_pctl_ops,
-       .pmxops = &ocelot_pmx_ops,
-       .owner = THIS_MODULE,
+static struct ocelot_match_data luton_desc = {
+       .desc = {
+               .name = "luton-pinctrl",
+               .pins = luton_pins,
+               .npins = ARRAY_SIZE(luton_pins),
+               .pctlops = &ocelot_pctl_ops,
+               .pmxops = &ocelot_pmx_ops,
+               .owner = THIS_MODULE,
+       },
 };
 
-static struct pinctrl_desc serval_desc = {
-       .name = "serval-pinctrl",
-       .pins = serval_pins,
-       .npins = ARRAY_SIZE(serval_pins),
-       .pctlops = &ocelot_pctl_ops,
-       .pmxops = &ocelot_pmx_ops,
-       .owner = THIS_MODULE,
+static struct ocelot_match_data serval_desc = {
+       .desc = {
+               .name = "serval-pinctrl",
+               .pins = serval_pins,
+               .npins = ARRAY_SIZE(serval_pins),
+               .pctlops = &ocelot_pctl_ops,
+               .pmxops = &ocelot_pmx_ops,
+               .owner = THIS_MODULE,
+       },
 };
 
-static struct pinctrl_desc ocelot_desc = {
-       .name = "ocelot-pinctrl",
-       .pins = ocelot_pins,
-       .npins = ARRAY_SIZE(ocelot_pins),
-       .pctlops = &ocelot_pctl_ops,
-       .pmxops = &ocelot_pmx_ops,
-       .owner = THIS_MODULE,
+static struct ocelot_match_data ocelot_desc = {
+       .desc = {
+               .name = "ocelot-pinctrl",
+               .pins = ocelot_pins,
+               .npins = ARRAY_SIZE(ocelot_pins),
+               .pctlops = &ocelot_pctl_ops,
+               .pmxops = &ocelot_pmx_ops,
+               .owner = THIS_MODULE,
+       },
 };
 
-static struct pinctrl_desc jaguar2_desc = {
-       .name = "jaguar2-pinctrl",
-       .pins = jaguar2_pins,
-       .npins = ARRAY_SIZE(jaguar2_pins),
-       .pctlops = &ocelot_pctl_ops,
-       .pmxops = &ocelot_pmx_ops,
-       .owner = THIS_MODULE,
+static struct ocelot_match_data jaguar2_desc = {
+       .desc = {
+               .name = "jaguar2-pinctrl",
+               .pins = jaguar2_pins,
+               .npins = ARRAY_SIZE(jaguar2_pins),
+               .pctlops = &ocelot_pctl_ops,
+               .pmxops = &ocelot_pmx_ops,
+               .owner = THIS_MODULE,
+       },
 };
 
-static struct pinctrl_desc servalt_desc = {
-       .name = "servalt-pinctrl",
-       .pins = servalt_pins,
-       .npins = ARRAY_SIZE(servalt_pins),
-       .pctlops = &ocelot_pctl_ops,
-       .pmxops = &ocelot_pmx_ops,
-       .owner = THIS_MODULE,
+static struct ocelot_match_data servalt_desc = {
+       .desc = {
+               .name = "servalt-pinctrl",
+               .pins = servalt_pins,
+               .npins = ARRAY_SIZE(servalt_pins),
+               .pctlops = &ocelot_pctl_ops,
+               .pmxops = &ocelot_pmx_ops,
+               .owner = THIS_MODULE,
+       },
 };
 
-static struct pinctrl_desc sparx5_desc = {
-       .name = "sparx5-pinctrl",
-       .pins = sparx5_pins,
-       .npins = ARRAY_SIZE(sparx5_pins),
-       .pctlops = &ocelot_pctl_ops,
-       .pmxops = &ocelot_pmx_ops,
-       .confops = &ocelot_confops,
-       .owner = THIS_MODULE,
+static struct ocelot_match_data sparx5_desc = {
+       .desc = {
+               .name = "sparx5-pinctrl",
+               .pins = sparx5_pins,
+               .npins = ARRAY_SIZE(sparx5_pins),
+               .pctlops = &ocelot_pctl_ops,
+               .pmxops = &ocelot_pmx_ops,
+               .confops = &ocelot_confops,
+               .owner = THIS_MODULE,
+       },
+       .pincfg_data = {
+               .pd_bit = BIT(4),
+               .pu_bit = BIT(3),
+               .drive_bits = GENMASK(1, 0),
+               .schmitt_bit = BIT(2),
+       },
 };
 
-static struct pinctrl_desc lan966x_desc = {
-       .name = "lan966x-pinctrl",
-       .pins = lan966x_pins,
-       .npins = ARRAY_SIZE(lan966x_pins),
-       .pctlops = &ocelot_pctl_ops,
-       .pmxops = &lan966x_pmx_ops,
-       .confops = &ocelot_confops,
-       .owner = THIS_MODULE,
+static struct ocelot_match_data lan966x_desc = {
+       .desc = {
+               .name = "lan966x-pinctrl",
+               .pins = lan966x_pins,
+               .npins = ARRAY_SIZE(lan966x_pins),
+               .pctlops = &ocelot_pctl_ops,
+               .pmxops = &lan966x_pmx_ops,
+               .confops = &ocelot_confops,
+               .owner = THIS_MODULE,
+       },
+       .pincfg_data = {
+               .pd_bit = BIT(3),
+               .pu_bit = BIT(2),
+               .drive_bits = GENMASK(1, 0),
+       },
 };
 
 static int ocelot_create_group_func_map(struct device *dev,
@@ -1761,6 +1810,7 @@ static void ocelot_irq_mask(struct irq_data *data)
 
        regmap_update_bits(info->map, REG(OCELOT_GPIO_INTR_ENA, info, gpio),
                           BIT(gpio % 32), 0);
+       gpiochip_disable_irq(chip, gpio);
 }
 
 static void ocelot_irq_unmask(struct irq_data *data)
@@ -1769,6 +1819,7 @@ static void ocelot_irq_unmask(struct irq_data *data)
        struct ocelot_pinctrl *info = gpiochip_get_data(chip);
        unsigned int gpio = irqd_to_hwirq(data);
 
+       gpiochip_enable_irq(chip, gpio);
        regmap_update_bits(info->map, REG(OCELOT_GPIO_INTR_ENA, info, gpio),
                           BIT(gpio % 32), BIT(gpio % 32));
 }
@@ -1790,8 +1841,10 @@ static struct irq_chip ocelot_eoi_irqchip = {
        .irq_mask       = ocelot_irq_mask,
        .irq_eoi        = ocelot_irq_ack,
        .irq_unmask     = ocelot_irq_unmask,
-       .flags          = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED,
+       .flags          = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED |
+                         IRQCHIP_IMMUTABLE,
        .irq_set_type   = ocelot_irq_set_type,
+       GPIOCHIP_IRQ_RESOURCE_HELPERS
 };
 
 static struct irq_chip ocelot_irqchip = {
@@ -1800,6 +1853,8 @@ static struct irq_chip ocelot_irqchip = {
        .irq_ack        = ocelot_irq_ack,
        .irq_unmask     = ocelot_irq_unmask,
        .irq_set_type   = ocelot_irq_set_type,
+       .flags          = IRQCHIP_IMMUTABLE,
+       GPIOCHIP_IRQ_RESOURCE_HELPERS
 };
 
 static int ocelot_irq_set_type(struct irq_data *data, unsigned int type)
@@ -1863,7 +1918,7 @@ static int ocelot_gpiochip_register(struct platform_device *pdev,
        irq = platform_get_irq_optional(pdev, 0);
        if (irq > 0) {
                girq = &gc->irq;
-               girq->chip = &ocelot_irqchip;
+               gpio_irq_chip_set_chip(girq, &ocelot_irqchip);
                girq->parent_handler = ocelot_irq_handler;
                girq->num_parents = 1;
                girq->parents = devm_kcalloc(&pdev->dev, 1,
@@ -1890,7 +1945,8 @@ static const struct of_device_id ocelot_pinctrl_of_match[] = {
        {},
 };
 
-static struct regmap *ocelot_pinctrl_create_pincfg(struct platform_device *pdev)
+static struct regmap *ocelot_pinctrl_create_pincfg(struct platform_device *pdev,
+                                                  const struct ocelot_pinctrl *info)
 {
        void __iomem *base;
 
@@ -1898,7 +1954,7 @@ static struct regmap *ocelot_pinctrl_create_pincfg(struct platform_device *pdev)
                .reg_bits = 32,
                .val_bits = 32,
                .reg_stride = 4,
-               .max_register = 32,
+               .max_register = info->desc->npins * 4,
                .name = "pincfg",
        };
 
@@ -1913,6 +1969,7 @@ static struct regmap *ocelot_pinctrl_create_pincfg(struct platform_device *pdev)
 
 static int ocelot_pinctrl_probe(struct platform_device *pdev)
 {
+       const struct ocelot_match_data *data;
        struct device *dev = &pdev->dev;
        struct ocelot_pinctrl *info;
        struct reset_control *reset;
@@ -1929,7 +1986,16 @@ static int ocelot_pinctrl_probe(struct platform_device *pdev)
        if (!info)
                return -ENOMEM;
 
-       info->desc = (struct pinctrl_desc *)device_get_match_data(dev);
+       data = device_get_match_data(dev);
+       if (!data)
+               return -EINVAL;
+
+       info->desc = devm_kmemdup(dev, &data->desc, sizeof(*info->desc),
+                                 GFP_KERNEL);
+       if (!info->desc)
+               return -ENOMEM;
+
+       info->pincfg_data = &data->pincfg_data;
 
        reset = devm_reset_control_get_optional_shared(dev, "switch");
        if (IS_ERR(reset))
@@ -1956,7 +2022,7 @@ static int ocelot_pinctrl_probe(struct platform_device *pdev)
 
        /* Pinconf registers */
        if (info->desc->confops) {
-               pincfg = ocelot_pinctrl_create_pincfg(pdev);
+               pincfg = ocelot_pinctrl_create_pincfg(pdev, info);
                if (IS_ERR(pincfg))
                        dev_dbg(dev, "Failed to create pincfg regmap\n");
                else
index fd5fff9..3be2a08 100644 (file)
@@ -966,16 +966,13 @@ static int pmic_gpio_child_to_parent_hwirq(struct gpio_chip *chip,
        return 0;
 }
 
-static void *pmic_gpio_populate_parent_fwspec(struct gpio_chip *chip,
-                                            unsigned int parent_hwirq,
-                                            unsigned int parent_type)
+static int pmic_gpio_populate_parent_fwspec(struct gpio_chip *chip,
+                                           union gpio_irq_fwspec *gfwspec,
+                                           unsigned int parent_hwirq,
+                                           unsigned int parent_type)
 {
        struct pmic_gpio_state *state = gpiochip_get_data(chip);
-       struct irq_fwspec *fwspec;
-
-       fwspec = kzalloc(sizeof(*fwspec), GFP_KERNEL);
-       if (!fwspec)
-               return NULL;
+       struct irq_fwspec *fwspec = &gfwspec->fwspec;
 
        fwspec->fwnode = chip->irq.parent_domain->fwnode;
 
@@ -985,7 +982,7 @@ static void *pmic_gpio_populate_parent_fwspec(struct gpio_chip *chip,
        /* param[2] must be left as 0 */
        fwspec->param[3] = parent_type;
 
-       return fwspec;
+       return 0;
 }
 
 static int pmic_gpio_probe(struct platform_device *pdev)
index 63429a2..770862f 100644 (file)
@@ -266,6 +266,8 @@ static int ralink_pinctrl_pins(struct ralink_priv *p)
                                                p->func[i]->pin_count,
                                                sizeof(int),
                                                GFP_KERNEL);
+               if (!p->func[i]->pins)
+                       return -ENOMEM;
                for (j = 0; j < p->func[i]->pin_count; j++)
                        p->func[i]->pins[j] = p->func[i]->pin_first + j;
 
index a48cac5..c47eed9 100644 (file)
@@ -9,8 +9,10 @@
 #include <linux/clk.h>
 #include <linux/gpio/driver.h>
 #include <linux/io.h>
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
+#include <linux/of_irq.h>
 #include <linux/pinctrl/pinconf-generic.h>
 #include <linux/pinctrl/pinconf.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -89,6 +91,7 @@
 #define PIN(n)                 (0x0800 + 0x10 + (n))
 #define IOLH(n)                        (0x1000 + (n) * 8)
 #define IEN(n)                 (0x1800 + (n) * 8)
+#define ISEL(n)                        (0x2c80 + (n) * 8)
 #define PWPR                   (0x3014)
 #define SD_CH(n)               (0x3000 + (n) * 4)
 #define QSPI                   (0x3008)
 #define RZG2L_PIN_ID_TO_PORT_OFFSET(id)        (RZG2L_PIN_ID_TO_PORT(id) + 0x10)
 #define RZG2L_PIN_ID_TO_PIN(id)                ((id) % RZG2L_PINS_PER_PORT)
 
+#define RZG2L_TINT_MAX_INTERRUPT       32
+#define RZG2L_TINT_IRQ_START_INDEX     9
+#define RZG2L_PACK_HWIRQ(t, i)         (((t) << 16) | (i))
+
 struct rzg2l_dedicated_configs {
        const char *name;
        u32 config;
@@ -137,6 +144,9 @@ struct rzg2l_pinctrl {
 
        struct gpio_chip                gpio_chip;
        struct pinctrl_gpio_range       gpio_range;
+       DECLARE_BITMAP(tint_slot, RZG2L_TINT_MAX_INTERRUPT);
+       spinlock_t                      bitmap_lock;
+       unsigned int                    hwirq[RZG2L_TINT_MAX_INTERRUPT];
 
        spinlock_t                      lock;
 };
@@ -883,8 +893,14 @@ static int rzg2l_gpio_get(struct gpio_chip *chip, unsigned int offset)
 
 static void rzg2l_gpio_free(struct gpio_chip *chip, unsigned int offset)
 {
+       unsigned int virq;
+
        pinctrl_gpio_free(chip->base + offset);
 
+       virq = irq_find_mapping(chip->irq.domain, offset);
+       if (virq)
+               irq_dispose_mapping(virq);
+
        /*
         * Set the GPIO as an input to ensure that the next GPIO request won't
         * drive the GPIO pin as an output.
@@ -1104,14 +1120,221 @@ static struct {
        }
 };
 
+static int rzg2l_gpio_get_gpioint(unsigned int virq)
+{
+       unsigned int gpioint;
+       unsigned int i;
+       u32 port, bit;
+
+       port = virq / 8;
+       bit = virq % 8;
+
+       if (port >= ARRAY_SIZE(rzg2l_gpio_configs) ||
+           bit >= RZG2L_GPIO_PORT_GET_PINCNT(rzg2l_gpio_configs[port]))
+               return -EINVAL;
+
+       gpioint = bit;
+       for (i = 0; i < port; i++)
+               gpioint += RZG2L_GPIO_PORT_GET_PINCNT(rzg2l_gpio_configs[i]);
+
+       return gpioint;
+}
+
+static void rzg2l_gpio_irq_disable(struct irq_data *d)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct rzg2l_pinctrl *pctrl = container_of(gc, struct rzg2l_pinctrl, gpio_chip);
+       unsigned int hwirq = irqd_to_hwirq(d);
+       unsigned long flags;
+       void __iomem *addr;
+       u32 port;
+       u8 bit;
+
+       port = RZG2L_PIN_ID_TO_PORT(hwirq);
+       bit = RZG2L_PIN_ID_TO_PIN(hwirq);
+
+       addr = pctrl->base + ISEL(port);
+       if (bit >= 4) {
+               bit -= 4;
+               addr += 4;
+       }
+
+       spin_lock_irqsave(&pctrl->lock, flags);
+       writel(readl(addr) & ~BIT(bit * 8), addr);
+       spin_unlock_irqrestore(&pctrl->lock, flags);
+
+       gpiochip_disable_irq(gc, hwirq);
+       irq_chip_disable_parent(d);
+}
+
+static void rzg2l_gpio_irq_enable(struct irq_data *d)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct rzg2l_pinctrl *pctrl = container_of(gc, struct rzg2l_pinctrl, gpio_chip);
+       unsigned int hwirq = irqd_to_hwirq(d);
+       unsigned long flags;
+       void __iomem *addr;
+       u32 port;
+       u8 bit;
+
+       gpiochip_enable_irq(gc, hwirq);
+
+       port = RZG2L_PIN_ID_TO_PORT(hwirq);
+       bit = RZG2L_PIN_ID_TO_PIN(hwirq);
+
+       addr = pctrl->base + ISEL(port);
+       if (bit >= 4) {
+               bit -= 4;
+               addr += 4;
+       }
+
+       spin_lock_irqsave(&pctrl->lock, flags);
+       writel(readl(addr) | BIT(bit * 8), addr);
+       spin_unlock_irqrestore(&pctrl->lock, flags);
+
+       irq_chip_enable_parent(d);
+}
+
+static int rzg2l_gpio_irq_set_type(struct irq_data *d, unsigned int type)
+{
+       return irq_chip_set_type_parent(d, type);
+}
+
+static void rzg2l_gpio_irqc_eoi(struct irq_data *d)
+{
+       irq_chip_eoi_parent(d);
+}
+
+static void rzg2l_gpio_irq_print_chip(struct irq_data *data, struct seq_file *p)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+
+       seq_printf(p, dev_name(gc->parent));
+}
+
+static const struct irq_chip rzg2l_gpio_irqchip = {
+       .name = "rzg2l-gpio",
+       .irq_disable = rzg2l_gpio_irq_disable,
+       .irq_enable = rzg2l_gpio_irq_enable,
+       .irq_mask = irq_chip_mask_parent,
+       .irq_unmask = irq_chip_unmask_parent,
+       .irq_set_type = rzg2l_gpio_irq_set_type,
+       .irq_eoi = rzg2l_gpio_irqc_eoi,
+       .irq_print_chip = rzg2l_gpio_irq_print_chip,
+       .flags = IRQCHIP_IMMUTABLE,
+       GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
+static int rzg2l_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
+                                           unsigned int child,
+                                           unsigned int child_type,
+                                           unsigned int *parent,
+                                           unsigned int *parent_type)
+{
+       struct rzg2l_pinctrl *pctrl = gpiochip_get_data(gc);
+       unsigned long flags;
+       int gpioint, irq;
+
+       gpioint = rzg2l_gpio_get_gpioint(child);
+       if (gpioint < 0)
+               return gpioint;
+
+       spin_lock_irqsave(&pctrl->bitmap_lock, flags);
+       irq = bitmap_find_free_region(pctrl->tint_slot, RZG2L_TINT_MAX_INTERRUPT, get_order(1));
+       spin_unlock_irqrestore(&pctrl->bitmap_lock, flags);
+       if (irq < 0)
+               return -ENOSPC;
+       pctrl->hwirq[irq] = child;
+       irq += RZG2L_TINT_IRQ_START_INDEX;
+
+       /* All these interrupts are level high in the CPU */
+       *parent_type = IRQ_TYPE_LEVEL_HIGH;
+       *parent = RZG2L_PACK_HWIRQ(gpioint, irq);
+       return 0;
+}
+
+static int rzg2l_gpio_populate_parent_fwspec(struct gpio_chip *chip,
+                                            union gpio_irq_fwspec *gfwspec,
+                                            unsigned int parent_hwirq,
+                                            unsigned int parent_type)
+{
+       struct irq_fwspec *fwspec = &gfwspec->fwspec;
+
+       fwspec->fwnode = chip->irq.parent_domain->fwnode;
+       fwspec->param_count = 2;
+       fwspec->param[0] = parent_hwirq;
+       fwspec->param[1] = parent_type;
+
+       return 0;
+}
+
+static void rzg2l_gpio_irq_domain_free(struct irq_domain *domain, unsigned int virq,
+                                      unsigned int nr_irqs)
+{
+       struct irq_data *d;
+
+       d = irq_domain_get_irq_data(domain, virq);
+       if (d) {
+               struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+               struct rzg2l_pinctrl *pctrl = container_of(gc, struct rzg2l_pinctrl, gpio_chip);
+               irq_hw_number_t hwirq = irqd_to_hwirq(d);
+               unsigned long flags;
+               unsigned int i;
+
+               for (i = 0; i < RZG2L_TINT_MAX_INTERRUPT; i++) {
+                       if (pctrl->hwirq[i] == hwirq) {
+                               spin_lock_irqsave(&pctrl->bitmap_lock, flags);
+                               bitmap_release_region(pctrl->tint_slot, i, get_order(1));
+                               spin_unlock_irqrestore(&pctrl->bitmap_lock, flags);
+                               pctrl->hwirq[i] = 0;
+                               break;
+                       }
+               }
+       }
+       irq_domain_free_irqs_common(domain, virq, nr_irqs);
+}
+
+static void rzg2l_init_irq_valid_mask(struct gpio_chip *gc,
+                                     unsigned long *valid_mask,
+                                     unsigned int ngpios)
+{
+       struct rzg2l_pinctrl *pctrl = gpiochip_get_data(gc);
+       struct gpio_chip *chip = &pctrl->gpio_chip;
+       unsigned int offset;
+
+       /* Forbid unused lines to be mapped as IRQs */
+       for (offset = 0; offset < chip->ngpio; offset++) {
+               u32 port, bit;
+
+               port = offset / 8;
+               bit = offset % 8;
+
+               if (port >= ARRAY_SIZE(rzg2l_gpio_configs) ||
+                   bit >= RZG2L_GPIO_PORT_GET_PINCNT(rzg2l_gpio_configs[port]))
+                       clear_bit(offset, valid_mask);
+       }
+}
+
 static int rzg2l_gpio_register(struct rzg2l_pinctrl *pctrl)
 {
        struct device_node *np = pctrl->dev->of_node;
        struct gpio_chip *chip = &pctrl->gpio_chip;
        const char *name = dev_name(pctrl->dev);
+       struct irq_domain *parent_domain;
        struct of_phandle_args of_args;
+       struct device_node *parent_np;
+       struct gpio_irq_chip *girq;
        int ret;
 
+       parent_np = of_irq_find_parent(np);
+       if (!parent_np)
+               return -ENXIO;
+
+       parent_domain = irq_find_host(parent_np);
+       of_node_put(parent_np);
+       if (!parent_domain)
+               return -EPROBE_DEFER;
+
        ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &of_args);
        if (ret) {
                dev_err(pctrl->dev, "Unable to parse gpio-ranges\n");
@@ -1138,6 +1361,15 @@ static int rzg2l_gpio_register(struct rzg2l_pinctrl *pctrl)
        chip->base = -1;
        chip->ngpio = of_args.args[2];
 
+       girq = &chip->irq;
+       gpio_irq_chip_set_chip(girq, &rzg2l_gpio_irqchip);
+       girq->fwnode = of_node_to_fwnode(np);
+       girq->parent_domain = parent_domain;
+       girq->child_to_parent_hwirq = rzg2l_gpio_child_to_parent_hwirq;
+       girq->populate_parent_alloc_arg = rzg2l_gpio_populate_parent_fwspec;
+       girq->child_irq_domain_ops.free = rzg2l_gpio_irq_domain_free;
+       girq->init_valid_mask = rzg2l_init_irq_valid_mask;
+
        pctrl->gpio_range.id = 0;
        pctrl->gpio_range.pin_base = 0;
        pctrl->gpio_range.base = 0;
@@ -1253,6 +1485,7 @@ static int rzg2l_pinctrl_probe(struct platform_device *pdev)
        }
 
        spin_lock_init(&pctrl->lock);
+       spin_lock_init(&pctrl->bitmap_lock);
 
        platform_set_drvdata(pdev, pctrl);
 
index 57a33fb..14bcca7 100644 (file)
@@ -1338,16 +1338,18 @@ static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl, struct fwnode
        bank->secure_control = pctl->match_data->secure_control;
        spin_lock_init(&bank->lock);
 
-       /* create irq hierarchical domain */
-       bank->fwnode = fwnode;
+       if (pctl->domain) {
+               /* create irq hierarchical domain */
+               bank->fwnode = fwnode;
 
-       bank->domain = irq_domain_create_hierarchy(pctl->domain, 0,
-                                       STM32_GPIO_IRQ_LINE, bank->fwnode,
-                                       &stm32_gpio_domain_ops, bank);
+               bank->domain = irq_domain_create_hierarchy(pctl->domain, 0, STM32_GPIO_IRQ_LINE,
+                                                          bank->fwnode, &stm32_gpio_domain_ops,
+                                                          bank);
 
-       if (!bank->domain) {
-               err = -ENODEV;
-               goto err_clk;
+               if (!bank->domain) {
+                       err = -ENODEV;
+                       goto err_clk;
+               }
        }
 
        err = gpiochip_add_data(&bank->gpio_chip, bank);
@@ -1510,6 +1512,8 @@ int stm32_pctl_probe(struct platform_device *pdev)
        pctl->domain = stm32_pctrl_get_irq_domain(pdev);
        if (IS_ERR(pctl->domain))
                return PTR_ERR(pctl->domain);
+       if (!pctl->domain)
+               dev_warn(dev, "pinctrl without interrupt support\n");
 
        /* hwspinlock is optional */
        hwlock_id = of_hwspin_lock_get_id(pdev->dev.of_node, 0);
index 3ba4704..2b3335a 100644 (file)
@@ -871,6 +871,9 @@ static int sppctl_dt_node_to_map(struct pinctrl_dev *pctldev, struct device_node
        }
 
        *map = kcalloc(*num_maps + nmG, sizeof(**map), GFP_KERNEL);
+       if (*map == NULL)
+               return -ENOMEM;
+
        for (i = 0; i < (*num_maps); i++) {
                dt_pin = be32_to_cpu(list[i]);
                pin_num = FIELD_GET(GENMASK(31, 24), dt_pin);
index 4ada803..b5c1a8f 100644 (file)
@@ -158,26 +158,26 @@ static const struct sunxi_desc_pin sun8i_a83t_pins[] = {
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand"),          /* DQ6 */
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ6 */
                  SUNXI_FUNCTION(0x3, "mmc2")),         /* D6 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand"),          /* DQ7 */
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ7 */
                  SUNXI_FUNCTION(0x3, "mmc2")),         /* D7 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 16),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand"),          /* DQS */
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQS */
                  SUNXI_FUNCTION(0x3, "mmc2")),         /* RST */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 17),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand")),         /* CE2 */
+                 SUNXI_FUNCTION(0x2, "nand0")),        /* CE2 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 18),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand")),         /* CE3 */
+                 SUNXI_FUNCTION(0x2, "nand0")),        /* CE3 */
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
index d9327d7..dd92840 100644 (file)
@@ -544,6 +544,8 @@ static int sunxi_pconf_set(struct pinctrl_dev *pctldev, unsigned pin,
        struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
        int i;
 
+       pin -= pctl->desc->pin_base;
+
        for (i = 0; i < num_configs; i++) {
                enum pin_config_param param;
                unsigned long flags;
index 2923daf..7b9c107 100644 (file)
@@ -890,6 +890,7 @@ nvsw_sn2201_create_static_devices(struct nvsw_sn2201 *nvsw_sn2201,
                                  int size)
 {
        struct mlxreg_hotplug_device *dev = devs;
+       int ret;
        int i;
 
        /* Create I2C static devices. */
@@ -901,6 +902,7 @@ nvsw_sn2201_create_static_devices(struct nvsw_sn2201 *nvsw_sn2201,
                                dev->nr, dev->brdinfo->addr);
 
                        dev->adapter = NULL;
+                       ret = PTR_ERR(dev->client);
                        goto fail_create_static_devices;
                }
        }
@@ -914,7 +916,7 @@ fail_create_static_devices:
                dev->client = NULL;
                dev->adapter = NULL;
        }
-       return IS_ERR(dev->client);
+       return ret;
 }
 
 static void nvsw_sn2201_destroy_static_devices(struct nvsw_sn2201 *nvsw_sn2201,
index f08ad85..bc4013e 100644 (file)
@@ -945,6 +945,8 @@ config PANASONIC_LAPTOP
        tristate "Panasonic Laptop Extras"
        depends on INPUT && ACPI
        depends on BACKLIGHT_CLASS_DEVICE
+       depends on ACPI_VIDEO=n || ACPI_VIDEO
+       depends on SERIO_I8042 || SERIO_I8042 = n
        select INPUT_SPARSEKMAP
        help
          This driver adds support for access to backlight control and hotkeys
index f11d18b..700eb19 100644 (file)
@@ -91,6 +91,8 @@
 #define AMD_CPU_ID_PCO                 AMD_CPU_ID_RV
 #define AMD_CPU_ID_CZN                 AMD_CPU_ID_RN
 #define AMD_CPU_ID_YC                  0x14B5
+#define AMD_CPU_ID_CB                  0x14D8
+#define AMD_CPU_ID_PS                  0x14E8
 
 #define PMC_MSG_DELAY_MIN_US           50
 #define RESPONSE_REGISTER_LOOP_MAX     20000
@@ -318,6 +320,8 @@ static int amd_pmc_idlemask_read(struct amd_pmc_dev *pdev, struct device *dev,
                val = amd_pmc_reg_read(pdev, AMD_PMC_SCRATCH_REG_CZN);
                break;
        case AMD_CPU_ID_YC:
+       case AMD_CPU_ID_CB:
+       case AMD_CPU_ID_PS:
                val = amd_pmc_reg_read(pdev, AMD_PMC_SCRATCH_REG_YC);
                break;
        default:
@@ -491,7 +495,8 @@ static void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev)
                            &amd_pmc_idlemask_fops);
        /* Enable STB only when the module_param is set */
        if (enable_stb) {
-               if (dev->cpu_id == AMD_CPU_ID_YC)
+               if (dev->cpu_id == AMD_CPU_ID_YC || dev->cpu_id == AMD_CPU_ID_CB ||
+                   dev->cpu_id == AMD_CPU_ID_PS)
                        debugfs_create_file("stb_read", 0644, dev->dbgfs_dir, dev,
                                            &amd_pmc_stb_debugfs_fops_v2);
                else
@@ -615,6 +620,8 @@ static int amd_pmc_get_os_hint(struct amd_pmc_dev *dev)
                return MSG_OS_HINT_PCO;
        case AMD_CPU_ID_RN:
        case AMD_CPU_ID_YC:
+       case AMD_CPU_ID_CB:
+       case AMD_CPU_ID_PS:
                return MSG_OS_HINT_RN;
        }
        return -EINVAL;
@@ -735,6 +742,8 @@ static struct acpi_s2idle_dev_ops amd_pmc_s2idle_dev_ops = {
 #endif
 
 static const struct pci_device_id pmc_pci_ids[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_PS) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_CB) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_YC) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_CZN) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_RN) },
@@ -877,7 +886,7 @@ static int amd_pmc_probe(struct platform_device *pdev)
 
        mutex_init(&dev->lock);
 
-       if (enable_stb && dev->cpu_id == AMD_CPU_ID_YC) {
+       if (enable_stb && (dev->cpu_id == AMD_CPU_ID_YC || dev->cpu_id == AMD_CPU_ID_CB)) {
                err = amd_pmc_s2d_init(dev);
                if (err)
                        return err;
@@ -915,6 +924,7 @@ static const struct acpi_device_id amd_pmc_acpi_ids[] = {
        {"AMDI0005", 0},
        {"AMDI0006", 0},
        {"AMDI0007", 0},
+       {"AMDI0008", 0},
        {"AMD0004", 0},
        {"AMD0005", 0},
        { }
index 57a07db..478dd30 100644 (file)
@@ -522,6 +522,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
        { KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
        { KE_KEY, 0x32, { KEY_MUTE } },
        { KE_KEY, 0x35, { KEY_SCREENLOCK } },
+       { KE_KEY, 0x38, { KEY_PROG3 } }, /* Armoury Crate */
        { KE_KEY, 0x40, { KEY_PREVIOUSSONG } },
        { KE_KEY, 0x41, { KEY_NEXTSONG } },
        { KE_KEY, 0x43, { KEY_STOPCD } }, /* Stop/Eject */
@@ -574,6 +575,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
        { KE_KEY, 0xA5, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + HDMI */
        { KE_KEY, 0xA6, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + HDMI */
        { KE_KEY, 0xA7, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + HDMI */
+       { KE_KEY, 0xB3, { KEY_PROG4 } }, /* AURA */
        { KE_KEY, 0xB5, { KEY_CALC } },
        { KE_KEY, 0xC4, { KEY_KBDILLUMUP } },
        { KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } },
index 497ad2f..5e7e665 100644 (file)
@@ -150,6 +150,7 @@ static const struct dmi_system_id gigabyte_wmi_known_working_platforms[] = {
        DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550M AORUS PRO-P"),
        DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550M DS3H"),
        DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B660 GAMING X DDR4"),
+       DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B660I AORUS PRO DDR4"),
        DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("Z390 I AORUS PRO WIFI-CF"),
        DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("Z490 AORUS ELITE AC"),
        DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("X570 AORUS ELITE"),
index 0d8cb22..bc7020e 100644 (file)
@@ -89,6 +89,7 @@ enum hp_wmi_event_ids {
        HPWMI_BACKLIT_KB_BRIGHTNESS     = 0x0D,
        HPWMI_PEAKSHIFT_PERIOD          = 0x0F,
        HPWMI_BATTERY_CHARGE_PERIOD     = 0x10,
+       HPWMI_SANITIZATION_MODE         = 0x17,
 };
 
 /*
@@ -853,6 +854,8 @@ static void hp_wmi_notify(u32 value, void *context)
                break;
        case HPWMI_BATTERY_CHARGE_PERIOD:
                break;
+       case HPWMI_SANITIZATION_MODE:
+               break;
        default:
                pr_info("Unknown event_id - %d - 0x%x\n", event_id, event_data);
                break;
index 3ccb7b7..abd0c81 100644 (file)
@@ -152,6 +152,10 @@ static bool no_bt_rfkill;
 module_param(no_bt_rfkill, bool, 0444);
 MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth.");
 
+static bool allow_v4_dytc;
+module_param(allow_v4_dytc, bool, 0444);
+MODULE_PARM_DESC(allow_v4_dytc, "Enable DYTC version 4 platform-profile support.");
+
 /*
  * ACPI Helpers
  */
@@ -871,12 +875,18 @@ static void dytc_profile_refresh(struct ideapad_private *priv)
 static const struct dmi_system_id ideapad_dytc_v4_allow_table[] = {
        {
                /* Ideapad 5 Pro 16ACH6 */
-               .ident = "LENOVO 82L5",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "82L5")
                }
        },
+       {
+               /* Ideapad 5 15ITL05 */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "IdeaPad 5 15ITL05")
+               }
+       },
        {}
 };
 
@@ -901,13 +911,16 @@ static int ideapad_dytc_profile_init(struct ideapad_private *priv)
 
        dytc_version = (output >> DYTC_QUERY_REV_BIT) & 0xF;
 
-       if (dytc_version < 5) {
-               if (dytc_version < 4 || !dmi_check_system(ideapad_dytc_v4_allow_table)) {
-                       dev_info(&priv->platform_device->dev,
-                                "DYTC_VERSION is less than 4 or is not allowed: %d\n",
-                                dytc_version);
-                       return -ENODEV;
-               }
+       if (dytc_version < 4) {
+               dev_info(&priv->platform_device->dev, "DYTC_VERSION < 4 is not supported\n");
+               return -ENODEV;
+       }
+
+       if (dytc_version < 5 &&
+           !(allow_v4_dytc || dmi_check_system(ideapad_dytc_v4_allow_table))) {
+               dev_info(&priv->platform_device->dev,
+                        "DYTC_VERSION 4 support may not work. Pass ideapad_laptop.allow_v4_dytc=Y on the kernel commandline to enable\n");
+               return -ENODEV;
        }
 
        priv->dytc = kzalloc(sizeof(*priv->dytc), GFP_KERNEL);
index 5935dfc..10077a6 100644 (file)
@@ -50,7 +50,8 @@ static const struct dmi_system_id atomisp2_led_systems[] __initconst = {
        {
                .matches = {
                        DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"),
+                       /* Non exact match to also match T100TAF */
+                       DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"),
                },
                .driver_data = &asus_t100ta_lookup,
        },
index 7ce8964..c341a27 100644 (file)
@@ -1,6 +1,9 @@
 config INTEL_IFS
        tristate "Intel In Field Scan"
        depends on X86 && CPU_SUP_INTEL && 64BIT && SMP
+       # Discussion on the list has shown that the sysfs API needs a bit
+       # more work, mark this as broken for now
+       depends on BROKEN
        select INTEL_IFS_DEVICE
        help
          Enable support for the In Field Scan capability in select
index 40183bd..a1fe1e0 100644 (file)
@@ -1911,6 +1911,7 @@ static const struct x86_cpu_id intel_pmc_core_ids[] = {
        X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT_L,      &icl_reg_map),
        X86_MATCH_INTEL_FAM6_MODEL(ROCKETLAKE,          &tgl_reg_map),
        X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L,         &tgl_reg_map),
+       X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_N,         &tgl_reg_map),
        X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE,           &adl_reg_map),
        X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P,        &tgl_reg_map),
        {}
index 37850d0..615e39c 100644 (file)
  *             - v0.1  start from toshiba_acpi driver written by John Belmonte
  */
 
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
+#include <linux/acpi.h>
 #include <linux/backlight.h>
 #include <linux/ctype.h>
-#include <linux/seq_file.h>
-#include <linux/uaccess.h>
-#include <linux/slab.h>
-#include <linux/acpi.h>
+#include <linux/i8042.h>
+#include <linux/init.h>
 #include <linux/input.h>
 #include <linux/input/sparse-keymap.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
-
+#include <linux/seq_file.h>
+#include <linux/serio.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <acpi/video.h>
 
 MODULE_AUTHOR("Hiroshi Miura <miura@da-cha.org>");
 MODULE_AUTHOR("David Bronaugh <dbronaugh@linuxboxen.org>");
@@ -241,6 +243,42 @@ struct pcc_acpi {
        struct platform_device  *platform;
 };
 
+/*
+ * On some Panasonic models the volume up / down / mute keys send duplicate
+ * keypress events over the PS/2 kbd interface, filter these out.
+ */
+static bool panasonic_i8042_filter(unsigned char data, unsigned char str,
+                                  struct serio *port)
+{
+       static bool extended;
+
+       if (str & I8042_STR_AUXDATA)
+               return false;
+
+       if (data == 0xe0) {
+               extended = true;
+               return true;
+       } else if (extended) {
+               extended = false;
+
+               switch (data & 0x7f) {
+               case 0x20: /* e0 20 / e0 a0, Volume Mute press / release */
+               case 0x2e: /* e0 2e / e0 ae, Volume Down press / release */
+               case 0x30: /* e0 30 / e0 b0, Volume Up press / release */
+                       return true;
+               default:
+                       /*
+                        * Report the previously filtered e0 before continuing
+                        * with the next non-filtered byte.
+                        */
+                       serio_interrupt(port, 0xe0, 0);
+                       return false;
+               }
+       }
+
+       return false;
+}
+
 /* method access functions */
 static int acpi_pcc_write_sset(struct pcc_acpi *pcc, int func, int val)
 {
@@ -762,6 +800,8 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
        struct input_dev *hotk_input_dev = pcc->input_dev;
        int rc;
        unsigned long long result;
+       unsigned int key;
+       unsigned int updown;
 
        rc = acpi_evaluate_integer(pcc->handle, METHOD_HKEY_QUERY,
                                   NULL, &result);
@@ -770,20 +810,27 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
                return;
        }
 
+       key = result & 0xf;
+       updown = result & 0x80; /* 0x80 == key down; 0x00 = key up */
+
        /* hack: some firmware sends no key down for sleep / hibernate */
-       if ((result & 0xf) == 0x7 || (result & 0xf) == 0xa) {
-               if (result & 0x80)
+       if (key == 7 || key == 10) {
+               if (updown)
                        sleep_keydown_seen = 1;
                if (!sleep_keydown_seen)
                        sparse_keymap_report_event(hotk_input_dev,
-                                       result & 0xf, 0x80, false);
+                                       key, 0x80, false);
        }
 
-       if ((result & 0xf) == 0x7 || (result & 0xf) == 0x9 || (result & 0xf) == 0xa) {
-               if (!sparse_keymap_report_event(hotk_input_dev,
-                                               result & 0xf, result & 0x80, false))
-                       pr_err("Unknown hotkey event: 0x%04llx\n", result);
-       }
+       /*
+        * Don't report brightness key-presses if they are also reported
+        * by the ACPI video bus.
+        */
+       if ((key == 1 || key == 2) && acpi_video_handles_brightness_key_presses())
+               return;
+
+       if (!sparse_keymap_report_event(hotk_input_dev, key, updown, false))
+               pr_err("Unknown hotkey event: 0x%04llx\n", result);
 }
 
 static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event)
@@ -997,6 +1044,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
                pcc->platform = NULL;
        }
 
+       i8042_install_filter(panasonic_i8042_filter);
        return 0;
 
 out_platform:
@@ -1020,6 +1068,8 @@ static int acpi_pcc_hotkey_remove(struct acpi_device *device)
        if (!device || !pcc)
                return -EINVAL;
 
+       i8042_remove_filter(panasonic_i8042_filter);
+
        if (pcc->platform) {
                device_remove_file(&pcc->platform->dev, &dev_attr_cdpower);
                platform_device_unregister(pcc->platform);
index e6cb4a1..502dcd1 100644 (file)
@@ -4529,6 +4529,7 @@ static void thinkpad_acpi_amd_s2idle_restore(void)
        iounmap(addr);
 cleanup_resource:
        release_resource(res);
+       kfree(res);
 }
 
 static struct acpi_s2idle_dev_ops thinkpad_acpi_s2idle_dev_ops = {
@@ -6841,6 +6842,31 @@ static const struct backlight_ops ibm_backlight_data = {
 
 /* --------------------------------------------------------------------- */
 
+static int __init tpacpi_evaluate_bcl(struct acpi_device *adev, void *not_used)
+{
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *obj;
+       acpi_status status;
+       int rc;
+
+       status = acpi_evaluate_object(adev->handle, "_BCL", NULL, &buffer);
+       if (ACPI_FAILURE(status))
+               return 0;
+
+       obj = buffer.pointer;
+       if (!obj || obj->type != ACPI_TYPE_PACKAGE) {
+               acpi_handle_info(adev->handle,
+                                "Unknown _BCL data, please report this to %s\n",
+                                TPACPI_MAIL);
+               rc = 0;
+       } else {
+               rc = obj->package.count;
+       }
+       kfree(obj);
+
+       return rc;
+}
+
 /*
  * Call _BCL method of video device.  On some ThinkPads this will
  * switch the firmware to the ACPI brightness control mode.
@@ -6848,37 +6874,13 @@ static const struct backlight_ops ibm_backlight_data = {
 
 static int __init tpacpi_query_bcl_levels(acpi_handle handle)
 {
-       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-       union acpi_object *obj;
-       struct acpi_device *device, *child;
-       int rc;
+       struct acpi_device *device;
 
        device = acpi_fetch_acpi_dev(handle);
        if (!device)
                return 0;
 
-       rc = 0;
-       list_for_each_entry(child, &device->children, node) {
-               acpi_status status = acpi_evaluate_object(child->handle, "_BCL",
-                                                         NULL, &buffer);
-               if (ACPI_FAILURE(status)) {
-                       buffer.length = ACPI_ALLOCATE_BUFFER;
-                       continue;
-               }
-
-               obj = (union acpi_object *)buffer.pointer;
-               if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
-                       pr_err("Unknown _BCL data, please report this to %s\n",
-                               TPACPI_MAIL);
-                       rc = 0;
-               } else {
-                       rc = obj->package.count;
-               }
-               break;
-       }
-
-       kfree(buffer.pointer);
-       return rc;
+       return acpi_dev_for_each_child(device, tpacpi_evaluate_bcl, NULL);
 }
 
 
@@ -10299,21 +10301,15 @@ static struct ibm_struct proxsensor_driver_data = {
 #define DYTC_DISABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_MMC_BALANCE, 0)
 #define DYTC_ENABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_MMC_BALANCE, 1)
 
-enum dytc_profile_funcmode {
-       DYTC_FUNCMODE_NONE = 0,
-       DYTC_FUNCMODE_MMC,
-       DYTC_FUNCMODE_PSC,
-};
-
-static enum dytc_profile_funcmode dytc_profile_available;
 static enum platform_profile_option dytc_current_profile;
 static atomic_t dytc_ignore_event = ATOMIC_INIT(0);
 static DEFINE_MUTEX(dytc_mutex);
+static int dytc_capabilities;
 static bool dytc_mmc_get_available;
 
 static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *profile)
 {
-       if (dytc_profile_available == DYTC_FUNCMODE_MMC) {
+       if (dytc_capabilities & BIT(DYTC_FC_MMC)) {
                switch (dytcmode) {
                case DYTC_MODE_MMC_LOWPOWER:
                        *profile = PLATFORM_PROFILE_LOW_POWER;
@@ -10330,7 +10326,7 @@ static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *p
                }
                return 0;
        }
-       if (dytc_profile_available == DYTC_FUNCMODE_PSC) {
+       if (dytc_capabilities & BIT(DYTC_FC_PSC)) {
                switch (dytcmode) {
                case DYTC_MODE_PSC_LOWPOWER:
                        *profile = PLATFORM_PROFILE_LOW_POWER;
@@ -10352,21 +10348,21 @@ static int convert_profile_to_dytc(enum platform_profile_option profile, int *pe
 {
        switch (profile) {
        case PLATFORM_PROFILE_LOW_POWER:
-               if (dytc_profile_available == DYTC_FUNCMODE_MMC)
+               if (dytc_capabilities & BIT(DYTC_FC_MMC))
                        *perfmode = DYTC_MODE_MMC_LOWPOWER;
-               else if (dytc_profile_available == DYTC_FUNCMODE_PSC)
+               else if (dytc_capabilities & BIT(DYTC_FC_PSC))
                        *perfmode = DYTC_MODE_PSC_LOWPOWER;
                break;
        case PLATFORM_PROFILE_BALANCED:
-               if (dytc_profile_available == DYTC_FUNCMODE_MMC)
+               if (dytc_capabilities & BIT(DYTC_FC_MMC))
                        *perfmode = DYTC_MODE_MMC_BALANCE;
-               else if (dytc_profile_available == DYTC_FUNCMODE_PSC)
+               else if (dytc_capabilities & BIT(DYTC_FC_PSC))
                        *perfmode = DYTC_MODE_PSC_BALANCE;
                break;
        case PLATFORM_PROFILE_PERFORMANCE:
-               if (dytc_profile_available == DYTC_FUNCMODE_MMC)
+               if (dytc_capabilities & BIT(DYTC_FC_MMC))
                        *perfmode = DYTC_MODE_MMC_PERFORM;
-               else if (dytc_profile_available == DYTC_FUNCMODE_PSC)
+               else if (dytc_capabilities & BIT(DYTC_FC_PSC))
                        *perfmode = DYTC_MODE_PSC_PERFORM;
                break;
        default: /* Unknown profile */
@@ -10445,7 +10441,7 @@ static int dytc_profile_set(struct platform_profile_handler *pprof,
        if (err)
                goto unlock;
 
-       if (dytc_profile_available == DYTC_FUNCMODE_MMC) {
+       if (dytc_capabilities & BIT(DYTC_FC_MMC)) {
                if (profile == PLATFORM_PROFILE_BALANCED) {
                        /*
                         * To get back to balanced mode we need to issue a reset command.
@@ -10464,7 +10460,7 @@ static int dytc_profile_set(struct platform_profile_handler *pprof,
                                goto unlock;
                }
        }
-       if (dytc_profile_available == DYTC_FUNCMODE_PSC) {
+       if (dytc_capabilities & BIT(DYTC_FC_PSC)) {
                err = dytc_command(DYTC_SET_COMMAND(DYTC_FUNCTION_PSC, perfmode, 1), &output);
                if (err)
                        goto unlock;
@@ -10483,12 +10479,12 @@ static void dytc_profile_refresh(void)
        int perfmode;
 
        mutex_lock(&dytc_mutex);
-       if (dytc_profile_available == DYTC_FUNCMODE_MMC) {
+       if (dytc_capabilities & BIT(DYTC_FC_MMC)) {
                if (dytc_mmc_get_available)
                        err = dytc_command(DYTC_CMD_MMC_GET, &output);
                else
                        err = dytc_cql_command(DYTC_CMD_GET, &output);
-       } else if (dytc_profile_available == DYTC_FUNCMODE_PSC)
+       } else if (dytc_capabilities & BIT(DYTC_FC_PSC))
                err = dytc_command(DYTC_CMD_GET, &output);
 
        mutex_unlock(&dytc_mutex);
@@ -10517,7 +10513,6 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
        set_bit(PLATFORM_PROFILE_BALANCED, dytc_profile.choices);
        set_bit(PLATFORM_PROFILE_PERFORMANCE, dytc_profile.choices);
 
-       dytc_profile_available = DYTC_FUNCMODE_NONE;
        err = dytc_command(DYTC_CMD_QUERY, &output);
        if (err)
                return err;
@@ -10530,13 +10525,12 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
                return -ENODEV;
 
        /* Check what capabilities are supported */
-       err = dytc_command(DYTC_CMD_FUNC_CAP, &output);
+       err = dytc_command(DYTC_CMD_FUNC_CAP, &dytc_capabilities);
        if (err)
                return err;
 
-       if (output & BIT(DYTC_FC_MMC)) { /* MMC MODE */
-               dytc_profile_available = DYTC_FUNCMODE_MMC;
-
+       if (dytc_capabilities & BIT(DYTC_FC_MMC)) { /* MMC MODE */
+               pr_debug("MMC is supported\n");
                /*
                 * Check if MMC_GET functionality available
                 * Version > 6 and return success from MMC_GET command
@@ -10547,8 +10541,13 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
                        if (!err && ((output & DYTC_ERR_MASK) == DYTC_ERR_SUCCESS))
                                dytc_mmc_get_available = true;
                }
-       } else if (output & BIT(DYTC_FC_PSC)) { /* PSC MODE */
-               dytc_profile_available = DYTC_FUNCMODE_PSC;
+       } else if (dytc_capabilities & BIT(DYTC_FC_PSC)) { /* PSC MODE */
+               /* Support for this only works on AMD platforms */
+               if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) {
+                       dbg_printk(TPACPI_DBG_INIT, "PSC not support on Intel platforms\n");
+                       return -ENODEV;
+               }
+               pr_debug("PSC is supported\n");
        } else {
                dbg_printk(TPACPI_DBG_INIT, "No DYTC support available\n");
                return -ENODEV;
@@ -10574,7 +10573,6 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
 
 static void dytc_profile_exit(void)
 {
-       dytc_profile_available = DYTC_FUNCMODE_NONE;
        platform_profile_remove();
 }
 
index f446be7..4803759 100644 (file)
@@ -27,8 +27,8 @@
 #include <linux/pinctrl/machine.h>
 #include <linux/platform_data/lp855x.h>
 #include <linux/platform_device.h>
-#include <linux/pm.h>
 #include <linux/power/bq24190_charger.h>
+#include <linux/reboot.h>
 #include <linux/rmi.h>
 #include <linux/serdev.h>
 #include <linux/spi/spi.h>
@@ -889,6 +889,7 @@ static const struct pinctrl_map lenovo_yoga_tab2_830_1050_codec_pinctrl_map =
                          "INT33FC:02", "pmu_clk2_grp", "pmu_clk");
 
 static struct pinctrl *lenovo_yoga_tab2_830_1050_codec_pinctrl;
+static struct sys_off_handler *lenovo_yoga_tab2_830_1050_sys_off_handler;
 
 static int __init lenovo_yoga_tab2_830_1050_init_codec(void)
 {
@@ -933,9 +934,11 @@ err_put_device:
  * followed by a normal 3 second press to recover. Avoid this by doing an EFI
  * poweroff instead.
  */
-static void lenovo_yoga_tab2_830_1050_power_off(void)
+static int lenovo_yoga_tab2_830_1050_power_off(struct sys_off_data *data)
 {
        efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL);
+
+       return NOTIFY_DONE;
 }
 
 static int __init lenovo_yoga_tab2_830_1050_init(void)
@@ -950,13 +953,19 @@ static int __init lenovo_yoga_tab2_830_1050_init(void)
        if (ret)
                return ret;
 
-       pm_power_off = lenovo_yoga_tab2_830_1050_power_off;
+       /* SYS_OFF_PRIO_FIRMWARE + 1 so that it runs before acpi_power_off */
+       lenovo_yoga_tab2_830_1050_sys_off_handler =
+               register_sys_off_handler(SYS_OFF_MODE_POWER_OFF, SYS_OFF_PRIO_FIRMWARE + 1,
+                                        lenovo_yoga_tab2_830_1050_power_off, NULL);
+       if (IS_ERR(lenovo_yoga_tab2_830_1050_sys_off_handler))
+               return PTR_ERR(lenovo_yoga_tab2_830_1050_sys_off_handler);
+
        return 0;
 }
 
 static void lenovo_yoga_tab2_830_1050_exit(void)
 {
-       pm_power_off = NULL; /* Just turn poweroff into halt on module unload */
+       unregister_sys_off_handler(lenovo_yoga_tab2_830_1050_sys_off_handler);
 
        if (lenovo_yoga_tab2_830_1050_codec_pinctrl) {
                pinctrl_put(lenovo_yoga_tab2_830_1050_codec_pinctrl);
index 08d0a07..c7624d7 100644 (file)
@@ -146,6 +146,7 @@ static int __init versatile_reboot_probe(void)
        versatile_reboot_type = (enum versatile_reboot)reboot_id->data;
 
        syscon_regmap = syscon_node_to_regmap(np);
+       of_node_put(np);
        if (IS_ERR(syscon_regmap))
                return PTR_ERR(syscon_regmap);
 
index ec8a404..4339fa9 100644 (file)
@@ -3148,6 +3148,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
        ret = ab8500_fg_init_hw_registers(di);
        if (ret) {
                dev_err(dev, "failed to initialize registers\n");
+               destroy_workqueue(di->fg_wq);
                return ret;
        }
 
@@ -3159,6 +3160,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
        di->fg_psy = devm_power_supply_register(dev, &ab8500_fg_desc, &psy_cfg);
        if (IS_ERR(di->fg_psy)) {
                dev_err(dev, "failed to register FG psy\n");
+               destroy_workqueue(di->fg_wq);
                return PTR_ERR(di->fg_psy);
        }
 
@@ -3174,8 +3176,10 @@ static int ab8500_fg_probe(struct platform_device *pdev)
        /* Register primary interrupt handlers */
        for (i = 0; i < ARRAY_SIZE(ab8500_fg_irq); i++) {
                irq = platform_get_irq_byname(pdev, ab8500_fg_irq[i].name);
-               if (irq < 0)
+               if (irq < 0) {
+                       destroy_workqueue(di->fg_wq);
                        return irq;
+               }
 
                ret = devm_request_threaded_irq(dev, irq, NULL,
                                  ab8500_fg_irq[i].isr,
@@ -3185,6 +3189,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
                if (ret != 0) {
                        dev_err(dev, "failed to request %s IRQ %d: %d\n",
                                ab8500_fg_irq[i].name, irq, ret);
+                       destroy_workqueue(di->fg_wq);
                        return ret;
                }
                dev_dbg(dev, "Requested %s IRQ %d: %d\n",
@@ -3200,6 +3205,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
        ret = ab8500_fg_sysfs_init(di);
        if (ret) {
                dev_err(dev, "failed to create sysfs entry\n");
+               destroy_workqueue(di->fg_wq);
                return ret;
        }
 
@@ -3207,6 +3213,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
        if (ret) {
                dev_err(dev, "failed to create FG psy\n");
                ab8500_fg_sysfs_exit(di);
+               destroy_workqueue(di->fg_wq);
                return ret;
        }
 
index fad5890..470253c 100644 (file)
@@ -846,17 +846,17 @@ int power_supply_temp2resist_simple(struct power_supply_resistance_temp_table *t
 {
        int i, high, low;
 
-       /* Break loop at table_len - 1 because that is the highest index */
-       for (i = 0; i < table_len - 1; i++)
+       for (i = 0; i < table_len; i++)
                if (temp > table[i].temp)
                        break;
 
        /* The library function will deal with high == low */
-       if ((i == 0) || (i == (table_len - 1)))
-               high = i;
+       if (i == 0)
+               high = low = i;
+       else if (i == table_len)
+               high = low = i - 1;
        else
-               high = i - 1;
-       low = i;
+               high = (low = i) - 1;
 
        return fixp_linear_interpolate(table[low].temp,
                                       table[low].resistance,
@@ -958,17 +958,17 @@ int power_supply_ocv2cap_simple(struct power_supply_battery_ocv_table *table,
 {
        int i, high, low;
 
-       /* Break loop at table_len - 1 because that is the highest index */
-       for (i = 0; i < table_len - 1; i++)
+       for (i = 0; i < table_len; i++)
                if (ocv > table[i].ocv)
                        break;
 
        /* The library function will deal with high == low */
-       if ((i == 0) || (i == (table_len - 1)))
-               high = i - 1;
+       if (i == 0)
+               high = low = i;
+       else if (i == table_len)
+               high = low = i - 1;
        else
-               high = i; /* i.e. i == 0 */
-       low = i;
+               high = (low = i) - 1;
 
        return fixp_linear_interpolate(table[low].ocv,
                                       table[low].capacity,
index f5eced0..2ff7717 100644 (file)
@@ -53,7 +53,7 @@ static u64 set_pd_power_limit(struct dtpm *dtpm, u64 power_limit)
 
        for (i = 0; i < pd->nr_perf_states; i++) {
 
-               power = pd->table[i].power * MICROWATT_PER_MILLIWATT * nr_cpus;
+               power = pd->table[i].power * nr_cpus;
 
                if (power > power_limit)
                        break;
@@ -63,42 +63,26 @@ static u64 set_pd_power_limit(struct dtpm *dtpm, u64 power_limit)
 
        freq_qos_update_request(&dtpm_cpu->qos_req, freq);
 
-       power_limit = pd->table[i - 1].power *
-               MICROWATT_PER_MILLIWATT * nr_cpus;
+       power_limit = pd->table[i - 1].power * nr_cpus;
 
        return power_limit;
 }
 
 static u64 scale_pd_power_uw(struct cpumask *pd_mask, u64 power)
 {
-       unsigned long max = 0, sum_util = 0;
+       unsigned long max, sum_util = 0;
        int cpu;
 
-       for_each_cpu_and(cpu, pd_mask, cpu_online_mask) {
-
-               /*
-                * The capacity is the same for all CPUs belonging to
-                * the same perf domain, so a single call to
-                * arch_scale_cpu_capacity() is enough. However, we
-                * need the CPU parameter to be initialized by the
-                * loop, so the call ends up in this block.
-                *
-                * We can initialize 'max' with a cpumask_first() call
-                * before the loop but the bits computation is not
-                * worth given the arch_scale_cpu_capacity() just
-                * returns a value where the resulting assembly code
-                * will be optimized by the compiler.
-                */
-               max = arch_scale_cpu_capacity(cpu);
-               sum_util += sched_cpu_util(cpu, max);
-       }
-
        /*
-        * In the improbable case where all the CPUs of the perf
-        * domain are offline, 'max' will be zero and will lead to an
-        * illegal operation with a zero division.
+        * The capacity is the same for all CPUs belonging to
+        * the same perf domain.
         */
-       return max ? (power * ((sum_util << 10) / max)) >> 10 : 0;
+       max = arch_scale_cpu_capacity(cpumask_first(pd_mask));
+
+       for_each_cpu_and(cpu, pd_mask, cpu_online_mask)
+               sum_util += sched_cpu_util(cpu);
+
+       return (power * ((sum_util << 10) / max)) >> 10;
 }
 
 static u64 get_pd_power_uw(struct dtpm *dtpm)
index a9c99d9..21d624f 100644 (file)
@@ -1109,6 +1109,7 @@ static const struct x86_cpu_id rapl_ids[] __initconst = {
        X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L,         &rapl_defaults_core),
        X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_N,         &rapl_defaults_core),
        X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE,          &rapl_defaults_core),
+       X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P,        &rapl_defaults_core),
        X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X,    &rapl_defaults_spr_server),
        X86_MATCH_INTEL_FAM6_MODEL(LAKEFIELD,           &rapl_defaults_core),
 
index 9d23984..bc6adda 100644 (file)
@@ -140,7 +140,9 @@ static const struct x86_cpu_id pl4_support_ids[] = {
        { X86_VENDOR_INTEL, 6, INTEL_FAM6_TIGERLAKE_L, X86_FEATURE_ANY },
        { X86_VENDOR_INTEL, 6, INTEL_FAM6_ALDERLAKE, X86_FEATURE_ANY },
        { X86_VENDOR_INTEL, 6, INTEL_FAM6_ALDERLAKE_L, X86_FEATURE_ANY },
+       { X86_VENDOR_INTEL, 6, INTEL_FAM6_ALDERLAKE_N, X86_FEATURE_ANY },
        { X86_VENDOR_INTEL, 6, INTEL_FAM6_RAPTORLAKE, X86_FEATURE_ANY },
+       { X86_VENDOR_INTEL, 6, INTEL_FAM6_RAPTORLAKE_P, X86_FEATURE_ANY },
        {}
 };
 
index 458218f..fe4971b 100644 (file)
@@ -176,6 +176,7 @@ config PTP_1588_CLOCK_OCP
        depends on !S390
        depends on COMMON_CLK
        select NET_DEVLINK
+       select CRC16
        help
          This driver adds support for an OpenCompute time card.
 
index 904de8d..60d13a9 100644 (file)
@@ -140,6 +140,16 @@ config PWM_BRCMSTB
          To compile this driver as a module, choose M Here: the module
          will be called pwm-brcmstb.c.
 
+config PWM_CLK
+       tristate "Clock based PWM support"
+       depends on HAVE_CLK || COMPILE_TEST
+       help
+         Generic PWM framework driver for outputs that can be
+         muxed to clocks.
+
+         To compile this driver as a module, choose M here: the module
+         will be called pwm-clk.
+
 config PWM_CLPS711X
        tristate "CLPS711X PWM support"
        depends on ARCH_CLPS711X || COMPILE_TEST
index 5c08bdb..7bf1a29 100644 (file)
@@ -10,6 +10,7 @@ obj-$(CONFIG_PWM_BCM_KONA)    += pwm-bcm-kona.o
 obj-$(CONFIG_PWM_BCM2835)      += pwm-bcm2835.o
 obj-$(CONFIG_PWM_BERLIN)       += pwm-berlin.o
 obj-$(CONFIG_PWM_BRCMSTB)      += pwm-brcmstb.o
+obj-$(CONFIG_PWM_CLK)          += pwm-clk.o
 obj-$(CONFIG_PWM_CLPS711X)     += pwm-clps711x.o
 obj-$(CONFIG_PWM_CRC)          += pwm-crc.o
 obj-$(CONFIG_PWM_CROS_EC)      += pwm-cros-ec.o
index c7552df..0e04241 100644 (file)
@@ -235,18 +235,8 @@ EXPORT_SYMBOL_GPL(pwm_get_chip_data);
 
 static bool pwm_ops_check(const struct pwm_chip *chip)
 {
-
        const struct pwm_ops *ops = chip->ops;
 
-       /* driver supports legacy, non-atomic operation */
-       if (ops->config && ops->enable && ops->disable) {
-               if (IS_ENABLED(CONFIG_PWM_DEBUG))
-                       dev_warn(chip->dev,
-                                "Driver needs updating to atomic API\n");
-
-               return true;
-       }
-
        if (!ops->apply)
                return false;
 
@@ -548,73 +538,6 @@ static void pwm_apply_state_debug(struct pwm_device *pwm,
        }
 }
 
-static int pwm_apply_legacy(struct pwm_chip *chip, struct pwm_device *pwm,
-                           const struct pwm_state *state)
-{
-       int err;
-       struct pwm_state initial_state = pwm->state;
-
-       if (state->polarity != pwm->state.polarity) {
-               if (!chip->ops->set_polarity)
-                       return -EINVAL;
-
-               /*
-                * Changing the polarity of a running PWM is only allowed when
-                * the PWM driver implements ->apply().
-                */
-               if (pwm->state.enabled) {
-                       chip->ops->disable(chip, pwm);
-
-                       /*
-                        * Update pwm->state already here in case
-                        * .set_polarity() or another callback depend on that.
-                        */
-                       pwm->state.enabled = false;
-               }
-
-               err = chip->ops->set_polarity(chip, pwm, state->polarity);
-               if (err)
-                       goto rollback;
-
-               pwm->state.polarity = state->polarity;
-       }
-
-       if (!state->enabled) {
-               if (pwm->state.enabled)
-                       chip->ops->disable(chip, pwm);
-
-               return 0;
-       }
-
-       /*
-        * We cannot skip calling ->config even if state->period ==
-        * pwm->state.period && state->duty_cycle == pwm->state.duty_cycle
-        * because we might have exited early in the last call to
-        * pwm_apply_state because of !state->enabled and so the two values in
-        * pwm->state might not be configured in hardware.
-        */
-       err = chip->ops->config(pwm->chip, pwm,
-                               state->duty_cycle,
-                               state->period);
-       if (err)
-               goto rollback;
-
-       pwm->state.period = state->period;
-       pwm->state.duty_cycle = state->duty_cycle;
-
-       if (!pwm->state.enabled) {
-               err = chip->ops->enable(chip, pwm);
-               if (err)
-                       goto rollback;
-       }
-
-       return 0;
-
-rollback:
-       pwm->state = initial_state;
-       return err;
-}
-
 /**
  * pwm_apply_state() - atomically apply a new state to a PWM device
  * @pwm: PWM device
@@ -647,10 +570,7 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
            state->usage_power == pwm->state.usage_power)
                return 0;
 
-       if (chip->ops->apply)
-               err = chip->ops->apply(chip, pwm, state);
-       else
-               err = pwm_apply_legacy(chip, pwm, state);
+       err = chip->ops->apply(chip, pwm, state);
        if (err)
                return err;
 
index 3977a0f..2837b4c 100644 (file)
@@ -304,7 +304,7 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
        /*
         * Find best clk divisor:
         * the smallest divisor which can fulfill the period_ns requirements.
-        * If there is a gclk, the first divisor is actuallly the gclk selector
+        * If there is a gclk, the first divisor is actually the gclk selector
         */
        if (tcbpwmc->gclk)
                i = 1;
diff --git a/drivers/pwm/pwm-clk.c b/drivers/pwm/pwm-clk.c
new file mode 100644 (file)
index 0000000..c2a503d
--- /dev/null
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Clock based PWM controller
+ *
+ * Copyright (c) 2021 Nikita Travkin <nikita@trvn.ru>
+ *
+ * This is an "adapter" driver that allows PWM consumers to use
+ * system clocks with duty cycle control as PWM outputs.
+ *
+ * Limitations:
+ * - Due to the fact that exact behavior depends on the underlying
+ *   clock driver, various limitations are possible.
+ * - Underlying clock may not be able to give 0% or 100% duty cycle
+ *   (constant off or on), exact behavior will depend on the clock.
+ * - When the PWM is disabled, the clock will be disabled as well,
+ *   line state will depend on the clock.
+ * - The clk API doesn't expose the necessary calls to implement
+ *   .get_state().
+ */
+
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/pwm.h>
+
+struct pwm_clk_chip {
+       struct pwm_chip chip;
+       struct clk *clk;
+       bool clk_enabled;
+};
+
+#define to_pwm_clk_chip(_chip) container_of(_chip, struct pwm_clk_chip, chip)
+
+static int pwm_clk_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+                        const struct pwm_state *state)
+{
+       struct pwm_clk_chip *pcchip = to_pwm_clk_chip(chip);
+       int ret;
+       u32 rate;
+       u64 period = state->period;
+       u64 duty_cycle = state->duty_cycle;
+
+       if (!state->enabled) {
+               if (pwm->state.enabled) {
+                       clk_disable(pcchip->clk);
+                       pcchip->clk_enabled = false;
+               }
+               return 0;
+       } else if (!pwm->state.enabled) {
+               ret = clk_enable(pcchip->clk);
+               if (ret)
+                       return ret;
+               pcchip->clk_enabled = true;
+       }
+
+       /*
+        * We have to enable the clk before setting the rate and duty_cycle,
+        * that however results in a window where the clk is on with a
+        * (potentially) different setting. Also setting period and duty_cycle
+        * are two separate calls, so that probably isn't atomic either.
+        */
+
+       rate = DIV64_U64_ROUND_UP(NSEC_PER_SEC, period);
+       ret = clk_set_rate(pcchip->clk, rate);
+       if (ret)
+               return ret;
+
+       if (state->polarity == PWM_POLARITY_INVERSED)
+               duty_cycle = period - duty_cycle;
+
+       return clk_set_duty_cycle(pcchip->clk, duty_cycle, period);
+}
+
+static const struct pwm_ops pwm_clk_ops = {
+       .apply = pwm_clk_apply,
+       .owner = THIS_MODULE,
+};
+
+static int pwm_clk_probe(struct platform_device *pdev)
+{
+       struct pwm_clk_chip *pcchip;
+       int ret;
+
+       pcchip = devm_kzalloc(&pdev->dev, sizeof(*pcchip), GFP_KERNEL);
+       if (!pcchip)
+               return -ENOMEM;
+
+       pcchip->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(pcchip->clk))
+               return dev_err_probe(&pdev->dev, PTR_ERR(pcchip->clk),
+                                    "Failed to get clock\n");
+
+       pcchip->chip.dev = &pdev->dev;
+       pcchip->chip.ops = &pwm_clk_ops;
+       pcchip->chip.npwm = 1;
+
+       ret = clk_prepare(pcchip->clk);
+       if (ret < 0)
+               return dev_err_probe(&pdev->dev, ret, "Failed to prepare clock\n");
+
+       ret = pwmchip_add(&pcchip->chip);
+       if (ret < 0) {
+               clk_unprepare(pcchip->clk);
+               return dev_err_probe(&pdev->dev, ret, "Failed to add pwm chip\n");
+       }
+
+       platform_set_drvdata(pdev, pcchip);
+       return 0;
+}
+
+static int pwm_clk_remove(struct platform_device *pdev)
+{
+       struct pwm_clk_chip *pcchip = platform_get_drvdata(pdev);
+
+       pwmchip_remove(&pcchip->chip);
+
+       if (pcchip->clk_enabled)
+               clk_disable(pcchip->clk);
+
+       clk_unprepare(pcchip->clk);
+
+       return 0;
+}
+
+static const struct of_device_id pwm_clk_dt_ids[] = {
+       { .compatible = "clk-pwm", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, pwm_clk_dt_ids);
+
+static struct platform_driver pwm_clk_driver = {
+       .driver = {
+               .name = "pwm-clk",
+               .of_match_table = pwm_clk_dt_ids,
+       },
+       .probe = pwm_clk_probe,
+       .remove = pwm_clk_remove,
+};
+module_platform_driver(pwm_clk_driver);
+
+MODULE_ALIAS("platform:pwm-clk");
+MODULE_AUTHOR("Nikita Travkin <nikita@trvn.ru>");
+MODULE_DESCRIPTION("Clock based PWM driver");
+MODULE_LICENSE("GPL");
index 272e0b5..763f2e3 100644 (file)
@@ -98,7 +98,7 @@ struct lpc18xx_pwm_chip {
        unsigned long clk_rate;
        unsigned int period_ns;
        unsigned int min_period_ns;
-       unsigned int max_period_ns;
+       u64 max_period_ns;
        unsigned int period_event;
        unsigned long event_map;
        struct mutex res_lock;
@@ -145,40 +145,48 @@ static void lpc18xx_pwm_set_conflict_res(struct lpc18xx_pwm_chip *lpc18xx_pwm,
        mutex_unlock(&lpc18xx_pwm->res_lock);
 }
 
-static void lpc18xx_pwm_config_period(struct pwm_chip *chip, int period_ns)
+static void lpc18xx_pwm_config_period(struct pwm_chip *chip, u64 period_ns)
 {
        struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
-       u64 val;
+       u32 val;
 
-       val = (u64)period_ns * lpc18xx_pwm->clk_rate;
-       do_div(val, NSEC_PER_SEC);
+       /*
+        * With clk_rate < NSEC_PER_SEC this cannot overflow.
+        * With period_ns < max_period_ns this also fits into an u32.
+        * As period_ns >= min_period_ns = DIV_ROUND_UP(NSEC_PER_SEC, lpc18xx_pwm->clk_rate);
+        * we have val >= 1.
+        */
+       val = mul_u64_u64_div_u64(period_ns, lpc18xx_pwm->clk_rate, NSEC_PER_SEC);
 
        lpc18xx_pwm_writel(lpc18xx_pwm,
                           LPC18XX_PWM_MATCH(lpc18xx_pwm->period_event),
-                          (u32)val - 1);
+                          val - 1);
 
        lpc18xx_pwm_writel(lpc18xx_pwm,
                           LPC18XX_PWM_MATCHREL(lpc18xx_pwm->period_event),
-                          (u32)val - 1);
+                          val - 1);
 }
 
 static void lpc18xx_pwm_config_duty(struct pwm_chip *chip,
-                                   struct pwm_device *pwm, int duty_ns)
+                                   struct pwm_device *pwm, u64 duty_ns)
 {
        struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
        struct lpc18xx_pwm_data *lpc18xx_data = &lpc18xx_pwm->channeldata[pwm->hwpwm];
-       u64 val;
+       u32 val;
 
-       val = (u64)duty_ns * lpc18xx_pwm->clk_rate;
-       do_div(val, NSEC_PER_SEC);
+       /*
+        * With clk_rate < NSEC_PER_SEC this cannot overflow.
+        * With duty_ns <= period_ns < max_period_ns this also fits into an u32.
+        */
+       val = mul_u64_u64_div_u64(duty_ns, lpc18xx_pwm->clk_rate, NSEC_PER_SEC);
 
        lpc18xx_pwm_writel(lpc18xx_pwm,
                           LPC18XX_PWM_MATCH(lpc18xx_data->duty_event),
-                          (u32)val);
+                          val);
 
        lpc18xx_pwm_writel(lpc18xx_pwm,
                           LPC18XX_PWM_MATCHREL(lpc18xx_data->duty_event),
-                          (u32)val);
+                          val);
 }
 
 static int lpc18xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -359,30 +367,35 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev)
                return PTR_ERR(lpc18xx_pwm->base);
 
        lpc18xx_pwm->pwm_clk = devm_clk_get(&pdev->dev, "pwm");
-       if (IS_ERR(lpc18xx_pwm->pwm_clk)) {
-               dev_err(&pdev->dev, "failed to get pwm clock\n");
-               return PTR_ERR(lpc18xx_pwm->pwm_clk);
-       }
+       if (IS_ERR(lpc18xx_pwm->pwm_clk))
+               return dev_err_probe(&pdev->dev, PTR_ERR(lpc18xx_pwm->pwm_clk),
+                                    "failed to get pwm clock\n");
 
        ret = clk_prepare_enable(lpc18xx_pwm->pwm_clk);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "could not prepare or enable pwm clock\n");
-               return ret;
-       }
+       if (ret < 0)
+               return dev_err_probe(&pdev->dev, ret,
+                                    "could not prepare or enable pwm clock\n");
 
        lpc18xx_pwm->clk_rate = clk_get_rate(lpc18xx_pwm->pwm_clk);
        if (!lpc18xx_pwm->clk_rate) {
-               dev_err(&pdev->dev, "pwm clock has no frequency\n");
-               ret = -EINVAL;
+               ret = dev_err_probe(&pdev->dev,
+                                   -EINVAL, "pwm clock has no frequency\n");
+               goto disable_pwmclk;
+       }
+
+       /*
+        * If clkrate is too fast, the calculations in .apply() might overflow.
+        */
+       if (lpc18xx_pwm->clk_rate > NSEC_PER_SEC) {
+               ret = dev_err_probe(&pdev->dev, -EINVAL, "pwm clock to fast\n");
                goto disable_pwmclk;
        }
 
        mutex_init(&lpc18xx_pwm->res_lock);
        mutex_init(&lpc18xx_pwm->period_lock);
 
-       val = (u64)NSEC_PER_SEC * LPC18XX_PWM_TIMER_MAX;
-       do_div(val, lpc18xx_pwm->clk_rate);
-       lpc18xx_pwm->max_period_ns = val;
+       lpc18xx_pwm->max_period_ns =
+               mul_u64_u64_div_u64(NSEC_PER_SEC, LPC18XX_PWM_TIMER_MAX, lpc18xx_pwm->clk_rate);
 
        lpc18xx_pwm->min_period_ns = DIV_ROUND_UP(NSEC_PER_SEC,
                                                  lpc18xx_pwm->clk_rate);
@@ -423,7 +436,7 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev)
 
        ret = pwmchip_add(&lpc18xx_pwm->chip);
        if (ret < 0) {
-               dev_err(&pdev->dev, "pwmchip_add failed: %d\n", ret);
+               dev_err_probe(&pdev->dev, ret, "pwmchip_add failed\n");
                goto disable_pwmclk;
        }
 
index d28c087..6901a44 100644 (file)
@@ -323,6 +323,12 @@ static const struct pwm_mediatek_of_data mt8183_pwm_data = {
        .has_ck_26m_sel = true,
 };
 
+static const struct pwm_mediatek_of_data mt8365_pwm_data = {
+       .num_pwms = 3,
+       .pwm45_fixup = false,
+       .has_ck_26m_sel = true,
+};
+
 static const struct pwm_mediatek_of_data mt8516_pwm_data = {
        .num_pwms = 5,
        .pwm45_fixup = false,
@@ -337,6 +343,7 @@ static const struct of_device_id pwm_mediatek_of_match[] = {
        { .compatible = "mediatek,mt7628-pwm", .data = &mt7628_pwm_data },
        { .compatible = "mediatek,mt7629-pwm", .data = &mt7629_pwm_data },
        { .compatible = "mediatek,mt8183-pwm", .data = &mt8183_pwm_data },
+       { .compatible = "mediatek,mt8365-pwm", .data = &mt8365_pwm_data },
        { .compatible = "mediatek,mt8516-pwm", .data = &mt8516_pwm_data },
        { },
 };
index e6d05a3..2d4fa5e 100644 (file)
@@ -23,7 +23,7 @@
 #define PWM_SIFIVE_PWMCFG              0x0
 #define PWM_SIFIVE_PWMCOUNT            0x8
 #define PWM_SIFIVE_PWMS                        0x10
-#define PWM_SIFIVE_PWMCMP0             0x20
+#define PWM_SIFIVE_PWMCMP(i)           (0x20 + 4 * (i))
 
 /* PWMCFG fields */
 #define PWM_SIFIVE_PWMCFG_SCALE                GENMASK(3, 0)
 #define PWM_SIFIVE_PWMCFG_GANG         BIT(24)
 #define PWM_SIFIVE_PWMCFG_IP           BIT(28)
 
-/* PWM_SIFIVE_SIZE_PWMCMP is used to calculate offset for pwmcmpX registers */
-#define PWM_SIFIVE_SIZE_PWMCMP         4
 #define PWM_SIFIVE_CMPWIDTH            16
 #define PWM_SIFIVE_DEFAULT_PERIOD      10000000
 
 struct pwm_sifive_ddata {
        struct pwm_chip chip;
-       struct mutex lock; /* lock to protect user_count */
+       struct mutex lock; /* lock to protect user_count and approx_period */
        struct notifier_block notifier;
        struct clk *clk;
        void __iomem *regs;
@@ -78,6 +76,7 @@ static void pwm_sifive_free(struct pwm_chip *chip, struct pwm_device *pwm)
        mutex_unlock(&ddata->lock);
 }
 
+/* Called holding ddata->lock */
 static void pwm_sifive_update_clock(struct pwm_sifive_ddata *ddata,
                                    unsigned long rate)
 {
@@ -112,8 +111,7 @@ static void pwm_sifive_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
        struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip);
        u32 duty, val;
 
-       duty = readl(ddata->regs + PWM_SIFIVE_PWMCMP0 +
-                    pwm->hwpwm * PWM_SIFIVE_SIZE_PWMCMP);
+       duty = readl(ddata->regs + PWM_SIFIVE_PWMCMP(pwm->hwpwm));
 
        state->enabled = duty > 0;
 
@@ -127,24 +125,6 @@ static void pwm_sifive_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
        state->polarity = PWM_POLARITY_INVERSED;
 }
 
-static int pwm_sifive_enable(struct pwm_chip *chip, bool enable)
-{
-       struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip);
-       int ret;
-
-       if (enable) {
-               ret = clk_enable(ddata->clk);
-               if (ret) {
-                       dev_err(ddata->chip.dev, "Enable clk failed\n");
-                       return ret;
-               }
-       } else {
-               clk_disable(ddata->clk);
-       }
-
-       return 0;
-}
-
 static int pwm_sifive_apply(struct pwm_chip *chip, struct pwm_device *pwm,
                            const struct pwm_state *state)
 {
@@ -159,13 +139,6 @@ static int pwm_sifive_apply(struct pwm_chip *chip, struct pwm_device *pwm,
        if (state->polarity != PWM_POLARITY_INVERSED)
                return -EINVAL;
 
-       ret = clk_enable(ddata->clk);
-       if (ret) {
-               dev_err(ddata->chip.dev, "Enable clk failed\n");
-               return ret;
-       }
-
-       mutex_lock(&ddata->lock);
        cur_state = pwm->state;
        enabled = cur_state.enabled;
 
@@ -184,25 +157,36 @@ static int pwm_sifive_apply(struct pwm_chip *chip, struct pwm_device *pwm,
        /* The hardware cannot generate a 100% duty cycle */
        frac = min(frac, (1U << PWM_SIFIVE_CMPWIDTH) - 1);
 
+       mutex_lock(&ddata->lock);
        if (state->period != ddata->approx_period) {
                if (ddata->user_count != 1) {
-                       ret = -EBUSY;
-                       goto exit;
+                       mutex_unlock(&ddata->lock);
+                       return -EBUSY;
                }
                ddata->approx_period = state->period;
                pwm_sifive_update_clock(ddata, clk_get_rate(ddata->clk));
        }
+       mutex_unlock(&ddata->lock);
 
-       writel(frac, ddata->regs + PWM_SIFIVE_PWMCMP0 +
-              pwm->hwpwm * PWM_SIFIVE_SIZE_PWMCMP);
+       /*
+        * If the PWM is enabled the clk is already on. So only enable it
+        * conditionally to have it on exactly once afterwards independent of
+        * the PWM state.
+        */
+       if (!enabled) {
+               ret = clk_enable(ddata->clk);
+               if (ret) {
+                       dev_err(ddata->chip.dev, "Enable clk failed\n");
+                       return ret;
+               }
+       }
 
-       if (state->enabled != enabled)
-               pwm_sifive_enable(chip, state->enabled);
+       writel(frac, ddata->regs + PWM_SIFIVE_PWMCMP(pwm->hwpwm));
 
-exit:
-       clk_disable(ddata->clk);
-       mutex_unlock(&ddata->lock);
-       return ret;
+       if (!state->enabled)
+               clk_disable(ddata->clk);
+
+       return 0;
 }
 
 static const struct pwm_ops pwm_sifive_ops = {
@@ -232,6 +216,8 @@ static int pwm_sifive_probe(struct platform_device *pdev)
        struct pwm_sifive_ddata *ddata;
        struct pwm_chip *chip;
        int ret;
+       u32 val;
+       unsigned int enabled_pwms = 0, enabled_clks = 1;
 
        ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
        if (!ddata)
@@ -258,6 +244,33 @@ static int pwm_sifive_probe(struct platform_device *pdev)
                return ret;
        }
 
+       val = readl(ddata->regs + PWM_SIFIVE_PWMCFG);
+       if (val & PWM_SIFIVE_PWMCFG_EN_ALWAYS) {
+               unsigned int i;
+
+               for (i = 0; i < chip->npwm; ++i) {
+                       val = readl(ddata->regs + PWM_SIFIVE_PWMCMP(i));
+                       if (val > 0)
+                               ++enabled_pwms;
+               }
+       }
+
+       /* The clk should be on once for each running PWM. */
+       if (enabled_pwms) {
+               while (enabled_clks < enabled_pwms) {
+                       /* This is not expected to fail as the clk is already on */
+                       ret = clk_enable(ddata->clk);
+                       if (unlikely(ret)) {
+                               dev_err_probe(dev, ret, "Failed to enable clk\n");
+                               goto disable_clk;
+                       }
+                       ++enabled_clks;
+               }
+       } else {
+               clk_disable(ddata->clk);
+               enabled_clks = 0;
+       }
+
        /* Watch for changes to underlying clock frequency */
        ddata->notifier.notifier_call = pwm_sifive_clock_notifier;
        ret = clk_notifier_register(ddata->clk, &ddata->notifier);
@@ -280,7 +293,11 @@ static int pwm_sifive_probe(struct platform_device *pdev)
 unregister_clk:
        clk_notifier_unregister(ddata->clk, &ddata->notifier);
 disable_clk:
-       clk_disable_unprepare(ddata->clk);
+       while (enabled_clks) {
+               clk_disable(ddata->clk);
+               --enabled_clks;
+       }
+       clk_unprepare(ddata->clk);
 
        return ret;
 }
@@ -288,23 +305,19 @@ disable_clk:
 static int pwm_sifive_remove(struct platform_device *dev)
 {
        struct pwm_sifive_ddata *ddata = platform_get_drvdata(dev);
-       bool is_enabled = false;
        struct pwm_device *pwm;
        int ch;
 
+       pwmchip_remove(&ddata->chip);
+       clk_notifier_unregister(ddata->clk, &ddata->notifier);
+
        for (ch = 0; ch < ddata->chip.npwm; ch++) {
                pwm = &ddata->chip.pwms[ch];
-               if (pwm->state.enabled) {
-                       is_enabled = true;
-                       break;
-               }
+               if (pwm->state.enabled)
+                       clk_disable(ddata->clk);
        }
-       if (is_enabled)
-               clk_disable(ddata->clk);
 
-       clk_disable_unprepare(ddata->clk);
-       pwmchip_remove(&ddata->chip);
-       clk_notifier_unregister(ddata->clk, &ddata->notifier);
+       clk_unprepare(ddata->clk);
 
        return 0;
 }
index ed0b63d..8fb84b4 100644 (file)
@@ -7,6 +7,22 @@
  *
  * This driver is a complete rewrite of the former pwm-twl6030.c authorded by:
  * Hemanth V <hemanthv@ti.com>
+ *
+ * Reference manual for the twl6030 is available at:
+ * https://www.ti.com/lit/ds/symlink/twl6030.pdf
+ *
+ * Limitations:
+ * - The twl6030 hardware only supports two period lengths (128 clock ticks and
+ *   64 clock ticks), the driver only uses 128 ticks
+ * - The hardware doesn't support ON = 0, so the active part of a period doesn't
+ *   start at its beginning.
+ * - The hardware could support inverted polarity (with a similar limitation as
+ *   for normal: the last clock tick is always inactive).
+ * - The hardware emits a constant low output when disabled.
+ * - A request for .duty_cycle = 0 results in an output wave with one active
+ *   clock tick per period. This should better use the disabled state.
+ * - The driver only implements setting the relative duty cycle.
+ * - The driver doesn't implement .get_state().
  */
 
 #include <linux/module.h>
index cbe0f96..23e3e4a 100644 (file)
@@ -546,6 +546,16 @@ config REGULATOR_MAX1586
          regulator via I2C bus. The provided regulator is suitable
          for PXA27x chips to control VCC_CORE and VCC_USIM voltages.
 
+config REGULATOR_MAX597X
+       tristate "Maxim 597x power switch and monitor"
+       depends on I2C
+       depends on OF
+       depends on MFD_MAX597X
+       help
+         This driver controls a Maxim 5970/5978 switch via I2C bus.
+         The MAX5970/5978 is a smart switch with no output regulation, but
+         fault protection and voltage and current monitoring capabilities.
+
 config REGULATOR_MAX77620
        tristate "Maxim 77620/MAX20024 voltage regulator"
        depends on MFD_MAX77620 || COMPILE_TEST
@@ -804,6 +814,14 @@ config REGULATOR_MT6360
          2-channel buck with Thermal Shutdown and Overload Protection
          6-channel High PSRR and Low Dropout LDO.
 
+config REGULATOR_MT6370
+       tristate "MT6370 SubPMIC Regulator"
+       depends on MFD_MT6370
+       help
+         Say Y here to enable MT6370 regulator support.
+         This driver supports the control for DisplayBias voltages and one
+         general purpose LDO which is commonly used to drive the vibrator.
+
 config REGULATOR_MT6380
        tristate "MediaTek MT6380 PMIC"
        depends on MTK_PMIC_WRAP
@@ -1047,6 +1065,16 @@ config REGULATOR_RT5033
          RT5033 PMIC. The device supports multiple regulators like
          current source, LDO and Buck.
 
+config REGULATOR_RT5120
+       tristate "Richtek RT5120 PMIC Regulators"
+       depends on MFD_RT5120
+       help
+         This adds support for voltage regulator in Richtek RT5120 PMIC.
+         It integrates 4 channels buck controller, 1 channel LDO, 1 EXTEN
+         to control external power source. Only BUCK1 is adjustable from
+         600mV to 1395mV, per step 6.250mV. The others are all fixed voltage
+         by external hardware circuit.
+
 config REGULATOR_RT5190A
        tristate "Richtek RT5190A PMIC"
        depends on I2C
index 8d3ee8b..fa49bb6 100644 (file)
@@ -67,6 +67,7 @@ obj-$(CONFIG_REGULATOR_LTC3589) += ltc3589.o
 obj-$(CONFIG_REGULATOR_LTC3676) += ltc3676.o
 obj-$(CONFIG_REGULATOR_MAX14577) += max14577-regulator.o
 obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
+obj-$(CONFIG_REGULATOR_MAX597X) += max597x-regulator.o
 obj-$(CONFIG_REGULATOR_MAX77620) += max77620-regulator.o
 obj-$(CONFIG_REGULATOR_MAX77650) += max77650-regulator.o
 obj-$(CONFIG_REGULATOR_MAX8649)        += max8649.o
@@ -97,6 +98,7 @@ obj-$(CONFIG_REGULATOR_MT6323)        += mt6323-regulator.o
 obj-$(CONFIG_REGULATOR_MT6358) += mt6358-regulator.o
 obj-$(CONFIG_REGULATOR_MT6359) += mt6359-regulator.o
 obj-$(CONFIG_REGULATOR_MT6360) += mt6360-regulator.o
+obj-$(CONFIG_REGULATOR_MT6370) += mt6370-regulator.o
 obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o
 obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
 obj-$(CONFIG_REGULATOR_MTK_DVFSRC) += mtk-dvfsrc-regulator.o
@@ -126,6 +128,7 @@ obj-$(CONFIG_REGULATOR_ROHM)        += rohm-regulator.o
 obj-$(CONFIG_REGULATOR_RT4801) += rt4801-regulator.o
 obj-$(CONFIG_REGULATOR_RT4831) += rt4831-regulator.o
 obj-$(CONFIG_REGULATOR_RT5033) += rt5033-regulator.o
+obj-$(CONFIG_REGULATOR_RT5120) += rt5120-regulator.o
 obj-$(CONFIG_REGULATOR_RT5190A) += rt5190a-regulator.o
 obj-$(CONFIG_REGULATOR_RT5759) += rt5759-regulator.o
 obj-$(CONFIG_REGULATOR_RT6160) += rt6160-regulator.o
index 1e54a83..7150b1d 100644 (file)
@@ -1565,6 +1565,9 @@ static int set_machine_constraints(struct regulator_dev *rdev)
                        rdev->constraints->always_on = true;
        }
 
+       if (rdev->desc->off_on_delay)
+               rdev->last_off = ktime_get();
+
        /* If the constraints say the regulator should be on at this point
         * and we have control then make sure it is enabled.
         */
@@ -1592,8 +1595,6 @@ static int set_machine_constraints(struct regulator_dev *rdev)
 
                if (rdev->constraints->always_on)
                        rdev->use_count++;
-       } else if (rdev->desc->off_on_delay) {
-               rdev->last_off = ktime_get();
        }
 
        print_constraints(rdev);
@@ -4783,22 +4784,26 @@ int regulator_bulk_get(struct device *dev, int num_consumers,
                consumers[i].consumer = regulator_get(dev,
                                                      consumers[i].supply);
                if (IS_ERR(consumers[i].consumer)) {
-                       ret = PTR_ERR(consumers[i].consumer);
                        consumers[i].consumer = NULL;
+                       ret = dev_err_probe(dev, PTR_ERR(consumers[i].consumer),
+                                           "Failed to get supply '%s'",
+                                           consumers[i].supply);
                        goto err;
                }
+
+               if (consumers[i].init_load_uA > 0) {
+                       ret = regulator_set_load(consumers[i].consumer,
+                                                consumers[i].init_load_uA);
+                       if (ret) {
+                               i++;
+                               goto err;
+                       }
+               }
        }
 
        return 0;
 
 err:
-       if (ret != -EPROBE_DEFER)
-               dev_err(dev, "Failed to get supply '%s': %pe\n",
-                       consumers[i].supply, ERR_PTR(ret));
-       else
-               dev_dbg(dev, "Failed to get supply '%s', deferring\n",
-                       consumers[i].supply);
-
        while (--i >= 0)
                regulator_put(consumers[i].consumer);
 
index 9113233..32823a8 100644 (file)
@@ -166,6 +166,34 @@ int devm_regulator_bulk_get(struct device *dev, int num_consumers,
 }
 EXPORT_SYMBOL_GPL(devm_regulator_bulk_get);
 
+/**
+ * devm_regulator_bulk_get_const - devm_regulator_bulk_get() w/ const data
+ *
+ * @dev:           device to supply
+ * @num_consumers: number of consumers to register
+ * @in_consumers:  const configuration of consumers
+ * @out_consumers: in_consumers is copied here and this is passed to
+ *                devm_regulator_bulk_get().
+ *
+ * This is a convenience function to allow bulk regulator configuration
+ * to be stored "static const" in files.
+ *
+ * Return: 0 on success, an errno on failure.
+ */
+int devm_regulator_bulk_get_const(struct device *dev, int num_consumers,
+                                 const struct regulator_bulk_data *in_consumers,
+                                 struct regulator_bulk_data **out_consumers)
+{
+       *out_consumers = devm_kmemdup(dev, in_consumers,
+                                     num_consumers * sizeof(*in_consumers),
+                                     GFP_KERNEL);
+       if (*out_consumers == NULL)
+               return -ENOMEM;
+
+       return devm_regulator_bulk_get(dev, num_consumers, *out_consumers);
+}
+EXPORT_SYMBOL_GPL(devm_regulator_bulk_get_const);
+
 static void devm_rdev_release(struct device *dev, void *res)
 {
        regulator_unregister(*(struct regulator_dev **)res);
diff --git a/drivers/regulator/max597x-regulator.c b/drivers/regulator/max597x-regulator.c
new file mode 100644 (file)
index 0000000..03c6027
--- /dev/null
@@ -0,0 +1,502 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device driver for regulators in MAX5970 and MAX5978 IC
+ *
+ * Copyright (c) 2022 9elements GmbH
+ *
+ * Author: Patrick Rudolph <patrick.rudolph@9elements.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/platform_device.h>
+
+#include <linux/mfd/max597x.h>
+
+struct max597x_regulator {
+       int num_switches, mon_rng, irng, shunt_micro_ohms, lim_uA;
+       struct regmap *regmap;
+};
+
+enum max597x_regulator_id {
+       MAX597X_SW0,
+       MAX597X_SW1,
+};
+
+static int max597x_uvp_ovp_check_mode(struct regulator_dev *rdev, int severity)
+{
+       int ret, reg;
+
+       /* Status1 register contains the soft strap values sampled at POR */
+       ret = regmap_read(rdev->regmap, MAX5970_REG_STATUS1, &reg);
+       if (ret)
+               return ret;
+
+       /* Check soft straps match requested mode */
+       if (severity == REGULATOR_SEVERITY_PROT) {
+               if (STATUS1_PROT(reg) != STATUS1_PROT_SHUTDOWN)
+                       return -EOPNOTSUPP;
+
+               return 0;
+       }
+       if (STATUS1_PROT(reg) == STATUS1_PROT_SHUTDOWN)
+               return -EOPNOTSUPP;
+
+       return 0;
+}
+
+static int max597x_set_vp(struct regulator_dev *rdev, int lim_uV, int severity,
+                         bool enable, bool overvoltage)
+{
+       int off_h, off_l, reg, ret;
+       struct max597x_regulator *data = rdev_get_drvdata(rdev);
+       int channel = rdev_get_id(rdev);
+
+       if (overvoltage) {
+               if (severity == REGULATOR_SEVERITY_WARN) {
+                       off_h = MAX5970_REG_CH_OV_WARN_H(channel);
+                       off_l = MAX5970_REG_CH_OV_WARN_L(channel);
+               } else {
+                       off_h = MAX5970_REG_CH_OV_CRIT_H(channel);
+                       off_l = MAX5970_REG_CH_OV_CRIT_L(channel);
+               }
+       } else {
+               if (severity == REGULATOR_SEVERITY_WARN) {
+                       off_h = MAX5970_REG_CH_UV_WARN_H(channel);
+                       off_l = MAX5970_REG_CH_UV_WARN_L(channel);
+               } else {
+                       off_h = MAX5970_REG_CH_UV_CRIT_H(channel);
+                       off_l = MAX5970_REG_CH_UV_CRIT_L(channel);
+               }
+       }
+
+       if (enable)
+               /* reg = ADC_MASK * (lim_uV / 1000000) / (data->mon_rng / 1000000) */
+               reg = ADC_MASK * lim_uV / data->mon_rng;
+       else
+               reg = 0;
+
+       ret = regmap_write(rdev->regmap, off_h, MAX5970_VAL2REG_H(reg));
+       if (ret)
+               return ret;
+
+       ret = regmap_write(rdev->regmap, off_l, MAX5970_VAL2REG_L(reg));
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int max597x_set_uvp(struct regulator_dev *rdev, int lim_uV, int severity,
+                          bool enable)
+{
+       int ret;
+
+       /*
+        * MAX5970 has enable control as a special value in limit reg. Can't
+        * set limit but keep feature disabled or enable W/O given limit.
+        */
+       if ((lim_uV && !enable) || (!lim_uV && enable))
+               return -EINVAL;
+
+       ret = max597x_uvp_ovp_check_mode(rdev, severity);
+       if (ret)
+               return ret;
+
+       return max597x_set_vp(rdev, lim_uV, severity, enable, false);
+}
+
+static int max597x_set_ovp(struct regulator_dev *rdev, int lim_uV, int severity,
+                          bool enable)
+{
+       int ret;
+
+       /*
+        * MAX5970 has enable control as a special value in limit reg. Can't
+        * set limit but keep feature disabled or enable W/O given limit.
+        */
+       if ((lim_uV && !enable) || (!lim_uV && enable))
+               return -EINVAL;
+
+       ret = max597x_uvp_ovp_check_mode(rdev, severity);
+       if (ret)
+               return ret;
+
+       return max597x_set_vp(rdev, lim_uV, severity, enable, true);
+}
+
+static int max597x_set_ocp(struct regulator_dev *rdev, int lim_uA,
+                          int severity, bool enable)
+{
+       int ret, val, reg;
+       unsigned int vthst, vthfst;
+
+       struct max597x_regulator *data = rdev_get_drvdata(rdev);
+       int rdev_id = rdev_get_id(rdev);
+       /*
+        * MAX5970 doesn't has enable control for ocp.
+        * If limit is specified but enable is not set then hold the value in
+        * variable & later use it when ocp needs to be enabled.
+        */
+       if (lim_uA != 0 && lim_uA != data->lim_uA)
+               data->lim_uA = lim_uA;
+
+       if (severity != REGULATOR_SEVERITY_PROT)
+               return -EINVAL;
+
+       if (enable) {
+
+               /* Calc Vtrip threshold in uV. */
+               vthst =
+                   div_u64(mul_u32_u32(data->shunt_micro_ohms, data->lim_uA),
+                           1000000);
+
+               /*
+                * As recommended in datasheed, add 20% margin to avoid
+                * spurious event & passive component tolerance.
+                */
+               vthst = div_u64(mul_u32_u32(vthst, 120), 100);
+
+               /* Calc fast Vtrip threshold in uV */
+               vthfst = vthst * (MAX5970_FAST2SLOW_RATIO / 100);
+
+               if (vthfst > data->irng) {
+                       dev_err(&rdev->dev, "Current limit out of range\n");
+                       return -EINVAL;
+               }
+               /* Fast trip threshold to be programmed */
+               val = div_u64(mul_u32_u32(0xFF, vthfst), data->irng);
+       } else
+               /*
+                * Since there is no option to disable ocp, set limit to max
+                * value
+                */
+               val = 0xFF;
+
+       reg = MAX5970_REG_DAC_FAST(rdev_id);
+       ret = regmap_write(rdev->regmap, reg, val);
+
+       return ret;
+}
+
+static int max597x_get_status(struct regulator_dev *rdev)
+{
+       int val, ret;
+
+       ret = regmap_read(rdev->regmap, MAX5970_REG_STATUS3, &val);
+       if (ret)
+               return REGULATOR_FAILED_RETRY;
+
+       if (val & MAX5970_STATUS3_ALERT)
+               return REGULATOR_STATUS_ERROR;
+
+       ret = regulator_is_enabled_regmap(rdev);
+       if (ret < 0)
+               return ret;
+
+       if (ret)
+               return REGULATOR_STATUS_ON;
+
+       return REGULATOR_STATUS_OFF;
+}
+
+static const struct regulator_ops max597x_switch_ops = {
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .get_status = max597x_get_status,
+       .set_over_voltage_protection = max597x_set_ovp,
+       .set_under_voltage_protection = max597x_set_uvp,
+       .set_over_current_protection = max597x_set_ocp,
+};
+
+static int max597x_dt_parse(struct device_node *np,
+                           const struct regulator_desc *desc,
+                           struct regulator_config *cfg)
+{
+       struct max597x_regulator *data = cfg->driver_data;
+       int ret = 0;
+
+       ret =
+           of_property_read_u32(np, "shunt-resistor-micro-ohms",
+                                &data->shunt_micro_ohms);
+       if (ret < 0)
+               dev_err(cfg->dev,
+                       "property 'shunt-resistor-micro-ohms' not found, err %d\n",
+                       ret);
+       return ret;
+
+}
+
+#define MAX597X_SWITCH(_ID, _ereg, _chan, _supply) {     \
+       .name            = #_ID,                         \
+       .of_match        = of_match_ptr(#_ID),           \
+       .ops             = &max597x_switch_ops,          \
+       .regulators_node = of_match_ptr("regulators"),   \
+       .type            = REGULATOR_VOLTAGE,            \
+       .id              = MAX597X_##_ID,                \
+       .owner           = THIS_MODULE,                  \
+       .supply_name     = _supply,                      \
+       .enable_reg      = _ereg,                        \
+       .enable_mask     = CHXEN((_chan)),               \
+       .of_parse_cb     = max597x_dt_parse,             \
+}
+
+static const struct regulator_desc regulators[] = {
+       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,
+                                    unsigned int *val)
+{
+       int ret;
+
+       ret = regmap_read(map, reg, val);
+       if (ret)
+               return ret;
+
+       if (*val)
+               return regmap_write(map, reg, *val);
+
+       return 0;
+}
+
+static int max597x_irq_handler(int irq, struct regulator_irq_data *rid,
+                              unsigned long *dev_mask)
+{
+       struct regulator_err_state *stat;
+       struct max597x_regulator *d = (struct max597x_regulator *)rid->data;
+       int val, ret, i;
+
+       ret = max597x_regmap_read_clear(d->regmap, MAX5970_REG_FAULT0, &val);
+       if (ret)
+               return REGULATOR_FAILED_RETRY;
+
+       *dev_mask = 0;
+       for (i = 0; i < d->num_switches; i++) {
+               stat = &rid->states[i];
+               stat->notifs = 0;
+               stat->errors = 0;
+       }
+
+       for (i = 0; i < d->num_switches; i++) {
+               stat = &rid->states[i];
+
+               if (val & UV_STATUS_CRIT(i)) {
+                       *dev_mask |= 1 << i;
+                       stat->notifs |= REGULATOR_EVENT_UNDER_VOLTAGE;
+                       stat->errors |= REGULATOR_ERROR_UNDER_VOLTAGE;
+               } else if (val & UV_STATUS_WARN(i)) {
+                       *dev_mask |= 1 << i;
+                       stat->notifs |= REGULATOR_EVENT_UNDER_VOLTAGE_WARN;
+                       stat->errors |= REGULATOR_ERROR_UNDER_VOLTAGE_WARN;
+               }
+       }
+
+       ret = max597x_regmap_read_clear(d->regmap, MAX5970_REG_FAULT1, &val);
+       if (ret)
+               return REGULATOR_FAILED_RETRY;
+
+       for (i = 0; i < d->num_switches; i++) {
+               stat = &rid->states[i];
+
+               if (val & OV_STATUS_CRIT(i)) {
+                       *dev_mask |= 1 << i;
+                       stat->notifs |= REGULATOR_EVENT_REGULATION_OUT;
+                       stat->errors |= REGULATOR_ERROR_REGULATION_OUT;
+               } else if (val & OV_STATUS_WARN(i)) {
+                       *dev_mask |= 1 << i;
+                       stat->notifs |= REGULATOR_EVENT_OVER_VOLTAGE_WARN;
+                       stat->errors |= REGULATOR_ERROR_OVER_VOLTAGE_WARN;
+               }
+       }
+
+       ret = max597x_regmap_read_clear(d->regmap, MAX5970_REG_FAULT2, &val);
+       if (ret)
+               return REGULATOR_FAILED_RETRY;
+
+       for (i = 0; i < d->num_switches; i++) {
+               stat = &rid->states[i];
+
+               if (val & OC_STATUS_WARN(i)) {
+                       *dev_mask |= 1 << i;
+                       stat->notifs |= REGULATOR_EVENT_OVER_CURRENT_WARN;
+                       stat->errors |= REGULATOR_ERROR_OVER_CURRENT_WARN;
+               }
+       }
+
+       ret = regmap_read(d->regmap, MAX5970_REG_STATUS0, &val);
+       if (ret)
+               return REGULATOR_FAILED_RETRY;
+
+       for (i = 0; i < d->num_switches; i++) {
+               stat = &rid->states[i];
+
+               if ((val & MAX5970_CB_IFAULTF(i))
+                   || (val & MAX5970_CB_IFAULTS(i))) {
+                       *dev_mask |= 1 << i;
+                       stat->notifs |=
+                           REGULATOR_EVENT_OVER_CURRENT |
+                           REGULATOR_EVENT_DISABLE;
+                       stat->errors |=
+                           REGULATOR_ERROR_OVER_CURRENT | REGULATOR_ERROR_FAIL;
+
+                       /* Clear the sub-IRQ status */
+                       regulator_disable_regmap(stat->rdev);
+               }
+       }
+       return 0;
+}
+
+static const struct regmap_config max597x_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = MAX_REGISTERS,
+};
+
+static int max597x_adc_range(struct regmap *regmap, const int ch,
+                            u32 *irng, u32 *mon_rng)
+{
+       unsigned int reg;
+       int ret;
+
+       /* Decode current ADC range */
+       ret = regmap_read(regmap, MAX5970_REG_STATUS2, &reg);
+       if (ret)
+               return ret;
+       switch (MAX5970_IRNG(reg, ch)) {
+       case 0:
+               *irng = 100000; /* 100 mV */
+               break;
+       case 1:
+               *irng = 50000;  /* 50 mV */
+               break;
+       case 2:
+               *irng = 25000;  /* 25 mV */
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Decode current voltage monitor range */
+       ret = regmap_read(regmap, MAX5970_REG_MON_RANGE, &reg);
+       if (ret)
+               return ret;
+
+       *mon_rng = MAX5970_MON_MAX_RANGE_UV >> MAX5970_MON(reg, ch);
+
+       return 0;
+}
+
+static int max597x_setup_irq(struct device *dev,
+                            int irq,
+                            struct regulator_dev *rdevs[MAX5970_NUM_SWITCHES],
+                            int num_switches, struct max597x_regulator *data)
+{
+       struct regulator_irq_desc max597x_notif = {
+               .name = "max597x-irq",
+               .map_event = max597x_irq_handler,
+               .data = data,
+       };
+       int errs = REGULATOR_ERROR_UNDER_VOLTAGE |
+           REGULATOR_ERROR_UNDER_VOLTAGE_WARN |
+           REGULATOR_ERROR_OVER_VOLTAGE_WARN |
+           REGULATOR_ERROR_REGULATION_OUT |
+           REGULATOR_ERROR_OVER_CURRENT |
+           REGULATOR_ERROR_OVER_CURRENT_WARN | REGULATOR_ERROR_FAIL;
+       void *irq_helper;
+
+       /* Register notifiers - can fail if IRQ is not given */
+       irq_helper = devm_regulator_irq_helper(dev, &max597x_notif,
+                                              irq, 0, errs, NULL,
+                                              &rdevs[0], num_switches);
+       if (IS_ERR(irq_helper)) {
+               if (PTR_ERR(irq_helper) == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+
+               dev_warn(dev, "IRQ disabled %pe\n", irq_helper);
+       }
+
+       return 0;
+}
+
+static int max597x_regulator_probe(struct platform_device *pdev)
+{
+
+
+       struct max597x_data *max597x = dev_get_drvdata(pdev->dev.parent);
+       struct max597x_regulator *data;
+
+       struct regulator_config config = { };
+       struct regulator_dev *rdev;
+       struct regulator_dev *rdevs[MAX5970_NUM_SWITCHES];
+       int num_switches = max597x->num_switches;
+       int ret, i;
+
+       for (i = 0; i < num_switches; i++) {
+               data =
+                   devm_kzalloc(max597x->dev, sizeof(struct max597x_regulator),
+                                GFP_KERNEL);
+               if (!data)
+                       return -ENOMEM;
+
+               data->num_switches = num_switches;
+               data->regmap = max597x->regmap;
+
+               ret = max597x_adc_range(data->regmap, i, &max597x->irng[i], &max597x->mon_rng[i]);
+               if (ret < 0)
+                       return ret;
+
+               data->irng = max597x->irng[i];
+               data->mon_rng = max597x->mon_rng[i];
+
+               config.dev = max597x->dev;
+               config.driver_data = (void *)data;
+               config.regmap = data->regmap;
+               rdev = devm_regulator_register(max597x->dev,
+                                              &regulators[i], &config);
+               if (IS_ERR(rdev)) {
+                       dev_err(max597x->dev, "failed to register regulator %s\n",
+                               regulators[i].name);
+                       return PTR_ERR(rdev);
+               }
+               rdevs[i] = rdev;
+               max597x->shunt_micro_ohms[i] = data->shunt_micro_ohms;
+       }
+
+       if (max597x->irq) {
+               ret =
+                   max597x_setup_irq(max597x->dev, max597x->irq, rdevs, num_switches,
+                                     data);
+               if (ret) {
+                       dev_err(max597x->dev, "IRQ setup failed");
+                       return ret;
+               }
+       }
+
+       return ret;
+}
+
+static struct platform_driver max597x_regulator_driver = {
+       .driver = {
+               .name = "max597x-regulator",
+       },
+       .probe = max597x_regulator_probe,
+};
+
+module_platform_driver(max597x_regulator_driver);
+
+
+MODULE_AUTHOR("Patrick Rudolph <patrick.rudolph@9elements.com>");
+MODULE_DESCRIPTION("MAX5970_hot-swap controller driver");
+MODULE_LICENSE("GPL v2");
index 39cebec..82892d7 100644 (file)
@@ -6,14 +6,14 @@
 //
 // Author: Saravanan Sekar <sravanhome@gmail.com>
 
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
 #include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/regulator/driver.h>
-#include <linux/i2c.h>
 
 #define MP5416_REG_CTL0                        0x00
 #define MP5416_REG_CTL1                        0x01
@@ -174,10 +174,22 @@ static struct regulator_desc mp5416_regulators_desc[MP5416_MAX_REGULATORS] = {
        MP5416LDO("ldo4", 4, BIT(1)),
 };
 
+static struct regulator_desc mp5496_regulators_desc[MP5416_MAX_REGULATORS] = {
+       MP5416BUCK("buck1", 1, mp5416_I_limits1, MP5416_REG_CTL1, BIT(0), 1),
+       MP5416BUCK("buck2", 2, mp5416_I_limits2, MP5416_REG_CTL1, BIT(1), 1),
+       MP5416BUCK("buck3", 3, mp5416_I_limits1, MP5416_REG_CTL1, BIT(2), 1),
+       MP5416BUCK("buck4", 4, mp5416_I_limits2, MP5416_REG_CTL2, BIT(5), 1),
+       MP5416LDO("ldo1", 1, BIT(4)),
+       MP5416LDO("ldo2", 2, BIT(3)),
+       MP5416LDO("ldo3", 3, BIT(2)),
+       MP5416LDO("ldo4", 4, BIT(1)),
+};
+
 static int mp5416_i2c_probe(struct i2c_client *client)
 {
        struct device *dev = &client->dev;
        struct regulator_config config = { NULL, };
+       static const struct regulator_desc *desc;
        struct regulator_dev *rdev;
        struct regmap *regmap;
        int i;
@@ -188,12 +200,16 @@ static int mp5416_i2c_probe(struct i2c_client *client)
                return PTR_ERR(regmap);
        }
 
+       desc = of_device_get_match_data(dev);
+       if (!desc)
+               return -ENODEV;
+
        config.dev = dev;
        config.regmap = regmap;
 
        for (i = 0; i < MP5416_MAX_REGULATORS; i++) {
                rdev = devm_regulator_register(dev,
-                                              &mp5416_regulators_desc[i],
+                                              &desc[i],
                                               &config);
                if (IS_ERR(rdev)) {
                        dev_err(dev, "Failed to register regulator!\n");
@@ -205,13 +221,15 @@ static int mp5416_i2c_probe(struct i2c_client *client)
 }
 
 static const struct of_device_id mp5416_of_match[] = {
-       { .compatible = "mps,mp5416" },
+       { .compatible = "mps,mp5416", .data = &mp5416_regulators_desc },
+       { .compatible = "mps,mp5496", .data = &mp5496_regulators_desc },
        {},
 };
 MODULE_DEVICE_TABLE(of, mp5416_of_match);
 
 static const struct i2c_device_id mp5416_id[] = {
        { "mp5416", },
+       { "mp5496", },
        { },
 };
 MODULE_DEVICE_TABLE(i2c, mp5416_id);
diff --git a/drivers/regulator/mt6370-regulator.c b/drivers/regulator/mt6370-regulator.c
new file mode 100644 (file)
index 0000000..e73f5a4
--- /dev/null
@@ -0,0 +1,390 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <linux/bits.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+enum {
+       MT6370_IDX_DSVBOOST = 0,
+       MT6370_IDX_DSVPOS,
+       MT6370_IDX_DSVNEG,
+       MT6370_IDX_VIBLDO,
+       MT6370_MAX_IDX
+};
+
+#define MT6370_REG_LDO_CFG     0x180
+#define MT6370_REG_LDO_VOUT    0x181
+#define MT6370_REG_DB_CTRL1    0x1B0
+#define MT6370_REG_DB_CTRL2    0x1B1
+#define MT6370_REG_DB_VBST     0x1B2
+#define MT6370_REG_DB_VPOS     0x1B3
+#define MT6370_REG_DB_VNEG     0x1B4
+#define MT6370_REG_LDO_STAT    0x1DC
+#define MT6370_REG_DB_STAT     0x1DF
+
+#define MT6370_LDOOMS_MASK     BIT(7)
+#define MT6370_LDOEN_MASK      BIT(7)
+#define MT6370_LDOVOUT_MASK    GENMASK(3, 0)
+#define MT6370_DBPERD_MASK     (BIT(7) | BIT(4))
+#define MT6370_DBEXTEN_MASK    BIT(0)
+#define MT6370_DBVPOSEN_MASK   BIT(6)
+#define MT6370_DBVPOSDISG_MASK BIT(5)
+#define MT6370_DBVNEGEN_MASK   BIT(3)
+#define MT6370_DBVNEGDISG_MASK BIT(2)
+#define MT6370_DBALLON_MASK    (MT6370_DBVPOSEN_MASK | MT6370_DBVNEGEN_MASK)
+#define MT6370_DBSLEW_MASK     GENMASK(7, 6)
+#define MT6370_DBVOUT_MASK     GENMASK(5, 0)
+#define MT6370_LDOOC_EVT_MASK  BIT(7)
+#define MT6370_POSSCP_EVT_MASK BIT(7)
+#define MT6370_NEGSCP_EVT_MASK BIT(6)
+#define MT6370_BSTOCP_EVT_MASK BIT(5)
+#define MT6370_POSOCP_EVT_MASK BIT(4)
+#define MT6370_NEGOCP_EVT_MASK BIT(3)
+
+#define MT6370_LDO_MINUV       1600000
+#define MT6370_LDO_STPUV       200000
+#define MT6370_LDO_N_VOLT      13
+#define MT6370_DBVBOOST_MINUV  4000000
+#define MT6370_DBVBOOST_STPUV  50000
+#define MT6370_DBVBOOST_N_VOLT 45
+#define MT6370_DBVOUT_MINUV    4000000
+#define MT6370_DBVOUT_STPUV    50000
+#define MT6370_DBVOUT_N_VOLT   41
+
+struct mt6370_priv {
+       struct device *dev;
+       struct regmap *regmap;
+       struct regulator_dev *rdev[MT6370_MAX_IDX];
+       bool use_external_ctrl;
+};
+
+static const unsigned int mt6370_vpos_ramp_tbl[] = { 8540, 5840, 4830, 3000 };
+static const unsigned int mt6370_vneg_ramp_tbl[] = { 10090, 6310, 5050, 3150 };
+
+static int mt6370_get_error_flags(struct regulator_dev *rdev,
+                                 unsigned int *flags)
+{
+       struct regmap *regmap = rdev_get_regmap(rdev);
+       unsigned int stat_reg, stat, rpt_flags = 0;
+       int rid = rdev_get_id(rdev), ret;
+
+       if (rid == MT6370_IDX_VIBLDO)
+               stat_reg = MT6370_REG_LDO_STAT;
+       else
+               stat_reg = MT6370_REG_DB_STAT;
+
+       ret = regmap_read(regmap, stat_reg, &stat);
+       if (ret)
+               return ret;
+
+       switch (rid) {
+       case MT6370_IDX_DSVBOOST:
+               if (stat & MT6370_BSTOCP_EVT_MASK)
+                       rpt_flags |= REGULATOR_ERROR_OVER_CURRENT;
+               break;
+       case MT6370_IDX_DSVPOS:
+               if (stat & MT6370_POSSCP_EVT_MASK)
+                       rpt_flags |= REGULATOR_ERROR_UNDER_VOLTAGE;
+
+               if (stat & MT6370_POSOCP_EVT_MASK)
+                       rpt_flags |= REGULATOR_ERROR_OVER_CURRENT;
+               break;
+       case MT6370_IDX_DSVNEG:
+               if (stat & MT6370_NEGSCP_EVT_MASK)
+                       rpt_flags |= REGULATOR_ERROR_UNDER_VOLTAGE;
+
+               if (stat & MT6370_NEGOCP_EVT_MASK)
+                       rpt_flags |= REGULATOR_ERROR_OVER_CURRENT;
+               break;
+       default:
+               if (stat & MT6370_LDOOC_EVT_MASK)
+                       rpt_flags |= REGULATOR_ERROR_OVER_CURRENT;
+               break;
+       }
+
+       *flags = rpt_flags;
+       return 0;
+}
+
+static const struct regulator_ops mt6370_dbvboost_ops = {
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .list_voltage = regulator_list_voltage_linear,
+       .get_bypass = regulator_get_bypass_regmap,
+       .set_bypass = regulator_set_bypass_regmap,
+       .get_error_flags = mt6370_get_error_flags,
+};
+
+static const struct regulator_ops mt6370_dbvout_ops = {
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .list_voltage = regulator_list_voltage_linear,
+       .is_enabled = regulator_is_enabled_regmap,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .set_active_discharge = regulator_set_active_discharge_regmap,
+       .set_ramp_delay = regulator_set_ramp_delay_regmap,
+       .get_error_flags = mt6370_get_error_flags,
+};
+
+static const struct regulator_ops mt6370_ldo_ops = {
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .list_voltage = regulator_list_voltage_linear,
+       .is_enabled = regulator_is_enabled_regmap,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .set_active_discharge = regulator_set_active_discharge_regmap,
+       .get_error_flags = mt6370_get_error_flags,
+};
+
+static int mt6370_of_parse_cb(struct device_node *np,
+                             const struct regulator_desc *desc,
+                             struct regulator_config *config)
+{
+       struct mt6370_priv *priv = config->driver_data;
+       struct gpio_desc *enable_gpio;
+       int ret;
+
+       enable_gpio = fwnode_gpiod_get_index(of_fwnode_handle(np), "enable", 0,
+                                            GPIOD_OUT_HIGH |
+                                            GPIOD_FLAGS_BIT_NONEXCLUSIVE,
+                                            desc->name);
+       if (IS_ERR(enable_gpio)) {
+               config->ena_gpiod = NULL;
+               return 0;
+       }
+
+       /*
+        * RG control by default
+        * Only if all are using external pin, change all by external control
+        */
+       if (priv->use_external_ctrl) {
+               ret = regmap_update_bits(priv->regmap, MT6370_REG_DB_CTRL1,
+                                        MT6370_DBEXTEN_MASK,
+                                        MT6370_DBEXTEN_MASK);
+               if (ret)
+                       return ret;
+       }
+
+       config->ena_gpiod = enable_gpio;
+       priv->use_external_ctrl = true;
+       return 0;
+}
+
+static const struct regulator_desc mt6370_regulator_descs[] = {
+       {
+               .name = "mt6370-dsv-vbst",
+               .of_match = of_match_ptr("dsvbst"),
+               .regulators_node = of_match_ptr("regulators"),
+               .id = MT6370_IDX_DSVBOOST,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .ops = &mt6370_dbvboost_ops,
+               .min_uV = MT6370_DBVBOOST_MINUV,
+               .uV_step = MT6370_DBVBOOST_STPUV,
+               .n_voltages = MT6370_DBVBOOST_N_VOLT,
+               .vsel_reg = MT6370_REG_DB_VBST,
+               .vsel_mask = MT6370_DBVOUT_MASK,
+               .bypass_reg = MT6370_REG_DB_CTRL1,
+               .bypass_mask = MT6370_DBPERD_MASK,
+               .bypass_val_on = MT6370_DBPERD_MASK,
+       },
+       {
+               .name = "mt6370-dsv-vpos",
+               .of_match = of_match_ptr("dsvpos"),
+               .regulators_node = of_match_ptr("regulators"),
+               .id = MT6370_IDX_DSVPOS,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .of_parse_cb = mt6370_of_parse_cb,
+               .ops = &mt6370_dbvout_ops,
+               .min_uV = MT6370_DBVOUT_MINUV,
+               .uV_step = MT6370_DBVOUT_STPUV,
+               .n_voltages = MT6370_DBVOUT_N_VOLT,
+               .vsel_reg = MT6370_REG_DB_VPOS,
+               .vsel_mask = MT6370_DBVOUT_MASK,
+               .enable_reg = MT6370_REG_DB_CTRL2,
+               .enable_mask = MT6370_DBVPOSEN_MASK,
+               .ramp_reg = MT6370_REG_DB_VPOS,
+               .ramp_mask = MT6370_DBSLEW_MASK,
+               .ramp_delay_table = mt6370_vpos_ramp_tbl,
+               .n_ramp_values = ARRAY_SIZE(mt6370_vpos_ramp_tbl),
+               .active_discharge_reg = MT6370_REG_DB_CTRL2,
+               .active_discharge_mask = MT6370_DBVPOSDISG_MASK,
+               .active_discharge_on = MT6370_DBVPOSDISG_MASK,
+       },
+       {
+               .name = "mt6370-dsv-vneg",
+               .of_match = of_match_ptr("dsvneg"),
+               .regulators_node = of_match_ptr("regulators"),
+               .id = MT6370_IDX_DSVNEG,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .of_parse_cb = mt6370_of_parse_cb,
+               .ops = &mt6370_dbvout_ops,
+               .min_uV = MT6370_DBVOUT_MINUV,
+               .uV_step = MT6370_DBVOUT_STPUV,
+               .n_voltages = MT6370_DBVOUT_N_VOLT,
+               .vsel_reg = MT6370_REG_DB_VNEG,
+               .vsel_mask = MT6370_DBVOUT_MASK,
+               .enable_reg = MT6370_REG_DB_CTRL2,
+               .enable_mask = MT6370_DBVNEGEN_MASK,
+               .ramp_reg = MT6370_REG_DB_VNEG,
+               .ramp_mask = MT6370_DBSLEW_MASK,
+               .ramp_delay_table = mt6370_vneg_ramp_tbl,
+               .n_ramp_values = ARRAY_SIZE(mt6370_vneg_ramp_tbl),
+               .active_discharge_reg = MT6370_REG_DB_CTRL2,
+               .active_discharge_mask = MT6370_DBVNEGDISG_MASK,
+               .active_discharge_on = MT6370_DBVNEGDISG_MASK,
+       },
+       {
+               .name = "mt6370-vib-ldo",
+               .of_match = of_match_ptr("vibldo"),
+               .regulators_node = of_match_ptr("regulators"),
+               .id = MT6370_IDX_VIBLDO,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .ops = &mt6370_ldo_ops,
+               .min_uV = MT6370_LDO_MINUV,
+               .uV_step = MT6370_LDO_STPUV,
+               .n_voltages = MT6370_LDO_N_VOLT,
+               .vsel_reg = MT6370_REG_LDO_VOUT,
+               .vsel_mask = MT6370_LDOVOUT_MASK,
+               .enable_reg = MT6370_REG_LDO_VOUT,
+               .enable_mask = MT6370_LDOEN_MASK,
+               .active_discharge_reg = MT6370_REG_LDO_CFG,
+               .active_discharge_mask = MT6370_LDOOMS_MASK,
+               .active_discharge_on = MT6370_LDOOMS_MASK,
+       }
+};
+
+static irqreturn_t mt6370_scp_handler(int irq, void *data)
+{
+       struct regulator_dev *rdev = data;
+
+       regulator_notifier_call_chain(rdev, REGULATOR_EVENT_UNDER_VOLTAGE,
+                                     NULL);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t mt6370_ocp_handler(int irq, void *data)
+{
+       struct regulator_dev *rdev = data;
+
+       regulator_notifier_call_chain(rdev, REGULATOR_EVENT_OVER_CURRENT, NULL);
+       return IRQ_HANDLED;
+}
+
+static int mt6370_regulator_irq_register(struct mt6370_priv *priv)
+{
+       struct platform_device *pdev = to_platform_device(priv->dev);
+       static const struct {
+               const char *name;
+               int rid;
+               irq_handler_t handler;
+       } mt6370_irqs[] = {
+               { "db_vpos_scp", MT6370_IDX_DSVPOS, mt6370_scp_handler },
+               { "db_vneg_scp", MT6370_IDX_DSVNEG, mt6370_scp_handler },
+               { "db_vbst_ocp", MT6370_IDX_DSVBOOST, mt6370_ocp_handler },
+               { "db_vpos_ocp", MT6370_IDX_DSVPOS,  mt6370_ocp_handler },
+               { "db_vneg_ocp", MT6370_IDX_DSVNEG, mt6370_ocp_handler },
+               { "ldo_oc", MT6370_IDX_VIBLDO, mt6370_ocp_handler }
+       };
+       struct regulator_dev *rdev;
+       int i, irq, ret;
+
+       for (i = 0; i < ARRAY_SIZE(mt6370_irqs); i++) {
+               irq = platform_get_irq_byname(pdev, mt6370_irqs[i].name);
+
+               rdev = priv->rdev[mt6370_irqs[i].rid];
+
+               ret = devm_request_threaded_irq(priv->dev, irq, NULL,
+                                               mt6370_irqs[i].handler, 0,
+                                               mt6370_irqs[i].name, rdev);
+               if (ret) {
+                       dev_err(priv->dev,
+                               "Failed to register (%d) interrupt\n", i);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int mt6370_regualtor_register(struct mt6370_priv *priv)
+{
+       struct regulator_dev *rdev;
+       struct regulator_config cfg = {};
+       struct device *parent = priv->dev->parent;
+       int i;
+
+       cfg.dev = parent;
+       cfg.driver_data = priv;
+
+       for (i = 0; i < MT6370_MAX_IDX; i++) {
+               rdev = devm_regulator_register(priv->dev,
+                                              mt6370_regulator_descs + i,
+                                              &cfg);
+               if (IS_ERR(rdev)) {
+                       dev_err(priv->dev,
+                               "Failed to register (%d) regulator\n", i);
+                       return PTR_ERR(rdev);
+               }
+
+               priv->rdev[i] = rdev;
+       }
+
+       return 0;
+}
+
+static int mt6370_regulator_probe(struct platform_device *pdev)
+{
+       struct mt6370_priv *priv;
+       int ret;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->dev = &pdev->dev;
+
+       priv->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+       if (!priv->regmap) {
+               dev_err(&pdev->dev, "Failed to init regmap\n");
+               return -ENODEV;
+       }
+
+       ret = mt6370_regualtor_register(priv);
+       if (ret)
+               return ret;
+
+       return mt6370_regulator_irq_register(priv);
+}
+
+static const struct platform_device_id mt6370_devid_table[] = {
+       { "mt6370-regulator", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(platform, mt6370_devid_table);
+
+static struct platform_driver mt6370_regulator_driver = {
+       .driver = {
+               .name = "mt6370-regulator",
+       },
+       .id_table = mt6370_devid_table,
+       .probe = mt6370_regulator_probe,
+};
+module_platform_driver(mt6370_regulator_driver);
+
+MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("Mediatek MT6370 Regulator Driver");
+MODULE_LICENSE("GPL v2");
index 2e6b61d..4323429 100644 (file)
@@ -319,7 +319,7 @@ static const struct platform_device_id mt6380_platform_ids[] = {
 };
 MODULE_DEVICE_TABLE(platform, mt6380_platform_ids);
 
-static const struct of_device_id mt6380_of_match[] = {
+static const struct of_device_id  __maybe_unused mt6380_of_match[] = {
        { .compatible = "mediatek,mt6380-regulator", },
        { /* sentinel */ },
 };
index f54d4f1..e12b681 100644 (file)
@@ -264,8 +264,12 @@ static int of_get_regulation_constraints(struct device *dev,
                }
 
                suspend_np = of_get_child_by_name(np, regulator_states[i]);
-               if (!suspend_np || !suspend_state)
+               if (!suspend_np)
                        continue;
+               if (!suspend_state) {
+                       of_node_put(suspend_np);
+                       continue;
+               }
 
                if (!of_property_read_u32(suspend_np, "regulator-mode",
                                          &pval)) {
index ef6e47d..59024c6 100644 (file)
@@ -205,6 +205,7 @@ static const struct regulator_ops rpm_mp5496_ops = {
        .is_enabled = rpm_reg_is_enabled,
        .list_voltage = regulator_list_voltage_linear_range,
 
+       .get_voltage = rpm_reg_get_voltage,
        .set_voltage = rpm_reg_set_voltage,
 };
 
@@ -357,10 +358,10 @@ static const struct regulator_desc pm8941_switch = {
 
 static const struct regulator_desc pm8916_pldo = {
        .linear_ranges = (struct linear_range[]) {
-               REGULATOR_LINEAR_RANGE(750000, 0, 208, 12500),
+               REGULATOR_LINEAR_RANGE(1750000, 0, 127, 12500),
        },
        .n_linear_ranges = 1,
-       .n_voltages = 209,
+       .n_voltages = 128,
        .ops = &rpm_smps_ldo_ops,
 };
 
@@ -783,6 +784,29 @@ static const struct rpm_regulator_data rpm_pm8841_regulators[] = {
        {}
 };
 
+static const struct rpm_regulator_data rpm_pm8909_regulators[] = {
+       { "s1", QCOM_SMD_RPM_SMPA, 1, &pm8916_buck_lvo_smps, "vdd_s1" },
+       { "s2", QCOM_SMD_RPM_SMPA, 2, &pm8916_buck_hvo_smps, "vdd_s2" },
+       { "l1", QCOM_SMD_RPM_LDOA, 1, &pm8916_nldo, "vdd_l1" },
+       { "l2", QCOM_SMD_RPM_LDOA, 2, &pm8916_nldo, "vdd_l2_l5" },
+       { "l3", QCOM_SMD_RPM_LDOA, 3, &pm8916_nldo, "vdd_l3_l6_l10" },
+       { "l4", QCOM_SMD_RPM_LDOA, 4, &pm8916_pldo, "vdd_l4_l7" },
+       { "l5", QCOM_SMD_RPM_LDOA, 5, &pm8226_pldo, "vdd_l2_l5" },
+       { "l6", QCOM_SMD_RPM_LDOA, 6, &pm8226_pldo, "vdd_l3_l6_l10" },
+       { "l7", QCOM_SMD_RPM_LDOA, 7, &pm8226_pldo, "vdd_l4_l7" },
+       { "l8", QCOM_SMD_RPM_LDOA, 8, &pm8916_pldo, "vdd_l8_l11_l15_l18" },
+       { "l9", QCOM_SMD_RPM_LDOA, 9, &pm8916_pldo, "vdd_l9_l12_l14_l17" },
+       { "l10", QCOM_SMD_RPM_LDOA, 10, &pm8916_nldo, "vdd_l3_l6_l10" },
+       { "l11", QCOM_SMD_RPM_LDOA, 11, &pm8226_pldo, "vdd_l8_l11_l15_l18" },
+       { "l12", QCOM_SMD_RPM_LDOA, 12, &pm8916_pldo, "vdd_l9_l12_l14_l17" },
+       { "l13", QCOM_SMD_RPM_LDOA, 13, &pm8916_pldo, "vdd_l13" },
+       { "l14", QCOM_SMD_RPM_LDOA, 14, &pm8916_pldo, "vdd_l9_l12_l14_l17" },
+       { "l15", QCOM_SMD_RPM_LDOA, 15, &pm8916_pldo, "vdd_l8_l11_l15_l18" },
+       { "l17", QCOM_SMD_RPM_LDOA, 17, &pm8916_pldo, "vdd_l9_l12_l14_l17" },
+       { "l18", QCOM_SMD_RPM_LDOA, 18, &pm8916_pldo, "vdd_l8_l11_l15_l18" },
+       {}
+};
+
 static const struct rpm_regulator_data rpm_pm8916_regulators[] = {
        { "s1", QCOM_SMD_RPM_SMPA, 1, &pm8916_buck_lvo_smps, "vdd_s1" },
        { "s2", QCOM_SMD_RPM_SMPA, 2, &pm8916_buck_lvo_smps, "vdd_s2" },
@@ -1221,6 +1245,7 @@ static const struct rpm_regulator_data rpm_pm2250_regulators[] = {
 static const struct of_device_id rpm_of_match[] = {
        { .compatible = "qcom,rpm-mp5496-regulators", .data = &rpm_mp5496_regulators },
        { .compatible = "qcom,rpm-pm8841-regulators", .data = &rpm_pm8841_regulators },
+       { .compatible = "qcom,rpm-pm8909-regulators", .data = &rpm_pm8909_regulators },
        { .compatible = "qcom,rpm-pm8916-regulators", .data = &rpm_pm8916_regulators },
        { .compatible = "qcom,rpm-pm8226-regulators", .data = &rpm_pm8226_regulators },
        { .compatible = "qcom,rpm-pm8941-regulators", .data = &rpm_pm8941_regulators },
index 02bfce9..a2d0292 100644 (file)
@@ -164,6 +164,8 @@ enum spmi_regulator_subtype {
        SPMI_REGULATOR_SUBTYPE_ULT_HF_CTL3      = 0x0f,
        SPMI_REGULATOR_SUBTYPE_ULT_HF_CTL4      = 0x10,
        SPMI_REGULATOR_SUBTYPE_HFS430           = 0x0a,
+       SPMI_REGULATOR_SUBTYPE_HT_P150          = 0x35,
+       SPMI_REGULATOR_SUBTYPE_HT_P600          = 0x3d,
 };
 
 enum spmi_common_regulator_registers {
@@ -544,6 +546,14 @@ static struct spmi_voltage_range hfs430_ranges[] = {
        SPMI_VOLTAGE_RANGE(0, 320000, 320000, 2040000, 2040000, 8000),
 };
 
+static struct spmi_voltage_range ht_p150_ranges[] = {
+       SPMI_VOLTAGE_RANGE(0, 1616000, 1616000, 3304000, 3304000, 8000),
+};
+
+static struct spmi_voltage_range ht_p600_ranges[] = {
+       SPMI_VOLTAGE_RANGE(0, 1704000, 1704000, 1896000, 1896000, 8000),
+};
+
 static DEFINE_SPMI_SET_POINTS(pldo);
 static DEFINE_SPMI_SET_POINTS(nldo1);
 static DEFINE_SPMI_SET_POINTS(nldo2);
@@ -564,6 +574,8 @@ static DEFINE_SPMI_SET_POINTS(nldo660);
 static DEFINE_SPMI_SET_POINTS(ht_lvpldo);
 static DEFINE_SPMI_SET_POINTS(ht_nldo);
 static DEFINE_SPMI_SET_POINTS(hfs430);
+static DEFINE_SPMI_SET_POINTS(ht_p150);
+static DEFINE_SPMI_SET_POINTS(ht_p600);
 
 static inline int spmi_vreg_read(struct spmi_regulator *vreg, u16 addr, u8 *buf,
                                 int len)
@@ -1458,6 +1470,8 @@ static const struct regulator_ops spmi_hfs430_ops = {
 
 static const struct spmi_regulator_mapping supported_regulators[] = {
        /*           type subtype dig_min dig_max ltype ops setpoints hpm_min */
+       SPMI_VREG(LDO,   HT_P600,  0, INF, HFS430, hfs430, ht_p600, 10000),
+       SPMI_VREG(LDO,   HT_P150,  0, INF, HFS430, hfs430, ht_p150, 10000),
        SPMI_VREG(BUCK,  GP_CTL,   0, INF, SMPS,   smps,   smps,   100000),
        SPMI_VREG(BUCK,  HFS430,   0, INF, HFS430, hfs430, hfs430,  10000),
        SPMI_VREG(LDO,   N300,     0, INF, LDO,    ldo,    nldo1,   10000),
@@ -2125,6 +2139,28 @@ static const struct spmi_regulator_data pm8005_regulators[] = {
        { }
 };
 
+static const struct spmi_regulator_data pmp8074_regulators[] = {
+       { "s1", 0x1400, "vdd_s1"},
+       { "s2", 0x1700, "vdd_s2"},
+       { "s3", 0x1a00, "vdd_s3"},
+       { "s4", 0x1d00, "vdd_s4"},
+       { "s5", 0x2000, "vdd_s5"},
+       { "l1", 0x4000, "vdd_l1_l2"},
+       { "l2", 0x4100, "vdd_l1_l2"},
+       { "l3", 0x4200, "vdd_l3_l8"},
+       { "l4", 0x4300, "vdd_l4"},
+       { "l5", 0x4400, "vdd_l5_l6_l15"},
+       { "l6", 0x4500, "vdd_l5_l6_l15"},
+       { "l7", 0x4600, "vdd_l7"},
+       { "l8", 0x4700, "vdd_l3_l8"},
+       { "l9", 0x4800, "vdd_l9"},
+       /* l10 is currently unsupported HT_P50 */
+       { "l11", 0x4a00, "vdd_l10_l11_l12_l13"},
+       { "l12", 0x4b00, "vdd_l10_l11_l12_l13"},
+       { "l13", 0x4c00, "vdd_l10_l11_l12_l13"},
+       { }
+};
+
 static const struct spmi_regulator_data pms405_regulators[] = {
        { "s3", 0x1a00, "vdd_s3"},
        { }
@@ -2142,6 +2178,7 @@ static const struct of_device_id qcom_spmi_regulator_match[] = {
        { .compatible = "qcom,pmi8994-regulators", .data = &pmi8994_regulators },
        { .compatible = "qcom,pm660-regulators", .data = &pm660_regulators },
        { .compatible = "qcom,pm660l-regulators", .data = &pm660l_regulators },
+       { .compatible = "qcom,pmp8074-regulators", .data = &pmp8074_regulators },
        { .compatible = "qcom,pms405-regulators", .data = &pms405_regulators },
        { }
 };
index fa8706a..105f694 100644 (file)
@@ -187,15 +187,11 @@ static int attiny_update_status(struct backlight_device *bl)
 {
        struct attiny_lcd *state = bl_get_data(bl);
        struct regmap *regmap = state->regmap;
-       int brightness = bl->props.brightness;
+       int brightness = backlight_get_brightness(bl);
        int ret, i;
 
        mutex_lock(&state->lock);
 
-       if (bl->props.power != FB_BLANK_UNBLANK ||
-           bl->props.fb_blank != FB_BLANK_UNBLANK)
-               brightness = 0;
-
        for (i = 0; i < 10; i++) {
                ret = regmap_write(regmap, REG_PWM, brightness);
                if (!ret)
diff --git a/drivers/regulator/rt5120-regulator.c b/drivers/regulator/rt5120-regulator.c
new file mode 100644 (file)
index 0000000..8173ede
--- /dev/null
@@ -0,0 +1,420 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <linux/bits.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+#define RT5120_REG_PGSTAT      0x03
+#define RT5120_REG_CH1VID      0x06
+#define RT5120_REG_CH1SLPVID   0x07
+#define RT5120_REG_ENABLE      0x08
+#define RT5120_REG_MODECTL     0x09
+#define RT5120_REG_UVOVPROT    0x0A
+#define RT5120_REG_SLPCTL      0x0C
+#define RT5120_REG_INTSTAT     0x1E
+#define RT5120_REG_DISCHG      0x1F
+
+#define RT5120_OUTPG_MASK(rid) BIT(rid + 1)
+#define RT5120_OUTUV_MASK(rid) BIT(rid + 9)
+#define RT5120_OUTOV_MASK(rid) BIT(rid + 16)
+#define RT5120_CH1VID_MASK     GENMASK(6, 0)
+#define RT5120_RIDEN_MASK(rid) BIT(rid + 1)
+#define RT5120_RADEN_MASK(rid) BIT(rid)
+#define RT5120_FPWM_MASK(rid)  BIT(rid + 1)
+#define RT5120_UVHICCUP_MASK   BIT(1)
+#define RT5120_OVHICCUP_MASK   BIT(0)
+#define RT5120_HOTDIE_MASK     BIT(1)
+
+#define RT5120_BUCK1_MINUV     600000
+#define RT5120_BUCK1_MAXUV     1393750
+#define RT5120_BUCK1_STEPUV    6250
+#define RT5120_BUCK1_NUM_VOLT  0x80
+
+#define RT5120_AUTO_MODE       0
+#define RT5120_FPWM_MODE       1
+
+enum {
+       RT5120_REGULATOR_BUCK1 = 0,
+       RT5120_REGULATOR_BUCK2,
+       RT5120_REGULATOR_BUCK3,
+       RT5120_REGULATOR_BUCK4,
+       RT5120_REGULATOR_LDO,
+       RT5120_REGULATOR_EXTEN,
+       RT5120_MAX_REGULATOR
+};
+
+struct rt5120_priv {
+       struct device *dev;
+       struct regmap *regmap;
+       struct regulator_desc rdesc[RT5120_MAX_REGULATOR];
+};
+
+static int rt5120_buck_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+       struct regmap *regmap = rdev_get_regmap(rdev);
+       int rid = rdev_get_id(rdev);
+       unsigned int mask = RT5120_FPWM_MASK(rid), val;
+
+       switch (mode) {
+       case REGULATOR_MODE_NORMAL:
+               val = 0;
+               break;
+       case REGULATOR_MODE_FAST:
+               val = RT5120_FPWM_MASK(rid);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return regmap_update_bits(regmap, RT5120_REG_MODECTL, mask, val);
+}
+
+static unsigned int rt5120_buck_get_mode(struct regulator_dev *rdev)
+{
+       struct regmap *regmap = rdev_get_regmap(rdev);
+       int ret, rid = rdev_get_id(rdev);
+       unsigned int val;
+
+       ret = regmap_read(regmap, RT5120_REG_MODECTL, &val);
+       if (ret)
+               return REGULATOR_MODE_INVALID;
+
+       if (val & RT5120_FPWM_MASK(rid))
+               return REGULATOR_MODE_FAST;
+
+       return REGULATOR_MODE_NORMAL;
+}
+
+static int rt5120_regulator_get_error_flags(struct regulator_dev *rdev,
+                                           unsigned int *flags)
+{
+       struct regmap *regmap = rdev_get_regmap(rdev);
+       unsigned int stat, hd_stat, cur_flags = 0;
+       int rid = rdev_get_id(rdev), ret;
+
+       /*
+        * reg 0x03/0x04/0x05 to indicate PG/UV/OV
+        * use block read to descrease I/O xfer time
+        */
+       ret = regmap_raw_read(regmap, RT5120_REG_PGSTAT, &stat, 3);
+       if (ret)
+               return ret;
+
+       ret = regmap_read(regmap, RT5120_REG_INTSTAT, &hd_stat);
+       if (ret)
+               return ret;
+
+       if (!(stat & RT5120_OUTPG_MASK(rid))) {
+               if (stat & RT5120_OUTUV_MASK(rid))
+                       cur_flags |= REGULATOR_ERROR_UNDER_VOLTAGE;
+
+               if (stat & RT5120_OUTOV_MASK(rid))
+                       cur_flags |= REGULATOR_ERROR_REGULATION_OUT;
+       }
+
+       if (hd_stat & RT5120_HOTDIE_MASK)
+               cur_flags |= REGULATOR_ERROR_OVER_TEMP;
+
+       *flags = cur_flags;
+       return 0;
+}
+
+static int rt5120_buck1_set_suspend_voltage(struct regulator_dev *rdev, int uV)
+{
+       struct regmap *regmap = rdev_get_regmap(rdev);
+       int sel;
+
+       if (uV < RT5120_BUCK1_MINUV || uV > RT5120_BUCK1_MAXUV)
+               return -EINVAL;
+
+       sel = (uV - RT5120_BUCK1_MINUV) / RT5120_BUCK1_STEPUV;
+       return regmap_write(regmap, RT5120_REG_CH1SLPVID, sel);
+}
+
+static int rt5120_regulator_set_suspend_enable(struct regulator_dev *rdev)
+{
+       struct regmap *regmap = rdev_get_regmap(rdev);
+       int rid = rdev_get_id(rdev);
+       unsigned int mask = RT5120_RIDEN_MASK(rid);
+
+       return regmap_update_bits(regmap, RT5120_REG_SLPCTL, mask, mask);
+}
+
+static int rt5120_regulator_set_suspend_disable(struct regulator_dev *rdev)
+{
+       struct regmap *regmap = rdev_get_regmap(rdev);
+       int rid = rdev_get_id(rdev);
+       unsigned int mask = RT5120_RIDEN_MASK(rid);
+
+       return regmap_update_bits(regmap, RT5120_REG_SLPCTL, mask, 0);
+}
+
+static const struct regulator_ops rt5120_buck1_ops = {
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .list_voltage = regulator_list_voltage_linear,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .set_active_discharge = regulator_set_active_discharge_regmap,
+       .set_mode = rt5120_buck_set_mode,
+       .get_mode = rt5120_buck_get_mode,
+       .get_error_flags = rt5120_regulator_get_error_flags,
+       .set_suspend_voltage = rt5120_buck1_set_suspend_voltage,
+       .set_suspend_enable = rt5120_regulator_set_suspend_enable,
+       .set_suspend_disable = rt5120_regulator_set_suspend_disable,
+};
+
+static const struct regulator_ops rt5120_buck234_ops = {
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .set_active_discharge = regulator_set_active_discharge_regmap,
+       .set_mode = rt5120_buck_set_mode,
+       .get_mode = rt5120_buck_get_mode,
+       .get_error_flags = rt5120_regulator_get_error_flags,
+       .set_suspend_enable = rt5120_regulator_set_suspend_enable,
+       .set_suspend_disable = rt5120_regulator_set_suspend_disable,
+};
+
+static const struct regulator_ops rt5120_ldo_ops = {
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .set_active_discharge = regulator_set_active_discharge_regmap,
+       .get_error_flags = rt5120_regulator_get_error_flags,
+       .set_suspend_enable = rt5120_regulator_set_suspend_enable,
+       .set_suspend_disable = rt5120_regulator_set_suspend_disable,
+};
+
+static const struct regulator_ops rt5120_exten_ops = {
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .set_suspend_enable = rt5120_regulator_set_suspend_enable,
+       .set_suspend_disable = rt5120_regulator_set_suspend_disable,
+};
+
+static unsigned int rt5120_buck_of_map_mode(unsigned int mode)
+{
+       switch (mode) {
+       case RT5120_AUTO_MODE:
+               return REGULATOR_MODE_NORMAL;
+       case RT5120_FPWM_MODE:
+               return REGULATOR_MODE_FAST;
+       default:
+               return REGULATOR_MODE_INVALID;
+       }
+}
+
+static void rt5120_fillin_regulator_desc(struct regulator_desc *desc, int rid)
+{
+       static const char * const name[] = {
+               "buck1", "buck2", "buck3", "buck4", "ldo", "exten" };
+       static const char * const sname[] = {
+               "vin1", "vin2", "vin3", "vin4", "vinldo", NULL };
+
+       /* Common regulator property */
+       desc->name = name[rid];
+       desc->supply_name = sname[rid];
+       desc->owner = THIS_MODULE;
+       desc->type = REGULATOR_VOLTAGE;
+       desc->id = rid;
+       desc->enable_reg = RT5120_REG_ENABLE;
+       desc->enable_mask = RT5120_RIDEN_MASK(rid);
+       desc->active_discharge_reg = RT5120_REG_DISCHG;
+       desc->active_discharge_mask = RT5120_RADEN_MASK(rid);
+       desc->active_discharge_on = RT5120_RADEN_MASK(rid);
+       /* Config n_voltages to 1 for all*/
+       desc->n_voltages = 1;
+
+       /* Only buck support mode change */
+       if (rid >= RT5120_REGULATOR_BUCK1 && rid <= RT5120_REGULATOR_BUCK4)
+               desc->of_map_mode = rt5120_buck_of_map_mode;
+
+       /* RID specific property init */
+       switch (rid) {
+       case RT5120_REGULATOR_BUCK1:
+               /* Only buck1 support voltage change by I2C */
+               desc->n_voltages = RT5120_BUCK1_NUM_VOLT;
+               desc->min_uV = RT5120_BUCK1_MINUV;
+               desc->uV_step = RT5120_BUCK1_STEPUV;
+               desc->vsel_reg = RT5120_REG_CH1VID,
+               desc->vsel_mask = RT5120_CH1VID_MASK,
+               desc->ops = &rt5120_buck1_ops;
+               break;
+       case RT5120_REGULATOR_BUCK2 ... RT5120_REGULATOR_BUCK4:
+               desc->ops = &rt5120_buck234_ops;
+               break;
+       case RT5120_REGULATOR_LDO:
+               desc->ops = &rt5120_ldo_ops;
+               break;
+       default:
+               desc->ops = &rt5120_exten_ops;
+       }
+}
+
+static int rt5120_of_parse_cb(struct rt5120_priv *priv, int rid,
+                             struct of_regulator_match *match)
+{
+       struct regulator_desc *desc = priv->rdesc + rid;
+       struct regulator_init_data *init_data = match->init_data;
+
+       if (!init_data || rid == RT5120_REGULATOR_BUCK1)
+               return 0;
+
+       if (init_data->constraints.min_uV != init_data->constraints.max_uV) {
+               dev_err(priv->dev, "Variable voltage for fixed regulator\n");
+               return -EINVAL;
+       }
+
+       desc->fixed_uV = init_data->constraints.min_uV;
+       return 0;
+}
+
+static struct of_regulator_match rt5120_regu_match[RT5120_MAX_REGULATOR] = {
+       [RT5120_REGULATOR_BUCK1] = { .name = "buck1", },
+       [RT5120_REGULATOR_BUCK2] = { .name = "buck2", },
+       [RT5120_REGULATOR_BUCK3] = { .name = "buck3", },
+       [RT5120_REGULATOR_BUCK4] = { .name = "buck4", },
+       [RT5120_REGULATOR_LDO] = { .name = "ldo", },
+       [RT5120_REGULATOR_EXTEN] = { .name = "exten", }
+};
+
+static int rt5120_parse_regulator_dt_data(struct rt5120_priv *priv)
+{
+       struct device *dev = priv->dev->parent;
+       struct device_node *reg_node;
+       int i, ret;
+
+       for (i = 0; i < RT5120_MAX_REGULATOR; i++) {
+               rt5120_fillin_regulator_desc(priv->rdesc + i, i);
+
+               rt5120_regu_match[i].desc = priv->rdesc + i;
+       }
+
+       reg_node = of_get_child_by_name(dev->of_node, "regulators");
+       if (!reg_node) {
+               dev_err(priv->dev, "Couldn't find 'regulators' node\n");
+               return -ENODEV;
+       }
+
+       ret = of_regulator_match(priv->dev, reg_node, rt5120_regu_match,
+                                ARRAY_SIZE(rt5120_regu_match));
+
+       of_node_put(reg_node);
+
+       if (ret < 0) {
+               dev_err(priv->dev,
+                       "Error parsing regulator init data (%d)\n", ret);
+               return ret;
+       }
+
+       for (i = 0; i < RT5120_MAX_REGULATOR; i++) {
+               ret = rt5120_of_parse_cb(priv, i, rt5120_regu_match + i);
+               if (ret) {
+                       dev_err(priv->dev, "Failed in [%d] of_passe_cb\n", i);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int rt5120_device_property_init(struct rt5120_priv *priv)
+{
+       struct device *dev = priv->dev->parent;
+       struct device_node *np = dev->of_node;
+       bool prot_enable;
+       unsigned int prot_enable_val = 0;
+
+       /* Assign UV/OV HW protection behavior */
+       prot_enable = of_property_read_bool(np,
+                                           "richtek,enable-undervolt-hiccup");
+       if (prot_enable)
+               prot_enable_val |= RT5120_UVHICCUP_MASK;
+
+       prot_enable = of_property_read_bool(np,
+                                           "richtek,enable-overvolt-hiccup");
+       if (prot_enable)
+               prot_enable_val |= RT5120_OVHICCUP_MASK;
+
+       return regmap_update_bits(priv->regmap, RT5120_REG_UVOVPROT,
+                                 RT5120_UVHICCUP_MASK | RT5120_OVHICCUP_MASK,
+                                 prot_enable_val);
+}
+
+static int rt5120_regulator_probe(struct platform_device *pdev)
+{
+       struct rt5120_priv *priv;
+       struct regulator_dev *rdev;
+       struct regulator_config config = {};
+       int i, ret;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->dev = &pdev->dev;
+
+       priv->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+       if (!priv->regmap) {
+               dev_err(&pdev->dev, "Failed to init regmap\n");
+               return -ENODEV;
+       }
+
+       ret = rt5120_device_property_init(priv);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to do property init\n");
+               return ret;
+       }
+
+       ret = rt5120_parse_regulator_dt_data(priv);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to parse dt data\n");
+               return ret;
+       }
+
+       config.dev = &pdev->dev;
+       config.regmap = priv->regmap;
+
+       for (i = 0; i < RT5120_MAX_REGULATOR; i++) {
+               config.of_node = rt5120_regu_match[i].of_node;
+               config.init_data = rt5120_regu_match[i].init_data;
+
+               rdev = devm_regulator_register(&pdev->dev, priv->rdesc + i,
+                                              &config);
+               if (IS_ERR(rdev)) {
+                       dev_err(&pdev->dev,
+                               "Failed to register regulator [%d]\n", i);
+                       return PTR_ERR(rdev);
+               }
+       }
+
+       return 0;
+}
+
+static const struct platform_device_id rt5120_regulator_dev_table[] = {
+       { "rt5120-regulator", 0 },
+       {}
+};
+MODULE_DEVICE_TABLE(platform, rt5120_regulator_dev_table);
+
+static struct platform_driver rt5120_regulator_driver = {
+       .driver = {
+               .name = "rt5120-regulator",
+       },
+       .id_table = rt5120_regulator_dev_table,
+       .probe = rt5120_regulator_probe,
+};
+module_platform_driver(rt5120_regulator_driver);
+
+MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("Richtek RT5120 regulator driver");
+MODULE_LICENSE("GPL v2");
index 155d4af..4a3397b 100644 (file)
@@ -224,6 +224,9 @@ static int rt5190a_of_parse_cb(struct rt5190a_priv *priv, int rid,
        bool latchup_enable;
        unsigned int mask = RT5190A_RID_BITMASK(rid), val;
 
+       if (!init_data)
+               return 0;
+
        switch (rid) {
        case RT5190A_IDX_BUCK1:
        case RT5190A_IDX_BUCK4:
index 41ae7ac..b9918f4 100644 (file)
@@ -343,6 +343,7 @@ static int scmi_regulator_probe(struct scmi_device *sdev)
         * plausible SCMI Voltage Domain number, all belonging to this SCMI
         * platform instance node (handle->dev->of_node).
         */
+       of_node_get(handle->dev->of_node);
        np = of_find_node_by_name(handle->dev->of_node, "regulators");
        for_each_child_of_node(np, child) {
                ret = process_scmi_regulator_of_node(sdev, ph, child, rinfo);
index bd7b2f2..afa336b 100644 (file)
@@ -309,7 +309,7 @@ out:
  *
  * Return: 0 on success or appropriate error value when fails
  */
-static int ti_abb_set_voltage_sel(struct regulator_dev *rdev, unsigned sel)
+static int ti_abb_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel)
 {
        const struct regulator_desc *desc = rdev->desc;
        struct ti_abb *abb = rdev_get_drvdata(rdev);
@@ -344,7 +344,7 @@ static int ti_abb_set_voltage_sel(struct regulator_dev *rdev, unsigned sel)
 
        info = &abb->info[sel];
        /*
-        * When Linux kernel is starting up, we are'nt sure of the
+        * When Linux kernel is starting up, we aren't sure of the
         * Bias configuration that bootloader has configured.
         * So, we get to know the actual setting the first time
         * we are asked to transition.
index 93c8d07..48d9464 100644 (file)
@@ -231,6 +231,15 @@ config RESET_STARFIVE_JH7100
        help
          This enables the reset controller driver for the StarFive JH7100 SoC.
 
+config RESET_SUNPLUS
+       bool "Sunplus SoCs Reset Driver" if COMPILE_TEST
+       default ARCH_SUNPLUS
+       help
+         This enables the reset driver support for Sunplus SoCs.
+         The reset lines that can be asserted and deasserted by toggling bits
+         in a contiguous, exclusive register space. The register is HIWORD_MASKED,
+         which means each register holds 16 reset lines.
+
 config RESET_SUNXI
        bool "Allwinner SoCs Reset Driver" if COMPILE_TEST && !ARCH_SUNXI
        default ARCH_SUNXI
index a80a9c4..3ff378f 100644 (file)
@@ -30,6 +30,7 @@ obj-$(CONFIG_RESET_SCMI) += reset-scmi.o
 obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
 obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
 obj-$(CONFIG_RESET_STARFIVE_JH7100) += reset-starfive-jh7100.o
+obj-$(CONFIG_RESET_SUNPLUS) += reset-sunplus.o
 obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
 obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o
 obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o
index 2ea4d31..24c55ef 100644 (file)
 
 /* NPCM7xx GCR registers */
 #define NPCM_MDLR_OFFSET       0x7C
-#define NPCM_MDLR_USBD0                BIT(9)
-#define NPCM_MDLR_USBD1                BIT(8)
-#define NPCM_MDLR_USBD2_4      BIT(21)
-#define NPCM_MDLR_USBD5_9      BIT(22)
+#define NPCM7XX_MDLR_USBD0     BIT(9)
+#define NPCM7XX_MDLR_USBD1     BIT(8)
+#define NPCM7XX_MDLR_USBD2_4   BIT(21)
+#define NPCM7XX_MDLR_USBD5_9   BIT(22)
+
+/* NPCM8xx MDLR bits */
+#define NPCM8XX_MDLR_USBD0_3   BIT(9)
+#define NPCM8XX_MDLR_USBD4_7   BIT(22)
+#define NPCM8XX_MDLR_USBD8     BIT(24)
+#define NPCM8XX_MDLR_USBD9     BIT(21)
 
 #define NPCM_USB1PHYCTL_OFFSET 0x140
 #define NPCM_USB2PHYCTL_OFFSET 0x144
+#define NPCM_USB3PHYCTL_OFFSET 0x148
 #define NPCM_USBXPHYCTL_RS     BIT(28)
 
 /* NPCM7xx Reset registers */
 #define NPCM_IPSRST3_USBPHY1   BIT(24)
 #define NPCM_IPSRST3_USBPHY2   BIT(25)
 
+#define NPCM_IPSRST4           0x74
+#define NPCM_IPSRST4_USBPHY3   BIT(25)
+#define NPCM_IPSRST4_USB_HOST2 BIT(31)
+
 #define NPCM_RC_RESETS_PER_REG 32
 #define NPCM_MASK_RESETS       GENMASK(4, 0)
 
+enum {
+       BMC_NPCM7XX = 0,
+       BMC_NPCM8XX,
+};
+
+static const u32 npxm7xx_ipsrst[] = {NPCM_IPSRST1, NPCM_IPSRST2, NPCM_IPSRST3};
+static const u32 npxm8xx_ipsrst[] = {NPCM_IPSRST1, NPCM_IPSRST2, NPCM_IPSRST3,
+       NPCM_IPSRST4};
+
+struct npcm_reset_info {
+       u32 bmc_id;
+       u32 num_ipsrst;
+       const u32 *ipsrst;
+};
+
+static const struct npcm_reset_info npxm7xx_reset_info[] = {
+       {.bmc_id = BMC_NPCM7XX, .num_ipsrst = 3, .ipsrst = npxm7xx_ipsrst}};
+static const struct npcm_reset_info npxm8xx_reset_info[] = {
+       {.bmc_id = BMC_NPCM8XX, .num_ipsrst = 4, .ipsrst = npxm8xx_ipsrst}};
+
 struct npcm_rc_data {
        struct reset_controller_dev rcdev;
        struct notifier_block restart_nb;
+       const struct npcm_reset_info *info;
+       struct regmap *gcr_regmap;
        u32 sw_reset_number;
        void __iomem *base;
        spinlock_t lock;
@@ -120,14 +153,24 @@ static int npcm_rc_status(struct reset_controller_dev *rcdev,
 static int npcm_reset_xlate(struct reset_controller_dev *rcdev,
                            const struct of_phandle_args *reset_spec)
 {
+       struct npcm_rc_data *rc = to_rc_data(rcdev);
        unsigned int offset, bit;
+       bool offset_found = false;
+       int off_num;
 
        offset = reset_spec->args[0];
-       if (offset != NPCM_IPSRST1 && offset != NPCM_IPSRST2 &&
-           offset != NPCM_IPSRST3) {
+       for (off_num = 0 ; off_num < rc->info->num_ipsrst ; off_num++) {
+               if (offset == rc->info->ipsrst[off_num]) {
+                       offset_found = true;
+                       break;
+               }
+       }
+
+       if (!offset_found) {
                dev_err(rcdev->dev, "Error reset register (0x%x)\n", offset);
                return -EINVAL;
        }
+
        bit = reset_spec->args[1];
        if (bit >= NPCM_RC_RESETS_PER_REG) {
                dev_err(rcdev->dev, "Error reset number (%d)\n", bit);
@@ -138,45 +181,29 @@ static int npcm_reset_xlate(struct reset_controller_dev *rcdev,
 }
 
 static const struct of_device_id npcm_rc_match[] = {
-       { .compatible = "nuvoton,npcm750-reset",
-               .data = (void *)"nuvoton,npcm750-gcr" },
+       { .compatible = "nuvoton,npcm750-reset", .data = &npxm7xx_reset_info},
+       { .compatible = "nuvoton,npcm845-reset", .data = &npxm8xx_reset_info},
        { }
 };
 
-/*
- *  The following procedure should be observed in USB PHY, USB device and
- *  USB host initialization at BMC boot
- */
-static int npcm_usb_reset(struct platform_device *pdev, struct npcm_rc_data *rc)
+static void npcm_usb_reset_npcm7xx(struct npcm_rc_data *rc)
 {
        u32 mdlr, iprst1, iprst2, iprst3;
-       struct device *dev = &pdev->dev;
-       struct regmap *gcr_regmap;
        u32 ipsrst1_bits = 0;
        u32 ipsrst2_bits = NPCM_IPSRST2_USB_HOST;
        u32 ipsrst3_bits = 0;
-       const char *gcr_dt;
-
-       gcr_dt = (const char *)
-       of_match_device(dev->driver->of_match_table, dev)->data;
-
-       gcr_regmap = syscon_regmap_lookup_by_compatible(gcr_dt);
-       if (IS_ERR(gcr_regmap)) {
-               dev_err(&pdev->dev, "Failed to find %s\n", gcr_dt);
-               return PTR_ERR(gcr_regmap);
-       }
 
        /* checking which USB device is enabled */
-       regmap_read(gcr_regmap, NPCM_MDLR_OFFSET, &mdlr);
-       if (!(mdlr & NPCM_MDLR_USBD0))
+       regmap_read(rc->gcr_regmap, NPCM_MDLR_OFFSET, &mdlr);
+       if (!(mdlr & NPCM7XX_MDLR_USBD0))
                ipsrst3_bits |= NPCM_IPSRST3_USBD0;
-       if (!(mdlr & NPCM_MDLR_USBD1))
+       if (!(mdlr & NPCM7XX_MDLR_USBD1))
                ipsrst1_bits |= NPCM_IPSRST1_USBD1;
-       if (!(mdlr & NPCM_MDLR_USBD2_4))
+       if (!(mdlr & NPCM7XX_MDLR_USBD2_4))
                ipsrst1_bits |= (NPCM_IPSRST1_USBD2 |
                                 NPCM_IPSRST1_USBD3 |
                                 NPCM_IPSRST1_USBD4);
-       if (!(mdlr & NPCM_MDLR_USBD0)) {
+       if (!(mdlr & NPCM7XX_MDLR_USBD0)) {
                ipsrst1_bits |= (NPCM_IPSRST1_USBD5 |
                                 NPCM_IPSRST1_USBD6);
                ipsrst3_bits |= (NPCM_IPSRST3_USBD7 |
@@ -199,9 +226,9 @@ static int npcm_usb_reset(struct platform_device *pdev, struct npcm_rc_data *rc)
        writel(iprst3, rc->base + NPCM_IPSRST3);
 
        /* clear USB PHY RS bit */
-       regmap_update_bits(gcr_regmap, NPCM_USB1PHYCTL_OFFSET,
+       regmap_update_bits(rc->gcr_regmap, NPCM_USB1PHYCTL_OFFSET,
                           NPCM_USBXPHYCTL_RS, 0);
-       regmap_update_bits(gcr_regmap, NPCM_USB2PHYCTL_OFFSET,
+       regmap_update_bits(rc->gcr_regmap, NPCM_USB2PHYCTL_OFFSET,
                           NPCM_USBXPHYCTL_RS, 0);
 
        /* deassert reset USB PHY */
@@ -211,19 +238,131 @@ static int npcm_usb_reset(struct platform_device *pdev, struct npcm_rc_data *rc)
        udelay(50);
 
        /* set USB PHY RS bit */
-       regmap_update_bits(gcr_regmap, NPCM_USB1PHYCTL_OFFSET,
+       regmap_update_bits(rc->gcr_regmap, NPCM_USB1PHYCTL_OFFSET,
+                          NPCM_USBXPHYCTL_RS, NPCM_USBXPHYCTL_RS);
+       regmap_update_bits(rc->gcr_regmap, NPCM_USB2PHYCTL_OFFSET,
+                          NPCM_USBXPHYCTL_RS, NPCM_USBXPHYCTL_RS);
+
+       /* deassert reset USB devices*/
+       iprst1 &= ~ipsrst1_bits;
+       iprst2 &= ~ipsrst2_bits;
+       iprst3 &= ~ipsrst3_bits;
+
+       writel(iprst1, rc->base + NPCM_IPSRST1);
+       writel(iprst2, rc->base + NPCM_IPSRST2);
+       writel(iprst3, rc->base + NPCM_IPSRST3);
+}
+
+static void npcm_usb_reset_npcm8xx(struct npcm_rc_data *rc)
+{
+       u32 mdlr, iprst1, iprst2, iprst3, iprst4;
+       u32 ipsrst1_bits = 0;
+       u32 ipsrst2_bits = NPCM_IPSRST2_USB_HOST;
+       u32 ipsrst3_bits = 0;
+       u32 ipsrst4_bits = NPCM_IPSRST4_USB_HOST2 | NPCM_IPSRST4_USBPHY3;
+
+       /* checking which USB device is enabled */
+       regmap_read(rc->gcr_regmap, NPCM_MDLR_OFFSET, &mdlr);
+       if (!(mdlr & NPCM8XX_MDLR_USBD0_3)) {
+               ipsrst3_bits |= NPCM_IPSRST3_USBD0;
+               ipsrst1_bits |= (NPCM_IPSRST1_USBD1 |
+                                NPCM_IPSRST1_USBD2 |
+                                NPCM_IPSRST1_USBD3);
+       }
+       if (!(mdlr & NPCM8XX_MDLR_USBD4_7)) {
+               ipsrst1_bits |= (NPCM_IPSRST1_USBD4 |
+                                NPCM_IPSRST1_USBD5 |
+                                NPCM_IPSRST1_USBD6);
+               ipsrst3_bits |= NPCM_IPSRST3_USBD7;
+       }
+
+       if (!(mdlr & NPCM8XX_MDLR_USBD8))
+               ipsrst3_bits |= NPCM_IPSRST3_USBD8;
+       if (!(mdlr & NPCM8XX_MDLR_USBD9))
+               ipsrst3_bits |= NPCM_IPSRST3_USBD9;
+
+       /* assert reset USB PHY and USB devices */
+       iprst1 = readl(rc->base + NPCM_IPSRST1);
+       iprst2 = readl(rc->base + NPCM_IPSRST2);
+       iprst3 = readl(rc->base + NPCM_IPSRST3);
+       iprst4 = readl(rc->base + NPCM_IPSRST4);
+
+       iprst1 |= ipsrst1_bits;
+       iprst2 |= ipsrst2_bits;
+       iprst3 |= (ipsrst3_bits | NPCM_IPSRST3_USBPHY1 |
+                  NPCM_IPSRST3_USBPHY2);
+       iprst2 |= ipsrst4_bits;
+
+       writel(iprst1, rc->base + NPCM_IPSRST1);
+       writel(iprst2, rc->base + NPCM_IPSRST2);
+       writel(iprst3, rc->base + NPCM_IPSRST3);
+       writel(iprst4, rc->base + NPCM_IPSRST4);
+
+       /* clear USB PHY RS bit */
+       regmap_update_bits(rc->gcr_regmap, NPCM_USB1PHYCTL_OFFSET,
+                          NPCM_USBXPHYCTL_RS, 0);
+       regmap_update_bits(rc->gcr_regmap, NPCM_USB2PHYCTL_OFFSET,
+                          NPCM_USBXPHYCTL_RS, 0);
+       regmap_update_bits(rc->gcr_regmap, NPCM_USB3PHYCTL_OFFSET,
+                          NPCM_USBXPHYCTL_RS, 0);
+
+       /* deassert reset USB PHY */
+       iprst3 &= ~(NPCM_IPSRST3_USBPHY1 | NPCM_IPSRST3_USBPHY2);
+       writel(iprst3, rc->base + NPCM_IPSRST3);
+       iprst4 &= ~NPCM_IPSRST4_USBPHY3;
+       writel(iprst4, rc->base + NPCM_IPSRST4);
+
+       /* set USB PHY RS bit */
+       regmap_update_bits(rc->gcr_regmap, NPCM_USB1PHYCTL_OFFSET,
+                          NPCM_USBXPHYCTL_RS, NPCM_USBXPHYCTL_RS);
+       regmap_update_bits(rc->gcr_regmap, NPCM_USB2PHYCTL_OFFSET,
                           NPCM_USBXPHYCTL_RS, NPCM_USBXPHYCTL_RS);
-       regmap_update_bits(gcr_regmap, NPCM_USB2PHYCTL_OFFSET,
+       regmap_update_bits(rc->gcr_regmap, NPCM_USB3PHYCTL_OFFSET,
                           NPCM_USBXPHYCTL_RS, NPCM_USBXPHYCTL_RS);
 
        /* deassert reset USB devices*/
        iprst1 &= ~ipsrst1_bits;
        iprst2 &= ~ipsrst2_bits;
        iprst3 &= ~ipsrst3_bits;
+       iprst4 &= ~ipsrst4_bits;
 
        writel(iprst1, rc->base + NPCM_IPSRST1);
        writel(iprst2, rc->base + NPCM_IPSRST2);
        writel(iprst3, rc->base + NPCM_IPSRST3);
+       writel(iprst4, rc->base + NPCM_IPSRST4);
+}
+
+/*
+ *  The following procedure should be observed in USB PHY, USB device and
+ *  USB host initialization at BMC boot
+ */
+static int npcm_usb_reset(struct platform_device *pdev, struct npcm_rc_data *rc)
+{
+       struct device *dev = &pdev->dev;
+
+       rc->gcr_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "nuvoton,sysgcr");
+       if (IS_ERR(rc->gcr_regmap)) {
+               dev_warn(&pdev->dev, "Failed to find nuvoton,sysgcr property, please update the device tree\n");
+               dev_info(&pdev->dev, "Using nuvoton,npcm750-gcr for Poleg backward compatibility\n");
+               rc->gcr_regmap = syscon_regmap_lookup_by_compatible("nuvoton,npcm750-gcr");
+               if (IS_ERR(rc->gcr_regmap)) {
+                       dev_err(&pdev->dev, "Failed to find nuvoton,npcm750-gcr");
+                       return PTR_ERR(rc->gcr_regmap);
+               }
+       }
+
+       rc->info = (const struct npcm_reset_info *)
+                       of_match_device(dev->driver->of_match_table, dev)->data;
+       switch (rc->info->bmc_id) {
+       case BMC_NPCM7XX:
+               npcm_usb_reset_npcm7xx(rc);
+               break;
+       case BMC_NPCM8XX:
+               npcm_usb_reset_npcm8xx(rc);
+               break;
+       default:
+               return -ENODEV;
+       }
 
        return 0;
 }
diff --git a/drivers/reset/reset-sunplus.c b/drivers/reset/reset-sunplus.c
new file mode 100644 (file)
index 0000000..2f23eca
--- /dev/null
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * SP7021 reset driver
+ *
+ * Copyright (C) Sunplus Technology Co., Ltd.
+ *       All rights reserved.
+ */
+
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/reboot.h>
+
+/* HIWORD_MASK_REG BITS */
+#define BITS_PER_HWM_REG       16
+
+/* resets HW info: reg_index_shift */
+static const u32 sp_resets[] = {
+/* SP7021: mo_reset0 ~ mo_reset9 */
+       0x00,
+       0x02,
+       0x03,
+       0x04,
+       0x05,
+       0x06,
+       0x07,
+       0x08,
+       0x09,
+       0x0a,
+       0x0b,
+       0x0d,
+       0x0e,
+       0x0f,
+       0x10,
+       0x12,
+       0x14,
+       0x15,
+       0x16,
+       0x17,
+       0x18,
+       0x19,
+       0x1a,
+       0x1b,
+       0x1c,
+       0x1d,
+       0x1e,
+       0x1f,
+       0x20,
+       0x21,
+       0x22,
+       0x23,
+       0x24,
+       0x25,
+       0x26,
+       0x2a,
+       0x2b,
+       0x2d,
+       0x2e,
+       0x30,
+       0x31,
+       0x32,
+       0x33,
+       0x3d,
+       0x3e,
+       0x3f,
+       0x42,
+       0x44,
+       0x4b,
+       0x4c,
+       0x4d,
+       0x4e,
+       0x4f,
+       0x50,
+       0x55,
+       0x60,
+       0x61,
+       0x6a,
+       0x6f,
+       0x70,
+       0x73,
+       0x74,
+       0x86,
+       0x8a,
+       0x8b,
+       0x8d,
+       0x8e,
+       0x8f,
+       0x90,
+       0x92,
+       0x93,
+       0x94,
+       0x95,
+       0x96,
+       0x97,
+       0x98,
+       0x99,
+};
+
+struct sp_reset {
+       struct reset_controller_dev rcdev;
+       struct notifier_block notifier;
+       void __iomem *base;
+};
+
+static inline struct sp_reset *to_sp_reset(struct reset_controller_dev *rcdev)
+{
+       return container_of(rcdev, struct sp_reset, rcdev);
+}
+
+static int sp_reset_update(struct reset_controller_dev *rcdev,
+                          unsigned long id, bool assert)
+{
+       struct sp_reset *reset = to_sp_reset(rcdev);
+       int index = sp_resets[id] / BITS_PER_HWM_REG;
+       int shift = sp_resets[id] % BITS_PER_HWM_REG;
+       u32 val;
+
+       val = (1 << (16 + shift)) | (assert << shift);
+       writel(val, reset->base + (index * 4));
+
+       return 0;
+}
+
+static int sp_reset_assert(struct reset_controller_dev *rcdev,
+                          unsigned long id)
+{
+       return sp_reset_update(rcdev, id, true);
+}
+
+static int sp_reset_deassert(struct reset_controller_dev *rcdev,
+                            unsigned long id)
+{
+       return sp_reset_update(rcdev, id, false);
+}
+
+static int sp_reset_status(struct reset_controller_dev *rcdev,
+                          unsigned long id)
+{
+       struct sp_reset *reset = to_sp_reset(rcdev);
+       int index = sp_resets[id] / BITS_PER_HWM_REG;
+       int shift = sp_resets[id] % BITS_PER_HWM_REG;
+       u32 reg;
+
+       reg = readl(reset->base + (index * 4));
+
+       return !!(reg & BIT(shift));
+}
+
+static const struct reset_control_ops sp_reset_ops = {
+       .assert   = sp_reset_assert,
+       .deassert = sp_reset_deassert,
+       .status   = sp_reset_status,
+};
+
+static int sp_restart(struct notifier_block *nb, unsigned long mode,
+                     void *cmd)
+{
+       struct sp_reset *reset = container_of(nb, struct sp_reset, notifier);
+
+       sp_reset_assert(&reset->rcdev, 0);
+       sp_reset_deassert(&reset->rcdev, 0);
+
+       return NOTIFY_DONE;
+}
+
+static int sp_reset_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct sp_reset *reset;
+       struct resource *res;
+       int ret;
+
+       reset = devm_kzalloc(dev, sizeof(*reset), GFP_KERNEL);
+       if (!reset)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       reset->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(reset->base))
+               return PTR_ERR(reset->base);
+
+       reset->rcdev.ops = &sp_reset_ops;
+       reset->rcdev.owner = THIS_MODULE;
+       reset->rcdev.of_node = dev->of_node;
+       reset->rcdev.nr_resets = resource_size(res) / 4 * BITS_PER_HWM_REG;
+
+       ret = devm_reset_controller_register(dev, &reset->rcdev);
+       if (ret)
+               return ret;
+
+       reset->notifier.notifier_call = sp_restart;
+       reset->notifier.priority = 192;
+
+       return register_restart_handler(&reset->notifier);
+}
+
+static const struct of_device_id sp_reset_dt_ids[] = {
+       {.compatible = "sunplus,sp7021-reset",},
+       { /* sentinel */ },
+};
+
+static struct platform_driver sp_reset_driver = {
+       .probe = sp_reset_probe,
+       .driver = {
+               .name                   = "sunplus-reset",
+               .of_match_table         = sp_reset_dt_ids,
+               .suppress_bind_attrs    = true,
+       },
+};
+builtin_platform_driver(sp_reset_driver);
index ba6d787..4df8bf6 100644 (file)
@@ -3145,7 +3145,7 @@ out:
  * BLK_EH_DONE if the request is handled or terminated
  *                   by the driver.
  */
-enum blk_eh_timer_return dasd_times_out(struct request *req, bool reserved)
+enum blk_eh_timer_return dasd_times_out(struct request *req)
 {
        struct dasd_block *block = req->q->queuedata;
        struct dasd_device *device;
@@ -3280,7 +3280,7 @@ static int dasd_alloc_queue(struct dasd_block *block)
 static void dasd_free_queue(struct dasd_block *block)
 {
        if (block->request_queue) {
-               blk_cleanup_queue(block->request_queue);
+               blk_mq_destroy_queue(block->request_queue);
                blk_mq_free_tag_set(&block->tag_set);
                block->request_queue = NULL;
        }
index a7a33eb..5a83f0a 100644 (file)
@@ -41,8 +41,8 @@ int dasd_gendisk_alloc(struct dasd_block *block)
        if (base->devindex >= DASD_PER_MAJOR)
                return -EBUSY;
 
-       gdp = __alloc_disk_node(block->request_queue, NUMA_NO_NODE,
-                               &dasd_bio_compl_lkclass);
+       gdp = blk_mq_alloc_disk_for_queue(block->request_queue,
+                                         &dasd_bio_compl_lkclass);
        if (!gdp)
                return -ENOMEM;
 
index 83b918b..333a399 100644 (file)
@@ -795,7 +795,7 @@ void dasd_free_device(struct dasd_device *);
 struct dasd_block *dasd_alloc_block(void);
 void dasd_free_block(struct dasd_block *);
 
-enum blk_eh_timer_return dasd_times_out(struct request *req, bool reserved);
+enum blk_eh_timer_return dasd_times_out(struct request *req);
 
 void dasd_enable_device(struct dasd_device *);
 void dasd_set_target_state(struct dasd_device *, int);
index 8d0d0ea..4d8d175 100644 (file)
@@ -414,7 +414,7 @@ removeseg:
        kill_dax(dev_info->dax_dev);
        put_dax(dev_info->dax_dev);
        del_gendisk(dev_info->gd);
-       blk_cleanup_disk(dev_info->gd);
+       put_disk(dev_info->gd);
        up_write(&dcssblk_devices_sem);
 
        if (device_remove_file_self(dev, attr)) {
@@ -712,7 +712,7 @@ out_dax:
        put_dax(dev_info->dax_dev);
 put_dev:
        list_del(&dev_info->lh);
-       blk_cleanup_disk(dev_info->gd);
+       put_disk(dev_info->gd);
        list_for_each_entry(seg_info, &dev_info->seg_list, lh) {
                segment_unload(seg_info->segment_name);
        }
@@ -722,7 +722,7 @@ put_dev:
 dev_list_del:
        list_del(&dev_info->lh);
 release_gd:
-       blk_cleanup_disk(dev_info->gd);
+       put_disk(dev_info->gd);
        up_write(&dcssblk_devices_sem);
 seg_list_del:
        if (dev_info == NULL)
@@ -790,7 +790,7 @@ dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const ch
        kill_dax(dev_info->dax_dev);
        put_dax(dev_info->dax_dev);
        del_gendisk(dev_info->gd);
-       blk_cleanup_disk(dev_info->gd);
+       put_disk(dev_info->gd);
 
        /* unload all related segments */
        list_for_each_entry(entry, &dev_info->seg_list, lh)
index 2a9c0dd..0c1df1d 100644 (file)
@@ -501,7 +501,7 @@ int scm_blk_dev_setup(struct scm_blk_dev *bdev, struct scm_device *scmdev)
        return 0;
 
 out_cleanup_disk:
-       blk_cleanup_disk(bdev->gendisk);
+       put_disk(bdev->gendisk);
 out_tag:
        blk_mq_free_tag_set(&bdev->tag_set);
 out:
@@ -512,7 +512,7 @@ out:
 void scm_blk_dev_cleanup(struct scm_blk_dev *bdev)
 {
        del_gendisk(bdev->gendisk);
-       blk_cleanup_disk(bdev->gendisk);
+       put_disk(bdev->gendisk);
        blk_mq_free_tag_set(&bdev->tag_set);
 }
 
index cb24917..ae1d6ee 100644 (file)
@@ -60,7 +60,7 @@ static LIST_HEAD(sclp_reg_list);
 /* List of queued requests. */
 static LIST_HEAD(sclp_req_queue);
 
-/* Data for read and and init requests. */
+/* Data for read and init requests. */
 static struct sclp_req sclp_read_req;
 static struct sclp_req sclp_init_req;
 static void *sclp_read_sccb;
index 5c13d20..0a9045b 100644 (file)
@@ -1435,7 +1435,7 @@ static int __verify_queue_reservations(struct device_driver *drv, void *data)
        if (ap_drv->in_use) {
                rc = ap_drv->in_use(ap_perms.apm, newaqm);
                if (rc)
-                       return -EBUSY;
+                       rc = -EBUSY;
        }
 
        /* release the driver's module */
index 9e54fe7..35d4b39 100644 (file)
@@ -3565,7 +3565,7 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
                        if (!atomic_read(&queue->set_pci_flags_count)) {
                                /*
                                 * there's no outstanding PCI any more, so we
-                                * have to request a PCI to be sure the the PCI
+                                * have to request a PCI to be sure the PCI
                                 * will wake at some time in the future then we
                                 * can flush packed buffers that might still be
                                 * hanging around, which can happen if no
index 97e51c3..161d3b1 100644 (file)
@@ -1136,8 +1136,13 @@ static void virtio_ccw_int_handler(struct ccw_device *cdev,
                        vcdev->err = -EIO;
        }
        virtio_ccw_check_activity(vcdev, activity);
-       /* Interrupts are disabled here */
+#ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION
+       /*
+        * Paired with virtio_ccw_synchronize_cbs() and interrupts are
+        * disabled here.
+        */
        read_lock(&vcdev->irq_lock);
+#endif
        for_each_set_bit(i, indicators(vcdev),
                         sizeof(*indicators(vcdev)) * BITS_PER_BYTE) {
                /* The bit clear must happen before the vring kick. */
@@ -1146,7 +1151,9 @@ static void virtio_ccw_int_handler(struct ccw_device *cdev,
                vq = virtio_ccw_vq_by_ind(vcdev, i);
                vring_interrupt(0, vq);
        }
+#ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION
        read_unlock(&vcdev->irq_lock);
+#endif
        if (test_bit(0, indicators2(vcdev))) {
                virtio_config_changed(&vcdev->vdev);
                clear_bit(0, indicators2(vcdev));
index 940a6de..bd99c54 100644 (file)
@@ -272,7 +272,7 @@ static void aac_queue_init(struct aac_dev * dev, struct aac_queue * q, u32 *mem,
        q->entries = qsize;
 }
 
-static bool wait_for_io_iter(struct scsi_cmnd *cmd, void *data, bool rsvd)
+static bool wait_for_io_iter(struct scsi_cmnd *cmd, void *data)
 {
        int *active = data;
 
index 9c27bc3..5ba5c18 100644 (file)
@@ -633,7 +633,7 @@ struct fib_count_data {
        int krlcnt;
 };
 
-static bool fib_count_iter(struct scsi_cmnd *scmnd, void *data, bool reserved)
+static bool fib_count_iter(struct scsi_cmnd *scmnd, void *data)
 {
        struct fib_count_data *fib_count = data;
 
index 1d9be77..610a515 100644 (file)
@@ -127,7 +127,7 @@ static int submit_rtpg(struct scsi_device *sdev, unsigned char *buff,
                       int bufflen, struct scsi_sense_hdr *sshdr, int flags)
 {
        u8 cdb[MAX_COMMAND_SIZE];
-       int req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
+       blk_opf_t req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
                REQ_FAILFAST_DRIVER;
 
        /* Prepare the command. */
@@ -157,7 +157,7 @@ static int submit_stpg(struct scsi_device *sdev, int group_id,
        u8 cdb[MAX_COMMAND_SIZE];
        unsigned char stpg_data[8];
        int stpg_len = 8;
-       int req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
+       blk_opf_t req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
                REQ_FAILFAST_DRIVER;
 
        /* Prepare the data buffer */
index bd28ec6..2e21ab4 100644 (file)
@@ -239,7 +239,7 @@ static int send_trespass_cmd(struct scsi_device *sdev,
        unsigned char cdb[MAX_COMMAND_SIZE];
        int err, res = SCSI_DH_OK, len;
        struct scsi_sense_hdr sshdr;
-       u64 req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
+       blk_opf_t req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
                REQ_FAILFAST_DRIVER;
 
        if (csdev->flags & CLARIION_SHORT_TRESPASS) {
index 4a3f783..0d2cfa6 100644 (file)
@@ -83,7 +83,7 @@ static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h)
        unsigned char cmd[6] = { TEST_UNIT_READY };
        struct scsi_sense_hdr sshdr;
        int ret = SCSI_DH_OK, res;
-       u64 req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
+       blk_opf_t req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
                REQ_FAILFAST_DRIVER;
 
 retry:
@@ -121,7 +121,7 @@ static int hp_sw_start_stop(struct hp_sw_dh_data *h)
        struct scsi_device *sdev = h->sdev;
        int res, rc = SCSI_DH_OK;
        int retry_cnt = HP_SW_RETRIES;
-       u64 req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
+       blk_opf_t req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
                REQ_FAILFAST_DRIVER;
 
 retry:
index 66652ab..bf87547 100644 (file)
@@ -536,7 +536,7 @@ static void send_mode_select(struct work_struct *work)
        unsigned char cdb[MAX_COMMAND_SIZE];
        struct scsi_sense_hdr sshdr;
        unsigned int data_size;
-       u64 req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
+       blk_opf_t req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
                REQ_FAILFAST_DRIVER;
 
        spin_lock(&ctlr->ms_lock);
index 3d64877..77a4d9f 100644 (file)
@@ -1350,8 +1350,7 @@ int fnic_wq_copy_cmpl_handler(struct fnic *fnic, int copy_work_to_do)
        return wq_work_done;
 }
 
-static bool fnic_cleanup_io_iter(struct scsi_cmnd *sc, void *data,
-                                bool reserved)
+static bool fnic_cleanup_io_iter(struct scsi_cmnd *sc, void *data)
 {
        const int tag = scsi_cmd_to_rq(sc)->tag;
        struct fnic *fnic = data;
@@ -1548,8 +1547,7 @@ struct fnic_rport_abort_io_iter_data {
        int term_cnt;
 };
 
-static bool fnic_rport_abort_io_iter(struct scsi_cmnd *sc, void *data,
-                                    bool reserved)
+static bool fnic_rport_abort_io_iter(struct scsi_cmnd *sc, void *data)
 {
        struct fnic_rport_abort_io_iter_data *iter_data = data;
        struct fnic *fnic = iter_data->fnic;
@@ -2003,8 +2001,7 @@ struct fnic_pending_aborts_iter_data {
        int ret;
 };
 
-static bool fnic_pending_aborts_iter(struct scsi_cmnd *sc,
-                                    void *data, bool reserved)
+static bool fnic_pending_aborts_iter(struct scsi_cmnd *sc, void *data)
 {
        struct fnic_pending_aborts_iter_data *iter_data = data;
        struct fnic *fnic = iter_data->fnic;
@@ -2019,8 +2016,6 @@ static bool fnic_pending_aborts_iter(struct scsi_cmnd *sc,
 
        if (sc == iter_data->lr_sc || sc->device != lun_dev)
                return true;
-       if (reserved)
-               return true;
 
        io_lock = fnic_io_lock_tag(fnic, abt_tag);
        spin_lock_irqsave(io_lock, flags);
@@ -2670,8 +2665,7 @@ call_fc_exch_mgr_reset:
 
 }
 
-static bool fnic_abts_pending_iter(struct scsi_cmnd *sc, void *data,
-                                  bool reserved)
+static bool fnic_abts_pending_iter(struct scsi_cmnd *sc, void *data)
 {
        struct fnic_pending_aborts_iter_data *iter_data = data;
        struct fnic *fnic = iter_data->fnic;
index 7d819fc..eb86afb 100644 (file)
@@ -2782,6 +2782,7 @@ static int slave_configure_v3_hw(struct scsi_device *sdev)
        struct hisi_hba *hisi_hba = shost_priv(shost);
        struct device *dev = hisi_hba->dev;
        int ret = sas_slave_configure(sdev);
+       unsigned int max_sectors;
 
        if (ret)
                return ret;
@@ -2799,6 +2800,12 @@ static int slave_configure_v3_hw(struct scsi_device *sdev)
                }
        }
 
+       /* Set according to IOMMU IOVA caching limit */
+       max_sectors = min_t(size_t, queue_max_hw_sectors(sdev->request_queue),
+                           (PAGE_SIZE * 32) >> SECTOR_SHIFT);
+
+       blk_queue_max_hw_sectors(sdev->request_queue, max_sectors);
+
        return 0;
 }
 
index 8352f90..315c7ac 100644 (file)
@@ -566,8 +566,7 @@ struct Scsi_Host *scsi_host_get(struct Scsi_Host *shost)
 }
 EXPORT_SYMBOL(scsi_host_get);
 
-static bool scsi_host_check_in_flight(struct request *rq, void *data,
-                                     bool reserved)
+static bool scsi_host_check_in_flight(struct request *rq, void *data)
 {
        int *count = data;
        struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq);
@@ -662,7 +661,7 @@ void scsi_flush_work(struct Scsi_Host *shost)
 }
 EXPORT_SYMBOL_GPL(scsi_flush_work);
 
-static bool complete_all_cmds_iter(struct request *rq, void *data, bool rsvd)
+static bool complete_all_cmds_iter(struct request *rq, void *data)
 {
        struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq);
        enum scsi_host_status status = *(enum scsi_host_status *)data;
@@ -693,17 +692,16 @@ void scsi_host_complete_all_commands(struct Scsi_Host *shost,
 EXPORT_SYMBOL_GPL(scsi_host_complete_all_commands);
 
 struct scsi_host_busy_iter_data {
-       bool (*fn)(struct scsi_cmnd *, void *, bool);
+       bool (*fn)(struct scsi_cmnd *, void *);
        void *priv;
 };
 
-static bool __scsi_host_busy_iter_fn(struct request *req, void *priv,
-                                  bool reserved)
+static bool __scsi_host_busy_iter_fn(struct request *req, void *priv)
 {
        struct scsi_host_busy_iter_data *iter_data = priv;
        struct scsi_cmnd *sc = blk_mq_rq_to_pdu(req);
 
-       return iter_data->fn(sc, iter_data->priv, reserved);
+       return iter_data->fn(sc, iter_data->priv);
 }
 
 /**
@@ -716,7 +714,7 @@ static bool __scsi_host_busy_iter_fn(struct request *req, void *priv,
  * ithas to be provided by the caller
  **/
 void scsi_host_busy_iter(struct Scsi_Host *shost,
-                        bool (*fn)(struct scsi_cmnd *, void *, bool),
+                        bool (*fn)(struct scsi_cmnd *, void *),
                         void *priv)
 {
        struct scsi_host_busy_iter_data iter_data = {
index c95360a..0917b05 100644 (file)
@@ -3195,6 +3195,9 @@ static int megasas_map_queues(struct Scsi_Host *shost)
        qoff += map->nr_queues;
        offset += map->nr_queues;
 
+       /* we never use READ queue, so can't cheat blk-mq */
+       shost->tag_set.map[HCTX_TYPE_READ].nr_queues = 0;
+
        /* Setup Poll hctx */
        map = &shost->tag_set.map[HCTX_TYPE_POLL];
        map->nr_queues = instance->iopoll_q_count;
index d8c195b..59a1876 100644 (file)
@@ -381,14 +381,12 @@ void mpi3mr_invalidate_devhandles(struct mpi3mr_ioc *mrioc)
  * mpi3mr_print_scmd - print individual SCSI command
  * @rq: Block request
  * @data: Adapter instance reference
- * @reserved: N/A. Currently not used
  *
  * Print the SCSI command details if it is in LLD scope.
  *
  * Return: true always.
  */
-static bool mpi3mr_print_scmd(struct request *rq,
-       void *data, bool reserved)
+static bool mpi3mr_print_scmd(struct request *rq, void *data)
 {
        struct mpi3mr_ioc *mrioc = (struct mpi3mr_ioc *)data;
        struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq);
@@ -412,7 +410,6 @@ out:
  * mpi3mr_flush_scmd - Flush individual SCSI command
  * @rq: Block request
  * @data: Adapter instance reference
- * @reserved: N/A. Currently not used
  *
  * Return the SCSI command to the upper layers if it is in LLD
  * scope.
@@ -420,8 +417,7 @@ out:
  * Return: true always.
  */
 
-static bool mpi3mr_flush_scmd(struct request *rq,
-       void *data, bool reserved)
+static bool mpi3mr_flush_scmd(struct request *rq, void *data)
 {
        struct mpi3mr_ioc *mrioc = (struct mpi3mr_ioc *)data;
        struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq);
@@ -451,7 +447,6 @@ out:
  * mpi3mr_count_dev_pending - Count commands pending for a lun
  * @rq: Block request
  * @data: SCSI device reference
- * @reserved: Unused
  *
  * This is an iterator function called for each SCSI command in
  * a host and if the command is pending in the LLD for the
@@ -461,8 +456,7 @@ out:
  * Return: true always.
  */
 
-static bool mpi3mr_count_dev_pending(struct request *rq,
-       void *data, bool reserved)
+static bool mpi3mr_count_dev_pending(struct request *rq, void *data)
 {
        struct scsi_device *sdev = (struct scsi_device *)data;
        struct mpi3mr_sdev_priv_data *sdev_priv_data = sdev->hostdata;
@@ -485,7 +479,6 @@ out:
  * mpi3mr_count_tgt_pending - Count commands pending for target
  * @rq: Block request
  * @data: SCSI target reference
- * @reserved: Unused
  *
  * This is an iterator function called for each SCSI command in
  * a host and if the command is pending in the LLD for the
@@ -495,8 +488,7 @@ out:
  * Return: true always.
  */
 
-static bool mpi3mr_count_tgt_pending(struct request *rq,
-       void *data, bool reserved)
+static bool mpi3mr_count_tgt_pending(struct request *rq, void *data)
 {
        struct scsi_target *starget = (struct scsi_target *)data;
        struct mpi3mr_stgt_priv_data *stgt_priv_data = starget->hostdata;
index b519f4b..5e8887f 100644 (file)
@@ -11386,6 +11386,7 @@ scsih_shutdown(struct pci_dev *pdev)
        _scsih_ir_shutdown(ioc);
        _scsih_nvme_shutdown(ioc);
        mpt3sas_base_mask_interrupts(ioc);
+       mpt3sas_base_stop_watchdog(ioc);
        ioc->shost_recovery = 1;
        mpt3sas_base_make_ioc_ready(ioc, SOFT_RESET);
        ioc->shost_recovery = 0;
index f7466a8..991eb01 100644 (file)
@@ -3145,15 +3145,6 @@ void pm8001_bytes_dmaed(struct pm8001_hba_info *pm8001_ha, int i)
        if (!phy->phy_attached)
                return;
 
-       if (sas_phy->phy) {
-               struct sas_phy *sphy = sas_phy->phy;
-               sphy->negotiated_linkrate = sas_phy->linkrate;
-               sphy->minimum_linkrate = phy->minimum_linkrate;
-               sphy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
-               sphy->maximum_linkrate = phy->maximum_linkrate;
-               sphy->maximum_linkrate_hw = phy->maximum_linkrate;
-       }
-
        if (phy->phy_type & PORT_TYPE_SAS) {
                struct sas_identify_frame *id;
                id = (struct sas_identify_frame *)phy->frame_rcvd;
@@ -3177,26 +3168,22 @@ void pm8001_get_lrate_mode(struct pm8001_phy *phy, u8 link_rate)
        switch (link_rate) {
        case PHY_SPEED_120:
                phy->sas_phy.linkrate = SAS_LINK_RATE_12_0_GBPS;
-               phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_12_0_GBPS;
                break;
        case PHY_SPEED_60:
                phy->sas_phy.linkrate = SAS_LINK_RATE_6_0_GBPS;
-               phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_6_0_GBPS;
                break;
        case PHY_SPEED_30:
                phy->sas_phy.linkrate = SAS_LINK_RATE_3_0_GBPS;
-               phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
                break;
        case PHY_SPEED_15:
                phy->sas_phy.linkrate = SAS_LINK_RATE_1_5_GBPS;
-               phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
                break;
        }
        sas_phy->negotiated_linkrate = phy->sas_phy.linkrate;
-       sas_phy->maximum_linkrate_hw = SAS_LINK_RATE_6_0_GBPS;
+       sas_phy->maximum_linkrate_hw = phy->maximum_linkrate;
        sas_phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
-       sas_phy->maximum_linkrate = SAS_LINK_RATE_6_0_GBPS;
-       sas_phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
+       sas_phy->maximum_linkrate = phy->maximum_linkrate;
+       sas_phy->minimum_linkrate = phy->minimum_linkrate;
 }
 
 /**
index 9b04f1a..01f2f41 100644 (file)
@@ -143,6 +143,8 @@ static void pm8001_phy_init(struct pm8001_hba_info *pm8001_ha, int phy_id)
        struct asd_sas_phy *sas_phy = &phy->sas_phy;
        phy->phy_state = PHY_LINK_DISABLE;
        phy->pm8001_ha = pm8001_ha;
+       phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
+       phy->maximum_linkrate = SAS_LINK_RATE_6_0_GBPS;
        sas_phy->enabled = (phy_id < pm8001_ha->chip->n_phy) ? 1 : 0;
        sas_phy->class = SAS;
        sas_phy->iproto = SAS_PROTOCOL_ALL;
index 01c5e8f..303cd05 100644 (file)
@@ -3723,8 +3723,12 @@ static int mpi_phy_stop_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
        pm8001_dbg(pm8001_ha, MSG, "phy:0x%x status:0x%x\n",
                   phyid, status);
        if (status == PHY_STOP_SUCCESS ||
-               status == PHY_STOP_ERR_DEVICE_ATTACHED)
+               status == PHY_STOP_ERR_DEVICE_ATTACHED) {
                phy->phy_state = PHY_LINK_DISABLE;
+               phy->sas_phy.phy->negotiated_linkrate = SAS_PHY_DISABLED;
+               phy->sas_phy.linkrate = SAS_PHY_DISABLED;
+       }
+
        return 0;
 }
 
index 49ef864..b776cef 100644 (file)
@@ -139,7 +139,7 @@ static bool scsi_eh_should_retry_cmd(struct scsi_cmnd *cmd)
  *
  * Note: this function must be called only for a command that has timed out.
  * Because the block layer marks a request as complete before it calls
- * scsi_times_out(), a .scsi_done() call from the LLD for a command that has
+ * scsi_timeout(), a .scsi_done() call from the LLD for a command that has
  * timed out do not have any effect. Hence it is safe to call
  * scsi_finish_command() from this function.
  */
@@ -316,7 +316,7 @@ void scsi_eh_scmd_add(struct scsi_cmnd *scmd)
 }
 
 /**
- * scsi_times_out - Timeout function for normal scsi commands.
+ * scsi_timeout - Timeout function for normal scsi commands.
  * @req:       request that is timing out.
  *
  * Notes:
@@ -325,7 +325,7 @@ void scsi_eh_scmd_add(struct scsi_cmnd *scmd)
  *     normal completion function determines that the timer has already
  *     fired, then it mustn't do anything.
  */
-enum blk_eh_timer_return scsi_times_out(struct request *req)
+enum blk_eh_timer_return scsi_timeout(struct request *req)
 {
        struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(req);
        enum blk_eh_timer_return rtn = BLK_EH_DONE;
@@ -1779,7 +1779,7 @@ static void scsi_eh_offline_sdevs(struct list_head *work_q,
  * scsi_noretry_cmd - determine if command should be failed fast
  * @scmd:      SCSI cmd to examine.
  */
-int scsi_noretry_cmd(struct scsi_cmnd *scmd)
+bool scsi_noretry_cmd(struct scsi_cmnd *scmd)
 {
        struct request *req = scsi_cmd_to_rq(scmd);
 
@@ -1789,19 +1789,19 @@ int scsi_noretry_cmd(struct scsi_cmnd *scmd)
        case DID_TIME_OUT:
                goto check_type;
        case DID_BUS_BUSY:
-               return req->cmd_flags & REQ_FAILFAST_TRANSPORT;
+               return !!(req->cmd_flags & REQ_FAILFAST_TRANSPORT);
        case DID_PARITY:
-               return req->cmd_flags & REQ_FAILFAST_DEV;
+               return !!(req->cmd_flags & REQ_FAILFAST_DEV);
        case DID_ERROR:
                if (get_status_byte(scmd) == SAM_STAT_RESERVATION_CONFLICT)
-                       return 0;
+                       return false;
                fallthrough;
        case DID_SOFT_ERROR:
-               return req->cmd_flags & REQ_FAILFAST_DRIVER;
+               return !!(req->cmd_flags & REQ_FAILFAST_DRIVER);
        }
 
        if (!scsi_status_is_check_condition(scmd->result))
-               return 0;
+               return false;
 
 check_type:
        /*
@@ -1809,9 +1809,9 @@ check_type:
         * the check condition was retryable.
         */
        if (req->cmd_flags & REQ_FAILFAST_DEV || blk_rq_is_passthrough(req))
-               return 1;
+               return true;
 
-       return 0;
+       return false;
 }
 
 /**
index a480c4d..729e309 100644 (file)
@@ -450,7 +450,7 @@ static int sg_io(struct scsi_device *sdev, struct sg_io_hdr *hdr, fmode_t mode)
                goto out_put_request;
 
        ret = 0;
-       if (hdr->iovec_count) {
+       if (hdr->iovec_count && hdr->dxfer_len) {
                struct iov_iter i;
                struct iovec *iov = NULL;
 
index 6ffc9e4..17a617d 100644 (file)
@@ -163,7 +163,7 @@ static void __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, bool unbusy)
         * Requeue this command.  It will go before all other commands
         * that are already in the queue. Schedule requeue work under
         * lock such that the kblockd_schedule_work() call happens
-        * before blk_cleanup_queue() finishes.
+        * before blk_mq_destroy_queue() finishes.
         */
        cmd->result = 0;
 
@@ -209,8 +209,8 @@ void scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
 int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
                 int data_direction, void *buffer, unsigned bufflen,
                 unsigned char *sense, struct scsi_sense_hdr *sshdr,
-                int timeout, int retries, u64 flags, req_flags_t rq_flags,
-                int *resid)
+                int timeout, int retries, blk_opf_t flags,
+                req_flags_t rq_flags, int *resid)
 {
        struct request *req;
        struct scsi_cmnd *scmd;
@@ -424,9 +424,9 @@ static void scsi_starved_list_run(struct Scsi_Host *shost)
                 * it and the queue.  Mitigate by taking a reference to the
                 * queue and never touching the sdev again after we drop the
                 * host lock.  Note: if __scsi_remove_device() invokes
-                * blk_cleanup_queue() before the queue is run from this
+                * blk_mq_destroy_queue() before the queue is run from this
                 * function then blk_run_queue() will return immediately since
-                * blk_cleanup_queue() marks the queue with QUEUE_FLAG_DYING.
+                * blk_mq_destroy_queue() marks the queue with QUEUE_FLAG_DYING.
                 */
                slq = sdev->request_queue;
                if (!blk_get_queue(slq))
@@ -633,7 +633,7 @@ static blk_status_t scsi_result_to_blk_status(struct scsi_cmnd *cmd, int result)
  */
 static unsigned int scsi_rq_err_bytes(const struct request *rq)
 {
-       unsigned int ff = rq->cmd_flags & REQ_FAILFAST_MASK;
+       blk_opf_t ff = rq->cmd_flags & REQ_FAILFAST_MASK;
        unsigned int bytes = 0;
        struct bio *bio;
 
@@ -1125,12 +1125,12 @@ static void scsi_initialize_rq(struct request *rq)
        cmd->retries = 0;
 }
 
-struct request *scsi_alloc_request(struct request_queue *q,
-               unsigned int op, blk_mq_req_flags_t flags)
+struct request *scsi_alloc_request(struct request_queue *q, blk_opf_t opf,
+                                  blk_mq_req_flags_t flags)
 {
        struct request *rq;
 
-       rq = blk_mq_alloc_request(q, op, flags);
+       rq = blk_mq_alloc_request(q, opf, flags);
        if (!IS_ERR(rq))
                scsi_initialize_rq(rq);
        return rq;
@@ -1790,14 +1790,6 @@ out_put_budget:
        return ret;
 }
 
-static enum blk_eh_timer_return scsi_timeout(struct request *req,
-               bool reserved)
-{
-       if (reserved)
-               return BLK_EH_RESET_TIMER;
-       return scsi_times_out(req);
-}
-
 static int scsi_mq_init_request(struct blk_mq_tag_set *set, struct request *rq,
                                unsigned int hctx_idx, unsigned int numa_node)
 {
index 5c47863..429663b 100644 (file)
@@ -72,7 +72,7 @@ extern void scsi_exit_devinfo(void);
 
 /* scsi_error.c */
 extern void scmd_eh_abort_handler(struct work_struct *work);
-extern enum blk_eh_timer_return scsi_times_out(struct request *req);
+extern enum blk_eh_timer_return scsi_timeout(struct request *req);
 extern int scsi_error_handler(void *host);
 extern enum scsi_disposition scsi_decide_disposition(struct scsi_cmnd *cmd);
 extern void scsi_eh_wakeup(struct Scsi_Host *shost);
@@ -82,7 +82,7 @@ void scsi_eh_ready_devs(struct Scsi_Host *shost,
                        struct list_head *done_q);
 int scsi_eh_get_sense(struct list_head *work_q,
                      struct list_head *done_q);
-int scsi_noretry_cmd(struct scsi_cmnd *scmd);
+bool scsi_noretry_cmd(struct scsi_cmnd *scmd);
 void scsi_eh_done(struct scsi_cmnd *scmd);
 
 /* scsi_lib.c */
index 4394979..aa70d92 100644 (file)
@@ -1475,7 +1475,7 @@ void __scsi_remove_device(struct scsi_device *sdev)
        scsi_device_set_state(sdev, SDEV_DEL);
        mutex_unlock(&sdev->state_mutex);
 
-       blk_cleanup_queue(sdev->request_queue);
+       blk_mq_destroy_queue(sdev->request_queue);
        cancel_work_sync(&sdev->requeue_work);
 
        if (sdev->host->hostt->slave_destroy)
index a1a2ac0..eb02d93 100644 (file)
@@ -2934,15 +2934,15 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp)
 
        if (sdkp->device->type == TYPE_ZBC) {
                /* Host-managed */
-               blk_queue_set_zoned(sdkp->disk, BLK_ZONED_HM);
+               disk_set_zoned(sdkp->disk, BLK_ZONED_HM);
        } else {
                sdkp->zoned = zoned;
                if (sdkp->zoned == 1) {
                        /* Host-aware */
-                       blk_queue_set_zoned(sdkp->disk, BLK_ZONED_HA);
+                       disk_set_zoned(sdkp->disk, BLK_ZONED_HA);
                } else {
                        /* Regular disk or drive managed disk */
-                       blk_queue_set_zoned(sdkp->disk, BLK_ZONED_NONE);
+                       disk_set_zoned(sdkp->disk, BLK_ZONED_NONE);
                }
        }
 
@@ -3440,8 +3440,8 @@ static int sd_probe(struct device *dev)
        if (!sdkp)
                goto out;
 
-       gd = __alloc_disk_node(sdp->request_queue, NUMA_NO_NODE,
-                              &sd_bio_compl_lkclass);
+       gd = blk_mq_alloc_disk_for_queue(sdp->request_queue,
+                                        &sd_bio_compl_lkclass);
        if (!gd)
                goto out_free;
 
index 6acc4f4..bd15624 100644 (file)
@@ -529,7 +529,7 @@ static unsigned int sd_zbc_zone_wp_update(struct scsi_cmnd *cmd,
        struct request *rq = scsi_cmd_to_rq(cmd);
        struct scsi_disk *sdkp = scsi_disk(rq->q->disk);
        unsigned int zno = blk_rq_zone_no(rq);
-       enum req_opf op = req_op(rq);
+       enum req_op op = req_op(rq);
        unsigned long flags;
 
        /*
@@ -855,7 +855,7 @@ int sd_zbc_revalidate_zones(struct scsi_disk *sdkp)
 
        if (sdkp->zone_info.zone_blocks == zone_blocks &&
            sdkp->zone_info.nr_zones == nr_zones &&
-           disk->queue->nr_zones == nr_zones)
+           disk->nr_zones == nr_zones)
                goto unlock;
 
        flags = memalloc_noio_save();
@@ -929,7 +929,7 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, u8 buf[SD_BUF_SIZE])
                /*
                 * This can happen for a host aware disk with partitions.
                 * The block device zone model was already cleared by
-                * blk_queue_set_zoned(). Only free the scsi disk zone
+                * disk_set_zoned(). Only free the scsi disk zone
                 * information and exit early.
                 */
                sd_zbc_free_zone_info(sdkp);
@@ -950,10 +950,10 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, u8 buf[SD_BUF_SIZE])
        blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, q);
        blk_queue_required_elevator_features(q, ELEVATOR_F_ZBD_SEQ_WRITE);
        if (sdkp->zones_max_open == U32_MAX)
-               blk_queue_max_open_zones(q, 0);
+               disk_set_max_open_zones(disk, 0);
        else
-               blk_queue_max_open_zones(q, sdkp->zones_max_open);
-       blk_queue_max_active_zones(q, 0);
+               disk_set_max_open_zones(disk, sdkp->zones_max_open);
+       disk_set_max_active_zones(disk, 0);
        nr_zones = round_up(sdkp->capacity, zone_blocks) >> ilog2(zone_blocks);
 
        /*
index 32d3b82..a278b73 100644 (file)
@@ -624,8 +624,8 @@ static int sr_probe(struct device *dev)
        if (!cd)
                goto fail;
 
-       disk = __alloc_disk_node(sdev->request_queue, NUMA_NO_NODE,
-                                &sr_bio_compl_lkclass);
+       disk = blk_mq_alloc_disk_for_queue(sdev->request_queue,
+                                          &sr_bio_compl_lkclass);
        if (!disk)
                goto fail_free;
        mutex_init(&cd->lock);
index 358df75..828d81e 100644 (file)
@@ -72,7 +72,7 @@ static int intc_set_affinity(struct irq_data *data,
        if (!cpumask_intersects(cpumask, cpu_online_mask))
                return -1;
 
-       cpumask_copy(irq_data_get_affinity_mask(data), cpumask);
+       irq_data_update_affinity(data, cpumask);
 
        return IRQ_SET_MASK_OK_NOCOPY;
 }
index 86ccf59..e461c07 100644 (file)
@@ -9,6 +9,7 @@ source "drivers/soc/atmel/Kconfig"
 source "drivers/soc/bcm/Kconfig"
 source "drivers/soc/canaan/Kconfig"
 source "drivers/soc/fsl/Kconfig"
+source "drivers/soc/fujitsu/Kconfig"
 source "drivers/soc/imx/Kconfig"
 source "drivers/soc/ixp4xx/Kconfig"
 source "drivers/soc/litex/Kconfig"
index 919716e..69ba650 100644 (file)
@@ -12,6 +12,7 @@ obj-$(CONFIG_SOC_CANAAN)      += canaan/
 obj-$(CONFIG_ARCH_DOVE)                += dove/
 obj-$(CONFIG_MACH_DOVE)                += dove/
 obj-y                          += fsl/
+obj-y                          += fujitsu/
 obj-$(CONFIG_ARCH_GEMINI)      += gemini/
 obj-y                          += imx/
 obj-y                          += ixp4xx/
index 78f0f1a..92125dd 100644 (file)
@@ -126,6 +126,7 @@ static int __init meson_mx_socinfo_init(void)
        np = of_find_matching_node(NULL, meson_mx_socinfo_analog_top_ids);
        if (np) {
                analog_top_regmap = syscon_node_to_regmap(np);
+               of_node_put(np);
                if (IS_ERR(analog_top_regmap))
                        return PTR_ERR(analog_top_regmap);
 
index a10a417..e935187 100644 (file)
@@ -152,8 +152,10 @@ static int meson_secure_pwrc_probe(struct platform_device *pdev)
        }
 
        pwrc = devm_kzalloc(&pdev->dev, sizeof(*pwrc), GFP_KERNEL);
-       if (!pwrc)
+       if (!pwrc) {
+               of_node_put(sm_np);
                return -ENOMEM;
+       }
 
        pwrc->fw = meson_sm_get(sm_np);
        of_node_put(sm_np);
index b2d365a..dae8a2e 100644 (file)
@@ -91,14 +91,14 @@ static const struct at91_soc socs[] __initconst = {
        AT91_SOC(SAM9X60_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
                 AT91_CIDR_VERSION_MASK, SAM9X60_EXID_MATCH,
                 "sam9x60", "sam9x60"),
-       AT91_SOC(SAM9X60_CIDR_MATCH, SAM9X60_D5M_EXID_MATCH,
-                AT91_CIDR_VERSION_MASK, SAM9X60_EXID_MATCH,
+       AT91_SOC(SAM9X60_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
+                AT91_CIDR_VERSION_MASK, SAM9X60_D5M_EXID_MATCH,
                 "sam9x60 64MiB DDR2 SiP", "sam9x60"),
-       AT91_SOC(SAM9X60_CIDR_MATCH, SAM9X60_D1G_EXID_MATCH,
-                AT91_CIDR_VERSION_MASK, SAM9X60_EXID_MATCH,
+       AT91_SOC(SAM9X60_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
+                AT91_CIDR_VERSION_MASK, SAM9X60_D1G_EXID_MATCH,
                 "sam9x60 128MiB DDR2 SiP", "sam9x60"),
-       AT91_SOC(SAM9X60_CIDR_MATCH, SAM9X60_D6K_EXID_MATCH,
-                AT91_CIDR_VERSION_MASK, SAM9X60_EXID_MATCH,
+       AT91_SOC(SAM9X60_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
+                AT91_CIDR_VERSION_MASK, SAM9X60_D6K_EXID_MATCH,
                 "sam9x60 8MiB SDRAM SiP", "sam9x60"),
 #endif
 #ifdef CONFIG_SOC_SAMA5
index 1e0041e..5bcd047 100644 (file)
 
 #define ASB_AXI_BRDG_ID                        0x20
 
-#define ASB_READ(reg) readl(power->asb + (reg))
-#define ASB_WRITE(reg, val) writel(PM_PASSWORD | (val), power->asb + (reg))
+#define BCM2835_BRDG_ID                        0x62726467
 
 struct bcm2835_power_domain {
        struct generic_pm_domain base;
@@ -142,24 +141,41 @@ struct bcm2835_power {
        void __iomem            *base;
        /* AXI Async bridge registers. */
        void __iomem            *asb;
+       /* RPiVid bridge registers. */
+       void __iomem            *rpivid_asb;
 
        struct genpd_onecell_data pd_xlate;
        struct bcm2835_power_domain domains[BCM2835_POWER_DOMAIN_COUNT];
        struct reset_controller_dev reset;
 };
 
-static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg)
+static int bcm2835_asb_control(struct bcm2835_power *power, u32 reg, bool enable)
 {
+       void __iomem *base = power->asb;
        u64 start;
+       u32 val;
 
-       if (!reg)
+       switch (reg) {
+       case 0:
                return 0;
+       case ASB_V3D_S_CTRL:
+       case ASB_V3D_M_CTRL:
+               if (power->rpivid_asb)
+                       base = power->rpivid_asb;
+               break;
+       }
 
        start = ktime_get_ns();
 
        /* Enable the module's async AXI bridges. */
-       ASB_WRITE(reg, ASB_READ(reg) & ~ASB_REQ_STOP);
-       while (ASB_READ(reg) & ASB_ACK) {
+       if (enable) {
+               val = readl(base + reg) & ~ASB_REQ_STOP;
+       } else {
+               val = readl(base + reg) | ASB_REQ_STOP;
+       }
+       writel(PM_PASSWORD | val, base + reg);
+
+       while (readl(base + reg) & ASB_ACK) {
                cpu_relax();
                if (ktime_get_ns() - start >= 1000)
                        return -ETIMEDOUT;
@@ -168,30 +184,24 @@ static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg)
        return 0;
 }
 
-static int bcm2835_asb_disable(struct bcm2835_power *power, u32 reg)
+static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg)
 {
-       u64 start;
-
-       if (!reg)
-               return 0;
-
-       start = ktime_get_ns();
-
-       /* Enable the module's async AXI bridges. */
-       ASB_WRITE(reg, ASB_READ(reg) | ASB_REQ_STOP);
-       while (!(ASB_READ(reg) & ASB_ACK)) {
-               cpu_relax();
-               if (ktime_get_ns() - start >= 1000)
-                       return -ETIMEDOUT;
-       }
+       return bcm2835_asb_control(power, reg, true);
+}
 
-       return 0;
+static int bcm2835_asb_disable(struct bcm2835_power *power, u32 reg)
+{
+       return bcm2835_asb_control(power, reg, false);
 }
 
 static int bcm2835_power_power_off(struct bcm2835_power_domain *pd, u32 pm_reg)
 {
        struct bcm2835_power *power = pd->power;
 
+       /* We don't run this on BCM2711 */
+       if (power->rpivid_asb)
+               return 0;
+
        /* Enable functional isolation */
        PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISFUNC);
 
@@ -213,6 +223,10 @@ static int bcm2835_power_power_on(struct bcm2835_power_domain *pd, u32 pm_reg)
        int inrush;
        bool powok;
 
+       /* We don't run this on BCM2711 */
+       if (power->rpivid_asb)
+               return 0;
+
        /* If it was already powered on by the fw, leave it that way. */
        if (PM_READ(pm_reg) & PM_POWUP)
                return 0;
@@ -626,13 +640,23 @@ static int bcm2835_power_probe(struct platform_device *pdev)
        power->dev = dev;
        power->base = pm->base;
        power->asb = pm->asb;
+       power->rpivid_asb = pm->rpivid_asb;
 
-       id = ASB_READ(ASB_AXI_BRDG_ID);
-       if (id != 0x62726467 /* "BRDG" */) {
+       id = readl(power->asb + ASB_AXI_BRDG_ID);
+       if (id != BCM2835_BRDG_ID /* "BRDG" */) {
                dev_err(dev, "ASB register ID returned 0x%08x\n", id);
                return -ENODEV;
        }
 
+       if (power->rpivid_asb) {
+               id = readl(power->rpivid_asb + ASB_AXI_BRDG_ID);
+               if (id != BCM2835_BRDG_ID /* "BRDG" */) {
+                       dev_err(dev, "RPiVid ASB register ID returned 0x%08x\n",
+                                    id);
+                       return -ENODEV;
+               }
+       }
+
        power->pd_xlate.domains = devm_kcalloc(dev,
                                               ARRAY_SIZE(power_domain_names),
                                               sizeof(*power->pd_xlate.domains),
index 2c975d7..1467bbd 100644 (file)
@@ -340,12 +340,12 @@ static int __init brcmstb_biuctrl_init(void)
 
        ret = setup_hifcpubiuctrl_regs(np);
        if (ret)
-               return ret;
+               goto out_put;
 
        ret = mcp_write_pairing_set();
        if (ret) {
                pr_err("MCP: Unable to disable write pairing!\n");
-               return ret;
+               goto out_put;
        }
 
        a72_b53_rac_enable_all(np);
@@ -353,6 +353,9 @@ static int __init brcmstb_biuctrl_init(void)
 #ifdef CONFIG_PM_SLEEP
        register_syscore_ops(&brcmstb_cpu_credit_syscore_ops);
 #endif
-       return 0;
+       ret = 0;
+out_put:
+       of_node_put(np);
+       return ret;
 }
 early_initcall(brcmstb_biuctrl_init);
index 3cbb165..d6b30d5 100644 (file)
@@ -721,7 +721,7 @@ static int brcmstb_pm_probe(struct platform_device *pdev)
        ctrl.phy_a_standby_ctrl_offs = ddr_phy_data->phy_a_standby_ctrl_offs;
        ctrl.phy_b_standby_ctrl_offs = ddr_phy_data->phy_b_standby_ctrl_offs;
        /*
-        * Slightly grosss to use the phy ver to get a memc,
+        * Slightly gross to use the phy ver to get a memc,
         * offset but that is the only versioned things so far
         * we can test for.
         */
@@ -783,6 +783,7 @@ static int brcmstb_pm_probe(struct platform_device *pdev)
        }
 
        ret = brcmstb_init_sram(dn);
+       of_node_put(dn);
        if (ret) {
                pr_err("error setting up SRAM for PM\n");
                return ret;
index 5ed2fc1..6bf3e6a 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/fsl/guts.h>
 
-struct guts {
-       struct ccsr_guts __iomem *regs;
-       bool little_endian;
-};
-
 struct fsl_soc_die_attr {
        char    *die;
        u32     svr;
        u32     mask;
 };
 
-static struct guts *guts;
-static struct soc_device_attribute soc_dev_attr;
-static struct soc_device *soc_dev;
-
+struct fsl_soc_data {
+       const char *sfp_compat;
+       u32 uid_offset;
+};
 
 /* SoC die attribute definition for QorIQ platform */
 static const struct fsl_soc_die_attr fsl_soc_die[] = {
@@ -120,88 +115,36 @@ static const struct fsl_soc_die_attr *fsl_soc_die_match(
        return NULL;
 }
 
-static u32 fsl_guts_get_svr(void)
-{
-       u32 svr = 0;
-
-       if (!guts || !guts->regs)
-               return svr;
-
-       if (guts->little_endian)
-               svr = ioread32(&guts->regs->svr);
-       else
-               svr = ioread32be(&guts->regs->svr);
-
-       return svr;
-}
-
-static int fsl_guts_probe(struct platform_device *pdev)
+static u64 fsl_guts_get_soc_uid(const char *compat, unsigned int offset)
 {
-       struct device_node *root, *np = pdev->dev.of_node;
-       struct device *dev = &pdev->dev;
-       const struct fsl_soc_die_attr *soc_die;
-       const char *machine;
-       u32 svr;
-
-       /* Initialize guts */
-       guts = devm_kzalloc(dev, sizeof(*guts), GFP_KERNEL);
-       if (!guts)
-               return -ENOMEM;
-
-       guts->little_endian = of_property_read_bool(np, "little-endian");
+       struct device_node *np;
+       void __iomem *sfp_base;
+       u64 uid;
 
-       guts->regs = devm_platform_ioremap_resource(pdev, 0);
-       if (IS_ERR(guts->regs))
-               return PTR_ERR(guts->regs);
+       np = of_find_compatible_node(NULL, NULL, compat);
+       if (!np)
+               return 0;
 
-       /* Register soc device */
-       root = of_find_node_by_path("/");
-       if (of_property_read_string(root, "model", &machine))
-               of_property_read_string_index(root, "compatible", 0, &machine);
-       if (machine) {
-               soc_dev_attr.machine = devm_kstrdup(dev, machine, GFP_KERNEL);
-               if (!soc_dev_attr.machine) {
-                       of_node_put(root);
-                       return -ENOMEM;
-               }
+       sfp_base = of_iomap(np, 0);
+       if (!sfp_base) {
+               of_node_put(np);
+               return 0;
        }
-       of_node_put(root);
 
-       svr = fsl_guts_get_svr();
-       soc_die = fsl_soc_die_match(svr, fsl_soc_die);
-       if (soc_die) {
-               soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL,
-                                                    "QorIQ %s", soc_die->die);
-       } else {
-               soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL, "QorIQ");
-       }
-       if (!soc_dev_attr.family)
-               return -ENOMEM;
-       soc_dev_attr.soc_id = devm_kasprintf(dev, GFP_KERNEL,
-                                            "svr:0x%08x", svr);
-       if (!soc_dev_attr.soc_id)
-               return -ENOMEM;
-       soc_dev_attr.revision = devm_kasprintf(dev, GFP_KERNEL, "%d.%d",
-                                              (svr >>  4) & 0xf, svr & 0xf);
-       if (!soc_dev_attr.revision)
-               return -ENOMEM;
+       uid = ioread32(sfp_base + offset);
+       uid <<= 32;
+       uid |= ioread32(sfp_base + offset + 4);
 
-       soc_dev = soc_device_register(&soc_dev_attr);
-       if (IS_ERR(soc_dev))
-               return PTR_ERR(soc_dev);
+       iounmap(sfp_base);
+       of_node_put(np);
 
-       pr_info("Machine: %s\n", soc_dev_attr.machine);
-       pr_info("SoC family: %s\n", soc_dev_attr.family);
-       pr_info("SoC ID: %s, Revision: %s\n",
-               soc_dev_attr.soc_id, soc_dev_attr.revision);
-       return 0;
+       return uid;
 }
 
-static int fsl_guts_remove(struct platform_device *dev)
-{
-       soc_device_unregister(soc_dev);
-       return 0;
-}
+static const struct fsl_soc_data ls1028a_data = {
+       .sfp_compat = "fsl,ls1028a-sfp",
+       .uid_offset = 0x21c,
+};
 
 /*
  * Table for matching compatible strings, for device tree
@@ -231,28 +174,106 @@ static const struct of_device_id fsl_guts_of_match[] = {
        { .compatible = "fsl,ls1012a-dcfg", },
        { .compatible = "fsl,ls1046a-dcfg", },
        { .compatible = "fsl,lx2160a-dcfg", },
-       { .compatible = "fsl,ls1028a-dcfg", },
+       { .compatible = "fsl,ls1028a-dcfg", .data = &ls1028a_data},
        {}
 };
-MODULE_DEVICE_TABLE(of, fsl_guts_of_match);
-
-static struct platform_driver fsl_guts_driver = {
-       .driver = {
-               .name = "fsl-guts",
-               .of_match_table = fsl_guts_of_match,
-       },
-       .probe = fsl_guts_probe,
-       .remove = fsl_guts_remove,
-};
 
 static int __init fsl_guts_init(void)
 {
-       return platform_driver_register(&fsl_guts_driver);
-}
-core_initcall(fsl_guts_init);
+       struct soc_device_attribute *soc_dev_attr;
+       static struct soc_device *soc_dev;
+       const struct fsl_soc_die_attr *soc_die;
+       const struct fsl_soc_data *soc_data;
+       const struct of_device_id *match;
+       struct ccsr_guts __iomem *regs;
+       const char *machine = NULL;
+       struct device_node *np;
+       bool little_endian;
+       u64 soc_uid = 0;
+       u32 svr;
+       int ret;
 
-static void __exit fsl_guts_exit(void)
-{
-       platform_driver_unregister(&fsl_guts_driver);
+       np = of_find_matching_node_and_match(NULL, fsl_guts_of_match, &match);
+       if (!np)
+               return 0;
+       soc_data = match->data;
+
+       regs = of_iomap(np, 0);
+       if (!regs) {
+               of_node_put(np);
+               return -ENOMEM;
+       }
+
+       little_endian = of_property_read_bool(np, "little-endian");
+       if (little_endian)
+               svr = ioread32(&regs->svr);
+       else
+               svr = ioread32be(&regs->svr);
+       iounmap(regs);
+       of_node_put(np);
+
+       /* Register soc device */
+       soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+       if (!soc_dev_attr)
+               return -ENOMEM;
+
+       if (of_property_read_string(of_root, "model", &machine))
+               of_property_read_string_index(of_root, "compatible", 0, &machine);
+       if (machine) {
+               soc_dev_attr->machine = kstrdup(machine, GFP_KERNEL);
+               if (!soc_dev_attr->machine)
+                       goto err_nomem;
+       }
+
+       soc_die = fsl_soc_die_match(svr, fsl_soc_die);
+       if (soc_die) {
+               soc_dev_attr->family = kasprintf(GFP_KERNEL, "QorIQ %s",
+                                                soc_die->die);
+       } else {
+               soc_dev_attr->family = kasprintf(GFP_KERNEL, "QorIQ");
+       }
+       if (!soc_dev_attr->family)
+               goto err_nomem;
+
+       soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "svr:0x%08x", svr);
+       if (!soc_dev_attr->soc_id)
+               goto err_nomem;
+
+       soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d.%d",
+                                          (svr >>  4) & 0xf, svr & 0xf);
+       if (!soc_dev_attr->revision)
+               goto err_nomem;
+
+       if (soc_data)
+               soc_uid = fsl_guts_get_soc_uid(soc_data->sfp_compat,
+                                              soc_data->uid_offset);
+       if (soc_uid)
+               soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX",
+                                                       soc_uid);
+
+       soc_dev = soc_device_register(soc_dev_attr);
+       if (IS_ERR(soc_dev)) {
+               ret = PTR_ERR(soc_dev);
+               goto err;
+       }
+
+       pr_info("Machine: %s\n", soc_dev_attr->machine);
+       pr_info("SoC family: %s\n", soc_dev_attr->family);
+       pr_info("SoC ID: %s, Revision: %s\n",
+               soc_dev_attr->soc_id, soc_dev_attr->revision);
+
+       return 0;
+
+err_nomem:
+       ret = -ENOMEM;
+err:
+       kfree(soc_dev_attr->machine);
+       kfree(soc_dev_attr->family);
+       kfree(soc_dev_attr->soc_id);
+       kfree(soc_dev_attr->revision);
+       kfree(soc_dev_attr->serial_number);
+       kfree(soc_dev_attr);
+
+       return ret;
 }
-module_exit(fsl_guts_exit);
+core_initcall(fsl_guts_init);
diff --git a/drivers/soc/fujitsu/Kconfig b/drivers/soc/fujitsu/Kconfig
new file mode 100644 (file)
index 0000000..987731e
--- /dev/null
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0-only
+menu "fujitsu SoC drivers"
+
+config A64FX_DIAG
+       bool "A64FX diag driver"
+       depends on ARM64
+       depends on ACPI
+       help
+         Say Y here if you want to enable diag interrupt on Fujitsu A64FX.
+         This driver enables BMC's diagnostic requests and enables
+         A64FX-specific interrupts. This allows administrators to obtain
+         kernel dumps via diagnostic requests using ipmitool, etc.
+
+         If unsure, say N.
+
+endmenu
diff --git a/drivers/soc/fujitsu/Makefile b/drivers/soc/fujitsu/Makefile
new file mode 100644 (file)
index 0000000..945bc1c
--- /dev/null
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_A64FX_DIAG)       += a64fx-diag.o
diff --git a/drivers/soc/fujitsu/a64fx-diag.c b/drivers/soc/fujitsu/a64fx-diag.c
new file mode 100644 (file)
index 0000000..d87f348
--- /dev/null
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * A64FX diag driver.
+ * Copyright (c) 2022 Fujitsu Ltd.
+ */
+
+#include <linux/acpi.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#define A64FX_DIAG_IRQ 1
+#define BMC_DIAG_INTERRUPT_ENABLE 0x40
+#define BMC_DIAG_INTERRUPT_STATUS 0x44
+#define BMC_DIAG_INTERRUPT_MASK BIT(31)
+
+struct a64fx_diag_priv {
+       void __iomem *mmsc_reg_base;
+       int irq;
+       bool has_nmi;
+};
+
+static irqreturn_t a64fx_diag_handler_nmi(int irq, void *dev_id)
+{
+       nmi_panic(NULL, "a64fx_diag: interrupt received\n");
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t a64fx_diag_handler_irq(int irq, void *dev_id)
+{
+       panic("a64fx_diag: interrupt received\n");
+
+       return IRQ_HANDLED;
+}
+
+static void a64fx_diag_interrupt_clear(struct a64fx_diag_priv *priv)
+{
+       void __iomem *diag_status_reg_addr;
+       u32 mmsc;
+
+       diag_status_reg_addr = priv->mmsc_reg_base + BMC_DIAG_INTERRUPT_STATUS;
+       mmsc = readl(diag_status_reg_addr);
+       if (mmsc & BMC_DIAG_INTERRUPT_MASK)
+               writel(BMC_DIAG_INTERRUPT_MASK, diag_status_reg_addr);
+}
+
+static void a64fx_diag_interrupt_enable(struct a64fx_diag_priv *priv)
+{
+       void __iomem *diag_enable_reg_addr;
+       u32 mmsc;
+
+       diag_enable_reg_addr = priv->mmsc_reg_base + BMC_DIAG_INTERRUPT_ENABLE;
+       mmsc = readl(diag_enable_reg_addr);
+       if (!(mmsc & BMC_DIAG_INTERRUPT_MASK)) {
+               mmsc |= BMC_DIAG_INTERRUPT_MASK;
+               writel(mmsc, diag_enable_reg_addr);
+       }
+}
+
+static void a64fx_diag_interrupt_disable(struct a64fx_diag_priv *priv)
+{
+       void __iomem *diag_enable_reg_addr;
+       u32 mmsc;
+
+       diag_enable_reg_addr = priv->mmsc_reg_base + BMC_DIAG_INTERRUPT_ENABLE;
+       mmsc = readl(diag_enable_reg_addr);
+       if (mmsc & BMC_DIAG_INTERRUPT_MASK) {
+               mmsc &= ~BMC_DIAG_INTERRUPT_MASK;
+               writel(mmsc, diag_enable_reg_addr);
+       }
+}
+
+static int a64fx_diag_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct a64fx_diag_priv *priv;
+       unsigned long irq_flags;
+       int ret;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (priv == NULL)
+               return -ENOMEM;
+
+       priv->mmsc_reg_base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(priv->mmsc_reg_base))
+               return PTR_ERR(priv->mmsc_reg_base);
+
+       priv->irq = platform_get_irq(pdev, A64FX_DIAG_IRQ);
+       if (priv->irq < 0)
+               return priv->irq;
+
+       platform_set_drvdata(pdev, priv);
+
+       irq_flags = IRQF_PERCPU | IRQF_NOBALANCING | IRQF_NO_AUTOEN |
+                  IRQF_NO_THREAD;
+       ret = request_nmi(priv->irq, &a64fx_diag_handler_nmi, irq_flags,
+                       "a64fx_diag_nmi", NULL);
+       if (ret) {
+               ret = request_irq(priv->irq, &a64fx_diag_handler_irq,
+                               irq_flags, "a64fx_diag_irq", NULL);
+               if (ret) {
+                       dev_err(dev, "cannot register IRQ %d\n", ret);
+                       return ret;
+               }
+               enable_irq(priv->irq);
+       } else {
+               enable_nmi(priv->irq);
+               priv->has_nmi = true;
+       }
+
+       a64fx_diag_interrupt_clear(priv);
+       a64fx_diag_interrupt_enable(priv);
+
+       return 0;
+}
+
+static int a64fx_diag_remove(struct platform_device *pdev)
+{
+       struct a64fx_diag_priv *priv = platform_get_drvdata(pdev);
+
+       a64fx_diag_interrupt_disable(priv);
+       a64fx_diag_interrupt_clear(priv);
+
+       if (priv->has_nmi)
+               free_nmi(priv->irq, NULL);
+       else
+               free_irq(priv->irq, NULL);
+
+       return 0;
+}
+
+static const struct acpi_device_id a64fx_diag_acpi_match[] = {
+       { "FUJI2007", 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(acpi, a64fx_diag_acpi_match);
+
+
+static struct platform_driver a64fx_diag_driver = {
+       .driver = {
+               .name = "a64fx_diag_driver",
+               .acpi_match_table = ACPI_PTR(a64fx_diag_acpi_match),
+       },
+       .probe = a64fx_diag_probe,
+       .remove = a64fx_diag_remove,
+};
+
+module_platform_driver(a64fx_diag_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Hitomi Hasegawa <hasegawa-hitomi@fujitsu.com>");
+MODULE_DESCRIPTION("A64FX diag driver");
index 85aa86e..6383a4e 100644 (file)
@@ -328,7 +328,9 @@ static int imx_pgc_power_up(struct generic_pm_domain *genpd)
        if (!IS_ERR(domain->regulator)) {
                ret = regulator_enable(domain->regulator);
                if (ret) {
-                       dev_err(domain->dev, "failed to enable regulator\n");
+                       dev_err(domain->dev,
+                               "failed to enable regulator: %pe\n",
+                               ERR_PTR(ret));
                        goto out_put_pm;
                }
        }
@@ -467,7 +469,9 @@ static int imx_pgc_power_down(struct generic_pm_domain *genpd)
        if (!IS_ERR(domain->regulator)) {
                ret = regulator_disable(domain->regulator);
                if (ret) {
-                       dev_err(domain->dev, "failed to disable regulator\n");
+                       dev_err(domain->dev,
+                               "failed to disable regulator: %pe\n",
+                               ERR_PTR(ret));
                        return ret;
                }
        }
index 7f49385..dff7529 100644 (file)
@@ -216,7 +216,7 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
        bc->bus_power_dev = genpd_dev_pm_attach_by_name(dev, "bus");
        if (IS_ERR(bc->bus_power_dev))
                return dev_err_probe(dev, PTR_ERR(bc->bus_power_dev),
-                                    "failed to attach power domain\n");
+                                    "failed to attach power domain \"bus\"\n");
 
        for (i = 0; i < bc_data->num_domains; i++) {
                const struct imx8m_blk_ctrl_domain_data *data = &bc_data->domains[i];
@@ -238,7 +238,8 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
                        dev_pm_domain_attach_by_name(dev, data->gpc_name);
                if (IS_ERR(domain->power_dev)) {
                        dev_err_probe(dev, PTR_ERR(domain->power_dev),
-                                     "failed to attach power domain\n");
+                                     "failed to attach power domain \"%s\"\n",
+                                     data->gpc_name);
                        ret = PTR_ERR(domain->power_dev);
                        goto cleanup_pds;
                }
@@ -251,7 +252,9 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
 
                ret = pm_genpd_init(&domain->genpd, NULL, true);
                if (ret) {
-                       dev_err_probe(dev, ret, "failed to init power domain\n");
+                       dev_err_probe(dev, ret,
+                                     "failed to init power domain \"%s\"\n",
+                                     data->gpc_name);
                        dev_pm_domain_detach(domain->power_dev, true);
                        goto cleanup_pds;
                }
@@ -667,7 +670,7 @@ static const struct imx8m_blk_ctrl_domain_data imx8mp_media_blk_ctl_domain_data[
        },
        [IMX8MP_MEDIABLK_PD_LCDIF_2] = {
                .name = "mediablk-lcdif-2",
-               .clk_names = (const char *[]){ "disp1", "apb", "axi", },
+               .clk_names = (const char *[]){ "disp2", "apb", "axi", },
                .num_clks = 3,
                .gpc_name = "lcdif2",
                .rst_mask = BIT(11) | BIT(12) | BIT(24),
index 613935c..58240e3 100644 (file)
@@ -758,7 +758,7 @@ static const struct of_device_id ixp4xx_npe_of_match[] = {
 static struct platform_driver ixp4xx_npe_driver = {
        .driver = {
                .name           = "ixp4xx-npe",
-               .of_match_table = of_match_ptr(ixp4xx_npe_of_match),
+               .of_match_table = ixp4xx_npe_of_match,
        },
        .probe = ixp4xx_npe_probe,
        .remove = ixp4xx_npe_remove,
index fdd8bc0..3c3eede 100644 (file)
@@ -73,4 +73,14 @@ config MTK_MMSYS
          Say yes here to add support for the MediaTek Multimedia
          Subsystem (MMSYS).
 
+config MTK_SVS
+       tristate "MediaTek Smart Voltage Scaling(SVS)"
+       depends on MTK_EFUSE && NVMEM
+       help
+         The Smart Voltage Scaling(SVS) engine is a piece of hardware
+         which has several controllers(banks) for calculating suitable
+         voltage to different power domains(CPU/GPU/CCI) according to
+         chip process corner, temperatures and other factors. Then DVFS
+         driver could apply SVS bank voltage to PMIC/Buck.
+
 endmenu
index 90270f8..0e9e703 100644 (file)
@@ -7,3 +7,4 @@ obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
 obj-$(CONFIG_MTK_SCPSYS_PM_DOMAINS) += mtk-pm-domains.o
 obj-$(CONFIG_MTK_MMSYS) += mtk-mmsys.o
 obj-$(CONFIG_MTK_MMSYS) += mtk-mutex.o
+obj-$(CONFIG_MTK_SVS) += mtk-svs.o
diff --git a/drivers/soc/mediatek/mt6795-pm-domains.h b/drivers/soc/mediatek/mt6795-pm-domains.h
new file mode 100644 (file)
index 0000000..ef07c9d
--- /dev/null
@@ -0,0 +1,112 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_MEDIATEK_MT6795_PM_DOMAINS_H
+#define __SOC_MEDIATEK_MT6795_PM_DOMAINS_H
+
+#include "mtk-pm-domains.h"
+#include <dt-bindings/power/mt6795-power.h>
+
+/*
+ * MT6795 power domain support
+ */
+
+static const struct scpsys_domain_data scpsys_domain_data_mt6795[] = {
+       [MT6795_POWER_DOMAIN_VDEC] = {
+               .name = "vdec",
+               .sta_mask = PWR_STATUS_VDEC,
+               .ctl_offs = SPM_VDE_PWR_CON,
+               .pwr_sta_offs = SPM_PWR_STATUS,
+               .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+               .sram_pdn_bits = GENMASK(11, 8),
+               .sram_pdn_ack_bits = GENMASK(12, 12),
+       },
+       [MT6795_POWER_DOMAIN_VENC] = {
+               .name = "venc",
+               .sta_mask = PWR_STATUS_VENC,
+               .ctl_offs = SPM_VEN_PWR_CON,
+               .pwr_sta_offs = SPM_PWR_STATUS,
+               .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+               .sram_pdn_bits = GENMASK(11, 8),
+               .sram_pdn_ack_bits = GENMASK(15, 12),
+       },
+       [MT6795_POWER_DOMAIN_ISP] = {
+               .name = "isp",
+               .sta_mask = PWR_STATUS_ISP,
+               .ctl_offs = SPM_ISP_PWR_CON,
+               .pwr_sta_offs = SPM_PWR_STATUS,
+               .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+               .sram_pdn_bits = GENMASK(11, 8),
+               .sram_pdn_ack_bits = GENMASK(13, 12),
+       },
+       [MT6795_POWER_DOMAIN_MM] = {
+               .name = "mm",
+               .sta_mask = PWR_STATUS_DISP,
+               .ctl_offs = SPM_DIS_PWR_CON,
+               .pwr_sta_offs = SPM_PWR_STATUS,
+               .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+               .sram_pdn_bits = GENMASK(11, 8),
+               .sram_pdn_ack_bits = GENMASK(12, 12),
+               .bp_infracfg = {
+                       BUS_PROT_UPDATE_TOPAXI(MT8173_TOP_AXI_PROT_EN_MM_M0 |
+                                              MT8173_TOP_AXI_PROT_EN_MM_M1),
+               },
+       },
+       [MT6795_POWER_DOMAIN_MJC] = {
+               .name = "mjc",
+               .sta_mask = BIT(20),
+               .ctl_offs = 0x298,
+               .pwr_sta_offs = SPM_PWR_STATUS,
+               .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+               .sram_pdn_bits = GENMASK(11, 8),
+               .sram_pdn_ack_bits = GENMASK(15, 12),
+       },
+       [MT6795_POWER_DOMAIN_AUDIO] = {
+               .name = "audio",
+               .sta_mask = PWR_STATUS_AUDIO,
+               .ctl_offs = SPM_AUDIO_PWR_CON,
+               .pwr_sta_offs = SPM_PWR_STATUS,
+               .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+               .sram_pdn_bits = GENMASK(11, 8),
+               .sram_pdn_ack_bits = GENMASK(15, 12),
+       },
+       [MT6795_POWER_DOMAIN_MFG_ASYNC] = {
+               .name = "mfg_async",
+               .sta_mask = PWR_STATUS_MFG_ASYNC,
+               .ctl_offs = SPM_MFG_ASYNC_PWR_CON,
+               .pwr_sta_offs = SPM_PWR_STATUS,
+               .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+               .sram_pdn_bits = GENMASK(11, 8),
+               .sram_pdn_ack_bits = 0,
+       },
+       [MT6795_POWER_DOMAIN_MFG_2D] = {
+               .name = "mfg_2d",
+               .sta_mask = PWR_STATUS_MFG_2D,
+               .ctl_offs = SPM_MFG_2D_PWR_CON,
+               .pwr_sta_offs = SPM_PWR_STATUS,
+               .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+               .sram_pdn_bits = GENMASK(11, 8),
+               .sram_pdn_ack_bits = GENMASK(13, 12),
+       },
+       [MT6795_POWER_DOMAIN_MFG] = {
+               .name = "mfg",
+               .sta_mask = PWR_STATUS_MFG,
+               .ctl_offs = SPM_MFG_PWR_CON,
+               .pwr_sta_offs = SPM_PWR_STATUS,
+               .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+               .sram_pdn_bits = GENMASK(13, 8),
+               .sram_pdn_ack_bits = GENMASK(21, 16),
+               .bp_infracfg = {
+                       BUS_PROT_UPDATE_TOPAXI(MT8173_TOP_AXI_PROT_EN_MFG_S |
+                                              MT8173_TOP_AXI_PROT_EN_MFG_M0 |
+                                              MT8173_TOP_AXI_PROT_EN_MFG_M1 |
+                                              MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT),
+               },
+       },
+};
+
+static const struct scpsys_soc_data mt6795_scpsys_data = {
+       .domains_data = scpsys_domain_data_mt6795,
+       .num_domains = ARRAY_SIZE(scpsys_domain_data_mt6795),
+};
+
+#endif /* __SOC_MEDIATEK_MT6795_PM_DOMAINS_H */
index 71b8757..99de67f 100644 (file)
@@ -41,6 +41,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
                .pwr_sta2nd_offs = 0x0184,
                .sram_pdn_bits = 0,
                .sram_pdn_ack_bits = 0,
+               .caps = MTK_SCPD_DOMAIN_SUPPLY,
        },
        [MT8183_POWER_DOMAIN_MFG] = {
                .name = "mfg",
index bf2dd0c..108af61 100644 (file)
@@ -51,7 +51,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8186[] = {
                                MT8186_TOP_AXI_PROT_EN_1_CLR,
                                MT8186_TOP_AXI_PROT_EN_1_STA),
                },
-               .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+               .caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_DOMAIN_SUPPLY,
        },
        [MT8186_POWER_DOMAIN_MFG2] = {
                .name = "mfg2",
index 558c4ee..b97b205 100644 (file)
@@ -58,6 +58,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
                .pwr_sta2nd_offs = 0x0170,
                .sram_pdn_bits = GENMASK(8, 8),
                .sram_pdn_ack_bits = GENMASK(12, 12),
+               .caps = MTK_SCPD_DOMAIN_SUPPLY,
        },
        [MT8192_POWER_DOMAIN_MFG1] = {
                .name = "mfg1",
@@ -85,6 +86,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
                                    MT8192_TOP_AXI_PROT_EN_2_CLR,
                                    MT8192_TOP_AXI_PROT_EN_2_STA1),
                },
+               .caps = MTK_SCPD_DOMAIN_SUPPLY,
        },
        [MT8192_POWER_DOMAIN_MFG2] = {
                .name = "mfg2",
index 938f4d5..d7387ea 100644 (file)
@@ -67,7 +67,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8195[] = {
                .ctl_offs = 0x334,
                .pwr_sta_offs = 0x174,
                .pwr_sta2nd_offs = 0x178,
-               .caps = MTK_SCPD_ACTIVE_WAKEUP,
+               .caps = MTK_SCPD_ACTIVE_WAKEUP | MTK_SCPD_ALWAYS_ON,
        },
        [MT8195_POWER_DOMAIN_CSI_RX_TOP] = {
                .name = "csi_rx_top",
@@ -162,7 +162,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8195[] = {
                                    MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_CLR,
                                    MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_STA1),
                },
-               .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+               .caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_DOMAIN_SUPPLY,
        },
        [MT8195_POWER_DOMAIN_MFG2] = {
                .name = "mfg2",
index 24129a6..7abaf04 100644 (file)
@@ -10,6 +10,9 @@
 #define MT8365_DISP_REG_CONFIG_DISP_RDMA0_RSZ0_SEL_IN  0xf60
 #define MT8365_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN      0xf64
 #define MT8365_DISP_REG_CONFIG_DISP_DSI0_SEL_IN                0xf68
+#define MT8365_DISP_REG_CONFIG_DISP_RDMA1_SOUT_SEL     0xfd0
+#define MT8365_DISP_REG_CONFIG_DISP_DPI0_SEL_IN                0xfd8
+#define MT8365_DISP_REG_CONFIG_DISP_LVDS_SYS_CFG_00    0xfdc
 
 #define MT8365_RDMA0_SOUT_COLOR0                       0x1
 #define MT8365_DITHER_MOUT_EN_DSI0                     0x1
 #define MT8365_RDMA0_RSZ0_SEL_IN_RDMA0                 0x0
 #define MT8365_DISP_COLOR_SEL_IN_COLOR0                        0x0
 #define MT8365_OVL0_MOUT_PATH0_SEL                     BIT(0)
+#define MT8365_RDMA1_SOUT_DPI0                         0x1
+#define MT8365_DPI0_SEL_IN_RDMA1                       0x0
+#define MT8365_LVDS_SYS_CFG_00_SEL_LVDS_PXL_CLK                0x1
+#define MT8365_DPI0_SEL_IN_RDMA1                       0x0
 
 static const struct mtk_mmsys_routes mt8365_mmsys_routing_table[] = {
        {
@@ -55,6 +62,21 @@ static const struct mtk_mmsys_routes mt8365_mmsys_routing_table[] = {
                MT8365_DISP_REG_CONFIG_DISP_RDMA0_RSZ0_SEL_IN,
                MT8365_RDMA0_RSZ0_SEL_IN_RDMA0, MT8365_RDMA0_RSZ0_SEL_IN_RDMA0
        },
+       {
+               DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0,
+               MT8365_DISP_REG_CONFIG_DISP_LVDS_SYS_CFG_00,
+               MT8365_LVDS_SYS_CFG_00_SEL_LVDS_PXL_CLK, MT8365_LVDS_SYS_CFG_00_SEL_LVDS_PXL_CLK
+       },
+       {
+               DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0,
+               MT8365_DISP_REG_CONFIG_DISP_DPI0_SEL_IN,
+               MT8365_DPI0_SEL_IN_RDMA1, MT8365_DPI0_SEL_IN_RDMA1
+       },
+       {
+               DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0,
+               MT8365_DISP_REG_CONFIG_DISP_RDMA1_SOUT_SEL,
+               MT8365_RDMA1_SOUT_DPI0, MT8365_RDMA1_SOUT_DPI0
+       },
 };
 
 #endif /* __SOC_MEDIATEK_MT8365_MMSYS_H */
index 7c65ad3..fc13334 100644 (file)
@@ -31,10 +31,7 @@ struct mtk_devapc_vio_dbgs {
        u32 vio_dbg1;
 };
 
-struct mtk_devapc_data {
-       /* numbers of violation index */
-       u32 vio_idx_num;
-
+struct mtk_devapc_regs_ofs {
        /* reg offset */
        u32 vio_mask_offset;
        u32 vio_sta_offset;
@@ -46,6 +43,12 @@ struct mtk_devapc_data {
        u32 vio_shift_con_offset;
 };
 
+struct mtk_devapc_data {
+       /* numbers of violation index */
+       u32 vio_idx_num;
+       const struct mtk_devapc_regs_ofs *regs_ofs;
+};
+
 struct mtk_devapc_context {
        struct device *dev;
        void __iomem *infra_base;
@@ -58,7 +61,7 @@ static void clear_vio_status(struct mtk_devapc_context *ctx)
        void __iomem *reg;
        int i;
 
-       reg = ctx->infra_base + ctx->data->vio_sta_offset;
+       reg = ctx->infra_base + ctx->data->regs_ofs->vio_sta_offset;
 
        for (i = 0; i < VIO_MOD_TO_REG_IND(ctx->data->vio_idx_num) - 1; i++)
                writel(GENMASK(31, 0), reg + 4 * i);
@@ -73,7 +76,7 @@ static void mask_module_irq(struct mtk_devapc_context *ctx, bool mask)
        u32 val;
        int i;
 
-       reg = ctx->infra_base + ctx->data->vio_mask_offset;
+       reg = ctx->infra_base + ctx->data->regs_ofs->vio_mask_offset;
 
        if (mask)
                val = GENMASK(31, 0);
@@ -116,11 +119,11 @@ static int devapc_sync_vio_dbg(struct mtk_devapc_context *ctx)
        u32 val;
 
        pd_vio_shift_sta_reg = ctx->infra_base +
-                              ctx->data->vio_shift_sta_offset;
+                              ctx->data->regs_ofs->vio_shift_sta_offset;
        pd_vio_shift_sel_reg = ctx->infra_base +
-                              ctx->data->vio_shift_sel_offset;
+                              ctx->data->regs_ofs->vio_shift_sel_offset;
        pd_vio_shift_con_reg = ctx->infra_base +
-                              ctx->data->vio_shift_con_offset;
+                              ctx->data->regs_ofs->vio_shift_con_offset;
 
        /* Find the minimum shift group which has violation */
        val = readl(pd_vio_shift_sta_reg);
@@ -161,8 +164,8 @@ static void devapc_extract_vio_dbg(struct mtk_devapc_context *ctx)
        void __iomem *vio_dbg0_reg;
        void __iomem *vio_dbg1_reg;
 
-       vio_dbg0_reg = ctx->infra_base + ctx->data->vio_dbg0_offset;
-       vio_dbg1_reg = ctx->infra_base + ctx->data->vio_dbg1_offset;
+       vio_dbg0_reg = ctx->infra_base + ctx->data->regs_ofs->vio_dbg0_offset;
+       vio_dbg1_reg = ctx->infra_base + ctx->data->regs_ofs->vio_dbg1_offset;
 
        vio_dbgs.vio_dbg0 = readl(vio_dbg0_reg);
        vio_dbgs.vio_dbg1 = readl(vio_dbg1_reg);
@@ -200,7 +203,7 @@ static irqreturn_t devapc_violation_irq(int irq_number, void *data)
  */
 static void start_devapc(struct mtk_devapc_context *ctx)
 {
-       writel(BIT(31), ctx->infra_base + ctx->data->apc_con_offset);
+       writel(BIT(31), ctx->infra_base + ctx->data->regs_ofs->apc_con_offset);
 
        mask_module_irq(ctx, false);
 }
@@ -212,11 +215,10 @@ static void stop_devapc(struct mtk_devapc_context *ctx)
 {
        mask_module_irq(ctx, true);
 
-       writel(BIT(2), ctx->infra_base + ctx->data->apc_con_offset);
+       writel(BIT(2), ctx->infra_base + ctx->data->regs_ofs->apc_con_offset);
 }
 
-static const struct mtk_devapc_data devapc_mt6779 = {
-       .vio_idx_num = 511,
+static const struct mtk_devapc_regs_ofs devapc_regs_ofs_mt6779 = {
        .vio_mask_offset = 0x0,
        .vio_sta_offset = 0x400,
        .vio_dbg0_offset = 0x900,
@@ -227,11 +229,24 @@ static const struct mtk_devapc_data devapc_mt6779 = {
        .vio_shift_con_offset = 0xF20,
 };
 
+static const struct mtk_devapc_data devapc_mt6779 = {
+       .vio_idx_num = 511,
+       .regs_ofs = &devapc_regs_ofs_mt6779,
+};
+
+static const struct mtk_devapc_data devapc_mt8186 = {
+       .vio_idx_num = 519,
+       .regs_ofs = &devapc_regs_ofs_mt6779,
+};
+
 static const struct of_device_id mtk_devapc_dt_match[] = {
        {
                .compatible = "mediatek,mt6779-devapc",
                .data = &devapc_mt6779,
        }, {
+               .compatible = "mediatek,mt8186-devapc",
+               .data = &devapc_mt8186,
+       }, {
        },
 };
 MODULE_DEVICE_TABLE(of, mtk_devapc_dt_match);
index 981d569..5ea43de 100644 (file)
@@ -7,10 +7,12 @@
 #include <linux/iopoll.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
+#include <linux/of_address.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/soc/mediatek/mtk-mmsys.h>
 #include <linux/soc/mediatek/mtk-mutex.h>
+#include <linux/soc/mediatek/mtk-cmdq.h>
 
 #define MT2701_MUTEX0_MOD0                     0x2c
 #define MT2701_MUTEX0_SOF0                     0x30
 #define MT8183_MUTEX_MOD_DISP_GAMMA0           16
 #define MT8183_MUTEX_MOD_DISP_DITHER0          17
 
+#define MT8183_MUTEX_MOD_MDP_RDMA0             2
+#define MT8183_MUTEX_MOD_MDP_RSZ0              4
+#define MT8183_MUTEX_MOD_MDP_RSZ1              5
+#define MT8183_MUTEX_MOD_MDP_TDSHP0            6
+#define MT8183_MUTEX_MOD_MDP_WROT0             7
+#define MT8183_MUTEX_MOD_MDP_WDMA              8
+#define MT8183_MUTEX_MOD_MDP_AAL0              23
+#define MT8183_MUTEX_MOD_MDP_CCORR0            24
+
 #define MT8173_MUTEX_MOD_DISP_OVL0             11
 #define MT8173_MUTEX_MOD_DISP_OVL1             12
 #define MT8173_MUTEX_MOD_DISP_RDMA0            13
 #define MT8195_MUTEX_MOD_DISP_DP_INTF0         21
 #define MT8195_MUTEX_MOD_DISP_PWM0             27
 
+#define MT8365_MUTEX_MOD_DISP_OVL0             7
+#define MT8365_MUTEX_MOD_DISP_OVL0_2L          8
+#define MT8365_MUTEX_MOD_DISP_RDMA0            9
+#define MT8365_MUTEX_MOD_DISP_RDMA1            10
+#define MT8365_MUTEX_MOD_DISP_WDMA0            11
+#define MT8365_MUTEX_MOD_DISP_COLOR0           12
+#define MT8365_MUTEX_MOD_DISP_CCORR            13
+#define MT8365_MUTEX_MOD_DISP_AAL              14
+#define MT8365_MUTEX_MOD_DISP_GAMMA            15
+#define MT8365_MUTEX_MOD_DISP_DITHER           16
+#define MT8365_MUTEX_MOD_DISP_DSI0             17
+#define MT8365_MUTEX_MOD_DISP_PWM0             20
+#define MT8365_MUTEX_MOD_DISP_DPI0             22
+
 #define MT2712_MUTEX_MOD_DISP_PWM2             10
 #define MT2712_MUTEX_MOD_DISP_OVL0             11
 #define MT2712_MUTEX_MOD_DISP_OVL1             12
@@ -185,6 +210,7 @@ struct mtk_mutex_data {
        const unsigned int *mutex_sof;
        const unsigned int mutex_mod_reg;
        const unsigned int mutex_sof_reg;
+       const unsigned int *mutex_table_mod;
        const bool no_clk;
 };
 
@@ -194,6 +220,8 @@ struct mtk_mutex_ctx {
        void __iomem                    *regs;
        struct mtk_mutex                mutex[10];
        const struct mtk_mutex_data     *data;
+       phys_addr_t                     addr;
+       struct cmdq_client_reg          cmdq_reg;
 };
 
 static const unsigned int mt2701_mutex_mod[DDP_COMPONENT_ID_MAX] = {
@@ -272,6 +300,17 @@ static const unsigned int mt8183_mutex_mod[DDP_COMPONENT_ID_MAX] = {
        [DDP_COMPONENT_WDMA0] = MT8183_MUTEX_MOD_DISP_WDMA0,
 };
 
+static const unsigned int mt8183_mutex_table_mod[MUTEX_MOD_IDX_MAX] = {
+       [MUTEX_MOD_IDX_MDP_RDMA0] = MT8183_MUTEX_MOD_MDP_RDMA0,
+       [MUTEX_MOD_IDX_MDP_RSZ0] = MT8183_MUTEX_MOD_MDP_RSZ0,
+       [MUTEX_MOD_IDX_MDP_RSZ1] = MT8183_MUTEX_MOD_MDP_RSZ1,
+       [MUTEX_MOD_IDX_MDP_TDSHP0] = MT8183_MUTEX_MOD_MDP_TDSHP0,
+       [MUTEX_MOD_IDX_MDP_WROT0] = MT8183_MUTEX_MOD_MDP_WROT0,
+       [MUTEX_MOD_IDX_MDP_WDMA] = MT8183_MUTEX_MOD_MDP_WDMA,
+       [MUTEX_MOD_IDX_MDP_AAL0] = MT8183_MUTEX_MOD_MDP_AAL0,
+       [MUTEX_MOD_IDX_MDP_CCORR0] = MT8183_MUTEX_MOD_MDP_CCORR0,
+};
+
 static const unsigned int mt8186_mutex_mod[DDP_COMPONENT_ID_MAX] = {
        [DDP_COMPONENT_AAL0] = MT8186_MUTEX_MOD_DISP_AAL0,
        [DDP_COMPONENT_CCORR] = MT8186_MUTEX_MOD_DISP_CCORR0,
@@ -315,6 +354,22 @@ static const unsigned int mt8195_mutex_mod[DDP_COMPONENT_ID_MAX] = {
        [DDP_COMPONENT_DP_INTF0] = MT8195_MUTEX_MOD_DISP_DP_INTF0,
 };
 
+static const unsigned int mt8365_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+       [DDP_COMPONENT_AAL0] = MT8365_MUTEX_MOD_DISP_AAL,
+       [DDP_COMPONENT_CCORR] = MT8365_MUTEX_MOD_DISP_CCORR,
+       [DDP_COMPONENT_COLOR0] = MT8365_MUTEX_MOD_DISP_COLOR0,
+       [DDP_COMPONENT_DITHER0] = MT8365_MUTEX_MOD_DISP_DITHER,
+       [DDP_COMPONENT_DPI0] = MT8365_MUTEX_MOD_DISP_DPI0,
+       [DDP_COMPONENT_DSI0] = MT8365_MUTEX_MOD_DISP_DSI0,
+       [DDP_COMPONENT_GAMMA] = MT8365_MUTEX_MOD_DISP_GAMMA,
+       [DDP_COMPONENT_OVL0] = MT8365_MUTEX_MOD_DISP_OVL0,
+       [DDP_COMPONENT_OVL_2L0] = MT8365_MUTEX_MOD_DISP_OVL0_2L,
+       [DDP_COMPONENT_PWM0] = MT8365_MUTEX_MOD_DISP_PWM0,
+       [DDP_COMPONENT_RDMA0] = MT8365_MUTEX_MOD_DISP_RDMA0,
+       [DDP_COMPONENT_RDMA1] = MT8365_MUTEX_MOD_DISP_RDMA1,
+       [DDP_COMPONENT_WDMA0] = MT8365_MUTEX_MOD_DISP_WDMA0,
+};
+
 static const unsigned int mt2712_mutex_sof[DDP_MUTEX_SOF_MAX] = {
        [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
        [MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0,
@@ -399,6 +454,7 @@ static const struct mtk_mutex_data mt8183_mutex_driver_data = {
        .mutex_sof = mt8183_mutex_sof,
        .mutex_mod_reg = MT8183_MUTEX0_MOD0,
        .mutex_sof_reg = MT8183_MUTEX0_SOF0,
+       .mutex_table_mod = mt8183_mutex_table_mod,
        .no_clk = true,
 };
 
@@ -423,6 +479,14 @@ static const struct mtk_mutex_data mt8195_mutex_driver_data = {
        .mutex_sof_reg = MT8183_MUTEX0_SOF0,
 };
 
+static const struct mtk_mutex_data mt8365_mutex_driver_data = {
+       .mutex_mod = mt8365_mutex_mod,
+       .mutex_sof = mt8183_mutex_sof,
+       .mutex_mod_reg = MT8183_MUTEX0_MOD0,
+       .mutex_sof_reg = MT8183_MUTEX0_SOF0,
+       .no_clk = true,
+};
+
 struct mtk_mutex *mtk_mutex_get(struct device *dev)
 {
        struct mtk_mutex_ctx *mtx = dev_get_drvdata(dev);
@@ -572,6 +636,30 @@ void mtk_mutex_enable(struct mtk_mutex *mutex)
 }
 EXPORT_SYMBOL_GPL(mtk_mutex_enable);
 
+int mtk_mutex_enable_by_cmdq(struct mtk_mutex *mutex, void *pkt)
+{
+       struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
+                                                mutex[mutex->id]);
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+       struct cmdq_pkt *cmdq_pkt = (struct cmdq_pkt *)pkt;
+
+       WARN_ON(&mtx->mutex[mutex->id] != mutex);
+
+       if (!mtx->cmdq_reg.size) {
+               dev_err(mtx->dev, "mediatek,gce-client-reg hasn't been set");
+               return -EINVAL;
+       }
+
+       cmdq_pkt_write(cmdq_pkt, mtx->cmdq_reg.subsys,
+                      mtx->addr + DISP_REG_MUTEX_EN(mutex->id), 1);
+       return 0;
+#else
+       dev_err(mtx->dev, "Not support for enable MUTEX by CMDQ");
+       return -ENODEV;
+#endif
+}
+EXPORT_SYMBOL_GPL(mtk_mutex_enable_by_cmdq);
+
 void mtk_mutex_disable(struct mtk_mutex *mutex)
 {
        struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
@@ -606,12 +694,67 @@ void mtk_mutex_release(struct mtk_mutex *mutex)
 }
 EXPORT_SYMBOL_GPL(mtk_mutex_release);
 
+int mtk_mutex_write_mod(struct mtk_mutex *mutex,
+                       enum mtk_mutex_mod_index idx, bool clear)
+{
+       struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
+                                                mutex[mutex->id]);
+       unsigned int reg;
+       unsigned int offset;
+
+       WARN_ON(&mtx->mutex[mutex->id] != mutex);
+
+       if (idx < MUTEX_MOD_IDX_MDP_RDMA0 ||
+           idx >= MUTEX_MOD_IDX_MAX) {
+               dev_err(mtx->dev, "Not supported MOD table index : %d", idx);
+               return -EINVAL;
+       }
+
+       offset = DISP_REG_MUTEX_MOD(mtx->data->mutex_mod_reg,
+                                   mutex->id);
+       reg = readl_relaxed(mtx->regs + offset);
+
+       if (clear)
+               reg &= ~BIT(mtx->data->mutex_table_mod[idx]);
+       else
+               reg |= BIT(mtx->data->mutex_table_mod[idx]);
+
+       writel_relaxed(reg, mtx->regs + offset);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_mutex_write_mod);
+
+int mtk_mutex_write_sof(struct mtk_mutex *mutex,
+                       enum mtk_mutex_sof_index idx)
+{
+       struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
+                                                mutex[mutex->id]);
+
+       WARN_ON(&mtx->mutex[mutex->id] != mutex);
+
+       if (idx < MUTEX_SOF_IDX_SINGLE_MODE ||
+           idx >= MUTEX_SOF_IDX_MAX) {
+               dev_err(mtx->dev, "Not supported SOF index : %d", idx);
+               return -EINVAL;
+       }
+
+       writel_relaxed(idx, mtx->regs +
+                      DISP_REG_MUTEX_SOF(mtx->data->mutex_sof_reg, mutex->id));
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_mutex_write_sof);
+
 static int mtk_mutex_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct mtk_mutex_ctx *mtx;
        struct resource *regs;
        int i;
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+       int ret;
+#endif
 
        mtx = devm_kzalloc(dev, sizeof(*mtx), GFP_KERNEL);
        if (!mtx)
@@ -631,12 +774,18 @@ static int mtk_mutex_probe(struct platform_device *pdev)
                }
        }
 
-       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       mtx->regs = devm_ioremap_resource(dev, regs);
+       mtx->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &regs);
        if (IS_ERR(mtx->regs)) {
                dev_err(dev, "Failed to map mutex registers\n");
                return PTR_ERR(mtx->regs);
        }
+       mtx->addr = regs->start;
+
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+       ret = cmdq_dev_get_client_reg(dev, &mtx->cmdq_reg, 0);
+       if (ret)
+               dev_dbg(dev, "No mediatek,gce-client-reg!\n");
+#endif
 
        platform_set_drvdata(pdev, mtx);
 
@@ -665,6 +814,8 @@ static const struct of_device_id mutex_driver_dt_match[] = {
          .data = &mt8192_mutex_driver_data},
        { .compatible = "mediatek,mt8195-disp-mutex",
          .data = &mt8195_mutex_driver_data},
+       { .compatible = "mediatek,mt8365-disp-mutex",
+         .data = &mt8365_mutex_driver_data},
        {},
 };
 MODULE_DEVICE_TABLE(of, mutex_driver_dt_match);
index 5ced254..9734f10 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/soc/mediatek/infracfg.h>
 
+#include "mt6795-pm-domains.h"
 #include "mt8167-pm-domains.h"
 #include "mt8173-pm-domains.h"
 #include "mt8183-pm-domains.h"
@@ -428,6 +429,9 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no
                        dev_err(scpsys->dev, "%pOF: failed to power on domain: %d\n", node, ret);
                        goto err_put_subsys_clocks;
                }
+
+               if (MTK_SCPD_CAPS(pd, MTK_SCPD_ALWAYS_ON))
+                       pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
        }
 
        if (scpsys->domains[id]) {
@@ -556,6 +560,10 @@ static void scpsys_domain_cleanup(struct scpsys *scpsys)
 
 static const struct of_device_id scpsys_of_match[] = {
        {
+               .compatible = "mediatek,mt6795-power-controller",
+               .data = &mt6795_scpsys_data,
+       },
+       {
                .compatible = "mediatek,mt8167-power-controller",
                .data = &mt8167_scpsys_data,
        },
index daa24e8..7d3c0c3 100644 (file)
@@ -8,6 +8,8 @@
 #define MTK_SCPD_SRAM_ISO              BIT(2)
 #define MTK_SCPD_KEEP_DEFAULT_OFF      BIT(3)
 #define MTK_SCPD_DOMAIN_SUPPLY         BIT(4)
+/* can't set MTK_SCPD_KEEP_DEFAULT_OFF at the same time */
+#define MTK_SCPD_ALWAYS_ON             BIT(5)
 #define MTK_SCPD_CAPS(_scpd, _x)       ((_scpd)->data->caps & (_x))
 
 #define SPM_VDE_PWR_CON                        0x0210
index bf39a64..d8cb0f8 100644 (file)
@@ -13,6 +13,9 @@
 #include <linux/regmap.h>
 #include <linux/reset.h>
 
+#define PWRAP_POLL_DELAY_US    10
+#define PWRAP_POLL_TIMEOUT_US  10000
+
 #define PWRAP_MT8135_BRIDGE_IORD_ARB_EN                0x4
 #define PWRAP_MT8135_BRIDGE_WACS3_EN           0x10
 #define PWRAP_MT8135_BRIDGE_INIT_DONE3         0x14
@@ -1140,12 +1143,9 @@ enum pwrap_type {
 };
 
 struct pmic_wrapper;
-struct pwrap_slv_type {
-       const u32 *dew_regs;
-       enum pmic_type type;
+
+struct pwrap_slv_regops {
        const struct regmap_config *regmap;
-       /* Flags indicating the capability for the target slave */
-       u32 caps;
        /*
         * pwrap operations are highly associated with the PMIC types,
         * so the pointers added increases flexibility allowing determination
@@ -1155,6 +1155,14 @@ struct pwrap_slv_type {
        int (*pwrap_write)(struct pmic_wrapper *wrp, u32 adr, u32 wdata);
 };
 
+struct pwrap_slv_type {
+       const u32 *dew_regs;
+       enum pmic_type type;
+       const struct pwrap_slv_regops *regops;
+       /* Flags indicating the capability for the target slave */
+       u32 caps;
+};
+
 struct pmic_wrapper {
        struct device *dev;
        void __iomem *base;
@@ -1241,27 +1249,14 @@ static bool pwrap_is_fsm_idle_and_sync_idle(struct pmic_wrapper *wrp)
                (val & PWRAP_STATE_SYNC_IDLE0);
 }
 
-static int pwrap_wait_for_state(struct pmic_wrapper *wrp,
-               bool (*fp)(struct pmic_wrapper *))
-{
-       unsigned long timeout;
-
-       timeout = jiffies + usecs_to_jiffies(10000);
-
-       do {
-               if (time_after(jiffies, timeout))
-                       return fp(wrp) ? 0 : -ETIMEDOUT;
-               if (fp(wrp))
-                       return 0;
-       } while (1);
-}
-
 static int pwrap_read16(struct pmic_wrapper *wrp, u32 adr, u32 *rdata)
 {
+       bool tmp;
        int ret;
        u32 val;
 
-       ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle);
+       ret = readx_poll_timeout(pwrap_is_fsm_idle, wrp, tmp, tmp,
+                                PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
        if (ret) {
                pwrap_leave_fsm_vldclr(wrp);
                return ret;
@@ -1273,7 +1268,8 @@ static int pwrap_read16(struct pmic_wrapper *wrp, u32 adr, u32 *rdata)
                val = (adr >> 1) << 16;
        pwrap_writel(wrp, val, PWRAP_WACS2_CMD);
 
-       ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_vldclr);
+       ret = readx_poll_timeout(pwrap_is_fsm_vldclr, wrp, tmp, tmp,
+                                PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
        if (ret)
                return ret;
 
@@ -1290,11 +1286,14 @@ static int pwrap_read16(struct pmic_wrapper *wrp, u32 adr, u32 *rdata)
 
 static int pwrap_read32(struct pmic_wrapper *wrp, u32 adr, u32 *rdata)
 {
+       bool tmp;
        int ret, msb;
 
        *rdata = 0;
        for (msb = 0; msb < 2; msb++) {
-               ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle);
+               ret = readx_poll_timeout(pwrap_is_fsm_idle, wrp, tmp, tmp,
+                                        PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
+
                if (ret) {
                        pwrap_leave_fsm_vldclr(wrp);
                        return ret;
@@ -1303,7 +1302,8 @@ static int pwrap_read32(struct pmic_wrapper *wrp, u32 adr, u32 *rdata)
                pwrap_writel(wrp, ((msb << 30) | (adr << 16)),
                             PWRAP_WACS2_CMD);
 
-               ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_vldclr);
+               ret = readx_poll_timeout(pwrap_is_fsm_vldclr, wrp, tmp, tmp,
+                                        PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
                if (ret)
                        return ret;
 
@@ -1318,14 +1318,16 @@ static int pwrap_read32(struct pmic_wrapper *wrp, u32 adr, u32 *rdata)
 
 static int pwrap_read(struct pmic_wrapper *wrp, u32 adr, u32 *rdata)
 {
-       return wrp->slave->pwrap_read(wrp, adr, rdata);
+       return wrp->slave->regops->pwrap_read(wrp, adr, rdata);
 }
 
 static int pwrap_write16(struct pmic_wrapper *wrp, u32 adr, u32 wdata)
 {
+       bool tmp;
        int ret;
 
-       ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle);
+       ret = readx_poll_timeout(pwrap_is_fsm_idle, wrp, tmp, tmp,
+                                PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
        if (ret) {
                pwrap_leave_fsm_vldclr(wrp);
                return ret;
@@ -1344,10 +1346,12 @@ static int pwrap_write16(struct pmic_wrapper *wrp, u32 adr, u32 wdata)
 
 static int pwrap_write32(struct pmic_wrapper *wrp, u32 adr, u32 wdata)
 {
+       bool tmp;
        int ret, msb, rdata;
 
        for (msb = 0; msb < 2; msb++) {
-               ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle);
+               ret = readx_poll_timeout(pwrap_is_fsm_idle, wrp, tmp, tmp,
+                                        PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
                if (ret) {
                        pwrap_leave_fsm_vldclr(wrp);
                        return ret;
@@ -1373,7 +1377,7 @@ static int pwrap_write32(struct pmic_wrapper *wrp, u32 adr, u32 wdata)
 
 static int pwrap_write(struct pmic_wrapper *wrp, u32 adr, u32 wdata)
 {
-       return wrp->slave->pwrap_write(wrp, adr, wdata);
+       return wrp->slave->regops->pwrap_write(wrp, adr, wdata);
 }
 
 static int pwrap_regmap_read(void *context, u32 adr, u32 *rdata)
@@ -1388,6 +1392,7 @@ static int pwrap_regmap_write(void *context, u32 adr, u32 wdata)
 
 static int pwrap_reset_spislave(struct pmic_wrapper *wrp)
 {
+       bool tmp;
        int ret, i;
 
        pwrap_writel(wrp, 0, PWRAP_HIPRIO_ARB_EN);
@@ -1407,7 +1412,8 @@ static int pwrap_reset_spislave(struct pmic_wrapper *wrp)
                pwrap_writel(wrp, wrp->master->spi_w | PWRAP_MAN_CMD_OP_OUTS,
                                PWRAP_MAN_CMD);
 
-       ret = pwrap_wait_for_state(wrp, pwrap_is_sync_idle);
+       ret = readx_poll_timeout(pwrap_is_sync_idle, wrp, tmp, tmp,
+                                PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
        if (ret) {
                dev_err(wrp->dev, "%s fail, ret=%d\n", __func__, ret);
                return ret;
@@ -1458,14 +1464,15 @@ static int pwrap_init_sidly(struct pmic_wrapper *wrp)
 static int pwrap_init_dual_io(struct pmic_wrapper *wrp)
 {
        int ret;
+       bool tmp;
        u32 rdata;
 
        /* Enable dual IO mode */
        pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_DIO_EN], 1);
 
        /* Check IDLE & INIT_DONE in advance */
-       ret = pwrap_wait_for_state(wrp,
-                                  pwrap_is_fsm_idle_and_sync_idle);
+       ret = readx_poll_timeout(pwrap_is_fsm_idle_and_sync_idle, wrp, tmp, tmp,
+                                PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
        if (ret) {
                dev_err(wrp->dev, "%s fail, ret=%d\n", __func__, ret);
                return ret;
@@ -1570,6 +1577,7 @@ static bool pwrap_is_pmic_cipher_ready(struct pmic_wrapper *wrp)
 static int pwrap_init_cipher(struct pmic_wrapper *wrp)
 {
        int ret;
+       bool tmp;
        u32 rdata = 0;
 
        pwrap_writel(wrp, 0x1, PWRAP_CIPHER_SWRST);
@@ -1624,14 +1632,16 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
        }
 
        /* wait for cipher data ready@AP */
-       ret = pwrap_wait_for_state(wrp, pwrap_is_cipher_ready);
+       ret = readx_poll_timeout(pwrap_is_cipher_ready, wrp, tmp, tmp,
+                                PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
        if (ret) {
                dev_err(wrp->dev, "cipher data ready@AP fail, ret=%d\n", ret);
                return ret;
        }
 
        /* wait for cipher data ready@PMIC */
-       ret = pwrap_wait_for_state(wrp, pwrap_is_pmic_cipher_ready);
+       ret = readx_poll_timeout(pwrap_is_pmic_cipher_ready, wrp, tmp, tmp,
+                                PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
        if (ret) {
                dev_err(wrp->dev,
                        "timeout waiting for cipher data ready@PMIC\n");
@@ -1640,7 +1650,8 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
 
        /* wait for cipher mode idle */
        pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_MODE], 0x1);
-       ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle_and_sync_idle);
+       ret = readx_poll_timeout(pwrap_is_fsm_idle_and_sync_idle, wrp, tmp, tmp,
+                                PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
        if (ret) {
                dev_err(wrp->dev, "cipher mode idle fail, ret=%d\n", ret);
                return ret;
@@ -1885,99 +1896,82 @@ static const struct regmap_config pwrap_regmap_config32 = {
        .max_register = 0xffff,
 };
 
+static const struct pwrap_slv_regops pwrap_regops16 = {
+       .pwrap_read = pwrap_read16,
+       .pwrap_write = pwrap_write16,
+       .regmap = &pwrap_regmap_config16,
+};
+
+static const struct pwrap_slv_regops pwrap_regops32 = {
+       .pwrap_read = pwrap_read32,
+       .pwrap_write = pwrap_write32,
+       .regmap = &pwrap_regmap_config32,
+};
+
 static const struct pwrap_slv_type pmic_mt6323 = {
        .dew_regs = mt6323_regs,
        .type = PMIC_MT6323,
-       .regmap = &pwrap_regmap_config16,
+       .regops = &pwrap_regops16,
        .caps = PWRAP_SLV_CAP_SPI | PWRAP_SLV_CAP_DUALIO |
                PWRAP_SLV_CAP_SECURITY,
-       .pwrap_read = pwrap_read16,
-       .pwrap_write = pwrap_write16,
 };
 
 static const struct pwrap_slv_type pmic_mt6351 = {
        .dew_regs = mt6351_regs,
        .type = PMIC_MT6351,
-       .regmap = &pwrap_regmap_config16,
+       .regops = &pwrap_regops16,
        .caps = 0,
-       .pwrap_read = pwrap_read16,
-       .pwrap_write = pwrap_write16,
 };
 
 static const struct pwrap_slv_type pmic_mt6357 = {
        .dew_regs = mt6357_regs,
        .type = PMIC_MT6357,
-       .regmap = &pwrap_regmap_config16,
+       .regops = &pwrap_regops16,
        .caps = 0,
-       .pwrap_read = pwrap_read16,
-       .pwrap_write = pwrap_write16,
 };
 
 static const struct pwrap_slv_type pmic_mt6358 = {
        .dew_regs = mt6358_regs,
        .type = PMIC_MT6358,
-       .regmap = &pwrap_regmap_config16,
+       .regops = &pwrap_regops16,
        .caps = PWRAP_SLV_CAP_SPI | PWRAP_SLV_CAP_DUALIO,
-       .pwrap_read = pwrap_read16,
-       .pwrap_write = pwrap_write16,
 };
 
 static const struct pwrap_slv_type pmic_mt6359 = {
        .dew_regs = mt6359_regs,
        .type = PMIC_MT6359,
-       .regmap = &pwrap_regmap_config16,
+       .regops = &pwrap_regops16,
        .caps = PWRAP_SLV_CAP_DUALIO,
-       .pwrap_read = pwrap_read16,
-       .pwrap_write = pwrap_write16,
 };
 
 static const struct pwrap_slv_type pmic_mt6380 = {
        .dew_regs = NULL,
        .type = PMIC_MT6380,
-       .regmap = &pwrap_regmap_config32,
+       .regops = &pwrap_regops32,
        .caps = 0,
-       .pwrap_read = pwrap_read32,
-       .pwrap_write = pwrap_write32,
 };
 
 static const struct pwrap_slv_type pmic_mt6397 = {
        .dew_regs = mt6397_regs,
        .type = PMIC_MT6397,
-       .regmap = &pwrap_regmap_config16,
+       .regops = &pwrap_regops16,
        .caps = PWRAP_SLV_CAP_SPI | PWRAP_SLV_CAP_DUALIO |
                PWRAP_SLV_CAP_SECURITY,
-       .pwrap_read = pwrap_read16,
-       .pwrap_write = pwrap_write16,
 };
 
 static const struct of_device_id of_slave_match_tbl[] = {
-       {
-               .compatible = "mediatek,mt6323",
-               .data = &pmic_mt6323,
-       }, {
-               .compatible = "mediatek,mt6351",
-               .data = &pmic_mt6351,
-       }, {
-               .compatible = "mediatek,mt6357",
-               .data = &pmic_mt6357,
-       }, {
-               .compatible = "mediatek,mt6358",
-               .data = &pmic_mt6358,
-       }, {
-               .compatible = "mediatek,mt6359",
-               .data = &pmic_mt6359,
-       }, {
-               /* The MT6380 PMIC only implements a regulator, so we bind it
-                * directly instead of using a MFD.
-                */
-               .compatible = "mediatek,mt6380-regulator",
-               .data = &pmic_mt6380,
-       }, {
-               .compatible = "mediatek,mt6397",
-               .data = &pmic_mt6397,
-       }, {
-               /* sentinel */
-       }
+       { .compatible = "mediatek,mt6323", .data = &pmic_mt6323 },
+       { .compatible = "mediatek,mt6351", .data = &pmic_mt6351 },
+       { .compatible = "mediatek,mt6357", .data = &pmic_mt6357 },
+       { .compatible = "mediatek,mt6358", .data = &pmic_mt6358 },
+       { .compatible = "mediatek,mt6359", .data = &pmic_mt6359 },
+
+       /* The MT6380 PMIC only implements a regulator, so we bind it
+        * directly instead of using a MFD.
+        */
+       { .compatible = "mediatek,mt6380-regulator", .data = &pmic_mt6380 },
+       { .compatible = "mediatek,mt6397", .data = &pmic_mt6397 },
+       { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, of_slave_match_tbl);
 
@@ -2136,45 +2130,19 @@ static struct pmic_wrapper_type pwrap_mt8186 = {
 };
 
 static const struct of_device_id of_pwrap_match_tbl[] = {
-       {
-               .compatible = "mediatek,mt2701-pwrap",
-               .data = &pwrap_mt2701,
-       }, {
-               .compatible = "mediatek,mt6765-pwrap",
-               .data = &pwrap_mt6765,
-       }, {
-               .compatible = "mediatek,mt6779-pwrap",
-               .data = &pwrap_mt6779,
-       }, {
-               .compatible = "mediatek,mt6797-pwrap",
-               .data = &pwrap_mt6797,
-       }, {
-               .compatible = "mediatek,mt6873-pwrap",
-               .data = &pwrap_mt6873,
-       }, {
-               .compatible = "mediatek,mt7622-pwrap",
-               .data = &pwrap_mt7622,
-       }, {
-               .compatible = "mediatek,mt8135-pwrap",
-               .data = &pwrap_mt8135,
-       }, {
-               .compatible = "mediatek,mt8173-pwrap",
-               .data = &pwrap_mt8173,
-       }, {
-               .compatible = "mediatek,mt8183-pwrap",
-               .data = &pwrap_mt8183,
-       }, {
-               .compatible = "mediatek,mt8186-pwrap",
-               .data = &pwrap_mt8186,
-       }, {
-               .compatible = "mediatek,mt8195-pwrap",
-               .data = &pwrap_mt8195,
-       }, {
-               .compatible = "mediatek,mt8516-pwrap",
-               .data = &pwrap_mt8516,
-       }, {
-               /* sentinel */
-       }
+       { .compatible = "mediatek,mt2701-pwrap", .data = &pwrap_mt2701 },
+       { .compatible = "mediatek,mt6765-pwrap", .data = &pwrap_mt6765 },
+       { .compatible = "mediatek,mt6779-pwrap", .data = &pwrap_mt6779 },
+       { .compatible = "mediatek,mt6797-pwrap", .data = &pwrap_mt6797 },
+       { .compatible = "mediatek,mt6873-pwrap", .data = &pwrap_mt6873 },
+       { .compatible = "mediatek,mt7622-pwrap", .data = &pwrap_mt7622 },
+       { .compatible = "mediatek,mt8135-pwrap", .data = &pwrap_mt8135 },
+       { .compatible = "mediatek,mt8173-pwrap", .data = &pwrap_mt8173 },
+       { .compatible = "mediatek,mt8183-pwrap", .data = &pwrap_mt8183 },
+       { .compatible = "mediatek,mt8186-pwrap", .data = &pwrap_mt8186 },
+       { .compatible = "mediatek,mt8195-pwrap", .data = &pwrap_mt8195 },
+       { .compatible = "mediatek,mt8516-pwrap", .data = &pwrap_mt8516 },
+       { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, of_pwrap_match_tbl);
 
@@ -2185,7 +2153,6 @@ static int pwrap_probe(struct platform_device *pdev)
        struct pmic_wrapper *wrp;
        struct device_node *np = pdev->dev.of_node;
        const struct of_device_id *of_slave_id = NULL;
-       struct resource *res;
 
        if (np->child)
                of_slave_id = of_match_node(of_slave_match_tbl, np->child);
@@ -2205,8 +2172,7 @@ static int pwrap_probe(struct platform_device *pdev)
        wrp->slave = of_slave_id->data;
        wrp->dev = &pdev->dev;
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwrap");
-       wrp->base = devm_ioremap_resource(wrp->dev, res);
+       wrp->base = devm_platform_ioremap_resource_byname(pdev, "pwrap");
        if (IS_ERR(wrp->base))
                return PTR_ERR(wrp->base);
 
@@ -2220,9 +2186,7 @@ static int pwrap_probe(struct platform_device *pdev)
        }
 
        if (HAS_CAP(wrp->master->caps, PWRAP_CAP_BRIDGE)) {
-               res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-                               "pwrap-bridge");
-               wrp->bridge_base = devm_ioremap_resource(wrp->dev, res);
+               wrp->bridge_base = devm_platform_ioremap_resource_byname(pdev, "pwrap-bridge");
                if (IS_ERR(wrp->bridge_base))
                        return PTR_ERR(wrp->bridge_base);
 
@@ -2315,13 +2279,18 @@ static int pwrap_probe(struct platform_device *pdev)
                pwrap_writel(wrp, wrp->master->int1_en_all, PWRAP_INT1_EN);
 
        irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               ret = irq;
+               goto err_out2;
+       }
+
        ret = devm_request_irq(wrp->dev, irq, pwrap_interrupt,
                               IRQF_TRIGGER_HIGH,
                               "mt-pmic-pwrap", wrp);
        if (ret)
                goto err_out2;
 
-       wrp->regmap = devm_regmap_init(wrp->dev, NULL, wrp, wrp->slave->regmap);
+       wrp->regmap = devm_regmap_init(wrp->dev, NULL, wrp, wrp->slave->regops->regmap);
        if (IS_ERR(wrp->regmap)) {
                ret = PTR_ERR(wrp->regmap);
                goto err_out2;
diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c
new file mode 100644 (file)
index 0000000..dee8664
--- /dev/null
@@ -0,0 +1,2403 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 MediaTek Inc.
+ */
+
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/cpuidle.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_opp.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/thermal.h>
+
+/* svs bank 1-line software id */
+#define SVSB_CPU_LITTLE                        BIT(0)
+#define SVSB_CPU_BIG                   BIT(1)
+#define SVSB_CCI                       BIT(2)
+#define SVSB_GPU                       BIT(3)
+
+/* svs bank 2-line type */
+#define SVSB_LOW                       BIT(8)
+#define SVSB_HIGH                      BIT(9)
+
+/* svs bank mode support */
+#define SVSB_MODE_ALL_DISABLE          0
+#define SVSB_MODE_INIT01               BIT(1)
+#define SVSB_MODE_INIT02               BIT(2)
+#define SVSB_MODE_MON                  BIT(3)
+
+/* svs bank volt flags */
+#define SVSB_INIT01_PD_REQ             BIT(0)
+#define SVSB_INIT01_VOLT_IGNORE                BIT(1)
+#define SVSB_INIT01_VOLT_INC_ONLY      BIT(2)
+#define SVSB_MON_VOLT_IGNORE           BIT(16)
+#define SVSB_REMOVE_DVTFIXED_VOLT      BIT(24)
+
+/* svs bank register common configuration */
+#define SVSB_DET_MAX                   0xffff
+#define SVSB_DET_WINDOW                        0xa28
+#define SVSB_DTHI                      0x1
+#define SVSB_DTLO                      0xfe
+#define SVSB_EN_INIT01                 0x1
+#define SVSB_EN_INIT02                 0x5
+#define SVSB_EN_MON                    0x2
+#define SVSB_EN_OFF                    0x0
+#define SVSB_INTEN_INIT0x              0x00005f01
+#define SVSB_INTEN_MONVOPEN            0x00ff0000
+#define SVSB_INTSTS_CLEAN              0x00ffffff
+#define SVSB_INTSTS_COMPLETE           0x1
+#define SVSB_INTSTS_MONVOP             0x00ff0000
+#define SVSB_RUNCONFIG_DEFAULT         0x80000000
+
+/* svs bank related setting */
+#define BITS8                          8
+#define MAX_OPP_ENTRIES                        16
+#define REG_BYTES                      4
+#define SVSB_DC_SIGNED_BIT             BIT(15)
+#define SVSB_DET_CLK_EN                        BIT(31)
+#define SVSB_TEMP_LOWER_BOUND          0xb2
+#define SVSB_TEMP_UPPER_BOUND          0x64
+
+static DEFINE_SPINLOCK(svs_lock);
+
+#define debug_fops_ro(name)                                            \
+       static int svs_##name##_debug_open(struct inode *inode,         \
+                                          struct file *filp)           \
+       {                                                               \
+               return single_open(filp, svs_##name##_debug_show,       \
+                                  inode->i_private);                   \
+       }                                                               \
+       static const struct file_operations svs_##name##_debug_fops = { \
+               .owner = THIS_MODULE,                                   \
+               .open = svs_##name##_debug_open,                        \
+               .read = seq_read,                                       \
+               .llseek = seq_lseek,                                    \
+               .release = single_release,                              \
+       }
+
+#define debug_fops_rw(name)                                            \
+       static int svs_##name##_debug_open(struct inode *inode,         \
+                                          struct file *filp)           \
+       {                                                               \
+               return single_open(filp, svs_##name##_debug_show,       \
+                                  inode->i_private);                   \
+       }                                                               \
+       static const struct file_operations svs_##name##_debug_fops = { \
+               .owner = THIS_MODULE,                                   \
+               .open = svs_##name##_debug_open,                        \
+               .read = seq_read,                                       \
+               .write = svs_##name##_debug_write,                      \
+               .llseek = seq_lseek,                                    \
+               .release = single_release,                              \
+       }
+
+#define svs_dentry_data(name)  {__stringify(name), &svs_##name##_debug_fops}
+
+/**
+ * enum svsb_phase - svs bank phase enumeration
+ * @SVSB_PHASE_ERROR: svs bank encounters unexpected condition
+ * @SVSB_PHASE_INIT01: svs bank basic init for data calibration
+ * @SVSB_PHASE_INIT02: svs bank can provide voltages to opp table
+ * @SVSB_PHASE_MON: svs bank can provide voltages with thermal effect
+ * @SVSB_PHASE_MAX: total number of svs bank phase (debug purpose)
+ *
+ * Each svs bank has its own independent phase and we enable each svs bank by
+ * running their phase orderly. However, when svs bank encounters unexpected
+ * condition, it will fire an irq (PHASE_ERROR) to inform svs software.
+ *
+ * svs bank general phase-enabled order:
+ * SVSB_PHASE_INIT01 -> SVSB_PHASE_INIT02 -> SVSB_PHASE_MON
+ */
+enum svsb_phase {
+       SVSB_PHASE_ERROR = 0,
+       SVSB_PHASE_INIT01,
+       SVSB_PHASE_INIT02,
+       SVSB_PHASE_MON,
+       SVSB_PHASE_MAX,
+};
+
+enum svs_reg_index {
+       DESCHAR = 0,
+       TEMPCHAR,
+       DETCHAR,
+       AGECHAR,
+       DCCONFIG,
+       AGECONFIG,
+       FREQPCT30,
+       FREQPCT74,
+       LIMITVALS,
+       VBOOT,
+       DETWINDOW,
+       CONFIG,
+       TSCALCS,
+       RUNCONFIG,
+       SVSEN,
+       INIT2VALS,
+       DCVALUES,
+       AGEVALUES,
+       VOP30,
+       VOP74,
+       TEMP,
+       INTSTS,
+       INTSTSRAW,
+       INTEN,
+       CHKINT,
+       CHKSHIFT,
+       STATUS,
+       VDESIGN30,
+       VDESIGN74,
+       DVT30,
+       DVT74,
+       AGECOUNT,
+       SMSTATE0,
+       SMSTATE1,
+       CTL0,
+       DESDETSEC,
+       TEMPAGESEC,
+       CTRLSPARE0,
+       CTRLSPARE1,
+       CTRLSPARE2,
+       CTRLSPARE3,
+       CORESEL,
+       THERMINTST,
+       INTST,
+       THSTAGE0ST,
+       THSTAGE1ST,
+       THSTAGE2ST,
+       THAHBST0,
+       THAHBST1,
+       SPARE0,
+       SPARE1,
+       SPARE2,
+       SPARE3,
+       THSLPEVEB,
+       SVS_REG_MAX,
+};
+
+static const u32 svs_regs_v2[] = {
+       [DESCHAR]               = 0xc00,
+       [TEMPCHAR]              = 0xc04,
+       [DETCHAR]               = 0xc08,
+       [AGECHAR]               = 0xc0c,
+       [DCCONFIG]              = 0xc10,
+       [AGECONFIG]             = 0xc14,
+       [FREQPCT30]             = 0xc18,
+       [FREQPCT74]             = 0xc1c,
+       [LIMITVALS]             = 0xc20,
+       [VBOOT]                 = 0xc24,
+       [DETWINDOW]             = 0xc28,
+       [CONFIG]                = 0xc2c,
+       [TSCALCS]               = 0xc30,
+       [RUNCONFIG]             = 0xc34,
+       [SVSEN]                 = 0xc38,
+       [INIT2VALS]             = 0xc3c,
+       [DCVALUES]              = 0xc40,
+       [AGEVALUES]             = 0xc44,
+       [VOP30]                 = 0xc48,
+       [VOP74]                 = 0xc4c,
+       [TEMP]                  = 0xc50,
+       [INTSTS]                = 0xc54,
+       [INTSTSRAW]             = 0xc58,
+       [INTEN]                 = 0xc5c,
+       [CHKINT]                = 0xc60,
+       [CHKSHIFT]              = 0xc64,
+       [STATUS]                = 0xc68,
+       [VDESIGN30]             = 0xc6c,
+       [VDESIGN74]             = 0xc70,
+       [DVT30]                 = 0xc74,
+       [DVT74]                 = 0xc78,
+       [AGECOUNT]              = 0xc7c,
+       [SMSTATE0]              = 0xc80,
+       [SMSTATE1]              = 0xc84,
+       [CTL0]                  = 0xc88,
+       [DESDETSEC]             = 0xce0,
+       [TEMPAGESEC]            = 0xce4,
+       [CTRLSPARE0]            = 0xcf0,
+       [CTRLSPARE1]            = 0xcf4,
+       [CTRLSPARE2]            = 0xcf8,
+       [CTRLSPARE3]            = 0xcfc,
+       [CORESEL]               = 0xf00,
+       [THERMINTST]            = 0xf04,
+       [INTST]                 = 0xf08,
+       [THSTAGE0ST]            = 0xf0c,
+       [THSTAGE1ST]            = 0xf10,
+       [THSTAGE2ST]            = 0xf14,
+       [THAHBST0]              = 0xf18,
+       [THAHBST1]              = 0xf1c,
+       [SPARE0]                = 0xf20,
+       [SPARE1]                = 0xf24,
+       [SPARE2]                = 0xf28,
+       [SPARE3]                = 0xf2c,
+       [THSLPEVEB]             = 0xf30,
+};
+
+/**
+ * struct svs_platform - svs platform control
+ * @name: svs platform name
+ * @base: svs platform register base
+ * @dev: svs platform device
+ * @main_clk: main clock for svs bank
+ * @pbank: svs bank pointer needing to be protected by spin_lock section
+ * @banks: svs banks that svs platform supports
+ * @rst: svs platform reset control
+ * @efuse_parsing: svs platform efuse parsing function pointer
+ * @probe: svs platform probe function pointer
+ * @irqflags: svs platform irq settings flags
+ * @efuse_max: total number of svs efuse
+ * @tefuse_max: total number of thermal efuse
+ * @regs: svs platform registers map
+ * @bank_max: total number of svs banks
+ * @efuse: svs efuse data received from NVMEM framework
+ * @tefuse: thermal efuse data received from NVMEM framework
+ */
+struct svs_platform {
+       char *name;
+       void __iomem *base;
+       struct device *dev;
+       struct clk *main_clk;
+       struct svs_bank *pbank;
+       struct svs_bank *banks;
+       struct reset_control *rst;
+       bool (*efuse_parsing)(struct svs_platform *svsp);
+       int (*probe)(struct svs_platform *svsp);
+       unsigned long irqflags;
+       size_t efuse_max;
+       size_t tefuse_max;
+       const u32 *regs;
+       u32 bank_max;
+       u32 *efuse;
+       u32 *tefuse;
+};
+
+struct svs_platform_data {
+       char *name;
+       struct svs_bank *banks;
+       bool (*efuse_parsing)(struct svs_platform *svsp);
+       int (*probe)(struct svs_platform *svsp);
+       unsigned long irqflags;
+       const u32 *regs;
+       u32 bank_max;
+};
+
+/**
+ * struct svs_bank - svs bank representation
+ * @dev: bank device
+ * @opp_dev: device for opp table/buck control
+ * @init_completion: the timeout completion for bank init
+ * @buck: regulator used by opp_dev
+ * @tzd: thermal zone device for getting temperature
+ * @lock: mutex lock to protect voltage update process
+ * @set_freq_pct: function pointer to set bank frequency percent table
+ * @get_volts: function pointer to get bank voltages
+ * @name: bank name
+ * @buck_name: regulator name
+ * @tzone_name: thermal zone name
+ * @phase: bank current phase
+ * @volt_od: bank voltage overdrive
+ * @reg_data: bank register data in different phase for debug purpose
+ * @pm_runtime_enabled_count: bank pm runtime enabled count
+ * @mode_support: bank mode support.
+ * @freq_base: reference frequency for bank init
+ * @turn_freq_base: refenrece frequency for 2-line turn point
+ * @vboot: voltage request for bank init01 only
+ * @opp_dfreq: default opp frequency table
+ * @opp_dvolt: default opp voltage table
+ * @freq_pct: frequency percent table for bank init
+ * @volt: bank voltage table
+ * @volt_step: bank voltage step
+ * @volt_base: bank voltage base
+ * @volt_flags: bank voltage flags
+ * @vmax: bank voltage maximum
+ * @vmin: bank voltage minimum
+ * @age_config: bank age configuration
+ * @age_voffset_in: bank age voltage offset
+ * @dc_config: bank dc configuration
+ * @dc_voffset_in: bank dc voltage offset
+ * @dvt_fixed: bank dvt fixed value
+ * @vco: bank VCO value
+ * @chk_shift: bank chicken shift
+ * @core_sel: bank selection
+ * @opp_count: bank opp count
+ * @int_st: bank interrupt identification
+ * @sw_id: bank software identification
+ * @cpu_id: cpu core id for SVS CPU bank use only
+ * @ctl0: TS-x selection
+ * @temp: bank temperature
+ * @tzone_htemp: thermal zone high temperature threshold
+ * @tzone_htemp_voffset: thermal zone high temperature voltage offset
+ * @tzone_ltemp: thermal zone low temperature threshold
+ * @tzone_ltemp_voffset: thermal zone low temperature voltage offset
+ * @bts: svs efuse data
+ * @mts: svs efuse data
+ * @bdes: svs efuse data
+ * @mdes: svs efuse data
+ * @mtdes: svs efuse data
+ * @dcbdet: svs efuse data
+ * @dcmdet: svs efuse data
+ * @turn_pt: 2-line turn point tells which opp_volt calculated by high/low bank
+ * @type: bank type to represent it is 2-line (high/low) bank or 1-line bank
+ *
+ * Svs bank will generate suitalbe voltages by below general math equation
+ * and provide these voltages to opp voltage table.
+ *
+ * opp_volt[i] = (volt[i] * volt_step) + volt_base;
+ */
+struct svs_bank {
+       struct device *dev;
+       struct device *opp_dev;
+       struct completion init_completion;
+       struct regulator *buck;
+       struct thermal_zone_device *tzd;
+       struct mutex lock;      /* lock to protect voltage update process */
+       void (*set_freq_pct)(struct svs_platform *svsp);
+       void (*get_volts)(struct svs_platform *svsp);
+       char *name;
+       char *buck_name;
+       char *tzone_name;
+       enum svsb_phase phase;
+       s32 volt_od;
+       u32 reg_data[SVSB_PHASE_MAX][SVS_REG_MAX];
+       u32 pm_runtime_enabled_count;
+       u32 mode_support;
+       u32 freq_base;
+       u32 turn_freq_base;
+       u32 vboot;
+       u32 opp_dfreq[MAX_OPP_ENTRIES];
+       u32 opp_dvolt[MAX_OPP_ENTRIES];
+       u32 freq_pct[MAX_OPP_ENTRIES];
+       u32 volt[MAX_OPP_ENTRIES];
+       u32 volt_step;
+       u32 volt_base;
+       u32 volt_flags;
+       u32 vmax;
+       u32 vmin;
+       u32 age_config;
+       u32 age_voffset_in;
+       u32 dc_config;
+       u32 dc_voffset_in;
+       u32 dvt_fixed;
+       u32 vco;
+       u32 chk_shift;
+       u32 core_sel;
+       u32 opp_count;
+       u32 int_st;
+       u32 sw_id;
+       u32 cpu_id;
+       u32 ctl0;
+       u32 temp;
+       u32 tzone_htemp;
+       u32 tzone_htemp_voffset;
+       u32 tzone_ltemp;
+       u32 tzone_ltemp_voffset;
+       u32 bts;
+       u32 mts;
+       u32 bdes;
+       u32 mdes;
+       u32 mtdes;
+       u32 dcbdet;
+       u32 dcmdet;
+       u32 turn_pt;
+       u32 type;
+};
+
+static u32 percent(u32 numerator, u32 denominator)
+{
+       /* If not divide 1000, "numerator * 100" will have data overflow. */
+       numerator /= 1000;
+       denominator /= 1000;
+
+       return DIV_ROUND_UP(numerator * 100, denominator);
+}
+
+static u32 svs_readl_relaxed(struct svs_platform *svsp, enum svs_reg_index rg_i)
+{
+       return readl_relaxed(svsp->base + svsp->regs[rg_i]);
+}
+
+static void svs_writel_relaxed(struct svs_platform *svsp, u32 val,
+                              enum svs_reg_index rg_i)
+{
+       writel_relaxed(val, svsp->base + svsp->regs[rg_i]);
+}
+
+static void svs_switch_bank(struct svs_platform *svsp)
+{
+       struct svs_bank *svsb = svsp->pbank;
+
+       svs_writel_relaxed(svsp, svsb->core_sel, CORESEL);
+}
+
+static u32 svs_bank_volt_to_opp_volt(u32 svsb_volt, u32 svsb_volt_step,
+                                    u32 svsb_volt_base)
+{
+       return (svsb_volt * svsb_volt_step) + svsb_volt_base;
+}
+
+static u32 svs_opp_volt_to_bank_volt(u32 opp_u_volt, u32 svsb_volt_step,
+                                    u32 svsb_volt_base)
+{
+       return (opp_u_volt - svsb_volt_base) / svsb_volt_step;
+}
+
+static int svs_sync_bank_volts_from_opp(struct svs_bank *svsb)
+{
+       struct dev_pm_opp *opp;
+       u32 i, opp_u_volt;
+
+       for (i = 0; i < svsb->opp_count; i++) {
+               opp = dev_pm_opp_find_freq_exact(svsb->opp_dev,
+                                                svsb->opp_dfreq[i],
+                                                true);
+               if (IS_ERR(opp)) {
+                       dev_err(svsb->dev, "cannot find freq = %u (%ld)\n",
+                               svsb->opp_dfreq[i], PTR_ERR(opp));
+                       return PTR_ERR(opp);
+               }
+
+               opp_u_volt = dev_pm_opp_get_voltage(opp);
+               svsb->volt[i] = svs_opp_volt_to_bank_volt(opp_u_volt,
+                                                         svsb->volt_step,
+                                                         svsb->volt_base);
+               dev_pm_opp_put(opp);
+       }
+
+       return 0;
+}
+
+static int svs_adjust_pm_opp_volts(struct svs_bank *svsb)
+{
+       int ret = -EPERM, tzone_temp = 0;
+       u32 i, svsb_volt, opp_volt, temp_voffset = 0, opp_start, opp_stop;
+
+       mutex_lock(&svsb->lock);
+
+       /*
+        * 2-line bank updates its corresponding opp volts.
+        * 1-line bank updates all opp volts.
+        */
+       if (svsb->type == SVSB_HIGH) {
+               opp_start = 0;
+               opp_stop = svsb->turn_pt;
+       } else if (svsb->type == SVSB_LOW) {
+               opp_start = svsb->turn_pt;
+               opp_stop = svsb->opp_count;
+       } else {
+               opp_start = 0;
+               opp_stop = svsb->opp_count;
+       }
+
+       /* Get thermal effect */
+       if (svsb->phase == SVSB_PHASE_MON) {
+               ret = thermal_zone_get_temp(svsb->tzd, &tzone_temp);
+               if (ret || (svsb->temp > SVSB_TEMP_UPPER_BOUND &&
+                           svsb->temp < SVSB_TEMP_LOWER_BOUND)) {
+                       dev_err(svsb->dev, "%s: %d (0x%x), run default volts\n",
+                               svsb->tzone_name, ret, svsb->temp);
+                       svsb->phase = SVSB_PHASE_ERROR;
+               }
+
+               if (tzone_temp >= svsb->tzone_htemp)
+                       temp_voffset += svsb->tzone_htemp_voffset;
+               else if (tzone_temp <= svsb->tzone_ltemp)
+                       temp_voffset += svsb->tzone_ltemp_voffset;
+
+               /* 2-line bank update all opp volts when running mon mode */
+               if (svsb->type == SVSB_HIGH || svsb->type == SVSB_LOW) {
+                       opp_start = 0;
+                       opp_stop = svsb->opp_count;
+               }
+       }
+
+       /* vmin <= svsb_volt (opp_volt) <= default opp voltage */
+       for (i = opp_start; i < opp_stop; i++) {
+               switch (svsb->phase) {
+               case SVSB_PHASE_ERROR:
+                       opp_volt = svsb->opp_dvolt[i];
+                       break;
+               case SVSB_PHASE_INIT01:
+                       /* do nothing */
+                       goto unlock_mutex;
+               case SVSB_PHASE_INIT02:
+                       svsb_volt = max(svsb->volt[i], svsb->vmin);
+                       opp_volt = svs_bank_volt_to_opp_volt(svsb_volt,
+                                                            svsb->volt_step,
+                                                            svsb->volt_base);
+                       break;
+               case SVSB_PHASE_MON:
+                       svsb_volt = max(svsb->volt[i] + temp_voffset, svsb->vmin);
+                       opp_volt = svs_bank_volt_to_opp_volt(svsb_volt,
+                                                            svsb->volt_step,
+                                                            svsb->volt_base);
+                       break;
+               default:
+                       dev_err(svsb->dev, "unknown phase: %u\n", svsb->phase);
+                       ret = -EINVAL;
+                       goto unlock_mutex;
+               }
+
+               opp_volt = min(opp_volt, svsb->opp_dvolt[i]);
+               ret = dev_pm_opp_adjust_voltage(svsb->opp_dev,
+                                               svsb->opp_dfreq[i],
+                                               opp_volt, opp_volt,
+                                               svsb->opp_dvolt[i]);
+               if (ret) {
+                       dev_err(svsb->dev, "set %uuV fail: %d\n",
+                               opp_volt, ret);
+                       goto unlock_mutex;
+               }
+       }
+
+unlock_mutex:
+       mutex_unlock(&svsb->lock);
+
+       return ret;
+}
+
+static int svs_dump_debug_show(struct seq_file *m, void *p)
+{
+       struct svs_platform *svsp = (struct svs_platform *)m->private;
+       struct svs_bank *svsb;
+       unsigned long svs_reg_addr;
+       u32 idx, i, j, bank_id;
+
+       for (i = 0; i < svsp->efuse_max; i++)
+               if (svsp->efuse && svsp->efuse[i])
+                       seq_printf(m, "M_HW_RES%d = 0x%08x\n",
+                                  i, svsp->efuse[i]);
+
+       for (i = 0; i < svsp->tefuse_max; i++)
+               if (svsp->tefuse)
+                       seq_printf(m, "THERMAL_EFUSE%d = 0x%08x\n",
+                                  i, svsp->tefuse[i]);
+
+       for (bank_id = 0, idx = 0; idx < svsp->bank_max; idx++, bank_id++) {
+               svsb = &svsp->banks[idx];
+
+               for (i = SVSB_PHASE_INIT01; i <= SVSB_PHASE_MON; i++) {
+                       seq_printf(m, "Bank_number = %u\n", bank_id);
+
+                       if (i == SVSB_PHASE_INIT01 || i == SVSB_PHASE_INIT02)
+                               seq_printf(m, "mode = init%d\n", i);
+                       else if (i == SVSB_PHASE_MON)
+                               seq_puts(m, "mode = mon\n");
+                       else
+                               seq_puts(m, "mode = error\n");
+
+                       for (j = DESCHAR; j < SVS_REG_MAX; j++) {
+                               svs_reg_addr = (unsigned long)(svsp->base +
+                                                              svsp->regs[j]);
+                               seq_printf(m, "0x%08lx = 0x%08x\n",
+                                          svs_reg_addr, svsb->reg_data[i][j]);
+                       }
+               }
+       }
+
+       return 0;
+}
+
+debug_fops_ro(dump);
+
+static int svs_enable_debug_show(struct seq_file *m, void *v)
+{
+       struct svs_bank *svsb = (struct svs_bank *)m->private;
+
+       switch (svsb->phase) {
+       case SVSB_PHASE_ERROR:
+               seq_puts(m, "disabled\n");
+               break;
+       case SVSB_PHASE_INIT01:
+               seq_puts(m, "init1\n");
+               break;
+       case SVSB_PHASE_INIT02:
+               seq_puts(m, "init2\n");
+               break;
+       case SVSB_PHASE_MON:
+               seq_puts(m, "mon mode\n");
+               break;
+       default:
+               seq_puts(m, "unknown\n");
+               break;
+       }
+
+       return 0;
+}
+
+static ssize_t svs_enable_debug_write(struct file *filp,
+                                     const char __user *buffer,
+                                     size_t count, loff_t *pos)
+{
+       struct svs_bank *svsb = file_inode(filp)->i_private;
+       struct svs_platform *svsp = dev_get_drvdata(svsb->dev);
+       unsigned long flags;
+       int enabled, ret;
+       char *buf = NULL;
+
+       if (count >= PAGE_SIZE)
+               return -EINVAL;
+
+       buf = (char *)memdup_user_nul(buffer, count);
+       if (IS_ERR(buf))
+               return PTR_ERR(buf);
+
+       ret = kstrtoint(buf, 10, &enabled);
+       if (ret)
+               return ret;
+
+       if (!enabled) {
+               spin_lock_irqsave(&svs_lock, flags);
+               svsp->pbank = svsb;
+               svsb->mode_support = SVSB_MODE_ALL_DISABLE;
+               svs_switch_bank(svsp);
+               svs_writel_relaxed(svsp, SVSB_EN_OFF, SVSEN);
+               svs_writel_relaxed(svsp, SVSB_INTSTS_CLEAN, INTSTS);
+               spin_unlock_irqrestore(&svs_lock, flags);
+
+               svsb->phase = SVSB_PHASE_ERROR;
+               svs_adjust_pm_opp_volts(svsb);
+       }
+
+       kfree(buf);
+
+       return count;
+}
+
+debug_fops_rw(enable);
+
+static int svs_status_debug_show(struct seq_file *m, void *v)
+{
+       struct svs_bank *svsb = (struct svs_bank *)m->private;
+       struct dev_pm_opp *opp;
+       int tzone_temp = 0, ret;
+       u32 i;
+
+       ret = thermal_zone_get_temp(svsb->tzd, &tzone_temp);
+       if (ret)
+               seq_printf(m, "%s: temperature ignore, turn_pt = %u\n",
+                          svsb->name, svsb->turn_pt);
+       else
+               seq_printf(m, "%s: temperature = %d, turn_pt = %u\n",
+                          svsb->name, tzone_temp, svsb->turn_pt);
+
+       for (i = 0; i < svsb->opp_count; i++) {
+               opp = dev_pm_opp_find_freq_exact(svsb->opp_dev,
+                                                svsb->opp_dfreq[i], true);
+               if (IS_ERR(opp)) {
+                       seq_printf(m, "%s: cannot find freq = %u (%ld)\n",
+                                  svsb->name, svsb->opp_dfreq[i],
+                                  PTR_ERR(opp));
+                       return PTR_ERR(opp);
+               }
+
+               seq_printf(m, "opp_freq[%02u]: %u, opp_volt[%02u]: %lu, ",
+                          i, svsb->opp_dfreq[i], i,
+                          dev_pm_opp_get_voltage(opp));
+               seq_printf(m, "svsb_volt[%02u]: 0x%x, freq_pct[%02u]: %u\n",
+                          i, svsb->volt[i], i, svsb->freq_pct[i]);
+               dev_pm_opp_put(opp);
+       }
+
+       return 0;
+}
+
+debug_fops_ro(status);
+
+static int svs_create_debug_cmds(struct svs_platform *svsp)
+{
+       struct svs_bank *svsb;
+       struct dentry *svs_dir, *svsb_dir, *file_entry;
+       const char *d = "/sys/kernel/debug/svs";
+       u32 i, idx;
+
+       struct svs_dentry {
+               const char *name;
+               const struct file_operations *fops;
+       };
+
+       struct svs_dentry svs_entries[] = {
+               svs_dentry_data(dump),
+       };
+
+       struct svs_dentry svsb_entries[] = {
+               svs_dentry_data(enable),
+               svs_dentry_data(status),
+       };
+
+       svs_dir = debugfs_create_dir("svs", NULL);
+       if (IS_ERR(svs_dir)) {
+               dev_err(svsp->dev, "cannot create %s: %ld\n",
+                       d, PTR_ERR(svs_dir));
+               return PTR_ERR(svs_dir);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(svs_entries); i++) {
+               file_entry = debugfs_create_file(svs_entries[i].name, 0664,
+                                                svs_dir, svsp,
+                                                svs_entries[i].fops);
+               if (IS_ERR(file_entry)) {
+                       dev_err(svsp->dev, "cannot create %s/%s: %ld\n",
+                               d, svs_entries[i].name, PTR_ERR(file_entry));
+                       return PTR_ERR(file_entry);
+               }
+       }
+
+       for (idx = 0; idx < svsp->bank_max; idx++) {
+               svsb = &svsp->banks[idx];
+
+               if (svsb->mode_support == SVSB_MODE_ALL_DISABLE)
+                       continue;
+
+               svsb_dir = debugfs_create_dir(svsb->name, svs_dir);
+               if (IS_ERR(svsb_dir)) {
+                       dev_err(svsp->dev, "cannot create %s/%s: %ld\n",
+                               d, svsb->name, PTR_ERR(svsb_dir));
+                       return PTR_ERR(svsb_dir);
+               }
+
+               for (i = 0; i < ARRAY_SIZE(svsb_entries); i++) {
+                       file_entry = debugfs_create_file(svsb_entries[i].name,
+                                                        0664, svsb_dir, svsb,
+                                                        svsb_entries[i].fops);
+                       if (IS_ERR(file_entry)) {
+                               dev_err(svsp->dev, "no %s/%s/%s?: %ld\n",
+                                       d, svsb->name, svsb_entries[i].name,
+                                       PTR_ERR(file_entry));
+                               return PTR_ERR(file_entry);
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static u32 interpolate(u32 f0, u32 f1, u32 v0, u32 v1, u32 fx)
+{
+       u32 vx;
+
+       if (v0 == v1 || f0 == f1)
+               return v0;
+
+       /* *100 to have decimal fraction factor */
+       vx = (v0 * 100) - ((((v0 - v1) * 100) / (f0 - f1)) * (f0 - fx));
+
+       return DIV_ROUND_UP(vx, 100);
+}
+
+static void svs_get_bank_volts_v3(struct svs_platform *svsp)
+{
+       struct svs_bank *svsb = svsp->pbank;
+       u32 i, j, *vop, vop74, vop30, turn_pt = svsb->turn_pt;
+       u32 b_sft, shift_byte = 0, opp_start = 0, opp_stop = 0;
+       u32 middle_index = (svsb->opp_count / 2);
+
+       if (svsb->phase == SVSB_PHASE_MON &&
+           svsb->volt_flags & SVSB_MON_VOLT_IGNORE)
+               return;
+
+       vop74 = svs_readl_relaxed(svsp, VOP74);
+       vop30 = svs_readl_relaxed(svsp, VOP30);
+
+       /* Target is to set svsb->volt[] by algorithm */
+       if (turn_pt < middle_index) {
+               if (svsb->type == SVSB_HIGH) {
+                       /* volt[0] ~ volt[turn_pt - 1] */
+                       for (i = 0; i < turn_pt; i++) {
+                               b_sft = BITS8 * (shift_byte % REG_BYTES);
+                               vop = (shift_byte < REG_BYTES) ? &vop30 :
+                                                                &vop74;
+                               svsb->volt[i] = (*vop >> b_sft) & GENMASK(7, 0);
+                               shift_byte++;
+                       }
+               } else if (svsb->type == SVSB_LOW) {
+                       /* volt[turn_pt] + volt[j] ~ volt[opp_count - 1] */
+                       j = svsb->opp_count - 7;
+                       svsb->volt[turn_pt] = vop30 & GENMASK(7, 0);
+                       shift_byte++;
+                       for (i = j; i < svsb->opp_count; i++) {
+                               b_sft = BITS8 * (shift_byte % REG_BYTES);
+                               vop = (shift_byte < REG_BYTES) ? &vop30 :
+                                                                &vop74;
+                               svsb->volt[i] = (*vop >> b_sft) & GENMASK(7, 0);
+                               shift_byte++;
+                       }
+
+                       /* volt[turn_pt + 1] ~ volt[j - 1] by interpolate */
+                       for (i = turn_pt + 1; i < j; i++)
+                               svsb->volt[i] = interpolate(svsb->freq_pct[turn_pt],
+                                                           svsb->freq_pct[j],
+                                                           svsb->volt[turn_pt],
+                                                           svsb->volt[j],
+                                                           svsb->freq_pct[i]);
+               }
+       } else {
+               if (svsb->type == SVSB_HIGH) {
+                       /* volt[0] + volt[j] ~ volt[turn_pt - 1] */
+                       j = turn_pt - 7;
+                       svsb->volt[0] = vop30 & GENMASK(7, 0);
+                       shift_byte++;
+                       for (i = j; i < turn_pt; i++) {
+                               b_sft = BITS8 * (shift_byte % REG_BYTES);
+                               vop = (shift_byte < REG_BYTES) ? &vop30 :
+                                                                &vop74;
+                               svsb->volt[i] = (*vop >> b_sft) & GENMASK(7, 0);
+                               shift_byte++;
+                       }
+
+                       /* volt[1] ~ volt[j - 1] by interpolate */
+                       for (i = 1; i < j; i++)
+                               svsb->volt[i] = interpolate(svsb->freq_pct[0],
+                                                           svsb->freq_pct[j],
+                                                           svsb->volt[0],
+                                                           svsb->volt[j],
+                                                           svsb->freq_pct[i]);
+               } else if (svsb->type == SVSB_LOW) {
+                       /* volt[turn_pt] ~ volt[opp_count - 1] */
+                       for (i = turn_pt; i < svsb->opp_count; i++) {
+                               b_sft = BITS8 * (shift_byte % REG_BYTES);
+                               vop = (shift_byte < REG_BYTES) ? &vop30 :
+                                                                &vop74;
+                               svsb->volt[i] = (*vop >> b_sft) & GENMASK(7, 0);
+                               shift_byte++;
+                       }
+               }
+       }
+
+       if (svsb->type == SVSB_HIGH) {
+               opp_start = 0;
+               opp_stop = svsb->turn_pt;
+       } else if (svsb->type == SVSB_LOW) {
+               opp_start = svsb->turn_pt;
+               opp_stop = svsb->opp_count;
+       }
+
+       for (i = opp_start; i < opp_stop; i++)
+               if (svsb->volt_flags & SVSB_REMOVE_DVTFIXED_VOLT)
+                       svsb->volt[i] -= svsb->dvt_fixed;
+}
+
+static void svs_set_bank_freq_pct_v3(struct svs_platform *svsp)
+{
+       struct svs_bank *svsb = svsp->pbank;
+       u32 i, j, *freq_pct, freq_pct74 = 0, freq_pct30 = 0;
+       u32 b_sft, shift_byte = 0, turn_pt;
+       u32 middle_index = (svsb->opp_count / 2);
+
+       for (i = 0; i < svsb->opp_count; i++) {
+               if (svsb->opp_dfreq[i] <= svsb->turn_freq_base) {
+                       svsb->turn_pt = i;
+                       break;
+               }
+       }
+
+       turn_pt = svsb->turn_pt;
+
+       /* Target is to fill out freq_pct74 / freq_pct30 by algorithm */
+       if (turn_pt < middle_index) {
+               if (svsb->type == SVSB_HIGH) {
+                       /*
+                        * If we don't handle this situation,
+                        * SVSB_HIGH's FREQPCT74 / FREQPCT30 would keep "0"
+                        * and this leads SVSB_LOW to work abnormally.
+                        */
+                       if (turn_pt == 0)
+                               freq_pct30 = svsb->freq_pct[0];
+
+                       /* freq_pct[0] ~ freq_pct[turn_pt - 1] */
+                       for (i = 0; i < turn_pt; i++) {
+                               b_sft = BITS8 * (shift_byte % REG_BYTES);
+                               freq_pct = (shift_byte < REG_BYTES) ?
+                                          &freq_pct30 : &freq_pct74;
+                               *freq_pct |= (svsb->freq_pct[i] << b_sft);
+                               shift_byte++;
+                       }
+               } else if (svsb->type == SVSB_LOW) {
+                       /*
+                        * freq_pct[turn_pt] +
+                        * freq_pct[opp_count - 7] ~ freq_pct[opp_count -1]
+                        */
+                       freq_pct30 = svsb->freq_pct[turn_pt];
+                       shift_byte++;
+                       j = svsb->opp_count - 7;
+                       for (i = j; i < svsb->opp_count; i++) {
+                               b_sft = BITS8 * (shift_byte % REG_BYTES);
+                               freq_pct = (shift_byte < REG_BYTES) ?
+                                          &freq_pct30 : &freq_pct74;
+                               *freq_pct |= (svsb->freq_pct[i] << b_sft);
+                               shift_byte++;
+                       }
+               }
+       } else {
+               if (svsb->type == SVSB_HIGH) {
+                       /*
+                        * freq_pct[0] +
+                        * freq_pct[turn_pt - 7] ~ freq_pct[turn_pt - 1]
+                        */
+                       freq_pct30 = svsb->freq_pct[0];
+                       shift_byte++;
+                       j = turn_pt - 7;
+                       for (i = j; i < turn_pt; i++) {
+                               b_sft = BITS8 * (shift_byte % REG_BYTES);
+                               freq_pct = (shift_byte < REG_BYTES) ?
+                                          &freq_pct30 : &freq_pct74;
+                               *freq_pct |= (svsb->freq_pct[i] << b_sft);
+                               shift_byte++;
+                       }
+               } else if (svsb->type == SVSB_LOW) {
+                       /* freq_pct[turn_pt] ~ freq_pct[opp_count - 1] */
+                       for (i = turn_pt; i < svsb->opp_count; i++) {
+                               b_sft = BITS8 * (shift_byte % REG_BYTES);
+                               freq_pct = (shift_byte < REG_BYTES) ?
+                                          &freq_pct30 : &freq_pct74;
+                               *freq_pct |= (svsb->freq_pct[i] << b_sft);
+                               shift_byte++;
+                       }
+               }
+       }
+
+       svs_writel_relaxed(svsp, freq_pct74, FREQPCT74);
+       svs_writel_relaxed(svsp, freq_pct30, FREQPCT30);
+}
+
+static void svs_get_bank_volts_v2(struct svs_platform *svsp)
+{
+       struct svs_bank *svsb = svsp->pbank;
+       u32 temp, i;
+
+       temp = svs_readl_relaxed(svsp, VOP74);
+       svsb->volt[14] = (temp >> 24) & GENMASK(7, 0);
+       svsb->volt[12] = (temp >> 16) & GENMASK(7, 0);
+       svsb->volt[10] = (temp >> 8)  & GENMASK(7, 0);
+       svsb->volt[8] = (temp & GENMASK(7, 0));
+
+       temp = svs_readl_relaxed(svsp, VOP30);
+       svsb->volt[6] = (temp >> 24) & GENMASK(7, 0);
+       svsb->volt[4] = (temp >> 16) & GENMASK(7, 0);
+       svsb->volt[2] = (temp >> 8)  & GENMASK(7, 0);
+       svsb->volt[0] = (temp & GENMASK(7, 0));
+
+       for (i = 0; i <= 12; i += 2)
+               svsb->volt[i + 1] = interpolate(svsb->freq_pct[i],
+                                               svsb->freq_pct[i + 2],
+                                               svsb->volt[i],
+                                               svsb->volt[i + 2],
+                                               svsb->freq_pct[i + 1]);
+
+       svsb->volt[15] = interpolate(svsb->freq_pct[12],
+                                    svsb->freq_pct[14],
+                                    svsb->volt[12],
+                                    svsb->volt[14],
+                                    svsb->freq_pct[15]);
+
+       for (i = 0; i < svsb->opp_count; i++)
+               svsb->volt[i] += svsb->volt_od;
+}
+
+static void svs_set_bank_freq_pct_v2(struct svs_platform *svsp)
+{
+       struct svs_bank *svsb = svsp->pbank;
+
+       svs_writel_relaxed(svsp,
+                          (svsb->freq_pct[14] << 24) |
+                          (svsb->freq_pct[12] << 16) |
+                          (svsb->freq_pct[10] << 8) |
+                          svsb->freq_pct[8],
+                          FREQPCT74);
+
+       svs_writel_relaxed(svsp,
+                          (svsb->freq_pct[6] << 24) |
+                          (svsb->freq_pct[4] << 16) |
+                          (svsb->freq_pct[2] << 8) |
+                          svsb->freq_pct[0],
+                          FREQPCT30);
+}
+
+static void svs_set_bank_phase(struct svs_platform *svsp,
+                              enum svsb_phase target_phase)
+{
+       struct svs_bank *svsb = svsp->pbank;
+       u32 des_char, temp_char, det_char, limit_vals, init2vals, ts_calcs;
+
+       svs_switch_bank(svsp);
+
+       des_char = (svsb->bdes << 8) | svsb->mdes;
+       svs_writel_relaxed(svsp, des_char, DESCHAR);
+
+       temp_char = (svsb->vco << 16) | (svsb->mtdes << 8) | svsb->dvt_fixed;
+       svs_writel_relaxed(svsp, temp_char, TEMPCHAR);
+
+       det_char = (svsb->dcbdet << 8) | svsb->dcmdet;
+       svs_writel_relaxed(svsp, det_char, DETCHAR);
+
+       svs_writel_relaxed(svsp, svsb->dc_config, DCCONFIG);
+       svs_writel_relaxed(svsp, svsb->age_config, AGECONFIG);
+       svs_writel_relaxed(svsp, SVSB_RUNCONFIG_DEFAULT, RUNCONFIG);
+
+       svsb->set_freq_pct(svsp);
+
+       limit_vals = (svsb->vmax << 24) | (svsb->vmin << 16) |
+                    (SVSB_DTHI << 8) | SVSB_DTLO;
+       svs_writel_relaxed(svsp, limit_vals, LIMITVALS);
+
+       svs_writel_relaxed(svsp, SVSB_DET_WINDOW, DETWINDOW);
+       svs_writel_relaxed(svsp, SVSB_DET_MAX, CONFIG);
+       svs_writel_relaxed(svsp, svsb->chk_shift, CHKSHIFT);
+       svs_writel_relaxed(svsp, svsb->ctl0, CTL0);
+       svs_writel_relaxed(svsp, SVSB_INTSTS_CLEAN, INTSTS);
+
+       switch (target_phase) {
+       case SVSB_PHASE_INIT01:
+               svs_writel_relaxed(svsp, svsb->vboot, VBOOT);
+               svs_writel_relaxed(svsp, SVSB_INTEN_INIT0x, INTEN);
+               svs_writel_relaxed(svsp, SVSB_EN_INIT01, SVSEN);
+               break;
+       case SVSB_PHASE_INIT02:
+               svs_writel_relaxed(svsp, SVSB_INTEN_INIT0x, INTEN);
+               init2vals = (svsb->age_voffset_in << 16) | svsb->dc_voffset_in;
+               svs_writel_relaxed(svsp, init2vals, INIT2VALS);
+               svs_writel_relaxed(svsp, SVSB_EN_INIT02, SVSEN);
+               break;
+       case SVSB_PHASE_MON:
+               ts_calcs = (svsb->bts << 12) | svsb->mts;
+               svs_writel_relaxed(svsp, ts_calcs, TSCALCS);
+               svs_writel_relaxed(svsp, SVSB_INTEN_MONVOPEN, INTEN);
+               svs_writel_relaxed(svsp, SVSB_EN_MON, SVSEN);
+               break;
+       default:
+               dev_err(svsb->dev, "requested unknown target phase: %u\n",
+                       target_phase);
+               break;
+       }
+}
+
+static inline void svs_save_bank_register_data(struct svs_platform *svsp,
+                                              enum svsb_phase phase)
+{
+       struct svs_bank *svsb = svsp->pbank;
+       enum svs_reg_index rg_i;
+
+       for (rg_i = DESCHAR; rg_i < SVS_REG_MAX; rg_i++)
+               svsb->reg_data[phase][rg_i] = svs_readl_relaxed(svsp, rg_i);
+}
+
+static inline void svs_error_isr_handler(struct svs_platform *svsp)
+{
+       struct svs_bank *svsb = svsp->pbank;
+
+       dev_err(svsb->dev, "%s: CORESEL = 0x%08x\n",
+               __func__, svs_readl_relaxed(svsp, CORESEL));
+       dev_err(svsb->dev, "SVSEN = 0x%08x, INTSTS = 0x%08x\n",
+               svs_readl_relaxed(svsp, SVSEN),
+               svs_readl_relaxed(svsp, INTSTS));
+       dev_err(svsb->dev, "SMSTATE0 = 0x%08x, SMSTATE1 = 0x%08x\n",
+               svs_readl_relaxed(svsp, SMSTATE0),
+               svs_readl_relaxed(svsp, SMSTATE1));
+       dev_err(svsb->dev, "TEMP = 0x%08x\n", svs_readl_relaxed(svsp, TEMP));
+
+       svs_save_bank_register_data(svsp, SVSB_PHASE_ERROR);
+
+       svsb->phase = SVSB_PHASE_ERROR;
+       svs_writel_relaxed(svsp, SVSB_EN_OFF, SVSEN);
+       svs_writel_relaxed(svsp, SVSB_INTSTS_CLEAN, INTSTS);
+}
+
+static inline void svs_init01_isr_handler(struct svs_platform *svsp)
+{
+       struct svs_bank *svsb = svsp->pbank;
+
+       dev_info(svsb->dev, "%s: VDN74~30:0x%08x~0x%08x, DC:0x%08x\n",
+                __func__, svs_readl_relaxed(svsp, VDESIGN74),
+                svs_readl_relaxed(svsp, VDESIGN30),
+                svs_readl_relaxed(svsp, DCVALUES));
+
+       svs_save_bank_register_data(svsp, SVSB_PHASE_INIT01);
+
+       svsb->phase = SVSB_PHASE_INIT01;
+       svsb->dc_voffset_in = ~(svs_readl_relaxed(svsp, DCVALUES) &
+                               GENMASK(15, 0)) + 1;
+       if (svsb->volt_flags & SVSB_INIT01_VOLT_IGNORE ||
+           (svsb->dc_voffset_in & SVSB_DC_SIGNED_BIT &&
+            svsb->volt_flags & SVSB_INIT01_VOLT_INC_ONLY))
+               svsb->dc_voffset_in = 0;
+
+       svsb->age_voffset_in = svs_readl_relaxed(svsp, AGEVALUES) &
+                              GENMASK(15, 0);
+
+       svs_writel_relaxed(svsp, SVSB_EN_OFF, SVSEN);
+       svs_writel_relaxed(svsp, SVSB_INTSTS_COMPLETE, INTSTS);
+       svsb->core_sel &= ~SVSB_DET_CLK_EN;
+}
+
+static inline void svs_init02_isr_handler(struct svs_platform *svsp)
+{
+       struct svs_bank *svsb = svsp->pbank;
+
+       dev_info(svsb->dev, "%s: VOP74~30:0x%08x~0x%08x, DC:0x%08x\n",
+                __func__, svs_readl_relaxed(svsp, VOP74),
+                svs_readl_relaxed(svsp, VOP30),
+                svs_readl_relaxed(svsp, DCVALUES));
+
+       svs_save_bank_register_data(svsp, SVSB_PHASE_INIT02);
+
+       svsb->phase = SVSB_PHASE_INIT02;
+       svsb->get_volts(svsp);
+
+       svs_writel_relaxed(svsp, SVSB_EN_OFF, SVSEN);
+       svs_writel_relaxed(svsp, SVSB_INTSTS_COMPLETE, INTSTS);
+}
+
+static inline void svs_mon_mode_isr_handler(struct svs_platform *svsp)
+{
+       struct svs_bank *svsb = svsp->pbank;
+
+       svs_save_bank_register_data(svsp, SVSB_PHASE_MON);
+
+       svsb->phase = SVSB_PHASE_MON;
+       svsb->get_volts(svsp);
+
+       svsb->temp = svs_readl_relaxed(svsp, TEMP) & GENMASK(7, 0);
+       svs_writel_relaxed(svsp, SVSB_INTSTS_MONVOP, INTSTS);
+}
+
+static irqreturn_t svs_isr(int irq, void *data)
+{
+       struct svs_platform *svsp = data;
+       struct svs_bank *svsb = NULL;
+       unsigned long flags;
+       u32 idx, int_sts, svs_en;
+
+       for (idx = 0; idx < svsp->bank_max; idx++) {
+               svsb = &svsp->banks[idx];
+               WARN(!svsb, "%s: svsb(%s) is null", __func__, svsb->name);
+
+               spin_lock_irqsave(&svs_lock, flags);
+               svsp->pbank = svsb;
+
+               /* Find out which svs bank fires interrupt */
+               if (svsb->int_st & svs_readl_relaxed(svsp, INTST)) {
+                       spin_unlock_irqrestore(&svs_lock, flags);
+                       continue;
+               }
+
+               svs_switch_bank(svsp);
+               int_sts = svs_readl_relaxed(svsp, INTSTS);
+               svs_en = svs_readl_relaxed(svsp, SVSEN);
+
+               if (int_sts == SVSB_INTSTS_COMPLETE &&
+                   svs_en == SVSB_EN_INIT01)
+                       svs_init01_isr_handler(svsp);
+               else if (int_sts == SVSB_INTSTS_COMPLETE &&
+                        svs_en == SVSB_EN_INIT02)
+                       svs_init02_isr_handler(svsp);
+               else if (int_sts & SVSB_INTSTS_MONVOP)
+                       svs_mon_mode_isr_handler(svsp);
+               else
+                       svs_error_isr_handler(svsp);
+
+               spin_unlock_irqrestore(&svs_lock, flags);
+               break;
+       }
+
+       svs_adjust_pm_opp_volts(svsb);
+
+       if (svsb->phase == SVSB_PHASE_INIT01 ||
+           svsb->phase == SVSB_PHASE_INIT02)
+               complete(&svsb->init_completion);
+
+       return IRQ_HANDLED;
+}
+
+static int svs_init01(struct svs_platform *svsp)
+{
+       struct svs_bank *svsb;
+       unsigned long flags, time_left;
+       bool search_done;
+       int ret = 0, r;
+       u32 opp_freq, opp_vboot, buck_volt, idx, i;
+
+       /* Keep CPUs' core power on for svs_init01 initialization */
+       cpuidle_pause_and_lock();
+
+        /* Svs bank init01 preparation - power enable */
+       for (idx = 0; idx < svsp->bank_max; idx++) {
+               svsb = &svsp->banks[idx];
+
+               if (!(svsb->mode_support & SVSB_MODE_INIT01))
+                       continue;
+
+               ret = regulator_enable(svsb->buck);
+               if (ret) {
+                       dev_err(svsb->dev, "%s enable fail: %d\n",
+                               svsb->buck_name, ret);
+                       goto svs_init01_resume_cpuidle;
+               }
+
+               /* Some buck doesn't support mode change. Show fail msg only */
+               ret = regulator_set_mode(svsb->buck, REGULATOR_MODE_FAST);
+               if (ret)
+                       dev_notice(svsb->dev, "set fast mode fail: %d\n", ret);
+
+               if (svsb->volt_flags & SVSB_INIT01_PD_REQ) {
+                       if (!pm_runtime_enabled(svsb->opp_dev)) {
+                               pm_runtime_enable(svsb->opp_dev);
+                               svsb->pm_runtime_enabled_count++;
+                       }
+
+                       ret = pm_runtime_get_sync(svsb->opp_dev);
+                       if (ret < 0) {
+                               dev_err(svsb->dev, "mtcmos on fail: %d\n", ret);
+                               goto svs_init01_resume_cpuidle;
+                       }
+               }
+       }
+
+       /*
+        * Svs bank init01 preparation - vboot voltage adjustment
+        * Sometimes two svs banks use the same buck. Therefore,
+        * we have to set each svs bank to target voltage(vboot) first.
+        */
+       for (idx = 0; idx < svsp->bank_max; idx++) {
+               svsb = &svsp->banks[idx];
+
+               if (!(svsb->mode_support & SVSB_MODE_INIT01))
+                       continue;
+
+               /*
+                * Find the fastest freq that can be run at vboot and
+                * fix to that freq until svs_init01 is done.
+                */
+               search_done = false;
+               opp_vboot = svs_bank_volt_to_opp_volt(svsb->vboot,
+                                                     svsb->volt_step,
+                                                     svsb->volt_base);
+
+               for (i = 0; i < svsb->opp_count; i++) {
+                       opp_freq = svsb->opp_dfreq[i];
+                       if (!search_done && svsb->opp_dvolt[i] <= opp_vboot) {
+                               ret = dev_pm_opp_adjust_voltage(svsb->opp_dev,
+                                                               opp_freq,
+                                                               opp_vboot,
+                                                               opp_vboot,
+                                                               opp_vboot);
+                               if (ret) {
+                                       dev_err(svsb->dev,
+                                               "set opp %uuV vboot fail: %d\n",
+                                               opp_vboot, ret);
+                                       goto svs_init01_finish;
+                               }
+
+                               search_done = true;
+                       } else {
+                               ret = dev_pm_opp_disable(svsb->opp_dev,
+                                                        svsb->opp_dfreq[i]);
+                               if (ret) {
+                                       dev_err(svsb->dev,
+                                               "opp %uHz disable fail: %d\n",
+                                               svsb->opp_dfreq[i], ret);
+                                       goto svs_init01_finish;
+                               }
+                       }
+               }
+       }
+
+       /* Svs bank init01 begins */
+       for (idx = 0; idx < svsp->bank_max; idx++) {
+               svsb = &svsp->banks[idx];
+
+               if (!(svsb->mode_support & SVSB_MODE_INIT01))
+                       continue;
+
+               opp_vboot = svs_bank_volt_to_opp_volt(svsb->vboot,
+                                                     svsb->volt_step,
+                                                     svsb->volt_base);
+
+               buck_volt = regulator_get_voltage(svsb->buck);
+               if (buck_volt != opp_vboot) {
+                       dev_err(svsb->dev,
+                               "buck voltage: %uuV, expected vboot: %uuV\n",
+                               buck_volt, opp_vboot);
+                       ret = -EPERM;
+                       goto svs_init01_finish;
+               }
+
+               spin_lock_irqsave(&svs_lock, flags);
+               svsp->pbank = svsb;
+               svs_set_bank_phase(svsp, SVSB_PHASE_INIT01);
+               spin_unlock_irqrestore(&svs_lock, flags);
+
+               time_left = wait_for_completion_timeout(&svsb->init_completion,
+                                                       msecs_to_jiffies(5000));
+               if (!time_left) {
+                       dev_err(svsb->dev, "init01 completion timeout\n");
+                       ret = -EBUSY;
+                       goto svs_init01_finish;
+               }
+       }
+
+svs_init01_finish:
+       for (idx = 0; idx < svsp->bank_max; idx++) {
+               svsb = &svsp->banks[idx];
+
+               if (!(svsb->mode_support & SVSB_MODE_INIT01))
+                       continue;
+
+               for (i = 0; i < svsb->opp_count; i++) {
+                       r = dev_pm_opp_enable(svsb->opp_dev,
+                                             svsb->opp_dfreq[i]);
+                       if (r)
+                               dev_err(svsb->dev, "opp %uHz enable fail: %d\n",
+                                       svsb->opp_dfreq[i], r);
+               }
+
+               if (svsb->volt_flags & SVSB_INIT01_PD_REQ) {
+                       r = pm_runtime_put_sync(svsb->opp_dev);
+                       if (r)
+                               dev_err(svsb->dev, "mtcmos off fail: %d\n", r);
+
+                       if (svsb->pm_runtime_enabled_count > 0) {
+                               pm_runtime_disable(svsb->opp_dev);
+                               svsb->pm_runtime_enabled_count--;
+                       }
+               }
+
+               r = regulator_set_mode(svsb->buck, REGULATOR_MODE_NORMAL);
+               if (r)
+                       dev_notice(svsb->dev, "set normal mode fail: %d\n", r);
+
+               r = regulator_disable(svsb->buck);
+               if (r)
+                       dev_err(svsb->dev, "%s disable fail: %d\n",
+                               svsb->buck_name, r);
+       }
+
+svs_init01_resume_cpuidle:
+       cpuidle_resume_and_unlock();
+
+       return ret;
+}
+
+static int svs_init02(struct svs_platform *svsp)
+{
+       struct svs_bank *svsb;
+       unsigned long flags, time_left;
+       u32 idx;
+
+       for (idx = 0; idx < svsp->bank_max; idx++) {
+               svsb = &svsp->banks[idx];
+
+               if (!(svsb->mode_support & SVSB_MODE_INIT02))
+                       continue;
+
+               reinit_completion(&svsb->init_completion);
+               spin_lock_irqsave(&svs_lock, flags);
+               svsp->pbank = svsb;
+               svs_set_bank_phase(svsp, SVSB_PHASE_INIT02);
+               spin_unlock_irqrestore(&svs_lock, flags);
+
+               time_left = wait_for_completion_timeout(&svsb->init_completion,
+                                                       msecs_to_jiffies(5000));
+               if (!time_left) {
+                       dev_err(svsb->dev, "init02 completion timeout\n");
+                       return -EBUSY;
+               }
+       }
+
+       /*
+        * 2-line high/low bank update its corresponding opp voltages only.
+        * Therefore, we sync voltages from opp for high/low bank voltages
+        * consistency.
+        */
+       for (idx = 0; idx < svsp->bank_max; idx++) {
+               svsb = &svsp->banks[idx];
+
+               if (!(svsb->mode_support & SVSB_MODE_INIT02))
+                       continue;
+
+               if (svsb->type == SVSB_HIGH || svsb->type == SVSB_LOW) {
+                       if (svs_sync_bank_volts_from_opp(svsb)) {
+                               dev_err(svsb->dev, "sync volt fail\n");
+                               return -EPERM;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static void svs_mon_mode(struct svs_platform *svsp)
+{
+       struct svs_bank *svsb;
+       unsigned long flags;
+       u32 idx;
+
+       for (idx = 0; idx < svsp->bank_max; idx++) {
+               svsb = &svsp->banks[idx];
+
+               if (!(svsb->mode_support & SVSB_MODE_MON))
+                       continue;
+
+               spin_lock_irqsave(&svs_lock, flags);
+               svsp->pbank = svsb;
+               svs_set_bank_phase(svsp, SVSB_PHASE_MON);
+               spin_unlock_irqrestore(&svs_lock, flags);
+       }
+}
+
+static int svs_start(struct svs_platform *svsp)
+{
+       int ret;
+
+       ret = svs_init01(svsp);
+       if (ret)
+               return ret;
+
+       ret = svs_init02(svsp);
+       if (ret)
+               return ret;
+
+       svs_mon_mode(svsp);
+
+       return 0;
+}
+
+static int svs_suspend(struct device *dev)
+{
+       struct svs_platform *svsp = dev_get_drvdata(dev);
+       struct svs_bank *svsb;
+       unsigned long flags;
+       int ret;
+       u32 idx;
+
+       for (idx = 0; idx < svsp->bank_max; idx++) {
+               svsb = &svsp->banks[idx];
+
+               /* This might wait for svs_isr() process */
+               spin_lock_irqsave(&svs_lock, flags);
+               svsp->pbank = svsb;
+               svs_switch_bank(svsp);
+               svs_writel_relaxed(svsp, SVSB_EN_OFF, SVSEN);
+               svs_writel_relaxed(svsp, SVSB_INTSTS_CLEAN, INTSTS);
+               spin_unlock_irqrestore(&svs_lock, flags);
+
+               svsb->phase = SVSB_PHASE_ERROR;
+               svs_adjust_pm_opp_volts(svsb);
+       }
+
+       ret = reset_control_assert(svsp->rst);
+       if (ret) {
+               dev_err(svsp->dev, "cannot assert reset %d\n", ret);
+               return ret;
+       }
+
+       clk_disable_unprepare(svsp->main_clk);
+
+       return 0;
+}
+
+static int svs_resume(struct device *dev)
+{
+       struct svs_platform *svsp = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(svsp->main_clk);
+       if (ret) {
+               dev_err(svsp->dev, "cannot enable main_clk, disable svs\n");
+               return ret;
+       }
+
+       ret = reset_control_deassert(svsp->rst);
+       if (ret) {
+               dev_err(svsp->dev, "cannot deassert reset %d\n", ret);
+               goto out_of_resume;
+       }
+
+       ret = svs_init02(svsp);
+       if (ret)
+               goto out_of_resume;
+
+       svs_mon_mode(svsp);
+
+       return 0;
+
+out_of_resume:
+       clk_disable_unprepare(svsp->main_clk);
+       return ret;
+}
+
+static int svs_bank_resource_setup(struct svs_platform *svsp)
+{
+       struct svs_bank *svsb;
+       struct dev_pm_opp *opp;
+       unsigned long freq;
+       int count, ret;
+       u32 idx, i;
+
+       dev_set_drvdata(svsp->dev, svsp);
+
+       for (idx = 0; idx < svsp->bank_max; idx++) {
+               svsb = &svsp->banks[idx];
+
+               switch (svsb->sw_id) {
+               case SVSB_CPU_LITTLE:
+                       svsb->name = "SVSB_CPU_LITTLE";
+                       break;
+               case SVSB_CPU_BIG:
+                       svsb->name = "SVSB_CPU_BIG";
+                       break;
+               case SVSB_CCI:
+                       svsb->name = "SVSB_CCI";
+                       break;
+               case SVSB_GPU:
+                       if (svsb->type == SVSB_HIGH)
+                               svsb->name = "SVSB_GPU_HIGH";
+                       else if (svsb->type == SVSB_LOW)
+                               svsb->name = "SVSB_GPU_LOW";
+                       else
+                               svsb->name = "SVSB_GPU";
+                       break;
+               default:
+                       dev_err(svsb->dev, "unknown sw_id: %u\n", svsb->sw_id);
+                       return -EINVAL;
+               }
+
+               svsb->dev = devm_kzalloc(svsp->dev, sizeof(*svsb->dev),
+                                        GFP_KERNEL);
+               if (!svsb->dev)
+                       return -ENOMEM;
+
+               ret = dev_set_name(svsb->dev, "%s", svsb->name);
+               if (ret)
+                       return ret;
+
+               dev_set_drvdata(svsb->dev, svsp);
+
+               ret = dev_pm_opp_of_add_table(svsb->opp_dev);
+               if (ret) {
+                       dev_err(svsb->dev, "add opp table fail: %d\n", ret);
+                       return ret;
+               }
+
+               mutex_init(&svsb->lock);
+               init_completion(&svsb->init_completion);
+
+               if (svsb->mode_support & SVSB_MODE_INIT01) {
+                       svsb->buck = devm_regulator_get_optional(svsb->opp_dev,
+                                                                svsb->buck_name);
+                       if (IS_ERR(svsb->buck)) {
+                               dev_err(svsb->dev, "cannot get \"%s-supply\"\n",
+                                       svsb->buck_name);
+                               return PTR_ERR(svsb->buck);
+                       }
+               }
+
+               if (svsb->mode_support & SVSB_MODE_MON) {
+                       svsb->tzd = thermal_zone_get_zone_by_name(svsb->tzone_name);
+                       if (IS_ERR(svsb->tzd)) {
+                               dev_err(svsb->dev, "cannot get \"%s\" thermal zone\n",
+                                       svsb->tzone_name);
+                               return PTR_ERR(svsb->tzd);
+                       }
+               }
+
+               count = dev_pm_opp_get_opp_count(svsb->opp_dev);
+               if (svsb->opp_count != count) {
+                       dev_err(svsb->dev,
+                               "opp_count not \"%u\" but get \"%d\"?\n",
+                               svsb->opp_count, count);
+                       return count;
+               }
+
+               for (i = 0, freq = U32_MAX; i < svsb->opp_count; i++, freq--) {
+                       opp = dev_pm_opp_find_freq_floor(svsb->opp_dev, &freq);
+                       if (IS_ERR(opp)) {
+                               dev_err(svsb->dev, "cannot find freq = %ld\n",
+                                       PTR_ERR(opp));
+                               return PTR_ERR(opp);
+                       }
+
+                       svsb->opp_dfreq[i] = freq;
+                       svsb->opp_dvolt[i] = dev_pm_opp_get_voltage(opp);
+                       svsb->freq_pct[i] = percent(svsb->opp_dfreq[i],
+                                                   svsb->freq_base);
+                       dev_pm_opp_put(opp);
+               }
+       }
+
+       return 0;
+}
+
+static bool svs_mt8192_efuse_parsing(struct svs_platform *svsp)
+{
+       struct svs_bank *svsb;
+       struct nvmem_cell *cell;
+       u32 idx, i, vmin, golden_temp;
+
+       for (i = 0; i < svsp->efuse_max; i++)
+               if (svsp->efuse[i])
+                       dev_info(svsp->dev, "M_HW_RES%d: 0x%08x\n",
+                                i, svsp->efuse[i]);
+
+       if (!svsp->efuse[9]) {
+               dev_notice(svsp->dev, "svs_efuse[9] = 0x0?\n");
+               return false;
+       }
+
+       /* Svs efuse parsing */
+       vmin = (svsp->efuse[19] >> 4) & GENMASK(1, 0);
+
+       for (idx = 0; idx < svsp->bank_max; idx++) {
+               svsb = &svsp->banks[idx];
+
+               if (vmin == 0x1)
+                       svsb->vmin = 0x1e;
+
+               if (svsb->type == SVSB_LOW) {
+                       svsb->mtdes = svsp->efuse[10] & GENMASK(7, 0);
+                       svsb->bdes = (svsp->efuse[10] >> 16) & GENMASK(7, 0);
+                       svsb->mdes = (svsp->efuse[10] >> 24) & GENMASK(7, 0);
+                       svsb->dcbdet = (svsp->efuse[17]) & GENMASK(7, 0);
+                       svsb->dcmdet = (svsp->efuse[17] >> 8) & GENMASK(7, 0);
+               } else if (svsb->type == SVSB_HIGH) {
+                       svsb->mtdes = svsp->efuse[9] & GENMASK(7, 0);
+                       svsb->bdes = (svsp->efuse[9] >> 16) & GENMASK(7, 0);
+                       svsb->mdes = (svsp->efuse[9] >> 24) & GENMASK(7, 0);
+                       svsb->dcbdet = (svsp->efuse[17] >> 16) & GENMASK(7, 0);
+                       svsb->dcmdet = (svsp->efuse[17] >> 24) & GENMASK(7, 0);
+               }
+
+               svsb->vmax += svsb->dvt_fixed;
+       }
+
+       /* Thermal efuse parsing */
+       cell = nvmem_cell_get(svsp->dev, "t-calibration-data");
+       if (IS_ERR_OR_NULL(cell)) {
+               dev_err(svsp->dev, "no \"t-calibration-data\"? %ld\n",
+                       PTR_ERR(cell));
+               return false;
+       }
+
+       svsp->tefuse = nvmem_cell_read(cell, &svsp->tefuse_max);
+       if (IS_ERR(svsp->tefuse)) {
+               dev_err(svsp->dev, "cannot read thermal efuse: %ld\n",
+                       PTR_ERR(svsp->tefuse));
+               nvmem_cell_put(cell);
+               return false;
+       }
+
+       svsp->tefuse_max /= sizeof(u32);
+       nvmem_cell_put(cell);
+
+       for (i = 0; i < svsp->tefuse_max; i++)
+               if (svsp->tefuse[i] != 0)
+                       break;
+
+       if (i == svsp->tefuse_max)
+               golden_temp = 50; /* All thermal efuse data are 0 */
+       else
+               golden_temp = (svsp->tefuse[0] >> 24) & GENMASK(7, 0);
+
+       for (idx = 0; idx < svsp->bank_max; idx++) {
+               svsb = &svsp->banks[idx];
+               svsb->mts = 500;
+               svsb->bts = (((500 * golden_temp + 250460) / 1000) - 25) * 4;
+       }
+
+       return true;
+}
+
+static bool svs_mt8183_efuse_parsing(struct svs_platform *svsp)
+{
+       struct svs_bank *svsb;
+       struct nvmem_cell *cell;
+       int format[6], x_roomt[6], o_vtsmcu[5], o_vtsabb, tb_roomt = 0;
+       int adc_ge_t, adc_oe_t, ge, oe, gain, degc_cali, adc_cali_en_t;
+       int o_slope, o_slope_sign, ts_id;
+       u32 idx, i, ft_pgm, mts, temp0, temp1, temp2;
+
+       for (i = 0; i < svsp->efuse_max; i++)
+               if (svsp->efuse[i])
+                       dev_info(svsp->dev, "M_HW_RES%d: 0x%08x\n",
+                                i, svsp->efuse[i]);
+
+       if (!svsp->efuse[2]) {
+               dev_notice(svsp->dev, "svs_efuse[2] = 0x0?\n");
+               return false;
+       }
+
+       /* Svs efuse parsing */
+       ft_pgm = (svsp->efuse[0] >> 4) & GENMASK(3, 0);
+
+       for (idx = 0; idx < svsp->bank_max; idx++) {
+               svsb = &svsp->banks[idx];
+
+               if (ft_pgm <= 1)
+                       svsb->volt_flags |= SVSB_INIT01_VOLT_IGNORE;
+
+               switch (svsb->sw_id) {
+               case SVSB_CPU_LITTLE:
+                       svsb->bdes = svsp->efuse[16] & GENMASK(7, 0);
+                       svsb->mdes = (svsp->efuse[16] >> 8) & GENMASK(7, 0);
+                       svsb->dcbdet = (svsp->efuse[16] >> 16) & GENMASK(7, 0);
+                       svsb->dcmdet = (svsp->efuse[16] >> 24) & GENMASK(7, 0);
+                       svsb->mtdes  = (svsp->efuse[17] >> 16) & GENMASK(7, 0);
+
+                       if (ft_pgm <= 3)
+                               svsb->volt_od += 10;
+                       else
+                               svsb->volt_od += 2;
+                       break;
+               case SVSB_CPU_BIG:
+                       svsb->bdes = svsp->efuse[18] & GENMASK(7, 0);
+                       svsb->mdes = (svsp->efuse[18] >> 8) & GENMASK(7, 0);
+                       svsb->dcbdet = (svsp->efuse[18] >> 16) & GENMASK(7, 0);
+                       svsb->dcmdet = (svsp->efuse[18] >> 24) & GENMASK(7, 0);
+                       svsb->mtdes  = svsp->efuse[17] & GENMASK(7, 0);
+
+                       if (ft_pgm <= 3)
+                               svsb->volt_od += 15;
+                       else
+                               svsb->volt_od += 12;
+                       break;
+               case SVSB_CCI:
+                       svsb->bdes = svsp->efuse[4] & GENMASK(7, 0);
+                       svsb->mdes = (svsp->efuse[4] >> 8) & GENMASK(7, 0);
+                       svsb->dcbdet = (svsp->efuse[4] >> 16) & GENMASK(7, 0);
+                       svsb->dcmdet = (svsp->efuse[4] >> 24) & GENMASK(7, 0);
+                       svsb->mtdes  = (svsp->efuse[5] >> 16) & GENMASK(7, 0);
+
+                       if (ft_pgm <= 3)
+                               svsb->volt_od += 10;
+                       else
+                               svsb->volt_od += 2;
+                       break;
+               case SVSB_GPU:
+                       svsb->bdes = svsp->efuse[6] & GENMASK(7, 0);
+                       svsb->mdes = (svsp->efuse[6] >> 8) & GENMASK(7, 0);
+                       svsb->dcbdet = (svsp->efuse[6] >> 16) & GENMASK(7, 0);
+                       svsb->dcmdet = (svsp->efuse[6] >> 24) & GENMASK(7, 0);
+                       svsb->mtdes  = svsp->efuse[5] & GENMASK(7, 0);
+
+                       if (ft_pgm >= 2) {
+                               svsb->freq_base = 800000000; /* 800MHz */
+                               svsb->dvt_fixed = 2;
+                       }
+                       break;
+               default:
+                       dev_err(svsb->dev, "unknown sw_id: %u\n", svsb->sw_id);
+                       return false;
+               }
+       }
+
+       /* Get thermal efuse by nvmem */
+       cell = nvmem_cell_get(svsp->dev, "t-calibration-data");
+       if (IS_ERR(cell)) {
+               dev_err(svsp->dev, "no \"t-calibration-data\"? %ld\n",
+                       PTR_ERR(cell));
+               goto remove_mt8183_svsb_mon_mode;
+       }
+
+       svsp->tefuse = nvmem_cell_read(cell, &svsp->tefuse_max);
+       if (IS_ERR(svsp->tefuse)) {
+               dev_err(svsp->dev, "cannot read thermal efuse: %ld\n",
+                       PTR_ERR(svsp->tefuse));
+               nvmem_cell_put(cell);
+               goto remove_mt8183_svsb_mon_mode;
+       }
+
+       svsp->tefuse_max /= sizeof(u32);
+       nvmem_cell_put(cell);
+
+       /* Thermal efuse parsing */
+       adc_ge_t = (svsp->tefuse[1] >> 22) & GENMASK(9, 0);
+       adc_oe_t = (svsp->tefuse[1] >> 12) & GENMASK(9, 0);
+
+       o_vtsmcu[0] = (svsp->tefuse[0] >> 17) & GENMASK(8, 0);
+       o_vtsmcu[1] = (svsp->tefuse[0] >> 8) & GENMASK(8, 0);
+       o_vtsmcu[2] = svsp->tefuse[1] & GENMASK(8, 0);
+       o_vtsmcu[3] = (svsp->tefuse[2] >> 23) & GENMASK(8, 0);
+       o_vtsmcu[4] = (svsp->tefuse[2] >> 5) & GENMASK(8, 0);
+       o_vtsabb = (svsp->tefuse[2] >> 14) & GENMASK(8, 0);
+
+       degc_cali = (svsp->tefuse[0] >> 1) & GENMASK(5, 0);
+       adc_cali_en_t = svsp->tefuse[0] & BIT(0);
+       o_slope_sign = (svsp->tefuse[0] >> 7) & BIT(0);
+
+       ts_id = (svsp->tefuse[1] >> 9) & BIT(0);
+       o_slope = (svsp->tefuse[0] >> 26) & GENMASK(5, 0);
+
+       if (adc_cali_en_t == 1) {
+               if (!ts_id)
+                       o_slope = 0;
+
+               if (adc_ge_t < 265 || adc_ge_t > 758 ||
+                   adc_oe_t < 265 || adc_oe_t > 758 ||
+                   o_vtsmcu[0] < -8 || o_vtsmcu[0] > 484 ||
+                   o_vtsmcu[1] < -8 || o_vtsmcu[1] > 484 ||
+                   o_vtsmcu[2] < -8 || o_vtsmcu[2] > 484 ||
+                   o_vtsmcu[3] < -8 || o_vtsmcu[3] > 484 ||
+                   o_vtsmcu[4] < -8 || o_vtsmcu[4] > 484 ||
+                   o_vtsabb < -8 || o_vtsabb > 484 ||
+                   degc_cali < 1 || degc_cali > 63) {
+                       dev_err(svsp->dev, "bad thermal efuse, no mon mode\n");
+                       goto remove_mt8183_svsb_mon_mode;
+               }
+       } else {
+               dev_err(svsp->dev, "no thermal efuse, no mon mode\n");
+               goto remove_mt8183_svsb_mon_mode;
+       }
+
+       ge = ((adc_ge_t - 512) * 10000) / 4096;
+       oe = (adc_oe_t - 512);
+       gain = (10000 + ge);
+
+       format[0] = (o_vtsmcu[0] + 3350 - oe);
+       format[1] = (o_vtsmcu[1] + 3350 - oe);
+       format[2] = (o_vtsmcu[2] + 3350 - oe);
+       format[3] = (o_vtsmcu[3] + 3350 - oe);
+       format[4] = (o_vtsmcu[4] + 3350 - oe);
+       format[5] = (o_vtsabb + 3350 - oe);
+
+       for (i = 0; i < 6; i++)
+               x_roomt[i] = (((format[i] * 10000) / 4096) * 10000) / gain;
+
+       temp0 = (10000 * 100000 / gain) * 15 / 18;
+
+       if (!o_slope_sign)
+               mts = (temp0 * 10) / (1534 + o_slope * 10);
+       else
+               mts = (temp0 * 10) / (1534 - o_slope * 10);
+
+       for (idx = 0; idx < svsp->bank_max; idx++) {
+               svsb = &svsp->banks[idx];
+               svsb->mts = mts;
+
+               switch (svsb->sw_id) {
+               case SVSB_CPU_LITTLE:
+                       tb_roomt = x_roomt[3];
+                       break;
+               case SVSB_CPU_BIG:
+                       tb_roomt = x_roomt[4];
+                       break;
+               case SVSB_CCI:
+                       tb_roomt = x_roomt[3];
+                       break;
+               case SVSB_GPU:
+                       tb_roomt = x_roomt[1];
+                       break;
+               default:
+                       dev_err(svsb->dev, "unknown sw_id: %u\n", svsb->sw_id);
+                       goto remove_mt8183_svsb_mon_mode;
+               }
+
+               temp0 = (degc_cali * 10 / 2);
+               temp1 = ((10000 * 100000 / 4096 / gain) *
+                        oe + tb_roomt * 10) * 15 / 18;
+
+               if (!o_slope_sign)
+                       temp2 = temp1 * 100 / (1534 + o_slope * 10);
+               else
+                       temp2 = temp1 * 100 / (1534 - o_slope * 10);
+
+               svsb->bts = (temp0 + temp2 - 250) * 4 / 10;
+       }
+
+       return true;
+
+remove_mt8183_svsb_mon_mode:
+       for (idx = 0; idx < svsp->bank_max; idx++) {
+               svsb = &svsp->banks[idx];
+               svsb->mode_support &= ~SVSB_MODE_MON;
+       }
+
+       return true;
+}
+
+static bool svs_is_efuse_data_correct(struct svs_platform *svsp)
+{
+       struct nvmem_cell *cell;
+
+       /* Get svs efuse by nvmem */
+       cell = nvmem_cell_get(svsp->dev, "svs-calibration-data");
+       if (IS_ERR(cell)) {
+               dev_err(svsp->dev, "no \"svs-calibration-data\"? %ld\n",
+                       PTR_ERR(cell));
+               return false;
+       }
+
+       svsp->efuse = nvmem_cell_read(cell, &svsp->efuse_max);
+       if (IS_ERR(svsp->efuse)) {
+               dev_err(svsp->dev, "cannot read svs efuse: %ld\n",
+                       PTR_ERR(svsp->efuse));
+               nvmem_cell_put(cell);
+               return false;
+       }
+
+       svsp->efuse_max /= sizeof(u32);
+       nvmem_cell_put(cell);
+
+       return svsp->efuse_parsing(svsp);
+}
+
+static struct device *svs_get_subsys_device(struct svs_platform *svsp,
+                                           const char *node_name)
+{
+       struct platform_device *pdev;
+       struct device_node *np;
+
+       np = of_find_node_by_name(NULL, node_name);
+       if (!np) {
+               dev_err(svsp->dev, "cannot find %s node\n", node_name);
+               return ERR_PTR(-ENODEV);
+       }
+
+       pdev = of_find_device_by_node(np);
+       if (!pdev) {
+               of_node_put(np);
+               dev_err(svsp->dev, "cannot find pdev by %s\n", node_name);
+               return ERR_PTR(-ENXIO);
+       }
+
+       of_node_put(np);
+
+       return &pdev->dev;
+}
+
+static struct device *svs_add_device_link(struct svs_platform *svsp,
+                                         const char *node_name)
+{
+       struct device *dev;
+       struct device_link *sup_link;
+
+       if (!node_name) {
+               dev_err(svsp->dev, "node name cannot be null\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       dev = svs_get_subsys_device(svsp, node_name);
+       if (IS_ERR(dev))
+               return dev;
+
+       sup_link = device_link_add(svsp->dev, dev,
+                                  DL_FLAG_AUTOREMOVE_CONSUMER);
+       if (!sup_link) {
+               dev_err(svsp->dev, "sup_link is NULL\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       if (sup_link->supplier->links.status != DL_DEV_DRIVER_BOUND)
+               return ERR_PTR(-EPROBE_DEFER);
+
+       return dev;
+}
+
+static int svs_mt8192_platform_probe(struct svs_platform *svsp)
+{
+       struct device *dev;
+       struct svs_bank *svsb;
+       u32 idx;
+
+       svsp->rst = devm_reset_control_get_optional(svsp->dev, "svs_rst");
+       if (IS_ERR(svsp->rst))
+               return dev_err_probe(svsp->dev, PTR_ERR(svsp->rst),
+                                    "cannot get svs reset control\n");
+
+       dev = svs_add_device_link(svsp, "lvts");
+       if (IS_ERR(dev))
+               return dev_err_probe(svsp->dev, PTR_ERR(dev),
+                                    "failed to get lvts device\n");
+
+       for (idx = 0; idx < svsp->bank_max; idx++) {
+               svsb = &svsp->banks[idx];
+
+               if (svsb->type == SVSB_HIGH)
+                       svsb->opp_dev = svs_add_device_link(svsp, "mali");
+               else if (svsb->type == SVSB_LOW)
+                       svsb->opp_dev = svs_get_subsys_device(svsp, "mali");
+
+               if (IS_ERR(svsb->opp_dev))
+                       return dev_err_probe(svsp->dev, PTR_ERR(svsb->opp_dev),
+                                            "failed to get OPP device for bank %d\n",
+                                            idx);
+       }
+
+       return 0;
+}
+
+static int svs_mt8183_platform_probe(struct svs_platform *svsp)
+{
+       struct device *dev;
+       struct svs_bank *svsb;
+       u32 idx;
+
+       dev = svs_add_device_link(svsp, "thermal");
+       if (IS_ERR(dev))
+               return dev_err_probe(svsp->dev, PTR_ERR(dev),
+                                    "failed to get thermal device\n");
+
+       for (idx = 0; idx < svsp->bank_max; idx++) {
+               svsb = &svsp->banks[idx];
+
+               switch (svsb->sw_id) {
+               case SVSB_CPU_LITTLE:
+               case SVSB_CPU_BIG:
+                       svsb->opp_dev = get_cpu_device(svsb->cpu_id);
+                       break;
+               case SVSB_CCI:
+                       svsb->opp_dev = svs_add_device_link(svsp, "cci");
+                       break;
+               case SVSB_GPU:
+                       svsb->opp_dev = svs_add_device_link(svsp, "gpu");
+                       break;
+               default:
+                       dev_err(svsb->dev, "unknown sw_id: %u\n", svsb->sw_id);
+                       return -EINVAL;
+               }
+
+               if (IS_ERR(svsb->opp_dev))
+                       return dev_err_probe(svsp->dev, PTR_ERR(svsb->opp_dev),
+                                            "failed to get OPP device for bank %d\n",
+                                            idx);
+       }
+
+       return 0;
+}
+
+static struct svs_bank svs_mt8192_banks[] = {
+       {
+               .sw_id                  = SVSB_GPU,
+               .type                   = SVSB_LOW,
+               .set_freq_pct           = svs_set_bank_freq_pct_v3,
+               .get_volts              = svs_get_bank_volts_v3,
+               .volt_flags             = SVSB_REMOVE_DVTFIXED_VOLT,
+               .mode_support           = SVSB_MODE_INIT02,
+               .opp_count              = MAX_OPP_ENTRIES,
+               .freq_base              = 688000000,
+               .turn_freq_base         = 688000000,
+               .volt_step              = 6250,
+               .volt_base              = 400000,
+               .vmax                   = 0x60,
+               .vmin                   = 0x1a,
+               .age_config             = 0x555555,
+               .dc_config              = 0x1,
+               .dvt_fixed              = 0x1,
+               .vco                    = 0x18,
+               .chk_shift              = 0x87,
+               .core_sel               = 0x0fff0100,
+               .int_st                 = BIT(0),
+               .ctl0                   = 0x00540003,
+       },
+       {
+               .sw_id                  = SVSB_GPU,
+               .type                   = SVSB_HIGH,
+               .set_freq_pct           = svs_set_bank_freq_pct_v3,
+               .get_volts              = svs_get_bank_volts_v3,
+               .tzone_name             = "gpu1",
+               .volt_flags             = SVSB_REMOVE_DVTFIXED_VOLT |
+                                         SVSB_MON_VOLT_IGNORE,
+               .mode_support           = SVSB_MODE_INIT02 | SVSB_MODE_MON,
+               .opp_count              = MAX_OPP_ENTRIES,
+               .freq_base              = 902000000,
+               .turn_freq_base         = 688000000,
+               .volt_step              = 6250,
+               .volt_base              = 400000,
+               .vmax                   = 0x60,
+               .vmin                   = 0x1a,
+               .age_config             = 0x555555,
+               .dc_config              = 0x1,
+               .dvt_fixed              = 0x6,
+               .vco                    = 0x18,
+               .chk_shift              = 0x87,
+               .core_sel               = 0x0fff0101,
+               .int_st                 = BIT(1),
+               .ctl0                   = 0x00540003,
+               .tzone_htemp            = 85000,
+               .tzone_htemp_voffset    = 0,
+               .tzone_ltemp            = 25000,
+               .tzone_ltemp_voffset    = 7,
+       },
+};
+
+static struct svs_bank svs_mt8183_banks[] = {
+       {
+               .sw_id                  = SVSB_CPU_LITTLE,
+               .set_freq_pct           = svs_set_bank_freq_pct_v2,
+               .get_volts              = svs_get_bank_volts_v2,
+               .cpu_id                 = 0,
+               .buck_name              = "proc",
+               .volt_flags             = SVSB_INIT01_VOLT_INC_ONLY,
+               .mode_support           = SVSB_MODE_INIT01 | SVSB_MODE_INIT02,
+               .opp_count              = MAX_OPP_ENTRIES,
+               .freq_base              = 1989000000,
+               .vboot                  = 0x30,
+               .volt_step              = 6250,
+               .volt_base              = 500000,
+               .vmax                   = 0x64,
+               .vmin                   = 0x18,
+               .age_config             = 0x555555,
+               .dc_config              = 0x555555,
+               .dvt_fixed              = 0x7,
+               .vco                    = 0x10,
+               .chk_shift              = 0x77,
+               .core_sel               = 0x8fff0000,
+               .int_st                 = BIT(0),
+               .ctl0                   = 0x00010001,
+       },
+       {
+               .sw_id                  = SVSB_CPU_BIG,
+               .set_freq_pct           = svs_set_bank_freq_pct_v2,
+               .get_volts              = svs_get_bank_volts_v2,
+               .cpu_id                 = 4,
+               .buck_name              = "proc",
+               .volt_flags             = SVSB_INIT01_VOLT_INC_ONLY,
+               .mode_support           = SVSB_MODE_INIT01 | SVSB_MODE_INIT02,
+               .opp_count              = MAX_OPP_ENTRIES,
+               .freq_base              = 1989000000,
+               .vboot                  = 0x30,
+               .volt_step              = 6250,
+               .volt_base              = 500000,
+               .vmax                   = 0x58,
+               .vmin                   = 0x10,
+               .age_config             = 0x555555,
+               .dc_config              = 0x555555,
+               .dvt_fixed              = 0x7,
+               .vco                    = 0x10,
+               .chk_shift              = 0x77,
+               .core_sel               = 0x8fff0001,
+               .int_st                 = BIT(1),
+               .ctl0                   = 0x00000001,
+       },
+       {
+               .sw_id                  = SVSB_CCI,
+               .set_freq_pct           = svs_set_bank_freq_pct_v2,
+               .get_volts              = svs_get_bank_volts_v2,
+               .buck_name              = "proc",
+               .volt_flags             = SVSB_INIT01_VOLT_INC_ONLY,
+               .mode_support           = SVSB_MODE_INIT01 | SVSB_MODE_INIT02,
+               .opp_count              = MAX_OPP_ENTRIES,
+               .freq_base              = 1196000000,
+               .vboot                  = 0x30,
+               .volt_step              = 6250,
+               .volt_base              = 500000,
+               .vmax                   = 0x64,
+               .vmin                   = 0x18,
+               .age_config             = 0x555555,
+               .dc_config              = 0x555555,
+               .dvt_fixed              = 0x7,
+               .vco                    = 0x10,
+               .chk_shift              = 0x77,
+               .core_sel               = 0x8fff0002,
+               .int_st                 = BIT(2),
+               .ctl0                   = 0x00100003,
+       },
+       {
+               .sw_id                  = SVSB_GPU,
+               .set_freq_pct           = svs_set_bank_freq_pct_v2,
+               .get_volts              = svs_get_bank_volts_v2,
+               .buck_name              = "mali",
+               .tzone_name             = "tzts2",
+               .volt_flags             = SVSB_INIT01_PD_REQ |
+                                         SVSB_INIT01_VOLT_INC_ONLY,
+               .mode_support           = SVSB_MODE_INIT01 | SVSB_MODE_INIT02 |
+                                         SVSB_MODE_MON,
+               .opp_count              = MAX_OPP_ENTRIES,
+               .freq_base              = 900000000,
+               .vboot                  = 0x30,
+               .volt_step              = 6250,
+               .volt_base              = 500000,
+               .vmax                   = 0x40,
+               .vmin                   = 0x14,
+               .age_config             = 0x555555,
+               .dc_config              = 0x555555,
+               .dvt_fixed              = 0x3,
+               .vco                    = 0x10,
+               .chk_shift              = 0x77,
+               .core_sel               = 0x8fff0003,
+               .int_st                 = BIT(3),
+               .ctl0                   = 0x00050001,
+               .tzone_htemp            = 85000,
+               .tzone_htemp_voffset    = 0,
+               .tzone_ltemp            = 25000,
+               .tzone_ltemp_voffset    = 3,
+       },
+};
+
+static const struct svs_platform_data svs_mt8192_platform_data = {
+       .name = "mt8192-svs",
+       .banks = svs_mt8192_banks,
+       .efuse_parsing = svs_mt8192_efuse_parsing,
+       .probe = svs_mt8192_platform_probe,
+       .irqflags = IRQF_TRIGGER_HIGH,
+       .regs = svs_regs_v2,
+       .bank_max = ARRAY_SIZE(svs_mt8192_banks),
+};
+
+static const struct svs_platform_data svs_mt8183_platform_data = {
+       .name = "mt8183-svs",
+       .banks = svs_mt8183_banks,
+       .efuse_parsing = svs_mt8183_efuse_parsing,
+       .probe = svs_mt8183_platform_probe,
+       .irqflags = IRQF_TRIGGER_LOW,
+       .regs = svs_regs_v2,
+       .bank_max = ARRAY_SIZE(svs_mt8183_banks),
+};
+
+static const struct of_device_id svs_of_match[] = {
+       {
+               .compatible = "mediatek,mt8192-svs",
+               .data = &svs_mt8192_platform_data,
+       }, {
+               .compatible = "mediatek,mt8183-svs",
+               .data = &svs_mt8183_platform_data,
+       }, {
+               /* Sentinel */
+       },
+};
+
+static struct svs_platform *svs_platform_probe(struct platform_device *pdev)
+{
+       struct svs_platform *svsp;
+       const struct svs_platform_data *svsp_data;
+       int ret;
+
+       svsp_data = of_device_get_match_data(&pdev->dev);
+       if (!svsp_data) {
+               dev_err(&pdev->dev, "no svs platform data?\n");
+               return ERR_PTR(-EPERM);
+       }
+
+       svsp = devm_kzalloc(&pdev->dev, sizeof(*svsp), GFP_KERNEL);
+       if (!svsp)
+               return ERR_PTR(-ENOMEM);
+
+       svsp->dev = &pdev->dev;
+       svsp->name = svsp_data->name;
+       svsp->banks = svsp_data->banks;
+       svsp->efuse_parsing = svsp_data->efuse_parsing;
+       svsp->probe = svsp_data->probe;
+       svsp->irqflags = svsp_data->irqflags;
+       svsp->regs = svsp_data->regs;
+       svsp->bank_max = svsp_data->bank_max;
+
+       ret = svsp->probe(svsp);
+       if (ret)
+               return ERR_PTR(ret);
+
+       return svsp;
+}
+
+static int svs_probe(struct platform_device *pdev)
+{
+       struct svs_platform *svsp;
+       unsigned int svsp_irq;
+       int ret;
+
+       svsp = svs_platform_probe(pdev);
+       if (IS_ERR(svsp))
+               return PTR_ERR(svsp);
+
+       if (!svs_is_efuse_data_correct(svsp)) {
+               dev_notice(svsp->dev, "efuse data isn't correct\n");
+               ret = -EPERM;
+               goto svs_probe_free_resource;
+       }
+
+       ret = svs_bank_resource_setup(svsp);
+       if (ret) {
+               dev_err(svsp->dev, "svs bank resource setup fail: %d\n", ret);
+               goto svs_probe_free_resource;
+       }
+
+       svsp_irq = irq_of_parse_and_map(svsp->dev->of_node, 0);
+       ret = devm_request_threaded_irq(svsp->dev, svsp_irq, NULL, svs_isr,
+                                       svsp->irqflags | IRQF_ONESHOT,
+                                       svsp->name, svsp);
+       if (ret) {
+               dev_err(svsp->dev, "register irq(%d) failed: %d\n",
+                       svsp_irq, ret);
+               goto svs_probe_free_resource;
+       }
+
+       svsp->main_clk = devm_clk_get(svsp->dev, "main");
+       if (IS_ERR(svsp->main_clk)) {
+               dev_err(svsp->dev, "failed to get clock: %ld\n",
+                       PTR_ERR(svsp->main_clk));
+               ret = PTR_ERR(svsp->main_clk);
+               goto svs_probe_free_resource;
+       }
+
+       ret = clk_prepare_enable(svsp->main_clk);
+       if (ret) {
+               dev_err(svsp->dev, "cannot enable main clk: %d\n", ret);
+               goto svs_probe_free_resource;
+       }
+
+       svsp->base = of_iomap(svsp->dev->of_node, 0);
+       if (IS_ERR_OR_NULL(svsp->base)) {
+               dev_err(svsp->dev, "cannot find svs register base\n");
+               ret = -EINVAL;
+               goto svs_probe_clk_disable;
+       }
+
+       ret = svs_start(svsp);
+       if (ret) {
+               dev_err(svsp->dev, "svs start fail: %d\n", ret);
+               goto svs_probe_iounmap;
+       }
+
+       ret = svs_create_debug_cmds(svsp);
+       if (ret) {
+               dev_err(svsp->dev, "svs create debug cmds fail: %d\n", ret);
+               goto svs_probe_iounmap;
+       }
+
+       return 0;
+
+svs_probe_iounmap:
+       iounmap(svsp->base);
+
+svs_probe_clk_disable:
+       clk_disable_unprepare(svsp->main_clk);
+
+svs_probe_free_resource:
+       if (!IS_ERR_OR_NULL(svsp->efuse))
+               kfree(svsp->efuse);
+       if (!IS_ERR_OR_NULL(svsp->tefuse))
+               kfree(svsp->tefuse);
+
+       return ret;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(svs_pm_ops, svs_suspend, svs_resume);
+
+static struct platform_driver svs_driver = {
+       .probe  = svs_probe,
+       .driver = {
+               .name           = "mtk-svs",
+               .pm             = &svs_pm_ops,
+               .of_match_table = of_match_ptr(svs_of_match),
+       },
+};
+
+module_platform_driver(svs_driver);
+
+MODULE_AUTHOR("Roger Lu <roger.lu@mediatek.com>");
+MODULE_DESCRIPTION("MediaTek SVS driver");
+MODULE_LICENSE("GPL");
index e718b87..e0d7a54 100644 (file)
@@ -129,7 +129,10 @@ config QCOM_RPMHPD
 
 config QCOM_RPMPD
        tristate "Qualcomm RPM Power domain driver"
+       depends on PM
        depends on QCOM_SMD_RPM
+       select PM_GENERIC_DOMAINS
+       select PM_GENERIC_DOMAINS_OF
        help
          QCOM RPM Power domain driver to support power-domains with
          performance states. The driver communicates a performance state
@@ -228,4 +231,19 @@ config QCOM_APR
          application processor and QDSP6. APR is
          used by audio driver to configure QDSP6
          ASM, ADM and AFE modules.
+
+config QCOM_ICC_BWMON
+       tristate "QCOM Interconnect Bandwidth Monitor driver"
+       depends on ARCH_QCOM || COMPILE_TEST
+       select PM_OPP
+       help
+         Sets up driver monitoring bandwidth on various interconnects and
+         based on that voting for interconnect bandwidth, adjusting their
+         speed to current demand.
+         Current implementation brings support for BWMON v4, used for example
+         on SDM845 to measure bandwidth between CPU (gladiator_noc) and Last
+         Level Cache (memnoc).  Usage of this BWMON allows to remove some of
+         the fixed bandwidth votes from cpufreq (CPU nodes) thus achieve high
+         memory throughput even with lower CPU frequencies.
+
 endmenu
index 70d5de6..d66604a 100644 (file)
@@ -28,3 +28,4 @@ obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o
 obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o
 obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o
 obj-$(CONFIG_QCOM_KRYO_L2_ACCESSORS) +=        kryo-l2-accessors.o
+obj-$(CONFIG_QCOM_ICC_BWMON)   += icc-bwmon.o
index 3caabd8..b4046f3 100644 (file)
@@ -377,17 +377,14 @@ static int apr_device_probe(struct device *dev)
 static void apr_device_remove(struct device *dev)
 {
        struct apr_device *adev = to_apr_device(dev);
-       struct apr_driver *adrv;
+       struct apr_driver *adrv = to_apr_driver(dev->driver);
        struct packet_router *apr = dev_get_drvdata(adev->dev.parent);
 
-       if (dev->driver) {
-               adrv = to_apr_driver(dev->driver);
-               if (adrv->remove)
-                       adrv->remove(adev);
-               spin_lock(&apr->svcs_lock);
-               idr_remove(&apr->svcs_idr, adev->svc.id);
-               spin_unlock(&apr->svcs_lock);
-       }
+       if (adrv->remove)
+               adrv->remove(adev);
+       spin_lock(&apr->svcs_lock);
+       idr_remove(&apr->svcs_idr, adev->svc.id);
+       spin_unlock(&apr->svcs_lock);
 }
 
 static int apr_uevent(struct device *dev, struct kobj_uevent_env *env)
index dd87201..629a718 100644 (file)
@@ -141,13 +141,17 @@ static int cmd_db_get_header(const char *id, const struct entry_header **eh,
        const struct rsc_hdr *rsc_hdr;
        const struct entry_header *ent;
        int ret, i, j;
-       u8 query[8];
+       u8 query[sizeof(ent->id)] __nonstring;
 
        ret = cmd_db_ready();
        if (ret)
                return ret;
 
-       /* Pad out query string to same length as in DB */
+       /*
+        * Pad out query string to same length as in DB. NOTE: the output
+        * query string is not necessarily '\0' terminated if it bumps up
+        * against the max size. That's OK and expected.
+        */
        strncpy(query, id, sizeof(query));
 
        for (i = 0; i < MAX_SLV_ID; i++) {
diff --git a/drivers/soc/qcom/icc-bwmon.c b/drivers/soc/qcom/icc-bwmon.c
new file mode 100644 (file)
index 0000000..7f8aca5
--- /dev/null
@@ -0,0 +1,419 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2021-2022 Linaro Ltd
+ * Author: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>, based on
+ *         previous work of Thara Gopinath and msm-4.9 downstream sources.
+ */
+#include <linux/interconnect.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_opp.h>
+#include <linux/sizes.h>
+
+/*
+ * The BWMON samples data throughput within 'sample_ms' time. With three
+ * configurable thresholds (Low, Medium and High) gives four windows (called
+ * zones) of current bandwidth:
+ *
+ * Zone 0: byte count < THRES_LO
+ * Zone 1: THRES_LO < byte count < THRES_MED
+ * Zone 2: THRES_MED < byte count < THRES_HIGH
+ * Zone 3: THRES_HIGH < byte count
+ *
+ * Zones 0 and 2 are not used by this driver.
+ */
+
+/* Internal sampling clock frequency */
+#define HW_TIMER_HZ                            19200000
+
+#define BWMON_GLOBAL_IRQ_STATUS                        0x0
+#define BWMON_GLOBAL_IRQ_CLEAR                 0x8
+#define BWMON_GLOBAL_IRQ_ENABLE                        0xc
+#define BWMON_GLOBAL_IRQ_ENABLE_ENABLE         BIT(0)
+
+#define BWMON_IRQ_STATUS                       0x100
+#define BWMON_IRQ_STATUS_ZONE_SHIFT            4
+#define BWMON_IRQ_CLEAR                                0x108
+#define BWMON_IRQ_ENABLE                       0x10c
+#define BWMON_IRQ_ENABLE_ZONE1_SHIFT           5
+#define BWMON_IRQ_ENABLE_ZONE2_SHIFT           6
+#define BWMON_IRQ_ENABLE_ZONE3_SHIFT           7
+#define BWMON_IRQ_ENABLE_MASK                  (BIT(BWMON_IRQ_ENABLE_ZONE1_SHIFT) | \
+                                                BIT(BWMON_IRQ_ENABLE_ZONE3_SHIFT))
+
+#define BWMON_ENABLE                           0x2a0
+#define BWMON_ENABLE_ENABLE                    BIT(0)
+
+#define BWMON_CLEAR                            0x2a4
+#define BWMON_CLEAR_CLEAR                      BIT(0)
+
+#define BWMON_SAMPLE_WINDOW                    0x2a8
+#define BWMON_THRESHOLD_HIGH                   0x2ac
+#define BWMON_THRESHOLD_MED                    0x2b0
+#define BWMON_THRESHOLD_LOW                    0x2b4
+
+#define BWMON_ZONE_ACTIONS                     0x2b8
+/*
+ * Actions to perform on some zone 'z' when current zone hits the threshold:
+ * Increment counter of zone 'z'
+ */
+#define BWMON_ZONE_ACTIONS_INCREMENT(z)                (0x2 << ((z) * 2))
+/* Clear counter of zone 'z' */
+#define BWMON_ZONE_ACTIONS_CLEAR(z)            (0x1 << ((z) * 2))
+
+/* Zone 0 threshold hit: Clear zone count */
+#define BWMON_ZONE_ACTIONS_ZONE0               (BWMON_ZONE_ACTIONS_CLEAR(0))
+
+/* Zone 1 threshold hit: Increment zone count & clear lower zones */
+#define BWMON_ZONE_ACTIONS_ZONE1               (BWMON_ZONE_ACTIONS_INCREMENT(1) | \
+                                                BWMON_ZONE_ACTIONS_CLEAR(0))
+
+/* Zone 2 threshold hit: Increment zone count & clear lower zones */
+#define BWMON_ZONE_ACTIONS_ZONE2               (BWMON_ZONE_ACTIONS_INCREMENT(2) | \
+                                                BWMON_ZONE_ACTIONS_CLEAR(1) | \
+                                                BWMON_ZONE_ACTIONS_CLEAR(0))
+
+/* Zone 3 threshold hit: Increment zone count & clear lower zones */
+#define BWMON_ZONE_ACTIONS_ZONE3               (BWMON_ZONE_ACTIONS_INCREMENT(3) | \
+                                                BWMON_ZONE_ACTIONS_CLEAR(2) | \
+                                                BWMON_ZONE_ACTIONS_CLEAR(1) | \
+                                                BWMON_ZONE_ACTIONS_CLEAR(0))
+/* Value for BWMON_ZONE_ACTIONS */
+#define BWMON_ZONE_ACTIONS_DEFAULT             (BWMON_ZONE_ACTIONS_ZONE0 | \
+                                                BWMON_ZONE_ACTIONS_ZONE1 << 8 | \
+                                                BWMON_ZONE_ACTIONS_ZONE2 << 16 | \
+                                                BWMON_ZONE_ACTIONS_ZONE3 << 24)
+
+/*
+ * There is no clear documentation/explanation of BWMON_THRESHOLD_COUNT
+ * register. Based on observations, this is number of times one threshold has to
+ * be reached, to trigger interrupt in given zone.
+ *
+ * 0xff are maximum values meant to ignore the zones 0 and 2.
+ */
+#define BWMON_THRESHOLD_COUNT                  0x2bc
+#define BWMON_THRESHOLD_COUNT_ZONE1_SHIFT      8
+#define BWMON_THRESHOLD_COUNT_ZONE2_SHIFT      16
+#define BWMON_THRESHOLD_COUNT_ZONE3_SHIFT      24
+#define BWMON_THRESHOLD_COUNT_ZONE0_DEFAULT    0xff
+#define BWMON_THRESHOLD_COUNT_ZONE2_DEFAULT    0xff
+
+/* BWMONv4 count registers use count unit of 64 kB */
+#define BWMON_COUNT_UNIT_KB                    64
+#define BWMON_ZONE_COUNT                       0x2d8
+#define BWMON_ZONE_MAX(zone)                   (0x2e0 + 4 * (zone))
+
+struct icc_bwmon_data {
+       unsigned int sample_ms;
+       unsigned int default_highbw_kbps;
+       unsigned int default_medbw_kbps;
+       unsigned int default_lowbw_kbps;
+       u8 zone1_thres_count;
+       u8 zone3_thres_count;
+};
+
+struct icc_bwmon {
+       struct device *dev;
+       void __iomem *base;
+       int irq;
+
+       unsigned int default_lowbw_kbps;
+       unsigned int sample_ms;
+       unsigned int max_bw_kbps;
+       unsigned int min_bw_kbps;
+       unsigned int target_kbps;
+       unsigned int current_kbps;
+};
+
+static void bwmon_clear_counters(struct icc_bwmon *bwmon)
+{
+       /*
+        * Clear counters. The order and barriers are
+        * important. Quoting downstream Qualcomm msm-4.9 tree:
+        *
+        * The counter clear and IRQ clear bits are not in the same 4KB
+        * region. So, we need to make sure the counter clear is completed
+        * before we try to clear the IRQ or do any other counter operations.
+        */
+       writel(BWMON_CLEAR_CLEAR, bwmon->base + BWMON_CLEAR);
+}
+
+static void bwmon_clear_irq(struct icc_bwmon *bwmon)
+{
+       /*
+        * Clear zone and global interrupts. The order and barriers are
+        * important. Quoting downstream Qualcomm msm-4.9 tree:
+        *
+        * Synchronize the local interrupt clear in mon_irq_clear()
+        * with the global interrupt clear here. Otherwise, the CPU
+        * may reorder the two writes and clear the global interrupt
+        * before the local interrupt, causing the global interrupt
+        * to be retriggered by the local interrupt still being high.
+        *
+        * Similarly, because the global registers are in a different
+        * region than the local registers, we need to ensure any register
+        * writes to enable the monitor after this call are ordered with the
+        * clearing here so that local writes don't happen before the
+        * interrupt is cleared.
+        */
+       writel(BWMON_IRQ_ENABLE_MASK, bwmon->base + BWMON_IRQ_CLEAR);
+       writel(BIT(0), bwmon->base + BWMON_GLOBAL_IRQ_CLEAR);
+}
+
+static void bwmon_disable(struct icc_bwmon *bwmon)
+{
+       /* Disable interrupts. Strict ordering, see bwmon_clear_irq(). */
+       writel(0x0, bwmon->base + BWMON_GLOBAL_IRQ_ENABLE);
+       writel(0x0, bwmon->base + BWMON_IRQ_ENABLE);
+
+       /*
+        * Disable bwmon. Must happen before bwmon_clear_irq() to avoid spurious
+        * IRQ.
+        */
+       writel(0x0, bwmon->base + BWMON_ENABLE);
+}
+
+static void bwmon_enable(struct icc_bwmon *bwmon, unsigned int irq_enable)
+{
+       /* Enable interrupts */
+       writel(BWMON_GLOBAL_IRQ_ENABLE_ENABLE,
+              bwmon->base + BWMON_GLOBAL_IRQ_ENABLE);
+       writel(irq_enable, bwmon->base + BWMON_IRQ_ENABLE);
+
+       /* Enable bwmon */
+       writel(BWMON_ENABLE_ENABLE, bwmon->base + BWMON_ENABLE);
+}
+
+static unsigned int bwmon_kbps_to_count(unsigned int kbps)
+{
+       return kbps / BWMON_COUNT_UNIT_KB;
+}
+
+static void bwmon_set_threshold(struct icc_bwmon *bwmon, unsigned int reg,
+                               unsigned int kbps)
+{
+       unsigned int thres;
+
+       thres = mult_frac(bwmon_kbps_to_count(kbps), bwmon->sample_ms,
+                         MSEC_PER_SEC);
+       writel_relaxed(thres, bwmon->base + reg);
+}
+
+static void bwmon_start(struct icc_bwmon *bwmon,
+                       const struct icc_bwmon_data *data)
+{
+       unsigned int thres_count;
+       int window;
+
+       bwmon_clear_counters(bwmon);
+
+       window = mult_frac(bwmon->sample_ms, HW_TIMER_HZ, MSEC_PER_SEC);
+       /* Maximum sampling window: 0xfffff */
+       writel_relaxed(window, bwmon->base + BWMON_SAMPLE_WINDOW);
+
+       bwmon_set_threshold(bwmon, BWMON_THRESHOLD_HIGH,
+                           data->default_highbw_kbps);
+       bwmon_set_threshold(bwmon, BWMON_THRESHOLD_MED,
+                           data->default_medbw_kbps);
+       bwmon_set_threshold(bwmon, BWMON_THRESHOLD_LOW,
+                           data->default_lowbw_kbps);
+
+       thres_count = data->zone3_thres_count << BWMON_THRESHOLD_COUNT_ZONE3_SHIFT |
+                     BWMON_THRESHOLD_COUNT_ZONE2_DEFAULT << BWMON_THRESHOLD_COUNT_ZONE2_SHIFT |
+                     data->zone1_thres_count << BWMON_THRESHOLD_COUNT_ZONE1_SHIFT |
+                     BWMON_THRESHOLD_COUNT_ZONE0_DEFAULT;
+       writel_relaxed(thres_count, bwmon->base + BWMON_THRESHOLD_COUNT);
+       writel_relaxed(BWMON_ZONE_ACTIONS_DEFAULT,
+                      bwmon->base + BWMON_ZONE_ACTIONS);
+       /* Write barriers in bwmon_clear_irq() */
+
+       bwmon_clear_irq(bwmon);
+       bwmon_enable(bwmon, BWMON_IRQ_ENABLE_MASK);
+}
+
+static irqreturn_t bwmon_intr(int irq, void *dev_id)
+{
+       struct icc_bwmon *bwmon = dev_id;
+       unsigned int status, max;
+       int zone;
+
+       status = readl(bwmon->base + BWMON_IRQ_STATUS);
+       status &= BWMON_IRQ_ENABLE_MASK;
+       if (!status) {
+               /*
+                * Only zone 1 and zone 3 interrupts are enabled but zone 2
+                * threshold could be hit and trigger interrupt even if not
+                * enabled.
+                * Such spurious interrupt might come with valuable max count or
+                * not, so solution would be to always check all
+                * BWMON_ZONE_MAX() registers to find the highest value.
+                * Such case is currently ignored.
+                */
+               return IRQ_NONE;
+       }
+
+       bwmon_disable(bwmon);
+
+       zone = get_bitmask_order(status >> BWMON_IRQ_STATUS_ZONE_SHIFT) - 1;
+       /*
+        * Zone max bytes count register returns count units within sampling
+        * window.  Downstream kernel for BWMONv4 (called BWMON type 2 in
+        * downstream) always increments the max bytes count by one.
+        */
+       max = readl(bwmon->base + BWMON_ZONE_MAX(zone)) + 1;
+       max *= BWMON_COUNT_UNIT_KB;
+       bwmon->target_kbps = mult_frac(max, MSEC_PER_SEC, bwmon->sample_ms);
+
+       return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t bwmon_intr_thread(int irq, void *dev_id)
+{
+       struct icc_bwmon *bwmon = dev_id;
+       unsigned int irq_enable = 0;
+       struct dev_pm_opp *opp, *target_opp;
+       unsigned int bw_kbps, up_kbps, down_kbps;
+
+       bw_kbps = bwmon->target_kbps;
+
+       target_opp = dev_pm_opp_find_bw_ceil(bwmon->dev, &bw_kbps, 0);
+       if (IS_ERR(target_opp) && PTR_ERR(target_opp) == -ERANGE)
+               target_opp = dev_pm_opp_find_bw_floor(bwmon->dev, &bw_kbps, 0);
+
+       bwmon->target_kbps = bw_kbps;
+
+       bw_kbps--;
+       opp = dev_pm_opp_find_bw_floor(bwmon->dev, &bw_kbps, 0);
+       if (IS_ERR(opp) && PTR_ERR(opp) == -ERANGE)
+               down_kbps = bwmon->target_kbps;
+       else
+               down_kbps = bw_kbps;
+
+       up_kbps = bwmon->target_kbps + 1;
+
+       if (bwmon->target_kbps >= bwmon->max_bw_kbps)
+               irq_enable = BIT(BWMON_IRQ_ENABLE_ZONE1_SHIFT);
+       else if (bwmon->target_kbps <= bwmon->min_bw_kbps)
+               irq_enable = BIT(BWMON_IRQ_ENABLE_ZONE3_SHIFT);
+       else
+               irq_enable = BWMON_IRQ_ENABLE_MASK;
+
+       bwmon_set_threshold(bwmon, BWMON_THRESHOLD_HIGH, up_kbps);
+       bwmon_set_threshold(bwmon, BWMON_THRESHOLD_MED, down_kbps);
+       /* Write barriers in bwmon_clear_counters() */
+       bwmon_clear_counters(bwmon);
+       bwmon_clear_irq(bwmon);
+       bwmon_enable(bwmon, irq_enable);
+
+       if (bwmon->target_kbps == bwmon->current_kbps)
+               goto out;
+
+       dev_pm_opp_set_opp(bwmon->dev, target_opp);
+       bwmon->current_kbps = bwmon->target_kbps;
+
+out:
+       dev_pm_opp_put(target_opp);
+       if (!IS_ERR(opp))
+               dev_pm_opp_put(opp);
+
+       return IRQ_HANDLED;
+}
+
+static int bwmon_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct dev_pm_opp *opp;
+       struct icc_bwmon *bwmon;
+       const struct icc_bwmon_data *data;
+       int ret;
+
+       bwmon = devm_kzalloc(dev, sizeof(*bwmon), GFP_KERNEL);
+       if (!bwmon)
+               return -ENOMEM;
+
+       data = of_device_get_match_data(dev);
+
+       bwmon->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(bwmon->base)) {
+               dev_err(dev, "failed to map bwmon registers\n");
+               return PTR_ERR(bwmon->base);
+       }
+
+       bwmon->irq = platform_get_irq(pdev, 0);
+       if (bwmon->irq < 0)
+               return bwmon->irq;
+
+       ret = devm_pm_opp_of_add_table(dev);
+       if (ret)
+               return dev_err_probe(dev, ret, "failed to add OPP table\n");
+
+       bwmon->max_bw_kbps = UINT_MAX;
+       opp = dev_pm_opp_find_bw_floor(dev, &bwmon->max_bw_kbps, 0);
+       if (IS_ERR(opp))
+               return dev_err_probe(dev, ret, "failed to find max peak bandwidth\n");
+
+       bwmon->min_bw_kbps = 0;
+       opp = dev_pm_opp_find_bw_ceil(dev, &bwmon->min_bw_kbps, 0);
+       if (IS_ERR(opp))
+               return dev_err_probe(dev, ret, "failed to find min peak bandwidth\n");
+
+       bwmon->sample_ms = data->sample_ms;
+       bwmon->default_lowbw_kbps = data->default_lowbw_kbps;
+       bwmon->dev = dev;
+
+       bwmon_disable(bwmon);
+       ret = devm_request_threaded_irq(dev, bwmon->irq, bwmon_intr,
+                                       bwmon_intr_thread,
+                                       IRQF_ONESHOT, dev_name(dev), bwmon);
+       if (ret)
+               return dev_err_probe(dev, ret, "failed to request IRQ\n");
+
+       platform_set_drvdata(pdev, bwmon);
+       bwmon_start(bwmon, data);
+
+       return 0;
+}
+
+static int bwmon_remove(struct platform_device *pdev)
+{
+       struct icc_bwmon *bwmon = platform_get_drvdata(pdev);
+
+       bwmon_disable(bwmon);
+
+       return 0;
+}
+
+/* BWMON v4 */
+static const struct icc_bwmon_data msm8998_bwmon_data = {
+       .sample_ms = 4,
+       .default_highbw_kbps = 4800 * 1024, /* 4.8 GBps */
+       .default_medbw_kbps = 512 * 1024, /* 512 MBps */
+       .default_lowbw_kbps = 0,
+       .zone1_thres_count = 16,
+       .zone3_thres_count = 1,
+};
+
+static const struct of_device_id bwmon_of_match[] = {
+       { .compatible = "qcom,msm8998-bwmon", .data = &msm8998_bwmon_data },
+       {}
+};
+MODULE_DEVICE_TABLE(of, bwmon_of_match);
+
+static struct platform_driver bwmon_driver = {
+       .probe = bwmon_probe,
+       .remove = bwmon_remove,
+       .driver = {
+               .name = "qcom-bwmon",
+               .of_match_table = bwmon_of_match,
+       },
+};
+module_platform_driver(bwmon_driver);
+
+MODULE_AUTHOR("Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>");
+MODULE_DESCRIPTION("QCOM BWMON driver");
+MODULE_LICENSE("GPL");
index 4b143cf..38d7296 100644 (file)
@@ -382,7 +382,7 @@ static struct llcc_drv_data *drv_data = (void *) -EPROBE_DEFER;
  * llcc_slice_getd - get llcc slice descriptor
  * @uid: usecase_id for the client
  *
- * A pointer to llcc slice descriptor will be returned on success and
+ * A pointer to llcc slice descriptor will be returned on success
  * and error pointer is returned on failure
  */
 struct llcc_slice_desc *llcc_slice_getd(u32 uid)
index 366db49..3f11554 100644 (file)
@@ -108,6 +108,8 @@ EXPORT_SYMBOL_GPL(qcom_mdt_get_size);
  * qcom_mdt_read_metadata() - read header and metadata from mdt or mbn
  * @fw:                firmware of mdt header or mbn
  * @data_len:  length of the read metadata blob
+ * @fw_name:   name of the firmware, for construction of segment file names
+ * @dev:       device handle to associate resources with
  *
  * The mechanism that performs the authentication of the loading firmware
  * expects an ELF header directly followed by the segment of hashes, with no
@@ -192,7 +194,7 @@ EXPORT_SYMBOL_GPL(qcom_mdt_read_metadata);
  * qcom_mdt_pas_init() - initialize PAS region for firmware loading
  * @dev:       device handle to associate resources with
  * @fw:                firmware object for the mdt file
- * @firmware:  name of the firmware, for construction of segment file names
+ * @fw_name:   name of the firmware, for construction of segment file names
  * @pas_id:    PAS identifier
  * @mem_phys:  physical address of allocated memory region
  * @ctx:       PAS metadata context, to be released by caller
index 97fd24c..c92d26b 100644 (file)
@@ -194,14 +194,17 @@ struct ocmem *of_get_ocmem(struct device *dev)
        devnode = of_parse_phandle(dev->of_node, "sram", 0);
        if (!devnode || !devnode->parent) {
                dev_err(dev, "Cannot look up sram phandle\n");
+               of_node_put(devnode);
                return ERR_PTR(-ENODEV);
        }
 
        pdev = of_find_device_by_node(devnode->parent);
        if (!pdev) {
                dev_err(dev, "Cannot find device node %s\n", devnode->name);
+               of_node_put(devnode);
                return ERR_PTR(-EPROBE_DEFER);
        }
+       of_node_put(devnode);
 
        ocmem = platform_get_drvdata(pdev);
        if (!ocmem) {
index a59bb34..18c8560 100644 (file)
@@ -399,8 +399,10 @@ static int qmp_cooling_devices_register(struct qmp *qmp)
                        continue;
                ret = qmp_cooling_device_add(qmp, &qmp->cooling_devs[count++],
                                             child);
-               if (ret)
+               if (ret) {
+                       of_node_put(child);
                        goto unroll;
+               }
        }
 
        if (!count)
index 05fff86..092f6ab 100644 (file)
@@ -23,8 +23,8 @@
 /**
  * struct rpmhpd - top level RPMh power domain resource data structure
  * @dev:               rpmh power domain controller device
- * @pd:                        generic_pm_domain corrresponding to the power domain
- * @parent:            generic_pm_domain corrresponding to the parent's power domain
+ * @pd:                        generic_pm_domain corresponding to the power domain
+ * @parent:            generic_pm_domain corresponding to the parent's power domain
  * @peer:              A peer power domain in case Active only Voting is
  *                     supported
  * @active_only:       True if it represents an Active only peer
index 3b5b916..5803038 100644 (file)
@@ -453,6 +453,7 @@ static const struct rpmpd_desc qcm2290_desc = {
 static const struct of_device_id rpmpd_match_table[] = {
        { .compatible = "qcom,mdm9607-rpmpd", .data = &mdm9607_desc },
        { .compatible = "qcom,msm8226-rpmpd", .data = &msm8226_desc },
+       { .compatible = "qcom,msm8909-rpmpd", .data = &msm8916_desc },
        { .compatible = "qcom,msm8916-rpmpd", .data = &msm8916_desc },
        { .compatible = "qcom,msm8939-rpmpd", .data = &msm8939_desc },
        { .compatible = "qcom,msm8953-rpmpd", .data = &msm8953_desc },
index 30dda1a..413f9f4 100644 (file)
@@ -234,6 +234,7 @@ static const struct of_device_id qcom_smd_rpm_of_match[] = {
        { .compatible = "qcom,rpm-apq8084" },
        { .compatible = "qcom,rpm-ipq6018" },
        { .compatible = "qcom,rpm-msm8226" },
+       { .compatible = "qcom,rpm-msm8909" },
        { .compatible = "qcom,rpm-msm8916" },
        { .compatible = "qcom,rpm-msm8936" },
        { .compatible = "qcom,rpm-msm8953" },
index 3e95835..4f163d6 100644 (file)
@@ -926,7 +926,7 @@ qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host)
        struct smem_partition_header *header;
        struct smem_ptable_entry *entry;
        struct smem_ptable *ptable;
-       unsigned int remote_host;
+       u16 remote_host;
        u16 host0, host1;
        int i;
 
@@ -951,12 +951,12 @@ qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host)
                        continue;
 
                if (remote_host >= SMEM_HOST_COUNT) {
-                       dev_err(smem->dev, "bad host %hu\n", remote_host);
+                       dev_err(smem->dev, "bad host %u\n", remote_host);
                        return -EINVAL;
                }
 
                if (smem->partitions[remote_host].virt_base) {
-                       dev_err(smem->dev, "duplicate host %hu\n", remote_host);
+                       dev_err(smem->dev, "duplicate host %u\n", remote_host);
                        return -EINVAL;
                }
 
index 59dbf4b..d9c28a8 100644 (file)
@@ -119,6 +119,9 @@ struct smp2p_entry {
  * @out:       pointer to the outbound smem item
  * @smem_items:        ids of the two smem items
  * @valid_entries: already scanned inbound entries
+ * @ssr_ack_enabled: SMP2P_FEATURE_SSR_ACK feature is supported and was enabled
+ * @ssr_ack: current cached state of the local ack bit
+ * @negotiation_done: whether negotiating finished
  * @local_pid: processor id of the inbound edge
  * @remote_pid:        processor id of the outbound edge
  * @ipc_regmap:        regmap for the outbound ipc
index cee579a..4554fb8 100644 (file)
@@ -328,10 +328,12 @@ static const struct soc_id soc_id[] = {
        { 455, "QRB5165" },
        { 457, "SM8450" },
        { 459, "SM7225" },
-       { 460, "SA8540P" },
+       { 460, "SA8295P" },
+       { 461, "SA8540P" },
        { 480, "SM8450" },
        { 482, "SM8450" },
        { 487, "SC7280" },
+       { 495, "SC7180P" },
 };
 
 static const char *socinfo_machine(struct device *dev, unsigned int id)
index f831420..484b42b 100644 (file)
@@ -74,6 +74,18 @@ static const u16 spm_reg_offset_v3_0[SPM_REG_NR] = {
        [SPM_REG_SEQ_ENTRY]     = 0x400,
 };
 
+/* SPM register data for 8909 */
+static const struct spm_reg_data spm_reg_8909_cpu = {
+       .reg_offset = spm_reg_offset_v3_0,
+       .spm_cfg = 0x1,
+       .spm_dly = 0x3C102800,
+       .seq = { 0x60, 0x03, 0x60, 0x0B, 0x0F, 0x20, 0x10, 0x80, 0x30, 0x90,
+               0x5B, 0x60, 0x03, 0x60, 0x76, 0x76, 0x0B, 0x94, 0x5B, 0x80,
+               0x10, 0x26, 0x30, 0x0F },
+       .start_index[PM_SLEEP_MODE_STBY] = 0,
+       .start_index[PM_SLEEP_MODE_SPC] = 5,
+};
+
 /* SPM register data for 8916 */
 static const struct spm_reg_data spm_reg_8916_cpu = {
        .reg_offset = spm_reg_offset_v3_0,
@@ -195,6 +207,8 @@ static const struct of_device_id spm_match_table[] = {
          .data = &spm_reg_660_silver_l2 },
        { .compatible = "qcom,msm8226-saw2-v2.1-cpu",
          .data = &spm_reg_8226_cpu },
+       { .compatible = "qcom,msm8909-saw2-v3.0-cpu",
+         .data = &spm_reg_8909_cpu },
        { .compatible = "qcom,msm8916-saw2-v3.0-cpu",
          .data = &spm_reg_8916_cpu },
        { .compatible = "qcom,msm8974-saw2-v2.1-cpu",
index fdfc857..04f1bc3 100644 (file)
@@ -57,11 +57,11 @@ static struct rcar_gen4_sysc_area r8a779a0_areas[] __initdata = {
        { "a2cv6",      R8A779A0_PD_A2CV6, R8A779A0_PD_A3IR },
        { "a2cn2",      R8A779A0_PD_A2CN2, R8A779A0_PD_A3IR },
        { "a2imp23",    R8A779A0_PD_A2IMP23, R8A779A0_PD_A3IR },
-       { "a2dp1",      R8A779A0_PD_A2DP0, R8A779A0_PD_A3IR },
-       { "a2cv2",      R8A779A0_PD_A2CV0, R8A779A0_PD_A3IR },
-       { "a2cv3",      R8A779A0_PD_A2CV1, R8A779A0_PD_A3IR },
-       { "a2cv5",      R8A779A0_PD_A2CV4, R8A779A0_PD_A3IR },
-       { "a2cv7",      R8A779A0_PD_A2CV6, R8A779A0_PD_A3IR },
+       { "a2dp1",      R8A779A0_PD_A2DP1, R8A779A0_PD_A3IR },
+       { "a2cv2",      R8A779A0_PD_A2CV2, R8A779A0_PD_A3IR },
+       { "a2cv3",      R8A779A0_PD_A2CV3, R8A779A0_PD_A3IR },
+       { "a2cv5",      R8A779A0_PD_A2CV5, R8A779A0_PD_A3IR },
+       { "a2cv7",      R8A779A0_PD_A2CV7, R8A779A0_PD_A3IR },
        { "a2cn1",      R8A779A0_PD_A2CN1, R8A779A0_PD_A3IR },
        { "a1cnn0",     R8A779A0_PD_A1CNN0, R8A779A0_PD_A2CN0 },
        { "a1cnn2",     R8A779A0_PD_A1CNN2, R8A779A0_PD_A2CN2 },
index fe2d982..388cfa8 100644 (file)
@@ -25,8 +25,8 @@
 struct rcar_gen4_sysc_area {
        const char *name;
        u8 pdr;                 /* PDRn */
-       int parent;             /* -1 if none */
-       unsigned int flags;     /* See PD_* */
+       s8 parent;              /* -1 if none */
+       u8 flags;               /* See PD_* */
 };
 
 /*
index 8d861c1..266c599 100644 (file)
@@ -31,8 +31,8 @@ struct rcar_sysc_area {
        u16 chan_offs;          /* Offset of PWRSR register for this area */
        u8 chan_bit;            /* Bit in PWR* (except for PWRUP in PWRSR) */
        u8 isr_bit;             /* Bit in SYSCI*R */
-       int parent;             /* -1 if none */
-       unsigned int flags;     /* See PD_* */
+       s8 parent;              /* -1 if none */
+       u8 flags;               /* See PD_* */
 };
 
 
index 1fef0e7..8aecbc9 100644 (file)
@@ -6,6 +6,7 @@
 config SUNXI_MBUS
        bool
        default ARCH_SUNXI
+       depends on ARM || ARM64
        help
          Say y to enable the fixups needed to support the Allwinner
          MBUS DMA quirks.
index 0e4ba0f..6882c86 100644 (file)
@@ -338,6 +338,7 @@ static const struct of_device_id pruss_of_match[] = {
        { .compatible = "ti,am654-icssg", .data = &am65x_j721e_pruss_data, },
        { .compatible = "ti,j721e-icssg", .data = &am65x_j721e_pruss_data, },
        { .compatible = "ti,am642-icssg", .data = &am65x_j721e_pruss_data, },
+       { .compatible = "ti,am625-pruss", .data = &am65x_j721e_pruss_data, },
        {},
 };
 MODULE_DEVICE_TABLE(of, pruss_of_match);
index 0076d46..343c58e 100644 (file)
@@ -688,7 +688,7 @@ static int wkup_m3_ipc_probe(struct platform_device *pdev)
                                      &m3_ipc->sd_fw_name);
        if (ret) {
                dev_dbg(dev, "Voltage scaling data blob not provided from DT.\n");
-       };
+       }
 
        /*
         * Wait for firmware loading completion in a thread so we
index 5dcb766..2de0827 100644 (file)
@@ -647,8 +647,7 @@ static int xlnx_event_manager_probe(struct platform_device *pdev)
        cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "soc/event:starting",
                          xlnx_event_cpuhp_start, xlnx_event_cpuhp_down);
 
-       ret = zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_REGISTER_SGI, sgi_num,
-                                 0, NULL);
+       ret = zynqmp_pm_register_sgi(sgi_num, 0);
        if (ret) {
                dev_err(&pdev->dev, "SGI %d Registration over TF-A failed with %d\n", sgi_num, ret);
                xlnx_event_cleanup_sgi(pdev);
@@ -681,7 +680,7 @@ static int xlnx_event_manager_remove(struct platform_device *pdev)
                kfree(eve_data);
        }
 
-       ret = zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_REGISTER_SGI, 0, 1, NULL);
+       ret = zynqmp_pm_register_sgi(0, 1);
        if (ret)
                dev_err(&pdev->dev, "SGI unregistration over TF-A failed with %d\n", ret);
 
index 669d757..00f7b49 100644 (file)
@@ -127,6 +127,71 @@ static bool find_slave(struct sdw_bus *bus,
        return true;
 }
 
+struct sdw_acpi_child_walk_data {
+       struct sdw_bus *bus;
+       struct acpi_device *adev;
+       struct sdw_slave_id id;
+       bool ignore_unique_id;
+};
+
+static int sdw_acpi_check_duplicate(struct acpi_device *adev, void *data)
+{
+       struct sdw_acpi_child_walk_data *cwd = data;
+       struct sdw_bus *bus = cwd->bus;
+       struct sdw_slave_id id;
+
+       if (adev == cwd->adev)
+               return 0;
+
+       if (!find_slave(bus, adev, &id))
+               return 0;
+
+       if (cwd->id.sdw_version != id.sdw_version || cwd->id.mfg_id != id.mfg_id ||
+           cwd->id.part_id != id.part_id || cwd->id.class_id != id.class_id)
+               return 0;
+
+       if (cwd->id.unique_id != id.unique_id) {
+               dev_dbg(bus->dev,
+                       "Valid unique IDs 0x%x 0x%x for Slave mfg_id 0x%04x, part_id 0x%04x\n",
+                       cwd->id.unique_id, id.unique_id, cwd->id.mfg_id,
+                       cwd->id.part_id);
+               cwd->ignore_unique_id = false;
+               return 0;
+       }
+
+       dev_err(bus->dev,
+               "Invalid unique IDs 0x%x 0x%x for Slave mfg_id 0x%04x, part_id 0x%04x\n",
+               cwd->id.unique_id, id.unique_id, cwd->id.mfg_id, cwd->id.part_id);
+       return -ENODEV;
+}
+
+static int sdw_acpi_find_one(struct acpi_device *adev, void *data)
+{
+       struct sdw_bus *bus = data;
+       struct sdw_acpi_child_walk_data cwd = {
+               .bus = bus,
+               .adev = adev,
+               .ignore_unique_id = true,
+       };
+       int ret;
+
+       if (!find_slave(bus, adev, &cwd.id))
+               return 0;
+
+       /* Brute-force O(N^2) search for duplicates. */
+       ret = acpi_dev_for_each_child(ACPI_COMPANION(bus->dev),
+                                     sdw_acpi_check_duplicate, &cwd);
+       if (ret)
+               return ret;
+
+       if (cwd.ignore_unique_id)
+               cwd.id.unique_id = SDW_IGNORED_UNIQUE_ID;
+
+       /* Ignore errors and continue. */
+       sdw_slave_add(bus, &cwd.id, acpi_fwnode_handle(adev));
+       return 0;
+}
+
 /*
  * sdw_acpi_find_slaves() - Find Slave devices in Master ACPI node
  * @bus: SDW bus instance
@@ -135,8 +200,7 @@ static bool find_slave(struct sdw_bus *bus,
  */
 int sdw_acpi_find_slaves(struct sdw_bus *bus)
 {
-       struct acpi_device *adev, *parent;
-       struct acpi_device *adev2, *parent2;
+       struct acpi_device *parent;
 
        parent = ACPI_COMPANION(bus->dev);
        if (!parent) {
@@ -144,54 +208,7 @@ int sdw_acpi_find_slaves(struct sdw_bus *bus)
                return -ENODEV;
        }
 
-       list_for_each_entry(adev, &parent->children, node) {
-               struct sdw_slave_id id;
-               struct sdw_slave_id id2;
-               bool ignore_unique_id = true;
-
-               if (!find_slave(bus, adev, &id))
-                       continue;
-
-               /* brute-force O(N^2) search for duplicates */
-               parent2 = parent;
-               list_for_each_entry(adev2, &parent2->children, node) {
-
-                       if (adev == adev2)
-                               continue;
-
-                       if (!find_slave(bus, adev2, &id2))
-                               continue;
-
-                       if (id.sdw_version != id2.sdw_version ||
-                           id.mfg_id != id2.mfg_id ||
-                           id.part_id != id2.part_id ||
-                           id.class_id != id2.class_id)
-                               continue;
-
-                       if (id.unique_id != id2.unique_id) {
-                               dev_dbg(bus->dev,
-                                       "Valid unique IDs 0x%x 0x%x for Slave mfg_id 0x%04x, part_id 0x%04x\n",
-                                       id.unique_id, id2.unique_id, id.mfg_id, id.part_id);
-                               ignore_unique_id = false;
-                       } else {
-                               dev_err(bus->dev,
-                                       "Invalid unique IDs 0x%x 0x%x for Slave mfg_id 0x%04x, part_id 0x%04x\n",
-                                       id.unique_id, id2.unique_id, id.mfg_id, id.part_id);
-                               return -ENODEV;
-                       }
-               }
-
-               if (ignore_unique_id)
-                       id.unique_id = SDW_IGNORED_UNIQUE_ID;
-
-               /*
-                * don't error check for sdw_slave_add as we want to continue
-                * adding Slaves
-                */
-               sdw_slave_add(bus, &id, acpi_fwnode_handle(adev));
-       }
-
-       return 0;
+       return acpi_dev_for_each_child(parent, sdw_acpi_find_one, bus);
 }
 
 #endif
index 3b1044e..e32f6a2 100644 (file)
@@ -183,7 +183,7 @@ config SPI_BCM63XX
 
 config SPI_BCM63XX_HSSPI
        tristate "Broadcom BCM63XX HS SPI controller driver"
-       depends on BCM63XX || BMIPS_GENERIC || ARCH_BCM_63XX || COMPILE_TEST
+       depends on BCM63XX || BMIPS_GENERIC || ARCH_BCMBCA || COMPILE_TEST
        help
          This enables support for the High Speed SPI controller present on
          newer Broadcom BCM63XX SoCs.
@@ -371,6 +371,13 @@ config SPI_FSL_QUADSPI
          This controller does not support generic SPI messages. It only
          supports the high-level SPI memory interface.
 
+config SPI_GXP
+       tristate "GXP SPI driver"
+       depends on ARCH_HPE || COMPILE_TEST
+       help
+         This enables support for the driver for GXP bus attached SPI
+         controllers.
+
 config SPI_HISI_KUNPENG
        tristate "HiSilicon SPI Controller for Kunpeng SoCs"
        depends on (ARM64 && ACPI) || COMPILE_TEST
@@ -575,6 +582,15 @@ config SPI_MESON_SPIFC
          This enables master mode support for the SPIFC (SPI flash
          controller) available in Amlogic Meson SoCs.
 
+config SPI_MICROCHIP_CORE
+       tristate "Microchip FPGA SPI controllers"
+       depends on SPI_MASTER
+       help
+         This enables the SPI driver for Microchip FPGA SPI controllers.
+         Say Y or M here if you want to use the "hard" controllers on
+         PolarFire SoC.
+         If built as a module, it will be called spi-microchip-core.
+
 config SPI_MT65XX
        tristate "MediaTek SPI controller"
        depends on ARCH_MEDIATEK || COMPILE_TEST
index 0f44eb6..15d2f38 100644 (file)
@@ -57,6 +57,7 @@ obj-$(CONFIG_SPI_FSL_LPSPI)           += spi-fsl-lpspi.o
 obj-$(CONFIG_SPI_FSL_QUADSPI)          += spi-fsl-qspi.o
 obj-$(CONFIG_SPI_FSL_SPI)              += spi-fsl-spi.o
 obj-$(CONFIG_SPI_GPIO)                 += spi-gpio.o
+obj-$(CONFIG_SPI_GXP)                  += spi-gxp.o
 obj-$(CONFIG_SPI_HISI_KUNPENG)         += spi-hisi-kunpeng.o
 obj-$(CONFIG_SPI_HISI_SFC_V3XX)                += spi-hisi-sfc-v3xx.o
 obj-$(CONFIG_SPI_IMG_SPFI)             += spi-img-spfi.o
@@ -71,6 +72,7 @@ obj-$(CONFIG_SPI_LM70_LLP)            += spi-lm70llp.o
 obj-$(CONFIG_SPI_LP8841_RTC)           += spi-lp8841-rtc.o
 obj-$(CONFIG_SPI_MESON_SPICC)          += spi-meson-spicc.o
 obj-$(CONFIG_SPI_MESON_SPIFC)          += spi-meson-spifc.o
+obj-$(CONFIG_SPI_MICROCHIP_CORE)       += spi-microchip-core.o
 obj-$(CONFIG_SPI_MPC512x_PSC)          += spi-mpc512x-psc.o
 obj-$(CONFIG_SPI_MPC52xx_PSC)          += spi-mpc52xx-psc.o
 obj-$(CONFIG_SPI_MPC52xx)              += spi-mpc52xx.o
index 480c0c8..976a217 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/spi/spi-mem.h>
 
 /* QSPI register offsets */
@@ -285,7 +286,7 @@ static bool atmel_qspi_supports_op(struct spi_mem *mem,
 
        /* special case not supported by hardware */
        if (op->addr.nbytes == 2 && op->cmd.buswidth != op->addr.buswidth &&
-               op->dummy.nbytes == 0)
+           op->dummy.nbytes == 0)
                return false;
 
        return true;
@@ -417,9 +418,13 @@ static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
        if (op->addr.val + op->data.nbytes > aq->mmap_size)
                return -ENOTSUPP;
 
+       err = pm_runtime_resume_and_get(&aq->pdev->dev);
+       if (err < 0)
+               return err;
+
        err = atmel_qspi_set_cfg(aq, op, &offset);
        if (err)
-               return err;
+               goto pm_runtime_put;
 
        /* Skip to the final steps if there is no data */
        if (op->data.nbytes) {
@@ -441,7 +446,7 @@ static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
        /* Poll INSTRuction End status */
        sr = atmel_qspi_read(aq, QSPI_SR);
        if ((sr & QSPI_SR_CMD_COMPLETED) == QSPI_SR_CMD_COMPLETED)
-               return err;
+               goto pm_runtime_put;
 
        /* Wait for INSTRuction End interrupt */
        reinit_completion(&aq->cmd_completion);
@@ -452,6 +457,9 @@ static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
                err = -ETIMEDOUT;
        atmel_qspi_write(QSPI_SR_CMD_COMPLETED, aq, QSPI_IDR);
 
+pm_runtime_put:
+       pm_runtime_mark_last_busy(&aq->pdev->dev);
+       pm_runtime_put_autosuspend(&aq->pdev->dev);
        return err;
 }
 
@@ -472,6 +480,7 @@ static int atmel_qspi_setup(struct spi_device *spi)
        struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
        unsigned long src_rate;
        u32 scbr;
+       int ret;
 
        if (ctrl->busy)
                return -EBUSY;
@@ -488,9 +497,16 @@ static int atmel_qspi_setup(struct spi_device *spi)
        if (scbr > 0)
                scbr--;
 
+       ret = pm_runtime_resume_and_get(ctrl->dev.parent);
+       if (ret < 0)
+               return ret;
+
        aq->scr = QSPI_SCR_SCBR(scbr);
        atmel_qspi_write(aq->scr, aq, QSPI_SCR);
 
+       pm_runtime_mark_last_busy(ctrl->dev.parent);
+       pm_runtime_put_autosuspend(ctrl->dev.parent);
+
        return 0;
 }
 
@@ -621,11 +637,24 @@ static int atmel_qspi_probe(struct platform_device *pdev)
        if (err)
                goto disable_qspick;
 
+       pm_runtime_set_autosuspend_delay(&pdev->dev, 500);
+       pm_runtime_use_autosuspend(&pdev->dev);
+       pm_runtime_set_active(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_get_noresume(&pdev->dev);
+
        atmel_qspi_init(aq);
 
        err = spi_register_controller(ctrl);
-       if (err)
+       if (err) {
+               pm_runtime_put_noidle(&pdev->dev);
+               pm_runtime_disable(&pdev->dev);
+               pm_runtime_set_suspended(&pdev->dev);
+               pm_runtime_dont_use_autosuspend(&pdev->dev);
                goto disable_qspick;
+       }
+       pm_runtime_mark_last_busy(&pdev->dev);
+       pm_runtime_put_autosuspend(&pdev->dev);
 
        return 0;
 
@@ -641,9 +670,18 @@ static int atmel_qspi_remove(struct platform_device *pdev)
 {
        struct spi_controller *ctrl = platform_get_drvdata(pdev);
        struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
+       int ret;
+
+       ret = pm_runtime_resume_and_get(&pdev->dev);
+       if (ret < 0)
+               return ret;
 
        spi_unregister_controller(ctrl);
        atmel_qspi_write(QSPI_CR_QSPIDIS, aq, QSPI_CR);
+
+       pm_runtime_disable(&pdev->dev);
+       pm_runtime_put_noidle(&pdev->dev);
+
        clk_disable_unprepare(aq->qspick);
        clk_disable_unprepare(aq->pclk);
        return 0;
@@ -653,10 +691,19 @@ static int __maybe_unused atmel_qspi_suspend(struct device *dev)
 {
        struct spi_controller *ctrl = dev_get_drvdata(dev);
        struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
+       int ret;
+
+       ret = pm_runtime_resume_and_get(dev);
+       if (ret < 0)
+               return ret;
 
        atmel_qspi_write(QSPI_CR_QSPIDIS, aq, QSPI_CR);
-       clk_disable_unprepare(aq->qspick);
-       clk_disable_unprepare(aq->pclk);
+
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_force_suspend(dev);
+
+       clk_unprepare(aq->qspick);
+       clk_unprepare(aq->pclk);
 
        return 0;
 }
@@ -665,19 +712,54 @@ static int __maybe_unused atmel_qspi_resume(struct device *dev)
 {
        struct spi_controller *ctrl = dev_get_drvdata(dev);
        struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
+       int ret;
 
-       clk_prepare_enable(aq->pclk);
-       clk_prepare_enable(aq->qspick);
+       clk_prepare(aq->pclk);
+       clk_prepare(aq->qspick);
+
+       ret = pm_runtime_force_resume(dev);
+       if (ret < 0)
+               return ret;
 
        atmel_qspi_init(aq);
 
        atmel_qspi_write(aq->scr, aq, QSPI_SCR);
 
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_put_autosuspend(dev);
+
+       return 0;
+}
+
+static int __maybe_unused atmel_qspi_runtime_suspend(struct device *dev)
+{
+       struct spi_controller *ctrl = dev_get_drvdata(dev);
+       struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
+
+       clk_disable(aq->qspick);
+       clk_disable(aq->pclk);
+
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(atmel_qspi_pm_ops, atmel_qspi_suspend,
-                        atmel_qspi_resume);
+static int __maybe_unused atmel_qspi_runtime_resume(struct device *dev)
+{
+       struct spi_controller *ctrl = dev_get_drvdata(dev);
+       struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
+       int ret;
+
+       ret = clk_enable(aq->pclk);
+       if (ret)
+               return ret;
+
+       return clk_enable(aq->qspick);
+}
+
+static const struct dev_pm_ops __maybe_unused atmel_qspi_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(atmel_qspi_suspend, atmel_qspi_resume)
+       SET_RUNTIME_PM_OPS(atmel_qspi_runtime_suspend,
+                          atmel_qspi_runtime_resume, NULL)
+};
 
 static const struct atmel_qspi_caps atmel_sama5d2_qspi_caps = {};
 
@@ -704,7 +786,7 @@ static struct platform_driver atmel_qspi_driver = {
        .driver = {
                .name   = "atmel_qspi",
                .of_match_table = atmel_qspi_dt_ids,
-               .pm     = &atmel_qspi_pm_ops,
+               .pm     = pm_ptr(&atmel_qspi_pm_ops),
        },
        .probe          = atmel_qspi_probe,
        .remove         = atmel_qspi_remove,
index ca40923..596e181 100644 (file)
@@ -128,9 +128,9 @@ static int dfl_spi_altera_probe(struct dfl_device *dfl_dev)
        struct spi_master *master;
        struct altera_spi *hw;
        void __iomem *base;
-       int err = -ENODEV;
+       int err;
 
-       master = spi_alloc_master(dev, sizeof(struct altera_spi));
+       master = devm_spi_alloc_master(dev, sizeof(struct altera_spi));
        if (!master)
                return -ENOMEM;
 
@@ -159,10 +159,9 @@ static int dfl_spi_altera_probe(struct dfl_device *dfl_dev)
        altera_spi_init_master(master);
 
        err = devm_spi_register_master(dev, master);
-       if (err) {
-               dev_err(dev, "%s failed to register spi master %d\n", __func__, err);
-               goto exit;
-       }
+       if (err)
+               return dev_err_probe(dev, err, "%s failed to register spi master\n",
+                                    __func__);
 
        if (dfl_dev->revision == FME_FEATURE_REV_MAX10_SPI_N5010)
                strscpy(board_info.modalias, "m10-n5010", SPI_NAME_SIZE);
@@ -179,9 +178,6 @@ static int dfl_spi_altera_probe(struct dfl_device *dfl_dev)
        }
 
        return 0;
-exit:
-       spi_master_put(master);
-       return err;
 }
 
 static const struct dfl_device_id dfl_spi_altera_ids[] = {
index cba6a44..08df4f8 100644 (file)
 #define AMD_SPI_RX_COUNT_REG   0x4B
 #define AMD_SPI_STATUS_REG     0x4C
 
+#define AMD_SPI_FIFO_SIZE      70
 #define AMD_SPI_MEM_SIZE       200
 
 /* M_CMD OP codes for SPI */
 #define AMD_SPI_XFER_TX                1
 #define AMD_SPI_XFER_RX                2
 
+/**
+ * enum amd_spi_versions - SPI controller versions
+ * @AMD_SPI_V1:                AMDI0061 hardware version
+ * @AMD_SPI_V2:                AMDI0062 hardware version
+ */
 enum amd_spi_versions {
-       AMD_SPI_V1 = 1, /* AMDI0061 */
-       AMD_SPI_V2,     /* AMDI0062 */
+       AMD_SPI_V1 = 1,
+       AMD_SPI_V2,
 };
 
+/**
+ * struct amd_spi - SPI driver instance
+ * @io_remap_addr:     Start address of the SPI controller registers
+ * @version:           SPI controller hardware version
+ */
 struct amd_spi {
        void __iomem *io_remap_addr;
-       unsigned long io_base_addr;
        enum amd_spi_versions version;
 };
 
@@ -270,27 +280,29 @@ static int amd_spi_master_transfer(struct spi_master *master,
        return 0;
 }
 
+static size_t amd_spi_max_transfer_size(struct spi_device *spi)
+{
+       return AMD_SPI_FIFO_SIZE;
+}
+
 static int amd_spi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct spi_master *master;
        struct amd_spi *amd_spi;
-       int err = 0;
+       int err;
 
        /* Allocate storage for spi_master and driver private data */
-       master = spi_alloc_master(dev, sizeof(struct amd_spi));
-       if (!master) {
-               dev_err(dev, "Error allocating SPI master\n");
-               return -ENOMEM;
-       }
+       master = devm_spi_alloc_master(dev, sizeof(struct amd_spi));
+       if (!master)
+               return dev_err_probe(dev, -ENOMEM, "Error allocating SPI master\n");
 
        amd_spi = spi_master_get_devdata(master);
        amd_spi->io_remap_addr = devm_platform_ioremap_resource(pdev, 0);
-       if (IS_ERR(amd_spi->io_remap_addr)) {
-               err = PTR_ERR(amd_spi->io_remap_addr);
-               dev_err(dev, "error %d ioremap of SPI registers failed\n", err);
-               goto err_free_master;
-       }
+       if (IS_ERR(amd_spi->io_remap_addr))
+               return dev_err_probe(dev, PTR_ERR(amd_spi->io_remap_addr),
+                                    "ioremap of SPI registers failed\n");
+
        dev_dbg(dev, "io_remap_address: %p\n", amd_spi->io_remap_addr);
 
        amd_spi->version = (enum amd_spi_versions) device_get_match_data(dev);
@@ -302,20 +314,15 @@ static int amd_spi_probe(struct platform_device *pdev)
        master->flags = SPI_MASTER_HALF_DUPLEX;
        master->setup = amd_spi_master_setup;
        master->transfer_one_message = amd_spi_master_transfer;
+       master->max_transfer_size = amd_spi_max_transfer_size;
+       master->max_message_size = amd_spi_max_transfer_size;
 
        /* Register the controller with SPI framework */
        err = devm_spi_register_master(dev, master);
-       if (err) {
-               dev_err(dev, "error %d registering SPI controller\n", err);
-               goto err_free_master;
-       }
+       if (err)
+               return dev_err_probe(dev, err, "error registering SPI controller\n");
 
        return 0;
-
-err_free_master:
-       spi_master_put(master);
-
-       return err;
 }
 
 #ifdef CONFIG_ACPI
index d8cc4b2..9df9fc4 100644 (file)
@@ -497,7 +497,7 @@ static int a3700_spi_fifo_write(struct a3700_spi *a3700_spi)
 
        while (!a3700_is_wfifo_full(a3700_spi) && a3700_spi->buf_len) {
                val = *(u32 *)a3700_spi->tx_buf;
-               spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG, val);
+               spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG, cpu_to_le32(val));
                a3700_spi->buf_len -= 4;
                a3700_spi->tx_buf += 4;
        }
@@ -519,7 +519,7 @@ static int a3700_spi_fifo_read(struct a3700_spi *a3700_spi)
        while (!a3700_is_rfifo_empty(a3700_spi) && a3700_spi->buf_len) {
                val = spireg_read(a3700_spi, A3700_SPI_DATA_IN_REG);
                if (a3700_spi->buf_len >= 4) {
-
+                       val = le32_to_cpu(val);
                        memcpy(a3700_spi->rx_buf, &val, 4);
 
                        a3700_spi->buf_len -= 4;
index 496f3e1..3e891bf 100644 (file)
@@ -558,6 +558,14 @@ static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
        u32 ctl_val;
        int ret = 0;
 
+       dev_dbg(aspi->dev,
+               "CE%d %s dirmap [ 0x%.8llx - 0x%.8llx ] OP %#x mode:%d.%d.%d.%d naddr:%#x ndummies:%#x\n",
+               chip->cs, op->data.dir == SPI_MEM_DATA_IN ? "read" : "write",
+               desc->info.offset, desc->info.offset + desc->info.length,
+               op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
+               op->dummy.buswidth, op->data.buswidth,
+               op->addr.nbytes, op->dummy.nbytes);
+
        chip->clk_freq = desc->mem->spi->max_speed_hz;
 
        /* Only for reads */
@@ -574,9 +582,11 @@ static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
        ctl_val = readl(chip->ctl) & ~CTRL_IO_CMD_MASK;
        ctl_val |= aspeed_spi_get_io_mode(op) |
                op->cmd.opcode << CTRL_COMMAND_SHIFT |
-               CTRL_IO_DUMMY_SET(op->dummy.nbytes / op->dummy.buswidth) |
                CTRL_IO_MODE_READ;
 
+       if (op->dummy.nbytes)
+               ctl_val |= CTRL_IO_DUMMY_SET(op->dummy.nbytes / op->dummy.buswidth);
+
        /* Tune 4BYTE address mode */
        if (op->addr.nbytes) {
                u32 addr_mode = readl(aspi->regs + CE_CTRL_REG);
index 9e300a9..c4f22d5 100644 (file)
@@ -1631,7 +1631,6 @@ static int atmel_spi_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
 static int atmel_spi_runtime_suspend(struct device *dev)
 {
        struct spi_master *master = dev_get_drvdata(dev);
@@ -1653,7 +1652,6 @@ static int atmel_spi_runtime_resume(struct device *dev)
        return clk_prepare_enable(as->clk);
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int atmel_spi_suspend(struct device *dev)
 {
        struct spi_master *master = dev_get_drvdata(dev);
@@ -1693,17 +1691,12 @@ static int atmel_spi_resume(struct device *dev)
        /* Start the queue running */
        return spi_master_resume(master);
 }
-#endif
 
 static const struct dev_pm_ops atmel_spi_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(atmel_spi_suspend, atmel_spi_resume)
-       SET_RUNTIME_PM_OPS(atmel_spi_runtime_suspend,
-                          atmel_spi_runtime_resume, NULL)
+       SYSTEM_SLEEP_PM_OPS(atmel_spi_suspend, atmel_spi_resume)
+       RUNTIME_PM_OPS(atmel_spi_runtime_suspend,
+                      atmel_spi_runtime_resume, NULL)
 };
-#define ATMEL_SPI_PM_OPS       (&atmel_spi_pm_ops)
-#else
-#define ATMEL_SPI_PM_OPS       NULL
-#endif
 
 static const struct of_device_id atmel_spi_dt_ids[] = {
        { .compatible = "atmel,at91rm9200-spi" },
@@ -1715,7 +1708,7 @@ MODULE_DEVICE_TABLE(of, atmel_spi_dt_ids);
 static struct platform_driver atmel_spi_driver = {
        .driver         = {
                .name   = "atmel_spi",
-               .pm     = ATMEL_SPI_PM_OPS,
+               .pm     = pm_ptr(&atmel_spi_pm_ops),
                .of_match_table = atmel_spi_dt_ids,
        },
        .probe          = atmel_spi_probe,
index 775c0bf..747e032 100644 (file)
@@ -372,6 +372,10 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)
        struct bcm2835_spi *bs = dev_id;
        u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
 
+       /* Bail out early if interrupts are not enabled */
+       if (!(cs & BCM2835_SPI_CS_INTR))
+               return IRQ_NONE;
+
        /*
         * An interrupt is signaled either if DONE is set (TX FIFO empty)
         * or if RXR is set (RX FIFO >= ¾ full).
@@ -1138,10 +1142,14 @@ static void bcm2835_spi_handle_err(struct spi_controller *ctlr,
        struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
 
        /* if an error occurred and we have an active dma, then terminate */
-       dmaengine_terminate_sync(ctlr->dma_tx);
-       bs->tx_dma_active = false;
-       dmaengine_terminate_sync(ctlr->dma_rx);
-       bs->rx_dma_active = false;
+       if (ctlr->dma_tx) {
+               dmaengine_terminate_sync(ctlr->dma_tx);
+               bs->tx_dma_active = false;
+       }
+       if (ctlr->dma_rx) {
+               dmaengine_terminate_sync(ctlr->dma_rx);
+               bs->rx_dma_active = false;
+       }
        bcm2835_spi_undo_prologue(bs);
 
        /* and reset */
@@ -1365,8 +1373,8 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
        bcm2835_wr(bs, BCM2835_SPI_CS,
                   BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX);
 
-       err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt, 0,
-                              dev_name(&pdev->dev), bs);
+       err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt,
+                              IRQF_SHARED, dev_name(&pdev->dev), bs);
        if (err) {
                dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
                goto out_dma_release;
index 2b9fc84..72b1a5a 100644 (file)
@@ -1578,8 +1578,7 @@ static int cqspi_probe(struct platform_device *pdev)
        ret = cqspi_of_get_pdata(cqspi);
        if (ret) {
                dev_err(dev, "Cannot get mandatory OF data.\n");
-               ret = -ENODEV;
-               goto probe_master_put;
+               return -ENODEV;
        }
 
        /* Obtain QSPI clock. */
@@ -1587,7 +1586,7 @@ static int cqspi_probe(struct platform_device *pdev)
        if (IS_ERR(cqspi->clk)) {
                dev_err(dev, "Cannot claim QSPI clock.\n");
                ret = PTR_ERR(cqspi->clk);
-               goto probe_master_put;
+               return ret;
        }
 
        /* Obtain and remap controller address. */
@@ -1596,7 +1595,7 @@ static int cqspi_probe(struct platform_device *pdev)
        if (IS_ERR(cqspi->iobase)) {
                dev_err(dev, "Cannot remap controller address.\n");
                ret = PTR_ERR(cqspi->iobase);
-               goto probe_master_put;
+               return ret;
        }
 
        /* Obtain and remap AHB address. */
@@ -1605,7 +1604,7 @@ static int cqspi_probe(struct platform_device *pdev)
        if (IS_ERR(cqspi->ahb_base)) {
                dev_err(dev, "Cannot remap AHB address.\n");
                ret = PTR_ERR(cqspi->ahb_base);
-               goto probe_master_put;
+               return ret;
        }
        cqspi->mmap_phys_base = (dma_addr_t)res_ahb->start;
        cqspi->ahb_size = resource_size(res_ahb);
@@ -1614,15 +1613,13 @@ static int cqspi_probe(struct platform_device *pdev)
 
        /* Obtain IRQ line. */
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               ret = -ENXIO;
-               goto probe_master_put;
-       }
+       if (irq < 0)
+               return -ENXIO;
 
        pm_runtime_enable(dev);
        ret = pm_runtime_resume_and_get(dev);
        if (ret < 0)
-               goto probe_master_put;
+               return ret;
 
        ret = clk_prepare_enable(cqspi->clk);
        if (ret) {
@@ -1716,8 +1713,6 @@ probe_reset_failed:
 probe_clk_failed:
        pm_runtime_put_sync(dev);
        pm_runtime_disable(dev);
-probe_master_put:
-       spi_master_put(master);
        return ret;
 }
 
index 31d778e..6a7f7df 100644 (file)
@@ -69,7 +69,7 @@
 #define CDNS_SPI_BAUD_DIV_SHIFT                3 /* Baud rate divisor shift in CR */
 #define CDNS_SPI_SS_SHIFT              10 /* Slave Select field shift in CR */
 #define CDNS_SPI_SS0                   0x1 /* Slave Select zero */
-#define CDNS_SPI_NOSS                  0x3C /* No Slave select */
+#define CDNS_SPI_NOSS                  0xF /* No Slave select */
 
 /*
  * SPI Interrupt Registers bit Masks
index ecea471..f87d97c 100644 (file)
@@ -307,8 +307,9 @@ static u32 dw_spi_prepare_cr0(struct dw_spi *dws, struct spi_device *spi)
                if (spi->mode & SPI_LOOP)
                        cr0 |= DW_HSSI_CTRLR0_SRL;
 
-               if (dws->caps & DW_SPI_CAP_KEEMBAY_MST)
-                       cr0 |= DW_HSSI_CTRLR0_KEEMBAY_MST;
+               /* CTRLR0[31] MST */
+               if (dw_spi_ver_is_ge(dws, HSSI, 102A))
+                       cr0 |= DW_HSSI_CTRLR0_MST;
        }
 
        return cr0;
@@ -942,7 +943,9 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
 
        if (dws->dma_ops && dws->dma_ops->dma_init) {
                ret = dws->dma_ops->dma_init(dev, dws);
-               if (ret) {
+               if (ret == -EPROBE_DEFER) {
+                       goto err_free_irq;
+               } else if (ret) {
                        dev_warn(dev, "DMA init failed\n");
                } else {
                        master->can_dma = dws->dma_ops->can_dma;
@@ -963,6 +966,7 @@ err_dma_exit:
        if (dws->dma_ops && dws->dma_ops->dma_exit)
                dws->dma_ops->dma_exit(dws);
        dw_spi_enable_chip(dws, 0);
+err_free_irq:
        free_irq(dws->irq, master);
 err_free_master:
        spi_controller_put(master);
index 63e5260..1322b8c 100644 (file)
@@ -139,15 +139,20 @@ err_exit:
 
 static int dw_spi_dma_init_generic(struct device *dev, struct dw_spi *dws)
 {
-       dws->rxchan = dma_request_slave_channel(dev, "rx");
-       if (!dws->rxchan)
-               return -ENODEV;
+       int ret;
 
-       dws->txchan = dma_request_slave_channel(dev, "tx");
-       if (!dws->txchan) {
-               dma_release_channel(dws->rxchan);
+       dws->rxchan = dma_request_chan(dev, "rx");
+       if (IS_ERR(dws->rxchan)) {
+               ret = PTR_ERR(dws->rxchan);
                dws->rxchan = NULL;
-               return -ENODEV;
+               goto err_exit;
+       }
+
+       dws->txchan = dma_request_chan(dev, "tx");
+       if (IS_ERR(dws->txchan)) {
+               ret = PTR_ERR(dws->txchan);
+               dws->txchan = NULL;
+               goto free_rxchan;
        }
 
        dws->master->dma_rx = dws->rxchan;
@@ -160,6 +165,12 @@ static int dw_spi_dma_init_generic(struct device *dev, struct dw_spi *dws)
        dw_spi_dma_sg_burst_init(dws);
 
        return 0;
+
+free_rxchan:
+       dma_release_channel(dws->rxchan);
+       dws->rxchan = NULL;
+err_exit:
+       return ret;
 }
 
 static void dw_spi_dma_exit(struct dw_spi *dws)
index 5101c4c..26c40ea 100644 (file)
@@ -214,11 +214,10 @@ static int dw_spi_hssi_init(struct platform_device *pdev,
        return 0;
 }
 
-static int dw_spi_keembay_init(struct platform_device *pdev,
-                              struct dw_spi_mmio *dwsmmio)
+static int dw_spi_intel_init(struct platform_device *pdev,
+                            struct dw_spi_mmio *dwsmmio)
 {
        dwsmmio->dws.ip = DW_HSSI_ID;
-       dwsmmio->dws.caps = DW_SPI_CAP_KEEMBAY_MST;
 
        return 0;
 }
@@ -349,7 +348,8 @@ static const struct of_device_id dw_spi_mmio_of_match[] = {
        { .compatible = "amazon,alpine-dw-apb-ssi", .data = dw_spi_alpine_init},
        { .compatible = "renesas,rzn1-spi", .data = dw_spi_pssi_init},
        { .compatible = "snps,dwc-ssi-1.01a", .data = dw_spi_hssi_init},
-       { .compatible = "intel,keembay-ssi", .data = dw_spi_keembay_init},
+       { .compatible = "intel,keembay-ssi", .data = dw_spi_intel_init},
+       { .compatible = "intel,thunderbay-ssi", .data = dw_spi_intel_init},
        { .compatible = "microchip,sparx5-spi", dw_spi_mscc_sparx5_init},
        { .compatible = "canaan,k210-spi", dw_spi_canaan_k210_init},
        { /* end of table */}
index d5ee513..9e8eb2b 100644 (file)
@@ -23,7 +23,7 @@
        ((_dws)->ip == DW_ ## _ip ## _ID)
 
 #define __dw_spi_ver_cmp(_dws, _ip, _ver, _op) \
-       (dw_spi_ip_is(_dws, _ip) && (_dws)->ver _op DW_ ## _ip ## _ver)
+       (dw_spi_ip_is(_dws, _ip) && (_dws)->ver _op DW_ ## _ip ## _ ## _ver)
 
 #define dw_spi_ver_is(_dws, _ip, _ver) __dw_spi_ver_cmp(_dws, _ip, _ver, ==)
 
@@ -31,8 +31,7 @@
 
 /* DW SPI controller capabilities */
 #define DW_SPI_CAP_CS_OVERRIDE         BIT(0)
-#define DW_SPI_CAP_KEEMBAY_MST         BIT(1)
-#define DW_SPI_CAP_DFS32               BIT(2)
+#define DW_SPI_CAP_DFS32               BIT(1)
 
 /* Register offsets (Generic for both DWC APB SSI and DWC SSI IP-cores) */
 #define DW_SPI_CTRLR0                  0x00
 #define DW_HSSI_CTRLR0_SCPOL                   BIT(9)
 #define DW_HSSI_CTRLR0_TMOD_MASK               GENMASK(11, 10)
 #define DW_HSSI_CTRLR0_SRL                     BIT(13)
-
-/*
- * For Keem Bay, CTRLR0[31] is used to select controller mode.
- * 0: SSI is slave
- * 1: SSI is master
- */
-#define DW_HSSI_CTRLR0_KEEMBAY_MST             BIT(31)
+#define DW_HSSI_CTRLR0_MST                     BIT(31)
 
 /* Bit fields in CTRLR1 */
 #define DW_SPI_NDF_MASK                                GENMASK(15, 0)
index 72ab066..cf1e4f9 100644 (file)
@@ -24,8 +24,7 @@
 #define FSI2SPI_IRQ                    0x20
 
 #define SPI_FSI_BASE                   0x70000
-#define SPI_FSI_INIT_TIMEOUT_MS                1000
-#define SPI_FSI_STATUS_TIMEOUT_MS      100
+#define SPI_FSI_TIMEOUT_MS             1000
 #define SPI_FSI_MAX_RX_SIZE            8
 #define SPI_FSI_MAX_TX_SIZE            40
 
@@ -299,6 +298,7 @@ static void fsi_spi_sequence_init(struct fsi_spi_sequence *seq)
 static int fsi_spi_transfer_data(struct fsi_spi *ctx,
                                 struct spi_transfer *transfer)
 {
+       int loops;
        int rc = 0;
        unsigned long end;
        u64 status = 0ULL;
@@ -317,9 +317,10 @@ static int fsi_spi_transfer_data(struct fsi_spi *ctx,
                        if (rc)
                                return rc;
 
-                       end = jiffies + msecs_to_jiffies(SPI_FSI_STATUS_TIMEOUT_MS);
+                       loops = 0;
+                       end = jiffies + msecs_to_jiffies(SPI_FSI_TIMEOUT_MS);
                        do {
-                               if (time_after(jiffies, end))
+                               if (loops++ && time_after(jiffies, end))
                                        return -ETIMEDOUT;
 
                                rc = fsi_spi_status(ctx, &status, "TX");
@@ -335,9 +336,10 @@ static int fsi_spi_transfer_data(struct fsi_spi *ctx,
                u8 *rx = transfer->rx_buf;
 
                while (transfer->len > recv) {
-                       end = jiffies + msecs_to_jiffies(SPI_FSI_STATUS_TIMEOUT_MS);
+                       loops = 0;
+                       end = jiffies + msecs_to_jiffies(SPI_FSI_TIMEOUT_MS);
                        do {
-                               if (time_after(jiffies, end))
+                               if (loops++ && time_after(jiffies, end))
                                        return -ETIMEDOUT;
 
                                rc = fsi_spi_status(ctx, &status, "RX");
@@ -359,6 +361,7 @@ static int fsi_spi_transfer_data(struct fsi_spi *ctx,
 
 static int fsi_spi_transfer_init(struct fsi_spi *ctx)
 {
+       int loops = 0;
        int rc;
        bool reset = false;
        unsigned long end;
@@ -369,9 +372,9 @@ static int fsi_spi_transfer_init(struct fsi_spi *ctx)
                SPI_FSI_CLOCK_CFG_SCK_NO_DEL |
                FIELD_PREP(SPI_FSI_CLOCK_CFG_SCK_DIV, 19);
 
-       end = jiffies + msecs_to_jiffies(SPI_FSI_INIT_TIMEOUT_MS);
+       end = jiffies + msecs_to_jiffies(SPI_FSI_TIMEOUT_MS);
        do {
-               if (time_after(jiffies, end))
+               if (loops++ && time_after(jiffies, end))
                        return -ETIMEDOUT;
 
                rc = fsi_spi_read_reg(ctx, SPI_FSI_STATUS, &status);
diff --git a/drivers/spi/spi-gxp.c b/drivers/spi/spi-gxp.c
new file mode 100644 (file)
index 0000000..9ea355f
--- /dev/null
@@ -0,0 +1,325 @@
+// SPDX-License-Identifier: GPL-2.0=or-later
+/* Copyright (C) 2022 Hewlett-Packard Development Company, L.P. */
+
+#include <linux/iopoll.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi-mem.h>
+
+#define GXP_SPI0_MAX_CHIPSELECT        2
+#define GXP_SPI_SLEEP_TIME     1
+#define GXP_SPI_TIMEOUT (130 * 1000000 / GXP_SPI_SLEEP_TIME)
+
+#define MANUAL_MODE            0
+#define DIRECT_MODE            1
+#define SPILDAT_LEN            256
+
+#define OFFSET_SPIMCFG         0x0
+#define OFFSET_SPIMCTRL                0x4
+#define OFFSET_SPICMD          0x5
+#define OFFSET_SPIDCNT         0x6
+#define OFFSET_SPIADDR         0x8
+#define OFFSET_SPIINTSTS       0xc
+
+#define SPIMCTRL_START         0x01
+#define SPIMCTRL_BUSY          0x02
+#define SPIMCTRL_DIR           0x08
+
+struct gxp_spi;
+
+struct gxp_spi_chip {
+       struct gxp_spi *spifi;
+       u32 cs;
+};
+
+struct gxp_spi_data {
+       u32 max_cs;
+       u32 mode_bits;
+};
+
+struct gxp_spi {
+       const struct gxp_spi_data *data;
+       void __iomem *reg_base;
+       void __iomem *dat_base;
+       void __iomem *dir_base;
+       struct device *dev;
+       struct gxp_spi_chip chips[GXP_SPI0_MAX_CHIPSELECT];
+};
+
+static void gxp_spi_set_mode(struct gxp_spi *spifi, int mode)
+{
+       u8 value;
+       void __iomem *reg_base = spifi->reg_base;
+
+       value = readb(reg_base + OFFSET_SPIMCTRL);
+
+       if (mode == MANUAL_MODE) {
+               writeb(0x55, reg_base + OFFSET_SPICMD);
+               writeb(0xaa, reg_base + OFFSET_SPICMD);
+               value &= ~0x30;
+       } else {
+               value |= 0x30;
+       }
+       writeb(value, reg_base + OFFSET_SPIMCTRL);
+}
+
+static int gxp_spi_read_reg(struct gxp_spi_chip *chip, const struct spi_mem_op *op)
+{
+       int ret;
+       struct gxp_spi *spifi = chip->spifi;
+       void __iomem *reg_base = spifi->reg_base;
+       u32 value;
+
+       value = readl(reg_base + OFFSET_SPIMCFG);
+       value &= ~(1 << 24);
+       value |= (chip->cs << 24);
+       value &= ~(0x07 << 16);
+       value &= ~(0x1f << 19);
+       writel(value, reg_base + OFFSET_SPIMCFG);
+
+       writel(0, reg_base + OFFSET_SPIADDR);
+
+       writeb(op->cmd.opcode, reg_base + OFFSET_SPICMD);
+
+       writew(op->data.nbytes, reg_base + OFFSET_SPIDCNT);
+
+       value = readb(reg_base + OFFSET_SPIMCTRL);
+       value &= ~SPIMCTRL_DIR;
+       value |= SPIMCTRL_START;
+
+       writeb(value, reg_base + OFFSET_SPIMCTRL);
+
+       ret = readb_poll_timeout(reg_base + OFFSET_SPIMCTRL, value,
+                                !(value & SPIMCTRL_BUSY),
+                                GXP_SPI_SLEEP_TIME, GXP_SPI_TIMEOUT);
+       if (ret) {
+               dev_warn(spifi->dev, "read reg busy time out\n");
+               return ret;
+       }
+
+       memcpy_fromio(op->data.buf.in, spifi->dat_base, op->data.nbytes);
+       return ret;
+}
+
+static int gxp_spi_write_reg(struct gxp_spi_chip *chip, const struct spi_mem_op *op)
+{
+       int ret;
+       struct gxp_spi *spifi = chip->spifi;
+       void __iomem *reg_base = spifi->reg_base;
+       u32 value;
+
+       value = readl(reg_base + OFFSET_SPIMCFG);
+       value &= ~(1 << 24);
+       value |= (chip->cs << 24);
+       value &= ~(0x07 << 16);
+       value &= ~(0x1f << 19);
+       writel(value, reg_base + OFFSET_SPIMCFG);
+
+       writel(0, reg_base + OFFSET_SPIADDR);
+
+       writeb(op->cmd.opcode, reg_base + OFFSET_SPICMD);
+
+       memcpy_toio(spifi->dat_base, op->data.buf.in, op->data.nbytes);
+
+       writew(op->data.nbytes, reg_base + OFFSET_SPIDCNT);
+
+       value = readb(reg_base + OFFSET_SPIMCTRL);
+       value |= SPIMCTRL_DIR;
+       value |= SPIMCTRL_START;
+
+       writeb(value, reg_base + OFFSET_SPIMCTRL);
+
+       ret = readb_poll_timeout(reg_base + OFFSET_SPIMCTRL, value,
+                                !(value & SPIMCTRL_BUSY),
+                                GXP_SPI_SLEEP_TIME, GXP_SPI_TIMEOUT);
+       if (ret)
+               dev_warn(spifi->dev, "write reg busy time out\n");
+
+       return ret;
+}
+
+static ssize_t gxp_spi_read(struct gxp_spi_chip *chip, const struct spi_mem_op *op)
+{
+       struct gxp_spi *spifi = chip->spifi;
+       u32 offset = op->addr.val;
+
+       if (chip->cs == 0)
+               offset += 0x4000000;
+
+       memcpy_fromio(op->data.buf.in, spifi->dir_base + offset, op->data.nbytes);
+
+       return 0;
+}
+
+static ssize_t gxp_spi_write(struct gxp_spi_chip *chip, const struct spi_mem_op *op)
+{
+       struct gxp_spi *spifi = chip->spifi;
+       void __iomem *reg_base = spifi->reg_base;
+       u32 write_len;
+       u32 value;
+       int ret;
+
+       write_len = op->data.nbytes;
+       if (write_len > SPILDAT_LEN)
+               write_len = SPILDAT_LEN;
+
+       value = readl(reg_base + OFFSET_SPIMCFG);
+       value &= ~(1 << 24);
+       value |= (chip->cs << 24);
+       value &= ~(0x07 << 16);
+       value |= (op->addr.nbytes << 16);
+       value &= ~(0x1f << 19);
+       writel(value, reg_base + OFFSET_SPIMCFG);
+
+       writel(op->addr.val, reg_base + OFFSET_SPIADDR);
+
+       writeb(op->cmd.opcode, reg_base + OFFSET_SPICMD);
+
+       writew(write_len, reg_base + OFFSET_SPIDCNT);
+
+       memcpy_toio(spifi->dat_base, op->data.buf.in, write_len);
+
+       value = readb(reg_base + OFFSET_SPIMCTRL);
+       value |= SPIMCTRL_DIR;
+       value |= SPIMCTRL_START;
+
+       writeb(value, reg_base + OFFSET_SPIMCTRL);
+
+       ret = readb_poll_timeout(reg_base + OFFSET_SPIMCTRL, value,
+                                !(value & SPIMCTRL_BUSY),
+                                GXP_SPI_SLEEP_TIME, GXP_SPI_TIMEOUT);
+       if (ret) {
+               dev_warn(spifi->dev, "write busy time out\n");
+               return ret;
+       }
+
+       return write_len;
+}
+
+static int do_gxp_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
+{
+       struct gxp_spi *spifi = spi_controller_get_devdata(mem->spi->master);
+       struct gxp_spi_chip *chip = &spifi->chips[mem->spi->chip_select];
+       int ret;
+
+       if (op->data.dir == SPI_MEM_DATA_IN) {
+               if (!op->addr.nbytes)
+                       ret = gxp_spi_read_reg(chip, op);
+               else
+                       ret = gxp_spi_read(chip, op);
+       } else {
+               if (!op->addr.nbytes)
+                       ret = gxp_spi_write_reg(chip, op);
+               else
+                       ret = gxp_spi_write(chip, op);
+       }
+
+       return ret;
+}
+
+static int gxp_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
+{
+       int ret;
+
+       ret = do_gxp_exec_mem_op(mem, op);
+       if (ret)
+               dev_err(&mem->spi->dev, "operation failed: %d", ret);
+
+       return ret;
+}
+
+static const struct spi_controller_mem_ops gxp_spi_mem_ops = {
+       .exec_op = gxp_exec_mem_op,
+};
+
+static int gxp_spi_setup(struct spi_device *spi)
+{
+       struct gxp_spi *spifi = spi_controller_get_devdata(spi->master);
+       unsigned int cs = spi->chip_select;
+       struct gxp_spi_chip *chip = &spifi->chips[cs];
+
+       chip->spifi = spifi;
+       chip->cs = cs;
+
+       gxp_spi_set_mode(spifi, MANUAL_MODE);
+
+       return 0;
+}
+
+static int gxp_spifi_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       const struct gxp_spi_data *data;
+       struct spi_controller *ctlr;
+       struct gxp_spi *spifi;
+       struct resource *res;
+       int ret;
+
+       data = of_device_get_match_data(&pdev->dev);
+
+       ctlr = devm_spi_alloc_master(dev, sizeof(*spifi));
+       if (!ctlr)
+               return -ENOMEM;
+
+       spifi = spi_controller_get_devdata(ctlr);
+
+       platform_set_drvdata(pdev, spifi);
+       spifi->data = data;
+       spifi->dev = dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       spifi->reg_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(spifi->reg_base))
+               return PTR_ERR(spifi->reg_base);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       spifi->dat_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(spifi->dat_base))
+               return PTR_ERR(spifi->dat_base);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+       spifi->dir_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(spifi->dir_base))
+               return PTR_ERR(spifi->dir_base);
+
+       ctlr->mode_bits = data->mode_bits;
+       ctlr->bus_num = pdev->id;
+       ctlr->mem_ops = &gxp_spi_mem_ops;
+       ctlr->setup = gxp_spi_setup;
+       ctlr->num_chipselect = data->max_cs;
+       ctlr->dev.of_node = dev->of_node;
+
+       ret = devm_spi_register_controller(dev, ctlr);
+       if (ret) {
+               return dev_err_probe(&pdev->dev, ret,
+                                    "failed to register spi controller\n");
+       }
+
+       return 0;
+}
+
+static const struct gxp_spi_data gxp_spifi_data = {
+       .max_cs = 2,
+       .mode_bits = 0,
+};
+
+static const struct of_device_id gxp_spifi_match[] = {
+       {.compatible = "hpe,gxp-spifi", .data = &gxp_spifi_data },
+       { /* null */ }
+};
+MODULE_DEVICE_TABLE(of, gxp_spifi_match);
+
+static struct platform_driver gxp_spifi_driver = {
+       .probe = gxp_spifi_probe,
+       .driver = {
+               .name = "gxp-spifi",
+               .of_match_table = gxp_spifi_match,
+       },
+};
+module_platform_driver(gxp_spifi_driver);
+
+MODULE_DESCRIPTION("HPE GXP SPI Flash Interface driver");
+MODULE_AUTHOR("Nick Hawkins <nick.hawkins@hpe.com>");
+MODULE_LICENSE("GPL");
index f6eec7a..f0d532e 100644 (file)
@@ -74,6 +74,7 @@ static const struct pci_device_id intel_spi_pci_ids[] = {
        { PCI_VDEVICE(INTEL, 0x54a4), (unsigned long)&cnl_info },
        { PCI_VDEVICE(INTEL, 0x7a24), (unsigned long)&cnl_info },
        { PCI_VDEVICE(INTEL, 0x7aa4), (unsigned long)&cnl_info },
+       { PCI_VDEVICE(INTEL, 0x7e23), (unsigned long)&cnl_info },
        { PCI_VDEVICE(INTEL, 0xa0a4), (unsigned long)&bxt_info },
        { PCI_VDEVICE(INTEL, 0xa1a4), (unsigned long)&bxt_info },
        { PCI_VDEVICE(INTEL, 0xa224), (unsigned long)&bxt_info },
index 50f4298..6606368 100644 (file)
@@ -1236,8 +1236,8 @@ static int intel_spi_populate_chip(struct intel_spi *ispi)
                return -ENOMEM;
 
        pdata->nr_parts = 1;
-       pdata->parts = devm_kcalloc(ispi->dev, sizeof(*pdata->parts),
-                                   pdata->nr_parts, GFP_KERNEL);
+       pdata->parts = devm_kcalloc(ispi->dev, pdata->nr_parts,
+                                   sizeof(*pdata->parts), GFP_KERNEL);
        if (!pdata->parts)
                return -ENOMEM;
 
diff --git a/drivers/spi/spi-microchip-core.c b/drivers/spi/spi-microchip-core.c
new file mode 100644 (file)
index 0000000..ce43853
--- /dev/null
@@ -0,0 +1,617 @@
+// SPDX-License-Identifier: (GPL-2.0)
+/*
+ * Microchip CoreSPI SPI controller driver
+ *
+ * Copyright (c) 2018-2022 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Daire McNamara <daire.mcnamara@microchip.com>
+ * Author: Conor Dooley <conor.dooley@microchip.com>
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+
+#define MAX_LEN                                (0xffff)
+#define MAX_CS                         (8)
+#define DEFAULT_FRAMESIZE              (8)
+#define FIFO_DEPTH                     (32)
+#define CLK_GEN_MODE1_MAX              (255)
+#define CLK_GEN_MODE0_MAX              (15)
+#define CLK_GEN_MIN                    (0)
+#define MODE_X_MASK_SHIFT              (24)
+
+#define CONTROL_ENABLE                 BIT(0)
+#define CONTROL_MASTER                 BIT(1)
+#define CONTROL_RX_DATA_INT            BIT(4)
+#define CONTROL_TX_DATA_INT            BIT(5)
+#define CONTROL_RX_OVER_INT            BIT(6)
+#define CONTROL_TX_UNDER_INT           BIT(7)
+#define CONTROL_SPO                    BIT(24)
+#define CONTROL_SPH                    BIT(25)
+#define CONTROL_SPS                    BIT(26)
+#define CONTROL_FRAMEURUN              BIT(27)
+#define CONTROL_CLKMODE                        BIT(28)
+#define CONTROL_BIGFIFO                        BIT(29)
+#define CONTROL_OENOFF                 BIT(30)
+#define CONTROL_RESET                  BIT(31)
+
+#define CONTROL_MODE_MASK              GENMASK(3, 2)
+#define  MOTOROLA_MODE                 (0)
+#define CONTROL_FRAMECNT_MASK          GENMASK(23, 8)
+#define CONTROL_FRAMECNT_SHIFT         (8)
+
+#define STATUS_ACTIVE                  BIT(14)
+#define STATUS_SSEL                    BIT(13)
+#define STATUS_FRAMESTART              BIT(12)
+#define STATUS_TXFIFO_EMPTY_NEXT_READ  BIT(11)
+#define STATUS_TXFIFO_EMPTY            BIT(10)
+#define STATUS_TXFIFO_FULL_NEXT_WRITE  BIT(9)
+#define STATUS_TXFIFO_FULL             BIT(8)
+#define STATUS_RXFIFO_EMPTY_NEXT_READ  BIT(7)
+#define STATUS_RXFIFO_EMPTY            BIT(6)
+#define STATUS_RXFIFO_FULL_NEXT_WRITE  BIT(5)
+#define STATUS_RXFIFO_FULL             BIT(4)
+#define STATUS_TX_UNDERRUN             BIT(3)
+#define STATUS_RX_OVERFLOW             BIT(2)
+#define STATUS_RXDAT_RXED              BIT(1)
+#define STATUS_TXDAT_SENT              BIT(0)
+
+#define INT_TXDONE                     BIT(0)
+#define INT_RXRDY                      BIT(1)
+#define INT_RX_CHANNEL_OVERFLOW                BIT(2)
+#define INT_TX_CHANNEL_UNDERRUN                BIT(3)
+
+#define INT_ENABLE_MASK (CONTROL_RX_DATA_INT | CONTROL_TX_DATA_INT | \
+                        CONTROL_RX_OVER_INT | CONTROL_TX_UNDER_INT)
+
+#define REG_CONTROL            (0x00)
+#define REG_FRAME_SIZE         (0x04)
+#define REG_STATUS             (0x08)
+#define REG_INT_CLEAR          (0x0c)
+#define REG_RX_DATA            (0x10)
+#define REG_TX_DATA            (0x14)
+#define REG_CLK_GEN            (0x18)
+#define REG_SLAVE_SELECT       (0x1c)
+#define  SSEL_MASK             GENMASK(7, 0)
+#define  SSEL_DIRECT           BIT(8)
+#define  SSELOUT_SHIFT         9
+#define  SSELOUT               BIT(SSELOUT_SHIFT)
+#define REG_MIS                        (0x20)
+#define REG_RIS                        (0x24)
+#define REG_CONTROL2           (0x28)
+#define REG_COMMAND            (0x2c)
+#define REG_PKTSIZE            (0x30)
+#define REG_CMD_SIZE           (0x34)
+#define REG_HWSTATUS           (0x38)
+#define REG_STAT8              (0x3c)
+#define REG_CTRL2              (0x48)
+#define REG_FRAMESUP           (0x50)
+
+struct mchp_corespi {
+       void __iomem *regs;
+       struct clk *clk;
+       const u8 *tx_buf;
+       u8 *rx_buf;
+       u32 clk_gen; /* divider for spi output clock generated by the controller */
+       u32 clk_mode;
+       int irq;
+       int tx_len;
+       int rx_len;
+       int pending;
+};
+
+static inline u32 mchp_corespi_read(struct mchp_corespi *spi, unsigned int reg)
+{
+       return readl(spi->regs + reg);
+}
+
+static inline void mchp_corespi_write(struct mchp_corespi *spi, unsigned int reg, u32 val)
+{
+       writel(val, spi->regs + reg);
+}
+
+static inline void mchp_corespi_enable(struct mchp_corespi *spi)
+{
+       u32 control = mchp_corespi_read(spi, REG_CONTROL);
+
+       control |= CONTROL_ENABLE;
+
+       mchp_corespi_write(spi, REG_CONTROL, control);
+}
+
+static inline void mchp_corespi_disable(struct mchp_corespi *spi)
+{
+       u32 control = mchp_corespi_read(spi, REG_CONTROL);
+
+       control &= ~CONTROL_ENABLE;
+
+       mchp_corespi_write(spi, REG_CONTROL, control);
+}
+
+static inline void mchp_corespi_read_fifo(struct mchp_corespi *spi)
+{
+       u8 data;
+       int fifo_max, i = 0;
+
+       fifo_max = min(spi->rx_len, FIFO_DEPTH);
+
+       while ((i < fifo_max) && !(mchp_corespi_read(spi, REG_STATUS) & STATUS_RXFIFO_EMPTY)) {
+               data = mchp_corespi_read(spi, REG_RX_DATA);
+
+               if (spi->rx_buf)
+                       *spi->rx_buf++ = data;
+               i++;
+       }
+       spi->rx_len -= i;
+       spi->pending -= i;
+}
+
+static void mchp_corespi_enable_ints(struct mchp_corespi *spi)
+{
+       u32 control, mask = INT_ENABLE_MASK;
+
+       mchp_corespi_disable(spi);
+
+       control = mchp_corespi_read(spi, REG_CONTROL);
+
+       control |= mask;
+       mchp_corespi_write(spi, REG_CONTROL, control);
+
+       control |= CONTROL_ENABLE;
+       mchp_corespi_write(spi, REG_CONTROL, control);
+}
+
+static void mchp_corespi_disable_ints(struct mchp_corespi *spi)
+{
+       u32 control, mask = INT_ENABLE_MASK;
+
+       mchp_corespi_disable(spi);
+
+       control = mchp_corespi_read(spi, REG_CONTROL);
+       control &= ~mask;
+       mchp_corespi_write(spi, REG_CONTROL, control);
+
+       control |= CONTROL_ENABLE;
+       mchp_corespi_write(spi, REG_CONTROL, control);
+}
+
+static inline void mchp_corespi_set_xfer_size(struct mchp_corespi *spi, int len)
+{
+       u32 control;
+       u16 lenpart;
+
+       /*
+        * Disable the SPI controller. Writes to transfer length have
+        * no effect when the controller is enabled.
+        */
+       mchp_corespi_disable(spi);
+
+       /*
+        * The lower 16 bits of the frame count are stored in the control reg
+        * for legacy reasons, but the upper 16 written to a different register:
+        * FRAMESUP. While both the upper and lower bits can be *READ* from the
+        * FRAMESUP register, writing to the lower 16 bits is a NOP
+        */
+       lenpart = len & 0xffff;
+
+       control = mchp_corespi_read(spi, REG_CONTROL);
+       control &= ~CONTROL_FRAMECNT_MASK;
+       control |= lenpart << CONTROL_FRAMECNT_SHIFT;
+       mchp_corespi_write(spi, REG_CONTROL, control);
+
+       lenpart = len & 0xffff0000;
+       mchp_corespi_write(spi, REG_FRAMESUP, lenpart);
+
+       control |= CONTROL_ENABLE;
+       mchp_corespi_write(spi, REG_CONTROL, control);
+}
+
+static inline void mchp_corespi_write_fifo(struct mchp_corespi *spi)
+{
+       u8 byte;
+       int fifo_max, i = 0;
+
+       fifo_max = min(spi->tx_len, FIFO_DEPTH);
+       mchp_corespi_set_xfer_size(spi, fifo_max);
+
+       while ((i < fifo_max) && !(mchp_corespi_read(spi, REG_STATUS) & STATUS_TXFIFO_FULL)) {
+               byte = spi->tx_buf ? *spi->tx_buf++ : 0xaa;
+               mchp_corespi_write(spi, REG_TX_DATA, byte);
+               i++;
+       }
+
+       spi->tx_len -= i;
+       spi->pending += i;
+}
+
+static inline void mchp_corespi_set_framesize(struct mchp_corespi *spi, int bt)
+{
+       u32 control;
+
+       /*
+        * Disable the SPI controller. Writes to the frame size have
+        * no effect when the controller is enabled.
+        */
+       mchp_corespi_disable(spi);
+
+       mchp_corespi_write(spi, REG_FRAME_SIZE, bt);
+
+       control = mchp_corespi_read(spi, REG_CONTROL);
+       control |= CONTROL_ENABLE;
+       mchp_corespi_write(spi, REG_CONTROL, control);
+}
+
+static void mchp_corespi_set_cs(struct spi_device *spi, bool disable)
+{
+       u32 reg;
+       struct mchp_corespi *corespi = spi_master_get_devdata(spi->master);
+
+       reg = mchp_corespi_read(corespi, REG_SLAVE_SELECT);
+       reg &= ~BIT(spi->chip_select);
+       reg |= !disable << spi->chip_select;
+
+       mchp_corespi_write(corespi, REG_SLAVE_SELECT, reg);
+}
+
+static int mchp_corespi_setup(struct spi_device *spi)
+{
+       struct mchp_corespi *corespi = spi_master_get_devdata(spi->master);
+       u32 reg;
+
+       /*
+        * Active high slaves need to be specifically set to their inactive
+        * states during probe by adding them to the "control group" & thus
+        * driving their select line low.
+        */
+       if (spi->mode & SPI_CS_HIGH) {
+               reg = mchp_corespi_read(corespi, REG_SLAVE_SELECT);
+               reg |= BIT(spi->chip_select);
+               mchp_corespi_write(corespi, REG_SLAVE_SELECT, reg);
+       }
+       return 0;
+}
+
+static void mchp_corespi_init(struct spi_master *master, struct mchp_corespi *spi)
+{
+       unsigned long clk_hz;
+       u32 control = mchp_corespi_read(spi, REG_CONTROL);
+
+       control |= CONTROL_MASTER;
+
+       control &= ~CONTROL_MODE_MASK;
+       control |= MOTOROLA_MODE;
+
+       mchp_corespi_set_framesize(spi, DEFAULT_FRAMESIZE);
+
+       /* max. possible spi clock rate is the apb clock rate */
+       clk_hz = clk_get_rate(spi->clk);
+       master->max_speed_hz = clk_hz;
+
+       /*
+        * The controller must be configured so that it doesn't remove Chip
+        * Select until the entire message has been transferred, even if at
+        * some points TX FIFO becomes empty.
+        *
+        * BIGFIFO mode is also enabled, which sets the fifo depth to 32 frames
+        * for the 8 bit transfers that this driver uses.
+        */
+       control = mchp_corespi_read(spi, REG_CONTROL);
+       control |= CONTROL_SPS | CONTROL_BIGFIFO;
+
+       mchp_corespi_write(spi, REG_CONTROL, control);
+
+       mchp_corespi_enable_ints(spi);
+
+       /*
+        * It is required to enable direct mode, otherwise control over the chip
+        * select is relinquished to the hardware. SSELOUT is enabled too so we
+        * can deal with active high slaves.
+        */
+       mchp_corespi_write(spi, REG_SLAVE_SELECT, SSELOUT | SSEL_DIRECT);
+
+       control = mchp_corespi_read(spi, REG_CONTROL);
+
+       control &= ~CONTROL_RESET;
+       control |= CONTROL_ENABLE;
+
+       mchp_corespi_write(spi, REG_CONTROL, control);
+}
+
+static inline void mchp_corespi_set_clk_gen(struct mchp_corespi *spi)
+{
+       u32 control;
+
+       mchp_corespi_disable(spi);
+
+       control = mchp_corespi_read(spi, REG_CONTROL);
+       if (spi->clk_mode)
+               control |= CONTROL_CLKMODE;
+       else
+               control &= ~CONTROL_CLKMODE;
+
+       mchp_corespi_write(spi, REG_CLK_GEN, spi->clk_gen);
+       mchp_corespi_write(spi, REG_CONTROL, control);
+       mchp_corespi_write(spi, REG_CONTROL, control | CONTROL_ENABLE);
+}
+
+static inline void mchp_corespi_set_mode(struct mchp_corespi *spi, unsigned int mode)
+{
+       u32 control, mode_val;
+
+       switch (mode & SPI_MODE_X_MASK) {
+       case SPI_MODE_0:
+               mode_val = 0;
+               break;
+       case SPI_MODE_1:
+               mode_val = CONTROL_SPH;
+               break;
+       case SPI_MODE_2:
+               mode_val = CONTROL_SPO;
+               break;
+       case SPI_MODE_3:
+               mode_val = CONTROL_SPH | CONTROL_SPO;
+               break;
+       }
+
+       /*
+        * Disable the SPI controller. Writes to the frame size have
+        * no effect when the controller is enabled.
+        */
+       mchp_corespi_disable(spi);
+
+       control = mchp_corespi_read(spi, REG_CONTROL);
+       control &= ~(SPI_MODE_X_MASK << MODE_X_MASK_SHIFT);
+       control |= mode_val;
+
+       mchp_corespi_write(spi, REG_CONTROL, control);
+
+       control |= CONTROL_ENABLE;
+       mchp_corespi_write(spi, REG_CONTROL, control);
+}
+
+static irqreturn_t mchp_corespi_interrupt(int irq, void *dev_id)
+{
+       struct spi_master *master = dev_id;
+       struct mchp_corespi *spi = spi_master_get_devdata(master);
+       u32 intfield = mchp_corespi_read(spi, REG_MIS) & 0xf;
+       bool finalise = false;
+
+       /* Interrupt line may be shared and not for us at all */
+       if (intfield == 0)
+               return IRQ_NONE;
+
+       if (intfield & INT_TXDONE) {
+               mchp_corespi_write(spi, REG_INT_CLEAR, INT_TXDONE);
+
+               if (spi->rx_len)
+                       mchp_corespi_read_fifo(spi);
+
+               if (spi->tx_len)
+                       mchp_corespi_write_fifo(spi);
+
+               if (!spi->rx_len)
+                       finalise = true;
+       }
+
+       if (intfield & INT_RXRDY)
+               mchp_corespi_write(spi, REG_INT_CLEAR, INT_RXRDY);
+
+       if (intfield & INT_RX_CHANNEL_OVERFLOW) {
+               mchp_corespi_write(spi, REG_INT_CLEAR, INT_RX_CHANNEL_OVERFLOW);
+               finalise = true;
+               dev_err(&master->dev,
+                       "%s: RX OVERFLOW: rxlen: %d, txlen: %d\n", __func__,
+                       spi->rx_len, spi->tx_len);
+       }
+
+       if (intfield & INT_TX_CHANNEL_UNDERRUN) {
+               mchp_corespi_write(spi, REG_INT_CLEAR, INT_TX_CHANNEL_UNDERRUN);
+               finalise = true;
+               dev_err(&master->dev,
+                       "%s: TX UNDERFLOW: rxlen: %d, txlen: %d\n", __func__,
+                       spi->rx_len, spi->tx_len);
+       }
+
+       if (finalise)
+               spi_finalize_current_transfer(master);
+
+       return IRQ_HANDLED;
+}
+
+static int mchp_corespi_calculate_clkgen(struct mchp_corespi *spi,
+                                        unsigned long target_hz)
+{
+       unsigned long clk_hz, spi_hz, clk_gen;
+
+       clk_hz = clk_get_rate(spi->clk);
+       if (!clk_hz)
+               return -EINVAL;
+       spi_hz = min(target_hz, clk_hz);
+
+       /*
+        * There are two possible clock modes for the controller generated
+        * clock's division ratio:
+        * CLK_MODE = 0: 1 / (2^(CLK_GEN + 1)) where CLK_GEN = 0 to 15.
+        * CLK_MODE = 1: 1 / (2 * CLK_GEN + 1) where CLK_GEN = 0 to 255.
+        * First try mode 1, fall back to 0 and if we have tried both modes and
+        * we /still/ can't get a good setting, we then throw the toys out of
+        * the pram and give up
+        * clk_gen is the register name for the clock divider on MPFS.
+        */
+       clk_gen = DIV_ROUND_UP(clk_hz, 2 * spi_hz) - 1;
+       if (clk_gen > CLK_GEN_MODE1_MAX || clk_gen <= CLK_GEN_MIN) {
+               clk_gen = DIV_ROUND_UP(clk_hz, spi_hz);
+               clk_gen = fls(clk_gen) - 1;
+
+               if (clk_gen > CLK_GEN_MODE0_MAX)
+                       return -EINVAL;
+
+               spi->clk_mode = 0;
+       } else {
+               spi->clk_mode = 1;
+       }
+
+       spi->clk_gen = clk_gen;
+       return 0;
+}
+
+static int mchp_corespi_transfer_one(struct spi_master *master,
+                                    struct spi_device *spi_dev,
+                                    struct spi_transfer *xfer)
+{
+       struct mchp_corespi *spi = spi_master_get_devdata(master);
+       int ret;
+
+       ret = mchp_corespi_calculate_clkgen(spi, (unsigned long)xfer->speed_hz);
+       if (ret) {
+               dev_err(&master->dev, "failed to set clk_gen for target %u Hz\n", xfer->speed_hz);
+               return ret;
+       }
+
+       mchp_corespi_set_clk_gen(spi);
+
+       spi->tx_buf = xfer->tx_buf;
+       spi->rx_buf = xfer->rx_buf;
+       spi->tx_len = xfer->len;
+       spi->rx_len = xfer->len;
+       spi->pending = 0;
+
+       mchp_corespi_set_xfer_size(spi, (spi->tx_len > FIFO_DEPTH)
+                                  ? FIFO_DEPTH : spi->tx_len);
+
+       if (spi->tx_len)
+               mchp_corespi_write_fifo(spi);
+       return 1;
+}
+
+static int mchp_corespi_prepare_message(struct spi_master *master,
+                                       struct spi_message *msg)
+{
+       struct spi_device *spi_dev = msg->spi;
+       struct mchp_corespi *spi = spi_master_get_devdata(master);
+
+       mchp_corespi_set_framesize(spi, DEFAULT_FRAMESIZE);
+       mchp_corespi_set_mode(spi, spi_dev->mode);
+
+       return 0;
+}
+
+static int mchp_corespi_probe(struct platform_device *pdev)
+{
+       struct spi_master *master;
+       struct mchp_corespi *spi;
+       struct resource *res;
+       u32 num_cs;
+       int ret = 0;
+
+       master = devm_spi_alloc_master(&pdev->dev, sizeof(*spi));
+       if (!master)
+               return dev_err_probe(&pdev->dev, -ENOMEM,
+                                    "unable to allocate master for SPI controller\n");
+
+       platform_set_drvdata(pdev, master);
+
+       if (of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs))
+               num_cs = MAX_CS;
+
+       master->num_chipselect = num_cs;
+       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+       master->setup = mchp_corespi_setup;
+       master->bits_per_word_mask = SPI_BPW_MASK(8);
+       master->transfer_one = mchp_corespi_transfer_one;
+       master->prepare_message = mchp_corespi_prepare_message;
+       master->set_cs = mchp_corespi_set_cs;
+       master->dev.of_node = pdev->dev.of_node;
+
+       spi = spi_master_get_devdata(master);
+
+       spi->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+       if (IS_ERR(spi->regs))
+               return PTR_ERR(spi->regs);
+
+       spi->irq = platform_get_irq(pdev, 0);
+       if (spi->irq <= 0)
+               return dev_err_probe(&pdev->dev, -ENXIO,
+                                    "invalid IRQ %d for SPI controller\n",
+                                    spi->irq);
+
+       ret = devm_request_irq(&pdev->dev, spi->irq, mchp_corespi_interrupt,
+                              IRQF_SHARED, dev_name(&pdev->dev), master);
+       if (ret)
+               return dev_err_probe(&pdev->dev, ret,
+                                    "could not request irq: %d\n", ret);
+
+       spi->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(spi->clk))
+               return dev_err_probe(&pdev->dev, PTR_ERR(spi->clk),
+                                    "could not get clk: %d\n", ret);
+
+       ret = clk_prepare_enable(spi->clk);
+       if (ret)
+               return dev_err_probe(&pdev->dev, ret,
+                                    "failed to enable clock\n");
+
+       mchp_corespi_init(master, spi);
+
+       ret = devm_spi_register_master(&pdev->dev, master);
+       if (ret) {
+               mchp_corespi_disable(spi);
+               clk_disable_unprepare(spi->clk);
+               return dev_err_probe(&pdev->dev, ret,
+                                    "unable to register master for SPI controller\n");
+       }
+
+       dev_info(&pdev->dev, "Registered SPI controller %d\n", master->bus_num);
+
+       return 0;
+}
+
+static int mchp_corespi_remove(struct platform_device *pdev)
+{
+       struct spi_master *master  = platform_get_drvdata(pdev);
+       struct mchp_corespi *spi = spi_master_get_devdata(master);
+
+       mchp_corespi_disable_ints(spi);
+       clk_disable_unprepare(spi->clk);
+       mchp_corespi_disable(spi);
+
+       return 0;
+}
+
+#define MICROCHIP_SPI_PM_OPS (NULL)
+
+/*
+ * Platform driver data structure
+ */
+
+#if defined(CONFIG_OF)
+static const struct of_device_id mchp_corespi_dt_ids[] = {
+       { .compatible = "microchip,mpfs-spi" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mchp_corespi_dt_ids);
+#endif
+
+static struct platform_driver mchp_corespi_driver = {
+       .probe = mchp_corespi_probe,
+       .driver = {
+               .name = "microchip-corespi",
+               .pm = MICROCHIP_SPI_PM_OPS,
+               .of_match_table = of_match_ptr(mchp_corespi_dt_ids),
+       },
+       .remove = mchp_corespi_remove,
+};
+module_platform_driver(mchp_corespi_driver);
+MODULE_DESCRIPTION("Microchip coreSPI SPI controller driver");
+MODULE_AUTHOR("Daire McNamara <daire.mcnamara@microchip.com>");
+MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>");
+MODULE_LICENSE("GPL");
index 7654736..6093112 100644 (file)
@@ -37,12 +37,6 @@ struct mpc52xx_psc_spi {
        struct mpc52xx_psc_fifo __iomem *fifo;
        unsigned int irq;
        u8 bits_per_word;
-       u8 busy;
-
-       struct work_struct work;
-
-       struct list_head queue;
-       spinlock_t lock;
 
        struct completion done;
 };
@@ -198,69 +192,53 @@ static int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi,
        return 0;
 }
 
-static void mpc52xx_psc_spi_work(struct work_struct *work)
+int mpc52xx_psc_spi_transfer_one_message(struct spi_controller *ctlr,
+                                        struct spi_message *m)
 {
-       struct mpc52xx_psc_spi *mps =
-               container_of(work, struct mpc52xx_psc_spi, work);
-
-       spin_lock_irq(&mps->lock);
-       mps->busy = 1;
-       while (!list_empty(&mps->queue)) {
-               struct spi_message *m;
-               struct spi_device *spi;
-               struct spi_transfer *t = NULL;
-               unsigned cs_change;
-               int status;
-
-               m = container_of(mps->queue.next, struct spi_message, queue);
-               list_del_init(&m->queue);
-               spin_unlock_irq(&mps->lock);
-
-               spi = m->spi;
-               cs_change = 1;
-               status = 0;
-               list_for_each_entry (t, &m->transfers, transfer_list) {
-                       if (t->bits_per_word || t->speed_hz) {
-                               status = mpc52xx_psc_spi_transfer_setup(spi, t);
-                               if (status < 0)
-                                       break;
-                       }
-
-                       if (cs_change)
-                               mpc52xx_psc_spi_activate_cs(spi);
-                       cs_change = t->cs_change;
-
-                       status = mpc52xx_psc_spi_transfer_rxtx(spi, t);
-                       if (status)
+       struct spi_device *spi;
+       struct spi_transfer *t = NULL;
+       unsigned cs_change;
+       int status;
+
+       spi = m->spi;
+       cs_change = 1;
+       status = 0;
+       list_for_each_entry (t, &m->transfers, transfer_list) {
+               if (t->bits_per_word || t->speed_hz) {
+                       status = mpc52xx_psc_spi_transfer_setup(spi, t);
+                       if (status < 0)
                                break;
-                       m->actual_length += t->len;
+               }
 
-                       spi_transfer_delay_exec(t);
+               if (cs_change)
+                       mpc52xx_psc_spi_activate_cs(spi);
+               cs_change = t->cs_change;
 
-                       if (cs_change)
-                               mpc52xx_psc_spi_deactivate_cs(spi);
-               }
+               status = mpc52xx_psc_spi_transfer_rxtx(spi, t);
+               if (status)
+                       break;
+               m->actual_length += t->len;
 
-               m->status = status;
-               if (m->complete)
-                       m->complete(m->context);
+               spi_transfer_delay_exec(t);
 
-               if (status || !cs_change)
+               if (cs_change)
                        mpc52xx_psc_spi_deactivate_cs(spi);
+       }
 
-               mpc52xx_psc_spi_transfer_setup(spi, NULL);
+       m->status = status;
+       if (status || !cs_change)
+               mpc52xx_psc_spi_deactivate_cs(spi);
 
-               spin_lock_irq(&mps->lock);
-       }
-       mps->busy = 0;
-       spin_unlock_irq(&mps->lock);
+       mpc52xx_psc_spi_transfer_setup(spi, NULL);
+
+       spi_finalize_current_message(ctlr);
+
+       return 0;
 }
 
 static int mpc52xx_psc_spi_setup(struct spi_device *spi)
 {
-       struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
        struct mpc52xx_psc_spi_cs *cs = spi->controller_state;
-       unsigned long flags;
 
        if (spi->bits_per_word%8)
                return -EINVAL;
@@ -275,28 +253,6 @@ static int mpc52xx_psc_spi_setup(struct spi_device *spi)
        cs->bits_per_word = spi->bits_per_word;
        cs->speed_hz = spi->max_speed_hz;
 
-       spin_lock_irqsave(&mps->lock, flags);
-       if (!mps->busy)
-               mpc52xx_psc_spi_deactivate_cs(spi);
-       spin_unlock_irqrestore(&mps->lock, flags);
-
-       return 0;
-}
-
-static int mpc52xx_psc_spi_transfer(struct spi_device *spi,
-               struct spi_message *m)
-{
-       struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
-       unsigned long flags;
-
-       m->actual_length = 0;
-       m->status = -EINPROGRESS;
-
-       spin_lock_irqsave(&mps->lock, flags);
-       list_add_tail(&m->queue, &mps->queue);
-       schedule_work(&mps->work);
-       spin_unlock_irqrestore(&mps->lock, flags);
-
        return 0;
 }
 
@@ -391,7 +347,7 @@ static int mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
                master->num_chipselect = pdata->max_chipselect;
        }
        master->setup = mpc52xx_psc_spi_setup;
-       master->transfer = mpc52xx_psc_spi_transfer;
+       master->transfer_one_message = mpc52xx_psc_spi_transfer_one_message;
        master->cleanup = mpc52xx_psc_spi_cleanup;
        master->dev.of_node = dev->of_node;
 
@@ -415,10 +371,7 @@ static int mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
                goto free_irq;
        }
 
-       spin_lock_init(&mps->lock);
        init_completion(&mps->done);
-       INIT_WORK(&mps->work, mpc52xx_psc_spi_work);
-       INIT_LIST_HEAD(&mps->queue);
 
        ret = spi_register_master(master);
        if (ret < 0)
@@ -470,7 +423,6 @@ static int mpc52xx_psc_spi_of_remove(struct platform_device *op)
        struct spi_master *master = spi_master_get(platform_get_drvdata(op));
        struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master);
 
-       flush_work(&mps->work);
        spi_unregister_master(master);
        free_irq(mps->irq, mps);
        if (mps->psc)
index ba67dbe..49f6424 100644 (file)
@@ -36,6 +36,7 @@
 #define NPCM_FIU_UMA_DR1               0x34
 #define NPCM_FIU_UMA_DR2               0x38
 #define NPCM_FIU_UMA_DR3               0x3C
+#define NPCM_FIU_CFG                   0x78
 #define NPCM_FIU_MAX_REG_LIMIT         0x80
 
 /* FIU Direct Read Configuration Register */
 #define NPCM_FIU_UMA_DR3_RB13          GENMASK(15, 8)
 #define NPCM_FIU_UMA_DR3_RB12          GENMASK(7, 0)
 
+/* FIU Configuration Register */
+#define NPCM_FIU_CFG_FIU_FIX           BIT(31)
+
 /* FIU Read Mode */
 enum {
        DRD_SINGLE_WIRE_MODE    = 0,
@@ -187,6 +191,7 @@ enum {
        FIU0 = 0,
        FIU3,
        FIUX,
+       FIU1,
 };
 
 struct npcm_fiu_info {
@@ -214,6 +219,21 @@ static const struct fiu_data npcm7xx_fiu_data = {
        .fiu_max = 3,
 };
 
+static const struct npcm_fiu_info npxm8xx_fiu_info[] = {
+       {.name = "FIU0", .fiu_id = FIU0,
+               .max_map_size = MAP_SIZE_128MB, .max_cs = 2},
+       {.name = "FIU3", .fiu_id = FIU3,
+               .max_map_size = MAP_SIZE_128MB, .max_cs = 4},
+       {.name = "FIUX", .fiu_id = FIUX,
+               .max_map_size = MAP_SIZE_16MB, .max_cs = 2},
+       {.name = "FIU1", .fiu_id = FIU1,
+               .max_map_size = MAP_SIZE_16MB, .max_cs = 4} };
+
+static const struct fiu_data npxm8xx_fiu_data = {
+       .npcm_fiu_data_info = npxm8xx_fiu_info,
+       .fiu_max = 4,
+};
+
 struct npcm_fiu_spi;
 
 struct npcm_fiu_chip {
@@ -252,8 +272,7 @@ static void npcm_fiu_set_drd(struct npcm_fiu_spi *fiu,
        fiu->drd_op.addr.buswidth = op->addr.buswidth;
        regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
                           NPCM_FIU_DRD_CFG_DBW,
-                          ((op->dummy.nbytes * ilog2(op->addr.buswidth)) / BITS_PER_BYTE)
-                          << NPCM_FIU_DRD_DBW_SHIFT);
+                          op->dummy.nbytes << NPCM_FIU_DRD_DBW_SHIFT);
        fiu->drd_op.dummy.nbytes = op->dummy.nbytes;
        regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
                           NPCM_FIU_DRD_CFG_RDCMD, op->cmd.opcode);
@@ -625,6 +644,10 @@ static int npcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc)
                regmap_update_bits(gcr_regmap, NPCM7XX_INTCR3_OFFSET,
                                   NPCM7XX_INTCR3_FIU_FIX,
                                   NPCM7XX_INTCR3_FIU_FIX);
+       } else {
+               regmap_update_bits(fiu->regmap, NPCM_FIU_CFG,
+                                  NPCM_FIU_CFG_FIU_FIX,
+                                  NPCM_FIU_CFG_FIU_FIX);
        }
 
        if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN) {
@@ -665,6 +688,7 @@ static const struct spi_controller_mem_ops npcm_fiu_mem_ops = {
 
 static const struct of_device_id npcm_fiu_dt_ids[] = {
        { .compatible = "nuvoton,npcm750-fiu", .data = &npcm7xx_fiu_data  },
+       { .compatible = "nuvoton,npcm845-fiu", .data = &npxm8xx_fiu_data  },
        { /* sentinel */ }
 };
 
index edb42d0..838d12e 100644 (file)
@@ -1404,6 +1404,10 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = {
        { PCI_VDEVICE(INTEL, 0x7aab), LPSS_CNL_SSP },
        { PCI_VDEVICE(INTEL, 0x7af9), LPSS_CNL_SSP },
        { PCI_VDEVICE(INTEL, 0x7afb), LPSS_CNL_SSP },
+       /* MTL-P */
+       { PCI_VDEVICE(INTEL, 0x7e27), LPSS_CNL_SSP },
+       { PCI_VDEVICE(INTEL, 0x7e30), LPSS_CNL_SSP },
+       { PCI_VDEVICE(INTEL, 0x7e46), LPSS_CNL_SSP },
        /* CNL-LP */
        { PCI_VDEVICE(INTEL, 0x9daa), LPSS_CNL_SSP },
        { PCI_VDEVICE(INTEL, 0x9dab), LPSS_CNL_SSP },
index 7a014ee..411b130 100644 (file)
@@ -613,6 +613,10 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx,
                                               rspi->dma_callbacked, HZ);
        if (ret > 0 && rspi->dma_callbacked) {
                ret = 0;
+               if (tx)
+                       dmaengine_synchronize(rspi->ctlr->dma_tx);
+               if (rx)
+                       dmaengine_synchronize(rspi->ctlr->dma_rx);
        } else {
                if (!ret) {
                        dev_err(&rspi->ctlr->dev, "DMA timeout\n");
index c26440e..7f34686 100644 (file)
@@ -18,7 +18,7 @@
 
 #include <linux/platform_data/spi-s3c64xx.h>
 
-#define MAX_SPI_PORTS          6
+#define MAX_SPI_PORTS          12
 #define S3C64XX_SPI_QUIRK_POLL         (1 << 0)
 #define S3C64XX_SPI_QUIRK_CS_AUTO      (1 << 1)
 #define AUTOSUSPEND_TIMEOUT    2000
@@ -59,6 +59,7 @@
 #define S3C64XX_SPI_MODE_BUS_TSZ_HALFWORD      (1<<17)
 #define S3C64XX_SPI_MODE_BUS_TSZ_WORD          (2<<17)
 #define S3C64XX_SPI_MODE_BUS_TSZ_MASK          (3<<17)
+#define S3C64XX_SPI_MODE_SELF_LOOPBACK         (1<<3)
 #define S3C64XX_SPI_MODE_RXDMA_ON              (1<<2)
 #define S3C64XX_SPI_MODE_TXDMA_ON              (1<<1)
 #define S3C64XX_SPI_MODE_4BURST                        (1<<0)
@@ -130,11 +131,13 @@ struct s3c64xx_spi_dma_data {
  * @fifo_lvl_mask: Bit-mask for {TX|RX}_FIFO_LVL bits in SPI_STATUS register.
  * @rx_lvl_offset: Bit offset of RX_FIFO_LVL bits in SPI_STATUS regiter.
  * @tx_st_done: Bit offset of TX_DONE bit in SPI_STATUS regiter.
+ * @clk_div: Internal clock divider
  * @quirks: Bitmask of known quirks
  * @high_speed: True, if the controller supports HIGH_SPEED_EN bit.
  * @clk_from_cmu: True, if the controller does not include a clock mux and
  *     prescaler unit.
  * @clk_ioclk: True if clock is present on this device
+ * @has_loopback: True if loopback mode can be supported
  *
  * The Samsung s3c64xx SPI controller are used on various Samsung SoC's but
  * differ in some aspects such as the size of the fifo and spi bus clock
@@ -146,9 +149,11 @@ struct s3c64xx_spi_port_config {
        int     rx_lvl_offset;
        int     tx_st_done;
        int     quirks;
+       int     clk_div;
        bool    high_speed;
        bool    clk_from_cmu;
        bool    clk_ioclk;
+       bool    has_loopback;
 };
 
 /**
@@ -350,19 +355,59 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
        if (is_polling(sdd))
                return 0;
 
+       /* Requests DMA channels */
+       sdd->rx_dma.ch = dma_request_chan(&sdd->pdev->dev, "rx");
+       if (IS_ERR(sdd->rx_dma.ch)) {
+               dev_err(&sdd->pdev->dev, "Failed to get RX DMA channel\n");
+               sdd->rx_dma.ch = NULL;
+               return 0;
+       }
+
+       sdd->tx_dma.ch = dma_request_chan(&sdd->pdev->dev, "tx");
+       if (IS_ERR(sdd->tx_dma.ch)) {
+               dev_err(&sdd->pdev->dev, "Failed to get TX DMA channel\n");
+               dma_release_channel(sdd->rx_dma.ch);
+               sdd->tx_dma.ch = NULL;
+               sdd->rx_dma.ch = NULL;
+               return 0;
+       }
+
        spi->dma_rx = sdd->rx_dma.ch;
        spi->dma_tx = sdd->tx_dma.ch;
 
        return 0;
 }
 
+static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
+{
+       struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
+
+       if (is_polling(sdd))
+               return 0;
+
+       /* Releases DMA channels if they are allocated */
+       if (sdd->rx_dma.ch && sdd->tx_dma.ch) {
+               dma_release_channel(sdd->rx_dma.ch);
+               dma_release_channel(sdd->tx_dma.ch);
+               sdd->rx_dma.ch = 0;
+               sdd->tx_dma.ch = 0;
+       }
+
+       return 0;
+}
+
 static bool s3c64xx_spi_can_dma(struct spi_master *master,
                                struct spi_device *spi,
                                struct spi_transfer *xfer)
 {
        struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
 
-       return xfer->len > (FIFO_LVL_MASK(sdd) >> 1) + 1;
+       if (sdd->rx_dma.ch && sdd->tx_dma.ch) {
+               return xfer->len > (FIFO_LVL_MASK(sdd) >> 1) + 1;
+       } else {
+               return false;
+       }
+
 }
 
 static int s3c64xx_enable_datapath(struct s3c64xx_spi_driver_data *sdd,
@@ -577,6 +622,7 @@ static int s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
        void __iomem *regs = sdd->regs;
        int ret;
        u32 val;
+       int div = sdd->port_conf->clk_div;
 
        /* Disable Clock */
        if (!sdd->port_conf->clk_from_cmu) {
@@ -619,19 +665,21 @@ static int s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
                break;
        }
 
+       if ((sdd->cur_mode & SPI_LOOP) && sdd->port_conf->has_loopback)
+               val |= S3C64XX_SPI_MODE_SELF_LOOPBACK;
+
        writel(val, regs + S3C64XX_SPI_MODE_CFG);
 
        if (sdd->port_conf->clk_from_cmu) {
-               /* The src_clk clock is divided internally by 2 */
-               ret = clk_set_rate(sdd->src_clk, sdd->cur_speed * 2);
+               ret = clk_set_rate(sdd->src_clk, sdd->cur_speed * div);
                if (ret)
                        return ret;
-               sdd->cur_speed = clk_get_rate(sdd->src_clk) / 2;
+               sdd->cur_speed = clk_get_rate(sdd->src_clk) / div;
        } else {
                /* Configure Clock */
                val = readl(regs + S3C64XX_SPI_CLK_CFG);
                val &= ~S3C64XX_SPI_PSR_MASK;
-               val |= ((clk_get_rate(sdd->src_clk) / sdd->cur_speed / 2 - 1)
+               val |= ((clk_get_rate(sdd->src_clk) / sdd->cur_speed / div - 1)
                                & S3C64XX_SPI_PSR_MASK);
                writel(val, regs + S3C64XX_SPI_CLK_CFG);
 
@@ -697,7 +745,7 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
            sdd->rx_dma.ch && sdd->tx_dma.ch) {
                use_dma = 1;
 
-       } else if (is_polling(sdd) && xfer->len > fifo_len) {
+       } else if (xfer->len > fifo_len) {
                tx_buf = xfer->tx_buf;
                rx_buf = xfer->rx_buf;
                origin_len = xfer->len;
@@ -825,6 +873,7 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
        struct s3c64xx_spi_csinfo *cs = spi->controller_data;
        struct s3c64xx_spi_driver_data *sdd;
        int err;
+       int div;
 
        sdd = spi_master_get_devdata(spi->master);
        if (spi->dev.of_node) {
@@ -843,22 +892,24 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
 
        pm_runtime_get_sync(&sdd->pdev->dev);
 
+       div = sdd->port_conf->clk_div;
+
        /* Check if we can provide the requested rate */
        if (!sdd->port_conf->clk_from_cmu) {
                u32 psr, speed;
 
                /* Max possible */
-               speed = clk_get_rate(sdd->src_clk) / 2 / (0 + 1);
+               speed = clk_get_rate(sdd->src_clk) / div / (0 + 1);
 
                if (spi->max_speed_hz > speed)
                        spi->max_speed_hz = speed;
 
-               psr = clk_get_rate(sdd->src_clk) / 2 / spi->max_speed_hz - 1;
+               psr = clk_get_rate(sdd->src_clk) / div / spi->max_speed_hz - 1;
                psr &= S3C64XX_SPI_PSR_MASK;
                if (psr == S3C64XX_SPI_PSR_MASK)
                        psr--;
 
-               speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
+               speed = clk_get_rate(sdd->src_clk) / div / (psr + 1);
                if (spi->max_speed_hz < speed) {
                        if (psr+1 < S3C64XX_SPI_PSR_MASK) {
                                psr++;
@@ -868,7 +919,7 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
                        }
                }
 
-               speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
+               speed = clk_get_rate(sdd->src_clk) / div / (psr + 1);
                if (spi->max_speed_hz >= speed) {
                        spi->max_speed_hz = speed;
                } else {
@@ -1098,6 +1149,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
        master->setup = s3c64xx_spi_setup;
        master->cleanup = s3c64xx_spi_cleanup;
        master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer;
+       master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer;
        master->prepare_message = s3c64xx_spi_prepare_message;
        master->transfer_one = s3c64xx_spi_transfer_one;
        master->num_chipselect = sci->num_cs;
@@ -1107,6 +1159,8 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
                                        SPI_BPW_MASK(8);
        /* the spi->mode bits understood by this driver: */
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+       if (sdd->port_conf->has_loopback)
+               master->mode_bits |= SPI_LOOP;
        master->auto_runtime_pm = true;
        if (!is_polling(sdd))
                master->can_dma = s3c64xx_spi_can_dma;
@@ -1167,22 +1221,6 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
                }
        }
 
-       if (!is_polling(sdd)) {
-               /* Acquire DMA channels */
-               sdd->rx_dma.ch = dma_request_chan(&pdev->dev, "rx");
-               if (IS_ERR(sdd->rx_dma.ch)) {
-                       dev_err(&pdev->dev, "Failed to get RX DMA channel\n");
-                       ret = PTR_ERR(sdd->rx_dma.ch);
-                       goto err_disable_io_clk;
-               }
-               sdd->tx_dma.ch = dma_request_chan(&pdev->dev, "tx");
-               if (IS_ERR(sdd->tx_dma.ch)) {
-                       dev_err(&pdev->dev, "Failed to get TX DMA channel\n");
-                       ret = PTR_ERR(sdd->tx_dma.ch);
-                       goto err_release_rx_dma;
-               }
-       }
-
        pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_TIMEOUT);
        pm_runtime_use_autosuspend(&pdev->dev);
        pm_runtime_set_active(&pdev->dev);
@@ -1228,12 +1266,6 @@ err_pm_put:
        pm_runtime_disable(&pdev->dev);
        pm_runtime_set_suspended(&pdev->dev);
 
-       if (!is_polling(sdd))
-               dma_release_channel(sdd->tx_dma.ch);
-err_release_rx_dma:
-       if (!is_polling(sdd))
-               dma_release_channel(sdd->rx_dma.ch);
-err_disable_io_clk:
        clk_disable_unprepare(sdd->ioclk);
 err_disable_src_clk:
        clk_disable_unprepare(sdd->src_clk);
@@ -1369,6 +1401,7 @@ static const struct s3c64xx_spi_port_config s3c2443_spi_port_config = {
        .fifo_lvl_mask  = { 0x7f },
        .rx_lvl_offset  = 13,
        .tx_st_done     = 21,
+       .clk_div        = 2,
        .high_speed     = true,
 };
 
@@ -1376,12 +1409,14 @@ static const struct s3c64xx_spi_port_config s3c6410_spi_port_config = {
        .fifo_lvl_mask  = { 0x7f, 0x7F },
        .rx_lvl_offset  = 13,
        .tx_st_done     = 21,
+       .clk_div        = 2,
 };
 
 static const struct s3c64xx_spi_port_config s5pv210_spi_port_config = {
        .fifo_lvl_mask  = { 0x1ff, 0x7F },
        .rx_lvl_offset  = 15,
        .tx_st_done     = 25,
+       .clk_div        = 2,
        .high_speed     = true,
 };
 
@@ -1389,6 +1424,7 @@ static const struct s3c64xx_spi_port_config exynos4_spi_port_config = {
        .fifo_lvl_mask  = { 0x1ff, 0x7F, 0x7F },
        .rx_lvl_offset  = 15,
        .tx_st_done     = 25,
+       .clk_div        = 2,
        .high_speed     = true,
        .clk_from_cmu   = true,
        .quirks         = S3C64XX_SPI_QUIRK_CS_AUTO,
@@ -1398,6 +1434,7 @@ static const struct s3c64xx_spi_port_config exynos7_spi_port_config = {
        .fifo_lvl_mask  = { 0x1ff, 0x7F, 0x7F, 0x7F, 0x7F, 0x1ff},
        .rx_lvl_offset  = 15,
        .tx_st_done     = 25,
+       .clk_div        = 2,
        .high_speed     = true,
        .clk_from_cmu   = true,
        .quirks         = S3C64XX_SPI_QUIRK_CS_AUTO,
@@ -1407,16 +1444,31 @@ static const struct s3c64xx_spi_port_config exynos5433_spi_port_config = {
        .fifo_lvl_mask  = { 0x1ff, 0x7f, 0x7f, 0x7f, 0x7f, 0x1ff},
        .rx_lvl_offset  = 15,
        .tx_st_done     = 25,
+       .clk_div        = 2,
+       .high_speed     = true,
+       .clk_from_cmu   = true,
+       .clk_ioclk      = true,
+       .quirks         = S3C64XX_SPI_QUIRK_CS_AUTO,
+};
+
+static const struct s3c64xx_spi_port_config exynosautov9_spi_port_config = {
+       .fifo_lvl_mask  = { 0x1ff, 0x1ff, 0x7f, 0x7f, 0x7f, 0x7f, 0x1ff, 0x7f,
+                           0x7f, 0x7f, 0x7f, 0x7f},
+       .rx_lvl_offset  = 15,
+       .tx_st_done     = 25,
+       .clk_div        = 4,
        .high_speed     = true,
        .clk_from_cmu   = true,
        .clk_ioclk      = true,
+       .has_loopback   = true,
        .quirks         = S3C64XX_SPI_QUIRK_CS_AUTO,
 };
 
-static struct s3c64xx_spi_port_config fsd_spi_port_config = {
+static const struct s3c64xx_spi_port_config fsd_spi_port_config = {
        .fifo_lvl_mask  = { 0x7f, 0x7f, 0x7f, 0x7f, 0x7f},
        .rx_lvl_offset  = 15,
        .tx_st_done     = 25,
+       .clk_div        = 2,
        .high_speed     = true,
        .clk_from_cmu   = true,
        .clk_ioclk      = false,
@@ -1453,6 +1505,9 @@ static const struct of_device_id s3c64xx_spi_dt_match[] = {
        { .compatible = "samsung,exynos5433-spi",
                        .data = (void *)&exynos5433_spi_port_config,
        },
+       { .compatible = "samsung,exynosautov9-spi",
+                       .data = (void *)&exynosautov9_spi_port_config,
+       },
        { .compatible = "tesla,fsd-spi",
                        .data = (void *)&fsd_spi_port_config,
        },
index 45f3049..3e72fad 100644 (file)
@@ -73,11 +73,8 @@ struct spi_sh_data {
        void __iomem *addr;
        int irq;
        struct spi_master *master;
-       struct list_head queue;
-       struct work_struct ws;
        unsigned long cr1;
        wait_queue_head_t wait;
-       spinlock_t lock;
        int width;
 };
 
@@ -271,47 +268,39 @@ static int spi_sh_receive(struct spi_sh_data *ss, struct spi_message *mesg,
        return 0;
 }
 
-static void spi_sh_work(struct work_struct *work)
+static int spi_sh_transfer_one_message(struct spi_controller *ctlr,
+                                       struct spi_message *mesg)
 {
-       struct spi_sh_data *ss = container_of(work, struct spi_sh_data, ws);
-       struct spi_message *mesg;
+       struct spi_sh_data *ss = spi_controller_get_devdata(ctlr);
        struct spi_transfer *t;
-       unsigned long flags;
        int ret;
 
        pr_debug("%s: enter\n", __func__);
 
-       spin_lock_irqsave(&ss->lock, flags);
-       while (!list_empty(&ss->queue)) {
-               mesg = list_entry(ss->queue.next, struct spi_message, queue);
-               list_del_init(&mesg->queue);
-
-               spin_unlock_irqrestore(&ss->lock, flags);
-               list_for_each_entry(t, &mesg->transfers, transfer_list) {
-                       pr_debug("tx_buf = %p, rx_buf = %p\n",
-                                       t->tx_buf, t->rx_buf);
-                       pr_debug("len = %d, delay.value = %d\n",
-                                       t->len, t->delay.value);
-
-                       if (t->tx_buf) {
-                               ret = spi_sh_send(ss, mesg, t);
-                               if (ret < 0)
-                                       goto error;
-                       }
-                       if (t->rx_buf) {
-                               ret = spi_sh_receive(ss, mesg, t);
-                               if (ret < 0)
-                                       goto error;
-                       }
-                       mesg->actual_length += t->len;
-               }
-               spin_lock_irqsave(&ss->lock, flags);
+       spi_sh_clear_bit(ss, SPI_SH_SSA, SPI_SH_CR1);
 
-               mesg->status = 0;
-               if (mesg->complete)
-                       mesg->complete(mesg->context);
+       list_for_each_entry(t, &mesg->transfers, transfer_list) {
+               pr_debug("tx_buf = %p, rx_buf = %p\n",
+                        t->tx_buf, t->rx_buf);
+               pr_debug("len = %d, delay.value = %d\n",
+                        t->len, t->delay.value);
+
+               if (t->tx_buf) {
+                       ret = spi_sh_send(ss, mesg, t);
+                       if (ret < 0)
+                               goto error;
+               }
+               if (t->rx_buf) {
+                       ret = spi_sh_receive(ss, mesg, t);
+                       if (ret < 0)
+                               goto error;
+               }
+               mesg->actual_length += t->len;
        }
 
+       mesg->status = 0;
+       spi_finalize_current_message(ctlr);
+
        clear_fifo(ss);
        spi_sh_set_bit(ss, SPI_SH_SSD, SPI_SH_CR1);
        udelay(100);
@@ -321,12 +310,11 @@ static void spi_sh_work(struct work_struct *work)
 
        clear_fifo(ss);
 
-       spin_unlock_irqrestore(&ss->lock, flags);
-
-       return;
+       return 0;
 
  error:
        mesg->status = ret;
+       spi_finalize_current_message(ctlr);
        if (mesg->complete)
                mesg->complete(mesg->context);
 
@@ -334,6 +322,7 @@ static void spi_sh_work(struct work_struct *work)
                         SPI_SH_CR1);
        clear_fifo(ss);
 
+       return ret;
 }
 
 static int spi_sh_setup(struct spi_device *spi)
@@ -355,29 +344,6 @@ static int spi_sh_setup(struct spi_device *spi)
        return 0;
 }
 
-static int spi_sh_transfer(struct spi_device *spi, struct spi_message *mesg)
-{
-       struct spi_sh_data *ss = spi_master_get_devdata(spi->master);
-       unsigned long flags;
-
-       pr_debug("%s: enter\n", __func__);
-       pr_debug("\tmode = %02x\n", spi->mode);
-
-       spin_lock_irqsave(&ss->lock, flags);
-
-       mesg->actual_length = 0;
-       mesg->status = -EINPROGRESS;
-
-       spi_sh_clear_bit(ss, SPI_SH_SSA, SPI_SH_CR1);
-
-       list_add_tail(&mesg->queue, &ss->queue);
-       schedule_work(&ss->ws);
-
-       spin_unlock_irqrestore(&ss->lock, flags);
-
-       return 0;
-}
-
 static void spi_sh_cleanup(struct spi_device *spi)
 {
        struct spi_sh_data *ss = spi_master_get_devdata(spi->master);
@@ -416,7 +382,6 @@ static int spi_sh_remove(struct platform_device *pdev)
        struct spi_sh_data *ss = platform_get_drvdata(pdev);
 
        spi_unregister_master(ss->master);
-       flush_work(&ss->ws);
        free_irq(ss->irq, ss);
 
        return 0;
@@ -467,9 +432,6 @@ static int spi_sh_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "ioremap error.\n");
                return -ENOMEM;
        }
-       INIT_LIST_HEAD(&ss->queue);
-       spin_lock_init(&ss->lock);
-       INIT_WORK(&ss->ws, spi_sh_work);
        init_waitqueue_head(&ss->wait);
 
        ret = request_irq(irq, spi_sh_irq, 0, "spi_sh", ss);
@@ -481,7 +443,7 @@ static int spi_sh_probe(struct platform_device *pdev)
        master->num_chipselect = 2;
        master->bus_num = pdev->id;
        master->setup = spi_sh_setup;
-       master->transfer = spi_sh_transfer;
+       master->transfer_one_message = spi_sh_transfer_one_message;
        master->cleanup = spi_sh_cleanup;
 
        ret = spi_register_master(master);
index f7c1e20..e29e85c 100644 (file)
@@ -427,6 +427,44 @@ static int sifive_spi_remove(struct platform_device *pdev)
        return 0;
 }
 
+static int sifive_spi_suspend(struct device *dev)
+{
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct sifive_spi *spi = spi_master_get_devdata(master);
+       int ret;
+
+       ret = spi_master_suspend(master);
+       if (ret)
+               return ret;
+
+       /* Disable all the interrupts just in case */
+       sifive_spi_write(spi, SIFIVE_SPI_REG_IE, 0);
+
+       clk_disable_unprepare(spi->clk);
+
+       return ret;
+}
+
+static int sifive_spi_resume(struct device *dev)
+{
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct sifive_spi *spi = spi_master_get_devdata(master);
+       int ret;
+
+       ret = clk_prepare_enable(spi->clk);
+       if (ret)
+               return ret;
+       ret = spi_master_resume(master);
+       if (ret)
+               clk_disable_unprepare(spi->clk);
+
+       return ret;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(sifive_spi_pm_ops,
+                               sifive_spi_suspend, sifive_spi_resume);
+
+
 static const struct of_device_id sifive_spi_of_match[] = {
        { .compatible = "sifive,spi0", },
        {}
@@ -438,6 +476,7 @@ static struct platform_driver sifive_spi_driver = {
        .remove = sifive_spi_remove,
        .driver = {
                .name = SIFIVE_SPI_DRIVER_NAME,
+               .pm = &sifive_spi_pm_ops,
                .of_match_table = sifive_spi_of_match,
        },
 };
index c0239e4..f3fe923 100644 (file)
@@ -299,8 +299,7 @@ static int stm32_qspi_wait_nobusy(struct stm32_qspi *qspi)
                                                 STM32_BUSY_TIMEOUT_US);
 }
 
-static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi,
-                              const struct spi_mem_op *op)
+static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi)
 {
        u32 cr, sr;
        int err = 0;
@@ -331,8 +330,7 @@ out:
        return err;
 }
 
-static int stm32_qspi_wait_poll_status(struct stm32_qspi *qspi,
-                                      const struct spi_mem_op *op)
+static int stm32_qspi_wait_poll_status(struct stm32_qspi *qspi)
 {
        u32 cr;
 
@@ -349,7 +347,7 @@ static int stm32_qspi_wait_poll_status(struct stm32_qspi *qspi,
        return 0;
 }
 
-static int stm32_qspi_get_mode(struct stm32_qspi *qspi, u8 buswidth)
+static int stm32_qspi_get_mode(u8 buswidth)
 {
        if (buswidth == 4)
                return CCR_BUSWIDTH_4;
@@ -382,11 +380,11 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op)
        ccr = qspi->fmode;
        ccr |= FIELD_PREP(CCR_INST_MASK, op->cmd.opcode);
        ccr |= FIELD_PREP(CCR_IMODE_MASK,
-                         stm32_qspi_get_mode(qspi, op->cmd.buswidth));
+                         stm32_qspi_get_mode(op->cmd.buswidth));
 
        if (op->addr.nbytes) {
                ccr |= FIELD_PREP(CCR_ADMODE_MASK,
-                                 stm32_qspi_get_mode(qspi, op->addr.buswidth));
+                                 stm32_qspi_get_mode(op->addr.buswidth));
                ccr |= FIELD_PREP(CCR_ADSIZE_MASK, op->addr.nbytes - 1);
        }
 
@@ -396,7 +394,7 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op)
 
        if (op->data.nbytes) {
                ccr |= FIELD_PREP(CCR_DMODE_MASK,
-                                 stm32_qspi_get_mode(qspi, op->data.buswidth));
+                                 stm32_qspi_get_mode(op->data.buswidth));
        }
 
        writel_relaxed(ccr, qspi->io_base + QSPI_CCR);
@@ -405,7 +403,7 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op)
                writel_relaxed(op->addr.val, qspi->io_base + QSPI_AR);
 
        if (qspi->fmode == CCR_FMODE_APM)
-               err_poll_status = stm32_qspi_wait_poll_status(qspi, op);
+               err_poll_status = stm32_qspi_wait_poll_status(qspi);
 
        err = stm32_qspi_tx(qspi, op);
 
@@ -420,7 +418,7 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op)
                goto abort;
 
        /* wait end of tx in indirect mode */
-       err = stm32_qspi_wait_cmd(qspi, op);
+       err = stm32_qspi_wait_cmd(qspi);
        if (err)
                goto abort;
 
index ea706d9..47cbe73 100644 (file)
@@ -783,6 +783,7 @@ static int __maybe_unused synquacer_spi_resume(struct device *dev)
 
                ret = synquacer_spi_enable(master);
                if (ret) {
+                       clk_disable_unprepare(sspi->clk);
                        dev_err(dev, "failed to enable spi (%d)\n", ret);
                        return ret;
                }
index 3836043..148043d 100644 (file)
@@ -1136,7 +1136,7 @@ exit_free_master:
 
 static int tegra_slink_remove(struct platform_device *pdev)
 {
-       struct spi_master *master = platform_get_drvdata(pdev);
+       struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
        struct tegra_slink_data *tspi = spi_master_get_devdata(master);
 
        spi_unregister_master(master);
@@ -1151,6 +1151,7 @@ static int tegra_slink_remove(struct platform_device *pdev)
        if (tspi->rx_dma_chan)
                tegra_slink_deinit_dma_param(tspi, true);
 
+       spi_master_put(master);
        return 0;
 }
 
index 66f647f..c89592b 100644 (file)
 #define QSPI_RX_EN                             BIT(12)
 #define QSPI_CS_SW_VAL                         BIT(20)
 #define QSPI_CS_SW_HW                          BIT(21)
+
+#define QSPI_CS_POL_INACTIVE(n)                        (1 << (22 + (n)))
+#define QSPI_CS_POL_INACTIVE_MASK              (0xF << 22)
+#define QSPI_CS_SEL_0                          (0 << 26)
+#define QSPI_CS_SEL_1                          (1 << 26)
+#define QSPI_CS_SEL_2                          (2 << 26)
+#define QSPI_CS_SEL_3                          (3 << 26)
+#define QSPI_CS_SEL_MASK                       (3 << 26)
+#define QSPI_CS_SEL(x)                         (((x) & 0x3) << 26)
+
 #define QSPI_CONTROL_MODE_0                    (0 << 28)
 #define QSPI_CONTROL_MODE_3                    (3 << 28)
 #define QSPI_CONTROL_MODE_MASK                 (3 << 28)
 struct tegra_qspi_soc_data {
        bool has_dma;
        bool cmb_xfer_capable;
+       unsigned int cs_count;
 };
 
 struct tegra_qspi_client_data {
@@ -812,6 +823,7 @@ static u32 tegra_qspi_setup_transfer_one(struct spi_device *spi, struct spi_tran
                tegra_qspi_mask_clear_irq(tqspi);
 
                command1 = tqspi->def_command1_reg;
+               command1 |= QSPI_CS_SEL(spi->chip_select);
                command1 |= QSPI_BIT_LENGTH(bits_per_word - 1);
 
                command1 &= ~QSPI_CONTROL_MODE_MASK;
@@ -941,10 +953,11 @@ static int tegra_qspi_setup(struct spi_device *spi)
 
        /* keep default cs state to inactive */
        val = tqspi->def_command1_reg;
+       val |= QSPI_CS_SEL(spi->chip_select);
        if (spi->mode & SPI_CS_HIGH)
-               val &= ~QSPI_CS_SW_VAL;
+               val &= ~QSPI_CS_POL_INACTIVE(spi->chip_select);
        else
-               val |= QSPI_CS_SW_VAL;
+               val |= QSPI_CS_POL_INACTIVE(spi->chip_select);
 
        tqspi->def_command1_reg = val;
        tegra_qspi_writel(tqspi, tqspi->def_command1_reg, QSPI_COMMAND1);
@@ -1425,16 +1438,25 @@ static irqreturn_t tegra_qspi_isr_thread(int irq, void *context_data)
 static struct tegra_qspi_soc_data tegra210_qspi_soc_data = {
        .has_dma = true,
        .cmb_xfer_capable = false,
+       .cs_count = 1,
 };
 
 static struct tegra_qspi_soc_data tegra186_qspi_soc_data = {
        .has_dma = true,
        .cmb_xfer_capable = true,
+       .cs_count = 1,
 };
 
 static struct tegra_qspi_soc_data tegra234_qspi_soc_data = {
        .has_dma = false,
        .cmb_xfer_capable = true,
+       .cs_count = 1,
+};
+
+static struct tegra_qspi_soc_data tegra241_qspi_soc_data = {
+       .has_dma = false,
+       .cmb_xfer_capable = true,
+       .cs_count = 4,
 };
 
 static const struct of_device_id tegra_qspi_of_match[] = {
@@ -1450,6 +1472,9 @@ static const struct of_device_id tegra_qspi_of_match[] = {
        }, {
                .compatible = "nvidia,tegra234-qspi",
                .data       = &tegra234_qspi_soc_data,
+       }, {
+               .compatible = "nvidia,tegra241-qspi",
+               .data       = &tegra241_qspi_soc_data,
        },
        {}
 };
@@ -1467,6 +1492,9 @@ static const struct acpi_device_id tegra_qspi_acpi_match[] = {
        }, {
                .id = "NVDA1413",
                .driver_data = (kernel_ulong_t)&tegra234_qspi_soc_data,
+       }, {
+               .id = "NVDA1513",
+               .driver_data = (kernel_ulong_t)&tegra241_qspi_soc_data,
        },
        {}
 };
@@ -1506,6 +1534,7 @@ static int tegra_qspi_probe(struct platform_device *pdev)
        spin_lock_init(&tqspi->lock);
 
        tqspi->soc_data = device_get_match_data(&pdev->dev);
+       master->num_chipselect = tqspi->soc_data->cs_count;
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        tqspi->base = devm_ioremap_resource(&pdev->dev, r);
        if (IS_ERR(tqspi->base))
index b5b65d8..6008686 100644 (file)
@@ -57,7 +57,6 @@ struct ti_qspi {
        void                    *rx_bb_addr;
        struct dma_chan         *rx_chan;
 
-       u32 spi_max_frequency;
        u32 cmd;
        u32 dc;
 
@@ -140,37 +139,19 @@ static inline void ti_qspi_write(struct ti_qspi *qspi,
 static int ti_qspi_setup(struct spi_device *spi)
 {
        struct ti_qspi  *qspi = spi_master_get_devdata(spi->master);
-       struct ti_qspi_regs *ctx_reg = &qspi->ctx_reg;
-       int clk_div = 0, ret;
-       u32 clk_ctrl_reg, clk_rate, clk_mask;
+       int ret;
 
        if (spi->master->busy) {
                dev_dbg(qspi->dev, "master busy doing other transfers\n");
                return -EBUSY;
        }
 
-       if (!qspi->spi_max_frequency) {
+       if (!qspi->master->max_speed_hz) {
                dev_err(qspi->dev, "spi max frequency not defined\n");
                return -EINVAL;
        }
 
-       clk_rate = clk_get_rate(qspi->fclk);
-
-       clk_div = DIV_ROUND_UP(clk_rate, qspi->spi_max_frequency) - 1;
-
-       if (clk_div < 0) {
-               dev_dbg(qspi->dev, "clock divider < 0, using /1 divider\n");
-               return -EINVAL;
-       }
-
-       if (clk_div > QSPI_CLK_DIV_MAX) {
-               dev_dbg(qspi->dev, "clock divider >%d , using /%d divider\n",
-                               QSPI_CLK_DIV_MAX, QSPI_CLK_DIV_MAX + 1);
-               return -EINVAL;
-       }
-
-       dev_dbg(qspi->dev, "hz: %d, clock divider %d\n",
-                       qspi->spi_max_frequency, clk_div);
+       spi->max_speed_hz = min(spi->max_speed_hz, qspi->master->max_speed_hz);
 
        ret = pm_runtime_resume_and_get(qspi->dev);
        if (ret < 0) {
@@ -178,18 +159,6 @@ static int ti_qspi_setup(struct spi_device *spi)
                return ret;
        }
 
-       clk_ctrl_reg = ti_qspi_read(qspi, QSPI_SPI_CLOCK_CNTRL_REG);
-
-       clk_ctrl_reg &= ~QSPI_CLK_EN;
-
-       /* disable SCLK */
-       ti_qspi_write(qspi, clk_ctrl_reg, QSPI_SPI_CLOCK_CNTRL_REG);
-
-       /* enable SCLK */
-       clk_mask = QSPI_CLK_EN | clk_div;
-       ti_qspi_write(qspi, clk_mask, QSPI_SPI_CLOCK_CNTRL_REG);
-       ctx_reg->clkctrl = clk_mask;
-
        pm_runtime_mark_last_busy(qspi->dev);
        ret = pm_runtime_put_autosuspend(qspi->dev);
        if (ret < 0) {
@@ -200,6 +169,37 @@ static int ti_qspi_setup(struct spi_device *spi)
        return 0;
 }
 
+static void ti_qspi_setup_clk(struct ti_qspi *qspi, u32 speed_hz)
+{
+       struct ti_qspi_regs *ctx_reg = &qspi->ctx_reg;
+       int clk_div;
+       u32 clk_ctrl_reg, clk_rate, clk_ctrl_new;
+
+       clk_rate = clk_get_rate(qspi->fclk);
+       clk_div = DIV_ROUND_UP(clk_rate, speed_hz) - 1;
+       clk_div = clamp(clk_div, 0, QSPI_CLK_DIV_MAX);
+       dev_dbg(qspi->dev, "hz: %d, clock divider %d\n", speed_hz, clk_div);
+
+       pm_runtime_resume_and_get(qspi->dev);
+
+       clk_ctrl_new = QSPI_CLK_EN | clk_div;
+       if (ctx_reg->clkctrl != clk_ctrl_new) {
+               clk_ctrl_reg = ti_qspi_read(qspi, QSPI_SPI_CLOCK_CNTRL_REG);
+
+               clk_ctrl_reg &= ~QSPI_CLK_EN;
+
+               /* disable SCLK */
+               ti_qspi_write(qspi, clk_ctrl_reg, QSPI_SPI_CLOCK_CNTRL_REG);
+
+               /* enable SCLK */
+               ti_qspi_write(qspi, clk_ctrl_new, QSPI_SPI_CLOCK_CNTRL_REG);
+               ctx_reg->clkctrl = clk_ctrl_new;
+       }
+
+       pm_runtime_mark_last_busy(qspi->dev);
+       pm_runtime_put_autosuspend(qspi->dev);
+}
+
 static void ti_qspi_restore_ctx(struct ti_qspi *qspi)
 {
        struct ti_qspi_regs *ctx_reg = &qspi->ctx_reg;
@@ -623,8 +623,10 @@ static int ti_qspi_exec_mem_op(struct spi_mem *mem,
 
        mutex_lock(&qspi->list_lock);
 
-       if (!qspi->mmap_enabled || qspi->current_cs != mem->spi->chip_select)
+       if (!qspi->mmap_enabled || qspi->current_cs != mem->spi->chip_select) {
+               ti_qspi_setup_clk(qspi, mem->spi->max_speed_hz);
                ti_qspi_enable_memory_map(mem->spi);
+       }
        ti_qspi_setup_mmap_read(mem->spi, op->cmd.opcode, op->data.buswidth,
                                op->addr.nbytes, op->dummy.nbytes);
 
@@ -701,6 +703,7 @@ static int ti_qspi_start_transfer_one(struct spi_master *master,
                wlen = t->bits_per_word >> 3;
                transfer_len_words = min(t->len / wlen, frame_len_words);
 
+               ti_qspi_setup_clk(qspi, t->speed_hz);
                ret = qspi_transfer_msg(qspi, t, transfer_len_words * wlen);
                if (ret) {
                        dev_dbg(qspi->dev, "transfer message failed\n");
@@ -851,7 +854,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
        pm_runtime_enable(&pdev->dev);
 
        if (!of_property_read_u32(np, "spi-max-frequency", &max_freq))
-               qspi->spi_max_frequency = max_freq;
+               master->max_speed_hz = max_freq;
 
        dma_cap_zero(mask);
        dma_cap_set(DMA_MEMCPY, mask);
index dfaa1d7..cbb6019 100644 (file)
@@ -455,35 +455,10 @@ static void pch_spi_reset(struct spi_master *master)
 
 static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
 {
-
-       struct spi_transfer *transfer;
        struct pch_spi_data *data = spi_master_get_devdata(pspi->master);
        int retval;
        unsigned long flags;
 
-       spin_lock_irqsave(&data->lock, flags);
-       /* validate Tx/Rx buffers and Transfer length */
-       list_for_each_entry(transfer, &pmsg->transfers, transfer_list) {
-               if (!transfer->tx_buf && !transfer->rx_buf) {
-                       dev_err(&pspi->dev,
-                               "%s Tx and Rx buffer NULL\n", __func__);
-                       retval = -EINVAL;
-                       goto err_return_spinlock;
-               }
-
-               if (!transfer->len) {
-                       dev_err(&pspi->dev, "%s Transfer length invalid\n",
-                               __func__);
-                       retval = -EINVAL;
-                       goto err_return_spinlock;
-               }
-
-               dev_dbg(&pspi->dev,
-                       "%s Tx/Rx buffer valid. Transfer length valid\n",
-                       __func__);
-       }
-       spin_unlock_irqrestore(&data->lock, flags);
-
        /* We won't process any messages if we have been asked to terminate */
        if (data->status == STATUS_EXITING) {
                dev_err(&pspi->dev, "%s status = STATUS_EXITING.\n", __func__);
@@ -518,10 +493,6 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
 err_out:
        dev_dbg(&pspi->dev, "%s RETURN=%d\n", __func__, retval);
        return retval;
-err_return_spinlock:
-       dev_dbg(&pspi->dev, "%s RETURN=%d\n", __func__, retval);
-       spin_unlock_irqrestore(&data->lock, flags);
-       return retval;
 }
 
 static inline void pch_spi_select_chip(struct pch_spi_data *data,
@@ -1365,6 +1336,7 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev)
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
        master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
        master->max_speed_hz = PCH_MAX_BAUDRATE;
+       master->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX;
 
        data->board_dat = board_dat;
        data->plat_dev = plat_dev;
index 2b5afae..c760aac 100644 (file)
 #define GQSPI_DMA_UNALIGN              0x3
 #define GQSPI_DEFAULT_NUM_CS   1       /* Default number of chip selects */
 
+#define GQSPI_MAX_NUM_CS       2       /* Maximum number of chip selects */
+
 #define SPI_AUTOSUSPEND_TIMEOUT                3000
 enum mode_type {GQSPI_MODE_IO, GQSPI_MODE_DMA};
 
@@ -363,8 +365,13 @@ static void zynqmp_qspi_chipselect(struct spi_device *qspi, bool is_high)
        genfifoentry |= GQSPI_GENFIFO_MODE_SPI;
 
        if (!is_high) {
-               xqspi->genfifobus = GQSPI_GENFIFO_BUS_LOWER;
-               xqspi->genfifocs = GQSPI_GENFIFO_CS_LOWER;
+               if (!qspi->chip_select) {
+                       xqspi->genfifobus = GQSPI_GENFIFO_BUS_LOWER;
+                       xqspi->genfifocs = GQSPI_GENFIFO_CS_LOWER;
+               } else {
+                       xqspi->genfifobus = GQSPI_GENFIFO_BUS_UPPER;
+                       xqspi->genfifocs = GQSPI_GENFIFO_CS_UPPER;
+               }
                genfifoentry |= xqspi->genfifobus;
                genfifoentry |= xqspi->genfifocs;
                genfifoentry |= GQSPI_GENFIFO_CS_SETUP;
@@ -1099,6 +1106,7 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
        struct zynqmp_qspi *xqspi;
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
+       u32 num_cs;
 
        ctlr = spi_alloc_master(&pdev->dev, sizeof(*xqspi));
        if (!ctlr)
@@ -1176,8 +1184,19 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
        if (ret)
                goto clk_dis_all;
 
+       ret = of_property_read_u32(np, "num-cs", &num_cs);
+       if (ret < 0) {
+               ctlr->num_chipselect = GQSPI_DEFAULT_NUM_CS;
+       } else if (num_cs > GQSPI_MAX_NUM_CS) {
+               ret = -EINVAL;
+               dev_err(&pdev->dev, "only %d chip selects are available\n",
+                       GQSPI_MAX_NUM_CS);
+               goto clk_dis_all;
+       } else {
+               ctlr->num_chipselect = num_cs;
+       }
+
        ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
-       ctlr->num_chipselect = GQSPI_DEFAULT_NUM_CS;
        ctlr->mem_ops = &zynqmp_qspi_mem_ops;
        ctlr->setup = zynqmp_qspi_setup_op;
        ctlr->max_speed_hz = clk_get_rate(xqspi->refclk) / 2;
index ea09d1b..1c14d68 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/idr.h>
 #include <linux/platform_data/x86/apple.h>
 #include <linux/ptp_clock_kernel.h>
+#include <linux/percpu.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/spi.h>
@@ -49,6 +50,7 @@ static void spidev_release(struct device *dev)
 
        spi_controller_put(spi->controller);
        kfree(spi->driver_override);
+       free_percpu(spi->pcpu_statistics);
        kfree(spi);
 }
 
@@ -93,6 +95,47 @@ static ssize_t driver_override_show(struct device *dev,
 }
 static DEVICE_ATTR_RW(driver_override);
 
+static struct spi_statistics *spi_alloc_pcpu_stats(struct device *dev)
+{
+       struct spi_statistics __percpu *pcpu_stats;
+
+       if (dev)
+               pcpu_stats = devm_alloc_percpu(dev, struct spi_statistics);
+       else
+               pcpu_stats = alloc_percpu_gfp(struct spi_statistics, GFP_KERNEL);
+
+       if (pcpu_stats) {
+               int cpu;
+
+               for_each_possible_cpu(cpu) {
+                       struct spi_statistics *stat;
+
+                       stat = per_cpu_ptr(pcpu_stats, cpu);
+                       u64_stats_init(&stat->syncp);
+               }
+       }
+       return pcpu_stats;
+}
+
+#define spi_pcpu_stats_totalize(ret, in, field)                                \
+do {                                                                   \
+       int i;                                                          \
+       ret = 0;                                                        \
+       for_each_possible_cpu(i) {                                      \
+               const struct spi_statistics *pcpu_stats;                \
+               u64 inc;                                                \
+               unsigned int start;                                     \
+               pcpu_stats = per_cpu_ptr(in, i);                        \
+               do {                                                    \
+                       start = u64_stats_fetch_begin_irq(              \
+                                       &pcpu_stats->syncp);            \
+                       inc = u64_stats_read(&pcpu_stats->field);       \
+               } while (u64_stats_fetch_retry_irq(                     \
+                                       &pcpu_stats->syncp, start));    \
+               ret += inc;                                             \
+       }                                                               \
+} while (0)
+
 #define SPI_STATISTICS_ATTRS(field, file)                              \
 static ssize_t spi_controller_##field##_show(struct device *dev,       \
                                             struct device_attribute *attr, \
@@ -100,7 +143,7 @@ static ssize_t spi_controller_##field##_show(struct device *dev,    \
 {                                                                      \
        struct spi_controller *ctlr = container_of(dev,                 \
                                         struct spi_controller, dev);   \
-       return spi_statistics_##field##_show(&ctlr->statistics, buf);   \
+       return spi_statistics_##field##_show(ctlr->pcpu_statistics, buf); \
 }                                                                      \
 static struct device_attribute dev_attr_spi_controller_##field = {     \
        .attr = { .name = file, .mode = 0444 },                         \
@@ -111,47 +154,46 @@ static ssize_t spi_device_##field##_show(struct device *dev,              \
                                        char *buf)                      \
 {                                                                      \
        struct spi_device *spi = to_spi_device(dev);                    \
-       return spi_statistics_##field##_show(&spi->statistics, buf);    \
+       return spi_statistics_##field##_show(spi->pcpu_statistics, buf); \
 }                                                                      \
 static struct device_attribute dev_attr_spi_device_##field = {         \
        .attr = { .name = file, .mode = 0444 },                         \
        .show = spi_device_##field##_show,                              \
 }
 
-#define SPI_STATISTICS_SHOW_NAME(name, file, field, format_string)     \
+#define SPI_STATISTICS_SHOW_NAME(name, file, field)                    \
 static ssize_t spi_statistics_##name##_show(struct spi_statistics *stat, \
                                            char *buf)                  \
 {                                                                      \
-       unsigned long flags;                                            \
        ssize_t len;                                                    \
-       spin_lock_irqsave(&stat->lock, flags);                          \
-       len = sysfs_emit(buf, format_string "\n", stat->field);         \
-       spin_unlock_irqrestore(&stat->lock, flags);                     \
+       u64 val;                                                        \
+       spi_pcpu_stats_totalize(val, stat, field);                      \
+       len = sysfs_emit(buf, "%llu\n", val);                           \
        return len;                                                     \
 }                                                                      \
 SPI_STATISTICS_ATTRS(name, file)
 
-#define SPI_STATISTICS_SHOW(field, format_string)                      \
+#define SPI_STATISTICS_SHOW(field)                                     \
        SPI_STATISTICS_SHOW_NAME(field, __stringify(field),             \
-                                field, format_string)
+                                field)
 
-SPI_STATISTICS_SHOW(messages, "%lu");
-SPI_STATISTICS_SHOW(transfers, "%lu");
-SPI_STATISTICS_SHOW(errors, "%lu");
-SPI_STATISTICS_SHOW(timedout, "%lu");
+SPI_STATISTICS_SHOW(messages);
+SPI_STATISTICS_SHOW(transfers);
+SPI_STATISTICS_SHOW(errors);
+SPI_STATISTICS_SHOW(timedout);
 
-SPI_STATISTICS_SHOW(spi_sync, "%lu");
-SPI_STATISTICS_SHOW(spi_sync_immediate, "%lu");
-SPI_STATISTICS_SHOW(spi_async, "%lu");
+SPI_STATISTICS_SHOW(spi_sync);
+SPI_STATISTICS_SHOW(spi_sync_immediate);
+SPI_STATISTICS_SHOW(spi_async);
 
-SPI_STATISTICS_SHOW(bytes, "%llu");
-SPI_STATISTICS_SHOW(bytes_rx, "%llu");
-SPI_STATISTICS_SHOW(bytes_tx, "%llu");
+SPI_STATISTICS_SHOW(bytes);
+SPI_STATISTICS_SHOW(bytes_rx);
+SPI_STATISTICS_SHOW(bytes_tx);
 
 #define SPI_STATISTICS_TRANSFER_BYTES_HISTO(index, number)             \
        SPI_STATISTICS_SHOW_NAME(transfer_bytes_histo##index,           \
                                 "transfer_bytes_histo_" number,        \
-                                transfer_bytes_histo[index],  "%lu")
+                                transfer_bytes_histo[index])
 SPI_STATISTICS_TRANSFER_BYTES_HISTO(0,  "0-1");
 SPI_STATISTICS_TRANSFER_BYTES_HISTO(1,  "2-3");
 SPI_STATISTICS_TRANSFER_BYTES_HISTO(2,  "4-7");
@@ -170,7 +212,7 @@ SPI_STATISTICS_TRANSFER_BYTES_HISTO(14, "16384-32767");
 SPI_STATISTICS_TRANSFER_BYTES_HISTO(15, "32768-65535");
 SPI_STATISTICS_TRANSFER_BYTES_HISTO(16, "65536+");
 
-SPI_STATISTICS_SHOW(transfers_split_maxsize, "%lu");
+SPI_STATISTICS_SHOW(transfers_split_maxsize);
 
 static struct attribute *spi_dev_attrs[] = {
        &dev_attr_modalias.attr,
@@ -267,30 +309,33 @@ static const struct attribute_group *spi_master_groups[] = {
        NULL,
 };
 
-static void spi_statistics_add_transfer_stats(struct spi_statistics *stats,
+static void spi_statistics_add_transfer_stats(struct spi_statistics *pcpu_stats,
                                              struct spi_transfer *xfer,
                                              struct spi_controller *ctlr)
 {
-       unsigned long flags;
        int l2len = min(fls(xfer->len), SPI_STATISTICS_HISTO_SIZE) - 1;
+       struct spi_statistics *stats;
 
        if (l2len < 0)
                l2len = 0;
 
-       spin_lock_irqsave(&stats->lock, flags);
+       get_cpu();
+       stats = this_cpu_ptr(pcpu_stats);
+       u64_stats_update_begin(&stats->syncp);
 
-       stats->transfers++;
-       stats->transfer_bytes_histo[l2len]++;
+       u64_stats_inc(&stats->transfers);
+       u64_stats_inc(&stats->transfer_bytes_histo[l2len]);
 
-       stats->bytes += xfer->len;
+       u64_stats_add(&stats->bytes, xfer->len);
        if ((xfer->tx_buf) &&
            (xfer->tx_buf != ctlr->dummy_tx))
-               stats->bytes_tx += xfer->len;
+               u64_stats_add(&stats->bytes_tx, xfer->len);
        if ((xfer->rx_buf) &&
            (xfer->rx_buf != ctlr->dummy_rx))
-               stats->bytes_rx += xfer->len;
+               u64_stats_add(&stats->bytes_rx, xfer->len);
 
-       spin_unlock_irqrestore(&stats->lock, flags);
+       u64_stats_update_end(&stats->syncp);
+       put_cpu();
 }
 
 /*
@@ -519,14 +564,19 @@ struct spi_device *spi_alloc_device(struct spi_controller *ctlr)
                return NULL;
        }
 
+       spi->pcpu_statistics = spi_alloc_pcpu_stats(NULL);
+       if (!spi->pcpu_statistics) {
+               kfree(spi);
+               spi_controller_put(ctlr);
+               return NULL;
+       }
+
        spi->master = spi->controller = ctlr;
        spi->dev.parent = &ctlr->dev;
        spi->dev.bus = &spi_bus_type;
        spi->dev.release = spidev_release;
        spi->mode = ctlr->buswidth_override_bits;
 
-       spin_lock_init(&spi->statistics.lock);
-
        device_initialize(&spi->dev);
        return spi;
 }
@@ -1225,8 +1275,8 @@ static int spi_transfer_wait(struct spi_controller *ctlr,
                             struct spi_message *msg,
                             struct spi_transfer *xfer)
 {
-       struct spi_statistics *statm = &ctlr->statistics;
-       struct spi_statistics *stats = &msg->spi->statistics;
+       struct spi_statistics *statm = ctlr->pcpu_statistics;
+       struct spi_statistics *stats = msg->spi->pcpu_statistics;
        u32 speed_hz = xfer->speed_hz;
        unsigned long long ms;
 
@@ -1304,7 +1354,7 @@ int spi_delay_to_ns(struct spi_delay *_delay, struct spi_transfer *xfer)
                /* Nothing to do here */
                break;
        case SPI_DELAY_UNIT_SCK:
-               /* clock cycles need to be obtained from spi_transfer */
+               /* Clock cycles need to be obtained from spi_transfer */
                if (!xfer)
                        return -EINVAL;
                /*
@@ -1353,7 +1403,7 @@ static void _spi_transfer_cs_change_delay(struct spi_message *msg,
        u32 unit = xfer->cs_change_delay.unit;
        int ret;
 
-       /* return early on "fast" mode - for everything but USECS */
+       /* Return early on "fast" mode - for everything but USECS */
        if (!delay) {
                if (unit == SPI_DELAY_UNIT_USECS)
                        _spi_transfer_delay_ns(default_delay_ns);
@@ -1382,8 +1432,8 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
        struct spi_transfer *xfer;
        bool keep_cs = false;
        int ret = 0;
-       struct spi_statistics *statm = &ctlr->statistics;
-       struct spi_statistics *stats = &msg->spi->statistics;
+       struct spi_statistics *statm = ctlr->pcpu_statistics;
+       struct spi_statistics *stats = msg->spi->pcpu_statistics;
 
        spi_set_cs(msg->spi, true, false);
 
@@ -1499,6 +1549,103 @@ static void spi_idle_runtime_pm(struct spi_controller *ctlr)
        }
 }
 
+static int __spi_pump_transfer_message(struct spi_controller *ctlr,
+               struct spi_message *msg, bool was_busy)
+{
+       struct spi_transfer *xfer;
+       int ret;
+
+       if (!was_busy && ctlr->auto_runtime_pm) {
+               ret = pm_runtime_get_sync(ctlr->dev.parent);
+               if (ret < 0) {
+                       pm_runtime_put_noidle(ctlr->dev.parent);
+                       dev_err(&ctlr->dev, "Failed to power device: %d\n",
+                               ret);
+                       return ret;
+               }
+       }
+
+       if (!was_busy)
+               trace_spi_controller_busy(ctlr);
+
+       if (!was_busy && ctlr->prepare_transfer_hardware) {
+               ret = ctlr->prepare_transfer_hardware(ctlr);
+               if (ret) {
+                       dev_err(&ctlr->dev,
+                               "failed to prepare transfer hardware: %d\n",
+                               ret);
+
+                       if (ctlr->auto_runtime_pm)
+                               pm_runtime_put(ctlr->dev.parent);
+
+                       msg->status = ret;
+                       spi_finalize_current_message(ctlr);
+
+                       return ret;
+               }
+       }
+
+       trace_spi_message_start(msg);
+
+       if (ctlr->prepare_message) {
+               ret = ctlr->prepare_message(ctlr, msg);
+               if (ret) {
+                       dev_err(&ctlr->dev, "failed to prepare message: %d\n",
+                               ret);
+                       msg->status = ret;
+                       spi_finalize_current_message(ctlr);
+                       return ret;
+               }
+               msg->prepared = true;
+       }
+
+       ret = spi_map_msg(ctlr, msg);
+       if (ret) {
+               msg->status = ret;
+               spi_finalize_current_message(ctlr);
+               return ret;
+       }
+
+       if (!ctlr->ptp_sts_supported && !ctlr->transfer_one) {
+               list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+                       xfer->ptp_sts_word_pre = 0;
+                       ptp_read_system_prets(xfer->ptp_sts);
+               }
+       }
+
+       /*
+        * Drivers implementation of transfer_one_message() must arrange for
+        * spi_finalize_current_message() to get called. Most drivers will do
+        * this in the calling context, but some don't. For those cases, a
+        * completion is used to guarantee that this function does not return
+        * until spi_finalize_current_message() is done accessing
+        * ctlr->cur_msg.
+        * Use of the following two flags enable to opportunistically skip the
+        * use of the completion since its use involves expensive spin locks.
+        * In case of a race with the context that calls
+        * spi_finalize_current_message() the completion will always be used,
+        * due to strict ordering of these flags using barriers.
+        */
+       WRITE_ONCE(ctlr->cur_msg_incomplete, true);
+       WRITE_ONCE(ctlr->cur_msg_need_completion, false);
+       reinit_completion(&ctlr->cur_msg_completion);
+       smp_wmb(); /* Make these available to spi_finalize_current_message() */
+
+       ret = ctlr->transfer_one_message(ctlr, msg);
+       if (ret) {
+               dev_err(&ctlr->dev,
+                       "failed to transfer one message from queue\n");
+               return ret;
+       }
+
+       WRITE_ONCE(ctlr->cur_msg_need_completion, true);
+       smp_mb(); /* See spi_finalize_current_message()... */
+       if (READ_ONCE(ctlr->cur_msg_incomplete))
+               wait_for_completion(&ctlr->cur_msg_completion);
+
+       return 0;
+}
+
 /**
  * __spi_pump_messages - function which processes spi message queue
  * @ctlr: controller to process queue for
@@ -1514,34 +1661,25 @@ static void spi_idle_runtime_pm(struct spi_controller *ctlr)
  */
 static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
 {
-       struct spi_transfer *xfer;
        struct spi_message *msg;
        bool was_busy = false;
        unsigned long flags;
        int ret;
 
+       /* Take the IO mutex */
+       mutex_lock(&ctlr->io_mutex);
+
        /* Lock queue */
        spin_lock_irqsave(&ctlr->queue_lock, flags);
 
        /* Make sure we are not already running a message */
-       if (ctlr->cur_msg) {
-               spin_unlock_irqrestore(&ctlr->queue_lock, flags);
-               return;
-       }
-
-       /* If another context is idling the device then defer */
-       if (ctlr->idling) {
-               kthread_queue_work(ctlr->kworker, &ctlr->pump_messages);
-               spin_unlock_irqrestore(&ctlr->queue_lock, flags);
-               return;
-       }
+       if (ctlr->cur_msg)
+               goto out_unlock;
 
        /* Check if the queue is idle */
        if (list_empty(&ctlr->queue) || !ctlr->running) {
-               if (!ctlr->busy) {
-                       spin_unlock_irqrestore(&ctlr->queue_lock, flags);
-                       return;
-               }
+               if (!ctlr->busy)
+                       goto out_unlock;
 
                /* Defer any non-atomic teardown to the thread */
                if (!in_kthread) {
@@ -1549,17 +1687,16 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
                            !ctlr->unprepare_transfer_hardware) {
                                spi_idle_runtime_pm(ctlr);
                                ctlr->busy = false;
+                               ctlr->queue_empty = true;
                                trace_spi_controller_idle(ctlr);
                        } else {
                                kthread_queue_work(ctlr->kworker,
                                                   &ctlr->pump_messages);
                        }
-                       spin_unlock_irqrestore(&ctlr->queue_lock, flags);
-                       return;
+                       goto out_unlock;
                }
 
                ctlr->busy = false;
-               ctlr->idling = true;
                spin_unlock_irqrestore(&ctlr->queue_lock, flags);
 
                kfree(ctlr->dummy_rx);
@@ -1574,9 +1711,8 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
                trace_spi_controller_idle(ctlr);
 
                spin_lock_irqsave(&ctlr->queue_lock, flags);
-               ctlr->idling = false;
-               spin_unlock_irqrestore(&ctlr->queue_lock, flags);
-               return;
+               ctlr->queue_empty = true;
+               goto out_unlock;
        }
 
        /* Extract head of queue */
@@ -1590,81 +1726,23 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
                ctlr->busy = true;
        spin_unlock_irqrestore(&ctlr->queue_lock, flags);
 
-       mutex_lock(&ctlr->io_mutex);
-
-       if (!was_busy && ctlr->auto_runtime_pm) {
-               ret = pm_runtime_resume_and_get(ctlr->dev.parent);
-               if (ret < 0) {
-                       dev_err(&ctlr->dev, "Failed to power device: %d\n",
-                               ret);
-                       mutex_unlock(&ctlr->io_mutex);
-                       return;
-               }
-       }
-
-       if (!was_busy)
-               trace_spi_controller_busy(ctlr);
-
-       if (!was_busy && ctlr->prepare_transfer_hardware) {
-               ret = ctlr->prepare_transfer_hardware(ctlr);
-               if (ret) {
-                       dev_err(&ctlr->dev,
-                               "failed to prepare transfer hardware: %d\n",
-                               ret);
-
-                       if (ctlr->auto_runtime_pm)
-                               pm_runtime_put(ctlr->dev.parent);
-
-                       msg->status = ret;
-                       spi_finalize_current_message(ctlr);
-
-                       mutex_unlock(&ctlr->io_mutex);
-                       return;
-               }
-       }
-
-       trace_spi_message_start(msg);
-
-       if (ctlr->prepare_message) {
-               ret = ctlr->prepare_message(ctlr, msg);
-               if (ret) {
-                       dev_err(&ctlr->dev, "failed to prepare message: %d\n",
-                               ret);
-                       msg->status = ret;
-                       spi_finalize_current_message(ctlr);
-                       goto out;
-               }
-               ctlr->cur_msg_prepared = true;
-       }
-
-       ret = spi_map_msg(ctlr, msg);
-       if (ret) {
-               msg->status = ret;
-               spi_finalize_current_message(ctlr);
-               goto out;
-       }
-
-       if (!ctlr->ptp_sts_supported && !ctlr->transfer_one) {
-               list_for_each_entry(xfer, &msg->transfers, transfer_list) {
-                       xfer->ptp_sts_word_pre = 0;
-                       ptp_read_system_prets(xfer->ptp_sts);
-               }
-       }
+       ret = __spi_pump_transfer_message(ctlr, msg, was_busy);
+       if (!ret)
+               kthread_queue_work(ctlr->kworker, &ctlr->pump_messages);
 
-       ret = ctlr->transfer_one_message(ctlr, msg);
-       if (ret) {
-               dev_err(&ctlr->dev,
-                       "failed to transfer one message from queue: %d\n",
-                       ret);
-               goto out;
-       }
+       ctlr->cur_msg = NULL;
+       ctlr->fallback = false;
 
-out:
        mutex_unlock(&ctlr->io_mutex);
 
        /* Prod the scheduler in case transfer_one() was busy waiting */
        if (!ret)
                cond_resched();
+       return;
+
+out_unlock:
+       spin_unlock_irqrestore(&ctlr->queue_lock, flags);
+       mutex_unlock(&ctlr->io_mutex);
 }
 
 /**
@@ -1789,6 +1867,7 @@ static int spi_init_queue(struct spi_controller *ctlr)
 {
        ctlr->running = false;
        ctlr->busy = false;
+       ctlr->queue_empty = true;
 
        ctlr->kworker = kthread_create_worker(0, dev_name(&ctlr->dev));
        if (IS_ERR(ctlr->kworker)) {
@@ -1826,7 +1905,7 @@ struct spi_message *spi_get_next_queued_message(struct spi_controller *ctlr)
        struct spi_message *next;
        unsigned long flags;
 
-       /* get a pointer to the next message, if any */
+       /* Get a pointer to the next message, if any */
        spin_lock_irqsave(&ctlr->queue_lock, flags);
        next = list_first_entry_or_null(&ctlr->queue, struct spi_message,
                                        queue);
@@ -1847,12 +1926,9 @@ void spi_finalize_current_message(struct spi_controller *ctlr)
 {
        struct spi_transfer *xfer;
        struct spi_message *mesg;
-       unsigned long flags;
        int ret;
 
-       spin_lock_irqsave(&ctlr->queue_lock, flags);
        mesg = ctlr->cur_msg;
-       spin_unlock_irqrestore(&ctlr->queue_lock, flags);
 
        if (!ctlr->ptp_sts_supported && !ctlr->transfer_one) {
                list_for_each_entry(xfer, &mesg->transfers, transfer_list) {
@@ -1876,7 +1952,7 @@ void spi_finalize_current_message(struct spi_controller *ctlr)
         */
        spi_res_release(ctlr, mesg);
 
-       if (ctlr->cur_msg_prepared && ctlr->unprepare_message) {
+       if (mesg->prepared && ctlr->unprepare_message) {
                ret = ctlr->unprepare_message(ctlr, mesg);
                if (ret) {
                        dev_err(&ctlr->dev, "failed to unprepare message: %d\n",
@@ -1884,12 +1960,12 @@ void spi_finalize_current_message(struct spi_controller *ctlr)
                }
        }
 
-       spin_lock_irqsave(&ctlr->queue_lock, flags);
-       ctlr->cur_msg = NULL;
-       ctlr->cur_msg_prepared = false;
-       ctlr->fallback = false;
-       kthread_queue_work(ctlr->kworker, &ctlr->pump_messages);
-       spin_unlock_irqrestore(&ctlr->queue_lock, flags);
+       mesg->prepared = false;
+
+       WRITE_ONCE(ctlr->cur_msg_incomplete, false);
+       smp_mb(); /* See __spi_pump_transfer_message()... */
+       if (READ_ONCE(ctlr->cur_msg_need_completion))
+               complete(&ctlr->cur_msg_completion);
 
        trace_spi_message_done(mesg);
 
@@ -1992,6 +2068,7 @@ static int __spi_queued_transfer(struct spi_device *spi,
        msg->status = -EINPROGRESS;
 
        list_add_tail(&msg->queue, &ctlr->queue);
+       ctlr->queue_empty = false;
        if (!ctlr->busy && need_pump)
                kthread_queue_work(ctlr->kworker, &ctlr->pump_messages);
 
@@ -2376,9 +2453,6 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
                        if (lookup->index != -1 && lookup->n++ != lookup->index)
                                return 1;
 
-                       if (lookup->index == -1 && !ctlr)
-                               return -ENODEV;
-
                        status = acpi_get_handle(NULL,
                                                 sb->resource_source.string_ptr,
                                                 &parent_handle);
@@ -2398,7 +2472,7 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
 
                                ctlr = acpi_spi_find_controller_by_adev(adev);
                                if (!ctlr)
-                                       return -ENODEV;
+                                       return -EPROBE_DEFER;
 
                                lookup->ctlr = ctlr;
                        }
@@ -2481,8 +2555,8 @@ struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr,
        acpi_dev_free_resource_list(&resource_list);
 
        if (ret < 0)
-               /* found SPI in _CRS but it points to another controller */
-               return ERR_PTR(-ENODEV);
+               /* Found SPI in _CRS but it points to another controller */
+               return ERR_PTR(ret);
 
        if (!lookup.max_speed_hz &&
            ACPI_SUCCESS(acpi_get_parent(adev->handle, &parent_handle)) &&
@@ -2937,7 +3011,7 @@ int spi_register_controller(struct spi_controller *ctlr)
                return status;
 
        if (ctlr->bus_num >= 0) {
-               /* devices with a fixed bus num must check-in with the num */
+               /* Devices with a fixed bus num must check-in with the num */
                mutex_lock(&board_lock);
                id = idr_alloc(&spi_master_idr, ctlr, ctlr->bus_num,
                        ctlr->bus_num + 1, GFP_KERNEL);
@@ -2946,7 +3020,7 @@ int spi_register_controller(struct spi_controller *ctlr)
                        return id == -ENOSPC ? -EBUSY : id;
                ctlr->bus_num = id;
        } else if (ctlr->dev.of_node) {
-               /* allocate dynamic bus number using Linux idr */
+               /* Allocate dynamic bus number using Linux idr */
                id = of_alias_get_id(ctlr->dev.of_node, "spi");
                if (id >= 0) {
                        ctlr->bus_num = id;
@@ -2975,6 +3049,7 @@ int spi_register_controller(struct spi_controller *ctlr)
        }
        ctlr->bus_lock_flag = 0;
        init_completion(&ctlr->xfer_completion);
+       init_completion(&ctlr->cur_msg_completion);
        if (!ctlr->max_dma_len)
                ctlr->max_dma_len = INT_MAX;
 
@@ -3004,7 +3079,7 @@ int spi_register_controller(struct spi_controller *ctlr)
                goto free_bus_id;
        }
 
-       /* setting last_cs to -1 means no chip selected */
+       /* Setting last_cs to -1 means no chip selected */
        ctlr->last_cs = -1;
 
        status = device_add(&ctlr->dev);
@@ -3028,8 +3103,13 @@ int spi_register_controller(struct spi_controller *ctlr)
                        goto free_bus_id;
                }
        }
-       /* add statistics */
-       spin_lock_init(&ctlr->statistics.lock);
+       /* Add statistics */
+       ctlr->pcpu_statistics = spi_alloc_pcpu_stats(dev);
+       if (!ctlr->pcpu_statistics) {
+               dev_err(dev, "Error allocating per-cpu statistics\n");
+               status = -ENOMEM;
+               goto destroy_queue;
+       }
 
        mutex_lock(&board_lock);
        list_add_tail(&ctlr->list, &spi_controller_list);
@@ -3042,6 +3122,8 @@ int spi_register_controller(struct spi_controller *ctlr)
        acpi_register_spi_devices(ctlr);
        return status;
 
+destroy_queue:
+       spi_destroy_queue(ctlr);
 free_bus_id:
        mutex_lock(&board_lock);
        idr_remove(&spi_master_idr, ctlr->bus_num);
@@ -3050,9 +3132,9 @@ free_bus_id:
 }
 EXPORT_SYMBOL_GPL(spi_register_controller);
 
-static void devm_spi_unregister(void *ctlr)
+static void devm_spi_unregister(struct device *dev, void *res)
 {
-       spi_unregister_controller(ctlr);
+       spi_unregister_controller(*(struct spi_controller **)res);
 }
 
 /**
@@ -3071,13 +3153,22 @@ static void devm_spi_unregister(void *ctlr)
 int devm_spi_register_controller(struct device *dev,
                                 struct spi_controller *ctlr)
 {
+       struct spi_controller **ptr;
        int ret;
 
+       ptr = devres_alloc(devm_spi_unregister, sizeof(*ptr), GFP_KERNEL);
+       if (!ptr)
+               return -ENOMEM;
+
        ret = spi_register_controller(ctlr);
-       if (ret)
-               return ret;
+       if (!ret) {
+               *ptr = ctlr;
+               devres_add(dev, ptr);
+       } else {
+               devres_free(ptr);
+       }
 
-       return devm_add_action_or_reset(dev, devm_spi_unregister, ctlr);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(devm_spi_register_controller);
 
@@ -3124,7 +3215,7 @@ void spi_unregister_controller(struct spi_controller *ctlr)
 
        device_del(&ctlr->dev);
 
-       /* free bus id */
+       /* Free bus id */
        mutex_lock(&board_lock);
        if (found == ctlr)
                idr_remove(&spi_master_idr, id);
@@ -3183,14 +3274,14 @@ static void __spi_replace_transfers_release(struct spi_controller *ctlr,
        struct spi_replaced_transfers *rxfer = res;
        size_t i;
 
-       /* call extra callback if requested */
+       /* Call extra callback if requested */
        if (rxfer->release)
                rxfer->release(ctlr, msg, res);
 
-       /* insert replaced transfers back into the message */
+       /* Insert replaced transfers back into the message */
        list_splice(&rxfer->replaced_transfers, rxfer->replaced_after);
 
-       /* remove the formerly inserted entries */
+       /* Remove the formerly inserted entries */
        for (i = 0; i < rxfer->inserted; i++)
                list_del(&rxfer->inserted_transfers[i].transfer_list);
 }
@@ -3223,7 +3314,7 @@ static struct spi_replaced_transfers *spi_replace_transfers(
        struct spi_transfer *xfer;
        size_t i;
 
-       /* allocate the structure using spi_res */
+       /* Allocate the structure using spi_res */
        rxfer = spi_res_alloc(msg->spi, __spi_replace_transfers_release,
                              struct_size(rxfer, inserted_transfers, insert)
                              + extradatasize,
@@ -3231,15 +3322,15 @@ static struct spi_replaced_transfers *spi_replace_transfers(
        if (!rxfer)
                return ERR_PTR(-ENOMEM);
 
-       /* the release code to invoke before running the generic release */
+       /* The release code to invoke before running the generic release */
        rxfer->release = release;
 
-       /* assign extradata */
+       /* Assign extradata */
        if (extradatasize)
                rxfer->extradata =
                        &rxfer->inserted_transfers[insert];
 
-       /* init the replaced_transfers list */
+       /* Init the replaced_transfers list */
        INIT_LIST_HEAD(&rxfer->replaced_transfers);
 
        /*
@@ -3248,7 +3339,7 @@ static struct spi_replaced_transfers *spi_replace_transfers(
         */
        rxfer->replaced_after = xfer_first->transfer_list.prev;
 
-       /* remove the requested number of transfers */
+       /* Remove the requested number of transfers */
        for (i = 0; i < remove; i++) {
                /*
                 * If the entry after replaced_after it is msg->transfers
@@ -3258,14 +3349,14 @@ static struct spi_replaced_transfers *spi_replace_transfers(
                if (rxfer->replaced_after->next == &msg->transfers) {
                        dev_err(&msg->spi->dev,
                                "requested to remove more spi_transfers than are available\n");
-                       /* insert replaced transfers back into the message */
+                       /* Insert replaced transfers back into the message */
                        list_splice(&rxfer->replaced_transfers,
                                    rxfer->replaced_after);
 
-                       /* free the spi_replace_transfer structure */
+                       /* Free the spi_replace_transfer structure... */
                        spi_res_free(rxfer);
 
-                       /* and return with an error */
+                       /* ...and return with an error */
                        return ERR_PTR(-EINVAL);
                }
 
@@ -3282,26 +3373,26 @@ static struct spi_replaced_transfers *spi_replace_transfers(
         * based on the first transfer to get removed.
         */
        for (i = 0; i < insert; i++) {
-               /* we need to run in reverse order */
+               /* We need to run in reverse order */
                xfer = &rxfer->inserted_transfers[insert - 1 - i];
 
-               /* copy all spi_transfer data */
+               /* Copy all spi_transfer data */
                memcpy(xfer, xfer_first, sizeof(*xfer));
 
-               /* add to list */
+               /* Add to list */
                list_add(&xfer->transfer_list, rxfer->replaced_after);
 
-               /* clear cs_change and delay for all but the last */
+               /* Clear cs_change and delay for all but the last */
                if (i) {
                        xfer->cs_change = false;
                        xfer->delay.value = 0;
                }
        }
 
-       /* set up inserted */
+       /* Set up inserted... */
        rxfer->inserted = insert;
 
-       /* and register it with spi_res/spi_message */
+       /* ...and register it with spi_res/spi_message */
        spi_res_add(msg, rxfer);
 
        return rxfer;
@@ -3318,10 +3409,10 @@ static int __spi_split_transfer_maxsize(struct spi_controller *ctlr,
        size_t offset;
        size_t count, i;
 
-       /* calculate how many we have to replace */
+       /* Calculate how many we have to replace */
        count = DIV_ROUND_UP(xfer->len, maxsize);
 
-       /* create replacement */
+       /* Create replacement */
        srt = spi_replace_transfers(msg, xfer, 1, count, NULL, 0, gfp);
        if (IS_ERR(srt))
                return PTR_ERR(srt);
@@ -3344,9 +3435,9 @@ static int __spi_split_transfer_maxsize(struct spi_controller *ctlr,
         */
        xfers[0].len = min_t(size_t, maxsize, xfer[0].len);
 
-       /* all the others need rx_buf/tx_buf also set */
+       /* All the others need rx_buf/tx_buf also set */
        for (i = 1, offset = maxsize; i < count; offset += maxsize, i++) {
-               /* update rx_buf, tx_buf and dma */
+               /* Update rx_buf, tx_buf and dma */
                if (xfers[i].rx_buf)
                        xfers[i].rx_buf += offset;
                if (xfers[i].rx_dma)
@@ -3356,7 +3447,7 @@ static int __spi_split_transfer_maxsize(struct spi_controller *ctlr,
                if (xfers[i].tx_dma)
                        xfers[i].tx_dma += offset;
 
-               /* update length */
+               /* Update length */
                xfers[i].len = min(maxsize, xfers[i].len - offset);
        }
 
@@ -3366,10 +3457,10 @@ static int __spi_split_transfer_maxsize(struct spi_controller *ctlr,
         */
        *xferp = &xfers[count - 1];
 
-       /* increment statistics counters */
-       SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics,
+       /* Increment statistics counters */
+       SPI_STATISTICS_INCREMENT_FIELD(ctlr->pcpu_statistics,
                                       transfers_split_maxsize);
-       SPI_STATISTICS_INCREMENT_FIELD(&msg->spi->statistics,
+       SPI_STATISTICS_INCREMENT_FIELD(msg->spi->pcpu_statistics,
                                       transfers_split_maxsize);
 
        return 0;
@@ -3628,7 +3719,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
                        return ret;
 
                list_for_each_entry(xfer, &message->transfers, transfer_list) {
-                       /* don't change cs_change on the last entry in the list */
+                       /* Don't change cs_change on the last entry in the list */
                        if (list_is_last(&xfer->transfer_list, &message->transfers))
                                break;
                        xfer->cs_change = 1;
@@ -3721,7 +3812,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
                                !(spi->mode & SPI_TX_QUAD))
                                return -EINVAL;
                }
-               /* check transfer rx_nbits */
+               /* Check transfer rx_nbits */
                if (xfer->rx_buf) {
                        if (spi->mode & SPI_NO_RX)
                                return -EINVAL;
@@ -3760,8 +3851,8 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
 
        message->spi = spi;
 
-       SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics, spi_async);
-       SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_async);
+       SPI_STATISTICS_INCREMENT_FIELD(ctlr->pcpu_statistics, spi_async);
+       SPI_STATISTICS_INCREMENT_FIELD(spi->pcpu_statistics, spi_async);
 
        trace_spi_message_submit(message);
 
@@ -3880,6 +3971,39 @@ static int spi_async_locked(struct spi_device *spi, struct spi_message *message)
 
 }
 
+static void __spi_transfer_message_noqueue(struct spi_controller *ctlr, struct spi_message *msg)
+{
+       bool was_busy;
+       int ret;
+
+       mutex_lock(&ctlr->io_mutex);
+
+       was_busy = ctlr->busy;
+
+       ctlr->cur_msg = msg;
+       ret = __spi_pump_transfer_message(ctlr, msg, was_busy);
+       if (ret)
+               goto out;
+
+       ctlr->cur_msg = NULL;
+       ctlr->fallback = false;
+
+       if (!was_busy) {
+               kfree(ctlr->dummy_rx);
+               ctlr->dummy_rx = NULL;
+               kfree(ctlr->dummy_tx);
+               ctlr->dummy_tx = NULL;
+               if (ctlr->unprepare_transfer_hardware &&
+                   ctlr->unprepare_transfer_hardware(ctlr))
+                       dev_err(&ctlr->dev,
+                               "failed to unprepare transfer hardware\n");
+               spi_idle_runtime_pm(ctlr);
+       }
+
+out:
+       mutex_unlock(&ctlr->io_mutex);
+}
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -3898,51 +4022,51 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message)
        DECLARE_COMPLETION_ONSTACK(done);
        int status;
        struct spi_controller *ctlr = spi->controller;
-       unsigned long flags;
 
        status = __spi_validate(spi, message);
        if (status != 0)
                return status;
 
-       message->complete = spi_complete;
-       message->context = &done;
        message->spi = spi;
 
-       SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics, spi_sync);
-       SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_sync);
+       SPI_STATISTICS_INCREMENT_FIELD(ctlr->pcpu_statistics, spi_sync);
+       SPI_STATISTICS_INCREMENT_FIELD(spi->pcpu_statistics, spi_sync);
 
        /*
-        * If we're not using the legacy transfer method then we will
-        * try to transfer in the calling context so special case.
-        * This code would be less tricky if we could remove the
-        * support for driver implemented message queues.
+        * Checking queue_empty here only guarantees async/sync message
+        * ordering when coming from the same context. It does not need to
+        * guard against reentrancy from a different context. The io_mutex
+        * will catch those cases.
         */
-       if (ctlr->transfer == spi_queued_transfer) {
-               spin_lock_irqsave(&ctlr->bus_lock_spinlock, flags);
+       if (READ_ONCE(ctlr->queue_empty)) {
+               message->actual_length = 0;
+               message->status = -EINPROGRESS;
 
                trace_spi_message_submit(message);
 
-               status = __spi_queued_transfer(spi, message, false);
+               SPI_STATISTICS_INCREMENT_FIELD(ctlr->pcpu_statistics, spi_sync_immediate);
+               SPI_STATISTICS_INCREMENT_FIELD(spi->pcpu_statistics, spi_sync_immediate);
 
-               spin_unlock_irqrestore(&ctlr->bus_lock_spinlock, flags);
-       } else {
-               status = spi_async_locked(spi, message);
+               __spi_transfer_message_noqueue(ctlr, message);
+
+               return message->status;
        }
 
+       /*
+        * There are messages in the async queue that could have originated
+        * from the same context, so we need to preserve ordering.
+        * Therefor we send the message to the async queue and wait until they
+        * are completed.
+        */
+       message->complete = spi_complete;
+       message->context = &done;
+       status = spi_async_locked(spi, message);
        if (status == 0) {
-               /* Push out the messages in the calling context if we can */
-               if (ctlr->transfer == spi_queued_transfer) {
-                       SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics,
-                                                      spi_sync_immediate);
-                       SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics,
-                                                      spi_sync_immediate);
-                       __spi_pump_messages(ctlr, false);
-               }
-
                wait_for_completion(&done);
                status = message->status;
        }
        message->context = NULL;
+
        return status;
 }
 
@@ -4026,7 +4150,7 @@ int spi_bus_lock(struct spi_controller *ctlr)
        ctlr->bus_lock_flag = 1;
        spin_unlock_irqrestore(&ctlr->bus_lock_spinlock, flags);
 
-       /* mutex remains locked until spi_bus_unlock is called */
+       /* Mutex remains locked until spi_bus_unlock() is called */
 
        return 0;
 }
@@ -4055,7 +4179,7 @@ int spi_bus_unlock(struct spi_controller *ctlr)
 }
 EXPORT_SYMBOL_GPL(spi_bus_unlock);
 
-/* portable code must never pass more than 32 bytes */
+/* Portable code must never pass more than 32 bytes */
 #define        SPI_BUFSIZ      max(32, SMP_CACHE_BYTES)
 
 static u8      *buf;
@@ -4121,7 +4245,7 @@ int spi_write_then_read(struct spi_device *spi,
        x[0].tx_buf = local_buf;
        x[1].rx_buf = local_buf + n_tx;
 
-       /* do the i/o */
+       /* Do the i/o */
        status = spi_sync(spi, &message);
        if (status == 0)
                memcpy(rxbuf, x[1].rx_buf, n_rx);
@@ -4138,7 +4262,7 @@ EXPORT_SYMBOL_GPL(spi_write_then_read);
 /*-------------------------------------------------------------------------*/
 
 #if IS_ENABLED(CONFIG_OF_DYNAMIC)
-/* must call put_device() when done with returned spi_device device */
+/* Must call put_device() when done with returned spi_device device */
 static struct spi_device *of_find_spi_device_by_node(struct device_node *node)
 {
        struct device *dev = bus_find_device_by_of_node(&spi_bus_type, node);
@@ -4146,7 +4270,7 @@ static struct spi_device *of_find_spi_device_by_node(struct device_node *node)
        return dev ? to_spi_device(dev) : NULL;
 }
 
-/* the spi controllers are not using spi_bus, so we find it with another way */
+/* The spi controllers are not using spi_bus, so we find it with another way */
 static struct spi_controller *of_find_spi_controller_by_node(struct device_node *node)
 {
        struct device *dev;
@@ -4157,7 +4281,7 @@ static struct spi_controller *of_find_spi_controller_by_node(struct device_node
        if (!dev)
                return NULL;
 
-       /* reference got in class_find_device */
+       /* Reference got in class_find_device */
        return container_of(dev, struct spi_controller, dev);
 }
 
@@ -4172,7 +4296,7 @@ static int of_spi_notify(struct notifier_block *nb, unsigned long action,
        case OF_RECONFIG_CHANGE_ADD:
                ctlr = of_find_spi_controller_by_node(rd->dn->parent);
                if (ctlr == NULL)
-                       return NOTIFY_OK;       /* not for us */
+                       return NOTIFY_OK;       /* Not for us */
 
                if (of_node_test_and_set_flag(rd->dn, OF_POPULATED)) {
                        put_device(&ctlr->dev);
@@ -4191,19 +4315,19 @@ static int of_spi_notify(struct notifier_block *nb, unsigned long action,
                break;
 
        case OF_RECONFIG_CHANGE_REMOVE:
-               /* already depopulated? */
+               /* Already depopulated? */
                if (!of_node_check_flag(rd->dn, OF_POPULATED))
                        return NOTIFY_OK;
 
-               /* find our device by node */
+               /* Find our device by node */
                spi = of_find_spi_device_by_node(rd->dn);
                if (spi == NULL)
-                       return NOTIFY_OK;       /* no? not meant for us */
+                       return NOTIFY_OK;       /* No? not meant for us */
 
-               /* unregister takes one ref away */
+               /* Unregister takes one ref away */
                spi_unregister_device(spi);
 
-               /* and put the reference of the find */
+               /* And put the reference of the find */
                put_device(&spi->dev);
                break;
        }
index 3384452..02fdef7 100644 (file)
@@ -2632,7 +2632,7 @@ static void hfa384x_usbctlx_reaper_task(struct work_struct *work)
  */
 static void hfa384x_usbctlx_completion_task(struct work_struct *work)
 {
-       struct hfa384x *hw = container_of(work, struct hfa384x, reaper_bh);
+       struct hfa384x *hw = container_of(work, struct hfa384x, completion_bh);
        struct hfa384x_usbctlx *ctlx, *temp;
        unsigned long flags;
 
index e68f1cc..6c8d8b0 100644 (file)
@@ -448,6 +448,9 @@ fd_execute_write_same(struct se_cmd *cmd)
                return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
        }
 
+       if (!cmd->t_data_nents)
+               return TCM_INVALID_CDB_FIELD;
+
        if (cmd->t_data_nents > 1 ||
            cmd->t_data_sg[0].length != cmd->se_dev->dev_attrib.block_size) {
                pr_err("WRITE_SAME: Illegal SGL t_data_nents: %u length: %u"
index 378c803..30712a1 100644 (file)
@@ -343,7 +343,7 @@ static void iblock_bio_done(struct bio *bio)
 }
 
 static struct bio *iblock_get_bio(struct se_cmd *cmd, sector_t lba, u32 sg_num,
-                                 unsigned int opf)
+                                 blk_opf_t opf)
 {
        struct iblock_dev *ib_dev = IBLOCK_DEV(cmd->se_dev);
        struct bio *bio;
@@ -494,6 +494,10 @@ iblock_execute_write_same(struct se_cmd *cmd)
                       " backends not supported\n");
                return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
        }
+
+       if (!cmd->t_data_nents)
+               return TCM_INVALID_CDB_FIELD;
+
        sg = &cmd->t_data_sg[0];
 
        if (cmd->t_data_nents > 1 ||
@@ -719,7 +723,7 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
        struct bio_list list;
        struct scatterlist *sg;
        u32 sg_num = sgl_nents;
-       unsigned int opf;
+       blk_opf_t opf;
        unsigned bio_cnt;
        int i, rc;
        struct sg_mapping_iter prot_miter;
index ca1b231..f613283 100644 (file)
@@ -312,6 +312,12 @@ sbc_setup_write_same(struct se_cmd *cmd, unsigned char flags, struct sbc_ops *op
                pr_warn("WRITE SAME with ANCHOR not supported\n");
                return TCM_INVALID_CDB_FIELD;
        }
+
+       if (flags & 0x01) {
+               pr_warn("WRITE SAME with NDOB not supported\n");
+               return TCM_INVALID_CDB_FIELD;
+       }
+
        /*
         * Special case for WRITE_SAME w/ UNMAP=1 that ends up getting
         * translated into block discard requests within backend code.
index c60896c..73b5e77 100644 (file)
@@ -189,7 +189,7 @@ struct optee_smc_call_get_os_revision_result {
  * Have config return register usage:
  * a0  OPTEE_SMC_RETURN_OK
  * a1  Physical address of start of SHM
- * a2  Size of of SHM
+ * a2  Size of SHM
  * a3  Cache settings of memory, as defined by the
  *     OPTEE_SMC_SHM_* values above
  * a4-7        Preserved
index 385cb0a..a1c1fa1 100644 (file)
@@ -884,8 +884,8 @@ static int optee_smc_do_call_with_arg(struct tee_context *ctx,
 
                rpc_arg_offs = OPTEE_MSG_GET_ARG_SIZE(arg->num_params);
                rpc_arg = tee_shm_get_va(shm, offs + rpc_arg_offs);
-               if (IS_ERR(arg))
-                       return PTR_ERR(arg);
+               if (IS_ERR(rpc_arg))
+                       return PTR_ERR(rpc_arg);
        }
 
        if  (rpc_arg && tee_shm_is_dynamic(shm)) {
index af0f7c6..98da206 100644 (file)
@@ -1073,7 +1073,7 @@ EXPORT_SYMBOL_GPL(tee_device_unregister);
 /**
  * tee_get_drvdata() - Return driver_data pointer
  * @teedev:    Device containing the driver_data pointer
- * @returns the driver_data pointer supplied to tee_register().
+ * @returns the driver_data pointer supplied to tee_device_alloc().
  */
 void *tee_get_drvdata(struct tee_device *teedev)
 {
index b8151d9..b76293c 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/pm_qos.h>
 #include <linux/slab.h>
 #include <linux/thermal.h>
+#include <linux/units.h>
 
 #include <trace/events/thermal.h>
 
@@ -59,6 +60,7 @@ struct time_in_idle {
  * @cdev: thermal_cooling_device pointer to keep track of the
  *     registered cooling device.
  * @policy: cpufreq policy.
+ * @cooling_ops: cpufreq callbacks to thermal cooling device ops
  * @idle_time: idle time stats
  * @qos_req: PM QoS contraint to apply
  *
@@ -71,6 +73,7 @@ struct cpufreq_cooling_device {
        unsigned int max_level;
        struct em_perf_domain *em;
        struct cpufreq_policy *policy;
+       struct thermal_cooling_device_ops cooling_ops;
 #ifndef CONFIG_SMP
        struct time_in_idle *idle_time;
 #endif
@@ -101,6 +104,7 @@ static unsigned long get_level(struct cpufreq_cooling_device *cpufreq_cdev,
 static u32 cpu_freq_to_power(struct cpufreq_cooling_device *cpufreq_cdev,
                             u32 freq)
 {
+       unsigned long power_mw;
        int i;
 
        for (i = cpufreq_cdev->max_level - 1; i >= 0; i--) {
@@ -108,16 +112,23 @@ static u32 cpu_freq_to_power(struct cpufreq_cooling_device *cpufreq_cdev,
                        break;
        }
 
-       return cpufreq_cdev->em->table[i + 1].power;
+       power_mw = cpufreq_cdev->em->table[i + 1].power;
+       power_mw /= MICROWATT_PER_MILLIWATT;
+
+       return power_mw;
 }
 
 static u32 cpu_power_to_freq(struct cpufreq_cooling_device *cpufreq_cdev,
                             u32 power)
 {
+       unsigned long em_power_mw;
        int i;
 
        for (i = cpufreq_cdev->max_level; i > 0; i--) {
-               if (power >= cpufreq_cdev->em->table[i].power)
+               /* Convert EM power to milli-Watts to make safe comparison */
+               em_power_mw = cpufreq_cdev->em->table[i].power;
+               em_power_mw /= MICROWATT_PER_MILLIWATT;
+               if (power >= em_power_mw)
                        break;
        }
 
@@ -137,11 +148,9 @@ static u32 cpu_power_to_freq(struct cpufreq_cooling_device *cpufreq_cdev,
 static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu,
                    int cpu_idx)
 {
-       unsigned long max = arch_scale_cpu_capacity(cpu);
-       unsigned long util;
+       unsigned long util = sched_cpu_util(cpu);
 
-       util = sched_cpu_util(cpu, max);
-       return (util * 100) / max;
+       return (util * 100) / arch_scale_cpu_capacity(cpu);
 }
 #else /* !CONFIG_SMP */
 static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu,
@@ -204,7 +213,7 @@ static u32 get_dynamic_power(struct cpufreq_cooling_device *cpufreq_cdev,
  * complex code may be needed if experiments show that it's not
  * accurate enough.
  *
- * Return: 0 on success, -E* if getting the static power failed.
+ * Return: 0 on success, this function doesn't fail.
  */
 static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev,
                                       u32 *power)
@@ -214,16 +223,9 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev,
        u32 total_load = 0;
        struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
        struct cpufreq_policy *policy = cpufreq_cdev->policy;
-       u32 *load_cpu = NULL;
 
        freq = cpufreq_quick_get(policy->cpu);
 
-       if (trace_thermal_power_cpu_get_power_enabled()) {
-               u32 ncpus = cpumask_weight(policy->related_cpus);
-
-               load_cpu = kcalloc(ncpus, sizeof(*load_cpu), GFP_KERNEL);
-       }
-
        for_each_cpu(cpu, policy->related_cpus) {
                u32 load;
 
@@ -233,22 +235,13 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev,
                        load = 0;
 
                total_load += load;
-               if (load_cpu)
-                       load_cpu[i] = load;
-
-               i++;
        }
 
        cpufreq_cdev->last_load = total_load;
 
        *power = get_dynamic_power(cpufreq_cdev, freq);
 
-       if (load_cpu) {
-               trace_thermal_power_cpu_get_power(policy->related_cpus, freq,
-                                                 load_cpu, i, *power);
-
-               kfree(load_cpu);
-       }
+       trace_thermal_power_cpu_get_power_simple(policy->cpu, *power);
 
        return 0;
 }
@@ -263,9 +256,8 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev,
  * milliwatts assuming 100% load.  Store the calculated power in
  * @power.
  *
- * Return: 0 on success, -EINVAL if the cooling device state could not
- * be converted into a frequency or other -E* if there was an error
- * when calculating the static power.
+ * Return: 0 on success, -EINVAL if the cooling device state is bigger
+ * than maximum allowed.
  */
 static int cpufreq_state2power(struct thermal_cooling_device *cdev,
                               unsigned long state, u32 *power)
@@ -295,15 +287,11 @@ static int cpufreq_state2power(struct thermal_cooling_device *cdev,
  * Calculate a cooling device state for the cpus described by @cdev
  * that would allow them to consume at most @power mW and store it in
  * @state.  Note that this calculation depends on external factors
- * such as the cpu load or the current static power.  Calling this
- * function with the same power as input can yield different cooling
- * device states depending on those external factors.
- *
- * Return: 0 on success, -ENODEV if no cpus are online or -EINVAL if
- * the calculated frequency could not be converted to a valid state.
- * The latter should not happen unless the frequencies available to
- * cpufreq have changed since the initialization of the cpu cooling
- * device.
+ * such as the CPUs load.  Calling this function with the same power
+ * as input can yield different cooling device states depending on those
+ * external factors.
+ *
+ * Return: 0 on success, this function doesn't fail.
  */
 static int cpufreq_power2state(struct thermal_cooling_device *cdev,
                               u32 power, unsigned long *state)
@@ -415,7 +403,7 @@ static unsigned int get_state_freq(struct cpufreq_cooling_device *cpufreq_cdev,
  * Callback for the thermal cooling device to return the cpufreq
  * max cooling state.
  *
- * Return: 0 on success, an error code otherwise.
+ * Return: 0 on success, this function doesn't fail.
  */
 static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
                                 unsigned long *state)
@@ -434,7 +422,7 @@ static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
  * Callback for the thermal cooling device to return the cpufreq
  * current cooling state.
  *
- * Return: 0 on success, an error code otherwise.
+ * Return: 0 on success, this function doesn't fail.
  */
 static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev,
                                 unsigned long *state)
@@ -485,14 +473,6 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
        return ret;
 }
 
-/* Bind cpufreq callbacks to thermal cooling device ops */
-
-static struct thermal_cooling_device_ops cpufreq_cooling_ops = {
-       .get_max_state          = cpufreq_get_max_state,
-       .get_cur_state          = cpufreq_get_cur_state,
-       .set_cur_state          = cpufreq_set_cur_state,
-};
-
 /**
  * __cpufreq_cooling_register - helper function to create cpufreq cooling device
  * @np: a valid struct device_node to the cooling device device tree node
@@ -501,7 +481,7 @@ static struct thermal_cooling_device_ops cpufreq_cooling_ops = {
  * @em: Energy Model of the cpufreq policy
  *
  * This interface function registers the cpufreq cooling device with the name
- * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq
+ * "cpufreq-%s". This API can support multiple instances of cpufreq
  * cooling devices. It also gives the opportunity to link the cooling device
  * with a device tree node, in order to bind it via the thermal DT code.
  *
@@ -554,7 +534,10 @@ __cpufreq_cooling_register(struct device_node *np,
        /* max_level is an index, not a counter */
        cpufreq_cdev->max_level = i - 1;
 
-       cooling_ops = &cpufreq_cooling_ops;
+       cooling_ops = &cpufreq_cdev->cooling_ops;
+       cooling_ops->get_max_state = cpufreq_get_max_state;
+       cooling_ops->get_cur_state = cpufreq_get_cur_state;
+       cooling_ops->set_cur_state = cpufreq_set_cur_state;
 
 #ifdef CONFIG_THERMAL_GOV_POWER_ALLOCATOR
        if (em_is_sane(cpufreq_cdev, em)) {
@@ -609,8 +592,8 @@ free_cdev:
  * @policy: cpufreq policy
  *
  * This interface function registers the cpufreq cooling device with the name
- * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq
- * cooling devices.
+ * "cpufreq-%s". This API can support multiple instances of cpufreq cooling
+ * devices.
  *
  * Return: a valid struct thermal_cooling_device pointer on success,
  * on failure, it returns a corresponding ERR_PTR().
@@ -627,17 +610,14 @@ EXPORT_SYMBOL_GPL(cpufreq_cooling_register);
  * @policy: cpufreq policy
  *
  * This interface function registers the cpufreq cooling device with the name
- * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq
- * cooling devices. Using this API, the cpufreq cooling device will be
- * linked to the device tree node provided.
+ * "cpufreq-%s". This API can support multiple instances of cpufreq cooling
+ * devices. Using this API, the cpufreq cooling device will be linked to the
+ * device tree node provided.
  *
  * Using this function, the cooling device will implement the power
- * extensions by using a simple cpu power model.  The cpus must have
+ * extensions by using the Energy Model (if present).  The cpus must have
  * registered their OPPs using the OPP library.
  *
- * It also takes into account, if property present in policy CPU node, the
- * static power consumed by the cpu.
- *
  * Return: a valid struct thermal_cooling_device pointer on success,
  * and NULL on failure.
  */
@@ -673,7 +653,7 @@ EXPORT_SYMBOL_GPL(of_cpufreq_cooling_register);
  * cpufreq_cooling_unregister - function to remove cpufreq cooling device.
  * @cdev: thermal cooling device pointer.
  *
- * This interface function unregisters the "thermal-cpufreq-%x" cooling device.
+ * This interface function unregisters the "cpufreq-%x" cooling device.
  */
 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
 {
index 21d4d6e..121cf85 100644 (file)
@@ -53,7 +53,6 @@ static const unsigned long db8500_thermal_points[] = {
 
 struct db8500_thermal_zone {
        struct thermal_zone_device *tz;
-       enum thermal_trend trend;
        unsigned long interpolated_temp;
        unsigned int cur_index;
 };
@@ -73,24 +72,12 @@ static int db8500_thermal_get_temp(void *data, int *temp)
        return 0;
 }
 
-/* Callback to get temperature changing trend */
-static int db8500_thermal_get_trend(void *data, int trip, enum thermal_trend *trend)
-{
-       struct db8500_thermal_zone *th = data;
-
-       *trend = th->trend;
-
-       return 0;
-}
-
 static struct thermal_zone_of_device_ops thdev_ops = {
        .get_temp = db8500_thermal_get_temp,
-       .get_trend = db8500_thermal_get_trend,
 };
 
 static void db8500_thermal_update_config(struct db8500_thermal_zone *th,
                                         unsigned int idx,
-                                        enum thermal_trend trend,
                                         unsigned long next_low,
                                         unsigned long next_high)
 {
@@ -98,7 +85,6 @@ static void db8500_thermal_update_config(struct db8500_thermal_zone *th,
 
        th->cur_index = idx;
        th->interpolated_temp = (next_low + next_high)/2;
-       th->trend = trend;
 
        /*
         * The PRCMU accept absolute temperatures in celsius so divide
@@ -127,8 +113,7 @@ static irqreturn_t prcmu_low_irq_handler(int irq, void *irq_data)
        }
        idx -= 1;
 
-       db8500_thermal_update_config(th, idx, THERMAL_TREND_DROPPING,
-                                    next_low, next_high);
+       db8500_thermal_update_config(th, idx, next_low, next_high);
        dev_dbg(&th->tz->device,
                "PRCMU set max %ld, min %ld\n", next_high, next_low);
 
@@ -149,8 +134,7 @@ static irqreturn_t prcmu_high_irq_handler(int irq, void *irq_data)
                next_low = db8500_thermal_points[idx];
                idx += 1;
 
-               db8500_thermal_update_config(th, idx, THERMAL_TREND_RAISING,
-                                            next_low, next_high);
+               db8500_thermal_update_config(th, idx, next_low, next_high);
 
                dev_dbg(&th->tz->device,
                        "PRCMU set max %ld, min %ld\n", next_high, next_low);
@@ -174,10 +158,8 @@ static int db8500_thermal_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        low_irq = platform_get_irq_byname(pdev, "IRQ_HOTMON_LOW");
-       if (low_irq < 0) {
-               dev_err(dev, "Get IRQ_HOTMON_LOW failed\n");
+       if (low_irq < 0)
                return low_irq;
-       }
 
        ret = devm_request_threaded_irq(dev, low_irq, NULL,
                prcmu_low_irq_handler, IRQF_NO_SUSPEND | IRQF_ONESHOT,
@@ -188,10 +170,8 @@ static int db8500_thermal_probe(struct platform_device *pdev)
        }
 
        high_irq = platform_get_irq_byname(pdev, "IRQ_HOTMON_HIGH");
-       if (high_irq < 0) {
-               dev_err(dev, "Get IRQ_HOTMON_HIGH failed\n");
+       if (high_irq < 0)
                return high_irq;
-       }
 
        ret = devm_request_threaded_irq(dev, high_irq, NULL,
                prcmu_high_irq_handler, IRQF_NO_SUSPEND | IRQF_ONESHOT,
@@ -210,8 +190,7 @@ static int db8500_thermal_probe(struct platform_device *pdev)
        dev_info(dev, "thermal zone sensor registered\n");
 
        /* Start measuring at the lowest point */
-       db8500_thermal_update_config(th, 0, THERMAL_TREND_STABLE,
-                                    PRCMU_DEFAULT_LOW_TEMP,
+       db8500_thermal_update_config(th, 0, PRCMU_DEFAULT_LOW_TEMP,
                                     db8500_thermal_points[0]);
 
        platform_set_drvdata(pdev, th);
@@ -232,8 +211,7 @@ static int db8500_thermal_resume(struct platform_device *pdev)
        struct db8500_thermal_zone *th = platform_get_drvdata(pdev);
 
        /* Resume and start measuring at the lowest point */
-       db8500_thermal_update_config(th, 0, THERMAL_TREND_STABLE,
-                                    PRCMU_DEFAULT_LOW_TEMP,
+       db8500_thermal_update_config(th, 0, PRCMU_DEFAULT_LOW_TEMP,
                                     db8500_thermal_points[0]);
 
        return 0;
index 8c76f96..24b4749 100644 (file)
@@ -28,6 +28,7 @@
  * struct devfreq_cooling_device - Devfreq cooling device
  *             devfreq_cooling_device registered.
  * @cdev:      Pointer to associated thermal cooling device.
+ * @cooling_ops: devfreq callbacks to thermal cooling device ops
  * @devfreq:   Pointer to associated devfreq device.
  * @cooling_state:     Current cooling state.
  * @freq_table:        Pointer to a table with the frequencies sorted in descending
@@ -48,6 +49,7 @@
  */
 struct devfreq_cooling_device {
        struct thermal_cooling_device *cdev;
+       struct thermal_cooling_device_ops cooling_ops;
        struct devfreq *devfreq;
        unsigned long cooling_state;
        u32 *freq_table;
@@ -200,7 +202,11 @@ static int devfreq_cooling_get_requested_power(struct thermal_cooling_device *cd
                res = dfc->power_ops->get_real_power(df, power, freq, voltage);
                if (!res) {
                        state = dfc->capped_state;
+
+                       /* Convert EM power into milli-Watts first */
                        dfc->res_util = dfc->em_pd->table[state].power;
+                       dfc->res_util /= MICROWATT_PER_MILLIWATT;
+
                        dfc->res_util *= SCALE_ERROR_MITIGATION;
 
                        if (*power > 1)
@@ -218,8 +224,10 @@ static int devfreq_cooling_get_requested_power(struct thermal_cooling_device *cd
 
                _normalize_load(&status);
 
-               /* Scale power for utilization */
+               /* Convert EM power into milli-Watts first */
                *power = dfc->em_pd->table[perf_idx].power;
+               *power /= MICROWATT_PER_MILLIWATT;
+               /* Scale power for utilization */
                *power *= status.busy_time;
                *power >>= 10;
        }
@@ -244,6 +252,7 @@ static int devfreq_cooling_state2power(struct thermal_cooling_device *cdev,
 
        perf_idx = dfc->max_state - state;
        *power = dfc->em_pd->table[perf_idx].power;
+       *power /= MICROWATT_PER_MILLIWATT;
 
        return 0;
 }
@@ -254,7 +263,7 @@ static int devfreq_cooling_power2state(struct thermal_cooling_device *cdev,
        struct devfreq_cooling_device *dfc = cdev->devdata;
        struct devfreq *df = dfc->devfreq;
        struct devfreq_dev_status status;
-       unsigned long freq;
+       unsigned long freq, em_power_mw;
        s32 est_power;
        int i;
 
@@ -279,9 +288,13 @@ static int devfreq_cooling_power2state(struct thermal_cooling_device *cdev,
         * Find the first cooling state that is within the power
         * budget. The EM power table is sorted ascending.
         */
-       for (i = dfc->max_state; i > 0; i--)
-               if (est_power >= dfc->em_pd->table[i].power)
+       for (i = dfc->max_state; i > 0; i--) {
+               /* Convert EM power to milli-Watts to make safe comparison */
+               em_power_mw = dfc->em_pd->table[i].power;
+               em_power_mw /= MICROWATT_PER_MILLIWATT;
+               if (est_power >= em_power_mw)
                        break;
+       }
 
        *state = dfc->max_state - i;
        dfc->capped_state = *state;
@@ -290,12 +303,6 @@ static int devfreq_cooling_power2state(struct thermal_cooling_device *cdev,
        return 0;
 }
 
-static struct thermal_cooling_device_ops devfreq_cooling_ops = {
-       .get_max_state = devfreq_cooling_get_max_state,
-       .get_cur_state = devfreq_cooling_get_cur_state,
-       .set_cur_state = devfreq_cooling_set_cur_state,
-};
-
 /**
  * devfreq_cooling_gen_tables() - Generate frequency table.
  * @dfc:       Pointer to devfreq cooling device.
@@ -363,18 +370,18 @@ of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
        char *name;
        int err, num_opps;
 
-       ops = kmemdup(&devfreq_cooling_ops, sizeof(*ops), GFP_KERNEL);
-       if (!ops)
-               return ERR_PTR(-ENOMEM);
 
        dfc = kzalloc(sizeof(*dfc), GFP_KERNEL);
-       if (!dfc) {
-               err = -ENOMEM;
-               goto free_ops;
-       }
+       if (!dfc)
+               return ERR_PTR(-ENOMEM);
 
        dfc->devfreq = df;
 
+       ops = &dfc->cooling_ops;
+       ops->get_max_state = devfreq_cooling_get_max_state;
+       ops->get_cur_state = devfreq_cooling_get_cur_state;
+       ops->set_cur_state = devfreq_cooling_set_cur_state;
+
        em = em_pd_get(dev);
        if (em && !em_is_artificial(em)) {
                dfc->em_pd = em;
@@ -437,8 +444,6 @@ free_table:
        kfree(dfc->freq_table);
 free_dfc:
        kfree(dfc);
-free_ops:
-       kfree(ops);
 
        return ERR_PTR(err);
 }
@@ -520,13 +525,11 @@ EXPORT_SYMBOL_GPL(devfreq_cooling_em_register);
 void devfreq_cooling_unregister(struct thermal_cooling_device *cdev)
 {
        struct devfreq_cooling_device *dfc;
-       const struct thermal_cooling_device_ops *ops;
        struct device *dev;
 
        if (IS_ERR_OR_NULL(cdev))
                return;
 
-       ops = cdev->ops;
        dfc = cdev->devdata;
        dev = dfc->devfreq->dev.parent;
 
@@ -537,6 +540,5 @@ void devfreq_cooling_unregister(struct thermal_cooling_device *cdev)
 
        kfree(dfc->freq_table);
        kfree(dfc);
-       kfree(ops);
 }
 EXPORT_SYMBOL_GPL(devfreq_cooling_unregister);
index 1e5abf4..6a2abcf 100644 (file)
@@ -25,10 +25,10 @@ static int get_trip_level(struct thermal_zone_device *tz)
        int trip_temp;
        enum thermal_trip_type trip_type;
 
-       if (tz->trips == 0 || !tz->ops->get_trip_temp)
+       if (tz->num_trips == 0 || !tz->ops->get_trip_temp)
                return 0;
 
-       for (count = 0; count < tz->trips; count++) {
+       for (count = 0; count < tz->num_trips; count++) {
                tz->ops->get_trip_temp(tz, count, &trip_temp);
                if (tz->temperature < trip_temp)
                        break;
@@ -53,7 +53,7 @@ static long get_target_state(struct thermal_zone_device *tz,
 
        cdev->ops->get_max_state(cdev, &max_state);
 
-       return (long)(percentage * level * max_state) / (100 * tz->trips);
+       return (long)(percentage * level * max_state) / (100 * tz->num_trips);
 }
 
 /**
index 13e3757..1d50524 100644 (file)
@@ -527,7 +527,7 @@ static void get_governor_trips(struct thermal_zone_device *tz,
        last_active = INVALID_TRIP;
        last_passive = INVALID_TRIP;
 
-       for (i = 0; i < tz->trips; i++) {
+       for (i = 0; i < tz->num_trips; i++) {
                enum thermal_trip_type type;
                int ret;
 
@@ -668,7 +668,7 @@ static int power_allocator_bind(struct thermal_zone_device *tz)
 
        get_governor_trips(tz, params);
 
-       if (tz->trips > 0) {
+       if (tz->num_trips > 0) {
                ret = tz->ops->get_trip_temp(tz,
                                        params->trip_max_desired_temperature,
                                        &control_temp);
index 12acb12..9729b46 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #include <linux/thermal.h>
+#include <linux/minmax.h>
 #include <trace/events/thermal.h>
 
 #include "thermal_core.h"
@@ -52,10 +53,7 @@ static unsigned long get_target_state(struct thermal_instance *instance,
 
        if (!instance->initialized) {
                if (throttle) {
-                       next_target = (cur_state + 1) >= instance->upper ?
-                                       instance->upper :
-                                       ((cur_state + 1) < instance->lower ?
-                                       instance->lower : (cur_state + 1));
+                       next_target = clamp((cur_state + 1), instance->lower, instance->upper);
                } else {
                        next_target = THERMAL_NO_TARGET;
                }
@@ -66,35 +64,19 @@ static unsigned long get_target_state(struct thermal_instance *instance,
        switch (trend) {
        case THERMAL_TREND_RAISING:
                if (throttle) {
-                       next_target = cur_state < instance->upper ?
-                                   (cur_state + 1) : instance->upper;
-                       if (next_target < instance->lower)
-                               next_target = instance->lower;
+                       next_target = clamp((cur_state + 1), instance->lower, instance->upper);
                }
                break;
-       case THERMAL_TREND_RAISE_FULL:
-               if (throttle)
-                       next_target = instance->upper;
-               break;
        case THERMAL_TREND_DROPPING:
                if (cur_state <= instance->lower) {
                        if (!throttle)
                                next_target = THERMAL_NO_TARGET;
                } else {
                        if (!throttle) {
-                               next_target = cur_state - 1;
-                               if (next_target > instance->upper)
-                                       next_target = instance->upper;
+                               next_target = clamp((cur_state - 1), instance->lower, instance->upper);
                        }
                }
                break;
-       case THERMAL_TREND_DROP_FULL:
-               if (cur_state == instance->lower) {
-                       if (!throttle)
-                               next_target = THERMAL_NO_TARGET;
-               } else
-                       next_target = instance->lower;
-               break;
        default:
                break;
        }
index c1fa2b2..dabf11a 100644 (file)
@@ -207,14 +207,6 @@ static int pch_wpt_suspend(struct pch_thermal_device *ptd)
                return 0;
        }
 
-       /* Do not check temperature if it is not a S0ix capable platform */
-#ifdef CONFIG_ACPI
-       if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0))
-               return 0;
-#else
-       return 0;
-#endif
-
        /* Do not check temperature if it is not s2idle */
        if (pm_suspend_via_firmware())
                return 0;
index cd80c7d..a9596e7 100644 (file)
@@ -81,6 +81,7 @@ static const struct x86_cpu_id tcc_ids[] __initconst = {
        X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, NULL),
        X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE, NULL),
        X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, NULL),
+       X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, NULL),
        {}
 };
 
index 4d8edc6..a0e234f 100644 (file)
@@ -105,7 +105,7 @@ static struct zone_device *pkg_temp_thermal_get_dev(unsigned int cpu)
 }
 
 /*
-* tj-max is is interesting because threshold is set relative to this
+* tj-max is interesting because threshold is set relative to this
 * temperature.
 */
 static int get_tj_max(int cpu, u32 *tj_max)
index 64e3231..115a44e 100644 (file)
@@ -151,8 +151,6 @@ static int prep_lookup_table(struct err_values *err_vals, int *ref_table)
                /* 300 milli celsius steps */
                while (i--)
                        derived_table[i] = derived_table[i + 1] - 300;
-               /* case 0 */
-               derived_table[i] = derived_table[i + 1] - 300;
        }
 
        /*
@@ -433,7 +431,7 @@ static int k3_j72xx_bandgap_probe(struct platform_device *pdev)
                                     GFP_KERNEL);
        if (!derived_table) {
                ret = -ENOMEM;
-               goto err_alloc;
+               goto err_free_ref_table;
        }
 
        /* Workaround not needed if bit30/bit31 is set even for J721e */
@@ -483,7 +481,7 @@ static int k3_j72xx_bandgap_probe(struct platform_device *pdev)
                if (IS_ERR(ti_thermal)) {
                        dev_err(bgp->dev, "thermal zone device is NULL\n");
                        ret = PTR_ERR(ti_thermal);
-                       goto err_alloc;
+                       goto err_free_ref_table;
                }
        }
 
@@ -514,6 +512,9 @@ static int k3_j72xx_bandgap_probe(struct platform_device *pdev)
 
        return 0;
 
+err_free_ref_table:
+       kfree(ref_table);
+
 err_alloc:
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
@@ -529,11 +530,11 @@ static int k3_j72xx_bandgap_remove(struct platform_device *pdev)
        return 0;
 }
 
-const struct k3_j72xx_bandgap_data k3_j72xx_bandgap_j721e_data = {
+static const struct k3_j72xx_bandgap_data k3_j72xx_bandgap_j721e_data = {
        .has_errata_i2128 = 1,
 };
 
-const struct k3_j72xx_bandgap_data k3_j72xx_bandgap_j7200_data = {
+static const struct k3_j72xx_bandgap_data k3_j72xx_bandgap_j7200_data = {
        .has_errata_i2128 = 0,
 };
 
index d9c9c97..073943c 100644 (file)
@@ -20,6 +20,8 @@
 #include <linux/thermal.h>
 #include <asm-generic/unaligned.h>
 
+#include "../thermal_hwmon.h"
+
 /*
  * Thermal monitoring block consists of 8 (ADC_TM5_NUM_CHANNELS) channels. Each
  * channel is programmed to use one of ADC channels for voltage comparison.
@@ -687,6 +689,9 @@ static int adc_tm5_register_tzd(struct adc_tm5_chip *adc_tm)
                        return PTR_ERR(tzd);
                }
                adc_tm->channels[i].tzd = tzd;
+               if (devm_thermal_add_hwmon_sysfs(tzd))
+                       dev_warn(adc_tm->dev,
+                                "Failed to add hwmon sysfs attributes\n");
        }
 
        return 0;
index 7419e19..770f82c 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/thermal.h>
 
 #include "../thermal_core.h"
+#include "../thermal_hwmon.h"
 
 #define QPNP_TM_REG_DIG_MAJOR          0x01
 #define QPNP_TM_REG_TYPE               0x04
@@ -458,6 +459,10 @@ static int qpnp_tm_probe(struct platform_device *pdev)
                return ret;
        }
 
+       if (devm_thermal_add_hwmon_sysfs(chip->tz_dev))
+               dev_warn(&pdev->dev,
+                        "Failed to add hwmon sysfs attributes\n");
+
        ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, qpnp_tm_isr,
                                        IRQF_ONESHOT, node->name, chip);
        if (ret < 0)
index 7963ee3..e49f58e 100644 (file)
@@ -933,17 +933,6 @@ static int tsens_get_temp(void *data, int *temp)
        return priv->ops->get_temp(s, temp);
 }
 
-static int tsens_get_trend(void *data, int trip, enum thermal_trend *trend)
-{
-       struct tsens_sensor *s = data;
-       struct tsens_priv *priv = s->priv;
-
-       if (priv->ops->get_trend)
-               return priv->ops->get_trend(s, trend);
-
-       return -ENOTSUPP;
-}
-
 static int  __maybe_unused tsens_suspend(struct device *dev)
 {
        struct tsens_priv *priv = dev_get_drvdata(dev);
@@ -1004,7 +993,6 @@ MODULE_DEVICE_TABLE(of, tsens_table);
 
 static const struct thermal_zone_of_device_ops tsens_of_ops = {
        .get_temp = tsens_get_temp,
-       .get_trend = tsens_get_trend,
        .set_trips = tsens_set_trips,
 };
 
index 1471a2c..ba05c82 100644 (file)
@@ -65,7 +65,6 @@ struct tsens_sensor {
  * @disable: Function to disable the tsens device
  * @suspend: Function to suspend the tsens device
  * @resume: Function to resume the tsens device
- * @get_trend: Function to get the thermal/temp trend
  */
 struct tsens_ops {
        /* mandatory callbacks */
@@ -77,7 +76,6 @@ struct tsens_ops {
        void (*disable)(struct tsens_priv *priv);
        int (*suspend)(struct tsens_priv *priv);
        int (*resume)(struct tsens_priv *priv);
-       int (*get_trend)(struct tsens_sensor *s, enum thermal_trend *trend);
 };
 
 #define REG_FIELD_FOR_EACH_SENSOR11(_name, _offset, _startbit, _stopbit) \
index 43eb25b..cda7c52 100644 (file)
@@ -399,6 +399,10 @@ static const struct of_device_id rcar_gen3_thermal_dt_ids[] = {
                .compatible = "renesas,r8a779a0-thermal",
                .data = &rcar_gen3_ths_tj_1,
        },
+       {
+               .compatible = "renesas,r8a779f0-thermal",
+               .data = &rcar_gen3_ths_tj_1,
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids);
@@ -507,7 +511,7 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
                zone = devm_thermal_zone_of_sensor_register(dev, i, tsc,
                                                            &rcar_gen3_tz_of_ops);
                if (IS_ERR(zone)) {
-                       dev_err(dev, "Can't register thermal zone\n");
+                       dev_err(dev, "Sensor %u: Can't register thermal zone\n", i);
                        ret = PTR_ERR(zone);
                        goto error_unregister;
                }
@@ -529,7 +533,7 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
                if (ret < 0)
                        goto error_unregister;
 
-               dev_info(dev, "TSC%u: Loaded %d trip points\n", i, ret);
+               dev_info(dev, "Sensor %u: Loaded %d trip points\n", i, ret);
        }
 
        if (!priv->num_tscs) {
index be07e04..51ae80e 100644 (file)
@@ -47,7 +47,7 @@
 
 #define TS_CODE_AVE_SCALE(x)   ((x) * 1000000)
 #define MCELSIUS(temp)         ((temp) * MILLIDEGREE_PER_DEGREE)
-#define TS_CODE_CAP_TIMES      8       /* Capture  times */
+#define TS_CODE_CAP_TIMES      8       /* Total number of ADC data samples */
 
 #define RZG2L_THERMAL_GRAN     500     /* milli Celsius */
 #define RZG2L_TSU_SS_TIMEOUT_US        1000
@@ -80,7 +80,8 @@ static int rzg2l_thermal_get_temp(void *devdata, int *temp)
        int val, i;
 
        for (i = 0; i < TS_CODE_CAP_TIMES ; i++) {
-               /* TSU repeats measurement at 20 microseconds intervals and
+               /*
+                * TSU repeats measurement at 20 microseconds intervals and
                 * automatically updates the results of measurement. As per
                 * the HW manual for measuring temperature we need to read 8
                 * values consecutively and then take the average.
@@ -92,16 +93,18 @@ static int rzg2l_thermal_get_temp(void *devdata, int *temp)
 
        ts_code_ave = result / TS_CODE_CAP_TIMES;
 
-       /* Calculate actual sensor value by applying curvature correction formula
+       /*
+        * Calculate actual sensor value by applying curvature correction formula
         * dsensor = ts_code_ave / (1 + ts_code_ave * 0.000013). Here we are doing
         * integer calculation by scaling all the values by 1000000.
         */
        dsensor = TS_CODE_AVE_SCALE(ts_code_ave) /
                (TS_CODE_AVE_SCALE(1) + (ts_code_ave * CURVATURE_CORRECTION_CONST));
 
-       /* The temperature Tj is calculated by the formula
+       /*
+        * The temperature Tj is calculated by the formula
         * Tj = (dsensor − calib1) * 165/ (calib0 − calib1) − 40
-        * where calib0 and calib1 are the caliberation values.
+        * where calib0 and calib1 are the calibration values.
         */
        val = ((dsensor - priv->calib1) * (MCELSIUS(165) /
                (priv->calib0 - priv->calib1))) - MCELSIUS(40);
@@ -122,7 +125,8 @@ static int rzg2l_thermal_init(struct rzg2l_thermal_priv *priv)
        rzg2l_thermal_write(priv, TSU_SM, TSU_SM_NORMAL_MODE);
        rzg2l_thermal_write(priv, TSU_ST, 0);
 
-       /* Before setting the START bit, TSU should be in normal operating
+       /*
+        * Before setting the START bit, TSU should be in normal operating
         * mode. As per the HW manual, it will take 60 µs to place the TSU
         * into normal operating mode.
         */
@@ -217,7 +221,7 @@ static int rzg2l_thermal_probe(struct platform_device *pdev)
        if (ret)
                goto err;
 
-       dev_dbg(dev, "TSU probed with %s caliberation values",
+       dev_dbg(dev, "TSU probed with %s calibration values",
                rzg2l_thermal_read(priv, OTPTSUTRIM_REG(0)) ?  "hw" : "sw");
 
        return 0;
index d9cd23c..212c87e 100644 (file)
@@ -237,7 +237,7 @@ static int sun50i_h6_ths_calibrate(struct ths_device *tmdev,
         * The calibration data on the H6 is the ambient temperature and
         * sensor values that are filled during the factory test stage.
         *
-        * The unit of stored FT temperature is 0.1 degreee celusis.
+        * The unit of stored FT temperature is 0.1 degree celsius.
         *
         * We need to calculate a delta between measured and caluclated
         * register values and this will become a calibration offset.
index 210325f..825eab5 100644 (file)
@@ -633,37 +633,6 @@ static int tegra_thermctl_set_trip_temp(void *data, int trip, int temp)
        return 0;
 }
 
-static int tegra_thermctl_get_trend(void *data, int trip,
-                                   enum thermal_trend *trend)
-{
-       struct tegra_thermctl_zone *zone = data;
-       struct thermal_zone_device *tz = zone->tz;
-       int trip_temp, temp, last_temp, ret;
-
-       if (!tz)
-               return -EINVAL;
-
-       ret = tz->ops->get_trip_temp(zone->tz, trip, &trip_temp);
-       if (ret)
-               return ret;
-
-       temp = READ_ONCE(tz->temperature);
-       last_temp = READ_ONCE(tz->last_temperature);
-
-       if (temp > trip_temp) {
-               if (temp >= last_temp)
-                       *trend = THERMAL_TREND_RAISING;
-               else
-                       *trend = THERMAL_TREND_STABLE;
-       } else if (temp < trip_temp) {
-               *trend = THERMAL_TREND_DROPPING;
-       } else {
-               *trend = THERMAL_TREND_STABLE;
-       }
-
-       return 0;
-}
-
 static void thermal_irq_enable(struct tegra_thermctl_zone *zn)
 {
        u32 r;
@@ -716,7 +685,6 @@ static int tegra_thermctl_set_trips(void *data, int lo, int hi)
 static const struct thermal_zone_of_device_ops tegra_of_thermal_ops = {
        .get_temp = tegra_thermctl_get_temp,
        .set_trip_temp = tegra_thermctl_set_trip_temp,
-       .get_trend = tegra_thermctl_get_trend,
        .set_trips = tegra_thermctl_set_trips,
 };
 
index 9b6b693..0588668 100644 (file)
@@ -316,7 +316,7 @@ static void tegra_tsensor_get_hw_channel_trips(struct thermal_zone_device *tzd,
        *hot_trip  = 85000;
        *crit_trip = 90000;
 
-       for (i = 0; i < tzd->trips; i++) {
+       for (i = 0; i < tzd->num_trips; i++) {
                enum thermal_trip_type type;
                int trip_temp;
 
index cdc0552..6a5d0ae 100644 (file)
@@ -340,12 +340,8 @@ void thermal_zone_device_critical(struct thermal_zone_device *tz)
 EXPORT_SYMBOL(thermal_zone_device_critical);
 
 static void handle_critical_trips(struct thermal_zone_device *tz,
-                                 int trip, enum thermal_trip_type trip_type)
+                                 int trip, int trip_temp, enum thermal_trip_type trip_type)
 {
-       int trip_temp;
-
-       tz->ops->get_trip_temp(tz, trip, &trip_temp);
-
        /* If we have not crossed the trip_temp, we do not care. */
        if (trip_temp <= 0 || tz->temperature < trip_temp)
                return;
@@ -384,7 +380,7 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
        }
 
        if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT)
-               handle_critical_trips(tz, trip, type);
+               handle_critical_trips(tz, trip, trip_temp, type);
        else
                handle_non_critical_trips(tz, trip);
        /*
@@ -505,7 +501,7 @@ void thermal_zone_device_update(struct thermal_zone_device *tz,
 
        tz->notify_event = event;
 
-       for (count = 0; count < tz->trips; count++)
+       for (count = 0; count < tz->num_trips; count++)
                handle_thermal_trip(tz, count);
 }
 EXPORT_SYMBOL_GPL(thermal_zone_device_update);
@@ -630,7 +626,7 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
        unsigned long max_state;
        int result, ret;
 
-       if (trip >= tz->trips || trip < 0)
+       if (trip >= tz->num_trips || trip < 0)
                return -EINVAL;
 
        list_for_each_entry(pos1, &thermal_tz_list, node) {
@@ -667,7 +663,7 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
        dev->target = THERMAL_NO_TARGET;
        dev->weight = weight;
 
-       result = ida_simple_get(&tz->ida, 0, 0, GFP_KERNEL);
+       result = ida_alloc(&tz->ida, GFP_KERNEL);
        if (result < 0)
                goto free_mem;
 
@@ -721,7 +717,7 @@ remove_trip_file:
 remove_symbol_link:
        sysfs_remove_link(&tz->device.kobj, dev->name);
 release_ida:
-       ida_simple_remove(&tz->ida, dev->id);
+       ida_free(&tz->ida, dev->id);
 free_mem:
        kfree(dev);
        return result;
@@ -768,7 +764,7 @@ unbind:
        device_remove_file(&tz->device, &pos->weight_attr);
        device_remove_file(&tz->device, &pos->attr);
        sysfs_remove_link(&tz->device.kobj, pos->name);
-       ida_simple_remove(&tz->ida, pos->id);
+       ida_free(&tz->ida, pos->id);
        kfree(pos);
        return 0;
 }
@@ -811,7 +807,7 @@ static void __bind(struct thermal_zone_device *tz, int mask,
 {
        int i, ret;
 
-       for (i = 0; i < tz->trips; i++) {
+       for (i = 0; i < tz->num_trips; i++) {
                if (mask & (1 << i)) {
                        unsigned long upper, lower;
 
@@ -901,7 +897,7 @@ __thermal_cooling_device_register(struct device_node *np,
        if (!cdev)
                return ERR_PTR(-ENOMEM);
 
-       ret = ida_simple_get(&thermal_cdev_ida, 0, 0, GFP_KERNEL);
+       ret = ida_alloc(&thermal_cdev_ida, GFP_KERNEL);
        if (ret < 0)
                goto out_kfree_cdev;
        cdev->id = ret;
@@ -952,7 +948,7 @@ out_kfree_type:
        put_device(&cdev->device);
        cdev = NULL;
 out_ida_remove:
-       ida_simple_remove(&thermal_cdev_ida, id);
+       ida_free(&thermal_cdev_ida, id);
 out_kfree_cdev:
        kfree(cdev);
        return ERR_PTR(ret);
@@ -1057,7 +1053,7 @@ static void __unbind(struct thermal_zone_device *tz, int mask,
 {
        int i;
 
-       for (i = 0; i < tz->trips; i++)
+       for (i = 0; i < tz->num_trips; i++)
                if (mask & (1 << i))
                        thermal_zone_unbind_cooling_device(tz, i, cdev);
 }
@@ -1111,7 +1107,7 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
 
        mutex_unlock(&thermal_list_lock);
 
-       ida_simple_remove(&thermal_cdev_ida, cdev->id);
+       ida_free(&thermal_cdev_ida, cdev->id);
        device_del(&cdev->device);
        thermal_cooling_device_destroy_sysfs(cdev);
        kfree(cdev->type);
@@ -1159,10 +1155,18 @@ exit:
        mutex_unlock(&thermal_list_lock);
 }
 
+static void thermal_set_delay_jiffies(unsigned long *delay_jiffies, int delay_ms)
+{
+       *delay_jiffies = msecs_to_jiffies(delay_ms);
+       if (delay_ms > 1000)
+               *delay_jiffies = round_jiffies(*delay_jiffies);
+}
+
 /**
- * thermal_zone_device_register() - register a new thermal zone device
+ * thermal_zone_device_register_with_trips() - register a new thermal zone device
  * @type:      the thermal zone device type
- * @trips:     the number of trip points the thermal zone support
+ * @trips:     a pointer to an array of thermal trips
+ * @num_trips: the number of trip points the thermal zone support
  * @mask:      a bit string indicating the writeablility of trip points
  * @devdata:   private device data
  * @ops:       standard thermal zone device callbacks
@@ -1184,10 +1188,10 @@ exit:
  * IS_ERR*() helpers.
  */
 struct thermal_zone_device *
-thermal_zone_device_register(const char *type, int trips, int mask,
-                            void *devdata, struct thermal_zone_device_ops *ops,
-                            struct thermal_zone_params *tzp, int passive_delay,
-                            int polling_delay)
+thermal_zone_device_register_with_trips(const char *type, struct thermal_trip *trips, int num_trips, int mask,
+                                       void *devdata, struct thermal_zone_device_ops *ops,
+                                       struct thermal_zone_params *tzp, int passive_delay,
+                                       int polling_delay)
 {
        struct thermal_zone_device *tz;
        enum thermal_trip_type trip_type;
@@ -1198,27 +1202,27 @@ thermal_zone_device_register(const char *type, int trips, int mask,
        struct thermal_governor *governor;
 
        if (!type || strlen(type) == 0) {
-               pr_err("Error: No thermal zone type defined\n");
+               pr_err("No thermal zone type defined\n");
                return ERR_PTR(-EINVAL);
        }
 
        if (type && strlen(type) >= THERMAL_NAME_LENGTH) {
-               pr_err("Error: Thermal zone name (%s) too long, should be under %d chars\n",
+               pr_err("Thermal zone name (%s) too long, should be under %d chars\n",
                       type, THERMAL_NAME_LENGTH);
                return ERR_PTR(-EINVAL);
        }
 
-       if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips) {
-               pr_err("Error: Incorrect number of thermal trips\n");
+       if (num_trips > THERMAL_MAX_TRIPS || num_trips < 0 || mask >> num_trips) {
+               pr_err("Incorrect number of thermal trips\n");
                return ERR_PTR(-EINVAL);
        }
 
        if (!ops) {
-               pr_err("Error: Thermal zone device ops not defined\n");
+               pr_err("Thermal zone device ops not defined\n");
                return ERR_PTR(-EINVAL);
        }
 
-       if (trips > 0 && (!ops->get_trip_type || !ops->get_trip_temp))
+       if (num_trips > 0 && (!ops->get_trip_type || !ops->get_trip_temp))
                return ERR_PTR(-EINVAL);
 
        tz = kzalloc(sizeof(*tz), GFP_KERNEL);
@@ -1228,7 +1232,7 @@ thermal_zone_device_register(const char *type, int trips, int mask,
        INIT_LIST_HEAD(&tz->thermal_instances);
        ida_init(&tz->ida);
        mutex_init(&tz->lock);
-       id = ida_simple_get(&thermal_tz_ida, 0, 0, GFP_KERNEL);
+       id = ida_alloc(&thermal_tz_ida, GFP_KERNEL);
        if (id < 0) {
                result = id;
                goto free_tz;
@@ -1249,6 +1253,7 @@ thermal_zone_device_register(const char *type, int trips, int mask,
        tz->device.class = &thermal_class;
        tz->devdata = devdata;
        tz->trips = trips;
+       tz->num_trips = num_trips;
 
        thermal_set_delay_jiffies(&tz->passive_delay_jiffies, passive_delay);
        thermal_set_delay_jiffies(&tz->polling_delay_jiffies, polling_delay);
@@ -1266,7 +1271,7 @@ thermal_zone_device_register(const char *type, int trips, int mask,
        if (result)
                goto release_device;
 
-       for (count = 0; count < trips; count++) {
+       for (count = 0; count < num_trips; count++) {
                if (tz->ops->get_trip_type(tz, count, &trip_type) ||
                    tz->ops->get_trip_temp(tz, count, &trip_temp) ||
                    !trip_temp)
@@ -1319,11 +1324,21 @@ release_device:
        put_device(&tz->device);
        tz = NULL;
 remove_id:
-       ida_simple_remove(&thermal_tz_ida, id);
+       ida_free(&thermal_tz_ida, id);
 free_tz:
        kfree(tz);
        return ERR_PTR(result);
 }
+
+struct thermal_zone_device *thermal_zone_device_register(const char *type, int ntrips, int mask,
+                                                        void *devdata, struct thermal_zone_device_ops *ops,
+                                                        struct thermal_zone_params *tzp, int passive_delay,
+                                                        int polling_delay)
+{
+       return thermal_zone_device_register_with_trips(type, NULL, ntrips, mask,
+                                                      devdata, ops, tzp,
+                                                      passive_delay, polling_delay);
+}
 EXPORT_SYMBOL_GPL(thermal_zone_device_register);
 
 /**
@@ -1379,7 +1394,7 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
        thermal_set_governor(tz, NULL);
 
        thermal_remove_hwmon_sysfs(tz);
-       ida_simple_remove(&thermal_tz_ida, tz->id);
+       ida_free(&thermal_tz_ida, tz->id);
        ida_destroy(&tz->ida);
        mutex_destroy(&tz->lock);
        device_unregister(&tz->device);
index 726e327..c991bb2 100644 (file)
@@ -68,20 +68,6 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)
 void thermal_cdev_update(struct thermal_cooling_device *);
 void __thermal_cdev_update(struct thermal_cooling_device *cdev);
 
-/**
- * struct thermal_trip - representation of a point in temperature domain
- * @np: pointer to struct device_node that this trip point was created from
- * @temperature: temperature value in miliCelsius
- * @hysteresis: relative hysteresis in miliCelsius
- * @type: trip point type
- */
-struct thermal_trip {
-       struct device_node *np;
-       int temperature;
-       int hysteresis;
-       enum thermal_trip_type type;
-};
-
 int get_tz_trend(struct thermal_zone_device *tz, int trip);
 
 struct thermal_instance *
@@ -126,7 +112,6 @@ int thermal_build_list_of_policies(char *buf);
 
 /* Helpers */
 void thermal_zone_set_trips(struct thermal_zone_device *tz);
-void thermal_set_delay_jiffies(unsigned long *delay_jiffies, int delay_ms);
 
 /* sysfs I/F */
 int thermal_zone_create_device_groups(struct thermal_zone_device *, int);
index 3edd047..690890f 100644 (file)
@@ -39,7 +39,6 @@ int get_tz_trend(struct thermal_zone_device *tz, int trip)
 
        return trend;
 }
-EXPORT_SYMBOL(get_tz_trend);
 
 struct thermal_instance *
 get_thermal_instance(struct thermal_zone_device *tz,
@@ -90,7 +89,7 @@ int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp)
        ret = tz->ops->get_temp(tz, temp);
 
        if (IS_ENABLED(CONFIG_THERMAL_EMULATION) && tz->emul_temperature) {
-               for (count = 0; count < tz->trips; count++) {
+               for (count = 0; count < tz->num_trips; count++) {
                        ret = tz->ops->get_trip_type(tz, count, &type);
                        if (!ret && type == THERMAL_TRIP_CRITICAL) {
                                ret = tz->ops->get_trip_temp(tz, count,
@@ -138,7 +137,7 @@ void thermal_zone_set_trips(struct thermal_zone_device *tz)
        if (!tz->ops->set_trips || !tz->ops->get_trip_hyst)
                goto exit;
 
-       for (i = 0; i < tz->trips; i++) {
+       for (i = 0; i < tz->num_trips; i++) {
                int trip_low;
 
                tz->ops->get_trip_temp(tz, i, &trip_temp);
@@ -175,13 +174,6 @@ exit:
        mutex_unlock(&tz->lock);
 }
 
-void thermal_set_delay_jiffies(unsigned long *delay_jiffies, int delay_ms)
-{
-       *delay_jiffies = msecs_to_jiffies(delay_ms);
-       if (delay_ms > 1000)
-               *delay_jiffies = round_jiffies(*delay_jiffies);
-}
-
 static void thermal_cdev_set_cur_state(struct thermal_cooling_device *cdev,
                                       int target)
 {
@@ -228,7 +220,6 @@ void thermal_cdev_update(struct thermal_cooling_device *cdev)
        }
        mutex_unlock(&cdev->lock);
 }
-EXPORT_SYMBOL(thermal_cdev_update);
 
 /**
  * thermal_zone_get_slope - return the slope attribute of the thermal zone
index 32fea51..050d243 100644 (file)
@@ -469,7 +469,7 @@ static int thermal_genl_cmd_tz_get_trip(struct param *p)
 
        mutex_lock(&tz->lock);
 
-       for (i = 0; i < tz->trips; i++) {
+       for (i = 0; i < tz->num_trips; i++) {
 
                enum thermal_trip_type type;
                int temp, hyst = 0;
index b65d435..802c30b 100644 (file)
@@ -118,12 +118,7 @@ static int of_thermal_set_trips(struct thermal_zone_device *tz,
  */
 int of_thermal_get_ntrips(struct thermal_zone_device *tz)
 {
-       struct __thermal_zone *data = tz->devdata;
-
-       if (!data || IS_ERR(data))
-               return -ENODEV;
-
-       return data->ntrips;
+       return tz->num_trips;
 }
 EXPORT_SYMBOL_GPL(of_thermal_get_ntrips);
 
@@ -139,9 +134,7 @@ EXPORT_SYMBOL_GPL(of_thermal_get_ntrips);
  */
 bool of_thermal_is_trip_valid(struct thermal_zone_device *tz, int trip)
 {
-       struct __thermal_zone *data = tz->devdata;
-
-       if (!data || trip >= data->ntrips || trip < 0)
+       if (trip >= tz->num_trips || trip < 0)
                return false;
 
        return true;
@@ -161,12 +154,7 @@ EXPORT_SYMBOL_GPL(of_thermal_is_trip_valid);
 const struct thermal_trip *
 of_thermal_get_trip_points(struct thermal_zone_device *tz)
 {
-       struct __thermal_zone *data = tz->devdata;
-
-       if (!data)
-               return NULL;
-
-       return data->trips;
+       return tz->trips;
 }
 EXPORT_SYMBOL_GPL(of_thermal_get_trip_points);
 
@@ -281,12 +269,10 @@ static int of_thermal_unbind(struct thermal_zone_device *thermal,
 static int of_thermal_get_trip_type(struct thermal_zone_device *tz, int trip,
                                    enum thermal_trip_type *type)
 {
-       struct __thermal_zone *data = tz->devdata;
-
-       if (trip >= data->ntrips || trip < 0)
+       if (trip >= tz->num_trips || trip < 0)
                return -EDOM;
 
-       *type = data->trips[trip].type;
+       *type = tz->trips[trip].type;
 
        return 0;
 }
@@ -294,12 +280,10 @@ static int of_thermal_get_trip_type(struct thermal_zone_device *tz, int trip,
 static int of_thermal_get_trip_temp(struct thermal_zone_device *tz, int trip,
                                    int *temp)
 {
-       struct __thermal_zone *data = tz->devdata;
-
-       if (trip >= data->ntrips || trip < 0)
+       if (trip >= tz->num_trips || trip < 0)
                return -EDOM;
 
-       *temp = data->trips[trip].temperature;
+       *temp = tz->trips[trip].temperature;
 
        return 0;
 }
@@ -309,7 +293,7 @@ static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip,
 {
        struct __thermal_zone *data = tz->devdata;
 
-       if (trip >= data->ntrips || trip < 0)
+       if (trip >= tz->num_trips || trip < 0)
                return -EDOM;
 
        if (data->ops && data->ops->set_trip_temp) {
@@ -321,7 +305,7 @@ static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip,
        }
 
        /* thermal framework should take care of data->mask & (1 << trip) */
-       data->trips[trip].temperature = temp;
+       tz->trips[trip].temperature = temp;
 
        return 0;
 }
@@ -329,12 +313,10 @@ static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip,
 static int of_thermal_get_trip_hyst(struct thermal_zone_device *tz, int trip,
                                    int *hyst)
 {
-       struct __thermal_zone *data = tz->devdata;
-
-       if (trip >= data->ntrips || trip < 0)
+       if (trip >= tz->num_trips || trip < 0)
                return -EDOM;
 
-       *hyst = data->trips[trip].hysteresis;
+       *hyst = tz->trips[trip].hysteresis;
 
        return 0;
 }
@@ -342,13 +324,11 @@ static int of_thermal_get_trip_hyst(struct thermal_zone_device *tz, int trip,
 static int of_thermal_set_trip_hyst(struct thermal_zone_device *tz, int trip,
                                    int hyst)
 {
-       struct __thermal_zone *data = tz->devdata;
-
-       if (trip >= data->ntrips || trip < 0)
+       if (trip >= tz->num_trips || trip < 0)
                return -EDOM;
 
        /* thermal framework should take care of data->mask & (1 << trip) */
-       data->trips[trip].hysteresis = hyst;
+       tz->trips[trip].hysteresis = hyst;
 
        return 0;
 }
@@ -356,12 +336,11 @@ static int of_thermal_set_trip_hyst(struct thermal_zone_device *tz, int trip,
 static int of_thermal_get_crit_temp(struct thermal_zone_device *tz,
                                    int *temp)
 {
-       struct __thermal_zone *data = tz->devdata;
        int i;
 
-       for (i = 0; i < data->ntrips; i++)
-               if (data->trips[i].type == THERMAL_TRIP_CRITICAL) {
-                       *temp = data->trips[i].temperature;
+       for (i = 0; i < tz->num_trips; i++)
+               if (tz->trips[i].type == THERMAL_TRIP_CRITICAL) {
+                       *temp = tz->trips[i].temperature;
                        return 0;
                }
 
@@ -671,6 +650,35 @@ EXPORT_SYMBOL_GPL(devm_thermal_zone_of_sensor_unregister);
 
 /***   functions parsing device tree nodes   ***/
 
+static int of_find_trip_id(struct device_node *np, struct device_node *trip)
+{
+       struct device_node *trips;
+       struct device_node *t;
+       int i = 0;
+
+       trips = of_get_child_by_name(np, "trips");
+       if (!trips) {
+               pr_err("Failed to find 'trips' node\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Find the trip id point associated with the cooling device map
+        */
+       for_each_child_of_node(trips, t) {
+
+               if (t == trip)
+                       goto out;
+               i++;
+       }
+
+       i = -ENXIO;
+out:
+       of_node_put(trips);
+
+       return i;
+}
+
 /**
  * thermal_of_populate_bind_params - parse and fill cooling map data
  * @np: DT node containing a cooling-map node
@@ -685,15 +693,15 @@ EXPORT_SYMBOL_GPL(devm_thermal_zone_of_sensor_unregister);
  *
  * Return: 0 on success, proper error code otherwise
  */
-static int thermal_of_populate_bind_params(struct device_node *np,
-                                          struct __thermal_bind_params *__tbp,
-                                          struct thermal_trip *trips,
-                                          int ntrips)
+static int thermal_of_populate_bind_params(struct device_node *tz_np,
+                                          struct device_node *np,
+                                          struct __thermal_bind_params *__tbp)
 {
        struct of_phandle_args cooling_spec;
        struct __thermal_cooling_bind_param *__tcbp;
        struct device_node *trip;
        int ret, i, count;
+       int trip_id;
        u32 prop;
 
        /* Default weight. Usage is optional */
@@ -708,18 +716,14 @@ static int thermal_of_populate_bind_params(struct device_node *np,
                return -ENODEV;
        }
 
-       /* match using device_node */
-       for (i = 0; i < ntrips; i++)
-               if (trip == trips[i].np) {
-                       __tbp->trip_id = i;
-                       break;
-               }
-
-       if (i == ntrips) {
-               ret = -ENODEV;
+       trip_id = of_find_trip_id(tz_np, trip);
+       if (trip_id < 0) {
+               ret = trip_id;
                goto end;
        }
 
+       __tbp->trip_id = trip_id;
+
        count = of_count_phandle_with_args(np, "cooling-device",
                                           "#cooling-cells");
        if (count <= 0) {
@@ -843,13 +847,56 @@ static int thermal_of_populate_trip(struct device_node *np,
                return ret;
        }
 
-       /* Required for cooling map matching */
-       trip->np = np;
-       of_node_get(np);
-
        return 0;
 }
 
+static struct thermal_trip *thermal_of_trips_init(struct device_node *np, int *ntrips)
+{
+       struct thermal_trip *tt;
+       struct device_node *trips, *trip;
+       int ret, count;
+
+       trips = of_get_child_by_name(np, "trips");
+       if (!trips) {
+               pr_err("Failed to find 'trips' node\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       count = of_get_child_count(trips);
+       if (!count) {
+               pr_err("No trip point defined\n");
+               ret = -EINVAL;
+               goto out_of_node_put;
+       }
+
+       tt = kzalloc(sizeof(*tt) * count, GFP_KERNEL);
+       if (!tt) {
+               ret = -ENOMEM;
+               goto out_of_node_put;
+       }
+
+       *ntrips = count;
+
+       count = 0;
+       for_each_child_of_node(trips, trip) {
+               ret = thermal_of_populate_trip(trip, &tt[count++]);
+               if (ret)
+                       goto out_kfree;
+       }
+
+       of_node_put(trips);
+
+       return tt;
+
+out_kfree:
+       kfree(tt);
+       *ntrips = 0;
+out_of_node_put:
+       of_node_put(trips);
+
+       return ERR_PTR(ret);
+}
+
 /**
  * thermal_of_build_thermal_zone - parse and fill one thermal zone data
  * @np: DT node containing a thermal zone node
@@ -909,32 +956,12 @@ __init *thermal_of_build_thermal_zone(struct device_node *np)
                tz->offset = 0;
        }
 
-       /* trips */
-       child = of_get_child_by_name(np, "trips");
-
-       /* No trips provided */
-       if (!child)
+       tz->trips = thermal_of_trips_init(np, &tz->ntrips);
+       if (IS_ERR(tz->trips)) {
+               ret = PTR_ERR(tz->trips);
                goto finish;
-
-       tz->ntrips = of_get_child_count(child);
-       if (tz->ntrips == 0) /* must have at least one child */
-               goto finish;
-
-       tz->trips = kcalloc(tz->ntrips, sizeof(*tz->trips), GFP_KERNEL);
-       if (!tz->trips) {
-               ret = -ENOMEM;
-               goto free_tz;
        }
 
-       i = 0;
-       for_each_child_of_node(child, gchild) {
-               ret = thermal_of_populate_trip(gchild, &tz->trips[i++]);
-               if (ret)
-                       goto free_trips;
-       }
-
-       of_node_put(child);
-
        /* cooling-maps */
        child = of_get_child_by_name(np, "cooling-maps");
 
@@ -954,10 +981,11 @@ __init *thermal_of_build_thermal_zone(struct device_node *np)
 
        i = 0;
        for_each_child_of_node(child, gchild) {
-               ret = thermal_of_populate_bind_params(gchild, &tz->tbps[i++],
-                                                     tz->trips, tz->ntrips);
-               if (ret)
+               ret = thermal_of_populate_bind_params(np, gchild, &tz->tbps[i++]);
+               if (ret) {
+                       of_node_put(gchild);
                        goto free_tbps;
+               }
        }
 
 finish:
@@ -978,10 +1006,7 @@ free_tbps:
 
        kfree(tz->tbps);
 free_trips:
-       for (i = 0; i < tz->ntrips; i++)
-               of_node_put(tz->trips[i].np);
        kfree(tz->trips);
-       of_node_put(gchild);
 free_tz:
        kfree(tz);
        of_node_put(child);
@@ -1004,8 +1029,6 @@ static __init void of_thermal_free_zone(struct __thermal_zone *tz)
        }
 
        kfree(tz->tbps);
-       for (i = 0; i < tz->ntrips; i++)
-               of_node_put(tz->trips[i].np);
        kfree(tz->trips);
        kfree(tz);
 }
@@ -1103,11 +1126,9 @@ int __init of_parse_thermal_zones(void)
                tzp->slope = tz->slope;
                tzp->offset = tz->offset;
 
-               zone = thermal_zone_device_register(child->name, tz->ntrips,
-                                                   mask, tz,
-                                                   ops, tzp,
-                                                   tz->passive_delay,
-                                                   tz->polling_delay);
+               zone = thermal_zone_device_register_with_trips(child->name, tz->trips, tz->ntrips,
+                                                              mask, tz, ops, tzp, tz->passive_delay,
+                                                              tz->polling_delay);
                if (IS_ERR(zone)) {
                        pr_err("Failed to build %pOFn zone %ld\n", child,
                               PTR_ERR(zone));
index 1c4aac8..5018459 100644 (file)
@@ -416,15 +416,15 @@ static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
        int indx;
 
        /* This function works only for zones with at least one trip */
-       if (tz->trips <= 0)
+       if (tz->num_trips <= 0)
                return -EINVAL;
 
-       tz->trip_type_attrs = kcalloc(tz->trips, sizeof(*tz->trip_type_attrs),
+       tz->trip_type_attrs = kcalloc(tz->num_trips, sizeof(*tz->trip_type_attrs),
                                      GFP_KERNEL);
        if (!tz->trip_type_attrs)
                return -ENOMEM;
 
-       tz->trip_temp_attrs = kcalloc(tz->trips, sizeof(*tz->trip_temp_attrs),
+       tz->trip_temp_attrs = kcalloc(tz->num_trips, sizeof(*tz->trip_temp_attrs),
                                      GFP_KERNEL);
        if (!tz->trip_temp_attrs) {
                kfree(tz->trip_type_attrs);
@@ -432,7 +432,7 @@ static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
        }
 
        if (tz->ops->get_trip_hyst) {
-               tz->trip_hyst_attrs = kcalloc(tz->trips,
+               tz->trip_hyst_attrs = kcalloc(tz->num_trips,
                                              sizeof(*tz->trip_hyst_attrs),
                                              GFP_KERNEL);
                if (!tz->trip_hyst_attrs) {
@@ -442,7 +442,7 @@ static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
                }
        }
 
-       attrs = kcalloc(tz->trips * 3 + 1, sizeof(*attrs), GFP_KERNEL);
+       attrs = kcalloc(tz->num_trips * 3 + 1, sizeof(*attrs), GFP_KERNEL);
        if (!attrs) {
                kfree(tz->trip_type_attrs);
                kfree(tz->trip_temp_attrs);
@@ -451,7 +451,7 @@ static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
                return -ENOMEM;
        }
 
-       for (indx = 0; indx < tz->trips; indx++) {
+       for (indx = 0; indx < tz->num_trips; indx++) {
                /* create trip type attribute */
                snprintf(tz->trip_type_attrs[indx].name, THERMAL_NAME_LENGTH,
                         "trip_point_%d_type", indx);
@@ -478,7 +478,7 @@ static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
                        tz->trip_temp_attrs[indx].attr.store =
                                                        trip_point_temp_store;
                }
-               attrs[indx + tz->trips] = &tz->trip_temp_attrs[indx].attr.attr;
+               attrs[indx + tz->num_trips] = &tz->trip_temp_attrs[indx].attr.attr;
 
                /* create Optional trip hyst attribute */
                if (!tz->ops->get_trip_hyst)
@@ -496,10 +496,10 @@ static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
                        tz->trip_hyst_attrs[indx].attr.store =
                                        trip_point_hyst_store;
                }
-               attrs[indx + tz->trips * 2] =
+               attrs[indx + tz->num_trips * 2] =
                                        &tz->trip_hyst_attrs[indx].attr.attr;
        }
-       attrs[tz->trips * 3] = NULL;
+       attrs[tz->num_trips * 3] = NULL;
 
        tz->trips_attribute_group.attrs = attrs;
 
@@ -540,7 +540,7 @@ int thermal_zone_create_device_groups(struct thermal_zone_device *tz,
        for (i = 0; i < size - 2; i++)
                groups[i] = thermal_zone_attribute_groups[i];
 
-       if (tz->trips) {
+       if (tz->num_trips) {
                result = create_trip_attrs(tz, mask);
                if (result) {
                        kfree(groups);
@@ -561,7 +561,7 @@ void thermal_zone_destroy_device_groups(struct thermal_zone_device *tz)
        if (!tz)
                return;
 
-       if (tz->trips)
+       if (tz->num_trips)
                destroy_trip_attrs(tz);
 
        kfree(tz->device.groups);
index ea0603b..67050a1 100644 (file)
@@ -226,7 +226,7 @@ static irqreturn_t ti_bandgap_talert_irq_handler(int irq, void *data)
                /*
                 * One TALERT interrupt: Two sources
                 * If the interrupt is due to t_hot then mask t_hot and
-                * and unmask t_cold else mask t_cold and unmask t_hot
+                * unmask t_cold else mask t_cold and unmask t_hot
                 */
                if (t_hot) {
                        ctrl &= ~tsr->mask_hot_mask;
index 4bfec8a..e76a6c1 100644 (file)
@@ -28,8 +28,10 @@ config USB4_DEBUGFS_WRITE
          this for production systems or distro kernels.
 
 config USB4_KUNIT_TEST
-       bool "KUnit tests"
-       depends on KUNIT=y
+       bool "KUnit tests" if !KUNIT_ALL_TESTS
+       depends on (USB4=m || KUNIT=y)
+       depends on KUNIT
+       default KUNIT_ALL_TESTS
 
 config USB4_DMA_TEST
        tristate "DMA traffic test driver"
index c89daac..b1f0dc8 100644 (file)
@@ -301,37 +301,22 @@ static bool tb_acpi_bus_match(struct device *dev)
        return tb_is_switch(dev) || tb_is_usb4_port_device(dev);
 }
 
-static struct acpi_device *tb_acpi_find_port(struct acpi_device *adev,
-                                            const struct tb_port *port)
+static struct acpi_device *tb_acpi_switch_find_companion(struct tb_switch *sw)
 {
-       struct acpi_device *port_adev;
-
-       if (!adev)
-               return NULL;
+       struct acpi_device *adev = NULL;
+       struct tb_switch *parent_sw;
 
        /*
         * Device routers exists under the downstream facing USB4 port
         * of the parent router. Their _ADR is always 0.
         */
-       list_for_each_entry(port_adev, &adev->children, node) {
-               if (acpi_device_adr(port_adev) == port->port)
-                       return port_adev;
-       }
-
-       return NULL;
-}
-
-static struct acpi_device *tb_acpi_switch_find_companion(struct tb_switch *sw)
-{
-       struct acpi_device *adev = NULL;
-       struct tb_switch *parent_sw;
-
        parent_sw = tb_switch_parent(sw);
        if (parent_sw) {
                struct tb_port *port = tb_port_at(tb_route(sw), parent_sw);
                struct acpi_device *port_adev;
 
-               port_adev = tb_acpi_find_port(ACPI_COMPANION(&parent_sw->dev), port);
+               port_adev = acpi_find_child_by_adr(ACPI_COMPANION(&parent_sw->dev),
+                                                  port->port);
                if (port_adev)
                        adev = acpi_find_child_device(port_adev, 0, false);
        } else {
@@ -364,8 +349,8 @@ static struct acpi_device *tb_acpi_find_companion(struct device *dev)
        if (tb_is_switch(dev))
                return tb_acpi_switch_find_companion(tb_to_switch(dev));
        else if (tb_is_usb4_port_device(dev))
-               return tb_acpi_find_port(ACPI_COMPANION(dev->parent),
-                                        tb_to_usb4_port_device(dev)->port);
+               return acpi_find_child_by_adr(ACPI_COMPANION(dev->parent),
+                                             tb_to_usb4_port_device(dev)->port->port);
        return NULL;
 }
 
index 2889a21..99211f3 100644 (file)
@@ -872,7 +872,6 @@ int tb_domain_init(void)
 {
        int ret;
 
-       tb_test_init();
        tb_debugfs_init();
        tb_acpi_init();
 
@@ -890,7 +889,6 @@ err_xdomain:
 err_acpi:
        tb_acpi_exit();
        tb_debugfs_exit();
-       tb_test_exit();
 
        return ret;
 }
@@ -903,5 +901,4 @@ void tb_domain_exit(void)
        tb_xdomain_exit();
        tb_acpi_exit();
        tb_debugfs_exit();
-       tb_test_exit();
 }
index 4602c69..a831faa 100644 (file)
@@ -1271,12 +1271,4 @@ static inline void tb_service_debugfs_init(struct tb_service *svc) { }
 static inline void tb_service_debugfs_remove(struct tb_service *svc) { }
 #endif
 
-#ifdef CONFIG_USB4_KUNIT_TEST
-int tb_test_init(void);
-void tb_test_exit(void);
-#else
-static inline int tb_test_init(void) { return 0; }
-static inline void tb_test_exit(void) { }
-#endif
-
 #endif
index ee37f8b..24c06e7 100644 (file)
@@ -2817,14 +2817,4 @@ static struct kunit_suite tb_test_suite = {
        .test_cases = tb_test_cases,
 };
 
-static struct kunit_suite *tb_test_suites[] = { &tb_test_suite, NULL };
-
-int tb_test_init(void)
-{
-       return __kunit_test_suites_init(tb_test_suites);
-}
-
-void tb_test_exit(void)
-{
-       return __kunit_test_suites_exit(tb_test_suites);
-}
+kunit_test_suite(tb_test_suite);
index 74bfabe..752dab3 100644 (file)
@@ -111,21 +111,11 @@ static void pty_unthrottle(struct tty_struct *tty)
 static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c)
 {
        struct tty_struct *to = tty->link;
-       unsigned long flags;
 
-       if (tty->flow.stopped)
+       if (tty->flow.stopped || !c)
                return 0;
 
-       if (c > 0) {
-               spin_lock_irqsave(&to->port->lock, flags);
-               /* Stuff the data into the input queue of the other end */
-               c = tty_insert_flip_string(to->port, buf, c);
-               spin_unlock_irqrestore(&to->port->lock, flags);
-               /* And shovel */
-               if (c)
-                       tty_flip_buffer_push(to->port);
-       }
-       return c;
+       return tty_insert_flip_string_and_push_buffer(to->port, buf, c);
 }
 
 /**
index cfbd2de..3f56dbc 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/sysrq.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/tty.h>
 #include <linux/ratelimit.h>
 #include <linux/tty_flip.h>
@@ -559,6 +560,9 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
 
                up->port.dev = dev;
 
+               if (uart_console_enabled(&up->port))
+                       pm_runtime_get_sync(up->port.dev);
+
                serial8250_apply_quirks(up);
                uart_add_one_port(drv, &up->port);
        }
index 7133fce..a8dba4a 100644 (file)
@@ -106,10 +106,10 @@ int serial8250_tx_dma(struct uart_8250_port *p)
                                   UART_XMIT_SIZE, DMA_TO_DEVICE);
 
        dma_async_issue_pending(dma->txchan);
-       if (dma->tx_err) {
+       serial8250_clear_THRI(p);
+       if (dma->tx_err)
                dma->tx_err = 0;
-               serial8250_clear_THRI(p);
-       }
+
        return 0;
 err:
        dma->tx_err = 1;
index f57bbd3..bb6aca0 100644 (file)
@@ -47,7 +47,7 @@
 #define RZN1_UART_xDMACR_DMA_EN                BIT(0)
 #define RZN1_UART_xDMACR_1_WORD_BURST  (0 << 1)
 #define RZN1_UART_xDMACR_4_WORD_BURST  (1 << 1)
-#define RZN1_UART_xDMACR_8_WORD_BURST  (3 << 1)
+#define RZN1_UART_xDMACR_8_WORD_BURST  (2 << 1)
 #define RZN1_UART_xDMACR_BLK_SZ(x)     ((x) << 3)
 
 /* Quirks */
@@ -773,18 +773,18 @@ static const struct of_device_id dw8250_of_match[] = {
 MODULE_DEVICE_TABLE(of, dw8250_of_match);
 
 static const struct acpi_device_id dw8250_acpi_match[] = {
-       { "INT33C4", 0 },
-       { "INT33C5", 0 },
-       { "INT3434", 0 },
-       { "INT3435", 0 },
-       { "80860F0A", 0 },
-       { "8086228A", 0 },
-       { "APMC0D08", 0},
-       { "AMD0020", 0 },
-       { "AMDI0020", 0 },
-       { "AMDI0022", 0 },
-       { "BRCM2032", 0 },
-       { "HISI0031", 0 },
+       { "80860F0A", (kernel_ulong_t)&dw8250_dw_apb },
+       { "8086228A", (kernel_ulong_t)&dw8250_dw_apb },
+       { "AMD0020", (kernel_ulong_t)&dw8250_dw_apb },
+       { "AMDI0020", (kernel_ulong_t)&dw8250_dw_apb },
+       { "AMDI0022", (kernel_ulong_t)&dw8250_dw_apb },
+       { "APMC0D08", (kernel_ulong_t)&dw8250_dw_apb},
+       { "BRCM2032", (kernel_ulong_t)&dw8250_dw_apb },
+       { "HISI0031", (kernel_ulong_t)&dw8250_dw_apb },
+       { "INT33C4", (kernel_ulong_t)&dw8250_dw_apb },
+       { "INT33C5", (kernel_ulong_t)&dw8250_dw_apb },
+       { "INT3434", (kernel_ulong_t)&dw8250_dw_apb },
+       { "INT3435", (kernel_ulong_t)&dw8250_dw_apb },
        { },
 };
 MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
index 8f32fe9..3c36a06 100644 (file)
@@ -1949,7 +1949,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
        if ((status & UART_LSR_THRE) && (up->ier & UART_IER_THRI)) {
                if (!up->dma || up->dma->tx_err)
                        serial8250_tx_chars(up);
-               else
+               else if (!up->dma->tx_running)
                        __stop_tx(up);
        }
 
@@ -2975,8 +2975,10 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
        case UPIO_MEM32BE:
        case UPIO_MEM16:
        case UPIO_MEM:
-               if (!port->mapbase)
+               if (!port->mapbase) {
+                       ret = -EINVAL;
                        break;
+               }
 
                if (!request_mem_region(port->mapbase, size, "serial")) {
                        ret = -EBUSY;
index a452748..7172cd1 100644 (file)
@@ -1099,8 +1099,8 @@ config SERIAL_TIMBERDALE
 config SERIAL_BCM63XX
        tristate "Broadcom BCM63xx/BCM33xx UART support"
        select SERIAL_CORE
-       depends on ARCH_BCM4908 || ARCH_BCM_63XX || BCM63XX || BMIPS_GENERIC || COMPILE_TEST
-       default ARCH_BCM4908 || ARCH_BCM_63XX || BCM63XX || BMIPS_GENERIC
+       depends on ARCH_BCM4908 || ARCH_BCMBCA || BCM63XX || BMIPS_GENERIC || COMPILE_TEST
+       default ARCH_BCM4908 || ARCH_BCMBCA || BCM63XX || BMIPS_GENERIC
        help
          This enables the driver for the onchip UART core found on
          the following chipsets:
index 97ef41c..16a2142 100644 (file)
@@ -1367,6 +1367,15 @@ static void pl011_stop_rx(struct uart_port *port)
        pl011_dma_rx_stop(uap);
 }
 
+static void pl011_throttle_rx(struct uart_port *port)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       pl011_stop_rx(port);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
 static void pl011_enable_ms(struct uart_port *port)
 {
        struct uart_amba_port *uap =
@@ -1788,9 +1797,10 @@ static int pl011_allocate_irq(struct uart_amba_port *uap)
  */
 static void pl011_enable_interrupts(struct uart_amba_port *uap)
 {
+       unsigned long flags;
        unsigned int i;
 
-       spin_lock_irq(&uap->port.lock);
+       spin_lock_irqsave(&uap->port.lock, flags);
 
        /* Clear out any spuriously appearing RX interrupts */
        pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR);
@@ -1812,7 +1822,14 @@ static void pl011_enable_interrupts(struct uart_amba_port *uap)
        if (!pl011_dma_rx_running(uap))
                uap->im |= UART011_RXIM;
        pl011_write(uap->im, uap, REG_IMSC);
-       spin_unlock_irq(&uap->port.lock);
+       spin_unlock_irqrestore(&uap->port.lock, flags);
+}
+
+static void pl011_unthrottle_rx(struct uart_port *port)
+{
+       struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port);
+
+       pl011_enable_interrupts(uap);
 }
 
 static int pl011_startup(struct uart_port *port)
@@ -2225,6 +2242,8 @@ static const struct uart_ops amba_pl011_pops = {
        .stop_tx        = pl011_stop_tx,
        .start_tx       = pl011_start_tx,
        .stop_rx        = pl011_stop_rx,
+       .throttle       = pl011_throttle_rx,
+       .unthrottle     = pl011_unthrottle_rx,
        .enable_ms      = pl011_enable_ms,
        .break_ctl      = pl011_break_ctl,
        .startup        = pl011_startup,
index 0429c2a..93489fe 100644 (file)
@@ -470,14 +470,14 @@ static void mvebu_uart_shutdown(struct uart_port *port)
        }
 }
 
-static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
+static unsigned int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
 {
        unsigned int d_divisor, m_divisor;
        unsigned long flags;
        u32 brdv, osamp;
 
        if (!port->uartclk)
-               return -EOPNOTSUPP;
+               return 0;
 
        /*
         * The baudrate is derived from the UART clock thanks to divisors:
@@ -548,7 +548,7 @@ static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
                        (m_divisor << 16) | (m_divisor << 24);
        writel(osamp, port->membase + UART_OSAMP);
 
-       return 0;
+       return DIV_ROUND_CLOSEST(port->uartclk, d_divisor * m_divisor);
 }
 
 static void mvebu_uart_set_termios(struct uart_port *port,
@@ -587,15 +587,11 @@ static void mvebu_uart_set_termios(struct uart_port *port,
        max_baud = port->uartclk / 80;
 
        baud = uart_get_baud_rate(port, termios, old, min_baud, max_baud);
-       if (mvebu_uart_baud_rate_set(port, baud)) {
-               /* No clock available, baudrate cannot be changed */
-               if (old)
-                       baud = uart_get_baud_rate(port, old, NULL,
-                                                 min_baud, max_baud);
-       } else {
-               tty_termios_encode_baud_rate(termios, baud, baud);
-               uart_update_timeout(port, termios->c_cflag, baud);
-       }
+       baud = mvebu_uart_baud_rate_set(port, baud);
+
+       /* In case baudrate cannot be changed, report previous old value */
+       if (baud == 0 && old)
+               baud = tty_termios_baud_rate(old);
 
        /* Only the following flag changes are supported */
        if (old) {
@@ -606,6 +602,11 @@ static void mvebu_uart_set_termios(struct uart_port *port,
                termios->c_cflag |= CS8;
        }
 
+       if (baud != 0) {
+               tty_termios_encode_baud_rate(termios, baud, baud);
+               uart_update_timeout(port, termios->c_cflag, baud);
+       }
+
        spin_unlock_irqrestore(&port->lock, flags);
 }
 
index d5ca904..1afe47b 100644 (file)
@@ -377,8 +377,7 @@ static void enable_tx_dma(struct s3c24xx_uart_port *ourport)
        /* Enable tx dma mode */
        ucon = rd_regl(port, S3C2410_UCON);
        ucon &= ~(S3C64XX_UCON_TXBURST_MASK | S3C64XX_UCON_TXMODE_MASK);
-       ucon |= (dma_get_cache_alignment() >= 16) ?
-               S3C64XX_UCON_TXBURST_16 : S3C64XX_UCON_TXBURST_1;
+       ucon |= S3C64XX_UCON_TXBURST_1;
        ucon |= S3C64XX_UCON_TXMODE_DMA;
        wr_regl(port,  S3C2410_UCON, ucon);
 
@@ -674,7 +673,7 @@ static void enable_rx_dma(struct s3c24xx_uart_port *ourport)
                        S3C64XX_UCON_DMASUS_EN |
                        S3C64XX_UCON_TIMEOUT_EN |
                        S3C64XX_UCON_RXMODE_MASK);
-       ucon |= S3C64XX_UCON_RXBURST_16 |
+       ucon |= S3C64XX_UCON_RXBURST_1 |
                        0xf << S3C64XX_UCON_TIMEOUT_SHIFT |
                        S3C64XX_UCON_EMPTYINT_EN |
                        S3C64XX_UCON_TIMEOUT_EN |
index 338ebad..3dc926d 100644 (file)
@@ -1941,11 +1941,6 @@ static int uart_proc_show(struct seq_file *m, void *v)
 }
 #endif
 
-static inline bool uart_console_enabled(struct uart_port *port)
-{
-       return uart_console(port) && (port->cons->flags & CON_ENABLED);
-}
-
 static void uart_port_spin_lock_init(struct uart_port *port)
 {
        spin_lock_init(&port->lock);
index b7b44f4..0973b03 100644 (file)
@@ -72,6 +72,8 @@ static void stm32_usart_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE,
        *cr3 |= USART_CR3_DEM;
        over8 = *cr1 & USART_CR1_OVER8;
 
+       *cr1 &= ~(USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK);
+
        if (over8)
                rs485_deat_dedt = delay_ADE * baud * 8;
        else
index b710c5e..f310a82 100644 (file)
@@ -111,4 +111,7 @@ static inline void tty_audit_tiocsti(struct tty_struct *tty, char ch)
 
 ssize_t redirected_tty_write(struct kiocb *, struct iov_iter *);
 
+int tty_insert_flip_string_and_push_buffer(struct tty_port *port,
+               const unsigned char *chars, size_t cnt);
+
 #endif
index bfa431a..595d8b4 100644 (file)
@@ -532,6 +532,15 @@ static void flush_to_ldisc(struct work_struct *work)
 
 }
 
+static inline void tty_flip_buffer_commit(struct tty_buffer *tail)
+{
+       /*
+        * Paired w/ acquire in flush_to_ldisc(); ensures flush_to_ldisc() sees
+        * buffer data.
+        */
+       smp_store_release(&tail->commit, tail->used);
+}
+
 /**
  * tty_flip_buffer_push                -       push terminal buffers
  * @port: tty port to push
@@ -546,16 +555,43 @@ void tty_flip_buffer_push(struct tty_port *port)
 {
        struct tty_bufhead *buf = &port->buf;
 
-       /*
-        * Paired w/ acquire in flush_to_ldisc(); ensures flush_to_ldisc() sees
-        * buffer data.
-        */
-       smp_store_release(&buf->tail->commit, buf->tail->used);
+       tty_flip_buffer_commit(buf->tail);
        queue_work(system_unbound_wq, &buf->work);
 }
 EXPORT_SYMBOL(tty_flip_buffer_push);
 
 /**
+ * tty_insert_flip_string_and_push_buffer - add characters to the tty buffer and
+ *     push
+ * @port: tty port
+ * @chars: characters
+ * @size: size
+ *
+ * The function combines tty_insert_flip_string() and tty_flip_buffer_push()
+ * with the exception of properly holding the @port->lock.
+ *
+ * To be used only internally (by pty currently).
+ *
+ * Returns: the number added.
+ */
+int tty_insert_flip_string_and_push_buffer(struct tty_port *port,
+               const unsigned char *chars, size_t size)
+{
+       struct tty_bufhead *buf = &port->buf;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       size = tty_insert_flip_string(port, chars, size);
+       if (size)
+               tty_flip_buffer_commit(buf->tail);
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       queue_work(system_unbound_wq, &buf->work);
+
+       return size;
+}
+
+/**
  * tty_buffer_init             -       prepare a tty buffer structure
  * @port: tty port to initialise
  *
index f8c87c4..dfc1f4b 100644 (file)
@@ -855,7 +855,7 @@ static void delete_char(struct vc_data *vc, unsigned int nr)
        unsigned short *p = (unsigned short *) vc->vc_pos;
 
        vc_uniscr_delete(vc, nr);
-       scr_memcpyw(p, p + nr, (vc->vc_cols - vc->state.x - nr) * 2);
+       scr_memmovew(p, p + nr, (vc->vc_cols - vc->state.x - nr) * 2);
        scr_memsetw(p + vc->vc_cols - vc->state.x - nr, vc->vc_video_erase_char,
                        nr * 2);
        vc->vc_need_wrap = 0;
index ce86d1b..2b40174 100644 (file)
@@ -2953,37 +2953,59 @@ ufshcd_dev_cmd_completion(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
 static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba,
                struct ufshcd_lrb *lrbp, int max_timeout)
 {
-       int err = 0;
-       unsigned long time_left;
+       unsigned long time_left = msecs_to_jiffies(max_timeout);
        unsigned long flags;
+       bool pending;
+       int err;
 
+retry:
        time_left = wait_for_completion_timeout(hba->dev_cmd.complete,
-                       msecs_to_jiffies(max_timeout));
+                                               time_left);
 
-       spin_lock_irqsave(hba->host->host_lock, flags);
-       hba->dev_cmd.complete = NULL;
        if (likely(time_left)) {
+               /*
+                * The completion handler called complete() and the caller of
+                * this function still owns the @lrbp tag so the code below does
+                * not trigger any race conditions.
+                */
+               hba->dev_cmd.complete = NULL;
                err = ufshcd_get_tr_ocs(lrbp);
                if (!err)
                        err = ufshcd_dev_cmd_completion(hba, lrbp);
-       }
-       spin_unlock_irqrestore(hba->host->host_lock, flags);
-
-       if (!time_left) {
+       } else {
                err = -ETIMEDOUT;
                dev_dbg(hba->dev, "%s: dev_cmd request timedout, tag %d\n",
                        __func__, lrbp->task_tag);
-               if (!ufshcd_clear_cmds(hba, 1U << lrbp->task_tag))
+               if (ufshcd_clear_cmds(hba, 1U << lrbp->task_tag) == 0) {
                        /* successfully cleared the command, retry if needed */
                        err = -EAGAIN;
-               /*
-                * in case of an error, after clearing the doorbell,
-                * we also need to clear the outstanding_request
-                * field in hba
-                */
-               spin_lock_irqsave(&hba->outstanding_lock, flags);
-               __clear_bit(lrbp->task_tag, &hba->outstanding_reqs);
-               spin_unlock_irqrestore(&hba->outstanding_lock, flags);
+                       /*
+                        * Since clearing the command succeeded we also need to
+                        * clear the task tag bit from the outstanding_reqs
+                        * variable.
+                        */
+                       spin_lock_irqsave(&hba->outstanding_lock, flags);
+                       pending = test_bit(lrbp->task_tag,
+                                          &hba->outstanding_reqs);
+                       if (pending) {
+                               hba->dev_cmd.complete = NULL;
+                               __clear_bit(lrbp->task_tag,
+                                           &hba->outstanding_reqs);
+                       }
+                       spin_unlock_irqrestore(&hba->outstanding_lock, flags);
+
+                       if (!pending) {
+                               /*
+                                * The completion handler ran while we tried to
+                                * clear the command.
+                                */
+                               time_left = 1;
+                               goto retry;
+                       }
+               } else {
+                       dev_err(hba->dev, "%s: failed to clear tag %d\n",
+                               __func__, lrbp->task_tag);
+               }
        }
 
        return err;
@@ -5738,7 +5760,7 @@ int ufshcd_wb_toggle(struct ufs_hba *hba, bool enable)
        }
 
        hba->dev_info.wb_enabled = enable;
-       dev_info(hba->dev, "%s Write Booster %s\n",
+       dev_dbg(hba->dev, "%s Write Booster %s\n",
                        __func__, enable ? "enabled" : "disabled");
 
        return ret;
@@ -7253,7 +7275,7 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba)
        hba->silence_err_logs = false;
 
        /* scale up clocks to max frequency before full reinitialization */
-       ufshcd_set_clk_freq(hba, true);
+       ufshcd_scale_clks(hba, true);
 
        err = ufshcd_hba_enable(hba);
 
@@ -9487,7 +9509,7 @@ void ufshcd_remove(struct ufs_hba *hba)
        ufs_bsg_remove(hba);
        ufshpb_remove(hba);
        ufs_sysfs_remove_nodes(hba->dev);
-       blk_cleanup_queue(hba->tmf_queue);
+       blk_mq_destroy_queue(hba->tmf_queue);
        blk_mq_free_tag_set(&hba->tmf_tag_set);
        scsi_remove_host(hba->host);
        /* disable interrupts */
@@ -9783,7 +9805,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
        return 0;
 
 free_tmf_queue:
-       blk_cleanup_queue(hba->tmf_queue);
+       blk_mq_destroy_queue(hba->tmf_queue);
 free_tmf_tag_set:
        blk_mq_free_tag_set(&hba->tmf_tag_set);
 out_remove_scsi_host:
index de2bb84..a1a7a11 100644 (file)
@@ -433,9 +433,8 @@ int ufshpb_prep(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
        return 0;
 }
 
-static struct ufshpb_req *ufshpb_get_req(struct ufshpb_lu *hpb,
-                                        int rgn_idx, enum req_opf dir,
-                                        bool atomic)
+static struct ufshpb_req *ufshpb_get_req(struct ufshpb_lu *hpb, int rgn_idx,
+                                        enum req_op op, bool atomic)
 {
        struct ufshpb_req *rq;
        struct request *req;
@@ -446,7 +445,7 @@ static struct ufshpb_req *ufshpb_get_req(struct ufshpb_lu *hpb,
                return NULL;
 
 retry:
-       req = blk_mq_alloc_request(hpb->sdev_ufs_lu->request_queue, dir,
+       req = blk_mq_alloc_request(hpb->sdev_ufs_lu->request_queue, op,
                              BLK_MQ_REQ_NOWAIT);
 
        if (!atomic && (PTR_ERR(req) == -EWOULDBLOCK) && (--retries > 0)) {
index e7332cc..173aea8 100644 (file)
@@ -108,9 +108,20 @@ out:
        return ret;
 }
 
+static bool phandle_exists(const struct device_node *np,
+                          const char *phandle_name, int index)
+{
+       struct device_node *parse_np = of_parse_phandle(np, phandle_name, index);
+
+       if (parse_np)
+               of_node_put(parse_np);
+
+       return parse_np != NULL;
+}
+
 #define MAX_PROP_SIZE 32
 static int ufshcd_populate_vreg(struct device *dev, const char *name,
-               struct ufs_vreg **out_vreg)
+                               struct ufs_vreg **out_vreg)
 {
        char prop_name[MAX_PROP_SIZE];
        struct ufs_vreg *vreg = NULL;
@@ -122,7 +133,7 @@ static int ufshcd_populate_vreg(struct device *dev, const char *name,
        }
 
        snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", name);
-       if (!of_parse_phandle(np, prop_name, 0)) {
+       if (!phandle_exists(np, prop_name, 0)) {
                dev_info(dev, "%s: Unable to find %s regulator, assuming enabled\n",
                                __func__, prop_name);
                goto out;
index d4dcaef..6d93428 100644 (file)
@@ -124,22 +124,6 @@ out:
  */
 #define USB_ACPI_LOCATION_VALID (1 << 31)
 
-static struct acpi_device *usb_acpi_find_port(struct acpi_device *parent,
-                                             int raw)
-{
-       struct acpi_device *adev;
-
-       if (!parent)
-               return NULL;
-
-       list_for_each_entry(adev, &parent->children, node) {
-               if (acpi_device_adr(adev) == raw)
-                       return adev;
-       }
-
-       return acpi_find_child_device(parent, raw, false);
-}
-
 static struct acpi_device *
 usb_acpi_get_companion_for_port(struct usb_port *port_dev)
 {
@@ -170,7 +154,7 @@ usb_acpi_get_companion_for_port(struct usb_port *port_dev)
                port1 = port_dev->portnum;
        }
 
-       return usb_acpi_find_port(adev, port1);
+       return acpi_find_child_by_adr(adev, port1);
 }
 
 static struct acpi_device *
index fea7aca..173cf35 100644 (file)
@@ -195,8 +195,7 @@ static int dwc3_ti_probe(struct platform_device *pdev)
 
        if (i == ARRAY_SIZE(dwc3_ti_rate_table)) {
                dev_err(dev, "unsupported usb2_refclk rate: %lu KHz\n", rate);
-               ret = -EINVAL;
-               goto err_clk_disable;
+               return -EINVAL;
        }
 
        data->rate_code = i;
@@ -204,7 +203,7 @@ static int dwc3_ti_probe(struct platform_device *pdev)
        /* Read the syscon property and set the rate code */
        ret = phy_syscon_pll_refclk(data);
        if (ret)
-               goto err_clk_disable;
+               return ret;
 
        /* VBUS divider select */
        data->vbus_divider = device_property_read_bool(dev, "ti,vbus-divider");
@@ -245,8 +244,6 @@ err_pm_disable:
        clk_disable_unprepare(data->usb2_refclk);
        pm_runtime_disable(dev);
        pm_runtime_set_suspended(dev);
-err_clk_disable:
-       clk_put(data->usb2_refclk);
        return ret;
 }
 
@@ -276,7 +273,6 @@ static int dwc3_ti_remove(struct platform_device *pdev)
        pm_runtime_disable(dev);
        pm_runtime_set_suspended(dev);
 
-       clk_put(data->usb2_refclk);
        platform_set_drvdata(pdev, NULL);
        return 0;
 }
index 8716bec..0d89dfa 100644 (file)
@@ -4249,7 +4249,6 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt)
        }
 
        evt->count = 0;
-       evt->flags &= ~DWC3_EVENT_PENDING;
        ret = IRQ_HANDLED;
 
        /* Unmask interrupt */
@@ -4261,6 +4260,9 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt)
                dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval);
        }
 
+       /* Keep the clearing of DWC3_EVENT_PENDING at the end */
+       evt->flags &= ~DWC3_EVENT_PENDING;
+
        return ret;
 }
 
index e5a6b6e..4303a32 100644 (file)
@@ -2371,6 +2371,7 @@ static ssize_t f_uvc_opts_string_##cname##_store(struct config_item *item,\
                                          const char *page, size_t len) \
 {                                                                      \
        struct f_uvc_opts *opts = to_f_uvc_opts(item);                  \
+       int size = min(sizeof(opts->aname), len + 1);                   \
        int ret = 0;                                                    \
                                                                        \
        mutex_lock(&opts->lock);                                        \
@@ -2379,8 +2380,9 @@ static ssize_t f_uvc_opts_string_##cname##_store(struct config_item *item,\
                goto end;                                               \
        }                                                               \
                                                                        \
-       ret = snprintf(opts->aname, min(sizeof(opts->aname), len),      \
-                       "%s", page);                                    \
+       ret = strscpy(opts->aname, page, size);                         \
+       if (ret == -E2BIG)                                              \
+               ret = size - 1;                                         \
                                                                        \
 end:                                                                   \
        mutex_unlock(&opts->lock);                                      \
index 385be30..896c0d1 100644 (file)
@@ -76,14 +76,9 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!res) {
-               dev_err(&pdev->dev,
-                       "Found HC with no IRQ. Check %s setup!\n",
-                       dev_name(&pdev->dev));
-               return -ENODEV;
-       }
-       irq = res->start;
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
 
        hcd = __usb_create_hcd(&fsl_ehci_hc_driver, pdev->dev.parent,
                               &pdev->dev, dev_name(&pdev->dev), NULL);
index 44a7e58..e5df175 100644 (file)
@@ -112,6 +112,9 @@ static struct platform_device *fsl_usb2_device_register(
                        goto error;
        }
 
+       pdev->dev.of_node = ofdev->dev.of_node;
+       pdev->dev.of_node_reused = true;
+
        retval = platform_device_add(pdev);
        if (retval)
                goto error;
index b440d33..d5a3986 100644 (file)
@@ -1023,6 +1023,9 @@ static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(FTDI_VID, CHETCO_SEASMART_DISPLAY_PID) },
        { USB_DEVICE(FTDI_VID, CHETCO_SEASMART_LITE_PID) },
        { USB_DEVICE(FTDI_VID, CHETCO_SEASMART_ANALOG_PID) },
+       /* Belimo Automation devices */
+       { USB_DEVICE(FTDI_VID, BELIMO_ZTH_PID) },
+       { USB_DEVICE(FTDI_VID, BELIMO_ZIP_PID) },
        /* ICP DAS I-756xU devices */
        { USB_DEVICE(ICPDAS_VID, ICPDAS_I7560U_PID) },
        { USB_DEVICE(ICPDAS_VID, ICPDAS_I7561U_PID) },
index d1a9564..4e92c16 100644 (file)
 #define CHETCO_SEASMART_ANALOG_PID     0xA5AF /* SeaSmart Analog Adapter */
 
 /*
+ * Belimo Automation
+ */
+#define BELIMO_ZTH_PID                 0x8050
+#define BELIMO_ZIP_PID                 0xC811
+
+/*
  * Unjo AB
  */
 #define UNJO_VID                       0x22B7
index ee0e520..c472475 100644 (file)
@@ -1718,6 +1718,7 @@ void typec_set_pwr_opmode(struct typec_port *port,
                        partner->usb_pd = 1;
                        sysfs_notify(&partner_dev->kobj, NULL,
                                     "supports_usb_power_delivery");
+                       kobject_uevent(&partner_dev->kobj, KOBJ_CHANGE);
                }
                put_device(partner_dev);
        }
index 1b6d46b..e85c1d7 100644 (file)
@@ -1962,6 +1962,8 @@ static void mlx5_vdpa_set_vq_cb(struct vdpa_device *vdev, u16 idx, struct vdpa_c
        struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev);
 
        ndev->event_cbs[idx] = *cb;
+       if (is_ctrl_vq_idx(mvdev, idx))
+               mvdev->cvq.event_cb = *cb;
 }
 
 static void mlx5_cvq_notify(struct vringh *vring)
@@ -2174,7 +2176,6 @@ static int verify_driver_features(struct mlx5_vdpa_dev *mvdev, u64 features)
 static int setup_virtqueues(struct mlx5_vdpa_dev *mvdev)
 {
        struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev);
-       struct mlx5_control_vq *cvq = &mvdev->cvq;
        int err;
        int i;
 
@@ -2184,16 +2185,6 @@ static int setup_virtqueues(struct mlx5_vdpa_dev *mvdev)
                        goto err_vq;
        }
 
-       if (mvdev->actual_features & BIT_ULL(VIRTIO_NET_F_CTRL_VQ)) {
-               err = vringh_init_iotlb(&cvq->vring, mvdev->actual_features,
-                                       MLX5_CVQ_MAX_ENT, false,
-                                       (struct vring_desc *)(uintptr_t)cvq->desc_addr,
-                                       (struct vring_avail *)(uintptr_t)cvq->driver_addr,
-                                       (struct vring_used *)(uintptr_t)cvq->device_addr);
-               if (err)
-                       goto err_vq;
-       }
-
        return 0;
 
 err_vq:
@@ -2466,6 +2457,21 @@ static void clear_vqs_ready(struct mlx5_vdpa_net *ndev)
        ndev->mvdev.cvq.ready = false;
 }
 
+static int setup_cvq_vring(struct mlx5_vdpa_dev *mvdev)
+{
+       struct mlx5_control_vq *cvq = &mvdev->cvq;
+       int err = 0;
+
+       if (mvdev->actual_features & BIT_ULL(VIRTIO_NET_F_CTRL_VQ))
+               err = vringh_init_iotlb(&cvq->vring, mvdev->actual_features,
+                                       MLX5_CVQ_MAX_ENT, false,
+                                       (struct vring_desc *)(uintptr_t)cvq->desc_addr,
+                                       (struct vring_avail *)(uintptr_t)cvq->driver_addr,
+                                       (struct vring_used *)(uintptr_t)cvq->device_addr);
+
+       return err;
+}
+
 static void mlx5_vdpa_set_status(struct vdpa_device *vdev, u8 status)
 {
        struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev);
@@ -2478,6 +2484,11 @@ static void mlx5_vdpa_set_status(struct vdpa_device *vdev, u8 status)
 
        if ((status ^ ndev->mvdev.status) & VIRTIO_CONFIG_S_DRIVER_OK) {
                if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
+                       err = setup_cvq_vring(mvdev);
+                       if (err) {
+                               mlx5_vdpa_warn(mvdev, "failed to setup control VQ vring\n");
+                               goto err_setup;
+                       }
                        err = setup_driver(mvdev);
                        if (err) {
                                mlx5_vdpa_warn(mvdev, "failed to setup driver\n");
index 776ad74..3bc27de 100644 (file)
@@ -1476,16 +1476,12 @@ static char *vduse_devnode(struct device *dev, umode_t *mode)
        return kasprintf(GFP_KERNEL, "vduse/%s", dev_name(dev));
 }
 
-static void vduse_mgmtdev_release(struct device *dev)
-{
-}
-
-static struct device vduse_mgmtdev = {
-       .init_name = "vduse",
-       .release = vduse_mgmtdev_release,
+struct vduse_mgmt_dev {
+       struct vdpa_mgmt_dev mgmt_dev;
+       struct device dev;
 };
 
-static struct vdpa_mgmt_dev mgmt_dev;
+static struct vduse_mgmt_dev *vduse_mgmt;
 
 static int vduse_dev_init_vdpa(struct vduse_dev *dev, const char *name)
 {
@@ -1510,7 +1506,7 @@ static int vduse_dev_init_vdpa(struct vduse_dev *dev, const char *name)
        }
        set_dma_ops(&vdev->vdpa.dev, &vduse_dev_dma_ops);
        vdev->vdpa.dma_dev = &vdev->vdpa.dev;
-       vdev->vdpa.mdev = &mgmt_dev;
+       vdev->vdpa.mdev = &vduse_mgmt->mgmt_dev;
 
        return 0;
 }
@@ -1556,34 +1552,52 @@ static struct virtio_device_id id_table[] = {
        { 0 },
 };
 
-static struct vdpa_mgmt_dev mgmt_dev = {
-       .device = &vduse_mgmtdev,
-       .id_table = id_table,
-       .ops = &vdpa_dev_mgmtdev_ops,
-};
+static void vduse_mgmtdev_release(struct device *dev)
+{
+       struct vduse_mgmt_dev *mgmt_dev;
+
+       mgmt_dev = container_of(dev, struct vduse_mgmt_dev, dev);
+       kfree(mgmt_dev);
+}
 
 static int vduse_mgmtdev_init(void)
 {
        int ret;
 
-       ret = device_register(&vduse_mgmtdev);
-       if (ret)
+       vduse_mgmt = kzalloc(sizeof(*vduse_mgmt), GFP_KERNEL);
+       if (!vduse_mgmt)
+               return -ENOMEM;
+
+       ret = dev_set_name(&vduse_mgmt->dev, "vduse");
+       if (ret) {
+               kfree(vduse_mgmt);
                return ret;
+       }
 
-       ret = vdpa_mgmtdev_register(&mgmt_dev);
+       vduse_mgmt->dev.release = vduse_mgmtdev_release;
+
+       ret = device_register(&vduse_mgmt->dev);
        if (ret)
-               goto err;
+               goto dev_reg_err;
 
-       return 0;
-err:
-       device_unregister(&vduse_mgmtdev);
+       vduse_mgmt->mgmt_dev.id_table = id_table;
+       vduse_mgmt->mgmt_dev.ops = &vdpa_dev_mgmtdev_ops;
+       vduse_mgmt->mgmt_dev.device = &vduse_mgmt->dev;
+       ret = vdpa_mgmtdev_register(&vduse_mgmt->mgmt_dev);
+       if (ret)
+               device_unregister(&vduse_mgmt->dev);
+
+       return ret;
+
+dev_reg_err:
+       put_device(&vduse_mgmt->dev);
        return ret;
 }
 
 static void vduse_mgmtdev_exit(void)
 {
-       vdpa_mgmtdev_unregister(&mgmt_dev);
-       device_unregister(&vduse_mgmtdev);
+       vdpa_mgmtdev_unregister(&vduse_mgmt->mgmt_dev);
+       device_unregister(&vduse_mgmt->dev);
 }
 
 static int vduse_init(void)
index 61e71c1..e60b06f 100644 (file)
@@ -549,6 +549,16 @@ static struct vfio_group *vfio_group_find_or_alloc(struct device *dev)
        if (!iommu_group)
                return ERR_PTR(-EINVAL);
 
+       /*
+        * VFIO always sets IOMMU_CACHE because we offer no way for userspace to
+        * restore cache coherency. It has to be checked here because it is only
+        * valid for cases where we are using iommu groups.
+        */
+       if (!iommu_capable(dev->bus, IOMMU_CAP_CACHE_COHERENCY)) {
+               iommu_group_put(iommu_group);
+               return ERR_PTR(-EINVAL);
+       }
+
        group = vfio_group_get_from_iommu(iommu_group);
        if (!group)
                group = vfio_create_group(iommu_group, VFIO_IOMMU);
@@ -601,13 +611,6 @@ static int __vfio_register_dev(struct vfio_device *device,
 
 int vfio_register_group_dev(struct vfio_device *device)
 {
-       /*
-        * VFIO always sets IOMMU_CACHE because we offer no way for userspace to
-        * restore cache coherency.
-        */
-       if (!iommu_capable(device->dev->bus, IOMMU_CAP_CACHE_COHERENCY))
-               return -EINVAL;
-
        return __vfio_register_dev(device,
                vfio_group_find_or_alloc(device->dev));
 }
index 5ad2596..23dcbfd 100644 (file)
@@ -1209,7 +1209,7 @@ static int vhost_vdpa_release(struct inode *inode, struct file *filep)
        vhost_dev_stop(&v->vdev);
        vhost_vdpa_free_domain(v);
        vhost_vdpa_config_put(v);
-       vhost_dev_cleanup(&v->vdev);
+       vhost_vdpa_cleanup(v);
        mutex_unlock(&d->mutex);
 
        atomic_dec(&v->opened);
index fa23bf0..bd4dc97 100644 (file)
@@ -1148,6 +1148,7 @@ int sti_call(const struct sti_struct *sti, unsigned long func,
        return ret;
 }
 
+#if defined(CONFIG_FB_STI)
 /* check if given fb_info is the primary device */
 int fb_is_primary_device(struct fb_info *info)
 {
@@ -1163,6 +1164,7 @@ int fb_is_primary_device(struct fb_info *info)
        return (sti->info == info);
 }
 EXPORT_SYMBOL(fb_is_primary_device);
+#endif
 
 MODULE_AUTHOR("Philipp Rumpf, Helge Deller, Thomas Bogendoerfer");
 MODULE_DESCRIPTION("Core STI driver for HP's NGLE series graphics cards in HP PARISC machines");
index 52f731a..519313b 100644 (file)
@@ -560,8 +560,7 @@ int au1100fb_drv_suspend(struct platform_device *dev, pm_message_t state)
        /* Blank the LCD */
        au1100fb_fb_blank(VESA_POWERDOWN, &fbdev->info);
 
-       if (fbdev->lcdclk)
-               clk_disable(fbdev->lcdclk);
+       clk_disable(fbdev->lcdclk);
 
        memcpy(&fbregs, fbdev->regs, sizeof(struct au1100fb_regs));
 
@@ -577,8 +576,7 @@ int au1100fb_drv_resume(struct platform_device *dev)
 
        memcpy(fbdev->regs, &fbregs, sizeof(struct au1100fb_regs));
 
-       if (fbdev->lcdclk)
-               clk_enable(fbdev->lcdclk);
+       clk_enable(fbdev->lcdclk);
 
        /* Unblank the LCD */
        au1100fb_fb_blank(VESA_NO_BLANKING, &fbdev->info);
index 3d47c34..51e072c 100644 (file)
@@ -2184,12 +2184,6 @@ static struct pci_driver cirrusfb_pci_driver = {
        .id_table       = cirrusfb_pci_table,
        .probe          = cirrusfb_pci_register,
        .remove         = cirrusfb_pci_unregister,
-#ifdef CONFIG_PM
-#if 0
-       .suspend        = cirrusfb_pci_suspend,
-       .resume         = cirrusfb_pci_resume,
-#endif
-#endif
 };
 #endif /* CONFIG_PCI */
 
index c4e9171..1a9aa12 100644 (file)
@@ -2469,6 +2469,11 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font,
        if (charcount != 256 && charcount != 512)
                return -EINVAL;
 
+       /* font bigger than screen resolution ? */
+       if (w > FBCON_SWAP(info->var.rotate, info->var.xres, info->var.yres) ||
+           h > FBCON_SWAP(info->var.rotate, info->var.yres, info->var.xres))
+               return -EINVAL;
+
        /* Make sure drawing engine can handle the font */
        if (!(info->pixmap.blit_x & (1 << (font->width - 1))) ||
            !(info->pixmap.blit_y & (1 << (font->height - 1))))
@@ -2731,6 +2736,34 @@ void fbcon_update_vcs(struct fb_info *info, bool all)
 }
 EXPORT_SYMBOL(fbcon_update_vcs);
 
+/* let fbcon check if it supports a new screen resolution */
+int fbcon_modechange_possible(struct fb_info *info, struct fb_var_screeninfo *var)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct vc_data *vc;
+       unsigned int i;
+
+       WARN_CONSOLE_UNLOCKED();
+
+       if (!ops)
+               return 0;
+
+       /* prevent setting a screen size which is smaller than font size */
+       for (i = first_fb_vc; i <= last_fb_vc; i++) {
+               vc = vc_cons[i].d;
+               if (!vc || vc->vc_mode != KD_TEXT ||
+                          fbcon_info_from_console(i) != info)
+                       continue;
+
+               if (vc->vc_font.width  > FBCON_SWAP(var->rotate, var->xres, var->yres) ||
+                   vc->vc_font.height > FBCON_SWAP(var->rotate, var->yres, var->xres))
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(fbcon_modechange_possible);
+
 int fbcon_mode_deleted(struct fb_info *info,
                       struct fb_videomode *mode)
 {
index afa2863..7ee6eb2 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/slab.h>
+#include <linux/sysfb.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
 #include <linux/vt.h>
@@ -510,7 +511,7 @@ static int fb_show_logo_line(struct fb_info *info, int rotate,
 
                while (n && (n * (logo->width + 8) - 8 > xres))
                        --n;
-               image.dx = (xres - n * (logo->width + 8) - 8) / 2;
+               image.dx = (xres - (n * (logo->width + 8) - 8)) / 2;
                image.dy = y ?: (yres - logo->height) / 2;
        } else {
                image.dx = 0;
@@ -1016,6 +1017,16 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
        if (ret)
                return ret;
 
+       /* verify that virtual resolution >= physical resolution */
+       if (var->xres_virtual < var->xres ||
+           var->yres_virtual < var->yres) {
+               pr_warn("WARNING: fbcon: Driver '%s' missed to adjust virtual screen size (%ux%u vs. %ux%u)\n",
+                       info->fix.id,
+                       var->xres_virtual, var->yres_virtual,
+                       var->xres, var->yres);
+               return -EINVAL;
+       }
+
        if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
                return 0;
 
@@ -1106,7 +1117,9 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
                        return -EFAULT;
                console_lock();
                lock_fb_info(info);
-               ret = fb_set_var(info, &var);
+               ret = fbcon_modechange_possible(info, &var);
+               if (!ret)
+                       ret = fb_set_var(info, &var);
                if (!ret)
                        fbcon_update_vcs(info, var.activate & FB_ACTIVATE_ALL);
                unlock_fb_info(info);
@@ -1752,6 +1765,17 @@ int remove_conflicting_framebuffers(struct apertures_struct *a,
                do_free = true;
        }
 
+       /*
+        * If a driver asked to unregister a platform device registered by
+        * sysfb, then can be assumed that this is a driver for a display
+        * that is set up by the system firmware and has a generic driver.
+        *
+        * Drivers for devices that don't have a generic driver will never
+        * ask for this, so let's assume that a real driver for the display
+        * was already probed and prevent sysfb to register devices later.
+        */
+       sysfb_disable();
+
        mutex_lock(&registration_lock);
        do_remove_conflicting_framebuffers(a, name, primary);
        mutex_unlock(&registration_lock);
index a957996..5647fca 100644 (file)
@@ -472,7 +472,7 @@ static int intelfb_pci_register(struct pci_dev *pdev,
        struct fb_info *info;
        struct intelfb_info *dinfo;
        int i, err, dvo;
-       int aperture_size, stolen_size;
+       int aperture_size, stolen_size = 0;
        struct agp_kern_info gtt_info;
        int agp_memtype;
        const char *s;
@@ -571,7 +571,7 @@ static int intelfb_pci_register(struct pci_dev *pdev,
                return -ENODEV;
        }
 
-       if (intelfbhw_get_memory(pdev, &aperture_size,&stolen_size)) {
+       if (intelfbhw_get_memory(pdev, &aperture_size, &stolen_size)) {
                cleanup(dinfo);
                return -ENODEV;
        }
index 57aff74..2086e06 100644 (file)
@@ -201,13 +201,11 @@ int intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
        case PCI_DEVICE_ID_INTEL_945GME:
        case PCI_DEVICE_ID_INTEL_965G:
        case PCI_DEVICE_ID_INTEL_965GM:
-               /* 915, 945 and 965 chipsets support a 256MB aperture.
-                  Aperture size is determined by inspected the
-                  base address of the aperture. */
-               if (pci_resource_start(pdev, 2) & 0x08000000)
-                       *aperture_size = MB(128);
-               else
-                       *aperture_size = MB(256);
+               /*
+                * 915, 945 and 965 chipsets support 64MB, 128MB or 256MB
+                * aperture. Determine size from PCI resource length.
+                */
+               *aperture_size = pci_resource_len(pdev, 2);
                break;
        default:
                if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M)
index c90eb8c..66aff6c 100644 (file)
@@ -359,7 +359,7 @@ static void sossi_set_bits_per_cycle(int bpc)
        int bus_pick_count, bus_pick_width;
 
        /*
-        * We set explicitly the the bus_pick_count as well, although
+        * We set explicitly the bus_pick_count as well, although
         * with remapping/reordering disabled it will be calculated by HW
         * as (32 / bus_pick_width).
         */
index 6fbfeb0..170463a 100644 (file)
@@ -143,7 +143,7 @@ int hdmi_phy_configure(struct hdmi_phy_data *phy, unsigned long hfbitclk,
        /*
         * In OMAP5+, the HFBITCLK must be divided by 2 before issuing the
         * HDMI_PHYPWRCMD_LDOON command.
-       */
+        */
        if (phy_feat->bist_ctrl)
                REG_FLD_MOD(phy->base, HDMI_TXPHY_BIST_CONTROL, 1, 11, 11);
 
index 043cc8f..c3cd1e1 100644 (file)
@@ -381,7 +381,7 @@ pxa3xx_gcu_write(struct file *file, const char *buff,
        struct pxa3xx_gcu_batch *buffer;
        struct pxa3xx_gcu_priv *priv = to_pxa3xx_gcu_priv(file);
 
-       int words = count / 4;
+       size_t words = count / 4;
 
        /* Does not need to be atomic. There's a lock in user space,
         * but anyhow, this is just for statistics. */
index 2c19856..f96ce88 100644 (file)
@@ -237,8 +237,7 @@ static int simplefb_clocks_get(struct simplefb_par *par,
                if (IS_ERR(clock)) {
                        if (PTR_ERR(clock) == -EPROBE_DEFER) {
                                while (--i >= 0) {
-                                       if (par->clks[i])
-                                               clk_put(par->clks[i]);
+                                       clk_put(par->clks[i]);
                                }
                                kfree(par->clks);
                                return -EPROBE_DEFER;
index bcacfb6..d119b1d 100644 (file)
@@ -96,7 +96,7 @@ static const struct fb_fix_screeninfo xxxfb_fix = {
 
     /*
      *         Modern graphical hardware not only supports pipelines but some 
-     *  also support multiple monitors where each display can have its  
+     *  also support multiple monitors where each display can have
      *  its own unique data. In this case each display could be  
      *  represented by a separate framebuffer device thus a separate 
      *  struct fb_info. Now the struct xxx_par represents the graphics
@@ -838,9 +838,9 @@ static void xxxfb_remove(struct pci_dev *dev)
  *
  *      See Documentation/driver-api/pm/devices.rst for more information
  */
-static int xxxfb_suspend(struct pci_dev *dev, pm_message_t msg)
+static int xxxfb_suspend(struct device *dev)
 {
-       struct fb_info *info = pci_get_drvdata(dev);
+       struct fb_info *info = dev_get_drvdata(dev);
        struct xxxfb_par *par = info->par;
 
        /* suspend here */
@@ -853,9 +853,9 @@ static int xxxfb_suspend(struct pci_dev *dev, pm_message_t msg)
  *
  *      See Documentation/driver-api/pm/devices.rst for more information
  */
-static int xxxfb_resume(struct pci_dev *dev)
+static int xxxfb_resume(struct device *dev)
 {
-       struct fb_info *info = pci_get_drvdata(dev);
+       struct fb_info *info = dev_get_drvdata(dev);
        struct xxxfb_par *par = info->par;
 
        /* resume here */
@@ -873,14 +873,15 @@ static const struct pci_device_id xxxfb_id_table[] = {
        { 0, }
 };
 
+static SIMPLE_DEV_PM_OPS(xxxfb_pm_ops, xxxfb_suspend, xxxfb_resume);
+
 /* For PCI drivers */
 static struct pci_driver xxxfb_driver = {
        .name =         "xxxfb",
        .id_table =     xxxfb_id_table,
        .probe =        xxxfb_probe,
        .remove =       xxxfb_remove,
-       .suspend =      xxxfb_suspend, /* optional but recommended */
-       .resume =       xxxfb_resume,  /* optional but recommended */
+       .driver.pm =    xxxfb_pm_ops, /* optional but recommended */
 };
 
 MODULE_DEVICE_TABLE(pci, xxxfb_id_table);
index 90ce16b..f422f9c 100644 (file)
@@ -632,16 +632,19 @@ static int __init sev_guest_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct snp_guest_dev *snp_dev;
        struct miscdevice *misc;
+       void __iomem *mapping;
        int ret;
 
        if (!dev->platform_data)
                return -ENODEV;
 
        data = (struct sev_guest_platform_data *)dev->platform_data;
-       layout = (__force void *)ioremap_encrypted(data->secrets_gpa, PAGE_SIZE);
-       if (!layout)
+       mapping = ioremap_encrypted(data->secrets_gpa, PAGE_SIZE);
+       if (!mapping)
                return -ENODEV;
 
+       layout = (__force void *)mapping;
+
        ret = -ENOMEM;
        snp_dev = devm_kzalloc(&pdev->dev, sizeof(struct snp_guest_dev), GFP_KERNEL);
        if (!snp_dev)
@@ -706,7 +709,7 @@ e_free_response:
 e_free_request:
        free_shared_pages(snp_dev->request, sizeof(struct snp_guest_msg));
 e_unmap:
-       iounmap(layout);
+       iounmap(mapping);
        return ret;
 }
 
index 2d3d981..ce91add 100644 (file)
@@ -16,8 +16,9 @@ config NITRO_ENCLAVES
          The module will be called nitro_enclaves.
 
 config NITRO_ENCLAVES_MISC_DEV_TEST
-       bool "Tests for the misc device functionality of the Nitro Enclaves"
-       depends on NITRO_ENCLAVES && KUNIT=y
+       bool "Tests for the misc device functionality of the Nitro Enclaves" if !KUNIT_ALL_TESTS
+       depends on NITRO_ENCLAVES && KUNIT
+       default KUNIT_ALL_TESTS
        help
          Enable KUnit tests for the misc device functionality of the Nitro
          Enclaves. Select this option only if you will boot the kernel for
index 20c881b..241b94f 100644 (file)
@@ -1759,35 +1759,10 @@ static long ne_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
 #if defined(CONFIG_NITRO_ENCLAVES_MISC_DEV_TEST)
 #include "ne_misc_dev_test.c"
-
-static inline int ne_misc_dev_test_init(void)
-{
-       return __kunit_test_suites_init(ne_misc_dev_test_suites);
-}
-
-static inline void ne_misc_dev_test_exit(void)
-{
-       __kunit_test_suites_exit(ne_misc_dev_test_suites);
-}
-#else
-static inline int ne_misc_dev_test_init(void)
-{
-       return 0;
-}
-
-static inline void ne_misc_dev_test_exit(void)
-{
-}
 #endif
 
 static int __init ne_init(void)
 {
-       int rc = 0;
-
-       rc = ne_misc_dev_test_init();
-       if (rc < 0)
-               return rc;
-
        mutex_init(&ne_cpu_pool.mutex);
 
        return pci_register_driver(&ne_pci_driver);
@@ -1798,8 +1773,6 @@ static void __exit ne_exit(void)
        pci_unregister_driver(&ne_pci_driver);
 
        ne_teardown_cpu_pool();
-
-       ne_misc_dev_test_exit();
 }
 
 module_init(ne_init);
index 265797b..74df43b 100644 (file)
@@ -151,7 +151,4 @@ static struct kunit_suite ne_misc_dev_test_suite = {
        .test_cases = ne_misc_dev_test_cases,
 };
 
-static struct kunit_suite *ne_misc_dev_test_suites[] = {
-       &ne_misc_dev_test_suite,
-       NULL
-};
+kunit_test_suite(ne_misc_dev_test_suite);
index a6dc8b5..e1556d2 100644 (file)
@@ -29,6 +29,19 @@ menuconfig VIRTIO_MENU
 
 if VIRTIO_MENU
 
+config VIRTIO_HARDEN_NOTIFICATION
+        bool "Harden virtio notification"
+        help
+          Enable this to harden the device notifications and suppress
+          those that happen at a time where notifications are illegal.
+
+          Experimental: Note that several drivers still have bugs that
+          may cause crashes or hangs when correct handling of
+          notifications is enforced; depending on the subset of
+          drivers and devices you use, this may or may not work.
+
+          If unsure, say N.
+
 config VIRTIO_PCI
        tristate "PCI driver for virtio devices"
        depends on PCI
index 6bace84..7deeed3 100644 (file)
@@ -219,6 +219,7 @@ static int virtio_features_ok(struct virtio_device *dev)
  * */
 void virtio_reset_device(struct virtio_device *dev)
 {
+#ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION
        /*
         * The below virtio_synchronize_cbs() guarantees that any
         * interrupt for this line arriving after
@@ -227,6 +228,7 @@ void virtio_reset_device(struct virtio_device *dev)
         */
        virtio_break_device(dev);
        virtio_synchronize_cbs(dev);
+#endif
 
        dev->config->reset(dev);
 }
index c9bec38..083ff1e 100644 (file)
@@ -62,6 +62,7 @@
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/pm.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/virtio.h>
@@ -556,6 +557,28 @@ static const struct virtio_config_ops virtio_mmio_config_ops = {
        .synchronize_cbs = vm_synchronize_cbs,
 };
 
+#ifdef CONFIG_PM_SLEEP
+static int virtio_mmio_freeze(struct device *dev)
+{
+       struct virtio_mmio_device *vm_dev = dev_get_drvdata(dev);
+
+       return virtio_device_freeze(&vm_dev->vdev);
+}
+
+static int virtio_mmio_restore(struct device *dev)
+{
+       struct virtio_mmio_device *vm_dev = dev_get_drvdata(dev);
+
+       if (vm_dev->version == 1)
+               writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_GUEST_PAGE_SIZE);
+
+       return virtio_device_restore(&vm_dev->vdev);
+}
+
+static const struct dev_pm_ops virtio_mmio_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(virtio_mmio_freeze, virtio_mmio_restore)
+};
+#endif
 
 static void virtio_mmio_release_dev(struct device *_d)
 {
@@ -799,6 +822,9 @@ static struct platform_driver virtio_mmio_driver = {
                .name   = "virtio-mmio",
                .of_match_table = virtio_mmio_match,
                .acpi_match_table = ACPI_PTR(virtio_mmio_acpi_match),
+#ifdef CONFIG_PM_SLEEP
+               .pm     = &virtio_mmio_pm_ops,
+#endif
        },
 };
 
index b790f30..fa2a944 100644 (file)
@@ -220,8 +220,6 @@ int vp_modern_probe(struct virtio_pci_modern_device *mdev)
 
        check_offsets();
 
-       mdev->pci_dev = pci_dev;
-
        /* We only own devices >= 0x1000 and <= 0x107f: leave the rest. */
        if (pci_dev->device < 0x1000 || pci_dev->device > 0x107f)
                return -ENODEV;
index 13a7348..643ca77 100644 (file)
@@ -111,7 +111,12 @@ struct vring_virtqueue {
        /* Number we've added since last sync. */
        unsigned int num_added;
 
-       /* Last used index we've seen. */
+       /* Last used index  we've seen.
+        * for split ring, it just contains last used index
+        * for packed ring:
+        * bits up to VRING_PACKED_EVENT_F_WRAP_CTR include the last used index.
+        * bits from VRING_PACKED_EVENT_F_WRAP_CTR include the used wrap counter.
+        */
        u16 last_used_idx;
 
        /* Hint for event idx: already triggered no need to disable. */
@@ -154,9 +159,6 @@ struct vring_virtqueue {
                        /* Driver ring wrap counter. */
                        bool avail_wrap_counter;
 
-                       /* Device ring wrap counter. */
-                       bool used_wrap_counter;
-
                        /* Avail used flags. */
                        u16 avail_used_flags;
 
@@ -933,7 +935,7 @@ static struct virtqueue *vring_create_virtqueue_split(
        for (; num && vring_size(num, vring_align) > PAGE_SIZE; num /= 2) {
                queue = vring_alloc_queue(vdev, vring_size(num, vring_align),
                                          &dma_addr,
-                                         GFP_KERNEL|__GFP_NOWARN|__GFP_ZERO);
+                                         GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO);
                if (queue)
                        break;
                if (!may_reduce_num)
@@ -973,6 +975,15 @@ static struct virtqueue *vring_create_virtqueue_split(
 /*
  * Packed ring specific functions - *_packed().
  */
+static inline bool packed_used_wrap_counter(u16 last_used_idx)
+{
+       return !!(last_used_idx & (1 << VRING_PACKED_EVENT_F_WRAP_CTR));
+}
+
+static inline u16 packed_last_used(u16 last_used_idx)
+{
+       return last_used_idx & ~(-(1 << VRING_PACKED_EVENT_F_WRAP_CTR));
+}
 
 static void vring_unmap_extra_packed(const struct vring_virtqueue *vq,
                                     struct vring_desc_extra *extra)
@@ -1406,8 +1417,14 @@ static inline bool is_used_desc_packed(const struct vring_virtqueue *vq,
 
 static inline bool more_used_packed(const struct vring_virtqueue *vq)
 {
-       return is_used_desc_packed(vq, vq->last_used_idx,
-                       vq->packed.used_wrap_counter);
+       u16 last_used;
+       u16 last_used_idx;
+       bool used_wrap_counter;
+
+       last_used_idx = READ_ONCE(vq->last_used_idx);
+       last_used = packed_last_used(last_used_idx);
+       used_wrap_counter = packed_used_wrap_counter(last_used_idx);
+       return is_used_desc_packed(vq, last_used, used_wrap_counter);
 }
 
 static void *virtqueue_get_buf_ctx_packed(struct virtqueue *_vq,
@@ -1415,7 +1432,8 @@ static void *virtqueue_get_buf_ctx_packed(struct virtqueue *_vq,
                                          void **ctx)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
-       u16 last_used, id;
+       u16 last_used, id, last_used_idx;
+       bool used_wrap_counter;
        void *ret;
 
        START_USE(vq);
@@ -1434,7 +1452,9 @@ static void *virtqueue_get_buf_ctx_packed(struct virtqueue *_vq,
        /* Only get used elements after they have been exposed by host. */
        virtio_rmb(vq->weak_barriers);
 
-       last_used = vq->last_used_idx;
+       last_used_idx = READ_ONCE(vq->last_used_idx);
+       used_wrap_counter = packed_used_wrap_counter(last_used_idx);
+       last_used = packed_last_used(last_used_idx);
        id = le16_to_cpu(vq->packed.vring.desc[last_used].id);
        *len = le32_to_cpu(vq->packed.vring.desc[last_used].len);
 
@@ -1451,12 +1471,15 @@ static void *virtqueue_get_buf_ctx_packed(struct virtqueue *_vq,
        ret = vq->packed.desc_state[id].data;
        detach_buf_packed(vq, id, ctx);
 
-       vq->last_used_idx += vq->packed.desc_state[id].num;
-       if (unlikely(vq->last_used_idx >= vq->packed.vring.num)) {
-               vq->last_used_idx -= vq->packed.vring.num;
-               vq->packed.used_wrap_counter ^= 1;
+       last_used += vq->packed.desc_state[id].num;
+       if (unlikely(last_used >= vq->packed.vring.num)) {
+               last_used -= vq->packed.vring.num;
+               used_wrap_counter ^= 1;
        }
 
+       last_used = (last_used | (used_wrap_counter << VRING_PACKED_EVENT_F_WRAP_CTR));
+       WRITE_ONCE(vq->last_used_idx, last_used);
+
        /*
         * If we expect an interrupt for the next entry, tell host
         * by writing event index and flush out the write before
@@ -1465,9 +1488,7 @@ static void *virtqueue_get_buf_ctx_packed(struct virtqueue *_vq,
        if (vq->packed.event_flags_shadow == VRING_PACKED_EVENT_FLAG_DESC)
                virtio_store_mb(vq->weak_barriers,
                                &vq->packed.vring.driver->off_wrap,
-                               cpu_to_le16(vq->last_used_idx |
-                                       (vq->packed.used_wrap_counter <<
-                                        VRING_PACKED_EVENT_F_WRAP_CTR)));
+                               cpu_to_le16(vq->last_used_idx));
 
        LAST_ADD_TIME_INVALID(vq);
 
@@ -1499,9 +1520,7 @@ static unsigned int virtqueue_enable_cb_prepare_packed(struct virtqueue *_vq)
 
        if (vq->event) {
                vq->packed.vring.driver->off_wrap =
-                       cpu_to_le16(vq->last_used_idx |
-                               (vq->packed.used_wrap_counter <<
-                                VRING_PACKED_EVENT_F_WRAP_CTR));
+                       cpu_to_le16(vq->last_used_idx);
                /*
                 * We need to update event offset and event wrap
                 * counter first before updating event flags.
@@ -1518,8 +1537,7 @@ static unsigned int virtqueue_enable_cb_prepare_packed(struct virtqueue *_vq)
        }
 
        END_USE(vq);
-       return vq->last_used_idx | ((u16)vq->packed.used_wrap_counter <<
-                       VRING_PACKED_EVENT_F_WRAP_CTR);
+       return vq->last_used_idx;
 }
 
 static bool virtqueue_poll_packed(struct virtqueue *_vq, u16 off_wrap)
@@ -1537,7 +1555,7 @@ static bool virtqueue_poll_packed(struct virtqueue *_vq, u16 off_wrap)
 static bool virtqueue_enable_cb_delayed_packed(struct virtqueue *_vq)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
-       u16 used_idx, wrap_counter;
+       u16 used_idx, wrap_counter, last_used_idx;
        u16 bufs;
 
        START_USE(vq);
@@ -1550,9 +1568,10 @@ static bool virtqueue_enable_cb_delayed_packed(struct virtqueue *_vq)
        if (vq->event) {
                /* TODO: tune this threshold */
                bufs = (vq->packed.vring.num - vq->vq.num_free) * 3 / 4;
-               wrap_counter = vq->packed.used_wrap_counter;
+               last_used_idx = READ_ONCE(vq->last_used_idx);
+               wrap_counter = packed_used_wrap_counter(last_used_idx);
 
-               used_idx = vq->last_used_idx + bufs;
+               used_idx = packed_last_used(last_used_idx) + bufs;
                if (used_idx >= vq->packed.vring.num) {
                        used_idx -= vq->packed.vring.num;
                        wrap_counter ^= 1;
@@ -1582,9 +1601,10 @@ static bool virtqueue_enable_cb_delayed_packed(struct virtqueue *_vq)
         */
        virtio_mb(vq->weak_barriers);
 
-       if (is_used_desc_packed(vq,
-                               vq->last_used_idx,
-                               vq->packed.used_wrap_counter)) {
+       last_used_idx = READ_ONCE(vq->last_used_idx);
+       wrap_counter = packed_used_wrap_counter(last_used_idx);
+       used_idx = packed_last_used(last_used_idx);
+       if (is_used_desc_packed(vq, used_idx, wrap_counter)) {
                END_USE(vq);
                return false;
        }
@@ -1688,8 +1708,12 @@ static struct virtqueue *vring_create_virtqueue_packed(
        vq->we_own_ring = true;
        vq->notify = notify;
        vq->weak_barriers = weak_barriers;
+#ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION
        vq->broken = true;
-       vq->last_used_idx = 0;
+#else
+       vq->broken = false;
+#endif
+       vq->last_used_idx = 0 | (1 << VRING_PACKED_EVENT_F_WRAP_CTR);
        vq->event_triggered = false;
        vq->num_added = 0;
        vq->packed_ring = true;
@@ -1720,7 +1744,6 @@ static struct virtqueue *vring_create_virtqueue_packed(
 
        vq->packed.next_avail_idx = 0;
        vq->packed.avail_wrap_counter = 1;
-       vq->packed.used_wrap_counter = 1;
        vq->packed.event_flags_shadow = 0;
        vq->packed.avail_used_flags = 1 << VRING_PACKED_DESC_F_AVAIL;
 
@@ -2135,9 +2158,13 @@ irqreturn_t vring_interrupt(int irq, void *_vq)
        }
 
        if (unlikely(vq->broken)) {
+#ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION
                dev_warn_once(&vq->vq.vdev->dev,
                              "virtio vring IRQ raised before DRIVER_OK");
                return IRQ_NONE;
+#else
+               return IRQ_HANDLED;
+#endif
        }
 
        /* Just a hint for performance: so it's ok that this can be racy! */
@@ -2180,7 +2207,11 @@ struct virtqueue *__vring_new_virtqueue(unsigned int index,
        vq->we_own_ring = false;
        vq->notify = notify;
        vq->weak_barriers = weak_barriers;
+#ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION
        vq->broken = true;
+#else
+       vq->broken = false;
+#endif
        vq->last_used_idx = 0;
        vq->event_triggered = false;
        vq->num_added = 0;
index 46d9295..5e8321f 100644 (file)
@@ -528,9 +528,10 @@ static void bind_evtchn_to_cpu(evtchn_port_t evtchn, unsigned int cpu,
        BUG_ON(irq == -1);
 
        if (IS_ENABLED(CONFIG_SMP) && force_affinity) {
-               cpumask_copy(irq_get_affinity_mask(irq), cpumask_of(cpu));
-               cpumask_copy(irq_get_effective_affinity_mask(irq),
-                            cpumask_of(cpu));
+               struct irq_data *data = irq_get_irq_data(irq);
+
+               irq_data_update_affinity(data, cpumask_of(cpu));
+               irq_data_update_effective_affinity(data, cpumask_of(cpu));
        }
 
        xen_evtchn_port_bind_to_cpu(evtchn, cpu, info->cpu);
index 4b56c39..84b143e 100644 (file)
@@ -396,13 +396,15 @@ static void __unmap_grant_pages_done(int result,
        unsigned int offset = data->unmap_ops - map->unmap_ops;
 
        for (i = 0; i < data->count; i++) {
-               WARN_ON(map->unmap_ops[offset+i].status);
+               WARN_ON(map->unmap_ops[offset + i].status != GNTST_okay &&
+                       map->unmap_ops[offset + i].handle != INVALID_GRANT_HANDLE);
                pr_debug("unmap handle=%d st=%d\n",
                        map->unmap_ops[offset+i].handle,
                        map->unmap_ops[offset+i].status);
                map->unmap_ops[offset+i].handle = INVALID_GRANT_HANDLE;
                if (use_ptemod) {
-                       WARN_ON(map->kunmap_ops[offset+i].status);
+                       WARN_ON(map->kunmap_ops[offset + i].status != GNTST_okay &&
+                               map->kunmap_ops[offset + i].handle != INVALID_GRANT_HANDLE);
                        pr_debug("kunmap handle=%u st=%d\n",
                                 map->kunmap_ops[offset+i].handle,
                                 map->kunmap_ops[offset+i].status);
index 208a74e..93b8052 100644 (file)
@@ -34,8 +34,6 @@ obj-$(CONFIG_TIMERFD)         += timerfd.o
 obj-$(CONFIG_EVENTFD)          += eventfd.o
 obj-$(CONFIG_USERFAULTFD)      += userfaultfd.o
 obj-$(CONFIG_AIO)               += aio.o
-obj-$(CONFIG_IO_URING)         += io_uring.o
-obj-$(CONFIG_IO_WQ)            += io-wq.o
 obj-$(CONFIG_FS_DAX)           += dax.o
 obj-$(CONFIG_FS_ENCRYPTION)    += crypto/
 obj-$(CONFIG_FS_VERITY)                += verity/
index 42118a4..d1cfb23 100644 (file)
@@ -375,7 +375,7 @@ static int afs_begin_cache_operation(struct netfs_io_request *rreq)
 }
 
 static int afs_check_write_begin(struct file *file, loff_t pos, unsigned len,
-                                struct folio *folio, void **_fsdata)
+                                struct folio **foliop, void **_fsdata)
 {
        struct afs_vnode *vnode = AFS_FS_I(file_inode(file));
 
index dbe996b..b5b8835 100644 (file)
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -22,7 +22,7 @@
  * chown_ok - verify permissions to chown inode
  * @mnt_userns:        user namespace of the mount @inode was found from
  * @inode:     inode to check permissions on
- * @uid:       uid to chown @inode to
+ * @ia_vfsuid: uid to chown @inode to
  *
  * If the inode has been found through an idmapped mount the user namespace of
  * the vfsmount must be passed through @mnt_userns. This function will then
  * performed on the raw inode simply passs init_user_ns.
  */
 static bool chown_ok(struct user_namespace *mnt_userns,
-                    const struct inode *inode,
-                    kuid_t uid)
+                    const struct inode *inode, vfsuid_t ia_vfsuid)
 {
-       kuid_t kuid = i_uid_into_mnt(mnt_userns, inode);
-       if (uid_eq(current_fsuid(), kuid) && uid_eq(uid, inode->i_uid))
+       vfsuid_t vfsuid = i_uid_into_vfsuid(mnt_userns, inode);
+       if (vfsuid_eq_kuid(vfsuid, current_fsuid()) &&
+           vfsuid_eq(ia_vfsuid, vfsuid))
                return true;
        if (capable_wrt_inode_uidgid(mnt_userns, inode, CAP_CHOWN))
                return true;
-       if (uid_eq(kuid, INVALID_UID) &&
+       if (!vfsuid_valid(vfsuid) &&
            ns_capable(inode->i_sb->s_user_ns, CAP_CHOWN))
                return true;
        return false;
@@ -49,7 +49,7 @@ static bool chown_ok(struct user_namespace *mnt_userns,
  * chgrp_ok - verify permissions to chgrp inode
  * @mnt_userns:        user namespace of the mount @inode was found from
  * @inode:     inode to check permissions on
- * @gid:       gid to chown @inode to
+ * @ia_vfsgid: gid to chown @inode to
  *
  * If the inode has been found through an idmapped mount the user namespace of
  * the vfsmount must be passed through @mnt_userns. This function will then
@@ -58,21 +58,19 @@ static bool chown_ok(struct user_namespace *mnt_userns,
  * performed on the raw inode simply passs init_user_ns.
  */
 static bool chgrp_ok(struct user_namespace *mnt_userns,
-                    const struct inode *inode, kgid_t gid)
+                    const struct inode *inode, vfsgid_t ia_vfsgid)
 {
-       kgid_t kgid = i_gid_into_mnt(mnt_userns, inode);
-       if (uid_eq(current_fsuid(), i_uid_into_mnt(mnt_userns, inode))) {
-               kgid_t mapped_gid;
-
-               if (gid_eq(gid, inode->i_gid))
+       vfsgid_t vfsgid = i_gid_into_vfsgid(mnt_userns, inode);
+       vfsuid_t vfsuid = i_uid_into_vfsuid(mnt_userns, inode);
+       if (vfsuid_eq_kuid(vfsuid, current_fsuid())) {
+               if (vfsgid_eq(ia_vfsgid, vfsgid))
                        return true;
-               mapped_gid = mapped_kgid_fs(mnt_userns, i_user_ns(inode), gid);
-               if (in_group_p(mapped_gid))
+               if (vfsgid_in_group_p(ia_vfsgid))
                        return true;
        }
        if (capable_wrt_inode_uidgid(mnt_userns, inode, CAP_CHOWN))
                return true;
-       if (gid_eq(kgid, INVALID_GID) &&
+       if (!vfsgid_valid(vfsgid) &&
            ns_capable(inode->i_sb->s_user_ns, CAP_CHOWN))
                return true;
        return false;
@@ -120,28 +118,29 @@ int setattr_prepare(struct user_namespace *mnt_userns, struct dentry *dentry,
                goto kill_priv;
 
        /* Make sure a caller can chown. */
-       if ((ia_valid & ATTR_UID) && !chown_ok(mnt_userns, inode, attr->ia_uid))
+       if ((ia_valid & ATTR_UID) &&
+           !chown_ok(mnt_userns, inode, attr->ia_vfsuid))
                return -EPERM;
 
        /* Make sure caller can chgrp. */
-       if ((ia_valid & ATTR_GID) && !chgrp_ok(mnt_userns, inode, attr->ia_gid))
+       if ((ia_valid & ATTR_GID) &&
+           !chgrp_ok(mnt_userns, inode, attr->ia_vfsgid))
                return -EPERM;
 
        /* Make sure a caller can chmod. */
        if (ia_valid & ATTR_MODE) {
-               kgid_t mapped_gid;
+               vfsgid_t vfsgid;
 
                if (!inode_owner_or_capable(mnt_userns, inode))
                        return -EPERM;
 
                if (ia_valid & ATTR_GID)
-                       mapped_gid = mapped_kgid_fs(mnt_userns,
-                                               i_user_ns(inode), attr->ia_gid);
+                       vfsgid = attr->ia_vfsgid;
                else
-                       mapped_gid = i_gid_into_mnt(mnt_userns, inode);
+                       vfsgid = i_gid_into_vfsgid(mnt_userns, inode);
 
                /* Also check the setgid bit! */
-               if (!in_group_p(mapped_gid) &&
+               if (!vfsgid_in_group_p(vfsgid) &&
                    !capable_wrt_inode_uidgid(mnt_userns, inode, CAP_FSETID))
                        attr->ia_mode &= ~S_ISGID;
        }
@@ -219,9 +218,7 @@ EXPORT_SYMBOL(inode_newsize_ok);
  * setattr_copy must be called with i_mutex held.
  *
  * setattr_copy updates the inode's metadata with that specified
- * in attr on idmapped mounts. If file ownership is changed setattr_copy
- * doesn't map ia_uid and ia_gid. It will asssume the caller has already
- * provided the intended values. Necessary permission checks to determine
+ * in attr on idmapped mounts. Necessary permission checks to determine
  * whether or not the S_ISGID property needs to be removed are performed with
  * the correct idmapped mount permission helpers.
  * Noticeably missing is inode size update, which is more complex
@@ -242,10 +239,8 @@ void setattr_copy(struct user_namespace *mnt_userns, struct inode *inode,
 {
        unsigned int ia_valid = attr->ia_valid;
 
-       if (ia_valid & ATTR_UID)
-               inode->i_uid = attr->ia_uid;
-       if (ia_valid & ATTR_GID)
-               inode->i_gid = attr->ia_gid;
+       i_uid_update(mnt_userns, attr, inode);
+       i_gid_update(mnt_userns, attr, inode);
        if (ia_valid & ATTR_ATIME)
                inode->i_atime = attr->ia_atime;
        if (ia_valid & ATTR_MTIME)
@@ -254,8 +249,8 @@ void setattr_copy(struct user_namespace *mnt_userns, struct inode *inode,
                inode->i_ctime = attr->ia_ctime;
        if (ia_valid & ATTR_MODE) {
                umode_t mode = attr->ia_mode;
-               kgid_t kgid = i_gid_into_mnt(mnt_userns, inode);
-               if (!in_group_p(kgid) &&
+               vfsgid_t vfsgid = i_gid_into_vfsgid(mnt_userns, inode);
+               if (!vfsgid_in_group_p(vfsgid) &&
                    !capable_wrt_inode_uidgid(mnt_userns, inode, CAP_FSETID))
                        mode &= ~S_ISGID;
                inode->i_mode = mode;
@@ -306,9 +301,6 @@ EXPORT_SYMBOL(may_setattr);
  * retry.  Because breaking a delegation may take a long time, the
  * caller should drop the i_mutex before doing so.
  *
- * If file ownership is changed notify_change() doesn't map ia_uid and
- * ia_gid. It will asssume the caller has already provided the intended values.
- *
  * Alternatively, a caller may pass NULL for delegated_inode.  This may
  * be appropriate for callers that expect the underlying filesystem not
  * to be NFS exported.  Also, passing NULL is fine for callers holding
@@ -397,23 +389,25 @@ int notify_change(struct user_namespace *mnt_userns, struct dentry *dentry,
         * namespace of the superblock.
         */
        if (ia_valid & ATTR_UID &&
-           !kuid_has_mapping(inode->i_sb->s_user_ns, attr->ia_uid))
+           !vfsuid_has_fsmapping(mnt_userns, inode->i_sb->s_user_ns,
+                                 attr->ia_vfsuid))
                return -EOVERFLOW;
        if (ia_valid & ATTR_GID &&
-           !kgid_has_mapping(inode->i_sb->s_user_ns, attr->ia_gid))
+           !vfsgid_has_fsmapping(mnt_userns, inode->i_sb->s_user_ns,
+                                 attr->ia_vfsgid))
                return -EOVERFLOW;
 
        /* Don't allow modifications of files with invalid uids or
         * gids unless those uids & gids are being made valid.
         */
        if (!(ia_valid & ATTR_UID) &&
-           !uid_valid(i_uid_into_mnt(mnt_userns, inode)))
+           !vfsuid_valid(i_uid_into_vfsuid(mnt_userns, inode)))
                return -EOVERFLOW;
        if (!(ia_valid & ATTR_GID) &&
-           !gid_valid(i_gid_into_mnt(mnt_userns, inode)))
+           !vfsgid_valid(i_gid_into_vfsgid(mnt_userns, inode)))
                return -EOVERFLOW;
 
-       error = security_inode_setattr(dentry, attr);
+       error = security_inode_setattr(mnt_userns, dentry, attr);
        if (error)
                return error;
        error = try_break_deleg(inode, delegated_inode);
index 3ac668a..35e0e86 100644 (file)
@@ -104,6 +104,7 @@ struct btrfs_block_group {
        unsigned int relocating_repair:1;
        unsigned int chunk_item_inserted:1;
        unsigned int zone_is_active:1;
+       unsigned int zoned_data_reloc_ongoing:1;
 
        int disk_cache_state;
 
index 5d20137..98c6e5f 100644 (file)
@@ -152,7 +152,7 @@ struct btrfsic_block {
        struct btrfsic_block *next_in_same_bio;
        void *orig_bio_private;
        bio_end_io_t *orig_bio_end_io;
-       int submit_bio_bh_rw;
+       blk_opf_t submit_bio_bh_rw;
        u64 flush_gen; /* only valid if !never_written */
 };
 
@@ -1681,7 +1681,7 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state,
                                          u64 dev_bytenr, char **mapped_datav,
                                          unsigned int num_pages,
                                          struct bio *bio, int *bio_is_patched,
-                                         int submit_bio_bh_rw)
+                                         blk_opf_t submit_bio_bh_rw)
 {
        int is_metadata;
        struct btrfsic_block *block;
index f4564f3..a82b9f1 100644 (file)
@@ -455,7 +455,7 @@ static blk_status_t submit_compressed_bio(struct btrfs_fs_info *fs_info,
 
 
 static struct bio *alloc_compressed_bio(struct compressed_bio *cb, u64 disk_bytenr,
-                                       unsigned int opf, bio_end_io_t endio_func,
+                                       blk_opf_t opf, bio_end_io_t endio_func,
                                        u64 *next_stripe_start)
 {
        struct btrfs_fs_info *fs_info = btrfs_sb(cb->inode->i_sb);
@@ -505,7 +505,7 @@ blk_status_t btrfs_submit_compressed_write(struct btrfs_inode *inode, u64 start,
                                 unsigned int compressed_len,
                                 struct page **compressed_pages,
                                 unsigned int nr_pages,
-                                unsigned int write_flags,
+                                blk_opf_t write_flags,
                                 struct cgroup_subsys_state *blkcg_css,
                                 bool writeback)
 {
@@ -517,7 +517,7 @@ blk_status_t btrfs_submit_compressed_write(struct btrfs_inode *inode, u64 start,
        blk_status_t ret;
        int skip_sum = inode->flags & BTRFS_INODE_NODATASUM;
        const bool use_append = btrfs_use_zone_append(inode, disk_start);
-       const unsigned int bio_op = use_append ? REQ_OP_ZONE_APPEND : REQ_OP_WRITE;
+       const enum req_op bio_op = use_append ? REQ_OP_ZONE_APPEND : REQ_OP_WRITE;
 
        ASSERT(IS_ALIGNED(start, fs_info->sectorsize) &&
               IS_ALIGNED(len, fs_info->sectorsize));
index 2707404..2b56d63 100644 (file)
@@ -99,7 +99,7 @@ blk_status_t btrfs_submit_compressed_write(struct btrfs_inode *inode, u64 start,
                                  unsigned int compressed_len,
                                  struct page **compressed_pages,
                                  unsigned int nr_pages,
-                                 unsigned int write_flags,
+                                 blk_opf_t write_flags,
                                  struct cgroup_subsys_state *blkcg_css,
                                  bool writeback);
 void btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
index 0e49b1a..9c21e21 100644 (file)
@@ -675,9 +675,8 @@ struct btrfs_fs_info {
        rwlock_t global_root_lock;
        struct rb_root global_root_tree;
 
-       /* The xarray that holds all the FS roots */
-       spinlock_t fs_roots_lock;
-       struct xarray fs_roots;
+       spinlock_t fs_roots_radix_lock;
+       struct radix_tree_root fs_roots_radix;
 
        /* block group cache stuff */
        rwlock_t block_group_cache_lock;
@@ -995,10 +994,10 @@ struct btrfs_fs_info {
 
        struct btrfs_delayed_root *delayed_root;
 
-       /* Extent buffer xarray */
+       /* Extent buffer radix tree */
        spinlock_t buffer_lock;
        /* Entries are eb->start / sectorsize */
-       struct xarray extent_buffers;
+       struct radix_tree_root buffer_radix;
 
        /* next backup root to be overwritten */
        int backup_root_index;
@@ -1119,8 +1118,7 @@ enum {
         */
        BTRFS_ROOT_SHAREABLE,
        BTRFS_ROOT_TRACK_DIRTY,
-       /* The root is tracked in fs_info::fs_roots */
-       BTRFS_ROOT_REGISTERED,
+       BTRFS_ROOT_IN_RADIX,
        BTRFS_ROOT_ORPHAN_ITEM_INSERTED,
        BTRFS_ROOT_DEFRAG_RUNNING,
        BTRFS_ROOT_FORCE_COW,
@@ -1224,10 +1222,10 @@ struct btrfs_root {
        struct rb_root inode_tree;
 
        /*
-        * Xarray that keeps track of delayed nodes of every inode, protected
-        * by inode_lock
+        * radix tree that keeps track of delayed nodes of every inode,
+        * protected by inode_lock
         */
-       struct xarray delayed_nodes;
+       struct radix_tree_root delayed_nodes_tree;
        /*
         * right now this just gets used so that a root has its own devid
         * for stat.  It may be used for more later
@@ -1330,6 +1328,8 @@ struct btrfs_replace_extent_info {
         * existing extent into a file range.
         */
        bool is_new_extent;
+       /* Indicate if we should update the inode's mtime and ctime. */
+       bool update_times;
        /* Meaningful only if is_new_extent is true. */
        int qgroup_reserved;
        /*
index 66779ab..748bf6b 100644 (file)
@@ -78,7 +78,7 @@ static struct btrfs_delayed_node *btrfs_get_delayed_node(
        }
 
        spin_lock(&root->inode_lock);
-       node = xa_load(&root->delayed_nodes, ino);
+       node = radix_tree_lookup(&root->delayed_nodes_tree, ino);
 
        if (node) {
                if (btrfs_inode->delayed_node) {
@@ -90,9 +90,9 @@ static struct btrfs_delayed_node *btrfs_get_delayed_node(
 
                /*
                 * It's possible that we're racing into the middle of removing
-                * this node from the xarray.  In this case, the refcount
+                * this node from the radix tree.  In this case, the refcount
                 * was zero and it should never go back to one.  Just return
-                * NULL like it was never in the xarray at all; our release
+                * NULL like it was never in the radix at all; our release
                 * function is in the process of removing it.
                 *
                 * Some implementations of refcount_inc refuse to bump the
@@ -100,7 +100,7 @@ static struct btrfs_delayed_node *btrfs_get_delayed_node(
                 * here, refcount_inc() may decide to just WARN_ONCE() instead
                 * of actually bumping the refcount.
                 *
-                * If this node is properly in the xarray, we want to bump the
+                * If this node is properly in the radix, we want to bump the
                 * refcount twice, once for the inode and once for this get
                 * operation.
                 */
@@ -128,30 +128,36 @@ static struct btrfs_delayed_node *btrfs_get_or_create_delayed_node(
        u64 ino = btrfs_ino(btrfs_inode);
        int ret;
 
-       do {
-               node = btrfs_get_delayed_node(btrfs_inode);
-               if (node)
-                       return node;
+again:
+       node = btrfs_get_delayed_node(btrfs_inode);
+       if (node)
+               return node;
 
-               node = kmem_cache_zalloc(delayed_node_cache, GFP_NOFS);
-               if (!node)
-                       return ERR_PTR(-ENOMEM);
-               btrfs_init_delayed_node(node, root, ino);
+       node = kmem_cache_zalloc(delayed_node_cache, GFP_NOFS);
+       if (!node)
+               return ERR_PTR(-ENOMEM);
+       btrfs_init_delayed_node(node, root, ino);
 
-               /* Cached in the inode and can be accessed */
-               refcount_set(&node->refs, 2);
+       /* cached in the btrfs inode and can be accessed */
+       refcount_set(&node->refs, 2);
 
-               spin_lock(&root->inode_lock);
-               ret = xa_insert(&root->delayed_nodes, ino, node, GFP_NOFS);
-               if (ret) {
-                       spin_unlock(&root->inode_lock);
-                       kmem_cache_free(delayed_node_cache, node);
-                       if (ret != -EBUSY)
-                               return ERR_PTR(ret);
-               }
-       } while (ret);
+       ret = radix_tree_preload(GFP_NOFS);
+       if (ret) {
+               kmem_cache_free(delayed_node_cache, node);
+               return ERR_PTR(ret);
+       }
+
+       spin_lock(&root->inode_lock);
+       ret = radix_tree_insert(&root->delayed_nodes_tree, ino, node);
+       if (ret == -EEXIST) {
+               spin_unlock(&root->inode_lock);
+               kmem_cache_free(delayed_node_cache, node);
+               radix_tree_preload_end();
+               goto again;
+       }
        btrfs_inode->delayed_node = node;
        spin_unlock(&root->inode_lock);
+       radix_tree_preload_end();
 
        return node;
 }
@@ -270,7 +276,8 @@ static void __btrfs_release_delayed_node(
                 * back up.  We can delete it now.
                 */
                ASSERT(refcount_read(&delayed_node->refs) == 0);
-               xa_erase(&root->delayed_nodes, delayed_node->inode_id);
+               radix_tree_delete(&root->delayed_nodes_tree,
+                                 delayed_node->inode_id);
                spin_unlock(&root->inode_lock);
                kmem_cache_free(delayed_node_cache, delayed_node);
        }
@@ -1863,35 +1870,34 @@ void btrfs_kill_delayed_inode_items(struct btrfs_inode *inode)
 
 void btrfs_kill_all_delayed_nodes(struct btrfs_root *root)
 {
-       unsigned long index = 0;
-       struct btrfs_delayed_node *delayed_node;
+       u64 inode_id = 0;
        struct btrfs_delayed_node *delayed_nodes[8];
+       int i, n;
 
        while (1) {
-               int n = 0;
-
                spin_lock(&root->inode_lock);
-               if (xa_empty(&root->delayed_nodes)) {
+               n = radix_tree_gang_lookup(&root->delayed_nodes_tree,
+                                          (void **)delayed_nodes, inode_id,
+                                          ARRAY_SIZE(delayed_nodes));
+               if (!n) {
                        spin_unlock(&root->inode_lock);
-                       return;
+                       break;
                }
 
-               xa_for_each_start(&root->delayed_nodes, index, delayed_node, index) {
+               inode_id = delayed_nodes[n - 1]->inode_id + 1;
+               for (i = 0; i < n; i++) {
                        /*
                         * Don't increase refs in case the node is dead and
                         * about to be removed from the tree in the loop below
                         */
-                       if (refcount_inc_not_zero(&delayed_node->refs)) {
-                               delayed_nodes[n] = delayed_node;
-                               n++;
-                       }
-                       if (n >= ARRAY_SIZE(delayed_nodes))
-                               break;
+                       if (!refcount_inc_not_zero(&delayed_nodes[i]->refs))
+                               delayed_nodes[i] = NULL;
                }
-               index++;
                spin_unlock(&root->inode_lock);
 
-               for (int i = 0; i < n; i++) {
+               for (i = 0; i < n; i++) {
+                       if (!delayed_nodes[i])
+                               continue;
                        __btrfs_kill_delayed_node(delayed_nodes[i]);
                        btrfs_release_delayed_node(delayed_nodes[i]);
                }
index 64d9299..1b23d80 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <linux/fs.h>
 #include <linux/blkdev.h>
+#include <linux/radix-tree.h>
 #include <linux/writeback.h>
 #include <linux/workqueue.h>
 #include <linux/kthread.h>
@@ -485,7 +486,7 @@ static int csum_dirty_subpage_buffers(struct btrfs_fs_info *fs_info,
                uptodate = btrfs_subpage_test_uptodate(fs_info, page, cur,
                                                       fs_info->nodesize);
 
-               /* A dirty eb shouldn't disappear from extent_buffers */
+               /* A dirty eb shouldn't disappear from buffer_radix */
                if (WARN_ON(!eb))
                        return -EUCLEAN;
 
@@ -1156,7 +1157,7 @@ static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info,
        root->nr_delalloc_inodes = 0;
        root->nr_ordered_extents = 0;
        root->inode_tree = RB_ROOT;
-       xa_init_flags(&root->delayed_nodes, GFP_ATOMIC);
+       INIT_RADIX_TREE(&root->delayed_nodes_tree, GFP_ATOMIC);
 
        btrfs_init_root_block_rsv(root);
 
@@ -1208,9 +1209,9 @@ static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info,
        btrfs_qgroup_init_swapped_blocks(&root->swapped_blocks);
 #ifdef CONFIG_BTRFS_DEBUG
        INIT_LIST_HEAD(&root->leak_list);
-       spin_lock(&fs_info->fs_roots_lock);
+       spin_lock(&fs_info->fs_roots_radix_lock);
        list_add_tail(&root->leak_list, &fs_info->allocated_roots);
-       spin_unlock(&fs_info->fs_roots_lock);
+       spin_unlock(&fs_info->fs_roots_radix_lock);
 #endif
 }
 
@@ -1657,11 +1658,12 @@ static struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
 {
        struct btrfs_root *root;
 
-       spin_lock(&fs_info->fs_roots_lock);
-       root = xa_load(&fs_info->fs_roots, (unsigned long)root_id);
+       spin_lock(&fs_info->fs_roots_radix_lock);
+       root = radix_tree_lookup(&fs_info->fs_roots_radix,
+                                (unsigned long)root_id);
        if (root)
                root = btrfs_grab_root(root);
-       spin_unlock(&fs_info->fs_roots_lock);
+       spin_unlock(&fs_info->fs_roots_radix_lock);
        return root;
 }
 
@@ -1703,14 +1705,20 @@ int btrfs_insert_fs_root(struct btrfs_fs_info *fs_info,
 {
        int ret;
 
-       spin_lock(&fs_info->fs_roots_lock);
-       ret = xa_insert(&fs_info->fs_roots, (unsigned long)root->root_key.objectid,
-                       root, GFP_NOFS);
+       ret = radix_tree_preload(GFP_NOFS);
+       if (ret)
+               return ret;
+
+       spin_lock(&fs_info->fs_roots_radix_lock);
+       ret = radix_tree_insert(&fs_info->fs_roots_radix,
+                               (unsigned long)root->root_key.objectid,
+                               root);
        if (ret == 0) {
                btrfs_grab_root(root);
-               set_bit(BTRFS_ROOT_REGISTERED, &root->state);
+               set_bit(BTRFS_ROOT_IN_RADIX, &root->state);
        }
-       spin_unlock(&fs_info->fs_roots_lock);
+       spin_unlock(&fs_info->fs_roots_radix_lock);
+       radix_tree_preload_end();
 
        return ret;
 }
@@ -2340,9 +2348,9 @@ void btrfs_put_root(struct btrfs_root *root)
                btrfs_drew_lock_destroy(&root->snapshot_lock);
                free_root_extent_buffers(root);
 #ifdef CONFIG_BTRFS_DEBUG
-               spin_lock(&root->fs_info->fs_roots_lock);
+               spin_lock(&root->fs_info->fs_roots_radix_lock);
                list_del_init(&root->leak_list);
-               spin_unlock(&root->fs_info->fs_roots_lock);
+               spin_unlock(&root->fs_info->fs_roots_radix_lock);
 #endif
                kfree(root);
        }
@@ -2350,21 +2358,28 @@ void btrfs_put_root(struct btrfs_root *root)
 
 void btrfs_free_fs_roots(struct btrfs_fs_info *fs_info)
 {
-       struct btrfs_root *root;
-       unsigned long index = 0;
+       int ret;
+       struct btrfs_root *gang[8];
+       int i;
 
        while (!list_empty(&fs_info->dead_roots)) {
-               root = list_entry(fs_info->dead_roots.next,
-                                 struct btrfs_root, root_list);
-               list_del(&root->root_list);
+               gang[0] = list_entry(fs_info->dead_roots.next,
+                                    struct btrfs_root, root_list);
+               list_del(&gang[0]->root_list);
 
-               if (test_bit(BTRFS_ROOT_REGISTERED, &root->state))
-                       btrfs_drop_and_free_fs_root(fs_info, root);
-               btrfs_put_root(root);
+               if (test_bit(BTRFS_ROOT_IN_RADIX, &gang[0]->state))
+                       btrfs_drop_and_free_fs_root(fs_info, gang[0]);
+               btrfs_put_root(gang[0]);
        }
 
-       xa_for_each(&fs_info->fs_roots, index, root) {
-               btrfs_drop_and_free_fs_root(fs_info, root);
+       while (1) {
+               ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix,
+                                            (void **)gang, 0,
+                                            ARRAY_SIZE(gang));
+               if (!ret)
+                       break;
+               for (i = 0; i < ret; i++)
+                       btrfs_drop_and_free_fs_root(fs_info, gang[i]);
        }
 }
 
@@ -3132,8 +3147,8 @@ static int __cold init_tree_roots(struct btrfs_fs_info *fs_info)
 
 void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
 {
-       xa_init_flags(&fs_info->fs_roots, GFP_ATOMIC);
-       xa_init_flags(&fs_info->extent_buffers, GFP_ATOMIC);
+       INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC);
+       INIT_RADIX_TREE(&fs_info->buffer_radix, GFP_ATOMIC);
        INIT_LIST_HEAD(&fs_info->trans_list);
        INIT_LIST_HEAD(&fs_info->dead_roots);
        INIT_LIST_HEAD(&fs_info->delayed_iputs);
@@ -3141,7 +3156,7 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
        INIT_LIST_HEAD(&fs_info->caching_block_groups);
        spin_lock_init(&fs_info->delalloc_root_lock);
        spin_lock_init(&fs_info->trans_lock);
-       spin_lock_init(&fs_info->fs_roots_lock);
+       spin_lock_init(&fs_info->fs_roots_radix_lock);
        spin_lock_init(&fs_info->delayed_iput_lock);
        spin_lock_init(&fs_info->defrag_inodes_lock);
        spin_lock_init(&fs_info->super_lock);
@@ -3372,7 +3387,7 @@ int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info)
        /*
         * btrfs_find_orphan_roots() is responsible for finding all the dead
         * roots (with 0 refs), flag them with BTRFS_ROOT_DEAD_TREE and load
-        * them into the fs_info->fs_roots. This must be done before
+        * them into the fs_info->fs_roots_radix tree. This must be done before
         * calling btrfs_orphan_cleanup() on the tree root. If we don't do it
         * first, then btrfs_orphan_cleanup() will delete a dead root's orphan
         * item before the root's tree is deleted - this means that if we unmount
@@ -4497,11 +4512,12 @@ void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info,
 {
        bool drop_ref = false;
 
-       spin_lock(&fs_info->fs_roots_lock);
-       xa_erase(&fs_info->fs_roots, (unsigned long)root->root_key.objectid);
-       if (test_and_clear_bit(BTRFS_ROOT_REGISTERED, &root->state))
+       spin_lock(&fs_info->fs_roots_radix_lock);
+       radix_tree_delete(&fs_info->fs_roots_radix,
+                         (unsigned long)root->root_key.objectid);
+       if (test_and_clear_bit(BTRFS_ROOT_IN_RADIX, &root->state))
                drop_ref = true;
-       spin_unlock(&fs_info->fs_roots_lock);
+       spin_unlock(&fs_info->fs_roots_radix_lock);
 
        if (BTRFS_FS_ERROR(fs_info)) {
                ASSERT(root->log_root == NULL);
@@ -4517,48 +4533,50 @@ void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info,
 
 int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info)
 {
-       struct btrfs_root *roots[8];
-       unsigned long index = 0;
-       int i;
+       u64 root_objectid = 0;
+       struct btrfs_root *gang[8];
+       int i = 0;
        int err = 0;
-       int grabbed;
+       unsigned int ret = 0;
 
        while (1) {
-               struct btrfs_root *root;
-
-               spin_lock(&fs_info->fs_roots_lock);
-               if (!xa_find(&fs_info->fs_roots, &index, ULONG_MAX, XA_PRESENT)) {
-                       spin_unlock(&fs_info->fs_roots_lock);
-                       return err;
+               spin_lock(&fs_info->fs_roots_radix_lock);
+               ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix,
+                                            (void **)gang, root_objectid,
+                                            ARRAY_SIZE(gang));
+               if (!ret) {
+                       spin_unlock(&fs_info->fs_roots_radix_lock);
+                       break;
                }
+               root_objectid = gang[ret - 1]->root_key.objectid + 1;
 
-               grabbed = 0;
-               xa_for_each_start(&fs_info->fs_roots, index, root, index) {
-                       /* Avoid grabbing roots in dead_roots */
-                       if (btrfs_root_refs(&root->root_item) > 0)
-                               roots[grabbed++] = btrfs_grab_root(root);
-                       if (grabbed >= ARRAY_SIZE(roots))
-                               break;
+               for (i = 0; i < ret; i++) {
+                       /* Avoid to grab roots in dead_roots */
+                       if (btrfs_root_refs(&gang[i]->root_item) == 0) {
+                               gang[i] = NULL;
+                               continue;
+                       }
+                       /* grab all the search result for later use */
+                       gang[i] = btrfs_grab_root(gang[i]);
                }
-               spin_unlock(&fs_info->fs_roots_lock);
+               spin_unlock(&fs_info->fs_roots_radix_lock);
 
-               for (i = 0; i < grabbed; i++) {
-                       if (!roots[i])
+               for (i = 0; i < ret; i++) {
+                       if (!gang[i])
                                continue;
-                       index = roots[i]->root_key.objectid;
-                       err = btrfs_orphan_cleanup(roots[i]);
+                       root_objectid = gang[i]->root_key.objectid;
+                       err = btrfs_orphan_cleanup(gang[i]);
                        if (err)
-                               goto out;
-                       btrfs_put_root(roots[i]);
+                               break;
+                       btrfs_put_root(gang[i]);
                }
-               index++;
+               root_objectid++;
        }
 
-out:
-       /* Release the roots that remain uncleaned due to error */
-       for (; i < grabbed; i++) {
-               if (roots[i])
-                       btrfs_put_root(roots[i]);
+       /* release the uncleaned roots due to error */
+       for (; i < ret; i++) {
+               if (gang[i])
+                       btrfs_put_root(gang[i]);
        }
        return err;
 }
@@ -4877,28 +4895,31 @@ static void btrfs_error_commit_super(struct btrfs_fs_info *fs_info)
 
 static void btrfs_drop_all_logs(struct btrfs_fs_info *fs_info)
 {
-       unsigned long index = 0;
-       int grabbed = 0;
-       struct btrfs_root *roots[8];
+       struct btrfs_root *gang[8];
+       u64 root_objectid = 0;
+       int ret;
+
+       spin_lock(&fs_info->fs_roots_radix_lock);
+       while ((ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix,
+                                            (void **)gang, root_objectid,
+                                            ARRAY_SIZE(gang))) != 0) {
+               int i;
 
-       spin_lock(&fs_info->fs_roots_lock);
-       while ((grabbed = xa_extract(&fs_info->fs_roots, (void **)roots, index,
-                                    ULONG_MAX, 8, XA_PRESENT))) {
-               for (int i = 0; i < grabbed; i++)
-                       roots[i] = btrfs_grab_root(roots[i]);
-               spin_unlock(&fs_info->fs_roots_lock);
+               for (i = 0; i < ret; i++)
+                       gang[i] = btrfs_grab_root(gang[i]);
+               spin_unlock(&fs_info->fs_roots_radix_lock);
 
-               for (int i = 0; i < grabbed; i++) {
-                       if (!roots[i])
+               for (i = 0; i < ret; i++) {
+                       if (!gang[i])
                                continue;
-                       index = roots[i]->root_key.objectid;
-                       btrfs_free_log(NULL, roots[i]);
-                       btrfs_put_root(roots[i]);
+                       root_objectid = gang[i]->root_key.objectid;
+                       btrfs_free_log(NULL, gang[i]);
+                       btrfs_put_root(gang[i]);
                }
-               index++;
-               spin_lock(&fs_info->fs_roots_lock);
+               root_objectid++;
+               spin_lock(&fs_info->fs_roots_radix_lock);
        }
-       spin_unlock(&fs_info->fs_roots_lock);
+       spin_unlock(&fs_info->fs_roots_radix_lock);
        btrfs_free_log_root_tree(NULL, fs_info);
 }
 
index 0867c5c..a3afc15 100644 (file)
@@ -3832,7 +3832,7 @@ static int do_allocation_zoned(struct btrfs_block_group *block_group,
               block_group->start == fs_info->data_reloc_bg ||
               fs_info->data_reloc_bg == 0);
 
-       if (block_group->ro) {
+       if (block_group->ro || block_group->zoned_data_reloc_ongoing) {
                ret = 1;
                goto out;
        }
@@ -3894,8 +3894,24 @@ static int do_allocation_zoned(struct btrfs_block_group *block_group,
 out:
        if (ret && ffe_ctl->for_treelog)
                fs_info->treelog_bg = 0;
-       if (ret && ffe_ctl->for_data_reloc)
+       if (ret && ffe_ctl->for_data_reloc &&
+           fs_info->data_reloc_bg == block_group->start) {
+               /*
+                * Do not allow further allocations from this block group.
+                * Compared to increasing the ->ro, setting the
+                * ->zoned_data_reloc_ongoing flag still allows nocow
+                *  writers to come in. See btrfs_inc_nocow_writers().
+                *
+                * We need to disable an allocation to avoid an allocation of
+                * regular (non-relocation data) extent. With mix of relocation
+                * extents and regular extents, we can dispatch WRITE commands
+                * (for relocation extents) and ZONE APPEND commands (for
+                * regular extents) at the same time to the same zone, which
+                * easily break the write pointer.
+                */
+               block_group->zoned_data_reloc_ongoing = 1;
                fs_info->data_reloc_bg = 0;
+       }
        spin_unlock(&fs_info->relocation_bg_lock);
        spin_unlock(&fs_info->treelog_bg_lock);
        spin_unlock(&block_group->lock);
@@ -5813,7 +5829,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref, int for_reloc)
        btrfs_qgroup_convert_reserved_meta(root, INT_MAX);
        btrfs_qgroup_free_meta_all_pertrans(root);
 
-       if (test_bit(BTRFS_ROOT_REGISTERED, &root->state))
+       if (test_bit(BTRFS_ROOT_IN_RADIX, &root->state))
                btrfs_add_dropped_root(trans, root);
        else
                btrfs_put_root(root);
index 8f6b544..9eb3056 100644 (file)
@@ -2966,7 +2966,7 @@ static void begin_page_read(struct btrfs_fs_info *fs_info, struct page *page)
 }
 
 /*
- * Find extent buffer for a given bytenr.
+ * Find extent buffer for a givne bytenr.
  *
  * This is for end_bio_extent_readpage(), thus we can't do any unsafe locking
  * in endio context.
@@ -2985,9 +2985,11 @@ static struct extent_buffer *find_extent_buffer_readpage(
                return (struct extent_buffer *)page->private;
        }
 
-       /* For subpage case, we need to lookup extent buffer xarray */
-       eb = xa_load(&fs_info->extent_buffers,
-                    bytenr >> fs_info->sectorsize_bits);
+       /* For subpage case, we need to lookup buffer radix tree */
+       rcu_read_lock();
+       eb = radix_tree_lookup(&fs_info->buffer_radix,
+                              bytenr >> fs_info->sectorsize_bits);
+       rcu_read_unlock();
        ASSERT(eb);
        return eb;
 }
@@ -3357,7 +3359,7 @@ static int calc_bio_boundaries(struct btrfs_bio_ctrl *bio_ctrl,
 static int alloc_new_bio(struct btrfs_inode *inode,
                         struct btrfs_bio_ctrl *bio_ctrl,
                         struct writeback_control *wbc,
-                        unsigned int opf,
+                        blk_opf_t opf,
                         bio_end_io_t end_io_func,
                         u64 disk_bytenr, u32 offset, u64 file_offset,
                         enum btrfs_compression_type compress_type)
@@ -3437,7 +3439,7 @@ error:
  * @prev_bio_flags:  flags of previous bio to see if we can merge the current one
  * @compress_type:   compress type for current bio
  */
-static int submit_extent_page(unsigned int opf,
+static int submit_extent_page(blk_opf_t opf,
                              struct writeback_control *wbc,
                              struct btrfs_bio_ctrl *bio_ctrl,
                              struct page *page, u64 disk_bytenr,
@@ -3615,7 +3617,7 @@ __get_extent_map(struct inode *inode, struct page *page, size_t pg_offset,
  */
 static int btrfs_do_readpage(struct page *page, struct extent_map **em_cached,
                      struct btrfs_bio_ctrl *bio_ctrl,
-                     unsigned int read_flags, u64 *prev_em_start)
+                     blk_opf_t read_flags, u64 *prev_em_start)
 {
        struct inode *inode = page->mapping->host;
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
@@ -3983,8 +3985,8 @@ static noinline_for_stack int __extent_writepage_io(struct btrfs_inode *inode,
        int saved_ret = 0;
        int ret = 0;
        int nr = 0;
-       u32 opf = REQ_OP_WRITE;
-       const unsigned int write_flags = wbc_to_write_flags(wbc);
+       enum req_op op = REQ_OP_WRITE;
+       const blk_opf_t write_flags = wbc_to_write_flags(wbc);
        bool has_error = false;
        bool compressed;
 
@@ -4058,7 +4060,7 @@ static noinline_for_stack int __extent_writepage_io(struct btrfs_inode *inode,
                iosize = min(min(em_end, end + 1), dirty_range_end) - cur;
 
                if (btrfs_use_zone_append(inode, em->block_start))
-                       opf = REQ_OP_ZONE_APPEND;
+                       op = REQ_OP_ZONE_APPEND;
 
                free_extent_map(em);
                em = NULL;
@@ -4094,7 +4096,7 @@ static noinline_for_stack int __extent_writepage_io(struct btrfs_inode *inode,
                 */
                btrfs_page_clear_dirty(fs_info, page, cur, iosize);
 
-               ret = submit_extent_page(opf | write_flags, wbc,
+               ret = submit_extent_page(op | write_flags, wbc,
                                         &epd->bio_ctrl, page,
                                         disk_bytenr, iosize,
                                         cur - page_offset(page),
@@ -4435,8 +4437,8 @@ static struct extent_buffer *find_extent_buffer_nolock(
        struct extent_buffer *eb;
 
        rcu_read_lock();
-       eb = xa_load(&fs_info->extent_buffers,
-                    start >> fs_info->sectorsize_bits);
+       eb = radix_tree_lookup(&fs_info->buffer_radix,
+                              start >> fs_info->sectorsize_bits);
        if (eb && atomic_inc_not_zero(&eb->refs)) {
                rcu_read_unlock();
                return eb;
@@ -4575,7 +4577,7 @@ static int write_one_subpage_eb(struct extent_buffer *eb,
 {
        struct btrfs_fs_info *fs_info = eb->fs_info;
        struct page *page = eb->pages[0];
-       unsigned int write_flags = wbc_to_write_flags(wbc) | REQ_META;
+       blk_opf_t write_flags = wbc_to_write_flags(wbc) | REQ_META;
        bool no_dirty_ebs = false;
        int ret;
 
@@ -4620,7 +4622,7 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb,
 {
        u64 disk_bytenr = eb->start;
        int i, num_pages;
-       unsigned int write_flags = wbc_to_write_flags(wbc) | REQ_META;
+       blk_opf_t write_flags = wbc_to_write_flags(wbc) | REQ_META;
        int ret = 0;
 
        prepare_eb_write(eb);
@@ -5241,13 +5243,14 @@ int extent_writepages(struct address_space *mapping,
         */
        btrfs_zoned_data_reloc_lock(BTRFS_I(inode));
        ret = extent_write_cache_pages(mapping, wbc, &epd);
-       btrfs_zoned_data_reloc_unlock(BTRFS_I(inode));
        ASSERT(ret <= 0);
        if (ret < 0) {
+               btrfs_zoned_data_reloc_unlock(BTRFS_I(inode));
                end_write_bio(&epd, ret);
                return ret;
        }
        flush_write_bio(&epd);
+       btrfs_zoned_data_reloc_unlock(BTRFS_I(inode));
        return ret;
 }
 
@@ -6128,22 +6131,24 @@ struct extent_buffer *alloc_test_extent_buffer(struct btrfs_fs_info *fs_info,
        if (!eb)
                return ERR_PTR(-ENOMEM);
        eb->fs_info = fs_info;
-
-       do {
-               ret = xa_insert(&fs_info->extent_buffers,
-                               start >> fs_info->sectorsize_bits,
-                               eb, GFP_NOFS);
-               if (ret == -ENOMEM) {
-                       exists = ERR_PTR(ret);
+again:
+       ret = radix_tree_preload(GFP_NOFS);
+       if (ret) {
+               exists = ERR_PTR(ret);
+               goto free_eb;
+       }
+       spin_lock(&fs_info->buffer_lock);
+       ret = radix_tree_insert(&fs_info->buffer_radix,
+                               start >> fs_info->sectorsize_bits, eb);
+       spin_unlock(&fs_info->buffer_lock);
+       radix_tree_preload_end();
+       if (ret == -EEXIST) {
+               exists = find_extent_buffer(fs_info, start);
+               if (exists)
                        goto free_eb;
-               }
-               if (ret == -EBUSY) {
-                       exists = find_extent_buffer(fs_info, start);
-                       if (exists)
-                               goto free_eb;
-               }
-       } while (ret);
-
+               else
+                       goto again;
+       }
        check_buffer_tree_ref(eb);
        set_bit(EXTENT_BUFFER_IN_TREE, &eb->bflags);
 
@@ -6318,22 +6323,25 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
        }
        if (uptodate)
                set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
-
-       do {
-               ret = xa_insert(&fs_info->extent_buffers,
-                               start >> fs_info->sectorsize_bits,
-                               eb, GFP_NOFS);
-               if (ret == -ENOMEM) {
-                       exists = ERR_PTR(ret);
+again:
+       ret = radix_tree_preload(GFP_NOFS);
+       if (ret) {
+               exists = ERR_PTR(ret);
+               goto free_eb;
+       }
+
+       spin_lock(&fs_info->buffer_lock);
+       ret = radix_tree_insert(&fs_info->buffer_radix,
+                               start >> fs_info->sectorsize_bits, eb);
+       spin_unlock(&fs_info->buffer_lock);
+       radix_tree_preload_end();
+       if (ret == -EEXIST) {
+               exists = find_extent_buffer(fs_info, start);
+               if (exists)
                        goto free_eb;
-               }
-               if (ret == -EBUSY) {
-                       exists = find_extent_buffer(fs_info, start);
-                       if (exists)
-                               goto free_eb;
-               }
-       } while (ret);
-
+               else
+                       goto again;
+       }
        /* add one reference for the tree */
        check_buffer_tree_ref(eb);
        set_bit(EXTENT_BUFFER_IN_TREE, &eb->bflags);
@@ -6378,8 +6386,10 @@ static int release_extent_buffer(struct extent_buffer *eb)
 
                        spin_unlock(&eb->refs_lock);
 
-                       xa_erase(&fs_info->extent_buffers,
-                                eb->start >> fs_info->sectorsize_bits);
+                       spin_lock(&fs_info->buffer_lock);
+                       radix_tree_delete(&fs_info->buffer_radix,
+                                         eb->start >> fs_info->sectorsize_bits);
+                       spin_unlock(&fs_info->buffer_lock);
                } else {
                        spin_unlock(&eb->refs_lock);
                }
@@ -7324,25 +7334,42 @@ void memmove_extent_buffer(const struct extent_buffer *dst,
        }
 }
 
+#define GANG_LOOKUP_SIZE       16
 static struct extent_buffer *get_next_extent_buffer(
                struct btrfs_fs_info *fs_info, struct page *page, u64 bytenr)
 {
-       struct extent_buffer *eb;
-       unsigned long index;
+       struct extent_buffer *gang[GANG_LOOKUP_SIZE];
+       struct extent_buffer *found = NULL;
        u64 page_start = page_offset(page);
+       u64 cur = page_start;
 
        ASSERT(in_range(bytenr, page_start, PAGE_SIZE));
        lockdep_assert_held(&fs_info->buffer_lock);
 
-       xa_for_each_start(&fs_info->extent_buffers, index, eb,
-                         page_start >> fs_info->sectorsize_bits) {
-               if (in_range(eb->start, page_start, PAGE_SIZE))
-                       return eb;
-               else if (eb->start >= page_start + PAGE_SIZE)
-                       /* Already beyond page end */
-                       return NULL;
+       while (cur < page_start + PAGE_SIZE) {
+               int ret;
+               int i;
+
+               ret = radix_tree_gang_lookup(&fs_info->buffer_radix,
+                               (void **)gang, cur >> fs_info->sectorsize_bits,
+                               min_t(unsigned int, GANG_LOOKUP_SIZE,
+                                     PAGE_SIZE / fs_info->nodesize));
+               if (ret == 0)
+                       goto out;
+               for (i = 0; i < ret; i++) {
+                       /* Already beyond page end */
+                       if (gang[i]->start >= page_start + PAGE_SIZE)
+                               goto out;
+                       /* Found one */
+                       if (gang[i]->start >= bytenr) {
+                               found = gang[i];
+                               goto out;
+                       }
+               }
+               cur = gang[ret - 1]->start + gang[ret - 1]->len;
        }
-       return NULL;
+out:
+       return found;
 }
 
 static int try_release_subpage_extent_buffer(struct page *page)
index 1fd827b..9dfde1a 100644 (file)
@@ -2323,25 +2323,62 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
         */
        btrfs_inode_unlock(inode, BTRFS_ILOCK_MMAP);
 
-       if (ret != BTRFS_NO_LOG_SYNC) {
+       if (ret == BTRFS_NO_LOG_SYNC) {
+               ret = btrfs_end_transaction(trans);
+               goto out;
+       }
+
+       /* We successfully logged the inode, attempt to sync the log. */
+       if (!ret) {
+               ret = btrfs_sync_log(trans, root, &ctx);
                if (!ret) {
-                       ret = btrfs_sync_log(trans, root, &ctx);
-                       if (!ret) {
-                               ret = btrfs_end_transaction(trans);
-                               goto out;
-                       }
-               }
-               if (!full_sync) {
-                       ret = btrfs_wait_ordered_range(inode, start, len);
-                       if (ret) {
-                               btrfs_end_transaction(trans);
-                               goto out;
-                       }
+                       ret = btrfs_end_transaction(trans);
+                       goto out;
                }
-               ret = btrfs_commit_transaction(trans);
-       } else {
+       }
+
+       /*
+        * At this point we need to commit the transaction because we had
+        * btrfs_need_log_full_commit() or some other error.
+        *
+        * If we didn't do a full sync we have to stop the trans handle, wait on
+        * the ordered extents, start it again and commit the transaction.  If
+        * we attempt to wait on the ordered extents here we could deadlock with
+        * something like fallocate() that is holding the extent lock trying to
+        * start a transaction while some other thread is trying to commit the
+        * transaction while we (fsync) are currently holding the transaction
+        * open.
+        */
+       if (!full_sync) {
                ret = btrfs_end_transaction(trans);
+               if (ret)
+                       goto out;
+               ret = btrfs_wait_ordered_range(inode, start, len);
+               if (ret)
+                       goto out;
+
+               /*
+                * This is safe to use here because we're only interested in
+                * making sure the transaction that had the ordered extents is
+                * committed.  We aren't waiting on anything past this point,
+                * we're purely getting the transaction and committing it.
+                */
+               trans = btrfs_attach_transaction_barrier(root);
+               if (IS_ERR(trans)) {
+                       ret = PTR_ERR(trans);
+
+                       /*
+                        * We committed the transaction and there's no currently
+                        * running transaction, this means everything we care
+                        * about made it to disk and we are done.
+                        */
+                       if (ret == -ENOENT)
+                               ret = 0;
+                       goto out;
+               }
        }
+
+       ret = btrfs_commit_transaction(trans);
 out:
        ASSERT(list_empty(&ctx.list));
        err = file_check_and_advance_wb_err(file);
@@ -2719,7 +2756,8 @@ int btrfs_replace_file_extents(struct btrfs_inode *inode,
 
        ret = btrfs_block_rsv_migrate(&fs_info->trans_block_rsv, rsv,
                                      min_size, false);
-       BUG_ON(ret);
+       if (WARN_ON(ret))
+               goto out_trans;
        trans->block_rsv = rsv;
 
        cur_offset = start;
@@ -2803,6 +2841,25 @@ int btrfs_replace_file_extents(struct btrfs_inode *inode,
                        extent_info->file_offset += replace_len;
                }
 
+               /*
+                * We are releasing our handle on the transaction, balance the
+                * dirty pages of the btree inode and flush delayed items, and
+                * then get a new transaction handle, which may now point to a
+                * new transaction in case someone else may have committed the
+                * transaction we used to replace/drop file extent items. So
+                * bump the inode's iversion and update mtime and ctime except
+                * if we are called from a dedupe context. This is because a
+                * power failure/crash may happen after the transaction is
+                * committed and before we finish replacing/dropping all the
+                * file extent items we need.
+                */
+               inode_inc_iversion(&inode->vfs_inode);
+
+               if (!extent_info || extent_info->update_times) {
+                       inode->vfs_inode.i_mtime = current_time(&inode->vfs_inode);
+                       inode->vfs_inode.i_ctime = inode->vfs_inode.i_mtime;
+               }
+
                ret = btrfs_update_inode(trans, root, inode);
                if (ret)
                        break;
@@ -2819,7 +2876,8 @@ int btrfs_replace_file_extents(struct btrfs_inode *inode,
 
                ret = btrfs_block_rsv_migrate(&fs_info->trans_block_rsv,
                                              rsv, min_size, false);
-               BUG_ON(ret);    /* shouldn't happen */
+               if (WARN_ON(ret))
+                       break;
                trans->block_rsv = rsv;
 
                cur_offset = drop_args.drop_end;
index 5f41d86..11a52db 100644 (file)
@@ -485,7 +485,7 @@ struct async_chunk {
        struct page *locked_page;
        u64 start;
        u64 end;
-       unsigned int write_flags;
+       blk_opf_t write_flags;
        struct list_head extents;
        struct cgroup_subsys_state *blkcg_css;
        struct btrfs_work work;
@@ -1435,7 +1435,7 @@ static int cow_file_range_async(struct btrfs_inode *inode,
        int i;
        bool should_compress;
        unsigned nofs_flag;
-       const unsigned int write_flags = wbc_to_write_flags(wbc);
+       const blk_opf_t write_flags = wbc_to_write_flags(wbc);
 
        unlock_extent(&inode->io_tree, start, end);
 
@@ -3195,6 +3195,8 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
                                                ordered_extent->file_offset,
                                                ordered_extent->file_offset +
                                                logical_len);
+               btrfs_zoned_release_data_reloc_bg(fs_info, ordered_extent->disk_bytenr,
+                                                 ordered_extent->disk_num_bytes);
        } else {
                BUG_ON(root == fs_info->tree_root);
                ret = insert_ordered_extent_file_extent(trans, ordered_extent);
@@ -3576,7 +3578,6 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
        u64 last_objectid = 0;
        int ret = 0, nr_unlink = 0;
 
-       /* Bail out if the cleanup is already running. */
        if (test_and_set_bit(BTRFS_ROOT_ORPHAN_CLEANUP, &root->state))
                return 0;
 
@@ -3659,17 +3660,17 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
                         *
                         * btrfs_find_orphan_roots() ran before us, which has
                         * found all deleted roots and loaded them into
-                        * fs_info->fs_roots. So here we can find if an
+                        * fs_info->fs_roots_radix. So here we can find if an
                         * orphan item corresponds to a deleted root by looking
-                        * up the root from that xarray.
+                        * up the root from that radix tree.
                         */
 
-                       spin_lock(&fs_info->fs_roots_lock);
-                       dead_root = xa_load(&fs_info->fs_roots,
-                                           (unsigned long)found_key.objectid);
+                       spin_lock(&fs_info->fs_roots_radix_lock);
+                       dead_root = radix_tree_lookup(&fs_info->fs_roots_radix,
+                                                        (unsigned long)found_key.objectid);
                        if (dead_root && btrfs_root_refs(&dead_root->root_item) == 0)
                                is_dead_root = 1;
-                       spin_unlock(&fs_info->fs_roots_lock);
+                       spin_unlock(&fs_info->fs_roots_radix_lock);
 
                        if (is_dead_root) {
                                /* prevent this orphan from being found again */
@@ -3909,7 +3910,7 @@ cache_index:
         * cache.
         *
         * This is required for both inode re-read from disk and delayed inode
-        * in the delayed_nodes xarray.
+        * in delayed_nodes_tree.
         */
        if (BTRFS_I(inode)->last_trans == fs_info->generation)
                set_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
@@ -7679,7 +7680,19 @@ static int btrfs_dio_iomap_begin(struct inode *inode, loff_t start,
        if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags) ||
            em->block_start == EXTENT_MAP_INLINE) {
                free_extent_map(em);
-               ret = -ENOTBLK;
+               /*
+                * If we are in a NOWAIT context, return -EAGAIN in order to
+                * fallback to buffered IO. This is not only because we can
+                * block with buffered IO (no support for NOWAIT semantics at
+                * the moment) but also to avoid returning short reads to user
+                * space - this happens if we were able to read some data from
+                * previous non-compressed extents and then when we fallback to
+                * buffered IO, at btrfs_file_read_iter() by calling
+                * filemap_read(), we fail to fault in pages for the read buffer,
+                * in which case filemap_read() returns a short read (the number
+                * of bytes previously read is > 0, so it does not return -EFAULT).
+                */
+               ret = (flags & IOMAP_NOWAIT) ? -EAGAIN : -ENOTBLK;
                goto unlock_err;
        }
 
@@ -9891,6 +9904,7 @@ static struct btrfs_trans_handle *insert_prealloc_file_extent(
        extent_info.file_offset = file_offset;
        extent_info.extent_buf = (char *)&stack_fi;
        extent_info.is_new_extent = true;
+       extent_info.update_times = true;
        extent_info.qgroup_reserved = qgroup_released;
        extent_info.insertions = 0;
 
index 313d9d6..33461b4 100644 (file)
@@ -45,7 +45,6 @@ void __btrfs_tree_read_lock(struct extent_buffer *eb, enum btrfs_lock_nesting ne
                start_ns = ktime_get_ns();
 
        down_read_nested(&eb->lock, nest);
-       eb->lock_owner = current->pid;
        trace_btrfs_tree_read_lock(eb, start_ns);
 }
 
@@ -62,7 +61,6 @@ void btrfs_tree_read_lock(struct extent_buffer *eb)
 int btrfs_try_tree_read_lock(struct extent_buffer *eb)
 {
        if (down_read_trylock(&eb->lock)) {
-               eb->lock_owner = current->pid;
                trace_btrfs_try_tree_read_lock(eb);
                return 1;
        }
@@ -90,7 +88,6 @@ int btrfs_try_tree_write_lock(struct extent_buffer *eb)
 void btrfs_tree_read_unlock(struct extent_buffer *eb)
 {
        trace_btrfs_tree_read_unlock(eb);
-       eb->lock_owner = 0;
        up_read(&eb->lock);
 }
 
index a5b623e..c520412 100644 (file)
@@ -1136,7 +1136,7 @@ static int rbio_add_io_sector(struct btrfs_raid_bio *rbio,
                              unsigned int stripe_nr,
                              unsigned int sector_nr,
                              unsigned long bio_max_len,
-                             unsigned int opf)
+                             enum req_op op)
 {
        const u32 sectorsize = rbio->bioc->fs_info->sectorsize;
        struct bio *last = bio_list->tail;
@@ -1181,7 +1181,7 @@ static int rbio_add_io_sector(struct btrfs_raid_bio *rbio,
 
        /* put a new bio on the list */
        bio = bio_alloc(stripe->dev->bdev, max(bio_max_len >> PAGE_SHIFT, 1UL),
-                       opf, GFP_NOFS);
+                       op, GFP_NOFS);
        bio->bi_iter.bi_sector = disk_start >> 9;
        bio->bi_private = rbio;
 
index c39f8b3..a3549d5 100644 (file)
@@ -344,6 +344,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
        int ret;
        const u64 len = olen_aligned;
        u64 last_dest_end = destoff;
+       u64 prev_extent_end = off;
 
        ret = -ENOMEM;
        buf = kvmalloc(fs_info->nodesize, GFP_KERNEL);
@@ -363,7 +364,6 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
        key.offset = off;
 
        while (1) {
-               u64 next_key_min_offset = key.offset + 1;
                struct btrfs_file_extent_item *extent;
                u64 extent_gen;
                int type;
@@ -431,14 +431,21 @@ process_slot:
                 * The first search might have left us at an extent item that
                 * ends before our target range's start, can happen if we have
                 * holes and NO_HOLES feature enabled.
+                *
+                * Subsequent searches may leave us on a file range we have
+                * processed before - this happens due to a race with ordered
+                * extent completion for a file range that is outside our source
+                * range, but that range was part of a file extent item that
+                * also covered a leading part of our source range.
                 */
-               if (key.offset + datal <= off) {
+               if (key.offset + datal <= prev_extent_end) {
                        path->slots[0]++;
                        goto process_slot;
                } else if (key.offset >= off + len) {
                        break;
                }
-               next_key_min_offset = key.offset + datal;
+
+               prev_extent_end = key.offset + datal;
                size = btrfs_item_size(leaf, slot);
                read_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf, slot),
                                   size);
@@ -489,6 +496,7 @@ process_slot:
                        clone_info.file_offset = new_key.offset;
                        clone_info.extent_buf = buf;
                        clone_info.is_new_extent = false;
+                       clone_info.update_times = !no_time_update;
                        ret = btrfs_replace_file_extents(BTRFS_I(inode), path,
                                        drop_start, new_key.offset + datal - 1,
                                        &clone_info, &trans);
@@ -550,7 +558,7 @@ process_slot:
                        break;
 
                btrfs_release_path(path);
-               key.offset = next_key_min_offset;
+               key.offset = prev_extent_end;
 
                if (fatal_signal_pending(current)) {
                        ret = -EINTR;
index fa56890..c7dea63 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/mount.h>
 #include <linux/xattr.h>
 #include <linux/posix_acl_xattr.h>
+#include <linux/radix-tree.h>
 #include <linux/vmalloc.h>
 #include <linux/string.h>
 #include <linux/compat.h>
@@ -127,7 +128,7 @@ struct send_ctx {
        struct list_head new_refs;
        struct list_head deleted_refs;
 
-       struct xarray name_cache;
+       struct radix_tree_root name_cache;
        struct list_head name_cache_list;
        int name_cache_size;
 
@@ -268,13 +269,14 @@ struct orphan_dir_info {
 struct name_cache_entry {
        struct list_head list;
        /*
-        * On 32bit kernels, xarray has only 32bit indices, but we need to
-        * handle 64bit inums. We use the lower 32bit of the 64bit inum to store
-        * it in the tree. If more than one inum would fall into the same entry,
-        * we use inum_aliases to store the additional entries. inum_aliases is
-        * also used to store entries with the same inum but different generations.
+        * radix_tree has only 32bit entries but we need to handle 64bit inums.
+        * We use the lower 32bit of the 64bit inum to store it in the tree. If
+        * more then one inum would fall into the same entry, we use radix_list
+        * to store the additional entries. radix_list is also used to store
+        * entries where two entries have the same inum but different
+        * generations.
         */
-       struct list_head inum_aliases;
+       struct list_head radix_list;
        u64 ino;
        u64 gen;
        u64 parent_ino;
@@ -2024,9 +2026,9 @@ out:
 }
 
 /*
- * Insert a name cache entry. On 32bit kernels the xarray index is 32bit,
+ * Insert a name cache entry. On 32bit kernels the radix tree index is 32bit,
  * so we need to do some special handling in case we have clashes. This function
- * takes care of this with the help of name_cache_entry::inum_aliases.
+ * takes care of this with the help of name_cache_entry::radix_list.
  * In case of error, nce is kfreed.
  */
 static int name_cache_insert(struct send_ctx *sctx,
@@ -2035,7 +2037,8 @@ static int name_cache_insert(struct send_ctx *sctx,
        int ret = 0;
        struct list_head *nce_head;
 
-       nce_head = xa_load(&sctx->name_cache, (unsigned long)nce->ino);
+       nce_head = radix_tree_lookup(&sctx->name_cache,
+                       (unsigned long)nce->ino);
        if (!nce_head) {
                nce_head = kmalloc(sizeof(*nce_head), GFP_KERNEL);
                if (!nce_head) {
@@ -2044,14 +2047,14 @@ static int name_cache_insert(struct send_ctx *sctx,
                }
                INIT_LIST_HEAD(nce_head);
 
-               ret = xa_insert(&sctx->name_cache, nce->ino, nce_head, GFP_KERNEL);
+               ret = radix_tree_insert(&sctx->name_cache, nce->ino, nce_head);
                if (ret < 0) {
                        kfree(nce_head);
                        kfree(nce);
                        return ret;
                }
        }
-       list_add_tail(&nce->inum_aliases, nce_head);
+       list_add_tail(&nce->radix_list, nce_head);
        list_add_tail(&nce->list, &sctx->name_cache_list);
        sctx->name_cache_size++;
 
@@ -2063,14 +2066,15 @@ static void name_cache_delete(struct send_ctx *sctx,
 {
        struct list_head *nce_head;
 
-       nce_head = xa_load(&sctx->name_cache, (unsigned long)nce->ino);
+       nce_head = radix_tree_lookup(&sctx->name_cache,
+                       (unsigned long)nce->ino);
        if (!nce_head) {
                btrfs_err(sctx->send_root->fs_info,
              "name_cache_delete lookup failed ino %llu cache size %d, leaking memory",
                        nce->ino, sctx->name_cache_size);
        }
 
-       list_del(&nce->inum_aliases);
+       list_del(&nce->radix_list);
        list_del(&nce->list);
        sctx->name_cache_size--;
 
@@ -2078,7 +2082,7 @@ static void name_cache_delete(struct send_ctx *sctx,
         * We may not get to the final release of nce_head if the lookup fails
         */
        if (nce_head && list_empty(nce_head)) {
-               xa_erase(&sctx->name_cache, (unsigned long)nce->ino);
+               radix_tree_delete(&sctx->name_cache, (unsigned long)nce->ino);
                kfree(nce_head);
        }
 }
@@ -2089,11 +2093,11 @@ static struct name_cache_entry *name_cache_search(struct send_ctx *sctx,
        struct list_head *nce_head;
        struct name_cache_entry *cur;
 
-       nce_head = xa_load(&sctx->name_cache, (unsigned long)ino);
+       nce_head = radix_tree_lookup(&sctx->name_cache, (unsigned long)ino);
        if (!nce_head)
                return NULL;
 
-       list_for_each_entry(cur, nce_head, inum_aliases) {
+       list_for_each_entry(cur, nce_head, radix_list) {
                if (cur->ino == ino && cur->gen == gen)
                        return cur;
        }
@@ -7518,7 +7522,7 @@ long btrfs_ioctl_send(struct inode *inode, struct btrfs_ioctl_send_args *arg)
 
        INIT_LIST_HEAD(&sctx->new_refs);
        INIT_LIST_HEAD(&sctx->deleted_refs);
-       xa_init_flags(&sctx->name_cache, GFP_KERNEL);
+       INIT_RADIX_TREE(&sctx->name_cache, GFP_KERNEL);
        INIT_LIST_HEAD(&sctx->name_cache_list);
 
        sctx->flags = arg->flags;
index 1591bfa..d8e56ed 100644 (file)
@@ -150,8 +150,8 @@ struct btrfs_fs_info *btrfs_alloc_dummy_fs_info(u32 nodesize, u32 sectorsize)
 
 void btrfs_free_dummy_fs_info(struct btrfs_fs_info *fs_info)
 {
-       unsigned long index;
-       struct extent_buffer *eb;
+       struct radix_tree_iter iter;
+       void **slot;
        struct btrfs_device *dev, *tmp;
 
        if (!fs_info)
@@ -163,9 +163,25 @@ void btrfs_free_dummy_fs_info(struct btrfs_fs_info *fs_info)
 
        test_mnt->mnt_sb->s_fs_info = NULL;
 
-       xa_for_each(&fs_info->extent_buffers, index, eb) {
+       spin_lock(&fs_info->buffer_lock);
+       radix_tree_for_each_slot(slot, &fs_info->buffer_radix, &iter, 0) {
+               struct extent_buffer *eb;
+
+               eb = radix_tree_deref_slot_protected(slot, &fs_info->buffer_lock);
+               if (!eb)
+                       continue;
+               /* Shouldn't happen but that kind of thinking creates CVE's */
+               if (radix_tree_exception(eb)) {
+                       if (radix_tree_deref_retry(eb))
+                               slot = radix_tree_iter_retry(&iter);
+                       continue;
+               }
+               slot = radix_tree_iter_resume(slot, &iter);
+               spin_unlock(&fs_info->buffer_lock);
                free_extent_buffer_stale(eb);
+               spin_lock(&fs_info->buffer_lock);
        }
+       spin_unlock(&fs_info->buffer_lock);
 
        btrfs_mapping_tree_free(&fs_info->mapping_tree);
        list_for_each_entry_safe(dev, tmp, &fs_info->fs_devices->devices,
@@ -186,7 +202,7 @@ void btrfs_free_dummy_root(struct btrfs_root *root)
        if (!root)
                return;
        /* Will be freed by btrfs_free_fs_roots */
-       if (WARN_ON(test_bit(BTRFS_ROOT_REGISTERED, &root->state)))
+       if (WARN_ON(test_bit(BTRFS_ROOT_IN_RADIX, &root->state)))
                return;
        btrfs_global_root_delete(root);
        btrfs_put_root(root);
index 06c0a95..875b801 100644 (file)
@@ -23,7 +23,7 @@
 #include "space-info.h"
 #include "zoned.h"
 
-#define BTRFS_ROOT_TRANS_TAG                           XA_MARK_0
+#define BTRFS_ROOT_TRANS_TAG 0
 
 /*
  * Transaction states and transitions
@@ -437,15 +437,15 @@ static int record_root_in_trans(struct btrfs_trans_handle *trans,
                 */
                smp_wmb();
 
-               spin_lock(&fs_info->fs_roots_lock);
+               spin_lock(&fs_info->fs_roots_radix_lock);
                if (root->last_trans == trans->transid && !force) {
-                       spin_unlock(&fs_info->fs_roots_lock);
+                       spin_unlock(&fs_info->fs_roots_radix_lock);
                        return 0;
                }
-               xa_set_mark(&fs_info->fs_roots,
-                           (unsigned long)root->root_key.objectid,
-                           BTRFS_ROOT_TRANS_TAG);
-               spin_unlock(&fs_info->fs_roots_lock);
+               radix_tree_tag_set(&fs_info->fs_roots_radix,
+                                  (unsigned long)root->root_key.objectid,
+                                  BTRFS_ROOT_TRANS_TAG);
+               spin_unlock(&fs_info->fs_roots_radix_lock);
                root->last_trans = trans->transid;
 
                /* this is pretty tricky.  We don't want to
@@ -487,9 +487,11 @@ void btrfs_add_dropped_root(struct btrfs_trans_handle *trans,
        spin_unlock(&cur_trans->dropped_roots_lock);
 
        /* Make sure we don't try to update the root at commit time */
-       xa_clear_mark(&fs_info->fs_roots,
-                     (unsigned long)root->root_key.objectid,
-                     BTRFS_ROOT_TRANS_TAG);
+       spin_lock(&fs_info->fs_roots_radix_lock);
+       radix_tree_tag_clear(&fs_info->fs_roots_radix,
+                            (unsigned long)root->root_key.objectid,
+                            BTRFS_ROOT_TRANS_TAG);
+       spin_unlock(&fs_info->fs_roots_radix_lock);
 }
 
 int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans,
@@ -1402,8 +1404,9 @@ void btrfs_add_dead_root(struct btrfs_root *root)
 static noinline int commit_fs_roots(struct btrfs_trans_handle *trans)
 {
        struct btrfs_fs_info *fs_info = trans->fs_info;
-       struct btrfs_root *root;
-       unsigned long index;
+       struct btrfs_root *gang[8];
+       int i;
+       int ret;
 
        /*
         * At this point no one can be using this transaction to modify any tree
@@ -1411,46 +1414,57 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans)
         */
        ASSERT(trans->transaction->state == TRANS_STATE_COMMIT_DOING);
 
-       spin_lock(&fs_info->fs_roots_lock);
-       xa_for_each_marked(&fs_info->fs_roots, index, root, BTRFS_ROOT_TRANS_TAG) {
-               int ret;
-
-               /*
-                * At this point we can neither have tasks logging inodes
-                * from a root nor trying to commit a log tree.
-                */
-               ASSERT(atomic_read(&root->log_writers) == 0);
-               ASSERT(atomic_read(&root->log_commit[0]) == 0);
-               ASSERT(atomic_read(&root->log_commit[1]) == 0);
-
-               xa_clear_mark(&fs_info->fs_roots,
-                             (unsigned long)root->root_key.objectid,
-                             BTRFS_ROOT_TRANS_TAG);
-               spin_unlock(&fs_info->fs_roots_lock);
-
-               btrfs_free_log(trans, root);
-               ret = btrfs_update_reloc_root(trans, root);
-               if (ret)
-                       return ret;
-
-               /* See comments in should_cow_block() */
-               clear_bit(BTRFS_ROOT_FORCE_COW, &root->state);
-               smp_mb__after_atomic();
+       spin_lock(&fs_info->fs_roots_radix_lock);
+       while (1) {
+               ret = radix_tree_gang_lookup_tag(&fs_info->fs_roots_radix,
+                                                (void **)gang, 0,
+                                                ARRAY_SIZE(gang),
+                                                BTRFS_ROOT_TRANS_TAG);
+               if (ret == 0)
+                       break;
+               for (i = 0; i < ret; i++) {
+                       struct btrfs_root *root = gang[i];
+                       int ret2;
+
+                       /*
+                        * At this point we can neither have tasks logging inodes
+                        * from a root nor trying to commit a log tree.
+                        */
+                       ASSERT(atomic_read(&root->log_writers) == 0);
+                       ASSERT(atomic_read(&root->log_commit[0]) == 0);
+                       ASSERT(atomic_read(&root->log_commit[1]) == 0);
+
+                       radix_tree_tag_clear(&fs_info->fs_roots_radix,
+                                       (unsigned long)root->root_key.objectid,
+                                       BTRFS_ROOT_TRANS_TAG);
+                       spin_unlock(&fs_info->fs_roots_radix_lock);
+
+                       btrfs_free_log(trans, root);
+                       ret2 = btrfs_update_reloc_root(trans, root);
+                       if (ret2)
+                               return ret2;
+
+                       /* see comments in should_cow_block() */
+                       clear_bit(BTRFS_ROOT_FORCE_COW, &root->state);
+                       smp_mb__after_atomic();
+
+                       if (root->commit_root != root->node) {
+                               list_add_tail(&root->dirty_list,
+                                       &trans->transaction->switch_commits);
+                               btrfs_set_root_node(&root->root_item,
+                                                   root->node);
+                       }
 
-               if (root->commit_root != root->node) {
-                       list_add_tail(&root->dirty_list,
-                                     &trans->transaction->switch_commits);
-                       btrfs_set_root_node(&root->root_item, root->node);
+                       ret2 = btrfs_update_root(trans, fs_info->tree_root,
+                                               &root->root_key,
+                                               &root->root_item);
+                       if (ret2)
+                               return ret2;
+                       spin_lock(&fs_info->fs_roots_radix_lock);
+                       btrfs_qgroup_free_meta_all_pertrans(root);
                }
-
-               ret = btrfs_update_root(trans, fs_info->tree_root,
-                                       &root->root_key, &root->root_item);
-               if (ret)
-                       return ret;
-               spin_lock(&fs_info->fs_roots_lock);
-               btrfs_qgroup_free_meta_all_pertrans(root);
        }
-       spin_unlock(&fs_info->fs_roots_lock);
+       spin_unlock(&fs_info->fs_roots_radix_lock);
        return 0;
 }
 
index 11237a9..d99026d 100644 (file)
@@ -1735,12 +1735,14 @@ static int read_zone_info(struct btrfs_fs_info *fs_info, u64 logical,
        ret = btrfs_map_sblock(fs_info, BTRFS_MAP_GET_READ_MIRRORS, logical,
                               &mapped_length, &bioc);
        if (ret || !bioc || mapped_length < PAGE_SIZE) {
-               btrfs_put_bioc(bioc);
-               return -EIO;
+               ret = -EIO;
+               goto out_put_bioc;
        }
 
-       if (bioc->map_type & BTRFS_BLOCK_GROUP_RAID56_MASK)
-               return -EINVAL;
+       if (bioc->map_type & BTRFS_BLOCK_GROUP_RAID56_MASK) {
+               ret = -EINVAL;
+               goto out_put_bioc;
+       }
 
        nofs_flag = memalloc_nofs_save();
        nmirrors = (int)bioc->num_stripes;
@@ -1759,7 +1761,8 @@ static int read_zone_info(struct btrfs_fs_info *fs_info, u64 logical,
                break;
        }
        memalloc_nofs_restore(nofs_flag);
-
+out_put_bioc:
+       btrfs_put_bioc(bioc);
        return ret;
 }
 
@@ -1885,7 +1888,6 @@ static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_writ
 {
        struct btrfs_fs_info *fs_info = block_group->fs_info;
        struct map_lookup *map;
-       bool need_zone_finish;
        int ret = 0;
        int i;
 
@@ -1942,12 +1944,6 @@ static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_writ
                }
        }
 
-       /*
-        * The block group is not fully allocated, so not fully written yet. We
-        * need to send ZONE_FINISH command to free up an active zone.
-        */
-       need_zone_finish = !btrfs_zoned_bg_is_full(block_group);
-
        block_group->zone_is_active = 0;
        block_group->alloc_offset = block_group->zone_capacity;
        block_group->free_space_ctl->free_space = 0;
@@ -1963,15 +1959,13 @@ static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_writ
                if (device->zone_info->max_active_zones == 0)
                        continue;
 
-               if (need_zone_finish) {
-                       ret = blkdev_zone_mgmt(device->bdev, REQ_OP_ZONE_FINISH,
-                                              physical >> SECTOR_SHIFT,
-                                              device->zone_info->zone_size >> SECTOR_SHIFT,
-                                              GFP_NOFS);
+               ret = blkdev_zone_mgmt(device->bdev, REQ_OP_ZONE_FINISH,
+                                      physical >> SECTOR_SHIFT,
+                                      device->zone_info->zone_size >> SECTOR_SHIFT,
+                                      GFP_NOFS);
 
-                       if (ret)
-                               return ret;
-               }
+               if (ret)
+                       return ret;
 
                btrfs_dev_clear_active_zone(device, physical);
        }
@@ -2139,3 +2133,30 @@ bool btrfs_zoned_should_reclaim(struct btrfs_fs_info *fs_info)
        factor = div64_u64(used * 100, total);
        return factor >= fs_info->bg_reclaim_threshold;
 }
+
+void btrfs_zoned_release_data_reloc_bg(struct btrfs_fs_info *fs_info, u64 logical,
+                                      u64 length)
+{
+       struct btrfs_block_group *block_group;
+
+       if (!btrfs_is_zoned(fs_info))
+               return;
+
+       block_group = btrfs_lookup_block_group(fs_info, logical);
+       /* It should be called on a previous data relocation block group. */
+       ASSERT(block_group && (block_group->flags & BTRFS_BLOCK_GROUP_DATA));
+
+       spin_lock(&block_group->lock);
+       if (!block_group->zoned_data_reloc_ongoing)
+               goto out;
+
+       /* All relocation extents are written. */
+       if (block_group->start + block_group->alloc_offset == logical + length) {
+               /* Now, release this block group for further allocations. */
+               block_group->zoned_data_reloc_ongoing = 0;
+       }
+
+out:
+       spin_unlock(&block_group->lock);
+       btrfs_put_block_group(block_group);
+}
index bb1a189..6b2eec9 100644 (file)
@@ -77,6 +77,8 @@ void btrfs_schedule_zone_finish_bg(struct btrfs_block_group *bg,
 void btrfs_clear_data_reloc_bg(struct btrfs_block_group *bg);
 void btrfs_free_zone_cache(struct btrfs_fs_info *fs_info);
 bool btrfs_zoned_should_reclaim(struct btrfs_fs_info *fs_info);
+void btrfs_zoned_release_data_reloc_bg(struct btrfs_fs_info *fs_info, u64 logical,
+                                      u64 length);
 #else /* CONFIG_BLK_DEV_ZONED */
 static inline int btrfs_get_dev_zone(struct btrfs_device *device, u64 pos,
                                     struct blk_zone *zone)
@@ -243,6 +245,9 @@ static inline bool btrfs_zoned_should_reclaim(struct btrfs_fs_info *fs_info)
 {
        return false;
 }
+
+static inline void btrfs_zoned_release_data_reloc_bg(struct btrfs_fs_info *fs_info,
+                                                    u64 logical, u64 length) { }
 #endif
 
 static inline bool btrfs_dev_is_sequential(struct btrfs_device *device, u64 pos)
index 5717d18..55e762a 100644 (file)
@@ -52,7 +52,7 @@
 #include "internal.h"
 
 static int fsync_buffers_list(spinlock_t *lock, struct list_head *list);
-static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh,
+static int submit_bh_wbc(blk_opf_t opf, struct buffer_head *bh,
                         struct writeback_control *wbc);
 
 #define BH_ENTRY(list) list_entry((list), struct buffer_head, b_assoc_buffers)
@@ -562,7 +562,7 @@ void write_boundary_block(struct block_device *bdev,
        struct buffer_head *bh = __find_get_block(bdev, bblock + 1, blocksize);
        if (bh) {
                if (buffer_dirty(bh))
-                       ll_rw_block(REQ_OP_WRITE, 0, 1, &bh);
+                       ll_rw_block(REQ_OP_WRITE, 1, &bh);
                put_bh(bh);
        }
 }
@@ -1174,7 +1174,7 @@ static struct buffer_head *__bread_slow(struct buffer_head *bh)
        } else {
                get_bh(bh);
                bh->b_end_io = end_buffer_read_sync;
-               submit_bh(REQ_OP_READ, 0, bh);
+               submit_bh(REQ_OP_READ, bh);
                wait_on_buffer(bh);
                if (buffer_uptodate(bh))
                        return bh;
@@ -1342,7 +1342,7 @@ void __breadahead(struct block_device *bdev, sector_t block, unsigned size)
 {
        struct buffer_head *bh = __getblk(bdev, block, size);
        if (likely(bh)) {
-               ll_rw_block(REQ_OP_READ, REQ_RAHEAD, 1, &bh);
+               ll_rw_block(REQ_OP_READ | REQ_RAHEAD, 1, &bh);
                brelse(bh);
        }
 }
@@ -1353,7 +1353,7 @@ void __breadahead_gfp(struct block_device *bdev, sector_t block, unsigned size,
 {
        struct buffer_head *bh = __getblk_gfp(bdev, block, size, gfp);
        if (likely(bh)) {
-               ll_rw_block(REQ_OP_READ, REQ_RAHEAD, 1, &bh);
+               ll_rw_block(REQ_OP_READ | REQ_RAHEAD, 1, &bh);
                brelse(bh);
        }
 }
@@ -1716,7 +1716,7 @@ int __block_write_full_page(struct inode *inode, struct page *page,
        struct buffer_head *bh, *head;
        unsigned int blocksize, bbits;
        int nr_underway = 0;
-       int write_flags = wbc_to_write_flags(wbc);
+       blk_opf_t write_flags = wbc_to_write_flags(wbc);
 
        head = create_page_buffers(page, inode,
                                        (1 << BH_Dirty)|(1 << BH_Uptodate));
@@ -1804,7 +1804,7 @@ int __block_write_full_page(struct inode *inode, struct page *page,
        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, wbc);
                        nr_underway++;
                }
                bh = next;
@@ -1858,7 +1858,7 @@ 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, wbc);
                        nr_underway++;
                }
                bh = next;
@@ -2033,7 +2033,7 @@ int __block_write_begin_int(struct folio *folio, loff_t pos, unsigned len,
                if (!buffer_uptodate(bh) && !buffer_delay(bh) &&
                    !buffer_unwritten(bh) &&
                     (block_start < from || block_end > to)) {
-                       ll_rw_block(REQ_OP_READ, 0, 1, &bh);
+                       ll_rw_block(REQ_OP_READ, 1, &bh);
                        *wait_bh++=bh;
                }
        }
@@ -2337,7 +2337,7 @@ int block_read_full_folio(struct folio *folio, get_block_t *get_block)
                if (buffer_uptodate(bh))
                        end_buffer_async_read(bh, 1);
                else
-                       submit_bh(REQ_OP_READ, 0, bh);
+                       submit_bh(REQ_OP_READ, bh);
        }
        return 0;
 }
@@ -2594,7 +2594,7 @@ int block_truncate_page(struct address_space *mapping,
 
        if (!buffer_uptodate(bh) && !buffer_delay(bh) && !buffer_unwritten(bh)) {
                err = -EIO;
-               ll_rw_block(REQ_OP_READ, 0, 1, &bh);
+               ll_rw_block(REQ_OP_READ, 1, &bh);
                wait_on_buffer(bh);
                /* Uhhuh. Read error. Complain and punt. */
                if (!buffer_uptodate(bh))
@@ -2673,9 +2673,10 @@ static void end_bio_bh_io_sync(struct bio *bio)
        bio_put(bio);
 }
 
-static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh,
+static int submit_bh_wbc(blk_opf_t opf, struct buffer_head *bh,
                         struct writeback_control *wbc)
 {
+       const enum req_op op = opf & REQ_OP_MASK;
        struct bio *bio;
 
        BUG_ON(!buffer_locked(bh));
@@ -2691,11 +2692,11 @@ static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh,
                clear_buffer_write_io_error(bh);
 
        if (buffer_meta(bh))
-               op_flags |= REQ_META;
+               opf |= REQ_META;
        if (buffer_prio(bh))
-               op_flags |= REQ_PRIO;
+               opf |= REQ_PRIO;
 
-       bio = bio_alloc(bh->b_bdev, 1, op | op_flags, GFP_NOIO);
+       bio = bio_alloc(bh->b_bdev, 1, opf, GFP_NOIO);
 
        fscrypt_set_bio_crypt_ctx_bh(bio, bh, GFP_NOIO);
 
@@ -2719,22 +2720,21 @@ static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh,
        return 0;
 }
 
-int submit_bh(int op, int op_flags, struct buffer_head *bh)
+int submit_bh(blk_opf_t opf, struct buffer_head *bh)
 {
-       return submit_bh_wbc(op, op_flags, bh, NULL);
+       return submit_bh_wbc(opf, bh, NULL);
 }
 EXPORT_SYMBOL(submit_bh);
 
 /**
  * ll_rw_block: low-level access to block devices (DEPRECATED)
- * @op: whether to %READ or %WRITE
- * @op_flags: req_flag_bits
+ * @opf: block layer request operation and flags.
  * @nr: number of &struct buffer_heads in the array
  * @bhs: array of pointers to &struct buffer_head
  *
  * ll_rw_block() takes an array of pointers to &struct buffer_heads, and
  * requests an I/O operation on them, either a %REQ_OP_READ or a %REQ_OP_WRITE.
- * @op_flags contains flags modifying the detailed I/O behavior, most notably
+ * @opf contains flags modifying the detailed I/O behavior, most notably
  * %REQ_RAHEAD.
  *
  * This function drops any buffer that it cannot get a lock on (with the
@@ -2751,8 +2751,9 @@ EXPORT_SYMBOL(submit_bh);
  * All of the buffers must be for the same device, and must also be a
  * multiple of the current approved size for the device.
  */
-void ll_rw_block(int op, int op_flags,  int nr, struct buffer_head *bhs[])
+void ll_rw_block(const blk_opf_t opf, int nr, struct buffer_head *bhs[])
 {
+       const enum req_op op = opf & REQ_OP_MASK;
        int i;
 
        for (i = 0; i < nr; i++) {
@@ -2760,18 +2761,18 @@ void ll_rw_block(int op, int op_flags,  int nr, struct buffer_head *bhs[])
 
                if (!trylock_buffer(bh))
                        continue;
-               if (op == WRITE) {
+               if (op == REQ_OP_WRITE) {
                        if (test_clear_buffer_dirty(bh)) {
                                bh->b_end_io = end_buffer_write_sync;
                                get_bh(bh);
-                               submit_bh(op, op_flags, bh);
+                               submit_bh(opf, bh);
                                continue;
                        }
                } else {
                        if (!buffer_uptodate(bh)) {
                                bh->b_end_io = end_buffer_read_sync;
                                get_bh(bh);
-                               submit_bh(op, op_flags, bh);
+                               submit_bh(opf, bh);
                                continue;
                        }
                }
@@ -2780,7 +2781,7 @@ void ll_rw_block(int op, int op_flags,  int nr, struct buffer_head *bhs[])
 }
 EXPORT_SYMBOL(ll_rw_block);
 
-void write_dirty_buffer(struct buffer_head *bh, int op_flags)
+void write_dirty_buffer(struct buffer_head *bh, blk_opf_t op_flags)
 {
        lock_buffer(bh);
        if (!test_clear_buffer_dirty(bh)) {
@@ -2789,7 +2790,7 @@ void write_dirty_buffer(struct buffer_head *bh, int op_flags)
        }
        bh->b_end_io = end_buffer_write_sync;
        get_bh(bh);
-       submit_bh(REQ_OP_WRITE, op_flags, bh);
+       submit_bh(REQ_OP_WRITE | op_flags, bh);
 }
 EXPORT_SYMBOL(write_dirty_buffer);
 
@@ -2798,7 +2799,7 @@ EXPORT_SYMBOL(write_dirty_buffer);
  * and then start new I/O and then wait upon it.  The caller must have a ref on
  * the buffer_head.
  */
-int __sync_dirty_buffer(struct buffer_head *bh, int op_flags)
+int __sync_dirty_buffer(struct buffer_head *bh, blk_opf_t op_flags)
 {
        int ret = 0;
 
@@ -2816,7 +2817,7 @@ int __sync_dirty_buffer(struct buffer_head *bh, int op_flags)
 
                get_bh(bh);
                bh->b_end_io = end_buffer_write_sync;
-               ret = submit_bh(REQ_OP_WRITE, op_flags, bh);
+               ret = submit_bh(REQ_OP_WRITE | op_flags, bh);
                wait_on_buffer(bh);
                if (!ret && !buffer_uptodate(bh))
                        ret = -EIO;
@@ -3044,7 +3045,7 @@ int bh_submit_read(struct buffer_head *bh)
 
        get_bh(bh);
        bh->b_end_io = end_buffer_read_sync;
-       submit_bh(REQ_OP_READ, 0, bh);
+       submit_bh(REQ_OP_READ, bh);
        wait_on_buffer(bh);
        if (buffer_uptodate(bh))
                return 0;
index a41ae6e..1fee702 100644 (file)
@@ -21,7 +21,8 @@ static int cachefiles_ondemand_fd_release(struct inode *inode,
         * anon_fd.
         */
        xas_for_each(&xas, req, ULONG_MAX) {
-               if (req->msg.opcode == CACHEFILES_OP_READ) {
+               if (req->msg.object_id == object_id &&
+                   req->msg.opcode == CACHEFILES_OP_READ) {
                        req->error = -EIO;
                        complete(&req->done);
                        xas_store(&xas, NULL);
index 6dee888..d6e5916 100644 (file)
@@ -63,7 +63,7 @@
         (CONGESTION_ON_THRESH(congestion_kb) >> 2))
 
 static int ceph_netfs_check_write_begin(struct file *file, loff_t pos, unsigned int len,
-                                       struct folio *folio, void **_fsdata);
+                                       struct folio **foliop, void **_fsdata);
 
 static inline struct ceph_snap_context *page_snap_context(struct page *page)
 {
@@ -1288,18 +1288,19 @@ ceph_find_incompatible(struct page *page)
 }
 
 static int ceph_netfs_check_write_begin(struct file *file, loff_t pos, unsigned int len,
-                                       struct folio *folio, void **_fsdata)
+                                       struct folio **foliop, void **_fsdata)
 {
        struct inode *inode = file_inode(file);
        struct ceph_inode_info *ci = ceph_inode(inode);
        struct ceph_snap_context *snapc;
 
-       snapc = ceph_find_incompatible(folio_page(folio, 0));
+       snapc = ceph_find_incompatible(folio_page(*foliop, 0));
        if (snapc) {
                int r;
 
-               folio_unlock(folio);
-               folio_put(folio);
+               folio_unlock(*foliop);
+               folio_put(*foliop);
+               *foliop = NULL;
                if (IS_ERR(snapc))
                        return PTR_ERR(snapc);
 
index 38c9303..ac8fd5e 100644 (file)
@@ -4377,6 +4377,7 @@ static void flush_dirty_session_caps(struct ceph_mds_session *s)
                ihold(inode);
                dout("flush_dirty_caps %llx.%llx\n", ceph_vinop(inode));
                spin_unlock(&mdsc->cap_dirty_lock);
+               ceph_wait_on_async_create(inode);
                ceph_check_caps(ci, CHECK_CAPS_FLUSH, NULL);
                iput(inode);
                spin_lock(&mdsc->cap_dirty_lock);
index 1dd995e..2cfbac8 100644 (file)
@@ -162,6 +162,8 @@ cifs_dump_iface(struct seq_file *m, struct cifs_server_iface *iface)
                seq_printf(m, "\t\tIPv4: %pI4\n", &ipv4->sin_addr);
        else if (iface->sockaddr.ss_family == AF_INET6)
                seq_printf(m, "\t\tIPv6: %pI6\n", &ipv6->sin6_addr);
+       if (!iface->is_active)
+               seq_puts(m, "\t\t[for-cleanup]\n");
 }
 
 static int cifs_debug_files_proc_show(struct seq_file *m, void *v)
@@ -221,6 +223,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
        struct TCP_Server_Info *server;
        struct cifs_ses *ses;
        struct cifs_tcon *tcon;
+       struct cifs_server_iface *iface;
        int c, i, j;
 
        seq_puts(m,
@@ -456,11 +459,10 @@ skip_rdma:
                        if (ses->iface_count)
                                seq_printf(m, "\n\n\tServer interfaces: %zu",
                                           ses->iface_count);
-                       for (j = 0; j < ses->iface_count; j++) {
-                               struct cifs_server_iface *iface;
-
-                               iface = &ses->iface_list[j];
-                               seq_printf(m, "\n\t%d)", j+1);
+                       j = 0;
+                       list_for_each_entry(iface, &ses->iface_list,
+                                                iface_head) {
+                               seq_printf(m, "\n\t%d)", ++j);
                                cifs_dump_iface(m, iface);
                                if (is_ses_using_iface(ses, iface))
                                        seq_puts(m, "\t\t[CONNECTED]\n");
index e773716..a643c84 100644 (file)
@@ -80,6 +80,9 @@
 #define SMB_DNS_RESOLVE_INTERVAL_MIN     120
 #define SMB_DNS_RESOLVE_INTERVAL_DEFAULT 600
 
+/* smb multichannel query server interfaces interval in seconds */
+#define SMB_INTERFACE_POLL_INTERVAL    600
+
 /* maximum number of PDUs in one compound */
 #define MAX_COMPOUND 5
 
@@ -933,15 +936,67 @@ static inline void cifs_set_net_ns(struct TCP_Server_Info *srv, struct net *net)
 #endif
 
 struct cifs_server_iface {
+       struct list_head iface_head;
+       struct kref refcount;
        size_t speed;
        unsigned int rdma_capable : 1;
        unsigned int rss_capable : 1;
+       unsigned int is_active : 1; /* unset if non existent */
        struct sockaddr_storage sockaddr;
 };
 
+/* release iface when last ref is dropped */
+static inline void
+release_iface(struct kref *ref)
+{
+       struct cifs_server_iface *iface = container_of(ref,
+                                                      struct cifs_server_iface,
+                                                      refcount);
+       list_del_init(&iface->iface_head);
+       kfree(iface);
+}
+
+/*
+ * compare two interfaces a and b
+ * return 0 if everything matches.
+ * return 1 if a has higher link speed, or rdma capable, or rss capable
+ * return -1 otherwise.
+ */
+static inline int
+iface_cmp(struct cifs_server_iface *a, struct cifs_server_iface *b)
+{
+       int cmp_ret = 0;
+
+       WARN_ON(!a || !b);
+       if (a->speed == b->speed) {
+               if (a->rdma_capable == b->rdma_capable) {
+                       if (a->rss_capable == b->rss_capable) {
+                               cmp_ret = memcmp(&a->sockaddr, &b->sockaddr,
+                                                sizeof(a->sockaddr));
+                               if (!cmp_ret)
+                                       return 0;
+                               else if (cmp_ret > 0)
+                                       return 1;
+                               else
+                                       return -1;
+                       } else if (a->rss_capable > b->rss_capable)
+                               return 1;
+                       else
+                               return -1;
+               } else if (a->rdma_capable > b->rdma_capable)
+                       return 1;
+               else
+                       return -1;
+       } else if (a->speed > b->speed)
+               return 1;
+       else
+               return -1;
+}
+
 struct cifs_chan {
        unsigned int in_reconnect : 1; /* if session setup in progress for this channel */
        struct TCP_Server_Info *server;
+       struct cifs_server_iface *iface; /* interface in use */
        __u8 signkey[SMB3_SIGN_KEY_SIZE];
 };
 
@@ -993,7 +1048,7 @@ struct cifs_ses {
         */
        spinlock_t iface_lock;
        /* ========= begin: protected by iface_lock ======== */
-       struct cifs_server_iface *iface_list;
+       struct list_head iface_list;
        size_t iface_count;
        unsigned long iface_last_update; /* jiffies */
        /* ========= end: protected by iface_lock ======== */
@@ -1203,6 +1258,7 @@ struct cifs_tcon {
 #ifdef CONFIG_CIFS_DFS_UPCALL
        struct list_head ulist; /* cache update list */
 #endif
+       struct delayed_work     query_interfaces; /* query interfaces workqueue job */
 };
 
 /*
index 3b7366e..d59aebe 100644 (file)
@@ -636,6 +636,13 @@ cifs_chan_clear_need_reconnect(struct cifs_ses *ses,
 bool
 cifs_chan_needs_reconnect(struct cifs_ses *ses,
                          struct TCP_Server_Info *server);
+bool
+cifs_chan_is_iface_active(struct cifs_ses *ses,
+                         struct TCP_Server_Info *server);
+int
+cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server);
+int
+SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon);
 
 void extract_unc_hostname(const char *unc, const char **h, size_t *len);
 int copy_path_name(char *dst, const char *src);
index 1849e34..386bb52 100644 (file)
@@ -145,6 +145,25 @@ requeue_resolve:
        return rc;
 }
 
+static void smb2_query_server_interfaces(struct work_struct *work)
+{
+       int rc;
+       struct cifs_tcon *tcon = container_of(work,
+                                       struct cifs_tcon,
+                                       query_interfaces.work);
+
+       /*
+        * query server network interfaces, in case they change
+        */
+       rc = SMB3_request_interfaces(0, tcon);
+       if (rc) {
+               cifs_dbg(FYI, "%s: failed to query server interfaces: %d\n",
+                               __func__, rc);
+       }
+
+       queue_delayed_work(cifsiod_wq, &tcon->query_interfaces,
+                          (SMB_INTERFACE_POLL_INTERVAL * HZ));
+}
 
 static void cifs_resolve_server(struct work_struct *work)
 {
@@ -217,7 +236,7 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
                                      bool mark_smb_session)
 {
        struct TCP_Server_Info *pserver;
-       struct cifs_ses *ses;
+       struct cifs_ses *ses, *nses;
        struct cifs_tcon *tcon;
 
        /*
@@ -231,7 +250,20 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
 
 
        spin_lock(&cifs_tcp_ses_lock);
-       list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
+       list_for_each_entry_safe(ses, nses, &pserver->smb_ses_list, smb_ses_list) {
+               /* check if iface is still active */
+               if (!cifs_chan_is_iface_active(ses, server)) {
+                       /*
+                        * HACK: drop the lock before calling
+                        * cifs_chan_update_iface to avoid deadlock
+                        */
+                       ses->ses_count++;
+                       spin_unlock(&cifs_tcp_ses_lock);
+                       cifs_chan_update_iface(ses, server);
+                       spin_lock(&cifs_tcp_ses_lock);
+                       ses->ses_count--;
+               }
+
                spin_lock(&ses->chan_lock);
                if (!mark_smb_session && cifs_chan_needs_reconnect(ses, server))
                        goto next_session;
@@ -1886,7 +1918,6 @@ void cifs_put_smb_ses(struct cifs_ses *ses)
        list_del_init(&ses->smb_ses_list);
        spin_unlock(&cifs_tcp_ses_lock);
 
-       spin_lock(&ses->chan_lock);
        chan_count = ses->chan_count;
 
        /* close any extra channels */
@@ -1894,13 +1925,14 @@ void cifs_put_smb_ses(struct cifs_ses *ses)
                int i;
 
                for (i = 1; i < chan_count; i++) {
-                       spin_unlock(&ses->chan_lock);
+                       if (ses->chans[i].iface) {
+                               kref_put(&ses->chans[i].iface->refcount, release_iface);
+                               ses->chans[i].iface = NULL;
+                       }
                        cifs_put_tcp_session(ses->chans[i].server, 0);
-                       spin_lock(&ses->chan_lock);
                        ses->chans[i].server = NULL;
                }
        }
-       spin_unlock(&ses->chan_lock);
 
        sesInfoFree(ses);
        cifs_put_tcp_session(server, 0);
@@ -2270,6 +2302,9 @@ cifs_put_tcon(struct cifs_tcon *tcon)
        list_del_init(&tcon->tcon_list);
        spin_unlock(&cifs_tcp_ses_lock);
 
+       /* cancel polling of interfaces */
+       cancel_delayed_work_sync(&tcon->query_interfaces);
+
        if (tcon->use_witness) {
                int rc;
 
@@ -2507,6 +2542,12 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
        tcon->local_lease = ctx->local_lease;
        INIT_LIST_HEAD(&tcon->pending_opens);
 
+       /* schedule query interfaces poll */
+       INIT_DELAYED_WORK(&tcon->query_interfaces,
+                         smb2_query_server_interfaces);
+       queue_delayed_work(cifsiod_wq, &tcon->query_interfaces,
+                          (SMB_INTERFACE_POLL_INTERVAL * HZ));
+
        spin_lock(&cifs_tcp_ses_lock);
        list_add(&tcon->tcon_list, &ses->tcon_list);
        spin_unlock(&cifs_tcp_ses_lock);
@@ -3982,10 +4023,16 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
                   struct nls_table *nls_info)
 {
        int rc = -ENOSYS;
+       struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
+       struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
        bool is_binding = false;
 
-
        spin_lock(&cifs_tcp_ses_lock);
+       if (server->dstaddr.ss_family == AF_INET6)
+               scnprintf(ses->ip_addr, sizeof(ses->ip_addr), "%pI6", &addr6->sin6_addr);
+       else
+               scnprintf(ses->ip_addr, sizeof(ses->ip_addr), "%pI4", &addr->sin_addr);
+
        if (ses->ses_status != SES_GOOD &&
            ses->ses_status != SES_NEW &&
            ses->ses_status != SES_NEED_RECON) {
index c69e124..0e84e6f 100644 (file)
@@ -75,6 +75,7 @@ sesInfoAlloc(void)
                INIT_LIST_HEAD(&ret_buf->tcon_list);
                mutex_init(&ret_buf->session_mutex);
                spin_lock_init(&ret_buf->iface_lock);
+               INIT_LIST_HEAD(&ret_buf->iface_list);
                spin_lock_init(&ret_buf->chan_lock);
        }
        return ret_buf;
@@ -83,6 +84,8 @@ sesInfoAlloc(void)
 void
 sesInfoFree(struct cifs_ses *buf_to_free)
 {
+       struct cifs_server_iface *iface = NULL, *niface = NULL;
+
        if (buf_to_free == NULL) {
                cifs_dbg(FYI, "Null buffer passed to sesInfoFree\n");
                return;
@@ -96,7 +99,11 @@ sesInfoFree(struct cifs_ses *buf_to_free)
        kfree(buf_to_free->user_name);
        kfree(buf_to_free->domainName);
        kfree_sensitive(buf_to_free->auth_key.response);
-       kfree(buf_to_free->iface_list);
+       spin_lock(&buf_to_free->iface_lock);
+       list_for_each_entry_safe(iface, niface, &buf_to_free->iface_list,
+                                iface_head)
+               kref_put(&iface->refcount, release_iface);
+       spin_unlock(&buf_to_free->iface_lock);
        kfree_sensitive(buf_to_free);
 }
 
index d417de3..02c8b29 100644 (file)
@@ -58,7 +58,7 @@ bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface)
 
        spin_lock(&ses->chan_lock);
        for (i = 0; i < ses->chan_count; i++) {
-               if (is_server_using_iface(ses->chans[i].server, iface)) {
+               if (ses->chans[i].iface == iface) {
                        spin_unlock(&ses->chan_lock);
                        return true;
                }
@@ -146,16 +146,24 @@ cifs_chan_needs_reconnect(struct cifs_ses *ses,
        return CIFS_CHAN_NEEDS_RECONNECT(ses, chan_index);
 }
 
+bool
+cifs_chan_is_iface_active(struct cifs_ses *ses,
+                         struct TCP_Server_Info *server)
+{
+       unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
+
+       return ses->chans[chan_index].iface &&
+               ses->chans[chan_index].iface->is_active;
+}
+
 /* returns number of channels added */
 int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses)
 {
        int old_chan_count, new_chan_count;
        int left;
-       int i = 0;
        int rc = 0;
        int tries = 0;
-       struct cifs_server_iface *ifaces = NULL;
-       size_t iface_count;
+       struct cifs_server_iface *iface = NULL, *niface = NULL;
 
        spin_lock(&ses->chan_lock);
 
@@ -185,32 +193,16 @@ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses)
        spin_unlock(&ses->chan_lock);
 
        /*
-        * Make a copy of the iface list at the time and use that
-        * instead so as to not hold the iface spinlock for opening
-        * channels
-        */
-       spin_lock(&ses->iface_lock);
-       iface_count = ses->iface_count;
-       if (iface_count <= 0) {
-               spin_unlock(&ses->iface_lock);
-               cifs_dbg(VFS, "no iface list available to open channels\n");
-               return 0;
-       }
-       ifaces = kmemdup(ses->iface_list, iface_count*sizeof(*ifaces),
-                        GFP_ATOMIC);
-       if (!ifaces) {
-               spin_unlock(&ses->iface_lock);
-               return 0;
-       }
-       spin_unlock(&ses->iface_lock);
-
-       /*
         * Keep connecting to same, fastest, iface for all channels as
         * long as its RSS. Try next fastest one if not RSS or channel
         * creation fails.
         */
+       spin_lock(&ses->iface_lock);
+       iface = list_first_entry(&ses->iface_list, struct cifs_server_iface,
+                                iface_head);
+       spin_unlock(&ses->iface_lock);
+
        while (left > 0) {
-               struct cifs_server_iface *iface;
 
                tries++;
                if (tries > 3*ses->chan_max) {
@@ -219,31 +211,128 @@ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses)
                        break;
                }
 
-               iface = &ifaces[i];
-               if (is_ses_using_iface(ses, iface) && !iface->rss_capable) {
-                       i = (i+1) % iface_count;
-                       continue;
+               spin_lock(&ses->iface_lock);
+               if (!ses->iface_count) {
+                       spin_unlock(&ses->iface_lock);
+                       break;
                }
 
-               rc = cifs_ses_add_channel(cifs_sb, ses, iface);
-               if (rc) {
-                       cifs_dbg(FYI, "failed to open extra channel on iface#%d rc=%d\n",
-                                i, rc);
-                       i = (i+1) % iface_count;
-                       continue;
+               list_for_each_entry_safe_from(iface, niface, &ses->iface_list,
+                                   iface_head) {
+                       /* skip ifaces that are unusable */
+                       if (!iface->is_active ||
+                           (is_ses_using_iface(ses, iface) &&
+                            !iface->rss_capable)) {
+                               continue;
+                       }
+
+                       /* take ref before unlock */
+                       kref_get(&iface->refcount);
+
+                       spin_unlock(&ses->iface_lock);
+                       rc = cifs_ses_add_channel(cifs_sb, ses, iface);
+                       spin_lock(&ses->iface_lock);
+
+                       if (rc) {
+                               cifs_dbg(VFS, "failed to open extra channel on iface:%pIS rc=%d\n",
+                                        &iface->sockaddr,
+                                        rc);
+                               kref_put(&iface->refcount, release_iface);
+                               continue;
+                       }
+
+                       cifs_dbg(FYI, "successfully opened new channel on iface:%pIS\n",
+                                &iface->sockaddr);
+                       break;
                }
+               spin_unlock(&ses->iface_lock);
 
-               cifs_dbg(FYI, "successfully opened new channel on iface#%d\n",
-                        i);
                left--;
                new_chan_count++;
        }
 
-       kfree(ifaces);
        return new_chan_count - old_chan_count;
 }
 
 /*
+ * update the iface for the channel if necessary.
+ * will return 0 when iface is updated, 1 if removed, 2 otherwise
+ * Must be called with chan_lock held.
+ */
+int
+cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
+{
+       unsigned int chan_index;
+       struct cifs_server_iface *iface = NULL;
+       struct cifs_server_iface *old_iface = NULL;
+       int rc = 0;
+
+       spin_lock(&ses->chan_lock);
+       chan_index = cifs_ses_get_chan_index(ses, server);
+       if (!chan_index) {
+               spin_unlock(&ses->chan_lock);
+               return 0;
+       }
+
+       if (ses->chans[chan_index].iface) {
+               old_iface = ses->chans[chan_index].iface;
+               if (old_iface->is_active) {
+                       spin_unlock(&ses->chan_lock);
+                       return 1;
+               }
+       }
+       spin_unlock(&ses->chan_lock);
+
+       spin_lock(&ses->iface_lock);
+       /* then look for a new one */
+       list_for_each_entry(iface, &ses->iface_list, iface_head) {
+               if (!iface->is_active ||
+                   (is_ses_using_iface(ses, iface) &&
+                    !iface->rss_capable)) {
+                       continue;
+               }
+               kref_get(&iface->refcount);
+       }
+
+       if (!list_entry_is_head(iface, &ses->iface_list, iface_head)) {
+               rc = 1;
+               iface = NULL;
+               cifs_dbg(FYI, "unable to find a suitable iface\n");
+       }
+
+       /* now drop the ref to the current iface */
+       if (old_iface && iface) {
+               kref_put(&old_iface->refcount, release_iface);
+               cifs_dbg(FYI, "replacing iface: %pIS with %pIS\n",
+                        &old_iface->sockaddr,
+                        &iface->sockaddr);
+       } else if (old_iface) {
+               kref_put(&old_iface->refcount, release_iface);
+               cifs_dbg(FYI, "releasing ref to iface: %pIS\n",
+                        &old_iface->sockaddr);
+       } else {
+               WARN_ON(!iface);
+               cifs_dbg(FYI, "adding new iface: %pIS\n", &iface->sockaddr);
+       }
+       spin_unlock(&ses->iface_lock);
+
+       spin_lock(&ses->chan_lock);
+       chan_index = cifs_ses_get_chan_index(ses, server);
+       ses->chans[chan_index].iface = iface;
+
+       /* No iface is found. if secondary chan, drop connection */
+       if (!iface && CIFS_SERVER_IS_CHAN(server))
+               ses->chans[chan_index].server = NULL;
+
+       spin_unlock(&ses->chan_lock);
+
+       if (!iface && CIFS_SERVER_IS_CHAN(server))
+               cifs_put_tcp_session(server, false);
+
+       return rc;
+}
+
+/*
  * If server is a channel of ses, return the corresponding enclosing
  * cifs_chan otherwise return NULL.
  */
@@ -355,6 +444,7 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
                spin_unlock(&ses->chan_lock);
                goto out;
        }
+       chan->iface = iface;
        ses->chan_count++;
        atomic_set(&ses->chan_seq, 0);
 
@@ -384,6 +474,14 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
 
 out:
        if (rc && chan->server) {
+               /*
+                * we should avoid race with these delayed works before we
+                * remove this channel
+                */
+               cancel_delayed_work_sync(&chan->server->echo);
+               cancel_delayed_work_sync(&chan->server->resolve);
+               cancel_delayed_work_sync(&chan->server->reconnect);
+
                spin_lock(&ses->chan_lock);
                /* we rely on all bits beyond chan_count to be clear */
                cifs_chan_clear_need_reconnect(ses, chan->server);
@@ -394,10 +492,9 @@ out:
                 */
                WARN_ON(ses->chan_count < 1);
                spin_unlock(&ses->chan_lock);
-       }
 
-       if (rc && chan->server)
                cifs_put_tcp_session(chan->server, 0);
+       }
 
        return rc;
 }
index 8543caf..8802995 100644 (file)
@@ -512,73 +512,41 @@ smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
 static int
 parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
                        size_t buf_len,
-                       struct cifs_server_iface **iface_list,
-                       size_t *iface_count)
+                       struct cifs_ses *ses)
 {
        struct network_interface_info_ioctl_rsp *p;
        struct sockaddr_in *addr4;
        struct sockaddr_in6 *addr6;
        struct iface_info_ipv4 *p4;
        struct iface_info_ipv6 *p6;
-       struct cifs_server_iface *info;
+       struct cifs_server_iface *info = NULL, *iface = NULL, *niface = NULL;
+       struct cifs_server_iface tmp_iface;
        ssize_t bytes_left;
        size_t next = 0;
        int nb_iface = 0;
-       int rc = 0;
-
-       *iface_list = NULL;
-       *iface_count = 0;
-
-       /*
-        * Fist pass: count and sanity check
-        */
+       int rc = 0, ret = 0;
 
        bytes_left = buf_len;
        p = buf;
-       while (bytes_left >= sizeof(*p)) {
-               nb_iface++;
-               next = le32_to_cpu(p->Next);
-               if (!next) {
-                       bytes_left -= sizeof(*p);
-                       break;
-               }
-               p = (struct network_interface_info_ioctl_rsp *)((u8 *)p+next);
-               bytes_left -= next;
-       }
-
-       if (!nb_iface) {
-               cifs_dbg(VFS, "%s: malformed interface info\n", __func__);
-               rc = -EINVAL;
-               goto out;
-       }
-
-       /* Azure rounds the buffer size up 8, to a 16 byte boundary */
-       if ((bytes_left > 8) || p->Next)
-               cifs_dbg(VFS, "%s: incomplete interface info\n", __func__);
-
 
+       spin_lock(&ses->iface_lock);
        /*
-        * Second pass: extract info to internal structure
+        * Go through iface_list and do kref_put to remove
+        * any unused ifaces. ifaces in use will be removed
+        * when the last user calls a kref_put on it
         */
-
-       *iface_list = kcalloc(nb_iface, sizeof(**iface_list), GFP_KERNEL);
-       if (!*iface_list) {
-               rc = -ENOMEM;
-               goto out;
+       list_for_each_entry_safe(iface, niface, &ses->iface_list,
+                                iface_head) {
+               iface->is_active = 0;
+               kref_put(&iface->refcount, release_iface);
        }
+       spin_unlock(&ses->iface_lock);
 
-       info = *iface_list;
-       bytes_left = buf_len;
-       p = buf;
        while (bytes_left >= sizeof(*p)) {
-               info->speed = le64_to_cpu(p->LinkSpeed);
-               info->rdma_capable = le32_to_cpu(p->Capability & RDMA_CAPABLE) ? 1 : 0;
-               info->rss_capable = le32_to_cpu(p->Capability & RSS_CAPABLE) ? 1 : 0;
-
-               cifs_dbg(FYI, "%s: adding iface %zu\n", __func__, *iface_count);
-               cifs_dbg(FYI, "%s: speed %zu bps\n", __func__, info->speed);
-               cifs_dbg(FYI, "%s: capabilities 0x%08x\n", __func__,
-                        le32_to_cpu(p->Capability));
+               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;
+               tmp_iface.rss_capable = le32_to_cpu(p->Capability & RSS_CAPABLE) ? 1 : 0;
 
                switch (p->Family) {
                /*
@@ -587,7 +555,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
                 * conversion explicit in case either one changes.
                 */
                case INTERNETWORK:
-                       addr4 = (struct sockaddr_in *)&info->sockaddr;
+                       addr4 = (struct sockaddr_in *)&tmp_iface.sockaddr;
                        p4 = (struct iface_info_ipv4 *)p->Buffer;
                        addr4->sin_family = AF_INET;
                        memcpy(&addr4->sin_addr, &p4->IPv4Address, 4);
@@ -599,7 +567,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
                                 &addr4->sin_addr);
                        break;
                case INTERNETWORKV6:
-                       addr6 = (struct sockaddr_in6 *)&info->sockaddr;
+                       addr6 = (struct sockaddr_in6 *)&tmp_iface.sockaddr;
                        p6 = (struct iface_info_ipv6 *)p->Buffer;
                        addr6->sin6_family = AF_INET6;
                        memcpy(&addr6->sin6_addr, &p6->IPv6Address, 16);
@@ -619,46 +587,96 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
                        goto next_iface;
                }
 
-               (*iface_count)++;
-               info++;
+               /*
+                * The iface_list is assumed to be sorted by speed.
+                * Check if the new interface exists in that list.
+                * NEVER change iface. it could be in use.
+                * Add a new one instead
+                */
+               spin_lock(&ses->iface_lock);
+               iface = niface = NULL;
+               list_for_each_entry_safe(iface, niface, &ses->iface_list,
+                                        iface_head) {
+                       ret = iface_cmp(iface, &tmp_iface);
+                       if (!ret) {
+                               /* just get a ref so that it doesn't get picked/freed */
+                               iface->is_active = 1;
+                               kref_get(&iface->refcount);
+                               spin_unlock(&ses->iface_lock);
+                               goto next_iface;
+                       } else if (ret < 0) {
+                               /* all remaining ifaces are slower */
+                               kref_get(&iface->refcount);
+                               break;
+                       }
+               }
+               spin_unlock(&ses->iface_lock);
+
+               /* no match. insert the entry in the list */
+               info = kmalloc(sizeof(struct cifs_server_iface),
+                              GFP_KERNEL);
+               if (!info) {
+                       rc = -ENOMEM;
+                       goto out;
+               }
+               memcpy(info, &tmp_iface, sizeof(tmp_iface));
+
+               /* add this new entry to the list */
+               kref_init(&info->refcount);
+               info->is_active = 1;
+
+               cifs_dbg(FYI, "%s: adding iface %zu\n", __func__, ses->iface_count);
+               cifs_dbg(FYI, "%s: speed %zu bps\n", __func__, info->speed);
+               cifs_dbg(FYI, "%s: capabilities 0x%08x\n", __func__,
+                        le32_to_cpu(p->Capability));
+
+               spin_lock(&ses->iface_lock);
+               if (!list_entry_is_head(iface, &ses->iface_list, iface_head)) {
+                       list_add_tail(&info->iface_head, &iface->iface_head);
+                       kref_put(&iface->refcount, release_iface);
+               } else
+                       list_add_tail(&info->iface_head, &ses->iface_list);
+               spin_unlock(&ses->iface_lock);
+
+               ses->iface_count++;
+               ses->iface_last_update = jiffies;
 next_iface:
+               nb_iface++;
                next = le32_to_cpu(p->Next);
-               if (!next)
+               if (!next) {
+                       bytes_left -= sizeof(*p);
                        break;
+               }
                p = (struct network_interface_info_ioctl_rsp *)((u8 *)p+next);
                bytes_left -= next;
        }
 
-       if (!*iface_count) {
+       if (!nb_iface) {
+               cifs_dbg(VFS, "%s: malformed interface info\n", __func__);
                rc = -EINVAL;
                goto out;
        }
 
-out:
-       if (rc) {
-               kfree(*iface_list);
-               *iface_count = 0;
-               *iface_list = NULL;
-       }
-       return rc;
-}
+       /* Azure rounds the buffer size up 8, to a 16 byte boundary */
+       if ((bytes_left > 8) || p->Next)
+               cifs_dbg(VFS, "%s: incomplete interface info\n", __func__);
 
-static int compare_iface(const void *ia, const void *ib)
-{
-       const struct cifs_server_iface *a = (struct cifs_server_iface *)ia;
-       const struct cifs_server_iface *b = (struct cifs_server_iface *)ib;
 
-       return a->speed == b->speed ? 0 : (a->speed > b->speed ? -1 : 1);
+       if (!ses->iface_count) {
+               rc = -EINVAL;
+               goto out;
+       }
+
+out:
+       return rc;
 }
 
-static int
+int
 SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon)
 {
        int rc;
        unsigned int ret_data_len = 0;
        struct network_interface_info_ioctl_rsp *out_buf = NULL;
-       struct cifs_server_iface *iface_list;
-       size_t iface_count;
        struct cifs_ses *ses = tcon->ses;
 
        rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
@@ -674,21 +692,10 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon)
                goto out;
        }
 
-       rc = parse_server_interfaces(out_buf, ret_data_len,
-                                    &iface_list, &iface_count);
+       rc = parse_server_interfaces(out_buf, ret_data_len, ses);
        if (rc)
                goto out;
 
-       /* sort interfaces from fastest to slowest */
-       sort(iface_list, iface_count, sizeof(*iface_list), compare_iface, NULL);
-
-       spin_lock(&ses->iface_lock);
-       kfree(ses->iface_list);
-       ses->iface_list = iface_list;
-       ses->iface_count = iface_count;
-       ses->iface_last_update = jiffies;
-       spin_unlock(&ses->iface_lock);
-
 out:
        kfree(out_buf);
        return rc;
index b515140..c705de3 100644 (file)
@@ -543,6 +543,7 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
                      struct TCP_Server_Info *server, unsigned int *total_len)
 {
        char *pneg_ctxt;
+       char *hostname = NULL;
        unsigned int ctxt_len, neg_context_count;
 
        if (*total_len > 200) {
@@ -570,16 +571,25 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
        *total_len += ctxt_len;
        pneg_ctxt += ctxt_len;
 
-       ctxt_len = build_netname_ctxt((struct smb2_netname_neg_context *)pneg_ctxt,
-                                       server->hostname);
-       *total_len += ctxt_len;
-       pneg_ctxt += ctxt_len;
+       /*
+        * secondary channels don't have the hostname field populated
+        * use the hostname field in the primary channel instead
+        */
+       hostname = CIFS_SERVER_IS_CHAN(server) ?
+               server->primary_server->hostname : server->hostname;
+       if (hostname && (hostname[0] != 0)) {
+               ctxt_len = build_netname_ctxt((struct smb2_netname_neg_context *)pneg_ctxt,
+                                             hostname);
+               *total_len += ctxt_len;
+               pneg_ctxt += ctxt_len;
+               neg_context_count = 3;
+       } else
+               neg_context_count = 2;
 
        build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt);
        *total_len += sizeof(struct smb2_posix_neg_context);
        pneg_ctxt += sizeof(struct smb2_posix_neg_context);
-
-       neg_context_count = 4;
+       neg_context_count++;
 
        if (server->compress_algorithm) {
                build_compression_ctxt((struct smb2_compression_capabilities_context *)
index 6b4c809..f5be777 100644 (file)
@@ -31,7 +31,7 @@
 #define FSCRYPT_CONTEXT_V2     2
 
 /* Keep this in sync with include/uapi/linux/fscrypt.h */
-#define FSCRYPT_MODE_MAX       FSCRYPT_MODE_ADIANTUM
+#define FSCRYPT_MODE_MAX       FSCRYPT_MODE_AES_256_HCTR2
 
 struct fscrypt_context_v1 {
        u8 version; /* FSCRYPT_CONTEXT_V1 */
index c357118..fbc71ab 100644 (file)
@@ -53,6 +53,13 @@ struct fscrypt_mode fscrypt_modes[] = {
                .ivsize = 32,
                .blk_crypto_mode = BLK_ENCRYPTION_MODE_ADIANTUM,
        },
+       [FSCRYPT_MODE_AES_256_HCTR2] = {
+               .friendly_name = "AES-256-HCTR2",
+               .cipher_str = "hctr2(aes)",
+               .keysize = 32,
+               .security_strength = 32,
+               .ivsize = 32,
+       },
 };
 
 static DEFINE_MUTEX(fscrypt_mode_key_setup_mutex);
index 5f858ce..8a054e6 100644 (file)
@@ -61,7 +61,7 @@ fscrypt_get_dummy_policy(struct super_block *sb)
        return sb->s_cop->get_dummy_policy(sb);
 }
 
-static bool fscrypt_valid_enc_modes(u32 contents_mode, u32 filenames_mode)
+static bool fscrypt_valid_enc_modes_v1(u32 contents_mode, u32 filenames_mode)
 {
        if (contents_mode == FSCRYPT_MODE_AES_256_XTS &&
            filenames_mode == FSCRYPT_MODE_AES_256_CTS)
@@ -78,6 +78,14 @@ static bool fscrypt_valid_enc_modes(u32 contents_mode, u32 filenames_mode)
        return false;
 }
 
+static bool fscrypt_valid_enc_modes_v2(u32 contents_mode, u32 filenames_mode)
+{
+       if (contents_mode == FSCRYPT_MODE_AES_256_XTS &&
+           filenames_mode == FSCRYPT_MODE_AES_256_HCTR2)
+               return true;
+       return fscrypt_valid_enc_modes_v1(contents_mode, filenames_mode);
+}
+
 static bool supported_direct_key_modes(const struct inode *inode,
                                       u32 contents_mode, u32 filenames_mode)
 {
@@ -151,7 +159,7 @@ static bool supported_iv_ino_lblk_policy(const struct fscrypt_policy_v2 *policy,
 static bool fscrypt_supported_v1_policy(const struct fscrypt_policy_v1 *policy,
                                        const struct inode *inode)
 {
-       if (!fscrypt_valid_enc_modes(policy->contents_encryption_mode,
+       if (!fscrypt_valid_enc_modes_v1(policy->contents_encryption_mode,
                                     policy->filenames_encryption_mode)) {
                fscrypt_warn(inode,
                             "Unsupported encryption modes (contents %d, filenames %d)",
@@ -187,7 +195,7 @@ static bool fscrypt_supported_v2_policy(const struct fscrypt_policy_v2 *policy,
 {
        int count = 0;
 
-       if (!fscrypt_valid_enc_modes(policy->contents_encryption_mode,
+       if (!fscrypt_valid_enc_modes_v2(policy->contents_encryption_mode,
                                     policy->filenames_encryption_mode)) {
                fscrypt_warn(inode,
                             "Unsupported encryption modes (contents %d, filenames %d)",
index 8407520..94b7144 100644 (file)
@@ -117,8 +117,7 @@ struct dio_submit {
 /* dio_state communicated between submission path and end_io */
 struct dio {
        int flags;                      /* doesn't change */
-       int op;
-       int op_flags;
+       blk_opf_t opf;                  /* request operation type and flags */
        struct gendisk *bio_disk;
        struct inode *inode;
        loff_t i_size;                  /* i_size when submitted */
@@ -167,12 +166,13 @@ static inline unsigned dio_pages_present(struct dio_submit *sdio)
  */
 static inline int dio_refill_pages(struct dio *dio, struct dio_submit *sdio)
 {
+       const enum req_op dio_op = dio->opf & REQ_OP_MASK;
        ssize_t ret;
 
        ret = iov_iter_get_pages(sdio->iter, dio->pages, LONG_MAX, DIO_PAGES,
                                &sdio->from);
 
-       if (ret < 0 && sdio->blocks_available && (dio->op == REQ_OP_WRITE)) {
+       if (ret < 0 && sdio->blocks_available && dio_op == REQ_OP_WRITE) {
                struct page *page = ZERO_PAGE(0);
                /*
                 * A memory fault, but the filesystem has some outstanding
@@ -234,6 +234,7 @@ static inline struct page *dio_get_page(struct dio *dio,
  */
 static ssize_t dio_complete(struct dio *dio, ssize_t ret, unsigned int flags)
 {
+       const enum req_op dio_op = dio->opf & REQ_OP_MASK;
        loff_t offset = dio->iocb->ki_pos;
        ssize_t transferred = 0;
        int err;
@@ -251,7 +252,7 @@ static ssize_t dio_complete(struct dio *dio, ssize_t ret, unsigned int flags)
                transferred = dio->result;
 
                /* Check for short read case */
-               if ((dio->op == REQ_OP_READ) &&
+               if (dio_op == REQ_OP_READ &&
                    ((offset + transferred) > dio->i_size))
                        transferred = dio->i_size - offset;
                /* ignore EFAULT if some IO has been done */
@@ -286,7 +287,7 @@ static ssize_t dio_complete(struct dio *dio, ssize_t ret, unsigned int flags)
         * zeros from unwritten extents.
         */
        if (flags & DIO_COMPLETE_INVALIDATE &&
-           ret > 0 && dio->op == REQ_OP_WRITE &&
+           ret > 0 && dio_op == REQ_OP_WRITE &&
            dio->inode->i_mapping->nrpages) {
                err = invalidate_inode_pages2_range(dio->inode->i_mapping,
                                        offset >> PAGE_SHIFT,
@@ -305,7 +306,7 @@ static ssize_t dio_complete(struct dio *dio, ssize_t ret, unsigned int flags)
                 */
                dio->iocb->ki_pos += transferred;
 
-               if (ret > 0 && dio->op == REQ_OP_WRITE)
+               if (ret > 0 && dio_op == REQ_OP_WRITE)
                        ret = generic_write_sync(dio->iocb, ret);
                dio->iocb->ki_complete(dio->iocb, ret);
        }
@@ -329,6 +330,7 @@ static blk_status_t dio_bio_complete(struct dio *dio, struct bio *bio);
 static void dio_bio_end_aio(struct bio *bio)
 {
        struct dio *dio = bio->bi_private;
+       const enum req_op dio_op = dio->opf & REQ_OP_MASK;
        unsigned long remaining;
        unsigned long flags;
        bool defer_completion = false;
@@ -353,7 +355,7 @@ static void dio_bio_end_aio(struct bio *bio)
                 */
                if (dio->result)
                        defer_completion = dio->defer_completion ||
-                                          (dio->op == REQ_OP_WRITE &&
+                                          (dio_op == REQ_OP_WRITE &&
                                            dio->inode->i_mapping->nrpages);
                if (defer_completion) {
                        INIT_WORK(&dio->complete_work, dio_aio_complete_work);
@@ -396,7 +398,7 @@ dio_bio_alloc(struct dio *dio, struct dio_submit *sdio,
         * bio_alloc() is guaranteed to return a bio when allowed to sleep and
         * we request a valid number of vectors.
         */
-       bio = bio_alloc(bdev, nr_vecs, dio->op | dio->op_flags, GFP_KERNEL);
+       bio = bio_alloc(bdev, nr_vecs, dio->opf, GFP_KERNEL);
        bio->bi_iter.bi_sector = first_sector;
        if (dio->is_async)
                bio->bi_end_io = dio_bio_end_aio;
@@ -415,6 +417,7 @@ dio_bio_alloc(struct dio *dio, struct dio_submit *sdio,
  */
 static inline void dio_bio_submit(struct dio *dio, struct dio_submit *sdio)
 {
+       const enum req_op dio_op = dio->opf & REQ_OP_MASK;
        struct bio *bio = sdio->bio;
        unsigned long flags;
 
@@ -426,7 +429,7 @@ static inline void dio_bio_submit(struct dio *dio, struct dio_submit *sdio)
        dio->refcount++;
        spin_unlock_irqrestore(&dio->bio_lock, flags);
 
-       if (dio->is_async && dio->op == REQ_OP_READ && dio->should_dirty)
+       if (dio->is_async && dio_op == REQ_OP_READ && dio->should_dirty)
                bio_set_pages_dirty(bio);
 
        dio->bio_disk = bio->bi_bdev->bd_disk;
@@ -492,7 +495,8 @@ static struct bio *dio_await_one(struct dio *dio)
 static blk_status_t dio_bio_complete(struct dio *dio, struct bio *bio)
 {
        blk_status_t err = bio->bi_status;
-       bool should_dirty = dio->op == REQ_OP_READ && dio->should_dirty;
+       const enum req_op dio_op = dio->opf & REQ_OP_MASK;
+       bool should_dirty = dio_op == REQ_OP_READ && dio->should_dirty;
 
        if (err) {
                if (err == BLK_STS_AGAIN && (bio->bi_opf & REQ_NOWAIT))
@@ -619,6 +623,7 @@ static int dio_set_defer_completion(struct dio *dio)
 static int get_more_blocks(struct dio *dio, struct dio_submit *sdio,
                           struct buffer_head *map_bh)
 {
+       const enum req_op dio_op = dio->opf & REQ_OP_MASK;
        int ret;
        sector_t fs_startblk;   /* Into file, in filesystem-sized blocks */
        sector_t fs_endblk;     /* Into file, in filesystem-sized blocks */
@@ -653,7 +658,7 @@ static int get_more_blocks(struct dio *dio, struct dio_submit *sdio,
                 * which may decide to handle it or also return an unmapped
                 * buffer head.
                 */
-               create = dio->op == REQ_OP_WRITE;
+               create = dio_op == REQ_OP_WRITE;
                if (dio->flags & DIO_SKIP_HOLES) {
                        i_size = i_size_read(dio->inode);
                        if (i_size && fs_startblk <= (i_size - 1) >> i_blkbits)
@@ -801,10 +806,11 @@ submit_page_section(struct dio *dio, struct dio_submit *sdio, struct page *page,
                    unsigned offset, unsigned len, sector_t blocknr,
                    struct buffer_head *map_bh)
 {
+       const enum req_op dio_op = dio->opf & REQ_OP_MASK;
        int ret = 0;
        int boundary = sdio->boundary;  /* dio_send_cur_page may clear it */
 
-       if (dio->op == REQ_OP_WRITE) {
+       if (dio_op == REQ_OP_WRITE) {
                /*
                 * Read accounting is performed in submit_bio()
                 */
@@ -917,6 +923,7 @@ static inline void dio_zero_block(struct dio *dio, struct dio_submit *sdio,
 static int do_direct_IO(struct dio *dio, struct dio_submit *sdio,
                        struct buffer_head *map_bh)
 {
+       const enum req_op dio_op = dio->opf & REQ_OP_MASK;
        const unsigned blkbits = sdio->blkbits;
        const unsigned i_blkbits = blkbits + sdio->blkfactor;
        int ret = 0;
@@ -992,7 +999,7 @@ do_holes:
                                loff_t i_size_aligned;
 
                                /* AKPM: eargh, -ENOTBLK is a hack */
-                               if (dio->op == REQ_OP_WRITE) {
+                               if (dio_op == REQ_OP_WRITE) {
                                        put_page(page);
                                        return -ENOTBLK;
                                }
@@ -1196,12 +1203,11 @@ ssize_t __blockdev_direct_IO(struct kiocb *iocb, struct inode *inode,
 
        dio->inode = inode;
        if (iov_iter_rw(iter) == WRITE) {
-               dio->op = REQ_OP_WRITE;
-               dio->op_flags = REQ_SYNC | REQ_IDLE;
+               dio->opf = REQ_OP_WRITE | REQ_SYNC | REQ_IDLE;
                if (iocb->ki_flags & IOCB_NOWAIT)
-                       dio->op_flags |= REQ_NOWAIT;
+                       dio->opf |= REQ_NOWAIT;
        } else {
-               dio->op = REQ_OP_READ;
+               dio->opf = REQ_OP_READ;
        }
 
        /*
index ee92634..1105ce3 100644 (file)
@@ -9,6 +9,15 @@ menuconfig DLM
        A general purpose distributed lock manager for kernel or userspace
        applications.
 
+config DLM_DEPRECATED_API
+       bool "DLM deprecated API"
+       depends on DLM
+       help
+       Enables deprecated DLM timeout features that will be removed in
+        later Linux kernel releases.
+
+       If you are unsure, say N.
+
 config DLM_DEBUG
        bool "DLM debugging"
        depends on DLM
index 3545fda..71dab73 100644 (file)
@@ -9,7 +9,6 @@ dlm-y :=                        ast.o \
                                member.o \
                                memory.o \
                                midcomms.o \
-                               netlink.o \
                                lowcomms.o \
                                plock.o \
                                rcom.o \
@@ -18,5 +17,6 @@ dlm-y :=                      ast.o \
                                requestqueue.o \
                                user.o \
                                util.o 
+dlm-$(CONFIG_DLM_DEPRECATED_API) +=    netlink.o
 dlm-$(CONFIG_DLM_DEBUG) +=     debug_fs.o
 
index bfac462..19ef136 100644 (file)
@@ -255,13 +255,13 @@ void dlm_callback_work(struct work_struct *work)
                if (callbacks[i].flags & DLM_CB_SKIP) {
                        continue;
                } else if (callbacks[i].flags & DLM_CB_BAST) {
-                       bastfn(lkb->lkb_astparam, callbacks[i].mode);
                        trace_dlm_bast(ls, lkb, callbacks[i].mode);
+                       bastfn(lkb->lkb_astparam, callbacks[i].mode);
                } else if (callbacks[i].flags & DLM_CB_CAST) {
                        lkb->lkb_lksb->sb_status = callbacks[i].sb_status;
                        lkb->lkb_lksb->sb_flags = callbacks[i].sb_flags;
+                       trace_dlm_ast(ls, lkb);
                        castfn(lkb->lkb_astparam);
-                       trace_dlm_ast(ls, lkb, lkb->lkb_lksb);
                }
        }
 
index 42eee27..ac8b621 100644 (file)
@@ -75,8 +75,9 @@ struct dlm_cluster {
        unsigned int cl_log_info;
        unsigned int cl_protocol;
        unsigned int cl_mark;
+#ifdef CONFIG_DLM_DEPRECATED_API
        unsigned int cl_timewarn_cs;
-       unsigned int cl_waitwarn_us;
+#endif
        unsigned int cl_new_rsb_count;
        unsigned int cl_recover_callbacks;
        char cl_cluster_name[DLM_LOCKSPACE_LEN];
@@ -102,8 +103,9 @@ enum {
        CLUSTER_ATTR_LOG_INFO,
        CLUSTER_ATTR_PROTOCOL,
        CLUSTER_ATTR_MARK,
+#ifdef CONFIG_DLM_DEPRECATED_API
        CLUSTER_ATTR_TIMEWARN_CS,
-       CLUSTER_ATTR_WAITWARN_US,
+#endif
        CLUSTER_ATTR_NEW_RSB_COUNT,
        CLUSTER_ATTR_RECOVER_CALLBACKS,
        CLUSTER_ATTR_CLUSTER_NAME,
@@ -224,8 +226,9 @@ CLUSTER_ATTR(log_debug, NULL);
 CLUSTER_ATTR(log_info, NULL);
 CLUSTER_ATTR(protocol, dlm_check_protocol_and_dlm_running);
 CLUSTER_ATTR(mark, NULL);
+#ifdef CONFIG_DLM_DEPRECATED_API
 CLUSTER_ATTR(timewarn_cs, dlm_check_zero);
-CLUSTER_ATTR(waitwarn_us, NULL);
+#endif
 CLUSTER_ATTR(new_rsb_count, NULL);
 CLUSTER_ATTR(recover_callbacks, NULL);
 
@@ -240,8 +243,9 @@ static struct configfs_attribute *cluster_attrs[] = {
        [CLUSTER_ATTR_LOG_INFO] = &cluster_attr_log_info,
        [CLUSTER_ATTR_PROTOCOL] = &cluster_attr_protocol,
        [CLUSTER_ATTR_MARK] = &cluster_attr_mark,
+#ifdef CONFIG_DLM_DEPRECATED_API
        [CLUSTER_ATTR_TIMEWARN_CS] = &cluster_attr_timewarn_cs,
-       [CLUSTER_ATTR_WAITWARN_US] = &cluster_attr_waitwarn_us,
+#endif
        [CLUSTER_ATTR_NEW_RSB_COUNT] = &cluster_attr_new_rsb_count,
        [CLUSTER_ATTR_RECOVER_CALLBACKS] = &cluster_attr_recover_callbacks,
        [CLUSTER_ATTR_CLUSTER_NAME] = &cluster_attr_cluster_name,
@@ -432,8 +436,9 @@ static struct config_group *make_cluster(struct config_group *g,
        cl->cl_log_debug = dlm_config.ci_log_debug;
        cl->cl_log_info = dlm_config.ci_log_info;
        cl->cl_protocol = dlm_config.ci_protocol;
+#ifdef CONFIG_DLM_DEPRECATED_API
        cl->cl_timewarn_cs = dlm_config.ci_timewarn_cs;
-       cl->cl_waitwarn_us = dlm_config.ci_waitwarn_us;
+#endif
        cl->cl_new_rsb_count = dlm_config.ci_new_rsb_count;
        cl->cl_recover_callbacks = dlm_config.ci_recover_callbacks;
        memcpy(cl->cl_cluster_name, dlm_config.ci_cluster_name,
@@ -954,8 +959,9 @@ int dlm_our_addr(struct sockaddr_storage *addr, int num)
 #define DEFAULT_LOG_INFO           1
 #define DEFAULT_PROTOCOL           DLM_PROTO_TCP
 #define DEFAULT_MARK               0
+#ifdef CONFIG_DLM_DEPRECATED_API
 #define DEFAULT_TIMEWARN_CS      500 /* 5 sec = 500 centiseconds */
-#define DEFAULT_WAITWARN_US       0
+#endif
 #define DEFAULT_NEW_RSB_COUNT    128
 #define DEFAULT_RECOVER_CALLBACKS  0
 #define DEFAULT_CLUSTER_NAME      ""
@@ -971,8 +977,9 @@ struct dlm_config_info dlm_config = {
        .ci_log_info = DEFAULT_LOG_INFO,
        .ci_protocol = DEFAULT_PROTOCOL,
        .ci_mark = DEFAULT_MARK,
+#ifdef CONFIG_DLM_DEPRECATED_API
        .ci_timewarn_cs = DEFAULT_TIMEWARN_CS,
-       .ci_waitwarn_us = DEFAULT_WAITWARN_US,
+#endif
        .ci_new_rsb_count = DEFAULT_NEW_RSB_COUNT,
        .ci_recover_callbacks = DEFAULT_RECOVER_CALLBACKS,
        .ci_cluster_name = DEFAULT_CLUSTER_NAME
index df92b0a..55c5f2c 100644 (file)
@@ -37,8 +37,9 @@ struct dlm_config_info {
        int ci_log_info;
        int ci_protocol;
        int ci_mark;
+#ifdef CONFIG_DLM_DEPRECATED_API
        int ci_timewarn_cs;
-       int ci_waitwarn_us;
+#endif
        int ci_new_rsb_count;
        int ci_recover_callbacks;
        char ci_cluster_name[DLM_LOCKSPACE_LEN];
index 776c3ed..8aca808 100644 (file)
@@ -145,7 +145,9 @@ struct dlm_args {
        void                    (*bastfn) (void *astparam, int mode);
        int                     mode;
        struct dlm_lksb         *lksb;
+#ifdef CONFIG_DLM_DEPRECATED_API
        unsigned long           timeout;
+#endif
 };
 
 
@@ -203,10 +205,20 @@ struct dlm_args {
 #define DLM_IFL_OVERLAP_UNLOCK  0x00080000
 #define DLM_IFL_OVERLAP_CANCEL  0x00100000
 #define DLM_IFL_ENDOFLIFE      0x00200000
+#ifdef CONFIG_DLM_DEPRECATED_API
 #define DLM_IFL_WATCH_TIMEWARN 0x00400000
 #define DLM_IFL_TIMEOUT_CANCEL 0x00800000
+#endif
 #define DLM_IFL_DEADLOCK_CANCEL        0x01000000
 #define DLM_IFL_STUB_MS                0x02000000 /* magic number for m_flags */
+/* least significant 2 bytes are message changed, they are full transmitted
+ * but at receive side only the 2 bytes LSB will be set.
+ *
+ * Even wireshark dlm dissector does only evaluate the lower bytes and note
+ * that they may not be used on transceiver side, we assume the higher bytes
+ * are for internal use or reserved so long they are not parsed on receiver
+ * side.
+ */
 #define DLM_IFL_USER           0x00000001
 #define DLM_IFL_ORPHAN         0x00000002
 
@@ -249,10 +261,12 @@ struct dlm_lkb {
        struct list_head        lkb_rsb_lookup; /* waiting for rsb lookup */
        struct list_head        lkb_wait_reply; /* waiting for remote reply */
        struct list_head        lkb_ownqueue;   /* list of locks for a process */
-       struct list_head        lkb_time_list;
        ktime_t                 lkb_timestamp;
-       ktime_t                 lkb_wait_time;
+
+#ifdef CONFIG_DLM_DEPRECATED_API
+       struct list_head        lkb_time_list;
        unsigned long           lkb_timeout_cs;
+#endif
 
        struct mutex            lkb_cb_mutex;
        struct work_struct      lkb_cb_work;
@@ -568,8 +582,10 @@ struct dlm_ls {
        struct mutex            ls_orphans_mutex;
        struct list_head        ls_orphans;
 
+#ifdef CONFIG_DLM_DEPRECATED_API
        struct mutex            ls_timeout_mutex;
        struct list_head        ls_timeout;
+#endif
 
        spinlock_t              ls_new_rsb_spin;
        int                     ls_new_rsb_count;
@@ -606,8 +622,8 @@ struct dlm_ls {
 
        wait_queue_head_t       ls_uevent_wait; /* user part of join/leave */
        int                     ls_uevent_result;
-       struct completion       ls_members_done;
-       int                     ls_members_result;
+       struct completion       ls_recovery_done;
+       int                     ls_recovery_result;
 
        struct miscdevice       ls_device;
 
@@ -688,7 +704,9 @@ struct dlm_ls {
 #define LSFL_RCOM_READY                5
 #define LSFL_RCOM_WAIT         6
 #define LSFL_UEVENT_WAIT       7
+#ifdef CONFIG_DLM_DEPRECATED_API
 #define LSFL_TIMEWARN          8
+#endif
 #define LSFL_CB_DELAY          9
 #define LSFL_NODIR             10
 
@@ -741,9 +759,15 @@ static inline int dlm_no_directory(struct dlm_ls *ls)
        return test_bit(LSFL_NODIR, &ls->ls_flags);
 }
 
+#ifdef CONFIG_DLM_DEPRECATED_API
 int dlm_netlink_init(void);
 void dlm_netlink_exit(void);
 void dlm_timeout_warn(struct dlm_lkb *lkb);
+#else
+static inline int dlm_netlink_init(void) { return 0; }
+static inline void dlm_netlink_exit(void) { };
+static inline void dlm_timeout_warn(struct dlm_lkb *lkb) { };
+#endif
 int dlm_plock_init(void);
 void dlm_plock_exit(void);
 
index 226822f..dac7eb7 100644 (file)
@@ -296,12 +296,14 @@ static void queue_cast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
 
        DLM_ASSERT(lkb->lkb_lksb, dlm_print_lkb(lkb););
 
+#ifdef CONFIG_DLM_DEPRECATED_API
        /* if the operation was a cancel, then return -DLM_ECANCEL, if a
           timeout caused the cancel then return -ETIMEDOUT */
        if (rv == -DLM_ECANCEL && (lkb->lkb_flags & DLM_IFL_TIMEOUT_CANCEL)) {
                lkb->lkb_flags &= ~DLM_IFL_TIMEOUT_CANCEL;
                rv = -ETIMEDOUT;
        }
+#endif
 
        if (rv == -DLM_ECANCEL && (lkb->lkb_flags & DLM_IFL_DEADLOCK_CANCEL)) {
                lkb->lkb_flags &= ~DLM_IFL_DEADLOCK_CANCEL;
@@ -1210,7 +1212,9 @@ static int _create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret,
        kref_init(&lkb->lkb_ref);
        INIT_LIST_HEAD(&lkb->lkb_ownqueue);
        INIT_LIST_HEAD(&lkb->lkb_rsb_lookup);
+#ifdef CONFIG_DLM_DEPRECATED_API
        INIT_LIST_HEAD(&lkb->lkb_time_list);
+#endif
        INIT_LIST_HEAD(&lkb->lkb_cb_list);
        mutex_init(&lkb->lkb_cb_mutex);
        INIT_WORK(&lkb->lkb_cb_work, dlm_callback_work);
@@ -1306,6 +1310,13 @@ static inline void hold_lkb(struct dlm_lkb *lkb)
        kref_get(&lkb->lkb_ref);
 }
 
+static void unhold_lkb_assert(struct kref *kref)
+{
+       struct dlm_lkb *lkb = container_of(kref, struct dlm_lkb, lkb_ref);
+
+       DLM_ASSERT(false, dlm_print_lkb(lkb););
+}
+
 /* This is called when we need to remove a reference and are certain
    it's not the last ref.  e.g. del_lkb is always called between a
    find_lkb/put_lkb and is always the inverse of a previous add_lkb.
@@ -1313,9 +1324,7 @@ static inline void hold_lkb(struct dlm_lkb *lkb)
 
 static inline void unhold_lkb(struct dlm_lkb *lkb)
 {
-       int rv;
-       rv = kref_put(&lkb->lkb_ref, kill_lkb);
-       DLM_ASSERT(!rv, dlm_print_lkb(lkb););
+       kref_put(&lkb->lkb_ref, unhold_lkb_assert);
 }
 
 static void lkb_add_ordered(struct list_head *new, struct list_head *head,
@@ -1402,75 +1411,6 @@ static int msg_reply_type(int mstype)
        return -1;
 }
 
-static int nodeid_warned(int nodeid, int num_nodes, int *warned)
-{
-       int i;
-
-       for (i = 0; i < num_nodes; i++) {
-               if (!warned[i]) {
-                       warned[i] = nodeid;
-                       return 0;
-               }
-               if (warned[i] == nodeid)
-                       return 1;
-       }
-       return 0;
-}
-
-void dlm_scan_waiters(struct dlm_ls *ls)
-{
-       struct dlm_lkb *lkb;
-       s64 us;
-       s64 debug_maxus = 0;
-       u32 debug_scanned = 0;
-       u32 debug_expired = 0;
-       int num_nodes = 0;
-       int *warned = NULL;
-
-       if (!dlm_config.ci_waitwarn_us)
-               return;
-
-       mutex_lock(&ls->ls_waiters_mutex);
-
-       list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) {
-               if (!lkb->lkb_wait_time)
-                       continue;
-
-               debug_scanned++;
-
-               us = ktime_to_us(ktime_sub(ktime_get(), lkb->lkb_wait_time));
-
-               if (us < dlm_config.ci_waitwarn_us)
-                       continue;
-
-               lkb->lkb_wait_time = 0;
-
-               debug_expired++;
-               if (us > debug_maxus)
-                       debug_maxus = us;
-
-               if (!num_nodes) {
-                       num_nodes = ls->ls_num_nodes;
-                       warned = kcalloc(num_nodes, sizeof(int), GFP_KERNEL);
-               }
-               if (!warned)
-                       continue;
-               if (nodeid_warned(lkb->lkb_wait_nodeid, num_nodes, warned))
-                       continue;
-
-               log_error(ls, "waitwarn %x %lld %d us check connection to "
-                         "node %d", lkb->lkb_id, (long long)us,
-                         dlm_config.ci_waitwarn_us, lkb->lkb_wait_nodeid);
-       }
-       mutex_unlock(&ls->ls_waiters_mutex);
-       kfree(warned);
-
-       if (debug_expired)
-               log_debug(ls, "scan_waiters %u warn %u over %d us max %lld us",
-                         debug_scanned, debug_expired,
-                         dlm_config.ci_waitwarn_us, (long long)debug_maxus);
-}
-
 /* add/remove lkb from global waiters list of lkb's waiting for
    a reply from a remote node */
 
@@ -1514,7 +1454,6 @@ static int add_to_waiters(struct dlm_lkb *lkb, int mstype, int to_nodeid)
 
        lkb->lkb_wait_count++;
        lkb->lkb_wait_type = mstype;
-       lkb->lkb_wait_time = ktime_get();
        lkb->lkb_wait_nodeid = to_nodeid; /* for debugging */
        hold_lkb(lkb);
        list_add(&lkb->lkb_wait_reply, &ls->ls_waiters);
@@ -1842,6 +1781,7 @@ void dlm_scan_rsbs(struct dlm_ls *ls)
        }
 }
 
+#ifdef CONFIG_DLM_DEPRECATED_API
 static void add_timeout(struct dlm_lkb *lkb)
 {
        struct dlm_ls *ls = lkb->lkb_resource->res_ls;
@@ -1962,17 +1902,11 @@ void dlm_adjust_timeouts(struct dlm_ls *ls)
        list_for_each_entry(lkb, &ls->ls_timeout, lkb_time_list)
                lkb->lkb_timestamp = ktime_add_us(lkb->lkb_timestamp, adj_us);
        mutex_unlock(&ls->ls_timeout_mutex);
-
-       if (!dlm_config.ci_waitwarn_us)
-               return;
-
-       mutex_lock(&ls->ls_waiters_mutex);
-       list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) {
-               if (ktime_to_us(lkb->lkb_wait_time))
-                       lkb->lkb_wait_time = ktime_get();
-       }
-       mutex_unlock(&ls->ls_waiters_mutex);
 }
+#else
+static void add_timeout(struct dlm_lkb *lkb) { }
+static void del_timeout(struct dlm_lkb *lkb) { }
+#endif
 
 /* lkb is master or local copy */
 
@@ -2837,12 +2771,20 @@ static void confirm_master(struct dlm_rsb *r, int error)
        }
 }
 
+#ifdef CONFIG_DLM_DEPRECATED_API
 static int set_lock_args(int mode, struct dlm_lksb *lksb, uint32_t flags,
                         int namelen, unsigned long timeout_cs,
                         void (*ast) (void *astparam),
                         void *astparam,
                         void (*bast) (void *astparam, int mode),
                         struct dlm_args *args)
+#else
+static int set_lock_args(int mode, struct dlm_lksb *lksb, uint32_t flags,
+                        int namelen, void (*ast)(void *astparam),
+                        void *astparam,
+                        void (*bast)(void *astparam, int mode),
+                        struct dlm_args *args)
+#endif
 {
        int rv = -EINVAL;
 
@@ -2895,7 +2837,9 @@ static int set_lock_args(int mode, struct dlm_lksb *lksb, uint32_t flags,
        args->astfn = ast;
        args->astparam = astparam;
        args->bastfn = bast;
+#ifdef CONFIG_DLM_DEPRECATED_API
        args->timeout = timeout_cs;
+#endif
        args->mode = mode;
        args->lksb = lksb;
        rv = 0;
@@ -2951,7 +2895,9 @@ static int validate_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
        lkb->lkb_lksb = args->lksb;
        lkb->lkb_lvbptr = args->lksb->sb_lvbptr;
        lkb->lkb_ownpid = (int) current->pid;
+#ifdef CONFIG_DLM_DEPRECATED_API
        lkb->lkb_timeout_cs = args->timeout;
+#endif
        rv = 0;
  out:
        if (rv)
@@ -3472,10 +3418,15 @@ int dlm_lock(dlm_lockspace_t *lockspace,
        if (error)
                goto out;
 
-       trace_dlm_lock_start(ls, lkb, mode, flags);
+       trace_dlm_lock_start(ls, lkb, name, namelen, mode, flags);
 
+#ifdef CONFIG_DLM_DEPRECATED_API
        error = set_lock_args(mode, lksb, flags, namelen, 0, ast,
                              astarg, bast, &args);
+#else
+       error = set_lock_args(mode, lksb, flags, namelen, ast, astarg, bast,
+                             &args);
+#endif
        if (error)
                goto out_put;
 
@@ -3487,7 +3438,7 @@ int dlm_lock(dlm_lockspace_t *lockspace,
        if (error == -EINPROGRESS)
                error = 0;
  out_put:
-       trace_dlm_lock_end(ls, lkb, mode, flags, error);
+       trace_dlm_lock_end(ls, lkb, name, namelen, mode, flags, error);
 
        if (convert || error)
                __put_lkb(ls, lkb);
@@ -5839,9 +5790,14 @@ int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc)
        return 0;
 }
 
+#ifdef CONFIG_DLM_DEPRECATED_API
 int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua,
                     int mode, uint32_t flags, void *name, unsigned int namelen,
                     unsigned long timeout_cs)
+#else
+int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua,
+                    int mode, uint32_t flags, void *name, unsigned int namelen)
+#endif
 {
        struct dlm_lkb *lkb;
        struct dlm_args args;
@@ -5864,8 +5820,13 @@ int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua,
                        goto out;
                }
        }
+#ifdef CONFIG_DLM_DEPRECATED_API
        error = set_lock_args(mode, &ua->lksb, flags, namelen, timeout_cs,
                              fake_astfn, ua, fake_bastfn, &args);
+#else
+       error = set_lock_args(mode, &ua->lksb, flags, namelen, fake_astfn, ua,
+                             fake_bastfn, &args);
+#endif
        if (error) {
                kfree(ua->lksb.sb_lvbptr);
                ua->lksb.sb_lvbptr = NULL;
@@ -5904,9 +5865,14 @@ int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua,
        return error;
 }
 
+#ifdef CONFIG_DLM_DEPRECATED_API
 int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
                     int mode, uint32_t flags, uint32_t lkid, char *lvb_in,
                     unsigned long timeout_cs)
+#else
+int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
+                    int mode, uint32_t flags, uint32_t lkid, char *lvb_in)
+#endif
 {
        struct dlm_lkb *lkb;
        struct dlm_args args;
@@ -5941,8 +5907,13 @@ int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
        ua->bastaddr = ua_tmp->bastaddr;
        ua->user_lksb = ua_tmp->user_lksb;
 
+#ifdef CONFIG_DLM_DEPRECATED_API
        error = set_lock_args(mode, &ua->lksb, flags, 0, timeout_cs,
                              fake_astfn, ua, fake_bastfn, &args);
+#else
+       error = set_lock_args(mode, &ua->lksb, flags, 0, fake_astfn, ua,
+                             fake_bastfn, &args);
+#endif
        if (error)
                goto out_put;
 
@@ -5966,7 +5937,7 @@ int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
 
 int dlm_user_adopt_orphan(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
                     int mode, uint32_t flags, void *name, unsigned int namelen,
-                    unsigned long timeout_cs, uint32_t *lkid)
+                    uint32_t *lkid)
 {
        struct dlm_lkb *lkb = NULL, *iter;
        struct dlm_user_args *ua;
index 252a589..a7b6474 100644 (file)
@@ -24,9 +24,15 @@ int dlm_put_lkb(struct dlm_lkb *lkb);
 void dlm_scan_rsbs(struct dlm_ls *ls);
 int dlm_lock_recovery_try(struct dlm_ls *ls);
 void dlm_unlock_recovery(struct dlm_ls *ls);
-void dlm_scan_waiters(struct dlm_ls *ls);
+
+#ifdef CONFIG_DLM_DEPRECATED_API
 void dlm_scan_timeout(struct dlm_ls *ls);
 void dlm_adjust_timeouts(struct dlm_ls *ls);
+#else
+static inline void dlm_scan_timeout(struct dlm_ls *ls) { }
+static inline void dlm_adjust_timeouts(struct dlm_ls *ls) { }
+#endif
+
 int dlm_master_lookup(struct dlm_ls *ls, int nodeid, char *name, int len,
                      unsigned int flags, int *r_nodeid, int *result);
 
@@ -41,15 +47,22 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls);
 int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc);
 int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc);
 
+#ifdef CONFIG_DLM_DEPRECATED_API
 int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua, int mode,
        uint32_t flags, void *name, unsigned int namelen,
        unsigned long timeout_cs);
 int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
        int mode, uint32_t flags, uint32_t lkid, char *lvb_in,
        unsigned long timeout_cs);
+#else
+int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua, int mode,
+       uint32_t flags, void *name, unsigned int namelen);
+int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
+       int mode, uint32_t flags, uint32_t lkid, char *lvb_in);
+#endif
 int dlm_user_adopt_orphan(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
        int mode, uint32_t flags, void *name, unsigned int namelen,
-       unsigned long timeout_cs, uint32_t *lkid);
+       uint32_t *lkid);
 int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
        uint32_t flags, uint32_t lkid, char *lvb_in);
 int dlm_user_cancel(struct dlm_ls *ls,  struct dlm_user_args *ua_tmp,
index 19ed41a..3972f4d 100644 (file)
@@ -275,7 +275,6 @@ static int dlm_scand(void *data)
                                ls->ls_scan_time = jiffies;
                                dlm_scan_rsbs(ls);
                                dlm_scan_timeout(ls);
-                               dlm_scan_waiters(ls);
                                dlm_unlock_recovery(ls);
                        } else {
                                ls->ls_scan_time += HZ;
@@ -490,13 +489,28 @@ static int new_lockspace(const char *name, const char *cluster,
                ls->ls_ops_arg = ops_arg;
        }
 
-       if (flags & DLM_LSFL_TIMEWARN)
+#ifdef CONFIG_DLM_DEPRECATED_API
+       if (flags & DLM_LSFL_TIMEWARN) {
+               pr_warn_once("===============================================================\n"
+                            "WARNING: the dlm DLM_LSFL_TIMEWARN flag is being deprecated and\n"
+                            "         will be removed in v6.2!\n"
+                            "         Inclusive DLM_LSFL_TIMEWARN define in UAPI header!\n"
+                            "===============================================================\n");
+
                set_bit(LSFL_TIMEWARN, &ls->ls_flags);
+       }
 
        /* ls_exflags are forced to match among nodes, and we don't
-          need to require all nodes to have some flags set */
+        * need to require all nodes to have some flags set
+        */
        ls->ls_exflags = (flags & ~(DLM_LSFL_TIMEWARN | DLM_LSFL_FS |
                                    DLM_LSFL_NEWEXCL));
+#else
+       /* ls_exflags are forced to match among nodes, and we don't
+        * need to require all nodes to have some flags set
+        */
+       ls->ls_exflags = (flags & ~(DLM_LSFL_FS | DLM_LSFL_NEWEXCL));
+#endif
 
        size = READ_ONCE(dlm_config.ci_rsbtbl_size);
        ls->ls_rsbtbl_size = size;
@@ -527,8 +541,10 @@ static int new_lockspace(const char *name, const char *cluster,
        mutex_init(&ls->ls_waiters_mutex);
        INIT_LIST_HEAD(&ls->ls_orphans);
        mutex_init(&ls->ls_orphans_mutex);
+#ifdef CONFIG_DLM_DEPRECATED_API
        INIT_LIST_HEAD(&ls->ls_timeout);
        mutex_init(&ls->ls_timeout_mutex);
+#endif
 
        INIT_LIST_HEAD(&ls->ls_new_rsb);
        spin_lock_init(&ls->ls_new_rsb_spin);
@@ -548,8 +564,8 @@ static int new_lockspace(const char *name, const char *cluster,
 
        init_waitqueue_head(&ls->ls_uevent_wait);
        ls->ls_uevent_result = 0;
-       init_completion(&ls->ls_members_done);
-       ls->ls_members_result = -1;
+       init_completion(&ls->ls_recovery_done);
+       ls->ls_recovery_result = -1;
 
        mutex_init(&ls->ls_cb_mutex);
        INIT_LIST_HEAD(&ls->ls_cb_delay);
@@ -645,8 +661,9 @@ static int new_lockspace(const char *name, const char *cluster,
        if (error)
                goto out_recoverd;
 
-       wait_for_completion(&ls->ls_members_done);
-       error = ls->ls_members_result;
+       /* wait until recovery is successful or failed */
+       wait_for_completion(&ls->ls_recovery_done);
+       error = ls->ls_recovery_result;
        if (error)
                goto out_members;
 
index 19e82f0..a4e84e8 100644 (file)
@@ -529,7 +529,7 @@ static void lowcomms_write_space(struct sock *sk)
                return;
 
        if (!test_and_set_bit(CF_CONNECTED, &con->flags)) {
-               log_print("successful connected to node %d", con->nodeid);
+               log_print("connected to node %d", con->nodeid);
                queue_work(send_workqueue, &con->swork);
                return;
        }
@@ -1931,7 +1931,7 @@ static int dlm_sctp_connect(struct connection *con, struct socket *sock,
                return ret;
 
        if (!test_and_set_bit(CF_CONNECTED, &con->flags))
-               log_print("successful connected to node %d", con->nodeid);
+               log_print("connected to node %d", con->nodeid);
 
        return 0;
 }
index 98084e0..2af2ccf 100644 (file)
@@ -534,7 +534,11 @@ int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out)
        int i, error, neg = 0, low = -1;
 
        /* previously removed members that we've not finished removing need to
-          count as a negative change so the "neg" recovery steps will happen */
+        * count as a negative change so the "neg" recovery steps will happen
+        *
+        * This functionality must report all member changes to lsops or
+        * midcomms layer and must never return before.
+        */
 
        list_for_each_entry(memb, &ls->ls_nodes_gone, list) {
                log_rinfo(ls, "prev removed member %d", memb->nodeid);
@@ -583,19 +587,6 @@ int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out)
        *neg_out = neg;
 
        error = ping_members(ls);
-       /* error -EINTR means that a new recovery action is triggered.
-        * We ignore this recovery action and let run the new one which might
-        * have new member configuration.
-        */
-       if (error == -EINTR)
-               error = 0;
-
-       /* new_lockspace() may be waiting to know if the config
-        * is good or bad
-        */
-       ls->ls_members_result = error;
-       complete(&ls->ls_members_done);
-
        log_rinfo(ls, "dlm_recover_members %d nodes", ls->ls_num_nodes);
        return error;
 }
@@ -675,7 +666,16 @@ int dlm_ls_stop(struct dlm_ls *ls)
        if (!ls->ls_recover_begin)
                ls->ls_recover_begin = jiffies;
 
-       dlm_lsop_recover_prep(ls);
+       /* call recover_prep ops only once and not multiple times
+        * for each possible dlm_ls_stop() when recovery is already
+        * stopped.
+        *
+        * If we successful was able to clear LSFL_RUNNING bit and
+        * it was set we know it is the first dlm_ls_stop() call.
+        */
+       if (new)
+               dlm_lsop_recover_prep(ls);
+
        return 0;
 }
 
index 0993eeb..737f185 100644 (file)
@@ -29,6 +29,8 @@ struct plock_async_data {
 struct plock_op {
        struct list_head list;
        int done;
+       /* if lock op got interrupted while waiting dlm_controld reply */
+       bool sigint;
        struct dlm_plock_info info;
        /* if set indicates async handling */
        struct plock_async_data *data;
@@ -79,8 +81,7 @@ static void send_op(struct plock_op *op)
    abandoned waiter.  So, we have to insert the unlock-close when the
    lock call is interrupted. */
 
-static void do_unlock_close(struct dlm_ls *ls, u64 number,
-                           struct file *file, struct file_lock *fl)
+static void do_unlock_close(const struct dlm_plock_info *info)
 {
        struct plock_op *op;
 
@@ -89,15 +90,12 @@ static void do_unlock_close(struct dlm_ls *ls, u64 number,
                return;
 
        op->info.optype         = DLM_PLOCK_OP_UNLOCK;
-       op->info.pid            = fl->fl_pid;
-       op->info.fsid           = ls->ls_global_id;
-       op->info.number         = number;
+       op->info.pid            = info->pid;
+       op->info.fsid           = info->fsid;
+       op->info.number         = info->number;
        op->info.start          = 0;
        op->info.end            = OFFSET_MAX;
-       if (fl->fl_lmops && fl->fl_lmops->lm_grant)
-               op->info.owner  = (__u64) fl->fl_pid;
-       else
-               op->info.owner  = (__u64)(long) fl->fl_owner;
+       op->info.owner          = info->owner;
 
        op->info.flags |= DLM_PLOCK_FL_CLOSE;
        send_op(op);
@@ -161,16 +159,24 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
        rv = wait_event_interruptible(recv_wq, (op->done != 0));
        if (rv == -ERESTARTSYS) {
                spin_lock(&ops_lock);
-               list_del(&op->list);
+               /* recheck under ops_lock if we got a done != 0,
+                * if so this interrupt case should be ignored
+                */
+               if (op->done != 0) {
+                       spin_unlock(&ops_lock);
+                       goto do_lock_wait;
+               }
+
+               op->sigint = true;
                spin_unlock(&ops_lock);
-               log_print("%s: wait interrupted %x %llx, op removed",
+               log_debug(ls, "%s: wait interrupted %x %llx pid %d",
                          __func__, ls->ls_global_id,
-                         (unsigned long long)number);
-               dlm_release_plock_op(op);
-               do_unlock_close(ls, number, file, fl);
+                         (unsigned long long)number, op->info.pid);
                goto out;
        }
 
+do_lock_wait:
+
        WARN_ON(!list_empty(&op->list));
 
        rv = op->info.rv;
@@ -378,7 +384,7 @@ static ssize_t dev_read(struct file *file, char __user *u, size_t count,
 
        spin_lock(&ops_lock);
        if (!list_empty(&send_list)) {
-               op = list_entry(send_list.next, struct plock_op, list);
+               op = list_first_entry(&send_list, struct plock_op, list);
                if (op->info.flags & DLM_PLOCK_FL_CLOSE)
                        list_del(&op->list);
                else
@@ -425,6 +431,19 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
                if (iter->info.fsid == info.fsid &&
                    iter->info.number == info.number &&
                    iter->info.owner == info.owner) {
+                       if (iter->sigint) {
+                               list_del(&iter->list);
+                               spin_unlock(&ops_lock);
+
+                               pr_debug("%s: sigint cleanup %x %llx pid %d",
+                                         __func__, iter->info.fsid,
+                                         (unsigned long long)iter->info.number,
+                                         iter->info.pid);
+                               do_unlock_close(&iter->info);
+                               memcpy(&iter->info, &info, sizeof(info));
+                               dlm_release_plock_op(iter);
+                               return count;
+                       }
                        list_del_init(&iter->list);
                        memcpy(&iter->info, &info, sizeof(info));
                        if (iter->data)
@@ -443,7 +462,7 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
                else
                        wake_up(&recv_wq);
        } else
-               log_print("%s: no op %x %llx - may got interrupted?", __func__,
+               log_print("%s: no op %x %llx", __func__,
                          info.fsid, (unsigned long long)info.number);
        return count;
 }
index a55dfce..e15eb51 100644 (file)
@@ -70,6 +70,10 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
 
        /*
         * Add or remove nodes from the lockspace's ls_nodes list.
+        *
+        * Due to the fact that we must report all membership changes to lsops
+        * or midcomms layer, it is not permitted to abort ls_recover() until
+        * this is done.
         */
 
        error = dlm_recover_members(ls, rv, &neg);
@@ -239,14 +243,12 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
                  jiffies_to_msecs(jiffies - start));
        mutex_unlock(&ls->ls_recoverd_active);
 
-       dlm_lsop_recover_done(ls);
        return 0;
 
  fail:
        dlm_release_root_list(ls);
-       log_rinfo(ls, "dlm_recover %llu error %d",
-                 (unsigned long long)rv->seq, error);
        mutex_unlock(&ls->ls_recoverd_active);
+
        return error;
 }
 
@@ -257,6 +259,7 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
 static void do_ls_recovery(struct dlm_ls *ls)
 {
        struct dlm_recover *rv = NULL;
+       int error;
 
        spin_lock(&ls->ls_recover_lock);
        rv = ls->ls_recover_args;
@@ -266,7 +269,31 @@ static void do_ls_recovery(struct dlm_ls *ls)
        spin_unlock(&ls->ls_recover_lock);
 
        if (rv) {
-               ls_recover(ls, rv);
+               error = ls_recover(ls, rv);
+               switch (error) {
+               case 0:
+                       ls->ls_recovery_result = 0;
+                       complete(&ls->ls_recovery_done);
+
+                       dlm_lsop_recover_done(ls);
+                       break;
+               case -EINTR:
+                       /* if recovery was interrupted -EINTR we wait for the next
+                        * ls_recover() iteration until it hopefully succeeds.
+                        */
+                       log_rinfo(ls, "%s %llu interrupted and should be queued to run again",
+                                 __func__, (unsigned long long)rv->seq);
+                       break;
+               default:
+                       log_rinfo(ls, "%s %llu error %d", __func__,
+                                 (unsigned long long)rv->seq, error);
+
+                       /* let new_lockspace() get aware of critical error */
+                       ls->ls_recovery_result = error;
+                       complete(&ls->ls_recovery_done);
+                       break;
+               }
+
                kfree(rv->nodes);
                kfree(rv);
        }
index 1060b24..99e8f07 100644 (file)
@@ -250,6 +250,14 @@ static int device_user_lock(struct dlm_user_proc *proc,
                goto out;
        }
 
+#ifdef CONFIG_DLM_DEPRECATED_API
+       if (params->timeout)
+               pr_warn_once("========================================================\n"
+                            "WARNING: the lkb timeout feature is being deprecated and\n"
+                            "         will be removed in v6.2!\n"
+                            "========================================================\n");
+#endif
+
        ua = kzalloc(sizeof(struct dlm_user_args), GFP_NOFS);
        if (!ua)
                goto out;
@@ -262,23 +270,34 @@ static int device_user_lock(struct dlm_user_proc *proc,
        ua->xid = params->xid;
 
        if (params->flags & DLM_LKF_CONVERT) {
+#ifdef CONFIG_DLM_DEPRECATED_API
                error = dlm_user_convert(ls, ua,
                                         params->mode, params->flags,
                                         params->lkid, params->lvb,
                                         (unsigned long) params->timeout);
+#else
+               error = dlm_user_convert(ls, ua,
+                                        params->mode, params->flags,
+                                        params->lkid, params->lvb);
+#endif
        } else if (params->flags & DLM_LKF_ORPHAN) {
                error = dlm_user_adopt_orphan(ls, ua,
                                         params->mode, params->flags,
                                         params->name, params->namelen,
-                                        (unsigned long) params->timeout,
                                         &lkid);
                if (!error)
                        error = lkid;
        } else {
+#ifdef CONFIG_DLM_DEPRECATED_API
                error = dlm_user_request(ls, ua,
                                         params->mode, params->flags,
                                         params->name, params->namelen,
                                         (unsigned long) params->timeout);
+#else
+               error = dlm_user_request(ls, ua,
+                                        params->mode, params->flags,
+                                        params->name, params->namelen);
+#endif
                if (!error)
                        error = ua->lksb.sb_lkid;
        }
index 19e6c56..26fa170 100644 (file)
@@ -17,7 +17,7 @@ struct z_erofs_decompress_req {
 
        /* indicate the algorithm will be used for decompression */
        unsigned int alg;
-       bool inplace_io, partial_decoding;
+       bool inplace_io, partial_decoding, fillgaps;
 };
 
 struct z_erofs_decompressor {
index fbb037b..fe8ac0e 100644 (file)
@@ -366,42 +366,33 @@ static sector_t erofs_bmap(struct address_space *mapping, sector_t block)
        return iomap_bmap(mapping, block, &erofs_iomap_ops);
 }
 
-static int erofs_prepare_dio(struct kiocb *iocb, struct iov_iter *to)
+static ssize_t erofs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
 {
        struct inode *inode = file_inode(iocb->ki_filp);
-       loff_t align = iocb->ki_pos | iov_iter_count(to) |
-               iov_iter_alignment(to);
-       struct block_device *bdev = inode->i_sb->s_bdev;
-       unsigned int blksize_mask;
-
-       if (bdev)
-               blksize_mask = (1 << ilog2(bdev_logical_block_size(bdev))) - 1;
-       else
-               blksize_mask = (1 << inode->i_blkbits) - 1;
 
-       if (align & blksize_mask)
-               return -EINVAL;
-       return 0;
-}
-
-static ssize_t erofs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
-{
        /* no need taking (shared) inode lock since it's a ro filesystem */
        if (!iov_iter_count(to))
                return 0;
 
 #ifdef CONFIG_FS_DAX
-       if (IS_DAX(iocb->ki_filp->f_mapping->host))
+       if (IS_DAX(inode))
                return dax_iomap_rw(iocb, to, &erofs_iomap_ops);
 #endif
        if (iocb->ki_flags & IOCB_DIRECT) {
-               int err = erofs_prepare_dio(iocb, to);
+               struct block_device *bdev = inode->i_sb->s_bdev;
+               unsigned int blksize_mask;
+
+               if (bdev)
+                       blksize_mask = bdev_logical_block_size(bdev) - 1;
+               else
+                       blksize_mask = (1 << inode->i_blkbits) - 1;
+
+               if ((iocb->ki_pos | iov_iter_count(to) |
+                    iov_iter_alignment(to)) & blksize_mask)
+                       return -EINVAL;
 
-               if (!err)
-                       return iomap_dio_rw(iocb, to, &erofs_iomap_ops,
-                                           NULL, 0, NULL, 0);
-               if (err < 0)
-                       return err;
+               return iomap_dio_rw(iocb, to, &erofs_iomap_ops,
+                                   NULL, 0, NULL, 0);
        }
        return filemap_read(iocb, to, 0);
 }
index 6dca190..2d55569 100644 (file)
@@ -83,7 +83,7 @@ static int z_erofs_lz4_prepare_dstpages(struct z_erofs_lz4_decompress_ctx *ctx,
                        j = 0;
 
                /* 'valid' bounced can only be tested after a complete round */
-               if (test_bit(j, bounced)) {
+               if (!rq->fillgaps && test_bit(j, bounced)) {
                        DBG_BUGON(i < lz4_max_distance_pages);
                        DBG_BUGON(top >= lz4_max_distance_pages);
                        availables[top++] = rq->out[i - lz4_max_distance_pages];
@@ -91,14 +91,18 @@ static int z_erofs_lz4_prepare_dstpages(struct z_erofs_lz4_decompress_ctx *ctx,
 
                if (page) {
                        __clear_bit(j, bounced);
-                       if (kaddr) {
-                               if (kaddr + PAGE_SIZE == page_address(page))
+                       if (!PageHighMem(page)) {
+                               if (!i) {
+                                       kaddr = page_address(page);
+                                       continue;
+                               }
+                               if (kaddr &&
+                                   kaddr + PAGE_SIZE == page_address(page)) {
                                        kaddr += PAGE_SIZE;
-                               else
-                                       kaddr = NULL;
-                       } else if (!i) {
-                               kaddr = page_address(page);
+                                       continue;
+                               }
                        }
+                       kaddr = NULL;
                        continue;
                }
                kaddr = NULL;
index 05a3063..5e59b3f 100644 (file)
@@ -143,6 +143,7 @@ again:
        DBG_BUGON(z_erofs_lzma_head);
        z_erofs_lzma_head = head;
        spin_unlock(&z_erofs_lzma_lock);
+       wake_up_all(&z_erofs_lzma_wq);
 
        z_erofs_lzma_max_dictsize = dict_size;
        mutex_unlock(&lzma_resize_mutex);
index 18e5982..ecf28f6 100644 (file)
@@ -22,10 +22,9 @@ static void debug_one_dentry(unsigned char d_type, const char *de_name,
 }
 
 static int erofs_fill_dentries(struct inode *dir, struct dir_context *ctx,
-                              void *dentry_blk, unsigned int *ofs,
+                              void *dentry_blk, struct erofs_dirent *de,
                               unsigned int nameoff, unsigned int maxsize)
 {
-       struct erofs_dirent *de = dentry_blk + *ofs;
        const struct erofs_dirent *end = dentry_blk + nameoff;
 
        while (de < end) {
@@ -59,9 +58,8 @@ static int erofs_fill_dentries(struct inode *dir, struct dir_context *ctx,
                        /* stopped by some reason */
                        return 1;
                ++de;
-               *ofs += sizeof(struct erofs_dirent);
+               ctx->pos += sizeof(struct erofs_dirent);
        }
-       *ofs = maxsize;
        return 0;
 }
 
@@ -90,33 +88,33 @@ static int erofs_readdir(struct file *f, struct dir_context *ctx)
 
                nameoff = le16_to_cpu(de->nameoff);
                if (nameoff < sizeof(struct erofs_dirent) ||
-                   nameoff >= PAGE_SIZE) {
+                   nameoff >= EROFS_BLKSIZ) {
                        erofs_err(dir->i_sb,
                                  "invalid de[0].nameoff %u @ nid %llu",
                                  nameoff, EROFS_I(dir)->nid);
                        err = -EFSCORRUPTED;
-                       goto skip_this;
+                       break;
                }
 
                maxsize = min_t(unsigned int,
-                               dirsize - ctx->pos + ofs, PAGE_SIZE);
+                               dirsize - ctx->pos + ofs, EROFS_BLKSIZ);
 
                /* search dirents at the arbitrary position */
                if (initial) {
                        initial = false;
 
                        ofs = roundup(ofs, sizeof(struct erofs_dirent));
+                       ctx->pos = blknr_to_addr(i) + ofs;
                        if (ofs >= nameoff)
                                goto skip_this;
                }
 
-               err = erofs_fill_dentries(dir, ctx, de, &ofs,
+               err = erofs_fill_dentries(dir, ctx, de, (void *)de + ofs,
                                          nameoff, maxsize);
-skip_this:
-               ctx->pos = blknr_to_addr(i) + ofs;
-
                if (err)
                        break;
+skip_this:
+               ctx->pos = blknr_to_addr(i) + maxsize;
                ++i;
                ofs = 0;
        }
index 724bb57..5792ca9 100644 (file)
@@ -2,6 +2,7 @@
 /*
  * Copyright (C) 2018 HUAWEI, Inc.
  *             https://www.huawei.com/
+ * Copyright (C) 2022 Alibaba Cloud
  */
 #include "zdata.h"
 #include "compress.h"
@@ -26,6 +27,82 @@ static struct z_erofs_pcluster_slab pcluster_pool[] __read_mostly = {
        _PCLP(Z_EROFS_PCLUSTER_MAX_PAGES)
 };
 
+struct z_erofs_bvec_iter {
+       struct page *bvpage;
+       struct z_erofs_bvset *bvset;
+       unsigned int nr, cur;
+};
+
+static struct page *z_erofs_bvec_iter_end(struct z_erofs_bvec_iter *iter)
+{
+       if (iter->bvpage)
+               kunmap_local(iter->bvset);
+       return iter->bvpage;
+}
+
+static struct page *z_erofs_bvset_flip(struct z_erofs_bvec_iter *iter)
+{
+       unsigned long base = (unsigned long)((struct z_erofs_bvset *)0)->bvec;
+       /* have to access nextpage in advance, otherwise it will be unmapped */
+       struct page *nextpage = iter->bvset->nextpage;
+       struct page *oldpage;
+
+       DBG_BUGON(!nextpage);
+       oldpage = z_erofs_bvec_iter_end(iter);
+       iter->bvpage = nextpage;
+       iter->bvset = kmap_local_page(nextpage);
+       iter->nr = (PAGE_SIZE - base) / sizeof(struct z_erofs_bvec);
+       iter->cur = 0;
+       return oldpage;
+}
+
+static void z_erofs_bvec_iter_begin(struct z_erofs_bvec_iter *iter,
+                                   struct z_erofs_bvset_inline *bvset,
+                                   unsigned int bootstrap_nr,
+                                   unsigned int cur)
+{
+       *iter = (struct z_erofs_bvec_iter) {
+               .nr = bootstrap_nr,
+               .bvset = (struct z_erofs_bvset *)bvset,
+       };
+
+       while (cur > iter->nr) {
+               cur -= iter->nr;
+               z_erofs_bvset_flip(iter);
+       }
+       iter->cur = cur;
+}
+
+static int z_erofs_bvec_enqueue(struct z_erofs_bvec_iter *iter,
+                               struct z_erofs_bvec *bvec,
+                               struct page **candidate_bvpage)
+{
+       if (iter->cur == iter->nr) {
+               if (!*candidate_bvpage)
+                       return -EAGAIN;
+
+               DBG_BUGON(iter->bvset->nextpage);
+               iter->bvset->nextpage = *candidate_bvpage;
+               z_erofs_bvset_flip(iter);
+
+               iter->bvset->nextpage = NULL;
+               *candidate_bvpage = NULL;
+       }
+       iter->bvset->bvec[iter->cur++] = *bvec;
+       return 0;
+}
+
+static void z_erofs_bvec_dequeue(struct z_erofs_bvec_iter *iter,
+                                struct z_erofs_bvec *bvec,
+                                struct page **old_bvpage)
+{
+       if (iter->cur == iter->nr)
+               *old_bvpage = z_erofs_bvset_flip(iter);
+       else
+               *old_bvpage = NULL;
+       *bvec = iter->bvset->bvec[iter->cur++];
+}
+
 static void z_erofs_destroy_pcluster_pool(void)
 {
        int i;
@@ -46,7 +123,7 @@ static int z_erofs_create_pcluster_pool(void)
 
        for (pcs = pcluster_pool;
             pcs < pcluster_pool + ARRAY_SIZE(pcluster_pool); ++pcs) {
-               size = struct_size(a, compressed_pages, pcs->maxpages);
+               size = struct_size(a, compressed_bvecs, pcs->maxpages);
 
                sprintf(pcs->name, "erofs_pcluster-%u", pcs->maxpages);
                pcs->slab = kmem_cache_create(pcs->name, size, 0,
@@ -150,30 +227,29 @@ int __init z_erofs_init_zip_subsystem(void)
        return err;
 }
 
-enum z_erofs_collectmode {
-       COLLECT_SECONDARY,
-       COLLECT_PRIMARY,
+enum z_erofs_pclustermode {
+       Z_EROFS_PCLUSTER_INFLIGHT,
        /*
-        * The current collection was the tail of an exist chain, in addition
-        * that the previous processed chained collections are all decided to
+        * The current pclusters was the tail of an exist chain, in addition
+        * that the previous processed chained pclusters are all decided to
         * be hooked up to it.
-        * A new chain will be created for the remaining collections which are
-        * not processed yet, therefore different from COLLECT_PRIMARY_FOLLOWED,
-        * the next collection cannot reuse the whole page safely in
-        * the following scenario:
+        * A new chain will be created for the remaining pclusters which are
+        * not processed yet, so different from Z_EROFS_PCLUSTER_FOLLOWED,
+        * the next pcluster cannot reuse the whole page safely for inplace I/O
+        * in the following scenario:
         *  ________________________________________________________________
         * |      tail (partial) page     |       head (partial) page       |
-        * |   (belongs to the next cl)   |   (belongs to the current cl)   |
-        * |_______PRIMARY_FOLLOWED_______|________PRIMARY_HOOKED___________|
+        * |   (belongs to the next pcl)  |   (belongs to the current pcl)  |
+        * |_______PCLUSTER_FOLLOWED______|________PCLUSTER_HOOKED__________|
         */
-       COLLECT_PRIMARY_HOOKED,
+       Z_EROFS_PCLUSTER_HOOKED,
        /*
-        * a weak form of COLLECT_PRIMARY_FOLLOWED, the difference is that it
+        * a weak form of Z_EROFS_PCLUSTER_FOLLOWED, the difference is that it
         * could be dispatched into bypass queue later due to uptodated managed
         * pages. All related online pages cannot be reused for inplace I/O (or
-        * pagevec) since it can be directly decoded without I/O submission.
+        * bvpage) since it can be directly decoded without I/O submission.
         */
-       COLLECT_PRIMARY_FOLLOWED_NOINPLACE,
+       Z_EROFS_PCLUSTER_FOLLOWED_NOINPLACE,
        /*
         * The current collection has been linked with the owned chain, and
         * could also be linked with the remaining collections, which means
@@ -184,39 +260,36 @@ enum z_erofs_collectmode {
         *  ________________________________________________________________
         * |  tail (partial) page |          head (partial) page           |
         * |  (of the current cl) |      (of the previous collection)      |
-        * |  PRIMARY_FOLLOWED or |                                        |
-        * |_____PRIMARY_HOOKED___|____________PRIMARY_FOLLOWED____________|
+        * | PCLUSTER_FOLLOWED or |                                        |
+        * |_____PCLUSTER_HOOKED__|___________PCLUSTER_FOLLOWED____________|
         *
         * [  (*) the above page can be used as inplace I/O.               ]
         */
-       COLLECT_PRIMARY_FOLLOWED,
+       Z_EROFS_PCLUSTER_FOLLOWED,
 };
 
 struct z_erofs_decompress_frontend {
        struct inode *const inode;
        struct erofs_map_blocks map;
+       struct z_erofs_bvec_iter biter;
 
-       struct z_erofs_pagevec_ctor vector;
-
+       struct page *candidate_bvpage;
        struct z_erofs_pcluster *pcl, *tailpcl;
-       /* a pointer used to pick up inplace I/O pages */
-       struct page **icpage_ptr;
        z_erofs_next_pcluster_t owned_head;
-
-       enum z_erofs_collectmode mode;
+       enum z_erofs_pclustermode mode;
 
        bool readahead;
        /* used for applying cache strategy on the fly */
        bool backmost;
        erofs_off_t headoffset;
+
+       /* a pointer used to pick up inplace I/O pages */
+       unsigned int icur;
 };
 
 #define DECOMPRESS_FRONTEND_INIT(__i) { \
        .inode = __i, .owned_head = Z_EROFS_PCLUSTER_TAIL, \
-       .mode = COLLECT_PRIMARY_FOLLOWED, .backmost = true }
-
-static struct page *z_pagemap_global[Z_EROFS_VMAP_GLOBAL_PAGES];
-static DEFINE_MUTEX(z_pagemap_global_lock);
+       .mode = Z_EROFS_PCLUSTER_FOLLOWED, .backmost = true }
 
 static void z_erofs_bind_cache(struct z_erofs_decompress_frontend *fe,
                               enum z_erofs_cache_alloctype type,
@@ -231,24 +304,21 @@ static void z_erofs_bind_cache(struct z_erofs_decompress_frontend *fe,
         */
        gfp_t gfp = (mapping_gfp_mask(mc) & ~__GFP_DIRECT_RECLAIM) |
                        __GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN;
-       struct page **pages;
-       pgoff_t index;
+       unsigned int i;
 
-       if (fe->mode < COLLECT_PRIMARY_FOLLOWED)
+       if (fe->mode < Z_EROFS_PCLUSTER_FOLLOWED)
                return;
 
-       pages = pcl->compressed_pages;
-       index = pcl->obj.index;
-       for (; index < pcl->obj.index + pcl->pclusterpages; ++index, ++pages) {
+       for (i = 0; i < pcl->pclusterpages; ++i) {
                struct page *page;
                compressed_page_t t;
                struct page *newpage = NULL;
 
                /* the compressed page was loaded before */
-               if (READ_ONCE(*pages))
+               if (READ_ONCE(pcl->compressed_bvecs[i].page))
                        continue;
 
-               page = find_get_page(mc, index);
+               page = find_get_page(mc, pcl->obj.index + i);
 
                if (page) {
                        t = tag_compressed_page_justfound(page);
@@ -269,7 +339,8 @@ static void z_erofs_bind_cache(struct z_erofs_decompress_frontend *fe,
                        }
                }
 
-               if (!cmpxchg_relaxed(pages, NULL, tagptr_cast_ptr(t)))
+               if (!cmpxchg_relaxed(&pcl->compressed_bvecs[i].page, NULL,
+                                    tagptr_cast_ptr(t)))
                        continue;
 
                if (page)
@@ -283,7 +354,7 @@ static void z_erofs_bind_cache(struct z_erofs_decompress_frontend *fe,
         * managed cache since it can be moved to the bypass queue instead.
         */
        if (standalone)
-               fe->mode = COLLECT_PRIMARY_FOLLOWED_NOINPLACE;
+               fe->mode = Z_EROFS_PCLUSTER_FOLLOWED_NOINPLACE;
 }
 
 /* called by erofs_shrinker to get rid of all compressed_pages */
@@ -300,7 +371,7 @@ int erofs_try_to_free_all_cached_pages(struct erofs_sb_info *sbi,
         * therefore no need to worry about available decompression users.
         */
        for (i = 0; i < pcl->pclusterpages; ++i) {
-               struct page *page = pcl->compressed_pages[i];
+               struct page *page = pcl->compressed_bvecs[i].page;
 
                if (!page)
                        continue;
@@ -313,7 +384,7 @@ int erofs_try_to_free_all_cached_pages(struct erofs_sb_info *sbi,
                        continue;
 
                /* barrier is implied in the following 'unlock_page' */
-               WRITE_ONCE(pcl->compressed_pages[i], NULL);
+               WRITE_ONCE(pcl->compressed_bvecs[i].page, NULL);
                detach_page_private(page);
                unlock_page(page);
        }
@@ -323,56 +394,59 @@ int erofs_try_to_free_all_cached_pages(struct erofs_sb_info *sbi,
 int erofs_try_to_free_cached_page(struct page *page)
 {
        struct z_erofs_pcluster *const pcl = (void *)page_private(page);
-       int ret = 0;    /* 0 - busy */
+       int ret, i;
 
-       if (erofs_workgroup_try_to_freeze(&pcl->obj, 1)) {
-               unsigned int i;
+       if (!erofs_workgroup_try_to_freeze(&pcl->obj, 1))
+               return 0;
 
-               DBG_BUGON(z_erofs_is_inline_pcluster(pcl));
-               for (i = 0; i < pcl->pclusterpages; ++i) {
-                       if (pcl->compressed_pages[i] == page) {
-                               WRITE_ONCE(pcl->compressed_pages[i], NULL);
-                               ret = 1;
-                               break;
-                       }
+       ret = 0;
+       DBG_BUGON(z_erofs_is_inline_pcluster(pcl));
+       for (i = 0; i < pcl->pclusterpages; ++i) {
+               if (pcl->compressed_bvecs[i].page == page) {
+                       WRITE_ONCE(pcl->compressed_bvecs[i].page, NULL);
+                       ret = 1;
+                       break;
                }
-               erofs_workgroup_unfreeze(&pcl->obj, 1);
-
-               if (ret)
-                       detach_page_private(page);
        }
+       erofs_workgroup_unfreeze(&pcl->obj, 1);
+       if (ret)
+               detach_page_private(page);
        return ret;
 }
 
-/* page_type must be Z_EROFS_PAGE_TYPE_EXCLUSIVE */
 static bool z_erofs_try_inplace_io(struct z_erofs_decompress_frontend *fe,
-                                  struct page *page)
+                                  struct z_erofs_bvec *bvec)
 {
        struct z_erofs_pcluster *const pcl = fe->pcl;
 
-       while (fe->icpage_ptr > pcl->compressed_pages)
-               if (!cmpxchg(--fe->icpage_ptr, NULL, page))
+       while (fe->icur > 0) {
+               if (!cmpxchg(&pcl->compressed_bvecs[--fe->icur].page,
+                            NULL, bvec->page)) {
+                       pcl->compressed_bvecs[fe->icur] = *bvec;
                        return true;
+               }
+       }
        return false;
 }
 
 /* callers must be with pcluster lock held */
 static int z_erofs_attach_page(struct z_erofs_decompress_frontend *fe,
-                              struct page *page, enum z_erofs_page_type type,
-                              bool pvec_safereuse)
+                              struct z_erofs_bvec *bvec, bool exclusive)
 {
        int ret;
 
-       /* give priority for inplaceio */
-       if (fe->mode >= COLLECT_PRIMARY &&
-           type == Z_EROFS_PAGE_TYPE_EXCLUSIVE &&
-           z_erofs_try_inplace_io(fe, page))
-               return 0;
-
-       ret = z_erofs_pagevec_enqueue(&fe->vector, page, type,
-                                     pvec_safereuse);
-       fe->pcl->vcnt += (unsigned int)ret;
-       return ret ? 0 : -EAGAIN;
+       if (exclusive) {
+               /* give priority for inplaceio to use file pages first */
+               if (z_erofs_try_inplace_io(fe, bvec))
+                       return 0;
+               /* otherwise, check if it can be used as a bvpage */
+               if (fe->mode >= Z_EROFS_PCLUSTER_FOLLOWED &&
+                   !fe->candidate_bvpage)
+                       fe->candidate_bvpage = bvec->page;
+       }
+       ret = z_erofs_bvec_enqueue(&fe->biter, bvec, &fe->candidate_bvpage);
+       fe->pcl->vcnt += (ret >= 0);
+       return ret;
 }
 
 static void z_erofs_try_to_claim_pcluster(struct z_erofs_decompress_frontend *f)
@@ -385,7 +459,7 @@ static void z_erofs_try_to_claim_pcluster(struct z_erofs_decompress_frontend *f)
                    *owned_head) == Z_EROFS_PCLUSTER_NIL) {
                *owned_head = &pcl->next;
                /* so we can attach this pcluster to our submission chain. */
-               f->mode = COLLECT_PRIMARY_FOLLOWED;
+               f->mode = Z_EROFS_PCLUSTER_FOLLOWED;
                return;
        }
 
@@ -393,66 +467,21 @@ static void z_erofs_try_to_claim_pcluster(struct z_erofs_decompress_frontend *f)
         * type 2, link to the end of an existing open chain, be careful
         * that its submission is controlled by the original attached chain.
         */
-       if (cmpxchg(&pcl->next, Z_EROFS_PCLUSTER_TAIL,
+       if (*owned_head != &pcl->next && pcl != f->tailpcl &&
+           cmpxchg(&pcl->next, Z_EROFS_PCLUSTER_TAIL,
                    *owned_head) == Z_EROFS_PCLUSTER_TAIL) {
                *owned_head = Z_EROFS_PCLUSTER_TAIL;
-               f->mode = COLLECT_PRIMARY_HOOKED;
+               f->mode = Z_EROFS_PCLUSTER_HOOKED;
                f->tailpcl = NULL;
                return;
        }
        /* type 3, it belongs to a chain, but it isn't the end of the chain */
-       f->mode = COLLECT_PRIMARY;
+       f->mode = Z_EROFS_PCLUSTER_INFLIGHT;
 }
 
-static int z_erofs_lookup_pcluster(struct z_erofs_decompress_frontend *fe,
-                                  struct inode *inode,
-                                  struct erofs_map_blocks *map)
-{
-       struct z_erofs_pcluster *pcl = fe->pcl;
-       unsigned int length;
-
-       /* to avoid unexpected loop formed by corrupted images */
-       if (fe->owned_head == &pcl->next || pcl == fe->tailpcl) {
-               DBG_BUGON(1);
-               return -EFSCORRUPTED;
-       }
-
-       if (pcl->pageofs_out != (map->m_la & ~PAGE_MASK)) {
-               DBG_BUGON(1);
-               return -EFSCORRUPTED;
-       }
-
-       length = READ_ONCE(pcl->length);
-       if (length & Z_EROFS_PCLUSTER_FULL_LENGTH) {
-               if ((map->m_llen << Z_EROFS_PCLUSTER_LENGTH_BIT) > length) {
-                       DBG_BUGON(1);
-                       return -EFSCORRUPTED;
-               }
-       } else {
-               unsigned int llen = map->m_llen << Z_EROFS_PCLUSTER_LENGTH_BIT;
-
-               if (map->m_flags & EROFS_MAP_FULL_MAPPED)
-                       llen |= Z_EROFS_PCLUSTER_FULL_LENGTH;
-
-               while (llen > length &&
-                      length != cmpxchg_relaxed(&pcl->length, length, llen)) {
-                       cpu_relax();
-                       length = READ_ONCE(pcl->length);
-               }
-       }
-       mutex_lock(&pcl->lock);
-       /* used to check tail merging loop due to corrupted images */
-       if (fe->owned_head == Z_EROFS_PCLUSTER_TAIL)
-               fe->tailpcl = pcl;
-
-       z_erofs_try_to_claim_pcluster(fe);
-       return 0;
-}
-
-static int z_erofs_register_pcluster(struct z_erofs_decompress_frontend *fe,
-                                    struct inode *inode,
-                                    struct erofs_map_blocks *map)
+static int z_erofs_register_pcluster(struct z_erofs_decompress_frontend *fe)
 {
+       struct erofs_map_blocks *map = &fe->map;
        bool ztailpacking = map->m_flags & EROFS_MAP_META;
        struct z_erofs_pcluster *pcl;
        struct erofs_workgroup *grp;
@@ -471,14 +500,13 @@ static int z_erofs_register_pcluster(struct z_erofs_decompress_frontend *fe,
 
        atomic_set(&pcl->obj.refcount, 1);
        pcl->algorithmformat = map->m_algorithmformat;
-       pcl->length = (map->m_llen << Z_EROFS_PCLUSTER_LENGTH_BIT) |
-               (map->m_flags & EROFS_MAP_FULL_MAPPED ?
-                       Z_EROFS_PCLUSTER_FULL_LENGTH : 0);
+       pcl->length = 0;
+       pcl->partial = true;
 
        /* new pclusters should be claimed as type 1, primary and followed */
        pcl->next = fe->owned_head;
        pcl->pageofs_out = map->m_la & ~PAGE_MASK;
-       fe->mode = COLLECT_PRIMARY_FOLLOWED;
+       fe->mode = Z_EROFS_PCLUSTER_FOLLOWED;
 
        /*
         * lock all primary followed works before visible to others
@@ -494,7 +522,7 @@ static int z_erofs_register_pcluster(struct z_erofs_decompress_frontend *fe,
        } else {
                pcl->obj.index = map->m_pa >> PAGE_SHIFT;
 
-               grp = erofs_insert_workgroup(inode->i_sb, &pcl->obj);
+               grp = erofs_insert_workgroup(fe->inode->i_sb, &pcl->obj);
                if (IS_ERR(grp)) {
                        err = PTR_ERR(grp);
                        goto err_out;
@@ -520,11 +548,10 @@ err_out:
        return err;
 }
 
-static int z_erofs_collector_begin(struct z_erofs_decompress_frontend *fe,
-                                  struct inode *inode,
-                                  struct erofs_map_blocks *map)
+static int z_erofs_collector_begin(struct z_erofs_decompress_frontend *fe)
 {
-       struct erofs_workgroup *grp;
+       struct erofs_map_blocks *map = &fe->map;
+       struct erofs_workgroup *grp = NULL;
        int ret;
 
        DBG_BUGON(fe->pcl);
@@ -533,38 +560,35 @@ static int z_erofs_collector_begin(struct z_erofs_decompress_frontend *fe,
        DBG_BUGON(fe->owned_head == Z_EROFS_PCLUSTER_NIL);
        DBG_BUGON(fe->owned_head == Z_EROFS_PCLUSTER_TAIL_CLOSED);
 
-       if (map->m_flags & EROFS_MAP_META) {
-               if ((map->m_pa & ~PAGE_MASK) + map->m_plen > PAGE_SIZE) {
-                       DBG_BUGON(1);
-                       return -EFSCORRUPTED;
-               }
-               goto tailpacking;
+       if (!(map->m_flags & EROFS_MAP_META)) {
+               grp = erofs_find_workgroup(fe->inode->i_sb,
+                                          map->m_pa >> PAGE_SHIFT);
+       } else if ((map->m_pa & ~PAGE_MASK) + map->m_plen > PAGE_SIZE) {
+               DBG_BUGON(1);
+               return -EFSCORRUPTED;
        }
 
-       grp = erofs_find_workgroup(inode->i_sb, map->m_pa >> PAGE_SHIFT);
        if (grp) {
                fe->pcl = container_of(grp, struct z_erofs_pcluster, obj);
+               ret = -EEXIST;
        } else {
-tailpacking:
-               ret = z_erofs_register_pcluster(fe, inode, map);
-               if (!ret)
-                       goto out;
-               if (ret != -EEXIST)
-                       return ret;
+               ret = z_erofs_register_pcluster(fe);
        }
 
-       ret = z_erofs_lookup_pcluster(fe, inode, map);
-       if (ret) {
-               erofs_workgroup_put(&fe->pcl->obj);
+       if (ret == -EEXIST) {
+               mutex_lock(&fe->pcl->lock);
+               /* used to check tail merging loop due to corrupted images */
+               if (fe->owned_head == Z_EROFS_PCLUSTER_TAIL)
+                       fe->tailpcl = fe->pcl;
+
+               z_erofs_try_to_claim_pcluster(fe);
+       } else if (ret) {
                return ret;
        }
-
-out:
-       z_erofs_pagevec_ctor_init(&fe->vector, Z_EROFS_NR_INLINE_PAGEVECS,
-                                 fe->pcl->pagevec, fe->pcl->vcnt);
+       z_erofs_bvec_iter_begin(&fe->biter, &fe->pcl->bvset,
+                               Z_EROFS_INLINE_BVECS, fe->pcl->vcnt);
        /* since file-backed online pages are traversed in reverse order */
-       fe->icpage_ptr = fe->pcl->compressed_pages +
-                       z_erofs_pclusterpages(fe->pcl);
+       fe->icur = z_erofs_pclusterpages(fe->pcl);
        return 0;
 }
 
@@ -593,14 +617,19 @@ static bool z_erofs_collector_end(struct z_erofs_decompress_frontend *fe)
        if (!pcl)
                return false;
 
-       z_erofs_pagevec_ctor_exit(&fe->vector, false);
+       z_erofs_bvec_iter_end(&fe->biter);
        mutex_unlock(&pcl->lock);
 
+       if (fe->candidate_bvpage) {
+               DBG_BUGON(z_erofs_is_shortlived_page(fe->candidate_bvpage));
+               fe->candidate_bvpage = NULL;
+       }
+
        /*
         * if all pending pages are added, don't hold its reference
         * any longer if the pcluster isn't hosted by ourselves.
         */
-       if (fe->mode < COLLECT_PRIMARY_FOLLOWED_NOINPLACE)
+       if (fe->mode < Z_EROFS_PCLUSTER_FOLLOWED_NOINPLACE)
                erofs_workgroup_put(&pcl->obj);
 
        fe->pcl = NULL;
@@ -628,11 +657,10 @@ static int z_erofs_do_read_page(struct z_erofs_decompress_frontend *fe,
        struct erofs_sb_info *const sbi = EROFS_I_SB(inode);
        struct erofs_map_blocks *const map = &fe->map;
        const loff_t offset = page_offset(page);
-       bool tight = true;
+       bool tight = true, exclusive;
 
        enum z_erofs_cache_alloctype cache_strategy;
-       enum z_erofs_page_type page_type;
-       unsigned int cur, end, spiltted, index;
+       unsigned int cur, end, spiltted;
        int err = 0;
 
        /* register locked file pages as online pages in pack */
@@ -653,7 +681,7 @@ repeat:
                map->m_llen = 0;
                err = z_erofs_map_blocks_iter(inode, map, 0);
                if (err)
-                       goto err_out;
+                       goto out;
        } else {
                if (fe->pcl)
                        goto hitted;
@@ -663,9 +691,9 @@ repeat:
        if (!(map->m_flags & EROFS_MAP_MAPPED))
                goto hitted;
 
-       err = z_erofs_collector_begin(fe, inode, map);
+       err = z_erofs_collector_begin(fe);
        if (err)
-               goto err_out;
+               goto out;
 
        if (z_erofs_is_inline_pcluster(fe->pcl)) {
                void *mp;
@@ -676,11 +704,12 @@ repeat:
                        err = PTR_ERR(mp);
                        erofs_err(inode->i_sb,
                                  "failed to get inline page, err %d", err);
-                       goto err_out;
+                       goto out;
                }
                get_page(fe->map.buf.page);
-               WRITE_ONCE(fe->pcl->compressed_pages[0], fe->map.buf.page);
-               fe->mode = COLLECT_PRIMARY_FOLLOWED_NOINPLACE;
+               WRITE_ONCE(fe->pcl->compressed_bvecs[0].page,
+                          fe->map.buf.page);
+               fe->mode = Z_EROFS_PCLUSTER_FOLLOWED_NOINPLACE;
        } else {
                /* bind cache first when cached decompression is preferred */
                if (should_alloc_managed_pages(fe, sbi->opt.cache_strategy,
@@ -696,10 +725,10 @@ hitted:
         * Ensure the current partial page belongs to this submit chain rather
         * than other concurrent submit chains or the noio(bypass) chain since
         * those chains are handled asynchronously thus the page cannot be used
-        * for inplace I/O or pagevec (should be processed in strict order.)
+        * for inplace I/O or bvpage (should be processed in a strict order.)
         */
-       tight &= (fe->mode >= COLLECT_PRIMARY_HOOKED &&
-                 fe->mode != COLLECT_PRIMARY_FOLLOWED_NOINPLACE);
+       tight &= (fe->mode >= Z_EROFS_PCLUSTER_HOOKED &&
+                 fe->mode != Z_EROFS_PCLUSTER_FOLLOWED_NOINPLACE);
 
        cur = end - min_t(unsigned int, offset + end - map->m_la, end);
        if (!(map->m_flags & EROFS_MAP_MAPPED)) {
@@ -707,60 +736,59 @@ hitted:
                goto next_part;
        }
 
-       /* let's derive page type */
-       page_type = cur ? Z_EROFS_VLE_PAGE_TYPE_HEAD :
-               (!spiltted ? Z_EROFS_PAGE_TYPE_EXCLUSIVE :
-                       (tight ? Z_EROFS_PAGE_TYPE_EXCLUSIVE :
-                               Z_EROFS_VLE_PAGE_TYPE_TAIL_SHARED));
-
+       exclusive = (!cur && (!spiltted || tight));
        if (cur)
-               tight &= (fe->mode >= COLLECT_PRIMARY_FOLLOWED);
+               tight &= (fe->mode >= Z_EROFS_PCLUSTER_FOLLOWED);
 
 retry:
-       err = z_erofs_attach_page(fe, page, page_type,
-                                 fe->mode >= COLLECT_PRIMARY_FOLLOWED);
-       /* should allocate an additional short-lived page for pagevec */
-       if (err == -EAGAIN) {
-               struct page *const newpage =
-                               alloc_page(GFP_NOFS | __GFP_NOFAIL);
-
-               set_page_private(newpage, Z_EROFS_SHORTLIVED_PAGE);
-               err = z_erofs_attach_page(fe, newpage,
-                                         Z_EROFS_PAGE_TYPE_EXCLUSIVE, true);
-               if (!err)
-                       goto retry;
+       err = z_erofs_attach_page(fe, &((struct z_erofs_bvec) {
+                                       .page = page,
+                                       .offset = offset - map->m_la,
+                                       .end = end,
+                                 }), exclusive);
+       /* should allocate an additional short-lived page for bvset */
+       if (err == -EAGAIN && !fe->candidate_bvpage) {
+               fe->candidate_bvpage = alloc_page(GFP_NOFS | __GFP_NOFAIL);
+               set_page_private(fe->candidate_bvpage,
+                                Z_EROFS_SHORTLIVED_PAGE);
+               goto retry;
        }
 
-       if (err)
-               goto err_out;
-
-       index = page->index - (map->m_la >> PAGE_SHIFT);
-
-       z_erofs_onlinepage_fixup(page, index, true);
+       if (err) {
+               DBG_BUGON(err == -EAGAIN && fe->candidate_bvpage);
+               goto out;
+       }
 
+       z_erofs_onlinepage_split(page);
        /* bump up the number of spiltted parts of a page */
        ++spiltted;
-       /* also update nr_pages */
-       fe->pcl->nr_pages = max_t(pgoff_t, fe->pcl->nr_pages, index + 1);
+       if (fe->pcl->pageofs_out != (map->m_la & ~PAGE_MASK))
+               fe->pcl->multibases = true;
+
+       if ((map->m_flags & EROFS_MAP_FULL_MAPPED) &&
+           fe->pcl->length == map->m_llen)
+               fe->pcl->partial = false;
+       if (fe->pcl->length < offset + end - map->m_la) {
+               fe->pcl->length = offset + end - map->m_la;
+               fe->pcl->pageofs_out = map->m_la & ~PAGE_MASK;
+       }
 next_part:
-       /* can be used for verification */
+       /* shorten the remaining extent to update progress */
        map->m_llen = offset + cur - map->m_la;
+       map->m_flags &= ~EROFS_MAP_FULL_MAPPED;
 
        end = cur;
        if (end > 0)
                goto repeat;
 
 out:
+       if (err)
+               z_erofs_page_mark_eio(page);
        z_erofs_onlinepage_endio(page);
 
        erofs_dbg("%s, finish page: %pK spiltted: %u map->m_llen %llu",
                  __func__, page, spiltted, map->m_llen);
        return err;
-
-       /* if some error occurred while processing this page */
-err_out:
-       SetPageError(page);
-       goto out;
 }
 
 static bool z_erofs_get_sync_decompress_policy(struct erofs_sb_info *sbi,
@@ -783,97 +811,137 @@ static bool z_erofs_page_is_invalidated(struct page *page)
        return !page->mapping && !z_erofs_is_shortlived_page(page);
 }
 
-static int z_erofs_decompress_pcluster(struct super_block *sb,
-                                      struct z_erofs_pcluster *pcl,
-                                      struct page **pagepool)
-{
-       struct erofs_sb_info *const sbi = EROFS_SB(sb);
-       unsigned int pclusterpages = z_erofs_pclusterpages(pcl);
-       struct z_erofs_pagevec_ctor ctor;
-       unsigned int i, inputsize, outputsize, llen, nr_pages;
-       struct page *pages_onstack[Z_EROFS_VMAP_ONSTACK_PAGES];
-       struct page **pages, **compressed_pages, *page;
+struct z_erofs_decompress_backend {
+       struct page *onstack_pages[Z_EROFS_ONSTACK_PAGES];
+       struct super_block *sb;
+       struct z_erofs_pcluster *pcl;
 
-       enum z_erofs_page_type page_type;
-       bool overlapped, partial;
-       int err;
+       /* pages with the longest decompressed length for deduplication */
+       struct page **decompressed_pages;
+       /* pages to keep the compressed data */
+       struct page **compressed_pages;
 
-       might_sleep();
-       DBG_BUGON(!READ_ONCE(pcl->nr_pages));
+       struct list_head decompressed_secondary_bvecs;
+       struct page **pagepool;
+       unsigned int onstack_used, nr_pages;
+};
 
-       mutex_lock(&pcl->lock);
-       nr_pages = pcl->nr_pages;
+struct z_erofs_bvec_item {
+       struct z_erofs_bvec bvec;
+       struct list_head list;
+};
 
-       if (nr_pages <= Z_EROFS_VMAP_ONSTACK_PAGES) {
-               pages = pages_onstack;
-       } else if (nr_pages <= Z_EROFS_VMAP_GLOBAL_PAGES &&
-                  mutex_trylock(&z_pagemap_global_lock)) {
-               pages = z_pagemap_global;
-       } else {
-               gfp_t gfp_flags = GFP_KERNEL;
+static void z_erofs_do_decompressed_bvec(struct z_erofs_decompress_backend *be,
+                                        struct z_erofs_bvec *bvec)
+{
+       struct z_erofs_bvec_item *item;
 
-               if (nr_pages > Z_EROFS_VMAP_GLOBAL_PAGES)
-                       gfp_flags |= __GFP_NOFAIL;
+       if (!((bvec->offset + be->pcl->pageofs_out) & ~PAGE_MASK)) {
+               unsigned int pgnr;
+               struct page *oldpage;
 
-               pages = kvmalloc_array(nr_pages, sizeof(struct page *),
-                                      gfp_flags);
+               pgnr = (bvec->offset + be->pcl->pageofs_out) >> PAGE_SHIFT;
+               DBG_BUGON(pgnr >= be->nr_pages);
+               oldpage = be->decompressed_pages[pgnr];
+               be->decompressed_pages[pgnr] = bvec->page;
 
-               /* fallback to global pagemap for the lowmem scenario */
-               if (!pages) {
-                       mutex_lock(&z_pagemap_global_lock);
-                       pages = z_pagemap_global;
-               }
+               if (!oldpage)
+                       return;
        }
 
-       for (i = 0; i < nr_pages; ++i)
-               pages[i] = NULL;
-
-       err = 0;
-       z_erofs_pagevec_ctor_init(&ctor, Z_EROFS_NR_INLINE_PAGEVECS,
-                                 pcl->pagevec, 0);
-
-       for (i = 0; i < pcl->vcnt; ++i) {
-               unsigned int pagenr;
+       /* (cold path) one pcluster is requested multiple times */
+       item = kmalloc(sizeof(*item), GFP_KERNEL | __GFP_NOFAIL);
+       item->bvec = *bvec;
+       list_add(&item->list, &be->decompressed_secondary_bvecs);
+}
 
-               page = z_erofs_pagevec_dequeue(&ctor, &page_type);
+static void z_erofs_fill_other_copies(struct z_erofs_decompress_backend *be,
+                                     int err)
+{
+       unsigned int off0 = be->pcl->pageofs_out;
+       struct list_head *p, *n;
+
+       list_for_each_safe(p, n, &be->decompressed_secondary_bvecs) {
+               struct z_erofs_bvec_item *bvi;
+               unsigned int end, cur;
+               void *dst, *src;
+
+               bvi = container_of(p, struct z_erofs_bvec_item, list);
+               cur = bvi->bvec.offset < 0 ? -bvi->bvec.offset : 0;
+               end = min_t(unsigned int, be->pcl->length - bvi->bvec.offset,
+                           bvi->bvec.end);
+               dst = kmap_local_page(bvi->bvec.page);
+               while (cur < end) {
+                       unsigned int pgnr, scur, len;
+
+                       pgnr = (bvi->bvec.offset + cur + off0) >> PAGE_SHIFT;
+                       DBG_BUGON(pgnr >= be->nr_pages);
+
+                       scur = bvi->bvec.offset + cur -
+                                       ((pgnr << PAGE_SHIFT) - off0);
+                       len = min_t(unsigned int, end - cur, PAGE_SIZE - scur);
+                       if (!be->decompressed_pages[pgnr]) {
+                               err = -EFSCORRUPTED;
+                               cur += len;
+                               continue;
+                       }
+                       src = kmap_local_page(be->decompressed_pages[pgnr]);
+                       memcpy(dst + cur, src + scur, len);
+                       kunmap_local(src);
+                       cur += len;
+               }
+               kunmap_local(dst);
+               if (err)
+                       z_erofs_page_mark_eio(bvi->bvec.page);
+               z_erofs_onlinepage_endio(bvi->bvec.page);
+               list_del(p);
+               kfree(bvi);
+       }
+}
 
-               /* all pages in pagevec ought to be valid */
-               DBG_BUGON(!page);
-               DBG_BUGON(z_erofs_page_is_invalidated(page));
+static void z_erofs_parse_out_bvecs(struct z_erofs_decompress_backend *be)
+{
+       struct z_erofs_pcluster *pcl = be->pcl;
+       struct z_erofs_bvec_iter biter;
+       struct page *old_bvpage;
+       int i;
 
-               if (z_erofs_put_shortlivedpage(pagepool, page))
-                       continue;
+       z_erofs_bvec_iter_begin(&biter, &pcl->bvset, Z_EROFS_INLINE_BVECS, 0);
+       for (i = 0; i < pcl->vcnt; ++i) {
+               struct z_erofs_bvec bvec;
 
-               if (page_type == Z_EROFS_VLE_PAGE_TYPE_HEAD)
-                       pagenr = 0;
-               else
-                       pagenr = z_erofs_onlinepage_index(page);
+               z_erofs_bvec_dequeue(&biter, &bvec, &old_bvpage);
 
-               DBG_BUGON(pagenr >= nr_pages);
+               if (old_bvpage)
+                       z_erofs_put_shortlivedpage(be->pagepool, old_bvpage);
 
-               /*
-                * currently EROFS doesn't support multiref(dedup),
-                * so here erroring out one multiref page.
-                */
-               if (pages[pagenr]) {
-                       DBG_BUGON(1);
-                       SetPageError(pages[pagenr]);
-                       z_erofs_onlinepage_endio(pages[pagenr]);
-                       err = -EFSCORRUPTED;
-               }
-               pages[pagenr] = page;
+               DBG_BUGON(z_erofs_page_is_invalidated(bvec.page));
+               z_erofs_do_decompressed_bvec(be, &bvec);
        }
-       z_erofs_pagevec_ctor_exit(&ctor, true);
 
-       overlapped = false;
-       compressed_pages = pcl->compressed_pages;
+       old_bvpage = z_erofs_bvec_iter_end(&biter);
+       if (old_bvpage)
+               z_erofs_put_shortlivedpage(be->pagepool, old_bvpage);
+}
 
+static int z_erofs_parse_in_bvecs(struct z_erofs_decompress_backend *be,
+                                 bool *overlapped)
+{
+       struct z_erofs_pcluster *pcl = be->pcl;
+       unsigned int pclusterpages = z_erofs_pclusterpages(pcl);
+       int i, err = 0;
+
+       *overlapped = false;
        for (i = 0; i < pclusterpages; ++i) {
-               unsigned int pagenr;
+               struct z_erofs_bvec *bvec = &pcl->compressed_bvecs[i];
+               struct page *page = bvec->page;
 
-               page = compressed_pages[i];
-               /* all compressed pages ought to be valid */
-               DBG_BUGON(!page);
+               /* compressed pages ought to be present before decompressing */
+               if (!page) {
+                       DBG_BUGON(1);
+                       continue;
+               }
+               be->compressed_pages[i] = page;
 
                if (z_erofs_is_inline_pcluster(pcl)) {
                        if (!PageUptodate(page))
@@ -883,109 +951,129 @@ static int z_erofs_decompress_pcluster(struct super_block *sb,
 
                DBG_BUGON(z_erofs_page_is_invalidated(page));
                if (!z_erofs_is_shortlived_page(page)) {
-                       if (erofs_page_is_managed(sbi, page)) {
+                       if (erofs_page_is_managed(EROFS_SB(be->sb), page)) {
                                if (!PageUptodate(page))
                                        err = -EIO;
                                continue;
                        }
+                       z_erofs_do_decompressed_bvec(be, bvec);
+                       *overlapped = true;
+               }
+       }
 
-                       /*
-                        * only if non-head page can be selected
-                        * for inplace decompression
-                        */
-                       pagenr = z_erofs_onlinepage_index(page);
-
-                       DBG_BUGON(pagenr >= nr_pages);
-                       if (pages[pagenr]) {
-                               DBG_BUGON(1);
-                               SetPageError(pages[pagenr]);
-                               z_erofs_onlinepage_endio(pages[pagenr]);
-                               err = -EFSCORRUPTED;
-                       }
-                       pages[pagenr] = page;
+       if (err)
+               return err;
+       return 0;
+}
 
-                       overlapped = true;
-               }
+static int z_erofs_decompress_pcluster(struct z_erofs_decompress_backend *be,
+                                      int err)
+{
+       struct erofs_sb_info *const sbi = EROFS_SB(be->sb);
+       struct z_erofs_pcluster *pcl = be->pcl;
+       unsigned int pclusterpages = z_erofs_pclusterpages(pcl);
+       unsigned int i, inputsize;
+       int err2;
+       struct page *page;
+       bool overlapped;
 
-               /* PG_error needs checking for all non-managed pages */
-               if (PageError(page)) {
-                       DBG_BUGON(PageUptodate(page));
-                       err = -EIO;
-               }
+       mutex_lock(&pcl->lock);
+       be->nr_pages = PAGE_ALIGN(pcl->length + pcl->pageofs_out) >> PAGE_SHIFT;
+
+       /* allocate (de)compressed page arrays if cannot be kept on stack */
+       be->decompressed_pages = NULL;
+       be->compressed_pages = NULL;
+       be->onstack_used = 0;
+       if (be->nr_pages <= Z_EROFS_ONSTACK_PAGES) {
+               be->decompressed_pages = be->onstack_pages;
+               be->onstack_used = be->nr_pages;
+               memset(be->decompressed_pages, 0,
+                      sizeof(struct page *) * be->nr_pages);
        }
 
+       if (pclusterpages + be->onstack_used <= Z_EROFS_ONSTACK_PAGES)
+               be->compressed_pages = be->onstack_pages + be->onstack_used;
+
+       if (!be->decompressed_pages)
+               be->decompressed_pages =
+                       kvcalloc(be->nr_pages, sizeof(struct page *),
+                                GFP_KERNEL | __GFP_NOFAIL);
+       if (!be->compressed_pages)
+               be->compressed_pages =
+                       kvcalloc(pclusterpages, sizeof(struct page *),
+                                GFP_KERNEL | __GFP_NOFAIL);
+
+       z_erofs_parse_out_bvecs(be);
+       err2 = z_erofs_parse_in_bvecs(be, &overlapped);
+       if (err2)
+               err = err2;
        if (err)
                goto out;
 
-       llen = pcl->length >> Z_EROFS_PCLUSTER_LENGTH_BIT;
-       if (nr_pages << PAGE_SHIFT >= pcl->pageofs_out + llen) {
-               outputsize = llen;
-               partial = !(pcl->length & Z_EROFS_PCLUSTER_FULL_LENGTH);
-       } else {
-               outputsize = (nr_pages << PAGE_SHIFT) - pcl->pageofs_out;
-               partial = true;
-       }
-
        if (z_erofs_is_inline_pcluster(pcl))
                inputsize = pcl->tailpacking_size;
        else
                inputsize = pclusterpages * PAGE_SIZE;
 
        err = z_erofs_decompress(&(struct z_erofs_decompress_req) {
-                                       .sb = sb,
-                                       .in = compressed_pages,
-                                       .out = pages,
+                                       .sb = be->sb,
+                                       .in = be->compressed_pages,
+                                       .out = be->decompressed_pages,
                                        .pageofs_in = pcl->pageofs_in,
                                        .pageofs_out = pcl->pageofs_out,
                                        .inputsize = inputsize,
-                                       .outputsize = outputsize,
+                                       .outputsize = pcl->length,
                                        .alg = pcl->algorithmformat,
                                        .inplace_io = overlapped,
-                                       .partial_decoding = partial
-                                }, pagepool);
+                                       .partial_decoding = pcl->partial,
+                                       .fillgaps = pcl->multibases,
+                                }, be->pagepool);
 
 out:
        /* must handle all compressed pages before actual file pages */
        if (z_erofs_is_inline_pcluster(pcl)) {
-               page = compressed_pages[0];
-               WRITE_ONCE(compressed_pages[0], NULL);
+               page = pcl->compressed_bvecs[0].page;
+               WRITE_ONCE(pcl->compressed_bvecs[0].page, NULL);
                put_page(page);
        } else {
                for (i = 0; i < pclusterpages; ++i) {
-                       page = compressed_pages[i];
+                       page = pcl->compressed_bvecs[i].page;
 
                        if (erofs_page_is_managed(sbi, page))
                                continue;
 
                        /* recycle all individual short-lived pages */
-                       (void)z_erofs_put_shortlivedpage(pagepool, page);
-                       WRITE_ONCE(compressed_pages[i], NULL);
+                       (void)z_erofs_put_shortlivedpage(be->pagepool, page);
+                       WRITE_ONCE(pcl->compressed_bvecs[i].page, NULL);
                }
        }
+       if (be->compressed_pages < be->onstack_pages ||
+           be->compressed_pages >= be->onstack_pages + Z_EROFS_ONSTACK_PAGES)
+               kvfree(be->compressed_pages);
+       z_erofs_fill_other_copies(be, err);
 
-       for (i = 0; i < nr_pages; ++i) {
-               page = pages[i];
+       for (i = 0; i < be->nr_pages; ++i) {
+               page = be->decompressed_pages[i];
                if (!page)
                        continue;
 
                DBG_BUGON(z_erofs_page_is_invalidated(page));
 
                /* recycle all individual short-lived pages */
-               if (z_erofs_put_shortlivedpage(pagepool, page))
+               if (z_erofs_put_shortlivedpage(be->pagepool, page))
                        continue;
-
-               if (err < 0)
-                       SetPageError(page);
-
+               if (err)
+                       z_erofs_page_mark_eio(page);
                z_erofs_onlinepage_endio(page);
        }
 
-       if (pages == z_pagemap_global)
-               mutex_unlock(&z_pagemap_global_lock);
-       else if (pages != pages_onstack)
-               kvfree(pages);
+       if (be->decompressed_pages != be->onstack_pages)
+               kvfree(be->decompressed_pages);
 
-       pcl->nr_pages = 0;
+       pcl->length = 0;
+       pcl->partial = true;
+       pcl->multibases = false;
+       pcl->bvset.nextpage = NULL;
        pcl->vcnt = 0;
 
        /* pcluster lock MUST be taken before the following line */
@@ -997,22 +1085,25 @@ out:
 static void z_erofs_decompress_queue(const struct z_erofs_decompressqueue *io,
                                     struct page **pagepool)
 {
+       struct z_erofs_decompress_backend be = {
+               .sb = io->sb,
+               .pagepool = pagepool,
+               .decompressed_secondary_bvecs =
+                       LIST_HEAD_INIT(be.decompressed_secondary_bvecs),
+       };
        z_erofs_next_pcluster_t owned = io->head;
 
        while (owned != Z_EROFS_PCLUSTER_TAIL_CLOSED) {
-               struct z_erofs_pcluster *pcl;
-
-               /* no possible that 'owned' equals Z_EROFS_WORK_TPTR_TAIL */
+               /* impossible that 'owned' equals Z_EROFS_WORK_TPTR_TAIL */
                DBG_BUGON(owned == Z_EROFS_PCLUSTER_TAIL);
-
-               /* no possible that 'owned' equals NULL */
+               /* impossible that 'owned' equals Z_EROFS_PCLUSTER_NIL */
                DBG_BUGON(owned == Z_EROFS_PCLUSTER_NIL);
 
-               pcl = container_of(owned, struct z_erofs_pcluster, next);
-               owned = READ_ONCE(pcl->next);
+               be.pcl = container_of(owned, struct z_erofs_pcluster, next);
+               owned = READ_ONCE(be.pcl->next);
 
-               z_erofs_decompress_pcluster(io->sb, pcl, pagepool);
-               erofs_workgroup_put(&pcl->obj);
+               z_erofs_decompress_pcluster(&be, io->eio ? -EIO : 0);
+               erofs_workgroup_put(&be.pcl->obj);
        }
 }
 
@@ -1038,7 +1129,6 @@ static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io,
        if (sync) {
                if (!atomic_add_return(bios, &io->pending_bios))
                        complete(&io->u.done);
-
                return;
        }
 
@@ -1071,7 +1161,7 @@ static struct page *pickup_page_for_submission(struct z_erofs_pcluster *pcl,
        int justfound;
 
 repeat:
-       page = READ_ONCE(pcl->compressed_pages[nr]);
+       page = READ_ONCE(pcl->compressed_bvecs[nr].page);
        oldpage = page;
 
        if (!page)
@@ -1087,7 +1177,7 @@ repeat:
         * otherwise, it will go inplace I/O path instead.
         */
        if (page->private == Z_EROFS_PREALLOCATED_PAGE) {
-               WRITE_ONCE(pcl->compressed_pages[nr], page);
+               WRITE_ONCE(pcl->compressed_bvecs[nr].page, page);
                set_page_private(page, 0);
                tocache = true;
                goto out_tocache;
@@ -1113,14 +1203,13 @@ repeat:
 
        /* the page is still in manage cache */
        if (page->mapping == mc) {
-               WRITE_ONCE(pcl->compressed_pages[nr], page);
+               WRITE_ONCE(pcl->compressed_bvecs[nr].page, page);
 
-               ClearPageError(page);
                if (!PagePrivate(page)) {
                        /*
                         * impossible to be !PagePrivate(page) for
                         * the current restriction as well if
-                        * the page is already in compressed_pages[].
+                        * the page is already in compressed_bvecs[].
                         */
                        DBG_BUGON(!justfound);
 
@@ -1149,7 +1238,8 @@ repeat:
        put_page(page);
 out_allocpage:
        page = erofs_allocpage(pagepool, gfp | __GFP_NOFAIL);
-       if (oldpage != cmpxchg(&pcl->compressed_pages[nr], oldpage, page)) {
+       if (oldpage != cmpxchg(&pcl->compressed_bvecs[nr].page,
+                              oldpage, page)) {
                erofs_pagepool_add(pagepool, page);
                cond_resched();
                goto repeat;
@@ -1186,6 +1276,7 @@ fg_out:
                q = fgq;
                init_completion(&fgq->u.done);
                atomic_set(&fgq->pending_bios, 0);
+               q->eio = false;
        }
        q->sb = sb;
        q->head = Z_EROFS_PCLUSTER_TAIL_CLOSED;
@@ -1246,26 +1337,25 @@ static void z_erofs_decompressqueue_endio(struct bio *bio)
                DBG_BUGON(PageUptodate(page));
                DBG_BUGON(z_erofs_page_is_invalidated(page));
 
-               if (err)
-                       SetPageError(page);
-
                if (erofs_page_is_managed(EROFS_SB(q->sb), page)) {
                        if (!err)
                                SetPageUptodate(page);
                        unlock_page(page);
                }
        }
+       if (err)
+               q->eio = true;
        z_erofs_decompress_kickoff(q, tagptr_unfold_tags(t), -1);
        bio_put(bio);
 }
 
-static void z_erofs_submit_queue(struct super_block *sb,
-                                struct z_erofs_decompress_frontend *f,
+static void z_erofs_submit_queue(struct z_erofs_decompress_frontend *f,
                                 struct page **pagepool,
                                 struct z_erofs_decompressqueue *fgq,
                                 bool *force_fg)
 {
-       struct erofs_sb_info *const sbi = EROFS_SB(sb);
+       struct super_block *sb = f->inode->i_sb;
+       struct address_space *mc = MNGD_MAPPING(EROFS_SB(sb));
        z_erofs_next_pcluster_t qtail[NR_JOBQUEUES];
        struct z_erofs_decompressqueue *q[NR_JOBQUEUES];
        void *bi_private;
@@ -1317,7 +1407,7 @@ static void z_erofs_submit_queue(struct super_block *sb,
                        struct page *page;
 
                        page = pickup_page_for_submission(pcl, i++, pagepool,
-                                                         MNGD_MAPPING(sbi));
+                                                         mc);
                        if (!page)
                                continue;
 
@@ -1369,15 +1459,14 @@ submit_bio_retry:
        z_erofs_decompress_kickoff(q[JQ_SUBMIT], *force_fg, nr_bios);
 }
 
-static void z_erofs_runqueue(struct super_block *sb,
-                            struct z_erofs_decompress_frontend *f,
+static void z_erofs_runqueue(struct z_erofs_decompress_frontend *f,
                             struct page **pagepool, bool force_fg)
 {
        struct z_erofs_decompressqueue io[NR_JOBQUEUES];
 
        if (f->owned_head == Z_EROFS_PCLUSTER_TAIL)
                return;
-       z_erofs_submit_queue(sb, f, pagepool, io, &force_fg);
+       z_erofs_submit_queue(f, pagepool, io, &force_fg);
 
        /* handle bypass queue (no i/o pclusters) immediately */
        z_erofs_decompress_queue(&io[JQ_BYPASS], pagepool);
@@ -1475,7 +1564,7 @@ static int z_erofs_read_folio(struct file *file, struct folio *folio)
        (void)z_erofs_collector_end(&f);
 
        /* if some compressed cluster ready, need submit them anyway */
-       z_erofs_runqueue(inode->i_sb, &f, &pagepool,
+       z_erofs_runqueue(&f, &pagepool,
                         z_erofs_get_sync_decompress_policy(sbi, 0));
 
        if (err)
@@ -1524,7 +1613,7 @@ static void z_erofs_readahead(struct readahead_control *rac)
        z_erofs_pcluster_readmore(&f, rac, 0, &pagepool, false);
        (void)z_erofs_collector_end(&f);
 
-       z_erofs_runqueue(inode->i_sb, &f, &pagepool,
+       z_erofs_runqueue(&f, &pagepool,
                         z_erofs_get_sync_decompress_policy(sbi, nr_pages));
        erofs_put_metabuf(&f.map.buf);
        erofs_release_pages(&pagepool);
index 58053bb..e7f04c4 100644 (file)
@@ -7,13 +7,10 @@
 #define __EROFS_FS_ZDATA_H
 
 #include "internal.h"
-#include "zpvec.h"
+#include "tagptr.h"
 
 #define Z_EROFS_PCLUSTER_MAX_PAGES     (Z_EROFS_PCLUSTER_MAX_SIZE / PAGE_SIZE)
-#define Z_EROFS_NR_INLINE_PAGEVECS      3
-
-#define Z_EROFS_PCLUSTER_FULL_LENGTH    0x00000001
-#define Z_EROFS_PCLUSTER_LENGTH_BIT     1
+#define Z_EROFS_INLINE_BVECS           2
 
 /*
  * let's leave a type here in case of introducing
  */
 typedef void *z_erofs_next_pcluster_t;
 
+struct z_erofs_bvec {
+       struct page *page;
+       int offset;
+       unsigned int end;
+};
+
+#define __Z_EROFS_BVSET(name, total) \
+struct name { \
+       /* point to the next page which contains the following bvecs */ \
+       struct page *nextpage; \
+       struct z_erofs_bvec bvec[total]; \
+}
+__Z_EROFS_BVSET(z_erofs_bvset,);
+__Z_EROFS_BVSET(z_erofs_bvset_inline, Z_EROFS_INLINE_BVECS);
+
 /*
  * Structure fields follow one of the following exclusion rules.
  *
@@ -38,24 +50,21 @@ struct z_erofs_pcluster {
        /* A: point to next chained pcluster or TAILs */
        z_erofs_next_pcluster_t next;
 
-       /* A: lower limit of decompressed length and if full length or not */
+       /* L: the maximum decompression size of this round */
        unsigned int length;
 
+       /* L: total number of bvecs */
+       unsigned int vcnt;
+
        /* I: page offset of start position of decompression */
        unsigned short pageofs_out;
 
        /* I: page offset of inline compressed data */
        unsigned short pageofs_in;
 
-       /* L: maximum relative page index in pagevec[] */
-       unsigned short nr_pages;
-
-       /* L: total number of pages in pagevec[] */
-       unsigned int vcnt;
-
        union {
-               /* L: inline a certain number of pagevecs for bootstrap */
-               erofs_vtptr_t pagevec[Z_EROFS_NR_INLINE_PAGEVECS];
+               /* L: inline a certain number of bvec for bootstrap */
+               struct z_erofs_bvset_inline bvset;
 
                /* I: can be used to free the pcluster by RCU. */
                struct rcu_head rcu;
@@ -72,8 +81,14 @@ struct z_erofs_pcluster {
        /* I: compression algorithm format */
        unsigned char algorithmformat;
 
-       /* A: compressed pages (can be cached or inplaced pages) */
-       struct page *compressed_pages[];
+       /* L: whether partial decompression or not */
+       bool partial;
+
+       /* L: indicate several pageofs_outs or not */
+       bool multibases;
+
+       /* A: compressed bvecs (can be cached or inplaced pages) */
+       struct z_erofs_bvec compressed_bvecs[];
 };
 
 /* let's avoid the valid 32-bit kernel addresses */
@@ -94,6 +109,8 @@ struct z_erofs_decompressqueue {
                struct completion done;
                struct work_struct work;
        } u;
+
+       bool eio;
 };
 
 static inline bool z_erofs_is_inline_pcluster(struct z_erofs_pcluster *pcl)
@@ -108,38 +125,17 @@ static inline unsigned int z_erofs_pclusterpages(struct z_erofs_pcluster *pcl)
        return pcl->pclusterpages;
 }
 
-#define Z_EROFS_ONLINEPAGE_COUNT_BITS   2
-#define Z_EROFS_ONLINEPAGE_COUNT_MASK   ((1 << Z_EROFS_ONLINEPAGE_COUNT_BITS) - 1)
-#define Z_EROFS_ONLINEPAGE_INDEX_SHIFT  (Z_EROFS_ONLINEPAGE_COUNT_BITS)
-
 /*
- * waiters (aka. ongoing_packs): # to unlock the page
- * sub-index: 0 - for partial page, >= 1 full page sub-index
+ * bit 31: I/O error occurred on this page
+ * bit 0 - 30: remaining parts to complete this page
  */
-typedef atomic_t z_erofs_onlinepage_t;
-
-/* type punning */
-union z_erofs_onlinepage_converter {
-       z_erofs_onlinepage_t *o;
-       unsigned long *v;
-};
-
-static inline unsigned int z_erofs_onlinepage_index(struct page *page)
-{
-       union z_erofs_onlinepage_converter u;
-
-       DBG_BUGON(!PagePrivate(page));
-       u.v = &page_private(page);
-
-       return atomic_read(u.o) >> Z_EROFS_ONLINEPAGE_INDEX_SHIFT;
-}
+#define Z_EROFS_PAGE_EIO                       (1 << 31)
 
 static inline void z_erofs_onlinepage_init(struct page *page)
 {
        union {
-               z_erofs_onlinepage_t o;
+               atomic_t o;
                unsigned long v;
-       /* keep from being unlocked in advance */
        } u = { .o = ATOMIC_INIT(1) };
 
        set_page_private(page, u.v);
@@ -147,49 +143,36 @@ static inline void z_erofs_onlinepage_init(struct page *page)
        SetPagePrivate(page);
 }
 
-static inline void z_erofs_onlinepage_fixup(struct page *page,
-       uintptr_t index, bool down)
+static inline void z_erofs_onlinepage_split(struct page *page)
 {
-       union z_erofs_onlinepage_converter u = { .v = &page_private(page) };
-       int orig, orig_index, val;
-
-repeat:
-       orig = atomic_read(u.o);
-       orig_index = orig >> Z_EROFS_ONLINEPAGE_INDEX_SHIFT;
-       if (orig_index) {
-               if (!index)
-                       return;
+       atomic_inc((atomic_t *)&page->private);
+}
 
-               DBG_BUGON(orig_index != index);
-       }
+static inline void z_erofs_page_mark_eio(struct page *page)
+{
+       int orig;
 
-       val = (index << Z_EROFS_ONLINEPAGE_INDEX_SHIFT) |
-               ((orig & Z_EROFS_ONLINEPAGE_COUNT_MASK) + (unsigned int)down);
-       if (atomic_cmpxchg(u.o, orig, val) != orig)
-               goto repeat;
+       do {
+               orig = atomic_read((atomic_t *)&page->private);
+       } while (atomic_cmpxchg((atomic_t *)&page->private, orig,
+                               orig | Z_EROFS_PAGE_EIO) != orig);
 }
 
 static inline void z_erofs_onlinepage_endio(struct page *page)
 {
-       union z_erofs_onlinepage_converter u;
        unsigned int v;
 
        DBG_BUGON(!PagePrivate(page));
-       u.v = &page_private(page);
-
-       v = atomic_dec_return(u.o);
-       if (!(v & Z_EROFS_ONLINEPAGE_COUNT_MASK)) {
+       v = atomic_dec_return((atomic_t *)&page->private);
+       if (!(v & ~Z_EROFS_PAGE_EIO)) {
                set_page_private(page, 0);
                ClearPagePrivate(page);
-               if (!PageError(page))
+               if (!(v & Z_EROFS_PAGE_EIO))
                        SetPageUptodate(page);
                unlock_page(page);
        }
-       erofs_dbg("%s, page %p value %x", __func__, page, atomic_read(u.o));
 }
 
-#define Z_EROFS_VMAP_ONSTACK_PAGES     \
-       min_t(unsigned int, THREAD_SIZE / 8 / sizeof(struct page *), 96U)
-#define Z_EROFS_VMAP_GLOBAL_PAGES      2048
+#define Z_EROFS_ONSTACK_PAGES          32
 
 #endif
diff --git a/fs/erofs/zpvec.h b/fs/erofs/zpvec.h
deleted file mode 100644 (file)
index b05464f..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (C) 2018 HUAWEI, Inc.
- *             https://www.huawei.com/
- */
-#ifndef __EROFS_FS_ZPVEC_H
-#define __EROFS_FS_ZPVEC_H
-
-#include "tagptr.h"
-
-/* page type in pagevec for decompress subsystem */
-enum z_erofs_page_type {
-       /* including Z_EROFS_VLE_PAGE_TAIL_EXCLUSIVE */
-       Z_EROFS_PAGE_TYPE_EXCLUSIVE,
-
-       Z_EROFS_VLE_PAGE_TYPE_TAIL_SHARED,
-
-       Z_EROFS_VLE_PAGE_TYPE_HEAD,
-       Z_EROFS_VLE_PAGE_TYPE_MAX
-};
-
-extern void __compiletime_error("Z_EROFS_PAGE_TYPE_EXCLUSIVE != 0")
-       __bad_page_type_exclusive(void);
-
-/* pagevec tagged pointer */
-typedef tagptr2_t      erofs_vtptr_t;
-
-/* pagevec collector */
-struct z_erofs_pagevec_ctor {
-       struct page *curr, *next;
-       erofs_vtptr_t *pages;
-
-       unsigned int nr, index;
-};
-
-static inline void z_erofs_pagevec_ctor_exit(struct z_erofs_pagevec_ctor *ctor,
-                                            bool atomic)
-{
-       if (!ctor->curr)
-               return;
-
-       if (atomic)
-               kunmap_atomic(ctor->pages);
-       else
-               kunmap(ctor->curr);
-}
-
-static inline struct page *
-z_erofs_pagevec_ctor_next_page(struct z_erofs_pagevec_ctor *ctor,
-                              unsigned int nr)
-{
-       unsigned int index;
-
-       /* keep away from occupied pages */
-       if (ctor->next)
-               return ctor->next;
-
-       for (index = 0; index < nr; ++index) {
-               const erofs_vtptr_t t = ctor->pages[index];
-               const unsigned int tags = tagptr_unfold_tags(t);
-
-               if (tags == Z_EROFS_PAGE_TYPE_EXCLUSIVE)
-                       return tagptr_unfold_ptr(t);
-       }
-       DBG_BUGON(nr >= ctor->nr);
-       return NULL;
-}
-
-static inline void
-z_erofs_pagevec_ctor_pagedown(struct z_erofs_pagevec_ctor *ctor,
-                             bool atomic)
-{
-       struct page *next = z_erofs_pagevec_ctor_next_page(ctor, ctor->nr);
-
-       z_erofs_pagevec_ctor_exit(ctor, atomic);
-
-       ctor->curr = next;
-       ctor->next = NULL;
-       ctor->pages = atomic ?
-               kmap_atomic(ctor->curr) : kmap(ctor->curr);
-
-       ctor->nr = PAGE_SIZE / sizeof(struct page *);
-       ctor->index = 0;
-}
-
-static inline void z_erofs_pagevec_ctor_init(struct z_erofs_pagevec_ctor *ctor,
-                                            unsigned int nr,
-                                            erofs_vtptr_t *pages,
-                                            unsigned int i)
-{
-       ctor->nr = nr;
-       ctor->curr = ctor->next = NULL;
-       ctor->pages = pages;
-
-       if (i >= nr) {
-               i -= nr;
-               z_erofs_pagevec_ctor_pagedown(ctor, false);
-               while (i > ctor->nr) {
-                       i -= ctor->nr;
-                       z_erofs_pagevec_ctor_pagedown(ctor, false);
-               }
-       }
-       ctor->next = z_erofs_pagevec_ctor_next_page(ctor, i);
-       ctor->index = i;
-}
-
-static inline bool z_erofs_pagevec_enqueue(struct z_erofs_pagevec_ctor *ctor,
-                                          struct page *page,
-                                          enum z_erofs_page_type type,
-                                          bool pvec_safereuse)
-{
-       if (!ctor->next) {
-               /* some pages cannot be reused as pvec safely without I/O */
-               if (type == Z_EROFS_PAGE_TYPE_EXCLUSIVE && !pvec_safereuse)
-                       type = Z_EROFS_VLE_PAGE_TYPE_TAIL_SHARED;
-
-               if (type != Z_EROFS_PAGE_TYPE_EXCLUSIVE &&
-                   ctor->index + 1 == ctor->nr)
-                       return false;
-       }
-
-       if (ctor->index >= ctor->nr)
-               z_erofs_pagevec_ctor_pagedown(ctor, false);
-
-       /* exclusive page type must be 0 */
-       if (Z_EROFS_PAGE_TYPE_EXCLUSIVE != (uintptr_t)NULL)
-               __bad_page_type_exclusive();
-
-       /* should remind that collector->next never equal to 1, 2 */
-       if (type == (uintptr_t)ctor->next) {
-               ctor->next = page;
-       }
-       ctor->pages[ctor->index++] = tagptr_fold(erofs_vtptr_t, page, type);
-       return true;
-}
-
-static inline struct page *
-z_erofs_pagevec_dequeue(struct z_erofs_pagevec_ctor *ctor,
-                       enum z_erofs_page_type *type)
-{
-       erofs_vtptr_t t;
-
-       if (ctor->index >= ctor->nr) {
-               DBG_BUGON(!ctor->next);
-               z_erofs_pagevec_ctor_pagedown(ctor, true);
-       }
-
-       t = ctor->pages[ctor->index];
-
-       *type = tagptr_unfold_tags(t);
-
-       /* should remind that collector->next never equal to 1, 2 */
-       if (*type == (uintptr_t)ctor->next)
-               ctor->next = tagptr_unfold_ptr(t);
-
-       ctor->pages[ctor->index++] = tagptr_fold(erofs_vtptr_t, NULL, 0);
-       return tagptr_unfold_ptr(t);
-}
-#endif
index 0989fb8..5fd7391 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -65,6 +65,7 @@
 #include <linux/io_uring.h>
 #include <linux/syscall_user_dispatch.h>
 #include <linux/coredump.h>
+#include <linux/time_namespace.h>
 
 #include <linux/uaccess.h>
 #include <asm/mmu_context.h>
@@ -630,7 +631,6 @@ int copy_string_kernel(const char *arg, struct linux_binprm *bprm)
                unsigned int bytes_to_copy = min_t(unsigned int, len,
                                min_not_zero(offset_in_page(pos), PAGE_SIZE));
                struct page *page;
-               char *kaddr;
 
                pos -= bytes_to_copy;
                arg -= bytes_to_copy;
@@ -639,11 +639,8 @@ int copy_string_kernel(const char *arg, struct linux_binprm *bprm)
                page = get_arg_page(bprm, pos, 1);
                if (!page)
                        return -E2BIG;
-               kaddr = kmap_atomic(page);
                flush_arg_page(bprm, pos & PAGE_MASK, page);
-               memcpy(kaddr + offset_in_page(pos), arg, bytes_to_copy);
-               flush_dcache_page(page);
-               kunmap_atomic(kaddr);
+               memcpy_to_page(page, offset_in_page(pos), arg, bytes_to_copy);
                put_arg_page(page);
        }
 
@@ -982,10 +979,12 @@ static int exec_mmap(struct mm_struct *mm)
 {
        struct task_struct *tsk;
        struct mm_struct *old_mm, *active_mm;
+       bool vfork;
        int ret;
 
        /* Notify parent that we're no longer interested in the old VM */
        tsk = current;
+       vfork = !!tsk->vfork_done;
        old_mm = current->mm;
        exec_mm_release(tsk, old_mm);
        if (old_mm)
@@ -1030,6 +1029,10 @@ static int exec_mmap(struct mm_struct *mm)
        tsk->mm->vmacache_seqnum = 0;
        vmacache_flush(tsk);
        task_unlock(tsk);
+
+       if (vfork)
+               timens_on_fork(tsk->nsproxy, tsk);
+
        if (old_mm) {
                mmap_read_unlock(old_mm);
                BUG_ON(active_mm != old_mm);
@@ -1149,7 +1152,7 @@ static int de_thread(struct task_struct *tsk)
                /*
                 * We are going to release_task()->ptrace_unlink() silently,
                 * the tracer can sleep in do_wait(). EXIT_DEAD guarantees
-                * the tracer wont't block again waiting for this thread.
+                * the tracer won't block again waiting for this thread.
                 */
                if (unlikely(leader->ptrace))
                        __wake_up_parent(leader, leader->parent);
@@ -1301,7 +1304,7 @@ int begin_new_exec(struct linux_binprm * bprm)
        bprm->mm = NULL;
 
 #ifdef CONFIG_POSIX_TIMERS
-       exit_itimers(me->signal);
+       exit_itimers(me);
        flush_itimer_signals();
 #endif
 
index 76acc37..c6eaf7e 100644 (file)
@@ -1198,7 +1198,9 @@ static int __exfat_rename(struct inode *old_parent_inode,
                return -ENOENT;
        }
 
-       exfat_chain_dup(&olddir, &ei->dir);
+       exfat_chain_set(&olddir, EXFAT_I(old_parent_inode)->start_clu,
+               EXFAT_B_TO_CLU_ROUND_UP(i_size_read(old_parent_inode), sbi),
+               EXFAT_I(old_parent_inode)->flags);
        dentry = ei->entry;
 
        ep = exfat_get_dentry(sb, &olddir, dentry, &old_bh);
index c522903..918ab2f 100644 (file)
@@ -1634,14 +1634,14 @@ int ext2_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
        if (error)
                return error;
 
-       if (is_quota_modification(inode, iattr)) {
+       if (is_quota_modification(mnt_userns, inode, iattr)) {
                error = dquot_initialize(inode);
                if (error)
                        return error;
        }
-       if ((iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)) ||
-           (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))) {
-               error = dquot_transfer(inode, iattr);
+       if (i_uid_needs_update(mnt_userns, iattr, inode) ||
+           i_gid_needs_update(mnt_userns, iattr, inode)) {
+               error = dquot_transfer(mnt_userns, inode, iattr);
                if (error)
                        return error;
        }
index a1c1263..27a0a8c 100644 (file)
@@ -1057,9 +1057,10 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
                        sbi->s_frags_per_group);
                goto failed_mount;
        }
-       if (sbi->s_inodes_per_group > sb->s_blocksize * 8) {
+       if (sbi->s_inodes_per_group < sbi->s_inodes_per_block ||
+           sbi->s_inodes_per_group > sb->s_blocksize * 8) {
                ext2_msg(sb, KERN_ERR,
-                       "error: #inodes per group too big: %lu",
+                       "error: invalid #inodes per group: %lu",
                        sbi->s_inodes_per_group);
                goto failed_mount;
        }
@@ -1069,6 +1070,13 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
        sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) -
                                le32_to_cpu(es->s_first_data_block) - 1)
                                        / EXT2_BLOCKS_PER_GROUP(sb)) + 1;
+       if ((u64)sbi->s_groups_count * sbi->s_inodes_per_group !=
+           le32_to_cpu(es->s_inodes_count)) {
+               ext2_msg(sb, KERN_ERR, "error: invalid #inodes: %u vs computed %llu",
+                        le32_to_cpu(es->s_inodes_count),
+                        (u64)sbi->s_groups_count * sbi->s_inodes_per_group);
+               goto failed_mount;
+       }
        db_count = (sbi->s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) /
                   EXT2_DESC_PER_BLOCK(sb);
        sbi->s_group_desc = kmalloc_array(db_count,
@@ -1488,8 +1496,7 @@ static ssize_t ext2_quota_read(struct super_block *sb, int type, char *data,
                len = i_size-off;
        toread = len;
        while (toread > 0) {
-               tocopy = sb->s_blocksize - offset < toread ?
-                               sb->s_blocksize - offset : toread;
+               tocopy = min_t(size_t, sb->s_blocksize - offset, toread);
 
                tmp_bh.b_state = 0;
                tmp_bh.b_size = sb->s_blocksize;
@@ -1527,8 +1534,7 @@ static ssize_t ext2_quota_write(struct super_block *sb, int type,
        struct buffer_head *bh;
 
        while (towrite > 0) {
-               tocopy = sb->s_blocksize - offset < towrite ?
-                               sb->s_blocksize - offset : towrite;
+               tocopy = min_t(size_t, sb->s_blocksize - offset, towrite);
 
                tmp_bh.b_state = 0;
                tmp_bh.b_size = sb->s_blocksize;
index 75b8d81..29fc575 100644 (file)
@@ -3058,14 +3058,14 @@ extern unsigned int ext4_list_backups(struct super_block *sb,
 
 /* super.c */
 extern struct buffer_head *ext4_sb_bread(struct super_block *sb,
-                                        sector_t block, int op_flags);
+                                        sector_t block, blk_opf_t op_flags);
 extern struct buffer_head *ext4_sb_bread_unmovable(struct super_block *sb,
                                                   sector_t block);
-extern void ext4_read_bh_nowait(struct buffer_head *bh, int op_flags,
+extern void ext4_read_bh_nowait(struct buffer_head *bh, blk_opf_t op_flags,
                                bh_end_io_t *end_io);
-extern int ext4_read_bh(struct buffer_head *bh, int op_flags,
+extern int ext4_read_bh(struct buffer_head *bh, blk_opf_t op_flags,
                        bh_end_io_t *end_io);
-extern int ext4_read_bh_lock(struct buffer_head *bh, int op_flags, bool wait);
+extern int ext4_read_bh_lock(struct buffer_head *bh, blk_opf_t op_flags, bool wait);
 extern void ext4_sb_breadahead_unmovable(struct super_block *sb, sector_t block);
 extern int ext4_seq_options_show(struct seq_file *seq, void *offset);
 extern int ext4_calculate_overhead(struct super_block *sb);
index 795a60a..eb4c8ad 100644 (file)
@@ -658,7 +658,7 @@ void ext4_fc_track_range(handle_t *handle, struct inode *inode, ext4_lblk_t star
 
 static void ext4_fc_submit_bh(struct super_block *sb, bool is_tail)
 {
-       int write_flags = REQ_SYNC;
+       blk_opf_t write_flags = REQ_SYNC;
        struct buffer_head *bh = EXT4_SB(sb)->s_fc_bh;
 
        /* Add REQ_FUA | REQ_PREFLUSH only its tail */
@@ -668,7 +668,7 @@ static void ext4_fc_submit_bh(struct super_block *sb, bool is_tail)
        set_buffer_dirty(bh);
        set_buffer_uptodate(bh);
        bh->b_end_io = ext4_end_buffer_io_sync;
-       submit_bh(REQ_OP_WRITE, write_flags, bh);
+       submit_bh(REQ_OP_WRITE | write_flags, bh);
        EXT4_SB(sb)->s_fc_bh = NULL;
 }
 
index 87a8b43..9fd60fc 100644 (file)
@@ -5352,14 +5352,14 @@ int ext4_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
        if (error)
                return error;
 
-       if (is_quota_modification(inode, attr)) {
+       if (is_quota_modification(mnt_userns, inode, attr)) {
                error = dquot_initialize(inode);
                if (error)
                        return error;
        }
 
-       if ((ia_valid & ATTR_UID && !uid_eq(attr->ia_uid, inode->i_uid)) ||
-           (ia_valid & ATTR_GID && !gid_eq(attr->ia_gid, inode->i_gid))) {
+       if (i_uid_needs_update(mnt_userns, attr, inode) ||
+           i_gid_needs_update(mnt_userns, attr, inode)) {
                handle_t *handle;
 
                /* (user+group)*(old+new) structure, inode write (sb,
@@ -5376,7 +5376,7 @@ int ext4_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
                 * counts xattr inode references.
                 */
                down_read(&EXT4_I(inode)->xattr_sem);
-               error = dquot_transfer(inode, attr);
+               error = dquot_transfer(mnt_userns, inode, attr);
                up_read(&EXT4_I(inode)->xattr_sem);
 
                if (error) {
@@ -5385,10 +5385,8 @@ int ext4_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
                }
                /* Update corresponding info in inode so that everything is in
                 * one transaction */
-               if (attr->ia_valid & ATTR_UID)
-                       inode->i_uid = attr->ia_uid;
-               if (attr->ia_valid & ATTR_GID)
-                       inode->i_gid = attr->ia_gid;
+               i_uid_update(mnt_userns, attr, inode);
+               i_gid_update(mnt_userns, attr, inode);
                error = ext4_mark_inode_dirty(handle, inode);
                ext4_journal_stop(handle);
                if (unlikely(error)) {
index 79d05e4..9af68a7 100644 (file)
@@ -52,7 +52,7 @@ static int write_mmp_block(struct super_block *sb, struct buffer_head *bh)
        lock_buffer(bh);
        bh->b_end_io = end_buffer_write_sync;
        get_bh(bh);
-       submit_bh(REQ_OP_WRITE, REQ_SYNC | REQ_META | REQ_PRIO, bh);
+       submit_bh(REQ_OP_WRITE | REQ_SYNC | REQ_META | REQ_PRIO, bh);
        wait_on_buffer(bh);
        sb_end_write(sb);
        if (unlikely(!buffer_uptodate(bh)))
@@ -150,8 +150,6 @@ static int kmmpd(void *data)
        mmp_check_interval = max(EXT4_MMP_CHECK_MULT * mmp_update_interval,
                                 EXT4_MMP_MIN_CHECK_INTERVAL);
        mmp->mmp_check_interval = cpu_to_le16(mmp_check_interval);
-       BUILD_BUG_ON(sizeof(mmp->mmp_bdevname) < BDEVNAME_SIZE);
-       bdevname(bh->b_bdev, mmp->mmp_bdevname);
 
        memcpy(mmp->mmp_nodename, init_utsname()->nodename,
               sizeof(mmp->mmp_nodename));
@@ -372,13 +370,16 @@ skip:
 
        EXT4_SB(sb)->s_mmp_bh = bh;
 
+       BUILD_BUG_ON(sizeof(mmp->mmp_bdevname) < BDEVNAME_SIZE);
+       snprintf(mmp->mmp_bdevname, sizeof(mmp->mmp_bdevname),
+                "%pg", bh->b_bdev);
+
        /*
         * Start a kernel thread to update the MMP block periodically.
         */
        EXT4_SB(sb)->s_mmp_tsk = kthread_run(kmmpd, sb, "kmmpd-%.*s",
                                             (int)sizeof(mmp->mmp_bdevname),
-                                            bdevname(bh->b_bdev,
-                                                     mmp->mmp_bdevname));
+                                            mmp->mmp_bdevname);
        if (IS_ERR(EXT4_SB(sb)->s_mmp_tsk)) {
                EXT4_SB(sb)->s_mmp_tsk = NULL;
                ext4_warning(sb, "Unable to create kmmpd thread for %s.",
index 845f2f8..2c68dec 100644 (file)
@@ -159,7 +159,7 @@ MODULE_ALIAS("ext3");
 #define IS_EXT3_SB(sb) ((sb)->s_bdev->bd_holder == &ext3_fs_type)
 
 
-static inline void __ext4_read_bh(struct buffer_head *bh, int op_flags,
+static inline void __ext4_read_bh(struct buffer_head *bh, blk_opf_t op_flags,
                                  bh_end_io_t *end_io)
 {
        /*
@@ -171,10 +171,10 @@ static inline void __ext4_read_bh(struct buffer_head *bh, int op_flags,
 
        bh->b_end_io = end_io ? end_io : end_buffer_read_sync;
        get_bh(bh);
-       submit_bh(REQ_OP_READ, op_flags, bh);
+       submit_bh(REQ_OP_READ | op_flags, bh);
 }
 
-void ext4_read_bh_nowait(struct buffer_head *bh, int op_flags,
+void ext4_read_bh_nowait(struct buffer_head *bh, blk_opf_t op_flags,
                         bh_end_io_t *end_io)
 {
        BUG_ON(!buffer_locked(bh));
@@ -186,7 +186,7 @@ void ext4_read_bh_nowait(struct buffer_head *bh, int op_flags,
        __ext4_read_bh(bh, op_flags, end_io);
 }
 
-int ext4_read_bh(struct buffer_head *bh, int op_flags, bh_end_io_t *end_io)
+int ext4_read_bh(struct buffer_head *bh, blk_opf_t op_flags, bh_end_io_t *end_io)
 {
        BUG_ON(!buffer_locked(bh));
 
@@ -203,7 +203,7 @@ int ext4_read_bh(struct buffer_head *bh, int op_flags, bh_end_io_t *end_io)
        return -EIO;
 }
 
-int ext4_read_bh_lock(struct buffer_head *bh, int op_flags, bool wait)
+int ext4_read_bh_lock(struct buffer_head *bh, blk_opf_t op_flags, bool wait)
 {
        if (trylock_buffer(bh)) {
                if (wait)
@@ -227,8 +227,8 @@ int ext4_read_bh_lock(struct buffer_head *bh, int op_flags, bool wait)
  * return.
  */
 static struct buffer_head *__ext4_sb_bread_gfp(struct super_block *sb,
-                                              sector_t block, int op_flags,
-                                              gfp_t gfp)
+                                              sector_t block,
+                                              blk_opf_t op_flags, gfp_t gfp)
 {
        struct buffer_head *bh;
        int ret;
@@ -248,7 +248,7 @@ static struct buffer_head *__ext4_sb_bread_gfp(struct super_block *sb,
 }
 
 struct buffer_head *ext4_sb_bread(struct super_block *sb, sector_t block,
-                                  int op_flags)
+                                  blk_opf_t op_flags)
 {
        return __ext4_sb_bread_gfp(sb, block, op_flags, __GFP_MOVABLE);
 }
@@ -5939,8 +5939,8 @@ static int ext4_commit_super(struct super_block *sb)
        /* Clear potential dirty bit if it was journalled update */
        clear_buffer_dirty(sbh);
        sbh->b_end_io = end_buffer_write_sync;
-       submit_bh(REQ_OP_WRITE,
-                 REQ_SYNC | (test_opt(sb, BARRIER) ? REQ_FUA : 0), sbh);
+       submit_bh(REQ_OP_WRITE | REQ_SYNC |
+                 (test_opt(sb, BARRIER) ? REQ_FUA : 0), sbh);
        wait_on_buffer(sbh);
        if (buffer_write_io_error(sbh)) {
                ext4_msg(sb, KERN_ERR, "I/O error while writing "
index 318a3f9..ed503d5 100644 (file)
@@ -387,11 +387,11 @@ int f2fs_target_device_index(struct f2fs_sb_info *sbi, block_t blkaddr)
        return 0;
 }
 
-static unsigned int f2fs_io_flags(struct f2fs_io_info *fio)
+static blk_opf_t f2fs_io_flags(struct f2fs_io_info *fio)
 {
        unsigned int temp_mask = (1 << NR_TEMP_TYPE) - 1;
        unsigned int fua_flag, meta_flag, io_flag;
-       unsigned int op_flags = 0;
+       blk_opf_t op_flags = 0;
 
        if (fio->op != REQ_OP_WRITE)
                return 0;
@@ -999,7 +999,7 @@ out:
 }
 
 static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr,
-                                     unsigned nr_pages, unsigned op_flag,
+                                     unsigned nr_pages, blk_opf_t op_flag,
                                      pgoff_t first_idx, bool for_write)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
@@ -1047,7 +1047,8 @@ static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr,
 
 /* This can handle encryption stuffs */
 static int f2fs_submit_page_read(struct inode *inode, struct page *page,
-                                block_t blkaddr, int op_flags, bool for_write)
+                                block_t blkaddr, blk_opf_t op_flags,
+                                bool for_write)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
        struct bio *bio;
@@ -1181,7 +1182,7 @@ int f2fs_get_block(struct dnode_of_data *dn, pgoff_t index)
 }
 
 struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index,
-                                               int op_flags, bool for_write)
+                                    blk_opf_t op_flags, bool for_write)
 {
        struct address_space *mapping = inode->i_mapping;
        struct dnode_of_data dn;
index f258a1b..85921a1 100644 (file)
@@ -1183,8 +1183,8 @@ struct f2fs_io_info {
        nid_t ino;              /* inode number */
        enum page_type type;    /* contains DATA/NODE/META/META_FLUSH */
        enum temp_type temp;    /* contains HOT/WARM/COLD */
-       int op;                 /* contains REQ_OP_ */
-       int op_flags;           /* req_flag_bits */
+       enum req_op op;         /* contains REQ_OP_ */
+       blk_opf_t op_flags;     /* req_flag_bits */
        block_t new_blkaddr;    /* new block address to be written */
        block_t old_blkaddr;    /* old block address before Cow */
        struct page *page;      /* page to be written */
@@ -3741,7 +3741,7 @@ int f2fs_reserve_new_block(struct dnode_of_data *dn);
 int f2fs_get_block(struct dnode_of_data *dn, pgoff_t index);
 int f2fs_reserve_block(struct dnode_of_data *dn, pgoff_t index);
 struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index,
-                       int op_flags, bool for_write);
+                       blk_opf_t op_flags, bool for_write);
 struct page *f2fs_find_data_page(struct inode *inode, pgoff_t index);
 struct page *f2fs_get_lock_data_page(struct inode *inode, pgoff_t index,
                        bool for_write);
index bd14cef..d66e37d 100644 (file)
@@ -861,10 +861,8 @@ static void __setattr_copy(struct user_namespace *mnt_userns,
 {
        unsigned int ia_valid = attr->ia_valid;
 
-       if (ia_valid & ATTR_UID)
-               inode->i_uid = attr->ia_uid;
-       if (ia_valid & ATTR_GID)
-               inode->i_gid = attr->ia_gid;
+       i_uid_update(mnt_userns, attr, inode);
+       i_gid_update(mnt_userns, attr, inode);
        if (ia_valid & ATTR_ATIME)
                inode->i_atime = attr->ia_atime;
        if (ia_valid & ATTR_MTIME)
@@ -917,17 +915,15 @@ int f2fs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
        if (err)
                return err;
 
-       if (is_quota_modification(inode, attr)) {
+       if (is_quota_modification(mnt_userns, inode, attr)) {
                err = f2fs_dquot_initialize(inode);
                if (err)
                        return err;
        }
-       if ((attr->ia_valid & ATTR_UID &&
-               !uid_eq(attr->ia_uid, inode->i_uid)) ||
-               (attr->ia_valid & ATTR_GID &&
-               !gid_eq(attr->ia_gid, inode->i_gid))) {
+       if (i_uid_needs_update(mnt_userns, attr, inode) ||
+           i_gid_needs_update(mnt_userns, attr, inode)) {
                f2fs_lock_op(F2FS_I_SB(inode));
-               err = dquot_transfer(inode, attr);
+               err = dquot_transfer(mnt_userns, inode, attr);
                if (err) {
                        set_sbi_flag(F2FS_I_SB(inode),
                                        SBI_QUOTA_NEED_REPAIR);
@@ -938,10 +934,8 @@ int f2fs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
                 * update uid/gid under lock_op(), so that dquot and inode can
                 * be updated atomically.
                 */
-               if (attr->ia_valid & ATTR_UID)
-                       inode->i_uid = attr->ia_uid;
-               if (attr->ia_valid & ATTR_GID)
-                       inode->i_gid = attr->ia_gid;
+               i_uid_update(mnt_userns, attr, inode);
+               i_gid_update(mnt_userns, attr, inode);
                f2fs_mark_inode_dirty_sync(inode, true);
                f2fs_unlock_op(F2FS_I_SB(inode));
        }
index 12bba66..740c72d 100644 (file)
@@ -1327,7 +1327,7 @@ fail:
  * 0: f2fs_put_page(page, 0)
  * LOCKED_PAGE or error: f2fs_put_page(page, 1)
  */
-static int read_node_page(struct page *page, int op_flags)
+static int read_node_page(struct page *page, blk_opf_t op_flags)
 {
        struct f2fs_sb_info *sbi = F2FS_P_SB(page);
        struct node_info ni;
index 3cb7f8a..dcd0a1e 100644 (file)
@@ -255,18 +255,18 @@ static int recover_quota_data(struct inode *inode, struct page *page)
 
        memset(&attr, 0, sizeof(attr));
 
-       attr.ia_uid = make_kuid(inode->i_sb->s_user_ns, i_uid);
-       attr.ia_gid = make_kgid(inode->i_sb->s_user_ns, i_gid);
+       attr.ia_vfsuid = VFSUIDT_INIT(make_kuid(inode->i_sb->s_user_ns, i_uid));
+       attr.ia_vfsgid = VFSGIDT_INIT(make_kgid(inode->i_sb->s_user_ns, i_gid));
 
-       if (!uid_eq(attr.ia_uid, inode->i_uid))
+       if (!vfsuid_eq(attr.ia_vfsuid, i_uid_into_vfsuid(&init_user_ns, inode)))
                attr.ia_valid |= ATTR_UID;
-       if (!gid_eq(attr.ia_gid, inode->i_gid))
+       if (!vfsgid_eq(attr.ia_vfsgid, i_gid_into_vfsgid(&init_user_ns, inode)))
                attr.ia_valid |= ATTR_GID;
 
        if (!attr.ia_valid)
                return 0;
 
-       err = dquot_transfer(inode, &attr);
+       err = dquot_transfer(&init_user_ns, inode, &attr);
        if (err)
                set_sbi_flag(F2FS_I_SB(inode), SBI_QUOTA_NEED_REPAIR);
        return err;
index 874c1b9..c7afc58 100644 (file)
@@ -1082,7 +1082,7 @@ static int __submit_discard_cmd(struct f2fs_sb_info *sbi,
        struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
        struct list_head *wait_list = (dpolicy->type == DPOLICY_FSTRIM) ?
                                        &(dcc->fstrim_list) : &(dcc->wait_list);
-       int flag = dpolicy->sync ? REQ_SYNC : 0;
+       blk_opf_t flag = dpolicy->sync ? REQ_SYNC : 0;
        block_t lstart, start, len, total_len;
        int err = 0;
 
index 3dae3ed..3e4eb34 100644 (file)
@@ -90,7 +90,8 @@ static int fat_ioctl_set_attributes(struct file *file, u32 __user *user_attr)
         * out the RO attribute for checking by the security
         * module, just because it maps to a file mode.
         */
-       err = security_inode_setattr(file->f_path.dentry, &ia);
+       err = security_inode_setattr(file_mnt_user_ns(file),
+                                    file->f_path.dentry, &ia);
        if (err)
                goto out_unlock_inode;
 
@@ -516,9 +517,11 @@ int fat_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
        }
 
        if (((attr->ia_valid & ATTR_UID) &&
-            (!uid_eq(attr->ia_uid, sbi->options.fs_uid))) ||
+            (!uid_eq(from_vfsuid(mnt_userns, i_user_ns(inode), attr->ia_vfsuid),
+                     sbi->options.fs_uid))) ||
            ((attr->ia_valid & ATTR_GID) &&
-            (!gid_eq(attr->ia_gid, sbi->options.fs_gid))) ||
+            (!gid_eq(from_vfsgid(mnt_userns, i_user_ns(inode), attr->ia_vfsgid),
+                     sbi->options.fs_gid))) ||
            ((attr->ia_valid & ATTR_MODE) &&
             (attr->ia_mode & ~FAT_VALID_MODE)))
                error = -EPERM;
index 9d3cf01..7492082 100644 (file)
@@ -372,17 +372,22 @@ nomem:
        return NULL;
 }
 
+static inline bool fscache_cookie_is_dropped(struct fscache_cookie *cookie)
+{
+       return READ_ONCE(cookie->state) == FSCACHE_COOKIE_STATE_DROPPED;
+}
+
 static void fscache_wait_on_collision(struct fscache_cookie *candidate,
                                      struct fscache_cookie *wait_for)
 {
        enum fscache_cookie_state *statep = &wait_for->state;
 
-       wait_var_event_timeout(statep, READ_ONCE(*statep) == FSCACHE_COOKIE_STATE_DROPPED,
+       wait_var_event_timeout(statep, fscache_cookie_is_dropped(wait_for),
                               20 * HZ);
-       if (READ_ONCE(*statep) != FSCACHE_COOKIE_STATE_DROPPED) {
+       if (!fscache_cookie_is_dropped(wait_for)) {
                pr_notice("Potential collision c=%08x old: c=%08x",
                          candidate->debug_id, wait_for->debug_id);
-               wait_var_event(statep, READ_ONCE(*statep) == FSCACHE_COOKIE_STATE_DROPPED);
+               wait_var_event(statep, fscache_cookie_is_dropped(wait_for));
        }
 }
 
@@ -517,7 +522,14 @@ static void fscache_perform_lookup(struct fscache_cookie *cookie)
        }
 
        fscache_see_cookie(cookie, fscache_cookie_see_active);
-       fscache_set_cookie_state(cookie, FSCACHE_COOKIE_STATE_ACTIVE);
+       spin_lock(&cookie->lock);
+       if (test_and_clear_bit(FSCACHE_COOKIE_DO_INVALIDATE, &cookie->flags))
+               __fscache_set_cookie_state(cookie,
+                                          FSCACHE_COOKIE_STATE_INVALIDATING);
+       else
+               __fscache_set_cookie_state(cookie, FSCACHE_COOKIE_STATE_ACTIVE);
+       spin_unlock(&cookie->lock);
+       wake_up_cookie_state(cookie);
        trace = fscache_access_lookup_cookie_end;
 
 out:
@@ -752,6 +764,9 @@ again_locked:
                        spin_lock(&cookie->lock);
                }
 
+               if (test_and_clear_bit(FSCACHE_COOKIE_DO_INVALIDATE, &cookie->flags))
+                       fscache_end_cookie_access(cookie, fscache_access_invalidate_cookie_end);
+
                switch (state) {
                case FSCACHE_COOKIE_STATE_RELINQUISHING:
                        fscache_see_cookie(cookie, fscache_cookie_see_relinquish);
@@ -1048,6 +1063,9 @@ void __fscache_invalidate(struct fscache_cookie *cookie,
                return;
 
        case FSCACHE_COOKIE_STATE_LOOKING_UP:
+               __fscache_begin_cookie_access(cookie, fscache_access_invalidate_cookie);
+               set_bit(FSCACHE_COOKIE_DO_INVALIDATE, &cookie->flags);
+               fallthrough;
        case FSCACHE_COOKIE_STATE_CREATING:
                spin_unlock(&cookie->lock);
                _leave(" [look %x]", cookie->inval_counter);
index f2aa7db..a058e01 100644 (file)
@@ -143,7 +143,7 @@ static void fscache_wait_on_volume_collision(struct fscache_volume *candidate,
 {
        wait_var_event_timeout(&candidate->flags,
                               !fscache_is_acquire_pending(candidate), 20 * HZ);
-       if (!fscache_is_acquire_pending(candidate)) {
+       if (fscache_is_acquire_pending(candidate)) {
                pr_notice("Potential volume collision new=%08x old=%08x",
                          candidate->debug_id, collidee_debug_id);
                fscache_stat(&fscache_n_volumes_collision);
@@ -182,7 +182,7 @@ static bool fscache_hash_volume(struct fscache_volume *candidate)
        hlist_bl_add_head(&candidate->hash_link, h);
        hlist_bl_unlock(h);
 
-       if (test_bit(FSCACHE_VOLUME_ACQUIRE_PENDING, &candidate->flags))
+       if (fscache_is_acquire_pending(candidate))
                fscache_wait_on_volume_collision(candidate, collidee_debug_id);
        return true;
 
index b669733..3bdb2c6 100644 (file)
@@ -310,9 +310,8 @@ static void gfs2_metapath_ra(struct gfs2_glock *gl, __be64 *start, __be64 *end)
                if (trylock_buffer(rabh)) {
                        if (!buffer_uptodate(rabh)) {
                                rabh->b_end_io = end_buffer_read_sync;
-                               submit_bh(REQ_OP_READ,
-                                         REQ_RAHEAD | REQ_META | REQ_PRIO,
-                                         rabh);
+                               submit_bh(REQ_OP_READ | REQ_RAHEAD | REQ_META |
+                                         REQ_PRIO, rabh);
                                continue;
                        }
                        unlock_buffer(rabh);
index 42b7dff..a0562dd 100644 (file)
@@ -1508,9 +1508,8 @@ static void gfs2_dir_readahead(struct inode *inode, unsigned hsize, u32 index,
                                continue;
                        }
                        bh->b_end_io = end_buffer_read_sync;
-                       submit_bh(REQ_OP_READ,
-                                 REQ_RAHEAD | REQ_META | REQ_PRIO,
-                                 bh);
+                       submit_bh(REQ_OP_READ | REQ_RAHEAD | REQ_META |
+                                 REQ_PRIO, bh);
                        continue;
                }
                brelse(bh);
index f0ee3ff..eec4159 100644 (file)
@@ -823,7 +823,7 @@ void gfs2_flush_revokes(struct gfs2_sbd *sdp)
 
 void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd,
                           u64 seq, u32 tail, u32 lblock, u32 flags,
-                          int op_flags)
+                          blk_opf_t op_flags)
 {
        struct gfs2_log_header *lh;
        u32 hash, crc;
@@ -905,7 +905,7 @@ void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd,
 
 static void log_write_header(struct gfs2_sbd *sdp, u32 flags)
 {
-       int op_flags = REQ_PREFLUSH | REQ_FUA | REQ_META | REQ_SYNC;
+       blk_opf_t op_flags = REQ_PREFLUSH | REQ_FUA | REQ_META | REQ_SYNC;
        enum gfs2_freeze_state state = atomic_read(&sdp->sd_freeze_state);
 
        gfs2_assert_withdraw(sdp, (state != SFS_FROZEN));
index fc905c2..653cffc 100644 (file)
@@ -82,7 +82,7 @@ extern void gfs2_log_reserve(struct gfs2_sbd *sdp, struct gfs2_trans *tr,
                             unsigned int *extra_revokes);
 extern void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd,
                                  u64 seq, u32 tail, u32 lblock, u32 flags,
-                                 int op_flags);
+                                 blk_opf_t op_flags);
 extern void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl,
                           u32 type);
 extern void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans);
index 1f67d37..1902413 100644 (file)
@@ -238,7 +238,7 @@ static void gfs2_end_log_write(struct bio *bio)
  * there is no pending bio, then this is a no-op.
  */
 
-void gfs2_log_submit_bio(struct bio **biop, int opf)
+void gfs2_log_submit_bio(struct bio **biop, blk_opf_t opf)
 {
        struct bio *bio = *biop;
        if (bio) {
@@ -292,7 +292,7 @@ static struct bio *gfs2_log_alloc_bio(struct gfs2_sbd *sdp, u64 blkno,
  */
 
 static struct bio *gfs2_log_get_bio(struct gfs2_sbd *sdp, u64 blkno,
-                                   struct bio **biop, int op,
+                                   struct bio **biop, enum req_op op,
                                    bio_end_io_t *end_io, bool flush)
 {
        struct bio *bio = *biop;
index f707601..1412ffb 100644 (file)
@@ -16,7 +16,7 @@ extern u64 gfs2_log_bmap(struct gfs2_jdesc *jd, unsigned int lbn);
 extern void gfs2_log_write(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd,
                           struct page *page, unsigned size, unsigned offset,
                           u64 blkno);
-extern void gfs2_log_submit_bio(struct bio **biop, int opf);
+extern void gfs2_log_submit_bio(struct bio **biop, blk_opf_t opf);
 extern void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh);
 extern int gfs2_find_jhead(struct gfs2_jdesc *jd,
                           struct gfs2_log_header_host *head, bool keep_cache);
index 868dcc7..7e70e0b 100644 (file)
@@ -34,7 +34,7 @@ static int gfs2_aspace_writepage(struct page *page, struct writeback_control *wb
 {
        struct buffer_head *bh, *head;
        int nr_underway = 0;
-       int write_flags = REQ_META | REQ_PRIO | wbc_to_write_flags(wbc);
+       blk_opf_t write_flags = REQ_META | REQ_PRIO | wbc_to_write_flags(wbc);
 
        BUG_ON(!PageLocked(page));
        BUG_ON(!page_has_buffers(page));
@@ -75,7 +75,7 @@ static int gfs2_aspace_writepage(struct page *page, struct writeback_control *wb
        do {
                struct buffer_head *next = bh->b_this_page;
                if (buffer_async_write(bh)) {
-                       submit_bh(REQ_OP_WRITE, write_flags, bh);
+                       submit_bh(REQ_OP_WRITE | write_flags, bh);
                        nr_underway++;
                }
                bh = next;
@@ -217,14 +217,13 @@ static void gfs2_meta_read_endio(struct bio *bio)
  * Submit several consecutive buffer head I/O requests as a single bio I/O
  * request.  (See submit_bh_wbc.)
  */
-static void gfs2_submit_bhs(int op, int op_flags, struct buffer_head *bhs[],
-                           int num)
+static void gfs2_submit_bhs(blk_opf_t opf, struct buffer_head *bhs[], int num)
 {
        while (num > 0) {
                struct buffer_head *bh = *bhs;
                struct bio *bio;
 
-               bio = bio_alloc(bh->b_bdev, num, op | op_flags, GFP_NOIO);
+               bio = bio_alloc(bh->b_bdev, num, opf, GFP_NOIO);
                bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9);
                while (num > 0) {
                        bh = *bhs;
@@ -288,7 +287,7 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
                }
        }
 
-       gfs2_submit_bhs(REQ_OP_READ, REQ_META | REQ_PRIO, bhs, num);
+       gfs2_submit_bhs(REQ_OP_READ | REQ_META | REQ_PRIO, bhs, num);
        if (!(flags & DIO_WAIT))
                return 0;
 
@@ -527,7 +526,7 @@ struct buffer_head *gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen)
        if (buffer_uptodate(first_bh))
                goto out;
        if (!buffer_locked(first_bh))
-               ll_rw_block(REQ_OP_READ, REQ_META | REQ_PRIO, 1, &first_bh);
+               ll_rw_block(REQ_OP_READ | REQ_META | REQ_PRIO, 1, &first_bh);
 
        dblock++;
        extlen--;
@@ -536,9 +535,8 @@ struct buffer_head *gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen)
                bh = gfs2_getbuf(gl, dblock, CREATE);
 
                if (!buffer_uptodate(bh) && !buffer_locked(bh))
-                       ll_rw_block(REQ_OP_READ,
-                                   REQ_RAHEAD | REQ_META | REQ_PRIO,
-                                   1, &bh);
+                       ll_rw_block(REQ_OP_READ | REQ_RAHEAD | REQ_META |
+                                   REQ_PRIO, 1, &bh);
                brelse(bh);
                dblock++;
                extlen--;
index 59d727a..c98a7fa 100644 (file)
@@ -746,7 +746,7 @@ static int gfs2_write_buf_to_page(struct gfs2_inode *ip, unsigned long index,
                if (PageUptodate(page))
                        set_buffer_uptodate(bh);
                if (!buffer_uptodate(bh)) {
-                       ll_rw_block(REQ_OP_READ, REQ_META | REQ_PRIO, 1, &bh);
+                       ll_rw_block(REQ_OP_READ | REQ_META | REQ_PRIO, 1, &bh);
                        wait_on_buffer(bh);
                        if (!buffer_uptodate(bh))
                                goto unlock_out;
index 396e73a..a5db2e3 100644 (file)
@@ -525,7 +525,7 @@ int hfsplus_compare_dentry(const struct dentry *dentry, unsigned int len,
 
 /* wrapper.c */
 int hfsplus_submit_bio(struct super_block *sb, sector_t sector, void *buf,
-                      void **data, int op, int op_flags);
+                      void **data, blk_opf_t opf);
 int hfsplus_read_wrapper(struct super_block *sb);
 
 /*
index 63164eb..9ec2166 100644 (file)
@@ -112,8 +112,7 @@ static int hfs_parse_new_pmap(struct super_block *sb, void *buf,
                if ((u8 *)pm - (u8 *)buf >= buf_size) {
                        res = hfsplus_submit_bio(sb,
                                                 *part_start + HFS_PMAP_BLK + i,
-                                                buf, (void **)&pm, REQ_OP_READ,
-                                                0);
+                                                buf, (void **)&pm, REQ_OP_READ);
                        if (res)
                                return res;
                }
@@ -137,7 +136,7 @@ int hfs_part_find(struct super_block *sb,
                return -ENOMEM;
 
        res = hfsplus_submit_bio(sb, *part_start + HFS_PMAP_BLK,
-                                buf, &data, REQ_OP_READ, 0);
+                                buf, &data, REQ_OP_READ);
        if (res)
                goto out;
 
index 8479add..122ed89 100644 (file)
@@ -221,7 +221,7 @@ static int hfsplus_sync_fs(struct super_block *sb, int wait)
 
        error2 = hfsplus_submit_bio(sb,
                                   sbi->part_start + HFSPLUS_VOLHEAD_SECTOR,
-                                  sbi->s_vhdr_buf, NULL, REQ_OP_WRITE,
+                                  sbi->s_vhdr_buf, NULL, REQ_OP_WRITE |
                                   REQ_SYNC);
        if (!error)
                error = error2;
@@ -230,7 +230,7 @@ static int hfsplus_sync_fs(struct super_block *sb, int wait)
 
        error2 = hfsplus_submit_bio(sb,
                                  sbi->part_start + sbi->sect_count - 2,
-                                 sbi->s_backup_vhdr_buf, NULL, REQ_OP_WRITE,
+                                 sbi->s_backup_vhdr_buf, NULL, REQ_OP_WRITE |
                                  REQ_SYNC);
        if (!error)
                error2 = error;
index 0b8ad65..0b791ad 100644 (file)
@@ -45,8 +45,9 @@ struct hfsplus_wd {
  * will work correctly.
  */
 int hfsplus_submit_bio(struct super_block *sb, sector_t sector,
-                      void *buf, void **data, int op, int op_flags)
+                      void *buf, void **data, blk_opf_t opf)
 {
+       const enum req_op op = opf & REQ_OP_MASK;
        struct bio *bio;
        int ret = 0;
        u64 io_size;
@@ -63,10 +64,10 @@ int hfsplus_submit_bio(struct super_block *sb, sector_t sector,
        offset = start & (io_size - 1);
        sector &= ~((io_size >> HFSPLUS_SECTOR_SHIFT) - 1);
 
-       bio = bio_alloc(sb->s_bdev, 1, op | op_flags, GFP_NOIO);
+       bio = bio_alloc(sb->s_bdev, 1, opf, GFP_NOIO);
        bio->bi_iter.bi_sector = sector;
 
-       if (op != WRITE && data)
+       if (op != REQ_OP_WRITE && data)
                *data = (u8 *)buf + offset;
 
        while (io_size > 0) {
@@ -184,7 +185,7 @@ int hfsplus_read_wrapper(struct super_block *sb)
 reread:
        error = hfsplus_submit_bio(sb, part_start + HFSPLUS_VOLHEAD_SECTOR,
                                   sbi->s_vhdr_buf, (void **)&sbi->s_vhdr,
-                                  REQ_OP_READ, 0);
+                                  REQ_OP_READ);
        if (error)
                goto out_free_backup_vhdr;
 
@@ -216,8 +217,7 @@ reread:
 
        error = hfsplus_submit_bio(sb, part_start + part_size - 2,
                                   sbi->s_backup_vhdr_buf,
-                                  (void **)&sbi->s_backup_vhdr, REQ_OP_READ,
-                                  0);
+                                  (void **)&sbi->s_backup_vhdr, REQ_OP_READ);
        if (error)
                goto out_free_backup_vhdr;
 
index eca1d0f..20336cb 100644 (file)
@@ -584,41 +584,79 @@ static void hugetlb_vmtruncate(struct inode *inode, loff_t offset)
        remove_inode_hugepages(inode, offset, LLONG_MAX);
 }
 
+static void hugetlbfs_zero_partial_page(struct hstate *h,
+                                       struct address_space *mapping,
+                                       loff_t start,
+                                       loff_t end)
+{
+       pgoff_t idx = start >> huge_page_shift(h);
+       struct folio *folio;
+
+       folio = filemap_lock_folio(mapping, idx);
+       if (!folio)
+               return;
+
+       start = start & ~huge_page_mask(h);
+       end = end & ~huge_page_mask(h);
+       if (!end)
+               end = huge_page_size(h);
+
+       folio_zero_segment(folio, (size_t)start, (size_t)end);
+
+       folio_unlock(folio);
+       folio_put(folio);
+}
+
 static long hugetlbfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
 {
+       struct hugetlbfs_inode_info *info = HUGETLBFS_I(inode);
+       struct address_space *mapping = inode->i_mapping;
        struct hstate *h = hstate_inode(inode);
        loff_t hpage_size = huge_page_size(h);
        loff_t hole_start, hole_end;
 
        /*
-        * For hole punch round up the beginning offset of the hole and
-        * round down the end.
+        * hole_start and hole_end indicate the full pages within the hole.
         */
        hole_start = round_up(offset, hpage_size);
        hole_end = round_down(offset + len, hpage_size);
 
-       if (hole_end > hole_start) {
-               struct address_space *mapping = inode->i_mapping;
-               struct hugetlbfs_inode_info *info = HUGETLBFS_I(inode);
+       inode_lock(inode);
 
-               inode_lock(inode);
+       /* protected by i_rwsem */
+       if (info->seals & (F_SEAL_WRITE | F_SEAL_FUTURE_WRITE)) {
+               inode_unlock(inode);
+               return -EPERM;
+       }
 
-               /* protected by i_rwsem */
-               if (info->seals & (F_SEAL_WRITE | F_SEAL_FUTURE_WRITE)) {
-                       inode_unlock(inode);
-                       return -EPERM;
-               }
+       i_mmap_lock_write(mapping);
+
+       /* If range starts before first full page, zero partial page. */
+       if (offset < hole_start)
+               hugetlbfs_zero_partial_page(h, mapping,
+                               offset, min(offset + len, hole_start));
 
-               i_mmap_lock_write(mapping);
+       /* Unmap users of full pages in the hole. */
+       if (hole_end > hole_start) {
                if (!RB_EMPTY_ROOT(&mapping->i_mmap.rb_root))
                        hugetlb_vmdelete_list(&mapping->i_mmap,
                                              hole_start >> PAGE_SHIFT,
                                              hole_end >> PAGE_SHIFT, 0);
-               i_mmap_unlock_write(mapping);
-               remove_inode_hugepages(inode, hole_start, hole_end);
-               inode_unlock(inode);
        }
 
+       /* If range extends beyond last full page, zero partial page. */
+       if ((offset + len) > hole_end && (offset + len) > hole_start)
+               hugetlbfs_zero_partial_page(h, mapping,
+                               hole_end, offset + len);
+
+       i_mmap_unlock_write(mapping);
+
+       /* Remove full pages from the file. */
+       if (hole_end > hole_start)
+               remove_inode_hugepages(inode, hole_start, hole_end);
+
+       inode_unlock(inode);
+
        return 0;
 }
 
index d2bdc40..524ee91 100644 (file)
@@ -2010,67 +2010,57 @@ static int __remove_privs(struct user_namespace *mnt_userns,
        return notify_change(mnt_userns, dentry, &newattrs, NULL);
 }
 
-/*
- * Remove special file priviledges (suid, capabilities) when file is written
- * to or truncated.
- */
-int file_remove_privs(struct file *file)
+static int __file_remove_privs(struct file *file, unsigned int flags)
 {
        struct dentry *dentry = file_dentry(file);
        struct inode *inode = file_inode(file);
+       int error;
        int kill;
-       int error = 0;
 
-       /*
-        * Fast path for nothing security related.
-        * As well for non-regular files, e.g. blkdev inodes.
-        * For example, blkdev_write_iter() might get here
-        * trying to remove privs which it is not allowed to.
-        */
        if (IS_NOSEC(inode) || !S_ISREG(inode->i_mode))
                return 0;
 
        kill = dentry_needs_remove_privs(dentry);
-       if (kill < 0)
+       if (kill <= 0)
                return kill;
-       if (kill)
-               error = __remove_privs(file_mnt_user_ns(file), dentry, kill);
+
+       if (flags & IOCB_NOWAIT)
+               return -EAGAIN;
+
+       error = __remove_privs(file_mnt_user_ns(file), dentry, kill);
        if (!error)
                inode_has_no_xattr(inode);
 
        return error;
 }
-EXPORT_SYMBOL(file_remove_privs);
 
 /**
- *     file_update_time        -       update mtime and ctime time
- *     @file: file accessed
+ * file_remove_privs - remove special file privileges (suid, capabilities)
+ * @file: file to remove privileges from
+ *
+ * When file is modified by a write or truncation ensure that special
+ * file privileges are removed.
  *
- *     Update the mtime and ctime members of an inode and mark the inode
- *     for writeback.  Note that this function is meant exclusively for
- *     usage in the file write path of filesystems, and filesystems may
- *     choose to explicitly ignore update via this function with the
- *     S_NOCMTIME inode flag, e.g. for network filesystem where these
- *     timestamps are handled by the server.  This can return an error for
- *     file systems who need to allocate space in order to update an inode.
+ * Return: 0 on success, negative errno on failure.
  */
+int file_remove_privs(struct file *file)
+{
+       return __file_remove_privs(file, 0);
+}
+EXPORT_SYMBOL(file_remove_privs);
 
-int file_update_time(struct file *file)
+static int inode_needs_update_time(struct inode *inode, struct timespec64 *now)
 {
-       struct inode *inode = file_inode(file);
-       struct timespec64 now;
        int sync_it = 0;
-       int ret;
 
        /* First try to exhaust all avenues to not sync */
        if (IS_NOCMTIME(inode))
                return 0;
 
-       now = current_time(inode);
-       if (!timespec64_equal(&inode->i_mtime, &now))
+       if (!timespec64_equal(&inode->i_mtime, now))
                sync_it = S_MTIME;
 
-       if (!timespec64_equal(&inode->i_ctime, &now))
+       if (!timespec64_equal(&inode->i_ctime, now))
                sync_it |= S_CTIME;
 
        if (IS_I_VERSION(inode) && inode_iversion_need_inc(inode))
@@ -2079,37 +2069,127 @@ int file_update_time(struct file *file)
        if (!sync_it)
                return 0;
 
-       /* Finally allowed to write? Takes lock. */
-       if (__mnt_want_write_file(file))
-               return 0;
+       return sync_it;
+}
+
+static int __file_update_time(struct file *file, struct timespec64 *now,
+                       int sync_mode)
+{
+       int ret = 0;
+       struct inode *inode = file_inode(file);
 
-       ret = inode_update_time(inode, &now, sync_it);
-       __mnt_drop_write_file(file);
+       /* try to update time settings */
+       if (!__mnt_want_write_file(file)) {
+               ret = inode_update_time(inode, now, sync_mode);
+               __mnt_drop_write_file(file);
+       }
 
        return ret;
 }
+
+/**
+ * file_update_time - update mtime and ctime time
+ * @file: file accessed
+ *
+ * Update the mtime and ctime members of an inode and mark the inode for
+ * writeback. Note that this function is meant exclusively for usage in
+ * the file write path of filesystems, and filesystems may choose to
+ * explicitly ignore updates via this function with the _NOCMTIME inode
+ * flag, e.g. for network filesystem where these imestamps are handled
+ * by the server. This can return an error for file systems who need to
+ * allocate space in order to update an inode.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int file_update_time(struct file *file)
+{
+       int ret;
+       struct inode *inode = file_inode(file);
+       struct timespec64 now = current_time(inode);
+
+       ret = inode_needs_update_time(inode, &now);
+       if (ret <= 0)
+               return ret;
+
+       return __file_update_time(file, &now, ret);
+}
 EXPORT_SYMBOL(file_update_time);
 
-/* Caller must hold the file's inode lock */
-int file_modified(struct file *file)
+/**
+ * file_modified_flags - handle mandated vfs changes when modifying a file
+ * @file: file that was modified
+ * @flags: kiocb flags
+ *
+ * When file has been modified ensure that special
+ * file privileges are removed and time settings are updated.
+ *
+ * If IOCB_NOWAIT is set, special file privileges will not be removed and
+ * time settings will not be updated. It will return -EAGAIN.
+ *
+ * Context: Caller must hold the file's inode lock.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+static int file_modified_flags(struct file *file, int flags)
 {
-       int err;
+       int ret;
+       struct inode *inode = file_inode(file);
+       struct timespec64 now = current_time(inode);
 
        /*
         * Clear the security bits if the process is not being run by root.
         * This keeps people from modifying setuid and setgid binaries.
         */
-       err = file_remove_privs(file);
-       if (err)
-               return err;
+       ret = __file_remove_privs(file, flags);
+       if (ret)
+               return ret;
 
        if (unlikely(file->f_mode & FMODE_NOCMTIME))
                return 0;
 
-       return file_update_time(file);
+       ret = inode_needs_update_time(inode, &now);
+       if (ret <= 0)
+               return ret;
+       if (flags & IOCB_NOWAIT)
+               return -EAGAIN;
+
+       return __file_update_time(file, &now, ret);
+}
+
+/**
+ * file_modified - handle mandated vfs changes when modifying a file
+ * @file: file that was modified
+ *
+ * When file has been modified ensure that special
+ * file privileges are removed and time settings are updated.
+ *
+ * Context: Caller must hold the file's inode lock.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int file_modified(struct file *file)
+{
+       return file_modified_flags(file, 0);
 }
 EXPORT_SYMBOL(file_modified);
 
+/**
+ * kiocb_modified - handle mandated vfs changes when modifying a file
+ * @iocb: iocb that was modified
+ *
+ * When file has been modified ensure that special
+ * file privileges are removed and time settings are updated.
+ *
+ * Context: Caller must hold the file's inode lock.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int kiocb_modified(struct kiocb *iocb)
+{
+       return file_modified_flags(iocb->ki_filp, iocb->ki_flags);
+}
+EXPORT_SYMBOL_GPL(kiocb_modified);
+
 int inode_needs_sync(struct inode *inode)
 {
        if (IS_SYNC(inode))
diff --git a/fs/io_uring.c b/fs/io_uring.c
deleted file mode 100644 (file)
index 5ff2cdb..0000000
+++ /dev/null
@@ -1,13257 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Shared application/kernel submission and completion ring pairs, for
- * supporting fast/efficient IO.
- *
- * A note on the read/write ordering memory barriers that are matched between
- * the application and kernel side.
- *
- * After the application reads the CQ ring tail, it must use an
- * appropriate smp_rmb() to pair with the smp_wmb() the kernel uses
- * before writing the tail (using smp_load_acquire to read the tail will
- * do). It also needs a smp_mb() before updating CQ head (ordering the
- * entry load(s) with the head store), pairing with an implicit barrier
- * through a control-dependency in io_get_cqe (smp_store_release to
- * store head will do). Failure to do so could lead to reading invalid
- * CQ entries.
- *
- * Likewise, the application must use an appropriate smp_wmb() before
- * writing the SQ tail (ordering SQ entry stores with the tail store),
- * which pairs with smp_load_acquire in io_get_sqring (smp_store_release
- * to store the tail will do). And it needs a barrier ordering the SQ
- * head load before writing new SQ entries (smp_load_acquire to read
- * head will do).
- *
- * When using the SQ poll thread (IORING_SETUP_SQPOLL), the application
- * needs to check the SQ flags for IORING_SQ_NEED_WAKEUP *after*
- * updating the SQ tail; a full memory barrier smp_mb() is needed
- * between.
- *
- * Also see the examples in the liburing library:
- *
- *     git://git.kernel.dk/liburing
- *
- * io_uring also uses READ/WRITE_ONCE() for _any_ store or load that happens
- * from data shared between the kernel and application. This is done both
- * for ordering purposes, but also to ensure that once a value is loaded from
- * data that the application could potentially modify, it remains stable.
- *
- * Copyright (C) 2018-2019 Jens Axboe
- * Copyright (c) 2018-2019 Christoph Hellwig
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/syscalls.h>
-#include <linux/compat.h>
-#include <net/compat.h>
-#include <linux/refcount.h>
-#include <linux/uio.h>
-#include <linux/bits.h>
-
-#include <linux/sched/signal.h>
-#include <linux/fs.h>
-#include <linux/file.h>
-#include <linux/fdtable.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/percpu.h>
-#include <linux/slab.h>
-#include <linux/blk-mq.h>
-#include <linux/bvec.h>
-#include <linux/net.h>
-#include <net/sock.h>
-#include <net/af_unix.h>
-#include <net/scm.h>
-#include <linux/anon_inodes.h>
-#include <linux/sched/mm.h>
-#include <linux/uaccess.h>
-#include <linux/nospec.h>
-#include <linux/sizes.h>
-#include <linux/hugetlb.h>
-#include <linux/highmem.h>
-#include <linux/namei.h>
-#include <linux/fsnotify.h>
-#include <linux/fadvise.h>
-#include <linux/eventpoll.h>
-#include <linux/splice.h>
-#include <linux/task_work.h>
-#include <linux/pagemap.h>
-#include <linux/io_uring.h>
-#include <linux/audit.h>
-#include <linux/security.h>
-#include <linux/xattr.h>
-
-#define CREATE_TRACE_POINTS
-#include <trace/events/io_uring.h>
-
-#include <uapi/linux/io_uring.h>
-
-#include "internal.h"
-#include "io-wq.h"
-
-#define IORING_MAX_ENTRIES     32768
-#define IORING_MAX_CQ_ENTRIES  (2 * IORING_MAX_ENTRIES)
-#define IORING_SQPOLL_CAP_ENTRIES_VALUE 8
-
-/* only define max */
-#define IORING_MAX_FIXED_FILES (1U << 20)
-#define IORING_MAX_RESTRICTIONS        (IORING_RESTRICTION_LAST + \
-                                IORING_REGISTER_LAST + IORING_OP_LAST)
-
-#define IO_RSRC_TAG_TABLE_SHIFT        (PAGE_SHIFT - 3)
-#define IO_RSRC_TAG_TABLE_MAX  (1U << IO_RSRC_TAG_TABLE_SHIFT)
-#define IO_RSRC_TAG_TABLE_MASK (IO_RSRC_TAG_TABLE_MAX - 1)
-
-#define IORING_MAX_REG_BUFFERS (1U << 14)
-
-#define SQE_COMMON_FLAGS (IOSQE_FIXED_FILE | IOSQE_IO_LINK | \
-                         IOSQE_IO_HARDLINK | IOSQE_ASYNC)
-
-#define SQE_VALID_FLAGS        (SQE_COMMON_FLAGS | IOSQE_BUFFER_SELECT | \
-                       IOSQE_IO_DRAIN | IOSQE_CQE_SKIP_SUCCESS)
-
-#define IO_REQ_CLEAN_FLAGS (REQ_F_BUFFER_SELECTED | REQ_F_NEED_CLEANUP | \
-                               REQ_F_POLLED | REQ_F_INFLIGHT | REQ_F_CREDS | \
-                               REQ_F_ASYNC_DATA)
-
-#define IO_REQ_CLEAN_SLOW_FLAGS (REQ_F_REFCOUNT | REQ_F_LINK | REQ_F_HARDLINK |\
-                                IO_REQ_CLEAN_FLAGS)
-
-#define IO_APOLL_MULTI_POLLED (REQ_F_APOLL_MULTISHOT | REQ_F_POLLED)
-
-#define IO_TCTX_REFS_CACHE_NR  (1U << 10)
-
-struct io_uring {
-       u32 head ____cacheline_aligned_in_smp;
-       u32 tail ____cacheline_aligned_in_smp;
-};
-
-/*
- * This data is shared with the application through the mmap at offsets
- * IORING_OFF_SQ_RING and IORING_OFF_CQ_RING.
- *
- * The offsets to the member fields are published through struct
- * io_sqring_offsets when calling io_uring_setup.
- */
-struct io_rings {
-       /*
-        * Head and tail offsets into the ring; the offsets need to be
-        * masked to get valid indices.
-        *
-        * The kernel controls head of the sq ring and the tail of the cq ring,
-        * and the application controls tail of the sq ring and the head of the
-        * cq ring.
-        */
-       struct io_uring         sq, cq;
-       /*
-        * Bitmasks to apply to head and tail offsets (constant, equals
-        * ring_entries - 1)
-        */
-       u32                     sq_ring_mask, cq_ring_mask;
-       /* Ring sizes (constant, power of 2) */
-       u32                     sq_ring_entries, cq_ring_entries;
-       /*
-        * Number of invalid entries dropped by the kernel due to
-        * invalid index stored in array
-        *
-        * Written by the kernel, shouldn't be modified by the
-        * application (i.e. get number of "new events" by comparing to
-        * cached value).
-        *
-        * After a new SQ head value was read by the application this
-        * counter includes all submissions that were dropped reaching
-        * the new SQ head (and possibly more).
-        */
-       u32                     sq_dropped;
-       /*
-        * Runtime SQ flags
-        *
-        * Written by the kernel, shouldn't be modified by the
-        * application.
-        *
-        * The application needs a full memory barrier before checking
-        * for IORING_SQ_NEED_WAKEUP after updating the sq tail.
-        */
-       atomic_t                sq_flags;
-       /*
-        * Runtime CQ flags
-        *
-        * Written by the application, shouldn't be modified by the
-        * kernel.
-        */
-       u32                     cq_flags;
-       /*
-        * Number of completion events lost because the queue was full;
-        * this should be avoided by the application by making sure
-        * there are not more requests pending than there is space in
-        * the completion queue.
-        *
-        * Written by the kernel, shouldn't be modified by the
-        * application (i.e. get number of "new events" by comparing to
-        * cached value).
-        *
-        * As completion events come in out of order this counter is not
-        * ordered with any other data.
-        */
-       u32                     cq_overflow;
-       /*
-        * Ring buffer of completion events.
-        *
-        * The kernel writes completion events fresh every time they are
-        * produced, so the application is allowed to modify pending
-        * entries.
-        */
-       struct io_uring_cqe     cqes[] ____cacheline_aligned_in_smp;
-};
-
-struct io_mapped_ubuf {
-       u64             ubuf;
-       u64             ubuf_end;
-       unsigned int    nr_bvecs;
-       unsigned long   acct_pages;
-       struct bio_vec  bvec[];
-};
-
-struct io_ring_ctx;
-
-struct io_overflow_cqe {
-       struct list_head list;
-       struct io_uring_cqe cqe;
-};
-
-/*
- * FFS_SCM is only available on 64-bit archs, for 32-bit we just define it as 0
- * and define IO_URING_SCM_ALL. For this case, we use SCM for all files as we
- * can't safely always dereference the file when the task has exited and ring
- * cleanup is done. If a file is tracked and part of SCM, then unix gc on
- * process exit may reap it before __io_sqe_files_unregister() is run.
- */
-#define FFS_NOWAIT             0x1UL
-#define FFS_ISREG              0x2UL
-#if defined(CONFIG_64BIT)
-#define FFS_SCM                        0x4UL
-#else
-#define IO_URING_SCM_ALL
-#define FFS_SCM                        0x0UL
-#endif
-#define FFS_MASK               ~(FFS_NOWAIT|FFS_ISREG|FFS_SCM)
-
-struct io_fixed_file {
-       /* file * with additional FFS_* flags */
-       unsigned long file_ptr;
-};
-
-struct io_rsrc_put {
-       struct list_head list;
-       u64 tag;
-       union {
-               void *rsrc;
-               struct file *file;
-               struct io_mapped_ubuf *buf;
-       };
-};
-
-struct io_file_table {
-       struct io_fixed_file *files;
-       unsigned long *bitmap;
-       unsigned int alloc_hint;
-};
-
-struct io_rsrc_node {
-       struct percpu_ref               refs;
-       struct list_head                node;
-       struct list_head                rsrc_list;
-       struct io_rsrc_data             *rsrc_data;
-       struct llist_node               llist;
-       bool                            done;
-};
-
-typedef void (rsrc_put_fn)(struct io_ring_ctx *ctx, struct io_rsrc_put *prsrc);
-
-struct io_rsrc_data {
-       struct io_ring_ctx              *ctx;
-
-       u64                             **tags;
-       unsigned int                    nr;
-       rsrc_put_fn                     *do_put;
-       atomic_t                        refs;
-       struct completion               done;
-       bool                            quiesce;
-};
-
-#define IO_BUFFER_LIST_BUF_PER_PAGE (PAGE_SIZE / sizeof(struct io_uring_buf))
-struct io_buffer_list {
-       /*
-        * If ->buf_nr_pages is set, then buf_pages/buf_ring are used. If not,
-        * then these are classic provided buffers and ->buf_list is used.
-        */
-       union {
-               struct list_head buf_list;
-               struct {
-                       struct page **buf_pages;
-                       struct io_uring_buf_ring *buf_ring;
-               };
-       };
-       __u16 bgid;
-
-       /* below is for ring provided buffers */
-       __u16 buf_nr_pages;
-       __u16 nr_entries;
-       __u16 head;
-       __u16 mask;
-};
-
-struct io_buffer {
-       struct list_head list;
-       __u64 addr;
-       __u32 len;
-       __u16 bid;
-       __u16 bgid;
-};
-
-struct io_restriction {
-       DECLARE_BITMAP(register_op, IORING_REGISTER_LAST);
-       DECLARE_BITMAP(sqe_op, IORING_OP_LAST);
-       u8 sqe_flags_allowed;
-       u8 sqe_flags_required;
-       bool registered;
-};
-
-enum {
-       IO_SQ_THREAD_SHOULD_STOP = 0,
-       IO_SQ_THREAD_SHOULD_PARK,
-};
-
-struct io_sq_data {
-       refcount_t              refs;
-       atomic_t                park_pending;
-       struct mutex            lock;
-
-       /* ctx's that are using this sqd */
-       struct list_head        ctx_list;
-
-       struct task_struct      *thread;
-       struct wait_queue_head  wait;
-
-       unsigned                sq_thread_idle;
-       int                     sq_cpu;
-       pid_t                   task_pid;
-       pid_t                   task_tgid;
-
-       unsigned long           state;
-       struct completion       exited;
-};
-
-#define IO_COMPL_BATCH                 32
-#define IO_REQ_CACHE_SIZE              32
-#define IO_REQ_ALLOC_BATCH             8
-
-struct io_submit_link {
-       struct io_kiocb         *head;
-       struct io_kiocb         *last;
-};
-
-struct io_submit_state {
-       /* inline/task_work completion list, under ->uring_lock */
-       struct io_wq_work_node  free_list;
-       /* batch completion logic */
-       struct io_wq_work_list  compl_reqs;
-       struct io_submit_link   link;
-
-       bool                    plug_started;
-       bool                    need_plug;
-       bool                    flush_cqes;
-       unsigned short          submit_nr;
-       struct blk_plug         plug;
-};
-
-struct io_ev_fd {
-       struct eventfd_ctx      *cq_ev_fd;
-       unsigned int            eventfd_async: 1;
-       struct rcu_head         rcu;
-};
-
-#define BGID_ARRAY     64
-
-struct io_ring_ctx {
-       /* const or read-mostly hot data */
-       struct {
-               struct percpu_ref       refs;
-
-               struct io_rings         *rings;
-               unsigned int            flags;
-               enum task_work_notify_mode      notify_method;
-               unsigned int            compat: 1;
-               unsigned int            drain_next: 1;
-               unsigned int            restricted: 1;
-               unsigned int            off_timeout_used: 1;
-               unsigned int            drain_active: 1;
-               unsigned int            drain_disabled: 1;
-               unsigned int            has_evfd: 1;
-               unsigned int            syscall_iopoll: 1;
-       } ____cacheline_aligned_in_smp;
-
-       /* submission data */
-       struct {
-               struct mutex            uring_lock;
-
-               /*
-                * Ring buffer of indices into array of io_uring_sqe, which is
-                * mmapped by the application using the IORING_OFF_SQES offset.
-                *
-                * This indirection could e.g. be used to assign fixed
-                * io_uring_sqe entries to operations and only submit them to
-                * the queue when needed.
-                *
-                * The kernel modifies neither the indices array nor the entries
-                * array.
-                */
-               u32                     *sq_array;
-               struct io_uring_sqe     *sq_sqes;
-               unsigned                cached_sq_head;
-               unsigned                sq_entries;
-               struct list_head        defer_list;
-
-               /*
-                * Fixed resources fast path, should be accessed only under
-                * uring_lock, and updated through io_uring_register(2)
-                */
-               struct io_rsrc_node     *rsrc_node;
-               int                     rsrc_cached_refs;
-               atomic_t                cancel_seq;
-               struct io_file_table    file_table;
-               unsigned                nr_user_files;
-               unsigned                nr_user_bufs;
-               struct io_mapped_ubuf   **user_bufs;
-
-               struct io_submit_state  submit_state;
-
-               struct io_buffer_list   *io_bl;
-               struct xarray           io_bl_xa;
-               struct list_head        io_buffers_cache;
-
-               struct list_head        timeout_list;
-               struct list_head        ltimeout_list;
-               struct list_head        cq_overflow_list;
-               struct list_head        apoll_cache;
-               struct xarray           personalities;
-               u32                     pers_next;
-               unsigned                sq_thread_idle;
-       } ____cacheline_aligned_in_smp;
-
-       /* IRQ completion list, under ->completion_lock */
-       struct io_wq_work_list  locked_free_list;
-       unsigned int            locked_free_nr;
-
-       const struct cred       *sq_creds;      /* cred used for __io_sq_thread() */
-       struct io_sq_data       *sq_data;       /* if using sq thread polling */
-
-       struct wait_queue_head  sqo_sq_wait;
-       struct list_head        sqd_list;
-
-       unsigned long           check_cq;
-
-       struct {
-               /*
-                * We cache a range of free CQEs we can use, once exhausted it
-                * should go through a slower range setup, see __io_get_cqe()
-                */
-               struct io_uring_cqe     *cqe_cached;
-               struct io_uring_cqe     *cqe_sentinel;
-
-               unsigned                cached_cq_tail;
-               unsigned                cq_entries;
-               struct io_ev_fd __rcu   *io_ev_fd;
-               struct wait_queue_head  cq_wait;
-               unsigned                cq_extra;
-               atomic_t                cq_timeouts;
-               unsigned                cq_last_tm_flush;
-       } ____cacheline_aligned_in_smp;
-
-       struct {
-               spinlock_t              completion_lock;
-
-               spinlock_t              timeout_lock;
-
-               /*
-                * ->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;
-               struct hlist_head       *cancel_hash;
-               unsigned                cancel_hash_bits;
-               bool                    poll_multi_queue;
-
-               struct list_head        io_buffers_comp;
-       } ____cacheline_aligned_in_smp;
-
-       struct io_restriction           restrictions;
-
-       /* slow path rsrc auxilary data, used by update/register */
-       struct {
-               struct io_rsrc_node             *rsrc_backup_node;
-               struct io_mapped_ubuf           *dummy_ubuf;
-               struct io_rsrc_data             *file_data;
-               struct io_rsrc_data             *buf_data;
-
-               struct delayed_work             rsrc_put_work;
-               struct llist_head               rsrc_put_llist;
-               struct list_head                rsrc_ref_list;
-               spinlock_t                      rsrc_ref_lock;
-
-               struct list_head        io_buffers_pages;
-       };
-
-       /* Keep this last, we don't need it for the fast path */
-       struct {
-               #if defined(CONFIG_UNIX)
-                       struct socket           *ring_sock;
-               #endif
-               /* hashed buffered write serialization */
-               struct io_wq_hash               *hash_map;
-
-               /* Only used for accounting purposes */
-               struct user_struct              *user;
-               struct mm_struct                *mm_account;
-
-               /* ctx exit and cancelation */
-               struct llist_head               fallback_llist;
-               struct delayed_work             fallback_work;
-               struct work_struct              exit_work;
-               struct list_head                tctx_list;
-               struct completion               ref_comp;
-               u32                             iowq_limits[2];
-               bool                            iowq_limits_set;
-       };
-};
-
-/*
- * Arbitrary limit, can be raised if need be
- */
-#define IO_RINGFD_REG_MAX 16
-
-struct io_uring_task {
-       /* submission side */
-       int                     cached_refs;
-       struct xarray           xa;
-       struct wait_queue_head  wait;
-       const struct io_ring_ctx *last;
-       struct io_wq            *io_wq;
-       struct percpu_counter   inflight;
-       atomic_t                inflight_tracked;
-       atomic_t                in_idle;
-
-       spinlock_t              task_lock;
-       struct io_wq_work_list  task_list;
-       struct io_wq_work_list  prio_task_list;
-       struct callback_head    task_work;
-       struct file             **registered_rings;
-       bool                    task_running;
-};
-
-/*
- * First field must be the file pointer in all the
- * iocb unions! See also 'struct kiocb' in <linux/fs.h>
- */
-struct io_poll_iocb {
-       struct file                     *file;
-       struct wait_queue_head          *head;
-       __poll_t                        events;
-       struct wait_queue_entry         wait;
-};
-
-struct io_poll_update {
-       struct file                     *file;
-       u64                             old_user_data;
-       u64                             new_user_data;
-       __poll_t                        events;
-       bool                            update_events;
-       bool                            update_user_data;
-};
-
-struct io_close {
-       struct file                     *file;
-       int                             fd;
-       u32                             file_slot;
-};
-
-struct io_timeout_data {
-       struct io_kiocb                 *req;
-       struct hrtimer                  timer;
-       struct timespec64               ts;
-       enum hrtimer_mode               mode;
-       u32                             flags;
-};
-
-struct io_accept {
-       struct file                     *file;
-       struct sockaddr __user          *addr;
-       int __user                      *addr_len;
-       int                             flags;
-       u32                             file_slot;
-       unsigned long                   nofile;
-};
-
-struct io_socket {
-       struct file                     *file;
-       int                             domain;
-       int                             type;
-       int                             protocol;
-       int                             flags;
-       u32                             file_slot;
-       unsigned long                   nofile;
-};
-
-struct io_sync {
-       struct file                     *file;
-       loff_t                          len;
-       loff_t                          off;
-       int                             flags;
-       int                             mode;
-};
-
-struct io_cancel {
-       struct file                     *file;
-       u64                             addr;
-       u32                             flags;
-       s32                             fd;
-};
-
-struct io_timeout {
-       struct file                     *file;
-       u32                             off;
-       u32                             target_seq;
-       struct list_head                list;
-       /* head of the link, used by linked timeouts only */
-       struct io_kiocb                 *head;
-       /* for linked completions */
-       struct io_kiocb                 *prev;
-};
-
-struct io_timeout_rem {
-       struct file                     *file;
-       u64                             addr;
-
-       /* timeout update */
-       struct timespec64               ts;
-       u32                             flags;
-       bool                            ltimeout;
-};
-
-struct io_rw {
-       /* NOTE: kiocb has the file as the first member, so don't do it here */
-       struct kiocb                    kiocb;
-       u64                             addr;
-       u32                             len;
-       rwf_t                           flags;
-};
-
-struct io_connect {
-       struct file                     *file;
-       struct sockaddr __user          *addr;
-       int                             addr_len;
-};
-
-struct io_sr_msg {
-       struct file                     *file;
-       union {
-               struct compat_msghdr __user     *umsg_compat;
-               struct user_msghdr __user       *umsg;
-               void __user                     *buf;
-       };
-       int                             msg_flags;
-       size_t                          len;
-       size_t                          done_io;
-       unsigned int                    flags;
-};
-
-struct io_open {
-       struct file                     *file;
-       int                             dfd;
-       u32                             file_slot;
-       struct filename                 *filename;
-       struct open_how                 how;
-       unsigned long                   nofile;
-};
-
-struct io_rsrc_update {
-       struct file                     *file;
-       u64                             arg;
-       u32                             nr_args;
-       u32                             offset;
-};
-
-struct io_fadvise {
-       struct file                     *file;
-       u64                             offset;
-       u32                             len;
-       u32                             advice;
-};
-
-struct io_madvise {
-       struct file                     *file;
-       u64                             addr;
-       u32                             len;
-       u32                             advice;
-};
-
-struct io_epoll {
-       struct file                     *file;
-       int                             epfd;
-       int                             op;
-       int                             fd;
-       struct epoll_event              event;
-};
-
-struct io_splice {
-       struct file                     *file_out;
-       loff_t                          off_out;
-       loff_t                          off_in;
-       u64                             len;
-       int                             splice_fd_in;
-       unsigned int                    flags;
-};
-
-struct io_provide_buf {
-       struct file                     *file;
-       __u64                           addr;
-       __u32                           len;
-       __u32                           bgid;
-       __u16                           nbufs;
-       __u16                           bid;
-};
-
-struct io_statx {
-       struct file                     *file;
-       int                             dfd;
-       unsigned int                    mask;
-       unsigned int                    flags;
-       struct filename                 *filename;
-       struct statx __user             *buffer;
-};
-
-struct io_shutdown {
-       struct file                     *file;
-       int                             how;
-};
-
-struct io_rename {
-       struct file                     *file;
-       int                             old_dfd;
-       int                             new_dfd;
-       struct filename                 *oldpath;
-       struct filename                 *newpath;
-       int                             flags;
-};
-
-struct io_unlink {
-       struct file                     *file;
-       int                             dfd;
-       int                             flags;
-       struct filename                 *filename;
-};
-
-struct io_mkdir {
-       struct file                     *file;
-       int                             dfd;
-       umode_t                         mode;
-       struct filename                 *filename;
-};
-
-struct io_symlink {
-       struct file                     *file;
-       int                             new_dfd;
-       struct filename                 *oldpath;
-       struct filename                 *newpath;
-};
-
-struct io_hardlink {
-       struct file                     *file;
-       int                             old_dfd;
-       int                             new_dfd;
-       struct filename                 *oldpath;
-       struct filename                 *newpath;
-       int                             flags;
-};
-
-struct io_msg {
-       struct file                     *file;
-       u64 user_data;
-       u32 len;
-};
-
-struct io_async_connect {
-       struct sockaddr_storage         address;
-};
-
-struct io_async_msghdr {
-       struct iovec                    fast_iov[UIO_FASTIOV];
-       /* points to an allocated iov, if NULL we use fast_iov instead */
-       struct iovec                    *free_iov;
-       struct sockaddr __user          *uaddr;
-       struct msghdr                   msg;
-       struct sockaddr_storage         addr;
-};
-
-struct io_rw_state {
-       struct iov_iter                 iter;
-       struct iov_iter_state           iter_state;
-       struct iovec                    fast_iov[UIO_FASTIOV];
-};
-
-struct io_async_rw {
-       struct io_rw_state              s;
-       const struct iovec              *free_iovec;
-       size_t                          bytes_done;
-       struct wait_page_queue          wpq;
-};
-
-struct io_xattr {
-       struct file                     *file;
-       struct xattr_ctx                ctx;
-       struct filename                 *filename;
-};
-
-enum {
-       REQ_F_FIXED_FILE_BIT    = IOSQE_FIXED_FILE_BIT,
-       REQ_F_IO_DRAIN_BIT      = IOSQE_IO_DRAIN_BIT,
-       REQ_F_LINK_BIT          = IOSQE_IO_LINK_BIT,
-       REQ_F_HARDLINK_BIT      = IOSQE_IO_HARDLINK_BIT,
-       REQ_F_FORCE_ASYNC_BIT   = IOSQE_ASYNC_BIT,
-       REQ_F_BUFFER_SELECT_BIT = IOSQE_BUFFER_SELECT_BIT,
-       REQ_F_CQE_SKIP_BIT      = IOSQE_CQE_SKIP_SUCCESS_BIT,
-
-       /* first byte is taken by user flags, shift it to not overlap */
-       REQ_F_FAIL_BIT          = 8,
-       REQ_F_INFLIGHT_BIT,
-       REQ_F_CUR_POS_BIT,
-       REQ_F_NOWAIT_BIT,
-       REQ_F_LINK_TIMEOUT_BIT,
-       REQ_F_NEED_CLEANUP_BIT,
-       REQ_F_POLLED_BIT,
-       REQ_F_BUFFER_SELECTED_BIT,
-       REQ_F_BUFFER_RING_BIT,
-       REQ_F_COMPLETE_INLINE_BIT,
-       REQ_F_REISSUE_BIT,
-       REQ_F_CREDS_BIT,
-       REQ_F_REFCOUNT_BIT,
-       REQ_F_ARM_LTIMEOUT_BIT,
-       REQ_F_ASYNC_DATA_BIT,
-       REQ_F_SKIP_LINK_CQES_BIT,
-       REQ_F_SINGLE_POLL_BIT,
-       REQ_F_DOUBLE_POLL_BIT,
-       REQ_F_PARTIAL_IO_BIT,
-       REQ_F_CQE32_INIT_BIT,
-       REQ_F_APOLL_MULTISHOT_BIT,
-       /* keep async read/write and isreg together and in order */
-       REQ_F_SUPPORT_NOWAIT_BIT,
-       REQ_F_ISREG_BIT,
-
-       /* not a real bit, just to check we're not overflowing the space */
-       __REQ_F_LAST_BIT,
-};
-
-enum {
-       /* ctx owns file */
-       REQ_F_FIXED_FILE        = BIT(REQ_F_FIXED_FILE_BIT),
-       /* drain existing IO first */
-       REQ_F_IO_DRAIN          = BIT(REQ_F_IO_DRAIN_BIT),
-       /* linked sqes */
-       REQ_F_LINK              = BIT(REQ_F_LINK_BIT),
-       /* doesn't sever on completion < 0 */
-       REQ_F_HARDLINK          = BIT(REQ_F_HARDLINK_BIT),
-       /* IOSQE_ASYNC */
-       REQ_F_FORCE_ASYNC       = BIT(REQ_F_FORCE_ASYNC_BIT),
-       /* IOSQE_BUFFER_SELECT */
-       REQ_F_BUFFER_SELECT     = BIT(REQ_F_BUFFER_SELECT_BIT),
-       /* IOSQE_CQE_SKIP_SUCCESS */
-       REQ_F_CQE_SKIP          = BIT(REQ_F_CQE_SKIP_BIT),
-
-       /* fail rest of links */
-       REQ_F_FAIL              = BIT(REQ_F_FAIL_BIT),
-       /* on inflight list, should be cancelled and waited on exit reliably */
-       REQ_F_INFLIGHT          = BIT(REQ_F_INFLIGHT_BIT),
-       /* read/write uses file position */
-       REQ_F_CUR_POS           = BIT(REQ_F_CUR_POS_BIT),
-       /* must not punt to workers */
-       REQ_F_NOWAIT            = BIT(REQ_F_NOWAIT_BIT),
-       /* has or had linked timeout */
-       REQ_F_LINK_TIMEOUT      = BIT(REQ_F_LINK_TIMEOUT_BIT),
-       /* needs cleanup */
-       REQ_F_NEED_CLEANUP      = BIT(REQ_F_NEED_CLEANUP_BIT),
-       /* already went through poll handler */
-       REQ_F_POLLED            = BIT(REQ_F_POLLED_BIT),
-       /* buffer already selected */
-       REQ_F_BUFFER_SELECTED   = BIT(REQ_F_BUFFER_SELECTED_BIT),
-       /* buffer selected from ring, needs commit */
-       REQ_F_BUFFER_RING       = BIT(REQ_F_BUFFER_RING_BIT),
-       /* completion is deferred through io_comp_state */
-       REQ_F_COMPLETE_INLINE   = BIT(REQ_F_COMPLETE_INLINE_BIT),
-       /* caller should reissue async */
-       REQ_F_REISSUE           = BIT(REQ_F_REISSUE_BIT),
-       /* supports async reads/writes */
-       REQ_F_SUPPORT_NOWAIT    = BIT(REQ_F_SUPPORT_NOWAIT_BIT),
-       /* regular file */
-       REQ_F_ISREG             = BIT(REQ_F_ISREG_BIT),
-       /* has creds assigned */
-       REQ_F_CREDS             = BIT(REQ_F_CREDS_BIT),
-       /* skip refcounting if not set */
-       REQ_F_REFCOUNT          = BIT(REQ_F_REFCOUNT_BIT),
-       /* there is a linked timeout that has to be armed */
-       REQ_F_ARM_LTIMEOUT      = BIT(REQ_F_ARM_LTIMEOUT_BIT),
-       /* ->async_data allocated */
-       REQ_F_ASYNC_DATA        = BIT(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),
-       /* single poll may be active */
-       REQ_F_SINGLE_POLL       = BIT(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),
-       /* fast poll multishot mode */
-       REQ_F_APOLL_MULTISHOT   = BIT(REQ_F_APOLL_MULTISHOT_BIT),
-       /* ->extra1 and ->extra2 are initialised */
-       REQ_F_CQE32_INIT        = BIT(REQ_F_CQE32_INIT_BIT),
-};
-
-struct async_poll {
-       struct io_poll_iocb     poll;
-       struct io_poll_iocb     *double_poll;
-};
-
-typedef void (*io_req_tw_func_t)(struct io_kiocb *req, bool *locked);
-
-struct io_task_work {
-       union {
-               struct io_wq_work_node  node;
-               struct llist_node       fallback_node;
-       };
-       io_req_tw_func_t                func;
-};
-
-enum {
-       IORING_RSRC_FILE                = 0,
-       IORING_RSRC_BUFFER              = 1,
-};
-
-struct io_cqe {
-       __u64   user_data;
-       __s32   res;
-       /* fd initially, then cflags for completion */
-       union {
-               __u32   flags;
-               int     fd;
-       };
-};
-
-enum {
-       IO_CHECK_CQ_OVERFLOW_BIT,
-       IO_CHECK_CQ_DROPPED_BIT,
-};
-
-/*
- * NOTE! Each of the iocb union members has the file pointer
- * as the first entry in their struct definition. So you can
- * access the file pointer through any of the sub-structs,
- * or directly as just 'file' in this struct.
- */
-struct io_kiocb {
-       union {
-               struct file             *file;
-               struct io_rw            rw;
-               struct io_poll_iocb     poll;
-               struct io_poll_update   poll_update;
-               struct io_accept        accept;
-               struct io_sync          sync;
-               struct io_cancel        cancel;
-               struct io_timeout       timeout;
-               struct io_timeout_rem   timeout_rem;
-               struct io_connect       connect;
-               struct io_sr_msg        sr_msg;
-               struct io_open          open;
-               struct io_close         close;
-               struct io_rsrc_update   rsrc_update;
-               struct io_fadvise       fadvise;
-               struct io_madvise       madvise;
-               struct io_epoll         epoll;
-               struct io_splice        splice;
-               struct io_provide_buf   pbuf;
-               struct io_statx         statx;
-               struct io_shutdown      shutdown;
-               struct io_rename        rename;
-               struct io_unlink        unlink;
-               struct io_mkdir         mkdir;
-               struct io_symlink       symlink;
-               struct io_hardlink      hardlink;
-               struct io_msg           msg;
-               struct io_xattr         xattr;
-               struct io_socket        sock;
-               struct io_uring_cmd     uring_cmd;
-       };
-
-       u8                              opcode;
-       /* polled IO has completed */
-       u8                              iopoll_completed;
-       /*
-        * Can be either a fixed buffer index, or used with provided buffers.
-        * For the latter, before issue it points to the buffer group ID,
-        * and after selection it points to the buffer ID itself.
-        */
-       u16                             buf_index;
-       unsigned int                    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;
-
-               /* stores selected buf, valid IFF REQ_F_BUFFER_SELECTED is set */
-               struct io_buffer        *kbuf;
-
-               /*
-                * stores buffer ID for ring provided buffers, valid IFF
-                * REQ_F_BUFFER_RING is set.
-                */
-               struct io_buffer_list   *buf_list;
-       };
-
-       union {
-               /* used by request caches, completion batching and iopoll */
-               struct io_wq_work_node  comp_list;
-               /* cache ->apoll->events */
-               __poll_t apoll_events;
-       };
-       atomic_t                        refs;
-       atomic_t                        poll_refs;
-       struct io_task_work             io_task_work;
-       /* for polled requests, i.e. IORING_OP_POLL_ADD and async armed poll */
-       union {
-               struct hlist_node       hash_node;
-               struct {
-                       u64             extra1;
-                       u64             extra2;
-               };
-       };
-       /* internal polling, see IORING_FEAT_FAST_POLL */
-       struct async_poll               *apoll;
-       /* opcode allocated if it needs to store data for async defer */
-       void                            *async_data;
-       /* linked requests, IFF REQ_F_HARDLINK or REQ_F_LINK are set */
-       struct io_kiocb                 *link;
-       /* custom credentials, valid IFF REQ_F_CREDS is set */
-       const struct cred               *creds;
-       struct io_wq_work               work;
-};
-
-struct io_tctx_node {
-       struct list_head        ctx_node;
-       struct task_struct      *task;
-       struct io_ring_ctx      *ctx;
-};
-
-struct io_defer_entry {
-       struct list_head        list;
-       struct io_kiocb         *req;
-       u32                     seq;
-};
-
-struct io_cancel_data {
-       struct io_ring_ctx *ctx;
-       union {
-               u64 data;
-               struct file *file;
-       };
-       u32 flags;
-       int seq;
-};
-
-/*
- * The URING_CMD payload starts at 'cmd' in the first sqe, and continues into
- * the following sqe if SQE128 is used.
- */
-#define uring_cmd_pdu_size(is_sqe128)                          \
-       ((1 + !!(is_sqe128)) * sizeof(struct io_uring_sqe) -    \
-               offsetof(struct io_uring_sqe, cmd))
-
-struct io_op_def {
-       /* needs req->file assigned */
-       unsigned                needs_file : 1;
-       /* should block plug */
-       unsigned                plug : 1;
-       /* hash wq insertion if file is a regular file */
-       unsigned                hash_reg_file : 1;
-       /* unbound wq insertion if file is a non-regular file */
-       unsigned                unbound_nonreg_file : 1;
-       /* set if opcode supports polled "wait" */
-       unsigned                pollin : 1;
-       unsigned                pollout : 1;
-       unsigned                poll_exclusive : 1;
-       /* op supports buffer selection */
-       unsigned                buffer_select : 1;
-       /* do prep async if is going to be punted */
-       unsigned                needs_async_setup : 1;
-       /* opcode is not supported by this kernel */
-       unsigned                not_supported : 1;
-       /* skip auditing */
-       unsigned                audit_skip : 1;
-       /* supports ioprio */
-       unsigned                ioprio : 1;
-       /* supports iopoll */
-       unsigned                iopoll : 1;
-       /* size of async data needed, if any */
-       unsigned short          async_size;
-};
-
-static const struct io_op_def io_op_defs[] = {
-       [IORING_OP_NOP] = {
-               .audit_skip             = 1,
-               .iopoll                 = 1,
-       },
-       [IORING_OP_READV] = {
-               .needs_file             = 1,
-               .unbound_nonreg_file    = 1,
-               .pollin                 = 1,
-               .buffer_select          = 1,
-               .needs_async_setup      = 1,
-               .plug                   = 1,
-               .audit_skip             = 1,
-               .ioprio                 = 1,
-               .iopoll                 = 1,
-               .async_size             = sizeof(struct io_async_rw),
-       },
-       [IORING_OP_WRITEV] = {
-               .needs_file             = 1,
-               .hash_reg_file          = 1,
-               .unbound_nonreg_file    = 1,
-               .pollout                = 1,
-               .needs_async_setup      = 1,
-               .plug                   = 1,
-               .audit_skip             = 1,
-               .ioprio                 = 1,
-               .iopoll                 = 1,
-               .async_size             = sizeof(struct io_async_rw),
-       },
-       [IORING_OP_FSYNC] = {
-               .needs_file             = 1,
-               .audit_skip             = 1,
-       },
-       [IORING_OP_READ_FIXED] = {
-               .needs_file             = 1,
-               .unbound_nonreg_file    = 1,
-               .pollin                 = 1,
-               .plug                   = 1,
-               .audit_skip             = 1,
-               .ioprio                 = 1,
-               .iopoll                 = 1,
-               .async_size             = sizeof(struct io_async_rw),
-       },
-       [IORING_OP_WRITE_FIXED] = {
-               .needs_file             = 1,
-               .hash_reg_file          = 1,
-               .unbound_nonreg_file    = 1,
-               .pollout                = 1,
-               .plug                   = 1,
-               .audit_skip             = 1,
-               .ioprio                 = 1,
-               .iopoll                 = 1,
-               .async_size             = sizeof(struct io_async_rw),
-       },
-       [IORING_OP_POLL_ADD] = {
-               .needs_file             = 1,
-               .unbound_nonreg_file    = 1,
-               .audit_skip             = 1,
-       },
-       [IORING_OP_POLL_REMOVE] = {
-               .audit_skip             = 1,
-       },
-       [IORING_OP_SYNC_FILE_RANGE] = {
-               .needs_file             = 1,
-               .audit_skip             = 1,
-       },
-       [IORING_OP_SENDMSG] = {
-               .needs_file             = 1,
-               .unbound_nonreg_file    = 1,
-               .pollout                = 1,
-               .needs_async_setup      = 1,
-               .async_size             = sizeof(struct io_async_msghdr),
-       },
-       [IORING_OP_RECVMSG] = {
-               .needs_file             = 1,
-               .unbound_nonreg_file    = 1,
-               .pollin                 = 1,
-               .buffer_select          = 1,
-               .needs_async_setup      = 1,
-               .async_size             = sizeof(struct io_async_msghdr),
-       },
-       [IORING_OP_TIMEOUT] = {
-               .audit_skip             = 1,
-               .async_size             = sizeof(struct io_timeout_data),
-       },
-       [IORING_OP_TIMEOUT_REMOVE] = {
-               /* used by timeout updates' prep() */
-               .audit_skip             = 1,
-       },
-       [IORING_OP_ACCEPT] = {
-               .needs_file             = 1,
-               .unbound_nonreg_file    = 1,
-               .pollin                 = 1,
-               .poll_exclusive         = 1,
-               .ioprio                 = 1,    /* used for flags */
-       },
-       [IORING_OP_ASYNC_CANCEL] = {
-               .audit_skip             = 1,
-       },
-       [IORING_OP_LINK_TIMEOUT] = {
-               .audit_skip             = 1,
-               .async_size             = sizeof(struct io_timeout_data),
-       },
-       [IORING_OP_CONNECT] = {
-               .needs_file             = 1,
-               .unbound_nonreg_file    = 1,
-               .pollout                = 1,
-               .needs_async_setup      = 1,
-               .async_size             = sizeof(struct io_async_connect),
-       },
-       [IORING_OP_FALLOCATE] = {
-               .needs_file             = 1,
-       },
-       [IORING_OP_OPENAT] = {},
-       [IORING_OP_CLOSE] = {},
-       [IORING_OP_FILES_UPDATE] = {
-               .audit_skip             = 1,
-               .iopoll                 = 1,
-       },
-       [IORING_OP_STATX] = {
-               .audit_skip             = 1,
-       },
-       [IORING_OP_READ] = {
-               .needs_file             = 1,
-               .unbound_nonreg_file    = 1,
-               .pollin                 = 1,
-               .buffer_select          = 1,
-               .plug                   = 1,
-               .audit_skip             = 1,
-               .ioprio                 = 1,
-               .iopoll                 = 1,
-               .async_size             = sizeof(struct io_async_rw),
-       },
-       [IORING_OP_WRITE] = {
-               .needs_file             = 1,
-               .hash_reg_file          = 1,
-               .unbound_nonreg_file    = 1,
-               .pollout                = 1,
-               .plug                   = 1,
-               .audit_skip             = 1,
-               .ioprio                 = 1,
-               .iopoll                 = 1,
-               .async_size             = sizeof(struct io_async_rw),
-       },
-       [IORING_OP_FADVISE] = {
-               .needs_file             = 1,
-               .audit_skip             = 1,
-       },
-       [IORING_OP_MADVISE] = {},
-       [IORING_OP_SEND] = {
-               .needs_file             = 1,
-               .unbound_nonreg_file    = 1,
-               .pollout                = 1,
-               .audit_skip             = 1,
-       },
-       [IORING_OP_RECV] = {
-               .needs_file             = 1,
-               .unbound_nonreg_file    = 1,
-               .pollin                 = 1,
-               .buffer_select          = 1,
-               .audit_skip             = 1,
-       },
-       [IORING_OP_OPENAT2] = {
-       },
-       [IORING_OP_EPOLL_CTL] = {
-               .unbound_nonreg_file    = 1,
-               .audit_skip             = 1,
-       },
-       [IORING_OP_SPLICE] = {
-               .needs_file             = 1,
-               .hash_reg_file          = 1,
-               .unbound_nonreg_file    = 1,
-               .audit_skip             = 1,
-       },
-       [IORING_OP_PROVIDE_BUFFERS] = {
-               .audit_skip             = 1,
-               .iopoll                 = 1,
-       },
-       [IORING_OP_REMOVE_BUFFERS] = {
-               .audit_skip             = 1,
-               .iopoll                 = 1,
-       },
-       [IORING_OP_TEE] = {
-               .needs_file             = 1,
-               .hash_reg_file          = 1,
-               .unbound_nonreg_file    = 1,
-               .audit_skip             = 1,
-       },
-       [IORING_OP_SHUTDOWN] = {
-               .needs_file             = 1,
-       },
-       [IORING_OP_RENAMEAT] = {},
-       [IORING_OP_UNLINKAT] = {},
-       [IORING_OP_MKDIRAT] = {},
-       [IORING_OP_SYMLINKAT] = {},
-       [IORING_OP_LINKAT] = {},
-       [IORING_OP_MSG_RING] = {
-               .needs_file             = 1,
-               .iopoll                 = 1,
-       },
-       [IORING_OP_FSETXATTR] = {
-               .needs_file = 1
-       },
-       [IORING_OP_SETXATTR] = {},
-       [IORING_OP_FGETXATTR] = {
-               .needs_file = 1
-       },
-       [IORING_OP_GETXATTR] = {},
-       [IORING_OP_SOCKET] = {
-               .audit_skip             = 1,
-       },
-       [IORING_OP_URING_CMD] = {
-               .needs_file             = 1,
-               .plug                   = 1,
-               .needs_async_setup      = 1,
-               .async_size             = uring_cmd_pdu_size(1),
-       },
-};
-
-/* requests with any of those set should undergo io_disarm_next() */
-#define IO_DISARM_MASK (REQ_F_ARM_LTIMEOUT | REQ_F_LINK_TIMEOUT | REQ_F_FAIL)
-#define IO_REQ_LINK_FLAGS (REQ_F_LINK | REQ_F_HARDLINK)
-
-static bool io_disarm_next(struct io_kiocb *req);
-static void io_uring_del_tctx_node(unsigned long index);
-static void io_uring_try_cancel_requests(struct io_ring_ctx *ctx,
-                                        struct task_struct *task,
-                                        bool cancel_all);
-static void io_uring_cancel_generic(bool cancel_all, struct io_sq_data *sqd);
-
-static void __io_req_complete_post(struct io_kiocb *req, s32 res, u32 cflags);
-static void io_dismantle_req(struct io_kiocb *req);
-static void io_queue_linked_timeout(struct io_kiocb *req);
-static int __io_register_rsrc_update(struct io_ring_ctx *ctx, unsigned type,
-                                    struct io_uring_rsrc_update2 *up,
-                                    unsigned nr_args);
-static void io_clean_op(struct io_kiocb *req);
-static inline struct file *io_file_get_fixed(struct io_kiocb *req, int fd,
-                                            unsigned issue_flags);
-static struct file *io_file_get_normal(struct io_kiocb *req, int fd);
-static void io_queue_sqe(struct io_kiocb *req);
-static void io_rsrc_put_work(struct work_struct *work);
-
-static void io_req_task_queue(struct io_kiocb *req);
-static void __io_submit_flush_completions(struct io_ring_ctx *ctx);
-static int io_req_prep_async(struct io_kiocb *req);
-
-static int io_install_fixed_file(struct io_kiocb *req, struct file *file,
-                                unsigned int issue_flags, u32 slot_index);
-static int __io_close_fixed(struct io_kiocb *req, unsigned int issue_flags,
-                           unsigned int offset);
-static inline int io_close_fixed(struct io_kiocb *req, unsigned int issue_flags);
-
-static enum hrtimer_restart io_link_timeout_fn(struct hrtimer *timer);
-static void io_eventfd_signal(struct io_ring_ctx *ctx);
-static void io_req_tw_post_queue(struct io_kiocb *req, s32 res, u32 cflags);
-
-static struct kmem_cache *req_cachep;
-
-static const struct file_operations io_uring_fops;
-
-const char *io_uring_get_opcode(u8 opcode)
-{
-       switch ((enum io_uring_op)opcode) {
-       case IORING_OP_NOP:
-               return "NOP";
-       case IORING_OP_READV:
-               return "READV";
-       case IORING_OP_WRITEV:
-               return "WRITEV";
-       case IORING_OP_FSYNC:
-               return "FSYNC";
-       case IORING_OP_READ_FIXED:
-               return "READ_FIXED";
-       case IORING_OP_WRITE_FIXED:
-               return "WRITE_FIXED";
-       case IORING_OP_POLL_ADD:
-               return "POLL_ADD";
-       case IORING_OP_POLL_REMOVE:
-               return "POLL_REMOVE";
-       case IORING_OP_SYNC_FILE_RANGE:
-               return "SYNC_FILE_RANGE";
-       case IORING_OP_SENDMSG:
-               return "SENDMSG";
-       case IORING_OP_RECVMSG:
-               return "RECVMSG";
-       case IORING_OP_TIMEOUT:
-               return "TIMEOUT";
-       case IORING_OP_TIMEOUT_REMOVE:
-               return "TIMEOUT_REMOVE";
-       case IORING_OP_ACCEPT:
-               return "ACCEPT";
-       case IORING_OP_ASYNC_CANCEL:
-               return "ASYNC_CANCEL";
-       case IORING_OP_LINK_TIMEOUT:
-               return "LINK_TIMEOUT";
-       case IORING_OP_CONNECT:
-               return "CONNECT";
-       case IORING_OP_FALLOCATE:
-               return "FALLOCATE";
-       case IORING_OP_OPENAT:
-               return "OPENAT";
-       case IORING_OP_CLOSE:
-               return "CLOSE";
-       case IORING_OP_FILES_UPDATE:
-               return "FILES_UPDATE";
-       case IORING_OP_STATX:
-               return "STATX";
-       case IORING_OP_READ:
-               return "READ";
-       case IORING_OP_WRITE:
-               return "WRITE";
-       case IORING_OP_FADVISE:
-               return "FADVISE";
-       case IORING_OP_MADVISE:
-               return "MADVISE";
-       case IORING_OP_SEND:
-               return "SEND";
-       case IORING_OP_RECV:
-               return "RECV";
-       case IORING_OP_OPENAT2:
-               return "OPENAT2";
-       case IORING_OP_EPOLL_CTL:
-               return "EPOLL_CTL";
-       case IORING_OP_SPLICE:
-               return "SPLICE";
-       case IORING_OP_PROVIDE_BUFFERS:
-               return "PROVIDE_BUFFERS";
-       case IORING_OP_REMOVE_BUFFERS:
-               return "REMOVE_BUFFERS";
-       case IORING_OP_TEE:
-               return "TEE";
-       case IORING_OP_SHUTDOWN:
-               return "SHUTDOWN";
-       case IORING_OP_RENAMEAT:
-               return "RENAMEAT";
-       case IORING_OP_UNLINKAT:
-               return "UNLINKAT";
-       case IORING_OP_MKDIRAT:
-               return "MKDIRAT";
-       case IORING_OP_SYMLINKAT:
-               return "SYMLINKAT";
-       case IORING_OP_LINKAT:
-               return "LINKAT";
-       case IORING_OP_MSG_RING:
-               return "MSG_RING";
-       case IORING_OP_FSETXATTR:
-               return "FSETXATTR";
-       case IORING_OP_SETXATTR:
-               return "SETXATTR";
-       case IORING_OP_FGETXATTR:
-               return "FGETXATTR";
-       case IORING_OP_GETXATTR:
-               return "GETXATTR";
-       case IORING_OP_SOCKET:
-               return "SOCKET";
-       case IORING_OP_URING_CMD:
-               return "URING_CMD";
-       case IORING_OP_LAST:
-               return "INVALID";
-       }
-       return "INVALID";
-}
-
-struct sock *io_uring_get_socket(struct file *file)
-{
-#if defined(CONFIG_UNIX)
-       if (file->f_op == &io_uring_fops) {
-               struct io_ring_ctx *ctx = file->private_data;
-
-               return ctx->ring_sock->sk;
-       }
-#endif
-       return NULL;
-}
-EXPORT_SYMBOL(io_uring_get_socket);
-
-#if defined(CONFIG_UNIX)
-static inline bool io_file_need_scm(struct file *filp)
-{
-#if defined(IO_URING_SCM_ALL)
-       return true;
-#else
-       return !!unix_get_socket(filp);
-#endif
-}
-#else
-static inline bool io_file_need_scm(struct file *filp)
-{
-       return false;
-}
-#endif
-
-static 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)
-               mutex_unlock(&ctx->uring_lock);
-}
-
-static void io_ring_submit_lock(struct io_ring_ctx *ctx, unsigned issue_flags)
-{
-       /*
-        * "Normal" inline submissions always hold the uring_lock, since we
-        * grab it from the system call. Same is true for the SQPOLL offload.
-        * 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)
-               mutex_lock(&ctx->uring_lock);
-       lockdep_assert_held(&ctx->uring_lock);
-}
-
-static inline void io_tw_lock(struct io_ring_ctx *ctx, bool *locked)
-{
-       if (!*locked) {
-               mutex_lock(&ctx->uring_lock);
-               *locked = true;
-       }
-}
-
-#define io_for_each_link(pos, head) \
-       for (pos = (head); pos; pos = pos->link)
-
-/*
- * Shamelessly stolen from the mm implementation of page reference checking,
- * see commit f958d7b528b1 for details.
- */
-#define req_ref_zero_or_close_to_overflow(req) \
-       ((unsigned int) atomic_read(&(req->refs)) + 127u <= 127u)
-
-static inline bool req_ref_inc_not_zero(struct io_kiocb *req)
-{
-       WARN_ON_ONCE(!(req->flags & REQ_F_REFCOUNT));
-       return atomic_inc_not_zero(&req->refs);
-}
-
-static inline bool req_ref_put_and_test(struct io_kiocb *req)
-{
-       if (likely(!(req->flags & REQ_F_REFCOUNT)))
-               return true;
-
-       WARN_ON_ONCE(req_ref_zero_or_close_to_overflow(req));
-       return atomic_dec_and_test(&req->refs);
-}
-
-static inline void req_ref_get(struct io_kiocb *req)
-{
-       WARN_ON_ONCE(!(req->flags & REQ_F_REFCOUNT));
-       WARN_ON_ONCE(req_ref_zero_or_close_to_overflow(req));
-       atomic_inc(&req->refs);
-}
-
-static inline void io_submit_flush_completions(struct io_ring_ctx *ctx)
-{
-       if (!wq_list_empty(&ctx->submit_state.compl_reqs))
-               __io_submit_flush_completions(ctx);
-}
-
-static inline void __io_req_set_refcount(struct io_kiocb *req, int nr)
-{
-       if (!(req->flags & REQ_F_REFCOUNT)) {
-               req->flags |= REQ_F_REFCOUNT;
-               atomic_set(&req->refs, nr);
-       }
-}
-
-static inline void io_req_set_refcount(struct io_kiocb *req)
-{
-       __io_req_set_refcount(req, 1);
-}
-
-#define IO_RSRC_REF_BATCH      100
-
-static void io_rsrc_put_node(struct io_rsrc_node *node, int nr)
-{
-       percpu_ref_put_many(&node->refs, nr);
-}
-
-static inline void io_req_put_rsrc_locked(struct io_kiocb *req,
-                                         struct io_ring_ctx *ctx)
-       __must_hold(&ctx->uring_lock)
-{
-       struct io_rsrc_node *node = req->rsrc_node;
-
-       if (node) {
-               if (node == ctx->rsrc_node)
-                       ctx->rsrc_cached_refs++;
-               else
-                       io_rsrc_put_node(node, 1);
-       }
-}
-
-static inline void io_req_put_rsrc(struct io_kiocb *req)
-{
-       if (req->rsrc_node)
-               io_rsrc_put_node(req->rsrc_node, 1);
-}
-
-static __cold void io_rsrc_refs_drop(struct io_ring_ctx *ctx)
-       __must_hold(&ctx->uring_lock)
-{
-       if (ctx->rsrc_cached_refs) {
-               io_rsrc_put_node(ctx->rsrc_node, ctx->rsrc_cached_refs);
-               ctx->rsrc_cached_refs = 0;
-       }
-}
-
-static void io_rsrc_refs_refill(struct io_ring_ctx *ctx)
-       __must_hold(&ctx->uring_lock)
-{
-       ctx->rsrc_cached_refs += IO_RSRC_REF_BATCH;
-       percpu_ref_get_many(&ctx->rsrc_node->refs, IO_RSRC_REF_BATCH);
-}
-
-static inline void io_req_set_rsrc_node(struct io_kiocb *req,
-                                       struct io_ring_ctx *ctx,
-                                       unsigned int issue_flags)
-{
-       if (!req->rsrc_node) {
-               req->rsrc_node = ctx->rsrc_node;
-
-               if (!(issue_flags & IO_URING_F_UNLOCKED)) {
-                       lockdep_assert_held(&ctx->uring_lock);
-                       ctx->rsrc_cached_refs--;
-                       if (unlikely(ctx->rsrc_cached_refs < 0))
-                               io_rsrc_refs_refill(ctx);
-               } else {
-                       percpu_ref_get(&req->rsrc_node->refs);
-               }
-       }
-}
-
-static unsigned int __io_put_kbuf(struct io_kiocb *req, struct list_head *list)
-{
-       if (req->flags & REQ_F_BUFFER_RING) {
-               if (req->buf_list)
-                       req->buf_list->head++;
-               req->flags &= ~REQ_F_BUFFER_RING;
-       } else {
-               list_add(&req->kbuf->list, list);
-               req->flags &= ~REQ_F_BUFFER_SELECTED;
-       }
-
-       return IORING_CQE_F_BUFFER | (req->buf_index << IORING_CQE_BUFFER_SHIFT);
-}
-
-static inline unsigned int io_put_kbuf_comp(struct io_kiocb *req)
-{
-       lockdep_assert_held(&req->ctx->completion_lock);
-
-       if (!(req->flags & (REQ_F_BUFFER_SELECTED|REQ_F_BUFFER_RING)))
-               return 0;
-       return __io_put_kbuf(req, &req->ctx->io_buffers_comp);
-}
-
-static inline unsigned int io_put_kbuf(struct io_kiocb *req,
-                                      unsigned issue_flags)
-{
-       unsigned int cflags;
-
-       if (!(req->flags & (REQ_F_BUFFER_SELECTED|REQ_F_BUFFER_RING)))
-               return 0;
-
-       /*
-        * We can add this buffer back to two lists:
-        *
-        * 1) The io_buffers_cache list. This one is protected by the
-        *    ctx->uring_lock. If we already hold this lock, add back to this
-        *    list as we can grab it from issue as well.
-        * 2) The io_buffers_comp list. This one is protected by the
-        *    ctx->completion_lock.
-        *
-        * 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(req, NULL);
-       } else if (issue_flags & IO_URING_F_UNLOCKED) {
-               struct io_ring_ctx *ctx = req->ctx;
-
-               spin_lock(&ctx->completion_lock);
-               cflags = __io_put_kbuf(req, &ctx->io_buffers_comp);
-               spin_unlock(&ctx->completion_lock);
-       } else {
-               lockdep_assert_held(&req->ctx->uring_lock);
-
-               cflags = __io_put_kbuf(req, &req->ctx->io_buffers_cache);
-       }
-
-       return cflags;
-}
-
-static struct io_buffer_list *io_buffer_get_list(struct io_ring_ctx *ctx,
-                                                unsigned int bgid)
-{
-       if (ctx->io_bl && bgid < BGID_ARRAY)
-               return &ctx->io_bl[bgid];
-
-       return xa_load(&ctx->io_bl_xa, bgid);
-}
-
-static void io_kbuf_recycle(struct io_kiocb *req, unsigned issue_flags)
-{
-       struct io_ring_ctx *ctx = req->ctx;
-       struct io_buffer_list *bl;
-       struct io_buffer *buf;
-
-       if (!(req->flags & (REQ_F_BUFFER_SELECTED|REQ_F_BUFFER_RING)))
-               return;
-       /*
-        * 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_BUFFER_SELECTED) &&
-           (req->flags & REQ_F_PARTIAL_IO))
-               return;
-
-       /*
-        * We don't need to recycle for REQ_F_BUFFER_RING, we can just clear
-        * the flag and hence ensure that bl->head doesn't get incremented.
-        * If the tail has already been incremented, hang on to it.
-        */
-       if (req->flags & REQ_F_BUFFER_RING) {
-               if (req->buf_list) {
-                       if (req->flags & REQ_F_PARTIAL_IO) {
-                               req->buf_list->head++;
-                               req->buf_list = NULL;
-                       } else {
-                               req->buf_index = req->buf_list->bgid;
-                               req->flags &= ~REQ_F_BUFFER_RING;
-                       }
-               }
-               return;
-       }
-
-       io_ring_submit_lock(ctx, issue_flags);
-
-       buf = req->kbuf;
-       bl = io_buffer_get_list(ctx, buf->bgid);
-       list_add(&buf->list, &bl->buf_list);
-       req->flags &= ~REQ_F_BUFFER_SELECTED;
-       req->buf_index = buf->bgid;
-
-       io_ring_submit_unlock(ctx, issue_flags);
-}
-
-static bool io_match_task(struct io_kiocb *head, struct task_struct *task,
-                         bool cancel_all)
-       __must_hold(&req->ctx->timeout_lock)
-{
-       struct io_kiocb *req;
-
-       if (task && head->task != task)
-               return false;
-       if (cancel_all)
-               return true;
-
-       io_for_each_link(req, head) {
-               if (req->flags & REQ_F_INFLIGHT)
-                       return true;
-       }
-       return false;
-}
-
-static bool io_match_linked(struct io_kiocb *head)
-{
-       struct io_kiocb *req;
-
-       io_for_each_link(req, head) {
-               if (req->flags & REQ_F_INFLIGHT)
-                       return true;
-       }
-       return false;
-}
-
-/*
- * As io_match_task() but protected against racing with linked timeouts.
- * User must not hold timeout_lock.
- */
-static bool io_match_task_safe(struct io_kiocb *head, struct task_struct *task,
-                              bool cancel_all)
-{
-       bool matched;
-
-       if (task && head->task != task)
-               return false;
-       if (cancel_all)
-               return true;
-
-       if (head->flags & REQ_F_LINK_TIMEOUT) {
-               struct io_ring_ctx *ctx = head->ctx;
-
-               /* protect against races with linked timeouts */
-               spin_lock_irq(&ctx->timeout_lock);
-               matched = io_match_linked(head);
-               spin_unlock_irq(&ctx->timeout_lock);
-       } else {
-               matched = io_match_linked(head);
-       }
-       return matched;
-}
-
-static inline bool req_has_async_data(struct io_kiocb *req)
-{
-       return req->flags & REQ_F_ASYNC_DATA;
-}
-
-static inline void req_set_fail(struct io_kiocb *req)
-{
-       req->flags |= REQ_F_FAIL;
-       if (req->flags & REQ_F_CQE_SKIP) {
-               req->flags &= ~REQ_F_CQE_SKIP;
-               req->flags |= REQ_F_SKIP_LINK_CQES;
-       }
-}
-
-static inline void req_fail_link_node(struct io_kiocb *req, int res)
-{
-       req_set_fail(req);
-       req->cqe.res = res;
-}
-
-static inline void io_req_add_to_cache(struct io_kiocb *req, struct io_ring_ctx *ctx)
-{
-       wq_stack_add_head(&req->comp_list, &ctx->submit_state.free_list);
-}
-
-static __cold void io_ring_ctx_ref_free(struct percpu_ref *ref)
-{
-       struct io_ring_ctx *ctx = container_of(ref, struct io_ring_ctx, refs);
-
-       complete(&ctx->ref_comp);
-}
-
-static inline bool io_is_timeout_noseq(struct io_kiocb *req)
-{
-       return !req->timeout.off;
-}
-
-static __cold void io_fallback_req_func(struct work_struct *work)
-{
-       struct io_ring_ctx *ctx = container_of(work, struct io_ring_ctx,
-                                               fallback_work.work);
-       struct llist_node *node = llist_del_all(&ctx->fallback_llist);
-       struct io_kiocb *req, *tmp;
-       bool locked = false;
-
-       percpu_ref_get(&ctx->refs);
-       llist_for_each_entry_safe(req, tmp, node, io_task_work.fallback_node)
-               req->io_task_work.func(req, &locked);
-
-       if (locked) {
-               io_submit_flush_completions(ctx);
-               mutex_unlock(&ctx->uring_lock);
-       }
-       percpu_ref_put(&ctx->refs);
-}
-
-static __cold struct io_ring_ctx *io_ring_ctx_alloc(struct io_uring_params *p)
-{
-       struct io_ring_ctx *ctx;
-       int hash_bits;
-
-       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
-       if (!ctx)
-               return NULL;
-
-       xa_init(&ctx->io_bl_xa);
-
-       /*
-        * Use 5 bits less than the max cq entries, that should give us around
-        * 32 entries per hash list if totally full and uniformly spread.
-        */
-       hash_bits = ilog2(p->cq_entries);
-       hash_bits -= 5;
-       if (hash_bits <= 0)
-               hash_bits = 1;
-       ctx->cancel_hash_bits = hash_bits;
-       ctx->cancel_hash = kmalloc((1U << hash_bits) * sizeof(struct hlist_head),
-                                       GFP_KERNEL);
-       if (!ctx->cancel_hash)
-               goto err;
-       __hash_init(ctx->cancel_hash, 1U << hash_bits);
-
-       ctx->dummy_ubuf = kzalloc(sizeof(*ctx->dummy_ubuf), GFP_KERNEL);
-       if (!ctx->dummy_ubuf)
-               goto err;
-       /* set invalid range, so io_import_fixed() fails meeting it */
-       ctx->dummy_ubuf->ubuf = -1UL;
-
-       if (percpu_ref_init(&ctx->refs, io_ring_ctx_ref_free,
-                           PERCPU_REF_ALLOW_REINIT, GFP_KERNEL))
-               goto err;
-
-       ctx->flags = p->flags;
-       init_waitqueue_head(&ctx->sqo_sq_wait);
-       INIT_LIST_HEAD(&ctx->sqd_list);
-       INIT_LIST_HEAD(&ctx->cq_overflow_list);
-       INIT_LIST_HEAD(&ctx->io_buffers_cache);
-       INIT_LIST_HEAD(&ctx->apoll_cache);
-       init_completion(&ctx->ref_comp);
-       xa_init_flags(&ctx->personalities, XA_FLAGS_ALLOC1);
-       mutex_init(&ctx->uring_lock);
-       init_waitqueue_head(&ctx->cq_wait);
-       spin_lock_init(&ctx->completion_lock);
-       spin_lock_init(&ctx->timeout_lock);
-       INIT_WQ_LIST(&ctx->iopoll_list);
-       INIT_LIST_HEAD(&ctx->io_buffers_pages);
-       INIT_LIST_HEAD(&ctx->io_buffers_comp);
-       INIT_LIST_HEAD(&ctx->defer_list);
-       INIT_LIST_HEAD(&ctx->timeout_list);
-       INIT_LIST_HEAD(&ctx->ltimeout_list);
-       spin_lock_init(&ctx->rsrc_ref_lock);
-       INIT_LIST_HEAD(&ctx->rsrc_ref_list);
-       INIT_DELAYED_WORK(&ctx->rsrc_put_work, io_rsrc_put_work);
-       init_llist_head(&ctx->rsrc_put_llist);
-       INIT_LIST_HEAD(&ctx->tctx_list);
-       ctx->submit_state.free_list.next = NULL;
-       INIT_WQ_LIST(&ctx->locked_free_list);
-       INIT_DELAYED_WORK(&ctx->fallback_work, io_fallback_req_func);
-       INIT_WQ_LIST(&ctx->submit_state.compl_reqs);
-       return ctx;
-err:
-       kfree(ctx->dummy_ubuf);
-       kfree(ctx->cancel_hash);
-       kfree(ctx->io_bl);
-       xa_destroy(&ctx->io_bl_xa);
-       kfree(ctx);
-       return NULL;
-}
-
-static void io_account_cq_overflow(struct io_ring_ctx *ctx)
-{
-       struct io_rings *r = ctx->rings;
-
-       WRITE_ONCE(r->cq_overflow, READ_ONCE(r->cq_overflow) + 1);
-       ctx->cq_extra--;
-}
-
-static bool req_need_defer(struct io_kiocb *req, u32 seq)
-{
-       if (unlikely(req->flags & REQ_F_IO_DRAIN)) {
-               struct io_ring_ctx *ctx = req->ctx;
-
-               return seq + READ_ONCE(ctx->cq_extra) != ctx->cached_cq_tail;
-       }
-
-       return false;
-}
-
-static inline bool io_req_ffs_set(struct io_kiocb *req)
-{
-       return req->flags & REQ_F_FIXED_FILE;
-}
-
-static inline void io_req_track_inflight(struct io_kiocb *req)
-{
-       if (!(req->flags & REQ_F_INFLIGHT)) {
-               req->flags |= REQ_F_INFLIGHT;
-               atomic_inc(&req->task->io_uring->inflight_tracked);
-       }
-}
-
-static struct io_kiocb *__io_prep_linked_timeout(struct io_kiocb *req)
-{
-       if (WARN_ON_ONCE(!req->link))
-               return NULL;
-
-       req->flags &= ~REQ_F_ARM_LTIMEOUT;
-       req->flags |= REQ_F_LINK_TIMEOUT;
-
-       /* linked timeouts should have two refs once prep'ed */
-       io_req_set_refcount(req);
-       __io_req_set_refcount(req->link, 2);
-       return req->link;
-}
-
-static inline struct io_kiocb *io_prep_linked_timeout(struct io_kiocb *req)
-{
-       if (likely(!(req->flags & REQ_F_ARM_LTIMEOUT)))
-               return NULL;
-       return __io_prep_linked_timeout(req);
-}
-
-static noinline void __io_arm_ltimeout(struct io_kiocb *req)
-{
-       io_queue_linked_timeout(__io_prep_linked_timeout(req));
-}
-
-static inline void io_arm_ltimeout(struct io_kiocb *req)
-{
-       if (unlikely(req->flags & REQ_F_ARM_LTIMEOUT))
-               __io_arm_ltimeout(req);
-}
-
-static void io_prep_async_work(struct io_kiocb *req)
-{
-       const struct io_op_def *def = &io_op_defs[req->opcode];
-       struct io_ring_ctx *ctx = req->ctx;
-
-       if (!(req->flags & REQ_F_CREDS)) {
-               req->flags |= REQ_F_CREDS;
-               req->creds = get_current_cred();
-       }
-
-       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;
-
-       if (req->flags & REQ_F_ISREG) {
-               if (def->hash_reg_file || (ctx->flags & IORING_SETUP_IOPOLL))
-                       io_wq_hash_work(&req->work, file_inode(req->file));
-       } else if (!req->file || !S_ISBLK(file_inode(req->file)->i_mode)) {
-               if (def->unbound_nonreg_file)
-                       req->work.flags |= IO_WQ_WORK_UNBOUND;
-       }
-}
-
-static void io_prep_async_link(struct io_kiocb *req)
-{
-       struct io_kiocb *cur;
-
-       if (req->flags & REQ_F_LINK_TIMEOUT) {
-               struct io_ring_ctx *ctx = req->ctx;
-
-               spin_lock_irq(&ctx->timeout_lock);
-               io_for_each_link(cur, req)
-                       io_prep_async_work(cur);
-               spin_unlock_irq(&ctx->timeout_lock);
-       } else {
-               io_for_each_link(cur, req)
-                       io_prep_async_work(cur);
-       }
-}
-
-static inline void io_req_add_compl_list(struct io_kiocb *req)
-{
-       struct io_submit_state *state = &req->ctx->submit_state;
-
-       if (!(req->flags & REQ_F_CQE_SKIP))
-               state->flush_cqes = true;
-       wq_list_add_tail(&req->comp_list, &state->compl_reqs);
-}
-
-static void io_queue_iowq(struct io_kiocb *req, bool *dont_use)
-{
-       struct io_kiocb *link = io_prep_linked_timeout(req);
-       struct io_uring_task *tctx = req->task->io_uring;
-
-       BUG_ON(!tctx);
-       BUG_ON(!tctx->io_wq);
-
-       /* init ->work of the whole link before punting */
-       io_prep_async_link(req);
-
-       /*
-        * Not expected to happen, but if we do have a bug where this _can_
-        * happen, catch it here and ensure the request is marked as
-        * canceled. That will make io-wq go through the usual work cancel
-        * procedure rather than attempt to run this request (or create a new
-        * worker for it).
-        */
-       if (WARN_ON_ONCE(!same_thread_group(req->task, current)))
-               req->work.flags |= IO_WQ_WORK_CANCEL;
-
-       trace_io_uring_queue_async_work(req->ctx, req, req->cqe.user_data,
-                                       req->opcode, req->flags, &req->work,
-                                       io_wq_is_hashed(&req->work));
-       io_wq_enqueue(tctx->io_wq, &req->work);
-       if (link)
-               io_queue_linked_timeout(link);
-}
-
-static void io_kill_timeout(struct io_kiocb *req, int status)
-       __must_hold(&req->ctx->completion_lock)
-       __must_hold(&req->ctx->timeout_lock)
-{
-       struct io_timeout_data *io = req->async_data;
-
-       if (hrtimer_try_to_cancel(&io->timer) != -1) {
-               if (status)
-                       req_set_fail(req);
-               atomic_set(&req->ctx->cq_timeouts,
-                       atomic_read(&req->ctx->cq_timeouts) + 1);
-               list_del_init(&req->timeout.list);
-               io_req_tw_post_queue(req, status, 0);
-       }
-}
-
-static __cold void io_queue_deferred(struct io_ring_ctx *ctx)
-{
-       while (!list_empty(&ctx->defer_list)) {
-               struct io_defer_entry *de = list_first_entry(&ctx->defer_list,
-                                               struct io_defer_entry, list);
-
-               if (req_need_defer(de->req, de->seq))
-                       break;
-               list_del_init(&de->list);
-               io_req_task_queue(de->req);
-               kfree(de);
-       }
-}
-
-static __cold void io_flush_timeouts(struct io_ring_ctx *ctx)
-       __must_hold(&ctx->completion_lock)
-{
-       u32 seq = ctx->cached_cq_tail - atomic_read(&ctx->cq_timeouts);
-       struct io_kiocb *req, *tmp;
-
-       spin_lock_irq(&ctx->timeout_lock);
-       list_for_each_entry_safe(req, tmp, &ctx->timeout_list, timeout.list) {
-               u32 events_needed, events_got;
-
-               if (io_is_timeout_noseq(req))
-                       break;
-
-               /*
-                * Since seq can easily wrap around over time, subtract
-                * the last seq at which timeouts were flushed before comparing.
-                * Assuming not more than 2^31-1 events have happened since,
-                * these subtractions won't have wrapped, so we can check if
-                * target is in [last_seq, current_seq] by comparing the two.
-                */
-               events_needed = req->timeout.target_seq - ctx->cq_last_tm_flush;
-               events_got = seq - ctx->cq_last_tm_flush;
-               if (events_got < events_needed)
-                       break;
-
-               io_kill_timeout(req, 0);
-       }
-       ctx->cq_last_tm_flush = seq;
-       spin_unlock_irq(&ctx->timeout_lock);
-}
-
-static inline void io_commit_cqring(struct io_ring_ctx *ctx)
-{
-       /* order cqe stores with ring update */
-       smp_store_release(&ctx->rings->cq.tail, ctx->cached_cq_tail);
-}
-
-static void __io_commit_cqring_flush(struct io_ring_ctx *ctx)
-{
-       if (ctx->off_timeout_used || ctx->drain_active) {
-               spin_lock(&ctx->completion_lock);
-               if (ctx->off_timeout_used)
-                       io_flush_timeouts(ctx);
-               if (ctx->drain_active)
-                       io_queue_deferred(ctx);
-               io_commit_cqring(ctx);
-               spin_unlock(&ctx->completion_lock);
-       }
-       if (ctx->has_evfd)
-               io_eventfd_signal(ctx);
-}
-
-static inline bool io_sqring_full(struct io_ring_ctx *ctx)
-{
-       struct io_rings *r = ctx->rings;
-
-       return READ_ONCE(r->sq.tail) - ctx->cached_sq_head == ctx->sq_entries;
-}
-
-static inline unsigned int __io_cqring_events(struct io_ring_ctx *ctx)
-{
-       return ctx->cached_cq_tail - READ_ONCE(ctx->rings->cq.head);
-}
-
-/*
- * writes to the cq entry need to come after reading head; the
- * control dependency is enough as we're using WRITE_ONCE to
- * fill the cq entry
- */
-static noinline struct io_uring_cqe *__io_get_cqe(struct io_ring_ctx *ctx)
-{
-       struct io_rings *rings = ctx->rings;
-       unsigned int off = ctx->cached_cq_tail & (ctx->cq_entries - 1);
-       unsigned int shift = 0;
-       unsigned int free, queued, len;
-
-       if (ctx->flags & IORING_SETUP_CQE32)
-               shift = 1;
-
-       /* userspace may cheat modifying the tail, be safe and do min */
-       queued = min(__io_cqring_events(ctx), ctx->cq_entries);
-       free = ctx->cq_entries - queued;
-       /* we need a contiguous range, limit based on the current array offset */
-       len = min(free, ctx->cq_entries - off);
-       if (!len)
-               return NULL;
-
-       ctx->cached_cq_tail++;
-       ctx->cqe_cached = &rings->cqes[off];
-       ctx->cqe_sentinel = ctx->cqe_cached + len;
-       ctx->cqe_cached++;
-       return &rings->cqes[off << shift];
-}
-
-static inline struct io_uring_cqe *io_get_cqe(struct io_ring_ctx *ctx)
-{
-       if (likely(ctx->cqe_cached < ctx->cqe_sentinel)) {
-               struct io_uring_cqe *cqe = ctx->cqe_cached;
-
-               if (ctx->flags & IORING_SETUP_CQE32) {
-                       unsigned int off = ctx->cqe_cached - ctx->rings->cqes;
-
-                       cqe += off;
-               }
-
-               ctx->cached_cq_tail++;
-               ctx->cqe_cached++;
-               return cqe;
-       }
-
-       return __io_get_cqe(ctx);
-}
-
-static void io_eventfd_signal(struct io_ring_ctx *ctx)
-{
-       struct io_ev_fd *ev_fd;
-
-       rcu_read_lock();
-       /*
-        * rcu_dereference ctx->io_ev_fd once and use it for both for checking
-        * and eventfd_signal
-        */
-       ev_fd = rcu_dereference(ctx->io_ev_fd);
-
-       /*
-        * Check again if ev_fd exists incase an io_eventfd_unregister call
-        * completed between the NULL check of ctx->io_ev_fd at the start of
-        * the function and rcu_read_lock.
-        */
-       if (unlikely(!ev_fd))
-               goto out;
-       if (READ_ONCE(ctx->rings->cq_flags) & IORING_CQ_EVENTFD_DISABLED)
-               goto out;
-
-       if (!ev_fd->eventfd_async || io_wq_current_is_worker())
-               eventfd_signal(ev_fd->cq_ev_fd, 1);
-out:
-       rcu_read_unlock();
-}
-
-static inline void io_cqring_wake(struct io_ring_ctx *ctx)
-{
-       /*
-        * wake_up_all() may seem excessive, but io_wake_function() and
-        * io_should_wake() handle the termination of the loop and only
-        * wake as many waiters as we need to.
-        */
-       if (wq_has_sleeper(&ctx->cq_wait))
-               wake_up_all(&ctx->cq_wait);
-}
-
-/*
- * This should only get called when at least one event has been posted.
- * Some applications rely on the eventfd notification count only changing
- * IFF a new CQE has been added to the CQ ring. There's no depedency on
- * 1:1 relationship between how many times this function is called (and
- * hence the eventfd count) and number of CQEs posted to the CQ ring.
- */
-static inline void io_cqring_ev_posted(struct io_ring_ctx *ctx)
-{
-       if (unlikely(ctx->off_timeout_used || ctx->drain_active ||
-                    ctx->has_evfd))
-               __io_commit_cqring_flush(ctx);
-
-       io_cqring_wake(ctx);
-}
-
-static void io_cqring_ev_posted_iopoll(struct io_ring_ctx *ctx)
-{
-       if (unlikely(ctx->off_timeout_used || ctx->drain_active ||
-                    ctx->has_evfd))
-               __io_commit_cqring_flush(ctx);
-
-       if (ctx->flags & IORING_SETUP_SQPOLL)
-               io_cqring_wake(ctx);
-}
-
-/* Returns true if there are no backlogged entries after the flush */
-static bool __io_cqring_overflow_flush(struct io_ring_ctx *ctx, bool force)
-{
-       bool all_flushed, posted;
-       size_t cqe_size = sizeof(struct io_uring_cqe);
-
-       if (!force && __io_cqring_events(ctx) == ctx->cq_entries)
-               return false;
-
-       if (ctx->flags & IORING_SETUP_CQE32)
-               cqe_size <<= 1;
-
-       posted = false;
-       spin_lock(&ctx->completion_lock);
-       while (!list_empty(&ctx->cq_overflow_list)) {
-               struct io_uring_cqe *cqe = io_get_cqe(ctx);
-               struct io_overflow_cqe *ocqe;
-
-               if (!cqe && !force)
-                       break;
-               ocqe = list_first_entry(&ctx->cq_overflow_list,
-                                       struct io_overflow_cqe, list);
-               if (cqe)
-                       memcpy(cqe, &ocqe->cqe, cqe_size);
-               else
-                       io_account_cq_overflow(ctx);
-
-               posted = true;
-               list_del(&ocqe->list);
-               kfree(ocqe);
-       }
-
-       all_flushed = list_empty(&ctx->cq_overflow_list);
-       if (all_flushed) {
-               clear_bit(IO_CHECK_CQ_OVERFLOW_BIT, &ctx->check_cq);
-               atomic_andnot(IORING_SQ_CQ_OVERFLOW, &ctx->rings->sq_flags);
-       }
-
-       io_commit_cqring(ctx);
-       spin_unlock(&ctx->completion_lock);
-       if (posted)
-               io_cqring_ev_posted(ctx);
-       return all_flushed;
-}
-
-static bool io_cqring_overflow_flush(struct io_ring_ctx *ctx)
-{
-       bool ret = true;
-
-       if (test_bit(IO_CHECK_CQ_OVERFLOW_BIT, &ctx->check_cq)) {
-               /* iopoll syncs against uring_lock, not completion_lock */
-               if (ctx->flags & IORING_SETUP_IOPOLL)
-                       mutex_lock(&ctx->uring_lock);
-               ret = __io_cqring_overflow_flush(ctx, false);
-               if (ctx->flags & IORING_SETUP_IOPOLL)
-                       mutex_unlock(&ctx->uring_lock);
-       }
-
-       return ret;
-}
-
-static void __io_put_task(struct task_struct *task, int nr)
-{
-       struct io_uring_task *tctx = task->io_uring;
-
-       percpu_counter_sub(&tctx->inflight, nr);
-       if (unlikely(atomic_read(&tctx->in_idle)))
-               wake_up(&tctx->wait);
-       put_task_struct_many(task, nr);
-}
-
-/* must to be called somewhat shortly after putting a request */
-static inline void io_put_task(struct task_struct *task, int nr)
-{
-       if (likely(task == current))
-               task->io_uring->cached_refs += nr;
-       else
-               __io_put_task(task, nr);
-}
-
-static void io_task_refs_refill(struct io_uring_task *tctx)
-{
-       unsigned int refill = -tctx->cached_refs + IO_TCTX_REFS_CACHE_NR;
-
-       percpu_counter_add(&tctx->inflight, refill);
-       refcount_add(refill, &current->usage);
-       tctx->cached_refs += refill;
-}
-
-static inline void io_get_task_refs(int nr)
-{
-       struct io_uring_task *tctx = current->io_uring;
-
-       tctx->cached_refs -= nr;
-       if (unlikely(tctx->cached_refs < 0))
-               io_task_refs_refill(tctx);
-}
-
-static __cold void io_uring_drop_tctx_refs(struct task_struct *task)
-{
-       struct io_uring_task *tctx = task->io_uring;
-       unsigned int refs = tctx->cached_refs;
-
-       if (refs) {
-               tctx->cached_refs = 0;
-               percpu_counter_sub(&tctx->inflight, refs);
-               put_task_struct_many(task, refs);
-       }
-}
-
-static bool io_cqring_event_overflow(struct io_ring_ctx *ctx, u64 user_data,
-                                    s32 res, u32 cflags, u64 extra1,
-                                    u64 extra2)
-{
-       struct io_overflow_cqe *ocqe;
-       size_t ocq_size = sizeof(struct io_overflow_cqe);
-       bool is_cqe32 = (ctx->flags & IORING_SETUP_CQE32);
-
-       if (is_cqe32)
-               ocq_size += sizeof(struct io_uring_cqe);
-
-       ocqe = kmalloc(ocq_size, GFP_ATOMIC | __GFP_ACCOUNT);
-       trace_io_uring_cqe_overflow(ctx, user_data, res, cflags, ocqe);
-       if (!ocqe) {
-               /*
-                * If we're in ring overflow flush mode, or in task cancel mode,
-                * or cannot allocate an overflow entry, then we need to drop it
-                * on the floor.
-                */
-               io_account_cq_overflow(ctx);
-               set_bit(IO_CHECK_CQ_DROPPED_BIT, &ctx->check_cq);
-               return false;
-       }
-       if (list_empty(&ctx->cq_overflow_list)) {
-               set_bit(IO_CHECK_CQ_OVERFLOW_BIT, &ctx->check_cq);
-               atomic_or(IORING_SQ_CQ_OVERFLOW, &ctx->rings->sq_flags);
-
-       }
-       ocqe->cqe.user_data = user_data;
-       ocqe->cqe.res = res;
-       ocqe->cqe.flags = cflags;
-       if (is_cqe32) {
-               ocqe->cqe.big_cqe[0] = extra1;
-               ocqe->cqe.big_cqe[1] = extra2;
-       }
-       list_add_tail(&ocqe->list, &ctx->cq_overflow_list);
-       return true;
-}
-
-static inline bool __io_fill_cqe_req(struct io_ring_ctx *ctx,
-                                    struct io_kiocb *req)
-{
-       struct io_uring_cqe *cqe;
-
-       if (!(ctx->flags & IORING_SETUP_CQE32)) {
-               trace_io_uring_complete(req->ctx, req, req->cqe.user_data,
-                                       req->cqe.res, req->cqe.flags, 0, 0);
-
-               /*
-                * If we can't get a cq entry, userspace overflowed the
-                * submission (by quite a lot). Increment the overflow count in
-                * the ring.
-                */
-               cqe = io_get_cqe(ctx);
-               if (likely(cqe)) {
-                       memcpy(cqe, &req->cqe, sizeof(*cqe));
-                       return true;
-               }
-
-               return io_cqring_event_overflow(ctx, req->cqe.user_data,
-                                               req->cqe.res, req->cqe.flags,
-                                               0, 0);
-       } else {
-               u64 extra1 = 0, extra2 = 0;
-
-               if (req->flags & REQ_F_CQE32_INIT) {
-                       extra1 = req->extra1;
-                       extra2 = req->extra2;
-               }
-
-               trace_io_uring_complete(req->ctx, req, req->cqe.user_data,
-                                       req->cqe.res, req->cqe.flags, extra1, extra2);
-
-               /*
-                * If we can't get a cq entry, userspace overflowed the
-                * submission (by quite a lot). Increment the overflow count in
-                * the ring.
-                */
-               cqe = io_get_cqe(ctx);
-               if (likely(cqe)) {
-                       memcpy(cqe, &req->cqe, sizeof(struct io_uring_cqe));
-                       WRITE_ONCE(cqe->big_cqe[0], extra1);
-                       WRITE_ONCE(cqe->big_cqe[1], extra2);
-                       return true;
-               }
-
-               return io_cqring_event_overflow(ctx, req->cqe.user_data,
-                               req->cqe.res, req->cqe.flags,
-                               extra1, extra2);
-       }
-}
-
-static noinline bool io_fill_cqe_aux(struct io_ring_ctx *ctx, u64 user_data,
-                                    s32 res, u32 cflags)
-{
-       struct io_uring_cqe *cqe;
-
-       ctx->cq_extra++;
-       trace_io_uring_complete(ctx, NULL, user_data, res, cflags, 0, 0);
-
-       /*
-        * If we can't get a cq entry, userspace overflowed the
-        * submission (by quite a lot). Increment the overflow count in
-        * the ring.
-        */
-       cqe = io_get_cqe(ctx);
-       if (likely(cqe)) {
-               WRITE_ONCE(cqe->user_data, user_data);
-               WRITE_ONCE(cqe->res, res);
-               WRITE_ONCE(cqe->flags, cflags);
-
-               if (ctx->flags & IORING_SETUP_CQE32) {
-                       WRITE_ONCE(cqe->big_cqe[0], 0);
-                       WRITE_ONCE(cqe->big_cqe[1], 0);
-               }
-               return true;
-       }
-       return io_cqring_event_overflow(ctx, user_data, res, cflags, 0, 0);
-}
-
-static void __io_req_complete_put(struct io_kiocb *req)
-{
-       /*
-        * If we're the last reference to this request, add to our locked
-        * free_list cache.
-        */
-       if (req_ref_put_and_test(req)) {
-               struct io_ring_ctx *ctx = req->ctx;
-
-               if (req->flags & IO_REQ_LINK_FLAGS) {
-                       if (req->flags & IO_DISARM_MASK)
-                               io_disarm_next(req);
-                       if (req->link) {
-                               io_req_task_queue(req->link);
-                               req->link = NULL;
-                       }
-               }
-               io_req_put_rsrc(req);
-               /*
-                * Selected buffer deallocation in io_clean_op() assumes that
-                * we don't hold ->completion_lock. Clean them here to avoid
-                * deadlocks.
-                */
-               io_put_kbuf_comp(req);
-               io_dismantle_req(req);
-               io_put_task(req->task, 1);
-               wq_list_add_head(&req->comp_list, &ctx->locked_free_list);
-               ctx->locked_free_nr++;
-       }
-}
-
-static void __io_req_complete_post(struct io_kiocb *req, s32 res,
-                                  u32 cflags)
-{
-       if (!(req->flags & REQ_F_CQE_SKIP)) {
-               req->cqe.res = res;
-               req->cqe.flags = cflags;
-               __io_fill_cqe_req(req->ctx, req);
-       }
-       __io_req_complete_put(req);
-}
-
-static void io_req_complete_post(struct io_kiocb *req, s32 res, u32 cflags)
-{
-       struct io_ring_ctx *ctx = req->ctx;
-
-       spin_lock(&ctx->completion_lock);
-       __io_req_complete_post(req, res, cflags);
-       io_commit_cqring(ctx);
-       spin_unlock(&ctx->completion_lock);
-       io_cqring_ev_posted(ctx);
-}
-
-static inline void io_req_complete_state(struct io_kiocb *req, s32 res,
-                                        u32 cflags)
-{
-       req->cqe.res = res;
-       req->cqe.flags = cflags;
-       req->flags |= REQ_F_COMPLETE_INLINE;
-}
-
-static inline void __io_req_complete(struct io_kiocb *req, unsigned issue_flags,
-                                    s32 res, u32 cflags)
-{
-       if (issue_flags & IO_URING_F_COMPLETE_DEFER)
-               io_req_complete_state(req, res, cflags);
-       else
-               io_req_complete_post(req, res, cflags);
-}
-
-static inline void io_req_complete(struct io_kiocb *req, s32 res)
-{
-       if (res < 0)
-               req_set_fail(req);
-       __io_req_complete(req, 0, res, 0);
-}
-
-static void io_req_complete_failed(struct io_kiocb *req, s32 res)
-{
-       req_set_fail(req);
-       io_req_complete_post(req, res, io_put_kbuf(req, IO_URING_F_UNLOCKED));
-}
-
-/*
- * Don't initialise the fields below on every allocation, but do that in
- * advance and keep them valid across allocations.
- */
-static void io_preinit_req(struct io_kiocb *req, struct io_ring_ctx *ctx)
-{
-       req->ctx = ctx;
-       req->link = NULL;
-       req->async_data = NULL;
-       /* not necessary, but safer to zero */
-       req->cqe.res = 0;
-}
-
-static void io_flush_cached_locked_reqs(struct io_ring_ctx *ctx,
-                                       struct io_submit_state *state)
-{
-       spin_lock(&ctx->completion_lock);
-       wq_list_splice(&ctx->locked_free_list, &state->free_list);
-       ctx->locked_free_nr = 0;
-       spin_unlock(&ctx->completion_lock);
-}
-
-static inline bool io_req_cache_empty(struct io_ring_ctx *ctx)
-{
-       return !ctx->submit_state.free_list.next;
-}
-
-/*
- * A request might get retired back into the request caches even before opcode
- * handlers and io_issue_sqe() are done with it, e.g. inline completion path.
- * Because of that, io_alloc_req() should be called only under ->uring_lock
- * and with extra caution to not get a request that is still worked on.
- */
-static __cold bool __io_alloc_req_refill(struct io_ring_ctx *ctx)
-       __must_hold(&ctx->uring_lock)
-{
-       gfp_t gfp = GFP_KERNEL | __GFP_NOWARN;
-       void *reqs[IO_REQ_ALLOC_BATCH];
-       int ret, i;
-
-       /*
-        * If we have more than a batch's worth of requests in our IRQ side
-        * locked cache, grab the lock and move them over to our submission
-        * side cache.
-        */
-       if (data_race(ctx->locked_free_nr) > IO_COMPL_BATCH) {
-               io_flush_cached_locked_reqs(ctx, &ctx->submit_state);
-               if (!io_req_cache_empty(ctx))
-                       return true;
-       }
-
-       ret = kmem_cache_alloc_bulk(req_cachep, gfp, ARRAY_SIZE(reqs), reqs);
-
-       /*
-        * Bulk alloc is all-or-nothing. If we fail to get a batch,
-        * retry single alloc to be on the safe side.
-        */
-       if (unlikely(ret <= 0)) {
-               reqs[0] = kmem_cache_alloc(req_cachep, gfp);
-               if (!reqs[0])
-                       return false;
-               ret = 1;
-       }
-
-       percpu_ref_get_many(&ctx->refs, ret);
-       for (i = 0; i < ret; i++) {
-               struct io_kiocb *req = reqs[i];
-
-               io_preinit_req(req, ctx);
-               io_req_add_to_cache(req, ctx);
-       }
-       return true;
-}
-
-static inline bool io_alloc_req_refill(struct io_ring_ctx *ctx)
-{
-       if (unlikely(io_req_cache_empty(ctx)))
-               return __io_alloc_req_refill(ctx);
-       return true;
-}
-
-static inline struct io_kiocb *io_alloc_req(struct io_ring_ctx *ctx)
-{
-       struct io_wq_work_node *node;
-
-       node = wq_stack_extract(&ctx->submit_state.free_list);
-       return container_of(node, struct io_kiocb, comp_list);
-}
-
-static inline void io_put_file(struct file *file)
-{
-       if (file)
-               fput(file);
-}
-
-static inline void io_dismantle_req(struct io_kiocb *req)
-{
-       unsigned int flags = req->flags;
-
-       if (unlikely(flags & IO_REQ_CLEAN_FLAGS))
-               io_clean_op(req);
-       if (!(flags & REQ_F_FIXED_FILE))
-               io_put_file(req->file);
-}
-
-static __cold void io_free_req(struct io_kiocb *req)
-{
-       struct io_ring_ctx *ctx = req->ctx;
-
-       io_req_put_rsrc(req);
-       io_dismantle_req(req);
-       io_put_task(req->task, 1);
-
-       spin_lock(&ctx->completion_lock);
-       wq_list_add_head(&req->comp_list, &ctx->locked_free_list);
-       ctx->locked_free_nr++;
-       spin_unlock(&ctx->completion_lock);
-}
-
-static inline void io_remove_next_linked(struct io_kiocb *req)
-{
-       struct io_kiocb *nxt = req->link;
-
-       req->link = nxt->link;
-       nxt->link = NULL;
-}
-
-static struct io_kiocb *io_disarm_linked_timeout(struct io_kiocb *req)
-       __must_hold(&req->ctx->completion_lock)
-       __must_hold(&req->ctx->timeout_lock)
-{
-       struct io_kiocb *link = req->link;
-
-       if (link && link->opcode == IORING_OP_LINK_TIMEOUT) {
-               struct io_timeout_data *io = link->async_data;
-
-               io_remove_next_linked(req);
-               link->timeout.head = NULL;
-               if (hrtimer_try_to_cancel(&io->timer) != -1) {
-                       list_del(&link->timeout.list);
-                       return link;
-               }
-       }
-       return NULL;
-}
-
-static void io_fail_links(struct io_kiocb *req)
-       __must_hold(&req->ctx->completion_lock)
-{
-       struct io_kiocb *nxt, *link = req->link;
-       bool ignore_cqes = req->flags & REQ_F_SKIP_LINK_CQES;
-
-       req->link = NULL;
-       while (link) {
-               long res = -ECANCELED;
-
-               if (link->flags & REQ_F_FAIL)
-                       res = link->cqe.res;
-
-               nxt = link->link;
-               link->link = NULL;
-
-               trace_io_uring_fail_link(req->ctx, req, req->cqe.user_data,
-                                       req->opcode, link);
-
-               if (ignore_cqes)
-                       link->flags |= REQ_F_CQE_SKIP;
-               else
-                       link->flags &= ~REQ_F_CQE_SKIP;
-               __io_req_complete_post(link, res, 0);
-               link = nxt;
-       }
-}
-
-static bool io_disarm_next(struct io_kiocb *req)
-       __must_hold(&req->ctx->completion_lock)
-{
-       struct io_kiocb *link = NULL;
-       bool posted = false;
-
-       if (req->flags & REQ_F_ARM_LTIMEOUT) {
-               link = req->link;
-               req->flags &= ~REQ_F_ARM_LTIMEOUT;
-               if (link && link->opcode == IORING_OP_LINK_TIMEOUT) {
-                       io_remove_next_linked(req);
-                       io_req_tw_post_queue(link, -ECANCELED, 0);
-                       posted = true;
-               }
-       } else if (req->flags & REQ_F_LINK_TIMEOUT) {
-               struct io_ring_ctx *ctx = req->ctx;
-
-               spin_lock_irq(&ctx->timeout_lock);
-               link = io_disarm_linked_timeout(req);
-               spin_unlock_irq(&ctx->timeout_lock);
-               if (link) {
-                       posted = true;
-                       io_req_tw_post_queue(link, -ECANCELED, 0);
-               }
-       }
-       if (unlikely((req->flags & REQ_F_FAIL) &&
-                    !(req->flags & REQ_F_HARDLINK))) {
-               posted |= (req->link != NULL);
-               io_fail_links(req);
-       }
-       return posted;
-}
-
-static void __io_req_find_next_prep(struct io_kiocb *req)
-{
-       struct io_ring_ctx *ctx = req->ctx;
-       bool posted;
-
-       spin_lock(&ctx->completion_lock);
-       posted = io_disarm_next(req);
-       io_commit_cqring(ctx);
-       spin_unlock(&ctx->completion_lock);
-       if (posted)
-               io_cqring_ev_posted(ctx);
-}
-
-static inline struct io_kiocb *io_req_find_next(struct io_kiocb *req)
-{
-       struct io_kiocb *nxt;
-
-       /*
-        * If LINK is set, we have dependent requests in this chain. If we
-        * didn't fail this request, queue the first one up, moving any other
-        * dependencies to the next request. In case of failure, fail the rest
-        * of the chain.
-        */
-       if (unlikely(req->flags & IO_DISARM_MASK))
-               __io_req_find_next_prep(req);
-       nxt = req->link;
-       req->link = NULL;
-       return nxt;
-}
-
-static void ctx_flush_and_put(struct io_ring_ctx *ctx, bool *locked)
-{
-       if (!ctx)
-               return;
-       if (ctx->flags & IORING_SETUP_TASKRUN_FLAG)
-               atomic_andnot(IORING_SQ_TASKRUN, &ctx->rings->sq_flags);
-       if (*locked) {
-               io_submit_flush_completions(ctx);
-               mutex_unlock(&ctx->uring_lock);
-               *locked = false;
-       }
-       percpu_ref_put(&ctx->refs);
-}
-
-static inline void ctx_commit_and_unlock(struct io_ring_ctx *ctx)
-{
-       io_commit_cqring(ctx);
-       spin_unlock(&ctx->completion_lock);
-       io_cqring_ev_posted(ctx);
-}
-
-static void handle_prev_tw_list(struct io_wq_work_node *node,
-                               struct io_ring_ctx **ctx, bool *uring_locked)
-{
-       if (*ctx && !*uring_locked)
-               spin_lock(&(*ctx)->completion_lock);
-
-       do {
-               struct io_wq_work_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) {
-                       if (unlikely(!*uring_locked && *ctx))
-                               ctx_commit_and_unlock(*ctx);
-
-                       ctx_flush_and_put(*ctx, uring_locked);
-                       *ctx = req->ctx;
-                       /* if not contended, grab and improve batching */
-                       *uring_locked = mutex_trylock(&(*ctx)->uring_lock);
-                       percpu_ref_get(&(*ctx)->refs);
-                       if (unlikely(!*uring_locked))
-                               spin_lock(&(*ctx)->completion_lock);
-               }
-               if (likely(*uring_locked))
-                       req->io_task_work.func(req, uring_locked);
-               else
-                       __io_req_complete_post(req, req->cqe.res,
-                                               io_put_kbuf_comp(req));
-               node = next;
-       } while (node);
-
-       if (unlikely(!*uring_locked))
-               ctx_commit_and_unlock(*ctx);
-}
-
-static void handle_tw_list(struct io_wq_work_node *node,
-                          struct io_ring_ctx **ctx, bool *locked)
-{
-       do {
-               struct io_wq_work_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, locked);
-                       *ctx = req->ctx;
-                       /* if not contended, grab and improve batching */
-                       *locked = mutex_trylock(&(*ctx)->uring_lock);
-                       percpu_ref_get(&(*ctx)->refs);
-               }
-               req->io_task_work.func(req, locked);
-               node = next;
-       } while (node);
-}
-
-static void tctx_task_work(struct callback_head *cb)
-{
-       bool uring_locked = false;
-       struct io_ring_ctx *ctx = NULL;
-       struct io_uring_task *tctx = container_of(cb, struct io_uring_task,
-                                                 task_work);
-
-       while (1) {
-               struct io_wq_work_node *node1, *node2;
-
-               spin_lock_irq(&tctx->task_lock);
-               node1 = tctx->prio_task_list.first;
-               node2 = tctx->task_list.first;
-               INIT_WQ_LIST(&tctx->task_list);
-               INIT_WQ_LIST(&tctx->prio_task_list);
-               if (!node2 && !node1)
-                       tctx->task_running = false;
-               spin_unlock_irq(&tctx->task_lock);
-               if (!node2 && !node1)
-                       break;
-
-               if (node1)
-                       handle_prev_tw_list(node1, &ctx, &uring_locked);
-               if (node2)
-                       handle_tw_list(node2, &ctx, &uring_locked);
-               cond_resched();
-
-               if (data_race(!tctx->task_list.first) &&
-                   data_race(!tctx->prio_task_list.first) && uring_locked)
-                       io_submit_flush_completions(ctx);
-       }
-
-       ctx_flush_and_put(ctx, &uring_locked);
-
-       /* relaxed read is enough as only the task itself sets ->in_idle */
-       if (unlikely(atomic_read(&tctx->in_idle)))
-               io_uring_drop_tctx_refs(current);
-}
-
-static void __io_req_task_work_add(struct io_kiocb *req,
-                                  struct io_uring_task *tctx,
-                                  struct io_wq_work_list *list)
-{
-       struct io_ring_ctx *ctx = req->ctx;
-       struct io_wq_work_node *node;
-       unsigned long flags;
-       bool running;
-
-       spin_lock_irqsave(&tctx->task_lock, flags);
-       wq_list_add_tail(&req->io_task_work.node, list);
-       running = tctx->task_running;
-       if (!running)
-               tctx->task_running = true;
-       spin_unlock_irqrestore(&tctx->task_lock, flags);
-
-       /* task_work already pending, we're done */
-       if (running)
-               return;
-
-       if (ctx->flags & IORING_SETUP_TASKRUN_FLAG)
-               atomic_or(IORING_SQ_TASKRUN, &ctx->rings->sq_flags);
-
-       if (likely(!task_work_add(req->task, &tctx->task_work, ctx->notify_method)))
-               return;
-
-       spin_lock_irqsave(&tctx->task_lock, flags);
-       tctx->task_running = false;
-       node = wq_list_merge(&tctx->prio_task_list, &tctx->task_list);
-       spin_unlock_irqrestore(&tctx->task_lock, flags);
-
-       while (node) {
-               req = container_of(node, struct io_kiocb, io_task_work.node);
-               node = node->next;
-               if (llist_add(&req->io_task_work.fallback_node,
-                             &req->ctx->fallback_llist))
-                       schedule_delayed_work(&req->ctx->fallback_work, 1);
-       }
-}
-
-static void io_req_task_work_add(struct io_kiocb *req)
-{
-       struct io_uring_task *tctx = req->task->io_uring;
-
-       __io_req_task_work_add(req, tctx, &tctx->task_list);
-}
-
-static void io_req_task_prio_work_add(struct io_kiocb *req)
-{
-       struct io_uring_task *tctx = req->task->io_uring;
-
-       if (req->ctx->flags & IORING_SETUP_SQPOLL)
-               __io_req_task_work_add(req, tctx, &tctx->prio_task_list);
-       else
-               __io_req_task_work_add(req, tctx, &tctx->task_list);
-}
-
-static void io_req_tw_post(struct io_kiocb *req, bool *locked)
-{
-       io_req_complete_post(req, req->cqe.res, req->cqe.flags);
-}
-
-static void io_req_tw_post_queue(struct io_kiocb *req, s32 res, u32 cflags)
-{
-       req->cqe.res = res;
-       req->cqe.flags = cflags;
-       req->io_task_work.func = io_req_tw_post;
-       io_req_task_work_add(req);
-}
-
-static void io_req_task_cancel(struct io_kiocb *req, bool *locked)
-{
-       /* not needed for normal modes, but SQPOLL depends on it */
-       io_tw_lock(req->ctx, locked);
-       io_req_complete_failed(req, req->cqe.res);
-}
-
-static void io_req_task_submit(struct io_kiocb *req, bool *locked)
-{
-       io_tw_lock(req->ctx, locked);
-       /* req->task == current here, checking PF_EXITING is safe */
-       if (likely(!(req->task->flags & PF_EXITING)))
-               io_queue_sqe(req);
-       else
-               io_req_complete_failed(req, -EFAULT);
-}
-
-static void io_req_task_queue_fail(struct io_kiocb *req, int ret)
-{
-       req->cqe.res = ret;
-       req->io_task_work.func = io_req_task_cancel;
-       io_req_task_work_add(req);
-}
-
-static void io_req_task_queue(struct io_kiocb *req)
-{
-       req->io_task_work.func = io_req_task_submit;
-       io_req_task_work_add(req);
-}
-
-static void io_req_task_queue_reissue(struct io_kiocb *req)
-{
-       req->io_task_work.func = io_queue_iowq;
-       io_req_task_work_add(req);
-}
-
-static void io_queue_next(struct io_kiocb *req)
-{
-       struct io_kiocb *nxt = io_req_find_next(req);
-
-       if (nxt)
-               io_req_task_queue(nxt);
-}
-
-static void io_free_batch_list(struct io_ring_ctx *ctx,
-                               struct io_wq_work_node *node)
-       __must_hold(&ctx->uring_lock)
-{
-       struct task_struct *task = NULL;
-       int task_refs = 0;
-
-       do {
-               struct io_kiocb *req = container_of(node, struct io_kiocb,
-                                                   comp_list);
-
-               if (unlikely(req->flags & IO_REQ_CLEAN_SLOW_FLAGS)) {
-                       if (req->flags & REQ_F_REFCOUNT) {
-                               node = req->comp_list.next;
-                               if (!req_ref_put_and_test(req))
-                                       continue;
-                       }
-                       if ((req->flags & REQ_F_POLLED) && req->apoll) {
-                               struct async_poll *apoll = req->apoll;
-
-                               if (apoll->double_poll)
-                                       kfree(apoll->double_poll);
-                               list_add(&apoll->poll.wait.entry,
-                                               &ctx->apoll_cache);
-                               req->flags &= ~REQ_F_POLLED;
-                       }
-                       if (req->flags & IO_REQ_LINK_FLAGS)
-                               io_queue_next(req);
-                       if (unlikely(req->flags & IO_REQ_CLEAN_FLAGS))
-                               io_clean_op(req);
-               }
-               if (!(req->flags & REQ_F_FIXED_FILE))
-                       io_put_file(req->file);
-
-               io_req_put_rsrc_locked(req, ctx);
-
-               if (req->task != task) {
-                       if (task)
-                               io_put_task(task, task_refs);
-                       task = req->task;
-                       task_refs = 0;
-               }
-               task_refs++;
-               node = req->comp_list.next;
-               io_req_add_to_cache(req, ctx);
-       } while (node);
-
-       if (task)
-               io_put_task(task, task_refs);
-}
-
-static void __io_submit_flush_completions(struct io_ring_ctx *ctx)
-       __must_hold(&ctx->uring_lock)
-{
-       struct io_wq_work_node *node, *prev;
-       struct io_submit_state *state = &ctx->submit_state;
-
-       if (state->flush_cqes) {
-               spin_lock(&ctx->completion_lock);
-               wq_list_for_each(node, prev, &state->compl_reqs) {
-                       struct io_kiocb *req = container_of(node, struct io_kiocb,
-                                                   comp_list);
-
-                       if (!(req->flags & REQ_F_CQE_SKIP))
-                               __io_fill_cqe_req(ctx, req);
-               }
-
-               io_commit_cqring(ctx);
-               spin_unlock(&ctx->completion_lock);
-               io_cqring_ev_posted(ctx);
-               state->flush_cqes = false;
-       }
-
-       io_free_batch_list(ctx, state->compl_reqs.first);
-       INIT_WQ_LIST(&state->compl_reqs);
-}
-
-/*
- * Drop reference to request, return next in chain (if there is one) if this
- * was the last reference to this request.
- */
-static inline struct io_kiocb *io_put_req_find_next(struct io_kiocb *req)
-{
-       struct io_kiocb *nxt = NULL;
-
-       if (req_ref_put_and_test(req)) {
-               if (unlikely(req->flags & IO_REQ_LINK_FLAGS))
-                       nxt = io_req_find_next(req);
-               io_free_req(req);
-       }
-       return nxt;
-}
-
-static inline void io_put_req(struct io_kiocb *req)
-{
-       if (req_ref_put_and_test(req)) {
-               io_queue_next(req);
-               io_free_req(req);
-       }
-}
-
-static unsigned io_cqring_events(struct io_ring_ctx *ctx)
-{
-       /* See comment at the top of this file */
-       smp_rmb();
-       return __io_cqring_events(ctx);
-}
-
-static inline unsigned int io_sqring_entries(struct io_ring_ctx *ctx)
-{
-       struct io_rings *rings = ctx->rings;
-
-       /* make sure SQ entry isn't read before tail */
-       return smp_load_acquire(&rings->sq.tail) - ctx->cached_sq_head;
-}
-
-static inline bool io_run_task_work(void)
-{
-       if (test_thread_flag(TIF_NOTIFY_SIGNAL) || task_work_pending(current)) {
-               __set_current_state(TASK_RUNNING);
-               clear_notify_signal();
-               if (task_work_pending(current))
-                       task_work_run();
-               return true;
-       }
-
-       return false;
-}
-
-static int io_do_iopoll(struct io_ring_ctx *ctx, bool force_nonspin)
-{
-       struct io_wq_work_node *pos, *start, *prev;
-       unsigned int poll_flags = BLK_POLL_NOSLEEP;
-       DEFINE_IO_COMP_BATCH(iob);
-       int nr_events = 0;
-
-       /*
-        * Only spin for completions if we don't have multiple devices hanging
-        * off our complete list.
-        */
-       if (ctx->poll_multi_queue || force_nonspin)
-               poll_flags |= BLK_POLL_ONESHOT;
-
-       wq_list_for_each(pos, start, &ctx->iopoll_list) {
-               struct io_kiocb *req = container_of(pos, struct io_kiocb, comp_list);
-               struct kiocb *kiocb = &req->rw.kiocb;
-               int ret;
-
-               /*
-                * Move completed and retryable entries to our local lists.
-                * If we find a request that requires polling, break out
-                * and complete those lists first, if we have entries there.
-                */
-               if (READ_ONCE(req->iopoll_completed))
-                       break;
-
-               ret = kiocb->ki_filp->f_op->iopoll(kiocb, &iob, poll_flags);
-               if (unlikely(ret < 0))
-                       return ret;
-               else if (ret)
-                       poll_flags |= BLK_POLL_ONESHOT;
-
-               /* iopoll may have completed current req */
-               if (!rq_list_empty(iob.req_list) ||
-                   READ_ONCE(req->iopoll_completed))
-                       break;
-       }
-
-       if (!rq_list_empty(iob.req_list))
-               iob.complete(&iob);
-       else if (!pos)
-               return 0;
-
-       prev = start;
-       wq_list_for_each_resume(pos, prev) {
-               struct io_kiocb *req = container_of(pos, struct io_kiocb, comp_list);
-
-               /* order with io_complete_rw_iopoll(), e.g. ->result updates */
-               if (!smp_load_acquire(&req->iopoll_completed))
-                       break;
-               nr_events++;
-               if (unlikely(req->flags & REQ_F_CQE_SKIP))
-                       continue;
-
-               req->cqe.flags = io_put_kbuf(req, 0);
-               __io_fill_cqe_req(req->ctx, req);
-       }
-
-       if (unlikely(!nr_events))
-               return 0;
-
-       io_commit_cqring(ctx);
-       io_cqring_ev_posted_iopoll(ctx);
-       pos = start ? start->next : ctx->iopoll_list.first;
-       wq_list_cut(&ctx->iopoll_list, prev, start);
-       io_free_batch_list(ctx, pos);
-       return nr_events;
-}
-
-/*
- * We can't just wait for polled events to come to us, we have to actively
- * find and complete them.
- */
-static __cold void io_iopoll_try_reap_events(struct io_ring_ctx *ctx)
-{
-       if (!(ctx->flags & IORING_SETUP_IOPOLL))
-               return;
-
-       mutex_lock(&ctx->uring_lock);
-       while (!wq_list_empty(&ctx->iopoll_list)) {
-               /* let it sleep and repeat later if can't complete a request */
-               if (io_do_iopoll(ctx, true) == 0)
-                       break;
-               /*
-                * Ensure we allow local-to-the-cpu processing to take place,
-                * in this case we need to ensure that we reap all events.
-                * Also let task_work, etc. to progress by releasing the mutex
-                */
-               if (need_resched()) {
-                       mutex_unlock(&ctx->uring_lock);
-                       cond_resched();
-                       mutex_lock(&ctx->uring_lock);
-               }
-       }
-       mutex_unlock(&ctx->uring_lock);
-}
-
-static int io_iopoll_check(struct io_ring_ctx *ctx, long min)
-{
-       unsigned int nr_events = 0;
-       int ret = 0;
-       unsigned long check_cq;
-
-       /*
-        * Don't enter poll loop if we already have events pending.
-        * If we do, we can potentially be spinning for commands that
-        * already triggered a CQE (eg in error).
-        */
-       check_cq = READ_ONCE(ctx->check_cq);
-       if (check_cq & BIT(IO_CHECK_CQ_OVERFLOW_BIT))
-               __io_cqring_overflow_flush(ctx, false);
-       if (io_cqring_events(ctx))
-               return 0;
-
-       /*
-        * Similarly do not spin if we have not informed the user of any
-        * dropped CQE.
-        */
-       if (unlikely(check_cq & BIT(IO_CHECK_CQ_DROPPED_BIT)))
-               return -EBADR;
-
-       do {
-               /*
-                * If a submit got punted to a workqueue, we can have the
-                * application entering polling for a command before it gets
-                * issued. That app will hold the uring_lock for the duration
-                * of the poll right here, so we need to take a breather every
-                * now and then to ensure that the issue has a chance to add
-                * the poll to the issued list. Otherwise we can spin here
-                * forever, while the workqueue is stuck trying to acquire the
-                * very same mutex.
-                */
-               if (wq_list_empty(&ctx->iopoll_list)) {
-                       u32 tail = ctx->cached_cq_tail;
-
-                       mutex_unlock(&ctx->uring_lock);
-                       io_run_task_work();
-                       mutex_lock(&ctx->uring_lock);
-
-                       /* some requests don't go through iopoll_list */
-                       if (tail != ctx->cached_cq_tail ||
-                           wq_list_empty(&ctx->iopoll_list))
-                               break;
-               }
-               ret = io_do_iopoll(ctx, !min);
-               if (ret < 0)
-                       break;
-               nr_events += ret;
-               ret = 0;
-       } while (nr_events < min && !need_resched());
-
-       return ret;
-}
-
-static void kiocb_end_write(struct io_kiocb *req)
-{
-       /*
-        * Tell lockdep we inherited freeze protection from submission
-        * thread.
-        */
-       if (req->flags & REQ_F_ISREG) {
-               struct super_block *sb = file_inode(req->file)->i_sb;
-
-               __sb_writers_acquired(sb, SB_FREEZE_WRITE);
-               sb_end_write(sb);
-       }
-}
-
-#ifdef CONFIG_BLOCK
-static bool io_resubmit_prep(struct io_kiocb *req)
-{
-       struct io_async_rw *rw = req->async_data;
-
-       if (!req_has_async_data(req))
-               return !io_req_prep_async(req);
-       iov_iter_restore(&rw->s.iter, &rw->s.iter_state);
-       return true;
-}
-
-static bool io_rw_should_reissue(struct io_kiocb *req)
-{
-       umode_t mode = file_inode(req->file)->i_mode;
-       struct io_ring_ctx *ctx = req->ctx;
-
-       if (!S_ISBLK(mode) && !S_ISREG(mode))
-               return false;
-       if ((req->flags & REQ_F_NOWAIT) || (io_wq_current_is_worker() &&
-           !(ctx->flags & IORING_SETUP_IOPOLL)))
-               return false;
-       /*
-        * If ref is dying, we might be running poll reap from the exit work.
-        * Don't attempt to reissue from that path, just let it fail with
-        * -EAGAIN.
-        */
-       if (percpu_ref_is_dying(&ctx->refs))
-               return false;
-       /*
-        * Play it safe and assume not safe to re-import and reissue if we're
-        * not in the original thread group (or in task context).
-        */
-       if (!same_thread_group(req->task, current) || !in_task())
-               return false;
-       return true;
-}
-#else
-static bool io_resubmit_prep(struct io_kiocb *req)
-{
-       return false;
-}
-static bool io_rw_should_reissue(struct io_kiocb *req)
-{
-       return false;
-}
-#endif
-
-static bool __io_complete_rw_common(struct io_kiocb *req, long res)
-{
-       if (req->rw.kiocb.ki_flags & IOCB_WRITE) {
-               kiocb_end_write(req);
-               fsnotify_modify(req->file);
-       } else {
-               fsnotify_access(req->file);
-       }
-       if (unlikely(res != req->cqe.res)) {
-               if ((res == -EAGAIN || res == -EOPNOTSUPP) &&
-                   io_rw_should_reissue(req)) {
-                       req->flags |= REQ_F_REISSUE | REQ_F_PARTIAL_IO;
-                       return true;
-               }
-               req_set_fail(req);
-               req->cqe.res = res;
-       }
-       return false;
-}
-
-static inline void io_req_task_complete(struct io_kiocb *req, bool *locked)
-{
-       int res = req->cqe.res;
-
-       if (*locked) {
-               io_req_complete_state(req, res, io_put_kbuf(req, 0));
-               io_req_add_compl_list(req);
-       } else {
-               io_req_complete_post(req, res,
-                                       io_put_kbuf(req, IO_URING_F_UNLOCKED));
-       }
-}
-
-static void __io_complete_rw(struct io_kiocb *req, long res,
-                            unsigned int issue_flags)
-{
-       if (__io_complete_rw_common(req, res))
-               return;
-       __io_req_complete(req, issue_flags, req->cqe.res,
-                               io_put_kbuf(req, issue_flags));
-}
-
-static void io_complete_rw(struct kiocb *kiocb, long res)
-{
-       struct io_kiocb *req = container_of(kiocb, struct io_kiocb, rw.kiocb);
-
-       if (__io_complete_rw_common(req, res))
-               return;
-       req->cqe.res = res;
-       req->io_task_work.func = io_req_task_complete;
-       io_req_task_prio_work_add(req);
-}
-
-static void io_complete_rw_iopoll(struct kiocb *kiocb, long res)
-{
-       struct io_kiocb *req = container_of(kiocb, struct io_kiocb, rw.kiocb);
-
-       if (kiocb->ki_flags & IOCB_WRITE)
-               kiocb_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;
-                       return;
-               }
-               req->cqe.res = res;
-       }
-
-       /* order with io_iopoll_complete() checking ->iopoll_completed */
-       smp_store_release(&req->iopoll_completed, 1);
-}
-
-/*
- * After the iocb has been issued, it's safe to be found on the poll list.
- * Adding the kiocb to the list AFTER submission ensures that we don't
- * find it from a io_do_iopoll() thread before the issuer is done
- * accessing the kiocb cookie.
- */
-static void io_iopoll_req_issued(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_ring_ctx *ctx = req->ctx;
-       const bool needs_lock = issue_flags & IO_URING_F_UNLOCKED;
-
-       /* workqueue context doesn't hold uring_lock, grab it now */
-       if (unlikely(needs_lock))
-               mutex_lock(&ctx->uring_lock);
-
-       /*
-        * Track whether we have multiple files in our lists. This will impact
-        * how we do polling eventually, not spinning if we're on potentially
-        * different devices.
-        */
-       if (wq_list_empty(&ctx->iopoll_list)) {
-               ctx->poll_multi_queue = false;
-       } else if (!ctx->poll_multi_queue) {
-               struct io_kiocb *list_req;
-
-               list_req = container_of(ctx->iopoll_list.first, struct io_kiocb,
-                                       comp_list);
-               if (list_req->file != req->file)
-                       ctx->poll_multi_queue = true;
-       }
-
-       /*
-        * For fast devices, IO may have already completed. If it has, add
-        * it to the front so we find it first.
-        */
-       if (READ_ONCE(req->iopoll_completed))
-               wq_list_add_head(&req->comp_list, &ctx->iopoll_list);
-       else
-               wq_list_add_tail(&req->comp_list, &ctx->iopoll_list);
-
-       if (unlikely(needs_lock)) {
-               /*
-                * If IORING_SETUP_SQPOLL is enabled, sqes are either handle
-                * in sq thread task context or in io worker task context. If
-                * current task context is sq thread, we don't need to check
-                * whether should wake up sq thread.
-                */
-               if ((ctx->flags & IORING_SETUP_SQPOLL) &&
-                   wq_has_sleeper(&ctx->sq_data->wait))
-                       wake_up(&ctx->sq_data->wait);
-
-               mutex_unlock(&ctx->uring_lock);
-       }
-}
-
-static bool io_bdev_nowait(struct block_device *bdev)
-{
-       return !bdev || blk_queue_nowait(bdev_get_queue(bdev));
-}
-
-/*
- * If we tracked the file through the SCM inflight mechanism, we could support
- * any file. For now, just ensure that anything potentially problematic is done
- * inline.
- */
-static bool __io_file_supports_nowait(struct file *file, umode_t mode)
-{
-       if (S_ISBLK(mode)) {
-               if (IS_ENABLED(CONFIG_BLOCK) &&
-                   io_bdev_nowait(I_BDEV(file->f_mapping->host)))
-                       return true;
-               return false;
-       }
-       if (S_ISSOCK(mode))
-               return true;
-       if (S_ISREG(mode)) {
-               if (IS_ENABLED(CONFIG_BLOCK) &&
-                   io_bdev_nowait(file->f_inode->i_sb->s_bdev) &&
-                   file->f_op != &io_uring_fops)
-                       return true;
-               return false;
-       }
-
-       /* any ->read/write should understand O_NONBLOCK */
-       if (file->f_flags & O_NONBLOCK)
-               return true;
-       return file->f_mode & FMODE_NOWAIT;
-}
-
-/*
- * If we tracked the file through the SCM inflight mechanism, we could support
- * any file. For now, just ensure that anything potentially problematic is done
- * inline.
- */
-static unsigned int io_file_get_flags(struct file *file)
-{
-       umode_t mode = file_inode(file)->i_mode;
-       unsigned int res = 0;
-
-       if (S_ISREG(mode))
-               res |= FFS_ISREG;
-       if (__io_file_supports_nowait(file, mode))
-               res |= FFS_NOWAIT;
-       if (io_file_need_scm(file))
-               res |= FFS_SCM;
-       return res;
-}
-
-static inline bool io_file_supports_nowait(struct io_kiocb *req)
-{
-       return req->flags & REQ_F_SUPPORT_NOWAIT;
-}
-
-static int io_prep_rw(struct io_kiocb *req, const struct io_uring_sqe *sqe)
-{
-       struct kiocb *kiocb = &req->rw.kiocb;
-       unsigned ioprio;
-       int ret;
-
-       kiocb->ki_pos = READ_ONCE(sqe->off);
-       /* used for fixed read/write too - just read unconditionally */
-       req->buf_index = READ_ONCE(sqe->buf_index);
-
-       if (req->opcode == IORING_OP_READ_FIXED ||
-           req->opcode == IORING_OP_WRITE_FIXED) {
-               struct io_ring_ctx *ctx = req->ctx;
-               u16 index;
-
-               if (unlikely(req->buf_index >= ctx->nr_user_bufs))
-                       return -EFAULT;
-               index = array_index_nospec(req->buf_index, ctx->nr_user_bufs);
-               req->imu = ctx->user_bufs[index];
-               io_req_set_rsrc_node(req, ctx, 0);
-       }
-
-       ioprio = READ_ONCE(sqe->ioprio);
-       if (ioprio) {
-               ret = ioprio_check_cap(ioprio);
-               if (ret)
-                       return ret;
-
-               kiocb->ki_ioprio = ioprio;
-       } else {
-               kiocb->ki_ioprio = get_current_ioprio();
-       }
-
-       req->rw.addr = READ_ONCE(sqe->addr);
-       req->rw.len = READ_ONCE(sqe->len);
-       req->rw.flags = READ_ONCE(sqe->rw_flags);
-       return 0;
-}
-
-static inline void io_rw_done(struct kiocb *kiocb, ssize_t ret)
-{
-       switch (ret) {
-       case -EIOCBQUEUED:
-               break;
-       case -ERESTARTSYS:
-       case -ERESTARTNOINTR:
-       case -ERESTARTNOHAND:
-       case -ERESTART_RESTARTBLOCK:
-               /*
-                * We can't just restart the syscall, since previously
-                * submitted sqes may already be in progress. Just fail this
-                * IO with EINTR.
-                */
-               ret = -EINTR;
-               fallthrough;
-       default:
-               kiocb->ki_complete(kiocb, ret);
-       }
-}
-
-static inline loff_t *io_kiocb_update_pos(struct io_kiocb *req)
-{
-       struct kiocb *kiocb = &req->rw.kiocb;
-
-       if (kiocb->ki_pos != -1)
-               return &kiocb->ki_pos;
-
-       if (!(req->file->f_mode & FMODE_STREAM)) {
-               req->flags |= REQ_F_CUR_POS;
-               kiocb->ki_pos = req->file->f_pos;
-               return &kiocb->ki_pos;
-       }
-
-       kiocb->ki_pos = 0;
-       return NULL;
-}
-
-static void kiocb_done(struct io_kiocb *req, ssize_t ret,
-                      unsigned int issue_flags)
-{
-       struct io_async_rw *io = req->async_data;
-
-       /* add previously done IO, if any */
-       if (req_has_async_data(req) && io->bytes_done > 0) {
-               if (ret < 0)
-                       ret = io->bytes_done;
-               else
-                       ret += io->bytes_done;
-       }
-
-       if (req->flags & REQ_F_CUR_POS)
-               req->file->f_pos = req->rw.kiocb.ki_pos;
-       if (ret >= 0 && (req->rw.kiocb.ki_complete == io_complete_rw))
-               __io_complete_rw(req, ret, issue_flags);
-       else
-               io_rw_done(&req->rw.kiocb, ret);
-
-       if (req->flags & REQ_F_REISSUE) {
-               req->flags &= ~REQ_F_REISSUE;
-               if (io_resubmit_prep(req))
-                       io_req_task_queue_reissue(req);
-               else
-                       io_req_task_queue_fail(req, ret);
-       }
-}
-
-static int __io_import_fixed(struct io_kiocb *req, int rw, struct iov_iter *iter,
-                            struct io_mapped_ubuf *imu)
-{
-       size_t len = req->rw.len;
-       u64 buf_end, buf_addr = req->rw.addr;
-       size_t offset;
-
-       if (unlikely(check_add_overflow(buf_addr, (u64)len, &buf_end)))
-               return -EFAULT;
-       /* not inside the mapped region */
-       if (unlikely(buf_addr < imu->ubuf || buf_end > imu->ubuf_end))
-               return -EFAULT;
-
-       /*
-        * May not be a start of buffer, set size appropriately
-        * and advance us to the beginning.
-        */
-       offset = buf_addr - imu->ubuf;
-       iov_iter_bvec(iter, rw, imu->bvec, imu->nr_bvecs, offset + len);
-
-       if (offset) {
-               /*
-                * Don't use iov_iter_advance() here, as it's really slow for
-                * using the latter parts of a big fixed buffer - it iterates
-                * over each segment manually. We can cheat a bit here, because
-                * we know that:
-                *
-                * 1) it's a BVEC iter, we set it up
-                * 2) all bvecs are PAGE_SIZE in size, except potentially the
-                *    first and last bvec
-                *
-                * So just find our index, and adjust the iterator afterwards.
-                * If the offset is within the first bvec (or the whole first
-                * bvec, just use iov_iter_advance(). This makes it easier
-                * since we can just skip the first segment, which may not
-                * be PAGE_SIZE aligned.
-                */
-               const struct bio_vec *bvec = imu->bvec;
-
-               if (offset <= bvec->bv_len) {
-                       iov_iter_advance(iter, offset);
-               } else {
-                       unsigned long seg_skip;
-
-                       /* skip first vec */
-                       offset -= bvec->bv_len;
-                       seg_skip = 1 + (offset >> PAGE_SHIFT);
-
-                       iter->bvec = bvec + seg_skip;
-                       iter->nr_segs -= seg_skip;
-                       iter->count -= bvec->bv_len + offset;
-                       iter->iov_offset = offset & ~PAGE_MASK;
-               }
-       }
-
-       return 0;
-}
-
-static int io_import_fixed(struct io_kiocb *req, int rw, struct iov_iter *iter,
-                          unsigned int issue_flags)
-{
-       if (WARN_ON_ONCE(!req->imu))
-               return -EFAULT;
-       return __io_import_fixed(req, rw, iter, req->imu);
-}
-
-static int io_buffer_add_list(struct io_ring_ctx *ctx,
-                             struct io_buffer_list *bl, unsigned int bgid)
-{
-       bl->bgid = bgid;
-       if (bgid < BGID_ARRAY)
-               return 0;
-
-       return xa_err(xa_store(&ctx->io_bl_xa, bgid, bl, GFP_KERNEL));
-}
-
-static void __user *io_provided_buffer_select(struct io_kiocb *req, size_t *len,
-                                             struct io_buffer_list *bl)
-{
-       if (!list_empty(&bl->buf_list)) {
-               struct io_buffer *kbuf;
-
-               kbuf = list_first_entry(&bl->buf_list, struct io_buffer, list);
-               list_del(&kbuf->list);
-               if (*len > kbuf->len)
-                       *len = kbuf->len;
-               req->flags |= REQ_F_BUFFER_SELECTED;
-               req->kbuf = kbuf;
-               req->buf_index = kbuf->bid;
-               return u64_to_user_ptr(kbuf->addr);
-       }
-       return NULL;
-}
-
-static void __user *io_ring_buffer_select(struct io_kiocb *req, size_t *len,
-                                         struct io_buffer_list *bl,
-                                         unsigned int issue_flags)
-{
-       struct io_uring_buf_ring *br = bl->buf_ring;
-       struct io_uring_buf *buf;
-       __u16 head = bl->head;
-
-       if (unlikely(smp_load_acquire(&br->tail) == head))
-               return NULL;
-
-       head &= bl->mask;
-       if (head < IO_BUFFER_LIST_BUF_PER_PAGE) {
-               buf = &br->bufs[head];
-       } else {
-               int off = head & (IO_BUFFER_LIST_BUF_PER_PAGE - 1);
-               int index = head / IO_BUFFER_LIST_BUF_PER_PAGE;
-               buf = page_address(bl->buf_pages[index]);
-               buf += off;
-       }
-       if (*len > buf->len)
-               *len = buf->len;
-       req->flags |= REQ_F_BUFFER_RING;
-       req->buf_list = bl;
-       req->buf_index = buf->bid;
-
-       if (issue_flags & IO_URING_F_UNLOCKED || !file_can_poll(req->file)) {
-               /*
-                * If we came in unlocked, we have no choice but to consume the
-                * buffer here. This does mean it'll be pinned until the IO
-                * completes. But coming in unlocked means we're in io-wq
-                * context, hence there should be no further retry. For the
-                * locked case, the caller must ensure to call the commit when
-                * the transfer completes (or if we get -EAGAIN and must poll
-                * or retry).
-                */
-               req->buf_list = NULL;
-               bl->head++;
-       }
-       return u64_to_user_ptr(buf->addr);
-}
-
-static void __user *io_buffer_select(struct io_kiocb *req, size_t *len,
-                                    unsigned int issue_flags)
-{
-       struct io_ring_ctx *ctx = req->ctx;
-       struct io_buffer_list *bl;
-       void __user *ret = NULL;
-
-       io_ring_submit_lock(req->ctx, issue_flags);
-
-       bl = io_buffer_get_list(ctx, req->buf_index);
-       if (likely(bl)) {
-               if (bl->buf_nr_pages)
-                       ret = io_ring_buffer_select(req, len, bl, issue_flags);
-               else
-                       ret = io_provided_buffer_select(req, len, bl);
-       }
-       io_ring_submit_unlock(req->ctx, issue_flags);
-       return ret;
-}
-
-#ifdef CONFIG_COMPAT
-static ssize_t io_compat_import(struct io_kiocb *req, struct iovec *iov,
-                               unsigned int issue_flags)
-{
-       struct compat_iovec __user *uiov;
-       compat_ssize_t clen;
-       void __user *buf;
-       size_t len;
-
-       uiov = u64_to_user_ptr(req->rw.addr);
-       if (!access_ok(uiov, sizeof(*uiov)))
-               return -EFAULT;
-       if (__get_user(clen, &uiov->iov_len))
-               return -EFAULT;
-       if (clen < 0)
-               return -EINVAL;
-
-       len = clen;
-       buf = io_buffer_select(req, &len, issue_flags);
-       if (!buf)
-               return -ENOBUFS;
-       req->rw.addr = (unsigned long) buf;
-       iov[0].iov_base = buf;
-       req->rw.len = iov[0].iov_len = (compat_size_t) len;
-       return 0;
-}
-#endif
-
-static ssize_t __io_iov_buffer_select(struct io_kiocb *req, struct iovec *iov,
-                                     unsigned int issue_flags)
-{
-       struct iovec __user *uiov = u64_to_user_ptr(req->rw.addr);
-       void __user *buf;
-       ssize_t len;
-
-       if (copy_from_user(iov, uiov, sizeof(*uiov)))
-               return -EFAULT;
-
-       len = iov[0].iov_len;
-       if (len < 0)
-               return -EINVAL;
-       buf = io_buffer_select(req, &len, issue_flags);
-       if (!buf)
-               return -ENOBUFS;
-       req->rw.addr = (unsigned long) buf;
-       iov[0].iov_base = buf;
-       req->rw.len = iov[0].iov_len = len;
-       return 0;
-}
-
-static ssize_t io_iov_buffer_select(struct io_kiocb *req, struct iovec *iov,
-                                   unsigned int issue_flags)
-{
-       if (req->flags & (REQ_F_BUFFER_SELECTED|REQ_F_BUFFER_RING)) {
-               iov[0].iov_base = u64_to_user_ptr(req->rw.addr);
-               iov[0].iov_len = req->rw.len;
-               return 0;
-       }
-       if (req->rw.len != 1)
-               return -EINVAL;
-
-#ifdef CONFIG_COMPAT
-       if (req->ctx->compat)
-               return io_compat_import(req, iov, issue_flags);
-#endif
-
-       return __io_iov_buffer_select(req, iov, issue_flags);
-}
-
-static inline bool io_do_buffer_select(struct io_kiocb *req)
-{
-       if (!(req->flags & REQ_F_BUFFER_SELECT))
-               return false;
-       return !(req->flags & (REQ_F_BUFFER_SELECTED|REQ_F_BUFFER_RING));
-}
-
-static struct iovec *__io_import_iovec(int rw, struct io_kiocb *req,
-                                      struct io_rw_state *s,
-                                      unsigned int issue_flags)
-{
-       struct iov_iter *iter = &s->iter;
-       u8 opcode = req->opcode;
-       struct iovec *iovec;
-       void __user *buf;
-       size_t sqe_len;
-       ssize_t ret;
-
-       if (opcode == IORING_OP_READ_FIXED || opcode == IORING_OP_WRITE_FIXED) {
-               ret = io_import_fixed(req, rw, iter, issue_flags);
-               if (ret)
-                       return ERR_PTR(ret);
-               return NULL;
-       }
-
-       buf = u64_to_user_ptr(req->rw.addr);
-       sqe_len = req->rw.len;
-
-       if (opcode == IORING_OP_READ || opcode == IORING_OP_WRITE) {
-               if (io_do_buffer_select(req)) {
-                       buf = io_buffer_select(req, &sqe_len, issue_flags);
-                       if (!buf)
-                               return ERR_PTR(-ENOBUFS);
-                       req->rw.addr = (unsigned long) buf;
-                       req->rw.len = sqe_len;
-               }
-
-               ret = import_single_range(rw, buf, sqe_len, s->fast_iov, iter);
-               if (ret)
-                       return ERR_PTR(ret);
-               return NULL;
-       }
-
-       iovec = s->fast_iov;
-       if (req->flags & REQ_F_BUFFER_SELECT) {
-               ret = io_iov_buffer_select(req, iovec, issue_flags);
-               if (ret)
-                       return ERR_PTR(ret);
-               iov_iter_init(iter, rw, iovec, 1, iovec->iov_len);
-               return NULL;
-       }
-
-       ret = __import_iovec(rw, buf, sqe_len, UIO_FASTIOV, &iovec, iter,
-                             req->ctx->compat);
-       if (unlikely(ret < 0))
-               return ERR_PTR(ret);
-       return iovec;
-}
-
-static inline int io_import_iovec(int rw, struct io_kiocb *req,
-                                 struct iovec **iovec, struct io_rw_state *s,
-                                 unsigned int issue_flags)
-{
-       *iovec = __io_import_iovec(rw, req, s, issue_flags);
-       if (unlikely(IS_ERR(*iovec)))
-               return PTR_ERR(*iovec);
-
-       iov_iter_save_state(&s->iter, &s->iter_state);
-       return 0;
-}
-
-static inline loff_t *io_kiocb_ppos(struct kiocb *kiocb)
-{
-       return (kiocb->ki_filp->f_mode & FMODE_STREAM) ? NULL : &kiocb->ki_pos;
-}
-
-/*
- * For files that don't have ->read_iter() and ->write_iter(), handle them
- * by looping over ->read() or ->write() manually.
- */
-static ssize_t loop_rw_iter(int rw, struct io_kiocb *req, struct iov_iter *iter)
-{
-       struct kiocb *kiocb = &req->rw.kiocb;
-       struct file *file = req->file;
-       ssize_t ret = 0;
-       loff_t *ppos;
-
-       /*
-        * Don't support polled IO through this interface, and we can't
-        * support non-blocking either. For the latter, this just causes
-        * the kiocb to be handled from an async context.
-        */
-       if (kiocb->ki_flags & IOCB_HIPRI)
-               return -EOPNOTSUPP;
-       if ((kiocb->ki_flags & IOCB_NOWAIT) &&
-           !(kiocb->ki_filp->f_flags & O_NONBLOCK))
-               return -EAGAIN;
-
-       ppos = io_kiocb_ppos(kiocb);
-
-       while (iov_iter_count(iter)) {
-               struct iovec iovec;
-               ssize_t nr;
-
-               if (!iov_iter_is_bvec(iter)) {
-                       iovec = iov_iter_iovec(iter);
-               } else {
-                       iovec.iov_base = u64_to_user_ptr(req->rw.addr);
-                       iovec.iov_len = req->rw.len;
-               }
-
-               if (rw == READ) {
-                       nr = file->f_op->read(file, iovec.iov_base,
-                                             iovec.iov_len, ppos);
-               } else {
-                       nr = file->f_op->write(file, iovec.iov_base,
-                                              iovec.iov_len, ppos);
-               }
-
-               if (nr < 0) {
-                       if (!ret)
-                               ret = nr;
-                       break;
-               }
-               ret += nr;
-               if (!iov_iter_is_bvec(iter)) {
-                       iov_iter_advance(iter, nr);
-               } else {
-                       req->rw.addr += nr;
-                       req->rw.len -= nr;
-                       if (!req->rw.len)
-                               break;
-               }
-               if (nr != iovec.iov_len)
-                       break;
-       }
-
-       return ret;
-}
-
-static void io_req_map_rw(struct io_kiocb *req, const struct iovec *iovec,
-                         const struct iovec *fast_iov, struct iov_iter *iter)
-{
-       struct io_async_rw *rw = req->async_data;
-
-       memcpy(&rw->s.iter, iter, sizeof(*iter));
-       rw->free_iovec = iovec;
-       rw->bytes_done = 0;
-       /* can only be fixed buffers, no need to do anything */
-       if (iov_iter_is_bvec(iter))
-               return;
-       if (!iovec) {
-               unsigned iov_off = 0;
-
-               rw->s.iter.iov = rw->s.fast_iov;
-               if (iter->iov != fast_iov) {
-                       iov_off = iter->iov - fast_iov;
-                       rw->s.iter.iov += iov_off;
-               }
-               if (rw->s.fast_iov != fast_iov)
-                       memcpy(rw->s.fast_iov + iov_off, fast_iov + iov_off,
-                              sizeof(struct iovec) * iter->nr_segs);
-       } else {
-               req->flags |= REQ_F_NEED_CLEANUP;
-       }
-}
-
-static inline bool io_alloc_async_data(struct io_kiocb *req)
-{
-       WARN_ON_ONCE(!io_op_defs[req->opcode].async_size);
-       req->async_data = kmalloc(io_op_defs[req->opcode].async_size, GFP_KERNEL);
-       if (req->async_data) {
-               req->flags |= REQ_F_ASYNC_DATA;
-               return false;
-       }
-       return true;
-}
-
-static int io_setup_async_rw(struct io_kiocb *req, const struct iovec *iovec,
-                            struct io_rw_state *s, bool force)
-{
-       if (!force && !io_op_defs[req->opcode].needs_async_setup)
-               return 0;
-       if (!req_has_async_data(req)) {
-               struct io_async_rw *iorw;
-
-               if (io_alloc_async_data(req)) {
-                       kfree(iovec);
-                       return -ENOMEM;
-               }
-
-               io_req_map_rw(req, iovec, s->fast_iov, &s->iter);
-               iorw = req->async_data;
-               /* we've copied and mapped the iter, ensure state is saved */
-               iov_iter_save_state(&iorw->s.iter, &iorw->s.iter_state);
-       }
-       return 0;
-}
-
-static inline int io_rw_prep_async(struct io_kiocb *req, int rw)
-{
-       struct io_async_rw *iorw = req->async_data;
-       struct iovec *iov;
-       int ret;
-
-       /* submission path, ->uring_lock should already be taken */
-       ret = io_import_iovec(rw, req, &iov, &iorw->s, 0);
-       if (unlikely(ret < 0))
-               return ret;
-
-       iorw->bytes_done = 0;
-       iorw->free_iovec = iov;
-       if (iov)
-               req->flags |= REQ_F_NEED_CLEANUP;
-       return 0;
-}
-
-static int io_readv_prep_async(struct io_kiocb *req)
-{
-       return io_rw_prep_async(req, READ);
-}
-
-static int io_writev_prep_async(struct io_kiocb *req)
-{
-       return io_rw_prep_async(req, WRITE);
-}
-
-/*
- * This is our waitqueue callback handler, registered through __folio_lock_async()
- * when we initially tried to do the IO with the iocb armed our waitqueue.
- * This gets called when the page is unlocked, and we generally expect that to
- * happen when the page IO is completed and the page is now uptodate. This will
- * queue a task_work based retry of the operation, attempting to copy the data
- * again. If the latter fails because the page was NOT uptodate, then we will
- * do a thread based blocking retry of the operation. That's the unexpected
- * slow path.
- */
-static int io_async_buf_func(struct wait_queue_entry *wait, unsigned mode,
-                            int sync, void *arg)
-{
-       struct wait_page_queue *wpq;
-       struct io_kiocb *req = wait->private;
-       struct wait_page_key *key = arg;
-
-       wpq = container_of(wait, struct wait_page_queue, wait);
-
-       if (!wake_page_match(wpq, key))
-               return 0;
-
-       req->rw.kiocb.ki_flags &= ~IOCB_WAITQ;
-       list_del_init(&wait->entry);
-       io_req_task_queue(req);
-       return 1;
-}
-
-/*
- * This controls whether a given IO request should be armed for async page
- * based retry. If we return false here, the request is handed to the async
- * worker threads for retry. If we're doing buffered reads on a regular file,
- * we prepare a private wait_page_queue entry and retry the operation. This
- * will either succeed because the page is now uptodate and unlocked, or it
- * will register a callback when the page is unlocked at IO completion. Through
- * that callback, io_uring uses task_work to setup a retry of the operation.
- * That retry will attempt the buffered read again. The retry will generally
- * succeed, or in rare cases where it fails, we then fall back to using the
- * async worker threads for a blocking retry.
- */
-static bool io_rw_should_retry(struct io_kiocb *req)
-{
-       struct io_async_rw *rw = req->async_data;
-       struct wait_page_queue *wait = &rw->wpq;
-       struct kiocb *kiocb = &req->rw.kiocb;
-
-       /* never retry for NOWAIT, we just complete with -EAGAIN */
-       if (req->flags & REQ_F_NOWAIT)
-               return false;
-
-       /* Only for buffered IO */
-       if (kiocb->ki_flags & (IOCB_DIRECT | IOCB_HIPRI))
-               return false;
-
-       /*
-        * 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))
-               return false;
-
-       wait->wait.func = io_async_buf_func;
-       wait->wait.private = req;
-       wait->wait.flags = 0;
-       INIT_LIST_HEAD(&wait->wait.entry);
-       kiocb->ki_flags |= IOCB_WAITQ;
-       kiocb->ki_flags &= ~IOCB_NOWAIT;
-       kiocb->ki_waitq = wait;
-       return true;
-}
-
-static inline int io_iter_do_read(struct io_kiocb *req, struct iov_iter *iter)
-{
-       if (likely(req->file->f_op->read_iter))
-               return call_read_iter(req->file, &req->rw.kiocb, iter);
-       else if (req->file->f_op->read)
-               return loop_rw_iter(READ, req, iter);
-       else
-               return -EINVAL;
-}
-
-static bool need_read_all(struct io_kiocb *req)
-{
-       return req->flags & REQ_F_ISREG ||
-               S_ISBLK(file_inode(req->file)->i_mode);
-}
-
-static int io_rw_init_file(struct io_kiocb *req, fmode_t mode)
-{
-       struct kiocb *kiocb = &req->rw.kiocb;
-       struct io_ring_ctx *ctx = req->ctx;
-       struct file *file = req->file;
-       int ret;
-
-       if (unlikely(!file || !(file->f_mode & mode)))
-               return -EBADF;
-
-       if (!io_req_ffs_set(req))
-               req->flags |= io_file_get_flags(file) << REQ_F_SUPPORT_NOWAIT_BIT;
-
-       kiocb->ki_flags = iocb_flags(file);
-       ret = kiocb_set_rw_flags(kiocb, req->rw.flags);
-       if (unlikely(ret))
-               return ret;
-
-       /*
-        * If the file is marked O_NONBLOCK, still allow retry for it if it
-        * supports async. Otherwise it's impossible to use O_NONBLOCK files
-        * reliably. If not, or it IOCB_NOWAIT is set, don't retry.
-        */
-       if ((kiocb->ki_flags & IOCB_NOWAIT) ||
-           ((file->f_flags & O_NONBLOCK) && !io_file_supports_nowait(req)))
-               req->flags |= REQ_F_NOWAIT;
-
-       if (ctx->flags & IORING_SETUP_IOPOLL) {
-               if (!(kiocb->ki_flags & IOCB_DIRECT) || !file->f_op->iopoll)
-                       return -EOPNOTSUPP;
-
-               kiocb->private = NULL;
-               kiocb->ki_flags |= IOCB_HIPRI | IOCB_ALLOC_CACHE;
-               kiocb->ki_complete = io_complete_rw_iopoll;
-               req->iopoll_completed = 0;
-       } else {
-               if (kiocb->ki_flags & IOCB_HIPRI)
-                       return -EINVAL;
-               kiocb->ki_complete = io_complete_rw;
-       }
-
-       return 0;
-}
-
-static int io_read(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_rw_state __s, *s = &__s;
-       struct iovec *iovec;
-       struct kiocb *kiocb = &req->rw.kiocb;
-       bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK;
-       struct io_async_rw *rw;
-       ssize_t ret, ret2;
-       loff_t *ppos;
-
-       if (!req_has_async_data(req)) {
-               ret = io_import_iovec(READ, req, &iovec, s, issue_flags);
-               if (unlikely(ret < 0))
-                       return ret;
-       } else {
-               /*
-                * Safe and required to re-import if we're using provided
-                * buffers, as we dropped the selected one before retry.
-                */
-               if (req->flags & REQ_F_BUFFER_SELECT) {
-                       ret = io_import_iovec(READ, req, &iovec, s, issue_flags);
-                       if (unlikely(ret < 0))
-                               return ret;
-               }
-
-               rw = req->async_data;
-               s = &rw->s;
-               /*
-                * We come here from an earlier attempt, restore our state to
-                * match in case it doesn't. It's cheap enough that we don't
-                * need to make this conditional.
-                */
-               iov_iter_restore(&s->iter, &s->iter_state);
-               iovec = NULL;
-       }
-       ret = io_rw_init_file(req, FMODE_READ);
-       if (unlikely(ret)) {
-               kfree(iovec);
-               return ret;
-       }
-       req->cqe.res = iov_iter_count(&s->iter);
-
-       if (force_nonblock) {
-               /* If the file doesn't support async, just async punt */
-               if (unlikely(!io_file_supports_nowait(req))) {
-                       ret = io_setup_async_rw(req, iovec, s, true);
-                       return ret ?: -EAGAIN;
-               }
-               kiocb->ki_flags |= IOCB_NOWAIT;
-       } else {
-               /* Ensure we clear previously set non-block flag */
-               kiocb->ki_flags &= ~IOCB_NOWAIT;
-       }
-
-       ppos = io_kiocb_update_pos(req);
-
-       ret = rw_verify_area(READ, req->file, ppos, req->cqe.res);
-       if (unlikely(ret)) {
-               kfree(iovec);
-               return ret;
-       }
-
-       ret = io_iter_do_read(req, &s->iter);
-
-       if (ret == -EAGAIN || (req->flags & REQ_F_REISSUE)) {
-               req->flags &= ~REQ_F_REISSUE;
-               /* if we can poll, just do that */
-               if (req->opcode == IORING_OP_READ && file_can_poll(req->file))
-                       return -EAGAIN;
-               /* IOPOLL retry should happen for io-wq threads */
-               if (!force_nonblock && !(req->ctx->flags & IORING_SETUP_IOPOLL))
-                       goto done;
-               /* no retry on NONBLOCK nor RWF_NOWAIT */
-               if (req->flags & REQ_F_NOWAIT)
-                       goto done;
-               ret = 0;
-       } else if (ret == -EIOCBQUEUED) {
-               goto out_free;
-       } else if (ret == req->cqe.res || ret <= 0 || !force_nonblock ||
-                  (req->flags & REQ_F_NOWAIT) || !need_read_all(req)) {
-               /* read all, failed, already did sync or don't want to retry */
-               goto done;
-       }
-
-       /*
-        * Don't depend on the iter state matching what was consumed, or being
-        * untouched in case of error. Restore it and we'll advance it
-        * manually if we need to.
-        */
-       iov_iter_restore(&s->iter, &s->iter_state);
-
-       ret2 = io_setup_async_rw(req, iovec, s, true);
-       if (ret2)
-               return ret2;
-
-       iovec = NULL;
-       rw = req->async_data;
-       s = &rw->s;
-       /*
-        * Now use our persistent iterator and state, if we aren't already.
-        * We've restored and mapped the iter to match.
-        */
-
-       do {
-               /*
-                * We end up here because of a partial read, either from
-                * above or inside this loop. Advance the iter by the bytes
-                * that were consumed.
-                */
-               iov_iter_advance(&s->iter, ret);
-               if (!iov_iter_count(&s->iter))
-                       break;
-               rw->bytes_done += ret;
-               iov_iter_save_state(&s->iter, &s->iter_state);
-
-               /* if we can retry, do so with the callbacks armed */
-               if (!io_rw_should_retry(req)) {
-                       kiocb->ki_flags &= ~IOCB_WAITQ;
-                       return -EAGAIN;
-               }
-
-               /*
-                * Now retry read with the IOCB_WAITQ parts set in the iocb. If
-                * we get -EIOCBQUEUED, then we'll get a notification when the
-                * desired page gets unlocked. We can also get a partial read
-                * here, and if we do, then just retry at the new offset.
-                */
-               ret = io_iter_do_read(req, &s->iter);
-               if (ret == -EIOCBQUEUED)
-                       return 0;
-               /* we got some bytes, but not all. retry. */
-               kiocb->ki_flags &= ~IOCB_WAITQ;
-               iov_iter_restore(&s->iter, &s->iter_state);
-       } while (ret > 0);
-done:
-       kiocb_done(req, ret, issue_flags);
-out_free:
-       /* it's faster to check here then delegate to kfree */
-       if (iovec)
-               kfree(iovec);
-       return 0;
-}
-
-static int io_write(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_rw_state __s, *s = &__s;
-       struct iovec *iovec;
-       struct kiocb *kiocb = &req->rw.kiocb;
-       bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK;
-       ssize_t ret, ret2;
-       loff_t *ppos;
-
-       if (!req_has_async_data(req)) {
-               ret = io_import_iovec(WRITE, req, &iovec, s, issue_flags);
-               if (unlikely(ret < 0))
-                       return ret;
-       } else {
-               struct io_async_rw *rw = req->async_data;
-
-               s = &rw->s;
-               iov_iter_restore(&s->iter, &s->iter_state);
-               iovec = NULL;
-       }
-       ret = io_rw_init_file(req, FMODE_WRITE);
-       if (unlikely(ret)) {
-               kfree(iovec);
-               return ret;
-       }
-       req->cqe.res = iov_iter_count(&s->iter);
-
-       if (force_nonblock) {
-               /* If the file doesn't support async, just async punt */
-               if (unlikely(!io_file_supports_nowait(req)))
-                       goto copy_iov;
-
-               /* file path doesn't support NOWAIT for non-direct_IO */
-               if (force_nonblock && !(kiocb->ki_flags & IOCB_DIRECT) &&
-                   (req->flags & REQ_F_ISREG))
-                       goto copy_iov;
-
-               kiocb->ki_flags |= IOCB_NOWAIT;
-       } else {
-               /* Ensure we clear previously set non-block flag */
-               kiocb->ki_flags &= ~IOCB_NOWAIT;
-       }
-
-       ppos = io_kiocb_update_pos(req);
-
-       ret = rw_verify_area(WRITE, req->file, ppos, req->cqe.res);
-       if (unlikely(ret))
-               goto out_free;
-
-       /*
-        * Open-code file_start_write here to grab freeze protection,
-        * which will be released by another thread in
-        * io_complete_rw().  Fool lockdep by telling it the lock got
-        * released so that it doesn't complain about the held lock when
-        * we return to userspace.
-        */
-       if (req->flags & REQ_F_ISREG) {
-               sb_start_write(file_inode(req->file)->i_sb);
-               __sb_writers_release(file_inode(req->file)->i_sb,
-                                       SB_FREEZE_WRITE);
-       }
-       kiocb->ki_flags |= IOCB_WRITE;
-
-       if (likely(req->file->f_op->write_iter))
-               ret2 = call_write_iter(req->file, kiocb, &s->iter);
-       else if (req->file->f_op->write)
-               ret2 = loop_rw_iter(WRITE, req, &s->iter);
-       else
-               ret2 = -EINVAL;
-
-       if (req->flags & REQ_F_REISSUE) {
-               req->flags &= ~REQ_F_REISSUE;
-               ret2 = -EAGAIN;
-       }
-
-       /*
-        * Raw bdev writes will return -EOPNOTSUPP for IOCB_NOWAIT. Just
-        * retry them without IOCB_NOWAIT.
-        */
-       if (ret2 == -EOPNOTSUPP && (kiocb->ki_flags & IOCB_NOWAIT))
-               ret2 = -EAGAIN;
-       /* no retry on NONBLOCK nor RWF_NOWAIT */
-       if (ret2 == -EAGAIN && (req->flags & REQ_F_NOWAIT))
-               goto done;
-       if (!force_nonblock || ret2 != -EAGAIN) {
-               /* IOPOLL retry should happen for io-wq threads */
-               if (ret2 == -EAGAIN && (req->ctx->flags & IORING_SETUP_IOPOLL))
-                       goto copy_iov;
-done:
-               kiocb_done(req, ret2, issue_flags);
-       } else {
-copy_iov:
-               iov_iter_restore(&s->iter, &s->iter_state);
-               ret = io_setup_async_rw(req, iovec, s, false);
-               return ret ?: -EAGAIN;
-       }
-out_free:
-       /* it's reportedly faster than delegating the null check to kfree() */
-       if (iovec)
-               kfree(iovec);
-       return ret;
-}
-
-static int io_renameat_prep(struct io_kiocb *req,
-                           const struct io_uring_sqe *sqe)
-{
-       struct io_rename *ren = &req->rename;
-       const char __user *oldf, *newf;
-
-       if (sqe->buf_index || sqe->splice_fd_in)
-               return -EINVAL;
-       if (unlikely(req->flags & REQ_F_FIXED_FILE))
-               return -EBADF;
-
-       ren->old_dfd = READ_ONCE(sqe->fd);
-       oldf = u64_to_user_ptr(READ_ONCE(sqe->addr));
-       newf = u64_to_user_ptr(READ_ONCE(sqe->addr2));
-       ren->new_dfd = READ_ONCE(sqe->len);
-       ren->flags = READ_ONCE(sqe->rename_flags);
-
-       ren->oldpath = getname(oldf);
-       if (IS_ERR(ren->oldpath))
-               return PTR_ERR(ren->oldpath);
-
-       ren->newpath = getname(newf);
-       if (IS_ERR(ren->newpath)) {
-               putname(ren->oldpath);
-               return PTR_ERR(ren->newpath);
-       }
-
-       req->flags |= REQ_F_NEED_CLEANUP;
-       return 0;
-}
-
-static int io_renameat(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_rename *ren = &req->rename;
-       int ret;
-
-       if (issue_flags & IO_URING_F_NONBLOCK)
-               return -EAGAIN;
-
-       ret = do_renameat2(ren->old_dfd, ren->oldpath, ren->new_dfd,
-                               ren->newpath, ren->flags);
-
-       req->flags &= ~REQ_F_NEED_CLEANUP;
-       io_req_complete(req, ret);
-       return 0;
-}
-
-static inline void __io_xattr_finish(struct io_kiocb *req)
-{
-       struct io_xattr *ix = &req->xattr;
-
-       if (ix->filename)
-               putname(ix->filename);
-
-       kfree(ix->ctx.kname);
-       kvfree(ix->ctx.kvalue);
-}
-
-static void io_xattr_finish(struct io_kiocb *req, int ret)
-{
-       req->flags &= ~REQ_F_NEED_CLEANUP;
-
-       __io_xattr_finish(req);
-       io_req_complete(req, ret);
-}
-
-static int __io_getxattr_prep(struct io_kiocb *req,
-                             const struct io_uring_sqe *sqe)
-{
-       struct io_xattr *ix = &req->xattr;
-       const char __user *name;
-       int ret;
-
-       if (unlikely(req->flags & REQ_F_FIXED_FILE))
-               return -EBADF;
-
-       ix->filename = NULL;
-       ix->ctx.kvalue = NULL;
-       name = u64_to_user_ptr(READ_ONCE(sqe->addr));
-       ix->ctx.cvalue = u64_to_user_ptr(READ_ONCE(sqe->addr2));
-       ix->ctx.size = READ_ONCE(sqe->len);
-       ix->ctx.flags = READ_ONCE(sqe->xattr_flags);
-
-       if (ix->ctx.flags)
-               return -EINVAL;
-
-       ix->ctx.kname = kmalloc(sizeof(*ix->ctx.kname), GFP_KERNEL);
-       if (!ix->ctx.kname)
-               return -ENOMEM;
-
-       ret = strncpy_from_user(ix->ctx.kname->name, name,
-                               sizeof(ix->ctx.kname->name));
-       if (!ret || ret == sizeof(ix->ctx.kname->name))
-               ret = -ERANGE;
-       if (ret < 0) {
-               kfree(ix->ctx.kname);
-               return ret;
-       }
-
-       req->flags |= REQ_F_NEED_CLEANUP;
-       return 0;
-}
-
-static int io_fgetxattr_prep(struct io_kiocb *req,
-                            const struct io_uring_sqe *sqe)
-{
-       return __io_getxattr_prep(req, sqe);
-}
-
-static int io_getxattr_prep(struct io_kiocb *req,
-                           const struct io_uring_sqe *sqe)
-{
-       struct io_xattr *ix = &req->xattr;
-       const char __user *path;
-       int ret;
-
-       ret = __io_getxattr_prep(req, sqe);
-       if (ret)
-               return ret;
-
-       path = u64_to_user_ptr(READ_ONCE(sqe->addr3));
-
-       ix->filename = getname_flags(path, LOOKUP_FOLLOW, NULL);
-       if (IS_ERR(ix->filename)) {
-               ret = PTR_ERR(ix->filename);
-               ix->filename = NULL;
-       }
-
-       return ret;
-}
-
-static int io_fgetxattr(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_xattr *ix = &req->xattr;
-       int ret;
-
-       if (issue_flags & IO_URING_F_NONBLOCK)
-               return -EAGAIN;
-
-       ret = do_getxattr(mnt_user_ns(req->file->f_path.mnt),
-                       req->file->f_path.dentry,
-                       &ix->ctx);
-
-       io_xattr_finish(req, ret);
-       return 0;
-}
-
-static int io_getxattr(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_xattr *ix = &req->xattr;
-       unsigned int lookup_flags = LOOKUP_FOLLOW;
-       struct path path;
-       int ret;
-
-       if (issue_flags & IO_URING_F_NONBLOCK)
-               return -EAGAIN;
-
-retry:
-       ret = filename_lookup(AT_FDCWD, ix->filename, lookup_flags, &path, NULL);
-       if (!ret) {
-               ret = do_getxattr(mnt_user_ns(path.mnt),
-                               path.dentry,
-                               &ix->ctx);
-
-               path_put(&path);
-               if (retry_estale(ret, lookup_flags)) {
-                       lookup_flags |= LOOKUP_REVAL;
-                       goto retry;
-               }
-       }
-
-       io_xattr_finish(req, ret);
-       return 0;
-}
-
-static int __io_setxattr_prep(struct io_kiocb *req,
-                       const struct io_uring_sqe *sqe)
-{
-       struct io_xattr *ix = &req->xattr;
-       const char __user *name;
-       int ret;
-
-       if (unlikely(req->flags & REQ_F_FIXED_FILE))
-               return -EBADF;
-
-       ix->filename = NULL;
-       name = u64_to_user_ptr(READ_ONCE(sqe->addr));
-       ix->ctx.cvalue = u64_to_user_ptr(READ_ONCE(sqe->addr2));
-       ix->ctx.kvalue = NULL;
-       ix->ctx.size = READ_ONCE(sqe->len);
-       ix->ctx.flags = READ_ONCE(sqe->xattr_flags);
-
-       ix->ctx.kname = kmalloc(sizeof(*ix->ctx.kname), GFP_KERNEL);
-       if (!ix->ctx.kname)
-               return -ENOMEM;
-
-       ret = setxattr_copy(name, &ix->ctx);
-       if (ret) {
-               kfree(ix->ctx.kname);
-               return ret;
-       }
-
-       req->flags |= REQ_F_NEED_CLEANUP;
-       return 0;
-}
-
-static int io_setxattr_prep(struct io_kiocb *req,
-                       const struct io_uring_sqe *sqe)
-{
-       struct io_xattr *ix = &req->xattr;
-       const char __user *path;
-       int ret;
-
-       ret = __io_setxattr_prep(req, sqe);
-       if (ret)
-               return ret;
-
-       path = u64_to_user_ptr(READ_ONCE(sqe->addr3));
-
-       ix->filename = getname_flags(path, LOOKUP_FOLLOW, NULL);
-       if (IS_ERR(ix->filename)) {
-               ret = PTR_ERR(ix->filename);
-               ix->filename = NULL;
-       }
-
-       return ret;
-}
-
-static int io_fsetxattr_prep(struct io_kiocb *req,
-                       const struct io_uring_sqe *sqe)
-{
-       return __io_setxattr_prep(req, sqe);
-}
-
-static int __io_setxattr(struct io_kiocb *req, unsigned int issue_flags,
-                       struct path *path)
-{
-       struct io_xattr *ix = &req->xattr;
-       int ret;
-
-       ret = mnt_want_write(path->mnt);
-       if (!ret) {
-               ret = do_setxattr(mnt_user_ns(path->mnt), path->dentry, &ix->ctx);
-               mnt_drop_write(path->mnt);
-       }
-
-       return ret;
-}
-
-static int io_fsetxattr(struct io_kiocb *req, unsigned int issue_flags)
-{
-       int ret;
-
-       if (issue_flags & IO_URING_F_NONBLOCK)
-               return -EAGAIN;
-
-       ret = __io_setxattr(req, issue_flags, &req->file->f_path);
-       io_xattr_finish(req, ret);
-
-       return 0;
-}
-
-static int io_setxattr(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_xattr *ix = &req->xattr;
-       unsigned int lookup_flags = LOOKUP_FOLLOW;
-       struct path path;
-       int ret;
-
-       if (issue_flags & IO_URING_F_NONBLOCK)
-               return -EAGAIN;
-
-retry:
-       ret = filename_lookup(AT_FDCWD, ix->filename, lookup_flags, &path, NULL);
-       if (!ret) {
-               ret = __io_setxattr(req, issue_flags, &path);
-               path_put(&path);
-               if (retry_estale(ret, lookup_flags)) {
-                       lookup_flags |= LOOKUP_REVAL;
-                       goto retry;
-               }
-       }
-
-       io_xattr_finish(req, ret);
-       return 0;
-}
-
-static int io_unlinkat_prep(struct io_kiocb *req,
-                           const struct io_uring_sqe *sqe)
-{
-       struct io_unlink *un = &req->unlink;
-       const char __user *fname;
-
-       if (sqe->off || sqe->len || sqe->buf_index || sqe->splice_fd_in)
-               return -EINVAL;
-       if (unlikely(req->flags & REQ_F_FIXED_FILE))
-               return -EBADF;
-
-       un->dfd = READ_ONCE(sqe->fd);
-
-       un->flags = READ_ONCE(sqe->unlink_flags);
-       if (un->flags & ~AT_REMOVEDIR)
-               return -EINVAL;
-
-       fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
-       un->filename = getname(fname);
-       if (IS_ERR(un->filename))
-               return PTR_ERR(un->filename);
-
-       req->flags |= REQ_F_NEED_CLEANUP;
-       return 0;
-}
-
-static int io_unlinkat(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_unlink *un = &req->unlink;
-       int ret;
-
-       if (issue_flags & IO_URING_F_NONBLOCK)
-               return -EAGAIN;
-
-       if (un->flags & AT_REMOVEDIR)
-               ret = do_rmdir(un->dfd, un->filename);
-       else
-               ret = do_unlinkat(un->dfd, un->filename);
-
-       req->flags &= ~REQ_F_NEED_CLEANUP;
-       io_req_complete(req, ret);
-       return 0;
-}
-
-static int io_mkdirat_prep(struct io_kiocb *req,
-                           const struct io_uring_sqe *sqe)
-{
-       struct io_mkdir *mkd = &req->mkdir;
-       const char __user *fname;
-
-       if (sqe->off || sqe->rw_flags || sqe->buf_index || sqe->splice_fd_in)
-               return -EINVAL;
-       if (unlikely(req->flags & REQ_F_FIXED_FILE))
-               return -EBADF;
-
-       mkd->dfd = READ_ONCE(sqe->fd);
-       mkd->mode = READ_ONCE(sqe->len);
-
-       fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
-       mkd->filename = getname(fname);
-       if (IS_ERR(mkd->filename))
-               return PTR_ERR(mkd->filename);
-
-       req->flags |= REQ_F_NEED_CLEANUP;
-       return 0;
-}
-
-static int io_mkdirat(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_mkdir *mkd = &req->mkdir;
-       int ret;
-
-       if (issue_flags & IO_URING_F_NONBLOCK)
-               return -EAGAIN;
-
-       ret = do_mkdirat(mkd->dfd, mkd->filename, mkd->mode);
-
-       req->flags &= ~REQ_F_NEED_CLEANUP;
-       io_req_complete(req, ret);
-       return 0;
-}
-
-static int io_symlinkat_prep(struct io_kiocb *req,
-                           const struct io_uring_sqe *sqe)
-{
-       struct io_symlink *sl = &req->symlink;
-       const char __user *oldpath, *newpath;
-
-       if (sqe->len || sqe->rw_flags || sqe->buf_index || sqe->splice_fd_in)
-               return -EINVAL;
-       if (unlikely(req->flags & REQ_F_FIXED_FILE))
-               return -EBADF;
-
-       sl->new_dfd = READ_ONCE(sqe->fd);
-       oldpath = u64_to_user_ptr(READ_ONCE(sqe->addr));
-       newpath = u64_to_user_ptr(READ_ONCE(sqe->addr2));
-
-       sl->oldpath = getname(oldpath);
-       if (IS_ERR(sl->oldpath))
-               return PTR_ERR(sl->oldpath);
-
-       sl->newpath = getname(newpath);
-       if (IS_ERR(sl->newpath)) {
-               putname(sl->oldpath);
-               return PTR_ERR(sl->newpath);
-       }
-
-       req->flags |= REQ_F_NEED_CLEANUP;
-       return 0;
-}
-
-static int io_symlinkat(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_symlink *sl = &req->symlink;
-       int ret;
-
-       if (issue_flags & IO_URING_F_NONBLOCK)
-               return -EAGAIN;
-
-       ret = do_symlinkat(sl->oldpath, sl->new_dfd, sl->newpath);
-
-       req->flags &= ~REQ_F_NEED_CLEANUP;
-       io_req_complete(req, ret);
-       return 0;
-}
-
-static int io_linkat_prep(struct io_kiocb *req,
-                           const struct io_uring_sqe *sqe)
-{
-       struct io_hardlink *lnk = &req->hardlink;
-       const char __user *oldf, *newf;
-
-       if (sqe->rw_flags || sqe->buf_index || sqe->splice_fd_in)
-               return -EINVAL;
-       if (unlikely(req->flags & REQ_F_FIXED_FILE))
-               return -EBADF;
-
-       lnk->old_dfd = READ_ONCE(sqe->fd);
-       lnk->new_dfd = READ_ONCE(sqe->len);
-       oldf = u64_to_user_ptr(READ_ONCE(sqe->addr));
-       newf = u64_to_user_ptr(READ_ONCE(sqe->addr2));
-       lnk->flags = READ_ONCE(sqe->hardlink_flags);
-
-       lnk->oldpath = getname(oldf);
-       if (IS_ERR(lnk->oldpath))
-               return PTR_ERR(lnk->oldpath);
-
-       lnk->newpath = getname(newf);
-       if (IS_ERR(lnk->newpath)) {
-               putname(lnk->oldpath);
-               return PTR_ERR(lnk->newpath);
-       }
-
-       req->flags |= REQ_F_NEED_CLEANUP;
-       return 0;
-}
-
-static int io_linkat(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_hardlink *lnk = &req->hardlink;
-       int ret;
-
-       if (issue_flags & IO_URING_F_NONBLOCK)
-               return -EAGAIN;
-
-       ret = do_linkat(lnk->old_dfd, lnk->oldpath, lnk->new_dfd,
-                               lnk->newpath, lnk->flags);
-
-       req->flags &= ~REQ_F_NEED_CLEANUP;
-       io_req_complete(req, ret);
-       return 0;
-}
-
-static void io_uring_cmd_work(struct io_kiocb *req, bool *locked)
-{
-       req->uring_cmd.task_work_cb(&req->uring_cmd);
-}
-
-void io_uring_cmd_complete_in_task(struct io_uring_cmd *ioucmd,
-                       void (*task_work_cb)(struct io_uring_cmd *))
-{
-       struct io_kiocb *req = container_of(ioucmd, struct io_kiocb, uring_cmd);
-
-       req->uring_cmd.task_work_cb = task_work_cb;
-       req->io_task_work.func = io_uring_cmd_work;
-       io_req_task_work_add(req);
-}
-EXPORT_SYMBOL_GPL(io_uring_cmd_complete_in_task);
-
-static inline void io_req_set_cqe32_extra(struct io_kiocb *req,
-                                         u64 extra1, u64 extra2)
-{
-       req->extra1 = extra1;
-       req->extra2 = extra2;
-       req->flags |= REQ_F_CQE32_INIT;
-}
-
-/*
- * Called by consumers of io_uring_cmd, if they originally returned
- * -EIOCBQUEUED upon receiving the command.
- */
-void io_uring_cmd_done(struct io_uring_cmd *ioucmd, ssize_t ret, ssize_t res2)
-{
-       struct io_kiocb *req = container_of(ioucmd, struct io_kiocb, uring_cmd);
-
-       if (ret < 0)
-               req_set_fail(req);
-
-       if (req->ctx->flags & IORING_SETUP_CQE32)
-               io_req_set_cqe32_extra(req, res2, 0);
-       io_req_complete(req, ret);
-}
-EXPORT_SYMBOL_GPL(io_uring_cmd_done);
-
-static int io_uring_cmd_prep_async(struct io_kiocb *req)
-{
-       size_t cmd_size;
-
-       cmd_size = uring_cmd_pdu_size(req->ctx->flags & IORING_SETUP_SQE128);
-
-       memcpy(req->async_data, req->uring_cmd.cmd, cmd_size);
-       return 0;
-}
-
-static int io_uring_cmd_prep(struct io_kiocb *req,
-                            const struct io_uring_sqe *sqe)
-{
-       struct io_uring_cmd *ioucmd = &req->uring_cmd;
-
-       if (sqe->rw_flags)
-               return -EINVAL;
-       ioucmd->cmd = sqe->cmd;
-       ioucmd->cmd_op = READ_ONCE(sqe->cmd_op);
-       return 0;
-}
-
-static int io_uring_cmd(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_uring_cmd *ioucmd = &req->uring_cmd;
-       struct io_ring_ctx *ctx = req->ctx;
-       struct file *file = req->file;
-       int ret;
-
-       if (!req->file->f_op->uring_cmd)
-               return -EOPNOTSUPP;
-
-       if (ctx->flags & IORING_SETUP_SQE128)
-               issue_flags |= IO_URING_F_SQE128;
-       if (ctx->flags & IORING_SETUP_CQE32)
-               issue_flags |= IO_URING_F_CQE32;
-       if (ctx->flags & IORING_SETUP_IOPOLL)
-               issue_flags |= IO_URING_F_IOPOLL;
-
-       if (req_has_async_data(req))
-               ioucmd->cmd = req->async_data;
-
-       ret = file->f_op->uring_cmd(ioucmd, issue_flags);
-       if (ret == -EAGAIN) {
-               if (!req_has_async_data(req)) {
-                       if (io_alloc_async_data(req))
-                               return -ENOMEM;
-                       io_uring_cmd_prep_async(req);
-               }
-               return -EAGAIN;
-       }
-
-       if (ret != -EIOCBQUEUED)
-               io_uring_cmd_done(ioucmd, ret, 0);
-       return 0;
-}
-
-static int __io_splice_prep(struct io_kiocb *req,
-                           const struct io_uring_sqe *sqe)
-{
-       struct io_splice *sp = &req->splice;
-       unsigned int valid_flags = SPLICE_F_FD_IN_FIXED | SPLICE_F_ALL;
-
-       sp->len = READ_ONCE(sqe->len);
-       sp->flags = READ_ONCE(sqe->splice_flags);
-       if (unlikely(sp->flags & ~valid_flags))
-               return -EINVAL;
-       sp->splice_fd_in = READ_ONCE(sqe->splice_fd_in);
-       return 0;
-}
-
-static int io_tee_prep(struct io_kiocb *req,
-                      const struct io_uring_sqe *sqe)
-{
-       if (READ_ONCE(sqe->splice_off_in) || READ_ONCE(sqe->off))
-               return -EINVAL;
-       return __io_splice_prep(req, sqe);
-}
-
-static int io_tee(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_splice *sp = &req->splice;
-       struct file *out = sp->file_out;
-       unsigned int flags = sp->flags & ~SPLICE_F_FD_IN_FIXED;
-       struct file *in;
-       long ret = 0;
-
-       if (issue_flags & IO_URING_F_NONBLOCK)
-               return -EAGAIN;
-
-       if (sp->flags & SPLICE_F_FD_IN_FIXED)
-               in = io_file_get_fixed(req, sp->splice_fd_in, issue_flags);
-       else
-               in = io_file_get_normal(req, sp->splice_fd_in);
-       if (!in) {
-               ret = -EBADF;
-               goto done;
-       }
-
-       if (sp->len)
-               ret = do_tee(in, out, sp->len, flags);
-
-       if (!(sp->flags & SPLICE_F_FD_IN_FIXED))
-               io_put_file(in);
-done:
-       if (ret != sp->len)
-               req_set_fail(req);
-       __io_req_complete(req, 0, ret, 0);
-       return 0;
-}
-
-static int io_splice_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
-{
-       struct io_splice *sp = &req->splice;
-
-       sp->off_in = READ_ONCE(sqe->splice_off_in);
-       sp->off_out = READ_ONCE(sqe->off);
-       return __io_splice_prep(req, sqe);
-}
-
-static int io_splice(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_splice *sp = &req->splice;
-       struct file *out = sp->file_out;
-       unsigned int flags = sp->flags & ~SPLICE_F_FD_IN_FIXED;
-       loff_t *poff_in, *poff_out;
-       struct file *in;
-       long ret = 0;
-
-       if (issue_flags & IO_URING_F_NONBLOCK)
-               return -EAGAIN;
-
-       if (sp->flags & SPLICE_F_FD_IN_FIXED)
-               in = io_file_get_fixed(req, sp->splice_fd_in, issue_flags);
-       else
-               in = io_file_get_normal(req, sp->splice_fd_in);
-       if (!in) {
-               ret = -EBADF;
-               goto done;
-       }
-
-       poff_in = (sp->off_in == -1) ? NULL : &sp->off_in;
-       poff_out = (sp->off_out == -1) ? NULL : &sp->off_out;
-
-       if (sp->len)
-               ret = do_splice(in, poff_in, out, poff_out, sp->len, flags);
-
-       if (!(sp->flags & SPLICE_F_FD_IN_FIXED))
-               io_put_file(in);
-done:
-       if (ret != sp->len)
-               req_set_fail(req);
-       __io_req_complete(req, 0, ret, 0);
-       return 0;
-}
-
-static int io_nop_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
-{
-       return 0;
-}
-
-/*
- * IORING_OP_NOP just posts a completion event, nothing else.
- */
-static int io_nop(struct io_kiocb *req, unsigned int issue_flags)
-{
-       __io_req_complete(req, issue_flags, 0, 0);
-       return 0;
-}
-
-static int io_msg_ring_prep(struct io_kiocb *req,
-                           const struct io_uring_sqe *sqe)
-{
-       if (unlikely(sqe->addr || sqe->rw_flags || sqe->splice_fd_in ||
-                    sqe->buf_index || sqe->personality))
-               return -EINVAL;
-
-       req->msg.user_data = READ_ONCE(sqe->off);
-       req->msg.len = READ_ONCE(sqe->len);
-       return 0;
-}
-
-static int io_msg_ring(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_ring_ctx *target_ctx;
-       struct io_msg *msg = &req->msg;
-       bool filled;
-       int ret;
-
-       ret = -EBADFD;
-       if (req->file->f_op != &io_uring_fops)
-               goto done;
-
-       ret = -EOVERFLOW;
-       target_ctx = req->file->private_data;
-
-       spin_lock(&target_ctx->completion_lock);
-       filled = io_fill_cqe_aux(target_ctx, msg->user_data, msg->len, 0);
-       io_commit_cqring(target_ctx);
-       spin_unlock(&target_ctx->completion_lock);
-
-       if (filled) {
-               io_cqring_ev_posted(target_ctx);
-               ret = 0;
-       }
-
-done:
-       if (ret < 0)
-               req_set_fail(req);
-       __io_req_complete(req, issue_flags, ret, 0);
-       /* put file to avoid an attempt to IOPOLL the req */
-       io_put_file(req->file);
-       req->file = NULL;
-       return 0;
-}
-
-static int io_fsync_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
-{
-       if (unlikely(sqe->addr || sqe->buf_index || sqe->splice_fd_in))
-               return -EINVAL;
-
-       req->sync.flags = READ_ONCE(sqe->fsync_flags);
-       if (unlikely(req->sync.flags & ~IORING_FSYNC_DATASYNC))
-               return -EINVAL;
-
-       req->sync.off = READ_ONCE(sqe->off);
-       req->sync.len = READ_ONCE(sqe->len);
-       return 0;
-}
-
-static int io_fsync(struct io_kiocb *req, unsigned int issue_flags)
-{
-       loff_t end = req->sync.off + req->sync.len;
-       int ret;
-
-       /* fsync always requires a blocking context */
-       if (issue_flags & IO_URING_F_NONBLOCK)
-               return -EAGAIN;
-
-       ret = vfs_fsync_range(req->file, req->sync.off,
-                               end > 0 ? end : LLONG_MAX,
-                               req->sync.flags & IORING_FSYNC_DATASYNC);
-       io_req_complete(req, ret);
-       return 0;
-}
-
-static int io_fallocate_prep(struct io_kiocb *req,
-                            const struct io_uring_sqe *sqe)
-{
-       if (sqe->buf_index || sqe->rw_flags || sqe->splice_fd_in)
-               return -EINVAL;
-
-       req->sync.off = READ_ONCE(sqe->off);
-       req->sync.len = READ_ONCE(sqe->addr);
-       req->sync.mode = READ_ONCE(sqe->len);
-       return 0;
-}
-
-static int io_fallocate(struct io_kiocb *req, unsigned int issue_flags)
-{
-       int ret;
-
-       /* fallocate always requiring blocking context */
-       if (issue_flags & IO_URING_F_NONBLOCK)
-               return -EAGAIN;
-       ret = vfs_fallocate(req->file, req->sync.mode, req->sync.off,
-                               req->sync.len);
-       if (ret >= 0)
-               fsnotify_modify(req->file);
-       io_req_complete(req, ret);
-       return 0;
-}
-
-static int __io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
-{
-       const char __user *fname;
-       int ret;
-
-       if (unlikely(sqe->buf_index))
-               return -EINVAL;
-       if (unlikely(req->flags & REQ_F_FIXED_FILE))
-               return -EBADF;
-
-       /* open.how should be already initialised */
-       if (!(req->open.how.flags & O_PATH) && force_o_largefile())
-               req->open.how.flags |= O_LARGEFILE;
-
-       req->open.dfd = READ_ONCE(sqe->fd);
-       fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
-       req->open.filename = getname(fname);
-       if (IS_ERR(req->open.filename)) {
-               ret = PTR_ERR(req->open.filename);
-               req->open.filename = NULL;
-               return ret;
-       }
-
-       req->open.file_slot = READ_ONCE(sqe->file_index);
-       if (req->open.file_slot && (req->open.how.flags & O_CLOEXEC))
-               return -EINVAL;
-
-       req->open.nofile = rlimit(RLIMIT_NOFILE);
-       req->flags |= REQ_F_NEED_CLEANUP;
-       return 0;
-}
-
-static int io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
-{
-       u64 mode = READ_ONCE(sqe->len);
-       u64 flags = READ_ONCE(sqe->open_flags);
-
-       req->open.how = build_open_how(flags, mode);
-       return __io_openat_prep(req, sqe);
-}
-
-static int io_openat2_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
-{
-       struct open_how __user *how;
-       size_t len;
-       int ret;
-
-       how = u64_to_user_ptr(READ_ONCE(sqe->addr2));
-       len = READ_ONCE(sqe->len);
-       if (len < OPEN_HOW_SIZE_VER0)
-               return -EINVAL;
-
-       ret = copy_struct_from_user(&req->open.how, sizeof(req->open.how), how,
-                                       len);
-       if (ret)
-               return ret;
-
-       return __io_openat_prep(req, sqe);
-}
-
-static int io_file_bitmap_get(struct io_ring_ctx *ctx)
-{
-       struct io_file_table *table = &ctx->file_table;
-       unsigned long nr = ctx->nr_user_files;
-       int ret;
-
-       do {
-               ret = find_next_zero_bit(table->bitmap, nr, table->alloc_hint);
-               if (ret != nr)
-                       return ret;
-
-               if (!table->alloc_hint)
-                       break;
-
-               nr = table->alloc_hint;
-               table->alloc_hint = 0;
-       } while (1);
-
-       return -ENFILE;
-}
-
-/*
- * Note when io_fixed_fd_install() returns error value, it will ensure
- * fput() is called correspondingly.
- */
-static int io_fixed_fd_install(struct io_kiocb *req, unsigned int issue_flags,
-                              struct file *file, unsigned int file_slot)
-{
-       bool alloc_slot = file_slot == IORING_FILE_INDEX_ALLOC;
-       struct io_ring_ctx *ctx = req->ctx;
-       int ret;
-
-       io_ring_submit_lock(ctx, issue_flags);
-
-       if (alloc_slot) {
-               ret = io_file_bitmap_get(ctx);
-               if (unlikely(ret < 0))
-                       goto err;
-               file_slot = ret;
-       } else {
-               file_slot--;
-       }
-
-       ret = io_install_fixed_file(req, file, issue_flags, file_slot);
-       if (!ret && alloc_slot)
-               ret = file_slot;
-err:
-       io_ring_submit_unlock(ctx, issue_flags);
-       if (unlikely(ret < 0))
-               fput(file);
-       return ret;
-}
-
-static int io_openat2(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct open_flags op;
-       struct file *file;
-       bool resolve_nonblock, nonblock_set;
-       bool fixed = !!req->open.file_slot;
-       int ret;
-
-       ret = build_open_flags(&req->open.how, &op);
-       if (ret)
-               goto err;
-       nonblock_set = op.open_flag & O_NONBLOCK;
-       resolve_nonblock = req->open.how.resolve & RESOLVE_CACHED;
-       if (issue_flags & IO_URING_F_NONBLOCK) {
-               /*
-                * Don't bother trying for O_TRUNC, O_CREAT, or O_TMPFILE open,
-                * it'll always -EAGAIN
-                */
-               if (req->open.how.flags & (O_TRUNC | O_CREAT | O_TMPFILE))
-                       return -EAGAIN;
-               op.lookup_flags |= LOOKUP_CACHED;
-               op.open_flag |= O_NONBLOCK;
-       }
-
-       if (!fixed) {
-               ret = __get_unused_fd_flags(req->open.how.flags, req->open.nofile);
-               if (ret < 0)
-                       goto err;
-       }
-
-       file = do_filp_open(req->open.dfd, req->open.filename, &op);
-       if (IS_ERR(file)) {
-               /*
-                * We could hang on to this 'fd' on retrying, but seems like
-                * marginal gain for something that is now known to be a slower
-                * path. So just put it, and we'll get a new one when we retry.
-                */
-               if (!fixed)
-                       put_unused_fd(ret);
-
-               ret = PTR_ERR(file);
-               /* only retry if RESOLVE_CACHED wasn't already set by application */
-               if (ret == -EAGAIN &&
-                   (!resolve_nonblock && (issue_flags & IO_URING_F_NONBLOCK)))
-                       return -EAGAIN;
-               goto err;
-       }
-
-       if ((issue_flags & IO_URING_F_NONBLOCK) && !nonblock_set)
-               file->f_flags &= ~O_NONBLOCK;
-       fsnotify_open(file);
-
-       if (!fixed)
-               fd_install(ret, file);
-       else
-               ret = io_fixed_fd_install(req, issue_flags, file,
-                                               req->open.file_slot);
-err:
-       putname(req->open.filename);
-       req->flags &= ~REQ_F_NEED_CLEANUP;
-       if (ret < 0)
-               req_set_fail(req);
-       __io_req_complete(req, issue_flags, ret, 0);
-       return 0;
-}
-
-static int io_openat(struct io_kiocb *req, unsigned int issue_flags)
-{
-       return io_openat2(req, issue_flags);
-}
-
-static int io_remove_buffers_prep(struct io_kiocb *req,
-                                 const struct io_uring_sqe *sqe)
-{
-       struct io_provide_buf *p = &req->pbuf;
-       u64 tmp;
-
-       if (sqe->rw_flags || sqe->addr || sqe->len || sqe->off ||
-           sqe->splice_fd_in)
-               return -EINVAL;
-
-       tmp = READ_ONCE(sqe->fd);
-       if (!tmp || tmp > USHRT_MAX)
-               return -EINVAL;
-
-       memset(p, 0, sizeof(*p));
-       p->nbufs = tmp;
-       p->bgid = READ_ONCE(sqe->buf_group);
-       return 0;
-}
-
-static int __io_remove_buffers(struct io_ring_ctx *ctx,
-                              struct io_buffer_list *bl, unsigned nbufs)
-{
-       unsigned i = 0;
-
-       /* shouldn't happen */
-       if (!nbufs)
-               return 0;
-
-       if (bl->buf_nr_pages) {
-               int j;
-
-               i = bl->buf_ring->tail - bl->head;
-               for (j = 0; j < bl->buf_nr_pages; j++)
-                       unpin_user_page(bl->buf_pages[j]);
-               kvfree(bl->buf_pages);
-               bl->buf_pages = NULL;
-               bl->buf_nr_pages = 0;
-               /* make sure it's seen as empty */
-               INIT_LIST_HEAD(&bl->buf_list);
-               return i;
-       }
-
-       /* the head kbuf is the list itself */
-       while (!list_empty(&bl->buf_list)) {
-               struct io_buffer *nxt;
-
-               nxt = list_first_entry(&bl->buf_list, struct io_buffer, list);
-               list_del(&nxt->list);
-               if (++i == nbufs)
-                       return i;
-               cond_resched();
-       }
-       i++;
-
-       return i;
-}
-
-static int io_remove_buffers(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_provide_buf *p = &req->pbuf;
-       struct io_ring_ctx *ctx = req->ctx;
-       struct io_buffer_list *bl;
-       int ret = 0;
-
-       io_ring_submit_lock(ctx, issue_flags);
-
-       ret = -ENOENT;
-       bl = io_buffer_get_list(ctx, p->bgid);
-       if (bl) {
-               ret = -EINVAL;
-               /* can't use provide/remove buffers command on mapped buffers */
-               if (!bl->buf_nr_pages)
-                       ret = __io_remove_buffers(ctx, bl, p->nbufs);
-       }
-       if (ret < 0)
-               req_set_fail(req);
-
-       /* complete before unlock, IOPOLL may need the lock */
-       __io_req_complete(req, issue_flags, ret, 0);
-       io_ring_submit_unlock(ctx, issue_flags);
-       return 0;
-}
-
-static int io_provide_buffers_prep(struct io_kiocb *req,
-                                  const struct io_uring_sqe *sqe)
-{
-       unsigned long size, tmp_check;
-       struct io_provide_buf *p = &req->pbuf;
-       u64 tmp;
-
-       if (sqe->rw_flags || sqe->splice_fd_in)
-               return -EINVAL;
-
-       tmp = READ_ONCE(sqe->fd);
-       if (!tmp || tmp > USHRT_MAX)
-               return -E2BIG;
-       p->nbufs = tmp;
-       p->addr = READ_ONCE(sqe->addr);
-       p->len = READ_ONCE(sqe->len);
-
-       if (check_mul_overflow((unsigned long)p->len, (unsigned long)p->nbufs,
-                               &size))
-               return -EOVERFLOW;
-       if (check_add_overflow((unsigned long)p->addr, size, &tmp_check))
-               return -EOVERFLOW;
-
-       size = (unsigned long)p->len * p->nbufs;
-       if (!access_ok(u64_to_user_ptr(p->addr), size))
-               return -EFAULT;
-
-       p->bgid = READ_ONCE(sqe->buf_group);
-       tmp = READ_ONCE(sqe->off);
-       if (tmp > USHRT_MAX)
-               return -E2BIG;
-       p->bid = tmp;
-       return 0;
-}
-
-static int io_refill_buffer_cache(struct io_ring_ctx *ctx)
-{
-       struct io_buffer *buf;
-       struct page *page;
-       int bufs_in_page;
-
-       /*
-        * Completions that don't happen inline (eg not under uring_lock) will
-        * add to ->io_buffers_comp. If we don't have any free buffers, check
-        * the completion list and splice those entries first.
-        */
-       if (!list_empty_careful(&ctx->io_buffers_comp)) {
-               spin_lock(&ctx->completion_lock);
-               if (!list_empty(&ctx->io_buffers_comp)) {
-                       list_splice_init(&ctx->io_buffers_comp,
-                                               &ctx->io_buffers_cache);
-                       spin_unlock(&ctx->completion_lock);
-                       return 0;
-               }
-               spin_unlock(&ctx->completion_lock);
-       }
-
-       /*
-        * No free buffers and no completion entries either. Allocate a new
-        * page worth of buffer entries and add those to our freelist.
-        */
-       page = alloc_page(GFP_KERNEL_ACCOUNT);
-       if (!page)
-               return -ENOMEM;
-
-       list_add(&page->lru, &ctx->io_buffers_pages);
-
-       buf = page_address(page);
-       bufs_in_page = PAGE_SIZE / sizeof(*buf);
-       while (bufs_in_page) {
-               list_add_tail(&buf->list, &ctx->io_buffers_cache);
-               buf++;
-               bufs_in_page--;
-       }
-
-       return 0;
-}
-
-static int io_add_buffers(struct io_ring_ctx *ctx, struct io_provide_buf *pbuf,
-                         struct io_buffer_list *bl)
-{
-       struct io_buffer *buf;
-       u64 addr = pbuf->addr;
-       int i, bid = pbuf->bid;
-
-       for (i = 0; i < pbuf->nbufs; i++) {
-               if (list_empty(&ctx->io_buffers_cache) &&
-                   io_refill_buffer_cache(ctx))
-                       break;
-               buf = list_first_entry(&ctx->io_buffers_cache, struct io_buffer,
-                                       list);
-               list_move_tail(&buf->list, &bl->buf_list);
-               buf->addr = addr;
-               buf->len = min_t(__u32, pbuf->len, MAX_RW_COUNT);
-               buf->bid = bid;
-               buf->bgid = pbuf->bgid;
-               addr += pbuf->len;
-               bid++;
-               cond_resched();
-       }
-
-       return i ? 0 : -ENOMEM;
-}
-
-static __cold int io_init_bl_list(struct io_ring_ctx *ctx)
-{
-       int i;
-
-       ctx->io_bl = kcalloc(BGID_ARRAY, sizeof(struct io_buffer_list),
-                               GFP_KERNEL);
-       if (!ctx->io_bl)
-               return -ENOMEM;
-
-       for (i = 0; i < BGID_ARRAY; i++) {
-               INIT_LIST_HEAD(&ctx->io_bl[i].buf_list);
-               ctx->io_bl[i].bgid = i;
-       }
-
-       return 0;
-}
-
-static int io_provide_buffers(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_provide_buf *p = &req->pbuf;
-       struct io_ring_ctx *ctx = req->ctx;
-       struct io_buffer_list *bl;
-       int ret = 0;
-
-       io_ring_submit_lock(ctx, issue_flags);
-
-       if (unlikely(p->bgid < BGID_ARRAY && !ctx->io_bl)) {
-               ret = io_init_bl_list(ctx);
-               if (ret)
-                       goto err;
-       }
-
-       bl = io_buffer_get_list(ctx, p->bgid);
-       if (unlikely(!bl)) {
-               bl = kzalloc(sizeof(*bl), GFP_KERNEL);
-               if (!bl) {
-                       ret = -ENOMEM;
-                       goto err;
-               }
-               INIT_LIST_HEAD(&bl->buf_list);
-               ret = io_buffer_add_list(ctx, bl, p->bgid);
-               if (ret) {
-                       kfree(bl);
-                       goto err;
-               }
-       }
-       /* can't add buffers via this command for a mapped buffer ring */
-       if (bl->buf_nr_pages) {
-               ret = -EINVAL;
-               goto err;
-       }
-
-       ret = io_add_buffers(ctx, p, bl);
-err:
-       if (ret < 0)
-               req_set_fail(req);
-       /* complete before unlock, IOPOLL may need the lock */
-       __io_req_complete(req, issue_flags, ret, 0);
-       io_ring_submit_unlock(ctx, issue_flags);
-       return 0;
-}
-
-static int io_epoll_ctl_prep(struct io_kiocb *req,
-                            const struct io_uring_sqe *sqe)
-{
-#if defined(CONFIG_EPOLL)
-       if (sqe->buf_index || sqe->splice_fd_in)
-               return -EINVAL;
-
-       req->epoll.epfd = READ_ONCE(sqe->fd);
-       req->epoll.op = READ_ONCE(sqe->len);
-       req->epoll.fd = READ_ONCE(sqe->off);
-
-       if (ep_op_has_event(req->epoll.op)) {
-               struct epoll_event __user *ev;
-
-               ev = u64_to_user_ptr(READ_ONCE(sqe->addr));
-               if (copy_from_user(&req->epoll.event, ev, sizeof(*ev)))
-                       return -EFAULT;
-       }
-
-       return 0;
-#else
-       return -EOPNOTSUPP;
-#endif
-}
-
-static int io_epoll_ctl(struct io_kiocb *req, unsigned int issue_flags)
-{
-#if defined(CONFIG_EPOLL)
-       struct io_epoll *ie = &req->epoll;
-       int ret;
-       bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK;
-
-       ret = do_epoll_ctl(ie->epfd, ie->op, ie->fd, &ie->event, force_nonblock);
-       if (force_nonblock && ret == -EAGAIN)
-               return -EAGAIN;
-
-       if (ret < 0)
-               req_set_fail(req);
-       __io_req_complete(req, issue_flags, ret, 0);
-       return 0;
-#else
-       return -EOPNOTSUPP;
-#endif
-}
-
-static int io_madvise_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
-{
-#if defined(CONFIG_ADVISE_SYSCALLS) && defined(CONFIG_MMU)
-       if (sqe->buf_index || sqe->off || sqe->splice_fd_in)
-               return -EINVAL;
-
-       req->madvise.addr = READ_ONCE(sqe->addr);
-       req->madvise.len = READ_ONCE(sqe->len);
-       req->madvise.advice = READ_ONCE(sqe->fadvise_advice);
-       return 0;
-#else
-       return -EOPNOTSUPP;
-#endif
-}
-
-static int io_madvise(struct io_kiocb *req, unsigned int issue_flags)
-{
-#if defined(CONFIG_ADVISE_SYSCALLS) && defined(CONFIG_MMU)
-       struct io_madvise *ma = &req->madvise;
-       int ret;
-
-       if (issue_flags & IO_URING_F_NONBLOCK)
-               return -EAGAIN;
-
-       ret = do_madvise(current->mm, ma->addr, ma->len, ma->advice);
-       io_req_complete(req, ret);
-       return 0;
-#else
-       return -EOPNOTSUPP;
-#endif
-}
-
-static int io_fadvise_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
-{
-       if (sqe->buf_index || sqe->addr || sqe->splice_fd_in)
-               return -EINVAL;
-
-       req->fadvise.offset = READ_ONCE(sqe->off);
-       req->fadvise.len = READ_ONCE(sqe->len);
-       req->fadvise.advice = READ_ONCE(sqe->fadvise_advice);
-       return 0;
-}
-
-static int io_fadvise(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_fadvise *fa = &req->fadvise;
-       int ret;
-
-       if (issue_flags & IO_URING_F_NONBLOCK) {
-               switch (fa->advice) {
-               case POSIX_FADV_NORMAL:
-               case POSIX_FADV_RANDOM:
-               case POSIX_FADV_SEQUENTIAL:
-                       break;
-               default:
-                       return -EAGAIN;
-               }
-       }
-
-       ret = vfs_fadvise(req->file, fa->offset, fa->len, fa->advice);
-       if (ret < 0)
-               req_set_fail(req);
-       __io_req_complete(req, issue_flags, ret, 0);
-       return 0;
-}
-
-static int io_statx_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
-{
-       const char __user *path;
-
-       if (sqe->buf_index || sqe->splice_fd_in)
-               return -EINVAL;
-       if (req->flags & REQ_F_FIXED_FILE)
-               return -EBADF;
-
-       req->statx.dfd = READ_ONCE(sqe->fd);
-       req->statx.mask = READ_ONCE(sqe->len);
-       path = u64_to_user_ptr(READ_ONCE(sqe->addr));
-       req->statx.buffer = u64_to_user_ptr(READ_ONCE(sqe->addr2));
-       req->statx.flags = READ_ONCE(sqe->statx_flags);
-
-       req->statx.filename = getname_flags(path,
-                                       getname_statx_lookup_flags(req->statx.flags),
-                                       NULL);
-
-       if (IS_ERR(req->statx.filename)) {
-               int ret = PTR_ERR(req->statx.filename);
-
-               req->statx.filename = NULL;
-               return ret;
-       }
-
-       req->flags |= REQ_F_NEED_CLEANUP;
-       return 0;
-}
-
-static int io_statx(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_statx *ctx = &req->statx;
-       int ret;
-
-       if (issue_flags & IO_URING_F_NONBLOCK)
-               return -EAGAIN;
-
-       ret = do_statx(ctx->dfd, ctx->filename, ctx->flags, ctx->mask,
-                      ctx->buffer);
-       io_req_complete(req, ret);
-       return 0;
-}
-
-static int io_close_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
-{
-       if (sqe->off || sqe->addr || sqe->len || sqe->rw_flags || sqe->buf_index)
-               return -EINVAL;
-       if (req->flags & REQ_F_FIXED_FILE)
-               return -EBADF;
-
-       req->close.fd = READ_ONCE(sqe->fd);
-       req->close.file_slot = READ_ONCE(sqe->file_index);
-       if (req->close.file_slot && req->close.fd)
-               return -EINVAL;
-
-       return 0;
-}
-
-static int io_close(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct files_struct *files = current->files;
-       struct io_close *close = &req->close;
-       struct fdtable *fdt;
-       struct file *file;
-       int ret = -EBADF;
-
-       if (req->close.file_slot) {
-               ret = io_close_fixed(req, issue_flags);
-               goto err;
-       }
-
-       spin_lock(&files->file_lock);
-       fdt = files_fdtable(files);
-       if (close->fd >= fdt->max_fds) {
-               spin_unlock(&files->file_lock);
-               goto err;
-       }
-       file = rcu_dereference_protected(fdt->fd[close->fd],
-                       lockdep_is_held(&files->file_lock));
-       if (!file || file->f_op == &io_uring_fops) {
-               spin_unlock(&files->file_lock);
-               goto err;
-       }
-
-       /* if the file has a flush method, be safe and punt to async */
-       if (file->f_op->flush && (issue_flags & IO_URING_F_NONBLOCK)) {
-               spin_unlock(&files->file_lock);
-               return -EAGAIN;
-       }
-
-       file = __close_fd_get_file(close->fd);
-       spin_unlock(&files->file_lock);
-       if (!file)
-               goto err;
-
-       /* No ->flush() or already async, safely close from here */
-       ret = filp_close(file, current->files);
-err:
-       if (ret < 0)
-               req_set_fail(req);
-       __io_req_complete(req, issue_flags, ret, 0);
-       return 0;
-}
-
-static int io_sfr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
-{
-       if (unlikely(sqe->addr || sqe->buf_index || sqe->splice_fd_in))
-               return -EINVAL;
-
-       req->sync.off = READ_ONCE(sqe->off);
-       req->sync.len = READ_ONCE(sqe->len);
-       req->sync.flags = READ_ONCE(sqe->sync_range_flags);
-       return 0;
-}
-
-static int io_sync_file_range(struct io_kiocb *req, unsigned int issue_flags)
-{
-       int ret;
-
-       /* sync_file_range always requires a blocking context */
-       if (issue_flags & IO_URING_F_NONBLOCK)
-               return -EAGAIN;
-
-       ret = sync_file_range(req->file, req->sync.off, req->sync.len,
-                               req->sync.flags);
-       io_req_complete(req, ret);
-       return 0;
-}
-
-#if defined(CONFIG_NET)
-static int io_shutdown_prep(struct io_kiocb *req,
-                           const struct io_uring_sqe *sqe)
-{
-       if (unlikely(sqe->off || sqe->addr || sqe->rw_flags ||
-                    sqe->buf_index || sqe->splice_fd_in))
-               return -EINVAL;
-
-       req->shutdown.how = READ_ONCE(sqe->len);
-       return 0;
-}
-
-static int io_shutdown(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct socket *sock;
-       int ret;
-
-       if (issue_flags & IO_URING_F_NONBLOCK)
-               return -EAGAIN;
-
-       sock = sock_from_file(req->file);
-       if (unlikely(!sock))
-               return -ENOTSOCK;
-
-       ret = __sys_shutdown_sock(sock, req->shutdown.how);
-       io_req_complete(req, ret);
-       return 0;
-}
-
-static bool io_net_retry(struct socket *sock, int flags)
-{
-       if (!(flags & MSG_WAITALL))
-               return false;
-       return sock->type == SOCK_STREAM || sock->type == SOCK_SEQPACKET;
-}
-
-static int io_setup_async_msg(struct io_kiocb *req,
-                             struct io_async_msghdr *kmsg)
-{
-       struct io_async_msghdr *async_msg = req->async_data;
-
-       if (async_msg)
-               return -EAGAIN;
-       if (io_alloc_async_data(req)) {
-               kfree(kmsg->free_iov);
-               return -ENOMEM;
-       }
-       async_msg = req->async_data;
-       req->flags |= REQ_F_NEED_CLEANUP;
-       memcpy(async_msg, kmsg, sizeof(*kmsg));
-       async_msg->msg.msg_name = &async_msg->addr;
-       /* if were using fast_iov, set it to the new one */
-       if (!async_msg->free_iov)
-               async_msg->msg.msg_iter.iov = async_msg->fast_iov;
-
-       return -EAGAIN;
-}
-
-static int io_sendmsg_copy_hdr(struct io_kiocb *req,
-                              struct io_async_msghdr *iomsg)
-{
-       iomsg->msg.msg_name = &iomsg->addr;
-       iomsg->free_iov = iomsg->fast_iov;
-       return sendmsg_copy_msghdr(&iomsg->msg, req->sr_msg.umsg,
-                                  req->sr_msg.msg_flags, &iomsg->free_iov);
-}
-
-static int io_sendmsg_prep_async(struct io_kiocb *req)
-{
-       int ret;
-
-       ret = io_sendmsg_copy_hdr(req, req->async_data);
-       if (!ret)
-               req->flags |= REQ_F_NEED_CLEANUP;
-       return ret;
-}
-
-static int io_sendmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
-{
-       struct io_sr_msg *sr = &req->sr_msg;
-
-       if (unlikely(sqe->file_index))
-               return -EINVAL;
-
-       sr->umsg = u64_to_user_ptr(READ_ONCE(sqe->addr));
-       sr->len = READ_ONCE(sqe->len);
-       sr->flags = READ_ONCE(sqe->addr2);
-       if (sr->flags & ~IORING_RECVSEND_POLL_FIRST)
-               return -EINVAL;
-       sr->msg_flags = READ_ONCE(sqe->msg_flags) | MSG_NOSIGNAL;
-       if (sr->msg_flags & MSG_DONTWAIT)
-               req->flags |= REQ_F_NOWAIT;
-
-#ifdef CONFIG_COMPAT
-       if (req->ctx->compat)
-               sr->msg_flags |= MSG_CMSG_COMPAT;
-#endif
-       sr->done_io = 0;
-       return 0;
-}
-
-static int io_sendmsg(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_async_msghdr iomsg, *kmsg;
-       struct io_sr_msg *sr = &req->sr_msg;
-       struct socket *sock;
-       unsigned flags;
-       int min_ret = 0;
-       int ret;
-
-       sock = sock_from_file(req->file);
-       if (unlikely(!sock))
-               return -ENOTSOCK;
-
-       if (req_has_async_data(req)) {
-               kmsg = req->async_data;
-       } else {
-               ret = io_sendmsg_copy_hdr(req, &iomsg);
-               if (ret)
-                       return ret;
-               kmsg = &iomsg;
-       }
-
-       if (!(req->flags & REQ_F_POLLED) &&
-           (sr->flags & IORING_RECVSEND_POLL_FIRST))
-               return io_setup_async_msg(req, kmsg);
-
-       flags = sr->msg_flags;
-       if (issue_flags & IO_URING_F_NONBLOCK)
-               flags |= MSG_DONTWAIT;
-       if (flags & MSG_WAITALL)
-               min_ret = iov_iter_count(&kmsg->msg.msg_iter);
-
-       ret = __sys_sendmsg_sock(sock, &kmsg->msg, flags);
-
-       if (ret < min_ret) {
-               if (ret == -EAGAIN && (issue_flags & IO_URING_F_NONBLOCK))
-                       return io_setup_async_msg(req, kmsg);
-               if (ret == -ERESTARTSYS)
-                       ret = -EINTR;
-               if (ret > 0 && io_net_retry(sock, flags)) {
-                       sr->done_io += ret;
-                       req->flags |= REQ_F_PARTIAL_IO;
-                       return io_setup_async_msg(req, kmsg);
-               }
-               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;
-       if (ret >= 0)
-               ret += sr->done_io;
-       else if (sr->done_io)
-               ret = sr->done_io;
-       __io_req_complete(req, issue_flags, ret, 0);
-       return 0;
-}
-
-static int io_send(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_sr_msg *sr = &req->sr_msg;
-       struct msghdr msg;
-       struct iovec iov;
-       struct socket *sock;
-       unsigned flags;
-       int min_ret = 0;
-       int ret;
-
-       if (!(req->flags & REQ_F_POLLED) &&
-           (sr->flags & IORING_RECVSEND_POLL_FIRST))
-               return -EAGAIN;
-
-       sock = sock_from_file(req->file);
-       if (unlikely(!sock))
-               return -ENOTSOCK;
-
-       ret = import_single_range(WRITE, sr->buf, sr->len, &iov, &msg.msg_iter);
-       if (unlikely(ret))
-               return ret;
-
-       msg.msg_name = NULL;
-       msg.msg_control = NULL;
-       msg.msg_controllen = 0;
-       msg.msg_namelen = 0;
-
-       flags = sr->msg_flags;
-       if (issue_flags & IO_URING_F_NONBLOCK)
-               flags |= MSG_DONTWAIT;
-       if (flags & MSG_WAITALL)
-               min_ret = iov_iter_count(&msg.msg_iter);
-
-       msg.msg_flags = flags;
-       ret = sock_sendmsg(sock, &msg);
-       if (ret < min_ret) {
-               if (ret == -EAGAIN && (issue_flags & IO_URING_F_NONBLOCK))
-                       return -EAGAIN;
-               if (ret == -ERESTARTSYS)
-                       ret = -EINTR;
-               if (ret > 0 && io_net_retry(sock, flags)) {
-                       sr->len -= ret;
-                       sr->buf += ret;
-                       sr->done_io += ret;
-                       req->flags |= REQ_F_PARTIAL_IO;
-                       return -EAGAIN;
-               }
-               req_set_fail(req);
-       }
-       if (ret >= 0)
-               ret += sr->done_io;
-       else if (sr->done_io)
-               ret = sr->done_io;
-       __io_req_complete(req, issue_flags, ret, 0);
-       return 0;
-}
-
-static int __io_recvmsg_copy_hdr(struct io_kiocb *req,
-                                struct io_async_msghdr *iomsg)
-{
-       struct io_sr_msg *sr = &req->sr_msg;
-       struct iovec __user *uiov;
-       size_t iov_len;
-       int ret;
-
-       ret = __copy_msghdr_from_user(&iomsg->msg, sr->umsg,
-                                       &iomsg->uaddr, &uiov, &iov_len);
-       if (ret)
-               return ret;
-
-       if (req->flags & REQ_F_BUFFER_SELECT) {
-               if (iov_len > 1)
-                       return -EINVAL;
-               if (copy_from_user(iomsg->fast_iov, uiov, sizeof(*uiov)))
-                       return -EFAULT;
-               sr->len = iomsg->fast_iov[0].iov_len;
-               iomsg->free_iov = NULL;
-       } else {
-               iomsg->free_iov = iomsg->fast_iov;
-               ret = __import_iovec(READ, uiov, iov_len, UIO_FASTIOV,
-                                    &iomsg->free_iov, &iomsg->msg.msg_iter,
-                                    false);
-               if (ret > 0)
-                       ret = 0;
-       }
-
-       return ret;
-}
-
-#ifdef CONFIG_COMPAT
-static int __io_compat_recvmsg_copy_hdr(struct io_kiocb *req,
-                                       struct io_async_msghdr *iomsg)
-{
-       struct io_sr_msg *sr = &req->sr_msg;
-       struct compat_iovec __user *uiov;
-       compat_uptr_t ptr;
-       compat_size_t len;
-       int ret;
-
-       ret = __get_compat_msghdr(&iomsg->msg, sr->umsg_compat, &iomsg->uaddr,
-                                 &ptr, &len);
-       if (ret)
-               return ret;
-
-       uiov = compat_ptr(ptr);
-       if (req->flags & REQ_F_BUFFER_SELECT) {
-               compat_ssize_t clen;
-
-               if (len > 1)
-                       return -EINVAL;
-               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;
-               iomsg->free_iov = NULL;
-       } else {
-               iomsg->free_iov = iomsg->fast_iov;
-               ret = __import_iovec(READ, (struct iovec __user *)uiov, len,
-                                  UIO_FASTIOV, &iomsg->free_iov,
-                                  &iomsg->msg.msg_iter, true);
-               if (ret < 0)
-                       return ret;
-       }
-
-       return 0;
-}
-#endif
-
-static int io_recvmsg_copy_hdr(struct io_kiocb *req,
-                              struct io_async_msghdr *iomsg)
-{
-       iomsg->msg.msg_name = &iomsg->addr;
-
-#ifdef CONFIG_COMPAT
-       if (req->ctx->compat)
-               return __io_compat_recvmsg_copy_hdr(req, iomsg);
-#endif
-
-       return __io_recvmsg_copy_hdr(req, iomsg);
-}
-
-static int io_recvmsg_prep_async(struct io_kiocb *req)
-{
-       int ret;
-
-       ret = io_recvmsg_copy_hdr(req, req->async_data);
-       if (!ret)
-               req->flags |= REQ_F_NEED_CLEANUP;
-       return ret;
-}
-
-static int io_recvmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
-{
-       struct io_sr_msg *sr = &req->sr_msg;
-
-       if (unlikely(sqe->file_index))
-               return -EINVAL;
-
-       sr->umsg = u64_to_user_ptr(READ_ONCE(sqe->addr));
-       sr->len = READ_ONCE(sqe->len);
-       sr->flags = READ_ONCE(sqe->addr2);
-       if (sr->flags & ~IORING_RECVSEND_POLL_FIRST)
-               return -EINVAL;
-       sr->msg_flags = READ_ONCE(sqe->msg_flags) | MSG_NOSIGNAL;
-       if (sr->msg_flags & MSG_DONTWAIT)
-               req->flags |= REQ_F_NOWAIT;
-
-#ifdef CONFIG_COMPAT
-       if (req->ctx->compat)
-               sr->msg_flags |= MSG_CMSG_COMPAT;
-#endif
-       sr->done_io = 0;
-       return 0;
-}
-
-static int io_recvmsg(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_async_msghdr iomsg, *kmsg;
-       struct io_sr_msg *sr = &req->sr_msg;
-       struct socket *sock;
-       unsigned int cflags;
-       unsigned flags;
-       int ret, min_ret = 0;
-       bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK;
-
-       sock = sock_from_file(req->file);
-       if (unlikely(!sock))
-               return -ENOTSOCK;
-
-       if (req_has_async_data(req)) {
-               kmsg = req->async_data;
-       } else {
-               ret = io_recvmsg_copy_hdr(req, &iomsg);
-               if (ret)
-                       return ret;
-               kmsg = &iomsg;
-       }
-
-       if (!(req->flags & REQ_F_POLLED) &&
-           (sr->flags & IORING_RECVSEND_POLL_FIRST))
-               return io_setup_async_msg(req, kmsg);
-
-       if (io_do_buffer_select(req)) {
-               void __user *buf;
-
-               buf = io_buffer_select(req, &sr->len, issue_flags);
-               if (!buf)
-                       return -ENOBUFS;
-               kmsg->fast_iov[0].iov_base = buf;
-               kmsg->fast_iov[0].iov_len = sr->len;
-               iov_iter_init(&kmsg->msg.msg_iter, READ, kmsg->fast_iov, 1,
-                               sr->len);
-       }
-
-       flags = sr->msg_flags;
-       if (force_nonblock)
-               flags |= MSG_DONTWAIT;
-       if (flags & MSG_WAITALL)
-               min_ret = iov_iter_count(&kmsg->msg.msg_iter);
-
-       kmsg->msg.msg_get_inq = 1;
-       ret = __sys_recvmsg_sock(sock, &kmsg->msg, sr->umsg, kmsg->uaddr, flags);
-       if (ret < min_ret) {
-               if (ret == -EAGAIN && force_nonblock)
-                       return io_setup_async_msg(req, kmsg);
-               if (ret == -ERESTARTSYS)
-                       ret = -EINTR;
-               if (ret > 0 && io_net_retry(sock, flags)) {
-                       sr->done_io += ret;
-                       req->flags |= REQ_F_PARTIAL_IO;
-                       return io_setup_async_msg(req, kmsg);
-               }
-               req_set_fail(req);
-       } else if ((flags & MSG_WAITALL) && (kmsg->msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC))) {
-               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;
-       if (ret >= 0)
-               ret += sr->done_io;
-       else if (sr->done_io)
-               ret = sr->done_io;
-       cflags = io_put_kbuf(req, issue_flags);
-       if (kmsg->msg.msg_inq)
-               cflags |= IORING_CQE_F_SOCK_NONEMPTY;
-       __io_req_complete(req, issue_flags, ret, cflags);
-       return 0;
-}
-
-static int io_recv(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_sr_msg *sr = &req->sr_msg;
-       struct msghdr msg;
-       struct socket *sock;
-       struct iovec iov;
-       unsigned int cflags;
-       unsigned flags;
-       int ret, min_ret = 0;
-       bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK;
-
-       if (!(req->flags & REQ_F_POLLED) &&
-           (sr->flags & IORING_RECVSEND_POLL_FIRST))
-               return -EAGAIN;
-
-       sock = sock_from_file(req->file);
-       if (unlikely(!sock))
-               return -ENOTSOCK;
-
-       if (io_do_buffer_select(req)) {
-               void __user *buf;
-
-               buf = io_buffer_select(req, &sr->len, issue_flags);
-               if (!buf)
-                       return -ENOBUFS;
-               sr->buf = buf;
-       }
-
-       ret = import_single_range(READ, sr->buf, sr->len, &iov, &msg.msg_iter);
-       if (unlikely(ret))
-               goto out_free;
-
-       msg.msg_name = NULL;
-       msg.msg_namelen = 0;
-       msg.msg_control = NULL;
-       msg.msg_get_inq = 1;
-       msg.msg_flags = 0;
-       msg.msg_controllen = 0;
-       msg.msg_iocb = NULL;
-
-       flags = sr->msg_flags;
-       if (force_nonblock)
-               flags |= MSG_DONTWAIT;
-       if (flags & MSG_WAITALL)
-               min_ret = iov_iter_count(&msg.msg_iter);
-
-       ret = sock_recvmsg(sock, &msg, flags);
-       if (ret < min_ret) {
-               if (ret == -EAGAIN && force_nonblock)
-                       return -EAGAIN;
-               if (ret == -ERESTARTSYS)
-                       ret = -EINTR;
-               if (ret > 0 && io_net_retry(sock, flags)) {
-                       sr->len -= ret;
-                       sr->buf += ret;
-                       sr->done_io += ret;
-                       req->flags |= REQ_F_PARTIAL_IO;
-                       return -EAGAIN;
-               }
-               req_set_fail(req);
-       } else if ((flags & MSG_WAITALL) && (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC))) {
-out_free:
-               req_set_fail(req);
-       }
-
-       if (ret >= 0)
-               ret += sr->done_io;
-       else if (sr->done_io)
-               ret = sr->done_io;
-       cflags = io_put_kbuf(req, issue_flags);
-       if (msg.msg_inq)
-               cflags |= IORING_CQE_F_SOCK_NONEMPTY;
-       __io_req_complete(req, issue_flags, ret, cflags);
-       return 0;
-}
-
-static int io_accept_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
-{
-       struct io_accept *accept = &req->accept;
-       unsigned flags;
-
-       if (sqe->len || sqe->buf_index)
-               return -EINVAL;
-
-       accept->addr = u64_to_user_ptr(READ_ONCE(sqe->addr));
-       accept->addr_len = u64_to_user_ptr(READ_ONCE(sqe->addr2));
-       accept->flags = READ_ONCE(sqe->accept_flags);
-       accept->nofile = rlimit(RLIMIT_NOFILE);
-       flags = READ_ONCE(sqe->ioprio);
-       if (flags & ~IORING_ACCEPT_MULTISHOT)
-               return -EINVAL;
-
-       accept->file_slot = READ_ONCE(sqe->file_index);
-       if (accept->file_slot) {
-               if (accept->flags & SOCK_CLOEXEC)
-                       return -EINVAL;
-               if (flags & IORING_ACCEPT_MULTISHOT &&
-                   accept->file_slot != IORING_FILE_INDEX_ALLOC)
-                       return -EINVAL;
-       }
-       if (accept->flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
-               return -EINVAL;
-       if (SOCK_NONBLOCK != O_NONBLOCK && (accept->flags & SOCK_NONBLOCK))
-               accept->flags = (accept->flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
-       if (flags & IORING_ACCEPT_MULTISHOT)
-               req->flags |= REQ_F_APOLL_MULTISHOT;
-       return 0;
-}
-
-static int io_accept(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_ring_ctx *ctx = req->ctx;
-       struct io_accept *accept = &req->accept;
-       bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK;
-       unsigned int file_flags = force_nonblock ? O_NONBLOCK : 0;
-       bool fixed = !!accept->file_slot;
-       struct file *file;
-       int ret, fd;
-
-retry:
-       if (!fixed) {
-               fd = __get_unused_fd_flags(accept->flags, accept->nofile);
-               if (unlikely(fd < 0))
-                       return fd;
-       }
-       file = do_accept(req->file, file_flags, accept->addr, accept->addr_len,
-                        accept->flags);
-       if (IS_ERR(file)) {
-               if (!fixed)
-                       put_unused_fd(fd);
-               ret = PTR_ERR(file);
-               if (ret == -EAGAIN && force_nonblock) {
-                       /*
-                        * if it's multishot and polled, we don't need to
-                        * return EAGAIN to arm the poll infra since it
-                        * has already been done
-                        */
-                       if ((req->flags & IO_APOLL_MULTI_POLLED) ==
-                           IO_APOLL_MULTI_POLLED)
-                               ret = 0;
-                       return ret;
-               }
-               if (ret == -ERESTARTSYS)
-                       ret = -EINTR;
-               req_set_fail(req);
-       } else if (!fixed) {
-               fd_install(fd, file);
-               ret = fd;
-       } else {
-               ret = io_fixed_fd_install(req, issue_flags, file,
-                                               accept->file_slot);
-       }
-
-       if (!(req->flags & REQ_F_APOLL_MULTISHOT)) {
-               __io_req_complete(req, issue_flags, ret, 0);
-               return 0;
-       }
-       if (ret >= 0) {
-               bool filled;
-
-               spin_lock(&ctx->completion_lock);
-               filled = io_fill_cqe_aux(ctx, req->cqe.user_data, ret,
-                                        IORING_CQE_F_MORE);
-               io_commit_cqring(ctx);
-               spin_unlock(&ctx->completion_lock);
-               if (filled) {
-                       io_cqring_ev_posted(ctx);
-                       goto retry;
-               }
-               ret = -ECANCELED;
-       }
-
-       return ret;
-}
-
-static int io_socket_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
-{
-       struct io_socket *sock = &req->sock;
-
-       if (sqe->addr || sqe->rw_flags || sqe->buf_index)
-               return -EINVAL;
-
-       sock->domain = READ_ONCE(sqe->fd);
-       sock->type = READ_ONCE(sqe->off);
-       sock->protocol = READ_ONCE(sqe->len);
-       sock->file_slot = READ_ONCE(sqe->file_index);
-       sock->nofile = rlimit(RLIMIT_NOFILE);
-
-       sock->flags = sock->type & ~SOCK_TYPE_MASK;
-       if (sock->file_slot && (sock->flags & SOCK_CLOEXEC))
-               return -EINVAL;
-       if (sock->flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
-               return -EINVAL;
-       return 0;
-}
-
-static int io_socket(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_socket *sock = &req->sock;
-       bool fixed = !!sock->file_slot;
-       struct file *file;
-       int ret, fd;
-
-       if (!fixed) {
-               fd = __get_unused_fd_flags(sock->flags, sock->nofile);
-               if (unlikely(fd < 0))
-                       return fd;
-       }
-       file = __sys_socket_file(sock->domain, sock->type, sock->protocol);
-       if (IS_ERR(file)) {
-               if (!fixed)
-                       put_unused_fd(fd);
-               ret = PTR_ERR(file);
-               if (ret == -EAGAIN && (issue_flags & IO_URING_F_NONBLOCK))
-                       return -EAGAIN;
-               if (ret == -ERESTARTSYS)
-                       ret = -EINTR;
-               req_set_fail(req);
-       } else if (!fixed) {
-               fd_install(fd, file);
-               ret = fd;
-       } else {
-               ret = io_fixed_fd_install(req, issue_flags, file,
-                                           sock->file_slot);
-       }
-       __io_req_complete(req, issue_flags, ret, 0);
-       return 0;
-}
-
-static int io_connect_prep_async(struct io_kiocb *req)
-{
-       struct io_async_connect *io = req->async_data;
-       struct io_connect *conn = &req->connect;
-
-       return move_addr_to_kernel(conn->addr, conn->addr_len, &io->address);
-}
-
-static int io_connect_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
-{
-       struct io_connect *conn = &req->connect;
-
-       if (sqe->len || sqe->buf_index || sqe->rw_flags || sqe->splice_fd_in)
-               return -EINVAL;
-
-       conn->addr = u64_to_user_ptr(READ_ONCE(sqe->addr));
-       conn->addr_len =  READ_ONCE(sqe->addr2);
-       return 0;
-}
-
-static int io_connect(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_async_connect __io, *io;
-       unsigned file_flags;
-       int ret;
-       bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK;
-
-       if (req_has_async_data(req)) {
-               io = req->async_data;
-       } else {
-               ret = move_addr_to_kernel(req->connect.addr,
-                                               req->connect.addr_len,
-                                               &__io.address);
-               if (ret)
-                       goto out;
-               io = &__io;
-       }
-
-       file_flags = force_nonblock ? O_NONBLOCK : 0;
-
-       ret = __sys_connect_file(req->file, &io->address,
-                                       req->connect.addr_len, file_flags);
-       if ((ret == -EAGAIN || ret == -EINPROGRESS) && force_nonblock) {
-               if (req_has_async_data(req))
-                       return -EAGAIN;
-               if (io_alloc_async_data(req)) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-               memcpy(req->async_data, &__io, sizeof(__io));
-               return -EAGAIN;
-       }
-       if (ret == -ERESTARTSYS)
-               ret = -EINTR;
-out:
-       if (ret < 0)
-               req_set_fail(req);
-       __io_req_complete(req, issue_flags, ret, 0);
-       return 0;
-}
-#else /* !CONFIG_NET */
-#define IO_NETOP_FN(op)                                                        \
-static int io_##op(struct io_kiocb *req, unsigned int issue_flags)     \
-{                                                                      \
-       return -EOPNOTSUPP;                                             \
-}
-
-#define IO_NETOP_PREP(op)                                              \
-IO_NETOP_FN(op)                                                                \
-static int io_##op##_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) \
-{                                                                      \
-       return -EOPNOTSUPP;                                             \
-}                                                                      \
-
-#define IO_NETOP_PREP_ASYNC(op)                                                \
-IO_NETOP_PREP(op)                                                      \
-static int io_##op##_prep_async(struct io_kiocb *req)                  \
-{                                                                      \
-       return -EOPNOTSUPP;                                             \
-}
-
-IO_NETOP_PREP_ASYNC(sendmsg);
-IO_NETOP_PREP_ASYNC(recvmsg);
-IO_NETOP_PREP_ASYNC(connect);
-IO_NETOP_PREP(accept);
-IO_NETOP_PREP(socket);
-IO_NETOP_PREP(shutdown);
-IO_NETOP_FN(send);
-IO_NETOP_FN(recv);
-#endif /* CONFIG_NET */
-
-struct io_poll_table {
-       struct poll_table_struct pt;
-       struct io_kiocb *req;
-       int nr_entries;
-       int error;
-};
-
-#define IO_POLL_CANCEL_FLAG    BIT(31)
-#define IO_POLL_REF_MASK       GENMASK(30, 0)
-
-/*
- * If refs part of ->poll_refs (see IO_POLL_REF_MASK) is 0, it's free. We can
- * bump it and acquire ownership. It's disallowed to modify requests while not
- * owning it, that prevents from races for enqueueing task_work's and b/w
- * arming poll and wakeups.
- */
-static inline bool io_poll_get_ownership(struct io_kiocb *req)
-{
-       return !(atomic_fetch_inc(&req->poll_refs) & IO_POLL_REF_MASK);
-}
-
-static void io_poll_mark_cancelled(struct io_kiocb *req)
-{
-       atomic_or(IO_POLL_CANCEL_FLAG, &req->poll_refs);
-}
-
-static struct io_poll_iocb *io_poll_get_double(struct io_kiocb *req)
-{
-       /* pure poll stashes this in ->async_data, poll driven retry elsewhere */
-       if (req->opcode == IORING_OP_POLL_ADD)
-               return req->async_data;
-       return req->apoll->double_poll;
-}
-
-static struct io_poll_iocb *io_poll_get_single(struct io_kiocb *req)
-{
-       if (req->opcode == IORING_OP_POLL_ADD)
-               return &req->poll;
-       return &req->apoll->poll;
-}
-
-static void io_poll_req_insert(struct io_kiocb *req)
-{
-       struct io_ring_ctx *ctx = req->ctx;
-       struct hlist_head *list;
-
-       list = &ctx->cancel_hash[hash_long(req->cqe.user_data, ctx->cancel_hash_bits)];
-       hlist_add_head(&req->hash_node, list);
-}
-
-static void io_init_poll_iocb(struct io_poll_iocb *poll, __poll_t events,
-                             wait_queue_func_t wake_func)
-{
-       poll->head = NULL;
-#define IO_POLL_UNMASK (EPOLLERR|EPOLLHUP|EPOLLNVAL|EPOLLRDHUP)
-       /* mask in events that we always want/need */
-       poll->events = events | IO_POLL_UNMASK;
-       INIT_LIST_HEAD(&poll->wait.entry);
-       init_waitqueue_func_entry(&poll->wait, wake_func);
-}
-
-static inline void io_poll_remove_entry(struct io_poll_iocb *poll)
-{
-       struct wait_queue_head *head = smp_load_acquire(&poll->head);
-
-       if (head) {
-               spin_lock_irq(&head->lock);
-               list_del_init(&poll->wait.entry);
-               poll->head = NULL;
-               spin_unlock_irq(&head->lock);
-       }
-}
-
-static void io_poll_remove_entries(struct io_kiocb *req)
-{
-       /*
-        * Nothing to do if neither of those flags are set. Avoid dipping
-        * into the poll/apoll/double cachelines if we can.
-        */
-       if (!(req->flags & (REQ_F_SINGLE_POLL | REQ_F_DOUBLE_POLL)))
-               return;
-
-       /*
-        * While we hold the waitqueue lock and the waitqueue is nonempty,
-        * wake_up_pollfree() will wait for us.  However, taking the waitqueue
-        * lock in the first place can race with the waitqueue being freed.
-        *
-        * We solve this as eventpoll does: by taking advantage of the fact that
-        * all users of wake_up_pollfree() will RCU-delay the actual free.  If
-        * we enter rcu_read_lock() and see that the pointer to the queue is
-        * non-NULL, we can then lock it without the memory being freed out from
-        * under us.
-        *
-        * Keep holding rcu_read_lock() as long as we hold the queue lock, in
-        * case the caller deletes the entry from the queue, leaving it empty.
-        * In that case, only RCU prevents the queue memory from being freed.
-        */
-       rcu_read_lock();
-       if (req->flags & REQ_F_SINGLE_POLL)
-               io_poll_remove_entry(io_poll_get_single(req));
-       if (req->flags & REQ_F_DOUBLE_POLL)
-               io_poll_remove_entry(io_poll_get_double(req));
-       rcu_read_unlock();
-}
-
-static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags);
-/*
- * All poll tw should go through this. Checks for poll events, manages
- * references, does rewait, etc.
- *
- * Returns a negative error on failure. >0 when no action require, which is
- * either spurious wakeup or multishot CQE is served. 0 when it's done with
- * the request, then the mask is stored in req->cqe.res.
- */
-static int io_poll_check_events(struct io_kiocb *req, bool *locked)
-{
-       struct io_ring_ctx *ctx = req->ctx;
-       int v, ret;
-
-       /* req->task == current here, checking PF_EXITING is safe */
-       if (unlikely(req->task->flags & PF_EXITING))
-               return -ECANCELED;
-
-       do {
-               v = atomic_read(&req->poll_refs);
-
-               /* tw handler should be the owner, and so have some references */
-               if (WARN_ON_ONCE(!(v & IO_POLL_REF_MASK)))
-                       return 0;
-               if (v & IO_POLL_CANCEL_FLAG)
-                       return -ECANCELED;
-
-               if (!req->cqe.res) {
-                       struct poll_table_struct pt = { ._key = req->apoll_events };
-                       req->cqe.res = vfs_poll(req->file, &pt) & req->apoll_events;
-               }
-
-               if ((unlikely(!req->cqe.res)))
-                       continue;
-               if (req->apoll_events & EPOLLONESHOT)
-                       return 0;
-
-               /* multishot, just fill a CQE and proceed */
-               if (!(req->flags & REQ_F_APOLL_MULTISHOT)) {
-                       __poll_t mask = mangle_poll(req->cqe.res &
-                                                   req->apoll_events);
-                       bool filled;
-
-                       spin_lock(&ctx->completion_lock);
-                       filled = io_fill_cqe_aux(ctx, req->cqe.user_data,
-                                                mask, IORING_CQE_F_MORE);
-                       io_commit_cqring(ctx);
-                       spin_unlock(&ctx->completion_lock);
-                       if (filled) {
-                               io_cqring_ev_posted(ctx);
-                               continue;
-                       }
-                       return -ECANCELED;
-               }
-
-               io_tw_lock(req->ctx, locked);
-               if (unlikely(req->task->flags & PF_EXITING))
-                       return -EFAULT;
-               ret = io_issue_sqe(req,
-                                  IO_URING_F_NONBLOCK|IO_URING_F_COMPLETE_DEFER);
-               if (ret)
-                       return ret;
-
-               /*
-                * 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));
-
-       return 1;
-}
-
-static void io_poll_task_func(struct io_kiocb *req, bool *locked)
-{
-       struct io_ring_ctx *ctx = req->ctx;
-       int ret;
-
-       ret = io_poll_check_events(req, locked);
-       if (ret > 0)
-               return;
-
-       if (!ret) {
-               req->cqe.res = mangle_poll(req->cqe.res & req->poll.events);
-       } else {
-               req->cqe.res = ret;
-               req_set_fail(req);
-       }
-
-       io_poll_remove_entries(req);
-       spin_lock(&ctx->completion_lock);
-       hash_del(&req->hash_node);
-       __io_req_complete_post(req, req->cqe.res, 0);
-       io_commit_cqring(ctx);
-       spin_unlock(&ctx->completion_lock);
-       io_cqring_ev_posted(ctx);
-}
-
-static void io_apoll_task_func(struct io_kiocb *req, bool *locked)
-{
-       struct io_ring_ctx *ctx = req->ctx;
-       int ret;
-
-       ret = io_poll_check_events(req, locked);
-       if (ret > 0)
-               return;
-
-       io_poll_remove_entries(req);
-       spin_lock(&ctx->completion_lock);
-       hash_del(&req->hash_node);
-       spin_unlock(&ctx->completion_lock);
-
-       if (!ret)
-               io_req_task_submit(req, locked);
-       else
-               io_req_complete_failed(req, ret);
-}
-
-static void __io_poll_execute(struct io_kiocb *req, int mask,
-                             __poll_t __maybe_unused events)
-{
-       req->cqe.res = mask;
-       /*
-        * This is useful for poll that is armed on behalf of another
-        * request, and where the wakeup path could be on a different
-        * CPU. We want to avoid pulling in req->apoll->events for that
-        * case.
-        */
-       if (req->opcode == IORING_OP_POLL_ADD)
-               req->io_task_work.func = io_poll_task_func;
-       else
-               req->io_task_work.func = io_apoll_task_func;
-
-       trace_io_uring_task_add(req->ctx, req, req->cqe.user_data, req->opcode, mask);
-       io_req_task_work_add(req);
-}
-
-static inline void io_poll_execute(struct io_kiocb *req, int res,
-               __poll_t events)
-{
-       if (io_poll_get_ownership(req))
-               __io_poll_execute(req, res, events);
-}
-
-static void io_poll_cancel_req(struct io_kiocb *req)
-{
-       io_poll_mark_cancelled(req);
-       /* kick tw, which should complete the request */
-       io_poll_execute(req, 0, 0);
-}
-
-#define wqe_to_req(wait)       ((void *)((unsigned long) (wait)->private & ~1))
-#define wqe_is_double(wait)    ((unsigned long) (wait)->private & 1)
-#define IO_ASYNC_POLL_COMMON   (EPOLLONESHOT | EPOLLPRI)
-
-static int io_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync,
-                       void *key)
-{
-       struct io_kiocb *req = wqe_to_req(wait);
-       struct io_poll_iocb *poll = container_of(wait, struct io_poll_iocb,
-                                                wait);
-       __poll_t mask = key_to_poll(key);
-
-       if (unlikely(mask & POLLFREE)) {
-               io_poll_mark_cancelled(req);
-               /* we have to kick tw in case it's not already */
-               io_poll_execute(req, 0, poll->events);
-
-               /*
-                * If the waitqueue is being freed early but someone is already
-                * holds ownership over it, we have to tear down the request as
-                * best we can. That means immediately removing the request from
-                * its waitqueue and preventing all further accesses to the
-                * waitqueue via the request.
-                */
-               list_del_init(&poll->wait.entry);
-
-               /*
-                * Careful: this *must* be the last step, since as soon
-                * as req->head is NULL'ed out, the request can be
-                * completed and freed, since aio_poll_complete_work()
-                * will no longer need to take the waitqueue lock.
-                */
-               smp_store_release(&poll->head, NULL);
-               return 1;
-       }
-
-       /* for instances that support it check for an event match first */
-       if (mask && !(mask & (poll->events & ~IO_ASYNC_POLL_COMMON)))
-               return 0;
-
-       if (io_poll_get_ownership(req)) {
-               /* optional, saves extra locking for removal in tw handler */
-               if (mask && poll->events & EPOLLONESHOT) {
-                       list_del_init(&poll->wait.entry);
-                       poll->head = NULL;
-                       if (wqe_is_double(wait))
-                               req->flags &= ~REQ_F_DOUBLE_POLL;
-                       else
-                               req->flags &= ~REQ_F_SINGLE_POLL;
-               }
-               __io_poll_execute(req, mask, poll->events);
-       }
-       return 1;
-}
-
-static void __io_queue_proc(struct io_poll_iocb *poll, struct io_poll_table *pt,
-                           struct wait_queue_head *head,
-                           struct io_poll_iocb **poll_ptr)
-{
-       struct io_kiocb *req = pt->req;
-       unsigned long wqe_private = (unsigned long) req;
-
-       /*
-        * The file being polled uses multiple waitqueues for poll handling
-        * (e.g. one for read, one for write). Setup a separate io_poll_iocb
-        * if this happens.
-        */
-       if (unlikely(pt->nr_entries)) {
-               struct io_poll_iocb *first = poll;
-
-               /* double add on the same waitqueue head, ignore */
-               if (first->head == head)
-                       return;
-               /* already have a 2nd entry, fail a third attempt */
-               if (*poll_ptr) {
-                       if ((*poll_ptr)->head == head)
-                               return;
-                       pt->error = -EINVAL;
-                       return;
-               }
-
-               poll = kmalloc(sizeof(*poll), GFP_ATOMIC);
-               if (!poll) {
-                       pt->error = -ENOMEM;
-                       return;
-               }
-               /* mark as double wq entry */
-               wqe_private |= 1;
-               req->flags |= REQ_F_DOUBLE_POLL;
-               io_init_poll_iocb(poll, first->events, first->wait.func);
-               *poll_ptr = poll;
-               if (req->opcode == IORING_OP_POLL_ADD)
-                       req->flags |= REQ_F_ASYNC_DATA;
-       }
-
-       req->flags |= REQ_F_SINGLE_POLL;
-       pt->nr_entries++;
-       poll->head = head;
-       poll->wait.private = (void *) wqe_private;
-
-       if (poll->events & EPOLLEXCLUSIVE)
-               add_wait_queue_exclusive(head, &poll->wait);
-       else
-               add_wait_queue(head, &poll->wait);
-}
-
-static void io_poll_queue_proc(struct file *file, struct wait_queue_head *head,
-                              struct poll_table_struct *p)
-{
-       struct io_poll_table *pt = container_of(p, struct io_poll_table, pt);
-
-       __io_queue_proc(&pt->req->poll, pt, head,
-                       (struct io_poll_iocb **) &pt->req->async_data);
-}
-
-static int __io_arm_poll_handler(struct io_kiocb *req,
-                                struct io_poll_iocb *poll,
-                                struct io_poll_table *ipt, __poll_t mask)
-{
-       struct io_ring_ctx *ctx = req->ctx;
-       int v;
-
-       INIT_HLIST_NODE(&req->hash_node);
-       req->work.cancel_seq = atomic_read(&ctx->cancel_seq);
-       io_init_poll_iocb(poll, mask, io_poll_wake);
-       poll->file = req->file;
-
-       req->apoll_events = poll->events;
-
-       ipt->pt._key = mask;
-       ipt->req = req;
-       ipt->error = 0;
-       ipt->nr_entries = 0;
-
-       /*
-        * Take the ownership to delay any tw execution up until we're done
-        * with poll arming. see io_poll_get_ownership().
-        */
-       atomic_set(&req->poll_refs, 1);
-       mask = vfs_poll(req->file, &ipt->pt) & poll->events;
-
-       if (mask && (poll->events & EPOLLONESHOT)) {
-               io_poll_remove_entries(req);
-               /* no one else has access to the req, forget about the ref */
-               return mask;
-       }
-       if (!mask && unlikely(ipt->error || !ipt->nr_entries)) {
-               io_poll_remove_entries(req);
-               if (!ipt->error)
-                       ipt->error = -EINVAL;
-               return 0;
-       }
-
-       spin_lock(&ctx->completion_lock);
-       io_poll_req_insert(req);
-       spin_unlock(&ctx->completion_lock);
-
-       if (mask) {
-               /* can't multishot if failed, just queue the event we've got */
-               if (unlikely(ipt->error || !ipt->nr_entries)) {
-                       poll->events |= EPOLLONESHOT;
-                       req->apoll_events |= EPOLLONESHOT;
-                       ipt->error = 0;
-               }
-               __io_poll_execute(req, mask, poll->events);
-               return 0;
-       }
-
-       /*
-        * Release ownership. If someone tried to queue a tw while it was
-        * locked, kick it off for them.
-        */
-       v = atomic_dec_return(&req->poll_refs);
-       if (unlikely(v & IO_POLL_REF_MASK))
-               __io_poll_execute(req, 0, poll->events);
-       return 0;
-}
-
-static void io_async_queue_proc(struct file *file, struct wait_queue_head *head,
-                              struct poll_table_struct *p)
-{
-       struct io_poll_table *pt = container_of(p, struct io_poll_table, pt);
-       struct async_poll *apoll = pt->req->apoll;
-
-       __io_queue_proc(&apoll->poll, pt, head, &apoll->double_poll);
-}
-
-enum {
-       IO_APOLL_OK,
-       IO_APOLL_ABORTED,
-       IO_APOLL_READY
-};
-
-static int io_arm_poll_handler(struct io_kiocb *req, unsigned issue_flags)
-{
-       const struct io_op_def *def = &io_op_defs[req->opcode];
-       struct io_ring_ctx *ctx = req->ctx;
-       struct async_poll *apoll;
-       struct io_poll_table ipt;
-       __poll_t mask = POLLPRI | POLLERR;
-       int ret;
-
-       if (!def->pollin && !def->pollout)
-               return IO_APOLL_ABORTED;
-       if (!file_can_poll(req->file))
-               return IO_APOLL_ABORTED;
-       if ((req->flags & (REQ_F_POLLED|REQ_F_PARTIAL_IO)) == REQ_F_POLLED)
-               return IO_APOLL_ABORTED;
-       if (!(req->flags & REQ_F_APOLL_MULTISHOT))
-               mask |= EPOLLONESHOT;
-
-       if (def->pollin) {
-               mask |= EPOLLIN | EPOLLRDNORM;
-
-               /* If reading from MSG_ERRQUEUE using recvmsg, ignore POLLIN */
-               if ((req->opcode == IORING_OP_RECVMSG) &&
-                   (req->sr_msg.msg_flags & MSG_ERRQUEUE))
-                       mask &= ~EPOLLIN;
-       } else {
-               mask |= EPOLLOUT | EPOLLWRNORM;
-       }
-       if (def->poll_exclusive)
-               mask |= EPOLLEXCLUSIVE;
-       if (req->flags & REQ_F_POLLED) {
-               apoll = req->apoll;
-               kfree(apoll->double_poll);
-       } else if (!(issue_flags & IO_URING_F_UNLOCKED) &&
-                  !list_empty(&ctx->apoll_cache)) {
-               apoll = list_first_entry(&ctx->apoll_cache, struct async_poll,
-                                               poll.wait.entry);
-               list_del_init(&apoll->poll.wait.entry);
-       } else {
-               apoll = kmalloc(sizeof(*apoll), GFP_ATOMIC);
-               if (unlikely(!apoll))
-                       return IO_APOLL_ABORTED;
-       }
-       apoll->double_poll = NULL;
-       req->apoll = apoll;
-       req->flags |= REQ_F_POLLED;
-       ipt.pt._qproc = io_async_queue_proc;
-
-       io_kbuf_recycle(req, issue_flags);
-
-       ret = __io_arm_poll_handler(req, &apoll->poll, &ipt, mask);
-       if (ret || ipt.error)
-               return ret ? IO_APOLL_READY : IO_APOLL_ABORTED;
-
-       trace_io_uring_poll_arm(ctx, req, req->cqe.user_data, req->opcode,
-                               mask, apoll->poll.events);
-       return IO_APOLL_OK;
-}
-
-/*
- * Returns true if we found and killed one or more poll requests
- */
-static __cold bool io_poll_remove_all(struct io_ring_ctx *ctx,
-                                     struct task_struct *tsk, bool cancel_all)
-{
-       struct hlist_node *tmp;
-       struct io_kiocb *req;
-       bool found = false;
-       int i;
-
-       spin_lock(&ctx->completion_lock);
-       for (i = 0; i < (1U << ctx->cancel_hash_bits); i++) {
-               struct hlist_head *list;
-
-               list = &ctx->cancel_hash[i];
-               hlist_for_each_entry_safe(req, tmp, list, hash_node) {
-                       if (io_match_task_safe(req, tsk, cancel_all)) {
-                               hlist_del_init(&req->hash_node);
-                               io_poll_cancel_req(req);
-                               found = true;
-                       }
-               }
-       }
-       spin_unlock(&ctx->completion_lock);
-       return found;
-}
-
-static struct io_kiocb *io_poll_find(struct io_ring_ctx *ctx, bool poll_only,
-                                    struct io_cancel_data *cd)
-       __must_hold(&ctx->completion_lock)
-{
-       struct hlist_head *list;
-       struct io_kiocb *req;
-
-       list = &ctx->cancel_hash[hash_long(cd->data, ctx->cancel_hash_bits)];
-       hlist_for_each_entry(req, list, hash_node) {
-               if (cd->data != req->cqe.user_data)
-                       continue;
-               if (poll_only && req->opcode != IORING_OP_POLL_ADD)
-                       continue;
-               if (cd->flags & IORING_ASYNC_CANCEL_ALL) {
-                       if (cd->seq == req->work.cancel_seq)
-                               continue;
-                       req->work.cancel_seq = cd->seq;
-               }
-               return req;
-       }
-       return NULL;
-}
-
-static struct io_kiocb *io_poll_file_find(struct io_ring_ctx *ctx,
-                                         struct io_cancel_data *cd)
-       __must_hold(&ctx->completion_lock)
-{
-       struct io_kiocb *req;
-       int i;
-
-       for (i = 0; i < (1U << ctx->cancel_hash_bits); i++) {
-               struct hlist_head *list;
-
-               list = &ctx->cancel_hash[i];
-               hlist_for_each_entry(req, list, hash_node) {
-                       if (!(cd->flags & IORING_ASYNC_CANCEL_ANY) &&
-                           req->file != cd->file)
-                               continue;
-                       if (cd->seq == req->work.cancel_seq)
-                               continue;
-                       req->work.cancel_seq = cd->seq;
-                       return req;
-               }
-       }
-       return NULL;
-}
-
-static bool io_poll_disarm(struct io_kiocb *req)
-       __must_hold(&ctx->completion_lock)
-{
-       if (!io_poll_get_ownership(req))
-               return false;
-       io_poll_remove_entries(req);
-       hash_del(&req->hash_node);
-       return true;
-}
-
-static int io_poll_cancel(struct io_ring_ctx *ctx, struct io_cancel_data *cd)
-       __must_hold(&ctx->completion_lock)
-{
-       struct io_kiocb *req;
-
-       if (cd->flags & (IORING_ASYNC_CANCEL_FD|IORING_ASYNC_CANCEL_ANY))
-               req = io_poll_file_find(ctx, cd);
-       else
-               req = io_poll_find(ctx, false, cd);
-       if (!req)
-               return -ENOENT;
-       io_poll_cancel_req(req);
-       return 0;
-}
-
-static __poll_t io_poll_parse_events(const struct io_uring_sqe *sqe,
-                                    unsigned int flags)
-{
-       u32 events;
-
-       events = READ_ONCE(sqe->poll32_events);
-#ifdef __BIG_ENDIAN
-       events = swahw32(events);
-#endif
-       if (!(flags & IORING_POLL_ADD_MULTI))
-               events |= EPOLLONESHOT;
-       return demangle_poll(events) | (events & (EPOLLEXCLUSIVE|EPOLLONESHOT));
-}
-
-static int io_poll_remove_prep(struct io_kiocb *req,
-                              const struct io_uring_sqe *sqe)
-{
-       struct io_poll_update *upd = &req->poll_update;
-       u32 flags;
-
-       if (sqe->buf_index || sqe->splice_fd_in)
-               return -EINVAL;
-       flags = READ_ONCE(sqe->len);
-       if (flags & ~(IORING_POLL_UPDATE_EVENTS | IORING_POLL_UPDATE_USER_DATA |
-                     IORING_POLL_ADD_MULTI))
-               return -EINVAL;
-       /* meaningless without update */
-       if (flags == IORING_POLL_ADD_MULTI)
-               return -EINVAL;
-
-       upd->old_user_data = READ_ONCE(sqe->addr);
-       upd->update_events = flags & IORING_POLL_UPDATE_EVENTS;
-       upd->update_user_data = flags & IORING_POLL_UPDATE_USER_DATA;
-
-       upd->new_user_data = READ_ONCE(sqe->off);
-       if (!upd->update_user_data && upd->new_user_data)
-               return -EINVAL;
-       if (upd->update_events)
-               upd->events = io_poll_parse_events(sqe, flags);
-       else if (sqe->poll32_events)
-               return -EINVAL;
-
-       return 0;
-}
-
-static int io_poll_add_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
-{
-       struct io_poll_iocb *poll = &req->poll;
-       u32 flags;
-
-       if (sqe->buf_index || sqe->off || sqe->addr)
-               return -EINVAL;
-       flags = READ_ONCE(sqe->len);
-       if (flags & ~IORING_POLL_ADD_MULTI)
-               return -EINVAL;
-       if ((flags & IORING_POLL_ADD_MULTI) && (req->flags & REQ_F_CQE_SKIP))
-               return -EINVAL;
-
-       io_req_set_refcount(req);
-       poll->events = io_poll_parse_events(sqe, flags);
-       return 0;
-}
-
-static int io_poll_add(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_poll_iocb *poll = &req->poll;
-       struct io_poll_table ipt;
-       int ret;
-
-       ipt.pt._qproc = io_poll_queue_proc;
-
-       ret = __io_arm_poll_handler(req, &req->poll, &ipt, poll->events);
-       if (!ret && ipt.error)
-               req_set_fail(req);
-       ret = ret ?: ipt.error;
-       if (ret)
-               __io_req_complete(req, issue_flags, ret, 0);
-       return 0;
-}
-
-static int io_poll_remove(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_cancel_data cd = { .data = req->poll_update.old_user_data, };
-       struct io_ring_ctx *ctx = req->ctx;
-       struct io_kiocb *preq;
-       int ret2, ret = 0;
-       bool locked;
-
-       spin_lock(&ctx->completion_lock);
-       preq = io_poll_find(ctx, true, &cd);
-       if (!preq || !io_poll_disarm(preq)) {
-               spin_unlock(&ctx->completion_lock);
-               ret = preq ? -EALREADY : -ENOENT;
-               goto out;
-       }
-       spin_unlock(&ctx->completion_lock);
-
-       if (req->poll_update.update_events || req->poll_update.update_user_data) {
-               /* only mask one event flags, keep behavior flags */
-               if (req->poll_update.update_events) {
-                       preq->poll.events &= ~0xffff;
-                       preq->poll.events |= req->poll_update.events & 0xffff;
-                       preq->poll.events |= IO_POLL_UNMASK;
-               }
-               if (req->poll_update.update_user_data)
-                       preq->cqe.user_data = req->poll_update.new_user_data;
-
-               ret2 = io_poll_add(preq, issue_flags);
-               /* successfully updated, don't complete poll request */
-               if (!ret2)
-                       goto out;
-       }
-
-       req_set_fail(preq);
-       preq->cqe.res = -ECANCELED;
-       locked = !(issue_flags & IO_URING_F_UNLOCKED);
-       io_req_task_complete(preq, &locked);
-out:
-       if (ret < 0)
-               req_set_fail(req);
-       /* complete update request, we're done with it */
-       __io_req_complete(req, issue_flags, ret, 0);
-       return 0;
-}
-
-static enum hrtimer_restart io_timeout_fn(struct hrtimer *timer)
-{
-       struct io_timeout_data *data = container_of(timer,
-                                               struct io_timeout_data, timer);
-       struct io_kiocb *req = data->req;
-       struct io_ring_ctx *ctx = req->ctx;
-       unsigned long flags;
-
-       spin_lock_irqsave(&ctx->timeout_lock, flags);
-       list_del_init(&req->timeout.list);
-       atomic_set(&req->ctx->cq_timeouts,
-               atomic_read(&req->ctx->cq_timeouts) + 1);
-       spin_unlock_irqrestore(&ctx->timeout_lock, flags);
-
-       if (!(data->flags & IORING_TIMEOUT_ETIME_SUCCESS))
-               req_set_fail(req);
-
-       req->cqe.res = -ETIME;
-       req->io_task_work.func = io_req_task_complete;
-       io_req_task_work_add(req);
-       return HRTIMER_NORESTART;
-}
-
-static struct io_kiocb *io_timeout_extract(struct io_ring_ctx *ctx,
-                                          struct io_cancel_data *cd)
-       __must_hold(&ctx->timeout_lock)
-{
-       struct io_timeout_data *io;
-       struct io_kiocb *req;
-       bool found = false;
-
-       list_for_each_entry(req, &ctx->timeout_list, timeout.list) {
-               if (!(cd->flags & IORING_ASYNC_CANCEL_ANY) &&
-                   cd->data != req->cqe.user_data)
-                       continue;
-               if (cd->flags & (IORING_ASYNC_CANCEL_ALL|IORING_ASYNC_CANCEL_ANY)) {
-                       if (cd->seq == req->work.cancel_seq)
-                               continue;
-                       req->work.cancel_seq = cd->seq;
-               }
-               found = true;
-               break;
-       }
-       if (!found)
-               return ERR_PTR(-ENOENT);
-
-       io = req->async_data;
-       if (hrtimer_try_to_cancel(&io->timer) == -1)
-               return ERR_PTR(-EALREADY);
-       list_del_init(&req->timeout.list);
-       return req;
-}
-
-static int io_timeout_cancel(struct io_ring_ctx *ctx, struct io_cancel_data *cd)
-       __must_hold(&ctx->completion_lock)
-{
-       struct io_kiocb *req;
-
-       spin_lock_irq(&ctx->timeout_lock);
-       req = io_timeout_extract(ctx, cd);
-       spin_unlock_irq(&ctx->timeout_lock);
-
-       if (IS_ERR(req))
-               return PTR_ERR(req);
-       io_req_task_queue_fail(req, -ECANCELED);
-       return 0;
-}
-
-static clockid_t io_timeout_get_clock(struct io_timeout_data *data)
-{
-       switch (data->flags & IORING_TIMEOUT_CLOCK_MASK) {
-       case IORING_TIMEOUT_BOOTTIME:
-               return CLOCK_BOOTTIME;
-       case IORING_TIMEOUT_REALTIME:
-               return CLOCK_REALTIME;
-       default:
-               /* can't happen, vetted at prep time */
-               WARN_ON_ONCE(1);
-               fallthrough;
-       case 0:
-               return CLOCK_MONOTONIC;
-       }
-}
-
-static int io_linked_timeout_update(struct io_ring_ctx *ctx, __u64 user_data,
-                                   struct timespec64 *ts, enum hrtimer_mode mode)
-       __must_hold(&ctx->timeout_lock)
-{
-       struct io_timeout_data *io;
-       struct io_kiocb *req;
-       bool found = false;
-
-       list_for_each_entry(req, &ctx->ltimeout_list, timeout.list) {
-               found = user_data == req->cqe.user_data;
-               if (found)
-                       break;
-       }
-       if (!found)
-               return -ENOENT;
-
-       io = req->async_data;
-       if (hrtimer_try_to_cancel(&io->timer) == -1)
-               return -EALREADY;
-       hrtimer_init(&io->timer, io_timeout_get_clock(io), mode);
-       io->timer.function = io_link_timeout_fn;
-       hrtimer_start(&io->timer, timespec64_to_ktime(*ts), mode);
-       return 0;
-}
-
-static int io_timeout_update(struct io_ring_ctx *ctx, __u64 user_data,
-                            struct timespec64 *ts, enum hrtimer_mode mode)
-       __must_hold(&ctx->timeout_lock)
-{
-       struct io_cancel_data cd = { .data = user_data, };
-       struct io_kiocb *req = io_timeout_extract(ctx, &cd);
-       struct io_timeout_data *data;
-
-       if (IS_ERR(req))
-               return PTR_ERR(req);
-
-       req->timeout.off = 0; /* noseq */
-       data = req->async_data;
-       list_add_tail(&req->timeout.list, &ctx->timeout_list);
-       hrtimer_init(&data->timer, io_timeout_get_clock(data), mode);
-       data->timer.function = io_timeout_fn;
-       hrtimer_start(&data->timer, timespec64_to_ktime(*ts), mode);
-       return 0;
-}
-
-static int io_timeout_remove_prep(struct io_kiocb *req,
-                                 const struct io_uring_sqe *sqe)
-{
-       struct io_timeout_rem *tr = &req->timeout_rem;
-
-       if (unlikely(req->flags & (REQ_F_FIXED_FILE | REQ_F_BUFFER_SELECT)))
-               return -EINVAL;
-       if (sqe->buf_index || sqe->len || sqe->splice_fd_in)
-               return -EINVAL;
-
-       tr->ltimeout = false;
-       tr->addr = READ_ONCE(sqe->addr);
-       tr->flags = READ_ONCE(sqe->timeout_flags);
-       if (tr->flags & IORING_TIMEOUT_UPDATE_MASK) {
-               if (hweight32(tr->flags & IORING_TIMEOUT_CLOCK_MASK) > 1)
-                       return -EINVAL;
-               if (tr->flags & IORING_LINK_TIMEOUT_UPDATE)
-                       tr->ltimeout = true;
-               if (tr->flags & ~(IORING_TIMEOUT_UPDATE_MASK|IORING_TIMEOUT_ABS))
-                       return -EINVAL;
-               if (get_timespec64(&tr->ts, u64_to_user_ptr(sqe->addr2)))
-                       return -EFAULT;
-               if (tr->ts.tv_sec < 0 || tr->ts.tv_nsec < 0)
-                       return -EINVAL;
-       } else if (tr->flags) {
-               /* timeout removal doesn't support flags */
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static inline enum hrtimer_mode io_translate_timeout_mode(unsigned int flags)
-{
-       return (flags & IORING_TIMEOUT_ABS) ? HRTIMER_MODE_ABS
-                                           : HRTIMER_MODE_REL;
-}
-
-/*
- * Remove or update an existing timeout command
- */
-static int io_timeout_remove(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_timeout_rem *tr = &req->timeout_rem;
-       struct io_ring_ctx *ctx = req->ctx;
-       int ret;
-
-       if (!(req->timeout_rem.flags & IORING_TIMEOUT_UPDATE)) {
-               struct io_cancel_data cd = { .data = tr->addr, };
-
-               spin_lock(&ctx->completion_lock);
-               ret = io_timeout_cancel(ctx, &cd);
-               spin_unlock(&ctx->completion_lock);
-       } else {
-               enum hrtimer_mode mode = io_translate_timeout_mode(tr->flags);
-
-               spin_lock_irq(&ctx->timeout_lock);
-               if (tr->ltimeout)
-                       ret = io_linked_timeout_update(ctx, tr->addr, &tr->ts, mode);
-               else
-                       ret = io_timeout_update(ctx, tr->addr, &tr->ts, mode);
-               spin_unlock_irq(&ctx->timeout_lock);
-       }
-
-       if (ret < 0)
-               req_set_fail(req);
-       io_req_complete_post(req, ret, 0);
-       return 0;
-}
-
-static int __io_timeout_prep(struct io_kiocb *req,
-                            const struct io_uring_sqe *sqe,
-                            bool is_timeout_link)
-{
-       struct io_timeout_data *data;
-       unsigned flags;
-       u32 off = READ_ONCE(sqe->off);
-
-       if (sqe->buf_index || sqe->len != 1 || sqe->splice_fd_in)
-               return -EINVAL;
-       if (off && is_timeout_link)
-               return -EINVAL;
-       flags = READ_ONCE(sqe->timeout_flags);
-       if (flags & ~(IORING_TIMEOUT_ABS | IORING_TIMEOUT_CLOCK_MASK |
-                     IORING_TIMEOUT_ETIME_SUCCESS))
-               return -EINVAL;
-       /* more than one clock specified is invalid, obviously */
-       if (hweight32(flags & IORING_TIMEOUT_CLOCK_MASK) > 1)
-               return -EINVAL;
-
-       INIT_LIST_HEAD(&req->timeout.list);
-       req->timeout.off = off;
-       if (unlikely(off && !req->ctx->off_timeout_used))
-               req->ctx->off_timeout_used = true;
-
-       if (WARN_ON_ONCE(req_has_async_data(req)))
-               return -EFAULT;
-       if (io_alloc_async_data(req))
-               return -ENOMEM;
-
-       data = req->async_data;
-       data->req = req;
-       data->flags = flags;
-
-       if (get_timespec64(&data->ts, u64_to_user_ptr(sqe->addr)))
-               return -EFAULT;
-
-       if (data->ts.tv_sec < 0 || data->ts.tv_nsec < 0)
-               return -EINVAL;
-
-       INIT_LIST_HEAD(&req->timeout.list);
-       data->mode = io_translate_timeout_mode(flags);
-       hrtimer_init(&data->timer, io_timeout_get_clock(data), data->mode);
-
-       if (is_timeout_link) {
-               struct io_submit_link *link = &req->ctx->submit_state.link;
-
-               if (!link->head)
-                       return -EINVAL;
-               if (link->last->opcode == IORING_OP_LINK_TIMEOUT)
-                       return -EINVAL;
-               req->timeout.head = link->last;
-               link->last->flags |= REQ_F_ARM_LTIMEOUT;
-       }
-       return 0;
-}
-
-static int io_timeout_prep(struct io_kiocb *req,
-                          const struct io_uring_sqe *sqe)
-{
-       return __io_timeout_prep(req, sqe, false);
-}
-
-static int io_link_timeout_prep(struct io_kiocb *req,
-                               const struct io_uring_sqe *sqe)
-{
-       return __io_timeout_prep(req, sqe, true);
-}
-
-static int io_timeout(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_ring_ctx *ctx = req->ctx;
-       struct io_timeout_data *data = req->async_data;
-       struct list_head *entry;
-       u32 tail, off = req->timeout.off;
-
-       spin_lock_irq(&ctx->timeout_lock);
-
-       /*
-        * sqe->off holds how many events that need to occur for this
-        * timeout event to be satisfied. If it isn't set, then this is
-        * a pure timeout request, sequence isn't used.
-        */
-       if (io_is_timeout_noseq(req)) {
-               entry = ctx->timeout_list.prev;
-               goto add;
-       }
-
-       tail = ctx->cached_cq_tail - atomic_read(&ctx->cq_timeouts);
-       req->timeout.target_seq = tail + off;
-
-       /* Update the last seq here in case io_flush_timeouts() hasn't.
-        * This is safe because ->completion_lock is held, and submissions
-        * and completions are never mixed in the same ->completion_lock section.
-        */
-       ctx->cq_last_tm_flush = tail;
-
-       /*
-        * Insertion sort, ensuring the first entry in the list is always
-        * the one we need first.
-        */
-       list_for_each_prev(entry, &ctx->timeout_list) {
-               struct io_kiocb *nxt = list_entry(entry, struct io_kiocb,
-                                                 timeout.list);
-
-               if (io_is_timeout_noseq(nxt))
-                       continue;
-               /* nxt.seq is behind @tail, otherwise would've been completed */
-               if (off >= nxt->timeout.target_seq - tail)
-                       break;
-       }
-add:
-       list_add(&req->timeout.list, entry);
-       data->timer.function = io_timeout_fn;
-       hrtimer_start(&data->timer, timespec64_to_ktime(data->ts), data->mode);
-       spin_unlock_irq(&ctx->timeout_lock);
-       return 0;
-}
-
-static bool io_cancel_cb(struct io_wq_work *work, void *data)
-{
-       struct io_kiocb *req = container_of(work, struct io_kiocb, work);
-       struct io_cancel_data *cd = data;
-
-       if (req->ctx != cd->ctx)
-               return false;
-       if (cd->flags & IORING_ASYNC_CANCEL_ANY) {
-               ;
-       } else if (cd->flags & IORING_ASYNC_CANCEL_FD) {
-               if (req->file != cd->file)
-                       return false;
-       } else {
-               if (req->cqe.user_data != cd->data)
-                       return false;
-       }
-       if (cd->flags & (IORING_ASYNC_CANCEL_ALL|IORING_ASYNC_CANCEL_ANY)) {
-               if (cd->seq == req->work.cancel_seq)
-                       return false;
-               req->work.cancel_seq = cd->seq;
-       }
-       return true;
-}
-
-static int io_async_cancel_one(struct io_uring_task *tctx,
-                              struct io_cancel_data *cd)
-{
-       enum io_wq_cancel cancel_ret;
-       int ret = 0;
-       bool all;
-
-       if (!tctx || !tctx->io_wq)
-               return -ENOENT;
-
-       all = cd->flags & (IORING_ASYNC_CANCEL_ALL|IORING_ASYNC_CANCEL_ANY);
-       cancel_ret = io_wq_cancel_cb(tctx->io_wq, io_cancel_cb, cd, all);
-       switch (cancel_ret) {
-       case IO_WQ_CANCEL_OK:
-               ret = 0;
-               break;
-       case IO_WQ_CANCEL_RUNNING:
-               ret = -EALREADY;
-               break;
-       case IO_WQ_CANCEL_NOTFOUND:
-               ret = -ENOENT;
-               break;
-       }
-
-       return ret;
-}
-
-static int io_try_cancel(struct io_kiocb *req, struct io_cancel_data *cd)
-{
-       struct io_ring_ctx *ctx = req->ctx;
-       int ret;
-
-       WARN_ON_ONCE(!io_wq_current_is_worker() && req->task != current);
-
-       ret = io_async_cancel_one(req->task->io_uring, cd);
-       /*
-        * Fall-through even for -EALREADY, as we may have poll armed
-        * that need unarming.
-        */
-       if (!ret)
-               return 0;
-
-       spin_lock(&ctx->completion_lock);
-       ret = io_poll_cancel(ctx, cd);
-       if (ret != -ENOENT)
-               goto out;
-       if (!(cd->flags & IORING_ASYNC_CANCEL_FD))
-               ret = io_timeout_cancel(ctx, cd);
-out:
-       spin_unlock(&ctx->completion_lock);
-       return ret;
-}
-
-#define CANCEL_FLAGS   (IORING_ASYNC_CANCEL_ALL | IORING_ASYNC_CANCEL_FD | \
-                        IORING_ASYNC_CANCEL_ANY)
-
-static int io_async_cancel_prep(struct io_kiocb *req,
-                               const struct io_uring_sqe *sqe)
-{
-       if (unlikely(req->flags & REQ_F_BUFFER_SELECT))
-               return -EINVAL;
-       if (sqe->off || sqe->len || sqe->splice_fd_in)
-               return -EINVAL;
-
-       req->cancel.addr = READ_ONCE(sqe->addr);
-       req->cancel.flags = READ_ONCE(sqe->cancel_flags);
-       if (req->cancel.flags & ~CANCEL_FLAGS)
-               return -EINVAL;
-       if (req->cancel.flags & IORING_ASYNC_CANCEL_FD) {
-               if (req->cancel.flags & IORING_ASYNC_CANCEL_ANY)
-                       return -EINVAL;
-               req->cancel.fd = READ_ONCE(sqe->fd);
-       }
-
-       return 0;
-}
-
-static int __io_async_cancel(struct io_cancel_data *cd, struct io_kiocb *req,
-                            unsigned int issue_flags)
-{
-       bool all = cd->flags & (IORING_ASYNC_CANCEL_ALL|IORING_ASYNC_CANCEL_ANY);
-       struct io_ring_ctx *ctx = cd->ctx;
-       struct io_tctx_node *node;
-       int ret, nr = 0;
-
-       do {
-               ret = io_try_cancel(req, cd);
-               if (ret == -ENOENT)
-                       break;
-               if (!all)
-                       return ret;
-               nr++;
-       } while (1);
-
-       /* slow path, try all io-wq's */
-       io_ring_submit_lock(ctx, issue_flags);
-       ret = -ENOENT;
-       list_for_each_entry(node, &ctx->tctx_list, ctx_node) {
-               struct io_uring_task *tctx = node->task->io_uring;
-
-               ret = io_async_cancel_one(tctx, cd);
-               if (ret != -ENOENT) {
-                       if (!all)
-                               break;
-                       nr++;
-               }
-       }
-       io_ring_submit_unlock(ctx, issue_flags);
-       return all ? nr : ret;
-}
-
-static int io_async_cancel(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_cancel_data cd = {
-               .ctx    = req->ctx,
-               .data   = req->cancel.addr,
-               .flags  = req->cancel.flags,
-               .seq    = atomic_inc_return(&req->ctx->cancel_seq),
-       };
-       int ret;
-
-       if (cd.flags & IORING_ASYNC_CANCEL_FD) {
-               if (req->flags & REQ_F_FIXED_FILE)
-                       req->file = io_file_get_fixed(req, req->cancel.fd,
-                                                       issue_flags);
-               else
-                       req->file = io_file_get_normal(req, req->cancel.fd);
-               if (!req->file) {
-                       ret = -EBADF;
-                       goto done;
-               }
-               cd.file = req->file;
-       }
-
-       ret = __io_async_cancel(&cd, req, issue_flags);
-done:
-       if (ret < 0)
-               req_set_fail(req);
-       io_req_complete_post(req, ret, 0);
-       return 0;
-}
-
-static int io_files_update_prep(struct io_kiocb *req,
-                               const struct io_uring_sqe *sqe)
-{
-       if (unlikely(req->flags & (REQ_F_FIXED_FILE | REQ_F_BUFFER_SELECT)))
-               return -EINVAL;
-       if (sqe->rw_flags || sqe->splice_fd_in)
-               return -EINVAL;
-
-       req->rsrc_update.offset = READ_ONCE(sqe->off);
-       req->rsrc_update.nr_args = READ_ONCE(sqe->len);
-       if (!req->rsrc_update.nr_args)
-               return -EINVAL;
-       req->rsrc_update.arg = READ_ONCE(sqe->addr);
-       return 0;
-}
-
-static int io_files_update_with_index_alloc(struct io_kiocb *req,
-                                           unsigned int issue_flags)
-{
-       __s32 __user *fds = u64_to_user_ptr(req->rsrc_update.arg);
-       unsigned int done;
-       struct file *file;
-       int ret, fd;
-
-       for (done = 0; done < req->rsrc_update.nr_args; done++) {
-               if (copy_from_user(&fd, &fds[done], sizeof(fd))) {
-                       ret = -EFAULT;
-                       break;
-               }
-
-               file = fget(fd);
-               if (!file) {
-                       ret = -EBADF;
-                       break;
-               }
-               ret = io_fixed_fd_install(req, issue_flags, file,
-                                         IORING_FILE_INDEX_ALLOC);
-               if (ret < 0)
-                       break;
-               if (copy_to_user(&fds[done], &ret, sizeof(ret))) {
-                       __io_close_fixed(req, issue_flags, ret);
-                       ret = -EFAULT;
-                       break;
-               }
-       }
-
-       if (done)
-               return done;
-       return ret;
-}
-
-static int io_files_update(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_ring_ctx *ctx = req->ctx;
-       struct io_uring_rsrc_update2 up;
-       int ret;
-
-       up.offset = req->rsrc_update.offset;
-       up.data = req->rsrc_update.arg;
-       up.nr = 0;
-       up.tags = 0;
-       up.resv = 0;
-       up.resv2 = 0;
-
-       if (req->rsrc_update.offset == IORING_FILE_INDEX_ALLOC) {
-               ret = io_files_update_with_index_alloc(req, issue_flags);
-       } else {
-               io_ring_submit_lock(ctx, issue_flags);
-               ret = __io_register_rsrc_update(ctx, IORING_RSRC_FILE,
-                               &up, req->rsrc_update.nr_args);
-               io_ring_submit_unlock(ctx, issue_flags);
-       }
-
-       if (ret < 0)
-               req_set_fail(req);
-       __io_req_complete(req, issue_flags, ret, 0);
-       return 0;
-}
-
-static int io_req_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
-{
-       switch (req->opcode) {
-       case IORING_OP_NOP:
-               return io_nop_prep(req, sqe);
-       case IORING_OP_READV:
-       case IORING_OP_READ_FIXED:
-       case IORING_OP_READ:
-       case IORING_OP_WRITEV:
-       case IORING_OP_WRITE_FIXED:
-       case IORING_OP_WRITE:
-               return io_prep_rw(req, sqe);
-       case IORING_OP_POLL_ADD:
-               return io_poll_add_prep(req, sqe);
-       case IORING_OP_POLL_REMOVE:
-               return io_poll_remove_prep(req, sqe);
-       case IORING_OP_FSYNC:
-               return io_fsync_prep(req, sqe);
-       case IORING_OP_SYNC_FILE_RANGE:
-               return io_sfr_prep(req, sqe);
-       case IORING_OP_SENDMSG:
-       case IORING_OP_SEND:
-               return io_sendmsg_prep(req, sqe);
-       case IORING_OP_RECVMSG:
-       case IORING_OP_RECV:
-               return io_recvmsg_prep(req, sqe);
-       case IORING_OP_CONNECT:
-               return io_connect_prep(req, sqe);
-       case IORING_OP_TIMEOUT:
-               return io_timeout_prep(req, sqe);
-       case IORING_OP_TIMEOUT_REMOVE:
-               return io_timeout_remove_prep(req, sqe);
-       case IORING_OP_ASYNC_CANCEL:
-               return io_async_cancel_prep(req, sqe);
-       case IORING_OP_LINK_TIMEOUT:
-               return io_link_timeout_prep(req, sqe);
-       case IORING_OP_ACCEPT:
-               return io_accept_prep(req, sqe);
-       case IORING_OP_FALLOCATE:
-               return io_fallocate_prep(req, sqe);
-       case IORING_OP_OPENAT:
-               return io_openat_prep(req, sqe);
-       case IORING_OP_CLOSE:
-               return io_close_prep(req, sqe);
-       case IORING_OP_FILES_UPDATE:
-               return io_files_update_prep(req, sqe);
-       case IORING_OP_STATX:
-               return io_statx_prep(req, sqe);
-       case IORING_OP_FADVISE:
-               return io_fadvise_prep(req, sqe);
-       case IORING_OP_MADVISE:
-               return io_madvise_prep(req, sqe);
-       case IORING_OP_OPENAT2:
-               return io_openat2_prep(req, sqe);
-       case IORING_OP_EPOLL_CTL:
-               return io_epoll_ctl_prep(req, sqe);
-       case IORING_OP_SPLICE:
-               return io_splice_prep(req, sqe);
-       case IORING_OP_PROVIDE_BUFFERS:
-               return io_provide_buffers_prep(req, sqe);
-       case IORING_OP_REMOVE_BUFFERS:
-               return io_remove_buffers_prep(req, sqe);
-       case IORING_OP_TEE:
-               return io_tee_prep(req, sqe);
-       case IORING_OP_SHUTDOWN:
-               return io_shutdown_prep(req, sqe);
-       case IORING_OP_RENAMEAT:
-               return io_renameat_prep(req, sqe);
-       case IORING_OP_UNLINKAT:
-               return io_unlinkat_prep(req, sqe);
-       case IORING_OP_MKDIRAT:
-               return io_mkdirat_prep(req, sqe);
-       case IORING_OP_SYMLINKAT:
-               return io_symlinkat_prep(req, sqe);
-       case IORING_OP_LINKAT:
-               return io_linkat_prep(req, sqe);
-       case IORING_OP_MSG_RING:
-               return io_msg_ring_prep(req, sqe);
-       case IORING_OP_FSETXATTR:
-               return io_fsetxattr_prep(req, sqe);
-       case IORING_OP_SETXATTR:
-               return io_setxattr_prep(req, sqe);
-       case IORING_OP_FGETXATTR:
-               return io_fgetxattr_prep(req, sqe);
-       case IORING_OP_GETXATTR:
-               return io_getxattr_prep(req, sqe);
-       case IORING_OP_SOCKET:
-               return io_socket_prep(req, sqe);
-       case IORING_OP_URING_CMD:
-               return io_uring_cmd_prep(req, sqe);
-       }
-
-       printk_once(KERN_WARNING "io_uring: unhandled opcode %d\n",
-                       req->opcode);
-       return -EINVAL;
-}
-
-static int io_req_prep_async(struct io_kiocb *req)
-{
-       const struct io_op_def *def = &io_op_defs[req->opcode];
-
-       /* assign early for deferred execution for non-fixed file */
-       if (def->needs_file && !(req->flags & REQ_F_FIXED_FILE))
-               req->file = io_file_get_normal(req, req->cqe.fd);
-       if (!def->needs_async_setup)
-               return 0;
-       if (WARN_ON_ONCE(req_has_async_data(req)))
-               return -EFAULT;
-       if (io_alloc_async_data(req))
-               return -EAGAIN;
-
-       switch (req->opcode) {
-       case IORING_OP_READV:
-               return io_readv_prep_async(req);
-       case IORING_OP_WRITEV:
-               return io_writev_prep_async(req);
-       case IORING_OP_SENDMSG:
-               return io_sendmsg_prep_async(req);
-       case IORING_OP_RECVMSG:
-               return io_recvmsg_prep_async(req);
-       case IORING_OP_CONNECT:
-               return io_connect_prep_async(req);
-       case IORING_OP_URING_CMD:
-               return io_uring_cmd_prep_async(req);
-       }
-       printk_once(KERN_WARNING "io_uring: prep_async() bad opcode %d\n",
-                   req->opcode);
-       return -EFAULT;
-}
-
-static u32 io_get_sequence(struct io_kiocb *req)
-{
-       u32 seq = req->ctx->cached_sq_head;
-       struct io_kiocb *cur;
-
-       /* need original cached_sq_head, but it was increased for each req */
-       io_for_each_link(cur, req)
-               seq--;
-       return seq;
-}
-
-static __cold void io_drain_req(struct io_kiocb *req)
-{
-       struct io_ring_ctx *ctx = req->ctx;
-       struct io_defer_entry *de;
-       int ret;
-       u32 seq = io_get_sequence(req);
-
-       /* Still need defer if there is pending req in defer list. */
-       spin_lock(&ctx->completion_lock);
-       if (!req_need_defer(req, seq) && list_empty_careful(&ctx->defer_list)) {
-               spin_unlock(&ctx->completion_lock);
-queue:
-               ctx->drain_active = false;
-               io_req_task_queue(req);
-               return;
-       }
-       spin_unlock(&ctx->completion_lock);
-
-       ret = io_req_prep_async(req);
-       if (ret) {
-fail:
-               io_req_complete_failed(req, ret);
-               return;
-       }
-       io_prep_async_link(req);
-       de = kmalloc(sizeof(*de), GFP_KERNEL);
-       if (!de) {
-               ret = -ENOMEM;
-               goto fail;
-       }
-
-       spin_lock(&ctx->completion_lock);
-       if (!req_need_defer(req, seq) && list_empty(&ctx->defer_list)) {
-               spin_unlock(&ctx->completion_lock);
-               kfree(de);
-               goto queue;
-       }
-
-       trace_io_uring_defer(ctx, req, req->cqe.user_data, req->opcode);
-       de->req = req;
-       de->seq = seq;
-       list_add_tail(&de->list, &ctx->defer_list);
-       spin_unlock(&ctx->completion_lock);
-}
-
-static void io_clean_op(struct io_kiocb *req)
-{
-       if (req->flags & REQ_F_BUFFER_SELECTED) {
-               spin_lock(&req->ctx->completion_lock);
-               io_put_kbuf_comp(req);
-               spin_unlock(&req->ctx->completion_lock);
-       }
-
-       if (req->flags & REQ_F_NEED_CLEANUP) {
-               switch (req->opcode) {
-               case IORING_OP_READV:
-               case IORING_OP_READ_FIXED:
-               case IORING_OP_READ:
-               case IORING_OP_WRITEV:
-               case IORING_OP_WRITE_FIXED:
-               case IORING_OP_WRITE: {
-                       struct io_async_rw *io = req->async_data;
-
-                       kfree(io->free_iovec);
-                       break;
-                       }
-               case IORING_OP_RECVMSG:
-               case IORING_OP_SENDMSG: {
-                       struct io_async_msghdr *io = req->async_data;
-
-                       kfree(io->free_iov);
-                       break;
-                       }
-               case IORING_OP_OPENAT:
-               case IORING_OP_OPENAT2:
-                       if (req->open.filename)
-                               putname(req->open.filename);
-                       break;
-               case IORING_OP_RENAMEAT:
-                       putname(req->rename.oldpath);
-                       putname(req->rename.newpath);
-                       break;
-               case IORING_OP_UNLINKAT:
-                       putname(req->unlink.filename);
-                       break;
-               case IORING_OP_MKDIRAT:
-                       putname(req->mkdir.filename);
-                       break;
-               case IORING_OP_SYMLINKAT:
-                       putname(req->symlink.oldpath);
-                       putname(req->symlink.newpath);
-                       break;
-               case IORING_OP_LINKAT:
-                       putname(req->hardlink.oldpath);
-                       putname(req->hardlink.newpath);
-                       break;
-               case IORING_OP_STATX:
-                       if (req->statx.filename)
-                               putname(req->statx.filename);
-                       break;
-               case IORING_OP_SETXATTR:
-               case IORING_OP_FSETXATTR:
-               case IORING_OP_GETXATTR:
-               case IORING_OP_FGETXATTR:
-                       __io_xattr_finish(req);
-                       break;
-               }
-       }
-       if ((req->flags & REQ_F_POLLED) && req->apoll) {
-               kfree(req->apoll->double_poll);
-               kfree(req->apoll);
-               req->apoll = NULL;
-       }
-       if (req->flags & REQ_F_INFLIGHT) {
-               struct io_uring_task *tctx = req->task->io_uring;
-
-               atomic_dec(&tctx->inflight_tracked);
-       }
-       if (req->flags & REQ_F_CREDS)
-               put_cred(req->creds);
-       if (req->flags & REQ_F_ASYNC_DATA) {
-               kfree(req->async_data);
-               req->async_data = NULL;
-       }
-       req->flags &= ~IO_REQ_CLEAN_FLAGS;
-}
-
-static bool io_assign_file(struct io_kiocb *req, unsigned int issue_flags)
-{
-       if (req->file || !io_op_defs[req->opcode].needs_file)
-               return true;
-
-       if (req->flags & REQ_F_FIXED_FILE)
-               req->file = io_file_get_fixed(req, req->cqe.fd, issue_flags);
-       else
-               req->file = io_file_get_normal(req, req->cqe.fd);
-
-       return !!req->file;
-}
-
-static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags)
-{
-       const struct io_op_def *def = &io_op_defs[req->opcode];
-       const struct cred *creds = NULL;
-       int ret;
-
-       if (unlikely(!io_assign_file(req, issue_flags)))
-               return -EBADF;
-
-       if (unlikely((req->flags & REQ_F_CREDS) && req->creds != current_cred()))
-               creds = override_creds(req->creds);
-
-       if (!def->audit_skip)
-               audit_uring_entry(req->opcode);
-
-       switch (req->opcode) {
-       case IORING_OP_NOP:
-               ret = io_nop(req, issue_flags);
-               break;
-       case IORING_OP_READV:
-       case IORING_OP_READ_FIXED:
-       case IORING_OP_READ:
-               ret = io_read(req, issue_flags);
-               break;
-       case IORING_OP_WRITEV:
-       case IORING_OP_WRITE_FIXED:
-       case IORING_OP_WRITE:
-               ret = io_write(req, issue_flags);
-               break;
-       case IORING_OP_FSYNC:
-               ret = io_fsync(req, issue_flags);
-               break;
-       case IORING_OP_POLL_ADD:
-               ret = io_poll_add(req, issue_flags);
-               break;
-       case IORING_OP_POLL_REMOVE:
-               ret = io_poll_remove(req, issue_flags);
-               break;
-       case IORING_OP_SYNC_FILE_RANGE:
-               ret = io_sync_file_range(req, issue_flags);
-               break;
-       case IORING_OP_SENDMSG:
-               ret = io_sendmsg(req, issue_flags);
-               break;
-       case IORING_OP_SEND:
-               ret = io_send(req, issue_flags);
-               break;
-       case IORING_OP_RECVMSG:
-               ret = io_recvmsg(req, issue_flags);
-               break;
-       case IORING_OP_RECV:
-               ret = io_recv(req, issue_flags);
-               break;
-       case IORING_OP_TIMEOUT:
-               ret = io_timeout(req, issue_flags);
-               break;
-       case IORING_OP_TIMEOUT_REMOVE:
-               ret = io_timeout_remove(req, issue_flags);
-               break;
-       case IORING_OP_ACCEPT:
-               ret = io_accept(req, issue_flags);
-               break;
-       case IORING_OP_CONNECT:
-               ret = io_connect(req, issue_flags);
-               break;
-       case IORING_OP_ASYNC_CANCEL:
-               ret = io_async_cancel(req, issue_flags);
-               break;
-       case IORING_OP_FALLOCATE:
-               ret = io_fallocate(req, issue_flags);
-               break;
-       case IORING_OP_OPENAT:
-               ret = io_openat(req, issue_flags);
-               break;
-       case IORING_OP_CLOSE:
-               ret = io_close(req, issue_flags);
-               break;
-       case IORING_OP_FILES_UPDATE:
-               ret = io_files_update(req, issue_flags);
-               break;
-       case IORING_OP_STATX:
-               ret = io_statx(req, issue_flags);
-               break;
-       case IORING_OP_FADVISE:
-               ret = io_fadvise(req, issue_flags);
-               break;
-       case IORING_OP_MADVISE:
-               ret = io_madvise(req, issue_flags);
-               break;
-       case IORING_OP_OPENAT2:
-               ret = io_openat2(req, issue_flags);
-               break;
-       case IORING_OP_EPOLL_CTL:
-               ret = io_epoll_ctl(req, issue_flags);
-               break;
-       case IORING_OP_SPLICE:
-               ret = io_splice(req, issue_flags);
-               break;
-       case IORING_OP_PROVIDE_BUFFERS:
-               ret = io_provide_buffers(req, issue_flags);
-               break;
-       case IORING_OP_REMOVE_BUFFERS:
-               ret = io_remove_buffers(req, issue_flags);
-               break;
-       case IORING_OP_TEE:
-               ret = io_tee(req, issue_flags);
-               break;
-       case IORING_OP_SHUTDOWN:
-               ret = io_shutdown(req, issue_flags);
-               break;
-       case IORING_OP_RENAMEAT:
-               ret = io_renameat(req, issue_flags);
-               break;
-       case IORING_OP_UNLINKAT:
-               ret = io_unlinkat(req, issue_flags);
-               break;
-       case IORING_OP_MKDIRAT:
-               ret = io_mkdirat(req, issue_flags);
-               break;
-       case IORING_OP_SYMLINKAT:
-               ret = io_symlinkat(req, issue_flags);
-               break;
-       case IORING_OP_LINKAT:
-               ret = io_linkat(req, issue_flags);
-               break;
-       case IORING_OP_MSG_RING:
-               ret = io_msg_ring(req, issue_flags);
-               break;
-       case IORING_OP_FSETXATTR:
-               ret = io_fsetxattr(req, issue_flags);
-               break;
-       case IORING_OP_SETXATTR:
-               ret = io_setxattr(req, issue_flags);
-               break;
-       case IORING_OP_FGETXATTR:
-               ret = io_fgetxattr(req, issue_flags);
-               break;
-       case IORING_OP_GETXATTR:
-               ret = io_getxattr(req, issue_flags);
-               break;
-       case IORING_OP_SOCKET:
-               ret = io_socket(req, issue_flags);
-               break;
-       case IORING_OP_URING_CMD:
-               ret = io_uring_cmd(req, issue_flags);
-               break;
-       default:
-               ret = -EINVAL;
-               break;
-       }
-
-       if (!def->audit_skip)
-               audit_uring_exit(!ret, ret);
-
-       if (creds)
-               revert_creds(creds);
-       if (ret)
-               return ret;
-       /* If the op doesn't have a file, we're not polling for it */
-       if ((req->ctx->flags & IORING_SETUP_IOPOLL) && req->file)
-               io_iopoll_req_issued(req, issue_flags);
-
-       return 0;
-}
-
-static struct io_wq_work *io_wq_free_work(struct io_wq_work *work)
-{
-       struct io_kiocb *req = container_of(work, struct io_kiocb, work);
-
-       req = io_put_req_find_next(req);
-       return req ? &req->work : NULL;
-}
-
-static void io_wq_submit_work(struct io_wq_work *work)
-{
-       struct io_kiocb *req = container_of(work, struct io_kiocb, work);
-       const struct io_op_def *def = &io_op_defs[req->opcode];
-       unsigned int issue_flags = IO_URING_F_UNLOCKED;
-       bool needs_poll = false;
-       int ret = 0, err = -ECANCELED;
-
-       /* one will be dropped by ->io_free_work() after returning to io-wq */
-       if (!(req->flags & REQ_F_REFCOUNT))
-               __io_req_set_refcount(req, 2);
-       else
-               req_ref_get(req);
-
-       io_arm_ltimeout(req);
-
-       /* either cancelled or io-wq is dying, so don't touch tctx->iowq */
-       if (work->flags & IO_WQ_WORK_CANCEL) {
-fail:
-               io_req_task_queue_fail(req, err);
-               return;
-       }
-       if (!io_assign_file(req, issue_flags)) {
-               err = -EBADF;
-               work->flags |= IO_WQ_WORK_CANCEL;
-               goto fail;
-       }
-
-       if (req->flags & REQ_F_FORCE_ASYNC) {
-               bool opcode_poll = def->pollin || def->pollout;
-
-               if (opcode_poll && file_can_poll(req->file)) {
-                       needs_poll = true;
-                       issue_flags |= IO_URING_F_NONBLOCK;
-               }
-       }
-
-       do {
-               ret = io_issue_sqe(req, issue_flags);
-               if (ret != -EAGAIN)
-                       break;
-               /*
-                * We can get EAGAIN for iopolled IO even though we're
-                * forcing a sync submission from here, since we can't
-                * wait for request slots on the block side.
-                */
-               if (!needs_poll) {
-                       if (!(req->ctx->flags & IORING_SETUP_IOPOLL))
-                               break;
-                       cond_resched();
-                       continue;
-               }
-
-               if (io_arm_poll_handler(req, issue_flags) == IO_APOLL_OK)
-                       return;
-               /* aborted or ready, in either case retry blocking */
-               needs_poll = false;
-               issue_flags &= ~IO_URING_F_NONBLOCK;
-       } while (1);
-
-       /* avoid locking problems by failing it from a clean context */
-       if (ret)
-               io_req_task_queue_fail(req, ret);
-}
-
-static inline struct io_fixed_file *io_fixed_file_slot(struct io_file_table *table,
-                                                      unsigned i)
-{
-       return &table->files[i];
-}
-
-static inline struct file *io_file_from_index(struct io_ring_ctx *ctx,
-                                             int index)
-{
-       struct io_fixed_file *slot = io_fixed_file_slot(&ctx->file_table, index);
-
-       return (struct file *) (slot->file_ptr & FFS_MASK);
-}
-
-static void io_fixed_file_set(struct io_fixed_file *file_slot, struct file *file)
-{
-       unsigned long file_ptr = (unsigned long) file;
-
-       file_ptr |= io_file_get_flags(file);
-       file_slot->file_ptr = file_ptr;
-}
-
-static inline struct file *io_file_get_fixed(struct io_kiocb *req, int fd,
-                                            unsigned int issue_flags)
-{
-       struct io_ring_ctx *ctx = req->ctx;
-       struct file *file = NULL;
-       unsigned long file_ptr;
-
-       io_ring_submit_lock(ctx, issue_flags);
-
-       if (unlikely((unsigned int)fd >= ctx->nr_user_files))
-               goto out;
-       fd = array_index_nospec(fd, ctx->nr_user_files);
-       file_ptr = io_fixed_file_slot(&ctx->file_table, fd)->file_ptr;
-       file = (struct file *) (file_ptr & FFS_MASK);
-       file_ptr &= ~FFS_MASK;
-       /* mask in overlapping REQ_F and FFS bits */
-       req->flags |= (file_ptr << REQ_F_SUPPORT_NOWAIT_BIT);
-       io_req_set_rsrc_node(req, ctx, 0);
-       WARN_ON_ONCE(file && !test_bit(fd, ctx->file_table.bitmap));
-out:
-       io_ring_submit_unlock(ctx, issue_flags);
-       return file;
-}
-
-static struct file *io_file_get_normal(struct io_kiocb *req, int fd)
-{
-       struct file *file = fget(fd);
-
-       trace_io_uring_file_get(req->ctx, req, req->cqe.user_data, fd);
-
-       /* we don't allow fixed io_uring files */
-       if (file && file->f_op == &io_uring_fops)
-               io_req_track_inflight(req);
-       return file;
-}
-
-static void io_req_task_link_timeout(struct io_kiocb *req, bool *locked)
-{
-       struct io_kiocb *prev = req->timeout.prev;
-       int ret = -ENOENT;
-
-       if (prev) {
-               if (!(req->task->flags & PF_EXITING)) {
-                       struct io_cancel_data cd = {
-                               .ctx            = req->ctx,
-                               .data           = prev->cqe.user_data,
-                       };
-
-                       ret = io_try_cancel(req, &cd);
-               }
-               io_req_complete_post(req, ret ?: -ETIME, 0);
-               io_put_req(prev);
-       } else {
-               io_req_complete_post(req, -ETIME, 0);
-       }
-}
-
-static enum hrtimer_restart io_link_timeout_fn(struct hrtimer *timer)
-{
-       struct io_timeout_data *data = container_of(timer,
-                                               struct io_timeout_data, timer);
-       struct io_kiocb *prev, *req = data->req;
-       struct io_ring_ctx *ctx = req->ctx;
-       unsigned long flags;
-
-       spin_lock_irqsave(&ctx->timeout_lock, flags);
-       prev = req->timeout.head;
-       req->timeout.head = NULL;
-
-       /*
-        * We don't expect the list to be empty, that will only happen if we
-        * race with the completion of the linked work.
-        */
-       if (prev) {
-               io_remove_next_linked(prev);
-               if (!req_ref_inc_not_zero(prev))
-                       prev = NULL;
-       }
-       list_del(&req->timeout.list);
-       req->timeout.prev = prev;
-       spin_unlock_irqrestore(&ctx->timeout_lock, flags);
-
-       req->io_task_work.func = io_req_task_link_timeout;
-       io_req_task_work_add(req);
-       return HRTIMER_NORESTART;
-}
-
-static void io_queue_linked_timeout(struct io_kiocb *req)
-{
-       struct io_ring_ctx *ctx = req->ctx;
-
-       spin_lock_irq(&ctx->timeout_lock);
-       /*
-        * If the back reference is NULL, then our linked request finished
-        * before we got a chance to setup the timer
-        */
-       if (req->timeout.head) {
-               struct io_timeout_data *data = req->async_data;
-
-               data->timer.function = io_link_timeout_fn;
-               hrtimer_start(&data->timer, timespec64_to_ktime(data->ts),
-                               data->mode);
-               list_add_tail(&req->timeout.list, &ctx->ltimeout_list);
-       }
-       spin_unlock_irq(&ctx->timeout_lock);
-       /* drop submission reference */
-       io_put_req(req);
-}
-
-static void io_queue_async(struct io_kiocb *req, int ret)
-       __must_hold(&req->ctx->uring_lock)
-{
-       struct io_kiocb *linked_timeout;
-
-       if (ret != -EAGAIN || (req->flags & REQ_F_NOWAIT)) {
-               io_req_complete_failed(req, ret);
-               return;
-       }
-
-       linked_timeout = io_prep_linked_timeout(req);
-
-       switch (io_arm_poll_handler(req, 0)) {
-       case IO_APOLL_READY:
-               io_req_task_queue(req);
-               break;
-       case IO_APOLL_ABORTED:
-               /*
-                * Queued up for async execution, worker will release
-                * submit reference when the iocb is actually submitted.
-                */
-               io_kbuf_recycle(req, 0);
-               io_queue_iowq(req, NULL);
-               break;
-       case IO_APOLL_OK:
-               break;
-       }
-
-       if (linked_timeout)
-               io_queue_linked_timeout(linked_timeout);
-}
-
-static inline void io_queue_sqe(struct io_kiocb *req)
-       __must_hold(&req->ctx->uring_lock)
-{
-       int ret;
-
-       ret = io_issue_sqe(req, IO_URING_F_NONBLOCK|IO_URING_F_COMPLETE_DEFER);
-
-       if (req->flags & REQ_F_COMPLETE_INLINE) {
-               io_req_add_compl_list(req);
-               return;
-       }
-       /*
-        * We async punt it if the file wasn't marked NOWAIT, or if the file
-        * doesn't support non-blocking read/write attempts
-        */
-       if (likely(!ret))
-               io_arm_ltimeout(req);
-       else
-               io_queue_async(req, ret);
-}
-
-static void io_queue_sqe_fallback(struct io_kiocb *req)
-       __must_hold(&req->ctx->uring_lock)
-{
-       if (unlikely(req->flags & REQ_F_FAIL)) {
-               /*
-                * We don't submit, fail them all, for that replace hardlinks
-                * with normal links. Extra REQ_F_LINK is tolerated.
-                */
-               req->flags &= ~REQ_F_HARDLINK;
-               req->flags |= REQ_F_LINK;
-               io_req_complete_failed(req, req->cqe.res);
-       } else if (unlikely(req->ctx->drain_active)) {
-               io_drain_req(req);
-       } else {
-               int ret = io_req_prep_async(req);
-
-               if (unlikely(ret))
-                       io_req_complete_failed(req, ret);
-               else
-                       io_queue_iowq(req, NULL);
-       }
-}
-
-/*
- * Check SQE restrictions (opcode and flags).
- *
- * Returns 'true' if SQE is allowed, 'false' otherwise.
- */
-static inline bool io_check_restriction(struct io_ring_ctx *ctx,
-                                       struct io_kiocb *req,
-                                       unsigned int sqe_flags)
-{
-       if (!test_bit(req->opcode, ctx->restrictions.sqe_op))
-               return false;
-
-       if ((sqe_flags & ctx->restrictions.sqe_flags_required) !=
-           ctx->restrictions.sqe_flags_required)
-               return false;
-
-       if (sqe_flags & ~(ctx->restrictions.sqe_flags_allowed |
-                         ctx->restrictions.sqe_flags_required))
-               return false;
-
-       return true;
-}
-
-static void io_init_req_drain(struct io_kiocb *req)
-{
-       struct io_ring_ctx *ctx = req->ctx;
-       struct io_kiocb *head = ctx->submit_state.link.head;
-
-       ctx->drain_active = true;
-       if (head) {
-               /*
-                * If we need to drain a request in the middle of a link, drain
-                * the head request and the next request/link after the current
-                * link. Considering sequential execution of links,
-                * REQ_F_IO_DRAIN will be maintained for every request of our
-                * link.
-                */
-               head->flags |= REQ_F_IO_DRAIN | REQ_F_FORCE_ASYNC;
-               ctx->drain_next = true;
-       }
-}
-
-static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
-                      const struct io_uring_sqe *sqe)
-       __must_hold(&ctx->uring_lock)
-{
-       const struct io_op_def *def;
-       unsigned int sqe_flags;
-       int personality;
-       u8 opcode;
-
-       /* 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);
-       req->cqe.user_data = READ_ONCE(sqe->user_data);
-       req->file = NULL;
-       req->rsrc_node = NULL;
-       req->task = current;
-
-       if (unlikely(opcode >= IORING_OP_LAST)) {
-               req->opcode = 0;
-               return -EINVAL;
-       }
-       def = &io_op_defs[opcode];
-       if (unlikely(sqe_flags & ~SQE_COMMON_FLAGS)) {
-               /* enforce forwards compatibility on users */
-               if (sqe_flags & ~SQE_VALID_FLAGS)
-                       return -EINVAL;
-               if (sqe_flags & IOSQE_BUFFER_SELECT) {
-                       if (!def->buffer_select)
-                               return -EOPNOTSUPP;
-                       req->buf_index = READ_ONCE(sqe->buf_group);
-               }
-               if (sqe_flags & IOSQE_CQE_SKIP_SUCCESS)
-                       ctx->drain_disabled = true;
-               if (sqe_flags & IOSQE_IO_DRAIN) {
-                       if (ctx->drain_disabled)
-                               return -EOPNOTSUPP;
-                       io_init_req_drain(req);
-               }
-       }
-       if (unlikely(ctx->restricted || ctx->drain_active || ctx->drain_next)) {
-               if (ctx->restricted && !io_check_restriction(ctx, req, sqe_flags))
-                       return -EACCES;
-               /* knock it to the slow queue path, will be drained there */
-               if (ctx->drain_active)
-                       req->flags |= REQ_F_FORCE_ASYNC;
-               /* if there is no link, we're at "next" request and need to drain */
-               if (unlikely(ctx->drain_next) && !ctx->submit_state.link.head) {
-                       ctx->drain_next = false;
-                       ctx->drain_active = true;
-                       req->flags |= REQ_F_IO_DRAIN | REQ_F_FORCE_ASYNC;
-               }
-       }
-
-       if (!def->ioprio && sqe->ioprio)
-               return -EINVAL;
-       if (!def->iopoll && (ctx->flags & IORING_SETUP_IOPOLL))
-               return -EINVAL;
-
-       if (def->needs_file) {
-               struct io_submit_state *state = &ctx->submit_state;
-
-               req->cqe.fd = READ_ONCE(sqe->fd);
-
-               /*
-                * Plug now if we have more than 2 IO left after this, and the
-                * target is potentially a read/write to block based storage.
-                */
-               if (state->need_plug && def->plug) {
-                       state->plug_started = true;
-                       state->need_plug = false;
-                       blk_start_plug_nr_ios(&state->plug, state->submit_nr);
-               }
-       }
-
-       personality = READ_ONCE(sqe->personality);
-       if (personality) {
-               int ret;
-
-               req->creds = xa_load(&ctx->personalities, personality);
-               if (!req->creds)
-                       return -EINVAL;
-               get_cred(req->creds);
-               ret = security_uring_override_creds(req->creds);
-               if (ret) {
-                       put_cred(req->creds);
-                       return ret;
-               }
-               req->flags |= REQ_F_CREDS;
-       }
-
-       return io_req_prep(req, sqe);
-}
-
-static __cold int io_submit_fail_init(const struct io_uring_sqe *sqe,
-                                     struct io_kiocb *req, int ret)
-{
-       struct io_ring_ctx *ctx = req->ctx;
-       struct io_submit_link *link = &ctx->submit_state.link;
-       struct io_kiocb *head = link->head;
-
-       trace_io_uring_req_failed(sqe, ctx, req, ret);
-
-       /*
-        * Avoid breaking links in the middle as it renders links with SQPOLL
-        * unusable. Instead of failing eagerly, continue assembling the link if
-        * applicable and mark the head with REQ_F_FAIL. The link flushing code
-        * should find the flag and handle the rest.
-        */
-       req_fail_link_node(req, ret);
-       if (head && !(head->flags & REQ_F_FAIL))
-               req_fail_link_node(head, -ECANCELED);
-
-       if (!(req->flags & IO_REQ_LINK_FLAGS)) {
-               if (head) {
-                       link->last->link = req;
-                       link->head = NULL;
-                       req = head;
-               }
-               io_queue_sqe_fallback(req);
-               return ret;
-       }
-
-       if (head)
-               link->last->link = req;
-       else
-               link->head = req;
-       link->last = req;
-       return 0;
-}
-
-static inline int io_submit_sqe(struct io_ring_ctx *ctx, struct io_kiocb *req,
-                        const struct io_uring_sqe *sqe)
-       __must_hold(&ctx->uring_lock)
-{
-       struct io_submit_link *link = &ctx->submit_state.link;
-       int ret;
-
-       ret = io_init_req(ctx, req, sqe);
-       if (unlikely(ret))
-               return io_submit_fail_init(sqe, req, ret);
-
-       /* don't need @sqe from now on */
-       trace_io_uring_submit_sqe(ctx, req, req->cqe.user_data, req->opcode,
-                                 req->flags, true,
-                                 ctx->flags & IORING_SETUP_SQPOLL);
-
-       /*
-        * If we already have a head request, queue this one for async
-        * submittal once the head completes. If we don't have a head but
-        * IOSQE_IO_LINK is set in the sqe, start a new head. This one will be
-        * submitted sync once the chain is complete. If none of those
-        * conditions are true (normal request), then just queue it.
-        */
-       if (unlikely(link->head)) {
-               ret = io_req_prep_async(req);
-               if (unlikely(ret))
-                       return io_submit_fail_init(sqe, req, ret);
-
-               trace_io_uring_link(ctx, req, link->head);
-               link->last->link = req;
-               link->last = req;
-
-               if (req->flags & IO_REQ_LINK_FLAGS)
-                       return 0;
-               /* last request of the link, flush it */
-               req = link->head;
-               link->head = NULL;
-               if (req->flags & (REQ_F_FORCE_ASYNC | REQ_F_FAIL))
-                       goto fallback;
-
-       } else if (unlikely(req->flags & (IO_REQ_LINK_FLAGS |
-                                         REQ_F_FORCE_ASYNC | REQ_F_FAIL))) {
-               if (req->flags & IO_REQ_LINK_FLAGS) {
-                       link->head = req;
-                       link->last = req;
-               } else {
-fallback:
-                       io_queue_sqe_fallback(req);
-               }
-               return 0;
-       }
-
-       io_queue_sqe(req);
-       return 0;
-}
-
-/*
- * Batched submission is done, ensure local IO is flushed out.
- */
-static void io_submit_state_end(struct io_ring_ctx *ctx)
-{
-       struct io_submit_state *state = &ctx->submit_state;
-
-       if (unlikely(state->link.head))
-               io_queue_sqe_fallback(state->link.head);
-       /* flush only after queuing links as they can generate completions */
-       io_submit_flush_completions(ctx);
-       if (state->plug_started)
-               blk_finish_plug(&state->plug);
-}
-
-/*
- * Start submission side cache.
- */
-static void io_submit_state_start(struct io_submit_state *state,
-                                 unsigned int max_ios)
-{
-       state->plug_started = false;
-       state->need_plug = max_ios > 2;
-       state->submit_nr = max_ios;
-       /* set only head, no need to init link_last in advance */
-       state->link.head = NULL;
-}
-
-static void io_commit_sqring(struct io_ring_ctx *ctx)
-{
-       struct io_rings *rings = ctx->rings;
-
-       /*
-        * Ensure any loads from the SQEs are done at this point,
-        * since once we write the new head, the application could
-        * write new data to them.
-        */
-       smp_store_release(&rings->sq.head, ctx->cached_sq_head);
-}
-
-/*
- * Fetch an sqe, if one is available. Note this returns a pointer to memory
- * that is mapped by userspace. This means that care needs to be taken to
- * ensure that reads are stable, as we cannot rely on userspace always
- * being a good citizen. If members of the sqe are validated and then later
- * used, it's important that those reads are done through READ_ONCE() to
- * prevent a re-load down the line.
- */
-static const struct io_uring_sqe *io_get_sqe(struct io_ring_ctx *ctx)
-{
-       unsigned head, mask = ctx->sq_entries - 1;
-       unsigned sq_idx = ctx->cached_sq_head++ & mask;
-
-       /*
-        * The cached sq head (or cq tail) serves two purposes:
-        *
-        * 1) allows us to batch the cost of updating the user visible
-        *    head updates.
-        * 2) allows the kernel side to track the head on its own, even
-        *    though the application is the one updating it.
-        */
-       head = READ_ONCE(ctx->sq_array[sq_idx]);
-       if (likely(head < ctx->sq_entries)) {
-               /* double index for 128-byte SQEs, twice as long */
-               if (ctx->flags & IORING_SETUP_SQE128)
-                       head <<= 1;
-               return &ctx->sq_sqes[head];
-       }
-
-       /* drop invalid entries */
-       ctx->cq_extra--;
-       WRITE_ONCE(ctx->rings->sq_dropped,
-                  READ_ONCE(ctx->rings->sq_dropped) + 1);
-       return NULL;
-}
-
-static int io_submit_sqes(struct io_ring_ctx *ctx, unsigned int nr)
-       __must_hold(&ctx->uring_lock)
-{
-       unsigned int entries = io_sqring_entries(ctx);
-       unsigned int left;
-       int ret;
-
-       if (unlikely(!entries))
-               return 0;
-       /* make sure SQ entry isn't read before tail */
-       ret = left = min3(nr, ctx->sq_entries, entries);
-       io_get_task_refs(left);
-       io_submit_state_start(&ctx->submit_state, left);
-
-       do {
-               const struct io_uring_sqe *sqe;
-               struct io_kiocb *req;
-
-               if (unlikely(!io_alloc_req_refill(ctx)))
-                       break;
-               req = io_alloc_req(ctx);
-               sqe = io_get_sqe(ctx);
-               if (unlikely(!sqe)) {
-                       io_req_add_to_cache(req, ctx);
-                       break;
-               }
-
-               /*
-                * Continue submitting even for sqe failure if the
-                * ring was setup with IORING_SETUP_SUBMIT_ALL
-                */
-               if (unlikely(io_submit_sqe(ctx, req, sqe)) &&
-                   !(ctx->flags & IORING_SETUP_SUBMIT_ALL)) {
-                       left--;
-                       break;
-               }
-       } while (--left);
-
-       if (unlikely(left)) {
-               ret -= left;
-               /* try again if it submitted nothing and can't allocate a req */
-               if (!ret && io_req_cache_empty(ctx))
-                       ret = -EAGAIN;
-               current->io_uring->cached_refs += left;
-       }
-
-       io_submit_state_end(ctx);
-        /* Commit SQ ring head once we've consumed and submitted all SQEs */
-       io_commit_sqring(ctx);
-       return ret;
-}
-
-static inline bool io_sqd_events_pending(struct io_sq_data *sqd)
-{
-       return READ_ONCE(sqd->state);
-}
-
-static int __io_sq_thread(struct io_ring_ctx *ctx, bool cap_entries)
-{
-       unsigned int to_submit;
-       int ret = 0;
-
-       to_submit = io_sqring_entries(ctx);
-       /* if we're handling multiple rings, cap submit size for fairness */
-       if (cap_entries && to_submit > IORING_SQPOLL_CAP_ENTRIES_VALUE)
-               to_submit = IORING_SQPOLL_CAP_ENTRIES_VALUE;
-
-       if (!wq_list_empty(&ctx->iopoll_list) || to_submit) {
-               const struct cred *creds = NULL;
-
-               if (ctx->sq_creds != current_cred())
-                       creds = override_creds(ctx->sq_creds);
-
-               mutex_lock(&ctx->uring_lock);
-               if (!wq_list_empty(&ctx->iopoll_list))
-                       io_do_iopoll(ctx, true);
-
-               /*
-                * Don't submit if refs are dying, good for io_uring_register(),
-                * but also it is relied upon by io_ring_exit_work()
-                */
-               if (to_submit && likely(!percpu_ref_is_dying(&ctx->refs)) &&
-                   !(ctx->flags & IORING_SETUP_R_DISABLED))
-                       ret = io_submit_sqes(ctx, to_submit);
-               mutex_unlock(&ctx->uring_lock);
-
-               if (to_submit && wq_has_sleeper(&ctx->sqo_sq_wait))
-                       wake_up(&ctx->sqo_sq_wait);
-               if (creds)
-                       revert_creds(creds);
-       }
-
-       return ret;
-}
-
-static __cold void io_sqd_update_thread_idle(struct io_sq_data *sqd)
-{
-       struct io_ring_ctx *ctx;
-       unsigned sq_thread_idle = 0;
-
-       list_for_each_entry(ctx, &sqd->ctx_list, sqd_list)
-               sq_thread_idle = max(sq_thread_idle, ctx->sq_thread_idle);
-       sqd->sq_thread_idle = sq_thread_idle;
-}
-
-static bool io_sqd_handle_event(struct io_sq_data *sqd)
-{
-       bool did_sig = false;
-       struct ksignal ksig;
-
-       if (test_bit(IO_SQ_THREAD_SHOULD_PARK, &sqd->state) ||
-           signal_pending(current)) {
-               mutex_unlock(&sqd->lock);
-               if (signal_pending(current))
-                       did_sig = get_signal(&ksig);
-               cond_resched();
-               mutex_lock(&sqd->lock);
-       }
-       return did_sig || test_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state);
-}
-
-static int io_sq_thread(void *data)
-{
-       struct io_sq_data *sqd = data;
-       struct io_ring_ctx *ctx;
-       unsigned long timeout = 0;
-       char buf[TASK_COMM_LEN];
-       DEFINE_WAIT(wait);
-
-       snprintf(buf, sizeof(buf), "iou-sqp-%d", sqd->task_pid);
-       set_task_comm(current, buf);
-
-       if (sqd->sq_cpu != -1)
-               set_cpus_allowed_ptr(current, cpumask_of(sqd->sq_cpu));
-       else
-               set_cpus_allowed_ptr(current, cpu_online_mask);
-       current->flags |= PF_NO_SETAFFINITY;
-
-       audit_alloc_kernel(current);
-
-       mutex_lock(&sqd->lock);
-       while (1) {
-               bool cap_entries, sqt_spin = false;
-
-               if (io_sqd_events_pending(sqd) || signal_pending(current)) {
-                       if (io_sqd_handle_event(sqd))
-                               break;
-                       timeout = jiffies + sqd->sq_thread_idle;
-               }
-
-               cap_entries = !list_is_singular(&sqd->ctx_list);
-               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())
-                       sqt_spin = true;
-
-               if (sqt_spin || !time_after(jiffies, timeout)) {
-                       cond_resched();
-                       if (sqt_spin)
-                               timeout = jiffies + sqd->sq_thread_idle;
-                       continue;
-               }
-
-               prepare_to_wait(&sqd->wait, &wait, TASK_INTERRUPTIBLE);
-               if (!io_sqd_events_pending(sqd) && !task_work_pending(current)) {
-                       bool needs_sched = true;
-
-                       list_for_each_entry(ctx, &sqd->ctx_list, sqd_list) {
-                               atomic_or(IORING_SQ_NEED_WAKEUP,
-                                               &ctx->rings->sq_flags);
-                               if ((ctx->flags & IORING_SETUP_IOPOLL) &&
-                                   !wq_list_empty(&ctx->iopoll_list)) {
-                                       needs_sched = false;
-                                       break;
-                               }
-
-                               /*
-                                * Ensure the store of the wakeup flag is not
-                                * reordered with the load of the SQ tail
-                                */
-                               smp_mb__after_atomic();
-
-                               if (io_sqring_entries(ctx)) {
-                                       needs_sched = false;
-                                       break;
-                               }
-                       }
-
-                       if (needs_sched) {
-                               mutex_unlock(&sqd->lock);
-                               schedule();
-                               mutex_lock(&sqd->lock);
-                       }
-                       list_for_each_entry(ctx, &sqd->ctx_list, sqd_list)
-                               atomic_andnot(IORING_SQ_NEED_WAKEUP,
-                                               &ctx->rings->sq_flags);
-               }
-
-               finish_wait(&sqd->wait, &wait);
-               timeout = jiffies + sqd->sq_thread_idle;
-       }
-
-       io_uring_cancel_generic(true, sqd);
-       sqd->thread = NULL;
-       list_for_each_entry(ctx, &sqd->ctx_list, sqd_list)
-               atomic_or(IORING_SQ_NEED_WAKEUP, &ctx->rings->sq_flags);
-       io_run_task_work();
-       mutex_unlock(&sqd->lock);
-
-       audit_free(current);
-
-       complete(&sqd->exited);
-       do_exit(0);
-}
-
-struct io_wait_queue {
-       struct wait_queue_entry wq;
-       struct io_ring_ctx *ctx;
-       unsigned cq_tail;
-       unsigned nr_timeouts;
-};
-
-static inline bool io_should_wake(struct io_wait_queue *iowq)
-{
-       struct io_ring_ctx *ctx = iowq->ctx;
-       int dist = ctx->cached_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)
-{
-       struct io_wait_queue *iowq = container_of(curr, struct io_wait_queue,
-                                                       wq);
-
-       /*
-        * Cannot safely flush overflowed CQEs from here, ensure we wake up
-        * the task, and the next invocation will do it.
-        */
-       if (io_should_wake(iowq) ||
-           test_bit(IO_CHECK_CQ_OVERFLOW_BIT, &iowq->ctx->check_cq))
-               return autoremove_wake_function(curr, mode, wake_flags, key);
-       return -1;
-}
-
-static int io_run_task_work_sig(void)
-{
-       if (io_run_task_work())
-               return 1;
-       if (test_thread_flag(TIF_NOTIFY_SIGNAL))
-               return -ERESTARTSYS;
-       if (task_sigpending(current))
-               return -EINTR;
-       return 0;
-}
-
-/* when returns >0, the caller should retry */
-static inline int io_cqring_wait_schedule(struct io_ring_ctx *ctx,
-                                         struct io_wait_queue *iowq,
-                                         ktime_t timeout)
-{
-       int ret;
-       unsigned long check_cq;
-
-       /* make sure we run task_work before checking for signals */
-       ret = io_run_task_work_sig();
-       if (ret || io_should_wake(iowq))
-               return ret;
-       check_cq = READ_ONCE(ctx->check_cq);
-       /* let the caller flush overflows, retry */
-       if (check_cq & BIT(IO_CHECK_CQ_OVERFLOW_BIT))
-               return 1;
-       if (unlikely(check_cq & BIT(IO_CHECK_CQ_DROPPED_BIT)))
-               return -EBADR;
-       if (!schedule_hrtimeout(&timeout, HRTIMER_MODE_ABS))
-               return -ETIME;
-       return 1;
-}
-
-/*
- * Wait until events become available, if we don't already have some. The
- * application must reap them itself, as they reside on the shared cq ring.
- */
-static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events,
-                         const sigset_t __user *sig, size_t sigsz,
-                         struct __kernel_timespec __user *uts)
-{
-       struct io_wait_queue iowq;
-       struct io_rings *rings = ctx->rings;
-       ktime_t timeout = KTIME_MAX;
-       int ret;
-
-       do {
-               io_cqring_overflow_flush(ctx);
-               if (io_cqring_events(ctx) >= min_events)
-                       return 0;
-               if (!io_run_task_work())
-                       break;
-       } while (1);
-
-       if (sig) {
-#ifdef CONFIG_COMPAT
-               if (in_compat_syscall())
-                       ret = set_compat_user_sigmask((const compat_sigset_t __user *)sig,
-                                                     sigsz);
-               else
-#endif
-                       ret = set_user_sigmask(sig, sigsz);
-
-               if (ret)
-                       return ret;
-       }
-
-       if (uts) {
-               struct timespec64 ts;
-
-               if (get_timespec64(&ts, uts))
-                       return -EFAULT;
-               timeout = ktime_add_ns(timespec64_to_ktime(ts), ktime_get_ns());
-       }
-
-       init_waitqueue_func_entry(&iowq.wq, io_wake_function);
-       iowq.wq.private = current;
-       INIT_LIST_HEAD(&iowq.wq.entry);
-       iowq.ctx = ctx;
-       iowq.nr_timeouts = atomic_read(&ctx->cq_timeouts);
-       iowq.cq_tail = READ_ONCE(ctx->rings->cq.head) + min_events;
-
-       trace_io_uring_cqring_wait(ctx, min_events);
-       do {
-               /* if we can't even flush overflow, don't wait for more */
-               if (!io_cqring_overflow_flush(ctx)) {
-                       ret = -EBUSY;
-                       break;
-               }
-               prepare_to_wait_exclusive(&ctx->cq_wait, &iowq.wq,
-                                               TASK_INTERRUPTIBLE);
-               ret = io_cqring_wait_schedule(ctx, &iowq, timeout);
-               cond_resched();
-       } while (ret > 0);
-
-       finish_wait(&ctx->cq_wait, &iowq.wq);
-       restore_saved_sigmask_unless(ret == -EINTR);
-
-       return READ_ONCE(rings->cq.head) == READ_ONCE(rings->cq.tail) ? ret : 0;
-}
-
-static void io_free_page_table(void **table, size_t size)
-{
-       unsigned i, nr_tables = DIV_ROUND_UP(size, PAGE_SIZE);
-
-       for (i = 0; i < nr_tables; i++)
-               kfree(table[i]);
-       kfree(table);
-}
-
-static __cold void **io_alloc_page_table(size_t size)
-{
-       unsigned i, nr_tables = DIV_ROUND_UP(size, PAGE_SIZE);
-       size_t init_size = size;
-       void **table;
-
-       table = kcalloc(nr_tables, sizeof(*table), GFP_KERNEL_ACCOUNT);
-       if (!table)
-               return NULL;
-
-       for (i = 0; i < nr_tables; i++) {
-               unsigned int this_size = min_t(size_t, size, PAGE_SIZE);
-
-               table[i] = kzalloc(this_size, GFP_KERNEL_ACCOUNT);
-               if (!table[i]) {
-                       io_free_page_table(table, init_size);
-                       return NULL;
-               }
-               size -= this_size;
-       }
-       return table;
-}
-
-static void io_rsrc_node_destroy(struct io_rsrc_node *ref_node)
-{
-       percpu_ref_exit(&ref_node->refs);
-       kfree(ref_node);
-}
-
-static __cold void io_rsrc_node_ref_zero(struct percpu_ref *ref)
-{
-       struct io_rsrc_node *node = container_of(ref, struct io_rsrc_node, refs);
-       struct io_ring_ctx *ctx = node->rsrc_data->ctx;
-       unsigned long flags;
-       bool first_add = false;
-       unsigned long delay = HZ;
-
-       spin_lock_irqsave(&ctx->rsrc_ref_lock, flags);
-       node->done = true;
-
-       /* if we are mid-quiesce then do not delay */
-       if (node->rsrc_data->quiesce)
-               delay = 0;
-
-       while (!list_empty(&ctx->rsrc_ref_list)) {
-               node = list_first_entry(&ctx->rsrc_ref_list,
-                                           struct io_rsrc_node, node);
-               /* recycle ref nodes in order */
-               if (!node->done)
-                       break;
-               list_del(&node->node);
-               first_add |= llist_add(&node->llist, &ctx->rsrc_put_llist);
-       }
-       spin_unlock_irqrestore(&ctx->rsrc_ref_lock, flags);
-
-       if (first_add)
-               mod_delayed_work(system_wq, &ctx->rsrc_put_work, delay);
-}
-
-static struct io_rsrc_node *io_rsrc_node_alloc(void)
-{
-       struct io_rsrc_node *ref_node;
-
-       ref_node = kzalloc(sizeof(*ref_node), GFP_KERNEL);
-       if (!ref_node)
-               return NULL;
-
-       if (percpu_ref_init(&ref_node->refs, io_rsrc_node_ref_zero,
-                           0, GFP_KERNEL)) {
-               kfree(ref_node);
-               return NULL;
-       }
-       INIT_LIST_HEAD(&ref_node->node);
-       INIT_LIST_HEAD(&ref_node->rsrc_list);
-       ref_node->done = false;
-       return ref_node;
-}
-
-static void io_rsrc_node_switch(struct io_ring_ctx *ctx,
-                               struct io_rsrc_data *data_to_kill)
-       __must_hold(&ctx->uring_lock)
-{
-       WARN_ON_ONCE(!ctx->rsrc_backup_node);
-       WARN_ON_ONCE(data_to_kill && !ctx->rsrc_node);
-
-       io_rsrc_refs_drop(ctx);
-
-       if (data_to_kill) {
-               struct io_rsrc_node *rsrc_node = ctx->rsrc_node;
-
-               rsrc_node->rsrc_data = data_to_kill;
-               spin_lock_irq(&ctx->rsrc_ref_lock);
-               list_add_tail(&rsrc_node->node, &ctx->rsrc_ref_list);
-               spin_unlock_irq(&ctx->rsrc_ref_lock);
-
-               atomic_inc(&data_to_kill->refs);
-               percpu_ref_kill(&rsrc_node->refs);
-               ctx->rsrc_node = NULL;
-       }
-
-       if (!ctx->rsrc_node) {
-               ctx->rsrc_node = ctx->rsrc_backup_node;
-               ctx->rsrc_backup_node = NULL;
-       }
-}
-
-static int io_rsrc_node_switch_start(struct io_ring_ctx *ctx)
-{
-       if (ctx->rsrc_backup_node)
-               return 0;
-       ctx->rsrc_backup_node = io_rsrc_node_alloc();
-       return ctx->rsrc_backup_node ? 0 : -ENOMEM;
-}
-
-static __cold int io_rsrc_ref_quiesce(struct io_rsrc_data *data,
-                                     struct io_ring_ctx *ctx)
-{
-       int ret;
-
-       /* As we may drop ->uring_lock, other task may have started quiesce */
-       if (data->quiesce)
-               return -ENXIO;
-
-       data->quiesce = true;
-       do {
-               ret = io_rsrc_node_switch_start(ctx);
-               if (ret)
-                       break;
-               io_rsrc_node_switch(ctx, data);
-
-               /* kill initial ref, already quiesced if zero */
-               if (atomic_dec_and_test(&data->refs))
-                       break;
-               mutex_unlock(&ctx->uring_lock);
-               flush_delayed_work(&ctx->rsrc_put_work);
-               ret = wait_for_completion_interruptible(&data->done);
-               if (!ret) {
-                       mutex_lock(&ctx->uring_lock);
-                       if (atomic_read(&data->refs) > 0) {
-                               /*
-                                * it has been revived by another thread while
-                                * we were unlocked
-                                */
-                               mutex_unlock(&ctx->uring_lock);
-                       } else {
-                               break;
-                       }
-               }
-
-               atomic_inc(&data->refs);
-               /* wait for all works potentially completing data->done */
-               flush_delayed_work(&ctx->rsrc_put_work);
-               reinit_completion(&data->done);
-
-               ret = io_run_task_work_sig();
-               mutex_lock(&ctx->uring_lock);
-       } while (ret >= 0);
-       data->quiesce = false;
-
-       return ret;
-}
-
-static u64 *io_get_tag_slot(struct io_rsrc_data *data, unsigned int idx)
-{
-       unsigned int off = idx & IO_RSRC_TAG_TABLE_MASK;
-       unsigned int table_idx = idx >> IO_RSRC_TAG_TABLE_SHIFT;
-
-       return &data->tags[table_idx][off];
-}
-
-static void io_rsrc_data_free(struct io_rsrc_data *data)
-{
-       size_t size = data->nr * sizeof(data->tags[0][0]);
-
-       if (data->tags)
-               io_free_page_table((void **)data->tags, size);
-       kfree(data);
-}
-
-static __cold int io_rsrc_data_alloc(struct io_ring_ctx *ctx, rsrc_put_fn *do_put,
-                                    u64 __user *utags, unsigned nr,
-                                    struct io_rsrc_data **pdata)
-{
-       struct io_rsrc_data *data;
-       int ret = -ENOMEM;
-       unsigned i;
-
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-       data->tags = (u64 **)io_alloc_page_table(nr * sizeof(data->tags[0][0]));
-       if (!data->tags) {
-               kfree(data);
-               return -ENOMEM;
-       }
-
-       data->nr = nr;
-       data->ctx = ctx;
-       data->do_put = do_put;
-       if (utags) {
-               ret = -EFAULT;
-               for (i = 0; i < nr; i++) {
-                       u64 *tag_slot = io_get_tag_slot(data, i);
-
-                       if (copy_from_user(tag_slot, &utags[i],
-                                          sizeof(*tag_slot)))
-                               goto fail;
-               }
-       }
-
-       atomic_set(&data->refs, 1);
-       init_completion(&data->done);
-       *pdata = data;
-       return 0;
-fail:
-       io_rsrc_data_free(data);
-       return ret;
-}
-
-static bool io_alloc_file_tables(struct io_file_table *table, unsigned nr_files)
-{
-       table->files = kvcalloc(nr_files, sizeof(table->files[0]),
-                               GFP_KERNEL_ACCOUNT);
-       if (unlikely(!table->files))
-               return false;
-
-       table->bitmap = bitmap_zalloc(nr_files, GFP_KERNEL_ACCOUNT);
-       if (unlikely(!table->bitmap)) {
-               kvfree(table->files);
-               return false;
-       }
-
-       return true;
-}
-
-static void io_free_file_tables(struct io_file_table *table)
-{
-       kvfree(table->files);
-       bitmap_free(table->bitmap);
-       table->files = NULL;
-       table->bitmap = NULL;
-}
-
-static inline void io_file_bitmap_set(struct io_file_table *table, int bit)
-{
-       WARN_ON_ONCE(test_bit(bit, table->bitmap));
-       __set_bit(bit, table->bitmap);
-       table->alloc_hint = bit + 1;
-}
-
-static inline void io_file_bitmap_clear(struct io_file_table *table, int bit)
-{
-       __clear_bit(bit, table->bitmap);
-       table->alloc_hint = bit;
-}
-
-static void __io_sqe_files_unregister(struct io_ring_ctx *ctx)
-{
-#if !defined(IO_URING_SCM_ALL)
-       int i;
-
-       for (i = 0; i < ctx->nr_user_files; i++) {
-               struct file *file = io_file_from_index(ctx, i);
-
-               if (!file)
-                       continue;
-               if (io_fixed_file_slot(&ctx->file_table, i)->file_ptr & FFS_SCM)
-                       continue;
-               io_file_bitmap_clear(&ctx->file_table, i);
-               fput(file);
-       }
-#endif
-
-#if defined(CONFIG_UNIX)
-       if (ctx->ring_sock) {
-               struct sock *sock = ctx->ring_sock->sk;
-               struct sk_buff *skb;
-
-               while ((skb = skb_dequeue(&sock->sk_receive_queue)) != NULL)
-                       kfree_skb(skb);
-       }
-#endif
-       io_free_file_tables(&ctx->file_table);
-       io_rsrc_data_free(ctx->file_data);
-       ctx->file_data = NULL;
-       ctx->nr_user_files = 0;
-}
-
-static int io_sqe_files_unregister(struct io_ring_ctx *ctx)
-{
-       unsigned nr = ctx->nr_user_files;
-       int ret;
-
-       if (!ctx->file_data)
-               return -ENXIO;
-
-       /*
-        * Quiesce may unlock ->uring_lock, and while it's not held
-        * prevent new requests using the table.
-        */
-       ctx->nr_user_files = 0;
-       ret = io_rsrc_ref_quiesce(ctx->file_data, ctx);
-       ctx->nr_user_files = nr;
-       if (!ret)
-               __io_sqe_files_unregister(ctx);
-       return ret;
-}
-
-static void io_sq_thread_unpark(struct io_sq_data *sqd)
-       __releases(&sqd->lock)
-{
-       WARN_ON_ONCE(sqd->thread == current);
-
-       /*
-        * Do the dance but not conditional clear_bit() because it'd race with
-        * other threads incrementing park_pending and setting the bit.
-        */
-       clear_bit(IO_SQ_THREAD_SHOULD_PARK, &sqd->state);
-       if (atomic_dec_return(&sqd->park_pending))
-               set_bit(IO_SQ_THREAD_SHOULD_PARK, &sqd->state);
-       mutex_unlock(&sqd->lock);
-}
-
-static void io_sq_thread_park(struct io_sq_data *sqd)
-       __acquires(&sqd->lock)
-{
-       WARN_ON_ONCE(sqd->thread == current);
-
-       atomic_inc(&sqd->park_pending);
-       set_bit(IO_SQ_THREAD_SHOULD_PARK, &sqd->state);
-       mutex_lock(&sqd->lock);
-       if (sqd->thread)
-               wake_up_process(sqd->thread);
-}
-
-static void io_sq_thread_stop(struct io_sq_data *sqd)
-{
-       WARN_ON_ONCE(sqd->thread == current);
-       WARN_ON_ONCE(test_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state));
-
-       set_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state);
-       mutex_lock(&sqd->lock);
-       if (sqd->thread)
-               wake_up_process(sqd->thread);
-       mutex_unlock(&sqd->lock);
-       wait_for_completion(&sqd->exited);
-}
-
-static void io_put_sq_data(struct io_sq_data *sqd)
-{
-       if (refcount_dec_and_test(&sqd->refs)) {
-               WARN_ON_ONCE(atomic_read(&sqd->park_pending));
-
-               io_sq_thread_stop(sqd);
-               kfree(sqd);
-       }
-}
-
-static void io_sq_thread_finish(struct io_ring_ctx *ctx)
-{
-       struct io_sq_data *sqd = ctx->sq_data;
-
-       if (sqd) {
-               io_sq_thread_park(sqd);
-               list_del_init(&ctx->sqd_list);
-               io_sqd_update_thread_idle(sqd);
-               io_sq_thread_unpark(sqd);
-
-               io_put_sq_data(sqd);
-               ctx->sq_data = NULL;
-       }
-}
-
-static struct io_sq_data *io_attach_sq_data(struct io_uring_params *p)
-{
-       struct io_ring_ctx *ctx_attach;
-       struct io_sq_data *sqd;
-       struct fd f;
-
-       f = fdget(p->wq_fd);
-       if (!f.file)
-               return ERR_PTR(-ENXIO);
-       if (f.file->f_op != &io_uring_fops) {
-               fdput(f);
-               return ERR_PTR(-EINVAL);
-       }
-
-       ctx_attach = f.file->private_data;
-       sqd = ctx_attach->sq_data;
-       if (!sqd) {
-               fdput(f);
-               return ERR_PTR(-EINVAL);
-       }
-       if (sqd->task_tgid != current->tgid) {
-               fdput(f);
-               return ERR_PTR(-EPERM);
-       }
-
-       refcount_inc(&sqd->refs);
-       fdput(f);
-       return sqd;
-}
-
-static struct io_sq_data *io_get_sq_data(struct io_uring_params *p,
-                                        bool *attached)
-{
-       struct io_sq_data *sqd;
-
-       *attached = false;
-       if (p->flags & IORING_SETUP_ATTACH_WQ) {
-               sqd = io_attach_sq_data(p);
-               if (!IS_ERR(sqd)) {
-                       *attached = true;
-                       return sqd;
-               }
-               /* fall through for EPERM case, setup new sqd/task */
-               if (PTR_ERR(sqd) != -EPERM)
-                       return sqd;
-       }
-
-       sqd = kzalloc(sizeof(*sqd), GFP_KERNEL);
-       if (!sqd)
-               return ERR_PTR(-ENOMEM);
-
-       atomic_set(&sqd->park_pending, 0);
-       refcount_set(&sqd->refs, 1);
-       INIT_LIST_HEAD(&sqd->ctx_list);
-       mutex_init(&sqd->lock);
-       init_waitqueue_head(&sqd->wait);
-       init_completion(&sqd->exited);
-       return sqd;
-}
-
-/*
- * Ensure the UNIX gc is aware of our file set, so we are certain that
- * the io_uring can be safely unregistered on process exit, even if we have
- * loops in the file referencing. We account only files that can hold other
- * files because otherwise they can't form a loop and so are not interesting
- * for GC.
- */
-static int io_scm_file_account(struct io_ring_ctx *ctx, struct file *file)
-{
-#if defined(CONFIG_UNIX)
-       struct sock *sk = ctx->ring_sock->sk;
-       struct sk_buff_head *head = &sk->sk_receive_queue;
-       struct scm_fp_list *fpl;
-       struct sk_buff *skb;
-
-       if (likely(!io_file_need_scm(file)))
-               return 0;
-
-       /*
-        * See if we can merge this file into an existing skb SCM_RIGHTS
-        * file set. If there's no room, fall back to allocating a new skb
-        * and filling it in.
-        */
-       spin_lock_irq(&head->lock);
-       skb = skb_peek(head);
-       if (skb && UNIXCB(skb).fp->count < SCM_MAX_FD)
-               __skb_unlink(skb, head);
-       else
-               skb = NULL;
-       spin_unlock_irq(&head->lock);
-
-       if (!skb) {
-               fpl = kzalloc(sizeof(*fpl), GFP_KERNEL);
-               if (!fpl)
-                       return -ENOMEM;
-
-               skb = alloc_skb(0, GFP_KERNEL);
-               if (!skb) {
-                       kfree(fpl);
-                       return -ENOMEM;
-               }
-
-               fpl->user = get_uid(current_user());
-               fpl->max = SCM_MAX_FD;
-               fpl->count = 0;
-
-               UNIXCB(skb).fp = fpl;
-               skb->sk = sk;
-               skb->destructor = unix_destruct_scm;
-               refcount_add(skb->truesize, &sk->sk_wmem_alloc);
-       }
-
-       fpl = UNIXCB(skb).fp;
-       fpl->fp[fpl->count++] = get_file(file);
-       unix_inflight(fpl->user, file);
-       skb_queue_head(head, skb);
-       fput(file);
-#endif
-       return 0;
-}
-
-static void io_rsrc_file_put(struct io_ring_ctx *ctx, struct io_rsrc_put *prsrc)
-{
-       struct file *file = prsrc->file;
-#if defined(CONFIG_UNIX)
-       struct sock *sock = ctx->ring_sock->sk;
-       struct sk_buff_head list, *head = &sock->sk_receive_queue;
-       struct sk_buff *skb;
-       int i;
-
-       if (!io_file_need_scm(file)) {
-               fput(file);
-               return;
-       }
-
-       __skb_queue_head_init(&list);
-
-       /*
-        * Find the skb that holds this file in its SCM_RIGHTS. When found,
-        * remove this entry and rearrange the file array.
-        */
-       skb = skb_dequeue(head);
-       while (skb) {
-               struct scm_fp_list *fp;
-
-               fp = UNIXCB(skb).fp;
-               for (i = 0; i < fp->count; i++) {
-                       int left;
-
-                       if (fp->fp[i] != file)
-                               continue;
-
-                       unix_notinflight(fp->user, fp->fp[i]);
-                       left = fp->count - 1 - i;
-                       if (left) {
-                               memmove(&fp->fp[i], &fp->fp[i + 1],
-                                               left * sizeof(struct file *));
-                       }
-                       fp->count--;
-                       if (!fp->count) {
-                               kfree_skb(skb);
-                               skb = NULL;
-                       } else {
-                               __skb_queue_tail(&list, skb);
-                       }
-                       fput(file);
-                       file = NULL;
-                       break;
-               }
-
-               if (!file)
-                       break;
-
-               __skb_queue_tail(&list, skb);
-
-               skb = skb_dequeue(head);
-       }
-
-       if (skb_peek(&list)) {
-               spin_lock_irq(&head->lock);
-               while ((skb = __skb_dequeue(&list)) != NULL)
-                       __skb_queue_tail(head, skb);
-               spin_unlock_irq(&head->lock);
-       }
-#else
-       fput(file);
-#endif
-}
-
-static void __io_rsrc_put_work(struct io_rsrc_node *ref_node)
-{
-       struct io_rsrc_data *rsrc_data = ref_node->rsrc_data;
-       struct io_ring_ctx *ctx = rsrc_data->ctx;
-       struct io_rsrc_put *prsrc, *tmp;
-
-       list_for_each_entry_safe(prsrc, tmp, &ref_node->rsrc_list, list) {
-               list_del(&prsrc->list);
-
-               if (prsrc->tag) {
-                       if (ctx->flags & IORING_SETUP_IOPOLL)
-                               mutex_lock(&ctx->uring_lock);
-
-                       spin_lock(&ctx->completion_lock);
-                       io_fill_cqe_aux(ctx, prsrc->tag, 0, 0);
-                       io_commit_cqring(ctx);
-                       spin_unlock(&ctx->completion_lock);
-                       io_cqring_ev_posted(ctx);
-
-                       if (ctx->flags & IORING_SETUP_IOPOLL)
-                               mutex_unlock(&ctx->uring_lock);
-               }
-
-               rsrc_data->do_put(ctx, prsrc);
-               kfree(prsrc);
-       }
-
-       io_rsrc_node_destroy(ref_node);
-       if (atomic_dec_and_test(&rsrc_data->refs))
-               complete(&rsrc_data->done);
-}
-
-static void io_rsrc_put_work(struct work_struct *work)
-{
-       struct io_ring_ctx *ctx;
-       struct llist_node *node;
-
-       ctx = container_of(work, struct io_ring_ctx, rsrc_put_work.work);
-       node = llist_del_all(&ctx->rsrc_put_llist);
-
-       while (node) {
-               struct io_rsrc_node *ref_node;
-               struct llist_node *next = node->next;
-
-               ref_node = llist_entry(node, struct io_rsrc_node, llist);
-               __io_rsrc_put_work(ref_node);
-               node = next;
-       }
-}
-
-static int io_sqe_files_register(struct io_ring_ctx *ctx, void __user *arg,
-                                unsigned nr_args, u64 __user *tags)
-{
-       __s32 __user *fds = (__s32 __user *) arg;
-       struct file *file;
-       int fd, ret;
-       unsigned i;
-
-       if (ctx->file_data)
-               return -EBUSY;
-       if (!nr_args)
-               return -EINVAL;
-       if (nr_args > IORING_MAX_FIXED_FILES)
-               return -EMFILE;
-       if (nr_args > rlimit(RLIMIT_NOFILE))
-               return -EMFILE;
-       ret = io_rsrc_node_switch_start(ctx);
-       if (ret)
-               return ret;
-       ret = io_rsrc_data_alloc(ctx, io_rsrc_file_put, tags, nr_args,
-                                &ctx->file_data);
-       if (ret)
-               return ret;
-
-       if (!io_alloc_file_tables(&ctx->file_table, nr_args)) {
-               io_rsrc_data_free(ctx->file_data);
-               ctx->file_data = NULL;
-               return -ENOMEM;
-       }
-
-       for (i = 0; i < nr_args; i++, ctx->nr_user_files++) {
-               struct io_fixed_file *file_slot;
-
-               if (fds && copy_from_user(&fd, &fds[i], sizeof(fd))) {
-                       ret = -EFAULT;
-                       goto fail;
-               }
-               /* allow sparse sets */
-               if (!fds || fd == -1) {
-                       ret = -EINVAL;
-                       if (unlikely(*io_get_tag_slot(ctx->file_data, i)))
-                               goto fail;
-                       continue;
-               }
-
-               file = fget(fd);
-               ret = -EBADF;
-               if (unlikely(!file))
-                       goto fail;
-
-               /*
-                * Don't allow io_uring instances to be registered. If UNIX
-                * isn't enabled, then this causes a reference cycle and this
-                * instance can never get freed. If UNIX is enabled we'll
-                * handle it just fine, but there's still no point in allowing
-                * a ring fd as it doesn't support regular read/write anyway.
-                */
-               if (file->f_op == &io_uring_fops) {
-                       fput(file);
-                       goto fail;
-               }
-               ret = io_scm_file_account(ctx, file);
-               if (ret) {
-                       fput(file);
-                       goto fail;
-               }
-               file_slot = io_fixed_file_slot(&ctx->file_table, i);
-               io_fixed_file_set(file_slot, file);
-               io_file_bitmap_set(&ctx->file_table, i);
-       }
-
-       io_rsrc_node_switch(ctx, NULL);
-       return 0;
-fail:
-       __io_sqe_files_unregister(ctx);
-       return ret;
-}
-
-static int io_queue_rsrc_removal(struct io_rsrc_data *data, unsigned idx,
-                                struct io_rsrc_node *node, void *rsrc)
-{
-       u64 *tag_slot = io_get_tag_slot(data, idx);
-       struct io_rsrc_put *prsrc;
-
-       prsrc = kzalloc(sizeof(*prsrc), GFP_KERNEL);
-       if (!prsrc)
-               return -ENOMEM;
-
-       prsrc->tag = *tag_slot;
-       *tag_slot = 0;
-       prsrc->rsrc = rsrc;
-       list_add(&prsrc->list, &node->rsrc_list);
-       return 0;
-}
-
-static int io_install_fixed_file(struct io_kiocb *req, struct file *file,
-                                unsigned int issue_flags, u32 slot_index)
-       __must_hold(&req->ctx->uring_lock)
-{
-       struct io_ring_ctx *ctx = req->ctx;
-       bool needs_switch = false;
-       struct io_fixed_file *file_slot;
-       int ret;
-
-       if (file->f_op == &io_uring_fops)
-               return -EBADF;
-       if (!ctx->file_data)
-               return -ENXIO;
-       if (slot_index >= ctx->nr_user_files)
-               return -EINVAL;
-
-       slot_index = array_index_nospec(slot_index, ctx->nr_user_files);
-       file_slot = io_fixed_file_slot(&ctx->file_table, slot_index);
-
-       if (file_slot->file_ptr) {
-               struct file *old_file;
-
-               ret = io_rsrc_node_switch_start(ctx);
-               if (ret)
-                       goto err;
-
-               old_file = (struct file *)(file_slot->file_ptr & FFS_MASK);
-               ret = io_queue_rsrc_removal(ctx->file_data, slot_index,
-                                           ctx->rsrc_node, old_file);
-               if (ret)
-                       goto err;
-               file_slot->file_ptr = 0;
-               io_file_bitmap_clear(&ctx->file_table, slot_index);
-               needs_switch = true;
-       }
-
-       ret = io_scm_file_account(ctx, file);
-       if (!ret) {
-               *io_get_tag_slot(ctx->file_data, slot_index) = 0;
-               io_fixed_file_set(file_slot, file);
-               io_file_bitmap_set(&ctx->file_table, slot_index);
-       }
-err:
-       if (needs_switch)
-               io_rsrc_node_switch(ctx, ctx->file_data);
-       if (ret)
-               fput(file);
-       return ret;
-}
-
-static int __io_close_fixed(struct io_kiocb *req, unsigned int issue_flags,
-                           unsigned int offset)
-{
-       struct io_ring_ctx *ctx = req->ctx;
-       struct io_fixed_file *file_slot;
-       struct file *file;
-       int ret;
-
-       io_ring_submit_lock(ctx, issue_flags);
-       ret = -ENXIO;
-       if (unlikely(!ctx->file_data))
-               goto out;
-       ret = -EINVAL;
-       if (offset >= ctx->nr_user_files)
-               goto out;
-       ret = io_rsrc_node_switch_start(ctx);
-       if (ret)
-               goto out;
-
-       offset = array_index_nospec(offset, ctx->nr_user_files);
-       file_slot = io_fixed_file_slot(&ctx->file_table, offset);
-       ret = -EBADF;
-       if (!file_slot->file_ptr)
-               goto out;
-
-       file = (struct file *)(file_slot->file_ptr & FFS_MASK);
-       ret = io_queue_rsrc_removal(ctx->file_data, offset, ctx->rsrc_node, file);
-       if (ret)
-               goto out;
-
-       file_slot->file_ptr = 0;
-       io_file_bitmap_clear(&ctx->file_table, offset);
-       io_rsrc_node_switch(ctx, ctx->file_data);
-       ret = 0;
-out:
-       io_ring_submit_unlock(ctx, issue_flags);
-       return ret;
-}
-
-static inline int io_close_fixed(struct io_kiocb *req, unsigned int issue_flags)
-{
-       return __io_close_fixed(req, issue_flags, req->close.file_slot - 1);
-}
-
-static int __io_sqe_files_update(struct io_ring_ctx *ctx,
-                                struct io_uring_rsrc_update2 *up,
-                                unsigned nr_args)
-{
-       u64 __user *tags = u64_to_user_ptr(up->tags);
-       __s32 __user *fds = u64_to_user_ptr(up->data);
-       struct io_rsrc_data *data = ctx->file_data;
-       struct io_fixed_file *file_slot;
-       struct file *file;
-       int fd, i, err = 0;
-       unsigned int done;
-       bool needs_switch = false;
-
-       if (!ctx->file_data)
-               return -ENXIO;
-       if (up->offset + nr_args > ctx->nr_user_files)
-               return -EINVAL;
-
-       for (done = 0; done < nr_args; done++) {
-               u64 tag = 0;
-
-               if ((tags && copy_from_user(&tag, &tags[done], sizeof(tag))) ||
-                   copy_from_user(&fd, &fds[done], sizeof(fd))) {
-                       err = -EFAULT;
-                       break;
-               }
-               if ((fd == IORING_REGISTER_FILES_SKIP || fd == -1) && tag) {
-                       err = -EINVAL;
-                       break;
-               }
-               if (fd == IORING_REGISTER_FILES_SKIP)
-                       continue;
-
-               i = array_index_nospec(up->offset + done, ctx->nr_user_files);
-               file_slot = io_fixed_file_slot(&ctx->file_table, i);
-
-               if (file_slot->file_ptr) {
-                       file = (struct file *)(file_slot->file_ptr & FFS_MASK);
-                       err = io_queue_rsrc_removal(data, i, ctx->rsrc_node, file);
-                       if (err)
-                               break;
-                       file_slot->file_ptr = 0;
-                       io_file_bitmap_clear(&ctx->file_table, i);
-                       needs_switch = true;
-               }
-               if (fd != -1) {
-                       file = fget(fd);
-                       if (!file) {
-                               err = -EBADF;
-                               break;
-                       }
-                       /*
-                        * Don't allow io_uring instances to be registered. If
-                        * UNIX isn't enabled, then this causes a reference
-                        * cycle and this instance can never get freed. If UNIX
-                        * is enabled we'll handle it just fine, but there's
-                        * still no point in allowing a ring fd as it doesn't
-                        * support regular read/write anyway.
-                        */
-                       if (file->f_op == &io_uring_fops) {
-                               fput(file);
-                               err = -EBADF;
-                               break;
-                       }
-                       err = io_scm_file_account(ctx, file);
-                       if (err) {
-                               fput(file);
-                               break;
-                       }
-                       *io_get_tag_slot(data, i) = tag;
-                       io_fixed_file_set(file_slot, file);
-                       io_file_bitmap_set(&ctx->file_table, i);
-               }
-       }
-
-       if (needs_switch)
-               io_rsrc_node_switch(ctx, data);
-       return done ? done : err;
-}
-
-static struct io_wq *io_init_wq_offload(struct io_ring_ctx *ctx,
-                                       struct task_struct *task)
-{
-       struct io_wq_hash *hash;
-       struct io_wq_data data;
-       unsigned int concurrency;
-
-       mutex_lock(&ctx->uring_lock);
-       hash = ctx->hash_map;
-       if (!hash) {
-               hash = kzalloc(sizeof(*hash), GFP_KERNEL);
-               if (!hash) {
-                       mutex_unlock(&ctx->uring_lock);
-                       return ERR_PTR(-ENOMEM);
-               }
-               refcount_set(&hash->refs, 1);
-               init_waitqueue_head(&hash->wait);
-               ctx->hash_map = hash;
-       }
-       mutex_unlock(&ctx->uring_lock);
-
-       data.hash = hash;
-       data.task = task;
-       data.free_work = io_wq_free_work;
-       data.do_work = io_wq_submit_work;
-
-       /* Do QD, or 4 * CPUS, whatever is smallest */
-       concurrency = min(ctx->sq_entries, 4 * num_online_cpus());
-
-       return io_wq_create(concurrency, &data);
-}
-
-static __cold int io_uring_alloc_task_context(struct task_struct *task,
-                                             struct io_ring_ctx *ctx)
-{
-       struct io_uring_task *tctx;
-       int ret;
-
-       tctx = kzalloc(sizeof(*tctx), GFP_KERNEL);
-       if (unlikely(!tctx))
-               return -ENOMEM;
-
-       tctx->registered_rings = kcalloc(IO_RINGFD_REG_MAX,
-                                        sizeof(struct file *), GFP_KERNEL);
-       if (unlikely(!tctx->registered_rings)) {
-               kfree(tctx);
-               return -ENOMEM;
-       }
-
-       ret = percpu_counter_init(&tctx->inflight, 0, GFP_KERNEL);
-       if (unlikely(ret)) {
-               kfree(tctx->registered_rings);
-               kfree(tctx);
-               return ret;
-       }
-
-       tctx->io_wq = io_init_wq_offload(ctx, task);
-       if (IS_ERR(tctx->io_wq)) {
-               ret = PTR_ERR(tctx->io_wq);
-               percpu_counter_destroy(&tctx->inflight);
-               kfree(tctx->registered_rings);
-               kfree(tctx);
-               return ret;
-       }
-
-       xa_init(&tctx->xa);
-       init_waitqueue_head(&tctx->wait);
-       atomic_set(&tctx->in_idle, 0);
-       atomic_set(&tctx->inflight_tracked, 0);
-       task->io_uring = tctx;
-       spin_lock_init(&tctx->task_lock);
-       INIT_WQ_LIST(&tctx->task_list);
-       INIT_WQ_LIST(&tctx->prio_task_list);
-       init_task_work(&tctx->task_work, tctx_task_work);
-       return 0;
-}
-
-void __io_uring_free(struct task_struct *tsk)
-{
-       struct io_uring_task *tctx = tsk->io_uring;
-
-       WARN_ON_ONCE(!xa_empty(&tctx->xa));
-       WARN_ON_ONCE(tctx->io_wq);
-       WARN_ON_ONCE(tctx->cached_refs);
-
-       kfree(tctx->registered_rings);
-       percpu_counter_destroy(&tctx->inflight);
-       kfree(tctx);
-       tsk->io_uring = NULL;
-}
-
-static __cold int io_sq_offload_create(struct io_ring_ctx *ctx,
-                                      struct io_uring_params *p)
-{
-       int ret;
-
-       /* Retain compatibility with failing for an invalid attach attempt */
-       if ((ctx->flags & (IORING_SETUP_ATTACH_WQ | IORING_SETUP_SQPOLL)) ==
-                               IORING_SETUP_ATTACH_WQ) {
-               struct fd f;
-
-               f = fdget(p->wq_fd);
-               if (!f.file)
-                       return -ENXIO;
-               if (f.file->f_op != &io_uring_fops) {
-                       fdput(f);
-                       return -EINVAL;
-               }
-               fdput(f);
-       }
-       if (ctx->flags & IORING_SETUP_SQPOLL) {
-               struct task_struct *tsk;
-               struct io_sq_data *sqd;
-               bool attached;
-
-               ret = security_uring_sqpoll();
-               if (ret)
-                       return ret;
-
-               sqd = io_get_sq_data(p, &attached);
-               if (IS_ERR(sqd)) {
-                       ret = PTR_ERR(sqd);
-                       goto err;
-               }
-
-               ctx->sq_creds = get_current_cred();
-               ctx->sq_data = sqd;
-               ctx->sq_thread_idle = msecs_to_jiffies(p->sq_thread_idle);
-               if (!ctx->sq_thread_idle)
-                       ctx->sq_thread_idle = HZ;
-
-               io_sq_thread_park(sqd);
-               list_add(&ctx->sqd_list, &sqd->ctx_list);
-               io_sqd_update_thread_idle(sqd);
-               /* don't attach to a dying SQPOLL thread, would be racy */
-               ret = (attached && !sqd->thread) ? -ENXIO : 0;
-               io_sq_thread_unpark(sqd);
-
-               if (ret < 0)
-                       goto err;
-               if (attached)
-                       return 0;
-
-               if (p->flags & IORING_SETUP_SQ_AFF) {
-                       int cpu = p->sq_thread_cpu;
-
-                       ret = -EINVAL;
-                       if (cpu >= nr_cpu_ids || !cpu_online(cpu))
-                               goto err_sqpoll;
-                       sqd->sq_cpu = cpu;
-               } else {
-                       sqd->sq_cpu = -1;
-               }
-
-               sqd->task_pid = current->pid;
-               sqd->task_tgid = current->tgid;
-               tsk = create_io_thread(io_sq_thread, sqd, NUMA_NO_NODE);
-               if (IS_ERR(tsk)) {
-                       ret = PTR_ERR(tsk);
-                       goto err_sqpoll;
-               }
-
-               sqd->thread = tsk;
-               ret = io_uring_alloc_task_context(tsk, ctx);
-               wake_up_new_task(tsk);
-               if (ret)
-                       goto err;
-       } else if (p->flags & IORING_SETUP_SQ_AFF) {
-               /* Can't have SQ_AFF without SQPOLL */
-               ret = -EINVAL;
-               goto err;
-       }
-
-       return 0;
-err_sqpoll:
-       complete(&ctx->sq_data->exited);
-err:
-       io_sq_thread_finish(ctx);
-       return ret;
-}
-
-static inline void __io_unaccount_mem(struct user_struct *user,
-                                     unsigned long nr_pages)
-{
-       atomic_long_sub(nr_pages, &user->locked_vm);
-}
-
-static inline int __io_account_mem(struct user_struct *user,
-                                  unsigned long nr_pages)
-{
-       unsigned long page_limit, cur_pages, new_pages;
-
-       /* Don't allow more pages than we can safely lock */
-       page_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
-
-       do {
-               cur_pages = atomic_long_read(&user->locked_vm);
-               new_pages = cur_pages + nr_pages;
-               if (new_pages > page_limit)
-                       return -ENOMEM;
-       } while (atomic_long_cmpxchg(&user->locked_vm, cur_pages,
-                                       new_pages) != cur_pages);
-
-       return 0;
-}
-
-static void io_unaccount_mem(struct io_ring_ctx *ctx, unsigned long nr_pages)
-{
-       if (ctx->user)
-               __io_unaccount_mem(ctx->user, nr_pages);
-
-       if (ctx->mm_account)
-               atomic64_sub(nr_pages, &ctx->mm_account->pinned_vm);
-}
-
-static int io_account_mem(struct io_ring_ctx *ctx, unsigned long nr_pages)
-{
-       int ret;
-
-       if (ctx->user) {
-               ret = __io_account_mem(ctx->user, nr_pages);
-               if (ret)
-                       return ret;
-       }
-
-       if (ctx->mm_account)
-               atomic64_add(nr_pages, &ctx->mm_account->pinned_vm);
-
-       return 0;
-}
-
-static void io_mem_free(void *ptr)
-{
-       struct page *page;
-
-       if (!ptr)
-               return;
-
-       page = virt_to_head_page(ptr);
-       if (put_page_testzero(page))
-               free_compound_page(page);
-}
-
-static void *io_mem_alloc(size_t size)
-{
-       gfp_t gfp = GFP_KERNEL_ACCOUNT | __GFP_ZERO | __GFP_NOWARN | __GFP_COMP;
-
-       return (void *) __get_free_pages(gfp, get_order(size));
-}
-
-static unsigned long rings_size(struct io_ring_ctx *ctx, unsigned int sq_entries,
-                               unsigned int cq_entries, size_t *sq_offset)
-{
-       struct io_rings *rings;
-       size_t off, sq_array_size;
-
-       off = struct_size(rings, cqes, cq_entries);
-       if (off == SIZE_MAX)
-               return SIZE_MAX;
-       if (ctx->flags & IORING_SETUP_CQE32) {
-               if (check_shl_overflow(off, 1, &off))
-                       return SIZE_MAX;
-       }
-
-#ifdef CONFIG_SMP
-       off = ALIGN(off, SMP_CACHE_BYTES);
-       if (off == 0)
-               return SIZE_MAX;
-#endif
-
-       if (sq_offset)
-               *sq_offset = off;
-
-       sq_array_size = array_size(sizeof(u32), sq_entries);
-       if (sq_array_size == SIZE_MAX)
-               return SIZE_MAX;
-
-       if (check_add_overflow(off, sq_array_size, &off))
-               return SIZE_MAX;
-
-       return off;
-}
-
-static void io_buffer_unmap(struct io_ring_ctx *ctx, struct io_mapped_ubuf **slot)
-{
-       struct io_mapped_ubuf *imu = *slot;
-       unsigned int i;
-
-       if (imu != ctx->dummy_ubuf) {
-               for (i = 0; i < imu->nr_bvecs; i++)
-                       unpin_user_page(imu->bvec[i].bv_page);
-               if (imu->acct_pages)
-                       io_unaccount_mem(ctx, imu->acct_pages);
-               kvfree(imu);
-       }
-       *slot = NULL;
-}
-
-static void io_rsrc_buf_put(struct io_ring_ctx *ctx, struct io_rsrc_put *prsrc)
-{
-       io_buffer_unmap(ctx, &prsrc->buf);
-       prsrc->buf = NULL;
-}
-
-static void __io_sqe_buffers_unregister(struct io_ring_ctx *ctx)
-{
-       unsigned int i;
-
-       for (i = 0; i < ctx->nr_user_bufs; i++)
-               io_buffer_unmap(ctx, &ctx->user_bufs[i]);
-       kfree(ctx->user_bufs);
-       io_rsrc_data_free(ctx->buf_data);
-       ctx->user_bufs = NULL;
-       ctx->buf_data = NULL;
-       ctx->nr_user_bufs = 0;
-}
-
-static int io_sqe_buffers_unregister(struct io_ring_ctx *ctx)
-{
-       unsigned nr = ctx->nr_user_bufs;
-       int ret;
-
-       if (!ctx->buf_data)
-               return -ENXIO;
-
-       /*
-        * Quiesce may unlock ->uring_lock, and while it's not held
-        * prevent new requests using the table.
-        */
-       ctx->nr_user_bufs = 0;
-       ret = io_rsrc_ref_quiesce(ctx->buf_data, ctx);
-       ctx->nr_user_bufs = nr;
-       if (!ret)
-               __io_sqe_buffers_unregister(ctx);
-       return ret;
-}
-
-static int io_copy_iov(struct io_ring_ctx *ctx, struct iovec *dst,
-                      void __user *arg, unsigned index)
-{
-       struct iovec __user *src;
-
-#ifdef CONFIG_COMPAT
-       if (ctx->compat) {
-               struct compat_iovec __user *ciovs;
-               struct compat_iovec ciov;
-
-               ciovs = (struct compat_iovec __user *) arg;
-               if (copy_from_user(&ciov, &ciovs[index], sizeof(ciov)))
-                       return -EFAULT;
-
-               dst->iov_base = u64_to_user_ptr((u64)ciov.iov_base);
-               dst->iov_len = ciov.iov_len;
-               return 0;
-       }
-#endif
-       src = (struct iovec __user *) arg;
-       if (copy_from_user(dst, &src[index], sizeof(*dst)))
-               return -EFAULT;
-       return 0;
-}
-
-/*
- * Not super efficient, but this is just a registration time. And we do cache
- * the last compound head, so generally we'll only do a full search if we don't
- * match that one.
- *
- * We check if the given compound head page has already been accounted, to
- * avoid double accounting it. This allows us to account the full size of the
- * page, not just the constituent pages of a huge page.
- */
-static bool headpage_already_acct(struct io_ring_ctx *ctx, struct page **pages,
-                                 int nr_pages, struct page *hpage)
-{
-       int i, j;
-
-       /* check current page array */
-       for (i = 0; i < nr_pages; i++) {
-               if (!PageCompound(pages[i]))
-                       continue;
-               if (compound_head(pages[i]) == hpage)
-                       return true;
-       }
-
-       /* check previously registered pages */
-       for (i = 0; i < ctx->nr_user_bufs; i++) {
-               struct io_mapped_ubuf *imu = ctx->user_bufs[i];
-
-               for (j = 0; j < imu->nr_bvecs; j++) {
-                       if (!PageCompound(imu->bvec[j].bv_page))
-                               continue;
-                       if (compound_head(imu->bvec[j].bv_page) == hpage)
-                               return true;
-               }
-       }
-
-       return false;
-}
-
-static int io_buffer_account_pin(struct io_ring_ctx *ctx, struct page **pages,
-                                int nr_pages, struct io_mapped_ubuf *imu,
-                                struct page **last_hpage)
-{
-       int i, ret;
-
-       imu->acct_pages = 0;
-       for (i = 0; i < nr_pages; i++) {
-               if (!PageCompound(pages[i])) {
-                       imu->acct_pages++;
-               } else {
-                       struct page *hpage;
-
-                       hpage = compound_head(pages[i]);
-                       if (hpage == *last_hpage)
-                               continue;
-                       *last_hpage = hpage;
-                       if (headpage_already_acct(ctx, pages, i, hpage))
-                               continue;
-                       imu->acct_pages += page_size(hpage) >> PAGE_SHIFT;
-               }
-       }
-
-       if (!imu->acct_pages)
-               return 0;
-
-       ret = io_account_mem(ctx, imu->acct_pages);
-       if (ret)
-               imu->acct_pages = 0;
-       return ret;
-}
-
-static struct page **io_pin_pages(unsigned long ubuf, unsigned long len,
-                                 int *npages)
-{
-       unsigned long start, end, nr_pages;
-       struct vm_area_struct **vmas = NULL;
-       struct page **pages = NULL;
-       int i, pret, ret = -ENOMEM;
-
-       end = (ubuf + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
-       start = ubuf >> PAGE_SHIFT;
-       nr_pages = end - start;
-
-       pages = kvmalloc_array(nr_pages, sizeof(struct page *), GFP_KERNEL);
-       if (!pages)
-               goto done;
-
-       vmas = kvmalloc_array(nr_pages, sizeof(struct vm_area_struct *),
-                             GFP_KERNEL);
-       if (!vmas)
-               goto done;
-
-       ret = 0;
-       mmap_read_lock(current->mm);
-       pret = pin_user_pages(ubuf, nr_pages, FOLL_WRITE | FOLL_LONGTERM,
-                             pages, vmas);
-       if (pret == nr_pages) {
-               /* don't support file backed memory */
-               for (i = 0; i < nr_pages; i++) {
-                       struct vm_area_struct *vma = vmas[i];
-
-                       if (vma_is_shmem(vma))
-                               continue;
-                       if (vma->vm_file &&
-                           !is_file_hugepages(vma->vm_file)) {
-                               ret = -EOPNOTSUPP;
-                               break;
-                       }
-               }
-               *npages = nr_pages;
-       } else {
-               ret = pret < 0 ? pret : -EFAULT;
-       }
-       mmap_read_unlock(current->mm);
-       if (ret) {
-               /*
-                * if we did partial map, or found file backed vmas,
-                * release any pages we did get
-                */
-               if (pret > 0)
-                       unpin_user_pages(pages, pret);
-               goto done;
-       }
-       ret = 0;
-done:
-       kvfree(vmas);
-       if (ret < 0) {
-               kvfree(pages);
-               pages = ERR_PTR(ret);
-       }
-       return pages;
-}
-
-static int io_sqe_buffer_register(struct io_ring_ctx *ctx, struct iovec *iov,
-                                 struct io_mapped_ubuf **pimu,
-                                 struct page **last_hpage)
-{
-       struct io_mapped_ubuf *imu = NULL;
-       struct page **pages = NULL;
-       unsigned long off;
-       size_t size;
-       int ret, nr_pages, i;
-
-       if (!iov->iov_base) {
-               *pimu = ctx->dummy_ubuf;
-               return 0;
-       }
-
-       *pimu = NULL;
-       ret = -ENOMEM;
-
-       pages = io_pin_pages((unsigned long) iov->iov_base, iov->iov_len,
-                               &nr_pages);
-       if (IS_ERR(pages)) {
-               ret = PTR_ERR(pages);
-               pages = NULL;
-               goto done;
-       }
-
-       imu = kvmalloc(struct_size(imu, bvec, nr_pages), GFP_KERNEL);
-       if (!imu)
-               goto done;
-
-       ret = io_buffer_account_pin(ctx, pages, nr_pages, imu, last_hpage);
-       if (ret) {
-               unpin_user_pages(pages, nr_pages);
-               goto done;
-       }
-
-       off = (unsigned long) iov->iov_base & ~PAGE_MASK;
-       size = iov->iov_len;
-       for (i = 0; i < nr_pages; i++) {
-               size_t vec_len;
-
-               vec_len = min_t(size_t, size, PAGE_SIZE - off);
-               imu->bvec[i].bv_page = pages[i];
-               imu->bvec[i].bv_len = vec_len;
-               imu->bvec[i].bv_offset = off;
-               off = 0;
-               size -= vec_len;
-       }
-       /* store original address for later verification */
-       imu->ubuf = (unsigned long) iov->iov_base;
-       imu->ubuf_end = imu->ubuf + iov->iov_len;
-       imu->nr_bvecs = nr_pages;
-       *pimu = imu;
-       ret = 0;
-done:
-       if (ret)
-               kvfree(imu);
-       kvfree(pages);
-       return ret;
-}
-
-static int io_buffers_map_alloc(struct io_ring_ctx *ctx, unsigned int nr_args)
-{
-       ctx->user_bufs = kcalloc(nr_args, sizeof(*ctx->user_bufs), GFP_KERNEL);
-       return ctx->user_bufs ? 0 : -ENOMEM;
-}
-
-static int io_buffer_validate(struct iovec *iov)
-{
-       unsigned long tmp, acct_len = iov->iov_len + (PAGE_SIZE - 1);
-
-       /*
-        * Don't impose further limits on the size and buffer
-        * constraints here, we'll -EINVAL later when IO is
-        * submitted if they are wrong.
-        */
-       if (!iov->iov_base)
-               return iov->iov_len ? -EFAULT : 0;
-       if (!iov->iov_len)
-               return -EFAULT;
-
-       /* arbitrary limit, but we need something */
-       if (iov->iov_len > SZ_1G)
-               return -EFAULT;
-
-       if (check_add_overflow((unsigned long)iov->iov_base, acct_len, &tmp))
-               return -EOVERFLOW;
-
-       return 0;
-}
-
-static int io_sqe_buffers_register(struct io_ring_ctx *ctx, void __user *arg,
-                                  unsigned int nr_args, u64 __user *tags)
-{
-       struct page *last_hpage = NULL;
-       struct io_rsrc_data *data;
-       int i, ret;
-       struct iovec iov;
-
-       if (ctx->user_bufs)
-               return -EBUSY;
-       if (!nr_args || nr_args > IORING_MAX_REG_BUFFERS)
-               return -EINVAL;
-       ret = io_rsrc_node_switch_start(ctx);
-       if (ret)
-               return ret;
-       ret = io_rsrc_data_alloc(ctx, io_rsrc_buf_put, tags, nr_args, &data);
-       if (ret)
-               return ret;
-       ret = io_buffers_map_alloc(ctx, nr_args);
-       if (ret) {
-               io_rsrc_data_free(data);
-               return ret;
-       }
-
-       for (i = 0; i < nr_args; i++, ctx->nr_user_bufs++) {
-               if (arg) {
-                       ret = io_copy_iov(ctx, &iov, arg, i);
-                       if (ret)
-                               break;
-                       ret = io_buffer_validate(&iov);
-                       if (ret)
-                               break;
-               } else {
-                       memset(&iov, 0, sizeof(iov));
-               }
-
-               if (!iov.iov_base && *io_get_tag_slot(data, i)) {
-                       ret = -EINVAL;
-                       break;
-               }
-
-               ret = io_sqe_buffer_register(ctx, &iov, &ctx->user_bufs[i],
-                                            &last_hpage);
-               if (ret)
-                       break;
-       }
-
-       WARN_ON_ONCE(ctx->buf_data);
-
-       ctx->buf_data = data;
-       if (ret)
-               __io_sqe_buffers_unregister(ctx);
-       else
-               io_rsrc_node_switch(ctx, NULL);
-       return ret;
-}
-
-static int __io_sqe_buffers_update(struct io_ring_ctx *ctx,
-                                  struct io_uring_rsrc_update2 *up,
-                                  unsigned int nr_args)
-{
-       u64 __user *tags = u64_to_user_ptr(up->tags);
-       struct iovec iov, __user *iovs = u64_to_user_ptr(up->data);
-       struct page *last_hpage = NULL;
-       bool needs_switch = false;
-       __u32 done;
-       int i, err;
-
-       if (!ctx->buf_data)
-               return -ENXIO;
-       if (up->offset + nr_args > ctx->nr_user_bufs)
-               return -EINVAL;
-
-       for (done = 0; done < nr_args; done++) {
-               struct io_mapped_ubuf *imu;
-               int offset = up->offset + done;
-               u64 tag = 0;
-
-               err = io_copy_iov(ctx, &iov, iovs, done);
-               if (err)
-                       break;
-               if (tags && copy_from_user(&tag, &tags[done], sizeof(tag))) {
-                       err = -EFAULT;
-                       break;
-               }
-               err = io_buffer_validate(&iov);
-               if (err)
-                       break;
-               if (!iov.iov_base && tag) {
-                       err = -EINVAL;
-                       break;
-               }
-               err = io_sqe_buffer_register(ctx, &iov, &imu, &last_hpage);
-               if (err)
-                       break;
-
-               i = array_index_nospec(offset, ctx->nr_user_bufs);
-               if (ctx->user_bufs[i] != ctx->dummy_ubuf) {
-                       err = io_queue_rsrc_removal(ctx->buf_data, i,
-                                                   ctx->rsrc_node, ctx->user_bufs[i]);
-                       if (unlikely(err)) {
-                               io_buffer_unmap(ctx, &imu);
-                               break;
-                       }
-                       ctx->user_bufs[i] = NULL;
-                       needs_switch = true;
-               }
-
-               ctx->user_bufs[i] = imu;
-               *io_get_tag_slot(ctx->buf_data, offset) = tag;
-       }
-
-       if (needs_switch)
-               io_rsrc_node_switch(ctx, ctx->buf_data);
-       return done ? done : err;
-}
-
-static int io_eventfd_register(struct io_ring_ctx *ctx, void __user *arg,
-                              unsigned int eventfd_async)
-{
-       struct io_ev_fd *ev_fd;
-       __s32 __user *fds = arg;
-       int fd;
-
-       ev_fd = rcu_dereference_protected(ctx->io_ev_fd,
-                                       lockdep_is_held(&ctx->uring_lock));
-       if (ev_fd)
-               return -EBUSY;
-
-       if (copy_from_user(&fd, fds, sizeof(*fds)))
-               return -EFAULT;
-
-       ev_fd = kmalloc(sizeof(*ev_fd), GFP_KERNEL);
-       if (!ev_fd)
-               return -ENOMEM;
-
-       ev_fd->cq_ev_fd = eventfd_ctx_fdget(fd);
-       if (IS_ERR(ev_fd->cq_ev_fd)) {
-               int ret = PTR_ERR(ev_fd->cq_ev_fd);
-               kfree(ev_fd);
-               return ret;
-       }
-       ev_fd->eventfd_async = eventfd_async;
-       ctx->has_evfd = true;
-       rcu_assign_pointer(ctx->io_ev_fd, ev_fd);
-       return 0;
-}
-
-static void io_eventfd_put(struct rcu_head *rcu)
-{
-       struct io_ev_fd *ev_fd = container_of(rcu, struct io_ev_fd, rcu);
-
-       eventfd_ctx_put(ev_fd->cq_ev_fd);
-       kfree(ev_fd);
-}
-
-static int io_eventfd_unregister(struct io_ring_ctx *ctx)
-{
-       struct io_ev_fd *ev_fd;
-
-       ev_fd = rcu_dereference_protected(ctx->io_ev_fd,
-                                       lockdep_is_held(&ctx->uring_lock));
-       if (ev_fd) {
-               ctx->has_evfd = false;
-               rcu_assign_pointer(ctx->io_ev_fd, NULL);
-               call_rcu(&ev_fd->rcu, io_eventfd_put);
-               return 0;
-       }
-
-       return -ENXIO;
-}
-
-static void io_destroy_buffers(struct io_ring_ctx *ctx)
-{
-       struct io_buffer_list *bl;
-       unsigned long index;
-       int i;
-
-       for (i = 0; i < BGID_ARRAY; i++) {
-               if (!ctx->io_bl)
-                       break;
-               __io_remove_buffers(ctx, &ctx->io_bl[i], -1U);
-       }
-
-       xa_for_each(&ctx->io_bl_xa, index, bl) {
-               xa_erase(&ctx->io_bl_xa, bl->bgid);
-               __io_remove_buffers(ctx, bl, -1U);
-               kfree(bl);
-       }
-
-       while (!list_empty(&ctx->io_buffers_pages)) {
-               struct page *page;
-
-               page = list_first_entry(&ctx->io_buffers_pages, struct page, lru);
-               list_del_init(&page->lru);
-               __free_page(page);
-       }
-}
-
-static void io_req_caches_free(struct io_ring_ctx *ctx)
-{
-       struct io_submit_state *state = &ctx->submit_state;
-       int nr = 0;
-
-       mutex_lock(&ctx->uring_lock);
-       io_flush_cached_locked_reqs(ctx, state);
-
-       while (!io_req_cache_empty(ctx)) {
-               struct io_wq_work_node *node;
-               struct io_kiocb *req;
-
-               node = wq_stack_extract(&state->free_list);
-               req = container_of(node, struct io_kiocb, comp_list);
-               kmem_cache_free(req_cachep, req);
-               nr++;
-       }
-       if (nr)
-               percpu_ref_put_many(&ctx->refs, nr);
-       mutex_unlock(&ctx->uring_lock);
-}
-
-static void io_wait_rsrc_data(struct io_rsrc_data *data)
-{
-       if (data && !atomic_dec_and_test(&data->refs))
-               wait_for_completion(&data->done);
-}
-
-static void io_flush_apoll_cache(struct io_ring_ctx *ctx)
-{
-       struct async_poll *apoll;
-
-       while (!list_empty(&ctx->apoll_cache)) {
-               apoll = list_first_entry(&ctx->apoll_cache, struct async_poll,
-                                               poll.wait.entry);
-               list_del(&apoll->poll.wait.entry);
-               kfree(apoll);
-       }
-}
-
-static __cold void io_ring_ctx_free(struct io_ring_ctx *ctx)
-{
-       io_sq_thread_finish(ctx);
-
-       if (ctx->mm_account) {
-               mmdrop(ctx->mm_account);
-               ctx->mm_account = NULL;
-       }
-
-       io_rsrc_refs_drop(ctx);
-       /* __io_rsrc_put_work() may need uring_lock to progress, wait w/o it */
-       io_wait_rsrc_data(ctx->buf_data);
-       io_wait_rsrc_data(ctx->file_data);
-
-       mutex_lock(&ctx->uring_lock);
-       if (ctx->buf_data)
-               __io_sqe_buffers_unregister(ctx);
-       if (ctx->file_data)
-               __io_sqe_files_unregister(ctx);
-       if (ctx->rings)
-               __io_cqring_overflow_flush(ctx, true);
-       io_eventfd_unregister(ctx);
-       io_flush_apoll_cache(ctx);
-       mutex_unlock(&ctx->uring_lock);
-       io_destroy_buffers(ctx);
-       if (ctx->sq_creds)
-               put_cred(ctx->sq_creds);
-
-       /* there are no registered resources left, nobody uses it */
-       if (ctx->rsrc_node)
-               io_rsrc_node_destroy(ctx->rsrc_node);
-       if (ctx->rsrc_backup_node)
-               io_rsrc_node_destroy(ctx->rsrc_backup_node);
-       flush_delayed_work(&ctx->rsrc_put_work);
-       flush_delayed_work(&ctx->fallback_work);
-
-       WARN_ON_ONCE(!list_empty(&ctx->rsrc_ref_list));
-       WARN_ON_ONCE(!llist_empty(&ctx->rsrc_put_llist));
-
-#if defined(CONFIG_UNIX)
-       if (ctx->ring_sock) {
-               ctx->ring_sock->file = NULL; /* so that iput() is called */
-               sock_release(ctx->ring_sock);
-       }
-#endif
-       WARN_ON_ONCE(!list_empty(&ctx->ltimeout_list));
-
-       io_mem_free(ctx->rings);
-       io_mem_free(ctx->sq_sqes);
-
-       percpu_ref_exit(&ctx->refs);
-       free_uid(ctx->user);
-       io_req_caches_free(ctx);
-       if (ctx->hash_map)
-               io_wq_put_hash(ctx->hash_map);
-       kfree(ctx->cancel_hash);
-       kfree(ctx->dummy_ubuf);
-       kfree(ctx->io_bl);
-       xa_destroy(&ctx->io_bl_xa);
-       kfree(ctx);
-}
-
-static __poll_t io_uring_poll(struct file *file, poll_table *wait)
-{
-       struct io_ring_ctx *ctx = file->private_data;
-       __poll_t mask = 0;
-
-       poll_wait(file, &ctx->cq_wait, wait);
-       /*
-        * synchronizes with barrier from wq_has_sleeper call in
-        * io_commit_cqring
-        */
-       smp_rmb();
-       if (!io_sqring_full(ctx))
-               mask |= EPOLLOUT | EPOLLWRNORM;
-
-       /*
-        * Don't flush cqring overflow list here, just do a simple check.
-        * Otherwise there could possible be ABBA deadlock:
-        *      CPU0                    CPU1
-        *      ----                    ----
-        * lock(&ctx->uring_lock);
-        *                              lock(&ep->mtx);
-        *                              lock(&ctx->uring_lock);
-        * lock(&ep->mtx);
-        *
-        * Users may get EPOLLIN meanwhile seeing nothing in cqring, this
-        * pushs them to do the flush.
-        */
-       if (io_cqring_events(ctx) ||
-           test_bit(IO_CHECK_CQ_OVERFLOW_BIT, &ctx->check_cq))
-               mask |= EPOLLIN | EPOLLRDNORM;
-
-       return mask;
-}
-
-static int io_unregister_personality(struct io_ring_ctx *ctx, unsigned id)
-{
-       const struct cred *creds;
-
-       creds = xa_erase(&ctx->personalities, id);
-       if (creds) {
-               put_cred(creds);
-               return 0;
-       }
-
-       return -EINVAL;
-}
-
-struct io_tctx_exit {
-       struct callback_head            task_work;
-       struct completion               completion;
-       struct io_ring_ctx              *ctx;
-};
-
-static __cold void io_tctx_exit_cb(struct callback_head *cb)
-{
-       struct io_uring_task *tctx = current->io_uring;
-       struct io_tctx_exit *work;
-
-       work = container_of(cb, struct io_tctx_exit, task_work);
-       /*
-        * When @in_idle, we're in cancellation and it's racy to remove the
-        * node. It'll be removed by the end of cancellation, just ignore it.
-        */
-       if (!atomic_read(&tctx->in_idle))
-               io_uring_del_tctx_node((unsigned long)work->ctx);
-       complete(&work->completion);
-}
-
-static __cold bool io_cancel_ctx_cb(struct io_wq_work *work, void *data)
-{
-       struct io_kiocb *req = container_of(work, struct io_kiocb, work);
-
-       return req->ctx == data;
-}
-
-static __cold void io_ring_exit_work(struct work_struct *work)
-{
-       struct io_ring_ctx *ctx = container_of(work, struct io_ring_ctx, exit_work);
-       unsigned long timeout = jiffies + HZ * 60 * 5;
-       unsigned long interval = HZ / 20;
-       struct io_tctx_exit exit;
-       struct io_tctx_node *node;
-       int ret;
-
-       /*
-        * If we're doing polled IO and end up having requests being
-        * submitted async (out-of-line), then completions can come in while
-        * we're waiting for refs to drop. We need to reap these manually,
-        * as nobody else will be looking for them.
-        */
-       do {
-               io_uring_try_cancel_requests(ctx, NULL, true);
-               if (ctx->sq_data) {
-                       struct io_sq_data *sqd = ctx->sq_data;
-                       struct task_struct *tsk;
-
-                       io_sq_thread_park(sqd);
-                       tsk = sqd->thread;
-                       if (tsk && tsk->io_uring && tsk->io_uring->io_wq)
-                               io_wq_cancel_cb(tsk->io_uring->io_wq,
-                                               io_cancel_ctx_cb, ctx, true);
-                       io_sq_thread_unpark(sqd);
-               }
-
-               io_req_caches_free(ctx);
-
-               if (WARN_ON_ONCE(time_after(jiffies, timeout))) {
-                       /* there is little hope left, don't run it too often */
-                       interval = HZ * 60;
-               }
-       } while (!wait_for_completion_timeout(&ctx->ref_comp, interval));
-
-       init_completion(&exit.completion);
-       init_task_work(&exit.task_work, io_tctx_exit_cb);
-       exit.ctx = ctx;
-       /*
-        * Some may use context even when all refs and requests have been put,
-        * and they are free to do so while still holding uring_lock or
-        * completion_lock, see io_req_task_submit(). Apart from other work,
-        * this lock/unlock section also waits them to finish.
-        */
-       mutex_lock(&ctx->uring_lock);
-       while (!list_empty(&ctx->tctx_list)) {
-               WARN_ON_ONCE(time_after(jiffies, timeout));
-
-               node = list_first_entry(&ctx->tctx_list, struct io_tctx_node,
-                                       ctx_node);
-               /* don't spin on a single task if cancellation failed */
-               list_rotate_left(&ctx->tctx_list);
-               ret = task_work_add(node->task, &exit.task_work, TWA_SIGNAL);
-               if (WARN_ON_ONCE(ret))
-                       continue;
-
-               mutex_unlock(&ctx->uring_lock);
-               wait_for_completion(&exit.completion);
-               mutex_lock(&ctx->uring_lock);
-       }
-       mutex_unlock(&ctx->uring_lock);
-       spin_lock(&ctx->completion_lock);
-       spin_unlock(&ctx->completion_lock);
-
-       io_ring_ctx_free(ctx);
-}
-
-/* Returns true if we found and killed one or more timeouts */
-static __cold bool io_kill_timeouts(struct io_ring_ctx *ctx,
-                                   struct task_struct *tsk, bool cancel_all)
-{
-       struct io_kiocb *req, *tmp;
-       int canceled = 0;
-
-       spin_lock(&ctx->completion_lock);
-       spin_lock_irq(&ctx->timeout_lock);
-       list_for_each_entry_safe(req, tmp, &ctx->timeout_list, timeout.list) {
-               if (io_match_task(req, tsk, cancel_all)) {
-                       io_kill_timeout(req, -ECANCELED);
-                       canceled++;
-               }
-       }
-       spin_unlock_irq(&ctx->timeout_lock);
-       io_commit_cqring(ctx);
-       spin_unlock(&ctx->completion_lock);
-       if (canceled != 0)
-               io_cqring_ev_posted(ctx);
-       return canceled != 0;
-}
-
-static __cold void io_ring_ctx_wait_and_kill(struct io_ring_ctx *ctx)
-{
-       unsigned long index;
-       struct creds *creds;
-
-       mutex_lock(&ctx->uring_lock);
-       percpu_ref_kill(&ctx->refs);
-       if (ctx->rings)
-               __io_cqring_overflow_flush(ctx, true);
-       xa_for_each(&ctx->personalities, index, creds)
-               io_unregister_personality(ctx, index);
-       mutex_unlock(&ctx->uring_lock);
-
-       /* failed during ring init, it couldn't have issued any requests */
-       if (ctx->rings) {
-               io_kill_timeouts(ctx, NULL, true);
-               io_poll_remove_all(ctx, NULL, true);
-               /* if we failed setting up the ctx, we might not have any rings */
-               io_iopoll_try_reap_events(ctx);
-       }
-
-       INIT_WORK(&ctx->exit_work, io_ring_exit_work);
-       /*
-        * Use system_unbound_wq to avoid spawning tons of event kworkers
-        * if we're exiting a ton of rings at the same time. It just adds
-        * noise and overhead, there's no discernable change in runtime
-        * over using system_wq.
-        */
-       queue_work(system_unbound_wq, &ctx->exit_work);
-}
-
-static int io_uring_release(struct inode *inode, struct file *file)
-{
-       struct io_ring_ctx *ctx = file->private_data;
-
-       file->private_data = NULL;
-       io_ring_ctx_wait_and_kill(ctx);
-       return 0;
-}
-
-struct io_task_cancel {
-       struct task_struct *task;
-       bool all;
-};
-
-static bool io_cancel_task_cb(struct io_wq_work *work, void *data)
-{
-       struct io_kiocb *req = container_of(work, struct io_kiocb, work);
-       struct io_task_cancel *cancel = data;
-
-       return io_match_task_safe(req, cancel->task, cancel->all);
-}
-
-static __cold bool io_cancel_defer_files(struct io_ring_ctx *ctx,
-                                        struct task_struct *task,
-                                        bool cancel_all)
-{
-       struct io_defer_entry *de;
-       LIST_HEAD(list);
-
-       spin_lock(&ctx->completion_lock);
-       list_for_each_entry_reverse(de, &ctx->defer_list, list) {
-               if (io_match_task_safe(de->req, task, cancel_all)) {
-                       list_cut_position(&list, &ctx->defer_list, &de->list);
-                       break;
-               }
-       }
-       spin_unlock(&ctx->completion_lock);
-       if (list_empty(&list))
-               return false;
-
-       while (!list_empty(&list)) {
-               de = list_first_entry(&list, struct io_defer_entry, list);
-               list_del_init(&de->list);
-               io_req_complete_failed(de->req, -ECANCELED);
-               kfree(de);
-       }
-       return true;
-}
-
-static __cold bool io_uring_try_cancel_iowq(struct io_ring_ctx *ctx)
-{
-       struct io_tctx_node *node;
-       enum io_wq_cancel cret;
-       bool ret = false;
-
-       mutex_lock(&ctx->uring_lock);
-       list_for_each_entry(node, &ctx->tctx_list, ctx_node) {
-               struct io_uring_task *tctx = node->task->io_uring;
-
-               /*
-                * io_wq will stay alive while we hold uring_lock, because it's
-                * killed after ctx nodes, which requires to take the lock.
-                */
-               if (!tctx || !tctx->io_wq)
-                       continue;
-               cret = io_wq_cancel_cb(tctx->io_wq, io_cancel_ctx_cb, ctx, true);
-               ret |= (cret != IO_WQ_CANCEL_NOTFOUND);
-       }
-       mutex_unlock(&ctx->uring_lock);
-
-       return ret;
-}
-
-static __cold void io_uring_try_cancel_requests(struct io_ring_ctx *ctx,
-                                               struct task_struct *task,
-                                               bool cancel_all)
-{
-       struct io_task_cancel cancel = { .task = task, .all = cancel_all, };
-       struct io_uring_task *tctx = task ? task->io_uring : NULL;
-
-       /* failed during ring init, it couldn't have issued any requests */
-       if (!ctx->rings)
-               return;
-
-       while (1) {
-               enum io_wq_cancel cret;
-               bool ret = false;
-
-               if (!task) {
-                       ret |= io_uring_try_cancel_iowq(ctx);
-               } else if (tctx && tctx->io_wq) {
-                       /*
-                        * Cancels requests of all rings, not only @ctx, but
-                        * it's fine as the task is in exit/exec.
-                        */
-                       cret = io_wq_cancel_cb(tctx->io_wq, io_cancel_task_cb,
-                                              &cancel, true);
-                       ret |= (cret != IO_WQ_CANCEL_NOTFOUND);
-               }
-
-               /* SQPOLL thread does its own polling */
-               if ((!(ctx->flags & IORING_SETUP_SQPOLL) && cancel_all) ||
-                   (ctx->sq_data && ctx->sq_data->thread == current)) {
-                       while (!wq_list_empty(&ctx->iopoll_list)) {
-                               io_iopoll_try_reap_events(ctx);
-                               ret = true;
-                       }
-               }
-
-               ret |= io_cancel_defer_files(ctx, task, cancel_all);
-               ret |= io_poll_remove_all(ctx, task, cancel_all);
-               ret |= io_kill_timeouts(ctx, task, cancel_all);
-               if (task)
-                       ret |= io_run_task_work();
-               if (!ret)
-                       break;
-               cond_resched();
-       }
-}
-
-static int __io_uring_add_tctx_node(struct io_ring_ctx *ctx)
-{
-       struct io_uring_task *tctx = current->io_uring;
-       struct io_tctx_node *node;
-       int ret;
-
-       if (unlikely(!tctx)) {
-               ret = io_uring_alloc_task_context(current, ctx);
-               if (unlikely(ret))
-                       return ret;
-
-               tctx = current->io_uring;
-               if (ctx->iowq_limits_set) {
-                       unsigned int limits[2] = { ctx->iowq_limits[0],
-                                                  ctx->iowq_limits[1], };
-
-                       ret = io_wq_max_workers(tctx->io_wq, limits);
-                       if (ret)
-                               return ret;
-               }
-       }
-       if (!xa_load(&tctx->xa, (unsigned long)ctx)) {
-               node = kmalloc(sizeof(*node), GFP_KERNEL);
-               if (!node)
-                       return -ENOMEM;
-               node->ctx = ctx;
-               node->task = current;
-
-               ret = xa_err(xa_store(&tctx->xa, (unsigned long)ctx,
-                                       node, GFP_KERNEL));
-               if (ret) {
-                       kfree(node);
-                       return ret;
-               }
-
-               mutex_lock(&ctx->uring_lock);
-               list_add(&node->ctx_node, &ctx->tctx_list);
-               mutex_unlock(&ctx->uring_lock);
-       }
-       tctx->last = ctx;
-       return 0;
-}
-
-/*
- * Note that this task has used io_uring. We use it for cancelation purposes.
- */
-static inline int io_uring_add_tctx_node(struct io_ring_ctx *ctx)
-{
-       struct io_uring_task *tctx = current->io_uring;
-
-       if (likely(tctx && tctx->last == ctx))
-               return 0;
-       return __io_uring_add_tctx_node(ctx);
-}
-
-/*
- * Remove this io_uring_file -> task mapping.
- */
-static __cold void io_uring_del_tctx_node(unsigned long index)
-{
-       struct io_uring_task *tctx = current->io_uring;
-       struct io_tctx_node *node;
-
-       if (!tctx)
-               return;
-       node = xa_erase(&tctx->xa, index);
-       if (!node)
-               return;
-
-       WARN_ON_ONCE(current != node->task);
-       WARN_ON_ONCE(list_empty(&node->ctx_node));
-
-       mutex_lock(&node->ctx->uring_lock);
-       list_del(&node->ctx_node);
-       mutex_unlock(&node->ctx->uring_lock);
-
-       if (tctx->last == node->ctx)
-               tctx->last = NULL;
-       kfree(node);
-}
-
-static __cold void io_uring_clean_tctx(struct io_uring_task *tctx)
-{
-       struct io_wq *wq = tctx->io_wq;
-       struct io_tctx_node *node;
-       unsigned long index;
-
-       xa_for_each(&tctx->xa, index, node) {
-               io_uring_del_tctx_node(index);
-               cond_resched();
-       }
-       if (wq) {
-               /*
-                * Must be after io_uring_del_tctx_node() (removes nodes under
-                * uring_lock) to avoid race with io_uring_try_cancel_iowq().
-                */
-               io_wq_put_and_exit(wq);
-               tctx->io_wq = NULL;
-       }
-}
-
-static s64 tctx_inflight(struct io_uring_task *tctx, bool tracked)
-{
-       if (tracked)
-               return atomic_read(&tctx->inflight_tracked);
-       return percpu_counter_sum(&tctx->inflight);
-}
-
-/*
- * Find any io_uring ctx that this task has registered or done IO on, and cancel
- * requests. @sqd should be not-null IFF it's an SQPOLL thread cancellation.
- */
-static __cold void io_uring_cancel_generic(bool cancel_all,
-                                          struct io_sq_data *sqd)
-{
-       struct io_uring_task *tctx = current->io_uring;
-       struct io_ring_ctx *ctx;
-       s64 inflight;
-       DEFINE_WAIT(wait);
-
-       WARN_ON_ONCE(sqd && sqd->thread != current);
-
-       if (!current->io_uring)
-               return;
-       if (tctx->io_wq)
-               io_wq_exit_start(tctx->io_wq);
-
-       atomic_inc(&tctx->in_idle);
-       do {
-               io_uring_drop_tctx_refs(current);
-               /* read completions before cancelations */
-               inflight = tctx_inflight(tctx, !cancel_all);
-               if (!inflight)
-                       break;
-
-               if (!sqd) {
-                       struct io_tctx_node *node;
-                       unsigned long index;
-
-                       xa_for_each(&tctx->xa, index, node) {
-                               /* sqpoll task will cancel all its requests */
-                               if (node->ctx->sq_data)
-                                       continue;
-                               io_uring_try_cancel_requests(node->ctx, current,
-                                                            cancel_all);
-                       }
-               } else {
-                       list_for_each_entry(ctx, &sqd->ctx_list, sqd_list)
-                               io_uring_try_cancel_requests(ctx, current,
-                                                            cancel_all);
-               }
-
-               prepare_to_wait(&tctx->wait, &wait, TASK_INTERRUPTIBLE);
-               io_run_task_work();
-               io_uring_drop_tctx_refs(current);
-
-               /*
-                * If we've seen completions, retry without waiting. This
-                * avoids a race where a completion comes in before we did
-                * prepare_to_wait().
-                */
-               if (inflight == tctx_inflight(tctx, !cancel_all))
-                       schedule();
-               finish_wait(&tctx->wait, &wait);
-       } while (1);
-
-       io_uring_clean_tctx(tctx);
-       if (cancel_all) {
-               /*
-                * We shouldn't run task_works after cancel, so just leave
-                * ->in_idle set for normal exit.
-                */
-               atomic_dec(&tctx->in_idle);
-               /* for exec all current's requests should be gone, kill tctx */
-               __io_uring_free(current);
-       }
-}
-
-void __io_uring_cancel(bool cancel_all)
-{
-       io_uring_cancel_generic(cancel_all, NULL);
-}
-
-void io_uring_unreg_ringfd(void)
-{
-       struct io_uring_task *tctx = current->io_uring;
-       int i;
-
-       for (i = 0; i < IO_RINGFD_REG_MAX; i++) {
-               if (tctx->registered_rings[i]) {
-                       fput(tctx->registered_rings[i]);
-                       tctx->registered_rings[i] = NULL;
-               }
-       }
-}
-
-static int io_ring_add_registered_fd(struct io_uring_task *tctx, int fd,
-                                    int start, int end)
-{
-       struct file *file;
-       int offset;
-
-       for (offset = start; offset < end; offset++) {
-               offset = array_index_nospec(offset, IO_RINGFD_REG_MAX);
-               if (tctx->registered_rings[offset])
-                       continue;
-
-               file = fget(fd);
-               if (!file) {
-                       return -EBADF;
-               } else if (file->f_op != &io_uring_fops) {
-                       fput(file);
-                       return -EOPNOTSUPP;
-               }
-               tctx->registered_rings[offset] = file;
-               return offset;
-       }
-
-       return -EBUSY;
-}
-
-/*
- * Register a ring fd to avoid fdget/fdput for each io_uring_enter()
- * invocation. User passes in an array of struct io_uring_rsrc_update
- * with ->data set to the ring_fd, and ->offset given for the desired
- * index. If no index is desired, application may set ->offset == -1U
- * and we'll find an available index. Returns number of entries
- * successfully processed, or < 0 on error if none were processed.
- */
-static int io_ringfd_register(struct io_ring_ctx *ctx, void __user *__arg,
-                             unsigned nr_args)
-{
-       struct io_uring_rsrc_update __user *arg = __arg;
-       struct io_uring_rsrc_update reg;
-       struct io_uring_task *tctx;
-       int ret, i;
-
-       if (!nr_args || nr_args > IO_RINGFD_REG_MAX)
-               return -EINVAL;
-
-       mutex_unlock(&ctx->uring_lock);
-       ret = io_uring_add_tctx_node(ctx);
-       mutex_lock(&ctx->uring_lock);
-       if (ret)
-               return ret;
-
-       tctx = current->io_uring;
-       for (i = 0; i < nr_args; i++) {
-               int start, end;
-
-               if (copy_from_user(&reg, &arg[i], sizeof(reg))) {
-                       ret = -EFAULT;
-                       break;
-               }
-
-               if (reg.resv) {
-                       ret = -EINVAL;
-                       break;
-               }
-
-               if (reg.offset == -1U) {
-                       start = 0;
-                       end = IO_RINGFD_REG_MAX;
-               } else {
-                       if (reg.offset >= IO_RINGFD_REG_MAX) {
-                               ret = -EINVAL;
-                               break;
-                       }
-                       start = reg.offset;
-                       end = start + 1;
-               }
-
-               ret = io_ring_add_registered_fd(tctx, reg.data, start, end);
-               if (ret < 0)
-                       break;
-
-               reg.offset = ret;
-               if (copy_to_user(&arg[i], &reg, sizeof(reg))) {
-                       fput(tctx->registered_rings[reg.offset]);
-                       tctx->registered_rings[reg.offset] = NULL;
-                       ret = -EFAULT;
-                       break;
-               }
-       }
-
-       return i ? i : ret;
-}
-
-static int io_ringfd_unregister(struct io_ring_ctx *ctx, void __user *__arg,
-                               unsigned nr_args)
-{
-       struct io_uring_rsrc_update __user *arg = __arg;
-       struct io_uring_task *tctx = current->io_uring;
-       struct io_uring_rsrc_update reg;
-       int ret = 0, i;
-
-       if (!nr_args || nr_args > IO_RINGFD_REG_MAX)
-               return -EINVAL;
-       if (!tctx)
-               return 0;
-
-       for (i = 0; i < nr_args; i++) {
-               if (copy_from_user(&reg, &arg[i], sizeof(reg))) {
-                       ret = -EFAULT;
-                       break;
-               }
-               if (reg.resv || reg.data || reg.offset >= IO_RINGFD_REG_MAX) {
-                       ret = -EINVAL;
-                       break;
-               }
-
-               reg.offset = array_index_nospec(reg.offset, IO_RINGFD_REG_MAX);
-               if (tctx->registered_rings[reg.offset]) {
-                       fput(tctx->registered_rings[reg.offset]);
-                       tctx->registered_rings[reg.offset] = NULL;
-               }
-       }
-
-       return i ? i : ret;
-}
-
-static void *io_uring_validate_mmap_request(struct file *file,
-                                           loff_t pgoff, size_t sz)
-{
-       struct io_ring_ctx *ctx = file->private_data;
-       loff_t offset = pgoff << PAGE_SHIFT;
-       struct page *page;
-       void *ptr;
-
-       switch (offset) {
-       case IORING_OFF_SQ_RING:
-       case IORING_OFF_CQ_RING:
-               ptr = ctx->rings;
-               break;
-       case IORING_OFF_SQES:
-               ptr = ctx->sq_sqes;
-               break;
-       default:
-               return ERR_PTR(-EINVAL);
-       }
-
-       page = virt_to_head_page(ptr);
-       if (sz > page_size(page))
-               return ERR_PTR(-EINVAL);
-
-       return ptr;
-}
-
-#ifdef CONFIG_MMU
-
-static __cold int io_uring_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       size_t sz = vma->vm_end - vma->vm_start;
-       unsigned long pfn;
-       void *ptr;
-
-       ptr = io_uring_validate_mmap_request(file, vma->vm_pgoff, sz);
-       if (IS_ERR(ptr))
-               return PTR_ERR(ptr);
-
-       pfn = virt_to_phys(ptr) >> PAGE_SHIFT;
-       return remap_pfn_range(vma, vma->vm_start, pfn, sz, vma->vm_page_prot);
-}
-
-#else /* !CONFIG_MMU */
-
-static int io_uring_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       return vma->vm_flags & (VM_SHARED | VM_MAYSHARE) ? 0 : -EINVAL;
-}
-
-static unsigned int io_uring_nommu_mmap_capabilities(struct file *file)
-{
-       return NOMMU_MAP_DIRECT | NOMMU_MAP_READ | NOMMU_MAP_WRITE;
-}
-
-static unsigned long io_uring_nommu_get_unmapped_area(struct file *file,
-       unsigned long addr, unsigned long len,
-       unsigned long pgoff, unsigned long flags)
-{
-       void *ptr;
-
-       ptr = io_uring_validate_mmap_request(file, pgoff, len);
-       if (IS_ERR(ptr))
-               return PTR_ERR(ptr);
-
-       return (unsigned long) ptr;
-}
-
-#endif /* !CONFIG_MMU */
-
-static int io_sqpoll_wait_sq(struct io_ring_ctx *ctx)
-{
-       DEFINE_WAIT(wait);
-
-       do {
-               if (!io_sqring_full(ctx))
-                       break;
-               prepare_to_wait(&ctx->sqo_sq_wait, &wait, TASK_INTERRUPTIBLE);
-
-               if (!io_sqring_full(ctx))
-                       break;
-               schedule();
-       } while (!signal_pending(current));
-
-       finish_wait(&ctx->sqo_sq_wait, &wait);
-       return 0;
-}
-
-static int io_validate_ext_arg(unsigned flags, const void __user *argp, size_t argsz)
-{
-       if (flags & IORING_ENTER_EXT_ARG) {
-               struct io_uring_getevents_arg arg;
-
-               if (argsz != sizeof(arg))
-                       return -EINVAL;
-               if (copy_from_user(&arg, argp, sizeof(arg)))
-                       return -EFAULT;
-       }
-       return 0;
-}
-
-static int io_get_ext_arg(unsigned flags, const void __user *argp, size_t *argsz,
-                         struct __kernel_timespec __user **ts,
-                         const sigset_t __user **sig)
-{
-       struct io_uring_getevents_arg arg;
-
-       /*
-        * If EXT_ARG isn't set, then we have no timespec and the argp pointer
-        * is just a pointer to the sigset_t.
-        */
-       if (!(flags & IORING_ENTER_EXT_ARG)) {
-               *sig = (const sigset_t __user *) argp;
-               *ts = NULL;
-               return 0;
-       }
-
-       /*
-        * EXT_ARG is set - ensure we agree on the size of it and copy in our
-        * timespec and sigset_t pointers if good.
-        */
-       if (*argsz != sizeof(arg))
-               return -EINVAL;
-       if (copy_from_user(&arg, argp, sizeof(arg)))
-               return -EFAULT;
-       if (arg.pad)
-               return -EINVAL;
-       *sig = u64_to_user_ptr(arg.sigmask);
-       *argsz = arg.sigmask_sz;
-       *ts = u64_to_user_ptr(arg.ts);
-       return 0;
-}
-
-SYSCALL_DEFINE6(io_uring_enter, unsigned int, fd, u32, to_submit,
-               u32, min_complete, u32, flags, const void __user *, argp,
-               size_t, argsz)
-{
-       struct io_ring_ctx *ctx;
-       struct fd f;
-       long ret;
-
-       io_run_task_work();
-
-       if (unlikely(flags & ~(IORING_ENTER_GETEVENTS | IORING_ENTER_SQ_WAKEUP |
-                              IORING_ENTER_SQ_WAIT | IORING_ENTER_EXT_ARG |
-                              IORING_ENTER_REGISTERED_RING)))
-               return -EINVAL;
-
-       /*
-        * Ring fd has been registered via IORING_REGISTER_RING_FDS, we
-        * need only dereference our task private array to find it.
-        */
-       if (flags & IORING_ENTER_REGISTERED_RING) {
-               struct io_uring_task *tctx = current->io_uring;
-
-               if (!tctx || fd >= IO_RINGFD_REG_MAX)
-                       return -EINVAL;
-               fd = array_index_nospec(fd, IO_RINGFD_REG_MAX);
-               f.file = tctx->registered_rings[fd];
-               f.flags = 0;
-       } else {
-               f = fdget(fd);
-       }
-
-       if (unlikely(!f.file))
-               return -EBADF;
-
-       ret = -EOPNOTSUPP;
-       if (unlikely(f.file->f_op != &io_uring_fops))
-               goto out_fput;
-
-       ret = -ENXIO;
-       ctx = f.file->private_data;
-       if (unlikely(!percpu_ref_tryget(&ctx->refs)))
-               goto out_fput;
-
-       ret = -EBADFD;
-       if (unlikely(ctx->flags & IORING_SETUP_R_DISABLED))
-               goto out;
-
-       /*
-        * For SQ polling, the thread will do all submissions and completions.
-        * Just return the requested submit count, and wake the thread if
-        * we were asked to.
-        */
-       ret = 0;
-       if (ctx->flags & IORING_SETUP_SQPOLL) {
-               io_cqring_overflow_flush(ctx);
-
-               if (unlikely(ctx->sq_data->thread == NULL)) {
-                       ret = -EOWNERDEAD;
-                       goto out;
-               }
-               if (flags & IORING_ENTER_SQ_WAKEUP)
-                       wake_up(&ctx->sq_data->wait);
-               if (flags & IORING_ENTER_SQ_WAIT) {
-                       ret = io_sqpoll_wait_sq(ctx);
-                       if (ret)
-                               goto out;
-               }
-               ret = to_submit;
-       } else if (to_submit) {
-               ret = io_uring_add_tctx_node(ctx);
-               if (unlikely(ret))
-                       goto out;
-
-               mutex_lock(&ctx->uring_lock);
-               ret = io_submit_sqes(ctx, to_submit);
-               if (ret != to_submit) {
-                       mutex_unlock(&ctx->uring_lock);
-                       goto out;
-               }
-               if ((flags & IORING_ENTER_GETEVENTS) && ctx->syscall_iopoll)
-                       goto iopoll_locked;
-               mutex_unlock(&ctx->uring_lock);
-       }
-       if (flags & IORING_ENTER_GETEVENTS) {
-               int ret2;
-               if (ctx->syscall_iopoll) {
-                       /*
-                        * We disallow the app entering submit/complete with
-                        * polling, but we still need to lock the ring to
-                        * prevent racing with polled issue that got punted to
-                        * a workqueue.
-                        */
-                       mutex_lock(&ctx->uring_lock);
-iopoll_locked:
-                       ret2 = io_validate_ext_arg(flags, argp, argsz);
-                       if (likely(!ret2)) {
-                               min_complete = min(min_complete,
-                                                  ctx->cq_entries);
-                               ret2 = io_iopoll_check(ctx, min_complete);
-                       }
-                       mutex_unlock(&ctx->uring_lock);
-               } else {
-                       const sigset_t __user *sig;
-                       struct __kernel_timespec __user *ts;
-
-                       ret2 = io_get_ext_arg(flags, argp, &argsz, &ts, &sig);
-                       if (likely(!ret2)) {
-                               min_complete = min(min_complete,
-                                                  ctx->cq_entries);
-                               ret2 = io_cqring_wait(ctx, min_complete, sig,
-                                                     argsz, ts);
-                       }
-               }
-
-               if (!ret) {
-                       ret = ret2;
-
-                       /*
-                        * EBADR indicates that one or more CQE were dropped.
-                        * Once the user has been informed we can clear the bit
-                        * as they are obviously ok with those drops.
-                        */
-                       if (unlikely(ret2 == -EBADR))
-                               clear_bit(IO_CHECK_CQ_DROPPED_BIT,
-                                         &ctx->check_cq);
-               }
-       }
-
-out:
-       percpu_ref_put(&ctx->refs);
-out_fput:
-       fdput(f);
-       return ret;
-}
-
-#ifdef CONFIG_PROC_FS
-static __cold int io_uring_show_cred(struct seq_file *m, unsigned int id,
-               const struct cred *cred)
-{
-       struct user_namespace *uns = seq_user_ns(m);
-       struct group_info *gi;
-       kernel_cap_t cap;
-       unsigned __capi;
-       int g;
-
-       seq_printf(m, "%5d\n", id);
-       seq_put_decimal_ull(m, "\tUid:\t", from_kuid_munged(uns, cred->uid));
-       seq_put_decimal_ull(m, "\t\t", from_kuid_munged(uns, cred->euid));
-       seq_put_decimal_ull(m, "\t\t", from_kuid_munged(uns, cred->suid));
-       seq_put_decimal_ull(m, "\t\t", from_kuid_munged(uns, cred->fsuid));
-       seq_put_decimal_ull(m, "\n\tGid:\t", from_kgid_munged(uns, cred->gid));
-       seq_put_decimal_ull(m, "\t\t", from_kgid_munged(uns, cred->egid));
-       seq_put_decimal_ull(m, "\t\t", from_kgid_munged(uns, cred->sgid));
-       seq_put_decimal_ull(m, "\t\t", from_kgid_munged(uns, cred->fsgid));
-       seq_puts(m, "\n\tGroups:\t");
-       gi = cred->group_info;
-       for (g = 0; g < gi->ngroups; g++) {
-               seq_put_decimal_ull(m, g ? " " : "",
-                                       from_kgid_munged(uns, gi->gid[g]));
-       }
-       seq_puts(m, "\n\tCapEff:\t");
-       cap = cred->cap_effective;
-       CAP_FOR_EACH_U32(__capi)
-               seq_put_hex_ll(m, NULL, cap.cap[CAP_LAST_U32 - __capi], 8);
-       seq_putc(m, '\n');
-       return 0;
-}
-
-static __cold void __io_uring_show_fdinfo(struct io_ring_ctx *ctx,
-                                         struct seq_file *m)
-{
-       struct io_sq_data *sq = NULL;
-       struct io_overflow_cqe *ocqe;
-       struct io_rings *r = ctx->rings;
-       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);
-       unsigned int cq_head = READ_ONCE(r->cq.head);
-       unsigned int cq_tail = READ_ONCE(r->cq.tail);
-       unsigned int cq_shift = 0;
-       unsigned int sq_entries, cq_entries;
-       bool has_lock;
-       bool is_cqe32 = (ctx->flags & IORING_SETUP_CQE32);
-       unsigned int i;
-
-       if (is_cqe32)
-               cq_shift = 1;
-
-       /*
-        * we may get imprecise sqe and cqe info if uring is actively running
-        * since we get cached_sq_head and cached_cq_tail without uring_lock
-        * and sq_tail and cq_head are changed by userspace. But it's ok since
-        * we usually use these info when it is stuck.
-        */
-       seq_printf(m, "SqMask:\t0x%x\n", sq_mask);
-       seq_printf(m, "SqHead:\t%u\n", sq_head);
-       seq_printf(m, "SqTail:\t%u\n", sq_tail);
-       seq_printf(m, "CachedSqHead:\t%u\n", ctx->cached_sq_head);
-       seq_printf(m, "CqMask:\t0x%x\n", cq_mask);
-       seq_printf(m, "CqHead:\t%u\n", cq_head);
-       seq_printf(m, "CqTail:\t%u\n", cq_tail);
-       seq_printf(m, "CachedCqTail:\t%u\n", ctx->cached_cq_tail);
-       seq_printf(m, "SQEs:\t%u\n", sq_tail - ctx->cached_sq_head);
-       sq_entries = min(sq_tail - sq_head, ctx->sq_entries);
-       for (i = 0; i < sq_entries; i++) {
-               unsigned int entry = i + sq_head;
-               unsigned int sq_idx = READ_ONCE(ctx->sq_array[entry & sq_mask]);
-               struct io_uring_sqe *sqe;
-
-               if (sq_idx > sq_mask)
-                       continue;
-               sqe = &ctx->sq_sqes[sq_idx];
-               seq_printf(m, "%5u: opcode:%d, fd:%d, flags:%x, user_data:%llu\n",
-                          sq_idx, sqe->opcode, sqe->fd, sqe->flags,
-                          sqe->user_data);
-       }
-       seq_printf(m, "CQEs:\t%u\n", cq_tail - cq_head);
-       cq_entries = min(cq_tail - cq_head, ctx->cq_entries);
-       for (i = 0; i < cq_entries; i++) {
-               unsigned int entry = i + cq_head;
-               struct io_uring_cqe *cqe = &r->cqes[(entry & cq_mask) << cq_shift];
-
-               if (!is_cqe32) {
-                       seq_printf(m, "%5u: user_data:%llu, res:%d, flag:%x\n",
-                          entry & cq_mask, cqe->user_data, cqe->res,
-                          cqe->flags);
-               } else {
-                       seq_printf(m, "%5u: user_data:%llu, res:%d, flag:%x, "
-                               "extra1:%llu, extra2:%llu\n",
-                               entry & cq_mask, cqe->user_data, cqe->res,
-                               cqe->flags, cqe->big_cqe[0], cqe->big_cqe[1]);
-               }
-       }
-
-       /*
-        * Avoid ABBA deadlock between the seq lock and the io_uring mutex,
-        * since fdinfo case grabs it in the opposite direction of normal use
-        * cases. If we fail to get the lock, we just don't iterate any
-        * structures that could be going away outside the io_uring mutex.
-        */
-       has_lock = mutex_trylock(&ctx->uring_lock);
-
-       if (has_lock && (ctx->flags & IORING_SETUP_SQPOLL)) {
-               sq = ctx->sq_data;
-               if (!sq->thread)
-                       sq = NULL;
-       }
-
-       seq_printf(m, "SqThread:\t%d\n", sq ? task_pid_nr(sq->thread) : -1);
-       seq_printf(m, "SqThreadCpu:\t%d\n", sq ? task_cpu(sq->thread) : -1);
-       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, i);
-
-               if (f)
-                       seq_printf(m, "%5u: %s\n", i, file_dentry(f)->d_iname);
-               else
-                       seq_printf(m, "%5u: <none>\n", i);
-       }
-       seq_printf(m, "UserBufs:\t%u\n", ctx->nr_user_bufs);
-       for (i = 0; has_lock && i < ctx->nr_user_bufs; i++) {
-               struct io_mapped_ubuf *buf = ctx->user_bufs[i];
-               unsigned int len = buf->ubuf_end - buf->ubuf;
-
-               seq_printf(m, "%5u: 0x%llx/%u\n", i, buf->ubuf, len);
-       }
-       if (has_lock && !xa_empty(&ctx->personalities)) {
-               unsigned long index;
-               const struct cred *cred;
-
-               seq_printf(m, "Personalities:\n");
-               xa_for_each(&ctx->personalities, index, cred)
-                       io_uring_show_cred(m, index, cred);
-       }
-       if (has_lock)
-               mutex_unlock(&ctx->uring_lock);
-
-       seq_puts(m, "PollList:\n");
-       spin_lock(&ctx->completion_lock);
-       for (i = 0; i < (1U << ctx->cancel_hash_bits); i++) {
-               struct hlist_head *list = &ctx->cancel_hash[i];
-               struct io_kiocb *req;
-
-               hlist_for_each_entry(req, list, hash_node)
-                       seq_printf(m, "  op=%d, task_works=%d\n", req->opcode,
-                                       task_work_pending(req->task));
-       }
-
-       seq_puts(m, "CqOverflowList:\n");
-       list_for_each_entry(ocqe, &ctx->cq_overflow_list, list) {
-               struct io_uring_cqe *cqe = &ocqe->cqe;
-
-               seq_printf(m, "  user_data=%llu, res=%d, flags=%x\n",
-                          cqe->user_data, cqe->res, cqe->flags);
-
-       }
-
-       spin_unlock(&ctx->completion_lock);
-}
-
-static __cold void io_uring_show_fdinfo(struct seq_file *m, struct file *f)
-{
-       struct io_ring_ctx *ctx = f->private_data;
-
-       if (percpu_ref_tryget(&ctx->refs)) {
-               __io_uring_show_fdinfo(ctx, m);
-               percpu_ref_put(&ctx->refs);
-       }
-}
-#endif
-
-static const struct file_operations io_uring_fops = {
-       .release        = io_uring_release,
-       .mmap           = io_uring_mmap,
-#ifndef CONFIG_MMU
-       .get_unmapped_area = io_uring_nommu_get_unmapped_area,
-       .mmap_capabilities = io_uring_nommu_mmap_capabilities,
-#endif
-       .poll           = io_uring_poll,
-#ifdef CONFIG_PROC_FS
-       .show_fdinfo    = io_uring_show_fdinfo,
-#endif
-};
-
-static __cold int io_allocate_scq_urings(struct io_ring_ctx *ctx,
-                                        struct io_uring_params *p)
-{
-       struct io_rings *rings;
-       size_t size, sq_array_offset;
-
-       /* make sure these are sane, as we already accounted them */
-       ctx->sq_entries = p->sq_entries;
-       ctx->cq_entries = p->cq_entries;
-
-       size = rings_size(ctx, p->sq_entries, p->cq_entries, &sq_array_offset);
-       if (size == SIZE_MAX)
-               return -EOVERFLOW;
-
-       rings = io_mem_alloc(size);
-       if (!rings)
-               return -ENOMEM;
-
-       ctx->rings = rings;
-       ctx->sq_array = (u32 *)((char *)rings + sq_array_offset);
-       rings->sq_ring_mask = p->sq_entries - 1;
-       rings->cq_ring_mask = p->cq_entries - 1;
-       rings->sq_ring_entries = p->sq_entries;
-       rings->cq_ring_entries = p->cq_entries;
-
-       if (p->flags & IORING_SETUP_SQE128)
-               size = array_size(2 * sizeof(struct io_uring_sqe), p->sq_entries);
-       else
-               size = array_size(sizeof(struct io_uring_sqe), p->sq_entries);
-       if (size == SIZE_MAX) {
-               io_mem_free(ctx->rings);
-               ctx->rings = NULL;
-               return -EOVERFLOW;
-       }
-
-       ctx->sq_sqes = io_mem_alloc(size);
-       if (!ctx->sq_sqes) {
-               io_mem_free(ctx->rings);
-               ctx->rings = NULL;
-               return -ENOMEM;
-       }
-
-       return 0;
-}
-
-static int io_uring_install_fd(struct io_ring_ctx *ctx, struct file *file)
-{
-       int ret, fd;
-
-       fd = get_unused_fd_flags(O_RDWR | O_CLOEXEC);
-       if (fd < 0)
-               return fd;
-
-       ret = io_uring_add_tctx_node(ctx);
-       if (ret) {
-               put_unused_fd(fd);
-               return ret;
-       }
-       fd_install(fd, file);
-       return fd;
-}
-
-/*
- * Allocate an anonymous fd, this is what constitutes the application
- * visible backing of an io_uring instance. The application mmaps this
- * fd to gain access to the SQ/CQ ring details. If UNIX sockets are enabled,
- * we have to tie this fd to a socket for file garbage collection purposes.
- */
-static struct file *io_uring_get_file(struct io_ring_ctx *ctx)
-{
-       struct file *file;
-#if defined(CONFIG_UNIX)
-       int ret;
-
-       ret = sock_create_kern(&init_net, PF_UNIX, SOCK_RAW, IPPROTO_IP,
-                               &ctx->ring_sock);
-       if (ret)
-               return ERR_PTR(ret);
-#endif
-
-       file = anon_inode_getfile_secure("[io_uring]", &io_uring_fops, ctx,
-                                        O_RDWR | O_CLOEXEC, NULL);
-#if defined(CONFIG_UNIX)
-       if (IS_ERR(file)) {
-               sock_release(ctx->ring_sock);
-               ctx->ring_sock = NULL;
-       } else {
-               ctx->ring_sock->file = file;
-       }
-#endif
-       return file;
-}
-
-static __cold int io_uring_create(unsigned entries, struct io_uring_params *p,
-                                 struct io_uring_params __user *params)
-{
-       struct io_ring_ctx *ctx;
-       struct file *file;
-       int ret;
-
-       if (!entries)
-               return -EINVAL;
-       if (entries > IORING_MAX_ENTRIES) {
-               if (!(p->flags & IORING_SETUP_CLAMP))
-                       return -EINVAL;
-               entries = IORING_MAX_ENTRIES;
-       }
-
-       /*
-        * Use twice as many entries for the CQ ring. It's possible for the
-        * application to drive a higher depth than the size of the SQ ring,
-        * since the sqes are only used at submission time. This allows for
-        * some flexibility in overcommitting a bit. If the application has
-        * set IORING_SETUP_CQSIZE, it will have passed in the desired number
-        * of CQ ring entries manually.
-        */
-       p->sq_entries = roundup_pow_of_two(entries);
-       if (p->flags & IORING_SETUP_CQSIZE) {
-               /*
-                * If IORING_SETUP_CQSIZE is set, we do the same roundup
-                * to a power-of-two, if it isn't already. We do NOT impose
-                * any cq vs sq ring sizing.
-                */
-               if (!p->cq_entries)
-                       return -EINVAL;
-               if (p->cq_entries > IORING_MAX_CQ_ENTRIES) {
-                       if (!(p->flags & IORING_SETUP_CLAMP))
-                               return -EINVAL;
-                       p->cq_entries = IORING_MAX_CQ_ENTRIES;
-               }
-               p->cq_entries = roundup_pow_of_two(p->cq_entries);
-               if (p->cq_entries < p->sq_entries)
-                       return -EINVAL;
-       } else {
-               p->cq_entries = 2 * p->sq_entries;
-       }
-
-       ctx = io_ring_ctx_alloc(p);
-       if (!ctx)
-               return -ENOMEM;
-
-       /*
-        * When SETUP_IOPOLL and SETUP_SQPOLL are both enabled, user
-        * space applications don't need to do io completion events
-        * polling again, they can rely on io_sq_thread to do polling
-        * work, which can reduce cpu usage and uring_lock contention.
-        */
-       if (ctx->flags & IORING_SETUP_IOPOLL &&
-           !(ctx->flags & IORING_SETUP_SQPOLL))
-               ctx->syscall_iopoll = 1;
-
-       ctx->compat = in_compat_syscall();
-       if (!capable(CAP_IPC_LOCK))
-               ctx->user = get_uid(current_user());
-
-       /*
-        * For SQPOLL, we just need a wakeup, always. For !SQPOLL, if
-        * COOP_TASKRUN is set, then IPIs are never needed by the app.
-        */
-       ret = -EINVAL;
-       if (ctx->flags & IORING_SETUP_SQPOLL) {
-               /* IPI related flags don't make sense with SQPOLL */
-               if (ctx->flags & (IORING_SETUP_COOP_TASKRUN |
-                                 IORING_SETUP_TASKRUN_FLAG))
-                       goto err;
-               ctx->notify_method = TWA_SIGNAL_NO_IPI;
-       } else if (ctx->flags & IORING_SETUP_COOP_TASKRUN) {
-               ctx->notify_method = TWA_SIGNAL_NO_IPI;
-       } else {
-               if (ctx->flags & IORING_SETUP_TASKRUN_FLAG)
-                       goto err;
-               ctx->notify_method = TWA_SIGNAL;
-       }
-
-       /*
-        * This is just grabbed for accounting purposes. When a process exits,
-        * the mm is exited and dropped before the files, hence we need to hang
-        * on to this mm purely for the purposes of being able to unaccount
-        * memory (locked/pinned vm). It's not used for anything else.
-        */
-       mmgrab(current->mm);
-       ctx->mm_account = current->mm;
-
-       ret = io_allocate_scq_urings(ctx, p);
-       if (ret)
-               goto err;
-
-       ret = io_sq_offload_create(ctx, p);
-       if (ret)
-               goto err;
-       /* always set a rsrc node */
-       ret = io_rsrc_node_switch_start(ctx);
-       if (ret)
-               goto err;
-       io_rsrc_node_switch(ctx, NULL);
-
-       memset(&p->sq_off, 0, sizeof(p->sq_off));
-       p->sq_off.head = offsetof(struct io_rings, sq.head);
-       p->sq_off.tail = offsetof(struct io_rings, sq.tail);
-       p->sq_off.ring_mask = offsetof(struct io_rings, sq_ring_mask);
-       p->sq_off.ring_entries = offsetof(struct io_rings, sq_ring_entries);
-       p->sq_off.flags = offsetof(struct io_rings, sq_flags);
-       p->sq_off.dropped = offsetof(struct io_rings, sq_dropped);
-       p->sq_off.array = (char *)ctx->sq_array - (char *)ctx->rings;
-
-       memset(&p->cq_off, 0, sizeof(p->cq_off));
-       p->cq_off.head = offsetof(struct io_rings, cq.head);
-       p->cq_off.tail = offsetof(struct io_rings, cq.tail);
-       p->cq_off.ring_mask = offsetof(struct io_rings, cq_ring_mask);
-       p->cq_off.ring_entries = offsetof(struct io_rings, cq_ring_entries);
-       p->cq_off.overflow = offsetof(struct io_rings, cq_overflow);
-       p->cq_off.cqes = offsetof(struct io_rings, cqes);
-       p->cq_off.flags = offsetof(struct io_rings, cq_flags);
-
-       p->features = IORING_FEAT_SINGLE_MMAP | IORING_FEAT_NODROP |
-                       IORING_FEAT_SUBMIT_STABLE | IORING_FEAT_RW_CUR_POS |
-                       IORING_FEAT_CUR_PERSONALITY | IORING_FEAT_FAST_POLL |
-                       IORING_FEAT_POLL_32BITS | IORING_FEAT_SQPOLL_NONFIXED |
-                       IORING_FEAT_EXT_ARG | IORING_FEAT_NATIVE_WORKERS |
-                       IORING_FEAT_RSRC_TAGS | IORING_FEAT_CQE_SKIP |
-                       IORING_FEAT_LINKED_FILE;
-
-       if (copy_to_user(params, p, sizeof(*p))) {
-               ret = -EFAULT;
-               goto err;
-       }
-
-       file = io_uring_get_file(ctx);
-       if (IS_ERR(file)) {
-               ret = PTR_ERR(file);
-               goto err;
-       }
-
-       /*
-        * Install ring fd as the very last thing, so we don't risk someone
-        * having closed it before we finish setup
-        */
-       ret = io_uring_install_fd(ctx, file);
-       if (ret < 0) {
-               /* fput will clean it up */
-               fput(file);
-               return ret;
-       }
-
-       trace_io_uring_create(ret, ctx, p->sq_entries, p->cq_entries, p->flags);
-       return ret;
-err:
-       io_ring_ctx_wait_and_kill(ctx);
-       return ret;
-}
-
-/*
- * Sets up an aio uring context, and returns the fd. Applications asks for a
- * ring size, we return the actual sq/cq ring sizes (among other things) in the
- * params structure passed in.
- */
-static long io_uring_setup(u32 entries, struct io_uring_params __user *params)
-{
-       struct io_uring_params p;
-       int i;
-
-       if (copy_from_user(&p, params, sizeof(p)))
-               return -EFAULT;
-       for (i = 0; i < ARRAY_SIZE(p.resv); i++) {
-               if (p.resv[i])
-                       return -EINVAL;
-       }
-
-       if (p.flags & ~(IORING_SETUP_IOPOLL | IORING_SETUP_SQPOLL |
-                       IORING_SETUP_SQ_AFF | IORING_SETUP_CQSIZE |
-                       IORING_SETUP_CLAMP | IORING_SETUP_ATTACH_WQ |
-                       IORING_SETUP_R_DISABLED | IORING_SETUP_SUBMIT_ALL |
-                       IORING_SETUP_COOP_TASKRUN | IORING_SETUP_TASKRUN_FLAG |
-                       IORING_SETUP_SQE128 | IORING_SETUP_CQE32))
-               return -EINVAL;
-
-       return io_uring_create(entries, &p, params);
-}
-
-SYSCALL_DEFINE2(io_uring_setup, u32, entries,
-               struct io_uring_params __user *, params)
-{
-       return io_uring_setup(entries, params);
-}
-
-static __cold int io_probe(struct io_ring_ctx *ctx, void __user *arg,
-                          unsigned nr_args)
-{
-       struct io_uring_probe *p;
-       size_t size;
-       int i, ret;
-
-       size = struct_size(p, ops, nr_args);
-       if (size == SIZE_MAX)
-               return -EOVERFLOW;
-       p = kzalloc(size, GFP_KERNEL);
-       if (!p)
-               return -ENOMEM;
-
-       ret = -EFAULT;
-       if (copy_from_user(p, arg, size))
-               goto out;
-       ret = -EINVAL;
-       if (memchr_inv(p, 0, size))
-               goto out;
-
-       p->last_op = IORING_OP_LAST - 1;
-       if (nr_args > IORING_OP_LAST)
-               nr_args = IORING_OP_LAST;
-
-       for (i = 0; i < nr_args; i++) {
-               p->ops[i].op = i;
-               if (!io_op_defs[i].not_supported)
-                       p->ops[i].flags = IO_URING_OP_SUPPORTED;
-       }
-       p->ops_len = i;
-
-       ret = 0;
-       if (copy_to_user(arg, p, size))
-               ret = -EFAULT;
-out:
-       kfree(p);
-       return ret;
-}
-
-static int io_register_personality(struct io_ring_ctx *ctx)
-{
-       const struct cred *creds;
-       u32 id;
-       int ret;
-
-       creds = get_current_cred();
-
-       ret = xa_alloc_cyclic(&ctx->personalities, &id, (void *)creds,
-                       XA_LIMIT(0, USHRT_MAX), &ctx->pers_next, GFP_KERNEL);
-       if (ret < 0) {
-               put_cred(creds);
-               return ret;
-       }
-       return id;
-}
-
-static __cold int io_register_restrictions(struct io_ring_ctx *ctx,
-                                          void __user *arg, unsigned int nr_args)
-{
-       struct io_uring_restriction *res;
-       size_t size;
-       int i, ret;
-
-       /* Restrictions allowed only if rings started disabled */
-       if (!(ctx->flags & IORING_SETUP_R_DISABLED))
-               return -EBADFD;
-
-       /* We allow only a single restrictions registration */
-       if (ctx->restrictions.registered)
-               return -EBUSY;
-
-       if (!arg || nr_args > IORING_MAX_RESTRICTIONS)
-               return -EINVAL;
-
-       size = array_size(nr_args, sizeof(*res));
-       if (size == SIZE_MAX)
-               return -EOVERFLOW;
-
-       res = memdup_user(arg, size);
-       if (IS_ERR(res))
-               return PTR_ERR(res);
-
-       ret = 0;
-
-       for (i = 0; i < nr_args; i++) {
-               switch (res[i].opcode) {
-               case IORING_RESTRICTION_REGISTER_OP:
-                       if (res[i].register_op >= IORING_REGISTER_LAST) {
-                               ret = -EINVAL;
-                               goto out;
-                       }
-
-                       __set_bit(res[i].register_op,
-                                 ctx->restrictions.register_op);
-                       break;
-               case IORING_RESTRICTION_SQE_OP:
-                       if (res[i].sqe_op >= IORING_OP_LAST) {
-                               ret = -EINVAL;
-                               goto out;
-                       }
-
-                       __set_bit(res[i].sqe_op, ctx->restrictions.sqe_op);
-                       break;
-               case IORING_RESTRICTION_SQE_FLAGS_ALLOWED:
-                       ctx->restrictions.sqe_flags_allowed = res[i].sqe_flags;
-                       break;
-               case IORING_RESTRICTION_SQE_FLAGS_REQUIRED:
-                       ctx->restrictions.sqe_flags_required = res[i].sqe_flags;
-                       break;
-               default:
-                       ret = -EINVAL;
-                       goto out;
-               }
-       }
-
-out:
-       /* Reset all restrictions if an error happened */
-       if (ret != 0)
-               memset(&ctx->restrictions, 0, sizeof(ctx->restrictions));
-       else
-               ctx->restrictions.registered = true;
-
-       kfree(res);
-       return ret;
-}
-
-static int io_register_enable_rings(struct io_ring_ctx *ctx)
-{
-       if (!(ctx->flags & IORING_SETUP_R_DISABLED))
-               return -EBADFD;
-
-       if (ctx->restrictions.registered)
-               ctx->restricted = 1;
-
-       ctx->flags &= ~IORING_SETUP_R_DISABLED;
-       if (ctx->sq_data && wq_has_sleeper(&ctx->sq_data->wait))
-               wake_up(&ctx->sq_data->wait);
-       return 0;
-}
-
-static int __io_register_rsrc_update(struct io_ring_ctx *ctx, unsigned type,
-                                    struct io_uring_rsrc_update2 *up,
-                                    unsigned nr_args)
-{
-       __u32 tmp;
-       int err;
-
-       if (check_add_overflow(up->offset, nr_args, &tmp))
-               return -EOVERFLOW;
-       err = io_rsrc_node_switch_start(ctx);
-       if (err)
-               return err;
-
-       switch (type) {
-       case IORING_RSRC_FILE:
-               return __io_sqe_files_update(ctx, up, nr_args);
-       case IORING_RSRC_BUFFER:
-               return __io_sqe_buffers_update(ctx, up, nr_args);
-       }
-       return -EINVAL;
-}
-
-static int io_register_files_update(struct io_ring_ctx *ctx, void __user *arg,
-                                   unsigned nr_args)
-{
-       struct io_uring_rsrc_update2 up;
-
-       if (!nr_args)
-               return -EINVAL;
-       memset(&up, 0, sizeof(up));
-       if (copy_from_user(&up, arg, sizeof(struct io_uring_rsrc_update)))
-               return -EFAULT;
-       if (up.resv || up.resv2)
-               return -EINVAL;
-       return __io_register_rsrc_update(ctx, IORING_RSRC_FILE, &up, nr_args);
-}
-
-static int io_register_rsrc_update(struct io_ring_ctx *ctx, void __user *arg,
-                                  unsigned size, unsigned type)
-{
-       struct io_uring_rsrc_update2 up;
-
-       if (size != sizeof(up))
-               return -EINVAL;
-       if (copy_from_user(&up, arg, sizeof(up)))
-               return -EFAULT;
-       if (!up.nr || up.resv || up.resv2)
-               return -EINVAL;
-       return __io_register_rsrc_update(ctx, type, &up, up.nr);
-}
-
-static __cold int io_register_rsrc(struct io_ring_ctx *ctx, void __user *arg,
-                           unsigned int size, unsigned int type)
-{
-       struct io_uring_rsrc_register rr;
-
-       /* keep it extendible */
-       if (size != sizeof(rr))
-               return -EINVAL;
-
-       memset(&rr, 0, sizeof(rr));
-       if (copy_from_user(&rr, arg, size))
-               return -EFAULT;
-       if (!rr.nr || rr.resv2)
-               return -EINVAL;
-       if (rr.flags & ~IORING_RSRC_REGISTER_SPARSE)
-               return -EINVAL;
-
-       switch (type) {
-       case IORING_RSRC_FILE:
-               if (rr.flags & IORING_RSRC_REGISTER_SPARSE && rr.data)
-                       break;
-               return io_sqe_files_register(ctx, u64_to_user_ptr(rr.data),
-                                            rr.nr, u64_to_user_ptr(rr.tags));
-       case IORING_RSRC_BUFFER:
-               if (rr.flags & IORING_RSRC_REGISTER_SPARSE && rr.data)
-                       break;
-               return io_sqe_buffers_register(ctx, u64_to_user_ptr(rr.data),
-                                              rr.nr, u64_to_user_ptr(rr.tags));
-       }
-       return -EINVAL;
-}
-
-static __cold int io_register_iowq_aff(struct io_ring_ctx *ctx,
-                                      void __user *arg, unsigned len)
-{
-       struct io_uring_task *tctx = current->io_uring;
-       cpumask_var_t new_mask;
-       int ret;
-
-       if (!tctx || !tctx->io_wq)
-               return -EINVAL;
-
-       if (!alloc_cpumask_var(&new_mask, GFP_KERNEL))
-               return -ENOMEM;
-
-       cpumask_clear(new_mask);
-       if (len > cpumask_size())
-               len = cpumask_size();
-
-       if (in_compat_syscall()) {
-               ret = compat_get_bitmap(cpumask_bits(new_mask),
-                                       (const compat_ulong_t __user *)arg,
-                                       len * 8 /* CHAR_BIT */);
-       } else {
-               ret = copy_from_user(new_mask, arg, len);
-       }
-
-       if (ret) {
-               free_cpumask_var(new_mask);
-               return -EFAULT;
-       }
-
-       ret = io_wq_cpu_affinity(tctx->io_wq, new_mask);
-       free_cpumask_var(new_mask);
-       return ret;
-}
-
-static __cold int io_unregister_iowq_aff(struct io_ring_ctx *ctx)
-{
-       struct io_uring_task *tctx = current->io_uring;
-
-       if (!tctx || !tctx->io_wq)
-               return -EINVAL;
-
-       return io_wq_cpu_affinity(tctx->io_wq, NULL);
-}
-
-static __cold int io_register_iowq_max_workers(struct io_ring_ctx *ctx,
-                                              void __user *arg)
-       __must_hold(&ctx->uring_lock)
-{
-       struct io_tctx_node *node;
-       struct io_uring_task *tctx = NULL;
-       struct io_sq_data *sqd = NULL;
-       __u32 new_count[2];
-       int i, ret;
-
-       if (copy_from_user(new_count, arg, sizeof(new_count)))
-               return -EFAULT;
-       for (i = 0; i < ARRAY_SIZE(new_count); i++)
-               if (new_count[i] > INT_MAX)
-                       return -EINVAL;
-
-       if (ctx->flags & IORING_SETUP_SQPOLL) {
-               sqd = ctx->sq_data;
-               if (sqd) {
-                       /*
-                        * Observe the correct sqd->lock -> ctx->uring_lock
-                        * ordering. Fine to drop uring_lock here, we hold
-                        * a ref to the ctx.
-                        */
-                       refcount_inc(&sqd->refs);
-                       mutex_unlock(&ctx->uring_lock);
-                       mutex_lock(&sqd->lock);
-                       mutex_lock(&ctx->uring_lock);
-                       if (sqd->thread)
-                               tctx = sqd->thread->io_uring;
-               }
-       } else {
-               tctx = current->io_uring;
-       }
-
-       BUILD_BUG_ON(sizeof(new_count) != sizeof(ctx->iowq_limits));
-
-       for (i = 0; i < ARRAY_SIZE(new_count); i++)
-               if (new_count[i])
-                       ctx->iowq_limits[i] = new_count[i];
-       ctx->iowq_limits_set = true;
-
-       if (tctx && tctx->io_wq) {
-               ret = io_wq_max_workers(tctx->io_wq, new_count);
-               if (ret)
-                       goto err;
-       } else {
-               memset(new_count, 0, sizeof(new_count));
-       }
-
-       if (sqd) {
-               mutex_unlock(&sqd->lock);
-               io_put_sq_data(sqd);
-       }
-
-       if (copy_to_user(arg, new_count, sizeof(new_count)))
-               return -EFAULT;
-
-       /* that's it for SQPOLL, only the SQPOLL task creates requests */
-       if (sqd)
-               return 0;
-
-       /* now propagate the restriction to all registered users */
-       list_for_each_entry(node, &ctx->tctx_list, ctx_node) {
-               struct io_uring_task *tctx = node->task->io_uring;
-
-               if (WARN_ON_ONCE(!tctx->io_wq))
-                       continue;
-
-               for (i = 0; i < ARRAY_SIZE(new_count); i++)
-                       new_count[i] = ctx->iowq_limits[i];
-               /* ignore errors, it always returns zero anyway */
-               (void)io_wq_max_workers(tctx->io_wq, new_count);
-       }
-       return 0;
-err:
-       if (sqd) {
-               mutex_unlock(&sqd->lock);
-               io_put_sq_data(sqd);
-       }
-       return ret;
-}
-
-static int io_register_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg)
-{
-       struct io_uring_buf_ring *br;
-       struct io_uring_buf_reg reg;
-       struct io_buffer_list *bl;
-       struct page **pages;
-       int nr_pages;
-
-       if (copy_from_user(&reg, arg, sizeof(reg)))
-               return -EFAULT;
-
-       if (reg.pad || reg.resv[0] || reg.resv[1] || reg.resv[2])
-               return -EINVAL;
-       if (!reg.ring_addr)
-               return -EFAULT;
-       if (reg.ring_addr & ~PAGE_MASK)
-               return -EINVAL;
-       if (!is_power_of_2(reg.ring_entries))
-               return -EINVAL;
-
-       /* cannot disambiguate full vs empty due to head/tail size */
-       if (reg.ring_entries >= 65536)
-               return -EINVAL;
-
-       if (unlikely(reg.bgid < BGID_ARRAY && !ctx->io_bl)) {
-               int ret = io_init_bl_list(ctx);
-               if (ret)
-                       return ret;
-       }
-
-       bl = io_buffer_get_list(ctx, reg.bgid);
-       if (bl) {
-               /* if mapped buffer ring OR classic exists, don't allow */
-               if (bl->buf_nr_pages || !list_empty(&bl->buf_list))
-                       return -EEXIST;
-       } else {
-               bl = kzalloc(sizeof(*bl), GFP_KERNEL);
-               if (!bl)
-                       return -ENOMEM;
-       }
-
-       pages = io_pin_pages(reg.ring_addr,
-                            struct_size(br, bufs, reg.ring_entries),
-                            &nr_pages);
-       if (IS_ERR(pages)) {
-               kfree(bl);
-               return PTR_ERR(pages);
-       }
-
-       br = page_address(pages[0]);
-       bl->buf_pages = pages;
-       bl->buf_nr_pages = nr_pages;
-       bl->nr_entries = reg.ring_entries;
-       bl->buf_ring = br;
-       bl->mask = reg.ring_entries - 1;
-       io_buffer_add_list(ctx, bl, reg.bgid);
-       return 0;
-}
-
-static int io_unregister_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg)
-{
-       struct io_uring_buf_reg reg;
-       struct io_buffer_list *bl;
-
-       if (copy_from_user(&reg, arg, sizeof(reg)))
-               return -EFAULT;
-       if (reg.pad || reg.resv[0] || reg.resv[1] || reg.resv[2])
-               return -EINVAL;
-
-       bl = io_buffer_get_list(ctx, reg.bgid);
-       if (!bl)
-               return -ENOENT;
-       if (!bl->buf_nr_pages)
-               return -EINVAL;
-
-       __io_remove_buffers(ctx, bl, -1U);
-       if (bl->bgid >= BGID_ARRAY) {
-               xa_erase(&ctx->io_bl_xa, bl->bgid);
-               kfree(bl);
-       }
-       return 0;
-}
-
-static int __io_uring_register(struct io_ring_ctx *ctx, unsigned opcode,
-                              void __user *arg, unsigned nr_args)
-       __releases(ctx->uring_lock)
-       __acquires(ctx->uring_lock)
-{
-       int ret;
-
-       /*
-        * We're inside the ring mutex, if the ref is already dying, then
-        * someone else killed the ctx or is already going through
-        * io_uring_register().
-        */
-       if (percpu_ref_is_dying(&ctx->refs))
-               return -ENXIO;
-
-       if (ctx->restricted) {
-               if (opcode >= IORING_REGISTER_LAST)
-                       return -EINVAL;
-               opcode = array_index_nospec(opcode, IORING_REGISTER_LAST);
-               if (!test_bit(opcode, ctx->restrictions.register_op))
-                       return -EACCES;
-       }
-
-       switch (opcode) {
-       case IORING_REGISTER_BUFFERS:
-               ret = -EFAULT;
-               if (!arg)
-                       break;
-               ret = io_sqe_buffers_register(ctx, arg, nr_args, NULL);
-               break;
-       case IORING_UNREGISTER_BUFFERS:
-               ret = -EINVAL;
-               if (arg || nr_args)
-                       break;
-               ret = io_sqe_buffers_unregister(ctx);
-               break;
-       case IORING_REGISTER_FILES:
-               ret = -EFAULT;
-               if (!arg)
-                       break;
-               ret = io_sqe_files_register(ctx, arg, nr_args, NULL);
-               break;
-       case IORING_UNREGISTER_FILES:
-               ret = -EINVAL;
-               if (arg || nr_args)
-                       break;
-               ret = io_sqe_files_unregister(ctx);
-               break;
-       case IORING_REGISTER_FILES_UPDATE:
-               ret = io_register_files_update(ctx, arg, nr_args);
-               break;
-       case IORING_REGISTER_EVENTFD:
-               ret = -EINVAL;
-               if (nr_args != 1)
-                       break;
-               ret = io_eventfd_register(ctx, arg, 0);
-               break;
-       case IORING_REGISTER_EVENTFD_ASYNC:
-               ret = -EINVAL;
-               if (nr_args != 1)
-                       break;
-               ret = io_eventfd_register(ctx, arg, 1);
-               break;
-       case IORING_UNREGISTER_EVENTFD:
-               ret = -EINVAL;
-               if (arg || nr_args)
-                       break;
-               ret = io_eventfd_unregister(ctx);
-               break;
-       case IORING_REGISTER_PROBE:
-               ret = -EINVAL;
-               if (!arg || nr_args > 256)
-                       break;
-               ret = io_probe(ctx, arg, nr_args);
-               break;
-       case IORING_REGISTER_PERSONALITY:
-               ret = -EINVAL;
-               if (arg || nr_args)
-                       break;
-               ret = io_register_personality(ctx);
-               break;
-       case IORING_UNREGISTER_PERSONALITY:
-               ret = -EINVAL;
-               if (arg)
-                       break;
-               ret = io_unregister_personality(ctx, nr_args);
-               break;
-       case IORING_REGISTER_ENABLE_RINGS:
-               ret = -EINVAL;
-               if (arg || nr_args)
-                       break;
-               ret = io_register_enable_rings(ctx);
-               break;
-       case IORING_REGISTER_RESTRICTIONS:
-               ret = io_register_restrictions(ctx, arg, nr_args);
-               break;
-       case IORING_REGISTER_FILES2:
-               ret = io_register_rsrc(ctx, arg, nr_args, IORING_RSRC_FILE);
-               break;
-       case IORING_REGISTER_FILES_UPDATE2:
-               ret = io_register_rsrc_update(ctx, arg, nr_args,
-                                             IORING_RSRC_FILE);
-               break;
-       case IORING_REGISTER_BUFFERS2:
-               ret = io_register_rsrc(ctx, arg, nr_args, IORING_RSRC_BUFFER);
-               break;
-       case IORING_REGISTER_BUFFERS_UPDATE:
-               ret = io_register_rsrc_update(ctx, arg, nr_args,
-                                             IORING_RSRC_BUFFER);
-               break;
-       case IORING_REGISTER_IOWQ_AFF:
-               ret = -EINVAL;
-               if (!arg || !nr_args)
-                       break;
-               ret = io_register_iowq_aff(ctx, arg, nr_args);
-               break;
-       case IORING_UNREGISTER_IOWQ_AFF:
-               ret = -EINVAL;
-               if (arg || nr_args)
-                       break;
-               ret = io_unregister_iowq_aff(ctx);
-               break;
-       case IORING_REGISTER_IOWQ_MAX_WORKERS:
-               ret = -EINVAL;
-               if (!arg || nr_args != 2)
-                       break;
-               ret = io_register_iowq_max_workers(ctx, arg);
-               break;
-       case IORING_REGISTER_RING_FDS:
-               ret = io_ringfd_register(ctx, arg, nr_args);
-               break;
-       case IORING_UNREGISTER_RING_FDS:
-               ret = io_ringfd_unregister(ctx, arg, nr_args);
-               break;
-       case IORING_REGISTER_PBUF_RING:
-               ret = -EINVAL;
-               if (!arg || nr_args != 1)
-                       break;
-               ret = io_register_pbuf_ring(ctx, arg);
-               break;
-       case IORING_UNREGISTER_PBUF_RING:
-               ret = -EINVAL;
-               if (!arg || nr_args != 1)
-                       break;
-               ret = io_unregister_pbuf_ring(ctx, arg);
-               break;
-       default:
-               ret = -EINVAL;
-               break;
-       }
-
-       return ret;
-}
-
-SYSCALL_DEFINE4(io_uring_register, unsigned int, fd, unsigned int, opcode,
-               void __user *, arg, unsigned int, nr_args)
-{
-       struct io_ring_ctx *ctx;
-       long ret = -EBADF;
-       struct fd f;
-
-       f = fdget(fd);
-       if (!f.file)
-               return -EBADF;
-
-       ret = -EOPNOTSUPP;
-       if (f.file->f_op != &io_uring_fops)
-               goto out_fput;
-
-       ctx = f.file->private_data;
-
-       io_run_task_work();
-
-       mutex_lock(&ctx->uring_lock);
-       ret = __io_uring_register(ctx, opcode, arg, nr_args);
-       mutex_unlock(&ctx->uring_lock);
-       trace_io_uring_register(ctx, opcode, ctx->nr_user_files, ctx->nr_user_bufs, ret);
-out_fput:
-       fdput(f);
-       return ret;
-}
-
-static int __init io_uring_init(void)
-{
-#define __BUILD_BUG_VERIFY_ELEMENT(stype, eoffset, etype, ename) do { \
-       BUILD_BUG_ON(offsetof(stype, ename) != eoffset); \
-       BUILD_BUG_ON(sizeof(etype) != sizeof_field(stype, ename)); \
-} while (0)
-
-#define BUILD_BUG_SQE_ELEM(eoffset, etype, ename) \
-       __BUILD_BUG_VERIFY_ELEMENT(struct io_uring_sqe, eoffset, etype, ename)
-       BUILD_BUG_ON(sizeof(struct io_uring_sqe) != 64);
-       BUILD_BUG_SQE_ELEM(0,  __u8,   opcode);
-       BUILD_BUG_SQE_ELEM(1,  __u8,   flags);
-       BUILD_BUG_SQE_ELEM(2,  __u16,  ioprio);
-       BUILD_BUG_SQE_ELEM(4,  __s32,  fd);
-       BUILD_BUG_SQE_ELEM(8,  __u64,  off);
-       BUILD_BUG_SQE_ELEM(8,  __u64,  addr2);
-       BUILD_BUG_SQE_ELEM(16, __u64,  addr);
-       BUILD_BUG_SQE_ELEM(16, __u64,  splice_off_in);
-       BUILD_BUG_SQE_ELEM(24, __u32,  len);
-       BUILD_BUG_SQE_ELEM(28,     __kernel_rwf_t, rw_flags);
-       BUILD_BUG_SQE_ELEM(28, /* compat */   int, rw_flags);
-       BUILD_BUG_SQE_ELEM(28, /* compat */ __u32, rw_flags);
-       BUILD_BUG_SQE_ELEM(28, __u32,  fsync_flags);
-       BUILD_BUG_SQE_ELEM(28, /* compat */ __u16,  poll_events);
-       BUILD_BUG_SQE_ELEM(28, __u32,  poll32_events);
-       BUILD_BUG_SQE_ELEM(28, __u32,  sync_range_flags);
-       BUILD_BUG_SQE_ELEM(28, __u32,  msg_flags);
-       BUILD_BUG_SQE_ELEM(28, __u32,  timeout_flags);
-       BUILD_BUG_SQE_ELEM(28, __u32,  accept_flags);
-       BUILD_BUG_SQE_ELEM(28, __u32,  cancel_flags);
-       BUILD_BUG_SQE_ELEM(28, __u32,  open_flags);
-       BUILD_BUG_SQE_ELEM(28, __u32,  statx_flags);
-       BUILD_BUG_SQE_ELEM(28, __u32,  fadvise_advice);
-       BUILD_BUG_SQE_ELEM(28, __u32,  splice_flags);
-       BUILD_BUG_SQE_ELEM(32, __u64,  user_data);
-       BUILD_BUG_SQE_ELEM(40, __u16,  buf_index);
-       BUILD_BUG_SQE_ELEM(40, __u16,  buf_group);
-       BUILD_BUG_SQE_ELEM(42, __u16,  personality);
-       BUILD_BUG_SQE_ELEM(44, __s32,  splice_fd_in);
-       BUILD_BUG_SQE_ELEM(44, __u32,  file_index);
-       BUILD_BUG_SQE_ELEM(48, __u64,  addr3);
-
-       BUILD_BUG_ON(sizeof(struct io_uring_files_update) !=
-                    sizeof(struct io_uring_rsrc_update));
-       BUILD_BUG_ON(sizeof(struct io_uring_rsrc_update) >
-                    sizeof(struct io_uring_rsrc_update2));
-
-       /* ->buf_index is u16 */
-       BUILD_BUG_ON(IORING_MAX_REG_BUFFERS >= (1u << 16));
-       BUILD_BUG_ON(BGID_ARRAY * sizeof(struct io_buffer_list) > PAGE_SIZE);
-       BUILD_BUG_ON(offsetof(struct io_uring_buf_ring, bufs) != 0);
-       BUILD_BUG_ON(offsetof(struct io_uring_buf, resv) !=
-                    offsetof(struct io_uring_buf_ring, tail));
-
-       /* should fit into one byte */
-       BUILD_BUG_ON(SQE_VALID_FLAGS >= (1 << 8));
-       BUILD_BUG_ON(SQE_COMMON_FLAGS >= (1 << 8));
-       BUILD_BUG_ON((SQE_VALID_FLAGS | SQE_COMMON_FLAGS) != SQE_VALID_FLAGS);
-
-       BUILD_BUG_ON(ARRAY_SIZE(io_op_defs) != IORING_OP_LAST);
-       BUILD_BUG_ON(__REQ_F_LAST_BIT > 8 * sizeof(int));
-
-       BUILD_BUG_ON(sizeof(atomic_t) != sizeof(u32));
-
-       BUILD_BUG_ON(sizeof(struct io_uring_cmd) > 64);
-
-       req_cachep = KMEM_CACHE(io_kiocb, SLAB_HWCACHE_ALIGN | SLAB_PANIC |
-                               SLAB_ACCOUNT);
-       return 0;
-};
-__initcall(io_uring_init);
index 5a91aa1..6505d45 100644 (file)
@@ -44,20 +44,28 @@ static inline struct iomap_page *to_iomap_page(struct folio *folio)
 static struct bio_set iomap_ioend_bioset;
 
 static struct iomap_page *
-iomap_page_create(struct inode *inode, struct folio *folio)
+iomap_page_create(struct inode *inode, struct folio *folio, unsigned int flags)
 {
        struct iomap_page *iop = to_iomap_page(folio);
        unsigned int nr_blocks = i_blocks_per_folio(inode, folio);
+       gfp_t gfp;
 
        if (iop || nr_blocks <= 1)
                return iop;
 
+       if (flags & IOMAP_NOWAIT)
+               gfp = GFP_NOWAIT;
+       else
+               gfp = GFP_NOFS | __GFP_NOFAIL;
+
        iop = kzalloc(struct_size(iop, uptodate, BITS_TO_LONGS(nr_blocks)),
-                       GFP_NOFS | __GFP_NOFAIL);
-       spin_lock_init(&iop->uptodate_lock);
-       if (folio_test_uptodate(folio))
-               bitmap_fill(iop->uptodate, nr_blocks);
-       folio_attach_private(folio, iop);
+                     gfp);
+       if (iop) {
+               spin_lock_init(&iop->uptodate_lock);
+               if (folio_test_uptodate(folio))
+                       bitmap_fill(iop->uptodate, nr_blocks);
+               folio_attach_private(folio, iop);
+       }
        return iop;
 }
 
@@ -223,7 +231,7 @@ static int iomap_read_inline_data(const struct iomap_iter *iter,
        if (WARN_ON_ONCE(size > iomap->length))
                return -EIO;
        if (offset > 0)
-               iop = iomap_page_create(iter->inode, folio);
+               iop = iomap_page_create(iter->inode, folio, iter->flags);
        else
                iop = to_iomap_page(folio);
 
@@ -261,7 +269,7 @@ static loff_t iomap_readpage_iter(const struct iomap_iter *iter,
                return iomap_read_inline_data(iter, folio);
 
        /* zero post-eof blocks as the page may be mapped */
-       iop = iomap_page_create(iter->inode, folio);
+       iop = iomap_page_create(iter->inode, folio, iter->flags);
        iomap_adjust_read_range(iter->inode, folio, &pos, length, &poff, &plen);
        if (plen == 0)
                goto done;
@@ -519,10 +527,11 @@ static int __iomap_write_begin(const struct iomap_iter *iter, loff_t pos,
                size_t len, struct folio *folio)
 {
        const struct iomap *srcmap = iomap_iter_srcmap(iter);
-       struct iomap_page *iop = iomap_page_create(iter->inode, folio);
+       struct iomap_page *iop;
        loff_t block_size = i_blocksize(iter->inode);
        loff_t block_start = round_down(pos, block_size);
        loff_t block_end = round_up(pos + len, block_size);
+       unsigned int nr_blocks = i_blocks_per_folio(iter->inode, folio);
        size_t from = offset_in_folio(folio, pos), to = from + len;
        size_t poff, plen;
 
@@ -530,6 +539,10 @@ static int __iomap_write_begin(const struct iomap_iter *iter, loff_t pos,
                return 0;
        folio_clear_error(folio);
 
+       iop = iomap_page_create(iter->inode, folio, iter->flags);
+       if ((iter->flags & IOMAP_NOWAIT) && !iop && nr_blocks > 1)
+               return -EAGAIN;
+
        do {
                iomap_adjust_read_range(iter->inode, folio, &block_start,
                                block_end - block_start, &poff, &plen);
@@ -546,7 +559,12 @@ static int __iomap_write_begin(const struct iomap_iter *iter, loff_t pos,
                                return -EIO;
                        folio_zero_segments(folio, poff, from, to, poff + plen);
                } else {
-                       int status = iomap_read_folio_sync(block_start, folio,
+                       int status;
+
+                       if (iter->flags & IOMAP_NOWAIT)
+                               return -EAGAIN;
+
+                       status = iomap_read_folio_sync(block_start, folio,
                                        poff, plen, srcmap);
                        if (status)
                                return status;
@@ -575,6 +593,9 @@ static int iomap_write_begin(const struct iomap_iter *iter, loff_t pos,
        unsigned fgp = FGP_LOCK | FGP_WRITE | FGP_CREAT | FGP_STABLE | FGP_NOFS;
        int status = 0;
 
+       if (iter->flags & IOMAP_NOWAIT)
+               fgp |= FGP_NOWAIT;
+
        BUG_ON(pos + len > iter->iomap.offset + iter->iomap.length);
        if (srcmap != &iter->iomap)
                BUG_ON(pos + len > srcmap->offset + srcmap->length);
@@ -594,7 +615,7 @@ static int iomap_write_begin(const struct iomap_iter *iter, loff_t pos,
        folio = __filemap_get_folio(iter->inode->i_mapping, pos >> PAGE_SHIFT,
                        fgp, mapping_gfp_mask(iter->inode->i_mapping));
        if (!folio) {
-               status = -ENOMEM;
+               status = (iter->flags & IOMAP_NOWAIT) ? -EAGAIN : -ENOMEM;
                goto out_no_page;
        }
        if (pos + len > folio_pos(folio) + folio_size(folio))
@@ -712,6 +733,8 @@ static loff_t iomap_write_iter(struct iomap_iter *iter, struct iov_iter *i)
        loff_t pos = iter->pos;
        ssize_t written = 0;
        long status = 0;
+       struct address_space *mapping = iter->inode->i_mapping;
+       unsigned int bdp_flags = (iter->flags & IOMAP_NOWAIT) ? BDP_ASYNC : 0;
 
        do {
                struct folio *folio;
@@ -724,6 +747,11 @@ static loff_t iomap_write_iter(struct iomap_iter *iter, struct iov_iter *i)
                bytes = min_t(unsigned long, PAGE_SIZE - offset,
                                                iov_iter_count(i));
 again:
+               status = balance_dirty_pages_ratelimited_flags(mapping,
+                                                              bdp_flags);
+               if (unlikely(status))
+                       break;
+
                if (bytes > length)
                        bytes = length;
 
@@ -732,6 +760,10 @@ again:
                 * Otherwise there's a nasty deadlock on copying from the
                 * same page as we're writing to, without it being marked
                 * up-to-date.
+                *
+                * For async buffered writes the assumption is that the user
+                * page has already been faulted in. This can be optimized by
+                * faulting the user page.
                 */
                if (unlikely(fault_in_iov_iter_readable(i, bytes) == bytes)) {
                        status = -EFAULT;
@@ -743,7 +775,7 @@ again:
                        break;
 
                page = folio_file_page(folio, pos >> PAGE_SHIFT);
-               if (mapping_writably_mapped(iter->inode->i_mapping))
+               if (mapping_writably_mapped(mapping))
                        flush_dcache_page(page);
 
                copied = copy_page_from_iter_atomic(page, offset, bytes, i);
@@ -768,10 +800,12 @@ again:
                pos += status;
                written += status;
                length -= status;
-
-               balance_dirty_pages_ratelimited(iter->inode->i_mapping);
        } while (iov_iter_count(i) && length);
 
+       if (status == -EAGAIN) {
+               iov_iter_revert(i, written);
+               return -EAGAIN;
+       }
        return written ? written : status;
 }
 
@@ -787,6 +821,9 @@ iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *i,
        };
        int ret;
 
+       if (iocb->ki_flags & IOCB_NOWAIT)
+               iter.flags |= IOMAP_NOWAIT;
+
        while ((ret = iomap_iter(&iter, ops)) > 0)
                iter.processed = iomap_write_iter(&iter, i);
        if (iter.pos == iocb->ki_pos)
@@ -1301,7 +1338,7 @@ iomap_writepage_map(struct iomap_writepage_ctx *wpc,
                struct writeback_control *wbc, struct inode *inode,
                struct folio *folio, u64 end_pos)
 {
-       struct iomap_page *iop = iomap_page_create(inode, folio);
+       struct iomap_page *iop = iomap_page_create(inode, folio, 0);
        struct iomap_ioend *ioend, *next;
        unsigned len = i_blocksize(inode);
        unsigned nblocks = i_blocks_per_folio(inode, folio);
index 370c324..18a3d93 100644 (file)
@@ -52,7 +52,7 @@ struct iomap_dio {
 };
 
 static struct bio *iomap_dio_alloc_bio(const struct iomap_iter *iter,
-               struct iomap_dio *dio, unsigned short nr_vecs, unsigned int opf)
+               struct iomap_dio *dio, unsigned short nr_vecs, blk_opf_t opf)
 {
        if (dio->dops && dio->dops->bio_set)
                return bio_alloc_bioset(iter->iomap.bdev, nr_vecs, opf,
@@ -212,10 +212,10 @@ static void iomap_dio_zero(const struct iomap_iter *iter, struct iomap_dio *dio,
  * mapping, and whether or not we want FUA.  Note that we can end up
  * clearing the WRITE_FUA flag in the dio request.
  */
-static inline unsigned int iomap_dio_bio_opflags(struct iomap_dio *dio,
+static inline blk_opf_t iomap_dio_bio_opflags(struct iomap_dio *dio,
                const struct iomap *iomap, bool use_fua)
 {
-       unsigned int opflags = REQ_SYNC | REQ_IDLE;
+       blk_opf_t opflags = REQ_SYNC | REQ_IDLE;
 
        if (!(dio->flags & IOMAP_DIO_WRITE)) {
                WARN_ON_ONCE(iomap->flags & IOMAP_F_ZONE_APPEND);
@@ -242,10 +242,9 @@ static loff_t iomap_dio_bio_iter(const struct iomap_iter *iter,
        struct inode *inode = iter->inode;
        unsigned int blkbits = blksize_bits(bdev_logical_block_size(iomap->bdev));
        unsigned int fs_block_size = i_blocksize(inode), pad;
-       unsigned int align = iov_iter_alignment(dio->submit.iter);
        loff_t length = iomap_length(iter);
        loff_t pos = iter->pos;
-       unsigned int bio_opf;
+       blk_opf_t bio_opf;
        struct bio *bio;
        bool need_zeroout = false;
        bool use_fua = false;
@@ -253,7 +252,8 @@ static loff_t iomap_dio_bio_iter(const struct iomap_iter *iter,
        size_t copied = 0;
        size_t orig_count;
 
-       if ((pos | length | align) & ((1 << blkbits) - 1))
+       if ((pos | length) & ((1 << blkbits) - 1) ||
+           !bdev_iter_is_aligned(iomap->bdev, dio->submit.iter))
                return -EINVAL;
 
        if (iomap->type == IOMAP_UNWRITTEN) {
index 95a19f2..b466172 100644 (file)
@@ -82,7 +82,7 @@ static loff_t zisofs_uncompress_block(struct inode *inode, loff_t block_start,
                return 0;
        }
        haveblocks = isofs_get_blocks(inode, blocknum, bhs, needblocks);
-       ll_rw_block(REQ_OP_READ, 0, haveblocks, bhs);
+       ll_rw_block(REQ_OP_READ, haveblocks, bhs);
 
        curbh = 0;
        curpage = 0;
index eb315e8..890b554 100644 (file)
@@ -155,10 +155,10 @@ static int journal_submit_commit_record(journal_t *journal,
 
        if (journal->j_flags & JBD2_BARRIER &&
            !jbd2_has_feature_async_commit(journal))
-               ret = submit_bh(REQ_OP_WRITE,
-                       REQ_SYNC | REQ_PREFLUSH | REQ_FUA, bh);
+               ret = submit_bh(REQ_OP_WRITE | REQ_SYNC | REQ_PREFLUSH |
+                               REQ_FUA, bh);
        else
-               ret = submit_bh(REQ_OP_WRITE, REQ_SYNC, bh);
+               ret = submit_bh(REQ_OP_WRITE | REQ_SYNC, bh);
 
        *cbh = bh;
        return ret;
@@ -763,7 +763,7 @@ start_journal_io:
                                clear_buffer_dirty(bh);
                                set_buffer_uptodate(bh);
                                bh->b_end_io = journal_end_buffer_io_sync;
-                               submit_bh(REQ_OP_WRITE, REQ_SYNC, bh);
+                               submit_bh(REQ_OP_WRITE | REQ_SYNC, bh);
                        }
                        cond_resched();
 
index c0cbeea..2a1b9da 100644 (file)
@@ -1465,7 +1465,8 @@ journal_t *jbd2_journal_init_dev(struct block_device *bdev,
        if (!journal)
                return NULL;
 
-       bdevname(journal->j_dev, journal->j_devname);
+       snprintf(journal->j_devname, sizeof(journal->j_devname),
+                "%pg", journal->j_dev);
        strreplace(journal->j_devname, '/', '!');
        jbd2_stats_proc_init(journal);
 
@@ -1507,7 +1508,8 @@ journal_t *jbd2_journal_init_inode(struct inode *inode)
                return NULL;
 
        journal->j_inode = inode;
-       bdevname(journal->j_dev, journal->j_devname);
+       snprintf(journal->j_devname, sizeof(journal->j_devname),
+                "%pg", journal->j_dev);
        p = strreplace(journal->j_devname, '/', '!');
        sprintf(p, "-%lu", journal->j_inode->i_ino);
        jbd2_stats_proc_init(journal);
@@ -1602,7 +1604,7 @@ static int journal_reset(journal_t *journal)
  * This function expects that the caller will have locked the journal
  * buffer head, and will return with it unlocked
  */
-static int jbd2_write_superblock(journal_t *journal, int write_flags)
+static int jbd2_write_superblock(journal_t *journal, blk_opf_t write_flags)
 {
        struct buffer_head *bh = journal->j_sb_buffer;
        journal_superblock_t *sb = journal->j_superblock;
@@ -1636,7 +1638,7 @@ static int jbd2_write_superblock(journal_t *journal, int write_flags)
                sb->s_checksum = jbd2_superblock_csum(journal, sb);
        get_bh(bh);
        bh->b_end_io = end_buffer_write_sync;
-       ret = submit_bh(REQ_OP_WRITE, write_flags, bh);
+       ret = submit_bh(REQ_OP_WRITE | write_flags, bh);
        wait_on_buffer(bh);
        if (buffer_write_io_error(bh)) {
                clear_buffer_write_io_error(bh);
@@ -1659,13 +1661,14 @@ static int jbd2_write_superblock(journal_t *journal, int write_flags)
  * @journal: The journal to update.
  * @tail_tid: TID of the new transaction at the tail of the log
  * @tail_block: The first block of the transaction at the tail of the log
- * @write_op: With which operation should we write the journal sb
+ * @write_flags: Flags for the journal sb write operation
  *
  * Update a journal's superblock information about log tail and write it to
  * disk, waiting for the IO to complete.
  */
 int jbd2_journal_update_sb_log_tail(journal_t *journal, tid_t tail_tid,
-                                    unsigned long tail_block, int write_op)
+                                   unsigned long tail_block,
+                                   blk_opf_t write_flags)
 {
        journal_superblock_t *sb = journal->j_superblock;
        int ret;
@@ -1685,7 +1688,7 @@ int jbd2_journal_update_sb_log_tail(journal_t *journal, tid_t tail_tid,
        sb->s_sequence = cpu_to_be32(tail_tid);
        sb->s_start    = cpu_to_be32(tail_block);
 
-       ret = jbd2_write_superblock(journal, write_op);
+       ret = jbd2_write_superblock(journal, write_flags);
        if (ret)
                goto out;
 
@@ -1702,12 +1705,12 @@ out:
 /**
  * jbd2_mark_journal_empty() - Mark on disk journal as empty.
  * @journal: The journal to update.
- * @write_op: With which operation should we write the journal sb
+ * @write_flags: Flags for the journal sb write operation
  *
  * Update a journal's dynamic superblock fields to show that journal is empty.
  * Write updated superblock to disk waiting for IO to complete.
  */
-static void jbd2_mark_journal_empty(journal_t *journal, int write_op)
+static void jbd2_mark_journal_empty(journal_t *journal, blk_opf_t write_flags)
 {
        journal_superblock_t *sb = journal->j_superblock;
        bool had_fast_commit = false;
@@ -1733,7 +1736,7 @@ static void jbd2_mark_journal_empty(journal_t *journal, int write_op)
                had_fast_commit = true;
        }
 
-       jbd2_write_superblock(journal, write_op);
+       jbd2_write_superblock(journal, write_flags);
 
        if (had_fast_commit)
                jbd2_set_feature_fast_commit(journal);
@@ -1898,7 +1901,7 @@ static int journal_get_superblock(journal_t *journal)
 
        J_ASSERT(bh != NULL);
        if (!buffer_uptodate(bh)) {
-               ll_rw_block(REQ_OP_READ, 0, 1, &bh);
+               ll_rw_block(REQ_OP_READ, 1, &bh);
                wait_on_buffer(bh);
                if (!buffer_uptodate(bh)) {
                        printk(KERN_ERR
index 8ca3527..e699d6a 100644 (file)
@@ -100,7 +100,7 @@ static int do_readahead(journal_t *journal, unsigned int start)
                if (!buffer_uptodate(bh) && !buffer_locked(bh)) {
                        bufs[nbufs++] = bh;
                        if (nbufs == MAXBUF) {
-                               ll_rw_block(REQ_OP_READ, 0, nbufs, bufs);
+                               ll_rw_block(REQ_OP_READ, nbufs, bufs);
                                journal_brelse_array(bufs, nbufs);
                                nbufs = 0;
                        }
@@ -109,7 +109,7 @@ static int do_readahead(journal_t *journal, unsigned int start)
        }
 
        if (nbufs)
-               ll_rw_block(REQ_OP_READ, 0, nbufs, bufs);
+               ll_rw_block(REQ_OP_READ, nbufs, bufs);
        err = 0;
 
 failed:
index 1d732fd..332dc9a 100644 (file)
@@ -95,14 +95,14 @@ int jfs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
        if (rc)
                return rc;
 
-       if (is_quota_modification(inode, iattr)) {
+       if (is_quota_modification(mnt_userns, inode, iattr)) {
                rc = dquot_initialize(inode);
                if (rc)
                        return rc;
        }
        if ((iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)) ||
            (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))) {
-               rc = dquot_transfer(inode, iattr);
+               rc = dquot_transfer(mnt_userns, inode, iattr);
                if (rc)
                        return rc;
        }
index e6f4ccc..353f047 100644 (file)
@@ -6490,6 +6490,7 @@ int smb2_write(struct ksmbd_work *work)
                goto out;
        }
 
+       ksmbd_debug(SMB, "flags %u\n", le32_to_cpu(req->Flags));
        if (le32_to_cpu(req->Flags) & SMB2_WRITEFLAG_WRITE_THROUGH)
                writethrough = true;
 
@@ -6505,10 +6506,6 @@ int smb2_write(struct ksmbd_work *work)
                data_buf = (char *)(((char *)&req->hdr.ProtocolId) +
                                    le16_to_cpu(req->DataOffset));
 
-               ksmbd_debug(SMB, "flags %u\n", le32_to_cpu(req->Flags));
-               if (le32_to_cpu(req->Flags) & SMB2_WRITEFLAG_WRITE_THROUGH)
-                       writethrough = true;
-
                ksmbd_debug(SMB, "filename %pd, offset %lld, len %zu\n",
                            fp->filp->f_path.dentry, offset, length);
                err = ksmbd_vfs_write(work, fp, data_buf, length, &offset,
@@ -7703,7 +7700,7 @@ int smb2_ioctl(struct ksmbd_work *work)
        {
                struct file_zero_data_information *zero_data;
                struct ksmbd_file *fp;
-               loff_t off, len;
+               loff_t off, len, bfz;
 
                if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) {
                        ksmbd_debug(SMB,
@@ -7720,19 +7717,26 @@ int smb2_ioctl(struct ksmbd_work *work)
                zero_data =
                        (struct file_zero_data_information *)&req->Buffer[0];
 
-               fp = ksmbd_lookup_fd_fast(work, id);
-               if (!fp) {
-                       ret = -ENOENT;
+               off = le64_to_cpu(zero_data->FileOffset);
+               bfz = le64_to_cpu(zero_data->BeyondFinalZero);
+               if (off > bfz) {
+                       ret = -EINVAL;
                        goto out;
                }
 
-               off = le64_to_cpu(zero_data->FileOffset);
-               len = le64_to_cpu(zero_data->BeyondFinalZero) - off;
+               len = bfz - off;
+               if (len) {
+                       fp = ksmbd_lookup_fd_fast(work, id);
+                       if (!fp) {
+                               ret = -ENOENT;
+                               goto out;
+                       }
 
-               ret = ksmbd_vfs_zero_data(work, fp, off, len);
-               ksmbd_fd_put(work, fp);
-               if (ret < 0)
-                       goto out;
+                       ret = ksmbd_vfs_zero_data(work, fp, off, len);
+                       ksmbd_fd_put(work, fp);
+                       if (ret < 0)
+                               goto out;
+               }
                break;
        }
        case FSCTL_QUERY_ALLOCATED_RANGES:
@@ -7806,14 +7810,24 @@ int smb2_ioctl(struct ksmbd_work *work)
                src_off = le64_to_cpu(dup_ext->SourceFileOffset);
                dst_off = le64_to_cpu(dup_ext->TargetFileOffset);
                length = le64_to_cpu(dup_ext->ByteCount);
-               cloned = vfs_clone_file_range(fp_in->filp, src_off, fp_out->filp,
-                                             dst_off, length, 0);
+               /*
+                * XXX: It is not clear if FSCTL_DUPLICATE_EXTENTS_TO_FILE
+                * should fall back to vfs_copy_file_range().  This could be
+                * beneficial when re-exporting nfs/smb mount, but note that
+                * this can result in partial copy that returns an error status.
+                * If/when FSCTL_DUPLICATE_EXTENTS_TO_FILE_EX is implemented,
+                * fall back to vfs_copy_file_range(), should be avoided when
+                * the flag DUPLICATE_EXTENTS_DATA_EX_SOURCE_ATOMIC is set.
+                */
+               cloned = vfs_clone_file_range(fp_in->filp, src_off,
+                                             fp_out->filp, dst_off, length, 0);
                if (cloned == -EXDEV || cloned == -EOPNOTSUPP) {
                        ret = -EOPNOTSUPP;
                        goto dup_ext_out;
                } else if (cloned != length) {
                        cloned = vfs_copy_file_range(fp_in->filp, src_off,
-                                                    fp_out->filp, dst_off, length, 0);
+                                                    fp_out->filp, dst_off,
+                                                    length, 0);
                        if (cloned != length) {
                                if (cloned < 0)
                                        ret = cloned;
index d035e06..35b55ee 100644 (file)
@@ -5,16 +5,6 @@
  *
  *   Author(s): Long Li <longli@microsoft.com>,
  *             Hyunchul Lee <hyc.lee@gmail.com>
- *
- *   This program is free software;  you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
- *   the GNU General Public License for more details.
  */
 
 #define SUBMOD_NAME    "smb_direct"
index 8fef9de..143bba4 100644 (file)
@@ -230,7 +230,7 @@ static int ksmbd_kthread_fn(void *p)
                        break;
                }
                ret = kernel_accept(iface->ksmbd_socket, &client_sk,
-                                   O_NONBLOCK);
+                                   SOCK_NONBLOCK);
                mutex_unlock(&iface->sock_release_lock);
                if (ret) {
                        if (ret == -EAGAIN)
index dcdd07c..7c84902 100644 (file)
@@ -963,7 +963,7 @@ ssize_t ksmbd_vfs_getxattr(struct user_namespace *user_ns,
  */
 int ksmbd_vfs_setxattr(struct user_namespace *user_ns,
                       struct dentry *dentry, const char *attr_name,
-                      const void *attr_value, size_t attr_size, int flags)
+                      void *attr_value, size_t attr_size, int flags)
 {
        int err;
 
@@ -1015,7 +1015,9 @@ int ksmbd_vfs_zero_data(struct ksmbd_work *work, struct ksmbd_file *fp,
                                     FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
                                     off, len);
 
-       return vfs_fallocate(fp->filp, FALLOC_FL_ZERO_RANGE, off, len);
+       return vfs_fallocate(fp->filp,
+                            FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE,
+                            off, len);
 }
 
 int ksmbd_vfs_fqar_lseek(struct ksmbd_file *fp, loff_t start, loff_t length,
@@ -1046,7 +1048,7 @@ int ksmbd_vfs_fqar_lseek(struct ksmbd_file *fp, loff_t start, loff_t length,
        *out_count = 0;
        end = start + length;
        while (start < end && *out_count < in_count) {
-               extent_start = f->f_op->llseek(f, start, SEEK_DATA);
+               extent_start = vfs_llseek(f, start, SEEK_DATA);
                if (extent_start < 0) {
                        if (extent_start != -ENXIO)
                                ret = (int)extent_start;
@@ -1056,7 +1058,7 @@ int ksmbd_vfs_fqar_lseek(struct ksmbd_file *fp, loff_t start, loff_t length,
                if (extent_start >= end)
                        break;
 
-               extent_end = f->f_op->llseek(f, extent_start, SEEK_HOLE);
+               extent_end = vfs_llseek(f, extent_start, SEEK_HOLE);
                if (extent_end < 0) {
                        if (extent_end != -ENXIO)
                                ret = (int)extent_end;
@@ -1777,6 +1779,10 @@ int ksmbd_vfs_copy_file_ranges(struct ksmbd_work *work,
 
                ret = vfs_copy_file_range(src_fp->filp, src_off,
                                          dst_fp->filp, dst_off, len, 0);
+               if (ret == -EOPNOTSUPP || ret == -EXDEV)
+                       ret = generic_copy_file_range(src_fp->filp, src_off,
+                                                     dst_fp->filp, dst_off,
+                                                     len, 0);
                if (ret < 0)
                        return ret;
 
index 8c37aaf..70da4c0 100644 (file)
@@ -109,7 +109,7 @@ ssize_t ksmbd_vfs_casexattr_len(struct user_namespace *user_ns,
                                int attr_name_len);
 int ksmbd_vfs_setxattr(struct user_namespace *user_ns,
                       struct dentry *dentry, const char *attr_name,
-                      const void *attr_value, size_t attr_size, int flags);
+                      void *attr_value, size_t attr_size, int flags);
 int ksmbd_vfs_xattr_stream_name(char *stream_name, char **xattr_stream_name,
                                size_t *xattr_stream_name_size, int s_type);
 int ksmbd_vfs_remove_xattr(struct user_namespace *user_ns,
index 0a22a2f..e1c4617 100644 (file)
@@ -176,7 +176,7 @@ nlm_delete_file(struct nlm_file *file)
        }
 }
 
-static int nlm_unlock_files(struct nlm_file *file)
+static int nlm_unlock_files(struct nlm_file *file, fl_owner_t owner)
 {
        struct file_lock lock;
 
@@ -184,6 +184,7 @@ static int nlm_unlock_files(struct nlm_file *file)
        lock.fl_type  = F_UNLCK;
        lock.fl_start = 0;
        lock.fl_end   = OFFSET_MAX;
+       lock.fl_owner = owner;
        if (file->f_file[O_RDONLY] &&
            vfs_lock_file(file->f_file[O_RDONLY], F_SETLK, &lock, NULL))
                goto out_err;
@@ -225,7 +226,7 @@ again:
                if (match(lockhost, host)) {
 
                        spin_unlock(&flctx->flc_lock);
-                       if (nlm_unlock_files(file))
+                       if (nlm_unlock_files(file, fl->fl_owner))
                                return 1;
                        goto again;
                }
@@ -282,11 +283,10 @@ nlm_file_inuse(struct nlm_file *file)
 
 static void nlm_close_files(struct nlm_file *file)
 {
-       struct file *f;
-
-       for (f = file->f_file[0]; f <= file->f_file[1]; f++)
-               if (f)
-                       nlmsvc_ops->fclose(f);
+       if (file->f_file[O_RDONLY])
+               nlmsvc_ops->fclose(file->f_file[O_RDONLY]);
+       if (file->f_file[O_WRONLY])
+               nlmsvc_ops->fclose(file->f_file[O_WRONLY]);
 }
 
 /*
index ca28e0e..c266cfd 100644 (file)
@@ -425,21 +425,9 @@ static inline int flock_translate_cmd(int cmd) {
 }
 
 /* Fill in a file_lock structure with an appropriate FLOCK lock. */
-static struct file_lock *
-flock_make_lock(struct file *filp, unsigned int cmd, struct file_lock *fl)
+static void flock_make_lock(struct file *filp, struct file_lock *fl, int type)
 {
-       int type = flock_translate_cmd(cmd);
-
-       if (type < 0)
-               return ERR_PTR(type);
-
-       if (fl == NULL) {
-               fl = locks_alloc_lock();
-               if (fl == NULL)
-                       return ERR_PTR(-ENOMEM);
-       } else {
-               locks_init_lock(fl);
-       }
+       locks_init_lock(fl);
 
        fl->fl_file = filp;
        fl->fl_owner = filp;
@@ -447,8 +435,6 @@ flock_make_lock(struct file *filp, unsigned int cmd, struct file_lock *fl)
        fl->fl_flags = FL_FLOCK;
        fl->fl_type = type;
        fl->fl_end = OFFSET_MAX;
-
-       return fl;
 }
 
 static int assign_type(struct file_lock *fl, long type)
@@ -2097,21 +2083,9 @@ EXPORT_SYMBOL(locks_lock_inode_wait);
  */
 SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
 {
-       struct fd f = fdget(fd);
-       struct file_lock *lock;
-       int can_sleep, unlock;
-       int error;
-
-       error = -EBADF;
-       if (!f.file)
-               goto out;
-
-       can_sleep = !(cmd & LOCK_NB);
-       cmd &= ~LOCK_NB;
-       unlock = (cmd == LOCK_UN);
-
-       if (!unlock && !(f.file->f_mode & (FMODE_READ|FMODE_WRITE)))
-               goto out_putf;
+       int can_sleep, error, type;
+       struct file_lock fl;
+       struct fd f;
 
        /*
         * LOCK_MAND locks were broken for a long time in that they never
@@ -2123,36 +2097,41 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
         */
        if (cmd & LOCK_MAND) {
                pr_warn_once("Attempt to set a LOCK_MAND lock via flock(2). This support has been removed and the request ignored.\n");
-               error = 0;
-               goto out_putf;
+               return 0;
        }
 
-       lock = flock_make_lock(f.file, cmd, NULL);
-       if (IS_ERR(lock)) {
-               error = PTR_ERR(lock);
+       type = flock_translate_cmd(cmd & ~LOCK_NB);
+       if (type < 0)
+               return type;
+
+       error = -EBADF;
+       f = fdget(fd);
+       if (!f.file)
+               return error;
+
+       if (type != F_UNLCK && !(f.file->f_mode & (FMODE_READ | FMODE_WRITE)))
                goto out_putf;
-       }
 
-       if (can_sleep)
-               lock->fl_flags |= FL_SLEEP;
+       flock_make_lock(f.file, &fl, type);
 
-       error = security_file_lock(f.file, lock->fl_type);
+       error = security_file_lock(f.file, fl.fl_type);
        if (error)
-               goto out_free;
+               goto out_putf;
+
+       can_sleep = !(cmd & LOCK_NB);
+       if (can_sleep)
+               fl.fl_flags |= FL_SLEEP;
 
        if (f.file->f_op->flock)
                error = f.file->f_op->flock(f.file,
-                                         (can_sleep) ? F_SETLKW : F_SETLK,
-                                         lock);
+                                           (can_sleep) ? F_SETLKW : F_SETLK,
+                                           &fl);
        else
-               error = locks_lock_file_wait(f.file, lock);
-
- out_free:
-       locks_free_lock(lock);
+               error = locks_lock_file_wait(f.file, &fl);
 
  out_putf:
        fdput(f);
- out:
+
        return error;
 }
 
@@ -2614,7 +2593,7 @@ locks_remove_flock(struct file *filp, struct file_lock_context *flctx)
        if (list_empty(&flctx->flc_flock))
                return;
 
-       flock_make_lock(filp, LOCK_UN, &fl);
+       flock_make_lock(filp, &fl, F_UNLCK);
        fl.fl_flags |= FL_CLOSE;
 
        if (filp->f_op->flock)
index 8326ff8..0f8ae95 100644 (file)
@@ -147,7 +147,7 @@ static struct bio *do_mpage_readpage(struct mpage_readpage_args *args)
        struct block_device *bdev = NULL;
        int length;
        int fully_mapped = 1;
-       int op = REQ_OP_READ;
+       blk_opf_t opf = REQ_OP_READ;
        unsigned nblocks;
        unsigned relative_block;
        gfp_t gfp = mapping_gfp_constraint(folio->mapping, GFP_KERNEL);
@@ -156,7 +156,7 @@ static struct bio *do_mpage_readpage(struct mpage_readpage_args *args)
        VM_BUG_ON_FOLIO(folio_test_large(folio), folio);
 
        if (args->is_readahead) {
-               op |= REQ_RAHEAD;
+               opf |= REQ_RAHEAD;
                gfp |= __GFP_NORETRY | __GFP_NOWARN;
        }
 
@@ -274,7 +274,7 @@ alloc_new:
                                                                &folio->page))
                                goto out;
                }
-               args->bio = bio_alloc(bdev, bio_max_segs(args->nr_pages), op,
+               args->bio = bio_alloc(bdev, bio_max_segs(args->nr_pages), opf,
                                      gfp);
                if (args->bio == NULL)
                        goto confused;
index 42f892c..0ce5358 100644 (file)
@@ -319,8 +319,9 @@ zero_out:
  * conflicting writes once the folio is grabbed and locked.  It is passed a
  * pointer to the fsdata cookie that gets returned to the VM to be passed to
  * write_end.  It is permitted to sleep.  It should return 0 if the request
- * should go ahead; unlock the folio and return -EAGAIN to cause the folio to
- * be regot; or return an error.
+ * should go ahead or it may return an error.  It may also unlock and put the
+ * folio, provided it sets ``*foliop`` to NULL, in which case a return of 0
+ * will cause the folio to be re-got and the process to be retried.
  *
  * The calling netfs must initialise a netfs context contiguous to the vfs
  * inode before calling this.
@@ -348,13 +349,13 @@ retry:
 
        if (ctx->ops->check_write_begin) {
                /* Allow the netfs (eg. ceph) to flush conflicts. */
-               ret = ctx->ops->check_write_begin(file, pos, len, folio, _fsdata);
+               ret = ctx->ops->check_write_begin(file, pos, len, &folio, _fsdata);
                if (ret < 0) {
                        trace_netfs_failure(NULL, NULL, ret, netfs_fail_check_write_begin);
-                       if (ret == -EAGAIN)
-                               goto retry;
                        goto error;
                }
+               if (!folio)
+                       goto retry;
        }
 
        if (folio_test_uptodate(folio))
@@ -416,8 +417,10 @@ have_folio_no_wait:
 error_put:
        netfs_put_request(rreq, false, netfs_rreq_trace_put_failed);
 error:
-       folio_unlock(folio);
-       folio_put(folio);
+       if (folio) {
+               folio_unlock(folio);
+               folio_put(folio);
+       }
        _leave(" = %d", ret);
        return ret;
 }
index 79a8b45..943aeea 100644 (file)
@@ -121,7 +121,7 @@ static bool offset_in_map(u64 offset, struct pnfs_block_dev_map *map)
 }
 
 static struct bio *
-do_add_page_to_bio(struct bio *bio, int npg, int rw, sector_t isect,
+do_add_page_to_bio(struct bio *bio, int npg, enum req_op op, sector_t isect,
                struct page *page, struct pnfs_block_dev_map *map,
                struct pnfs_block_extent *be, bio_end_io_t end_io,
                struct parallel_io *par, unsigned int offset, int *len)
@@ -131,7 +131,7 @@ do_add_page_to_bio(struct bio *bio, int npg, int rw, sector_t isect,
        u64 disk_addr, end;
 
        dprintk("%s: npg %d rw %d isect %llu offset %u len %d\n", __func__,
-               npg, rw, (unsigned long long)isect, offset, *len);
+               npg, (__force u32)op, (unsigned long long)isect, offset, *len);
 
        /* translate to device offset */
        isect += be->be_v_offset;
@@ -154,7 +154,7 @@ do_add_page_to_bio(struct bio *bio, int npg, int rw, sector_t isect,
 
 retry:
        if (!bio) {
-               bio = bio_alloc(map->bdev, bio_max_segs(npg), rw, GFP_NOIO);
+               bio = bio_alloc(map->bdev, bio_max_segs(npg), op, GFP_NOIO);
                bio->bi_iter.bi_sector = disk_addr >> SECTOR_SHIFT;
                bio->bi_end_io = end_io;
                bio->bi_private = par;
@@ -291,7 +291,7 @@ bl_read_pagelist(struct nfs_pgio_header *header)
                } else {
                        bio = do_add_page_to_bio(bio,
                                                 header->page_array.npages - i,
-                                                READ,
+                                                REQ_OP_READ,
                                                 isect, pages[i], &map, &be,
                                                 bl_end_io_read, par,
                                                 pg_offset, &pg_len);
@@ -420,9 +420,8 @@ bl_write_pagelist(struct nfs_pgio_header *header, int sync)
 
                pg_len = PAGE_SIZE;
                bio = do_add_page_to_bio(bio, header->page_array.npages - i,
-                                        WRITE, isect, pages[i], &map, &be,
-                                        bl_end_io_write, par,
-                                        0, &pg_len);
+                                        REQ_OP_WRITE, isect, pages[i], &map,
+                                        &be, bl_end_io_write, par, 0, &pg_len);
                if (IS_ERR(bio)) {
                        header->pnfs_error = PTR_ERR(bio);
                        bio = NULL;
index c0fdcf8..bb0e84a 100644 (file)
@@ -4012,22 +4012,29 @@ static int _nfs4_discover_trunking(struct nfs_server *server,
        }
 
        page = alloc_page(GFP_KERNEL);
+       if (!page)
+               return -ENOMEM;
        locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL);
-       if (page == NULL || locations == NULL)
-               goto out;
+       if (!locations)
+               goto out_free;
+       locations->fattr = nfs_alloc_fattr();
+       if (!locations->fattr)
+               goto out_free_2;
 
        status = nfs4_proc_get_locations(server, fhandle, locations, page,
                                         cred);
        if (status)
-               goto out;
+               goto out_free_3;
 
        for (i = 0; i < locations->nlocations; i++)
                test_fs_location_for_trunking(&locations->locations[i], clp,
                                              server);
-out:
-       if (page)
-               __free_page(page);
+out_free_3:
+       kfree(locations->fattr);
+out_free_2:
        kfree(locations);
+out_free:
+       __free_page(page);
        return status;
 }
 
index 2540b35..9bab3e9 100644 (file)
@@ -2753,5 +2753,6 @@ again:
                goto again;
 
        nfs_put_client(clp);
+       module_put_and_kthread_exit(0);
        return 0;
 }
index 61b2aae..2acea77 100644 (file)
@@ -470,6 +470,15 @@ nfsd4_decode_fattr4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen,
                        return nfserr_bad_xdr;
                }
        }
+       if (bmval[1] & FATTR4_WORD1_TIME_CREATE) {
+               struct timespec64 ts;
+
+               /* No Linux filesystem supports setting this attribute. */
+               bmval[1] &= ~FATTR4_WORD1_TIME_CREATE;
+               status = nfsd4_decode_nfstime4(argp, &ts);
+               if (status)
+                       return status;
+       }
        if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) {
                u32 set_it;
 
index 847b482..9a8b09a 100644 (file)
@@ -465,7 +465,8 @@ static inline bool nfsd_attrs_supported(u32 minorversion, const u32 *bmval)
        (FATTR4_WORD0_SIZE | FATTR4_WORD0_ACL)
 #define NFSD_WRITEABLE_ATTRS_WORD1 \
        (FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \
-       | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)
+       | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_CREATE \
+       | FATTR4_WORD1_TIME_MODIFY_SET)
 #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
 #define MAYBE_FATTR4_WORD2_SECURITY_LABEL \
        FATTR4_WORD2_SECURITY_LABEL
index 840e3af..d79db56 100644 (file)
@@ -577,6 +577,7 @@ out_err:
 ssize_t nfsd_copy_file_range(struct file *src, u64 src_pos, struct file *dst,
                             u64 dst_pos, u64 count)
 {
+       ssize_t ret;
 
        /*
         * Limit copy to 4MB to prevent indefinitely blocking an nfsd
@@ -587,7 +588,12 @@ ssize_t nfsd_copy_file_range(struct file *src, u64 src_pos, struct file *dst,
         * limit like this and pipeline multiple COPY requests.
         */
        count = min_t(u64, count, 1 << 22);
-       return vfs_copy_file_range(src, src_pos, dst, dst_pos, count, 0);
+       ret = vfs_copy_file_range(src, src_pos, dst, dst_pos, count, 0);
+
+       if (ret == -EOPNOTSUPP || ret == -EXDEV)
+               ret = generic_copy_file_range(src, src_pos, dst, dst_pos,
+                                             count, 0);
+       return ret;
 }
 
 __be32 nfsd4_vfs_fallocate(struct svc_rqst *rqstp, struct svc_fh *fhp,
@@ -1173,6 +1179,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, u64 offset,
                        nfsd_copy_write_verifier(verf, nn);
                        err2 = filemap_check_wb_err(nf->nf_file->f_mapping,
                                                    since);
+                       err = nfserrno(err2);
                        break;
                case -EINVAL:
                        err = nfserr_notsupp;
@@ -1180,8 +1187,8 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, u64 offset,
                default:
                        nfsd_reset_write_verifier(nn);
                        trace_nfsd_writeverf_reset(nn, rqstp, err2);
+                       err = nfserrno(err2);
                }
-               err = nfserrno(err2);
        } else
                nfsd_copy_write_verifier(verf, nn);
 
index ca611ac..e74fda2 100644 (file)
@@ -70,7 +70,7 @@ nilfs_btnode_create_block(struct address_space *btnc, __u64 blocknr)
 }
 
 int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr,
-                             sector_t pblocknr, int mode, int mode_flags,
+                             sector_t pblocknr, blk_opf_t opf,
                              struct buffer_head **pbh, sector_t *submit_ptr)
 {
        struct buffer_head *bh;
@@ -103,13 +103,13 @@ int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr,
                }
        }
 
-       if (mode_flags & REQ_RAHEAD) {
+       if (opf & REQ_RAHEAD) {
                if (pblocknr != *submit_ptr + 1 || !trylock_buffer(bh)) {
                        err = -EBUSY; /* internal code */
                        brelse(bh);
                        goto out_locked;
                }
-       } else { /* mode == READ */
+       } else { /* opf == REQ_OP_READ */
                lock_buffer(bh);
        }
        if (buffer_uptodate(bh)) {
@@ -122,7 +122,7 @@ int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr,
        bh->b_blocknr = pblocknr; /* set block address for read */
        bh->b_end_io = end_buffer_read_sync;
        get_bh(bh);
-       submit_bh(mode, mode_flags, bh);
+       submit_bh(opf, bh);
        bh->b_blocknr = blocknr; /* set back to the given block address */
        *submit_ptr = pblocknr;
        err = 0;
index bd5544e..4bc5612 100644 (file)
@@ -34,8 +34,8 @@ void nilfs_init_btnc_inode(struct inode *btnc_inode);
 void nilfs_btnode_cache_clear(struct address_space *);
 struct buffer_head *nilfs_btnode_create_block(struct address_space *btnc,
                                              __u64 blocknr);
-int nilfs_btnode_submit_block(struct address_space *, __u64, sector_t, int,
-                             int, struct buffer_head **, sector_t *);
+int nilfs_btnode_submit_block(struct address_space *, __u64, sector_t,
+                             blk_opf_t, struct buffer_head **, sector_t *);
 void nilfs_btnode_delete(struct buffer_head *);
 int nilfs_btnode_prepare_change_key(struct address_space *,
                                    struct nilfs_btnode_chkey_ctxt *);
index f544c22..9f4d943 100644 (file)
@@ -477,7 +477,7 @@ static int __nilfs_btree_get_block(const struct nilfs_bmap *btree, __u64 ptr,
        sector_t submit_ptr = 0;
        int ret;
 
-       ret = nilfs_btnode_submit_block(btnc, ptr, 0, REQ_OP_READ, 0, &bh,
+       ret = nilfs_btnode_submit_block(btnc, ptr, 0, REQ_OP_READ, &bh,
                                        &submit_ptr);
        if (ret) {
                if (ret != -EEXIST)
@@ -495,8 +495,8 @@ static int __nilfs_btree_get_block(const struct nilfs_bmap *btree, __u64 ptr,
                        ptr2 = nilfs_btree_node_get_ptr(ra->node, i, ra->ncmax);
 
                        ret = nilfs_btnode_submit_block(btnc, ptr2, 0,
-                                                       REQ_OP_READ, REQ_RAHEAD,
-                                                       &ra_bh, &submit_ptr);
+                                               REQ_OP_READ | REQ_RAHEAD,
+                                               &ra_bh, &submit_ptr);
                        if (likely(!ret || ret == -EEXIST))
                                brelse(ra_bh);
                        else if (ret != -EBUSY)
index 04fdd42..b0d22ff 100644 (file)
@@ -92,7 +92,7 @@ int nilfs_gccache_submit_read_data(struct inode *inode, sector_t blkoff,
        bh->b_blocknr = pbn;
        bh->b_end_io = end_buffer_read_sync;
        get_bh(bh);
-       submit_bh(REQ_OP_READ, 0, bh);
+       submit_bh(REQ_OP_READ, bh);
        if (vbn)
                bh->b_blocknr = vbn;
  out:
@@ -129,9 +129,8 @@ int nilfs_gccache_submit_read_node(struct inode *inode, sector_t pbn,
        struct inode *btnc_inode = NILFS_I(inode)->i_assoc_inode;
        int ret;
 
-       ret = nilfs_btnode_submit_block(btnc_inode->i_mapping,
-                                       vbn ? : pbn, pbn, REQ_OP_READ, 0,
-                                       out_bh, &pbn);
+       ret = nilfs_btnode_submit_block(btnc_inode->i_mapping, vbn ? : pbn, pbn,
+                                       REQ_OP_READ, out_bh, &pbn);
        if (ret == -EEXIST) /* internal code (cache hit) */
                ret = 0;
        return ret;
index d29a0f2..cbf4fa6 100644 (file)
@@ -111,8 +111,8 @@ static int nilfs_mdt_create_block(struct inode *inode, unsigned long block,
 }
 
 static int
-nilfs_mdt_submit_block(struct inode *inode, unsigned long blkoff,
-                      int mode, int mode_flags, struct buffer_head **out_bh)
+nilfs_mdt_submit_block(struct inode *inode, unsigned long blkoff, blk_opf_t opf,
+                      struct buffer_head **out_bh)
 {
        struct buffer_head *bh;
        __u64 blknum = 0;
@@ -126,12 +126,12 @@ nilfs_mdt_submit_block(struct inode *inode, unsigned long blkoff,
        if (buffer_uptodate(bh))
                goto out;
 
-       if (mode_flags & REQ_RAHEAD) {
+       if (opf & REQ_RAHEAD) {
                if (!trylock_buffer(bh)) {
                        ret = -EBUSY;
                        goto failed_bh;
                }
-       } else /* mode == READ */
+       } else /* opf == REQ_OP_READ */
                lock_buffer(bh);
 
        if (buffer_uptodate(bh)) {
@@ -148,10 +148,11 @@ nilfs_mdt_submit_block(struct inode *inode, unsigned long blkoff,
 
        bh->b_end_io = end_buffer_read_sync;
        get_bh(bh);
-       submit_bh(mode, mode_flags, bh);
+       submit_bh(opf, bh);
        ret = 0;
 
-       trace_nilfs2_mdt_submit_block(inode, inode->i_ino, blkoff, mode);
+       trace_nilfs2_mdt_submit_block(inode, inode->i_ino, blkoff,
+                                     opf & REQ_OP_MASK);
  out:
        get_bh(bh);
        *out_bh = bh;
@@ -172,7 +173,7 @@ static int nilfs_mdt_read_block(struct inode *inode, unsigned long block,
        int i, nr_ra_blocks = NILFS_MDT_MAX_RA_BLOCKS;
        int err;
 
-       err = nilfs_mdt_submit_block(inode, block, REQ_OP_READ, 0, &first_bh);
+       err = nilfs_mdt_submit_block(inode, block, REQ_OP_READ, &first_bh);
        if (err == -EEXIST) /* internal code */
                goto out;
 
@@ -182,8 +183,8 @@ static int nilfs_mdt_read_block(struct inode *inode, unsigned long block,
        if (readahead) {
                blkoff = block + 1;
                for (i = 0; i < nr_ra_blocks; i++, blkoff++) {
-                       err = nilfs_mdt_submit_block(inode, blkoff, REQ_OP_READ,
-                                                    REQ_RAHEAD, &bh);
+                       err = nilfs_mdt_submit_block(inode, blkoff,
+                                               REQ_OP_READ | REQ_RAHEAD, &bh);
                        if (likely(!err || err == -EEXIST))
                                brelse(bh);
                        else if (err != -EBUSY)
index 1344f7d..aecda4f 100644 (file)
@@ -198,6 +198,9 @@ static inline int nilfs_acl_chmod(struct inode *inode)
 
 static inline int nilfs_init_acl(struct inode *inode, struct inode *dir)
 {
+       if (S_ISLNK(inode->i_mode))
+               return 0;
+
        inode->i_mode &= ~current_umask();
        return 0;
 }
index 4f897e1..cd7d09a 100644 (file)
@@ -295,12 +295,13 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group,
                                     const void *data, int data_type,
                                     struct inode *dir)
 {
-       __u32 marks_mask = 0, marks_ignored_mask = 0;
+       __u32 marks_mask = 0, marks_ignore_mask = 0;
        __u32 test_mask, user_mask = FANOTIFY_OUTGOING_EVENTS |
                                     FANOTIFY_EVENT_FLAGS;
        const struct path *path = fsnotify_data_path(data, data_type);
        unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS);
        struct fsnotify_mark *mark;
+       bool ondir = event_mask & FAN_ONDIR;
        int type;
 
        pr_debug("%s: report_mask=%x mask=%x data=%p data_type=%d\n",
@@ -315,19 +316,21 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group,
                        return 0;
        } else if (!(fid_mode & FAN_REPORT_FID)) {
                /* Do we have a directory inode to report? */
-               if (!dir && !(event_mask & FS_ISDIR))
+               if (!dir && !ondir)
                        return 0;
        }
 
        fsnotify_foreach_iter_mark_type(iter_info, mark, type) {
-               /* Apply ignore mask regardless of mark's ISDIR flag */
-               marks_ignored_mask |= mark->ignored_mask;
+               /*
+                * Apply ignore mask depending on event flags in ignore mask.
+                */
+               marks_ignore_mask |=
+                       fsnotify_effective_ignore_mask(mark, ondir, type);
 
                /*
-                * If the event is on dir and this mark doesn't care about
-                * events on dir, don't send it!
+                * Send the event depending on event flags in mark mask.
                 */
-               if (event_mask & FS_ISDIR && !(mark->mask & FS_ISDIR))
+               if (!fsnotify_mask_applicable(mark->mask, ondir, type))
                        continue;
 
                marks_mask |= mark->mask;
@@ -336,7 +339,7 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group,
                *match_mask |= 1U << type;
        }
 
-       test_mask = event_mask & marks_mask & ~marks_ignored_mask;
+       test_mask = event_mask & marks_mask & ~marks_ignore_mask;
 
        /*
         * For dirent modification events (create/delete/move) that do not carry
index 80e0ec9..1d9f112 100644 (file)
@@ -499,6 +499,8 @@ static inline unsigned int fanotify_mark_user_flags(struct fsnotify_mark *mark)
                mflags |= FAN_MARK_IGNORED_SURV_MODIFY;
        if (mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF)
                mflags |= FAN_MARK_EVICTABLE;
+       if (mark->flags & FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS)
+               mflags |= FAN_MARK_IGNORE;
 
        return mflags;
 }
index c2255b4..f0e49a4 100644 (file)
@@ -1009,10 +1009,10 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark,
        mask &= ~umask;
        spin_lock(&fsn_mark->lock);
        oldmask = fsnotify_calc_mask(fsn_mark);
-       if (!(flags & FAN_MARK_IGNORED_MASK)) {
+       if (!(flags & FANOTIFY_MARK_IGNORE_BITS)) {
                fsn_mark->mask &= ~mask;
        } else {
-               fsn_mark->ignored_mask &= ~mask;
+               fsn_mark->ignore_mask &= ~mask;
        }
        newmask = fsnotify_calc_mask(fsn_mark);
        /*
@@ -1021,7 +1021,7 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark,
         * changes to the mask.
         * Destroy mark when only umask bits remain.
         */
-       *destroy = !((fsn_mark->mask | fsn_mark->ignored_mask) & ~umask);
+       *destroy = !((fsn_mark->mask | fsn_mark->ignore_mask) & ~umask);
        spin_unlock(&fsn_mark->lock);
 
        return oldmask & ~newmask;
@@ -1085,15 +1085,24 @@ static bool fanotify_mark_update_flags(struct fsnotify_mark *fsn_mark,
                                       unsigned int fan_flags)
 {
        bool want_iref = !(fan_flags & FAN_MARK_EVICTABLE);
+       unsigned int ignore = fan_flags & FANOTIFY_MARK_IGNORE_BITS;
        bool recalc = false;
 
        /*
+        * When using FAN_MARK_IGNORE for the first time, mark starts using
+        * independent event flags in ignore mask.  After that, trying to
+        * update the ignore mask with the old FAN_MARK_IGNORED_MASK API
+        * will result in EEXIST error.
+        */
+       if (ignore == FAN_MARK_IGNORE)
+               fsn_mark->flags |= FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS;
+
+       /*
         * Setting FAN_MARK_IGNORED_SURV_MODIFY for the first time may lead to
         * the removal of the FS_MODIFY bit in calculated mask if it was set
-        * because of an ignored mask that is now going to survive FS_MODIFY.
+        * because of an ignore mask that is now going to survive FS_MODIFY.
         */
-       if ((fan_flags & FAN_MARK_IGNORED_MASK) &&
-           (fan_flags & FAN_MARK_IGNORED_SURV_MODIFY) &&
+       if (ignore && (fan_flags & FAN_MARK_IGNORED_SURV_MODIFY) &&
            !(fsn_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) {
                fsn_mark->flags |= FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY;
                if (!(fsn_mark->mask & FS_MODIFY))
@@ -1120,10 +1129,10 @@ static bool fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark,
        bool recalc;
 
        spin_lock(&fsn_mark->lock);
-       if (!(fan_flags & FAN_MARK_IGNORED_MASK))
+       if (!(fan_flags & FANOTIFY_MARK_IGNORE_BITS))
                fsn_mark->mask |= mask;
        else
-               fsn_mark->ignored_mask |= mask;
+               fsn_mark->ignore_mask |= mask;
 
        recalc = fsnotify_calc_mask(fsn_mark) &
                ~fsnotify_conn_mask(fsn_mark->connector);
@@ -1187,6 +1196,37 @@ static int fanotify_group_init_error_pool(struct fsnotify_group *group)
                                         sizeof(struct fanotify_error_event));
 }
 
+static int fanotify_may_update_existing_mark(struct fsnotify_mark *fsn_mark,
+                                             unsigned int fan_flags)
+{
+       /*
+        * Non evictable mark cannot be downgraded to evictable mark.
+        */
+       if (fan_flags & FAN_MARK_EVICTABLE &&
+           !(fsn_mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF))
+               return -EEXIST;
+
+       /*
+        * New ignore mask semantics cannot be downgraded to old semantics.
+        */
+       if (fan_flags & FAN_MARK_IGNORED_MASK &&
+           fsn_mark->flags & FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS)
+               return -EEXIST;
+
+       /*
+        * An ignore mask that survives modify could never be downgraded to not
+        * survive modify.  With new FAN_MARK_IGNORE semantics we make that rule
+        * explicit and return an error when trying to update the ignore mask
+        * without the original FAN_MARK_IGNORED_SURV_MODIFY value.
+        */
+       if (fan_flags & FAN_MARK_IGNORE &&
+           !(fan_flags & FAN_MARK_IGNORED_SURV_MODIFY) &&
+           fsn_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)
+               return -EEXIST;
+
+       return 0;
+}
+
 static int fanotify_add_mark(struct fsnotify_group *group,
                             fsnotify_connp_t *connp, unsigned int obj_type,
                             __u32 mask, unsigned int fan_flags,
@@ -1208,19 +1248,18 @@ static int fanotify_add_mark(struct fsnotify_group *group,
        }
 
        /*
-        * Non evictable mark cannot be downgraded to evictable mark.
+        * Check if requested mark flags conflict with an existing mark flags.
         */
-       if (fan_flags & FAN_MARK_EVICTABLE &&
-           !(fsn_mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF)) {
-               ret = -EEXIST;
+       ret = fanotify_may_update_existing_mark(fsn_mark, fan_flags);
+       if (ret)
                goto out;
-       }
 
        /*
         * Error events are pre-allocated per group, only if strictly
         * needed (i.e. FAN_FS_ERROR was requested).
         */
-       if (!(fan_flags & FAN_MARK_IGNORED_MASK) && (mask & FAN_FS_ERROR)) {
+       if (!(fan_flags & FANOTIFY_MARK_IGNORE_BITS) &&
+           (mask & FAN_FS_ERROR)) {
                ret = fanotify_group_init_error_pool(group);
                if (ret)
                        goto out;
@@ -1261,10 +1300,10 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group,
 
        /*
         * If some other task has this inode open for write we should not add
-        * an ignored mark, unless that ignored mark is supposed to survive
+        * an ignore mask, unless that ignore mask is supposed to survive
         * modification changes anyway.
         */
-       if ((flags & FAN_MARK_IGNORED_MASK) &&
+       if ((flags & FANOTIFY_MARK_IGNORE_BITS) &&
            !(flags & FAN_MARK_IGNORED_SURV_MODIFY) &&
            inode_is_open_for_write(inode))
                return 0;
@@ -1513,8 +1552,16 @@ static int fanotify_test_fid(struct dentry *dentry)
        return 0;
 }
 
-static int fanotify_events_supported(struct path *path, __u64 mask)
+static int fanotify_events_supported(struct fsnotify_group *group,
+                                    struct path *path, __u64 mask,
+                                    unsigned int flags)
 {
+       unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS;
+       /* Strict validation of events in non-dir inode mask with v5.17+ APIs */
+       bool strict_dir_events = FAN_GROUP_FLAG(group, FAN_REPORT_TARGET_FID) ||
+                                (mask & FAN_RENAME) ||
+                                (flags & FAN_MARK_IGNORE);
+
        /*
         * Some filesystems such as 'proc' acquire unusual locks when opening
         * files. For them fanotify permission events have high chances of
@@ -1526,6 +1573,16 @@ static int fanotify_events_supported(struct path *path, __u64 mask)
        if (mask & FANOTIFY_PERM_EVENTS &&
            path->mnt->mnt_sb->s_type->fs_flags & FS_DISALLOW_NOTIFY_PERM)
                return -EINVAL;
+
+       /*
+        * We shouldn't have allowed setting dirent events and the directory
+        * flags FAN_ONDIR and FAN_EVENT_ON_CHILD in mask of non-dir inode,
+        * but because we always allowed it, error only when using new APIs.
+        */
+       if (strict_dir_events && mark_type == FAN_MARK_INODE &&
+           !d_is_dir(path->dentry) && (mask & FANOTIFY_DIRONLY_EVENT_BITS))
+               return -ENOTDIR;
+
        return 0;
 }
 
@@ -1540,7 +1597,8 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
        __kernel_fsid_t __fsid, *fsid = NULL;
        u32 valid_mask = FANOTIFY_EVENTS | FANOTIFY_EVENT_FLAGS;
        unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS;
-       bool ignored = flags & FAN_MARK_IGNORED_MASK;
+       unsigned int mark_cmd = flags & FANOTIFY_MARK_CMD_BITS;
+       unsigned int ignore = flags & FANOTIFY_MARK_IGNORE_BITS;
        unsigned int obj_type, fid_mode;
        u32 umask = 0;
        int ret;
@@ -1569,7 +1627,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
                return -EINVAL;
        }
 
-       switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_FLUSH)) {
+       switch (mark_cmd) {
        case FAN_MARK_ADD:
        case FAN_MARK_REMOVE:
                if (!mask)
@@ -1589,9 +1647,19 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
        if (mask & ~valid_mask)
                return -EINVAL;
 
-       /* Event flags (ONDIR, ON_CHILD) are meaningless in ignored mask */
-       if (ignored)
+
+       /* We don't allow FAN_MARK_IGNORE & FAN_MARK_IGNORED_MASK together */
+       if (ignore == (FAN_MARK_IGNORE | FAN_MARK_IGNORED_MASK))
+               return -EINVAL;
+
+       /*
+        * Event flags (FAN_ONDIR, FAN_EVENT_ON_CHILD) have no effect with
+        * FAN_MARK_IGNORED_MASK.
+        */
+       if (ignore == FAN_MARK_IGNORED_MASK) {
                mask &= ~FANOTIFY_EVENT_FLAGS;
+               umask = FANOTIFY_EVENT_FLAGS;
+       }
 
        f = fdget(fanotify_fd);
        if (unlikely(!f.file))
@@ -1655,7 +1723,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
        if (mask & FAN_RENAME && !(fid_mode & FAN_REPORT_NAME))
                goto fput_and_out;
 
-       if (flags & FAN_MARK_FLUSH) {
+       if (mark_cmd == FAN_MARK_FLUSH) {
                ret = 0;
                if (mark_type == FAN_MARK_MOUNT)
                        fsnotify_clear_vfsmount_marks_by_group(group);
@@ -1671,8 +1739,8 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
        if (ret)
                goto fput_and_out;
 
-       if (flags & FAN_MARK_ADD) {
-               ret = fanotify_events_supported(&path, mask);
+       if (mark_cmd == FAN_MARK_ADD) {
+               ret = fanotify_events_supported(group, &path, mask, flags);
                if (ret)
                        goto path_put_and_out;
        }
@@ -1695,17 +1763,11 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
        else
                mnt = path.mnt;
 
-       /*
-        * FAN_RENAME is not allowed on non-dir (for now).
-        * We shouldn't have allowed setting any dirent events in mask of
-        * non-dir, but because we always allowed it, error only if group
-        * was initialized with the new flag FAN_REPORT_TARGET_FID.
-        */
-       ret = -ENOTDIR;
-       if (inode && !S_ISDIR(inode->i_mode) &&
-           ((mask & FAN_RENAME) ||
-            ((mask & FANOTIFY_DIRENT_EVENTS) &&
-             FAN_GROUP_FLAG(group, FAN_REPORT_TARGET_FID))))
+       ret = mnt ? -EINVAL : -EISDIR;
+       /* FAN_MARK_IGNORE requires SURV_MODIFY for sb/mount/dir marks */
+       if (mark_cmd == FAN_MARK_ADD && ignore == FAN_MARK_IGNORE &&
+           (mnt || S_ISDIR(inode->i_mode)) &&
+           !(flags & FAN_MARK_IGNORED_SURV_MODIFY))
                goto path_put_and_out;
 
        /* Mask out FAN_EVENT_ON_CHILD flag for sb/mount/non-dir marks */
@@ -1717,12 +1779,12 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
                 * events with parent/name info for non-directory.
                 */
                if ((fid_mode & FAN_REPORT_DIR_FID) &&
-                   (flags & FAN_MARK_ADD) && !ignored)
+                   (flags & FAN_MARK_ADD) && !ignore)
                        mask |= FAN_EVENT_ON_CHILD;
        }
 
        /* create/update an inode mark */
-       switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE)) {
+       switch (mark_cmd) {
        case FAN_MARK_ADD:
                if (mark_type == FAN_MARK_MOUNT)
                        ret = fanotify_add_vfsmount_mark(group, mnt, mask,
@@ -1800,7 +1862,7 @@ static int __init fanotify_user_setup(void)
 
        BUILD_BUG_ON(FANOTIFY_INIT_FLAGS & FANOTIFY_INTERNAL_GROUP_FLAGS);
        BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 12);
-       BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 10);
+       BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 11);
 
        fanotify_mark_cache = KMEM_CACHE(fsnotify_mark,
                                         SLAB_PANIC|SLAB_ACCOUNT);
index 59fb40a..55081ae 100644 (file)
@@ -113,7 +113,7 @@ static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark)
                        return;
                seq_printf(m, "fanotify ino:%lx sdev:%x mflags:%x mask:%x ignored_mask:%x ",
                           inode->i_ino, inode->i_sb->s_dev,
-                          mflags, mark->mask, mark->ignored_mask);
+                          mflags, mark->mask, mark->ignore_mask);
                show_mark_fhandle(m, inode);
                seq_putc(m, '\n');
                iput(inode);
@@ -121,12 +121,12 @@ static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark)
                struct mount *mnt = fsnotify_conn_mount(mark->connector);
 
                seq_printf(m, "fanotify mnt_id:%x mflags:%x mask:%x ignored_mask:%x\n",
-                          mnt->mnt_id, mflags, mark->mask, mark->ignored_mask);
+                          mnt->mnt_id, mflags, mark->mask, mark->ignore_mask);
        } else if (mark->connector->type == FSNOTIFY_OBJ_TYPE_SB) {
                struct super_block *sb = fsnotify_conn_sb(mark->connector);
 
                seq_printf(m, "fanotify sdev:%x mflags:%x mask:%x ignored_mask:%x\n",
-                          sb->s_dev, mflags, mark->mask, mark->ignored_mask);
+                          sb->s_dev, mflags, mark->mask, mark->ignore_mask);
        }
 }
 
index 0b3e749..7974e91 100644 (file)
@@ -100,7 +100,7 @@ void fsnotify_sb_delete(struct super_block *sb)
  * Given an inode, first check if we care what happens to our children.  Inotify
  * and dnotify both tell their parents about events.  If we care about any event
  * on a child we run all of our children and set a dentry flag saying that the
- * parent cares.  Thus when an event happens on a child it can quickly tell if
+ * parent cares.  Thus when an event happens on a child it can quickly tell
  * if there is a need to find a parent and send the event to the parent.
  */
 void __fsnotify_update_child_dentry_flags(struct inode *inode)
@@ -324,7 +324,8 @@ static int send_to_group(__u32 mask, const void *data, int data_type,
        struct fsnotify_group *group = NULL;
        __u32 test_mask = (mask & ALL_FSNOTIFY_EVENTS);
        __u32 marks_mask = 0;
-       __u32 marks_ignored_mask = 0;
+       __u32 marks_ignore_mask = 0;
+       bool is_dir = mask & FS_ISDIR;
        struct fsnotify_mark *mark;
        int type;
 
@@ -336,7 +337,7 @@ static int send_to_group(__u32 mask, const void *data, int data_type,
                fsnotify_foreach_iter_mark_type(iter_info, mark, type) {
                        if (!(mark->flags &
                              FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
-                               mark->ignored_mask = 0;
+                               mark->ignore_mask = 0;
                }
        }
 
@@ -344,14 +345,15 @@ static int send_to_group(__u32 mask, const void *data, int data_type,
        fsnotify_foreach_iter_mark_type(iter_info, mark, type) {
                group = mark->group;
                marks_mask |= mark->mask;
-               marks_ignored_mask |= mark->ignored_mask;
+               marks_ignore_mask |=
+                       fsnotify_effective_ignore_mask(mark, is_dir, type);
        }
 
-       pr_debug("%s: group=%p mask=%x marks_mask=%x marks_ignored_mask=%x data=%p data_type=%d dir=%p cookie=%d\n",
-                __func__, group, mask, marks_mask, marks_ignored_mask,
+       pr_debug("%s: group=%p mask=%x marks_mask=%x marks_ignore_mask=%x data=%p data_type=%d dir=%p cookie=%d\n",
+                __func__, group, mask, marks_mask, marks_ignore_mask,
                 data, data_type, dir, cookie);
 
-       if (!(test_mask & marks_mask & ~marks_ignored_mask))
+       if (!(test_mask & marks_mask & ~marks_ignore_mask))
                return 0;
 
        if (group->ops->handle_event) {
@@ -423,7 +425,8 @@ static bool fsnotify_iter_select_report_types(
                         * But is *this mark* watching children?
                         */
                        if (type == FSNOTIFY_ITER_TYPE_PARENT &&
-                           !(mark->mask & FS_EVENT_ON_CHILD))
+                           !(mark->mask & FS_EVENT_ON_CHILD) &&
+                           !(fsnotify_ignore_mask(mark) & FS_EVENT_ON_CHILD))
                                continue;
 
                        fsnotify_iter_set_report_type(iter_info, type);
@@ -532,8 +535,8 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir,
 
 
        /*
-        * If this is a modify event we may need to clear some ignored masks.
-        * In that case, the object with ignored masks will have the FS_MODIFY
+        * If this is a modify event we may need to clear some ignore masks.
+        * In that case, the object with ignore masks will have the FS_MODIFY
         * event in its mask.
         * Otherwise, return if none of the marks care about this type of event.
         */
index ed42a18..1c4bfda 100644 (file)
@@ -136,7 +136,7 @@ static inline u32 inotify_mask_to_arg(__u32 mask)
                       IN_Q_OVERFLOW);
 }
 
-/* intofiy userspace file descriptor functions */
+/* inotify userspace file descriptor functions */
 static __poll_t inotify_poll(struct file *file, poll_table *wait)
 {
        struct fsnotify_group *group = file->private_data;
index 5f4fb6c..9364d35 100644 (file)
@@ -342,7 +342,7 @@ handle_zblock:
                for (i = 0; i < nr; i++) {
                        tbh = arr[i];
                        if (likely(!buffer_uptodate(tbh)))
-                               submit_bh(REQ_OP_READ, 0, tbh);
+                               submit_bh(REQ_OP_READ, tbh);
                        else
                                ntfs_end_buffer_async_read(tbh, 1);
                }
@@ -859,7 +859,7 @@ lock_retry_remap:
        do {
                struct buffer_head *next = bh->b_this_page;
                if (buffer_async_write(bh)) {
-                       submit_bh(REQ_OP_WRITE, 0, bh);
+                       submit_bh(REQ_OP_WRITE, bh);
                        need_end_writeback = false;
                }
                bh = next;
@@ -1187,7 +1187,7 @@ lock_retry_remap:
                BUG_ON(!buffer_mapped(tbh));
                get_bh(tbh);
                tbh->b_end_io = end_buffer_write_sync;
-               submit_bh(REQ_OP_WRITE, 0, tbh);
+               submit_bh(REQ_OP_WRITE, tbh);
        }
        /* Synchronize the mft mirror now if not @sync. */
        if (is_mft && !sync)
index 4de597a..52615e6 100644 (file)
@@ -592,8 +592,12 @@ static int ntfs_attr_find(const ATTR_TYPE type, const ntfschar *name,
                a = (ATTR_RECORD*)((u8*)ctx->attr +
                                le32_to_cpu(ctx->attr->length));
        for (;; a = (ATTR_RECORD*)((u8*)a + le32_to_cpu(a->length))) {
-               if ((u8*)a < (u8*)ctx->mrec || (u8*)a > (u8*)ctx->mrec +
-                               le32_to_cpu(ctx->mrec->bytes_allocated))
+               u8 *mrec_end = (u8 *)ctx->mrec +
+                              le32_to_cpu(ctx->mrec->bytes_allocated);
+               u8 *name_end = (u8 *)a + le16_to_cpu(a->name_offset) +
+                              a->name_length * sizeof(ntfschar);
+               if ((u8*)a < (u8*)ctx->mrec || (u8*)a > mrec_end ||
+                   name_end > mrec_end)
                        break;
                ctx->attr = a;
                if (unlikely(le32_to_cpu(a->type) > le32_to_cpu(type) ||
index a60f543..587e9b1 100644 (file)
@@ -658,7 +658,7 @@ lock_retry_remap:
                }
                get_bh(tbh);
                tbh->b_end_io = end_buffer_read_sync;
-               submit_bh(REQ_OP_READ, 0, tbh);
+               submit_bh(REQ_OP_READ, tbh);
        }
 
        /* Wait for io completion on all buffer heads. */
index 3436d58..58b660d 100644 (file)
@@ -532,7 +532,7 @@ static inline int ntfs_submit_bh_for_read(struct buffer_head *bh)
        lock_buffer(bh);
        get_bh(bh);
        bh->b_end_io = end_buffer_read_sync;
-       return submit_bh(REQ_OP_READ, 0, bh);
+       return submit_bh(REQ_OP_READ, bh);
 }
 
 /**
index bc1bf21..6ce60ff 100644 (file)
@@ -807,7 +807,7 @@ map_vcn:
                         * completed ignore errors afterwards as we can assume
                         * that if one buffer worked all of them will work.
                         */
-                       submit_bh(REQ_OP_WRITE, 0, bh);
+                       submit_bh(REQ_OP_WRITE, bh);
                        if (should_wait) {
                                should_wait = false;
                                wait_on_buffer(bh);
index 0d62cd5..f7bf5ce 100644 (file)
@@ -583,7 +583,7 @@ int ntfs_sync_mft_mirror(ntfs_volume *vol, const unsigned long mft_no,
                        clear_buffer_dirty(tbh);
                        get_bh(tbh);
                        tbh->b_end_io = end_buffer_write_sync;
-                       submit_bh(REQ_OP_WRITE, 0, tbh);
+                       submit_bh(REQ_OP_WRITE, tbh);
                }
                /* Wait on i/o completion of buffers. */
                for (i_bhs = 0; i_bhs < nr_bhs; i_bhs++) {
@@ -780,7 +780,7 @@ int write_mft_record_nolock(ntfs_inode *ni, MFT_RECORD *m, int sync)
                clear_buffer_dirty(tbh);
                get_bh(tbh);
                tbh->b_end_io = end_buffer_write_sync;
-               submit_bh(REQ_OP_WRITE, 0, tbh);
+               submit_bh(REQ_OP_WRITE, tbh);
        }
        /* Synchronize the mft mirror now if not @sync. */
        if (!sync && ni->mft_no < vol->mftmirr_size)
index 8e9d2b3..4a21745 100644 (file)
@@ -242,7 +242,7 @@ static int ntfs_zero_range(struct inode *inode, u64 vbo, u64 vbo_to)
                                lock_buffer(bh);
                                bh->b_end_io = end_buffer_read_sync;
                                get_bh(bh);
-                               submit_bh(REQ_OP_READ, 0, bh);
+                               submit_bh(REQ_OP_READ, bh);
 
                                wait_on_buffer(bh);
                                if (!buffer_uptodate(bh)) {
index 3de5700..1835e35 100644 (file)
@@ -1448,7 +1448,7 @@ int ntfs_write_bh(struct ntfs_sb_info *sbi, struct NTFS_RECORD_HEADER *rhdr,
  */
 int ntfs_bio_pages(struct ntfs_sb_info *sbi, const struct runs_tree *run,
                   struct page **pages, u32 nr_pages, u64 vbo, u32 bytes,
-                  u32 op)
+                  enum req_op op)
 {
        int err = 0;
        struct bio *new, *bio = NULL;
index 28c09c2..80104af 100644 (file)
@@ -629,7 +629,7 @@ static noinline int ntfs_get_block_vbo(struct inode *inode, u64 vbo,
                        bh->b_size = block_size;
                        off = vbo & (PAGE_SIZE - 1);
                        set_bh_page(bh, page, off);
-                       ll_rw_block(REQ_OP_READ, 0, 1, &bh);
+                       ll_rw_block(REQ_OP_READ, 1, &bh);
                        wait_on_buffer(bh);
                        if (!buffer_uptodate(bh)) {
                                err = -EIO;
index f28726c..8dbdca0 100644 (file)
@@ -617,7 +617,7 @@ int ntfs_write_bh(struct ntfs_sb_info *sbi, struct NTFS_RECORD_HEADER *rhdr,
                  struct ntfs_buffers *nb, int sync);
 int ntfs_bio_pages(struct ntfs_sb_info *sbi, const struct runs_tree *run,
                   struct page **pages, u32 nr_pages, u64 vbo, u32 bytes,
-                  u32 op);
+                  enum req_op op);
 int ntfs_bio_fill_1(struct ntfs_sb_info *sbi, const struct runs_tree *run);
 int ntfs_vbo_to_lbo(struct ntfs_sb_info *sbi, const struct runs_tree *run,
                    u64 vbo, u64 *lbo, u64 *bytes);
index 1d48900..af4157f 100644 (file)
@@ -636,7 +636,7 @@ int ocfs2_map_page_blocks(struct page *page, u64 *p_blkno,
                           !buffer_new(bh) &&
                           ocfs2_should_read_blk(inode, page, block_start) &&
                           (block_start < from || block_end > to)) {
-                       ll_rw_block(REQ_OP_READ, 0, 1, &bh);
+                       ll_rw_block(REQ_OP_READ, 1, &bh);
                        *wait_bh++=bh;
                }
 
index e775877..196638a 100644 (file)
@@ -64,7 +64,7 @@ int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh,
 
        get_bh(bh); /* for end_buffer_write_sync() */
        bh->b_end_io = end_buffer_write_sync;
-       submit_bh(REQ_OP_WRITE, 0, bh);
+       submit_bh(REQ_OP_WRITE, bh);
 
        wait_on_buffer(bh);
 
@@ -147,7 +147,7 @@ int ocfs2_read_blocks_sync(struct ocfs2_super *osb, u64 block,
 
                get_bh(bh); /* for end_buffer_read_sync() */
                bh->b_end_io = end_buffer_read_sync;
-               submit_bh(REQ_OP_READ, 0, bh);
+               submit_bh(REQ_OP_READ, bh);
        }
 
 read_failure:
@@ -328,7 +328,7 @@ int ocfs2_read_blocks(struct ocfs2_caching_info *ci, u64 block, int nr,
                        if (validate)
                                set_buffer_needs_validate(bh);
                        bh->b_end_io = end_buffer_read_sync;
-                       submit_bh(REQ_OP_READ, 0, bh);
+                       submit_bh(REQ_OP_READ, bh);
                        continue;
                }
        }
@@ -449,7 +449,7 @@ int ocfs2_write_super_or_backup(struct ocfs2_super *osb,
        get_bh(bh); /* for end_buffer_write_sync() */
        bh->b_end_io = end_buffer_write_sync;
        ocfs2_compute_meta_ecc(osb->sb, bh->b_data, &di->i_check);
-       submit_bh(REQ_OP_WRITE, 0, bh);
+       submit_bh(REQ_OP_WRITE, bh);
 
        wait_on_buffer(bh);
 
index ea0e70c..b13d344 100644 (file)
@@ -235,8 +235,6 @@ struct o2hb_region {
         * (hr_steady_iterations == 0) within hr_unsteady_iterations */
        atomic_t                hr_unsteady_iterations;
 
-       char                    hr_dev_name[BDEVNAME_SIZE];
-
        unsigned int            hr_timeout_ms;
 
        /* randomized as the region goes up and down so that a node
@@ -287,8 +285,8 @@ static void o2hb_write_timeout(struct work_struct *work)
                container_of(work, struct o2hb_region,
                             hr_write_timeout_work.work);
 
-       mlog(ML_ERROR, "Heartbeat write timeout to device %s after %u "
-            "milliseconds\n", reg->hr_dev_name,
+       mlog(ML_ERROR, "Heartbeat write timeout to device %pg after %u "
+            "milliseconds\n", reg->hr_bdev,
             jiffies_to_msecs(jiffies - reg->hr_last_timeout_start));
 
        if (o2hb_global_heartbeat_active()) {
@@ -383,9 +381,9 @@ static void o2hb_nego_timeout(struct work_struct *work)
 
        if (master_node == o2nm_this_node()) {
                if (!test_bit(master_node, reg->hr_nego_node_bitmap)) {
-                       printk(KERN_NOTICE "o2hb: node %d hb write hung for %ds on region %s (%s).\n",
+                       printk(KERN_NOTICE "o2hb: node %d hb write hung for %ds on region %s (%pg).\n",
                                o2nm_this_node(), O2HB_NEGO_TIMEOUT_MS/1000,
-                               config_item_name(&reg->hr_item), reg->hr_dev_name);
+                               config_item_name(&reg->hr_item), reg->hr_bdev);
                        set_bit(master_node, reg->hr_nego_node_bitmap);
                }
                if (memcmp(reg->hr_nego_node_bitmap, live_node_bitmap,
@@ -399,8 +397,8 @@ static void o2hb_nego_timeout(struct work_struct *work)
                        return;
                }
 
-               printk(KERN_NOTICE "o2hb: all nodes hb write hung, maybe region %s (%s) is down.\n",
-                       config_item_name(&reg->hr_item), reg->hr_dev_name);
+               printk(KERN_NOTICE "o2hb: all nodes hb write hung, maybe region %s (%pg) is down.\n",
+                       config_item_name(&reg->hr_item), reg->hr_bdev);
                /* approve negotiate timeout request. */
                o2hb_arm_timeout(reg);
 
@@ -419,9 +417,9 @@ static void o2hb_nego_timeout(struct work_struct *work)
                }
        } else {
                /* negotiate timeout with master node. */
-               printk(KERN_NOTICE "o2hb: node %d hb write hung for %ds on region %s (%s), negotiate timeout with node %d.\n",
+               printk(KERN_NOTICE "o2hb: node %d hb write hung for %ds on region %s (%pg), negotiate timeout with node %d.\n",
                        o2nm_this_node(), O2HB_NEGO_TIMEOUT_MS/1000, config_item_name(&reg->hr_item),
-                       reg->hr_dev_name, master_node);
+                       reg->hr_bdev, master_node);
                ret = o2hb_send_nego_msg(reg->hr_key, O2HB_NEGO_TIMEOUT_MSG,
                                master_node);
                if (ret)
@@ -437,8 +435,8 @@ static int o2hb_nego_timeout_handler(struct o2net_msg *msg, u32 len, void *data,
        struct o2hb_nego_msg *nego_msg;
 
        nego_msg = (struct o2hb_nego_msg *)msg->buf;
-       printk(KERN_NOTICE "o2hb: receive negotiate timeout message from node %d on region %s (%s).\n",
-               nego_msg->node_num, config_item_name(&reg->hr_item), reg->hr_dev_name);
+       printk(KERN_NOTICE "o2hb: receive negotiate timeout message from node %d on region %s (%pg).\n",
+               nego_msg->node_num, config_item_name(&reg->hr_item), reg->hr_bdev);
        if (nego_msg->node_num < O2NM_MAX_NODES)
                set_bit(nego_msg->node_num, reg->hr_nego_node_bitmap);
        else
@@ -452,8 +450,8 @@ static int o2hb_nego_approve_handler(struct o2net_msg *msg, u32 len, void *data,
 {
        struct o2hb_region *reg = data;
 
-       printk(KERN_NOTICE "o2hb: negotiate timeout approved by master node on region %s (%s).\n",
-               config_item_name(&reg->hr_item), reg->hr_dev_name);
+       printk(KERN_NOTICE "o2hb: negotiate timeout approved by master node on region %s (%pg).\n",
+               config_item_name(&reg->hr_item), reg->hr_bdev);
        o2hb_arm_timeout(reg);
        return 0;
 }
@@ -503,8 +501,7 @@ static void o2hb_bio_end_io(struct bio *bio)
 static struct bio *o2hb_setup_one_bio(struct o2hb_region *reg,
                                      struct o2hb_bio_wait_ctxt *wc,
                                      unsigned int *current_slot,
-                                     unsigned int max_slots, int op,
-                                     int op_flags)
+                                     unsigned int max_slots, blk_opf_t opf)
 {
        int len, current_page;
        unsigned int vec_len, vec_start;
@@ -518,7 +515,7 @@ static struct bio *o2hb_setup_one_bio(struct o2hb_region *reg,
         * GFP_KERNEL that the local node can get fenced. It would be
         * nicest if we could pre-allocate these bios and avoid this
         * all together. */
-       bio = bio_alloc(reg->hr_bdev, 16, op | op_flags, GFP_ATOMIC);
+       bio = bio_alloc(reg->hr_bdev, 16, opf, GFP_ATOMIC);
        if (!bio) {
                mlog(ML_ERROR, "Could not alloc slots BIO!\n");
                bio = ERR_PTR(-ENOMEM);
@@ -566,7 +563,7 @@ static int o2hb_read_slots(struct o2hb_region *reg,
 
        while(current_slot < max_slots) {
                bio = o2hb_setup_one_bio(reg, &wc, &current_slot, max_slots,
-                                        REQ_OP_READ, 0);
+                                        REQ_OP_READ);
                if (IS_ERR(bio)) {
                        status = PTR_ERR(bio);
                        mlog_errno(status);
@@ -598,8 +595,8 @@ static int o2hb_issue_node_write(struct o2hb_region *reg,
 
        slot = o2nm_this_node();
 
-       bio = o2hb_setup_one_bio(reg, write_wc, &slot, slot+1, REQ_OP_WRITE,
-                                REQ_SYNC);
+       bio = o2hb_setup_one_bio(reg, write_wc, &slot, slot+1,
+                                REQ_OP_WRITE | REQ_SYNC);
        if (IS_ERR(bio)) {
                status = PTR_ERR(bio);
                mlog_errno(status);
@@ -689,8 +686,8 @@ static int o2hb_check_own_slot(struct o2hb_region *reg)
        else
                errstr = ERRSTR3;
 
-       mlog(ML_ERROR, "%s (%s): expected(%u:0x%llx, 0x%llx), "
-            "ondisk(%u:0x%llx, 0x%llx)\n", errstr, reg->hr_dev_name,
+       mlog(ML_ERROR, "%s (%pg): expected(%u:0x%llx, 0x%llx), "
+            "ondisk(%u:0x%llx, 0x%llx)\n", errstr, reg->hr_bdev,
             slot->ds_node_num, (unsigned long long)slot->ds_last_generation,
             (unsigned long long)slot->ds_last_time, hb_block->hb_node,
             (unsigned long long)le64_to_cpu(hb_block->hb_generation),
@@ -863,8 +860,8 @@ static void o2hb_set_quorum_device(struct o2hb_region *reg)
                   sizeof(o2hb_live_node_bitmap)))
                goto unlock;
 
-       printk(KERN_NOTICE "o2hb: Region %s (%s) is now a quorum device\n",
-              config_item_name(&reg->hr_item), reg->hr_dev_name);
+       printk(KERN_NOTICE "o2hb: Region %s (%pg) is now a quorum device\n",
+              config_item_name(&reg->hr_item), reg->hr_bdev);
 
        set_bit(reg->hr_region_num, o2hb_quorum_region_bitmap);
 
@@ -922,8 +919,8 @@ static int o2hb_check_slot(struct o2hb_region *reg,
                /* The node is live but pushed out a bad crc. We
                 * consider it a transient miss but don't populate any
                 * other values as they may be junk. */
-               mlog(ML_ERROR, "Node %d has written a bad crc to %s\n",
-                    slot->ds_node_num, reg->hr_dev_name);
+               mlog(ML_ERROR, "Node %d has written a bad crc to %pg\n",
+                    slot->ds_node_num, reg->hr_bdev);
                o2hb_dump_slot(hb_block);
 
                slot->ds_equal_samples++;
@@ -1002,11 +999,11 @@ fire_callbacks:
                slot_dead_ms = le32_to_cpu(hb_block->hb_dead_ms);
                if (slot_dead_ms && slot_dead_ms != dead_ms) {
                        /* TODO: Perhaps we can fail the region here. */
-                       mlog(ML_ERROR, "Node %d on device %s has a dead count "
+                       mlog(ML_ERROR, "Node %d on device %pg has a dead count "
                             "of %u ms, but our count is %u ms.\n"
                             "Please double check your configuration values "
                             "for 'O2CB_HEARTBEAT_THRESHOLD'\n",
-                            slot->ds_node_num, reg->hr_dev_name, slot_dead_ms,
+                            slot->ds_node_num, reg->hr_bdev, slot_dead_ms,
                             dead_ms);
                }
                goto out;
@@ -1145,8 +1142,8 @@ static int o2hb_do_disk_heartbeat(struct o2hb_region *reg)
                /* Do not re-arm the write timeout on I/O error - we
                 * can't be sure that the new block ever made it to
                 * disk */
-               mlog(ML_ERROR, "Write error %d on device \"%s\"\n",
-                    write_wc.wc_error, reg->hr_dev_name);
+               mlog(ML_ERROR, "Write error %d on device \"%pg\"\n",
+                    write_wc.wc_error, reg->hr_bdev);
                ret = write_wc.wc_error;
                goto bail;
        }
@@ -1170,9 +1167,9 @@ bail:
        if (atomic_read(&reg->hr_steady_iterations) != 0) {
                if (atomic_dec_and_test(&reg->hr_unsteady_iterations)) {
                        printk(KERN_NOTICE "o2hb: Unable to stabilize "
-                              "heartbeat on region %s (%s)\n",
+                              "heartbeat on region %s (%pg)\n",
                               config_item_name(&reg->hr_item),
-                              reg->hr_dev_name);
+                              reg->hr_bdev);
                        atomic_set(&reg->hr_steady_iterations, 0);
                        reg->hr_aborted_start = 1;
                        wake_up(&o2hb_steady_queue);
@@ -1494,7 +1491,7 @@ static void o2hb_region_release(struct config_item *item)
        struct page *page;
        struct o2hb_region *reg = to_o2hb_region(item);
 
-       mlog(ML_HEARTBEAT, "hb region release (%s)\n", reg->hr_dev_name);
+       mlog(ML_HEARTBEAT, "hb region release (%pg)\n", reg->hr_bdev);
 
        kfree(reg->hr_tmp_block);
 
@@ -1641,7 +1638,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)
-               ret = sprintf(page, "%s\n", to_o2hb_region(item)->hr_dev_name);
+               ret = sprintf(page, "%pg\n", to_o2hb_region(item)->hr_bdev);
 
        return ret;
 }
@@ -1798,8 +1795,6 @@ static ssize_t o2hb_region_dev_store(struct config_item *item,
                goto out2;
        }
 
-       bdevname(reg->hr_bdev, reg->hr_dev_name);
-
        sectsize = bdev_logical_block_size(reg->hr_bdev);
        if (sectsize != reg->hr_block_bytes) {
                mlog(ML_ERROR,
@@ -1895,8 +1890,8 @@ static ssize_t o2hb_region_dev_store(struct config_item *item,
                ret = -EIO;
 
        if (hb_task && o2hb_global_heartbeat_active())
-               printk(KERN_NOTICE "o2hb: Heartbeat started on region %s (%s)\n",
-                      config_item_name(&reg->hr_item), reg->hr_dev_name);
+               printk(KERN_NOTICE "o2hb: Heartbeat started on region %s (%pg)\n",
+                      config_item_name(&reg->hr_item), reg->hr_bdev);
 
 out3:
        if (ret < 0) {
@@ -2088,10 +2083,10 @@ static void o2hb_heartbeat_group_drop_item(struct config_group *group,
                        quorum_region = 1;
                clear_bit(reg->hr_region_num, o2hb_quorum_region_bitmap);
                spin_unlock(&o2hb_live_lock);
-               printk(KERN_NOTICE "o2hb: Heartbeat %s on region %s (%s)\n",
+               printk(KERN_NOTICE "o2hb: Heartbeat %s on region %s (%pg)\n",
                       ((atomic_read(&reg->hr_steady_iterations) == 0) ?
                        "stopped" : "start aborted"), config_item_name(item),
-                      reg->hr_dev_name);
+                      reg->hr_bdev);
        }
 
        /*
index 7497cd5..9c67edd 100644 (file)
@@ -1146,7 +1146,7 @@ int ocfs2_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
        if (status)
                return status;
 
-       if (is_quota_modification(inode, attr)) {
+       if (is_quota_modification(mnt_userns, inode, attr)) {
                status = dquot_initialize(inode);
                if (status)
                        return status;
index 3375275..740b642 100644 (file)
@@ -277,7 +277,6 @@ enum ocfs2_mount_options
        OCFS2_MOUNT_JOURNAL_ASYNC_COMMIT = 1 << 15,  /* Journal Async Commit */
        OCFS2_MOUNT_ERRORS_CONT = 1 << 16, /* Return EIO to the calling process on error */
        OCFS2_MOUNT_ERRORS_ROFS = 1 << 17, /* Change filesystem to read-only on error */
-       OCFS2_MOUNT_NOCLUSTER = 1 << 18, /* No cluster aware filesystem mount */
 };
 
 #define OCFS2_OSB_SOFT_RO      0x0001
@@ -673,8 +672,7 @@ static inline int ocfs2_cluster_o2cb_global_heartbeat(struct ocfs2_super *osb)
 
 static inline int ocfs2_mount_local(struct ocfs2_super *osb)
 {
-       return ((osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT)
-               || (osb->s_mount_opt & OCFS2_MOUNT_NOCLUSTER));
+       return (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT);
 }
 
 static inline int ocfs2_uses_extended_slot_map(struct ocfs2_super *osb)
index 0b0ae3e..da7718c 100644 (file)
@@ -252,16 +252,14 @@ static int __ocfs2_find_empty_slot(struct ocfs2_slot_info *si,
        int i, ret = -ENOSPC;
 
        if ((preferred >= 0) && (preferred < si->si_num_slots)) {
-               if (!si->si_slots[preferred].sl_valid ||
-                   !si->si_slots[preferred].sl_node_num) {
+               if (!si->si_slots[preferred].sl_valid) {
                        ret = preferred;
                        goto out;
                }
        }
 
        for(i = 0; i < si->si_num_slots; i++) {
-               if (!si->si_slots[i].sl_valid ||
-                   !si->si_slots[i].sl_node_num) {
+               if (!si->si_slots[i].sl_valid) {
                        ret = i;
                        break;
                }
@@ -456,30 +454,24 @@ int ocfs2_find_slot(struct ocfs2_super *osb)
        spin_lock(&osb->osb_lock);
        ocfs2_update_slot_info(si);
 
-       if (ocfs2_mount_local(osb))
-               /* use slot 0 directly in local mode */
-               slot = 0;
-       else {
-               /* search for ourselves first and take the slot if it already
-                * exists. Perhaps we need to mark this in a variable for our
-                * own journal recovery? Possibly not, though we certainly
-                * need to warn to the user */
-               slot = __ocfs2_node_num_to_slot(si, osb->node_num);
+       /* search for ourselves first and take the slot if it already
+        * exists. Perhaps we need to mark this in a variable for our
+        * own journal recovery? Possibly not, though we certainly
+        * need to warn to the user */
+       slot = __ocfs2_node_num_to_slot(si, osb->node_num);
+       if (slot < 0) {
+               /* if no slot yet, then just take 1st available
+                * one. */
+               slot = __ocfs2_find_empty_slot(si, osb->preferred_slot);
                if (slot < 0) {
-                       /* if no slot yet, then just take 1st available
-                        * one. */
-                       slot = __ocfs2_find_empty_slot(si, osb->preferred_slot);
-                       if (slot < 0) {
-                               spin_unlock(&osb->osb_lock);
-                               mlog(ML_ERROR, "no free slots available!\n");
-                               status = -EINVAL;
-                               goto bail;
-                       }
-               } else
-                       printk(KERN_INFO "ocfs2: Slot %d on device (%s) was "
-                              "already allocated to this node!\n",
-                              slot, osb->dev_str);
-       }
+                       spin_unlock(&osb->osb_lock);
+                       mlog(ML_ERROR, "no free slots available!\n");
+                       status = -EINVAL;
+                       goto bail;
+               }
+       } else
+               printk(KERN_INFO "ocfs2: Slot %d on device (%s) was already "
+                      "allocated to this node!\n", slot, osb->dev_str);
 
        ocfs2_set_slot(si, slot, osb->node_num);
        osb->slot_num = slot;
index f729881..013a727 100644 (file)
@@ -172,7 +172,6 @@ enum {
        Opt_dir_resv_level,
        Opt_journal_async_commit,
        Opt_err_cont,
-       Opt_nocluster,
        Opt_err,
 };
 
@@ -206,7 +205,6 @@ static const match_table_t tokens = {
        {Opt_dir_resv_level, "dir_resv_level=%u"},
        {Opt_journal_async_commit, "journal_async_commit"},
        {Opt_err_cont, "errors=continue"},
-       {Opt_nocluster, "nocluster"},
        {Opt_err, NULL}
 };
 
@@ -618,13 +616,6 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
                goto out;
        }
 
-       tmp = OCFS2_MOUNT_NOCLUSTER;
-       if ((osb->s_mount_opt & tmp) != (parsed_options.mount_opt & tmp)) {
-               ret = -EINVAL;
-               mlog(ML_ERROR, "Cannot change nocluster option on remount\n");
-               goto out;
-       }
-
        tmp = OCFS2_MOUNT_HB_LOCAL | OCFS2_MOUNT_HB_GLOBAL |
                OCFS2_MOUNT_HB_NONE;
        if ((osb->s_mount_opt & tmp) != (parsed_options.mount_opt & tmp)) {
@@ -865,7 +856,6 @@ static int ocfs2_verify_userspace_stack(struct ocfs2_super *osb,
        }
 
        if (ocfs2_userspace_stack(osb) &&
-           !(osb->s_mount_opt & OCFS2_MOUNT_NOCLUSTER) &&
            strncmp(osb->osb_cluster_stack, mopt->cluster_stack,
                    OCFS2_STACK_LABEL_LEN)) {
                mlog(ML_ERROR,
@@ -1137,11 +1127,6 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
               osb->s_mount_opt & OCFS2_MOUNT_DATA_WRITEBACK ? "writeback" :
               "ordered");
 
-       if ((osb->s_mount_opt & OCFS2_MOUNT_NOCLUSTER) &&
-          !(osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT))
-               printk(KERN_NOTICE "ocfs2: The shared device (%s) is mounted "
-                      "without cluster aware mode.\n", osb->dev_str);
-
        atomic_set(&osb->vol_state, VOLUME_MOUNTED);
        wake_up(&osb->osb_mount_event);
 
@@ -1452,9 +1437,6 @@ static int ocfs2_parse_options(struct super_block *sb,
                case Opt_journal_async_commit:
                        mopt->mount_opt |= OCFS2_MOUNT_JOURNAL_ASYNC_COMMIT;
                        break;
-               case Opt_nocluster:
-                       mopt->mount_opt |= OCFS2_MOUNT_NOCLUSTER;
-                       break;
                default:
                        mlog(ML_ERROR,
                             "Unrecognized mount option \"%s\" "
@@ -1566,9 +1548,6 @@ static int ocfs2_show_options(struct seq_file *s, struct dentry *root)
        if (opts & OCFS2_MOUNT_JOURNAL_ASYNC_COMMIT)
                seq_printf(s, ",journal_async_commit");
 
-       if (opts & OCFS2_MOUNT_NOCLUSTER)
-               seq_printf(s, ",nocluster");
-
        return 0;
 }
 
@@ -1785,7 +1764,7 @@ static int ocfs2_get_sector(struct super_block *sb,
        if (!buffer_dirty(*bh))
                clear_buffer_uptodate(*bh);
        unlock_buffer(*bh);
-       ll_rw_block(REQ_OP_READ, 0, 1, bh);
+       ll_rw_block(REQ_OP_READ, 1, bh);
        wait_on_buffer(*bh);
        if (!buffer_uptodate(*bh)) {
                mlog_errno(-EIO);
index 1d57fbd..2790aac 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -663,6 +663,42 @@ SYSCALL_DEFINE2(chmod, const char __user *, filename, umode_t, mode)
        return do_fchmodat(AT_FDCWD, filename, mode);
 }
 
+/**
+ * setattr_vfsuid - check and set ia_fsuid attribute
+ * @kuid: new inode owner
+ *
+ * Check whether @kuid is valid and if so generate and set vfsuid_t in
+ * ia_vfsuid.
+ *
+ * Return: true if @kuid is valid, false if not.
+ */
+static inline bool setattr_vfsuid(struct iattr *attr, kuid_t kuid)
+{
+       if (!uid_valid(kuid))
+               return false;
+       attr->ia_valid |= ATTR_UID;
+       attr->ia_vfsuid = VFSUIDT_INIT(kuid);
+       return true;
+}
+
+/**
+ * setattr_vfsgid - check and set ia_fsgid attribute
+ * @kgid: new inode owner
+ *
+ * Check whether @kgid is valid and if so generate and set vfsgid_t in
+ * ia_vfsgid.
+ *
+ * Return: true if @kgid is valid, false if not.
+ */
+static inline bool setattr_vfsgid(struct iattr *attr, kgid_t kgid)
+{
+       if (!gid_valid(kgid))
+               return false;
+       attr->ia_valid |= ATTR_GID;
+       attr->ia_vfsgid = VFSGIDT_INIT(kgid);
+       return true;
+}
+
 int chown_common(const struct path *path, uid_t user, gid_t group)
 {
        struct user_namespace *mnt_userns, *fs_userns;
@@ -678,28 +714,22 @@ int chown_common(const struct path *path, uid_t user, gid_t group)
 
        mnt_userns = mnt_user_ns(path->mnt);
        fs_userns = i_user_ns(inode);
-       uid = mapped_kuid_user(mnt_userns, fs_userns, uid);
-       gid = mapped_kgid_user(mnt_userns, fs_userns, gid);
 
 retry_deleg:
        newattrs.ia_valid =  ATTR_CTIME;
-       if (user != (uid_t) -1) {
-               if (!uid_valid(uid))
-                       return -EINVAL;
-               newattrs.ia_valid |= ATTR_UID;
-               newattrs.ia_uid = uid;
-       }
-       if (group != (gid_t) -1) {
-               if (!gid_valid(gid))
-                       return -EINVAL;
-               newattrs.ia_valid |= ATTR_GID;
-               newattrs.ia_gid = gid;
-       }
+       if ((user != (uid_t)-1) && !setattr_vfsuid(&newattrs, uid))
+               return -EINVAL;
+       if ((group != (gid_t)-1) && !setattr_vfsgid(&newattrs, gid))
+               return -EINVAL;
        if (!S_ISDIR(inode->i_mode))
                newattrs.ia_valid |=
                        ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV;
        inode_lock(inode);
-       error = security_path_chown(path, uid, gid);
+       /* Continue to send actual fs values, not the mount values. */
+       error = security_path_chown(
+               path,
+               from_vfsuid(mnt_userns, fs_userns, newattrs.ia_vfsuid),
+               from_vfsgid(mnt_userns, fs_userns, newattrs.ia_vfsgid));
        if (!error)
                error = notify_change(mnt_userns, path->dentry, &newattrs,
                                      &delegated_inode);
index 714ec56..245e2cb 100644 (file)
@@ -331,8 +331,8 @@ int ovl_set_attr(struct ovl_fs *ofs, struct dentry *upperdentry,
        if (!err) {
                struct iattr attr = {
                        .ia_valid = ATTR_UID | ATTR_GID,
-                       .ia_uid = stat->uid,
-                       .ia_gid = stat->gid,
+                       .ia_vfsuid = VFSUIDT_INIT(stat->uid),
+                       .ia_vfsgid = VFSGIDT_INIT(stat->gid),
                };
                err = ovl_do_notify_change(ofs, upperdentry, &attr);
        }
index 492edde..7922b61 100644 (file)
@@ -454,23 +454,94 @@ ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
        return res;
 }
 
+/*
+ * Apply the idmapping of the layer to POSIX ACLs. The caller must pass a clone
+ * of the POSIX ACLs retrieved from the lower layer to this function to not
+ * alter the POSIX ACLs for the underlying filesystem.
+ */
+static void ovl_idmap_posix_acl(struct user_namespace *mnt_userns,
+                               struct posix_acl *acl)
+{
+       for (unsigned int i = 0; i < acl->a_count; i++) {
+               vfsuid_t vfsuid;
+               vfsgid_t vfsgid;
+
+               struct posix_acl_entry *e = &acl->a_entries[i];
+               switch (e->e_tag) {
+               case ACL_USER:
+                       vfsuid = make_vfsuid(mnt_userns, &init_user_ns, e->e_uid);
+                       e->e_uid = vfsuid_into_kuid(vfsuid);
+                       break;
+               case ACL_GROUP:
+                       vfsgid = make_vfsgid(mnt_userns, &init_user_ns, e->e_gid);
+                       e->e_gid = vfsgid_into_kgid(vfsgid);
+                       break;
+               }
+       }
+}
+
+/*
+ * When the relevant layer is an idmapped mount we need to take the idmapping
+ * of the layer into account and translate any ACL_{GROUP,USER} values
+ * according to the idmapped mount.
+ *
+ * We cannot alter the ACLs returned from the relevant layer as that would
+ * alter the cached values filesystem wide for the lower filesystem. Instead we
+ * can clone the ACLs and then apply the relevant idmapping of the layer.
+ *
+ * This is obviously only relevant when idmapped layers are used.
+ */
 struct posix_acl *ovl_get_acl(struct inode *inode, int type, bool rcu)
 {
        struct inode *realinode = ovl_inode_real(inode);
-       const struct cred *old_cred;
-       struct posix_acl *acl;
+       struct posix_acl *acl, *clone;
+       struct path realpath;
 
        if (!IS_ENABLED(CONFIG_FS_POSIX_ACL) || !IS_POSIXACL(realinode))
                return NULL;
 
-       if (rcu)
-               return get_cached_acl_rcu(realinode, type);
+       /* Careful in RCU walk mode */
+       ovl_i_path_real(inode, &realpath);
+       if (!realpath.dentry) {
+               WARN_ON(!rcu);
+               return ERR_PTR(-ECHILD);
+       }
 
-       old_cred = ovl_override_creds(inode->i_sb);
-       acl = get_acl(realinode, type);
-       revert_creds(old_cred);
+       if (rcu) {
+               acl = get_cached_acl_rcu(realinode, type);
+       } else {
+               const struct cred *old_cred;
+
+               old_cred = ovl_override_creds(inode->i_sb);
+               acl = get_acl(realinode, type);
+               revert_creds(old_cred);
+       }
+       /*
+        * If there are no POSIX ACLs, or we encountered an error,
+        * or the layer isn't idmapped we don't need to do anything.
+        */
+       if (!is_idmapped_mnt(realpath.mnt) || IS_ERR_OR_NULL(acl))
+               return acl;
 
-       return acl;
+       /*
+        * We only get here if the layer is idmapped. So drop out of RCU path
+        * walk so we can clone the ACLs. There's no need to release the ACLs
+        * since get_cached_acl_rcu() doesn't take a reference on the ACLs.
+        */
+       if (rcu)
+               return ERR_PTR(-ECHILD);
+
+       clone = posix_acl_clone(acl, GFP_KERNEL);
+       if (!clone)
+               clone = ERR_PTR(-ENOMEM);
+       else
+               ovl_idmap_posix_acl(mnt_user_ns(realpath.mnt), clone);
+       /*
+        * Since we're not in RCU path walk we always need to release the
+        * original ACLs.
+        */
+       posix_acl_release(acl);
+       return clone;
 }
 
 int ovl_update_time(struct inode *inode, struct timespec64 *ts, int flags)
index 4f34b7e..6ec815b 100644 (file)
@@ -139,17 +139,7 @@ static inline int ovl_do_notify_change(struct ovl_fs *ofs,
                                       struct dentry *upperdentry,
                                       struct iattr *attr)
 {
-       struct user_namespace *upper_mnt_userns = ovl_upper_mnt_userns(ofs);
-       struct user_namespace *fs_userns = i_user_ns(d_inode(upperdentry));
-
-       if (attr->ia_valid & ATTR_UID)
-               attr->ia_uid = mapped_kuid_user(upper_mnt_userns,
-                                               fs_userns, attr->ia_uid);
-       if (attr->ia_valid & ATTR_GID)
-               attr->ia_gid = mapped_kgid_user(upper_mnt_userns,
-                                               fs_userns, attr->ia_gid);
-
-       return notify_change(upper_mnt_userns, upperdentry, attr, NULL);
+       return notify_change(ovl_upper_mnt_userns(ofs), upperdentry, attr, NULL);
 }
 
 static inline int ovl_do_rmdir(struct ovl_fs *ofs,
@@ -259,7 +249,8 @@ static inline int ovl_do_setxattr(struct ovl_fs *ofs, struct dentry *dentry,
                                  const char *name, const void *value,
                                  size_t size, int flags)
 {
-       int err = vfs_setxattr(ovl_upper_mnt_userns(ofs), dentry, name, value, size, flags);
+       int err = vfs_setxattr(ovl_upper_mnt_userns(ofs), dentry, name,
+                              (void *)value, size, flags);
 
        pr_debug("setxattr(%pd2, \"%s\", \"%*pE\", %zu, %d) = %i\n",
                 dentry, name, min((int)size, 48), value, size, flags, err);
index 962d324..1d17d7b 100644 (file)
@@ -199,7 +199,7 @@ EXPORT_SYMBOL(posix_acl_alloc);
 /*
  * Clone an ACL.
  */
-static struct posix_acl *
+struct posix_acl *
 posix_acl_clone(const struct posix_acl *acl, gfp_t flags)
 {
        struct posix_acl *clone = NULL;
@@ -213,6 +213,7 @@ posix_acl_clone(const struct posix_acl *acl, gfp_t flags)
        }
        return clone;
 }
+EXPORT_SYMBOL_GPL(posix_acl_clone);
 
 /*
  * Check if an acl is valid. Returns 0 if it is, or -E... otherwise.
@@ -361,8 +362,8 @@ posix_acl_permission(struct user_namespace *mnt_userns, struct inode *inode,
 {
        const struct posix_acl_entry *pa, *pe, *mask_obj;
        int found = 0;
-       kuid_t uid;
-       kgid_t gid;
+       vfsuid_t vfsuid;
+       vfsgid_t vfsgid;
 
        want &= MAY_READ | MAY_WRITE | MAY_EXEC;
 
@@ -370,30 +371,28 @@ posix_acl_permission(struct user_namespace *mnt_userns, struct inode *inode,
                 switch(pa->e_tag) {
                         case ACL_USER_OBJ:
                                /* (May have been checked already) */
-                               uid = i_uid_into_mnt(mnt_userns, inode);
-                               if (uid_eq(uid, current_fsuid()))
+                               vfsuid = i_uid_into_vfsuid(mnt_userns, inode);
+                               if (vfsuid_eq_kuid(vfsuid, current_fsuid()))
                                         goto check_perm;
                                 break;
                         case ACL_USER:
-                               uid = mapped_kuid_fs(mnt_userns,
-                                                    i_user_ns(inode),
+                               vfsuid = make_vfsuid(mnt_userns, &init_user_ns,
                                                     pa->e_uid);
-                               if (uid_eq(uid, current_fsuid()))
+                               if (vfsuid_eq_kuid(vfsuid, current_fsuid()))
                                         goto mask;
                                break;
                         case ACL_GROUP_OBJ:
-                               gid = i_gid_into_mnt(mnt_userns, inode);
-                               if (in_group_p(gid)) {
+                               vfsgid = i_gid_into_vfsgid(mnt_userns, inode);
+                               if (vfsgid_in_group_p(vfsgid)) {
                                        found = 1;
                                        if ((pa->e_perm & want) == want)
                                                goto mask;
                                 }
                                break;
                         case ACL_GROUP:
-                               gid = mapped_kgid_fs(mnt_userns,
-                                                    i_user_ns(inode),
+                               vfsgid = make_vfsgid(mnt_userns, &init_user_ns,
                                                     pa->e_gid);
-                               if (in_group_p(gid)) {
+                               if (vfsgid_in_group_p(vfsgid)) {
                                        found = 1;
                                        if ((pa->e_perm & want) == want)
                                                goto mask;
@@ -699,7 +698,7 @@ int posix_acl_update_mode(struct user_namespace *mnt_userns,
                return error;
        if (error == 0)
                *acl = NULL;
-       if (!in_group_p(i_gid_into_mnt(mnt_userns, inode)) &&
+       if (!vfsgid_in_group_p(i_gid_into_vfsgid(mnt_userns, inode)) &&
            !capable_wrt_inode_uidgid(mnt_userns, inode, CAP_FSETID))
                mode &= ~S_ISGID;
        *mode_p = mode;
@@ -710,46 +709,127 @@ EXPORT_SYMBOL(posix_acl_update_mode);
 /*
  * Fix up the uids and gids in posix acl extended attributes in place.
  */
-static void posix_acl_fix_xattr_userns(
-       struct user_namespace *to, struct user_namespace *from,
-       struct user_namespace *mnt_userns,
-       void *value, size_t size, bool from_user)
+static int posix_acl_fix_xattr_common(void *value, size_t size)
+{
+       struct posix_acl_xattr_header *header = value;
+       int count;
+
+       if (!header)
+               return -EINVAL;
+       if (size < sizeof(struct posix_acl_xattr_header))
+               return -EINVAL;
+       if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
+               return -EINVAL;
+
+       count = posix_acl_xattr_count(size);
+       if (count < 0)
+               return -EINVAL;
+       if (count == 0)
+               return -EINVAL;
+
+       return count;
+}
+
+void posix_acl_getxattr_idmapped_mnt(struct user_namespace *mnt_userns,
+                                    const struct inode *inode,
+                                    void *value, size_t size)
 {
        struct posix_acl_xattr_header *header = value;
        struct posix_acl_xattr_entry *entry = (void *)(header + 1), *end;
        int count;
+       vfsuid_t vfsuid;
+       vfsgid_t vfsgid;
        kuid_t uid;
        kgid_t gid;
 
-       if (!value)
+       if (no_idmapping(mnt_userns, i_user_ns(inode)))
                return;
-       if (size < sizeof(struct posix_acl_xattr_header))
+
+       count = posix_acl_fix_xattr_common(value, size);
+       if (count < 0)
                return;
-       if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
+
+       for (end = entry + count; entry != end; entry++) {
+               switch (le16_to_cpu(entry->e_tag)) {
+               case ACL_USER:
+                       uid = make_kuid(&init_user_ns, le32_to_cpu(entry->e_id));
+                       vfsuid = make_vfsuid(mnt_userns, &init_user_ns, uid);
+                       entry->e_id = cpu_to_le32(from_kuid(&init_user_ns,
+                                               vfsuid_into_kuid(vfsuid)));
+                       break;
+               case ACL_GROUP:
+                       gid = make_kgid(&init_user_ns, le32_to_cpu(entry->e_id));
+                       vfsgid = make_vfsgid(mnt_userns, &init_user_ns, gid);
+                       entry->e_id = cpu_to_le32(from_kgid(&init_user_ns,
+                                               vfsgid_into_kgid(vfsgid)));
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+void posix_acl_setxattr_idmapped_mnt(struct user_namespace *mnt_userns,
+                                    const struct inode *inode,
+                                    void *value, size_t size)
+{
+       struct posix_acl_xattr_header *header = value;
+       struct posix_acl_xattr_entry *entry = (void *)(header + 1), *end;
+       int count;
+       vfsuid_t vfsuid;
+       vfsgid_t vfsgid;
+       kuid_t uid;
+       kgid_t gid;
+
+       if (no_idmapping(mnt_userns, i_user_ns(inode)))
                return;
 
-       count = posix_acl_xattr_count(size);
+       count = posix_acl_fix_xattr_common(value, size);
        if (count < 0)
                return;
-       if (count == 0)
+
+       for (end = entry + count; entry != end; entry++) {
+               switch (le16_to_cpu(entry->e_tag)) {
+               case ACL_USER:
+                       uid = make_kuid(&init_user_ns, le32_to_cpu(entry->e_id));
+                       vfsuid = VFSUIDT_INIT(uid);
+                       uid = from_vfsuid(mnt_userns, &init_user_ns, vfsuid);
+                       entry->e_id = cpu_to_le32(from_kuid(&init_user_ns, uid));
+                       break;
+               case ACL_GROUP:
+                       gid = make_kgid(&init_user_ns, le32_to_cpu(entry->e_id));
+                       vfsgid = VFSGIDT_INIT(gid);
+                       gid = from_vfsgid(mnt_userns, &init_user_ns, vfsgid);
+                       entry->e_id = cpu_to_le32(from_kgid(&init_user_ns, gid));
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+static void posix_acl_fix_xattr_userns(
+       struct user_namespace *to, struct user_namespace *from,
+       void *value, size_t size)
+{
+       struct posix_acl_xattr_header *header = value;
+       struct posix_acl_xattr_entry *entry = (void *)(header + 1), *end;
+       int count;
+       kuid_t uid;
+       kgid_t gid;
+
+       count = posix_acl_fix_xattr_common(value, size);
+       if (count < 0)
                return;
 
        for (end = entry + count; entry != end; entry++) {
                switch(le16_to_cpu(entry->e_tag)) {
                case ACL_USER:
                        uid = make_kuid(from, le32_to_cpu(entry->e_id));
-                       if (from_user)
-                               uid = mapped_kuid_user(mnt_userns, &init_user_ns, uid);
-                       else
-                               uid = mapped_kuid_fs(mnt_userns, &init_user_ns, uid);
                        entry->e_id = cpu_to_le32(from_kuid(to, uid));
                        break;
                case ACL_GROUP:
                        gid = make_kgid(from, le32_to_cpu(entry->e_id));
-                       if (from_user)
-                               gid = mapped_kgid_user(mnt_userns, &init_user_ns, gid);
-                       else
-                               gid = mapped_kgid_fs(mnt_userns, &init_user_ns, gid);
                        entry->e_id = cpu_to_le32(from_kgid(to, gid));
                        break;
                default:
@@ -758,34 +838,20 @@ static void posix_acl_fix_xattr_userns(
        }
 }
 
-void posix_acl_fix_xattr_from_user(struct user_namespace *mnt_userns,
-                                  struct inode *inode,
-                                  void *value, size_t size)
+void posix_acl_fix_xattr_from_user(void *value, size_t size)
 {
        struct user_namespace *user_ns = current_user_ns();
-
-       /* Leave ids untouched on non-idmapped mounts. */
-       if (no_idmapping(mnt_userns, i_user_ns(inode)))
-               mnt_userns = &init_user_ns;
-       if ((user_ns == &init_user_ns) && (mnt_userns == &init_user_ns))
+       if (user_ns == &init_user_ns)
                return;
-       posix_acl_fix_xattr_userns(&init_user_ns, user_ns, mnt_userns, value,
-                                  size, true);
+       posix_acl_fix_xattr_userns(&init_user_ns, user_ns, value, size);
 }
 
-void posix_acl_fix_xattr_to_user(struct user_namespace *mnt_userns,
-                                struct inode *inode,
-                                void *value, size_t size)
+void posix_acl_fix_xattr_to_user(void *value, size_t size)
 {
        struct user_namespace *user_ns = current_user_ns();
-
-       /* Leave ids untouched on non-idmapped mounts. */
-       if (no_idmapping(mnt_userns, i_user_ns(inode)))
-               mnt_userns = &init_user_ns;
-       if ((user_ns == &init_user_ns) && (mnt_userns == &init_user_ns))
+       if (user_ns == &init_user_ns)
                return;
-       posix_acl_fix_xattr_userns(user_ns, &init_user_ns, mnt_userns, value,
-                                  size, false);
+       posix_acl_fix_xattr_userns(user_ns, &init_user_ns, value, size);
 }
 
 /*
index e26162f..4d7fc1c 100644 (file)
 #include <linux/crypto.h>
 #include <linux/string.h>
 #include <linux/timer.h>
+#include <linux/scatterlist.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
 #include <linux/jiffies.h>
 #include <linux/workqueue.h>
 
+#include <crypto/acompress.h>
+
 #include "internal.h"
 
 /*
@@ -90,7 +93,8 @@ module_param(compress, charp, 0444);
 MODULE_PARM_DESC(compress, "compression to use");
 
 /* Compression parameters */
-static struct crypto_comp *tfm;
+static struct crypto_acomp *tfm;
+static struct acomp_req *creq;
 
 struct pstore_zbackend {
        int (*zbufsize)(size_t size);
@@ -268,12 +272,21 @@ static const struct pstore_zbackend zbackends[] = {
 static int pstore_compress(const void *in, void *out,
                           unsigned int inlen, unsigned int outlen)
 {
+       struct scatterlist src, dst;
        int ret;
 
        if (!IS_ENABLED(CONFIG_PSTORE_COMPRESS))
                return -EINVAL;
 
-       ret = crypto_comp_compress(tfm, in, inlen, out, &outlen);
+       sg_init_table(&src, 1);
+       sg_set_buf(&src, in, inlen);
+
+       sg_init_table(&dst, 1);
+       sg_set_buf(&dst, out, outlen);
+
+       acomp_request_set_params(creq, &src, &dst, inlen, outlen);
+
+       ret = crypto_acomp_compress(creq);
        if (ret) {
                pr_err("crypto_comp_compress failed, ret = %d!\n", ret);
                return ret;
@@ -284,7 +297,7 @@ static int pstore_compress(const void *in, void *out,
 
 static void allocate_buf_for_compression(void)
 {
-       struct crypto_comp *ctx;
+       struct crypto_acomp *acomp;
        int size;
        char *buf;
 
@@ -296,7 +309,7 @@ static void allocate_buf_for_compression(void)
        if (!psinfo || tfm)
                return;
 
-       if (!crypto_has_comp(zbackend->name, 0, 0)) {
+       if (!crypto_has_acomp(zbackend->name, 0, CRYPTO_ALG_ASYNC)) {
                pr_err("Unknown compression: %s\n", zbackend->name);
                return;
        }
@@ -315,16 +328,24 @@ static void allocate_buf_for_compression(void)
                return;
        }
 
-       ctx = crypto_alloc_comp(zbackend->name, 0, 0);
-       if (IS_ERR_OR_NULL(ctx)) {
+       acomp = crypto_alloc_acomp(zbackend->name, 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR_OR_NULL(acomp)) {
                kfree(buf);
                pr_err("crypto_alloc_comp('%s') failed: %ld\n", zbackend->name,
-                      PTR_ERR(ctx));
+                      PTR_ERR(acomp));
+               return;
+       }
+
+       creq = acomp_request_alloc(acomp);
+       if (!creq) {
+               crypto_free_acomp(acomp);
+               kfree(buf);
+               pr_err("acomp_request_alloc('%s') failed\n", zbackend->name);
                return;
        }
 
        /* A non-NULL big_oops_buf indicates compression is available. */
-       tfm = ctx;
+       tfm = acomp;
        big_oops_buf_sz = size;
        big_oops_buf = buf;
 
@@ -334,7 +355,8 @@ static void allocate_buf_for_compression(void)
 static void free_buf_for_compression(void)
 {
        if (IS_ENABLED(CONFIG_PSTORE_COMPRESS) && tfm) {
-               crypto_free_comp(tfm);
+               acomp_request_free(creq);
+               crypto_free_acomp(tfm);
                tfm = NULL;
        }
        kfree(big_oops_buf);
@@ -671,6 +693,8 @@ static void decompress_record(struct pstore_record *record)
        int ret;
        int unzipped_len;
        char *unzipped, *workspace;
+       struct acomp_req *dreq;
+       struct scatterlist src, dst;
 
        if (!IS_ENABLED(CONFIG_PSTORE_COMPRESS) || !record->compressed)
                return;
@@ -694,16 +718,30 @@ static void decompress_record(struct pstore_record *record)
        if (!workspace)
                return;
 
+       dreq = acomp_request_alloc(tfm);
+       if (!dreq) {
+               kfree(workspace);
+               return;
+       }
+
+       sg_init_table(&src, 1);
+       sg_set_buf(&src, record->buf, record->size);
+
+       sg_init_table(&dst, 1);
+       sg_set_buf(&dst, workspace, unzipped_len);
+
+       acomp_request_set_params(dreq, &src, &dst, record->size, unzipped_len);
+
        /* After decompression "unzipped_len" is almost certainly smaller. */
-       ret = crypto_comp_decompress(tfm, record->buf, record->size,
-                                         workspace, &unzipped_len);
+       ret = crypto_acomp_decompress(dreq);
        if (ret) {
-               pr_err("crypto_comp_decompress failed, ret = %d!\n", ret);
+               pr_err("crypto_acomp_decompress failed, ret = %d!\n", ret);
                kfree(workspace);
                return;
        }
 
        /* Append ECC notice to decompressed buffer. */
+       unzipped_len = dreq->dlen;
        memcpy(workspace + unzipped_len, record->buf + record->size,
               record->ecc_notice_size);
 
@@ -711,6 +749,7 @@ static void decompress_record(struct pstore_record *record)
        unzipped = kmemdup(workspace, unzipped_len + record->ecc_notice_size,
                           GFP_KERNEL);
        kfree(workspace);
+       acomp_request_free(dreq);
        if (!unzipped)
                return;
 
index 7c8f8fe..017d0d4 100644 (file)
@@ -363,7 +363,7 @@ static int psz_kmsg_recover_data(struct psz_context *cxt)
                rcnt = info->read((char *)buf, zone->buffer_size + sizeof(*buf),
                                zone->off);
                if (rcnt != zone->buffer_size + sizeof(*buf))
-                       return (int)rcnt < 0 ? (int)rcnt : -EIO;
+                       return rcnt < 0 ? rcnt : -EIO;
        }
        return 0;
 }
@@ -372,7 +372,7 @@ static int psz_kmsg_recover_meta(struct psz_context *cxt)
 {
        struct pstore_zone_info *info = cxt->pstore_zone_info;
        struct pstore_zone *zone;
-       size_t rcnt, len;
+       ssize_t rcnt, len;
        struct psz_buffer *buf;
        struct psz_kmsg_header *hdr;
        struct timespec64 time = { };
@@ -400,7 +400,7 @@ static int psz_kmsg_recover_meta(struct psz_context *cxt)
                        continue;
                } else if (rcnt != len) {
                        pr_err("read %s with id %lu failed\n", zone->name, i);
-                       return (int)rcnt < 0 ? (int)rcnt : -EIO;
+                       return rcnt < 0 ? rcnt : -EIO;
                }
 
                if (buf->sig != zone->buffer->sig) {
@@ -502,7 +502,7 @@ static int psz_recover_zone(struct psz_context *cxt, struct pstore_zone *zone)
        rcnt = info->read((char *)&tmpbuf, len, zone->off);
        if (rcnt != len) {
                pr_debug("read zone %s failed\n", zone->name);
-               return (int)rcnt < 0 ? (int)rcnt : -EIO;
+               return rcnt < 0 ? rcnt : -EIO;
        }
 
        if (tmpbuf.sig != zone->buffer->sig) {
@@ -544,7 +544,7 @@ static int psz_recover_zone(struct psz_context *cxt, struct pstore_zone *zone)
        rcnt = info->read(buf, len - start, off + start);
        if (rcnt != len - start) {
                pr_err("read zone %s failed\n", zone->name);
-               ret = (int)rcnt < 0 ? (int)rcnt : -EIO;
+               ret = rcnt < 0 ? rcnt : -EIO;
                goto free_oldbuf;
        }
 
@@ -552,7 +552,7 @@ static int psz_recover_zone(struct psz_context *cxt, struct pstore_zone *zone)
        rcnt = info->read(buf + len - start, start, off);
        if (rcnt != start) {
                pr_err("read zone %s failed\n", zone->name);
-               ret = (int)rcnt < 0 ? (int)rcnt : -EIO;
+               ret = rcnt < 0 ? rcnt : -EIO;
                goto free_oldbuf;
        }
 
index 09d1307..28966da 100644 (file)
@@ -2085,7 +2085,8 @@ EXPORT_SYMBOL(__dquot_transfer);
 /* Wrapper for transferring ownership of an inode for uid/gid only
  * Called from FSXXX_setattr()
  */
-int dquot_transfer(struct inode *inode, struct iattr *iattr)
+int dquot_transfer(struct user_namespace *mnt_userns, struct inode *inode,
+                  struct iattr *iattr)
 {
        struct dquot *transfer_to[MAXQUOTAS] = {};
        struct dquot *dquot;
@@ -2095,8 +2096,11 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
        if (!dquot_active(inode))
                return 0;
 
-       if (iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)){
-               dquot = dqget(sb, make_kqid_uid(iattr->ia_uid));
+       if (i_uid_needs_update(mnt_userns, iattr, inode)) {
+               kuid_t kuid = from_vfsuid(mnt_userns, i_user_ns(inode),
+                                         iattr->ia_vfsuid);
+
+               dquot = dqget(sb, make_kqid_uid(kuid));
                if (IS_ERR(dquot)) {
                        if (PTR_ERR(dquot) != -ESRCH) {
                                ret = PTR_ERR(dquot);
@@ -2106,8 +2110,11 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
                }
                transfer_to[USRQUOTA] = dquot;
        }
-       if (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid)){
-               dquot = dqget(sb, make_kqid_gid(iattr->ia_gid));
+       if (i_gid_needs_update(mnt_userns, iattr, inode)) {
+               kgid_t kgid = from_vfsgid(mnt_userns, i_user_ns(inode),
+                                         iattr->ia_vfsgid);
+
+               dquot = dqget(sb, make_kqid_gid(kgid));
                if (IS_ERR(dquot)) {
                        if (PTR_ERR(dquot) != -ESRCH) {
                                ret = PTR_ERR(dquot);
index b1b1cdf..0131d0d 100644 (file)
@@ -1263,6 +1263,9 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
                                          count, fl);
                file_end_write(out.file);
        } else {
+               if (out.file->f_flags & O_NONBLOCK)
+                       fl |= SPLICE_F_NONBLOCK;
+
                retval = splice_file_to_pipe(in.file, opipe, &pos, count, fl);
        }
 
@@ -1397,28 +1400,6 @@ ssize_t generic_copy_file_range(struct file *file_in, loff_t pos_in,
 }
 EXPORT_SYMBOL(generic_copy_file_range);
 
-static ssize_t do_copy_file_range(struct file *file_in, loff_t pos_in,
-                                 struct file *file_out, loff_t pos_out,
-                                 size_t len, unsigned int flags)
-{
-       /*
-        * Although we now allow filesystems to handle cross sb copy, passing
-        * a file of the wrong filesystem type to filesystem driver can result
-        * in an attempt to dereference the wrong type of ->private_data, so
-        * avoid doing that until we really have a good reason.  NFS defines
-        * several different file_system_type structures, but they all end up
-        * using the same ->copy_file_range() function pointer.
-        */
-       if (file_out->f_op->copy_file_range &&
-           file_out->f_op->copy_file_range == file_in->f_op->copy_file_range)
-               return file_out->f_op->copy_file_range(file_in, pos_in,
-                                                      file_out, pos_out,
-                                                      len, flags);
-
-       return generic_copy_file_range(file_in, pos_in, file_out, pos_out, len,
-                                      flags);
-}
-
 /*
  * Performs necessary checks before doing a file copy
  *
@@ -1440,6 +1421,24 @@ static int generic_copy_file_checks(struct file *file_in, loff_t pos_in,
        if (ret)
                return ret;
 
+       /*
+        * We allow some filesystems to handle cross sb copy, but passing
+        * a file of the wrong filesystem type to filesystem driver can result
+        * in an attempt to dereference the wrong type of ->private_data, so
+        * avoid doing that until we really have a good reason.
+        *
+        * nfs and cifs define several different file_system_type structures
+        * and several different sets of file_operations, but they all end up
+        * using the same ->copy_file_range() function pointer.
+        */
+       if (file_out->f_op->copy_file_range) {
+               if (file_in->f_op->copy_file_range !=
+                   file_out->f_op->copy_file_range)
+                       return -EXDEV;
+       } else if (file_inode(file_in)->i_sb != file_inode(file_out)->i_sb) {
+               return -EXDEV;
+       }
+
        /* Don't touch certain kinds of inodes */
        if (IS_IMMUTABLE(inode_out))
                return -EPERM;
@@ -1505,26 +1504,41 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
        file_start_write(file_out);
 
        /*
-        * Try cloning first, this is supported by more file systems, and
-        * more efficient if both clone and copy are supported (e.g. NFS).
+        * Cloning is supported by more file systems, so we implement copy on
+        * same sb using clone, but for filesystems where both clone and copy
+        * are supported (e.g. nfs,cifs), we only call the copy method.
         */
+       if (file_out->f_op->copy_file_range) {
+               ret = file_out->f_op->copy_file_range(file_in, pos_in,
+                                                     file_out, pos_out,
+                                                     len, flags);
+               goto done;
+       }
+
        if (file_in->f_op->remap_file_range &&
            file_inode(file_in)->i_sb == file_inode(file_out)->i_sb) {
-               loff_t cloned;
-
-               cloned = file_in->f_op->remap_file_range(file_in, pos_in,
+               ret = file_in->f_op->remap_file_range(file_in, pos_in,
                                file_out, pos_out,
                                min_t(loff_t, MAX_RW_COUNT, len),
                                REMAP_FILE_CAN_SHORTEN);
-               if (cloned > 0) {
-                       ret = cloned;
+               if (ret > 0)
                        goto done;
-               }
        }
 
-       ret = do_copy_file_range(file_in, pos_in, file_out, pos_out, len,
-                               flags);
-       WARN_ON_ONCE(ret == -EOPNOTSUPP);
+       /*
+        * We can get here for same sb copy of filesystems that do not implement
+        * ->copy_file_range() in case filesystem does not support clone or in
+        * case filesystem supports clone but rejected the clone request (e.g.
+        * because it was not block aligned).
+        *
+        * In both cases, fall back to kernel copy so we are able to maintain a
+        * consistent story about which filesystems support copy_file_range()
+        * and which filesystems do not, that will allow userspace tools to
+        * make consistent desicions w.r.t using copy_file_range().
+        */
+       ret = generic_copy_file_range(file_in, pos_in, file_out, pos_out, len,
+                                     flags);
+
 done:
        if (ret > 0) {
                fsnotify_access(file_in);
@@ -1649,7 +1663,9 @@ int generic_write_checks_count(struct kiocb *iocb, loff_t *count)
        if (iocb->ki_flags & IOCB_APPEND)
                iocb->ki_pos = i_size_read(inode);
 
-       if ((iocb->ki_flags & IOCB_NOWAIT) && !(iocb->ki_flags & IOCB_DIRECT))
+       if ((iocb->ki_flags & IOCB_NOWAIT) &&
+           !((iocb->ki_flags & IOCB_DIRECT) ||
+             (file->f_mode & FMODE_BUF_WASYNC)))
                return -EINVAL;
 
        return generic_write_check_limits(iocb->ki_filp, iocb->ki_pos, count);
index 0cffe05..b9580a6 100644 (file)
@@ -290,7 +290,7 @@ static int _get_block_create_0(struct inode *inode, sector_t block,
        struct buffer_head *bh;
        struct item_head *ih, tmp_ih;
        b_blocknr_t blocknr;
-       char *p = NULL;
+       char *p;
        int chars;
        int ret;
        int result;
@@ -305,8 +305,6 @@ static int _get_block_create_0(struct inode *inode, sector_t block,
        result = search_for_position_by_key(inode->i_sb, &key, &path);
        if (result != POSITION_FOUND) {
                pathrelse(&path);
-               if (p)
-                       kunmap(bh_result->b_page);
                if (result == IO_ERROR)
                        return -EIO;
                /*
@@ -352,8 +350,6 @@ static int _get_block_create_0(struct inode *inode, sector_t block,
                }
 
                pathrelse(&path);
-               if (p)
-                       kunmap(bh_result->b_page);
                return ret;
        }
        /* requested data are in direct item(s) */
@@ -363,8 +359,6 @@ static int _get_block_create_0(struct inode *inode, sector_t block,
                 * when it is stored in direct item(s)
                 */
                pathrelse(&path);
-               if (p)
-                       kunmap(bh_result->b_page);
                return -ENOENT;
        }
 
@@ -396,9 +390,7 @@ static int _get_block_create_0(struct inode *inode, sector_t block,
         * sure we need to.  But, this means the item might move if
         * kmap schedules
         */
-       if (!p)
-               p = (char *)kmap(bh_result->b_page);
-
+       p = (char *)kmap(bh_result->b_page);
        p += offset;
        memset(p, 0, inode->i_sb->s_blocksize);
        do {
@@ -2664,7 +2656,7 @@ static int reiserfs_write_full_page(struct page *page,
        do {
                struct buffer_head *next = bh->b_this_page;
                if (buffer_async_write(bh)) {
-                       submit_bh(REQ_OP_WRITE, 0, bh);
+                       submit_bh(REQ_OP_WRITE, bh);
                        nr++;
                }
                put_bh(bh);
@@ -2724,7 +2716,7 @@ fail:
                struct buffer_head *next = bh->b_this_page;
                if (buffer_async_write(bh)) {
                        clear_buffer_dirty(bh);
-                       submit_bh(REQ_OP_WRITE, 0, bh);
+                       submit_bh(REQ_OP_WRITE, bh);
                        nr++;
                }
                put_bh(bh);
@@ -3284,7 +3276,7 @@ int reiserfs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
        /* must be turned off for recursive notify_change calls */
        ia_valid = attr->ia_valid &= ~(ATTR_KILL_SUID|ATTR_KILL_SGID);
 
-       if (is_quota_modification(inode, attr)) {
+       if (is_quota_modification(mnt_userns, inode, attr)) {
                error = dquot_initialize(inode);
                if (error)
                        return error;
@@ -3367,7 +3359,7 @@ int reiserfs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
                reiserfs_write_unlock(inode->i_sb);
                if (error)
                        goto out;
-               error = dquot_transfer(inode, attr);
+               error = dquot_transfer(mnt_userns, inode, attr);
                reiserfs_write_lock(inode->i_sb);
                if (error) {
                        journal_end(&th);
index d8cc9a3..94addfc 100644 (file)
@@ -650,7 +650,7 @@ static void submit_logged_buffer(struct buffer_head *bh)
                BUG();
        if (!buffer_uptodate(bh))
                BUG();
-       submit_bh(REQ_OP_WRITE, 0, bh);
+       submit_bh(REQ_OP_WRITE, bh);
 }
 
 static void submit_ordered_buffer(struct buffer_head *bh)
@@ -660,7 +660,7 @@ static void submit_ordered_buffer(struct buffer_head *bh)
        clear_buffer_dirty(bh);
        if (!buffer_uptodate(bh))
                BUG();
-       submit_bh(REQ_OP_WRITE, 0, bh);
+       submit_bh(REQ_OP_WRITE, bh);
 }
 
 #define CHUNK_SIZE 32
@@ -868,7 +868,7 @@ loop_next:
                 */
                if (buffer_dirty(bh) && unlikely(bh->b_page->mapping == NULL)) {
                        spin_unlock(lock);
-                       ll_rw_block(REQ_OP_WRITE, 0, 1, &bh);
+                       ll_rw_block(REQ_OP_WRITE, 1, &bh);
                        spin_lock(lock);
                }
                put_bh(bh);
@@ -1054,7 +1054,7 @@ static int flush_commit_list(struct super_block *s,
                if (tbh) {
                        if (buffer_dirty(tbh)) {
                            depth = reiserfs_write_unlock_nested(s);
-                           ll_rw_block(REQ_OP_WRITE, 0, 1, &tbh);
+                           ll_rw_block(REQ_OP_WRITE, 1, &tbh);
                            reiserfs_write_lock_nested(s, depth);
                        }
                        put_bh(tbh) ;
@@ -2240,7 +2240,7 @@ abort_replay:
                }
        }
        /* read in the log blocks, memcpy to the corresponding real block */
-       ll_rw_block(REQ_OP_READ, 0, get_desc_trans_len(desc), log_blocks);
+       ll_rw_block(REQ_OP_READ, get_desc_trans_len(desc), log_blocks);
        for (i = 0; i < get_desc_trans_len(desc); i++) {
 
                wait_on_buffer(log_blocks[i]);
@@ -2342,7 +2342,7 @@ static struct buffer_head *reiserfs_breada(struct block_device *dev,
                } else
                        bhlist[j++] = bh;
        }
-       ll_rw_block(REQ_OP_READ, 0, j, bhlist);
+       ll_rw_block(REQ_OP_READ, j, bhlist);
        for (i = 1; i < j; i++)
                brelse(bhlist[i]);
        bh = bhlist[0];
index ef42729..9a29360 100644 (file)
@@ -579,7 +579,7 @@ static int search_by_key_reada(struct super_block *s,
                if (!buffer_uptodate(bh[j])) {
                        if (depth == -1)
                                depth = reiserfs_write_unlock_nested(s);
-                       ll_rw_block(REQ_OP_READ, REQ_RAHEAD, 1, bh + j);
+                       ll_rw_block(REQ_OP_READ | REQ_RAHEAD, 1, bh + j);
                }
                brelse(bh[j]);
        }
@@ -685,7 +685,7 @@ int search_by_key(struct super_block *sb, const struct cpu_key *key,
                        if (!buffer_uptodate(bh) && depth == -1)
                                depth = reiserfs_write_unlock_nested(sb);
 
-                       ll_rw_block(REQ_OP_READ, 0, 1, &bh);
+                       ll_rw_block(REQ_OP_READ, 1, &bh);
                        wait_on_buffer(bh);
 
                        if (depth != -1)
index cfb7c44..c88cd2c 100644 (file)
@@ -1702,7 +1702,7 @@ static int read_super_block(struct super_block *s, int offset)
 /* after journal replay, reread all bitmap and super blocks */
 static int reread_meta_blocks(struct super_block *s)
 {
-       ll_rw_block(REQ_OP_READ, 0, 1, &SB_BUFFER_WITH_SB(s));
+       ll_rw_block(REQ_OP_READ, 1, &SB_BUFFER_WITH_SB(s));
        wait_on_buffer(SB_BUFFER_WITH_SB(s));
        if (!buffer_uptodate(SB_BUFFER_WITH_SB(s))) {
                reiserfs_warning(s, "reiserfs-2504", "error reading the super");
index f1a3795..046a513 100644 (file)
@@ -71,7 +71,8 @@ static int generic_remap_checks(struct file *file_in, loff_t pos_in,
         * Otherwise, make sure the count is also block-aligned, having
         * already confirmed the starting offsets' block alignment.
         */
-       if (pos_in + count == size_in) {
+       if (pos_in + count == size_in &&
+           (!(remap_flags & REMAP_FILE_DEDUP) || pos_out + count == size_out)) {
                bcount = ALIGN(size_in, bs) - pos_in;
        } else {
                if (!IS_ALIGNED(count, bs))
index 42e3e55..cad3772 100644 (file)
@@ -130,7 +130,7 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
                                        brelse(tmp);
                        }
                        if (num) {
-                               ll_rw_block(REQ_OP_READ, REQ_RAHEAD, num, bha);
+                               ll_rw_block(REQ_OP_READ | REQ_RAHEAD, num, bha);
                                for (i = 0; i < num; i++)
                                        brelse(bha[i]);
                        }
index 7372032..a2adf62 100644 (file)
@@ -89,7 +89,7 @@ struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t *nf_pos,
                                        brelse(tmp);
                        }
                        if (num) {
-                               ll_rw_block(REQ_OP_READ, REQ_RAHEAD, num, bha);
+                               ll_rw_block(REQ_OP_READ | REQ_RAHEAD, num, bha);
                                for (i = 0; i < num; i++)
                                        brelse(bha[i]);
                        }
index edc8871..8d06dae 100644 (file)
@@ -1214,7 +1214,7 @@ struct buffer_head *udf_bread(struct inode *inode, udf_pblk_t block,
        if (buffer_uptodate(bh))
                return bh;
 
-       ll_rw_block(REQ_OP_READ, 0, 1, &bh);
+       ll_rw_block(REQ_OP_READ, 1, &bh);
 
        wait_on_buffer(bh);
        if (buffer_uptodate(bh))
index 075d3d9..bd810d8 100644 (file)
@@ -296,7 +296,7 @@ static void ufs_change_blocknr(struct inode *inode, sector_t beg,
                        if (!buffer_mapped(bh))
                                        map_bh(bh, inode->i_sb, oldb + pos);
                        if (!buffer_uptodate(bh)) {
-                               ll_rw_block(REQ_OP_READ, 0, 1, &bh);
+                               ll_rw_block(REQ_OP_READ, 1, &bh);
                                wait_on_buffer(bh);
                                if (!buffer_uptodate(bh)) {
                                        ufs_error(inode->i_sb, __func__,
index e943370..de86f5b 100644 (file)
@@ -192,17 +192,19 @@ static inline void msg_init(struct uffd_msg *msg)
 }
 
 static inline struct uffd_msg userfault_msg(unsigned long address,
+                                           unsigned long real_address,
                                            unsigned int flags,
                                            unsigned long reason,
                                            unsigned int features)
 {
        struct uffd_msg msg;
+
        msg_init(&msg);
        msg.event = UFFD_EVENT_PAGEFAULT;
 
-       if (!(features & UFFD_FEATURE_EXACT_ADDRESS))
-               address &= PAGE_MASK;
-       msg.arg.pagefault.address = address;
+       msg.arg.pagefault.address = (features & UFFD_FEATURE_EXACT_ADDRESS) ?
+                                   real_address : address;
+
        /*
         * These flags indicate why the userfault occurred:
         * - UFFD_PAGEFAULT_FLAG_WP indicates a write protect fault.
@@ -488,8 +490,8 @@ vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason)
 
        init_waitqueue_func_entry(&uwq.wq, userfaultfd_wake_function);
        uwq.wq.private = current;
-       uwq.msg = userfault_msg(vmf->real_address, vmf->flags, reason,
-                       ctx->features);
+       uwq.msg = userfault_msg(vmf->address, vmf->real_address, vmf->flags,
+                               reason, ctx->features);
        uwq.ctx = ctx;
        uwq.waken = false;
 
index 54598cd..aad1f1d 100644 (file)
@@ -14,11 +14,11 @@ config FS_VERITY
        help
          This option enables fs-verity.  fs-verity is the dm-verity
          mechanism implemented at the file level.  On supported
-         filesystems (currently EXT4 and F2FS), userspace can use an
-         ioctl to enable verity for a file, which causes the filesystem
-         to build a Merkle tree for the file.  The filesystem will then
-         transparently verify any data read from the file against the
-         Merkle tree.  The file is also made read-only.
+         filesystems (currently ext4, f2fs, and btrfs), userspace can
+         use an ioctl to enable verity for a file, which causes the
+         filesystem to build a Merkle tree for the file.  The filesystem
+         will then transparently verify any data read from the file
+         against the Merkle tree.  The file is also made read-only.
 
          This serves as an integrity check, but the availability of the
          Merkle tree root hash also allows efficiently supporting
index e8dd03e..a1f4998 100644 (file)
@@ -282,9 +282,15 @@ out:
 }
 EXPORT_SYMBOL_GPL(__vfs_setxattr_locked);
 
+static inline bool is_posix_acl_xattr(const char *name)
+{
+       return (strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
+              (strcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT) == 0);
+}
+
 int
 vfs_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
-            const char *name, const void *value, size_t size, int flags)
+            const char *name, void *value, size_t size, int flags)
 {
        struct inode *inode = dentry->d_inode;
        struct inode *delegated_inode = NULL;
@@ -292,12 +298,16 @@ vfs_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
        int error;
 
        if (size && strcmp(name, XATTR_NAME_CAPS) == 0) {
-               error = cap_convert_nscap(mnt_userns, dentry, &value, size);
+               error = cap_convert_nscap(mnt_userns, dentry,
+                                         (const void **)&value, size);
                if (error < 0)
                        return error;
                size = error;
        }
 
+       if (size && is_posix_acl_xattr(name))
+               posix_acl_setxattr_idmapped_mnt(mnt_userns, inode, value, size);
+
 retry_deleg:
        inode_lock(inode);
        error = __vfs_setxattr_locked(mnt_userns, dentry, name, value, size,
@@ -431,7 +441,10 @@ vfs_getxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
                return ret;
        }
 nolsm:
-       return __vfs_getxattr(dentry, inode, name, value, size);
+       error = __vfs_getxattr(dentry, inode, name, value, size);
+       if (error > 0 && is_posix_acl_xattr(name))
+               posix_acl_getxattr_idmapped_mnt(mnt_userns, inode, value, size);
+       return error;
 }
 EXPORT_SYMBOL_GPL(vfs_getxattr);
 
@@ -577,8 +590,7 @@ static void setxattr_convert(struct user_namespace *mnt_userns,
        if (ctx->size &&
                ((strcmp(ctx->kname->name, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
                (strcmp(ctx->kname->name, XATTR_NAME_POSIX_ACL_DEFAULT) == 0)))
-               posix_acl_fix_xattr_from_user(mnt_userns, d_inode(d),
-                                               ctx->kvalue, ctx->size);
+               posix_acl_fix_xattr_from_user(ctx->kvalue, ctx->size);
 }
 
 int do_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
@@ -695,8 +707,7 @@ do_getxattr(struct user_namespace *mnt_userns, struct dentry *d,
        if (error > 0) {
                if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
                    (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
-                       posix_acl_fix_xattr_to_user(mnt_userns, d_inode(d),
-                                                       ctx->kvalue, error);
+                       posix_acl_fix_xattr_to_user(ctx->kvalue, error);
                if (ctx->size && copy_to_user(ctx->value, ctx->kvalue, error))
                        error = -EFAULT;
        } else if (error == -ERANGE && ctx->size >= XATTR_SIZE_MAX) {
index 1824f61..224649a 100644 (file)
@@ -50,7 +50,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
 STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
 STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
 STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp);
-STATIC int xfs_attr_leaf_try_add(struct xfs_da_args *args, struct xfs_buf *bp);
+STATIC int xfs_attr_leaf_try_add(struct xfs_da_args *args);
 
 /*
  * Internal routines when attribute list is more than one block.
@@ -393,16 +393,10 @@ xfs_attr_sf_addname(
         * It won't fit in the shortform, transform to a leaf block.  GROT:
         * another possible req'mt for a double-split btree op.
         */
-       error = xfs_attr_shortform_to_leaf(args, &attr->xattri_leaf_bp);
+       error = xfs_attr_shortform_to_leaf(args);
        if (error)
                return error;
 
-       /*
-        * Prevent the leaf buffer from being unlocked so that a concurrent AIL
-        * push cannot grab the half-baked leaf buffer and run into problems
-        * with the write verifier.
-        */
-       xfs_trans_bhold(args->trans, attr->xattri_leaf_bp);
        attr->xattri_dela_state = XFS_DAS_LEAF_ADD;
 out:
        trace_xfs_attr_sf_addname_return(attr->xattri_dela_state, args->dp);
@@ -447,11 +441,9 @@ xfs_attr_leaf_addname(
 
        /*
         * Use the leaf buffer we may already hold locked as a result of
-        * a sf-to-leaf conversion. The held buffer is no longer valid
-        * after this call, regardless of the result.
+        * a sf-to-leaf conversion.
         */
-       error = xfs_attr_leaf_try_add(args, attr->xattri_leaf_bp);
-       attr->xattri_leaf_bp = NULL;
+       error = xfs_attr_leaf_try_add(args);
 
        if (error == -ENOSPC) {
                error = xfs_attr3_leaf_to_node(args);
@@ -497,8 +489,6 @@ xfs_attr_node_addname(
        struct xfs_da_args      *args = attr->xattri_da_args;
        int                     error;
 
-       ASSERT(!attr->xattri_leaf_bp);
-
        error = xfs_attr_node_addname_find_attr(attr);
        if (error)
                return error;
@@ -1215,24 +1205,14 @@ xfs_attr_restore_rmt_blk(
  */
 STATIC int
 xfs_attr_leaf_try_add(
-       struct xfs_da_args      *args,
-       struct xfs_buf          *bp)
+       struct xfs_da_args      *args)
 {
+       struct xfs_buf          *bp;
        int                     error;
 
-       /*
-        * If the caller provided a buffer to us, it is locked and held in
-        * the transaction because it just did a shortform to leaf conversion.
-        * Hence we don't need to read it again. Otherwise read in the leaf
-        * buffer.
-        */
-       if (bp) {
-               xfs_trans_bhold_release(args->trans, bp);
-       } else {
-               error = xfs_attr3_leaf_read(args->trans, args->dp, 0, &bp);
-               if (error)
-                       return error;
-       }
+       error = xfs_attr3_leaf_read(args->trans, args->dp, 0, &bp);
+       if (error)
+               return error;
 
        /*
         * Look up the xattr name to set the insertion point for the new xattr.
index b4a2fc7..dfb47fa 100644 (file)
@@ -515,11 +515,6 @@ struct xfs_attr_intent {
         */
        struct xfs_attri_log_nameval    *xattri_nameval;
 
-       /*
-        * Used by xfs_attr_set to hold a leaf buffer across a transaction roll
-        */
-       struct xfs_buf                  *xattri_leaf_bp;
-
        /* Used to keep track of current state of delayed operation */
        enum xfs_delattr_state          xattri_dela_state;
 
index 37e7c33..8f47396 100644 (file)
@@ -289,6 +289,23 @@ xfs_attr3_leaf_verify_entry(
        return NULL;
 }
 
+/*
+ * Validate an attribute leaf block.
+ *
+ * Empty leaf blocks can occur under the following circumstances:
+ *
+ * 1. setxattr adds a new extended attribute to a file;
+ * 2. The file has zero existing attributes;
+ * 3. The attribute is too large to fit in the attribute fork;
+ * 4. The attribute is small enough to fit in a leaf block;
+ * 5. A log flush occurs after committing the transaction that creates
+ *    the (empty) leaf block; and
+ * 6. The filesystem goes down after the log flush but before the new
+ *    attribute can be committed to the leaf block.
+ *
+ * Hence we need to ensure that we don't fail the validation purely
+ * because the leaf is empty.
+ */
 static xfs_failaddr_t
 xfs_attr3_leaf_verify(
        struct xfs_buf                  *bp)
@@ -311,15 +328,6 @@ xfs_attr3_leaf_verify(
                return fa;
 
        /*
-        * Empty leaf blocks should never occur;  they imply the existence of a
-        * software bug that needs fixing. xfs_repair also flags them as a
-        * corruption that needs fixing, so we should never let these go to
-        * disk.
-        */
-       if (ichdr.count == 0)
-               return __this_address;
-
-       /*
         * firstused is the block offset of the first name info structure.
         * Make sure it doesn't go off the block or crash into the header.
         */
@@ -922,14 +930,10 @@ xfs_attr_shortform_getvalue(
        return -ENOATTR;
 }
 
-/*
- * Convert from using the shortform to the leaf.  On success, return the
- * buffer so that we can keep it locked until we're totally done with it.
- */
+/* Convert from using the shortform to the leaf format. */
 int
 xfs_attr_shortform_to_leaf(
-       struct xfs_da_args              *args,
-       struct xfs_buf                  **leaf_bp)
+       struct xfs_da_args              *args)
 {
        struct xfs_inode                *dp;
        struct xfs_attr_shortform       *sf;
@@ -991,7 +995,6 @@ xfs_attr_shortform_to_leaf(
                sfe = xfs_attr_sf_nextentry(sfe);
        }
        error = 0;
-       *leaf_bp = bp;
 out:
        kmem_free(tmpbuffer);
        return error;
index efa757f..368f4d9 100644 (file)
@@ -49,8 +49,7 @@ void  xfs_attr_shortform_create(struct xfs_da_args *args);
 void   xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff);
 int    xfs_attr_shortform_lookup(struct xfs_da_args *args);
 int    xfs_attr_shortform_getvalue(struct xfs_da_args *args);
-int    xfs_attr_shortform_to_leaf(struct xfs_da_args *args,
-                       struct xfs_buf **leaf_bp);
+int    xfs_attr_shortform_to_leaf(struct xfs_da_args *args);
 int    xfs_attr_sf_removename(struct xfs_da_args *args);
 int    xfs_attr_sf_findname(struct xfs_da_args *args,
                             struct xfs_attr_sf_entry **sfep,
index 135d441..5077a7a 100644 (file)
@@ -576,7 +576,7 @@ xfs_attri_item_recover(
        struct xfs_trans_res            tres;
        struct xfs_attri_log_format     *attrp;
        struct xfs_attri_log_nameval    *nv = attrip->attri_nameval;
-       int                             error, ret = 0;
+       int                             error;
        int                             total;
        int                             local;
        struct xfs_attrd_log_item       *done_item = NULL;
@@ -655,29 +655,32 @@ xfs_attri_item_recover(
        xfs_ilock(ip, XFS_ILOCK_EXCL);
        xfs_trans_ijoin(tp, ip, 0);
 
-       ret = xfs_xattri_finish_update(attr, done_item);
-       if (ret == -EAGAIN) {
-               /* There's more work to do, so add it to this transaction */
+       error = xfs_xattri_finish_update(attr, done_item);
+       if (error == -EAGAIN) {
+               /*
+                * There's more work to do, so add the intent item to this
+                * transaction so that we can continue it later.
+                */
                xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_ATTR, &attr->xattri_list);
-       } else
-               error = ret;
+               error = xfs_defer_ops_capture_and_commit(tp, capture_list);
+               if (error)
+                       goto out_unlock;
 
+               xfs_iunlock(ip, XFS_ILOCK_EXCL);
+               xfs_irele(ip);
+               return 0;
+       }
        if (error) {
                xfs_trans_cancel(tp);
                goto out_unlock;
        }
 
        error = xfs_defer_ops_capture_and_commit(tp, capture_list);
-
 out_unlock:
-       if (attr->xattri_leaf_bp)
-               xfs_buf_relse(attr->xattri_leaf_bp);
-
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
        xfs_irele(ip);
 out:
-       if (ret != -EAGAIN)
-               xfs_attr_free_item(attr);
+       xfs_attr_free_item(attr);
        return error;
 }
 
index ae4345b..fe21c76 100644 (file)
@@ -15,7 +15,7 @@ xfs_rw_bdev(
        sector_t                sector,
        unsigned int            count,
        char                    *data,
-       unsigned int            op)
+       enum req_op             op)
 
 {
        unsigned int            is_vmalloc = is_vmalloc_addr(data);
index 52be583..85e1a26 100644 (file)
@@ -686,6 +686,8 @@ xfs_can_free_eofblocks(
         * forever.
         */
        end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_ISIZE(ip));
+       if (XFS_IS_REALTIME_INODE(ip) && mp->m_sb.sb_rextsize > 1)
+               end_fsb = roundup_64(end_fsb, mp->m_sb.sb_rextsize);
        last_fsb = XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes);
        if (last_fsb <= end_fsb)
                return false;
index bf4e608..5e8f40d 100644 (file)
@@ -1416,7 +1416,7 @@ xfs_buf_ioapply_map(
        int             map,
        int             *buf_offset,
        int             *count,
-       int             op)
+       blk_opf_t       op)
 {
        int             page_index;
        unsigned int    total_nr_pages = bp->b_page_count;
@@ -1493,7 +1493,7 @@ _xfs_buf_ioapply(
        struct xfs_buf  *bp)
 {
        struct blk_plug plug;
-       int             op;
+       blk_opf_t       op;
        int             offset;
        int             size;
        int             i;
index 5a171c0..8d9b14d 100644 (file)
@@ -410,7 +410,7 @@ restart:
                spin_unlock(&ip->i_flags_lock);
 
 out:
-       return file_modified(file);
+       return kiocb_modified(iocb);
 }
 
 static int
@@ -700,12 +700,11 @@ xfs_file_buffered_write(
        bool                    cleared_space = false;
        unsigned int            iolock;
 
-       if (iocb->ki_flags & IOCB_NOWAIT)
-               return -EOPNOTSUPP;
-
 write_retry:
        iolock = XFS_IOLOCK_EXCL;
-       xfs_ilock(ip, iolock);
+       ret = xfs_ilock_iocb(iocb, iolock);
+       if (ret)
+               return ret;
 
        ret = xfs_file_write_checks(iocb, from, &iolock);
        if (ret)
@@ -1165,7 +1164,7 @@ xfs_file_open(
 {
        if (xfs_is_shutdown(XFS_M(inode->i_sb)))
                return -EIO;
-       file->f_mode |= FMODE_NOWAIT | FMODE_BUF_RASYNC;
+       file->f_mode |= FMODE_NOWAIT | FMODE_BUF_RASYNC | FMODE_BUF_WASYNC;
        return generic_file_open(inode, file);
 }
 
index 5269354..2609825 100644 (file)
@@ -440,7 +440,7 @@ xfs_inodegc_queue_all(
        for_each_online_cpu(cpu) {
                gc = per_cpu_ptr(mp->m_inodegc, cpu);
                if (!llist_empty(&gc->list))
-                       queue_work_on(cpu, mp->m_inodegc_wq, &gc->work);
+                       mod_delayed_work_on(cpu, mp->m_inodegc_wq, &gc->work, 0);
        }
 }
 
@@ -1841,8 +1841,8 @@ void
 xfs_inodegc_worker(
        struct work_struct      *work)
 {
-       struct xfs_inodegc      *gc = container_of(work, struct xfs_inodegc,
-                                                       work);
+       struct xfs_inodegc      *gc = container_of(to_delayed_work(work),
+                                               struct xfs_inodegc, work);
        struct llist_node       *node = llist_del_all(&gc->list);
        struct xfs_inode        *ip, *n;
 
@@ -1862,19 +1862,29 @@ xfs_inodegc_worker(
 }
 
 /*
- * Force all currently queued inode inactivation work to run immediately and
- * wait for the work to finish.
+ * Expedite all pending inodegc work to run immediately. This does not wait for
+ * completion of the work.
  */
 void
-xfs_inodegc_flush(
+xfs_inodegc_push(
        struct xfs_mount        *mp)
 {
        if (!xfs_is_inodegc_enabled(mp))
                return;
+       trace_xfs_inodegc_push(mp, __return_address);
+       xfs_inodegc_queue_all(mp);
+}
 
+/*
+ * Force all currently queued inode inactivation work to run immediately and
+ * wait for the work to finish.
+ */
+void
+xfs_inodegc_flush(
+       struct xfs_mount        *mp)
+{
+       xfs_inodegc_push(mp);
        trace_xfs_inodegc_flush(mp, __return_address);
-
-       xfs_inodegc_queue_all(mp);
        flush_workqueue(mp->m_inodegc_wq);
 }
 
@@ -2014,6 +2024,7 @@ xfs_inodegc_queue(
        struct xfs_inodegc      *gc;
        int                     items;
        unsigned int            shrinker_hits;
+       unsigned long           queue_delay = 1;
 
        trace_xfs_inode_set_need_inactive(ip);
        spin_lock(&ip->i_flags_lock);
@@ -2025,19 +2036,26 @@ xfs_inodegc_queue(
        items = READ_ONCE(gc->items);
        WRITE_ONCE(gc->items, items + 1);
        shrinker_hits = READ_ONCE(gc->shrinker_hits);
-       put_cpu_ptr(gc);
 
-       if (!xfs_is_inodegc_enabled(mp))
+       /*
+        * We queue the work while holding the current CPU so that the work
+        * is scheduled to run on this CPU.
+        */
+       if (!xfs_is_inodegc_enabled(mp)) {
+               put_cpu_ptr(gc);
                return;
-
-       if (xfs_inodegc_want_queue_work(ip, items)) {
-               trace_xfs_inodegc_queue(mp, __return_address);
-               queue_work(mp->m_inodegc_wq, &gc->work);
        }
 
+       if (xfs_inodegc_want_queue_work(ip, items))
+               queue_delay = 0;
+
+       trace_xfs_inodegc_queue(mp, __return_address);
+       mod_delayed_work(mp->m_inodegc_wq, &gc->work, queue_delay);
+       put_cpu_ptr(gc);
+
        if (xfs_inodegc_want_flush_work(ip, items, shrinker_hits)) {
                trace_xfs_inodegc_throttle(mp, __return_address);
-               flush_work(&gc->work);
+               flush_delayed_work(&gc->work);
        }
 }
 
@@ -2054,7 +2072,7 @@ xfs_inodegc_cpu_dead(
        unsigned int            count = 0;
 
        dead_gc = per_cpu_ptr(mp->m_inodegc, dead_cpu);
-       cancel_work_sync(&dead_gc->work);
+       cancel_delayed_work_sync(&dead_gc->work);
 
        if (llist_empty(&dead_gc->list))
                return;
@@ -2073,12 +2091,12 @@ xfs_inodegc_cpu_dead(
        llist_add_batch(first, last, &gc->list);
        count += READ_ONCE(gc->items);
        WRITE_ONCE(gc->items, count);
-       put_cpu_ptr(gc);
 
        if (xfs_is_inodegc_enabled(mp)) {
                trace_xfs_inodegc_queue(mp, __return_address);
-               queue_work(mp->m_inodegc_wq, &gc->work);
+               mod_delayed_work(mp->m_inodegc_wq, &gc->work, 0);
        }
+       put_cpu_ptr(gc);
 }
 
 /*
@@ -2173,7 +2191,7 @@ xfs_inodegc_shrinker_scan(
                        unsigned int    h = READ_ONCE(gc->shrinker_hits);
 
                        WRITE_ONCE(gc->shrinker_hits, h + 1);
-                       queue_work_on(cpu, mp->m_inodegc_wq, &gc->work);
+                       mod_delayed_work_on(cpu, mp->m_inodegc_wq, &gc->work, 0);
                        no_items = false;
                }
        }
index 2e4cfdd..6cd1807 100644 (file)
@@ -76,6 +76,7 @@ void xfs_blockgc_stop(struct xfs_mount *mp);
 void xfs_blockgc_start(struct xfs_mount *mp);
 
 void xfs_inodegc_worker(struct work_struct *work);
+void xfs_inodegc_push(struct xfs_mount *mp);
 void xfs_inodegc_flush(struct xfs_mount *mp);
 void xfs_inodegc_stop(struct xfs_mount *mp);
 void xfs_inodegc_start(struct xfs_mount *mp);
index 52d6f2c..3e1c62f 100644 (file)
@@ -132,6 +132,26 @@ xfs_ilock_attr_map_shared(
 }
 
 /*
+ * You can't set both SHARED and EXCL for the same lock,
+ * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_MMAPLOCK_SHARED,
+ * XFS_MMAPLOCK_EXCL, XFS_ILOCK_SHARED, XFS_ILOCK_EXCL are valid values
+ * to set in lock_flags.
+ */
+static inline void
+xfs_lock_flags_assert(
+       uint            lock_flags)
+{
+       ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) !=
+               (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
+       ASSERT((lock_flags & (XFS_MMAPLOCK_SHARED | XFS_MMAPLOCK_EXCL)) !=
+               (XFS_MMAPLOCK_SHARED | XFS_MMAPLOCK_EXCL));
+       ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) !=
+               (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
+       ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_SUBCLASS_MASK)) == 0);
+       ASSERT(lock_flags != 0);
+}
+
+/*
  * In addition to i_rwsem in the VFS inode, the xfs inode contains 2
  * multi-reader locks: invalidate_lock and the i_lock.  This routine allows
  * various combinations of the locks to be obtained.
@@ -168,18 +188,7 @@ xfs_ilock(
 {
        trace_xfs_ilock(ip, lock_flags, _RET_IP_);
 
-       /*
-        * You can't set both SHARED and EXCL for the same lock,
-        * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED,
-        * and XFS_ILOCK_EXCL are valid values to set in lock_flags.
-        */
-       ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) !=
-              (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
-       ASSERT((lock_flags & (XFS_MMAPLOCK_SHARED | XFS_MMAPLOCK_EXCL)) !=
-              (XFS_MMAPLOCK_SHARED | XFS_MMAPLOCK_EXCL));
-       ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) !=
-              (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
-       ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_SUBCLASS_MASK)) == 0);
+       xfs_lock_flags_assert(lock_flags);
 
        if (lock_flags & XFS_IOLOCK_EXCL) {
                down_write_nested(&VFS_I(ip)->i_rwsem,
@@ -222,18 +231,7 @@ xfs_ilock_nowait(
 {
        trace_xfs_ilock_nowait(ip, lock_flags, _RET_IP_);
 
-       /*
-        * You can't set both SHARED and EXCL for the same lock,
-        * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED,
-        * and XFS_ILOCK_EXCL are valid values to set in lock_flags.
-        */
-       ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) !=
-              (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
-       ASSERT((lock_flags & (XFS_MMAPLOCK_SHARED | XFS_MMAPLOCK_EXCL)) !=
-              (XFS_MMAPLOCK_SHARED | XFS_MMAPLOCK_EXCL));
-       ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) !=
-              (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
-       ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_SUBCLASS_MASK)) == 0);
+       xfs_lock_flags_assert(lock_flags);
 
        if (lock_flags & XFS_IOLOCK_EXCL) {
                if (!down_write_trylock(&VFS_I(ip)->i_rwsem))
@@ -291,19 +289,7 @@ xfs_iunlock(
        xfs_inode_t             *ip,
        uint                    lock_flags)
 {
-       /*
-        * You can't set both SHARED and EXCL for the same lock,
-        * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED,
-        * and XFS_ILOCK_EXCL are valid values to set in lock_flags.
-        */
-       ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) !=
-              (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
-       ASSERT((lock_flags & (XFS_MMAPLOCK_SHARED | XFS_MMAPLOCK_EXCL)) !=
-              (XFS_MMAPLOCK_SHARED | XFS_MMAPLOCK_EXCL));
-       ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) !=
-              (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
-       ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_SUBCLASS_MASK)) == 0);
-       ASSERT(lock_flags != 0);
+       xfs_lock_flags_assert(lock_flags);
 
        if (lock_flags & XFS_IOLOCK_EXCL)
                up_write(&VFS_I(ip)->i_rwsem);
@@ -379,8 +365,8 @@ xfs_isilocked(
        }
 
        if (lock_flags & (XFS_MMAPLOCK_EXCL|XFS_MMAPLOCK_SHARED)) {
-               return __xfs_rwsem_islocked(&VFS_I(ip)->i_rwsem,
-                               (lock_flags & XFS_IOLOCK_SHARED));
+               return __xfs_rwsem_islocked(&VFS_I(ip)->i_mapping->invalidate_lock,
+                               (lock_flags & XFS_MMAPLOCK_SHARED));
        }
 
        if (lock_flags & (XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED)) {
index 5a39325..5d50fed 100644 (file)
@@ -664,7 +664,7 @@ xfs_ilock_for_iomap(
        unsigned                flags,
        unsigned                *lockmode)
 {
-       unsigned                mode = XFS_ILOCK_SHARED;
+       unsigned int            mode = *lockmode;
        bool                    is_write = flags & (IOMAP_WRITE | IOMAP_ZERO);
 
        /*
@@ -742,7 +742,7 @@ xfs_direct_write_iomap_begin(
        int                     nimaps = 1, error = 0;
        bool                    shared = false;
        u16                     iomap_flags = 0;
-       unsigned                lockmode;
+       unsigned int            lockmode = XFS_ILOCK_SHARED;
 
        ASSERT(flags & (IOMAP_WRITE | IOMAP_ZERO));
 
@@ -886,6 +886,7 @@ xfs_buffered_write_iomap_begin(
        bool                    eof = false, cow_eof = false, shared = false;
        int                     allocfork = XFS_DATA_FORK;
        int                     error = 0;
+       unsigned int            lockmode = XFS_ILOCK_EXCL;
 
        if (xfs_is_shutdown(mp))
                return -EIO;
@@ -897,7 +898,9 @@ xfs_buffered_write_iomap_begin(
 
        ASSERT(!XFS_IS_REALTIME_INODE(ip));
 
-       xfs_ilock(ip, XFS_ILOCK_EXCL);
+       error = xfs_ilock_for_iomap(ip, flags, &lockmode);
+       if (error)
+               return error;
 
        if (XFS_IS_CORRUPT(mp, !xfs_ifork_has_extents(&ip->i_df)) ||
            XFS_TEST_ERROR(false, mp, XFS_ERRTAG_BMAPIFORMAT)) {
@@ -1172,7 +1175,7 @@ xfs_read_iomap_begin(
        xfs_fileoff_t           end_fsb = xfs_iomap_end_fsb(mp, offset, length);
        int                     nimaps = 1, error = 0;
        bool                    shared = false;
-       unsigned                lockmode;
+       unsigned int            lockmode = XFS_ILOCK_SHARED;
 
        ASSERT(!(flags & (IOMAP_WRITE | IOMAP_ZERO)));
 
index 29f5b8b..a7402f6 100644 (file)
@@ -667,13 +667,15 @@ xfs_setattr_nonsize(
                uint    qflags = 0;
 
                if ((mask & ATTR_UID) && XFS_IS_UQUOTA_ON(mp)) {
-                       uid = iattr->ia_uid;
+                       uid = from_vfsuid(mnt_userns, i_user_ns(inode),
+                                         iattr->ia_vfsuid);
                        qflags |= XFS_QMOPT_UQUOTA;
                } else {
                        uid = inode->i_uid;
                }
                if ((mask & ATTR_GID) && XFS_IS_GQUOTA_ON(mp)) {
-                       gid = iattr->ia_gid;
+                       gid = from_vfsgid(mnt_userns, i_user_ns(inode),
+                                         iattr->ia_vfsgid);
                        qflags |= XFS_QMOPT_GQUOTA;
                }  else {
                        gid = inode->i_gid;
@@ -704,13 +706,13 @@ xfs_setattr_nonsize(
         * didn't have the inode locked, inode's dquot(s) would have changed
         * also.
         */
-       if ((mask & ATTR_UID) && XFS_IS_UQUOTA_ON(mp) &&
-           !uid_eq(inode->i_uid, iattr->ia_uid)) {
+       if (XFS_IS_UQUOTA_ON(mp) &&
+           i_uid_needs_update(mnt_userns, iattr, inode)) {
                ASSERT(udqp);
                old_udqp = xfs_qm_vop_chown(tp, ip, &ip->i_udquot, udqp);
        }
-       if ((mask & ATTR_GID) && XFS_IS_GQUOTA_ON(mp) &&
-           !gid_eq(inode->i_gid, iattr->ia_gid)) {
+       if (XFS_IS_GQUOTA_ON(mp) &&
+           i_gid_needs_update(mnt_userns, iattr, inode)) {
                ASSERT(xfs_has_pquotino(mp) || !XFS_IS_PQUOTA_ON(mp));
                ASSERT(gdqp);
                old_gdqp = xfs_qm_vop_chown(tp, ip, &ip->i_gdquot, gdqp);
index cb9105d..f987802 100644 (file)
@@ -196,7 +196,7 @@ static inline uint64_t howmany_64(uint64_t x, uint32_t y)
 }
 
 int xfs_rw_bdev(struct block_device *bdev, sector_t sector, unsigned int count,
-               char *data, unsigned int op);
+               char *data, enum req_op op);
 
 #define ASSERT_ALWAYS(expr)    \
        (likely(expr) ? (void)0 : assfail(NULL, #expr, __FILE__, __LINE__))
index 1e972f8..ae904b2 100644 (file)
@@ -2092,8 +2092,6 @@ xlog_dealloc_log(
        xlog_in_core_t  *iclog, *next_iclog;
        int             i;
 
-       xlog_cil_destroy(log);
-
        /*
         * Cycle all the iclogbuf locks to make sure all log IO completion
         * is done before we tear down these buffers.
@@ -2105,6 +2103,13 @@ xlog_dealloc_log(
                iclog = iclog->ic_next;
        }
 
+       /*
+        * Destroy the CIL after waiting for iclog IO completion because an
+        * iclog EIO error will try to shut down the log, which accesses the
+        * CIL to wake up the waiters.
+        */
+       xlog_cil_destroy(log);
+
        iclog = log->l_iclog;
        for (i = 0; i < log->l_iclog_bufs; i++) {
                next_iclog = iclog->ic_next;
index 5f7e4e6..940c810 100644 (file)
@@ -122,7 +122,7 @@ xlog_do_io(
        xfs_daddr_t             blk_no,
        unsigned int            nbblks,
        char                    *data,
-       unsigned int            op)
+       enum req_op             op)
 {
        int                     error;
 
index ba5d42a..d2eaebd 100644 (file)
@@ -61,7 +61,7 @@ struct xfs_error_cfg {
  */
 struct xfs_inodegc {
        struct llist_head       list;
-       struct work_struct      work;
+       struct delayed_work     work;
 
        /* approximate count of inodes in the list */
        unsigned int            items;
index 74ac9ca..392cb39 100644 (file)
@@ -454,9 +454,12 @@ xfs_qm_scall_getquota(
        struct xfs_dquot        *dqp;
        int                     error;
 
-       /* Flush inodegc work at the start of a quota reporting scan. */
+       /*
+        * Expedite pending inodegc work at the start of a quota reporting
+        * scan but don't block waiting for it to complete.
+        */
        if (id == 0)
-               xfs_inodegc_flush(mp);
+               xfs_inodegc_push(mp);
 
        /*
         * Try to get the dquot. We don't want it allocated on disk, so don't
@@ -498,7 +501,7 @@ xfs_qm_scall_getquota_next(
 
        /* Flush inodegc work at the start of a quota reporting scan. */
        if (*id == 0)
-               xfs_inodegc_flush(mp);
+               xfs_inodegc_push(mp);
 
        error = xfs_qm_dqget_next(mp, *id, type, &dqp);
        if (error)
index ed18160..aa977c7 100644 (file)
@@ -797,8 +797,11 @@ xfs_fs_statfs(
        xfs_extlen_t            lsize;
        int64_t                 ffree;
 
-       /* Wait for whatever inactivations are in progress. */
-       xfs_inodegc_flush(mp);
+       /*
+        * Expedite background inodegc but don't wait. We do not want to block
+        * here waiting hours for a billion extent file to be truncated.
+        */
+       xfs_inodegc_push(mp);
 
        statp->f_type = XFS_SUPER_MAGIC;
        statp->f_namelen = MAXNAMELEN - 1;
@@ -1074,7 +1077,7 @@ xfs_inodegc_init_percpu(
                gc = per_cpu_ptr(mp->m_inodegc, cpu);
                init_llist_head(&gc->list);
                gc->items = 0;
-               INIT_WORK(&gc->work, xfs_inodegc_worker);
+               INIT_DELAYED_WORK(&gc->work, xfs_inodegc_worker);
        }
        return 0;
 }
index d320265..0fa1b7a 100644 (file)
@@ -240,6 +240,7 @@ DEFINE_EVENT(xfs_fs_class, name,                                    \
        TP_PROTO(struct xfs_mount *mp, void *caller_ip), \
        TP_ARGS(mp, caller_ip))
 DEFINE_FS_EVENT(xfs_inodegc_flush);
+DEFINE_FS_EVENT(xfs_inodegc_push);
 DEFINE_FS_EVENT(xfs_inodegc_start);
 DEFINE_FS_EVENT(xfs_inodegc_stop);
 DEFINE_FS_EVENT(xfs_inodegc_queue);
index cc6d4cf..c5fa8ad 100644 (file)
@@ -60,8 +60,7 @@ static void zonefs_account_active(struct inode *inode)
        }
 }
 
-static inline int zonefs_zone_mgmt(struct inode *inode,
-                                  enum req_opf op)
+static inline int zonefs_zone_mgmt(struct inode *inode, enum req_op op)
 {
        struct zonefs_inode_info *zi = ZONEFS_I(inode);
        int ret;
@@ -525,7 +524,7 @@ static int zonefs_file_truncate(struct inode *inode, loff_t isize)
 {
        struct zonefs_inode_info *zi = ZONEFS_I(inode);
        loff_t old_isize;
-       enum req_opf op;
+       enum req_op op;
        int ret = 0;
 
        /*
@@ -616,7 +615,7 @@ static int zonefs_inode_setattr(struct user_namespace *mnt_userns,
             !uid_eq(iattr->ia_uid, inode->i_uid)) ||
            ((iattr->ia_valid & ATTR_GID) &&
             !gid_eq(iattr->ia_gid, inode->i_gid))) {
-               ret = dquot_transfer(inode, iattr);
+               ret = dquot_transfer(mnt_userns, inode, iattr);
                if (ret)
                        return ret;
        }
@@ -1394,7 +1393,7 @@ static void zonefs_init_dir_inode(struct inode *parent, struct inode *inode,
 {
        struct super_block *sb = parent->i_sb;
 
-       inode->i_ino = blkdev_nr_zones(sb->s_bdev->bd_disk) + type + 1;
+       inode->i_ino = bdev_nr_zones(sb->s_bdev) + type + 1;
        inode_init_owner(&init_user_ns, inode, parent, S_IFDIR | 0555);
        inode->i_op = &zonefs_dir_inode_operations;
        inode->i_fop = &simple_dir_operations;
@@ -1540,7 +1539,7 @@ static int zonefs_create_zgroup(struct zonefs_zone_data *zd,
        /*
         * The first zone contains the super block: skip it.
         */
-       end = zd->zones + blkdev_nr_zones(sb->s_bdev->bd_disk);
+       end = zd->zones + bdev_nr_zones(sb->s_bdev);
        for (zone = &zd->zones[1]; zone < end; zone = next) {
 
                next = zone + 1;
@@ -1635,8 +1634,8 @@ static int zonefs_get_zone_info(struct zonefs_zone_data *zd)
        struct block_device *bdev = zd->sb->s_bdev;
        int ret;
 
-       zd->zones = kvcalloc(blkdev_nr_zones(bdev->bd_disk),
-                            sizeof(struct blk_zone), GFP_KERNEL);
+       zd->zones = kvcalloc(bdev_nr_zones(bdev), sizeof(struct blk_zone),
+                            GFP_KERNEL);
        if (!zd->zones)
                return -ENOMEM;
 
@@ -1648,9 +1647,9 @@ static int zonefs_get_zone_info(struct zonefs_zone_data *zd)
                return ret;
        }
 
-       if (ret != blkdev_nr_zones(bdev->bd_disk)) {
+       if (ret != bdev_nr_zones(bdev)) {
                zonefs_err(zd->sb, "Invalid zone report (%d/%u zones)\n",
-                          ret, blkdev_nr_zones(bdev->bd_disk));
+                          ret, bdev_nr_zones(bdev));
                return -EIO;
        }
 
@@ -1816,8 +1815,7 @@ static int zonefs_fill_super(struct super_block *sb, void *data, int silent)
        if (ret)
                goto cleanup;
 
-       zonefs_info(sb, "Mounting %u zones",
-                   blkdev_nr_zones(sb->s_bdev->bd_disk));
+       zonefs_info(sb, "Mounting %u zones", bdev_nr_zones(sb->s_bdev));
 
        if (!sbi->s_max_wro_seq_files &&
            !sbi->s_max_active_seq_files &&
@@ -1833,7 +1831,7 @@ static int zonefs_fill_super(struct super_block *sb, void *data, int silent)
        if (!inode)
                goto cleanup;
 
-       inode->i_ino = blkdev_nr_zones(sb->s_bdev->bd_disk);
+       inode->i_ino = bdev_nr_zones(sb->s_bdev);
        inode->i_mode = S_IFDIR | 0555;
        inode->i_ctime = inode->i_mtime = inode->i_atime = current_time(inode);
        inode->i_op = &zonefs_dir_inode_operations;
index f369d7d..42edcfd 100644 (file)
 #define show_dev(dev) MAJOR(dev), MINOR(dev)
 
 TRACE_EVENT(zonefs_zone_mgmt,
-           TP_PROTO(struct inode *inode, enum req_opf op),
+           TP_PROTO(struct inode *inode, enum req_op op),
            TP_ARGS(inode, op),
            TP_STRUCT__entry(
                             __field(dev_t, dev)
                             __field(ino_t, ino)
-                            __field(int, op)
+                            __field(enum req_op, op)
                             __field(sector_t, sector)
                             __field(sector_t, nr_sectors)
            ),
index 0dc1ea0..48f0fd4 100644 (file)
@@ -365,8 +365,6 @@ struct acpi_device {
        acpi_handle handle;             /* no handle for fixed hardware */
        struct fwnode_handle fwnode;
        struct acpi_device *parent;
-       struct list_head children;
-       struct list_head node;
        struct list_head wakeup_list;
        struct list_head del_list;
        struct acpi_device_status status;
@@ -379,7 +377,6 @@ struct acpi_device {
        struct acpi_device_data data;
        struct acpi_scan_handler *handler;
        struct acpi_hotplug_context *hp;
-       struct acpi_driver *driver;
        const struct acpi_gpio_mapping *driver_gpios;
        void *driver_data;
        struct device dev;
@@ -483,6 +480,9 @@ extern struct bus_type acpi_bus_type;
 int acpi_bus_for_each_dev(int (*fn)(struct device *, void *), void *data);
 int acpi_dev_for_each_child(struct acpi_device *adev,
                            int (*fn)(struct acpi_device *, void *), void *data);
+int acpi_dev_for_each_child_reverse(struct acpi_device *adev,
+                                   int (*fn)(struct acpi_device *, void *),
+                                   void *data);
 
 /*
  * Events
@@ -521,6 +521,7 @@ const char *acpi_power_state_string(int state);
 int acpi_device_set_power(struct acpi_device *device, int state);
 int acpi_bus_init_power(struct acpi_device *device);
 int acpi_device_fix_up_power(struct acpi_device *device);
+void acpi_device_fix_up_power_extended(struct acpi_device *adev);
 int acpi_bus_update_power(acpi_handle handle, int *state_p);
 int acpi_device_update_power(struct acpi_device *device, int *state_p);
 bool acpi_bus_power_manageable(acpi_handle handle);
@@ -622,6 +623,8 @@ static inline int acpi_dma_configure(struct device *dev,
 }
 struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
                                           u64 address, bool check_children);
+struct acpi_device *acpi_find_child_by_adr(struct acpi_device *adev,
+                                          acpi_bus_address adr);
 int acpi_is_root_bridge(acpi_handle);
 struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle);
 
index c610858..f73d357 100644 (file)
@@ -17,7 +17,7 @@
 #include <acpi/pcc.h>
 #include <acpi/processor.h>
 
-/* Support CPPCv2 and CPPCv3  */
+/* CPPCv2 and CPPCv3 support */
 #define CPPC_V2_REV    2
 #define CPPC_V3_REV    3
 #define CPPC_V2_NUM_ENT        21
@@ -145,6 +145,7 @@ extern bool cppc_allow_fast_switch(void);
 extern int acpi_get_psd_map(unsigned int cpu, struct cppc_cpudata *cpu_data);
 extern unsigned int cppc_get_transition_latency(int cpu);
 extern bool cpc_ffh_supported(void);
+extern bool cpc_supported_by_cpu(void);
 extern int cpc_read_ffh(int cpunum, struct cpc_reg *reg, u64 *val);
 extern int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val);
 #else /* !CONFIG_ACPI_CPPC_LIB */
index 1940273..9fa4968 100644 (file)
@@ -441,9 +441,12 @@ static inline int acpi_processor_hotplug(struct acpi_processor *pr)
 #endif /* CONFIG_ACPI_PROCESSOR_IDLE */
 
 /* in processor_thermal.c */
-int acpi_processor_get_limit_info(struct acpi_processor *pr);
+int acpi_processor_thermal_init(struct acpi_processor *pr,
+                               struct acpi_device *device);
+void acpi_processor_thermal_exit(struct acpi_processor *pr,
+                                struct acpi_device *device);
 extern const struct thermal_cooling_device_ops processor_cooling_ops;
-#if defined(CONFIG_ACPI_CPU_FREQ_PSS) & defined(CONFIG_CPU_FREQ)
+#ifdef CONFIG_CPU_FREQ
 void acpi_thermal_cpufreq_init(struct cpufreq_policy *policy);
 void acpi_thermal_cpufreq_exit(struct cpufreq_policy *policy);
 #else
@@ -455,6 +458,6 @@ static inline void acpi_thermal_cpufreq_exit(struct cpufreq_policy *policy)
 {
        return;
 }
-#endif /* CONFIG_ACPI_CPU_FREQ_PSS */
+#endif /* CONFIG_CPU_FREQ */
 
 #endif
index 8e47d48..36db8b9 100644 (file)
@@ -5,6 +5,7 @@
 # asm headers from the host architecutre.)
 
 mandatory-y += atomic.h
+mandatory-y += archrandom.h
 mandatory-y += barrier.h
 mandatory-y += bitops.h
 mandatory-y += bug.h
diff --git a/include/asm-generic/archrandom.h b/include/asm-generic/archrandom.h
new file mode 100644 (file)
index 0000000..3cd7f98
--- /dev/null
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_GENERIC_ARCHRANDOM_H__
+#define __ASM_GENERIC_ARCHRANDOM_H__
+
+static inline size_t __must_check arch_get_random_longs(unsigned long *v, size_t max_longs)
+{
+       return 0;
+}
+
+static inline size_t __must_check arch_get_random_seed_longs(unsigned long *v, size_t max_longs)
+{
+       return 0;
+}
+
+#endif
index fd7e8fb..961f4d8 100644 (file)
 #define wmb()  do { kcsan_wmb(); __wmb(); } while (0)
 #endif
 
+#ifdef __dma_mb
+#define dma_mb()       do { kcsan_mb(); __dma_mb(); } while (0)
+#endif
+
 #ifdef __dma_rmb
 #define dma_rmb()      do { kcsan_rmb(); __dma_rmb(); } while (0)
 #endif
 #define wmb()  mb()
 #endif
 
+#ifndef dma_mb
+#define dma_mb()       mb()
+#endif
+
 #ifndef dma_rmb
 #define dma_rmb()      rmb()
 #endif
index 7ce93aa..72974cb 100644 (file)
@@ -964,7 +964,34 @@ static inline void iounmap(volatile void __iomem *addr)
 #elif defined(CONFIG_GENERIC_IOREMAP)
 #include <linux/pgtable.h>
 
-void __iomem *ioremap_prot(phys_addr_t addr, size_t size, unsigned long prot);
+/*
+ * Arch code can implement the following two hooks when using GENERIC_IOREMAP
+ * ioremap_allowed() return a bool,
+ *   - true means continue to remap
+ *   - false means skip remap and return directly
+ * iounmap_allowed() return a bool,
+ *   - true means continue to vunmap
+ *   - false means skip vunmap and return directly
+ */
+#ifndef ioremap_allowed
+#define ioremap_allowed ioremap_allowed
+static inline bool ioremap_allowed(phys_addr_t phys_addr, size_t size,
+                                  unsigned long prot)
+{
+       return true;
+}
+#endif
+
+#ifndef iounmap_allowed
+#define iounmap_allowed iounmap_allowed
+static inline bool iounmap_allowed(void *addr)
+{
+       return true;
+}
+#endif
+
+void __iomem *ioremap_prot(phys_addr_t phys_addr, size_t size,
+                          unsigned long prot);
 void iounmap(volatile void __iomem *addr);
 
 static inline void __iomem *ioremap(phys_addr_t addr, size_t size)
@@ -1125,9 +1152,7 @@ static inline void memcpy_toio(volatile void __iomem *addr, const void *buffer,
 }
 #endif
 
-#ifndef CONFIG_GENERIC_DEVMEM_IS_ALLOWED
 extern int devmem_is_allowed(unsigned long pfn);
-#endif
 
 #endif /* __KERNEL__ */
 
index ff3e825..492dce4 100644 (file)
  *  Useful if your architecture doesn't use IPIs for remote TLB invalidates
  *  and therefore doesn't naturally serialize with software page-table walkers.
  *
+ *  MMU_GATHER_NO_FLUSH_CACHE
+ *
+ *  Indicates the architecture has flush_cache_range() but it needs *NOT* be called
+ *  before unmapping a VMA.
+ *
+ *  NOTE: strictly speaking we shouldn't have this knob and instead rely on
+ *       flush_cache_range() being a NOP, except Sparc64 seems to be
+ *       different here.
+ *
+ *  MMU_GATHER_MERGE_VMAS
+ *
+ *  Indicates the architecture wants to merge ranges over VMAs; typical when
+ *  multiple range invalidates are more expensive than a full invalidate.
+ *
  *  MMU_GATHER_NO_RANGE
  *
- *  Use this if your architecture lacks an efficient flush_tlb_range().
+ *  Use this if your architecture lacks an efficient flush_tlb_range(). This
+ *  option implies MMU_GATHER_MERGE_VMAS above.
  *
  *  MMU_GATHER_NO_GATHER
  *
@@ -288,6 +303,7 @@ struct mmu_gather {
         */
        unsigned int            vma_exec : 1;
        unsigned int            vma_huge : 1;
+       unsigned int            vma_pfn  : 1;
 
        unsigned int            batch_count;
 
@@ -334,8 +350,8 @@ static inline void __tlb_reset_range(struct mmu_gather *tlb)
 
 #ifdef CONFIG_MMU_GATHER_NO_RANGE
 
-#if defined(tlb_flush) || defined(tlb_start_vma) || defined(tlb_end_vma)
-#error MMU_GATHER_NO_RANGE relies on default tlb_flush(), tlb_start_vma() and tlb_end_vma()
+#if defined(tlb_flush)
+#error MMU_GATHER_NO_RANGE relies on default tlb_flush()
 #endif
 
 /*
@@ -352,20 +368,9 @@ static inline void tlb_flush(struct mmu_gather *tlb)
                flush_tlb_mm(tlb->mm);
 }
 
-static inline void
-tlb_update_vma_flags(struct mmu_gather *tlb, struct vm_area_struct *vma) { }
-
-#define tlb_end_vma tlb_end_vma
-static inline void tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma) { }
-
 #else /* CONFIG_MMU_GATHER_NO_RANGE */
 
 #ifndef tlb_flush
-
-#if defined(tlb_start_vma) || defined(tlb_end_vma)
-#error Default tlb_flush() relies on default tlb_start_vma() and tlb_end_vma()
-#endif
-
 /*
  * When an architecture does not provide its own tlb_flush() implementation
  * but does have a reasonably efficient flush_vma_range() implementation
@@ -385,6 +390,9 @@ static inline void tlb_flush(struct mmu_gather *tlb)
                flush_tlb_range(&vma, tlb->start, tlb->end);
        }
 }
+#endif
+
+#endif /* CONFIG_MMU_GATHER_NO_RANGE */
 
 static inline void
 tlb_update_vma_flags(struct mmu_gather *tlb, struct vm_area_struct *vma)
@@ -402,17 +410,9 @@ tlb_update_vma_flags(struct mmu_gather *tlb, struct vm_area_struct *vma)
         */
        tlb->vma_huge = is_vm_hugetlb_page(vma);
        tlb->vma_exec = !!(vma->vm_flags & VM_EXEC);
+       tlb->vma_pfn  = !!(vma->vm_flags & (VM_PFNMAP|VM_MIXEDMAP));
 }
 
-#else
-
-static inline void
-tlb_update_vma_flags(struct mmu_gather *tlb, struct vm_area_struct *vma) { }
-
-#endif
-
-#endif /* CONFIG_MMU_GATHER_NO_RANGE */
-
 static inline void tlb_flush_mmu_tlbonly(struct mmu_gather *tlb)
 {
        /*
@@ -486,32 +486,36 @@ static inline unsigned long tlb_get_unmap_size(struct mmu_gather *tlb)
  * case where we're doing a full MM flush.  When we're doing a munmap,
  * the vmas are adjusted to only cover the region to be torn down.
  */
-#ifndef tlb_start_vma
 static inline void tlb_start_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
 {
        if (tlb->fullmm)
                return;
 
        tlb_update_vma_flags(tlb, vma);
+#ifndef CONFIG_MMU_GATHER_NO_FLUSH_CACHE
        flush_cache_range(vma, vma->vm_start, vma->vm_end);
-}
 #endif
+}
 
-#ifndef tlb_end_vma
 static inline void tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
 {
        if (tlb->fullmm)
                return;
 
        /*
-        * Do a TLB flush and reset the range at VMA boundaries; this avoids
-        * the ranges growing with the unused space between consecutive VMAs,
-        * but also the mmu_gather::vma_* flags from tlb_start_vma() rely on
-        * this.
+        * VM_PFNMAP is more fragile because the core mm will not track the
+        * page mapcount -- there might not be page-frames for these PFNs after
+        * all. Force flush TLBs for such ranges to avoid munmap() vs
+        * unmap_mapping_range() races.
         */
-       tlb_flush_mmu_tlbonly(tlb);
+       if (tlb->vma_pfn || !IS_ENABLED(CONFIG_MMU_GATHER_MERGE_VMAS)) {
+               /*
+                * Do a TLB flush and reset the range at VMA boundaries; this avoids
+                * the ranges growing with the unused space between consecutive VMAs.
+                */
+               tlb_flush_mmu_tlbonly(tlb);
+       }
 }
-#endif
 
 /*
  * tlb_flush_{pte|pmd|pud|p4d}_range() adjust the tlb->start and tlb->end,
index f6da8a1..b0f80cf 100644 (file)
@@ -247,148 +247,4 @@ int omap_dm_timers_active(void);
 #define OMAP_TIMER_TICK_INT_MASK_COUNT_REG                             \
                (_OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET | (WP_TOWR << WPSHIFT))
 
-/*
- * The below are inlined to optimize code size for system timers. Other code
- * should not need these at all.
- */
-#if defined(CONFIG_ARCH_OMAP1) || defined(CONFIG_ARCH_OMAP2PLUS)
-static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
-                                               int posted)
-{
-       if (posted)
-               while (readl_relaxed(timer->pend) & (reg >> WPSHIFT))
-                       cpu_relax();
-
-       return readl_relaxed(timer->func_base + (reg & 0xff));
-}
-
-static inline void __omap_dm_timer_write(struct omap_dm_timer *timer,
-                                       u32 reg, u32 val, int posted)
-{
-       if (posted)
-               while (readl_relaxed(timer->pend) & (reg >> WPSHIFT))
-                       cpu_relax();
-
-       writel_relaxed(val, timer->func_base + (reg & 0xff));
-}
-
-static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)
-{
-       u32 tidr;
-
-       /* Assume v1 ip if bits [31:16] are zero */
-       tidr = readl_relaxed(timer->io_base);
-       if (!(tidr >> 16)) {
-               timer->revision = 1;
-               timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET;
-               timer->irq_ena = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET;
-               timer->irq_dis = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET;
-               timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET;
-               timer->func_base = timer->io_base;
-       } else {
-               timer->revision = 2;
-               timer->irq_stat = timer->io_base + OMAP_TIMER_V2_IRQSTATUS;
-               timer->irq_ena = timer->io_base + OMAP_TIMER_V2_IRQENABLE_SET;
-               timer->irq_dis = timer->io_base + OMAP_TIMER_V2_IRQENABLE_CLR;
-               timer->pend = timer->io_base +
-                       _OMAP_TIMER_WRITE_PEND_OFFSET +
-                               OMAP_TIMER_V2_FUNC_OFFSET;
-               timer->func_base = timer->io_base + OMAP_TIMER_V2_FUNC_OFFSET;
-       }
-}
-
-/*
- * __omap_dm_timer_enable_posted - enables write posted mode
- * @timer:      pointer to timer instance handle
- *
- * Enables the write posted mode for the timer. When posted mode is enabled
- * writes to certain timer registers are immediately acknowledged by the
- * internal bus and hence prevents stalling the CPU waiting for the write to
- * complete. Enabling this feature can improve performance for writing to the
- * timer registers.
- */
-static inline void __omap_dm_timer_enable_posted(struct omap_dm_timer *timer)
-{
-       if (timer->posted)
-               return;
-
-       if (timer->errata & OMAP_TIMER_ERRATA_I103_I767) {
-               timer->posted = OMAP_TIMER_NONPOSTED;
-               __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG, 0, 0);
-               return;
-       }
-
-       __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG,
-                             OMAP_TIMER_CTRL_POSTED, 0);
-       timer->context.tsicr = OMAP_TIMER_CTRL_POSTED;
-       timer->posted = OMAP_TIMER_POSTED;
-}
-
-/**
- * __omap_dm_timer_override_errata - override errata flags for a timer
- * @timer:      pointer to timer handle
- * @errata:    errata flags to be ignored
- *
- * For a given timer, override a timer errata by clearing the flags
- * specified by the errata argument. A specific erratum should only be
- * overridden for a timer if the timer is used in such a way the erratum
- * has no impact.
- */
-static inline void __omap_dm_timer_override_errata(struct omap_dm_timer *timer,
-                                                  u32 errata)
-{
-       timer->errata &= ~errata;
-}
-
-static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer,
-                                       int posted, unsigned long rate)
-{
-       u32 l;
-
-       l = __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted);
-       if (l & OMAP_TIMER_CTRL_ST) {
-               l &= ~0x1;
-               __omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, l, posted);
-#ifdef CONFIG_ARCH_OMAP2PLUS
-               /* Readback to make sure write has completed */
-               __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted);
-               /*
-                * Wait for functional clock period x 3.5 to make sure that
-                * timer is stopped
-                */
-               udelay(3500000 / rate + 1);
-#endif
-       }
-
-       /* Ack possibly pending interrupt */
-       writel_relaxed(OMAP_TIMER_INT_OVERFLOW, timer->irq_stat);
-}
-
-static inline void __omap_dm_timer_load_start(struct omap_dm_timer *timer,
-                                               u32 ctrl, unsigned int load,
-                                               int posted)
-{
-       __omap_dm_timer_write(timer, OMAP_TIMER_COUNTER_REG, load, posted);
-       __omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, ctrl, posted);
-}
-
-static inline void __omap_dm_timer_int_enable(struct omap_dm_timer *timer,
-                                               unsigned int value)
-{
-       writel_relaxed(value, timer->irq_ena);
-       __omap_dm_timer_write(timer, OMAP_TIMER_WAKEUP_EN_REG, value, 0);
-}
-
-static inline unsigned int
-__omap_dm_timer_read_counter(struct omap_dm_timer *timer, int posted)
-{
-       return __omap_dm_timer_read(timer, OMAP_TIMER_COUNTER_REG, posted);
-}
-
-static inline void __omap_dm_timer_write_status(struct omap_dm_timer *timer,
-                                               unsigned int value)
-{
-       writel_relaxed(value, timer->irq_stat);
-}
-#endif /* CONFIG_ARCH_OMAP1 || CONFIG_ARCH_OMAP2PLUS */
 #endif /* __CLOCKSOURCE_DMTIMER_H */
diff --git a/include/crypto/aria.h b/include/crypto/aria.h
new file mode 100644 (file)
index 0000000..4a86661
--- /dev/null
@@ -0,0 +1,461 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Cryptographic API.
+ *
+ * ARIA Cipher Algorithm.
+ *
+ * Documentation of ARIA can be found in RFC 5794.
+ * Copyright (c) 2022 Taehee Yoo <ap420073@gmail.com>
+ * Copyright (c) 2022 Taehee Yoo <ap420073@gmail.com>
+ *
+ * Information for ARIA
+ *     http://210.104.33.10/ARIA/index-e.html (English)
+ *     http://seed.kisa.or.kr/ (Korean)
+ *
+ * Public domain version is distributed above.
+ */
+
+#ifndef _CRYPTO_ARIA_H
+#define _CRYPTO_ARIA_H
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/crypto.h>
+#include <asm/byteorder.h>
+
+#define ARIA_MIN_KEY_SIZE      16
+#define ARIA_MAX_KEY_SIZE      32
+#define ARIA_BLOCK_SIZE                16
+#define ARIA_MAX_RD_KEYS       17
+#define ARIA_RD_KEY_WORDS      (ARIA_BLOCK_SIZE / sizeof(u32))
+
+struct aria_ctx {
+       int key_length;
+       int rounds;
+       u32 enc_key[ARIA_MAX_RD_KEYS][ARIA_RD_KEY_WORDS];
+       u32 dec_key[ARIA_MAX_RD_KEYS][ARIA_RD_KEY_WORDS];
+};
+
+static const u32 key_rc[5][4] = {
+       { 0x517cc1b7, 0x27220a94, 0xfe13abe8, 0xfa9a6ee0 },
+       { 0x6db14acc, 0x9e21c820, 0xff28b1d5, 0xef5de2b0 },
+       { 0xdb92371d, 0x2126e970, 0x03249775, 0x04e8c90e },
+       { 0x517cc1b7, 0x27220a94, 0xfe13abe8, 0xfa9a6ee0 },
+       { 0x6db14acc, 0x9e21c820, 0xff28b1d5, 0xef5de2b0 }
+};
+
+static const u32 s1[256] = {
+       0x00636363, 0x007c7c7c, 0x00777777, 0x007b7b7b,
+       0x00f2f2f2, 0x006b6b6b, 0x006f6f6f, 0x00c5c5c5,
+       0x00303030, 0x00010101, 0x00676767, 0x002b2b2b,
+       0x00fefefe, 0x00d7d7d7, 0x00ababab, 0x00767676,
+       0x00cacaca, 0x00828282, 0x00c9c9c9, 0x007d7d7d,
+       0x00fafafa, 0x00595959, 0x00474747, 0x00f0f0f0,
+       0x00adadad, 0x00d4d4d4, 0x00a2a2a2, 0x00afafaf,
+       0x009c9c9c, 0x00a4a4a4, 0x00727272, 0x00c0c0c0,
+       0x00b7b7b7, 0x00fdfdfd, 0x00939393, 0x00262626,
+       0x00363636, 0x003f3f3f, 0x00f7f7f7, 0x00cccccc,
+       0x00343434, 0x00a5a5a5, 0x00e5e5e5, 0x00f1f1f1,
+       0x00717171, 0x00d8d8d8, 0x00313131, 0x00151515,
+       0x00040404, 0x00c7c7c7, 0x00232323, 0x00c3c3c3,
+       0x00181818, 0x00969696, 0x00050505, 0x009a9a9a,
+       0x00070707, 0x00121212, 0x00808080, 0x00e2e2e2,
+       0x00ebebeb, 0x00272727, 0x00b2b2b2, 0x00757575,
+       0x00090909, 0x00838383, 0x002c2c2c, 0x001a1a1a,
+       0x001b1b1b, 0x006e6e6e, 0x005a5a5a, 0x00a0a0a0,
+       0x00525252, 0x003b3b3b, 0x00d6d6d6, 0x00b3b3b3,
+       0x00292929, 0x00e3e3e3, 0x002f2f2f, 0x00848484,
+       0x00535353, 0x00d1d1d1, 0x00000000, 0x00ededed,
+       0x00202020, 0x00fcfcfc, 0x00b1b1b1, 0x005b5b5b,
+       0x006a6a6a, 0x00cbcbcb, 0x00bebebe, 0x00393939,
+       0x004a4a4a, 0x004c4c4c, 0x00585858, 0x00cfcfcf,
+       0x00d0d0d0, 0x00efefef, 0x00aaaaaa, 0x00fbfbfb,
+       0x00434343, 0x004d4d4d, 0x00333333, 0x00858585,
+       0x00454545, 0x00f9f9f9, 0x00020202, 0x007f7f7f,
+       0x00505050, 0x003c3c3c, 0x009f9f9f, 0x00a8a8a8,
+       0x00515151, 0x00a3a3a3, 0x00404040, 0x008f8f8f,
+       0x00929292, 0x009d9d9d, 0x00383838, 0x00f5f5f5,
+       0x00bcbcbc, 0x00b6b6b6, 0x00dadada, 0x00212121,
+       0x00101010, 0x00ffffff, 0x00f3f3f3, 0x00d2d2d2,
+       0x00cdcdcd, 0x000c0c0c, 0x00131313, 0x00ececec,
+       0x005f5f5f, 0x00979797, 0x00444444, 0x00171717,
+       0x00c4c4c4, 0x00a7a7a7, 0x007e7e7e, 0x003d3d3d,
+       0x00646464, 0x005d5d5d, 0x00191919, 0x00737373,
+       0x00606060, 0x00818181, 0x004f4f4f, 0x00dcdcdc,
+       0x00222222, 0x002a2a2a, 0x00909090, 0x00888888,
+       0x00464646, 0x00eeeeee, 0x00b8b8b8, 0x00141414,
+       0x00dedede, 0x005e5e5e, 0x000b0b0b, 0x00dbdbdb,
+       0x00e0e0e0, 0x00323232, 0x003a3a3a, 0x000a0a0a,
+       0x00494949, 0x00060606, 0x00242424, 0x005c5c5c,
+       0x00c2c2c2, 0x00d3d3d3, 0x00acacac, 0x00626262,
+       0x00919191, 0x00959595, 0x00e4e4e4, 0x00797979,
+       0x00e7e7e7, 0x00c8c8c8, 0x00373737, 0x006d6d6d,
+       0x008d8d8d, 0x00d5d5d5, 0x004e4e4e, 0x00a9a9a9,
+       0x006c6c6c, 0x00565656, 0x00f4f4f4, 0x00eaeaea,
+       0x00656565, 0x007a7a7a, 0x00aeaeae, 0x00080808,
+       0x00bababa, 0x00787878, 0x00252525, 0x002e2e2e,
+       0x001c1c1c, 0x00a6a6a6, 0x00b4b4b4, 0x00c6c6c6,
+       0x00e8e8e8, 0x00dddddd, 0x00747474, 0x001f1f1f,
+       0x004b4b4b, 0x00bdbdbd, 0x008b8b8b, 0x008a8a8a,
+       0x00707070, 0x003e3e3e, 0x00b5b5b5, 0x00666666,
+       0x00484848, 0x00030303, 0x00f6f6f6, 0x000e0e0e,
+       0x00616161, 0x00353535, 0x00575757, 0x00b9b9b9,
+       0x00868686, 0x00c1c1c1, 0x001d1d1d, 0x009e9e9e,
+       0x00e1e1e1, 0x00f8f8f8, 0x00989898, 0x00111111,
+       0x00696969, 0x00d9d9d9, 0x008e8e8e, 0x00949494,
+       0x009b9b9b, 0x001e1e1e, 0x00878787, 0x00e9e9e9,
+       0x00cecece, 0x00555555, 0x00282828, 0x00dfdfdf,
+       0x008c8c8c, 0x00a1a1a1, 0x00898989, 0x000d0d0d,
+       0x00bfbfbf, 0x00e6e6e6, 0x00424242, 0x00686868,
+       0x00414141, 0x00999999, 0x002d2d2d, 0x000f0f0f,
+       0x00b0b0b0, 0x00545454, 0x00bbbbbb, 0x00161616
+};
+
+static const u32 s2[256] = {
+       0xe200e2e2, 0x4e004e4e, 0x54005454, 0xfc00fcfc,
+       0x94009494, 0xc200c2c2, 0x4a004a4a, 0xcc00cccc,
+       0x62006262, 0x0d000d0d, 0x6a006a6a, 0x46004646,
+       0x3c003c3c, 0x4d004d4d, 0x8b008b8b, 0xd100d1d1,
+       0x5e005e5e, 0xfa00fafa, 0x64006464, 0xcb00cbcb,
+       0xb400b4b4, 0x97009797, 0xbe00bebe, 0x2b002b2b,
+       0xbc00bcbc, 0x77007777, 0x2e002e2e, 0x03000303,
+       0xd300d3d3, 0x19001919, 0x59005959, 0xc100c1c1,
+       0x1d001d1d, 0x06000606, 0x41004141, 0x6b006b6b,
+       0x55005555, 0xf000f0f0, 0x99009999, 0x69006969,
+       0xea00eaea, 0x9c009c9c, 0x18001818, 0xae00aeae,
+       0x63006363, 0xdf00dfdf, 0xe700e7e7, 0xbb00bbbb,
+       0x00000000, 0x73007373, 0x66006666, 0xfb00fbfb,
+       0x96009696, 0x4c004c4c, 0x85008585, 0xe400e4e4,
+       0x3a003a3a, 0x09000909, 0x45004545, 0xaa00aaaa,
+       0x0f000f0f, 0xee00eeee, 0x10001010, 0xeb00ebeb,
+       0x2d002d2d, 0x7f007f7f, 0xf400f4f4, 0x29002929,
+       0xac00acac, 0xcf00cfcf, 0xad00adad, 0x91009191,
+       0x8d008d8d, 0x78007878, 0xc800c8c8, 0x95009595,
+       0xf900f9f9, 0x2f002f2f, 0xce00cece, 0xcd00cdcd,
+       0x08000808, 0x7a007a7a, 0x88008888, 0x38003838,
+       0x5c005c5c, 0x83008383, 0x2a002a2a, 0x28002828,
+       0x47004747, 0xdb00dbdb, 0xb800b8b8, 0xc700c7c7,
+       0x93009393, 0xa400a4a4, 0x12001212, 0x53005353,
+       0xff00ffff, 0x87008787, 0x0e000e0e, 0x31003131,
+       0x36003636, 0x21002121, 0x58005858, 0x48004848,
+       0x01000101, 0x8e008e8e, 0x37003737, 0x74007474,
+       0x32003232, 0xca00caca, 0xe900e9e9, 0xb100b1b1,
+       0xb700b7b7, 0xab00abab, 0x0c000c0c, 0xd700d7d7,
+       0xc400c4c4, 0x56005656, 0x42004242, 0x26002626,
+       0x07000707, 0x98009898, 0x60006060, 0xd900d9d9,
+       0xb600b6b6, 0xb900b9b9, 0x11001111, 0x40004040,
+       0xec00ecec, 0x20002020, 0x8c008c8c, 0xbd00bdbd,
+       0xa000a0a0, 0xc900c9c9, 0x84008484, 0x04000404,
+       0x49004949, 0x23002323, 0xf100f1f1, 0x4f004f4f,
+       0x50005050, 0x1f001f1f, 0x13001313, 0xdc00dcdc,
+       0xd800d8d8, 0xc000c0c0, 0x9e009e9e, 0x57005757,
+       0xe300e3e3, 0xc300c3c3, 0x7b007b7b, 0x65006565,
+       0x3b003b3b, 0x02000202, 0x8f008f8f, 0x3e003e3e,
+       0xe800e8e8, 0x25002525, 0x92009292, 0xe500e5e5,
+       0x15001515, 0xdd00dddd, 0xfd00fdfd, 0x17001717,
+       0xa900a9a9, 0xbf00bfbf, 0xd400d4d4, 0x9a009a9a,
+       0x7e007e7e, 0xc500c5c5, 0x39003939, 0x67006767,
+       0xfe00fefe, 0x76007676, 0x9d009d9d, 0x43004343,
+       0xa700a7a7, 0xe100e1e1, 0xd000d0d0, 0xf500f5f5,
+       0x68006868, 0xf200f2f2, 0x1b001b1b, 0x34003434,
+       0x70007070, 0x05000505, 0xa300a3a3, 0x8a008a8a,
+       0xd500d5d5, 0x79007979, 0x86008686, 0xa800a8a8,
+       0x30003030, 0xc600c6c6, 0x51005151, 0x4b004b4b,
+       0x1e001e1e, 0xa600a6a6, 0x27002727, 0xf600f6f6,
+       0x35003535, 0xd200d2d2, 0x6e006e6e, 0x24002424,
+       0x16001616, 0x82008282, 0x5f005f5f, 0xda00dada,
+       0xe600e6e6, 0x75007575, 0xa200a2a2, 0xef00efef,
+       0x2c002c2c, 0xb200b2b2, 0x1c001c1c, 0x9f009f9f,
+       0x5d005d5d, 0x6f006f6f, 0x80008080, 0x0a000a0a,
+       0x72007272, 0x44004444, 0x9b009b9b, 0x6c006c6c,
+       0x90009090, 0x0b000b0b, 0x5b005b5b, 0x33003333,
+       0x7d007d7d, 0x5a005a5a, 0x52005252, 0xf300f3f3,
+       0x61006161, 0xa100a1a1, 0xf700f7f7, 0xb000b0b0,
+       0xd600d6d6, 0x3f003f3f, 0x7c007c7c, 0x6d006d6d,
+       0xed00eded, 0x14001414, 0xe000e0e0, 0xa500a5a5,
+       0x3d003d3d, 0x22002222, 0xb300b3b3, 0xf800f8f8,
+       0x89008989, 0xde00dede, 0x71007171, 0x1a001a1a,
+       0xaf00afaf, 0xba00baba, 0xb500b5b5, 0x81008181
+};
+
+static const u32 x1[256] = {
+       0x52520052, 0x09090009, 0x6a6a006a, 0xd5d500d5,
+       0x30300030, 0x36360036, 0xa5a500a5, 0x38380038,
+       0xbfbf00bf, 0x40400040, 0xa3a300a3, 0x9e9e009e,
+       0x81810081, 0xf3f300f3, 0xd7d700d7, 0xfbfb00fb,
+       0x7c7c007c, 0xe3e300e3, 0x39390039, 0x82820082,
+       0x9b9b009b, 0x2f2f002f, 0xffff00ff, 0x87870087,
+       0x34340034, 0x8e8e008e, 0x43430043, 0x44440044,
+       0xc4c400c4, 0xdede00de, 0xe9e900e9, 0xcbcb00cb,
+       0x54540054, 0x7b7b007b, 0x94940094, 0x32320032,
+       0xa6a600a6, 0xc2c200c2, 0x23230023, 0x3d3d003d,
+       0xeeee00ee, 0x4c4c004c, 0x95950095, 0x0b0b000b,
+       0x42420042, 0xfafa00fa, 0xc3c300c3, 0x4e4e004e,
+       0x08080008, 0x2e2e002e, 0xa1a100a1, 0x66660066,
+       0x28280028, 0xd9d900d9, 0x24240024, 0xb2b200b2,
+       0x76760076, 0x5b5b005b, 0xa2a200a2, 0x49490049,
+       0x6d6d006d, 0x8b8b008b, 0xd1d100d1, 0x25250025,
+       0x72720072, 0xf8f800f8, 0xf6f600f6, 0x64640064,
+       0x86860086, 0x68680068, 0x98980098, 0x16160016,
+       0xd4d400d4, 0xa4a400a4, 0x5c5c005c, 0xcccc00cc,
+       0x5d5d005d, 0x65650065, 0xb6b600b6, 0x92920092,
+       0x6c6c006c, 0x70700070, 0x48480048, 0x50500050,
+       0xfdfd00fd, 0xeded00ed, 0xb9b900b9, 0xdada00da,
+       0x5e5e005e, 0x15150015, 0x46460046, 0x57570057,
+       0xa7a700a7, 0x8d8d008d, 0x9d9d009d, 0x84840084,
+       0x90900090, 0xd8d800d8, 0xabab00ab, 0x00000000,
+       0x8c8c008c, 0xbcbc00bc, 0xd3d300d3, 0x0a0a000a,
+       0xf7f700f7, 0xe4e400e4, 0x58580058, 0x05050005,
+       0xb8b800b8, 0xb3b300b3, 0x45450045, 0x06060006,
+       0xd0d000d0, 0x2c2c002c, 0x1e1e001e, 0x8f8f008f,
+       0xcaca00ca, 0x3f3f003f, 0x0f0f000f, 0x02020002,
+       0xc1c100c1, 0xafaf00af, 0xbdbd00bd, 0x03030003,
+       0x01010001, 0x13130013, 0x8a8a008a, 0x6b6b006b,
+       0x3a3a003a, 0x91910091, 0x11110011, 0x41410041,
+       0x4f4f004f, 0x67670067, 0xdcdc00dc, 0xeaea00ea,
+       0x97970097, 0xf2f200f2, 0xcfcf00cf, 0xcece00ce,
+       0xf0f000f0, 0xb4b400b4, 0xe6e600e6, 0x73730073,
+       0x96960096, 0xacac00ac, 0x74740074, 0x22220022,
+       0xe7e700e7, 0xadad00ad, 0x35350035, 0x85850085,
+       0xe2e200e2, 0xf9f900f9, 0x37370037, 0xe8e800e8,
+       0x1c1c001c, 0x75750075, 0xdfdf00df, 0x6e6e006e,
+       0x47470047, 0xf1f100f1, 0x1a1a001a, 0x71710071,
+       0x1d1d001d, 0x29290029, 0xc5c500c5, 0x89890089,
+       0x6f6f006f, 0xb7b700b7, 0x62620062, 0x0e0e000e,
+       0xaaaa00aa, 0x18180018, 0xbebe00be, 0x1b1b001b,
+       0xfcfc00fc, 0x56560056, 0x3e3e003e, 0x4b4b004b,
+       0xc6c600c6, 0xd2d200d2, 0x79790079, 0x20200020,
+       0x9a9a009a, 0xdbdb00db, 0xc0c000c0, 0xfefe00fe,
+       0x78780078, 0xcdcd00cd, 0x5a5a005a, 0xf4f400f4,
+       0x1f1f001f, 0xdddd00dd, 0xa8a800a8, 0x33330033,
+       0x88880088, 0x07070007, 0xc7c700c7, 0x31310031,
+       0xb1b100b1, 0x12120012, 0x10100010, 0x59590059,
+       0x27270027, 0x80800080, 0xecec00ec, 0x5f5f005f,
+       0x60600060, 0x51510051, 0x7f7f007f, 0xa9a900a9,
+       0x19190019, 0xb5b500b5, 0x4a4a004a, 0x0d0d000d,
+       0x2d2d002d, 0xe5e500e5, 0x7a7a007a, 0x9f9f009f,
+       0x93930093, 0xc9c900c9, 0x9c9c009c, 0xefef00ef,
+       0xa0a000a0, 0xe0e000e0, 0x3b3b003b, 0x4d4d004d,
+       0xaeae00ae, 0x2a2a002a, 0xf5f500f5, 0xb0b000b0,
+       0xc8c800c8, 0xebeb00eb, 0xbbbb00bb, 0x3c3c003c,
+       0x83830083, 0x53530053, 0x99990099, 0x61610061,
+       0x17170017, 0x2b2b002b, 0x04040004, 0x7e7e007e,
+       0xbaba00ba, 0x77770077, 0xd6d600d6, 0x26260026,
+       0xe1e100e1, 0x69690069, 0x14140014, 0x63630063,
+       0x55550055, 0x21210021, 0x0c0c000c, 0x7d7d007d
+};
+
+static const u32 x2[256] = {
+       0x30303000, 0x68686800, 0x99999900, 0x1b1b1b00,
+       0x87878700, 0xb9b9b900, 0x21212100, 0x78787800,
+       0x50505000, 0x39393900, 0xdbdbdb00, 0xe1e1e100,
+       0x72727200, 0x09090900, 0x62626200, 0x3c3c3c00,
+       0x3e3e3e00, 0x7e7e7e00, 0x5e5e5e00, 0x8e8e8e00,
+       0xf1f1f100, 0xa0a0a000, 0xcccccc00, 0xa3a3a300,
+       0x2a2a2a00, 0x1d1d1d00, 0xfbfbfb00, 0xb6b6b600,
+       0xd6d6d600, 0x20202000, 0xc4c4c400, 0x8d8d8d00,
+       0x81818100, 0x65656500, 0xf5f5f500, 0x89898900,
+       0xcbcbcb00, 0x9d9d9d00, 0x77777700, 0xc6c6c600,
+       0x57575700, 0x43434300, 0x56565600, 0x17171700,
+       0xd4d4d400, 0x40404000, 0x1a1a1a00, 0x4d4d4d00,
+       0xc0c0c000, 0x63636300, 0x6c6c6c00, 0xe3e3e300,
+       0xb7b7b700, 0xc8c8c800, 0x64646400, 0x6a6a6a00,
+       0x53535300, 0xaaaaaa00, 0x38383800, 0x98989800,
+       0x0c0c0c00, 0xf4f4f400, 0x9b9b9b00, 0xededed00,
+       0x7f7f7f00, 0x22222200, 0x76767600, 0xafafaf00,
+       0xdddddd00, 0x3a3a3a00, 0x0b0b0b00, 0x58585800,
+       0x67676700, 0x88888800, 0x06060600, 0xc3c3c300,
+       0x35353500, 0x0d0d0d00, 0x01010100, 0x8b8b8b00,
+       0x8c8c8c00, 0xc2c2c200, 0xe6e6e600, 0x5f5f5f00,
+       0x02020200, 0x24242400, 0x75757500, 0x93939300,
+       0x66666600, 0x1e1e1e00, 0xe5e5e500, 0xe2e2e200,
+       0x54545400, 0xd8d8d800, 0x10101000, 0xcecece00,
+       0x7a7a7a00, 0xe8e8e800, 0x08080800, 0x2c2c2c00,
+       0x12121200, 0x97979700, 0x32323200, 0xababab00,
+       0xb4b4b400, 0x27272700, 0x0a0a0a00, 0x23232300,
+       0xdfdfdf00, 0xefefef00, 0xcacaca00, 0xd9d9d900,
+       0xb8b8b800, 0xfafafa00, 0xdcdcdc00, 0x31313100,
+       0x6b6b6b00, 0xd1d1d100, 0xadadad00, 0x19191900,
+       0x49494900, 0xbdbdbd00, 0x51515100, 0x96969600,
+       0xeeeeee00, 0xe4e4e400, 0xa8a8a800, 0x41414100,
+       0xdadada00, 0xffffff00, 0xcdcdcd00, 0x55555500,
+       0x86868600, 0x36363600, 0xbebebe00, 0x61616100,
+       0x52525200, 0xf8f8f800, 0xbbbbbb00, 0x0e0e0e00,
+       0x82828200, 0x48484800, 0x69696900, 0x9a9a9a00,
+       0xe0e0e000, 0x47474700, 0x9e9e9e00, 0x5c5c5c00,
+       0x04040400, 0x4b4b4b00, 0x34343400, 0x15151500,
+       0x79797900, 0x26262600, 0xa7a7a700, 0xdedede00,
+       0x29292900, 0xaeaeae00, 0x92929200, 0xd7d7d700,
+       0x84848400, 0xe9e9e900, 0xd2d2d200, 0xbababa00,
+       0x5d5d5d00, 0xf3f3f300, 0xc5c5c500, 0xb0b0b000,
+       0xbfbfbf00, 0xa4a4a400, 0x3b3b3b00, 0x71717100,
+       0x44444400, 0x46464600, 0x2b2b2b00, 0xfcfcfc00,
+       0xebebeb00, 0x6f6f6f00, 0xd5d5d500, 0xf6f6f600,
+       0x14141400, 0xfefefe00, 0x7c7c7c00, 0x70707000,
+       0x5a5a5a00, 0x7d7d7d00, 0xfdfdfd00, 0x2f2f2f00,
+       0x18181800, 0x83838300, 0x16161600, 0xa5a5a500,
+       0x91919100, 0x1f1f1f00, 0x05050500, 0x95959500,
+       0x74747400, 0xa9a9a900, 0xc1c1c100, 0x5b5b5b00,
+       0x4a4a4a00, 0x85858500, 0x6d6d6d00, 0x13131300,
+       0x07070700, 0x4f4f4f00, 0x4e4e4e00, 0x45454500,
+       0xb2b2b200, 0x0f0f0f00, 0xc9c9c900, 0x1c1c1c00,
+       0xa6a6a600, 0xbcbcbc00, 0xececec00, 0x73737300,
+       0x90909000, 0x7b7b7b00, 0xcfcfcf00, 0x59595900,
+       0x8f8f8f00, 0xa1a1a100, 0xf9f9f900, 0x2d2d2d00,
+       0xf2f2f200, 0xb1b1b100, 0x00000000, 0x94949400,
+       0x37373700, 0x9f9f9f00, 0xd0d0d000, 0x2e2e2e00,
+       0x9c9c9c00, 0x6e6e6e00, 0x28282800, 0x3f3f3f00,
+       0x80808000, 0xf0f0f000, 0x3d3d3d00, 0xd3d3d300,
+       0x25252500, 0x8a8a8a00, 0xb5b5b500, 0xe7e7e700,
+       0x42424200, 0xb3b3b300, 0xc7c7c700, 0xeaeaea00,
+       0xf7f7f700, 0x4c4c4c00, 0x11111100, 0x33333300,
+       0x03030300, 0xa2a2a200, 0xacacac00, 0x60606000
+};
+
+static inline u32 rotl32(u32 v, u32 r)
+{
+       return ((v << r) | (v >> (32 - r)));
+}
+
+static inline u32 rotr32(u32 v, u32 r)
+{
+       return ((v >> r) | (v << (32 - r)));
+}
+
+static inline u32 bswap32(u32 v)
+{
+       return ((v << 24) ^
+               (v >> 24) ^
+               ((v & 0x0000ff00) << 8) ^
+               ((v & 0x00ff0000) >> 8));
+}
+
+static inline u8 get_u8(u32 x, u32 y)
+{
+       return (x >> ((3 - y) * 8));
+}
+
+static inline u32 make_u32(u8 v0, u8 v1, u8 v2, u8 v3)
+{
+       return ((u32)v0 << 24) | ((u32)v1 << 16) | ((u32)v2 <<  8) | ((u32)v3);
+}
+
+static inline u32 aria_m(u32 t0)
+{
+       return rotr32(t0, 8) ^ rotr32(t0 ^ rotr32(t0, 8), 16);
+}
+
+/* S-Box Layer 1 + M */
+static inline void aria_sbox_layer1_with_pre_diff(u32 *t0, u32 *t1, u32 *t2,
+                                                 u32 *t3)
+{
+       *t0 = s1[get_u8(*t0, 0)] ^
+             s2[get_u8(*t0, 1)] ^
+             x1[get_u8(*t0, 2)] ^
+             x2[get_u8(*t0, 3)];
+       *t1 = s1[get_u8(*t1, 0)] ^
+             s2[get_u8(*t1, 1)] ^
+             x1[get_u8(*t1, 2)] ^
+             x2[get_u8(*t1, 3)];
+       *t2 = s1[get_u8(*t2, 0)] ^
+             s2[get_u8(*t2, 1)] ^
+             x1[get_u8(*t2, 2)] ^
+             x2[get_u8(*t2, 3)];
+       *t3 = s1[get_u8(*t3, 0)] ^
+             s2[get_u8(*t3, 1)] ^
+             x1[get_u8(*t3, 2)] ^
+             x2[get_u8(*t3, 3)];
+}
+
+/* S-Box Layer 2 + M */
+static inline void aria_sbox_layer2_with_pre_diff(u32 *t0, u32 *t1, u32 *t2,
+                                                 u32 *t3)
+{
+       *t0 = x1[get_u8(*t0, 0)] ^
+             x2[get_u8(*t0, 1)] ^
+             s1[get_u8(*t0, 2)] ^
+             s2[get_u8(*t0, 3)];
+       *t1 = x1[get_u8(*t1, 0)] ^
+             x2[get_u8(*t1, 1)] ^
+             s1[get_u8(*t1, 2)] ^
+             s2[get_u8(*t1, 3)];
+       *t2 = x1[get_u8(*t2, 0)] ^
+             x2[get_u8(*t2, 1)] ^
+             s1[get_u8(*t2, 2)] ^
+             s2[get_u8(*t2, 3)];
+       *t3 = x1[get_u8(*t3, 0)] ^
+             x2[get_u8(*t3, 1)] ^
+             s1[get_u8(*t3, 2)] ^
+             s2[get_u8(*t3, 3)];
+}
+
+/* Word-level diffusion */
+static inline void aria_diff_word(u32 *t0, u32 *t1, u32 *t2, u32 *t3)
+{
+       *t1 ^= *t2;
+       *t2 ^= *t3;
+       *t0 ^= *t1;
+
+       *t3 ^= *t1;
+       *t2 ^= *t0;
+       *t1 ^= *t2;
+}
+
+/* Byte-level diffusion */
+static inline void aria_diff_byte(u32 *t1, u32 *t2, u32 *t3)
+{
+       *t1 = ((*t1 << 8) & 0xff00ff00) ^ ((*t1 >> 8) & 0x00ff00ff);
+       *t2 = rotr32(*t2, 16);
+       *t3 = bswap32(*t3);
+}
+
+/* Key XOR Layer */
+static inline void aria_add_round_key(u32 *rk, u32 *t0, u32 *t1, u32 *t2,
+                                     u32 *t3)
+{
+       *t0 ^= rk[0];
+       *t1 ^= rk[1];
+       *t2 ^= rk[2];
+       *t3 ^= rk[3];
+}
+/* Odd round Substitution & Diffusion */
+static inline void aria_subst_diff_odd(u32 *t0, u32 *t1, u32 *t2, u32 *t3)
+{
+       aria_sbox_layer1_with_pre_diff(t0, t1, t2, t3);
+       aria_diff_word(t0, t1, t2, t3);
+       aria_diff_byte(t1, t2, t3);
+       aria_diff_word(t0, t1, t2, t3);
+}
+
+/* Even round Substitution & Diffusion */
+static inline void aria_subst_diff_even(u32 *t0, u32 *t1, u32 *t2, u32 *t3)
+{
+       aria_sbox_layer2_with_pre_diff(t0, t1, t2, t3);
+       aria_diff_word(t0, t1, t2, t3);
+       aria_diff_byte(t3, t0, t1);
+       aria_diff_word(t0, t1, t2, t3);
+}
+
+/* Q, R Macro expanded ARIA GSRK */
+static inline void aria_gsrk(u32 *rk, u32 *x, u32 *y, u32 n)
+{
+       int q = 4 - (n / 32);
+       int r = n % 32;
+
+       rk[0] = (x[0]) ^
+               ((y[q % 4]) >> r) ^
+               ((y[(q + 3) % 4]) << (32 - r));
+       rk[1] = (x[1]) ^
+               ((y[(q + 1) % 4]) >> r) ^
+               ((y[q % 4]) << (32 - r));
+       rk[2] = (x[2]) ^
+               ((y[(q + 2) % 4]) >> r) ^
+               ((y[(q + 1) % 4]) << (32 - r));
+       rk[3] = (x[3]) ^
+               ((y[(q + 3) % 4]) >> r) ^
+               ((y[(q + 2) % 4]) << (32 - r));
+}
+
+#endif
index 52363ee..506d565 100644 (file)
@@ -8,7 +8,6 @@
 #define _CRYPTO_INTERNAL_BLAKE2S_H
 
 #include <crypto/blake2s.h>
-#include <crypto/internal/hash.h>
 #include <linux/string.h>
 
 void blake2s_compress_generic(struct blake2s_state *state, const u8 *block,
@@ -19,111 +18,4 @@ void blake2s_compress(struct blake2s_state *state, const u8 *block,
 
 bool blake2s_selftest(void);
 
-static inline void blake2s_set_lastblock(struct blake2s_state *state)
-{
-       state->f[0] = -1;
-}
-
-/* Helper functions for BLAKE2s shared by the library and shash APIs */
-
-static __always_inline void
-__blake2s_update(struct blake2s_state *state, const u8 *in, size_t inlen,
-                bool force_generic)
-{
-       const size_t fill = BLAKE2S_BLOCK_SIZE - state->buflen;
-
-       if (unlikely(!inlen))
-               return;
-       if (inlen > fill) {
-               memcpy(state->buf + state->buflen, in, fill);
-               if (force_generic)
-                       blake2s_compress_generic(state, state->buf, 1,
-                                                BLAKE2S_BLOCK_SIZE);
-               else
-                       blake2s_compress(state, state->buf, 1,
-                                        BLAKE2S_BLOCK_SIZE);
-               state->buflen = 0;
-               in += fill;
-               inlen -= fill;
-       }
-       if (inlen > BLAKE2S_BLOCK_SIZE) {
-               const size_t nblocks = DIV_ROUND_UP(inlen, BLAKE2S_BLOCK_SIZE);
-               /* Hash one less (full) block than strictly possible */
-               if (force_generic)
-                       blake2s_compress_generic(state, in, nblocks - 1,
-                                                BLAKE2S_BLOCK_SIZE);
-               else
-                       blake2s_compress(state, in, nblocks - 1,
-                                        BLAKE2S_BLOCK_SIZE);
-               in += BLAKE2S_BLOCK_SIZE * (nblocks - 1);
-               inlen -= BLAKE2S_BLOCK_SIZE * (nblocks - 1);
-       }
-       memcpy(state->buf + state->buflen, in, inlen);
-       state->buflen += inlen;
-}
-
-static __always_inline void
-__blake2s_final(struct blake2s_state *state, u8 *out, bool force_generic)
-{
-       blake2s_set_lastblock(state);
-       memset(state->buf + state->buflen, 0,
-              BLAKE2S_BLOCK_SIZE - state->buflen); /* Padding */
-       if (force_generic)
-               blake2s_compress_generic(state, state->buf, 1, state->buflen);
-       else
-               blake2s_compress(state, state->buf, 1, state->buflen);
-       cpu_to_le32_array(state->h, ARRAY_SIZE(state->h));
-       memcpy(out, state->h, state->outlen);
-}
-
-/* Helper functions for shash implementations of BLAKE2s */
-
-struct blake2s_tfm_ctx {
-       u8 key[BLAKE2S_KEY_SIZE];
-       unsigned int keylen;
-};
-
-static inline int crypto_blake2s_setkey(struct crypto_shash *tfm,
-                                       const u8 *key, unsigned int keylen)
-{
-       struct blake2s_tfm_ctx *tctx = crypto_shash_ctx(tfm);
-
-       if (keylen == 0 || keylen > BLAKE2S_KEY_SIZE)
-               return -EINVAL;
-
-       memcpy(tctx->key, key, keylen);
-       tctx->keylen = keylen;
-
-       return 0;
-}
-
-static inline int crypto_blake2s_init(struct shash_desc *desc)
-{
-       const struct blake2s_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm);
-       struct blake2s_state *state = shash_desc_ctx(desc);
-       unsigned int outlen = crypto_shash_digestsize(desc->tfm);
-
-       __blake2s_init(state, outlen, tctx->key, tctx->keylen);
-       return 0;
-}
-
-static inline int crypto_blake2s_update(struct shash_desc *desc,
-                                       const u8 *in, unsigned int inlen,
-                                       bool force_generic)
-{
-       struct blake2s_state *state = shash_desc_ctx(desc);
-
-       __blake2s_update(state, in, inlen, force_generic);
-       return 0;
-}
-
-static inline int crypto_blake2s_final(struct shash_desc *desc, u8 *out,
-                                      bool force_generic)
-{
-       struct blake2s_state *state = shash_desc_ctx(desc);
-
-       __blake2s_final(state, out, force_generic);
-       return 0;
-}
-
 #endif /* _CRYPTO_INTERNAL_BLAKE2S_H */
diff --git a/include/crypto/polyval.h b/include/crypto/polyval.h
new file mode 100644 (file)
index 0000000..1d630f3
--- /dev/null
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Common values for the Polyval hash algorithm
+ *
+ * Copyright 2021 Google LLC
+ */
+
+#ifndef _CRYPTO_POLYVAL_H
+#define _CRYPTO_POLYVAL_H
+
+#include <linux/types.h>
+#include <linux/crypto.h>
+
+#define POLYVAL_BLOCK_SIZE     16
+#define POLYVAL_DIGEST_SIZE    16
+
+void polyval_mul_non4k(u8 *op1, const u8 *op2);
+
+void polyval_update_non4k(const u8 *key, const u8 *in,
+                         size_t nblocks, u8 *accumulator);
+
+#endif
index 0fca8f3..addb135 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/dma-fence.h>
 #include <linux/completion.h>
 #include <linux/xarray.h>
-#include <linux/irq_work.h>
+#include <linux/workqueue.h>
 
 #define MAX_WAIT_SCHED_ENTITY_Q_EMPTY msecs_to_jiffies(1000)
 
@@ -295,7 +295,7 @@ struct drm_sched_job {
         */
        union {
                struct dma_fence_cb             finish_cb;
-               struct irq_work                 work;
+               struct work_struct              work;
        };
 
        uint64_t                        id;
index 1f87016..8256e74 100644 (file)
 #define CLK_GOUT_PERI_USI0             43
 #define CLK_GOUT_PERI_USI1             44
 #define CLK_GOUT_PERI_USI2             45
-#define TOP_NR_CLK                     46
+#define CLK_MOUT_FSYS_BUS              46
+#define CLK_MOUT_FSYS_MMC_CARD         47
+#define CLK_MOUT_FSYS_MMC_EMBD         48
+#define CLK_MOUT_FSYS_MMC_SDIO         49
+#define CLK_MOUT_FSYS_USB30DRD         50
+#define CLK_DOUT_FSYS_BUS              51
+#define CLK_DOUT_FSYS_MMC_CARD         52
+#define CLK_DOUT_FSYS_MMC_EMBD         53
+#define CLK_DOUT_FSYS_MMC_SDIO         54
+#define CLK_DOUT_FSYS_USB30DRD         55
+#define CLK_GOUT_FSYS_BUS              56
+#define CLK_GOUT_FSYS_MMC_CARD         57
+#define CLK_GOUT_FSYS_MMC_EMBD         58
+#define CLK_GOUT_FSYS_MMC_SDIO         59
+#define CLK_GOUT_FSYS_USB30DRD         60
+#define TOP_NR_CLK                     61
 
 /* CMU_CORE */
-#define CLK_MOUT_CORE_BUS_USER         1
-#define CLK_MOUT_CORE_CCI_USER         2
-#define CLK_MOUT_CORE_G3D_USER         3
-#define CLK_MOUT_CORE_GIC              4
-#define CLK_DOUT_CORE_BUSP             5
-#define CLK_GOUT_CCI_ACLK              6
-#define CLK_GOUT_GIC400_CLK            7
-#define CORE_NR_CLK                    8
+#define CLK_MOUT_CORE_BUS_USER                 1
+#define CLK_MOUT_CORE_CCI_USER                 2
+#define CLK_MOUT_CORE_G3D_USER                 3
+#define CLK_MOUT_CORE_GIC                      4
+#define CLK_DOUT_CORE_BUSP                     5
+#define CLK_GOUT_CCI_ACLK                      6
+#define CLK_GOUT_GIC400_CLK                    7
+#define CLK_GOUT_TREX_D_CORE_ACLK              8
+#define CLK_GOUT_TREX_D_CORE_GCLK              9
+#define CLK_GOUT_TREX_D_CORE_PCLK              10
+#define CLK_GOUT_TREX_P_CORE_ACLK_P_CORE       11
+#define CLK_GOUT_TREX_P_CORE_CCLK_P_CORE       12
+#define CLK_GOUT_TREX_P_CORE_PCLK              13
+#define CLK_GOUT_TREX_P_CORE_PCLK_P_CORE       14
+#define CORE_NR_CLK                            15
 
 /* CMU_PERI */
 #define CLK_MOUT_PERI_BUS_USER         1
 #define CLK_GOUT_WDT1_PCLK             43
 #define PERI_NR_CLK                    44
 
+/* CMU_FSYS */
+#define CLK_MOUT_FSYS_BUS_USER         1
+#define CLK_MOUT_FSYS_MMC_CARD_USER    2
+#define CLK_MOUT_FSYS_MMC_EMBD_USER    3
+#define CLK_MOUT_FSYS_MMC_SDIO_USER    4
+#define CLK_MOUT_FSYS_USB30DRD_USER    4
+#define CLK_GOUT_MMC_CARD_ACLK         5
+#define CLK_GOUT_MMC_CARD_SDCLKIN      6
+#define CLK_GOUT_MMC_EMBD_ACLK         7
+#define CLK_GOUT_MMC_EMBD_SDCLKIN      8
+#define CLK_GOUT_MMC_SDIO_ACLK         9
+#define CLK_GOUT_MMC_SDIO_SDCLKIN      10
+#define FSYS_NR_CLK                    11
+
 #endif /* _DT_BINDINGS_CLOCK_EXYNOS_7885_H */
diff --git a/include/dt-bindings/clock/nuvoton,npcm845-clk.h b/include/dt-bindings/clock/nuvoton,npcm845-clk.h
new file mode 100644 (file)
index 0000000..e5cce08
--- /dev/null
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (C) 2021 Nuvoton Technologies.
+ * Author: Tomer Maimon <tomer.maimon@nuvoton.com>
+ *
+ * Device Tree binding constants for NPCM8XX clock controller.
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_NPCM8XX_H
+#define __DT_BINDINGS_CLOCK_NPCM8XX_H
+
+#define NPCM8XX_CLK_CPU                0
+#define NPCM8XX_CLK_GFX_PIXEL  1
+#define NPCM8XX_CLK_MC         2
+#define NPCM8XX_CLK_ADC                3
+#define NPCM8XX_CLK_AHB                4
+#define NPCM8XX_CLK_TIMER      5
+#define NPCM8XX_CLK_UART       6
+#define NPCM8XX_CLK_UART2      7
+#define NPCM8XX_CLK_MMC                8
+#define NPCM8XX_CLK_SPI3       9
+#define NPCM8XX_CLK_PCI                10
+#define NPCM8XX_CLK_AXI                11
+#define NPCM8XX_CLK_APB4       12
+#define NPCM8XX_CLK_APB3       13
+#define NPCM8XX_CLK_APB2       14
+#define NPCM8XX_CLK_APB1       15
+#define NPCM8XX_CLK_APB5       16
+#define NPCM8XX_CLK_CLKOUT     17
+#define NPCM8XX_CLK_GFX                18
+#define NPCM8XX_CLK_SU         19
+#define NPCM8XX_CLK_SU48       20
+#define NPCM8XX_CLK_SDHC       21
+#define NPCM8XX_CLK_SPI0       22
+#define NPCM8XX_CLK_SPI1       23
+#define NPCM8XX_CLK_SPIX       24
+#define NPCM8XX_CLK_RG         25
+#define NPCM8XX_CLK_RCP                26
+#define NPCM8XX_CLK_PRE_ADC    27
+#define NPCM8XX_CLK_ATB                28
+#define NPCM8XX_CLK_PRE_CLK    29
+#define NPCM8XX_CLK_TH         30
+#define NPCM8XX_CLK_REFCLK     31
+#define NPCM8XX_CLK_SYSBYPCK   32
+#define NPCM8XX_CLK_MCBYPCK    33
+
+#define NPCM8XX_NUM_CLOCKS     (NPCM8XX_CLK_MCBYPCK + 1)
+
+#endif
diff --git a/include/dt-bindings/clock/qcom,dispcc-sm8350.h b/include/dt-bindings/clock/qcom,dispcc-sm8350.h
new file mode 120000 (symlink)
index 0000000..0312b45
--- /dev/null
@@ -0,0 +1 @@
+qcom,dispcc-sm8250.h
\ No newline at end of file
index 8e2bec1..55f8322 100644 (file)
 #define GCC_PCIE1_AXI_MASTER_STICKY_ARES       130
 #define GCC_PCIE0_AXI_SLAVE_STICKY_ARES                131
 
+#define USB0_GDSC                              0
+#define USB1_GDSC                              1
+
 #endif
diff --git a/include/dt-bindings/clock/qcom,gpucc-sm8350.h b/include/dt-bindings/clock/qcom,gpucc-sm8350.h
new file mode 100644 (file)
index 0000000..2ca857f
--- /dev/null
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) 2022, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _DT_BINDINGS_CLK_QCOM_GPU_CC_SM8350_H
+#define _DT_BINDINGS_CLK_QCOM_GPU_CC_SM8350_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_APB_CLK              3
+#define GPU_CC_CX_GMU_CLK              4
+#define GPU_CC_CX_QDSS_AT_CLK          5
+#define GPU_CC_CX_QDSS_TRIG_CLK                6
+#define GPU_CC_CX_QDSS_TSCTR_CLK       7
+#define GPU_CC_CX_SNOC_DVM_CLK         8
+#define GPU_CC_CXO_AON_CLK             9
+#define GPU_CC_CXO_CLK                 10
+#define GPU_CC_FREQ_MEASURE_CLK                11
+#define GPU_CC_GMU_CLK_SRC             12
+#define GPU_CC_GX_GMU_CLK              13
+#define GPU_CC_GX_QDSS_TSCTR_CLK       14
+#define GPU_CC_GX_VSENSE_CLK           15
+#define GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK 16
+#define GPU_CC_HUB_AHB_DIV_CLK_SRC     17
+#define GPU_CC_HUB_AON_CLK             18
+#define GPU_CC_HUB_CLK_SRC             19
+#define GPU_CC_HUB_CX_INT_CLK          20
+#define GPU_CC_HUB_CX_INT_DIV_CLK_SRC  21
+#define GPU_CC_MND1X_0_GFX3D_CLK       22
+#define GPU_CC_MND1X_1_GFX3D_CLK       23
+#define GPU_CC_PLL0                    24
+#define GPU_CC_PLL1                    25
+#define GPU_CC_SLEEP_CLK               26
+
+/* GPU_CC resets */
+#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_GFX3D_AON_BCR     4
+#define GPUCC_GPU_CC_GMU_BCR           5
+#define GPUCC_GPU_CC_GX_BCR            6
+#define GPUCC_GPU_CC_XO_BCR            7
+
+/* GPU_CC GDSCRs */
+#define GPU_CX_GDSC                    0
+#define GPU_GX_GDSC                    1
+
+#endif
diff --git a/include/dt-bindings/clock/qcom,sm8450-camcc.h b/include/dt-bindings/clock/qcom,sm8450-camcc.h
new file mode 100644 (file)
index 0000000..7ff67ac
--- /dev/null
@@ -0,0 +1,159 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _DT_BINDINGS_CLK_QCOM_CAM_CC_SM8450_H
+#define _DT_BINDINGS_CLK_QCOM_CAM_CC_SM8450_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_CLK                                  4
+#define CAM_CC_CAMNOC_AXI_CLK_SRC                              5
+#define CAM_CC_CAMNOC_DCD_XO_CLK                               6
+#define CAM_CC_CCI_0_CLK                                       7
+#define CAM_CC_CCI_0_CLK_SRC                                   8
+#define CAM_CC_CCI_1_CLK                                       9
+#define CAM_CC_CCI_1_CLK_SRC                                   10
+#define CAM_CC_CORE_AHB_CLK                                    11
+#define CAM_CC_CPAS_AHB_CLK                                    12
+#define CAM_CC_CPAS_BPS_CLK                                    13
+#define CAM_CC_CPAS_FAST_AHB_CLK                               14
+#define CAM_CC_CPAS_IFE_0_CLK                                  15
+#define CAM_CC_CPAS_IFE_1_CLK                                  16
+#define CAM_CC_CPAS_IFE_2_CLK                                  17
+#define CAM_CC_CPAS_IFE_LITE_CLK                               18
+#define CAM_CC_CPAS_IPE_NPS_CLK                                        19
+#define CAM_CC_CPAS_SBI_CLK                                    20
+#define CAM_CC_CPAS_SFE_0_CLK                                  21
+#define CAM_CC_CPAS_SFE_1_CLK                                  22
+#define CAM_CC_CPHY_RX_CLK_SRC                                 23
+#define CAM_CC_CSI0PHYTIMER_CLK                                        24
+#define CAM_CC_CSI0PHYTIMER_CLK_SRC                            25
+#define CAM_CC_CSI1PHYTIMER_CLK                                        26
+#define CAM_CC_CSI1PHYTIMER_CLK_SRC                            27
+#define CAM_CC_CSI2PHYTIMER_CLK                                        28
+#define CAM_CC_CSI2PHYTIMER_CLK_SRC                            29
+#define CAM_CC_CSI3PHYTIMER_CLK                                        30
+#define CAM_CC_CSI3PHYTIMER_CLK_SRC                            31
+#define CAM_CC_CSI4PHYTIMER_CLK                                        32
+#define CAM_CC_CSI4PHYTIMER_CLK_SRC                            33
+#define CAM_CC_CSI5PHYTIMER_CLK                                        34
+#define CAM_CC_CSI5PHYTIMER_CLK_SRC                            35
+#define CAM_CC_CSID_CLK                                                36
+#define CAM_CC_CSID_CLK_SRC                                    37
+#define CAM_CC_CSID_CSIPHY_RX_CLK                              38
+#define CAM_CC_CSIPHY0_CLK                                     39
+#define CAM_CC_CSIPHY1_CLK                                     40
+#define CAM_CC_CSIPHY2_CLK                                     41
+#define CAM_CC_CSIPHY3_CLK                                     42
+#define CAM_CC_CSIPHY4_CLK                                     43
+#define CAM_CC_CSIPHY5_CLK                                     44
+#define CAM_CC_FAST_AHB_CLK_SRC                                        45
+#define CAM_CC_GDSC_CLK                                                46
+#define CAM_CC_ICP_AHB_CLK                                     47
+#define CAM_CC_ICP_CLK                                         48
+#define CAM_CC_ICP_CLK_SRC                                     49
+#define CAM_CC_IFE_0_CLK                                       50
+#define CAM_CC_IFE_0_CLK_SRC                                   51
+#define CAM_CC_IFE_0_DSP_CLK                                   52
+#define CAM_CC_IFE_0_FAST_AHB_CLK                              53
+#define CAM_CC_IFE_1_CLK                                       54
+#define CAM_CC_IFE_1_CLK_SRC                                   55
+#define CAM_CC_IFE_1_DSP_CLK                                   56
+#define CAM_CC_IFE_1_FAST_AHB_CLK                              57
+#define CAM_CC_IFE_2_CLK                                       58
+#define CAM_CC_IFE_2_CLK_SRC                                   59
+#define CAM_CC_IFE_2_DSP_CLK                                   60
+#define CAM_CC_IFE_2_FAST_AHB_CLK                              61
+#define CAM_CC_IFE_LITE_AHB_CLK                                        62
+#define CAM_CC_IFE_LITE_CLK                                    63
+#define CAM_CC_IFE_LITE_CLK_SRC                                        64
+#define CAM_CC_IFE_LITE_CPHY_RX_CLK                            65
+#define CAM_CC_IFE_LITE_CSID_CLK                               66
+#define CAM_CC_IFE_LITE_CSID_CLK_SRC                           67
+#define CAM_CC_IPE_NPS_AHB_CLK                                 68
+#define CAM_CC_IPE_NPS_CLK                                     69
+#define CAM_CC_IPE_NPS_CLK_SRC                                 70
+#define CAM_CC_IPE_NPS_FAST_AHB_CLK                            71
+#define CAM_CC_IPE_PPS_CLK                                     72
+#define CAM_CC_IPE_PPS_FAST_AHB_CLK                            73
+#define CAM_CC_JPEG_CLK                                                74
+#define CAM_CC_JPEG_CLK_SRC                                    75
+#define CAM_CC_MCLK0_CLK                                       76
+#define CAM_CC_MCLK0_CLK_SRC                                   77
+#define CAM_CC_MCLK1_CLK                                       78
+#define CAM_CC_MCLK1_CLK_SRC                                   79
+#define CAM_CC_MCLK2_CLK                                       80
+#define CAM_CC_MCLK2_CLK_SRC                                   81
+#define CAM_CC_MCLK3_CLK                                       82
+#define CAM_CC_MCLK3_CLK_SRC                                   83
+#define CAM_CC_MCLK4_CLK                                       84
+#define CAM_CC_MCLK4_CLK_SRC                                   85
+#define CAM_CC_MCLK5_CLK                                       86
+#define CAM_CC_MCLK5_CLK_SRC                                   87
+#define CAM_CC_MCLK6_CLK                                       88
+#define CAM_CC_MCLK6_CLK_SRC                                   89
+#define CAM_CC_MCLK7_CLK                                       90
+#define CAM_CC_MCLK7_CLK_SRC                                   91
+#define CAM_CC_PLL0                                            92
+#define CAM_CC_PLL0_OUT_EVEN                                   93
+#define CAM_CC_PLL0_OUT_ODD                                    94
+#define CAM_CC_PLL1                                            95
+#define CAM_CC_PLL1_OUT_EVEN                                   96
+#define CAM_CC_PLL2                                            97
+#define CAM_CC_PLL3                                            98
+#define CAM_CC_PLL3_OUT_EVEN                                   99
+#define CAM_CC_PLL4                                            100
+#define CAM_CC_PLL4_OUT_EVEN                                   101
+#define CAM_CC_PLL5                                            102
+#define CAM_CC_PLL5_OUT_EVEN                                   103
+#define CAM_CC_PLL6                                            104
+#define CAM_CC_PLL6_OUT_EVEN                                   105
+#define CAM_CC_PLL7                                            106
+#define CAM_CC_PLL7_OUT_EVEN                                   107
+#define CAM_CC_PLL8                                            108
+#define CAM_CC_PLL8_OUT_EVEN                                   109
+#define CAM_CC_QDSS_DEBUG_CLK                                  110
+#define CAM_CC_QDSS_DEBUG_CLK_SRC                              111
+#define CAM_CC_QDSS_DEBUG_XO_CLK                               112
+#define CAM_CC_SBI_AHB_CLK                                     113
+#define CAM_CC_SBI_CLK                                         114
+#define CAM_CC_SFE_0_CLK                                       115
+#define CAM_CC_SFE_0_CLK_SRC                                   116
+#define CAM_CC_SFE_0_FAST_AHB_CLK                              117
+#define CAM_CC_SFE_1_CLK                                       118
+#define CAM_CC_SFE_1_CLK_SRC                                   119
+#define CAM_CC_SFE_1_FAST_AHB_CLK                              120
+#define CAM_CC_SLEEP_CLK                                       121
+#define CAM_CC_SLEEP_CLK_SRC                                   122
+#define CAM_CC_SLOW_AHB_CLK_SRC                                        123
+#define CAM_CC_XO_CLK_SRC                                      124
+
+/* 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_IFE_2_BCR                                       4
+#define CAM_CC_IPE_0_BCR                                       5
+#define CAM_CC_QDSS_DEBUG_BCR                                  6
+#define CAM_CC_SBI_BCR                                         7
+#define CAM_CC_SFE_0_BCR                                       8
+#define CAM_CC_SFE_1_BCR                                       9
+
+/* CAM_CC GDSCRs */
+#define BPS_GDSC               0
+#define IPE_0_GDSC             1
+#define SBI_GDSC               2
+#define IFE_0_GDSC             3
+#define IFE_1_GDSC             4
+#define IFE_2_GDSC             5
+#define SFE_0_GDSC             6
+#define SFE_1_GDSC             7
+#define TITAN_TOP_GDSC         8
+
+#endif
diff --git a/include/dt-bindings/clock/sunplus,sp7021-clkc.h b/include/dt-bindings/clock/sunplus,sp7021-clkc.h
new file mode 100644 (file)
index 0000000..cd84321
--- /dev/null
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (C) Sunplus Technology Co., Ltd.
+ *       All rights reserved.
+ */
+#ifndef _DT_BINDINGS_CLOCK_SUNPLUS_SP7021_H
+#define _DT_BINDINGS_CLOCK_SUNPLUS_SP7021_H
+
+/* gates */
+#define CLK_RTC         0
+#define CLK_OTPRX       1
+#define CLK_NOC         2
+#define CLK_BR          3
+#define CLK_SPIFL       4
+#define CLK_PERI0       5
+#define CLK_PERI1       6
+#define CLK_STC0        7
+#define CLK_STC_AV0     8
+#define CLK_STC_AV1     9
+#define CLK_STC_AV2     10
+#define CLK_UA0         11
+#define CLK_UA1         12
+#define CLK_UA2         13
+#define CLK_UA3         14
+#define CLK_UA4         15
+#define CLK_HWUA        16
+#define CLK_DDC0        17
+#define CLK_UADMA       18
+#define CLK_CBDMA0      19
+#define CLK_CBDMA1      20
+#define CLK_SPI_COMBO_0 21
+#define CLK_SPI_COMBO_1 22
+#define CLK_SPI_COMBO_2 23
+#define CLK_SPI_COMBO_3 24
+#define CLK_AUD         25
+#define CLK_USBC0       26
+#define CLK_USBC1       27
+#define CLK_UPHY0       28
+#define CLK_UPHY1       29
+#define CLK_I2CM0       30
+#define CLK_I2CM1       31
+#define CLK_I2CM2       32
+#define CLK_I2CM3       33
+#define CLK_PMC         34
+#define CLK_CARD_CTL0   35
+#define CLK_CARD_CTL1   36
+#define CLK_CARD_CTL4   37
+#define CLK_BCH         38
+#define CLK_DDFCH       39
+#define CLK_CSIIW0      40
+#define CLK_CSIIW1      41
+#define CLK_MIPICSI0    42
+#define CLK_MIPICSI1    43
+#define CLK_HDMI_TX     44
+#define CLK_VPOST       45
+#define CLK_TGEN        46
+#define CLK_DMIX        47
+#define CLK_TCON        48
+#define CLK_GPIO        49
+#define CLK_MAILBOX     50
+#define CLK_SPIND       51
+#define CLK_I2C2CBUS    52
+#define CLK_SEC         53
+#define CLK_DVE         54
+#define CLK_GPOST0      55
+#define CLK_OSD0        56
+#define CLK_DISP_PWM    57
+#define CLK_UADBG       58
+#define CLK_FIO_CTL     59
+#define CLK_FPGA        60
+#define CLK_L2SW        61
+#define CLK_ICM         62
+#define CLK_AXI_GLOBAL  63
+
+/* plls */
+#define PLL_A           64
+#define PLL_E           65
+#define PLL_E_2P5       66
+#define PLL_E_25        67
+#define PLL_E_112P5     68
+#define PLL_F           69
+#define PLL_TV          70
+#define PLL_TV_A        71
+#define PLL_SYS         72
+
+#define CLK_MAX         73
+
+#endif
index bd4c308..173364a 100644 (file)
@@ -38,6 +38,8 @@
  * throughput and memory controller power.
  */
 #define TEGRA234_CLK_EMC                       31U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X */
+#define TEGRA234_CLK_HOST1X                     46U
 /** @brief output of gate CLK_ENB_FUSE */
 #define TEGRA234_CLK_FUSE                      40U
 /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 */
 #define TEGRA234_CLK_UARTA                     155U
 /** @brief output of gate CLK_ENB_PEX1_CORE_6 */
 #define TEGRA234_CLK_PEX1_C6_CORE              161U
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_VIC */
+#define TEGRA234_CLK_VIC                        167U
 /** @brief output of gate CLK_ENB_PEX2_CORE_7 */
 #define TEGRA234_CLK_PEX2_C7_CORE              171U
 /** @brief output of gate CLK_ENB_PEX2_CORE_8 */
 #define TEGRA234_CLK_PEX1_C5_CORE              225U
 /** @brief PLL controlled by CLK_RST_CONTROLLER_PLLC4_BASE */
 #define TEGRA234_CLK_PLLC4                     237U
+/** @brief RX clock recovered from MGBE0 lane input */
+#define TEGRA234_CLK_MGBE0_RX_INPUT            248U
+/** @brief RX clock recovered from MGBE1 lane input */
+#define TEGRA234_CLK_MGBE1_RX_INPUT            249U
+/** @brief RX clock recovered from MGBE2 lane input */
+#define TEGRA234_CLK_MGBE2_RX_INPUT            250U
+/** @brief RX clock recovered from MGBE3 lane input */
+#define TEGRA234_CLK_MGBE3_RX_INPUT            251U
 /** @brief 32K input clock provided by PMIC */
 #define TEGRA234_CLK_CLK_32K                   289U
+/** @brief Monitored branch of MBGE0 RX input clock */
+#define TEGRA234_CLK_MGBE0_RX_INPUT_M          357U
+/** @brief Monitored branch of MBGE1 RX input clock */
+#define TEGRA234_CLK_MGBE1_RX_INPUT_M          358U
+/** @brief Monitored branch of MBGE2 RX input clock */
+#define TEGRA234_CLK_MGBE2_RX_INPUT_M          359U
+/** @brief Monitored branch of MBGE3 RX input clock */
+#define TEGRA234_CLK_MGBE3_RX_INPUT_M          360U
+/** @brief Monitored branch of MGBE0 RX PCS mux output */
+#define TEGRA234_CLK_MGBE0_RX_PCS_M            361U
+/** @brief Monitored branch of MGBE1 RX PCS mux output */
+#define TEGRA234_CLK_MGBE1_RX_PCS_M            362U
+/** @brief Monitored branch of MGBE2 RX PCS mux output */
+#define TEGRA234_CLK_MGBE2_RX_PCS_M            363U
+/** @brief Monitored branch of MGBE3 RX PCS mux output */
+#define TEGRA234_CLK_MGBE3_RX_PCS_M            364U
+/** @brief RX PCS clock recovered from MGBE0 lane input */
+#define TEGRA234_CLK_MGBE0_RX_PCS_INPUT                369U
+/** @brief RX PCS clock recovered from MGBE1 lane input */
+#define TEGRA234_CLK_MGBE1_RX_PCS_INPUT                370U
+/** @brief RX PCS clock recovered from MGBE2 lane input */
+#define TEGRA234_CLK_MGBE2_RX_PCS_INPUT                371U
+/** @brief RX PCS clock recovered from MGBE3 lane input */
+#define TEGRA234_CLK_MGBE3_RX_PCS_INPUT                372U
+/** @brief output of mux controlled by GBE_UPHY_MGBE0_RX_PCS_CLK_SRC_SEL */
+#define TEGRA234_CLK_MGBE0_RX_PCS              373U
+/** @brief GBE_UPHY_MGBE0_TX_CLK divider gated output */
+#define TEGRA234_CLK_MGBE0_TX                  374U
+/** @brief GBE_UPHY_MGBE0_TX_PCS_CLK divider gated output */
+#define TEGRA234_CLK_MGBE0_TX_PCS              375U
+/** @brief GBE_UPHY_MGBE0_MAC_CLK divider output */
+#define TEGRA234_CLK_MGBE0_MAC_DIVIDER         376U
+/** @brief GBE_UPHY_MGBE0_MAC_CLK gate output */
+#define TEGRA234_CLK_MGBE0_MAC                 377U
+/** @brief GBE_UPHY_MGBE0_MACSEC_CLK gate output */
+#define TEGRA234_CLK_MGBE0_MACSEC              378U
+/** @brief GBE_UPHY_MGBE0_EEE_PCS_CLK gate output */
+#define TEGRA234_CLK_MGBE0_EEE_PCS             379U
+/** @brief GBE_UPHY_MGBE0_APP_CLK gate output */
+#define TEGRA234_CLK_MGBE0_APP                 380U
+/** @brief GBE_UPHY_MGBE0_PTP_REF_CLK divider gated output */
+#define TEGRA234_CLK_MGBE0_PTP_REF             381U
+/** @brief output of mux controlled by GBE_UPHY_MGBE1_RX_PCS_CLK_SRC_SEL */
+#define TEGRA234_CLK_MGBE1_RX_PCS              382U
+/** @brief GBE_UPHY_MGBE1_TX_CLK divider gated output */
+#define TEGRA234_CLK_MGBE1_TX                  383U
+/** @brief GBE_UPHY_MGBE1_TX_PCS_CLK divider gated output */
+#define TEGRA234_CLK_MGBE1_TX_PCS              384U
+/** @brief GBE_UPHY_MGBE1_MAC_CLK divider output */
+#define TEGRA234_CLK_MGBE1_MAC_DIVIDER         385U
+/** @brief GBE_UPHY_MGBE1_MAC_CLK gate output */
+#define TEGRA234_CLK_MGBE1_MAC                 386U
+/** @brief GBE_UPHY_MGBE1_EEE_PCS_CLK gate output */
+#define TEGRA234_CLK_MGBE1_EEE_PCS             388U
+/** @brief GBE_UPHY_MGBE1_APP_CLK gate output */
+#define TEGRA234_CLK_MGBE1_APP                 389U
+/** @brief GBE_UPHY_MGBE1_PTP_REF_CLK divider gated output */
+#define TEGRA234_CLK_MGBE1_PTP_REF             390U
+/** @brief output of mux controlled by GBE_UPHY_MGBE2_RX_PCS_CLK_SRC_SEL */
+#define TEGRA234_CLK_MGBE2_RX_PCS              391U
+/** @brief GBE_UPHY_MGBE2_TX_CLK divider gated output */
+#define TEGRA234_CLK_MGBE2_TX                  392U
+/** @brief GBE_UPHY_MGBE2_TX_PCS_CLK divider gated output */
+#define TEGRA234_CLK_MGBE2_TX_PCS              393U
+/** @brief GBE_UPHY_MGBE2_MAC_CLK divider output */
+#define TEGRA234_CLK_MGBE2_MAC_DIVIDER         394U
+/** @brief GBE_UPHY_MGBE2_MAC_CLK gate output */
+#define TEGRA234_CLK_MGBE2_MAC                 395U
+/** @brief GBE_UPHY_MGBE2_EEE_PCS_CLK gate output */
+#define TEGRA234_CLK_MGBE2_EEE_PCS             397U
+/** @brief GBE_UPHY_MGBE2_APP_CLK gate output */
+#define TEGRA234_CLK_MGBE2_APP                 398U
+/** @brief GBE_UPHY_MGBE2_PTP_REF_CLK divider gated output */
+#define TEGRA234_CLK_MGBE2_PTP_REF             399U
+/** @brief output of mux controlled by GBE_UPHY_MGBE3_RX_PCS_CLK_SRC_SEL */
+#define TEGRA234_CLK_MGBE3_RX_PCS              400U
+/** @brief GBE_UPHY_MGBE3_TX_CLK divider gated output */
+#define TEGRA234_CLK_MGBE3_TX                  401U
+/** @brief GBE_UPHY_MGBE3_TX_PCS_CLK divider gated output */
+#define TEGRA234_CLK_MGBE3_TX_PCS              402U
+/** @brief GBE_UPHY_MGBE3_MAC_CLK divider output */
+#define TEGRA234_CLK_MGBE3_MAC_DIVIDER         403U
+/** @brief GBE_UPHY_MGBE3_MAC_CLK gate output */
+#define TEGRA234_CLK_MGBE3_MAC                 404U
+/** @brief GBE_UPHY_MGBE3_MACSEC_CLK gate output */
+#define TEGRA234_CLK_MGBE3_MACSEC              405U
+/** @brief GBE_UPHY_MGBE3_EEE_PCS_CLK gate output */
+#define TEGRA234_CLK_MGBE3_EEE_PCS             406U
+/** @brief GBE_UPHY_MGBE3_APP_CLK gate output */
+#define TEGRA234_CLK_MGBE3_APP                 407U
+/** @brief GBE_UPHY_MGBE3_PTP_REF_CLK divider gated output */
+#define TEGRA234_CLK_MGBE3_PTP_REF             408U
 /** @brief CLK_RST_CONTROLLER_AZA2XBITCLK_OUT_SWITCH_DIVIDER switch divider output (aza_2xbitclk) */
 #define TEGRA234_CLK_AZA_2XBIT                 457U
 /** @brief aza_2xbitclk / 2 (aza_bitclk) */
 #define TEGRA234_CLK_AZA_BIT                   458U
+
 #endif
index 9296d0b..fbfa3fe 100644 (file)
@@ -30,6 +30,7 @@
 #define IPCC_CLIENT_PCIE1              14
 #define IPCC_CLIENT_PCIE2              15
 #define IPCC_CLIENT_SPSS               16
+#define IPCC_CLIENT_NSP1               18
 #define IPCC_CLIENT_TME                        23
 #define IPCC_CLIENT_WPSS               24
 
index e3b0e9d..62987b4 100644 (file)
 /* NISO0 stream IDs */
 #define TEGRA234_SID_APE       0x02
 #define TEGRA234_SID_HDA       0x03
+#define TEGRA234_SID_GPCDMA    0x04
+#define TEGRA234_SID_MGBE      0x06
 #define TEGRA234_SID_PCIE0     0x12
 #define TEGRA234_SID_PCIE4     0x13
 #define TEGRA234_SID_PCIE5     0x14
 #define TEGRA234_SID_PCIE6     0x15
 #define TEGRA234_SID_PCIE9     0x1f
+#define TEGRA234_SID_MGBE_VF1  0x49
+#define TEGRA234_SID_MGBE_VF2  0x4a
+#define TEGRA234_SID_MGBE_VF3  0x4b
 
 /* NISO1 stream IDs */
 #define TEGRA234_SID_SDMMC4    0x02
@@ -26,6 +31,8 @@
 #define TEGRA234_SID_PCIE8     0x09
 #define TEGRA234_SID_PCIE10    0x0b
 #define TEGRA234_SID_BPMP      0x10
+#define TEGRA234_SID_HOST1X    0x27
+#define TEGRA234_SID_VIC       0x34
 
 /*
  * memory client IDs
@@ -33,6 +40,7 @@
 
 /* High-definition audio (HDA) read clients */
 #define TEGRA234_MEMORY_CLIENT_HDAR 0x15
+#define TEGRA234_MEMORY_CLIENT_HOST1XDMAR 0x16
 /* PCIE6 read clients */
 #define TEGRA234_MEMORY_CLIENT_PCIE6AR 0x28
 /* PCIE6 write clients */
 #define TEGRA234_MEMORY_CLIENT_PCIE10AR1 0x48
 /* PCIE7r1 read clients */
 #define TEGRA234_MEMORY_CLIENT_PCIE7AR1 0x49
+/* MGBE0 read client */
+#define TEGRA234_MEMORY_CLIENT_MGBEARD 0x58
+/* MGBEB read client */
+#define TEGRA234_MEMORY_CLIENT_MGBEBRD 0x59
+/* MGBEC read client */
+#define TEGRA234_MEMORY_CLIENT_MGBECRD 0x5a
+/* MGBED read client */
+#define TEGRA234_MEMORY_CLIENT_MGBEDRD 0x5b
+/* MGBE0 write client */
+#define TEGRA234_MEMORY_CLIENT_MGBEAWR 0x5c
+/* MGBEB write client */
+#define TEGRA234_MEMORY_CLIENT_MGBEBWR 0x5f
+/* MGBEC write client */
+#define TEGRA234_MEMORY_CLIENT_MGBECWR 0x61
 /* sdmmcd memory read client */
 #define TEGRA234_MEMORY_CLIENT_SDMMCRAB 0x63
+/* MGBED write client */
+#define TEGRA234_MEMORY_CLIENT_MGBEDWR 0x65
 /* sdmmcd memory write client */
 #define TEGRA234_MEMORY_CLIENT_SDMMCWAB 0x67
+#define TEGRA234_MEMORY_CLIENT_VICSRD 0x6c
+#define TEGRA234_MEMORY_CLIENT_VICSWR 0x6d
 /* BPMP read client */
 #define TEGRA234_MEMORY_CLIENT_BPMPR 0x93
 /* BPMP write client */
diff --git a/include/dt-bindings/net/pcs-rzn1-miic.h b/include/dt-bindings/net/pcs-rzn1-miic.h
new file mode 100644 (file)
index 0000000..784782e
--- /dev/null
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (C) 2022 Schneider-Electric
+ *
+ * Clément Léger <clement.leger@bootlin.com>
+ */
+
+#ifndef _DT_BINDINGS_PCS_RZN1_MIIC
+#define _DT_BINDINGS_PCS_RZN1_MIIC
+
+/*
+ * Reefer to the datasheet [1] section 8.2.1, Internal Connection of Ethernet
+ * Ports to check the available combination
+ *
+ * [1] REN_r01uh0750ej0140-rzn1-introduction_MAT_20210228.pdf
+ */
+
+#define MIIC_GMAC1_PORT                        0
+#define MIIC_GMAC2_PORT                        1
+#define MIIC_RTOS_PORT                 2
+#define MIIC_SERCOS_PORTA              3
+#define MIIC_SERCOS_PORTB              4
+#define MIIC_ETHERCAT_PORTA            5
+#define MIIC_ETHERCAT_PORTB            6
+#define MIIC_ETHERCAT_PORTC            7
+#define MIIC_SWITCH_PORTA              8
+#define MIIC_SWITCH_PORTB              9
+#define MIIC_SWITCH_PORTC              10
+#define MIIC_SWITCH_PORTD              11
+#define MIIC_HSR_PORTA                 12
+#define MIIC_HSR_PORTB                 13
+
+#endif
diff --git a/include/dt-bindings/power/mt6795-power.h b/include/dt-bindings/power/mt6795-power.h
new file mode 100644 (file)
index 0000000..b0fc26c
--- /dev/null
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+#ifndef _DT_BINDINGS_POWER_MT6795_POWER_H
+#define _DT_BINDINGS_POWER_MT6795_POWER_H
+
+#define MT6795_POWER_DOMAIN_MM         0
+#define MT6795_POWER_DOMAIN_VDEC       1
+#define MT6795_POWER_DOMAIN_VENC       2
+#define MT6795_POWER_DOMAIN_ISP                3
+#define MT6795_POWER_DOMAIN_MJC                4
+#define MT6795_POWER_DOMAIN_AUDIO      5
+#define MT6795_POWER_DOMAIN_MFG_ASYNC  6
+#define MT6795_POWER_DOMAIN_MFG_2D     7
+#define MT6795_POWER_DOMAIN_MFG                8
+#define MT6795_POWER_DOMAIN_MODEM      9
+
+#endif /* _DT_BINDINGS_POWER_MT6795_POWER_H */
index 6cce5b7..d81de63 100644 (file)
 #define MSM8916_VDDMX          3
 #define MSM8916_VDDMX_AO       4
 
+/* MSM8909 Power Domain Indexes */
+#define MSM8909_VDDCX          MSM8916_VDDCX
+#define MSM8909_VDDCX_AO       MSM8916_VDDCX_AO
+#define MSM8909_VDDCX_VFC      MSM8916_VDDCX_VFC
+#define MSM8909_VDDMX          MSM8916_VDDMX
+#define MSM8909_VDDMX_AO       MSM8916_VDDMX_AO
+
 /* MSM8953 Power Domain Indexes */
 #define MSM8953_VDDMD          0
 #define MSM8953_VDDMD_AO       1
index f610eee..ae9286c 100644 (file)
@@ -18,5 +18,7 @@
 #define TEGRA234_POWER_DOMAIN_MGBEA    17U
 #define TEGRA234_POWER_DOMAIN_MGBEB    18U
 #define TEGRA234_POWER_DOMAIN_MGBEC    19U
+#define TEGRA234_POWER_DOMAIN_MGBED    20U
+#define TEGRA234_POWER_DOMAIN_VIC      29U
 
 #endif
diff --git a/include/dt-bindings/reset/sunplus,sp7021-reset.h b/include/dt-bindings/reset/sunplus,sp7021-reset.h
new file mode 100644 (file)
index 0000000..ab48670
--- /dev/null
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (C) Sunplus Technology Co., Ltd.
+ *       All rights reserved.
+ */
+#ifndef _DT_BINDINGS_RST_SUNPLUS_SP7021_H
+#define _DT_BINDINGS_RST_SUNPLUS_SP7021_H
+
+#define RST_SYSTEM              0
+#define RST_RTC                 1
+#define RST_IOCTL               2
+#define RST_IOP                 3
+#define RST_OTPRX               4
+#define RST_NOC                 5
+#define RST_BR                  6
+#define RST_RBUS_L00            7
+#define RST_SPIFL               8
+#define RST_SDCTRL0             9
+#define RST_PERI0               10
+#define RST_A926                11
+#define RST_UMCTL2              12
+#define RST_PERI1               13
+#define RST_DDR_PHY0            14
+#define RST_ACHIP               15
+#define RST_STC0                16
+#define RST_STC_AV0             17
+#define RST_STC_AV1             18
+#define RST_STC_AV2             19
+#define RST_UA0                 20
+#define RST_UA1                 21
+#define RST_UA2                 22
+#define RST_UA3                 23
+#define RST_UA4                 24
+#define RST_HWUA                25
+#define RST_DDC0                26
+#define RST_UADMA               27
+#define RST_CBDMA0              28
+#define RST_CBDMA1              29
+#define RST_SPI_COMBO_0         30
+#define RST_SPI_COMBO_1         31
+#define RST_SPI_COMBO_2         32
+#define RST_SPI_COMBO_3         33
+#define RST_AUD                 34
+#define RST_USBC0               35
+#define RST_USBC1               36
+#define RST_UPHY0               37
+#define RST_UPHY1               38
+#define RST_I2CM0               39
+#define RST_I2CM1               40
+#define RST_I2CM2               41
+#define RST_I2CM3               42
+#define RST_PMC                 43
+#define RST_CARD_CTL0           44
+#define RST_CARD_CTL1           45
+#define RST_CARD_CTL4           46
+#define RST_BCH                 47
+#define RST_DDFCH               48
+#define RST_CSIIW0              49
+#define RST_CSIIW1              50
+#define RST_MIPICSI0            51
+#define RST_MIPICSI1            52
+#define RST_HDMI_TX             53
+#define RST_VPOST               54
+#define RST_TGEN                55
+#define RST_DMIX                56
+#define RST_TCON                57
+#define RST_INTERRUPT           58
+#define RST_RGST                59
+#define RST_GPIO                60
+#define RST_RBUS_TOP            61
+#define RST_MAILBOX             62
+#define RST_SPIND               63
+#define RST_I2C2CBUS            64
+#define RST_SEC                 65
+#define RST_DVE                 66
+#define RST_GPOST0              67
+#define RST_OSD0                68
+#define RST_DISP_PWM            69
+#define RST_UADBG               70
+#define RST_DUMMY_MASTER        71
+#define RST_FIO_CTL             72
+#define RST_FPGA                73
+#define RST_L2SW                74
+#define RST_ICM                 75
+#define RST_AXI_GLOBAL          76
+
+#endif
index 547ca3b..d48d22b 100644 (file)
@@ -15,6 +15,7 @@
 #define TEGRA234_RESET_PEX1_COMMON_APB         13U
 #define TEGRA234_RESET_PEX2_CORE_7             14U
 #define TEGRA234_RESET_PEX2_CORE_7_APB         15U
+#define TEGRA234_RESET_GPCDMA                  18U
 #define TEGRA234_RESET_HDA                     20U
 #define TEGRA234_RESET_HDACODEC                        21U
 #define TEGRA234_RESET_I2C1                    24U
 #define TEGRA234_RESET_I2C7                    33U
 #define TEGRA234_RESET_I2C8                    34U
 #define TEGRA234_RESET_I2C9                    35U
+#define TEGRA234_RESET_MGBE0_PCS               45U
+#define TEGRA234_RESET_MGBE0_MAC               46U
+#define TEGRA234_RESET_MGBE1_PCS               49U
+#define TEGRA234_RESET_MGBE1_MAC               50U
+#define TEGRA234_RESET_MGBE2_PCS               53U
+#define TEGRA234_RESET_MGBE2_MAC               54U
 #define TEGRA234_RESET_PEX2_CORE_10            56U
 #define TEGRA234_RESET_PEX2_CORE_10_APB                57U
 #define TEGRA234_RESET_PEX2_COMMON_APB         58U
 #define TEGRA234_RESET_QSPI0                   76U
 #define TEGRA234_RESET_QSPI1                   77U
 #define TEGRA234_RESET_SDMMC4                  85U
+#define TEGRA234_RESET_MGBE3_PCS               87U
+#define TEGRA234_RESET_MGBE3_MAC               88U
 #define TEGRA234_RESET_UARTA                   100U
+#define TEGRA234_RESET_VIC                      113U
 #define TEGRA234_RESET_PEX0_CORE_0             116U
 #define TEGRA234_RESET_PEX0_CORE_1             117U
 #define TEGRA234_RESET_PEX0_CORE_2             118U
diff --git a/include/dt-bindings/soc/samsung,boot-mode.h b/include/dt-bindings/soc/samsung,boot-mode.h
new file mode 100644 (file)
index 0000000..47ef1cd
--- /dev/null
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Author: Chanho Park <chanho61.park@samsung.com>
+ *
+ * Device Tree bindings for Samsung Boot Mode.
+ */
+
+#ifndef __DT_BINDINGS_SAMSUNG_BOOT_MODE_H
+#define __DT_BINDINGS_SAMSUNG_BOOT_MODE_H
+
+/* Boot mode definitions for Exynos Auto v9 SoC */
+
+#define EXYNOSAUTOV9_BOOT_FASTBOOT     0xfa
+#define EXYNOSAUTOV9_BOOT_BOOTLOADER   0xfc
+#define EXYNOSAUTOV9_BOOT_RECOVERY     0xff
+
+#endif /* __DT_BINDINGS_SAMSUNG_BOOT_MODE_H */
index 8ffcd7d..c958855 100644 (file)
@@ -237,9 +237,9 @@ size_t kunit_suite_num_test_cases(struct kunit_suite *suite);
 unsigned int kunit_test_case_num(struct kunit_suite *suite,
                                 struct kunit_case *test_case);
 
-int __kunit_test_suites_init(struct kunit_suite * const * const suites);
+int __kunit_test_suites_init(struct kunit_suite * const * const suites, int num_suites);
 
-void __kunit_test_suites_exit(struct kunit_suite **suites);
+void __kunit_test_suites_exit(struct kunit_suite **suites, int num_suites);
 
 #if IS_BUILTIN(CONFIG_KUNIT)
 int kunit_run_all_tests(void);
@@ -250,43 +250,11 @@ static inline int kunit_run_all_tests(void)
 }
 #endif /* IS_BUILTIN(CONFIG_KUNIT) */
 
-#ifdef MODULE
-/**
- * kunit_test_suites_for_module() - used to register one or more
- *                      &struct kunit_suite with KUnit.
- *
- * @__suites: a statically allocated list of &struct kunit_suite.
- *
- * Registers @__suites with the test framework. See &struct kunit_suite for
- * more information.
- *
- * If a test suite is built-in, module_init() gets translated into
- * an initcall which we don't want as the idea is that for builtins
- * the executor will manage execution.  So ensure we do not define
- * module_{init|exit} functions for the builtin case when registering
- * suites via kunit_test_suites() below.
- */
-#define kunit_test_suites_for_module(__suites)                         \
-       static int __init kunit_test_suites_init(void)                  \
-       {                                                               \
-               return __kunit_test_suites_init(__suites);              \
-       }                                                               \
-       module_init(kunit_test_suites_init);                            \
-                                                                       \
-       static void __exit kunit_test_suites_exit(void)                 \
-       {                                                               \
-               return __kunit_test_suites_exit(__suites);              \
-       }                                                               \
-       module_exit(kunit_test_suites_exit)
-#else
-#define kunit_test_suites_for_module(__suites)
-#endif /* MODULE */
-
-#define __kunit_test_suites(unique_array, unique_suites, ...)                 \
-       static struct kunit_suite *unique_array[] = { __VA_ARGS__, NULL };     \
-       kunit_test_suites_for_module(unique_array);                            \
-       static struct kunit_suite **unique_suites                              \
-       __used __section(".kunit_test_suites") = unique_array
+#define __kunit_test_suites(unique_array, ...)                                \
+       MODULE_INFO(test, "Y");                                                \
+       static struct kunit_suite *unique_array[]                              \
+       __aligned(sizeof(struct kunit_suite *))                                \
+       __used __section(".kunit_test_suites") = { __VA_ARGS__ }
 
 /**
  * kunit_test_suites() - used to register one or more &struct kunit_suite
@@ -294,21 +262,16 @@ static inline int kunit_run_all_tests(void)
  *
  * @__suites: a statically allocated list of &struct kunit_suite.
  *
- * Registers @suites with the test framework. See &struct kunit_suite for
- * more information.
- *
- * When builtin,  KUnit tests are all run via executor; this is done
- * by placing the array of struct kunit_suite * in the .kunit_test_suites
- * ELF section.
+ * Registers @suites with the test framework.
+ * This is done by placing the array of struct kunit_suite * in the
+ * .kunit_test_suites ELF section.
  *
- * An alternative is to build the tests as a module.  Because modules do not
- * support multiple initcall()s, we need to initialize an array of suites for a
- * module.
+ * When builtin, KUnit tests are all run via the executor at boot, and when
+ * built as a module, they run on module load.
  *
  */
 #define kunit_test_suites(__suites...)                                         \
        __kunit_test_suites(__UNIQUE_ID(array),                         \
-                           __UNIQUE_ID(suites),                        \
                            ##__suites)
 
 #define kunit_test_suite(suite)        kunit_test_suites(&suite)
@@ -320,7 +283,7 @@ static inline int kunit_run_all_tests(void)
  *
  * @__suites: a statically allocated list of &struct kunit_suite.
  *
- * This functions identically as &kunit_test_suites() except that it suppresses
+ * This functions identically as kunit_test_suites() except that it suppresses
  * modpost warnings for referencing functions marked __init or data marked
  * __initdata; this is OK because currently KUnit only runs tests upon boot
  * during the init phase or upon loading a module during the init phase.
index 4f82a5b..7e7a33b 100644 (file)
@@ -105,6 +105,7 @@ enum acpi_irq_model_id {
        ACPI_IRQ_MODEL_IOSAPIC,
        ACPI_IRQ_MODEL_PLATFORM,
        ACPI_IRQ_MODEL_GIC,
+       ACPI_IRQ_MODEL_LPIC,
        ACPI_IRQ_MODEL_COUNT
 };
 
@@ -356,7 +357,8 @@ int acpi_gsi_to_irq (u32 gsi, unsigned int *irq);
 int acpi_isa_irq_to_gsi (unsigned isa_irq, u32 *gsi);
 
 void acpi_set_irq_model(enum acpi_irq_model_id model,
-                       struct fwnode_handle *fwnode);
+                       struct fwnode_handle *(*)(u32));
+void acpi_set_gsi_to_irq_fallback(u32 (*)(u32));
 
 struct irq_domain *acpi_irq_create_hierarchy(unsigned int flags,
                                             unsigned int size,
@@ -584,7 +586,7 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context);
 extern bool osc_sb_apei_support_acked;
 extern bool osc_pc_lpi_support_confirmed;
 extern bool osc_sb_native_usb4_support_confirmed;
-extern bool osc_sb_cppc_not_supported;
+extern bool osc_sb_cppc2_support_acked;
 extern bool osc_cpc_flexible_adr_space_confirmed;
 
 /* USB4 Capabilities */
index 1eb8ee5..a5a1224 100644 (file)
@@ -6,9 +6,11 @@
 #include <linux/acpi.h>
 
 #ifdef CONFIG_ACPI_VIOT
+void __init acpi_viot_early_init(void);
 void __init acpi_viot_init(void);
 int viot_iommu_configure(struct device *dev);
 #else
+static inline void acpi_viot_early_init(void) {}
 static inline void acpi_viot_init(void) {}
 static inline int viot_iommu_configure(struct device *dev)
 {
index cece702..00f7a80 100644 (file)
@@ -119,8 +119,6 @@ enum audit_nfcfgop {
        AUDIT_NFT_OP_INVALID,
 };
 
-extern int is_audit_feature_set(int which);
-
 extern int __init audit_register_class(int class, unsigned *list);
 extern int audit_classify_syscall(int abi, unsigned syscall);
 extern int audit_classify_arch(int arch);
index 992ee98..ca22b06 100644 (file)
@@ -405,7 +405,7 @@ extern void bioset_exit(struct bio_set *);
 extern int biovec_init_pool(mempool_t *pool, int pool_entries);
 
 struct bio *bio_alloc_bioset(struct block_device *bdev, unsigned short nr_vecs,
-                            unsigned int opf, gfp_t gfp_mask,
+                            blk_opf_t opf, gfp_t gfp_mask,
                             struct bio_set *bs);
 struct bio *bio_kmalloc(unsigned short nr_vecs, gfp_t gfp_mask);
 extern void bio_put(struct bio *);
@@ -418,7 +418,7 @@ int bio_init_clone(struct block_device *bdev, struct bio *bio,
 extern struct bio_set fs_bio_set;
 
 static inline struct bio *bio_alloc(struct block_device *bdev,
-               unsigned short nr_vecs, unsigned int opf, gfp_t gfp_mask)
+               unsigned short nr_vecs, blk_opf_t opf, gfp_t gfp_mask)
 {
        return bio_alloc_bioset(bdev, nr_vecs, opf, gfp_mask, &fs_bio_set);
 }
@@ -456,9 +456,9 @@ struct request_queue;
 
 extern int submit_bio_wait(struct bio *bio);
 void bio_init(struct bio *bio, struct block_device *bdev, struct bio_vec *table,
-             unsigned short max_vecs, unsigned int opf);
+             unsigned short max_vecs, blk_opf_t opf);
 extern void bio_uninit(struct bio *);
-void bio_reset(struct bio *bio, struct block_device *bdev, unsigned int opf);
+void bio_reset(struct bio *bio, struct block_device *bdev, blk_opf_t opf);
 void bio_chain(struct bio *, struct bio *);
 
 int bio_add_page(struct bio *, struct page *, unsigned len, unsigned off);
@@ -789,6 +789,6 @@ static inline void bio_clear_polled(struct bio *bio)
 }
 
 struct bio *blk_next_bio(struct bio *bio, struct block_device *bdev,
-               unsigned int nr_pages, unsigned int opf, gfp_t gfp);
+               unsigned int nr_pages, blk_opf_t opf, gfp_t gfp);
 
 #endif /* __LINUX_BIO_H */
index e2d9daf..effee1d 100644 (file)
@@ -57,6 +57,7 @@ typedef __u32 __bitwise req_flags_t;
 #define RQF_TIMED_OUT          ((__force req_flags_t)(1 << 21))
 /* queue has elevator attached */
 #define RQF_ELV                        ((__force req_flags_t)(1 << 22))
+#define RQF_RESV                       ((__force req_flags_t)(1 << 23))
 
 /* flags that prevent us from merging requests: */
 #define RQF_NOMERGE_FLAGS \
@@ -79,7 +80,7 @@ struct request {
        struct blk_mq_ctx *mq_ctx;
        struct blk_mq_hw_ctx *mq_hctx;
 
-       unsigned int cmd_flags;         /* op and common flags */
+       blk_opf_t cmd_flags;            /* op and common flags */
        req_flags_t rq_flags;
 
        int tag;
@@ -197,8 +198,10 @@ struct request {
        void *end_io_data;
 };
 
-#define req_op(req) \
-       ((req)->cmd_flags & REQ_OP_MASK)
+static inline enum req_op req_op(const struct request *req)
+{
+       return req->cmd_flags & REQ_OP_MASK;
+}
 
 static inline bool blk_rq_is_passthrough(struct request *rq)
 {
@@ -519,7 +522,7 @@ struct blk_mq_queue_data {
        bool last;
 };
 
-typedef bool (busy_tag_iter_fn)(struct request *, void *, bool);
+typedef bool (busy_tag_iter_fn)(struct request *, void *);
 
 /**
  * struct blk_mq_ops - Callback functions that implements block driver
@@ -574,7 +577,7 @@ struct blk_mq_ops {
        /**
         * @timeout: Called on request timeout.
         */
-       enum blk_eh_timer_return (*timeout)(struct request *, bool);
+       enum blk_eh_timer_return (*timeout)(struct request *);
 
        /**
         * @poll: Called to poll for completion of a specific tag.
@@ -686,10 +689,12 @@ struct gendisk *__blk_mq_alloc_disk(struct blk_mq_tag_set *set, void *queuedata,
                                                                        \
        __blk_mq_alloc_disk(set, 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 *);
 int blk_mq_init_allocated_queue(struct blk_mq_tag_set *set,
                struct request_queue *q);
-void blk_mq_unregister_dev(struct device *, struct request_queue *);
+void blk_mq_destroy_queue(struct request_queue *);
 
 int blk_mq_alloc_tag_set(struct blk_mq_tag_set *set);
 int blk_mq_alloc_sq_tag_set(struct blk_mq_tag_set *set,
@@ -710,10 +715,10 @@ enum {
        BLK_MQ_REQ_PM           = (__force blk_mq_req_flags_t)(1 << 2),
 };
 
-struct request *blk_mq_alloc_request(struct request_queue *q, unsigned int op,
+struct request *blk_mq_alloc_request(struct request_queue *q, blk_opf_t opf,
                blk_mq_req_flags_t flags);
 struct request *blk_mq_alloc_request_hctx(struct request_queue *q,
-               unsigned int op, blk_mq_req_flags_t flags,
+               blk_opf_t opf, blk_mq_req_flags_t flags,
                unsigned int hctx_idx);
 
 /*
@@ -823,6 +828,11 @@ static inline bool blk_mq_need_time_stamp(struct request *rq)
        return (rq->rq_flags & (RQF_IO_STAT | RQF_STATS | RQF_ELV));
 }
 
+static inline bool blk_mq_is_reserved_rq(struct request *rq)
+{
+       return rq->rq_flags & RQF_RESV;
+}
+
 /*
  * Batched completions only work when there is no I/O error and no special
  * ->end_io handler.
@@ -1121,12 +1131,12 @@ void blk_dump_rq_flags(struct request *, char *);
 #ifdef CONFIG_BLK_DEV_ZONED
 static inline unsigned int blk_rq_zone_no(struct request *rq)
 {
-       return blk_queue_zone_no(rq->q, blk_rq_pos(rq));
+       return disk_zone_no(rq->q->disk, blk_rq_pos(rq));
 }
 
 static inline unsigned int blk_rq_zone_is_seq(struct request *rq)
 {
-       return blk_queue_zone_is_seq(rq->q, blk_rq_pos(rq));
+       return disk_zone_is_seq(rq->q->disk, blk_rq_pos(rq));
 }
 
 bool blk_req_needs_zone_write_lock(struct request *rq);
@@ -1148,8 +1158,8 @@ static inline void blk_req_zone_write_unlock(struct request *rq)
 
 static inline bool blk_req_zone_is_write_locked(struct request *rq)
 {
-       return rq->q->seq_zones_wlock &&
-               test_bit(blk_rq_zone_no(rq), rq->q->seq_zones_wlock);
+       return rq->q->disk->seq_zones_wlock &&
+               test_bit(blk_rq_zone_no(rq), rq->q->disk->seq_zones_wlock);
 }
 
 static inline bool blk_req_can_dispatch_to_zone(struct request *rq)
index a24d407..1ef9979 100644 (file)
@@ -240,6 +240,8 @@ static inline void bio_issue_init(struct bio_issue *issue,
                        ((u64)size << BIO_ISSUE_SIZE_SHIFT));
 }
 
+typedef __u32 __bitwise blk_opf_t;
+
 typedef unsigned int blk_qc_t;
 #define BLK_QC_T_NONE          -1U
 
@@ -250,7 +252,7 @@ typedef unsigned int blk_qc_t;
 struct bio {
        struct bio              *bi_next;       /* request queue link */
        struct block_device     *bi_bdev;
-       unsigned int            bi_opf;         /* bottom bits REQ_OP, top bits
+       blk_opf_t               bi_opf;         /* bottom bits REQ_OP, top bits
                                                 * req_flags.
                                                 */
        unsigned short          bi_flags;       /* BIO_* below */
@@ -337,8 +339,12 @@ enum {
 
 typedef __u32 __bitwise blk_mq_req_flags_t;
 
-/*
- * Operations and flags common to the bio and request structures.
+#define REQ_OP_BITS    8
+#define REQ_OP_MASK    (__force blk_opf_t)((1 << REQ_OP_BITS) - 1)
+#define REQ_FLAG_BITS  24
+
+/**
+ * enum req_op - Operations common to the bio and request structures.
  * We use 8 bits for encoding the operation, and the remaining 24 for flags.
  *
  * The least significant bit of the operation number indicates the data
@@ -350,41 +356,37 @@ typedef __u32 __bitwise blk_mq_req_flags_t;
  * If a operation does not transfer data the least significant bit has no
  * meaning.
  */
-#define REQ_OP_BITS    8
-#define REQ_OP_MASK    ((1 << REQ_OP_BITS) - 1)
-#define REQ_FLAG_BITS  24
-
-enum req_opf {
+enum req_op {
        /* read sectors from the device */
-       REQ_OP_READ             = 0,
+       REQ_OP_READ             = (__force blk_opf_t)0,
        /* write sectors to the device */
-       REQ_OP_WRITE            = 1,
+       REQ_OP_WRITE            = (__force blk_opf_t)1,
        /* flush the volatile write cache */
-       REQ_OP_FLUSH            = 2,
+       REQ_OP_FLUSH            = (__force blk_opf_t)2,
        /* discard sectors */
-       REQ_OP_DISCARD          = 3,
+       REQ_OP_DISCARD          = (__force blk_opf_t)3,
        /* securely erase sectors */
-       REQ_OP_SECURE_ERASE     = 5,
+       REQ_OP_SECURE_ERASE     = (__force blk_opf_t)5,
        /* write the zero filled sector many times */
-       REQ_OP_WRITE_ZEROES     = 9,
+       REQ_OP_WRITE_ZEROES     = (__force blk_opf_t)9,
        /* Open a zone */
-       REQ_OP_ZONE_OPEN        = 10,
+       REQ_OP_ZONE_OPEN        = (__force blk_opf_t)10,
        /* Close a zone */
-       REQ_OP_ZONE_CLOSE       = 11,
+       REQ_OP_ZONE_CLOSE       = (__force blk_opf_t)11,
        /* Transition a zone to full */
-       REQ_OP_ZONE_FINISH      = 12,
+       REQ_OP_ZONE_FINISH      = (__force blk_opf_t)12,
        /* write data at the current zone write pointer */
-       REQ_OP_ZONE_APPEND      = 13,
+       REQ_OP_ZONE_APPEND      = (__force blk_opf_t)13,
        /* reset a zone write pointer */
-       REQ_OP_ZONE_RESET       = 15,
+       REQ_OP_ZONE_RESET       = (__force blk_opf_t)15,
        /* reset all the zone present on the device */
-       REQ_OP_ZONE_RESET_ALL   = 17,
+       REQ_OP_ZONE_RESET_ALL   = (__force blk_opf_t)17,
 
        /* Driver private requests */
-       REQ_OP_DRV_IN           = 34,
-       REQ_OP_DRV_OUT          = 35,
+       REQ_OP_DRV_IN           = (__force blk_opf_t)34,
+       REQ_OP_DRV_OUT          = (__force blk_opf_t)35,
 
-       REQ_OP_LAST,
+       REQ_OP_LAST             = (__force blk_opf_t)36,
 };
 
 enum req_flag_bits {
@@ -425,28 +427,31 @@ enum req_flag_bits {
        __REQ_NR_BITS,          /* stops here */
 };
 
-#define REQ_FAILFAST_DEV       (1ULL << __REQ_FAILFAST_DEV)
-#define REQ_FAILFAST_TRANSPORT (1ULL << __REQ_FAILFAST_TRANSPORT)
-#define REQ_FAILFAST_DRIVER    (1ULL << __REQ_FAILFAST_DRIVER)
-#define REQ_SYNC               (1ULL << __REQ_SYNC)
-#define REQ_META               (1ULL << __REQ_META)
-#define REQ_PRIO               (1ULL << __REQ_PRIO)
-#define REQ_NOMERGE            (1ULL << __REQ_NOMERGE)
-#define REQ_IDLE               (1ULL << __REQ_IDLE)
-#define REQ_INTEGRITY          (1ULL << __REQ_INTEGRITY)
-#define REQ_FUA                        (1ULL << __REQ_FUA)
-#define REQ_PREFLUSH           (1ULL << __REQ_PREFLUSH)
-#define REQ_RAHEAD             (1ULL << __REQ_RAHEAD)
-#define REQ_BACKGROUND         (1ULL << __REQ_BACKGROUND)
-#define REQ_NOWAIT             (1ULL << __REQ_NOWAIT)
-#define REQ_CGROUP_PUNT                (1ULL << __REQ_CGROUP_PUNT)
-
-#define REQ_NOUNMAP            (1ULL << __REQ_NOUNMAP)
-#define REQ_POLLED             (1ULL << __REQ_POLLED)
-#define REQ_ALLOC_CACHE                (1ULL << __REQ_ALLOC_CACHE)
-
-#define REQ_DRV                        (1ULL << __REQ_DRV)
-#define REQ_SWAP               (1ULL << __REQ_SWAP)
+#define REQ_FAILFAST_DEV       \
+                       (__force blk_opf_t)(1ULL << __REQ_FAILFAST_DEV)
+#define REQ_FAILFAST_TRANSPORT \
+                       (__force blk_opf_t)(1ULL << __REQ_FAILFAST_TRANSPORT)
+#define REQ_FAILFAST_DRIVER    \
+                       (__force blk_opf_t)(1ULL << __REQ_FAILFAST_DRIVER)
+#define REQ_SYNC       (__force blk_opf_t)(1ULL << __REQ_SYNC)
+#define REQ_META       (__force blk_opf_t)(1ULL << __REQ_META)
+#define REQ_PRIO       (__force blk_opf_t)(1ULL << __REQ_PRIO)
+#define REQ_NOMERGE    (__force blk_opf_t)(1ULL << __REQ_NOMERGE)
+#define REQ_IDLE       (__force blk_opf_t)(1ULL << __REQ_IDLE)
+#define REQ_INTEGRITY  (__force blk_opf_t)(1ULL << __REQ_INTEGRITY)
+#define REQ_FUA                (__force blk_opf_t)(1ULL << __REQ_FUA)
+#define REQ_PREFLUSH   (__force blk_opf_t)(1ULL << __REQ_PREFLUSH)
+#define REQ_RAHEAD     (__force blk_opf_t)(1ULL << __REQ_RAHEAD)
+#define REQ_BACKGROUND (__force blk_opf_t)(1ULL << __REQ_BACKGROUND)
+#define REQ_NOWAIT     (__force blk_opf_t)(1ULL << __REQ_NOWAIT)
+#define REQ_CGROUP_PUNT        (__force blk_opf_t)(1ULL << __REQ_CGROUP_PUNT)
+
+#define REQ_NOUNMAP    (__force blk_opf_t)(1ULL << __REQ_NOUNMAP)
+#define REQ_POLLED     (__force blk_opf_t)(1ULL << __REQ_POLLED)
+#define REQ_ALLOC_CACHE        (__force blk_opf_t)(1ULL << __REQ_ALLOC_CACHE)
+
+#define REQ_DRV                (__force blk_opf_t)(1ULL << __REQ_DRV)
+#define REQ_SWAP       (__force blk_opf_t)(1ULL << __REQ_SWAP)
 
 #define REQ_FAILFAST_MASK \
        (REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER)
@@ -463,26 +468,28 @@ enum stat_group {
        NR_STAT_GROUPS
 };
 
-#define bio_op(bio) \
-       ((bio)->bi_opf & REQ_OP_MASK)
+static inline enum req_op bio_op(const struct bio *bio)
+{
+       return bio->bi_opf & REQ_OP_MASK;
+}
 
 /* obsolete, don't use in new code */
-static inline void bio_set_op_attrs(struct bio *bio, unsigned op,
-               unsigned op_flags)
+static inline void bio_set_op_attrs(struct bio *bio, enum req_op op,
+                                   blk_opf_t op_flags)
 {
        bio->bi_opf = op | op_flags;
 }
 
-static inline bool op_is_write(unsigned int op)
+static inline bool op_is_write(blk_opf_t op)
 {
-       return (op & 1);
+       return !!(op & (__force blk_opf_t)1);
 }
 
 /*
  * Check if the bio or request is one that needs special treatment in the
  * flush state machine.
  */
-static inline bool op_is_flush(unsigned int op)
+static inline bool op_is_flush(blk_opf_t op)
 {
        return op & (REQ_FUA | REQ_PREFLUSH);
 }
@@ -492,13 +499,13 @@ static inline bool op_is_flush(unsigned int op)
  * PREFLUSH flag.  Other operations may be marked as synchronous using the
  * REQ_SYNC flag.
  */
-static inline bool op_is_sync(unsigned int op)
+static inline bool op_is_sync(blk_opf_t op)
 {
        return (op & REQ_OP_MASK) == REQ_OP_READ ||
                (op & (REQ_SYNC | REQ_FUA | REQ_PREFLUSH));
 }
 
-static inline bool op_is_discard(unsigned int op)
+static inline bool op_is_discard(blk_opf_t op)
 {
        return (op & REQ_OP_MASK) == REQ_OP_DISCARD;
 }
@@ -509,7 +516,7 @@ static inline bool op_is_discard(unsigned int op)
  * due to its different handling in the block layer and device response in
  * case of command failure.
  */
-static inline bool op_is_zone_mgmt(enum req_opf op)
+static inline bool op_is_zone_mgmt(enum req_op op)
 {
        switch (op & REQ_OP_MASK) {
        case REQ_OP_ZONE_RESET:
@@ -522,7 +529,7 @@ static inline bool op_is_zone_mgmt(enum req_opf op)
        }
 }
 
-static inline int op_stat_group(unsigned int op)
+static inline int op_stat_group(enum req_op op)
 {
        if (op_is_discard(op))
                return STAT_DISCARD;
index 2f7b434..d04bdf5 100644 (file)
@@ -148,6 +148,7 @@ struct gendisk {
 #define GD_NATIVE_CAPACITY             3
 #define GD_ADDED                       4
 #define GD_SUPPRESS_PART_SCAN          5
+#define GD_OWNS_QUEUE                  6
 
        struct mutex open_mutex;        /* open/close mutex */
        unsigned open_partitions;       /* number of open partitions */
@@ -163,6 +164,29 @@ struct gendisk {
 #ifdef  CONFIG_BLK_DEV_INTEGRITY
        struct kobject integrity_kobj;
 #endif /* CONFIG_BLK_DEV_INTEGRITY */
+
+#ifdef CONFIG_BLK_DEV_ZONED
+       /*
+        * Zoned block device information for request dispatch control.
+        * nr_zones is the total number of zones of the device. This is always
+        * 0 for regular block devices. conv_zones_bitmap is a bitmap of nr_zones
+        * bits which indicates if a zone is conventional (bit set) or
+        * sequential (bit clear). seq_zones_wlock is a bitmap of nr_zones
+        * bits which indicates if a zone is write locked, that is, if a write
+        * request targeting the zone was dispatched.
+        *
+        * Reads of this information must be protected with blk_queue_enter() /
+        * blk_queue_exit(). Modifying this information is only allowed while
+        * no requests are being processed. See also blk_mq_freeze_queue() and
+        * 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 */
+
 #if IS_ENABLED(CONFIG_CDROM)
        struct cdrom_device_info *cdi;
 #endif
@@ -170,6 +194,12 @@ struct gendisk {
        struct badblocks *bb;
        struct lockdep_map lockdep_map;
        u64 diskseq;
+
+       /*
+        * Independent sector access ranges. This is always NULL for
+        * devices that do not have multiple independent access ranges.
+        */
+       struct blk_independent_access_ranges *ia_ranges;
 };
 
 static inline bool disk_live(struct gendisk *disk)
@@ -220,7 +250,7 @@ static inline int blk_validate_block_size(unsigned long bsize)
        return 0;
 }
 
-static inline bool blk_op_is_passthrough(unsigned int op)
+static inline bool blk_op_is_passthrough(blk_opf_t op)
 {
        op &= REQ_OP_MASK;
        return op == REQ_OP_DRV_IN || op == REQ_OP_DRV_OUT;
@@ -284,15 +314,15 @@ struct queue_limits {
 typedef int (*report_zones_cb)(struct blk_zone *zone, unsigned int idx,
                               void *data);
 
-void blk_queue_set_zoned(struct gendisk *disk, enum blk_zoned_model model);
+void disk_set_zoned(struct gendisk *disk, enum blk_zoned_model model);
 
 #ifdef CONFIG_BLK_DEV_ZONED
 
 #define BLK_ALL_ZONES  ((unsigned int)-1)
 int blkdev_report_zones(struct block_device *bdev, sector_t sector,
                        unsigned int nr_zones, report_zones_cb cb, void *data);
-unsigned int blkdev_nr_zones(struct gendisk *disk);
-extern int blkdev_zone_mgmt(struct block_device *bdev, enum req_opf op,
+unsigned int bdev_nr_zones(struct block_device *bdev);
+extern int blkdev_zone_mgmt(struct block_device *bdev, enum req_op op,
                            sector_t sectors, sector_t nr_sectors,
                            gfp_t gfp_mask);
 int blk_revalidate_disk_zones(struct gendisk *disk,
@@ -305,7 +335,7 @@ extern int blkdev_zone_mgmt_ioctl(struct block_device *bdev, fmode_t mode,
 
 #else /* CONFIG_BLK_DEV_ZONED */
 
-static inline unsigned int blkdev_nr_zones(struct gendisk *disk)
+static inline unsigned int bdev_nr_zones(struct block_device *bdev)
 {
        return 0;
 }
@@ -424,6 +454,11 @@ struct request_queue {
        unsigned long           nr_requests;    /* Max # of requests */
 
        unsigned int            dma_pad_mask;
+       /*
+        * Drivers that set dma_alignment to less than 511 must be prepared to
+        * handle individual bvec's that are not a multiple of a SECTOR_SIZE
+        * due to possible offsets.
+        */
        unsigned int            dma_alignment;
 
 #ifdef CONFIG_BLK_INLINE_ENCRYPTION
@@ -455,31 +490,6 @@ struct request_queue {
 
        unsigned int            required_elevator_features;
 
-#ifdef CONFIG_BLK_DEV_ZONED
-       /*
-        * Zoned block device information for request dispatch control.
-        * nr_zones is the total number of zones of the device. This is always
-        * 0 for regular block devices. conv_zones_bitmap is a bitmap of nr_zones
-        * bits which indicates if a zone is conventional (bit set) or
-        * sequential (bit clear). seq_zones_wlock is a bitmap of nr_zones
-        * bits which indicates if a zone is write locked, that is, if a write
-        * request targeting the zone was dispatched. All three fields are
-        * initialized by the low level device driver (e.g. scsi/sd.c).
-        * Stacking drivers (device mappers) may or may not initialize
-        * these fields.
-        *
-        * Reads of this information must be protected with blk_queue_enter() /
-        * blk_queue_exit(). Modifying this information is only allowed while
-        * no requests are being processed. See also blk_mq_freeze_queue() and
-        * blk_mq_unfreeze_queue().
-        */
-       unsigned int            nr_zones;
-       unsigned long           *conv_zones_bitmap;
-       unsigned long           *seq_zones_wlock;
-       unsigned int            max_open_zones;
-       unsigned int            max_active_zones;
-#endif /* CONFIG_BLK_DEV_ZONED */
-
        int                     node;
 #ifdef CONFIG_BLK_DEV_IO_TRACE
        struct blk_trace __rcu  *blk_trace;
@@ -533,12 +543,6 @@ struct request_queue {
 
        bool                    mq_sysfs_init_done;
 
-       /*
-        * Independent sector access ranges. This is always NULL for
-        * devices that do not have multiple independent access ranges.
-        */
-       struct blk_independent_access_ranges *ia_ranges;
-
        /**
         * @srcu: Sleepable RCU. Use as lock when type of the request queue
         * is blocking (BLK_MQ_F_BLOCKING). Must be the last member
@@ -559,7 +563,6 @@ struct request_queue {
 #define QUEUE_FLAG_NOXMERGES   9       /* No extended merges */
 #define QUEUE_FLAG_ADD_RANDOM  10      /* Contributes to random pool */
 #define QUEUE_FLAG_SAME_FORCE  12      /* force complete on same CPU */
-#define QUEUE_FLAG_DEAD                13      /* queue tear-down finished */
 #define QUEUE_FLAG_INIT_DONE   14      /* queue is initialized */
 #define QUEUE_FLAG_STABLE_WRITES 15    /* don't modify blks until WB is done */
 #define QUEUE_FLAG_POLL                16      /* IO polling enabled if set */
@@ -587,7 +590,6 @@ bool blk_queue_flag_test_and_set(unsigned int flag, struct request_queue *q);
 #define blk_queue_stopped(q)   test_bit(QUEUE_FLAG_STOPPED, &(q)->queue_flags)
 #define blk_queue_dying(q)     test_bit(QUEUE_FLAG_DYING, &(q)->queue_flags)
 #define blk_queue_has_srcu(q)  test_bit(QUEUE_FLAG_HAS_SRCU, &(q)->queue_flags)
-#define blk_queue_dead(q)      test_bit(QUEUE_FLAG_DEAD, &(q)->queue_flags)
 #define blk_queue_init_done(q) test_bit(QUEUE_FLAG_INIT_DONE, &(q)->queue_flags)
 #define blk_queue_nomerges(q)  test_bit(QUEUE_FLAG_NOMERGES, &(q)->queue_flags)
 #define blk_queue_noxmerges(q) \
@@ -663,76 +665,69 @@ static inline bool blk_queue_is_zoned(struct request_queue *q)
        }
 }
 
-static inline sector_t blk_queue_zone_sectors(struct request_queue *q)
-{
-       return blk_queue_is_zoned(q) ? q->limits.chunk_sectors : 0;
-}
-
 #ifdef CONFIG_BLK_DEV_ZONED
-static inline unsigned int blk_queue_nr_zones(struct request_queue *q)
+static inline unsigned int disk_nr_zones(struct gendisk *disk)
 {
-       return blk_queue_is_zoned(q) ? q->nr_zones : 0;
+       return blk_queue_is_zoned(disk->queue) ? disk->nr_zones : 0;
 }
 
-static inline unsigned int blk_queue_zone_no(struct request_queue *q,
-                                            sector_t sector)
+static inline unsigned int disk_zone_no(struct gendisk *disk, sector_t sector)
 {
-       if (!blk_queue_is_zoned(q))
+       if (!blk_queue_is_zoned(disk->queue))
                return 0;
-       return sector >> ilog2(q->limits.chunk_sectors);
+       return sector >> ilog2(disk->queue->limits.chunk_sectors);
 }
 
-static inline bool blk_queue_zone_is_seq(struct request_queue *q,
-                                        sector_t sector)
+static inline bool disk_zone_is_seq(struct gendisk *disk, sector_t sector)
 {
-       if (!blk_queue_is_zoned(q))
+       if (!blk_queue_is_zoned(disk->queue))
                return false;
-       if (!q->conv_zones_bitmap)
+       if (!disk->conv_zones_bitmap)
                return true;
-       return !test_bit(blk_queue_zone_no(q, sector), q->conv_zones_bitmap);
+       return !test_bit(disk_zone_no(disk, sector), disk->conv_zones_bitmap);
 }
 
-static inline void blk_queue_max_open_zones(struct request_queue *q,
+static inline void disk_set_max_open_zones(struct gendisk *disk,
                unsigned int max_open_zones)
 {
-       q->max_open_zones = max_open_zones;
+       disk->max_open_zones = max_open_zones;
 }
 
-static inline unsigned int queue_max_open_zones(const struct request_queue *q)
+static inline void disk_set_max_active_zones(struct gendisk *disk,
+               unsigned int max_active_zones)
 {
-       return q->max_open_zones;
+       disk->max_active_zones = max_active_zones;
 }
 
-static inline void blk_queue_max_active_zones(struct request_queue *q,
-               unsigned int max_active_zones)
+static inline unsigned int bdev_max_open_zones(struct block_device *bdev)
 {
-       q->max_active_zones = max_active_zones;
+       return bdev->bd_disk->max_open_zones;
 }
 
-static inline unsigned int queue_max_active_zones(const struct request_queue *q)
+static inline unsigned int bdev_max_active_zones(struct block_device *bdev)
 {
-       return q->max_active_zones;
+       return bdev->bd_disk->max_active_zones;
 }
+
 #else /* CONFIG_BLK_DEV_ZONED */
-static inline unsigned int blk_queue_nr_zones(struct request_queue *q)
+static inline unsigned int disk_nr_zones(struct gendisk *disk)
 {
        return 0;
 }
-static inline bool blk_queue_zone_is_seq(struct request_queue *q,
-                                        sector_t sector)
+static inline bool disk_zone_is_seq(struct gendisk *disk, sector_t sector)
 {
        return false;
 }
-static inline unsigned int blk_queue_zone_no(struct request_queue *q,
-                                            sector_t sector)
+static inline unsigned int disk_zone_no(struct gendisk *disk, sector_t sector)
 {
        return 0;
 }
-static inline unsigned int queue_max_open_zones(const struct request_queue *q)
+static inline unsigned int bdev_max_open_zones(struct block_device *bdev)
 {
        return 0;
 }
-static inline unsigned int queue_max_active_zones(const struct request_queue *q)
+
+static inline unsigned int bdev_max_active_zones(struct block_device *bdev)
 {
        return 0;
 }
@@ -812,8 +807,6 @@ static inline u64 sb_bdev_nr_blocks(struct super_block *sb)
 
 int bdev_disk_changed(struct gendisk *disk, bool invalidate);
 
-struct gendisk *__alloc_disk_node(struct request_queue *q, int node_id,
-               struct lock_class_key *lkclass);
 void put_disk(struct gendisk *disk);
 struct gendisk *__blk_alloc_disk(int node, struct lock_class_key *lkclass);
 
@@ -832,7 +825,6 @@ struct gendisk *__blk_alloc_disk(int node, struct lock_class_key *lkclass);
                                                                        \
        __blk_alloc_disk(node_id, &__key);                              \
 })
-void blk_cleanup_disk(struct gendisk *disk);
 
 int __register_blkdev(unsigned int major, const char *name,
                void (*probe)(dev_t devt));
@@ -880,7 +872,7 @@ extern void blk_queue_exit(struct request_queue *q);
 extern void blk_sync_queue(struct request_queue *q);
 
 /* Helper to convert REQ_OP_XXX to its string format XXX */
-extern const char *blk_op_str(unsigned int op);
+extern const char *blk_op_str(enum req_op op);
 
 int blk_status_to_errno(blk_status_t status);
 blk_status_t errno_to_blk_status(int errno);
@@ -898,64 +890,33 @@ static inline struct request_queue *bdev_get_queue(struct block_device *bdev)
        return bdev->bd_queue;  /* this is never NULL */
 }
 
-#ifdef CONFIG_BLK_DEV_ZONED
-
 /* Helper to convert BLK_ZONE_ZONE_XXX to its string format XXX */
 const char *blk_zone_cond_str(enum blk_zone_cond zone_cond);
 
 static inline unsigned int bio_zone_no(struct bio *bio)
 {
-       return blk_queue_zone_no(bdev_get_queue(bio->bi_bdev),
-                                bio->bi_iter.bi_sector);
+       return disk_zone_no(bio->bi_bdev->bd_disk, bio->bi_iter.bi_sector);
 }
 
 static inline unsigned int bio_zone_is_seq(struct bio *bio)
 {
-       return blk_queue_zone_is_seq(bdev_get_queue(bio->bi_bdev),
-                                    bio->bi_iter.bi_sector);
-}
-#endif /* CONFIG_BLK_DEV_ZONED */
-
-static inline unsigned int blk_queue_get_max_sectors(struct request_queue *q,
-                                                    int op)
-{
-       if (unlikely(op == REQ_OP_DISCARD || op == REQ_OP_SECURE_ERASE))
-               return min(q->limits.max_discard_sectors,
-                          UINT_MAX >> SECTOR_SHIFT);
-
-       if (unlikely(op == REQ_OP_WRITE_ZEROES))
-               return q->limits.max_write_zeroes_sectors;
-
-       return q->limits.max_sectors;
+       return disk_zone_is_seq(bio->bi_bdev->bd_disk, bio->bi_iter.bi_sector);
 }
 
 /*
- * Return maximum size of a request at given offset. Only valid for
- * file system requests.
+ * Return how much of the chunk is left to be used for I/O at a given offset.
  */
-static inline unsigned int blk_max_size_offset(struct request_queue *q,
-                                              sector_t offset,
-                                              unsigned int chunk_sectors)
-{
-       if (!chunk_sectors) {
-               if (q->limits.chunk_sectors)
-                       chunk_sectors = q->limits.chunk_sectors;
-               else
-                       return q->limits.max_sectors;
-       }
-
-       if (likely(is_power_of_2(chunk_sectors)))
-               chunk_sectors -= offset & (chunk_sectors - 1);
-       else
-               chunk_sectors -= sector_div(offset, chunk_sectors);
-
-       return min(q->limits.max_sectors, chunk_sectors);
+static inline unsigned int blk_chunk_sectors_left(sector_t offset,
+               unsigned int chunk_sectors)
+{
+       if (unlikely(!is_power_of_2(chunk_sectors)))
+               return chunk_sectors - sector_div(offset, chunk_sectors);
+       return chunk_sectors - (offset & (chunk_sectors - 1));
 }
 
 /*
  * Access functions for manipulating queue properties
  */
-extern void blk_cleanup_queue(struct request_queue *);
 void blk_queue_bounce_limit(struct request_queue *q, enum blk_bounce limit);
 extern void blk_queue_max_hw_sectors(struct request_queue *, unsigned int);
 extern void blk_queue_chunk_sectors(struct request_queue *, unsigned int);
@@ -1337,32 +1298,26 @@ static inline sector_t bdev_zone_sectors(struct block_device *bdev)
 {
        struct request_queue *q = bdev_get_queue(bdev);
 
-       if (q)
-               return blk_queue_zone_sectors(q);
-       return 0;
+       if (!blk_queue_is_zoned(q))
+               return 0;
+       return q->limits.chunk_sectors;
 }
 
-static inline unsigned int bdev_max_open_zones(struct block_device *bdev)
+static inline int queue_dma_alignment(const struct request_queue *q)
 {
-       struct request_queue *q = bdev_get_queue(bdev);
-
-       if (q)
-               return queue_max_open_zones(q);
-       return 0;
+       return q ? q->dma_alignment : 511;
 }
 
-static inline unsigned int bdev_max_active_zones(struct block_device *bdev)
+static inline unsigned int bdev_dma_alignment(struct block_device *bdev)
 {
-       struct request_queue *q = bdev_get_queue(bdev);
-
-       if (q)
-               return queue_max_active_zones(q);
-       return 0;
+       return queue_dma_alignment(bdev_get_queue(bdev));
 }
 
-static inline int queue_dma_alignment(const struct request_queue *q)
+static inline bool bdev_iter_is_aligned(struct block_device *bdev,
+                                       struct iov_iter *iter)
 {
-       return q ? q->dma_alignment : 511;
+       return iov_iter_is_aligned(iter, bdev_dma_alignment(bdev),
+                                  bdev_logical_block_size(bdev) - 1);
 }
 
 static inline int blk_rq_aligned(struct request_queue *q, unsigned long addr,
@@ -1426,7 +1381,7 @@ struct block_device_operations {
                        unsigned int flags);
        int (*open) (struct block_device *, fmode_t);
        void (*release) (struct gendisk *, fmode_t);
-       int (*rw_page)(struct block_device *, sector_t, struct page *, unsigned int);
+       int (*rw_page)(struct block_device *, sector_t, struct page *, enum req_op);
        int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
        int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
        unsigned int (*check_events) (struct gendisk *disk,
@@ -1479,9 +1434,9 @@ static inline void blk_wake_io_task(struct task_struct *waiter)
 }
 
 unsigned long bdev_start_io_acct(struct block_device *bdev,
-                                unsigned int sectors, unsigned int op,
+                                unsigned int sectors, enum req_op op,
                                 unsigned long start_time);
-void bdev_end_io_acct(struct block_device *bdev, unsigned int op,
+void bdev_end_io_acct(struct block_device *bdev, enum req_op op,
                unsigned long start_time);
 
 void bio_start_io_acct_time(struct bio *bio, unsigned long start_time);
@@ -1502,7 +1457,6 @@ static inline void bio_end_io_acct(struct bio *bio, unsigned long start_time)
 int bdev_read_only(struct block_device *bdev);
 int set_blocksize(struct block_device *bdev, int size);
 
-const char *bdevname(struct block_device *bdev, char *buffer);
 int lookup_bdev(const char *pathname, dev_t *dev);
 
 void blkdev_show(struct seq_file *seqf, off_t offset);
index 623e224..cfbda11 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/compat.h>
 #include <uapi/linux/blktrace_api.h>
 #include <linux/list.h>
+#include <linux/blk_types.h>
 
 #if defined(CONFIG_BLK_DEV_IO_TRACE)
 
@@ -77,10 +78,6 @@ extern int blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
                           char __user *arg);
 extern int blk_trace_startstop(struct request_queue *q, int start);
 extern int blk_trace_remove(struct request_queue *q);
-extern void blk_trace_remove_sysfs(struct device *dev);
-extern int blk_trace_init_sysfs(struct device *dev);
-
-extern struct attribute_group blk_trace_attr_group;
 
 #else /* !CONFIG_BLK_DEV_IO_TRACE */
 # define blk_trace_ioctl(bdev, cmd, arg)               (-ENOTTY)
@@ -91,13 +88,7 @@ extern struct attribute_group blk_trace_attr_group;
 # define blk_trace_remove(q)                           (-ENOTTY)
 # define blk_add_trace_msg(q, fmt, ...)                        do { } while (0)
 # define blk_add_cgroup_trace_msg(q, cg, fmt, ...)     do { } while (0)
-# define blk_trace_remove_sysfs(dev)                   do { } while (0)
 # define blk_trace_note_message_enabled(q)             (false)
-static inline int blk_trace_init_sysfs(struct device *dev)
-{
-       return 0;
-}
-
 #endif /* CONFIG_BLK_DEV_IO_TRACE */
 
 #ifdef CONFIG_COMPAT
@@ -115,7 +106,7 @@ struct compat_blk_user_trace_setup {
 
 #endif
 
-void blk_fill_rwbs(char *rwbs, unsigned int op);
+void blk_fill_rwbs(char *rwbs, blk_opf_t opf);
 
 static inline sector_t blk_rq_trace_sector(struct request *rq)
 {
index 61afb81..307445d 100644 (file)
@@ -9,6 +9,7 @@
 #define _LINUX_BUFFER_HEAD_H
 
 #include <linux/types.h>
+#include <linux/blk_types.h>
 #include <linux/fs.h>
 #include <linux/linkage.h>
 #include <linux/pagemap.h>
@@ -201,11 +202,11 @@ struct buffer_head *alloc_buffer_head(gfp_t gfp_flags);
 void free_buffer_head(struct buffer_head * bh);
 void unlock_buffer(struct buffer_head *bh);
 void __lock_buffer(struct buffer_head *bh);
-void ll_rw_block(int, int, int, struct buffer_head * bh[]);
+void ll_rw_block(blk_opf_t, int, struct buffer_head * bh[]);
 int sync_dirty_buffer(struct buffer_head *bh);
-int __sync_dirty_buffer(struct buffer_head *bh, int op_flags);
-void write_dirty_buffer(struct buffer_head *bh, int op_flags);
-int submit_bh(int, int, struct buffer_head *);
+int __sync_dirty_buffer(struct buffer_head *bh, blk_opf_t op_flags);
+void write_dirty_buffer(struct buffer_head *bh, blk_opf_t op_flags);
+int submit_bh(blk_opf_t, struct buffer_head *);
 void write_boundary_block(struct block_device *bdev,
                        sector_t bblock, unsigned blocksize);
 int bh_uptodate_or_lock(struct buffer_head *bh);
index 1bfcfb1..4bcf56b 100644 (file)
@@ -89,19 +89,32 @@ enum {
        CGRP_ROOT_NS_DELEGATE   = (1 << 3),
 
        /*
+        * Reduce latencies on dynamic cgroup modifications such as task
+        * migrations and controller on/offs by disabling percpu operation on
+        * cgroup_threadgroup_rwsem. This makes hot path operations such as
+        * forks and exits into the slow path and more expensive.
+        *
+        * The static usage pattern of creating a cgroup, enabling controllers,
+        * and then seeding it with CLONE_INTO_CGROUP doesn't require write
+        * locking cgroup_threadgroup_rwsem and thus doesn't benefit from
+        * favordynmod.
+        */
+       CGRP_ROOT_FAVOR_DYNMODS = (1 << 4),
+
+       /*
         * Enable cpuset controller in v1 cgroup to use v2 behavior.
         */
-       CGRP_ROOT_CPUSET_V2_MODE = (1 << 4),
+       CGRP_ROOT_CPUSET_V2_MODE = (1 << 16),
 
        /*
         * Enable legacy local memory.events.
         */
-       CGRP_ROOT_MEMORY_LOCAL_EVENTS = (1 << 5),
+       CGRP_ROOT_MEMORY_LOCAL_EVENTS = (1 << 17),
 
        /*
         * Enable recursive subtree protection
         */
-       CGRP_ROOT_MEMORY_RECURSIVE_PROT = (1 << 6),
+       CGRP_ROOT_MEMORY_RECURSIVE_PROT = (1 << 18),
 };
 
 /* cftype->flags */
@@ -264,7 +277,8 @@ struct css_set {
         * List of csets participating in the on-going migration either as
         * source or destination.  Protected by cgroup_mutex.
         */
-       struct list_head mg_preload_node;
+       struct list_head mg_src_preload_node;
+       struct list_head mg_dst_preload_node;
        struct list_head mg_node;
 
        /*
@@ -287,6 +301,10 @@ struct css_set {
 
 struct cgroup_base_stat {
        struct task_cputime cputime;
+
+#ifdef CONFIG_SCHED_CORE
+       u64 forceidle_sum;
+#endif
 };
 
 /*
@@ -475,7 +493,7 @@ struct cgroup {
        struct work_struct release_agent_work;
 
        /* used to track pressure stalls */
-       struct psi_group psi;
+       struct psi_group *psi;
 
        /* used to store eBPF programs */
        struct cgroup_bpf bpf;
index 0d1ada8..ed53bfe 100644 (file)
@@ -674,7 +674,7 @@ static inline void pr_cont_cgroup_path(struct cgroup *cgrp)
 
 static inline struct psi_group *cgroup_psi(struct cgroup *cgrp)
 {
-       return &cgrp->psi;
+       return cgrp->psi;
 }
 
 bool cgroup_psi_enabled(void);
index d08dfcb..4f2a819 100644 (file)
@@ -24,6 +24,7 @@ static inline void __chk_io_ptr(const volatile void __iomem *ptr) { }
 /* context/locking */
 # define __must_hold(x)        __attribute__((context(x,1,1)))
 # define __acquires(x) __attribute__((context(x,0,1)))
+# define __cond_acquires(x) __attribute__((context(x,0,-1)))
 # define __releases(x) __attribute__((context(x,1,0)))
 # define __acquire(x)  __context__(x,1)
 # define __release(x)  __context__(x,-1)
@@ -50,6 +51,7 @@ static inline void __chk_io_ptr(const volatile void __iomem *ptr) { }
 /* context/locking */
 # define __must_hold(x)
 # define __acquires(x)
+# define __cond_acquires(x)
 # define __releases(x)
 # define __acquire(x)  (void)0
 # define __release(x)  (void)0
index 7a14807..dcef4a9 100644 (file)
 #include <asm/ptrace.h>
 
 
-#ifdef CONFIG_CONTEXT_TRACKING
-extern void context_tracking_cpu_set(int cpu);
+#ifdef CONFIG_CONTEXT_TRACKING_USER
+extern void ct_cpu_track_user(int cpu);
 
 /* Called with interrupts disabled.  */
-extern void __context_tracking_enter(enum ctx_state state);
-extern void __context_tracking_exit(enum ctx_state state);
+extern void __ct_user_enter(enum ctx_state state);
+extern void __ct_user_exit(enum ctx_state state);
 
-extern void context_tracking_enter(enum ctx_state state);
-extern void context_tracking_exit(enum ctx_state state);
-extern void context_tracking_user_enter(void);
-extern void context_tracking_user_exit(void);
+extern void ct_user_enter(enum ctx_state state);
+extern void ct_user_exit(enum ctx_state state);
+
+extern void user_enter_callable(void);
+extern void user_exit_callable(void);
 
 static inline void user_enter(void)
 {
        if (context_tracking_enabled())
-               context_tracking_enter(CONTEXT_USER);
+               ct_user_enter(CONTEXT_USER);
 
 }
 static inline void user_exit(void)
 {
        if (context_tracking_enabled())
-               context_tracking_exit(CONTEXT_USER);
+               ct_user_exit(CONTEXT_USER);
 }
 
 /* Called with interrupts disabled.  */
 static __always_inline void user_enter_irqoff(void)
 {
        if (context_tracking_enabled())
-               __context_tracking_enter(CONTEXT_USER);
+               __ct_user_enter(CONTEXT_USER);
 
 }
 static __always_inline void user_exit_irqoff(void)
 {
        if (context_tracking_enabled())
-               __context_tracking_exit(CONTEXT_USER);
+               __ct_user_exit(CONTEXT_USER);
 }
 
 static inline enum ctx_state exception_enter(void)
 {
        enum ctx_state prev_ctx;
 
-       if (IS_ENABLED(CONFIG_HAVE_CONTEXT_TRACKING_OFFSTACK) ||
+       if (IS_ENABLED(CONFIG_HAVE_CONTEXT_TRACKING_USER_OFFSTACK) ||
            !context_tracking_enabled())
                return 0;
 
-       prev_ctx = this_cpu_read(context_tracking.state);
+       prev_ctx = __ct_state();
        if (prev_ctx != CONTEXT_KERNEL)
-               context_tracking_exit(prev_ctx);
+               ct_user_exit(prev_ctx);
 
        return prev_ctx;
 }
 
 static inline void exception_exit(enum ctx_state prev_ctx)
 {
-       if (!IS_ENABLED(CONFIG_HAVE_CONTEXT_TRACKING_OFFSTACK) &&
+       if (!IS_ENABLED(CONFIG_HAVE_CONTEXT_TRACKING_USER_OFFSTACK) &&
            context_tracking_enabled()) {
                if (prev_ctx != CONTEXT_KERNEL)
-                       context_tracking_enter(prev_ctx);
+                       ct_user_enter(prev_ctx);
        }
 }
 
 static __always_inline bool context_tracking_guest_enter(void)
 {
        if (context_tracking_enabled())
-               __context_tracking_enter(CONTEXT_GUEST);
+               __ct_user_enter(CONTEXT_GUEST);
 
        return context_tracking_enabled_this_cpu();
 }
@@ -82,40 +83,56 @@ static __always_inline bool context_tracking_guest_enter(void)
 static __always_inline void context_tracking_guest_exit(void)
 {
        if (context_tracking_enabled())
-               __context_tracking_exit(CONTEXT_GUEST);
+               __ct_user_exit(CONTEXT_GUEST);
 }
 
-/**
- * ct_state() - return the current context tracking state if known
- *
- * Returns the current cpu's context tracking state if context tracking
- * is enabled.  If context tracking is disabled, returns
- * CONTEXT_DISABLED.  This should be used primarily for debugging.
- */
-static __always_inline enum ctx_state ct_state(void)
-{
-       return context_tracking_enabled() ?
-               this_cpu_read(context_tracking.state) : CONTEXT_DISABLED;
-}
+#define CT_WARN_ON(cond) WARN_ON(context_tracking_enabled() && (cond))
+
 #else
 static inline void user_enter(void) { }
 static inline void user_exit(void) { }
 static inline void user_enter_irqoff(void) { }
 static inline void user_exit_irqoff(void) { }
-static inline enum ctx_state exception_enter(void) { return 0; }
+static inline int exception_enter(void) { return 0; }
 static inline void exception_exit(enum ctx_state prev_ctx) { }
-static inline enum ctx_state ct_state(void) { return CONTEXT_DISABLED; }
+static inline int ct_state(void) { return -1; }
 static __always_inline bool context_tracking_guest_enter(void) { return false; }
 static inline void context_tracking_guest_exit(void) { }
+#define CT_WARN_ON(cond) do { } while (0)
+#endif /* !CONFIG_CONTEXT_TRACKING_USER */
 
-#endif /* !CONFIG_CONTEXT_TRACKING */
-
-#define CT_WARN_ON(cond) WARN_ON(context_tracking_enabled() && (cond))
-
-#ifdef CONFIG_CONTEXT_TRACKING_FORCE
+#ifdef CONFIG_CONTEXT_TRACKING_USER_FORCE
 extern void context_tracking_init(void);
 #else
 static inline void context_tracking_init(void) { }
-#endif /* CONFIG_CONTEXT_TRACKING_FORCE */
+#endif /* CONFIG_CONTEXT_TRACKING_USER_FORCE */
+
+#ifdef CONFIG_CONTEXT_TRACKING_IDLE
+extern void ct_idle_enter(void);
+extern void ct_idle_exit(void);
+
+/*
+ * Is the current CPU in an extended quiescent state?
+ *
+ * No ordering, as we are sampling CPU-local information.
+ */
+static __always_inline bool rcu_dynticks_curr_cpu_in_eqs(void)
+{
+       return !(arch_atomic_read(this_cpu_ptr(&context_tracking.state)) & RCU_DYNTICKS_IDX);
+}
+
+/*
+ * Increment the current CPU's context_tracking structure's ->state field
+ * with ordering.  Return the new value.
+ */
+static __always_inline unsigned long ct_state_inc(int incby)
+{
+       return arch_atomic_add_return(incby, this_cpu_ptr(&context_tracking.state));
+}
+
+#else
+static inline void ct_idle_enter(void) { }
+static inline void ct_idle_exit(void) { }
+#endif /* !CONFIG_CONTEXT_TRACKING_IDLE */
 
 #endif
diff --git a/include/linux/context_tracking_irq.h b/include/linux/context_tracking_irq.h
new file mode 100644 (file)
index 0000000..c50b567
--- /dev/null
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_CONTEXT_TRACKING_IRQ_H
+#define _LINUX_CONTEXT_TRACKING_IRQ_H
+
+#ifdef CONFIG_CONTEXT_TRACKING_IDLE
+void ct_irq_enter(void);
+void ct_irq_exit(void);
+void ct_irq_enter_irqson(void);
+void ct_irq_exit_irqson(void);
+void ct_nmi_enter(void);
+void ct_nmi_exit(void);
+#else
+static inline void ct_irq_enter(void) { }
+static inline void ct_irq_exit(void) { }
+static inline void ct_irq_enter_irqson(void) { }
+static inline void ct_irq_exit_irqson(void) { }
+static inline void ct_nmi_enter(void) { }
+static inline void ct_nmi_exit(void) { }
+#endif
+
+#endif
index ae1e63e..4a4d56f 100644 (file)
@@ -4,8 +4,28 @@
 
 #include <linux/percpu.h>
 #include <linux/static_key.h>
+#include <linux/context_tracking_irq.h>
+
+/* Offset to allow distinguishing irq vs. task-based idle entry/exit. */
+#define DYNTICK_IRQ_NONIDLE    ((LONG_MAX / 2) + 1)
+
+enum ctx_state {
+       CONTEXT_DISABLED        = -1,   /* returned by ct_state() if unknown */
+       CONTEXT_KERNEL          = 0,
+       CONTEXT_IDLE            = 1,
+       CONTEXT_USER            = 2,
+       CONTEXT_GUEST           = 3,
+       CONTEXT_MAX             = 4,
+};
+
+/* Even value for idle, else odd. */
+#define RCU_DYNTICKS_IDX CONTEXT_MAX
+
+#define CT_STATE_MASK (CONTEXT_MAX - 1)
+#define CT_DYNTICKS_MASK (~CT_STATE_MASK)
 
 struct context_tracking {
+#ifdef CONFIG_CONTEXT_TRACKING_USER
        /*
         * When active is false, probes are unset in order
         * to minimize overhead: TIF flags are cleared
@@ -14,18 +34,73 @@ struct context_tracking {
         */
        bool active;
        int recursion;
-       enum ctx_state {
-               CONTEXT_DISABLED = -1,  /* returned by ct_state() if unknown */
-               CONTEXT_KERNEL = 0,
-               CONTEXT_USER,
-               CONTEXT_GUEST,
-       } state;
+#endif
+#ifdef CONFIG_CONTEXT_TRACKING
+       atomic_t state;
+#endif
+#ifdef CONFIG_CONTEXT_TRACKING_IDLE
+       long dynticks_nesting;          /* Track process nesting level. */
+       long dynticks_nmi_nesting;      /* Track irq/NMI nesting level. */
+#endif
 };
 
 #ifdef CONFIG_CONTEXT_TRACKING
-extern struct static_key_false context_tracking_key;
 DECLARE_PER_CPU(struct context_tracking, context_tracking);
 
+static __always_inline int __ct_state(void)
+{
+       return arch_atomic_read(this_cpu_ptr(&context_tracking.state)) & CT_STATE_MASK;
+}
+#endif
+
+#ifdef CONFIG_CONTEXT_TRACKING_IDLE
+static __always_inline int ct_dynticks(void)
+{
+       return atomic_read(this_cpu_ptr(&context_tracking.state)) & CT_DYNTICKS_MASK;
+}
+
+static __always_inline int ct_dynticks_cpu(int cpu)
+{
+       struct context_tracking *ct = per_cpu_ptr(&context_tracking, cpu);
+
+       return atomic_read(&ct->state) & CT_DYNTICKS_MASK;
+}
+
+static __always_inline int ct_dynticks_cpu_acquire(int cpu)
+{
+       struct context_tracking *ct = per_cpu_ptr(&context_tracking, cpu);
+
+       return atomic_read_acquire(&ct->state) & CT_DYNTICKS_MASK;
+}
+
+static __always_inline long ct_dynticks_nesting(void)
+{
+       return __this_cpu_read(context_tracking.dynticks_nesting);
+}
+
+static __always_inline long ct_dynticks_nesting_cpu(int cpu)
+{
+       struct context_tracking *ct = per_cpu_ptr(&context_tracking, cpu);
+
+       return ct->dynticks_nesting;
+}
+
+static __always_inline long ct_dynticks_nmi_nesting(void)
+{
+       return __this_cpu_read(context_tracking.dynticks_nmi_nesting);
+}
+
+static __always_inline long ct_dynticks_nmi_nesting_cpu(int cpu)
+{
+       struct context_tracking *ct = per_cpu_ptr(&context_tracking, cpu);
+
+       return ct->dynticks_nmi_nesting;
+}
+#endif /* #ifdef CONFIG_CONTEXT_TRACKING_IDLE */
+
+#ifdef CONFIG_CONTEXT_TRACKING_USER
+extern struct static_key_false context_tracking_key;
+
 static __always_inline bool context_tracking_enabled(void)
 {
        return static_branch_unlikely(&context_tracking_key);
@@ -41,15 +116,31 @@ static inline bool context_tracking_enabled_this_cpu(void)
        return context_tracking_enabled() && __this_cpu_read(context_tracking.active);
 }
 
-static __always_inline bool context_tracking_in_user(void)
+/**
+ * ct_state() - return the current context tracking state if known
+ *
+ * Returns the current cpu's context tracking state if context tracking
+ * is enabled.  If context tracking is disabled, returns
+ * CONTEXT_DISABLED.  This should be used primarily for debugging.
+ */
+static __always_inline int ct_state(void)
 {
-       return __this_cpu_read(context_tracking.state) == CONTEXT_USER;
+       int ret;
+
+       if (!context_tracking_enabled())
+               return CONTEXT_DISABLED;
+
+       preempt_disable();
+       ret = __ct_state();
+       preempt_enable();
+
+       return ret;
 }
+
 #else
-static __always_inline bool context_tracking_in_user(void) { return false; }
 static __always_inline bool context_tracking_enabled(void) { return false; }
 static __always_inline bool context_tracking_enabled_cpu(int cpu) { return false; }
 static __always_inline bool context_tracking_enabled_this_cpu(void) { return false; }
-#endif /* CONFIG_CONTEXT_TRACKING */
+#endif /* CONFIG_CONTEXT_TRACKING_USER */
 
 #endif
index 2c74773..314802f 100644 (file)
@@ -68,6 +68,8 @@ extern ssize_t cpu_show_srbds(struct device *dev, struct device_attribute *attr,
 extern ssize_t cpu_show_mmio_stale_data(struct device *dev,
                                        struct device_attribute *attr,
                                        char *buf);
+extern ssize_t cpu_show_retbleed(struct device *dev,
+                                struct device_attribute *attr, char *buf);
 
 extern __printf(4, 5)
 struct device *cpu_device_create(struct device *parent, void *drvdata,
index 19f0dbf..f614479 100644 (file)
@@ -130,7 +130,6 @@ enum cpuhp_state {
        CPUHP_ZCOMP_PREPARE,
        CPUHP_TIMERS_PREPARE,
        CPUHP_MIPS_SOC_PREPARE,
-       CPUHP_LOONGARCH_SOC_PREPARE,
        CPUHP_BP_PREPARE_DYN,
        CPUHP_BP_PREPARE_DYN_END                = CPUHP_BP_PREPARE_DYN + 20,
        CPUHP_BRINGUP_CPU,
@@ -151,6 +150,7 @@ enum cpuhp_state {
        CPUHP_AP_IRQ_BCM2836_STARTING,
        CPUHP_AP_IRQ_MIPS_GIC_STARTING,
        CPUHP_AP_IRQ_RISCV_STARTING,
+       CPUHP_AP_IRQ_LOONGARCH_STARTING,
        CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING,
        CPUHP_AP_ARM_MVEBU_COHERENCY,
        CPUHP_AP_MICROCODE_LOADER,
@@ -230,6 +230,7 @@ enum cpuhp_state {
        CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
        CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
        CPUHP_AP_PERF_ARM_HISI_PCIE_PMU_ONLINE,
+       CPUHP_AP_PERF_ARM_HNS3_PMU_ONLINE,
        CPUHP_AP_PERF_ARM_L2X0_ONLINE,
        CPUHP_AP_PERF_ARM_QCOM_L2_ONLINE,
        CPUHP_AP_PERF_ARM_QCOM_L3_ONLINE,
index dc10bee..34aab4d 100644 (file)
@@ -148,6 +148,8 @@ struct devfreq_stats {
  *             reevaluate operable frequencies. Devfreq users may use
  *             devfreq.nb to the corresponding register notifier call chain.
  * @work:      delayed work for load monitoring.
+ * @freq_table:                current frequency table used by the devfreq driver.
+ * @max_state:         count of entry present in the frequency table.
  * @previous_freq:     previously configured frequency value.
  * @last_status:       devfreq user device info, performance statistics
  * @data:      Private data of the governor. The devfreq framework does not
@@ -185,6 +187,9 @@ struct devfreq {
        struct notifier_block nb;
        struct delayed_work work;
 
+       unsigned long *freq_table;
+       unsigned int max_state;
+
        unsigned long previous_freq;
        struct devfreq_dev_status last_status;
 
index 47a01c7..04c6acf 100644 (file)
@@ -373,6 +373,12 @@ struct dm_target {
         * after returning DM_MAPIO_SUBMITTED from its map function.
         */
        bool accounts_remapped_io:1;
+
+       /*
+        * Set if the target will submit the DM bio without first calling
+        * bio_set_dev(). NOTE: ideally a target should _not_ need this.
+        */
+       bool needs_bio_set_dev:1;
 };
 
 void *dm_per_bio_data(struct bio *bio, size_t data_size);
@@ -561,7 +567,6 @@ void dm_sync_table(struct mapped_device *md);
  * Queries
  */
 sector_t dm_table_get_size(struct dm_table *t);
-unsigned int dm_table_get_num_targets(struct dm_table *t);
 fmode_t dm_table_get_mode(struct dm_table *t);
 struct mapped_device *dm_table_get_md(struct dm_table *t);
 const char *dm_table_device_name(struct dm_table *t);
index b698266..6c57339 100644 (file)
@@ -21,7 +21,7 @@
  * We consider 10% difference as significant.
  */
 #define IS_SIGNIFICANT_DIFF(val, ref) \
-       (((100UL * abs((val) - (ref))) / (ref)) > 10)
+       ((ref) && (((100UL * abs((val) - (ref))) / (ref)) > 10))
 
 /*
  * Calculate the gap between two values.
index a52c658..8e1c4ab 100644 (file)
@@ -13,6 +13,7 @@
 #ifdef __KERNEL__
 
 #include <linux/types.h>
+#include <linux/blk_types.h>
 
 struct dm_io_region {
        struct block_device *bdev;
@@ -57,8 +58,7 @@ struct dm_io_notify {
  */
 struct dm_io_client;
 struct dm_io_request {
-       int bi_op;                      /* REQ_OP */
-       int bi_op_flags;                /* req_flag_bits */
+       blk_opf_t           bi_opf;     /* Request type and flags */
        struct dm_io_memory mem;        /* Memory to use for io */
        struct dm_io_notify notify;     /* Synchronous if notify.fn is NULL */
        struct dm_io_client *client;    /* Client memory handler */
diff --git a/include/linux/dm-verity-loadpin.h b/include/linux/dm-verity-loadpin.h
new file mode 100644 (file)
index 0000000..552b817
--- /dev/null
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __LINUX_DM_VERITY_LOADPIN_H
+#define __LINUX_DM_VERITY_LOADPIN_H
+
+#include <linux/list.h>
+
+struct block_device;
+
+extern struct list_head dm_verity_loadpin_trusted_root_digests;
+
+struct dm_verity_loadpin_trusted_root_digest {
+       struct list_head node;
+       unsigned int len;
+       u8 data[];
+};
+
+#if IS_ENABLED(CONFIG_SECURITY_LOADPIN_VERITY)
+bool dm_verity_loadpin_is_bdev_trusted(struct block_device *bdev);
+#else
+static inline bool dm_verity_loadpin_is_bdev_trusted(struct block_device *bdev)
+{
+       return false;
+}
+#endif
+
+#endif /* __LINUX_DM_VERITY_LOADPIN_H */
index 8419bff..b9caa01 100644 (file)
@@ -62,7 +62,7 @@ struct em_perf_domain {
 /*
  *  em_perf_domain flags:
  *
- *  EM_PERF_DOMAIN_MILLIWATTS: The power values are in milli-Watts or some
+ *  EM_PERF_DOMAIN_MICROWATTS: The power values are in micro-Watts or some
  *  other scale.
  *
  *  EM_PERF_DOMAIN_SKIP_INEFFICIENCIES: Skip inefficient states when estimating
@@ -71,7 +71,7 @@ struct em_perf_domain {
  *  EM_PERF_DOMAIN_ARTIFICIAL: The power values are artificial and might be
  *  created by platform missing real power information
  */
-#define EM_PERF_DOMAIN_MILLIWATTS BIT(0)
+#define EM_PERF_DOMAIN_MICROWATTS BIT(0)
 #define EM_PERF_DOMAIN_SKIP_INEFFICIENCIES BIT(1)
 #define EM_PERF_DOMAIN_ARTIFICIAL BIT(2)
 
@@ -79,22 +79,44 @@ struct em_perf_domain {
 #define em_is_artificial(em) ((em)->flags & EM_PERF_DOMAIN_ARTIFICIAL)
 
 #ifdef CONFIG_ENERGY_MODEL
-#define EM_MAX_POWER 0xFFFF
+/*
+ * The max power value in micro-Watts. The limit of 64 Watts is set as
+ * a safety net to not overflow multiplications on 32bit platforms. The
+ * 32bit value limit for total Perf Domain power implies a limit of
+ * maximum CPUs in such domain to 64.
+ */
+#define EM_MAX_POWER (64000000) /* 64 Watts */
+
+/*
+ * To avoid possible energy estimation overflow on 32bit machines add
+ * limits to number of CPUs in the Perf. Domain.
+ * We are safe on 64bit machine, thus some big number.
+ */
+#ifdef CONFIG_64BIT
+#define EM_MAX_NUM_CPUS 4096
+#else
+#define EM_MAX_NUM_CPUS 16
+#endif
 
 /*
- * Increase resolution of energy estimation calculations for 64-bit
- * architectures. The extra resolution improves decision made by EAS for the
- * task placement when two Performance Domains might provide similar energy
- * estimation values (w/o better resolution the values could be equal).
+ * To avoid an overflow on 32bit machines while calculating the energy
+ * use a different order in the operation. First divide by the 'cpu_scale'
+ * which would reduce big value stored in the 'cost' field, then multiply by
+ * the 'sum_util'. This would allow to handle existing platforms, which have
+ * e.g. power ~1.3 Watt at max freq, so the 'cost' value > 1mln micro-Watts.
+ * In such scenario, where there are 4 CPUs in the Perf. Domain the 'sum_util'
+ * could be 4096, then multiplication: 'cost' * 'sum_util'  would overflow.
+ * This reordering of operations has some limitations, we lose small
+ * precision in the estimation (comparing to 64bit platform w/o reordering).
  *
- * We increase resolution only if we have enough bits to allow this increased
- * resolution (i.e. 64-bit). The costs for increasing resolution when 32-bit
- * are pretty high and the returns do not justify the increased costs.
+ * We are safe on 64bit machine.
  */
 #ifdef CONFIG_64BIT
-#define em_scale_power(p) ((p) * 1000)
+#define em_estimate_energy(cost, sum_util, scale_cpu) \
+       (((cost) * (sum_util)) / (scale_cpu))
 #else
-#define em_scale_power(p) (p)
+#define em_estimate_energy(cost, sum_util, scale_cpu) \
+       (((cost) / (scale_cpu)) * (sum_util))
 #endif
 
 struct em_data_callback {
@@ -112,7 +134,7 @@ struct em_data_callback {
         * and frequency.
         *
         * In case of CPUs, the power is the one of a single CPU in the domain,
-        * expressed in milli-Watts or an abstract scale. It is expected to
+        * expressed in micro-Watts or an abstract scale. It is expected to
         * fit in the [0, EM_MAX_POWER] range.
         *
         * Return 0 on success.
@@ -148,7 +170,7 @@ struct em_perf_domain *em_cpu_get(int cpu);
 struct em_perf_domain *em_pd_get(struct device *dev);
 int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
                                struct em_data_callback *cb, cpumask_t *span,
-                               bool milliwatts);
+                               bool microwatts);
 void em_dev_unregister_perf_domain(struct device *dev);
 
 /**
@@ -273,7 +295,7 @@ static inline unsigned long em_cpu_energy(struct em_perf_domain *pd,
         *   pd_nrg = ------------------------                       (4)
         *                  scale_cpu
         */
-       return ps->cost * sum_util / scale_cpu;
+       return em_estimate_energy(ps->cost, sum_util, scale_cpu);
 }
 
 /**
@@ -297,7 +319,7 @@ struct em_data_callback {};
 static inline
 int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
                                struct em_data_callback *cb, cpumask_t *span,
-                               bool milliwatts)
+                               bool microwatts)
 {
        return -EINVAL;
 }
index c92ac75..84a466b 100644 (file)
@@ -357,7 +357,7 @@ void irqentry_exit_to_user_mode(struct pt_regs *regs);
 /**
  * struct irqentry_state - Opaque object for exception state storage
  * @exit_rcu: Used exclusively in the irqentry_*() calls; signals whether the
- *            exit path has to invoke rcu_irq_exit().
+ *            exit path has to invoke ct_irq_exit().
  * @lockdep: Used exclusively in the irqentry_nmi_*() calls; ensures that
  *           lockdep state is restored correctly on exit from nmi.
  *
@@ -395,12 +395,12 @@ typedef struct irqentry_state {
  *
  * For kernel mode entries RCU handling is done conditional. If RCU is
  * watching then the only RCU requirement is to check whether the tick has
- * to be restarted. If RCU is not watching then rcu_irq_enter() has to be
- * invoked on entry and rcu_irq_exit() on exit.
+ * to be restarted. If RCU is not watching then ct_irq_enter() has to be
+ * invoked on entry and ct_irq_exit() on exit.
  *
- * Avoiding the rcu_irq_enter/exit() calls is an optimization but also
+ * Avoiding the ct_irq_enter/exit() calls is an optimization but also
  * solves the problem of kernel mode pagefaults which can schedule, which
- * is not possible after invoking rcu_irq_enter() without undoing it.
+ * is not possible after invoking ct_irq_enter() without undoing it.
  *
  * For user mode entries irqentry_enter_from_user_mode() is invoked to
  * establish the proper context for NOHZ_FULL. Otherwise scheduling on exit
index 4c374be..aa63e0b 100644 (file)
@@ -21,7 +21,8 @@ extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
                                             void *xattr_value,
                                             size_t xattr_value_len,
                                             struct integrity_iint_cache *iint);
-extern int evm_inode_setattr(struct dentry *dentry, struct iattr *attr);
+extern int evm_inode_setattr(struct user_namespace *mnt_userns,
+                            struct dentry *dentry, struct iattr *attr);
 extern void evm_inode_post_setattr(struct dentry *dentry, int ia_valid);
 extern int evm_inode_setxattr(struct user_namespace *mnt_userns,
                              struct dentry *dentry, const char *name,
@@ -68,7 +69,8 @@ static inline enum integrity_status evm_verifyxattr(struct dentry *dentry,
 }
 #endif
 
-static inline int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
+static inline int evm_inode_setattr(struct user_namespace *mnt_userns,
+                                   struct dentry *dentry, struct iattr *attr)
 {
        return 0;
 }
index edc2855..8ad743d 100644 (file)
 #define FANOTIFY_MARK_TYPE_BITS        (FAN_MARK_INODE | FAN_MARK_MOUNT | \
                                 FAN_MARK_FILESYSTEM)
 
+#define FANOTIFY_MARK_CMD_BITS (FAN_MARK_ADD | FAN_MARK_REMOVE | \
+                                FAN_MARK_FLUSH)
+
+#define FANOTIFY_MARK_IGNORE_BITS (FAN_MARK_IGNORED_MASK | \
+                                  FAN_MARK_IGNORE)
+
 #define FANOTIFY_MARK_FLAGS    (FANOTIFY_MARK_TYPE_BITS | \
-                                FAN_MARK_ADD | \
-                                FAN_MARK_REMOVE | \
+                                FANOTIFY_MARK_CMD_BITS | \
+                                FANOTIFY_MARK_IGNORE_BITS | \
                                 FAN_MARK_DONT_FOLLOW | \
                                 FAN_MARK_ONLYDIR | \
-                                FAN_MARK_IGNORED_MASK | \
                                 FAN_MARK_IGNORED_SURV_MODIFY | \
-                                FAN_MARK_EVICTABLE | \
-                                FAN_MARK_FLUSH)
+                                FAN_MARK_EVICTABLE)
 
 /*
  * Events that can be reported with data type FSNOTIFY_EVENT_PATH.
                                         FANOTIFY_PERM_EVENTS | \
                                         FAN_Q_OVERFLOW | FAN_ONDIR)
 
+/* Events and flags relevant only for directories */
+#define FANOTIFY_DIRONLY_EVENT_BITS    (FANOTIFY_DIRENT_EVENTS | \
+                                        FAN_EVENT_ON_CHILD | FAN_ONDIR)
+
 #define ALL_FANOTIFY_EVENT_BITS                (FANOTIFY_OUTGOING_EVENTS | \
                                         FANOTIFY_EVENT_FLAGS)
 
index ff5596d..2382dec 100644 (file)
@@ -15,6 +15,8 @@ void fbcon_new_modelist(struct fb_info *info);
 void fbcon_get_requirement(struct fb_info *info,
                           struct fb_blit_caps *caps);
 void fbcon_fb_blanked(struct fb_info *info, int blank);
+int  fbcon_modechange_possible(struct fb_info *info,
+                              struct fb_var_screeninfo *var);
 void fbcon_update_vcs(struct fb_info *info, bool all);
 void fbcon_remap_all(struct fb_info *info);
 int fbcon_set_con2fb_map_ioctl(void __user *argp);
@@ -33,6 +35,8 @@ static inline void fbcon_new_modelist(struct fb_info *info) {}
 static inline void fbcon_get_requirement(struct fb_info *info,
                                         struct fb_blit_caps *caps) {}
 static inline void fbcon_fb_blanked(struct fb_info *info, int blank) {}
+static inline int  fbcon_modechange_possible(struct fb_info *info,
+                               struct fb_var_screeninfo *var) { return 0; }
 static inline void fbcon_update_vcs(struct fb_info *info, bool all) {}
 static inline void fbcon_remap_all(struct fb_info *info) {}
 static inline int fbcon_set_con2fb_map_ioctl(void __user *argp) { return 0; }
index 1ec73d5..cbde3b1 100644 (file)
@@ -34,6 +34,7 @@
 #define PM_API_VERSION_2       2
 
 /* ATF only commands */
+#define TF_A_PM_REGISTER_SGI           0xa04
 #define PM_GET_TRUSTZONE_VERSION       0xa03
 #define PM_SET_SUSPEND_MODE            0xa02
 #define GET_CALLBACK_DATA              0xa01
@@ -468,6 +469,7 @@ int zynqmp_pm_feature(const u32 api_id);
 int zynqmp_pm_is_function_supported(const u32 api_id, const u32 id);
 int zynqmp_pm_set_feature_config(enum pm_feature_config_id id, u32 value);
 int zynqmp_pm_get_feature_config(enum pm_feature_config_id id, u32 *payload);
+int zynqmp_pm_register_sgi(u32 sgi_num, u32 reset);
 #else
 static inline int zynqmp_pm_get_api_version(u32 *version)
 {
@@ -733,6 +735,11 @@ static inline int zynqmp_pm_get_feature_config(enum pm_feature_config_id id,
 {
        return -ENODEV;
 }
+
+static inline int zynqmp_pm_register_sgi(u32 sgi_num, u32 reset)
+{
+       return -ENODEV;
+}
 #endif
 
 #endif /* __FIRMWARE_ZYNQMP_H__ */
index 7e06919..7d32b7e 100644 (file)
@@ -180,6 +180,9 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
 /* File supports async buffered reads */
 #define FMODE_BUF_RASYNC       ((__force fmode_t)0x40000000)
 
+/* File supports async nowait buffered writes */
+#define FMODE_BUF_WASYNC       ((__force fmode_t)0x80000000)
+
 /*
  * Attribute flags.  These should be or-ed together to figure out what
  * has been changed!
@@ -221,8 +224,26 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
 struct iattr {
        unsigned int    ia_valid;
        umode_t         ia_mode;
-       kuid_t          ia_uid;
-       kgid_t          ia_gid;
+       /*
+        * The two anonymous unions wrap structures with the same member.
+        *
+        * Filesystems raising FS_ALLOW_IDMAP need to use ia_vfs{g,u}id which
+        * are a dedicated type requiring the filesystem to use the dedicated
+        * helpers. Other filesystem can continue to use ia_{g,u}id until they
+        * have been ported.
+        *
+        * They always contain the same value. In other words FS_ALLOW_IDMAP
+        * pass down the same value on idmapped mounts as they would on regular
+        * mounts.
+        */
+       union {
+               kuid_t          ia_uid;
+               vfsuid_t        ia_vfsuid;
+       };
+       union {
+               kgid_t          ia_gid;
+               vfsgid_t        ia_vfsgid;
+       };
        loff_t          ia_size;
        struct timespec64 ia_atime;
        struct timespec64 ia_mtime;
@@ -1598,13 +1619,68 @@ static inline void i_gid_write(struct inode *inode, gid_t gid)
  * @mnt_userns: user namespace of the mount the inode was found from
  * @inode: inode to map
  *
+ * Note, this will eventually be removed completely in favor of the type-safe
+ * i_uid_into_vfsuid().
+ *
  * Return: the inode's i_uid mapped down according to @mnt_userns.
  * If the inode's i_uid has no mapping INVALID_UID is returned.
  */
 static inline kuid_t i_uid_into_mnt(struct user_namespace *mnt_userns,
                                    const struct inode *inode)
 {
-       return mapped_kuid_fs(mnt_userns, i_user_ns(inode), inode->i_uid);
+       return AS_KUIDT(make_vfsuid(mnt_userns, i_user_ns(inode), inode->i_uid));
+}
+
+/**
+ * i_uid_into_vfsuid - map an inode's i_uid down into a mnt_userns
+ * @mnt_userns: user namespace of the mount the inode was found from
+ * @inode: inode to map
+ *
+ * Return: whe inode's i_uid mapped down according to @mnt_userns.
+ * If the inode's i_uid has no mapping INVALID_VFSUID is returned.
+ */
+static inline vfsuid_t i_uid_into_vfsuid(struct user_namespace *mnt_userns,
+                                        const struct inode *inode)
+{
+       return make_vfsuid(mnt_userns, i_user_ns(inode), inode->i_uid);
+}
+
+/**
+ * i_uid_needs_update - check whether inode's i_uid needs to be updated
+ * @mnt_userns: user namespace of the mount the inode was found from
+ * @attr: the new attributes of @inode
+ * @inode: the inode to update
+ *
+ * Check whether the $inode's i_uid field needs to be updated taking idmapped
+ * mounts into account if the filesystem supports it.
+ *
+ * Return: true if @inode's i_uid field needs to be updated, false if not.
+ */
+static inline bool i_uid_needs_update(struct user_namespace *mnt_userns,
+                                     const struct iattr *attr,
+                                     const struct inode *inode)
+{
+       return ((attr->ia_valid & ATTR_UID) &&
+               !vfsuid_eq(attr->ia_vfsuid,
+                          i_uid_into_vfsuid(mnt_userns, inode)));
+}
+
+/**
+ * i_uid_update - update @inode's i_uid field
+ * @mnt_userns: user namespace of the mount the inode was found from
+ * @attr: the new attributes of @inode
+ * @inode: the inode to update
+ *
+ * Safely update @inode's i_uid field translating the vfsuid of any idmapped
+ * mount into the filesystem kuid.
+ */
+static inline void i_uid_update(struct user_namespace *mnt_userns,
+                               const struct iattr *attr,
+                               struct inode *inode)
+{
+       if (attr->ia_valid & ATTR_UID)
+               inode->i_uid = from_vfsuid(mnt_userns, i_user_ns(inode),
+                                          attr->ia_vfsuid);
 }
 
 /**
@@ -1612,13 +1688,68 @@ static inline kuid_t i_uid_into_mnt(struct user_namespace *mnt_userns,
  * @mnt_userns: user namespace of the mount the inode was found from
  * @inode: inode to map
  *
+ * Note, this will eventually be removed completely in favor of the type-safe
+ * i_gid_into_vfsgid().
+ *
  * Return: the inode's i_gid mapped down according to @mnt_userns.
  * If the inode's i_gid has no mapping INVALID_GID is returned.
  */
 static inline kgid_t i_gid_into_mnt(struct user_namespace *mnt_userns,
                                    const struct inode *inode)
 {
-       return mapped_kgid_fs(mnt_userns, i_user_ns(inode), inode->i_gid);
+       return AS_KGIDT(make_vfsgid(mnt_userns, i_user_ns(inode), inode->i_gid));
+}
+
+/**
+ * i_gid_into_vfsgid - map an inode's i_gid down into a mnt_userns
+ * @mnt_userns: user namespace of the mount the inode was found from
+ * @inode: inode to map
+ *
+ * Return: the inode's i_gid mapped down according to @mnt_userns.
+ * If the inode's i_gid has no mapping INVALID_VFSGID is returned.
+ */
+static inline vfsgid_t i_gid_into_vfsgid(struct user_namespace *mnt_userns,
+                                        const struct inode *inode)
+{
+       return make_vfsgid(mnt_userns, i_user_ns(inode), inode->i_gid);
+}
+
+/**
+ * i_gid_needs_update - check whether inode's i_gid needs to be updated
+ * @mnt_userns: user namespace of the mount the inode was found from
+ * @attr: the new attributes of @inode
+ * @inode: the inode to update
+ *
+ * Check whether the $inode's i_gid field needs to be updated taking idmapped
+ * mounts into account if the filesystem supports it.
+ *
+ * Return: true if @inode's i_gid field needs to be updated, false if not.
+ */
+static inline bool i_gid_needs_update(struct user_namespace *mnt_userns,
+                                     const struct iattr *attr,
+                                     const struct inode *inode)
+{
+       return ((attr->ia_valid & ATTR_GID) &&
+               !vfsgid_eq(attr->ia_vfsgid,
+                          i_gid_into_vfsgid(mnt_userns, inode)));
+}
+
+/**
+ * i_gid_update - update @inode's i_gid field
+ * @mnt_userns: user namespace of the mount the inode was found from
+ * @attr: the new attributes of @inode
+ * @inode: the inode to update
+ *
+ * Safely update @inode's i_gid field translating the vfsgid of any idmapped
+ * mount into the filesystem kgid.
+ */
+static inline void i_gid_update(struct user_namespace *mnt_userns,
+                               const struct iattr *attr,
+                               struct inode *inode)
+{
+       if (attr->ia_valid & ATTR_GID)
+               inode->i_gid = from_vfsgid(mnt_userns, i_user_ns(inode),
+                                          attr->ia_vfsgid);
 }
 
 /**
@@ -2193,8 +2324,8 @@ static inline bool sb_rdonly(const struct super_block *sb) { return sb->s_flags
 static inline bool HAS_UNMAPPED_ID(struct user_namespace *mnt_userns,
                                   struct inode *inode)
 {
-       return !uid_valid(i_uid_into_mnt(mnt_userns, inode)) ||
-              !gid_valid(i_gid_into_mnt(mnt_userns, inode));
+       return !vfsuid_valid(i_uid_into_vfsuid(mnt_userns, inode)) ||
+              !vfsgid_valid(i_gid_into_vfsgid(mnt_userns, inode));
 }
 
 static inline int iocb_flags(struct file *file);
@@ -2385,6 +2516,7 @@ static inline void file_accessed(struct file *file)
 }
 
 extern int file_modified(struct file *file);
+int kiocb_modified(struct kiocb *iocb);
 
 int sync_inode_metadata(struct inode *inode, int wait);
 
index 72585c9..720874e 100644 (file)
@@ -130,6 +130,7 @@ struct fscache_cookie {
 #define FSCACHE_COOKIE_DO_PREP_TO_WRITE        12              /* T if cookie needs write preparation */
 #define FSCACHE_COOKIE_HAVE_DATA       13              /* T if this cookie has data stored */
 #define FSCACHE_COOKIE_IS_HASHED       14              /* T if this cookie is hashed */
+#define FSCACHE_COOKIE_DO_INVALIDATE   15              /* T if cookie needs invalidation */
 
        enum fscache_cookie_state       state;
        u8                              advice;         /* FSCACHE_ADV_* */
@@ -378,7 +379,7 @@ void fscache_update_cookie(struct fscache_cookie *cookie, const void *aux_data,
  *
  * Request that the size of an object be changed.
  *
- * See Documentation/filesystems/caching/netfs-api.txt for a complete
+ * See Documentation/filesystems/caching/netfs-api.rst for a complete
  * description.
  */
 static inline
index 9560734..d7d96c8 100644 (file)
@@ -518,8 +518,8 @@ struct fsnotify_mark {
        struct hlist_node obj_list;
        /* Head of list of marks for an object [mark ref] */
        struct fsnotify_mark_connector *connector;
-       /* Events types to ignore [mark->lock, group->mark_mutex] */
-       __u32 ignored_mask;
+       /* Events types and flags to ignore [mark->lock, group->mark_mutex] */
+       __u32 ignore_mask;
        /* General fsnotify mark flags */
 #define FSNOTIFY_MARK_FLAG_ALIVE               0x0001
 #define FSNOTIFY_MARK_FLAG_ATTACHED            0x0002
@@ -529,6 +529,7 @@ struct fsnotify_mark {
        /* fanotify mark flags */
 #define FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY 0x0100
 #define FSNOTIFY_MARK_FLAG_NO_IREF             0x0200
+#define FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS    0x0400
        unsigned int flags;             /* flags [mark->lock] */
 };
 
@@ -655,15 +656,91 @@ extern void fsnotify_remove_queued_event(struct fsnotify_group *group,
 
 /* functions used to manipulate the marks attached to inodes */
 
-/* Get mask for calculating object interest taking ignored mask into account */
+/*
+ * Canonical "ignore mask" including event flags.
+ *
+ * Note the subtle semantic difference from the legacy ->ignored_mask.
+ * ->ignored_mask traditionally only meant which events should be ignored,
+ * while ->ignore_mask also includes flags regarding the type of objects on
+ * which events should be ignored.
+ */
+static inline __u32 fsnotify_ignore_mask(struct fsnotify_mark *mark)
+{
+       __u32 ignore_mask = mark->ignore_mask;
+
+       /* The event flags in ignore mask take effect */
+       if (mark->flags & FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS)
+               return ignore_mask;
+
+       /*
+        * Legacy behavior:
+        * - Always ignore events on dir
+        * - Ignore events on child if parent is watching children
+        */
+       ignore_mask |= FS_ISDIR;
+       ignore_mask &= ~FS_EVENT_ON_CHILD;
+       ignore_mask |= mark->mask & FS_EVENT_ON_CHILD;
+
+       return ignore_mask;
+}
+
+/* Legacy ignored_mask - only event types to ignore */
+static inline __u32 fsnotify_ignored_events(struct fsnotify_mark *mark)
+{
+       return mark->ignore_mask & ALL_FSNOTIFY_EVENTS;
+}
+
+/*
+ * Check if mask (or ignore mask) should be applied depending if victim is a
+ * directory and whether it is reported to a watching parent.
+ */
+static inline bool fsnotify_mask_applicable(__u32 mask, bool is_dir,
+                                           int iter_type)
+{
+       /* Should mask be applied to a directory? */
+       if (is_dir && !(mask & FS_ISDIR))
+               return false;
+
+       /* Should mask be applied to a child? */
+       if (iter_type == FSNOTIFY_ITER_TYPE_PARENT &&
+           !(mask & FS_EVENT_ON_CHILD))
+               return false;
+
+       return true;
+}
+
+/*
+ * Effective ignore mask taking into account if event victim is a
+ * directory and whether it is reported to a watching parent.
+ */
+static inline __u32 fsnotify_effective_ignore_mask(struct fsnotify_mark *mark,
+                                                  bool is_dir, int iter_type)
+{
+       __u32 ignore_mask = fsnotify_ignored_events(mark);
+
+       if (!ignore_mask)
+               return 0;
+
+       /* For non-dir and non-child, no need to consult the event flags */
+       if (!is_dir && iter_type != FSNOTIFY_ITER_TYPE_PARENT)
+               return ignore_mask;
+
+       ignore_mask = fsnotify_ignore_mask(mark);
+       if (!fsnotify_mask_applicable(ignore_mask, is_dir, iter_type))
+               return 0;
+
+       return ignore_mask & ALL_FSNOTIFY_EVENTS;
+}
+
+/* Get mask for calculating object interest taking ignore mask into account */
 static inline __u32 fsnotify_calc_mask(struct fsnotify_mark *mark)
 {
        __u32 mask = mark->mask;
 
-       if (!mark->ignored_mask)
+       if (!fsnotify_ignored_events(mark))
                return mask;
 
-       /* Interest in FS_MODIFY may be needed for clearing ignored mask */
+       /* Interest in FS_MODIFY may be needed for clearing ignore mask */
        if (!(mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
                mask |= FS_MODIFY;
 
@@ -671,7 +748,7 @@ static inline __u32 fsnotify_calc_mask(struct fsnotify_mark *mark)
         * If mark is interested in ignoring events on children, the object must
         * show interest in those events for fsnotify_parent() to notice it.
         */
-       return mask | (mark->ignored_mask & ALL_FSNOTIFY_EVENTS);
+       return mask | mark->ignore_mask;
 }
 
 /* Get mask of events for a list of marks */
index 2d2ccae..0ace775 100644 (file)
@@ -348,7 +348,7 @@ struct vm_area_struct;
 #define GFP_DMA32      __GFP_DMA32
 #define GFP_HIGHUSER   (GFP_USER | __GFP_HIGHMEM)
 #define GFP_HIGHUSER_MOVABLE   (GFP_HIGHUSER | __GFP_MOVABLE | \
-                        __GFP_SKIP_KASAN_POISON)
+                        __GFP_SKIP_KASAN_POISON | __GFP_SKIP_KASAN_UNPOISON)
 #define GFP_TRANSHUGE_LIGHT    ((GFP_HIGHUSER_MOVABLE | __GFP_COMP | \
                         __GFP_NOMEMALLOC | __GFP_NOWARN) & ~__GFP_RECLAIM)
 #define GFP_TRANSHUGE  (GFP_TRANSHUGE_LIGHT | __GFP_DIRECT_RECLAIM)
index 54c3c65..6aeea10 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/property.h>
 #include <linux/types.h>
 
+#include <asm/msi.h>
+
 struct gpio_desc;
 struct of_phandle_args;
 struct device_node;
@@ -23,6 +25,13 @@ enum gpio_lookup_flags;
 
 struct gpio_chip;
 
+union gpio_irq_fwspec {
+       struct irq_fwspec       fwspec;
+#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
+       msi_alloc_info_t        msiinfo;
+#endif
+};
+
 #define GPIO_LINE_DIRECTION_IN 1
 #define GPIO_LINE_DIRECTION_OUT        0
 
@@ -103,9 +112,10 @@ struct gpio_irq_chip {
         * variant named &gpiochip_populate_parent_fwspec_fourcell is also
         * available.
         */
-       void *(*populate_parent_alloc_arg)(struct gpio_chip *gc,
-                                      unsigned int parent_hwirq,
-                                      unsigned int parent_type);
+       int (*populate_parent_alloc_arg)(struct gpio_chip *gc,
+                                        union gpio_irq_fwspec *fwspec,
+                                        unsigned int parent_hwirq,
+                                        unsigned int parent_type);
 
        /**
         * @child_offset_to_irq:
@@ -649,28 +659,14 @@ struct bgpio_pdata {
 
 #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
 
-void *gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *gc,
+int gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *gc,
+                                           union gpio_irq_fwspec *gfwspec,
+                                           unsigned int parent_hwirq,
+                                           unsigned int parent_type);
+int gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *gc,
+                                            union gpio_irq_fwspec *gfwspec,
                                             unsigned int parent_hwirq,
                                             unsigned int parent_type);
-void *gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *gc,
-                                             unsigned int parent_hwirq,
-                                             unsigned int parent_type);
-
-#else
-
-static inline void *gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *gc,
-                                                   unsigned int parent_hwirq,
-                                                   unsigned int parent_type)
-{
-       return NULL;
-}
-
-static inline void *gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *gc,
-                                                    unsigned int parent_hwirq,
-                                                    unsigned int parent_type)
-{
-       return NULL;
-}
 
 #endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */
 
index 76878b3..d57cab4 100644 (file)
@@ -92,14 +92,6 @@ void irq_exit_rcu(void);
 #define arch_nmi_exit()                do { } while (0)
 #endif
 
-#ifdef CONFIG_TINY_RCU
-static inline void rcu_nmi_enter(void) { }
-static inline void rcu_nmi_exit(void) { }
-#else
-extern void rcu_nmi_enter(void);
-extern void rcu_nmi_exit(void);
-#endif
-
 /*
  * NMI vs Tracing
  * --------------
@@ -124,7 +116,7 @@ extern void rcu_nmi_exit(void);
        do {                                                    \
                __nmi_enter();                                  \
                lockdep_hardirq_enter();                        \
-               rcu_nmi_enter();                                \
+               ct_nmi_enter();                         \
                instrumentation_begin();                        \
                ftrace_nmi_enter();                             \
                instrumentation_end();                          \
@@ -143,7 +135,7 @@ extern void rcu_nmi_exit(void);
                instrumentation_begin();                        \
                ftrace_nmi_exit();                              \
                instrumentation_end();                          \
-               rcu_nmi_exit();                                 \
+               ct_nmi_exit();                                  \
                lockdep_hardirq_exit();                         \
                __nmi_exit();                                   \
        } while (0)
index 3af34de..56d6a01 100644 (file)
@@ -149,19 +149,19 @@ static inline void *kmap_local_folio(struct folio *folio, size_t offset);
  * It is used in atomic context when code wants to access the contents of a
  * page that might be allocated from high memory (see __GFP_HIGHMEM), for
  * example a page in the pagecache.  The API has two functions, and they
- * can be used in a manner similar to the following:
+ * can be used in a manner similar to the following::
  *
- * -- Find the page of interest. --
- * struct page *page = find_get_page(mapping, offset);
+ *   // Find the page of interest.
+ *   struct page *page = find_get_page(mapping, offset);
  *
- * -- Gain access to the contents of that page. --
- * void *vaddr = kmap_atomic(page);
+ *   // Gain access to the contents of that page.
+ *   void *vaddr = kmap_atomic(page);
  *
- * -- Do something to the contents of that page. --
- * memset(vaddr, 0, PAGE_SIZE);
+ *   // Do something to the contents of that page.
+ *   memset(vaddr, 0, PAGE_SIZE);
  *
- * -- Unmap that page. --
- * kunmap_atomic(vaddr);
+ *   // Unmap that page.
+ *   kunmap_atomic(vaddr);
  *
  * Note that the kunmap_atomic() call takes the result of the kmap_atomic()
  * call, not the argument.
index 6cabaff..116e8bd 100644 (file)
@@ -265,6 +265,12 @@ struct hisi_qm_list {
        void (*unregister_from_crypto)(struct hisi_qm *qm);
 };
 
+struct hisi_qm_poll_data {
+       struct hisi_qm *qm;
+       struct work_struct work;
+       u16 *qp_finish_id;
+};
+
 struct hisi_qm {
        enum qm_hw_ver ver;
        enum qm_fun_type fun_type;
@@ -302,6 +308,7 @@ struct hisi_qm {
        struct rw_semaphore qps_lock;
        struct idr qp_idr;
        struct hisi_qp *qp_array;
+       struct hisi_qm_poll_data *poll_data;
 
        struct mutex mailbox_lock;
 
@@ -312,7 +319,6 @@ struct hisi_qm {
        u32 error_mask;
 
        struct workqueue_struct *wq;
-       struct work_struct work;
        struct work_struct rst_work;
        struct work_struct cmd_process;
 
index de29821..4ddaf6a 100644 (file)
@@ -461,4 +461,16 @@ static inline int split_folio_to_list(struct folio *folio,
        return split_huge_page_to_list(&folio->page, list);
 }
 
+/*
+ * archs that select ARCH_WANTS_THP_SWAP but don't support THP_SWP due to
+ * limitations in the implementation like arm64 MTE can override this to
+ * false
+ */
+#ifndef arch_thp_swp_supported
+static inline bool arch_thp_swp_supported(void)
+{
+       return true;
+}
+#endif
+
 #endif /* _LINUX_HUGE_MM_H */
index 426b174..81708ca 100644 (file)
@@ -140,6 +140,11 @@ static inline int ima_measure_critical_data(const char *event_label,
 
 #endif /* CONFIG_IMA */
 
+#ifdef CONFIG_HAVE_IMA_KEXEC
+int __init ima_free_kexec_buffer(void);
+int __init ima_get_kexec_buffer(void **addr, size_t *size);
+#endif
+
 #ifdef CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT
 extern bool arch_ima_get_secureboot(void);
 extern const char * const *arch_get_ima_policy(void);
index 4f29139..5fcf89f 100644 (file)
@@ -612,7 +612,6 @@ struct intel_iommu {
 struct device_domain_info {
        struct list_head link;  /* link to domain siblings */
        struct list_head global; /* link to global list */
-       struct list_head table; /* link to pasid table */
        u32 segment;            /* PCI segment number */
        u8 bus;                 /* PCI bus number */
        u8 devfn;               /* PCI devfn number */
@@ -729,8 +728,6 @@ extern int dmar_ir_support(void);
 void *alloc_pgtable_page(int node);
 void free_pgtable_page(void *vaddr);
 struct intel_iommu *domain_get_iommu(struct dmar_domain *domain);
-int for_each_device_domain(int (*fn)(struct device_domain_info *info,
-                                    void *data), void *data);
 void iommu_flush_write_buffer(struct intel_iommu *iommu);
 int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct device *dev);
 struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn);
diff --git a/include/linux/io_uring_types.h b/include/linux/io_uring_types.h
new file mode 100644 (file)
index 0000000..f7fab37
--- /dev/null
@@ -0,0 +1,574 @@
+#ifndef IO_URING_TYPES_H
+#define IO_URING_TYPES_H
+
+#include <linux/blkdev.h>
+#include <linux/task_work.h>
+#include <linux/bitmap.h>
+#include <linux/llist.h>
+#include <uapi/linux/io_uring.h>
+
+struct io_wq_work_node {
+       struct io_wq_work_node *next;
+};
+
+struct io_wq_work_list {
+       struct io_wq_work_node *first;
+       struct io_wq_work_node *last;
+};
+
+struct io_wq_work {
+       struct io_wq_work_node list;
+       unsigned flags;
+       /* place it here instead of io_kiocb as it fills padding and saves 4B */
+       int cancel_seq;
+};
+
+struct io_fixed_file {
+       /* file * with additional FFS_* flags */
+       unsigned long file_ptr;
+};
+
+struct io_file_table {
+       struct io_fixed_file *files;
+       unsigned long *bitmap;
+       unsigned int alloc_hint;
+};
+
+struct io_notif;
+struct io_notif_slot;
+
+struct io_hash_bucket {
+       spinlock_t              lock;
+       struct hlist_head       list;
+} ____cacheline_aligned_in_smp;
+
+struct io_hash_table {
+       struct io_hash_bucket   *hbs;
+       unsigned                hash_bits;
+};
+
+/*
+ * Arbitrary limit, can be raised if need be
+ */
+#define IO_RINGFD_REG_MAX 16
+
+struct io_uring_task {
+       /* submission side */
+       int                             cached_refs;
+       const struct io_ring_ctx        *last;
+       struct io_wq                    *io_wq;
+       struct file                     *registered_rings[IO_RINGFD_REG_MAX];
+
+       struct xarray                   xa;
+       struct wait_queue_head          wait;
+       atomic_t                        in_idle;
+       atomic_t                        inflight_tracked;
+       struct percpu_counter           inflight;
+
+       struct { /* task_work */
+               struct llist_head       task_list;
+               struct callback_head    task_work;
+       } ____cacheline_aligned_in_smp;
+};
+
+struct io_uring {
+       u32 head ____cacheline_aligned_in_smp;
+       u32 tail ____cacheline_aligned_in_smp;
+};
+
+/*
+ * This data is shared with the application through the mmap at offsets
+ * IORING_OFF_SQ_RING and IORING_OFF_CQ_RING.
+ *
+ * The offsets to the member fields are published through struct
+ * io_sqring_offsets when calling io_uring_setup.
+ */
+struct io_rings {
+       /*
+        * Head and tail offsets into the ring; the offsets need to be
+        * masked to get valid indices.
+        *
+        * The kernel controls head of the sq ring and the tail of the cq ring,
+        * and the application controls tail of the sq ring and the head of the
+        * cq ring.
+        */
+       struct io_uring         sq, cq;
+       /*
+        * Bitmasks to apply to head and tail offsets (constant, equals
+        * ring_entries - 1)
+        */
+       u32                     sq_ring_mask, cq_ring_mask;
+       /* Ring sizes (constant, power of 2) */
+       u32                     sq_ring_entries, cq_ring_entries;
+       /*
+        * Number of invalid entries dropped by the kernel due to
+        * invalid index stored in array
+        *
+        * Written by the kernel, shouldn't be modified by the
+        * application (i.e. get number of "new events" by comparing to
+        * cached value).
+        *
+        * After a new SQ head value was read by the application this
+        * counter includes all submissions that were dropped reaching
+        * the new SQ head (and possibly more).
+        */
+       u32                     sq_dropped;
+       /*
+        * Runtime SQ flags
+        *
+        * Written by the kernel, shouldn't be modified by the
+        * application.
+        *
+        * The application needs a full memory barrier before checking
+        * for IORING_SQ_NEED_WAKEUP after updating the sq tail.
+        */
+       atomic_t                sq_flags;
+       /*
+        * Runtime CQ flags
+        *
+        * Written by the application, shouldn't be modified by the
+        * kernel.
+        */
+       u32                     cq_flags;
+       /*
+        * Number of completion events lost because the queue was full;
+        * this should be avoided by the application by making sure
+        * there are not more requests pending than there is space in
+        * the completion queue.
+        *
+        * Written by the kernel, shouldn't be modified by the
+        * application (i.e. get number of "new events" by comparing to
+        * cached value).
+        *
+        * As completion events come in out of order this counter is not
+        * ordered with any other data.
+        */
+       u32                     cq_overflow;
+       /*
+        * Ring buffer of completion events.
+        *
+        * The kernel writes completion events fresh every time they are
+        * produced, so the application is allowed to modify pending
+        * entries.
+        */
+       struct io_uring_cqe     cqes[] ____cacheline_aligned_in_smp;
+};
+
+struct io_restriction {
+       DECLARE_BITMAP(register_op, IORING_REGISTER_LAST);
+       DECLARE_BITMAP(sqe_op, IORING_OP_LAST);
+       u8 sqe_flags_allowed;
+       u8 sqe_flags_required;
+       bool registered;
+};
+
+struct io_submit_link {
+       struct io_kiocb         *head;
+       struct io_kiocb         *last;
+};
+
+struct io_submit_state {
+       /* inline/task_work completion list, under ->uring_lock */
+       struct io_wq_work_node  free_list;
+       /* batch completion logic */
+       struct io_wq_work_list  compl_reqs;
+       struct io_submit_link   link;
+
+       bool                    plug_started;
+       bool                    need_plug;
+       unsigned short          submit_nr;
+       struct blk_plug         plug;
+};
+
+struct io_ev_fd {
+       struct eventfd_ctx      *cq_ev_fd;
+       unsigned int            eventfd_async: 1;
+       struct rcu_head         rcu;
+};
+
+struct io_alloc_cache {
+       struct hlist_head       list;
+       unsigned int            nr_cached;
+};
+
+struct io_ring_ctx {
+       /* const or read-mostly hot data */
+       struct {
+               struct percpu_ref       refs;
+
+               struct io_rings         *rings;
+               unsigned int            flags;
+               enum task_work_notify_mode      notify_method;
+               unsigned int            compat: 1;
+               unsigned int            drain_next: 1;
+               unsigned int            restricted: 1;
+               unsigned int            off_timeout_used: 1;
+               unsigned int            drain_active: 1;
+               unsigned int            drain_disabled: 1;
+               unsigned int            has_evfd: 1;
+               unsigned int            syscall_iopoll: 1;
+       } ____cacheline_aligned_in_smp;
+
+       /* submission data */
+       struct {
+               struct mutex            uring_lock;
+
+               /*
+                * Ring buffer of indices into array of io_uring_sqe, which is
+                * mmapped by the application using the IORING_OFF_SQES offset.
+                *
+                * This indirection could e.g. be used to assign fixed
+                * io_uring_sqe entries to operations and only submit them to
+                * the queue when needed.
+                *
+                * The kernel modifies neither the indices array nor the entries
+                * array.
+                */
+               u32                     *sq_array;
+               struct io_uring_sqe     *sq_sqes;
+               unsigned                cached_sq_head;
+               unsigned                sq_entries;
+
+               /*
+                * Fixed resources fast path, should be accessed only under
+                * uring_lock, and updated through io_uring_register(2)
+                */
+               struct io_rsrc_node     *rsrc_node;
+               int                     rsrc_cached_refs;
+               atomic_t                cancel_seq;
+               struct io_file_table    file_table;
+               unsigned                nr_user_files;
+               unsigned                nr_user_bufs;
+               struct io_mapped_ubuf   **user_bufs;
+               struct io_notif_slot    *notif_slots;
+               unsigned                nr_notif_slots;
+
+               struct io_submit_state  submit_state;
+
+               struct io_buffer_list   *io_bl;
+               struct xarray           io_bl_xa;
+               struct list_head        io_buffers_cache;
+
+               struct io_hash_table    cancel_table_locked;
+               struct list_head        cq_overflow_list;
+               struct io_alloc_cache   apoll_cache;
+               struct io_alloc_cache   netmsg_cache;
+       } ____cacheline_aligned_in_smp;
+
+       /* IRQ completion list, under ->completion_lock */
+       struct io_wq_work_list  locked_free_list;
+       unsigned int            locked_free_nr;
+
+       const struct cred       *sq_creds;      /* cred used for __io_sq_thread() */
+       struct io_sq_data       *sq_data;       /* if using sq thread polling */
+
+       struct wait_queue_head  sqo_sq_wait;
+       struct list_head        sqd_list;
+
+       unsigned long           check_cq;
+
+       unsigned int            file_alloc_start;
+       unsigned int            file_alloc_end;
+
+       struct xarray           personalities;
+       u32                     pers_next;
+
+       struct {
+               /*
+                * We cache a range of free CQEs we can use, once exhausted it
+                * should go through a slower range setup, see __io_get_cqe()
+                */
+               struct io_uring_cqe     *cqe_cached;
+               struct io_uring_cqe     *cqe_sentinel;
+
+               unsigned                cached_cq_tail;
+               unsigned                cq_entries;
+               struct io_ev_fd __rcu   *io_ev_fd;
+               struct wait_queue_head  cq_wait;
+               unsigned                cq_extra;
+       } ____cacheline_aligned_in_smp;
+
+       struct {
+               spinlock_t              completion_lock;
+
+               /*
+                * ->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;
+               struct io_hash_table    cancel_table;
+               bool                    poll_multi_queue;
+
+               struct list_head        io_buffers_comp;
+       } ____cacheline_aligned_in_smp;
+
+       /* timeouts */
+       struct {
+               spinlock_t              timeout_lock;
+               atomic_t                cq_timeouts;
+               struct list_head        timeout_list;
+               struct list_head        ltimeout_list;
+               unsigned                cq_last_tm_flush;
+       } ____cacheline_aligned_in_smp;
+
+       /* Keep this last, we don't need it for the fast path */
+
+       struct io_restriction           restrictions;
+       struct task_struct              *submitter_task;
+
+       /* slow path rsrc auxilary data, used by update/register */
+       struct io_rsrc_node             *rsrc_backup_node;
+       struct io_mapped_ubuf           *dummy_ubuf;
+       struct io_rsrc_data             *file_data;
+       struct io_rsrc_data             *buf_data;
+
+       struct delayed_work             rsrc_put_work;
+       struct llist_head               rsrc_put_llist;
+       struct list_head                rsrc_ref_list;
+       spinlock_t                      rsrc_ref_lock;
+
+       struct list_head                io_buffers_pages;
+
+       #if defined(CONFIG_UNIX)
+               struct socket           *ring_sock;
+       #endif
+       /* hashed buffered write serialization */
+       struct io_wq_hash               *hash_map;
+
+       /* Only used for accounting purposes */
+       struct user_struct              *user;
+       struct mm_struct                *mm_account;
+
+       /* ctx exit and cancelation */
+       struct llist_head               fallback_llist;
+       struct delayed_work             fallback_work;
+       struct work_struct              exit_work;
+       struct list_head                tctx_list;
+       struct completion               ref_comp;
+
+       /* io-wq management, e.g. thread count */
+       u32                             iowq_limits[2];
+       bool                            iowq_limits_set;
+
+       struct list_head                defer_list;
+       unsigned                        sq_thread_idle;
+       /* protected by ->completion_lock */
+       unsigned                        evfd_last_cq_tail;
+};
+
+enum {
+       REQ_F_FIXED_FILE_BIT    = IOSQE_FIXED_FILE_BIT,
+       REQ_F_IO_DRAIN_BIT      = IOSQE_IO_DRAIN_BIT,
+       REQ_F_LINK_BIT          = IOSQE_IO_LINK_BIT,
+       REQ_F_HARDLINK_BIT      = IOSQE_IO_HARDLINK_BIT,
+       REQ_F_FORCE_ASYNC_BIT   = IOSQE_ASYNC_BIT,
+       REQ_F_BUFFER_SELECT_BIT = IOSQE_BUFFER_SELECT_BIT,
+       REQ_F_CQE_SKIP_BIT      = IOSQE_CQE_SKIP_SUCCESS_BIT,
+
+       /* first byte is taken by user flags, shift it to not overlap */
+       REQ_F_FAIL_BIT          = 8,
+       REQ_F_INFLIGHT_BIT,
+       REQ_F_CUR_POS_BIT,
+       REQ_F_NOWAIT_BIT,
+       REQ_F_LINK_TIMEOUT_BIT,
+       REQ_F_NEED_CLEANUP_BIT,
+       REQ_F_POLLED_BIT,
+       REQ_F_BUFFER_SELECTED_BIT,
+       REQ_F_BUFFER_RING_BIT,
+       REQ_F_REISSUE_BIT,
+       REQ_F_CREDS_BIT,
+       REQ_F_REFCOUNT_BIT,
+       REQ_F_ARM_LTIMEOUT_BIT,
+       REQ_F_ASYNC_DATA_BIT,
+       REQ_F_SKIP_LINK_CQES_BIT,
+       REQ_F_SINGLE_POLL_BIT,
+       REQ_F_DOUBLE_POLL_BIT,
+       REQ_F_PARTIAL_IO_BIT,
+       REQ_F_CQE32_INIT_BIT,
+       REQ_F_APOLL_MULTISHOT_BIT,
+       REQ_F_CLEAR_POLLIN_BIT,
+       REQ_F_HASH_LOCKED_BIT,
+       /* keep async read/write and isreg together and in order */
+       REQ_F_SUPPORT_NOWAIT_BIT,
+       REQ_F_ISREG_BIT,
+
+       /* not a real bit, just to check we're not overflowing the space */
+       __REQ_F_LAST_BIT,
+};
+
+enum {
+       /* ctx owns file */
+       REQ_F_FIXED_FILE        = BIT(REQ_F_FIXED_FILE_BIT),
+       /* drain existing IO first */
+       REQ_F_IO_DRAIN          = BIT(REQ_F_IO_DRAIN_BIT),
+       /* linked sqes */
+       REQ_F_LINK              = BIT(REQ_F_LINK_BIT),
+       /* doesn't sever on completion < 0 */
+       REQ_F_HARDLINK          = BIT(REQ_F_HARDLINK_BIT),
+       /* IOSQE_ASYNC */
+       REQ_F_FORCE_ASYNC       = BIT(REQ_F_FORCE_ASYNC_BIT),
+       /* IOSQE_BUFFER_SELECT */
+       REQ_F_BUFFER_SELECT     = BIT(REQ_F_BUFFER_SELECT_BIT),
+       /* IOSQE_CQE_SKIP_SUCCESS */
+       REQ_F_CQE_SKIP          = BIT(REQ_F_CQE_SKIP_BIT),
+
+       /* fail rest of links */
+       REQ_F_FAIL              = BIT(REQ_F_FAIL_BIT),
+       /* on inflight list, should be cancelled and waited on exit reliably */
+       REQ_F_INFLIGHT          = BIT(REQ_F_INFLIGHT_BIT),
+       /* read/write uses file position */
+       REQ_F_CUR_POS           = BIT(REQ_F_CUR_POS_BIT),
+       /* must not punt to workers */
+       REQ_F_NOWAIT            = BIT(REQ_F_NOWAIT_BIT),
+       /* has or had linked timeout */
+       REQ_F_LINK_TIMEOUT      = BIT(REQ_F_LINK_TIMEOUT_BIT),
+       /* needs cleanup */
+       REQ_F_NEED_CLEANUP      = BIT(REQ_F_NEED_CLEANUP_BIT),
+       /* already went through poll handler */
+       REQ_F_POLLED            = BIT(REQ_F_POLLED_BIT),
+       /* buffer already selected */
+       REQ_F_BUFFER_SELECTED   = BIT(REQ_F_BUFFER_SELECTED_BIT),
+       /* buffer selected from ring, needs commit */
+       REQ_F_BUFFER_RING       = BIT(REQ_F_BUFFER_RING_BIT),
+       /* caller should reissue async */
+       REQ_F_REISSUE           = BIT(REQ_F_REISSUE_BIT),
+       /* supports async reads/writes */
+       REQ_F_SUPPORT_NOWAIT    = BIT(REQ_F_SUPPORT_NOWAIT_BIT),
+       /* regular file */
+       REQ_F_ISREG             = BIT(REQ_F_ISREG_BIT),
+       /* has creds assigned */
+       REQ_F_CREDS             = BIT(REQ_F_CREDS_BIT),
+       /* skip refcounting if not set */
+       REQ_F_REFCOUNT          = BIT(REQ_F_REFCOUNT_BIT),
+       /* there is a linked timeout that has to be armed */
+       REQ_F_ARM_LTIMEOUT      = BIT(REQ_F_ARM_LTIMEOUT_BIT),
+       /* ->async_data allocated */
+       REQ_F_ASYNC_DATA        = BIT(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),
+       /* single poll may be active */
+       REQ_F_SINGLE_POLL       = BIT(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),
+       /* fast poll multishot mode */
+       REQ_F_APOLL_MULTISHOT   = BIT(REQ_F_APOLL_MULTISHOT_BIT),
+       /* ->extra1 and ->extra2 are initialised */
+       REQ_F_CQE32_INIT        = BIT(REQ_F_CQE32_INIT_BIT),
+       /* recvmsg special flag, clear EPOLLIN */
+       REQ_F_CLEAR_POLLIN      = BIT(REQ_F_CLEAR_POLLIN_BIT),
+       /* hashed into ->cancel_hash_locked, protected by ->uring_lock */
+       REQ_F_HASH_LOCKED       = BIT(REQ_F_HASH_LOCKED_BIT),
+};
+
+typedef void (*io_req_tw_func_t)(struct io_kiocb *req, bool *locked);
+
+struct io_task_work {
+       struct llist_node               node;
+       io_req_tw_func_t                func;
+};
+
+struct io_cqe {
+       __u64   user_data;
+       __s32   res;
+       /* fd initially, then cflags for completion */
+       union {
+               __u32   flags;
+               int     fd;
+       };
+};
+
+/*
+ * Each request type overlays its private data structure on top of this one.
+ * They must not exceed this one in size.
+ */
+struct io_cmd_data {
+       struct file             *file;
+       /* each command gets 56 bytes of data */
+       __u8                    data[56];
+};
+
+#define io_kiocb_to_cmd(req)   ((void *) &(req)->cmd)
+#define cmd_to_io_kiocb(ptr)   ((struct io_kiocb *) ptr)
+
+struct io_kiocb {
+       union {
+               /*
+                * NOTE! Each of the io_kiocb union members has the file pointer
+                * as the first entry in their struct definition. So you can
+                * access the file pointer through any of the sub-structs,
+                * or directly as just 'file' in this struct.
+                */
+               struct file             *file;
+               struct io_cmd_data      cmd;
+       };
+
+       u8                              opcode;
+       /* polled IO has completed */
+       u8                              iopoll_completed;
+       /*
+        * Can be either a fixed buffer index, or used with provided buffers.
+        * For the latter, before issue it points to the buffer group ID,
+        * and after selection it points to the buffer ID itself.
+        */
+       u16                             buf_index;
+       unsigned int                    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;
+
+               /* stores selected buf, valid IFF REQ_F_BUFFER_SELECTED is set */
+               struct io_buffer        *kbuf;
+
+               /*
+                * stores buffer ID for ring provided buffers, valid IFF
+                * REQ_F_BUFFER_RING is set.
+                */
+               struct io_buffer_list   *buf_list;
+       };
+
+       union {
+               /* used by request caches, completion batching and iopoll */
+               struct io_wq_work_node  comp_list;
+               /* cache ->apoll->events */
+               __poll_t apoll_events;
+       };
+       atomic_t                        refs;
+       atomic_t                        poll_refs;
+       struct io_task_work             io_task_work;
+       /* for polled requests, i.e. IORING_OP_POLL_ADD and async armed poll */
+       union {
+               struct hlist_node       hash_node;
+               struct {
+                       u64             extra1;
+                       u64             extra2;
+               };
+       };
+       /* internal polling, see IORING_FEAT_FAST_POLL */
+       struct async_poll               *apoll;
+       /* opcode allocated if it needs to store data for async defer */
+       void                            *async_data;
+       /* linked requests, IFF REQ_F_HARDLINK or REQ_F_LINK are set */
+       struct io_kiocb                 *link;
+       /* custom credentials, valid IFF REQ_F_CREDS is set */
+       const struct cred               *creds;
+       struct io_wq_work               work;
+};
+
+struct io_overflow_cqe {
+       struct list_head list;
+       struct io_uring_cqe cqe;
+};
+
+#endif
index 3f53bc2..7578d4f 100644 (file)
@@ -11,7 +11,7 @@
 /*
  * Default IO priority.
  */
-#define IOPRIO_DEFAULT IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, IOPRIO_BE_NORM)
+#define IOPRIO_DEFAULT IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, 0)
 
 /*
  * Check that a priority value has a valid class.
@@ -46,23 +46,19 @@ static inline int task_nice_ioclass(struct task_struct *task)
                return IOPRIO_CLASS_BE;
 }
 
-/*
- * If the calling process has set an I/O priority, use that. Otherwise, return
- * the default I/O priority.
- */
-static inline int get_current_ioprio(void)
+#ifdef CONFIG_BLOCK
+int __get_task_ioprio(struct task_struct *p);
+#else
+static inline int __get_task_ioprio(struct task_struct *p)
 {
-       struct io_context *ioc = current->io_context;
-
-       if (ioc)
-               return ioc->ioprio;
        return IOPRIO_DEFAULT;
 }
+#endif /* CONFIG_BLOCK */
 
-/*
- * For inheritance, return the highest of the two given priorities
- */
-extern int ioprio_best(unsigned short aprio, unsigned short bprio);
+static inline int get_current_ioprio(void)
+{
+       return __get_task_ioprio(current);
+}
 
 extern int set_task_ioprio(struct task_struct *task, int ioprio);
 
index 5053082..c3eb896 100644 (file)
@@ -151,7 +151,9 @@ struct irq_common_data {
 #endif
        void                    *handler_data;
        struct msi_desc         *msi_desc;
+#ifdef CONFIG_SMP
        cpumask_var_t           affinity;
+#endif
 #ifdef CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK
        cpumask_var_t           effective_affinity;
 #endif
@@ -879,21 +881,34 @@ static inline int irq_data_get_node(struct irq_data *d)
        return irq_common_data_get_node(d->common);
 }
 
-static inline struct cpumask *irq_get_affinity_mask(int irq)
+static inline
+const struct cpumask *irq_data_get_affinity_mask(struct irq_data *d)
 {
-       struct irq_data *d = irq_get_irq_data(irq);
+#ifdef CONFIG_SMP
+       return d->common->affinity;
+#else
+       return cpumask_of(0);
+#endif
+}
 
-       return d ? d->common->affinity : NULL;
+static inline void irq_data_update_affinity(struct irq_data *d,
+                                           const struct cpumask *m)
+{
+#ifdef CONFIG_SMP
+       cpumask_copy(d->common->affinity, m);
+#endif
 }
 
-static inline struct cpumask *irq_data_get_affinity_mask(struct irq_data *d)
+static inline const struct cpumask *irq_get_affinity_mask(int irq)
 {
-       return d->common->affinity;
+       struct irq_data *d = irq_get_irq_data(irq);
+
+       return d ? irq_data_get_affinity_mask(d) : NULL;
 }
 
 #ifdef CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK
 static inline
-struct cpumask *irq_data_get_effective_affinity_mask(struct irq_data *d)
+const struct cpumask *irq_data_get_effective_affinity_mask(struct irq_data *d)
 {
        return d->common->effective_affinity;
 }
@@ -908,13 +923,14 @@ static inline void irq_data_update_effective_affinity(struct irq_data *d,
 {
 }
 static inline
-struct cpumask *irq_data_get_effective_affinity_mask(struct irq_data *d)
+const struct cpumask *irq_data_get_effective_affinity_mask(struct irq_data *d)
 {
-       return d->common->affinity;
+       return irq_data_get_affinity_mask(d);
 }
 #endif
 
-static inline struct cpumask *irq_get_effective_affinity_mask(unsigned int irq)
+static inline
+const struct cpumask *irq_get_effective_affinity_mask(unsigned int irq)
 {
        struct irq_data *d = irq_get_irq_data(irq);
 
@@ -1121,6 +1137,7 @@ int irq_gc_set_wake(struct irq_data *d, unsigned int on);
 /* Setup functions for irq_chip_generic */
 int irq_map_generic_chip(struct irq_domain *d, unsigned int virq,
                         irq_hw_number_t hw_irq);
+void irq_unmap_generic_chip(struct irq_domain *d, unsigned int virq);
 struct irq_chip_generic *
 irq_alloc_generic_chip(const char *name, int nr_ct, unsigned int irq_base,
                       void __iomem *reg_base, irq_flow_handler_t handler);
index cb8455c..aa18137 100644 (file)
@@ -4,4 +4,7 @@
 
 extern struct irq_chip icu_irq_chip;
 
+extern void icu_init_irq(void);
+extern void mmp2_init_icu(void);
+
 #endif /* __IRQCHIP_MMP_H */
index a775845..1cd4e36 100644 (file)
@@ -209,14 +209,15 @@ static inline void irq_set_handler_locked(struct irq_data *data,
  * Must be called with irq_desc locked and valid parameters.
  */
 static inline void
-irq_set_chip_handler_name_locked(struct irq_data *data, struct irq_chip *chip,
+irq_set_chip_handler_name_locked(struct irq_data *data,
+                                const struct irq_chip *chip,
                                 irq_flow_handler_t handler, const char *name)
 {
        struct irq_desc *desc = irq_data_to_desc(data);
 
        desc->handle_irq = handler;
        desc->name = name;
-       data->chip = chip;
+       data->chip = (struct irq_chip *)chip;
 }
 
 bool irq_check_status_bit(unsigned int irq, unsigned int bitmask);
index e79d6e0..dc17241 100644 (file)
@@ -1557,7 +1557,7 @@ extern int           jbd2_journal_wipe       (journal_t *, int);
 extern int        jbd2_journal_skip_recovery   (journal_t *);
 extern void       jbd2_journal_update_sb_errno(journal_t *);
 extern int        jbd2_journal_update_sb_log_tail      (journal_t *, tid_t,
-                               unsigned long, int);
+                               unsigned long, blk_opf_t);
 extern void       jbd2_journal_abort      (journal_t *, int);
 extern int        jbd2_journal_errno      (journal_t *);
 extern void       jbd2_journal_ack_err    (journal_t *);
index bf1eef3..570831c 100644 (file)
@@ -220,8 +220,6 @@ extern void jump_label_lock(void);
 extern void jump_label_unlock(void);
 extern void arch_jump_label_transform(struct jump_entry *entry,
                                      enum jump_label_type type);
-extern void arch_jump_label_transform_static(struct jump_entry *entry,
-                                            enum jump_label_type type);
 extern bool arch_jump_label_transform_queue(struct jump_entry *entry,
                                            enum jump_label_type type);
 extern void arch_jump_label_transform_apply(void);
@@ -230,12 +228,12 @@ extern void static_key_slow_inc(struct static_key *key);
 extern void static_key_slow_dec(struct static_key *key);
 extern void static_key_slow_inc_cpuslocked(struct static_key *key);
 extern void static_key_slow_dec_cpuslocked(struct static_key *key);
-extern void jump_label_apply_nops(struct module *mod);
 extern int static_key_count(struct static_key *key);
 extern void static_key_enable(struct static_key *key);
 extern void static_key_disable(struct static_key *key);
 extern void static_key_enable_cpuslocked(struct static_key *key);
 extern void static_key_disable_cpuslocked(struct static_key *key);
+extern enum jump_label_type jump_label_init_type(struct jump_entry *entry);
 
 /*
  * We should be using ATOMIC_INIT() for initializing .enabled, but
@@ -303,11 +301,6 @@ static inline int jump_label_text_reserved(void *start, void *end)
 static inline void jump_label_lock(void) {}
 static inline void jump_label_unlock(void) {}
 
-static inline int jump_label_apply_nops(struct module *mod)
-{
-       return 0;
-}
-
 static inline void static_key_enable(struct static_key *key)
 {
        STATIC_KEY_CHECK_USE(key);
index 69ae6b2..ddb5a35 100644 (file)
@@ -28,6 +28,9 @@ enum cpu_usage_stat {
        CPUTIME_STEAL,
        CPUTIME_GUEST,
        CPUTIME_GUEST_NICE,
+#ifdef CONFIG_SCHED_CORE
+       CPUTIME_FORCEIDLE,
+#endif
        NR_STATS,
 };
 
@@ -115,4 +118,8 @@ extern void account_process_tick(struct task_struct *, int user);
 
 extern void account_idle_ticks(unsigned long ticks);
 
+#ifdef CONFIG_SCHED_CORE
+extern void __account_forceidle_time(struct task_struct *tsk, u64 delta);
+#endif
+
 #endif /* _LINUX_KERNEL_STAT_H */
index ce6536f..13e6c4b 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/io.h>
 
 #include <uapi/linux/kexec.h>
+#include <linux/verification.h>
 
 /* Location of a reserved region to hold the crash kernel.
  */
@@ -188,21 +189,54 @@ int kexec_purgatory_get_set_symbol(struct kimage *image, const char *name,
                                   void *buf, unsigned int size,
                                   bool get_value);
 void *kexec_purgatory_get_symbol_addr(struct kimage *image, const char *name);
+void *kexec_image_load_default(struct kimage *image);
+
+#ifndef arch_kexec_kernel_image_probe
+static inline int
+arch_kexec_kernel_image_probe(struct kimage *image, void *buf, unsigned long buf_len)
+{
+       return kexec_image_probe_default(image, buf, buf_len);
+}
+#endif
+
+#ifndef arch_kimage_file_post_load_cleanup
+static inline int arch_kimage_file_post_load_cleanup(struct kimage *image)
+{
+       return kexec_image_post_load_cleanup_default(image);
+}
+#endif
+
+#ifndef arch_kexec_kernel_image_load
+static inline void *arch_kexec_kernel_image_load(struct kimage *image)
+{
+       return kexec_image_load_default(image);
+}
+#endif
 
-/* Architectures may override the below functions */
-int arch_kexec_kernel_image_probe(struct kimage *image, void *buf,
-                                 unsigned long buf_len);
-void *arch_kexec_kernel_image_load(struct kimage *image);
-int arch_kimage_file_post_load_cleanup(struct kimage *image);
 #ifdef CONFIG_KEXEC_SIG
-int arch_kexec_kernel_verify_sig(struct kimage *image, void *buf,
-                                unsigned long buf_len);
+#ifdef CONFIG_SIGNED_PE_FILE_VERIFICATION
+int kexec_kernel_verify_pe_sig(const char *kernel, unsigned long kernel_len);
+#endif
 #endif
-int arch_kexec_locate_mem_hole(struct kexec_buf *kbuf);
 
 extern int kexec_add_buffer(struct kexec_buf *kbuf);
 int kexec_locate_mem_hole(struct kexec_buf *kbuf);
 
+#ifndef arch_kexec_locate_mem_hole
+/**
+ * arch_kexec_locate_mem_hole - Find free memory to place the segments.
+ * @kbuf:                       Parameters for the memory search.
+ *
+ * On success, kbuf->mem will have the start address of the memory region found.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+static inline int arch_kexec_locate_mem_hole(struct kexec_buf *kbuf)
+{
+       return kexec_locate_mem_hole(kbuf);
+}
+#endif
+
 /* Alignment required for elf header segment */
 #define ELF_CORE_HEADER_ALIGN   4096
 
@@ -358,7 +392,10 @@ extern void machine_kexec_cleanup(struct kimage *image);
 extern int kernel_kexec(void);
 extern struct page *kimage_alloc_control_pages(struct kimage *image,
                                                unsigned int order);
-int machine_kexec_post_load(struct kimage *image);
+
+#ifndef machine_kexec_post_load
+static inline int machine_kexec_post_load(struct kimage *image) { return 0; }
+#endif
 
 extern void __crash_kexec(struct pt_regs *);
 extern void crash_kexec(struct pt_regs *);
@@ -391,10 +428,21 @@ extern bool kexec_in_progress;
 
 int crash_shrink_memory(unsigned long new_size);
 size_t crash_get_memory_size(void);
-void crash_free_reserved_phys_range(unsigned long begin, unsigned long end);
 
-void arch_kexec_protect_crashkres(void);
-void arch_kexec_unprotect_crashkres(void);
+#ifndef arch_kexec_protect_crashkres
+/*
+ * Protection mechanism for crashkernel reserved memory after
+ * the kdump kernel is loaded.
+ *
+ * Provide an empty default implementation here -- architecture
+ * code may override this
+ */
+static inline void arch_kexec_protect_crashkres(void) { }
+#endif
+
+#ifndef arch_kexec_unprotect_crashkres
+static inline void arch_kexec_unprotect_crashkres(void) { }
+#endif
 
 #ifndef page_to_boot_pfn
 static inline unsigned long page_to_boot_pfn(struct page *page)
@@ -424,6 +472,16 @@ static inline phys_addr_t boot_phys_to_phys(unsigned long boot_phys)
 }
 #endif
 
+#ifndef crash_free_reserved_phys_range
+static inline void crash_free_reserved_phys_range(unsigned long begin, unsigned long end)
+{
+       unsigned long addr;
+
+       for (addr = begin; addr < end; addr += PAGE_SIZE)
+               free_reserved_page(boot_pfn_to_page(addr >> PAGE_SHIFT));
+}
+#endif
+
 static inline unsigned long virt_to_boot_phys(void *addr)
 {
        return phys_to_boot_phys(__pa((unsigned long)addr));
@@ -452,6 +510,12 @@ static inline int kexec_crash_loaded(void) { return 0; }
 #define kexec_in_progress false
 #endif /* CONFIG_KEXEC_CORE */
 
+#ifdef CONFIG_KEXEC_SIG
+void set_kexec_sig_enforced(void);
+#else
+static inline void set_kexec_sig_enforced(void) {}
+#endif
+
 #endif /* !defined(__ASSEBMLY__) */
 
 #endif /* LINUX_KEXEC_H */
index c20f2d5..90a45ef 100644 (file)
@@ -1513,7 +1513,7 @@ static inline void kvm_arch_end_assignment(struct kvm *kvm)
 {
 }
 
-static inline bool kvm_arch_has_assigned_device(struct kvm *kvm)
+static __always_inline bool kvm_arch_has_assigned_device(struct kvm *kvm)
 {
        return false;
 }
@@ -1822,6 +1822,15 @@ struct _kvm_stats_desc {
        STATS_DESC_PEAK(SCOPE, name, KVM_STATS_UNIT_NONE,                      \
                KVM_STATS_BASE_POW10, 0)
 
+/* Instantaneous boolean value, read only */
+#define STATS_DESC_IBOOLEAN(SCOPE, name)                                      \
+       STATS_DESC_INSTANT(SCOPE, name, KVM_STATS_UNIT_BOOLEAN,                \
+               KVM_STATS_BASE_POW10, 0)
+/* Peak (sticky) boolean value, read/write */
+#define STATS_DESC_PBOOLEAN(SCOPE, name)                                      \
+       STATS_DESC_PEAK(SCOPE, name, KVM_STATS_UNIT_BOOLEAN,                   \
+               KVM_STATS_BASE_POW10, 0)
+
 /* Cumulative time in nanosecond */
 #define STATS_DESC_TIME_NSEC(SCOPE, name)                                     \
        STATS_DESC_CUMULATIVE(SCOPE, name, KVM_STATS_UNIT_SECONDS,             \
@@ -1853,7 +1862,7 @@ struct _kvm_stats_desc {
                        HALT_POLL_HIST_COUNT),                                 \
        STATS_DESC_LOGHIST_TIME_NSEC(VCPU_GENERIC, halt_wait_hist,             \
                        HALT_POLL_HIST_COUNT),                                 \
-       STATS_DESC_ICOUNTER(VCPU_GENERIC, blocking)
+       STATS_DESC_IBOOLEAN(VCPU_GENERIC, blocking)
 
 extern struct dentry *kvm_debugfs_dir;
 
index b6829b9..1f1099d 100644 (file)
@@ -188,7 +188,7 @@ static inline void
 lockdep_init_map_waits(struct lockdep_map *lock, const char *name,
                       struct lock_class_key *key, int subclass, u8 inner, u8 outer)
 {
-       lockdep_init_map_type(lock, name, key, subclass, inner, LD_WAIT_INV, LD_LOCK_NORMAL);
+       lockdep_init_map_type(lock, name, key, subclass, inner, outer, LD_LOCK_NORMAL);
 }
 
 static inline void
@@ -211,24 +211,28 @@ static inline void lockdep_init_map(struct lockdep_map *lock, const char *name,
  * or they are too narrow (they suffer from a false class-split):
  */
 #define lockdep_set_class(lock, key)                           \
-       lockdep_init_map_waits(&(lock)->dep_map, #key, key, 0,  \
-                              (lock)->dep_map.wait_type_inner, \
-                              (lock)->dep_map.wait_type_outer)
+       lockdep_init_map_type(&(lock)->dep_map, #key, key, 0,   \
+                             (lock)->dep_map.wait_type_inner,  \
+                             (lock)->dep_map.wait_type_outer,  \
+                             (lock)->dep_map.lock_type)
 
 #define lockdep_set_class_and_name(lock, key, name)            \
-       lockdep_init_map_waits(&(lock)->dep_map, name, key, 0,  \
-                              (lock)->dep_map.wait_type_inner, \
-                              (lock)->dep_map.wait_type_outer)
+       lockdep_init_map_type(&(lock)->dep_map, name, key, 0,   \
+                             (lock)->dep_map.wait_type_inner,  \
+                             (lock)->dep_map.wait_type_outer,  \
+                             (lock)->dep_map.lock_type)
 
 #define lockdep_set_class_and_subclass(lock, key, sub)         \
-       lockdep_init_map_waits(&(lock)->dep_map, #key, key, sub,\
-                              (lock)->dep_map.wait_type_inner, \
-                              (lock)->dep_map.wait_type_outer)
+       lockdep_init_map_type(&(lock)->dep_map, #key, key, sub, \
+                             (lock)->dep_map.wait_type_inner,  \
+                             (lock)->dep_map.wait_type_outer,  \
+                             (lock)->dep_map.lock_type)
 
 #define lockdep_set_subclass(lock, sub)                                        \
-       lockdep_init_map_waits(&(lock)->dep_map, #lock, (lock)->dep_map.key, sub,\
-                              (lock)->dep_map.wait_type_inner,         \
-                              (lock)->dep_map.wait_type_outer)
+       lockdep_init_map_type(&(lock)->dep_map, #lock, (lock)->dep_map.key, sub,\
+                             (lock)->dep_map.wait_type_inner,          \
+                             (lock)->dep_map.wait_type_outer,          \
+                             (lock)->dep_map.lock_type)
 
 #define lockdep_set_novalidate_class(lock) \
        lockdep_set_class_and_name(lock, &__lockdep_no_validate__, #lock)
index 99f17cc..c3a1f78 100644 (file)
@@ -38,7 +38,6 @@ extern void lockref_get(struct lockref *);
 extern int lockref_put_return(struct lockref *);
 extern int lockref_get_not_zero(struct lockref *);
 extern int lockref_put_not_zero(struct lockref *);
-extern int lockref_get_or_lock(struct lockref *);
 extern int lockref_put_or_lock(struct lockref *);
 
 extern void lockref_mark_dead(struct lockref *);
index eafa1d2..8064481 100644 (file)
@@ -201,6 +201,7 @@ LSM_HOOK(int, 0, task_fix_setuid, struct cred *new, const struct cred *old,
         int flags)
 LSM_HOOK(int, 0, task_fix_setgid, struct cred *new, const struct cred * old,
         int flags)
+LSM_HOOK(int, 0, task_fix_setgroups, struct cred *new, const struct cred * old)
 LSM_HOOK(int, 0, task_setpgid, struct task_struct *p, pid_t pgid)
 LSM_HOOK(int, 0, task_getpgid, struct task_struct *p)
 LSM_HOOK(int, 0, task_getsid, struct task_struct *p)
index 91c8146..84a0d7e 100644 (file)
  *     @old is the set of credentials that are being replaced.
  *     @flags contains one of the LSM_SETID_* values.
  *     Return 0 on success.
+ * @task_fix_setgroups:
+ *     Update the module's state after setting the supplementary group
+ *     identity attributes of the current process.
+ *     @new is the set of credentials that will be installed.  Modifications
+ *     should be made to this rather than to @current->cred.
+ *     @old is the set of credentials that are being replaced.
+ *     Return 0 on success.
  * @task_setpgid:
  *     Check permission before setting the process group identifier of the
  *     process @p to @pgid.
index e115952..c04c4fd 100644 (file)
@@ -16,7 +16,7 @@ static inline int memregion_alloc(gfp_t gfp)
 {
        return -ENOMEM;
 }
-void memregion_free(int id)
+static inline void memregion_free(int id)
 {
 }
 #endif
index ed37dc4..f70a810 100644 (file)
@@ -9,6 +9,7 @@ struct bcm2835_pm {
        struct device *dev;
        void __iomem *base;
        void __iomem *asb;
+       void __iomem *rpivid_asb;
 };
 
 #endif /* BCM2835_MFD_PM_H */
index bc8f326..7898e29 100644 (file)
@@ -1130,23 +1130,27 @@ static inline bool is_zone_movable_page(const struct page *page)
 #if defined(CONFIG_ZONE_DEVICE) && defined(CONFIG_FS_DAX)
 DECLARE_STATIC_KEY_FALSE(devmap_managed_key);
 
-bool __put_devmap_managed_page(struct page *page);
-static inline bool put_devmap_managed_page(struct page *page)
+bool __put_devmap_managed_page_refs(struct page *page, int refs);
+static inline bool put_devmap_managed_page_refs(struct page *page, int refs)
 {
        if (!static_branch_unlikely(&devmap_managed_key))
                return false;
        if (!is_zone_device_page(page))
                return false;
-       return __put_devmap_managed_page(page);
+       return __put_devmap_managed_page_refs(page, refs);
 }
-
 #else /* CONFIG_ZONE_DEVICE && CONFIG_FS_DAX */
-static inline bool put_devmap_managed_page(struct page *page)
+static inline bool put_devmap_managed_page_refs(struct page *page, int refs)
 {
        return false;
 }
 #endif /* CONFIG_ZONE_DEVICE && CONFIG_FS_DAX */
 
+static inline bool put_devmap_managed_page(struct page *page)
+{
+       return put_devmap_managed_page_refs(page, 1);
+}
+
 /* 127: arbitrary random number, small enough to assemble well */
 #define folio_ref_zero_or_close_to_overflow(folio) \
        ((unsigned int) folio_ref_count(folio) + 127u <= 127u)
@@ -1600,7 +1604,7 @@ static inline bool is_pinnable_page(struct page *page)
        if (mt == MIGRATE_CMA || mt == MIGRATE_ISOLATE)
                return false;
 #endif
-       return !(is_zone_movable_page(page) || is_zero_pfn(page_to_pfn(page)));
+       return !is_zone_movable_page(page) || is_zero_pfn(page_to_pfn(page));
 }
 #else
 static inline bool is_pinnable_page(struct page *page)
@@ -3232,6 +3236,7 @@ enum mf_flags {
        MF_MUST_KILL = 1 << 2,
        MF_SOFT_OFFLINE = 1 << 3,
        MF_UNPOISON = 1 << 4,
+       MF_SW_SIMULATED = 1 << 5,
 };
 extern int memory_failure(unsigned long pfn, int flags);
 extern void memory_failure_queue(unsigned long pfn, int flags);
index ee5a217..f6e5369 100644 (file)
@@ -13,6 +13,129 @@ struct user_namespace;
  */
 extern struct user_namespace init_user_ns;
 
+typedef struct {
+       uid_t val;
+} vfsuid_t;
+
+typedef struct {
+       gid_t val;
+} vfsgid_t;
+
+static_assert(sizeof(vfsuid_t) == sizeof(kuid_t));
+static_assert(sizeof(vfsgid_t) == sizeof(kgid_t));
+static_assert(offsetof(vfsuid_t, val) == offsetof(kuid_t, val));
+static_assert(offsetof(vfsgid_t, val) == offsetof(kgid_t, val));
+
+#ifdef CONFIG_MULTIUSER
+static inline uid_t __vfsuid_val(vfsuid_t uid)
+{
+       return uid.val;
+}
+
+static inline gid_t __vfsgid_val(vfsgid_t gid)
+{
+       return gid.val;
+}
+#else
+static inline uid_t __vfsuid_val(vfsuid_t uid)
+{
+       return 0;
+}
+
+static inline gid_t __vfsgid_val(vfsgid_t gid)
+{
+       return 0;
+}
+#endif
+
+static inline bool vfsuid_valid(vfsuid_t uid)
+{
+       return __vfsuid_val(uid) != (uid_t)-1;
+}
+
+static inline bool vfsgid_valid(vfsgid_t gid)
+{
+       return __vfsgid_val(gid) != (gid_t)-1;
+}
+
+static inline bool vfsuid_eq(vfsuid_t left, vfsuid_t right)
+{
+       return vfsuid_valid(left) && __vfsuid_val(left) == __vfsuid_val(right);
+}
+
+static inline bool vfsgid_eq(vfsgid_t left, vfsgid_t right)
+{
+       return vfsgid_valid(left) && __vfsgid_val(left) == __vfsgid_val(right);
+}
+
+/**
+ * vfsuid_eq_kuid - check whether kuid and vfsuid have the same value
+ * @vfsuid: the vfsuid to compare
+ * @kuid: the kuid to compare
+ *
+ * Check whether @vfsuid and @kuid have the same values.
+ *
+ * Return: true if @vfsuid and @kuid have the same value, false if not.
+ * Comparison between two invalid uids returns false.
+ */
+static inline bool vfsuid_eq_kuid(vfsuid_t vfsuid, kuid_t kuid)
+{
+       return vfsuid_valid(vfsuid) && __vfsuid_val(vfsuid) == __kuid_val(kuid);
+}
+
+/**
+ * vfsgid_eq_kgid - check whether kgid and vfsgid have the same value
+ * @vfsgid: the vfsgid to compare
+ * @kgid: the kgid to compare
+ *
+ * Check whether @vfsgid and @kgid have the same values.
+ *
+ * Return: true if @vfsgid and @kgid have the same value, false if not.
+ * Comparison between two invalid gids returns false.
+ */
+static inline bool vfsgid_eq_kgid(vfsgid_t vfsgid, kgid_t kgid)
+{
+       return vfsgid_valid(vfsgid) && __vfsgid_val(vfsgid) == __kgid_val(kgid);
+}
+
+/*
+ * vfs{g,u}ids are created from k{g,u}ids.
+ * We don't allow them to be created from regular {u,g}id.
+ */
+#define VFSUIDT_INIT(val) (vfsuid_t){ __kuid_val(val) }
+#define VFSGIDT_INIT(val) (vfsgid_t){ __kgid_val(val) }
+
+#define INVALID_VFSUID VFSUIDT_INIT(INVALID_UID)
+#define INVALID_VFSGID VFSGIDT_INIT(INVALID_GID)
+
+/*
+ * Allow a vfs{g,u}id to be used as a k{g,u}id where we want to compare
+ * whether the mapped value is identical to value of a k{g,u}id.
+ */
+#define AS_KUIDT(val) (kuid_t){ __vfsuid_val(val) }
+#define AS_KGIDT(val) (kgid_t){ __vfsgid_val(val) }
+
+#ifdef CONFIG_MULTIUSER
+/**
+ * vfsgid_in_group_p() - check whether a vfsuid matches the caller's groups
+ * @vfsgid: the mnt gid to match
+ *
+ * This function can be used to determine whether @vfsuid matches any of the
+ * caller's groups.
+ *
+ * Return: 1 if vfsuid matches caller's groups, 0 if not.
+ */
+static inline int vfsgid_in_group_p(vfsgid_t vfsgid)
+{
+       return in_group_p(AS_KGIDT(vfsgid));
+}
+#else
+static inline int vfsgid_in_group_p(vfsgid_t vfsgid)
+{
+       return 1;
+}
+#endif
+
 /**
  * initial_idmapping - check whether this is the initial mapping
  * @ns: idmapping to check
@@ -48,7 +171,7 @@ static inline bool no_idmapping(const struct user_namespace *mnt_userns,
 }
 
 /**
- * mapped_kuid_fs - map a filesystem kuid into a mnt_userns
+ * make_vfsuid - map a filesystem kuid into a mnt_userns
  * @mnt_userns: the mount's idmapping
  * @fs_userns: the filesystem's idmapping
  * @kuid : kuid to be mapped
@@ -67,25 +190,33 @@ static inline bool no_idmapping(const struct user_namespace *mnt_userns,
  * If @kuid has no mapping in either @mnt_userns or @fs_userns INVALID_UID is
  * returned.
  */
-static inline kuid_t mapped_kuid_fs(struct user_namespace *mnt_userns,
-                                   struct user_namespace *fs_userns,
-                                   kuid_t kuid)
+
+static inline vfsuid_t make_vfsuid(struct user_namespace *mnt_userns,
+                                  struct user_namespace *fs_userns,
+                                  kuid_t kuid)
 {
        uid_t uid;
 
        if (no_idmapping(mnt_userns, fs_userns))
-               return kuid;
+               return VFSUIDT_INIT(kuid);
        if (initial_idmapping(fs_userns))
                uid = __kuid_val(kuid);
        else
                uid = from_kuid(fs_userns, kuid);
        if (uid == (uid_t)-1)
-               return INVALID_UID;
-       return make_kuid(mnt_userns, uid);
+               return INVALID_VFSUID;
+       return VFSUIDT_INIT(make_kuid(mnt_userns, uid));
+}
+
+static inline kuid_t mapped_kuid_fs(struct user_namespace *mnt_userns,
+                                   struct user_namespace *fs_userns,
+                                   kuid_t kuid)
+{
+       return AS_KUIDT(make_vfsuid(mnt_userns, fs_userns, kuid));
 }
 
 /**
- * mapped_kgid_fs - map a filesystem kgid into a mnt_userns
+ * make_vfsgid - map a filesystem kgid into a mnt_userns
  * @mnt_userns: the mount's idmapping
  * @fs_userns: the filesystem's idmapping
  * @kgid : kgid to be mapped
@@ -104,21 +235,56 @@ static inline kuid_t mapped_kuid_fs(struct user_namespace *mnt_userns,
  * If @kgid has no mapping in either @mnt_userns or @fs_userns INVALID_GID is
  * returned.
  */
-static inline kgid_t mapped_kgid_fs(struct user_namespace *mnt_userns,
-                                   struct user_namespace *fs_userns,
-                                   kgid_t kgid)
+
+static inline vfsgid_t make_vfsgid(struct user_namespace *mnt_userns,
+                                  struct user_namespace *fs_userns,
+                                  kgid_t kgid)
 {
        gid_t gid;
 
        if (no_idmapping(mnt_userns, fs_userns))
-               return kgid;
+               return VFSGIDT_INIT(kgid);
        if (initial_idmapping(fs_userns))
                gid = __kgid_val(kgid);
        else
                gid = from_kgid(fs_userns, kgid);
        if (gid == (gid_t)-1)
-               return INVALID_GID;
-       return make_kgid(mnt_userns, gid);
+               return INVALID_VFSGID;
+       return VFSGIDT_INIT(make_kgid(mnt_userns, gid));
+}
+
+static inline kgid_t mapped_kgid_fs(struct user_namespace *mnt_userns,
+                                   struct user_namespace *fs_userns,
+                                   kgid_t kgid)
+{
+       return AS_KGIDT(make_vfsgid(mnt_userns, fs_userns, kgid));
+}
+
+/**
+ * from_vfsuid - map a vfsuid into the filesystem idmapping
+ * @mnt_userns: the mount's idmapping
+ * @fs_userns: the filesystem's idmapping
+ * @vfsuid : vfsuid to be mapped
+ *
+ * Map @vfsuid into the filesystem idmapping. This function has to be used in
+ * order to e.g. write @vfsuid to inode->i_uid.
+ *
+ * Return: @vfsuid mapped into the filesystem idmapping
+ */
+static inline kuid_t from_vfsuid(struct user_namespace *mnt_userns,
+                                struct user_namespace *fs_userns,
+                                vfsuid_t vfsuid)
+{
+       uid_t uid;
+
+       if (no_idmapping(mnt_userns, fs_userns))
+               return AS_KUIDT(vfsuid);
+       uid = from_kuid(mnt_userns, AS_KUIDT(vfsuid));
+       if (uid == (uid_t)-1)
+               return INVALID_UID;
+       if (initial_idmapping(fs_userns))
+               return KUIDT_INIT(uid);
+       return make_kuid(fs_userns, uid);
 }
 
 /**
@@ -145,16 +311,66 @@ static inline kuid_t mapped_kuid_user(struct user_namespace *mnt_userns,
                                      struct user_namespace *fs_userns,
                                      kuid_t kuid)
 {
-       uid_t uid;
+       return from_vfsuid(mnt_userns, fs_userns, VFSUIDT_INIT(kuid));
+}
+
+/**
+ * vfsuid_has_fsmapping - check whether a vfsuid maps into the filesystem
+ * @mnt_userns: the mount's idmapping
+ * @fs_userns: the filesystem's idmapping
+ * @vfsuid: vfsuid to be mapped
+ *
+ * Check whether @vfsuid has a mapping in the filesystem idmapping. Use this
+ * function to check whether the filesystem idmapping has a mapping for
+ * @vfsuid.
+ *
+ * Return: true if @vfsuid has a mapping in the filesystem, false if not.
+ */
+static inline bool vfsuid_has_fsmapping(struct user_namespace *mnt_userns,
+                                       struct user_namespace *fs_userns,
+                                       vfsuid_t vfsuid)
+{
+       return uid_valid(from_vfsuid(mnt_userns, fs_userns, vfsuid));
+}
+
+/**
+ * vfsuid_into_kuid - convert vfsuid into kuid
+ * @vfsuid: the vfsuid to convert
+ *
+ * This can be used when a vfsuid is committed as a kuid.
+ *
+ * Return: a kuid with the value of @vfsuid
+ */
+static inline kuid_t vfsuid_into_kuid(vfsuid_t vfsuid)
+{
+       return AS_KUIDT(vfsuid);
+}
+
+/**
+ * from_vfsgid - map a vfsgid into the filesystem idmapping
+ * @mnt_userns: the mount's idmapping
+ * @fs_userns: the filesystem's idmapping
+ * @vfsgid : vfsgid to be mapped
+ *
+ * Map @vfsgid into the filesystem idmapping. This function has to be used in
+ * order to e.g. write @vfsgid to inode->i_gid.
+ *
+ * Return: @vfsgid mapped into the filesystem idmapping
+ */
+static inline kgid_t from_vfsgid(struct user_namespace *mnt_userns,
+                                struct user_namespace *fs_userns,
+                                vfsgid_t vfsgid)
+{
+       gid_t gid;
 
        if (no_idmapping(mnt_userns, fs_userns))
-               return kuid;
-       uid = from_kuid(mnt_userns, kuid);
-       if (uid == (uid_t)-1)
-               return INVALID_UID;
+               return AS_KGIDT(vfsgid);
+       gid = from_kgid(mnt_userns, AS_KGIDT(vfsgid));
+       if (gid == (gid_t)-1)
+               return INVALID_GID;
        if (initial_idmapping(fs_userns))
-               return KUIDT_INIT(uid);
-       return make_kuid(fs_userns, uid);
+               return KGIDT_INIT(gid);
+       return make_kgid(fs_userns, gid);
 }
 
 /**
@@ -181,16 +397,39 @@ static inline kgid_t mapped_kgid_user(struct user_namespace *mnt_userns,
                                      struct user_namespace *fs_userns,
                                      kgid_t kgid)
 {
-       gid_t gid;
+       return from_vfsgid(mnt_userns, fs_userns, VFSGIDT_INIT(kgid));
+}
 
-       if (no_idmapping(mnt_userns, fs_userns))
-               return kgid;
-       gid = from_kgid(mnt_userns, kgid);
-       if (gid == (gid_t)-1)
-               return INVALID_GID;
-       if (initial_idmapping(fs_userns))
-               return KGIDT_INIT(gid);
-       return make_kgid(fs_userns, gid);
+/**
+ * vfsgid_has_fsmapping - check whether a vfsgid maps into the filesystem
+ * @mnt_userns: the mount's idmapping
+ * @fs_userns: the filesystem's idmapping
+ * @vfsgid: vfsgid to be mapped
+ *
+ * Check whether @vfsgid has a mapping in the filesystem idmapping. Use this
+ * function to check whether the filesystem idmapping has a mapping for
+ * @vfsgid.
+ *
+ * Return: true if @vfsgid has a mapping in the filesystem, false if not.
+ */
+static inline bool vfsgid_has_fsmapping(struct user_namespace *mnt_userns,
+                                       struct user_namespace *fs_userns,
+                                       vfsgid_t vfsgid)
+{
+       return gid_valid(from_vfsgid(mnt_userns, fs_userns, vfsgid));
+}
+
+/**
+ * vfsgid_into_kgid - convert vfsgid into kgid
+ * @vfsgid: the vfsgid to convert
+ *
+ * This can be used when a vfsgid is committed as a kgid.
+ *
+ * Return: a kgid with the value of @vfsgid
+ */
+static inline kgid_t vfsgid_into_kgid(vfsgid_t vfsgid)
+{
+       return AS_KGIDT(vfsgid);
 }
 
 /**
@@ -209,7 +448,8 @@ static inline kgid_t mapped_kgid_user(struct user_namespace *mnt_userns,
 static inline kuid_t mapped_fsuid(struct user_namespace *mnt_userns,
                                  struct user_namespace *fs_userns)
 {
-       return mapped_kuid_user(mnt_userns, fs_userns, current_fsuid());
+       return from_vfsuid(mnt_userns, fs_userns,
+                          VFSUIDT_INIT(current_fsuid()));
 }
 
 /**
@@ -228,7 +468,8 @@ static inline kuid_t mapped_fsuid(struct user_namespace *mnt_userns,
 static inline kgid_t mapped_fsgid(struct user_namespace *mnt_userns,
                                  struct user_namespace *fs_userns)
 {
-       return mapped_kgid_user(mnt_userns, fs_userns, current_fsgid());
+       return from_vfsgid(mnt_userns, fs_userns,
+                          VFSGIDT_INIT(current_fsgid()));
 }
 
 #endif /* _LINUX_MNT_IDMAPPING_H */
index abd9fa9..518296e 100644 (file)
@@ -505,6 +505,11 @@ struct module {
        int num_static_call_sites;
        struct static_call_site *static_call_sites;
 #endif
+#if IS_ENABLED(CONFIG_KUNIT)
+       int num_kunit_suites;
+       struct kunit_suite **kunit_suites;
+#endif
+
 
 #ifdef CONFIG_LIVEPATCH
        bool klp; /* Is this a livepatch module? */
index f615a66..2563d30 100644 (file)
@@ -1671,7 +1671,7 @@ enum netdev_priv_flags {
        IFF_FAILOVER_SLAVE              = 1<<28,
        IFF_L3MDEV_RX_HANDLER           = 1<<29,
        IFF_LIVE_RENAME_OK              = 1<<30,
-       IFF_TX_SKB_NO_LINEAR            = 1<<31,
+       IFF_TX_SKB_NO_LINEAR            = BIT_ULL(31),
        IFF_CHANGE_PROTO_DOWN           = BIT_ULL(32),
 };
 
index 11df38d..f2402dd 100644 (file)
@@ -214,7 +214,7 @@ struct netfs_request_ops {
        void (*issue_read)(struct netfs_io_subrequest *subreq);
        bool (*is_still_valid)(struct netfs_io_request *rreq);
        int (*check_write_begin)(struct file *file, loff_t pos, unsigned len,
-                                struct folio *folio, void **_fsdata);
+                                struct folio **foliop, void **_fsdata);
        void (*done)(struct netfs_io_request *rreq);
 };
 
index e393400..07cfc92 100644 (file)
@@ -906,12 +906,14 @@ struct nvme_common_command {
        __le32                  cdw2[2];
        __le64                  metadata;
        union nvme_data_ptr     dptr;
+       struct_group(cdws,
        __le32                  cdw10;
        __le32                  cdw11;
        __le32                  cdw12;
        __le32                  cdw13;
        __le32                  cdw14;
        __le32                  cdw15;
+       );
 };
 
 struct nvme_rw_command {
index 15b940e..62c54ff 100644 (file)
@@ -32,11 +32,16 @@ struct unwind_hint {
  *
  * UNWIND_HINT_FUNC: Generate the unwind metadata of a callable function.
  * Useful for code which doesn't have an ELF function annotation.
+ *
+ * UNWIND_HINT_ENTRY: machine entry without stack, SYSCALL/SYSENTER etc.
  */
 #define UNWIND_HINT_TYPE_CALL          0
 #define UNWIND_HINT_TYPE_REGS          1
 #define UNWIND_HINT_TYPE_REGS_PARTIAL  2
 #define UNWIND_HINT_TYPE_FUNC          3
+#define UNWIND_HINT_TYPE_ENTRY         4
+#define UNWIND_HINT_TYPE_SAVE          5
+#define UNWIND_HINT_TYPE_RESTORE       6
 
 #ifdef CONFIG_OBJTOOL
 
@@ -62,7 +67,7 @@ struct unwind_hint {
  * It should only be used in special cases where you're 100% sure it won't
  * affect the reliability of frame pointers and kernel stack traces.
  *
- * For more information, see tools/objtool/Documentation/stack-validation.txt.
+ * For more information, see tools/objtool/Documentation/objtool.txt.
  */
 #define STACK_FRAME_NON_STANDARD(func) \
        static void __used __section(".discard.func_stack_frame_non_standard") \
@@ -124,7 +129,7 @@ struct unwind_hint {
  * the debuginfo as necessary.  It will also warn if it sees any
  * inconsistencies.
  */
-.macro UNWIND_HINT sp_reg:req sp_offset=0 type:req end=0
+.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 end=0
 .Lunwind_hint_ip_\@:
        .pushsection .discard.unwind_hints
                /* struct unwind_hint */
@@ -177,7 +182,7 @@ struct unwind_hint {
 #define ASM_REACHABLE
 #else
 #define ANNOTATE_INTRA_FUNCTION_CALL
-.macro UNWIND_HINT sp_reg:req sp_offset=0 type:req end=0
+.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 end=0
 .endm
 .macro STACK_FRAME_NON_STANDARD func:req
 .endm
index f0a5d6b..20a4e7c 100644 (file)
@@ -441,8 +441,6 @@ void *of_kexec_alloc_and_setup_fdt(const struct kimage *image,
                                   unsigned long initrd_load_addr,
                                   unsigned long initrd_len,
                                   const char *cmdline, size_t extra_fdt_size);
-int ima_get_kexec_buffer(void **addr, size_t *size);
-int ima_free_kexec_buffer(void);
 #else /* CONFIG_OF */
 
 static inline void of_core_init(void)
index 861e606..b7bce49 100644 (file)
@@ -9,15 +9,27 @@
  */
 #define DO_ONCE_LITE(func, ...)                                                \
        DO_ONCE_LITE_IF(true, func, ##__VA_ARGS__)
-#define DO_ONCE_LITE_IF(condition, func, ...)                          \
+
+#define __ONCE_LITE_IF(condition)                                      \
        ({                                                              \
                static bool __section(".data.once") __already_done;     \
-               bool __ret_do_once = !!(condition);                     \
+               bool __ret_cond = !!(condition);                        \
+               bool __ret_once = false;                                \
                                                                        \
-               if (unlikely(__ret_do_once && !__already_done)) {       \
+               if (unlikely(__ret_cond && !__already_done)) {          \
                        __already_done = true;                          \
-                       func(__VA_ARGS__);                              \
+                       __ret_once = true;                              \
                }                                                       \
+               unlikely(__ret_once);                                   \
+       })
+
+#define DO_ONCE_LITE_IF(condition, func, ...)                          \
+       ({                                                              \
+               bool __ret_do_once = !!(condition);                     \
+                                                                       \
+               if (__ONCE_LITE_IF(__ret_do_once))                      \
+                       func(__VA_ARGS__);                              \
+                                                                       \
                unlikely(__ret_do_once);                                \
        })
 
index e71161d..c7759b3 100644 (file)
@@ -68,7 +68,8 @@ static inline void set_arch_panic_timeout(int timeout, int arch_default_timeout)
 #define TAINT_LIVEPATCH                        15
 #define TAINT_AUX                      16
 #define TAINT_RANDSTRUCT               17
-#define TAINT_FLAGS_COUNT              18
+#define TAINT_TEST                     18
+#define TAINT_FLAGS_COUNT              19
 #define TAINT_FLAGS_MAX                        ((1UL << TAINT_FLAGS_COUNT) - 1)
 
 struct taint_flag {
index 0178823..7fa460c 100644 (file)
 #define PCI_DEVICE_ID_AMD_17H_M30H_DF_F3 0x1493
 #define PCI_DEVICE_ID_AMD_17H_M60H_DF_F3 0x144b
 #define PCI_DEVICE_ID_AMD_17H_M70H_DF_F3 0x1443
+#define PCI_DEVICE_ID_AMD_17H_MA0H_DF_F3 0x1727
 #define PCI_DEVICE_ID_AMD_19H_DF_F3    0x1653
 #define PCI_DEVICE_ID_AMD_19H_M10H_DF_F3 0x14b0
 #define PCI_DEVICE_ID_AMD_19H_M40H_DF_F3 0x167c
 #define PCI_DEVICE_ID_AMD_19H_M50H_DF_F3 0x166d
+#define PCI_DEVICE_ID_AMD_19H_M60H_DF_F3 0x14e3
+#define PCI_DEVICE_ID_AMD_19H_M70H_DF_F3 0x14f3
 #define PCI_DEVICE_ID_AMD_CNB17H_F3    0x1703
 #define PCI_DEVICE_ID_AMD_LANCE                0x2000
 #define PCI_DEVICE_ID_AMD_LANCE_HOME   0x2001
index 46f9b6f..bf66fe0 100644 (file)
@@ -56,9 +56,13 @@ struct riscv_pmu {
 
        struct cpu_hw_events    __percpu *hw_events;
        struct hlist_node       node;
+       struct notifier_block   riscv_pm_nb;
 };
 
 #define to_riscv_pmu(p) (container_of(p, struct riscv_pmu, pmu))
+
+void riscv_pmu_start(struct perf_event *event, int flags);
+void riscv_pmu_stop(struct perf_event *event, int flags);
 unsigned long riscv_pmu_ctr_read_csr(unsigned long csr);
 int riscv_pmu_event_set_period(struct perf_event *event);
 uint64_t riscv_pmu_ctr_get_width_mask(struct perf_event *event);
index da75956..ee8b9ec 100644 (file)
@@ -759,6 +759,8 @@ struct perf_event {
        struct pid_namespace            *ns;
        u64                             id;
 
+       atomic64_t                      lost_samples;
+
        u64                             (*clock)(void);
        perf_overflow_handler_t         overflow_handler;
        void                            *overflow_handler_context;
index 508f114..b09f7d3 100644 (file)
@@ -572,6 +572,10 @@ struct macsec_ops;
  * @mdix_ctrl: User setting of crossover
  * @pma_extable: Cached value of PMA/PMD Extended Abilities Register
  * @interrupts: Flag interrupts have been enabled
+ * @irq_suspended: Flag indicating PHY is suspended and therefore interrupt
+ *                 handling shall be postponed until PHY has resumed
+ * @irq_rerun: Flag indicating interrupts occurred while PHY was suspended,
+ *             requiring a rerun of the interrupt handler after resume
  * @interface: enum phy_interface_t value
  * @skb: Netlink message for cable diagnostics
  * @nest: Netlink nest used for cable diagnostics
@@ -626,6 +630,8 @@ struct phy_device {
 
        /* Interrupts are enabled */
        unsigned interrupts:1;
+       unsigned irq_suspended:1;
+       unsigned irq_rerun:1;
 
        enum phy_state state;
 
index 9e4d056..0a41b2d 100644 (file)
@@ -88,7 +88,7 @@ extern void pm_runtime_get_suppliers(struct device *dev);
 extern void pm_runtime_put_suppliers(struct device *dev);
 extern void pm_runtime_new_link(struct device *dev);
 extern void pm_runtime_drop_link(struct device_link *link);
-extern void pm_runtime_release_supplier(struct device_link *link, bool check_idle);
+extern void pm_runtime_release_supplier(struct device_link *link);
 
 extern int devm_pm_runtime_enable(struct device *dev);
 
@@ -314,8 +314,7 @@ static inline void pm_runtime_get_suppliers(struct device *dev) {}
 static inline void pm_runtime_put_suppliers(struct device *dev) {}
 static inline void pm_runtime_new_link(struct device *dev) {}
 static inline void pm_runtime_drop_link(struct device_link *link) {}
-static inline void pm_runtime_release_supplier(struct device_link *link,
-                                              bool check_idle) {}
+static inline void pm_runtime_release_supplier(struct device_link *link) {}
 
 #endif /* !CONFIG_PM */
 
index 196a157..77f4849 100644 (file)
@@ -109,7 +109,6 @@ extern struct wakeup_source *wakeup_sources_walk_next(struct wakeup_source *ws);
 extern int device_wakeup_enable(struct device *dev);
 extern int device_wakeup_disable(struct device *dev);
 extern void device_set_wakeup_capable(struct device *dev, bool capable);
-extern int device_init_wakeup(struct device *dev, bool val);
 extern int device_set_wakeup_enable(struct device *dev, bool enable);
 extern void __pm_stay_awake(struct wakeup_source *ws);
 extern void pm_stay_awake(struct device *dev);
@@ -167,13 +166,6 @@ static inline int device_set_wakeup_enable(struct device *dev, bool enable)
        return 0;
 }
 
-static inline int device_init_wakeup(struct device *dev, bool val)
-{
-       device_set_wakeup_capable(dev, val);
-       device_set_wakeup_enable(dev, val);
-       return 0;
-}
-
 static inline bool device_may_wakeup(struct device *dev)
 {
        return dev->power.can_wakeup && dev->power.should_wakeup;
@@ -217,4 +209,27 @@ static inline void pm_wakeup_hard_event(struct device *dev)
        return pm_wakeup_dev_event(dev, 0, true);
 }
 
+/**
+ * device_init_wakeup - Device wakeup initialization.
+ * @dev: Device to handle.
+ * @enable: Whether or not to enable @dev as a wakeup device.
+ *
+ * By default, most devices should leave wakeup disabled.  The exceptions are
+ * devices that everyone expects to be wakeup sources: keyboards, power buttons,
+ * possibly network interfaces, etc.  Also, devices that don't generate their
+ * own wakeup requests but merely forward requests from one bus to another
+ * (like PCI bridges) should have wakeup enabled by default.
+ */
+static inline int device_init_wakeup(struct device *dev, bool enable)
+{
+       if (enable) {
+               device_set_wakeup_capable(dev, true);
+               return device_wakeup_enable(dev);
+       } else {
+               device_wakeup_disable(dev);
+               device_set_wakeup_capable(dev, false);
+               return 0;
+       }
+}
+
 #endif /* _LINUX_PM_WAKEUP_H */
index b65c877..7d1e604 100644 (file)
@@ -73,6 +73,7 @@ extern int set_posix_acl(struct user_namespace *, struct inode *, int,
                         struct posix_acl *);
 
 struct posix_acl *get_cached_acl_rcu(struct inode *inode, int type);
+struct posix_acl *posix_acl_clone(const struct posix_acl *acl, gfp_t flags);
 
 #ifdef CONFIG_FS_POSIX_ACL
 int posix_acl_chmod(struct user_namespace *, struct inode *, umode_t);
index 1766e1d..b6bd3ea 100644 (file)
@@ -33,21 +33,31 @@ posix_acl_xattr_count(size_t size)
 }
 
 #ifdef CONFIG_FS_POSIX_ACL
-void posix_acl_fix_xattr_from_user(struct user_namespace *mnt_userns,
-                                  struct inode *inode,
-                                  void *value, size_t size);
-void posix_acl_fix_xattr_to_user(struct user_namespace *mnt_userns,
-                                  struct inode *inode,
-                                void *value, size_t size);
+void posix_acl_fix_xattr_from_user(void *value, size_t size);
+void posix_acl_fix_xattr_to_user(void *value, size_t size);
+void posix_acl_getxattr_idmapped_mnt(struct user_namespace *mnt_userns,
+                                    const struct inode *inode,
+                                    void *value, size_t size);
+void posix_acl_setxattr_idmapped_mnt(struct user_namespace *mnt_userns,
+                                    const struct inode *inode,
+                                    void *value, size_t size);
 #else
-static inline void posix_acl_fix_xattr_from_user(struct user_namespace *mnt_userns,
-                                                struct inode *inode,
-                                                void *value, size_t size)
+static inline void posix_acl_fix_xattr_from_user(void *value, size_t size)
 {
 }
-static inline void posix_acl_fix_xattr_to_user(struct user_namespace *mnt_userns,
-                                              struct inode *inode,
-                                              void *value, size_t size)
+static inline void posix_acl_fix_xattr_to_user(void *value, size_t size)
+{
+}
+static inline void
+posix_acl_getxattr_idmapped_mnt(struct user_namespace *mnt_userns,
+                               const struct inode *inode, void *value,
+                               size_t size)
+{
+}
+static inline void
+posix_acl_setxattr_idmapped_mnt(struct user_namespace *mnt_userns,
+                               const struct inode *inode, void *value,
+                               size_t size)
 {
 }
 #endif
index 9771a07..9429930 100644 (file)
@@ -6,9 +6,6 @@
 #include <linux/mutex.h>
 #include <linux/of.h>
 
-struct pwm_capture;
-struct seq_file;
-
 struct pwm_chip;
 
 /**
@@ -252,6 +249,16 @@ pwm_set_relative_duty_cycle(struct pwm_state *state, unsigned int duty_cycle,
 }
 
 /**
+ * struct pwm_capture - PWM capture data
+ * @period: period of the PWM signal (in nanoseconds)
+ * @duty_cycle: duty cycle of the PWM signal (in nanoseconds)
+ */
+struct pwm_capture {
+       unsigned int period;
+       unsigned int duty_cycle;
+};
+
+/**
  * struct pwm_ops - PWM controller operations
  * @request: optional hook for requesting a PWM
  * @free: optional hook for freeing a PWM
@@ -261,10 +268,6 @@ pwm_set_relative_duty_cycle(struct pwm_state *state, unsigned int duty_cycle,
  *            called once per PWM device when the PWM chip is
  *            registered.
  * @owner: helps prevent removal of modules exporting active PWMs
- * @config: configure duty cycles and period length for this PWM
- * @set_polarity: configure the polarity of this PWM
- * @enable: enable PWM output toggling
- * @disable: disable PWM output toggling
  */
 struct pwm_ops {
        int (*request)(struct pwm_chip *chip, struct pwm_device *pwm);
@@ -276,14 +279,6 @@ struct pwm_ops {
        void (*get_state)(struct pwm_chip *chip, struct pwm_device *pwm,
                          struct pwm_state *state);
        struct module *owner;
-
-       /* Only used by legacy drivers */
-       int (*config)(struct pwm_chip *chip, struct pwm_device *pwm,
-                     int duty_ns, int period_ns);
-       int (*set_polarity)(struct pwm_chip *chip, struct pwm_device *pwm,
-                           enum pwm_polarity polarity);
-       int (*enable)(struct pwm_chip *chip, struct pwm_device *pwm);
-       void (*disable)(struct pwm_chip *chip, struct pwm_device *pwm);
 };
 
 /**
@@ -312,16 +307,6 @@ struct pwm_chip {
        struct pwm_device *pwms;
 };
 
-/**
- * struct pwm_capture - PWM capture data
- * @period: period of the PWM signal (in nanoseconds)
- * @duty_cycle: duty cycle of the PWM signal (in nanoseconds)
- */
-struct pwm_capture {
-       unsigned int period;
-       unsigned int duty_cycle;
-};
-
 #if IS_ENABLED(CONFIG_PWM)
 /* PWM user APIs */
 struct pwm_device *pwm_request(int pwm_id, const char *label);
index a0f6668..0d8625d 100644 (file)
@@ -20,11 +20,12 @@ static inline struct quota_info *sb_dqopt(struct super_block *sb)
 }
 
 /* i_mutex must being held */
-static inline bool is_quota_modification(struct inode *inode, struct iattr *ia)
+static inline bool is_quota_modification(struct user_namespace *mnt_userns,
+                                        struct inode *inode, struct iattr *ia)
 {
-       return (ia->ia_valid & ATTR_SIZE) ||
-               (ia->ia_valid & ATTR_UID && !uid_eq(ia->ia_uid, inode->i_uid)) ||
-               (ia->ia_valid & ATTR_GID && !gid_eq(ia->ia_gid, inode->i_gid));
+       return ((ia->ia_valid & ATTR_SIZE) ||
+               i_uid_needs_update(mnt_userns, ia, inode) ||
+               i_gid_needs_update(mnt_userns, ia, inode));
 }
 
 #if defined(CONFIG_QUOTA)
@@ -115,7 +116,8 @@ int dquot_set_dqblk(struct super_block *sb, struct kqid id,
                struct qc_dqblk *di);
 
 int __dquot_transfer(struct inode *inode, struct dquot **transfer_to);
-int dquot_transfer(struct inode *inode, struct iattr *iattr);
+int dquot_transfer(struct user_namespace *mnt_userns, struct inode *inode,
+                  struct iattr *iattr);
 
 static inline struct mem_dqinfo *sb_dqinfo(struct super_block *sb, int type)
 {
@@ -234,7 +236,8 @@ static inline void dquot_free_inode(struct inode *inode)
 {
 }
 
-static inline int dquot_transfer(struct inode *inode, struct iattr *iattr)
+static inline int dquot_transfer(struct user_namespace *mnt_userns,
+                                struct inode *inode, struct iattr *iattr)
 {
        return 0;
 }
index 20e389a..3fec206 100644 (file)
@@ -106,32 +106,25 @@ declare_get_random_var_wait(long, unsigned long)
  */
 #include <linux/prandom.h>
 
-#ifdef CONFIG_ARCH_RANDOM
-# include <asm/archrandom.h>
-#else
-static inline bool __must_check arch_get_random_long(unsigned long *v) { return false; }
-static inline bool __must_check arch_get_random_int(unsigned int *v) { return false; }
-static inline bool __must_check arch_get_random_seed_long(unsigned long *v) { return false; }
-static inline bool __must_check arch_get_random_seed_int(unsigned int *v) { return false; }
-#endif
+#include <asm/archrandom.h>
 
 /*
  * Called from the boot CPU during startup; not valid to call once
  * secondary CPUs are up and preemption is possible.
  */
-#ifndef arch_get_random_seed_long_early
-static inline bool __init arch_get_random_seed_long_early(unsigned long *v)
+#ifndef arch_get_random_seed_longs_early
+static inline size_t __init arch_get_random_seed_longs_early(unsigned long *v, size_t max_longs)
 {
        WARN_ON(system_state != SYSTEM_BOOTING);
-       return arch_get_random_seed_long(v);
+       return arch_get_random_seed_longs(v, max_longs);
 }
 #endif
 
-#ifndef arch_get_random_long_early
-static inline bool __init arch_get_random_long_early(unsigned long *v)
+#ifndef arch_get_random_longs_early
+static inline bool __init arch_get_random_longs_early(unsigned long *v, size_t max_longs)
 {
        WARN_ON(system_state != SYSTEM_BOOTING);
-       return arch_get_random_long(v);
+       return arch_get_random_longs(v, max_longs);
 }
 #endif
 
index 1a32036..f527f27 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/lockdep.h>
 #include <asm/processor.h>
 #include <linux/cpumask.h>
+#include <linux/context_tracking_irq.h>
 
 #define ULONG_CMP_GE(a, b)     (ULONG_MAX / 2 >= (a) - (b))
 #define ULONG_CMP_LT(a, b)     (ULONG_MAX / 2 < (a) - (b))
@@ -41,6 +42,7 @@ void call_rcu(struct rcu_head *head, rcu_callback_t func);
 void rcu_barrier_tasks(void);
 void rcu_barrier_tasks_rude(void);
 void synchronize_rcu(void);
+unsigned long get_completed_synchronize_rcu(void);
 
 #ifdef CONFIG_PREEMPT_RCU
 
@@ -103,13 +105,11 @@ static inline void rcu_sysrq_start(void) { }
 static inline void rcu_sysrq_end(void) { }
 #endif /* #else #ifdef CONFIG_RCU_STALL_COMMON */
 
-#ifdef CONFIG_NO_HZ_FULL
-void rcu_user_enter(void);
-void rcu_user_exit(void);
+#if defined(CONFIG_NO_HZ_FULL) && (!defined(CONFIG_GENERIC_ENTRY) || !defined(CONFIG_KVM_XFER_TO_GUEST_WORK))
+void rcu_irq_work_resched(void);
 #else
-static inline void rcu_user_enter(void) { }
-static inline void rcu_user_exit(void) { }
-#endif /* CONFIG_NO_HZ_FULL */
+static inline void rcu_irq_work_resched(void) { }
+#endif
 
 #ifdef CONFIG_RCU_NOCB_CPU
 void rcu_init_nohz(void);
@@ -128,7 +128,7 @@ static inline void rcu_nocb_flush_deferred_wakeup(void) { }
  * @a: Code that RCU needs to pay attention to.
  *
  * RCU read-side critical sections are forbidden in the inner idle loop,
- * that is, between the rcu_idle_enter() and the rcu_idle_exit() -- RCU
+ * that is, between the ct_idle_enter() and the ct_idle_exit() -- RCU
  * will happily ignore any such read-side critical sections.  However,
  * things like powertop need tracepoints in the inner idle loop.
  *
@@ -143,9 +143,9 @@ static inline void rcu_nocb_flush_deferred_wakeup(void) { }
  */
 #define RCU_NONIDLE(a) \
        do { \
-               rcu_irq_enter_irqson(); \
+               ct_irq_enter_irqson(); \
                do { a; } while (0); \
-               rcu_irq_exit_irqson(); \
+               ct_irq_exit_irqson(); \
        } while (0)
 
 /*
@@ -169,13 +169,24 @@ void synchronize_rcu_tasks(void);
 # endif
 
 # ifdef CONFIG_TASKS_TRACE_RCU
-# define rcu_tasks_trace_qs(t)                                         \
-       do {                                                            \
-               if (!likely(READ_ONCE((t)->trc_reader_checked)) &&      \
-                   !unlikely(READ_ONCE((t)->trc_reader_nesting))) {    \
-                       smp_store_release(&(t)->trc_reader_checked, true); \
-                       smp_mb(); /* Readers partitioned by store. */   \
-               }                                                       \
+// Bits for ->trc_reader_special.b.need_qs field.
+#define TRC_NEED_QS            0x1  // Task needs a quiescent state.
+#define TRC_NEED_QS_CHECKED    0x2  // Task has been checked for needing quiescent state.
+
+u8 rcu_trc_cmpxchg_need_qs(struct task_struct *t, u8 old, u8 new);
+void rcu_tasks_trace_qs_blkd(struct task_struct *t);
+
+# define rcu_tasks_trace_qs(t)                                                 \
+       do {                                                                    \
+               int ___rttq_nesting = READ_ONCE((t)->trc_reader_nesting);       \
+                                                                               \
+               if (likely(!READ_ONCE((t)->trc_reader_special.b.need_qs)) &&    \
+                   likely(!___rttq_nesting)) {                                 \
+                       rcu_trc_cmpxchg_need_qs((t), 0, 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);                             \
+               }                                                               \
        } while (0)
 # else
 # define rcu_tasks_trace_qs(t) do { } while (0)
@@ -184,7 +195,7 @@ void synchronize_rcu_tasks(void);
 #define rcu_tasks_qs(t, preempt)                                       \
 do {                                                                   \
        rcu_tasks_classic_qs((t), (preempt));                           \
-       rcu_tasks_trace_qs((t));                                        \
+       rcu_tasks_trace_qs(t);                                          \
 } while (0)
 
 # ifdef CONFIG_TASKS_RUDE_RCU
index 6f9c358..9bc8cbb 100644 (file)
@@ -75,7 +75,7 @@ static inline void rcu_read_unlock_trace(void)
        nesting = READ_ONCE(t->trc_reader_nesting) - 1;
        barrier(); // Critical section before disabling.
        // Disable IPI-based setting of .need_qs.
-       WRITE_ONCE(t->trc_reader_nesting, INT_MIN);
+       WRITE_ONCE(t->trc_reader_nesting, INT_MIN + nesting);
        if (likely(!READ_ONCE(t->trc_reader_special.s)) || nesting) {
                WRITE_ONCE(t->trc_reader_nesting, nesting);
                return;  // We assume shallow reader nesting.
index 5fed476..62815c0 100644 (file)
@@ -23,6 +23,16 @@ static inline void cond_synchronize_rcu(unsigned long oldstate)
        might_sleep();
 }
 
+static inline unsigned long start_poll_synchronize_rcu_expedited(void)
+{
+       return start_poll_synchronize_rcu();
+}
+
+static inline void cond_synchronize_rcu_expedited(unsigned long oldstate)
+{
+       cond_synchronize_rcu(oldstate);
+}
+
 extern void rcu_barrier(void);
 
 static inline void synchronize_rcu_expedited(void)
@@ -38,7 +48,7 @@ static inline void synchronize_rcu_expedited(void)
  */
 extern void kvfree(const void *addr);
 
-static inline void kvfree_call_rcu(struct rcu_head *head, rcu_callback_t func)
+static inline void __kvfree_call_rcu(struct rcu_head *head, rcu_callback_t func)
 {
        if (head) {
                call_rcu(head, func);
@@ -51,6 +61,15 @@ static inline void kvfree_call_rcu(struct rcu_head *head, rcu_callback_t func)
        kvfree((void *) func);
 }
 
+#ifdef CONFIG_KASAN_GENERIC
+void kvfree_call_rcu(struct rcu_head *head, rcu_callback_t func);
+#else
+static inline void kvfree_call_rcu(struct rcu_head *head, rcu_callback_t func)
+{
+       __kvfree_call_rcu(head, func);
+}
+#endif
+
 void rcu_qs(void);
 
 static inline void rcu_softirq_qs(void)
@@ -76,12 +95,6 @@ static inline int rcu_needs_cpu(void)
 static inline void rcu_virt_note_context_switch(int cpu) { }
 static inline void rcu_cpu_stall_reset(void) { }
 static inline int rcu_jiffies_till_stall_check(void) { return 21 * HZ; }
-static inline void rcu_idle_enter(void) { }
-static inline void rcu_idle_exit(void) { }
-static inline void rcu_irq_enter(void) { }
-static inline void rcu_irq_exit_irqson(void) { }
-static inline void rcu_irq_enter_irqson(void) { }
-static inline void rcu_irq_exit(void) { }
 static inline void rcu_irq_exit_check_preempt(void) { }
 #define rcu_is_idle_cpu(cpu) \
        (is_idle_task(current) && !in_nmi() && !in_hardirq() && !in_serving_softirq())
index 9c6cfb7..47eaa4c 100644 (file)
@@ -40,17 +40,13 @@ bool rcu_eqs_special_set(int cpu);
 void rcu_momentary_dyntick_idle(void);
 void kfree_rcu_scheduler_running(void);
 bool rcu_gp_might_be_stalled(void);
+unsigned long start_poll_synchronize_rcu_expedited(void);
+void cond_synchronize_rcu_expedited(unsigned long oldstate);
 unsigned long get_state_synchronize_rcu(void);
 unsigned long start_poll_synchronize_rcu(void);
 bool poll_state_synchronize_rcu(unsigned long oldstate);
 void cond_synchronize_rcu(unsigned long oldstate);
 
-void rcu_idle_enter(void);
-void rcu_idle_exit(void);
-void rcu_irq_enter(void);
-void rcu_irq_exit(void);
-void rcu_irq_enter_irqson(void);
-void rcu_irq_exit_irqson(void);
 bool rcu_is_idle_cpu(int cpu);
 
 #ifdef CONFIG_PROVE_RCU
@@ -59,6 +55,9 @@ void rcu_irq_exit_check_preempt(void);
 static inline void rcu_irq_exit_check_preempt(void) { }
 #endif
 
+struct task_struct;
+void rcu_preempt_deferred_qs(struct task_struct *t);
+
 void exit_rcu(void);
 
 void rcu_scheduler_starting(void);
index b8a6e38..a62fcca 100644 (file)
@@ -361,9 +361,9 @@ static inline void refcount_dec(refcount_t *r)
 
 extern __must_check bool refcount_dec_if_one(refcount_t *r);
 extern __must_check bool refcount_dec_not_one(refcount_t *r);
-extern __must_check bool refcount_dec_and_mutex_lock(refcount_t *r, struct mutex *lock);
-extern __must_check bool refcount_dec_and_lock(refcount_t *r, spinlock_t *lock);
+extern __must_check bool refcount_dec_and_mutex_lock(refcount_t *r, struct mutex *lock) __cond_acquires(lock);
+extern __must_check bool refcount_dec_and_lock(refcount_t *r, spinlock_t *lock) __cond_acquires(lock);
 extern __must_check bool refcount_dec_and_lock_irqsave(refcount_t *r,
                                                       spinlock_t *lock,
-                                                      unsigned long *flags);
+                                                      unsigned long *flags) __cond_acquires(lock);
 #endif /* _LINUX_REFCOUNT_H */
index 8952fa3..7cf2157 100644 (file)
@@ -1336,6 +1336,22 @@ static inline int regmap_field_update_bits(struct regmap_field *field,
                                             NULL, false, false);
 }
 
+static inline int regmap_field_set_bits(struct regmap_field *field,
+                                       unsigned int bits)
+{
+       return regmap_field_update_bits_base(field, bits, bits, NULL, false,
+                                            false);
+}
+
+static inline int regmap_field_clear_bits(struct regmap_field *field,
+                                         unsigned int bits)
+{
+       return regmap_field_update_bits_base(field, bits, 0, NULL, false,
+                                            false);
+}
+
+int regmap_field_test_bits(struct regmap_field *field, unsigned int bits);
+
 static inline int
 regmap_field_force_update_bits(struct regmap_field *field,
                               unsigned int mask, unsigned int val)
@@ -1424,6 +1440,8 @@ struct regmap_irq_sub_irq_map {
        unsigned int *offset;
 };
 
+struct regmap_irq_chip_data;
+
 /**
  * struct regmap_irq_chip - Description of a generic regmap irq_chip.
  *
@@ -1451,32 +1469,50 @@ struct regmap_irq_sub_irq_map {
  *                main_status set.
  *
  * @status_base: Base status register address.
- * @mask_base:   Base mask register address.
- * @mask_writeonly: Base mask register is write only.
- * @unmask_base:  Base unmask register address. for chips who have
- *                separate mask and unmask registers
+ * @mask_base:   Base mask register address. Mask bits are set to 1 when an
+ *               interrupt is masked, 0 when unmasked.
+ * @unmask_base:  Base unmask register address. Unmask bits are set to 1 when
+ *                an interrupt is unmasked and 0 when masked.
  * @ack_base:    Base ack address. If zero then the chip is clear on read.
  *               Using zero value is possible with @use_ack bit.
  * @wake_base:   Base address for wake enables.  If zero unsupported.
- * @type_base:   Base address for irq type.  If zero unsupported.
- * @virt_reg_base:   Base addresses for extra config regs.
+ * @type_base:   Base address for irq type.  If zero unsupported.  Deprecated,
+ *              use @config_base instead.
+ * @virt_reg_base:   Base addresses for extra config regs. Deprecated, use
+ *                  @config_base instead.
+ * @config_base: Base address for IRQ type config regs. If null unsupported.
  * @irq_reg_stride:  Stride to use for chips where registers are not contiguous.
  * @init_ack_masked: Ack all masked interrupts once during initalization.
  * @mask_invert: Inverted mask register: cleared bits are masked out.
+ *              Deprecated; prefer describing an inverted mask register as
+ *              an unmask register.
+ * @mask_unmask_non_inverted: Controls mask bit inversion for chips that set
+ *     both @mask_base and @unmask_base. If false, mask and unmask bits are
+ *     inverted (which is deprecated behavior); if true, bits will not be
+ *     inverted and the registers keep their normal behavior. Note that if
+ *     you use only one of @mask_base or @unmask_base, this flag has no
+ *     effect and is unnecessary. Any new drivers that set both @mask_base
+ *     and @unmask_base should set this to true to avoid relying on the
+ *     deprecated behavior.
  * @use_ack:     Use @ack register even if it is zero.
  * @ack_invert:  Inverted ack register: cleared bits for ack.
  * @clear_ack:  Use this to set 1 and 0 or vice-versa to clear interrupts.
  * @wake_invert: Inverted wake register: cleared bits are wake enabled.
- * @type_invert: Invert the type flags.
- * @type_in_mask: Use the mask registers for controlling irq type. For
- *                interrupts defining type_rising/falling_mask use mask_base
- *                for edge configuration and never update bits in type_base.
+ * @type_invert: Invert the type flags. Deprecated, use config registers
+ *              instead.
+ * @type_in_mask: Use the mask registers for controlling irq type. Use this if
+ *               the hardware provides separate bits for rising/falling edge
+ *               or low/high level interrupts and they should be combined into
+ *               a single logical interrupt. Use &struct regmap_irq_type data
+ *               to define the mask bit for each irq type.
  * @clear_on_unmask: For chips with interrupts cleared on read: read the status
  *                   registers before unmasking interrupts to clear any bits
  *                   set when they were masked.
  * @not_fixed_stride: Used when chip peripherals are not laid out with fixed
- *                   stride. Must be used with sub_reg_offsets containing the
- *                   offsets to each peripheral.
+ *                   stride. Must be used with sub_reg_offsets containing the
+ *                   offsets to each peripheral. Deprecated; the same thing
+ *                   can be accomplished with a @get_irq_reg callback, without
+ *                   the need for a @sub_reg_offsets table.
  * @status_invert: Inverted status register: cleared bits are active interrupts.
  * @runtime_pm:  Hold a runtime PM lock on the device when accessing it.
  *
@@ -1484,17 +1520,28 @@ struct regmap_irq_sub_irq_map {
  * @irqs:        Descriptors for individual IRQs.  Interrupt numbers are
  *               assigned based on the index in the array of the interrupt.
  * @num_irqs:    Number of descriptors.
- * @num_type_reg:    Number of type registers.
+ * @num_type_reg:    Number of type registers. Deprecated, use config registers
+ *                  instead.
  * @num_virt_regs:   Number of non-standard irq configuration registers.
- *                  If zero unsupported.
- * @type_reg_stride: Stride to use for chips where type registers are not
- *                     contiguous.
+ *                  If zero unsupported. Deprecated, use config registers
+ *                  instead.
+ * @num_config_bases:  Number of config base registers.
+ * @num_config_regs:   Number of config registers for each config base register.
  * @handle_pre_irq:  Driver specific callback to handle interrupt from device
  *                  before regmap_irq_handler process the interrupts.
  * @handle_post_irq: Driver specific callback to handle interrupt from device
  *                  after handling the interrupts in regmap_irq_handler().
  * @set_type_virt:   Driver specific callback to extend regmap_irq_set_type()
- *                  and configure virt regs.
+ *                  and configure virt regs. Deprecated, use @set_type_config
+ *                  callback and config registers instead.
+ * @set_type_config: Callback used for configuring irq types.
+ * @get_irq_reg: Callback for mapping (base register, index) pairs to register
+ *              addresses. The base register will be one of @status_base,
+ *              @mask_base, etc., @main_status, or any of @config_base.
+ *              The index will be in the range [0, num_main_regs[ for the
+ *              main status base, [0, num_type_settings[ for any config
+ *              register base, and [0, num_regs[ for any other base.
+ *              If unspecified then regmap_irq_get_irq_reg_linear() is used.
  * @irq_drv_data:    Driver specific IRQ data which is passed as parameter when
  *                  driver specific pre/post interrupt handler is called.
  *
@@ -1517,20 +1564,21 @@ struct regmap_irq_chip {
        unsigned int wake_base;
        unsigned int type_base;
        unsigned int *virt_reg_base;
+       const unsigned int *config_base;
        unsigned int irq_reg_stride;
-       bool mask_writeonly:1;
-       bool init_ack_masked:1;
-       bool mask_invert:1;
-       bool use_ack:1;
-       bool ack_invert:1;
-       bool clear_ack:1;
-       bool wake_invert:1;
-       bool runtime_pm:1;
-       bool type_invert:1;
-       bool type_in_mask:1;
-       bool clear_on_unmask:1;
-       bool not_fixed_stride:1;
-       bool status_invert:1;
+       unsigned int init_ack_masked:1;
+       unsigned int mask_invert:1;
+       unsigned int mask_unmask_non_inverted:1;
+       unsigned int use_ack:1;
+       unsigned int ack_invert:1;
+       unsigned int clear_ack:1;
+       unsigned int wake_invert:1;
+       unsigned int runtime_pm:1;
+       unsigned int type_invert:1;
+       unsigned int type_in_mask:1;
+       unsigned int clear_on_unmask:1;
+       unsigned int not_fixed_stride:1;
+       unsigned int status_invert:1;
 
        int num_regs;
 
@@ -1539,16 +1587,24 @@ struct regmap_irq_chip {
 
        int num_type_reg;
        int num_virt_regs;
-       unsigned int type_reg_stride;
+       int num_config_bases;
+       int num_config_regs;
 
        int (*handle_pre_irq)(void *irq_drv_data);
        int (*handle_post_irq)(void *irq_drv_data);
        int (*set_type_virt)(unsigned int **buf, unsigned int type,
                             unsigned long hwirq, int reg);
+       int (*set_type_config)(unsigned int **buf, unsigned int type,
+                              const struct regmap_irq *irq_data, int idx);
+       unsigned int (*get_irq_reg)(struct regmap_irq_chip_data *data,
+                                   unsigned int base, int index);
        void *irq_drv_data;
 };
 
-struct regmap_irq_chip_data;
+unsigned int regmap_irq_get_irq_reg_linear(struct regmap_irq_chip_data *data,
+                                          unsigned int base, int index);
+int regmap_irq_set_type_config_simple(unsigned int **buf, unsigned int type,
+                                     const struct regmap_irq *irq_data, int idx);
 
 int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
                        int irq_base, const struct regmap_irq_chip *chip,
@@ -1769,6 +1825,27 @@ regmap_field_force_update_bits(struct regmap_field *field,
        return -EINVAL;
 }
 
+static inline int regmap_field_set_bits(struct regmap_field *field,
+                                       unsigned int bits)
+{
+       WARN_ONCE(1, "regmap API is disabled");
+       return -EINVAL;
+}
+
+static inline int regmap_field_clear_bits(struct regmap_field *field,
+                                         unsigned int bits)
+{
+       WARN_ONCE(1, "regmap API is disabled");
+       return -EINVAL;
+}
+
+static inline int regmap_field_test_bits(struct regmap_field *field,
+                                        unsigned int bits)
+{
+       WARN_ONCE(1, "regmap API is disabled");
+       return -EINVAL;
+}
+
 static inline int regmap_fields_write(struct regmap_field *field,
                                      unsigned int id, unsigned int val)
 {
index bbf6590..bc6cda7 100644 (file)
@@ -171,10 +171,13 @@ struct regulator;
 /**
  * struct regulator_bulk_data - Data used for bulk regulator operations.
  *
- * @supply:   The name of the supply.  Initialised by the user before
- *            using the bulk regulator APIs.
- * @consumer: The regulator consumer for the supply.  This will be managed
- *            by the bulk API.
+ * @supply:       The name of the supply.  Initialised by the user before
+ *                using the bulk regulator APIs.
+ * @init_load_uA: After getting the regulator, regulator_set_load() will be
+ *                called with this load.  Initialised by the user before
+ *                using the bulk regulator APIs.
+ * @consumer:     The regulator consumer for the supply.  This will be managed
+ *                by the bulk API.
  *
  * The regulator APIs provide a series of regulator_bulk_() API calls as
  * a convenience to consumers which require multiple supplies.  This
@@ -182,6 +185,7 @@ struct regulator;
  */
 struct regulator_bulk_data {
        const char *supply;
+       int init_load_uA;
        struct regulator *consumer;
 
        /* private: Internal use */
@@ -240,6 +244,10 @@ int __must_check regulator_bulk_get(struct device *dev, int num_consumers,
                                    struct regulator_bulk_data *consumers);
 int __must_check devm_regulator_bulk_get(struct device *dev, int num_consumers,
                                         struct regulator_bulk_data *consumers);
+int __must_check devm_regulator_bulk_get_const(
+       struct device *dev, int num_consumers,
+       const struct regulator_bulk_data *in_consumers,
+       struct regulator_bulk_data **out_consumers);
 int __must_check regulator_bulk_enable(int num_consumers,
                                       struct regulator_bulk_data *consumers);
 int regulator_bulk_disable(int num_consumers,
index 0228caa..f9a7461 100644 (file)
@@ -348,6 +348,7 @@ enum regulator_type {
  * @ramp_delay_table:  Table for mapping the regulator ramp-rate values. Values
  *                     should be given in units of V/S (uV/uS). See the
  *                     regulator_set_ramp_delay_regmap().
+ * @n_ramp_values:     number of elements at @ramp_delay_table.
  *
  * @enable_time: Time taken for initial enable of regulator (in uS).
  * @off_on_delay: guard time (in uS), before re-enabling a regulator
index 8a21b57..514ddf0 100644 (file)
@@ -731,7 +731,7 @@ static inline int __must_check
 devm_reset_control_bulk_get_optional_exclusive(struct device *dev, int num_rstcs,
                                               struct reset_control_bulk_data *rstcs)
 {
-       return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, true, false, true);
+       return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, false, true, true);
 }
 
 /**
index 159729c..3247ed8 100644 (file)
@@ -54,8 +54,6 @@ struct rtsx_ucr {
        struct usb_device       *pusb_dev;
        struct usb_interface    *pusb_intf;
        struct usb_sg_request   current_sg;
-       unsigned char           *iobuf;
-       dma_addr_t              iobuf_dma;
 
        struct timer_list       sg_timer;
        struct mutex            dev_mutex;
index c46f3a6..d6b0866 100644 (file)
@@ -843,8 +843,9 @@ struct task_struct {
        int                             trc_reader_nesting;
        int                             trc_ipi_to_cpu;
        union rcu_special               trc_reader_special;
-       bool                            trc_reader_checked;
        struct list_head                trc_holdout_list;
+       struct list_head                trc_blkd_node;
+       int                             trc_blkd_cpu;
 #endif /* #ifdef CONFIG_TASKS_TRACE_RCU */
 
        struct sched_info               sched_info;
@@ -2223,6 +2224,7 @@ static inline void set_task_cpu(struct task_struct *p, unsigned int cpu)
 
 extern bool sched_task_on_rq(struct task_struct *p);
 extern unsigned long get_wchan(struct task_struct *p);
+extern struct task_struct *cpu_curr_snapshot(int cpu);
 
 /*
  * In order to reduce various lock holder preemption latencies provide an
@@ -2257,7 +2259,7 @@ static inline bool owner_on_cpu(struct task_struct *owner)
 }
 
 /* Returns effective CPU energy utilization, as seen by the scheduler */
-unsigned long sched_cpu_util(int cpu, unsigned long max);
+unsigned long sched_cpu_util(int cpu);
 #endif /* CONFIG_SMP */
 
 #ifdef CONFIG_RSEQ
index e5af028..994c256 100644 (file)
@@ -39,20 +39,12 @@ static inline struct task_struct *rt_mutex_get_top_task(struct task_struct *p)
 }
 extern void rt_mutex_setprio(struct task_struct *p, struct task_struct *pi_task);
 extern void rt_mutex_adjust_pi(struct task_struct *p);
-static inline bool tsk_is_pi_blocked(struct task_struct *tsk)
-{
-       return tsk->pi_blocked_on != NULL;
-}
 #else
 static inline struct task_struct *rt_mutex_get_top_task(struct task_struct *task)
 {
        return NULL;
 }
 # define rt_mutex_adjust_pi(p)         do { } while (0)
-static inline bool tsk_is_pi_blocked(struct task_struct *tsk)
-{
-       return false;
-}
 #endif
 
 extern void normalize_rt_tasks(void);
index 505aaf9..81cab4b 100644 (file)
@@ -85,7 +85,7 @@ static inline void exit_thread(struct task_struct *tsk)
 extern __noreturn void do_group_exit(int);
 
 extern void exit_files(struct task_struct *);
-extern void exit_itimers(struct signal_struct *);
+extern void exit_itimers(struct task_struct *);
 
 extern pid_t kernel_clone(struct kernel_clone_args *kargs);
 struct task_struct *create_io_thread(int (*fn)(void *), void *arg, int node);
index 56cffe4..816df6c 100644 (file)
@@ -81,6 +81,7 @@ struct sched_domain_shared {
        atomic_t        ref;
        atomic_t        nr_busy_cpus;
        int             has_idle_cores;
+       int             nr_idle_scan;
 };
 
 struct sched_domain {
index 1c58646..a193884 100644 (file)
@@ -13,8 +13,9 @@
 #include <linux/notifier.h>
 #include <linux/types.h>
 
-#define SCMI_MAX_STR_SIZE      64
-#define SCMI_MAX_NUM_RATES     16
+#define SCMI_MAX_STR_SIZE              64
+#define SCMI_SHORT_NAME_MAX_SIZE       16
+#define SCMI_MAX_NUM_RATES             16
 
 /**
  * struct scmi_revision_info - version information structure
@@ -36,8 +37,8 @@ struct scmi_revision_info {
        u8 num_protocols;
        u8 num_agents;
        u32 impl_ver;
-       char vendor_id[SCMI_MAX_STR_SIZE];
-       char sub_vendor_id[SCMI_MAX_STR_SIZE];
+       char vendor_id[SCMI_SHORT_NAME_MAX_SIZE];
+       char sub_vendor_id[SCMI_SHORT_NAME_MAX_SIZE];
 };
 
 struct scmi_clock_info {
@@ -59,6 +60,12 @@ struct scmi_clock_info {
        };
 };
 
+enum scmi_power_scale {
+       SCMI_POWER_BOGOWATTS,
+       SCMI_POWER_MILLIWATTS,
+       SCMI_POWER_MICROWATTS
+};
+
 struct scmi_handle;
 struct scmi_device;
 struct scmi_protocol_handle;
@@ -134,7 +141,7 @@ struct scmi_perf_proto_ops {
                             unsigned long *rate, unsigned long *power);
        bool (*fast_switch_possible)(const struct scmi_protocol_handle *ph,
                                     struct device *dev);
-       bool (*power_scale_mw_get)(const struct scmi_protocol_handle *ph);
+       enum scmi_power_scale (*power_scale_get)(const struct scmi_protocol_handle *ph);
 };
 
 /**
@@ -560,6 +567,116 @@ struct scmi_voltage_proto_ops {
 };
 
 /**
+ * struct scmi_powercap_info  - Describe one available Powercap domain
+ *
+ * @id: Domain ID as advertised by the platform.
+ * @notify_powercap_cap_change: CAP change notification support.
+ * @notify_powercap_measurement_change: MEASUREMENTS change notifications
+ *                                    support.
+ * @async_powercap_cap_set: Asynchronous CAP set support.
+ * @powercap_cap_config: CAP configuration support.
+ * @powercap_monitoring: Monitoring (measurements) support.
+ * @powercap_pai_config: PAI configuration support.
+ * @powercap_scale_mw: Domain reports power data in milliwatt units.
+ * @powercap_scale_uw: Domain reports power data in microwatt units.
+ *                    Note that, when both @powercap_scale_mw and
+ *                    @powercap_scale_uw are set to false, the domain
+ *                    reports power data on an abstract linear scale.
+ * @name: name assigned to the Powercap Domain by platform.
+ * @min_pai: Minimum configurable PAI.
+ * @max_pai: Maximum configurable PAI.
+ * @pai_step: Step size between two consecutive PAI values.
+ * @min_power_cap: Minimum configurable CAP.
+ * @max_power_cap: Maximum configurable CAP.
+ * @power_cap_step: Step size between two consecutive CAP values.
+ * @sustainable_power: Maximum sustainable power consumption for this domain
+ *                    under normal conditions.
+ * @accuracy: The accuracy with which the power is measured and reported in
+ *           integral multiples of 0.001 percent.
+ * @parent_id: Identifier of the containing parent power capping domain, or the
+ *            value 0xFFFFFFFF if this powercap domain is a root domain not
+ *            contained in any other domain.
+ */
+struct scmi_powercap_info {
+       unsigned int id;
+       bool notify_powercap_cap_change;
+       bool notify_powercap_measurement_change;
+       bool async_powercap_cap_set;
+       bool powercap_cap_config;
+       bool powercap_monitoring;
+       bool powercap_pai_config;
+       bool powercap_scale_mw;
+       bool powercap_scale_uw;
+       bool fastchannels;
+       char name[SCMI_MAX_STR_SIZE];
+       unsigned int min_pai;
+       unsigned int max_pai;
+       unsigned int pai_step;
+       unsigned int min_power_cap;
+       unsigned int max_power_cap;
+       unsigned int power_cap_step;
+       unsigned int sustainable_power;
+       unsigned int accuracy;
+#define SCMI_POWERCAP_ROOT_ZONE_ID     0xFFFFFFFFUL
+       unsigned int parent_id;
+       struct scmi_fc_info *fc_info;
+};
+
+/**
+ * struct scmi_powercap_proto_ops - represents the various operations provided
+ * by SCMI Powercap Protocol
+ *
+ * @num_domains_get: get the count of powercap domains provided by SCMI.
+ * @info_get: get the information for the specified domain.
+ * @cap_get: get the current CAP value for the specified domain.
+ * @cap_set: set the CAP value for the specified domain to the provided value;
+ *          if the domain supports setting the CAP with an asynchronous command
+ *          this request will finally trigger an asynchronous transfer, but, if
+ *          @ignore_dresp here is set to true, this call will anyway return
+ *          immediately without waiting for the related delayed response.
+ * @pai_get: get the current PAI value for the specified domain.
+ * @pai_set: set the PAI value for the specified domain to the provided value.
+ * @measurements_get: retrieve the current average power measurements for the
+ *                   specified domain and the related PAI upon which is
+ *                   calculated.
+ * @measurements_threshold_set: set the desired low and high power thresholds
+ *                             to be used when registering for notification
+ *                             of type POWERCAP_MEASUREMENTS_NOTIFY with this
+ *                             powercap domain.
+ *                             Note that this must be called at least once
+ *                             before registering any callback with the usual
+ *                             @scmi_notify_ops; moreover, in case this method
+ *                             is called with measurement notifications already
+ *                             enabled it will also trigger, transparently, a
+ *                             proper update of the power thresholds configured
+ *                             in the SCMI backend server.
+ * @measurements_threshold_get: get the currently configured low and high power
+ *                             thresholds used when registering callbacks for
+ *                             notification POWERCAP_MEASUREMENTS_NOTIFY.
+ */
+struct scmi_powercap_proto_ops {
+       int (*num_domains_get)(const struct scmi_protocol_handle *ph);
+       const struct scmi_powercap_info __must_check *(*info_get)
+               (const struct scmi_protocol_handle *ph, u32 domain_id);
+       int (*cap_get)(const struct scmi_protocol_handle *ph, u32 domain_id,
+                      u32 *power_cap);
+       int (*cap_set)(const struct scmi_protocol_handle *ph, u32 domain_id,
+                      u32 power_cap, bool ignore_dresp);
+       int (*pai_get)(const struct scmi_protocol_handle *ph, u32 domain_id,
+                      u32 *pai);
+       int (*pai_set)(const struct scmi_protocol_handle *ph, u32 domain_id,
+                      u32 pai);
+       int (*measurements_get)(const struct scmi_protocol_handle *ph,
+                               u32 domain_id, u32 *average_power, u32 *pai);
+       int (*measurements_threshold_set)(const struct scmi_protocol_handle *ph,
+                                         u32 domain_id, u32 power_thresh_low,
+                                         u32 power_thresh_high);
+       int (*measurements_threshold_get)(const struct scmi_protocol_handle *ph,
+                                         u32 domain_id, u32 *power_thresh_low,
+                                         u32 *power_thresh_high);
+};
+
+/**
  * struct scmi_notify_ops  - represents notifications' operations provided by
  * SCMI core
  * @devm_event_notifier_register: Managed registration of a notifier_block for
@@ -623,6 +740,9 @@ struct scmi_notify_ops {
  *
  * @dev: pointer to the SCMI device
  * @version: pointer to the structure containing SCMI version information
+ * @devm_protocol_acquire: devres managed method to get hold of a protocol,
+ *                        causing its initialization and related resource
+ *                        accounting
  * @devm_protocol_get: devres managed method to acquire a protocol and get specific
  *                    operations and a dedicated protocol handler
  * @devm_protocol_put: devres managed method to release a protocol
@@ -641,6 +761,8 @@ struct scmi_handle {
        struct device *dev;
        struct scmi_revision_info *version;
 
+       int __must_check (*devm_protocol_acquire)(struct scmi_device *sdev,
+                                                 u8 proto);
        const void __must_check *
                (*devm_protocol_get)(struct scmi_device *sdev, u8 proto,
                                     struct scmi_protocol_handle **ph);
@@ -660,6 +782,7 @@ enum scmi_std_protocol {
        SCMI_PROTOCOL_SENSOR = 0x15,
        SCMI_PROTOCOL_RESET = 0x16,
        SCMI_PROTOCOL_VOLTAGE = 0x17,
+       SCMI_PROTOCOL_POWERCAP = 0x18,
 };
 
 enum scmi_system_events {
@@ -761,6 +884,8 @@ enum scmi_notification_events {
        SCMI_EVENT_RESET_ISSUED = 0x0,
        SCMI_EVENT_BASE_ERROR_EVENT = 0x0,
        SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER = 0x0,
+       SCMI_EVENT_POWERCAP_CAP_CHANGED = 0x0,
+       SCMI_EVENT_POWERCAP_MEASUREMENTS_CHANGED = 0x1,
 };
 
 struct scmi_power_state_changed_report {
@@ -780,8 +905,10 @@ struct scmi_clock_rate_notif_report {
 struct scmi_system_power_state_notifier_report {
        ktime_t         timestamp;
        unsigned int    agent_id;
+#define SCMI_SYSPOWER_IS_REQUEST_GRACEFUL(flags)       ((flags) & BIT(0))
        unsigned int    flags;
        unsigned int    system_state;
+       unsigned int    timeout;
 };
 
 struct scmi_perf_limits_report {
@@ -829,4 +956,18 @@ struct scmi_base_error_report {
        unsigned long long      reports[];
 };
 
+struct scmi_powercap_cap_changed_report {
+       ktime_t         timestamp;
+       unsigned int    agent_id;
+       unsigned int    domain_id;
+       unsigned int    power_cap;
+       unsigned int    pai;
+};
+
+struct scmi_powercap_meas_changed_report {
+       ktime_t         timestamp;
+       unsigned int    agent_id;
+       unsigned int    domain_id;
+       unsigned int    power;
+};
 #endif /* _LINUX_SCMI_PROTOCOL_H */
index 7fc4e9f..1bc362c 100644 (file)
@@ -353,7 +353,8 @@ int security_inode_readlink(struct dentry *dentry);
 int security_inode_follow_link(struct dentry *dentry, struct inode *inode,
                               bool rcu);
 int security_inode_permission(struct inode *inode, int mask);
-int security_inode_setattr(struct dentry *dentry, struct iattr *attr);
+int security_inode_setattr(struct user_namespace *mnt_userns,
+                          struct dentry *dentry, struct iattr *attr);
 int security_inode_getattr(const struct path *path);
 int security_inode_setxattr(struct user_namespace *mnt_userns,
                            struct dentry *dentry, const char *name,
@@ -415,6 +416,7 @@ int security_task_fix_setuid(struct cred *new, const struct cred *old,
                             int flags);
 int security_task_fix_setgid(struct cred *new, const struct cred *old,
                             int flags);
+int security_task_fix_setgroups(struct cred *new, const struct cred *old);
 int security_task_setpgid(struct task_struct *p, pid_t pgid);
 int security_task_getpgid(struct task_struct *p);
 int security_task_getsid(struct task_struct *p);
@@ -848,8 +850,9 @@ static inline int security_inode_permission(struct inode *inode, int mask)
        return 0;
 }
 
-static inline int security_inode_setattr(struct dentry *dentry,
-                                         struct iattr *attr)
+static inline int security_inode_setattr(struct user_namespace *mnt_userns,
+                                        struct dentry *dentry,
+                                        struct iattr *attr)
 {
        return 0;
 }
@@ -1098,6 +1101,12 @@ static inline int security_task_fix_setgid(struct cred *new,
        return 0;
 }
 
+static inline int security_task_fix_setgroups(struct cred *new,
+                                          const struct cred *old)
+{
+       return 0;
+}
+
 static inline int security_task_setpgid(struct task_struct *p, pid_t pgid)
 {
        return 0;
index 657a0fc..fde258b 100644 (file)
@@ -390,6 +390,11 @@ static const bool earlycon_acpi_spcr_enable EARLYCON_USED_OR_UNUSED;
 static inline int setup_earlycon(char *buf) { return 0; }
 #endif
 
+static inline bool uart_console_enabled(struct uart_port *port)
+{
+       return uart_console(port) && (port->cons->flags & CON_ENABLED);
+}
+
 struct uart_port *uart_get_console(struct uart_port *ports, int nr,
                                   struct console *c);
 int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr,
index d3d1055..1111ade 100644 (file)
@@ -686,10 +686,18 @@ enum {
         * charged to the kernel memory.
         */
        SKBFL_PURE_ZEROCOPY = BIT(2),
+
+       SKBFL_DONT_ORPHAN = BIT(3),
+
+       /* page references are managed by the ubuf_info, so it's safe to
+        * use frags only up until ubuf_info is released
+        */
+       SKBFL_MANAGED_FRAG_REFS = BIT(4),
 };
 
 #define SKBFL_ZEROCOPY_FRAG    (SKBFL_ZEROCOPY_ENABLE | SKBFL_SHARED_FRAG)
-#define SKBFL_ALL_ZEROCOPY     (SKBFL_ZEROCOPY_FRAG | SKBFL_PURE_ZEROCOPY)
+#define SKBFL_ALL_ZEROCOPY     (SKBFL_ZEROCOPY_FRAG | SKBFL_PURE_ZEROCOPY | \
+                                SKBFL_DONT_ORPHAN | SKBFL_MANAGED_FRAG_REFS)
 
 /*
  * The callback notifies userspace to release buffers when skb DMA is done in
@@ -1773,13 +1781,14 @@ void msg_zerocopy_put_abort(struct ubuf_info *uarg, bool have_uref);
 void msg_zerocopy_callback(struct sk_buff *skb, struct ubuf_info *uarg,
                           bool success);
 
-int __zerocopy_sg_from_iter(struct sock *sk, struct sk_buff *skb,
-                           struct iov_iter *from, size_t length);
+int __zerocopy_sg_from_iter(struct msghdr *msg, struct sock *sk,
+                           struct sk_buff *skb, struct iov_iter *from,
+                           size_t length);
 
 static inline int skb_zerocopy_iter_dgram(struct sk_buff *skb,
                                          struct msghdr *msg, int len)
 {
-       return __zerocopy_sg_from_iter(skb->sk, skb, &msg->msg_iter, len);
+       return __zerocopy_sg_from_iter(msg, skb->sk, skb, &msg->msg_iter, len);
 }
 
 int skb_zerocopy_iter_stream(struct sock *sk, struct sk_buff *skb,
@@ -1806,6 +1815,11 @@ static inline bool skb_zcopy_pure(const struct sk_buff *skb)
        return skb_shinfo(skb)->flags & SKBFL_PURE_ZEROCOPY;
 }
 
+static inline bool skb_zcopy_managed(const struct sk_buff *skb)
+{
+       return skb_shinfo(skb)->flags & SKBFL_MANAGED_FRAG_REFS;
+}
+
 static inline bool skb_pure_zcopy_same(const struct sk_buff *skb1,
                                       const struct sk_buff *skb2)
 {
@@ -1880,6 +1894,14 @@ static inline void skb_zcopy_clear(struct sk_buff *skb, bool zerocopy_success)
        }
 }
 
+void __skb_zcopy_downgrade_managed(struct sk_buff *skb);
+
+static inline void skb_zcopy_downgrade_managed(struct sk_buff *skb)
+{
+       if (unlikely(skb_zcopy_managed(skb)))
+               __skb_zcopy_downgrade_managed(skb);
+}
+
 static inline void skb_mark_not_on_list(struct sk_buff *skb)
 {
        skb->next = NULL;
@@ -2528,6 +2550,22 @@ static inline unsigned int skb_pagelen(const struct sk_buff *skb)
        return skb_headlen(skb) + __skb_pagelen(skb);
 }
 
+static inline void __skb_fill_page_desc_noacc(struct skb_shared_info *shinfo,
+                                             int i, struct page *page,
+                                             int off, int size)
+{
+       skb_frag_t *frag = &shinfo->frags[i];
+
+       /*
+        * Propagate page pfmemalloc to the skb if we can. The problem is
+        * that not all callers have unique ownership of the page but rely
+        * on page_is_pfmemalloc doing the right thing(tm).
+        */
+       frag->bv_page             = page;
+       frag->bv_offset           = off;
+       skb_frag_size_set(frag, size);
+}
+
 /**
  * __skb_fill_page_desc - initialise a paged fragment in an skb
  * @skb: buffer containing fragment to be initialised
@@ -2544,17 +2582,7 @@ static inline unsigned int skb_pagelen(const struct sk_buff *skb)
 static inline void __skb_fill_page_desc(struct sk_buff *skb, int i,
                                        struct page *page, int off, int size)
 {
-       skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-
-       /*
-        * Propagate page pfmemalloc to the skb if we can. The problem is
-        * that not all callers have unique ownership of the page but rely
-        * on page_is_pfmemalloc doing the right thing(tm).
-        */
-       frag->bv_page             = page;
-       frag->bv_offset           = off;
-       skb_frag_size_set(frag, size);
-
+       __skb_fill_page_desc_noacc(skb_shinfo(skb), i, page, off, size);
        page = compound_head(page);
        if (page_is_pfmemalloc(page))
                skb->pfmemalloc = true;
@@ -3182,8 +3210,7 @@ static inline int skb_orphan_frags(struct sk_buff *skb, gfp_t gfp_mask)
 {
        if (likely(!skb_zcopy(skb)))
                return 0;
-       if (!skb_zcopy_is_nouarg(skb) &&
-           skb_uarg(skb)->callback == msg_zerocopy_callback)
+       if (skb_shinfo(skb)->flags & SKBFL_DONT_ORPHAN)
                return 0;
        return skb_copy_ubufs(skb, gfp_mask);
 }
@@ -3496,7 +3523,10 @@ static inline void __skb_frag_unref(skb_frag_t *frag, bool recycle)
  */
 static inline void skb_frag_unref(struct sk_buff *skb, int f)
 {
-       __skb_frag_unref(&skb_shinfo(skb)->frags[f], skb->pp_recycle);
+       struct skb_shared_info *shinfo = skb_shinfo(skb);
+
+       if (!skb_zcopy_managed(skb))
+               __skb_frag_unref(&shinfo->frags[f], skb->pp_recycle);
 }
 
 /**
index 6fe4ffb..a0f4f51 100644 (file)
@@ -10,11 +10,33 @@ struct regmap;
 struct device;
 struct mtk_mutex;
 
+enum mtk_mutex_mod_index {
+       /* MDP table index */
+       MUTEX_MOD_IDX_MDP_RDMA0,
+       MUTEX_MOD_IDX_MDP_RSZ0,
+       MUTEX_MOD_IDX_MDP_RSZ1,
+       MUTEX_MOD_IDX_MDP_TDSHP0,
+       MUTEX_MOD_IDX_MDP_WROT0,
+       MUTEX_MOD_IDX_MDP_WDMA,
+       MUTEX_MOD_IDX_MDP_AAL0,
+       MUTEX_MOD_IDX_MDP_CCORR0,
+
+       MUTEX_MOD_IDX_MAX               /* ALWAYS keep at the end */
+};
+
+enum mtk_mutex_sof_index {
+       MUTEX_SOF_IDX_SINGLE_MODE,
+
+       MUTEX_SOF_IDX_MAX               /* ALWAYS keep at the end */
+};
+
 struct mtk_mutex *mtk_mutex_get(struct device *dev);
 int mtk_mutex_prepare(struct mtk_mutex *mutex);
 void mtk_mutex_add_comp(struct mtk_mutex *mutex,
                        enum mtk_ddp_comp_id id);
 void mtk_mutex_enable(struct mtk_mutex *mutex);
+int mtk_mutex_enable_by_cmdq(struct mtk_mutex *mutex,
+                            void *pkt);
 void mtk_mutex_disable(struct mtk_mutex *mutex);
 void mtk_mutex_remove_comp(struct mtk_mutex *mutex,
                           enum mtk_ddp_comp_id id);
@@ -22,5 +44,10 @@ void mtk_mutex_unprepare(struct mtk_mutex *mutex);
 void mtk_mutex_put(struct mtk_mutex *mutex);
 void mtk_mutex_acquire(struct mtk_mutex *mutex);
 void mtk_mutex_release(struct mtk_mutex *mutex);
+int mtk_mutex_write_mod(struct mtk_mutex *mutex,
+                       enum mtk_mutex_mod_index idx,
+                       bool clear);
+int mtk_mutex_write_sof(struct mtk_mutex *mutex,
+                       enum mtk_mutex_sof_index idx);
 
 #endif /* MTK_MUTEX_H */
index 17311ad..d452397 100644 (file)
@@ -14,6 +14,8 @@ struct file;
 struct pid;
 struct cred;
 struct socket;
+struct sock;
+struct sk_buff;
 
 #define __sockaddr_check_size(size)    \
        BUILD_BUG_ON(((size) > sizeof(struct __kernel_sockaddr_storage)))
@@ -69,6 +71,9 @@ struct msghdr {
        unsigned int    msg_flags;      /* flags on received message */
        __kernel_size_t msg_controllen; /* ancillary data buffer length */
        struct kiocb    *msg_iocb;      /* ptr to iocb for async requests */
+       struct ubuf_info *msg_ubuf;
+       int (*sg_from_iter)(struct sock *sk, struct sk_buff *skb,
+                           struct iov_iter *from, size_t length);
 };
 
 struct user_msghdr {
@@ -416,10 +421,9 @@ extern int recvmsg_copy_msghdr(struct msghdr *msg,
                               struct user_msghdr __user *umsg, unsigned flags,
                               struct sockaddr __user **uaddr,
                               struct iovec **iov);
-extern int __copy_msghdr_from_user(struct msghdr *kmsg,
-                                  struct user_msghdr __user *umsg,
-                                  struct sockaddr __user **save_addr,
-                                  struct iovec __user **uiov, size_t *nsegs);
+extern int __copy_msghdr(struct msghdr *kmsg,
+                        struct user_msghdr *umsg,
+                        struct sockaddr __user **save_addr);
 
 /* helpers which do the actual work for syscalls */
 extern int __sys_recvfrom(int fd, void __user *ubuf, size_t size,
index d361ba2..e6c73d5 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <uapi/linux/spi/spi.h>
 #include <linux/acpi.h>
+#include <linux/u64_stats_sync.h>
 
 struct dma_chan;
 struct software_node;
@@ -34,7 +35,8 @@ extern struct bus_type spi_bus_type;
 
 /**
  * struct spi_statistics - statistics for spi transfers
- * @lock:          lock protecting this structure
+ * @syncp:         seqcount to protect members in this struct for per-cpu udate
+ *                 on 32-bit systems
  *
  * @messages:      number of spi-messages handled
  * @transfers:     number of spi_transfers handled
@@ -59,37 +61,48 @@ extern struct bus_type spi_bus_type;
  *                 maxsize limit
  */
 struct spi_statistics {
-       spinlock_t              lock; /* lock for the whole structure */
+       struct u64_stats_sync   syncp;
 
-       unsigned long           messages;
-       unsigned long           transfers;
-       unsigned long           errors;
-       unsigned long           timedout;
+       u64_stats_t             messages;
+       u64_stats_t             transfers;
+       u64_stats_t             errors;
+       u64_stats_t             timedout;
 
-       unsigned long           spi_sync;
-       unsigned long           spi_sync_immediate;
-       unsigned long           spi_async;
+       u64_stats_t             spi_sync;
+       u64_stats_t             spi_sync_immediate;
+       u64_stats_t             spi_async;
 
-       unsigned long long      bytes;
-       unsigned long long      bytes_rx;
-       unsigned long long      bytes_tx;
+       u64_stats_t             bytes;
+       u64_stats_t             bytes_rx;
+       u64_stats_t             bytes_tx;
 
 #define SPI_STATISTICS_HISTO_SIZE 17
-       unsigned long transfer_bytes_histo[SPI_STATISTICS_HISTO_SIZE];
+       u64_stats_t     transfer_bytes_histo[SPI_STATISTICS_HISTO_SIZE];
 
-       unsigned long transfers_split_maxsize;
+       u64_stats_t     transfers_split_maxsize;
 };
 
-#define SPI_STATISTICS_ADD_TO_FIELD(stats, field, count)       \
-       do {                                                    \
-               unsigned long flags;                            \
-               spin_lock_irqsave(&(stats)->lock, flags);       \
-               (stats)->field += count;                        \
-               spin_unlock_irqrestore(&(stats)->lock, flags);  \
+#define SPI_STATISTICS_ADD_TO_FIELD(pcpu_stats, field, count)          \
+       do {                                                            \
+               struct spi_statistics *__lstats;                        \
+               get_cpu();                                              \
+               __lstats = this_cpu_ptr(pcpu_stats);                    \
+               u64_stats_update_begin(&__lstats->syncp);               \
+               u64_stats_add(&__lstats->field, count);                 \
+               u64_stats_update_end(&__lstats->syncp);                 \
+               put_cpu();                                              \
        } while (0)
 
-#define SPI_STATISTICS_INCREMENT_FIELD(stats, field)   \
-       SPI_STATISTICS_ADD_TO_FIELD(stats, field, 1)
+#define SPI_STATISTICS_INCREMENT_FIELD(pcpu_stats, field)              \
+       do {                                                            \
+               struct spi_statistics *__lstats;                        \
+               get_cpu();                                              \
+               __lstats = this_cpu_ptr(pcpu_stats);                    \
+               u64_stats_update_begin(&__lstats->syncp);               \
+               u64_stats_inc(&__lstats->field);                        \
+               u64_stats_update_end(&__lstats->syncp);                 \
+               put_cpu();                                              \
+       } while (0)
 
 /**
  * struct spi_delay - SPI delay information
@@ -149,7 +162,7 @@ extern int spi_delay_exec(struct spi_delay *_delay, struct spi_transfer *xfer);
  * @cs_inactive: delay to be introduced by the controller after CS is
  *     deasserted. If @cs_change_delay is used from @spi_transfer, then the
  *     two delays will be added up.
- * @statistics: statistics for the spi_device
+ * @pcpu_statistics: statistics for the spi_device
  *
  * A @spi_device is used to interchange data between an SPI slave
  * (usually a discrete chip) and CPU memory.
@@ -163,13 +176,13 @@ extern int spi_delay_exec(struct spi_delay *_delay, struct spi_transfer *xfer);
 struct spi_device {
        struct device           dev;
        struct spi_controller   *controller;
-       struct spi_controller   *master;        /* compatibility layer */
+       struct spi_controller   *master;        /* Compatibility layer */
        u32                     max_speed_hz;
        u8                      chip_select;
        u8                      bits_per_word;
        bool                    rt;
-#define SPI_NO_TX      BIT(31)         /* no transmit wire */
-#define SPI_NO_RX      BIT(30)         /* no receive wire */
+#define SPI_NO_TX      BIT(31)         /* No transmit wire */
+#define SPI_NO_RX      BIT(30)         /* No receive wire */
        /*
         * All bits defined above should be covered by SPI_MODE_KERNEL_MASK.
         * The SPI_MODE_KERNEL_MASK has the SPI_MODE_USER_MASK counterpart,
@@ -186,15 +199,15 @@ struct spi_device {
        void                    *controller_data;
        char                    modalias[SPI_NAME_SIZE];
        const char              *driver_override;
-       struct gpio_desc        *cs_gpiod;      /* chip select gpio desc */
-       struct spi_delay        word_delay; /* inter-word delay */
+       struct gpio_desc        *cs_gpiod;      /* Chip select gpio desc */
+       struct spi_delay        word_delay; /* Inter-word delay */
        /* CS delays */
        struct spi_delay        cs_setup;
        struct spi_delay        cs_hold;
        struct spi_delay        cs_inactive;
 
-       /* the statistics */
-       struct spi_statistics   statistics;
+       /* The statistics */
+       struct spi_statistics __percpu  *pcpu_statistics;
 
        /*
         * likely need more hooks for more protocol options affecting how
@@ -215,7 +228,7 @@ static inline struct spi_device *to_spi_device(struct device *dev)
        return dev ? container_of(dev, struct spi_device, dev) : NULL;
 }
 
-/* most drivers won't need to care about device refcounting */
+/* Most drivers won't need to care about device refcounting */
 static inline struct spi_device *spi_dev_get(struct spi_device *spi)
 {
        return (spi && get_device(&spi->dev)) ? spi : NULL;
@@ -238,7 +251,7 @@ static inline void spi_set_ctldata(struct spi_device *spi, void *state)
        spi->controller_state = state;
 }
 
-/* device driver data */
+/* Device driver data */
 
 static inline void spi_set_drvdata(struct spi_device *spi, void *data)
 {
@@ -305,7 +318,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
 
 extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 chip_select);
 
-/* use a define to avoid include chaining to get THIS_MODULE */
+/* Use a define to avoid include chaining to get THIS_MODULE */
 #define spi_register_driver(driver) \
        __spi_register_driver(THIS_MODULE, driver)
 
@@ -370,10 +383,14 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch
  * @pump_messages: work struct for scheduling work to the message pump
  * @queue_lock: spinlock to syncronise access to message queue
  * @queue: message queue
- * @idling: the device is entering idle state
  * @cur_msg: the currently in-flight message
- * @cur_msg_prepared: spi_prepare_message was called for the currently
- *                    in-flight message
+ * @cur_msg_completion: a completion for the current in-flight message
+ * @cur_msg_incomplete: Flag used internally to opportunistically skip
+ *     the @cur_msg_completion. This flag is used to check if the driver has
+ *     already called spi_finalize_current_message().
+ * @cur_msg_need_completion: Flag used internally to opportunistically skip
+ *     the @cur_msg_completion. This flag is used to signal the context that
+ *     is running spi_finalize_current_message() that it needs to complete()
  * @cur_msg_mapped: message has been mapped for DMA
  * @last_cs: the last chip_select that is recorded by set_cs, -1 on non chip
  *           selected
@@ -433,7 +450,7 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch
  * @max_native_cs: When cs_gpiods is used, and this field is filled in,
  *     spi_register_controller() will validate all native CS (including the
  *     unused native CS) against this value.
- * @statistics: statistics for the spi_controller
+ * @pcpu_statistics: statistics for the spi_controller
  * @dma_tx: DMA transmit channel
  * @dma_rx: DMA receive channel
  * @dummy_rx: dummy receive buffer for full-duplex devices
@@ -450,6 +467,8 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch
  * @irq_flags: Interrupt enable state during PTP system timestamping
  * @fallback: fallback to pio if dma transfer return failure with
  *     SPI_TRANS_FAIL_NO_START.
+ * @queue_empty: signal green light for opportunistically skipping the queue
+ *     for spi_sync transfers.
  *
  * Each SPI controller can communicate with one or more @spi_device
  * children.  These make a small bus, sharing MOSI, MISO and SCK signals
@@ -467,7 +486,7 @@ struct spi_controller {
 
        struct list_head list;
 
-       /* other than negative (== assign one dynamically), bus_num is fully
+       /* Other than negative (== assign one dynamically), bus_num is fully
         * board-specific.  usually that simplifies to being SOC-specific.
         * example:  one SOC has three SPI controllers, numbered 0..2,
         * and one board's schematics might show it using SPI-2.  software
@@ -480,7 +499,7 @@ struct spi_controller {
         */
        u16                     num_chipselect;
 
-       /* some SPI controllers pose alignment requirements on DMAable
+       /* Some SPI controllers pose alignment requirements on DMAable
         * buffers; let protocol drivers know about these requirements.
         */
        u16                     dma_alignment;
@@ -491,29 +510,29 @@ struct spi_controller {
        /* spi_device.mode flags override flags for this controller */
        u32                     buswidth_override_bits;
 
-       /* bitmask of supported bits_per_word for transfers */
+       /* Bitmask of supported bits_per_word for transfers */
        u32                     bits_per_word_mask;
 #define SPI_BPW_MASK(bits) BIT((bits) - 1)
 #define SPI_BPW_RANGE_MASK(min, max) GENMASK((max) - 1, (min) - 1)
 
-       /* limits on transfer speed */
+       /* Limits on transfer speed */
        u32                     min_speed_hz;
        u32                     max_speed_hz;
 
-       /* other constraints relevant to this driver */
+       /* Other constraints relevant to this driver */
        u16                     flags;
-#define SPI_CONTROLLER_HALF_DUPLEX     BIT(0)  /* can't do full duplex */
-#define SPI_CONTROLLER_NO_RX           BIT(1)  /* can't do buffer read */
-#define SPI_CONTROLLER_NO_TX           BIT(2)  /* can't do buffer write */
-#define SPI_CONTROLLER_MUST_RX         BIT(3)  /* requires rx */
-#define SPI_CONTROLLER_MUST_TX         BIT(4)  /* requires tx */
+#define SPI_CONTROLLER_HALF_DUPLEX     BIT(0)  /* Can't do full duplex */
+#define SPI_CONTROLLER_NO_RX           BIT(1)  /* Can't do buffer read */
+#define SPI_CONTROLLER_NO_TX           BIT(2)  /* Can't do buffer write */
+#define SPI_CONTROLLER_MUST_RX         BIT(3)  /* Requires rx */
+#define SPI_CONTROLLER_MUST_TX         BIT(4)  /* Requires tx */
 
 #define SPI_MASTER_GPIO_SS             BIT(5)  /* GPIO CS must select slave */
 
-       /* flag indicating if the allocation of this struct is devres-managed */
+       /* Flag indicating if the allocation of this struct is devres-managed */
        bool                    devm_allocated;
 
-       /* flag indicating this is an SPI slave controller */
+       /* Flag indicating this is an SPI slave controller */
        bool                    slave;
 
        /*
@@ -529,11 +548,11 @@ struct spi_controller {
        /* Used to avoid adding the same CS twice */
        struct mutex            add_lock;
 
-       /* lock and mutex for SPI bus locking */
+       /* Lock and mutex for SPI bus locking */
        spinlock_t              bus_lock_spinlock;
        struct mutex            bus_lock_mutex;
 
-       /* flag indicating that the SPI bus is locked for exclusive use */
+       /* Flag indicating that the SPI bus is locked for exclusive use */
        bool                    bus_lock_flag;
 
        /* Setup mode and clock, etc (spi driver may call many times).
@@ -554,7 +573,7 @@ struct spi_controller {
         */
        int (*set_cs_timing)(struct spi_device *spi);
 
-       /* bidirectional bulk transfers
+       /* Bidirectional bulk transfers
         *
         * + The transfer() method may not sleep; its main role is
         *   just to add the message to the queue.
@@ -576,7 +595,7 @@ struct spi_controller {
        int                     (*transfer)(struct spi_device *spi,
                                                struct spi_message *mesg);
 
-       /* called on release() to free memory provided by spi_controller */
+       /* Called on release() to free memory provided by spi_controller */
        void                    (*cleanup)(struct spi_device *spi);
 
        /*
@@ -603,12 +622,13 @@ struct spi_controller {
        spinlock_t                      queue_lock;
        struct list_head                queue;
        struct spi_message              *cur_msg;
-       bool                            idling;
+       struct completion               cur_msg_completion;
+       bool                            cur_msg_incomplete;
+       bool                            cur_msg_need_completion;
        bool                            busy;
        bool                            running;
        bool                            rt;
        bool                            auto_runtime_pm;
-       bool                            cur_msg_prepared;
        bool                            cur_msg_mapped;
        char                            last_cs;
        bool                            last_cs_mode_high;
@@ -646,14 +666,14 @@ struct spi_controller {
        s8                      unused_native_cs;
        s8                      max_native_cs;
 
-       /* statistics */
-       struct spi_statistics   statistics;
+       /* Statistics */
+       struct spi_statistics __percpu  *pcpu_statistics;
 
        /* DMA channels for use with core dmaengine helpers */
        struct dma_chan         *dma_tx;
        struct dma_chan         *dma_rx;
 
-       /* dummy data for full duplex devices */
+       /* Dummy data for full duplex devices */
        void                    *dummy_rx;
        void                    *dummy_tx;
 
@@ -667,6 +687,9 @@ struct spi_controller {
 
        /* Interrupt enable state during PTP system timestamping */
        unsigned long           irq_flags;
+
+       /* Flag for enabling opportunistic skipping of the queue in spi_sync */
+       bool                    queue_empty;
 };
 
 static inline void *spi_controller_get_devdata(struct spi_controller *ctlr)
@@ -715,7 +738,7 @@ void spi_take_timestamp_post(struct spi_controller *ctlr,
                             struct spi_transfer *xfer,
                             size_t progress, bool irqs_off);
 
-/* the spi driver core manages memory for the spi_controller classdev */
+/* The spi driver core manages memory for the spi_controller classdev */
 extern struct spi_controller *__spi_alloc_controller(struct device *host,
                                                unsigned int size, bool slave);
 
@@ -785,7 +808,7 @@ typedef void (*spi_res_release_t)(struct spi_controller *ctlr,
 struct spi_res {
        struct list_head        entry;
        spi_res_release_t       release;
-       unsigned long long      data[]; /* guarantee ull alignment */
+       unsigned long long      data[]; /* Guarantee ull alignment */
 };
 
 /*---------------------------------------------------------------------------*/
@@ -918,7 +941,7 @@ struct spi_res {
  * and its transfers, ignore them until its completion callback.
  */
 struct spi_transfer {
-       /* it's ok if tx_buf == rx_buf (right?)
+       /* It's ok if tx_buf == rx_buf (right?)
         * for MicroWire, one buffer must be null
         * buffers must work with dma_*map_single() calls, unless
         *   spi_message.is_dma_mapped reports a pre-existing mapping
@@ -975,6 +998,7 @@ struct spi_transfer {
  * @queue: for use by whichever driver currently owns the message
  * @state: for use by whichever driver currently owns the message
  * @resources: for resource management when the spi message is processed
+ * @prepared: spi_prepare_message was called for the this message
  *
  * A @spi_message is used to execute an atomic sequence of data transfers,
  * each represented by a struct spi_transfer.  The sequence is "atomic"
@@ -1008,22 +1032,25 @@ struct spi_message {
         * tell them about such special cases.
         */
 
-       /* completion is reported through a callback */
+       /* Completion is reported through a callback */
        void                    (*complete)(void *context);
        void                    *context;
        unsigned                frame_length;
        unsigned                actual_length;
        int                     status;
 
-       /* for optional use by whatever driver currently owns the
+       /* For optional use by whatever driver currently owns the
         * spi_message ...  between calls to spi_async and then later
         * complete(), that's the spi_controller controller driver.
         */
        struct list_head        queue;
        void                    *state;
 
-       /* list of spi_res reources when the spi message is processed */
+       /* List of spi_res reources when the spi message is processed */
        struct list_head        resources;
+
+       /* spi_prepare_message() was called for this message */
+       bool                    prepared;
 };
 
 static inline void spi_message_init_no_memset(struct spi_message *m)
@@ -1127,7 +1154,7 @@ spi_max_transfer_size(struct spi_device *spi)
        if (ctlr->max_transfer_size)
                tr_max = ctlr->max_transfer_size(spi);
 
-       /* transfer size limit must not be greater than messsage size limit */
+       /* Transfer size limit must not be greater than message size limit */
        return min(tr_max, msg_max);
 }
 
@@ -1278,7 +1305,7 @@ spi_read(struct spi_device *spi, void *buf, size_t len)
        return spi_sync_transfer(spi, &t, 1);
 }
 
-/* this copies txbuf and rxbuf data; for small transfers only! */
+/* This copies txbuf and rxbuf data; for small transfers only! */
 extern int spi_write_then_read(struct spi_device *spi,
                const void *txbuf, unsigned n_tx,
                void *rxbuf, unsigned n_rx);
@@ -1301,7 +1328,7 @@ static inline ssize_t spi_w8r8(struct spi_device *spi, u8 cmd)
 
        status = spi_write_then_read(spi, &cmd, 1, &result, 1);
 
-       /* return negative errno or unsigned value */
+       /* Return negative errno or unsigned value */
        return (status < 0) ? status : result;
 }
 
@@ -1326,7 +1353,7 @@ static inline ssize_t spi_w8r16(struct spi_device *spi, u8 cmd)
 
        status = spi_write_then_read(spi, &cmd, 1, &result, 2);
 
-       /* return negative errno or unsigned value */
+       /* Return negative errno or unsigned value */
        return (status < 0) ? status : result;
 }
 
@@ -1406,7 +1433,7 @@ static inline ssize_t spi_w8r16be(struct spi_device *spi, u8 cmd)
  * are active in some dynamic board configuration models.
  */
 struct spi_board_info {
-       /* the device name and module name are coupled, like platform_bus;
+       /* The device name and module name are coupled, like platform_bus;
         * "modalias" is normally the driver name.
         *
         * platform_data goes to spi_device.dev.platform_data,
@@ -1419,7 +1446,7 @@ struct spi_board_info {
        void            *controller_data;
        int             irq;
 
-       /* slower signaling on noisy or low voltage boards */
+       /* Slower signaling on noisy or low voltage boards */
        u32             max_speed_hz;
 
 
@@ -1448,7 +1475,7 @@ struct spi_board_info {
 extern int
 spi_register_board_info(struct spi_board_info const *info, unsigned n);
 #else
-/* board init code may ignore whether SPI is configured or not */
+/* Board init code may ignore whether SPI is configured or not */
 static inline int
 spi_register_board_info(struct spi_board_info const *info, unsigned n)
        { return 0; }
index 2991785..8df475d 100644 (file)
@@ -260,6 +260,7 @@ struct plat_stmmacenet_data {
        bool has_crossts;
        int int_snapshot_num;
        int ext_snapshot_num;
+       bool int_snapshot_en;
        bool ext_snapshot_en;
        bool multi_msi_en;
        int msi_mac_vec;
index b0dcfa2..8ba8b5b 100644 (file)
@@ -55,6 +55,18 @@ struct efifb_dmi_info {
        int flags;
 };
 
+#ifdef CONFIG_SYSFB
+
+void sysfb_disable(void);
+
+#else /* CONFIG_SYSFB */
+
+static inline void sysfb_disable(void)
+{
+}
+
+#endif /* CONFIG_SYSFB */
+
 #ifdef CONFIG_EFI
 
 extern struct efifb_dmi_info efifb_dmi_list[];
@@ -72,8 +84,8 @@ static inline void sysfb_apply_efi_quirks(struct platform_device *pd)
 
 bool sysfb_parse_mode(const struct screen_info *si,
                      struct simplefb_platform_data *mode);
-int sysfb_create_simplefb(const struct screen_info *si,
-                         const struct simplefb_platform_data *mode);
+struct platform_device *sysfb_create_simplefb(const struct screen_info *si,
+                                             const struct simplefb_platform_data *mode);
 
 #else /* CONFIG_SYSFB_SIMPLE */
 
@@ -83,10 +95,10 @@ static inline bool sysfb_parse_mode(const struct screen_info *si,
        return false;
 }
 
-static inline int sysfb_create_simplefb(const struct screen_info *si,
-                                        const struct simplefb_platform_data *mode)
+static inline struct platform_device *sysfb_create_simplefb(const struct screen_info *si,
+                                                           const struct simplefb_platform_data *mode)
 {
-       return -EINVAL;
+       return ERR_PTR(-EINVAL);
 }
 
 #endif /* CONFIG_SYSFB_SIMPLE */
index 365733b..1386c71 100644 (file)
@@ -40,8 +40,6 @@ enum thermal_trend {
        THERMAL_TREND_STABLE, /* temperature is stable */
        THERMAL_TREND_RAISING, /* temperature is raising */
        THERMAL_TREND_DROPPING, /* temperature is dropping */
-       THERMAL_TREND_RAISE_FULL, /* apply highest cooling action */
-       THERMAL_TREND_DROP_FULL, /* apply lowest cooling action */
 };
 
 /* Thermal notification reason */
@@ -80,6 +78,18 @@ struct thermal_zone_device_ops {
        void (*critical)(struct thermal_zone_device *);
 };
 
+/**
+ * struct thermal_trip - representation of a point in temperature domain
+ * @temperature: temperature value in miliCelsius
+ * @hysteresis: relative hysteresis in miliCelsius
+ * @type: trip point type
+ */
+struct thermal_trip {
+       int temperature;
+       int hysteresis;
+       enum thermal_trip_type type;
+};
+
 struct thermal_cooling_device_ops {
        int (*get_max_state) (struct thermal_cooling_device *, unsigned long *);
        int (*get_cur_state) (struct thermal_cooling_device *, unsigned long *);
@@ -113,7 +123,8 @@ struct thermal_cooling_device {
  * @trip_hyst_attrs:   attributes for trip points for sysfs: trip hysteresis
  * @mode:              current mode of this thermal zone
  * @devdata:   private pointer for device private data
- * @trips:     number of trip points the thermal zone supports
+ * @trips:     an array of struct thermal_trip
+ * @num_trips: number of trip points the thermal zone supports
  * @trips_disabled;    bitmap for disabled trips
  * @passive_delay_jiffies: number of jiffies to wait between polls when
  *                     performing passive cooling.
@@ -153,7 +164,8 @@ struct thermal_zone_device {
        struct thermal_attr *trip_hyst_attrs;
        enum thermal_device_mode mode;
        void *devdata;
-       int trips;
+       struct thermal_trip *trips;
+       int num_trips;
        unsigned long trips_disabled;   /* bitmap for disabled trips */
        unsigned long passive_delay_jiffies;
        unsigned long polling_delay_jiffies;
@@ -366,8 +378,14 @@ void devm_thermal_zone_of_sensor_unregister(struct device *dev,
 struct thermal_zone_device *thermal_zone_device_register(const char *, int, int,
                void *, struct thermal_zone_device_ops *,
                struct thermal_zone_params *, int, int);
+
 void thermal_zone_device_unregister(struct thermal_zone_device *);
 
+struct thermal_zone_device *
+thermal_zone_device_register_with_trips(const char *, struct thermal_trip *, int, int,
+                                       void *, struct thermal_zone_device_ops *,
+                                       struct thermal_zone_params *, int, int);
+
 int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
                                     struct thermal_cooling_device *,
                                     unsigned long, unsigned long,
index 28031b1..55717a2 100644 (file)
@@ -200,13 +200,13 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
                 */                                                     \
                if (rcuidle) {                                          \
                        __idx = srcu_read_lock_notrace(&tracepoint_srcu);\
-                       rcu_irq_enter_irqson();                         \
+                       ct_irq_enter_irqson();                          \
                }                                                       \
                                                                        \
                __DO_TRACE_CALL(name, TP_ARGS(args));                   \
                                                                        \
                if (rcuidle) {                                          \
-                       rcu_irq_exit_irqson();                          \
+                       ct_irq_exit_irqson();                           \
                        srcu_read_unlock_notrace(&tracepoint_srcu, __idx);\
                }                                                       \
                                                                        \
index 739285f..34ba4a7 100644 (file)
@@ -219,6 +219,8 @@ size_t _copy_mc_to_iter(const void *addr, size_t bytes, struct iov_iter *i);
 #endif
 
 size_t iov_iter_zero(size_t bytes, struct iov_iter *);
+bool iov_iter_is_aligned(const struct iov_iter *i, unsigned addr_mask,
+                       unsigned len_mask);
 unsigned long iov_iter_alignment(const struct iov_iter *i);
 unsigned long iov_iter_gap_alignment(const struct iov_iter *i);
 void iov_iter_init(struct iov_iter *i, unsigned int direction, const struct iovec *iov,
index 49c7c32..b47c2e7 100644 (file)
@@ -257,6 +257,7 @@ void virtio_device_ready(struct virtio_device *dev)
 
        WARN_ON(status & VIRTIO_CONFIG_S_DRIVER_OK);
 
+#ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION
        /*
         * The virtio_synchronize_cbs() makes sure vring_interrupt()
         * will see the driver specific setup if it sees vq->broken
@@ -264,6 +265,7 @@ void virtio_device_ready(struct virtio_device *dev)
         */
        virtio_synchronize_cbs(dev);
        __virtio_unbreak_device(dev);
+#endif
        /*
         * The transport should ensure the visibility of vq->broken
         * before setting DRIVER_OK. See the comments for the transport
index 851e07d..58cfbf8 100644 (file)
@@ -544,10 +544,11 @@ do {                                                                              \
                                                                                \
        hrtimer_init_sleeper_on_stack(&__t, CLOCK_MONOTONIC,                    \
                                      HRTIMER_MODE_REL);                        \
-       if ((timeout) != KTIME_MAX)                                             \
-               hrtimer_start_range_ns(&__t.timer, timeout,                     \
-                                      current->timer_slack_ns,                 \
-                                      HRTIMER_MODE_REL);                       \
+       if ((timeout) != KTIME_MAX) {                                           \
+               hrtimer_set_expires_range_ns(&__t.timer, timeout,               \
+                                       current->timer_slack_ns);               \
+               hrtimer_sleeper_start_expires(&__t, HRTIMER_MODE_REL);          \
+       }                                                                       \
                                                                                \
        __ret = ___wait_event(wq_head, condition, state, 0, 0,                  \
                if (!__t.task) {                                                \
index 3b9a40a..fc6bba2 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2020 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
- * See Documentation/watch_queue.rst
+ * See Documentation/core-api/watch_queue.rst
  */
 
 #ifndef _LINUX_WATCH_QUEUE_H
index da21d63..3f045f6 100644 (file)
@@ -101,9 +101,9 @@ struct writeback_control {
 #endif
 };
 
-static inline int wbc_to_write_flags(struct writeback_control *wbc)
+static inline blk_opf_t wbc_to_write_flags(struct writeback_control *wbc)
 {
-       int flags = 0;
+       blk_opf_t flags = 0;
 
        if (wbc->punt_to_cgroup)
                flags = REQ_CGROUP_PUNT;
@@ -364,7 +364,14 @@ void global_dirty_limits(unsigned long *pbackground, unsigned long *pdirty);
 unsigned long wb_calc_thresh(struct bdi_writeback *wb, unsigned long thresh);
 
 void wb_update_bandwidth(struct bdi_writeback *wb);
+
+/* Invoke balance dirty pages in async mode. */
+#define BDP_ASYNC 0x0001
+
 void balance_dirty_pages_ratelimited(struct address_space *mapping);
+int balance_dirty_pages_ratelimited_flags(struct address_space *mapping,
+               unsigned int flags);
+
 bool wb_over_bg_thresh(struct bdi_writeback *wb);
 
 typedef int (*writepage_t)(struct page *page, struct writeback_control *wbc,
index c29e11b..44dd6d6 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/kconfig.h>
 #include <linux/kernel.h>
 #include <linux/rcupdate.h>
+#include <linux/sched/mm.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
 
@@ -586,6 +587,7 @@ static inline void *xa_store_bh(struct xarray *xa, unsigned long index,
 {
        void *curr;
 
+       might_alloc(gfp);
        xa_lock_bh(xa);
        curr = __xa_store(xa, index, entry, gfp);
        xa_unlock_bh(xa);
@@ -612,6 +614,7 @@ static inline void *xa_store_irq(struct xarray *xa, unsigned long index,
 {
        void *curr;
 
+       might_alloc(gfp);
        xa_lock_irq(xa);
        curr = __xa_store(xa, index, entry, gfp);
        xa_unlock_irq(xa);
@@ -687,6 +690,7 @@ static inline void *xa_cmpxchg(struct xarray *xa, unsigned long index,
 {
        void *curr;
 
+       might_alloc(gfp);
        xa_lock(xa);
        curr = __xa_cmpxchg(xa, index, old, entry, gfp);
        xa_unlock(xa);
@@ -714,6 +718,7 @@ static inline void *xa_cmpxchg_bh(struct xarray *xa, unsigned long index,
 {
        void *curr;
 
+       might_alloc(gfp);
        xa_lock_bh(xa);
        curr = __xa_cmpxchg(xa, index, old, entry, gfp);
        xa_unlock_bh(xa);
@@ -741,6 +746,7 @@ static inline void *xa_cmpxchg_irq(struct xarray *xa, unsigned long index,
 {
        void *curr;
 
+       might_alloc(gfp);
        xa_lock_irq(xa);
        curr = __xa_cmpxchg(xa, index, old, entry, gfp);
        xa_unlock_irq(xa);
@@ -770,6 +776,7 @@ static inline int __must_check xa_insert(struct xarray *xa,
 {
        int err;
 
+       might_alloc(gfp);
        xa_lock(xa);
        err = __xa_insert(xa, index, entry, gfp);
        xa_unlock(xa);
@@ -799,6 +806,7 @@ static inline int __must_check xa_insert_bh(struct xarray *xa,
 {
        int err;
 
+       might_alloc(gfp);
        xa_lock_bh(xa);
        err = __xa_insert(xa, index, entry, gfp);
        xa_unlock_bh(xa);
@@ -828,6 +836,7 @@ static inline int __must_check xa_insert_irq(struct xarray *xa,
 {
        int err;
 
+       might_alloc(gfp);
        xa_lock_irq(xa);
        err = __xa_insert(xa, index, entry, gfp);
        xa_unlock_irq(xa);
@@ -857,6 +866,7 @@ static inline __must_check int xa_alloc(struct xarray *xa, u32 *id,
 {
        int err;
 
+       might_alloc(gfp);
        xa_lock(xa);
        err = __xa_alloc(xa, id, entry, limit, gfp);
        xa_unlock(xa);
@@ -886,6 +896,7 @@ static inline int __must_check xa_alloc_bh(struct xarray *xa, u32 *id,
 {
        int err;
 
+       might_alloc(gfp);
        xa_lock_bh(xa);
        err = __xa_alloc(xa, id, entry, limit, gfp);
        xa_unlock_bh(xa);
@@ -915,6 +926,7 @@ static inline int __must_check xa_alloc_irq(struct xarray *xa, u32 *id,
 {
        int err;
 
+       might_alloc(gfp);
        xa_lock_irq(xa);
        err = __xa_alloc(xa, id, entry, limit, gfp);
        xa_unlock_irq(xa);
@@ -948,6 +960,7 @@ static inline int xa_alloc_cyclic(struct xarray *xa, u32 *id, void *entry,
 {
        int err;
 
+       might_alloc(gfp);
        xa_lock(xa);
        err = __xa_alloc_cyclic(xa, id, entry, limit, next, gfp);
        xa_unlock(xa);
@@ -981,6 +994,7 @@ static inline int xa_alloc_cyclic_bh(struct xarray *xa, u32 *id, void *entry,
 {
        int err;
 
+       might_alloc(gfp);
        xa_lock_bh(xa);
        err = __xa_alloc_cyclic(xa, id, entry, limit, next, gfp);
        xa_unlock_bh(xa);
@@ -1014,6 +1028,7 @@ static inline int xa_alloc_cyclic_irq(struct xarray *xa, u32 *id, void *entry,
 {
        int err;
 
+       might_alloc(gfp);
        xa_lock_irq(xa);
        err = __xa_alloc_cyclic(xa, id, entry, limit, next, gfp);
        xa_unlock_irq(xa);
index 4c379d2..979a9d3 100644 (file)
@@ -61,7 +61,7 @@ int __vfs_setxattr_locked(struct user_namespace *, struct dentry *,
                          const char *, const void *, size_t, int,
                          struct inode **);
 int vfs_setxattr(struct user_namespace *, struct dentry *, const char *,
-                const void *, size_t, int);
+                void *, size_t, int);
 int __vfs_removexattr(struct user_namespace *, struct dentry *, const char *);
 int __vfs_removexattr_locked(struct user_namespace *, struct dentry *,
                             const char *, struct inode **);
index f7506f0..c04f359 100644 (file)
@@ -405,6 +405,9 @@ static inline bool ip6_ignore_linkdown(const struct net_device *dev)
 {
        const struct inet6_dev *idev = __in6_dev_get(dev);
 
+       if (unlikely(!idev))
+               return true;
+
        return !!idev->cnf.ignore_routes_with_linkdown;
 }
 
index 0e40c3d..08fc30c 100644 (file)
@@ -78,6 +78,15 @@ enum amt_status {
 
 #define AMT_STATUS_MAX (__AMT_STATUS_MAX - 1)
 
+/* Gateway events only */
+enum amt_event {
+       AMT_EVENT_NONE,
+       AMT_EVENT_RECEIVE,
+       AMT_EVENT_SEND_DISCOVERY,
+       AMT_EVENT_SEND_REQUEST,
+       __AMT_EVENT_MAX,
+};
+
 struct amt_header {
 #if defined(__LITTLE_ENDIAN_BITFIELD)
        u8 type:4,
@@ -292,6 +301,12 @@ struct amt_group_node {
        struct hlist_head       sources[];
 };
 
+#define AMT_MAX_EVENTS 16
+struct amt_events {
+       enum amt_event event;
+       struct sk_buff *skb;
+};
+
 struct amt_dev {
        struct net_device       *dev;
        struct net_device       *stream_dev;
@@ -308,6 +323,7 @@ struct amt_dev {
        struct delayed_work     req_wq;
        /* Protected by RTNL */
        struct delayed_work     secret_wq;
+       struct work_struct      event_wq;
        /* AMT status */
        enum amt_status         status;
        /* Generated key */
@@ -345,6 +361,10 @@ struct amt_dev {
        /* Used only in gateway mode */
        u64                     mac:48,
                                reserved:16;
+       /* AMT gateway side message handler queue */
+       struct amt_events       events[AMT_MAX_EVENTS];
+       u8                      event_idx;
+       u8                      nr_events;
 };
 
 #define AMT_TOS                        0xc0
index 3c4f550..2f766e3 100644 (file)
@@ -847,6 +847,7 @@ enum {
 };
 
 void l2cap_chan_hold(struct l2cap_chan *c);
+struct l2cap_chan *l2cap_chan_hold_unless_zero(struct l2cap_chan *c);
 void l2cap_chan_put(struct l2cap_chan *c);
 
 static inline void l2cap_chan_lock(struct l2cap_chan *chan)
index 6d02e12..80f4144 100644 (file)
@@ -8462,11 +8462,12 @@ int cfg80211_bss_color_notify(struct net_device *dev, gfp_t gfp,
  * cfg80211_obss_color_collision_notify - notify about bss color collision
  * @dev: network device
  * @color_bitmap: representations of the colors that the local BSS is aware of
+ * @gfp: allocation flags
  */
 static inline int cfg80211_obss_color_collision_notify(struct net_device *dev,
-                                                      u64 color_bitmap)
+                                                      u64 color_bitmap, gfp_t gfp)
 {
-       return cfg80211_bss_color_notify(dev, GFP_KERNEL,
+       return cfg80211_bss_color_notify(dev, gfp,
                                         NL80211_CMD_OBSS_COLOR_COLLISION,
                                         0, color_bitmap);
 }
index 595fee0..84c163f 100644 (file)
@@ -46,9 +46,8 @@ struct compat_rtentry {
        unsigned short  rt_irtt;        /* Initial RTT                  */
 };
 
-int __get_compat_msghdr(struct msghdr *kmsg, struct compat_msghdr __user *umsg,
-                       struct sockaddr __user **save_addr, compat_uptr_t *ptr,
-                       compat_size_t *len);
+int __get_compat_msghdr(struct msghdr *kmsg, struct compat_msghdr *msg,
+                       struct sockaddr __user **save_addr);
 int get_compat_msghdr(struct msghdr *, struct compat_msghdr __user *,
                      struct sockaddr __user **, struct iovec **);
 int put_cmsg_compat(struct msghdr*, int, int, int, void *);
index 6484095..7ac3138 100644 (file)
@@ -152,6 +152,7 @@ enum flow_action_id {
        FLOW_ACTION_PIPE,
        FLOW_ACTION_VLAN_PUSH_ETH,
        FLOW_ACTION_VLAN_POP_ETH,
+       FLOW_ACTION_CONTINUE,
        NUM_FLOW_ACTIONS,
 };
 
index 85cd695..ee88f0f 100644 (file)
@@ -321,7 +321,7 @@ void inet_csk_update_fastreuse(struct inet_bind_bucket *tb,
 
 struct dst_entry *inet_csk_update_pmtu(struct sock *sk, u32 mtu);
 
-#define TCP_PINGPONG_THRESH    3
+#define TCP_PINGPONG_THRESH    1
 
 static inline void inet_csk_enter_pingpong_mode(struct sock *sk)
 {
@@ -338,14 +338,6 @@ static inline bool inet_csk_in_pingpong_mode(struct sock *sk)
        return inet_csk(sk)->icsk_ack.pingpong >= TCP_PINGPONG_THRESH;
 }
 
-static inline void inet_csk_inc_pingpong_cnt(struct sock *sk)
-{
-       struct inet_connection_sock *icsk = inet_csk(sk);
-
-       if (icsk->icsk_ack.pingpong < U8_MAX)
-               icsk->icsk_ack.pingpong++;
-}
-
 static inline bool inet_csk_has_ulp(struct sock *sk)
 {
        return inet_sk(sk)->is_icsk && !!inet_csk(sk)->icsk_ulp_ops;
index ebfa3df..fd6b510 100644 (file)
@@ -179,7 +179,7 @@ static inline bool inet_sk_bound_dev_eq(struct net *net, int bound_dev_if,
                                        int dif, int sdif)
 {
 #if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV)
-       return inet_bound_dev_eq(!!net->ipv4.sysctl_tcp_l3mdev_accept,
+       return inet_bound_dev_eq(!!READ_ONCE(net->ipv4.sysctl_tcp_l3mdev_accept),
                                 bound_dev_if, dif, sdif);
 #else
        return inet_bound_dev_eq(true, bound_dev_if, dif, sdif);
index daead5f..6395f6b 100644 (file)
@@ -107,7 +107,8 @@ static inline struct inet_request_sock *inet_rsk(const struct request_sock *sk)
 
 static inline u32 inet_request_mark(const struct sock *sk, struct sk_buff *skb)
 {
-       if (!sk->sk_mark && sock_net(sk)->ipv4.sysctl_tcp_fwmark_accept)
+       if (!sk->sk_mark &&
+           READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_fwmark_accept))
                return skb->mark;
 
        return sk->sk_mark;
@@ -120,7 +121,7 @@ static inline int inet_request_bound_dev_if(const struct sock *sk,
 #ifdef CONFIG_NET_L3_MASTER_DEV
        struct net *net = sock_net(sk);
 
-       if (!bound_dev_if && net->ipv4.sysctl_tcp_l3mdev_accept)
+       if (!bound_dev_if && READ_ONCE(net->ipv4.sysctl_tcp_l3mdev_accept))
                return l3mdev_master_ifindex_by_index(net, skb->skb_iif);
 #endif
 
@@ -132,7 +133,7 @@ static inline int inet_sk_bound_l3mdev(const struct sock *sk)
 #ifdef CONFIG_NET_L3_MASTER_DEV
        struct net *net = sock_net(sk);
 
-       if (!net->ipv4.sysctl_tcp_l3mdev_accept)
+       if (!READ_ONCE(net->ipv4.sysctl_tcp_l3mdev_accept))
                return l3mdev_master_ifindex_by_index(net,
                                                      sk->sk_bound_dev_if);
 #endif
@@ -374,7 +375,7 @@ static inline bool inet_get_convert_csum(struct sock *sk)
 static inline bool inet_can_nonlocal_bind(struct net *net,
                                          struct inet_sock *inet)
 {
-       return net->ipv4.sysctl_ip_nonlocal_bind ||
+       return READ_ONCE(net->ipv4.sysctl_ip_nonlocal_bind) ||
                inet->freebind || inet->transparent;
 }
 
index 26fffda..1c979fd 100644 (file)
@@ -357,7 +357,7 @@ static inline bool sysctl_dev_name_is_allowed(const char *name)
 
 static inline bool inet_port_requires_bind_service(struct net *net, unsigned short port)
 {
-       return port < net->ipv4.sysctl_ip_prot_sock;
+       return port < READ_ONCE(net->ipv4.sysctl_ip_prot_sock);
 }
 
 #else
@@ -384,7 +384,7 @@ void ipfrag_init(void);
 void ip_static_sysctl_init(void);
 
 #define IP4_REPLY_MARK(net, mark) \
-       ((net)->ipv4.sysctl_fwmark_reflect ? (mark) : 0)
+       (READ_ONCE((net)->ipv4.sysctl_fwmark_reflect) ? (mark) : 0)
 
 static inline bool ip_is_fragment(const struct iphdr *iph)
 {
@@ -446,7 +446,7 @@ static inline unsigned int ip_dst_mtu_maybe_forward(const struct dst_entry *dst,
        struct net *net = dev_net(dst->dev);
        unsigned int mtu;
 
-       if (net->ipv4.sysctl_ip_fwd_use_pmtu ||
+       if (READ_ONCE(net->ipv4.sysctl_ip_fwd_use_pmtu) ||
            ip_mtu_locked(dst) ||
            !forwarding) {
                mtu = rt->rt_pmtu;
index ebadb21..47642b0 100644 (file)
@@ -6960,10 +6960,11 @@ ieee80211_get_unsol_bcast_probe_resp_tmpl(struct ieee80211_hw *hw,
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  * @color_bitmap: a 64 bit bitmap representing the colors that the local BSS is
  *     aware of.
+ * @gfp: allocation flags
  */
 void
 ieeee80211_obss_color_collision_notify(struct ieee80211_vif *vif,
-                                      u64 color_bitmap);
+                                      u64 color_bitmap, gfp_t gfp);
 
 /**
  * ieee80211_is_tx_data - check if frame is a data frame
index 279ae0f..64cf655 100644 (file)
@@ -657,18 +657,22 @@ static inline void nft_set_ext_prepare(struct nft_set_ext_tmpl *tmpl)
        tmpl->len = sizeof(struct nft_set_ext);
 }
 
-static inline void nft_set_ext_add_length(struct nft_set_ext_tmpl *tmpl, u8 id,
-                                         unsigned int len)
+static inline int nft_set_ext_add_length(struct nft_set_ext_tmpl *tmpl, u8 id,
+                                        unsigned int len)
 {
        tmpl->len        = ALIGN(tmpl->len, nft_set_ext_types[id].align);
-       BUG_ON(tmpl->len > U8_MAX);
+       if (tmpl->len > U8_MAX)
+               return -EINVAL;
+
        tmpl->offset[id] = tmpl->len;
        tmpl->len       += nft_set_ext_types[id].len + len;
+
+       return 0;
 }
 
-static inline void nft_set_ext_add(struct nft_set_ext_tmpl *tmpl, u8 id)
+static inline int nft_set_ext_add(struct nft_set_ext_tmpl *tmpl, u8 id)
 {
-       nft_set_ext_add_length(tmpl, id, 0);
+       return nft_set_ext_add_length(tmpl, id, 0);
 }
 
 static inline void nft_set_ext_init(struct nft_set_ext *ext,
@@ -1338,24 +1342,28 @@ void nft_unregister_flowtable_type(struct nf_flowtable_type *type);
 /**
  *     struct nft_traceinfo - nft tracing information and state
  *
+ *     @trace: other struct members are initialised
+ *     @nf_trace: copy of skb->nf_trace before rule evaluation
+ *     @type: event type (enum nft_trace_types)
+ *     @skbid: hash of skb to be used as trace id
+ *     @packet_dumped: packet headers sent in a previous traceinfo message
  *     @pkt: pktinfo currently processed
  *     @basechain: base chain currently processed
  *     @chain: chain currently processed
  *     @rule:  rule that was evaluated
  *     @verdict: verdict given by rule
- *     @type: event type (enum nft_trace_types)
- *     @packet_dumped: packet headers sent in a previous traceinfo message
- *     @trace: other struct members are initialised
  */
 struct nft_traceinfo {
+       bool                            trace;
+       bool                            nf_trace;
+       bool                            packet_dumped;
+       enum nft_trace_types            type:8;
+       u32                             skbid;
        const struct nft_pktinfo        *pkt;
        const struct nft_base_chain     *basechain;
        const struct nft_chain          *chain;
        const struct nft_rule_dp        *rule;
        const struct nft_verdict        *verdict;
-       enum nft_trace_types            type;
-       bool                            packet_dumped;
-       bool                            trace;
 };
 
 void nft_trace_init(struct nft_traceinfo *info, const struct nft_pktinfo *pkt,
index f51c06a..6aef8cb 100644 (file)
@@ -35,8 +35,6 @@
 
 /* This is used to register protocols. */
 struct net_protocol {
-       int                     (*early_demux)(struct sk_buff *skb);
-       int                     (*early_demux_handler)(struct sk_buff *skb);
        int                     (*handler)(struct sk_buff *skb);
 
        /* This returns an error if we weren't able to handle the error. */
@@ -52,8 +50,6 @@ struct net_protocol {
 
 #if IS_ENABLED(CONFIG_IPV6)
 struct inet6_protocol {
-       void    (*early_demux)(struct sk_buff *skb);
-       void    (*early_demux_handler)(struct sk_buff *skb);
        int     (*handler)(struct sk_buff *skb);
 
        /* This returns an error if we weren't able to handle the error. */
index 8ad8df5..c51a635 100644 (file)
@@ -75,7 +75,7 @@ static inline bool raw_sk_bound_dev_eq(struct net *net, int bound_dev_if,
                                       int dif, int sdif)
 {
 #if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV)
-       return inet_bound_dev_eq(!!net->ipv4.sysctl_raw_l3mdev_accept,
+       return inet_bound_dev_eq(READ_ONCE(net->ipv4.sysctl_raw_l3mdev_accept),
                                 bound_dev_if, dif, sdif);
 #else
        return inet_bound_dev_eq(true, bound_dev_if, dif, sdif);
index 991a398..bbcf2ab 100644 (file)
@@ -373,7 +373,7 @@ static inline int ip4_dst_hoplimit(const struct dst_entry *dst)
        struct net *net = dev_net(dst->dev);
 
        if (hoplimit == 0)
-               hoplimit = net->ipv4.sysctl_ip_default_ttl;
+               hoplimit = READ_ONCE(net->ipv4.sysctl_ip_default_ttl);
        return hoplimit;
 }
 
index 72ca97c..7a48991 100644 (file)
@@ -1529,7 +1529,7 @@ void __sk_mem_reclaim(struct sock *sk, int amount);
 /* sysctl_mem values are in pages, we convert them in SK_MEM_QUANTUM units */
 static inline long sk_prot_mem_limits(const struct sock *sk, int index)
 {
-       long val = sk->sk_prot->sysctl_mem[index];
+       long val = READ_ONCE(sk->sk_prot->sysctl_mem[index]);
 
 #if PAGE_SIZE > SK_MEM_QUANTUM
        val <<= PAGE_SHIFT - SK_MEM_QUANTUM_SHIFT;
@@ -2843,18 +2843,18 @@ static inline int sk_get_wmem0(const struct sock *sk, const struct proto *proto)
 {
        /* Does this proto have per netns sysctl_wmem ? */
        if (proto->sysctl_wmem_offset)
-               return *(int *)((void *)sock_net(sk) + proto->sysctl_wmem_offset);
+               return READ_ONCE(*(int *)((void *)sock_net(sk) + proto->sysctl_wmem_offset));
 
-       return *proto->sysctl_wmem;
+       return READ_ONCE(*proto->sysctl_wmem);
 }
 
 static inline int sk_get_rmem0(const struct sock *sk, const struct proto *proto)
 {
        /* Does this proto have per netns sysctl_rmem ? */
        if (proto->sysctl_rmem_offset)
-               return *(int *)((void *)sock_net(sk) + proto->sysctl_rmem_offset);
+               return READ_ONCE(*(int *)((void *)sock_net(sk) + proto->sysctl_rmem_offset));
 
-       return *proto->sysctl_rmem;
+       return READ_ONCE(*proto->sysctl_rmem);
 }
 
 /* Default TCP Small queue budget is ~1 ms of data (1sec >> 10)
index 1e99f5c..78a64e1 100644 (file)
@@ -932,7 +932,7 @@ extern const struct inet_connection_sock_af_ops ipv6_specific;
 
 INDIRECT_CALLABLE_DECLARE(void tcp_v6_send_check(struct sock *sk, struct sk_buff *skb));
 INDIRECT_CALLABLE_DECLARE(int tcp_v6_rcv(struct sk_buff *skb));
-INDIRECT_CALLABLE_DECLARE(void tcp_v6_early_demux(struct sk_buff *skb));
+void tcp_v6_early_demux(struct sk_buff *skb);
 
 #endif
 
@@ -1403,8 +1403,8 @@ static inline void tcp_slow_start_after_idle_check(struct sock *sk)
        struct tcp_sock *tp = tcp_sk(sk);
        s32 delta;
 
-       if (!sock_net(sk)->ipv4.sysctl_tcp_slow_start_after_idle || tp->packets_out ||
-           ca_ops->cong_control)
+       if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_slow_start_after_idle) ||
+           tp->packets_out || ca_ops->cong_control)
                return;
        delta = tcp_jiffies32 - tp->lsndtime;
        if (delta > inet_csk(sk)->icsk_rto)
@@ -1419,7 +1419,7 @@ void tcp_select_initial_window(const struct sock *sk, int __space,
 
 static inline int tcp_win_from_space(const struct sock *sk, int space)
 {
-       int tcp_adv_win_scale = sock_net(sk)->ipv4.sysctl_tcp_adv_win_scale;
+       int tcp_adv_win_scale = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_adv_win_scale);
 
        return tcp_adv_win_scale <= 0 ?
                (space>>(-tcp_adv_win_scale)) :
@@ -1493,21 +1493,24 @@ static inline int keepalive_intvl_when(const struct tcp_sock *tp)
 {
        struct net *net = sock_net((struct sock *)tp);
 
-       return tp->keepalive_intvl ? : net->ipv4.sysctl_tcp_keepalive_intvl;
+       return tp->keepalive_intvl ? :
+               READ_ONCE(net->ipv4.sysctl_tcp_keepalive_intvl);
 }
 
 static inline int keepalive_time_when(const struct tcp_sock *tp)
 {
        struct net *net = sock_net((struct sock *)tp);
 
-       return tp->keepalive_time ? : net->ipv4.sysctl_tcp_keepalive_time;
+       return tp->keepalive_time ? :
+               READ_ONCE(net->ipv4.sysctl_tcp_keepalive_time);
 }
 
 static inline int keepalive_probes(const struct tcp_sock *tp)
 {
        struct net *net = sock_net((struct sock *)tp);
 
-       return tp->keepalive_probes ? : net->ipv4.sysctl_tcp_keepalive_probes;
+       return tp->keepalive_probes ? :
+               READ_ONCE(net->ipv4.sysctl_tcp_keepalive_probes);
 }
 
 static inline u32 keepalive_time_elapsed(const struct tcp_sock *tp)
@@ -1520,7 +1523,8 @@ static inline u32 keepalive_time_elapsed(const struct tcp_sock *tp)
 
 static inline int tcp_fin_time(const struct sock *sk)
 {
-       int fin_timeout = tcp_sk(sk)->linger2 ? : sock_net(sk)->ipv4.sysctl_tcp_fin_timeout;
+       int fin_timeout = tcp_sk(sk)->linger2 ? :
+               READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_fin_timeout);
        const int rto = inet_csk(sk)->icsk_rto;
 
        if (fin_timeout < (rto << 2) - (rto >> 1))
@@ -2023,7 +2027,7 @@ void __tcp_v4_send_check(struct sk_buff *skb, __be32 saddr, __be32 daddr);
 static inline u32 tcp_notsent_lowat(const struct tcp_sock *tp)
 {
        struct net *net = sock_net((struct sock *)tp);
-       return tp->notsent_lowat ?: net->ipv4.sysctl_tcp_notsent_lowat;
+       return tp->notsent_lowat ?: READ_ONCE(net->ipv4.sysctl_tcp_notsent_lowat);
 }
 
 bool tcp_stream_memory_free(const struct sock *sk, int wake);
index 8017f17..8bd938f 100644 (file)
@@ -704,7 +704,7 @@ int tls_sw_fallback_init(struct sock *sk,
                         struct tls_crypto_info *crypto_info);
 
 #ifdef CONFIG_TLS_DEVICE
-void tls_device_init(void);
+int tls_device_init(void);
 void tls_device_cleanup(void);
 void tls_device_sk_destruct(struct sock *sk);
 int tls_set_device_offload(struct sock *sk, struct tls_context *ctx);
@@ -724,7 +724,7 @@ static inline bool tls_is_sk_rx_device_offloaded(struct sock *sk)
        return tls_get_ctx(sk)->rx_conf == TLS_HW;
 }
 #else
-static inline void tls_device_init(void) {}
+static inline int tls_device_init(void) { return 0; }
 static inline void tls_device_cleanup(void) {}
 
 static inline int
index b83a003..8dd4aa1 100644 (file)
@@ -167,7 +167,7 @@ static inline void udp_csum_pull_header(struct sk_buff *skb)
 typedef struct sock *(*udp_lookup_t)(const struct sk_buff *skb, __be16 sport,
                                     __be16 dport);
 
-INDIRECT_CALLABLE_DECLARE(void udp_v6_early_demux(struct sk_buff *));
+void udp_v6_early_demux(struct sk_buff *skb);
 INDIRECT_CALLABLE_DECLARE(int udpv6_rcv(struct sk_buff *));
 
 struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
@@ -238,7 +238,7 @@ static inline bool udp_sk_bound_dev_eq(struct net *net, int bound_dev_if,
                                       int dif, int sdif)
 {
 #if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV)
-       return inet_bound_dev_eq(!!net->ipv4.sysctl_udp_l3mdev_accept,
+       return inet_bound_dev_eq(!!READ_ONCE(net->ipv4.sysctl_udp_l3mdev_accept),
                                 bound_dev_if, dif, sdif);
 #else
        return inet_bound_dev_eq(true, bound_dev_if, dif, sdif);
index 1e80e70..bac55de 100644 (file)
@@ -386,7 +386,7 @@ static inline unsigned scsi_transfer_length(struct scsi_cmnd *scmd)
 extern void scsi_build_sense(struct scsi_cmnd *scmd, int desc,
                             u8 key, u8 asc, u8 ascq);
 
-struct request *scsi_alloc_request(struct request_queue *q,
-               unsigned int op, blk_mq_req_flags_t flags);
+struct request *scsi_alloc_request(struct request_queue *q, blk_opf_t opf,
+                                  blk_mq_req_flags_t flags);
 
 #endif /* _SCSI_SCSI_CMND_H */
index 7cf5f3b..2493bd6 100644 (file)
@@ -457,7 +457,7 @@ extern void scsi_sanitize_inquiry_string(unsigned char *s, int len);
 extern int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
                        int data_direction, void *buffer, unsigned bufflen,
                        unsigned char *sense, struct scsi_sense_hdr *sshdr,
-                       int timeout, int retries, u64 flags,
+                       int timeout, int retries, blk_opf_t flags,
                        req_flags_t rq_flags, int *resid);
 /* Make sure any sense buffer is the correct size. */
 #define scsi_execute(sdev, cmd, data_direction, buffer, bufflen, sense,        \
index 667d889..65082ec 100644 (file)
@@ -786,7 +786,7 @@ extern int scsi_host_block(struct Scsi_Host *shost);
 extern int scsi_host_unblock(struct Scsi_Host *shost, int new_state);
 
 void scsi_host_busy_iter(struct Scsi_Host *,
-                        bool (*fn)(struct scsi_cmnd *, void *, bool), void *priv);
+                        bool (*fn)(struct scsi_cmnd *, void *), void *priv);
 
 struct class_container;
 
index f20f5f8..b276dcb 100644 (file)
@@ -408,8 +408,6 @@ struct snd_soc_jack_pin;
 
 struct snd_soc_jack_gpio;
 
-typedef int (*hw_write_t)(void *,const char* ,int);
-
 enum snd_soc_pcm_subclass {
        SND_SOC_PCM_CLASS_PCM   = 0,
        SND_SOC_PCM_CLASS_BE    = 1,
index 32088c6..bad2122 100644 (file)
 /* note: we begin tracing dlm_lock_start() only if ls and lkb are found */
 TRACE_EVENT(dlm_lock_start,
 
-       TP_PROTO(struct dlm_ls *ls, struct dlm_lkb *lkb, int mode,
-                __u32 flags),
+       TP_PROTO(struct dlm_ls *ls, struct dlm_lkb *lkb, void *name,
+                unsigned int namelen, int mode, __u32 flags),
 
-       TP_ARGS(ls, lkb, mode, flags),
+       TP_ARGS(ls, lkb, name, namelen, mode, flags),
 
        TP_STRUCT__entry(
                __field(__u32, ls_id)
                __field(__u32, lkb_id)
                __field(int, mode)
                __field(__u32, flags)
+               __dynamic_array(unsigned char, res_name,
+                               lkb->lkb_resource ? lkb->lkb_resource->res_length : namelen)
        ),
 
        TP_fast_assign(
+               struct dlm_rsb *r;
+
                __entry->ls_id = ls->ls_global_id;
                __entry->lkb_id = lkb->lkb_id;
                __entry->mode = mode;
                __entry->flags = flags;
+
+               r = lkb->lkb_resource;
+               if (r)
+                       memcpy(__get_dynamic_array(res_name), r->res_name,
+                              __get_dynamic_array_len(res_name));
+               else if (name)
+                       memcpy(__get_dynamic_array(res_name), name,
+                              __get_dynamic_array_len(res_name));
        ),
 
-       TP_printk("ls_id=%u lkb_id=%x mode=%s flags=%s",
+       TP_printk("ls_id=%u lkb_id=%x mode=%s flags=%s res_name=%s",
                  __entry->ls_id, __entry->lkb_id,
                  show_lock_mode(__entry->mode),
-                 show_lock_flags(__entry->flags))
+                 show_lock_flags(__entry->flags),
+                 __print_hex_str(__get_dynamic_array(res_name),
+                                 __get_dynamic_array_len(res_name)))
 
 );
 
 TRACE_EVENT(dlm_lock_end,
 
-       TP_PROTO(struct dlm_ls *ls, struct dlm_lkb *lkb, int mode, __u32 flags,
-                int error),
+       TP_PROTO(struct dlm_ls *ls, struct dlm_lkb *lkb, void *name,
+                unsigned int namelen, int mode, __u32 flags, int error),
 
-       TP_ARGS(ls, lkb, mode, flags, error),
+       TP_ARGS(ls, lkb, name, namelen, mode, flags, error),
 
        TP_STRUCT__entry(
                __field(__u32, ls_id)
@@ -88,14 +102,26 @@ TRACE_EVENT(dlm_lock_end,
                __field(int, mode)
                __field(__u32, flags)
                __field(int, error)
+               __dynamic_array(unsigned char, res_name,
+                               lkb->lkb_resource ? lkb->lkb_resource->res_length : namelen)
        ),
 
        TP_fast_assign(
+               struct dlm_rsb *r;
+
                __entry->ls_id = ls->ls_global_id;
                __entry->lkb_id = lkb->lkb_id;
                __entry->mode = mode;
                __entry->flags = flags;
 
+               r = lkb->lkb_resource;
+               if (r)
+                       memcpy(__get_dynamic_array(res_name), r->res_name,
+                              __get_dynamic_array_len(res_name));
+               else if (name)
+                       memcpy(__get_dynamic_array(res_name), name,
+                              __get_dynamic_array_len(res_name));
+
                /* return value will be zeroed in those cases by dlm_lock()
                 * we do it here again to not introduce more overhead if
                 * trace isn't running and error reflects the return value.
@@ -104,12 +130,15 @@ TRACE_EVENT(dlm_lock_end,
                        __entry->error = 0;
                else
                        __entry->error = error;
+
        ),
 
-       TP_printk("ls_id=%u lkb_id=%x mode=%s flags=%s error=%d",
+       TP_printk("ls_id=%u lkb_id=%x mode=%s flags=%s error=%d res_name=%s",
                  __entry->ls_id, __entry->lkb_id,
                  show_lock_mode(__entry->mode),
-                 show_lock_flags(__entry->flags), __entry->error)
+                 show_lock_flags(__entry->flags), __entry->error,
+                 __print_hex_str(__get_dynamic_array(res_name),
+                                 __get_dynamic_array_len(res_name)))
 
 );
 
@@ -123,42 +152,65 @@ TRACE_EVENT(dlm_bast,
                __field(__u32, ls_id)
                __field(__u32, lkb_id)
                __field(int, mode)
+               __dynamic_array(unsigned char, res_name,
+                               lkb->lkb_resource ? lkb->lkb_resource->res_length : 0)
        ),
 
        TP_fast_assign(
+               struct dlm_rsb *r;
+
                __entry->ls_id = ls->ls_global_id;
                __entry->lkb_id = lkb->lkb_id;
                __entry->mode = mode;
+
+               r = lkb->lkb_resource;
+               if (r)
+                       memcpy(__get_dynamic_array(res_name), r->res_name,
+                              __get_dynamic_array_len(res_name));
        ),
 
-       TP_printk("ls_id=%u lkb_id=%x mode=%s", __entry->ls_id,
-                 __entry->lkb_id, show_lock_mode(__entry->mode))
+       TP_printk("ls_id=%u lkb_id=%x mode=%s res_name=%s",
+                 __entry->ls_id, __entry->lkb_id,
+                 show_lock_mode(__entry->mode),
+                 __print_hex_str(__get_dynamic_array(res_name),
+                                 __get_dynamic_array_len(res_name)))
 
 );
 
 TRACE_EVENT(dlm_ast,
 
-       TP_PROTO(struct dlm_ls *ls, struct dlm_lkb *lkb, struct dlm_lksb *lksb),
+       TP_PROTO(struct dlm_ls *ls, struct dlm_lkb *lkb),
 
-       TP_ARGS(ls, lkb, lksb),
+       TP_ARGS(ls, lkb),
 
        TP_STRUCT__entry(
                __field(__u32, ls_id)
                __field(__u32, lkb_id)
                __field(u8, sb_flags)
                __field(int, sb_status)
+               __dynamic_array(unsigned char, res_name,
+                               lkb->lkb_resource ? lkb->lkb_resource->res_length : 0)
        ),
 
        TP_fast_assign(
+               struct dlm_rsb *r;
+
                __entry->ls_id = ls->ls_global_id;
                __entry->lkb_id = lkb->lkb_id;
-               __entry->sb_flags = lksb->sb_flags;
-               __entry->sb_status = lksb->sb_status;
+               __entry->sb_flags = lkb->lkb_lksb->sb_flags;
+               __entry->sb_status = lkb->lkb_lksb->sb_status;
+
+               r = lkb->lkb_resource;
+               if (r)
+                       memcpy(__get_dynamic_array(res_name), r->res_name,
+                              __get_dynamic_array_len(res_name));
        ),
 
-       TP_printk("ls_id=%u lkb_id=%x sb_flags=%s sb_status=%d",
+       TP_printk("ls_id=%u lkb_id=%x sb_flags=%s sb_status=%d res_name=%s",
                  __entry->ls_id, __entry->lkb_id,
-                 show_dlm_sb_flags(__entry->sb_flags), __entry->sb_status)
+                 show_dlm_sb_flags(__entry->sb_flags), __entry->sb_status,
+                 __print_hex_str(__get_dynamic_array(res_name),
+                                 __get_dynamic_array_len(res_name)))
 
 );
 
@@ -173,17 +225,28 @@ TRACE_EVENT(dlm_unlock_start,
                __field(__u32, ls_id)
                __field(__u32, lkb_id)
                __field(__u32, flags)
+               __dynamic_array(unsigned char, res_name,
+                               lkb->lkb_resource ? lkb->lkb_resource->res_length : 0)
        ),
 
        TP_fast_assign(
+               struct dlm_rsb *r;
+
                __entry->ls_id = ls->ls_global_id;
                __entry->lkb_id = lkb->lkb_id;
                __entry->flags = flags;
+
+               r = lkb->lkb_resource;
+               if (r)
+                       memcpy(__get_dynamic_array(res_name), r->res_name,
+                              __get_dynamic_array_len(res_name));
        ),
 
-       TP_printk("ls_id=%u lkb_id=%x flags=%s",
+       TP_printk("ls_id=%u lkb_id=%x flags=%s res_name=%s",
                  __entry->ls_id, __entry->lkb_id,
-                 show_lock_flags(__entry->flags))
+                 show_lock_flags(__entry->flags),
+                 __print_hex_str(__get_dynamic_array(res_name),
+                                 __get_dynamic_array_len(res_name)))
 
 );
 
@@ -199,18 +262,29 @@ TRACE_EVENT(dlm_unlock_end,
                __field(__u32, lkb_id)
                __field(__u32, flags)
                __field(int, error)
+               __dynamic_array(unsigned char, res_name,
+                               lkb->lkb_resource ? lkb->lkb_resource->res_length : 0)
        ),
 
        TP_fast_assign(
+               struct dlm_rsb *r;
+
                __entry->ls_id = ls->ls_global_id;
                __entry->lkb_id = lkb->lkb_id;
                __entry->flags = flags;
                __entry->error = error;
+
+               r = lkb->lkb_resource;
+               if (r)
+                       memcpy(__get_dynamic_array(res_name), r->res_name,
+                              __get_dynamic_array_len(res_name));
        ),
 
-       TP_printk("ls_id=%u lkb_id=%x flags=%s error=%d",
+       TP_printk("ls_id=%u lkb_id=%x flags=%s error=%d res_name=%s",
                  __entry->ls_id, __entry->lkb_id,
-                 show_lock_flags(__entry->flags), __entry->error)
+                 show_lock_flags(__entry->flags), __entry->error,
+                 __print_hex_str(__get_dynamic_array(res_name),
+                                 __get_dynamic_array_len(res_name)))
 
 );
 
index 513e889..f1e9222 100644 (file)
@@ -66,7 +66,7 @@ TRACE_DEFINE_ENUM(CP_RESIZE);
 
 #define F2FS_OP_FLAGS (REQ_RAHEAD | REQ_SYNC | REQ_META | REQ_PRIO |   \
                        REQ_PREFLUSH | REQ_FUA)
-#define F2FS_BIO_FLAG_MASK(t)  (t & F2FS_OP_FLAGS)
+#define F2FS_BIO_FLAG_MASK(t) (__force u32)((t) & F2FS_OP_FLAGS)
 
 #define show_bio_type(op,op_flags)     show_bio_op(op),                \
                                                show_bio_op_flags(op_flags)
@@ -75,12 +75,12 @@ TRACE_DEFINE_ENUM(CP_RESIZE);
 
 #define show_bio_op_flags(flags)                                       \
        __print_flags(F2FS_BIO_FLAG_MASK(flags), "|",                   \
-               { REQ_RAHEAD,           "R" },                          \
-               { REQ_SYNC,             "S" },                          \
-               { REQ_META,             "M" },                          \
-               { REQ_PRIO,             "P" },                          \
-               { REQ_PREFLUSH,         "PF" },                         \
-               { REQ_FUA,              "FUA" })
+               { (__force u32)REQ_RAHEAD,      "R" },                  \
+               { (__force u32)REQ_SYNC,        "S" },                  \
+               { (__force u32)REQ_META,        "M" },                  \
+               { (__force u32)REQ_PRIO,        "P" },                  \
+               { (__force u32)REQ_PREFLUSH,    "PF" },                 \
+               { (__force u32)REQ_FUA,         "FUA" })
 
 #define show_data_type(type)                                           \
        __print_symbolic(type,                                          \
@@ -1036,8 +1036,8 @@ DECLARE_EVENT_CLASS(f2fs__submit_page_bio,
                __field(pgoff_t, index)
                __field(block_t, old_blkaddr)
                __field(block_t, new_blkaddr)
-               __field(int, op)
-               __field(int, op_flags)
+               __field(enum req_op, op)
+               __field(blk_opf_t, op_flags)
                __field(int, temp)
                __field(int, type)
        ),
@@ -1092,8 +1092,8 @@ DECLARE_EVENT_CLASS(f2fs__bio,
        TP_STRUCT__entry(
                __field(dev_t,  dev)
                __field(dev_t,  target)
-               __field(int,    op)
-               __field(int,    op_flags)
+               __field(enum req_op,    op)
+               __field(blk_opf_t,      op_flags)
                __field(int,    type)
                __field(sector_t,       sector)
                __field(unsigned int,   size)
index aa2f951..c5b21ff 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/tracepoint.h>
 #include <uapi/linux/io_uring.h>
+#include <linux/io_uring_types.h>
 #include <linux/io_uring.h>
 
 struct io_wq_work;
@@ -97,9 +98,7 @@ TRACE_EVENT(io_uring_register,
 /**
  * io_uring_file_get - called before getting references to an SQE file
  *
- * @ctx:       pointer to a ring context structure
  * @req:       pointer to a submitted request
- * @user_data: user data associated with the request
  * @fd:                SQE file descriptor
  *
  * Allows to trace out how often an SQE file reference is obtained, which can
@@ -108,9 +107,9 @@ TRACE_EVENT(io_uring_register,
  */
 TRACE_EVENT(io_uring_file_get,
 
-       TP_PROTO(void *ctx, void *req, unsigned long long user_data, int fd),
+       TP_PROTO(struct io_kiocb *req, int fd),
 
-       TP_ARGS(ctx, req, user_data, fd),
+       TP_ARGS(req, fd),
 
        TP_STRUCT__entry (
                __field(  void *,       ctx             )
@@ -120,9 +119,9 @@ TRACE_EVENT(io_uring_file_get,
        ),
 
        TP_fast_assign(
-               __entry->ctx            = ctx;
+               __entry->ctx            = req->ctx;
                __entry->req            = req;
-               __entry->user_data      = user_data;
+               __entry->user_data      = req->cqe.user_data;
                __entry->fd             = fd;
        ),
 
@@ -133,22 +132,16 @@ TRACE_EVENT(io_uring_file_get,
 /**
  * io_uring_queue_async_work - called before submitting a new async work
  *
- * @ctx:       pointer to a ring context structure
  * @req:       pointer to a submitted request
- * @user_data: user data associated with the request
- * @opcode:    opcode of request
- * @flags      request flags
- * @work:      pointer to a submitted io_wq_work
  * @rw:                type of workqueue, hashed or normal
  *
  * Allows to trace asynchronous work submission.
  */
 TRACE_EVENT(io_uring_queue_async_work,
 
-       TP_PROTO(void *ctx, void * req, unsigned long long user_data, u8 opcode,
-               unsigned int flags, struct io_wq_work *work, int rw),
+       TP_PROTO(struct io_kiocb *req, int rw),
 
-       TP_ARGS(ctx, req, user_data, opcode, flags, work, rw),
+       TP_ARGS(req, rw),
 
        TP_STRUCT__entry (
                __field(  void *,                       ctx             )
@@ -159,19 +152,19 @@ TRACE_EVENT(io_uring_queue_async_work,
                __field(  struct io_wq_work *,          work            )
                __field(  int,                          rw              )
 
-               __string( op_str, io_uring_get_opcode(opcode)   )
+               __string( op_str, io_uring_get_opcode(req->opcode)      )
        ),
 
        TP_fast_assign(
-               __entry->ctx            = ctx;
+               __entry->ctx            = req->ctx;
                __entry->req            = req;
-               __entry->user_data      = user_data;
-               __entry->flags          = flags;
-               __entry->opcode         = opcode;
-               __entry->work           = work;
+               __entry->user_data      = req->cqe.user_data;
+               __entry->flags          = req->flags;
+               __entry->opcode         = req->opcode;
+               __entry->work           = &req->work;
                __entry->rw             = rw;
 
-               __assign_str(op_str, io_uring_get_opcode(opcode));
+               __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",
@@ -183,19 +176,16 @@ TRACE_EVENT(io_uring_queue_async_work,
 /**
  * io_uring_defer - called when an io_uring request is deferred
  *
- * @ctx:       pointer to a ring context structure
  * @req:       pointer to a deferred request
- * @user_data: user data associated with the request
- * @opcode:    opcode of request
  *
  * Allows to track deferred requests, to get an insight about what requests are
  * not started immediately.
  */
 TRACE_EVENT(io_uring_defer,
 
-       TP_PROTO(void *ctx, void *req, unsigned long long user_data, u8 opcode),
+       TP_PROTO(struct io_kiocb *req),
 
-       TP_ARGS(ctx, req, user_data, opcode),
+       TP_ARGS(req),
 
        TP_STRUCT__entry (
                __field(  void *,               ctx     )
@@ -203,16 +193,16 @@ TRACE_EVENT(io_uring_defer,
                __field(  unsigned long long,   data    )
                __field(  u8,                   opcode  )
 
-               __string( op_str, io_uring_get_opcode(opcode) )
+               __string( op_str, io_uring_get_opcode(req->opcode) )
        ),
 
        TP_fast_assign(
-               __entry->ctx    = ctx;
+               __entry->ctx    = req->ctx;
                __entry->req    = req;
-               __entry->data   = user_data;
-               __entry->opcode = opcode;
+               __entry->data   = req->cqe.user_data;
+               __entry->opcode = req->opcode;
 
-               __assign_str(op_str, io_uring_get_opcode(opcode));
+               __assign_str(op_str, io_uring_get_opcode(req->opcode));
        ),
 
        TP_printk("ring %p, request %p, user_data 0x%llx, opcode %s",
@@ -224,7 +214,6 @@ TRACE_EVENT(io_uring_defer,
  * io_uring_link - called before the io_uring request added into link_list of
  *                another request
  *
- * @ctx:               pointer to a ring context structure
  * @req:               pointer to a linked request
  * @target_req:                pointer to a previous request, that would contain @req
  *
@@ -233,9 +222,9 @@ TRACE_EVENT(io_uring_defer,
  */
 TRACE_EVENT(io_uring_link,
 
-       TP_PROTO(void *ctx, void *req, void *target_req),
+       TP_PROTO(struct io_kiocb *req, struct io_kiocb *target_req),
 
-       TP_ARGS(ctx, req, target_req),
+       TP_ARGS(req, target_req),
 
        TP_STRUCT__entry (
                __field(  void *,       ctx             )
@@ -244,7 +233,7 @@ TRACE_EVENT(io_uring_link,
        ),
 
        TP_fast_assign(
-               __entry->ctx            = ctx;
+               __entry->ctx            = req->ctx;
                __entry->req            = req;
                __entry->target_req     = target_req;
        ),
@@ -285,10 +274,7 @@ TRACE_EVENT(io_uring_cqring_wait,
 /**
  * io_uring_fail_link - called before failing a linked request
  *
- * @ctx:       pointer to a ring context structure
  * @req:       request, which links were cancelled
- * @user_data: user data associated with the request
- * @opcode:    opcode of request
  * @link:      cancelled link
  *
  * Allows to track linked requests cancellation, to see not only that some work
@@ -296,9 +282,9 @@ TRACE_EVENT(io_uring_cqring_wait,
  */
 TRACE_EVENT(io_uring_fail_link,
 
-       TP_PROTO(void *ctx, void *req, unsigned long long user_data, u8 opcode, void *link),
+       TP_PROTO(struct io_kiocb *req, struct io_kiocb *link),
 
-       TP_ARGS(ctx, req, user_data, opcode, link),
+       TP_ARGS(req, link),
 
        TP_STRUCT__entry (
                __field(  void *,               ctx             )
@@ -307,17 +293,17 @@ TRACE_EVENT(io_uring_fail_link,
                __field(  u8,                   opcode          )
                __field(  void *,               link            )
 
-               __string( op_str, io_uring_get_opcode(opcode) )
+               __string( op_str, io_uring_get_opcode(req->opcode) )
        ),
 
        TP_fast_assign(
-               __entry->ctx            = ctx;
+               __entry->ctx            = req->ctx;
                __entry->req            = req;
-               __entry->user_data      = user_data;
-               __entry->opcode         = opcode;
+               __entry->user_data      = req->cqe.user_data;
+               __entry->opcode         = req->opcode;
                __entry->link           = link;
 
-               __assign_str(op_str, io_uring_get_opcode(opcode));
+               __assign_str(op_str, io_uring_get_opcode(req->opcode));
        ),
 
        TP_printk("ring %p, request %p, user_data 0x%llx, opcode %s, link %p",
@@ -376,23 +362,17 @@ TRACE_EVENT(io_uring_complete,
 /**
  * io_uring_submit_sqe - called before submitting one SQE
  *
- * @ctx:               pointer to a ring context structure
  * @req:               pointer to a submitted request
- * @user_data:         user data associated with the request
- * @opcode:            opcode of request
- * @flags              request flags
  * @force_nonblock:    whether a context blocking or not
- * @sq_thread:         true if sq_thread has submitted this SQE
  *
  * Allows to track SQE submitting, to understand what was the source of it, SQ
  * thread or io_uring_enter call.
  */
 TRACE_EVENT(io_uring_submit_sqe,
 
-       TP_PROTO(void *ctx, void *req, unsigned long long user_data, u8 opcode, u32 flags,
-                bool force_nonblock, bool sq_thread),
+       TP_PROTO(struct io_kiocb *req, bool force_nonblock),
 
-       TP_ARGS(ctx, req, user_data, opcode, flags, force_nonblock, sq_thread),
+       TP_ARGS(req, force_nonblock),
 
        TP_STRUCT__entry (
                __field(  void *,               ctx             )
@@ -403,19 +383,19 @@ TRACE_EVENT(io_uring_submit_sqe,
                __field(  bool,                 force_nonblock  )
                __field(  bool,                 sq_thread       )
 
-               __string( op_str, io_uring_get_opcode(opcode) )
+               __string( op_str, io_uring_get_opcode(req->opcode) )
        ),
 
        TP_fast_assign(
-               __entry->ctx            = ctx;
+               __entry->ctx            = req->ctx;
                __entry->req            = req;
-               __entry->user_data      = user_data;
-               __entry->opcode         = opcode;
-               __entry->flags          = flags;
+               __entry->user_data      = req->cqe.user_data;
+               __entry->opcode         = req->opcode;
+               __entry->flags          = req->flags;
                __entry->force_nonblock = force_nonblock;
-               __entry->sq_thread      = sq_thread;
+               __entry->sq_thread      = req->ctx->flags & IORING_SETUP_SQPOLL;
 
-               __assign_str(op_str, io_uring_get_opcode(opcode));
+               __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, "
@@ -427,10 +407,7 @@ TRACE_EVENT(io_uring_submit_sqe,
 /*
  * io_uring_poll_arm - called after arming a poll wait if successful
  *
- * @ctx:               pointer to a ring context structure
  * @req:               pointer to the armed request
- * @user_data:         user data associated with the request
- * @opcode:            opcode of request
  * @mask:              request poll events mask
  * @events:            registered events of interest
  *
@@ -439,10 +416,9 @@ TRACE_EVENT(io_uring_submit_sqe,
  */
 TRACE_EVENT(io_uring_poll_arm,
 
-       TP_PROTO(void *ctx, void *req, u64 user_data, u8 opcode,
-                int mask, int events),
+       TP_PROTO(struct io_kiocb *req, int mask, int events),
 
-       TP_ARGS(ctx, req, user_data, opcode, mask, events),
+       TP_ARGS(req, mask, events),
 
        TP_STRUCT__entry (
                __field(  void *,               ctx             )
@@ -452,18 +428,18 @@ TRACE_EVENT(io_uring_poll_arm,
                __field(  int,                  mask            )
                __field(  int,                  events          )
 
-               __string( op_str, io_uring_get_opcode(opcode) )
+               __string( op_str, io_uring_get_opcode(req->opcode) )
        ),
 
        TP_fast_assign(
-               __entry->ctx            = ctx;
+               __entry->ctx            = req->ctx;
                __entry->req            = req;
-               __entry->user_data      = user_data;
-               __entry->opcode         = opcode;
+               __entry->user_data      = req->cqe.user_data;
+               __entry->opcode         = req->opcode;
                __entry->mask           = mask;
                __entry->events         = events;
 
-               __assign_str(op_str, io_uring_get_opcode(opcode));
+               __assign_str(op_str, io_uring_get_opcode(req->opcode));
        ),
 
        TP_printk("ring %p, req %p, user_data 0x%llx, opcode %s, mask 0x%x, events 0x%x",
@@ -475,18 +451,15 @@ TRACE_EVENT(io_uring_poll_arm,
 /*
  * io_uring_task_add - called after adding a task
  *
- * @ctx:               pointer to a ring context structure
  * @req:               pointer to request
- * @user_data:         user data associated with the request
- * @opcode:            opcode of request
  * @mask:              request poll events mask
  *
  */
 TRACE_EVENT(io_uring_task_add,
 
-       TP_PROTO(void *ctx, void *req, unsigned long long user_data, u8 opcode, int mask),
+       TP_PROTO(struct io_kiocb *req, int mask),
 
-       TP_ARGS(ctx, req, user_data, opcode, mask),
+       TP_ARGS(req, mask),
 
        TP_STRUCT__entry (
                __field(  void *,               ctx             )
@@ -495,17 +468,17 @@ TRACE_EVENT(io_uring_task_add,
                __field(  u8,                   opcode          )
                __field(  int,                  mask            )
 
-               __string( op_str, io_uring_get_opcode(opcode) )
+               __string( op_str, io_uring_get_opcode(req->opcode) )
        ),
 
        TP_fast_assign(
-               __entry->ctx            = ctx;
+               __entry->ctx            = req->ctx;
                __entry->req            = req;
-               __entry->user_data      = user_data;
-               __entry->opcode         = opcode;
+               __entry->user_data      = req->cqe.user_data;
+               __entry->opcode         = req->opcode;
                __entry->mask           = mask;
 
-               __assign_str(op_str, io_uring_get_opcode(opcode));
+               __assign_str(op_str, io_uring_get_opcode(req->opcode));
        ),
 
        TP_printk("ring %p, req %p, user_data 0x%llx, opcode %s, mask %x",
@@ -518,7 +491,6 @@ TRACE_EVENT(io_uring_task_add,
  * io_uring_req_failed - called when an sqe is errored dring submission
  *
  * @sqe:               pointer to the io_uring_sqe that failed
- * @ctx:               pointer to a ring context structure
  * @req:               pointer to request
  * @error:             error it failed with
  *
@@ -526,9 +498,9 @@ TRACE_EVENT(io_uring_task_add,
  */
 TRACE_EVENT(io_uring_req_failed,
 
-       TP_PROTO(const struct io_uring_sqe *sqe, void *ctx, void *req, int error),
+       TP_PROTO(const struct io_uring_sqe *sqe, struct io_kiocb *req, int error),
 
-       TP_ARGS(sqe, ctx, req, error),
+       TP_ARGS(sqe, req, error),
 
        TP_STRUCT__entry (
                __field(  void *,               ctx             )
@@ -552,7 +524,7 @@ TRACE_EVENT(io_uring_req_failed,
        ),
 
        TP_fast_assign(
-               __entry->ctx            = ctx;
+               __entry->ctx            = req->ctx;
                __entry->req            = req;
                __entry->user_data      = sqe->user_data;
                __entry->opcode         = sqe->opcode;
@@ -622,12 +594,67 @@ TRACE_EVENT(io_uring_cqe_overflow,
                __entry->ocqe           = ocqe;
        ),
 
-       TP_printk("ring %p, user_data 0x%llx, res %d, flags %x, "
+       TP_printk("ring %p, user_data 0x%llx, res %d, cflags 0x%x, "
                  "overflow_cqe %p",
                  __entry->ctx, __entry->user_data, __entry->res,
                  __entry->cflags, __entry->ocqe)
 );
 
+/*
+ * io_uring_task_work_run - ran task work
+ *
+ * @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_ARGS(tctx, count, loops),
+
+       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)
+);
+
+TRACE_EVENT(io_uring_short_write,
+
+       TP_PROTO(void *ctx, u64 fpos, u64 wanted, u64 got),
+
+       TP_ARGS(ctx, fpos, wanted, got),
+
+       TP_STRUCT__entry(
+               __field(void *, ctx)
+               __field(u64,    fpos)
+               __field(u64,    wanted)
+               __field(u64,    got)
+       ),
+
+       TP_fast_assign(
+               __entry->ctx    = ctx;
+               __entry->fpos   = fpos;
+               __entry->wanted = wanted;
+               __entry->got    = got;
+       ),
+
+       TP_printk("ring %p, fpos %lld, wanted %lld, got %lld",
+                         __entry->ctx, __entry->fpos,
+                         __entry->wanted, __entry->got)
+);
+
 #endif /* _TRACE_IO_URING_H */
 
 /* This part must be outside protection */
index e282ce0..6d1626e 100644 (file)
@@ -160,7 +160,7 @@ TRACE_EVENT(iocost_ioc_vrate_adj,
 
        TP_fast_assign(
                __assign_str(devname, ioc_name(ioc));
-               __entry->old_vrate = atomic64_read(&ioc->vtime_rate);;
+               __entry->old_vrate = atomic64_read(&ioc->vtime_rate);
                __entry->new_vrate = new_vrate;
                __entry->busy_level = ioc->busy_level;
                __entry->read_missed_ppm = missed_ppm[READ];
index a4dfe00..99f783c 100644 (file)
@@ -355,22 +355,22 @@ TRACE_EVENT(jbd2_update_log_tail,
 
 TRACE_EVENT(jbd2_write_superblock,
 
-       TP_PROTO(journal_t *journal, int write_op),
+       TP_PROTO(journal_t *journal, blk_opf_t write_flags),
 
-       TP_ARGS(journal, write_op),
+       TP_ARGS(journal, write_flags),
 
        TP_STRUCT__entry(
                __field(        dev_t,  dev                     )
-               __field(          int,  write_op                )
+               __field(    blk_opf_t,  write_flags             )
        ),
 
        TP_fast_assign(
                __entry->dev            = journal->j_fs_dev->bd_dev;
-               __entry->write_op       = write_op;
+               __entry->write_flags    = write_flags;
        ),
 
-       TP_printk("dev %d,%d write_op %x", MAJOR(__entry->dev),
-                 MINOR(__entry->dev), __entry->write_op)
+       TP_printk("dev %d,%d write_flags %x", MAJOR(__entry->dev),
+                 MINOR(__entry->dev), (__force u32)__entry->write_flags)
 );
 
 TRACE_EVENT(jbd2_lock_buffer_stall,
index f766683..4cb51ac 100644 (file)
@@ -13,11 +13,12 @@ DECLARE_EVENT_CLASS(kmem_alloc,
 
        TP_PROTO(unsigned long call_site,
                 const void *ptr,
+                struct kmem_cache *s,
                 size_t bytes_req,
                 size_t bytes_alloc,
                 gfp_t gfp_flags),
 
-       TP_ARGS(call_site, ptr, bytes_req, bytes_alloc, gfp_flags),
+       TP_ARGS(call_site, ptr, s, bytes_req, bytes_alloc, gfp_flags),
 
        TP_STRUCT__entry(
                __field(        unsigned long,  call_site       )
@@ -25,6 +26,7 @@ DECLARE_EVENT_CLASS(kmem_alloc,
                __field(        size_t,         bytes_req       )
                __field(        size_t,         bytes_alloc     )
                __field(        unsigned long,  gfp_flags       )
+               __field(        bool,           accounted       )
        ),
 
        TP_fast_assign(
@@ -33,42 +35,47 @@ DECLARE_EVENT_CLASS(kmem_alloc,
                __entry->bytes_req      = bytes_req;
                __entry->bytes_alloc    = bytes_alloc;
                __entry->gfp_flags      = (__force unsigned long)gfp_flags;
+               __entry->accounted      = IS_ENABLED(CONFIG_MEMCG_KMEM) ?
+                                         ((gfp_flags & __GFP_ACCOUNT) ||
+                                         (s && s->flags & SLAB_ACCOUNT)) : false;
        ),
 
-       TP_printk("call_site=%pS ptr=%p bytes_req=%zu bytes_alloc=%zu gfp_flags=%s",
+       TP_printk("call_site=%pS ptr=%p bytes_req=%zu bytes_alloc=%zu gfp_flags=%s accounted=%s",
                (void *)__entry->call_site,
                __entry->ptr,
                __entry->bytes_req,
                __entry->bytes_alloc,
-               show_gfp_flags(__entry->gfp_flags))
+               show_gfp_flags(__entry->gfp_flags),
+               __entry->accounted ? "true" : "false")
 );
 
 DEFINE_EVENT(kmem_alloc, kmalloc,
 
-       TP_PROTO(unsigned long call_site, const void *ptr,
+       TP_PROTO(unsigned long call_site, const void *ptr, struct kmem_cache *s,
                 size_t bytes_req, size_t bytes_alloc, gfp_t gfp_flags),
 
-       TP_ARGS(call_site, ptr, bytes_req, bytes_alloc, gfp_flags)
+       TP_ARGS(call_site, ptr, s, bytes_req, bytes_alloc, gfp_flags)
 );
 
 DEFINE_EVENT(kmem_alloc, kmem_cache_alloc,
 
-       TP_PROTO(unsigned long call_site, const void *ptr,
+       TP_PROTO(unsigned long call_site, const void *ptr, struct kmem_cache *s,
                 size_t bytes_req, size_t bytes_alloc, gfp_t gfp_flags),
 
-       TP_ARGS(call_site, ptr, bytes_req, bytes_alloc, gfp_flags)
+       TP_ARGS(call_site, ptr, s, bytes_req, bytes_alloc, gfp_flags)
 );
 
 DECLARE_EVENT_CLASS(kmem_alloc_node,
 
        TP_PROTO(unsigned long call_site,
                 const void *ptr,
+                struct kmem_cache *s,
                 size_t bytes_req,
                 size_t bytes_alloc,
                 gfp_t gfp_flags,
                 int node),
 
-       TP_ARGS(call_site, ptr, bytes_req, bytes_alloc, gfp_flags, node),
+       TP_ARGS(call_site, ptr, s, bytes_req, bytes_alloc, gfp_flags, node),
 
        TP_STRUCT__entry(
                __field(        unsigned long,  call_site       )
@@ -77,6 +84,7 @@ DECLARE_EVENT_CLASS(kmem_alloc_node,
                __field(        size_t,         bytes_alloc     )
                __field(        unsigned long,  gfp_flags       )
                __field(        int,            node            )
+               __field(        bool,           accounted       )
        ),
 
        TP_fast_assign(
@@ -86,33 +94,37 @@ DECLARE_EVENT_CLASS(kmem_alloc_node,
                __entry->bytes_alloc    = bytes_alloc;
                __entry->gfp_flags      = (__force unsigned long)gfp_flags;
                __entry->node           = node;
+               __entry->accounted      = IS_ENABLED(CONFIG_MEMCG_KMEM) ?
+                                         ((gfp_flags & __GFP_ACCOUNT) ||
+                                         (s && s->flags & SLAB_ACCOUNT)) : false;
        ),
 
-       TP_printk("call_site=%pS ptr=%p bytes_req=%zu bytes_alloc=%zu gfp_flags=%s node=%d",
+       TP_printk("call_site=%pS ptr=%p bytes_req=%zu bytes_alloc=%zu gfp_flags=%s node=%d accounted=%s",
                (void *)__entry->call_site,
                __entry->ptr,
                __entry->bytes_req,
                __entry->bytes_alloc,
                show_gfp_flags(__entry->gfp_flags),
-               __entry->node)
+               __entry->node,
+               __entry->accounted ? "true" : "false")
 );
 
 DEFINE_EVENT(kmem_alloc_node, kmalloc_node,
 
        TP_PROTO(unsigned long call_site, const void *ptr,
-                size_t bytes_req, size_t bytes_alloc,
+                struct kmem_cache *s, size_t bytes_req, size_t bytes_alloc,
                 gfp_t gfp_flags, int node),
 
-       TP_ARGS(call_site, ptr, bytes_req, bytes_alloc, gfp_flags, node)
+       TP_ARGS(call_site, ptr, s, bytes_req, bytes_alloc, gfp_flags, node)
 );
 
 DEFINE_EVENT(kmem_alloc_node, kmem_cache_alloc_node,
 
        TP_PROTO(unsigned long call_site, const void *ptr,
-                size_t bytes_req, size_t bytes_alloc,
+                struct kmem_cache *s, size_t bytes_req, size_t bytes_alloc,
                 gfp_t gfp_flags, int node),
 
-       TP_ARGS(call_site, ptr, bytes_req, bytes_alloc, gfp_flags, node)
+       TP_ARGS(call_site, ptr, s, bytes_req, bytes_alloc, gfp_flags, node)
 );
 
 TRACE_EVENT(kfree,
index 84ee31f..8efc623 100644 (file)
@@ -192,7 +192,7 @@ TRACE_EVENT(nilfs2_mdt_submit_block,
            TP_PROTO(struct inode *inode,
                     unsigned long ino,
                     unsigned long blkoff,
-                    int mode),
+                    enum req_op mode),
 
            TP_ARGS(inode, ino, blkoff, mode),
 
@@ -200,7 +200,7 @@ TRACE_EVENT(nilfs2_mdt_submit_block,
                    __field(struct inode *, inode)
                    __field(unsigned long, ino)
                    __field(unsigned long, blkoff)
-                   __field(int, mode)
+                   __field(enum req_op, mode)
            ),
 
            TP_fast_assign(
index af5018a..c708521 100644 (file)
@@ -500,6 +500,35 @@ DEFINE_EVENT(dev_pm_qos_request, dev_pm_qos_remove_request,
 
        TP_ARGS(name, type, new_value)
 );
+
+TRACE_EVENT(guest_halt_poll_ns,
+
+       TP_PROTO(bool grow, unsigned int new, unsigned int old),
+
+       TP_ARGS(grow, new, old),
+
+       TP_STRUCT__entry(
+               __field(bool, grow)
+               __field(unsigned int, new)
+               __field(unsigned int, old)
+       ),
+
+       TP_fast_assign(
+               __entry->grow   = grow;
+               __entry->new    = new;
+               __entry->old    = old;
+       ),
+
+       TP_printk("halt_poll_ns %u (%s %u)",
+               __entry->new,
+               __entry->grow ? "grow" : "shrink",
+               __entry->old)
+);
+
+#define trace_guest_halt_poll_ns_grow(new, old) \
+       trace_guest_halt_poll_ns(true, new, old)
+#define trace_guest_halt_poll_ns_shrink(new, old) \
+       trace_guest_halt_poll_ns(false, new, old)
 #endif /* _TRACE_POWER_H */
 
 /* This part must be outside protection */
index cee4b2b..65016a7 100644 (file)
@@ -7,6 +7,31 @@
 
 #include <linux/tracepoint.h>
 
+TRACE_EVENT(scmi_fc_call,
+       TP_PROTO(u8 protocol_id, u8 msg_id, u32 res_id, u32 val1, u32 val2),
+       TP_ARGS(protocol_id, msg_id, res_id, val1, val2),
+
+       TP_STRUCT__entry(
+               __field(u8, protocol_id)
+               __field(u8, msg_id)
+               __field(u32, res_id)
+               __field(u32, val1)
+               __field(u32, val2)
+       ),
+
+       TP_fast_assign(
+               __entry->protocol_id = protocol_id;
+               __entry->msg_id = msg_id;
+               __entry->res_id = res_id;
+               __entry->val1 = val1;
+               __entry->val2 = val2;
+       ),
+
+       TP_printk("[0x%02X]:[0x%02X]:[%08X]:%u:%u",
+                 __entry->protocol_id, __entry->msg_id,
+                 __entry->res_id, __entry->val1, __entry->val2)
+);
+
 TRACE_EVENT(scmi_xfer_begin,
        TP_PROTO(int transfer_id, u8 msg_id, u8 protocol_id, u16 seq,
                 bool poll),
@@ -112,6 +137,37 @@ TRACE_EVENT(scmi_rx_done,
                __entry->transfer_id, __entry->msg_id, __entry->protocol_id,
                __entry->seq, __entry->msg_type)
 );
+
+TRACE_EVENT(scmi_msg_dump,
+       TP_PROTO(u8 protocol_id, u8 msg_id, unsigned char *tag, u16 seq,
+                int status, void *buf, size_t len),
+       TP_ARGS(protocol_id, msg_id, tag, seq, status, buf, len),
+
+       TP_STRUCT__entry(
+               __field(u8, protocol_id)
+               __field(u8, msg_id)
+               __array(char, tag, 5)
+               __field(u16, seq)
+               __field(int, status)
+               __field(size_t, len)
+               __dynamic_array(unsigned char, cmd, len)
+       ),
+
+       TP_fast_assign(
+               __entry->protocol_id = protocol_id;
+               __entry->msg_id = msg_id;
+               strscpy(__entry->tag, tag, 5);
+               __entry->seq = seq;
+               __entry->status = status;
+               __entry->len = len;
+               memcpy(__get_dynamic_array(cmd), buf, __entry->len);
+       ),
+
+       TP_printk("pt=%02X t=%s msg_id=%02X seq=%04X s=%d pyld=%s",
+                 __entry->protocol_id, __entry->tag, __entry->msg_id,
+                 __entry->seq, __entry->status,
+               __print_hex_str(__get_dynamic_array(cmd), __entry->len))
+);
 #endif /* _TRACE_SCMI_H */
 
 /* This part must be outside protection */
index 12c3157..777ee6c 100644 (file)
@@ -98,7 +98,7 @@ TRACE_EVENT(sock_exceed_buf_limit,
 
        TP_STRUCT__entry(
                __array(char, name, 32)
-               __field(long *, sysctl_mem)
+               __array(long, sysctl_mem, 3)
                __field(long, allocated)
                __field(int, sysctl_rmem)
                __field(int, rmem_alloc)
@@ -110,7 +110,9 @@ TRACE_EVENT(sock_exceed_buf_limit,
 
        TP_fast_assign(
                strncpy(__entry->name, prot->name, 32);
-               __entry->sysctl_mem = prot->sysctl_mem;
+               __entry->sysctl_mem[0] = READ_ONCE(prot->sysctl_mem[0]);
+               __entry->sysctl_mem[1] = READ_ONCE(prot->sysctl_mem[1]);
+               __entry->sysctl_mem[2] = READ_ONCE(prot->sysctl_mem[2]);
                __entry->allocated = allocated;
                __entry->sysctl_rmem = sk_get_rmem0(sk, prot);
                __entry->rmem_alloc = atomic_read(&sk->sk_rmem_alloc);
index 8a5f048..e58bf30 100644 (file)
@@ -92,34 +92,22 @@ TRACE_EVENT(thermal_zone_trip,
 );
 
 #ifdef CONFIG_CPU_THERMAL
-TRACE_EVENT(thermal_power_cpu_get_power,
-       TP_PROTO(const struct cpumask *cpus, unsigned long freq, u32 *load,
-               size_t load_len, u32 dynamic_power),
+TRACE_EVENT(thermal_power_cpu_get_power_simple,
+       TP_PROTO(int cpu, u32 power),
 
-       TP_ARGS(cpus, freq, load, load_len, dynamic_power),
+       TP_ARGS(cpupower),
 
        TP_STRUCT__entry(
-               __bitmask(cpumask, num_possible_cpus())
-               __field(unsigned long, freq          )
-               __dynamic_array(u32,   load, load_len)
-               __field(size_t,        load_len      )
-               __field(u32,           dynamic_power )
+               __field(int, cpu)
+               __field(u32, power)
        ),
 
        TP_fast_assign(
-               __assign_bitmask(cpumask, cpumask_bits(cpus),
-                               num_possible_cpus());
-               __entry->freq = freq;
-               memcpy(__get_dynamic_array(load), load,
-                       load_len * sizeof(*load));
-               __entry->load_len = load_len;
-               __entry->dynamic_power = dynamic_power;
+               __entry->cpu = cpu;
+               __entry->power = power;
        ),
 
-       TP_printk("cpus=%s freq=%lu load={%s} dynamic_power=%d",
-               __get_bitmask(cpumask), __entry->freq,
-               __print_array(__get_dynamic_array(load), __entry->load_len, 4),
-               __entry->dynamic_power)
+       TP_printk("cpu=%d power=%u", __entry->cpu, __entry->power)
 );
 
 TRACE_EVENT(thermal_power_cpu_limit,
index f13d37b..1ecdb91 100644 (file)
@@ -192,6 +192,7 @@ struct f_owner_ex {
 
 #define F_LINUX_SPECIFIC_BASE  1024
 
+#ifndef HAVE_ARCH_STRUCT_FLOCK
 struct flock {
        short   l_type;
        short   l_whence;
@@ -216,5 +217,6 @@ struct flock64 {
        __ARCH_FLOCK64_PAD
 #endif
 };
+#endif /* HAVE_ARCH_STRUCT_FLOCK */
 
 #endif /* _ASM_GENERIC_FCNTL_H */
index f197215..0980678 100644 (file)
@@ -1444,11 +1444,11 @@ drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier)
 #define AMD_FMT_MOD_PIPE_MASK 0x7
 
 #define AMD_FMT_MOD_SET(field, value) \
-       ((uint64_t)(value) << AMD_FMT_MOD_##field##_SHIFT)
+       ((__u64)(value) << AMD_FMT_MOD_##field##_SHIFT)
 #define AMD_FMT_MOD_GET(field, value) \
        (((value) >> AMD_FMT_MOD_##field##_SHIFT) & AMD_FMT_MOD_##field##_MASK)
 #define AMD_FMT_MOD_CLEAR(field) \
-       (~((uint64_t)AMD_FMT_MOD_##field##_MASK << AMD_FMT_MOD_##field##_SHIFT))
+       (~((__u64)AMD_FMT_MOD_##field##_MASK << AMD_FMT_MOD_##field##_SHIFT))
 
 #if defined(__cplusplus)
 }
index a2def7b..b28ff5d 100644 (file)
@@ -2123,7 +2123,7 @@ struct i915_context_engines_load_balance {
 
        __u64 mbz64; /* reserved for future use; must be zero */
 
-       struct i915_engine_class_instance engines[0];
+       struct i915_engine_class_instance engines[];
 } __attribute__((packed));
 
 #define I915_DEFINE_CONTEXT_ENGINES_LOAD_BALANCE(name__, N__) struct { \
@@ -2161,7 +2161,7 @@ struct i915_context_engines_bond {
        __u64 flags; /* all undefined flags must be zero */
        __u64 mbz64[4]; /* reserved for future use; must be zero */
 
-       struct i915_engine_class_instance engines[0];
+       struct i915_engine_class_instance engines[];
 } __attribute__((packed));
 
 #define I915_DEFINE_CONTEXT_ENGINES_BOND(name__, N__) struct { \
@@ -2288,7 +2288,7 @@ struct i915_context_engines_parallel_submit {
         * length = width (i) * num_siblings (j)
         * index = j + i * num_siblings
         */
-       struct i915_engine_class_instance engines[0];
+       struct i915_engine_class_instance engines[];
 
 } __packed;
 
index 656a326..b80fcc9 100644 (file)
@@ -130,7 +130,7 @@ struct blk_zone_report {
        __u64           sector;
        __u32           nr_zones;
        __u32           flags;
-       struct blk_zone zones[0];
+       struct blk_zone zones[];
 };
 
 /**
index f4009db..ff225aa 100644 (file)
@@ -79,7 +79,7 @@ struct bpf_insn {
 /* Key of an a BPF_MAP_TYPE_LPM_TRIE entry */
 struct bpf_lpm_trie_key {
        __u32   prefixlen;      /* up to 32 for AF_INET, 128 for AF_INET6 */
-       __u8    data[0];        /* Arbitrary size */
+       __u8    data[]; /* Arbitrary size */
 };
 
 struct bpf_cgroup_storage_key {
@@ -5222,22 +5222,25 @@ union bpf_attr {
  *     Return
  *             Nothing. Always succeeds.
  *
- * long bpf_dynptr_read(void *dst, u32 len, struct bpf_dynptr *src, u32 offset)
+ * long bpf_dynptr_read(void *dst, u32 len, struct bpf_dynptr *src, u32 offset, u64 flags)
  *     Description
  *             Read *len* bytes from *src* into *dst*, starting from *offset*
  *             into *src*.
+ *             *flags* is currently unused.
  *     Return
  *             0 on success, -E2BIG if *offset* + *len* exceeds the length
- *             of *src*'s data, -EINVAL if *src* is an invalid dynptr.
+ *             of *src*'s data, -EINVAL if *src* is an invalid dynptr or if
+ *             *flags* is not 0.
  *
- * long bpf_dynptr_write(struct bpf_dynptr *dst, u32 offset, void *src, u32 len)
+ * long bpf_dynptr_write(struct bpf_dynptr *dst, u32 offset, void *src, u32 len, u64 flags)
  *     Description
  *             Write *len* bytes from *src* into *dst*, starting from *offset*
  *             into *dst*.
+ *             *flags* is currently unused.
  *     Return
  *             0 on success, -E2BIG if *offset* + *len* exceeds the length
  *             of *dst*'s data, -EINVAL if *dst* is an invalid dynptr or if *dst*
- *             is a read-only dynptr.
+ *             is a read-only dynptr or if *flags* is not 0.
  *
  * void *bpf_dynptr_data(struct bpf_dynptr *ptr, u32 offset, u32 len)
  *     Description
index d956b29..3d0edbe 100644 (file)
@@ -93,7 +93,7 @@ struct btrfs_qgroup_inherit {
        __u64   num_ref_copies;
        __u64   num_excl_copies;
        struct btrfs_qgroup_limit lim;
-       __u64   qgroups[0];
+       __u64   qgroups[];
 };
 
 struct btrfs_ioctl_qgroup_limit_args {
@@ -561,7 +561,7 @@ struct btrfs_ioctl_search_args_v2 {
        __u64 buf_size;            /* in - size of buffer
                                            * out - on EOVERFLOW: needed size
                                            *       to store item */
-       __u64 buf[0];                       /* out - found items */
+       __u64 buf[];                       /* out - found items */
 };
 
 struct btrfs_ioctl_clone_range_args {
@@ -632,7 +632,7 @@ struct btrfs_ioctl_same_args {
        __u16 dest_count;       /* in - total elements in info array */
        __u16 reserved1;
        __u32 reserved2;
-       struct btrfs_ioctl_same_extent_info info[0];
+       struct btrfs_ioctl_same_extent_info info[];
 };
 
 struct btrfs_ioctl_space_info {
@@ -644,7 +644,7 @@ struct btrfs_ioctl_space_info {
 struct btrfs_ioctl_space_args {
        __u64 space_slots;
        __u64 total_spaces;
-       struct btrfs_ioctl_space_info spaces[0];
+       struct btrfs_ioctl_space_info spaces[];
 };
 
 struct btrfs_data_container {
@@ -652,7 +652,7 @@ struct btrfs_data_container {
        __u32   bytes_missing;  /* out -- additional bytes needed for result */
        __u32   elem_cnt;       /* out */
        __u32   elem_missed;    /* out */
-       __u64   val[0];         /* out */
+       __u64   val[];          /* out */
 };
 
 struct btrfs_ioctl_ino_path_args {
index d411715..5f32a2a 100644 (file)
@@ -575,7 +575,7 @@ struct btrfs_inode_extref {
        __le64 parent_objectid;
        __le64 index;
        __le16 name_len;
-       __u8   name[0];
+       __u8   name[];
        /* name goes here */
 } __attribute__ ((__packed__));
 
index dd2b925..f1e45f5 100644 (file)
@@ -71,7 +71,7 @@ struct bcm_msg_head {
        struct bcm_timeval ival1, ival2;
        canid_t can_id;
        __u32 nframes;
-       struct can_frame frames[0];
+       struct can_frame frames[];
 };
 
 enum {
index 3738936..5ae131c 100644 (file)
@@ -75,7 +75,7 @@ struct cn_msg {
 
        __u16 len;              /* Length of the following data */
        __u16 flags;
-       __u8 data[0];
+       __u8 data[];
 };
 
 #endif /* _UAPI__CONNECTOR_H */
index 51f5419..91778c8 100644 (file)
@@ -91,7 +91,7 @@ struct cycx_firmware {
        unsigned short      reserved[6];
        char                descr[CFM_DESCR_LEN];
        struct cycx_fw_info info;
-       unsigned char       image[0];
+       unsigned char       image[];
 };
 
 struct cycx_fw_header {
index 2e9550f..7edf335 100644 (file)
@@ -182,7 +182,7 @@ struct dm_target_spec {
 struct dm_target_deps {
        __u32 count;    /* Array size */
        __u32 padding;  /* unused */
-       __u64 dev[0];   /* out */
+       __u64 dev[];    /* out */
 };
 
 /*
@@ -192,7 +192,7 @@ struct dm_name_list {
        __u64 dev;
        __u32 next;             /* offset to the next record from
                                   the _start_ of this */
-       char name[0];
+       char name[];
 
        /*
         * The following members can be accessed by taking a pointer that
@@ -216,7 +216,7 @@ struct dm_target_versions {
         __u32 next;
         __u32 version[3];
 
-        char name[0];
+        char name[];
 };
 
 /*
@@ -225,7 +225,7 @@ struct dm_target_versions {
 struct dm_target_msg {
        __u64 sector;   /* Device sector */
 
-       char message[0];
+       char message[];
 };
 
 /*
@@ -286,9 +286,9 @@ enum {
 #define DM_DEV_SET_GEOMETRY    _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
 
 #define DM_VERSION_MAJOR       4
-#define DM_VERSION_MINOR       46
+#define DM_VERSION_MINOR       47
 #define DM_VERSION_PATCHLEVEL  0
-#define DM_VERSION_EXTRA       "-ioctl (2022-02-22)"
+#define DM_VERSION_EXTRA       "-ioctl (2022-07-28)"
 
 /* Status bits */
 #define DM_READONLY_FLAG       (1 << 0) /* In/Out */
index 5c47a86..23dad95 100644 (file)
@@ -426,7 +426,7 @@ struct dm_ulog_request {
        __u32 request_type;  /* DM_ULOG_* defined above */
        __u32 data_size;     /* How much data (not including this struct) */
 
-       char data[0];
+       char data[];
 };
 
 #endif /* __DM_LOG_USERSPACE_H__ */
index e0f0ee9..2d5741f 100644 (file)
@@ -257,7 +257,7 @@ struct ethtool_tunable {
        __u32   id;
        __u32   type_id;
        __u32   len;
-       void    *data[0];
+       void    *data[];
 };
 
 #define DOWNSHIFT_DEV_DEFAULT_COUNT    0xff
@@ -322,7 +322,7 @@ struct ethtool_regs {
        __u32   cmd;
        __u32   version;
        __u32   len;
-       __u8    data[0];
+       __u8    data[];
 };
 
 /**
@@ -348,7 +348,7 @@ struct ethtool_eeprom {
        __u32   magic;
        __u32   offset;
        __u32   len;
-       __u8    data[0];
+       __u8    data[];
 };
 
 /**
@@ -752,7 +752,7 @@ struct ethtool_gstrings {
        __u32   cmd;
        __u32   string_set;
        __u32   len;
-       __u8    data[0];
+       __u8    data[];
 };
 
 /**
@@ -777,7 +777,7 @@ struct ethtool_sset_info {
        __u32   cmd;
        __u32   reserved;
        __u64   sset_mask;
-       __u32   data[0];
+       __u32   data[];
 };
 
 /**
@@ -817,7 +817,7 @@ struct ethtool_test {
        __u32   flags;
        __u32   reserved;
        __u32   len;
-       __u64   data[0];
+       __u64   data[];
 };
 
 /**
@@ -834,7 +834,7 @@ struct ethtool_test {
 struct ethtool_stats {
        __u32   cmd;
        __u32   n_stats;
-       __u64   data[0];
+       __u64   data[];
 };
 
 /**
@@ -851,7 +851,7 @@ struct ethtool_stats {
 struct ethtool_perm_addr {
        __u32   cmd;
        __u32   size;
-       __u8    data[0];
+       __u8    data[];
 };
 
 /* boolean flags controlling per-interface behavior characteristics.
@@ -1160,7 +1160,7 @@ struct ethtool_rxnfc {
 struct ethtool_rxfh_indir {
        __u32   cmd;
        __u32   size;
-       __u32   ring_index[0];
+       __u32   ring_index[];
 };
 
 /**
@@ -1201,7 +1201,7 @@ struct ethtool_rxfh {
        __u8    hfunc;
        __u8    rsvd8[3];
        __u32   rsvd32;
-       __u32   rss_config[0];
+       __u32   rss_config[];
 };
 #define ETH_RXFH_CONTEXT_ALLOC         0xffffffff
 #define ETH_RXFH_INDIR_NO_CHANGE       0xffffffff
@@ -1286,7 +1286,7 @@ struct ethtool_dump {
        __u32   version;
        __u32   flag;
        __u32   len;
-       __u8    data[0];
+       __u8    data[];
 };
 
 #define ETH_FW_DUMP_DISABLE 0
@@ -1318,7 +1318,7 @@ struct ethtool_get_features_block {
 struct ethtool_gfeatures {
        __u32   cmd;
        __u32   size;
-       struct ethtool_get_features_block features[0];
+       struct ethtool_get_features_block features[];
 };
 
 /**
@@ -1340,7 +1340,7 @@ struct ethtool_set_features_block {
 struct ethtool_sfeatures {
        __u32   cmd;
        __u32   size;
-       struct ethtool_set_features_block features[0];
+       struct ethtool_set_features_block features[];
 };
 
 /**
@@ -2087,7 +2087,7 @@ struct ethtool_link_settings {
        __u8    master_slave_state;
        __u8    reserved1[1];
        __u32   reserved[7];
-       __u32   link_mode_masks[0];
+       __u32   link_mode_masks[];
        /* layout of link_mode_masks fields:
         * __u32 map_supported[link_mode_masks_nwords];
         * __u32 map_advertising[link_mode_masks_nwords];
index f1f8913..4362582 100644 (file)
 #define FAN_MARK_FLUSH         0x00000080
 /* FAN_MARK_FILESYSTEM is      0x00000100 */
 #define FAN_MARK_EVICTABLE     0x00000200
+/* This bit is mutually exclusive with FAN_MARK_IGNORED_MASK bit */
+#define FAN_MARK_IGNORE                0x00000400
 
 /* These are NOT bitwise flags.  Both bits can be used togther.  */
 #define FAN_MARK_INODE         0x00000000
 #define FAN_MARK_MOUNT         0x00000010
 #define FAN_MARK_FILESYSTEM    0x00000100
 
+/*
+ * Convenience macro - FAN_MARK_IGNORE requires FAN_MARK_IGNORED_SURV_MODIFY
+ * for non-inode mark types.
+ */
+#define FAN_MARK_IGNORE_SURV   (FAN_MARK_IGNORE | FAN_MARK_IGNORED_SURV_MODIFY)
+
 /* Deprecated - do not use this in programs and do not add new flags here! */
 #define FAN_ALL_MARK_FLAGS     (FAN_MARK_ADD |\
                                 FAN_MARK_REMOVE |\
@@ -162,7 +170,7 @@ struct fanotify_event_info_fid {
         * Following is an opaque struct file_handle that can be passed as
         * an argument to open_by_handle_at(2).
         */
-       unsigned char handle[0];
+       unsigned char handle[];
 };
 
 /*
index 07c1cdc..24ca0c0 100644 (file)
@@ -34,7 +34,7 @@ struct fiemap {
        __u32 fm_mapped_extents;/* number of extents that were mapped (out) */
        __u32 fm_extent_count;  /* size of fm_extents array (in) */
        __u32 fm_reserved;
-       struct fiemap_extent fm_extents[0]; /* array of mapped extents (out) */
+       struct fiemap_extent fm_extents[]; /* array of mapped extents (out) */
 };
 
 #define FIEMAP_MAX_OFFSET      (~0ULL)
index 5effa98..92be3ea 100644 (file)
@@ -118,7 +118,7 @@ struct fw_cdev_event_response {
        __u32 type;
        __u32 rcode;
        __u32 length;
-       __u32 data[0];
+       __u32 data[];
 };
 
 /**
@@ -142,7 +142,7 @@ struct fw_cdev_event_request {
        __u64 offset;
        __u32 handle;
        __u32 length;
-       __u32 data[0];
+       __u32 data[];
 };
 
 /**
@@ -205,7 +205,7 @@ struct fw_cdev_event_request2 {
        __u32 generation;
        __u32 handle;
        __u32 length;
-       __u32 data[0];
+       __u32 data[];
 };
 
 /**
@@ -265,7 +265,7 @@ struct fw_cdev_event_iso_interrupt {
        __u32 type;
        __u32 cycle;
        __u32 header_length;
-       __u32 header[0];
+       __u32 header[];
 };
 
 /**
@@ -355,7 +355,7 @@ struct fw_cdev_event_phy_packet {
        __u32 type;
        __u32 rcode;
        __u32 length;
-       __u32 data[0];
+       __u32 data[];
 };
 
 /**
@@ -803,7 +803,7 @@ struct fw_cdev_set_iso_channels {
  */
 struct fw_cdev_iso_packet {
        __u32 control;
-       __u32 header[0];
+       __u32 header[];
 };
 
 /**
index bdf7b40..b7b5687 100644 (file)
@@ -90,7 +90,7 @@ struct file_dedupe_range {
        __u16 dest_count;       /* in - total elements in info array */
        __u16 reserved1;        /* must be zero */
        __u32 reserved2;        /* must be zero */
-       struct file_dedupe_range_info info[0];
+       struct file_dedupe_range_info info[];
 };
 
 /* And dynamically-tunable limits and defaults: */
index 9f4428b..a756b29 100644 (file)
@@ -27,7 +27,8 @@
 #define FSCRYPT_MODE_AES_128_CBC               5
 #define FSCRYPT_MODE_AES_128_CTS               6
 #define FSCRYPT_MODE_ADIANTUM                  9
-/* If adding a mode number > 9, update FSCRYPT_MODE_MAX in fscrypt_private.h */
+#define FSCRYPT_MODE_AES_256_HCTR2             10
+/* If adding a mode number > 10, update FSCRYPT_MODE_MAX in fscrypt_private.h */
 
 /*
  * Legacy policy version; ad-hoc KDF and no key verification.
index dc52a11..578b18a 100644 (file)
@@ -42,7 +42,7 @@ struct sockaddr_alg_new {
 
 struct af_alg_iv {
        __u32   ivlen;
-       __u8    iv[0];
+       __u8    iv[];
 };
 
 /* Socket options */
index 6838780..b122cfa 100644 (file)
@@ -60,7 +60,7 @@ struct arc_rfc1201 {
        __u8  proto;            /* protocol ID field - varies           */
        __u8  split_flag;       /* for use with split packets           */
        __be16   sequence;      /* sequence number                      */
-       __u8  payload[0];       /* space remaining in packet (504 bytes)*/
+       __u8  payload[];        /* space remaining in packet (504 bytes)*/
 };
 #define RFC1201_HDR_SIZE 4
 
@@ -69,7 +69,7 @@ struct arc_rfc1201 {
  */
 struct arc_rfc1051 {
        __u8 proto;             /* ARC_P_RFC1051_ARP/RFC1051_IP */
-       __u8 payload[0];        /* 507 bytes                    */
+       __u8 payload[]; /* 507 bytes                    */
 };
 #define RFC1051_HDR_SIZE 1
 
@@ -80,7 +80,7 @@ struct arc_rfc1051 {
 struct arc_eth_encap {
        __u8 proto;             /* Always ARC_P_ETHER                   */
        struct ethhdr eth;      /* standard ethernet header (yuck!)     */
-       __u8 payload[0];        /* 493 bytes                            */
+       __u8 payload[]; /* 493 bytes                            */
 };
 #define ETH_ENCAP_HDR_SIZE 14
 
index e7a693c..9abd80d 100644 (file)
@@ -122,7 +122,7 @@ struct sockaddr_pppol2tpv3in6 {
 struct pppoe_tag {
        __be16 tag_type;
        __be16 tag_len;
-       char tag_data[0];
+       char tag_data[];
 } __attribute__ ((packed));
 
 /* Tag identifiers */
@@ -150,7 +150,7 @@ struct pppoe_hdr {
        __u8 code;
        __be16 sid;
        __be16 length;
-       struct pppoe_tag tag[0];
+       struct pppoe_tag tag[];
 } __packed;
 
 /* Length of entire PPPoE + PPP header */
index 454ae31..2ec07de 100644 (file)
@@ -108,7 +108,7 @@ struct tun_pi {
 struct tun_filter {
        __u16  flags; /* TUN_FLT_ flags see above */
        __u16  count; /* Number of addresses */
-       __u8   addr[0][ETH_ALEN];
+       __u8   addr[][ETH_ALEN];
 };
 
 #endif /* _UAPI__IF_TUN_H */
index 90c28bc..5930f24 100644 (file)
@@ -48,7 +48,7 @@ struct igmpv3_grec {
        __u8    grec_auxwords;
        __be16  grec_nsrcs;
        __be32  grec_mca;
-       __be32  grec_src[0];
+       __be32  grec_src[];
 };
 
 struct igmpv3_report {
@@ -57,7 +57,7 @@ struct igmpv3_report {
        __sum16 csum;
        __be16 resv2;
        __be16 ngrec;
-       struct igmpv3_grec grec[0];
+       struct igmpv3_grec grec[];
 };
 
 struct igmpv3_query {
@@ -78,7 +78,7 @@ struct igmpv3_query {
 #endif
        __u8 qqic;
        __be16 nsrcs;
-       __be32 srcs[0];
+       __be32 srcs[];
 };
 
 #define IGMP_HOST_MEMBERSHIP_QUERY     0x11    /* From RFC1112 */
index 20ee93f..50655de 100644 (file)
@@ -104,7 +104,7 @@ struct inet_diag_hostcond {
        __u8    family;
        __u8    prefix_len;
        int     port;
-       __be32  addr[0];
+       __be32  addr[];
 };
 
 struct inet_diag_markcond {
index 884b484..b3e1658 100644 (file)
@@ -23,7 +23,7 @@ struct inotify_event {
        __u32           mask;           /* watch mask */
        __u32           cookie;         /* cookie to synchronize two events */
        __u32           len;            /* length (including nulls) of name */
-       char            name[0];        /* stub for possible name */
+       char            name[]; /* stub for possible name */
 };
 
 /* the following are legal, implemented events that user-space can watch for */
index ef4257a..2557eb7 100644 (file)
@@ -78,10 +78,13 @@ struct input_id {
  * Note that input core does not clamp reported values to the
  * [minimum, maximum] limits, such task is left to userspace.
  *
- * The default resolution for main axes (ABS_X, ABS_Y, ABS_Z)
- * is reported in units per millimeter (units/mm), resolution
- * for rotational axes (ABS_RX, ABS_RY, ABS_RZ) is reported
- * in units per radian.
+ * The default resolution for main axes (ABS_X, ABS_Y, ABS_Z,
+ * ABS_MT_POSITION_X, ABS_MT_POSITION_Y) is reported in units
+ * per millimeter (units/mm), resolution for rotational axes
+ * (ABS_RX, ABS_RY, ABS_RZ) is reported in units per radian.
+ * The resolution for the size axes (ABS_MT_TOUCH_MAJOR,
+ * ABS_MT_TOUCH_MINOR, ABS_MT_WIDTH_MAJOR, ABS_MT_WIDTH_MINOR)
+ * is reported in units per millimeter (units/mm).
  * When INPUT_PROP_ACCELEROMETER is set the resolution changes.
  * The main axes (ABS_X, ABS_Y, ABS_Z) are then reported in
  * units per g (units/g) and in units per degree per second
index 53e7dae..1463cfe 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/fs.h>
 #include <linux/types.h>
+#include <linux/time_types.h>
 
 /*
  * IO submission data structure (Submission Queue Entry)
@@ -22,7 +23,10 @@ struct io_uring_sqe {
        union {
                __u64   off;    /* offset into file */
                __u64   addr2;
-               __u32   cmd_op;
+               struct {
+                       __u32   cmd_op;
+                       __u32   __pad1;
+               };
        };
        union {
                __u64   addr;   /* pointer to buffer or iovecs */
@@ -47,6 +51,7 @@ struct io_uring_sqe {
                __u32           unlink_flags;
                __u32           hardlink_flags;
                __u32           xattr_flags;
+               __u32           msg_ring_flags;
        };
        __u64   user_data;      /* data to be passed back at completion time */
        /* pack this to avoid bogus arm OABI complaints */
@@ -61,6 +66,10 @@ struct io_uring_sqe {
        union {
                __s32   splice_fd_in;
                __u32   file_index;
+               struct {
+                       __u16   notification_idx;
+                       __u16   addr_len;
+               };
        };
        union {
                struct {
@@ -137,9 +146,12 @@ enum {
  * IORING_SQ_TASKRUN in the sq ring flags. Not valid with COOP_TASKRUN.
  */
 #define IORING_SETUP_TASKRUN_FLAG      (1U << 9)
-
 #define IORING_SETUP_SQE128            (1U << 10) /* SQEs are 128 byte */
 #define IORING_SETUP_CQE32             (1U << 11) /* CQEs are 32 byte */
+/*
+ * Only one task is allowed to submit requests
+ */
+#define IORING_SETUP_SINGLE_ISSUER     (1U << 12)
 
 enum io_uring_op {
        IORING_OP_NOP,
@@ -162,7 +174,8 @@ enum io_uring_op {
        IORING_OP_FALLOCATE,
        IORING_OP_OPENAT,
        IORING_OP_CLOSE,
-       IORING_OP_FILES_UPDATE,
+       IORING_OP_RSRC_UPDATE,
+       IORING_OP_FILES_UPDATE = IORING_OP_RSRC_UPDATE,
        IORING_OP_STATX,
        IORING_OP_READ,
        IORING_OP_WRITE,
@@ -189,6 +202,7 @@ enum io_uring_op {
        IORING_OP_GETXATTR,
        IORING_OP_SOCKET,
        IORING_OP_URING_CMD,
+       IORING_OP_SENDZC_NOTIF,
 
        /* this goes last, obviously */
        IORING_OP_LAST,
@@ -210,6 +224,7 @@ enum io_uring_op {
 #define IORING_TIMEOUT_ETIME_SUCCESS   (1U << 5)
 #define IORING_TIMEOUT_CLOCK_MASK      (IORING_TIMEOUT_BOOTTIME | IORING_TIMEOUT_REALTIME)
 #define IORING_TIMEOUT_UPDATE_MASK     (IORING_TIMEOUT_UPDATE | IORING_LINK_TIMEOUT_UPDATE)
+
 /*
  * sqe->splice_flags
  * extends splice(2) flags
@@ -226,10 +241,13 @@ enum io_uring_op {
  *
  * IORING_POLL_UPDATE          Update existing poll request, matching
  *                             sqe->addr as the old user_data field.
+ *
+ * IORING_POLL_LEVEL           Level triggered poll.
  */
 #define IORING_POLL_ADD_MULTI  (1U << 0)
 #define IORING_POLL_UPDATE_EVENTS      (1U << 1)
 #define IORING_POLL_UPDATE_USER_DATA   (1U << 2)
+#define IORING_POLL_ADD_LEVEL          (1U << 3)
 
 /*
  * ASYNC_CANCEL flags.
@@ -238,26 +256,66 @@ enum io_uring_op {
  * IORING_ASYNC_CANCEL_FD      Key off 'fd' for cancelation rather than the
  *                             request 'user_data'
  * IORING_ASYNC_CANCEL_ANY     Match any request
+ * IORING_ASYNC_CANCEL_FD_FIXED        'fd' passed in is a fixed descriptor
  */
 #define IORING_ASYNC_CANCEL_ALL        (1U << 0)
 #define IORING_ASYNC_CANCEL_FD (1U << 1)
 #define IORING_ASYNC_CANCEL_ANY        (1U << 2)
+#define IORING_ASYNC_CANCEL_FD_FIXED   (1U << 3)
 
 /*
- * send/sendmsg and recv/recvmsg flags (sqe->addr2)
+ * send/sendmsg and recv/recvmsg flags (sqe->ioprio)
  *
  * IORING_RECVSEND_POLL_FIRST  If set, instead of first attempting to send
  *                             or receive and arm poll if that yields an
  *                             -EAGAIN result, arm poll upfront and skip
  *                             the initial transfer attempt.
+ *
+ * IORING_RECV_MULTISHOT       Multishot recv. Sets IORING_CQE_F_MORE if
+ *                             the handler will continue to report
+ *                             CQEs on behalf of the same SQE.
+ *
+ * IORING_RECVSEND_FIXED_BUF   Use registered buffers, the index is stored in
+ *                             the buf_index field.
+ *
+ * IORING_RECVSEND_NOTIF_FLUSH Flush a notification after a successful
+ *                             successful. Only for zerocopy sends.
  */
 #define IORING_RECVSEND_POLL_FIRST     (1U << 0)
+#define IORING_RECV_MULTISHOT          (1U << 1)
+#define IORING_RECVSEND_FIXED_BUF      (1U << 2)
+#define IORING_RECVSEND_NOTIF_FLUSH    (1U << 3)
 
 /*
  * accept flags stored in sqe->ioprio
  */
 #define IORING_ACCEPT_MULTISHOT        (1U << 0)
 
+
+/*
+ * IORING_OP_RSRC_UPDATE flags
+ */
+enum {
+       IORING_RSRC_UPDATE_FILES,
+       IORING_RSRC_UPDATE_NOTIF,
+};
+
+/*
+ * IORING_OP_MSG_RING command types, stored in sqe->addr
+ */
+enum {
+       IORING_MSG_DATA,        /* pass sqe->len as 'res' and off as user_data */
+       IORING_MSG_SEND_FD,     /* send a registered fd to another ring */
+};
+
+/*
+ * IORING_OP_MSG_RING flags (sqe->msg_ring_flags)
+ *
+ * IORING_MSG_RING_CQE_SKIP    Don't post a CQE to the target ring. Not
+ *                             applicable for IORING_MSG_DATA, obviously.
+ */
+#define IORING_MSG_RING_CQE_SKIP       (1U << 0)
+
 /*
  * IO completion data structure (Completion Queue Entry)
  */
@@ -417,6 +475,16 @@ enum {
        IORING_REGISTER_PBUF_RING               = 22,
        IORING_UNREGISTER_PBUF_RING             = 23,
 
+       /* sync cancelation API */
+       IORING_REGISTER_SYNC_CANCEL             = 24,
+
+       /* register a range of fixed file slots for automatic slot allocation */
+       IORING_REGISTER_FILE_ALLOC_RANGE        = 25,
+
+       /* zerocopy notification API */
+       IORING_REGISTER_NOTIFIERS               = 26,
+       IORING_UNREGISTER_NOTIFIERS             = 27,
+
        /* this goes last */
        IORING_REGISTER_LAST
 };
@@ -463,6 +531,19 @@ struct io_uring_rsrc_update2 {
        __u32 resv2;
 };
 
+struct io_uring_notification_slot {
+       __u64 tag;
+       __u64 resv[3];
+};
+
+struct io_uring_notification_register {
+       __u32 nr_slots;
+       __u32 resv;
+       __u64 resv2;
+       __u64 data;
+       __u64 resv3;
+};
+
 /* Skip updating fd indexes set to this value in the fd table */
 #define IORING_REGISTER_FILES_SKIP     (-2)
 
@@ -480,7 +561,7 @@ struct io_uring_probe {
        __u8 ops_len;   /* length of ops[] array below */
        __u16 resv;
        __u32 resv2[3];
-       struct io_uring_probe_op ops[0];
+       struct io_uring_probe_op ops[];
 };
 
 struct io_uring_restriction {
@@ -552,4 +633,32 @@ struct io_uring_getevents_arg {
        __u64   ts;
 };
 
+/*
+ * Argument for IORING_REGISTER_SYNC_CANCEL
+ */
+struct io_uring_sync_cancel_reg {
+       __u64                           addr;
+       __s32                           fd;
+       __u32                           flags;
+       struct __kernel_timespec        timeout;
+       __u64                           pad[4];
+};
+
+/*
+ * Argument for IORING_REGISTER_FILE_ALLOC_RANGE
+ * The range is specified as [off, off + len)
+ */
+struct io_uring_file_index_range {
+       __u32   off;
+       __u32   len;
+       __u64   resv;
+};
+
+struct io_uring_recvmsg_out {
+       __u32 namelen;
+       __u32 controllen;
+       __u32 payloadlen;
+       __u32 flags;
+};
+
 #endif
index e00bbb9..961ec16 100644 (file)
@@ -112,13 +112,13 @@ struct ip_auth_hdr {
        __be16 reserved;
        __be32 spi;
        __be32 seq_no;          /* Sequence number */
-       __u8  auth_data[0];     /* Variable len but >=4. Mind the 64 bit alignment! */
+       __u8  auth_data[];      /* Variable len but >=4. Mind the 64 bit alignment! */
 };
 
 struct ip_esp_hdr {
        __be32 spi;
        __be32 seq_no;          /* Sequence number */
-       __u8  enc_data[0];      /* Variable len but >=8. Mind the 64 bit alignment! */
+       __u8  enc_data[];       /* Variable len but >=8. Mind the 64 bit alignment! */
 };
 
 struct ip_comp_hdr {
index 4102ddc..1ed234e 100644 (file)
@@ -254,7 +254,7 @@ struct ip_vs_get_dests {
        unsigned int            num_dests;
 
        /* the real servers */
-       struct ip_vs_dest_entry entrytable[0];
+       struct ip_vs_dest_entry entrytable[];
 };
 
 
@@ -264,7 +264,7 @@ struct ip_vs_get_services {
        unsigned int            num_services;
 
        /* service table */
-       struct ip_vs_service_entry entrytable[0];
+       struct ip_vs_service_entry entrytable[];
 };
 
 
index a255517..758178f 100644 (file)
@@ -137,7 +137,7 @@ struct iso_path_table{
        __u8  name_len[2];      /* 721 */
        __u8  extent[4];        /* 731 */
        __u8  parent[2];        /* 721 */
-       char name[0];
+       char name[];
 } __attribute__((packed));
 
 /* high sierra is identical to iso, except that the date is only 6 bytes, and
@@ -154,7 +154,7 @@ struct iso_directory_record {
        __u8 interleave                 [ISODCL (28, 28)]; /* 711 */
        __u8 volume_sequence_number     [ISODCL (29, 32)]; /* 723 */
        __u8 name_len                   [ISODCL (33, 33)]; /* 711 */
-       char name                       [0];
+       char name                       [];
 } __attribute__((packed));
 
 #define ISOFS_BLOCK_BITS 11
index 784ba0b..637ee4a 100644 (file)
@@ -123,7 +123,7 @@ struct jffs2_raw_dirent
        __u8 unused[2];
        jint32_t node_crc;
        jint32_t name_crc;
-       __u8 name[0];
+       __u8 name[];
 };
 
 /* The JFFS2 raw inode structure: Used for storage on physical media.  */
@@ -155,7 +155,7 @@ struct jffs2_raw_inode
        jint16_t flags;      /* See JFFS2_INO_FLAG_* */
        jint32_t data_crc;   /* CRC for the (compressed) data.  */
        jint32_t node_crc;   /* CRC for the raw inode (excluding data)  */
-       __u8 data[0];
+       __u8 data[];
 };
 
 struct jffs2_raw_xattr {
@@ -170,7 +170,7 @@ struct jffs2_raw_xattr {
        jint16_t value_len;
        jint32_t data_crc;
        jint32_t node_crc;
-       __u8 data[0];
+       __u8 data[];
 } __attribute__((packed));
 
 struct jffs2_raw_xref
@@ -196,7 +196,7 @@ struct jffs2_raw_summary
        jint32_t padded;        /* sum of the size of padding nodes */
        jint32_t sum_crc;       /* summary information crc */
        jint32_t node_crc;      /* node crc */
-       jint32_t sum[0];        /* inode summary info */
+       jint32_t sum[];         /* inode summary info */
 };
 
 union jffs2_node_union
index 1d0350e..ed95dba 100644 (file)
@@ -13,7 +13,7 @@ struct kcov_remote_arg {
        __u32           area_size;      /* Length of coverage buffer in words */
        __u32           num_handles;    /* Size of handles array */
        __aligned_u64   common_handle;
-       __aligned_u64   handles[0];
+       __aligned_u64   handles[];
 };
 
 #define KCOV_REMOTE_MAX_HANDLES                0x100
index 5088bd9..cb6e384 100644 (file)
@@ -542,7 +542,7 @@ struct kvm_coalesced_mmio {
 
 struct kvm_coalesced_mmio_ring {
        __u32 first, last;
-       struct kvm_coalesced_mmio coalesced_mmio[0];
+       struct kvm_coalesced_mmio coalesced_mmio[];
 };
 
 #define KVM_COALESCED_MMIO_MAX \
@@ -621,7 +621,7 @@ struct kvm_clear_dirty_log {
 /* for KVM_SET_SIGNAL_MASK */
 struct kvm_signal_mask {
        __u32 len;
-       __u8  sigset[0];
+       __u8  sigset[];
 };
 
 /* for KVM_TPR_ACCESS_REPORTING */
@@ -1221,7 +1221,7 @@ struct kvm_irq_routing_entry {
 struct kvm_irq_routing {
        __u32 nr;
        __u32 flags;
-       struct kvm_irq_routing_entry entries[0];
+       struct kvm_irq_routing_entry entries[];
 };
 
 #endif
@@ -1341,7 +1341,7 @@ struct kvm_dirty_tlb {
 
 struct kvm_reg_list {
        __u64 n; /* number of regs */
-       __u64 reg[0];
+       __u64 reg[];
 };
 
 struct kvm_one_reg {
@@ -2083,7 +2083,8 @@ struct kvm_stats_header {
 #define KVM_STATS_UNIT_BYTES           (0x1 << KVM_STATS_UNIT_SHIFT)
 #define KVM_STATS_UNIT_SECONDS         (0x2 << KVM_STATS_UNIT_SHIFT)
 #define KVM_STATS_UNIT_CYCLES          (0x3 << KVM_STATS_UNIT_SHIFT)
-#define KVM_STATS_UNIT_MAX             KVM_STATS_UNIT_CYCLES
+#define KVM_STATS_UNIT_BOOLEAN         (0x4 << KVM_STATS_UNIT_SHIFT)
+#define KVM_STATS_UNIT_MAX             KVM_STATS_UNIT_BOOLEAN
 
 #define KVM_STATS_BASE_SHIFT           8
 #define KVM_STATS_BASE_MASK            (0xF << KVM_STATS_BASE_SHIFT)
diff --git a/include/uapi/linux/loadpin.h b/include/uapi/linux/loadpin.h
new file mode 100644 (file)
index 0000000..daa6dbb
--- /dev/null
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * Copyright (c) 2022, Google LLC
+ */
+
+#ifndef _UAPI_LINUX_LOOP_LOADPIN_H
+#define _UAPI_LINUX_LOOP_LOADPIN_H
+
+#define LOADPIN_IOC_MAGIC      'L'
+
+/**
+ * LOADPIN_IOC_SET_TRUSTED_VERITY_DIGESTS - Set up the root digests of verity devices
+ *                                          that loadpin should trust.
+ *
+ * Takes a file descriptor from which to read the root digests of trusted verity devices. The file
+ * is expected to contain a list of digests in ASCII format, with one line per digest. The ioctl
+ * must be issued on the securityfs attribute 'loadpin/dm-verity' (which can be typically found
+ * under /sys/kernel/security/loadpin/dm-verity).
+ */
+#define LOADPIN_IOC_SET_TRUSTED_VERITY_DIGESTS _IOW(LOADPIN_IOC_MAGIC, 0x00, unsigned int)
+
+#endif /* _UAPI_LINUX_LOOP_LOADPIN_H */
index 95dbcb1..8d9ca8b 100644 (file)
@@ -97,11 +97,11 @@ struct minix3_super_block {
 
 struct minix_dir_entry {
        __u16 inode;
-       char name[0];
+       char name[];
 };
 
 struct minix3_dir_entry {
        __u32 inode;
-       char name[0];
+       char name[];
 };
 #endif
index 27a3984..e7401ad 100644 (file)
@@ -58,7 +58,7 @@ struct mmc_ioc_cmd {
  */
 struct mmc_ioc_multi_cmd {
        __u64 num_of_cmds;
-       struct mmc_ioc_cmd cmds[0];
+       struct mmc_ioc_cmd cmds[];
 };
 
 #define MMC_IOC_CMD _IOWR(MMC_BLOCK_MAJOR, 0, struct mmc_ioc_cmd)
index 9219635..dfe19bf 100644 (file)
@@ -2,16 +2,17 @@
 #ifndef _UAPI_MPTCP_H
 #define _UAPI_MPTCP_H
 
+#ifndef __KERNEL__
+#include <netinet/in.h>                /* for sockaddr_in and sockaddr_in6     */
+#include <sys/socket.h>                /* for struct sockaddr                  */
+#endif
+
 #include <linux/const.h>
 #include <linux/types.h>
 #include <linux/in.h>          /* for sockaddr_in                      */
 #include <linux/in6.h>         /* for sockaddr_in6                     */
 #include <linux/socket.h>      /* for sockaddr_storage and sa_family   */
 
-#ifndef __KERNEL__
-#include <sys/socket.h>                /* for struct sockaddr                  */
-#endif
-
 #define MPTCP_SUBFLOW_FLAG_MCAP_REM            _BITUL(0)
 #define MPTCP_SUBFLOW_FLAG_MCAP_LOC            _BITUL(1)
 #define MPTCP_SUBFLOW_FLAG_JOIN_REM            _BITUL(2)
index 17e02b6..73516e2 100644 (file)
@@ -30,25 +30,25 @@ struct nd_cmd_get_config_data_hdr {
        __u32 in_offset;
        __u32 in_length;
        __u32 status;
-       __u8 out_buf[0];
+       __u8 out_buf[];
 } __packed;
 
 struct nd_cmd_set_config_hdr {
        __u32 in_offset;
        __u32 in_length;
-       __u8 in_buf[0];
+       __u8 in_buf[];
 } __packed;
 
 struct nd_cmd_vendor_hdr {
        __u32 opcode;
        __u32 in_length;
-       __u8 in_buf[0];
+       __u8 in_buf[];
 } __packed;
 
 struct nd_cmd_vendor_tail {
        __u32 status;
        __u32 out_length;
-       __u8 out_buf[0];
+       __u8 out_buf[];
 } __packed;
 
 struct nd_cmd_ars_cap {
@@ -86,7 +86,7 @@ struct nd_cmd_ars_status {
                __u32 reserved;
                __u64 err_address;
                __u64 length;
-       } __packed records[0];
+       } __packed records[];
 } __packed;
 
 struct nd_cmd_clear_error {
index 1bbea8f..84f622a 100644 (file)
@@ -29,12 +29,12 @@ struct net_dm_config_entry {
 
 struct net_dm_config_msg {
        __u32 entries;
-       struct net_dm_config_entry options[0];
+       struct net_dm_config_entry options[];
 };
 
 struct net_dm_alert_msg {
        __u32 entries;
-       struct net_dm_drop_point points[0];
+       struct net_dm_drop_point points[];
 };
 
 struct net_dm_user_msg {
index b8c6bb2..796af83 100644 (file)
@@ -28,7 +28,7 @@ struct xt_entry_match {
                __u16 match_size;
        } u;
 
-       unsigned char data[0];
+       unsigned char data[];
 };
 
 struct xt_entry_target {
@@ -119,7 +119,7 @@ struct xt_counters_info {
        unsigned int num_counters;
 
        /* The counters (actually `number' of these). */
-       struct xt_counters counters[0];
+       struct xt_counters counters[];
 };
 
 #define XT_INV_PROTO           0x40    /* Invert the sense of PROTO. */
index bbf5af2..a6ac246 100644 (file)
@@ -109,7 +109,7 @@ struct arpt_entry
        struct xt_counters counters;
 
        /* The matches (if any), then the target. */
-       unsigned char elems[0];
+       unsigned char elems[];
 };
 
 /*
@@ -181,7 +181,7 @@ struct arpt_replace {
        struct xt_counters __user *counters;
 
        /* The entries (hang off end: not really an array). */
-       struct arpt_entry entries[0];
+       struct arpt_entry entries[];
 };
 
 /* The argument to ARPT_SO_GET_ENTRIES. */
@@ -193,7 +193,7 @@ struct arpt_get_entries {
        unsigned int size;
 
        /* The entries. */
-       struct arpt_entry entrytable[0];
+       struct arpt_entry entrytable[];
 };
 
 /* Helper functions */
index 9acf757..73b26a2 100644 (file)
@@ -40,7 +40,7 @@ struct ebt_mac_wormhash_tuple {
 struct ebt_mac_wormhash {
        int table[257];
        int poolsize;
-       struct ebt_mac_wormhash_tuple pool[0];
+       struct ebt_mac_wormhash_tuple pool[];
 };
 
 #define ebt_mac_wormhash_size(x) ((x) ? sizeof(struct ebt_mac_wormhash) \
index 50c7fee..1485df2 100644 (file)
@@ -121,7 +121,7 @@ struct ipt_entry {
        struct xt_counters counters;
 
        /* The matches (if any), then the target. */
-       unsigned char elems[0];
+       unsigned char elems[];
 };
 
 /*
@@ -203,7 +203,7 @@ struct ipt_replace {
        struct xt_counters __user *counters;
 
        /* The entries (hang off end: not really an array). */
-       struct ipt_entry entries[0];
+       struct ipt_entry entries[];
 };
 
 /* The argument to IPT_SO_GET_ENTRIES. */
@@ -215,7 +215,7 @@ struct ipt_get_entries {
        unsigned int size;
 
        /* The entries. */
-       struct ipt_entry entrytable[0];
+       struct ipt_entry entrytable[];
 };
 
 /* Helper functions */
index d9e364f..766e8e0 100644 (file)
@@ -243,7 +243,7 @@ struct ip6t_replace {
        struct xt_counters __user *counters;
 
        /* The entries (hang off end: not really an array). */
-       struct ip6t_entry entries[0];
+       struct ip6t_entry entries[];
 };
 
 /* The argument to IP6T_SO_GET_ENTRIES. */
@@ -255,7 +255,7 @@ struct ip6t_get_entries {
        unsigned int size;
 
        /* The entries. */
-       struct ip6t_entry entrytable[0];
+       struct ip6t_entry entrytable[];
 };
 
 /* Helper functions */
index d37629d..03b3700 100644 (file)
@@ -301,6 +301,7 @@ enum {
  *       { u64         time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
  *       { u64         time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
  *       { u64         id;           } && PERF_FORMAT_ID
+ *       { u64         lost;         } && PERF_FORMAT_LOST
  *     } && !PERF_FORMAT_GROUP
  *
  *     { u64           nr;
@@ -308,6 +309,7 @@ enum {
  *       { u64         time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
  *       { u64         value;
  *         { u64       id;           } && PERF_FORMAT_ID
+ *         { u64       lost;         } && PERF_FORMAT_LOST
  *       }             cntr[nr];
  *     } && PERF_FORMAT_GROUP
  * };
@@ -317,8 +319,9 @@ enum perf_event_read_format {
        PERF_FORMAT_TOTAL_TIME_RUNNING          = 1U << 1,
        PERF_FORMAT_ID                          = 1U << 2,
        PERF_FORMAT_GROUP                       = 1U << 3,
+       PERF_FORMAT_LOST                        = 1U << 4,
 
-       PERF_FORMAT_MAX = 1U << 4,              /* non-ABI */
+       PERF_FORMAT_MAX = 1U << 5,              /* non-ABI */
 };
 
 #define PERF_ATTR_SIZE_VER0    64      /* sizeof first published struct */
@@ -491,7 +494,7 @@ struct perf_event_query_bpf {
        /*
         * User provided buffer to store program ids
         */
-       __u32   ids[0];
+       __u32   ids[];
 };
 
 /*
index 9a2ee1e..ffbe230 100644 (file)
@@ -256,7 +256,7 @@ struct tc_u32_sel {
 
        short                   hoff;
        __be32                  hmask;
-       struct tc_u32_key       keys[0];
+       struct tc_u32_key       keys[];
 };
 
 struct tc_u32_mark {
@@ -268,7 +268,7 @@ struct tc_u32_mark {
 struct tc_u32_pcnt {
        __u64 rcnt;
        __u64 rhit;
-       __u64 kcnts[0];
+       __u64 kcnts[];
 };
 
 /* Flags */
index e5a98a1..6c0aa57 100644 (file)
@@ -303,7 +303,7 @@ struct mdp_superblock_1 {
         * into the 'roles' value.  If a device is spare or faulty, then it doesn't
         * have a meaningful role.
         */
-       __le16  dev_roles[0];   /* role in array, or 0xffff for a spare, or 0xfffe for faulty */
+       __le16  dev_roles[];    /* role in array, or 0xffff for a spare, or 0xfffe for faulty */
 };
 
 /* feature_map bits */
index dcc1b3e..e744c23 100644 (file)
@@ -41,7 +41,7 @@
 struct rand_pool_info {
        int     entropy_count;
        int     buf_size;
-       __u32   buf[0];
+       __u32   buf[];
 };
 
 /*
index a7f1585..6aa05e7 100644 (file)
@@ -27,7 +27,7 @@ struct romfs_super_block {
        __be32 word1;
        __be32 size;
        __be32 checksum;
-       char name[0];           /* volume name */
+       char name[];            /* volume name */
 };
 
 /* On disk inode */
@@ -37,7 +37,7 @@ struct romfs_inode {
        __be32 spec;
        __be32 size;
        __be32 checksum;
-       char name[0];
+       char name[];
 };
 
 #define ROMFH_TYPE 7
index 83849a3..eb2747d 100644 (file)
@@ -440,7 +440,7 @@ struct rtnexthop {
 /* RTA_VIA */
 struct rtvia {
        __kernel_sa_family_t    rtvia_family;
-       __u8                    rtvia_addr[0];
+       __u8                    rtvia_addr[];
 };
 
 /* RTM_CACHEINFO */
index c4ff1eb..ed7d4ec 100644 (file)
@@ -365,7 +365,7 @@ struct sctp_assoc_change {
        __u16 sac_outbound_streams;
        __u16 sac_inbound_streams;
        sctp_assoc_t sac_assoc_id;
-       __u8 sac_info[0];
+       __u8 sac_info[];
 };
 
 /*
@@ -436,7 +436,7 @@ struct sctp_remote_error {
        __u32 sre_length;
        __be16 sre_error;
        sctp_assoc_t sre_assoc_id;
-       __u8 sre_data[0];
+       __u8 sre_data[];
 };
 
 
@@ -453,7 +453,7 @@ struct sctp_send_failed {
        __u32 ssf_error;
        struct sctp_sndrcvinfo ssf_info;
        sctp_assoc_t ssf_assoc_id;
-       __u8 ssf_data[0];
+       __u8 ssf_data[];
 };
 
 struct sctp_send_failed_event {
@@ -463,7 +463,7 @@ struct sctp_send_failed_event {
        __u32 ssf_error;
        struct sctp_sndinfo ssfe_info;
        sctp_assoc_t ssf_assoc_id;
-       __u8 ssf_data[0];
+       __u8 ssf_data[];
 };
 
 /*
@@ -1029,7 +1029,7 @@ struct sctp_getaddrs_old {
 struct sctp_getaddrs {
        sctp_assoc_t            assoc_id; /*input*/
        __u32                   addr_num; /*output*/
-       __u8                    addrs[0]; /*output, variable size*/
+       __u8                    addrs[]; /*output, variable size*/
 };
 
 /* A socket user request obtained via SCTP_GET_ASSOC_STATS that retrieves
index 286e8d6..13bcbc8 100644 (file)
@@ -30,7 +30,7 @@ struct ipv6_sr_hdr {
        __u8    flags;
        __u16   tag;
 
-       struct in6_addr segments[0];
+       struct in6_addr segments[];
 };
 
 #define SR6_FLAG1_PROTECTED    (1 << 6)
index eb815e0..a742942 100644 (file)
@@ -26,7 +26,7 @@ enum {
 
 struct seg6_iptunnel_encap {
        int mode;
-       struct ipv6_sr_hdr srh[0];
+       struct ipv6_sr_hdr srh[];
 };
 
 #define SEG6_IPTUN_ENCAP_SIZE(x) ((sizeof(*x)) + (((x)->srh->hdrlen + 1) << 3))
index 7bac318..de3579c 100644 (file)
@@ -36,7 +36,7 @@ struct stp_policy_id {
        /* padding */
        __u16           __reserved_0;
        __u32           __reserved_1;
-       char            id[0];
+       char            id[];
 };
 
 #define STP_POLICY_ID_SET      _IOWR('%', 0, struct stp_policy_id)
index 27ace51..fbd8ca6 100644 (file)
@@ -152,7 +152,7 @@ struct tcmu_tmr_entry {
        __u32 cmd_cnt;
        __u64 __pad3;
        __u64 __pad4;
-       __u16 cmd_ids[0];
+       __u16 cmd_ids[];
 } __packed;
 
 #define TCMU_OP_ALIGN_SIZE sizeof(__u64)
index 9d0f06b..68aeae2 100644 (file)
@@ -38,8 +38,9 @@
 #define N_NULL         27      /* Null ldisc used for error handling */
 #define N_MCTP         28      /* MCTP-over-serial */
 #define N_DEVELOPMENT  29      /* Manual out-of-tree testing */
+#define N_CAN327       30      /* ELM327 based OBD-II interfaces */
 
 /* Always the newest line discipline + 1 */
-#define NR_LDISCS      30
+#define NR_LDISCS      31
 
 #endif /* _UAPI_LINUX_TTY_H */
diff --git a/include/uapi/linux/ublk_cmd.h b/include/uapi/linux/ublk_cmd.h
new file mode 100644 (file)
index 0000000..ca33092
--- /dev/null
@@ -0,0 +1,161 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef USER_BLK_DRV_CMD_INC_H
+#define USER_BLK_DRV_CMD_INC_H
+
+#include <linux/types.h>
+
+/* ublk server command definition */
+
+/*
+ * Admin commands, issued by ublk server, and handled by ublk driver.
+ */
+#define        UBLK_CMD_GET_QUEUE_AFFINITY     0x01
+#define        UBLK_CMD_GET_DEV_INFO   0x02
+#define        UBLK_CMD_ADD_DEV                0x04
+#define        UBLK_CMD_DEL_DEV                0x05
+#define        UBLK_CMD_START_DEV      0x06
+#define        UBLK_CMD_STOP_DEV       0x07
+
+/*
+ * IO commands, issued by ublk server, and handled by ublk driver.
+ *
+ * FETCH_REQ: issued via sqe(URING_CMD) beforehand for fetching IO request
+ *      from ublk driver, should be issued only when starting device. After
+ *      the associated cqe is returned, request's tag can be retrieved via
+ *      cqe->userdata.
+ *
+ * COMMIT_AND_FETCH_REQ: issued via sqe(URING_CMD) after ublkserver handled
+ *      this IO request, request's handling result is committed to ublk
+ *      driver, meantime FETCH_REQ is piggyback, and FETCH_REQ has to be
+ *      handled before completing io request.
+ */
+#define        UBLK_IO_FETCH_REQ               0x20
+#define        UBLK_IO_COMMIT_AND_FETCH_REQ    0x21
+
+/* only ABORT means that no re-fetch */
+#define UBLK_IO_RES_OK                 0
+#define UBLK_IO_RES_ABORT              (-ENODEV)
+
+#define UBLKSRV_CMD_BUF_OFFSET 0
+#define UBLKSRV_IO_BUF_OFFSET  0x80000000
+
+/* tag bit is 12bit, so at most 4096 IOs for each queue */
+#define UBLK_MAX_QUEUE_DEPTH   4096
+
+/*
+ * zero copy requires 4k block size, and can remap ublk driver's io
+ * request into ublksrv's vm space
+ */
+#define UBLK_F_SUPPORT_ZERO_COPY       (1ULL << 0)
+
+/*
+ * Force to complete io cmd via io_uring_cmd_complete_in_task so that
+ * performance comparison is done easily with using task_work_add
+ */
+#define UBLK_F_URING_CMD_COMP_IN_TASK  (1ULL << 1)
+
+/* device state */
+#define UBLK_S_DEV_DEAD        0
+#define UBLK_S_DEV_LIVE        1
+
+/* shipped via sqe->cmd of io_uring command */
+struct ublksrv_ctrl_cmd {
+       /* sent to which device, must be valid */
+       __u32   dev_id;
+
+       /* sent to which queue, must be -1 if the cmd isn't for queue */
+       __u16   queue_id;
+       /*
+        * cmd specific buffer, can be IN or OUT.
+        */
+       __u16   len;
+       __u64   addr;
+
+       /* inline data */
+       __u64   data[2];
+};
+
+struct ublksrv_ctrl_dev_info {
+       __u16   nr_hw_queues;
+       __u16   queue_depth;
+       __u16   block_size;
+       __u16   state;
+
+       __u32   rq_max_blocks;
+       __u32   dev_id;
+
+       __u64   dev_blocks;
+
+       __s32   ublksrv_pid;
+       __s32   reserved0;
+       __u64   flags;
+       __u64   flags_reserved;
+
+       /* For ublksrv internal use, invisible to ublk driver */
+       __u64   ublksrv_flags;
+       __u64   reserved1[9];
+};
+
+#define                UBLK_IO_OP_READ         0
+#define                UBLK_IO_OP_WRITE                1
+#define                UBLK_IO_OP_FLUSH                2
+#define                UBLK_IO_OP_DISCARD      3
+#define                UBLK_IO_OP_WRITE_SAME   4
+#define                UBLK_IO_OP_WRITE_ZEROES 5
+
+#define                UBLK_IO_F_FAILFAST_DEV          (1U << 8)
+#define                UBLK_IO_F_FAILFAST_TRANSPORT    (1U << 9)
+#define                UBLK_IO_F_FAILFAST_DRIVER       (1U << 10)
+#define                UBLK_IO_F_META                  (1U << 11)
+#define                UBLK_IO_F_FUA                   (1U << 13)
+#define                UBLK_IO_F_NOUNMAP               (1U << 15)
+#define                UBLK_IO_F_SWAP                  (1U << 16)
+
+/*
+ * io cmd is described by this structure, and stored in share memory, indexed
+ * by request tag.
+ *
+ * The data is stored by ublk driver, and read by ublksrv after one fetch command
+ * returns.
+ */
+struct ublksrv_io_desc {
+       /* op: bit 0-7, flags: bit 8-31 */
+       __u32           op_flags;
+
+       __u32           nr_sectors;
+
+       /* start sector for this io */
+       __u64           start_sector;
+
+       /* buffer address in ublksrv daemon vm space, from ublk driver */
+       __u64           addr;
+};
+
+static inline __u8 ublksrv_get_op(const struct ublksrv_io_desc *iod)
+{
+       return iod->op_flags & 0xff;
+}
+
+static inline __u32 ublksrv_get_flags(const struct ublksrv_io_desc *iod)
+{
+       return iod->op_flags >> 8;
+}
+
+/* issued to ublk driver via /dev/ublkcN */
+struct ublksrv_io_cmd {
+       __u16   q_id;
+
+       /* for fetch/commit which result */
+       __u16   tag;
+
+       /* io result, it is valid for COMMIT* command only */
+       __s32   result;
+
+       /*
+        * userspace buffer address in ublksrv daemon process, valid for
+        * FETCH* command only
+        */
+       __u64   addr;
+};
+
+#endif
index 76b7c3f..c917c53 100644 (file)
@@ -341,7 +341,7 @@ struct uac_feature_unit_descriptor {
        __u8 bUnitID;
        __u8 bSourceID;
        __u8 bControlSize;
-       __u8 bmaControls[0]; /* variable length */
+       __u8 bmaControls[]; /* variable length */
 } __attribute__((packed));
 
 static inline __u8 uac_feature_unit_iFeature(struct uac_feature_unit_descriptor *desc)
index 6d61550..acf3852 100644 (file)
@@ -171,7 +171,7 @@ struct usb_cdc_mdlm_detail_desc {
 
        /* type is associated with mdlm_desc.bGUID */
        __u8    bGuidDescriptorType;
-       __u8    bDetailData[0];
+       __u8    bDetailData[];
 } __attribute__ ((packed));
 
 /* "OBEX Control Model Functional Descriptor" */
@@ -379,7 +379,7 @@ struct usb_cdc_ncm_ndp16 {
        __le32  dwSignature;
        __le16  wLength;
        __le16  wNextNdpIndex;
-       struct  usb_cdc_ncm_dpe16 dpe16[0];
+       struct  usb_cdc_ncm_dpe16 dpe16[];
 } __attribute__ ((packed));
 
 /* 32-bit NCM Datagram Pointer Entry */
@@ -395,7 +395,7 @@ struct usb_cdc_ncm_ndp32 {
        __le16  wReserved6;
        __le32  dwNextNdpIndex;
        __le32  dwReserved12;
-       struct  usb_cdc_ncm_dpe32 dpe32[0];
+       struct  usb_cdc_ncm_dpe32 dpe32[];
 } __attribute__ ((packed));
 
 /* CDC NCM subclass 3.2.1 and 3.2.2 */
index 17ce561..31fcfa0 100644 (file)
@@ -818,7 +818,7 @@ struct usb_key_descriptor {
 
        __u8  tTKID[3];
        __u8  bReserved;
-       __u8  bKeyData[0];
+       __u8  bKeyData[];
 } __attribute__((packed));
 
 /*-------------------------------------------------------------------------*/
index 0be6852..c7d2199 100644 (file)
@@ -60,7 +60,7 @@ enum usb_raw_event_type {
 struct usb_raw_event {
        __u32           type;
        __u32           length;
-       __u8            data[0];
+       __u8            data[];
 };
 
 #define USB_RAW_IO_FLAGS_ZERO  0x0001
@@ -90,7 +90,7 @@ struct usb_raw_ep_io {
        __u16           ep;
        __u16           flags;
        __u32           length;
-       __u8            data[0];
+       __u8            data[];
 };
 
 /* Maximum number of non-control endpoints in struct usb_raw_eps_info. */
index cf525cd..74a84e0 100644 (file)
@@ -131,7 +131,7 @@ struct usbdevfs_urb {
        unsigned int signr;     /* signal to be sent on completion,
                                  or 0 if none should be sent. */
        void __user *usercontext;
-       struct usbdevfs_iso_packet_desc iso_frame_desc[0];
+       struct usbdevfs_iso_packet_desc iso_frame_desc[];
 };
 
 /* ioctls for talking directly to drivers */
@@ -176,7 +176,7 @@ struct usbdevfs_disconnect_claim {
 struct usbdevfs_streams {
        unsigned int num_streams; /* Not used by USBDEVFS_FREE_STREAMS */
        unsigned int num_eps;
-       unsigned char eps[0];
+       unsigned char eps[];
 };
 
 /*
index 634cee4..391331a 100644 (file)
@@ -107,7 +107,7 @@ struct vhost_memory_region {
 struct vhost_memory {
        __u32 nregions;
        __u32 padding;
-       struct vhost_memory_region regions[0];
+       struct vhost_memory_region regions[];
 };
 
 /* VHOST_SCSI specific definitions */
@@ -135,7 +135,7 @@ struct vhost_scsi_target {
 struct vhost_vdpa_config {
        __u32 off;
        __u32 len;
-       __u8 buf[0];
+       __u8 buf[];
 };
 
 /* vhost vdpa IOVA range
index 4410474..374b68f 100644 (file)
@@ -38,7 +38,7 @@ struct virtio_9p_config {
        /* length of the tag name */
        __virtio16 tag_len;
        /* non-NULL terminated tag name */
-       __u8 tag[0];
+       __u8 tag[];
 } __attribute__((packed));
 
 #endif /* _LINUX_VIRTIO_9P_H */
index 65e13a0..e8191e0 100644 (file)
@@ -33,7 +33,7 @@ struct xfrm_sec_ctx {
        __u8    ctx_alg;
        __u16   ctx_len;
        __u32   ctx_sid;
-       char    ctx_str[0];
+       char    ctx_str[];
 };
 
 /* Security Context Domains of Interpretation */
@@ -96,27 +96,27 @@ struct xfrm_replay_state_esn {
        __u32           oseq_hi;
        __u32           seq_hi;
        __u32           replay_window;
-       __u32           bmp[0];
+       __u32           bmp[];
 };
 
 struct xfrm_algo {
        char            alg_name[64];
        unsigned int    alg_key_len;    /* in bits */
-       char            alg_key[0];
+       char            alg_key[];
 };
 
 struct xfrm_algo_auth {
        char            alg_name[64];
        unsigned int    alg_key_len;    /* in bits */
        unsigned int    alg_trunc_len;  /* in bits */
-       char            alg_key[0];
+       char            alg_key[];
 };
 
 struct xfrm_algo_aead {
        char            alg_name[64];
        unsigned int    alg_key_len;    /* in bits */
        unsigned int    alg_icv_len;    /* in bits */
-       char            alg_key[0];
+       char            alg_key[];
 };
 
 struct xfrm_stats {
index d95ef9a..1106a7c 100644 (file)
@@ -180,7 +180,7 @@ struct hfi1_sdma_comp_entry {
 struct hfi1_status {
        __aligned_u64 dev;      /* device/hw status bits */
        __aligned_u64 port;     /* port state and status bits */
-       char freezemsg[0];
+       char freezemsg[];
 };
 
 enum sdma_req_opcode {
index 7dd903d..43672cb 100644 (file)
@@ -158,18 +158,18 @@ struct ib_uverbs_ex_cmd_hdr {
 
 struct ib_uverbs_get_context {
        __aligned_u64 response;
-       __aligned_u64 driver_data[0];
+       __aligned_u64 driver_data[];
 };
 
 struct ib_uverbs_get_context_resp {
        __u32 async_fd;
        __u32 num_comp_vectors;
-       __aligned_u64 driver_data[0];
+       __aligned_u64 driver_data[];
 };
 
 struct ib_uverbs_query_device {
        __aligned_u64 response;
-       __aligned_u64 driver_data[0];
+       __aligned_u64 driver_data[];
 };
 
 struct ib_uverbs_query_device_resp {
@@ -278,7 +278,7 @@ struct ib_uverbs_query_port {
        __aligned_u64 response;
        __u8  port_num;
        __u8  reserved[7];
-       __aligned_u64 driver_data[0];
+       __aligned_u64 driver_data[];
 };
 
 struct ib_uverbs_query_port_resp {
@@ -308,12 +308,12 @@ struct ib_uverbs_query_port_resp {
 
 struct ib_uverbs_alloc_pd {
        __aligned_u64 response;
-       __aligned_u64 driver_data[0];
+       __aligned_u64 driver_data[];
 };
 
 struct ib_uverbs_alloc_pd_resp {
        __u32 pd_handle;
-       __u32 driver_data[0];
+       __u32 driver_data[];
 };
 
 struct ib_uverbs_dealloc_pd {
@@ -324,12 +324,12 @@ struct ib_uverbs_open_xrcd {
        __aligned_u64 response;
        __u32 fd;
        __u32 oflags;
-       __aligned_u64 driver_data[0];
+       __aligned_u64 driver_data[];
 };
 
 struct ib_uverbs_open_xrcd_resp {
        __u32 xrcd_handle;
-       __u32 driver_data[0];
+       __u32 driver_data[];
 };
 
 struct ib_uverbs_close_xrcd {
@@ -343,14 +343,14 @@ struct ib_uverbs_reg_mr {
        __aligned_u64 hca_va;
        __u32 pd_handle;
        __u32 access_flags;
-       __aligned_u64 driver_data[0];
+       __aligned_u64 driver_data[];
 };
 
 struct ib_uverbs_reg_mr_resp {
        __u32 mr_handle;
        __u32 lkey;
        __u32 rkey;
-       __u32 driver_data[0];
+       __u32 driver_data[];
 };
 
 struct ib_uverbs_rereg_mr {
@@ -362,13 +362,13 @@ struct ib_uverbs_rereg_mr {
        __aligned_u64 hca_va;
        __u32 pd_handle;
        __u32 access_flags;
-       __aligned_u64 driver_data[0];
+       __aligned_u64 driver_data[];
 };
 
 struct ib_uverbs_rereg_mr_resp {
        __u32 lkey;
        __u32 rkey;
-       __aligned_u64 driver_data[0];
+       __aligned_u64 driver_data[];
 };
 
 struct ib_uverbs_dereg_mr {
@@ -380,13 +380,13 @@ struct ib_uverbs_alloc_mw {
        __u32 pd_handle;
        __u8  mw_type;
        __u8  reserved[3];
-       __aligned_u64 driver_data[0];
+       __aligned_u64 driver_data[];
 };
 
 struct ib_uverbs_alloc_mw_resp {
        __u32 mw_handle;
        __u32 rkey;
-       __aligned_u64 driver_data[0];
+       __aligned_u64 driver_data[];
 };
 
 struct ib_uverbs_dealloc_mw {
@@ -408,7 +408,7 @@ struct ib_uverbs_create_cq {
        __u32 comp_vector;
        __s32 comp_channel;
        __u32 reserved;
-       __aligned_u64 driver_data[0];
+       __aligned_u64 driver_data[];
 };
 
 enum ib_uverbs_ex_create_cq_flags {
@@ -442,13 +442,13 @@ struct ib_uverbs_resize_cq {
        __aligned_u64 response;
        __u32 cq_handle;
        __u32 cqe;
-       __aligned_u64 driver_data[0];
+       __aligned_u64 driver_data[];
 };
 
 struct ib_uverbs_resize_cq_resp {
        __u32 cqe;
        __u32 reserved;
-       __aligned_u64 driver_data[0];
+       __aligned_u64 driver_data[];
 };
 
 struct ib_uverbs_poll_cq {
@@ -492,7 +492,7 @@ struct ib_uverbs_wc {
 struct ib_uverbs_poll_cq_resp {
        __u32 count;
        __u32 reserved;
-       struct ib_uverbs_wc wc[0];
+       struct ib_uverbs_wc wc[];
 };
 
 struct ib_uverbs_req_notify_cq {
@@ -585,7 +585,7 @@ struct ib_uverbs_create_qp {
        __u8  qp_type;
        __u8  is_srq;
        __u8  reserved;
-       __aligned_u64 driver_data[0];
+       __aligned_u64 driver_data[];
 };
 
 enum ib_uverbs_create_qp_mask {
@@ -624,7 +624,7 @@ struct ib_uverbs_open_qp {
        __u32 qpn;
        __u8  qp_type;
        __u8  reserved[7];
-       __aligned_u64 driver_data[0];
+       __aligned_u64 driver_data[];
 };
 
 /* also used for open response */
@@ -669,7 +669,7 @@ struct ib_uverbs_query_qp {
        __aligned_u64 response;
        __u32 qp_handle;
        __u32 attr_mask;
-       __aligned_u64 driver_data[0];
+       __aligned_u64 driver_data[];
 };
 
 struct ib_uverbs_query_qp_resp {
@@ -703,7 +703,7 @@ struct ib_uverbs_query_qp_resp {
        __u8  alt_timeout;
        __u8  sq_sig_all;
        __u8  reserved[5];
-       __aligned_u64 driver_data[0];
+       __aligned_u64 driver_data[];
 };
 
 struct ib_uverbs_modify_qp {
@@ -824,7 +824,7 @@ struct ib_uverbs_post_send {
        __u32 wr_count;
        __u32 sge_count;
        __u32 wqe_size;
-       struct ib_uverbs_send_wr send_wr[0];
+       struct ib_uverbs_send_wr send_wr[];
 };
 
 struct ib_uverbs_post_send_resp {
@@ -843,7 +843,7 @@ struct ib_uverbs_post_recv {
        __u32 wr_count;
        __u32 sge_count;
        __u32 wqe_size;
-       struct ib_uverbs_recv_wr recv_wr[0];
+       struct ib_uverbs_recv_wr recv_wr[];
 };
 
 struct ib_uverbs_post_recv_resp {
@@ -856,7 +856,7 @@ struct ib_uverbs_post_srq_recv {
        __u32 wr_count;
        __u32 sge_count;
        __u32 wqe_size;
-       struct ib_uverbs_recv_wr recv[0];
+       struct ib_uverbs_recv_wr recv[];
 };
 
 struct ib_uverbs_post_srq_recv_resp {
@@ -869,12 +869,12 @@ struct ib_uverbs_create_ah {
        __u32 pd_handle;
        __u32 reserved;
        struct ib_uverbs_ah_attr attr;
-       __aligned_u64 driver_data[0];
+       __aligned_u64 driver_data[];
 };
 
 struct ib_uverbs_create_ah_resp {
        __u32 ah_handle;
-       __u32 driver_data[0];
+       __u32 driver_data[];
 };
 
 struct ib_uverbs_destroy_ah {
@@ -886,7 +886,7 @@ struct ib_uverbs_attach_mcast {
        __u32 qp_handle;
        __u16 mlid;
        __u16 reserved;
-       __aligned_u64 driver_data[0];
+       __aligned_u64 driver_data[];
 };
 
 struct ib_uverbs_detach_mcast {
@@ -894,7 +894,7 @@ struct ib_uverbs_detach_mcast {
        __u32 qp_handle;
        __u16 mlid;
        __u16 reserved;
-       __aligned_u64 driver_data[0];
+       __aligned_u64 driver_data[];
 };
 
 struct ib_uverbs_flow_spec_hdr {
@@ -1135,7 +1135,7 @@ struct ib_uverbs_flow_attr {
         * struct ib_flow_spec_xxx
         * struct ib_flow_spec_yyy
         */
-       struct ib_uverbs_flow_spec_hdr flow_specs[0];
+       struct ib_uverbs_flow_spec_hdr flow_specs[];
 };
 
 struct ib_uverbs_create_flow  {
@@ -1161,7 +1161,7 @@ struct ib_uverbs_create_srq {
        __u32 max_wr;
        __u32 max_sge;
        __u32 srq_limit;
-       __aligned_u64 driver_data[0];
+       __aligned_u64 driver_data[];
 };
 
 struct ib_uverbs_create_xsrq {
@@ -1175,7 +1175,7 @@ struct ib_uverbs_create_xsrq {
        __u32 max_num_tags;
        __u32 xrcd_handle;
        __u32 cq_handle;
-       __aligned_u64 driver_data[0];
+       __aligned_u64 driver_data[];
 };
 
 struct ib_uverbs_create_srq_resp {
@@ -1183,7 +1183,7 @@ struct ib_uverbs_create_srq_resp {
        __u32 max_wr;
        __u32 max_sge;
        __u32 srqn;
-       __u32 driver_data[0];
+       __u32 driver_data[];
 };
 
 struct ib_uverbs_modify_srq {
@@ -1191,14 +1191,14 @@ struct ib_uverbs_modify_srq {
        __u32 attr_mask;
        __u32 max_wr;
        __u32 srq_limit;
-       __aligned_u64 driver_data[0];
+       __aligned_u64 driver_data[];
 };
 
 struct ib_uverbs_query_srq {
        __aligned_u64 response;
        __u32 srq_handle;
        __u32 reserved;
-       __aligned_u64 driver_data[0];
+       __aligned_u64 driver_data[];
 };
 
 struct ib_uverbs_query_srq_resp {
@@ -1269,7 +1269,7 @@ struct ib_uverbs_ex_create_rwq_ind_table  {
         * wq_handle1
         * wq_handle2
         */
-       __u32 wq_handles[0];
+       __u32 wq_handles[];
 };
 
 struct ib_uverbs_ex_create_rwq_ind_table_resp {
index ed5a514..7cea035 100644 (file)
@@ -184,7 +184,7 @@ struct rdma_ucm_query_addr_resp {
 struct rdma_ucm_query_path_resp {
        __u32 num_paths;
        __u32 reserved;
-       struct ib_path_rec_data path_data[0];
+       struct ib_path_rec_data path_data[];
 };
 
 struct rdma_ucm_conn_param {
index 38ab7ac..ab1aef1 100644 (file)
@@ -81,7 +81,7 @@ struct ib_uverbs_ioctl_hdr {
        __aligned_u64 reserved1;
        __u32 driver_id;
        __u32 reserved2;
-       struct ib_uverbs_attr  attrs[0];
+       struct ib_uverbs_attr  attrs[];
 };
 
 #endif
index c9812c5..16782c3 100644 (file)
@@ -264,7 +264,7 @@ struct fc_tlv_desc {
                                         * Size of descriptor excluding
                                         * desc_tag and desc_len fields.
                                         */
-       __u8            desc_value[0];  /* Descriptor Value */
+       __u8            desc_value[];  /* Descriptor Value */
 };
 
 /* Descriptor tag and len fields are considered the mandatory header
@@ -1027,7 +1027,7 @@ struct fc_fn_li_desc {
                                         * threshold to caause the LI event
                                         */
        __be32          pname_count;    /* number of portname_list elements */
-       __be64          pname_list[0];  /* list of N_Port_Names accessible
+       __be64          pname_list[];   /* list of N_Port_Names accessible
                                         * through the attached port
                                         */
 };
@@ -1069,7 +1069,7 @@ struct fc_fn_peer_congn_desc {
                                         * congestion event
                                         */
        __be32          pname_count;    /* number of portname_list elements */
-       __be64          pname_list[0];  /* list of N_Port_Names accessible
+       __be64          pname_list[];   /* list of N_Port_Names accessible
                                         * through the attached port
                                         */
 };
@@ -1104,7 +1104,7 @@ struct fc_els_fpin {
                                         * Size of ELS excluding fpin_cmd,
                                         * fpin_zero and desc_len fields.
                                         */
-       struct fc_tlv_desc      fpin_desc[0];   /* Descriptor list */
+       struct fc_tlv_desc      fpin_desc[];    /* Descriptor list */
 };
 
 /* Diagnostic Function Descriptor - FPIN Registration */
@@ -1115,7 +1115,7 @@ struct fc_df_desc_fpin_reg {
                                         * desc_tag and desc_len fields.
                                         */
        __be32          count;          /* Number of desc_tags elements */
-       __be32          desc_tags[0];   /* Array of Descriptor Tags.
+       __be32          desc_tags[];    /* Array of Descriptor Tags.
                                         * Each tag indicates a function
                                         * supported by the N_Port (request)
                                         * or by the  N_Port and Fabric
@@ -1135,7 +1135,7 @@ struct fc_els_rdf {
                                         * Size of ELS excluding fpin_cmd,
                                         * fpin_zero and desc_len fields.
                                         */
-       struct fc_tlv_desc      desc[0];        /* Descriptor list */
+       struct fc_tlv_desc      desc[]; /* Descriptor list */
 };
 
 /*
@@ -1148,7 +1148,7 @@ struct fc_els_rdf_resp {
                                                 * and desc_list_len fields.
                                                 */
        struct fc_els_lsri_desc lsri;
-       struct fc_tlv_desc      desc[0];        /* Supported Descriptor list */
+       struct fc_tlv_desc      desc[]; /* Supported Descriptor list */
 };
 
 
@@ -1231,7 +1231,7 @@ struct fc_els_edc {
                                         * Size of ELS excluding edc_cmd,
                                         * edc_zero and desc_len fields.
                                         */
-       struct fc_tlv_desc      desc[0];
+       struct fc_tlv_desc      desc[];
                                        /* Diagnostic Descriptor list */
 };
 
@@ -1245,7 +1245,7 @@ struct fc_els_edc_resp {
                                                 * and desc_list_len fields.
                                                 */
        struct fc_els_lsri_desc lsri;
-       struct fc_tlv_desc      desc[0];
+       struct fc_tlv_desc      desc[];
                                    /* Supported Diagnostic Descriptor list */
 };
 
index 3ae65e9..7f59308 100644 (file)
@@ -209,7 +209,7 @@ struct fc_bsg_host_vendor {
        __u64 vendor_id;
 
        /* start of vendor command area */
-       __u32 vendor_cmd[0];
+       __u32 vendor_cmd[];
 };
 
 /* Response:
index 2d3e5df..3974a2a 100644 (file)
@@ -1106,7 +1106,7 @@ struct snd_ctl_elem_value {
 struct snd_ctl_tlv {
        unsigned int numid;     /* control element numeric identification */
        unsigned int length;    /* in bytes aligned to 4 */
-       unsigned int tlv[0];    /* first TLV */
+       unsigned int tlv[];     /* first TLV */
 };
 
 #define SNDRV_CTL_IOCTL_PVERSION       _IOR('U', 0x00, int)
index 39cf6eb..3532ac7 100644 (file)
@@ -38,11 +38,11 @@ struct snd_efw_transaction {
        __be32 category;
        __be32 command;
        __be32 status;
-       __be32 params[0];
+       __be32 params[];
 };
 struct snd_firewire_event_efw_response {
        unsigned int type;
-       __be32 response[0];     /* some responses */
+       __be32 response[];      /* some responses */
 };
 
 struct snd_firewire_event_digi00x_message {
@@ -63,7 +63,7 @@ struct snd_firewire_tascam_change {
 
 struct snd_firewire_event_tascam_control {
        unsigned int type;
-       struct snd_firewire_tascam_change changes[0];
+       struct snd_firewire_tascam_change changes[];
 };
 
 struct snd_firewire_event_motu_register_dsp_change {
index a93c0de..f29899b 100644 (file)
@@ -151,7 +151,7 @@ struct skl_dfw_algo_data {
        __u32 rsvd:30;
        __u32 param_id;
        __u32 max;
-       char params[0];
+       char params[];
 } __packed;
 
 enum skl_tkn_dir {
index 5f4518e..dbf1375 100644 (file)
@@ -23,7 +23,7 @@ struct sof_abi_hdr {
        __u32 size;             /**< size in bytes of data excl. this struct */
        __u32 abi;              /**< SOF ABI version */
        __u32 reserved[4];      /**< reserved for future use */
-       __u32 data[0];          /**< Component data - opaque to core */
+       __u32 data[];           /**< Component data - opaque to core */
 }  __packed;
 
 #endif
index 95419d8..ffdd3ea 100644 (file)
@@ -61,7 +61,7 @@ struct usb_stream {
        unsigned                 inpacket_split_at;
        unsigned                 next_inpacket_split;
        unsigned                 next_inpacket_split_at;
-       struct usb_stream_packet inpacket[0];
+       struct usb_stream_packet inpacket[];
 };
 
 enum usb_stream_state {
index e1126a7..eff166f 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef __LINUX_OF_DISPLAY_TIMING_H
 #define __LINUX_OF_DISPLAY_TIMING_H
 
+#include <linux/errno.h>
+
 struct device_node;
 struct display_timing;
 struct display_timings;
index c7900e8..8c9ad53 100644 (file)
@@ -414,7 +414,7 @@ config WATCH_QUEUE
          with watches for key/keyring change notifications and device
          notifications.
 
-         See Documentation/watch_queue.rst
+         See Documentation/core-api/watch_queue.rst
 
 config CROSS_MEMORY_ATTACH
        bool "Enable process_vm_readv/writev syscalls"
@@ -494,11 +494,11 @@ config VIRT_CPU_ACCOUNTING_NATIVE
 
 config VIRT_CPU_ACCOUNTING_GEN
        bool "Full dynticks CPU time accounting"
-       depends on HAVE_CONTEXT_TRACKING
+       depends on HAVE_CONTEXT_TRACKING_USER
        depends on HAVE_VIRT_CPU_ACCOUNTING_GEN
        depends on GENERIC_CLOCKEVENTS
        select VIRT_CPU_ACCOUNTING
-       select CONTEXT_TRACKING
+       select CONTEXT_TRACKING_USER
        help
          Select this option to enable task and CPU time accounting on full
          dynticks systems. This accounting is implemented by watching every
@@ -945,6 +945,16 @@ if CGROUPS
 config PAGE_COUNTER
        bool
 
+config CGROUP_FAVOR_DYNMODS
+        bool "Favor dynamic modification latency reduction by default"
+        help
+          This option enables the "favordynmods" mount option by default
+          which reduces the latencies of dynamic cgroup modifications such
+          as task migrations and controller on/offs at the cost of making
+          hot path operations such as forks and exits more expensive.
+
+          Say N if unsure.
+
 config MEMCG
        bool "Memory controller"
        select PAGE_COUNTER
@@ -1481,6 +1491,7 @@ config HAVE_PCSPKR_PLATFORM
 # interpreter that classic socket filters depend on
 config BPF
        bool
+       select CRYPTO_LIB_SHA1
 
 menuconfig EXPERT
        bool "Configure standard kernel features (expert users)"
index 73cc8f0..ff6c4b9 100644 (file)
@@ -157,6 +157,7 @@ struct task_struct init_task
        .trc_reader_nesting = 0,
        .trc_reader_special.s = 0,
        .trc_holdout_list = LIST_HEAD_INIT(init_task.trc_holdout_list),
+       .trc_blkd_node = LIST_HEAD_INIT(init_task.trc_blkd_node),
 #endif
 #ifdef CONFIG_CPUSETS
        .mems_allowed_seq = SEQCNT_SPINLOCK_ZERO(init_task.mems_allowed_seq,
index 0ee39cd..91642a4 100644 (file)
@@ -99,6 +99,7 @@
 #include <linux/kcsan.h>
 #include <linux/init_syscalls.h>
 #include <linux/stackdepot.h>
+#include <linux/randomize_kstack.h>
 #include <net/net_namespace.h>
 
 #include <asm/io.h>
diff --git a/io_uring/Makefile b/io_uring/Makefile
new file mode 100644 (file)
index 0000000..8cc8e53
--- /dev/null
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for io_uring
+
+obj-$(CONFIG_IO_URING)         += io_uring.o xattr.o nop.o fs.o splice.o \
+                                       sync.o advise.o filetable.o \
+                                       openclose.o uring_cmd.o epoll.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
+obj-$(CONFIG_IO_WQ)            += io-wq.o
diff --git a/io_uring/advise.c b/io_uring/advise.c
new file mode 100644 (file)
index 0000000..5819569
--- /dev/null
@@ -0,0 +1,99 @@
+// 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/namei.h>
+#include <linux/io_uring.h>
+
+#include <uapi/linux/fadvise.h>
+#include <uapi/linux/io_uring.h>
+
+#include "io_uring.h"
+#include "advise.h"
+
+struct io_fadvise {
+       struct file                     *file;
+       u64                             offset;
+       u32                             len;
+       u32                             advice;
+};
+
+struct io_madvise {
+       struct file                     *file;
+       u64                             addr;
+       u32                             len;
+       u32                             advice;
+};
+
+int io_madvise_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+#if defined(CONFIG_ADVISE_SYSCALLS) && defined(CONFIG_MMU)
+       struct io_madvise *ma = io_kiocb_to_cmd(req);
+
+       if (sqe->buf_index || sqe->off || sqe->splice_fd_in)
+               return -EINVAL;
+
+       ma->addr = READ_ONCE(sqe->addr);
+       ma->len = READ_ONCE(sqe->len);
+       ma->advice = READ_ONCE(sqe->fadvise_advice);
+       return 0;
+#else
+       return -EOPNOTSUPP;
+#endif
+}
+
+int io_madvise(struct io_kiocb *req, unsigned int issue_flags)
+{
+#if defined(CONFIG_ADVISE_SYSCALLS) && defined(CONFIG_MMU)
+       struct io_madvise *ma = io_kiocb_to_cmd(req);
+       int ret;
+
+       if (issue_flags & IO_URING_F_NONBLOCK)
+               return -EAGAIN;
+
+       ret = do_madvise(current->mm, ma->addr, ma->len, ma->advice);
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+#else
+       return -EOPNOTSUPP;
+#endif
+}
+
+int io_fadvise_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_fadvise *fa = io_kiocb_to_cmd(req);
+
+       if (sqe->buf_index || sqe->addr || sqe->splice_fd_in)
+               return -EINVAL;
+
+       fa->offset = READ_ONCE(sqe->off);
+       fa->len = READ_ONCE(sqe->len);
+       fa->advice = READ_ONCE(sqe->fadvise_advice);
+       return 0;
+}
+
+int io_fadvise(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_fadvise *fa = io_kiocb_to_cmd(req);
+       int ret;
+
+       if (issue_flags & IO_URING_F_NONBLOCK) {
+               switch (fa->advice) {
+               case POSIX_FADV_NORMAL:
+               case POSIX_FADV_RANDOM:
+               case POSIX_FADV_SEQUENTIAL:
+                       break;
+               default:
+                       return -EAGAIN;
+               }
+       }
+
+       ret = vfs_fadvise(req->file, fa->offset, fa->len, fa->advice);
+       if (ret < 0)
+               req_set_fail(req);
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
diff --git a/io_uring/advise.h b/io_uring/advise.h
new file mode 100644 (file)
index 0000000..5ece2a0
--- /dev/null
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+
+int io_madvise_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_madvise(struct io_kiocb *req, unsigned int issue_flags);
+
+int io_fadvise_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_fadvise(struct io_kiocb *req, unsigned int issue_flags);
diff --git a/io_uring/alloc_cache.h b/io_uring/alloc_cache.h
new file mode 100644 (file)
index 0000000..729793a
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef IOU_ALLOC_CACHE_H
+#define IOU_ALLOC_CACHE_H
+
+/*
+ * Don't allow the cache to grow beyond this size.
+ */
+#define IO_ALLOC_CACHE_MAX     512
+
+struct io_cache_entry {
+       struct hlist_node       node;
+};
+
+static inline bool io_alloc_cache_put(struct io_alloc_cache *cache,
+                                     struct io_cache_entry *entry)
+{
+       if (cache->nr_cached < IO_ALLOC_CACHE_MAX) {
+               cache->nr_cached++;
+               hlist_add_head(&entry->node, &cache->list);
+               return true;
+       }
+       return false;
+}
+
+static inline struct io_cache_entry *io_alloc_cache_get(struct io_alloc_cache *cache)
+{
+       if (!hlist_empty(&cache->list)) {
+               struct hlist_node *node = cache->list.first;
+
+               hlist_del(node);
+               return container_of(node, struct io_cache_entry, node);
+       }
+
+       return NULL;
+}
+
+static inline void io_alloc_cache_init(struct io_alloc_cache *cache)
+{
+       INIT_HLIST_HEAD(&cache->list);
+       cache->nr_cached = 0;
+}
+
+static inline void io_alloc_cache_free(struct io_alloc_cache *cache,
+                                       void (*free)(struct io_cache_entry *))
+{
+       while (!hlist_empty(&cache->list)) {
+               struct hlist_node *node = cache->list.first;
+
+               hlist_del(node);
+               free(container_of(node, struct io_cache_entry, node));
+       }
+       cache->nr_cached = 0;
+}
+#endif
diff --git a/io_uring/cancel.c b/io_uring/cancel.c
new file mode 100644 (file)
index 0000000..8435a1e
--- /dev/null
@@ -0,0 +1,315 @@
+// 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/namei.h>
+#include <linux/nospec.h>
+#include <linux/io_uring.h>
+
+#include <uapi/linux/io_uring.h>
+
+#include "io_uring.h"
+#include "tctx.h"
+#include "poll.h"
+#include "timeout.h"
+#include "cancel.h"
+
+struct io_cancel {
+       struct file                     *file;
+       u64                             addr;
+       u32                             flags;
+       s32                             fd;
+};
+
+#define CANCEL_FLAGS   (IORING_ASYNC_CANCEL_ALL | IORING_ASYNC_CANCEL_FD | \
+                        IORING_ASYNC_CANCEL_ANY | IORING_ASYNC_CANCEL_FD_FIXED)
+
+static bool io_cancel_cb(struct io_wq_work *work, void *data)
+{
+       struct io_kiocb *req = container_of(work, struct io_kiocb, work);
+       struct io_cancel_data *cd = data;
+
+       if (req->ctx != cd->ctx)
+               return false;
+       if (cd->flags & IORING_ASYNC_CANCEL_ANY) {
+               ;
+       } else if (cd->flags & IORING_ASYNC_CANCEL_FD) {
+               if (req->file != cd->file)
+                       return false;
+       } else {
+               if (req->cqe.user_data != cd->data)
+                       return false;
+       }
+       if (cd->flags & (IORING_ASYNC_CANCEL_ALL|IORING_ASYNC_CANCEL_ANY)) {
+               if (cd->seq == req->work.cancel_seq)
+                       return false;
+               req->work.cancel_seq = cd->seq;
+       }
+       return true;
+}
+
+static int io_async_cancel_one(struct io_uring_task *tctx,
+                              struct io_cancel_data *cd)
+{
+       enum io_wq_cancel cancel_ret;
+       int ret = 0;
+       bool all;
+
+       if (!tctx || !tctx->io_wq)
+               return -ENOENT;
+
+       all = cd->flags & (IORING_ASYNC_CANCEL_ALL|IORING_ASYNC_CANCEL_ANY);
+       cancel_ret = io_wq_cancel_cb(tctx->io_wq, io_cancel_cb, cd, all);
+       switch (cancel_ret) {
+       case IO_WQ_CANCEL_OK:
+               ret = 0;
+               break;
+       case IO_WQ_CANCEL_RUNNING:
+               ret = -EALREADY;
+               break;
+       case IO_WQ_CANCEL_NOTFOUND:
+               ret = -ENOENT;
+               break;
+       }
+
+       return ret;
+}
+
+int io_try_cancel(struct io_uring_task *tctx, struct io_cancel_data *cd,
+                 unsigned issue_flags)
+{
+       struct io_ring_ctx *ctx = cd->ctx;
+       int ret;
+
+       WARN_ON_ONCE(!io_wq_current_is_worker() && tctx != current->io_uring);
+
+       ret = io_async_cancel_one(tctx, cd);
+       /*
+        * Fall-through even for -EALREADY, as we may have poll armed
+        * that need unarming.
+        */
+       if (!ret)
+               return 0;
+
+       ret = io_poll_cancel(ctx, cd, issue_flags);
+       if (ret != -ENOENT)
+               return ret;
+
+       spin_lock(&ctx->completion_lock);
+       if (!(cd->flags & IORING_ASYNC_CANCEL_FD))
+               ret = io_timeout_cancel(ctx, cd);
+       spin_unlock(&ctx->completion_lock);
+       return ret;
+}
+
+int io_async_cancel_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_cancel *cancel = io_kiocb_to_cmd(req);
+
+       if (unlikely(req->flags & REQ_F_BUFFER_SELECT))
+               return -EINVAL;
+       if (sqe->off || sqe->len || sqe->splice_fd_in)
+               return -EINVAL;
+
+       cancel->addr = READ_ONCE(sqe->addr);
+       cancel->flags = READ_ONCE(sqe->cancel_flags);
+       if (cancel->flags & ~CANCEL_FLAGS)
+               return -EINVAL;
+       if (cancel->flags & IORING_ASYNC_CANCEL_FD) {
+               if (cancel->flags & IORING_ASYNC_CANCEL_ANY)
+                       return -EINVAL;
+               cancel->fd = READ_ONCE(sqe->fd);
+       }
+
+       return 0;
+}
+
+static int __io_async_cancel(struct io_cancel_data *cd,
+                            struct io_uring_task *tctx,
+                            unsigned int issue_flags)
+{
+       bool all = cd->flags & (IORING_ASYNC_CANCEL_ALL|IORING_ASYNC_CANCEL_ANY);
+       struct io_ring_ctx *ctx = cd->ctx;
+       struct io_tctx_node *node;
+       int ret, nr = 0;
+
+       do {
+               ret = io_try_cancel(tctx, cd, issue_flags);
+               if (ret == -ENOENT)
+                       break;
+               if (!all)
+                       return ret;
+               nr++;
+       } while (1);
+
+       /* slow path, try all io-wq's */
+       io_ring_submit_lock(ctx, issue_flags);
+       ret = -ENOENT;
+       list_for_each_entry(node, &ctx->tctx_list, ctx_node) {
+               struct io_uring_task *tctx = node->task->io_uring;
+
+               ret = io_async_cancel_one(tctx, cd);
+               if (ret != -ENOENT) {
+                       if (!all)
+                               break;
+                       nr++;
+               }
+       }
+       io_ring_submit_unlock(ctx, issue_flags);
+       return all ? nr : ret;
+}
+
+int io_async_cancel(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_cancel *cancel = io_kiocb_to_cmd(req);
+       struct io_cancel_data cd = {
+               .ctx    = req->ctx,
+               .data   = cancel->addr,
+               .flags  = cancel->flags,
+               .seq    = atomic_inc_return(&req->ctx->cancel_seq),
+       };
+       struct io_uring_task *tctx = req->task->io_uring;
+       int ret;
+
+       if (cd.flags & IORING_ASYNC_CANCEL_FD) {
+               if (req->flags & REQ_F_FIXED_FILE ||
+                   cd.flags & IORING_ASYNC_CANCEL_FD_FIXED) {
+                       req->flags |= REQ_F_FIXED_FILE;
+                       req->file = io_file_get_fixed(req, cancel->fd,
+                                                       issue_flags);
+               } else {
+                       req->file = io_file_get_normal(req, cancel->fd);
+               }
+               if (!req->file) {
+                       ret = -EBADF;
+                       goto done;
+               }
+               cd.file = req->file;
+       }
+
+       ret = __io_async_cancel(&cd, tctx, issue_flags);
+done:
+       if (ret < 0)
+               req_set_fail(req);
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
+
+void init_hash_table(struct io_hash_table *table, unsigned size)
+{
+       unsigned int i;
+
+       for (i = 0; i < size; i++) {
+               spin_lock_init(&table->hbs[i].lock);
+               INIT_HLIST_HEAD(&table->hbs[i].list);
+       }
+}
+
+static int __io_sync_cancel(struct io_uring_task *tctx,
+                           struct io_cancel_data *cd, int fd)
+{
+       struct io_ring_ctx *ctx = cd->ctx;
+
+       /* fixed must be grabbed every time since we drop the uring_lock */
+       if ((cd->flags & IORING_ASYNC_CANCEL_FD) &&
+           (cd->flags & IORING_ASYNC_CANCEL_FD_FIXED)) {
+               unsigned long file_ptr;
+
+               if (unlikely(fd > ctx->nr_user_files))
+                       return -EBADF;
+               fd = array_index_nospec(fd, ctx->nr_user_files);
+               file_ptr = io_fixed_file_slot(&ctx->file_table, fd)->file_ptr;
+               cd->file = (struct file *) (file_ptr & FFS_MASK);
+               if (!cd->file)
+                       return -EBADF;
+       }
+
+       return __io_async_cancel(cd, tctx, 0);
+}
+
+int io_sync_cancel(struct io_ring_ctx *ctx, void __user *arg)
+       __must_hold(&ctx->uring_lock)
+{
+       struct io_cancel_data cd = {
+               .ctx    = ctx,
+               .seq    = atomic_inc_return(&ctx->cancel_seq),
+       };
+       ktime_t timeout = KTIME_MAX;
+       struct io_uring_sync_cancel_reg sc;
+       struct fd f = { };
+       DEFINE_WAIT(wait);
+       int ret;
+
+       if (copy_from_user(&sc, arg, sizeof(sc)))
+               return -EFAULT;
+       if (sc.flags & ~CANCEL_FLAGS)
+               return -EINVAL;
+       if (sc.pad[0] || sc.pad[1] || sc.pad[2] || sc.pad[3])
+               return -EINVAL;
+
+       cd.data = sc.addr;
+       cd.flags = sc.flags;
+
+       /* we can grab a normal file descriptor upfront */
+       if ((cd.flags & IORING_ASYNC_CANCEL_FD) &&
+          !(cd.flags & IORING_ASYNC_CANCEL_FD_FIXED)) {
+               f = fdget(sc.fd);
+               if (!f.file)
+                       return -EBADF;
+               cd.file = f.file;
+       }
+
+       ret = __io_sync_cancel(current->io_uring, &cd, sc.fd);
+
+       /* found something, done! */
+       if (ret != -EALREADY)
+               goto out;
+
+       if (sc.timeout.tv_sec != -1UL || sc.timeout.tv_nsec != -1UL) {
+               struct timespec64 ts = {
+                       .tv_sec         = sc.timeout.tv_sec,
+                       .tv_nsec        = sc.timeout.tv_nsec
+               };
+
+               timeout = ktime_add_ns(timespec64_to_ktime(ts), ktime_get_ns());
+       }
+
+       /*
+        * Keep looking until we get -ENOENT. we'll get woken everytime
+        * every time a request completes and will retry the cancelation.
+        */
+       do {
+               cd.seq = atomic_inc_return(&ctx->cancel_seq);
+
+               prepare_to_wait(&ctx->cq_wait, &wait, TASK_INTERRUPTIBLE);
+
+               ret = __io_sync_cancel(current->io_uring, &cd, sc.fd);
+
+               if (ret != -EALREADY)
+                       break;
+
+               mutex_unlock(&ctx->uring_lock);
+               ret = io_run_task_work_sig();
+               if (ret < 0) {
+                       mutex_lock(&ctx->uring_lock);
+                       break;
+               }
+               ret = schedule_hrtimeout(&timeout, HRTIMER_MODE_ABS);
+               mutex_lock(&ctx->uring_lock);
+               if (!ret) {
+                       ret = -ETIME;
+                       break;
+               }
+       } while (1);
+
+       finish_wait(&ctx->cq_wait, &wait);
+
+       if (ret == -ENOENT || ret > 0)
+               ret = 0;
+out:
+       fdput(f);
+       return ret;
+}
diff --git a/io_uring/cancel.h b/io_uring/cancel.h
new file mode 100644 (file)
index 0000000..6a59ee4
--- /dev/null
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/io_uring_types.h>
+
+struct io_cancel_data {
+       struct io_ring_ctx *ctx;
+       union {
+               u64 data;
+               struct file *file;
+       };
+       u32 flags;
+       int seq;
+};
+
+
+int io_async_cancel_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_async_cancel(struct io_kiocb *req, unsigned int issue_flags);
+
+int io_try_cancel(struct io_uring_task *tctx, struct io_cancel_data *cd,
+                 unsigned int issue_flags);
+void init_hash_table(struct io_hash_table *table, unsigned size);
+
+int io_sync_cancel(struct io_ring_ctx *ctx, void __user *arg);
diff --git a/io_uring/epoll.c b/io_uring/epoll.c
new file mode 100644 (file)
index 0000000..a8b7944
--- /dev/null
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/io_uring.h>
+#include <linux/eventpoll.h>
+
+#include <uapi/linux/io_uring.h>
+
+#include "io_uring.h"
+#include "epoll.h"
+
+#if defined(CONFIG_EPOLL)
+struct io_epoll {
+       struct file                     *file;
+       int                             epfd;
+       int                             op;
+       int                             fd;
+       struct epoll_event              event;
+};
+
+int io_epoll_ctl_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_epoll *epoll = io_kiocb_to_cmd(req);
+
+       pr_warn_once("%s: epoll_ctl support in io_uring is deprecated and will "
+                    "be removed in a future Linux kernel version.\n",
+                    current->comm);
+
+       if (sqe->buf_index || sqe->splice_fd_in)
+               return -EINVAL;
+
+       epoll->epfd = READ_ONCE(sqe->fd);
+       epoll->op = READ_ONCE(sqe->len);
+       epoll->fd = READ_ONCE(sqe->off);
+
+       if (ep_op_has_event(epoll->op)) {
+               struct epoll_event __user *ev;
+
+               ev = u64_to_user_ptr(READ_ONCE(sqe->addr));
+               if (copy_from_user(&epoll->event, ev, sizeof(*ev)))
+                       return -EFAULT;
+       }
+
+       return 0;
+}
+
+int io_epoll_ctl(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_epoll *ie = io_kiocb_to_cmd(req);
+       int ret;
+       bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK;
+
+       ret = do_epoll_ctl(ie->epfd, ie->op, ie->fd, &ie->event, force_nonblock);
+       if (force_nonblock && ret == -EAGAIN)
+               return -EAGAIN;
+
+       if (ret < 0)
+               req_set_fail(req);
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
+#endif
diff --git a/io_uring/epoll.h b/io_uring/epoll.h
new file mode 100644 (file)
index 0000000..870cce1
--- /dev/null
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#if defined(CONFIG_EPOLL)
+int io_epoll_ctl_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_epoll_ctl(struct io_kiocb *req, unsigned int issue_flags);
+#endif
diff --git a/io_uring/fdinfo.c b/io_uring/fdinfo.c
new file mode 100644 (file)
index 0000000..b29e2d0
--- /dev/null
@@ -0,0 +1,194 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/io_uring.h>
+
+#include <uapi/linux/io_uring.h>
+
+#include "io_uring.h"
+#include "sqpoll.h"
+#include "fdinfo.h"
+#include "cancel.h"
+#include "rsrc.h"
+
+#ifdef CONFIG_PROC_FS
+static __cold int io_uring_show_cred(struct seq_file *m, unsigned int id,
+               const struct cred *cred)
+{
+       struct user_namespace *uns = seq_user_ns(m);
+       struct group_info *gi;
+       kernel_cap_t cap;
+       unsigned __capi;
+       int g;
+
+       seq_printf(m, "%5d\n", id);
+       seq_put_decimal_ull(m, "\tUid:\t", from_kuid_munged(uns, cred->uid));
+       seq_put_decimal_ull(m, "\t\t", from_kuid_munged(uns, cred->euid));
+       seq_put_decimal_ull(m, "\t\t", from_kuid_munged(uns, cred->suid));
+       seq_put_decimal_ull(m, "\t\t", from_kuid_munged(uns, cred->fsuid));
+       seq_put_decimal_ull(m, "\n\tGid:\t", from_kgid_munged(uns, cred->gid));
+       seq_put_decimal_ull(m, "\t\t", from_kgid_munged(uns, cred->egid));
+       seq_put_decimal_ull(m, "\t\t", from_kgid_munged(uns, cred->sgid));
+       seq_put_decimal_ull(m, "\t\t", from_kgid_munged(uns, cred->fsgid));
+       seq_puts(m, "\n\tGroups:\t");
+       gi = cred->group_info;
+       for (g = 0; g < gi->ngroups; g++) {
+               seq_put_decimal_ull(m, g ? " " : "",
+                                       from_kgid_munged(uns, gi->gid[g]));
+       }
+       seq_puts(m, "\n\tCapEff:\t");
+       cap = cred->cap_effective;
+       CAP_FOR_EACH_U32(__capi)
+               seq_put_hex_ll(m, NULL, cap.cap[CAP_LAST_U32 - __capi], 8);
+       seq_putc(m, '\n');
+       return 0;
+}
+
+static __cold void __io_uring_show_fdinfo(struct io_ring_ctx *ctx,
+                                         struct seq_file *m)
+{
+       struct io_sq_data *sq = NULL;
+       struct io_overflow_cqe *ocqe;
+       struct io_rings *r = ctx->rings;
+       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);
+       unsigned int cq_head = READ_ONCE(r->cq.head);
+       unsigned int cq_tail = READ_ONCE(r->cq.tail);
+       unsigned int cq_shift = 0;
+       unsigned int sq_entries, cq_entries;
+       bool has_lock;
+       bool is_cqe32 = (ctx->flags & IORING_SETUP_CQE32);
+       unsigned int i;
+
+       if (is_cqe32)
+               cq_shift = 1;
+
+       /*
+        * we may get imprecise sqe and cqe info if uring is actively running
+        * since we get cached_sq_head and cached_cq_tail without uring_lock
+        * and sq_tail and cq_head are changed by userspace. But it's ok since
+        * we usually use these info when it is stuck.
+        */
+       seq_printf(m, "SqMask:\t0x%x\n", sq_mask);
+       seq_printf(m, "SqHead:\t%u\n", sq_head);
+       seq_printf(m, "SqTail:\t%u\n", sq_tail);
+       seq_printf(m, "CachedSqHead:\t%u\n", ctx->cached_sq_head);
+       seq_printf(m, "CqMask:\t0x%x\n", cq_mask);
+       seq_printf(m, "CqHead:\t%u\n", cq_head);
+       seq_printf(m, "CqTail:\t%u\n", cq_tail);
+       seq_printf(m, "CachedCqTail:\t%u\n", ctx->cached_cq_tail);
+       seq_printf(m, "SQEs:\t%u\n", sq_tail - ctx->cached_sq_head);
+       sq_entries = min(sq_tail - sq_head, ctx->sq_entries);
+       for (i = 0; i < sq_entries; i++) {
+               unsigned int entry = i + sq_head;
+               unsigned int sq_idx = READ_ONCE(ctx->sq_array[entry & sq_mask]);
+               struct io_uring_sqe *sqe;
+
+               if (sq_idx > sq_mask)
+                       continue;
+               sqe = &ctx->sq_sqes[sq_idx];
+               seq_printf(m, "%5u: opcode:%d, fd:%d, flags:%x, user_data:%llu\n",
+                          sq_idx, sqe->opcode, sqe->fd, sqe->flags,
+                          sqe->user_data);
+       }
+       seq_printf(m, "CQEs:\t%u\n", cq_tail - cq_head);
+       cq_entries = min(cq_tail - cq_head, ctx->cq_entries);
+       for (i = 0; i < cq_entries; i++) {
+               unsigned int entry = i + cq_head;
+               struct io_uring_cqe *cqe = &r->cqes[(entry & cq_mask) << cq_shift];
+
+               if (!is_cqe32) {
+                       seq_printf(m, "%5u: user_data:%llu, res:%d, flag:%x\n",
+                          entry & cq_mask, cqe->user_data, cqe->res,
+                          cqe->flags);
+               } else {
+                       seq_printf(m, "%5u: user_data:%llu, res:%d, flag:%x, "
+                               "extra1:%llu, extra2:%llu\n",
+                               entry & cq_mask, cqe->user_data, cqe->res,
+                               cqe->flags, cqe->big_cqe[0], cqe->big_cqe[1]);
+               }
+       }
+
+       /*
+        * Avoid ABBA deadlock between the seq lock and the io_uring mutex,
+        * since fdinfo case grabs it in the opposite direction of normal use
+        * cases. If we fail to get the lock, we just don't iterate any
+        * structures that could be going away outside the io_uring mutex.
+        */
+       has_lock = mutex_trylock(&ctx->uring_lock);
+
+       if (has_lock && (ctx->flags & IORING_SETUP_SQPOLL)) {
+               sq = ctx->sq_data;
+               if (!sq->thread)
+                       sq = NULL;
+       }
+
+       seq_printf(m, "SqThread:\t%d\n", sq ? task_pid_nr(sq->thread) : -1);
+       seq_printf(m, "SqThreadCpu:\t%d\n", sq ? task_cpu(sq->thread) : -1);
+       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);
+
+               if (f)
+                       seq_printf(m, "%5u: %s\n", i, file_dentry(f)->d_iname);
+               else
+                       seq_printf(m, "%5u: <none>\n", i);
+       }
+       seq_printf(m, "UserBufs:\t%u\n", ctx->nr_user_bufs);
+       for (i = 0; has_lock && i < ctx->nr_user_bufs; i++) {
+               struct io_mapped_ubuf *buf = ctx->user_bufs[i];
+               unsigned int len = buf->ubuf_end - buf->ubuf;
+
+               seq_printf(m, "%5u: 0x%llx/%u\n", i, buf->ubuf, len);
+       }
+       if (has_lock && !xa_empty(&ctx->personalities)) {
+               unsigned long index;
+               const struct cred *cred;
+
+               seq_printf(m, "Personalities:\n");
+               xa_for_each(&ctx->personalities, index, cred)
+                       io_uring_show_cred(m, index, cred);
+       }
+       if (has_lock)
+               mutex_unlock(&ctx->uring_lock);
+
+       seq_puts(m, "PollList:\n");
+       for (i = 0; i < (1U << ctx->cancel_table.hash_bits); i++) {
+               struct io_hash_bucket *hb = &ctx->cancel_table.hbs[i];
+               struct io_kiocb *req;
+
+               spin_lock(&hb->lock);
+               hlist_for_each_entry(req, &hb->list, hash_node)
+                       seq_printf(m, "  op=%d, task_works=%d\n", req->opcode,
+                                       task_work_pending(req->task));
+               spin_unlock(&hb->lock);
+       }
+
+       seq_puts(m, "CqOverflowList:\n");
+       spin_lock(&ctx->completion_lock);
+       list_for_each_entry(ocqe, &ctx->cq_overflow_list, list) {
+               struct io_uring_cqe *cqe = &ocqe->cqe;
+
+               seq_printf(m, "  user_data=%llu, res=%d, flags=%x\n",
+                          cqe->user_data, cqe->res, cqe->flags);
+
+       }
+
+       spin_unlock(&ctx->completion_lock);
+}
+
+__cold void io_uring_show_fdinfo(struct seq_file *m, struct file *f)
+{
+       struct io_ring_ctx *ctx = f->private_data;
+
+       if (percpu_ref_tryget(&ctx->refs)) {
+               __io_uring_show_fdinfo(ctx, m);
+               percpu_ref_put(&ctx->refs);
+       }
+}
+#endif
diff --git a/io_uring/fdinfo.h b/io_uring/fdinfo.h
new file mode 100644 (file)
index 0000000..6fde48c
--- /dev/null
@@ -0,0 +1,3 @@
+// SPDX-License-Identifier: GPL-2.0
+
+void io_uring_show_fdinfo(struct seq_file *m, struct file *f);
diff --git a/io_uring/filetable.c b/io_uring/filetable.c
new file mode 100644 (file)
index 0000000..7b47325
--- /dev/null
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/file.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/nospec.h>
+#include <linux/io_uring.h>
+
+#include <uapi/linux/io_uring.h>
+
+#include "io_uring.h"
+#include "rsrc.h"
+#include "filetable.h"
+
+static int io_file_bitmap_get(struct io_ring_ctx *ctx)
+{
+       struct io_file_table *table = &ctx->file_table;
+       unsigned long nr = ctx->file_alloc_end;
+       int ret;
+
+       do {
+               ret = find_next_zero_bit(table->bitmap, nr, table->alloc_hint);
+               if (ret != nr)
+                       return ret;
+
+               if (table->alloc_hint == ctx->file_alloc_start)
+                       break;
+               nr = table->alloc_hint;
+               table->alloc_hint = ctx->file_alloc_start;
+       } while (1);
+
+       return -ENFILE;
+}
+
+bool io_alloc_file_tables(struct io_file_table *table, unsigned nr_files)
+{
+       table->files = kvcalloc(nr_files, sizeof(table->files[0]),
+                               GFP_KERNEL_ACCOUNT);
+       if (unlikely(!table->files))
+               return false;
+
+       table->bitmap = bitmap_zalloc(nr_files, GFP_KERNEL_ACCOUNT);
+       if (unlikely(!table->bitmap)) {
+               kvfree(table->files);
+               return false;
+       }
+
+       return true;
+}
+
+void io_free_file_tables(struct io_file_table *table)
+{
+       kvfree(table->files);
+       bitmap_free(table->bitmap);
+       table->files = NULL;
+       table->bitmap = NULL;
+}
+
+static int io_install_fixed_file(struct io_ring_ctx *ctx, struct file *file,
+                                u32 slot_index)
+       __must_hold(&req->ctx->uring_lock)
+{
+       bool needs_switch = false;
+       struct io_fixed_file *file_slot;
+       int ret;
+
+       if (io_is_uring_fops(file))
+               return -EBADF;
+       if (!ctx->file_data)
+               return -ENXIO;
+       if (slot_index >= ctx->nr_user_files)
+               return -EINVAL;
+
+       slot_index = array_index_nospec(slot_index, ctx->nr_user_files);
+       file_slot = io_fixed_file_slot(&ctx->file_table, slot_index);
+
+       if (file_slot->file_ptr) {
+               struct file *old_file;
+
+               ret = io_rsrc_node_switch_start(ctx);
+               if (ret)
+                       goto err;
+
+               old_file = (struct file *)(file_slot->file_ptr & FFS_MASK);
+               ret = io_queue_rsrc_removal(ctx->file_data, slot_index,
+                                           ctx->rsrc_node, old_file);
+               if (ret)
+                       goto err;
+               file_slot->file_ptr = 0;
+               io_file_bitmap_clear(&ctx->file_table, slot_index);
+               needs_switch = true;
+       }
+
+       ret = io_scm_file_account(ctx, file);
+       if (!ret) {
+               *io_get_tag_slot(ctx->file_data, slot_index) = 0;
+               io_fixed_file_set(file_slot, file);
+               io_file_bitmap_set(&ctx->file_table, slot_index);
+       }
+err:
+       if (needs_switch)
+               io_rsrc_node_switch(ctx, ctx->file_data);
+       if (ret)
+               fput(file);
+       return ret;
+}
+
+int __io_fixed_fd_install(struct io_ring_ctx *ctx, struct file *file,
+                         unsigned int file_slot)
+{
+       bool alloc_slot = file_slot == IORING_FILE_INDEX_ALLOC;
+       int ret;
+
+       if (alloc_slot) {
+               ret = io_file_bitmap_get(ctx);
+               if (unlikely(ret < 0))
+                       return ret;
+               file_slot = ret;
+       } else {
+               file_slot--;
+       }
+
+       ret = io_install_fixed_file(ctx, file, file_slot);
+       if (!ret && alloc_slot)
+               ret = file_slot;
+       return ret;
+}
+/*
+ * Note when io_fixed_fd_install() returns error value, it will ensure
+ * fput() is called correspondingly.
+ */
+int io_fixed_fd_install(struct io_kiocb *req, unsigned int issue_flags,
+                       struct file *file, unsigned int file_slot)
+{
+       struct io_ring_ctx *ctx = req->ctx;
+       int ret;
+
+       io_ring_submit_lock(ctx, issue_flags);
+       ret = __io_fixed_fd_install(ctx, file, file_slot);
+       io_ring_submit_unlock(ctx, issue_flags);
+
+       if (unlikely(ret < 0))
+               fput(file);
+       return ret;
+}
+
+int io_fixed_fd_remove(struct io_ring_ctx *ctx, unsigned int offset)
+{
+       struct io_fixed_file *file_slot;
+       struct file *file;
+       int ret;
+
+       if (unlikely(!ctx->file_data))
+               return -ENXIO;
+       if (offset >= ctx->nr_user_files)
+               return -EINVAL;
+       ret = io_rsrc_node_switch_start(ctx);
+       if (ret)
+               return ret;
+
+       offset = array_index_nospec(offset, ctx->nr_user_files);
+       file_slot = io_fixed_file_slot(&ctx->file_table, offset);
+       if (!file_slot->file_ptr)
+               return -EBADF;
+
+       file = (struct file *)(file_slot->file_ptr & FFS_MASK);
+       ret = io_queue_rsrc_removal(ctx->file_data, offset, ctx->rsrc_node, file);
+       if (ret)
+               return ret;
+
+       file_slot->file_ptr = 0;
+       io_file_bitmap_clear(&ctx->file_table, offset);
+       io_rsrc_node_switch(ctx, ctx->file_data);
+       return 0;
+}
+
+int io_register_file_alloc_range(struct io_ring_ctx *ctx,
+                                struct io_uring_file_index_range __user *arg)
+{
+       struct io_uring_file_index_range range;
+       u32 end;
+
+       if (copy_from_user(&range, arg, sizeof(range)))
+               return -EFAULT;
+       if (check_add_overflow(range.off, range.len, &end))
+               return -EOVERFLOW;
+       if (range.resv || end > ctx->nr_user_files)
+               return -EINVAL;
+
+       io_file_table_set_alloc_range(ctx, range.off, range.len);
+       return 0;
+}
diff --git a/io_uring/filetable.h b/io_uring/filetable.h
new file mode 100644 (file)
index 0000000..ff3a712
--- /dev/null
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0
+#ifndef IOU_FILE_TABLE_H
+#define IOU_FILE_TABLE_H
+
+#include <linux/file.h>
+#include <linux/io_uring_types.h>
+
+/*
+ * FFS_SCM is only available on 64-bit archs, for 32-bit we just define it as 0
+ * and define IO_URING_SCM_ALL. For this case, we use SCM for all files as we
+ * can't safely always dereference the file when the task has exited and ring
+ * cleanup is done. If a file is tracked and part of SCM, then unix gc on
+ * process exit may reap it before __io_sqe_files_unregister() is run.
+ */
+#define FFS_NOWAIT             0x1UL
+#define FFS_ISREG              0x2UL
+#if defined(CONFIG_64BIT)
+#define FFS_SCM                        0x4UL
+#else
+#define IO_URING_SCM_ALL
+#define FFS_SCM                        0x0UL
+#endif
+#define FFS_MASK               ~(FFS_NOWAIT|FFS_ISREG|FFS_SCM)
+
+bool io_alloc_file_tables(struct io_file_table *table, unsigned nr_files);
+void io_free_file_tables(struct io_file_table *table);
+
+int io_fixed_fd_install(struct io_kiocb *req, unsigned int issue_flags,
+                       struct file *file, unsigned int file_slot);
+int __io_fixed_fd_install(struct io_ring_ctx *ctx, struct file *file,
+                               unsigned int file_slot);
+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);
+
+static inline void io_file_bitmap_clear(struct io_file_table *table, int bit)
+{
+       __clear_bit(bit, table->bitmap);
+       table->alloc_hint = bit;
+}
+
+static inline void io_file_bitmap_set(struct io_file_table *table, int bit)
+{
+       WARN_ON_ONCE(test_bit(bit, table->bitmap));
+       __set_bit(bit, table->bitmap);
+       table->alloc_hint = bit + 1;
+}
+
+static inline struct io_fixed_file *
+io_fixed_file_slot(struct io_file_table *table, unsigned i)
+{
+       return &table->files[i];
+}
+
+static inline struct file *io_file_from_index(struct io_file_table *table,
+                                             int index)
+{
+       struct io_fixed_file *slot = io_fixed_file_slot(table, index);
+
+       return (struct file *) (slot->file_ptr & FFS_MASK);
+}
+
+static inline void io_fixed_file_set(struct io_fixed_file *file_slot,
+                                    struct file *file)
+{
+       unsigned long file_ptr = (unsigned long) file;
+
+       file_ptr |= io_file_get_flags(file);
+       file_slot->file_ptr = file_ptr;
+}
+
+static inline void io_reset_alloc_hint(struct io_ring_ctx *ctx)
+{
+       ctx->file_table.alloc_hint = ctx->file_alloc_start;
+}
+
+static inline void io_file_table_set_alloc_range(struct io_ring_ctx *ctx,
+                                                unsigned off, unsigned len)
+{
+       ctx->file_alloc_start = off;
+       ctx->file_alloc_end = off + len;
+       io_reset_alloc_hint(ctx);
+}
+
+#endif
diff --git a/io_uring/fs.c b/io_uring/fs.c
new file mode 100644 (file)
index 0000000..0de4f54
--- /dev/null
@@ -0,0 +1,293 @@
+// 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/namei.h>
+#include <linux/io_uring.h>
+
+#include <uapi/linux/io_uring.h>
+
+#include "../fs/internal.h"
+
+#include "io_uring.h"
+#include "fs.h"
+
+struct io_rename {
+       struct file                     *file;
+       int                             old_dfd;
+       int                             new_dfd;
+       struct filename                 *oldpath;
+       struct filename                 *newpath;
+       int                             flags;
+};
+
+struct io_unlink {
+       struct file                     *file;
+       int                             dfd;
+       int                             flags;
+       struct filename                 *filename;
+};
+
+struct io_mkdir {
+       struct file                     *file;
+       int                             dfd;
+       umode_t                         mode;
+       struct filename                 *filename;
+};
+
+struct io_link {
+       struct file                     *file;
+       int                             old_dfd;
+       int                             new_dfd;
+       struct filename                 *oldpath;
+       struct filename                 *newpath;
+       int                             flags;
+};
+
+int io_renameat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_rename *ren = io_kiocb_to_cmd(req);
+       const char __user *oldf, *newf;
+
+       if (sqe->buf_index || sqe->splice_fd_in)
+               return -EINVAL;
+       if (unlikely(req->flags & REQ_F_FIXED_FILE))
+               return -EBADF;
+
+       ren->old_dfd = READ_ONCE(sqe->fd);
+       oldf = u64_to_user_ptr(READ_ONCE(sqe->addr));
+       newf = u64_to_user_ptr(READ_ONCE(sqe->addr2));
+       ren->new_dfd = READ_ONCE(sqe->len);
+       ren->flags = READ_ONCE(sqe->rename_flags);
+
+       ren->oldpath = getname(oldf);
+       if (IS_ERR(ren->oldpath))
+               return PTR_ERR(ren->oldpath);
+
+       ren->newpath = getname(newf);
+       if (IS_ERR(ren->newpath)) {
+               putname(ren->oldpath);
+               return PTR_ERR(ren->newpath);
+       }
+
+       req->flags |= REQ_F_NEED_CLEANUP;
+       return 0;
+}
+
+int io_renameat(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_rename *ren = io_kiocb_to_cmd(req);
+       int ret;
+
+       if (issue_flags & IO_URING_F_NONBLOCK)
+               return -EAGAIN;
+
+       ret = do_renameat2(ren->old_dfd, ren->oldpath, ren->new_dfd,
+                               ren->newpath, ren->flags);
+
+       req->flags &= ~REQ_F_NEED_CLEANUP;
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
+
+void io_renameat_cleanup(struct io_kiocb *req)
+{
+       struct io_rename *ren = io_kiocb_to_cmd(req);
+
+       putname(ren->oldpath);
+       putname(ren->newpath);
+}
+
+int io_unlinkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_unlink *un = io_kiocb_to_cmd(req);
+       const char __user *fname;
+
+       if (sqe->off || sqe->len || sqe->buf_index || sqe->splice_fd_in)
+               return -EINVAL;
+       if (unlikely(req->flags & REQ_F_FIXED_FILE))
+               return -EBADF;
+
+       un->dfd = READ_ONCE(sqe->fd);
+
+       un->flags = READ_ONCE(sqe->unlink_flags);
+       if (un->flags & ~AT_REMOVEDIR)
+               return -EINVAL;
+
+       fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
+       un->filename = getname(fname);
+       if (IS_ERR(un->filename))
+               return PTR_ERR(un->filename);
+
+       req->flags |= REQ_F_NEED_CLEANUP;
+       return 0;
+}
+
+int io_unlinkat(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_unlink *un = io_kiocb_to_cmd(req);
+       int ret;
+
+       if (issue_flags & IO_URING_F_NONBLOCK)
+               return -EAGAIN;
+
+       if (un->flags & AT_REMOVEDIR)
+               ret = do_rmdir(un->dfd, un->filename);
+       else
+               ret = do_unlinkat(un->dfd, un->filename);
+
+       req->flags &= ~REQ_F_NEED_CLEANUP;
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
+
+void io_unlinkat_cleanup(struct io_kiocb *req)
+{
+       struct io_unlink *ul = io_kiocb_to_cmd(req);
+
+       putname(ul->filename);
+}
+
+int io_mkdirat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_mkdir *mkd = io_kiocb_to_cmd(req);
+       const char __user *fname;
+
+       if (sqe->off || sqe->rw_flags || sqe->buf_index || sqe->splice_fd_in)
+               return -EINVAL;
+       if (unlikely(req->flags & REQ_F_FIXED_FILE))
+               return -EBADF;
+
+       mkd->dfd = READ_ONCE(sqe->fd);
+       mkd->mode = READ_ONCE(sqe->len);
+
+       fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
+       mkd->filename = getname(fname);
+       if (IS_ERR(mkd->filename))
+               return PTR_ERR(mkd->filename);
+
+       req->flags |= REQ_F_NEED_CLEANUP;
+       return 0;
+}
+
+int io_mkdirat(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_mkdir *mkd = io_kiocb_to_cmd(req);
+       int ret;
+
+       if (issue_flags & IO_URING_F_NONBLOCK)
+               return -EAGAIN;
+
+       ret = do_mkdirat(mkd->dfd, mkd->filename, mkd->mode);
+
+       req->flags &= ~REQ_F_NEED_CLEANUP;
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
+
+void io_mkdirat_cleanup(struct io_kiocb *req)
+{
+       struct io_mkdir *md = io_kiocb_to_cmd(req);
+
+       putname(md->filename);
+}
+
+int io_symlinkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_link *sl = io_kiocb_to_cmd(req);
+       const char __user *oldpath, *newpath;
+
+       if (sqe->len || sqe->rw_flags || sqe->buf_index || sqe->splice_fd_in)
+               return -EINVAL;
+       if (unlikely(req->flags & REQ_F_FIXED_FILE))
+               return -EBADF;
+
+       sl->new_dfd = READ_ONCE(sqe->fd);
+       oldpath = u64_to_user_ptr(READ_ONCE(sqe->addr));
+       newpath = u64_to_user_ptr(READ_ONCE(sqe->addr2));
+
+       sl->oldpath = getname(oldpath);
+       if (IS_ERR(sl->oldpath))
+               return PTR_ERR(sl->oldpath);
+
+       sl->newpath = getname(newpath);
+       if (IS_ERR(sl->newpath)) {
+               putname(sl->oldpath);
+               return PTR_ERR(sl->newpath);
+       }
+
+       req->flags |= REQ_F_NEED_CLEANUP;
+       return 0;
+}
+
+int io_symlinkat(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_link *sl = io_kiocb_to_cmd(req);
+       int ret;
+
+       if (issue_flags & IO_URING_F_NONBLOCK)
+               return -EAGAIN;
+
+       ret = do_symlinkat(sl->oldpath, sl->new_dfd, sl->newpath);
+
+       req->flags &= ~REQ_F_NEED_CLEANUP;
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
+
+int io_linkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_link *lnk = io_kiocb_to_cmd(req);
+       const char __user *oldf, *newf;
+
+       if (sqe->rw_flags || sqe->buf_index || sqe->splice_fd_in)
+               return -EINVAL;
+       if (unlikely(req->flags & REQ_F_FIXED_FILE))
+               return -EBADF;
+
+       lnk->old_dfd = READ_ONCE(sqe->fd);
+       lnk->new_dfd = READ_ONCE(sqe->len);
+       oldf = u64_to_user_ptr(READ_ONCE(sqe->addr));
+       newf = u64_to_user_ptr(READ_ONCE(sqe->addr2));
+       lnk->flags = READ_ONCE(sqe->hardlink_flags);
+
+       lnk->oldpath = getname(oldf);
+       if (IS_ERR(lnk->oldpath))
+               return PTR_ERR(lnk->oldpath);
+
+       lnk->newpath = getname(newf);
+       if (IS_ERR(lnk->newpath)) {
+               putname(lnk->oldpath);
+               return PTR_ERR(lnk->newpath);
+       }
+
+       req->flags |= REQ_F_NEED_CLEANUP;
+       return 0;
+}
+
+int io_linkat(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_link *lnk = io_kiocb_to_cmd(req);
+       int ret;
+
+       if (issue_flags & IO_URING_F_NONBLOCK)
+               return -EAGAIN;
+
+       ret = do_linkat(lnk->old_dfd, lnk->oldpath, lnk->new_dfd,
+                               lnk->newpath, lnk->flags);
+
+       req->flags &= ~REQ_F_NEED_CLEANUP;
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
+
+void io_link_cleanup(struct io_kiocb *req)
+{
+       struct io_link *sl = io_kiocb_to_cmd(req);
+
+       putname(sl->oldpath);
+       putname(sl->newpath);
+}
diff --git a/io_uring/fs.h b/io_uring/fs.h
new file mode 100644 (file)
index 0000000..0bb5efe
--- /dev/null
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+
+int io_renameat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_renameat(struct io_kiocb *req, unsigned int issue_flags);
+void io_renameat_cleanup(struct io_kiocb *req);
+
+int io_unlinkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_unlinkat(struct io_kiocb *req, unsigned int issue_flags);
+void io_unlinkat_cleanup(struct io_kiocb *req);
+
+int io_mkdirat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_mkdirat(struct io_kiocb *req, unsigned int issue_flags);
+void io_mkdirat_cleanup(struct io_kiocb *req);
+
+int io_symlinkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_symlinkat(struct io_kiocb *req, unsigned int issue_flags);
+
+int io_linkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_linkat(struct io_kiocb *req, unsigned int issue_flags);
+void io_link_cleanup(struct io_kiocb *req);
similarity index 99%
rename from fs/io-wq.c
rename to io_uring/io-wq.c
index 824623b..77df5b4 100644 (file)
@@ -18,6 +18,8 @@
 #include <uapi/linux/io_uring.h>
 
 #include "io-wq.h"
+#include "slist.h"
+#include "io_uring.h"
 
 #define WORKER_IDLE_TIMEOUT    (5 * HZ)
 
@@ -518,23 +520,11 @@ static struct io_wq_work *io_get_next_work(struct io_wqe_acct *acct,
        return NULL;
 }
 
-static bool io_flush_signals(void)
-{
-       if (unlikely(test_thread_flag(TIF_NOTIFY_SIGNAL))) {
-               __set_current_state(TASK_RUNNING);
-               clear_notify_signal();
-               if (task_work_pending(current))
-                       task_work_run();
-               return true;
-       }
-       return false;
-}
-
 static void io_assign_current_work(struct io_worker *worker,
                                   struct io_wq_work *work)
 {
        if (work) {
-               io_flush_signals();
+               io_run_task_work();
                cond_resched();
        }
 
@@ -654,7 +644,7 @@ static int io_wqe_worker(void *data)
                last_timeout = false;
                __io_worker_idle(wqe, worker);
                raw_spin_unlock(&wqe->lock);
-               if (io_flush_signals())
+               if (io_run_task_work())
                        continue;
                ret = schedule_timeout(WORKER_IDLE_TIMEOUT);
                if (signal_pending(current)) {
diff --git a/io_uring/io-wq.h b/io_uring/io-wq.h
new file mode 100644 (file)
index 0000000..3122842
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef INTERNAL_IO_WQ_H
+#define INTERNAL_IO_WQ_H
+
+#include <linux/refcount.h>
+#include <linux/io_uring_types.h>
+
+struct io_wq;
+
+enum {
+       IO_WQ_WORK_CANCEL       = 1,
+       IO_WQ_WORK_HASHED       = 2,
+       IO_WQ_WORK_UNBOUND      = 4,
+       IO_WQ_WORK_CONCURRENT   = 16,
+
+       IO_WQ_HASH_SHIFT        = 24,   /* upper 8 bits are used for hash key */
+};
+
+enum io_wq_cancel {
+       IO_WQ_CANCEL_OK,        /* cancelled before started */
+       IO_WQ_CANCEL_RUNNING,   /* found, running, and attempted cancelled */
+       IO_WQ_CANCEL_NOTFOUND,  /* work not found */
+};
+
+typedef struct io_wq_work *(free_work_fn)(struct io_wq_work *);
+typedef void (io_wq_work_fn)(struct io_wq_work *);
+
+struct io_wq_hash {
+       refcount_t refs;
+       unsigned long map;
+       struct wait_queue_head wait;
+};
+
+static inline void io_wq_put_hash(struct io_wq_hash *hash)
+{
+       if (refcount_dec_and_test(&hash->refs))
+               kfree(hash);
+}
+
+struct io_wq_data {
+       struct io_wq_hash *hash;
+       struct task_struct *task;
+       io_wq_work_fn *do_work;
+       free_work_fn *free_work;
+};
+
+struct io_wq *io_wq_create(unsigned bounded, struct io_wq_data *data);
+void io_wq_exit_start(struct io_wq *wq);
+void io_wq_put_and_exit(struct io_wq *wq);
+
+void io_wq_enqueue(struct io_wq *wq, struct io_wq_work *work);
+void io_wq_hash_work(struct io_wq_work *work, void *val);
+
+int io_wq_cpu_affinity(struct io_wq *wq, cpumask_var_t mask);
+int io_wq_max_workers(struct io_wq *wq, int *new_count);
+
+static inline bool io_wq_is_hashed(struct io_wq_work *work)
+{
+       return work->flags & IO_WQ_WORK_HASHED;
+}
+
+typedef bool (work_cancel_fn)(struct io_wq_work *, void *);
+
+enum io_wq_cancel io_wq_cancel_cb(struct io_wq *wq, work_cancel_fn *cancel,
+                                       void *data, bool cancel_all);
+
+#if defined(CONFIG_IO_WQ)
+extern void io_wq_worker_sleeping(struct task_struct *);
+extern void io_wq_worker_running(struct task_struct *);
+#else
+static inline void io_wq_worker_sleeping(struct task_struct *tsk)
+{
+}
+static inline void io_wq_worker_running(struct task_struct *tsk)
+{
+}
+#endif
+
+static inline bool io_wq_current_is_worker(void)
+{
+       return in_task() && (current->flags & PF_IO_WORKER) &&
+               current->worker_private;
+}
+#endif
diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
new file mode 100644 (file)
index 0000000..b54218d
--- /dev/null
@@ -0,0 +1,3953 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Shared application/kernel submission and completion ring pairs, for
+ * supporting fast/efficient IO.
+ *
+ * A note on the read/write ordering memory barriers that are matched between
+ * the application and kernel side.
+ *
+ * After the application reads the CQ ring tail, it must use an
+ * appropriate smp_rmb() to pair with the smp_wmb() the kernel uses
+ * before writing the tail (using smp_load_acquire to read the tail will
+ * do). It also needs a smp_mb() before updating CQ head (ordering the
+ * entry load(s) with the head store), pairing with an implicit barrier
+ * through a control-dependency in io_get_cqe (smp_store_release to
+ * store head will do). Failure to do so could lead to reading invalid
+ * CQ entries.
+ *
+ * Likewise, the application must use an appropriate smp_wmb() before
+ * writing the SQ tail (ordering SQ entry stores with the tail store),
+ * which pairs with smp_load_acquire in io_get_sqring (smp_store_release
+ * to store the tail will do). And it needs a barrier ordering the SQ
+ * head load before writing new SQ entries (smp_load_acquire to read
+ * head will do).
+ *
+ * When using the SQ poll thread (IORING_SETUP_SQPOLL), the application
+ * needs to check the SQ flags for IORING_SQ_NEED_WAKEUP *after*
+ * updating the SQ tail; a full memory barrier smp_mb() is needed
+ * between.
+ *
+ * Also see the examples in the liburing library:
+ *
+ *     git://git.kernel.dk/liburing
+ *
+ * io_uring also uses READ/WRITE_ONCE() for _any_ store or load that happens
+ * from data shared between the kernel and application. This is done both
+ * for ordering purposes, but also to ensure that once a value is loaded from
+ * data that the application could potentially modify, it remains stable.
+ *
+ * Copyright (C) 2018-2019 Jens Axboe
+ * Copyright (c) 2018-2019 Christoph Hellwig
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/syscalls.h>
+#include <net/compat.h>
+#include <linux/refcount.h>
+#include <linux/uio.h>
+#include <linux/bits.h>
+
+#include <linux/sched/signal.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/fdtable.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/percpu.h>
+#include <linux/slab.h>
+#include <linux/bvec.h>
+#include <linux/net.h>
+#include <net/sock.h>
+#include <net/af_unix.h>
+#include <net/scm.h>
+#include <linux/anon_inodes.h>
+#include <linux/sched/mm.h>
+#include <linux/uaccess.h>
+#include <linux/nospec.h>
+#include <linux/highmem.h>
+#include <linux/fsnotify.h>
+#include <linux/fadvise.h>
+#include <linux/task_work.h>
+#include <linux/io_uring.h>
+#include <linux/audit.h>
+#include <linux/security.h>
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/io_uring.h>
+
+#include <uapi/linux/io_uring.h>
+
+#include "io-wq.h"
+
+#include "io_uring.h"
+#include "opdef.h"
+#include "refs.h"
+#include "tctx.h"
+#include "sqpoll.h"
+#include "fdinfo.h"
+#include "kbuf.h"
+#include "rsrc.h"
+#include "cancel.h"
+#include "net.h"
+#include "notif.h"
+
+#include "timeout.h"
+#include "poll.h"
+#include "alloc_cache.h"
+
+#define IORING_MAX_ENTRIES     32768
+#define IORING_MAX_CQ_ENTRIES  (2 * IORING_MAX_ENTRIES)
+
+#define IORING_MAX_RESTRICTIONS        (IORING_RESTRICTION_LAST + \
+                                IORING_REGISTER_LAST + IORING_OP_LAST)
+
+#define SQE_COMMON_FLAGS (IOSQE_FIXED_FILE | IOSQE_IO_LINK | \
+                         IOSQE_IO_HARDLINK | IOSQE_ASYNC)
+
+#define SQE_VALID_FLAGS        (SQE_COMMON_FLAGS | IOSQE_BUFFER_SELECT | \
+                       IOSQE_IO_DRAIN | IOSQE_CQE_SKIP_SUCCESS)
+
+#define IO_REQ_CLEAN_FLAGS (REQ_F_BUFFER_SELECTED | REQ_F_NEED_CLEANUP | \
+                               REQ_F_POLLED | REQ_F_INFLIGHT | REQ_F_CREDS | \
+                               REQ_F_ASYNC_DATA)
+
+#define IO_REQ_CLEAN_SLOW_FLAGS (REQ_F_REFCOUNT | REQ_F_LINK | REQ_F_HARDLINK |\
+                                IO_REQ_CLEAN_FLAGS)
+
+#define IO_TCTX_REFS_CACHE_NR  (1U << 10)
+
+#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;
+       u32                     seq;
+};
+
+/* requests with any of those set should undergo io_disarm_next() */
+#define IO_DISARM_MASK (REQ_F_ARM_LTIMEOUT | REQ_F_LINK_TIMEOUT | REQ_F_FAIL)
+#define IO_REQ_LINK_FLAGS (REQ_F_LINK | REQ_F_HARDLINK)
+
+static bool io_uring_try_cancel_requests(struct io_ring_ctx *ctx,
+                                        struct task_struct *task,
+                                        bool cancel_all);
+
+static void io_dismantle_req(struct io_kiocb *req);
+static void io_clean_op(struct io_kiocb *req);
+static void io_queue_sqe(struct io_kiocb *req);
+
+static void __io_submit_flush_completions(struct io_ring_ctx *ctx);
+
+static struct kmem_cache *req_cachep;
+
+struct sock *io_uring_get_socket(struct file *file)
+{
+#if defined(CONFIG_UNIX)
+       if (io_is_uring_fops(file)) {
+               struct io_ring_ctx *ctx = file->private_data;
+
+               return ctx->ring_sock->sk;
+       }
+#endif
+       return NULL;
+}
+EXPORT_SYMBOL(io_uring_get_socket);
+
+static inline void io_submit_flush_completions(struct io_ring_ctx *ctx)
+{
+       if (!wq_list_empty(&ctx->submit_state.compl_reqs))
+               __io_submit_flush_completions(ctx);
+}
+
+static inline unsigned int __io_cqring_events(struct io_ring_ctx *ctx)
+{
+       return ctx->cached_cq_tail - READ_ONCE(ctx->rings->cq.head);
+}
+
+static bool io_match_linked(struct io_kiocb *head)
+{
+       struct io_kiocb *req;
+
+       io_for_each_link(req, head) {
+               if (req->flags & REQ_F_INFLIGHT)
+                       return true;
+       }
+       return false;
+}
+
+/*
+ * As io_match_task() but protected against racing with linked timeouts.
+ * User must not hold timeout_lock.
+ */
+bool io_match_task_safe(struct io_kiocb *head, struct task_struct *task,
+                       bool cancel_all)
+{
+       bool matched;
+
+       if (task && head->task != task)
+               return false;
+       if (cancel_all)
+               return true;
+
+       if (head->flags & REQ_F_LINK_TIMEOUT) {
+               struct io_ring_ctx *ctx = head->ctx;
+
+               /* protect against races with linked timeouts */
+               spin_lock_irq(&ctx->timeout_lock);
+               matched = io_match_linked(head);
+               spin_unlock_irq(&ctx->timeout_lock);
+       } else {
+               matched = io_match_linked(head);
+       }
+       return matched;
+}
+
+static inline void req_fail_link_node(struct io_kiocb *req, int res)
+{
+       req_set_fail(req);
+       io_req_set_res(req, res, 0);
+}
+
+static inline void io_req_add_to_cache(struct io_kiocb *req, struct io_ring_ctx *ctx)
+{
+       wq_stack_add_head(&req->comp_list, &ctx->submit_state.free_list);
+}
+
+static __cold void io_ring_ctx_ref_free(struct percpu_ref *ref)
+{
+       struct io_ring_ctx *ctx = container_of(ref, struct io_ring_ctx, refs);
+
+       complete(&ctx->ref_comp);
+}
+
+static __cold void io_fallback_req_func(struct work_struct *work)
+{
+       struct io_ring_ctx *ctx = container_of(work, struct io_ring_ctx,
+                                               fallback_work.work);
+       struct llist_node *node = llist_del_all(&ctx->fallback_llist);
+       struct io_kiocb *req, *tmp;
+       bool locked = false;
+
+       percpu_ref_get(&ctx->refs);
+       llist_for_each_entry_safe(req, tmp, node, io_task_work.node)
+               req->io_task_work.func(req, &locked);
+
+       if (locked) {
+               io_submit_flush_completions(ctx);
+               mutex_unlock(&ctx->uring_lock);
+       }
+       percpu_ref_put(&ctx->refs);
+}
+
+static int io_alloc_hash_table(struct io_hash_table *table, unsigned bits)
+{
+       unsigned hash_buckets = 1U << bits;
+       size_t hash_size = hash_buckets * sizeof(table->hbs[0]);
+
+       table->hbs = kmalloc(hash_size, GFP_KERNEL);
+       if (!table->hbs)
+               return -ENOMEM;
+
+       table->hash_bits = bits;
+       init_hash_table(table, hash_buckets);
+       return 0;
+}
+
+static __cold struct io_ring_ctx *io_ring_ctx_alloc(struct io_uring_params *p)
+{
+       struct io_ring_ctx *ctx;
+       int hash_bits;
+
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return NULL;
+
+       xa_init(&ctx->io_bl_xa);
+
+       /*
+        * Use 5 bits less than the max cq entries, that should give us around
+        * 32 entries per hash list if totally full and uniformly spread, but
+        * don't keep too many buckets to not overconsume memory.
+        */
+       hash_bits = ilog2(p->cq_entries) - 5;
+       hash_bits = clamp(hash_bits, 1, 8);
+       if (io_alloc_hash_table(&ctx->cancel_table, hash_bits))
+               goto err;
+       if (io_alloc_hash_table(&ctx->cancel_table_locked, hash_bits))
+               goto err;
+
+       ctx->dummy_ubuf = kzalloc(sizeof(*ctx->dummy_ubuf), GFP_KERNEL);
+       if (!ctx->dummy_ubuf)
+               goto err;
+       /* set invalid range, so io_import_fixed() fails meeting it */
+       ctx->dummy_ubuf->ubuf = -1UL;
+
+       if (percpu_ref_init(&ctx->refs, io_ring_ctx_ref_free,
+                           0, GFP_KERNEL))
+               goto err;
+
+       ctx->flags = p->flags;
+       init_waitqueue_head(&ctx->sqo_sq_wait);
+       INIT_LIST_HEAD(&ctx->sqd_list);
+       INIT_LIST_HEAD(&ctx->cq_overflow_list);
+       INIT_LIST_HEAD(&ctx->io_buffers_cache);
+       io_alloc_cache_init(&ctx->apoll_cache);
+       io_alloc_cache_init(&ctx->netmsg_cache);
+       init_completion(&ctx->ref_comp);
+       xa_init_flags(&ctx->personalities, XA_FLAGS_ALLOC1);
+       mutex_init(&ctx->uring_lock);
+       init_waitqueue_head(&ctx->cq_wait);
+       spin_lock_init(&ctx->completion_lock);
+       spin_lock_init(&ctx->timeout_lock);
+       INIT_WQ_LIST(&ctx->iopoll_list);
+       INIT_LIST_HEAD(&ctx->io_buffers_pages);
+       INIT_LIST_HEAD(&ctx->io_buffers_comp);
+       INIT_LIST_HEAD(&ctx->defer_list);
+       INIT_LIST_HEAD(&ctx->timeout_list);
+       INIT_LIST_HEAD(&ctx->ltimeout_list);
+       spin_lock_init(&ctx->rsrc_ref_lock);
+       INIT_LIST_HEAD(&ctx->rsrc_ref_list);
+       INIT_DELAYED_WORK(&ctx->rsrc_put_work, io_rsrc_put_work);
+       init_llist_head(&ctx->rsrc_put_llist);
+       INIT_LIST_HEAD(&ctx->tctx_list);
+       ctx->submit_state.free_list.next = NULL;
+       INIT_WQ_LIST(&ctx->locked_free_list);
+       INIT_DELAYED_WORK(&ctx->fallback_work, io_fallback_req_func);
+       INIT_WQ_LIST(&ctx->submit_state.compl_reqs);
+       return ctx;
+err:
+       kfree(ctx->dummy_ubuf);
+       kfree(ctx->cancel_table.hbs);
+       kfree(ctx->cancel_table_locked.hbs);
+       kfree(ctx->io_bl);
+       xa_destroy(&ctx->io_bl_xa);
+       kfree(ctx);
+       return NULL;
+}
+
+static void io_account_cq_overflow(struct io_ring_ctx *ctx)
+{
+       struct io_rings *r = ctx->rings;
+
+       WRITE_ONCE(r->cq_overflow, READ_ONCE(r->cq_overflow) + 1);
+       ctx->cq_extra--;
+}
+
+static bool req_need_defer(struct io_kiocb *req, u32 seq)
+{
+       if (unlikely(req->flags & REQ_F_IO_DRAIN)) {
+               struct io_ring_ctx *ctx = req->ctx;
+
+               return seq + READ_ONCE(ctx->cq_extra) != ctx->cached_cq_tail;
+       }
+
+       return false;
+}
+
+static inline void io_req_track_inflight(struct io_kiocb *req)
+{
+       if (!(req->flags & REQ_F_INFLIGHT)) {
+               req->flags |= REQ_F_INFLIGHT;
+               atomic_inc(&req->task->io_uring->inflight_tracked);
+       }
+}
+
+static struct io_kiocb *__io_prep_linked_timeout(struct io_kiocb *req)
+{
+       if (WARN_ON_ONCE(!req->link))
+               return NULL;
+
+       req->flags &= ~REQ_F_ARM_LTIMEOUT;
+       req->flags |= REQ_F_LINK_TIMEOUT;
+
+       /* linked timeouts should have two refs once prep'ed */
+       io_req_set_refcount(req);
+       __io_req_set_refcount(req->link, 2);
+       return req->link;
+}
+
+static inline struct io_kiocb *io_prep_linked_timeout(struct io_kiocb *req)
+{
+       if (likely(!(req->flags & REQ_F_ARM_LTIMEOUT)))
+               return NULL;
+       return __io_prep_linked_timeout(req);
+}
+
+static noinline void __io_arm_ltimeout(struct io_kiocb *req)
+{
+       io_queue_linked_timeout(__io_prep_linked_timeout(req));
+}
+
+static inline void io_arm_ltimeout(struct io_kiocb *req)
+{
+       if (unlikely(req->flags & REQ_F_ARM_LTIMEOUT))
+               __io_arm_ltimeout(req);
+}
+
+static void io_prep_async_work(struct io_kiocb *req)
+{
+       const struct io_op_def *def = &io_op_defs[req->opcode];
+       struct io_ring_ctx *ctx = req->ctx;
+
+       if (!(req->flags & REQ_F_CREDS)) {
+               req->flags |= REQ_F_CREDS;
+               req->creds = get_current_cred();
+       }
+
+       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;
+
+       if (req->file && !io_req_ffs_set(req))
+               req->flags |= io_file_get_flags(req->file) << REQ_F_SUPPORT_NOWAIT_BIT;
+
+       if (req->flags & REQ_F_ISREG) {
+               if (def->hash_reg_file || (ctx->flags & IORING_SETUP_IOPOLL))
+                       io_wq_hash_work(&req->work, file_inode(req->file));
+       } else if (!req->file || !S_ISBLK(file_inode(req->file)->i_mode)) {
+               if (def->unbound_nonreg_file)
+                       req->work.flags |= IO_WQ_WORK_UNBOUND;
+       }
+}
+
+static void io_prep_async_link(struct io_kiocb *req)
+{
+       struct io_kiocb *cur;
+
+       if (req->flags & REQ_F_LINK_TIMEOUT) {
+               struct io_ring_ctx *ctx = req->ctx;
+
+               spin_lock_irq(&ctx->timeout_lock);
+               io_for_each_link(cur, req)
+                       io_prep_async_work(cur);
+               spin_unlock_irq(&ctx->timeout_lock);
+       } else {
+               io_for_each_link(cur, req)
+                       io_prep_async_work(cur);
+       }
+}
+
+void io_queue_iowq(struct io_kiocb *req, bool *dont_use)
+{
+       struct io_kiocb *link = io_prep_linked_timeout(req);
+       struct io_uring_task *tctx = req->task->io_uring;
+
+       BUG_ON(!tctx);
+       BUG_ON(!tctx->io_wq);
+
+       /* init ->work of the whole link before punting */
+       io_prep_async_link(req);
+
+       /*
+        * Not expected to happen, but if we do have a bug where this _can_
+        * happen, catch it here and ensure the request is marked as
+        * canceled. That will make io-wq go through the usual work cancel
+        * procedure rather than attempt to run this request (or create a new
+        * worker for it).
+        */
+       if (WARN_ON_ONCE(!same_thread_group(req->task, current)))
+               req->work.flags |= IO_WQ_WORK_CANCEL;
+
+       trace_io_uring_queue_async_work(req, io_wq_is_hashed(&req->work));
+       io_wq_enqueue(tctx->io_wq, &req->work);
+       if (link)
+               io_queue_linked_timeout(link);
+}
+
+static __cold void io_queue_deferred(struct io_ring_ctx *ctx)
+{
+       while (!list_empty(&ctx->defer_list)) {
+               struct io_defer_entry *de = list_first_entry(&ctx->defer_list,
+                                               struct io_defer_entry, list);
+
+               if (req_need_defer(de->req, de->seq))
+                       break;
+               list_del_init(&de->list);
+               io_req_task_queue(de->req);
+               kfree(de);
+       }
+}
+
+static void io_eventfd_signal(struct io_ring_ctx *ctx)
+{
+       struct io_ev_fd *ev_fd;
+       bool skip;
+
+       spin_lock(&ctx->completion_lock);
+       /*
+        * Eventfd should only get triggered when at least one event has been
+        * posted. Some applications rely on the eventfd notification count only
+        * changing IFF a new CQE has been added to the CQ ring. There's no
+        * depedency on 1:1 relationship between how many times this function is
+        * called (and hence the eventfd count) and number of CQEs posted to the
+        * CQ ring.
+        */
+       skip = ctx->cached_cq_tail == ctx->evfd_last_cq_tail;
+       ctx->evfd_last_cq_tail = ctx->cached_cq_tail;
+       spin_unlock(&ctx->completion_lock);
+       if (skip)
+               return;
+
+       rcu_read_lock();
+       /*
+        * rcu_dereference ctx->io_ev_fd once and use it for both for checking
+        * and eventfd_signal
+        */
+       ev_fd = rcu_dereference(ctx->io_ev_fd);
+
+       /*
+        * Check again if ev_fd exists incase an io_eventfd_unregister call
+        * completed between the NULL check of ctx->io_ev_fd at the start of
+        * the function and rcu_read_lock.
+        */
+       if (unlikely(!ev_fd))
+               goto out;
+       if (READ_ONCE(ctx->rings->cq_flags) & IORING_CQ_EVENTFD_DISABLED)
+               goto out;
+
+       if (!ev_fd->eventfd_async || io_wq_current_is_worker())
+               eventfd_signal(ev_fd->cq_ev_fd, 1);
+out:
+       rcu_read_unlock();
+}
+
+void __io_commit_cqring_flush(struct io_ring_ctx *ctx)
+{
+       if (ctx->off_timeout_used || ctx->drain_active) {
+               spin_lock(&ctx->completion_lock);
+               if (ctx->off_timeout_used)
+                       io_flush_timeouts(ctx);
+               if (ctx->drain_active)
+                       io_queue_deferred(ctx);
+               spin_unlock(&ctx->completion_lock);
+       }
+       if (ctx->has_evfd)
+               io_eventfd_signal(ctx);
+}
+
+static inline void io_cqring_ev_posted(struct io_ring_ctx *ctx)
+{
+       io_commit_cqring_flush(ctx);
+       io_cqring_wake(ctx);
+}
+
+static inline void __io_cq_unlock_post(struct io_ring_ctx *ctx)
+       __releases(ctx->completion_lock)
+{
+       io_commit_cqring(ctx);
+       spin_unlock(&ctx->completion_lock);
+       io_cqring_ev_posted(ctx);
+}
+
+void io_cq_unlock_post(struct io_ring_ctx *ctx)
+{
+       __io_cq_unlock_post(ctx);
+}
+
+/* Returns true if there are no backlogged entries after the flush */
+static bool __io_cqring_overflow_flush(struct io_ring_ctx *ctx, bool force)
+{
+       bool all_flushed;
+       size_t cqe_size = sizeof(struct io_uring_cqe);
+
+       if (!force && __io_cqring_events(ctx) == ctx->cq_entries)
+               return false;
+
+       if (ctx->flags & IORING_SETUP_CQE32)
+               cqe_size <<= 1;
+
+       io_cq_lock(ctx);
+       while (!list_empty(&ctx->cq_overflow_list)) {
+               struct io_uring_cqe *cqe = io_get_cqe(ctx);
+               struct io_overflow_cqe *ocqe;
+
+               if (!cqe && !force)
+                       break;
+               ocqe = list_first_entry(&ctx->cq_overflow_list,
+                                       struct io_overflow_cqe, list);
+               if (cqe)
+                       memcpy(cqe, &ocqe->cqe, cqe_size);
+               else
+                       io_account_cq_overflow(ctx);
+
+               list_del(&ocqe->list);
+               kfree(ocqe);
+       }
+
+       all_flushed = list_empty(&ctx->cq_overflow_list);
+       if (all_flushed) {
+               clear_bit(IO_CHECK_CQ_OVERFLOW_BIT, &ctx->check_cq);
+               atomic_andnot(IORING_SQ_CQ_OVERFLOW, &ctx->rings->sq_flags);
+       }
+
+       io_cq_unlock_post(ctx);
+       return all_flushed;
+}
+
+static bool io_cqring_overflow_flush(struct io_ring_ctx *ctx)
+{
+       bool ret = true;
+
+       if (test_bit(IO_CHECK_CQ_OVERFLOW_BIT, &ctx->check_cq)) {
+               /* iopoll syncs against uring_lock, not completion_lock */
+               if (ctx->flags & IORING_SETUP_IOPOLL)
+                       mutex_lock(&ctx->uring_lock);
+               ret = __io_cqring_overflow_flush(ctx, false);
+               if (ctx->flags & IORING_SETUP_IOPOLL)
+                       mutex_unlock(&ctx->uring_lock);
+       }
+
+       return ret;
+}
+
+void __io_put_task(struct task_struct *task, int nr)
+{
+       struct io_uring_task *tctx = task->io_uring;
+
+       percpu_counter_sub(&tctx->inflight, nr);
+       if (unlikely(atomic_read(&tctx->in_idle)))
+               wake_up(&tctx->wait);
+       put_task_struct_many(task, nr);
+}
+
+void io_task_refs_refill(struct io_uring_task *tctx)
+{
+       unsigned int refill = -tctx->cached_refs + IO_TCTX_REFS_CACHE_NR;
+
+       percpu_counter_add(&tctx->inflight, refill);
+       refcount_add(refill, &current->usage);
+       tctx->cached_refs += refill;
+}
+
+static __cold void io_uring_drop_tctx_refs(struct task_struct *task)
+{
+       struct io_uring_task *tctx = task->io_uring;
+       unsigned int refs = tctx->cached_refs;
+
+       if (refs) {
+               tctx->cached_refs = 0;
+               percpu_counter_sub(&tctx->inflight, refs);
+               put_task_struct_many(task, refs);
+       }
+}
+
+static bool io_cqring_event_overflow(struct io_ring_ctx *ctx, u64 user_data,
+                                    s32 res, u32 cflags, u64 extra1, u64 extra2)
+{
+       struct io_overflow_cqe *ocqe;
+       size_t ocq_size = sizeof(struct io_overflow_cqe);
+       bool is_cqe32 = (ctx->flags & IORING_SETUP_CQE32);
+
+       if (is_cqe32)
+               ocq_size += sizeof(struct io_uring_cqe);
+
+       ocqe = kmalloc(ocq_size, GFP_ATOMIC | __GFP_ACCOUNT);
+       trace_io_uring_cqe_overflow(ctx, user_data, res, cflags, ocqe);
+       if (!ocqe) {
+               /*
+                * If we're in ring overflow flush mode, or in task cancel mode,
+                * or cannot allocate an overflow entry, then we need to drop it
+                * on the floor.
+                */
+               io_account_cq_overflow(ctx);
+               set_bit(IO_CHECK_CQ_DROPPED_BIT, &ctx->check_cq);
+               return false;
+       }
+       if (list_empty(&ctx->cq_overflow_list)) {
+               set_bit(IO_CHECK_CQ_OVERFLOW_BIT, &ctx->check_cq);
+               atomic_or(IORING_SQ_CQ_OVERFLOW, &ctx->rings->sq_flags);
+
+       }
+       ocqe->cqe.user_data = user_data;
+       ocqe->cqe.res = res;
+       ocqe->cqe.flags = cflags;
+       if (is_cqe32) {
+               ocqe->cqe.big_cqe[0] = extra1;
+               ocqe->cqe.big_cqe[1] = extra2;
+       }
+       list_add_tail(&ocqe->list, &ctx->cq_overflow_list);
+       return true;
+}
+
+bool io_req_cqe_overflow(struct io_kiocb *req)
+{
+       if (!(req->flags & REQ_F_CQE32_INIT)) {
+               req->extra1 = 0;
+               req->extra2 = 0;
+       }
+       return io_cqring_event_overflow(req->ctx, req->cqe.user_data,
+                                       req->cqe.res, req->cqe.flags,
+                                       req->extra1, req->extra2);
+}
+
+/*
+ * writes to the cq entry need to come after reading head; the
+ * control dependency is enough as we're using WRITE_ONCE to
+ * fill the cq entry
+ */
+struct io_uring_cqe *__io_get_cqe(struct io_ring_ctx *ctx)
+{
+       struct io_rings *rings = ctx->rings;
+       unsigned int off = ctx->cached_cq_tail & (ctx->cq_entries - 1);
+       unsigned int free, queued, len;
+
+
+       /* userspace may cheat modifying the tail, be safe and do min */
+       queued = min(__io_cqring_events(ctx), ctx->cq_entries);
+       free = ctx->cq_entries - queued;
+       /* we need a contiguous range, limit based on the current array offset */
+       len = min(free, ctx->cq_entries - off);
+       if (!len)
+               return NULL;
+
+       if (ctx->flags & IORING_SETUP_CQE32) {
+               off <<= 1;
+               len <<= 1;
+       }
+
+       ctx->cqe_cached = &rings->cqes[off];
+       ctx->cqe_sentinel = ctx->cqe_cached + len;
+
+       ctx->cached_cq_tail++;
+       ctx->cqe_cached++;
+       if (ctx->flags & IORING_SETUP_CQE32)
+               ctx->cqe_cached++;
+       return &rings->cqes[off];
+}
+
+bool io_fill_cqe_aux(struct io_ring_ctx *ctx, u64 user_data, s32 res, u32 cflags,
+                    bool allow_overflow)
+{
+       struct io_uring_cqe *cqe;
+
+       ctx->cq_extra++;
+
+       /*
+        * If we can't get a cq entry, userspace overflowed the
+        * submission (by quite a lot). Increment the overflow count in
+        * the ring.
+        */
+       cqe = io_get_cqe(ctx);
+       if (likely(cqe)) {
+               trace_io_uring_complete(ctx, NULL, user_data, res, cflags, 0, 0);
+
+               WRITE_ONCE(cqe->user_data, user_data);
+               WRITE_ONCE(cqe->res, res);
+               WRITE_ONCE(cqe->flags, cflags);
+
+               if (ctx->flags & IORING_SETUP_CQE32) {
+                       WRITE_ONCE(cqe->big_cqe[0], 0);
+                       WRITE_ONCE(cqe->big_cqe[1], 0);
+               }
+               return true;
+       }
+
+       if (allow_overflow)
+               return io_cqring_event_overflow(ctx, user_data, res, cflags, 0, 0);
+
+       return false;
+}
+
+bool io_post_aux_cqe(struct io_ring_ctx *ctx,
+                    u64 user_data, s32 res, u32 cflags,
+                    bool allow_overflow)
+{
+       bool filled;
+
+       io_cq_lock(ctx);
+       filled = io_fill_cqe_aux(ctx, user_data, res, cflags, allow_overflow);
+       io_cq_unlock_post(ctx);
+       return filled;
+}
+
+static void __io_req_complete_put(struct io_kiocb *req)
+{
+       /*
+        * If we're the last reference to this request, add to our locked
+        * free_list cache.
+        */
+       if (req_ref_put_and_test(req)) {
+               struct io_ring_ctx *ctx = req->ctx;
+
+               if (req->flags & IO_REQ_LINK_FLAGS) {
+                       if (req->flags & IO_DISARM_MASK)
+                               io_disarm_next(req);
+                       if (req->link) {
+                               io_req_task_queue(req->link);
+                               req->link = NULL;
+                       }
+               }
+               io_req_put_rsrc(req);
+               /*
+                * Selected buffer deallocation in io_clean_op() assumes that
+                * we don't hold ->completion_lock. Clean them here to avoid
+                * deadlocks.
+                */
+               io_put_kbuf_comp(req);
+               io_dismantle_req(req);
+               io_put_task(req->task, 1);
+               wq_list_add_head(&req->comp_list, &ctx->locked_free_list);
+               ctx->locked_free_nr++;
+       }
+}
+
+void __io_req_complete_post(struct io_kiocb *req)
+{
+       if (!(req->flags & REQ_F_CQE_SKIP))
+               __io_fill_cqe_req(req->ctx, req);
+       __io_req_complete_put(req);
+}
+
+void io_req_complete_post(struct io_kiocb *req)
+{
+       struct io_ring_ctx *ctx = req->ctx;
+
+       io_cq_lock(ctx);
+       __io_req_complete_post(req);
+       io_cq_unlock_post(ctx);
+}
+
+inline void __io_req_complete(struct io_kiocb *req, unsigned issue_flags)
+{
+       io_req_complete_post(req);
+}
+
+void io_req_complete_failed(struct io_kiocb *req, s32 res)
+{
+       req_set_fail(req);
+       io_req_set_res(req, res, io_put_kbuf(req, IO_URING_F_UNLOCKED));
+       io_req_complete_post(req);
+}
+
+/*
+ * Don't initialise the fields below on every allocation, but do that in
+ * advance and keep them valid across allocations.
+ */
+static void io_preinit_req(struct io_kiocb *req, struct io_ring_ctx *ctx)
+{
+       req->ctx = ctx;
+       req->link = NULL;
+       req->async_data = NULL;
+       /* not necessary, but safer to zero */
+       req->cqe.res = 0;
+}
+
+static void io_flush_cached_locked_reqs(struct io_ring_ctx *ctx,
+                                       struct io_submit_state *state)
+{
+       spin_lock(&ctx->completion_lock);
+       wq_list_splice(&ctx->locked_free_list, &state->free_list);
+       ctx->locked_free_nr = 0;
+       spin_unlock(&ctx->completion_lock);
+}
+
+/*
+ * A request might get retired back into the request caches even before opcode
+ * handlers and io_issue_sqe() are done with it, e.g. inline completion path.
+ * Because of that, io_alloc_req() should be called only under ->uring_lock
+ * and with extra caution to not get a request that is still worked on.
+ */
+__cold bool __io_alloc_req_refill(struct io_ring_ctx *ctx)
+       __must_hold(&ctx->uring_lock)
+{
+       gfp_t gfp = GFP_KERNEL | __GFP_NOWARN;
+       void *reqs[IO_REQ_ALLOC_BATCH];
+       int ret, i;
+
+       /*
+        * If we have more than a batch's worth of requests in our IRQ side
+        * locked cache, grab the lock and move them over to our submission
+        * side cache.
+        */
+       if (data_race(ctx->locked_free_nr) > IO_COMPL_BATCH) {
+               io_flush_cached_locked_reqs(ctx, &ctx->submit_state);
+               if (!io_req_cache_empty(ctx))
+                       return true;
+       }
+
+       ret = kmem_cache_alloc_bulk(req_cachep, gfp, ARRAY_SIZE(reqs), reqs);
+
+       /*
+        * Bulk alloc is all-or-nothing. If we fail to get a batch,
+        * retry single alloc to be on the safe side.
+        */
+       if (unlikely(ret <= 0)) {
+               reqs[0] = kmem_cache_alloc(req_cachep, gfp);
+               if (!reqs[0])
+                       return false;
+               ret = 1;
+       }
+
+       percpu_ref_get_many(&ctx->refs, ret);
+       for (i = 0; i < ret; i++) {
+               struct io_kiocb *req = reqs[i];
+
+               io_preinit_req(req, ctx);
+               io_req_add_to_cache(req, ctx);
+       }
+       return true;
+}
+
+static inline void io_dismantle_req(struct io_kiocb *req)
+{
+       unsigned int flags = req->flags;
+
+       if (unlikely(flags & IO_REQ_CLEAN_FLAGS))
+               io_clean_op(req);
+       if (!(flags & REQ_F_FIXED_FILE))
+               io_put_file(req->file);
+}
+
+__cold void io_free_req(struct io_kiocb *req)
+{
+       struct io_ring_ctx *ctx = req->ctx;
+
+       io_req_put_rsrc(req);
+       io_dismantle_req(req);
+       io_put_task(req->task, 1);
+
+       spin_lock(&ctx->completion_lock);
+       wq_list_add_head(&req->comp_list, &ctx->locked_free_list);
+       ctx->locked_free_nr++;
+       spin_unlock(&ctx->completion_lock);
+}
+
+static void __io_req_find_next_prep(struct io_kiocb *req)
+{
+       struct io_ring_ctx *ctx = req->ctx;
+
+       io_cq_lock(ctx);
+       io_disarm_next(req);
+       io_cq_unlock_post(ctx);
+}
+
+static inline struct io_kiocb *io_req_find_next(struct io_kiocb *req)
+{
+       struct io_kiocb *nxt;
+
+       /*
+        * If LINK is set, we have dependent requests in this chain. If we
+        * didn't fail this request, queue the first one up, moving any other
+        * dependencies to the next request. In case of failure, fail the rest
+        * of the chain.
+        */
+       if (unlikely(req->flags & IO_DISARM_MASK))
+               __io_req_find_next_prep(req);
+       nxt = req->link;
+       req->link = NULL;
+       return nxt;
+}
+
+static void ctx_flush_and_put(struct io_ring_ctx *ctx, bool *locked)
+{
+       if (!ctx)
+               return;
+       if (ctx->flags & IORING_SETUP_TASKRUN_FLAG)
+               atomic_andnot(IORING_SQ_TASKRUN, &ctx->rings->sq_flags);
+       if (*locked) {
+               io_submit_flush_completions(ctx);
+               mutex_unlock(&ctx->uring_lock);
+               *locked = false;
+       }
+       percpu_ref_put(&ctx->refs);
+}
+
+static unsigned int handle_tw_list(struct llist_node *node,
+                                  struct io_ring_ctx **ctx, bool *locked,
+                                  struct llist_node *last)
+{
+       unsigned int count = 0;
+
+       while (node != last) {
+               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, locked);
+                       *ctx = req->ctx;
+                       /* if not contended, grab and improve batching */
+                       *locked = mutex_trylock(&(*ctx)->uring_lock);
+                       percpu_ref_get(&(*ctx)->refs);
+               }
+               req->io_task_work.func(req, locked);
+               node = next;
+               count++;
+       }
+
+       return count;
+}
+
+/**
+ * io_llist_xchg - swap all entries in a lock-less list
+ * @head:      the head of lock-less list to delete all entries
+ * @new:       new entry as the head of the list
+ *
+ * If list is empty, return NULL, otherwise, return the pointer to the first entry.
+ * The order of entries returned is from the newest to the oldest added one.
+ */
+static inline struct llist_node *io_llist_xchg(struct llist_head *head,
+                                              struct llist_node *new)
+{
+       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);
+}
+
+void tctx_task_work(struct callback_head *cb)
+{
+       bool uring_locked = false;
+       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 = io_llist_xchg(&tctx->task_list, &fake);
+       unsigned int loops = 1;
+       unsigned int count = handle_tw_list(node, &ctx, &uring_locked, NULL);
+
+       node = io_llist_cmpxchg(&tctx->task_list, &fake, NULL);
+       while (node != &fake) {
+               loops++;
+               node = io_llist_xchg(&tctx->task_list, &fake);
+               count += handle_tw_list(node, &ctx, &uring_locked, &fake);
+               node = io_llist_cmpxchg(&tctx->task_list, &fake, NULL);
+       }
+
+       ctx_flush_and_put(ctx, &uring_locked);
+
+       /* relaxed read is enough as only the task itself sets ->in_idle */
+       if (unlikely(atomic_read(&tctx->in_idle)))
+               io_uring_drop_tctx_refs(current);
+
+       trace_io_uring_task_work_run(tctx, count, loops);
+}
+
+void io_req_task_work_add(struct io_kiocb *req)
+{
+       struct io_uring_task *tctx = req->task->io_uring;
+       struct io_ring_ctx *ctx = req->ctx;
+       struct llist_node *node;
+       bool running;
+
+       running = !llist_add(&req->io_task_work.node, &tctx->task_list);
+
+       /* task_work already pending, we're done */
+       if (running)
+               return;
+
+       if (ctx->flags & IORING_SETUP_TASKRUN_FLAG)
+               atomic_or(IORING_SQ_TASKRUN, &ctx->rings->sq_flags);
+
+       if (likely(!task_work_add(req->task, &tctx->task_work, ctx->notify_method)))
+               return;
+
+       node = llist_del_all(&tctx->task_list);
+
+       while (node) {
+               req = container_of(node, struct io_kiocb, io_task_work.node);
+               node = node->next;
+               if (llist_add(&req->io_task_work.node,
+                             &req->ctx->fallback_llist))
+                       schedule_delayed_work(&req->ctx->fallback_work, 1);
+       }
+}
+
+static void io_req_tw_post(struct io_kiocb *req, bool *locked)
+{
+       io_req_complete_post(req);
+}
+
+void io_req_tw_post_queue(struct io_kiocb *req, s32 res, u32 cflags)
+{
+       io_req_set_res(req, res, cflags);
+       req->io_task_work.func = io_req_tw_post;
+       io_req_task_work_add(req);
+}
+
+static void io_req_task_cancel(struct io_kiocb *req, bool *locked)
+{
+       /* not needed for normal modes, but SQPOLL depends on it */
+       io_tw_lock(req->ctx, locked);
+       io_req_complete_failed(req, req->cqe.res);
+}
+
+void io_req_task_submit(struct io_kiocb *req, bool *locked)
+{
+       io_tw_lock(req->ctx, locked);
+       /* req->task == current here, checking PF_EXITING is safe */
+       if (likely(!(req->task->flags & PF_EXITING)))
+               io_queue_sqe(req);
+       else
+               io_req_complete_failed(req, -EFAULT);
+}
+
+void io_req_task_queue_fail(struct io_kiocb *req, int ret)
+{
+       io_req_set_res(req, ret, 0);
+       req->io_task_work.func = io_req_task_cancel;
+       io_req_task_work_add(req);
+}
+
+void io_req_task_queue(struct io_kiocb *req)
+{
+       req->io_task_work.func = io_req_task_submit;
+       io_req_task_work_add(req);
+}
+
+void io_queue_next(struct io_kiocb *req)
+{
+       struct io_kiocb *nxt = io_req_find_next(req);
+
+       if (nxt)
+               io_req_task_queue(nxt);
+}
+
+void io_free_batch_list(struct io_ring_ctx *ctx, struct io_wq_work_node *node)
+       __must_hold(&ctx->uring_lock)
+{
+       struct task_struct *task = NULL;
+       int task_refs = 0;
+
+       do {
+               struct io_kiocb *req = container_of(node, struct io_kiocb,
+                                                   comp_list);
+
+               if (unlikely(req->flags & IO_REQ_CLEAN_SLOW_FLAGS)) {
+                       if (req->flags & REQ_F_REFCOUNT) {
+                               node = req->comp_list.next;
+                               if (!req_ref_put_and_test(req))
+                                       continue;
+                       }
+                       if ((req->flags & REQ_F_POLLED) && req->apoll) {
+                               struct async_poll *apoll = req->apoll;
+
+                               if (apoll->double_poll)
+                                       kfree(apoll->double_poll);
+                               if (!io_alloc_cache_put(&ctx->apoll_cache, &apoll->cache))
+                                       kfree(apoll);
+                               req->flags &= ~REQ_F_POLLED;
+                       }
+                       if (req->flags & IO_REQ_LINK_FLAGS)
+                               io_queue_next(req);
+                       if (unlikely(req->flags & IO_REQ_CLEAN_FLAGS))
+                               io_clean_op(req);
+               }
+               if (!(req->flags & REQ_F_FIXED_FILE))
+                       io_put_file(req->file);
+
+               io_req_put_rsrc_locked(req, ctx);
+
+               if (req->task != task) {
+                       if (task)
+                               io_put_task(task, task_refs);
+                       task = req->task;
+                       task_refs = 0;
+               }
+               task_refs++;
+               node = req->comp_list.next;
+               io_req_add_to_cache(req, ctx);
+       } while (node);
+
+       if (task)
+               io_put_task(task, task_refs);
+}
+
+static void __io_submit_flush_completions(struct io_ring_ctx *ctx)
+       __must_hold(&ctx->uring_lock)
+{
+       struct io_wq_work_node *node, *prev;
+       struct io_submit_state *state = &ctx->submit_state;
+
+       spin_lock(&ctx->completion_lock);
+       wq_list_for_each(node, prev, &state->compl_reqs) {
+               struct io_kiocb *req = container_of(node, struct io_kiocb,
+                                           comp_list);
+
+               if (!(req->flags & REQ_F_CQE_SKIP))
+                       __io_fill_cqe_req(ctx, req);
+       }
+       __io_cq_unlock_post(ctx);
+
+       io_free_batch_list(ctx, state->compl_reqs.first);
+       INIT_WQ_LIST(&state->compl_reqs);
+}
+
+/*
+ * Drop reference to request, return next in chain (if there is one) if this
+ * was the last reference to this request.
+ */
+static inline struct io_kiocb *io_put_req_find_next(struct io_kiocb *req)
+{
+       struct io_kiocb *nxt = NULL;
+
+       if (req_ref_put_and_test(req)) {
+               if (unlikely(req->flags & IO_REQ_LINK_FLAGS))
+                       nxt = io_req_find_next(req);
+               io_free_req(req);
+       }
+       return nxt;
+}
+
+static unsigned io_cqring_events(struct io_ring_ctx *ctx)
+{
+       /* See comment at the top of this file */
+       smp_rmb();
+       return __io_cqring_events(ctx);
+}
+
+/*
+ * We can't just wait for polled events to come to us, we have to actively
+ * find and complete them.
+ */
+static __cold void io_iopoll_try_reap_events(struct io_ring_ctx *ctx)
+{
+       if (!(ctx->flags & IORING_SETUP_IOPOLL))
+               return;
+
+       mutex_lock(&ctx->uring_lock);
+       while (!wq_list_empty(&ctx->iopoll_list)) {
+               /* let it sleep and repeat later if can't complete a request */
+               if (io_do_iopoll(ctx, true) == 0)
+                       break;
+               /*
+                * Ensure we allow local-to-the-cpu processing to take place,
+                * in this case we need to ensure that we reap all events.
+                * Also let task_work, etc. to progress by releasing the mutex
+                */
+               if (need_resched()) {
+                       mutex_unlock(&ctx->uring_lock);
+                       cond_resched();
+                       mutex_lock(&ctx->uring_lock);
+               }
+       }
+       mutex_unlock(&ctx->uring_lock);
+}
+
+static int io_iopoll_check(struct io_ring_ctx *ctx, long min)
+{
+       unsigned int nr_events = 0;
+       int ret = 0;
+       unsigned long check_cq;
+
+       check_cq = READ_ONCE(ctx->check_cq);
+       if (unlikely(check_cq)) {
+               if (check_cq & BIT(IO_CHECK_CQ_OVERFLOW_BIT))
+                       __io_cqring_overflow_flush(ctx, false);
+               /*
+                * Similarly do not spin if we have not informed the user of any
+                * dropped CQE.
+                */
+               if (check_cq & BIT(IO_CHECK_CQ_DROPPED_BIT))
+                       return -EBADR;
+       }
+       /*
+        * Don't enter poll loop if we already have events pending.
+        * If we do, we can potentially be spinning for commands that
+        * already triggered a CQE (eg in error).
+        */
+       if (io_cqring_events(ctx))
+               return 0;
+
+       do {
+               /*
+                * If a submit got punted to a workqueue, we can have the
+                * application entering polling for a command before it gets
+                * issued. That app will hold the uring_lock for the duration
+                * of the poll right here, so we need to take a breather every
+                * now and then to ensure that the issue has a chance to add
+                * the poll to the issued list. Otherwise we can spin here
+                * forever, while the workqueue is stuck trying to acquire the
+                * very same mutex.
+                */
+               if (wq_list_empty(&ctx->iopoll_list)) {
+                       u32 tail = ctx->cached_cq_tail;
+
+                       mutex_unlock(&ctx->uring_lock);
+                       io_run_task_work();
+                       mutex_lock(&ctx->uring_lock);
+
+                       /* some requests don't go through iopoll_list */
+                       if (tail != ctx->cached_cq_tail ||
+                           wq_list_empty(&ctx->iopoll_list))
+                               break;
+               }
+               ret = io_do_iopoll(ctx, !min);
+               if (ret < 0)
+                       break;
+               nr_events += ret;
+               ret = 0;
+       } while (nr_events < min && !need_resched());
+
+       return ret;
+}
+
+void io_req_task_complete(struct io_kiocb *req, bool *locked)
+{
+       if (req->flags & (REQ_F_BUFFER_SELECTED|REQ_F_BUFFER_RING)) {
+               unsigned issue_flags = *locked ? 0 : IO_URING_F_UNLOCKED;
+
+               req->cqe.flags |= io_put_kbuf(req, issue_flags);
+       }
+
+       if (*locked)
+               io_req_complete_defer(req);
+       else
+               io_req_complete_post(req);
+}
+
+/*
+ * After the iocb has been issued, it's safe to be found on the poll list.
+ * Adding the kiocb to the list AFTER submission ensures that we don't
+ * find it from a io_do_iopoll() thread before the issuer is done
+ * accessing the kiocb cookie.
+ */
+static void io_iopoll_req_issued(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_ring_ctx *ctx = req->ctx;
+       const bool needs_lock = issue_flags & IO_URING_F_UNLOCKED;
+
+       /* workqueue context doesn't hold uring_lock, grab it now */
+       if (unlikely(needs_lock))
+               mutex_lock(&ctx->uring_lock);
+
+       /*
+        * Track whether we have multiple files in our lists. This will impact
+        * how we do polling eventually, not spinning if we're on potentially
+        * different devices.
+        */
+       if (wq_list_empty(&ctx->iopoll_list)) {
+               ctx->poll_multi_queue = false;
+       } else if (!ctx->poll_multi_queue) {
+               struct io_kiocb *list_req;
+
+               list_req = container_of(ctx->iopoll_list.first, struct io_kiocb,
+                                       comp_list);
+               if (list_req->file != req->file)
+                       ctx->poll_multi_queue = true;
+       }
+
+       /*
+        * For fast devices, IO may have already completed. If it has, add
+        * it to the front so we find it first.
+        */
+       if (READ_ONCE(req->iopoll_completed))
+               wq_list_add_head(&req->comp_list, &ctx->iopoll_list);
+       else
+               wq_list_add_tail(&req->comp_list, &ctx->iopoll_list);
+
+       if (unlikely(needs_lock)) {
+               /*
+                * If IORING_SETUP_SQPOLL is enabled, sqes are either handle
+                * in sq thread task context or in io worker task context. If
+                * current task context is sq thread, we don't need to check
+                * whether should wake up sq thread.
+                */
+               if ((ctx->flags & IORING_SETUP_SQPOLL) &&
+                   wq_has_sleeper(&ctx->sq_data->wait))
+                       wake_up(&ctx->sq_data->wait);
+
+               mutex_unlock(&ctx->uring_lock);
+       }
+}
+
+static bool io_bdev_nowait(struct block_device *bdev)
+{
+       return !bdev || blk_queue_nowait(bdev_get_queue(bdev));
+}
+
+/*
+ * If we tracked the file through the SCM inflight mechanism, we could support
+ * any file. For now, just ensure that anything potentially problematic is done
+ * inline.
+ */
+static bool __io_file_supports_nowait(struct file *file, umode_t mode)
+{
+       if (S_ISBLK(mode)) {
+               if (IS_ENABLED(CONFIG_BLOCK) &&
+                   io_bdev_nowait(I_BDEV(file->f_mapping->host)))
+                       return true;
+               return false;
+       }
+       if (S_ISSOCK(mode))
+               return true;
+       if (S_ISREG(mode)) {
+               if (IS_ENABLED(CONFIG_BLOCK) &&
+                   io_bdev_nowait(file->f_inode->i_sb->s_bdev) &&
+                   !io_is_uring_fops(file))
+                       return true;
+               return false;
+       }
+
+       /* any ->read/write should understand O_NONBLOCK */
+       if (file->f_flags & O_NONBLOCK)
+               return true;
+       return file->f_mode & FMODE_NOWAIT;
+}
+
+/*
+ * If we tracked the file through the SCM inflight mechanism, we could support
+ * any file. For now, just ensure that anything potentially problematic is done
+ * inline.
+ */
+unsigned int io_file_get_flags(struct file *file)
+{
+       umode_t mode = file_inode(file)->i_mode;
+       unsigned int res = 0;
+
+       if (S_ISREG(mode))
+               res |= FFS_ISREG;
+       if (__io_file_supports_nowait(file, mode))
+               res |= FFS_NOWAIT;
+       if (io_file_need_scm(file))
+               res |= FFS_SCM;
+       return res;
+}
+
+bool io_alloc_async_data(struct io_kiocb *req)
+{
+       WARN_ON_ONCE(!io_op_defs[req->opcode].async_size);
+       req->async_data = kmalloc(io_op_defs[req->opcode].async_size, GFP_KERNEL);
+       if (req->async_data) {
+               req->flags |= REQ_F_ASYNC_DATA;
+               return false;
+       }
+       return true;
+}
+
+int io_req_prep_async(struct io_kiocb *req)
+{
+       const struct io_op_def *def = &io_op_defs[req->opcode];
+
+       /* assign early for deferred execution for non-fixed file */
+       if (def->needs_file && !(req->flags & REQ_F_FIXED_FILE))
+               req->file = io_file_get_normal(req, req->cqe.fd);
+       if (!def->prep_async)
+               return 0;
+       if (WARN_ON_ONCE(req_has_async_data(req)))
+               return -EFAULT;
+       if (io_alloc_async_data(req))
+               return -EAGAIN;
+
+       return def->prep_async(req);
+}
+
+static u32 io_get_sequence(struct io_kiocb *req)
+{
+       u32 seq = req->ctx->cached_sq_head;
+       struct io_kiocb *cur;
+
+       /* need original cached_sq_head, but it was increased for each req */
+       io_for_each_link(cur, req)
+               seq--;
+       return seq;
+}
+
+static __cold void io_drain_req(struct io_kiocb *req)
+{
+       struct io_ring_ctx *ctx = req->ctx;
+       struct io_defer_entry *de;
+       int ret;
+       u32 seq = io_get_sequence(req);
+
+       /* Still need defer if there is pending req in defer list. */
+       spin_lock(&ctx->completion_lock);
+       if (!req_need_defer(req, seq) && list_empty_careful(&ctx->defer_list)) {
+               spin_unlock(&ctx->completion_lock);
+queue:
+               ctx->drain_active = false;
+               io_req_task_queue(req);
+               return;
+       }
+       spin_unlock(&ctx->completion_lock);
+
+       ret = io_req_prep_async(req);
+       if (ret) {
+fail:
+               io_req_complete_failed(req, ret);
+               return;
+       }
+       io_prep_async_link(req);
+       de = kmalloc(sizeof(*de), GFP_KERNEL);
+       if (!de) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       spin_lock(&ctx->completion_lock);
+       if (!req_need_defer(req, seq) && list_empty(&ctx->defer_list)) {
+               spin_unlock(&ctx->completion_lock);
+               kfree(de);
+               goto queue;
+       }
+
+       trace_io_uring_defer(req);
+       de->req = req;
+       de->seq = seq;
+       list_add_tail(&de->list, &ctx->defer_list);
+       spin_unlock(&ctx->completion_lock);
+}
+
+static void io_clean_op(struct io_kiocb *req)
+{
+       if (req->flags & REQ_F_BUFFER_SELECTED) {
+               spin_lock(&req->ctx->completion_lock);
+               io_put_kbuf_comp(req);
+               spin_unlock(&req->ctx->completion_lock);
+       }
+
+       if (req->flags & REQ_F_NEED_CLEANUP) {
+               const struct io_op_def *def = &io_op_defs[req->opcode];
+
+               if (def->cleanup)
+                       def->cleanup(req);
+       }
+       if ((req->flags & REQ_F_POLLED) && req->apoll) {
+               kfree(req->apoll->double_poll);
+               kfree(req->apoll);
+               req->apoll = NULL;
+       }
+       if (req->flags & REQ_F_INFLIGHT) {
+               struct io_uring_task *tctx = req->task->io_uring;
+
+               atomic_dec(&tctx->inflight_tracked);
+       }
+       if (req->flags & REQ_F_CREDS)
+               put_cred(req->creds);
+       if (req->flags & REQ_F_ASYNC_DATA) {
+               kfree(req->async_data);
+               req->async_data = NULL;
+       }
+       req->flags &= ~IO_REQ_CLEAN_FLAGS;
+}
+
+static bool io_assign_file(struct io_kiocb *req, unsigned int issue_flags)
+{
+       if (req->file || !io_op_defs[req->opcode].needs_file)
+               return true;
+
+       if (req->flags & REQ_F_FIXED_FILE)
+               req->file = io_file_get_fixed(req, req->cqe.fd, issue_flags);
+       else
+               req->file = io_file_get_normal(req, req->cqe.fd);
+
+       return !!req->file;
+}
+
+static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags)
+{
+       const struct io_op_def *def = &io_op_defs[req->opcode];
+       const struct cred *creds = NULL;
+       int ret;
+
+       if (unlikely(!io_assign_file(req, issue_flags)))
+               return -EBADF;
+
+       if (unlikely((req->flags & REQ_F_CREDS) && req->creds != current_cred()))
+               creds = override_creds(req->creds);
+
+       if (!def->audit_skip)
+               audit_uring_entry(req->opcode);
+
+       ret = def->issue(req, issue_flags);
+
+       if (!def->audit_skip)
+               audit_uring_exit(!ret, ret);
+
+       if (creds)
+               revert_creds(creds);
+
+       if (ret == IOU_OK) {
+               if (issue_flags & IO_URING_F_COMPLETE_DEFER)
+                       io_req_complete_defer(req);
+               else
+                       io_req_complete_post(req);
+       } else if (ret != IOU_ISSUE_SKIP_COMPLETE)
+               return ret;
+
+       /* If the op doesn't have a file, we're not polling for it */
+       if ((req->ctx->flags & IORING_SETUP_IOPOLL) && req->file)
+               io_iopoll_req_issued(req, issue_flags);
+
+       return 0;
+}
+
+int io_poll_issue(struct io_kiocb *req, bool *locked)
+{
+       io_tw_lock(req->ctx, locked);
+       if (unlikely(req->task->flags & PF_EXITING))
+               return -EFAULT;
+       return io_issue_sqe(req, IO_URING_F_NONBLOCK);
+}
+
+struct io_wq_work *io_wq_free_work(struct io_wq_work *work)
+{
+       struct io_kiocb *req = container_of(work, struct io_kiocb, work);
+
+       req = io_put_req_find_next(req);
+       return req ? &req->work : NULL;
+}
+
+void io_wq_submit_work(struct io_wq_work *work)
+{
+       struct io_kiocb *req = container_of(work, struct io_kiocb, work);
+       const struct io_op_def *def = &io_op_defs[req->opcode];
+       unsigned int issue_flags = IO_URING_F_UNLOCKED;
+       bool needs_poll = false;
+       int ret = 0, err = -ECANCELED;
+
+       /* one will be dropped by ->io_free_work() after returning to io-wq */
+       if (!(req->flags & REQ_F_REFCOUNT))
+               __io_req_set_refcount(req, 2);
+       else
+               req_ref_get(req);
+
+       io_arm_ltimeout(req);
+
+       /* either cancelled or io-wq is dying, so don't touch tctx->iowq */
+       if (work->flags & IO_WQ_WORK_CANCEL) {
+fail:
+               io_req_task_queue_fail(req, err);
+               return;
+       }
+       if (!io_assign_file(req, issue_flags)) {
+               err = -EBADF;
+               work->flags |= IO_WQ_WORK_CANCEL;
+               goto fail;
+       }
+
+       if (req->flags & REQ_F_FORCE_ASYNC) {
+               bool opcode_poll = def->pollin || def->pollout;
+
+               if (opcode_poll && file_can_poll(req->file)) {
+                       needs_poll = true;
+                       issue_flags |= IO_URING_F_NONBLOCK;
+               }
+       }
+
+       do {
+               ret = io_issue_sqe(req, issue_flags);
+               if (ret != -EAGAIN)
+                       break;
+               /*
+                * We can get EAGAIN for iopolled IO even though we're
+                * forcing a sync submission from here, since we can't
+                * wait for request slots on the block side.
+                */
+               if (!needs_poll) {
+                       if (!(req->ctx->flags & IORING_SETUP_IOPOLL))
+                               break;
+                       cond_resched();
+                       continue;
+               }
+
+               if (io_arm_poll_handler(req, issue_flags) == IO_APOLL_OK)
+                       return;
+               /* aborted or ready, in either case retry blocking */
+               needs_poll = false;
+               issue_flags &= ~IO_URING_F_NONBLOCK;
+       } while (1);
+
+       /* avoid locking problems by failing it from a clean context */
+       if (ret < 0)
+               io_req_task_queue_fail(req, ret);
+}
+
+inline struct file *io_file_get_fixed(struct io_kiocb *req, int fd,
+                                     unsigned int issue_flags)
+{
+       struct io_ring_ctx *ctx = req->ctx;
+       struct file *file = NULL;
+       unsigned long file_ptr;
+
+       io_ring_submit_lock(ctx, issue_flags);
+
+       if (unlikely((unsigned int)fd >= ctx->nr_user_files))
+               goto out;
+       fd = array_index_nospec(fd, ctx->nr_user_files);
+       file_ptr = io_fixed_file_slot(&ctx->file_table, fd)->file_ptr;
+       file = (struct file *) (file_ptr & FFS_MASK);
+       file_ptr &= ~FFS_MASK;
+       /* mask in overlapping REQ_F and FFS bits */
+       req->flags |= (file_ptr << REQ_F_SUPPORT_NOWAIT_BIT);
+       io_req_set_rsrc_node(req, ctx, 0);
+       WARN_ON_ONCE(file && !test_bit(fd, ctx->file_table.bitmap));
+out:
+       io_ring_submit_unlock(ctx, issue_flags);
+       return file;
+}
+
+struct file *io_file_get_normal(struct io_kiocb *req, int fd)
+{
+       struct file *file = fget(fd);
+
+       trace_io_uring_file_get(req, fd);
+
+       /* we don't allow fixed io_uring files */
+       if (file && io_is_uring_fops(file))
+               io_req_track_inflight(req);
+       return file;
+}
+
+static void io_queue_async(struct io_kiocb *req, int ret)
+       __must_hold(&req->ctx->uring_lock)
+{
+       struct io_kiocb *linked_timeout;
+
+       if (ret != -EAGAIN || (req->flags & REQ_F_NOWAIT)) {
+               io_req_complete_failed(req, ret);
+               return;
+       }
+
+       linked_timeout = io_prep_linked_timeout(req);
+
+       switch (io_arm_poll_handler(req, 0)) {
+       case IO_APOLL_READY:
+               io_req_task_queue(req);
+               break;
+       case IO_APOLL_ABORTED:
+               /*
+                * Queued up for async execution, worker will release
+                * submit reference when the iocb is actually submitted.
+                */
+               io_kbuf_recycle(req, 0);
+               io_queue_iowq(req, NULL);
+               break;
+       case IO_APOLL_OK:
+               break;
+       }
+
+       if (linked_timeout)
+               io_queue_linked_timeout(linked_timeout);
+}
+
+static inline void io_queue_sqe(struct io_kiocb *req)
+       __must_hold(&req->ctx->uring_lock)
+{
+       int ret;
+
+       ret = io_issue_sqe(req, IO_URING_F_NONBLOCK|IO_URING_F_COMPLETE_DEFER);
+
+       /*
+        * We async punt it if the file wasn't marked NOWAIT, or if the file
+        * doesn't support non-blocking read/write attempts
+        */
+       if (likely(!ret))
+               io_arm_ltimeout(req);
+       else
+               io_queue_async(req, ret);
+}
+
+static void io_queue_sqe_fallback(struct io_kiocb *req)
+       __must_hold(&req->ctx->uring_lock)
+{
+       if (unlikely(req->flags & REQ_F_FAIL)) {
+               /*
+                * We don't submit, fail them all, for that replace hardlinks
+                * with normal links. Extra REQ_F_LINK is tolerated.
+                */
+               req->flags &= ~REQ_F_HARDLINK;
+               req->flags |= REQ_F_LINK;
+               io_req_complete_failed(req, req->cqe.res);
+       } else if (unlikely(req->ctx->drain_active)) {
+               io_drain_req(req);
+       } else {
+               int ret = io_req_prep_async(req);
+
+               if (unlikely(ret))
+                       io_req_complete_failed(req, ret);
+               else
+                       io_queue_iowq(req, NULL);
+       }
+}
+
+/*
+ * Check SQE restrictions (opcode and flags).
+ *
+ * Returns 'true' if SQE is allowed, 'false' otherwise.
+ */
+static inline bool io_check_restriction(struct io_ring_ctx *ctx,
+                                       struct io_kiocb *req,
+                                       unsigned int sqe_flags)
+{
+       if (!test_bit(req->opcode, ctx->restrictions.sqe_op))
+               return false;
+
+       if ((sqe_flags & ctx->restrictions.sqe_flags_required) !=
+           ctx->restrictions.sqe_flags_required)
+               return false;
+
+       if (sqe_flags & ~(ctx->restrictions.sqe_flags_allowed |
+                         ctx->restrictions.sqe_flags_required))
+               return false;
+
+       return true;
+}
+
+static void io_init_req_drain(struct io_kiocb *req)
+{
+       struct io_ring_ctx *ctx = req->ctx;
+       struct io_kiocb *head = ctx->submit_state.link.head;
+
+       ctx->drain_active = true;
+       if (head) {
+               /*
+                * If we need to drain a request in the middle of a link, drain
+                * the head request and the next request/link after the current
+                * link. Considering sequential execution of links,
+                * REQ_F_IO_DRAIN will be maintained for every request of our
+                * link.
+                */
+               head->flags |= REQ_F_IO_DRAIN | REQ_F_FORCE_ASYNC;
+               ctx->drain_next = true;
+       }
+}
+
+static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
+                      const struct io_uring_sqe *sqe)
+       __must_hold(&ctx->uring_lock)
+{
+       const struct io_op_def *def;
+       unsigned int sqe_flags;
+       int personality;
+       u8 opcode;
+
+       /* 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);
+       req->cqe.user_data = READ_ONCE(sqe->user_data);
+       req->file = NULL;
+       req->rsrc_node = NULL;
+       req->task = current;
+
+       if (unlikely(opcode >= IORING_OP_LAST)) {
+               req->opcode = 0;
+               return -EINVAL;
+       }
+       def = &io_op_defs[opcode];
+       if (unlikely(sqe_flags & ~SQE_COMMON_FLAGS)) {
+               /* enforce forwards compatibility on users */
+               if (sqe_flags & ~SQE_VALID_FLAGS)
+                       return -EINVAL;
+               if (sqe_flags & IOSQE_BUFFER_SELECT) {
+                       if (!def->buffer_select)
+                               return -EOPNOTSUPP;
+                       req->buf_index = READ_ONCE(sqe->buf_group);
+               }
+               if (sqe_flags & IOSQE_CQE_SKIP_SUCCESS)
+                       ctx->drain_disabled = true;
+               if (sqe_flags & IOSQE_IO_DRAIN) {
+                       if (ctx->drain_disabled)
+                               return -EOPNOTSUPP;
+                       io_init_req_drain(req);
+               }
+       }
+       if (unlikely(ctx->restricted || ctx->drain_active || ctx->drain_next)) {
+               if (ctx->restricted && !io_check_restriction(ctx, req, sqe_flags))
+                       return -EACCES;
+               /* knock it to the slow queue path, will be drained there */
+               if (ctx->drain_active)
+                       req->flags |= REQ_F_FORCE_ASYNC;
+               /* if there is no link, we're at "next" request and need to drain */
+               if (unlikely(ctx->drain_next) && !ctx->submit_state.link.head) {
+                       ctx->drain_next = false;
+                       ctx->drain_active = true;
+                       req->flags |= REQ_F_IO_DRAIN | REQ_F_FORCE_ASYNC;
+               }
+       }
+
+       if (!def->ioprio && sqe->ioprio)
+               return -EINVAL;
+       if (!def->iopoll && (ctx->flags & IORING_SETUP_IOPOLL))
+               return -EINVAL;
+
+       if (def->needs_file) {
+               struct io_submit_state *state = &ctx->submit_state;
+
+               req->cqe.fd = READ_ONCE(sqe->fd);
+
+               /*
+                * Plug now if we have more than 2 IO left after this, and the
+                * target is potentially a read/write to block based storage.
+                */
+               if (state->need_plug && def->plug) {
+                       state->plug_started = true;
+                       state->need_plug = false;
+                       blk_start_plug_nr_ios(&state->plug, state->submit_nr);
+               }
+       }
+
+       personality = READ_ONCE(sqe->personality);
+       if (personality) {
+               int ret;
+
+               req->creds = xa_load(&ctx->personalities, personality);
+               if (!req->creds)
+                       return -EINVAL;
+               get_cred(req->creds);
+               ret = security_uring_override_creds(req->creds);
+               if (ret) {
+                       put_cred(req->creds);
+                       return ret;
+               }
+               req->flags |= REQ_F_CREDS;
+       }
+
+       return def->prep(req, sqe);
+}
+
+static __cold int io_submit_fail_init(const struct io_uring_sqe *sqe,
+                                     struct io_kiocb *req, int ret)
+{
+       struct io_ring_ctx *ctx = req->ctx;
+       struct io_submit_link *link = &ctx->submit_state.link;
+       struct io_kiocb *head = link->head;
+
+       trace_io_uring_req_failed(sqe, req, ret);
+
+       /*
+        * Avoid breaking links in the middle as it renders links with SQPOLL
+        * unusable. Instead of failing eagerly, continue assembling the link if
+        * applicable and mark the head with REQ_F_FAIL. The link flushing code
+        * should find the flag and handle the rest.
+        */
+       req_fail_link_node(req, ret);
+       if (head && !(head->flags & REQ_F_FAIL))
+               req_fail_link_node(head, -ECANCELED);
+
+       if (!(req->flags & IO_REQ_LINK_FLAGS)) {
+               if (head) {
+                       link->last->link = req;
+                       link->head = NULL;
+                       req = head;
+               }
+               io_queue_sqe_fallback(req);
+               return ret;
+       }
+
+       if (head)
+               link->last->link = req;
+       else
+               link->head = req;
+       link->last = req;
+       return 0;
+}
+
+static inline int io_submit_sqe(struct io_ring_ctx *ctx, struct io_kiocb *req,
+                        const struct io_uring_sqe *sqe)
+       __must_hold(&ctx->uring_lock)
+{
+       struct io_submit_link *link = &ctx->submit_state.link;
+       int ret;
+
+       ret = io_init_req(ctx, req, sqe);
+       if (unlikely(ret))
+               return io_submit_fail_init(sqe, req, ret);
+
+       /* don't need @sqe from now on */
+       trace_io_uring_submit_sqe(req, true);
+
+       /*
+        * If we already have a head request, queue this one for async
+        * submittal once the head completes. If we don't have a head but
+        * IOSQE_IO_LINK is set in the sqe, start a new head. This one will be
+        * submitted sync once the chain is complete. If none of those
+        * conditions are true (normal request), then just queue it.
+        */
+       if (unlikely(link->head)) {
+               ret = io_req_prep_async(req);
+               if (unlikely(ret))
+                       return io_submit_fail_init(sqe, req, ret);
+
+               trace_io_uring_link(req, link->head);
+               link->last->link = req;
+               link->last = req;
+
+               if (req->flags & IO_REQ_LINK_FLAGS)
+                       return 0;
+               /* last request of the link, flush it */
+               req = link->head;
+               link->head = NULL;
+               if (req->flags & (REQ_F_FORCE_ASYNC | REQ_F_FAIL))
+                       goto fallback;
+
+       } else if (unlikely(req->flags & (IO_REQ_LINK_FLAGS |
+                                         REQ_F_FORCE_ASYNC | REQ_F_FAIL))) {
+               if (req->flags & IO_REQ_LINK_FLAGS) {
+                       link->head = req;
+                       link->last = req;
+               } else {
+fallback:
+                       io_queue_sqe_fallback(req);
+               }
+               return 0;
+       }
+
+       io_queue_sqe(req);
+       return 0;
+}
+
+/*
+ * Batched submission is done, ensure local IO is flushed out.
+ */
+static void io_submit_state_end(struct io_ring_ctx *ctx)
+{
+       struct io_submit_state *state = &ctx->submit_state;
+
+       if (unlikely(state->link.head))
+               io_queue_sqe_fallback(state->link.head);
+       /* flush only after queuing links as they can generate completions */
+       io_submit_flush_completions(ctx);
+       if (state->plug_started)
+               blk_finish_plug(&state->plug);
+}
+
+/*
+ * Start submission side cache.
+ */
+static void io_submit_state_start(struct io_submit_state *state,
+                                 unsigned int max_ios)
+{
+       state->plug_started = false;
+       state->need_plug = max_ios > 2;
+       state->submit_nr = max_ios;
+       /* set only head, no need to init link_last in advance */
+       state->link.head = NULL;
+}
+
+static void io_commit_sqring(struct io_ring_ctx *ctx)
+{
+       struct io_rings *rings = ctx->rings;
+
+       /*
+        * Ensure any loads from the SQEs are done at this point,
+        * since once we write the new head, the application could
+        * write new data to them.
+        */
+       smp_store_release(&rings->sq.head, ctx->cached_sq_head);
+}
+
+/*
+ * Fetch an sqe, if one is available. Note this returns a pointer to memory
+ * that is mapped by userspace. This means that care needs to be taken to
+ * ensure that reads are stable, as we cannot rely on userspace always
+ * being a good citizen. If members of the sqe are validated and then later
+ * used, it's important that those reads are done through READ_ONCE() to
+ * prevent a re-load down the line.
+ */
+static const struct io_uring_sqe *io_get_sqe(struct io_ring_ctx *ctx)
+{
+       unsigned head, mask = ctx->sq_entries - 1;
+       unsigned sq_idx = ctx->cached_sq_head++ & mask;
+
+       /*
+        * The cached sq head (or cq tail) serves two purposes:
+        *
+        * 1) allows us to batch the cost of updating the user visible
+        *    head updates.
+        * 2) allows the kernel side to track the head on its own, even
+        *    though the application is the one updating it.
+        */
+       head = READ_ONCE(ctx->sq_array[sq_idx]);
+       if (likely(head < ctx->sq_entries)) {
+               /* double index for 128-byte SQEs, twice as long */
+               if (ctx->flags & IORING_SETUP_SQE128)
+                       head <<= 1;
+               return &ctx->sq_sqes[head];
+       }
+
+       /* drop invalid entries */
+       ctx->cq_extra--;
+       WRITE_ONCE(ctx->rings->sq_dropped,
+                  READ_ONCE(ctx->rings->sq_dropped) + 1);
+       return NULL;
+}
+
+int io_submit_sqes(struct io_ring_ctx *ctx, unsigned int nr)
+       __must_hold(&ctx->uring_lock)
+{
+       unsigned int entries = io_sqring_entries(ctx);
+       unsigned int left;
+       int ret;
+
+       if (unlikely(!entries))
+               return 0;
+       /* make sure SQ entry isn't read before tail */
+       ret = left = min3(nr, ctx->sq_entries, entries);
+       io_get_task_refs(left);
+       io_submit_state_start(&ctx->submit_state, left);
+
+       do {
+               const struct io_uring_sqe *sqe;
+               struct io_kiocb *req;
+
+               if (unlikely(!io_alloc_req_refill(ctx)))
+                       break;
+               req = io_alloc_req(ctx);
+               sqe = io_get_sqe(ctx);
+               if (unlikely(!sqe)) {
+                       io_req_add_to_cache(req, ctx);
+                       break;
+               }
+
+               /*
+                * Continue submitting even for sqe failure if the
+                * ring was setup with IORING_SETUP_SUBMIT_ALL
+                */
+               if (unlikely(io_submit_sqe(ctx, req, sqe)) &&
+                   !(ctx->flags & IORING_SETUP_SUBMIT_ALL)) {
+                       left--;
+                       break;
+               }
+       } while (--left);
+
+       if (unlikely(left)) {
+               ret -= left;
+               /* try again if it submitted nothing and can't allocate a req */
+               if (!ret && io_req_cache_empty(ctx))
+                       ret = -EAGAIN;
+               current->io_uring->cached_refs += left;
+       }
+
+       io_submit_state_end(ctx);
+        /* Commit SQ ring head once we've consumed and submitted all SQEs */
+       io_commit_sqring(ctx);
+       return ret;
+}
+
+struct io_wait_queue {
+       struct wait_queue_entry wq;
+       struct io_ring_ctx *ctx;
+       unsigned cq_tail;
+       unsigned nr_timeouts;
+};
+
+static inline bool io_should_wake(struct io_wait_queue *iowq)
+{
+       struct io_ring_ctx *ctx = iowq->ctx;
+       int dist = ctx->cached_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)
+{
+       struct io_wait_queue *iowq = container_of(curr, struct io_wait_queue,
+                                                       wq);
+
+       /*
+        * Cannot safely flush overflowed CQEs from here, ensure we wake up
+        * the task, and the next invocation will do it.
+        */
+       if (io_should_wake(iowq) ||
+           test_bit(IO_CHECK_CQ_OVERFLOW_BIT, &iowq->ctx->check_cq))
+               return autoremove_wake_function(curr, mode, wake_flags, key);
+       return -1;
+}
+
+int io_run_task_work_sig(void)
+{
+       if (io_run_task_work())
+               return 1;
+       if (task_sigpending(current))
+               return -EINTR;
+       return 0;
+}
+
+/* when returns >0, the caller should retry */
+static inline int io_cqring_wait_schedule(struct io_ring_ctx *ctx,
+                                         struct io_wait_queue *iowq,
+                                         ktime_t timeout)
+{
+       int ret;
+       unsigned long check_cq;
+
+       /* make sure we run task_work before checking for signals */
+       ret = io_run_task_work_sig();
+       if (ret || io_should_wake(iowq))
+               return ret;
+
+       check_cq = READ_ONCE(ctx->check_cq);
+       if (unlikely(check_cq)) {
+               /* let the caller flush overflows, retry */
+               if (check_cq & BIT(IO_CHECK_CQ_OVERFLOW_BIT))
+                       return 1;
+               if (check_cq & BIT(IO_CHECK_CQ_DROPPED_BIT))
+                       return -EBADR;
+       }
+       if (!schedule_hrtimeout(&timeout, HRTIMER_MODE_ABS))
+               return -ETIME;
+       return 1;
+}
+
+/*
+ * Wait until events become available, if we don't already have some. The
+ * application must reap them itself, as they reside on the shared cq ring.
+ */
+static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events,
+                         const sigset_t __user *sig, size_t sigsz,
+                         struct __kernel_timespec __user *uts)
+{
+       struct io_wait_queue iowq;
+       struct io_rings *rings = ctx->rings;
+       ktime_t timeout = KTIME_MAX;
+       int ret;
+
+       do {
+               io_cqring_overflow_flush(ctx);
+               if (io_cqring_events(ctx) >= min_events)
+                       return 0;
+               if (!io_run_task_work())
+                       break;
+       } while (1);
+
+       if (sig) {
+#ifdef CONFIG_COMPAT
+               if (in_compat_syscall())
+                       ret = set_compat_user_sigmask((const compat_sigset_t __user *)sig,
+                                                     sigsz);
+               else
+#endif
+                       ret = set_user_sigmask(sig, sigsz);
+
+               if (ret)
+                       return ret;
+       }
+
+       if (uts) {
+               struct timespec64 ts;
+
+               if (get_timespec64(&ts, uts))
+                       return -EFAULT;
+               timeout = ktime_add_ns(timespec64_to_ktime(ts), ktime_get_ns());
+       }
+
+       init_waitqueue_func_entry(&iowq.wq, io_wake_function);
+       iowq.wq.private = current;
+       INIT_LIST_HEAD(&iowq.wq.entry);
+       iowq.ctx = ctx;
+       iowq.nr_timeouts = atomic_read(&ctx->cq_timeouts);
+       iowq.cq_tail = READ_ONCE(ctx->rings->cq.head) + min_events;
+
+       trace_io_uring_cqring_wait(ctx, min_events);
+       do {
+               /* if we can't even flush overflow, don't wait for more */
+               if (!io_cqring_overflow_flush(ctx)) {
+                       ret = -EBUSY;
+                       break;
+               }
+               prepare_to_wait_exclusive(&ctx->cq_wait, &iowq.wq,
+                                               TASK_INTERRUPTIBLE);
+               ret = io_cqring_wait_schedule(ctx, &iowq, timeout);
+               cond_resched();
+       } while (ret > 0);
+
+       finish_wait(&ctx->cq_wait, &iowq.wq);
+       restore_saved_sigmask_unless(ret == -EINTR);
+
+       return READ_ONCE(rings->cq.head) == READ_ONCE(rings->cq.tail) ? ret : 0;
+}
+
+static void io_mem_free(void *ptr)
+{
+       struct page *page;
+
+       if (!ptr)
+               return;
+
+       page = virt_to_head_page(ptr);
+       if (put_page_testzero(page))
+               free_compound_page(page);
+}
+
+static void *io_mem_alloc(size_t size)
+{
+       gfp_t gfp = GFP_KERNEL_ACCOUNT | __GFP_ZERO | __GFP_NOWARN | __GFP_COMP;
+
+       return (void *) __get_free_pages(gfp, get_order(size));
+}
+
+static unsigned long rings_size(struct io_ring_ctx *ctx, unsigned int sq_entries,
+                               unsigned int cq_entries, size_t *sq_offset)
+{
+       struct io_rings *rings;
+       size_t off, sq_array_size;
+
+       off = struct_size(rings, cqes, cq_entries);
+       if (off == SIZE_MAX)
+               return SIZE_MAX;
+       if (ctx->flags & IORING_SETUP_CQE32) {
+               if (check_shl_overflow(off, 1, &off))
+                       return SIZE_MAX;
+       }
+
+#ifdef CONFIG_SMP
+       off = ALIGN(off, SMP_CACHE_BYTES);
+       if (off == 0)
+               return SIZE_MAX;
+#endif
+
+       if (sq_offset)
+               *sq_offset = off;
+
+       sq_array_size = array_size(sizeof(u32), sq_entries);
+       if (sq_array_size == SIZE_MAX)
+               return SIZE_MAX;
+
+       if (check_add_overflow(off, sq_array_size, &off))
+               return SIZE_MAX;
+
+       return off;
+}
+
+static int io_eventfd_register(struct io_ring_ctx *ctx, void __user *arg,
+                              unsigned int eventfd_async)
+{
+       struct io_ev_fd *ev_fd;
+       __s32 __user *fds = arg;
+       int fd;
+
+       ev_fd = rcu_dereference_protected(ctx->io_ev_fd,
+                                       lockdep_is_held(&ctx->uring_lock));
+       if (ev_fd)
+               return -EBUSY;
+
+       if (copy_from_user(&fd, fds, sizeof(*fds)))
+               return -EFAULT;
+
+       ev_fd = kmalloc(sizeof(*ev_fd), GFP_KERNEL);
+       if (!ev_fd)
+               return -ENOMEM;
+
+       ev_fd->cq_ev_fd = eventfd_ctx_fdget(fd);
+       if (IS_ERR(ev_fd->cq_ev_fd)) {
+               int ret = PTR_ERR(ev_fd->cq_ev_fd);
+               kfree(ev_fd);
+               return ret;
+       }
+
+       spin_lock(&ctx->completion_lock);
+       ctx->evfd_last_cq_tail = ctx->cached_cq_tail;
+       spin_unlock(&ctx->completion_lock);
+
+       ev_fd->eventfd_async = eventfd_async;
+       ctx->has_evfd = true;
+       rcu_assign_pointer(ctx->io_ev_fd, ev_fd);
+       return 0;
+}
+
+static void io_eventfd_put(struct rcu_head *rcu)
+{
+       struct io_ev_fd *ev_fd = container_of(rcu, struct io_ev_fd, rcu);
+
+       eventfd_ctx_put(ev_fd->cq_ev_fd);
+       kfree(ev_fd);
+}
+
+static int io_eventfd_unregister(struct io_ring_ctx *ctx)
+{
+       struct io_ev_fd *ev_fd;
+
+       ev_fd = rcu_dereference_protected(ctx->io_ev_fd,
+                                       lockdep_is_held(&ctx->uring_lock));
+       if (ev_fd) {
+               ctx->has_evfd = false;
+               rcu_assign_pointer(ctx->io_ev_fd, NULL);
+               call_rcu(&ev_fd->rcu, io_eventfd_put);
+               return 0;
+       }
+
+       return -ENXIO;
+}
+
+static void io_req_caches_free(struct io_ring_ctx *ctx)
+{
+       struct io_submit_state *state = &ctx->submit_state;
+       int nr = 0;
+
+       mutex_lock(&ctx->uring_lock);
+       io_flush_cached_locked_reqs(ctx, state);
+
+       while (!io_req_cache_empty(ctx)) {
+               struct io_wq_work_node *node;
+               struct io_kiocb *req;
+
+               node = wq_stack_extract(&state->free_list);
+               req = container_of(node, struct io_kiocb, comp_list);
+               kmem_cache_free(req_cachep, req);
+               nr++;
+       }
+       if (nr)
+               percpu_ref_put_many(&ctx->refs, nr);
+       mutex_unlock(&ctx->uring_lock);
+}
+
+static __cold void io_ring_ctx_free(struct io_ring_ctx *ctx)
+{
+       io_sq_thread_finish(ctx);
+
+       if (ctx->mm_account) {
+               mmdrop(ctx->mm_account);
+               ctx->mm_account = NULL;
+       }
+
+       io_rsrc_refs_drop(ctx);
+       /* __io_rsrc_put_work() may need uring_lock to progress, wait w/o it */
+       io_wait_rsrc_data(ctx->buf_data);
+       io_wait_rsrc_data(ctx->file_data);
+
+       mutex_lock(&ctx->uring_lock);
+       if (ctx->buf_data)
+               __io_sqe_buffers_unregister(ctx);
+       if (ctx->file_data)
+               __io_sqe_files_unregister(ctx);
+       if (ctx->rings)
+               __io_cqring_overflow_flush(ctx, true);
+       io_eventfd_unregister(ctx);
+       io_alloc_cache_free(&ctx->apoll_cache, io_apoll_cache_free);
+       io_alloc_cache_free(&ctx->netmsg_cache, io_netmsg_cache_free);
+       mutex_unlock(&ctx->uring_lock);
+       io_destroy_buffers(ctx);
+       if (ctx->sq_creds)
+               put_cred(ctx->sq_creds);
+       if (ctx->submitter_task)
+               put_task_struct(ctx->submitter_task);
+
+       /* there are no registered resources left, nobody uses it */
+       if (ctx->rsrc_node)
+               io_rsrc_node_destroy(ctx->rsrc_node);
+       if (ctx->rsrc_backup_node)
+               io_rsrc_node_destroy(ctx->rsrc_backup_node);
+       flush_delayed_work(&ctx->rsrc_put_work);
+       flush_delayed_work(&ctx->fallback_work);
+
+       WARN_ON_ONCE(!list_empty(&ctx->rsrc_ref_list));
+       WARN_ON_ONCE(!llist_empty(&ctx->rsrc_put_llist));
+
+#if defined(CONFIG_UNIX)
+       if (ctx->ring_sock) {
+               ctx->ring_sock->file = NULL; /* so that iput() is called */
+               sock_release(ctx->ring_sock);
+       }
+#endif
+       WARN_ON_ONCE(!list_empty(&ctx->ltimeout_list));
+       WARN_ON_ONCE(ctx->notif_slots || ctx->nr_notif_slots);
+
+       io_mem_free(ctx->rings);
+       io_mem_free(ctx->sq_sqes);
+
+       percpu_ref_exit(&ctx->refs);
+       free_uid(ctx->user);
+       io_req_caches_free(ctx);
+       if (ctx->hash_map)
+               io_wq_put_hash(ctx->hash_map);
+       kfree(ctx->cancel_table.hbs);
+       kfree(ctx->cancel_table_locked.hbs);
+       kfree(ctx->dummy_ubuf);
+       kfree(ctx->io_bl);
+       xa_destroy(&ctx->io_bl_xa);
+       kfree(ctx);
+}
+
+static __poll_t io_uring_poll(struct file *file, poll_table *wait)
+{
+       struct io_ring_ctx *ctx = file->private_data;
+       __poll_t mask = 0;
+
+       poll_wait(file, &ctx->cq_wait, wait);
+       /*
+        * synchronizes with barrier from wq_has_sleeper call in
+        * io_commit_cqring
+        */
+       smp_rmb();
+       if (!io_sqring_full(ctx))
+               mask |= EPOLLOUT | EPOLLWRNORM;
+
+       /*
+        * Don't flush cqring overflow list here, just do a simple check.
+        * Otherwise there could possible be ABBA deadlock:
+        *      CPU0                    CPU1
+        *      ----                    ----
+        * lock(&ctx->uring_lock);
+        *                              lock(&ep->mtx);
+        *                              lock(&ctx->uring_lock);
+        * lock(&ep->mtx);
+        *
+        * Users may get EPOLLIN meanwhile seeing nothing in cqring, this
+        * pushs them to do the flush.
+        */
+       if (io_cqring_events(ctx) ||
+           test_bit(IO_CHECK_CQ_OVERFLOW_BIT, &ctx->check_cq))
+               mask |= EPOLLIN | EPOLLRDNORM;
+
+       return mask;
+}
+
+static int io_unregister_personality(struct io_ring_ctx *ctx, unsigned id)
+{
+       const struct cred *creds;
+
+       creds = xa_erase(&ctx->personalities, id);
+       if (creds) {
+               put_cred(creds);
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+struct io_tctx_exit {
+       struct callback_head            task_work;
+       struct completion               completion;
+       struct io_ring_ctx              *ctx;
+};
+
+static __cold void io_tctx_exit_cb(struct callback_head *cb)
+{
+       struct io_uring_task *tctx = current->io_uring;
+       struct io_tctx_exit *work;
+
+       work = container_of(cb, struct io_tctx_exit, task_work);
+       /*
+        * When @in_idle, we're in cancellation and it's racy to remove the
+        * node. It'll be removed by the end of cancellation, just ignore it.
+        */
+       if (!atomic_read(&tctx->in_idle))
+               io_uring_del_tctx_node((unsigned long)work->ctx);
+       complete(&work->completion);
+}
+
+static __cold bool io_cancel_ctx_cb(struct io_wq_work *work, void *data)
+{
+       struct io_kiocb *req = container_of(work, struct io_kiocb, work);
+
+       return req->ctx == data;
+}
+
+static __cold void io_ring_exit_work(struct work_struct *work)
+{
+       struct io_ring_ctx *ctx = container_of(work, struct io_ring_ctx, exit_work);
+       unsigned long timeout = jiffies + HZ * 60 * 5;
+       unsigned long interval = HZ / 20;
+       struct io_tctx_exit exit;
+       struct io_tctx_node *node;
+       int ret;
+
+       /*
+        * If we're doing polled IO and end up having requests being
+        * submitted async (out-of-line), then completions can come in while
+        * we're waiting for refs to drop. We need to reap these manually,
+        * as nobody else will be looking for them.
+        */
+       do {
+               while (io_uring_try_cancel_requests(ctx, NULL, true))
+                       cond_resched();
+
+               if (ctx->sq_data) {
+                       struct io_sq_data *sqd = ctx->sq_data;
+                       struct task_struct *tsk;
+
+                       io_sq_thread_park(sqd);
+                       tsk = sqd->thread;
+                       if (tsk && tsk->io_uring && tsk->io_uring->io_wq)
+                               io_wq_cancel_cb(tsk->io_uring->io_wq,
+                                               io_cancel_ctx_cb, ctx, true);
+                       io_sq_thread_unpark(sqd);
+               }
+
+               io_req_caches_free(ctx);
+
+               if (WARN_ON_ONCE(time_after(jiffies, timeout))) {
+                       /* there is little hope left, don't run it too often */
+                       interval = HZ * 60;
+               }
+       } while (!wait_for_completion_timeout(&ctx->ref_comp, interval));
+
+       init_completion(&exit.completion);
+       init_task_work(&exit.task_work, io_tctx_exit_cb);
+       exit.ctx = ctx;
+       /*
+        * Some may use context even when all refs and requests have been put,
+        * and they are free to do so while still holding uring_lock or
+        * completion_lock, see io_req_task_submit(). Apart from other work,
+        * this lock/unlock section also waits them to finish.
+        */
+       mutex_lock(&ctx->uring_lock);
+       while (!list_empty(&ctx->tctx_list)) {
+               WARN_ON_ONCE(time_after(jiffies, timeout));
+
+               node = list_first_entry(&ctx->tctx_list, struct io_tctx_node,
+                                       ctx_node);
+               /* don't spin on a single task if cancellation failed */
+               list_rotate_left(&ctx->tctx_list);
+               ret = task_work_add(node->task, &exit.task_work, TWA_SIGNAL);
+               if (WARN_ON_ONCE(ret))
+                       continue;
+
+               mutex_unlock(&ctx->uring_lock);
+               wait_for_completion(&exit.completion);
+               mutex_lock(&ctx->uring_lock);
+       }
+       mutex_unlock(&ctx->uring_lock);
+       spin_lock(&ctx->completion_lock);
+       spin_unlock(&ctx->completion_lock);
+
+       io_ring_ctx_free(ctx);
+}
+
+static __cold void io_ring_ctx_wait_and_kill(struct io_ring_ctx *ctx)
+{
+       unsigned long index;
+       struct creds *creds;
+
+       mutex_lock(&ctx->uring_lock);
+       percpu_ref_kill(&ctx->refs);
+       if (ctx->rings)
+               __io_cqring_overflow_flush(ctx, true);
+       xa_for_each(&ctx->personalities, index, creds)
+               io_unregister_personality(ctx, index);
+       if (ctx->rings)
+               io_poll_remove_all(ctx, NULL, true);
+       io_notif_unregister(ctx);
+       mutex_unlock(&ctx->uring_lock);
+
+       /* failed during ring init, it couldn't have issued any requests */
+       if (ctx->rings) {
+               io_kill_timeouts(ctx, NULL, true);
+               /* if we failed setting up the ctx, we might not have any rings */
+               io_iopoll_try_reap_events(ctx);
+       }
+
+       INIT_WORK(&ctx->exit_work, io_ring_exit_work);
+       /*
+        * Use system_unbound_wq to avoid spawning tons of event kworkers
+        * if we're exiting a ton of rings at the same time. It just adds
+        * noise and overhead, there's no discernable change in runtime
+        * over using system_wq.
+        */
+       queue_work(system_unbound_wq, &ctx->exit_work);
+}
+
+static int io_uring_release(struct inode *inode, struct file *file)
+{
+       struct io_ring_ctx *ctx = file->private_data;
+
+       file->private_data = NULL;
+       io_ring_ctx_wait_and_kill(ctx);
+       return 0;
+}
+
+struct io_task_cancel {
+       struct task_struct *task;
+       bool all;
+};
+
+static bool io_cancel_task_cb(struct io_wq_work *work, void *data)
+{
+       struct io_kiocb *req = container_of(work, struct io_kiocb, work);
+       struct io_task_cancel *cancel = data;
+
+       return io_match_task_safe(req, cancel->task, cancel->all);
+}
+
+static __cold bool io_cancel_defer_files(struct io_ring_ctx *ctx,
+                                        struct task_struct *task,
+                                        bool cancel_all)
+{
+       struct io_defer_entry *de;
+       LIST_HEAD(list);
+
+       spin_lock(&ctx->completion_lock);
+       list_for_each_entry_reverse(de, &ctx->defer_list, list) {
+               if (io_match_task_safe(de->req, task, cancel_all)) {
+                       list_cut_position(&list, &ctx->defer_list, &de->list);
+                       break;
+               }
+       }
+       spin_unlock(&ctx->completion_lock);
+       if (list_empty(&list))
+               return false;
+
+       while (!list_empty(&list)) {
+               de = list_first_entry(&list, struct io_defer_entry, list);
+               list_del_init(&de->list);
+               io_req_complete_failed(de->req, -ECANCELED);
+               kfree(de);
+       }
+       return true;
+}
+
+static __cold bool io_uring_try_cancel_iowq(struct io_ring_ctx *ctx)
+{
+       struct io_tctx_node *node;
+       enum io_wq_cancel cret;
+       bool ret = false;
+
+       mutex_lock(&ctx->uring_lock);
+       list_for_each_entry(node, &ctx->tctx_list, ctx_node) {
+               struct io_uring_task *tctx = node->task->io_uring;
+
+               /*
+                * io_wq will stay alive while we hold uring_lock, because it's
+                * killed after ctx nodes, which requires to take the lock.
+                */
+               if (!tctx || !tctx->io_wq)
+                       continue;
+               cret = io_wq_cancel_cb(tctx->io_wq, io_cancel_ctx_cb, ctx, true);
+               ret |= (cret != IO_WQ_CANCEL_NOTFOUND);
+       }
+       mutex_unlock(&ctx->uring_lock);
+
+       return ret;
+}
+
+static __cold bool io_uring_try_cancel_requests(struct io_ring_ctx *ctx,
+                                               struct task_struct *task,
+                                               bool cancel_all)
+{
+       struct io_task_cancel cancel = { .task = task, .all = cancel_all, };
+       struct io_uring_task *tctx = task ? task->io_uring : NULL;
+       enum io_wq_cancel cret;
+       bool ret = false;
+
+       /* failed during ring init, it couldn't have issued any requests */
+       if (!ctx->rings)
+               return false;
+
+       if (!task) {
+               ret |= io_uring_try_cancel_iowq(ctx);
+       } else if (tctx && tctx->io_wq) {
+               /*
+                * Cancels requests of all rings, not only @ctx, but
+                * it's fine as the task is in exit/exec.
+                */
+               cret = io_wq_cancel_cb(tctx->io_wq, io_cancel_task_cb,
+                                      &cancel, true);
+               ret |= (cret != IO_WQ_CANCEL_NOTFOUND);
+       }
+
+       /* SQPOLL thread does its own polling */
+       if ((!(ctx->flags & IORING_SETUP_SQPOLL) && cancel_all) ||
+           (ctx->sq_data && ctx->sq_data->thread == current)) {
+               while (!wq_list_empty(&ctx->iopoll_list)) {
+                       io_iopoll_try_reap_events(ctx);
+                       ret = true;
+               }
+       }
+
+       ret |= io_cancel_defer_files(ctx, task, cancel_all);
+       mutex_lock(&ctx->uring_lock);
+       ret |= io_poll_remove_all(ctx, task, cancel_all);
+       mutex_unlock(&ctx->uring_lock);
+       ret |= io_kill_timeouts(ctx, task, cancel_all);
+       if (task)
+               ret |= io_run_task_work();
+       return ret;
+}
+
+static s64 tctx_inflight(struct io_uring_task *tctx, bool tracked)
+{
+       if (tracked)
+               return atomic_read(&tctx->inflight_tracked);
+       return percpu_counter_sum(&tctx->inflight);
+}
+
+/*
+ * Find any io_uring ctx that this task has registered or done IO on, and cancel
+ * requests. @sqd should be not-null IFF it's an SQPOLL thread cancellation.
+ */
+__cold void io_uring_cancel_generic(bool cancel_all, struct io_sq_data *sqd)
+{
+       struct io_uring_task *tctx = current->io_uring;
+       struct io_ring_ctx *ctx;
+       s64 inflight;
+       DEFINE_WAIT(wait);
+
+       WARN_ON_ONCE(sqd && sqd->thread != current);
+
+       if (!current->io_uring)
+               return;
+       if (tctx->io_wq)
+               io_wq_exit_start(tctx->io_wq);
+
+       atomic_inc(&tctx->in_idle);
+       do {
+               bool loop = false;
+
+               io_uring_drop_tctx_refs(current);
+               /* read completions before cancelations */
+               inflight = tctx_inflight(tctx, !cancel_all);
+               if (!inflight)
+                       break;
+
+               if (!sqd) {
+                       struct io_tctx_node *node;
+                       unsigned long index;
+
+                       xa_for_each(&tctx->xa, index, node) {
+                               /* sqpoll task will cancel all its requests */
+                               if (node->ctx->sq_data)
+                                       continue;
+                               loop |= io_uring_try_cancel_requests(node->ctx,
+                                                       current, cancel_all);
+                       }
+               } else {
+                       list_for_each_entry(ctx, &sqd->ctx_list, sqd_list)
+                               loop |= io_uring_try_cancel_requests(ctx,
+                                                                    current,
+                                                                    cancel_all);
+               }
+
+               if (loop) {
+                       cond_resched();
+                       continue;
+               }
+
+               prepare_to_wait(&tctx->wait, &wait, TASK_INTERRUPTIBLE);
+               io_run_task_work();
+               io_uring_drop_tctx_refs(current);
+
+               /*
+                * If we've seen completions, retry without waiting. This
+                * avoids a race where a completion comes in before we did
+                * prepare_to_wait().
+                */
+               if (inflight == tctx_inflight(tctx, !cancel_all))
+                       schedule();
+               finish_wait(&tctx->wait, &wait);
+       } while (1);
+
+       io_uring_clean_tctx(tctx);
+       if (cancel_all) {
+               /*
+                * We shouldn't run task_works after cancel, so just leave
+                * ->in_idle set for normal exit.
+                */
+               atomic_dec(&tctx->in_idle);
+               /* for exec all current's requests should be gone, kill tctx */
+               __io_uring_free(current);
+       }
+}
+
+void __io_uring_cancel(bool cancel_all)
+{
+       io_uring_cancel_generic(cancel_all, NULL);
+}
+
+static void *io_uring_validate_mmap_request(struct file *file,
+                                           loff_t pgoff, size_t sz)
+{
+       struct io_ring_ctx *ctx = file->private_data;
+       loff_t offset = pgoff << PAGE_SHIFT;
+       struct page *page;
+       void *ptr;
+
+       switch (offset) {
+       case IORING_OFF_SQ_RING:
+       case IORING_OFF_CQ_RING:
+               ptr = ctx->rings;
+               break;
+       case IORING_OFF_SQES:
+               ptr = ctx->sq_sqes;
+               break;
+       default:
+               return ERR_PTR(-EINVAL);
+       }
+
+       page = virt_to_head_page(ptr);
+       if (sz > page_size(page))
+               return ERR_PTR(-EINVAL);
+
+       return ptr;
+}
+
+#ifdef CONFIG_MMU
+
+static __cold int io_uring_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       size_t sz = vma->vm_end - vma->vm_start;
+       unsigned long pfn;
+       void *ptr;
+
+       ptr = io_uring_validate_mmap_request(file, vma->vm_pgoff, sz);
+       if (IS_ERR(ptr))
+               return PTR_ERR(ptr);
+
+       pfn = virt_to_phys(ptr) >> PAGE_SHIFT;
+       return remap_pfn_range(vma, vma->vm_start, pfn, sz, vma->vm_page_prot);
+}
+
+#else /* !CONFIG_MMU */
+
+static int io_uring_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       return vma->vm_flags & (VM_SHARED | VM_MAYSHARE) ? 0 : -EINVAL;
+}
+
+static unsigned int io_uring_nommu_mmap_capabilities(struct file *file)
+{
+       return NOMMU_MAP_DIRECT | NOMMU_MAP_READ | NOMMU_MAP_WRITE;
+}
+
+static unsigned long io_uring_nommu_get_unmapped_area(struct file *file,
+       unsigned long addr, unsigned long len,
+       unsigned long pgoff, unsigned long flags)
+{
+       void *ptr;
+
+       ptr = io_uring_validate_mmap_request(file, pgoff, len);
+       if (IS_ERR(ptr))
+               return PTR_ERR(ptr);
+
+       return (unsigned long) ptr;
+}
+
+#endif /* !CONFIG_MMU */
+
+static int io_validate_ext_arg(unsigned flags, const void __user *argp, size_t argsz)
+{
+       if (flags & IORING_ENTER_EXT_ARG) {
+               struct io_uring_getevents_arg arg;
+
+               if (argsz != sizeof(arg))
+                       return -EINVAL;
+               if (copy_from_user(&arg, argp, sizeof(arg)))
+                       return -EFAULT;
+       }
+       return 0;
+}
+
+static int io_get_ext_arg(unsigned flags, const void __user *argp, size_t *argsz,
+                         struct __kernel_timespec __user **ts,
+                         const sigset_t __user **sig)
+{
+       struct io_uring_getevents_arg arg;
+
+       /*
+        * If EXT_ARG isn't set, then we have no timespec and the argp pointer
+        * is just a pointer to the sigset_t.
+        */
+       if (!(flags & IORING_ENTER_EXT_ARG)) {
+               *sig = (const sigset_t __user *) argp;
+               *ts = NULL;
+               return 0;
+       }
+
+       /*
+        * EXT_ARG is set - ensure we agree on the size of it and copy in our
+        * timespec and sigset_t pointers if good.
+        */
+       if (*argsz != sizeof(arg))
+               return -EINVAL;
+       if (copy_from_user(&arg, argp, sizeof(arg)))
+               return -EFAULT;
+       if (arg.pad)
+               return -EINVAL;
+       *sig = u64_to_user_ptr(arg.sigmask);
+       *argsz = arg.sigmask_sz;
+       *ts = u64_to_user_ptr(arg.ts);
+       return 0;
+}
+
+SYSCALL_DEFINE6(io_uring_enter, unsigned int, fd, u32, to_submit,
+               u32, min_complete, u32, flags, const void __user *, argp,
+               size_t, argsz)
+{
+       struct io_ring_ctx *ctx;
+       struct fd f;
+       long ret;
+
+       io_run_task_work();
+
+       if (unlikely(flags & ~(IORING_ENTER_GETEVENTS | IORING_ENTER_SQ_WAKEUP |
+                              IORING_ENTER_SQ_WAIT | IORING_ENTER_EXT_ARG |
+                              IORING_ENTER_REGISTERED_RING)))
+               return -EINVAL;
+
+       /*
+        * Ring fd has been registered via IORING_REGISTER_RING_FDS, we
+        * need only dereference our task private array to find it.
+        */
+       if (flags & IORING_ENTER_REGISTERED_RING) {
+               struct io_uring_task *tctx = current->io_uring;
+
+               if (unlikely(!tctx || fd >= IO_RINGFD_REG_MAX))
+                       return -EINVAL;
+               fd = array_index_nospec(fd, IO_RINGFD_REG_MAX);
+               f.file = tctx->registered_rings[fd];
+               f.flags = 0;
+               if (unlikely(!f.file))
+                       return -EBADF;
+       } else {
+               f = fdget(fd);
+               if (unlikely(!f.file))
+                       return -EBADF;
+               ret = -EOPNOTSUPP;
+               if (unlikely(!io_is_uring_fops(f.file)))
+                       goto out;
+       }
+
+       ctx = f.file->private_data;
+       ret = -EBADFD;
+       if (unlikely(ctx->flags & IORING_SETUP_R_DISABLED))
+               goto out;
+
+       /*
+        * For SQ polling, the thread will do all submissions and completions.
+        * Just return the requested submit count, and wake the thread if
+        * we were asked to.
+        */
+       ret = 0;
+       if (ctx->flags & IORING_SETUP_SQPOLL) {
+               io_cqring_overflow_flush(ctx);
+
+               if (unlikely(ctx->sq_data->thread == NULL)) {
+                       ret = -EOWNERDEAD;
+                       goto out;
+               }
+               if (flags & IORING_ENTER_SQ_WAKEUP)
+                       wake_up(&ctx->sq_data->wait);
+               if (flags & IORING_ENTER_SQ_WAIT) {
+                       ret = io_sqpoll_wait_sq(ctx);
+                       if (ret)
+                               goto out;
+               }
+               ret = to_submit;
+       } else if (to_submit) {
+               ret = io_uring_add_tctx_node(ctx);
+               if (unlikely(ret))
+                       goto out;
+
+               mutex_lock(&ctx->uring_lock);
+               ret = io_submit_sqes(ctx, to_submit);
+               if (ret != to_submit) {
+                       mutex_unlock(&ctx->uring_lock);
+                       goto out;
+               }
+               if ((flags & IORING_ENTER_GETEVENTS) && ctx->syscall_iopoll)
+                       goto iopoll_locked;
+               mutex_unlock(&ctx->uring_lock);
+       }
+       if (flags & IORING_ENTER_GETEVENTS) {
+               int ret2;
+               if (ctx->syscall_iopoll) {
+                       /*
+                        * We disallow the app entering submit/complete with
+                        * polling, but we still need to lock the ring to
+                        * prevent racing with polled issue that got punted to
+                        * a workqueue.
+                        */
+                       mutex_lock(&ctx->uring_lock);
+iopoll_locked:
+                       ret2 = io_validate_ext_arg(flags, argp, argsz);
+                       if (likely(!ret2)) {
+                               min_complete = min(min_complete,
+                                                  ctx->cq_entries);
+                               ret2 = io_iopoll_check(ctx, min_complete);
+                       }
+                       mutex_unlock(&ctx->uring_lock);
+               } else {
+                       const sigset_t __user *sig;
+                       struct __kernel_timespec __user *ts;
+
+                       ret2 = io_get_ext_arg(flags, argp, &argsz, &ts, &sig);
+                       if (likely(!ret2)) {
+                               min_complete = min(min_complete,
+                                                  ctx->cq_entries);
+                               ret2 = io_cqring_wait(ctx, min_complete, sig,
+                                                     argsz, ts);
+                       }
+               }
+
+               if (!ret) {
+                       ret = ret2;
+
+                       /*
+                        * EBADR indicates that one or more CQE were dropped.
+                        * Once the user has been informed we can clear the bit
+                        * as they are obviously ok with those drops.
+                        */
+                       if (unlikely(ret2 == -EBADR))
+                               clear_bit(IO_CHECK_CQ_DROPPED_BIT,
+                                         &ctx->check_cq);
+               }
+       }
+out:
+       fdput(f);
+       return ret;
+}
+
+static const struct file_operations io_uring_fops = {
+       .release        = io_uring_release,
+       .mmap           = io_uring_mmap,
+#ifndef CONFIG_MMU
+       .get_unmapped_area = io_uring_nommu_get_unmapped_area,
+       .mmap_capabilities = io_uring_nommu_mmap_capabilities,
+#endif
+       .poll           = io_uring_poll,
+#ifdef CONFIG_PROC_FS
+       .show_fdinfo    = io_uring_show_fdinfo,
+#endif
+};
+
+bool io_is_uring_fops(struct file *file)
+{
+       return file->f_op == &io_uring_fops;
+}
+
+static __cold int io_allocate_scq_urings(struct io_ring_ctx *ctx,
+                                        struct io_uring_params *p)
+{
+       struct io_rings *rings;
+       size_t size, sq_array_offset;
+
+       /* make sure these are sane, as we already accounted them */
+       ctx->sq_entries = p->sq_entries;
+       ctx->cq_entries = p->cq_entries;
+
+       size = rings_size(ctx, p->sq_entries, p->cq_entries, &sq_array_offset);
+       if (size == SIZE_MAX)
+               return -EOVERFLOW;
+
+       rings = io_mem_alloc(size);
+       if (!rings)
+               return -ENOMEM;
+
+       ctx->rings = rings;
+       ctx->sq_array = (u32 *)((char *)rings + sq_array_offset);
+       rings->sq_ring_mask = p->sq_entries - 1;
+       rings->cq_ring_mask = p->cq_entries - 1;
+       rings->sq_ring_entries = p->sq_entries;
+       rings->cq_ring_entries = p->cq_entries;
+
+       if (p->flags & IORING_SETUP_SQE128)
+               size = array_size(2 * sizeof(struct io_uring_sqe), p->sq_entries);
+       else
+               size = array_size(sizeof(struct io_uring_sqe), p->sq_entries);
+       if (size == SIZE_MAX) {
+               io_mem_free(ctx->rings);
+               ctx->rings = NULL;
+               return -EOVERFLOW;
+       }
+
+       ctx->sq_sqes = io_mem_alloc(size);
+       if (!ctx->sq_sqes) {
+               io_mem_free(ctx->rings);
+               ctx->rings = NULL;
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static int io_uring_install_fd(struct io_ring_ctx *ctx, struct file *file)
+{
+       int ret, fd;
+
+       fd = get_unused_fd_flags(O_RDWR | O_CLOEXEC);
+       if (fd < 0)
+               return fd;
+
+       ret = __io_uring_add_tctx_node(ctx, false);
+       if (ret) {
+               put_unused_fd(fd);
+               return ret;
+       }
+       fd_install(fd, file);
+       return fd;
+}
+
+/*
+ * Allocate an anonymous fd, this is what constitutes the application
+ * visible backing of an io_uring instance. The application mmaps this
+ * fd to gain access to the SQ/CQ ring details. If UNIX sockets are enabled,
+ * we have to tie this fd to a socket for file garbage collection purposes.
+ */
+static struct file *io_uring_get_file(struct io_ring_ctx *ctx)
+{
+       struct file *file;
+#if defined(CONFIG_UNIX)
+       int ret;
+
+       ret = sock_create_kern(&init_net, PF_UNIX, SOCK_RAW, IPPROTO_IP,
+                               &ctx->ring_sock);
+       if (ret)
+               return ERR_PTR(ret);
+#endif
+
+       file = anon_inode_getfile_secure("[io_uring]", &io_uring_fops, ctx,
+                                        O_RDWR | O_CLOEXEC, NULL);
+#if defined(CONFIG_UNIX)
+       if (IS_ERR(file)) {
+               sock_release(ctx->ring_sock);
+               ctx->ring_sock = NULL;
+       } else {
+               ctx->ring_sock->file = file;
+       }
+#endif
+       return file;
+}
+
+static __cold int io_uring_create(unsigned entries, struct io_uring_params *p,
+                                 struct io_uring_params __user *params)
+{
+       struct io_ring_ctx *ctx;
+       struct file *file;
+       int ret;
+
+       if (!entries)
+               return -EINVAL;
+       if (entries > IORING_MAX_ENTRIES) {
+               if (!(p->flags & IORING_SETUP_CLAMP))
+                       return -EINVAL;
+               entries = IORING_MAX_ENTRIES;
+       }
+
+       /*
+        * Use twice as many entries for the CQ ring. It's possible for the
+        * application to drive a higher depth than the size of the SQ ring,
+        * since the sqes are only used at submission time. This allows for
+        * some flexibility in overcommitting a bit. If the application has
+        * set IORING_SETUP_CQSIZE, it will have passed in the desired number
+        * of CQ ring entries manually.
+        */
+       p->sq_entries = roundup_pow_of_two(entries);
+       if (p->flags & IORING_SETUP_CQSIZE) {
+               /*
+                * If IORING_SETUP_CQSIZE is set, we do the same roundup
+                * to a power-of-two, if it isn't already. We do NOT impose
+                * any cq vs sq ring sizing.
+                */
+               if (!p->cq_entries)
+                       return -EINVAL;
+               if (p->cq_entries > IORING_MAX_CQ_ENTRIES) {
+                       if (!(p->flags & IORING_SETUP_CLAMP))
+                               return -EINVAL;
+                       p->cq_entries = IORING_MAX_CQ_ENTRIES;
+               }
+               p->cq_entries = roundup_pow_of_two(p->cq_entries);
+               if (p->cq_entries < p->sq_entries)
+                       return -EINVAL;
+       } else {
+               p->cq_entries = 2 * p->sq_entries;
+       }
+
+       ctx = io_ring_ctx_alloc(p);
+       if (!ctx)
+               return -ENOMEM;
+
+       /*
+        * When SETUP_IOPOLL and SETUP_SQPOLL are both enabled, user
+        * space applications don't need to do io completion events
+        * polling again, they can rely on io_sq_thread to do polling
+        * work, which can reduce cpu usage and uring_lock contention.
+        */
+       if (ctx->flags & IORING_SETUP_IOPOLL &&
+           !(ctx->flags & IORING_SETUP_SQPOLL))
+               ctx->syscall_iopoll = 1;
+
+       ctx->compat = in_compat_syscall();
+       if (!capable(CAP_IPC_LOCK))
+               ctx->user = get_uid(current_user());
+
+       /*
+        * For SQPOLL, we just need a wakeup, always. For !SQPOLL, if
+        * COOP_TASKRUN is set, then IPIs are never needed by the app.
+        */
+       ret = -EINVAL;
+       if (ctx->flags & IORING_SETUP_SQPOLL) {
+               /* IPI related flags don't make sense with SQPOLL */
+               if (ctx->flags & (IORING_SETUP_COOP_TASKRUN |
+                                 IORING_SETUP_TASKRUN_FLAG))
+                       goto err;
+               ctx->notify_method = TWA_SIGNAL_NO_IPI;
+       } else if (ctx->flags & IORING_SETUP_COOP_TASKRUN) {
+               ctx->notify_method = TWA_SIGNAL_NO_IPI;
+       } else {
+               if (ctx->flags & IORING_SETUP_TASKRUN_FLAG)
+                       goto err;
+               ctx->notify_method = TWA_SIGNAL;
+       }
+
+       /*
+        * This is just grabbed for accounting purposes. When a process exits,
+        * the mm is exited and dropped before the files, hence we need to hang
+        * on to this mm purely for the purposes of being able to unaccount
+        * memory (locked/pinned vm). It's not used for anything else.
+        */
+       mmgrab(current->mm);
+       ctx->mm_account = current->mm;
+
+       ret = io_allocate_scq_urings(ctx, p);
+       if (ret)
+               goto err;
+
+       ret = io_sq_offload_create(ctx, p);
+       if (ret)
+               goto err;
+       /* always set a rsrc node */
+       ret = io_rsrc_node_switch_start(ctx);
+       if (ret)
+               goto err;
+       io_rsrc_node_switch(ctx, NULL);
+
+       memset(&p->sq_off, 0, sizeof(p->sq_off));
+       p->sq_off.head = offsetof(struct io_rings, sq.head);
+       p->sq_off.tail = offsetof(struct io_rings, sq.tail);
+       p->sq_off.ring_mask = offsetof(struct io_rings, sq_ring_mask);
+       p->sq_off.ring_entries = offsetof(struct io_rings, sq_ring_entries);
+       p->sq_off.flags = offsetof(struct io_rings, sq_flags);
+       p->sq_off.dropped = offsetof(struct io_rings, sq_dropped);
+       p->sq_off.array = (char *)ctx->sq_array - (char *)ctx->rings;
+
+       memset(&p->cq_off, 0, sizeof(p->cq_off));
+       p->cq_off.head = offsetof(struct io_rings, cq.head);
+       p->cq_off.tail = offsetof(struct io_rings, cq.tail);
+       p->cq_off.ring_mask = offsetof(struct io_rings, cq_ring_mask);
+       p->cq_off.ring_entries = offsetof(struct io_rings, cq_ring_entries);
+       p->cq_off.overflow = offsetof(struct io_rings, cq_overflow);
+       p->cq_off.cqes = offsetof(struct io_rings, cqes);
+       p->cq_off.flags = offsetof(struct io_rings, cq_flags);
+
+       p->features = IORING_FEAT_SINGLE_MMAP | IORING_FEAT_NODROP |
+                       IORING_FEAT_SUBMIT_STABLE | IORING_FEAT_RW_CUR_POS |
+                       IORING_FEAT_CUR_PERSONALITY | IORING_FEAT_FAST_POLL |
+                       IORING_FEAT_POLL_32BITS | IORING_FEAT_SQPOLL_NONFIXED |
+                       IORING_FEAT_EXT_ARG | IORING_FEAT_NATIVE_WORKERS |
+                       IORING_FEAT_RSRC_TAGS | IORING_FEAT_CQE_SKIP |
+                       IORING_FEAT_LINKED_FILE;
+
+       if (copy_to_user(params, p, sizeof(*p))) {
+               ret = -EFAULT;
+               goto err;
+       }
+
+       file = io_uring_get_file(ctx);
+       if (IS_ERR(file)) {
+               ret = PTR_ERR(file);
+               goto err;
+       }
+
+       /*
+        * Install ring fd as the very last thing, so we don't risk someone
+        * having closed it before we finish setup
+        */
+       ret = io_uring_install_fd(ctx, file);
+       if (ret < 0) {
+               /* fput will clean it up */
+               fput(file);
+               return ret;
+       }
+
+       trace_io_uring_create(ret, ctx, p->sq_entries, p->cq_entries, p->flags);
+       return ret;
+err:
+       io_ring_ctx_wait_and_kill(ctx);
+       return ret;
+}
+
+/*
+ * Sets up an aio uring context, and returns the fd. Applications asks for a
+ * ring size, we return the actual sq/cq ring sizes (among other things) in the
+ * params structure passed in.
+ */
+static long io_uring_setup(u32 entries, struct io_uring_params __user *params)
+{
+       struct io_uring_params p;
+       int i;
+
+       if (copy_from_user(&p, params, sizeof(p)))
+               return -EFAULT;
+       for (i = 0; i < ARRAY_SIZE(p.resv); i++) {
+               if (p.resv[i])
+                       return -EINVAL;
+       }
+
+       if (p.flags & ~(IORING_SETUP_IOPOLL | IORING_SETUP_SQPOLL |
+                       IORING_SETUP_SQ_AFF | IORING_SETUP_CQSIZE |
+                       IORING_SETUP_CLAMP | IORING_SETUP_ATTACH_WQ |
+                       IORING_SETUP_R_DISABLED | IORING_SETUP_SUBMIT_ALL |
+                       IORING_SETUP_COOP_TASKRUN | IORING_SETUP_TASKRUN_FLAG |
+                       IORING_SETUP_SQE128 | IORING_SETUP_CQE32 |
+                       IORING_SETUP_SINGLE_ISSUER))
+               return -EINVAL;
+
+       return io_uring_create(entries, &p, params);
+}
+
+SYSCALL_DEFINE2(io_uring_setup, u32, entries,
+               struct io_uring_params __user *, params)
+{
+       return io_uring_setup(entries, params);
+}
+
+static __cold int io_probe(struct io_ring_ctx *ctx, void __user *arg,
+                          unsigned nr_args)
+{
+       struct io_uring_probe *p;
+       size_t size;
+       int i, ret;
+
+       size = struct_size(p, ops, nr_args);
+       if (size == SIZE_MAX)
+               return -EOVERFLOW;
+       p = kzalloc(size, GFP_KERNEL);
+       if (!p)
+               return -ENOMEM;
+
+       ret = -EFAULT;
+       if (copy_from_user(p, arg, size))
+               goto out;
+       ret = -EINVAL;
+       if (memchr_inv(p, 0, size))
+               goto out;
+
+       p->last_op = IORING_OP_LAST - 1;
+       if (nr_args > IORING_OP_LAST)
+               nr_args = IORING_OP_LAST;
+
+       for (i = 0; i < nr_args; i++) {
+               p->ops[i].op = i;
+               if (!io_op_defs[i].not_supported)
+                       p->ops[i].flags = IO_URING_OP_SUPPORTED;
+       }
+       p->ops_len = i;
+
+       ret = 0;
+       if (copy_to_user(arg, p, size))
+               ret = -EFAULT;
+out:
+       kfree(p);
+       return ret;
+}
+
+static int io_register_personality(struct io_ring_ctx *ctx)
+{
+       const struct cred *creds;
+       u32 id;
+       int ret;
+
+       creds = get_current_cred();
+
+       ret = xa_alloc_cyclic(&ctx->personalities, &id, (void *)creds,
+                       XA_LIMIT(0, USHRT_MAX), &ctx->pers_next, GFP_KERNEL);
+       if (ret < 0) {
+               put_cred(creds);
+               return ret;
+       }
+       return id;
+}
+
+static __cold int io_register_restrictions(struct io_ring_ctx *ctx,
+                                          void __user *arg, unsigned int nr_args)
+{
+       struct io_uring_restriction *res;
+       size_t size;
+       int i, ret;
+
+       /* Restrictions allowed only if rings started disabled */
+       if (!(ctx->flags & IORING_SETUP_R_DISABLED))
+               return -EBADFD;
+
+       /* We allow only a single restrictions registration */
+       if (ctx->restrictions.registered)
+               return -EBUSY;
+
+       if (!arg || nr_args > IORING_MAX_RESTRICTIONS)
+               return -EINVAL;
+
+       size = array_size(nr_args, sizeof(*res));
+       if (size == SIZE_MAX)
+               return -EOVERFLOW;
+
+       res = memdup_user(arg, size);
+       if (IS_ERR(res))
+               return PTR_ERR(res);
+
+       ret = 0;
+
+       for (i = 0; i < nr_args; i++) {
+               switch (res[i].opcode) {
+               case IORING_RESTRICTION_REGISTER_OP:
+                       if (res[i].register_op >= IORING_REGISTER_LAST) {
+                               ret = -EINVAL;
+                               goto out;
+                       }
+
+                       __set_bit(res[i].register_op,
+                                 ctx->restrictions.register_op);
+                       break;
+               case IORING_RESTRICTION_SQE_OP:
+                       if (res[i].sqe_op >= IORING_OP_LAST) {
+                               ret = -EINVAL;
+                               goto out;
+                       }
+
+                       __set_bit(res[i].sqe_op, ctx->restrictions.sqe_op);
+                       break;
+               case IORING_RESTRICTION_SQE_FLAGS_ALLOWED:
+                       ctx->restrictions.sqe_flags_allowed = res[i].sqe_flags;
+                       break;
+               case IORING_RESTRICTION_SQE_FLAGS_REQUIRED:
+                       ctx->restrictions.sqe_flags_required = res[i].sqe_flags;
+                       break;
+               default:
+                       ret = -EINVAL;
+                       goto out;
+               }
+       }
+
+out:
+       /* Reset all restrictions if an error happened */
+       if (ret != 0)
+               memset(&ctx->restrictions, 0, sizeof(ctx->restrictions));
+       else
+               ctx->restrictions.registered = true;
+
+       kfree(res);
+       return ret;
+}
+
+static int io_register_enable_rings(struct io_ring_ctx *ctx)
+{
+       if (!(ctx->flags & IORING_SETUP_R_DISABLED))
+               return -EBADFD;
+
+       if (ctx->restrictions.registered)
+               ctx->restricted = 1;
+
+       ctx->flags &= ~IORING_SETUP_R_DISABLED;
+       if (ctx->sq_data && wq_has_sleeper(&ctx->sq_data->wait))
+               wake_up(&ctx->sq_data->wait);
+       return 0;
+}
+
+static __cold int io_register_iowq_aff(struct io_ring_ctx *ctx,
+                                      void __user *arg, unsigned len)
+{
+       struct io_uring_task *tctx = current->io_uring;
+       cpumask_var_t new_mask;
+       int ret;
+
+       if (!tctx || !tctx->io_wq)
+               return -EINVAL;
+
+       if (!alloc_cpumask_var(&new_mask, GFP_KERNEL))
+               return -ENOMEM;
+
+       cpumask_clear(new_mask);
+       if (len > cpumask_size())
+               len = cpumask_size();
+
+       if (in_compat_syscall()) {
+               ret = compat_get_bitmap(cpumask_bits(new_mask),
+                                       (const compat_ulong_t __user *)arg,
+                                       len * 8 /* CHAR_BIT */);
+       } else {
+               ret = copy_from_user(new_mask, arg, len);
+       }
+
+       if (ret) {
+               free_cpumask_var(new_mask);
+               return -EFAULT;
+       }
+
+       ret = io_wq_cpu_affinity(tctx->io_wq, new_mask);
+       free_cpumask_var(new_mask);
+       return ret;
+}
+
+static __cold int io_unregister_iowq_aff(struct io_ring_ctx *ctx)
+{
+       struct io_uring_task *tctx = current->io_uring;
+
+       if (!tctx || !tctx->io_wq)
+               return -EINVAL;
+
+       return io_wq_cpu_affinity(tctx->io_wq, NULL);
+}
+
+static __cold int io_register_iowq_max_workers(struct io_ring_ctx *ctx,
+                                              void __user *arg)
+       __must_hold(&ctx->uring_lock)
+{
+       struct io_tctx_node *node;
+       struct io_uring_task *tctx = NULL;
+       struct io_sq_data *sqd = NULL;
+       __u32 new_count[2];
+       int i, ret;
+
+       if (copy_from_user(new_count, arg, sizeof(new_count)))
+               return -EFAULT;
+       for (i = 0; i < ARRAY_SIZE(new_count); i++)
+               if (new_count[i] > INT_MAX)
+                       return -EINVAL;
+
+       if (ctx->flags & IORING_SETUP_SQPOLL) {
+               sqd = ctx->sq_data;
+               if (sqd) {
+                       /*
+                        * Observe the correct sqd->lock -> ctx->uring_lock
+                        * ordering. Fine to drop uring_lock here, we hold
+                        * a ref to the ctx.
+                        */
+                       refcount_inc(&sqd->refs);
+                       mutex_unlock(&ctx->uring_lock);
+                       mutex_lock(&sqd->lock);
+                       mutex_lock(&ctx->uring_lock);
+                       if (sqd->thread)
+                               tctx = sqd->thread->io_uring;
+               }
+       } else {
+               tctx = current->io_uring;
+       }
+
+       BUILD_BUG_ON(sizeof(new_count) != sizeof(ctx->iowq_limits));
+
+       for (i = 0; i < ARRAY_SIZE(new_count); i++)
+               if (new_count[i])
+                       ctx->iowq_limits[i] = new_count[i];
+       ctx->iowq_limits_set = true;
+
+       if (tctx && tctx->io_wq) {
+               ret = io_wq_max_workers(tctx->io_wq, new_count);
+               if (ret)
+                       goto err;
+       } else {
+               memset(new_count, 0, sizeof(new_count));
+       }
+
+       if (sqd) {
+               mutex_unlock(&sqd->lock);
+               io_put_sq_data(sqd);
+       }
+
+       if (copy_to_user(arg, new_count, sizeof(new_count)))
+               return -EFAULT;
+
+       /* that's it for SQPOLL, only the SQPOLL task creates requests */
+       if (sqd)
+               return 0;
+
+       /* now propagate the restriction to all registered users */
+       list_for_each_entry(node, &ctx->tctx_list, ctx_node) {
+               struct io_uring_task *tctx = node->task->io_uring;
+
+               if (WARN_ON_ONCE(!tctx->io_wq))
+                       continue;
+
+               for (i = 0; i < ARRAY_SIZE(new_count); i++)
+                       new_count[i] = ctx->iowq_limits[i];
+               /* ignore errors, it always returns zero anyway */
+               (void)io_wq_max_workers(tctx->io_wq, new_count);
+       }
+       return 0;
+err:
+       if (sqd) {
+               mutex_unlock(&sqd->lock);
+               io_put_sq_data(sqd);
+       }
+       return ret;
+}
+
+static int __io_uring_register(struct io_ring_ctx *ctx, unsigned opcode,
+                              void __user *arg, unsigned nr_args)
+       __releases(ctx->uring_lock)
+       __acquires(ctx->uring_lock)
+{
+       int ret;
+
+       /*
+        * We don't quiesce the refs for register anymore and so it can't be
+        * dying as we're holding a file ref here.
+        */
+       if (WARN_ON_ONCE(percpu_ref_is_dying(&ctx->refs)))
+               return -ENXIO;
+
+       if (ctx->restricted) {
+               if (opcode >= IORING_REGISTER_LAST)
+                       return -EINVAL;
+               opcode = array_index_nospec(opcode, IORING_REGISTER_LAST);
+               if (!test_bit(opcode, ctx->restrictions.register_op))
+                       return -EACCES;
+       }
+
+       switch (opcode) {
+       case IORING_REGISTER_BUFFERS:
+               ret = -EFAULT;
+               if (!arg)
+                       break;
+               ret = io_sqe_buffers_register(ctx, arg, nr_args, NULL);
+               break;
+       case IORING_UNREGISTER_BUFFERS:
+               ret = -EINVAL;
+               if (arg || nr_args)
+                       break;
+               ret = io_sqe_buffers_unregister(ctx);
+               break;
+       case IORING_REGISTER_FILES:
+               ret = -EFAULT;
+               if (!arg)
+                       break;
+               ret = io_sqe_files_register(ctx, arg, nr_args, NULL);
+               break;
+       case IORING_UNREGISTER_FILES:
+               ret = -EINVAL;
+               if (arg || nr_args)
+                       break;
+               ret = io_sqe_files_unregister(ctx);
+               break;
+       case IORING_REGISTER_FILES_UPDATE:
+               ret = io_register_files_update(ctx, arg, nr_args);
+               break;
+       case IORING_REGISTER_EVENTFD:
+               ret = -EINVAL;
+               if (nr_args != 1)
+                       break;
+               ret = io_eventfd_register(ctx, arg, 0);
+               break;
+       case IORING_REGISTER_EVENTFD_ASYNC:
+               ret = -EINVAL;
+               if (nr_args != 1)
+                       break;
+               ret = io_eventfd_register(ctx, arg, 1);
+               break;
+       case IORING_UNREGISTER_EVENTFD:
+               ret = -EINVAL;
+               if (arg || nr_args)
+                       break;
+               ret = io_eventfd_unregister(ctx);
+               break;
+       case IORING_REGISTER_PROBE:
+               ret = -EINVAL;
+               if (!arg || nr_args > 256)
+                       break;
+               ret = io_probe(ctx, arg, nr_args);
+               break;
+       case IORING_REGISTER_PERSONALITY:
+               ret = -EINVAL;
+               if (arg || nr_args)
+                       break;
+               ret = io_register_personality(ctx);
+               break;
+       case IORING_UNREGISTER_PERSONALITY:
+               ret = -EINVAL;
+               if (arg)
+                       break;
+               ret = io_unregister_personality(ctx, nr_args);
+               break;
+       case IORING_REGISTER_ENABLE_RINGS:
+               ret = -EINVAL;
+               if (arg || nr_args)
+                       break;
+               ret = io_register_enable_rings(ctx);
+               break;
+       case IORING_REGISTER_RESTRICTIONS:
+               ret = io_register_restrictions(ctx, arg, nr_args);
+               break;
+       case IORING_REGISTER_FILES2:
+               ret = io_register_rsrc(ctx, arg, nr_args, IORING_RSRC_FILE);
+               break;
+       case IORING_REGISTER_FILES_UPDATE2:
+               ret = io_register_rsrc_update(ctx, arg, nr_args,
+                                             IORING_RSRC_FILE);
+               break;
+       case IORING_REGISTER_BUFFERS2:
+               ret = io_register_rsrc(ctx, arg, nr_args, IORING_RSRC_BUFFER);
+               break;
+       case IORING_REGISTER_BUFFERS_UPDATE:
+               ret = io_register_rsrc_update(ctx, arg, nr_args,
+                                             IORING_RSRC_BUFFER);
+               break;
+       case IORING_REGISTER_IOWQ_AFF:
+               ret = -EINVAL;
+               if (!arg || !nr_args)
+                       break;
+               ret = io_register_iowq_aff(ctx, arg, nr_args);
+               break;
+       case IORING_UNREGISTER_IOWQ_AFF:
+               ret = -EINVAL;
+               if (arg || nr_args)
+                       break;
+               ret = io_unregister_iowq_aff(ctx);
+               break;
+       case IORING_REGISTER_IOWQ_MAX_WORKERS:
+               ret = -EINVAL;
+               if (!arg || nr_args != 2)
+                       break;
+               ret = io_register_iowq_max_workers(ctx, arg);
+               break;
+       case IORING_REGISTER_RING_FDS:
+               ret = io_ringfd_register(ctx, arg, nr_args);
+               break;
+       case IORING_UNREGISTER_RING_FDS:
+               ret = io_ringfd_unregister(ctx, arg, nr_args);
+               break;
+       case IORING_REGISTER_PBUF_RING:
+               ret = -EINVAL;
+               if (!arg || nr_args != 1)
+                       break;
+               ret = io_register_pbuf_ring(ctx, arg);
+               break;
+       case IORING_UNREGISTER_PBUF_RING:
+               ret = -EINVAL;
+               if (!arg || nr_args != 1)
+                       break;
+               ret = io_unregister_pbuf_ring(ctx, arg);
+               break;
+       case IORING_REGISTER_SYNC_CANCEL:
+               ret = -EINVAL;
+               if (!arg || nr_args != 1)
+                       break;
+               ret = io_sync_cancel(ctx, arg);
+               break;
+       case IORING_REGISTER_FILE_ALLOC_RANGE:
+               ret = -EINVAL;
+               if (!arg || nr_args)
+                       break;
+               ret = io_register_file_alloc_range(ctx, arg);
+               break;
+       case IORING_REGISTER_NOTIFIERS:
+               ret = io_notif_register(ctx, arg, nr_args);
+               break;
+       case IORING_UNREGISTER_NOTIFIERS:
+               ret = -EINVAL;
+               if (arg || nr_args)
+                       break;
+               ret = io_notif_unregister(ctx);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+SYSCALL_DEFINE4(io_uring_register, unsigned int, fd, unsigned int, opcode,
+               void __user *, arg, unsigned int, nr_args)
+{
+       struct io_ring_ctx *ctx;
+       long ret = -EBADF;
+       struct fd f;
+
+       f = fdget(fd);
+       if (!f.file)
+               return -EBADF;
+
+       ret = -EOPNOTSUPP;
+       if (!io_is_uring_fops(f.file))
+               goto out_fput;
+
+       ctx = f.file->private_data;
+
+       io_run_task_work();
+
+       mutex_lock(&ctx->uring_lock);
+       ret = __io_uring_register(ctx, opcode, arg, nr_args);
+       mutex_unlock(&ctx->uring_lock);
+       trace_io_uring_register(ctx, opcode, ctx->nr_user_files, ctx->nr_user_bufs, ret);
+out_fput:
+       fdput(f);
+       return ret;
+}
+
+static int __init io_uring_init(void)
+{
+#define __BUILD_BUG_VERIFY_ELEMENT(stype, eoffset, etype, ename) do { \
+       BUILD_BUG_ON(offsetof(stype, ename) != eoffset); \
+       BUILD_BUG_ON(sizeof(etype) != sizeof_field(stype, ename)); \
+} while (0)
+
+#define BUILD_BUG_SQE_ELEM(eoffset, etype, ename) \
+       __BUILD_BUG_VERIFY_ELEMENT(struct io_uring_sqe, eoffset, etype, ename)
+       BUILD_BUG_ON(sizeof(struct io_uring_sqe) != 64);
+       BUILD_BUG_SQE_ELEM(0,  __u8,   opcode);
+       BUILD_BUG_SQE_ELEM(1,  __u8,   flags);
+       BUILD_BUG_SQE_ELEM(2,  __u16,  ioprio);
+       BUILD_BUG_SQE_ELEM(4,  __s32,  fd);
+       BUILD_BUG_SQE_ELEM(8,  __u64,  off);
+       BUILD_BUG_SQE_ELEM(8,  __u64,  addr2);
+       BUILD_BUG_SQE_ELEM(16, __u64,  addr);
+       BUILD_BUG_SQE_ELEM(16, __u64,  splice_off_in);
+       BUILD_BUG_SQE_ELEM(24, __u32,  len);
+       BUILD_BUG_SQE_ELEM(28,     __kernel_rwf_t, rw_flags);
+       BUILD_BUG_SQE_ELEM(28, /* compat */   int, rw_flags);
+       BUILD_BUG_SQE_ELEM(28, /* compat */ __u32, rw_flags);
+       BUILD_BUG_SQE_ELEM(28, __u32,  fsync_flags);
+       BUILD_BUG_SQE_ELEM(28, /* compat */ __u16,  poll_events);
+       BUILD_BUG_SQE_ELEM(28, __u32,  poll32_events);
+       BUILD_BUG_SQE_ELEM(28, __u32,  sync_range_flags);
+       BUILD_BUG_SQE_ELEM(28, __u32,  msg_flags);
+       BUILD_BUG_SQE_ELEM(28, __u32,  timeout_flags);
+       BUILD_BUG_SQE_ELEM(28, __u32,  accept_flags);
+       BUILD_BUG_SQE_ELEM(28, __u32,  cancel_flags);
+       BUILD_BUG_SQE_ELEM(28, __u32,  open_flags);
+       BUILD_BUG_SQE_ELEM(28, __u32,  statx_flags);
+       BUILD_BUG_SQE_ELEM(28, __u32,  fadvise_advice);
+       BUILD_BUG_SQE_ELEM(28, __u32,  splice_flags);
+       BUILD_BUG_SQE_ELEM(32, __u64,  user_data);
+       BUILD_BUG_SQE_ELEM(40, __u16,  buf_index);
+       BUILD_BUG_SQE_ELEM(40, __u16,  buf_group);
+       BUILD_BUG_SQE_ELEM(42, __u16,  personality);
+       BUILD_BUG_SQE_ELEM(44, __s32,  splice_fd_in);
+       BUILD_BUG_SQE_ELEM(44, __u32,  file_index);
+       BUILD_BUG_SQE_ELEM(48, __u64,  addr3);
+
+       BUILD_BUG_ON(sizeof(struct io_uring_files_update) !=
+                    sizeof(struct io_uring_rsrc_update));
+       BUILD_BUG_ON(sizeof(struct io_uring_rsrc_update) >
+                    sizeof(struct io_uring_rsrc_update2));
+
+       /* ->buf_index is u16 */
+       BUILD_BUG_ON(offsetof(struct io_uring_buf_ring, bufs) != 0);
+       BUILD_BUG_ON(offsetof(struct io_uring_buf, resv) !=
+                    offsetof(struct io_uring_buf_ring, tail));
+
+       /* should fit into one byte */
+       BUILD_BUG_ON(SQE_VALID_FLAGS >= (1 << 8));
+       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(sizeof(atomic_t) != sizeof(u32));
+
+       io_uring_optable_init();
+
+       req_cachep = KMEM_CACHE(io_kiocb, SLAB_HWCACHE_ALIGN | SLAB_PANIC |
+                               SLAB_ACCOUNT);
+       return 0;
+};
+__initcall(io_uring_init);
diff --git a/io_uring/io_uring.h b/io_uring/io_uring.h
new file mode 100644 (file)
index 0000000..2f73f83
--- /dev/null
@@ -0,0 +1,304 @@
+#ifndef IOU_CORE_H
+#define IOU_CORE_H
+
+#include <linux/errno.h>
+#include <linux/lockdep.h>
+#include <linux/io_uring_types.h>
+#include "io-wq.h"
+#include "slist.h"
+#include "filetable.h"
+
+#ifndef CREATE_TRACE_POINTS
+#include <trace/events/io_uring.h>
+#endif
+
+enum {
+       IOU_OK                  = 0,
+       IOU_ISSUE_SKIP_COMPLETE = -EIOCBQUEUED,
+
+       /*
+        * Intended only when both REQ_F_POLLED and REQ_F_APOLL_MULTISHOT
+        * are set to indicate to the poll runner that multishot should be
+        * removed and the result is set on req->cqe.res.
+        */
+       IOU_STOP_MULTISHOT      = -ECANCELED,
+};
+
+struct io_uring_cqe *__io_get_cqe(struct io_ring_ctx *ctx);
+bool io_req_cqe_overflow(struct io_kiocb *req);
+int io_run_task_work_sig(void);
+void io_req_complete_failed(struct io_kiocb *req, s32 res);
+void __io_req_complete(struct io_kiocb *req, unsigned issue_flags);
+void io_req_complete_post(struct io_kiocb *req);
+void __io_req_complete_post(struct io_kiocb *req);
+bool io_post_aux_cqe(struct io_ring_ctx *ctx, u64 user_data, s32 res, u32 cflags,
+                    bool allow_overflow);
+bool io_fill_cqe_aux(struct io_ring_ctx *ctx, u64 user_data, s32 res, u32 cflags,
+                    bool allow_overflow);
+void __io_commit_cqring_flush(struct io_ring_ctx *ctx);
+
+struct page **io_pin_pages(unsigned long ubuf, unsigned long len, int *npages);
+
+struct file *io_file_get_normal(struct io_kiocb *req, int fd);
+struct file *io_file_get_fixed(struct io_kiocb *req, int fd,
+                              unsigned issue_flags);
+
+static inline bool io_req_ffs_set(struct io_kiocb *req)
+{
+       return req->flags & REQ_F_FIXED_FILE;
+}
+
+bool io_is_uring_fops(struct file *file);
+bool io_alloc_async_data(struct io_kiocb *req);
+void io_req_task_work_add(struct io_kiocb *req);
+void io_req_tw_post_queue(struct io_kiocb *req, s32 res, u32 cflags);
+void io_req_task_queue(struct io_kiocb *req);
+void io_queue_iowq(struct io_kiocb *req, bool *dont_use);
+void io_req_task_complete(struct io_kiocb *req, bool *locked);
+void io_req_task_queue_fail(struct io_kiocb *req, int ret);
+void io_req_task_submit(struct io_kiocb *req, bool *locked);
+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,
+                               struct io_ring_ctx *ctx);
+
+int io_poll_issue(struct io_kiocb *req, bool *locked);
+int io_submit_sqes(struct io_ring_ctx *ctx, unsigned int nr);
+int io_do_iopoll(struct io_ring_ctx *ctx, bool force_nonspin);
+void io_free_batch_list(struct io_ring_ctx *ctx, struct io_wq_work_node *node);
+int io_req_prep_async(struct io_kiocb *req);
+
+struct io_wq_work *io_wq_free_work(struct io_wq_work *work);
+void io_wq_submit_work(struct io_wq_work *work);
+
+void io_free_req(struct io_kiocb *req);
+void io_queue_next(struct io_kiocb *req);
+void __io_put_task(struct task_struct *task, int nr);
+void io_task_refs_refill(struct io_uring_task *tctx);
+bool __io_alloc_req_refill(struct io_ring_ctx *ctx);
+
+bool io_match_task_safe(struct io_kiocb *head, struct task_struct *task,
+                       bool cancel_all);
+
+#define io_for_each_link(pos, head) \
+       for (pos = (head); pos; pos = pos->link)
+
+static inline void io_cq_lock(struct io_ring_ctx *ctx)
+       __acquires(ctx->completion_lock)
+{
+       spin_lock(&ctx->completion_lock);
+}
+
+void io_cq_unlock_post(struct io_ring_ctx *ctx);
+
+static inline struct io_uring_cqe *io_get_cqe(struct io_ring_ctx *ctx)
+{
+       if (likely(ctx->cqe_cached < ctx->cqe_sentinel)) {
+               struct io_uring_cqe *cqe = ctx->cqe_cached;
+
+               ctx->cached_cq_tail++;
+               ctx->cqe_cached++;
+               if (ctx->flags & IORING_SETUP_CQE32)
+                       ctx->cqe_cached++;
+               return cqe;
+       }
+
+       return __io_get_cqe(ctx);
+}
+
+static inline bool __io_fill_cqe_req(struct io_ring_ctx *ctx,
+                                    struct io_kiocb *req)
+{
+       struct io_uring_cqe *cqe;
+
+       /*
+        * If we can't get a cq entry, userspace overflowed the
+        * submission (by quite a lot). Increment the overflow count in
+        * the ring.
+        */
+       cqe = io_get_cqe(ctx);
+       if (unlikely(!cqe))
+               return io_req_cqe_overflow(req);
+
+       trace_io_uring_complete(req->ctx, req, req->cqe.user_data,
+                               req->cqe.res, req->cqe.flags,
+                               (req->flags & REQ_F_CQE32_INIT) ? req->extra1 : 0,
+                               (req->flags & REQ_F_CQE32_INIT) ? req->extra2 : 0);
+
+       memcpy(cqe, &req->cqe, sizeof(*cqe));
+
+       if (ctx->flags & IORING_SETUP_CQE32) {
+               u64 extra1 = 0, extra2 = 0;
+
+               if (req->flags & REQ_F_CQE32_INIT) {
+                       extra1 = req->extra1;
+                       extra2 = req->extra2;
+               }
+
+               WRITE_ONCE(cqe->big_cqe[0], extra1);
+               WRITE_ONCE(cqe->big_cqe[1], extra2);
+       }
+       return true;
+}
+
+static inline void req_set_fail(struct io_kiocb *req)
+{
+       req->flags |= REQ_F_FAIL;
+       if (req->flags & REQ_F_CQE_SKIP) {
+               req->flags &= ~REQ_F_CQE_SKIP;
+               req->flags |= REQ_F_SKIP_LINK_CQES;
+       }
+}
+
+static inline void io_req_set_res(struct io_kiocb *req, s32 res, u32 cflags)
+{
+       req->cqe.res = res;
+       req->cqe.flags = cflags;
+}
+
+static inline bool req_has_async_data(struct io_kiocb *req)
+{
+       return req->flags & REQ_F_ASYNC_DATA;
+}
+
+static inline void io_put_file(struct file *file)
+{
+       if (file)
+               fput(file);
+}
+
+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)
+               mutex_unlock(&ctx->uring_lock);
+}
+
+static inline void io_ring_submit_lock(struct io_ring_ctx *ctx,
+                                      unsigned issue_flags)
+{
+       /*
+        * "Normal" inline submissions always hold the uring_lock, since we
+        * grab it from the system call. Same is true for the SQPOLL offload.
+        * 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)
+               mutex_lock(&ctx->uring_lock);
+       lockdep_assert_held(&ctx->uring_lock);
+}
+
+static inline void io_commit_cqring(struct io_ring_ctx *ctx)
+{
+       /* order cqe stores with ring update */
+       smp_store_release(&ctx->rings->cq.tail, ctx->cached_cq_tail);
+}
+
+static inline void io_cqring_wake(struct io_ring_ctx *ctx)
+{
+       /*
+        * wake_up_all() may seem excessive, but io_wake_function() and
+        * io_should_wake() handle the termination of the loop and only
+        * wake as many waiters as we need to.
+        */
+       if (wq_has_sleeper(&ctx->cq_wait))
+               wake_up_all(&ctx->cq_wait);
+}
+
+static inline bool io_sqring_full(struct io_ring_ctx *ctx)
+{
+       struct io_rings *r = ctx->rings;
+
+       return READ_ONCE(r->sq.tail) - ctx->cached_sq_head == ctx->sq_entries;
+}
+
+static inline unsigned int io_sqring_entries(struct io_ring_ctx *ctx)
+{
+       struct io_rings *rings = ctx->rings;
+
+       /* make sure SQ entry isn't read before tail */
+       return smp_load_acquire(&rings->sq.tail) - ctx->cached_sq_head;
+}
+
+static inline bool io_run_task_work(void)
+{
+       if (test_thread_flag(TIF_NOTIFY_SIGNAL)) {
+               __set_current_state(TASK_RUNNING);
+               clear_notify_signal();
+               if (task_work_pending(current))
+                       task_work_run();
+               return true;
+       }
+
+       return false;
+}
+
+static inline void io_tw_lock(struct io_ring_ctx *ctx, bool *locked)
+{
+       if (!*locked) {
+               mutex_lock(&ctx->uring_lock);
+               *locked = true;
+       }
+}
+
+/*
+ * Don't complete immediately but use deferred completion infrastructure.
+ * Protected by ->uring_lock and can only be used either with
+ * IO_URING_F_COMPLETE_DEFER or inside a tw handler holding the mutex.
+ */
+static inline void io_req_complete_defer(struct io_kiocb *req)
+       __must_hold(&req->ctx->uring_lock)
+{
+       struct io_submit_state *state = &req->ctx->submit_state;
+
+       lockdep_assert_held(&req->ctx->uring_lock);
+
+       wq_list_add_tail(&req->comp_list, &state->compl_reqs);
+}
+
+static inline void io_commit_cqring_flush(struct io_ring_ctx *ctx)
+{
+       if (unlikely(ctx->off_timeout_used || ctx->drain_active || ctx->has_evfd))
+               __io_commit_cqring_flush(ctx);
+}
+
+/* must to be called somewhat shortly after putting a request */
+static inline void io_put_task(struct task_struct *task, int nr)
+{
+       if (likely(task == current))
+               task->io_uring->cached_refs += nr;
+       else
+               __io_put_task(task, nr);
+}
+
+static inline void io_get_task_refs(int nr)
+{
+       struct io_uring_task *tctx = current->io_uring;
+
+       tctx->cached_refs -= nr;
+       if (unlikely(tctx->cached_refs < 0))
+               io_task_refs_refill(tctx);
+}
+
+static inline bool io_req_cache_empty(struct io_ring_ctx *ctx)
+{
+       return !ctx->submit_state.free_list.next;
+}
+
+static inline bool io_alloc_req_refill(struct io_ring_ctx *ctx)
+{
+       if (unlikely(io_req_cache_empty(ctx)))
+               return __io_alloc_req_refill(ctx);
+       return true;
+}
+
+static inline struct io_kiocb *io_alloc_req(struct io_ring_ctx *ctx)
+{
+       struct io_wq_work_node *node;
+
+       node = wq_stack_extract(&ctx->submit_state.free_list);
+       return container_of(node, struct io_kiocb, comp_list);
+}
+
+#endif
diff --git a/io_uring/kbuf.c b/io_uring/kbuf.c
new file mode 100644 (file)
index 0000000..e538fa7
--- /dev/null
@@ -0,0 +1,549 @@
+// 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/namei.h>
+#include <linux/poll.h>
+#include <linux/io_uring.h>
+
+#include <uapi/linux/io_uring.h>
+
+#include "io_uring.h"
+#include "opdef.h"
+#include "kbuf.h"
+
+#define IO_BUFFER_LIST_BUF_PER_PAGE (PAGE_SIZE / sizeof(struct io_uring_buf))
+
+#define BGID_ARRAY     64
+
+struct io_provide_buf {
+       struct file                     *file;
+       __u64                           addr;
+       __u32                           len;
+       __u32                           bgid;
+       __u16                           nbufs;
+       __u16                           bid;
+};
+
+static inline struct io_buffer_list *io_buffer_get_list(struct io_ring_ctx *ctx,
+                                                       unsigned int bgid)
+{
+       if (ctx->io_bl && bgid < BGID_ARRAY)
+               return &ctx->io_bl[bgid];
+
+       return xa_load(&ctx->io_bl_xa, bgid);
+}
+
+static int io_buffer_add_list(struct io_ring_ctx *ctx,
+                             struct io_buffer_list *bl, unsigned int bgid)
+{
+       bl->bgid = bgid;
+       if (bgid < BGID_ARRAY)
+               return 0;
+
+       return xa_err(xa_store(&ctx->io_bl_xa, bgid, bl, GFP_KERNEL));
+}
+
+void io_kbuf_recycle_legacy(struct io_kiocb *req, unsigned issue_flags)
+{
+       struct io_ring_ctx *ctx = req->ctx;
+       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;
+
+       io_ring_submit_lock(ctx, issue_flags);
+
+       buf = req->kbuf;
+       bl = io_buffer_get_list(ctx, buf->bgid);
+       list_add(&buf->list, &bl->buf_list);
+       req->flags &= ~REQ_F_BUFFER_SELECTED;
+       req->buf_index = buf->bgid;
+
+       io_ring_submit_unlock(ctx, issue_flags);
+       return;
+}
+
+unsigned int __io_put_kbuf(struct io_kiocb *req, unsigned issue_flags)
+{
+       unsigned int cflags;
+
+       /*
+        * We can add this buffer back to two lists:
+        *
+        * 1) The io_buffers_cache list. This one is protected by the
+        *    ctx->uring_lock. If we already hold this lock, add back to this
+        *    list as we can grab it from issue as well.
+        * 2) The io_buffers_comp list. This one is protected by the
+        *    ctx->completion_lock.
+        *
+        * 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) {
+               struct io_ring_ctx *ctx = req->ctx;
+
+               spin_lock(&ctx->completion_lock);
+               cflags = __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);
+       }
+       return cflags;
+}
+
+static void __user *io_provided_buffer_select(struct io_kiocb *req, size_t *len,
+                                             struct io_buffer_list *bl)
+{
+       if (!list_empty(&bl->buf_list)) {
+               struct io_buffer *kbuf;
+
+               kbuf = list_first_entry(&bl->buf_list, struct io_buffer, list);
+               list_del(&kbuf->list);
+               if (*len == 0 || *len > kbuf->len)
+                       *len = kbuf->len;
+               req->flags |= REQ_F_BUFFER_SELECTED;
+               req->kbuf = kbuf;
+               req->buf_index = kbuf->bid;
+               return u64_to_user_ptr(kbuf->addr);
+       }
+       return NULL;
+}
+
+static void __user *io_ring_buffer_select(struct io_kiocb *req, size_t *len,
+                                         struct io_buffer_list *bl,
+                                         unsigned int issue_flags)
+{
+       struct io_uring_buf_ring *br = bl->buf_ring;
+       struct io_uring_buf *buf;
+       __u16 head = bl->head;
+
+       if (unlikely(smp_load_acquire(&br->tail) == head))
+               return NULL;
+
+       head &= bl->mask;
+       if (head < IO_BUFFER_LIST_BUF_PER_PAGE) {
+               buf = &br->bufs[head];
+       } else {
+               int off = head & (IO_BUFFER_LIST_BUF_PER_PAGE - 1);
+               int index = head / IO_BUFFER_LIST_BUF_PER_PAGE;
+               buf = page_address(bl->buf_pages[index]);
+               buf += off;
+       }
+       if (*len == 0 || *len > buf->len)
+               *len = buf->len;
+       req->flags |= REQ_F_BUFFER_RING;
+       req->buf_list = bl;
+       req->buf_index = buf->bid;
+
+       if (issue_flags & IO_URING_F_UNLOCKED || !file_can_poll(req->file)) {
+               /*
+                * If we came in unlocked, we have no choice but to consume the
+                * buffer here, otherwise nothing ensures that the buffer won't
+                * get used by others. This does mean it'll be pinned until the
+                * IO completes, coming in unlocked means we're being called from
+                * io-wq context and there may be further retries in async hybrid
+                * mode. For the locked case, the caller must call commit when
+                * the transfer completes (or if we get -EAGAIN and must poll of
+                * retry).
+                */
+               req->buf_list = NULL;
+               bl->head++;
+       }
+       return u64_to_user_ptr(buf->addr);
+}
+
+void __user *io_buffer_select(struct io_kiocb *req, size_t *len,
+                             unsigned int issue_flags)
+{
+       struct io_ring_ctx *ctx = req->ctx;
+       struct io_buffer_list *bl;
+       void __user *ret = NULL;
+
+       io_ring_submit_lock(req->ctx, issue_flags);
+
+       bl = io_buffer_get_list(ctx, req->buf_index);
+       if (likely(bl)) {
+               if (bl->buf_nr_pages)
+                       ret = io_ring_buffer_select(req, len, bl, issue_flags);
+               else
+                       ret = io_provided_buffer_select(req, len, bl);
+       }
+       io_ring_submit_unlock(req->ctx, issue_flags);
+       return ret;
+}
+
+static __cold int io_init_bl_list(struct io_ring_ctx *ctx)
+{
+       int i;
+
+       ctx->io_bl = kcalloc(BGID_ARRAY, sizeof(struct io_buffer_list),
+                               GFP_KERNEL);
+       if (!ctx->io_bl)
+               return -ENOMEM;
+
+       for (i = 0; i < BGID_ARRAY; i++) {
+               INIT_LIST_HEAD(&ctx->io_bl[i].buf_list);
+               ctx->io_bl[i].bgid = i;
+       }
+
+       return 0;
+}
+
+static int __io_remove_buffers(struct io_ring_ctx *ctx,
+                              struct io_buffer_list *bl, unsigned nbufs)
+{
+       unsigned i = 0;
+
+       /* shouldn't happen */
+       if (!nbufs)
+               return 0;
+
+       if (bl->buf_nr_pages) {
+               int j;
+
+               i = bl->buf_ring->tail - bl->head;
+               for (j = 0; j < bl->buf_nr_pages; j++)
+                       unpin_user_page(bl->buf_pages[j]);
+               kvfree(bl->buf_pages);
+               bl->buf_pages = NULL;
+               bl->buf_nr_pages = 0;
+               /* make sure it's seen as empty */
+               INIT_LIST_HEAD(&bl->buf_list);
+               return i;
+       }
+
+       /* the head kbuf is the list itself */
+       while (!list_empty(&bl->buf_list)) {
+               struct io_buffer *nxt;
+
+               nxt = list_first_entry(&bl->buf_list, struct io_buffer, list);
+               list_del(&nxt->list);
+               if (++i == nbufs)
+                       return i;
+               cond_resched();
+       }
+       i++;
+
+       return i;
+}
+
+void io_destroy_buffers(struct io_ring_ctx *ctx)
+{
+       struct io_buffer_list *bl;
+       unsigned long index;
+       int i;
+
+       for (i = 0; i < BGID_ARRAY; i++) {
+               if (!ctx->io_bl)
+                       break;
+               __io_remove_buffers(ctx, &ctx->io_bl[i], -1U);
+       }
+
+       xa_for_each(&ctx->io_bl_xa, index, bl) {
+               xa_erase(&ctx->io_bl_xa, bl->bgid);
+               __io_remove_buffers(ctx, bl, -1U);
+               kfree(bl);
+       }
+
+       while (!list_empty(&ctx->io_buffers_pages)) {
+               struct page *page;
+
+               page = list_first_entry(&ctx->io_buffers_pages, struct page, lru);
+               list_del_init(&page->lru);
+               __free_page(page);
+       }
+}
+
+int io_remove_buffers_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_provide_buf *p = io_kiocb_to_cmd(req);
+       u64 tmp;
+
+       if (sqe->rw_flags || sqe->addr || sqe->len || sqe->off ||
+           sqe->splice_fd_in)
+               return -EINVAL;
+
+       tmp = READ_ONCE(sqe->fd);
+       if (!tmp || tmp > USHRT_MAX)
+               return -EINVAL;
+
+       memset(p, 0, sizeof(*p));
+       p->nbufs = tmp;
+       p->bgid = READ_ONCE(sqe->buf_group);
+       return 0;
+}
+
+int io_remove_buffers(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_provide_buf *p = io_kiocb_to_cmd(req);
+       struct io_ring_ctx *ctx = req->ctx;
+       struct io_buffer_list *bl;
+       int ret = 0;
+
+       io_ring_submit_lock(ctx, issue_flags);
+
+       ret = -ENOENT;
+       bl = io_buffer_get_list(ctx, p->bgid);
+       if (bl) {
+               ret = -EINVAL;
+               /* can't use provide/remove buffers command on mapped buffers */
+               if (!bl->buf_nr_pages)
+                       ret = __io_remove_buffers(ctx, bl, p->nbufs);
+       }
+       if (ret < 0)
+               req_set_fail(req);
+
+       /* complete before unlock, IOPOLL may need the lock */
+       io_req_set_res(req, ret, 0);
+       __io_req_complete(req, issue_flags);
+       io_ring_submit_unlock(ctx, issue_flags);
+       return IOU_ISSUE_SKIP_COMPLETE;
+}
+
+int io_provide_buffers_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       unsigned long size, tmp_check;
+       struct io_provide_buf *p = io_kiocb_to_cmd(req);
+       u64 tmp;
+
+       if (sqe->rw_flags || sqe->splice_fd_in)
+               return -EINVAL;
+
+       tmp = READ_ONCE(sqe->fd);
+       if (!tmp || tmp > USHRT_MAX)
+               return -E2BIG;
+       p->nbufs = tmp;
+       p->addr = READ_ONCE(sqe->addr);
+       p->len = READ_ONCE(sqe->len);
+
+       if (check_mul_overflow((unsigned long)p->len, (unsigned long)p->nbufs,
+                               &size))
+               return -EOVERFLOW;
+       if (check_add_overflow((unsigned long)p->addr, size, &tmp_check))
+               return -EOVERFLOW;
+
+       size = (unsigned long)p->len * p->nbufs;
+       if (!access_ok(u64_to_user_ptr(p->addr), size))
+               return -EFAULT;
+
+       p->bgid = READ_ONCE(sqe->buf_group);
+       tmp = READ_ONCE(sqe->off);
+       if (tmp > USHRT_MAX)
+               return -E2BIG;
+       p->bid = tmp;
+       return 0;
+}
+
+static int io_refill_buffer_cache(struct io_ring_ctx *ctx)
+{
+       struct io_buffer *buf;
+       struct page *page;
+       int bufs_in_page;
+
+       /*
+        * Completions that don't happen inline (eg not under uring_lock) will
+        * add to ->io_buffers_comp. If we don't have any free buffers, check
+        * the completion list and splice those entries first.
+        */
+       if (!list_empty_careful(&ctx->io_buffers_comp)) {
+               spin_lock(&ctx->completion_lock);
+               if (!list_empty(&ctx->io_buffers_comp)) {
+                       list_splice_init(&ctx->io_buffers_comp,
+                                               &ctx->io_buffers_cache);
+                       spin_unlock(&ctx->completion_lock);
+                       return 0;
+               }
+               spin_unlock(&ctx->completion_lock);
+       }
+
+       /*
+        * No free buffers and no completion entries either. Allocate a new
+        * page worth of buffer entries and add those to our freelist.
+        */
+       page = alloc_page(GFP_KERNEL_ACCOUNT);
+       if (!page)
+               return -ENOMEM;
+
+       list_add(&page->lru, &ctx->io_buffers_pages);
+
+       buf = page_address(page);
+       bufs_in_page = PAGE_SIZE / sizeof(*buf);
+       while (bufs_in_page) {
+               list_add_tail(&buf->list, &ctx->io_buffers_cache);
+               buf++;
+               bufs_in_page--;
+       }
+
+       return 0;
+}
+
+static int io_add_buffers(struct io_ring_ctx *ctx, struct io_provide_buf *pbuf,
+                         struct io_buffer_list *bl)
+{
+       struct io_buffer *buf;
+       u64 addr = pbuf->addr;
+       int i, bid = pbuf->bid;
+
+       for (i = 0; i < pbuf->nbufs; i++) {
+               if (list_empty(&ctx->io_buffers_cache) &&
+                   io_refill_buffer_cache(ctx))
+                       break;
+               buf = list_first_entry(&ctx->io_buffers_cache, struct io_buffer,
+                                       list);
+               list_move_tail(&buf->list, &bl->buf_list);
+               buf->addr = addr;
+               buf->len = min_t(__u32, pbuf->len, MAX_RW_COUNT);
+               buf->bid = bid;
+               buf->bgid = pbuf->bgid;
+               addr += pbuf->len;
+               bid++;
+               cond_resched();
+       }
+
+       return i ? 0 : -ENOMEM;
+}
+
+int io_provide_buffers(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_provide_buf *p = io_kiocb_to_cmd(req);
+       struct io_ring_ctx *ctx = req->ctx;
+       struct io_buffer_list *bl;
+       int ret = 0;
+
+       io_ring_submit_lock(ctx, issue_flags);
+
+       if (unlikely(p->bgid < BGID_ARRAY && !ctx->io_bl)) {
+               ret = io_init_bl_list(ctx);
+               if (ret)
+                       goto err;
+       }
+
+       bl = io_buffer_get_list(ctx, p->bgid);
+       if (unlikely(!bl)) {
+               bl = kzalloc(sizeof(*bl), GFP_KERNEL);
+               if (!bl) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+               INIT_LIST_HEAD(&bl->buf_list);
+               ret = io_buffer_add_list(ctx, bl, p->bgid);
+               if (ret) {
+                       kfree(bl);
+                       goto err;
+               }
+       }
+       /* can't add buffers via this command for a mapped buffer ring */
+       if (bl->buf_nr_pages) {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       ret = io_add_buffers(ctx, p, bl);
+err:
+       if (ret < 0)
+               req_set_fail(req);
+       /* complete before unlock, IOPOLL may need the lock */
+       io_req_set_res(req, ret, 0);
+       __io_req_complete(req, issue_flags);
+       io_ring_submit_unlock(ctx, issue_flags);
+       return IOU_ISSUE_SKIP_COMPLETE;
+}
+
+int io_register_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg)
+{
+       struct io_uring_buf_ring *br;
+       struct io_uring_buf_reg reg;
+       struct io_buffer_list *bl, *free_bl = NULL;
+       struct page **pages;
+       int nr_pages;
+
+       if (copy_from_user(&reg, arg, sizeof(reg)))
+               return -EFAULT;
+
+       if (reg.pad || reg.resv[0] || reg.resv[1] || reg.resv[2])
+               return -EINVAL;
+       if (!reg.ring_addr)
+               return -EFAULT;
+       if (reg.ring_addr & ~PAGE_MASK)
+               return -EINVAL;
+       if (!is_power_of_2(reg.ring_entries))
+               return -EINVAL;
+
+       /* cannot disambiguate full vs empty due to head/tail size */
+       if (reg.ring_entries >= 65536)
+               return -EINVAL;
+
+       if (unlikely(reg.bgid < BGID_ARRAY && !ctx->io_bl)) {
+               int ret = io_init_bl_list(ctx);
+               if (ret)
+                       return ret;
+       }
+
+       bl = io_buffer_get_list(ctx, reg.bgid);
+       if (bl) {
+               /* if mapped buffer ring OR classic exists, don't allow */
+               if (bl->buf_nr_pages || !list_empty(&bl->buf_list))
+                       return -EEXIST;
+       } else {
+               free_bl = bl = kzalloc(sizeof(*bl), GFP_KERNEL);
+               if (!bl)
+                       return -ENOMEM;
+       }
+
+       pages = io_pin_pages(reg.ring_addr,
+                            struct_size(br, bufs, reg.ring_entries),
+                            &nr_pages);
+       if (IS_ERR(pages)) {
+               kfree(free_bl);
+               return PTR_ERR(pages);
+       }
+
+       br = page_address(pages[0]);
+       bl->buf_pages = pages;
+       bl->buf_nr_pages = nr_pages;
+       bl->nr_entries = reg.ring_entries;
+       bl->buf_ring = br;
+       bl->mask = reg.ring_entries - 1;
+       io_buffer_add_list(ctx, bl, reg.bgid);
+       return 0;
+}
+
+int io_unregister_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg)
+{
+       struct io_uring_buf_reg reg;
+       struct io_buffer_list *bl;
+
+       if (copy_from_user(&reg, arg, sizeof(reg)))
+               return -EFAULT;
+       if (reg.pad || reg.resv[0] || reg.resv[1] || reg.resv[2])
+               return -EINVAL;
+
+       bl = io_buffer_get_list(ctx, reg.bgid);
+       if (!bl)
+               return -ENOENT;
+       if (!bl->buf_nr_pages)
+               return -EINVAL;
+
+       __io_remove_buffers(ctx, bl, -1U);
+       if (bl->bgid >= BGID_ARRAY) {
+               xa_erase(&ctx->io_bl_xa, bl->bgid);
+               kfree(bl);
+       }
+       return 0;
+}
diff --git a/io_uring/kbuf.h b/io_uring/kbuf.h
new file mode 100644 (file)
index 0000000..d6af208
--- /dev/null
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0
+#ifndef IOU_KBUF_H
+#define IOU_KBUF_H
+
+#include <uapi/linux/io_uring.h>
+
+struct io_buffer_list {
+       /*
+        * If ->buf_nr_pages is set, then buf_pages/buf_ring are used. If not,
+        * then these are classic provided buffers and ->buf_list is used.
+        */
+       union {
+               struct list_head buf_list;
+               struct {
+                       struct page **buf_pages;
+                       struct io_uring_buf_ring *buf_ring;
+               };
+       };
+       __u16 bgid;
+
+       /* below is for ring provided buffers */
+       __u16 buf_nr_pages;
+       __u16 nr_entries;
+       __u16 head;
+       __u16 mask;
+};
+
+struct io_buffer {
+       struct list_head list;
+       __u64 addr;
+       __u32 len;
+       __u16 bid;
+       __u16 bgid;
+};
+
+void __user *io_buffer_select(struct io_kiocb *req, size_t *len,
+                             unsigned int issue_flags);
+void io_destroy_buffers(struct io_ring_ctx *ctx);
+
+int io_remove_buffers_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_remove_buffers(struct io_kiocb *req, unsigned int issue_flags);
+
+int io_provide_buffers_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_provide_buffers(struct io_kiocb *req, unsigned int issue_flags);
+
+int io_register_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg);
+int io_unregister_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg);
+
+unsigned int __io_put_kbuf(struct io_kiocb *req, unsigned issue_flags);
+
+void io_kbuf_recycle_legacy(struct io_kiocb *req, unsigned issue_flags);
+
+static inline void io_kbuf_recycle_ring(struct io_kiocb *req)
+{
+       /*
+        * We don't need to recycle for REQ_F_BUFFER_RING, we can just clear
+        * the flag and hence ensure that bl->head doesn't get incremented.
+        * If the tail has already been incremented, hang on to it.
+        * The exception is partial io, that case we should increment bl->head
+        * 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;
+               }
+       }
+}
+
+static inline bool io_do_buffer_select(struct io_kiocb *req)
+{
+       if (!(req->flags & REQ_F_BUFFER_SELECT))
+               return false;
+       return !(req->flags & (REQ_F_BUFFER_SELECTED|REQ_F_BUFFER_RING));
+}
+
+static inline void io_kbuf_recycle(struct io_kiocb *req, unsigned issue_flags)
+{
+       /*
+        * READV uses fields in `struct io_rw` (len/addr) to stash the selected
+        * buffer data. However if that buffer is recycled the original request
+        * data stored in addr is lost. Therefore forbid recycling for now.
+        */
+       if (req->opcode == IORING_OP_READV)
+               return;
+
+       if (req->flags & REQ_F_BUFFER_SELECTED)
+               io_kbuf_recycle_legacy(req, issue_flags);
+       if (req->flags & REQ_F_BUFFER_RING)
+               io_kbuf_recycle_ring(req);
+}
+
+static inline unsigned int __io_put_kbuf_list(struct io_kiocb *req,
+                                             struct list_head *list)
+{
+       unsigned int ret = IORING_CQE_F_BUFFER | (req->buf_index << IORING_CQE_BUFFER_SHIFT);
+
+       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;
+       } 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)
+{
+       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);
+}
+
+static inline unsigned int io_put_kbuf(struct io_kiocb *req,
+                                      unsigned issue_flags)
+{
+
+       if (!(req->flags & (REQ_F_BUFFER_SELECTED|REQ_F_BUFFER_RING)))
+               return 0;
+       return __io_put_kbuf(req, issue_flags);
+}
+#endif
diff --git a/io_uring/msg_ring.c b/io_uring/msg_ring.c
new file mode 100644 (file)
index 0000000..753d167
--- /dev/null
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+#include <linux/nospec.h>
+#include <linux/io_uring.h>
+
+#include <uapi/linux/io_uring.h>
+
+#include "io_uring.h"
+#include "rsrc.h"
+#include "filetable.h"
+#include "msg_ring.h"
+
+struct io_msg {
+       struct file                     *file;
+       u64 user_data;
+       u32 len;
+       u32 cmd;
+       u32 src_fd;
+       u32 dst_fd;
+       u32 flags;
+};
+
+static int io_msg_ring_data(struct io_kiocb *req)
+{
+       struct io_ring_ctx *target_ctx = req->file->private_data;
+       struct io_msg *msg = io_kiocb_to_cmd(req);
+
+       if (msg->src_fd || msg->dst_fd || msg->flags)
+               return -EINVAL;
+
+       if (io_post_aux_cqe(target_ctx, msg->user_data, msg->len, 0, true))
+               return 0;
+
+       return -EOVERFLOW;
+}
+
+static void io_double_unlock_ctx(struct io_ring_ctx *ctx,
+                                struct io_ring_ctx *octx,
+                                unsigned int issue_flags)
+{
+       if (issue_flags & IO_URING_F_UNLOCKED)
+               mutex_unlock(&ctx->uring_lock);
+       mutex_unlock(&octx->uring_lock);
+}
+
+static int io_double_lock_ctx(struct io_ring_ctx *ctx,
+                             struct io_ring_ctx *octx,
+                             unsigned int issue_flags)
+{
+       /*
+        * To ensure proper ordering between the two ctxs, we can only
+        * attempt a trylock on the target. If that fails and we already have
+        * the source ctx lock, punt to io-wq.
+        */
+       if (!(issue_flags & IO_URING_F_UNLOCKED)) {
+               if (!mutex_trylock(&octx->uring_lock))
+                       return -EAGAIN;
+               return 0;
+       }
+
+       /* Always grab smallest value ctx first. We know ctx != octx. */
+       if (ctx < octx) {
+               mutex_lock(&ctx->uring_lock);
+               mutex_lock(&octx->uring_lock);
+       } else {
+               mutex_lock(&octx->uring_lock);
+               mutex_lock(&ctx->uring_lock);
+       }
+
+       return 0;
+}
+
+static int io_msg_send_fd(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_ring_ctx *target_ctx = req->file->private_data;
+       struct io_msg *msg = io_kiocb_to_cmd(req);
+       struct io_ring_ctx *ctx = req->ctx;
+       unsigned long file_ptr;
+       struct file *src_file;
+       int ret;
+
+       if (target_ctx == ctx)
+               return -EINVAL;
+
+       ret = io_double_lock_ctx(ctx, target_ctx, issue_flags);
+       if (unlikely(ret))
+               return ret;
+
+       ret = -EBADF;
+       if (unlikely(msg->src_fd >= ctx->nr_user_files))
+               goto out_unlock;
+
+       msg->src_fd = array_index_nospec(msg->src_fd, ctx->nr_user_files);
+       file_ptr = io_fixed_file_slot(&ctx->file_table, msg->src_fd)->file_ptr;
+       src_file = (struct file *) (file_ptr & FFS_MASK);
+       get_file(src_file);
+
+       ret = __io_fixed_fd_install(target_ctx, src_file, msg->dst_fd);
+       if (ret < 0) {
+               fput(src_file);
+               goto out_unlock;
+       }
+
+       if (msg->flags & IORING_MSG_RING_CQE_SKIP)
+               goto out_unlock;
+
+       /*
+        * If this fails, the target still received the file descriptor but
+        * wasn't notified of the fact. This means that if this request
+        * completes with -EOVERFLOW, then the sender must ensure that a
+        * later IORING_OP_MSG_RING delivers the message.
+        */
+       if (!io_post_aux_cqe(target_ctx, msg->user_data, msg->len, 0, true))
+               ret = -EOVERFLOW;
+out_unlock:
+       io_double_unlock_ctx(ctx, target_ctx, issue_flags);
+       return ret;
+}
+
+int io_msg_ring_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_msg *msg = io_kiocb_to_cmd(req);
+
+       if (unlikely(sqe->buf_index || sqe->personality))
+               return -EINVAL;
+
+       msg->user_data = READ_ONCE(sqe->off);
+       msg->len = READ_ONCE(sqe->len);
+       msg->cmd = READ_ONCE(sqe->addr);
+       msg->src_fd = READ_ONCE(sqe->addr3);
+       msg->dst_fd = READ_ONCE(sqe->file_index);
+       msg->flags = READ_ONCE(sqe->msg_ring_flags);
+       if (msg->flags & ~IORING_MSG_RING_CQE_SKIP)
+               return -EINVAL;
+
+       return 0;
+}
+
+int io_msg_ring(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_msg *msg = io_kiocb_to_cmd(req);
+       int ret;
+
+       ret = -EBADFD;
+       if (!io_is_uring_fops(req->file))
+               goto done;
+
+       switch (msg->cmd) {
+       case IORING_MSG_DATA:
+               ret = io_msg_ring_data(req);
+               break;
+       case IORING_MSG_SEND_FD:
+               ret = io_msg_send_fd(req, issue_flags);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+done:
+       if (ret < 0)
+               req_set_fail(req);
+       io_req_set_res(req, ret, 0);
+       /* put file to avoid an attempt to IOPOLL the req */
+       io_put_file(req->file);
+       req->file = NULL;
+       return IOU_OK;
+}
diff --git a/io_uring/msg_ring.h b/io_uring/msg_ring.h
new file mode 100644 (file)
index 0000000..fb9601f
--- /dev/null
@@ -0,0 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
+
+int io_msg_ring_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_msg_ring(struct io_kiocb *req, unsigned int issue_flags);
diff --git a/io_uring/net.c b/io_uring/net.c
new file mode 100644 (file)
index 0000000..32fc3da
--- /dev/null
@@ -0,0 +1,1236 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+#include <linux/net.h>
+#include <linux/compat.h>
+#include <net/compat.h>
+#include <linux/io_uring.h>
+
+#include <uapi/linux/io_uring.h>
+
+#include "io_uring.h"
+#include "kbuf.h"
+#include "alloc_cache.h"
+#include "net.h"
+#include "notif.h"
+#include "rsrc.h"
+
+#if defined(CONFIG_NET)
+struct io_shutdown {
+       struct file                     *file;
+       int                             how;
+};
+
+struct io_accept {
+       struct file                     *file;
+       struct sockaddr __user          *addr;
+       int __user                      *addr_len;
+       int                             flags;
+       u32                             file_slot;
+       unsigned long                   nofile;
+};
+
+struct io_socket {
+       struct file                     *file;
+       int                             domain;
+       int                             type;
+       int                             protocol;
+       int                             flags;
+       u32                             file_slot;
+       unsigned long                   nofile;
+};
+
+struct io_connect {
+       struct file                     *file;
+       struct sockaddr __user          *addr;
+       int                             addr_len;
+};
+
+struct io_sr_msg {
+       struct file                     *file;
+       union {
+               struct compat_msghdr __user     *umsg_compat;
+               struct user_msghdr __user       *umsg;
+               void __user                     *buf;
+       };
+       unsigned                        msg_flags;
+       unsigned                        flags;
+       size_t                          len;
+       size_t                          done_io;
+};
+
+struct io_sendzc {
+       struct file                     *file;
+       void __user                     *buf;
+       size_t                          len;
+       u16                             slot_idx;
+       unsigned                        msg_flags;
+       unsigned                        flags;
+       unsigned                        addr_len;
+       void __user                     *addr;
+};
+
+#define IO_APOLL_MULTI_POLLED (REQ_F_APOLL_MULTISHOT | REQ_F_POLLED)
+
+int io_shutdown_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_shutdown *shutdown = io_kiocb_to_cmd(req);
+
+       if (unlikely(sqe->off || sqe->addr || sqe->rw_flags ||
+                    sqe->buf_index || sqe->splice_fd_in))
+               return -EINVAL;
+
+       shutdown->how = READ_ONCE(sqe->len);
+       return 0;
+}
+
+int io_shutdown(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_shutdown *shutdown = io_kiocb_to_cmd(req);
+       struct socket *sock;
+       int ret;
+
+       if (issue_flags & IO_URING_F_NONBLOCK)
+               return -EAGAIN;
+
+       sock = sock_from_file(req->file);
+       if (unlikely(!sock))
+               return -ENOTSOCK;
+
+       ret = __sys_shutdown_sock(sock, shutdown->how);
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
+
+static bool io_net_retry(struct socket *sock, int flags)
+{
+       if (!(flags & MSG_WAITALL))
+               return false;
+       return sock->type == SOCK_STREAM || sock->type == SOCK_SEQPACKET;
+}
+
+static void io_netmsg_recycle(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_async_msghdr *hdr = req->async_data;
+
+       if (!hdr || issue_flags & IO_URING_F_UNLOCKED)
+               return;
+
+       /* Let normal cleanup path reap it if we fail adding to the cache */
+       if (io_alloc_cache_put(&req->ctx->netmsg_cache, &hdr->cache)) {
+               req->async_data = NULL;
+               req->flags &= ~REQ_F_ASYNC_DATA;
+       }
+}
+
+static struct io_async_msghdr *io_recvmsg_alloc_async(struct io_kiocb *req,
+                                                     unsigned int issue_flags)
+{
+       struct io_ring_ctx *ctx = req->ctx;
+       struct io_cache_entry *entry;
+
+       if (!(issue_flags & IO_URING_F_UNLOCKED) &&
+           (entry = io_alloc_cache_get(&ctx->netmsg_cache)) != NULL) {
+               struct io_async_msghdr *hdr;
+
+               hdr = container_of(entry, struct io_async_msghdr, cache);
+               req->flags |= REQ_F_ASYNC_DATA;
+               req->async_data = hdr;
+               return hdr;
+       }
+
+       if (!io_alloc_async_data(req))
+               return req->async_data;
+
+       return NULL;
+}
+
+static int io_setup_async_msg(struct io_kiocb *req,
+                             struct io_async_msghdr *kmsg,
+                             unsigned int issue_flags)
+{
+       struct io_async_msghdr *async_msg = req->async_data;
+
+       if (async_msg)
+               return -EAGAIN;
+       async_msg = io_recvmsg_alloc_async(req, issue_flags);
+       if (!async_msg) {
+               kfree(kmsg->free_iov);
+               return -ENOMEM;
+       }
+       req->flags |= REQ_F_NEED_CLEANUP;
+       memcpy(async_msg, kmsg, sizeof(*kmsg));
+       async_msg->msg.msg_name = &async_msg->addr;
+       /* if were using fast_iov, set it to the new one */
+       if (!async_msg->free_iov)
+               async_msg->msg.msg_iter.iov = async_msg->fast_iov;
+
+       return -EAGAIN;
+}
+
+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);
+
+       iomsg->msg.msg_name = &iomsg->addr;
+       iomsg->free_iov = iomsg->fast_iov;
+       return sendmsg_copy_msghdr(&iomsg->msg, sr->umsg, sr->msg_flags,
+                                       &iomsg->free_iov);
+}
+
+int io_sendmsg_prep_async(struct io_kiocb *req)
+{
+       int ret;
+
+       ret = io_sendmsg_copy_hdr(req, req->async_data);
+       if (!ret)
+               req->flags |= REQ_F_NEED_CLEANUP;
+       return ret;
+}
+
+void io_sendmsg_recvmsg_cleanup(struct io_kiocb *req)
+{
+       struct io_async_msghdr *io = req->async_data;
+
+       kfree(io->free_iov);
+}
+
+int io_sendmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_sr_msg *sr = io_kiocb_to_cmd(req);
+
+       if (unlikely(sqe->file_index || sqe->addr2))
+               return -EINVAL;
+
+       sr->umsg = u64_to_user_ptr(READ_ONCE(sqe->addr));
+       sr->len = READ_ONCE(sqe->len);
+       sr->flags = READ_ONCE(sqe->ioprio);
+       if (sr->flags & ~IORING_RECVSEND_POLL_FIRST)
+               return -EINVAL;
+       sr->msg_flags = READ_ONCE(sqe->msg_flags) | MSG_NOSIGNAL;
+       if (sr->msg_flags & MSG_DONTWAIT)
+               req->flags |= REQ_F_NOWAIT;
+
+#ifdef CONFIG_COMPAT
+       if (req->ctx->compat)
+               sr->msg_flags |= MSG_CMSG_COMPAT;
+#endif
+       sr->done_io = 0;
+       return 0;
+}
+
+int io_sendmsg(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_sr_msg *sr = io_kiocb_to_cmd(req);
+       struct io_async_msghdr iomsg, *kmsg;
+       struct socket *sock;
+       unsigned flags;
+       int min_ret = 0;
+       int ret;
+
+       sock = sock_from_file(req->file);
+       if (unlikely(!sock))
+               return -ENOTSOCK;
+
+       if (req_has_async_data(req)) {
+               kmsg = req->async_data;
+       } else {
+               ret = io_sendmsg_copy_hdr(req, &iomsg);
+               if (ret)
+                       return ret;
+               kmsg = &iomsg;
+       }
+
+       if (!(req->flags & REQ_F_POLLED) &&
+           (sr->flags & IORING_RECVSEND_POLL_FIRST))
+               return io_setup_async_msg(req, kmsg, issue_flags);
+
+       flags = sr->msg_flags;
+       if (issue_flags & IO_URING_F_NONBLOCK)
+               flags |= MSG_DONTWAIT;
+       if (flags & MSG_WAITALL)
+               min_ret = iov_iter_count(&kmsg->msg.msg_iter);
+
+       ret = __sys_sendmsg_sock(sock, &kmsg->msg, flags);
+
+       if (ret < min_ret) {
+               if (ret == -EAGAIN && (issue_flags & IO_URING_F_NONBLOCK))
+                       return io_setup_async_msg(req, kmsg, issue_flags);
+               if (ret == -ERESTARTSYS)
+                       ret = -EINTR;
+               if (ret > 0 && io_net_retry(sock, flags)) {
+                       sr->done_io += ret;
+                       req->flags |= REQ_F_PARTIAL_IO;
+                       return io_setup_async_msg(req, kmsg, issue_flags);
+               }
+               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);
+       if (ret >= 0)
+               ret += sr->done_io;
+       else if (sr->done_io)
+               ret = sr->done_io;
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
+
+int io_send(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_sr_msg *sr = io_kiocb_to_cmd(req);
+       struct msghdr msg;
+       struct iovec iov;
+       struct socket *sock;
+       unsigned flags;
+       int min_ret = 0;
+       int ret;
+
+       if (!(req->flags & REQ_F_POLLED) &&
+           (sr->flags & IORING_RECVSEND_POLL_FIRST))
+               return -EAGAIN;
+
+       sock = sock_from_file(req->file);
+       if (unlikely(!sock))
+               return -ENOTSOCK;
+
+       ret = import_single_range(WRITE, sr->buf, sr->len, &iov, &msg.msg_iter);
+       if (unlikely(ret))
+               return ret;
+
+       msg.msg_name = NULL;
+       msg.msg_control = NULL;
+       msg.msg_controllen = 0;
+       msg.msg_namelen = 0;
+       msg.msg_ubuf = NULL;
+
+       flags = sr->msg_flags;
+       if (issue_flags & IO_URING_F_NONBLOCK)
+               flags |= MSG_DONTWAIT;
+       if (flags & MSG_WAITALL)
+               min_ret = iov_iter_count(&msg.msg_iter);
+
+       msg.msg_flags = flags;
+       ret = sock_sendmsg(sock, &msg);
+       if (ret < min_ret) {
+               if (ret == -EAGAIN && (issue_flags & IO_URING_F_NONBLOCK))
+                       return -EAGAIN;
+               if (ret == -ERESTARTSYS)
+                       ret = -EINTR;
+               if (ret > 0 && io_net_retry(sock, flags)) {
+                       sr->len -= ret;
+                       sr->buf += ret;
+                       sr->done_io += ret;
+                       req->flags |= REQ_F_PARTIAL_IO;
+                       return -EAGAIN;
+               }
+               req_set_fail(req);
+       }
+       if (ret >= 0)
+               ret += sr->done_io;
+       else if (sr->done_io)
+               ret = sr->done_io;
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
+
+static bool io_recvmsg_multishot_overflow(struct io_async_msghdr *iomsg)
+{
+       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;
+
+       return false;
+}
+
+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 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(READ, msg.msg_iov, msg.msg_iovlen, UIO_FASTIOV,
+                                    &iomsg->free_iov, &iomsg->msg.msg_iter,
+                                    false);
+               if (ret > 0)
+                       ret = 0;
+       }
+
+       return ret;
+}
+
+#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 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;
+
+       uiov = compat_ptr(msg.msg_iov);
+       if (req->flags & REQ_F_BUFFER_SELECT) {
+               compat_ssize_t clen;
+
+               if (msg.msg_iovlen == 0) {
+                       sr->len = 0;
+                       iomsg->free_iov = NULL;
+               } 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;
+                       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(READ, (struct iovec __user *)uiov, msg.msg_iovlen,
+                                  UIO_FASTIOV, &iomsg->free_iov,
+                                  &iomsg->msg.msg_iter, true);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+#endif
+
+static int io_recvmsg_copy_hdr(struct io_kiocb *req,
+                              struct io_async_msghdr *iomsg)
+{
+       iomsg->msg.msg_name = &iomsg->addr;
+
+#ifdef CONFIG_COMPAT
+       if (req->ctx->compat)
+               return __io_compat_recvmsg_copy_hdr(req, iomsg);
+#endif
+
+       return __io_recvmsg_copy_hdr(req, iomsg);
+}
+
+int io_recvmsg_prep_async(struct io_kiocb *req)
+{
+       int ret;
+
+       ret = io_recvmsg_copy_hdr(req, req->async_data);
+       if (!ret)
+               req->flags |= REQ_F_NEED_CLEANUP;
+       return ret;
+}
+
+#define RECVMSG_FLAGS (IORING_RECVSEND_POLL_FIRST | IORING_RECV_MULTISHOT)
+
+int io_recvmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_sr_msg *sr = io_kiocb_to_cmd(req);
+
+       if (unlikely(sqe->file_index || sqe->addr2))
+               return -EINVAL;
+
+       sr->umsg = u64_to_user_ptr(READ_ONCE(sqe->addr));
+       sr->len = READ_ONCE(sqe->len);
+       sr->flags = READ_ONCE(sqe->ioprio);
+       if (sr->flags & ~(RECVMSG_FLAGS))
+               return -EINVAL;
+       sr->msg_flags = READ_ONCE(sqe->msg_flags) | MSG_NOSIGNAL;
+       if (sr->msg_flags & MSG_DONTWAIT)
+               req->flags |= REQ_F_NOWAIT;
+       if (sr->msg_flags & MSG_ERRQUEUE)
+               req->flags |= REQ_F_CLEAR_POLLIN;
+       if (sr->flags & IORING_RECV_MULTISHOT) {
+               if (!(req->flags & REQ_F_BUFFER_SELECT))
+                       return -EINVAL;
+               if (sr->msg_flags & MSG_WAITALL)
+                       return -EINVAL;
+               if (req->opcode == IORING_OP_RECV && sr->len)
+                       return -EINVAL;
+               req->flags |= REQ_F_APOLL_MULTISHOT;
+       }
+
+#ifdef CONFIG_COMPAT
+       if (req->ctx->compat)
+               sr->msg_flags |= MSG_CMSG_COMPAT;
+#endif
+       sr->done_io = 0;
+       return 0;
+}
+
+static inline void io_recv_prep_retry(struct io_kiocb *req)
+{
+       struct io_sr_msg *sr = io_kiocb_to_cmd(req);
+
+       sr->done_io = 0;
+       sr->len = 0; /* get from the provided buffer */
+}
+
+/*
+ * Finishes io_recv and io_recvmsg.
+ *
+ * Returns true if it is actually finished, or false if it should run
+ * again (for multishot).
+ */
+static inline bool io_recv_finish(struct io_kiocb *req, int *ret,
+                                 unsigned int cflags, bool mshot_finished)
+{
+       if (!(req->flags & REQ_F_APOLL_MULTISHOT)) {
+               io_req_set_res(req, *ret, cflags);
+               *ret = IOU_OK;
+               return true;
+       }
+
+       if (!mshot_finished) {
+               if (io_post_aux_cqe(req->ctx, req->cqe.user_data, *ret,
+                                   cflags | IORING_CQE_F_MORE, false)) {
+                       io_recv_prep_retry(req);
+                       return false;
+               }
+               /*
+                * Otherwise stop multishot but use the current result.
+                * Probably will end up going into overflow, but this means
+                * we cannot trust the ordering anymore
+                */
+       }
+
+       io_req_set_res(req, *ret, cflags);
+
+       if (req->flags & REQ_F_POLLED)
+               *ret = IOU_STOP_MULTISHOT;
+       else
+               *ret = IOU_OK;
+       return true;
+}
+
+static int io_recvmsg_prep_multishot(struct io_async_msghdr *kmsg,
+                                    struct io_sr_msg *sr, void __user **buf,
+                                    size_t *len)
+{
+       unsigned long ubuf = (unsigned long) *buf;
+       unsigned long hdr;
+
+       hdr = sizeof(struct io_uring_recvmsg_out) + kmsg->namelen +
+               kmsg->controllen;
+       if (*len < hdr)
+               return -EFAULT;
+
+       if (kmsg->controllen) {
+               unsigned long control = ubuf + hdr - kmsg->controllen;
+
+               kmsg->msg.msg_control_user = (void *) control;
+               kmsg->msg.msg_controllen = kmsg->controllen;
+       }
+
+       sr->buf = *buf; /* stash for later copy */
+       *buf = (void *) (ubuf + hdr);
+       kmsg->payloadlen = *len = *len - hdr;
+       return 0;
+}
+
+struct io_recvmsg_multishot_hdr {
+       struct io_uring_recvmsg_out msg;
+       struct sockaddr_storage addr;
+};
+
+static int io_recvmsg_multishot(struct socket *sock, struct io_sr_msg *io,
+                               struct io_async_msghdr *kmsg,
+                               unsigned int flags, bool *finished)
+{
+       int err;
+       int copy_len;
+       struct io_recvmsg_multishot_hdr hdr;
+
+       if (kmsg->namelen)
+               kmsg->msg.msg_name = &hdr.addr;
+       kmsg->msg.msg_flags = flags & (MSG_CMSG_CLOEXEC|MSG_CMSG_COMPAT);
+       kmsg->msg.msg_namelen = 0;
+
+       if (sock->file->f_flags & O_NONBLOCK)
+               flags |= MSG_DONTWAIT;
+
+       err = sock_recvmsg(sock, &kmsg->msg, flags);
+       *finished = err <= 0;
+       if (err < 0)
+               return err;
+
+       hdr.msg = (struct io_uring_recvmsg_out) {
+               .controllen = kmsg->controllen - kmsg->msg.msg_controllen,
+               .flags = kmsg->msg.msg_flags & ~MSG_CMSG_COMPAT
+       };
+
+       hdr.msg.payloadlen = err;
+       if (err > kmsg->payloadlen)
+               err = kmsg->payloadlen;
+
+       copy_len = sizeof(struct io_uring_recvmsg_out);
+       if (kmsg->msg.msg_namelen > kmsg->namelen)
+               copy_len += kmsg->namelen;
+       else
+               copy_len += kmsg->msg.msg_namelen;
+
+       /*
+        *      "fromlen shall refer to the value before truncation.."
+        *                      1003.1g
+        */
+       hdr.msg.namelen = kmsg->msg.msg_namelen;
+
+       /* ensure that there is no gap between hdr and sockaddr_storage */
+       BUILD_BUG_ON(offsetof(struct io_recvmsg_multishot_hdr, addr) !=
+                    sizeof(struct io_uring_recvmsg_out));
+       if (copy_to_user(io->buf, &hdr, copy_len)) {
+               *finished = true;
+               return -EFAULT;
+       }
+
+       return sizeof(struct io_uring_recvmsg_out) + kmsg->namelen +
+                       kmsg->controllen + err;
+}
+
+int io_recvmsg(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_sr_msg *sr = io_kiocb_to_cmd(req);
+       struct io_async_msghdr iomsg, *kmsg;
+       struct socket *sock;
+       unsigned int cflags;
+       unsigned flags;
+       int ret, min_ret = 0;
+       bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK;
+       bool mshot_finished = true;
+
+       sock = sock_from_file(req->file);
+       if (unlikely(!sock))
+               return -ENOTSOCK;
+
+       if (req_has_async_data(req)) {
+               kmsg = req->async_data;
+       } else {
+               ret = io_recvmsg_copy_hdr(req, &iomsg);
+               if (ret)
+                       return ret;
+               kmsg = &iomsg;
+       }
+
+       if (!(req->flags & REQ_F_POLLED) &&
+           (sr->flags & IORING_RECVSEND_POLL_FIRST))
+               return io_setup_async_msg(req, kmsg, issue_flags);
+
+retry_multishot:
+       if (io_do_buffer_select(req)) {
+               void __user *buf;
+               size_t len = sr->len;
+
+               buf = io_buffer_select(req, &len, issue_flags);
+               if (!buf)
+                       return -ENOBUFS;
+
+               if (req->flags & REQ_F_APOLL_MULTISHOT) {
+                       ret = io_recvmsg_prep_multishot(kmsg, sr, &buf, &len);
+                       if (ret) {
+                               io_kbuf_recycle(req, issue_flags);
+                               return ret;
+                       }
+               }
+
+               kmsg->fast_iov[0].iov_base = buf;
+               kmsg->fast_iov[0].iov_len = len;
+               iov_iter_init(&kmsg->msg.msg_iter, READ, kmsg->fast_iov, 1,
+                               len);
+       }
+
+       flags = sr->msg_flags;
+       if (force_nonblock)
+               flags |= MSG_DONTWAIT;
+       if (flags & MSG_WAITALL)
+               min_ret = iov_iter_count(&kmsg->msg.msg_iter);
+
+       kmsg->msg.msg_get_inq = 1;
+       if (req->flags & REQ_F_APOLL_MULTISHOT)
+               ret = io_recvmsg_multishot(sock, sr, kmsg, flags,
+                                          &mshot_finished);
+       else
+               ret = __sys_recvmsg_sock(sock, &kmsg->msg, sr->umsg,
+                                        kmsg->uaddr, flags);
+
+       if (ret < min_ret) {
+               if (ret == -EAGAIN && force_nonblock) {
+                       ret = io_setup_async_msg(req, kmsg, issue_flags);
+                       if (ret == -EAGAIN && (req->flags & IO_APOLL_MULTI_POLLED) ==
+                                              IO_APOLL_MULTI_POLLED) {
+                               io_kbuf_recycle(req, issue_flags);
+                               return IOU_ISSUE_SKIP_COMPLETE;
+                       }
+                       return ret;
+               }
+               if (ret == -ERESTARTSYS)
+                       ret = -EINTR;
+               if (ret > 0 && io_net_retry(sock, flags)) {
+                       sr->done_io += ret;
+                       req->flags |= REQ_F_PARTIAL_IO;
+                       return io_setup_async_msg(req, kmsg, issue_flags);
+               }
+               req_set_fail(req);
+       } else if ((flags & MSG_WAITALL) && (kmsg->msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC))) {
+               req_set_fail(req);
+       }
+
+       if (ret > 0)
+               ret += sr->done_io;
+       else if (sr->done_io)
+               ret = sr->done_io;
+       else
+               io_kbuf_recycle(req, issue_flags);
+
+       cflags = io_put_kbuf(req, issue_flags);
+       if (kmsg->msg.msg_inq)
+               cflags |= IORING_CQE_F_SOCK_NONEMPTY;
+
+       if (!io_recv_finish(req, &ret, cflags, mshot_finished))
+               goto retry_multishot;
+
+       if (mshot_finished) {
+               io_netmsg_recycle(req, issue_flags);
+               /* fast path, check for non-NULL to avoid function call */
+               if (kmsg->free_iov)
+                       kfree(kmsg->free_iov);
+               req->flags &= ~REQ_F_NEED_CLEANUP;
+       }
+
+       return ret;
+}
+
+int io_recv(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_sr_msg *sr = io_kiocb_to_cmd(req);
+       struct msghdr msg;
+       struct socket *sock;
+       struct iovec iov;
+       unsigned int cflags;
+       unsigned flags;
+       int ret, min_ret = 0;
+       bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK;
+       size_t len = sr->len;
+
+       if (!(req->flags & REQ_F_POLLED) &&
+           (sr->flags & IORING_RECVSEND_POLL_FIRST))
+               return -EAGAIN;
+
+       sock = sock_from_file(req->file);
+       if (unlikely(!sock))
+               return -ENOTSOCK;
+
+retry_multishot:
+       if (io_do_buffer_select(req)) {
+               void __user *buf;
+
+               buf = io_buffer_select(req, &len, issue_flags);
+               if (!buf)
+                       return -ENOBUFS;
+               sr->buf = buf;
+       }
+
+       ret = import_single_range(READ, sr->buf, len, &iov, &msg.msg_iter);
+       if (unlikely(ret))
+               goto out_free;
+
+       msg.msg_name = NULL;
+       msg.msg_namelen = 0;
+       msg.msg_control = NULL;
+       msg.msg_get_inq = 1;
+       msg.msg_flags = 0;
+       msg.msg_controllen = 0;
+       msg.msg_iocb = NULL;
+       msg.msg_ubuf = NULL;
+
+       flags = sr->msg_flags;
+       if (force_nonblock)
+               flags |= MSG_DONTWAIT;
+       if (flags & MSG_WAITALL)
+               min_ret = iov_iter_count(&msg.msg_iter);
+
+       ret = sock_recvmsg(sock, &msg, flags);
+       if (ret < min_ret) {
+               if (ret == -EAGAIN && force_nonblock) {
+                       if ((req->flags & IO_APOLL_MULTI_POLLED) == IO_APOLL_MULTI_POLLED) {
+                               io_kbuf_recycle(req, issue_flags);
+                               return IOU_ISSUE_SKIP_COMPLETE;
+                       }
+
+                       return -EAGAIN;
+               }
+               if (ret == -ERESTARTSYS)
+                       ret = -EINTR;
+               if (ret > 0 && io_net_retry(sock, flags)) {
+                       sr->len -= ret;
+                       sr->buf += ret;
+                       sr->done_io += ret;
+                       req->flags |= REQ_F_PARTIAL_IO;
+                       return -EAGAIN;
+               }
+               req_set_fail(req);
+       } else if ((flags & MSG_WAITALL) && (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC))) {
+out_free:
+               req_set_fail(req);
+       }
+
+       if (ret > 0)
+               ret += sr->done_io;
+       else if (sr->done_io)
+               ret = sr->done_io;
+       else
+               io_kbuf_recycle(req, issue_flags);
+
+       cflags = io_put_kbuf(req, issue_flags);
+       if (msg.msg_inq)
+               cflags |= IORING_CQE_F_SOCK_NONEMPTY;
+
+       if (!io_recv_finish(req, &ret, cflags, ret <= 0))
+               goto retry_multishot;
+
+       return ret;
+}
+
+int io_sendzc_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_sendzc *zc = io_kiocb_to_cmd(req);
+       struct io_ring_ctx *ctx = req->ctx;
+
+       if (READ_ONCE(sqe->__pad2[0]) || READ_ONCE(sqe->addr3))
+               return -EINVAL;
+
+       zc->flags = READ_ONCE(sqe->ioprio);
+       if (zc->flags & ~(IORING_RECVSEND_POLL_FIRST |
+                         IORING_RECVSEND_FIXED_BUF | IORING_RECVSEND_NOTIF_FLUSH))
+               return -EINVAL;
+       if (zc->flags & IORING_RECVSEND_FIXED_BUF) {
+               unsigned idx = READ_ONCE(sqe->buf_index);
+
+               if (unlikely(idx >= ctx->nr_user_bufs))
+                       return -EFAULT;
+               idx = array_index_nospec(idx, ctx->nr_user_bufs);
+               req->imu = READ_ONCE(ctx->user_bufs[idx]);
+               io_req_set_rsrc_node(req, ctx, 0);
+       }
+
+       zc->buf = u64_to_user_ptr(READ_ONCE(sqe->addr));
+       zc->len = READ_ONCE(sqe->len);
+       zc->msg_flags = READ_ONCE(sqe->msg_flags) | MSG_NOSIGNAL;
+       zc->slot_idx = READ_ONCE(sqe->notification_idx);
+       if (zc->msg_flags & MSG_DONTWAIT)
+               req->flags |= REQ_F_NOWAIT;
+
+       zc->addr = u64_to_user_ptr(READ_ONCE(sqe->addr2));
+       zc->addr_len = READ_ONCE(sqe->addr_len);
+
+#ifdef CONFIG_COMPAT
+       if (req->ctx->compat)
+               zc->msg_flags |= MSG_CMSG_COMPAT;
+#endif
+       return 0;
+}
+
+static int io_sg_from_iter(struct sock *sk, struct sk_buff *skb,
+                          struct iov_iter *from, size_t length)
+{
+       struct skb_shared_info *shinfo = skb_shinfo(skb);
+       int frag = shinfo->nr_frags;
+       int ret = 0;
+       struct bvec_iter bi;
+       ssize_t copied = 0;
+       unsigned long truesize = 0;
+
+       if (!shinfo->nr_frags)
+               shinfo->flags |= SKBFL_MANAGED_FRAG_REFS;
+
+       if (!skb_zcopy_managed(skb) || !iov_iter_is_bvec(from)) {
+               skb_zcopy_downgrade_managed(skb);
+               return __zerocopy_sg_from_iter(NULL, sk, skb, from, length);
+       }
+
+       bi.bi_size = min(from->count, length);
+       bi.bi_bvec_done = from->iov_offset;
+       bi.bi_idx = 0;
+
+       while (bi.bi_size && frag < MAX_SKB_FRAGS) {
+               struct bio_vec v = mp_bvec_iter_bvec(from->bvec, bi);
+
+               copied += v.bv_len;
+               truesize += PAGE_ALIGN(v.bv_len + v.bv_offset);
+               __skb_fill_page_desc_noacc(shinfo, frag++, v.bv_page,
+                                          v.bv_offset, v.bv_len);
+               bvec_iter_advance_single(from->bvec, &bi, v.bv_len);
+       }
+       if (bi.bi_size)
+               ret = -EMSGSIZE;
+
+       shinfo->nr_frags = frag;
+       from->bvec += bi.bi_idx;
+       from->nr_segs -= bi.bi_idx;
+       from->count = bi.bi_size;
+       from->iov_offset = bi.bi_bvec_done;
+
+       skb->data_len += copied;
+       skb->len += copied;
+       skb->truesize += truesize;
+
+       if (sk && sk->sk_type == SOCK_STREAM) {
+               sk_wmem_queued_add(sk, truesize);
+               if (!skb_zcopy_pure(skb))
+                       sk_mem_charge(sk, truesize);
+       } else {
+               refcount_add(truesize, &skb->sk->sk_wmem_alloc);
+       }
+       return ret;
+}
+
+int io_sendzc(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct sockaddr_storage address;
+       struct io_ring_ctx *ctx = req->ctx;
+       struct io_sendzc *zc = io_kiocb_to_cmd(req);
+       struct io_notif_slot *notif_slot;
+       struct io_kiocb *notif;
+       struct msghdr msg;
+       struct iovec iov;
+       struct socket *sock;
+       unsigned msg_flags;
+       int ret, min_ret = 0;
+
+       if (!(req->flags & REQ_F_POLLED) &&
+           (zc->flags & IORING_RECVSEND_POLL_FIRST))
+               return -EAGAIN;
+
+       if (issue_flags & IO_URING_F_UNLOCKED)
+               return -EAGAIN;
+       sock = sock_from_file(req->file);
+       if (unlikely(!sock))
+               return -ENOTSOCK;
+
+       notif_slot = io_get_notif_slot(ctx, zc->slot_idx);
+       if (!notif_slot)
+               return -EINVAL;
+       notif = io_get_notif(ctx, notif_slot);
+       if (!notif)
+               return -ENOMEM;
+
+       msg.msg_name = NULL;
+       msg.msg_control = NULL;
+       msg.msg_controllen = 0;
+       msg.msg_namelen = 0;
+
+       if (zc->flags & IORING_RECVSEND_FIXED_BUF) {
+               ret = io_import_fixed(WRITE, &msg.msg_iter, req->imu,
+                                       (u64)(uintptr_t)zc->buf, zc->len);
+               if (unlikely(ret))
+                               return ret;
+       } else {
+               ret = import_single_range(WRITE, zc->buf, zc->len, &iov,
+                                         &msg.msg_iter);
+               if (unlikely(ret))
+                       return ret;
+               ret = io_notif_account_mem(notif, zc->len);
+               if (unlikely(ret))
+                       return ret;
+       }
+
+       if (zc->addr) {
+               ret = move_addr_to_kernel(zc->addr, zc->addr_len, &address);
+               if (unlikely(ret < 0))
+                       return ret;
+               msg.msg_name = (struct sockaddr *)&address;
+               msg.msg_namelen = zc->addr_len;
+       }
+
+       msg_flags = zc->msg_flags | MSG_ZEROCOPY;
+       if (issue_flags & IO_URING_F_NONBLOCK)
+               msg_flags |= MSG_DONTWAIT;
+       if (msg_flags & MSG_WAITALL)
+               min_ret = iov_iter_count(&msg.msg_iter);
+
+       msg.msg_flags = msg_flags;
+       msg.msg_ubuf = &io_notif_to_data(notif)->uarg;
+       msg.sg_from_iter = io_sg_from_iter;
+       ret = sock_sendmsg(sock, &msg);
+
+       if (unlikely(ret < min_ret)) {
+               if (ret == -EAGAIN && (issue_flags & IO_URING_F_NONBLOCK))
+                       return -EAGAIN;
+               return ret == -ERESTARTSYS ? -EINTR : ret;
+       }
+
+       if (zc->flags & IORING_RECVSEND_NOTIF_FLUSH)
+               io_notif_slot_flush_submit(notif_slot, 0);
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
+
+int io_accept_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_accept *accept = io_kiocb_to_cmd(req);
+       unsigned flags;
+
+       if (sqe->len || sqe->buf_index)
+               return -EINVAL;
+
+       accept->addr = u64_to_user_ptr(READ_ONCE(sqe->addr));
+       accept->addr_len = u64_to_user_ptr(READ_ONCE(sqe->addr2));
+       accept->flags = READ_ONCE(sqe->accept_flags);
+       accept->nofile = rlimit(RLIMIT_NOFILE);
+       flags = READ_ONCE(sqe->ioprio);
+       if (flags & ~IORING_ACCEPT_MULTISHOT)
+               return -EINVAL;
+
+       accept->file_slot = READ_ONCE(sqe->file_index);
+       if (accept->file_slot) {
+               if (accept->flags & SOCK_CLOEXEC)
+                       return -EINVAL;
+               if (flags & IORING_ACCEPT_MULTISHOT &&
+                   accept->file_slot != IORING_FILE_INDEX_ALLOC)
+                       return -EINVAL;
+       }
+       if (accept->flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
+               return -EINVAL;
+       if (SOCK_NONBLOCK != O_NONBLOCK && (accept->flags & SOCK_NONBLOCK))
+               accept->flags = (accept->flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
+       if (flags & IORING_ACCEPT_MULTISHOT)
+               req->flags |= REQ_F_APOLL_MULTISHOT;
+       return 0;
+}
+
+int io_accept(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_ring_ctx *ctx = req->ctx;
+       struct io_accept *accept = io_kiocb_to_cmd(req);
+       bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK;
+       unsigned int file_flags = force_nonblock ? O_NONBLOCK : 0;
+       bool fixed = !!accept->file_slot;
+       struct file *file;
+       int ret, fd;
+
+retry:
+       if (!fixed) {
+               fd = __get_unused_fd_flags(accept->flags, accept->nofile);
+               if (unlikely(fd < 0))
+                       return fd;
+       }
+       file = do_accept(req->file, file_flags, accept->addr, accept->addr_len,
+                        accept->flags);
+       if (IS_ERR(file)) {
+               if (!fixed)
+                       put_unused_fd(fd);
+               ret = PTR_ERR(file);
+               if (ret == -EAGAIN && force_nonblock) {
+                       /*
+                        * if it's multishot and polled, we don't need to
+                        * return EAGAIN to arm the poll infra since it
+                        * has already been done
+                        */
+                       if ((req->flags & IO_APOLL_MULTI_POLLED) ==
+                           IO_APOLL_MULTI_POLLED)
+                               ret = IOU_ISSUE_SKIP_COMPLETE;
+                       return ret;
+               }
+               if (ret == -ERESTARTSYS)
+                       ret = -EINTR;
+               req_set_fail(req);
+       } else if (!fixed) {
+               fd_install(fd, file);
+               ret = fd;
+       } else {
+               ret = io_fixed_fd_install(req, issue_flags, file,
+                                               accept->file_slot);
+       }
+
+       if (!(req->flags & REQ_F_APOLL_MULTISHOT)) {
+               io_req_set_res(req, ret, 0);
+               return IOU_OK;
+       }
+
+       if (ret >= 0 &&
+           io_post_aux_cqe(ctx, req->cqe.user_data, ret, IORING_CQE_F_MORE, false))
+               goto retry;
+
+       io_req_set_res(req, ret, 0);
+       if (req->flags & REQ_F_POLLED)
+               return IOU_STOP_MULTISHOT;
+       return IOU_OK;
+}
+
+int io_socket_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_socket *sock = io_kiocb_to_cmd(req);
+
+       if (sqe->addr || sqe->rw_flags || sqe->buf_index)
+               return -EINVAL;
+
+       sock->domain = READ_ONCE(sqe->fd);
+       sock->type = READ_ONCE(sqe->off);
+       sock->protocol = READ_ONCE(sqe->len);
+       sock->file_slot = READ_ONCE(sqe->file_index);
+       sock->nofile = rlimit(RLIMIT_NOFILE);
+
+       sock->flags = sock->type & ~SOCK_TYPE_MASK;
+       if (sock->file_slot && (sock->flags & SOCK_CLOEXEC))
+               return -EINVAL;
+       if (sock->flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
+               return -EINVAL;
+       return 0;
+}
+
+int io_socket(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_socket *sock = io_kiocb_to_cmd(req);
+       bool fixed = !!sock->file_slot;
+       struct file *file;
+       int ret, fd;
+
+       if (!fixed) {
+               fd = __get_unused_fd_flags(sock->flags, sock->nofile);
+               if (unlikely(fd < 0))
+                       return fd;
+       }
+       file = __sys_socket_file(sock->domain, sock->type, sock->protocol);
+       if (IS_ERR(file)) {
+               if (!fixed)
+                       put_unused_fd(fd);
+               ret = PTR_ERR(file);
+               if (ret == -EAGAIN && (issue_flags & IO_URING_F_NONBLOCK))
+                       return -EAGAIN;
+               if (ret == -ERESTARTSYS)
+                       ret = -EINTR;
+               req_set_fail(req);
+       } else if (!fixed) {
+               fd_install(fd, file);
+               ret = fd;
+       } else {
+               ret = io_fixed_fd_install(req, issue_flags, file,
+                                           sock->file_slot);
+       }
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
+
+int io_connect_prep_async(struct io_kiocb *req)
+{
+       struct io_async_connect *io = req->async_data;
+       struct io_connect *conn = io_kiocb_to_cmd(req);
+
+       return move_addr_to_kernel(conn->addr, conn->addr_len, &io->address);
+}
+
+int io_connect_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_connect *conn = io_kiocb_to_cmd(req);
+
+       if (sqe->len || sqe->buf_index || sqe->rw_flags || sqe->splice_fd_in)
+               return -EINVAL;
+
+       conn->addr = u64_to_user_ptr(READ_ONCE(sqe->addr));
+       conn->addr_len =  READ_ONCE(sqe->addr2);
+       return 0;
+}
+
+int io_connect(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_connect *connect = io_kiocb_to_cmd(req);
+       struct io_async_connect __io, *io;
+       unsigned file_flags;
+       int ret;
+       bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK;
+
+       if (req_has_async_data(req)) {
+               io = req->async_data;
+       } else {
+               ret = move_addr_to_kernel(connect->addr,
+                                               connect->addr_len,
+                                               &__io.address);
+               if (ret)
+                       goto out;
+               io = &__io;
+       }
+
+       file_flags = force_nonblock ? O_NONBLOCK : 0;
+
+       ret = __sys_connect_file(req->file, &io->address,
+                                       connect->addr_len, file_flags);
+       if ((ret == -EAGAIN || ret == -EINPROGRESS) && force_nonblock) {
+               if (req_has_async_data(req))
+                       return -EAGAIN;
+               if (io_alloc_async_data(req)) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               memcpy(req->async_data, &__io, sizeof(__io));
+               return -EAGAIN;
+       }
+       if (ret == -ERESTARTSYS)
+               ret = -EINTR;
+out:
+       if (ret < 0)
+               req_set_fail(req);
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
+
+void io_netmsg_cache_free(struct io_cache_entry *entry)
+{
+       kfree(container_of(entry, struct io_async_msghdr, cache));
+}
+#endif
diff --git a/io_uring/net.h b/io_uring/net.h
new file mode 100644 (file)
index 0000000..7c438d3
--- /dev/null
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/net.h>
+#include <linux/uio.h>
+
+#include "alloc_cache.h"
+
+#if defined(CONFIG_NET)
+struct io_async_msghdr {
+       union {
+               struct iovec            fast_iov[UIO_FASTIOV];
+               struct {
+                       struct iovec    fast_iov_one;
+                       __kernel_size_t controllen;
+                       int             namelen;
+                       __kernel_size_t payloadlen;
+               };
+               struct io_cache_entry   cache;
+       };
+       /* points to an allocated iov, if NULL we use fast_iov instead */
+       struct iovec                    *free_iov;
+       struct sockaddr __user          *uaddr;
+       struct msghdr                   msg;
+       struct sockaddr_storage         addr;
+};
+
+struct io_async_connect {
+       struct sockaddr_storage         address;
+};
+
+int io_shutdown_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_shutdown(struct io_kiocb *req, unsigned int issue_flags);
+
+int io_sendmsg_prep_async(struct io_kiocb *req);
+void io_sendmsg_recvmsg_cleanup(struct io_kiocb *req);
+int io_sendmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_sendmsg(struct io_kiocb *req, unsigned int issue_flags);
+int io_send(struct io_kiocb *req, unsigned int issue_flags);
+
+int io_recvmsg_prep_async(struct io_kiocb *req);
+int io_recvmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_recvmsg(struct io_kiocb *req, unsigned int issue_flags);
+int io_recv(struct io_kiocb *req, unsigned int issue_flags);
+
+int io_accept_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_accept(struct io_kiocb *req, unsigned int issue_flags);
+
+int io_socket_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_socket(struct io_kiocb *req, unsigned int issue_flags);
+
+int io_connect_prep_async(struct io_kiocb *req);
+int io_connect_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_connect(struct io_kiocb *req, unsigned int issue_flags);
+
+int io_sendzc(struct io_kiocb *req, unsigned int issue_flags);
+int io_sendzc_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+
+void io_netmsg_cache_free(struct io_cache_entry *entry);
+#else
+static inline void io_netmsg_cache_free(struct io_cache_entry *entry)
+{
+}
+#endif
diff --git a/io_uring/nop.c b/io_uring/nop.c
new file mode 100644 (file)
index 0000000..d956599
--- /dev/null
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/io_uring.h>
+
+#include <uapi/linux/io_uring.h>
+
+#include "io_uring.h"
+#include "nop.h"
+
+int io_nop_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       return 0;
+}
+
+/*
+ * IORING_OP_NOP just posts a completion event, nothing else.
+ */
+int io_nop(struct io_kiocb *req, unsigned int issue_flags)
+{
+       io_req_set_res(req, 0, 0);
+       return IOU_OK;
+}
diff --git a/io_uring/nop.h b/io_uring/nop.h
new file mode 100644 (file)
index 0000000..97f1535
--- /dev/null
@@ -0,0 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
+
+int io_nop_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_nop(struct io_kiocb *req, unsigned int issue_flags);
diff --git a/io_uring/notif.c b/io_uring/notif.c
new file mode 100644 (file)
index 0000000..b5f989d
--- /dev/null
@@ -0,0 +1,159 @@
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+#include <linux/net.h>
+#include <linux/io_uring.h>
+
+#include "io_uring.h"
+#include "notif.h"
+#include "rsrc.h"
+
+static void __io_notif_complete_tw(struct io_kiocb *notif, bool *locked)
+{
+       struct io_notif_data *nd = io_notif_to_data(notif);
+       struct io_ring_ctx *ctx = notif->ctx;
+
+       if (nd->account_pages && ctx->user) {
+               __io_unaccount_mem(ctx->user, nd->account_pages);
+               nd->account_pages = 0;
+       }
+       io_req_task_complete(notif, locked);
+}
+
+static inline void io_notif_complete(struct io_kiocb *notif)
+       __must_hold(&notif->ctx->uring_lock)
+{
+       bool locked = true;
+
+       __io_notif_complete_tw(notif, &locked);
+}
+
+static void io_uring_tx_zerocopy_callback(struct sk_buff *skb,
+                                         struct ubuf_info *uarg,
+                                         bool success)
+{
+       struct io_notif_data *nd = container_of(uarg, struct io_notif_data, uarg);
+       struct io_kiocb *notif = cmd_to_io_kiocb(nd);
+
+       if (refcount_dec_and_test(&uarg->refcnt)) {
+               notif->io_task_work.func = __io_notif_complete_tw;
+               io_req_task_work_add(notif);
+       }
+}
+
+struct io_kiocb *io_alloc_notif(struct io_ring_ctx *ctx,
+                               struct io_notif_slot *slot)
+       __must_hold(&ctx->uring_lock)
+{
+       struct io_kiocb *notif;
+       struct io_notif_data *nd;
+
+       if (unlikely(!io_alloc_req_refill(ctx)))
+               return NULL;
+       notif = io_alloc_req(ctx);
+       notif->opcode = IORING_OP_NOP;
+       notif->flags = 0;
+       notif->file = NULL;
+       notif->task = current;
+       io_get_task_refs(1);
+       notif->rsrc_node = NULL;
+       io_req_set_rsrc_node(notif, ctx, 0);
+       notif->cqe.user_data = slot->tag;
+       notif->cqe.flags = slot->seq++;
+       notif->cqe.res = 0;
+
+       nd = io_notif_to_data(notif);
+       nd->account_pages = 0;
+       nd->uarg.flags = SKBFL_ZEROCOPY_FRAG | SKBFL_DONT_ORPHAN;
+       nd->uarg.callback = io_uring_tx_zerocopy_callback;
+       /* master ref owned by io_notif_slot, will be dropped on flush */
+       refcount_set(&nd->uarg.refcnt, 1);
+       return notif;
+}
+
+void io_notif_slot_flush(struct io_notif_slot *slot)
+       __must_hold(&ctx->uring_lock)
+{
+       struct io_kiocb *notif = slot->notif;
+       struct io_notif_data *nd = io_notif_to_data(notif);
+
+       slot->notif = NULL;
+
+       /* drop slot's master ref */
+       if (refcount_dec_and_test(&nd->uarg.refcnt))
+               io_notif_complete(notif);
+}
+
+__cold int io_notif_unregister(struct io_ring_ctx *ctx)
+       __must_hold(&ctx->uring_lock)
+{
+       int i;
+
+       if (!ctx->notif_slots)
+               return -ENXIO;
+
+       for (i = 0; i < ctx->nr_notif_slots; i++) {
+               struct io_notif_slot *slot = &ctx->notif_slots[i];
+               struct io_kiocb *notif = slot->notif;
+               struct io_notif_data *nd;
+
+               if (!notif)
+                       continue;
+               nd = io_kiocb_to_cmd(notif);
+               slot->notif = NULL;
+               if (!refcount_dec_and_test(&nd->uarg.refcnt))
+                       continue;
+               notif->io_task_work.func = __io_notif_complete_tw;
+               io_req_task_work_add(notif);
+       }
+
+       kvfree(ctx->notif_slots);
+       ctx->notif_slots = NULL;
+       ctx->nr_notif_slots = 0;
+       return 0;
+}
+
+__cold int io_notif_register(struct io_ring_ctx *ctx,
+                            void __user *arg, unsigned int size)
+       __must_hold(&ctx->uring_lock)
+{
+       struct io_uring_notification_slot __user *slots;
+       struct io_uring_notification_slot slot;
+       struct io_uring_notification_register reg;
+       unsigned i;
+
+       BUILD_BUG_ON(sizeof(struct io_notif_data) > 64);
+
+       if (ctx->nr_notif_slots)
+               return -EBUSY;
+       if (size != sizeof(reg))
+               return -EINVAL;
+       if (copy_from_user(&reg, arg, sizeof(reg)))
+               return -EFAULT;
+       if (!reg.nr_slots || reg.nr_slots > IORING_MAX_NOTIF_SLOTS)
+               return -EINVAL;
+       if (reg.resv || reg.resv2 || reg.resv3)
+               return -EINVAL;
+
+       slots = u64_to_user_ptr(reg.data);
+       ctx->notif_slots = kvcalloc(reg.nr_slots, sizeof(ctx->notif_slots[0]),
+                               GFP_KERNEL_ACCOUNT);
+       if (!ctx->notif_slots)
+               return -ENOMEM;
+
+       for (i = 0; i < reg.nr_slots; i++, ctx->nr_notif_slots++) {
+               struct io_notif_slot *notif_slot = &ctx->notif_slots[i];
+
+               if (copy_from_user(&slot, &slots[i], sizeof(slot))) {
+                       io_notif_unregister(ctx);
+                       return -EFAULT;
+               }
+               if (slot.resv[0] | slot.resv[1] | slot.resv[2]) {
+                       io_notif_unregister(ctx);
+                       return -EINVAL;
+               }
+               notif_slot->tag = slot.tag;
+       }
+       return 0;
+}
diff --git a/io_uring/notif.h b/io_uring/notif.h
new file mode 100644 (file)
index 0000000..0819304
--- /dev/null
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/net.h>
+#include <linux/uio.h>
+#include <net/sock.h>
+#include <linux/nospec.h>
+
+#include "rsrc.h"
+
+#define IO_NOTIF_SPLICE_BATCH  32
+#define IORING_MAX_NOTIF_SLOTS (1U << 10)
+
+struct io_notif_data {
+       struct file             *file;
+       struct ubuf_info        uarg;
+       unsigned long           account_pages;
+};
+
+struct io_notif_slot {
+       /*
+        * Current/active notifier. A slot holds only one active notifier at a
+        * time and keeps one reference to it. Flush releases the reference and
+        * lazily replaces it with a new notifier.
+        */
+       struct io_kiocb         *notif;
+
+       /*
+        * Default ->user_data for this slot notifiers CQEs
+        */
+       u64                     tag;
+       /*
+        * Notifiers of a slot live in generations, we create a new notifier
+        * only after flushing the previous one. Track the sequential number
+        * for all notifiers and copy it into notifiers's cqe->cflags
+        */
+       u32                     seq;
+};
+
+int io_notif_register(struct io_ring_ctx *ctx,
+                     void __user *arg, unsigned int size);
+int io_notif_unregister(struct io_ring_ctx *ctx);
+
+void io_notif_slot_flush(struct io_notif_slot *slot);
+struct io_kiocb *io_alloc_notif(struct io_ring_ctx *ctx,
+                               struct io_notif_slot *slot);
+
+static inline struct io_notif_data *io_notif_to_data(struct io_kiocb *notif)
+{
+       return io_kiocb_to_cmd(notif);
+}
+
+static inline struct io_kiocb *io_get_notif(struct io_ring_ctx *ctx,
+                                           struct io_notif_slot *slot)
+{
+       if (!slot->notif)
+               slot->notif = io_alloc_notif(ctx, slot);
+       return slot->notif;
+}
+
+static inline struct io_notif_slot *io_get_notif_slot(struct io_ring_ctx *ctx,
+                                                     unsigned idx)
+       __must_hold(&ctx->uring_lock)
+{
+       if (idx >= ctx->nr_notif_slots)
+               return NULL;
+       idx = array_index_nospec(idx, ctx->nr_notif_slots);
+       return &ctx->notif_slots[idx];
+}
+
+static inline void io_notif_slot_flush_submit(struct io_notif_slot *slot,
+                                             unsigned int issue_flags)
+{
+       io_notif_slot_flush(slot);
+}
+
+static inline int io_notif_account_mem(struct io_kiocb *notif, unsigned len)
+{
+       struct io_ring_ctx *ctx = notif->ctx;
+       struct io_notif_data *nd = io_notif_to_data(notif);
+       unsigned nr_pages = (len >> PAGE_SHIFT) + 2;
+       int ret;
+
+       if (ctx->user) {
+               ret = __io_account_mem(ctx->user, nr_pages);
+               if (ret)
+                       return ret;
+               nd->account_pages += nr_pages;
+       }
+       return 0;
+}
diff --git a/io_uring/opdef.c b/io_uring/opdef.c
new file mode 100644 (file)
index 0000000..72dd2b2
--- /dev/null
@@ -0,0 +1,510 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * io_uring opcode handling table
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/io_uring.h>
+
+#include "io_uring.h"
+#include "opdef.h"
+#include "refs.h"
+#include "tctx.h"
+#include "sqpoll.h"
+#include "fdinfo.h"
+#include "kbuf.h"
+#include "rsrc.h"
+
+#include "xattr.h"
+#include "nop.h"
+#include "fs.h"
+#include "splice.h"
+#include "sync.h"
+#include "advise.h"
+#include "openclose.h"
+#include "uring_cmd.h"
+#include "epoll.h"
+#include "statx.h"
+#include "net.h"
+#include "msg_ring.h"
+#include "timeout.h"
+#include "poll.h"
+#include "cancel.h"
+#include "rw.h"
+
+static int io_no_issue(struct io_kiocb *req, unsigned int issue_flags)
+{
+       WARN_ON_ONCE(1);
+       return -ECANCELED;
+}
+
+static __maybe_unused int io_eopnotsupp_prep(struct io_kiocb *kiocb,
+                                            const struct io_uring_sqe *sqe)
+{
+       return -EOPNOTSUPP;
+}
+
+const struct io_op_def io_op_defs[] = {
+       [IORING_OP_NOP] = {
+               .audit_skip             = 1,
+               .iopoll                 = 1,
+               .name                   = "NOP",
+               .prep                   = io_nop_prep,
+               .issue                  = io_nop,
+       },
+       [IORING_OP_READV] = {
+               .needs_file             = 1,
+               .unbound_nonreg_file    = 1,
+               .pollin                 = 1,
+               .buffer_select          = 1,
+               .plug                   = 1,
+               .audit_skip             = 1,
+               .ioprio                 = 1,
+               .iopoll                 = 1,
+               .async_size             = sizeof(struct io_async_rw),
+               .name                   = "READV",
+               .prep                   = io_prep_rw,
+               .issue                  = io_read,
+               .prep_async             = io_readv_prep_async,
+               .cleanup                = io_readv_writev_cleanup,
+       },
+       [IORING_OP_WRITEV] = {
+               .needs_file             = 1,
+               .hash_reg_file          = 1,
+               .unbound_nonreg_file    = 1,
+               .pollout                = 1,
+               .plug                   = 1,
+               .audit_skip             = 1,
+               .ioprio                 = 1,
+               .iopoll                 = 1,
+               .async_size             = sizeof(struct io_async_rw),
+               .name                   = "WRITEV",
+               .prep                   = io_prep_rw,
+               .issue                  = io_write,
+               .prep_async             = io_writev_prep_async,
+               .cleanup                = io_readv_writev_cleanup,
+       },
+       [IORING_OP_FSYNC] = {
+               .needs_file             = 1,
+               .audit_skip             = 1,
+               .name                   = "FSYNC",
+               .prep                   = io_fsync_prep,
+               .issue                  = io_fsync,
+       },
+       [IORING_OP_READ_FIXED] = {
+               .needs_file             = 1,
+               .unbound_nonreg_file    = 1,
+               .pollin                 = 1,
+               .plug                   = 1,
+               .audit_skip             = 1,
+               .ioprio                 = 1,
+               .iopoll                 = 1,
+               .async_size             = sizeof(struct io_async_rw),
+               .name                   = "READ_FIXED",
+               .prep                   = io_prep_rw,
+               .issue                  = io_read,
+       },
+       [IORING_OP_WRITE_FIXED] = {
+               .needs_file             = 1,
+               .hash_reg_file          = 1,
+               .unbound_nonreg_file    = 1,
+               .pollout                = 1,
+               .plug                   = 1,
+               .audit_skip             = 1,
+               .ioprio                 = 1,
+               .iopoll                 = 1,
+               .async_size             = sizeof(struct io_async_rw),
+               .name                   = "WRITE_FIXED",
+               .prep                   = io_prep_rw,
+               .issue                  = io_write,
+       },
+       [IORING_OP_POLL_ADD] = {
+               .needs_file             = 1,
+               .unbound_nonreg_file    = 1,
+               .audit_skip             = 1,
+               .name                   = "POLL_ADD",
+               .prep                   = io_poll_add_prep,
+               .issue                  = io_poll_add,
+       },
+       [IORING_OP_POLL_REMOVE] = {
+               .audit_skip             = 1,
+               .name                   = "POLL_REMOVE",
+               .prep                   = io_poll_remove_prep,
+               .issue                  = io_poll_remove,
+       },
+       [IORING_OP_SYNC_FILE_RANGE] = {
+               .needs_file             = 1,
+               .audit_skip             = 1,
+               .name                   = "SYNC_FILE_RANGE",
+               .prep                   = io_sfr_prep,
+               .issue                  = io_sync_file_range,
+       },
+       [IORING_OP_SENDMSG] = {
+               .needs_file             = 1,
+               .unbound_nonreg_file    = 1,
+               .pollout                = 1,
+               .ioprio                 = 1,
+               .name                   = "SENDMSG",
+#if defined(CONFIG_NET)
+               .async_size             = sizeof(struct io_async_msghdr),
+               .prep                   = io_sendmsg_prep,
+               .issue                  = io_sendmsg,
+               .prep_async             = io_sendmsg_prep_async,
+               .cleanup                = io_sendmsg_recvmsg_cleanup,
+#else
+               .prep                   = io_eopnotsupp_prep,
+#endif
+       },
+       [IORING_OP_RECVMSG] = {
+               .needs_file             = 1,
+               .unbound_nonreg_file    = 1,
+               .pollin                 = 1,
+               .buffer_select          = 1,
+               .ioprio                 = 1,
+               .name                   = "RECVMSG",
+#if defined(CONFIG_NET)
+               .async_size             = sizeof(struct io_async_msghdr),
+               .prep                   = io_recvmsg_prep,
+               .issue                  = io_recvmsg,
+               .prep_async             = io_recvmsg_prep_async,
+               .cleanup                = io_sendmsg_recvmsg_cleanup,
+#else
+               .prep                   = io_eopnotsupp_prep,
+#endif
+       },
+       [IORING_OP_TIMEOUT] = {
+               .audit_skip             = 1,
+               .async_size             = sizeof(struct io_timeout_data),
+               .name                   = "TIMEOUT",
+               .prep                   = io_timeout_prep,
+               .issue                  = io_timeout,
+       },
+       [IORING_OP_TIMEOUT_REMOVE] = {
+               /* used by timeout updates' prep() */
+               .audit_skip             = 1,
+               .name                   = "TIMEOUT_REMOVE",
+               .prep                   = io_timeout_remove_prep,
+               .issue                  = io_timeout_remove,
+       },
+       [IORING_OP_ACCEPT] = {
+               .needs_file             = 1,
+               .unbound_nonreg_file    = 1,
+               .pollin                 = 1,
+               .poll_exclusive         = 1,
+               .ioprio                 = 1,    /* used for flags */
+               .name                   = "ACCEPT",
+#if defined(CONFIG_NET)
+               .prep                   = io_accept_prep,
+               .issue                  = io_accept,
+#else
+               .prep                   = io_eopnotsupp_prep,
+#endif
+       },
+       [IORING_OP_ASYNC_CANCEL] = {
+               .audit_skip             = 1,
+               .name                   = "ASYNC_CANCEL",
+               .prep                   = io_async_cancel_prep,
+               .issue                  = io_async_cancel,
+       },
+       [IORING_OP_LINK_TIMEOUT] = {
+               .audit_skip             = 1,
+               .async_size             = sizeof(struct io_timeout_data),
+               .name                   = "LINK_TIMEOUT",
+               .prep                   = io_link_timeout_prep,
+               .issue                  = io_no_issue,
+       },
+       [IORING_OP_CONNECT] = {
+               .needs_file             = 1,
+               .unbound_nonreg_file    = 1,
+               .pollout                = 1,
+               .name                   = "CONNECT",
+#if defined(CONFIG_NET)
+               .async_size             = sizeof(struct io_async_connect),
+               .prep                   = io_connect_prep,
+               .issue                  = io_connect,
+               .prep_async             = io_connect_prep_async,
+#else
+               .prep                   = io_eopnotsupp_prep,
+#endif
+       },
+       [IORING_OP_FALLOCATE] = {
+               .needs_file             = 1,
+               .name                   = "FALLOCATE",
+               .prep                   = io_fallocate_prep,
+               .issue                  = io_fallocate,
+       },
+       [IORING_OP_OPENAT] = {
+               .name                   = "OPENAT",
+               .prep                   = io_openat_prep,
+               .issue                  = io_openat,
+               .cleanup                = io_open_cleanup,
+       },
+       [IORING_OP_CLOSE] = {
+               .name                   = "CLOSE",
+               .prep                   = io_close_prep,
+               .issue                  = io_close,
+       },
+       [IORING_OP_RSRC_UPDATE] = {
+               .audit_skip             = 1,
+               .iopoll                 = 1,
+               .name                   = "RSRC_UPDATE",
+               .prep                   = io_rsrc_update_prep,
+               .issue                  = io_rsrc_update,
+               .ioprio                 = 1,
+       },
+       [IORING_OP_STATX] = {
+               .audit_skip             = 1,
+               .name                   = "STATX",
+               .prep                   = io_statx_prep,
+               .issue                  = io_statx,
+               .cleanup                = io_statx_cleanup,
+       },
+       [IORING_OP_READ] = {
+               .needs_file             = 1,
+               .unbound_nonreg_file    = 1,
+               .pollin                 = 1,
+               .buffer_select          = 1,
+               .plug                   = 1,
+               .audit_skip             = 1,
+               .ioprio                 = 1,
+               .iopoll                 = 1,
+               .async_size             = sizeof(struct io_async_rw),
+               .name                   = "READ",
+               .prep                   = io_prep_rw,
+               .issue                  = io_read,
+       },
+       [IORING_OP_WRITE] = {
+               .needs_file             = 1,
+               .hash_reg_file          = 1,
+               .unbound_nonreg_file    = 1,
+               .pollout                = 1,
+               .plug                   = 1,
+               .audit_skip             = 1,
+               .ioprio                 = 1,
+               .iopoll                 = 1,
+               .async_size             = sizeof(struct io_async_rw),
+               .name                   = "WRITE",
+               .prep                   = io_prep_rw,
+               .issue                  = io_write,
+       },
+       [IORING_OP_FADVISE] = {
+               .needs_file             = 1,
+               .audit_skip             = 1,
+               .name                   = "FADVISE",
+               .prep                   = io_fadvise_prep,
+               .issue                  = io_fadvise,
+       },
+       [IORING_OP_MADVISE] = {
+               .name                   = "MADVISE",
+               .prep                   = io_madvise_prep,
+               .issue                  = io_madvise,
+       },
+       [IORING_OP_SEND] = {
+               .needs_file             = 1,
+               .unbound_nonreg_file    = 1,
+               .pollout                = 1,
+               .audit_skip             = 1,
+               .ioprio                 = 1,
+               .name                   = "SEND",
+#if defined(CONFIG_NET)
+               .prep                   = io_sendmsg_prep,
+               .issue                  = io_send,
+#else
+               .prep                   = io_eopnotsupp_prep,
+#endif
+       },
+       [IORING_OP_RECV] = {
+               .needs_file             = 1,
+               .unbound_nonreg_file    = 1,
+               .pollin                 = 1,
+               .buffer_select          = 1,
+               .audit_skip             = 1,
+               .ioprio                 = 1,
+               .name                   = "RECV",
+#if defined(CONFIG_NET)
+               .prep                   = io_recvmsg_prep,
+               .issue                  = io_recv,
+#else
+               .prep                   = io_eopnotsupp_prep,
+#endif
+       },
+       [IORING_OP_OPENAT2] = {
+               .name                   = "OPENAT2",
+               .prep                   = io_openat2_prep,
+               .issue                  = io_openat2,
+               .cleanup                = io_open_cleanup,
+       },
+       [IORING_OP_EPOLL_CTL] = {
+               .unbound_nonreg_file    = 1,
+               .audit_skip             = 1,
+               .name                   = "EPOLL",
+#if defined(CONFIG_EPOLL)
+               .prep                   = io_epoll_ctl_prep,
+               .issue                  = io_epoll_ctl,
+#else
+               .prep                   = io_eopnotsupp_prep,
+#endif
+       },
+       [IORING_OP_SPLICE] = {
+               .needs_file             = 1,
+               .hash_reg_file          = 1,
+               .unbound_nonreg_file    = 1,
+               .audit_skip             = 1,
+               .name                   = "SPLICE",
+               .prep                   = io_splice_prep,
+               .issue                  = io_splice,
+       },
+       [IORING_OP_PROVIDE_BUFFERS] = {
+               .audit_skip             = 1,
+               .iopoll                 = 1,
+               .name                   = "PROVIDE_BUFFERS",
+               .prep                   = io_provide_buffers_prep,
+               .issue                  = io_provide_buffers,
+       },
+       [IORING_OP_REMOVE_BUFFERS] = {
+               .audit_skip             = 1,
+               .iopoll                 = 1,
+               .name                   = "REMOVE_BUFFERS",
+               .prep                   = io_remove_buffers_prep,
+               .issue                  = io_remove_buffers,
+       },
+       [IORING_OP_TEE] = {
+               .needs_file             = 1,
+               .hash_reg_file          = 1,
+               .unbound_nonreg_file    = 1,
+               .audit_skip             = 1,
+               .name                   = "TEE",
+               .prep                   = io_tee_prep,
+               .issue                  = io_tee,
+       },
+       [IORING_OP_SHUTDOWN] = {
+               .needs_file             = 1,
+               .name                   = "SHUTDOWN",
+#if defined(CONFIG_NET)
+               .prep                   = io_shutdown_prep,
+               .issue                  = io_shutdown,
+#else
+               .prep                   = io_eopnotsupp_prep,
+#endif
+       },
+       [IORING_OP_RENAMEAT] = {
+               .name                   = "RENAMEAT",
+               .prep                   = io_renameat_prep,
+               .issue                  = io_renameat,
+               .cleanup                = io_renameat_cleanup,
+       },
+       [IORING_OP_UNLINKAT] = {
+               .name                   = "UNLINKAT",
+               .prep                   = io_unlinkat_prep,
+               .issue                  = io_unlinkat,
+               .cleanup                = io_unlinkat_cleanup,
+       },
+       [IORING_OP_MKDIRAT] = {
+               .name                   = "MKDIRAT",
+               .prep                   = io_mkdirat_prep,
+               .issue                  = io_mkdirat,
+               .cleanup                = io_mkdirat_cleanup,
+       },
+       [IORING_OP_SYMLINKAT] = {
+               .name                   = "SYMLINKAT",
+               .prep                   = io_symlinkat_prep,
+               .issue                  = io_symlinkat,
+               .cleanup                = io_link_cleanup,
+       },
+       [IORING_OP_LINKAT] = {
+               .name                   = "LINKAT",
+               .prep                   = io_linkat_prep,
+               .issue                  = io_linkat,
+               .cleanup                = io_link_cleanup,
+       },
+       [IORING_OP_MSG_RING] = {
+               .needs_file             = 1,
+               .iopoll                 = 1,
+               .name                   = "MSG_RING",
+               .prep                   = io_msg_ring_prep,
+               .issue                  = io_msg_ring,
+       },
+       [IORING_OP_FSETXATTR] = {
+               .needs_file = 1,
+               .name                   = "FSETXATTR",
+               .prep                   = io_fsetxattr_prep,
+               .issue                  = io_fsetxattr,
+               .cleanup                = io_xattr_cleanup,
+       },
+       [IORING_OP_SETXATTR] = {
+               .name                   = "SETXATTR",
+               .prep                   = io_setxattr_prep,
+               .issue                  = io_setxattr,
+               .cleanup                = io_xattr_cleanup,
+       },
+       [IORING_OP_FGETXATTR] = {
+               .needs_file = 1,
+               .name                   = "FGETXATTR",
+               .prep                   = io_fgetxattr_prep,
+               .issue                  = io_fgetxattr,
+               .cleanup                = io_xattr_cleanup,
+       },
+       [IORING_OP_GETXATTR] = {
+               .name                   = "GETXATTR",
+               .prep                   = io_getxattr_prep,
+               .issue                  = io_getxattr,
+               .cleanup                = io_xattr_cleanup,
+       },
+       [IORING_OP_SOCKET] = {
+               .audit_skip             = 1,
+               .name                   = "SOCKET",
+#if defined(CONFIG_NET)
+               .prep                   = io_socket_prep,
+               .issue                  = io_socket,
+#else
+               .prep                   = io_eopnotsupp_prep,
+#endif
+       },
+       [IORING_OP_URING_CMD] = {
+               .needs_file             = 1,
+               .plug                   = 1,
+               .name                   = "URING_CMD",
+               .async_size             = uring_cmd_pdu_size(1),
+               .prep                   = io_uring_cmd_prep,
+               .issue                  = io_uring_cmd,
+               .prep_async             = io_uring_cmd_prep_async,
+       },
+       [IORING_OP_SENDZC_NOTIF] = {
+               .name                   = "SENDZC_NOTIF",
+               .needs_file             = 1,
+               .unbound_nonreg_file    = 1,
+               .pollout                = 1,
+               .audit_skip             = 1,
+               .ioprio                 = 1,
+#if defined(CONFIG_NET)
+               .prep                   = io_sendzc_prep,
+               .issue                  = io_sendzc,
+#else
+               .prep                   = io_eopnotsupp_prep,
+#endif
+
+       },
+};
+
+const char *io_uring_get_opcode(u8 opcode)
+{
+       if (opcode < IORING_OP_LAST)
+               return io_op_defs[opcode].name;
+       return "INVALID";
+}
+
+void __init io_uring_optable_init(void)
+{
+       int i;
+
+       BUILD_BUG_ON(ARRAY_SIZE(io_op_defs) != IORING_OP_LAST);
+
+       for (i = 0; i < ARRAY_SIZE(io_op_defs); i++) {
+               BUG_ON(!io_op_defs[i].prep);
+               if (io_op_defs[i].prep != io_eopnotsupp_prep)
+                       BUG_ON(!io_op_defs[i].issue);
+               WARN_ON_ONCE(!io_op_defs[i].name);
+       }
+}
diff --git a/io_uring/opdef.h b/io_uring/opdef.h
new file mode 100644 (file)
index 0000000..ece8ed4
--- /dev/null
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0
+#ifndef IOU_OP_DEF_H
+#define IOU_OP_DEF_H
+
+struct io_op_def {
+       /* needs req->file assigned */
+       unsigned                needs_file : 1;
+       /* should block plug */
+       unsigned                plug : 1;
+       /* hash wq insertion if file is a regular file */
+       unsigned                hash_reg_file : 1;
+       /* unbound wq insertion if file is a non-regular file */
+       unsigned                unbound_nonreg_file : 1;
+       /* set if opcode supports polled "wait" */
+       unsigned                pollin : 1;
+       unsigned                pollout : 1;
+       unsigned                poll_exclusive : 1;
+       /* op supports buffer selection */
+       unsigned                buffer_select : 1;
+       /* opcode is not supported by this kernel */
+       unsigned                not_supported : 1;
+       /* skip auditing */
+       unsigned                audit_skip : 1;
+       /* supports ioprio */
+       unsigned                ioprio : 1;
+       /* supports iopoll */
+       unsigned                iopoll : 1;
+       /* size of async data needed, if any */
+       unsigned short          async_size;
+
+       const char              *name;
+
+       int (*prep)(struct io_kiocb *, const struct io_uring_sqe *);
+       int (*issue)(struct io_kiocb *, unsigned int);
+       int (*prep_async)(struct io_kiocb *);
+       void (*cleanup)(struct io_kiocb *);
+};
+
+extern const struct io_op_def io_op_defs[];
+
+void io_uring_optable_init(void);
+#endif
diff --git a/io_uring/openclose.c b/io_uring/openclose.c
new file mode 100644 (file)
index 0000000..d1818ec
--- /dev/null
@@ -0,0 +1,256 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/fdtable.h>
+#include <linux/fsnotify.h>
+#include <linux/namei.h>
+#include <linux/io_uring.h>
+
+#include <uapi/linux/io_uring.h>
+
+#include "../fs/internal.h"
+
+#include "io_uring.h"
+#include "rsrc.h"
+#include "openclose.h"
+
+struct io_open {
+       struct file                     *file;
+       int                             dfd;
+       u32                             file_slot;
+       struct filename                 *filename;
+       struct open_how                 how;
+       unsigned long                   nofile;
+};
+
+struct io_close {
+       struct file                     *file;
+       int                             fd;
+       u32                             file_slot;
+};
+
+static int __io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_open *open = io_kiocb_to_cmd(req);
+       const char __user *fname;
+       int ret;
+
+       if (unlikely(sqe->buf_index))
+               return -EINVAL;
+       if (unlikely(req->flags & REQ_F_FIXED_FILE))
+               return -EBADF;
+
+       /* open.how should be already initialised */
+       if (!(open->how.flags & O_PATH) && force_o_largefile())
+               open->how.flags |= O_LARGEFILE;
+
+       open->dfd = READ_ONCE(sqe->fd);
+       fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
+       open->filename = getname(fname);
+       if (IS_ERR(open->filename)) {
+               ret = PTR_ERR(open->filename);
+               open->filename = NULL;
+               return ret;
+       }
+
+       open->file_slot = READ_ONCE(sqe->file_index);
+       if (open->file_slot && (open->how.flags & O_CLOEXEC))
+               return -EINVAL;
+
+       open->nofile = rlimit(RLIMIT_NOFILE);
+       req->flags |= REQ_F_NEED_CLEANUP;
+       return 0;
+}
+
+int io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_open *open = io_kiocb_to_cmd(req);
+       u64 mode = READ_ONCE(sqe->len);
+       u64 flags = READ_ONCE(sqe->open_flags);
+
+       open->how = build_open_how(flags, mode);
+       return __io_openat_prep(req, sqe);
+}
+
+int io_openat2_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_open *open = io_kiocb_to_cmd(req);
+       struct open_how __user *how;
+       size_t len;
+       int ret;
+
+       how = u64_to_user_ptr(READ_ONCE(sqe->addr2));
+       len = READ_ONCE(sqe->len);
+       if (len < OPEN_HOW_SIZE_VER0)
+               return -EINVAL;
+
+       ret = copy_struct_from_user(&open->how, sizeof(open->how), how, len);
+       if (ret)
+               return ret;
+
+       return __io_openat_prep(req, sqe);
+}
+
+int io_openat2(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_open *open = io_kiocb_to_cmd(req);
+       struct open_flags op;
+       struct file *file;
+       bool resolve_nonblock, nonblock_set;
+       bool fixed = !!open->file_slot;
+       int ret;
+
+       ret = build_open_flags(&open->how, &op);
+       if (ret)
+               goto err;
+       nonblock_set = op.open_flag & O_NONBLOCK;
+       resolve_nonblock = open->how.resolve & RESOLVE_CACHED;
+       if (issue_flags & IO_URING_F_NONBLOCK) {
+               /*
+                * Don't bother trying for O_TRUNC, O_CREAT, or O_TMPFILE open,
+                * it'll always -EAGAIN
+                */
+               if (open->how.flags & (O_TRUNC | O_CREAT | O_TMPFILE))
+                       return -EAGAIN;
+               op.lookup_flags |= LOOKUP_CACHED;
+               op.open_flag |= O_NONBLOCK;
+       }
+
+       if (!fixed) {
+               ret = __get_unused_fd_flags(open->how.flags, open->nofile);
+               if (ret < 0)
+                       goto err;
+       }
+
+       file = do_filp_open(open->dfd, open->filename, &op);
+       if (IS_ERR(file)) {
+               /*
+                * We could hang on to this 'fd' on retrying, but seems like
+                * marginal gain for something that is now known to be a slower
+                * path. So just put it, and we'll get a new one when we retry.
+                */
+               if (!fixed)
+                       put_unused_fd(ret);
+
+               ret = PTR_ERR(file);
+               /* only retry if RESOLVE_CACHED wasn't already set by application */
+               if (ret == -EAGAIN &&
+                   (!resolve_nonblock && (issue_flags & IO_URING_F_NONBLOCK)))
+                       return -EAGAIN;
+               goto err;
+       }
+
+       if ((issue_flags & IO_URING_F_NONBLOCK) && !nonblock_set)
+               file->f_flags &= ~O_NONBLOCK;
+       fsnotify_open(file);
+
+       if (!fixed)
+               fd_install(ret, file);
+       else
+               ret = io_fixed_fd_install(req, issue_flags, file,
+                                               open->file_slot);
+err:
+       putname(open->filename);
+       req->flags &= ~REQ_F_NEED_CLEANUP;
+       if (ret < 0)
+               req_set_fail(req);
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
+
+int io_openat(struct io_kiocb *req, unsigned int issue_flags)
+{
+       return io_openat2(req, issue_flags);
+}
+
+void io_open_cleanup(struct io_kiocb *req)
+{
+       struct io_open *open = io_kiocb_to_cmd(req);
+
+       if (open->filename)
+               putname(open->filename);
+}
+
+int __io_close_fixed(struct io_ring_ctx *ctx, unsigned int issue_flags,
+                    unsigned int offset)
+{
+       int ret;
+
+       io_ring_submit_lock(ctx, issue_flags);
+       ret = io_fixed_fd_remove(ctx, offset);
+       io_ring_submit_unlock(ctx, issue_flags);
+
+       return ret;
+}
+
+static inline int io_close_fixed(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_close *close = io_kiocb_to_cmd(req);
+
+       return __io_close_fixed(req->ctx, issue_flags, close->file_slot - 1);
+}
+
+int io_close_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_close *close = io_kiocb_to_cmd(req);
+
+       if (sqe->off || sqe->addr || sqe->len || sqe->rw_flags || sqe->buf_index)
+               return -EINVAL;
+       if (req->flags & REQ_F_FIXED_FILE)
+               return -EBADF;
+
+       close->fd = READ_ONCE(sqe->fd);
+       close->file_slot = READ_ONCE(sqe->file_index);
+       if (close->file_slot && close->fd)
+               return -EINVAL;
+
+       return 0;
+}
+
+int io_close(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct files_struct *files = current->files;
+       struct io_close *close = io_kiocb_to_cmd(req);
+       struct fdtable *fdt;
+       struct file *file;
+       int ret = -EBADF;
+
+       if (close->file_slot) {
+               ret = io_close_fixed(req, issue_flags);
+               goto err;
+       }
+
+       spin_lock(&files->file_lock);
+       fdt = files_fdtable(files);
+       if (close->fd >= fdt->max_fds) {
+               spin_unlock(&files->file_lock);
+               goto err;
+       }
+       file = rcu_dereference_protected(fdt->fd[close->fd],
+                       lockdep_is_held(&files->file_lock));
+       if (!file || io_is_uring_fops(file)) {
+               spin_unlock(&files->file_lock);
+               goto err;
+       }
+
+       /* if the file has a flush method, be safe and punt to async */
+       if (file->f_op->flush && (issue_flags & IO_URING_F_NONBLOCK)) {
+               spin_unlock(&files->file_lock);
+               return -EAGAIN;
+       }
+
+       file = __close_fd_get_file(close->fd);
+       spin_unlock(&files->file_lock);
+       if (!file)
+               goto err;
+
+       /* No ->flush() or already async, safely close from here */
+       ret = filp_close(file, current->files);
+err:
+       if (ret < 0)
+               req_set_fail(req);
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
diff --git a/io_uring/openclose.h b/io_uring/openclose.h
new file mode 100644 (file)
index 0000000..4b1c28d
--- /dev/null
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0
+
+int __io_close_fixed(struct io_ring_ctx *ctx, unsigned int issue_flags,
+                    unsigned int offset);
+
+int io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_openat(struct io_kiocb *req, unsigned int issue_flags);
+void io_open_cleanup(struct io_kiocb *req);
+
+int io_openat2_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_openat2(struct io_kiocb *req, unsigned int issue_flags);
+
+int io_close_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_close(struct io_kiocb *req, unsigned int issue_flags);
diff --git a/io_uring/poll.c b/io_uring/poll.c
new file mode 100644 (file)
index 0000000..dadd293
--- /dev/null
@@ -0,0 +1,965 @@
+// 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/poll.h>
+#include <linux/hashtable.h>
+#include <linux/io_uring.h>
+
+#include <trace/events/io_uring.h>
+
+#include <uapi/linux/io_uring.h>
+
+#include "io_uring.h"
+#include "refs.h"
+#include "opdef.h"
+#include "kbuf.h"
+#include "poll.h"
+#include "cancel.h"
+
+struct io_poll_update {
+       struct file                     *file;
+       u64                             old_user_data;
+       u64                             new_user_data;
+       __poll_t                        events;
+       bool                            update_events;
+       bool                            update_user_data;
+};
+
+struct io_poll_table {
+       struct poll_table_struct pt;
+       struct io_kiocb *req;
+       int nr_entries;
+       int error;
+       bool owning;
+       /* output value, set only if arm poll returns >0 */
+       __poll_t result_mask;
+};
+
+#define IO_POLL_CANCEL_FLAG    BIT(31)
+#define IO_POLL_REF_MASK       GENMASK(30, 0)
+
+#define IO_WQE_F_DOUBLE                1
+
+static inline struct io_kiocb *wqe_to_req(struct wait_queue_entry *wqe)
+{
+       unsigned long priv = (unsigned long)wqe->private;
+
+       return (struct io_kiocb *)(priv & ~IO_WQE_F_DOUBLE);
+}
+
+static inline bool wqe_is_double(struct wait_queue_entry *wqe)
+{
+       unsigned long priv = (unsigned long)wqe->private;
+
+       return priv & IO_WQE_F_DOUBLE;
+}
+
+/*
+ * If refs part of ->poll_refs (see IO_POLL_REF_MASK) is 0, it's free. We can
+ * bump it and acquire ownership. It's disallowed to modify requests while not
+ * owning it, that prevents from races for enqueueing task_work's and b/w
+ * arming poll and wakeups.
+ */
+static inline bool io_poll_get_ownership(struct io_kiocb *req)
+{
+       return !(atomic_fetch_inc(&req->poll_refs) & IO_POLL_REF_MASK);
+}
+
+static void io_poll_mark_cancelled(struct io_kiocb *req)
+{
+       atomic_or(IO_POLL_CANCEL_FLAG, &req->poll_refs);
+}
+
+static struct io_poll *io_poll_get_double(struct io_kiocb *req)
+{
+       /* pure poll stashes this in ->async_data, poll driven retry elsewhere */
+       if (req->opcode == IORING_OP_POLL_ADD)
+               return req->async_data;
+       return req->apoll->double_poll;
+}
+
+static struct io_poll *io_poll_get_single(struct io_kiocb *req)
+{
+       if (req->opcode == IORING_OP_POLL_ADD)
+               return io_kiocb_to_cmd(req);
+       return &req->apoll->poll;
+}
+
+static void io_poll_req_insert(struct io_kiocb *req)
+{
+       struct io_hash_table *table = &req->ctx->cancel_table;
+       u32 index = hash_long(req->cqe.user_data, table->hash_bits);
+       struct io_hash_bucket *hb = &table->hbs[index];
+
+       spin_lock(&hb->lock);
+       hlist_add_head(&req->hash_node, &hb->list);
+       spin_unlock(&hb->lock);
+}
+
+static void io_poll_req_delete(struct io_kiocb *req, struct io_ring_ctx *ctx)
+{
+       struct io_hash_table *table = &req->ctx->cancel_table;
+       u32 index = hash_long(req->cqe.user_data, table->hash_bits);
+       spinlock_t *lock = &table->hbs[index].lock;
+
+       spin_lock(lock);
+       hash_del(&req->hash_node);
+       spin_unlock(lock);
+}
+
+static void io_poll_req_insert_locked(struct io_kiocb *req)
+{
+       struct io_hash_table *table = &req->ctx->cancel_table_locked;
+       u32 index = hash_long(req->cqe.user_data, table->hash_bits);
+
+       hlist_add_head(&req->hash_node, &table->hbs[index].list);
+}
+
+static void io_poll_tw_hash_eject(struct io_kiocb *req, bool *locked)
+{
+       struct io_ring_ctx *ctx = req->ctx;
+
+       if (req->flags & REQ_F_HASH_LOCKED) {
+               /*
+                * ->cancel_table_locked is protected by ->uring_lock in
+                * contrast to per bucket spinlocks. Likely, tctx_task_work()
+                * already grabbed the mutex for us, but there is a chance it
+                * failed.
+                */
+               io_tw_lock(ctx, locked);
+               hash_del(&req->hash_node);
+               req->flags &= ~REQ_F_HASH_LOCKED;
+       } else {
+               io_poll_req_delete(req, ctx);
+       }
+}
+
+static void io_init_poll_iocb(struct io_poll *poll, __poll_t events,
+                             wait_queue_func_t wake_func)
+{
+       poll->head = NULL;
+#define IO_POLL_UNMASK (EPOLLERR|EPOLLHUP|EPOLLNVAL|EPOLLRDHUP)
+       /* mask in events that we always want/need */
+       poll->events = events | IO_POLL_UNMASK;
+       INIT_LIST_HEAD(&poll->wait.entry);
+       init_waitqueue_func_entry(&poll->wait, wake_func);
+}
+
+static inline void io_poll_remove_entry(struct io_poll *poll)
+{
+       struct wait_queue_head *head = smp_load_acquire(&poll->head);
+
+       if (head) {
+               spin_lock_irq(&head->lock);
+               list_del_init(&poll->wait.entry);
+               poll->head = NULL;
+               spin_unlock_irq(&head->lock);
+       }
+}
+
+static void io_poll_remove_entries(struct io_kiocb *req)
+{
+       /*
+        * Nothing to do if neither of those flags are set. Avoid dipping
+        * into the poll/apoll/double cachelines if we can.
+        */
+       if (!(req->flags & (REQ_F_SINGLE_POLL | REQ_F_DOUBLE_POLL)))
+               return;
+
+       /*
+        * While we hold the waitqueue lock and the waitqueue is nonempty,
+        * wake_up_pollfree() will wait for us.  However, taking the waitqueue
+        * lock in the first place can race with the waitqueue being freed.
+        *
+        * We solve this as eventpoll does: by taking advantage of the fact that
+        * all users of wake_up_pollfree() will RCU-delay the actual free.  If
+        * we enter rcu_read_lock() and see that the pointer to the queue is
+        * non-NULL, we can then lock it without the memory being freed out from
+        * under us.
+        *
+        * Keep holding rcu_read_lock() as long as we hold the queue lock, in
+        * case the caller deletes the entry from the queue, leaving it empty.
+        * In that case, only RCU prevents the queue memory from being freed.
+        */
+       rcu_read_lock();
+       if (req->flags & REQ_F_SINGLE_POLL)
+               io_poll_remove_entry(io_poll_get_single(req));
+       if (req->flags & REQ_F_DOUBLE_POLL)
+               io_poll_remove_entry(io_poll_get_double(req));
+       rcu_read_unlock();
+}
+
+enum {
+       IOU_POLL_DONE = 0,
+       IOU_POLL_NO_ACTION = 1,
+       IOU_POLL_REMOVE_POLL_USE_RES = 2,
+};
+
+/*
+ * All poll tw should go through this. Checks for poll events, manages
+ * references, does rewait, etc.
+ *
+ * Returns a negative error on failure. IOU_POLL_NO_ACTION when no action require,
+ * which is either spurious wakeup or multishot CQE is served.
+ * IOU_POLL_DONE when it's done with the request, then the mask is stored in req->cqe.res.
+ * IOU_POLL_REMOVE_POLL_USE_RES indicates to remove multishot poll and that the result
+ * is stored in req->cqe.
+ */
+static int io_poll_check_events(struct io_kiocb *req, bool *locked)
+{
+       struct io_ring_ctx *ctx = req->ctx;
+       int v, ret;
+
+       /* req->task == current here, checking PF_EXITING is safe */
+       if (unlikely(req->task->flags & PF_EXITING))
+               return -ECANCELED;
+
+       do {
+               v = atomic_read(&req->poll_refs);
+
+               /* tw handler should be the owner, and so have some references */
+               if (WARN_ON_ONCE(!(v & IO_POLL_REF_MASK)))
+                       return IOU_POLL_DONE;
+               if (v & IO_POLL_CANCEL_FLAG)
+                       return -ECANCELED;
+
+               /* the mask was stashed in __io_poll_execute */
+               if (!req->cqe.res) {
+                       struct poll_table_struct pt = { ._key = req->apoll_events };
+                       req->cqe.res = vfs_poll(req->file, &pt) & req->apoll_events;
+               }
+
+               if ((unlikely(!req->cqe.res)))
+                       continue;
+               if (req->apoll_events & EPOLLONESHOT)
+                       return IOU_POLL_DONE;
+
+               /* multishot, just fill a CQE and proceed */
+               if (!(req->flags & REQ_F_APOLL_MULTISHOT)) {
+                       __poll_t mask = mangle_poll(req->cqe.res &
+                                                   req->apoll_events);
+
+                       if (!io_post_aux_cqe(ctx, req->cqe.user_data,
+                                            mask, IORING_CQE_F_MORE, false)) {
+                               io_req_set_res(req, mask, 0);
+                               return IOU_POLL_REMOVE_POLL_USE_RES;
+                       }
+               } else {
+                       ret = io_poll_issue(req, locked);
+                       if (ret == IOU_STOP_MULTISHOT)
+                               return IOU_POLL_REMOVE_POLL_USE_RES;
+                       if (ret < 0)
+                               return ret;
+               }
+
+               /*
+                * 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));
+
+       return IOU_POLL_NO_ACTION;
+}
+
+static void io_poll_task_func(struct io_kiocb *req, bool *locked)
+{
+       int ret;
+
+       ret = io_poll_check_events(req, locked);
+       if (ret == IOU_POLL_NO_ACTION)
+               return;
+
+       if (ret == IOU_POLL_DONE) {
+               struct io_poll *poll = io_kiocb_to_cmd(req);
+               req->cqe.res = mangle_poll(req->cqe.res & poll->events);
+       } else if (ret != IOU_POLL_REMOVE_POLL_USE_RES) {
+               req->cqe.res = ret;
+               req_set_fail(req);
+       }
+
+       io_poll_remove_entries(req);
+       io_poll_tw_hash_eject(req, locked);
+
+       io_req_set_res(req, req->cqe.res, 0);
+       io_req_task_complete(req, locked);
+}
+
+static void io_apoll_task_func(struct io_kiocb *req, bool *locked)
+{
+       int ret;
+
+       ret = io_poll_check_events(req, locked);
+       if (ret == IOU_POLL_NO_ACTION)
+               return;
+
+       io_poll_remove_entries(req);
+       io_poll_tw_hash_eject(req, locked);
+
+       if (ret == IOU_POLL_REMOVE_POLL_USE_RES)
+               io_req_complete_post(req);
+       else if (ret == IOU_POLL_DONE)
+               io_req_task_submit(req, locked);
+       else
+               io_req_complete_failed(req, ret);
+}
+
+static void __io_poll_execute(struct io_kiocb *req, int mask)
+{
+       io_req_set_res(req, mask, 0);
+       /*
+        * This is useful for poll that is armed on behalf of another
+        * request, and where the wakeup path could be on a different
+        * CPU. We want to avoid pulling in req->apoll->events for that
+        * case.
+        */
+       if (req->opcode == IORING_OP_POLL_ADD)
+               req->io_task_work.func = io_poll_task_func;
+       else
+               req->io_task_work.func = io_apoll_task_func;
+
+       trace_io_uring_task_add(req, mask);
+       io_req_task_work_add(req);
+}
+
+static inline void io_poll_execute(struct io_kiocb *req, int res)
+{
+       if (io_poll_get_ownership(req))
+               __io_poll_execute(req, res);
+}
+
+static void io_poll_cancel_req(struct io_kiocb *req)
+{
+       io_poll_mark_cancelled(req);
+       /* kick tw, which should complete the request */
+       io_poll_execute(req, 0);
+}
+
+#define IO_ASYNC_POLL_COMMON   (EPOLLONESHOT | EPOLLPRI)
+
+static __cold int io_pollfree_wake(struct io_kiocb *req, struct io_poll *poll)
+{
+       io_poll_mark_cancelled(req);
+       /* we have to kick tw in case it's not already */
+       io_poll_execute(req, 0);
+
+       /*
+        * If the waitqueue is being freed early but someone is already
+        * holds ownership over it, we have to tear down the request as
+        * best we can. That means immediately removing the request from
+        * its waitqueue and preventing all further accesses to the
+        * waitqueue via the request.
+        */
+       list_del_init(&poll->wait.entry);
+
+       /*
+        * Careful: this *must* be the last step, since as soon
+        * as req->head is NULL'ed out, the request can be
+        * completed and freed, since aio_poll_complete_work()
+        * will no longer need to take the waitqueue lock.
+        */
+       smp_store_release(&poll->head, NULL);
+       return 1;
+}
+
+static int io_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync,
+                       void *key)
+{
+       struct io_kiocb *req = wqe_to_req(wait);
+       struct io_poll *poll = container_of(wait, struct io_poll, wait);
+       __poll_t mask = key_to_poll(key);
+
+       if (unlikely(mask & POLLFREE))
+               return io_pollfree_wake(req, poll);
+
+       /* for instances that support it check for an event match first */
+       if (mask && !(mask & (poll->events & ~IO_ASYNC_POLL_COMMON)))
+               return 0;
+
+       if (io_poll_get_ownership(req)) {
+               /* optional, saves extra locking for removal in tw handler */
+               if (mask && poll->events & EPOLLONESHOT) {
+                       list_del_init(&poll->wait.entry);
+                       poll->head = NULL;
+                       if (wqe_is_double(wait))
+                               req->flags &= ~REQ_F_DOUBLE_POLL;
+                       else
+                               req->flags &= ~REQ_F_SINGLE_POLL;
+               }
+               __io_poll_execute(req, mask);
+       }
+       return 1;
+}
+
+static void io_poll_double_prepare(struct io_kiocb *req)
+{
+       struct wait_queue_head *head;
+       struct io_poll *poll = io_poll_get_single(req);
+
+       /* head is RCU protected, see io_poll_remove_entries() comments */
+       rcu_read_lock();
+       head = smp_load_acquire(&poll->head);
+       /*
+        * poll arm may not hold ownership and so race with
+        * io_poll_wake() by modifying req->flags. There is only one
+        * poll entry queued, serialise with it by taking its head lock.
+        */
+       if (head)
+               spin_lock_irq(&head->lock);
+
+       req->flags |= REQ_F_DOUBLE_POLL;
+       if (req->opcode == IORING_OP_POLL_ADD)
+               req->flags |= REQ_F_ASYNC_DATA;
+
+       if (head)
+               spin_unlock_irq(&head->lock);
+       rcu_read_unlock();
+}
+
+static void __io_queue_proc(struct io_poll *poll, struct io_poll_table *pt,
+                           struct wait_queue_head *head,
+                           struct io_poll **poll_ptr)
+{
+       struct io_kiocb *req = pt->req;
+       unsigned long wqe_private = (unsigned long) req;
+
+       /*
+        * The file being polled uses multiple waitqueues for poll handling
+        * (e.g. one for read, one for write). Setup a separate io_poll
+        * if this happens.
+        */
+       if (unlikely(pt->nr_entries)) {
+               struct io_poll *first = poll;
+
+               /* double add on the same waitqueue head, ignore */
+               if (first->head == head)
+                       return;
+               /* already have a 2nd entry, fail a third attempt */
+               if (*poll_ptr) {
+                       if ((*poll_ptr)->head == head)
+                               return;
+                       pt->error = -EINVAL;
+                       return;
+               }
+
+               poll = kmalloc(sizeof(*poll), GFP_ATOMIC);
+               if (!poll) {
+                       pt->error = -ENOMEM;
+                       return;
+               }
+
+               /* mark as double wq entry */
+               wqe_private |= IO_WQE_F_DOUBLE;
+               io_init_poll_iocb(poll, first->events, first->wait.func);
+               io_poll_double_prepare(req);
+               *poll_ptr = poll;
+       } else {
+               /* fine to modify, there is no poll queued to race with us */
+               req->flags |= REQ_F_SINGLE_POLL;
+       }
+
+       pt->nr_entries++;
+       poll->head = head;
+       poll->wait.private = (void *) wqe_private;
+
+       if (poll->events & EPOLLEXCLUSIVE)
+               add_wait_queue_exclusive(head, &poll->wait);
+       else
+               add_wait_queue(head, &poll->wait);
+}
+
+static void io_poll_queue_proc(struct file *file, struct wait_queue_head *head,
+                              struct poll_table_struct *p)
+{
+       struct io_poll_table *pt = container_of(p, struct io_poll_table, pt);
+       struct io_poll *poll = io_kiocb_to_cmd(pt->req);
+
+       __io_queue_proc(poll, pt, head,
+                       (struct io_poll **) &pt->req->async_data);
+}
+
+static bool io_poll_can_finish_inline(struct io_kiocb *req,
+                                     struct io_poll_table *pt)
+{
+       return pt->owning || io_poll_get_ownership(req);
+}
+
+/*
+ * Returns 0 when it's handed over for polling. The caller owns the requests if
+ * it returns non-zero, but otherwise should not touch it. Negative values
+ * contain an error code. When the result is >0, the polling has completed
+ * inline and ipt.result_mask is set to the mask.
+ */
+static int __io_arm_poll_handler(struct io_kiocb *req,
+                                struct io_poll *poll,
+                                struct io_poll_table *ipt, __poll_t mask,
+                                unsigned issue_flags)
+{
+       struct io_ring_ctx *ctx = req->ctx;
+       int v;
+
+       INIT_HLIST_NODE(&req->hash_node);
+       req->work.cancel_seq = atomic_read(&ctx->cancel_seq);
+       io_init_poll_iocb(poll, mask, io_poll_wake);
+       poll->file = req->file;
+       req->apoll_events = poll->events;
+
+       ipt->pt._key = mask;
+       ipt->req = req;
+       ipt->error = 0;
+       ipt->nr_entries = 0;
+       /*
+        * Polling is either completed here or via task_work, so if we're in the
+        * task context we're naturally serialised with tw by merit of running
+        * the same task. When it's io-wq, take the ownership to prevent tw
+        * from running. However, when we're in the task context, skip taking
+        * it as an optimisation.
+        *
+        * Note: even though the request won't be completed/freed, without
+        * ownership we still can race with io_poll_wake().
+        * io_poll_can_finish_inline() tries to deal with that.
+        */
+       ipt->owning = issue_flags & IO_URING_F_UNLOCKED;
+       atomic_set(&req->poll_refs, (int)ipt->owning);
+
+       /* io-wq doesn't hold uring_lock */
+       if (issue_flags & IO_URING_F_UNLOCKED)
+               req->flags &= ~REQ_F_HASH_LOCKED;
+
+       mask = vfs_poll(req->file, &ipt->pt) & poll->events;
+
+       if (unlikely(ipt->error || !ipt->nr_entries)) {
+               io_poll_remove_entries(req);
+
+               if (!io_poll_can_finish_inline(req, ipt)) {
+                       io_poll_mark_cancelled(req);
+                       return 0;
+               } else if (mask && (poll->events & EPOLLET)) {
+                       ipt->result_mask = mask;
+                       return 1;
+               }
+               return ipt->error ?: -EINVAL;
+       }
+
+       if (mask &&
+          ((poll->events & (EPOLLET|EPOLLONESHOT)) == (EPOLLET|EPOLLONESHOT))) {
+               if (!io_poll_can_finish_inline(req, ipt))
+                       return 0;
+               io_poll_remove_entries(req);
+               ipt->result_mask = mask;
+               /* no one else has access to the req, forget about the ref */
+               return 1;
+       }
+
+       if (req->flags & REQ_F_HASH_LOCKED)
+               io_poll_req_insert_locked(req);
+       else
+               io_poll_req_insert(req);
+
+       if (mask && (poll->events & EPOLLET) &&
+           io_poll_can_finish_inline(req, ipt)) {
+               __io_poll_execute(req, mask);
+               return 0;
+       }
+
+       if (ipt->owning) {
+               /*
+                * Release ownership. If someone tried to queue a tw while it was
+                * locked, kick it off for them.
+                */
+               v = atomic_dec_return(&req->poll_refs);
+               if (unlikely(v & IO_POLL_REF_MASK))
+                       __io_poll_execute(req, 0);
+       }
+       return 0;
+}
+
+static void io_async_queue_proc(struct file *file, struct wait_queue_head *head,
+                              struct poll_table_struct *p)
+{
+       struct io_poll_table *pt = container_of(p, struct io_poll_table, pt);
+       struct async_poll *apoll = pt->req->apoll;
+
+       __io_queue_proc(&apoll->poll, pt, head, &apoll->double_poll);
+}
+
+static struct async_poll *io_req_alloc_apoll(struct io_kiocb *req,
+                                            unsigned issue_flags)
+{
+       struct io_ring_ctx *ctx = req->ctx;
+       struct io_cache_entry *entry;
+       struct async_poll *apoll;
+
+       if (req->flags & REQ_F_POLLED) {
+               apoll = req->apoll;
+               kfree(apoll->double_poll);
+       } else if (!(issue_flags & IO_URING_F_UNLOCKED) &&
+                  (entry = io_alloc_cache_get(&ctx->apoll_cache)) != NULL) {
+               apoll = container_of(entry, struct async_poll, cache);
+       } else {
+               apoll = kmalloc(sizeof(*apoll), GFP_ATOMIC);
+               if (unlikely(!apoll))
+                       return NULL;
+       }
+       apoll->double_poll = NULL;
+       req->apoll = apoll;
+       return apoll;
+}
+
+int io_arm_poll_handler(struct io_kiocb *req, unsigned issue_flags)
+{
+       const struct io_op_def *def = &io_op_defs[req->opcode];
+       struct async_poll *apoll;
+       struct io_poll_table ipt;
+       __poll_t mask = POLLPRI | POLLERR | EPOLLET;
+       int ret;
+
+       /*
+        * apoll requests already grab the mutex to complete in the tw handler,
+        * so removal from the mutex-backed hash is free, use it by default.
+        */
+       req->flags |= REQ_F_HASH_LOCKED;
+
+       if (!def->pollin && !def->pollout)
+               return IO_APOLL_ABORTED;
+       if (!file_can_poll(req->file))
+               return IO_APOLL_ABORTED;
+       if ((req->flags & (REQ_F_POLLED|REQ_F_PARTIAL_IO)) == REQ_F_POLLED)
+               return IO_APOLL_ABORTED;
+       if (!(req->flags & REQ_F_APOLL_MULTISHOT))
+               mask |= EPOLLONESHOT;
+
+       if (def->pollin) {
+               mask |= EPOLLIN | EPOLLRDNORM;
+
+               /* If reading from MSG_ERRQUEUE using recvmsg, ignore POLLIN */
+               if (req->flags & REQ_F_CLEAR_POLLIN)
+                       mask &= ~EPOLLIN;
+       } else {
+               mask |= EPOLLOUT | EPOLLWRNORM;
+       }
+       if (def->poll_exclusive)
+               mask |= EPOLLEXCLUSIVE;
+
+       apoll = io_req_alloc_apoll(req, issue_flags);
+       if (!apoll)
+               return IO_APOLL_ABORTED;
+       req->flags |= REQ_F_POLLED;
+       ipt.pt._qproc = io_async_queue_proc;
+
+       io_kbuf_recycle(req, issue_flags);
+
+       ret = __io_arm_poll_handler(req, &apoll->poll, &ipt, mask, issue_flags);
+       if (ret)
+               return ret > 0 ? IO_APOLL_READY : IO_APOLL_ABORTED;
+       trace_io_uring_poll_arm(req, mask, apoll->poll.events);
+       return IO_APOLL_OK;
+}
+
+static __cold bool io_poll_remove_all_table(struct task_struct *tsk,
+                                           struct io_hash_table *table,
+                                           bool cancel_all)
+{
+       unsigned nr_buckets = 1U << table->hash_bits;
+       struct hlist_node *tmp;
+       struct io_kiocb *req;
+       bool found = false;
+       int i;
+
+       for (i = 0; i < nr_buckets; i++) {
+               struct io_hash_bucket *hb = &table->hbs[i];
+
+               spin_lock(&hb->lock);
+               hlist_for_each_entry_safe(req, tmp, &hb->list, hash_node) {
+                       if (io_match_task_safe(req, tsk, cancel_all)) {
+                               hlist_del_init(&req->hash_node);
+                               io_poll_cancel_req(req);
+                               found = true;
+                       }
+               }
+               spin_unlock(&hb->lock);
+       }
+       return found;
+}
+
+/*
+ * Returns true if we found and killed one or more poll requests
+ */
+__cold bool io_poll_remove_all(struct io_ring_ctx *ctx, struct task_struct *tsk,
+                              bool cancel_all)
+       __must_hold(&ctx->uring_lock)
+{
+       bool ret;
+
+       ret = io_poll_remove_all_table(tsk, &ctx->cancel_table, cancel_all);
+       ret |= io_poll_remove_all_table(tsk, &ctx->cancel_table_locked, cancel_all);
+       return ret;
+}
+
+static struct io_kiocb *io_poll_find(struct io_ring_ctx *ctx, bool poll_only,
+                                    struct io_cancel_data *cd,
+                                    struct io_hash_table *table,
+                                    struct io_hash_bucket **out_bucket)
+{
+       struct io_kiocb *req;
+       u32 index = hash_long(cd->data, table->hash_bits);
+       struct io_hash_bucket *hb = &table->hbs[index];
+
+       *out_bucket = NULL;
+
+       spin_lock(&hb->lock);
+       hlist_for_each_entry(req, &hb->list, hash_node) {
+               if (cd->data != req->cqe.user_data)
+                       continue;
+               if (poll_only && req->opcode != IORING_OP_POLL_ADD)
+                       continue;
+               if (cd->flags & IORING_ASYNC_CANCEL_ALL) {
+                       if (cd->seq == req->work.cancel_seq)
+                               continue;
+                       req->work.cancel_seq = cd->seq;
+               }
+               *out_bucket = hb;
+               return req;
+       }
+       spin_unlock(&hb->lock);
+       return NULL;
+}
+
+static struct io_kiocb *io_poll_file_find(struct io_ring_ctx *ctx,
+                                         struct io_cancel_data *cd,
+                                         struct io_hash_table *table,
+                                         struct io_hash_bucket **out_bucket)
+{
+       unsigned nr_buckets = 1U << table->hash_bits;
+       struct io_kiocb *req;
+       int i;
+
+       *out_bucket = NULL;
+
+       for (i = 0; i < nr_buckets; i++) {
+               struct io_hash_bucket *hb = &table->hbs[i];
+
+               spin_lock(&hb->lock);
+               hlist_for_each_entry(req, &hb->list, hash_node) {
+                       if (!(cd->flags & IORING_ASYNC_CANCEL_ANY) &&
+                           req->file != cd->file)
+                               continue;
+                       if (cd->seq == req->work.cancel_seq)
+                               continue;
+                       req->work.cancel_seq = cd->seq;
+                       *out_bucket = hb;
+                       return req;
+               }
+               spin_unlock(&hb->lock);
+       }
+       return NULL;
+}
+
+static int io_poll_disarm(struct io_kiocb *req)
+{
+       if (!req)
+               return -ENOENT;
+       if (!io_poll_get_ownership(req))
+               return -EALREADY;
+       io_poll_remove_entries(req);
+       hash_del(&req->hash_node);
+       return 0;
+}
+
+static int __io_poll_cancel(struct io_ring_ctx *ctx, struct io_cancel_data *cd,
+                           struct io_hash_table *table)
+{
+       struct io_hash_bucket *bucket;
+       struct io_kiocb *req;
+
+       if (cd->flags & (IORING_ASYNC_CANCEL_FD|IORING_ASYNC_CANCEL_ANY))
+               req = io_poll_file_find(ctx, cd, table, &bucket);
+       else
+               req = io_poll_find(ctx, false, cd, table, &bucket);
+
+       if (req)
+               io_poll_cancel_req(req);
+       if (bucket)
+               spin_unlock(&bucket->lock);
+       return req ? 0 : -ENOENT;
+}
+
+int io_poll_cancel(struct io_ring_ctx *ctx, struct io_cancel_data *cd,
+                  unsigned issue_flags)
+{
+       int ret;
+
+       ret = __io_poll_cancel(ctx, cd, &ctx->cancel_table);
+       if (ret != -ENOENT)
+               return ret;
+
+       io_ring_submit_lock(ctx, issue_flags);
+       ret = __io_poll_cancel(ctx, cd, &ctx->cancel_table_locked);
+       io_ring_submit_unlock(ctx, issue_flags);
+       return ret;
+}
+
+static __poll_t io_poll_parse_events(const struct io_uring_sqe *sqe,
+                                    unsigned int flags)
+{
+       u32 events;
+
+       events = READ_ONCE(sqe->poll32_events);
+#ifdef __BIG_ENDIAN
+       events = swahw32(events);
+#endif
+       if (!(flags & IORING_POLL_ADD_MULTI))
+               events |= EPOLLONESHOT;
+       if (!(flags & IORING_POLL_ADD_LEVEL))
+               events |= EPOLLET;
+       return demangle_poll(events) |
+               (events & (EPOLLEXCLUSIVE|EPOLLONESHOT|EPOLLET));
+}
+
+int io_poll_remove_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_poll_update *upd = io_kiocb_to_cmd(req);
+       u32 flags;
+
+       if (sqe->buf_index || sqe->splice_fd_in)
+               return -EINVAL;
+       flags = READ_ONCE(sqe->len);
+       if (flags & ~(IORING_POLL_UPDATE_EVENTS | IORING_POLL_UPDATE_USER_DATA |
+                     IORING_POLL_ADD_MULTI))
+               return -EINVAL;
+       /* meaningless without update */
+       if (flags == IORING_POLL_ADD_MULTI)
+               return -EINVAL;
+
+       upd->old_user_data = READ_ONCE(sqe->addr);
+       upd->update_events = flags & IORING_POLL_UPDATE_EVENTS;
+       upd->update_user_data = flags & IORING_POLL_UPDATE_USER_DATA;
+
+       upd->new_user_data = READ_ONCE(sqe->off);
+       if (!upd->update_user_data && upd->new_user_data)
+               return -EINVAL;
+       if (upd->update_events)
+               upd->events = io_poll_parse_events(sqe, flags);
+       else if (sqe->poll32_events)
+               return -EINVAL;
+
+       return 0;
+}
+
+int io_poll_add_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_poll *poll = io_kiocb_to_cmd(req);
+       u32 flags;
+
+       if (sqe->buf_index || sqe->off || sqe->addr)
+               return -EINVAL;
+       flags = READ_ONCE(sqe->len);
+       if (flags & ~(IORING_POLL_ADD_MULTI|IORING_POLL_ADD_LEVEL))
+               return -EINVAL;
+       if ((flags & IORING_POLL_ADD_MULTI) && (req->flags & REQ_F_CQE_SKIP))
+               return -EINVAL;
+
+       poll->events = io_poll_parse_events(sqe, flags);
+       return 0;
+}
+
+int io_poll_add(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_poll *poll = io_kiocb_to_cmd(req);
+       struct io_poll_table ipt;
+       int ret;
+
+       ipt.pt._qproc = io_poll_queue_proc;
+
+       /*
+        * If sqpoll or single issuer, there is no contention for ->uring_lock
+        * and we'll end up holding it in tw handlers anyway.
+        */
+       if (req->ctx->flags & (IORING_SETUP_SQPOLL|IORING_SETUP_SINGLE_ISSUER))
+               req->flags |= REQ_F_HASH_LOCKED;
+
+       ret = __io_arm_poll_handler(req, poll, &ipt, poll->events, issue_flags);
+       if (ret > 0) {
+               io_req_set_res(req, ipt.result_mask, 0);
+               return IOU_OK;
+       }
+       return ret ?: IOU_ISSUE_SKIP_COMPLETE;
+}
+
+int io_poll_remove(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_poll_update *poll_update = io_kiocb_to_cmd(req);
+       struct io_cancel_data cd = { .data = poll_update->old_user_data, };
+       struct io_ring_ctx *ctx = req->ctx;
+       struct io_hash_bucket *bucket;
+       struct io_kiocb *preq;
+       int ret2, ret = 0;
+       bool locked;
+
+       preq = io_poll_find(ctx, true, &cd, &ctx->cancel_table, &bucket);
+       ret2 = io_poll_disarm(preq);
+       if (bucket)
+               spin_unlock(&bucket->lock);
+       if (!ret2)
+               goto found;
+       if (ret2 != -ENOENT) {
+               ret = ret2;
+               goto out;
+       }
+
+       io_ring_submit_lock(ctx, issue_flags);
+       preq = io_poll_find(ctx, true, &cd, &ctx->cancel_table_locked, &bucket);
+       ret2 = io_poll_disarm(preq);
+       if (bucket)
+               spin_unlock(&bucket->lock);
+       io_ring_submit_unlock(ctx, issue_flags);
+       if (ret2) {
+               ret = ret2;
+               goto out;
+       }
+
+found:
+       if (WARN_ON_ONCE(preq->opcode != IORING_OP_POLL_ADD)) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       if (poll_update->update_events || poll_update->update_user_data) {
+               /* only mask one event flags, keep behavior flags */
+               if (poll_update->update_events) {
+                       struct io_poll *poll = io_kiocb_to_cmd(preq);
+
+                       poll->events &= ~0xffff;
+                       poll->events |= poll_update->events & 0xffff;
+                       poll->events |= IO_POLL_UNMASK;
+               }
+               if (poll_update->update_user_data)
+                       preq->cqe.user_data = poll_update->new_user_data;
+
+               ret2 = io_poll_add(preq, issue_flags);
+               /* successfully updated, don't complete poll request */
+               if (!ret2 || ret2 == -EIOCBQUEUED)
+                       goto out;
+       }
+
+       req_set_fail(preq);
+       io_req_set_res(preq, -ECANCELED, 0);
+       locked = !(issue_flags & IO_URING_F_UNLOCKED);
+       io_req_task_complete(preq, &locked);
+out:
+       if (ret < 0) {
+               req_set_fail(req);
+               return ret;
+       }
+       /* complete update request, we're done with it */
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
+
+void io_apoll_cache_free(struct io_cache_entry *entry)
+{
+       kfree(container_of(entry, struct async_poll, cache));
+}
diff --git a/io_uring/poll.h b/io_uring/poll.h
new file mode 100644 (file)
index 0000000..5f3bae5
--- /dev/null
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "alloc_cache.h"
+
+enum {
+       IO_APOLL_OK,
+       IO_APOLL_ABORTED,
+       IO_APOLL_READY
+};
+
+struct io_poll {
+       struct file                     *file;
+       struct wait_queue_head          *head;
+       __poll_t                        events;
+       struct wait_queue_entry         wait;
+};
+
+struct async_poll {
+       union {
+               struct io_poll          poll;
+               struct io_cache_entry   cache;
+       };
+       struct io_poll          *double_poll;
+};
+
+int io_poll_add_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_poll_add(struct io_kiocb *req, unsigned int issue_flags);
+
+int io_poll_remove_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_poll_remove(struct io_kiocb *req, unsigned int issue_flags);
+
+struct io_cancel_data;
+int io_poll_cancel(struct io_ring_ctx *ctx, struct io_cancel_data *cd,
+                  unsigned issue_flags);
+int io_arm_poll_handler(struct io_kiocb *req, unsigned issue_flags);
+bool io_poll_remove_all(struct io_ring_ctx *ctx, struct task_struct *tsk,
+                       bool cancel_all);
+
+void io_apoll_cache_free(struct io_cache_entry *entry);
diff --git a/io_uring/refs.h b/io_uring/refs.h
new file mode 100644 (file)
index 0000000..1336de3
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef IOU_REQ_REF_H
+#define IOU_REQ_REF_H
+
+#include <linux/atomic.h>
+#include <linux/io_uring_types.h>
+
+/*
+ * Shamelessly stolen from the mm implementation of page reference checking,
+ * see commit f958d7b528b1 for details.
+ */
+#define req_ref_zero_or_close_to_overflow(req) \
+       ((unsigned int) atomic_read(&(req->refs)) + 127u <= 127u)
+
+static inline bool req_ref_inc_not_zero(struct io_kiocb *req)
+{
+       WARN_ON_ONCE(!(req->flags & REQ_F_REFCOUNT));
+       return atomic_inc_not_zero(&req->refs);
+}
+
+static inline bool req_ref_put_and_test(struct io_kiocb *req)
+{
+       if (likely(!(req->flags & REQ_F_REFCOUNT)))
+               return true;
+
+       WARN_ON_ONCE(req_ref_zero_or_close_to_overflow(req));
+       return atomic_dec_and_test(&req->refs);
+}
+
+static inline void req_ref_get(struct io_kiocb *req)
+{
+       WARN_ON_ONCE(!(req->flags & REQ_F_REFCOUNT));
+       WARN_ON_ONCE(req_ref_zero_or_close_to_overflow(req));
+       atomic_inc(&req->refs);
+}
+
+static inline void __io_req_set_refcount(struct io_kiocb *req, int nr)
+{
+       if (!(req->flags & REQ_F_REFCOUNT)) {
+               req->flags |= REQ_F_REFCOUNT;
+               atomic_set(&req->refs, nr);
+       }
+}
+
+static inline void io_req_set_refcount(struct io_kiocb *req)
+{
+       __io_req_set_refcount(req, 1);
+}
+#endif
diff --git a/io_uring/rsrc.c b/io_uring/rsrc.c
new file mode 100644 (file)
index 0000000..59704b9
--- /dev/null
@@ -0,0 +1,1420 @@
+// 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/nospec.h>
+#include <linux/hugetlb.h>
+#include <linux/compat.h>
+#include <linux/io_uring.h>
+
+#include <uapi/linux/io_uring.h>
+
+#include "io_uring.h"
+#include "openclose.h"
+#include "rsrc.h"
+#include "notif.h"
+
+struct io_rsrc_update {
+       struct file                     *file;
+       u64                             arg;
+       u32                             nr_args;
+       u32                             offset;
+       int                             type;
+};
+
+static int io_sqe_buffer_register(struct io_ring_ctx *ctx, struct iovec *iov,
+                                 struct io_mapped_ubuf **pimu,
+                                 struct page **last_hpage);
+
+#define IO_RSRC_REF_BATCH      100
+
+/* only define max */
+#define IORING_MAX_FIXED_FILES (1U << 20)
+#define IORING_MAX_REG_BUFFERS (1U << 14)
+
+void io_rsrc_refs_drop(struct io_ring_ctx *ctx)
+       __must_hold(&ctx->uring_lock)
+{
+       if (ctx->rsrc_cached_refs) {
+               io_rsrc_put_node(ctx->rsrc_node, ctx->rsrc_cached_refs);
+               ctx->rsrc_cached_refs = 0;
+       }
+}
+
+int __io_account_mem(struct user_struct *user, unsigned long nr_pages)
+{
+       unsigned long page_limit, cur_pages, new_pages;
+
+       if (!nr_pages)
+               return 0;
+
+       /* Don't allow more pages than we can safely lock */
+       page_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
+
+       cur_pages = atomic_long_read(&user->locked_vm);
+       do {
+               new_pages = cur_pages + nr_pages;
+               if (new_pages > page_limit)
+                       return -ENOMEM;
+       } while (!atomic_long_try_cmpxchg(&user->locked_vm,
+                                         &cur_pages, new_pages));
+       return 0;
+}
+
+static void io_unaccount_mem(struct io_ring_ctx *ctx, unsigned long nr_pages)
+{
+       if (ctx->user)
+               __io_unaccount_mem(ctx->user, nr_pages);
+
+       if (ctx->mm_account)
+               atomic64_sub(nr_pages, &ctx->mm_account->pinned_vm);
+}
+
+static int io_account_mem(struct io_ring_ctx *ctx, unsigned long nr_pages)
+{
+       int ret;
+
+       if (ctx->user) {
+               ret = __io_account_mem(ctx->user, nr_pages);
+               if (ret)
+                       return ret;
+       }
+
+       if (ctx->mm_account)
+               atomic64_add(nr_pages, &ctx->mm_account->pinned_vm);
+
+       return 0;
+}
+
+static int io_copy_iov(struct io_ring_ctx *ctx, struct iovec *dst,
+                      void __user *arg, unsigned index)
+{
+       struct iovec __user *src;
+
+#ifdef CONFIG_COMPAT
+       if (ctx->compat) {
+               struct compat_iovec __user *ciovs;
+               struct compat_iovec ciov;
+
+               ciovs = (struct compat_iovec __user *) arg;
+               if (copy_from_user(&ciov, &ciovs[index], sizeof(ciov)))
+                       return -EFAULT;
+
+               dst->iov_base = u64_to_user_ptr((u64)ciov.iov_base);
+               dst->iov_len = ciov.iov_len;
+               return 0;
+       }
+#endif
+       src = (struct iovec __user *) arg;
+       if (copy_from_user(dst, &src[index], sizeof(*dst)))
+               return -EFAULT;
+       return 0;
+}
+
+static int io_buffer_validate(struct iovec *iov)
+{
+       unsigned long tmp, acct_len = iov->iov_len + (PAGE_SIZE - 1);
+
+       /*
+        * Don't impose further limits on the size and buffer
+        * constraints here, we'll -EINVAL later when IO is
+        * submitted if they are wrong.
+        */
+       if (!iov->iov_base)
+               return iov->iov_len ? -EFAULT : 0;
+       if (!iov->iov_len)
+               return -EFAULT;
+
+       /* arbitrary limit, but we need something */
+       if (iov->iov_len > SZ_1G)
+               return -EFAULT;
+
+       if (check_add_overflow((unsigned long)iov->iov_base, acct_len, &tmp))
+               return -EOVERFLOW;
+
+       return 0;
+}
+
+static void io_buffer_unmap(struct io_ring_ctx *ctx, struct io_mapped_ubuf **slot)
+{
+       struct io_mapped_ubuf *imu = *slot;
+       unsigned int i;
+
+       if (imu != ctx->dummy_ubuf) {
+               for (i = 0; i < imu->nr_bvecs; i++)
+                       unpin_user_page(imu->bvec[i].bv_page);
+               if (imu->acct_pages)
+                       io_unaccount_mem(ctx, imu->acct_pages);
+               kvfree(imu);
+       }
+       *slot = NULL;
+}
+
+void io_rsrc_refs_refill(struct io_ring_ctx *ctx)
+       __must_hold(&ctx->uring_lock)
+{
+       ctx->rsrc_cached_refs += IO_RSRC_REF_BATCH;
+       percpu_ref_get_many(&ctx->rsrc_node->refs, IO_RSRC_REF_BATCH);
+}
+
+static void __io_rsrc_put_work(struct io_rsrc_node *ref_node)
+{
+       struct io_rsrc_data *rsrc_data = ref_node->rsrc_data;
+       struct io_ring_ctx *ctx = rsrc_data->ctx;
+       struct io_rsrc_put *prsrc, *tmp;
+
+       list_for_each_entry_safe(prsrc, tmp, &ref_node->rsrc_list, list) {
+               list_del(&prsrc->list);
+
+               if (prsrc->tag) {
+                       if (ctx->flags & IORING_SETUP_IOPOLL) {
+                               mutex_lock(&ctx->uring_lock);
+                               io_post_aux_cqe(ctx, prsrc->tag, 0, 0, true);
+                               mutex_unlock(&ctx->uring_lock);
+                       } else {
+                               io_post_aux_cqe(ctx, prsrc->tag, 0, 0, true);
+                       }
+               }
+
+               rsrc_data->do_put(ctx, prsrc);
+               kfree(prsrc);
+       }
+
+       io_rsrc_node_destroy(ref_node);
+       if (atomic_dec_and_test(&rsrc_data->refs))
+               complete(&rsrc_data->done);
+}
+
+void io_rsrc_put_work(struct work_struct *work)
+{
+       struct io_ring_ctx *ctx;
+       struct llist_node *node;
+
+       ctx = container_of(work, struct io_ring_ctx, rsrc_put_work.work);
+       node = llist_del_all(&ctx->rsrc_put_llist);
+
+       while (node) {
+               struct io_rsrc_node *ref_node;
+               struct llist_node *next = node->next;
+
+               ref_node = llist_entry(node, struct io_rsrc_node, llist);
+               __io_rsrc_put_work(ref_node);
+               node = next;
+       }
+}
+
+void io_wait_rsrc_data(struct io_rsrc_data *data)
+{
+       if (data && !atomic_dec_and_test(&data->refs))
+               wait_for_completion(&data->done);
+}
+
+void io_rsrc_node_destroy(struct io_rsrc_node *ref_node)
+{
+       percpu_ref_exit(&ref_node->refs);
+       kfree(ref_node);
+}
+
+static __cold void io_rsrc_node_ref_zero(struct percpu_ref *ref)
+{
+       struct io_rsrc_node *node = container_of(ref, struct io_rsrc_node, refs);
+       struct io_ring_ctx *ctx = node->rsrc_data->ctx;
+       unsigned long flags;
+       bool first_add = false;
+       unsigned long delay = HZ;
+
+       spin_lock_irqsave(&ctx->rsrc_ref_lock, flags);
+       node->done = true;
+
+       /* if we are mid-quiesce then do not delay */
+       if (node->rsrc_data->quiesce)
+               delay = 0;
+
+       while (!list_empty(&ctx->rsrc_ref_list)) {
+               node = list_first_entry(&ctx->rsrc_ref_list,
+                                           struct io_rsrc_node, node);
+               /* recycle ref nodes in order */
+               if (!node->done)
+                       break;
+               list_del(&node->node);
+               first_add |= llist_add(&node->llist, &ctx->rsrc_put_llist);
+       }
+       spin_unlock_irqrestore(&ctx->rsrc_ref_lock, flags);
+
+       if (first_add)
+               mod_delayed_work(system_wq, &ctx->rsrc_put_work, delay);
+}
+
+static struct io_rsrc_node *io_rsrc_node_alloc(void)
+{
+       struct io_rsrc_node *ref_node;
+
+       ref_node = kzalloc(sizeof(*ref_node), GFP_KERNEL);
+       if (!ref_node)
+               return NULL;
+
+       if (percpu_ref_init(&ref_node->refs, io_rsrc_node_ref_zero,
+                           0, GFP_KERNEL)) {
+               kfree(ref_node);
+               return NULL;
+       }
+       INIT_LIST_HEAD(&ref_node->node);
+       INIT_LIST_HEAD(&ref_node->rsrc_list);
+       ref_node->done = false;
+       return ref_node;
+}
+
+void io_rsrc_node_switch(struct io_ring_ctx *ctx,
+                        struct io_rsrc_data *data_to_kill)
+       __must_hold(&ctx->uring_lock)
+{
+       WARN_ON_ONCE(!ctx->rsrc_backup_node);
+       WARN_ON_ONCE(data_to_kill && !ctx->rsrc_node);
+
+       io_rsrc_refs_drop(ctx);
+
+       if (data_to_kill) {
+               struct io_rsrc_node *rsrc_node = ctx->rsrc_node;
+
+               rsrc_node->rsrc_data = data_to_kill;
+               spin_lock_irq(&ctx->rsrc_ref_lock);
+               list_add_tail(&rsrc_node->node, &ctx->rsrc_ref_list);
+               spin_unlock_irq(&ctx->rsrc_ref_lock);
+
+               atomic_inc(&data_to_kill->refs);
+               percpu_ref_kill(&rsrc_node->refs);
+               ctx->rsrc_node = NULL;
+       }
+
+       if (!ctx->rsrc_node) {
+               ctx->rsrc_node = ctx->rsrc_backup_node;
+               ctx->rsrc_backup_node = NULL;
+       }
+}
+
+int io_rsrc_node_switch_start(struct io_ring_ctx *ctx)
+{
+       if (ctx->rsrc_backup_node)
+               return 0;
+       ctx->rsrc_backup_node = io_rsrc_node_alloc();
+       return ctx->rsrc_backup_node ? 0 : -ENOMEM;
+}
+
+__cold static int io_rsrc_ref_quiesce(struct io_rsrc_data *data,
+                                     struct io_ring_ctx *ctx)
+{
+       int ret;
+
+       /* As we may drop ->uring_lock, other task may have started quiesce */
+       if (data->quiesce)
+               return -ENXIO;
+
+       data->quiesce = true;
+       do {
+               ret = io_rsrc_node_switch_start(ctx);
+               if (ret)
+                       break;
+               io_rsrc_node_switch(ctx, data);
+
+               /* kill initial ref, already quiesced if zero */
+               if (atomic_dec_and_test(&data->refs))
+                       break;
+               mutex_unlock(&ctx->uring_lock);
+               flush_delayed_work(&ctx->rsrc_put_work);
+               ret = wait_for_completion_interruptible(&data->done);
+               if (!ret) {
+                       mutex_lock(&ctx->uring_lock);
+                       if (atomic_read(&data->refs) > 0) {
+                               /*
+                                * it has been revived by another thread while
+                                * we were unlocked
+                                */
+                               mutex_unlock(&ctx->uring_lock);
+                       } else {
+                               break;
+                       }
+               }
+
+               atomic_inc(&data->refs);
+               /* wait for all works potentially completing data->done */
+               flush_delayed_work(&ctx->rsrc_put_work);
+               reinit_completion(&data->done);
+
+               ret = io_run_task_work_sig();
+               mutex_lock(&ctx->uring_lock);
+       } while (ret >= 0);
+       data->quiesce = false;
+
+       return ret;
+}
+
+static void io_free_page_table(void **table, size_t size)
+{
+       unsigned i, nr_tables = DIV_ROUND_UP(size, PAGE_SIZE);
+
+       for (i = 0; i < nr_tables; i++)
+               kfree(table[i]);
+       kfree(table);
+}
+
+static void io_rsrc_data_free(struct io_rsrc_data *data)
+{
+       size_t size = data->nr * sizeof(data->tags[0][0]);
+
+       if (data->tags)
+               io_free_page_table((void **)data->tags, size);
+       kfree(data);
+}
+
+static __cold void **io_alloc_page_table(size_t size)
+{
+       unsigned i, nr_tables = DIV_ROUND_UP(size, PAGE_SIZE);
+       size_t init_size = size;
+       void **table;
+
+       table = kcalloc(nr_tables, sizeof(*table), GFP_KERNEL_ACCOUNT);
+       if (!table)
+               return NULL;
+
+       for (i = 0; i < nr_tables; i++) {
+               unsigned int this_size = min_t(size_t, size, PAGE_SIZE);
+
+               table[i] = kzalloc(this_size, GFP_KERNEL_ACCOUNT);
+               if (!table[i]) {
+                       io_free_page_table(table, init_size);
+                       return NULL;
+               }
+               size -= this_size;
+       }
+       return table;
+}
+
+__cold static int io_rsrc_data_alloc(struct io_ring_ctx *ctx,
+                                    rsrc_put_fn *do_put, u64 __user *utags,
+                                    unsigned nr, struct io_rsrc_data **pdata)
+{
+       struct io_rsrc_data *data;
+       int ret = -ENOMEM;
+       unsigned i;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+       data->tags = (u64 **)io_alloc_page_table(nr * sizeof(data->tags[0][0]));
+       if (!data->tags) {
+               kfree(data);
+               return -ENOMEM;
+       }
+
+       data->nr = nr;
+       data->ctx = ctx;
+       data->do_put = do_put;
+       if (utags) {
+               ret = -EFAULT;
+               for (i = 0; i < nr; i++) {
+                       u64 *tag_slot = io_get_tag_slot(data, i);
+
+                       if (copy_from_user(tag_slot, &utags[i],
+                                          sizeof(*tag_slot)))
+                               goto fail;
+               }
+       }
+
+       atomic_set(&data->refs, 1);
+       init_completion(&data->done);
+       *pdata = data;
+       return 0;
+fail:
+       io_rsrc_data_free(data);
+       return ret;
+}
+
+static int __io_sqe_files_update(struct io_ring_ctx *ctx,
+                                struct io_uring_rsrc_update2 *up,
+                                unsigned nr_args)
+{
+       u64 __user *tags = u64_to_user_ptr(up->tags);
+       __s32 __user *fds = u64_to_user_ptr(up->data);
+       struct io_rsrc_data *data = ctx->file_data;
+       struct io_fixed_file *file_slot;
+       struct file *file;
+       int fd, i, err = 0;
+       unsigned int done;
+       bool needs_switch = false;
+
+       if (!ctx->file_data)
+               return -ENXIO;
+       if (up->offset + nr_args > ctx->nr_user_files)
+               return -EINVAL;
+
+       for (done = 0; done < nr_args; done++) {
+               u64 tag = 0;
+
+               if ((tags && copy_from_user(&tag, &tags[done], sizeof(tag))) ||
+                   copy_from_user(&fd, &fds[done], sizeof(fd))) {
+                       err = -EFAULT;
+                       break;
+               }
+               if ((fd == IORING_REGISTER_FILES_SKIP || fd == -1) && tag) {
+                       err = -EINVAL;
+                       break;
+               }
+               if (fd == IORING_REGISTER_FILES_SKIP)
+                       continue;
+
+               i = array_index_nospec(up->offset + done, ctx->nr_user_files);
+               file_slot = io_fixed_file_slot(&ctx->file_table, i);
+
+               if (file_slot->file_ptr) {
+                       file = (struct file *)(file_slot->file_ptr & FFS_MASK);
+                       err = io_queue_rsrc_removal(data, i, ctx->rsrc_node, file);
+                       if (err)
+                               break;
+                       file_slot->file_ptr = 0;
+                       io_file_bitmap_clear(&ctx->file_table, i);
+                       needs_switch = true;
+               }
+               if (fd != -1) {
+                       file = fget(fd);
+                       if (!file) {
+                               err = -EBADF;
+                               break;
+                       }
+                       /*
+                        * Don't allow io_uring instances to be registered. If
+                        * UNIX isn't enabled, then this causes a reference
+                        * cycle and this instance can never get freed. If UNIX
+                        * is enabled we'll handle it just fine, but there's
+                        * still no point in allowing a ring fd as it doesn't
+                        * support regular read/write anyway.
+                        */
+                       if (io_is_uring_fops(file)) {
+                               fput(file);
+                               err = -EBADF;
+                               break;
+                       }
+                       err = io_scm_file_account(ctx, file);
+                       if (err) {
+                               fput(file);
+                               break;
+                       }
+                       *io_get_tag_slot(data, i) = tag;
+                       io_fixed_file_set(file_slot, file);
+                       io_file_bitmap_set(&ctx->file_table, i);
+               }
+       }
+
+       if (needs_switch)
+               io_rsrc_node_switch(ctx, data);
+       return done ? done : err;
+}
+
+static int __io_sqe_buffers_update(struct io_ring_ctx *ctx,
+                                  struct io_uring_rsrc_update2 *up,
+                                  unsigned int nr_args)
+{
+       u64 __user *tags = u64_to_user_ptr(up->tags);
+       struct iovec iov, __user *iovs = u64_to_user_ptr(up->data);
+       struct page *last_hpage = NULL;
+       bool needs_switch = false;
+       __u32 done;
+       int i, err;
+
+       if (!ctx->buf_data)
+               return -ENXIO;
+       if (up->offset + nr_args > ctx->nr_user_bufs)
+               return -EINVAL;
+
+       for (done = 0; done < nr_args; done++) {
+               struct io_mapped_ubuf *imu;
+               int offset = up->offset + done;
+               u64 tag = 0;
+
+               err = io_copy_iov(ctx, &iov, iovs, done);
+               if (err)
+                       break;
+               if (tags && copy_from_user(&tag, &tags[done], sizeof(tag))) {
+                       err = -EFAULT;
+                       break;
+               }
+               err = io_buffer_validate(&iov);
+               if (err)
+                       break;
+               if (!iov.iov_base && tag) {
+                       err = -EINVAL;
+                       break;
+               }
+               err = io_sqe_buffer_register(ctx, &iov, &imu, &last_hpage);
+               if (err)
+                       break;
+
+               i = array_index_nospec(offset, ctx->nr_user_bufs);
+               if (ctx->user_bufs[i] != ctx->dummy_ubuf) {
+                       err = io_queue_rsrc_removal(ctx->buf_data, i,
+                                                   ctx->rsrc_node, ctx->user_bufs[i]);
+                       if (unlikely(err)) {
+                               io_buffer_unmap(ctx, &imu);
+                               break;
+                       }
+                       ctx->user_bufs[i] = ctx->dummy_ubuf;
+                       needs_switch = true;
+               }
+
+               ctx->user_bufs[i] = imu;
+               *io_get_tag_slot(ctx->buf_data, offset) = tag;
+       }
+
+       if (needs_switch)
+               io_rsrc_node_switch(ctx, ctx->buf_data);
+       return done ? done : err;
+}
+
+static int __io_register_rsrc_update(struct io_ring_ctx *ctx, unsigned type,
+                                    struct io_uring_rsrc_update2 *up,
+                                    unsigned nr_args)
+{
+       __u32 tmp;
+       int err;
+
+       if (check_add_overflow(up->offset, nr_args, &tmp))
+               return -EOVERFLOW;
+       err = io_rsrc_node_switch_start(ctx);
+       if (err)
+               return err;
+
+       switch (type) {
+       case IORING_RSRC_FILE:
+               return __io_sqe_files_update(ctx, up, nr_args);
+       case IORING_RSRC_BUFFER:
+               return __io_sqe_buffers_update(ctx, up, nr_args);
+       }
+       return -EINVAL;
+}
+
+int io_register_files_update(struct io_ring_ctx *ctx, void __user *arg,
+                            unsigned nr_args)
+{
+       struct io_uring_rsrc_update2 up;
+
+       if (!nr_args)
+               return -EINVAL;
+       memset(&up, 0, sizeof(up));
+       if (copy_from_user(&up, arg, sizeof(struct io_uring_rsrc_update)))
+               return -EFAULT;
+       if (up.resv || up.resv2)
+               return -EINVAL;
+       return __io_register_rsrc_update(ctx, IORING_RSRC_FILE, &up, nr_args);
+}
+
+int io_register_rsrc_update(struct io_ring_ctx *ctx, void __user *arg,
+                           unsigned size, unsigned type)
+{
+       struct io_uring_rsrc_update2 up;
+
+       if (size != sizeof(up))
+               return -EINVAL;
+       if (copy_from_user(&up, arg, sizeof(up)))
+               return -EFAULT;
+       if (!up.nr || up.resv || up.resv2)
+               return -EINVAL;
+       return __io_register_rsrc_update(ctx, type, &up, up.nr);
+}
+
+__cold int io_register_rsrc(struct io_ring_ctx *ctx, void __user *arg,
+                           unsigned int size, unsigned int type)
+{
+       struct io_uring_rsrc_register rr;
+
+       /* keep it extendible */
+       if (size != sizeof(rr))
+               return -EINVAL;
+
+       memset(&rr, 0, sizeof(rr));
+       if (copy_from_user(&rr, arg, size))
+               return -EFAULT;
+       if (!rr.nr || rr.resv2)
+               return -EINVAL;
+       if (rr.flags & ~IORING_RSRC_REGISTER_SPARSE)
+               return -EINVAL;
+
+       switch (type) {
+       case IORING_RSRC_FILE:
+               if (rr.flags & IORING_RSRC_REGISTER_SPARSE && rr.data)
+                       break;
+               return io_sqe_files_register(ctx, u64_to_user_ptr(rr.data),
+                                            rr.nr, u64_to_user_ptr(rr.tags));
+       case IORING_RSRC_BUFFER:
+               if (rr.flags & IORING_RSRC_REGISTER_SPARSE && rr.data)
+                       break;
+               return io_sqe_buffers_register(ctx, u64_to_user_ptr(rr.data),
+                                              rr.nr, u64_to_user_ptr(rr.tags));
+       }
+       return -EINVAL;
+}
+
+int io_rsrc_update_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_rsrc_update *up = io_kiocb_to_cmd(req);
+
+       if (unlikely(req->flags & (REQ_F_FIXED_FILE | REQ_F_BUFFER_SELECT)))
+               return -EINVAL;
+       if (sqe->rw_flags || sqe->splice_fd_in)
+               return -EINVAL;
+
+       up->offset = READ_ONCE(sqe->off);
+       up->nr_args = READ_ONCE(sqe->len);
+       if (!up->nr_args)
+               return -EINVAL;
+       up->arg = READ_ONCE(sqe->addr);
+       up->type = READ_ONCE(sqe->ioprio);
+       return 0;
+}
+
+static int io_files_update_with_index_alloc(struct io_kiocb *req,
+                                           unsigned int issue_flags)
+{
+       struct io_rsrc_update *up = io_kiocb_to_cmd(req);
+       __s32 __user *fds = u64_to_user_ptr(up->arg);
+       unsigned int done;
+       struct file *file;
+       int ret, fd;
+
+       if (!req->ctx->file_data)
+               return -ENXIO;
+
+       for (done = 0; done < up->nr_args; done++) {
+               if (copy_from_user(&fd, &fds[done], sizeof(fd))) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               file = fget(fd);
+               if (!file) {
+                       ret = -EBADF;
+                       break;
+               }
+               ret = io_fixed_fd_install(req, issue_flags, file,
+                                         IORING_FILE_INDEX_ALLOC);
+               if (ret < 0)
+                       break;
+               if (copy_to_user(&fds[done], &ret, sizeof(ret))) {
+                       __io_close_fixed(req->ctx, issue_flags, ret);
+                       ret = -EFAULT;
+                       break;
+               }
+       }
+
+       if (done)
+               return done;
+       return ret;
+}
+
+static int io_files_update(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_rsrc_update *up = io_kiocb_to_cmd(req);
+       struct io_ring_ctx *ctx = req->ctx;
+       struct io_uring_rsrc_update2 up2;
+       int ret;
+
+       up2.offset = up->offset;
+       up2.data = up->arg;
+       up2.nr = 0;
+       up2.tags = 0;
+       up2.resv = 0;
+       up2.resv2 = 0;
+
+       if (up->offset == IORING_FILE_INDEX_ALLOC) {
+               ret = io_files_update_with_index_alloc(req, issue_flags);
+       } else {
+               io_ring_submit_lock(ctx, issue_flags);
+               ret = __io_register_rsrc_update(ctx, IORING_RSRC_FILE,
+                                               &up2, up->nr_args);
+               io_ring_submit_unlock(ctx, issue_flags);
+       }
+
+       if (ret < 0)
+               req_set_fail(req);
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
+
+static int io_notif_update(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_rsrc_update *up = io_kiocb_to_cmd(req);
+       struct io_ring_ctx *ctx = req->ctx;
+       unsigned len = up->nr_args;
+       unsigned idx_end, idx = up->offset;
+       int ret = 0;
+
+       io_ring_submit_lock(ctx, issue_flags);
+       if (unlikely(check_add_overflow(idx, len, &idx_end))) {
+               ret = -EOVERFLOW;
+               goto out;
+       }
+       if (unlikely(idx_end > ctx->nr_notif_slots)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       for (; idx < idx_end; idx++) {
+               struct io_notif_slot *slot = &ctx->notif_slots[idx];
+
+               if (!slot->notif)
+                       continue;
+               if (up->arg)
+                       slot->tag = up->arg;
+               io_notif_slot_flush_submit(slot, issue_flags);
+       }
+out:
+       io_ring_submit_unlock(ctx, issue_flags);
+       if (ret < 0)
+               req_set_fail(req);
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
+
+int io_rsrc_update(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_rsrc_update *up = io_kiocb_to_cmd(req);
+
+       switch (up->type) {
+       case IORING_RSRC_UPDATE_FILES:
+               return io_files_update(req, issue_flags);
+       case IORING_RSRC_UPDATE_NOTIF:
+               return io_notif_update(req, issue_flags);
+       }
+       return -EINVAL;
+}
+
+int io_queue_rsrc_removal(struct io_rsrc_data *data, unsigned idx,
+                         struct io_rsrc_node *node, void *rsrc)
+{
+       u64 *tag_slot = io_get_tag_slot(data, idx);
+       struct io_rsrc_put *prsrc;
+
+       prsrc = kzalloc(sizeof(*prsrc), GFP_KERNEL);
+       if (!prsrc)
+               return -ENOMEM;
+
+       prsrc->tag = *tag_slot;
+       *tag_slot = 0;
+       prsrc->rsrc = rsrc;
+       list_add(&prsrc->list, &node->rsrc_list);
+       return 0;
+}
+
+void __io_sqe_files_unregister(struct io_ring_ctx *ctx)
+{
+#if !defined(IO_URING_SCM_ALL)
+       int i;
+
+       for (i = 0; i < ctx->nr_user_files; i++) {
+               struct file *file = io_file_from_index(&ctx->file_table, i);
+
+               if (!file)
+                       continue;
+               if (io_fixed_file_slot(&ctx->file_table, i)->file_ptr & FFS_SCM)
+                       continue;
+               io_file_bitmap_clear(&ctx->file_table, i);
+               fput(file);
+       }
+#endif
+
+#if defined(CONFIG_UNIX)
+       if (ctx->ring_sock) {
+               struct sock *sock = ctx->ring_sock->sk;
+               struct sk_buff *skb;
+
+               while ((skb = skb_dequeue(&sock->sk_receive_queue)) != NULL)
+                       kfree_skb(skb);
+       }
+#endif
+       io_free_file_tables(&ctx->file_table);
+       io_rsrc_data_free(ctx->file_data);
+       ctx->file_data = NULL;
+       ctx->nr_user_files = 0;
+}
+
+int io_sqe_files_unregister(struct io_ring_ctx *ctx)
+{
+       unsigned nr = ctx->nr_user_files;
+       int ret;
+
+       if (!ctx->file_data)
+               return -ENXIO;
+
+       /*
+        * Quiesce may unlock ->uring_lock, and while it's not held
+        * prevent new requests using the table.
+        */
+       ctx->nr_user_files = 0;
+       ret = io_rsrc_ref_quiesce(ctx->file_data, ctx);
+       ctx->nr_user_files = nr;
+       if (!ret)
+               __io_sqe_files_unregister(ctx);
+       return ret;
+}
+
+/*
+ * Ensure the UNIX gc is aware of our file set, so we are certain that
+ * the io_uring can be safely unregistered on process exit, even if we have
+ * loops in the file referencing. We account only files that can hold other
+ * files because otherwise they can't form a loop and so are not interesting
+ * for GC.
+ */
+int __io_scm_file_account(struct io_ring_ctx *ctx, struct file *file)
+{
+#if defined(CONFIG_UNIX)
+       struct sock *sk = ctx->ring_sock->sk;
+       struct sk_buff_head *head = &sk->sk_receive_queue;
+       struct scm_fp_list *fpl;
+       struct sk_buff *skb;
+
+       if (likely(!io_file_need_scm(file)))
+               return 0;
+
+       /*
+        * See if we can merge this file into an existing skb SCM_RIGHTS
+        * file set. If there's no room, fall back to allocating a new skb
+        * and filling it in.
+        */
+       spin_lock_irq(&head->lock);
+       skb = skb_peek(head);
+       if (skb && UNIXCB(skb).fp->count < SCM_MAX_FD)
+               __skb_unlink(skb, head);
+       else
+               skb = NULL;
+       spin_unlock_irq(&head->lock);
+
+       if (!skb) {
+               fpl = kzalloc(sizeof(*fpl), GFP_KERNEL);
+               if (!fpl)
+                       return -ENOMEM;
+
+               skb = alloc_skb(0, GFP_KERNEL);
+               if (!skb) {
+                       kfree(fpl);
+                       return -ENOMEM;
+               }
+
+               fpl->user = get_uid(current_user());
+               fpl->max = SCM_MAX_FD;
+               fpl->count = 0;
+
+               UNIXCB(skb).fp = fpl;
+               skb->sk = sk;
+               skb->destructor = unix_destruct_scm;
+               refcount_add(skb->truesize, &sk->sk_wmem_alloc);
+       }
+
+       fpl = UNIXCB(skb).fp;
+       fpl->fp[fpl->count++] = get_file(file);
+       unix_inflight(fpl->user, file);
+       skb_queue_head(head, skb);
+       fput(file);
+#endif
+       return 0;
+}
+
+static void io_rsrc_file_put(struct io_ring_ctx *ctx, struct io_rsrc_put *prsrc)
+{
+       struct file *file = prsrc->file;
+#if defined(CONFIG_UNIX)
+       struct sock *sock = ctx->ring_sock->sk;
+       struct sk_buff_head list, *head = &sock->sk_receive_queue;
+       struct sk_buff *skb;
+       int i;
+
+       if (!io_file_need_scm(file)) {
+               fput(file);
+               return;
+       }
+
+       __skb_queue_head_init(&list);
+
+       /*
+        * Find the skb that holds this file in its SCM_RIGHTS. When found,
+        * remove this entry and rearrange the file array.
+        */
+       skb = skb_dequeue(head);
+       while (skb) {
+               struct scm_fp_list *fp;
+
+               fp = UNIXCB(skb).fp;
+               for (i = 0; i < fp->count; i++) {
+                       int left;
+
+                       if (fp->fp[i] != file)
+                               continue;
+
+                       unix_notinflight(fp->user, fp->fp[i]);
+                       left = fp->count - 1 - i;
+                       if (left) {
+                               memmove(&fp->fp[i], &fp->fp[i + 1],
+                                               left * sizeof(struct file *));
+                       }
+                       fp->count--;
+                       if (!fp->count) {
+                               kfree_skb(skb);
+                               skb = NULL;
+                       } else {
+                               __skb_queue_tail(&list, skb);
+                       }
+                       fput(file);
+                       file = NULL;
+                       break;
+               }
+
+               if (!file)
+                       break;
+
+               __skb_queue_tail(&list, skb);
+
+               skb = skb_dequeue(head);
+       }
+
+       if (skb_peek(&list)) {
+               spin_lock_irq(&head->lock);
+               while ((skb = __skb_dequeue(&list)) != NULL)
+                       __skb_queue_tail(head, skb);
+               spin_unlock_irq(&head->lock);
+       }
+#else
+       fput(file);
+#endif
+}
+
+int io_sqe_files_register(struct io_ring_ctx *ctx, void __user *arg,
+                         unsigned nr_args, u64 __user *tags)
+{
+       __s32 __user *fds = (__s32 __user *) arg;
+       struct file *file;
+       int fd, ret;
+       unsigned i;
+
+       if (ctx->file_data)
+               return -EBUSY;
+       if (!nr_args)
+               return -EINVAL;
+       if (nr_args > IORING_MAX_FIXED_FILES)
+               return -EMFILE;
+       if (nr_args > rlimit(RLIMIT_NOFILE))
+               return -EMFILE;
+       ret = io_rsrc_node_switch_start(ctx);
+       if (ret)
+               return ret;
+       ret = io_rsrc_data_alloc(ctx, io_rsrc_file_put, tags, nr_args,
+                                &ctx->file_data);
+       if (ret)
+               return ret;
+
+       if (!io_alloc_file_tables(&ctx->file_table, nr_args)) {
+               io_rsrc_data_free(ctx->file_data);
+               ctx->file_data = NULL;
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < nr_args; i++, ctx->nr_user_files++) {
+               struct io_fixed_file *file_slot;
+
+               if (fds && copy_from_user(&fd, &fds[i], sizeof(fd))) {
+                       ret = -EFAULT;
+                       goto fail;
+               }
+               /* allow sparse sets */
+               if (!fds || fd == -1) {
+                       ret = -EINVAL;
+                       if (unlikely(*io_get_tag_slot(ctx->file_data, i)))
+                               goto fail;
+                       continue;
+               }
+
+               file = fget(fd);
+               ret = -EBADF;
+               if (unlikely(!file))
+                       goto fail;
+
+               /*
+                * Don't allow io_uring instances to be registered. If UNIX
+                * isn't enabled, then this causes a reference cycle and this
+                * instance can never get freed. If UNIX is enabled we'll
+                * handle it just fine, but there's still no point in allowing
+                * a ring fd as it doesn't support regular read/write anyway.
+                */
+               if (io_is_uring_fops(file)) {
+                       fput(file);
+                       goto fail;
+               }
+               ret = io_scm_file_account(ctx, file);
+               if (ret) {
+                       fput(file);
+                       goto fail;
+               }
+               file_slot = io_fixed_file_slot(&ctx->file_table, i);
+               io_fixed_file_set(file_slot, file);
+               io_file_bitmap_set(&ctx->file_table, i);
+       }
+
+       /* default it to the whole table */
+       io_file_table_set_alloc_range(ctx, 0, ctx->nr_user_files);
+       io_rsrc_node_switch(ctx, NULL);
+       return 0;
+fail:
+       __io_sqe_files_unregister(ctx);
+       return ret;
+}
+
+static void io_rsrc_buf_put(struct io_ring_ctx *ctx, struct io_rsrc_put *prsrc)
+{
+       io_buffer_unmap(ctx, &prsrc->buf);
+       prsrc->buf = NULL;
+}
+
+void __io_sqe_buffers_unregister(struct io_ring_ctx *ctx)
+{
+       unsigned int i;
+
+       for (i = 0; i < ctx->nr_user_bufs; i++)
+               io_buffer_unmap(ctx, &ctx->user_bufs[i]);
+       kfree(ctx->user_bufs);
+       io_rsrc_data_free(ctx->buf_data);
+       ctx->user_bufs = NULL;
+       ctx->buf_data = NULL;
+       ctx->nr_user_bufs = 0;
+}
+
+int io_sqe_buffers_unregister(struct io_ring_ctx *ctx)
+{
+       unsigned nr = ctx->nr_user_bufs;
+       int ret;
+
+       if (!ctx->buf_data)
+               return -ENXIO;
+
+       /*
+        * Quiesce may unlock ->uring_lock, and while it's not held
+        * prevent new requests using the table.
+        */
+       ctx->nr_user_bufs = 0;
+       ret = io_rsrc_ref_quiesce(ctx->buf_data, ctx);
+       ctx->nr_user_bufs = nr;
+       if (!ret)
+               __io_sqe_buffers_unregister(ctx);
+       return ret;
+}
+
+/*
+ * Not super efficient, but this is just a registration time. And we do cache
+ * the last compound head, so generally we'll only do a full search if we don't
+ * match that one.
+ *
+ * We check if the given compound head page has already been accounted, to
+ * avoid double accounting it. This allows us to account the full size of the
+ * page, not just the constituent pages of a huge page.
+ */
+static bool headpage_already_acct(struct io_ring_ctx *ctx, struct page **pages,
+                                 int nr_pages, struct page *hpage)
+{
+       int i, j;
+
+       /* check current page array */
+       for (i = 0; i < nr_pages; i++) {
+               if (!PageCompound(pages[i]))
+                       continue;
+               if (compound_head(pages[i]) == hpage)
+                       return true;
+       }
+
+       /* check previously registered pages */
+       for (i = 0; i < ctx->nr_user_bufs; i++) {
+               struct io_mapped_ubuf *imu = ctx->user_bufs[i];
+
+               for (j = 0; j < imu->nr_bvecs; j++) {
+                       if (!PageCompound(imu->bvec[j].bv_page))
+                               continue;
+                       if (compound_head(imu->bvec[j].bv_page) == hpage)
+                               return true;
+               }
+       }
+
+       return false;
+}
+
+static int io_buffer_account_pin(struct io_ring_ctx *ctx, struct page **pages,
+                                int nr_pages, struct io_mapped_ubuf *imu,
+                                struct page **last_hpage)
+{
+       int i, ret;
+
+       imu->acct_pages = 0;
+       for (i = 0; i < nr_pages; i++) {
+               if (!PageCompound(pages[i])) {
+                       imu->acct_pages++;
+               } else {
+                       struct page *hpage;
+
+                       hpage = compound_head(pages[i]);
+                       if (hpage == *last_hpage)
+                               continue;
+                       *last_hpage = hpage;
+                       if (headpage_already_acct(ctx, pages, i, hpage))
+                               continue;
+                       imu->acct_pages += page_size(hpage) >> PAGE_SHIFT;
+               }
+       }
+
+       if (!imu->acct_pages)
+               return 0;
+
+       ret = io_account_mem(ctx, imu->acct_pages);
+       if (ret)
+               imu->acct_pages = 0;
+       return ret;
+}
+
+struct page **io_pin_pages(unsigned long ubuf, unsigned long len, int *npages)
+{
+       unsigned long start, end, nr_pages;
+       struct vm_area_struct **vmas = NULL;
+       struct page **pages = NULL;
+       int i, pret, ret = -ENOMEM;
+
+       end = (ubuf + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       start = ubuf >> PAGE_SHIFT;
+       nr_pages = end - start;
+
+       pages = kvmalloc_array(nr_pages, sizeof(struct page *), GFP_KERNEL);
+       if (!pages)
+               goto done;
+
+       vmas = kvmalloc_array(nr_pages, sizeof(struct vm_area_struct *),
+                             GFP_KERNEL);
+       if (!vmas)
+               goto done;
+
+       ret = 0;
+       mmap_read_lock(current->mm);
+       pret = pin_user_pages(ubuf, nr_pages, FOLL_WRITE | FOLL_LONGTERM,
+                             pages, vmas);
+       if (pret == nr_pages) {
+               /* don't support file backed memory */
+               for (i = 0; i < nr_pages; i++) {
+                       struct vm_area_struct *vma = vmas[i];
+
+                       if (vma_is_shmem(vma))
+                               continue;
+                       if (vma->vm_file &&
+                           !is_file_hugepages(vma->vm_file)) {
+                               ret = -EOPNOTSUPP;
+                               break;
+                       }
+               }
+               *npages = nr_pages;
+       } else {
+               ret = pret < 0 ? pret : -EFAULT;
+       }
+       mmap_read_unlock(current->mm);
+       if (ret) {
+               /*
+                * if we did partial map, or found file backed vmas,
+                * release any pages we did get
+                */
+               if (pret > 0)
+                       unpin_user_pages(pages, pret);
+               goto done;
+       }
+       ret = 0;
+done:
+       kvfree(vmas);
+       if (ret < 0) {
+               kvfree(pages);
+               pages = ERR_PTR(ret);
+       }
+       return pages;
+}
+
+static int io_sqe_buffer_register(struct io_ring_ctx *ctx, struct iovec *iov,
+                                 struct io_mapped_ubuf **pimu,
+                                 struct page **last_hpage)
+{
+       struct io_mapped_ubuf *imu = NULL;
+       struct page **pages = NULL;
+       unsigned long off;
+       size_t size;
+       int ret, nr_pages, i;
+
+       *pimu = ctx->dummy_ubuf;
+       if (!iov->iov_base)
+               return 0;
+
+       ret = -ENOMEM;
+       pages = io_pin_pages((unsigned long) iov->iov_base, iov->iov_len,
+                               &nr_pages);
+       if (IS_ERR(pages)) {
+               ret = PTR_ERR(pages);
+               pages = NULL;
+               goto done;
+       }
+
+       imu = kvmalloc(struct_size(imu, bvec, nr_pages), GFP_KERNEL);
+       if (!imu)
+               goto done;
+
+       ret = io_buffer_account_pin(ctx, pages, nr_pages, imu, last_hpage);
+       if (ret) {
+               unpin_user_pages(pages, nr_pages);
+               goto done;
+       }
+
+       off = (unsigned long) iov->iov_base & ~PAGE_MASK;
+       size = iov->iov_len;
+       for (i = 0; i < nr_pages; i++) {
+               size_t vec_len;
+
+               vec_len = min_t(size_t, size, PAGE_SIZE - off);
+               imu->bvec[i].bv_page = pages[i];
+               imu->bvec[i].bv_len = vec_len;
+               imu->bvec[i].bv_offset = off;
+               off = 0;
+               size -= vec_len;
+       }
+       /* store original address for later verification */
+       imu->ubuf = (unsigned long) iov->iov_base;
+       imu->ubuf_end = imu->ubuf + iov->iov_len;
+       imu->nr_bvecs = nr_pages;
+       *pimu = imu;
+       ret = 0;
+done:
+       if (ret)
+               kvfree(imu);
+       kvfree(pages);
+       return ret;
+}
+
+static int io_buffers_map_alloc(struct io_ring_ctx *ctx, unsigned int nr_args)
+{
+       ctx->user_bufs = kcalloc(nr_args, sizeof(*ctx->user_bufs), GFP_KERNEL);
+       return ctx->user_bufs ? 0 : -ENOMEM;
+}
+
+int io_sqe_buffers_register(struct io_ring_ctx *ctx, void __user *arg,
+                           unsigned int nr_args, u64 __user *tags)
+{
+       struct page *last_hpage = NULL;
+       struct io_rsrc_data *data;
+       int i, ret;
+       struct iovec iov;
+
+       BUILD_BUG_ON(IORING_MAX_REG_BUFFERS >= (1u << 16));
+
+       if (ctx->user_bufs)
+               return -EBUSY;
+       if (!nr_args || nr_args > IORING_MAX_REG_BUFFERS)
+               return -EINVAL;
+       ret = io_rsrc_node_switch_start(ctx);
+       if (ret)
+               return ret;
+       ret = io_rsrc_data_alloc(ctx, io_rsrc_buf_put, tags, nr_args, &data);
+       if (ret)
+               return ret;
+       ret = io_buffers_map_alloc(ctx, nr_args);
+       if (ret) {
+               io_rsrc_data_free(data);
+               return ret;
+       }
+
+       for (i = 0; i < nr_args; i++, ctx->nr_user_bufs++) {
+               if (arg) {
+                       ret = io_copy_iov(ctx, &iov, arg, i);
+                       if (ret)
+                               break;
+                       ret = io_buffer_validate(&iov);
+                       if (ret)
+                               break;
+               } else {
+                       memset(&iov, 0, sizeof(iov));
+               }
+
+               if (!iov.iov_base && *io_get_tag_slot(data, i)) {
+                       ret = -EINVAL;
+                       break;
+               }
+
+               ret = io_sqe_buffer_register(ctx, &iov, &ctx->user_bufs[i],
+                                            &last_hpage);
+               if (ret)
+                       break;
+       }
+
+       WARN_ON_ONCE(ctx->buf_data);
+
+       ctx->buf_data = data;
+       if (ret)
+               __io_sqe_buffers_unregister(ctx);
+       else
+               io_rsrc_node_switch(ctx, NULL);
+       return ret;
+}
+
+int io_import_fixed(int ddir, struct iov_iter *iter,
+                          struct io_mapped_ubuf *imu,
+                          u64 buf_addr, size_t len)
+{
+       u64 buf_end;
+       size_t offset;
+
+       if (WARN_ON_ONCE(!imu))
+               return -EFAULT;
+       if (unlikely(check_add_overflow(buf_addr, (u64)len, &buf_end)))
+               return -EFAULT;
+       /* not inside the mapped region */
+       if (unlikely(buf_addr < imu->ubuf || buf_end > imu->ubuf_end))
+               return -EFAULT;
+
+       /*
+        * May not be a start of buffer, set size appropriately
+        * and advance us to the beginning.
+        */
+       offset = buf_addr - imu->ubuf;
+       iov_iter_bvec(iter, ddir, imu->bvec, imu->nr_bvecs, offset + len);
+
+       if (offset) {
+               /*
+                * Don't use iov_iter_advance() here, as it's really slow for
+                * using the latter parts of a big fixed buffer - it iterates
+                * over each segment manually. We can cheat a bit here, because
+                * we know that:
+                *
+                * 1) it's a BVEC iter, we set it up
+                * 2) all bvecs are PAGE_SIZE in size, except potentially the
+                *    first and last bvec
+                *
+                * So just find our index, and adjust the iterator afterwards.
+                * If the offset is within the first bvec (or the whole first
+                * bvec, just use iov_iter_advance(). This makes it easier
+                * since we can just skip the first segment, which may not
+                * be PAGE_SIZE aligned.
+                */
+               const struct bio_vec *bvec = imu->bvec;
+
+               if (offset <= bvec->bv_len) {
+                       iov_iter_advance(iter, offset);
+               } else {
+                       unsigned long seg_skip;
+
+                       /* skip first vec */
+                       offset -= bvec->bv_len;
+                       seg_skip = 1 + (offset >> PAGE_SHIFT);
+
+                       iter->bvec = bvec + seg_skip;
+                       iter->nr_segs -= seg_skip;
+                       iter->count -= bvec->bv_len + offset;
+                       iter->iov_offset = offset & ~PAGE_MASK;
+               }
+       }
+
+       return 0;
+}
diff --git a/io_uring/rsrc.h b/io_uring/rsrc.h
new file mode 100644 (file)
index 0000000..f3a9a17
--- /dev/null
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: GPL-2.0
+#ifndef IOU_RSRC_H
+#define IOU_RSRC_H
+
+#include <net/af_unix.h>
+
+#define IO_RSRC_TAG_TABLE_SHIFT        (PAGE_SHIFT - 3)
+#define IO_RSRC_TAG_TABLE_MAX  (1U << IO_RSRC_TAG_TABLE_SHIFT)
+#define IO_RSRC_TAG_TABLE_MASK (IO_RSRC_TAG_TABLE_MAX - 1)
+
+enum {
+       IORING_RSRC_FILE                = 0,
+       IORING_RSRC_BUFFER              = 1,
+};
+
+struct io_rsrc_put {
+       struct list_head list;
+       u64 tag;
+       union {
+               void *rsrc;
+               struct file *file;
+               struct io_mapped_ubuf *buf;
+       };
+};
+
+typedef void (rsrc_put_fn)(struct io_ring_ctx *ctx, struct io_rsrc_put *prsrc);
+
+struct io_rsrc_data {
+       struct io_ring_ctx              *ctx;
+
+       u64                             **tags;
+       unsigned int                    nr;
+       rsrc_put_fn                     *do_put;
+       atomic_t                        refs;
+       struct completion               done;
+       bool                            quiesce;
+};
+
+struct io_rsrc_node {
+       struct percpu_ref               refs;
+       struct list_head                node;
+       struct list_head                rsrc_list;
+       struct io_rsrc_data             *rsrc_data;
+       struct llist_node               llist;
+       bool                            done;
+};
+
+struct io_mapped_ubuf {
+       u64             ubuf;
+       u64             ubuf_end;
+       unsigned int    nr_bvecs;
+       unsigned long   acct_pages;
+       struct bio_vec  bvec[];
+};
+
+void io_rsrc_put_work(struct work_struct *work);
+void io_rsrc_refs_refill(struct io_ring_ctx *ctx);
+void io_wait_rsrc_data(struct io_rsrc_data *data);
+void io_rsrc_node_destroy(struct io_rsrc_node *ref_node);
+void io_rsrc_refs_drop(struct io_ring_ctx *ctx);
+int io_rsrc_node_switch_start(struct io_ring_ctx *ctx);
+int io_queue_rsrc_removal(struct io_rsrc_data *data, unsigned idx,
+                         struct io_rsrc_node *node, void *rsrc);
+void io_rsrc_node_switch(struct io_ring_ctx *ctx,
+                        struct io_rsrc_data *data_to_kill);
+
+int io_import_fixed(int ddir, struct iov_iter *iter,
+                          struct io_mapped_ubuf *imu,
+                          u64 buf_addr, size_t len);
+
+void __io_sqe_buffers_unregister(struct io_ring_ctx *ctx);
+int io_sqe_buffers_unregister(struct io_ring_ctx *ctx);
+int io_sqe_buffers_register(struct io_ring_ctx *ctx, void __user *arg,
+                           unsigned int nr_args, u64 __user *tags);
+void __io_sqe_files_unregister(struct io_ring_ctx *ctx);
+int io_sqe_files_unregister(struct io_ring_ctx *ctx);
+int io_sqe_files_register(struct io_ring_ctx *ctx, void __user *arg,
+                         unsigned nr_args, u64 __user *tags);
+
+int __io_scm_file_account(struct io_ring_ctx *ctx, struct file *file);
+
+#if defined(CONFIG_UNIX)
+static inline bool io_file_need_scm(struct file *filp)
+{
+#if defined(IO_URING_SCM_ALL)
+       return true;
+#else
+       return !!unix_get_socket(filp);
+#endif
+}
+#else
+static inline bool io_file_need_scm(struct file *filp)
+{
+       return false;
+}
+#endif
+
+static inline int io_scm_file_account(struct io_ring_ctx *ctx,
+                                     struct file *file)
+{
+       if (likely(!io_file_need_scm(file)))
+               return 0;
+       return __io_scm_file_account(ctx, file);
+}
+
+int io_register_files_update(struct io_ring_ctx *ctx, void __user *arg,
+                            unsigned nr_args);
+int io_register_rsrc_update(struct io_ring_ctx *ctx, void __user *arg,
+                           unsigned size, unsigned type);
+int io_register_rsrc(struct io_ring_ctx *ctx, void __user *arg,
+                       unsigned int size, unsigned int type);
+
+static inline void io_rsrc_put_node(struct io_rsrc_node *node, int nr)
+{
+       percpu_ref_put_many(&node->refs, nr);
+}
+
+static inline void io_req_put_rsrc(struct io_kiocb *req)
+{
+       if (req->rsrc_node)
+               io_rsrc_put_node(req->rsrc_node, 1);
+}
+
+static inline void io_req_put_rsrc_locked(struct io_kiocb *req,
+                                         struct io_ring_ctx *ctx)
+       __must_hold(&ctx->uring_lock)
+{
+       struct io_rsrc_node *node = req->rsrc_node;
+
+       if (node) {
+               if (node == ctx->rsrc_node)
+                       ctx->rsrc_cached_refs++;
+               else
+                       io_rsrc_put_node(node, 1);
+       }
+}
+
+static inline void io_charge_rsrc_node(struct io_ring_ctx *ctx)
+{
+       ctx->rsrc_cached_refs--;
+       if (unlikely(ctx->rsrc_cached_refs < 0))
+               io_rsrc_refs_refill(ctx);
+}
+
+static inline void io_req_set_rsrc_node(struct io_kiocb *req,
+                                       struct io_ring_ctx *ctx,
+                                       unsigned int issue_flags)
+{
+       if (!req->rsrc_node) {
+               req->rsrc_node = ctx->rsrc_node;
+
+               if (!(issue_flags & IO_URING_F_UNLOCKED)) {
+                       lockdep_assert_held(&ctx->uring_lock);
+
+                       io_charge_rsrc_node(ctx);
+               } else {
+                       percpu_ref_get(&req->rsrc_node->refs);
+               }
+       }
+}
+
+static inline u64 *io_get_tag_slot(struct io_rsrc_data *data, unsigned int idx)
+{
+       unsigned int off = idx & IO_RSRC_TAG_TABLE_MASK;
+       unsigned int table_idx = idx >> IO_RSRC_TAG_TABLE_SHIFT;
+
+       return &data->tags[table_idx][off];
+}
+
+int io_rsrc_update(struct io_kiocb *req, unsigned int issue_flags);
+int io_rsrc_update_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+
+int __io_account_mem(struct user_struct *user, unsigned long nr_pages);
+
+static inline void __io_unaccount_mem(struct user_struct *user,
+                                     unsigned long nr_pages)
+{
+       atomic_long_sub(nr_pages, &user->locked_vm);
+}
+
+#endif
diff --git a/io_uring/rw.c b/io_uring/rw.c
new file mode 100644 (file)
index 0000000..2b78479
--- /dev/null
@@ -0,0 +1,1049 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/blk-mq.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/fsnotify.h>
+#include <linux/poll.h>
+#include <linux/nospec.h>
+#include <linux/compat.h>
+#include <linux/io_uring.h>
+
+#include <uapi/linux/io_uring.h>
+
+#include "io_uring.h"
+#include "opdef.h"
+#include "kbuf.h"
+#include "rsrc.h"
+#include "rw.h"
+
+struct io_rw {
+       /* NOTE: kiocb has the file as the first member, so don't do it here */
+       struct kiocb                    kiocb;
+       u64                             addr;
+       u32                             len;
+       rwf_t                           flags;
+};
+
+static inline bool io_file_supports_nowait(struct io_kiocb *req)
+{
+       return req->flags & REQ_F_SUPPORT_NOWAIT;
+}
+
+int io_prep_rw(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_rw *rw = io_kiocb_to_cmd(req);
+       unsigned ioprio;
+       int ret;
+
+       rw->kiocb.ki_pos = READ_ONCE(sqe->off);
+       /* used for fixed read/write too - just read unconditionally */
+       req->buf_index = READ_ONCE(sqe->buf_index);
+
+       if (req->opcode == IORING_OP_READ_FIXED ||
+           req->opcode == IORING_OP_WRITE_FIXED) {
+               struct io_ring_ctx *ctx = req->ctx;
+               u16 index;
+
+               if (unlikely(req->buf_index >= ctx->nr_user_bufs))
+                       return -EFAULT;
+               index = array_index_nospec(req->buf_index, ctx->nr_user_bufs);
+               req->imu = ctx->user_bufs[index];
+               io_req_set_rsrc_node(req, ctx, 0);
+       }
+
+       ioprio = READ_ONCE(sqe->ioprio);
+       if (ioprio) {
+               ret = ioprio_check_cap(ioprio);
+               if (ret)
+                       return ret;
+
+               rw->kiocb.ki_ioprio = ioprio;
+       } else {
+               rw->kiocb.ki_ioprio = get_current_ioprio();
+       }
+
+       rw->addr = READ_ONCE(sqe->addr);
+       rw->len = READ_ONCE(sqe->len);
+       rw->flags = READ_ONCE(sqe->rw_flags);
+       return 0;
+}
+
+void io_readv_writev_cleanup(struct io_kiocb *req)
+{
+       struct io_async_rw *io = req->async_data;
+
+       kfree(io->free_iovec);
+}
+
+static inline void io_rw_done(struct kiocb *kiocb, ssize_t ret)
+{
+       switch (ret) {
+       case -EIOCBQUEUED:
+               break;
+       case -ERESTARTSYS:
+       case -ERESTARTNOINTR:
+       case -ERESTARTNOHAND:
+       case -ERESTART_RESTARTBLOCK:
+               /*
+                * We can't just restart the syscall, since previously
+                * submitted sqes may already be in progress. Just fail this
+                * IO with EINTR.
+                */
+               ret = -EINTR;
+               fallthrough;
+       default:
+               kiocb->ki_complete(kiocb, ret);
+       }
+}
+
+static inline loff_t *io_kiocb_update_pos(struct io_kiocb *req)
+{
+       struct io_rw *rw = io_kiocb_to_cmd(req);
+
+       if (rw->kiocb.ki_pos != -1)
+               return &rw->kiocb.ki_pos;
+
+       if (!(req->file->f_mode & FMODE_STREAM)) {
+               req->flags |= REQ_F_CUR_POS;
+               rw->kiocb.ki_pos = req->file->f_pos;
+               return &rw->kiocb.ki_pos;
+       }
+
+       rw->kiocb.ki_pos = 0;
+       return NULL;
+}
+
+static void io_req_task_queue_reissue(struct io_kiocb *req)
+{
+       req->io_task_work.func = io_queue_iowq;
+       io_req_task_work_add(req);
+}
+
+#ifdef CONFIG_BLOCK
+static bool io_resubmit_prep(struct io_kiocb *req)
+{
+       struct io_async_rw *io = req->async_data;
+
+       if (!req_has_async_data(req))
+               return !io_req_prep_async(req);
+       iov_iter_restore(&io->s.iter, &io->s.iter_state);
+       return true;
+}
+
+static bool io_rw_should_reissue(struct io_kiocb *req)
+{
+       umode_t mode = file_inode(req->file)->i_mode;
+       struct io_ring_ctx *ctx = req->ctx;
+
+       if (!S_ISBLK(mode) && !S_ISREG(mode))
+               return false;
+       if ((req->flags & REQ_F_NOWAIT) || (io_wq_current_is_worker() &&
+           !(ctx->flags & IORING_SETUP_IOPOLL)))
+               return false;
+       /*
+        * If ref is dying, we might be running poll reap from the exit work.
+        * Don't attempt to reissue from that path, just let it fail with
+        * -EAGAIN.
+        */
+       if (percpu_ref_is_dying(&ctx->refs))
+               return false;
+       /*
+        * Play it safe and assume not safe to re-import and reissue if we're
+        * not in the original thread group (or in task context).
+        */
+       if (!same_thread_group(req->task, current) || !in_task())
+               return false;
+       return true;
+}
+#else
+static bool io_resubmit_prep(struct io_kiocb *req)
+{
+       return false;
+}
+static bool io_rw_should_reissue(struct io_kiocb *req)
+{
+       return false;
+}
+#endif
+
+static void kiocb_end_write(struct io_kiocb *req)
+{
+       /*
+        * Tell lockdep we inherited freeze protection from submission
+        * thread.
+        */
+       if (req->flags & REQ_F_ISREG) {
+               struct super_block *sb = file_inode(req->file)->i_sb;
+
+               __sb_writers_acquired(sb, SB_FREEZE_WRITE);
+               sb_end_write(sb);
+       }
+}
+
+static bool __io_complete_rw_common(struct io_kiocb *req, long res)
+{
+       struct io_rw *rw = io_kiocb_to_cmd(req);
+
+       if (rw->kiocb.ki_flags & IOCB_WRITE) {
+               kiocb_end_write(req);
+               fsnotify_modify(req->file);
+       } else {
+               fsnotify_access(req->file);
+       }
+       if (unlikely(res != req->cqe.res)) {
+               if ((res == -EAGAIN || res == -EOPNOTSUPP) &&
+                   io_rw_should_reissue(req)) {
+                       req->flags |= REQ_F_REISSUE | REQ_F_PARTIAL_IO;
+                       return true;
+               }
+               req_set_fail(req);
+               req->cqe.res = res;
+       }
+       return false;
+}
+
+static void io_complete_rw(struct kiocb *kiocb, long res)
+{
+       struct io_rw *rw = container_of(kiocb, struct io_rw, kiocb);
+       struct io_kiocb *req = cmd_to_io_kiocb(rw);
+
+       if (__io_complete_rw_common(req, res))
+               return;
+       io_req_set_res(req, res, 0);
+       req->io_task_work.func = io_req_task_complete;
+       io_req_task_work_add(req);
+}
+
+static void io_complete_rw_iopoll(struct kiocb *kiocb, long res)
+{
+       struct io_rw *rw = container_of(kiocb, struct io_rw, kiocb);
+       struct io_kiocb *req = cmd_to_io_kiocb(rw);
+
+       if (kiocb->ki_flags & IOCB_WRITE)
+               kiocb_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;
+                       return;
+               }
+               req->cqe.res = res;
+       }
+
+       /* order with io_iopoll_complete() checking ->iopoll_completed */
+       smp_store_release(&req->iopoll_completed, 1);
+}
+
+static int kiocb_done(struct io_kiocb *req, ssize_t ret,
+                      unsigned int issue_flags)
+{
+       struct io_async_rw *io = req->async_data;
+       struct io_rw *rw = io_kiocb_to_cmd(req);
+
+       /* add previously done IO, if any */
+       if (req_has_async_data(req) && io->bytes_done > 0) {
+               if (ret < 0)
+                       ret = io->bytes_done;
+               else
+                       ret += io->bytes_done;
+       }
+
+       if (req->flags & REQ_F_CUR_POS)
+               req->file->f_pos = rw->kiocb.ki_pos;
+       if (ret >= 0 && (rw->kiocb.ki_complete == io_complete_rw)) {
+               if (!__io_complete_rw_common(req, ret)) {
+                       io_req_set_res(req, req->cqe.res,
+                                      io_put_kbuf(req, issue_flags));
+                       return IOU_OK;
+               }
+       } else {
+               io_rw_done(&rw->kiocb, ret);
+       }
+
+       if (req->flags & REQ_F_REISSUE) {
+               req->flags &= ~REQ_F_REISSUE;
+               if (io_resubmit_prep(req))
+                       io_req_task_queue_reissue(req);
+               else
+                       io_req_task_queue_fail(req, ret);
+       }
+       return IOU_ISSUE_SKIP_COMPLETE;
+}
+
+#ifdef CONFIG_COMPAT
+static ssize_t io_compat_import(struct io_kiocb *req, struct iovec *iov,
+                               unsigned int issue_flags)
+{
+       struct io_rw *rw = io_kiocb_to_cmd(req);
+       struct compat_iovec __user *uiov;
+       compat_ssize_t clen;
+       void __user *buf;
+       size_t len;
+
+       uiov = u64_to_user_ptr(rw->addr);
+       if (!access_ok(uiov, sizeof(*uiov)))
+               return -EFAULT;
+       if (__get_user(clen, &uiov->iov_len))
+               return -EFAULT;
+       if (clen < 0)
+               return -EINVAL;
+
+       len = clen;
+       buf = io_buffer_select(req, &len, issue_flags);
+       if (!buf)
+               return -ENOBUFS;
+       rw->addr = (unsigned long) buf;
+       iov[0].iov_base = buf;
+       rw->len = iov[0].iov_len = (compat_size_t) len;
+       return 0;
+}
+#endif
+
+static ssize_t __io_iov_buffer_select(struct io_kiocb *req, struct iovec *iov,
+                                     unsigned int issue_flags)
+{
+       struct io_rw *rw = io_kiocb_to_cmd(req);
+       struct iovec __user *uiov = u64_to_user_ptr(rw->addr);
+       void __user *buf;
+       ssize_t len;
+
+       if (copy_from_user(iov, uiov, sizeof(*uiov)))
+               return -EFAULT;
+
+       len = iov[0].iov_len;
+       if (len < 0)
+               return -EINVAL;
+       buf = io_buffer_select(req, &len, issue_flags);
+       if (!buf)
+               return -ENOBUFS;
+       rw->addr = (unsigned long) buf;
+       iov[0].iov_base = buf;
+       rw->len = iov[0].iov_len = len;
+       return 0;
+}
+
+static ssize_t io_iov_buffer_select(struct io_kiocb *req, struct iovec *iov,
+                                   unsigned int issue_flags)
+{
+       struct io_rw *rw = io_kiocb_to_cmd(req);
+
+       if (req->flags & (REQ_F_BUFFER_SELECTED|REQ_F_BUFFER_RING)) {
+               iov[0].iov_base = u64_to_user_ptr(rw->addr);
+               iov[0].iov_len = rw->len;
+               return 0;
+       }
+       if (rw->len != 1)
+               return -EINVAL;
+
+#ifdef CONFIG_COMPAT
+       if (req->ctx->compat)
+               return io_compat_import(req, iov, issue_flags);
+#endif
+
+       return __io_iov_buffer_select(req, iov, issue_flags);
+}
+
+static struct iovec *__io_import_iovec(int ddir, struct io_kiocb *req,
+                                      struct io_rw_state *s,
+                                      unsigned int issue_flags)
+{
+       struct io_rw *rw = io_kiocb_to_cmd(req);
+       struct iov_iter *iter = &s->iter;
+       u8 opcode = req->opcode;
+       struct iovec *iovec;
+       void __user *buf;
+       size_t sqe_len;
+       ssize_t ret;
+
+       if (opcode == IORING_OP_READ_FIXED || opcode == IORING_OP_WRITE_FIXED) {
+               ret = io_import_fixed(ddir, iter, req->imu, rw->addr, rw->len);
+               if (ret)
+                       return ERR_PTR(ret);
+               return NULL;
+       }
+
+       buf = u64_to_user_ptr(rw->addr);
+       sqe_len = rw->len;
+
+       if (opcode == IORING_OP_READ || opcode == IORING_OP_WRITE) {
+               if (io_do_buffer_select(req)) {
+                       buf = io_buffer_select(req, &sqe_len, issue_flags);
+                       if (!buf)
+                               return ERR_PTR(-ENOBUFS);
+                       rw->addr = (unsigned long) buf;
+                       rw->len = sqe_len;
+               }
+
+               ret = import_single_range(ddir, buf, sqe_len, s->fast_iov, iter);
+               if (ret)
+                       return ERR_PTR(ret);
+               return NULL;
+       }
+
+       iovec = s->fast_iov;
+       if (req->flags & REQ_F_BUFFER_SELECT) {
+               ret = io_iov_buffer_select(req, iovec, issue_flags);
+               if (ret)
+                       return ERR_PTR(ret);
+               iov_iter_init(iter, ddir, iovec, 1, iovec->iov_len);
+               return NULL;
+       }
+
+       ret = __import_iovec(ddir, buf, sqe_len, UIO_FASTIOV, &iovec, iter,
+                             req->ctx->compat);
+       if (unlikely(ret < 0))
+               return ERR_PTR(ret);
+       return iovec;
+}
+
+static inline int io_import_iovec(int rw, struct io_kiocb *req,
+                                 struct iovec **iovec, struct io_rw_state *s,
+                                 unsigned int issue_flags)
+{
+       *iovec = __io_import_iovec(rw, req, s, issue_flags);
+       if (unlikely(IS_ERR(*iovec)))
+               return PTR_ERR(*iovec);
+
+       iov_iter_save_state(&s->iter, &s->iter_state);
+       return 0;
+}
+
+static inline loff_t *io_kiocb_ppos(struct kiocb *kiocb)
+{
+       return (kiocb->ki_filp->f_mode & FMODE_STREAM) ? NULL : &kiocb->ki_pos;
+}
+
+/*
+ * For files that don't have ->read_iter() and ->write_iter(), handle them
+ * by looping over ->read() or ->write() manually.
+ */
+static ssize_t loop_rw_iter(int ddir, struct io_rw *rw, struct iov_iter *iter)
+{
+       struct kiocb *kiocb = &rw->kiocb;
+       struct file *file = kiocb->ki_filp;
+       ssize_t ret = 0;
+       loff_t *ppos;
+
+       /*
+        * Don't support polled IO through this interface, and we can't
+        * support non-blocking either. For the latter, this just causes
+        * the kiocb to be handled from an async context.
+        */
+       if (kiocb->ki_flags & IOCB_HIPRI)
+               return -EOPNOTSUPP;
+       if ((kiocb->ki_flags & IOCB_NOWAIT) &&
+           !(kiocb->ki_filp->f_flags & O_NONBLOCK))
+               return -EAGAIN;
+
+       ppos = io_kiocb_ppos(kiocb);
+
+       while (iov_iter_count(iter)) {
+               struct iovec iovec;
+               ssize_t nr;
+
+               if (!iov_iter_is_bvec(iter)) {
+                       iovec = iov_iter_iovec(iter);
+               } else {
+                       iovec.iov_base = u64_to_user_ptr(rw->addr);
+                       iovec.iov_len = rw->len;
+               }
+
+               if (ddir == READ) {
+                       nr = file->f_op->read(file, iovec.iov_base,
+                                             iovec.iov_len, ppos);
+               } else {
+                       nr = file->f_op->write(file, iovec.iov_base,
+                                              iovec.iov_len, ppos);
+               }
+
+               if (nr < 0) {
+                       if (!ret)
+                               ret = nr;
+                       break;
+               }
+               ret += nr;
+               if (!iov_iter_is_bvec(iter)) {
+                       iov_iter_advance(iter, nr);
+               } else {
+                       rw->addr += nr;
+                       rw->len -= nr;
+                       if (!rw->len)
+                               break;
+               }
+               if (nr != iovec.iov_len)
+                       break;
+       }
+
+       return ret;
+}
+
+static void io_req_map_rw(struct io_kiocb *req, const struct iovec *iovec,
+                         const struct iovec *fast_iov, struct iov_iter *iter)
+{
+       struct io_async_rw *io = req->async_data;
+
+       memcpy(&io->s.iter, iter, sizeof(*iter));
+       io->free_iovec = iovec;
+       io->bytes_done = 0;
+       /* can only be fixed buffers, no need to do anything */
+       if (iov_iter_is_bvec(iter))
+               return;
+       if (!iovec) {
+               unsigned iov_off = 0;
+
+               io->s.iter.iov = io->s.fast_iov;
+               if (iter->iov != fast_iov) {
+                       iov_off = iter->iov - fast_iov;
+                       io->s.iter.iov += iov_off;
+               }
+               if (io->s.fast_iov != fast_iov)
+                       memcpy(io->s.fast_iov + iov_off, fast_iov + iov_off,
+                              sizeof(struct iovec) * iter->nr_segs);
+       } else {
+               req->flags |= REQ_F_NEED_CLEANUP;
+       }
+}
+
+static int io_setup_async_rw(struct io_kiocb *req, const struct iovec *iovec,
+                            struct io_rw_state *s, bool force)
+{
+       if (!force && !io_op_defs[req->opcode].prep_async)
+               return 0;
+       if (!req_has_async_data(req)) {
+               struct io_async_rw *iorw;
+
+               if (io_alloc_async_data(req)) {
+                       kfree(iovec);
+                       return -ENOMEM;
+               }
+
+               io_req_map_rw(req, iovec, s->fast_iov, &s->iter);
+               iorw = req->async_data;
+               /* we've copied and mapped the iter, ensure state is saved */
+               iov_iter_save_state(&iorw->s.iter, &iorw->s.iter_state);
+       }
+       return 0;
+}
+
+static inline int io_rw_prep_async(struct io_kiocb *req, int rw)
+{
+       struct io_async_rw *iorw = req->async_data;
+       struct iovec *iov;
+       int ret;
+
+       /* submission path, ->uring_lock should already be taken */
+       ret = io_import_iovec(rw, req, &iov, &iorw->s, 0);
+       if (unlikely(ret < 0))
+               return ret;
+
+       iorw->bytes_done = 0;
+       iorw->free_iovec = iov;
+       if (iov)
+               req->flags |= REQ_F_NEED_CLEANUP;
+       return 0;
+}
+
+int io_readv_prep_async(struct io_kiocb *req)
+{
+       return io_rw_prep_async(req, READ);
+}
+
+int io_writev_prep_async(struct io_kiocb *req)
+{
+       return io_rw_prep_async(req, WRITE);
+}
+
+/*
+ * This is our waitqueue callback handler, registered through __folio_lock_async()
+ * when we initially tried to do the IO with the iocb armed our waitqueue.
+ * This gets called when the page is unlocked, and we generally expect that to
+ * happen when the page IO is completed and the page is now uptodate. This will
+ * queue a task_work based retry of the operation, attempting to copy the data
+ * again. If the latter fails because the page was NOT uptodate, then we will
+ * do a thread based blocking retry of the operation. That's the unexpected
+ * slow path.
+ */
+static int io_async_buf_func(struct wait_queue_entry *wait, unsigned mode,
+                            int sync, void *arg)
+{
+       struct wait_page_queue *wpq;
+       struct io_kiocb *req = wait->private;
+       struct io_rw *rw = io_kiocb_to_cmd(req);
+       struct wait_page_key *key = arg;
+
+       wpq = container_of(wait, struct wait_page_queue, wait);
+
+       if (!wake_page_match(wpq, key))
+               return 0;
+
+       rw->kiocb.ki_flags &= ~IOCB_WAITQ;
+       list_del_init(&wait->entry);
+       io_req_task_queue(req);
+       return 1;
+}
+
+/*
+ * This controls whether a given IO request should be armed for async page
+ * based retry. If we return false here, the request is handed to the async
+ * worker threads for retry. If we're doing buffered reads on a regular file,
+ * we prepare a private wait_page_queue entry and retry the operation. This
+ * will either succeed because the page is now uptodate and unlocked, or it
+ * will register a callback when the page is unlocked at IO completion. Through
+ * that callback, io_uring uses task_work to setup a retry of the operation.
+ * That retry will attempt the buffered read again. The retry will generally
+ * succeed, or in rare cases where it fails, we then fall back to using the
+ * async worker threads for a blocking retry.
+ */
+static bool io_rw_should_retry(struct io_kiocb *req)
+{
+       struct io_async_rw *io = req->async_data;
+       struct wait_page_queue *wait = &io->wpq;
+       struct io_rw *rw = io_kiocb_to_cmd(req);
+       struct kiocb *kiocb = &rw->kiocb;
+
+       /* never retry for NOWAIT, we just complete with -EAGAIN */
+       if (req->flags & REQ_F_NOWAIT)
+               return false;
+
+       /* Only for buffered IO */
+       if (kiocb->ki_flags & (IOCB_DIRECT | IOCB_HIPRI))
+               return false;
+
+       /*
+        * 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))
+               return false;
+
+       wait->wait.func = io_async_buf_func;
+       wait->wait.private = req;
+       wait->wait.flags = 0;
+       INIT_LIST_HEAD(&wait->wait.entry);
+       kiocb->ki_flags |= IOCB_WAITQ;
+       kiocb->ki_flags &= ~IOCB_NOWAIT;
+       kiocb->ki_waitq = wait;
+       return true;
+}
+
+static inline int io_iter_do_read(struct io_rw *rw, struct iov_iter *iter)
+{
+       struct file *file = rw->kiocb.ki_filp;
+
+       if (likely(file->f_op->read_iter))
+               return call_read_iter(file, &rw->kiocb, iter);
+       else if (file->f_op->read)
+               return loop_rw_iter(READ, rw, iter);
+       else
+               return -EINVAL;
+}
+
+static bool need_complete_io(struct io_kiocb *req)
+{
+       return req->flags & REQ_F_ISREG ||
+               S_ISBLK(file_inode(req->file)->i_mode);
+}
+
+static int io_rw_init_file(struct io_kiocb *req, fmode_t mode)
+{
+       struct io_rw *rw = io_kiocb_to_cmd(req);
+       struct kiocb *kiocb = &rw->kiocb;
+       struct io_ring_ctx *ctx = req->ctx;
+       struct file *file = req->file;
+       int ret;
+
+       if (unlikely(!file || !(file->f_mode & mode)))
+               return -EBADF;
+
+       if (!io_req_ffs_set(req))
+               req->flags |= io_file_get_flags(file) << REQ_F_SUPPORT_NOWAIT_BIT;
+
+       kiocb->ki_flags = iocb_flags(file);
+       ret = kiocb_set_rw_flags(kiocb, rw->flags);
+       if (unlikely(ret))
+               return ret;
+
+       /*
+        * If the file is marked O_NONBLOCK, still allow retry for it if it
+        * supports async. Otherwise it's impossible to use O_NONBLOCK files
+        * reliably. If not, or it IOCB_NOWAIT is set, don't retry.
+        */
+       if ((kiocb->ki_flags & IOCB_NOWAIT) ||
+           ((file->f_flags & O_NONBLOCK) && !io_file_supports_nowait(req)))
+               req->flags |= REQ_F_NOWAIT;
+
+       if (ctx->flags & IORING_SETUP_IOPOLL) {
+               if (!(kiocb->ki_flags & IOCB_DIRECT) || !file->f_op->iopoll)
+                       return -EOPNOTSUPP;
+
+               kiocb->private = NULL;
+               kiocb->ki_flags |= IOCB_HIPRI | IOCB_ALLOC_CACHE;
+               kiocb->ki_complete = io_complete_rw_iopoll;
+               req->iopoll_completed = 0;
+       } else {
+               if (kiocb->ki_flags & IOCB_HIPRI)
+                       return -EINVAL;
+               kiocb->ki_complete = io_complete_rw;
+       }
+
+       return 0;
+}
+
+int io_read(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_rw *rw = io_kiocb_to_cmd(req);
+       struct io_rw_state __s, *s = &__s;
+       struct iovec *iovec;
+       struct kiocb *kiocb = &rw->kiocb;
+       bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK;
+       struct io_async_rw *io;
+       ssize_t ret, ret2;
+       loff_t *ppos;
+
+       if (!req_has_async_data(req)) {
+               ret = io_import_iovec(READ, req, &iovec, s, issue_flags);
+               if (unlikely(ret < 0))
+                       return ret;
+       } else {
+               io = req->async_data;
+               s = &io->s;
+
+               /*
+                * Safe and required to re-import if we're using provided
+                * buffers, as we dropped the selected one before retry.
+                */
+               if (io_do_buffer_select(req)) {
+                       ret = io_import_iovec(READ, req, &iovec, s, issue_flags);
+                       if (unlikely(ret < 0))
+                               return ret;
+               }
+
+               /*
+                * We come here from an earlier attempt, restore our state to
+                * match in case it doesn't. It's cheap enough that we don't
+                * need to make this conditional.
+                */
+               iov_iter_restore(&s->iter, &s->iter_state);
+               iovec = NULL;
+       }
+       ret = io_rw_init_file(req, FMODE_READ);
+       if (unlikely(ret)) {
+               kfree(iovec);
+               return ret;
+       }
+       req->cqe.res = iov_iter_count(&s->iter);
+
+       if (force_nonblock) {
+               /* If the file doesn't support async, just async punt */
+               if (unlikely(!io_file_supports_nowait(req))) {
+                       ret = io_setup_async_rw(req, iovec, s, true);
+                       return ret ?: -EAGAIN;
+               }
+               kiocb->ki_flags |= IOCB_NOWAIT;
+       } else {
+               /* Ensure we clear previously set non-block flag */
+               kiocb->ki_flags &= ~IOCB_NOWAIT;
+       }
+
+       ppos = io_kiocb_update_pos(req);
+
+       ret = rw_verify_area(READ, req->file, ppos, req->cqe.res);
+       if (unlikely(ret)) {
+               kfree(iovec);
+               return ret;
+       }
+
+       ret = io_iter_do_read(rw, &s->iter);
+
+       if (ret == -EAGAIN || (req->flags & REQ_F_REISSUE)) {
+               req->flags &= ~REQ_F_REISSUE;
+               /* if we can poll, just do that */
+               if (req->opcode == IORING_OP_READ && file_can_poll(req->file))
+                       return -EAGAIN;
+               /* IOPOLL retry should happen for io-wq threads */
+               if (!force_nonblock && !(req->ctx->flags & IORING_SETUP_IOPOLL))
+                       goto done;
+               /* no retry on NONBLOCK nor RWF_NOWAIT */
+               if (req->flags & REQ_F_NOWAIT)
+                       goto done;
+               ret = 0;
+       } else if (ret == -EIOCBQUEUED) {
+               if (iovec)
+                       kfree(iovec);
+               return IOU_ISSUE_SKIP_COMPLETE;
+       } else if (ret == req->cqe.res || ret <= 0 || !force_nonblock ||
+                  (req->flags & REQ_F_NOWAIT) || !need_complete_io(req)) {
+               /* read all, failed, already did sync or don't want to retry */
+               goto done;
+       }
+
+       /*
+        * Don't depend on the iter state matching what was consumed, or being
+        * untouched in case of error. Restore it and we'll advance it
+        * manually if we need to.
+        */
+       iov_iter_restore(&s->iter, &s->iter_state);
+
+       ret2 = io_setup_async_rw(req, iovec, s, true);
+       if (ret2)
+               return ret2;
+
+       iovec = NULL;
+       io = req->async_data;
+       s = &io->s;
+       /*
+        * Now use our persistent iterator and state, if we aren't already.
+        * We've restored and mapped the iter to match.
+        */
+
+       do {
+               /*
+                * We end up here because of a partial read, either from
+                * above or inside this loop. Advance the iter by the bytes
+                * that were consumed.
+                */
+               iov_iter_advance(&s->iter, ret);
+               if (!iov_iter_count(&s->iter))
+                       break;
+               io->bytes_done += ret;
+               iov_iter_save_state(&s->iter, &s->iter_state);
+
+               /* if we can retry, do so with the callbacks armed */
+               if (!io_rw_should_retry(req)) {
+                       kiocb->ki_flags &= ~IOCB_WAITQ;
+                       return -EAGAIN;
+               }
+
+               /*
+                * Now retry read with the IOCB_WAITQ parts set in the iocb. If
+                * we get -EIOCBQUEUED, then we'll get a notification when the
+                * desired page gets unlocked. We can also get a partial read
+                * here, and if we do, then just retry at the new offset.
+                */
+               ret = io_iter_do_read(rw, &s->iter);
+               if (ret == -EIOCBQUEUED)
+                       return IOU_ISSUE_SKIP_COMPLETE;
+               /* we got some bytes, but not all. retry. */
+               kiocb->ki_flags &= ~IOCB_WAITQ;
+               iov_iter_restore(&s->iter, &s->iter_state);
+       } while (ret > 0);
+done:
+       /* it's faster to check here then delegate to kfree */
+       if (iovec)
+               kfree(iovec);
+       return kiocb_done(req, ret, issue_flags);
+}
+
+int io_write(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_rw *rw = io_kiocb_to_cmd(req);
+       struct io_rw_state __s, *s = &__s;
+       struct iovec *iovec;
+       struct kiocb *kiocb = &rw->kiocb;
+       bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK;
+       ssize_t ret, ret2;
+       loff_t *ppos;
+
+       if (!req_has_async_data(req)) {
+               ret = io_import_iovec(WRITE, req, &iovec, s, issue_flags);
+               if (unlikely(ret < 0))
+                       return ret;
+       } else {
+               struct io_async_rw *io = req->async_data;
+
+               s = &io->s;
+               iov_iter_restore(&s->iter, &s->iter_state);
+               iovec = NULL;
+       }
+       ret = io_rw_init_file(req, FMODE_WRITE);
+       if (unlikely(ret)) {
+               kfree(iovec);
+               return ret;
+       }
+       req->cqe.res = iov_iter_count(&s->iter);
+
+       if (force_nonblock) {
+               /* If the file doesn't support async, just async punt */
+               if (unlikely(!io_file_supports_nowait(req)))
+                       goto copy_iov;
+
+               /* File path supports NOWAIT for non-direct_IO only for block devices. */
+               if (!(kiocb->ki_flags & IOCB_DIRECT) &&
+                       !(kiocb->ki_filp->f_mode & FMODE_BUF_WASYNC) &&
+                       (req->flags & REQ_F_ISREG))
+                       goto copy_iov;
+
+               kiocb->ki_flags |= IOCB_NOWAIT;
+       } else {
+               /* Ensure we clear previously set non-block flag */
+               kiocb->ki_flags &= ~IOCB_NOWAIT;
+       }
+
+       ppos = io_kiocb_update_pos(req);
+
+       ret = rw_verify_area(WRITE, req->file, ppos, req->cqe.res);
+       if (unlikely(ret)) {
+               kfree(iovec);
+               return ret;
+       }
+
+       /*
+        * Open-code file_start_write here to grab freeze protection,
+        * which will be released by another thread in
+        * io_complete_rw().  Fool lockdep by telling it the lock got
+        * released so that it doesn't complain about the held lock when
+        * we return to userspace.
+        */
+       if (req->flags & REQ_F_ISREG) {
+               sb_start_write(file_inode(req->file)->i_sb);
+               __sb_writers_release(file_inode(req->file)->i_sb,
+                                       SB_FREEZE_WRITE);
+       }
+       kiocb->ki_flags |= IOCB_WRITE;
+
+       if (likely(req->file->f_op->write_iter))
+               ret2 = call_write_iter(req->file, kiocb, &s->iter);
+       else if (req->file->f_op->write)
+               ret2 = loop_rw_iter(WRITE, rw, &s->iter);
+       else
+               ret2 = -EINVAL;
+
+       if (req->flags & REQ_F_REISSUE) {
+               req->flags &= ~REQ_F_REISSUE;
+               ret2 = -EAGAIN;
+       }
+
+       /*
+        * Raw bdev writes will return -EOPNOTSUPP for IOCB_NOWAIT. Just
+        * retry them without IOCB_NOWAIT.
+        */
+       if (ret2 == -EOPNOTSUPP && (kiocb->ki_flags & IOCB_NOWAIT))
+               ret2 = -EAGAIN;
+       /* no retry on NONBLOCK nor RWF_NOWAIT */
+       if (ret2 == -EAGAIN && (req->flags & REQ_F_NOWAIT))
+               goto done;
+       if (!force_nonblock || ret2 != -EAGAIN) {
+               /* IOPOLL retry should happen for io-wq threads */
+               if (ret2 == -EAGAIN && (req->ctx->flags & IORING_SETUP_IOPOLL))
+                       goto copy_iov;
+
+               if (ret2 != req->cqe.res && ret2 >= 0 && need_complete_io(req)) {
+                       struct io_async_rw *rw;
+
+                       trace_io_uring_short_write(req->ctx, kiocb->ki_pos - ret2,
+                                               req->cqe.res, ret2);
+
+                       /* This is a partial write. The file pos has already been
+                        * updated, setup the async struct to complete the request
+                        * in the worker. Also update bytes_done to account for
+                        * the bytes already written.
+                        */
+                       iov_iter_save_state(&s->iter, &s->iter_state);
+                       ret = io_setup_async_rw(req, iovec, s, true);
+
+                       rw = req->async_data;
+                       if (rw)
+                               rw->bytes_done += ret2;
+
+                       if (kiocb->ki_flags & IOCB_WRITE)
+                               kiocb_end_write(req);
+                       return ret ? ret : -EAGAIN;
+               }
+done:
+               ret = kiocb_done(req, ret2, issue_flags);
+       } else {
+copy_iov:
+               iov_iter_restore(&s->iter, &s->iter_state);
+               ret = io_setup_async_rw(req, iovec, s, false);
+               if (!ret) {
+                       if (kiocb->ki_flags & IOCB_WRITE)
+                               kiocb_end_write(req);
+                       return -EAGAIN;
+               }
+               return ret;
+       }
+       /* it's reportedly faster than delegating the null check to kfree() */
+       if (iovec)
+               kfree(iovec);
+       return ret;
+}
+
+static void io_cqring_ev_posted_iopoll(struct io_ring_ctx *ctx)
+{
+       io_commit_cqring_flush(ctx);
+       if (ctx->flags & IORING_SETUP_SQPOLL)
+               io_cqring_wake(ctx);
+}
+
+int io_do_iopoll(struct io_ring_ctx *ctx, bool force_nonspin)
+{
+       struct io_wq_work_node *pos, *start, *prev;
+       unsigned int poll_flags = BLK_POLL_NOSLEEP;
+       DEFINE_IO_COMP_BATCH(iob);
+       int nr_events = 0;
+
+       /*
+        * Only spin for completions if we don't have multiple devices hanging
+        * off our complete list.
+        */
+       if (ctx->poll_multi_queue || force_nonspin)
+               poll_flags |= BLK_POLL_ONESHOT;
+
+       wq_list_for_each(pos, start, &ctx->iopoll_list) {
+               struct io_kiocb *req = container_of(pos, struct io_kiocb, comp_list);
+               struct io_rw *rw = io_kiocb_to_cmd(req);
+               int ret;
+
+               /*
+                * Move completed and retryable entries to our local lists.
+                * If we find a request that requires polling, break out
+                * and complete those lists first, if we have entries there.
+                */
+               if (READ_ONCE(req->iopoll_completed))
+                       break;
+
+               ret = rw->kiocb.ki_filp->f_op->iopoll(&rw->kiocb, &iob, poll_flags);
+               if (unlikely(ret < 0))
+                       return ret;
+               else if (ret)
+                       poll_flags |= BLK_POLL_ONESHOT;
+
+               /* iopoll may have completed current req */
+               if (!rq_list_empty(iob.req_list) ||
+                   READ_ONCE(req->iopoll_completed))
+                       break;
+       }
+
+       if (!rq_list_empty(iob.req_list))
+               iob.complete(&iob);
+       else if (!pos)
+               return 0;
+
+       prev = start;
+       wq_list_for_each_resume(pos, prev) {
+               struct io_kiocb *req = container_of(pos, struct io_kiocb, comp_list);
+
+               /* order with io_complete_rw_iopoll(), e.g. ->result updates */
+               if (!smp_load_acquire(&req->iopoll_completed))
+                       break;
+               nr_events++;
+               if (unlikely(req->flags & REQ_F_CQE_SKIP))
+                       continue;
+
+               req->cqe.flags = io_put_kbuf(req, 0);
+               __io_fill_cqe_req(req->ctx, req);
+       }
+
+       if (unlikely(!nr_events))
+               return 0;
+
+       io_commit_cqring(ctx);
+       io_cqring_ev_posted_iopoll(ctx);
+       pos = start ? start->next : ctx->iopoll_list.first;
+       wq_list_cut(&ctx->iopoll_list, prev, start);
+       io_free_batch_list(ctx, pos);
+       return nr_events;
+}
diff --git a/io_uring/rw.h b/io_uring/rw.h
new file mode 100644 (file)
index 0000000..0204c3f
--- /dev/null
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/pagemap.h>
+
+struct io_rw_state {
+       struct iov_iter                 iter;
+       struct iov_iter_state           iter_state;
+       struct iovec                    fast_iov[UIO_FASTIOV];
+};
+
+struct io_async_rw {
+       struct io_rw_state              s;
+       const struct iovec              *free_iovec;
+       size_t                          bytes_done;
+       struct wait_page_queue          wpq;
+};
+
+int io_prep_rw(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_read(struct io_kiocb *req, unsigned int issue_flags);
+int io_readv_prep_async(struct io_kiocb *req);
+int io_write(struct io_kiocb *req, unsigned int issue_flags);
+int io_writev_prep_async(struct io_kiocb *req);
+void io_readv_writev_cleanup(struct io_kiocb *req);
similarity index 56%
rename from fs/io-wq.h
rename to io_uring/slist.h
index ba6eee7..f27601f 100644 (file)
@@ -1,33 +1,7 @@
-#ifndef INTERNAL_IO_WQ_H
-#define INTERNAL_IO_WQ_H
+#ifndef INTERNAL_IO_SLIST_H
+#define INTERNAL_IO_SLIST_H
 
-#include <linux/refcount.h>
-
-struct io_wq;
-
-enum {
-       IO_WQ_WORK_CANCEL       = 1,
-       IO_WQ_WORK_HASHED       = 2,
-       IO_WQ_WORK_UNBOUND      = 4,
-       IO_WQ_WORK_CONCURRENT   = 16,
-
-       IO_WQ_HASH_SHIFT        = 24,   /* upper 8 bits are used for hash key */
-};
-
-enum io_wq_cancel {
-       IO_WQ_CANCEL_OK,        /* cancelled before started */
-       IO_WQ_CANCEL_RUNNING,   /* found, running, and attempted cancelled */
-       IO_WQ_CANCEL_NOTFOUND,  /* work not found */
-};
-
-struct io_wq_work_node {
-       struct io_wq_work_node *next;
-};
-
-struct io_wq_work_list {
-       struct io_wq_work_node *first;
-       struct io_wq_work_node *last;
-};
+#include <linux/io_uring_types.h>
 
 #define wq_list_for_each(pos, prv, head)                       \
        for (pos = (head)->first, prv = NULL; pos; prv = pos, pos = (pos)->next)
@@ -36,6 +10,7 @@ struct io_wq_work_list {
        for (; pos; prv = pos, pos = (pos)->next)
 
 #define wq_list_empty(list)    (READ_ONCE((list)->first) == NULL)
+
 #define INIT_WQ_LIST(list)     do {                            \
        (list)->first = NULL;                                   \
 } while (0)
@@ -152,12 +127,6 @@ struct io_wq_work_node *wq_stack_extract(struct io_wq_work_node *stack)
        return node;
 }
 
-struct io_wq_work {
-       struct io_wq_work_node list;
-       unsigned flags;
-       int cancel_seq;
-};
-
 static inline struct io_wq_work *wq_next_work(struct io_wq_work *work)
 {
        if (!work->list.next)
@@ -166,63 +135,4 @@ static inline struct io_wq_work *wq_next_work(struct io_wq_work *work)
        return container_of(work->list.next, struct io_wq_work, list);
 }
 
-typedef struct io_wq_work *(free_work_fn)(struct io_wq_work *);
-typedef void (io_wq_work_fn)(struct io_wq_work *);
-
-struct io_wq_hash {
-       refcount_t refs;
-       unsigned long map;
-       struct wait_queue_head wait;
-};
-
-static inline void io_wq_put_hash(struct io_wq_hash *hash)
-{
-       if (refcount_dec_and_test(&hash->refs))
-               kfree(hash);
-}
-
-struct io_wq_data {
-       struct io_wq_hash *hash;
-       struct task_struct *task;
-       io_wq_work_fn *do_work;
-       free_work_fn *free_work;
-};
-
-struct io_wq *io_wq_create(unsigned bounded, struct io_wq_data *data);
-void io_wq_exit_start(struct io_wq *wq);
-void io_wq_put_and_exit(struct io_wq *wq);
-
-void io_wq_enqueue(struct io_wq *wq, struct io_wq_work *work);
-void io_wq_hash_work(struct io_wq_work *work, void *val);
-
-int io_wq_cpu_affinity(struct io_wq *wq, cpumask_var_t mask);
-int io_wq_max_workers(struct io_wq *wq, int *new_count);
-
-static inline bool io_wq_is_hashed(struct io_wq_work *work)
-{
-       return work->flags & IO_WQ_WORK_HASHED;
-}
-
-typedef bool (work_cancel_fn)(struct io_wq_work *, void *);
-
-enum io_wq_cancel io_wq_cancel_cb(struct io_wq *wq, work_cancel_fn *cancel,
-                                       void *data, bool cancel_all);
-
-#if defined(CONFIG_IO_WQ)
-extern void io_wq_worker_sleeping(struct task_struct *);
-extern void io_wq_worker_running(struct task_struct *);
-#else
-static inline void io_wq_worker_sleeping(struct task_struct *tsk)
-{
-}
-static inline void io_wq_worker_running(struct task_struct *tsk)
-{
-}
-#endif
-
-static inline bool io_wq_current_is_worker(void)
-{
-       return in_task() && (current->flags & PF_IO_WORKER) &&
-               current->worker_private;
-}
-#endif
+#endif // INTERNAL_IO_SLIST_H
\ No newline at end of file
diff --git a/io_uring/splice.c b/io_uring/splice.c
new file mode 100644 (file)
index 0000000..b013ba3
--- /dev/null
@@ -0,0 +1,122 @@
+// 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/namei.h>
+#include <linux/io_uring.h>
+#include <linux/splice.h>
+
+#include <uapi/linux/io_uring.h>
+
+#include "io_uring.h"
+#include "splice.h"
+
+struct io_splice {
+       struct file                     *file_out;
+       loff_t                          off_out;
+       loff_t                          off_in;
+       u64                             len;
+       int                             splice_fd_in;
+       unsigned int                    flags;
+};
+
+static int __io_splice_prep(struct io_kiocb *req,
+                           const struct io_uring_sqe *sqe)
+{
+       struct io_splice *sp = io_kiocb_to_cmd(req);
+       unsigned int valid_flags = SPLICE_F_FD_IN_FIXED | SPLICE_F_ALL;
+
+       sp->len = READ_ONCE(sqe->len);
+       sp->flags = READ_ONCE(sqe->splice_flags);
+       if (unlikely(sp->flags & ~valid_flags))
+               return -EINVAL;
+       sp->splice_fd_in = READ_ONCE(sqe->splice_fd_in);
+       return 0;
+}
+
+int io_tee_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       if (READ_ONCE(sqe->splice_off_in) || READ_ONCE(sqe->off))
+               return -EINVAL;
+       return __io_splice_prep(req, sqe);
+}
+
+int io_tee(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_splice *sp = io_kiocb_to_cmd(req);
+       struct file *out = sp->file_out;
+       unsigned int flags = sp->flags & ~SPLICE_F_FD_IN_FIXED;
+       struct file *in;
+       long ret = 0;
+
+       if (issue_flags & IO_URING_F_NONBLOCK)
+               return -EAGAIN;
+
+       if (sp->flags & SPLICE_F_FD_IN_FIXED)
+               in = io_file_get_fixed(req, sp->splice_fd_in, issue_flags);
+       else
+               in = io_file_get_normal(req, sp->splice_fd_in);
+       if (!in) {
+               ret = -EBADF;
+               goto done;
+       }
+
+       if (sp->len)
+               ret = do_tee(in, out, sp->len, flags);
+
+       if (!(sp->flags & SPLICE_F_FD_IN_FIXED))
+               io_put_file(in);
+done:
+       if (ret != sp->len)
+               req_set_fail(req);
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
+
+int io_splice_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_splice *sp = io_kiocb_to_cmd(req);
+
+       sp->off_in = READ_ONCE(sqe->splice_off_in);
+       sp->off_out = READ_ONCE(sqe->off);
+       return __io_splice_prep(req, sqe);
+}
+
+int io_splice(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_splice *sp = io_kiocb_to_cmd(req);
+       struct file *out = sp->file_out;
+       unsigned int flags = sp->flags & ~SPLICE_F_FD_IN_FIXED;
+       loff_t *poff_in, *poff_out;
+       struct file *in;
+       long ret = 0;
+
+       if (issue_flags & IO_URING_F_NONBLOCK)
+               return -EAGAIN;
+
+       if (sp->flags & SPLICE_F_FD_IN_FIXED)
+               in = io_file_get_fixed(req, sp->splice_fd_in, issue_flags);
+       else
+               in = io_file_get_normal(req, sp->splice_fd_in);
+       if (!in) {
+               ret = -EBADF;
+               goto done;
+       }
+
+       poff_in = (sp->off_in == -1) ? NULL : &sp->off_in;
+       poff_out = (sp->off_out == -1) ? NULL : &sp->off_out;
+
+       if (sp->len)
+               ret = do_splice(in, poff_in, out, poff_out, sp->len, flags);
+
+       if (!(sp->flags & SPLICE_F_FD_IN_FIXED))
+               io_put_file(in);
+done:
+       if (ret != sp->len)
+               req_set_fail(req);
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
diff --git a/io_uring/splice.h b/io_uring/splice.h
new file mode 100644 (file)
index 0000000..542f941
--- /dev/null
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+
+int io_tee_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_tee(struct io_kiocb *req, unsigned int issue_flags);
+
+int io_splice_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_splice(struct io_kiocb *req, unsigned int issue_flags);
diff --git a/io_uring/sqpoll.c b/io_uring/sqpoll.c
new file mode 100644 (file)
index 0000000..76d4d70
--- /dev/null
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Contains the core associated with submission side polling of the SQ
+ * ring, offloading submissions from the application to a kernel thread.
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/file.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/audit.h>
+#include <linux/security.h>
+#include <linux/io_uring.h>
+
+#include <uapi/linux/io_uring.h>
+
+#include "io_uring.h"
+#include "sqpoll.h"
+
+#define IORING_SQPOLL_CAP_ENTRIES_VALUE 8
+
+enum {
+       IO_SQ_THREAD_SHOULD_STOP = 0,
+       IO_SQ_THREAD_SHOULD_PARK,
+};
+
+void io_sq_thread_unpark(struct io_sq_data *sqd)
+       __releases(&sqd->lock)
+{
+       WARN_ON_ONCE(sqd->thread == current);
+
+       /*
+        * Do the dance but not conditional clear_bit() because it'd race with
+        * other threads incrementing park_pending and setting the bit.
+        */
+       clear_bit(IO_SQ_THREAD_SHOULD_PARK, &sqd->state);
+       if (atomic_dec_return(&sqd->park_pending))
+               set_bit(IO_SQ_THREAD_SHOULD_PARK, &sqd->state);
+       mutex_unlock(&sqd->lock);
+}
+
+void io_sq_thread_park(struct io_sq_data *sqd)
+       __acquires(&sqd->lock)
+{
+       WARN_ON_ONCE(sqd->thread == current);
+
+       atomic_inc(&sqd->park_pending);
+       set_bit(IO_SQ_THREAD_SHOULD_PARK, &sqd->state);
+       mutex_lock(&sqd->lock);
+       if (sqd->thread)
+               wake_up_process(sqd->thread);
+}
+
+void io_sq_thread_stop(struct io_sq_data *sqd)
+{
+       WARN_ON_ONCE(sqd->thread == current);
+       WARN_ON_ONCE(test_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state));
+
+       set_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state);
+       mutex_lock(&sqd->lock);
+       if (sqd->thread)
+               wake_up_process(sqd->thread);
+       mutex_unlock(&sqd->lock);
+       wait_for_completion(&sqd->exited);
+}
+
+void io_put_sq_data(struct io_sq_data *sqd)
+{
+       if (refcount_dec_and_test(&sqd->refs)) {
+               WARN_ON_ONCE(atomic_read(&sqd->park_pending));
+
+               io_sq_thread_stop(sqd);
+               kfree(sqd);
+       }
+}
+
+static __cold void io_sqd_update_thread_idle(struct io_sq_data *sqd)
+{
+       struct io_ring_ctx *ctx;
+       unsigned sq_thread_idle = 0;
+
+       list_for_each_entry(ctx, &sqd->ctx_list, sqd_list)
+               sq_thread_idle = max(sq_thread_idle, ctx->sq_thread_idle);
+       sqd->sq_thread_idle = sq_thread_idle;
+}
+
+void io_sq_thread_finish(struct io_ring_ctx *ctx)
+{
+       struct io_sq_data *sqd = ctx->sq_data;
+
+       if (sqd) {
+               io_sq_thread_park(sqd);
+               list_del_init(&ctx->sqd_list);
+               io_sqd_update_thread_idle(sqd);
+               io_sq_thread_unpark(sqd);
+
+               io_put_sq_data(sqd);
+               ctx->sq_data = NULL;
+       }
+}
+
+static struct io_sq_data *io_attach_sq_data(struct io_uring_params *p)
+{
+       struct io_ring_ctx *ctx_attach;
+       struct io_sq_data *sqd;
+       struct fd f;
+
+       f = fdget(p->wq_fd);
+       if (!f.file)
+               return ERR_PTR(-ENXIO);
+       if (!io_is_uring_fops(f.file)) {
+               fdput(f);
+               return ERR_PTR(-EINVAL);
+       }
+
+       ctx_attach = f.file->private_data;
+       sqd = ctx_attach->sq_data;
+       if (!sqd) {
+               fdput(f);
+               return ERR_PTR(-EINVAL);
+       }
+       if (sqd->task_tgid != current->tgid) {
+               fdput(f);
+               return ERR_PTR(-EPERM);
+       }
+
+       refcount_inc(&sqd->refs);
+       fdput(f);
+       return sqd;
+}
+
+static struct io_sq_data *io_get_sq_data(struct io_uring_params *p,
+                                        bool *attached)
+{
+       struct io_sq_data *sqd;
+
+       *attached = false;
+       if (p->flags & IORING_SETUP_ATTACH_WQ) {
+               sqd = io_attach_sq_data(p);
+               if (!IS_ERR(sqd)) {
+                       *attached = true;
+                       return sqd;
+               }
+               /* fall through for EPERM case, setup new sqd/task */
+               if (PTR_ERR(sqd) != -EPERM)
+                       return sqd;
+       }
+
+       sqd = kzalloc(sizeof(*sqd), GFP_KERNEL);
+       if (!sqd)
+               return ERR_PTR(-ENOMEM);
+
+       atomic_set(&sqd->park_pending, 0);
+       refcount_set(&sqd->refs, 1);
+       INIT_LIST_HEAD(&sqd->ctx_list);
+       mutex_init(&sqd->lock);
+       init_waitqueue_head(&sqd->wait);
+       init_completion(&sqd->exited);
+       return sqd;
+}
+
+static inline bool io_sqd_events_pending(struct io_sq_data *sqd)
+{
+       return READ_ONCE(sqd->state);
+}
+
+static int __io_sq_thread(struct io_ring_ctx *ctx, bool cap_entries)
+{
+       unsigned int to_submit;
+       int ret = 0;
+
+       to_submit = io_sqring_entries(ctx);
+       /* if we're handling multiple rings, cap submit size for fairness */
+       if (cap_entries && to_submit > IORING_SQPOLL_CAP_ENTRIES_VALUE)
+               to_submit = IORING_SQPOLL_CAP_ENTRIES_VALUE;
+
+       if (!wq_list_empty(&ctx->iopoll_list) || to_submit) {
+               const struct cred *creds = NULL;
+
+               if (ctx->sq_creds != current_cred())
+                       creds = override_creds(ctx->sq_creds);
+
+               mutex_lock(&ctx->uring_lock);
+               if (!wq_list_empty(&ctx->iopoll_list))
+                       io_do_iopoll(ctx, true);
+
+               /*
+                * Don't submit if refs are dying, good for io_uring_register(),
+                * but also it is relied upon by io_ring_exit_work()
+                */
+               if (to_submit && likely(!percpu_ref_is_dying(&ctx->refs)) &&
+                   !(ctx->flags & IORING_SETUP_R_DISABLED))
+                       ret = io_submit_sqes(ctx, to_submit);
+               mutex_unlock(&ctx->uring_lock);
+
+               if (to_submit && wq_has_sleeper(&ctx->sqo_sq_wait))
+                       wake_up(&ctx->sqo_sq_wait);
+               if (creds)
+                       revert_creds(creds);
+       }
+
+       return ret;
+}
+
+static bool io_sqd_handle_event(struct io_sq_data *sqd)
+{
+       bool did_sig = false;
+       struct ksignal ksig;
+
+       if (test_bit(IO_SQ_THREAD_SHOULD_PARK, &sqd->state) ||
+           signal_pending(current)) {
+               mutex_unlock(&sqd->lock);
+               if (signal_pending(current))
+                       did_sig = get_signal(&ksig);
+               cond_resched();
+               mutex_lock(&sqd->lock);
+       }
+       return did_sig || test_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state);
+}
+
+static int io_sq_thread(void *data)
+{
+       struct io_sq_data *sqd = data;
+       struct io_ring_ctx *ctx;
+       unsigned long timeout = 0;
+       char buf[TASK_COMM_LEN];
+       DEFINE_WAIT(wait);
+
+       snprintf(buf, sizeof(buf), "iou-sqp-%d", sqd->task_pid);
+       set_task_comm(current, buf);
+
+       if (sqd->sq_cpu != -1)
+               set_cpus_allowed_ptr(current, cpumask_of(sqd->sq_cpu));
+       else
+               set_cpus_allowed_ptr(current, cpu_online_mask);
+       current->flags |= PF_NO_SETAFFINITY;
+
+       audit_alloc_kernel(current);
+
+       mutex_lock(&sqd->lock);
+       while (1) {
+               bool cap_entries, sqt_spin = false;
+
+               if (io_sqd_events_pending(sqd) || signal_pending(current)) {
+                       if (io_sqd_handle_event(sqd))
+                               break;
+                       timeout = jiffies + sqd->sq_thread_idle;
+               }
+
+               cap_entries = !list_is_singular(&sqd->ctx_list);
+               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())
+                       sqt_spin = true;
+
+               if (sqt_spin || !time_after(jiffies, timeout)) {
+                       cond_resched();
+                       if (sqt_spin)
+                               timeout = jiffies + sqd->sq_thread_idle;
+                       continue;
+               }
+
+               prepare_to_wait(&sqd->wait, &wait, TASK_INTERRUPTIBLE);
+               if (!io_sqd_events_pending(sqd) && !task_work_pending(current)) {
+                       bool needs_sched = true;
+
+                       list_for_each_entry(ctx, &sqd->ctx_list, sqd_list) {
+                               atomic_or(IORING_SQ_NEED_WAKEUP,
+                                               &ctx->rings->sq_flags);
+                               if ((ctx->flags & IORING_SETUP_IOPOLL) &&
+                                   !wq_list_empty(&ctx->iopoll_list)) {
+                                       needs_sched = false;
+                                       break;
+                               }
+
+                               /*
+                                * Ensure the store of the wakeup flag is not
+                                * reordered with the load of the SQ tail
+                                */
+                               smp_mb__after_atomic();
+
+                               if (io_sqring_entries(ctx)) {
+                                       needs_sched = false;
+                                       break;
+                               }
+                       }
+
+                       if (needs_sched) {
+                               mutex_unlock(&sqd->lock);
+                               schedule();
+                               mutex_lock(&sqd->lock);
+                       }
+                       list_for_each_entry(ctx, &sqd->ctx_list, sqd_list)
+                               atomic_andnot(IORING_SQ_NEED_WAKEUP,
+                                               &ctx->rings->sq_flags);
+               }
+
+               finish_wait(&sqd->wait, &wait);
+               timeout = jiffies + sqd->sq_thread_idle;
+       }
+
+       io_uring_cancel_generic(true, sqd);
+       sqd->thread = NULL;
+       list_for_each_entry(ctx, &sqd->ctx_list, sqd_list)
+               atomic_or(IORING_SQ_NEED_WAKEUP, &ctx->rings->sq_flags);
+       io_run_task_work();
+       mutex_unlock(&sqd->lock);
+
+       audit_free(current);
+
+       complete(&sqd->exited);
+       do_exit(0);
+}
+
+int io_sqpoll_wait_sq(struct io_ring_ctx *ctx)
+{
+       DEFINE_WAIT(wait);
+
+       do {
+               if (!io_sqring_full(ctx))
+                       break;
+               prepare_to_wait(&ctx->sqo_sq_wait, &wait, TASK_INTERRUPTIBLE);
+
+               if (!io_sqring_full(ctx))
+                       break;
+               schedule();
+       } while (!signal_pending(current));
+
+       finish_wait(&ctx->sqo_sq_wait, &wait);
+       return 0;
+}
+
+__cold int io_sq_offload_create(struct io_ring_ctx *ctx,
+                               struct io_uring_params *p)
+{
+       int ret;
+
+       /* Retain compatibility with failing for an invalid attach attempt */
+       if ((ctx->flags & (IORING_SETUP_ATTACH_WQ | IORING_SETUP_SQPOLL)) ==
+                               IORING_SETUP_ATTACH_WQ) {
+               struct fd f;
+
+               f = fdget(p->wq_fd);
+               if (!f.file)
+                       return -ENXIO;
+               if (!io_is_uring_fops(f.file)) {
+                       fdput(f);
+                       return -EINVAL;
+               }
+               fdput(f);
+       }
+       if (ctx->flags & IORING_SETUP_SQPOLL) {
+               struct task_struct *tsk;
+               struct io_sq_data *sqd;
+               bool attached;
+
+               ret = security_uring_sqpoll();
+               if (ret)
+                       return ret;
+
+               sqd = io_get_sq_data(p, &attached);
+               if (IS_ERR(sqd)) {
+                       ret = PTR_ERR(sqd);
+                       goto err;
+               }
+
+               ctx->sq_creds = get_current_cred();
+               ctx->sq_data = sqd;
+               ctx->sq_thread_idle = msecs_to_jiffies(p->sq_thread_idle);
+               if (!ctx->sq_thread_idle)
+                       ctx->sq_thread_idle = HZ;
+
+               io_sq_thread_park(sqd);
+               list_add(&ctx->sqd_list, &sqd->ctx_list);
+               io_sqd_update_thread_idle(sqd);
+               /* don't attach to a dying SQPOLL thread, would be racy */
+               ret = (attached && !sqd->thread) ? -ENXIO : 0;
+               io_sq_thread_unpark(sqd);
+
+               if (ret < 0)
+                       goto err;
+               if (attached)
+                       return 0;
+
+               if (p->flags & IORING_SETUP_SQ_AFF) {
+                       int cpu = p->sq_thread_cpu;
+
+                       ret = -EINVAL;
+                       if (cpu >= nr_cpu_ids || !cpu_online(cpu))
+                               goto err_sqpoll;
+                       sqd->sq_cpu = cpu;
+               } else {
+                       sqd->sq_cpu = -1;
+               }
+
+               sqd->task_pid = current->pid;
+               sqd->task_tgid = current->tgid;
+               tsk = create_io_thread(io_sq_thread, sqd, NUMA_NO_NODE);
+               if (IS_ERR(tsk)) {
+                       ret = PTR_ERR(tsk);
+                       goto err_sqpoll;
+               }
+
+               sqd->thread = tsk;
+               ret = io_uring_alloc_task_context(tsk, ctx);
+               wake_up_new_task(tsk);
+               if (ret)
+                       goto err;
+       } else if (p->flags & IORING_SETUP_SQ_AFF) {
+               /* Can't have SQ_AFF without SQPOLL */
+               ret = -EINVAL;
+               goto err;
+       }
+
+       return 0;
+err_sqpoll:
+       complete(&ctx->sq_data->exited);
+err:
+       io_sq_thread_finish(ctx);
+       return ret;
+}
diff --git a/io_uring/sqpoll.h b/io_uring/sqpoll.h
new file mode 100644 (file)
index 0000000..0c3fbcd
--- /dev/null
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0
+
+struct io_sq_data {
+       refcount_t              refs;
+       atomic_t                park_pending;
+       struct mutex            lock;
+
+       /* ctx's that are using this sqd */
+       struct list_head        ctx_list;
+
+       struct task_struct      *thread;
+       struct wait_queue_head  wait;
+
+       unsigned                sq_thread_idle;
+       int                     sq_cpu;
+       pid_t                   task_pid;
+       pid_t                   task_tgid;
+
+       unsigned long           state;
+       struct completion       exited;
+};
+
+int io_sq_offload_create(struct io_ring_ctx *ctx, struct io_uring_params *p);
+void io_sq_thread_finish(struct io_ring_ctx *ctx);
+void io_sq_thread_stop(struct io_sq_data *sqd);
+void io_sq_thread_park(struct io_sq_data *sqd);
+void io_sq_thread_unpark(struct io_sq_data *sqd);
+void io_put_sq_data(struct io_sq_data *sqd);
+int io_sqpoll_wait_sq(struct io_ring_ctx *ctx);
diff --git a/io_uring/statx.c b/io_uring/statx.c
new file mode 100644 (file)
index 0000000..6056cd7
--- /dev/null
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/file.h>
+#include <linux/io_uring.h>
+
+#include <uapi/linux/io_uring.h>
+
+#include "../fs/internal.h"
+
+#include "io_uring.h"
+#include "statx.h"
+
+struct io_statx {
+       struct file                     *file;
+       int                             dfd;
+       unsigned int                    mask;
+       unsigned int                    flags;
+       struct filename                 *filename;
+       struct statx __user             *buffer;
+};
+
+int io_statx_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_statx *sx = io_kiocb_to_cmd(req);
+       const char __user *path;
+
+       if (sqe->buf_index || sqe->splice_fd_in)
+               return -EINVAL;
+       if (req->flags & REQ_F_FIXED_FILE)
+               return -EBADF;
+
+       sx->dfd = READ_ONCE(sqe->fd);
+       sx->mask = READ_ONCE(sqe->len);
+       path = u64_to_user_ptr(READ_ONCE(sqe->addr));
+       sx->buffer = u64_to_user_ptr(READ_ONCE(sqe->addr2));
+       sx->flags = READ_ONCE(sqe->statx_flags);
+
+       sx->filename = getname_flags(path,
+                                    getname_statx_lookup_flags(sx->flags),
+                                    NULL);
+
+       if (IS_ERR(sx->filename)) {
+               int ret = PTR_ERR(sx->filename);
+
+               sx->filename = NULL;
+               return ret;
+       }
+
+       req->flags |= REQ_F_NEED_CLEANUP;
+       return 0;
+}
+
+int io_statx(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_statx *sx = io_kiocb_to_cmd(req);
+       int ret;
+
+       if (issue_flags & IO_URING_F_NONBLOCK)
+               return -EAGAIN;
+
+       ret = do_statx(sx->dfd, sx->filename, sx->flags, sx->mask, sx->buffer);
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
+
+void io_statx_cleanup(struct io_kiocb *req)
+{
+       struct io_statx *sx = io_kiocb_to_cmd(req);
+
+       if (sx->filename)
+               putname(sx->filename);
+}
diff --git a/io_uring/statx.h b/io_uring/statx.h
new file mode 100644 (file)
index 0000000..9a17f4d
--- /dev/null
@@ -0,0 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0
+
+int io_statx_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_statx(struct io_kiocb *req, unsigned int issue_flags);
+void io_statx_cleanup(struct io_kiocb *req);
diff --git a/io_uring/sync.c b/io_uring/sync.c
new file mode 100644 (file)
index 0000000..f2102af
--- /dev/null
@@ -0,0 +1,110 @@
+// 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/namei.h>
+#include <linux/io_uring.h>
+#include <linux/fsnotify.h>
+
+#include <uapi/linux/io_uring.h>
+
+#include "io_uring.h"
+#include "sync.h"
+
+struct io_sync {
+       struct file                     *file;
+       loff_t                          len;
+       loff_t                          off;
+       int                             flags;
+       int                             mode;
+};
+
+int io_sfr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_sync *sync = io_kiocb_to_cmd(req);
+
+       if (unlikely(sqe->addr || sqe->buf_index || sqe->splice_fd_in))
+               return -EINVAL;
+
+       sync->off = READ_ONCE(sqe->off);
+       sync->len = READ_ONCE(sqe->len);
+       sync->flags = READ_ONCE(sqe->sync_range_flags);
+       return 0;
+}
+
+int io_sync_file_range(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_sync *sync = io_kiocb_to_cmd(req);
+       int ret;
+
+       /* sync_file_range always requires a blocking context */
+       if (issue_flags & IO_URING_F_NONBLOCK)
+               return -EAGAIN;
+
+       ret = sync_file_range(req->file, sync->off, sync->len, sync->flags);
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
+
+int io_fsync_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_sync *sync = io_kiocb_to_cmd(req);
+
+       if (unlikely(sqe->addr || sqe->buf_index || sqe->splice_fd_in))
+               return -EINVAL;
+
+       sync->flags = READ_ONCE(sqe->fsync_flags);
+       if (unlikely(sync->flags & ~IORING_FSYNC_DATASYNC))
+               return -EINVAL;
+
+       sync->off = READ_ONCE(sqe->off);
+       sync->len = READ_ONCE(sqe->len);
+       return 0;
+}
+
+int io_fsync(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_sync *sync = io_kiocb_to_cmd(req);
+       loff_t end = sync->off + sync->len;
+       int ret;
+
+       /* fsync always requires a blocking context */
+       if (issue_flags & IO_URING_F_NONBLOCK)
+               return -EAGAIN;
+
+       ret = vfs_fsync_range(req->file, sync->off, end > 0 ? end : LLONG_MAX,
+                               sync->flags & IORING_FSYNC_DATASYNC);
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
+
+int io_fallocate_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_sync *sync = io_kiocb_to_cmd(req);
+
+       if (sqe->buf_index || sqe->rw_flags || sqe->splice_fd_in)
+               return -EINVAL;
+
+       sync->off = READ_ONCE(sqe->off);
+       sync->len = READ_ONCE(sqe->addr);
+       sync->mode = READ_ONCE(sqe->len);
+       return 0;
+}
+
+int io_fallocate(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_sync *sync = io_kiocb_to_cmd(req);
+       int ret;
+
+       /* fallocate always requiring blocking context */
+       if (issue_flags & IO_URING_F_NONBLOCK)
+               return -EAGAIN;
+       ret = vfs_fallocate(req->file, sync->mode, sync->off, sync->len);
+       if (ret >= 0)
+               fsnotify_modify(req->file);
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
diff --git a/io_uring/sync.h b/io_uring/sync.h
new file mode 100644 (file)
index 0000000..e873c88
--- /dev/null
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
+
+int io_sfr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_sync_file_range(struct io_kiocb *req, unsigned int issue_flags);
+
+int io_fsync_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_fsync(struct io_kiocb *req, unsigned int issue_flags);
+
+int io_fallocate(struct io_kiocb *req, unsigned int issue_flags);
+int io_fallocate_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
diff --git a/io_uring/tctx.c b/io_uring/tctx.c
new file mode 100644 (file)
index 0000000..7f97d97
--- /dev/null
@@ -0,0 +1,340 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/file.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/nospec.h>
+#include <linux/io_uring.h>
+
+#include <uapi/linux/io_uring.h>
+
+#include "io_uring.h"
+#include "tctx.h"
+
+static struct io_wq *io_init_wq_offload(struct io_ring_ctx *ctx,
+                                       struct task_struct *task)
+{
+       struct io_wq_hash *hash;
+       struct io_wq_data data;
+       unsigned int concurrency;
+
+       mutex_lock(&ctx->uring_lock);
+       hash = ctx->hash_map;
+       if (!hash) {
+               hash = kzalloc(sizeof(*hash), GFP_KERNEL);
+               if (!hash) {
+                       mutex_unlock(&ctx->uring_lock);
+                       return ERR_PTR(-ENOMEM);
+               }
+               refcount_set(&hash->refs, 1);
+               init_waitqueue_head(&hash->wait);
+               ctx->hash_map = hash;
+       }
+       mutex_unlock(&ctx->uring_lock);
+
+       data.hash = hash;
+       data.task = task;
+       data.free_work = io_wq_free_work;
+       data.do_work = io_wq_submit_work;
+
+       /* Do QD, or 4 * CPUS, whatever is smallest */
+       concurrency = min(ctx->sq_entries, 4 * num_online_cpus());
+
+       return io_wq_create(concurrency, &data);
+}
+
+void __io_uring_free(struct task_struct *tsk)
+{
+       struct io_uring_task *tctx = tsk->io_uring;
+
+       WARN_ON_ONCE(!xa_empty(&tctx->xa));
+       WARN_ON_ONCE(tctx->io_wq);
+       WARN_ON_ONCE(tctx->cached_refs);
+
+       percpu_counter_destroy(&tctx->inflight);
+       kfree(tctx);
+       tsk->io_uring = NULL;
+}
+
+__cold int io_uring_alloc_task_context(struct task_struct *task,
+                                      struct io_ring_ctx *ctx)
+{
+       struct io_uring_task *tctx;
+       int ret;
+
+       tctx = kzalloc(sizeof(*tctx), GFP_KERNEL);
+       if (unlikely(!tctx))
+               return -ENOMEM;
+
+       ret = percpu_counter_init(&tctx->inflight, 0, GFP_KERNEL);
+       if (unlikely(ret)) {
+               kfree(tctx);
+               return ret;
+       }
+
+       tctx->io_wq = io_init_wq_offload(ctx, task);
+       if (IS_ERR(tctx->io_wq)) {
+               ret = PTR_ERR(tctx->io_wq);
+               percpu_counter_destroy(&tctx->inflight);
+               kfree(tctx);
+               return ret;
+       }
+
+       xa_init(&tctx->xa);
+       init_waitqueue_head(&tctx->wait);
+       atomic_set(&tctx->in_idle, 0);
+       atomic_set(&tctx->inflight_tracked, 0);
+       task->io_uring = tctx;
+       init_llist_head(&tctx->task_list);
+       init_task_work(&tctx->task_work, tctx_task_work);
+       return 0;
+}
+
+static int io_register_submitter(struct io_ring_ctx *ctx)
+{
+       int ret = 0;
+
+       mutex_lock(&ctx->uring_lock);
+       if (!ctx->submitter_task)
+               ctx->submitter_task = get_task_struct(current);
+       else if (ctx->submitter_task != current)
+               ret = -EEXIST;
+       mutex_unlock(&ctx->uring_lock);
+
+       return ret;
+}
+
+int __io_uring_add_tctx_node(struct io_ring_ctx *ctx, bool submitter)
+{
+       struct io_uring_task *tctx = current->io_uring;
+       struct io_tctx_node *node;
+       int ret;
+
+       if ((ctx->flags & IORING_SETUP_SINGLE_ISSUER) && submitter) {
+               ret = io_register_submitter(ctx);
+               if (ret)
+                       return ret;
+       }
+
+       if (unlikely(!tctx)) {
+               ret = io_uring_alloc_task_context(current, ctx);
+               if (unlikely(ret))
+                       return ret;
+
+               tctx = current->io_uring;
+               if (ctx->iowq_limits_set) {
+                       unsigned int limits[2] = { ctx->iowq_limits[0],
+                                                  ctx->iowq_limits[1], };
+
+                       ret = io_wq_max_workers(tctx->io_wq, limits);
+                       if (ret)
+                               return ret;
+               }
+       }
+       if (!xa_load(&tctx->xa, (unsigned long)ctx)) {
+               node = kmalloc(sizeof(*node), GFP_KERNEL);
+               if (!node)
+                       return -ENOMEM;
+               node->ctx = ctx;
+               node->task = current;
+
+               ret = xa_err(xa_store(&tctx->xa, (unsigned long)ctx,
+                                       node, GFP_KERNEL));
+               if (ret) {
+                       kfree(node);
+                       return ret;
+               }
+
+               mutex_lock(&ctx->uring_lock);
+               list_add(&node->ctx_node, &ctx->tctx_list);
+               mutex_unlock(&ctx->uring_lock);
+       }
+       if (submitter)
+               tctx->last = ctx;
+       return 0;
+}
+
+/*
+ * Remove this io_uring_file -> task mapping.
+ */
+__cold void io_uring_del_tctx_node(unsigned long index)
+{
+       struct io_uring_task *tctx = current->io_uring;
+       struct io_tctx_node *node;
+
+       if (!tctx)
+               return;
+       node = xa_erase(&tctx->xa, index);
+       if (!node)
+               return;
+
+       WARN_ON_ONCE(current != node->task);
+       WARN_ON_ONCE(list_empty(&node->ctx_node));
+
+       mutex_lock(&node->ctx->uring_lock);
+       list_del(&node->ctx_node);
+       mutex_unlock(&node->ctx->uring_lock);
+
+       if (tctx->last == node->ctx)
+               tctx->last = NULL;
+       kfree(node);
+}
+
+__cold void io_uring_clean_tctx(struct io_uring_task *tctx)
+{
+       struct io_wq *wq = tctx->io_wq;
+       struct io_tctx_node *node;
+       unsigned long index;
+
+       xa_for_each(&tctx->xa, index, node) {
+               io_uring_del_tctx_node(index);
+               cond_resched();
+       }
+       if (wq) {
+               /*
+                * Must be after io_uring_del_tctx_node() (removes nodes under
+                * uring_lock) to avoid race with io_uring_try_cancel_iowq().
+                */
+               io_wq_put_and_exit(wq);
+               tctx->io_wq = NULL;
+       }
+}
+
+void io_uring_unreg_ringfd(void)
+{
+       struct io_uring_task *tctx = current->io_uring;
+       int i;
+
+       for (i = 0; i < IO_RINGFD_REG_MAX; i++) {
+               if (tctx->registered_rings[i]) {
+                       fput(tctx->registered_rings[i]);
+                       tctx->registered_rings[i] = NULL;
+               }
+       }
+}
+
+static int io_ring_add_registered_fd(struct io_uring_task *tctx, int fd,
+                                    int start, int end)
+{
+       struct file *file;
+       int offset;
+
+       for (offset = start; offset < end; offset++) {
+               offset = array_index_nospec(offset, IO_RINGFD_REG_MAX);
+               if (tctx->registered_rings[offset])
+                       continue;
+
+               file = fget(fd);
+               if (!file) {
+                       return -EBADF;
+               } else if (!io_is_uring_fops(file)) {
+                       fput(file);
+                       return -EOPNOTSUPP;
+               }
+               tctx->registered_rings[offset] = file;
+               return offset;
+       }
+
+       return -EBUSY;
+}
+
+/*
+ * Register a ring fd to avoid fdget/fdput for each io_uring_enter()
+ * invocation. User passes in an array of struct io_uring_rsrc_update
+ * with ->data set to the ring_fd, and ->offset given for the desired
+ * index. If no index is desired, application may set ->offset == -1U
+ * and we'll find an available index. Returns number of entries
+ * successfully processed, or < 0 on error if none were processed.
+ */
+int io_ringfd_register(struct io_ring_ctx *ctx, void __user *__arg,
+                      unsigned nr_args)
+{
+       struct io_uring_rsrc_update __user *arg = __arg;
+       struct io_uring_rsrc_update reg;
+       struct io_uring_task *tctx;
+       int ret, i;
+
+       if (!nr_args || nr_args > IO_RINGFD_REG_MAX)
+               return -EINVAL;
+
+       mutex_unlock(&ctx->uring_lock);
+       ret = __io_uring_add_tctx_node(ctx, false);
+       mutex_lock(&ctx->uring_lock);
+       if (ret)
+               return ret;
+
+       tctx = current->io_uring;
+       for (i = 0; i < nr_args; i++) {
+               int start, end;
+
+               if (copy_from_user(&reg, &arg[i], sizeof(reg))) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               if (reg.resv) {
+                       ret = -EINVAL;
+                       break;
+               }
+
+               if (reg.offset == -1U) {
+                       start = 0;
+                       end = IO_RINGFD_REG_MAX;
+               } else {
+                       if (reg.offset >= IO_RINGFD_REG_MAX) {
+                               ret = -EINVAL;
+                               break;
+                       }
+                       start = reg.offset;
+                       end = start + 1;
+               }
+
+               ret = io_ring_add_registered_fd(tctx, reg.data, start, end);
+               if (ret < 0)
+                       break;
+
+               reg.offset = ret;
+               if (copy_to_user(&arg[i], &reg, sizeof(reg))) {
+                       fput(tctx->registered_rings[reg.offset]);
+                       tctx->registered_rings[reg.offset] = NULL;
+                       ret = -EFAULT;
+                       break;
+               }
+       }
+
+       return i ? i : ret;
+}
+
+int io_ringfd_unregister(struct io_ring_ctx *ctx, void __user *__arg,
+                        unsigned nr_args)
+{
+       struct io_uring_rsrc_update __user *arg = __arg;
+       struct io_uring_task *tctx = current->io_uring;
+       struct io_uring_rsrc_update reg;
+       int ret = 0, i;
+
+       if (!nr_args || nr_args > IO_RINGFD_REG_MAX)
+               return -EINVAL;
+       if (!tctx)
+               return 0;
+
+       for (i = 0; i < nr_args; i++) {
+               if (copy_from_user(&reg, &arg[i], sizeof(reg))) {
+                       ret = -EFAULT;
+                       break;
+               }
+               if (reg.resv || reg.data || reg.offset >= IO_RINGFD_REG_MAX) {
+                       ret = -EINVAL;
+                       break;
+               }
+
+               reg.offset = array_index_nospec(reg.offset, IO_RINGFD_REG_MAX);
+               if (tctx->registered_rings[reg.offset]) {
+                       fput(tctx->registered_rings[reg.offset]);
+                       tctx->registered_rings[reg.offset] = NULL;
+               }
+       }
+
+       return i ? i : ret;
+}
diff --git a/io_uring/tctx.h b/io_uring/tctx.h
new file mode 100644 (file)
index 0000000..25974be
--- /dev/null
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0
+
+struct io_tctx_node {
+       struct list_head        ctx_node;
+       struct task_struct      *task;
+       struct io_ring_ctx      *ctx;
+};
+
+int io_uring_alloc_task_context(struct task_struct *task,
+                               struct io_ring_ctx *ctx);
+void io_uring_del_tctx_node(unsigned long index);
+int __io_uring_add_tctx_node(struct io_ring_ctx *ctx, bool submitter);
+void io_uring_clean_tctx(struct io_uring_task *tctx);
+
+void io_uring_unreg_ringfd(void);
+int io_ringfd_register(struct io_ring_ctx *ctx, void __user *__arg,
+                      unsigned nr_args);
+int io_ringfd_unregister(struct io_ring_ctx *ctx, void __user *__arg,
+                        unsigned nr_args);
+
+/*
+ * Note that this task has used io_uring. We use it for cancelation purposes.
+ */
+static inline int io_uring_add_tctx_node(struct io_ring_ctx *ctx)
+{
+       struct io_uring_task *tctx = current->io_uring;
+
+       if (likely(tctx && tctx->last == ctx))
+               return 0;
+       return __io_uring_add_tctx_node(ctx, true);
+}
diff --git a/io_uring/timeout.c b/io_uring/timeout.c
new file mode 100644 (file)
index 0000000..2f9e569
--- /dev/null
@@ -0,0 +1,644 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/file.h>
+#include <linux/io_uring.h>
+
+#include <trace/events/io_uring.h>
+
+#include <uapi/linux/io_uring.h>
+
+#include "io_uring.h"
+#include "refs.h"
+#include "cancel.h"
+#include "timeout.h"
+
+struct io_timeout {
+       struct file                     *file;
+       u32                             off;
+       u32                             target_seq;
+       struct list_head                list;
+       /* head of the link, used by linked timeouts only */
+       struct io_kiocb                 *head;
+       /* for linked completions */
+       struct io_kiocb                 *prev;
+};
+
+struct io_timeout_rem {
+       struct file                     *file;
+       u64                             addr;
+
+       /* timeout update */
+       struct timespec64               ts;
+       u32                             flags;
+       bool                            ltimeout;
+};
+
+static inline bool io_is_timeout_noseq(struct io_kiocb *req)
+{
+       struct io_timeout *timeout = io_kiocb_to_cmd(req);
+
+       return !timeout->off;
+}
+
+static inline void io_put_req(struct io_kiocb *req)
+{
+       if (req_ref_put_and_test(req)) {
+               io_queue_next(req);
+               io_free_req(req);
+       }
+}
+
+static bool io_kill_timeout(struct io_kiocb *req, int status)
+       __must_hold(&req->ctx->completion_lock)
+       __must_hold(&req->ctx->timeout_lock)
+{
+       struct io_timeout_data *io = req->async_data;
+
+       if (hrtimer_try_to_cancel(&io->timer) != -1) {
+               struct io_timeout *timeout = io_kiocb_to_cmd(req);
+
+               if (status)
+                       req_set_fail(req);
+               atomic_set(&req->ctx->cq_timeouts,
+                       atomic_read(&req->ctx->cq_timeouts) + 1);
+               list_del_init(&timeout->list);
+               io_req_tw_post_queue(req, status, 0);
+               return true;
+       }
+       return false;
+}
+
+__cold void io_flush_timeouts(struct io_ring_ctx *ctx)
+       __must_hold(&ctx->completion_lock)
+{
+       u32 seq = ctx->cached_cq_tail - atomic_read(&ctx->cq_timeouts);
+       struct io_timeout *timeout, *tmp;
+
+       spin_lock_irq(&ctx->timeout_lock);
+       list_for_each_entry_safe(timeout, tmp, &ctx->timeout_list, list) {
+               struct io_kiocb *req = cmd_to_io_kiocb(timeout);
+               u32 events_needed, events_got;
+
+               if (io_is_timeout_noseq(req))
+                       break;
+
+               /*
+                * Since seq can easily wrap around over time, subtract
+                * the last seq at which timeouts were flushed before comparing.
+                * Assuming not more than 2^31-1 events have happened since,
+                * these subtractions won't have wrapped, so we can check if
+                * target is in [last_seq, current_seq] by comparing the two.
+                */
+               events_needed = timeout->target_seq - ctx->cq_last_tm_flush;
+               events_got = seq - ctx->cq_last_tm_flush;
+               if (events_got < events_needed)
+                       break;
+
+               io_kill_timeout(req, 0);
+       }
+       ctx->cq_last_tm_flush = seq;
+       spin_unlock_irq(&ctx->timeout_lock);
+}
+
+static void io_req_tw_fail_links(struct io_kiocb *link, bool *locked)
+{
+       io_tw_lock(link->ctx, locked);
+       while (link) {
+               struct io_kiocb *nxt = link->link;
+               long res = -ECANCELED;
+
+               if (link->flags & REQ_F_FAIL)
+                       res = link->cqe.res;
+               link->link = NULL;
+               io_req_set_res(link, res, 0);
+               io_req_task_complete(link, locked);
+               link = nxt;
+       }
+}
+
+static void io_fail_links(struct io_kiocb *req)
+       __must_hold(&req->ctx->completion_lock)
+{
+       struct io_kiocb *link = req->link;
+       bool ignore_cqes = req->flags & REQ_F_SKIP_LINK_CQES;
+
+       if (!link)
+               return;
+
+       while (link) {
+               if (ignore_cqes)
+                       link->flags |= REQ_F_CQE_SKIP;
+               else
+                       link->flags &= ~REQ_F_CQE_SKIP;
+               trace_io_uring_fail_link(req, link);
+               link = link->link;
+       }
+
+       link = req->link;
+       link->io_task_work.func = io_req_tw_fail_links;
+       io_req_task_work_add(link);
+       req->link = NULL;
+}
+
+static inline void io_remove_next_linked(struct io_kiocb *req)
+{
+       struct io_kiocb *nxt = req->link;
+
+       req->link = nxt->link;
+       nxt->link = NULL;
+}
+
+bool io_disarm_next(struct io_kiocb *req)
+       __must_hold(&req->ctx->completion_lock)
+{
+       struct io_kiocb *link = NULL;
+       bool posted = false;
+
+       if (req->flags & REQ_F_ARM_LTIMEOUT) {
+               link = req->link;
+               req->flags &= ~REQ_F_ARM_LTIMEOUT;
+               if (link && link->opcode == IORING_OP_LINK_TIMEOUT) {
+                       io_remove_next_linked(req);
+                       io_req_tw_post_queue(link, -ECANCELED, 0);
+                       posted = true;
+               }
+       } else if (req->flags & REQ_F_LINK_TIMEOUT) {
+               struct io_ring_ctx *ctx = req->ctx;
+
+               spin_lock_irq(&ctx->timeout_lock);
+               link = io_disarm_linked_timeout(req);
+               spin_unlock_irq(&ctx->timeout_lock);
+               if (link) {
+                       posted = true;
+                       io_req_tw_post_queue(link, -ECANCELED, 0);
+               }
+       }
+       if (unlikely((req->flags & REQ_F_FAIL) &&
+                    !(req->flags & REQ_F_HARDLINK))) {
+               posted |= (req->link != NULL);
+               io_fail_links(req);
+       }
+       return posted;
+}
+
+struct io_kiocb *__io_disarm_linked_timeout(struct io_kiocb *req,
+                                           struct io_kiocb *link)
+       __must_hold(&req->ctx->completion_lock)
+       __must_hold(&req->ctx->timeout_lock)
+{
+       struct io_timeout_data *io = link->async_data;
+       struct io_timeout *timeout = io_kiocb_to_cmd(link);
+
+       io_remove_next_linked(req);
+       timeout->head = NULL;
+       if (hrtimer_try_to_cancel(&io->timer) != -1) {
+               list_del(&timeout->list);
+               return link;
+       }
+
+       return NULL;
+}
+
+static enum hrtimer_restart io_timeout_fn(struct hrtimer *timer)
+{
+       struct io_timeout_data *data = container_of(timer,
+                                               struct io_timeout_data, timer);
+       struct io_kiocb *req = data->req;
+       struct io_timeout *timeout = io_kiocb_to_cmd(req);
+       struct io_ring_ctx *ctx = req->ctx;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ctx->timeout_lock, flags);
+       list_del_init(&timeout->list);
+       atomic_set(&req->ctx->cq_timeouts,
+               atomic_read(&req->ctx->cq_timeouts) + 1);
+       spin_unlock_irqrestore(&ctx->timeout_lock, flags);
+
+       if (!(data->flags & IORING_TIMEOUT_ETIME_SUCCESS))
+               req_set_fail(req);
+
+       io_req_set_res(req, -ETIME, 0);
+       req->io_task_work.func = io_req_task_complete;
+       io_req_task_work_add(req);
+       return HRTIMER_NORESTART;
+}
+
+static struct io_kiocb *io_timeout_extract(struct io_ring_ctx *ctx,
+                                          struct io_cancel_data *cd)
+       __must_hold(&ctx->timeout_lock)
+{
+       struct io_timeout *timeout;
+       struct io_timeout_data *io;
+       struct io_kiocb *req = NULL;
+
+       list_for_each_entry(timeout, &ctx->timeout_list, list) {
+               struct io_kiocb *tmp = cmd_to_io_kiocb(timeout);
+
+               if (!(cd->flags & IORING_ASYNC_CANCEL_ANY) &&
+                   cd->data != tmp->cqe.user_data)
+                       continue;
+               if (cd->flags & (IORING_ASYNC_CANCEL_ALL|IORING_ASYNC_CANCEL_ANY)) {
+                       if (cd->seq == tmp->work.cancel_seq)
+                               continue;
+                       tmp->work.cancel_seq = cd->seq;
+               }
+               req = tmp;
+               break;
+       }
+       if (!req)
+               return ERR_PTR(-ENOENT);
+
+       io = req->async_data;
+       if (hrtimer_try_to_cancel(&io->timer) == -1)
+               return ERR_PTR(-EALREADY);
+       timeout = io_kiocb_to_cmd(req);
+       list_del_init(&timeout->list);
+       return req;
+}
+
+int io_timeout_cancel(struct io_ring_ctx *ctx, struct io_cancel_data *cd)
+       __must_hold(&ctx->completion_lock)
+{
+       struct io_kiocb *req;
+
+       spin_lock_irq(&ctx->timeout_lock);
+       req = io_timeout_extract(ctx, cd);
+       spin_unlock_irq(&ctx->timeout_lock);
+
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+       io_req_task_queue_fail(req, -ECANCELED);
+       return 0;
+}
+
+static void io_req_task_link_timeout(struct io_kiocb *req, bool *locked)
+{
+       unsigned issue_flags = *locked ? 0 : IO_URING_F_UNLOCKED;
+       struct io_timeout *timeout = io_kiocb_to_cmd(req);
+       struct io_kiocb *prev = timeout->prev;
+       int ret = -ENOENT;
+
+       if (prev) {
+               if (!(req->task->flags & PF_EXITING)) {
+                       struct io_cancel_data cd = {
+                               .ctx            = req->ctx,
+                               .data           = prev->cqe.user_data,
+                       };
+
+                       ret = io_try_cancel(req->task->io_uring, &cd, issue_flags);
+               }
+               io_req_set_res(req, ret ?: -ETIME, 0);
+               io_req_complete_post(req);
+               io_put_req(prev);
+       } else {
+               io_req_set_res(req, -ETIME, 0);
+               io_req_complete_post(req);
+       }
+}
+
+static enum hrtimer_restart io_link_timeout_fn(struct hrtimer *timer)
+{
+       struct io_timeout_data *data = container_of(timer,
+                                               struct io_timeout_data, timer);
+       struct io_kiocb *prev, *req = data->req;
+       struct io_timeout *timeout = io_kiocb_to_cmd(req);
+       struct io_ring_ctx *ctx = req->ctx;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ctx->timeout_lock, flags);
+       prev = timeout->head;
+       timeout->head = NULL;
+
+       /*
+        * We don't expect the list to be empty, that will only happen if we
+        * race with the completion of the linked work.
+        */
+       if (prev) {
+               io_remove_next_linked(prev);
+               if (!req_ref_inc_not_zero(prev))
+                       prev = NULL;
+       }
+       list_del(&timeout->list);
+       timeout->prev = prev;
+       spin_unlock_irqrestore(&ctx->timeout_lock, flags);
+
+       req->io_task_work.func = io_req_task_link_timeout;
+       io_req_task_work_add(req);
+       return HRTIMER_NORESTART;
+}
+
+static clockid_t io_timeout_get_clock(struct io_timeout_data *data)
+{
+       switch (data->flags & IORING_TIMEOUT_CLOCK_MASK) {
+       case IORING_TIMEOUT_BOOTTIME:
+               return CLOCK_BOOTTIME;
+       case IORING_TIMEOUT_REALTIME:
+               return CLOCK_REALTIME;
+       default:
+               /* can't happen, vetted at prep time */
+               WARN_ON_ONCE(1);
+               fallthrough;
+       case 0:
+               return CLOCK_MONOTONIC;
+       }
+}
+
+static int io_linked_timeout_update(struct io_ring_ctx *ctx, __u64 user_data,
+                                   struct timespec64 *ts, enum hrtimer_mode mode)
+       __must_hold(&ctx->timeout_lock)
+{
+       struct io_timeout_data *io;
+       struct io_timeout *timeout;
+       struct io_kiocb *req = NULL;
+
+       list_for_each_entry(timeout, &ctx->ltimeout_list, list) {
+               struct io_kiocb *tmp = cmd_to_io_kiocb(timeout);
+
+               if (user_data == tmp->cqe.user_data) {
+                       req = tmp;
+                       break;
+               }
+       }
+       if (!req)
+               return -ENOENT;
+
+       io = req->async_data;
+       if (hrtimer_try_to_cancel(&io->timer) == -1)
+               return -EALREADY;
+       hrtimer_init(&io->timer, io_timeout_get_clock(io), mode);
+       io->timer.function = io_link_timeout_fn;
+       hrtimer_start(&io->timer, timespec64_to_ktime(*ts), mode);
+       return 0;
+}
+
+static int io_timeout_update(struct io_ring_ctx *ctx, __u64 user_data,
+                            struct timespec64 *ts, enum hrtimer_mode mode)
+       __must_hold(&ctx->timeout_lock)
+{
+       struct io_cancel_data cd = { .data = user_data, };
+       struct io_kiocb *req = io_timeout_extract(ctx, &cd);
+       struct io_timeout *timeout = io_kiocb_to_cmd(req);
+       struct io_timeout_data *data;
+
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+
+       timeout->off = 0; /* noseq */
+       data = req->async_data;
+       list_add_tail(&timeout->list, &ctx->timeout_list);
+       hrtimer_init(&data->timer, io_timeout_get_clock(data), mode);
+       data->timer.function = io_timeout_fn;
+       hrtimer_start(&data->timer, timespec64_to_ktime(*ts), mode);
+       return 0;
+}
+
+int io_timeout_remove_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_timeout_rem *tr = io_kiocb_to_cmd(req);
+
+       if (unlikely(req->flags & (REQ_F_FIXED_FILE | REQ_F_BUFFER_SELECT)))
+               return -EINVAL;
+       if (sqe->buf_index || sqe->len || sqe->splice_fd_in)
+               return -EINVAL;
+
+       tr->ltimeout = false;
+       tr->addr = READ_ONCE(sqe->addr);
+       tr->flags = READ_ONCE(sqe->timeout_flags);
+       if (tr->flags & IORING_TIMEOUT_UPDATE_MASK) {
+               if (hweight32(tr->flags & IORING_TIMEOUT_CLOCK_MASK) > 1)
+                       return -EINVAL;
+               if (tr->flags & IORING_LINK_TIMEOUT_UPDATE)
+                       tr->ltimeout = true;
+               if (tr->flags & ~(IORING_TIMEOUT_UPDATE_MASK|IORING_TIMEOUT_ABS))
+                       return -EINVAL;
+               if (get_timespec64(&tr->ts, u64_to_user_ptr(sqe->addr2)))
+                       return -EFAULT;
+               if (tr->ts.tv_sec < 0 || tr->ts.tv_nsec < 0)
+                       return -EINVAL;
+       } else if (tr->flags) {
+               /* timeout removal doesn't support flags */
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static inline enum hrtimer_mode io_translate_timeout_mode(unsigned int flags)
+{
+       return (flags & IORING_TIMEOUT_ABS) ? HRTIMER_MODE_ABS
+                                           : HRTIMER_MODE_REL;
+}
+
+/*
+ * Remove or update an existing timeout command
+ */
+int io_timeout_remove(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_timeout_rem *tr = io_kiocb_to_cmd(req);
+       struct io_ring_ctx *ctx = req->ctx;
+       int ret;
+
+       if (!(tr->flags & IORING_TIMEOUT_UPDATE)) {
+               struct io_cancel_data cd = { .data = tr->addr, };
+
+               spin_lock(&ctx->completion_lock);
+               ret = io_timeout_cancel(ctx, &cd);
+               spin_unlock(&ctx->completion_lock);
+       } else {
+               enum hrtimer_mode mode = io_translate_timeout_mode(tr->flags);
+
+               spin_lock_irq(&ctx->timeout_lock);
+               if (tr->ltimeout)
+                       ret = io_linked_timeout_update(ctx, tr->addr, &tr->ts, mode);
+               else
+                       ret = io_timeout_update(ctx, tr->addr, &tr->ts, mode);
+               spin_unlock_irq(&ctx->timeout_lock);
+       }
+
+       if (ret < 0)
+               req_set_fail(req);
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
+
+static int __io_timeout_prep(struct io_kiocb *req,
+                            const struct io_uring_sqe *sqe,
+                            bool is_timeout_link)
+{
+       struct io_timeout *timeout = io_kiocb_to_cmd(req);
+       struct io_timeout_data *data;
+       unsigned flags;
+       u32 off = READ_ONCE(sqe->off);
+
+       if (sqe->buf_index || sqe->len != 1 || sqe->splice_fd_in)
+               return -EINVAL;
+       if (off && is_timeout_link)
+               return -EINVAL;
+       flags = READ_ONCE(sqe->timeout_flags);
+       if (flags & ~(IORING_TIMEOUT_ABS | IORING_TIMEOUT_CLOCK_MASK |
+                     IORING_TIMEOUT_ETIME_SUCCESS))
+               return -EINVAL;
+       /* more than one clock specified is invalid, obviously */
+       if (hweight32(flags & IORING_TIMEOUT_CLOCK_MASK) > 1)
+               return -EINVAL;
+
+       INIT_LIST_HEAD(&timeout->list);
+       timeout->off = off;
+       if (unlikely(off && !req->ctx->off_timeout_used))
+               req->ctx->off_timeout_used = true;
+
+       if (WARN_ON_ONCE(req_has_async_data(req)))
+               return -EFAULT;
+       if (io_alloc_async_data(req))
+               return -ENOMEM;
+
+       data = req->async_data;
+       data->req = req;
+       data->flags = flags;
+
+       if (get_timespec64(&data->ts, u64_to_user_ptr(sqe->addr)))
+               return -EFAULT;
+
+       if (data->ts.tv_sec < 0 || data->ts.tv_nsec < 0)
+               return -EINVAL;
+
+       INIT_LIST_HEAD(&timeout->list);
+       data->mode = io_translate_timeout_mode(flags);
+       hrtimer_init(&data->timer, io_timeout_get_clock(data), data->mode);
+
+       if (is_timeout_link) {
+               struct io_submit_link *link = &req->ctx->submit_state.link;
+
+               if (!link->head)
+                       return -EINVAL;
+               if (link->last->opcode == IORING_OP_LINK_TIMEOUT)
+                       return -EINVAL;
+               timeout->head = link->last;
+               link->last->flags |= REQ_F_ARM_LTIMEOUT;
+       }
+       return 0;
+}
+
+int io_timeout_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       return __io_timeout_prep(req, sqe, false);
+}
+
+int io_link_timeout_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       return __io_timeout_prep(req, sqe, true);
+}
+
+int io_timeout(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_timeout *timeout = io_kiocb_to_cmd(req);
+       struct io_ring_ctx *ctx = req->ctx;
+       struct io_timeout_data *data = req->async_data;
+       struct list_head *entry;
+       u32 tail, off = timeout->off;
+
+       spin_lock_irq(&ctx->timeout_lock);
+
+       /*
+        * sqe->off holds how many events that need to occur for this
+        * timeout event to be satisfied. If it isn't set, then this is
+        * a pure timeout request, sequence isn't used.
+        */
+       if (io_is_timeout_noseq(req)) {
+               entry = ctx->timeout_list.prev;
+               goto add;
+       }
+
+       tail = ctx->cached_cq_tail - atomic_read(&ctx->cq_timeouts);
+       timeout->target_seq = tail + off;
+
+       /* Update the last seq here in case io_flush_timeouts() hasn't.
+        * This is safe because ->completion_lock is held, and submissions
+        * and completions are never mixed in the same ->completion_lock section.
+        */
+       ctx->cq_last_tm_flush = tail;
+
+       /*
+        * Insertion sort, ensuring the first entry in the list is always
+        * the one we need first.
+        */
+       list_for_each_prev(entry, &ctx->timeout_list) {
+               struct io_timeout *nextt = list_entry(entry, struct io_timeout, list);
+               struct io_kiocb *nxt = cmd_to_io_kiocb(nextt);
+
+               if (io_is_timeout_noseq(nxt))
+                       continue;
+               /* nxt.seq is behind @tail, otherwise would've been completed */
+               if (off >= nextt->target_seq - tail)
+                       break;
+       }
+add:
+       list_add(&timeout->list, entry);
+       data->timer.function = io_timeout_fn;
+       hrtimer_start(&data->timer, timespec64_to_ktime(data->ts), data->mode);
+       spin_unlock_irq(&ctx->timeout_lock);
+       return IOU_ISSUE_SKIP_COMPLETE;
+}
+
+void io_queue_linked_timeout(struct io_kiocb *req)
+{
+       struct io_timeout *timeout = io_kiocb_to_cmd(req);
+       struct io_ring_ctx *ctx = req->ctx;
+
+       spin_lock_irq(&ctx->timeout_lock);
+       /*
+        * If the back reference is NULL, then our linked request finished
+        * before we got a chance to setup the timer
+        */
+       if (timeout->head) {
+               struct io_timeout_data *data = req->async_data;
+
+               data->timer.function = io_link_timeout_fn;
+               hrtimer_start(&data->timer, timespec64_to_ktime(data->ts),
+                               data->mode);
+               list_add_tail(&timeout->list, &ctx->ltimeout_list);
+       }
+       spin_unlock_irq(&ctx->timeout_lock);
+       /* drop submission reference */
+       io_put_req(req);
+}
+
+static bool io_match_task(struct io_kiocb *head, struct task_struct *task,
+                         bool cancel_all)
+       __must_hold(&req->ctx->timeout_lock)
+{
+       struct io_kiocb *req;
+
+       if (task && head->task != task)
+               return false;
+       if (cancel_all)
+               return true;
+
+       io_for_each_link(req, head) {
+               if (req->flags & REQ_F_INFLIGHT)
+                       return true;
+       }
+       return false;
+}
+
+/* Returns true if we found and killed one or more timeouts */
+__cold bool io_kill_timeouts(struct io_ring_ctx *ctx, struct task_struct *tsk,
+                            bool cancel_all)
+{
+       struct io_timeout *timeout, *tmp;
+       int canceled = 0;
+
+       io_cq_lock(ctx);
+       spin_lock_irq(&ctx->timeout_lock);
+       list_for_each_entry_safe(timeout, tmp, &ctx->timeout_list, list) {
+               struct io_kiocb *req = cmd_to_io_kiocb(timeout);
+
+               if (io_match_task(req, tsk, cancel_all) &&
+                   io_kill_timeout(req, -ECANCELED))
+                       canceled++;
+       }
+       spin_unlock_irq(&ctx->timeout_lock);
+       io_cq_unlock_post(ctx);
+       return canceled != 0;
+}
diff --git a/io_uring/timeout.h b/io_uring/timeout.h
new file mode 100644 (file)
index 0000000..858c626
--- /dev/null
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0
+
+struct io_timeout_data {
+       struct io_kiocb                 *req;
+       struct hrtimer                  timer;
+       struct timespec64               ts;
+       enum hrtimer_mode               mode;
+       u32                             flags;
+};
+
+struct io_kiocb *__io_disarm_linked_timeout(struct io_kiocb *req,
+                                           struct io_kiocb *link);
+
+static inline struct io_kiocb *io_disarm_linked_timeout(struct io_kiocb *req)
+{
+       struct io_kiocb *link = req->link;
+
+       if (link && link->opcode == IORING_OP_LINK_TIMEOUT)
+               return __io_disarm_linked_timeout(req, link);
+
+       return NULL;
+}
+
+__cold void io_flush_timeouts(struct io_ring_ctx *ctx);
+struct io_cancel_data;
+int io_timeout_cancel(struct io_ring_ctx *ctx, struct io_cancel_data *cd);
+__cold bool io_kill_timeouts(struct io_ring_ctx *ctx, struct task_struct *tsk,
+                            bool cancel_all);
+void io_queue_linked_timeout(struct io_kiocb *req);
+bool io_disarm_next(struct io_kiocb *req);
+
+int io_timeout_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_link_timeout_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_timeout(struct io_kiocb *req, unsigned int issue_flags);
+int io_timeout_remove_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_timeout_remove(struct io_kiocb *req, unsigned int issue_flags);
diff --git a/io_uring/uring_cmd.c b/io_uring/uring_cmd.c
new file mode 100644 (file)
index 0000000..0a421ed
--- /dev/null
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/file.h>
+#include <linux/io_uring.h>
+
+#include <uapi/linux/io_uring.h>
+
+#include "io_uring.h"
+#include "uring_cmd.h"
+
+static void io_uring_cmd_work(struct io_kiocb *req, bool *locked)
+{
+       struct io_uring_cmd *ioucmd = io_kiocb_to_cmd(req);
+
+       ioucmd->task_work_cb(ioucmd);
+}
+
+void io_uring_cmd_complete_in_task(struct io_uring_cmd *ioucmd,
+                       void (*task_work_cb)(struct io_uring_cmd *))
+{
+       struct io_kiocb *req = cmd_to_io_kiocb(ioucmd);
+
+       ioucmd->task_work_cb = task_work_cb;
+       req->io_task_work.func = io_uring_cmd_work;
+       io_req_task_work_add(req);
+}
+EXPORT_SYMBOL_GPL(io_uring_cmd_complete_in_task);
+
+static inline void io_req_set_cqe32_extra(struct io_kiocb *req,
+                                         u64 extra1, u64 extra2)
+{
+       req->extra1 = extra1;
+       req->extra2 = extra2;
+       req->flags |= REQ_F_CQE32_INIT;
+}
+
+/*
+ * Called by consumers of io_uring_cmd, if they originally returned
+ * -EIOCBQUEUED upon receiving the command.
+ */
+void io_uring_cmd_done(struct io_uring_cmd *ioucmd, ssize_t ret, ssize_t res2)
+{
+       struct io_kiocb *req = cmd_to_io_kiocb(ioucmd);
+
+       if (ret < 0)
+               req_set_fail(req);
+
+       io_req_set_res(req, 0, ret);
+       if (req->ctx->flags & IORING_SETUP_CQE32)
+               io_req_set_cqe32_extra(req, res2, 0);
+       __io_req_complete(req, 0);
+}
+EXPORT_SYMBOL_GPL(io_uring_cmd_done);
+
+int io_uring_cmd_prep_async(struct io_kiocb *req)
+{
+       struct io_uring_cmd *ioucmd = io_kiocb_to_cmd(req);
+       size_t cmd_size;
+
+       cmd_size = uring_cmd_pdu_size(req->ctx->flags & IORING_SETUP_SQE128);
+
+       memcpy(req->async_data, ioucmd->cmd, cmd_size);
+       return 0;
+}
+
+int io_uring_cmd_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_uring_cmd *ioucmd = io_kiocb_to_cmd(req);
+
+       if (sqe->rw_flags || sqe->__pad1)
+               return -EINVAL;
+       ioucmd->cmd = sqe->cmd;
+       ioucmd->cmd_op = READ_ONCE(sqe->cmd_op);
+       return 0;
+}
+
+int io_uring_cmd(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_uring_cmd *ioucmd = io_kiocb_to_cmd(req);
+       struct io_ring_ctx *ctx = req->ctx;
+       struct file *file = req->file;
+       int ret;
+
+       if (!req->file->f_op->uring_cmd)
+               return -EOPNOTSUPP;
+
+       if (ctx->flags & IORING_SETUP_SQE128)
+               issue_flags |= IO_URING_F_SQE128;
+       if (ctx->flags & IORING_SETUP_CQE32)
+               issue_flags |= IO_URING_F_CQE32;
+       if (ctx->flags & IORING_SETUP_IOPOLL)
+               issue_flags |= IO_URING_F_IOPOLL;
+
+       if (req_has_async_data(req))
+               ioucmd->cmd = req->async_data;
+
+       ret = file->f_op->uring_cmd(ioucmd, issue_flags);
+       if (ret == -EAGAIN) {
+               if (!req_has_async_data(req)) {
+                       if (io_alloc_async_data(req))
+                               return -ENOMEM;
+                       io_uring_cmd_prep_async(req);
+               }
+               return -EAGAIN;
+       }
+
+       if (ret != -EIOCBQUEUED) {
+               io_uring_cmd_done(ioucmd, ret, 0);
+               return IOU_OK;
+       }
+
+       return IOU_ISSUE_SKIP_COMPLETE;
+}
diff --git a/io_uring/uring_cmd.h b/io_uring/uring_cmd.h
new file mode 100644 (file)
index 0000000..7c6697d
--- /dev/null
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0
+
+int io_uring_cmd(struct io_kiocb *req, unsigned int issue_flags);
+int io_uring_cmd_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_uring_cmd_prep_async(struct io_kiocb *req);
+
+/*
+ * The URING_CMD payload starts at 'cmd' in the first sqe, and continues into
+ * the following sqe if SQE128 is used.
+ */
+#define uring_cmd_pdu_size(is_sqe128)                          \
+       ((1 + !!(is_sqe128)) * sizeof(struct io_uring_sqe) -    \
+               offsetof(struct io_uring_sqe, cmd))
diff --git a/io_uring/xattr.c b/io_uring/xattr.c
new file mode 100644 (file)
index 0000000..b179f9a
--- /dev/null
@@ -0,0 +1,258 @@
+// 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/namei.h>
+#include <linux/io_uring.h>
+#include <linux/xattr.h>
+
+#include <uapi/linux/io_uring.h>
+
+#include "../fs/internal.h"
+
+#include "io_uring.h"
+#include "xattr.h"
+
+struct io_xattr {
+       struct file                     *file;
+       struct xattr_ctx                ctx;
+       struct filename                 *filename;
+};
+
+void io_xattr_cleanup(struct io_kiocb *req)
+{
+       struct io_xattr *ix = io_kiocb_to_cmd(req);
+
+       if (ix->filename)
+               putname(ix->filename);
+
+       kfree(ix->ctx.kname);
+       kvfree(ix->ctx.kvalue);
+}
+
+static void io_xattr_finish(struct io_kiocb *req, int ret)
+{
+       req->flags &= ~REQ_F_NEED_CLEANUP;
+
+       io_xattr_cleanup(req);
+       io_req_set_res(req, ret, 0);
+}
+
+static int __io_getxattr_prep(struct io_kiocb *req,
+                             const struct io_uring_sqe *sqe)
+{
+       struct io_xattr *ix = io_kiocb_to_cmd(req);
+       const char __user *name;
+       int ret;
+
+       if (unlikely(req->flags & REQ_F_FIXED_FILE))
+               return -EBADF;
+
+       ix->filename = NULL;
+       ix->ctx.kvalue = NULL;
+       name = u64_to_user_ptr(READ_ONCE(sqe->addr));
+       ix->ctx.cvalue = u64_to_user_ptr(READ_ONCE(sqe->addr2));
+       ix->ctx.size = READ_ONCE(sqe->len);
+       ix->ctx.flags = READ_ONCE(sqe->xattr_flags);
+
+       if (ix->ctx.flags)
+               return -EINVAL;
+
+       ix->ctx.kname = kmalloc(sizeof(*ix->ctx.kname), GFP_KERNEL);
+       if (!ix->ctx.kname)
+               return -ENOMEM;
+
+       ret = strncpy_from_user(ix->ctx.kname->name, name,
+                               sizeof(ix->ctx.kname->name));
+       if (!ret || ret == sizeof(ix->ctx.kname->name))
+               ret = -ERANGE;
+       if (ret < 0) {
+               kfree(ix->ctx.kname);
+               return ret;
+       }
+
+       req->flags |= REQ_F_NEED_CLEANUP;
+       return 0;
+}
+
+int io_fgetxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       return __io_getxattr_prep(req, sqe);
+}
+
+int io_getxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_xattr *ix = io_kiocb_to_cmd(req);
+       const char __user *path;
+       int ret;
+
+       ret = __io_getxattr_prep(req, sqe);
+       if (ret)
+               return ret;
+
+       path = u64_to_user_ptr(READ_ONCE(sqe->addr3));
+
+       ix->filename = getname_flags(path, LOOKUP_FOLLOW, NULL);
+       if (IS_ERR(ix->filename)) {
+               ret = PTR_ERR(ix->filename);
+               ix->filename = NULL;
+       }
+
+       return ret;
+}
+
+int io_fgetxattr(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_xattr *ix = io_kiocb_to_cmd(req);
+       int ret;
+
+       if (issue_flags & IO_URING_F_NONBLOCK)
+               return -EAGAIN;
+
+       ret = do_getxattr(mnt_user_ns(req->file->f_path.mnt),
+                       req->file->f_path.dentry,
+                       &ix->ctx);
+
+       io_xattr_finish(req, ret);
+       return IOU_OK;
+}
+
+int io_getxattr(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_xattr *ix = io_kiocb_to_cmd(req);
+       unsigned int lookup_flags = LOOKUP_FOLLOW;
+       struct path path;
+       int ret;
+
+       if (issue_flags & IO_URING_F_NONBLOCK)
+               return -EAGAIN;
+
+retry:
+       ret = filename_lookup(AT_FDCWD, ix->filename, lookup_flags, &path, NULL);
+       if (!ret) {
+               ret = do_getxattr(mnt_user_ns(path.mnt),
+                               path.dentry,
+                               &ix->ctx);
+
+               path_put(&path);
+               if (retry_estale(ret, lookup_flags)) {
+                       lookup_flags |= LOOKUP_REVAL;
+                       goto retry;
+               }
+       }
+
+       io_xattr_finish(req, ret);
+       return IOU_OK;
+}
+
+static int __io_setxattr_prep(struct io_kiocb *req,
+                       const struct io_uring_sqe *sqe)
+{
+       struct io_xattr *ix = io_kiocb_to_cmd(req);
+       const char __user *name;
+       int ret;
+
+       if (unlikely(req->flags & REQ_F_FIXED_FILE))
+               return -EBADF;
+
+       ix->filename = NULL;
+       name = u64_to_user_ptr(READ_ONCE(sqe->addr));
+       ix->ctx.cvalue = u64_to_user_ptr(READ_ONCE(sqe->addr2));
+       ix->ctx.kvalue = NULL;
+       ix->ctx.size = READ_ONCE(sqe->len);
+       ix->ctx.flags = READ_ONCE(sqe->xattr_flags);
+
+       ix->ctx.kname = kmalloc(sizeof(*ix->ctx.kname), GFP_KERNEL);
+       if (!ix->ctx.kname)
+               return -ENOMEM;
+
+       ret = setxattr_copy(name, &ix->ctx);
+       if (ret) {
+               kfree(ix->ctx.kname);
+               return ret;
+       }
+
+       req->flags |= REQ_F_NEED_CLEANUP;
+       return 0;
+}
+
+int io_setxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_xattr *ix = io_kiocb_to_cmd(req);
+       const char __user *path;
+       int ret;
+
+       ret = __io_setxattr_prep(req, sqe);
+       if (ret)
+               return ret;
+
+       path = u64_to_user_ptr(READ_ONCE(sqe->addr3));
+
+       ix->filename = getname_flags(path, LOOKUP_FOLLOW, NULL);
+       if (IS_ERR(ix->filename)) {
+               ret = PTR_ERR(ix->filename);
+               ix->filename = NULL;
+       }
+
+       return ret;
+}
+
+int io_fsetxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       return __io_setxattr_prep(req, sqe);
+}
+
+static int __io_setxattr(struct io_kiocb *req, unsigned int issue_flags,
+                       struct path *path)
+{
+       struct io_xattr *ix = io_kiocb_to_cmd(req);
+       int ret;
+
+       ret = mnt_want_write(path->mnt);
+       if (!ret) {
+               ret = do_setxattr(mnt_user_ns(path->mnt), path->dentry, &ix->ctx);
+               mnt_drop_write(path->mnt);
+       }
+
+       return ret;
+}
+
+int io_fsetxattr(struct io_kiocb *req, unsigned int issue_flags)
+{
+       int ret;
+
+       if (issue_flags & IO_URING_F_NONBLOCK)
+               return -EAGAIN;
+
+       ret = __io_setxattr(req, issue_flags, &req->file->f_path);
+       io_xattr_finish(req, ret);
+       return IOU_OK;
+}
+
+int io_setxattr(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_xattr *ix = io_kiocb_to_cmd(req);
+       unsigned int lookup_flags = LOOKUP_FOLLOW;
+       struct path path;
+       int ret;
+
+       if (issue_flags & IO_URING_F_NONBLOCK)
+               return -EAGAIN;
+
+retry:
+       ret = filename_lookup(AT_FDCWD, ix->filename, lookup_flags, &path, NULL);
+       if (!ret) {
+               ret = __io_setxattr(req, issue_flags, &path);
+               path_put(&path);
+               if (retry_estale(ret, lookup_flags)) {
+                       lookup_flags |= LOOKUP_REVAL;
+                       goto retry;
+               }
+       }
+
+       io_xattr_finish(req, ret);
+       return IOU_OK;
+}
diff --git a/io_uring/xattr.h b/io_uring/xattr.h
new file mode 100644 (file)
index 0000000..9b459d2
--- /dev/null
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+
+void io_xattr_cleanup(struct io_kiocb *req);
+
+int io_fsetxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_fsetxattr(struct io_kiocb *req, unsigned int issue_flags);
+
+int io_setxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_setxattr(struct io_kiocb *req, unsigned int issue_flags);
+
+int io_fgetxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_fgetxattr(struct io_kiocb *req, unsigned int issue_flags);
+
+int io_getxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_getxattr(struct io_kiocb *req, unsigned int issue_flags);
index 754f323..e1fcaed 100644 (file)
@@ -64,7 +64,7 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
                goto fail_put;
 
        if (!setup_ipc_sysctls(ns))
-               goto fail_put;
+               goto fail_mq;
 
        sem_init_ns(ns);
        msg_init_ns(ns);
@@ -72,6 +72,9 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
 
        return ns;
 
+fail_mq:
+       retire_mq_sysctls(ns);
+
 fail_put:
        put_user_ns(ns->user_ns);
        ns_free_inum(&ns->ns);
index 7690c29..a75978a 100644 (file)
@@ -1100,7 +1100,7 @@ static inline void audit_log_user_recv_msg(struct audit_buffer **ab,
        audit_log_common_recv_msg(NULL, ab, msg_type);
 }
 
-int is_audit_feature_set(int i)
+static int is_audit_feature_set(int i)
 {
        return af.features & AUDIT_FEATURE_TO_MASK(i);
 }
@@ -1390,7 +1390,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                                                 str);
                        } else {
                                audit_log_format(ab, " data=");
-                               if (data_len > 0 && str[data_len - 1] == '\0')
+                               if (str[data_len - 1] == '\0')
                                        data_len--;
                                audit_log_n_untrustedstring(ab, str, data_len);
                        }
index 5f6f3f8..e796150 100644 (file)
@@ -68,11 +68,13 @@ void *bpf_internal_load_pointer_neg_helper(const struct sk_buff *skb, int k, uns
 {
        u8 *ptr = NULL;
 
-       if (k >= SKF_NET_OFF)
+       if (k >= SKF_NET_OFF) {
                ptr = skb_network_header(skb) + k - SKF_NET_OFF;
-       else if (k >= SKF_LL_OFF)
+       } else if (k >= SKF_LL_OFF) {
+               if (unlikely(!skb_mac_header_was_set(skb)))
+                       return NULL;
                ptr = skb_mac_header(skb) + k - SKF_LL_OFF;
-
+       }
        if (ptr >= skb->head && ptr + size <= skb_tail_pointer(skb))
                return ptr;
 
index 225806a..bb1254f 100644 (file)
@@ -1497,11 +1497,12 @@ const struct bpf_func_proto bpf_dynptr_from_mem_proto = {
        .arg4_type      = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_LOCAL | MEM_UNINIT,
 };
 
-BPF_CALL_4(bpf_dynptr_read, void *, dst, u32, len, struct bpf_dynptr_kern *, src, u32, offset)
+BPF_CALL_5(bpf_dynptr_read, void *, dst, u32, len, struct bpf_dynptr_kern *, src,
+          u32, offset, u64, flags)
 {
        int err;
 
-       if (!src->data)
+       if (!src->data || flags)
                return -EINVAL;
 
        err = bpf_dynptr_check_off_len(src, offset, len);
@@ -1521,13 +1522,15 @@ const struct bpf_func_proto bpf_dynptr_read_proto = {
        .arg2_type      = ARG_CONST_SIZE_OR_ZERO,
        .arg3_type      = ARG_PTR_TO_DYNPTR,
        .arg4_type      = ARG_ANYTHING,
+       .arg5_type      = ARG_ANYTHING,
 };
 
-BPF_CALL_4(bpf_dynptr_write, struct bpf_dynptr_kern *, dst, u32, offset, void *, src, u32, len)
+BPF_CALL_5(bpf_dynptr_write, struct bpf_dynptr_kern *, dst, u32, offset, void *, src,
+          u32, len, u64, flags)
 {
        int err;
 
-       if (!dst->data || bpf_dynptr_is_rdonly(dst))
+       if (!dst->data || flags || bpf_dynptr_is_rdonly(dst))
                return -EINVAL;
 
        err = bpf_dynptr_check_off_len(dst, offset, len);
@@ -1547,6 +1550,7 @@ const struct bpf_func_proto bpf_dynptr_write_proto = {
        .arg2_type      = ARG_ANYTHING,
        .arg3_type      = ARG_PTR_TO_MEM | MEM_RDONLY,
        .arg4_type      = ARG_CONST_SIZE_OR_ZERO,
+       .arg5_type      = ARG_ANYTHING,
 };
 
 BPF_CALL_3(bpf_dynptr_data, struct bpf_dynptr_kern *, ptr, u32, offset, u32, len)
index aedac2a..0efbac0 100644 (file)
@@ -1562,6 +1562,21 @@ static void __reg_bound_offset(struct bpf_reg_state *reg)
        reg->var_off = tnum_or(tnum_clear_subreg(var64_off), var32_off);
 }
 
+static void reg_bounds_sync(struct bpf_reg_state *reg)
+{
+       /* We might have learned new bounds from the var_off. */
+       __update_reg_bounds(reg);
+       /* We might have learned something about the sign bit. */
+       __reg_deduce_bounds(reg);
+       /* We might have learned some bits from the bounds. */
+       __reg_bound_offset(reg);
+       /* Intersecting with the old var_off might have improved our bounds
+        * slightly, e.g. if umax was 0x7f...f and var_off was (0; 0xf...fc),
+        * then new var_off is (0; 0x7f...fc) which improves our umax.
+        */
+       __update_reg_bounds(reg);
+}
+
 static bool __reg32_bound_s64(s32 a)
 {
        return a >= 0 && a <= S32_MAX;
@@ -1603,16 +1618,8 @@ static void __reg_combine_32_into_64(struct bpf_reg_state *reg)
                 * so they do not impact tnum bounds calculation.
                 */
                __mark_reg64_unbounded(reg);
-               __update_reg_bounds(reg);
        }
-
-       /* Intersecting with the old var_off might have improved our bounds
-        * slightly.  e.g. if umax was 0x7f...f and var_off was (0; 0xf...fc),
-        * then new var_off is (0; 0x7f...fc) which improves our umax.
-        */
-       __reg_deduce_bounds(reg);
-       __reg_bound_offset(reg);
-       __update_reg_bounds(reg);
+       reg_bounds_sync(reg);
 }
 
 static bool __reg64_bound_s32(s64 a)
@@ -1628,7 +1635,6 @@ static bool __reg64_bound_u32(u64 a)
 static void __reg_combine_64_into_32(struct bpf_reg_state *reg)
 {
        __mark_reg32_unbounded(reg);
-
        if (__reg64_bound_s32(reg->smin_value) && __reg64_bound_s32(reg->smax_value)) {
                reg->s32_min_value = (s32)reg->smin_value;
                reg->s32_max_value = (s32)reg->smax_value;
@@ -1637,14 +1643,7 @@ static void __reg_combine_64_into_32(struct bpf_reg_state *reg)
                reg->u32_min_value = (u32)reg->umin_value;
                reg->u32_max_value = (u32)reg->umax_value;
        }
-
-       /* Intersecting with the old var_off might have improved our bounds
-        * slightly.  e.g. if umax was 0x7f...f and var_off was (0; 0xf...fc),
-        * then new var_off is (0; 0x7f...fc) which improves our umax.
-        */
-       __reg_deduce_bounds(reg);
-       __reg_bound_offset(reg);
-       __update_reg_bounds(reg);
+       reg_bounds_sync(reg);
 }
 
 /* Mark a register as having a completely unknown (scalar) value. */
@@ -6943,9 +6942,7 @@ static void do_refine_retval_range(struct bpf_reg_state *regs, int ret_type,
        ret_reg->s32_max_value = meta->msize_max_value;
        ret_reg->smin_value = -MAX_ERRNO;
        ret_reg->s32_min_value = -MAX_ERRNO;
-       __reg_deduce_bounds(ret_reg);
-       __reg_bound_offset(ret_reg);
-       __update_reg_bounds(ret_reg);
+       reg_bounds_sync(ret_reg);
 }
 
 static int
@@ -8202,11 +8199,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
 
        if (!check_reg_sane_offset(env, dst_reg, ptr_reg->type))
                return -EINVAL;
-
-       __update_reg_bounds(dst_reg);
-       __reg_deduce_bounds(dst_reg);
-       __reg_bound_offset(dst_reg);
-
+       reg_bounds_sync(dst_reg);
        if (sanitize_check_bounds(env, insn, dst_reg) < 0)
                return -EACCES;
        if (sanitize_needed(opcode)) {
@@ -8944,10 +8937,7 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
        /* ALU32 ops are zero extended into 64bit register */
        if (alu32)
                zext_32_to_64(dst_reg);
-
-       __update_reg_bounds(dst_reg);
-       __reg_deduce_bounds(dst_reg);
-       __reg_bound_offset(dst_reg);
+       reg_bounds_sync(dst_reg);
        return 0;
 }
 
@@ -9136,10 +9126,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
                                                         insn->dst_reg);
                                }
                                zext_32_to_64(dst_reg);
-
-                               __update_reg_bounds(dst_reg);
-                               __reg_deduce_bounds(dst_reg);
-                               __reg_bound_offset(dst_reg);
+                               reg_bounds_sync(dst_reg);
                        }
                } else {
                        /* case: R = imm
@@ -9577,26 +9564,33 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg,
                return;
 
        switch (opcode) {
+       /* JEQ/JNE comparison doesn't change the register equivalence.
+        *
+        * r1 = r2;
+        * if (r1 == 42) goto label;
+        * ...
+        * label: // here both r1 and r2 are known to be 42.
+        *
+        * Hence when marking register as known preserve it's ID.
+        */
        case BPF_JEQ:
+               if (is_jmp32) {
+                       __mark_reg32_known(true_reg, val32);
+                       true_32off = tnum_subreg(true_reg->var_off);
+               } else {
+                       ___mark_reg_known(true_reg, val);
+                       true_64off = true_reg->var_off;
+               }
+               break;
        case BPF_JNE:
-       {
-               struct bpf_reg_state *reg =
-                       opcode == BPF_JEQ ? true_reg : false_reg;
-
-               /* JEQ/JNE comparison doesn't change the register equivalence.
-                * r1 = r2;
-                * if (r1 == 42) goto label;
-                * ...
-                * label: // here both r1 and r2 are known to be 42.
-                *
-                * Hence when marking register as known preserve it's ID.
-                */
-               if (is_jmp32)
-                       __mark_reg32_known(reg, val32);
-               else
-                       ___mark_reg_known(reg, val);
+               if (is_jmp32) {
+                       __mark_reg32_known(false_reg, val32);
+                       false_32off = tnum_subreg(false_reg->var_off);
+               } else {
+                       ___mark_reg_known(false_reg, val);
+                       false_64off = false_reg->var_off;
+               }
                break;
-       }
        case BPF_JSET:
                if (is_jmp32) {
                        false_32off = tnum_and(false_32off, tnum_const(~val32));
@@ -9735,21 +9729,8 @@ static void __reg_combine_min_max(struct bpf_reg_state *src_reg,
                                                        dst_reg->smax_value);
        src_reg->var_off = dst_reg->var_off = tnum_intersect(src_reg->var_off,
                                                             dst_reg->var_off);
-       /* We might have learned new bounds from the var_off. */
-       __update_reg_bounds(src_reg);
-       __update_reg_bounds(dst_reg);
-       /* We might have learned something about the sign bit. */
-       __reg_deduce_bounds(src_reg);
-       __reg_deduce_bounds(dst_reg);
-       /* We might have learned some bits from the bounds. */
-       __reg_bound_offset(src_reg);
-       __reg_bound_offset(dst_reg);
-       /* Intersecting with the old var_off might have improved our bounds
-        * slightly.  e.g. if umax was 0x7f...f and var_off was (0; 0xf...fc),
-        * then new var_off is (0; 0x7f...fc) which improves our umax.
-        */
-       __update_reg_bounds(src_reg);
-       __update_reg_bounds(dst_reg);
+       reg_bounds_sync(src_reg);
+       reg_bounds_sync(dst_reg);
 }
 
 static void reg_combine_min_max(struct bpf_reg_state *true_src,
index 08102d1..2046276 100644 (file)
@@ -295,7 +295,7 @@ static inline cfi_check_fn find_check_fn(unsigned long ptr)
        rcu_idle = !rcu_is_watching();
        if (rcu_idle) {
                local_irq_save(flags);
-               rcu_irq_enter();
+               ct_irq_enter();
        }
 
        if (IS_ENABLED(CONFIG_CFI_CLANG_SHADOW))
@@ -304,7 +304,7 @@ static inline cfi_check_fn find_check_fn(unsigned long ptr)
                fn = find_module_check_fn(ptr);
 
        if (rcu_idle) {
-               rcu_irq_exit();
+               ct_irq_exit();
                local_irq_restore(flags);
        }
 
index 5da09c7..36b740c 100644 (file)
@@ -233,6 +233,7 @@ void cgroup_kn_unlock(struct kernfs_node *kn);
 int cgroup_path_ns_locked(struct cgroup *cgrp, char *buf, size_t buflen,
                          struct cgroup_namespace *ns);
 
+void cgroup_favor_dynmods(struct cgroup_root *root, bool favor);
 void cgroup_free_root(struct cgroup_root *root);
 void init_cgroup_root(struct cgroup_fs_context *ctx);
 int cgroup_setup_root(struct cgroup_root *root, u16 ss_mask);
index afc6c0e..2ade21b 100644 (file)
@@ -875,6 +875,8 @@ static int cgroup1_show_options(struct seq_file *seq, struct kernfs_root *kf_roo
                seq_puts(seq, ",xattr");
        if (root->flags & CGRP_ROOT_CPUSET_V2_MODE)
                seq_puts(seq, ",cpuset_v2_mode");
+       if (root->flags & CGRP_ROOT_FAVOR_DYNMODS)
+               seq_puts(seq, ",favordynmods");
 
        spin_lock(&release_agent_path_lock);
        if (strlen(root->release_agent_path))
@@ -898,6 +900,8 @@ enum cgroup1_param {
        Opt_noprefix,
        Opt_release_agent,
        Opt_xattr,
+       Opt_favordynmods,
+       Opt_nofavordynmods,
 };
 
 const struct fs_parameter_spec cgroup1_fs_parameters[] = {
@@ -909,6 +913,8 @@ const struct fs_parameter_spec cgroup1_fs_parameters[] = {
        fsparam_flag  ("noprefix",      Opt_noprefix),
        fsparam_string("release_agent", Opt_release_agent),
        fsparam_flag  ("xattr",         Opt_xattr),
+       fsparam_flag  ("favordynmods",  Opt_favordynmods),
+       fsparam_flag  ("nofavordynmods", Opt_nofavordynmods),
        {}
 };
 
@@ -960,6 +966,12 @@ int cgroup1_parse_param(struct fs_context *fc, struct fs_parameter *param)
        case Opt_xattr:
                ctx->flags |= CGRP_ROOT_XATTR;
                break;
+       case Opt_favordynmods:
+               ctx->flags |= CGRP_ROOT_FAVOR_DYNMODS;
+               break;
+       case Opt_nofavordynmods:
+               ctx->flags &= ~CGRP_ROOT_FAVOR_DYNMODS;
+               break;
        case Opt_release_agent:
                /* Specifying two release agents is forbidden */
                if (ctx->release_agent)
@@ -1211,8 +1223,11 @@ static int cgroup1_root_to_use(struct fs_context *fc)
        init_cgroup_root(ctx);
 
        ret = cgroup_setup_root(root, ctx->subsys_mask);
-       if (ret)
+       if (!ret)
+               cgroup_favor_dynmods(root, ctx->flags & CGRP_ROOT_FAVOR_DYNMODS);
+       else
                cgroup_free_root(root);
+
        return ret;
 }
 
index 1779ccd..ffaccd6 100644 (file)
@@ -279,8 +279,6 @@ bool cgroup_ssid_enabled(int ssid)
  *
  * - When mounting an existing superblock, mount options should match.
  *
- * - Remount is disallowed.
- *
  * - rename(2) is disallowed.
  *
  * - "tasks" is removed.  Everything should be at process granularity.  Use
@@ -765,7 +763,8 @@ struct css_set init_css_set = {
        .task_iters             = LIST_HEAD_INIT(init_css_set.task_iters),
        .threaded_csets         = LIST_HEAD_INIT(init_css_set.threaded_csets),
        .cgrp_links             = LIST_HEAD_INIT(init_css_set.cgrp_links),
-       .mg_preload_node        = LIST_HEAD_INIT(init_css_set.mg_preload_node),
+       .mg_src_preload_node    = LIST_HEAD_INIT(init_css_set.mg_src_preload_node),
+       .mg_dst_preload_node    = LIST_HEAD_INIT(init_css_set.mg_dst_preload_node),
        .mg_node                = LIST_HEAD_INIT(init_css_set.mg_node),
 
        /*
@@ -1240,7 +1239,8 @@ static struct css_set *find_css_set(struct css_set *old_cset,
        INIT_LIST_HEAD(&cset->threaded_csets);
        INIT_HLIST_NODE(&cset->hlist);
        INIT_LIST_HEAD(&cset->cgrp_links);
-       INIT_LIST_HEAD(&cset->mg_preload_node);
+       INIT_LIST_HEAD(&cset->mg_src_preload_node);
+       INIT_LIST_HEAD(&cset->mg_dst_preload_node);
        INIT_LIST_HEAD(&cset->mg_node);
 
        /* Copy the set of subsystem state objects generated in
@@ -1307,6 +1307,20 @@ struct cgroup_root *cgroup_root_from_kf(struct kernfs_root *kf_root)
        return root_cgrp->root;
 }
 
+void cgroup_favor_dynmods(struct cgroup_root *root, bool favor)
+{
+       bool favoring = root->flags & CGRP_ROOT_FAVOR_DYNMODS;
+
+       /* see the comment above CGRP_ROOT_FAVOR_DYNMODS definition */
+       if (favor && !favoring) {
+               rcu_sync_enter(&cgroup_threadgroup_rwsem.rss);
+               root->flags |= CGRP_ROOT_FAVOR_DYNMODS;
+       } else if (!favor && favoring) {
+               rcu_sync_exit(&cgroup_threadgroup_rwsem.rss);
+               root->flags &= ~CGRP_ROOT_FAVOR_DYNMODS;
+       }
+}
+
 static int cgroup_init_root_id(struct cgroup_root *root)
 {
        int id;
@@ -1367,6 +1381,7 @@ static void cgroup_destroy_root(struct cgroup_root *root)
                cgroup_root_count--;
        }
 
+       cgroup_favor_dynmods(root, false);
        cgroup_exit_root_id(root);
 
        mutex_unlock(&cgroup_mutex);
@@ -1376,6 +1391,31 @@ static void cgroup_destroy_root(struct cgroup_root *root)
        cgroup_free_root(root);
 }
 
+static inline struct cgroup *__cset_cgroup_from_root(struct css_set *cset,
+                                           struct cgroup_root *root)
+{
+       struct cgroup *res_cgroup = NULL;
+
+       if (cset == &init_css_set) {
+               res_cgroup = &root->cgrp;
+       } else if (root == &cgrp_dfl_root) {
+               res_cgroup = cset->dfl_cgrp;
+       } else {
+               struct cgrp_cset_link *link;
+
+               list_for_each_entry(link, &cset->cgrp_links, cgrp_link) {
+                       struct cgroup *c = link->cgrp;
+
+                       if (c->root == root) {
+                               res_cgroup = c;
+                               break;
+                       }
+               }
+       }
+
+       return res_cgroup;
+}
+
 /*
  * look up cgroup associated with current task's cgroup namespace on the
  * specified hierarchy
@@ -1391,22 +1431,8 @@ current_cgns_cgroup_from_root(struct cgroup_root *root)
        rcu_read_lock();
 
        cset = current->nsproxy->cgroup_ns->root_cset;
-       if (cset == &init_css_set) {
-               res = &root->cgrp;
-       } else if (root == &cgrp_dfl_root) {
-               res = cset->dfl_cgrp;
-       } else {
-               struct cgrp_cset_link *link;
+       res = __cset_cgroup_from_root(cset, root);
 
-               list_for_each_entry(link, &cset->cgrp_links, cgrp_link) {
-                       struct cgroup *c = link->cgrp;
-
-                       if (c->root == root) {
-                               res = c;
-                               break;
-                       }
-               }
-       }
        rcu_read_unlock();
 
        BUG_ON(!res);
@@ -1422,22 +1448,7 @@ static struct cgroup *cset_cgroup_from_root(struct css_set *cset,
        lockdep_assert_held(&cgroup_mutex);
        lockdep_assert_held(&css_set_lock);
 
-       if (cset == &init_css_set) {
-               res = &root->cgrp;
-       } else if (root == &cgrp_dfl_root) {
-               res = cset->dfl_cgrp;
-       } else {
-               struct cgrp_cset_link *link;
-
-               list_for_each_entry(link, &cset->cgrp_links, cgrp_link) {
-                       struct cgroup *c = link->cgrp;
-
-                       if (c->root == root) {
-                               res = c;
-                               break;
-                       }
-               }
-       }
+       res = __cset_cgroup_from_root(cset, root);
 
        BUG_ON(!res);
        return res;
@@ -1864,6 +1875,7 @@ int cgroup_show_path(struct seq_file *sf, struct kernfs_node *kf_node,
 
 enum cgroup2_param {
        Opt_nsdelegate,
+       Opt_favordynmods,
        Opt_memory_localevents,
        Opt_memory_recursiveprot,
        nr__cgroup2_params
@@ -1871,6 +1883,7 @@ enum cgroup2_param {
 
 static const struct fs_parameter_spec cgroup2_fs_parameters[] = {
        fsparam_flag("nsdelegate",              Opt_nsdelegate),
+       fsparam_flag("favordynmods",            Opt_favordynmods),
        fsparam_flag("memory_localevents",      Opt_memory_localevents),
        fsparam_flag("memory_recursiveprot",    Opt_memory_recursiveprot),
        {}
@@ -1890,6 +1903,9 @@ static int cgroup2_parse_param(struct fs_context *fc, struct fs_parameter *param
        case Opt_nsdelegate:
                ctx->flags |= CGRP_ROOT_NS_DELEGATE;
                return 0;
+       case Opt_favordynmods:
+               ctx->flags |= CGRP_ROOT_FAVOR_DYNMODS;
+               return 0;
        case Opt_memory_localevents:
                ctx->flags |= CGRP_ROOT_MEMORY_LOCAL_EVENTS;
                return 0;
@@ -1908,6 +1924,9 @@ static void apply_cgroup_root_flags(unsigned int root_flags)
                else
                        cgrp_dfl_root.flags &= ~CGRP_ROOT_NS_DELEGATE;
 
+               cgroup_favor_dynmods(&cgrp_dfl_root,
+                                    root_flags & CGRP_ROOT_FAVOR_DYNMODS);
+
                if (root_flags & CGRP_ROOT_MEMORY_LOCAL_EVENTS)
                        cgrp_dfl_root.flags |= CGRP_ROOT_MEMORY_LOCAL_EVENTS;
                else
@@ -1924,6 +1943,8 @@ static int cgroup_show_options(struct seq_file *seq, struct kernfs_root *kf_root
 {
        if (cgrp_dfl_root.flags & CGRP_ROOT_NS_DELEGATE)
                seq_puts(seq, ",nsdelegate");
+       if (cgrp_dfl_root.flags & CGRP_ROOT_FAVOR_DYNMODS)
+               seq_puts(seq, ",favordynmods");
        if (cgrp_dfl_root.flags & CGRP_ROOT_MEMORY_LOCAL_EVENTS)
                seq_puts(seq, ",memory_localevents");
        if (cgrp_dfl_root.flags & CGRP_ROOT_MEMORY_RECURSIVE_PROT)
@@ -1974,7 +1995,8 @@ void init_cgroup_root(struct cgroup_fs_context *ctx)
        cgrp->root = root;
        init_cgroup_housekeeping(cgrp);
 
-       root->flags = ctx->flags;
+       /* DYNMODS must be modified through cgroup_favor_dynmods() */
+       root->flags = ctx->flags & ~CGRP_ROOT_FAVOR_DYNMODS;
        if (ctx->release_agent)
                strscpy(root->release_agent_path, ctx->release_agent, PATH_MAX);
        if (ctx->name)
@@ -2196,6 +2218,10 @@ static int cgroup_init_fs_context(struct fs_context *fc)
        put_user_ns(fc->user_ns);
        fc->user_ns = get_user_ns(ctx->ns->user_ns);
        fc->global = true;
+
+#ifdef CONFIG_CGROUP_FAVOR_DYNMODS
+       ctx->flags |= CGRP_ROOT_FAVOR_DYNMODS;
+#endif
        return 0;
 }
 
@@ -2570,10 +2596,6 @@ int cgroup_migrate_vet_dst(struct cgroup *dst_cgrp)
        if (!cgroup_is_valid_domain(dst_cgrp->dom_cgrp))
                return -EOPNOTSUPP;
 
-       /* mixables don't care */
-       if (cgroup_is_mixable(dst_cgrp))
-               return 0;
-
        /*
         * If @dst_cgrp is already or can become a thread root or is
         * threaded, it doesn't matter.
@@ -2597,21 +2619,27 @@ int cgroup_migrate_vet_dst(struct cgroup *dst_cgrp)
  */
 void cgroup_migrate_finish(struct cgroup_mgctx *mgctx)
 {
-       LIST_HEAD(preloaded);
        struct css_set *cset, *tmp_cset;
 
        lockdep_assert_held(&cgroup_mutex);
 
        spin_lock_irq(&css_set_lock);
 
-       list_splice_tail_init(&mgctx->preloaded_src_csets, &preloaded);
-       list_splice_tail_init(&mgctx->preloaded_dst_csets, &preloaded);
+       list_for_each_entry_safe(cset, tmp_cset, &mgctx->preloaded_src_csets,
+                                mg_src_preload_node) {
+               cset->mg_src_cgrp = NULL;
+               cset->mg_dst_cgrp = NULL;
+               cset->mg_dst_cset = NULL;
+               list_del_init(&cset->mg_src_preload_node);
+               put_css_set_locked(cset);
+       }
 
-       list_for_each_entry_safe(cset, tmp_cset, &preloaded, mg_preload_node) {
+       list_for_each_entry_safe(cset, tmp_cset, &mgctx->preloaded_dst_csets,
+                                mg_dst_preload_node) {
                cset->mg_src_cgrp = NULL;
                cset->mg_dst_cgrp = NULL;
                cset->mg_dst_cset = NULL;
-               list_del_init(&cset->mg_preload_node);
+               list_del_init(&cset->mg_dst_preload_node);
                put_css_set_locked(cset);
        }
 
@@ -2651,7 +2679,7 @@ void cgroup_migrate_add_src(struct css_set *src_cset,
        if (src_cset->dead)
                return;
 
-       if (!list_empty(&src_cset->mg_preload_node))
+       if (!list_empty(&src_cset->mg_src_preload_node))
                return;
 
        src_cgrp = cset_cgroup_from_root(src_cset, dst_cgrp->root);
@@ -2664,7 +2692,7 @@ void cgroup_migrate_add_src(struct css_set *src_cset,
        src_cset->mg_src_cgrp = src_cgrp;
        src_cset->mg_dst_cgrp = dst_cgrp;
        get_css_set(src_cset);
-       list_add_tail(&src_cset->mg_preload_node, &mgctx->preloaded_src_csets);
+       list_add_tail(&src_cset->mg_src_preload_node, &mgctx->preloaded_src_csets);
 }
 
 /**
@@ -2689,7 +2717,7 @@ int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx)
 
        /* look up the dst cset for each src cset and link it to src */
        list_for_each_entry_safe(src_cset, tmp_cset, &mgctx->preloaded_src_csets,
-                                mg_preload_node) {
+                                mg_src_preload_node) {
                struct css_set *dst_cset;
                struct cgroup_subsys *ss;
                int ssid;
@@ -2708,7 +2736,7 @@ int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx)
                if (src_cset == dst_cset) {
                        src_cset->mg_src_cgrp = NULL;
                        src_cset->mg_dst_cgrp = NULL;
-                       list_del_init(&src_cset->mg_preload_node);
+                       list_del_init(&src_cset->mg_src_preload_node);
                        put_css_set(src_cset);
                        put_css_set(dst_cset);
                        continue;
@@ -2716,8 +2744,8 @@ int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx)
 
                src_cset->mg_dst_cset = dst_cset;
 
-               if (list_empty(&dst_cset->mg_preload_node))
-                       list_add_tail(&dst_cset->mg_preload_node,
+               if (list_empty(&dst_cset->mg_dst_preload_node))
+                       list_add_tail(&dst_cset->mg_dst_preload_node,
                                      &mgctx->preloaded_dst_csets);
                else
                        put_css_set(dst_cset);
@@ -2941,29 +2969,48 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp)
        struct cgroup_subsys_state *d_css;
        struct cgroup *dsct;
        struct css_set *src_cset;
+       bool has_tasks;
        int ret;
 
        lockdep_assert_held(&cgroup_mutex);
 
-       percpu_down_write(&cgroup_threadgroup_rwsem);
-
        /* look up all csses currently attached to @cgrp's subtree */
        spin_lock_irq(&css_set_lock);
        cgroup_for_each_live_descendant_pre(dsct, d_css, cgrp) {
                struct cgrp_cset_link *link;
 
+               /*
+                * As cgroup_update_dfl_csses() is only called by
+                * cgroup_apply_control(). The csses associated with the
+                * given cgrp will not be affected by changes made to
+                * its subtree_control file. We can skip them.
+                */
+               if (dsct == cgrp)
+                       continue;
+
                list_for_each_entry(link, &dsct->cset_links, cset_link)
                        cgroup_migrate_add_src(link->cset, dsct, &mgctx);
        }
        spin_unlock_irq(&css_set_lock);
 
+       /*
+        * We need to write-lock threadgroup_rwsem while migrating tasks.
+        * However, if there are no source csets for @cgrp, changing its
+        * controllers isn't gonna produce any task migrations and the
+        * write-locking can be skipped safely.
+        */
+       has_tasks = !list_empty(&mgctx.preloaded_src_csets);
+       if (has_tasks)
+               percpu_down_write(&cgroup_threadgroup_rwsem);
+
        /* NULL dst indicates self on default hierarchy */
        ret = cgroup_migrate_prepare_dst(&mgctx);
        if (ret)
                goto out_finish;
 
        spin_lock_irq(&css_set_lock);
-       list_for_each_entry(src_cset, &mgctx.preloaded_src_csets, mg_preload_node) {
+       list_for_each_entry(src_cset, &mgctx.preloaded_src_csets,
+                           mg_src_preload_node) {
                struct task_struct *task, *ntask;
 
                /* all tasks in src_csets need to be migrated */
@@ -2975,7 +3022,8 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp)
        ret = cgroup_migrate_execute(&mgctx);
 out_finish:
        cgroup_migrate_finish(&mgctx);
-       percpu_up_write(&cgroup_threadgroup_rwsem);
+       if (has_tasks)
+               percpu_up_write(&cgroup_threadgroup_rwsem);
        return ret;
 }
 
@@ -3609,21 +3657,21 @@ static int cpu_stat_show(struct seq_file *seq, void *v)
 static int cgroup_io_pressure_show(struct seq_file *seq, void *v)
 {
        struct cgroup *cgrp = seq_css(seq)->cgroup;
-       struct psi_group *psi = cgroup_ino(cgrp) == 1 ? &psi_system : &cgrp->psi;
+       struct psi_group *psi = cgroup_ino(cgrp) == 1 ? &psi_system : cgrp->psi;
 
        return psi_show(seq, psi, PSI_IO);
 }
 static int cgroup_memory_pressure_show(struct seq_file *seq, void *v)
 {
        struct cgroup *cgrp = seq_css(seq)->cgroup;
-       struct psi_group *psi = cgroup_ino(cgrp) == 1 ? &psi_system : &cgrp->psi;
+       struct psi_group *psi = cgroup_ino(cgrp) == 1 ? &psi_system : cgrp->psi;
 
        return psi_show(seq, psi, PSI_MEM);
 }
 static int cgroup_cpu_pressure_show(struct seq_file *seq, void *v)
 {
        struct cgroup *cgrp = seq_css(seq)->cgroup;
-       struct psi_group *psi = cgroup_ino(cgrp) == 1 ? &psi_system : &cgrp->psi;
+       struct psi_group *psi = cgroup_ino(cgrp) == 1 ? &psi_system : cgrp->psi;
 
        return psi_show(seq, psi, PSI_CPU);
 }
@@ -3649,7 +3697,7 @@ static ssize_t cgroup_pressure_write(struct kernfs_open_file *of, char *buf,
                return -EBUSY;
        }
 
-       psi = cgroup_ino(cgrp) == 1 ? &psi_system : &cgrp->psi;
+       psi = cgroup_ino(cgrp) == 1 ? &psi_system : cgrp->psi;
        new = psi_trigger_create(psi, buf, nbytes, res);
        if (IS_ERR(new)) {
                cgroup_put(cgrp);
@@ -5842,12 +5890,6 @@ int __init cgroup_init(void)
 
        cgroup_rstat_boot();
 
-       /*
-        * The latency of the synchronize_rcu() is too high for cgroups,
-        * avoid it at the cost of forcing all readers into the slow path.
-        */
-       rcu_sync_enter_start(&cgroup_threadgroup_rwsem.rss);
-
        get_user_ns(init_cgroup_ns.user_ns);
 
        mutex_lock(&cgroup_mutex);
@@ -6759,6 +6801,7 @@ static ssize_t features_show(struct kobject *kobj, struct kobj_attribute *attr,
 {
        return snprintf(buf, PAGE_SIZE,
                        "nsdelegate\n"
+                       "favordynmods\n"
                        "memory_localevents\n"
                        "memory_recursiveprot\n");
 }
index 24b5c2a..feb5938 100644 (file)
@@ -310,6 +310,9 @@ static void cgroup_base_stat_add(struct cgroup_base_stat *dst_bstat,
        dst_bstat->cputime.utime += src_bstat->cputime.utime;
        dst_bstat->cputime.stime += src_bstat->cputime.stime;
        dst_bstat->cputime.sum_exec_runtime += src_bstat->cputime.sum_exec_runtime;
+#ifdef CONFIG_SCHED_CORE
+       dst_bstat->forceidle_sum += src_bstat->forceidle_sum;
+#endif
 }
 
 static void cgroup_base_stat_sub(struct cgroup_base_stat *dst_bstat,
@@ -318,6 +321,9 @@ static void cgroup_base_stat_sub(struct cgroup_base_stat *dst_bstat,
        dst_bstat->cputime.utime -= src_bstat->cputime.utime;
        dst_bstat->cputime.stime -= src_bstat->cputime.stime;
        dst_bstat->cputime.sum_exec_runtime -= src_bstat->cputime.sum_exec_runtime;
+#ifdef CONFIG_SCHED_CORE
+       dst_bstat->forceidle_sum -= src_bstat->forceidle_sum;
+#endif
 }
 
 static void cgroup_base_stat_flush(struct cgroup *cgrp, int cpu)
@@ -398,6 +404,11 @@ void __cgroup_account_cputime_field(struct cgroup *cgrp,
        case CPUTIME_SOFTIRQ:
                rstatc->bstat.cputime.stime += delta_exec;
                break;
+#ifdef CONFIG_SCHED_CORE
+       case CPUTIME_FORCEIDLE:
+               rstatc->bstat.forceidle_sum += delta_exec;
+               break;
+#endif
        default:
                break;
        }
@@ -411,8 +422,9 @@ void __cgroup_account_cputime_field(struct cgroup *cgrp,
  * with how it is done by __cgroup_account_cputime_field for each bit of
  * cpu time attributed to a cgroup.
  */
-static void root_cgroup_cputime(struct task_cputime *cputime)
+static void root_cgroup_cputime(struct cgroup_base_stat *bstat)
 {
+       struct task_cputime *cputime = &bstat->cputime;
        int i;
 
        cputime->stime = 0;
@@ -438,6 +450,10 @@ static void root_cgroup_cputime(struct task_cputime *cputime)
                cputime->sum_exec_runtime += user;
                cputime->sum_exec_runtime += sys;
                cputime->sum_exec_runtime += cpustat[CPUTIME_STEAL];
+
+#ifdef CONFIG_SCHED_CORE
+               bstat->forceidle_sum += cpustat[CPUTIME_FORCEIDLE];
+#endif
        }
 }
 
@@ -445,27 +461,43 @@ void cgroup_base_stat_cputime_show(struct seq_file *seq)
 {
        struct cgroup *cgrp = seq_css(seq)->cgroup;
        u64 usage, utime, stime;
-       struct task_cputime cputime;
+       struct cgroup_base_stat bstat;
+#ifdef CONFIG_SCHED_CORE
+       u64 forceidle_time;
+#endif
 
        if (cgroup_parent(cgrp)) {
                cgroup_rstat_flush_hold(cgrp);
                usage = cgrp->bstat.cputime.sum_exec_runtime;
                cputime_adjust(&cgrp->bstat.cputime, &cgrp->prev_cputime,
                               &utime, &stime);
+#ifdef CONFIG_SCHED_CORE
+               forceidle_time = cgrp->bstat.forceidle_sum;
+#endif
                cgroup_rstat_flush_release();
        } else {
-               root_cgroup_cputime(&cputime);
-               usage = cputime.sum_exec_runtime;
-               utime = cputime.utime;
-               stime = cputime.stime;
+               root_cgroup_cputime(&bstat);
+               usage = bstat.cputime.sum_exec_runtime;
+               utime = bstat.cputime.utime;
+               stime = bstat.cputime.stime;
+#ifdef CONFIG_SCHED_CORE
+               forceidle_time = bstat.forceidle_sum;
+#endif
        }
 
        do_div(usage, NSEC_PER_USEC);
        do_div(utime, NSEC_PER_USEC);
        do_div(stime, NSEC_PER_USEC);
+#ifdef CONFIG_SCHED_CORE
+       do_div(forceidle_time, NSEC_PER_USEC);
+#endif
 
        seq_printf(seq, "usage_usec %llu\n"
                   "user_usec %llu\n"
                   "system_usec %llu\n",
                   usage, utime, stime);
+
+#ifdef CONFIG_SCHED_CORE
+       seq_printf(seq, "core_sched.force_idle_usec %llu\n", forceidle_time);
+#endif
 }
index dcd86f3..6fac5b4 100644 (file)
@@ -7,12 +7,11 @@ CONFIG_DEBUG_SLAB=y
 CONFIG_DEBUG_KMEMLEAK=y
 CONFIG_DEBUG_PAGEALLOC=y
 CONFIG_SLUB_DEBUG_ON=y
-CONFIG_KMEMCHECK=y
 CONFIG_DEBUG_OBJECTS=y
 CONFIG_DEBUG_OBJECTS_ENABLE_DEFAULT=1
 CONFIG_GCOV_KERNEL=y
 CONFIG_LOCKDEP=y
 CONFIG_PROVE_LOCKING=y
 CONFIG_SCHEDSTATS=y
-CONFIG_VMLINUX_VALIDATION=y
+CONFIG_NOINSTR_VALIDATION=y
 CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
index 36a98c4..77978e3 100644 (file)
@@ -1,18 +1,20 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Context tracking: Probe on high level context boundaries such as kernel
- * and userspace. This includes syscalls and exceptions entry/exit.
+ * Context tracking: Probe on high level context boundaries such as kernel,
+ * userspace, guest or idle.
  *
  * This is used by RCU to remove its dependency on the timer tick while a CPU
- * runs in userspace.
+ * runs in idle, userspace or guest mode.
  *
- *  Started by Frederic Weisbecker:
+ * User/guest tracking started by Frederic Weisbecker:
  *
- * Copyright (C) 2012 Red Hat, Inc., Frederic Weisbecker <fweisbec@redhat.com>
+ * Copyright (C) 2012 Red Hat, Inc., Frederic Weisbecker
  *
  * Many thanks to Gilad Ben-Yossef, Paul McKenney, Ingo Molnar, Andrew Morton,
  * Steven Rostedt, Peter Zijlstra for suggestions and improvements.
  *
+ * RCU extended quiescent state bits imported from kernel/rcu/tree.c
+ * where the relevant authorship may be found.
  */
 
 #include <linux/context_tracking.h>
 #include <linux/hardirq.h>
 #include <linux/export.h>
 #include <linux/kprobes.h>
+#include <trace/events/rcu.h>
+
+
+DEFINE_PER_CPU(struct context_tracking, context_tracking) = {
+#ifdef CONFIG_CONTEXT_TRACKING_IDLE
+       .dynticks_nesting = 1,
+       .dynticks_nmi_nesting = DYNTICK_IRQ_NONIDLE,
+#endif
+       .state = ATOMIC_INIT(RCU_DYNTICKS_IDX),
+};
+EXPORT_SYMBOL_GPL(context_tracking);
+
+#ifdef CONFIG_CONTEXT_TRACKING_IDLE
+#define TPS(x)  tracepoint_string(x)
+
+/* Record the current task on dyntick-idle entry. */
+static __always_inline void rcu_dynticks_task_enter(void)
+{
+#if defined(CONFIG_TASKS_RCU) && defined(CONFIG_NO_HZ_FULL)
+       WRITE_ONCE(current->rcu_tasks_idle_cpu, smp_processor_id());
+#endif /* #if defined(CONFIG_TASKS_RCU) && defined(CONFIG_NO_HZ_FULL) */
+}
+
+/* Record no current task on dyntick-idle exit. */
+static __always_inline void rcu_dynticks_task_exit(void)
+{
+#if defined(CONFIG_TASKS_RCU) && defined(CONFIG_NO_HZ_FULL)
+       WRITE_ONCE(current->rcu_tasks_idle_cpu, -1);
+#endif /* #if defined(CONFIG_TASKS_RCU) && defined(CONFIG_NO_HZ_FULL) */
+}
+
+/* Turn on heavyweight RCU tasks trace readers on idle/user entry. */
+static __always_inline void rcu_dynticks_task_trace_enter(void)
+{
+#ifdef CONFIG_TASKS_TRACE_RCU
+       if (IS_ENABLED(CONFIG_TASKS_TRACE_RCU_READ_MB))
+               current->trc_reader_special.b.need_mb = true;
+#endif /* #ifdef CONFIG_TASKS_TRACE_RCU */
+}
+
+/* Turn off heavyweight RCU tasks trace readers on idle/user exit. */
+static __always_inline void rcu_dynticks_task_trace_exit(void)
+{
+#ifdef CONFIG_TASKS_TRACE_RCU
+       if (IS_ENABLED(CONFIG_TASKS_TRACE_RCU_READ_MB))
+               current->trc_reader_special.b.need_mb = false;
+#endif /* #ifdef CONFIG_TASKS_TRACE_RCU */
+}
+
+/*
+ * Record entry into an extended quiescent state.  This is only to be
+ * called when not already in an extended quiescent state, that is,
+ * RCU is watching prior to the call to this function and is no longer
+ * watching upon return.
+ */
+static noinstr void ct_kernel_exit_state(int offset)
+{
+       int seq;
+
+       /*
+        * CPUs seeing atomic_add_return() must see prior RCU read-side
+        * critical sections, and we also must force ordering with the
+        * next idle sojourn.
+        */
+       rcu_dynticks_task_trace_enter();  // Before ->dynticks update!
+       seq = ct_state_inc(offset);
+       // RCU is no longer watching.  Better be in extended quiescent state!
+       WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) && (seq & RCU_DYNTICKS_IDX));
+}
+
+/*
+ * Record exit from an extended quiescent state.  This is only to be
+ * called from an extended quiescent state, that is, RCU is not watching
+ * prior to the call to this function and is watching upon return.
+ */
+static noinstr void ct_kernel_enter_state(int offset)
+{
+       int seq;
+
+       /*
+        * CPUs seeing atomic_add_return() must see prior idle sojourns,
+        * and we also must force ordering with the next RCU read-side
+        * critical section.
+        */
+       seq = ct_state_inc(offset);
+       // RCU is now watching.  Better not be in an extended quiescent state!
+       rcu_dynticks_task_trace_exit();  // After ->dynticks update!
+       WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) && !(seq & RCU_DYNTICKS_IDX));
+}
+
+/*
+ * Enter an RCU extended quiescent state, which can be either the
+ * idle loop or adaptive-tickless usermode execution.
+ *
+ * We crowbar the ->dynticks_nmi_nesting field to zero to allow for
+ * the possibility of usermode upcalls having messed up our count
+ * of interrupt nesting level during the prior busy period.
+ */
+static void noinstr ct_kernel_exit(bool user, int offset)
+{
+       struct context_tracking *ct = this_cpu_ptr(&context_tracking);
+
+       WARN_ON_ONCE(ct_dynticks_nmi_nesting() != DYNTICK_IRQ_NONIDLE);
+       WRITE_ONCE(ct->dynticks_nmi_nesting, 0);
+       WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&
+                    ct_dynticks_nesting() == 0);
+       if (ct_dynticks_nesting() != 1) {
+               // RCU will still be watching, so just do accounting and leave.
+               ct->dynticks_nesting--;
+               return;
+       }
+
+       instrumentation_begin();
+       lockdep_assert_irqs_disabled();
+       trace_rcu_dyntick(TPS("Start"), ct_dynticks_nesting(), 0, ct_dynticks());
+       WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) && !user && !is_idle_task(current));
+       rcu_preempt_deferred_qs(current);
+
+       // instrumentation for the noinstr ct_kernel_exit_state()
+       instrument_atomic_write(&ct->state, sizeof(ct->state));
+
+       instrumentation_end();
+       WRITE_ONCE(ct->dynticks_nesting, 0); /* Avoid irq-access tearing. */
+       // RCU is watching here ...
+       ct_kernel_exit_state(offset);
+       // ... but is no longer watching here.
+       rcu_dynticks_task_enter();
+}
+
+/*
+ * Exit an RCU extended quiescent state, which can be either the
+ * idle loop or adaptive-tickless usermode execution.
+ *
+ * We crowbar the ->dynticks_nmi_nesting field to DYNTICK_IRQ_NONIDLE to
+ * allow for the possibility of usermode upcalls messing up our count of
+ * interrupt nesting level during the busy period that is just now starting.
+ */
+static void noinstr ct_kernel_enter(bool user, int offset)
+{
+       struct context_tracking *ct = this_cpu_ptr(&context_tracking);
+       long oldval;
+
+       WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) && !raw_irqs_disabled());
+       oldval = ct_dynticks_nesting();
+       WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) && oldval < 0);
+       if (oldval) {
+               // RCU was already watching, so just do accounting and leave.
+               ct->dynticks_nesting++;
+               return;
+       }
+       rcu_dynticks_task_exit();
+       // RCU is not watching here ...
+       ct_kernel_enter_state(offset);
+       // ... but is watching here.
+       instrumentation_begin();
+
+       // instrumentation for the noinstr ct_kernel_enter_state()
+       instrument_atomic_write(&ct->state, sizeof(ct->state));
+
+       trace_rcu_dyntick(TPS("End"), ct_dynticks_nesting(), 1, ct_dynticks());
+       WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) && !user && !is_idle_task(current));
+       WRITE_ONCE(ct->dynticks_nesting, 1);
+       WARN_ON_ONCE(ct_dynticks_nmi_nesting());
+       WRITE_ONCE(ct->dynticks_nmi_nesting, DYNTICK_IRQ_NONIDLE);
+       instrumentation_end();
+}
+
+/**
+ * ct_nmi_exit - inform RCU of exit from NMI context
+ *
+ * If we are returning from the outermost NMI handler that interrupted an
+ * RCU-idle period, update ct->state and ct->dynticks_nmi_nesting
+ * to let the RCU grace-period handling know that the CPU is back to
+ * being RCU-idle.
+ *
+ * If you add or remove a call to ct_nmi_exit(), be sure to test
+ * with CONFIG_RCU_EQS_DEBUG=y.
+ */
+void noinstr ct_nmi_exit(void)
+{
+       struct context_tracking *ct = this_cpu_ptr(&context_tracking);
+
+       instrumentation_begin();
+       /*
+        * Check for ->dynticks_nmi_nesting underflow and bad ->dynticks.
+        * (We are exiting an NMI handler, so RCU better be paying attention
+        * to us!)
+        */
+       WARN_ON_ONCE(ct_dynticks_nmi_nesting() <= 0);
+       WARN_ON_ONCE(rcu_dynticks_curr_cpu_in_eqs());
+
+       /*
+        * If the nesting level is not 1, the CPU wasn't RCU-idle, so
+        * leave it in non-RCU-idle state.
+        */
+       if (ct_dynticks_nmi_nesting() != 1) {
+               trace_rcu_dyntick(TPS("--="), ct_dynticks_nmi_nesting(), ct_dynticks_nmi_nesting() - 2,
+                                 ct_dynticks());
+               WRITE_ONCE(ct->dynticks_nmi_nesting, /* No store tearing. */
+                          ct_dynticks_nmi_nesting() - 2);
+               instrumentation_end();
+               return;
+       }
+
+       /* This NMI interrupted an RCU-idle CPU, restore RCU-idleness. */
+       trace_rcu_dyntick(TPS("Startirq"), ct_dynticks_nmi_nesting(), 0, ct_dynticks());
+       WRITE_ONCE(ct->dynticks_nmi_nesting, 0); /* Avoid store tearing. */
+
+       // instrumentation for the noinstr ct_kernel_exit_state()
+       instrument_atomic_write(&ct->state, sizeof(ct->state));
+       instrumentation_end();
+
+       // RCU is watching here ...
+       ct_kernel_exit_state(RCU_DYNTICKS_IDX);
+       // ... but is no longer watching here.
+
+       if (!in_nmi())
+               rcu_dynticks_task_enter();
+}
+
+/**
+ * ct_nmi_enter - inform RCU of entry to NMI context
+ *
+ * If the CPU was idle from RCU's viewpoint, update ct->state and
+ * ct->dynticks_nmi_nesting to let the RCU grace-period handling know
+ * that the CPU is active.  This implementation permits nested NMIs, as
+ * long as the nesting level does not overflow an int.  (You will probably
+ * run out of stack space first.)
+ *
+ * If you add or remove a call to ct_nmi_enter(), be sure to test
+ * with CONFIG_RCU_EQS_DEBUG=y.
+ */
+void noinstr ct_nmi_enter(void)
+{
+       long incby = 2;
+       struct context_tracking *ct = this_cpu_ptr(&context_tracking);
+
+       /* Complain about underflow. */
+       WARN_ON_ONCE(ct_dynticks_nmi_nesting() < 0);
+
+       /*
+        * If idle from RCU viewpoint, atomically increment ->dynticks
+        * to mark non-idle and increment ->dynticks_nmi_nesting by one.
+        * Otherwise, increment ->dynticks_nmi_nesting by two.  This means
+        * if ->dynticks_nmi_nesting is equal to one, we are guaranteed
+        * to be in the outermost NMI handler that interrupted an RCU-idle
+        * period (observation due to Andy Lutomirski).
+        */
+       if (rcu_dynticks_curr_cpu_in_eqs()) {
+
+               if (!in_nmi())
+                       rcu_dynticks_task_exit();
+
+               // RCU is not watching here ...
+               ct_kernel_enter_state(RCU_DYNTICKS_IDX);
+               // ... but is watching here.
+
+               instrumentation_begin();
+               // instrumentation for the noinstr rcu_dynticks_curr_cpu_in_eqs()
+               instrument_atomic_read(&ct->state, sizeof(ct->state));
+               // instrumentation for the noinstr ct_kernel_enter_state()
+               instrument_atomic_write(&ct->state, sizeof(ct->state));
+
+               incby = 1;
+       } else if (!in_nmi()) {
+               instrumentation_begin();
+               rcu_irq_enter_check_tick();
+       } else  {
+               instrumentation_begin();
+       }
+
+       trace_rcu_dyntick(incby == 1 ? TPS("Endirq") : TPS("++="),
+                         ct_dynticks_nmi_nesting(),
+                         ct_dynticks_nmi_nesting() + incby, ct_dynticks());
+       instrumentation_end();
+       WRITE_ONCE(ct->dynticks_nmi_nesting, /* Prevent store tearing. */
+                  ct_dynticks_nmi_nesting() + incby);
+       barrier();
+}
+
+/**
+ * ct_idle_enter - inform RCU that current CPU is entering idle
+ *
+ * Enter idle mode, in other words, -leave- the mode in which RCU
+ * read-side critical sections can occur.  (Though RCU read-side
+ * critical sections can occur in irq handlers in idle, a possibility
+ * handled by irq_enter() and irq_exit().)
+ *
+ * If you add or remove a call to ct_idle_enter(), be sure to test with
+ * CONFIG_RCU_EQS_DEBUG=y.
+ */
+void noinstr ct_idle_enter(void)
+{
+       WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) && !raw_irqs_disabled());
+       ct_kernel_exit(false, RCU_DYNTICKS_IDX + CONTEXT_IDLE);
+}
+EXPORT_SYMBOL_GPL(ct_idle_enter);
+
+/**
+ * ct_idle_exit - inform RCU that current CPU is leaving idle
+ *
+ * Exit idle mode, in other words, -enter- the mode in which RCU
+ * read-side critical sections can occur.
+ *
+ * If you add or remove a call to ct_idle_exit(), be sure to test with
+ * CONFIG_RCU_EQS_DEBUG=y.
+ */
+void noinstr ct_idle_exit(void)
+{
+       unsigned long flags;
+
+       raw_local_irq_save(flags);
+       ct_kernel_enter(false, RCU_DYNTICKS_IDX - CONTEXT_IDLE);
+       raw_local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(ct_idle_exit);
+
+/**
+ * ct_irq_enter - inform RCU that current CPU is entering irq away from idle
+ *
+ * Enter an interrupt handler, which might possibly result in exiting
+ * idle mode, in other words, entering the mode in which read-side critical
+ * sections can occur.  The caller must have disabled interrupts.
+ *
+ * Note that the Linux kernel is fully capable of entering an interrupt
+ * handler that it never exits, for example when doing upcalls to user mode!
+ * This code assumes that the idle loop never does upcalls to user mode.
+ * If your architecture's idle loop does do upcalls to user mode (or does
+ * anything else that results in unbalanced calls to the irq_enter() and
+ * irq_exit() functions), RCU will give you what you deserve, good and hard.
+ * But very infrequently and irreproducibly.
+ *
+ * Use things like work queues to work around this limitation.
+ *
+ * You have been warned.
+ *
+ * If you add or remove a call to ct_irq_enter(), be sure to test with
+ * CONFIG_RCU_EQS_DEBUG=y.
+ */
+noinstr void ct_irq_enter(void)
+{
+       lockdep_assert_irqs_disabled();
+       ct_nmi_enter();
+}
+
+/**
+ * ct_irq_exit - inform RCU that current CPU is exiting irq towards idle
+ *
+ * Exit from an interrupt handler, which might possibly result in entering
+ * idle mode, in other words, leaving the mode in which read-side critical
+ * sections can occur.  The caller must have disabled interrupts.
+ *
+ * This code assumes that the idle loop never does anything that might
+ * result in unbalanced calls to irq_enter() and irq_exit().  If your
+ * architecture's idle loop violates this assumption, RCU will give you what
+ * you deserve, good and hard.  But very infrequently and irreproducibly.
+ *
+ * Use things like work queues to work around this limitation.
+ *
+ * You have been warned.
+ *
+ * If you add or remove a call to ct_irq_exit(), be sure to test with
+ * CONFIG_RCU_EQS_DEBUG=y.
+ */
+noinstr void ct_irq_exit(void)
+{
+       lockdep_assert_irqs_disabled();
+       ct_nmi_exit();
+}
+
+/*
+ * Wrapper for ct_irq_enter() where interrupts are enabled.
+ *
+ * If you add or remove a call to ct_irq_enter_irqson(), be sure to test
+ * with CONFIG_RCU_EQS_DEBUG=y.
+ */
+void ct_irq_enter_irqson(void)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       ct_irq_enter();
+       local_irq_restore(flags);
+}
+
+/*
+ * Wrapper for ct_irq_exit() where interrupts are enabled.
+ *
+ * If you add or remove a call to ct_irq_exit_irqson(), be sure to test
+ * with CONFIG_RCU_EQS_DEBUG=y.
+ */
+void ct_irq_exit_irqson(void)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       ct_irq_exit();
+       local_irq_restore(flags);
+}
+#else
+static __always_inline void ct_kernel_exit(bool user, int offset) { }
+static __always_inline void ct_kernel_enter(bool user, int offset) { }
+#endif /* #ifdef CONFIG_CONTEXT_TRACKING_IDLE */
+
+#ifdef CONFIG_CONTEXT_TRACKING_USER
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/context_tracking.h>
 DEFINE_STATIC_KEY_FALSE(context_tracking_key);
 EXPORT_SYMBOL_GPL(context_tracking_key);
 
-DEFINE_PER_CPU(struct context_tracking, context_tracking);
-EXPORT_SYMBOL_GPL(context_tracking);
-
 static noinstr bool context_tracking_recursion_enter(void)
 {
        int recursion;
@@ -51,29 +455,32 @@ static __always_inline void context_tracking_recursion_exit(void)
 }
 
 /**
- * context_tracking_enter - Inform the context tracking that the CPU is going
- *                          enter user or guest space mode.
+ * __ct_user_enter - Inform the context tracking that the CPU is going
+ *                  to enter user or guest space mode.
  *
  * 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
  * because this function sets RCU in extended quiescent state.
  */
-void noinstr __context_tracking_enter(enum ctx_state state)
+void noinstr __ct_user_enter(enum ctx_state state)
 {
+       struct context_tracking *ct = this_cpu_ptr(&context_tracking);
+       lockdep_assert_irqs_disabled();
+
        /* Kernel threads aren't supposed to go to userspace */
        WARN_ON_ONCE(!current->mm);
 
        if (!context_tracking_recursion_enter())
                return;
 
-       if ( __this_cpu_read(context_tracking.state) != state) {
-               if (__this_cpu_read(context_tracking.active)) {
+       if (__ct_state() != state) {
+               if (ct->active) {
                        /*
                         * At this stage, only low level arch entry code remains and
                         * then we'll run in userspace. We can assume there won't be
                         * any RCU read-side critical section until the next call to
-                        * user_exit() or rcu_irq_enter(). Let's remove RCU's dependency
+                        * user_exit() or ct_irq_enter(). Let's remove RCU's dependency
                         * on the tick.
                         */
                        if (state == CONTEXT_USER) {
@@ -82,35 +489,77 @@ void noinstr __context_tracking_enter(enum ctx_state state)
                                vtime_user_enter(current);
                                instrumentation_end();
                        }
-                       rcu_user_enter();
+                       /*
+                        * Other than generic entry implementation, we may be past the last
+                        * rescheduling opportunity in the entry code. Trigger a self IPI
+                        * that will fire and reschedule once we resume in user/guest mode.
+                        */
+                       rcu_irq_work_resched();
+
+                       /*
+                        * Enter RCU idle mode right before resuming userspace.  No use of RCU
+                        * is permitted between this call and rcu_eqs_exit(). This way the
+                        * CPU doesn't need to maintain the tick for RCU maintenance purposes
+                        * when the CPU runs in userspace.
+                        */
+                       ct_kernel_exit(true, RCU_DYNTICKS_IDX + state);
+
+                       /*
+                        * Special case if we only track user <-> kernel transitions for tickless
+                        * cputime accounting but we don't support RCU extended quiescent state.
+                        * In this we case we don't care about any concurrency/ordering.
+                        */
+                       if (!IS_ENABLED(CONFIG_CONTEXT_TRACKING_IDLE))
+                               atomic_set(&ct->state, state);
+               } else {
+                       /*
+                        * Even if context tracking is disabled on this CPU, because it's outside
+                        * the full dynticks mask for example, we still have to keep track of the
+                        * context transitions and states to prevent inconsistency on those of
+                        * other CPUs.
+                        * If a task triggers an exception in userspace, sleep on the exception
+                        * handler and then migrate to another CPU, that new CPU must know where
+                        * the exception returns by the time we call exception_exit().
+                        * This information can only be provided by the previous CPU when it called
+                        * exception_enter().
+                        * OTOH we can spare the calls to vtime and RCU when context_tracking.active
+                        * is false because we know that CPU is not tickless.
+                        */
+                       if (!IS_ENABLED(CONFIG_CONTEXT_TRACKING_IDLE)) {
+                               /* Tracking for vtime only, no concurrent RCU EQS accounting */
+                               atomic_set(&ct->state, state);
+                       } else {
+                               /*
+                                * Tracking for vtime and RCU EQS. Make sure we don't race
+                                * with NMIs. OTOH we don't care about ordering here since
+                                * RCU only requires RCU_DYNTICKS_IDX increments to be fully
+                                * ordered.
+                                */
+                               atomic_add(state, &ct->state);
+                       }
                }
-               /*
-                * Even if context tracking is disabled on this CPU, because it's outside
-                * the full dynticks mask for example, we still have to keep track of the
-                * context transitions and states to prevent inconsistency on those of
-                * other CPUs.
-                * If a task triggers an exception in userspace, sleep on the exception
-                * handler and then migrate to another CPU, that new CPU must know where
-                * the exception returns by the time we call exception_exit().
-                * This information can only be provided by the previous CPU when it called
-                * exception_enter().
-                * OTOH we can spare the calls to vtime and RCU when context_tracking.active
-                * is false because we know that CPU is not tickless.
-                */
-               __this_cpu_write(context_tracking.state, state);
        }
        context_tracking_recursion_exit();
 }
-EXPORT_SYMBOL_GPL(__context_tracking_enter);
+EXPORT_SYMBOL_GPL(__ct_user_enter);
 
-void context_tracking_enter(enum ctx_state state)
+/*
+ * OBSOLETE:
+ * This function should be noinstr but the below local_irq_restore() is
+ * unsafe because it involves illegal RCU uses through tracing and lockdep.
+ * This is unlikely to be fixed as this function is obsolete. The preferred
+ * way is to call __context_tracking_enter() through user_enter_irqoff()
+ * or context_tracking_guest_enter(). It should be the arch entry code
+ * responsibility to call into context tracking with IRQs disabled.
+ */
+void ct_user_enter(enum ctx_state state)
 {
        unsigned long flags;
 
        /*
         * Some contexts may involve an exception occuring in an irq,
         * leading to that nesting:
-        * rcu_irq_enter() rcu_user_exit() rcu_user_exit() rcu_irq_exit()
+        * ct_irq_enter() rcu_eqs_exit(true) rcu_eqs_enter(true) ct_irq_exit()
         * This would mess up the dyntick_nesting count though. And rcu_irq_*()
         * helpers are enough to protect RCU uses inside the exception. So
         * just return immediately if we detect we are in an IRQ.
@@ -119,21 +568,32 @@ void context_tracking_enter(enum ctx_state state)
                return;
 
        local_irq_save(flags);
-       __context_tracking_enter(state);
+       __ct_user_enter(state);
        local_irq_restore(flags);
 }
-NOKPROBE_SYMBOL(context_tracking_enter);
-EXPORT_SYMBOL_GPL(context_tracking_enter);
+NOKPROBE_SYMBOL(ct_user_enter);
+EXPORT_SYMBOL_GPL(ct_user_enter);
 
-void context_tracking_user_enter(void)
+/**
+ * user_enter_callable() - Unfortunate ASM callable version of user_enter() for
+ *                        archs that didn't manage to check the context tracking
+ *                        static key from low level code.
+ *
+ * This OBSOLETE function should be noinstr but it unsafely calls
+ * local_irq_restore(), involving illegal RCU uses through tracing and lockdep.
+ * This is unlikely to be fixed as this function is obsolete. The preferred
+ * way is to call user_enter_irqoff(). It should be the arch entry code
+ * responsibility to call into context tracking with IRQs disabled.
+ */
+void user_enter_callable(void)
 {
        user_enter();
 }
-NOKPROBE_SYMBOL(context_tracking_user_enter);
+NOKPROBE_SYMBOL(user_enter_callable);
 
 /**
- * context_tracking_exit - Inform the context tracking that the CPU is
- *                         exiting user or guest mode and entering the kernel.
+ * __ct_user_exit - Inform the context tracking that the CPU is
+ *                 exiting user or guest mode and entering the kernel.
  *
  * 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
@@ -143,32 +603,64 @@ NOKPROBE_SYMBOL(context_tracking_user_enter);
  * This call supports re-entrancy. This way it can be called from any exception
  * handler without needing to know if we came from userspace or not.
  */
-void noinstr __context_tracking_exit(enum ctx_state state)
+void noinstr __ct_user_exit(enum ctx_state state)
 {
+       struct context_tracking *ct = this_cpu_ptr(&context_tracking);
+
        if (!context_tracking_recursion_enter())
                return;
 
-       if (__this_cpu_read(context_tracking.state) == state) {
-               if (__this_cpu_read(context_tracking.active)) {
+       if (__ct_state() == state) {
+               if (ct->active) {
                        /*
-                        * We are going to run code that may use RCU. Inform
-                        * RCU core about that (ie: we may need the tick again).
+                        * Exit RCU idle mode while entering the kernel because it can
+                        * run a RCU read side critical section anytime.
                         */
-                       rcu_user_exit();
+                       ct_kernel_enter(true, RCU_DYNTICKS_IDX - state);
                        if (state == CONTEXT_USER) {
                                instrumentation_begin();
                                vtime_user_exit(current);
                                trace_user_exit(0);
                                instrumentation_end();
                        }
+
+                       /*
+                        * Special case if we only track user <-> kernel transitions for tickless
+                        * cputime accounting but we don't support RCU extended quiescent state.
+                        * In this we case we don't care about any concurrency/ordering.
+                        */
+                       if (!IS_ENABLED(CONFIG_CONTEXT_TRACKING_IDLE))
+                               atomic_set(&ct->state, CONTEXT_KERNEL);
+
+               } else {
+                       if (!IS_ENABLED(CONFIG_CONTEXT_TRACKING_IDLE)) {
+                               /* Tracking for vtime only, no concurrent RCU EQS accounting */
+                               atomic_set(&ct->state, CONTEXT_KERNEL);
+                       } else {
+                               /*
+                                * Tracking for vtime and RCU EQS. Make sure we don't race
+                                * with NMIs. OTOH we don't care about ordering here since
+                                * RCU only requires RCU_DYNTICKS_IDX increments to be fully
+                                * ordered.
+                                */
+                               atomic_sub(state, &ct->state);
+                       }
                }
-               __this_cpu_write(context_tracking.state, CONTEXT_KERNEL);
        }
        context_tracking_recursion_exit();
 }
-EXPORT_SYMBOL_GPL(__context_tracking_exit);
+EXPORT_SYMBOL_GPL(__ct_user_exit);
 
-void context_tracking_exit(enum ctx_state state)
+/*
+ * OBSOLETE:
+ * This function should be noinstr but the below local_irq_save() is
+ * unsafe because it involves illegal RCU uses through tracing and lockdep.
+ * This is unlikely to be fixed as this function is obsolete. The preferred
+ * way is to call __context_tracking_exit() through user_exit_irqoff()
+ * or context_tracking_guest_exit(). It should be the arch entry code
+ * responsibility to call into context tracking with IRQs disabled.
+ */
+void ct_user_exit(enum ctx_state state)
 {
        unsigned long flags;
 
@@ -176,19 +668,30 @@ void context_tracking_exit(enum ctx_state state)
                return;
 
        local_irq_save(flags);
-       __context_tracking_exit(state);
+       __ct_user_exit(state);
        local_irq_restore(flags);
 }
-NOKPROBE_SYMBOL(context_tracking_exit);
-EXPORT_SYMBOL_GPL(context_tracking_exit);
+NOKPROBE_SYMBOL(ct_user_exit);
+EXPORT_SYMBOL_GPL(ct_user_exit);
 
-void context_tracking_user_exit(void)
+/**
+ * user_exit_callable() - Unfortunate ASM callable version of user_exit() for
+ *                       archs that didn't manage to check the context tracking
+ *                       static key from low level code.
+ *
+ * This OBSOLETE function should be noinstr but it unsafely calls local_irq_save(),
+ * involving illegal RCU uses through tracing and lockdep. This is unlikely
+ * to be fixed as this function is obsolete. The preferred way is to call
+ * user_exit_irqoff(). It should be the arch entry code responsibility to
+ * call into context tracking with IRQs disabled.
+ */
+void user_exit_callable(void)
 {
        user_exit();
 }
-NOKPROBE_SYMBOL(context_tracking_user_exit);
+NOKPROBE_SYMBOL(user_exit_callable);
 
-void __init context_tracking_cpu_set(int cpu)
+void __init ct_cpu_track_user(int cpu)
 {
        static __initdata bool initialized = false;
 
@@ -212,12 +715,14 @@ void __init context_tracking_cpu_set(int cpu)
        initialized = true;
 }
 
-#ifdef CONFIG_CONTEXT_TRACKING_FORCE
+#ifdef CONFIG_CONTEXT_TRACKING_USER_FORCE
 void __init context_tracking_init(void)
 {
        int cpu;
 
        for_each_possible_cpu(cpu)
-               context_tracking_cpu_set(cpu);
+               ct_cpu_track_user(cpu);
 }
 #endif
+
+#endif /* #ifdef CONFIG_CONTEXT_TRACKING_USER */
index 246efc7..ba4ba71 100644 (file)
@@ -35,11 +35,11 @@ static int cpu_pm_notify(enum cpu_pm_event event)
         * disfunctional in cpu idle. Copy RCU_NONIDLE code to let RCU know
         * this.
         */
-       rcu_irq_enter_irqson();
+       ct_irq_enter_irqson();
        rcu_read_lock();
        ret = raw_notifier_call_chain(&cpu_pm_notifier.chain, event, NULL);
        rcu_read_unlock();
-       rcu_irq_exit_irqson();
+       ct_irq_exit_irqson();
 
        return notifier_to_errno(ret);
 }
@@ -49,11 +49,11 @@ static int cpu_pm_notify_robust(enum cpu_pm_event event_up, enum cpu_pm_event ev
        unsigned long flags;
        int ret;
 
-       rcu_irq_enter_irqson();
+       ct_irq_enter_irqson();
        raw_spin_lock_irqsave(&cpu_pm_notifier.lock, flags);
        ret = raw_notifier_call_chain_robust(&cpu_pm_notifier.chain, event_up, event_down, NULL);
        raw_spin_unlock_irqrestore(&cpu_pm_notifier.lock, flags);
-       rcu_irq_exit_irqson();
+       ct_irq_exit_irqson();
 
        return notifier_to_errno(ret);
 }
index e978f36..8d0b68a 100644 (file)
@@ -357,7 +357,7 @@ void dma_direct_free(struct device *dev, size_t size,
        } else {
                if (IS_ENABLED(CONFIG_ARCH_HAS_DMA_CLEAR_UNCACHED))
                        arch_dma_clear_uncached(cpu_addr, size);
-               if (dma_set_encrypted(dev, cpu_addr, 1 << page_order))
+               if (dma_set_encrypted(dev, cpu_addr, size))
                        return;
        }
 
@@ -392,7 +392,6 @@ void dma_direct_free_pages(struct device *dev, size_t size,
                struct page *page, dma_addr_t dma_addr,
                enum dma_data_direction dir)
 {
-       unsigned int page_order = get_order(size);
        void *vaddr = page_address(page);
 
        /* If cpu_addr is not from an atomic pool, dma_free_from_pool() fails */
@@ -400,7 +399,7 @@ void dma_direct_free_pages(struct device *dev, size_t size,
            dma_free_from_pool(dev, vaddr, size))
                return;
 
-       if (dma_set_encrypted(dev, vaddr, 1 << page_order))
+       if (dma_set_encrypted(dev, vaddr, size))
                return;
        __dma_direct_free_pages(dev, page, size);
 }
index 032f164..063068a 100644 (file)
@@ -321,7 +321,7 @@ noinstr irqentry_state_t irqentry_enter(struct pt_regs *regs)
        }
 
        /*
-        * If this entry hit the idle task invoke rcu_irq_enter() whether
+        * If this entry hit the idle task invoke ct_irq_enter() whether
         * RCU is watching or not.
         *
         * Interrupts can nest when the first interrupt invokes softirq
@@ -332,12 +332,12 @@ noinstr irqentry_state_t irqentry_enter(struct pt_regs *regs)
         * not nested into another interrupt.
         *
         * Checking for rcu_is_watching() here would prevent the nesting
-        * interrupt to invoke rcu_irq_enter(). If that nested interrupt is
+        * interrupt to invoke ct_irq_enter(). If that nested interrupt is
         * the tick then rcu_flavor_sched_clock_irq() would wrongfully
         * assume that it is the first interrupt and eventually claim
         * quiescent state and end grace periods prematurely.
         *
-        * Unconditionally invoke rcu_irq_enter() so RCU state stays
+        * Unconditionally invoke ct_irq_enter() so RCU state stays
         * consistent.
         *
         * TINY_RCU does not support EQS, so let the compiler eliminate
@@ -350,7 +350,7 @@ noinstr irqentry_state_t irqentry_enter(struct pt_regs *regs)
                 * as in irqentry_enter_from_user_mode().
                 */
                lockdep_hardirqs_off(CALLER_ADDR0);
-               rcu_irq_enter();
+               ct_irq_enter();
                instrumentation_begin();
                trace_hardirqs_off_finish();
                instrumentation_end();
@@ -418,7 +418,7 @@ noinstr void irqentry_exit(struct pt_regs *regs, irqentry_state_t state)
                        trace_hardirqs_on_prepare();
                        lockdep_hardirqs_on_prepare();
                        instrumentation_end();
-                       rcu_irq_exit();
+                       ct_irq_exit();
                        lockdep_hardirqs_on(CALLER_ADDR0);
                        return;
                }
@@ -436,7 +436,7 @@ noinstr void irqentry_exit(struct pt_regs *regs, irqentry_state_t state)
                 * was not watching on entry.
                 */
                if (state.exit_rcu)
-                       rcu_irq_exit();
+                       ct_irq_exit();
        }
 }
 
@@ -449,7 +449,7 @@ irqentry_state_t noinstr irqentry_nmi_enter(struct pt_regs *regs)
        __nmi_enter();
        lockdep_hardirqs_off(CALLER_ADDR0);
        lockdep_hardirq_enter();
-       rcu_nmi_enter();
+       ct_nmi_enter();
 
        instrumentation_begin();
        trace_hardirqs_off_finish();
@@ -469,7 +469,7 @@ void noinstr irqentry_nmi_exit(struct pt_regs *regs, irqentry_state_t irq_state)
        }
        instrumentation_end();
 
-       rcu_nmi_exit();
+       ct_nmi_exit();
        lockdep_hardirq_exit();
        if (irq_state.lockdep)
                lockdep_hardirqs_on(CALLER_ADDR0);
index 80782cd..c9d32d4 100644 (file)
@@ -1819,6 +1819,9 @@ static void __perf_event_read_size(struct perf_event *event, int nr_siblings)
        if (event->attr.read_format & PERF_FORMAT_ID)
                entry += sizeof(u64);
 
+       if (event->attr.read_format & PERF_FORMAT_LOST)
+               entry += sizeof(u64);
+
        if (event->attr.read_format & PERF_FORMAT_GROUP) {
                nr += nr_siblings;
                size += sizeof(u64);
@@ -5260,11 +5263,15 @@ static int __perf_read_group_add(struct perf_event *leader,
        values[n++] += perf_event_count(leader);
        if (read_format & PERF_FORMAT_ID)
                values[n++] = primary_event_id(leader);
+       if (read_format & PERF_FORMAT_LOST)
+               values[n++] = atomic64_read(&leader->lost_samples);
 
        for_each_sibling_event(sub, leader) {
                values[n++] += perf_event_count(sub);
                if (read_format & PERF_FORMAT_ID)
                        values[n++] = primary_event_id(sub);
+               if (read_format & PERF_FORMAT_LOST)
+                       values[n++] = atomic64_read(&sub->lost_samples);
        }
 
        raw_spin_unlock_irqrestore(&ctx->lock, flags);
@@ -5321,7 +5328,7 @@ static int perf_read_one(struct perf_event *event,
                                 u64 read_format, char __user *buf)
 {
        u64 enabled, running;
-       u64 values[4];
+       u64 values[5];
        int n = 0;
 
        values[n++] = __perf_event_read_value(event, &enabled, &running);
@@ -5331,6 +5338,8 @@ static int perf_read_one(struct perf_event *event,
                values[n++] = running;
        if (read_format & PERF_FORMAT_ID)
                values[n++] = primary_event_id(event);
+       if (read_format & PERF_FORMAT_LOST)
+               values[n++] = atomic64_read(&event->lost_samples);
 
        if (copy_to_user(buf, values, n * sizeof(u64)))
                return -EFAULT;
@@ -6253,10 +6262,10 @@ again:
 
                if (!atomic_inc_not_zero(&event->rb->mmap_count)) {
                        /*
-                        * Raced against perf_mmap_close() through
-                        * perf_event_set_output(). Try again, hope for better
-                        * luck.
+                        * Raced against perf_mmap_close(); remove the
+                        * event and try again.
                         */
+                       ring_buffer_attach(event, NULL);
                        mutex_unlock(&event->mmap_mutex);
                        goto again;
                }
@@ -6858,7 +6867,7 @@ static void perf_output_read_one(struct perf_output_handle *handle,
                                 u64 enabled, u64 running)
 {
        u64 read_format = event->attr.read_format;
-       u64 values[4];
+       u64 values[5];
        int n = 0;
 
        values[n++] = perf_event_count(event);
@@ -6872,6 +6881,8 @@ static void perf_output_read_one(struct perf_output_handle *handle,
        }
        if (read_format & PERF_FORMAT_ID)
                values[n++] = primary_event_id(event);
+       if (read_format & PERF_FORMAT_LOST)
+               values[n++] = atomic64_read(&event->lost_samples);
 
        __output_copy(handle, values, n * sizeof(u64));
 }
@@ -6882,7 +6893,7 @@ static void perf_output_read_group(struct perf_output_handle *handle,
 {
        struct perf_event *leader = event->group_leader, *sub;
        u64 read_format = event->attr.read_format;
-       u64 values[5];
+       u64 values[6];
        int n = 0;
 
        values[n++] = 1 + leader->nr_siblings;
@@ -6900,6 +6911,8 @@ static void perf_output_read_group(struct perf_output_handle *handle,
        values[n++] = perf_event_count(leader);
        if (read_format & PERF_FORMAT_ID)
                values[n++] = primary_event_id(leader);
+       if (read_format & PERF_FORMAT_LOST)
+               values[n++] = atomic64_read(&leader->lost_samples);
 
        __output_copy(handle, values, n * sizeof(u64));
 
@@ -6913,6 +6926,8 @@ static void perf_output_read_group(struct perf_output_handle *handle,
                values[n++] = perf_event_count(sub);
                if (read_format & PERF_FORMAT_ID)
                        values[n++] = primary_event_id(sub);
+               if (read_format & PERF_FORMAT_LOST)
+                       values[n++] = atomic64_read(&sub->lost_samples);
 
                __output_copy(handle, values, n * sizeof(u64));
        }
@@ -11825,14 +11840,25 @@ err_size:
        goto out;
 }
 
+static void mutex_lock_double(struct mutex *a, struct mutex *b)
+{
+       if (b < a)
+               swap(a, b);
+
+       mutex_lock(a);
+       mutex_lock_nested(b, SINGLE_DEPTH_NESTING);
+}
+
 static int
 perf_event_set_output(struct perf_event *event, struct perf_event *output_event)
 {
        struct perf_buffer *rb = NULL;
        int ret = -EINVAL;
 
-       if (!output_event)
+       if (!output_event) {
+               mutex_lock(&event->mmap_mutex);
                goto set;
+       }
 
        /* don't allow circular references */
        if (event == output_event)
@@ -11870,8 +11896,15 @@ perf_event_set_output(struct perf_event *event, struct perf_event *output_event)
            event->pmu != output_event->pmu)
                goto out;
 
+       /*
+        * Hold both mmap_mutex to serialize against perf_mmap_close().  Since
+        * output_event is already on rb->event_list, and the list iteration
+        * restarts after every removal, it is guaranteed this new event is
+        * observed *OR* if output_event is already removed, it's guaranteed we
+        * observe !rb->mmap_count.
+        */
+       mutex_lock_double(&event->mmap_mutex, &output_event->mmap_mutex);
 set:
-       mutex_lock(&event->mmap_mutex);
        /* Can't redirect output if we've got an active mmap() */
        if (atomic_read(&event->mmap_count))
                goto unlock;
@@ -11881,6 +11914,12 @@ set:
                rb = ring_buffer_get(output_event);
                if (!rb)
                        goto unlock;
+
+               /* did we race against perf_mmap_close() */
+               if (!atomic_read(&rb->mmap_count)) {
+                       ring_buffer_put(rb);
+                       goto unlock;
+               }
        }
 
        ring_buffer_attach(event, rb);
@@ -11888,20 +11927,13 @@ set:
        ret = 0;
 unlock:
        mutex_unlock(&event->mmap_mutex);
+       if (output_event)
+               mutex_unlock(&output_event->mmap_mutex);
 
 out:
        return ret;
 }
 
-static void mutex_lock_double(struct mutex *a, struct mutex *b)
-{
-       if (b < a)
-               swap(a, b);
-
-       mutex_lock(a);
-       mutex_lock_nested(b, SINGLE_DEPTH_NESTING);
-}
-
 static int perf_event_set_clock(struct perf_event *event, clockid_t clk_id)
 {
        bool nmi_safe = false;
index fb35b92..7261320 100644 (file)
@@ -172,8 +172,10 @@ __perf_output_begin(struct perf_output_handle *handle,
                goto out;
 
        if (unlikely(rb->paused)) {
-               if (rb->nr_pages)
+               if (rb->nr_pages) {
                        local_inc(&rb->lost);
+                       atomic64_inc(&event->lost_samples);
+               }
                goto out;
        }
 
@@ -254,6 +256,7 @@ __perf_output_begin(struct perf_output_handle *handle,
 
 fail:
        local_inc(&rb->lost);
+       atomic64_inc(&event->lost_samples);
        perf_output_put_handle(handle);
 out:
        rcu_read_unlock();
index f072959..64c938c 100644 (file)
@@ -766,7 +766,7 @@ void __noreturn do_exit(long code)
 
 #ifdef CONFIG_POSIX_TIMERS
                hrtimer_cancel(&tsk->signal->real_timer);
-               exit_itimers(tsk->signal);
+               exit_itimers(tsk);
 #endif
                if (tsk->mm)
                        setmax_mm_hiwater_rss(&tsk->signal->maxrss, tsk->mm);
index bda5e97..71f4825 100644 (file)
@@ -114,7 +114,7 @@ int kernel_text_address(unsigned long addr)
 
        /* Treat this like an NMI as it can happen anywhere */
        if (no_rcu)
-               rcu_nmi_enter();
+               ct_nmi_enter();
 
        if (is_module_text_address(addr))
                goto out;
@@ -127,7 +127,7 @@ int kernel_text_address(unsigned long addr)
        ret = 0;
 out:
        if (no_rcu)
-               rcu_nmi_exit();
+               ct_nmi_exit();
 
        return ret;
 }
index 9d44f2d..2877214 100644 (file)
@@ -1814,6 +1814,7 @@ static inline void rcu_copy_process(struct task_struct *p)
        p->trc_reader_nesting = 0;
        p->trc_reader_special.s = 0;
        INIT_LIST_HEAD(&p->trc_holdout_list);
+       INIT_LIST_HEAD(&p->trc_blkd_node);
 #endif /* #ifdef CONFIG_TASKS_TRACE_RCU */
 }
 
@@ -2033,8 +2034,11 @@ static __latent_entropy struct task_struct *copy_process(
        /*
         * If the new process will be in a different time namespace
         * do not allow it to share VM or a thread group with the forking task.
+        *
+        * On vfork, the child process enters the target time namespace only
+        * after exec.
         */
-       if (clone_flags & (CLONE_THREAD | CLONE_VM)) {
+       if ((clone_flags & (CLONE_VM | CLONE_VFORK)) == CLONE_VM) {
                if (nsp->time_ns != nsp->time_ns_for_children)
                        return ERR_PTR(-EINVAL);
        }
index 787b381..9aaed2a 100644 (file)
@@ -134,13 +134,26 @@ EXPORT_SYMBOL(set_groups);
 int set_current_groups(struct group_info *group_info)
 {
        struct cred *new;
+       const struct cred *old;
+       int retval;
 
        new = prepare_creds();
        if (!new)
                return -ENOMEM;
 
+       old = current_cred();
+
        set_groups(new, group_info);
+
+       retval = security_task_fix_setgroups(new, old);
+       if (retval < 0)
+               goto error;
+
        return commit_creds(new);
+
+error:
+       abort_creds(new);
+       return retval;
 }
 
 EXPORT_SYMBOL(set_current_groups);
index 10929ed..db3d174 100644 (file)
@@ -24,6 +24,7 @@ config GENERIC_IRQ_SHOW_LEVEL
 
 # Supports effective affinity mask
 config GENERIC_IRQ_EFFECTIVE_AFF_MASK
+       depends on SMP
        bool
 
 # Support for delayed migration from interrupt context
@@ -82,6 +83,7 @@ config IRQ_FASTEOI_HIERARCHY_HANDLERS
 # Generic IRQ IPI support
 config GENERIC_IRQ_IPI
        bool
+       depends on SMP
        select IRQ_DOMAIN_HIERARCHY
 
 # Generic MSI interrupt support
index 886789d..8ac37e8 100644 (file)
@@ -188,7 +188,8 @@ enum {
 
 #ifdef CONFIG_SMP
 static int
-__irq_startup_managed(struct irq_desc *desc, struct cpumask *aff, bool force)
+__irq_startup_managed(struct irq_desc *desc, const struct cpumask *aff,
+                     bool force)
 {
        struct irq_data *d = irq_desc_get_irq_data(desc);
 
@@ -224,7 +225,8 @@ __irq_startup_managed(struct irq_desc *desc, struct cpumask *aff, bool force)
 }
 #else
 static __always_inline int
-__irq_startup_managed(struct irq_desc *desc, struct cpumask *aff, bool force)
+__irq_startup_managed(struct irq_desc *desc, const struct cpumask *aff,
+                     bool force)
 {
        return IRQ_STARTUP_NORMAL;
 }
@@ -252,7 +254,7 @@ static int __irq_startup(struct irq_desc *desc)
 int irq_startup(struct irq_desc *desc, bool resend, bool force)
 {
        struct irq_data *d = irq_desc_get_irq_data(desc);
-       struct cpumask *aff = irq_data_get_affinity_mask(d);
+       const struct cpumask *aff = irq_data_get_affinity_mask(d);
        int ret = 0;
 
        desc->depth = 0;
@@ -1516,7 +1518,8 @@ int irq_chip_request_resources_parent(struct irq_data *data)
        if (data->chip->irq_request_resources)
                return data->chip->irq_request_resources(data);
 
-       return -ENOSYS;
+       /* no error on missing optional irq_chip::irq_request_resources */
+       return 0;
 }
 EXPORT_SYMBOL_GPL(irq_chip_request_resources_parent);
 
index bc8e40c..bbcaac6 100644 (file)
@@ -30,7 +30,7 @@ static void irq_debug_show_bits(struct seq_file *m, int ind, unsigned int state,
 static void irq_debug_show_masks(struct seq_file *m, struct irq_desc *desc)
 {
        struct irq_data *data = irq_desc_get_irq_data(desc);
-       struct cpumask *msk;
+       const struct cpumask *msk;
 
        msk = irq_data_get_affinity_mask(data);
        seq_printf(m, "affinity: %*pbl\n", cpumask_pr_args(msk));
index f0862eb..c653cd3 100644 (file)
@@ -431,7 +431,7 @@ int irq_map_generic_chip(struct irq_domain *d, unsigned int virq,
        return 0;
 }
 
-static void irq_unmap_generic_chip(struct irq_domain *d, unsigned int virq)
+void irq_unmap_generic_chip(struct irq_domain *d, unsigned int virq)
 {
        struct irq_data *data = irq_domain_get_irq_data(d, virq);
        struct irq_domain_chip_generic *dgc = d->gc;
index 08ce7da..bbd945b 100644 (file)
@@ -115,11 +115,11 @@ free_descs:
 int irq_destroy_ipi(unsigned int irq, const struct cpumask *dest)
 {
        struct irq_data *data = irq_get_irq_data(irq);
-       struct cpumask *ipimask = data ? irq_data_get_affinity_mask(data) : NULL;
+       const struct cpumask *ipimask;
        struct irq_domain *domain;
        unsigned int nr_irqs;
 
-       if (!irq || !data || !ipimask)
+       if (!irq || !data)
                return -EINVAL;
 
        domain = data->domain;
@@ -131,7 +131,8 @@ int irq_destroy_ipi(unsigned int irq, const struct cpumask *dest)
                return -EINVAL;
        }
 
-       if (WARN_ON(!cpumask_subset(dest, ipimask)))
+       ipimask = irq_data_get_affinity_mask(data);
+       if (!ipimask || WARN_ON(!cpumask_subset(dest, ipimask)))
                /*
                 * Must be destroying a subset of CPUs to which this IPI
                 * was set up to target
@@ -162,12 +163,13 @@ int irq_destroy_ipi(unsigned int irq, const struct cpumask *dest)
 irq_hw_number_t ipi_get_hwirq(unsigned int irq, unsigned int cpu)
 {
        struct irq_data *data = irq_get_irq_data(irq);
-       struct cpumask *ipimask = data ? irq_data_get_affinity_mask(data) : NULL;
+       const struct cpumask *ipimask;
 
-       if (!data || !ipimask || cpu >= nr_cpu_ids)
+       if (!data || cpu >= nr_cpu_ids)
                return INVALID_HWIRQ;
 
-       if (!cpumask_test_cpu(cpu, ipimask))
+       ipimask = irq_data_get_affinity_mask(data);
+       if (!ipimask || !cpumask_test_cpu(cpu, ipimask))
                return INVALID_HWIRQ;
 
        /*
@@ -186,7 +188,7 @@ EXPORT_SYMBOL_GPL(ipi_get_hwirq);
 static int ipi_send_verify(struct irq_chip *chip, struct irq_data *data,
                           const struct cpumask *dest, unsigned int cpu)
 {
-       struct cpumask *ipimask = irq_data_get_affinity_mask(data);
+       const struct cpumask *ipimask = irq_data_get_affinity_mask(data);
 
        if (!chip || !ipimask)
                return -EINVAL;
index d323b18..5db0230 100644 (file)
@@ -251,7 +251,7 @@ static ssize_t actions_show(struct kobject *kobj,
        char *p = "";
 
        raw_spin_lock_irq(&desc->lock);
-       for (action = desc->action; action != NULL; action = action->next) {
+       for_each_action_of_desc(desc, action) {
                ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s%s",
                                 p, action->name);
                p = ",";
index d5ce965..8fe1da9 100644 (file)
@@ -147,7 +147,8 @@ struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, unsigned int s
        static atomic_t unknown_domains;
 
        if (WARN_ON((size && direct_max) ||
-                   (!IS_ENABLED(CONFIG_IRQ_DOMAIN_NOMAP) && direct_max)))
+                   (!IS_ENABLED(CONFIG_IRQ_DOMAIN_NOMAP) && direct_max) ||
+                   (direct_max && (direct_max != hwirq_max))))
                return NULL;
 
        domain = kzalloc_node(struct_size(domain, revmap, size),
@@ -219,7 +220,6 @@ struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, unsigned int s
        domain->hwirq_max = hwirq_max;
 
        if (direct_max) {
-               size = direct_max;
                domain->flags |= IRQ_DOMAIN_FLAG_NO_MAP;
        }
 
@@ -650,9 +650,9 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain)
                pr_debug("create_direct virq allocation failed\n");
                return 0;
        }
-       if (virq >= domain->revmap_size) {
-               pr_err("ERROR: no free irqs available below %i maximum\n",
-                       domain->revmap_size);
+       if (virq >= domain->hwirq_max) {
+               pr_err("ERROR: no free irqs available below %lu maximum\n",
+                       domain->hwirq_max);
                irq_free_desc(virq);
                return 0;
        }
@@ -906,10 +906,12 @@ struct irq_desc *__irq_resolve_mapping(struct irq_domain *domain,
                return desc;
 
        if (irq_domain_is_nomap(domain)) {
-               if (hwirq < domain->revmap_size) {
+               if (hwirq < domain->hwirq_max) {
                        data = irq_domain_get_irq_data(domain, hwirq);
                        if (data && data->hwirq == hwirq)
                                desc = irq_data_to_desc(data);
+                       if (irq && desc)
+                               *irq = hwirq;
                }
 
                return desc;
index 8c39631..40fe780 100644 (file)
@@ -205,16 +205,8 @@ static void irq_validate_effective_affinity(struct irq_data *data)
        pr_warn_once("irq_chip %s did not update eff. affinity mask of irq %u\n",
                     chip->name, data->irq);
 }
-
-static inline void irq_init_effective_affinity(struct irq_data *data,
-                                              const struct cpumask *mask)
-{
-       cpumask_copy(irq_data_get_effective_affinity_mask(data), mask);
-}
 #else
 static inline void irq_validate_effective_affinity(struct irq_data *data) { }
-static inline void irq_init_effective_affinity(struct irq_data *data,
-                                              const struct cpumask *mask) { }
 #endif
 
 int irq_do_set_affinity(struct irq_data *data, const struct cpumask *mask,
@@ -347,7 +339,7 @@ static bool irq_set_affinity_deactivated(struct irq_data *data,
                return false;
 
        cpumask_copy(desc->irq_common_data.affinity, mask);
-       irq_init_effective_affinity(data, mask);
+       irq_data_update_effective_affinity(data, mask);
        irqd_set(data, IRQD_AFFINITY_SET);
        return true;
 }
index ca71123..c556bc4 100644 (file)
@@ -147,7 +147,6 @@ void suspend_device_irqs(void)
                        synchronize_irq(irq);
        }
 }
-EXPORT_SYMBOL_GPL(suspend_device_irqs);
 
 static void resume_irq(struct irq_desc *desc)
 {
@@ -259,4 +258,3 @@ void resume_device_irqs(void)
 {
        resume_irqs(false);
 }
-EXPORT_SYMBOL_GPL(resume_device_irqs);
index b156e15..714ac4c 100644 (file)
@@ -332,17 +332,13 @@ static int __jump_label_text_reserved(struct jump_entry *iter_start,
        return 0;
 }
 
-/*
- * Update code which is definitely not currently executing.
- * Architectures which need heavyweight synchronization to modify
- * running code can override this to make the non-live update case
- * cheaper.
- */
-void __weak __init_or_module arch_jump_label_transform_static(struct jump_entry *entry,
-                                           enum jump_label_type type)
+#ifndef arch_jump_label_transform_static
+static void arch_jump_label_transform_static(struct jump_entry *entry,
+                                            enum jump_label_type type)
 {
-       arch_jump_label_transform(entry, type);
+       /* nothing to do on most architectures */
 }
+#endif
 
 static inline struct jump_entry *static_key_entries(struct static_key *key)
 {
@@ -508,7 +504,7 @@ void __init jump_label_init(void)
 
 #ifdef CONFIG_MODULES
 
-static enum jump_label_type jump_label_init_type(struct jump_entry *entry)
+enum jump_label_type jump_label_init_type(struct jump_entry *entry)
 {
        struct static_key *key = jump_entry_key(entry);
        bool type = static_key_type(key);
@@ -596,31 +592,6 @@ static void __jump_label_mod_update(struct static_key *key)
        }
 }
 
-/***
- * apply_jump_label_nops - patch module jump labels with arch_get_jump_label_nop()
- * @mod: module to patch
- *
- * Allow for run-time selection of the optimal nops. Before the module
- * loads patch these with arch_get_jump_label_nop(), which is specified by
- * the arch specific jump label code.
- */
-void jump_label_apply_nops(struct module *mod)
-{
-       struct jump_entry *iter_start = mod->jump_entries;
-       struct jump_entry *iter_stop = iter_start + mod->num_jump_entries;
-       struct jump_entry *iter;
-
-       /* if the module doesn't have jump label entries, just return */
-       if (iter_start == iter_stop)
-               return;
-
-       for (iter = iter_start; iter < iter_stop; iter++) {
-               /* Only write NOPs for arch_branch_static(). */
-               if (jump_label_init_type(iter) == JUMP_LABEL_NOP)
-                       arch_jump_label_transform_static(iter, JUMP_LABEL_NOP);
-       }
-}
-
 static int jump_label_add_module(struct module *mod)
 {
        struct jump_entry *iter_start = mod->jump_entries;
diff --git a/kernel/kcsan/.kunitconfig b/kernel/kcsan/.kunitconfig
new file mode 100644 (file)
index 0000000..e82f0f5
--- /dev/null
@@ -0,0 +1,24 @@
+# Note that the KCSAN tests need to run on an SMP setup.
+# Under kunit_tool, this can be done by using the --qemu_args
+# option to configure a machine with several cores. For example:
+# ./tools/testing/kunit/kunit.py run --kunitconfig=kernel/kcsan \
+#                               --arch=x86_64 --qemu_args="-smp 8"
+
+CONFIG_KUNIT=y
+
+CONFIG_DEBUG_KERNEL=y
+
+# Need some level of concurrency to test a concurrency sanitizer.
+CONFIG_SMP=y
+
+CONFIG_KCSAN=y
+CONFIG_KCSAN_KUNIT_TEST=y
+
+# Set these if you want to run test_barrier_nothreads
+#CONFIG_KCSAN_STRICT=y
+#CONFIG_KCSAN_WEAK_MEMORY=y
+
+# This prevents the test from timing out on many setups. Feel free to remove
+# (or alter) this, in conjunction with setting a different test timeout with,
+# for example, the --timeout kunit_tool option.
+CONFIG_KCSAN_REPORT_ONCE_IN_MS=100
index 4d34c78..acd029b 100644 (file)
@@ -591,11 +591,6 @@ static void kimage_free_extra_pages(struct kimage *image)
 
 }
 
-int __weak machine_kexec_post_load(struct kimage *image)
-{
-       return 0;
-}
-
 void kimage_terminate(struct kimage *image)
 {
        if (*image->entry != 0)
@@ -1020,15 +1015,6 @@ size_t crash_get_memory_size(void)
        return size;
 }
 
-void __weak crash_free_reserved_phys_range(unsigned long begin,
-                                          unsigned long end)
-{
-       unsigned long addr;
-
-       for (addr = begin; addr < end; addr += PAGE_SIZE)
-               free_reserved_page(boot_pfn_to_page(addr >> PAGE_SHIFT));
-}
-
 int crash_shrink_memory(unsigned long new_size)
 {
        int ret = 0;
@@ -1225,16 +1211,3 @@ int kernel_kexec(void)
        mutex_unlock(&kexec_mutex);
        return error;
 }
-
-/*
- * Protection mechanism for crashkernel reserved memory after
- * the kdump kernel is loaded.
- *
- * Provide an empty default implementation here -- architecture
- * code may override this
- */
-void __weak arch_kexec_protect_crashkres(void)
-{}
-
-void __weak arch_kexec_unprotect_crashkres(void)
-{}
index 145321a..a7b411c 100644 (file)
 #include <linux/vmalloc.h>
 #include "kexec_internal.h"
 
+#ifdef CONFIG_KEXEC_SIG
+static bool sig_enforce = IS_ENABLED(CONFIG_KEXEC_SIG_FORCE);
+
+void set_kexec_sig_enforced(void)
+{
+       sig_enforce = true;
+}
+#endif
+
 static int kexec_calculate_store_digests(struct kimage *image);
 
 /*
@@ -53,14 +62,7 @@ int kexec_image_probe_default(struct kimage *image, void *buf,
        return ret;
 }
 
-/* Architectures can provide this probe function */
-int __weak arch_kexec_kernel_image_probe(struct kimage *image, void *buf,
-                                        unsigned long buf_len)
-{
-       return kexec_image_probe_default(image, buf, buf_len);
-}
-
-static void *kexec_image_load_default(struct kimage *image)
+void *kexec_image_load_default(struct kimage *image)
 {
        if (!image->fops || !image->fops->load)
                return ERR_PTR(-ENOEXEC);
@@ -71,11 +73,6 @@ static void *kexec_image_load_default(struct kimage *image)
                                 image->cmdline_buf_len);
 }
 
-void * __weak arch_kexec_kernel_image_load(struct kimage *image)
-{
-       return kexec_image_load_default(image);
-}
-
 int kexec_image_post_load_cleanup_default(struct kimage *image)
 {
        if (!image->fops || !image->fops->cleanup)
@@ -84,30 +81,6 @@ int kexec_image_post_load_cleanup_default(struct kimage *image)
        return image->fops->cleanup(image->image_loader_data);
 }
 
-int __weak arch_kimage_file_post_load_cleanup(struct kimage *image)
-{
-       return kexec_image_post_load_cleanup_default(image);
-}
-
-#ifdef CONFIG_KEXEC_SIG
-static int kexec_image_verify_sig_default(struct kimage *image, void *buf,
-                                         unsigned long buf_len)
-{
-       if (!image->fops || !image->fops->verify_sig) {
-               pr_debug("kernel loader does not support signature verification.\n");
-               return -EKEYREJECTED;
-       }
-
-       return image->fops->verify_sig(buf, buf_len);
-}
-
-int __weak arch_kexec_kernel_verify_sig(struct kimage *image, void *buf,
-                                       unsigned long buf_len)
-{
-       return kexec_image_verify_sig_default(image, buf, buf_len);
-}
-#endif
-
 /*
  * Free up memory used by kernel, initrd, and command line. This is temporary
  * memory allocation which is not needed any more after these buffers have
@@ -150,16 +123,44 @@ void kimage_file_post_load_cleanup(struct kimage *image)
 }
 
 #ifdef CONFIG_KEXEC_SIG
+#ifdef CONFIG_SIGNED_PE_FILE_VERIFICATION
+int kexec_kernel_verify_pe_sig(const char *kernel, unsigned long kernel_len)
+{
+       int ret;
+
+       ret = verify_pefile_signature(kernel, kernel_len,
+                                     VERIFY_USE_SECONDARY_KEYRING,
+                                     VERIFYING_KEXEC_PE_SIGNATURE);
+       if (ret == -ENOKEY && IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING)) {
+               ret = verify_pefile_signature(kernel, kernel_len,
+                                             VERIFY_USE_PLATFORM_KEYRING,
+                                             VERIFYING_KEXEC_PE_SIGNATURE);
+       }
+       return ret;
+}
+#endif
+
+static int kexec_image_verify_sig(struct kimage *image, void *buf,
+                                 unsigned long buf_len)
+{
+       if (!image->fops || !image->fops->verify_sig) {
+               pr_debug("kernel loader does not support signature verification.\n");
+               return -EKEYREJECTED;
+       }
+
+       return image->fops->verify_sig(buf, buf_len);
+}
+
 static int
 kimage_validate_signature(struct kimage *image)
 {
        int ret;
 
-       ret = arch_kexec_kernel_verify_sig(image, image->kernel_buf,
-                                          image->kernel_buf_len);
+       ret = kexec_image_verify_sig(image, image->kernel_buf,
+                                    image->kernel_buf_len);
        if (ret) {
 
-               if (IS_ENABLED(CONFIG_KEXEC_SIG_FORCE)) {
+               if (sig_enforce) {
                        pr_notice("Enforced kernel signature verification failed (%d).\n", ret);
                        return ret;
                }
@@ -613,19 +614,6 @@ int kexec_locate_mem_hole(struct kexec_buf *kbuf)
 }
 
 /**
- * arch_kexec_locate_mem_hole - Find free memory to place the segments.
- * @kbuf:                       Parameters for the memory search.
- *
- * On success, kbuf->mem will have the start address of the memory region found.
- *
- * Return: 0 on success, negative errno on error.
- */
-int __weak arch_kexec_locate_mem_hole(struct kexec_buf *kbuf)
-{
-       return kexec_locate_mem_hole(kbuf);
-}
-
-/**
  * kexec_add_buffer - place a buffer in a kexec segment
  * @kbuf:      Buffer contents and memory parameters.
  *
index 544fd40..3c67791 100644 (file)
@@ -340,7 +340,7 @@ static int kthread(void *_create)
 
        self = to_kthread(current);
 
-       /* If user was SIGKILLed, I release the structure. */
+       /* Release the structure when caller killed by a fatal signal. */
        done = xchg(&create->done, NULL);
        if (!done) {
                kfree(create);
@@ -398,7 +398,7 @@ static void create_kthread(struct kthread_create_info *create)
        /* We want our own signal handler (we take no signals by default). */
        pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD);
        if (pid < 0) {
-               /* If user was SIGKILLed, I release the structure. */
+               /* Release the structure when caller killed by a fatal signal. */
                struct completion *done = xchg(&create->done, NULL);
 
                if (!done) {
@@ -440,9 +440,9 @@ struct task_struct *__kthread_create_on_node(int (*threadfn)(void *data),
         */
        if (unlikely(wait_for_completion_killable(&done))) {
                /*
-                * If I was SIGKILLed before kthreadd (or new kernel thread)
-                * calls complete(), leave the cleanup of this structure to
-                * that thread.
+                * If I was killed by a fatal signal before kthreadd (or new
+                * kernel thread) calls complete(), leave the cleanup of this
+                * structure to that thread.
                 */
                if (xchg(&create->done, NULL))
                        return ERR_PTR(-EINTR);
@@ -876,7 +876,7 @@ fail_task:
  *
  * Returns a pointer to the allocated worker on success, ERR_PTR(-ENOMEM)
  * when the needed structures could not get allocated, and ERR_PTR(-EINTR)
- * when the worker was SIGKILLed.
+ * when the caller was killed by a fatal signal.
  */
 struct kthread_worker *
 kthread_create_worker(unsigned int flags, const char namefmt[], ...)
@@ -925,7 +925,7 @@ EXPORT_SYMBOL(kthread_create_worker);
  * Return:
  * The pointer to the allocated worker on success, ERR_PTR(-ENOMEM)
  * when the needed structures could not get allocated, and ERR_PTR(-EINTR)
- * when the worker was SIGKILLed.
+ * when the caller was killed by a fatal signal.
  */
 struct kthread_worker *
 kthread_create_worker_on_cpu(int cpu, unsigned int flags,
index f06b91c..64a13eb 100644 (file)
@@ -5238,9 +5238,10 @@ __lock_set_class(struct lockdep_map *lock, const char *name,
                return 0;
        }
 
-       lockdep_init_map_waits(lock, name, key, 0,
-                              lock->wait_type_inner,
-                              lock->wait_type_outer);
+       lockdep_init_map_type(lock, name, key, 0,
+                             lock->wait_type_inner,
+                             lock->wait_type_outer,
+                             lock->lock_type);
        class = register_lock_class(lock, subclass, 0);
        hlock->class_idx = class - lock_classes;
 
@@ -6570,7 +6571,7 @@ void lockdep_rcu_suspicious(const char *file, const int line, const char *s)
 
        /*
         * If a CPU is in the RCU-free window in idle (ie: in the section
-        * between rcu_idle_enter() and rcu_idle_exit(), then RCU
+        * between ct_idle_enter() and ct_idle_exit(), then RCU
         * considers that CPU to be in an "extended quiescent state",
         * which means that RCU will be completely ignoring that CPU.
         * Therefore, rcu_read_lock() and friends have absolutely no
index 9d1db4a..65f0262 100644 (file)
@@ -335,8 +335,6 @@ struct rwsem_waiter {
        struct task_struct *task;
        enum rwsem_waiter_type type;
        unsigned long timeout;
-
-       /* Writer only, not initialized in reader */
        bool handoff_set;
 };
 #define rwsem_first_waiter(sem) \
@@ -459,10 +457,12 @@ static void rwsem_mark_wake(struct rw_semaphore *sem,
                         * to give up the lock), request a HANDOFF to
                         * force the issue.
                         */
-                       if (!(oldcount & RWSEM_FLAG_HANDOFF) &&
-                           time_after(jiffies, waiter->timeout)) {
-                               adjustment -= RWSEM_FLAG_HANDOFF;
-                               lockevent_inc(rwsem_rlock_handoff);
+                       if (time_after(jiffies, waiter->timeout)) {
+                               if (!(oldcount & RWSEM_FLAG_HANDOFF)) {
+                                       adjustment -= RWSEM_FLAG_HANDOFF;
+                                       lockevent_inc(rwsem_rlock_handoff);
+                               }
+                               waiter->handoff_set = true;
                        }
 
                        atomic_long_add(-adjustment, &sem->count);
@@ -599,7 +599,7 @@ rwsem_del_wake_waiter(struct rw_semaphore *sem, struct rwsem_waiter *waiter,
 static inline bool rwsem_try_write_lock(struct rw_semaphore *sem,
                                        struct rwsem_waiter *waiter)
 {
-       bool first = rwsem_first_waiter(sem) == waiter;
+       struct rwsem_waiter *first = rwsem_first_waiter(sem);
        long count, new;
 
        lockdep_assert_held(&sem->wait_lock);
@@ -609,11 +609,20 @@ static inline bool rwsem_try_write_lock(struct rw_semaphore *sem,
                bool has_handoff = !!(count & RWSEM_FLAG_HANDOFF);
 
                if (has_handoff) {
-                       if (!first)
+                       /*
+                        * Honor handoff bit and yield only when the first
+                        * waiter is the one that set it. Otherwisee, we
+                        * still try to acquire the rwsem.
+                        */
+                       if (first->handoff_set && (waiter != first))
                                return false;
 
-                       /* First waiter inherits a previously set handoff bit */
-                       waiter->handoff_set = true;
+                       /*
+                        * First waiter can inherit a previously set handoff
+                        * bit and spin on rwsem if lock acquisition fails.
+                        */
+                       if (waiter == first)
+                               waiter->handoff_set = true;
                }
 
                new = count;
@@ -1027,6 +1036,7 @@ queue:
        waiter.task = current;
        waiter.type = RWSEM_WAITING_FOR_READ;
        waiter.timeout = jiffies + RWSEM_WAIT_TIMEOUT;
+       waiter.handoff_set = false;
 
        raw_spin_lock_irq(&sem->wait_lock);
        if (list_empty(&sem->wait_list)) {
index bc5507a..ec104c2 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/mutex.h>
 #include <linux/rculist.h>
 #include <linux/rcupdate.h>
+#include <linux/mm.h>
 
 #ifndef ARCH_SHF_SMALL
 #define ARCH_SHF_SMALL 0
  * to ensure complete separation of code and data, but
  * only when CONFIG_STRICT_MODULE_RWX=y
  */
-#ifdef CONFIG_STRICT_MODULE_RWX
-# define strict_align(X) PAGE_ALIGN(X)
-#else
-# define strict_align(X) (X)
-#endif
+static inline unsigned int strict_align(unsigned int size)
+{
+       if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX))
+               return PAGE_ALIGN(size);
+       else
+               return size;
+}
 
 extern struct mutex module_mutex;
 extern struct list_head modules;
index 3e11523..77e75be 100644 (file)
@@ -137,6 +137,7 @@ void layout_symtab(struct module *mod, struct load_info *info)
        info->symoffs = ALIGN(mod->data_layout.size, symsect->sh_addralign ?: 1);
        info->stroffs = mod->data_layout.size = info->symoffs + ndst * sizeof(Elf_Sym);
        mod->data_layout.size += strtab_size;
+       /* Note add_kallsyms() computes strtab_size as core_typeoffs - stroffs */
        info->core_typeoffs = mod->data_layout.size;
        mod->data_layout.size += ndst * sizeof(char);
        mod->data_layout.size = strict_align(mod->data_layout.size);
@@ -169,19 +170,20 @@ void add_kallsyms(struct module *mod, const struct load_info *info)
        Elf_Sym *dst;
        char *s;
        Elf_Shdr *symsec = &info->sechdrs[info->index.sym];
+       unsigned long strtab_size;
 
        /* Set up to point into init section. */
        mod->kallsyms = (void __rcu *)mod->init_layout.base +
                info->mod_kallsyms_init_off;
 
-       preempt_disable();
+       rcu_read_lock();
        /* The following is safe since this pointer cannot change */
-       rcu_dereference_sched(mod->kallsyms)->symtab = (void *)symsec->sh_addr;
-       rcu_dereference_sched(mod->kallsyms)->num_symtab = symsec->sh_size / sizeof(Elf_Sym);
+       rcu_dereference(mod->kallsyms)->symtab = (void *)symsec->sh_addr;
+       rcu_dereference(mod->kallsyms)->num_symtab = symsec->sh_size / sizeof(Elf_Sym);
        /* Make sure we get permanent strtab: don't use info->strtab. */
-       rcu_dereference_sched(mod->kallsyms)->strtab =
+       rcu_dereference(mod->kallsyms)->strtab =
                (void *)info->sechdrs[info->index.str].sh_addr;
-       rcu_dereference_sched(mod->kallsyms)->typetab = mod->init_layout.base + info->init_typeoffs;
+       rcu_dereference(mod->kallsyms)->typetab = mod->init_layout.base + info->init_typeoffs;
 
        /*
         * Now populate the cut down core kallsyms for after init
@@ -190,22 +192,29 @@ void add_kallsyms(struct module *mod, const struct load_info *info)
        mod->core_kallsyms.symtab = dst = mod->data_layout.base + info->symoffs;
        mod->core_kallsyms.strtab = s = mod->data_layout.base + info->stroffs;
        mod->core_kallsyms.typetab = mod->data_layout.base + info->core_typeoffs;
-       src = rcu_dereference_sched(mod->kallsyms)->symtab;
-       for (ndst = i = 0; i < rcu_dereference_sched(mod->kallsyms)->num_symtab; i++) {
-               rcu_dereference_sched(mod->kallsyms)->typetab[i] = elf_type(src + i, info);
+       strtab_size = info->core_typeoffs - info->stroffs;
+       src = rcu_dereference(mod->kallsyms)->symtab;
+       for (ndst = i = 0; i < rcu_dereference(mod->kallsyms)->num_symtab; i++) {
+               rcu_dereference(mod->kallsyms)->typetab[i] = elf_type(src + i, info);
                if (i == 0 || is_livepatch_module(mod) ||
                    is_core_symbol(src + i, info->sechdrs, info->hdr->e_shnum,
                                   info->index.pcpu)) {
+                       ssize_t ret;
+
                        mod->core_kallsyms.typetab[ndst] =
-                           rcu_dereference_sched(mod->kallsyms)->typetab[i];
+                           rcu_dereference(mod->kallsyms)->typetab[i];
                        dst[ndst] = src[i];
                        dst[ndst++].st_name = s - mod->core_kallsyms.strtab;
-                       s += strscpy(s,
-                                    &rcu_dereference_sched(mod->kallsyms)->strtab[src[i].st_name],
-                                    KSYM_NAME_LEN) + 1;
+                       ret = strscpy(s,
+                                     &rcu_dereference(mod->kallsyms)->strtab[src[i].st_name],
+                                     strtab_size);
+                       if (ret < 0)
+                               break;
+                       s += ret + 1;
+                       strtab_size -= ret + 1;
                }
        }
-       preempt_enable();
+       rcu_read_unlock();
        mod->core_kallsyms.num_symtab = ndst;
 }
 
index fed58d3..57fc282 100644 (file)
@@ -1988,6 +1988,13 @@ static int check_modinfo(struct module *mod, struct load_info *info, int flags)
        /* Set up license info based on the info section */
        set_license(mod, get_modinfo(info, "license"));
 
+       if (get_modinfo(info, "test")) {
+               if (!test_taint(TAINT_TEST))
+                       pr_warn("%s: loading test module taints kernel.\n",
+                               mod->name);
+               add_taint_module(mod, TAINT_TEST, LOCKDEP_STILL_OK);
+       }
+
        return 0;
 }
 
@@ -2087,6 +2094,12 @@ static int find_module_sections(struct module *mod, struct load_info *info)
                                              sizeof(*mod->static_call_sites),
                                              &mod->num_static_call_sites);
 #endif
+#ifdef CONFIG_KUNIT
+       mod->kunit_suites = section_objs(info, ".kunit_test_suites",
+                                             sizeof(*mod->kunit_suites),
+                                             &mod->num_kunit_suites);
+#endif
+
        mod->extable = section_objs(info, "__ex_table",
                                    sizeof(*mod->extable), &mod->num_exentries);
 
@@ -2939,24 +2952,25 @@ static void cfi_init(struct module *mod)
 {
 #ifdef CONFIG_CFI_CLANG
        initcall_t *init;
+#ifdef CONFIG_MODULE_UNLOAD
        exitcall_t *exit;
+#endif
 
        rcu_read_lock_sched();
        mod->cfi_check = (cfi_check_fn)
                find_kallsyms_symbol_value(mod, "__cfi_check");
        init = (initcall_t *)
                find_kallsyms_symbol_value(mod, "__cfi_jt_init_module");
-       exit = (exitcall_t *)
-               find_kallsyms_symbol_value(mod, "__cfi_jt_cleanup_module");
-       rcu_read_unlock_sched();
-
        /* Fix init/exit functions to point to the CFI jump table */
        if (init)
                mod->init = *init;
 #ifdef CONFIG_MODULE_UNLOAD
+       exit = (exitcall_t *)
+               find_kallsyms_symbol_value(mod, "__cfi_jt_cleanup_module");
        if (exit)
                mod->exit = *exit;
 #endif
+       rcu_read_unlock_sched();
 
        cfi_module_add(mod, mod_tree.addr_min);
 #endif
index eec72ca..b4cbb40 100644 (file)
@@ -179,7 +179,8 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk)
        if (IS_ERR(new_ns))
                return  PTR_ERR(new_ns);
 
-       timens_on_fork(new_ns, tsk);
+       if ((flags & CLONE_VM) == 0)
+               timens_on_fork(new_ns, tsk);
 
        tsk->nsproxy = new_ns;
        return 0;
index a3308af..c6eb8f8 100644 (file)
@@ -428,6 +428,7 @@ const struct taint_flag taint_flags[TAINT_FLAGS_COUNT] = {
        [ TAINT_LIVEPATCH ]             = { 'K', ' ', true },
        [ TAINT_AUX ]                   = { 'X', ' ', true },
        [ TAINT_RANDSTRUCT ]            = { 'T', ' ', true },
+       [ TAINT_TEST ]                  = { 'N', ' ', true },
 };
 
 /**
index 6c373f2..f821118 100644 (file)
@@ -145,7 +145,7 @@ static int em_create_perf_table(struct device *dev, struct em_perf_domain *pd,
 
                /*
                 * The power returned by active_state() is expected to be
-                * positive and to fit into 16 bits.
+                * positive and be in range.
                 */
                if (!power || power > EM_MAX_POWER) {
                        dev_err(dev, "EM: invalid power: %lu\n",
@@ -170,7 +170,7 @@ static int em_create_perf_table(struct device *dev, struct em_perf_domain *pd,
                                goto free_ps_table;
                        }
                } else {
-                       power_res = em_scale_power(table[i].power);
+                       power_res = table[i].power;
                        cost = div64_u64(fmax * power_res, table[i].frequency);
                }
 
@@ -201,9 +201,17 @@ static int em_create_pd(struct device *dev, int nr_states,
 {
        struct em_perf_domain *pd;
        struct device *cpu_dev;
-       int cpu, ret;
+       int cpu, ret, num_cpus;
 
        if (_is_cpu_device(dev)) {
+               num_cpus = cpumask_weight(cpus);
+
+               /* Prevent max possible energy calculation to not overflow */
+               if (num_cpus > EM_MAX_NUM_CPUS) {
+                       dev_err(dev, "EM: too many CPUs, overflow possible\n");
+                       return -EINVAL;
+               }
+
                pd = kzalloc(sizeof(*pd) + cpumask_size(), GFP_KERNEL);
                if (!pd)
                        return -ENOMEM;
@@ -314,13 +322,13 @@ EXPORT_SYMBOL_GPL(em_cpu_get);
  * @cpus       : Pointer to cpumask_t, which in case of a CPU device is
  *             obligatory. It can be taken from i.e. 'policy->cpus'. For other
  *             type of devices this should be set to NULL.
- * @milliwatts : Flag indicating that the power values are in milliWatts or
+ * @microwatts : Flag indicating that the power values are in micro-Watts or
  *             in some other scale. It must be set properly.
  *
  * Create Energy Model tables for a performance domain using the callbacks
  * defined in cb.
  *
- * The @milliwatts is important to set with correct value. Some kernel
+ * The @microwatts is important to set with correct value. Some kernel
  * sub-systems might rely on this flag and check if all devices in the EM are
  * using the same scale.
  *
@@ -331,7 +339,7 @@ EXPORT_SYMBOL_GPL(em_cpu_get);
  */
 int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
                                struct em_data_callback *cb, cpumask_t *cpus,
-                               bool milliwatts)
+                               bool microwatts)
 {
        unsigned long cap, prev_cap = 0;
        unsigned long flags = 0;
@@ -381,8 +389,8 @@ int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
                }
        }
 
-       if (milliwatts)
-               flags |= EM_PERF_DOMAIN_MILLIWATTS;
+       if (microwatts)
+               flags |= EM_PERF_DOMAIN_MICROWATTS;
        else if (cb->get_cost)
                flags |= EM_PERF_DOMAIN_ARTIFICIAL;
 
index ec7e1e8..af51ed6 100644 (file)
@@ -531,7 +531,7 @@ int freq_qos_add_request(struct freq_constraints *qos,
 {
        int ret;
 
-       if (IS_ERR_OR_NULL(qos) || !req)
+       if (IS_ERR_OR_NULL(qos) || !req || value < 0)
                return -EINVAL;
 
        if (WARN(freq_qos_request_active(req),
@@ -563,7 +563,7 @@ EXPORT_SYMBOL_GPL(freq_qos_add_request);
  */
 int freq_qos_update_request(struct freq_qos_request *req, s32 new_value)
 {
-       if (!req)
+       if (!req || new_value < 0)
                return -EINVAL;
 
        if (WARN(!freq_qos_request_active(req),
index 91fffdd..277434b 100644 (file)
@@ -269,15 +269,14 @@ static void hib_end_io(struct bio *bio)
        bio_put(bio);
 }
 
-static int hib_submit_io(int op, int op_flags, pgoff_t page_off, void *addr,
-               struct hib_bio_batch *hb)
+static int hib_submit_io(blk_opf_t opf, pgoff_t page_off, void *addr,
+                        struct hib_bio_batch *hb)
 {
        struct page *page = virt_to_page(addr);
        struct bio *bio;
        int error = 0;
 
-       bio = bio_alloc(hib_resume_bdev, 1, op | op_flags,
-                       GFP_NOIO | __GFP_HIGH);
+       bio = bio_alloc(hib_resume_bdev, 1, opf, GFP_NOIO | __GFP_HIGH);
        bio->bi_iter.bi_sector = page_off * (PAGE_SIZE >> 9);
 
        if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
@@ -317,8 +316,7 @@ static int mark_swapfiles(struct swap_map_handle *handle, unsigned int flags)
 {
        int error;
 
-       hib_submit_io(REQ_OP_READ, 0, swsusp_resume_block,
-                     swsusp_header, NULL);
+       hib_submit_io(REQ_OP_READ, swsusp_resume_block, swsusp_header, NULL);
        if (!memcmp("SWAP-SPACE",swsusp_header->sig, 10) ||
            !memcmp("SWAPSPACE2",swsusp_header->sig, 10)) {
                memcpy(swsusp_header->orig_sig,swsusp_header->sig, 10);
@@ -331,7 +329,7 @@ static int mark_swapfiles(struct swap_map_handle *handle, unsigned int flags)
                swsusp_header->flags = flags;
                if (flags & SF_CRC32_MODE)
                        swsusp_header->crc32 = handle->crc32;
-               error = hib_submit_io(REQ_OP_WRITE, REQ_SYNC,
+               error = hib_submit_io(REQ_OP_WRITE | REQ_SYNC,
                                      swsusp_resume_block, swsusp_header, NULL);
        } else {
                pr_err("Swap header not found!\n");
@@ -408,7 +406,7 @@ static int write_page(void *buf, sector_t offset, struct hib_bio_batch *hb)
        } else {
                src = buf;
        }
-       return hib_submit_io(REQ_OP_WRITE, REQ_SYNC, offset, src, hb);
+       return hib_submit_io(REQ_OP_WRITE | REQ_SYNC, offset, src, hb);
 }
 
 static void release_swap_writer(struct swap_map_handle *handle)
@@ -1003,7 +1001,7 @@ static int get_swap_reader(struct swap_map_handle *handle,
                        return -ENOMEM;
                }
 
-               error = hib_submit_io(REQ_OP_READ, 0, offset, tmp->map, NULL);
+               error = hib_submit_io(REQ_OP_READ, offset, tmp->map, NULL);
                if (error) {
                        release_swap_reader(handle);
                        return error;
@@ -1027,7 +1025,7 @@ static int swap_read_page(struct swap_map_handle *handle, void *buf,
        offset = handle->cur->entries[handle->k];
        if (!offset)
                return -EFAULT;
-       error = hib_submit_io(REQ_OP_READ, 0, offset, buf, hb);
+       error = hib_submit_io(REQ_OP_READ, offset, buf, hb);
        if (error)
                return error;
        if (++handle->k >= MAP_PAGE_ENTRIES) {
@@ -1526,8 +1524,7 @@ int swsusp_check(void)
        if (!IS_ERR(hib_resume_bdev)) {
                set_blocksize(hib_resume_bdev, PAGE_SIZE);
                clear_page(swsusp_header);
-               error = hib_submit_io(REQ_OP_READ, 0,
-                                       swsusp_resume_block,
+               error = hib_submit_io(REQ_OP_READ, swsusp_resume_block,
                                        swsusp_header, NULL);
                if (error)
                        goto put;
@@ -1535,7 +1532,7 @@ int swsusp_check(void)
                if (!memcmp(HIBERNATE_SIG, swsusp_header->sig, 10)) {
                        memcpy(swsusp_header->sig, swsusp_header->orig_sig, 10);
                        /* Reset swap signature now */
-                       error = hib_submit_io(REQ_OP_WRITE, REQ_SYNC,
+                       error = hib_submit_io(REQ_OP_WRITE | REQ_SYNC,
                                                swsusp_resume_block,
                                                swsusp_header, NULL);
                } else {
@@ -1586,11 +1583,11 @@ int swsusp_unmark(void)
 {
        int error;
 
-       hib_submit_io(REQ_OP_READ, 0, swsusp_resume_block,
-                     swsusp_header, NULL);
+       hib_submit_io(REQ_OP_READ, swsusp_resume_block,
+                       swsusp_header, NULL);
        if (!memcmp(HIBERNATE_SIG,swsusp_header->sig, 10)) {
                memcpy(swsusp_header->sig,swsusp_header->orig_sig, 10);
-               error = hib_submit_io(REQ_OP_WRITE, REQ_SYNC,
+               error = hib_submit_io(REQ_OP_WRITE | REQ_SYNC,
                                        swsusp_resume_block,
                                        swsusp_header, NULL);
        } else {
index ad241b4..d43c2aa 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "power.h"
 
+static bool need_wait;
 
 static struct snapshot_data {
        struct snapshot_handle handle;
@@ -78,7 +79,7 @@ static int snapshot_open(struct inode *inode, struct file *filp)
                 * Resuming.  We may need to wait for the image device to
                 * appear.
                 */
-               wait_for_device_probe();
+               need_wait = true;
 
                data->swap = -1;
                data->mode = O_WRONLY;
@@ -168,6 +169,11 @@ static ssize_t snapshot_write(struct file *filp, const char __user *buf,
        ssize_t res;
        loff_t pg_offp = *offp & ~PAGE_MASK;
 
+       if (need_wait) {
+               wait_for_device_probe();
+               need_wait = false;
+       }
+
        lock_system_sleep();
 
        data = filp->private_data;
@@ -244,6 +250,11 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
        loff_t size;
        sector_t offset;
 
+       if (need_wait) {
+               wait_for_device_probe();
+               need_wait = false;
+       }
+
        if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC)
                return -ENOTTY;
        if (_IOC_NR(cmd) > SNAPSHOT_IOC_MAXNR)
index b49c6ff..a1a81fd 100644 (file)
@@ -3380,6 +3380,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
                diff = 0;
 
                console_lock();
+
                for_each_console(c) {
                        if (con && con != c)
                                continue;
@@ -3389,11 +3390,19 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
                        if (printk_seq < seq)
                                diff += seq - printk_seq;
                }
-               console_unlock();
 
-               if (diff != last_diff && reset_on_progress)
+               /*
+                * If consoles are suspended, it cannot be expected that they
+                * make forward progress, so timeout immediately. @diff is
+                * still used to return a valid flush status.
+                */
+               if (console_suspended)
+                       remaining = 0;
+               else if (diff != last_diff && reset_on_progress)
                        remaining = timeout_ms;
 
+               console_unlock();
+
                if (diff == 0 || remaining == 0)
                        break;
 
index 156a992..1893d90 100644 (file)
@@ -222,7 +222,7 @@ static void ptrace_unfreeze_traced(struct task_struct *task)
        if (lock_task_sighand(task, &flags)) {
                task->jobctl &= ~JOBCTL_PTRACE_FROZEN;
                if (__fatal_signal_pending(task)) {
-                       task->jobctl &= ~TASK_TRACED;
+                       task->jobctl &= ~JOBCTL_TRACED;
                        wake_up_state(task, __TASK_TRACED);
                }
                unlock_task_sighand(task, &flags);
index 1c630e5..d471d22 100644 (file)
@@ -8,6 +8,8 @@ menu "RCU Subsystem"
 config TREE_RCU
        bool
        default y if SMP
+       # Dynticks-idle tracking
+       select CONTEXT_TRACKING_IDLE
        help
          This option selects the RCU implementation that is
          designed for very large SMP system with hundreds or
@@ -262,6 +264,35 @@ config RCU_NOCB_CPU
          Say Y here if you need reduced OS jitter, despite added overhead.
          Say N here if you are unsure.
 
+config RCU_NOCB_CPU_DEFAULT_ALL
+       bool "Offload RCU callback processing from all CPUs by default"
+       depends on RCU_NOCB_CPU
+       default n
+       help
+         Use this option to offload callback processing from all CPUs
+         by default, in the absence of the rcu_nocbs or nohz_full boot
+         parameter. This also avoids the need to use any boot parameters
+         to achieve the effect of offloading all CPUs on boot.
+
+         Say Y here if you want offload all CPUs by default on boot.
+         Say N here if you are unsure.
+
+config RCU_NOCB_CPU_CB_BOOST
+       bool "Offload RCU callback from real-time kthread"
+       depends on RCU_NOCB_CPU && RCU_BOOST
+       default y if PREEMPT_RT
+       help
+         Use this option to invoke offloaded callbacks as SCHED_FIFO
+         to avoid starvation by heavy SCHED_OTHER background load.
+         Of course, running as SCHED_FIFO during callback floods will
+         cause the rcuo[ps] kthreads to monopolize the CPU for hundreds
+         of milliseconds or more.  Therefore, when enabling this option,
+         it is your responsibility to ensure that latency-sensitive
+         tasks either run with higher priority or run on some other CPU.
+
+         Say Y here if you want to set RT priority for offloading kthreads.
+         Say N here if you are building a !PREEMPT_RT kernel and are unsure.
+
 config TASKS_TRACE_RCU_READ_MB
        bool "Tasks Trace RCU readers use memory barriers in user and idle"
        depends on RCU_EXPERT && TASKS_TRACE_RCU
index 9b64e55..4da05be 100644 (file)
@@ -121,7 +121,7 @@ config RCU_EQS_DEBUG
 
 config RCU_STRICT_GRACE_PERIOD
        bool "Provide debug RCU implementation with short grace periods"
-       depends on DEBUG_KERNEL && RCU_EXPERT && NR_CPUS <= 4
+       depends on DEBUG_KERNEL && RCU_EXPERT && NR_CPUS <= 4 && !TINY_RCU
        default n
        select PREEMPT_COUNT if PREEMPT=n
        help
index 4916077..be5979d 100644 (file)
 
 #include <trace/events/rcu.h>
 
-/* Offset to allow distinguishing irq vs. task-based idle entry/exit. */
-#define DYNTICK_IRQ_NONIDLE    ((LONG_MAX / 2) + 1)
-
-
 /*
  * Grace-period counter management.
  */
@@ -23,6 +19,9 @@
 #define RCU_SEQ_CTR_SHIFT      2
 #define RCU_SEQ_STATE_MASK     ((1 << RCU_SEQ_CTR_SHIFT) - 1)
 
+/* Low-order bit definition for polled grace-period APIs. */
+#define RCU_GET_STATE_COMPLETED        0x1
+
 extern int sysctl_sched_rt_runtime;
 
 /*
@@ -120,6 +119,18 @@ static inline bool rcu_seq_done(unsigned long *sp, unsigned long s)
 }
 
 /*
+ * Given a snapshot from rcu_seq_snap(), determine whether or not a
+ * full update-side operation has occurred, but do not allow the
+ * (ULONG_MAX / 2) safety-factor/guard-band.
+ */
+static inline bool rcu_seq_done_exact(unsigned long *sp, unsigned long s)
+{
+       unsigned long cur_s = READ_ONCE(*sp);
+
+       return ULONG_CMP_GE(cur_s, s) || ULONG_CMP_LT(cur_s, s - (2 * RCU_SEQ_STATE_MASK + 1));
+}
+
+/*
  * Has a grace period completed since the time the old gp_seq was collected?
  */
 static inline bool rcu_seq_completed_gp(unsigned long old, unsigned long new)
index 277a5bf..3ef02d4 100644 (file)
@@ -419,6 +419,7 @@ rcu_scale_writer(void *arg)
        VERBOSE_SCALEOUT_STRING("rcu_scale_writer task started");
        WARN_ON(!wdpp);
        set_cpus_allowed_ptr(current, cpumask_of(me % nr_cpu_ids));
+       current->flags |= PF_NO_SETAFFINITY;
        sched_set_fifo_low(current);
 
        if (holdoff)
index 7120165..d8e1b27 100644 (file)
@@ -75,62 +75,47 @@ MODULE_AUTHOR("Paul E. McKenney <paulmck@linux.ibm.com> and Josh Triplett <josh@
 
 torture_param(int, extendables, RCUTORTURE_MAX_EXTEND,
              "Extend readers by disabling bh (1), irqs (2), or preempt (4)");
-torture_param(int, fqs_duration, 0,
-             "Duration of fqs bursts (us), 0 to disable");
+torture_param(int, fqs_duration, 0, "Duration of fqs bursts (us), 0 to disable");
 torture_param(int, fqs_holdoff, 0, "Holdoff time within fqs bursts (us)");
 torture_param(int, fqs_stutter, 3, "Wait time between fqs bursts (s)");
-torture_param(int, fwd_progress, 1, "Test grace-period forward progress");
+torture_param(int, fwd_progress, 1, "Number of grace-period forward progress tasks (0 to disable)");
 torture_param(int, fwd_progress_div, 4, "Fraction of CPU stall to wait");
-torture_param(int, fwd_progress_holdoff, 60,
-             "Time between forward-progress tests (s)");
-torture_param(bool, fwd_progress_need_resched, 1,
-             "Hide cond_resched() behind need_resched()");
+torture_param(int, fwd_progress_holdoff, 60, "Time between forward-progress tests (s)");
+torture_param(bool, fwd_progress_need_resched, 1, "Hide cond_resched() behind need_resched()");
 torture_param(bool, gp_cond, false, "Use conditional/async GP wait primitives");
+torture_param(bool, gp_cond_exp, false, "Use conditional/async expedited GP wait primitives");
 torture_param(bool, gp_exp, false, "Use expedited GP wait primitives");
-torture_param(bool, gp_normal, false,
-            "Use normal (non-expedited) GP wait primitives");
+torture_param(bool, gp_normal, false, "Use normal (non-expedited) GP wait primitives");
 torture_param(bool, gp_poll, false, "Use polling GP wait primitives");
+torture_param(bool, gp_poll_exp, false, "Use polling expedited GP wait primitives");
 torture_param(bool, gp_sync, false, "Use synchronous GP wait primitives");
 torture_param(int, irqreader, 1, "Allow RCU readers from irq handlers");
 torture_param(int, leakpointer, 0, "Leak pointer dereferences from readers");
-torture_param(int, n_barrier_cbs, 0,
-            "# of callbacks/kthreads for barrier testing");
+torture_param(int, n_barrier_cbs, 0, "# of callbacks/kthreads for barrier testing");
 torture_param(int, nfakewriters, 4, "Number of RCU fake writer threads");
 torture_param(int, nreaders, -1, "Number of RCU reader threads");
-torture_param(int, object_debug, 0,
-            "Enable debug-object double call_rcu() testing");
+torture_param(int, object_debug, 0, "Enable debug-object double call_rcu() testing");
 torture_param(int, onoff_holdoff, 0, "Time after boot before CPU hotplugs (s)");
-torture_param(int, onoff_interval, 0,
-            "Time between CPU hotplugs (jiffies), 0=disable");
+torture_param(int, onoff_interval, 0, "Time between CPU hotplugs (jiffies), 0=disable");
 torture_param(int, nocbs_nthreads, 0, "Number of NOCB toggle threads, 0 to disable");
 torture_param(int, nocbs_toggle, 1000, "Time between toggling nocb state (ms)");
-torture_param(int, read_exit_delay, 13,
-             "Delay between read-then-exit episodes (s)");
-torture_param(int, read_exit_burst, 16,
-             "# of read-then-exit bursts per episode, zero to disable");
+torture_param(int, read_exit_delay, 13, "Delay between read-then-exit episodes (s)");
+torture_param(int, read_exit_burst, 16, "# of read-then-exit bursts per episode, zero to disable");
 torture_param(int, shuffle_interval, 3, "Number of seconds between shuffles");
 torture_param(int, shutdown_secs, 0, "Shutdown time (s), <= zero to disable.");
 torture_param(int, stall_cpu, 0, "Stall duration (s), zero to disable.");
-torture_param(int, stall_cpu_holdoff, 10,
-            "Time to wait before starting stall (s).");
-torture_param(bool, stall_no_softlockup, false,
-            "Avoid softlockup warning during cpu stall.");
+torture_param(int, stall_cpu_holdoff, 10, "Time to wait before starting stall (s).");
+torture_param(bool, stall_no_softlockup, false, "Avoid softlockup warning during cpu stall.");
 torture_param(int, stall_cpu_irqsoff, 0, "Disable interrupts while stalling.");
 torture_param(int, stall_cpu_block, 0, "Sleep while stalling.");
-torture_param(int, stall_gp_kthread, 0,
-             "Grace-period kthread stall duration (s).");
-torture_param(int, stat_interval, 60,
-            "Number of seconds between stats printk()s");
+torture_param(int, stall_gp_kthread, 0, "Grace-period kthread stall duration (s).");
+torture_param(int, stat_interval, 60, "Number of seconds between stats printk()s");
 torture_param(int, stutter, 5, "Number of seconds to run/halt test");
 torture_param(int, test_boost, 1, "Test RCU prio boost: 0=no, 1=maybe, 2=yes.");
-torture_param(int, test_boost_duration, 4,
-            "Duration of each boost test, seconds.");
-torture_param(int, test_boost_interval, 7,
-            "Interval between boost tests, seconds.");
-torture_param(bool, test_no_idle_hz, true,
-            "Test support for tickless idle CPUs");
-torture_param(int, verbose, 1,
-            "Enable verbose debugging printk()s");
+torture_param(int, test_boost_duration, 4, "Duration of each boost test, seconds.");
+torture_param(int, test_boost_interval, 7, "Interval between boost tests, seconds.");
+torture_param(bool, test_no_idle_hz, true, "Test support for tickless idle CPUs");
+torture_param(int, verbose, 1, "Enable verbose debugging printk()s");
 
 static char *torture_type = "rcu";
 module_param(torture_type, charp, 0444);
@@ -209,12 +194,16 @@ static int rcu_torture_writer_state;
 #define RTWS_DEF_FREE          3
 #define RTWS_EXP_SYNC          4
 #define RTWS_COND_GET          5
-#define RTWS_COND_SYNC         6
-#define RTWS_POLL_GET          7
-#define RTWS_POLL_WAIT         8
-#define RTWS_SYNC              9
-#define RTWS_STUTTER           10
-#define RTWS_STOPPING          11
+#define RTWS_COND_GET_EXP      6
+#define RTWS_COND_SYNC         7
+#define RTWS_COND_SYNC_EXP     8
+#define RTWS_POLL_GET          9
+#define RTWS_POLL_GET_EXP      10
+#define RTWS_POLL_WAIT         11
+#define RTWS_POLL_WAIT_EXP     12
+#define RTWS_SYNC              13
+#define RTWS_STUTTER           14
+#define RTWS_STOPPING          15
 static const char * const rcu_torture_writer_state_names[] = {
        "RTWS_FIXED_DELAY",
        "RTWS_DELAY",
@@ -222,9 +211,13 @@ static const char * const rcu_torture_writer_state_names[] = {
        "RTWS_DEF_FREE",
        "RTWS_EXP_SYNC",
        "RTWS_COND_GET",
+       "RTWS_COND_GET_EXP",
        "RTWS_COND_SYNC",
+       "RTWS_COND_SYNC_EXP",
        "RTWS_POLL_GET",
+       "RTWS_POLL_GET_EXP",
        "RTWS_POLL_WAIT",
+       "RTWS_POLL_WAIT_EXP",
        "RTWS_SYNC",
        "RTWS_STUTTER",
        "RTWS_STOPPING",
@@ -337,7 +330,12 @@ struct rcu_torture_ops {
        void (*deferred_free)(struct rcu_torture *p);
        void (*sync)(void);
        void (*exp_sync)(void);
+       unsigned long (*get_gp_state_exp)(void);
+       unsigned long (*start_gp_poll_exp)(void);
+       bool (*poll_gp_state_exp)(unsigned long oldstate);
+       void (*cond_sync_exp)(unsigned long oldstate);
        unsigned long (*get_gp_state)(void);
+       unsigned long (*get_gp_completed)(void);
        unsigned long (*start_gp_poll)(void);
        bool (*poll_gp_state)(unsigned long oldstate);
        void (*cond_sync)(unsigned long oldstate);
@@ -504,9 +502,14 @@ static struct rcu_torture_ops rcu_ops = {
        .sync                   = synchronize_rcu,
        .exp_sync               = synchronize_rcu_expedited,
        .get_gp_state           = get_state_synchronize_rcu,
+       .get_gp_completed       = get_completed_synchronize_rcu,
        .start_gp_poll          = start_poll_synchronize_rcu,
        .poll_gp_state          = poll_state_synchronize_rcu,
        .cond_sync              = cond_synchronize_rcu,
+       .get_gp_state_exp       = get_state_synchronize_rcu,
+       .start_gp_poll_exp      = start_poll_synchronize_rcu_expedited,
+       .poll_gp_state_exp      = poll_state_synchronize_rcu,
+       .cond_sync_exp          = cond_synchronize_rcu_expedited,
        .call                   = call_rcu,
        .cb_barrier             = rcu_barrier,
        .fqs                    = rcu_force_quiescent_state,
@@ -1136,9 +1139,8 @@ rcu_torture_fqs(void *arg)
        return 0;
 }
 
-// Used by writers to randomly choose from the available grace-period
-// primitives.  The only purpose of the initialization is to size the array.
-static int synctype[] = { RTWS_DEF_FREE, RTWS_EXP_SYNC, RTWS_COND_GET, RTWS_POLL_GET, RTWS_SYNC };
+// Used by writers to randomly choose from the available grace-period primitives.
+static int synctype[ARRAY_SIZE(rcu_torture_writer_state_names)] = { };
 static int nsynctypes;
 
 /*
@@ -1146,18 +1148,27 @@ static int nsynctypes;
  */
 static void rcu_torture_write_types(void)
 {
-       bool gp_cond1 = gp_cond, gp_exp1 = gp_exp, gp_normal1 = gp_normal;
-       bool gp_poll1 = gp_poll, gp_sync1 = gp_sync;
+       bool gp_cond1 = gp_cond, gp_cond_exp1 = gp_cond_exp, gp_exp1 = gp_exp;
+       bool gp_poll_exp1 = gp_poll_exp, gp_normal1 = gp_normal, gp_poll1 = gp_poll;
+       bool gp_sync1 = gp_sync;
 
        /* Initialize synctype[] array.  If none set, take default. */
-       if (!gp_cond1 && !gp_exp1 && !gp_normal1 && !gp_poll1 && !gp_sync1)
-               gp_cond1 = gp_exp1 = gp_normal1 = gp_poll1 = gp_sync1 = true;
+       if (!gp_cond1 && !gp_cond_exp1 && !gp_exp1 && !gp_poll_exp &&
+           !gp_normal1 && !gp_poll1 && !gp_sync1)
+               gp_cond1 = gp_cond_exp1 = gp_exp1 = gp_poll_exp1 =
+                          gp_normal1 = gp_poll1 = gp_sync1 = true;
        if (gp_cond1 && cur_ops->get_gp_state && cur_ops->cond_sync) {
                synctype[nsynctypes++] = RTWS_COND_GET;
                pr_info("%s: Testing conditional GPs.\n", __func__);
        } else if (gp_cond && (!cur_ops->get_gp_state || !cur_ops->cond_sync)) {
                pr_alert("%s: gp_cond without primitives.\n", __func__);
        }
+       if (gp_cond_exp1 && cur_ops->get_gp_state_exp && cur_ops->cond_sync_exp) {
+               synctype[nsynctypes++] = RTWS_COND_GET_EXP;
+               pr_info("%s: Testing conditional expedited GPs.\n", __func__);
+       } else if (gp_cond_exp && (!cur_ops->get_gp_state_exp || !cur_ops->cond_sync_exp)) {
+               pr_alert("%s: gp_cond_exp without primitives.\n", __func__);
+       }
        if (gp_exp1 && cur_ops->exp_sync) {
                synctype[nsynctypes++] = RTWS_EXP_SYNC;
                pr_info("%s: Testing expedited GPs.\n", __func__);
@@ -1176,6 +1187,12 @@ static void rcu_torture_write_types(void)
        } else if (gp_poll && (!cur_ops->start_gp_poll || !cur_ops->poll_gp_state)) {
                pr_alert("%s: gp_poll without primitives.\n", __func__);
        }
+       if (gp_poll_exp1 && cur_ops->start_gp_poll_exp && cur_ops->poll_gp_state_exp) {
+               synctype[nsynctypes++] = RTWS_POLL_GET_EXP;
+               pr_info("%s: Testing polling expedited GPs.\n", __func__);
+       } else if (gp_poll_exp && (!cur_ops->start_gp_poll_exp || !cur_ops->poll_gp_state_exp)) {
+               pr_alert("%s: gp_poll_exp without primitives.\n", __func__);
+       }
        if (gp_sync1 && cur_ops->sync) {
                synctype[nsynctypes++] = RTWS_SYNC;
                pr_info("%s: Testing normal GPs.\n", __func__);
@@ -1254,6 +1271,10 @@ rcu_torture_writer(void *arg)
                                          rcu_torture_writer_state_getname(),
                                          rcu_torture_writer_state,
                                          cookie, cur_ops->get_gp_state());
+                               if (cur_ops->get_gp_completed) {
+                                       cookie = cur_ops->get_gp_completed();
+                                       WARN_ON_ONCE(!cur_ops->poll_gp_state(cookie));
+                               }
                                cur_ops->readunlock(idx);
                        }
                        switch (synctype[torture_random(&rand) % nsynctypes]) {
@@ -1263,7 +1284,12 @@ rcu_torture_writer(void *arg)
                                break;
                        case RTWS_EXP_SYNC:
                                rcu_torture_writer_state = RTWS_EXP_SYNC;
+                               if (cur_ops->get_gp_state && cur_ops->poll_gp_state)
+                                       cookie = cur_ops->get_gp_state();
                                cur_ops->exp_sync();
+                               cur_ops->exp_sync();
+                               if (cur_ops->get_gp_state && cur_ops->poll_gp_state)
+                                       WARN_ON_ONCE(!cur_ops->poll_gp_state(cookie));
                                rcu_torture_pipe_update(old_rp);
                                break;
                        case RTWS_COND_GET:
@@ -1274,6 +1300,14 @@ rcu_torture_writer(void *arg)
                                cur_ops->cond_sync(gp_snap);
                                rcu_torture_pipe_update(old_rp);
                                break;
+                       case RTWS_COND_GET_EXP:
+                               rcu_torture_writer_state = RTWS_COND_GET_EXP;
+                               gp_snap = cur_ops->get_gp_state_exp();
+                               torture_hrtimeout_jiffies(torture_random(&rand) % 16, &rand);
+                               rcu_torture_writer_state = RTWS_COND_SYNC_EXP;
+                               cur_ops->cond_sync_exp(gp_snap);
+                               rcu_torture_pipe_update(old_rp);
+                               break;
                        case RTWS_POLL_GET:
                                rcu_torture_writer_state = RTWS_POLL_GET;
                                gp_snap = cur_ops->start_gp_poll();
@@ -1283,9 +1317,23 @@ rcu_torture_writer(void *arg)
                                                                  &rand);
                                rcu_torture_pipe_update(old_rp);
                                break;
+                       case RTWS_POLL_GET_EXP:
+                               rcu_torture_writer_state = RTWS_POLL_GET_EXP;
+                               gp_snap = cur_ops->start_gp_poll_exp();
+                               rcu_torture_writer_state = RTWS_POLL_WAIT_EXP;
+                               while (!cur_ops->poll_gp_state_exp(gp_snap))
+                                       torture_hrtimeout_jiffies(torture_random(&rand) % 16,
+                                                                 &rand);
+                               rcu_torture_pipe_update(old_rp);
+                               break;
                        case RTWS_SYNC:
                                rcu_torture_writer_state = RTWS_SYNC;
+                               if (cur_ops->get_gp_state && cur_ops->poll_gp_state)
+                                       cookie = cur_ops->get_gp_state();
                                cur_ops->sync();
+                               cur_ops->sync();
+                               if (cur_ops->get_gp_state && cur_ops->poll_gp_state)
+                                       WARN_ON_ONCE(!cur_ops->poll_gp_state(cookie));
                                rcu_torture_pipe_update(old_rp);
                                break;
                        default:
@@ -1321,8 +1369,9 @@ rcu_torture_writer(void *arg)
                                if (list_empty(&rcu_tortures[i].rtort_free) &&
                                    rcu_access_pointer(rcu_torture_current) !=
                                    &rcu_tortures[i]) {
-                                       rcu_ftrace_dump(DUMP_ALL);
+                                       tracing_off();
                                        WARN(1, "%s: rtort_pipe_count: %d\n", __func__, rcu_tortures[i].rtort_pipe_count);
+                                       rcu_ftrace_dump(DUMP_ALL);
                                }
                if (stutter_waited)
                        sched_set_normal(current, oldnice);
@@ -1384,6 +1433,11 @@ rcu_torture_fakewriter(void *arg)
                                torture_hrtimeout_jiffies(torture_random(&rand) % 16, &rand);
                                cur_ops->cond_sync(gp_snap);
                                break;
+                       case RTWS_COND_GET_EXP:
+                               gp_snap = cur_ops->get_gp_state_exp();
+                               torture_hrtimeout_jiffies(torture_random(&rand) % 16, &rand);
+                               cur_ops->cond_sync_exp(gp_snap);
+                               break;
                        case RTWS_POLL_GET:
                                gp_snap = cur_ops->start_gp_poll();
                                while (!cur_ops->poll_gp_state(gp_snap)) {
@@ -1391,6 +1445,13 @@ rcu_torture_fakewriter(void *arg)
                                                                  &rand);
                                }
                                break;
+                       case RTWS_POLL_GET_EXP:
+                               gp_snap = cur_ops->start_gp_poll_exp();
+                               while (!cur_ops->poll_gp_state_exp(gp_snap)) {
+                                       torture_hrtimeout_jiffies(torture_random(&rand) % 16,
+                                                                 &rand);
+                               }
+                               break;
                        case RTWS_SYNC:
                                cur_ops->sync();
                                break;
@@ -1868,7 +1929,7 @@ rcu_torture_stats_print(void)
                        batchsummary[i] += READ_ONCE(per_cpu(rcu_torture_batch, cpu)[i]);
                }
        }
-       for (i = RCU_TORTURE_PIPE_LEN - 1; i >= 0; i--) {
+       for (i = RCU_TORTURE_PIPE_LEN; i >= 0; i--) {
                if (pipesummary[i] != 0)
                        break;
        }
@@ -1990,7 +2051,13 @@ static void rcu_torture_mem_dump_obj(void)
        static int z;
 
        kcp = kmem_cache_create("rcuscale", 136, 8, SLAB_STORE_USER, NULL);
+       if (WARN_ON_ONCE(!kcp))
+               return;
        rhp = kmem_cache_alloc(kcp, GFP_KERNEL);
+       if (WARN_ON_ONCE(!rhp)) {
+               kmem_cache_destroy(kcp);
+               return;
+       }
        pr_alert("mem_dump_obj() slab test: rcu_torture_stats = %px, &rhp = %px, rhp = %px, &z = %px\n", stats_task, &rhp, rhp, &z);
        pr_alert("mem_dump_obj(ZERO_SIZE_PTR):");
        mem_dump_obj(ZERO_SIZE_PTR);
@@ -2007,6 +2074,8 @@ static void rcu_torture_mem_dump_obj(void)
        kmem_cache_free(kcp, rhp);
        kmem_cache_destroy(kcp);
        rhp = kmalloc(sizeof(*rhp), GFP_KERNEL);
+       if (WARN_ON_ONCE(!rhp))
+               return;
        pr_alert("mem_dump_obj() kmalloc test: rcu_torture_stats = %px, &rhp = %px, rhp = %px\n", stats_task, &rhp, rhp);
        pr_alert("mem_dump_obj(kmalloc %px):", rhp);
        mem_dump_obj(rhp);
@@ -2014,6 +2083,8 @@ static void rcu_torture_mem_dump_obj(void)
        mem_dump_obj(&rhp->func);
        kfree(rhp);
        rhp = vmalloc(4096);
+       if (WARN_ON_ONCE(!rhp))
+               return;
        pr_alert("mem_dump_obj() vmalloc test: rcu_torture_stats = %px, &rhp = %px, rhp = %px\n", stats_task, &rhp, rhp);
        pr_alert("mem_dump_obj(vmalloc %px):", rhp);
        mem_dump_obj(rhp);
@@ -2075,6 +2146,19 @@ static int rcutorture_booster_init(unsigned int cpu)
        if (boost_tasks[cpu] != NULL)
                return 0;  /* Already created, nothing more to do. */
 
+       // Testing RCU priority boosting requires rcutorture do
+       // some serious abuse.  Counter this by running ksoftirqd
+       // at higher priority.
+       if (IS_BUILTIN(CONFIG_RCU_TORTURE_TEST)) {
+               struct sched_param sp;
+               struct task_struct *t;
+
+               t = per_cpu(ksoftirqd, cpu);
+               WARN_ON_ONCE(!t);
+               sp.sched_priority = 2;
+               sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
+       }
+
        /* Don't allow time recalculation while creating a new task. */
        mutex_lock(&boost_mutex);
        rcu_torture_disable_rt_throttle();
@@ -2873,7 +2957,6 @@ static int rcu_torture_read_exit_child(void *trsp_in)
 // Parent kthread which creates and destroys read-exit child kthreads.
 static int rcu_torture_read_exit(void *unused)
 {
-       int count = 0;
        bool errexit = false;
        int i;
        struct task_struct *tsp;
@@ -2885,34 +2968,28 @@ static int rcu_torture_read_exit(void *unused)
 
        // Each pass through this loop does one read-exit episode.
        do {
-               if (++count > read_exit_burst) {
-                       VERBOSE_TOROUT_STRING("rcu_torture_read_exit: End of episode");
-                       rcu_barrier(); // Wait for task_struct free, avoid OOM.
-                       for (i = 0; i < read_exit_delay; i++) {
-                               schedule_timeout_uninterruptible(HZ);
-                               if (READ_ONCE(read_exit_child_stop))
-                                       break;
+               VERBOSE_TOROUT_STRING("rcu_torture_read_exit: Start of episode");
+               for (i = 0; i < read_exit_burst; i++) {
+                       if (READ_ONCE(read_exit_child_stop))
+                               break;
+                       stutter_wait("rcu_torture_read_exit");
+                       // Spawn child.
+                       tsp = kthread_run(rcu_torture_read_exit_child,
+                                         &trs, "%s", "rcu_torture_read_exit_child");
+                       if (IS_ERR(tsp)) {
+                               TOROUT_ERRSTRING("out of memory");
+                               errexit = true;
+                               break;
                        }
-                       if (!READ_ONCE(read_exit_child_stop))
-                               VERBOSE_TOROUT_STRING("rcu_torture_read_exit: Start of episode");
-                       count = 0;
-               }
-               if (READ_ONCE(read_exit_child_stop))
-                       break;
-               // Spawn child.
-               tsp = kthread_run(rcu_torture_read_exit_child,
-                                    &trs, "%s",
-                                    "rcu_torture_read_exit_child");
-               if (IS_ERR(tsp)) {
-                       TOROUT_ERRSTRING("out of memory");
-                       errexit = true;
-                       tsp = NULL;
-                       break;
+                       cond_resched();
+                       kthread_stop(tsp);
+                       n_read_exits++;
                }
-               cond_resched();
-               kthread_stop(tsp);
-               n_read_exits ++;
-               stutter_wait("rcu_torture_read_exit");
+               VERBOSE_TOROUT_STRING("rcu_torture_read_exit: End of episode");
+               rcu_barrier(); // Wait for task_struct free, avoid OOM.
+               i = 0;
+               for (; !errexit && !READ_ONCE(read_exit_child_stop) && i < read_exit_delay; i++)
+                       schedule_timeout_uninterruptible(HZ);
        } while (!errexit && !READ_ONCE(read_exit_child_stop));
 
        // Clean up and exit.
@@ -3122,6 +3199,7 @@ static void rcu_test_debug_objects(void)
        pr_alert("%s: WARN: Duplicate call_rcu() test complete.\n", KBUILD_MODNAME);
        destroy_rcu_head_on_stack(&rh1);
        destroy_rcu_head_on_stack(&rh2);
+       kfree(rhp);
 #else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
        pr_alert("%s: !CONFIG_DEBUG_OBJECTS_RCU_HEAD, not testing duplicate call_rcu()\n", KBUILD_MODNAME);
 #endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
@@ -3329,21 +3407,6 @@ rcu_torture_init(void)
                rcutor_hp = firsterr;
                if (torture_init_error(firsterr))
                        goto unwind;
-
-               // Testing RCU priority boosting requires rcutorture do
-               // some serious abuse.  Counter this by running ksoftirqd
-               // at higher priority.
-               if (IS_BUILTIN(CONFIG_RCU_TORTURE_TEST)) {
-                       for_each_online_cpu(cpu) {
-                               struct sched_param sp;
-                               struct task_struct *t;
-
-                               t = per_cpu(ksoftirqd, cpu);
-                               WARN_ON_ONCE(!t);
-                               sp.sched_priority = 2;
-                               sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
-                       }
-               }
        }
        shutdown_jiffies = jiffies + shutdown_secs * HZ;
        firsterr = torture_shutdown_init(shutdown_secs, rcu_torture_cleanup);
index 909644a..435c884 100644 (file)
@@ -385,7 +385,7 @@ static struct ref_scale_ops rwsem_ops = {
 };
 
 // Definitions for global spinlock
-static DEFINE_SPINLOCK(test_lock);
+static DEFINE_RAW_SPINLOCK(test_lock);
 
 static void ref_lock_section(const int nloops)
 {
@@ -393,8 +393,8 @@ static void ref_lock_section(const int nloops)
 
        preempt_disable();
        for (i = nloops; i >= 0; i--) {
-               spin_lock(&test_lock);
-               spin_unlock(&test_lock);
+               raw_spin_lock(&test_lock);
+               raw_spin_unlock(&test_lock);
        }
        preempt_enable();
 }
@@ -405,9 +405,9 @@ static void ref_lock_delay_section(const int nloops, const int udl, const int nd
 
        preempt_disable();
        for (i = nloops; i >= 0; i--) {
-               spin_lock(&test_lock);
+               raw_spin_lock(&test_lock);
                un_delay(udl, ndl);
-               spin_unlock(&test_lock);
+               raw_spin_unlock(&test_lock);
        }
        preempt_enable();
 }
@@ -427,8 +427,8 @@ static void ref_lock_irq_section(const int nloops)
 
        preempt_disable();
        for (i = nloops; i >= 0; i--) {
-               spin_lock_irqsave(&test_lock, flags);
-               spin_unlock_irqrestore(&test_lock, flags);
+               raw_spin_lock_irqsave(&test_lock, flags);
+               raw_spin_unlock_irqrestore(&test_lock, flags);
        }
        preempt_enable();
 }
@@ -440,9 +440,9 @@ static void ref_lock_irq_delay_section(const int nloops, const int udl, const in
 
        preempt_disable();
        for (i = nloops; i >= 0; i--) {
-               spin_lock_irqsave(&test_lock, flags);
+               raw_spin_lock_irqsave(&test_lock, flags);
                un_delay(udl, ndl);
-               spin_unlock_irqrestore(&test_lock, flags);
+               raw_spin_unlock_irqrestore(&test_lock, flags);
        }
        preempt_enable();
 }
index 50ba70f..1c304fe 100644 (file)
@@ -511,10 +511,52 @@ static bool srcu_readers_active(struct srcu_struct *ssp)
        return sum;
 }
 
-#define SRCU_INTERVAL          1       // Base delay if no expedited GPs pending.
-#define SRCU_MAX_INTERVAL      10      // Maximum incremental delay from slow readers.
-#define SRCU_MAX_NODELAY_PHASE 1       // Maximum per-GP-phase consecutive no-delay instances.
-#define SRCU_MAX_NODELAY       100     // Maximum consecutive no-delay instances.
+/*
+ * We use an adaptive strategy for synchronize_srcu() and especially for
+ * synchronize_srcu_expedited().  We spin for a fixed time period
+ * (defined below, boot time configurable) to allow SRCU readers to exit
+ * their read-side critical sections.  If there are still some readers
+ * after one jiffy, we repeatedly block for one jiffy time periods.
+ * The blocking time is increased as the grace-period age increases,
+ * with max blocking time capped at 10 jiffies.
+ */
+#define SRCU_DEFAULT_RETRY_CHECK_DELAY         5
+
+static ulong srcu_retry_check_delay = SRCU_DEFAULT_RETRY_CHECK_DELAY;
+module_param(srcu_retry_check_delay, ulong, 0444);
+
+#define SRCU_INTERVAL          1               // Base delay if no expedited GPs pending.
+#define SRCU_MAX_INTERVAL      10              // Maximum incremental delay from slow readers.
+
+#define SRCU_DEFAULT_MAX_NODELAY_PHASE_LO      3UL     // Lowmark on default per-GP-phase
+                                                       // no-delay instances.
+#define SRCU_DEFAULT_MAX_NODELAY_PHASE_HI      1000UL  // Highmark on default per-GP-phase
+                                                       // no-delay instances.
+
+#define SRCU_UL_CLAMP_LO(val, low)     ((val) > (low) ? (val) : (low))
+#define SRCU_UL_CLAMP_HI(val, high)    ((val) < (high) ? (val) : (high))
+#define SRCU_UL_CLAMP(val, low, high)  SRCU_UL_CLAMP_HI(SRCU_UL_CLAMP_LO((val), (low)), (high))
+// per-GP-phase no-delay instances adjusted to allow non-sleeping poll upto
+// one jiffies time duration. Mult by 2 is done to factor in the srcu_get_delay()
+// called from process_srcu().
+#define SRCU_DEFAULT_MAX_NODELAY_PHASE_ADJUSTED        \
+       (2UL * USEC_PER_SEC / HZ / SRCU_DEFAULT_RETRY_CHECK_DELAY)
+
+// Maximum per-GP-phase consecutive no-delay instances.
+#define SRCU_DEFAULT_MAX_NODELAY_PHASE \
+       SRCU_UL_CLAMP(SRCU_DEFAULT_MAX_NODELAY_PHASE_ADJUSTED,  \
+                     SRCU_DEFAULT_MAX_NODELAY_PHASE_LO,        \
+                     SRCU_DEFAULT_MAX_NODELAY_PHASE_HI)
+
+static ulong srcu_max_nodelay_phase = SRCU_DEFAULT_MAX_NODELAY_PHASE;
+module_param(srcu_max_nodelay_phase, ulong, 0444);
+
+// Maximum consecutive no-delay instances.
+#define SRCU_DEFAULT_MAX_NODELAY       (SRCU_DEFAULT_MAX_NODELAY_PHASE > 100 ? \
+                                        SRCU_DEFAULT_MAX_NODELAY_PHASE : 100)
+
+static ulong srcu_max_nodelay = SRCU_DEFAULT_MAX_NODELAY;
+module_param(srcu_max_nodelay, ulong, 0444);
 
 /*
  * Return grace-period delay, zero if there are expedited grace
@@ -522,16 +564,22 @@ static bool srcu_readers_active(struct srcu_struct *ssp)
  */
 static unsigned long srcu_get_delay(struct srcu_struct *ssp)
 {
+       unsigned long gpstart;
+       unsigned long j;
        unsigned long jbase = SRCU_INTERVAL;
 
        if (ULONG_CMP_LT(READ_ONCE(ssp->srcu_gp_seq), READ_ONCE(ssp->srcu_gp_seq_needed_exp)))
                jbase = 0;
-       if (rcu_seq_state(READ_ONCE(ssp->srcu_gp_seq)))
-               jbase += jiffies - READ_ONCE(ssp->srcu_gp_start);
-       if (!jbase) {
-               WRITE_ONCE(ssp->srcu_n_exp_nodelay, READ_ONCE(ssp->srcu_n_exp_nodelay) + 1);
-               if (READ_ONCE(ssp->srcu_n_exp_nodelay) > SRCU_MAX_NODELAY_PHASE)
-                       jbase = 1;
+       if (rcu_seq_state(READ_ONCE(ssp->srcu_gp_seq))) {
+               j = jiffies - 1;
+               gpstart = READ_ONCE(ssp->srcu_gp_start);
+               if (time_after(j, gpstart))
+                       jbase += j - gpstart;
+               if (!jbase) {
+                       WRITE_ONCE(ssp->srcu_n_exp_nodelay, READ_ONCE(ssp->srcu_n_exp_nodelay) + 1);
+                       if (READ_ONCE(ssp->srcu_n_exp_nodelay) > srcu_max_nodelay_phase)
+                               jbase = 1;
+               }
        }
        return jbase > SRCU_MAX_INTERVAL ? SRCU_MAX_INTERVAL : jbase;
 }
@@ -607,15 +655,6 @@ void __srcu_read_unlock(struct srcu_struct *ssp, int idx)
 EXPORT_SYMBOL_GPL(__srcu_read_unlock);
 
 /*
- * We use an adaptive strategy for synchronize_srcu() and especially for
- * synchronize_srcu_expedited().  We spin for a fixed time period
- * (defined below) to allow SRCU readers to exit their read-side critical
- * sections.  If there are still some readers after a few microseconds,
- * we repeatedly block for 1-millisecond time periods.
- */
-#define SRCU_RETRY_CHECK_DELAY         5
-
-/*
  * Start an SRCU grace period.
  */
 static void srcu_gp_start(struct srcu_struct *ssp)
@@ -700,7 +739,7 @@ static void srcu_schedule_cbs_snp(struct srcu_struct *ssp, struct srcu_node *snp
  */
 static void srcu_gp_end(struct srcu_struct *ssp)
 {
-       unsigned long cbdelay;
+       unsigned long cbdelay = 1;
        bool cbs;
        bool last_lvl;
        int cpu;
@@ -720,7 +759,9 @@ static void srcu_gp_end(struct srcu_struct *ssp)
        spin_lock_irq_rcu_node(ssp);
        idx = rcu_seq_state(ssp->srcu_gp_seq);
        WARN_ON_ONCE(idx != SRCU_STATE_SCAN2);
-       cbdelay = !!srcu_get_delay(ssp);
+       if (ULONG_CMP_LT(READ_ONCE(ssp->srcu_gp_seq), READ_ONCE(ssp->srcu_gp_seq_needed_exp)))
+               cbdelay = 0;
+
        WRITE_ONCE(ssp->srcu_last_gp_end, ktime_get_mono_fast_ns());
        rcu_seq_end(&ssp->srcu_gp_seq);
        gpseq = rcu_seq_current(&ssp->srcu_gp_seq);
@@ -921,12 +962,16 @@ static void srcu_funnel_gp_start(struct srcu_struct *ssp, struct srcu_data *sdp,
  */
 static bool try_check_zero(struct srcu_struct *ssp, int idx, int trycount)
 {
+       unsigned long curdelay;
+
+       curdelay = !srcu_get_delay(ssp);
+
        for (;;) {
                if (srcu_readers_active_idx_check(ssp, idx))
                        return true;
-               if (--trycount + !srcu_get_delay(ssp) <= 0)
+               if ((--trycount + curdelay) <= 0)
                        return false;
-               udelay(SRCU_RETRY_CHECK_DELAY);
+               udelay(srcu_retry_check_delay);
        }
 }
 
@@ -1582,7 +1627,7 @@ static void process_srcu(struct work_struct *work)
                j = jiffies;
                if (READ_ONCE(ssp->reschedule_jiffies) == j) {
                        WRITE_ONCE(ssp->reschedule_count, READ_ONCE(ssp->reschedule_count) + 1);
-                       if (READ_ONCE(ssp->reschedule_count) > SRCU_MAX_NODELAY)
+                       if (READ_ONCE(ssp->reschedule_count) > srcu_max_nodelay)
                                curdelay = 1;
                } else {
                        WRITE_ONCE(ssp->reschedule_count, 1);
@@ -1674,6 +1719,11 @@ static int __init srcu_bootup_announce(void)
        pr_info("Hierarchical SRCU implementation.\n");
        if (exp_holdoff != DEFAULT_SRCU_EXP_HOLDOFF)
                pr_info("\tNon-default auto-expedite holdoff of %lu ns.\n", exp_holdoff);
+       if (srcu_retry_check_delay != SRCU_DEFAULT_RETRY_CHECK_DELAY)
+               pr_info("\tNon-default retry check delay of %lu us.\n", srcu_retry_check_delay);
+       if (srcu_max_nodelay != SRCU_DEFAULT_MAX_NODELAY)
+               pr_info("\tNon-default max no-delay of %lu.\n", srcu_max_nodelay);
+       pr_info("\tMax phase no-delay instances is %lu.\n", srcu_max_nodelay_phase);
        return 0;
 }
 early_initcall(srcu_bootup_announce);
index 3925e32..83c7e66 100644 (file)
@@ -14,7 +14,7 @@
 
 struct rcu_tasks;
 typedef void (*rcu_tasks_gp_func_t)(struct rcu_tasks *rtp);
-typedef void (*pregp_func_t)(void);
+typedef void (*pregp_func_t)(struct list_head *hop);
 typedef void (*pertask_func_t)(struct task_struct *t, struct list_head *hop);
 typedef void (*postscan_func_t)(struct list_head *hop);
 typedef void (*holdouts_func_t)(struct list_head *hop, bool ndrpt, bool *frptp);
@@ -29,6 +29,7 @@ typedef void (*postgp_func_t)(struct rcu_tasks *rtp);
  * @rtp_work: Work queue for invoking callbacks.
  * @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.
  * @cpu: CPU number corresponding to this entry.
  * @rtpp: Pointer to the rcu_tasks structure.
  */
@@ -40,6 +41,7 @@ struct rcu_tasks_percpu {
        struct work_struct rtp_work;
        struct irq_work rtp_irq_work;
        struct rcu_head barrier_q_head;
+       struct list_head rtp_blkd_tasks;
        int cpu;
        struct rcu_tasks *rtpp;
 };
@@ -48,6 +50,7 @@ struct rcu_tasks_percpu {
  * struct rcu_tasks - Definition for a Tasks-RCU-like mechanism.
  * @cbs_wait: RCU wait allowing a new callback to get kthread's attention.
  * @cbs_gbl_lock: Lock protecting callback list.
+ * @tasks_gp_mutex: Mutex protecting grace period, needed during mid-boot dead zone.
  * @kthread_ptr: This flavor's grace-period/callback-invocation kthread.
  * @gp_func: This flavor's grace-period-wait function.
  * @gp_state: Grace period's most recent state transition (debugging).
@@ -79,6 +82,7 @@ struct rcu_tasks_percpu {
 struct rcu_tasks {
        struct rcuwait cbs_wait;
        raw_spinlock_t cbs_gbl_lock;
+       struct mutex tasks_gp_mutex;
        int gp_state;
        int gp_sleep;
        int init_fract;
@@ -119,6 +123,7 @@ static struct rcu_tasks rt_name =                                                   \
 {                                                                                      \
        .cbs_wait = __RCUWAIT_INITIALIZER(rt_name.wait),                                \
        .cbs_gbl_lock = __RAW_SPIN_LOCK_UNLOCKED(rt_name.cbs_gbl_lock),                 \
+       .tasks_gp_mutex = __MUTEX_INITIALIZER(rt_name.tasks_gp_mutex),                  \
        .gp_func = gp,                                                                  \
        .call_func = call,                                                              \
        .rtpcpu = &rt_name ## __percpu,                                                 \
@@ -140,6 +145,7 @@ static int rcu_task_ipi_delay __read_mostly = RCU_TASK_IPI_DELAY;
 module_param(rcu_task_ipi_delay, int, 0644);
 
 /* Control stall timeouts.  Disable with <= 0, otherwise jiffies till stall. */
+#define RCU_TASK_BOOT_STALL_TIMEOUT (HZ * 30)
 #define RCU_TASK_STALL_TIMEOUT (HZ * 60 * 10)
 static int rcu_task_stall_timeout __read_mostly = RCU_TASK_STALL_TIMEOUT;
 module_param(rcu_task_stall_timeout, int, 0644);
@@ -253,6 +259,8 @@ static void cblist_init_generic(struct rcu_tasks *rtp)
                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);
                raw_spin_unlock_rcu_node(rtpcp); // irqs remain disabled.
        }
        raw_spin_unlock_irqrestore(&rtp->cbs_gbl_lock, flags);
@@ -323,17 +331,6 @@ static void call_rcu_tasks_generic(struct rcu_head *rhp, rcu_callback_t func,
                irq_work_queue(&rtpcp->rtp_irq_work);
 }
 
-// Wait for a grace period for the specified flavor of Tasks RCU.
-static void synchronize_rcu_tasks_generic(struct rcu_tasks *rtp)
-{
-       /* Complain if the scheduler has not started.  */
-       RCU_LOCKDEP_WARN(rcu_scheduler_active == RCU_SCHEDULER_INACTIVE,
-                        "synchronize_rcu_tasks called too soon");
-
-       /* Wait for the grace period. */
-       wait_rcu_gp(rtp->call_func);
-}
-
 // RCU callback function for rcu_barrier_tasks_generic().
 static void rcu_barrier_tasks_generic_cb(struct rcu_head *rhp)
 {
@@ -439,6 +436,11 @@ static int rcu_tasks_need_gpcb(struct rcu_tasks *rtp)
                        WRITE_ONCE(rtp->percpu_dequeue_lim, 1);
                        pr_info("Completing switch %s to CPU-0 callback queuing.\n", rtp->name);
                }
+               for (cpu = rtp->percpu_dequeue_lim; cpu < nr_cpu_ids; cpu++) {
+                       struct rcu_tasks_percpu *rtpcp = per_cpu_ptr(rtp->rtpcpu, cpu);
+
+                       WARN_ON_ONCE(rcu_segcblist_n_cbs(&rtpcp->cblist));
+               }
                raw_spin_unlock_irqrestore(&rtp->cbs_gbl_lock, flags);
        }
 
@@ -497,10 +499,41 @@ static void rcu_tasks_invoke_cbs_wq(struct work_struct *wp)
        rcu_tasks_invoke_cbs(rtp, rtpcp);
 }
 
-/* RCU-tasks kthread that detects grace periods and invokes callbacks. */
-static int __noreturn rcu_tasks_kthread(void *arg)
+// Wait for one grace period.
+static void rcu_tasks_one_gp(struct rcu_tasks *rtp, bool midboot)
 {
        int needgpcb;
+
+       mutex_lock(&rtp->tasks_gp_mutex);
+
+       // If there were none, wait a bit and start over.
+       if (unlikely(midboot)) {
+               needgpcb = 0x2;
+       } else {
+               set_tasks_gp_state(rtp, RTGS_WAIT_CBS);
+               rcuwait_wait_event(&rtp->cbs_wait,
+                                  (needgpcb = rcu_tasks_need_gpcb(rtp)),
+                                  TASK_IDLE);
+       }
+
+       if (needgpcb & 0x2) {
+               // Wait for one grace period.
+               set_tasks_gp_state(rtp, RTGS_WAIT_GP);
+               rtp->gp_start = jiffies;
+               rcu_seq_start(&rtp->tasks_gp_seq);
+               rtp->gp_func(rtp);
+               rcu_seq_end(&rtp->tasks_gp_seq);
+       }
+
+       // Invoke callbacks.
+       set_tasks_gp_state(rtp, RTGS_INVOKE_CBS);
+       rcu_tasks_invoke_cbs(rtp, per_cpu_ptr(rtp->rtpcpu, 0));
+       mutex_unlock(&rtp->tasks_gp_mutex);
+}
+
+// RCU-tasks kthread that detects grace periods and invokes callbacks.
+static int __noreturn rcu_tasks_kthread(void *arg)
+{
        struct rcu_tasks *rtp = arg;
 
        /* Run on housekeeping CPUs by default.  Sysadm can move if desired. */
@@ -514,29 +547,28 @@ static int __noreturn rcu_tasks_kthread(void *arg)
         * This loop is terminated by the system going down.  ;-)
         */
        for (;;) {
-               set_tasks_gp_state(rtp, RTGS_WAIT_CBS);
+               // Wait for one grace period and invoke any callbacks
+               // that are ready.
+               rcu_tasks_one_gp(rtp, false);
 
-               /* If there were none, wait a bit and start over. */
-               rcuwait_wait_event(&rtp->cbs_wait,
-                                  (needgpcb = rcu_tasks_need_gpcb(rtp)),
-                                  TASK_IDLE);
-
-               if (needgpcb & 0x2) {
-                       // Wait for one grace period.
-                       set_tasks_gp_state(rtp, RTGS_WAIT_GP);
-                       rtp->gp_start = jiffies;
-                       rcu_seq_start(&rtp->tasks_gp_seq);
-                       rtp->gp_func(rtp);
-                       rcu_seq_end(&rtp->tasks_gp_seq);
-               }
+               // Paranoid sleep to keep this from entering a tight loop.
+               schedule_timeout_idle(rtp->gp_sleep);
+       }
+}
 
-               /* Invoke callbacks. */
-               set_tasks_gp_state(rtp, RTGS_INVOKE_CBS);
-               rcu_tasks_invoke_cbs(rtp, per_cpu_ptr(rtp->rtpcpu, 0));
+// Wait for a grace period for the specified flavor of Tasks RCU.
+static void synchronize_rcu_tasks_generic(struct rcu_tasks *rtp)
+{
+       /* Complain if the scheduler has not started.  */
+       RCU_LOCKDEP_WARN(rcu_scheduler_active == RCU_SCHEDULER_INACTIVE,
+                        "synchronize_rcu_tasks called too soon");
 
-               /* Paranoid sleep to keep this from entering a tight loop */
-               schedule_timeout_idle(rtp->gp_sleep);
+       // If the grace-period kthread is running, use it.
+       if (READ_ONCE(rtp->kthread_ptr)) {
+               wait_rcu_gp(rtp->call_func);
+               return;
        }
+       rcu_tasks_one_gp(rtp, true);
 }
 
 /* Spawn RCU-tasks grace-period kthread. */
@@ -630,7 +662,7 @@ static void rcu_tasks_wait_gp(struct rcu_tasks *rtp)
        struct task_struct *t;
 
        set_tasks_gp_state(rtp, RTGS_PRE_WAIT_GP);
-       rtp->pregp_func();
+       rtp->pregp_func(&holdouts);
 
        /*
         * There were callbacks, so we need to wait for an RCU-tasks
@@ -639,10 +671,12 @@ static void rcu_tasks_wait_gp(struct rcu_tasks *rtp)
         * and make a list of them in holdouts.
         */
        set_tasks_gp_state(rtp, RTGS_SCAN_TASKLIST);
-       rcu_read_lock();
-       for_each_process_thread(g, t)
-               rtp->pertask_func(t, &holdouts);
-       rcu_read_unlock();
+       if (rtp->pertask_func) {
+               rcu_read_lock();
+               for_each_process_thread(g, t)
+                       rtp->pertask_func(t, &holdouts);
+               rcu_read_unlock();
+       }
 
        set_tasks_gp_state(rtp, RTGS_POST_SCAN_TASKLIST);
        rtp->postscan_func(&holdouts);
@@ -760,7 +794,7 @@ static void rcu_tasks_wait_gp(struct rcu_tasks *rtp)
 // disabling.
 
 /* Pre-grace-period preparation. */
-static void rcu_tasks_pregp_step(void)
+static void rcu_tasks_pregp_step(struct list_head *hop)
 {
        /*
         * Wait for all pre-existing t->on_rq and t->nvcsw transitions
@@ -1105,11 +1139,10 @@ EXPORT_SYMBOL_GPL(show_rcu_tasks_rude_gp_kthread);
 // 3.  Avoids expensive read-side instructions, having overhead similar
 //     to that of Preemptible RCU.
 //
-// There are of course downsides.  The grace-period code can send IPIs to
-// CPUs, even when those CPUs are in the idle loop or in nohz_full userspace.
-// It is necessary to scan the full tasklist, much as for Tasks RCU.  There
-// is a single callback queue guarded by a single lock, again, much as for
-// Tasks RCU.  If needed, these downsides can be at least partially remedied.
+// There are of course downsides.  For example, the grace-period code
+// can send IPIs to CPUs, even when those CPUs are in the idle loop or
+// in nohz_full userspace.  If needed, these downsides can be at least
+// partially remedied.
 //
 // Perhaps most important, this variant of RCU does not affect the vanilla
 // flavors, rcu_preempt and rcu_sched.  The fact that RCU Tasks Trace
@@ -1122,38 +1155,30 @@ EXPORT_SYMBOL_GPL(show_rcu_tasks_rude_gp_kthread);
 // invokes these functions in this order:
 //
 // rcu_tasks_trace_pregp_step():
-//     Initialize the count of readers and block CPU-hotplug operations.
-// rcu_tasks_trace_pertask(), invoked on every non-idle task:
-//     Initialize per-task state and attempt to identify an immediate
-//     quiescent state for that task, or, failing that, attempt to
-//     set that task's .need_qs flag so that task's next outermost
-//     rcu_read_unlock_trace() will report the quiescent state (in which
-//     case the count of readers is incremented).  If both attempts fail,
-//     the task is added to a "holdout" list.  Note that IPIs are used
-//     to invoke trc_read_check_handler() in the context of running tasks
-//     in order to avoid ordering overhead on common-case shared-variable
-//     accessses.
+//     Disables CPU hotplug, adds all currently executing tasks to the
+//     holdout list, then checks the state of all tasks that blocked
+//     or were preempted within their current RCU Tasks Trace read-side
+//     critical section, adding them to the holdout list if appropriate.
+//     Finally, this function re-enables CPU hotplug.
+// The ->pertask_func() pointer is NULL, so there is no per-task processing.
 // rcu_tasks_trace_postscan():
-//     Initialize state and attempt to identify an immediate quiescent
-//     state as above (but only for idle tasks), unblock CPU-hotplug
-//     operations, and wait for an RCU grace period to avoid races with
-//     tasks that are in the process of exiting.
+//     Invokes synchronize_rcu() to wait for late-stage exiting tasks
+//     to finish exiting.
 // check_all_holdout_tasks_trace(), 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
-//     corresponding task is removed from the holdout list.
+//     corresponding task is removed from the holdout list.  Once this
+//     list is empty, the grace period has completed.
 // rcu_tasks_trace_postgp():
-//     Wait for the count of readers do drop to zero, reporting any stalls.
-//     Also execute full memory barriers to maintain ordering with code
-//     executing after the grace period.
+//     Provides the needed full memory barrier and does debug checks.
 //
 // The exit_tasks_rcu_finish_trace() synchronizes with exiting tasks.
 //
-// Pre-grace-period update-side code is ordered before the grace
-// period via the ->cbs_lock and barriers in rcu_tasks_kthread().
-// Pre-grace-period read-side code is ordered before the grace period by
-// atomic_dec_and_test() of the count of readers (for IPIed readers) and by
-// scheduler context-switch ordering (for locked-down non-running readers).
+// Pre-grace-period update-side code is ordered before the grace period
+// via the ->cbs_lock and barriers in rcu_tasks_kthread().  Pre-grace-period
+// read-side code is ordered before the grace period by atomic operations
+// on .b.need_qs flag of each task involved in this process, or by scheduler
+// context-switch ordering (for locked-down non-running readers).
 
 // The lockdep state must be outside of #ifdef to be useful.
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
@@ -1165,9 +1190,6 @@ EXPORT_SYMBOL_GPL(rcu_trace_lock_map);
 
 #ifdef CONFIG_TASKS_TRACE_RCU
 
-static atomic_t trc_n_readers_need_end;                // Number of waited-for readers.
-static DECLARE_WAIT_QUEUE_HEAD(trc_wait);      // List of holdout tasks.
-
 // Record outstanding IPIs to each CPU.  No point in sending two...
 static DEFINE_PER_CPU(bool, trc_ipi_to_cpu);
 
@@ -1176,44 +1198,104 @@ static DEFINE_PER_CPU(bool, trc_ipi_to_cpu);
 static unsigned long n_heavy_reader_attempts;
 static unsigned long n_heavy_reader_updates;
 static unsigned long n_heavy_reader_ofl_updates;
+static unsigned long n_trc_holdouts;
 
 void call_rcu_tasks_trace(struct rcu_head *rhp, rcu_callback_t func);
 DEFINE_RCU_TASKS(rcu_tasks_trace, rcu_tasks_wait_gp, call_rcu_tasks_trace,
                 "RCU Tasks Trace");
 
+/* Load from ->trc_reader_special.b.need_qs with proper ordering. */
+static u8 rcu_ld_need_qs(struct task_struct *t)
+{
+       smp_mb(); // Enforce full grace-period ordering.
+       return smp_load_acquire(&t->trc_reader_special.b.need_qs);
+}
+
+/* Store to ->trc_reader_special.b.need_qs with proper ordering. */
+static void rcu_st_need_qs(struct task_struct *t, u8 v)
+{
+       smp_store_release(&t->trc_reader_special.b.need_qs, v);
+       smp_mb(); // Enforce full grace-period ordering.
+}
+
 /*
- * This irq_work handler allows rcu_read_unlock_trace() to be invoked
- * while the scheduler locks are held.
+ * Do a cmpxchg() on ->trc_reader_special.b.need_qs, allowing for
+ * the four-byte operand-size restriction of some platforms.
+ * Returns the old value, which is often ignored.
  */
-static void rcu_read_unlock_iw(struct irq_work *iwp)
+u8 rcu_trc_cmpxchg_need_qs(struct task_struct *t, u8 old, u8 new)
 {
-       wake_up(&trc_wait);
+       union rcu_special ret;
+       union rcu_special trs_old = READ_ONCE(t->trc_reader_special);
+       union rcu_special trs_new = trs_old;
+
+       if (trs_old.b.need_qs != old)
+               return trs_old.b.need_qs;
+       trs_new.b.need_qs = new;
+       ret.s = cmpxchg(&t->trc_reader_special.s, trs_old.s, trs_new.s);
+       return ret.b.need_qs;
 }
-static DEFINE_IRQ_WORK(rcu_tasks_trace_iw, rcu_read_unlock_iw);
+EXPORT_SYMBOL_GPL(rcu_trc_cmpxchg_need_qs);
 
-/* If we are the last reader, wake up the grace-period kthread. */
+/*
+ * If we are the last reader, signal the grace-period kthread.
+ * Also remove from the per-CPU list of blocked tasks.
+ */
 void rcu_read_unlock_trace_special(struct task_struct *t)
 {
-       int nq = READ_ONCE(t->trc_reader_special.b.need_qs);
+       unsigned long flags;
+       struct rcu_tasks_percpu *rtpcp;
+       union rcu_special trs;
+
+       // Open-coded full-word version of rcu_ld_need_qs().
+       smp_mb(); // Enforce full grace-period ordering.
+       trs = smp_load_acquire(&t->trc_reader_special);
 
-       if (IS_ENABLED(CONFIG_TASKS_TRACE_RCU_READ_MB) &&
-           t->trc_reader_special.b.need_mb)
+       if (IS_ENABLED(CONFIG_TASKS_TRACE_RCU_READ_MB) && t->trc_reader_special.b.need_mb)
                smp_mb(); // Pairs with update-side barriers.
        // Update .need_qs before ->trc_reader_nesting for irq/NMI handlers.
-       if (nq)
-               WRITE_ONCE(t->trc_reader_special.b.need_qs, false);
+       if (trs.b.need_qs == (TRC_NEED_QS_CHECKED | TRC_NEED_QS)) {
+               u8 result = rcu_trc_cmpxchg_need_qs(t, TRC_NEED_QS_CHECKED | TRC_NEED_QS,
+                                                      TRC_NEED_QS_CHECKED);
+
+               WARN_ONCE(result != trs.b.need_qs, "%s: result = %d", __func__, result);
+       }
+       if (trs.b.blocked) {
+               rtpcp = per_cpu_ptr(rcu_tasks_trace.rtpcpu, t->trc_blkd_cpu);
+               raw_spin_lock_irqsave_rcu_node(rtpcp, flags);
+               list_del_init(&t->trc_blkd_node);
+               WRITE_ONCE(t->trc_reader_special.b.blocked, false);
+               raw_spin_unlock_irqrestore_rcu_node(rtpcp, flags);
+       }
        WRITE_ONCE(t->trc_reader_nesting, 0);
-       if (nq && atomic_dec_and_test(&trc_n_readers_need_end))
-               irq_work_queue(&rcu_tasks_trace_iw);
 }
 EXPORT_SYMBOL_GPL(rcu_read_unlock_trace_special);
 
+/* Add a newly blocked reader task to its CPU's list. */
+void rcu_tasks_trace_qs_blkd(struct task_struct *t)
+{
+       unsigned long flags;
+       struct rcu_tasks_percpu *rtpcp;
+
+       local_irq_save(flags);
+       rtpcp = this_cpu_ptr(rcu_tasks_trace.rtpcpu);
+       raw_spin_lock_rcu_node(rtpcp); // irqs already disabled
+       t->trc_blkd_cpu = smp_processor_id();
+       if (!rtpcp->rtp_blkd_tasks.next)
+               INIT_LIST_HEAD(&rtpcp->rtp_blkd_tasks);
+       list_add(&t->trc_blkd_node, &rtpcp->rtp_blkd_tasks);
+       WRITE_ONCE(t->trc_reader_special.b.blocked, true);
+       raw_spin_unlock_irqrestore_rcu_node(rtpcp, flags);
+}
+EXPORT_SYMBOL_GPL(rcu_tasks_trace_qs_blkd);
+
 /* Add a task to the holdout list, if it is not already on the list. */
 static void trc_add_holdout(struct task_struct *t, struct list_head *bhp)
 {
        if (list_empty(&t->trc_holdout_list)) {
                get_task_struct(t);
                list_add(&t->trc_holdout_list, bhp);
+               n_trc_holdouts++;
        }
 }
 
@@ -1223,37 +1305,36 @@ static void trc_del_holdout(struct task_struct *t)
        if (!list_empty(&t->trc_holdout_list)) {
                list_del_init(&t->trc_holdout_list);
                put_task_struct(t);
+               n_trc_holdouts--;
        }
 }
 
 /* IPI handler to check task state. */
 static void trc_read_check_handler(void *t_in)
 {
+       int nesting;
        struct task_struct *t = current;
        struct task_struct *texp = t_in;
 
        // If the task is no longer running on this CPU, leave.
-       if (unlikely(texp != t)) {
+       if (unlikely(texp != t))
                goto reset_ipi; // Already on holdout list, so will check later.
-       }
 
        // If the task is not in a read-side critical section, and
        // if this is the last reader, awaken the grace-period kthread.
-       if (likely(!READ_ONCE(t->trc_reader_nesting))) {
-               WRITE_ONCE(t->trc_reader_checked, true);
+       nesting = READ_ONCE(t->trc_reader_nesting);
+       if (likely(!nesting)) {
+               rcu_trc_cmpxchg_need_qs(t, 0, TRC_NEED_QS_CHECKED);
                goto reset_ipi;
        }
        // If we are racing with an rcu_read_unlock_trace(), try again later.
-       if (unlikely(READ_ONCE(t->trc_reader_nesting) < 0))
+       if (unlikely(nesting < 0))
                goto reset_ipi;
-       WRITE_ONCE(t->trc_reader_checked, true);
 
-       // Get here if the task is in a read-side critical section.  Set
-       // its state so that it will awaken the grace-period kthread upon
-       // exit from that critical section.
-       atomic_inc(&trc_n_readers_need_end); // One more to wait on.
-       WARN_ON_ONCE(READ_ONCE(t->trc_reader_special.b.need_qs));
-       WRITE_ONCE(t->trc_reader_special.b.need_qs, true);
+       // Get here if the task is in a read-side critical section.
+       // Set its state so that it will update state for the grace-period
+       // kthread upon exit from that critical section.
+       rcu_trc_cmpxchg_need_qs(t, 0, TRC_NEED_QS | TRC_NEED_QS_CHECKED);
 
 reset_ipi:
        // Allow future IPIs to be sent on CPU and for task.
@@ -1264,48 +1345,50 @@ reset_ipi:
 }
 
 /* Callback function for scheduler to check locked-down task.  */
-static int trc_inspect_reader(struct task_struct *t, void *arg)
+static int trc_inspect_reader(struct task_struct *t, void *bhp_in)
 {
+       struct list_head *bhp = bhp_in;
        int cpu = task_cpu(t);
        int nesting;
        bool ofl = cpu_is_offline(cpu);
 
-       if (task_curr(t)) {
-               WARN_ON_ONCE(ofl && !is_idle_task(t));
-
+       if (task_curr(t) && !ofl) {
                // If no chance of heavyweight readers, do it the hard way.
-               if (!ofl && !IS_ENABLED(CONFIG_TASKS_TRACE_RCU_READ_MB))
+               if (!IS_ENABLED(CONFIG_TASKS_TRACE_RCU_READ_MB))
                        return -EINVAL;
 
                // If heavyweight readers are enabled on the remote task,
                // we can inspect its state despite its currently running.
                // However, we cannot safely change its state.
                n_heavy_reader_attempts++;
-               if (!ofl && // Check for "running" idle tasks on offline CPUs.
-                   !rcu_dynticks_zero_in_eqs(cpu, &t->trc_reader_nesting))
+               // Check for "running" idle tasks on offline CPUs.
+               if (!rcu_dynticks_zero_in_eqs(cpu, &t->trc_reader_nesting))
                        return -EINVAL; // No quiescent state, do it the hard way.
                n_heavy_reader_updates++;
-               if (ofl)
-                       n_heavy_reader_ofl_updates++;
                nesting = 0;
        } else {
                // The task is not running, so C-language access is safe.
                nesting = t->trc_reader_nesting;
+               WARN_ON_ONCE(ofl && task_curr(t) && !is_idle_task(t));
+               if (IS_ENABLED(CONFIG_TASKS_TRACE_RCU_READ_MB) && ofl)
+                       n_heavy_reader_ofl_updates++;
        }
 
        // If not exiting a read-side critical section, mark as checked
        // so that the grace-period kthread will remove it from the
        // holdout list.
-       t->trc_reader_checked = nesting >= 0;
-       if (nesting <= 0)
-               return nesting ? -EINVAL : 0;  // If in QS, done, otherwise try again later.
+       if (!nesting) {
+               rcu_trc_cmpxchg_need_qs(t, 0, TRC_NEED_QS_CHECKED);
+               return 0;  // In QS, so done.
+       }
+       if (nesting < 0)
+               return -EINVAL; // Reader transitioning, try again later.
 
        // The task is in a read-side critical section, so set up its
-       // state so that it will awaken the grace-period kthread upon exit
-       // from that critical section.
-       atomic_inc(&trc_n_readers_need_end); // One more to wait on.
-       WARN_ON_ONCE(READ_ONCE(t->trc_reader_special.b.need_qs));
-       WRITE_ONCE(t->trc_reader_special.b.need_qs, true);
+       // state so that it will update state upon exit from that critical
+       // section.
+       if (!rcu_trc_cmpxchg_need_qs(t, 0, TRC_NEED_QS | TRC_NEED_QS_CHECKED))
+               trc_add_holdout(t, bhp);
        return 0;
 }
 
@@ -1321,14 +1404,14 @@ static void trc_wait_for_one_reader(struct task_struct *t,
 
        // The current task had better be in a quiescent state.
        if (t == current) {
-               t->trc_reader_checked = true;
+               rcu_trc_cmpxchg_need_qs(t, 0, TRC_NEED_QS_CHECKED);
                WARN_ON_ONCE(READ_ONCE(t->trc_reader_nesting));
                return;
        }
 
        // Attempt to nail down the task for inspection.
        get_task_struct(t);
-       if (!task_call_func(t, trc_inspect_reader, NULL)) {
+       if (!task_call_func(t, trc_inspect_reader, bhp)) {
                put_task_struct(t);
                return;
        }
@@ -1366,56 +1449,93 @@ static void trc_wait_for_one_reader(struct task_struct *t,
        }
 }
 
+/*
+ * Initialize for first-round processing for the specified task.
+ * Return false if task is NULL or already taken care of, true otherwise.
+ */
+static bool rcu_tasks_trace_pertask_prep(struct task_struct *t, bool notself)
+{
+       // During early boot when there is only the one boot CPU, there
+       // is no idle task for the other CPUs.  Also, the grace-period
+       // kthread is always in a quiescent state.  In addition, just return
+       // if this task is already on the list.
+       if (unlikely(t == NULL) || (t == current && notself) || !list_empty(&t->trc_holdout_list))
+               return false;
+
+       rcu_st_need_qs(t, 0);
+       t->trc_ipi_to_cpu = -1;
+       return true;
+}
+
+/* Do first-round processing for the specified task. */
+static void rcu_tasks_trace_pertask(struct task_struct *t, struct list_head *hop)
+{
+       if (rcu_tasks_trace_pertask_prep(t, true))
+               trc_wait_for_one_reader(t, hop);
+}
+
 /* Initialize for a new RCU-tasks-trace grace period. */
-static void rcu_tasks_trace_pregp_step(void)
+static void rcu_tasks_trace_pregp_step(struct list_head *hop)
 {
+       LIST_HEAD(blkd_tasks);
        int cpu;
-
-       // Allow for fast-acting IPIs.
-       atomic_set(&trc_n_readers_need_end, 1);
+       unsigned long flags;
+       struct rcu_tasks_percpu *rtpcp;
+       struct task_struct *t;
 
        // There shouldn't be any old IPIs, but...
        for_each_possible_cpu(cpu)
                WARN_ON_ONCE(per_cpu(trc_ipi_to_cpu, cpu));
 
-       // Disable CPU hotplug across the tasklist scan.
-       // This also waits for all readers in CPU-hotplug code paths.
+       // Disable CPU hotplug across the CPU scan for the benefit of
+       // any IPIs that might be needed.  This also waits for all readers
+       // in CPU-hotplug code paths.
        cpus_read_lock();
-}
 
-/* Do first-round processing for the specified task. */
-static void rcu_tasks_trace_pertask(struct task_struct *t,
-                                   struct list_head *hop)
-{
-       // During early boot when there is only the one boot CPU, there
-       // is no idle task for the other CPUs. Just return.
-       if (unlikely(t == NULL))
-               return;
+       // These rcu_tasks_trace_pertask_prep() calls are serialized to
+       // allow safe access to the hop list.
+       for_each_online_cpu(cpu) {
+               rcu_read_lock();
+               t = cpu_curr_snapshot(cpu);
+               if (rcu_tasks_trace_pertask_prep(t, true))
+                       trc_add_holdout(t, hop);
+               rcu_read_unlock();
+       }
 
-       WRITE_ONCE(t->trc_reader_special.b.need_qs, false);
-       WRITE_ONCE(t->trc_reader_checked, false);
-       t->trc_ipi_to_cpu = -1;
-       trc_wait_for_one_reader(t, hop);
+       // Only after all running tasks have been accounted for is it
+       // safe to take care of the tasks that have blocked within their
+       // current RCU tasks trace read-side critical section.
+       for_each_possible_cpu(cpu) {
+               rtpcp = per_cpu_ptr(rcu_tasks_trace.rtpcpu, cpu);
+               raw_spin_lock_irqsave_rcu_node(rtpcp, flags);
+               list_splice_init(&rtpcp->rtp_blkd_tasks, &blkd_tasks);
+               while (!list_empty(&blkd_tasks)) {
+                       rcu_read_lock();
+                       t = list_first_entry(&blkd_tasks, struct task_struct, trc_blkd_node);
+                       list_del_init(&t->trc_blkd_node);
+                       list_add(&t->trc_blkd_node, &rtpcp->rtp_blkd_tasks);
+                       raw_spin_unlock_irqrestore_rcu_node(rtpcp, flags);
+                       rcu_tasks_trace_pertask(t, hop);
+                       rcu_read_unlock();
+                       raw_spin_lock_irqsave_rcu_node(rtpcp, flags);
+               }
+               raw_spin_unlock_irqrestore_rcu_node(rtpcp, flags);
+       }
+
+       // Re-enable CPU hotplug now that the holdout list is populated.
+       cpus_read_unlock();
 }
 
 /*
- * Do intermediate processing between task and holdout scans and
- * pick up the idle tasks.
+ * Do intermediate processing between task and holdout scans.
  */
 static void rcu_tasks_trace_postscan(struct list_head *hop)
 {
-       int cpu;
-
-       for_each_possible_cpu(cpu)
-               rcu_tasks_trace_pertask(idle_task(cpu), hop);
-
-       // Re-enable CPU hotplug now that the tasklist scan has completed.
-       cpus_read_unlock();
-
        // Wait for late-stage exiting tasks to finish exiting.
        // These might have passed the call to exit_tasks_rcu_finish().
        synchronize_rcu();
-       // Any tasks that exit after this point will set ->trc_reader_checked.
+       // Any tasks that exit after this point will set
+       // TRC_NEED_QS_CHECKED in ->trc_reader_special.b.need_qs.
 }
 
 /* Communicate task state back to the RCU tasks trace stall warning request. */
@@ -1429,11 +1549,11 @@ static int trc_check_slow_task(struct task_struct *t, void *arg)
 {
        struct trc_stall_chk_rdr *trc_rdrp = arg;
 
-       if (task_curr(t))
+       if (task_curr(t) && cpu_online(task_cpu(t)))
                return false; // It is running, so decline to inspect it.
        trc_rdrp->nesting = READ_ONCE(t->trc_reader_nesting);
        trc_rdrp->ipi_to_cpu = READ_ONCE(t->trc_ipi_to_cpu);
-       trc_rdrp->needqs = READ_ONCE(t->trc_reader_special.b.need_qs);
+       trc_rdrp->needqs = rcu_ld_need_qs(t);
        return true;
 }
 
@@ -1450,18 +1570,21 @@ static void show_stalled_task_trace(struct task_struct *t, bool *firstreport)
        }
        cpu = task_cpu(t);
        if (!task_call_func(t, trc_check_slow_task, &trc_rdr))
-               pr_alert("P%d: %c\n",
+               pr_alert("P%d: %c%c\n",
                         t->pid,
+                        ".I"[t->trc_ipi_to_cpu >= 0],
                         ".i"[is_idle_tsk]);
        else
-               pr_alert("P%d: %c%c%c nesting: %d%c cpu: %d\n",
+               pr_alert("P%d: %c%c%c%c nesting: %d%c%c cpu: %d%s\n",
                         t->pid,
                         ".I"[trc_rdr.ipi_to_cpu >= 0],
                         ".i"[is_idle_tsk],
                         ".N"[cpu >= 0 && tick_nohz_full_cpu(cpu)],
+                        ".B"[!!data_race(t->trc_reader_special.b.blocked)],
                         trc_rdr.nesting,
-                        " N"[!!trc_rdr.needqs],
-                        cpu);
+                        " !CN"[trc_rdr.needqs & 0x3],
+                        " ?"[trc_rdr.needqs > 0x3],
+                        cpu, cpu_online(cpu) ? "" : "(offline)");
        sched_show_task(t);
 }
 
@@ -1481,18 +1604,18 @@ static void check_all_holdout_tasks_trace(struct list_head *hop,
 {
        struct task_struct *g, *t;
 
-       // Disable CPU hotplug across the holdout list scan.
+       // Disable CPU hotplug across the holdout list scan for IPIs.
        cpus_read_lock();
 
        list_for_each_entry_safe(t, g, hop, trc_holdout_list) {
                // If safe and needed, try to check the current task.
                if (READ_ONCE(t->trc_ipi_to_cpu) == -1 &&
-                   !READ_ONCE(t->trc_reader_checked))
+                   !(rcu_ld_need_qs(t) & TRC_NEED_QS_CHECKED))
                        trc_wait_for_one_reader(t, hop);
 
                // If check succeeded, remove this task from the list.
                if (smp_load_acquire(&t->trc_ipi_to_cpu) == -1 &&
-                   READ_ONCE(t->trc_reader_checked))
+                   rcu_ld_need_qs(t) == TRC_NEED_QS_CHECKED)
                        trc_del_holdout(t);
                else if (needreport)
                        show_stalled_task_trace(t, firstreport);
@@ -1516,10 +1639,6 @@ static void rcu_tasks_trace_empty_fn(void *unused)
 static void rcu_tasks_trace_postgp(struct rcu_tasks *rtp)
 {
        int cpu;
-       bool firstreport;
-       struct task_struct *g, *t;
-       LIST_HEAD(holdouts);
-       long ret;
 
        // Wait for any lingering IPI handlers to complete.  Note that
        // if a CPU has gone offline or transitioned to userspace in the
@@ -1530,37 +1649,6 @@ static void rcu_tasks_trace_postgp(struct rcu_tasks *rtp)
                if (WARN_ON_ONCE(smp_load_acquire(per_cpu_ptr(&trc_ipi_to_cpu, cpu))))
                        smp_call_function_single(cpu, rcu_tasks_trace_empty_fn, NULL, 1);
 
-       // Remove the safety count.
-       smp_mb__before_atomic();  // Order vs. earlier atomics
-       atomic_dec(&trc_n_readers_need_end);
-       smp_mb__after_atomic();  // Order vs. later atomics
-
-       // Wait for readers.
-       set_tasks_gp_state(rtp, RTGS_WAIT_READERS);
-       for (;;) {
-               ret = wait_event_idle_exclusive_timeout(
-                               trc_wait,
-                               atomic_read(&trc_n_readers_need_end) == 0,
-                               READ_ONCE(rcu_task_stall_timeout));
-               if (ret)
-                       break;  // Count reached zero.
-               // Stall warning time, so make a list of the offenders.
-               rcu_read_lock();
-               for_each_process_thread(g, t)
-                       if (READ_ONCE(t->trc_reader_special.b.need_qs))
-                               trc_add_holdout(t, &holdouts);
-               rcu_read_unlock();
-               firstreport = true;
-               list_for_each_entry_safe(t, g, &holdouts, trc_holdout_list) {
-                       if (READ_ONCE(t->trc_reader_special.b.need_qs))
-                               show_stalled_task_trace(t, &firstreport);
-                       trc_del_holdout(t); // Release task_struct reference.
-               }
-               if (firstreport)
-                       pr_err("INFO: rcu_tasks_trace detected stalls? (Counter/taskslist mismatch?)\n");
-               show_stalled_ipi_trace();
-               pr_err("\t%d holdouts\n", atomic_read(&trc_n_readers_need_end));
-       }
        smp_mb(); // Caller's code must be ordered after wakeup.
                  // Pairs with pretty much every ordering primitive.
 }
@@ -1568,11 +1656,14 @@ static void rcu_tasks_trace_postgp(struct rcu_tasks *rtp)
 /* Report any needed quiescent state for this exiting task. */
 static void exit_tasks_rcu_finish_trace(struct task_struct *t)
 {
-       WRITE_ONCE(t->trc_reader_checked, true);
+       union rcu_special trs = READ_ONCE(t->trc_reader_special);
+
+       rcu_trc_cmpxchg_need_qs(t, 0, TRC_NEED_QS_CHECKED);
        WARN_ON_ONCE(READ_ONCE(t->trc_reader_nesting));
-       WRITE_ONCE(t->trc_reader_nesting, 0);
-       if (WARN_ON_ONCE(READ_ONCE(t->trc_reader_special.b.need_qs)))
+       if (WARN_ON_ONCE(rcu_ld_need_qs(t) & TRC_NEED_QS || trs.b.blocked))
                rcu_read_unlock_trace_special(t);
+       else
+               WRITE_ONCE(t->trc_reader_nesting, 0);
 }
 
 /**
@@ -1646,7 +1737,6 @@ static int __init rcu_spawn_tasks_trace_kthread(void)
                        rcu_tasks_trace.init_fract = 1;
        }
        rcu_tasks_trace.pregp_func = rcu_tasks_trace_pregp_step;
-       rcu_tasks_trace.pertask_func = rcu_tasks_trace_pertask;
        rcu_tasks_trace.postscan_func = rcu_tasks_trace_postscan;
        rcu_tasks_trace.holdouts_func = check_all_holdout_tasks_trace;
        rcu_tasks_trace.postgp_func = rcu_tasks_trace_postgp;
@@ -1659,7 +1749,8 @@ void show_rcu_tasks_trace_gp_kthread(void)
 {
        char buf[64];
 
-       sprintf(buf, "N%d h:%lu/%lu/%lu", atomic_read(&trc_n_readers_need_end),
+       sprintf(buf, "N%lu h:%lu/%lu/%lu",
+               data_race(n_trc_holdouts),
                data_race(n_heavy_reader_ofl_updates),
                data_race(n_heavy_reader_updates),
                data_race(n_heavy_reader_attempts));
@@ -1686,23 +1777,24 @@ struct rcu_tasks_test_desc {
        struct rcu_head rh;
        const char *name;
        bool notrun;
+       unsigned long runstart;
 };
 
 static struct rcu_tasks_test_desc tests[] = {
        {
                .name = "call_rcu_tasks()",
                /* If not defined, the test is skipped. */
-               .notrun = !IS_ENABLED(CONFIG_TASKS_RCU),
+               .notrun = IS_ENABLED(CONFIG_TASKS_RCU),
        },
        {
                .name = "call_rcu_tasks_rude()",
                /* If not defined, the test is skipped. */
-               .notrun = !IS_ENABLED(CONFIG_TASKS_RUDE_RCU),
+               .notrun = IS_ENABLED(CONFIG_TASKS_RUDE_RCU),
        },
        {
                .name = "call_rcu_tasks_trace()",
                /* If not defined, the test is skipped. */
-               .notrun = !IS_ENABLED(CONFIG_TASKS_TRACE_RCU)
+               .notrun = IS_ENABLED(CONFIG_TASKS_TRACE_RCU)
        }
 };
 
@@ -1713,46 +1805,85 @@ static void test_rcu_tasks_callback(struct rcu_head *rhp)
 
        pr_info("Callback from %s invoked.\n", rttd->name);
 
-       rttd->notrun = true;
+       rttd->notrun = false;
 }
 
 static void rcu_tasks_initiate_self_tests(void)
 {
+       unsigned long j = jiffies;
+
        pr_info("Running RCU-tasks wait API self tests\n");
 #ifdef CONFIG_TASKS_RCU
+       tests[0].runstart = j;
        synchronize_rcu_tasks();
        call_rcu_tasks(&tests[0].rh, test_rcu_tasks_callback);
 #endif
 
 #ifdef CONFIG_TASKS_RUDE_RCU
+       tests[1].runstart = j;
        synchronize_rcu_tasks_rude();
        call_rcu_tasks_rude(&tests[1].rh, test_rcu_tasks_callback);
 #endif
 
 #ifdef CONFIG_TASKS_TRACE_RCU
+       tests[2].runstart = j;
        synchronize_rcu_tasks_trace();
        call_rcu_tasks_trace(&tests[2].rh, test_rcu_tasks_callback);
 #endif
 }
 
+/*
+ * Return:  0 - test passed
+ *         1 - test failed, but have not timed out yet
+ *        -1 - test failed and timed out
+ */
 static int rcu_tasks_verify_self_tests(void)
 {
        int ret = 0;
        int i;
+       unsigned long bst = rcu_task_stall_timeout;
 
+       if (bst <= 0 || bst > RCU_TASK_BOOT_STALL_TIMEOUT)
+               bst = RCU_TASK_BOOT_STALL_TIMEOUT;
        for (i = 0; i < ARRAY_SIZE(tests); i++) {
-               if (!tests[i].notrun) {         // still hanging.
-                       pr_err("%s has been failed.\n", tests[i].name);
-                       ret = -1;
+               while (tests[i].notrun) {               // still hanging.
+                       if (time_after(jiffies, tests[i].runstart + bst)) {
+                               pr_err("%s has failed boot-time tests.\n", tests[i].name);
+                               ret = -1;
+                               break;
+                       }
+                       ret = 1;
+                       break;
                }
        }
-
-       if (ret)
-               WARN_ON(1);
+       WARN_ON(ret < 0);
 
        return ret;
 }
-late_initcall(rcu_tasks_verify_self_tests);
+
+/*
+ * Repeat the rcu_tasks_verify_self_tests() call once every second until the
+ * test passes or has timed out.
+ */
+static struct delayed_work rcu_tasks_verify_work;
+static void rcu_tasks_verify_work_fn(struct work_struct *work __maybe_unused)
+{
+       int ret = rcu_tasks_verify_self_tests();
+
+       if (ret <= 0)
+               return;
+
+       /* Test fails but not timed out yet, reschedule another check */
+       schedule_delayed_work(&rcu_tasks_verify_work, HZ);
+}
+
+static int rcu_tasks_verify_schedule_work(void)
+{
+       INIT_DELAYED_WORK(&rcu_tasks_verify_work, rcu_tasks_verify_work_fn);
+       rcu_tasks_verify_work_fn(NULL);
+       return 0;
+}
+late_initcall(rcu_tasks_verify_schedule_work);
 #else /* #ifdef CONFIG_PROVE_RCU */
 static void rcu_tasks_initiate_self_tests(void) { }
 #endif /* #else #ifdef CONFIG_PROVE_RCU */
index 340b3f8..f0561ee 100644 (file)
@@ -58,7 +58,7 @@ void rcu_qs(void)
                rcu_ctrlblk.donetail = rcu_ctrlblk.curtail;
                raise_softirq_irqoff(RCU_SOFTIRQ);
        }
-       WRITE_ONCE(rcu_ctrlblk.gp_seq, rcu_ctrlblk.gp_seq + 1);
+       WRITE_ONCE(rcu_ctrlblk.gp_seq, rcu_ctrlblk.gp_seq + 2);
        local_irq_restore(flags);
 }
 
@@ -139,8 +139,10 @@ static __latent_entropy void rcu_process_callbacks(struct softirq_action *unused
 /*
  * Wait for a grace period to elapse.  But it is illegal to invoke
  * synchronize_rcu() from within an RCU read-side critical section.
- * Therefore, any legal call to synchronize_rcu() is a quiescent
- * state, and so on a UP system, synchronize_rcu() need do nothing.
+ * Therefore, any legal call to synchronize_rcu() is a quiescent state,
+ * and so on a UP system, synchronize_rcu() need do nothing, other than
+ * let the polled APIs know that another grace period elapsed.
+ *
  * (But Lai Jiangshan points out the benefits of doing might_sleep()
  * to reduce latency.)
  *
@@ -152,6 +154,7 @@ void synchronize_rcu(void)
                         lock_is_held(&rcu_lock_map) ||
                         lock_is_held(&rcu_sched_lock_map),
                         "Illegal synchronize_rcu() in RCU read-side critical section");
+       WRITE_ONCE(rcu_ctrlblk.gp_seq, rcu_ctrlblk.gp_seq + 2);
 }
 EXPORT_SYMBOL_GPL(synchronize_rcu);
 
@@ -213,10 +216,24 @@ EXPORT_SYMBOL_GPL(start_poll_synchronize_rcu);
  */
 bool poll_state_synchronize_rcu(unsigned long oldstate)
 {
-       return READ_ONCE(rcu_ctrlblk.gp_seq) != oldstate;
+       return oldstate == RCU_GET_STATE_COMPLETED || READ_ONCE(rcu_ctrlblk.gp_seq) != oldstate;
 }
 EXPORT_SYMBOL_GPL(poll_state_synchronize_rcu);
 
+#ifdef CONFIG_KASAN_GENERIC
+void kvfree_call_rcu(struct rcu_head *head, rcu_callback_t func)
+{
+       if (head) {
+               void *ptr = (void *) head - (unsigned long) func;
+
+               kasan_record_aux_stack_noalloc(ptr);
+       }
+
+       __kvfree_call_rcu(head, func);
+}
+EXPORT_SYMBOL_GPL(kvfree_call_rcu);
+#endif
+
 void __init rcu_init(void)
 {
        open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
index c25ba44..3dc9680 100644 (file)
@@ -62,6 +62,7 @@
 #include <linux/vmalloc.h>
 #include <linux/mm.h>
 #include <linux/kasan.h>
+#include <linux/context_tracking.h>
 #include "../time/tick-internal.h"
 
 #include "tree.h"
@@ -75,9 +76,6 @@
 /* Data structures. */
 
 static DEFINE_PER_CPU_SHARED_ALIGNED(struct rcu_data, rcu_data) = {
-       .dynticks_nesting = 1,
-       .dynticks_nmi_nesting = DYNTICK_IRQ_NONIDLE,
-       .dynticks = ATOMIC_INIT(1),
 #ifdef CONFIG_RCU_NOCB_CPU
        .cblist.flags = SEGCBLIST_RCU_CORE,
 #endif
@@ -154,7 +152,11 @@ static void sync_sched_exp_online_cleanup(int cpu);
 static void check_cb_ovld_locked(struct rcu_data *rdp, struct rcu_node *rnp);
 static bool rcu_rdp_is_offloaded(struct rcu_data *rdp);
 
-/* rcuc/rcub/rcuop kthread realtime priority */
+/*
+ * rcuc/rcub/rcuop kthread realtime priority. The "rcuop"
+ * real-time priority(enabling/disabling) is controlled by
+ * the extra CONFIG_RCU_NOCB_CPU_CB_BOOST configuration.
+ */
 static int kthread_prio = IS_ENABLED(CONFIG_RCU_BOOST) ? 1 : 0;
 module_param(kthread_prio, int, 0444);
 
@@ -263,56 +265,6 @@ void rcu_softirq_qs(void)
 }
 
 /*
- * Increment the current CPU's rcu_data structure's ->dynticks field
- * with ordering.  Return the new value.
- */
-static noinline noinstr unsigned long rcu_dynticks_inc(int incby)
-{
-       return arch_atomic_add_return(incby, this_cpu_ptr(&rcu_data.dynticks));
-}
-
-/*
- * Record entry into an extended quiescent state.  This is only to be
- * called when not already in an extended quiescent state, that is,
- * RCU is watching prior to the call to this function and is no longer
- * watching upon return.
- */
-static noinstr void rcu_dynticks_eqs_enter(void)
-{
-       int seq;
-
-       /*
-        * CPUs seeing atomic_add_return() must see prior RCU read-side
-        * critical sections, and we also must force ordering with the
-        * next idle sojourn.
-        */
-       rcu_dynticks_task_trace_enter();  // Before ->dynticks update!
-       seq = rcu_dynticks_inc(1);
-       // RCU is no longer watching.  Better be in extended quiescent state!
-       WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) && (seq & 0x1));
-}
-
-/*
- * Record exit from an extended quiescent state.  This is only to be
- * called from an extended quiescent state, that is, RCU is not watching
- * prior to the call to this function and is watching upon return.
- */
-static noinstr void rcu_dynticks_eqs_exit(void)
-{
-       int seq;
-
-       /*
-        * CPUs seeing atomic_add_return() must see prior idle sojourns,
-        * and we also must force ordering with the next RCU read-side
-        * critical section.
-        */
-       seq = rcu_dynticks_inc(1);
-       // RCU is now watching.  Better not be in an extended quiescent state!
-       rcu_dynticks_task_trace_exit();  // After ->dynticks update!
-       WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) && !(seq & 0x1));
-}
-
-/*
  * Reset the current CPU's ->dynticks counter to indicate that the
  * newly onlined CPU is no longer in an extended quiescent state.
  * This will either leave the counter unchanged, or increment it
@@ -324,31 +276,19 @@ static noinstr void rcu_dynticks_eqs_exit(void)
  */
 static void rcu_dynticks_eqs_online(void)
 {
-       struct rcu_data *rdp = this_cpu_ptr(&rcu_data);
-
-       if (atomic_read(&rdp->dynticks) & 0x1)
+       if (ct_dynticks() & RCU_DYNTICKS_IDX)
                return;
-       rcu_dynticks_inc(1);
-}
-
-/*
- * Is the current CPU in an extended quiescent state?
- *
- * No ordering, as we are sampling CPU-local information.
- */
-static __always_inline bool rcu_dynticks_curr_cpu_in_eqs(void)
-{
-       return !(arch_atomic_read(this_cpu_ptr(&rcu_data.dynticks)) & 0x1);
+       ct_state_inc(RCU_DYNTICKS_IDX);
 }
 
 /*
  * Snapshot the ->dynticks counter with full ordering so as to allow
  * stable comparison of this counter with past and future snapshots.
  */
-static int rcu_dynticks_snap(struct rcu_data *rdp)
+static int rcu_dynticks_snap(int cpu)
 {
        smp_mb();  // Fundamental RCU ordering guarantee.
-       return atomic_read_acquire(&rdp->dynticks);
+       return ct_dynticks_cpu_acquire(cpu);
 }
 
 /*
@@ -357,15 +297,13 @@ static int rcu_dynticks_snap(struct rcu_data *rdp)
  */
 static bool rcu_dynticks_in_eqs(int snap)
 {
-       return !(snap & 0x1);
+       return !(snap & RCU_DYNTICKS_IDX);
 }
 
 /* Return true if the specified CPU is currently idle from an RCU viewpoint.  */
 bool rcu_is_idle_cpu(int cpu)
 {
-       struct rcu_data *rdp = per_cpu_ptr(&rcu_data, cpu);
-
-       return rcu_dynticks_in_eqs(rcu_dynticks_snap(rdp));
+       return rcu_dynticks_in_eqs(rcu_dynticks_snap(cpu));
 }
 
 /*
@@ -375,7 +313,7 @@ bool rcu_is_idle_cpu(int cpu)
  */
 static bool rcu_dynticks_in_eqs_since(struct rcu_data *rdp, int snap)
 {
-       return snap != rcu_dynticks_snap(rdp);
+       return snap != rcu_dynticks_snap(rdp->cpu);
 }
 
 /*
@@ -384,19 +322,17 @@ static bool rcu_dynticks_in_eqs_since(struct rcu_data *rdp, int snap)
  */
 bool rcu_dynticks_zero_in_eqs(int cpu, int *vp)
 {
-       struct rcu_data *rdp = per_cpu_ptr(&rcu_data, cpu);
        int snap;
 
        // If not quiescent, force back to earlier extended quiescent state.
-       snap = atomic_read(&rdp->dynticks) & ~0x1;
-
+       snap = ct_dynticks_cpu(cpu) & ~RCU_DYNTICKS_IDX;
        smp_rmb(); // Order ->dynticks and *vp reads.
        if (READ_ONCE(*vp))
                return false;  // Non-zero, so report failure;
        smp_rmb(); // Order *vp read and ->dynticks re-read.
 
        // If still in the same extended quiescent state, we are good!
-       return snap == atomic_read(&rdp->dynticks);
+       return snap == ct_dynticks_cpu(cpu);
 }
 
 /*
@@ -415,9 +351,9 @@ notrace void rcu_momentary_dyntick_idle(void)
        int seq;
 
        raw_cpu_write(rcu_data.rcu_need_heavy_qs, false);
-       seq = rcu_dynticks_inc(2);
+       seq = ct_state_inc(2 * RCU_DYNTICKS_IDX);
        /* It is illegal to call this from idle state. */
-       WARN_ON_ONCE(!(seq & 0x1));
+       WARN_ON_ONCE(!(seq & RCU_DYNTICKS_IDX));
        rcu_preempt_deferred_qs(current);
 }
 EXPORT_SYMBOL_GPL(rcu_momentary_dyntick_idle);
@@ -442,13 +378,13 @@ static int rcu_is_cpu_rrupt_from_idle(void)
        lockdep_assert_irqs_disabled();
 
        /* Check for counter underflows */
-       RCU_LOCKDEP_WARN(__this_cpu_read(rcu_data.dynticks_nesting) < 0,
+       RCU_LOCKDEP_WARN(ct_dynticks_nesting() < 0,
                         "RCU dynticks_nesting counter underflow!");
-       RCU_LOCKDEP_WARN(__this_cpu_read(rcu_data.dynticks_nmi_nesting) <= 0,
+       RCU_LOCKDEP_WARN(ct_dynticks_nmi_nesting() <= 0,
                         "RCU dynticks_nmi_nesting counter underflow/zero!");
 
        /* Are we at first interrupt nesting level? */
-       nesting = __this_cpu_read(rcu_data.dynticks_nmi_nesting);
+       nesting = ct_dynticks_nmi_nesting();
        if (nesting > 1)
                return false;
 
@@ -458,7 +394,7 @@ static int rcu_is_cpu_rrupt_from_idle(void)
        WARN_ON_ONCE(!nesting && !is_idle_task(current));
 
        /* Does CPU appear to be idle from an RCU standpoint? */
-       return __this_cpu_read(rcu_data.dynticks_nesting) == 0;
+       return ct_dynticks_nesting() == 0;
 }
 
 #define DEFAULT_RCU_BLIMIT (IS_ENABLED(CONFIG_RCU_STRICT_GRACE_PERIOD) ? 1000 : 10)
@@ -609,66 +545,7 @@ void rcutorture_get_gp_data(enum rcutorture_type test_type, int *flags,
 }
 EXPORT_SYMBOL_GPL(rcutorture_get_gp_data);
 
-/*
- * Enter an RCU extended quiescent state, which can be either the
- * idle loop or adaptive-tickless usermode execution.
- *
- * We crowbar the ->dynticks_nmi_nesting field to zero to allow for
- * the possibility of usermode upcalls having messed up our count
- * of interrupt nesting level during the prior busy period.
- */
-static noinstr void rcu_eqs_enter(bool user)
-{
-       struct rcu_data *rdp = this_cpu_ptr(&rcu_data);
-
-       WARN_ON_ONCE(rdp->dynticks_nmi_nesting != DYNTICK_IRQ_NONIDLE);
-       WRITE_ONCE(rdp->dynticks_nmi_nesting, 0);
-       WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&
-                    rdp->dynticks_nesting == 0);
-       if (rdp->dynticks_nesting != 1) {
-               // RCU will still be watching, so just do accounting and leave.
-               rdp->dynticks_nesting--;
-               return;
-       }
-
-       lockdep_assert_irqs_disabled();
-       instrumentation_begin();
-       trace_rcu_dyntick(TPS("Start"), rdp->dynticks_nesting, 0, atomic_read(&rdp->dynticks));
-       WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) && !user && !is_idle_task(current));
-       rcu_preempt_deferred_qs(current);
-
-       // instrumentation for the noinstr rcu_dynticks_eqs_enter()
-       instrument_atomic_write(&rdp->dynticks, sizeof(rdp->dynticks));
-
-       instrumentation_end();
-       WRITE_ONCE(rdp->dynticks_nesting, 0); /* Avoid irq-access tearing. */
-       // RCU is watching here ...
-       rcu_dynticks_eqs_enter();
-       // ... but is no longer watching here.
-       rcu_dynticks_task_enter();
-}
-
-/**
- * rcu_idle_enter - inform RCU that current CPU is entering idle
- *
- * Enter idle mode, in other words, -leave- the mode in which RCU
- * read-side critical sections can occur.  (Though RCU read-side
- * critical sections can occur in irq handlers in idle, a possibility
- * handled by irq_enter() and irq_exit().)
- *
- * If you add or remove a call to rcu_idle_enter(), be sure to test with
- * CONFIG_RCU_EQS_DEBUG=y.
- */
-void rcu_idle_enter(void)
-{
-       lockdep_assert_irqs_disabled();
-       rcu_eqs_enter(false);
-}
-EXPORT_SYMBOL_GPL(rcu_idle_enter);
-
-#ifdef CONFIG_NO_HZ_FULL
-
-#if !defined(CONFIG_GENERIC_ENTRY) || !defined(CONFIG_KVM_XFER_TO_GUEST_WORK)
+#if defined(CONFIG_NO_HZ_FULL) && (!defined(CONFIG_GENERIC_ENTRY) || !defined(CONFIG_KVM_XFER_TO_GUEST_WORK))
 /*
  * An empty function that will trigger a reschedule on
  * IRQ tail once IRQs get re-enabled on userspace/guest resume.
@@ -690,7 +567,7 @@ static DEFINE_PER_CPU(struct irq_work, late_wakeup_work) =
  * last resort is to fire a local irq_work that will trigger a reschedule once IRQs
  * get re-enabled again.
  */
-noinstr static void rcu_irq_work_resched(void)
+noinstr void rcu_irq_work_resched(void)
 {
        struct rcu_data *rdp = this_cpu_ptr(&rcu_data);
 
@@ -706,114 +583,7 @@ noinstr static void rcu_irq_work_resched(void)
        }
        instrumentation_end();
 }
-
-#else
-static inline void rcu_irq_work_resched(void) { }
-#endif
-
-/**
- * rcu_user_enter - inform RCU that we are resuming userspace.
- *
- * Enter RCU idle mode right before resuming userspace.  No use of RCU
- * is permitted between this call and rcu_user_exit(). This way the
- * CPU doesn't need to maintain the tick for RCU maintenance purposes
- * when the CPU runs in userspace.
- *
- * If you add or remove a call to rcu_user_enter(), be sure to test with
- * CONFIG_RCU_EQS_DEBUG=y.
- */
-noinstr void rcu_user_enter(void)
-{
-       lockdep_assert_irqs_disabled();
-
-       /*
-        * Other than generic entry implementation, we may be past the last
-        * rescheduling opportunity in the entry code. Trigger a self IPI
-        * that will fire and reschedule once we resume in user/guest mode.
-        */
-       rcu_irq_work_resched();
-       rcu_eqs_enter(true);
-}
-
-#endif /* CONFIG_NO_HZ_FULL */
-
-/**
- * rcu_nmi_exit - inform RCU of exit from NMI context
- *
- * If we are returning from the outermost NMI handler that interrupted an
- * RCU-idle period, update rdp->dynticks and rdp->dynticks_nmi_nesting
- * to let the RCU grace-period handling know that the CPU is back to
- * being RCU-idle.
- *
- * If you add or remove a call to rcu_nmi_exit(), be sure to test
- * with CONFIG_RCU_EQS_DEBUG=y.
- */
-noinstr void rcu_nmi_exit(void)
-{
-       struct rcu_data *rdp = this_cpu_ptr(&rcu_data);
-
-       instrumentation_begin();
-       /*
-        * Check for ->dynticks_nmi_nesting underflow and bad ->dynticks.
-        * (We are exiting an NMI handler, so RCU better be paying attention
-        * to us!)
-        */
-       WARN_ON_ONCE(rdp->dynticks_nmi_nesting <= 0);
-       WARN_ON_ONCE(rcu_dynticks_curr_cpu_in_eqs());
-
-       /*
-        * If the nesting level is not 1, the CPU wasn't RCU-idle, so
-        * leave it in non-RCU-idle state.
-        */
-       if (rdp->dynticks_nmi_nesting != 1) {
-               trace_rcu_dyntick(TPS("--="), rdp->dynticks_nmi_nesting, rdp->dynticks_nmi_nesting - 2,
-                                 atomic_read(&rdp->dynticks));
-               WRITE_ONCE(rdp->dynticks_nmi_nesting, /* No store tearing. */
-                          rdp->dynticks_nmi_nesting - 2);
-               instrumentation_end();
-               return;
-       }
-
-       /* This NMI interrupted an RCU-idle CPU, restore RCU-idleness. */
-       trace_rcu_dyntick(TPS("Startirq"), rdp->dynticks_nmi_nesting, 0, atomic_read(&rdp->dynticks));
-       WRITE_ONCE(rdp->dynticks_nmi_nesting, 0); /* Avoid store tearing. */
-
-       // instrumentation for the noinstr rcu_dynticks_eqs_enter()
-       instrument_atomic_write(&rdp->dynticks, sizeof(rdp->dynticks));
-       instrumentation_end();
-
-       // RCU is watching here ...
-       rcu_dynticks_eqs_enter();
-       // ... but is no longer watching here.
-
-       if (!in_nmi())
-               rcu_dynticks_task_enter();
-}
-
-/**
- * rcu_irq_exit - inform RCU that current CPU is exiting irq towards idle
- *
- * Exit from an interrupt handler, which might possibly result in entering
- * idle mode, in other words, leaving the mode in which read-side critical
- * sections can occur.  The caller must have disabled interrupts.
- *
- * This code assumes that the idle loop never does anything that might
- * result in unbalanced calls to irq_enter() and irq_exit().  If your
- * architecture's idle loop violates this assumption, RCU will give you what
- * you deserve, good and hard.  But very infrequently and irreproducibly.
- *
- * Use things like work queues to work around this limitation.
- *
- * You have been warned.
- *
- * If you add or remove a call to rcu_irq_exit(), be sure to test with
- * CONFIG_RCU_EQS_DEBUG=y.
- */
-void noinstr rcu_irq_exit(void)
-{
-       lockdep_assert_irqs_disabled();
-       rcu_nmi_exit();
-}
+#endif /* #if defined(CONFIG_NO_HZ_FULL) && (!defined(CONFIG_GENERIC_ENTRY) || !defined(CONFIG_KVM_XFER_TO_GUEST_WORK)) */
 
 #ifdef CONFIG_PROVE_RCU
 /**
@@ -823,9 +593,9 @@ void rcu_irq_exit_check_preempt(void)
 {
        lockdep_assert_irqs_disabled();
 
-       RCU_LOCKDEP_WARN(__this_cpu_read(rcu_data.dynticks_nesting) <= 0,
+       RCU_LOCKDEP_WARN(ct_dynticks_nesting() <= 0,
                         "RCU dynticks_nesting counter underflow/zero!");
-       RCU_LOCKDEP_WARN(__this_cpu_read(rcu_data.dynticks_nmi_nesting) !=
+       RCU_LOCKDEP_WARN(ct_dynticks_nmi_nesting() !=
                         DYNTICK_IRQ_NONIDLE,
                         "Bad RCU  dynticks_nmi_nesting counter\n");
        RCU_LOCKDEP_WARN(rcu_dynticks_curr_cpu_in_eqs(),
@@ -833,95 +603,8 @@ void rcu_irq_exit_check_preempt(void)
 }
 #endif /* #ifdef CONFIG_PROVE_RCU */
 
-/*
- * Wrapper for rcu_irq_exit() where interrupts are enabled.
- *
- * If you add or remove a call to rcu_irq_exit_irqson(), be sure to test
- * with CONFIG_RCU_EQS_DEBUG=y.
- */
-void rcu_irq_exit_irqson(void)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-       rcu_irq_exit();
-       local_irq_restore(flags);
-}
-
-/*
- * Exit an RCU extended quiescent state, which can be either the
- * idle loop or adaptive-tickless usermode execution.
- *
- * We crowbar the ->dynticks_nmi_nesting field to DYNTICK_IRQ_NONIDLE to
- * allow for the possibility of usermode upcalls messing up our count of
- * interrupt nesting level during the busy period that is just now starting.
- */
-static void noinstr rcu_eqs_exit(bool user)
-{
-       struct rcu_data *rdp;
-       long oldval;
-
-       lockdep_assert_irqs_disabled();
-       rdp = this_cpu_ptr(&rcu_data);
-       oldval = rdp->dynticks_nesting;
-       WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) && oldval < 0);
-       if (oldval) {
-               // RCU was already watching, so just do accounting and leave.
-               rdp->dynticks_nesting++;
-               return;
-       }
-       rcu_dynticks_task_exit();
-       // RCU is not watching here ...
-       rcu_dynticks_eqs_exit();
-       // ... but is watching here.
-       instrumentation_begin();
-
-       // instrumentation for the noinstr rcu_dynticks_eqs_exit()
-       instrument_atomic_write(&rdp->dynticks, sizeof(rdp->dynticks));
-
-       trace_rcu_dyntick(TPS("End"), rdp->dynticks_nesting, 1, atomic_read(&rdp->dynticks));
-       WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) && !user && !is_idle_task(current));
-       WRITE_ONCE(rdp->dynticks_nesting, 1);
-       WARN_ON_ONCE(rdp->dynticks_nmi_nesting);
-       WRITE_ONCE(rdp->dynticks_nmi_nesting, DYNTICK_IRQ_NONIDLE);
-       instrumentation_end();
-}
-
-/**
- * rcu_idle_exit - inform RCU that current CPU is leaving idle
- *
- * Exit idle mode, in other words, -enter- the mode in which RCU
- * read-side critical sections can occur.
- *
- * If you add or remove a call to rcu_idle_exit(), be sure to test with
- * CONFIG_RCU_EQS_DEBUG=y.
- */
-void rcu_idle_exit(void)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-       rcu_eqs_exit(false);
-       local_irq_restore(flags);
-}
-EXPORT_SYMBOL_GPL(rcu_idle_exit);
-
 #ifdef CONFIG_NO_HZ_FULL
 /**
- * rcu_user_exit - inform RCU that we are exiting userspace.
- *
- * Exit RCU idle mode while entering the kernel because it can
- * run a RCU read side critical section anytime.
- *
- * If you add or remove a call to rcu_user_exit(), be sure to test with
- * CONFIG_RCU_EQS_DEBUG=y.
- */
-void noinstr rcu_user_exit(void)
-{
-       rcu_eqs_exit(true);
-}
-
-/**
  * __rcu_irq_enter_check_tick - Enable scheduler tick on CPU if RCU needs it.
  *
  * The scheduler tick is not normally enabled when CPUs enter the kernel
@@ -983,109 +666,6 @@ void __rcu_irq_enter_check_tick(void)
 }
 #endif /* CONFIG_NO_HZ_FULL */
 
-/**
- * rcu_nmi_enter - inform RCU of entry to NMI context
- *
- * If the CPU was idle from RCU's viewpoint, update rdp->dynticks and
- * rdp->dynticks_nmi_nesting to let the RCU grace-period handling know
- * that the CPU is active.  This implementation permits nested NMIs, as
- * long as the nesting level does not overflow an int.  (You will probably
- * run out of stack space first.)
- *
- * If you add or remove a call to rcu_nmi_enter(), be sure to test
- * with CONFIG_RCU_EQS_DEBUG=y.
- */
-noinstr void rcu_nmi_enter(void)
-{
-       long incby = 2;
-       struct rcu_data *rdp = this_cpu_ptr(&rcu_data);
-
-       /* Complain about underflow. */
-       WARN_ON_ONCE(rdp->dynticks_nmi_nesting < 0);
-
-       /*
-        * If idle from RCU viewpoint, atomically increment ->dynticks
-        * to mark non-idle and increment ->dynticks_nmi_nesting by one.
-        * Otherwise, increment ->dynticks_nmi_nesting by two.  This means
-        * if ->dynticks_nmi_nesting is equal to one, we are guaranteed
-        * to be in the outermost NMI handler that interrupted an RCU-idle
-        * period (observation due to Andy Lutomirski).
-        */
-       if (rcu_dynticks_curr_cpu_in_eqs()) {
-
-               if (!in_nmi())
-                       rcu_dynticks_task_exit();
-
-               // RCU is not watching here ...
-               rcu_dynticks_eqs_exit();
-               // ... but is watching here.
-
-               instrumentation_begin();
-               // instrumentation for the noinstr rcu_dynticks_curr_cpu_in_eqs()
-               instrument_atomic_read(&rdp->dynticks, sizeof(rdp->dynticks));
-               // instrumentation for the noinstr rcu_dynticks_eqs_exit()
-               instrument_atomic_write(&rdp->dynticks, sizeof(rdp->dynticks));
-
-               incby = 1;
-       } else if (!in_nmi()) {
-               instrumentation_begin();
-               rcu_irq_enter_check_tick();
-       } else  {
-               instrumentation_begin();
-       }
-
-       trace_rcu_dyntick(incby == 1 ? TPS("Endirq") : TPS("++="),
-                         rdp->dynticks_nmi_nesting,
-                         rdp->dynticks_nmi_nesting + incby, atomic_read(&rdp->dynticks));
-       instrumentation_end();
-       WRITE_ONCE(rdp->dynticks_nmi_nesting, /* Prevent store tearing. */
-                  rdp->dynticks_nmi_nesting + incby);
-       barrier();
-}
-
-/**
- * rcu_irq_enter - inform RCU that current CPU is entering irq away from idle
- *
- * Enter an interrupt handler, which might possibly result in exiting
- * idle mode, in other words, entering the mode in which read-side critical
- * sections can occur.  The caller must have disabled interrupts.
- *
- * Note that the Linux kernel is fully capable of entering an interrupt
- * handler that it never exits, for example when doing upcalls to user mode!
- * This code assumes that the idle loop never does upcalls to user mode.
- * If your architecture's idle loop does do upcalls to user mode (or does
- * anything else that results in unbalanced calls to the irq_enter() and
- * irq_exit() functions), RCU will give you what you deserve, good and hard.
- * But very infrequently and irreproducibly.
- *
- * Use things like work queues to work around this limitation.
- *
- * You have been warned.
- *
- * If you add or remove a call to rcu_irq_enter(), be sure to test with
- * CONFIG_RCU_EQS_DEBUG=y.
- */
-noinstr void rcu_irq_enter(void)
-{
-       lockdep_assert_irqs_disabled();
-       rcu_nmi_enter();
-}
-
-/*
- * Wrapper for rcu_irq_enter() where interrupts are enabled.
- *
- * If you add or remove a call to rcu_irq_enter_irqson(), be sure to test
- * with CONFIG_RCU_EQS_DEBUG=y.
- */
-void rcu_irq_enter_irqson(void)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-       rcu_irq_enter();
-       local_irq_restore(flags);
-}
-
 /*
  * Check to see if any future non-offloaded RCU-related work will need
  * to be done by the current CPU, even if none need be done immediately,
@@ -1223,7 +803,7 @@ static void rcu_gpnum_ovf(struct rcu_node *rnp, struct rcu_data *rdp)
  */
 static int dyntick_save_progress_counter(struct rcu_data *rdp)
 {
-       rdp->dynticks_snap = rcu_dynticks_snap(rdp);
+       rdp->dynticks_snap = rcu_dynticks_snap(rdp->cpu);
        if (rcu_dynticks_in_eqs(rdp->dynticks_snap)) {
                trace_rcu_fqs(rcu_state.name, rdp->gp_seq, rdp->cpu, TPS("dti"));
                rcu_gpnum_ovf(rdp->mynode, rdp);
@@ -1775,6 +1355,79 @@ static void rcu_strict_gp_boundary(void *unused)
        invoke_rcu_core();
 }
 
+// Has rcu_init() been invoked?  This is used (for example) to determine
+// whether spinlocks may be acquired safely.
+static bool rcu_init_invoked(void)
+{
+       return !!rcu_state.n_online_cpus;
+}
+
+// Make the polled API aware of the beginning of a grace period.
+static void rcu_poll_gp_seq_start(unsigned long *snap)
+{
+       struct rcu_node *rnp = rcu_get_root();
+
+       if (rcu_init_invoked())
+               raw_lockdep_assert_held_rcu_node(rnp);
+
+       // If RCU was idle, note beginning of GP.
+       if (!rcu_seq_state(rcu_state.gp_seq_polled))
+               rcu_seq_start(&rcu_state.gp_seq_polled);
+
+       // Either way, record current state.
+       *snap = rcu_state.gp_seq_polled;
+}
+
+// Make the polled API aware of the end of a grace period.
+static void rcu_poll_gp_seq_end(unsigned long *snap)
+{
+       struct rcu_node *rnp = rcu_get_root();
+
+       if (rcu_init_invoked())
+               raw_lockdep_assert_held_rcu_node(rnp);
+
+       // If the previously noted GP is still in effect, record the
+       // end of that GP.  Either way, zero counter to avoid counter-wrap
+       // problems.
+       if (*snap && *snap == rcu_state.gp_seq_polled) {
+               rcu_seq_end(&rcu_state.gp_seq_polled);
+               rcu_state.gp_seq_polled_snap = 0;
+               rcu_state.gp_seq_polled_exp_snap = 0;
+       } else {
+               *snap = 0;
+       }
+}
+
+// Make the polled API aware of the beginning of a grace period, but
+// where caller does not hold the root rcu_node structure's lock.
+static void rcu_poll_gp_seq_start_unlocked(unsigned long *snap)
+{
+       struct rcu_node *rnp = rcu_get_root();
+
+       if (rcu_init_invoked()) {
+               lockdep_assert_irqs_enabled();
+               raw_spin_lock_irq_rcu_node(rnp);
+       }
+       rcu_poll_gp_seq_start(snap);
+       if (rcu_init_invoked())
+               raw_spin_unlock_irq_rcu_node(rnp);
+}
+
+// Make the polled API aware of the end of a grace period, but where
+// caller does not hold the root rcu_node structure's lock.
+static void rcu_poll_gp_seq_end_unlocked(unsigned long *snap)
+{
+       struct rcu_node *rnp = rcu_get_root();
+
+       if (rcu_init_invoked()) {
+               lockdep_assert_irqs_enabled();
+               raw_spin_lock_irq_rcu_node(rnp);
+       }
+       rcu_poll_gp_seq_end(snap);
+       if (rcu_init_invoked())
+               raw_spin_unlock_irq_rcu_node(rnp);
+}
+
 /*
  * Initialize a new grace period.  Return false if no grace period required.
  */
@@ -1810,6 +1463,7 @@ static noinline_for_stack bool rcu_gp_init(void)
        rcu_seq_start(&rcu_state.gp_seq);
        ASSERT_EXCLUSIVE_WRITER(rcu_state.gp_seq);
        trace_rcu_grace_period(rcu_state.name, rcu_state.gp_seq, TPS("start"));
+       rcu_poll_gp_seq_start(&rcu_state.gp_seq_polled_snap);
        raw_spin_unlock_irq_rcu_node(rnp);
 
        /*
@@ -1971,19 +1625,23 @@ static void rcu_gp_fqs(bool first_time)
  */
 static noinline_for_stack void rcu_gp_fqs_loop(void)
 {
-       bool first_gp_fqs;
+       bool first_gp_fqs = true;
        int gf = 0;
        unsigned long j;
        int ret;
        struct rcu_node *rnp = rcu_get_root();
 
-       first_gp_fqs = true;
        j = READ_ONCE(jiffies_till_first_fqs);
        if (rcu_state.cbovld)
                gf = RCU_GP_FLAG_OVLD;
        ret = 0;
        for (;;) {
-               if (!ret) {
+               if (rcu_state.cbovld) {
+                       j = (j + 2) / 3;
+                       if (j <= 0)
+                               j = 1;
+               }
+               if (!ret || time_before(jiffies + j, rcu_state.jiffies_force_qs)) {
                        WRITE_ONCE(rcu_state.jiffies_force_qs, jiffies + j);
                        /*
                         * jiffies_force_qs before RCU_GP_WAIT_FQS state
@@ -2001,7 +1659,15 @@ static noinline_for_stack void rcu_gp_fqs_loop(void)
                rcu_gp_torture_wait();
                WRITE_ONCE(rcu_state.gp_state, RCU_GP_DOING_FQS);
                /* Locking provides needed memory barriers. */
-               /* If grace period done, leave loop. */
+               /*
+                * Exit the loop if the root rcu_node structure indicates that the grace period
+                * has ended, leave the loop.  The rcu_preempt_blocked_readers_cgp(rnp) check
+                * is required only for single-node rcu_node trees because readers blocking
+                * the current grace period are queued only on leaf rcu_node structures.
+                * For multi-node trees, checking the root node's ->qsmask suffices, because a
+                * given root node's ->qsmask bit is cleared only when all CPUs and tasks from
+                * the corresponding leaf nodes have passed through their quiescent state.
+                */
                if (!READ_ONCE(rnp->qsmask) &&
                    !rcu_preempt_blocked_readers_cgp(rnp))
                        break;
@@ -2069,6 +1735,7 @@ static noinline void rcu_gp_cleanup(void)
         * safe for us to drop the lock in order to mark the grace
         * period as completed in all of the rcu_node structures.
         */
+       rcu_poll_gp_seq_end(&rcu_state.gp_seq_polled_snap);
        raw_spin_unlock_irq_rcu_node(rnp);
 
        /*
@@ -2530,7 +2197,7 @@ static void rcu_do_batch(struct rcu_data *rdp)
                trace_rcu_batch_end(rcu_state.name, 0,
                                    !rcu_segcblist_empty(&rdp->cblist),
                                    need_resched(), is_idle_task(current),
-                                   rcu_is_callbacks_kthread());
+                                   rcu_is_callbacks_kthread(rdp));
                return;
        }
 
@@ -2608,7 +2275,7 @@ static void rcu_do_batch(struct rcu_data *rdp)
        rcu_nocb_lock_irqsave(rdp, flags);
        rdp->n_cbs_invoked += count;
        trace_rcu_batch_end(rcu_state.name, count, !!rcl.head, need_resched(),
-                           is_idle_task(current), rcu_is_callbacks_kthread());
+                           is_idle_task(current), rcu_is_callbacks_kthread(rdp));
 
        /* Update counts and requeue any remaining callbacks. */
        rcu_segcblist_insert_done_cbs(&rdp->cblist, &rcl);
@@ -3211,7 +2878,6 @@ struct kfree_rcu_cpu_work {
  * @krw_arr: Array of batches of kfree_rcu() objects waiting for a grace period
  * @lock: Synchronize access to this structure
  * @monitor_work: Promote @head to @head_free after KFREE_DRAIN_JIFFIES
- * @monitor_todo: Tracks whether a @monitor_work delayed work is pending
  * @initialized: The @rcu_work fields have been initialized
  * @count: Number of objects for which GP not started
  * @bkvcache:
@@ -3236,7 +2902,6 @@ struct kfree_rcu_cpu {
        struct kfree_rcu_cpu_work krw_arr[KFREE_N_BATCHES];
        raw_spinlock_t lock;
        struct delayed_work monitor_work;
-       bool monitor_todo;
        bool initialized;
        int count;
 
@@ -3416,6 +3081,18 @@ static void kfree_rcu_work(struct work_struct *work)
        }
 }
 
+static bool
+need_offload_krc(struct kfree_rcu_cpu *krcp)
+{
+       int i;
+
+       for (i = 0; i < FREE_N_CHANNELS; i++)
+               if (krcp->bkvhead[i])
+                       return true;
+
+       return !!krcp->head;
+}
+
 /*
  * This function is invoked after the KFREE_DRAIN_JIFFIES timeout.
  */
@@ -3472,9 +3149,7 @@ static void kfree_rcu_monitor(struct work_struct *work)
        // of the channels that is still busy we should rearm the
        // work to repeat an attempt. Because previous batches are
        // still in progress.
-       if (!krcp->bkvhead[0] && !krcp->bkvhead[1] && !krcp->head)
-               krcp->monitor_todo = false;
-       else
+       if (need_offload_krc(krcp))
                schedule_delayed_work(&krcp->monitor_work, KFREE_DRAIN_JIFFIES);
 
        raw_spin_unlock_irqrestore(&krcp->lock, flags);
@@ -3662,11 +3337,8 @@ void kvfree_call_rcu(struct rcu_head *head, rcu_callback_t func)
        WRITE_ONCE(krcp->count, krcp->count + 1);
 
        // Set timer to drain after KFREE_DRAIN_JIFFIES.
-       if (rcu_scheduler_active == RCU_SCHEDULER_RUNNING &&
-           !krcp->monitor_todo) {
-               krcp->monitor_todo = true;
+       if (rcu_scheduler_active == RCU_SCHEDULER_RUNNING)
                schedule_delayed_work(&krcp->monitor_work, KFREE_DRAIN_JIFFIES);
-       }
 
 unlock_return:
        krc_this_cpu_unlock(krcp, flags);
@@ -3741,14 +3413,8 @@ void __init kfree_rcu_scheduler_running(void)
                struct kfree_rcu_cpu *krcp = per_cpu_ptr(&krc, cpu);
 
                raw_spin_lock_irqsave(&krcp->lock, flags);
-               if ((!krcp->bkvhead[0] && !krcp->bkvhead[1] && !krcp->head) ||
-                               krcp->monitor_todo) {
-                       raw_spin_unlock_irqrestore(&krcp->lock, flags);
-                       continue;
-               }
-               krcp->monitor_todo = true;
-               schedule_delayed_work_on(cpu, &krcp->monitor_work,
-                                        KFREE_DRAIN_JIFFIES);
+               if (need_offload_krc(krcp))
+                       schedule_delayed_work_on(cpu, &krcp->monitor_work, KFREE_DRAIN_JIFFIES);
                raw_spin_unlock_irqrestore(&krcp->lock, flags);
        }
 }
@@ -3837,8 +3503,18 @@ void synchronize_rcu(void)
                         lock_is_held(&rcu_lock_map) ||
                         lock_is_held(&rcu_sched_lock_map),
                         "Illegal synchronize_rcu() in RCU read-side critical section");
-       if (rcu_blocking_is_gp())
+       if (rcu_blocking_is_gp()) {
+               // Note well that this code runs with !PREEMPT && !SMP.
+               // In addition, all code that advances grace periods runs at
+               // process level.  Therefore, this normal GP overlaps with
+               // other normal GPs only by being fully nested within them,
+               // which allows reuse of ->gp_seq_polled_snap.
+               rcu_poll_gp_seq_start_unlocked(&rcu_state.gp_seq_polled_snap);
+               rcu_poll_gp_seq_end_unlocked(&rcu_state.gp_seq_polled_snap);
+               if (rcu_init_invoked())
+                       cond_resched_tasks_rcu_qs();
                return;  // Context allows vacuous grace periods.
+       }
        if (rcu_gp_is_expedited())
                synchronize_rcu_expedited();
        else
@@ -3860,7 +3536,7 @@ unsigned long get_state_synchronize_rcu(void)
         * before the load from ->gp_seq.
         */
        smp_mb();  /* ^^^ */
-       return rcu_seq_snap(&rcu_state.gp_seq);
+       return rcu_seq_snap(&rcu_state.gp_seq_polled);
 }
 EXPORT_SYMBOL_GPL(get_state_synchronize_rcu);
 
@@ -3889,7 +3565,13 @@ unsigned long start_poll_synchronize_rcu(void)
        rdp = this_cpu_ptr(&rcu_data);
        rnp = rdp->mynode;
        raw_spin_lock_rcu_node(rnp); // irqs already disabled.
-       needwake = rcu_start_this_gp(rnp, rdp, gp_seq);
+       // Note it is possible for a grace period to have elapsed between
+       // the above call to get_state_synchronize_rcu() and the below call
+       // to rcu_seq_snap.  This is OK, the worst that happens is that we
+       // get a grace period that no one needed.  These accesses are ordered
+       // by smp_mb(), and we are accessing them in the opposite order
+       // from which they are updated at grace-period start, as required.
+       needwake = rcu_start_this_gp(rnp, rdp, rcu_seq_snap(&rcu_state.gp_seq));
        raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
        if (needwake)
                rcu_gp_kthread_wake();
@@ -3911,7 +3593,7 @@ EXPORT_SYMBOL_GPL(start_poll_synchronize_rcu);
  *
  * Yes, this function does not take counter wrap into account.
  * But counter wrap is harmless.  If the counter wraps, we have waited for
- * more than 2 billion grace periods (and way more on a 64-bit system!).
+ * more than a billion grace periods (and way more on a 64-bit system!).
  * Those needing to keep oldstate values for very long time periods
  * (many hours even on 32-bit systems) should check them occasionally
  * and either refresh them or set a flag indicating that the grace period
@@ -3924,7 +3606,8 @@ EXPORT_SYMBOL_GPL(start_poll_synchronize_rcu);
  */
 bool poll_state_synchronize_rcu(unsigned long oldstate)
 {
-       if (rcu_seq_done(&rcu_state.gp_seq, oldstate)) {
+       if (oldstate == RCU_GET_STATE_COMPLETED ||
+           rcu_seq_done_exact(&rcu_state.gp_seq_polled, oldstate)) {
                smp_mb(); /* Ensure GP ends before subsequent accesses. */
                return true;
        }
@@ -3935,20 +3618,20 @@ EXPORT_SYMBOL_GPL(poll_state_synchronize_rcu);
 /**
  * cond_synchronize_rcu - Conditionally wait for an RCU grace period
  *
- * @oldstate: value from get_state_synchronize_rcu() or start_poll_synchronize_rcu()
+ * @oldstate: value from get_state_synchronize_rcu(), start_poll_synchronize_rcu(), or start_poll_synchronize_rcu_expedited()
  *
  * If a full RCU grace period has elapsed since the earlier call to
  * get_state_synchronize_rcu() or start_poll_synchronize_rcu(), just return.
  * Otherwise, invoke synchronize_rcu() to wait for a full grace period.
  *
- * Yes, this function does not take counter wrap into account.  But
- * counter wrap is harmless.  If the counter wraps, we have waited for
+ * Yes, this function does not take counter wrap into account.
+ * But counter wrap is harmless.  If the counter wraps, we have waited for
  * more than 2 billion grace periods (and way more on a 64-bit system!),
- * so waiting for one additional grace period should be just fine.
+ * so waiting for a couple of additional grace periods should be just fine.
  *
  * This function provides the same memory-ordering guarantees that
  * would be provided by a synchronize_rcu() that was invoked at the call
- * to the function that provided @oldstate, and that returned at the end
+ * to the function that provided @oldstate and that returned at the end
  * of this function.
  */
 void cond_synchronize_rcu(unsigned long oldstate)
@@ -4221,13 +3904,14 @@ static void rcu_init_new_rnp(struct rcu_node *rnp_leaf)
 static void __init
 rcu_boot_init_percpu_data(int cpu)
 {
+       struct context_tracking *ct = this_cpu_ptr(&context_tracking);
        struct rcu_data *rdp = per_cpu_ptr(&rcu_data, cpu);
 
        /* Set up local state, ensuring consistent view of global state. */
        rdp->grpmask = leaf_node_cpu_bit(rdp->mynode, cpu);
        INIT_WORK(&rdp->strict_work, strict_work_handler);
-       WARN_ON_ONCE(rdp->dynticks_nesting != 1);
-       WARN_ON_ONCE(rcu_dynticks_in_eqs(rcu_dynticks_snap(rdp)));
+       WARN_ON_ONCE(ct->dynticks_nesting != 1);
+       WARN_ON_ONCE(rcu_dynticks_in_eqs(rcu_dynticks_snap(cpu)));
        rdp->barrier_seq_snap = rcu_state.barrier_sequence;
        rdp->rcu_ofl_gp_seq = rcu_state.gp_seq;
        rdp->rcu_ofl_gp_flags = RCU_GP_CLEANED;
@@ -4251,6 +3935,7 @@ rcu_boot_init_percpu_data(int cpu)
 int rcutree_prepare_cpu(unsigned int cpu)
 {
        unsigned long flags;
+       struct context_tracking *ct = per_cpu_ptr(&context_tracking, cpu);
        struct rcu_data *rdp = per_cpu_ptr(&rcu_data, cpu);
        struct rcu_node *rnp = rcu_get_root();
 
@@ -4259,7 +3944,7 @@ int rcutree_prepare_cpu(unsigned int cpu)
        rdp->qlen_last_fqs_check = 0;
        rdp->n_force_qs_snap = READ_ONCE(rcu_state.n_force_qs);
        rdp->blimit = blimit;
-       rdp->dynticks_nesting = 1;      /* CPU not up, no tearing. */
+       ct->dynticks_nesting = 1;       /* CPU not up, no tearing. */
        raw_spin_unlock_rcu_node(rnp);          /* irqs remain disabled. */
 
        /*
@@ -4441,6 +4126,7 @@ void rcu_report_dead(unsigned int cpu)
        rdp->rcu_ofl_gp_flags = READ_ONCE(rcu_state.gp_flags);
        if (rnp->qsmask & mask) { /* RCU waiting on outgoing CPU? */
                /* Report quiescent state -before- changing ->qsmaskinitnext! */
+               rcu_disable_urgency_upon_qs(rdp);
                rcu_report_qs_rnp(mask, rnp, rnp->gp_seq, flags);
                raw_spin_lock_irqsave_rcu_node(rnp, flags);
        }
@@ -4486,6 +4172,7 @@ void rcutree_migrate_callbacks(int cpu)
        needwake = needwake || rcu_advance_cbs(my_rnp, my_rdp);
        rcu_segcblist_disable(&rdp->cblist);
        WARN_ON_ONCE(rcu_segcblist_empty(&my_rdp->cblist) != !rcu_segcblist_n_cbs(&my_rdp->cblist));
+       check_cb_ovld_locked(my_rdp, my_rnp);
        if (rcu_rdp_is_offloaded(my_rdp)) {
                raw_spin_unlock_rcu_node(my_rnp); /* irqs remain disabled. */
                __call_rcu_nocb_wake(my_rdp, true, flags);
@@ -4701,6 +4388,9 @@ static void __init rcu_init_one(void)
                        init_waitqueue_head(&rnp->exp_wq[3]);
                        spin_lock_init(&rnp->exp_lock);
                        mutex_init(&rnp->boost_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);
                }
        }
 
@@ -4926,6 +4616,10 @@ void __init rcu_init(void)
                qovld_calc = DEFAULT_RCU_QOVLD_MULT * qhimark;
        else
                qovld_calc = qovld;
+
+       // Kick-start any polled grace periods that started early.
+       if (!(per_cpu_ptr(&rcu_data, cpu)->mynode->exp_seq_poll_rq & 0x1))
+               (void)start_poll_synchronize_rcu_expedited();
 }
 
 #include "tree_stall.h"
index 2ccf584..d4a97e4 100644 (file)
@@ -133,6 +133,10 @@ struct rcu_node {
        wait_queue_head_t exp_wq[4];
        struct rcu_exp_work rew;
        bool exp_need_flush;    /* Need to flush workitem? */
+       raw_spinlock_t exp_poll_lock;
+                               /* Lock and data for polled expedited grace periods. */
+       unsigned long exp_seq_poll_rq;
+       struct work_struct exp_poll_wq;
 } ____cacheline_internodealigned_in_smp;
 
 /*
@@ -187,9 +191,6 @@ struct rcu_data {
 
        /* 3) dynticks interface. */
        int dynticks_snap;              /* Per-GP tracking for dynticks. */
-       long dynticks_nesting;          /* Track process nesting level. */
-       long dynticks_nmi_nesting;      /* Track irq/NMI nesting level. */
-       atomic_t dynticks;              /* Even value for idle, else odd. */
        bool rcu_need_heavy_qs;         /* GP old, so heavy quiescent state! */
        bool rcu_urgent_qs;             /* GP old need light quiescent state. */
        bool rcu_forced_tick;           /* Forced tick to provide QS. */
@@ -235,6 +236,7 @@ struct rcu_data {
                                         * if rdp_gp.
                                         */
        struct list_head nocb_entry_rdp; /* rcu_data node in wakeup chain. */
+       struct rcu_data *nocb_toggling_rdp; /* rdp queued for (de-)offloading */
 
        /* The following fields are used by CB kthread, hence new cacheline. */
        struct rcu_data *nocb_gp_rdp ____cacheline_internodealigned_in_smp;
@@ -323,6 +325,9 @@ struct rcu_state {
        short gp_state;                         /* GP kthread sleep state. */
        unsigned long gp_wake_time;             /* Last GP kthread wake. */
        unsigned long gp_wake_seq;              /* ->gp_seq at ^^^. */
+       unsigned long gp_seq_polled;            /* GP seq for polled API. */
+       unsigned long gp_seq_polled_snap;       /* ->gp_seq_polled at normal GP start. */
+       unsigned long gp_seq_polled_exp_snap;   /* ->gp_seq_polled at expedited GP start. */
 
        /* End of fields guarded by root rcu_node's lock. */
 
@@ -425,12 +430,11 @@ static void rcu_flavor_sched_clock_irq(int user);
 static void dump_blkd_tasks(struct rcu_node *rnp, int ncheck);
 static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags);
 static void rcu_preempt_boost_start_gp(struct rcu_node *rnp);
-static bool rcu_is_callbacks_kthread(void);
+static bool rcu_is_callbacks_kthread(struct rcu_data *rdp);
 static void rcu_cpu_kthread_setup(unsigned int cpu);
 static void rcu_spawn_one_boost_kthread(struct rcu_node *rnp);
 static bool rcu_preempt_has_tasks(struct rcu_node *rnp);
 static bool rcu_preempt_need_deferred_qs(struct task_struct *t);
-static void rcu_preempt_deferred_qs(struct task_struct *t);
 static void zero_cpu_stall_ticks(struct rcu_data *rdp);
 static struct swait_queue_head *rcu_nocb_gp_get(struct rcu_node *rnp);
 static void rcu_nocb_gp_cleanup(struct swait_queue_head *sq);
@@ -470,10 +474,6 @@ do {                                                               \
 
 static void rcu_bind_gp_kthread(void);
 static bool rcu_nohz_full_cpu(void);
-static void rcu_dynticks_task_enter(void);
-static void rcu_dynticks_task_exit(void);
-static void rcu_dynticks_task_trace_enter(void);
-static void rcu_dynticks_task_trace_exit(void);
 
 /* Forward declarations for tree_stall.h */
 static void record_gp_stall_check_time(void);
@@ -481,3 +481,6 @@ static void rcu_iw_handler(struct irq_work *iwp);
 static void check_cpu_stall(struct rcu_data *rdp);
 static void rcu_check_gp_start_stall(struct rcu_node *rnp, struct rcu_data *rdp,
                                     const unsigned long gpssdelay);
+
+/* Forward declarations for tree_exp.h. */
+static void sync_rcu_do_polled_gp(struct work_struct *wp);
index 0f70f62..be66758 100644 (file)
@@ -18,6 +18,7 @@ static int rcu_print_task_exp_stall(struct rcu_node *rnp);
 static void rcu_exp_gp_seq_start(void)
 {
        rcu_seq_start(&rcu_state.expedited_sequence);
+       rcu_poll_gp_seq_start_unlocked(&rcu_state.gp_seq_polled_exp_snap);
 }
 
 /*
@@ -34,6 +35,7 @@ static __maybe_unused unsigned long rcu_exp_gp_seq_endval(void)
  */
 static void rcu_exp_gp_seq_end(void)
 {
+       rcu_poll_gp_seq_end_unlocked(&rcu_state.gp_seq_polled_exp_snap);
        rcu_seq_end(&rcu_state.expedited_sequence);
        smp_mb(); /* Ensure that consecutive grace periods serialize. */
 }
@@ -356,7 +358,7 @@ static void __sync_rcu_exp_select_node_cpus(struct rcu_exp_work *rewp)
                    !(rnp->qsmaskinitnext & mask)) {
                        mask_ofl_test |= mask;
                } else {
-                       snap = rcu_dynticks_snap(rdp);
+                       snap = rcu_dynticks_snap(cpu);
                        if (rcu_dynticks_in_eqs(snap))
                                mask_ofl_test |= mask;
                        else
@@ -621,7 +623,6 @@ static void synchronize_rcu_expedited_wait(void)
                        return;
                if (rcu_stall_is_suppressed())
                        continue;
-               panic_on_rcu_stall();
                trace_rcu_stall_warning(rcu_state.name, TPS("ExpeditedStall"));
                pr_err("INFO: %s detected expedited stalls on CPUs/tasks: {",
                       rcu_state.name);
@@ -636,10 +637,11 @@ static void synchronize_rcu_expedited_wait(void)
                                        continue;
                                ndetected++;
                                rdp = per_cpu_ptr(&rcu_data, cpu);
-                               pr_cont(" %d-%c%c%c", cpu,
+                               pr_cont(" %d-%c%c%c%c", cpu,
                                        "O."[!!cpu_online(cpu)],
                                        "o."[!!(rdp->grpmask & rnp->expmaskinit)],
-                                       "N."[!!(rdp->grpmask & rnp->expmaskinitnext)]);
+                                       "N."[!!(rdp->grpmask & rnp->expmaskinitnext)],
+                                       "D."[!!(rdp->cpu_no_qs.b.exp)]);
                        }
                }
                pr_cont(" } %lu jiffies s: %lu root: %#lx/%c\n",
@@ -669,6 +671,7 @@ static void synchronize_rcu_expedited_wait(void)
                        }
                }
                jiffies_stall = 3 * rcu_exp_jiffies_till_stall_check() + 3;
+               panic_on_rcu_stall();
        }
 }
 
@@ -913,8 +916,18 @@ void synchronize_rcu_expedited(void)
                         "Illegal synchronize_rcu_expedited() in RCU read-side critical section");
 
        /* Is the state is such that the call is a grace period? */
-       if (rcu_blocking_is_gp())
-               return;
+       if (rcu_blocking_is_gp()) {
+               // Note well that this code runs with !PREEMPT && !SMP.
+               // In addition, all code that advances grace periods runs
+               // at process level.  Therefore, this expedited GP overlaps
+               // with other expedited GPs only by being fully nested within
+               // them, which allows reuse of ->gp_seq_polled_exp_snap.
+               rcu_poll_gp_seq_start_unlocked(&rcu_state.gp_seq_polled_exp_snap);
+               rcu_poll_gp_seq_end_unlocked(&rcu_state.gp_seq_polled_exp_snap);
+               if (rcu_init_invoked())
+                       cond_resched();
+               return;  // Context allows vacuous grace periods.
+       }
 
        /* If expedited grace periods are prohibited, fall back to normal. */
        if (rcu_gp_is_normal()) {
@@ -950,3 +963,93 @@ void synchronize_rcu_expedited(void)
                synchronize_rcu_expedited_destroy_work(&rew);
 }
 EXPORT_SYMBOL_GPL(synchronize_rcu_expedited);
+
+/*
+ * Ensure that start_poll_synchronize_rcu_expedited() has the expedited
+ * RCU grace periods that it needs.
+ */
+static void sync_rcu_do_polled_gp(struct work_struct *wp)
+{
+       unsigned long flags;
+       int i = 0;
+       struct rcu_node *rnp = container_of(wp, struct rcu_node, exp_poll_wq);
+       unsigned long s;
+
+       raw_spin_lock_irqsave(&rnp->exp_poll_lock, flags);
+       s = rnp->exp_seq_poll_rq;
+       rnp->exp_seq_poll_rq = RCU_GET_STATE_COMPLETED;
+       raw_spin_unlock_irqrestore(&rnp->exp_poll_lock, flags);
+       if (s == RCU_GET_STATE_COMPLETED)
+               return;
+       while (!poll_state_synchronize_rcu(s)) {
+               synchronize_rcu_expedited();
+               if (i == 10 || i == 20)
+                       pr_info("%s: i = %d s = %lx gp_seq_polled = %lx\n", __func__, i, s, READ_ONCE(rcu_state.gp_seq_polled));
+               i++;
+       }
+       raw_spin_lock_irqsave(&rnp->exp_poll_lock, flags);
+       s = rnp->exp_seq_poll_rq;
+       if (poll_state_synchronize_rcu(s))
+               rnp->exp_seq_poll_rq = RCU_GET_STATE_COMPLETED;
+       raw_spin_unlock_irqrestore(&rnp->exp_poll_lock, flags);
+}
+
+/**
+ * start_poll_synchronize_rcu_expedited - Snapshot current RCU state and start expedited grace period
+ *
+ * Returns a cookie to pass to a call to cond_synchronize_rcu(),
+ * cond_synchronize_rcu_expedited(), or poll_state_synchronize_rcu(),
+ * allowing them to determine whether or not any sort of grace period has
+ * elapsed in the meantime.  If the needed expedited grace period is not
+ * already slated to start, initiates that grace period.
+ */
+unsigned long start_poll_synchronize_rcu_expedited(void)
+{
+       unsigned long flags;
+       struct rcu_data *rdp;
+       struct rcu_node *rnp;
+       unsigned long s;
+
+       s = get_state_synchronize_rcu();
+       rdp = per_cpu_ptr(&rcu_data, raw_smp_processor_id());
+       rnp = rdp->mynode;
+       if (rcu_init_invoked())
+               raw_spin_lock_irqsave(&rnp->exp_poll_lock, flags);
+       if (!poll_state_synchronize_rcu(s)) {
+               rnp->exp_seq_poll_rq = s;
+               if (rcu_init_invoked())
+                       queue_work(rcu_gp_wq, &rnp->exp_poll_wq);
+       }
+       if (rcu_init_invoked())
+               raw_spin_unlock_irqrestore(&rnp->exp_poll_lock, flags);
+
+       return s;
+}
+EXPORT_SYMBOL_GPL(start_poll_synchronize_rcu_expedited);
+
+/**
+ * cond_synchronize_rcu_expedited - Conditionally wait for an expedited RCU grace period
+ *
+ * @oldstate: value from get_state_synchronize_rcu(), start_poll_synchronize_rcu(), or start_poll_synchronize_rcu_expedited()
+ *
+ * If any type of full RCU grace period has elapsed since the earlier
+ * call to get_state_synchronize_rcu(), start_poll_synchronize_rcu(),
+ * or start_poll_synchronize_rcu_expedited(), just return.  Otherwise,
+ * invoke synchronize_rcu_expedited() to wait for a full grace period.
+ *
+ * Yes, this function does not take counter wrap into account.
+ * But counter wrap is harmless.  If the counter wraps, we have waited for
+ * more than 2 billion grace periods (and way more on a 64-bit system!),
+ * so waiting for a couple of additional grace periods should be just fine.
+ *
+ * This function provides the same memory-ordering guarantees that
+ * would be provided by a synchronize_rcu() that was invoked at the call
+ * to the function that provided @oldstate and that returned at the end
+ * of this function.
+ */
+void cond_synchronize_rcu_expedited(unsigned long oldstate)
+{
+       if (!poll_state_synchronize_rcu(oldstate))
+               synchronize_rcu_expedited();
+}
+EXPORT_SYMBOL_GPL(cond_synchronize_rcu_expedited);
index 46694e1..a8f574d 100644 (file)
@@ -546,52 +546,51 @@ static void __call_rcu_nocb_wake(struct rcu_data *rdp, bool was_alldone,
        }
 }
 
-/*
- * Check if we ignore this rdp.
- *
- * We check that without holding the nocb lock but
- * we make sure not to miss a freshly offloaded rdp
- * with the current ordering:
- *
- *  rdp_offload_toggle()        nocb_gp_enabled_cb()
- * -------------------------   ----------------------------
- *    WRITE flags                 LOCK nocb_gp_lock
- *    LOCK nocb_gp_lock           READ/WRITE nocb_gp_sleep
- *    READ/WRITE nocb_gp_sleep    UNLOCK nocb_gp_lock
- *    UNLOCK nocb_gp_lock         READ flags
- */
-static inline bool nocb_gp_enabled_cb(struct rcu_data *rdp)
-{
-       u8 flags = SEGCBLIST_OFFLOADED | SEGCBLIST_KTHREAD_GP;
-
-       return rcu_segcblist_test_flags(&rdp->cblist, flags);
-}
-
-static inline bool nocb_gp_update_state_deoffloading(struct rcu_data *rdp,
-                                                    bool *needwake_state)
+static int nocb_gp_toggle_rdp(struct rcu_data *rdp,
+                              bool *wake_state)
 {
        struct rcu_segcblist *cblist = &rdp->cblist;
+       unsigned long flags;
+       int ret;
 
-       if (rcu_segcblist_test_flags(cblist, SEGCBLIST_OFFLOADED)) {
-               if (!rcu_segcblist_test_flags(cblist, SEGCBLIST_KTHREAD_GP)) {
-                       rcu_segcblist_set_flags(cblist, SEGCBLIST_KTHREAD_GP);
-                       if (rcu_segcblist_test_flags(cblist, SEGCBLIST_KTHREAD_CB))
-                               *needwake_state = true;
-               }
-               return false;
+       rcu_nocb_lock_irqsave(rdp, flags);
+       if (rcu_segcblist_test_flags(cblist, SEGCBLIST_OFFLOADED) &&
+           !rcu_segcblist_test_flags(cblist, SEGCBLIST_KTHREAD_GP)) {
+               /*
+                * Offloading. Set our flag and notify the offload worker.
+                * We will handle this rdp until it ever gets de-offloaded.
+                */
+               rcu_segcblist_set_flags(cblist, SEGCBLIST_KTHREAD_GP);
+               if (rcu_segcblist_test_flags(cblist, SEGCBLIST_KTHREAD_CB))
+                       *wake_state = true;
+               ret = 1;
+       } else if (!rcu_segcblist_test_flags(cblist, SEGCBLIST_OFFLOADED) &&
+                  rcu_segcblist_test_flags(cblist, SEGCBLIST_KTHREAD_GP)) {
+               /*
+                * De-offloading. Clear our flag and notify the de-offload worker.
+                * We will ignore this rdp until it ever gets re-offloaded.
+                */
+               rcu_segcblist_clear_flags(cblist, SEGCBLIST_KTHREAD_GP);
+               if (!rcu_segcblist_test_flags(cblist, SEGCBLIST_KTHREAD_CB))
+                       *wake_state = true;
+               ret = 0;
+       } else {
+               WARN_ON_ONCE(1);
+               ret = -1;
        }
 
-       /*
-        * De-offloading. Clear our flag and notify the de-offload worker.
-        * We will ignore this rdp until it ever gets re-offloaded.
-        */
-       WARN_ON_ONCE(!rcu_segcblist_test_flags(cblist, SEGCBLIST_KTHREAD_GP));
-       rcu_segcblist_clear_flags(cblist, SEGCBLIST_KTHREAD_GP);
-       if (!rcu_segcblist_test_flags(cblist, SEGCBLIST_KTHREAD_CB))
-               *needwake_state = true;
-       return true;
+       rcu_nocb_unlock_irqrestore(rdp, flags);
+
+       return ret;
 }
 
+static void nocb_gp_sleep(struct rcu_data *my_rdp, int cpu)
+{
+       trace_rcu_nocb_wake(rcu_state.name, cpu, TPS("Sleep"));
+       swait_event_interruptible_exclusive(my_rdp->nocb_gp_wq,
+                                       !READ_ONCE(my_rdp->nocb_gp_sleep));
+       trace_rcu_nocb_wake(rcu_state.name, cpu, TPS("EndSleep"));
+}
 
 /*
  * No-CBs GP kthreads come here to wait for additional callbacks to show up
@@ -609,7 +608,7 @@ static void nocb_gp_wait(struct rcu_data *my_rdp)
        bool needwait_gp = false; // This prevents actual uninitialized use.
        bool needwake;
        bool needwake_gp;
-       struct rcu_data *rdp;
+       struct rcu_data *rdp, *rdp_toggling = NULL;
        struct rcu_node *rnp;
        unsigned long wait_gp_seq = 0; // Suppress "use uninitialized" warning.
        bool wasempty = false;
@@ -634,19 +633,10 @@ static void nocb_gp_wait(struct rcu_data *my_rdp)
         * is added to the list, so the skipped-over rcu_data structures
         * won't be ignored for long.
         */
-       list_for_each_entry_rcu(rdp, &my_rdp->nocb_head_rdp, nocb_entry_rdp, 1) {
-               bool needwake_state = false;
-
-               if (!nocb_gp_enabled_cb(rdp))
-                       continue;
+       list_for_each_entry(rdp, &my_rdp->nocb_head_rdp, nocb_entry_rdp) {
                trace_rcu_nocb_wake(rcu_state.name, rdp->cpu, TPS("Check"));
                rcu_nocb_lock_irqsave(rdp, flags);
-               if (nocb_gp_update_state_deoffloading(rdp, &needwake_state)) {
-                       rcu_nocb_unlock_irqrestore(rdp, flags);
-                       if (needwake_state)
-                               swake_up_one(&rdp->nocb_state_wq);
-                       continue;
-               }
+               lockdep_assert_held(&rdp->nocb_lock);
                bypass_ncbs = rcu_cblist_n_cbs(&rdp->nocb_bypass);
                if (bypass_ncbs &&
                    (time_after(j, READ_ONCE(rdp->nocb_bypass_first) + 1) ||
@@ -656,8 +646,6 @@ static void nocb_gp_wait(struct rcu_data *my_rdp)
                        bypass_ncbs = rcu_cblist_n_cbs(&rdp->nocb_bypass);
                } else if (!bypass_ncbs && rcu_segcblist_empty(&rdp->cblist)) {
                        rcu_nocb_unlock_irqrestore(rdp, flags);
-                       if (needwake_state)
-                               swake_up_one(&rdp->nocb_state_wq);
                        continue; /* No callbacks here, try next. */
                }
                if (bypass_ncbs) {
@@ -705,8 +693,6 @@ static void nocb_gp_wait(struct rcu_data *my_rdp)
                }
                if (needwake_gp)
                        rcu_gp_kthread_wake();
-               if (needwake_state)
-                       swake_up_one(&rdp->nocb_state_wq);
        }
 
        my_rdp->nocb_gp_bypass = bypass;
@@ -723,13 +709,19 @@ static void nocb_gp_wait(struct rcu_data *my_rdp)
                /* Polling, so trace if first poll in the series. */
                if (gotcbs)
                        trace_rcu_nocb_wake(rcu_state.name, cpu, TPS("Poll"));
-               schedule_timeout_idle(1);
+               if (list_empty(&my_rdp->nocb_head_rdp)) {
+                       raw_spin_lock_irqsave(&my_rdp->nocb_gp_lock, flags);
+                       if (!my_rdp->nocb_toggling_rdp)
+                               WRITE_ONCE(my_rdp->nocb_gp_sleep, true);
+                       raw_spin_unlock_irqrestore(&my_rdp->nocb_gp_lock, flags);
+                       /* Wait for any offloading rdp */
+                       nocb_gp_sleep(my_rdp, cpu);
+               } else {
+                       schedule_timeout_idle(1);
+               }
        } else if (!needwait_gp) {
                /* Wait for callbacks to appear. */
-               trace_rcu_nocb_wake(rcu_state.name, cpu, TPS("Sleep"));
-               swait_event_interruptible_exclusive(my_rdp->nocb_gp_wq,
-                               !READ_ONCE(my_rdp->nocb_gp_sleep));
-               trace_rcu_nocb_wake(rcu_state.name, cpu, TPS("EndSleep"));
+               nocb_gp_sleep(my_rdp, cpu);
        } else {
                rnp = my_rdp->mynode;
                trace_rcu_this_gp(rnp, my_rdp, wait_gp_seq, TPS("StartWait"));
@@ -739,15 +731,49 @@ static void nocb_gp_wait(struct rcu_data *my_rdp)
                        !READ_ONCE(my_rdp->nocb_gp_sleep));
                trace_rcu_this_gp(rnp, my_rdp, wait_gp_seq, TPS("EndWait"));
        }
+
        if (!rcu_nocb_poll) {
                raw_spin_lock_irqsave(&my_rdp->nocb_gp_lock, flags);
+               // (De-)queue an rdp to/from the group if its nocb state is changing
+               rdp_toggling = my_rdp->nocb_toggling_rdp;
+               if (rdp_toggling)
+                       my_rdp->nocb_toggling_rdp = NULL;
+
                if (my_rdp->nocb_defer_wakeup > RCU_NOCB_WAKE_NOT) {
                        WRITE_ONCE(my_rdp->nocb_defer_wakeup, RCU_NOCB_WAKE_NOT);
                        del_timer(&my_rdp->nocb_timer);
                }
                WRITE_ONCE(my_rdp->nocb_gp_sleep, true);
                raw_spin_unlock_irqrestore(&my_rdp->nocb_gp_lock, flags);
+       } else {
+               rdp_toggling = READ_ONCE(my_rdp->nocb_toggling_rdp);
+               if (rdp_toggling) {
+                       /*
+                        * Paranoid locking to make sure nocb_toggling_rdp is well
+                        * reset *before* we (re)set SEGCBLIST_KTHREAD_GP or we could
+                        * race with another round of nocb toggling for this rdp.
+                        * Nocb locking should prevent from that already but we stick
+                        * to paranoia, especially in rare path.
+                        */
+                       raw_spin_lock_irqsave(&my_rdp->nocb_gp_lock, flags);
+                       my_rdp->nocb_toggling_rdp = NULL;
+                       raw_spin_unlock_irqrestore(&my_rdp->nocb_gp_lock, flags);
+               }
+       }
+
+       if (rdp_toggling) {
+               bool wake_state = false;
+               int ret;
+
+               ret = nocb_gp_toggle_rdp(rdp_toggling, &wake_state);
+               if (ret == 1)
+                       list_add_tail(&rdp_toggling->nocb_entry_rdp, &my_rdp->nocb_head_rdp);
+               else if (ret == 0)
+                       list_del(&rdp_toggling->nocb_entry_rdp);
+               if (wake_state)
+                       swake_up_one(&rdp_toggling->nocb_state_wq);
        }
+
        my_rdp->nocb_gp_seq = -1;
        WARN_ON(signal_pending(current));
 }
@@ -966,16 +992,15 @@ static int rdp_offload_toggle(struct rcu_data *rdp,
        swake_up_one(&rdp->nocb_cb_wq);
 
        raw_spin_lock_irqsave(&rdp_gp->nocb_gp_lock, flags);
+       // Queue this rdp for add/del to/from the list to iterate on rcuog
+       WRITE_ONCE(rdp_gp->nocb_toggling_rdp, rdp);
        if (rdp_gp->nocb_gp_sleep) {
                rdp_gp->nocb_gp_sleep = false;
                wake_gp = true;
        }
        raw_spin_unlock_irqrestore(&rdp_gp->nocb_gp_lock, flags);
 
-       if (wake_gp)
-               wake_up_process(rdp_gp->nocb_gp_kthread);
-
-       return 0;
+       return wake_gp;
 }
 
 static long rcu_nocb_rdp_deoffload(void *arg)
@@ -983,9 +1008,15 @@ static long rcu_nocb_rdp_deoffload(void *arg)
        struct rcu_data *rdp = arg;
        struct rcu_segcblist *cblist = &rdp->cblist;
        unsigned long flags;
-       int ret;
+       int wake_gp;
+       struct rcu_data *rdp_gp = rdp->nocb_gp_rdp;
 
-       WARN_ON_ONCE(rdp->cpu != raw_smp_processor_id());
+       /*
+        * rcu_nocb_rdp_deoffload() may be called directly if
+        * rcuog/o[p] spawn failed, because at this time the rdp->cpu
+        * is not online yet.
+        */
+       WARN_ON_ONCE((rdp->cpu != raw_smp_processor_id()) && cpu_online(rdp->cpu));
 
        pr_info("De-offloading %d\n", rdp->cpu);
 
@@ -1009,12 +1040,41 @@ static long rcu_nocb_rdp_deoffload(void *arg)
         */
        rcu_segcblist_set_flags(cblist, SEGCBLIST_RCU_CORE);
        invoke_rcu_core();
-       ret = rdp_offload_toggle(rdp, false, flags);
-       swait_event_exclusive(rdp->nocb_state_wq,
-                             !rcu_segcblist_test_flags(cblist, SEGCBLIST_KTHREAD_CB |
-                                                       SEGCBLIST_KTHREAD_GP));
-       /* Stop nocb_gp_wait() from iterating over this structure. */
-       list_del_rcu(&rdp->nocb_entry_rdp);
+       wake_gp = rdp_offload_toggle(rdp, false, flags);
+
+       mutex_lock(&rdp_gp->nocb_gp_kthread_mutex);
+       if (rdp_gp->nocb_gp_kthread) {
+               if (wake_gp)
+                       wake_up_process(rdp_gp->nocb_gp_kthread);
+
+               /*
+                * If rcuo[p] kthread spawn failed, directly remove SEGCBLIST_KTHREAD_CB.
+                * Just wait SEGCBLIST_KTHREAD_GP to be cleared by rcuog.
+                */
+               if (!rdp->nocb_cb_kthread) {
+                       rcu_nocb_lock_irqsave(rdp, flags);
+                       rcu_segcblist_clear_flags(&rdp->cblist, SEGCBLIST_KTHREAD_CB);
+                       rcu_nocb_unlock_irqrestore(rdp, flags);
+               }
+
+               swait_event_exclusive(rdp->nocb_state_wq,
+                                       !rcu_segcblist_test_flags(cblist,
+                                         SEGCBLIST_KTHREAD_CB | SEGCBLIST_KTHREAD_GP));
+       } else {
+               /*
+                * No kthread to clear the flags for us or remove the rdp from the nocb list
+                * to iterate. Do it here instead. Locking doesn't look stricly necessary
+                * but we stick to paranoia in this rare path.
+                */
+               rcu_nocb_lock_irqsave(rdp, flags);
+               rcu_segcblist_clear_flags(&rdp->cblist,
+                               SEGCBLIST_KTHREAD_CB | SEGCBLIST_KTHREAD_GP);
+               rcu_nocb_unlock_irqrestore(rdp, flags);
+
+               list_del(&rdp->nocb_entry_rdp);
+       }
+       mutex_unlock(&rdp_gp->nocb_gp_kthread_mutex);
+
        /*
         * Lock one last time to acquire latest callback updates from kthreads
         * so we can later handle callbacks locally without locking.
@@ -1035,7 +1095,7 @@ static long rcu_nocb_rdp_deoffload(void *arg)
        WARN_ON_ONCE(rcu_cblist_n_cbs(&rdp->nocb_bypass));
 
 
-       return ret;
+       return 0;
 }
 
 int rcu_nocb_cpu_deoffload(int cpu)
@@ -1043,8 +1103,8 @@ int rcu_nocb_cpu_deoffload(int cpu)
        struct rcu_data *rdp = per_cpu_ptr(&rcu_data, cpu);
        int ret = 0;
 
-       mutex_lock(&rcu_state.barrier_mutex);
        cpus_read_lock();
+       mutex_lock(&rcu_state.barrier_mutex);
        if (rcu_rdp_is_offloaded(rdp)) {
                if (cpu_online(cpu)) {
                        ret = work_on_cpu(cpu, rcu_nocb_rdp_deoffload, rdp);
@@ -1055,8 +1115,8 @@ int rcu_nocb_cpu_deoffload(int cpu)
                        ret = -EINVAL;
                }
        }
-       cpus_read_unlock();
        mutex_unlock(&rcu_state.barrier_mutex);
+       cpus_read_unlock();
 
        return ret;
 }
@@ -1067,7 +1127,8 @@ static long rcu_nocb_rdp_offload(void *arg)
        struct rcu_data *rdp = arg;
        struct rcu_segcblist *cblist = &rdp->cblist;
        unsigned long flags;
-       int ret;
+       int wake_gp;
+       struct rcu_data *rdp_gp = rdp->nocb_gp_rdp;
 
        WARN_ON_ONCE(rdp->cpu != raw_smp_processor_id());
        /*
@@ -1077,17 +1138,10 @@ static long rcu_nocb_rdp_offload(void *arg)
        if (!rdp->nocb_gp_rdp)
                return -EINVAL;
 
-       pr_info("Offloading %d\n", rdp->cpu);
+       if (WARN_ON_ONCE(!rdp_gp->nocb_gp_kthread))
+               return -EINVAL;
 
-       /*
-        * Cause future nocb_gp_wait() invocations to iterate over
-        * structure, resetting ->nocb_gp_sleep and waking up the related
-        * "rcuog".  Since nocb_gp_wait() in turn locks ->nocb_gp_lock
-        * before setting ->nocb_gp_sleep again, we are guaranteed to
-        * iterate this newly added structure before "rcuog" goes to
-        * sleep again.
-        */
-       list_add_tail_rcu(&rdp->nocb_entry_rdp, &rdp->nocb_gp_rdp->nocb_head_rdp);
+       pr_info("Offloading %d\n", rdp->cpu);
 
        /*
         * Can't use rcu_nocb_lock_irqsave() before SEGCBLIST_LOCKING
@@ -1111,7 +1165,9 @@ static long rcu_nocb_rdp_offload(void *arg)
         *      WRITE flags               READ callbacks
         *      rcu_nocb_unlock()         rcu_nocb_unlock()
         */
-       ret = rdp_offload_toggle(rdp, true, flags);
+       wake_gp = rdp_offload_toggle(rdp, true, flags);
+       if (wake_gp)
+               wake_up_process(rdp_gp->nocb_gp_kthread);
        swait_event_exclusive(rdp->nocb_state_wq,
                              rcu_segcblist_test_flags(cblist, SEGCBLIST_KTHREAD_CB) &&
                              rcu_segcblist_test_flags(cblist, SEGCBLIST_KTHREAD_GP));
@@ -1124,7 +1180,7 @@ static long rcu_nocb_rdp_offload(void *arg)
        rcu_segcblist_clear_flags(cblist, SEGCBLIST_RCU_CORE);
        rcu_nocb_unlock_irqrestore(rdp, flags);
 
-       return ret;
+       return 0;
 }
 
 int rcu_nocb_cpu_offload(int cpu)
@@ -1132,8 +1188,8 @@ int rcu_nocb_cpu_offload(int cpu)
        struct rcu_data *rdp = per_cpu_ptr(&rcu_data, cpu);
        int ret = 0;
 
-       mutex_lock(&rcu_state.barrier_mutex);
        cpus_read_lock();
+       mutex_lock(&rcu_state.barrier_mutex);
        if (!rcu_rdp_is_offloaded(rdp)) {
                if (cpu_online(cpu)) {
                        ret = work_on_cpu(cpu, rcu_nocb_rdp_offload, rdp);
@@ -1144,8 +1200,8 @@ int rcu_nocb_cpu_offload(int cpu)
                        ret = -EINVAL;
                }
        }
-       cpus_read_unlock();
        mutex_unlock(&rcu_state.barrier_mutex);
+       cpus_read_unlock();
 
        return ret;
 }
@@ -1155,11 +1211,21 @@ void __init rcu_init_nohz(void)
 {
        int cpu;
        bool need_rcu_nocb_mask = false;
+       bool offload_all = false;
        struct rcu_data *rdp;
 
+#if defined(CONFIG_RCU_NOCB_CPU_DEFAULT_ALL)
+       if (!rcu_state.nocb_is_setup) {
+               need_rcu_nocb_mask = true;
+               offload_all = true;
+       }
+#endif /* #if defined(CONFIG_RCU_NOCB_CPU_DEFAULT_ALL) */
+
 #if defined(CONFIG_NO_HZ_FULL)
-       if (tick_nohz_full_running && !cpumask_empty(tick_nohz_full_mask))
+       if (tick_nohz_full_running && !cpumask_empty(tick_nohz_full_mask)) {
                need_rcu_nocb_mask = true;
+               offload_all = false; /* NO_HZ_FULL has its own mask. */
+       }
 #endif /* #if defined(CONFIG_NO_HZ_FULL) */
 
        if (need_rcu_nocb_mask) {
@@ -1180,6 +1246,9 @@ void __init rcu_init_nohz(void)
                cpumask_or(rcu_nocb_mask, rcu_nocb_mask, tick_nohz_full_mask);
 #endif /* #if defined(CONFIG_NO_HZ_FULL) */
 
+       if (offload_all)
+               cpumask_setall(rcu_nocb_mask);
+
        if (!cpumask_subset(rcu_nocb_mask, cpu_possible_mask)) {
                pr_info("\tNote: kernel parameter 'rcu_nocbs=', 'nohz_full', or 'isolcpus=' contains nonexistent CPUs.\n");
                cpumask_and(rcu_nocb_mask, cpu_possible_mask,
@@ -1246,7 +1315,7 @@ static void rcu_spawn_cpu_nocb_kthread(int cpu)
                                "rcuog/%d", rdp_gp->cpu);
                if (WARN_ONCE(IS_ERR(t), "%s: Could not start rcuo GP kthread, OOM is now expected behavior\n", __func__)) {
                        mutex_unlock(&rdp_gp->nocb_gp_kthread_mutex);
-                       return;
+                       goto end;
                }
                WRITE_ONCE(rdp_gp->nocb_gp_kthread, t);
                if (kthread_prio)
@@ -1258,12 +1327,21 @@ static void rcu_spawn_cpu_nocb_kthread(int cpu)
        t = kthread_run(rcu_nocb_cb_kthread, rdp,
                        "rcuo%c/%d", rcu_state.abbr, cpu);
        if (WARN_ONCE(IS_ERR(t), "%s: Could not start rcuo CB kthread, OOM is now expected behavior\n", __func__))
-               return;
+               goto end;
 
-       if (kthread_prio)
+       if (IS_ENABLED(CONFIG_RCU_NOCB_CPU_CB_BOOST) && kthread_prio)
                sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
+
        WRITE_ONCE(rdp->nocb_cb_kthread, t);
        WRITE_ONCE(rdp->nocb_gp_kthread, rdp_gp->nocb_gp_kthread);
+       return;
+end:
+       mutex_lock(&rcu_state.barrier_mutex);
+       if (rcu_rdp_is_offloaded(rdp)) {
+               rcu_nocb_rdp_deoffload(rdp);
+               cpumask_clear_cpu(cpu, rcu_nocb_mask);
+       }
+       mutex_unlock(&rcu_state.barrier_mutex);
 }
 
 /* How many CB CPU IDs per GP kthread?  Default of -1 for sqrt(nr_cpu_ids). */
index c8ba0fe..438ecae 100644 (file)
@@ -460,7 +460,7 @@ static bool rcu_preempt_has_tasks(struct rcu_node *rnp)
  * be quite short, for example, in the case of the call from
  * rcu_read_unlock_special().
  */
-static void
+static notrace void
 rcu_preempt_deferred_qs_irqrestore(struct task_struct *t, unsigned long flags)
 {
        bool empty_exp;
@@ -581,7 +581,7 @@ rcu_preempt_deferred_qs_irqrestore(struct task_struct *t, unsigned long flags)
  * is disabled.  This function cannot be expected to understand these
  * nuances, so the caller must handle them.
  */
-static bool rcu_preempt_need_deferred_qs(struct task_struct *t)
+static notrace bool rcu_preempt_need_deferred_qs(struct task_struct *t)
 {
        return (__this_cpu_read(rcu_data.cpu_no_qs.b.exp) ||
                READ_ONCE(t->rcu_read_unlock_special.s)) &&
@@ -595,7 +595,7 @@ static bool rcu_preempt_need_deferred_qs(struct task_struct *t)
  * evaluate safety in terms of interrupt, softirq, and preemption
  * disabling.
  */
-static void rcu_preempt_deferred_qs(struct task_struct *t)
+notrace void rcu_preempt_deferred_qs(struct task_struct *t)
 {
        unsigned long flags;
 
@@ -899,8 +899,8 @@ void rcu_note_context_switch(bool preempt)
        this_cpu_write(rcu_data.rcu_urgent_qs, false);
        if (unlikely(raw_cpu_read(rcu_data.rcu_need_heavy_qs)))
                rcu_momentary_dyntick_idle();
-       rcu_tasks_qs(current, preempt);
 out:
+       rcu_tasks_qs(current, preempt);
        trace_rcu_utilization(TPS("End context switch"));
 }
 EXPORT_SYMBOL_GPL(rcu_note_context_switch);
@@ -926,7 +926,7 @@ static bool rcu_preempt_has_tasks(struct rcu_node *rnp)
  * Because there is no preemptible RCU, there can be no deferred quiescent
  * states.
  */
-static bool rcu_preempt_need_deferred_qs(struct task_struct *t)
+static notrace bool rcu_preempt_need_deferred_qs(struct task_struct *t)
 {
        return false;
 }
@@ -935,7 +935,7 @@ static bool rcu_preempt_need_deferred_qs(struct task_struct *t)
 // period for a quiescent state from this CPU.  Note that requests from
 // tasks are handled when removing the task from the blocked-tasks list
 // below.
-static void rcu_preempt_deferred_qs(struct task_struct *t)
+notrace void rcu_preempt_deferred_qs(struct task_struct *t)
 {
        struct rcu_data *rdp = this_cpu_ptr(&rcu_data);
 
@@ -1012,6 +1012,25 @@ static void rcu_cpu_kthread_setup(unsigned int cpu)
        WRITE_ONCE(rdp->rcuc_activity, jiffies);
 }
 
+static bool rcu_is_callbacks_nocb_kthread(struct rcu_data *rdp)
+{
+#ifdef CONFIG_RCU_NOCB_CPU
+       return rdp->nocb_cb_kthread == current;
+#else
+       return false;
+#endif
+}
+
+/*
+ * Is the current CPU running the RCU-callbacks kthread?
+ * Caller must have preemption disabled.
+ */
+static bool rcu_is_callbacks_kthread(struct rcu_data *rdp)
+{
+       return rdp->rcu_cpu_kthread_task == current ||
+                       rcu_is_callbacks_nocb_kthread(rdp);
+}
+
 #ifdef CONFIG_RCU_BOOST
 
 /*
@@ -1140,7 +1159,8 @@ static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags)
            (rnp->gp_tasks != NULL &&
             rnp->boost_tasks == NULL &&
             rnp->qsmask == 0 &&
-            (!time_after(rnp->boost_time, jiffies) || rcu_state.cbovld))) {
+            (!time_after(rnp->boost_time, jiffies) || rcu_state.cbovld ||
+             IS_ENABLED(CONFIG_RCU_STRICT_GRACE_PERIOD)))) {
                if (rnp->exp_tasks == NULL)
                        WRITE_ONCE(rnp->boost_tasks, rnp->gp_tasks);
                raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
@@ -1151,15 +1171,6 @@ static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags)
        }
 }
 
-/*
- * Is the current CPU running the RCU-callbacks kthread?
- * Caller must have preemption disabled.
- */
-static bool rcu_is_callbacks_kthread(void)
-{
-       return __this_cpu_read(rcu_data.rcu_cpu_kthread_task) == current;
-}
-
 #define RCU_BOOST_DELAY_JIFFIES DIV_ROUND_UP(CONFIG_RCU_BOOST_DELAY * HZ, 1000)
 
 /*
@@ -1242,11 +1253,6 @@ static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags)
        raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
 }
 
-static bool rcu_is_callbacks_kthread(void)
-{
-       return false;
-}
-
 static void rcu_preempt_boost_start_gp(struct rcu_node *rnp)
 {
 }
@@ -1290,37 +1296,3 @@ static void rcu_bind_gp_kthread(void)
                return;
        housekeeping_affine(current, HK_TYPE_RCU);
 }
-
-/* Record the current task on dyntick-idle entry. */
-static __always_inline void rcu_dynticks_task_enter(void)
-{
-#if defined(CONFIG_TASKS_RCU) && defined(CONFIG_NO_HZ_FULL)
-       WRITE_ONCE(current->rcu_tasks_idle_cpu, smp_processor_id());
-#endif /* #if defined(CONFIG_TASKS_RCU) && defined(CONFIG_NO_HZ_FULL) */
-}
-
-/* Record no current task on dyntick-idle exit. */
-static __always_inline void rcu_dynticks_task_exit(void)
-{
-#if defined(CONFIG_TASKS_RCU) && defined(CONFIG_NO_HZ_FULL)
-       WRITE_ONCE(current->rcu_tasks_idle_cpu, -1);
-#endif /* #if defined(CONFIG_TASKS_RCU) && defined(CONFIG_NO_HZ_FULL) */
-}
-
-/* Turn on heavyweight RCU tasks trace readers on idle/user entry. */
-static __always_inline void rcu_dynticks_task_trace_enter(void)
-{
-#ifdef CONFIG_TASKS_TRACE_RCU
-       if (IS_ENABLED(CONFIG_TASKS_TRACE_RCU_READ_MB))
-               current->trc_reader_special.b.need_mb = true;
-#endif /* #ifdef CONFIG_TASKS_TRACE_RCU */
-}
-
-/* Turn off heavyweight RCU tasks trace readers on idle/user exit. */
-static __always_inline void rcu_dynticks_task_trace_exit(void)
-{
-#ifdef CONFIG_TASKS_TRACE_RCU
-       if (IS_ENABLED(CONFIG_TASKS_TRACE_RCU_READ_MB))
-               current->trc_reader_special.b.need_mb = false;
-#endif /* #ifdef CONFIG_TASKS_TRACE_RCU */
-}
index a001e1e..c3fbbcc 100644 (file)
@@ -409,7 +409,19 @@ static bool rcu_is_gp_kthread_starving(unsigned long *jp)
 
 static bool rcu_is_rcuc_kthread_starving(struct rcu_data *rdp, unsigned long *jp)
 {
-       unsigned long j = jiffies - READ_ONCE(rdp->rcuc_activity);
+       int cpu;
+       struct task_struct *rcuc;
+       unsigned long j;
+
+       rcuc = rdp->rcu_cpu_kthread_task;
+       if (!rcuc)
+               return false;
+
+       cpu = task_cpu(rcuc);
+       if (cpu_is_offline(cpu) || idle_cpu(cpu))
+               return false;
+
+       j = jiffies - READ_ONCE(rdp->rcuc_activity);
 
        if (jp)
                *jp = j;
@@ -434,6 +446,9 @@ static void print_cpu_stall_info(int cpu)
        struct rcu_data *rdp = per_cpu_ptr(&rcu_data, cpu);
        char *ticks_title;
        unsigned long ticks_value;
+       bool rcuc_starved;
+       unsigned long j;
+       char buf[32];
 
        /*
         * We could be printing a lot while holding a spinlock.  Avoid
@@ -450,8 +465,11 @@ static void print_cpu_stall_info(int cpu)
        }
        delta = rcu_seq_ctr(rdp->mynode->gp_seq - rdp->rcu_iw_gp_seq);
        falsepositive = rcu_is_gp_kthread_starving(NULL) &&
-                       rcu_dynticks_in_eqs(rcu_dynticks_snap(rdp));
-       pr_err("\t%d-%c%c%c%c: (%lu %s) idle=%03x/%ld/%#lx softirq=%u/%u fqs=%ld %s\n",
+                       rcu_dynticks_in_eqs(rcu_dynticks_snap(cpu));
+       rcuc_starved = rcu_is_rcuc_kthread_starving(rdp, &j);
+       if (rcuc_starved)
+               sprintf(buf, " rcuc=%ld jiffies(starved)", j);
+       pr_err("\t%d-%c%c%c%c: (%lu %s) idle=%04x/%ld/%#lx softirq=%u/%u fqs=%ld%s%s\n",
               cpu,
               "O."[!!cpu_online(cpu)],
               "o."[!!(rdp->grpmask & rdp->mynode->qsmaskinit)],
@@ -460,36 +478,14 @@ static void print_cpu_stall_info(int cpu)
                        rdp->rcu_iw_pending ? (int)min(delta, 9UL) + '0' :
                                "!."[!delta],
               ticks_value, ticks_title,
-              rcu_dynticks_snap(rdp) & 0xfff,
-              rdp->dynticks_nesting, rdp->dynticks_nmi_nesting,
+              rcu_dynticks_snap(cpu) & 0xffff,
+              ct_dynticks_nesting_cpu(cpu), ct_dynticks_nmi_nesting_cpu(cpu),
               rdp->softirq_snap, kstat_softirqs_cpu(RCU_SOFTIRQ, cpu),
               data_race(rcu_state.n_force_qs) - rcu_state.n_force_qs_gpstart,
+              rcuc_starved ? buf : "",
               falsepositive ? " (false positive?)" : "");
 }
 
-static void rcuc_kthread_dump(struct rcu_data *rdp)
-{
-       int cpu;
-       unsigned long j;
-       struct task_struct *rcuc;
-
-       rcuc = rdp->rcu_cpu_kthread_task;
-       if (!rcuc)
-               return;
-
-       cpu = task_cpu(rcuc);
-       if (cpu_is_offline(cpu) || idle_cpu(cpu))
-               return;
-
-       if (!rcu_is_rcuc_kthread_starving(rdp, &j))
-               return;
-
-       pr_err("%s kthread starved for %ld jiffies\n", rcuc->comm, j);
-       sched_show_task(rcuc);
-       if (!trigger_single_cpu_backtrace(cpu))
-               dump_cpu_task(cpu);
-}
-
 /* Complain about starvation of grace-period kthread.  */
 static void rcu_check_gp_kthread_starvation(void)
 {
@@ -661,9 +657,6 @@ static void print_cpu_stall(unsigned long gps)
        rcu_check_gp_kthread_expired_fqs_timer();
        rcu_check_gp_kthread_starvation();
 
-       if (!use_softirq)
-               rcuc_kthread_dump(rdp);
-
        rcu_dump_cpu_stacks();
 
        raw_spin_lock_irqsave_rcu_node(rnp, flags);
index fc7fef5..738842c 100644 (file)
@@ -85,7 +85,7 @@ module_param(rcu_normal_after_boot, int, 0444);
  * and while lockdep is disabled.
  *
  * Note that if the CPU is in the idle loop from an RCU point of view (ie:
- * that we are in the section between rcu_idle_enter() and rcu_idle_exit())
+ * that we are in the section between ct_idle_enter() and ct_idle_exit())
  * then rcu_read_lock_held() sets ``*ret`` to false even if the CPU did an
  * rcu_read_lock().  The reason for this is that RCU ignores CPUs that are
  * in such a section, considering these as in extended quiescent state,
@@ -516,6 +516,19 @@ int rcu_cpu_stall_suppress_at_boot __read_mostly; // !0 = suppress boot stalls.
 EXPORT_SYMBOL_GPL(rcu_cpu_stall_suppress_at_boot);
 module_param(rcu_cpu_stall_suppress_at_boot, int, 0444);
 
+/**
+ * get_completed_synchronize_rcu - Return a pre-completed polled state cookie
+ *
+ * Returns a value that will always be treated by functions like
+ * poll_state_synchronize_rcu() as a cookie whose grace period has already
+ * completed.
+ */
+unsigned long get_completed_synchronize_rcu(void)
+{
+       return RCU_GET_STATE_COMPLETED;
+}
+EXPORT_SYMBOL_GPL(get_completed_synchronize_rcu);
+
 #ifdef CONFIG_PROVE_RCU
 
 /*
index 97ac20b..bda8175 100644 (file)
@@ -18,8 +18,9 @@
 #define CREATE_TRACE_POINTS
 #include <trace/events/rseq.h>
 
-#define RSEQ_CS_PREEMPT_MIGRATE_FLAGS (RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE | \
-                                      RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT)
+#define RSEQ_CS_NO_RESTART_FLAGS (RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT | \
+                                 RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL | \
+                                 RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE)
 
 /*
  *
@@ -175,23 +176,15 @@ static int rseq_need_restart(struct task_struct *t, u32 cs_flags)
        u32 flags, event_mask;
        int ret;
 
+       if (WARN_ON_ONCE(cs_flags & RSEQ_CS_NO_RESTART_FLAGS) || cs_flags)
+               return -EINVAL;
+
        /* Get thread flags. */
        ret = get_user(flags, &t->rseq->flags);
        if (ret)
                return ret;
 
-       /* Take critical section flags into account. */
-       flags |= cs_flags;
-
-       /*
-        * Restart on signal can only be inhibited when restart on
-        * preempt and restart on migrate are inhibited too. Otherwise,
-        * a preempted signal handler could fail to restart the prior
-        * execution context on sigreturn.
-        */
-       if (unlikely((flags & RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL) &&
-                    (flags & RSEQ_CS_PREEMPT_MIGRATE_FLAGS) !=
-                    RSEQ_CS_PREEMPT_MIGRATE_FLAGS))
+       if (WARN_ON_ONCE(flags & RSEQ_CS_NO_RESTART_FLAGS) || flags)
                return -EINVAL;
 
        /*
@@ -203,7 +196,7 @@ static int rseq_need_restart(struct task_struct *t, u32 cs_flags)
        t->rseq_event_mask = 0;
        preempt_enable();
 
-       return !!(event_mask & ~flags);
+       return !!event_mask;
 }
 
 static int clear_rseq_cs(struct task_struct *t)
index da0bf6f..1899990 100644 (file)
@@ -91,7 +91,7 @@
 #include "stats.h"
 
 #include "../workqueue_internal.h"
-#include "../../fs/io-wq.h"
+#include "../../io_uring/io-wq.h"
 #include "../smpboot.h"
 
 /*
@@ -873,15 +873,11 @@ static inline void hrtick_rq_init(struct rq *rq)
        ({                                                              \
                typeof(ptr) _ptr = (ptr);                               \
                typeof(mask) _mask = (mask);                            \
-               typeof(*_ptr) _old, _val = *_ptr;                       \
+               typeof(*_ptr) _val = *_ptr;                             \
                                                                        \
-               for (;;) {                                              \
-                       _old = cmpxchg(_ptr, _val, _val | _mask);       \
-                       if (_old == _val)                               \
-                               break;                                  \
-                       _val = _old;                                    \
-               }                                                       \
-       _old;                                                           \
+               do {                                                    \
+               } while (!try_cmpxchg(_ptr, &_val, _val | _mask));      \
+       _val;                                                           \
 })
 
 #if defined(CONFIG_SMP) && defined(TIF_POLLING_NRFLAG)
@@ -890,7 +886,7 @@ static inline void hrtick_rq_init(struct rq *rq)
  * this avoids any races wrt polling state changes and thereby avoids
  * spurious IPIs.
  */
-static bool set_nr_and_not_polling(struct task_struct *p)
+static inline bool set_nr_and_not_polling(struct task_struct *p)
 {
        struct thread_info *ti = task_thread_info(p);
        return !(fetch_or(&ti->flags, _TIF_NEED_RESCHED) & _TIF_POLLING_NRFLAG);
@@ -905,30 +901,28 @@ static bool set_nr_and_not_polling(struct task_struct *p)
 static bool set_nr_if_polling(struct task_struct *p)
 {
        struct thread_info *ti = task_thread_info(p);
-       typeof(ti->flags) old, val = READ_ONCE(ti->flags);
+       typeof(ti->flags) val = READ_ONCE(ti->flags);
 
        for (;;) {
                if (!(val & _TIF_POLLING_NRFLAG))
                        return false;
                if (val & _TIF_NEED_RESCHED)
                        return true;
-               old = cmpxchg(&ti->flags, val, val | _TIF_NEED_RESCHED);
-               if (old == val)
+               if (try_cmpxchg(&ti->flags, &val, val | _TIF_NEED_RESCHED))
                        break;
-               val = old;
        }
        return true;
 }
 
 #else
-static bool set_nr_and_not_polling(struct task_struct *p)
+static inline bool set_nr_and_not_polling(struct task_struct *p)
 {
        set_tsk_need_resched(p);
        return true;
 }
 
 #ifdef CONFIG_SMP
-static bool set_nr_if_polling(struct task_struct *p)
+static inline bool set_nr_if_polling(struct task_struct *p)
 {
        return false;
 }
@@ -3808,7 +3802,7 @@ bool cpus_share_cache(int this_cpu, int that_cpu)
        return per_cpu(sd_llc_id, this_cpu) == per_cpu(sd_llc_id, that_cpu);
 }
 
-static inline bool ttwu_queue_cond(int cpu, int wake_flags)
+static inline bool ttwu_queue_cond(int cpu)
 {
        /*
         * Do not complicate things with the async wake_list while the CPU is
@@ -3824,13 +3818,21 @@ static inline bool ttwu_queue_cond(int cpu, int wake_flags)
        if (!cpus_share_cache(smp_processor_id(), cpu))
                return true;
 
+       if (cpu == smp_processor_id())
+               return false;
+
        /*
-        * If the task is descheduling and the only running task on the
-        * CPU then use the wakelist to offload the task activation to
-        * the soon-to-be-idle CPU as the current CPU is likely busy.
-        * nr_running is checked to avoid unnecessary task stacking.
+        * If the wakee cpu is idle, or the task is descheduling and the
+        * only running task on the CPU, then use the wakelist to offload
+        * the task activation to the idle (or soon-to-be-idle) CPU as
+        * the current CPU is likely busy. nr_running is checked to
+        * avoid unnecessary task stacking.
+        *
+        * Note that we can only get here with (wakee) p->on_rq=0,
+        * p->on_cpu can be whatever, we've done the dequeue, so
+        * the wakee has been accounted out of ->nr_running.
         */
-       if ((wake_flags & WF_ON_CPU) && cpu_rq(cpu)->nr_running <= 1)
+       if (!cpu_rq(cpu)->nr_running)
                return true;
 
        return false;
@@ -3838,10 +3840,7 @@ static inline bool ttwu_queue_cond(int cpu, int wake_flags)
 
 static bool ttwu_queue_wakelist(struct task_struct *p, int cpu, int wake_flags)
 {
-       if (sched_feat(TTWU_QUEUE) && ttwu_queue_cond(cpu, wake_flags)) {
-               if (WARN_ON_ONCE(cpu == smp_processor_id()))
-                       return false;
-
+       if (sched_feat(TTWU_QUEUE) && ttwu_queue_cond(cpu)) {
                sched_clock_cpu(cpu); /* Sync clocks across CPUs */
                __ttwu_queue_wakelist(p, cpu, wake_flags);
                return true;
@@ -4163,7 +4162,7 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
         * scheduling.
         */
        if (smp_load_acquire(&p->on_cpu) &&
-           ttwu_queue_wakelist(p, task_cpu(p), wake_flags | WF_ON_CPU))
+           ttwu_queue_wakelist(p, task_cpu(p), wake_flags))
                goto unlock;
 
        /*
@@ -4264,6 +4263,38 @@ int task_call_func(struct task_struct *p, task_call_f func, void *arg)
 }
 
 /**
+ * cpu_curr_snapshot - Return a snapshot of the currently running task
+ * @cpu: The CPU on which to snapshot the task.
+ *
+ * Returns the task_struct pointer of the task "currently" running on
+ * the specified CPU.  If the same task is running on that CPU throughout,
+ * the return value will be a pointer to that task's task_struct structure.
+ * If the CPU did any context switches even vaguely concurrently with the
+ * execution of this function, the return value will be a pointer to the
+ * task_struct structure of a randomly chosen task that was running on
+ * that CPU somewhere around the time that this function was executing.
+ *
+ * If the specified CPU was offline, the return value is whatever it
+ * is, perhaps a pointer to the task_struct structure of that CPU's idle
+ * task, but there is no guarantee.  Callers wishing a useful return
+ * value must take some action to ensure that the specified CPU remains
+ * online throughout.
+ *
+ * This function executes full memory barriers before and after fetching
+ * the pointer, which permits the caller to confine this function's fetch
+ * with respect to the caller's accesses to other shared variables.
+ */
+struct task_struct *cpu_curr_snapshot(int cpu)
+{
+       struct task_struct *t;
+
+       smp_mb(); /* Pairing determined by caller's synchronization design. */
+       t = rcu_dereference(cpu_curr(cpu));
+       smp_mb(); /* Pairing determined by caller's synchronization design. */
+       return t;
+}
+
+/**
  * wake_up_process - Wake up a specific process
  * @p: The process to be woken up.
  *
@@ -4753,7 +4784,8 @@ static inline void prepare_task(struct task_struct *next)
         * Claim the task as running, we do this before switching to it
         * such that any running task will have this set.
         *
-        * See the ttwu() WF_ON_CPU case and its ordering comment.
+        * See the smp_load_acquire(&p->on_cpu) case in ttwu() and
+        * its ordering comment.
         */
        WRITE_ONCE(next->on_cpu, 1);
 #endif
@@ -6500,8 +6532,12 @@ static inline void sched_submit_work(struct task_struct *tsk)
                        io_wq_worker_sleeping(tsk);
        }
 
-       if (tsk_is_pi_blocked(tsk))
-               return;
+       /*
+        * spinlock and rwlock must not flush block requests.  This will
+        * deadlock if the callback attempts to acquire a lock which is
+        * already acquired.
+        */
+       SCHED_WARN_ON(current->__state & TASK_RTLOCK_WAIT);
 
        /*
         * If we are going to sleep and we have plugged IO queued,
@@ -6559,7 +6595,7 @@ void __sched schedule_idle(void)
        } while (need_resched());
 }
 
-#if defined(CONFIG_CONTEXT_TRACKING) && !defined(CONFIG_HAVE_CONTEXT_TRACKING_OFFSTACK)
+#if defined(CONFIG_CONTEXT_TRACKING_USER) && !defined(CONFIG_HAVE_CONTEXT_TRACKING_USER_OFFSTACK)
 asmlinkage __visible void __sched schedule_user(void)
 {
        /*
@@ -6998,17 +7034,29 @@ out_unlock:
 EXPORT_SYMBOL(set_user_nice);
 
 /*
- * can_nice - check if a task can reduce its nice value
+ * is_nice_reduction - check if nice value is an actual reduction
+ *
+ * Similar to can_nice() but does not perform a capability check.
+ *
  * @p: task
  * @nice: nice value
  */
-int can_nice(const struct task_struct *p, const int nice)
+static bool is_nice_reduction(const struct task_struct *p, const int nice)
 {
        /* Convert nice value [19,-20] to rlimit style value [1,40]: */
        int nice_rlim = nice_to_rlimit(nice);
 
-       return (nice_rlim <= task_rlimit(p, RLIMIT_NICE) ||
-               capable(CAP_SYS_NICE));
+       return (nice_rlim <= task_rlimit(p, RLIMIT_NICE));
+}
+
+/*
+ * can_nice - check if a task can reduce its nice value
+ * @p: task
+ * @nice: nice value
+ */
+int can_nice(const struct task_struct *p, const int nice)
+{
+       return is_nice_reduction(p, nice) || capable(CAP_SYS_NICE);
 }
 
 #ifdef __ARCH_WANT_SYS_NICE
@@ -7137,12 +7185,14 @@ struct task_struct *idle_task(int cpu)
  * required to meet deadlines.
  */
 unsigned long effective_cpu_util(int cpu, unsigned long util_cfs,
-                                unsigned long max, enum cpu_util_type type,
+                                enum cpu_util_type type,
                                 struct task_struct *p)
 {
-       unsigned long dl_util, util, irq;
+       unsigned long dl_util, util, irq, max;
        struct rq *rq = cpu_rq(cpu);
 
+       max = arch_scale_cpu_capacity(cpu);
+
        if (!uclamp_is_used() &&
            type == FREQUENCY_UTIL && rt_rq_is_runnable(&rq->rt)) {
                return max;
@@ -7222,10 +7272,9 @@ unsigned long effective_cpu_util(int cpu, unsigned long util_cfs,
        return min(max, util);
 }
 
-unsigned long sched_cpu_util(int cpu, unsigned long max)
+unsigned long sched_cpu_util(int cpu)
 {
-       return effective_cpu_util(cpu, cpu_util_cfs(cpu), max,
-                                 ENERGY_UTIL, NULL);
+       return effective_cpu_util(cpu, cpu_util_cfs(cpu), ENERGY_UTIL, NULL);
 }
 #endif /* CONFIG_SMP */
 
@@ -7287,6 +7336,69 @@ static bool check_same_owner(struct task_struct *p)
        return match;
 }
 
+/*
+ * Allow unprivileged RT tasks to decrease priority.
+ * Only issue a capable test if needed and only once to avoid an audit
+ * event on permitted non-privileged operations:
+ */
+static int user_check_sched_setscheduler(struct task_struct *p,
+                                        const struct sched_attr *attr,
+                                        int policy, int reset_on_fork)
+{
+       if (fair_policy(policy)) {
+               if (attr->sched_nice < task_nice(p) &&
+                   !is_nice_reduction(p, attr->sched_nice))
+                       goto req_priv;
+       }
+
+       if (rt_policy(policy)) {
+               unsigned long rlim_rtprio = task_rlimit(p, RLIMIT_RTPRIO);
+
+               /* Can't set/change the rt policy: */
+               if (policy != p->policy && !rlim_rtprio)
+                       goto req_priv;
+
+               /* Can't increase priority: */
+               if (attr->sched_priority > p->rt_priority &&
+                   attr->sched_priority > rlim_rtprio)
+                       goto req_priv;
+       }
+
+       /*
+        * Can't set/change SCHED_DEADLINE policy at all for now
+        * (safest behavior); in the future we would like to allow
+        * unprivileged DL tasks to increase their relative deadline
+        * or reduce their runtime (both ways reducing utilization)
+        */
+       if (dl_policy(policy))
+               goto req_priv;
+
+       /*
+        * Treat SCHED_IDLE as nice 20. Only allow a switch to
+        * SCHED_NORMAL if the RLIMIT_NICE would normally permit it.
+        */
+       if (task_has_idle_policy(p) && !idle_policy(policy)) {
+               if (!is_nice_reduction(p, task_nice(p)))
+                       goto req_priv;
+       }
+
+       /* Can't change other user's priorities: */
+       if (!check_same_owner(p))
+               goto req_priv;
+
+       /* Normal users shall not reset the sched_reset_on_fork flag: */
+       if (p->sched_reset_on_fork && !reset_on_fork)
+               goto req_priv;
+
+       return 0;
+
+req_priv:
+       if (!capable(CAP_SYS_NICE))
+               return -EPERM;
+
+       return 0;
+}
+
 static int __sched_setscheduler(struct task_struct *p,
                                const struct sched_attr *attr,
                                bool user, bool pi)
@@ -7328,58 +7440,11 @@ recheck:
            (rt_policy(policy) != (attr->sched_priority != 0)))
                return -EINVAL;
 
-       /*
-        * Allow unprivileged RT tasks to decrease priority:
-        */
-       if (user && !capable(CAP_SYS_NICE)) {
-               if (fair_policy(policy)) {
-                       if (attr->sched_nice < task_nice(p) &&
-                           !can_nice(p, attr->sched_nice))
-                               return -EPERM;
-               }
-
-               if (rt_policy(policy)) {
-                       unsigned long rlim_rtprio =
-                                       task_rlimit(p, RLIMIT_RTPRIO);
-
-                       /* Can't set/change the rt policy: */
-                       if (policy != p->policy && !rlim_rtprio)
-                               return -EPERM;
-
-                       /* Can't increase priority: */
-                       if (attr->sched_priority > p->rt_priority &&
-                           attr->sched_priority > rlim_rtprio)
-                               return -EPERM;
-               }
-
-                /*
-                 * Can't set/change SCHED_DEADLINE policy at all for now
-                 * (safest behavior); in the future we would like to allow
-                 * unprivileged DL tasks to increase their relative deadline
-                 * or reduce their runtime (both ways reducing utilization)
-                 */
-               if (dl_policy(policy))
-                       return -EPERM;
-
-               /*
-                * Treat SCHED_IDLE as nice 20. Only allow a switch to
-                * SCHED_NORMAL if the RLIMIT_NICE would normally permit it.
-                */
-               if (task_has_idle_policy(p) && !idle_policy(policy)) {
-                       if (!can_nice(p, task_nice(p)))
-                               return -EPERM;
-               }
-
-               /* Can't change other user's priorities: */
-               if (!check_same_owner(p))
-                       return -EPERM;
-
-               /* Normal users shall not reset the sched_reset_on_fork flag: */
-               if (p->sched_reset_on_fork && !reset_on_fork)
-                       return -EPERM;
-       }
-
        if (user) {
+               retval = user_check_sched_setscheduler(p, attr, policy, reset_on_fork);
+               if (retval)
+                       return retval;
+
                if (attr->sched_flags & SCHED_FLAG_SUGOV)
                        return -EINVAL;
 
@@ -9531,7 +9596,7 @@ static struct kmem_cache *task_group_cache __read_mostly;
 #endif
 
 DECLARE_PER_CPU(cpumask_var_t, load_balance_mask);
-DECLARE_PER_CPU(cpumask_var_t, select_idle_mask);
+DECLARE_PER_CPU(cpumask_var_t, select_rq_mask);
 
 void __init sched_init(void)
 {
@@ -9580,7 +9645,7 @@ void __init sched_init(void)
        for_each_possible_cpu(i) {
                per_cpu(load_balance_mask, i) = (cpumask_var_t)kzalloc_node(
                        cpumask_size(), GFP_KERNEL, cpu_to_node(i));
-               per_cpu(select_idle_mask, i) = (cpumask_var_t)kzalloc_node(
+               per_cpu(select_rq_mask, i) = (cpumask_var_t)kzalloc_node(
                        cpumask_size(), GFP_KERNEL, cpu_to_node(i));
        }
 #endif /* CONFIG_CPUMASK_OFFSTACK */
index 38a2cec..93878cb 100644 (file)
@@ -56,7 +56,6 @@ static unsigned long sched_core_update_cookie(struct task_struct *p,
        unsigned long old_cookie;
        struct rq_flags rf;
        struct rq *rq;
-       bool enqueued;
 
        rq = task_rq_lock(p, &rf);
 
@@ -68,14 +67,16 @@ static unsigned long sched_core_update_cookie(struct task_struct *p,
         */
        SCHED_WARN_ON((p->core_cookie || cookie) && !sched_core_enabled(rq));
 
-       enqueued = sched_core_enqueued(p);
-       if (enqueued)
+       if (sched_core_enqueued(p))
                sched_core_dequeue(rq, p, DEQUEUE_SAVE);
 
        old_cookie = p->core_cookie;
        p->core_cookie = cookie;
 
-       if (enqueued)
+       /*
+        * Consider the cases: !prev_cookie and !cookie.
+        */
+       if (cookie && task_on_rq_queued(p))
                sched_core_enqueue(rq, p);
 
        /*
@@ -277,7 +278,11 @@ void __sched_core_account_forceidle(struct rq *rq)
                if (p == rq_i->idle)
                        continue;
 
-               __schedstat_add(p->stats.core_forceidle_sum, delta);
+               /*
+                * Note: this will account forceidle to the current cpu, even
+                * if it comes from our SMT sibling.
+                */
+               __account_forceidle_time(p, delta);
        }
 }
 
index 3dbf351..1207c78 100644 (file)
@@ -157,11 +157,10 @@ static unsigned int get_next_freq(struct sugov_policy *sg_policy,
 static void sugov_get_util(struct sugov_cpu *sg_cpu)
 {
        struct rq *rq = cpu_rq(sg_cpu->cpu);
-       unsigned long max = arch_scale_cpu_capacity(sg_cpu->cpu);
 
-       sg_cpu->max = max;
+       sg_cpu->max = arch_scale_cpu_capacity(sg_cpu->cpu);
        sg_cpu->bw_dl = cpu_bw_dl(rq);
-       sg_cpu->util = effective_cpu_util(sg_cpu->cpu, cpu_util_cfs(sg_cpu->cpu), max,
+       sg_cpu->util = effective_cpu_util(sg_cpu->cpu, cpu_util_cfs(sg_cpu->cpu),
                                          FREQUENCY_UTIL, NULL);
 }
 
index 78a233d..95fc778 100644 (file)
@@ -226,6 +226,21 @@ void account_idle_time(u64 cputime)
                cpustat[CPUTIME_IDLE] += cputime;
 }
 
+
+#ifdef CONFIG_SCHED_CORE
+/*
+ * Account for forceidle time due to core scheduling.
+ *
+ * REQUIRES: schedstat is enabled.
+ */
+void __account_forceidle_time(struct task_struct *p, u64 delta)
+{
+       __schedstat_add(p->stats.core_forceidle_sum, delta);
+
+       task_group_account_field(p, CPUTIME_FORCEIDLE, delta);
+}
+#endif
+
 /*
  * When a guest is interrupted for a longer amount of time, missed clock
  * ticks are not redelivered later. Due to that, this function may on
index b515296..0ab79d8 100644 (file)
@@ -30,14 +30,16 @@ static struct ctl_table sched_dl_sysctls[] = {
                .data           = &sysctl_sched_dl_period_max,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec,
+               .proc_handler   = proc_douintvec_minmax,
+               .extra1         = (void *)&sysctl_sched_dl_period_min,
        },
        {
                .procname       = "sched_deadline_period_min_us",
                .data           = &sysctl_sched_dl_period_min,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec,
+               .proc_handler   = proc_douintvec_minmax,
+               .extra2         = (void *)&sysctl_sched_dl_period_max,
        },
        {}
 };
@@ -1701,7 +1703,10 @@ static void enqueue_task_dl(struct rq *rq, struct task_struct *p, int flags)
                 * the throttle.
                 */
                p->dl.dl_throttled = 0;
-               BUG_ON(!is_dl_boosted(&p->dl) || flags != ENQUEUE_REPLENISH);
+               if (!(flags & ENQUEUE_REPLENISH))
+                       printk_deferred_once("sched: DL de-boosted task PID %d: REPLENISH flag missing\n",
+                                            task_pid_nr(p));
+
                return;
        }
 
index 77b2048..914096c 100644 (file)
@@ -612,11 +612,8 @@ static void update_min_vruntime(struct cfs_rq *cfs_rq)
        }
 
        /* ensure we never gain time by being placed backwards. */
-       cfs_rq->min_vruntime = max_vruntime(cfs_rq->min_vruntime, vruntime);
-#ifndef CONFIG_64BIT
-       smp_wmb();
-       cfs_rq->min_vruntime_copy = cfs_rq->min_vruntime;
-#endif
+       u64_u32_store(cfs_rq->min_vruntime,
+                     max_vruntime(cfs_rq->min_vruntime, vruntime));
 }
 
 static inline bool __entity_less(struct rb_node *a, const struct rb_node *b)
@@ -1055,6 +1052,33 @@ update_stats_curr_start(struct cfs_rq *cfs_rq, struct sched_entity *se)
  * Scheduling class queueing methods:
  */
 
+#ifdef CONFIG_NUMA
+#define NUMA_IMBALANCE_MIN 2
+
+static inline long
+adjust_numa_imbalance(int imbalance, int dst_running, int imb_numa_nr)
+{
+       /*
+        * Allow a NUMA imbalance if busy CPUs is less than the maximum
+        * threshold. Above this threshold, individual tasks may be contending
+        * for both memory bandwidth and any shared HT resources.  This is an
+        * approximation as the number of running tasks may not be related to
+        * the number of busy CPUs due to sched_setaffinity.
+        */
+       if (dst_running > imb_numa_nr)
+               return imbalance;
+
+       /*
+        * Allow a small imbalance based on a simple pair of communicating
+        * tasks that remain local when the destination is lightly loaded.
+        */
+       if (imbalance <= NUMA_IMBALANCE_MIN)
+               return 0;
+
+       return imbalance;
+}
+#endif /* CONFIG_NUMA */
+
 #ifdef CONFIG_NUMA_BALANCING
 /*
  * Approximate time to scan a full NUMA task in ms. The task scan period is
@@ -1548,8 +1572,6 @@ struct task_numa_env {
 
 static unsigned long cpu_load(struct rq *rq);
 static unsigned long cpu_runnable(struct rq *rq);
-static inline long adjust_numa_imbalance(int imbalance,
-                                       int dst_running, int imb_numa_nr);
 
 static inline enum
 numa_type numa_classify(unsigned int imbalance_pct,
@@ -1790,6 +1812,15 @@ static bool task_numa_compare(struct task_numa_env *env,
         */
        cur_ng = rcu_dereference(cur->numa_group);
        if (cur_ng == p_ng) {
+               /*
+                * Do not swap within a group or between tasks that have
+                * no group if there is spare capacity. Swapping does
+                * not address the load imbalance and helps one task at
+                * the cost of punishing another.
+                */
+               if (env->dst_stats.node_type == node_has_spare)
+                       goto unlock;
+
                imp = taskimp + task_weight(cur, env->src_nid, dist) -
                      task_weight(cur, env->dst_nid, dist);
                /*
@@ -2885,6 +2916,7 @@ void init_numa_balancing(unsigned long clone_flags, struct task_struct *p)
        p->node_stamp                   = 0;
        p->numa_scan_seq                = mm ? mm->numa_scan_seq : 0;
        p->numa_scan_period             = sysctl_numa_balancing_scan_delay;
+       p->numa_migrate_retry           = 0;
        /* Protect against double add, see task_tick_numa and task_numa_work */
        p->numa_work.next               = &p->numa_work;
        p->numa_faults                  = NULL;
@@ -3144,6 +3176,8 @@ void reweight_task(struct task_struct *p, int prio)
        load->inv_weight = sched_prio_to_wmult[prio];
 }
 
+static inline int throttled_hierarchy(struct cfs_rq *cfs_rq);
+
 #ifdef CONFIG_FAIR_GROUP_SCHED
 #ifdef CONFIG_SMP
 /*
@@ -3254,8 +3288,6 @@ static long calc_group_shares(struct cfs_rq *cfs_rq)
 }
 #endif /* CONFIG_SMP */
 
-static inline int throttled_hierarchy(struct cfs_rq *cfs_rq);
-
 /*
  * Recomputes the group entity based on the current state of its group
  * runqueue.
@@ -3313,6 +3345,34 @@ static inline void cfs_rq_util_change(struct cfs_rq *cfs_rq, int flags)
 }
 
 #ifdef CONFIG_SMP
+static inline bool load_avg_is_decayed(struct sched_avg *sa)
+{
+       if (sa->load_sum)
+               return false;
+
+       if (sa->util_sum)
+               return false;
+
+       if (sa->runnable_sum)
+               return false;
+
+       /*
+        * _avg must be null when _sum are null because _avg = _sum / divider
+        * Make sure that rounding and/or propagation of PELT values never
+        * break this.
+        */
+       SCHED_WARN_ON(sa->load_avg ||
+                     sa->util_avg ||
+                     sa->runnable_avg);
+
+       return true;
+}
+
+static inline u64 cfs_rq_last_update_time(struct cfs_rq *cfs_rq)
+{
+       return u64_u32_load_copy(cfs_rq->avg.last_update_time,
+                                cfs_rq->last_update_time_copy);
+}
 #ifdef CONFIG_FAIR_GROUP_SCHED
 /*
  * Because list_add_leaf_cfs_rq always places a child cfs_rq on the list
@@ -3345,27 +3405,12 @@ static inline bool cfs_rq_is_decayed(struct cfs_rq *cfs_rq)
        if (cfs_rq->load.weight)
                return false;
 
-       if (cfs_rq->avg.load_sum)
-               return false;
-
-       if (cfs_rq->avg.util_sum)
-               return false;
-
-       if (cfs_rq->avg.runnable_sum)
+       if (!load_avg_is_decayed(&cfs_rq->avg))
                return false;
 
        if (child_cfs_rq_on_list(cfs_rq))
                return false;
 
-       /*
-        * _avg must be null when _sum are null because _avg = _sum / divider
-        * Make sure that rounding and/or propagation of PELT values never
-        * break this.
-        */
-       SCHED_WARN_ON(cfs_rq->avg.load_avg ||
-                     cfs_rq->avg.util_avg ||
-                     cfs_rq->avg.runnable_avg);
-
        return true;
 }
 
@@ -3423,27 +3468,9 @@ void set_task_rq_fair(struct sched_entity *se,
        if (!(se->avg.last_update_time && prev))
                return;
 
-#ifndef CONFIG_64BIT
-       {
-               u64 p_last_update_time_copy;
-               u64 n_last_update_time_copy;
-
-               do {
-                       p_last_update_time_copy = prev->load_last_update_time_copy;
-                       n_last_update_time_copy = next->load_last_update_time_copy;
-
-                       smp_rmb();
-
-                       p_last_update_time = prev->avg.last_update_time;
-                       n_last_update_time = next->avg.last_update_time;
+       p_last_update_time = cfs_rq_last_update_time(prev);
+       n_last_update_time = cfs_rq_last_update_time(next);
 
-               } while (p_last_update_time != p_last_update_time_copy ||
-                        n_last_update_time != n_last_update_time_copy);
-       }
-#else
-       p_last_update_time = prev->avg.last_update_time;
-       n_last_update_time = next->avg.last_update_time;
-#endif
        __update_load_avg_blocked_se(p_last_update_time, se);
        se->avg.last_update_time = n_last_update_time;
 }
@@ -3722,6 +3749,89 @@ static inline void add_tg_cfs_propagate(struct cfs_rq *cfs_rq, long runnable_sum
 
 #endif /* CONFIG_FAIR_GROUP_SCHED */
 
+#ifdef CONFIG_NO_HZ_COMMON
+static inline void migrate_se_pelt_lag(struct sched_entity *se)
+{
+       u64 throttled = 0, now, lut;
+       struct cfs_rq *cfs_rq;
+       struct rq *rq;
+       bool is_idle;
+
+       if (load_avg_is_decayed(&se->avg))
+               return;
+
+       cfs_rq = cfs_rq_of(se);
+       rq = rq_of(cfs_rq);
+
+       rcu_read_lock();
+       is_idle = is_idle_task(rcu_dereference(rq->curr));
+       rcu_read_unlock();
+
+       /*
+        * The lag estimation comes with a cost we don't want to pay all the
+        * time. Hence, limiting to the case where the source CPU is idle and
+        * we know we are at the greatest risk to have an outdated clock.
+        */
+       if (!is_idle)
+               return;
+
+       /*
+        * Estimated "now" is: last_update_time + cfs_idle_lag + rq_idle_lag, where:
+        *
+        *   last_update_time (the cfs_rq's last_update_time)
+        *      = cfs_rq_clock_pelt()@cfs_rq_idle
+        *      = rq_clock_pelt()@cfs_rq_idle
+        *        - cfs->throttled_clock_pelt_time@cfs_rq_idle
+        *
+        *   cfs_idle_lag (delta between rq's update and cfs_rq's update)
+        *      = rq_clock_pelt()@rq_idle - rq_clock_pelt()@cfs_rq_idle
+        *
+        *   rq_idle_lag (delta between now and rq's update)
+        *      = sched_clock_cpu() - rq_clock()@rq_idle
+        *
+        * We can then write:
+        *
+        *    now = rq_clock_pelt()@rq_idle - cfs->throttled_clock_pelt_time +
+        *          sched_clock_cpu() - rq_clock()@rq_idle
+        * Where:
+        *      rq_clock_pelt()@rq_idle is rq->clock_pelt_idle
+        *      rq_clock()@rq_idle      is rq->clock_idle
+        *      cfs->throttled_clock_pelt_time@cfs_rq_idle
+        *                              is cfs_rq->throttled_pelt_idle
+        */
+
+#ifdef CONFIG_CFS_BANDWIDTH
+       throttled = u64_u32_load(cfs_rq->throttled_pelt_idle);
+       /* The clock has been stopped for throttling */
+       if (throttled == U64_MAX)
+               return;
+#endif
+       now = u64_u32_load(rq->clock_pelt_idle);
+       /*
+        * Paired with _update_idle_rq_clock_pelt(). It ensures at the worst case
+        * is observed the old clock_pelt_idle value and the new clock_idle,
+        * which lead to an underestimation. The opposite would lead to an
+        * overestimation.
+        */
+       smp_rmb();
+       lut = cfs_rq_last_update_time(cfs_rq);
+
+       now -= throttled;
+       if (now < lut)
+               /*
+                * cfs_rq->avg.last_update_time is more recent than our
+                * estimation, let's use it.
+                */
+               now = lut;
+       else
+               now += sched_clock_cpu(cpu_of(rq)) - u64_u32_load(rq->clock_idle);
+
+       __update_load_avg_blocked_se(now, se);
+}
+#else
+static void migrate_se_pelt_lag(struct sched_entity *se) {}
+#endif
+
 /**
  * update_cfs_rq_load_avg - update the cfs_rq's load/util averages
  * @now: current time, as per cfs_rq_clock_pelt()
@@ -3796,12 +3906,9 @@ update_cfs_rq_load_avg(u64 now, struct cfs_rq *cfs_rq)
        }
 
        decayed |= __update_load_avg_cfs_rq(now, cfs_rq);
-
-#ifndef CONFIG_64BIT
-       smp_wmb();
-       cfs_rq->load_last_update_time_copy = sa->last_update_time;
-#endif
-
+       u64_u32_store_copy(sa->last_update_time,
+                          cfs_rq->last_update_time_copy,
+                          sa->last_update_time);
        return decayed;
 }
 
@@ -3933,27 +4040,6 @@ static inline void update_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s
        }
 }
 
-#ifndef CONFIG_64BIT
-static inline u64 cfs_rq_last_update_time(struct cfs_rq *cfs_rq)
-{
-       u64 last_update_time_copy;
-       u64 last_update_time;
-
-       do {
-               last_update_time_copy = cfs_rq->load_last_update_time_copy;
-               smp_rmb();
-               last_update_time = cfs_rq->avg.last_update_time;
-       } while (last_update_time != last_update_time_copy);
-
-       return last_update_time;
-}
-#else
-static inline u64 cfs_rq_last_update_time(struct cfs_rq *cfs_rq)
-{
-       return cfs_rq->avg.last_update_time;
-}
-#endif
-
 /*
  * Synchronize entity load avg of dequeued entity without locking
  * the previous rq.
@@ -4368,16 +4454,11 @@ enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
                __enqueue_entity(cfs_rq, se);
        se->on_rq = 1;
 
-       /*
-        * When bandwidth control is enabled, cfs might have been removed
-        * because of a parent been throttled but cfs->nr_running > 1. Try to
-        * add it unconditionally.
-        */
-       if (cfs_rq->nr_running == 1 || cfs_bandwidth_used())
-               list_add_leaf_cfs_rq(cfs_rq);
-
-       if (cfs_rq->nr_running == 1)
+       if (cfs_rq->nr_running == 1) {
                check_enqueue_throttle(cfs_rq);
+               if (!throttled_hierarchy(cfs_rq))
+                       list_add_leaf_cfs_rq(cfs_rq);
+       }
 }
 
 static void __clear_buddies_last(struct sched_entity *se)
@@ -4477,6 +4558,9 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
         */
        if ((flags & (DEQUEUE_SAVE | DEQUEUE_MOVE)) != DEQUEUE_SAVE)
                update_min_vruntime(cfs_rq);
+
+       if (cfs_rq->nr_running == 0)
+               update_idle_cfs_rq_clock_pelt(cfs_rq);
 }
 
 /*
@@ -4992,11 +5076,18 @@ void unthrottle_cfs_rq(struct cfs_rq *cfs_rq)
        /* update hierarchical throttle state */
        walk_tg_tree_from(cfs_rq->tg, tg_nop, tg_unthrottle_up, (void *)rq);
 
-       /* Nothing to run but something to decay (on_list)? Complete the branch */
        if (!cfs_rq->load.weight) {
-               if (cfs_rq->on_list)
-                       goto unthrottle_throttle;
-               return;
+               if (!cfs_rq->on_list)
+                       return;
+               /*
+                * Nothing to run but something to decay (on_list)?
+                * Complete the branch.
+                */
+               for_each_sched_entity(se) {
+                       if (list_add_leaf_cfs_rq(cfs_rq_of(se)))
+                               break;
+               }
+               goto unthrottle_throttle;
        }
 
        task_delta = cfs_rq->h_nr_running;
@@ -5034,31 +5125,12 @@ void unthrottle_cfs_rq(struct cfs_rq *cfs_rq)
                /* end evaluation on encountering a throttled cfs_rq */
                if (cfs_rq_throttled(qcfs_rq))
                        goto unthrottle_throttle;
-
-               /*
-                * One parent has been throttled and cfs_rq removed from the
-                * list. Add it back to not break the leaf list.
-                */
-               if (throttled_hierarchy(qcfs_rq))
-                       list_add_leaf_cfs_rq(qcfs_rq);
        }
 
        /* At this point se is NULL and we are at root level*/
        add_nr_running(rq, task_delta);
 
 unthrottle_throttle:
-       /*
-        * The cfs_rq_throttled() breaks in the above iteration can result in
-        * incomplete leaf list maintenance, resulting in triggering the
-        * assertion below.
-        */
-       for_each_sched_entity(se) {
-               struct cfs_rq *qcfs_rq = cfs_rq_of(se);
-
-               if (list_add_leaf_cfs_rq(qcfs_rq))
-                       break;
-       }
-
        assert_list_leaf_cfs_rq(rq);
 
        /* Determine whether we need to wake up potentially idle CPU: */
@@ -5713,13 +5785,6 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
                /* end evaluation on encountering a throttled cfs_rq */
                if (cfs_rq_throttled(cfs_rq))
                        goto enqueue_throttle;
-
-               /*
-                * One parent has been throttled and cfs_rq removed from the
-                * list. Add it back to not break the leaf list.
-                */
-               if (throttled_hierarchy(cfs_rq))
-                       list_add_leaf_cfs_rq(cfs_rq);
        }
 
        /* At this point se is NULL and we are at root level*/
@@ -5743,21 +5808,6 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
                update_overutilized_status(rq);
 
 enqueue_throttle:
-       if (cfs_bandwidth_used()) {
-               /*
-                * When bandwidth control is enabled; the cfs_rq_throttled()
-                * breaks in the above iteration can result in incomplete
-                * leaf list maintenance, resulting in triggering the assertion
-                * below.
-                */
-               for_each_sched_entity(se) {
-                       cfs_rq = cfs_rq_of(se);
-
-                       if (list_add_leaf_cfs_rq(cfs_rq))
-                               break;
-               }
-       }
-
        assert_list_leaf_cfs_rq(rq);
 
        hrtick_update(rq);
@@ -5844,7 +5894,7 @@ dequeue_throttle:
 
 /* Working cpumask for: load_balance, load_balance_newidle. */
 DEFINE_PER_CPU(cpumask_var_t, load_balance_mask);
-DEFINE_PER_CPU(cpumask_var_t, select_idle_mask);
+DEFINE_PER_CPU(cpumask_var_t, select_rq_mask);
 
 #ifdef CONFIG_NO_HZ_COMMON
 
@@ -6334,8 +6384,9 @@ static inline int select_idle_smt(struct task_struct *p, struct sched_domain *sd
  */
 static int select_idle_cpu(struct task_struct *p, struct sched_domain *sd, bool has_idle_core, int target)
 {
-       struct cpumask *cpus = this_cpu_cpumask_var_ptr(select_idle_mask);
+       struct cpumask *cpus = this_cpu_cpumask_var_ptr(select_rq_mask);
        int i, cpu, idle_cpu = -1, nr = INT_MAX;
+       struct sched_domain_shared *sd_share;
        struct rq *this_rq = this_rq();
        int this = smp_processor_id();
        struct sched_domain *this_sd;
@@ -6375,6 +6426,17 @@ static int select_idle_cpu(struct task_struct *p, struct sched_domain *sd, bool
                time = cpu_clock(this);
        }
 
+       if (sched_feat(SIS_UTIL)) {
+               sd_share = rcu_dereference(per_cpu(sd_llc_shared, target));
+               if (sd_share) {
+                       /* because !--nr is the condition to stop scan */
+                       nr = READ_ONCE(sd_share->nr_idle_scan) + 1;
+                       /* overloaded LLC is unlikely to have idle cpu/core */
+                       if (nr == 1)
+                               return -1;
+               }
+       }
+
        for_each_cpu_wrap(cpu, cpus, target + 1) {
                if (has_idle_core) {
                        i = select_idle_core(p, cpu, cpus, &idle_cpu);
@@ -6420,7 +6482,7 @@ select_idle_capacity(struct task_struct *p, struct sched_domain *sd, int target)
        int cpu, best_cpu = -1;
        struct cpumask *cpus;
 
-       cpus = this_cpu_cpumask_var_ptr(select_idle_mask);
+       cpus = this_cpu_cpumask_var_ptr(select_rq_mask);
        cpumask_and(cpus, sched_domain_span(sd), p->cpus_ptr);
 
        task_util = uclamp_task_util(p);
@@ -6470,7 +6532,7 @@ static int select_idle_sibling(struct task_struct *p, int prev, int target)
        }
 
        /*
-        * per-cpu select_idle_mask usage
+        * per-cpu select_rq_mask usage
         */
        lockdep_assert_irqs_disabled();
 
@@ -6640,62 +6702,96 @@ static unsigned long cpu_util_without(int cpu, struct task_struct *p)
 }
 
 /*
- * compute_energy(): Estimates the energy that @pd would consume if @p was
- * migrated to @dst_cpu. compute_energy() predicts what will be the utilization
- * landscape of @pd's CPUs after the task migration, and uses the Energy Model
- * to compute what would be the energy if we decided to actually migrate that
- * task.
+ * energy_env - Utilization landscape for energy estimation.
+ * @task_busy_time: Utilization contribution by the task for which we test the
+ *                  placement. Given by eenv_task_busy_time().
+ * @pd_busy_time:   Utilization of the whole perf domain without the task
+ *                  contribution. Given by eenv_pd_busy_time().
+ * @cpu_cap:        Maximum CPU capacity for the perf domain.
+ * @pd_cap:         Entire perf domain capacity. (pd->nr_cpus * cpu_cap).
+ */
+struct energy_env {
+       unsigned long task_busy_time;
+       unsigned long pd_busy_time;
+       unsigned long cpu_cap;
+       unsigned long pd_cap;
+};
+
+/*
+ * Compute the task busy time for compute_energy(). This time cannot be
+ * injected directly into effective_cpu_util() because of the IRQ scaling.
+ * The latter only makes sense with the most recent CPUs where the task has
+ * run.
+ */
+static inline void eenv_task_busy_time(struct energy_env *eenv,
+                                      struct task_struct *p, int prev_cpu)
+{
+       unsigned long busy_time, max_cap = arch_scale_cpu_capacity(prev_cpu);
+       unsigned long irq = cpu_util_irq(cpu_rq(prev_cpu));
+
+       if (unlikely(irq >= max_cap))
+               busy_time = max_cap;
+       else
+               busy_time = scale_irq_capacity(task_util_est(p), irq, max_cap);
+
+       eenv->task_busy_time = busy_time;
+}
+
+/*
+ * Compute the perf_domain (PD) busy time for compute_energy(). Based on the
+ * utilization for each @pd_cpus, it however doesn't take into account
+ * clamping since the ratio (utilization / cpu_capacity) is already enough to
+ * scale the EM reported power consumption at the (eventually clamped)
+ * cpu_capacity.
+ *
+ * The contribution of the task @p for which we want to estimate the
+ * energy cost is removed (by cpu_util_next()) and must be calculated
+ * separately (see eenv_task_busy_time). This ensures:
+ *
+ *   - A stable PD utilization, no matter which CPU of that PD we want to place
+ *     the task on.
+ *
+ *   - A fair comparison between CPUs as the task contribution (task_util())
+ *     will always be the same no matter which CPU utilization we rely on
+ *     (util_avg or util_est).
+ *
+ * Set @eenv busy time for the PD that spans @pd_cpus. This busy time can't
+ * exceed @eenv->pd_cap.
  */
-static long
-compute_energy(struct task_struct *p, int dst_cpu, struct perf_domain *pd)
+static inline void eenv_pd_busy_time(struct energy_env *eenv,
+                                    struct cpumask *pd_cpus,
+                                    struct task_struct *p)
 {
-       struct cpumask *pd_mask = perf_domain_span(pd);
-       unsigned long cpu_cap = arch_scale_cpu_capacity(cpumask_first(pd_mask));
-       unsigned long max_util = 0, sum_util = 0;
-       unsigned long _cpu_cap = cpu_cap;
+       unsigned long busy_time = 0;
        int cpu;
 
-       _cpu_cap -= arch_scale_thermal_pressure(cpumask_first(pd_mask));
+       for_each_cpu(cpu, pd_cpus) {
+               unsigned long util = cpu_util_next(cpu, p, -1);
 
-       /*
-        * The capacity state of CPUs of the current rd can be driven by CPUs
-        * of another rd if they belong to the same pd. So, account for the
-        * utilization of these CPUs too by masking pd with cpu_online_mask
-        * instead of the rd span.
-        *
-        * If an entire pd is outside of the current rd, it will not appear in
-        * its pd list and will not be accounted by compute_energy().
-        */
-       for_each_cpu_and(cpu, pd_mask, cpu_online_mask) {
-               unsigned long util_freq = cpu_util_next(cpu, p, dst_cpu);
-               unsigned long cpu_util, util_running = util_freq;
-               struct task_struct *tsk = NULL;
+               busy_time += effective_cpu_util(cpu, util, ENERGY_UTIL, NULL);
+       }
 
-               /*
-                * When @p is placed on @cpu:
-                *
-                * util_running = max(cpu_util, cpu_util_est) +
-                *                max(task_util, _task_util_est)
-                *
-                * while cpu_util_next is: max(cpu_util + task_util,
-                *                             cpu_util_est + _task_util_est)
-                */
-               if (cpu == dst_cpu) {
-                       tsk = p;
-                       util_running =
-                               cpu_util_next(cpu, p, -1) + task_util_est(p);
-               }
+       eenv->pd_busy_time = min(eenv->pd_cap, busy_time);
+}
 
-               /*
-                * Busy time computation: utilization clamping is not
-                * required since the ratio (sum_util / cpu_capacity)
-                * is already enough to scale the EM reported power
-                * consumption at the (eventually clamped) cpu_capacity.
-                */
-               cpu_util = effective_cpu_util(cpu, util_running, cpu_cap,
-                                             ENERGY_UTIL, NULL);
+/*
+ * Compute the maximum utilization for compute_energy() when the task @p
+ * is placed on the cpu @dst_cpu.
+ *
+ * Returns the maximum utilization among @eenv->cpus. This utilization can't
+ * exceed @eenv->cpu_cap.
+ */
+static inline unsigned long
+eenv_pd_max_util(struct energy_env *eenv, struct cpumask *pd_cpus,
+                struct task_struct *p, int dst_cpu)
+{
+       unsigned long max_util = 0;
+       int cpu;
 
-               sum_util += min(cpu_util, _cpu_cap);
+       for_each_cpu(cpu, pd_cpus) {
+               struct task_struct *tsk = (cpu == dst_cpu) ? p : NULL;
+               unsigned long util = cpu_util_next(cpu, p, dst_cpu);
+               unsigned long cpu_util;
 
                /*
                 * Performance domain frequency: utilization clamping
@@ -6704,12 +6800,29 @@ compute_energy(struct task_struct *p, int dst_cpu, struct perf_domain *pd)
                 * NOTE: in case RT tasks are running, by default the
                 * FREQUENCY_UTIL's utilization can be max OPP.
                 */
-               cpu_util = effective_cpu_util(cpu, util_freq, cpu_cap,
-                                             FREQUENCY_UTIL, tsk);
-               max_util = max(max_util, min(cpu_util, _cpu_cap));
+               cpu_util = effective_cpu_util(cpu, util, FREQUENCY_UTIL, tsk);
+               max_util = max(max_util, cpu_util);
        }
 
-       return em_cpu_energy(pd->em_pd, max_util, sum_util, _cpu_cap);
+       return min(max_util, eenv->cpu_cap);
+}
+
+/*
+ * compute_energy(): Use the Energy Model to estimate the energy that @pd would
+ * consume for a given utilization landscape @eenv. When @dst_cpu < 0, the task
+ * contribution is ignored.
+ */
+static inline unsigned long
+compute_energy(struct energy_env *eenv, struct perf_domain *pd,
+              struct cpumask *pd_cpus, struct task_struct *p, int dst_cpu)
+{
+       unsigned long max_util = eenv_pd_max_util(eenv, pd_cpus, p, dst_cpu);
+       unsigned long busy_time = eenv->pd_busy_time;
+
+       if (dst_cpu >= 0)
+               busy_time = min(eenv->pd_cap, busy_time + eenv->task_busy_time);
+
+       return em_cpu_energy(pd->em_pd, max_util, busy_time, eenv->cpu_cap);
 }
 
 /*
@@ -6753,12 +6866,13 @@ compute_energy(struct task_struct *p, int dst_cpu, struct perf_domain *pd)
  */
 static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu)
 {
+       struct cpumask *cpus = this_cpu_cpumask_var_ptr(select_rq_mask);
        unsigned long prev_delta = ULONG_MAX, best_delta = ULONG_MAX;
-       struct root_domain *rd = cpu_rq(smp_processor_id())->rd;
-       int cpu, best_energy_cpu = prev_cpu, target = -1;
-       unsigned long cpu_cap, util, base_energy = 0;
+       struct root_domain *rd = this_rq()->rd;
+       int cpu, best_energy_cpu, target = -1;
        struct sched_domain *sd;
        struct perf_domain *pd;
+       struct energy_env eenv;
 
        rcu_read_lock();
        pd = rcu_dereference(rd->pd);
@@ -6781,20 +6895,39 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu)
        if (!task_util_est(p))
                goto unlock;
 
+       eenv_task_busy_time(&eenv, p, prev_cpu);
+
        for (; pd; pd = pd->next) {
-               unsigned long cur_delta, spare_cap, max_spare_cap = 0;
+               unsigned long cpu_cap, cpu_thermal_cap, util;
+               unsigned long cur_delta, max_spare_cap = 0;
                bool compute_prev_delta = false;
-               unsigned long base_energy_pd;
                int max_spare_cap_cpu = -1;
+               unsigned long base_energy;
+
+               cpumask_and(cpus, perf_domain_span(pd), cpu_online_mask);
+
+               if (cpumask_empty(cpus))
+                       continue;
+
+               /* Account thermal pressure for the energy estimation */
+               cpu = cpumask_first(cpus);
+               cpu_thermal_cap = arch_scale_cpu_capacity(cpu);
+               cpu_thermal_cap -= arch_scale_thermal_pressure(cpu);
+
+               eenv.cpu_cap = cpu_thermal_cap;
+               eenv.pd_cap = 0;
+
+               for_each_cpu(cpu, cpus) {
+                       eenv.pd_cap += cpu_thermal_cap;
+
+                       if (!cpumask_test_cpu(cpu, sched_domain_span(sd)))
+                               continue;
 
-               for_each_cpu_and(cpu, perf_domain_span(pd), sched_domain_span(sd)) {
                        if (!cpumask_test_cpu(cpu, p->cpus_ptr))
                                continue;
 
                        util = cpu_util_next(cpu, p, cpu);
                        cpu_cap = capacity_of(cpu);
-                       spare_cap = cpu_cap;
-                       lsub_positive(&spare_cap, util);
 
                        /*
                         * Skip CPUs that cannot satisfy the capacity request.
@@ -6807,15 +6940,17 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu)
                        if (!fits_capacity(util, cpu_cap))
                                continue;
 
+                       lsub_positive(&cpu_cap, util);
+
                        if (cpu == prev_cpu) {
                                /* Always use prev_cpu as a candidate. */
                                compute_prev_delta = true;
-                       } else if (spare_cap > max_spare_cap) {
+                       } else if (cpu_cap > max_spare_cap) {
                                /*
                                 * Find the CPU with the maximum spare capacity
                                 * in the performance domain.
                                 */
-                               max_spare_cap = spare_cap;
+                               max_spare_cap = cpu_cap;
                                max_spare_cap_cpu = cpu;
                        }
                }
@@ -6823,25 +6958,29 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu)
                if (max_spare_cap_cpu < 0 && !compute_prev_delta)
                        continue;
 
+               eenv_pd_busy_time(&eenv, cpus, p);
                /* Compute the 'base' energy of the pd, without @p */
-               base_energy_pd = compute_energy(p, -1, pd);
-               base_energy += base_energy_pd;
+               base_energy = compute_energy(&eenv, pd, cpus, p, -1);
 
                /* Evaluate the energy impact of using prev_cpu. */
                if (compute_prev_delta) {
-                       prev_delta = compute_energy(p, prev_cpu, pd);
-                       if (prev_delta < base_energy_pd)
+                       prev_delta = compute_energy(&eenv, pd, cpus, p,
+                                                   prev_cpu);
+                       /* CPU utilization has changed */
+                       if (prev_delta < base_energy)
                                goto unlock;
-                       prev_delta -= base_energy_pd;
+                       prev_delta -= base_energy;
                        best_delta = min(best_delta, prev_delta);
                }
 
                /* Evaluate the energy impact of using max_spare_cap_cpu. */
                if (max_spare_cap_cpu >= 0) {
-                       cur_delta = compute_energy(p, max_spare_cap_cpu, pd);
-                       if (cur_delta < base_energy_pd)
+                       cur_delta = compute_energy(&eenv, pd, cpus, p,
+                                                  max_spare_cap_cpu);
+                       /* CPU utilization has changed */
+                       if (cur_delta < base_energy)
                                goto unlock;
-                       cur_delta -= base_energy_pd;
+                       cur_delta -= base_energy;
                        if (cur_delta < best_delta) {
                                best_delta = cur_delta;
                                best_energy_cpu = max_spare_cap_cpu;
@@ -6850,12 +6989,7 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu)
        }
        rcu_read_unlock();
 
-       /*
-        * Pick the best CPU if prev_cpu cannot be used, or if it saves at
-        * least 6% of the energy used by prev_cpu.
-        */
-       if ((prev_delta == ULONG_MAX) ||
-           (prev_delta - best_delta) > ((prev_delta + base_energy) >> 4))
+       if (best_delta < prev_delta)
                target = best_energy_cpu;
 
        return target;
@@ -6951,6 +7085,8 @@ static void detach_entity_cfs_rq(struct sched_entity *se);
  */
 static void migrate_task_rq_fair(struct task_struct *p, int new_cpu)
 {
+       struct sched_entity *se = &p->se;
+
        /*
         * As blocked tasks retain absolute vruntime the migration needs to
         * deal with this by subtracting the old and adding the new
@@ -6958,23 +7094,9 @@ static void migrate_task_rq_fair(struct task_struct *p, int new_cpu)
         * the task on the new runqueue.
         */
        if (READ_ONCE(p->__state) == TASK_WAKING) {
-               struct sched_entity *se = &p->se;
                struct cfs_rq *cfs_rq = cfs_rq_of(se);
-               u64 min_vruntime;
-
-#ifndef CONFIG_64BIT
-               u64 min_vruntime_copy;
-
-               do {
-                       min_vruntime_copy = cfs_rq->min_vruntime_copy;
-                       smp_rmb();
-                       min_vruntime = cfs_rq->min_vruntime;
-               } while (min_vruntime != min_vruntime_copy);
-#else
-               min_vruntime = cfs_rq->min_vruntime;
-#endif
 
-               se->vruntime -= min_vruntime;
+               se->vruntime -= u64_u32_load(cfs_rq->min_vruntime);
        }
 
        if (p->on_rq == TASK_ON_RQ_MIGRATING) {
@@ -6983,25 +7105,29 @@ static void migrate_task_rq_fair(struct task_struct *p, int new_cpu)
                 * rq->lock and can modify state directly.
                 */
                lockdep_assert_rq_held(task_rq(p));
-               detach_entity_cfs_rq(&p->se);
+               detach_entity_cfs_rq(se);
 
        } else {
+               remove_entity_load_avg(se);
+
                /*
-                * We are supposed to update the task to "current" time, then
-                * its up to date and ready to go to new CPU/cfs_rq. But we
-                * have difficulty in getting what current time is, so simply
-                * throw away the out-of-date time. This will result in the
-                * wakee task is less decayed, but giving the wakee more load
-                * sounds not bad.
+                * Here, the task's PELT values have been updated according to
+                * the current rq's clock. But if that clock hasn't been
+                * updated in a while, a substantial idle time will be missed,
+                * leading to an inflation after wake-up on the new rq.
+                *
+                * Estimate the missing time from the cfs_rq last_update_time
+                * and update sched_avg to improve the PELT continuity after
+                * migration.
                 */
-               remove_entity_load_avg(&p->se);
+               migrate_se_pelt_lag(se);
        }
 
        /* Tell new CPU we are migrated */
-       p->se.avg.last_update_time = 0;
+       se->avg.last_update_time = 0;
 
        /* We have migrated, no longer consider this task hot */
-       p->se.exec_start = 0;
+       se->exec_start = 0;
 
        update_scan_period(p, new_cpu);
 }
@@ -7585,8 +7711,8 @@ enum group_type {
         */
        group_fully_busy,
        /*
-        * SD_ASYM_CPUCAPACITY only: One task doesn't fit with CPU's capacity
-        * and must be migrated to a more powerful CPU.
+        * One task doesn't fit with CPU's capacity and must be migrated to a
+        * more powerful CPU.
         */
        group_misfit_task,
        /*
@@ -8167,6 +8293,9 @@ static bool __update_blocked_fair(struct rq *rq, bool *done)
                if (update_cfs_rq_load_avg(cfs_rq_clock_pelt(cfs_rq), cfs_rq)) {
                        update_tg_load_avg(cfs_rq);
 
+                       if (cfs_rq->nr_running == 0)
+                               update_idle_cfs_rq_clock_pelt(cfs_rq);
+
                        if (cfs_rq == &rq->cfs)
                                decayed = true;
                }
@@ -8500,7 +8629,7 @@ static inline int sg_imbalanced(struct sched_group *group)
 /*
  * group_has_capacity returns true if the group has spare capacity that could
  * be used by some tasks.
- * We consider that a group has spare capacity if the  * number of task is
+ * We consider that a group has spare capacity if the number of task is
  * smaller than the number of CPUs or if the utilization is lower than the
  * available capacity for CFS tasks.
  * For the latter, we use a threshold to stabilize the state, to take into
@@ -8669,6 +8798,19 @@ sched_asym(struct lb_env *env, struct sd_lb_stats *sds,  struct sg_lb_stats *sgs
        return sched_asym_prefer(env->dst_cpu, group->asym_prefer_cpu);
 }
 
+static inline bool
+sched_reduced_capacity(struct rq *rq, struct sched_domain *sd)
+{
+       /*
+        * When there is more than 1 task, the group_overloaded case already
+        * takes care of cpu with reduced capacity
+        */
+       if (rq->cfs.h_nr_running != 1)
+               return false;
+
+       return check_cpu_capacity(rq, sd);
+}
+
 /**
  * update_sg_lb_stats - Update sched_group's statistics for load balancing.
  * @env: The load balancing environment.
@@ -8691,8 +8833,9 @@ static inline void update_sg_lb_stats(struct lb_env *env,
 
        for_each_cpu_and(i, sched_group_span(group), env->cpus) {
                struct rq *rq = cpu_rq(i);
+               unsigned long load = cpu_load(rq);
 
-               sgs->group_load += cpu_load(rq);
+               sgs->group_load += load;
                sgs->group_util += cpu_util_cfs(i);
                sgs->group_runnable += cpu_runnable(rq);
                sgs->sum_h_nr_running += rq->cfs.h_nr_running;
@@ -8722,11 +8865,17 @@ static inline void update_sg_lb_stats(struct lb_env *env,
                if (local_group)
                        continue;
 
-               /* Check for a misfit task on the cpu */
-               if (env->sd->flags & SD_ASYM_CPUCAPACITY &&
-                   sgs->group_misfit_task_load < rq->misfit_task_load) {
-                       sgs->group_misfit_task_load = rq->misfit_task_load;
-                       *sg_status |= SG_OVERLOAD;
+               if (env->sd->flags & SD_ASYM_CPUCAPACITY) {
+                       /* Check for a misfit task on the cpu */
+                       if (sgs->group_misfit_task_load < rq->misfit_task_load) {
+                               sgs->group_misfit_task_load = rq->misfit_task_load;
+                               *sg_status |= SG_OVERLOAD;
+                       }
+               } else if ((env->idle != CPU_NOT_IDLE) &&
+                          sched_reduced_capacity(rq, env->sd)) {
+                       /* Check for a task running on a CPU with reduced capacity */
+                       if (sgs->group_misfit_task_load < load)
+                               sgs->group_misfit_task_load = load;
                }
        }
 
@@ -8779,7 +8928,8 @@ static bool update_sd_pick_busiest(struct lb_env *env,
         * CPUs in the group should either be possible to resolve
         * internally or be covered by avg_load imbalance (eventually).
         */
-       if (sgs->group_type == group_misfit_task &&
+       if ((env->sd->flags & SD_ASYM_CPUCAPACITY) &&
+           (sgs->group_type == group_misfit_task) &&
            (!capacity_greater(capacity_of(env->dst_cpu), sg->sgc->max_capacity) ||
             sds->local_stat.group_type != group_has_spare))
                return false;
@@ -9058,16 +9208,6 @@ static bool update_pick_idlest(struct sched_group *idlest,
 }
 
 /*
- * Allow a NUMA imbalance if busy CPUs is less than 25% of the domain.
- * This is an approximation as the number of running tasks may not be
- * related to the number of busy CPUs due to sched_setaffinity.
- */
-static inline bool allow_numa_imbalance(int running, int imb_numa_nr)
-{
-       return running <= imb_numa_nr;
-}
-
-/*
  * find_idlest_group() finds and returns the least busy CPU group within the
  * domain.
  *
@@ -9183,7 +9323,9 @@ find_idlest_group(struct sched_domain *sd, struct task_struct *p, int this_cpu)
                break;
 
        case group_has_spare:
+#ifdef CONFIG_NUMA
                if (sd->flags & SD_NUMA) {
+                       int imb_numa_nr = sd->imb_numa_nr;
 #ifdef CONFIG_NUMA_BALANCING
                        int idlest_cpu;
                        /*
@@ -9196,17 +9338,31 @@ find_idlest_group(struct sched_domain *sd, struct task_struct *p, int this_cpu)
                        idlest_cpu = cpumask_first(sched_group_span(idlest));
                        if (cpu_to_node(idlest_cpu) == p->numa_preferred_nid)
                                return idlest;
-#endif
+#endif /* CONFIG_NUMA_BALANCING */
                        /*
                         * Otherwise, keep the task close to the wakeup source
                         * and improve locality if the number of running tasks
                         * would remain below threshold where an imbalance is
-                        * allowed. If there is a real need of migration,
-                        * periodic load balance will take care of it.
+                        * allowed while accounting for the possibility the
+                        * task is pinned to a subset of CPUs. If there is a
+                        * real need of migration, periodic load balance will
+                        * take care of it.
                         */
-                       if (allow_numa_imbalance(local_sgs.sum_nr_running + 1, sd->imb_numa_nr))
+                       if (p->nr_cpus_allowed != NR_CPUS) {
+                               struct cpumask *cpus = this_cpu_cpumask_var_ptr(select_rq_mask);
+
+                               cpumask_and(cpus, sched_group_span(local), p->cpus_ptr);
+                               imb_numa_nr = min(cpumask_weight(cpus), sd->imb_numa_nr);
+                       }
+
+                       imbalance = abs(local_sgs.idle_cpus - idlest_sgs.idle_cpus);
+                       if (!adjust_numa_imbalance(imbalance,
+                                                  local_sgs.sum_nr_running + 1,
+                                                  imb_numa_nr)) {
                                return NULL;
+                       }
                }
+#endif /* CONFIG_NUMA */
 
                /*
                 * Select group with highest number of idle CPUs. We could also
@@ -9222,6 +9378,77 @@ find_idlest_group(struct sched_domain *sd, struct task_struct *p, int this_cpu)
        return idlest;
 }
 
+static void update_idle_cpu_scan(struct lb_env *env,
+                                unsigned long sum_util)
+{
+       struct sched_domain_shared *sd_share;
+       int llc_weight, pct;
+       u64 x, y, tmp;
+       /*
+        * Update the number of CPUs to scan in LLC domain, which could
+        * be used as a hint in select_idle_cpu(). The update of sd_share
+        * could be expensive because it is within a shared cache line.
+        * So the write of this hint only occurs during periodic load
+        * balancing, rather than CPU_NEWLY_IDLE, because the latter
+        * can fire way more frequently than the former.
+        */
+       if (!sched_feat(SIS_UTIL) || env->idle == CPU_NEWLY_IDLE)
+               return;
+
+       llc_weight = per_cpu(sd_llc_size, env->dst_cpu);
+       if (env->sd->span_weight != llc_weight)
+               return;
+
+       sd_share = rcu_dereference(per_cpu(sd_llc_shared, env->dst_cpu));
+       if (!sd_share)
+               return;
+
+       /*
+        * The number of CPUs to search drops as sum_util increases, when
+        * sum_util hits 85% or above, the scan stops.
+        * The reason to choose 85% as the threshold is because this is the
+        * imbalance_pct(117) when a LLC sched group is overloaded.
+        *
+        * let y = SCHED_CAPACITY_SCALE - p * x^2                       [1]
+        * and y'= y / SCHED_CAPACITY_SCALE
+        *
+        * x is the ratio of sum_util compared to the CPU capacity:
+        * x = sum_util / (llc_weight * SCHED_CAPACITY_SCALE)
+        * y' is the ratio of CPUs to be scanned in the LLC domain,
+        * and the number of CPUs to scan is calculated by:
+        *
+        * nr_scan = llc_weight * y'                                    [2]
+        *
+        * When x hits the threshold of overloaded, AKA, when
+        * x = 100 / pct, y drops to 0. According to [1],
+        * p should be SCHED_CAPACITY_SCALE * pct^2 / 10000
+        *
+        * Scale x by SCHED_CAPACITY_SCALE:
+        * x' = sum_util / llc_weight;                                  [3]
+        *
+        * and finally [1] becomes:
+        * y = SCHED_CAPACITY_SCALE -
+        *     x'^2 * pct^2 / (10000 * SCHED_CAPACITY_SCALE)            [4]
+        *
+        */
+       /* equation [3] */
+       x = sum_util;
+       do_div(x, llc_weight);
+
+       /* equation [4] */
+       pct = env->sd->imbalance_pct;
+       tmp = x * x * pct * pct;
+       do_div(tmp, 10000 * SCHED_CAPACITY_SCALE);
+       tmp = min_t(long, tmp, SCHED_CAPACITY_SCALE);
+       y = SCHED_CAPACITY_SCALE - tmp;
+
+       /* equation [2] */
+       y *= llc_weight;
+       do_div(y, SCHED_CAPACITY_SCALE);
+       if ((int)y != sd_share->nr_idle_scan)
+               WRITE_ONCE(sd_share->nr_idle_scan, (int)y);
+}
+
 /**
  * update_sd_lb_stats - Update sched_domain's statistics for load balancing.
  * @env: The load balancing environment.
@@ -9234,6 +9461,7 @@ static inline void update_sd_lb_stats(struct lb_env *env, struct sd_lb_stats *sd
        struct sched_group *sg = env->sd->groups;
        struct sg_lb_stats *local = &sds->local_stat;
        struct sg_lb_stats tmp_sgs;
+       unsigned long sum_util = 0;
        int sg_status = 0;
 
        do {
@@ -9266,6 +9494,7 @@ next_group:
                sds->total_load += sgs->group_load;
                sds->total_capacity += sgs->group_capacity;
 
+               sum_util += sgs->group_util;
                sg = sg->next;
        } while (sg != env->sd->groups);
 
@@ -9291,24 +9520,8 @@ next_group:
                WRITE_ONCE(rd->overutilized, SG_OVERUTILIZED);
                trace_sched_overutilized_tp(rd, SG_OVERUTILIZED);
        }
-}
-
-#define NUMA_IMBALANCE_MIN 2
-
-static inline long adjust_numa_imbalance(int imbalance,
-                               int dst_running, int imb_numa_nr)
-{
-       if (!allow_numa_imbalance(dst_running, imb_numa_nr))
-               return imbalance;
 
-       /*
-        * Allow a small imbalance based on a simple pair of communicating
-        * tasks that remain local when the destination is lightly loaded.
-        */
-       if (imbalance <= NUMA_IMBALANCE_MIN)
-               return 0;
-
-       return imbalance;
+       update_idle_cpu_scan(env, sum_util);
 }
 
 /**
@@ -9325,9 +9538,18 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s
        busiest = &sds->busiest_stat;
 
        if (busiest->group_type == group_misfit_task) {
-               /* Set imbalance to allow misfit tasks to be balanced. */
-               env->migration_type = migrate_misfit;
-               env->imbalance = 1;
+               if (env->sd->flags & SD_ASYM_CPUCAPACITY) {
+                       /* Set imbalance to allow misfit tasks to be balanced. */
+                       env->migration_type = migrate_misfit;
+                       env->imbalance = 1;
+               } else {
+                       /*
+                        * Set load imbalance to allow moving task from cpu
+                        * with reduced capacity.
+                        */
+                       env->migration_type = migrate_load;
+                       env->imbalance = busiest->group_misfit_task_load;
+               }
                return;
        }
 
@@ -9395,7 +9617,7 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s
                         */
                        env->migration_type = migrate_task;
                        lsub_positive(&nr_diff, local->sum_nr_running);
-                       env->imbalance = nr_diff >> 1;
+                       env->imbalance = nr_diff;
                } else {
 
                        /*
@@ -9403,15 +9625,21 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s
                         * idle cpus.
                         */
                        env->migration_type = migrate_task;
-                       env->imbalance = max_t(long, 0, (local->idle_cpus -
-                                                busiest->idle_cpus) >> 1);
+                       env->imbalance = max_t(long, 0,
+                                              (local->idle_cpus - busiest->idle_cpus));
                }
 
+#ifdef CONFIG_NUMA
                /* Consider allowing a small imbalance between NUMA groups */
                if (env->sd->flags & SD_NUMA) {
                        env->imbalance = adjust_numa_imbalance(env->imbalance,
-                               local->sum_nr_running + 1, env->sd->imb_numa_nr);
+                                                              local->sum_nr_running + 1,
+                                                              env->sd->imb_numa_nr);
                }
+#endif
+
+               /* Number of tasks to move to restore balance */
+               env->imbalance >>= 1;
 
                return;
        }
@@ -9834,9 +10062,15 @@ static int should_we_balance(struct lb_env *env)
        /*
         * In the newly idle case, we will allow all the CPUs
         * to do the newly idle load balance.
+        *
+        * However, we bail out if we already have tasks or a wakeup pending,
+        * to optimize wakeup latency.
         */
-       if (env->idle == CPU_NEWLY_IDLE)
+       if (env->idle == CPU_NEWLY_IDLE) {
+               if (env->dst_rq->nr_running > 0 || env->dst_rq->ttwu_pending)
+                       return 0;
                return 1;
+       }
 
        /* Try to find first idle CPU */
        for_each_cpu_and(cpu, group_balance_mask(sg), env->cpus) {
@@ -11287,9 +11521,13 @@ static inline bool vruntime_normalized(struct task_struct *p)
  */
 static void propagate_entity_cfs_rq(struct sched_entity *se)
 {
-       struct cfs_rq *cfs_rq;
+       struct cfs_rq *cfs_rq = cfs_rq_of(se);
 
-       list_add_leaf_cfs_rq(cfs_rq_of(se));
+       if (cfs_rq_throttled(cfs_rq))
+               return;
+
+       if (!throttled_hierarchy(cfs_rq))
+               list_add_leaf_cfs_rq(cfs_rq);
 
        /* Start to propagate at parent */
        se = se->parent;
@@ -11297,14 +11535,13 @@ static void propagate_entity_cfs_rq(struct sched_entity *se)
        for_each_sched_entity(se) {
                cfs_rq = cfs_rq_of(se);
 
-               if (!cfs_rq_throttled(cfs_rq)){
-                       update_load_avg(cfs_rq, se, UPDATE_TG);
-                       list_add_leaf_cfs_rq(cfs_rq);
-                       continue;
-               }
+               update_load_avg(cfs_rq, se, UPDATE_TG);
 
-               if (list_add_leaf_cfs_rq(cfs_rq))
+               if (cfs_rq_throttled(cfs_rq))
                        break;
+
+               if (!throttled_hierarchy(cfs_rq))
+                       list_add_leaf_cfs_rq(cfs_rq);
        }
 }
 #else
@@ -11422,10 +11659,7 @@ static void set_next_task_fair(struct rq *rq, struct task_struct *p, bool first)
 void init_cfs_rq(struct cfs_rq *cfs_rq)
 {
        cfs_rq->tasks_timeline = RB_ROOT_CACHED;
-       cfs_rq->min_vruntime = (u64)(-(1LL << 20));
-#ifndef CONFIG_64BIT
-       cfs_rq->min_vruntime_copy = cfs_rq->min_vruntime;
-#endif
+       u64_u32_store(cfs_rq->min_vruntime, (u64)(-(1LL << 20)));
 #ifdef CONFIG_SMP
        raw_spin_lock_init(&cfs_rq->removed.lock);
 #endif
index 1cf435b..ee7f23c 100644 (file)
@@ -60,7 +60,8 @@ SCHED_FEAT(TTWU_QUEUE, true)
 /*
  * When doing wakeups, attempt to limit superfluous scans of the LLC domain.
  */
-SCHED_FEAT(SIS_PROP, true)
+SCHED_FEAT(SIS_PROP, false)
+SCHED_FEAT(SIS_UTIL, true)
 
 /*
  * Issue a WARN when we do multiple update_rq_clock() calls
index 328cccb..f26ab26 100644 (file)
@@ -53,14 +53,14 @@ static noinline int __cpuidle cpu_idle_poll(void)
 {
        trace_cpu_idle(0, smp_processor_id());
        stop_critical_timings();
-       rcu_idle_enter();
+       ct_idle_enter();
        local_irq_enable();
 
        while (!tif_need_resched() &&
               (cpu_idle_force_poll || tick_check_broadcast_expired()))
                cpu_relax();
 
-       rcu_idle_exit();
+       ct_idle_exit();
        start_critical_timings();
        trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
 
@@ -98,12 +98,12 @@ void __cpuidle default_idle_call(void)
                 *
                 * Trace IRQs enable here, then switch off RCU, and have
                 * arch_cpu_idle() use raw_local_irq_enable(). Note that
-                * rcu_idle_enter() relies on lockdep IRQ state, so switch that
+                * ct_idle_enter() relies on lockdep IRQ state, so switch that
                 * last -- this is very similar to the entry code.
                 */
                trace_hardirqs_on_prepare();
                lockdep_hardirqs_on_prepare();
-               rcu_idle_enter();
+               ct_idle_enter();
                lockdep_hardirqs_on(_THIS_IP_);
 
                arch_cpu_idle();
@@ -116,7 +116,7 @@ void __cpuidle default_idle_call(void)
                 */
                raw_local_irq_disable();
                lockdep_hardirqs_off(_THIS_IP_);
-               rcu_idle_exit();
+               ct_idle_exit();
                lockdep_hardirqs_on(_THIS_IP_);
                raw_local_irq_enable();
 
index 4ff2ed4..3a0e0dc 100644 (file)
@@ -61,6 +61,25 @@ static inline void cfs_se_util_change(struct sched_avg *avg)
        WRITE_ONCE(avg->util_est.enqueued, enqueued);
 }
 
+static inline u64 rq_clock_pelt(struct rq *rq)
+{
+       lockdep_assert_rq_held(rq);
+       assert_clock_updated(rq);
+
+       return rq->clock_pelt - rq->lost_idle_time;
+}
+
+/* The rq is idle, we can sync to clock_task */
+static inline void _update_idle_rq_clock_pelt(struct rq *rq)
+{
+       rq->clock_pelt  = rq_clock_task(rq);
+
+       u64_u32_store(rq->clock_idle, rq_clock(rq));
+       /* Paired with smp_rmb in migrate_se_pelt_lag() */
+       smp_wmb();
+       u64_u32_store(rq->clock_pelt_idle, rq_clock_pelt(rq));
+}
+
 /*
  * The clock_pelt scales the time to reflect the effective amount of
  * computation done during the running delta time but then sync back to
@@ -76,8 +95,7 @@ static inline void cfs_se_util_change(struct sched_avg *avg)
 static inline void update_rq_clock_pelt(struct rq *rq, s64 delta)
 {
        if (unlikely(is_idle_task(rq->curr))) {
-               /* The rq is idle, we can sync to clock_task */
-               rq->clock_pelt  = rq_clock_task(rq);
+               _update_idle_rq_clock_pelt(rq);
                return;
        }
 
@@ -130,17 +148,23 @@ static inline void update_idle_rq_clock_pelt(struct rq *rq)
         */
        if (util_sum >= divider)
                rq->lost_idle_time += rq_clock_task(rq) - rq->clock_pelt;
+
+       _update_idle_rq_clock_pelt(rq);
 }
 
-static inline u64 rq_clock_pelt(struct rq *rq)
+#ifdef CONFIG_CFS_BANDWIDTH
+static inline void update_idle_cfs_rq_clock_pelt(struct cfs_rq *cfs_rq)
 {
-       lockdep_assert_rq_held(rq);
-       assert_clock_updated(rq);
+       u64 throttled;
 
-       return rq->clock_pelt - rq->lost_idle_time;
+       if (unlikely(cfs_rq->throttle_count))
+               throttled = U64_MAX;
+       else
+               throttled = cfs_rq->throttled_clock_pelt_time;
+
+       u64_u32_store(cfs_rq->throttled_pelt_idle, throttled);
 }
 
-#ifdef CONFIG_CFS_BANDWIDTH
 /* rq->task_clock normalized against any time this cfs_rq has spent throttled */
 static inline u64 cfs_rq_clock_pelt(struct cfs_rq *cfs_rq)
 {
@@ -150,6 +174,7 @@ static inline u64 cfs_rq_clock_pelt(struct cfs_rq *cfs_rq)
        return rq_clock_pelt(rq_of(cfs_rq)) - cfs_rq->throttled_clock_pelt_time;
 }
 #else
+static inline void update_idle_cfs_rq_clock_pelt(struct cfs_rq *cfs_rq) { }
 static inline u64 cfs_rq_clock_pelt(struct cfs_rq *cfs_rq)
 {
        return rq_clock_pelt(rq_of(cfs_rq));
@@ -204,6 +229,7 @@ update_rq_clock_pelt(struct rq *rq, s64 delta) { }
 static inline void
 update_idle_rq_clock_pelt(struct rq *rq) { }
 
+static inline void update_idle_cfs_rq_clock_pelt(struct cfs_rq *cfs_rq) { }
 #endif
 
 
index a337f3e..ec66b40 100644 (file)
@@ -957,10 +957,16 @@ int psi_cgroup_alloc(struct cgroup *cgroup)
        if (static_branch_likely(&psi_disabled))
                return 0;
 
-       cgroup->psi.pcpu = alloc_percpu(struct psi_group_cpu);
-       if (!cgroup->psi.pcpu)
+       cgroup->psi = kmalloc(sizeof(struct psi_group), GFP_KERNEL);
+       if (!cgroup->psi)
                return -ENOMEM;
-       group_init(&cgroup->psi);
+
+       cgroup->psi->pcpu = alloc_percpu(struct psi_group_cpu);
+       if (!cgroup->psi->pcpu) {
+               kfree(cgroup->psi);
+               return -ENOMEM;
+       }
+       group_init(cgroup->psi);
        return 0;
 }
 
@@ -969,10 +975,11 @@ void psi_cgroup_free(struct cgroup *cgroup)
        if (static_branch_likely(&psi_disabled))
                return;
 
-       cancel_delayed_work_sync(&cgroup->psi.avgs_work);
-       free_percpu(cgroup->psi.pcpu);
+       cancel_delayed_work_sync(&cgroup->psi->avgs_work);
+       free_percpu(cgroup->psi->pcpu);
        /* All triggers must be removed by now */
-       WARN_ONCE(cgroup->psi.poll_states, "psi: trigger leak\n");
+       WARN_ONCE(cgroup->psi->poll_states, "psi: trigger leak\n");
+       kfree(cgroup->psi);
 }
 
 /**
index 8c9ed96..55f39c8 100644 (file)
@@ -480,7 +480,7 @@ static inline void rt_queue_push_tasks(struct rq *rq)
 #endif /* CONFIG_SMP */
 
 static void enqueue_top_rt_rq(struct rt_rq *rt_rq);
-static void dequeue_top_rt_rq(struct rt_rq *rt_rq);
+static void dequeue_top_rt_rq(struct rt_rq *rt_rq, unsigned int count);
 
 static inline int on_rt_rq(struct sched_rt_entity *rt_se)
 {
@@ -601,7 +601,7 @@ static void sched_rt_rq_dequeue(struct rt_rq *rt_rq)
        rt_se = rt_rq->tg->rt_se[cpu];
 
        if (!rt_se) {
-               dequeue_top_rt_rq(rt_rq);
+               dequeue_top_rt_rq(rt_rq, rt_rq->rt_nr_running);
                /* Kick cpufreq (see the comment in kernel/sched/sched.h). */
                cpufreq_update_util(rq_of_rt_rq(rt_rq), 0);
        }
@@ -687,7 +687,7 @@ static inline void sched_rt_rq_enqueue(struct rt_rq *rt_rq)
 
 static inline void sched_rt_rq_dequeue(struct rt_rq *rt_rq)
 {
-       dequeue_top_rt_rq(rt_rq);
+       dequeue_top_rt_rq(rt_rq, rt_rq->rt_nr_running);
 }
 
 static inline int rt_rq_throttled(struct rt_rq *rt_rq)
@@ -1089,7 +1089,7 @@ static void update_curr_rt(struct rq *rq)
 }
 
 static void
-dequeue_top_rt_rq(struct rt_rq *rt_rq)
+dequeue_top_rt_rq(struct rt_rq *rt_rq, unsigned int count)
 {
        struct rq *rq = rq_of_rt_rq(rt_rq);
 
@@ -1100,7 +1100,7 @@ dequeue_top_rt_rq(struct rt_rq *rt_rq)
 
        BUG_ON(!rq->nr_running);
 
-       sub_nr_running(rq, rt_rq->rt_nr_running);
+       sub_nr_running(rq, count);
        rt_rq->rt_queued = 0;
 
 }
@@ -1486,18 +1486,21 @@ static void __dequeue_rt_entity(struct sched_rt_entity *rt_se, unsigned int flag
 static void dequeue_rt_stack(struct sched_rt_entity *rt_se, unsigned int flags)
 {
        struct sched_rt_entity *back = NULL;
+       unsigned int rt_nr_running;
 
        for_each_sched_rt_entity(rt_se) {
                rt_se->back = back;
                back = rt_se;
        }
 
-       dequeue_top_rt_rq(rt_rq_of_se(back));
+       rt_nr_running = rt_rq_of_se(back)->rt_nr_running;
 
        for (rt_se = back; rt_se; rt_se = rt_se->back) {
                if (on_rt_rq(rt_se))
                        __dequeue_rt_entity(rt_se, flags);
        }
+
+       dequeue_top_rt_rq(rt_rq_of_se(back), rt_nr_running);
 }
 
 static void enqueue_rt_entity(struct sched_rt_entity *rt_se, unsigned int flags)
index 47b89a0..a6f071b 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/capability.h>
 #include <linux/cgroup_api.h>
 #include <linux/cgroup.h>
+#include <linux/context_tracking.h>
 #include <linux/cpufreq.h>
 #include <linux/cpumask_api.h>
 #include <linux/ctype.h>
@@ -520,6 +521,45 @@ struct cfs_bandwidth { };
 
 #endif /* CONFIG_CGROUP_SCHED */
 
+/*
+ * u64_u32_load/u64_u32_store
+ *
+ * Use a copy of a u64 value to protect against data race. This is only
+ * applicable for 32-bits architectures.
+ */
+#ifdef CONFIG_64BIT
+# define u64_u32_load_copy(var, copy)       var
+# define u64_u32_store_copy(var, copy, val) (var = val)
+#else
+# define u64_u32_load_copy(var, copy)                                  \
+({                                                                     \
+       u64 __val, __val_copy;                                          \
+       do {                                                            \
+               __val_copy = copy;                                      \
+               /*                                                      \
+                * paired with u64_u32_store_copy(), ordering access    \
+                * to var and copy.                                     \
+                */                                                     \
+               smp_rmb();                                              \
+               __val = var;                                            \
+       } while (__val != __val_copy);                                  \
+       __val;                                                          \
+})
+# define u64_u32_store_copy(var, copy, val)                            \
+do {                                                                   \
+       typeof(val) __val = (val);                                      \
+       var = __val;                                                    \
+       /*                                                              \
+        * paired with u64_u32_load_copy(), ordering access to var and  \
+        * copy.                                                        \
+        */                                                             \
+       smp_wmb();                                                      \
+       copy = __val;                                                   \
+} while (0)
+#endif
+# define u64_u32_load(var)      u64_u32_load_copy(var, var##_copy)
+# define u64_u32_store(var, val) u64_u32_store_copy(var, var##_copy, val)
+
 /* CFS-related fields in a runqueue */
 struct cfs_rq {
        struct load_weight      load;
@@ -560,7 +600,7 @@ struct cfs_rq {
         */
        struct sched_avg        avg;
 #ifndef CONFIG_64BIT
-       u64                     load_last_update_time_copy;
+       u64                     last_update_time_copy;
 #endif
        struct {
                raw_spinlock_t  lock ____cacheline_aligned;
@@ -609,6 +649,10 @@ struct cfs_rq {
        int                     runtime_enabled;
        s64                     runtime_remaining;
 
+       u64                     throttled_pelt_idle;
+#ifndef CONFIG_64BIT
+       u64                     throttled_pelt_idle_copy;
+#endif
        u64                     throttled_clock;
        u64                     throttled_clock_pelt;
        u64                     throttled_clock_pelt_time;
@@ -981,6 +1025,12 @@ struct rq {
        u64                     clock_task ____cacheline_aligned;
        u64                     clock_pelt;
        unsigned long           lost_idle_time;
+       u64                     clock_pelt_idle;
+       u64                     clock_idle;
+#ifndef CONFIG_64BIT
+       u64                     clock_pelt_idle_copy;
+       u64                     clock_idle_copy;
+#endif
 
        atomic_t                nr_iowait;
 
@@ -1815,15 +1865,6 @@ static inline struct cpumask *group_balance_mask(struct sched_group *sg)
        return to_cpumask(sg->sgc->cpumask);
 }
 
-/**
- * group_first_cpu - Returns the first CPU in the cpumask of a sched_group.
- * @group: The group whose first CPU is to be returned.
- */
-static inline unsigned int group_first_cpu(struct sched_group *group)
-{
-       return cpumask_first(sched_group_span(group));
-}
-
 extern int group_balance_cpu(struct sched_group *sg);
 
 #ifdef CONFIG_SCHED_DEBUG
@@ -2044,7 +2085,6 @@ static inline int task_on_rq_migrating(struct task_struct *p)
 
 #define WF_SYNC     0x10 /* Waker goes to sleep after wakeup */
 #define WF_MIGRATED 0x20 /* Internal use, task got migrated */
-#define WF_ON_CPU   0x40 /* Wakee is on_cpu */
 
 #ifdef CONFIG_SMP
 static_assert(WF_EXEC == SD_BALANCE_EXEC);
@@ -2852,7 +2892,7 @@ enum cpu_util_type {
 };
 
 unsigned long effective_cpu_util(int cpu, unsigned long util_cfs,
-                                unsigned long max, enum cpu_util_type type,
+                                enum cpu_util_type type,
                                 struct task_struct *p);
 
 static inline unsigned long cpu_bw_dl(struct rq *rq)
index 05b6c2a..8739c2a 100644 (file)
@@ -2316,23 +2316,30 @@ build_sched_domains(const struct cpumask *cpu_map, struct sched_domain_attr *att
 
                                /*
                                 * For a single LLC per node, allow an
-                                * imbalance up to 25% of the node. This is an
-                                * arbitrary cutoff based on SMT-2 to balance
-                                * between memory bandwidth and avoiding
-                                * premature sharing of HT resources and SMT-4
-                                * or SMT-8 *may* benefit from a different
-                                * cutoff.
+                                * imbalance up to 12.5% of the node. This is
+                                * arbitrary cutoff based two factors -- SMT and
+                                * memory channels. For SMT-2, the intent is to
+                                * avoid premature sharing of HT resources but
+                                * SMT-4 or SMT-8 *may* benefit from a different
+                                * cutoff. For memory channels, this is a very
+                                * rough estimate of how many channels may be
+                                * active and is based on recent CPUs with
+                                * many cores.
                                 *
                                 * For multiple LLCs, allow an imbalance
                                 * until multiple tasks would share an LLC
                                 * on one node while LLCs on another node
-                                * remain idle.
+                                * remain idle. This assumes that there are
+                                * enough logical CPUs per LLC to avoid SMT
+                                * factors and that there is a correlation
+                                * between LLCs and memory channels.
                                 */
                                nr_llcs = sd->span_weight / child->span_weight;
                                if (nr_llcs == 1)
-                                       imb = sd->span_weight >> 2;
+                                       imb = sd->span_weight >> 3;
                                else
                                        imb = nr_llcs;
+                               imb = max(1U, imb);
                                sd->imb_numa_nr = imb;
 
                                /* Set span based on the first NUMA domain. */
index edb1dc9..6f86fda 100644 (file)
@@ -2029,12 +2029,12 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
        bool autoreap = false;
        u64 utime, stime;
 
-       BUG_ON(sig == -1);
+       WARN_ON_ONCE(sig == -1);
 
-       /* do_notify_parent_cldstop should have been called instead.  */
-       BUG_ON(task_is_stopped_or_traced(tsk));
+       /* do_notify_parent_cldstop should have been called instead.  */
+       WARN_ON_ONCE(task_is_stopped_or_traced(tsk));
 
-       BUG_ON(!tsk->ptrace &&
+       WARN_ON_ONCE(!tsk->ptrace &&
               (tsk->group_leader != tsk || !thread_group_empty(tsk)));
 
        /* Wake up all pidfd waiters */
index dd215f4..650810a 100644 (file)
@@ -174,9 +174,9 @@ static int __init csdlock_debug(char *str)
        if (val)
                static_branch_enable(&csdlock_debug_enabled);
 
-       return 0;
+       return 1;
 }
-early_param("csdlock_debug", csdlock_debug);
+__setup("csdlock_debug=", csdlock_debug);
 
 static DEFINE_PER_CPU(call_single_data_t *, cur_csd);
 static DEFINE_PER_CPU(smp_call_func_t, cur_csd_func);
index 9f0aef8..c8a6913 100644 (file)
@@ -620,7 +620,7 @@ void irq_enter_rcu(void)
  */
 void irq_enter(void)
 {
-       rcu_irq_enter();
+       ct_irq_enter();
        irq_enter_rcu();
 }
 
@@ -672,7 +672,7 @@ void irq_exit_rcu(void)
 void irq_exit(void)
 {
        __irq_exit_rcu();
-       rcu_irq_exit();
+       ct_irq_exit();
         /* must be last! */
        lockdep_hardirq_exit();
 }
index e52b6e3..35d0342 100644 (file)
@@ -446,14 +446,14 @@ static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp,
                if (*negp) {
                        if (*lvalp > (unsigned long) INT_MAX + 1)
                                return -EINVAL;
-                       *valp = -*lvalp;
+                       WRITE_ONCE(*valp, -*lvalp);
                } else {
                        if (*lvalp > (unsigned long) INT_MAX)
                                return -EINVAL;
-                       *valp = *lvalp;
+                       WRITE_ONCE(*valp, *lvalp);
                }
        } else {
-               int val = *valp;
+               int val = READ_ONCE(*valp);
                if (val < 0) {
                        *negp = true;
                        *lvalp = -(unsigned long)val;
@@ -472,9 +472,9 @@ static int do_proc_douintvec_conv(unsigned long *lvalp,
        if (write) {
                if (*lvalp > UINT_MAX)
                        return -EINVAL;
-               *valp = *lvalp;
+               WRITE_ONCE(*valp, *lvalp);
        } else {
-               unsigned int val = *valp;
+               unsigned int val = READ_ONCE(*valp);
                *lvalp = (unsigned long)val;
        }
        return 0;
@@ -857,7 +857,7 @@ static int do_proc_dointvec_minmax_conv(bool *negp, unsigned long *lvalp,
                if ((param->min && *param->min > tmp) ||
                    (param->max && *param->max < tmp))
                        return -EINVAL;
-               *valp = tmp;
+               WRITE_ONCE(*valp, tmp);
        }
 
        return 0;
@@ -923,7 +923,7 @@ static int do_proc_douintvec_minmax_conv(unsigned long *lvalp,
                    (param->max && *param->max < tmp))
                        return -ERANGE;
 
-               *valp = tmp;
+               WRITE_ONCE(*valp, tmp);
        }
 
        return 0;
@@ -1007,13 +1007,13 @@ int proc_dou8vec_minmax(struct ctl_table *table, int write,
 
        tmp.maxlen = sizeof(val);
        tmp.data = &val;
-       val = *data;
+       val = READ_ONCE(*data);
        res = do_proc_douintvec(&tmp, write, buffer, lenp, ppos,
                                do_proc_douintvec_minmax_conv, &param);
        if (res)
                return res;
        if (write)
-               *data = val;
+               WRITE_ONCE(*data, val);
        return 0;
 }
 EXPORT_SYMBOL_GPL(proc_dou8vec_minmax);
@@ -1090,9 +1090,9 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table,
                                err = -EINVAL;
                                break;
                        }
-                       *i = val;
+                       WRITE_ONCE(*i, val);
                } else {
-                       val = convdiv * (*i) / convmul;
+                       val = convdiv * READ_ONCE(*i) / convmul;
                        if (!first)
                                proc_put_char(&buffer, &left, '\t');
                        proc_put_long(&buffer, &left, val, false);
@@ -1173,9 +1173,12 @@ static int do_proc_dointvec_jiffies_conv(bool *negp, unsigned long *lvalp,
        if (write) {
                if (*lvalp > INT_MAX / HZ)
                        return 1;
-               *valp = *negp ? -(*lvalp*HZ) : (*lvalp*HZ);
+               if (*negp)
+                       WRITE_ONCE(*valp, -*lvalp * HZ);
+               else
+                       WRITE_ONCE(*valp, *lvalp * HZ);
        } else {
-               int val = *valp;
+               int val = READ_ONCE(*valp);
                unsigned long lval;
                if (val < 0) {
                        *negp = true;
@@ -1221,9 +1224,9 @@ static int do_proc_dointvec_ms_jiffies_conv(bool *negp, unsigned long *lvalp,
 
                if (jif > INT_MAX)
                        return 1;
-               *valp = (int)jif;
+               WRITE_ONCE(*valp, (int)jif);
        } else {
-               int val = *valp;
+               int val = READ_ONCE(*valp);
                unsigned long lval;
                if (val < 0) {
                        *negp = true;
@@ -1291,8 +1294,8 @@ int proc_dointvec_userhz_jiffies(struct ctl_table *table, int write,
  * @ppos: the current position in the file
  *
  * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
- * values from/to the user buffer, treated as an ASCII string. 
- * The values read are assumed to be in 1/1000 seconds, and 
+ * values from/to the user buffer, treated as an ASCII string.
+ * The values read are assumed to be in 1/1000 seconds, and
  * are converted into jiffies.
  *
  * Returns 0 on success.
@@ -2091,6 +2094,17 @@ static struct ctl_table vm_table[] = {
                .extra1         = SYSCTL_ZERO,
                .extra2         = SYSCTL_TWO_HUNDRED,
        },
+#ifdef CONFIG_NUMA
+       {
+               .procname       = "numa_stat",
+               .data           = &sysctl_vm_numa_stat,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = sysctl_vm_numa_stat_handler,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
+       },
+#endif
 #ifdef CONFIG_HUGETLB_PAGE
        {
                .procname       = "nr_hugepages",
@@ -2107,15 +2121,6 @@ static struct ctl_table vm_table[] = {
                .mode           = 0644,
                .proc_handler   = &hugetlb_mempolicy_sysctl_handler,
        },
-       {
-               .procname               = "numa_stat",
-               .data                   = &sysctl_vm_numa_stat,
-               .maxlen                 = sizeof(int),
-               .mode                   = 0644,
-               .proc_handler   = sysctl_vm_numa_stat_handler,
-               .extra1                 = SYSCTL_ZERO,
-               .extra2                 = SYSCTL_ONE,
-       },
 #endif
         {
                .procname       = "hugetlb_shm_group",
index 27b7868..a41753b 100644 (file)
@@ -73,6 +73,15 @@ config TIME_KUNIT_TEST
 
          If unsure, say N.
 
+config CONTEXT_TRACKING
+       bool
+
+config CONTEXT_TRACKING_IDLE
+       bool
+       select CONTEXT_TRACKING
+       help
+         Tracks idle state on behalf of RCU.
+
 if GENERIC_CLOCKEVENTS
 menu "Timers subsystem"
 
@@ -111,7 +120,7 @@ config NO_HZ_FULL
        # NO_HZ_COMMON dependency
        # We need at least one periodic CPU for timekeeping
        depends on SMP
-       depends on HAVE_CONTEXT_TRACKING
+       depends on HAVE_CONTEXT_TRACKING_USER
        # VIRT_CPU_ACCOUNTING_GEN dependency
        depends on HAVE_VIRT_CPU_ACCOUNTING_GEN
        select NO_HZ_COMMON
@@ -137,31 +146,37 @@ config NO_HZ_FULL
 
 endchoice
 
-config CONTEXT_TRACKING
-       bool
+config CONTEXT_TRACKING_USER
+       bool
+       depends on HAVE_CONTEXT_TRACKING_USER
+       select CONTEXT_TRACKING
+       help
+         Track transitions between kernel and user on behalf of RCU and
+         tickless cputime accounting. The former case relies on context
+         tracking to enter/exit RCU extended quiescent states.
 
-config CONTEXT_TRACKING_FORCE
-       bool "Force context tracking"
-       depends on CONTEXT_TRACKING
+config CONTEXT_TRACKING_USER_FORCE
+       bool "Force user context tracking"
+       depends on CONTEXT_TRACKING_USER
        default y if !NO_HZ_FULL
        help
          The major pre-requirement for full dynticks to work is to
-         support the context tracking subsystem. But there are also
+         support the user context tracking subsystem. But there are also
          other dependencies to provide in order to make the full
          dynticks working.
 
          This option stands for testing when an arch implements the
-         context tracking backend but doesn't yet fulfill all the
+         user context tracking backend but doesn't yet fulfill all the
          requirements to make the full dynticks feature working.
          Without the full dynticks, there is no way to test the support
-         for context tracking and the subsystems that rely on it: RCU
+         for user context tracking and the subsystems that rely on it: RCU
          userspace extended quiescent state and tickless cputime
          accounting. This option copes with the absence of the full
-         dynticks subsystem by forcing the context tracking on all
+         dynticks subsystem by forcing the user context tracking on all
          CPUs in the system.
 
          Say Y only if you're working on the development of an
-         architecture backend for the context tracking.
+         architecture backend for the user context tracking.
 
          Say N otherwise, this option brings an overhead that you
          don't want in production.
index 1cd10b1..5dead89 100644 (file)
@@ -1051,15 +1051,24 @@ retry_delete:
 }
 
 /*
- * This is called by do_exit or de_thread, only when there are no more
- * references to the shared signal_struct.
+ * This is called by do_exit or de_thread, only when nobody else can
+ * modify the signal->posix_timers list. Yet we need sighand->siglock
+ * to prevent the race with /proc/pid/timers.
  */
-void exit_itimers(struct signal_struct *sig)
+void exit_itimers(struct task_struct *tsk)
 {
+       struct list_head timers;
        struct k_itimer *tmr;
 
-       while (!list_empty(&sig->posix_timers)) {
-               tmr = list_entry(sig->posix_timers.next, struct k_itimer, list);
+       if (list_empty(&tsk->signal->posix_timers))
+               return;
+
+       spin_lock_irq(&tsk->sighand->siglock);
+       list_replace_init(&tsk->signal->posix_timers, &timers);
+       spin_unlock_irq(&tsk->sighand->siglock);
+
+       while (!list_empty(&timers)) {
+               tmr = list_first_entry(&timers, struct k_itimer, list);
                itimer_delete(tmr);
        }
 }
index 58a11f8..b0e3c92 100644 (file)
@@ -526,7 +526,6 @@ void __init tick_nohz_full_setup(cpumask_var_t cpumask)
        cpumask_copy(tick_nohz_full_mask, cpumask);
        tick_nohz_full_running = true;
 }
-EXPORT_SYMBOL_GPL(tick_nohz_full_setup);
 
 static int tick_nohz_cpu_down(unsigned int cpu)
 {
@@ -571,7 +570,7 @@ void __init tick_nohz_init(void)
        }
 
        for_each_cpu(cpu, tick_nohz_full_mask)
-               context_tracking_cpu_set(cpu);
+               ct_cpu_track_user(cpu);
 
        ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
                                        "kernel/nohz:predown", NULL,
index 8e4b3c3..f72b9f1 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/pvclock_gtod.h>
 #include <linux/compiler.h>
 #include <linux/audit.h>
+#include <linux/random.h>
 
 #include "tick-internal.h"
 #include "ntp_internal.h"
@@ -1343,8 +1344,10 @@ out:
        /* Signal hrtimers about time change */
        clock_was_set(CLOCK_SET_WALL);
 
-       if (!ret)
+       if (!ret) {
                audit_tk_injoffset(ts_delta);
+               add_device_randomness(ts, sizeof(*ts));
+       }
 
        return ret;
 }
@@ -2430,6 +2433,7 @@ int do_adjtimex(struct __kernel_timex *txc)
        ret = timekeeping_validate_timex(txc);
        if (ret)
                return ret;
+       add_device_randomness(txc, sizeof(*txc));
 
        if (txc->modes & ADJ_SETOFFSET) {
                struct timespec64 delta;
@@ -2447,6 +2451,7 @@ int do_adjtimex(struct __kernel_timex *txc)
        audit_ntp_init(&ad);
 
        ktime_get_real_ts64(&ts);
+       add_device_randomness(&ts, sizeof(ts));
 
        raw_spin_lock_irqsave(&timekeeper_lock, flags);
        write_seqcount_begin(&tk_core.seq);
index debbbb0..ccd6a5a 100644 (file)
@@ -194,7 +194,8 @@ config FUNCTION_TRACER
          sequence is then dynamically patched into a tracer call when
          tracing is enabled by the administrator. If it's runtime disabled
          (the bootup default), then the overhead of the instructions is very
-         small and not measurable even in micro-benchmarks.
+         small and not measurable even in micro-benchmarks (at least on
+         x86, but may have impact on other architectures).
 
 config FUNCTION_GRAPH_TRACER
        bool "Kernel Function Graph Tracer"
index fe04c6f..7f5eb29 100644 (file)
@@ -205,7 +205,7 @@ static const u32 ddir_act[2] = { BLK_TC_ACT(BLK_TC_READ),
 #define BLK_TC_PREFLUSH                BLK_TC_FLUSH
 
 /* The ilog2() calls fall out because they're constant */
-#define MASK_TC_BIT(rw, __name) ((rw & REQ_ ## __name) << \
+#define MASK_TC_BIT(rw, __name) ((__force u32)(rw & REQ_ ## __name) << \
          (ilog2(BLK_TC_ ## __name) + BLK_TC_SHIFT - __REQ_ ## __name))
 
 /*
@@ -213,8 +213,8 @@ static const u32 ddir_act[2] = { BLK_TC_ACT(BLK_TC_READ),
  * blk_io_trace structure and places it in a per-cpu subbuffer.
  */
 static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,
-                    int op, int op_flags, u32 what, int error, int pdu_len,
-                    void *pdu_data, u64 cgid)
+                           const blk_opf_t opf, u32 what, int error,
+                           int pdu_len, void *pdu_data, u64 cgid)
 {
        struct task_struct *tsk = current;
        struct ring_buffer_event *event = NULL;
@@ -227,16 +227,17 @@ static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,
        int cpu;
        bool blk_tracer = blk_tracer_enabled;
        ssize_t cgid_len = cgid ? sizeof(cgid) : 0;
+       const enum req_op op = opf & REQ_OP_MASK;
 
        if (unlikely(bt->trace_state != Blktrace_running && !blk_tracer))
                return;
 
        what |= ddir_act[op_is_write(op) ? WRITE : READ];
-       what |= MASK_TC_BIT(op_flags, SYNC);
-       what |= MASK_TC_BIT(op_flags, RAHEAD);
-       what |= MASK_TC_BIT(op_flags, META);
-       what |= MASK_TC_BIT(op_flags, PREFLUSH);
-       what |= MASK_TC_BIT(op_flags, FUA);
+       what |= MASK_TC_BIT(opf, SYNC);
+       what |= MASK_TC_BIT(opf, RAHEAD);
+       what |= MASK_TC_BIT(opf, META);
+       what |= MASK_TC_BIT(opf, PREFLUSH);
+       what |= MASK_TC_BIT(opf, FUA);
        if (op == REQ_OP_DISCARD || op == REQ_OP_SECURE_ERASE)
                what |= BLK_TC_ACT(BLK_TC_DISCARD);
        if (op == REQ_OP_FLUSH)
@@ -736,12 +737,12 @@ int blk_trace_ioctl(struct block_device *bdev, unsigned cmd, char __user *arg)
 
        switch (cmd) {
        case BLKTRACESETUP:
-               bdevname(bdev, b);
+               snprintf(b, sizeof(b), "%pg", bdev);
                ret = __blk_trace_setup(q, b, bdev->bd_dev, bdev, arg);
                break;
 #if defined(CONFIG_COMPAT) && defined(CONFIG_X86_64)
        case BLKTRACESETUP32:
-               bdevname(bdev, b);
+               snprintf(b, sizeof(b), "%pg", bdev);
                ret = compat_blk_trace_setup(q, b, bdev->bd_dev, bdev, arg);
                break;
 #endif
@@ -842,9 +843,8 @@ static void blk_add_trace_rq(struct request *rq, blk_status_t error,
        else
                what |= BLK_TC_ACT(BLK_TC_FS);
 
-       __blk_add_trace(bt, blk_rq_trace_sector(rq), nr_bytes, req_op(rq),
-                       rq->cmd_flags, what, blk_status_to_errno(error), 0,
-                       NULL, cgid);
+       __blk_add_trace(bt, blk_rq_trace_sector(rq), nr_bytes, rq->cmd_flags,
+                       what, blk_status_to_errno(error), 0, NULL, cgid);
        rcu_read_unlock();
 }
 
@@ -903,7 +903,7 @@ static void blk_add_trace_bio(struct request_queue *q, struct bio *bio,
        }
 
        __blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size,
-                       bio_op(bio), bio->bi_opf, what, error, 0, NULL,
+                       bio->bi_opf, what, error, 0, NULL,
                        blk_trace_bio_get_cgid(q, bio));
        rcu_read_unlock();
 }
@@ -949,7 +949,7 @@ static void blk_add_trace_plug(void *ignore, struct request_queue *q)
        rcu_read_lock();
        bt = rcu_dereference(q->blk_trace);
        if (bt)
-               __blk_add_trace(bt, 0, 0, 0, 0, BLK_TA_PLUG, 0, 0, NULL, 0);
+               __blk_add_trace(bt, 0, 0, 0, BLK_TA_PLUG, 0, 0, NULL, 0);
        rcu_read_unlock();
 }
 
@@ -969,7 +969,7 @@ static void blk_add_trace_unplug(void *ignore, struct request_queue *q,
                else
                        what = BLK_TA_UNPLUG_TIMER;
 
-               __blk_add_trace(bt, 0, 0, 0, 0, what, 0, sizeof(rpdu), &rpdu, 0);
+               __blk_add_trace(bt, 0, 0, 0, what, 0, sizeof(rpdu), &rpdu, 0);
        }
        rcu_read_unlock();
 }
@@ -985,8 +985,7 @@ static void blk_add_trace_split(void *ignore, struct bio *bio, unsigned int pdu)
                __be64 rpdu = cpu_to_be64(pdu);
 
                __blk_add_trace(bt, bio->bi_iter.bi_sector,
-                               bio->bi_iter.bi_size, bio_op(bio), bio->bi_opf,
-                               BLK_TA_SPLIT,
+                               bio->bi_iter.bi_size, bio->bi_opf, BLK_TA_SPLIT,
                                blk_status_to_errno(bio->bi_status),
                                sizeof(rpdu), &rpdu,
                                blk_trace_bio_get_cgid(q, bio));
@@ -1022,7 +1021,7 @@ static void blk_add_trace_bio_remap(void *ignore, struct bio *bio, dev_t dev,
        r.sector_from = cpu_to_be64(from);
 
        __blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size,
-                       bio_op(bio), bio->bi_opf, BLK_TA_REMAP,
+                       bio->bi_opf, BLK_TA_REMAP,
                        blk_status_to_errno(bio->bi_status),
                        sizeof(r), &r, blk_trace_bio_get_cgid(q, bio));
        rcu_read_unlock();
@@ -1058,7 +1057,7 @@ static void blk_add_trace_rq_remap(void *ignore, struct request *rq, dev_t dev,
        r.sector_from = cpu_to_be64(from);
 
        __blk_add_trace(bt, blk_rq_pos(rq), blk_rq_bytes(rq),
-                       rq_data_dir(rq), 0, BLK_TA_REMAP, 0,
+                       rq->cmd_flags, BLK_TA_REMAP, 0,
                        sizeof(r), &r, blk_trace_request_get_cgid(rq));
        rcu_read_unlock();
 }
@@ -1084,7 +1083,7 @@ void blk_add_driver_data(struct request *rq, void *data, size_t len)
                return;
        }
 
-       __blk_add_trace(bt, blk_rq_trace_sector(rq), blk_rq_bytes(rq), 0, 0,
+       __blk_add_trace(bt, blk_rq_trace_sector(rq), blk_rq_bytes(rq), 0,
                                BLK_TA_DRV_DATA, 0, len, data,
                                blk_trace_request_get_cgid(rq));
        rcu_read_unlock();
@@ -1867,17 +1866,6 @@ out_unlock_bdev:
 out:
        return ret ? ret : count;
 }
-
-int blk_trace_init_sysfs(struct device *dev)
-{
-       return sysfs_create_group(&dev->kobj, &blk_trace_attr_group);
-}
-
-void blk_trace_remove_sysfs(struct device *dev)
-{
-       sysfs_remove_group(&dev->kobj, &blk_trace_attr_group);
-}
-
 #endif /* CONFIG_BLK_DEV_IO_TRACE */
 
 #ifdef CONFIG_EVENT_TRACING
@@ -1885,21 +1873,21 @@ void blk_trace_remove_sysfs(struct device *dev)
 /**
  * blk_fill_rwbs - Fill the buffer rwbs by mapping op to character string.
  * @rwbs:      buffer to be filled
- * @op:                REQ_OP_XXX for the tracepoint
+ * @opf:       request operation type (REQ_OP_XXX) and flags for the tracepoint
  *
  * Description:
- *     Maps the REQ_OP_XXX to character and fills the buffer provided by the
- *     caller with resulting string.
+ *     Maps each request operation and flag to a single character and fills the
+ *     buffer provided by the caller with resulting string.
  *
  **/
-void blk_fill_rwbs(char *rwbs, unsigned int op)
+void blk_fill_rwbs(char *rwbs, blk_opf_t opf)
 {
        int i = 0;
 
-       if (op & REQ_PREFLUSH)
+       if (opf & REQ_PREFLUSH)
                rwbs[i++] = 'F';
 
-       switch (op & REQ_OP_MASK) {
+       switch (opf & REQ_OP_MASK) {
        case REQ_OP_WRITE:
                rwbs[i++] = 'W';
                break;
@@ -1920,13 +1908,13 @@ void blk_fill_rwbs(char *rwbs, unsigned int op)
                rwbs[i++] = 'N';
        }
 
-       if (op & REQ_FUA)
+       if (opf & REQ_FUA)
                rwbs[i++] = 'F';
-       if (op & REQ_RAHEAD)
+       if (opf & REQ_RAHEAD)
                rwbs[i++] = 'A';
-       if (op & REQ_SYNC)
+       if (opf & REQ_SYNC)
                rwbs[i++] = 'S';
-       if (op & REQ_META)
+       if (opf & REQ_META)
                rwbs[i++] = 'M';
 
        rwbs[i] = '\0';
index a8cfac0..0c517c8 100644 (file)
@@ -3105,17 +3105,17 @@ void __trace_stack(struct trace_array *tr, unsigned int trace_ctx,
        }
 
        /*
-        * When an NMI triggers, RCU is enabled via rcu_nmi_enter(),
+        * When an NMI triggers, RCU is enabled via ct_nmi_enter(),
         * but if the above rcu_is_watching() failed, then the NMI
-        * triggered someplace critical, and rcu_irq_enter() should
+        * triggered someplace critical, and ct_irq_enter() should
         * not be called from NMI.
         */
        if (unlikely(in_nmi()))
                return;
 
-       rcu_irq_enter_irqson();
+       ct_irq_enter_irqson();
        __ftrace_trace_stack(buffer, trace_ctx, skip, NULL);
-       rcu_irq_exit_irqson();
+       ct_irq_exit_irqson();
 }
 
 /**
@@ -9864,6 +9864,12 @@ void trace_init_global_iter(struct trace_iterator *iter)
        /* Output in nanoseconds only if we are using a clock in nanoseconds. */
        if (trace_clocks[iter->tr->clock_id].in_ns)
                iter->iter_flags |= TRACE_FILE_TIME_IN_NS;
+
+       /* Can not use kmalloc for iter.temp and iter.fmt */
+       iter->temp = static_temp_buf;
+       iter->temp_size = STATIC_TEMP_BUF_SIZE;
+       iter->fmt = static_fmt_buf;
+       iter->fmt_size = STATIC_FMT_BUF_SIZE;
 }
 
 void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
@@ -9896,11 +9902,6 @@ void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
 
        /* Simulate the iterator */
        trace_init_global_iter(&iter);
-       /* Can not use kmalloc for iter.temp and iter.fmt */
-       iter.temp = static_temp_buf;
-       iter.temp_size = STATIC_TEMP_BUF_SIZE;
-       iter.fmt = static_fmt_buf;
-       iter.fmt_size = STATIC_FMT_BUF_SIZE;
 
        for_each_tracing_cpu(cpu) {
                atomic_inc(&per_cpu_ptr(iter.array_buffer->data, cpu)->disabled);
index 48e82e1..e87a467 100644 (file)
@@ -4430,6 +4430,8 @@ static int parse_var_defs(struct hist_trigger_data *hist_data)
 
                        s = kstrdup(field_str, GFP_KERNEL);
                        if (!s) {
+                               kfree(hist_data->attrs->var_defs.name[n_vars]);
+                               hist_data->attrs->var_defs.name[n_vars] = NULL;
                                ret = -ENOMEM;
                                goto free;
                        }
index 230038d..a6f9bdd 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2020 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
- * See Documentation/watch_queue.rst
+ * See Documentation/core-api/watch_queue.rst
  */
 
 #define pr_fmt(fmt) "watchq: " fmt
@@ -34,6 +34,27 @@ MODULE_LICENSE("GPL");
 #define WATCH_QUEUE_NOTE_SIZE 128
 #define WATCH_QUEUE_NOTES_PER_PAGE (PAGE_SIZE / WATCH_QUEUE_NOTE_SIZE)
 
+/*
+ * This must be called under the RCU read-lock, which makes
+ * sure that the wqueue still exists. It can then take the lock,
+ * and check that the wqueue hasn't been destroyed, which in
+ * turn makes sure that the notification pipe still exists.
+ */
+static inline bool lock_wqueue(struct watch_queue *wqueue)
+{
+       spin_lock_bh(&wqueue->lock);
+       if (unlikely(wqueue->defunct)) {
+               spin_unlock_bh(&wqueue->lock);
+               return false;
+       }
+       return true;
+}
+
+static inline void unlock_wqueue(struct watch_queue *wqueue)
+{
+       spin_unlock_bh(&wqueue->lock);
+}
+
 static void watch_queue_pipe_buf_release(struct pipe_inode_info *pipe,
                                         struct pipe_buffer *buf)
 {
@@ -69,6 +90,10 @@ static const struct pipe_buf_operations watch_queue_pipe_buf_ops = {
 
 /*
  * Post a notification to a watch queue.
+ *
+ * Must be called with the RCU lock for reading, and the
+ * watch_queue lock held, which guarantees that the pipe
+ * hasn't been released.
  */
 static bool post_one_notification(struct watch_queue *wqueue,
                                  struct watch_notification *n)
@@ -85,9 +110,6 @@ static bool post_one_notification(struct watch_queue *wqueue,
 
        spin_lock_irq(&pipe->rd_wait.lock);
 
-       if (wqueue->defunct)
-               goto out;
-
        mask = pipe->ring_size - 1;
        head = pipe->head;
        tail = pipe->tail;
@@ -203,7 +225,10 @@ void __post_watch_notification(struct watch_list *wlist,
                if (security_post_notification(watch->cred, cred, n) < 0)
                        continue;
 
-               post_one_notification(wqueue, n);
+               if (lock_wqueue(wqueue)) {
+                       post_one_notification(wqueue, n);
+                       unlock_wqueue(wqueue);
+               }
        }
 
        rcu_read_unlock();
@@ -429,6 +454,33 @@ void init_watch(struct watch *watch, struct watch_queue *wqueue)
        rcu_assign_pointer(watch->queue, wqueue);
 }
 
+static int add_one_watch(struct watch *watch, struct watch_list *wlist, struct watch_queue *wqueue)
+{
+       const struct cred *cred;
+       struct watch *w;
+
+       hlist_for_each_entry(w, &wlist->watchers, list_node) {
+               struct watch_queue *wq = rcu_access_pointer(w->queue);
+               if (wqueue == wq && watch->id == w->id)
+                       return -EBUSY;
+       }
+
+       cred = current_cred();
+       if (atomic_inc_return(&cred->user->nr_watches) > task_rlimit(current, RLIMIT_NOFILE)) {
+               atomic_dec(&cred->user->nr_watches);
+               return -EAGAIN;
+       }
+
+       watch->cred = get_cred(cred);
+       rcu_assign_pointer(watch->watch_list, wlist);
+
+       kref_get(&wqueue->usage);
+       kref_get(&watch->usage);
+       hlist_add_head(&watch->queue_node, &wqueue->watches);
+       hlist_add_head_rcu(&watch->list_node, &wlist->watchers);
+       return 0;
+}
+
 /**
  * add_watch_to_object - Add a watch on an object to a watch list
  * @watch: The watch to add
@@ -443,33 +495,21 @@ void init_watch(struct watch *watch, struct watch_queue *wqueue)
  */
 int add_watch_to_object(struct watch *watch, struct watch_list *wlist)
 {
-       struct watch_queue *wqueue = rcu_access_pointer(watch->queue);
-       struct watch *w;
-
-       hlist_for_each_entry(w, &wlist->watchers, list_node) {
-               struct watch_queue *wq = rcu_access_pointer(w->queue);
-               if (wqueue == wq && watch->id == w->id)
-                       return -EBUSY;
-       }
+       struct watch_queue *wqueue;
+       int ret = -ENOENT;
 
-       watch->cred = get_current_cred();
-       rcu_assign_pointer(watch->watch_list, wlist);
+       rcu_read_lock();
 
-       if (atomic_inc_return(&watch->cred->user->nr_watches) >
-           task_rlimit(current, RLIMIT_NOFILE)) {
-               atomic_dec(&watch->cred->user->nr_watches);
-               put_cred(watch->cred);
-               return -EAGAIN;
+       wqueue = rcu_access_pointer(watch->queue);
+       if (lock_wqueue(wqueue)) {
+               spin_lock(&wlist->lock);
+               ret = add_one_watch(watch, wlist, wqueue);
+               spin_unlock(&wlist->lock);
+               unlock_wqueue(wqueue);
        }
 
-       spin_lock_bh(&wqueue->lock);
-       kref_get(&wqueue->usage);
-       kref_get(&watch->usage);
-       hlist_add_head(&watch->queue_node, &wqueue->watches);
-       spin_unlock_bh(&wqueue->lock);
-
-       hlist_add_head(&watch->list_node, &wlist->watchers);
-       return 0;
+       rcu_read_unlock();
+       return ret;
 }
 EXPORT_SYMBOL(add_watch_to_object);
 
@@ -520,20 +560,15 @@ found:
 
        wqueue = rcu_dereference(watch->queue);
 
-       /* We don't need the watch list lock for the next bit as RCU is
-        * protecting *wqueue from deallocation.
-        */
-       if (wqueue) {
+       if (lock_wqueue(wqueue)) {
                post_one_notification(wqueue, &n.watch);
 
-               spin_lock_bh(&wqueue->lock);
-
                if (!hlist_unhashed(&watch->queue_node)) {
                        hlist_del_init_rcu(&watch->queue_node);
                        put_watch(watch);
                }
 
-               spin_unlock_bh(&wqueue->lock);
+               unlock_wqueue(wqueue);
        }
 
        if (wlist->release_watch) {
index 1ea50f6..aa8a82b 100644 (file)
@@ -5001,7 +5001,10 @@ static void unbind_workers(int cpu)
 
                for_each_pool_worker(worker, pool) {
                        kthread_set_per_cpu(worker->task, -1);
-                       WARN_ON_ONCE(set_cpus_allowed_ptr(worker->task, wq_unbound_cpumask) < 0);
+                       if (cpumask_intersects(wq_unbound_cpumask, cpu_active_mask))
+                               WARN_ON_ONCE(set_cpus_allowed_ptr(worker->task, wq_unbound_cpumask) < 0);
+                       else
+                               WARN_ON_ONCE(set_cpus_allowed_ptr(worker->task, cpu_possible_mask) < 0);
                }
 
                mutex_unlock(&wq_pool_attach_mutex);
index 2e24db4..79a71eb 100644 (file)
@@ -498,7 +498,7 @@ config STACK_VALIDATION
          runtime stack traces are more reliable.
 
          For more information, see
-         tools/objtool/Documentation/stack-validation.txt.
+         tools/objtool/Documentation/objtool.txt.
 
 config NOINSTR_VALIDATION
        bool
index a9f7eb0..fd15230 100644 (file)
@@ -84,6 +84,9 @@ config UBSAN_SHIFT
 config UBSAN_DIV_ZERO
        bool "Perform checking for integer divide-by-zero"
        depends on $(cc-option,-fsanitize=integer-divide-by-zero)
+       # https://github.com/ClangBuiltLinux/linux/issues/1657
+       # https://github.com/llvm/llvm-project/issues/56289
+       depends on !CC_IS_CLANG
        help
          This option enables -fsanitize=integer-divide-by-zero which checks
          for integer division by zero. This is effectively redundant with the
index f99bf61..67482f5 100644 (file)
@@ -29,7 +29,7 @@ endif
 
 lib-y := ctype.o string.o vsprintf.o cmdline.o \
         rbtree.o radix-tree.o timerqueue.o xarray.o \
-        idr.o extable.o sha1.o irq_regs.o argv_split.o \
+        idr.o extable.o irq_regs.o argv_split.o \
         flex_proportions.o ratelimit.o show_mem.o \
         is_single_threaded.o plist.o decompress.o kobject_uevent.o \
         earlycpio.o seq_buf.o siphash.o dec_and_lock.o \
index 2082af4..9ff549f 100644 (file)
@@ -121,6 +121,9 @@ config CRYPTO_LIB_CHACHA20POLY1305
        select CRYPTO_LIB_POLY1305
        select CRYPTO_ALGAPI
 
+config CRYPTO_LIB_SHA1
+       tristate
+
 config CRYPTO_LIB_SHA256
        tristate
 
index 26be2bb..919cbb2 100644 (file)
@@ -34,6 +34,9 @@ libpoly1305-y                                 := poly1305-donna32.o
 libpoly1305-$(CONFIG_ARCH_SUPPORTS_INT128)     := poly1305-donna64.o
 libpoly1305-y                                  += poly1305.o
 
+obj-$(CONFIG_CRYPTO_LIB_SHA1)                  += libsha1.o
+libsha1-y                                      := sha1.o
+
 obj-$(CONFIG_CRYPTO_LIB_SHA256)                        += libsha256.o
 libsha256-y                                    := sha256.o
 
index 409e4b7..7d77dea 100644 (file)
@@ -4,6 +4,8 @@
  */
 
 #include <crypto/internal/blake2s.h>
+#include <linux/kernel.h>
+#include <linux/random.h>
 #include <linux/string.h>
 
 /*
@@ -587,5 +589,44 @@ bool __init blake2s_selftest(void)
                }
        }
 
+       for (i = 0; i < 32; ++i) {
+               enum { TEST_ALIGNMENT = 16 };
+               u8 unaligned_block[BLAKE2S_BLOCK_SIZE + TEST_ALIGNMENT - 1]
+                                       __aligned(TEST_ALIGNMENT);
+               u8 blocks[BLAKE2S_BLOCK_SIZE * 2];
+               struct blake2s_state state1, state2;
+
+               get_random_bytes(blocks, sizeof(blocks));
+               get_random_bytes(&state, sizeof(state));
+
+#if defined(CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC) && \
+    defined(CONFIG_CRYPTO_ARCH_HAVE_LIB_BLAKE2S)
+               memcpy(&state1, &state, sizeof(state1));
+               memcpy(&state2, &state, sizeof(state2));
+               blake2s_compress(&state1, blocks, 2, BLAKE2S_BLOCK_SIZE);
+               blake2s_compress_generic(&state2, blocks, 2, BLAKE2S_BLOCK_SIZE);
+               if (memcmp(&state1, &state2, sizeof(state1))) {
+                       pr_err("blake2s random compress self-test %d: FAIL\n",
+                              i + 1);
+                       success = false;
+               }
+#endif
+
+               memcpy(&state1, &state, sizeof(state1));
+               blake2s_compress(&state1, blocks, 1, BLAKE2S_BLOCK_SIZE);
+               for (l = 1; l < TEST_ALIGNMENT; ++l) {
+                       memcpy(unaligned_block + l, blocks,
+                              BLAKE2S_BLOCK_SIZE);
+                       memcpy(&state2, &state, sizeof(state2));
+                       blake2s_compress(&state2, unaligned_block + l, 1,
+                                        BLAKE2S_BLOCK_SIZE);
+                       if (memcmp(&state1, &state2, sizeof(state1))) {
+                               pr_err("blake2s random compress align %d self-test %d: FAIL\n",
+                                      l, i + 1);
+                               success = false;
+                       }
+               }
+       }
+
        return success;
 }
index c71c096..98e688c 100644 (file)
 #include <linux/init.h>
 #include <linux/bug.h>
 
+static inline void blake2s_set_lastblock(struct blake2s_state *state)
+{
+       state->f[0] = -1;
+}
+
 void blake2s_update(struct blake2s_state *state, const u8 *in, size_t inlen)
 {
-       __blake2s_update(state, in, inlen, false);
+       const size_t fill = BLAKE2S_BLOCK_SIZE - state->buflen;
+
+       if (unlikely(!inlen))
+               return;
+       if (inlen > fill) {
+               memcpy(state->buf + state->buflen, in, fill);
+               blake2s_compress(state, state->buf, 1, BLAKE2S_BLOCK_SIZE);
+               state->buflen = 0;
+               in += fill;
+               inlen -= fill;
+       }
+       if (inlen > BLAKE2S_BLOCK_SIZE) {
+               const size_t nblocks = DIV_ROUND_UP(inlen, BLAKE2S_BLOCK_SIZE);
+               blake2s_compress(state, in, nblocks - 1, BLAKE2S_BLOCK_SIZE);
+               in += BLAKE2S_BLOCK_SIZE * (nblocks - 1);
+               inlen -= BLAKE2S_BLOCK_SIZE * (nblocks - 1);
+       }
+       memcpy(state->buf + state->buflen, in, inlen);
+       state->buflen += inlen;
 }
 EXPORT_SYMBOL(blake2s_update);
 
 void blake2s_final(struct blake2s_state *state, u8 *out)
 {
        WARN_ON(IS_ENABLED(DEBUG) && !out);
-       __blake2s_final(state, out, false);
+       blake2s_set_lastblock(state);
+       memset(state->buf + state->buflen, 0,
+              BLAKE2S_BLOCK_SIZE - state->buflen); /* Padding */
+       blake2s_compress(state, state->buf, 1, state->buflen);
+       cpu_to_le32_array(state->h, ARRAY_SIZE(state->h));
+       memcpy(out, state->h, state->outlen);
        memzero_explicit(state, sizeof(*state));
 }
 EXPORT_SYMBOL(blake2s_final);
@@ -38,12 +66,7 @@ static int __init blake2s_mod_init(void)
        return 0;
 }
 
-static void __exit blake2s_mod_exit(void)
-{
-}
-
 module_init(blake2s_mod_init);
-module_exit(blake2s_mod_exit);
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("BLAKE2s hash function");
 MODULE_AUTHOR("Jason A. Donenfeld <Jason@zx2c4.com>");
similarity index 98%
rename from lib/sha1.c
rename to lib/crypto/sha1.c
index 0494766..1aebe7b 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <linux/kernel.h>
 #include <linux/export.h>
+#include <linux/module.h>
 #include <linux/bitops.h>
 #include <linux/string.h>
 #include <crypto/sha1.h>
@@ -135,3 +136,5 @@ void sha1_init(__u32 *buf)
        buf[4] = 0xc3d2e1f0;
 }
 EXPORT_SYMBOL(sha1_init);
+
+MODULE_LICENSE("GPL");
index f4ab4f4..7ecdfdb 100644 (file)
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -491,7 +491,8 @@ void ida_free(struct ida *ida, unsigned int id)
        struct ida_bitmap *bitmap;
        unsigned long flags;
 
-       BUG_ON((int)id < 0);
+       if ((int)id < 0)
+               return;
 
        xas_lock_irqsave(&xas, flags);
        bitmap = xas_load(&xas);
index 0b64695..507e732 100644 (file)
@@ -1268,6 +1268,98 @@ void iov_iter_discard(struct iov_iter *i, unsigned int direction, size_t count)
 }
 EXPORT_SYMBOL(iov_iter_discard);
 
+static bool iov_iter_aligned_iovec(const struct iov_iter *i, unsigned addr_mask,
+                                  unsigned len_mask)
+{
+       size_t size = i->count;
+       size_t skip = i->iov_offset;
+       unsigned k;
+
+       for (k = 0; k < i->nr_segs; k++, skip = 0) {
+               size_t len = i->iov[k].iov_len - skip;
+
+               if (len > size)
+                       len = size;
+               if (len & len_mask)
+                       return false;
+               if ((unsigned long)(i->iov[k].iov_base + skip) & addr_mask)
+                       return false;
+
+               size -= len;
+               if (!size)
+                       break;
+       }
+       return true;
+}
+
+static bool iov_iter_aligned_bvec(const struct iov_iter *i, unsigned addr_mask,
+                                 unsigned len_mask)
+{
+       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;
+
+               if (len > size)
+                       len = size;
+               if (len & len_mask)
+                       return false;
+               if ((unsigned long)(i->bvec[k].bv_offset + skip) & addr_mask)
+                       return false;
+
+               size -= len;
+               if (!size)
+                       break;
+       }
+       return true;
+}
+
+/**
+ * iov_iter_is_aligned() - Check if the addresses and lengths of each segments
+ *     are aligned to the parameters.
+ *
+ * @i: &struct iov_iter to restore
+ * @addr_mask: bit mask to check against the iov element's addresses
+ * @len_mask: bit mask to check against the iov element's lengths
+ *
+ * Return: false if any addresses or lengths intersect with the provided masks
+ */
+bool iov_iter_is_aligned(const struct iov_iter *i, unsigned addr_mask,
+                        unsigned len_mask)
+{
+       if (likely(iter_is_iovec(i) || iov_iter_is_kvec(i)))
+               return iov_iter_aligned_iovec(i, addr_mask, len_mask);
+
+       if (iov_iter_is_bvec(i))
+               return iov_iter_aligned_bvec(i, addr_mask, len_mask);
+
+       if (iov_iter_is_pipe(i)) {
+               unsigned int p_mask = i->pipe->ring_size - 1;
+               size_t size = i->count;
+
+               if (size & len_mask)
+                       return false;
+               if (size && allocated(&i->pipe->bufs[i->head & p_mask])) {
+                       if (i->iov_offset & addr_mask)
+                               return false;
+               }
+
+               return true;
+       }
+
+       if (iov_iter_is_xarray(i)) {
+               if (i->count & len_mask)
+                       return false;
+               if ((i->xarray_start + i->iov_offset) & addr_mask)
+                       return false;
+       }
+
+       return true;
+}
+EXPORT_SYMBOL_GPL(iov_iter_is_aligned);
+
 static unsigned long iov_iter_alignment_iovec(const struct iov_iter *i)
 {
        unsigned long res = 0;
index 96f96e4..5e22332 100644 (file)
@@ -9,8 +9,8 @@
  * These symbols point to the .kunit_test_suites section and are defined in
  * include/asm-generic/vmlinux.lds.h, and consequently must be extern.
  */
-extern struct kunit_suite * const * const __kunit_suites_start[];
-extern struct kunit_suite * const * const __kunit_suites_end[];
+extern struct kunit_suite * const __kunit_suites_start[];
+extern struct kunit_suite * const __kunit_suites_end[];
 
 #if IS_BUILTIN(CONFIG_KUNIT)
 
@@ -55,7 +55,7 @@ static void kunit_parse_filter_glob(struct kunit_test_filter *parsed,
 
 /* Create a copy of suite with only tests that match test_glob. */
 static struct kunit_suite *
-kunit_filter_tests(struct kunit_suite *const suite, const char *test_glob)
+kunit_filter_tests(const struct kunit_suite *const suite, const char *test_glob)
 {
        int n = 0;
        struct kunit_case *filtered, *test_case;
@@ -69,15 +69,15 @@ kunit_filter_tests(struct kunit_suite *const suite, const char *test_glob)
        if (n == 0)
                return NULL;
 
-       /* Use memcpy to workaround copy->name being const. */
-       copy = kmalloc(sizeof(*copy), GFP_KERNEL);
+       copy = kmemdup(suite, sizeof(*copy), GFP_KERNEL);
        if (!copy)
                return ERR_PTR(-ENOMEM);
-       memcpy(copy, suite, sizeof(*copy));
 
        filtered = kcalloc(n + 1, sizeof(*filtered), GFP_KERNEL);
-       if (!filtered)
+       if (!filtered) {
+               kfree(copy);
                return ERR_PTR(-ENOMEM);
+       }
 
        n = 0;
        kunit_suite_for_each_test_case(suite, test_case) {
@@ -92,62 +92,18 @@ kunit_filter_tests(struct kunit_suite *const suite, const char *test_glob)
 static char *kunit_shutdown;
 core_param(kunit_shutdown, kunit_shutdown, charp, 0644);
 
-static struct kunit_suite * const *
-kunit_filter_subsuite(struct kunit_suite * const * const subsuite,
-                     struct kunit_test_filter *filter)
-{
-       int i, n = 0;
-       struct kunit_suite **filtered, *filtered_suite;
-
-       n = 0;
-       for (i = 0; subsuite[i]; ++i) {
-               if (glob_match(filter->suite_glob, subsuite[i]->name))
-                       ++n;
-       }
-
-       if (n == 0)
-               return NULL;
-
-       filtered = kmalloc_array(n + 1, sizeof(*filtered), GFP_KERNEL);
-       if (!filtered)
-               return ERR_PTR(-ENOMEM);
-
-       n = 0;
-       for (i = 0; subsuite[i] != NULL; ++i) {
-               if (!glob_match(filter->suite_glob, subsuite[i]->name))
-                       continue;
-               filtered_suite = kunit_filter_tests(subsuite[i], filter->test_glob);
-               if (IS_ERR(filtered_suite))
-                       return ERR_CAST(filtered_suite);
-               else if (filtered_suite)
-                       filtered[n++] = filtered_suite;
-       }
-       filtered[n] = NULL;
-
-       return filtered;
-}
-
+/* Stores an array of suites, end points one past the end */
 struct suite_set {
-       struct kunit_suite * const * const *start;
-       struct kunit_suite * const * const *end;
+       struct kunit_suite * const *start;
+       struct kunit_suite * const *end;
 };
 
-static void kunit_free_subsuite(struct kunit_suite * const *subsuite)
-{
-       unsigned int i;
-
-       for (i = 0; subsuite[i]; i++)
-               kfree(subsuite[i]);
-
-       kfree(subsuite);
-}
-
 static void kunit_free_suite_set(struct suite_set suite_set)
 {
-       struct kunit_suite * const * const *suites;
+       struct kunit_suite * const *suites;
 
        for (suites = suite_set.start; suites < suite_set.end; suites++)
-               kunit_free_subsuite(*suites);
+               kfree(*suites);
        kfree(suite_set.start);
 }
 
@@ -156,7 +112,7 @@ static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,
                                            int *err)
 {
        int i;
-       struct kunit_suite * const **copy, * const *filtered_subsuite;
+       struct kunit_suite **copy, *filtered_suite;
        struct suite_set filtered;
        struct kunit_test_filter filter;
 
@@ -171,14 +127,19 @@ static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,
 
        kunit_parse_filter_glob(&filter, filter_glob);
 
-       for (i = 0; i < max; ++i) {
-               filtered_subsuite = kunit_filter_subsuite(suite_set->start[i], &filter);
-               if (IS_ERR(filtered_subsuite)) {
-                       *err = PTR_ERR(filtered_subsuite);
+       for (i = 0; &suite_set->start[i] != suite_set->end; i++) {
+               if (!glob_match(filter.suite_glob, suite_set->start[i]->name))
+                       continue;
+
+               filtered_suite = kunit_filter_tests(suite_set->start[i], filter.test_glob);
+               if (IS_ERR(filtered_suite)) {
+                       *err = PTR_ERR(filtered_suite);
                        return filtered;
                }
-               if (filtered_subsuite)
-                       *copy++ = filtered_subsuite;
+               if (!filtered_suite)
+                       continue;
+
+               *copy++ = filtered_suite;
        }
        filtered.end = copy;
 
@@ -201,52 +162,33 @@ static void kunit_handle_shutdown(void)
 
 }
 
-static void kunit_print_tap_header(struct suite_set *suite_set)
-{
-       struct kunit_suite * const * const *suites, * const *subsuite;
-       int num_of_suites = 0;
-
-       for (suites = suite_set->start; suites < suite_set->end; suites++)
-               for (subsuite = *suites; *subsuite != NULL; subsuite++)
-                       num_of_suites++;
-
-       pr_info("TAP version 14\n");
-       pr_info("1..%d\n", num_of_suites);
-}
-
 static void kunit_exec_run_tests(struct suite_set *suite_set)
 {
-       struct kunit_suite * const * const *suites;
+       size_t num_suites = suite_set->end - suite_set->start;
 
-       kunit_print_tap_header(suite_set);
+       pr_info("TAP version 14\n");
+       pr_info("1..%zu\n", num_suites);
 
-       for (suites = suite_set->start; suites < suite_set->end; suites++)
-               __kunit_test_suites_init(*suites);
+       __kunit_test_suites_init(suite_set->start, num_suites);
 }
 
 static void kunit_exec_list_tests(struct suite_set *suite_set)
 {
-       unsigned int i;
-       struct kunit_suite * const * const *suites;
+       struct kunit_suite * const *suites;
        struct kunit_case *test_case;
 
        /* Hack: print a tap header so kunit.py can find the start of KUnit output. */
        pr_info("TAP version 14\n");
 
        for (suites = suite_set->start; suites < suite_set->end; suites++)
-               for (i = 0; (*suites)[i] != NULL; i++) {
-                       kunit_suite_for_each_test_case((*suites)[i], test_case) {
-                               pr_info("%s.%s\n", (*suites)[i]->name, test_case->name);
-                       }
+               kunit_suite_for_each_test_case((*suites), test_case) {
+                       pr_info("%s.%s\n", (*suites)->name, test_case->name);
                }
 }
 
 int kunit_run_all_tests(void)
 {
-       struct suite_set suite_set = {
-               .start = __kunit_suites_start,
-               .end = __kunit_suites_end,
-       };
+       struct suite_set suite_set = {__kunit_suites_start, __kunit_suites_end};
        int err = 0;
 
        if (filter_glob_param) {
@@ -264,11 +206,10 @@ int kunit_run_all_tests(void)
        else
                pr_err("kunit executor: unknown action '%s'\n", action_param);
 
-       if (filter_glob_param) { /* a copy was made of each array */
+       if (filter_glob_param) { /* a copy was made of each suite */
                kunit_free_suite_set(suite_set);
        }
 
-
 out:
        kunit_handle_shutdown();
        return err;
index eac6ff4..0cea31c 100644 (file)
@@ -9,8 +9,6 @@
 #include <kunit/test.h>
 
 static void kfree_at_end(struct kunit *test, const void *to_free);
-static void free_subsuite_at_end(struct kunit *test,
-                                struct kunit_suite *const *to_free);
 static struct kunit_suite *alloc_fake_suite(struct kunit *test,
                                            const char *suite_name,
                                            struct kunit_case *test_cases);
@@ -41,126 +39,80 @@ static void parse_filter_test(struct kunit *test)
        kfree(filter.test_glob);
 }
 
-static void filter_subsuite_test(struct kunit *test)
+static void filter_suites_test(struct kunit *test)
 {
-       struct kunit_suite *subsuite[3] = {NULL, NULL, NULL};
-       struct kunit_suite * const *filtered;
-       struct kunit_test_filter filter = {
-               .suite_glob = "suite2",
-               .test_glob = NULL,
-       };
+       struct kunit_suite *subsuite[3] = {NULL, NULL};
+       struct suite_set suite_set = {.start = subsuite, .end = &subsuite[2]};
+       struct suite_set got;
+       int err = 0;
 
        subsuite[0] = alloc_fake_suite(test, "suite1", dummy_test_cases);
        subsuite[1] = alloc_fake_suite(test, "suite2", dummy_test_cases);
 
        /* Want: suite1, suite2, NULL -> suite2, NULL */
-       filtered = kunit_filter_subsuite(subsuite, &filter);
-       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filtered);
-       free_subsuite_at_end(test, filtered);
+       got = kunit_filter_suites(&suite_set, "suite2", &err);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start);
+       KUNIT_ASSERT_EQ(test, err, 0);
+       kfree_at_end(test, got.start);
 
        /* Validate we just have suite2 */
-       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filtered[0]);
-       KUNIT_EXPECT_STREQ(test, (const char *)filtered[0]->name, "suite2");
-       KUNIT_EXPECT_FALSE(test, filtered[1]);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]);
+       KUNIT_EXPECT_STREQ(test, (const char *)got.start[0]->name, "suite2");
+
+       /* Contains one element (end is 1 past end) */
+       KUNIT_ASSERT_EQ(test, got.end - got.start, 1);
 }
 
-static void filter_subsuite_test_glob_test(struct kunit *test)
+static void filter_suites_test_glob_test(struct kunit *test)
 {
-       struct kunit_suite *subsuite[3] = {NULL, NULL, NULL};
-       struct kunit_suite * const *filtered;
-       struct kunit_test_filter filter = {
-               .suite_glob = "suite2",
-               .test_glob = "test2",
-       };
+       struct kunit_suite *subsuite[3] = {NULL, NULL};
+       struct suite_set suite_set = {.start = subsuite, .end = &subsuite[2]};
+       struct suite_set got;
+       int err = 0;
 
        subsuite[0] = alloc_fake_suite(test, "suite1", dummy_test_cases);
        subsuite[1] = alloc_fake_suite(test, "suite2", dummy_test_cases);
 
        /* Want: suite1, suite2, NULL -> suite2 (just test1), NULL */
-       filtered = kunit_filter_subsuite(subsuite, &filter);
-       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filtered);
-       free_subsuite_at_end(test, filtered);
+       got = kunit_filter_suites(&suite_set, "suite2.test2", &err);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start);
+       KUNIT_ASSERT_EQ(test, err, 0);
+       kfree_at_end(test, got.start);
 
        /* Validate we just have suite2 */
-       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filtered[0]);
-       KUNIT_EXPECT_STREQ(test, (const char *)filtered[0]->name, "suite2");
-       KUNIT_EXPECT_FALSE(test, filtered[1]);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]);
+       KUNIT_EXPECT_STREQ(test, (const char *)got.start[0]->name, "suite2");
+       KUNIT_ASSERT_EQ(test, got.end - got.start, 1);
 
        /* Now validate we just have test2 */
-       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filtered[0]->test_cases);
-       KUNIT_EXPECT_STREQ(test, (const char *)filtered[0]->test_cases[0].name, "test2");
-       KUNIT_EXPECT_FALSE(test, filtered[0]->test_cases[1].name);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]->test_cases);
+       KUNIT_EXPECT_STREQ(test, (const char *)got.start[0]->test_cases[0].name, "test2");
+       KUNIT_EXPECT_FALSE(test, got.start[0]->test_cases[1].name);
 }
 
-static void filter_subsuite_to_empty_test(struct kunit *test)
+static void filter_suites_to_empty_test(struct kunit *test)
 {
-       struct kunit_suite *subsuite[3] = {NULL, NULL, NULL};
-       struct kunit_suite * const *filtered;
-       struct kunit_test_filter filter = {
-               .suite_glob = "not_found",
-               .test_glob = NULL,
-       };
+       struct kunit_suite *subsuite[3] = {NULL, NULL};
+       struct suite_set suite_set = {.start = subsuite, .end = &subsuite[2]};
+       struct suite_set got;
+       int err = 0;
 
        subsuite[0] = alloc_fake_suite(test, "suite1", dummy_test_cases);
        subsuite[1] = alloc_fake_suite(test, "suite2", dummy_test_cases);
 
-       filtered = kunit_filter_subsuite(subsuite, &filter);
-       free_subsuite_at_end(test, filtered); /* just in case */
+       got = kunit_filter_suites(&suite_set, "not_found", &err);
+       KUNIT_ASSERT_EQ(test, err, 0);
+       kfree_at_end(test, got.start); /* just in case */
 
-       KUNIT_EXPECT_FALSE_MSG(test, filtered,
-                              "should be NULL to indicate no match");
-}
-
-static void kfree_subsuites_at_end(struct kunit *test, struct suite_set *suite_set)
-{
-       struct kunit_suite * const * const *suites;
-
-       kfree_at_end(test, suite_set->start);
-       for (suites = suite_set->start; suites < suite_set->end; suites++)
-               free_subsuite_at_end(test, *suites);
-}
-
-static void filter_suites_test(struct kunit *test)
-{
-       /* Suites per-file are stored as a NULL terminated array */
-       struct kunit_suite *subsuites[2][2] = {
-               {NULL, NULL},
-               {NULL, NULL},
-       };
-       /* Match the memory layout of suite_set */
-       struct kunit_suite * const * const suites[2] = {
-               subsuites[0], subsuites[1],
-       };
-
-       const struct suite_set suite_set = {
-               .start = suites,
-               .end = suites + 2,
-       };
-       struct suite_set filtered = {.start = NULL, .end = NULL};
-       int err = 0;
-
-       /* Emulate two files, each having one suite */
-       subsuites[0][0] = alloc_fake_suite(test, "suite0", dummy_test_cases);
-       subsuites[1][0] = alloc_fake_suite(test, "suite1", dummy_test_cases);
-
-       /* Filter out suite1 */
-       filtered = kunit_filter_suites(&suite_set, "suite0", &err);
-       kfree_subsuites_at_end(test, &filtered); /* let us use ASSERTs without leaking */
-       KUNIT_EXPECT_EQ(test, err, 0);
-       KUNIT_ASSERT_EQ(test, filtered.end - filtered.start, (ptrdiff_t)1);
-
-       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filtered.start);
-       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filtered.start[0]);
-       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filtered.start[0][0]);
-       KUNIT_EXPECT_STREQ(test, (const char *)filtered.start[0][0]->name, "suite0");
+       KUNIT_EXPECT_PTR_EQ_MSG(test, got.start, got.end,
+                               "should be empty to indicate no match");
 }
 
 static struct kunit_case executor_test_cases[] = {
        KUNIT_CASE(parse_filter_test),
-       KUNIT_CASE(filter_subsuite_test),
-       KUNIT_CASE(filter_subsuite_test_glob_test),
-       KUNIT_CASE(filter_subsuite_to_empty_test),
        KUNIT_CASE(filter_suites_test),
+       KUNIT_CASE(filter_suites_test_glob_test),
+       KUNIT_CASE(filter_suites_to_empty_test),
        {}
 };
 
@@ -190,20 +142,6 @@ static void kfree_at_end(struct kunit *test, const void *to_free)
                             (void *)to_free);
 }
 
-static void free_subsuite_res_free(struct kunit_resource *res)
-{
-       kunit_free_subsuite(res->data);
-}
-
-static void free_subsuite_at_end(struct kunit *test,
-                                struct kunit_suite *const *to_free)
-{
-       if (IS_ERR_OR_NULL(to_free))
-               return;
-       kunit_alloc_resource(test, NULL, free_subsuite_res_free,
-                            GFP_KERNEL, (void *)to_free);
-}
-
 static struct kunit_suite *alloc_fake_suite(struct kunit *test,
                                            const char *suite_name,
                                            struct kunit_case *test_cases)
index a5053a0..b73d5bb 100644 (file)
@@ -10,7 +10,9 @@
 #include <kunit/test.h>
 #include <kunit/test-bug.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/panic.h>
 #include <linux/sched/debug.h>
 #include <linux/sched.h>
 
@@ -501,6 +503,9 @@ int kunit_run_tests(struct kunit_suite *suite)
        struct kunit_result_stats suite_stats = { 0 };
        struct kunit_result_stats total_stats = { 0 };
 
+       /* Taint the kernel so we know we've run tests. */
+       add_taint(TAINT_TEST, LOCKDEP_STILL_OK);
+
        if (suite->suite_init) {
                suite->suite_init_err = suite->suite_init(suite);
                if (suite->suite_init_err) {
@@ -581,11 +586,11 @@ static void kunit_init_suite(struct kunit_suite *suite)
        suite->suite_init_err = 0;
 }
 
-int __kunit_test_suites_init(struct kunit_suite * const * const suites)
+int __kunit_test_suites_init(struct kunit_suite * const * const suites, int num_suites)
 {
        unsigned int i;
 
-       for (i = 0; suites[i] != NULL; i++) {
+       for (i = 0; i < num_suites; i++) {
                kunit_init_suite(suites[i]);
                kunit_run_tests(suites[i]);
        }
@@ -598,17 +603,54 @@ static void kunit_exit_suite(struct kunit_suite *suite)
        kunit_debugfs_destroy_suite(suite);
 }
 
-void __kunit_test_suites_exit(struct kunit_suite **suites)
+void __kunit_test_suites_exit(struct kunit_suite **suites, int num_suites)
 {
        unsigned int i;
 
-       for (i = 0; suites[i] != NULL; i++)
+       for (i = 0; i < num_suites; i++)
                kunit_exit_suite(suites[i]);
 
        kunit_suite_counter = 1;
 }
 EXPORT_SYMBOL_GPL(__kunit_test_suites_exit);
 
+#ifdef CONFIG_MODULES
+static void kunit_module_init(struct module *mod)
+{
+       __kunit_test_suites_init(mod->kunit_suites, mod->num_kunit_suites);
+}
+
+static void kunit_module_exit(struct module *mod)
+{
+       __kunit_test_suites_exit(mod->kunit_suites, mod->num_kunit_suites);
+}
+
+static int kunit_module_notify(struct notifier_block *nb, unsigned long val,
+                              void *data)
+{
+       struct module *mod = data;
+
+       switch (val) {
+       case MODULE_STATE_LIVE:
+               kunit_module_init(mod);
+               break;
+       case MODULE_STATE_GOING:
+               kunit_module_exit(mod);
+               break;
+       case MODULE_STATE_COMING:
+       case MODULE_STATE_UNFORMED:
+               break;
+       }
+
+       return 0;
+}
+
+static struct notifier_block kunit_mod_nb = {
+       .notifier_call = kunit_module_notify,
+       .priority = 0,
+};
+#endif
+
 struct kunit_kmalloc_array_params {
        size_t n;
        size_t size;
@@ -703,13 +745,19 @@ EXPORT_SYMBOL_GPL(kunit_cleanup);
 static int __init kunit_init(void)
 {
        kunit_debugfs_init();
-
+#ifdef CONFIG_MODULES
+       return register_module_notifier(&kunit_mod_nb);
+#else
        return 0;
+#endif
 }
 late_initcall(kunit_init);
 
 static void __exit kunit_exit(void)
 {
+#ifdef CONFIG_MODULES
+       unregister_module_notifier(&kunit_mod_nb);
+#endif
        kunit_debugfs_cleanup();
 }
 module_exit(kunit_exit);
index c6f0b18..45e93ec 100644 (file)
@@ -111,31 +111,6 @@ int lockref_put_not_zero(struct lockref *lockref)
 EXPORT_SYMBOL(lockref_put_not_zero);
 
 /**
- * lockref_get_or_lock - Increments count unless the count is 0 or dead
- * @lockref: pointer to lockref structure
- * Return: 1 if count updated successfully or 0 if count was zero
- * and we got the lock instead.
- */
-int lockref_get_or_lock(struct lockref *lockref)
-{
-       CMPXCHG_LOOP(
-               new.count++;
-               if (old.count <= 0)
-                       break;
-       ,
-               return 1;
-       );
-
-       spin_lock(&lockref->lock);
-       if (lockref->count <= 0)
-               return 0;
-       lockref->count++;
-       spin_unlock(&lockref->lock);
-       return 1;
-}
-EXPORT_SYMBOL(lockref_get_or_lock);
-
-/**
  * lockref_put_return - Decrement reference count if possible
  * @lockref: pointer to lockref structure
  *
index 2cdae54..9056fc5 100644 (file)
@@ -138,7 +138,7 @@ void mpi_sub(MPI w, MPI u, MPI v)
        mpi_add(w, u, vv);
        mpi_free(vv);
 }
-
+EXPORT_SYMBOL_GPL(mpi_sub);
 
 void mpi_addm(MPI w, MPI u, MPI v, MPI m)
 {
index 8f5fa20..7f4eda8 100644 (file)
@@ -82,6 +82,7 @@ void mpi_mul(MPI w, MPI u, MPI v)
        if (tmp_limb)
                mpi_free_limb_space(tmp_limb);
 }
+EXPORT_SYMBOL_GPL(mpi_mul);
 
 void mpi_mulm(MPI w, MPI u, MPI v, MPI m)
 {
index 475f0c0..7e3e436 100644 (file)
@@ -91,6 +91,7 @@ DEFINE_TEST_ARRAY(u32) = {
        {-4U, 5U, 1U, -9U, -20U, true, false, true},
 };
 
+#if BITS_PER_LONG == 64
 DEFINE_TEST_ARRAY(u64) = {
        {0, 0, 0, 0, 0, false, false, false},
        {1, 1, 2, 0, 1, false, false, false},
@@ -114,6 +115,7 @@ DEFINE_TEST_ARRAY(u64) = {
         false, true, false},
        {-15ULL, 10ULL, -5ULL, -25ULL, -150ULL, false, false, true},
 };
+#endif
 
 DEFINE_TEST_ARRAY(s8) = {
        {0, 0, 0, 0, 0, false, false, false},
@@ -188,6 +190,8 @@ DEFINE_TEST_ARRAY(s32) = {
        {S32_MIN, S32_MIN, 0, 0, 0, true, false, true},
        {S32_MAX, S32_MAX, -2, 0, 1, true, false, true},
 };
+
+#if BITS_PER_LONG == 64
 DEFINE_TEST_ARRAY(s64) = {
        {0, 0, 0, 0, 0, false, false, false},
 
@@ -216,6 +220,7 @@ DEFINE_TEST_ARRAY(s64) = {
        {-128, -1, -129, -127, 128, false, false, false},
        {0, -S64_MAX, -S64_MAX, S64_MAX, 0, false, false, false},
 };
+#endif
 
 #define check_one_op(t, fmt, op, sym, a, b, r, of) do {                \
        t _r;                                                   \
@@ -650,6 +655,7 @@ static struct kunit_case overflow_test_cases[] = {
        KUNIT_CASE(s16_overflow_test),
        KUNIT_CASE(u32_overflow_test),
        KUNIT_CASE(s32_overflow_test),
+/* Clang 13 and earlier generate unwanted libcalls on 32-bit. */
 #if BITS_PER_LONG == 64
        KUNIT_CASE(u64_overflow_test),
        KUNIT_CASE(s64_overflow_test),
index ae4fd4d..29eb048 100644 (file)
@@ -528,7 +528,7 @@ unsigned long __sbitmap_queue_get_batch(struct sbitmap_queue *sbq, int nr_tags,
 
                sbitmap_deferred_clear(map);
                if (map->word == (1UL << (map_depth - 1)) - 1)
-                       continue;
+                       goto next;
 
                nr = find_first_zero_bit(&map->word, map_depth);
                if (nr + nr_tags <= map_depth) {
@@ -539,6 +539,8 @@ unsigned long __sbitmap_queue_get_batch(struct sbitmap_queue *sbq, int nr_tags,
                        get_mask = ((1UL << map_tags) - 1) << nr;
                        do {
                                val = READ_ONCE(map->word);
+                               if ((val & ~get_mask) != val)
+                                       goto next;
                                ret = atomic_long_cmpxchg(ptr, val, get_mask | val);
                        } while (ret != val);
                        get_mask = (get_mask & ~ret) >> nr;
@@ -549,6 +551,7 @@ unsigned long __sbitmap_queue_get_batch(struct sbitmap_queue *sbq, int nr_tags,
                                return get_mask;
                        }
                }
+next:
                /* Jump to next index. */
                if (++index >= sb->map_nr)
                        index = 0;
index c233b1a..58c1b01 100644 (file)
@@ -131,6 +131,7 @@ static void kmalloc_oob_right(struct kunit *test)
        ptr = kmalloc(size, GFP_KERNEL);
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
 
+       OPTIMIZER_HIDE_VAR(ptr);
        /*
         * An unaligned access past the requested kmalloc size.
         * Only generic KASAN can precisely detect these.
@@ -159,6 +160,7 @@ static void kmalloc_oob_left(struct kunit *test)
        ptr = kmalloc(size, GFP_KERNEL);
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
 
+       OPTIMIZER_HIDE_VAR(ptr);
        KUNIT_EXPECT_KASAN_FAIL(test, *ptr = *(ptr - 1));
        kfree(ptr);
 }
@@ -171,6 +173,7 @@ static void kmalloc_node_oob_right(struct kunit *test)
        ptr = kmalloc_node(size, GFP_KERNEL, 0);
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
 
+       OPTIMIZER_HIDE_VAR(ptr);
        KUNIT_EXPECT_KASAN_FAIL(test, ptr[0] = ptr[size]);
        kfree(ptr);
 }
@@ -191,6 +194,7 @@ static void kmalloc_pagealloc_oob_right(struct kunit *test)
        ptr = kmalloc(size, GFP_KERNEL);
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
 
+       OPTIMIZER_HIDE_VAR(ptr);
        KUNIT_EXPECT_KASAN_FAIL(test, ptr[size + OOB_TAG_OFF] = 0);
 
        kfree(ptr);
@@ -271,6 +275,7 @@ static void kmalloc_large_oob_right(struct kunit *test)
        ptr = kmalloc(size, GFP_KERNEL);
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
 
+       OPTIMIZER_HIDE_VAR(ptr);
        KUNIT_EXPECT_KASAN_FAIL(test, ptr[size] = 0);
        kfree(ptr);
 }
@@ -410,6 +415,8 @@ static void kmalloc_oob_16(struct kunit *test)
        ptr2 = kmalloc(sizeof(*ptr2), GFP_KERNEL);
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr2);
 
+       OPTIMIZER_HIDE_VAR(ptr1);
+       OPTIMIZER_HIDE_VAR(ptr2);
        KUNIT_EXPECT_KASAN_FAIL(test, *ptr1 = *ptr2);
        kfree(ptr1);
        kfree(ptr2);
@@ -756,6 +763,8 @@ static void ksize_unpoisons_memory(struct kunit *test)
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
        real_size = ksize(ptr);
 
+       OPTIMIZER_HIDE_VAR(ptr);
+
        /* This access shouldn't trigger a KASAN report. */
        ptr[size] = 'x';
 
@@ -778,6 +787,7 @@ static void ksize_uaf(struct kunit *test)
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
        kfree(ptr);
 
+       OPTIMIZER_HIDE_VAR(ptr);
        KUNIT_EXPECT_KASAN_FAIL(test, ksize(ptr));
        KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr)[0]);
        KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr)[size]);
index 8efbfb2..4b07c29 100644 (file)
@@ -374,6 +374,8 @@ static void damon_reclaim_timer_fn(struct work_struct *work)
 }
 static DECLARE_DELAYED_WORK(damon_reclaim_timer, damon_reclaim_timer_fn);
 
+static bool damon_reclaim_initialized;
+
 static int enabled_store(const char *val,
                const struct kernel_param *kp)
 {
@@ -382,6 +384,10 @@ static int enabled_store(const char *val,
        if (rc < 0)
                return rc;
 
+       /* system_wq might not initialized yet */
+       if (!damon_reclaim_initialized)
+               return rc;
+
        if (enabled)
                schedule_delayed_work(&damon_reclaim_timer, 0);
 
@@ -449,6 +455,8 @@ static int __init damon_reclaim_init(void)
        damon_add_target(ctx, target);
 
        schedule_delayed_work(&damon_reclaim_timer, 0);
+
+       damon_reclaim_initialized = true;
        return 0;
 }
 
index 59e1653..3c7b9d6 100644 (file)
@@ -336,8 +336,7 @@ static void damon_hugetlb_mkold(pte_t *pte, struct mm_struct *mm,
        if (pte_young(entry)) {
                referenced = true;
                entry = pte_mkold(entry);
-               huge_ptep_set_access_flags(vma, addr, pte, entry,
-                                          vma->vm_flags & VM_WRITE);
+               set_huge_pte_at(mm, addr, pte, entry);
        }
 
 #ifdef CONFIG_MMU_NOTIFIER
index 8ccb868..0dec96e 100644 (file)
@@ -1968,6 +1968,10 @@ no_page:
                        gfp |= __GFP_WRITE;
                if (fgp_flags & FGP_NOFS)
                        gfp &= ~__GFP_FS;
+               if (fgp_flags & FGP_NOWAIT) {
+                       gfp &= ~GFP_KERNEL;
+                       gfp |= GFP_NOWAIT | __GFP_NOWARN;
+               }
 
                folio = filemap_alloc_folio(gfp, 0);
                if (!folio)
index 5512644..e2a39e3 100644 (file)
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -87,7 +87,8 @@ retry:
         * belongs to this folio.
         */
        if (unlikely(page_folio(page) != folio)) {
-               folio_put_refs(folio, refs);
+               if (!put_devmap_managed_page_refs(&folio->page, refs))
+                       folio_put_refs(folio, refs);
                goto retry;
        }
 
@@ -176,7 +177,8 @@ static void gup_put_folio(struct folio *folio, int refs, unsigned int flags)
                        refs *= GUP_PIN_COUNTING_BIAS;
        }
 
-       folio_put_refs(folio, refs);
+       if (!put_devmap_managed_page_refs(&folio->page, refs))
+               folio_put_refs(folio, refs);
 }
 
 /**
index 3fd3242..f2aa63b 100644 (file)
--- a/mm/hmm.c
+++ b/mm/hmm.c
@@ -212,14 +212,6 @@ int hmm_vma_handle_pmd(struct mm_walk *walk, unsigned long addr,
                unsigned long end, unsigned long hmm_pfns[], pmd_t pmd);
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
-static inline bool hmm_is_device_private_entry(struct hmm_range *range,
-               swp_entry_t entry)
-{
-       return is_device_private_entry(entry) &&
-               pfn_swap_entry_to_page(entry)->pgmap->owner ==
-               range->dev_private_owner;
-}
-
 static inline unsigned long pte_to_hmm_pfn_flags(struct hmm_range *range,
                                                 pte_t pte)
 {
@@ -252,10 +244,12 @@ static int hmm_vma_handle_pte(struct mm_walk *walk, unsigned long addr,
                swp_entry_t entry = pte_to_swp_entry(pte);
 
                /*
-                * Never fault in device private pages, but just report
-                * the PFN even if not present.
+                * Don't fault in device private pages owned by the caller,
+                * just report the PFN.
                 */
-               if (hmm_is_device_private_entry(range, entry)) {
+               if (is_device_private_entry(entry) &&
+                   pfn_swap_entry_to_page(entry)->pgmap->owner ==
+                   range->dev_private_owner) {
                        cpu_flags = HMM_PFN_VALID;
                        if (is_writable_device_private_entry(entry))
                                cpu_flags |= HMM_PFN_WRITE;
@@ -273,6 +267,9 @@ static int hmm_vma_handle_pte(struct mm_walk *walk, unsigned long addr,
                if (!non_swap_entry(entry))
                        goto fault;
 
+               if (is_device_private_entry(entry))
+                       goto fault;
+
                if (is_device_exclusive_entry(entry))
                        goto fault;
 
index 33b2c27..aa39534 100644 (file)
@@ -4788,8 +4788,13 @@ again:
                         * sharing with another vma.
                         */
                        ;
-               } else if (unlikely(is_hugetlb_entry_migration(entry) ||
-                                   is_hugetlb_entry_hwpoisoned(entry))) {
+               } else if (unlikely(is_hugetlb_entry_hwpoisoned(entry))) {
+                       bool uffd_wp = huge_pte_uffd_wp(entry);
+
+                       if (!userfaultfd_wp(dst_vma) && uffd_wp)
+                               entry = huge_pte_clear_uffd_wp(entry);
+                       set_huge_pte_at(dst, addr, dst_pte, entry);
+               } else if (unlikely(is_hugetlb_entry_migration(entry))) {
                        swp_entry_t swp_entry = pte_to_swp_entry(entry);
                        bool uffd_wp = huge_pte_uffd_wp(entry);
 
@@ -5953,6 +5958,7 @@ int hugetlb_mcopy_atomic_pte(struct mm_struct *dst_mm,
 
                page = alloc_huge_page(dst_vma, dst_addr, 0);
                if (IS_ERR(page)) {
+                       put_page(*pagep);
                        ret = -ENOMEM;
                        *pagep = NULL;
                        goto out;
index 5c0cddd..65e242b 100644 (file)
@@ -48,7 +48,7 @@ static int hwpoison_inject(void *data, u64 val)
 
 inject:
        pr_info("Injecting memory failure at pfn %#lx\n", pfn);
-       err = memory_failure(pfn, 0);
+       err = memory_failure(pfn, MF_SW_SIMULATED);
        return (err == -EOPNOTSUPP) ? 0 : err;
 }
 
index 5fe598e..8652426 100644 (file)
 #include <linux/io.h>
 #include <linux/export.h>
 
-void __iomem *ioremap_prot(phys_addr_t addr, size_t size, unsigned long prot)
+void __iomem *ioremap_prot(phys_addr_t phys_addr, size_t size,
+                          unsigned long prot)
 {
        unsigned long offset, vaddr;
        phys_addr_t last_addr;
        struct vm_struct *area;
 
        /* Disallow wrap-around or zero size */
-       last_addr = addr + size - 1;
-       if (!size || last_addr < addr)
+       last_addr = phys_addr + size - 1;
+       if (!size || last_addr < phys_addr)
                return NULL;
 
        /* Page-align mappings */
-       offset = addr & (~PAGE_MASK);
-       addr -= offset;
+       offset = phys_addr & (~PAGE_MASK);
+       phys_addr -= offset;
        size = PAGE_ALIGN(size + offset);
 
+       if (!ioremap_allowed(phys_addr, size, prot))
+               return NULL;
+
        area = get_vm_area_caller(size, VM_IOREMAP,
                        __builtin_return_address(0));
        if (!area)
                return NULL;
        vaddr = (unsigned long)area->addr;
+       area->phys_addr = phys_addr;
 
-       if (ioremap_page_range(vaddr, vaddr + size, addr, __pgprot(prot))) {
+       if (ioremap_page_range(vaddr, vaddr + size, phys_addr,
+                              __pgprot(prot))) {
                free_vm_area(area);
                return NULL;
        }
@@ -44,6 +50,12 @@ EXPORT_SYMBOL(ioremap_prot);
 
 void iounmap(volatile void __iomem *addr)
 {
-       vunmap((void *)((unsigned long)addr & PAGE_MASK));
+       void *vaddr = (void *)((unsigned long)addr & PAGE_MASK);
+
+       if (!iounmap_allowed(vaddr))
+               return;
+
+       if (is_vmalloc_addr(vaddr))
+               vunmap(vaddr);
 }
 EXPORT_SYMBOL(iounmap);
index c40c0e7..78be2be 100644 (file)
@@ -108,9 +108,10 @@ void __kasan_unpoison_pages(struct page *page, unsigned int order, bool init)
                return;
 
        tag = kasan_random_tag();
+       kasan_unpoison(set_tag(page_address(page), tag),
+                      PAGE_SIZE << order, init);
        for (i = 0; i < (1 << order); i++)
                page_kasan_tag_set(page + i, tag);
-       kasan_unpoison(page_address(page), PAGE_SIZE << order, init);
 }
 
 void __kasan_poison_pages(struct page *page, unsigned int order, bool init)
index 4e7cd4c..6aff49f 100644 (file)
@@ -360,6 +360,9 @@ static void *kfence_guarded_alloc(struct kmem_cache *cache, size_t size, gfp_t g
        unsigned long flags;
        struct slab *slab;
        void *addr;
+       const bool random_right_allocate = prandom_u32_max(2);
+       const bool random_fault = CONFIG_KFENCE_STRESS_TEST_FAULTS &&
+                                 !prandom_u32_max(CONFIG_KFENCE_STRESS_TEST_FAULTS);
 
        /* Try to obtain a free object. */
        raw_spin_lock_irqsave(&kfence_freelist_lock, flags);
@@ -404,7 +407,7 @@ static void *kfence_guarded_alloc(struct kmem_cache *cache, size_t size, gfp_t g
         * is that the out-of-bounds accesses detected are deterministic for
         * such allocations.
         */
-       if (prandom_u32_max(2)) {
+       if (random_right_allocate) {
                /* Allocate on the "right" side, re-calculate address. */
                meta->addr += PAGE_SIZE - size;
                meta->addr = ALIGN_DOWN(meta->addr, cache->align);
@@ -444,7 +447,7 @@ static void *kfence_guarded_alloc(struct kmem_cache *cache, size_t size, gfp_t g
        if (cache->ctor)
                cache->ctor(addr);
 
-       if (CONFIG_KFENCE_STRESS_TEST_FAULTS && !prandom_u32_max(CONFIG_KFENCE_STRESS_TEST_FAULTS))
+       if (random_fault)
                kfence_protect(meta->addr); /* Random "faults" by protecting the object. */
 
        atomic_long_inc(&counters[KFENCE_COUNTER_ALLOCATED]);
@@ -600,14 +603,6 @@ static unsigned long kfence_init_pool(void)
                addr += 2 * PAGE_SIZE;
        }
 
-       /*
-        * The pool is live and will never be deallocated from this point on.
-        * Remove the pool object from the kmemleak object tree, as it would
-        * otherwise overlap with allocations returned by kfence_alloc(), which
-        * are registered with kmemleak through the slab post-alloc hook.
-        */
-       kmemleak_free(__kfence_pool);
-
        return 0;
 }
 
@@ -620,8 +615,16 @@ static bool __init kfence_init_pool_early(void)
 
        addr = kfence_init_pool();
 
-       if (!addr)
+       if (!addr) {
+               /*
+                * The pool is live and will never be deallocated from this point on.
+                * Ignore the pool object from the kmemleak phys object tree, as it would
+                * otherwise overlap with allocations returned by kfence_alloc(), which
+                * are registered with kmemleak through the slab post-alloc hook.
+                */
+               kmemleak_ignore_phys(__pa(__kfence_pool));
                return true;
+       }
 
        /*
         * Only release unprotected pages, and do not try to go back and change
index d7b4f26..0316bbc 100644 (file)
@@ -1112,7 +1112,7 @@ static int madvise_inject_error(int behavior,
                } else {
                        pr_info("Injecting memory failure for pfn %#lx at process virtual address %#lx\n",
                                 pfn, start);
-                       ret = memory_failure(pfn, MF_COUNT_INCREASED);
+                       ret = memory_failure(pfn, MF_COUNT_INCREASED | MF_SW_SIMULATED);
                        if (ret == -EOPNOTSUPP)
                                ret = 0;
                }
index abec50f..618c366 100644 (file)
@@ -4859,7 +4859,7 @@ static int mem_cgroup_slab_show(struct seq_file *m, void *p)
 {
        /*
         * Deprecated.
-        * Please, take a look at tools/cgroup/slabinfo.py .
+        * Please, take a look at tools/cgroup/memcg_slabinfo.py .
         */
        return 0;
 }
index a859486..b864c2e 100644 (file)
@@ -69,6 +69,8 @@ int sysctl_memory_failure_recovery __read_mostly = 1;
 
 atomic_long_t num_poisoned_pages __read_mostly = ATOMIC_LONG_INIT(0);
 
+static bool hw_memory_failure __read_mostly = false;
+
 static bool __page_handle_poison(struct page *page)
 {
        int ret;
@@ -1768,6 +1770,9 @@ int memory_failure(unsigned long pfn, int flags)
 
        mutex_lock(&mf_mutex);
 
+       if (!(flags & MF_SW_SIMULATED))
+               hw_memory_failure = true;
+
        p = pfn_to_online_page(pfn);
        if (!p) {
                res = arch_memory_failure(pfn, flags);
@@ -2103,6 +2108,13 @@ int unpoison_memory(unsigned long pfn)
 
        mutex_lock(&mf_mutex);
 
+       if (hw_memory_failure) {
+               unpoison_pr_info("Unpoison: Disabled after HW memory failure %#lx\n",
+                                pfn, &unpoison_rs);
+               ret = -EOPNOTSUPP;
+               goto unlock_mutex;
+       }
+
        if (!PageHWPoison(p)) {
                unpoison_pr_info("Unpoison: Page was already unpoisoned %#lx\n",
                                 pfn, &unpoison_rs);
index 7a08914..1c6027a 100644 (file)
@@ -3043,7 +3043,7 @@ static inline void wp_page_reuse(struct vm_fault *vmf)
        pte_t entry;
 
        VM_BUG_ON(!(vmf->flags & FAULT_FLAG_WRITE));
-       VM_BUG_ON(PageAnon(page) && !PageAnonExclusive(page));
+       VM_BUG_ON(page && PageAnon(page) && !PageAnonExclusive(page));
 
        /*
         * Clear the pages cpupid information as the existing
@@ -4369,9 +4369,12 @@ vm_fault_t finish_fault(struct vm_fault *vmf)
                        return VM_FAULT_OOM;
        }
 
-       /* See comment in handle_pte_fault() */
+       /*
+        * See comment in handle_pte_fault() for how this scenario happens, we
+        * need to return NOPAGE so that we drop this page.
+        */
        if (pmd_devmap_trans_unstable(vmf->pmd))
-               return 0;
+               return VM_FAULT_NOPAGE;
 
        vmf->pte = pte_offset_map_lock(vma->vm_mm, vmf->pmd,
                                      vmf->address, &vmf->ptl);
@@ -4802,6 +4805,19 @@ static vm_fault_t create_huge_pud(struct vm_fault *vmf)
        defined(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD)
        /* No support for anonymous transparent PUD pages yet */
        if (vma_is_anonymous(vmf->vma))
+               return VM_FAULT_FALLBACK;
+       if (vmf->vma->vm_ops->huge_fault)
+               return vmf->vma->vm_ops->huge_fault(vmf, PE_SIZE_PUD);
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+       return VM_FAULT_FALLBACK;
+}
+
+static vm_fault_t wp_huge_pud(struct vm_fault *vmf, pud_t orig_pud)
+{
+#if defined(CONFIG_TRANSPARENT_HUGEPAGE) &&                    \
+       defined(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD)
+       /* No support for anonymous transparent PUD pages yet */
+       if (vma_is_anonymous(vmf->vma))
                goto split;
        if (vmf->vma->vm_ops->huge_fault) {
                vm_fault_t ret = vmf->vma->vm_ops->huge_fault(vmf, PE_SIZE_PUD);
@@ -4812,19 +4828,7 @@ static vm_fault_t create_huge_pud(struct vm_fault *vmf)
 split:
        /* COW or write-notify not handled on PUD level: split pud.*/
        __split_huge_pud(vmf->vma, vmf->pud, vmf->address);
-#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
-       return VM_FAULT_FALLBACK;
-}
-
-static vm_fault_t wp_huge_pud(struct vm_fault *vmf, pud_t orig_pud)
-{
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-       /* No support for anonymous transparent PUD pages yet */
-       if (vma_is_anonymous(vmf->vma))
-               return VM_FAULT_FALLBACK;
-       if (vmf->vma->vm_ops->huge_fault)
-               return vmf->vma->vm_ops->huge_fault(vmf, PE_SIZE_PUD);
-#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE && CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */
        return VM_FAULT_FALLBACK;
 }
 
index b870a65..745eea0 100644 (file)
@@ -499,7 +499,7 @@ void free_zone_device_page(struct page *page)
 }
 
 #ifdef CONFIG_FS_DAX
-bool __put_devmap_managed_page(struct page *page)
+bool __put_devmap_managed_page_refs(struct page *page, int refs)
 {
        if (page->pgmap->type != MEMORY_DEVICE_FS_DAX)
                return false;
@@ -509,9 +509,9 @@ bool __put_devmap_managed_page(struct page *page)
         * refcount is 1, then the page is free and the refcount is
         * stable because nobody holds a reference on the page.
         */
-       if (page_ref_dec_return(page) == 1)
+       if (page_ref_sub_return(page, refs) == 1)
                wake_up_var(&page->_refcount);
        return true;
 }
-EXPORT_SYMBOL(__put_devmap_managed_page);
+EXPORT_SYMBOL(__put_devmap_managed_page_refs);
 #endif /* CONFIG_FS_DAX */
index 55c2776..d0d466a 100644 (file)
@@ -1554,8 +1554,8 @@ static inline void wb_dirty_limits(struct dirty_throttle_control *dtc)
  * If we're over `background_thresh' then the writeback threads are woken to
  * perform some writeout.
  */
-static void balance_dirty_pages(struct bdi_writeback *wb,
-                               unsigned long pages_dirtied)
+static int balance_dirty_pages(struct bdi_writeback *wb,
+                              unsigned long pages_dirtied, unsigned int flags)
 {
        struct dirty_throttle_control gdtc_stor = { GDTC_INIT(wb) };
        struct dirty_throttle_control mdtc_stor = { MDTC_INIT(wb, &gdtc_stor) };
@@ -1575,6 +1575,7 @@ static void balance_dirty_pages(struct bdi_writeback *wb,
        struct backing_dev_info *bdi = wb->bdi;
        bool strictlimit = bdi->capabilities & BDI_CAP_STRICTLIMIT;
        unsigned long start_time = jiffies;
+       int ret = 0;
 
        for (;;) {
                unsigned long now = jiffies;
@@ -1628,6 +1629,19 @@ static void balance_dirty_pages(struct bdi_writeback *wb,
                }
 
                /*
+                * In laptop mode, we wait until hitting the higher threshold
+                * before starting background writeout, and then write out all
+                * the way down to the lower threshold.  So slow writers cause
+                * minimal disk activity.
+                *
+                * In normal mode, we start background writeout at the lower
+                * background_thresh, to keep the amount of dirty memory low.
+                */
+               if (!laptop_mode && nr_reclaimable > gdtc->bg_thresh &&
+                   !writeback_in_progress(wb))
+                       wb_start_background_writeback(wb);
+
+               /*
                 * Throttle it only when the background writeback cannot
                 * catch-up. This avoids (excessively) small writeouts
                 * when the wb limits are ramping up in case of !strictlimit.
@@ -1657,6 +1671,7 @@ free_running:
                        break;
                }
 
+               /* Start writeback even when in laptop mode */
                if (unlikely(!writeback_in_progress(wb)))
                        wb_start_background_writeback(wb);
 
@@ -1715,8 +1730,8 @@ free_running:
                                sdtc = mdtc;
                }
 
-               if (dirty_exceeded && !wb->dirty_exceeded)
-                       wb->dirty_exceeded = 1;
+               if (dirty_exceeded != wb->dirty_exceeded)
+                       wb->dirty_exceeded = dirty_exceeded;
 
                if (time_is_before_jiffies(READ_ONCE(wb->bw_time_stamp) +
                                           BANDWIDTH_INTERVAL))
@@ -1789,6 +1804,10 @@ pause:
                                          period,
                                          pause,
                                          start_time);
+               if (flags & BDP_ASYNC) {
+                       ret = -EAGAIN;
+                       break;
+               }
                __set_current_state(TASK_KILLABLE);
                wb->dirty_sleep = now;
                io_schedule_timeout(pause);
@@ -1820,26 +1839,7 @@ pause:
                if (fatal_signal_pending(current))
                        break;
        }
-
-       if (!dirty_exceeded && wb->dirty_exceeded)
-               wb->dirty_exceeded = 0;
-
-       if (writeback_in_progress(wb))
-               return;
-
-       /*
-        * In laptop mode, we wait until hitting the higher threshold before
-        * starting background writeout, and then write out all the way down
-        * to the lower threshold.  So slow writers cause minimal disk activity.
-        *
-        * In normal mode, we start background writeout at the lower
-        * background_thresh, to keep the amount of dirty memory low.
-        */
-       if (laptop_mode)
-               return;
-
-       if (nr_reclaimable > gdtc->bg_thresh)
-               wb_start_background_writeback(wb);
+       return ret;
 }
 
 static DEFINE_PER_CPU(int, bdp_ratelimits);
@@ -1861,27 +1861,34 @@ static DEFINE_PER_CPU(int, bdp_ratelimits);
 DEFINE_PER_CPU(int, dirty_throttle_leaks) = 0;
 
 /**
- * balance_dirty_pages_ratelimited - balance dirty memory state
- * @mapping: address_space which was dirtied
+ * balance_dirty_pages_ratelimited_flags - Balance dirty memory state.
+ * @mapping: address_space which was dirtied.
+ * @flags: BDP flags.
  *
  * Processes which are dirtying memory should call in here once for each page
  * which was newly dirtied.  The function will periodically check the system's
  * dirty state and will initiate writeback if needed.
  *
- * Once we're over the dirty memory limit we decrease the ratelimiting
- * by a lot, to prevent individual processes from overshooting the limit
- * by (ratelimit_pages) each.
+ * See balance_dirty_pages_ratelimited() for details.
+ *
+ * Return: If @flags contains BDP_ASYNC, it may return -EAGAIN to
+ * indicate that memory is out of balance and the caller must wait
+ * for I/O to complete.  Otherwise, it will return 0 to indicate
+ * that either memory was already in balance, or it was able to sleep
+ * until the amount of dirty memory returned to balance.
  */
-void balance_dirty_pages_ratelimited(struct address_space *mapping)
+int balance_dirty_pages_ratelimited_flags(struct address_space *mapping,
+                                       unsigned int flags)
 {
        struct inode *inode = mapping->host;
        struct backing_dev_info *bdi = inode_to_bdi(inode);
        struct bdi_writeback *wb = NULL;
        int ratelimit;
+       int ret = 0;
        int *p;
 
        if (!(bdi->capabilities & BDI_CAP_WRITEBACK))
-               return;
+               return ret;
 
        if (inode_cgwb_enabled(inode))
                wb = wb_get_create_current(bdi, GFP_KERNEL);
@@ -1921,9 +1928,27 @@ void balance_dirty_pages_ratelimited(struct address_space *mapping)
        preempt_enable();
 
        if (unlikely(current->nr_dirtied >= ratelimit))
-               balance_dirty_pages(wb, current->nr_dirtied);
+               ret = balance_dirty_pages(wb, current->nr_dirtied, flags);
 
        wb_put(wb);
+       return ret;
+}
+
+/**
+ * balance_dirty_pages_ratelimited - balance dirty memory state.
+ * @mapping: address_space which was dirtied.
+ *
+ * Processes which are dirtying memory should call in here once for each page
+ * which was newly dirtied.  The function will periodically check the system's
+ * dirty state and will initiate writeback if needed.
+ *
+ * Once we're over the dirty memory limit we decrease the ratelimiting
+ * by a lot, to prevent individual processes from overshooting the limit
+ * by (ratelimit_pages) each.
+ */
+void balance_dirty_pages_ratelimited(struct address_space *mapping)
+{
+       balance_dirty_pages_ratelimited_flags(mapping, 0);
 }
 EXPORT_SYMBOL(balance_dirty_pages_ratelimited);
 
index e008a3d..b0bcab5 100644 (file)
@@ -2361,7 +2361,7 @@ static inline bool check_new_pcp(struct page *page, unsigned int order)
 }
 #endif /* CONFIG_DEBUG_VM */
 
-static inline bool should_skip_kasan_unpoison(gfp_t flags, bool init_tags)
+static inline bool should_skip_kasan_unpoison(gfp_t flags)
 {
        /* Don't skip if a software KASAN mode is enabled. */
        if (IS_ENABLED(CONFIG_KASAN_GENERIC) ||
@@ -2373,12 +2373,10 @@ static inline bool should_skip_kasan_unpoison(gfp_t flags, bool init_tags)
                return true;
 
        /*
-        * With hardware tag-based KASAN enabled, skip if either:
-        *
-        * 1. Memory tags have already been cleared via tag_clear_highpage().
-        * 2. Skipping has been requested via __GFP_SKIP_KASAN_UNPOISON.
+        * With hardware tag-based KASAN enabled, skip if this has been
+        * requested via __GFP_SKIP_KASAN_UNPOISON.
         */
-       return init_tags || (flags & __GFP_SKIP_KASAN_UNPOISON);
+       return flags & __GFP_SKIP_KASAN_UNPOISON;
 }
 
 static inline bool should_skip_init(gfp_t flags)
@@ -2397,6 +2395,7 @@ inline void post_alloc_hook(struct page *page, unsigned int order,
        bool init = !want_init_on_free() && want_init_on_alloc(gfp_flags) &&
                        !should_skip_init(gfp_flags);
        bool init_tags = init && (gfp_flags & __GFP_ZEROTAGS);
+       int i;
 
        set_page_private(page, 0);
        set_page_refcounted(page);
@@ -2422,8 +2421,6 @@ inline void post_alloc_hook(struct page *page, unsigned int order,
         * should be initialized as well).
         */
        if (init_tags) {
-               int i;
-
                /* Initialize both memory and tags. */
                for (i = 0; i != 1 << order; ++i)
                        tag_clear_highpage(page + i);
@@ -2431,13 +2428,17 @@ inline void post_alloc_hook(struct page *page, unsigned int order,
                /* Note that memory is already initialized by the loop above. */
                init = false;
        }
-       if (!should_skip_kasan_unpoison(gfp_flags, init_tags)) {
+       if (!should_skip_kasan_unpoison(gfp_flags)) {
                /* Unpoison shadow memory or set memory tags. */
                kasan_unpoison_pages(page, order, init);
 
                /* Note that memory is already initialized by KASAN. */
                if (kasan_has_integrated_init())
                        init = false;
+       } else {
+               /* Ensure page_address() dereferencing does not fault. */
+               for (i = 0; i != 1 << order; ++i)
+                       page_kasan_tag_reset(page + i);
        }
        /* If memory is still not initialized, do it now. */
        if (init)
@@ -3968,11 +3969,15 @@ static inline bool zone_watermark_fast(struct zone *z, unsigned int order,
         * need to be calculated.
         */
        if (!order) {
-               long fast_free;
+               long usable_free;
+               long reserved;
+
+               usable_free = free_pages;
+               reserved = __zone_watermark_unusable_free(z, 0, alloc_flags);
 
-               fast_free = free_pages;
-               fast_free -= __zone_watermark_unusable_free(z, 0, alloc_flags);
-               if (fast_free > mark + z->lowmem_reserve[highest_zoneidx])
+               /* reserved may over estimate high-atomic reserves. */
+               usable_free -= min(usable_free, reserved);
+               if (usable_free > mark + z->lowmem_reserve[highest_zoneidx])
                        return true;
        }
 
index d200d41..9d73dc3 100644 (file)
@@ -286,6 +286,8 @@ __first_valid_page(unsigned long pfn, unsigned long nr_pages)
  * @flags:                     isolation flags
  * @gfp_flags:                 GFP flags used for migrating pages
  * @isolate_before:    isolate the pageblock before the boundary_pfn
+ * @skip_isolation:    the flag to skip the pageblock isolation in second
+ *                     isolate_single_pageblock()
  *
  * Free and in-use pages can be as big as MAX_ORDER-1 and contain more than one
  * pageblock. When not all pageblocks within a page are isolated at the same
index 5bcb334..746c05a 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1899,8 +1899,23 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,
                /* Unexpected PMD-mapped THP? */
                VM_BUG_ON_FOLIO(!pvmw.pte, folio);
 
-               subpage = folio_page(folio,
-                               pte_pfn(*pvmw.pte) - folio_pfn(folio));
+               if (folio_is_zone_device(folio)) {
+                       /*
+                        * Our PTE is a non-present device exclusive entry and
+                        * calculating the subpage as for the common case would
+                        * result in an invalid pointer.
+                        *
+                        * Since only PAGE_SIZE pages can currently be
+                        * migrated, just set it to page. This will need to be
+                        * changed when hugepage migrations to device private
+                        * memory are supported.
+                        */
+                       VM_BUG_ON_FOLIO(folio_nr_pages(folio) > 1, folio);
+                       subpage = &folio->page;
+               } else {
+                       subpage = folio_page(folio,
+                                       pte_pfn(*pvmw.pte) - folio_pfn(folio));
+               }
                address = pvmw.address;
                anon_exclusive = folio_test_anon(folio) &&
                                 PageAnonExclusive(subpage);
@@ -1993,15 +2008,7 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,
                        /*
                         * No need to invalidate here it will synchronize on
                         * against the special swap migration pte.
-                        *
-                        * The assignment to subpage above was computed from a
-                        * swap PTE which results in an invalid pointer.
-                        * Since only PAGE_SIZE pages can currently be
-                        * migrated, just set it to page. This will need to be
-                        * changed when hugepage migrations to device private
-                        * memory are supported.
                         */
-                       subpage = &folio->page;
                } else if (PageHWPoison(subpage)) {
                        pteval = swp_entry_to_pte(make_hwpoison_entry(subpage));
                        if (folio_test_hugetlb(folio)) {
index 658a748..e3e9590 100644 (file)
@@ -55,22 +55,28 @@ static vm_fault_t secretmem_fault(struct vm_fault *vmf)
        gfp_t gfp = vmf->gfp_mask;
        unsigned long addr;
        struct page *page;
+       vm_fault_t ret;
        int err;
 
        if (((loff_t)vmf->pgoff << PAGE_SHIFT) >= i_size_read(inode))
                return vmf_error(-EINVAL);
 
+       filemap_invalidate_lock_shared(mapping);
+
 retry:
        page = find_lock_page(mapping, offset);
        if (!page) {
                page = alloc_page(gfp | __GFP_ZERO);
-               if (!page)
-                       return VM_FAULT_OOM;
+               if (!page) {
+                       ret = VM_FAULT_OOM;
+                       goto out;
+               }
 
                err = set_direct_map_invalid_noflush(page);
                if (err) {
                        put_page(page);
-                       return vmf_error(err);
+                       ret = vmf_error(err);
+                       goto out;
                }
 
                __SetPageUptodate(page);
@@ -86,7 +92,8 @@ retry:
                        if (err == -EEXIST)
                                goto retry;
 
-                       return vmf_error(err);
+                       ret = vmf_error(err);
+                       goto out;
                }
 
                addr = (unsigned long)page_address(page);
@@ -94,7 +101,11 @@ retry:
        }
 
        vmf->page = page;
-       return VM_FAULT_LOCKED;
+       ret = VM_FAULT_LOCKED;
+
+out:
+       filemap_invalidate_unlock_shared(mapping);
+       return ret;
 }
 
 static const struct vm_operations_struct secretmem_vm_ops = {
@@ -155,12 +166,20 @@ static int secretmem_setattr(struct user_namespace *mnt_userns,
                             struct dentry *dentry, struct iattr *iattr)
 {
        struct inode *inode = d_inode(dentry);
+       struct address_space *mapping = inode->i_mapping;
        unsigned int ia_valid = iattr->ia_valid;
+       int ret;
+
+       filemap_invalidate_lock(mapping);
 
        if ((ia_valid & ATTR_SIZE) && inode->i_size)
-               return -EINVAL;
+               ret = -EINVAL;
+       else
+               ret = simple_setattr(mnt_userns, dentry, iattr);
 
-       return simple_setattr(mnt_userns, dentry, iattr);
+       filemap_invalidate_unlock(mapping);
+
+       return ret;
 }
 
 static const struct inode_operations secretmem_iops = {
@@ -173,11 +192,20 @@ static struct file *secretmem_file_create(unsigned long flags)
 {
        struct file *file = ERR_PTR(-ENOMEM);
        struct inode *inode;
+       const char *anon_name = "[secretmem]";
+       const struct qstr qname = QSTR_INIT(anon_name, strlen(anon_name));
+       int err;
 
        inode = alloc_anon_inode(secretmem_mnt->mnt_sb);
        if (IS_ERR(inode))
                return ERR_CAST(inode);
 
+       err = security_inode_init_security_anon(inode, &qname, NULL);
+       if (err) {
+               file = ERR_PTR(err);
+               goto err_free_inode;
+       }
+
        file = alloc_file_pseudo(inode, secretmem_mnt, "secretmem",
                                 O_RDWR, &secretmem_fops);
        if (IS_ERR(file))
index 15c6145..e5e43b9 100644 (file)
@@ -3391,7 +3391,7 @@ static int shmem_parse_one(struct fs_context *fc, struct fs_parameter *param)
                break;
        case Opt_nr_blocks:
                ctx->blocks = memparse(param->string, &rest);
-               if (*rest)
+               if (*rest || ctx->blocks > S64_MAX)
                        goto bad_value;
                ctx->seen |= SHMEM_SEEN_BLOCKS;
                break;
@@ -3513,10 +3513,7 @@ static int shmem_reconfigure(struct fs_context *fc)
 
        raw_spin_lock(&sbinfo->stat_lock);
        inodes = sbinfo->max_inodes - sbinfo->free_inodes;
-       if (ctx->blocks > S64_MAX) {
-               err = "Number of blocks too large";
-               goto out;
-       }
+
        if ((ctx->seen & SHMEM_SEEN_BLOCKS) && ctx->blocks) {
                if (!sbinfo->max_blocks) {
                        err = "Cannot retroactively limit size";
index f8cd00f..5e73e2d 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -3230,7 +3230,7 @@ slab_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid, size_t orig_
        }
        /* ___cache_alloc_node can fall back to other nodes */
        ptr = ____cache_alloc_node(cachep, flags, nodeid);
-  out:
+out:
        local_irq_restore(save_flags);
        ptr = cache_alloc_debugcheck_after(cachep, flags, ptr, caller);
        init = slab_want_init_on_alloc(flags, cachep);
@@ -3259,7 +3259,7 @@ __do_cache_alloc(struct kmem_cache *cache, gfp_t flags)
        if (!objp)
                objp = ____cache_alloc_node(cache, flags, numa_mem_id());
 
-  out:
+out:
        return objp;
 }
 #else
@@ -3406,9 +3406,10 @@ static __always_inline void __cache_free(struct kmem_cache *cachep, void *objp,
 {
        bool init;
 
+       memcg_slab_free_hook(cachep, virt_to_slab(objp), &objp, 1);
+
        if (is_kfence_address(objp)) {
                kmemleak_free_recursive(objp, cachep->flags);
-               memcg_slab_free_hook(cachep, &objp, 1);
                __kfence_free(objp);
                return;
        }
@@ -3441,7 +3442,6 @@ void ___cache_free(struct kmem_cache *cachep, void *objp,
        check_irq_off();
        kmemleak_free_recursive(objp, cachep->flags);
        objp = cache_free_debugcheck(cachep, objp, caller);
-       memcg_slab_free_hook(cachep, &objp, 1);
 
        /*
         * Skip calling cache_free_alien() when the platform is not numa.
@@ -3478,7 +3478,7 @@ void *__kmem_cache_alloc_lru(struct kmem_cache *cachep, struct list_lru *lru,
 {
        void *ret = slab_alloc(cachep, lru, flags, cachep->object_size, _RET_IP_);
 
-       trace_kmem_cache_alloc(_RET_IP_, ret,
+       trace_kmem_cache_alloc(_RET_IP_, ret, cachep,
                               cachep->object_size, cachep->size, flags);
 
        return ret;
@@ -3553,7 +3553,7 @@ error:
        local_irq_enable();
        cache_alloc_debugcheck_after_bulk(s, flags, i, p, _RET_IP_);
        slab_post_alloc_hook(s, objcg, flags, i, p, false);
-       __kmem_cache_free_bulk(s, i, p);
+       kmem_cache_free_bulk(s, i, p);
        return 0;
 }
 EXPORT_SYMBOL(kmem_cache_alloc_bulk);
@@ -3567,7 +3567,7 @@ kmem_cache_alloc_trace(struct kmem_cache *cachep, gfp_t flags, size_t size)
        ret = slab_alloc(cachep, NULL, flags, size, _RET_IP_);
 
        ret = kasan_kmalloc(cachep, ret, size, flags);
-       trace_kmalloc(_RET_IP_, ret,
+       trace_kmalloc(_RET_IP_, ret, cachep,
                      size, cachep->size, flags);
        return ret;
 }
@@ -3592,7 +3592,7 @@ void *kmem_cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid)
 {
        void *ret = slab_alloc_node(cachep, flags, nodeid, cachep->object_size, _RET_IP_);
 
-       trace_kmem_cache_alloc_node(_RET_IP_, ret,
+       trace_kmem_cache_alloc_node(_RET_IP_, ret, cachep,
                                    cachep->object_size, cachep->size,
                                    flags, nodeid);
 
@@ -3611,7 +3611,7 @@ void *kmem_cache_alloc_node_trace(struct kmem_cache *cachep,
        ret = slab_alloc_node(cachep, flags, nodeid, size, _RET_IP_);
 
        ret = kasan_kmalloc(cachep, ret, size, flags);
-       trace_kmalloc_node(_RET_IP_, ret,
+       trace_kmalloc_node(_RET_IP_, ret, cachep,
                           size, cachep->size,
                           flags, nodeid);
        return ret;
@@ -3694,7 +3694,7 @@ static __always_inline void *__do_kmalloc(size_t size, gfp_t flags,
        ret = slab_alloc(cachep, NULL, flags, size, caller);
 
        ret = kasan_kmalloc(cachep, ret, size, flags);
-       trace_kmalloc(caller, ret,
+       trace_kmalloc(caller, ret, cachep,
                      size, cachep->size, flags);
 
        return ret;
index db9fb5c..4ec82be 100644 (file)
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -380,15 +380,6 @@ void slabinfo_show_stats(struct seq_file *m, struct kmem_cache *s);
 ssize_t slabinfo_write(struct file *file, const char __user *buffer,
                       size_t count, loff_t *ppos);
 
-/*
- * Generic implementation of bulk operations
- * These are useful for situations in which the allocator cannot
- * perform optimizations. In that case segments of the object listed
- * may be allocated or freed using these operations.
- */
-void __kmem_cache_free_bulk(struct kmem_cache *, size_t, void **);
-int __kmem_cache_alloc_bulk(struct kmem_cache *, gfp_t, size_t, void **);
-
 static inline enum node_stat_item cache_vmstat_idx(struct kmem_cache *s)
 {
        return (s->flags & SLAB_RECLAIM_ACCOUNT) ?
@@ -547,36 +538,22 @@ static inline void memcg_slab_post_alloc_hook(struct kmem_cache *s,
        obj_cgroup_put(objcg);
 }
 
-static inline void memcg_slab_free_hook(struct kmem_cache *s_orig,
+static inline void memcg_slab_free_hook(struct kmem_cache *s, struct slab *slab,
                                        void **p, int objects)
 {
-       struct kmem_cache *s;
        struct obj_cgroup **objcgs;
-       struct obj_cgroup *objcg;
-       struct slab *slab;
-       unsigned int off;
        int i;
 
        if (!memcg_kmem_enabled())
                return;
 
-       for (i = 0; i < objects; i++) {
-               if (unlikely(!p[i]))
-                       continue;
-
-               slab = virt_to_slab(p[i]);
-               /* we could be given a kmalloc_large() object, skip those */
-               if (!slab)
-                       continue;
-
-               objcgs = slab_objcgs(slab);
-               if (!objcgs)
-                       continue;
+       objcgs = slab_objcgs(slab);
+       if (!objcgs)
+               return;
 
-               if (!s_orig)
-                       s = slab->slab_cache;
-               else
-                       s = s_orig;
+       for (i = 0; i < objects; i++) {
+               struct obj_cgroup *objcg;
+               unsigned int off;
 
                off = obj_to_index(s, slab, p[i]);
                objcg = objcgs[off];
@@ -628,7 +605,7 @@ static inline void memcg_slab_post_alloc_hook(struct kmem_cache *s,
 {
 }
 
-static inline void memcg_slab_free_hook(struct kmem_cache *s,
+static inline void memcg_slab_free_hook(struct kmem_cache *s, struct slab *slab,
                                        void **p, int objects)
 {
 }
index 77c3adf..1799664 100644 (file)
 #include <linux/memcontrol.h>
 #include <linux/stackdepot.h>
 
-#define CREATE_TRACE_POINTS
-#include <trace/events/kmem.h>
-
 #include "internal.h"
-
 #include "slab.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/kmem.h>
+
 enum slab_state slab_state;
 LIST_HEAD(slab_caches);
 DEFINE_MUTEX(slab_mutex);
@@ -105,33 +104,6 @@ static inline int kmem_cache_sanity_check(const char *name, unsigned int size)
 }
 #endif
 
-void __kmem_cache_free_bulk(struct kmem_cache *s, size_t nr, void **p)
-{
-       size_t i;
-
-       for (i = 0; i < nr; i++) {
-               if (s)
-                       kmem_cache_free(s, p[i]);
-               else
-                       kfree(p[i]);
-       }
-}
-
-int __kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t nr,
-                                                               void **p)
-{
-       size_t i;
-
-       for (i = 0; i < nr; i++) {
-               void *x = p[i] = kmem_cache_alloc(s, flags);
-               if (!x) {
-                       __kmem_cache_free_bulk(s, i, p);
-                       return 0;
-               }
-       }
-       return i;
-}
-
 /*
  * Figure out what the alignment of the objects will be given a set of
  * flags, a user specified alignment and the size of the objects.
@@ -959,7 +931,7 @@ EXPORT_SYMBOL(kmalloc_order);
 void *kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order)
 {
        void *ret = kmalloc_order(size, flags, order);
-       trace_kmalloc(_RET_IP_, ret, size, PAGE_SIZE << order, flags);
+       trace_kmalloc(_RET_IP_, ret, NULL, size, PAGE_SIZE << order, flags);
        return ret;
 }
 EXPORT_SYMBOL(kmalloc_order_trace);
index f47811f..2bd4f47 100644 (file)
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -507,7 +507,7 @@ __do_kmalloc_node(size_t size, gfp_t gfp, int node, unsigned long caller)
                *m = size;
                ret = (void *)m + minalign;
 
-               trace_kmalloc_node(caller, ret,
+               trace_kmalloc_node(caller, ret, NULL,
                                   size, size + minalign, gfp, node);
        } else {
                unsigned int order = get_order(size);
@@ -516,7 +516,7 @@ __do_kmalloc_node(size_t size, gfp_t gfp, int node, unsigned long caller)
                        gfp |= __GFP_COMP;
                ret = slob_new_pages(gfp, order, node);
 
-               trace_kmalloc_node(caller, ret,
+               trace_kmalloc_node(caller, ret, NULL,
                                   size, PAGE_SIZE << order, gfp, node);
        }
 
@@ -616,12 +616,12 @@ static void *slob_alloc_node(struct kmem_cache *c, gfp_t flags, int node)
 
        if (c->size < PAGE_SIZE) {
                b = slob_alloc(c->size, flags, c->align, node, 0);
-               trace_kmem_cache_alloc_node(_RET_IP_, b, c->object_size,
+               trace_kmem_cache_alloc_node(_RET_IP_, b, NULL, c->object_size,
                                            SLOB_UNITS(c->size) * SLOB_UNIT,
                                            flags, node);
        } else {
                b = slob_new_pages(flags, get_order(c->size), node);
-               trace_kmem_cache_alloc_node(_RET_IP_, b, c->object_size,
+               trace_kmem_cache_alloc_node(_RET_IP_, b, NULL, c->object_size,
                                            PAGE_SIZE << get_order(c->size),
                                            flags, node);
        }
@@ -692,16 +692,33 @@ void kmem_cache_free(struct kmem_cache *c, void *b)
 }
 EXPORT_SYMBOL(kmem_cache_free);
 
-void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p)
+void kmem_cache_free_bulk(struct kmem_cache *s, size_t nr, void **p)
 {
-       __kmem_cache_free_bulk(s, size, p);
+       size_t i;
+
+       for (i = 0; i < nr; i++) {
+               if (s)
+                       kmem_cache_free(s, p[i]);
+               else
+                       kfree(p[i]);
+       }
 }
 EXPORT_SYMBOL(kmem_cache_free_bulk);
 
-int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
+int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t nr,
                                                                void **p)
 {
-       return __kmem_cache_alloc_bulk(s, flags, size, p);
+       size_t i;
+
+       for (i = 0; i < nr; i++) {
+               void *x = p[i] = kmem_cache_alloc(s, flags);
+
+               if (!x) {
+                       kmem_cache_free_bulk(s, i, p);
+                       return 0;
+               }
+       }
+       return i;
 }
 EXPORT_SYMBOL(kmem_cache_alloc_bulk);
 
index b1281b8..862dbd9 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -3257,7 +3257,7 @@ void *__kmem_cache_alloc_lru(struct kmem_cache *s, struct list_lru *lru,
 {
        void *ret = slab_alloc(s, lru, gfpflags, _RET_IP_, s->object_size);
 
-       trace_kmem_cache_alloc(_RET_IP_, ret, s->object_size,
+       trace_kmem_cache_alloc(_RET_IP_, ret, s, s->object_size,
                                s->size, gfpflags);
 
        return ret;
@@ -3280,7 +3280,7 @@ EXPORT_SYMBOL(kmem_cache_alloc_lru);
 void *kmem_cache_alloc_trace(struct kmem_cache *s, gfp_t gfpflags, size_t size)
 {
        void *ret = slab_alloc(s, NULL, gfpflags, _RET_IP_, size);
-       trace_kmalloc(_RET_IP_, ret, size, s->size, gfpflags);
+       trace_kmalloc(_RET_IP_, ret, s, size, s->size, gfpflags);
        ret = kasan_kmalloc(s, ret, size, gfpflags);
        return ret;
 }
@@ -3292,7 +3292,7 @@ void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t gfpflags, int node)
 {
        void *ret = slab_alloc_node(s, NULL, gfpflags, node, _RET_IP_, s->object_size);
 
-       trace_kmem_cache_alloc_node(_RET_IP_, ret,
+       trace_kmem_cache_alloc_node(_RET_IP_, ret, s,
                                    s->object_size, s->size, gfpflags, node);
 
        return ret;
@@ -3306,7 +3306,7 @@ void *kmem_cache_alloc_node_trace(struct kmem_cache *s,
 {
        void *ret = slab_alloc_node(s, NULL, gfpflags, node, _RET_IP_, size);
 
-       trace_kmalloc_node(_RET_IP_, ret,
+       trace_kmalloc_node(_RET_IP_, ret, s,
                           size, s->size, gfpflags, node);
 
        ret = kasan_kmalloc(s, ret, size, gfpflags);
@@ -3464,9 +3464,6 @@ static __always_inline void do_slab_free(struct kmem_cache *s,
        struct kmem_cache_cpu *c;
        unsigned long tid;
 
-       /* memcg_slab_free_hook() is already called for bulk free. */
-       if (!tail)
-               memcg_slab_free_hook(s, &head, 1);
 redo:
        /*
         * Determine the currently cpus per cpu slab.
@@ -3526,9 +3523,10 @@ redo:
 }
 
 static __always_inline void slab_free(struct kmem_cache *s, struct slab *slab,
-                                     void *head, void *tail, int cnt,
+                                     void *head, void *tail, void **p, int cnt,
                                      unsigned long addr)
 {
+       memcg_slab_free_hook(s, slab, p, cnt);
        /*
         * With KASAN enabled slab_free_freelist_hook modifies the freelist
         * to remove objects, whose reuse must be delayed.
@@ -3550,7 +3548,7 @@ void kmem_cache_free(struct kmem_cache *s, void *x)
        if (!s)
                return;
        trace_kmem_cache_free(_RET_IP_, x, s->name);
-       slab_free(s, virt_to_slab(x), x, NULL, 1, _RET_IP_);
+       slab_free(s, virt_to_slab(x), x, NULL, &x, 1, _RET_IP_);
 }
 EXPORT_SYMBOL(kmem_cache_free);
 
@@ -3591,88 +3589,67 @@ static inline
 int build_detached_freelist(struct kmem_cache *s, size_t size,
                            void **p, struct detached_freelist *df)
 {
-       size_t first_skipped_index = 0;
        int lookahead = 3;
        void *object;
        struct folio *folio;
-       struct slab *slab;
-
-       /* Always re-init detached_freelist */
-       df->slab = NULL;
-
-       do {
-               object = p[--size];
-               /* Do we need !ZERO_OR_NULL_PTR(object) here? (for kfree) */
-       } while (!object && size);
-
-       if (!object)
-               return 0;
+       size_t same;
 
+       object = p[--size];
        folio = virt_to_folio(object);
        if (!s) {
                /* Handle kalloc'ed objects */
                if (unlikely(!folio_test_slab(folio))) {
                        free_large_kmalloc(folio, object);
-                       p[size] = NULL; /* mark object processed */
+                       df->slab = NULL;
                        return size;
                }
                /* Derive kmem_cache from object */
-               slab = folio_slab(folio);
-               df->s = slab->slab_cache;
+               df->slab = folio_slab(folio);
+               df->s = df->slab->slab_cache;
        } else {
-               slab = folio_slab(folio);
+               df->slab = folio_slab(folio);
                df->s = cache_from_obj(s, object); /* Support for memcg */
        }
 
-       if (is_kfence_address(object)) {
-               slab_free_hook(df->s, object, false);
-               __kfence_free(object);
-               p[size] = NULL; /* mark object processed */
-               return size;
-       }
-
        /* Start new detached freelist */
-       df->slab = slab;
-       set_freepointer(df->s, object, NULL);
        df->tail = object;
        df->freelist = object;
-       p[size] = NULL; /* mark object processed */
        df->cnt = 1;
 
+       if (is_kfence_address(object))
+               return size;
+
+       set_freepointer(df->s, object, NULL);
+
+       same = size;
        while (size) {
                object = p[--size];
-               if (!object)
-                       continue; /* Skip processed objects */
-
                /* df->slab is always set at this point */
                if (df->slab == virt_to_slab(object)) {
                        /* Opportunity build freelist */
                        set_freepointer(df->s, object, df->freelist);
                        df->freelist = object;
                        df->cnt++;
-                       p[size] = NULL; /* mark object processed */
-
+                       same--;
+                       if (size != same)
+                               swap(p[size], p[same]);
                        continue;
                }
 
                /* Limit look ahead search */
                if (!--lookahead)
                        break;
-
-               if (!first_skipped_index)
-                       first_skipped_index = size + 1;
        }
 
-       return first_skipped_index;
+       return same;
 }
 
 /* Note that interrupts must be enabled when calling this function. */
 void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p)
 {
-       if (WARN_ON(!size))
+       if (!size)
                return;
 
-       memcg_slab_free_hook(s, p, size);
        do {
                struct detached_freelist df;
 
@@ -3680,7 +3657,8 @@ void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p)
                if (!df.slab)
                        continue;
 
-               slab_free(df.s, df.slab, df.freelist, df.tail, df.cnt, _RET_IP_);
+               slab_free(df.s, df.slab, df.freelist, df.tail, &p[size], df.cnt,
+                         _RET_IP_);
        } while (likely(size));
 }
 EXPORT_SYMBOL(kmem_cache_free_bulk);
@@ -3760,7 +3738,7 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
 error:
        slub_put_cpu_ptr(s->cpu_slab);
        slab_post_alloc_hook(s, objcg, flags, i, p, false);
-       __kmem_cache_free_bulk(s, i, p);
+       kmem_cache_free_bulk(s, i, p);
        return 0;
 }
 EXPORT_SYMBOL(kmem_cache_alloc_bulk);
@@ -4441,7 +4419,7 @@ void *__kmalloc(size_t size, gfp_t flags)
 
        ret = slab_alloc(s, NULL, flags, _RET_IP_, size);
 
-       trace_kmalloc(_RET_IP_, ret, size, s->size, flags);
+       trace_kmalloc(_RET_IP_, ret, s, size, s->size, flags);
 
        ret = kasan_kmalloc(s, ret, size, flags);
 
@@ -4475,7 +4453,7 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node)
        if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) {
                ret = kmalloc_large_node(size, flags, node);
 
-               trace_kmalloc_node(_RET_IP_, ret,
+               trace_kmalloc_node(_RET_IP_, ret, NULL,
                                   size, PAGE_SIZE << get_order(size),
                                   flags, node);
 
@@ -4489,7 +4467,7 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node)
 
        ret = slab_alloc_node(s, NULL, flags, node, _RET_IP_, size);
 
-       trace_kmalloc_node(_RET_IP_, ret, size, s->size, flags, node);
+       trace_kmalloc_node(_RET_IP_, ret, s, size, s->size, flags, node);
 
        ret = kasan_kmalloc(s, ret, size, flags);
 
@@ -4581,7 +4559,7 @@ void kfree(const void *x)
                return;
        }
        slab = folio_slab(folio);
-       slab_free(slab->slab_cache, slab, object, NULL, 1, _RET_IP_);
+       slab_free(slab->slab_cache, slab, object, NULL, &object, 1, _RET_IP_);
 }
 EXPORT_SYMBOL(kfree);
 
@@ -4890,6 +4868,9 @@ __kmem_cache_alias(const char *name, unsigned int size, unsigned int align,
 
        s = find_mergeable(size, align, flags, name, ctor);
        if (s) {
+               if (sysfs_slab_alias(s, name))
+                       return NULL;
+
                s->refcount++;
 
                /*
@@ -4898,11 +4879,6 @@ __kmem_cache_alias(const char *name, unsigned int size, unsigned int align,
                 */
                s->object_size = max(s->object_size, size);
                s->inuse = max(s->inuse, ALIGN(size, sizeof(void *)));
-
-               if (sysfs_slab_alias(s, name)) {
-                       s->refcount--;
-                       s = NULL;
-               }
        }
 
        return s;
@@ -4948,7 +4924,7 @@ void *__kmalloc_track_caller(size_t size, gfp_t gfpflags, unsigned long caller)
        ret = slab_alloc(s, NULL, gfpflags, caller, size);
 
        /* Honor the call site pointer we received. */
-       trace_kmalloc(caller, ret, size, s->size, gfpflags);
+       trace_kmalloc(caller, ret, s, size, s->size, gfpflags);
 
        return ret;
 }
@@ -4964,7 +4940,7 @@ void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags,
        if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) {
                ret = kmalloc_large_node(size, gfpflags, node);
 
-               trace_kmalloc_node(caller, ret,
+               trace_kmalloc_node(caller, ret, NULL,
                                   size, PAGE_SIZE << get_order(size),
                                   gfpflags, node);
 
@@ -4979,7 +4955,7 @@ void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags,
        ret = slab_alloc_node(s, NULL, gfpflags, node, caller, size);
 
        /* Honor the call site pointer we received. */
-       trace_kmalloc_node(caller, ret, size, s->size, gfpflags, node);
+       trace_kmalloc_node(caller, ret, s, size, s->size, gfpflags, node);
 
        return ret;
 }
index f4fa61d..dbbd1a7 100644 (file)
@@ -78,6 +78,14 @@ static int __split_vmemmap_huge_pmd(pmd_t *pmd, unsigned long start)
 
        spin_lock(&init_mm.page_table_lock);
        if (likely(pmd_leaf(*pmd))) {
+               /*
+                * Higher order allocations from buddy allocator must be able to
+                * be treated as indepdenent small pages (as they can be freed
+                * individually).
+                */
+               if (!PageReserved(page))
+                       split_page(page, get_order(PMD_SIZE));
+
                /* Make pte visible before pmd. See comment in pmd_install(). */
                smp_wmb();
                pmd_populate_kernel(&init_mm, pmd, pgtable);
index f65e284..275a4ea 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -881,7 +881,7 @@ void lru_cache_disable(void)
         * lru_disable_count = 0 will have exited the critical
         * section when synchronize_rcu() returns.
         */
-       synchronize_rcu();
+       synchronize_rcu_expedited();
 #ifdef CONFIG_SMP
        __lru_add_drain_all(true);
 #else
index 2a65a89..10b94d6 100644 (file)
@@ -307,7 +307,7 @@ swp_entry_t folio_alloc_swap(struct folio *folio)
        entry.val = 0;
 
        if (folio_test_large(folio)) {
-               if (IS_ENABLED(CONFIG_THP_SWAP))
+               if (IS_ENABLED(CONFIG_THP_SWAP) && arch_thp_swp_supported())
                        get_swap_pages(1, &entry, folio_nr_pages(folio));
                goto out;
        }
index 4e1da70..c1ee15a 100644 (file)
@@ -161,7 +161,7 @@ static inline void check_bogus_address(const unsigned long ptr, unsigned long n,
 static inline void check_heap_object(const void *ptr, unsigned long n,
                                     bool to_user)
 {
-       uintptr_t addr = (uintptr_t)ptr;
+       unsigned long addr = (unsigned long)ptr;
        unsigned long offset;
        struct folio *folio;
 
index 4f4892a..07d3bef 100644 (file)
@@ -246,7 +246,10 @@ static int mcontinue_atomic_pte(struct mm_struct *dst_mm,
        struct page *page;
        int ret;
 
-       ret = shmem_getpage(inode, pgoff, &page, SGP_READ);
+       ret = shmem_getpage(inode, pgoff, &page, SGP_NOALLOC);
+       /* Our caller expects us to return -EFAULT if we failed to find page. */
+       if (ret == -ENOENT)
+               ret = -EFAULT;
        if (ret)
                goto out;
        if (!page) {
index 53b1955..2145321 100644 (file)
@@ -182,10 +182,14 @@ static int vlan_newlink(struct net *src_net, struct net_device *dev,
        else if (dev->mtu > max_mtu)
                return -EINVAL;
 
+       /* Note: If this initial vlan_changelink() fails, we need
+        * to call vlan_dev_free_egress_priority() to free memory.
+        */
        err = vlan_changelink(dev, tb, data, extack);
-       if (err)
-               return err;
-       err = register_vlan_dev(dev, extack);
+
+       if (!err)
+               err = register_vlan_dev(dev, extack);
+
        if (err)
                vlan_dev_free_egress_priority(dev);
        return err;
index 59a5c13..a0f99ba 100644 (file)
@@ -571,6 +571,7 @@ int hci_dev_close(__u16 dev)
                goto done;
        }
 
+       cancel_work_sync(&hdev->power_on);
        if (hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF))
                cancel_delayed_work(&hdev->power_off);
 
@@ -2675,6 +2676,8 @@ void hci_unregister_dev(struct hci_dev *hdev)
        list_del(&hdev->list);
        write_unlock(&hci_dev_list_lock);
 
+       cancel_work_sync(&hdev->power_on);
+
        hci_cmd_sync_clear(hdev);
 
        if (!test_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks))
index 286d676..c170216 100644 (file)
@@ -4088,7 +4088,6 @@ int hci_dev_close_sync(struct hci_dev *hdev)
 
        bt_dev_dbg(hdev, "");
 
-       cancel_work_sync(&hdev->power_on);
        cancel_delayed_work(&hdev->power_off);
        cancel_delayed_work(&hdev->ncmd_timer);
 
@@ -4974,6 +4973,9 @@ int hci_suspend_sync(struct hci_dev *hdev)
                return err;
        }
 
+       /* Update event mask so only the allowed event can wakeup the host */
+       hci_set_event_mask_sync(hdev);
+
        /* Only configure accept list if disconnect succeeded and wake
         * isn't being prevented.
         */
@@ -4985,9 +4987,6 @@ int hci_suspend_sync(struct hci_dev *hdev)
        /* Unpause to take care of updating scanning params */
        hdev->scanning_paused = false;
 
-       /* Update event mask so only the allowed event can wakeup the host */
-       hci_set_event_mask_sync(hdev);
-
        /* Enable event filter for paired devices */
        hci_update_event_filter_sync(hdev);
 
index ae78490..5266866 100644 (file)
@@ -111,7 +111,8 @@ static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn,
 }
 
 /* Find channel with given SCID.
- * Returns locked channel. */
+ * Returns a reference locked channel.
+ */
 static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn,
                                                 u16 cid)
 {
@@ -119,15 +120,19 @@ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn,
 
        mutex_lock(&conn->chan_lock);
        c = __l2cap_get_chan_by_scid(conn, cid);
-       if (c)
-               l2cap_chan_lock(c);
+       if (c) {
+               /* Only lock if chan reference is not 0 */
+               c = l2cap_chan_hold_unless_zero(c);
+               if (c)
+                       l2cap_chan_lock(c);
+       }
        mutex_unlock(&conn->chan_lock);
 
        return c;
 }
 
 /* Find channel with given DCID.
- * Returns locked channel.
+ * Returns a reference locked channel.
  */
 static struct l2cap_chan *l2cap_get_chan_by_dcid(struct l2cap_conn *conn,
                                                 u16 cid)
@@ -136,8 +141,12 @@ static struct l2cap_chan *l2cap_get_chan_by_dcid(struct l2cap_conn *conn,
 
        mutex_lock(&conn->chan_lock);
        c = __l2cap_get_chan_by_dcid(conn, cid);
-       if (c)
-               l2cap_chan_lock(c);
+       if (c) {
+               /* Only lock if chan reference is not 0 */
+               c = l2cap_chan_hold_unless_zero(c);
+               if (c)
+                       l2cap_chan_lock(c);
+       }
        mutex_unlock(&conn->chan_lock);
 
        return c;
@@ -162,8 +171,12 @@ static struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn,
 
        mutex_lock(&conn->chan_lock);
        c = __l2cap_get_chan_by_ident(conn, ident);
-       if (c)
-               l2cap_chan_lock(c);
+       if (c) {
+               /* Only lock if chan reference is not 0 */
+               c = l2cap_chan_hold_unless_zero(c);
+               if (c)
+                       l2cap_chan_lock(c);
+       }
        mutex_unlock(&conn->chan_lock);
 
        return c;
@@ -497,6 +510,16 @@ void l2cap_chan_hold(struct l2cap_chan *c)
        kref_get(&c->kref);
 }
 
+struct l2cap_chan *l2cap_chan_hold_unless_zero(struct l2cap_chan *c)
+{
+       BT_DBG("chan %p orig refcnt %u", c, kref_read(&c->kref));
+
+       if (!kref_get_unless_zero(&c->kref))
+               return NULL;
+
+       return c;
+}
+
 void l2cap_chan_put(struct l2cap_chan *c)
 {
        BT_DBG("chan %p orig refcnt %u", c, kref_read(&c->kref));
@@ -1968,7 +1991,10 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm,
                        src_match = !bacmp(&c->src, src);
                        dst_match = !bacmp(&c->dst, dst);
                        if (src_match && dst_match) {
-                               l2cap_chan_hold(c);
+                               c = l2cap_chan_hold_unless_zero(c);
+                               if (!c)
+                                       continue;
+
                                read_unlock(&chan_list_lock);
                                return c;
                        }
@@ -1983,7 +2009,7 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm,
        }
 
        if (c1)
-               l2cap_chan_hold(c1);
+               c1 = l2cap_chan_hold_unless_zero(c1);
 
        read_unlock(&chan_list_lock);
 
@@ -4463,6 +4489,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
 
 unlock:
        l2cap_chan_unlock(chan);
+       l2cap_chan_put(chan);
        return err;
 }
 
@@ -4577,6 +4604,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
 
 done:
        l2cap_chan_unlock(chan);
+       l2cap_chan_put(chan);
        return err;
 }
 
@@ -5304,6 +5332,7 @@ send_move_response:
        l2cap_send_move_chan_rsp(chan, result);
 
        l2cap_chan_unlock(chan);
+       l2cap_chan_put(chan);
 
        return 0;
 }
@@ -5396,6 +5425,7 @@ static void l2cap_move_continue(struct l2cap_conn *conn, u16 icid, u16 result)
        }
 
        l2cap_chan_unlock(chan);
+       l2cap_chan_put(chan);
 }
 
 static void l2cap_move_fail(struct l2cap_conn *conn, u8 ident, u16 icid,
@@ -5425,6 +5455,7 @@ static void l2cap_move_fail(struct l2cap_conn *conn, u8 ident, u16 icid,
        l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED);
 
        l2cap_chan_unlock(chan);
+       l2cap_chan_put(chan);
 }
 
 static int l2cap_move_channel_rsp(struct l2cap_conn *conn,
@@ -5488,6 +5519,7 @@ static int l2cap_move_channel_confirm(struct l2cap_conn *conn,
        l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
 
        l2cap_chan_unlock(chan);
+       l2cap_chan_put(chan);
 
        return 0;
 }
@@ -5523,6 +5555,7 @@ static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
        }
 
        l2cap_chan_unlock(chan);
+       l2cap_chan_put(chan);
 
        return 0;
 }
@@ -5895,12 +5928,11 @@ static inline int l2cap_le_credits(struct l2cap_conn *conn,
        if (credits > max_credits) {
                BT_ERR("LE credits overflow");
                l2cap_send_disconn_req(chan, ECONNRESET);
-               l2cap_chan_unlock(chan);
 
                /* Return 0 so that we don't trigger an unnecessary
                 * command reject packet.
                 */
-               return 0;
+               goto unlock;
        }
 
        chan->tx_credits += credits;
@@ -5911,7 +5943,9 @@ static inline int l2cap_le_credits(struct l2cap_conn *conn,
        if (chan->tx_credits)
                chan->ops->resume(chan);
 
+unlock:
        l2cap_chan_unlock(chan);
+       l2cap_chan_put(chan);
 
        return 0;
 }
@@ -7597,6 +7631,7 @@ drop:
 
 done:
        l2cap_chan_unlock(chan);
+       l2cap_chan_put(chan);
 }
 
 static void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm,
@@ -8085,7 +8120,7 @@ static struct l2cap_chan *l2cap_global_fixed_chan(struct l2cap_chan *c,
                if (src_type != c->src_type)
                        continue;
 
-               l2cap_chan_hold(c);
+               c = l2cap_chan_hold_unless_zero(c);
                read_unlock(&chan_list_lock);
                return c;
        }
index ae758ab..2f91a8c 100644 (file)
@@ -4723,7 +4723,6 @@ static int __add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
                else
                        status = MGMT_STATUS_FAILED;
 
-               mgmt_pending_remove(cmd);
                goto unlock;
        }
 
index 4fd8826..ff47790 100644 (file)
@@ -1012,9 +1012,24 @@ int br_nf_hook_thresh(unsigned int hook, struct net *net,
                return okfn(net, sk, skb);
 
        ops = nf_hook_entries_get_hook_ops(e);
-       for (i = 0; i < e->num_hook_entries &&
-             ops[i]->priority <= NF_BR_PRI_BRNF; i++)
-               ;
+       for (i = 0; i < e->num_hook_entries; i++) {
+               /* These hooks have already been called */
+               if (ops[i]->priority < NF_BR_PRI_BRNF)
+                       continue;
+
+               /* These hooks have not been called yet, run them. */
+               if (ops[i]->priority > NF_BR_PRI_BRNF)
+                       break;
+
+               /* take a closer look at NF_BR_PRI_BRNF. */
+               if (ops[i]->hook == br_nf_pre_routing) {
+                       /* This hook diverted the skb to this function,
+                        * hooks after this have not been run yet.
+                        */
+                       i++;
+                       break;
+               }
+       }
 
        nf_hook_state_init(&state, hook, NFPROTO_BRIDGE, indev, outdev,
                           sk, net, okfn);
index bb01776..c96509c 100644 (file)
@@ -589,9 +589,13 @@ static int br_fill_ifinfo(struct sk_buff *skb,
        }
 
 done:
+       if (af) {
+               if (nlmsg_get_pos(skb) - (void *)af > nla_attr_size(0))
+                       nla_nest_end(skb, af);
+               else
+                       nla_nest_cancel(skb, af);
+       }
 
-       if (af)
-               nla_nest_end(skb, af);
        nlmsg_end(skb, nlh);
        return 0;
 
index 251e666..748be72 100644 (file)
@@ -47,7 +47,7 @@ enum caif_states {
 struct caifsock {
        struct sock sk; /* must be first member */
        struct cflayer layer;
-       u32 flow_state;
+       unsigned long flow_state;
        struct caif_connect_request conn_req;
        struct mutex readlock;
        struct dentry *debugfs_socket_dir;
@@ -56,38 +56,32 @@ struct caifsock {
 
 static int rx_flow_is_on(struct caifsock *cf_sk)
 {
-       return test_bit(RX_FLOW_ON_BIT,
-                       (void *) &cf_sk->flow_state);
+       return test_bit(RX_FLOW_ON_BIT, &cf_sk->flow_state);
 }
 
 static int tx_flow_is_on(struct caifsock *cf_sk)
 {
-       return test_bit(TX_FLOW_ON_BIT,
-                       (void *) &cf_sk->flow_state);
+       return test_bit(TX_FLOW_ON_BIT, &cf_sk->flow_state);
 }
 
 static void set_rx_flow_off(struct caifsock *cf_sk)
 {
-        clear_bit(RX_FLOW_ON_BIT,
-                (void *) &cf_sk->flow_state);
+       clear_bit(RX_FLOW_ON_BIT, &cf_sk->flow_state);
 }
 
 static void set_rx_flow_on(struct caifsock *cf_sk)
 {
-        set_bit(RX_FLOW_ON_BIT,
-                       (void *) &cf_sk->flow_state);
+       set_bit(RX_FLOW_ON_BIT, &cf_sk->flow_state);
 }
 
 static void set_tx_flow_off(struct caifsock *cf_sk)
 {
-        clear_bit(TX_FLOW_ON_BIT,
-               (void *) &cf_sk->flow_state);
+       clear_bit(TX_FLOW_ON_BIT, &cf_sk->flow_state);
 }
 
 static void set_tx_flow_on(struct caifsock *cf_sk)
 {
-        set_bit(TX_FLOW_ON_BIT,
-               (void *) &cf_sk->flow_state);
+       set_bit(TX_FLOW_ON_BIT, &cf_sk->flow_state);
 }
 
 static void caif_read_lock(struct sock *sk)
index 65ee1b7..e60161b 100644 (file)
@@ -100,6 +100,7 @@ static inline u64 get_u64(const struct canfd_frame *cp, int offset)
 
 struct bcm_op {
        struct list_head list;
+       struct rcu_head rcu;
        int ifindex;
        canid_t can_id;
        u32 flags;
@@ -718,10 +719,9 @@ static struct bcm_op *bcm_find_op(struct list_head *ops,
        return NULL;
 }
 
-static void bcm_remove_op(struct bcm_op *op)
+static void bcm_free_op_rcu(struct rcu_head *rcu_head)
 {
-       hrtimer_cancel(&op->timer);
-       hrtimer_cancel(&op->thrtimer);
+       struct bcm_op *op = container_of(rcu_head, struct bcm_op, rcu);
 
        if ((op->frames) && (op->frames != &op->sframe))
                kfree(op->frames);
@@ -732,6 +732,14 @@ static void bcm_remove_op(struct bcm_op *op)
        kfree(op);
 }
 
+static void bcm_remove_op(struct bcm_op *op)
+{
+       hrtimer_cancel(&op->timer);
+       hrtimer_cancel(&op->thrtimer);
+
+       call_rcu(&op->rcu, bcm_free_op_rcu);
+}
+
 static void bcm_rx_unreg(struct net_device *dev, struct bcm_op *op)
 {
        if (op->rx_reg_dev == dev) {
@@ -757,6 +765,9 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
                if ((op->can_id == mh->can_id) && (op->ifindex == ifindex) &&
                    (op->flags & CAN_FD_FRAME) == (mh->flags & CAN_FD_FRAME)) {
 
+                       /* disable automatic timer on frame reception */
+                       op->flags |= RX_NO_AUTOTIMER;
+
                        /*
                         * Don't care if we're bound or not (due to netdev
                         * problems) can_rx_unregister() is always a save
@@ -785,7 +796,6 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
                                                  bcm_rx_handler, op);
 
                        list_del(&op->list);
-                       synchronize_rcu();
                        bcm_remove_op(op);
                        return 1; /* done */
                }
index 210fc3b..fe9be3c 100644 (file)
 #include <net/compat.h>
 
 int __get_compat_msghdr(struct msghdr *kmsg,
-                       struct compat_msghdr __user *umsg,
-                       struct sockaddr __user **save_addr,
-                       compat_uptr_t *ptr, compat_size_t *len)
+                       struct compat_msghdr *msg,
+                       struct sockaddr __user **save_addr)
 {
-       struct compat_msghdr msg;
        ssize_t err;
 
-       if (copy_from_user(&msg, umsg, sizeof(*umsg)))
-               return -EFAULT;
-
-       kmsg->msg_flags = msg.msg_flags;
-       kmsg->msg_namelen = msg.msg_namelen;
+       kmsg->msg_flags = msg->msg_flags;
+       kmsg->msg_namelen = msg->msg_namelen;
 
-       if (!msg.msg_name)
+       if (!msg->msg_name)
                kmsg->msg_namelen = 0;
 
        if (kmsg->msg_namelen < 0)
@@ -57,15 +52,15 @@ int __get_compat_msghdr(struct msghdr *kmsg,
                kmsg->msg_namelen = sizeof(struct sockaddr_storage);
 
        kmsg->msg_control_is_user = true;
-       kmsg->msg_control_user = compat_ptr(msg.msg_control);
-       kmsg->msg_controllen = msg.msg_controllen;
+       kmsg->msg_control_user = compat_ptr(msg->msg_control);
+       kmsg->msg_controllen = msg->msg_controllen;
 
        if (save_addr)
-               *save_addr = compat_ptr(msg.msg_name);
+               *save_addr = compat_ptr(msg->msg_name);
 
-       if (msg.msg_name && kmsg->msg_namelen) {
+       if (msg->msg_name && kmsg->msg_namelen) {
                if (!save_addr) {
-                       err = move_addr_to_kernel(compat_ptr(msg.msg_name),
+                       err = move_addr_to_kernel(compat_ptr(msg->msg_name),
                                                  kmsg->msg_namelen,
                                                  kmsg->msg_name);
                        if (err < 0)
@@ -76,12 +71,11 @@ int __get_compat_msghdr(struct msghdr *kmsg,
                kmsg->msg_namelen = 0;
        }
 
-       if (msg.msg_iovlen > UIO_MAXIOV)
+       if (msg->msg_iovlen > UIO_MAXIOV)
                return -EMSGSIZE;
 
        kmsg->msg_iocb = NULL;
-       *ptr = msg.msg_iov;
-       *len = msg.msg_iovlen;
+       kmsg->msg_ubuf = NULL;
        return 0;
 }
 
@@ -90,15 +84,17 @@ int get_compat_msghdr(struct msghdr *kmsg,
                      struct sockaddr __user **save_addr,
                      struct iovec **iov)
 {
-       compat_uptr_t ptr;
-       compat_size_t len;
+       struct compat_msghdr msg;
        ssize_t err;
 
-       err = __get_compat_msghdr(kmsg, umsg, save_addr, &ptr, &len);
+       if (copy_from_user(&msg, umsg, sizeof(*umsg)))
+               return -EFAULT;
+
+       err = __get_compat_msghdr(kmsg, &msg, save_addr);
        if (err)
                return err;
 
-       err = import_iovec(save_addr ? READ : WRITE, compat_ptr(ptr), len,
+       err = import_iovec(save_addr ? READ : WRITE, compat_ptr(msg.msg_iov), msg.msg_iovlen,
                           UIO_FASTIOV, iov, &kmsg->msg_iter);
        return err < 0 ? err : 0;
 }
index 50f4fae..ecbc0f4 100644 (file)
@@ -613,10 +613,16 @@ fault:
 }
 EXPORT_SYMBOL(skb_copy_datagram_from_iter);
 
-int __zerocopy_sg_from_iter(struct sock *sk, struct sk_buff *skb,
-                           struct iov_iter *from, size_t length)
+int __zerocopy_sg_from_iter(struct msghdr *msg, struct sock *sk,
+                           struct sk_buff *skb, struct iov_iter *from,
+                           size_t length)
 {
-       int frag = skb_shinfo(skb)->nr_frags;
+       int frag;
+
+       if (msg && msg->msg_ubuf && msg->sg_from_iter)
+               return msg->sg_from_iter(sk, skb, from, length);
+
+       frag = skb_shinfo(skb)->nr_frags;
 
        while (length && iov_iter_count(from)) {
                struct page *pages[MAX_SKB_FRAGS];
@@ -702,7 +708,7 @@ int zerocopy_sg_from_iter(struct sk_buff *skb, struct iov_iter *from)
        if (skb_copy_datagram_from_iter(skb, 0, from, copy))
                return -EFAULT;
 
-       return __zerocopy_sg_from_iter(NULL, skb, from, ~0U);
+       return __zerocopy_sg_from_iter(NULL, NULL, skb, from, ~0U);
 }
 EXPORT_SYMBOL(zerocopy_sg_from_iter);
 
index 8e6f229..30a1603 100644 (file)
@@ -4863,7 +4863,10 @@ static u32 netif_receive_generic_xdp(struct sk_buff *skb,
 }
 
 /* When doing generic XDP we have to bypass the qdisc layer and the
- * network taps in order to match in-driver-XDP behavior.
+ * network taps in order to match in-driver-XDP behavior. This also means
+ * that XDP packets are able to starve other packets going through a qdisc,
+ * and DDOS attacks will be more effective. In-driver-XDP use dedicated TX
+ * queues, so they do not have this starvation issue.
  */
 void generic_xdp_tx(struct sk_buff *skb, struct bpf_prog *xdp_prog)
 {
@@ -4875,7 +4878,7 @@ void generic_xdp_tx(struct sk_buff *skb, struct bpf_prog *xdp_prog)
        txq = netdev_core_pick_tx(dev, skb, NULL);
        cpu = smp_processor_id();
        HARD_TX_LOCK(dev, txq, cpu);
-       if (!netif_xmit_stopped(txq)) {
+       if (!netif_xmit_frozen_or_drv_stopped(txq)) {
                rc = netdev_start_xmit(skb, dev, txq, 0);
                if (dev_xmit_complete(rc))
                        free_skb = false;
@@ -4883,6 +4886,7 @@ void generic_xdp_tx(struct sk_buff *skb, struct bpf_prog *xdp_prog)
        HARD_TX_UNLOCK(dev, txq);
        if (free_skb) {
                trace_xdp_exception(dev, xdp_prog, XDP_TX);
+               dev_core_stats_tx_dropped_inc(dev);
                kfree_skb(skb);
        }
 }
index 5d16d66..7950f75 100644 (file)
@@ -6158,7 +6158,6 @@ static int bpf_push_seg6_encap(struct sk_buff *skb, u32 type, void *hdr, u32 len
        if (err)
                return err;
 
-       ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
        skb_set_transport_header(skb, sizeof(struct ipv6hdr));
 
        return seg6_lookup_nexthop(skb, NULL, 0);
@@ -7042,7 +7041,7 @@ BPF_CALL_5(bpf_tcp_check_syncookie, struct sock *, sk, void *, iph, u32, iph_len
        if (sk->sk_protocol != IPPROTO_TCP || sk->sk_state != TCP_LISTEN)
                return -EINVAL;
 
-       if (!sock_net(sk)->ipv4.sysctl_tcp_syncookies)
+       if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_syncookies))
                return -EINVAL;
 
        if (!th->ack || th->rst || th->syn)
@@ -7117,7 +7116,7 @@ BPF_CALL_5(bpf_tcp_gen_syncookie, struct sock *, sk, void *, iph, u32, iph_len,
        if (sk->sk_protocol != IPPROTO_TCP || sk->sk_state != TCP_LISTEN)
                return -EINVAL;
 
-       if (!sock_net(sk)->ipv4.sysctl_tcp_syncookies)
+       if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_syncookies))
                return -ENOENT;
 
        if (!th->syn || th->ack || th->fin || th->rst)
index 5f85e01..b0ff615 100644 (file)
@@ -64,7 +64,7 @@ u32 secure_tcpv6_ts_off(const struct net *net,
                .daddr = *(struct in6_addr *)daddr,
        };
 
-       if (net->ipv4.sysctl_tcp_timestamps != 1)
+       if (READ_ONCE(net->ipv4.sysctl_tcp_timestamps) != 1)
                return 0;
 
        ts_secret_init();
@@ -120,7 +120,7 @@ EXPORT_SYMBOL(secure_ipv6_port_ephemeral);
 #ifdef CONFIG_INET
 u32 secure_tcp_ts_off(const struct net *net, __be32 saddr, __be32 daddr)
 {
-       if (net->ipv4.sysctl_tcp_timestamps != 1)
+       if (READ_ONCE(net->ipv4.sysctl_tcp_timestamps) != 1)
                return 0;
 
        ts_secret_init();
index 5b3559c..cf4107d 100644 (file)
@@ -666,11 +666,18 @@ static void skb_release_data(struct sk_buff *skb)
                              &shinfo->dataref))
                goto exit;
 
-       skb_zcopy_clear(skb, true);
+       if (skb_zcopy(skb)) {
+               bool skip_unref = shinfo->flags & SKBFL_MANAGED_FRAG_REFS;
+
+               skb_zcopy_clear(skb, true);
+               if (skip_unref)
+                       goto free_head;
+       }
 
        for (i = 0; i < shinfo->nr_frags; i++)
                __skb_frag_unref(&shinfo->frags[i], skb->pp_recycle);
 
+free_head:
        if (shinfo->frag_list)
                kfree_skb_list(shinfo->frag_list);
 
@@ -895,7 +902,10 @@ EXPORT_SYMBOL(skb_dump);
  */
 void skb_tx_error(struct sk_buff *skb)
 {
-       skb_zcopy_clear(skb, true);
+       if (skb) {
+               skb_zcopy_downgrade_managed(skb);
+               skb_zcopy_clear(skb, true);
+       }
 }
 EXPORT_SYMBOL(skb_tx_error);
 
@@ -1193,7 +1203,7 @@ static struct ubuf_info *msg_zerocopy_alloc(struct sock *sk, size_t size)
        uarg->len = 1;
        uarg->bytelen = size;
        uarg->zerocopy = 1;
-       uarg->flags = SKBFL_ZEROCOPY_FRAG;
+       uarg->flags = SKBFL_ZEROCOPY_FRAG | SKBFL_DONT_ORPHAN;
        refcount_set(&uarg->refcnt, 1);
        sock_hold(sk);
 
@@ -1212,6 +1222,10 @@ struct ubuf_info *msg_zerocopy_realloc(struct sock *sk, size_t size,
                const u32 byte_limit = 1 << 19;         /* limit to a few TSO */
                u32 bytelen, next;
 
+               /* there might be non MSG_ZEROCOPY users */
+               if (uarg->callback != msg_zerocopy_callback)
+                       return NULL;
+
                /* realloc only when socket is locked (TCP, UDP cork),
                 * so uarg->len and sk_zckey access is serialized
                 */
@@ -1354,7 +1368,7 @@ int skb_zerocopy_iter_stream(struct sock *sk, struct sk_buff *skb,
        if (orig_uarg && uarg != orig_uarg)
                return -EEXIST;
 
-       err = __zerocopy_sg_from_iter(sk, skb, &msg->msg_iter, len);
+       err = __zerocopy_sg_from_iter(msg, sk, skb, &msg->msg_iter, len);
        if (err == -EFAULT || (err == -EMSGSIZE && skb->len == orig_len)) {
                struct sock *save_sk = skb->sk;
 
@@ -1371,6 +1385,16 @@ int skb_zerocopy_iter_stream(struct sock *sk, struct sk_buff *skb,
 }
 EXPORT_SYMBOL_GPL(skb_zerocopy_iter_stream);
 
+void __skb_zcopy_downgrade_managed(struct sk_buff *skb)
+{
+       int i;
+
+       skb_shinfo(skb)->flags &= ~SKBFL_MANAGED_FRAG_REFS;
+       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
+               skb_frag_ref(skb, i);
+}
+EXPORT_SYMBOL_GPL(__skb_zcopy_downgrade_managed);
+
 static int skb_zerocopy_clone(struct sk_buff *nskb, struct sk_buff *orig,
                              gfp_t gfp_mask)
 {
@@ -1688,6 +1712,8 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
 
        BUG_ON(skb_shared(skb));
 
+       skb_zcopy_downgrade_managed(skb);
+
        size = SKB_DATA_ALIGN(size);
 
        if (skb_pfmemalloc(skb))
@@ -3484,6 +3510,8 @@ void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len)
        int pos = skb_headlen(skb);
        const int zc_flags = SKBFL_SHARED_FRAG | SKBFL_PURE_ZEROCOPY;
 
+       skb_zcopy_downgrade_managed(skb);
+
        skb_shinfo(skb1)->flags |= skb_shinfo(skb)->flags & zc_flags;
        skb_zerocopy_clone(skb1, skb, 0);
        if (len < pos)  /* Split line is inside header. */
@@ -3837,6 +3865,7 @@ int skb_append_pagefrags(struct sk_buff *skb, struct page *page,
        if (skb_can_coalesce(skb, i, page, offset)) {
                skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], size);
        } else if (i < MAX_SKB_FRAGS) {
+               skb_zcopy_downgrade_managed(skb);
                get_page(page);
                skb_fill_page_desc(skb, i, page, offset, size);
        } else {
index 3f00a28..5daa1fa 100644 (file)
@@ -387,7 +387,7 @@ void reuseport_stop_listen_sock(struct sock *sk)
                prog = rcu_dereference_protected(reuse->prog,
                                                 lockdep_is_held(&reuseport_lock));
 
-               if (sock_net(sk)->ipv4.sysctl_tcp_migrate_req ||
+               if (READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_migrate_req) ||
                    (prog && prog->expected_attach_type == BPF_SK_REUSEPORT_SELECT_OR_MIGRATE)) {
                        /* Migration capable, move sk from the listening section
                         * to the closed section.
@@ -545,7 +545,7 @@ struct sock *reuseport_migrate_sock(struct sock *sk,
        hash = migrating_sk->sk_hash;
        prog = rcu_dereference(reuse->prog);
        if (!prog || prog->expected_attach_type != BPF_SK_REUSEPORT_SELECT_OR_MIGRATE) {
-               if (sock_net(sk)->ipv4.sysctl_tcp_migrate_req)
+               if (READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_migrate_req))
                        goto select_by_hash;
                goto failure;
        }
index dc92a67..7d542eb 100644 (file)
@@ -480,8 +480,8 @@ static struct sock *dn_alloc_sock(struct net *net, struct socket *sock, gfp_t gf
        sk->sk_family      = PF_DECnet;
        sk->sk_protocol    = 0;
        sk->sk_allocation  = gfp;
-       sk->sk_sndbuf      = sysctl_decnet_wmem[1];
-       sk->sk_rcvbuf      = sysctl_decnet_rmem[1];
+       sk->sk_sndbuf      = READ_ONCE(sysctl_decnet_wmem[1]);
+       sk->sk_rcvbuf      = READ_ONCE(sysctl_decnet_rmem[1]);
 
        /* Initialization of DECnet Session Control Port                */
        scp = DN_SK(sk);
index 3738f2d..2dd76eb 100644 (file)
@@ -248,6 +248,7 @@ static void dsa_port_reset_vlan_filtering(struct dsa_port *dp,
        struct netlink_ext_ack extack = {0};
        bool change_vlan_filtering = false;
        struct dsa_switch *ds = dp->ds;
+       struct dsa_port *other_dp;
        bool vlan_filtering;
        int err;
 
@@ -270,8 +271,8 @@ static void dsa_port_reset_vlan_filtering(struct dsa_port *dp,
         * VLAN-aware bridge.
         */
        if (change_vlan_filtering && ds->vlan_filtering_is_global) {
-               dsa_switch_for_each_port(dp, ds) {
-                       struct net_device *br = dsa_port_bridge_dev_get(dp);
+               dsa_switch_for_each_port(other_dp, ds) {
+                       struct net_device *br = dsa_port_bridge_dev_get(other_dp);
 
                        if (br && br_vlan_enabled(br)) {
                                change_vlan_filtering = false;
@@ -799,7 +800,7 @@ int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering,
                ds->vlan_filtering = vlan_filtering;
 
                dsa_switch_for_each_user_port(other_dp, ds) {
-                       struct net_device *slave = dp->slave;
+                       struct net_device *slave = other_dp->slave;
 
                        /* We might be called in the unbind path, so not
                         * all slave devices might still be registered.
index 2b56218..4dfd68c 100644 (file)
@@ -344,6 +344,7 @@ static int dsa_switch_do_lag_fdb_add(struct dsa_switch *ds, struct dsa_lag *lag,
 
        ether_addr_copy(a->addr, addr);
        a->vid = vid;
+       a->db = db;
        refcount_set(&a->refcount, 1);
        list_add_tail(&a->list, &lag->fdbs);
 
index 93da9f7..252c8bc 100644 (file)
@@ -217,7 +217,7 @@ int inet_listen(struct socket *sock, int backlog)
                 * because the socket was in TCP_LISTEN state previously but
                 * was shutdown() rather than close().
                 */
-               tcp_fastopen = sock_net(sk)->ipv4.sysctl_tcp_fastopen;
+               tcp_fastopen = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_fastopen);
                if ((tcp_fastopen & TFO_SERVER_WO_SOCKOPT1) &&
                    (tcp_fastopen & TFO_SERVER_ENABLE) &&
                    !inet_csk(sk)->icsk_accept_queue.fastopenq.max_qlen) {
@@ -335,7 +335,7 @@ lookup_protocol:
                        inet->hdrincl = 1;
        }
 
-       if (net->ipv4.sysctl_ip_no_pmtu_disc)
+       if (READ_ONCE(net->ipv4.sysctl_ip_no_pmtu_disc))
                inet->pmtudisc = IP_PMTUDISC_DONT;
        else
                inet->pmtudisc = IP_PMTUDISC_WANT;
@@ -1246,7 +1246,7 @@ static int inet_sk_reselect_saddr(struct sock *sk)
        if (new_saddr == old_saddr)
                return 0;
 
-       if (sock_net(sk)->ipv4.sysctl_ip_dynaddr > 1) {
+       if (READ_ONCE(sock_net(sk)->ipv4.sysctl_ip_dynaddr) > 1) {
                pr_info("%s(): shifting inet->saddr from %pI4 to %pI4\n",
                        __func__, &old_saddr, &new_saddr);
        }
@@ -1301,7 +1301,7 @@ int inet_sk_rebuild_header(struct sock *sk)
                 * Other protocols have to map its equivalent state to TCP_SYN_SENT.
                 * DCCP maps its DCCP_REQUESTING state to TCP_SYN_SENT. -acme
                 */
-               if (!sock_net(sk)->ipv4.sysctl_ip_dynaddr ||
+               if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_ip_dynaddr) ||
                    sk->sk_state != TCP_SYN_SENT ||
                    (sk->sk_userlocks & SOCK_BINDADDR_LOCK) ||
                    (err = inet_sk_reselect_saddr(sk)) != 0)
@@ -1710,24 +1710,14 @@ static const struct net_protocol igmp_protocol = {
 };
 #endif
 
-/* thinking of making this const? Don't.
- * early_demux can change based on sysctl.
- */
-static struct net_protocol tcp_protocol = {
-       .early_demux    =       tcp_v4_early_demux,
-       .early_demux_handler =  tcp_v4_early_demux,
+static const struct net_protocol tcp_protocol = {
        .handler        =       tcp_v4_rcv,
        .err_handler    =       tcp_v4_err,
        .no_policy      =       1,
        .icmp_strict_tag_validation = 1,
 };
 
-/* thinking of making this const? Don't.
- * early_demux can change based on sysctl.
- */
-static struct net_protocol udp_protocol = {
-       .early_demux =  udp_v4_early_demux,
-       .early_demux_handler =  udp_v4_early_demux,
+static const struct net_protocol udp_protocol = {
        .handler =      udp_rcv,
        .err_handler =  udp_err,
        .no_policy =    1,
index 6eea1e9..f8ad044 100644 (file)
@@ -507,7 +507,7 @@ static int ah_init_state(struct xfrm_state *x)
 
        if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
            crypto_ahash_digestsize(ahash)) {
-               pr_info("%s: %s digestsize %u != %hu\n",
+               pr_info("%s: %s digestsize %u != %u\n",
                        __func__, x->aalg->alg_name,
                        crypto_ahash_digestsize(ahash),
                        aalg_desc->uinfo.auth.icv_fullbits / 8);
index 62d5f99..6cd3b6c 100644 (file)
@@ -239,7 +239,7 @@ static int cipso_v4_cache_check(const unsigned char *key,
        struct cipso_v4_map_cache_entry *prev_entry = NULL;
        u32 hash;
 
-       if (!cipso_v4_cache_enabled)
+       if (!READ_ONCE(cipso_v4_cache_enabled))
                return -ENOENT;
 
        hash = cipso_v4_map_cache_hash(key, key_len);
@@ -296,13 +296,14 @@ static int cipso_v4_cache_check(const unsigned char *key,
 int cipso_v4_cache_add(const unsigned char *cipso_ptr,
                       const struct netlbl_lsm_secattr *secattr)
 {
+       int bkt_size = READ_ONCE(cipso_v4_cache_bucketsize);
        int ret_val = -EPERM;
        u32 bkt;
        struct cipso_v4_map_cache_entry *entry = NULL;
        struct cipso_v4_map_cache_entry *old_entry = NULL;
        u32 cipso_ptr_len;
 
-       if (!cipso_v4_cache_enabled || cipso_v4_cache_bucketsize <= 0)
+       if (!READ_ONCE(cipso_v4_cache_enabled) || bkt_size <= 0)
                return 0;
 
        cipso_ptr_len = cipso_ptr[1];
@@ -322,7 +323,7 @@ int cipso_v4_cache_add(const unsigned char *cipso_ptr,
 
        bkt = entry->hash & (CIPSO_V4_CACHE_BUCKETS - 1);
        spin_lock_bh(&cipso_v4_cache[bkt].lock);
-       if (cipso_v4_cache[bkt].size < cipso_v4_cache_bucketsize) {
+       if (cipso_v4_cache[bkt].size < bkt_size) {
                list_add(&entry->list, &cipso_v4_cache[bkt].list);
                cipso_v4_cache[bkt].size += 1;
        } else {
@@ -1199,7 +1200,8 @@ static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def,
                /* This will send packets using the "optimized" format when
                 * possible as specified in  section 3.4.2.6 of the
                 * CIPSO draft. */
-               if (cipso_v4_rbm_optfmt && ret_val > 0 && ret_val <= 10)
+               if (READ_ONCE(cipso_v4_rbm_optfmt) && ret_val > 0 &&
+                   ret_val <= 10)
                        tag_len = 14;
                else
                        tag_len = 4 + ret_val;
@@ -1603,7 +1605,7 @@ int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option)
                         * all the CIPSO validations here but it doesn't
                         * really specify _exactly_ what we need to validate
                         * ... so, just make it a sysctl tunable. */
-                       if (cipso_v4_rbm_strictvalid) {
+                       if (READ_ONCE(cipso_v4_rbm_strictvalid)) {
                                if (cipso_v4_map_lvl_valid(doi_def,
                                                           tag[3]) < 0) {
                                        err_offset = opt_iter + 3;
index b21238d..b694f35 100644 (file)
@@ -1108,7 +1108,7 @@ static int esp_init_authenc(struct xfrm_state *x)
                err = -EINVAL;
                if (aalg_desc->uinfo.auth.icv_fullbits / 8 !=
                    crypto_aead_authsize(aead)) {
-                       pr_info("ESP: %s digestsize %u != %hu\n",
+                       pr_info("ESP: %s digestsize %u != %u\n",
                                x->aalg->alg_name,
                                crypto_aead_authsize(aead),
                                aalg_desc->uinfo.auth.icv_fullbits / 8);
index a57ba23..db7b250 100644 (file)
@@ -1230,7 +1230,7 @@ static int fib_check_nh_nongw(struct net *net, struct fib_nh *nh,
 
        nh->fib_nh_dev = in_dev->dev;
        dev_hold_track(nh->fib_nh_dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC);
-       nh->fib_nh_scope = RT_SCOPE_HOST;
+       nh->fib_nh_scope = RT_SCOPE_LINK;
        if (!netif_carrier_ok(nh->fib_nh_dev))
                nh->fib_nh_flags |= RTNH_F_LINKDOWN;
        err = 0;
@@ -1811,7 +1811,7 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
                        goto nla_put_failure;
                if (nexthop_is_blackhole(fi->nh))
                        rtm->rtm_type = RTN_BLACKHOLE;
-               if (!fi->fib_net->ipv4.sysctl_nexthop_compat_mode)
+               if (!READ_ONCE(fi->fib_net->ipv4.sysctl_nexthop_compat_mode))
                        goto offload;
        }
 
@@ -2216,7 +2216,7 @@ void fib_select_multipath(struct fib_result *res, int hash)
        }
 
        change_nexthops(fi) {
-               if (net->ipv4.sysctl_fib_multipath_use_neigh) {
+               if (READ_ONCE(net->ipv4.sysctl_fib_multipath_use_neigh)) {
                        if (!fib_good_nh(nexthop_nh))
                                continue;
                        if (!first) {
index 2734c3a..452ff17 100644 (file)
@@ -498,7 +498,7 @@ static void tnode_free(struct key_vector *tn)
                tn = container_of(head, struct tnode, rcu)->kv;
        }
 
-       if (tnode_free_size >= sysctl_fib_sync_mem) {
+       if (tnode_free_size >= READ_ONCE(sysctl_fib_sync_mem)) {
                tnode_free_size = 0;
                synchronize_rcu();
        }
@@ -1042,6 +1042,7 @@ fib_find_matching_alias(struct net *net, const struct fib_rt_info *fri)
 
 void fib_alias_hw_flags_set(struct net *net, const struct fib_rt_info *fri)
 {
+       u8 fib_notify_on_flag_change;
        struct fib_alias *fa_match;
        struct sk_buff *skb;
        int err;
@@ -1063,14 +1064,16 @@ void fib_alias_hw_flags_set(struct net *net, const struct fib_rt_info *fri)
        WRITE_ONCE(fa_match->offload, fri->offload);
        WRITE_ONCE(fa_match->trap, fri->trap);
 
+       fib_notify_on_flag_change = READ_ONCE(net->ipv4.sysctl_fib_notify_on_flag_change);
+
        /* 2 means send notifications only if offload_failed was changed. */
-       if (net->ipv4.sysctl_fib_notify_on_flag_change == 2 &&
+       if (fib_notify_on_flag_change == 2 &&
            READ_ONCE(fa_match->offload_failed) == fri->offload_failed)
                goto out;
 
        WRITE_ONCE(fa_match->offload_failed, fri->offload_failed);
 
-       if (!net->ipv4.sysctl_fib_notify_on_flag_change)
+       if (!fib_notify_on_flag_change)
                goto out;
 
        skb = nlmsg_new(fib_nlmsg_size(fa_match->fa_info), GFP_ATOMIC);
index efea0e7..d5d745c 100644 (file)
@@ -253,11 +253,12 @@ bool icmp_global_allow(void)
        spin_lock(&icmp_global.lock);
        delta = min_t(u32, now - icmp_global.stamp, HZ);
        if (delta >= HZ / 50) {
-               incr = sysctl_icmp_msgs_per_sec * delta / HZ ;
+               incr = READ_ONCE(sysctl_icmp_msgs_per_sec) * delta / HZ;
                if (incr)
                        WRITE_ONCE(icmp_global.stamp, now);
        }
-       credit = min_t(u32, icmp_global.credit + incr, sysctl_icmp_msgs_burst);
+       credit = min_t(u32, icmp_global.credit + incr,
+                      READ_ONCE(sysctl_icmp_msgs_burst));
        if (credit) {
                /* We want to use a credit of one in average, but need to randomize
                 * it for security reasons.
@@ -281,7 +282,7 @@ static bool icmpv4_mask_allow(struct net *net, int type, int code)
                return true;
 
        /* Limit if icmp type is enabled in ratemask. */
-       if (!((1 << type) & net->ipv4.sysctl_icmp_ratemask))
+       if (!((1 << type) & READ_ONCE(net->ipv4.sysctl_icmp_ratemask)))
                return true;
 
        return false;
@@ -319,7 +320,8 @@ static bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
 
        vif = l3mdev_master_ifindex(dst->dev);
        peer = inet_getpeer_v4(net->ipv4.peers, fl4->daddr, vif, 1);
-       rc = inet_peer_xrlim_allow(peer, net->ipv4.sysctl_icmp_ratelimit);
+       rc = inet_peer_xrlim_allow(peer,
+                                  READ_ONCE(net->ipv4.sysctl_icmp_ratelimit));
        if (peer)
                inet_putpeer(peer);
 out:
@@ -692,7 +694,7 @@ void __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info,
 
                rcu_read_lock();
                if (rt_is_input_route(rt) &&
-                   net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr)
+                   READ_ONCE(net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr))
                        dev = dev_get_by_index_rcu(net, inet_iif(skb_in));
 
                if (dev)
@@ -879,7 +881,7 @@ static enum skb_drop_reason icmp_unreach(struct sk_buff *skb)
                         * values please see
                         * Documentation/networking/ip-sysctl.rst
                         */
-                       switch (net->ipv4.sysctl_ip_no_pmtu_disc) {
+                       switch (READ_ONCE(net->ipv4.sysctl_ip_no_pmtu_disc)) {
                        default:
                                net_dbg_ratelimited("%pI4: fragmentation needed and DF set\n",
                                                    &iph->daddr);
@@ -932,7 +934,7 @@ static enum skb_drop_reason icmp_unreach(struct sk_buff *skb)
         *      get the other vendor to fix their kit.
         */
 
-       if (!net->ipv4.sysctl_icmp_ignore_bogus_error_responses &&
+       if (!READ_ONCE(net->ipv4.sysctl_icmp_ignore_bogus_error_responses) &&
            inet_addr_type_dev_table(net, skb->dev, iph->daddr) == RTN_BROADCAST) {
                net_warn_ratelimited("%pI4 sent an invalid ICMP type %u, code %u error to a broadcast: %pI4 on %s\n",
                                     &ip_hdr(skb)->saddr,
@@ -992,7 +994,7 @@ static enum skb_drop_reason icmp_echo(struct sk_buff *skb)
 
        net = dev_net(skb_dst(skb)->dev);
        /* should there be an ICMP stat for ignored echos? */
-       if (net->ipv4.sysctl_icmp_echo_ignore_all)
+       if (READ_ONCE(net->ipv4.sysctl_icmp_echo_ignore_all))
                return SKB_NOT_DROPPED_YET;
 
        icmp_param.data.icmph      = *icmp_hdr(skb);
@@ -1027,7 +1029,7 @@ bool icmp_build_probe(struct sk_buff *skb, struct icmphdr *icmphdr)
        u16 ident_len;
        u8 status;
 
-       if (!net->ipv4.sysctl_icmp_echo_enable_probe)
+       if (!READ_ONCE(net->ipv4.sysctl_icmp_echo_enable_probe))
                return false;
 
        /* We currently only support probing interfaces on the proxy node
@@ -1248,7 +1250,7 @@ int icmp_rcv(struct sk_buff *skb)
                 */
                if ((icmph->type == ICMP_ECHO ||
                     icmph->type == ICMP_TIMESTAMP) &&
-                   net->ipv4.sysctl_icmp_echo_ignore_broadcasts) {
+                   READ_ONCE(net->ipv4.sysctl_icmp_echo_ignore_broadcasts)) {
                        reason = SKB_DROP_REASON_INVALID_PROTO;
                        goto error;
                }
index b65d074..e3ab0cb 100644 (file)
@@ -467,7 +467,8 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc,
 
        if (pmc->multiaddr == IGMP_ALL_HOSTS)
                return skb;
-       if (ipv4_is_local_multicast(pmc->multiaddr) && !net->ipv4.sysctl_igmp_llm_reports)
+       if (ipv4_is_local_multicast(pmc->multiaddr) &&
+           !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
                return skb;
 
        mtu = READ_ONCE(dev->mtu);
@@ -593,7 +594,7 @@ static int igmpv3_send_report(struct in_device *in_dev, struct ip_mc_list *pmc)
                        if (pmc->multiaddr == IGMP_ALL_HOSTS)
                                continue;
                        if (ipv4_is_local_multicast(pmc->multiaddr) &&
-                            !net->ipv4.sysctl_igmp_llm_reports)
+                           !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
                                continue;
                        spin_lock_bh(&pmc->lock);
                        if (pmc->sfcount[MCAST_EXCLUDE])
@@ -736,7 +737,8 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
        if (type == IGMPV3_HOST_MEMBERSHIP_REPORT)
                return igmpv3_send_report(in_dev, pmc);
 
-       if (ipv4_is_local_multicast(group) && !net->ipv4.sysctl_igmp_llm_reports)
+       if (ipv4_is_local_multicast(group) &&
+           !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
                return 0;
 
        if (type == IGMP_HOST_LEAVE_MESSAGE)
@@ -825,7 +827,7 @@ static void igmp_ifc_event(struct in_device *in_dev)
        struct net *net = dev_net(in_dev->dev);
        if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev))
                return;
-       WRITE_ONCE(in_dev->mr_ifc_count, in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv);
+       WRITE_ONCE(in_dev->mr_ifc_count, in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv));
        igmp_ifc_start_timer(in_dev, 1);
 }
 
@@ -920,7 +922,8 @@ static bool igmp_heard_report(struct in_device *in_dev, __be32 group)
 
        if (group == IGMP_ALL_HOSTS)
                return false;
-       if (ipv4_is_local_multicast(group) && !net->ipv4.sysctl_igmp_llm_reports)
+       if (ipv4_is_local_multicast(group) &&
+           !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
                return false;
 
        rcu_read_lock();
@@ -1006,7 +1009,7 @@ static bool igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
                 * received value was zero, use the default or statically
                 * configured value.
                 */
-               in_dev->mr_qrv = ih3->qrv ?: net->ipv4.sysctl_igmp_qrv;
+               in_dev->mr_qrv = ih3->qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
                in_dev->mr_qi = IGMPV3_QQIC(ih3->qqic)*HZ ?: IGMP_QUERY_INTERVAL;
 
                /* RFC3376, 8.3. Query Response Interval:
@@ -1045,7 +1048,7 @@ static bool igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
                if (im->multiaddr == IGMP_ALL_HOSTS)
                        continue;
                if (ipv4_is_local_multicast(im->multiaddr) &&
-                   !net->ipv4.sysctl_igmp_llm_reports)
+                   !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
                        continue;
                spin_lock_bh(&im->lock);
                if (im->tm_running)
@@ -1186,7 +1189,7 @@ static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im,
        pmc->interface = im->interface;
        in_dev_hold(in_dev);
        pmc->multiaddr = im->multiaddr;
-       pmc->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
+       pmc->crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
        pmc->sfmode = im->sfmode;
        if (pmc->sfmode == MCAST_INCLUDE) {
                struct ip_sf_list *psf;
@@ -1237,9 +1240,11 @@ static void igmpv3_del_delrec(struct in_device *in_dev, struct ip_mc_list *im)
                        swap(im->tomb, pmc->tomb);
                        swap(im->sources, pmc->sources);
                        for (psf = im->sources; psf; psf = psf->sf_next)
-                               psf->sf_crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
+                               psf->sf_crcount = in_dev->mr_qrv ?:
+                                       READ_ONCE(net->ipv4.sysctl_igmp_qrv);
                } else {
-                       im->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
+                       im->crcount = in_dev->mr_qrv ?:
+                               READ_ONCE(net->ipv4.sysctl_igmp_qrv);
                }
                in_dev_put(pmc->interface);
                kfree_pmc(pmc);
@@ -1296,7 +1301,8 @@ static void __igmp_group_dropped(struct ip_mc_list *im, gfp_t gfp)
 #ifdef CONFIG_IP_MULTICAST
        if (im->multiaddr == IGMP_ALL_HOSTS)
                return;
-       if (ipv4_is_local_multicast(im->multiaddr) && !net->ipv4.sysctl_igmp_llm_reports)
+       if (ipv4_is_local_multicast(im->multiaddr) &&
+           !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
                return;
 
        reporter = im->reporter;
@@ -1338,13 +1344,14 @@ static void igmp_group_added(struct ip_mc_list *im)
 #ifdef CONFIG_IP_MULTICAST
        if (im->multiaddr == IGMP_ALL_HOSTS)
                return;
-       if (ipv4_is_local_multicast(im->multiaddr) && !net->ipv4.sysctl_igmp_llm_reports)
+       if (ipv4_is_local_multicast(im->multiaddr) &&
+           !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
                return;
 
        if (in_dev->dead)
                return;
 
-       im->unsolicit_count = net->ipv4.sysctl_igmp_qrv;
+       im->unsolicit_count = READ_ONCE(net->ipv4.sysctl_igmp_qrv);
        if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev)) {
                spin_lock_bh(&im->lock);
                igmp_start_timer(im, IGMP_INITIAL_REPORT_DELAY);
@@ -1358,7 +1365,7 @@ static void igmp_group_added(struct ip_mc_list *im)
         * IN() to IN(A).
         */
        if (im->sfmode == MCAST_EXCLUDE)
-               im->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
+               im->crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
 
        igmp_ifc_event(in_dev);
 #endif
@@ -1642,7 +1649,7 @@ static void ip_mc_rejoin_groups(struct in_device *in_dev)
                if (im->multiaddr == IGMP_ALL_HOSTS)
                        continue;
                if (ipv4_is_local_multicast(im->multiaddr) &&
-                   !net->ipv4.sysctl_igmp_llm_reports)
+                   !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
                        continue;
 
                /* a failover is happening and switches
@@ -1749,7 +1756,7 @@ static void ip_mc_reset(struct in_device *in_dev)
 
        in_dev->mr_qi = IGMP_QUERY_INTERVAL;
        in_dev->mr_qri = IGMP_QUERY_RESPONSE_INTERVAL;
-       in_dev->mr_qrv = net->ipv4.sysctl_igmp_qrv;
+       in_dev->mr_qrv = READ_ONCE(net->ipv4.sysctl_igmp_qrv);
 }
 #else
 static void ip_mc_reset(struct in_device *in_dev)
@@ -1883,7 +1890,7 @@ static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode,
 #ifdef CONFIG_IP_MULTICAST
                if (psf->sf_oldin &&
                    !IGMP_V1_SEEN(in_dev) && !IGMP_V2_SEEN(in_dev)) {
-                       psf->sf_crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
+                       psf->sf_crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
                        psf->sf_next = pmc->tomb;
                        pmc->tomb = psf;
                        rv = 1;
@@ -1947,7 +1954,7 @@ static int ip_mc_del_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
                /* filter mode change */
                pmc->sfmode = MCAST_INCLUDE;
 #ifdef CONFIG_IP_MULTICAST
-               pmc->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
+               pmc->crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
                WRITE_ONCE(in_dev->mr_ifc_count, pmc->crcount);
                for (psf = pmc->sources; psf; psf = psf->sf_next)
                        psf->sf_crcount = 0;
@@ -2126,7 +2133,7 @@ static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
 #ifdef CONFIG_IP_MULTICAST
                /* else no filters; keep old mode for reports */
 
-               pmc->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
+               pmc->crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
                WRITE_ONCE(in_dev->mr_ifc_count, pmc->crcount);
                for (psf = pmc->sources; psf; psf = psf->sf_next)
                        psf->sf_crcount = 0;
@@ -2192,7 +2199,7 @@ static int __ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr,
                count++;
        }
        err = -ENOBUFS;
-       if (count >= net->ipv4.sysctl_igmp_max_memberships)
+       if (count >= READ_ONCE(net->ipv4.sysctl_igmp_max_memberships))
                goto done;
        iml = sock_kmalloc(sk, sizeof(*iml), GFP_KERNEL);
        if (!iml)
@@ -2379,7 +2386,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
        }
        /* else, add a new source to the filter */
 
-       if (psl && psl->sl_count >= net->ipv4.sysctl_igmp_max_msf) {
+       if (psl && psl->sl_count >= READ_ONCE(net->ipv4.sysctl_igmp_max_msf)) {
                err = -ENOBUFS;
                goto done;
        }
index 53f5f95..eb31c71 100644 (file)
@@ -263,7 +263,7 @@ next_port:
                goto other_half_scan;
        }
 
-       if (net->ipv4.sysctl_ip_autobind_reuse && !relax) {
+       if (READ_ONCE(net->ipv4.sysctl_ip_autobind_reuse) && !relax) {
                /* We still have a chance to connect to different destinations */
                relax = true;
                goto ports_exhausted;
@@ -833,7 +833,8 @@ static void reqsk_timer_handler(struct timer_list *t)
 
        icsk = inet_csk(sk_listener);
        net = sock_net(sk_listener);
-       max_syn_ack_retries = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_synack_retries;
+       max_syn_ack_retries = icsk->icsk_syn_retries ? :
+               READ_ONCE(net->ipv4.sysctl_tcp_synack_retries);
        /* Normally all the openreqs are young and become mature
         * (i.e. converted to established socket) for first timeout.
         * If synack was not acknowledged for 1 second, it means
index 0ec5018..47ccc34 100644 (file)
@@ -156,7 +156,8 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk,
 {
        struct inet_timewait_sock *tw;
 
-       if (refcount_read(&dr->tw_refcount) - 1 >= dr->sysctl_max_tw_buckets)
+       if (refcount_read(&dr->tw_refcount) - 1 >=
+           READ_ONCE(dr->sysctl_max_tw_buckets))
                return NULL;
 
        tw = kmem_cache_alloc(sk->sk_prot_creator->twsk_prot->twsk_slab,
index da21dfc..e9fed83 100644 (file)
@@ -141,16 +141,20 @@ static void inet_peer_gc(struct inet_peer_base *base,
                         struct inet_peer *gc_stack[],
                         unsigned int gc_cnt)
 {
+       int peer_threshold, peer_maxttl, peer_minttl;
        struct inet_peer *p;
        __u32 delta, ttl;
        int i;
 
-       if (base->total >= inet_peer_threshold)
+       peer_threshold = READ_ONCE(inet_peer_threshold);
+       peer_maxttl = READ_ONCE(inet_peer_maxttl);
+       peer_minttl = READ_ONCE(inet_peer_minttl);
+
+       if (base->total >= peer_threshold)
                ttl = 0; /* be aggressive */
        else
-               ttl = inet_peer_maxttl
-                               - (inet_peer_maxttl - inet_peer_minttl) / HZ *
-                                       base->total / inet_peer_threshold * HZ;
+               ttl = peer_maxttl - (peer_maxttl - peer_minttl) / HZ *
+                       base->total / peer_threshold * HZ;
        for (i = 0; i < gc_cnt; i++) {
                p = gc_stack[i];
 
index e3aa436..e18931a 100644 (file)
@@ -157,7 +157,7 @@ int ip_forward(struct sk_buff *skb)
            !skb_sec_path(skb))
                ip_rt_send_redirect(skb);
 
-       if (net->ipv4.sysctl_ip_fwd_update_priority)
+       if (READ_ONCE(net->ipv4.sysctl_ip_fwd_update_priority))
                skb->priority = rt_tos2priority(iph->tos);
 
        return NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD,
index b1165f7..1b51239 100644 (file)
@@ -312,14 +312,13 @@ static bool ip_can_use_hint(const struct sk_buff *skb, const struct iphdr *iph,
               ip_hdr(hint)->tos == iph->tos;
 }
 
-INDIRECT_CALLABLE_DECLARE(int udp_v4_early_demux(struct sk_buff *));
-INDIRECT_CALLABLE_DECLARE(int tcp_v4_early_demux(struct sk_buff *));
+int tcp_v4_early_demux(struct sk_buff *skb);
+int udp_v4_early_demux(struct sk_buff *skb);
 static int ip_rcv_finish_core(struct net *net, struct sock *sk,
                              struct sk_buff *skb, struct net_device *dev,
                              const struct sk_buff *hint)
 {
        const struct iphdr *iph = ip_hdr(skb);
-       int (*edemux)(struct sk_buff *skb);
        int err, drop_reason;
        struct rtable *rt;
 
@@ -332,21 +331,29 @@ static int ip_rcv_finish_core(struct net *net, struct sock *sk,
                        goto drop_error;
        }
 
-       if (net->ipv4.sysctl_ip_early_demux &&
+       if (READ_ONCE(net->ipv4.sysctl_ip_early_demux) &&
            !skb_dst(skb) &&
            !skb->sk &&
            !ip_is_fragment(iph)) {
-               const struct net_protocol *ipprot;
-               int protocol = iph->protocol;
-
-               ipprot = rcu_dereference(inet_protos[protocol]);
-               if (ipprot && (edemux = READ_ONCE(ipprot->early_demux))) {
-                       err = INDIRECT_CALL_2(edemux, tcp_v4_early_demux,
-                                             udp_v4_early_demux, skb);
-                       if (unlikely(err))
-                               goto drop_error;
-                       /* must reload iph, skb->head might have changed */
-                       iph = ip_hdr(skb);
+               switch (iph->protocol) {
+               case IPPROTO_TCP:
+                       if (READ_ONCE(net->ipv4.sysctl_tcp_early_demux)) {
+                               tcp_v4_early_demux(skb);
+
+                               /* must reload iph, skb->head might have changed */
+                               iph = ip_hdr(skb);
+                       }
+                       break;
+               case IPPROTO_UDP:
+                       if (READ_ONCE(net->ipv4.sysctl_udp_early_demux)) {
+                               err = udp_v4_early_demux(skb);
+                               if (unlikely(err))
+                                       goto drop_error;
+
+                               /* must reload iph, skb->head might have changed */
+                               iph = ip_hdr(skb);
+                       }
+                       break;
                }
        }
 
index 00b4bf2..df7f9df 100644 (file)
@@ -969,7 +969,6 @@ static int __ip_append_data(struct sock *sk,
        struct inet_sock *inet = inet_sk(sk);
        struct ubuf_info *uarg = NULL;
        struct sk_buff *skb;
-
        struct ip_options *opt = cork->opt;
        int hh_len;
        int exthdrlen;
@@ -977,6 +976,7 @@ static int __ip_append_data(struct sock *sk,
        int copy;
        int err;
        int offset = 0;
+       bool zc = false;
        unsigned int maxfraglen, fragheaderlen, maxnonfragsize;
        int csummode = CHECKSUM_NONE;
        struct rtable *rt = (struct rtable *)cork->dst;
@@ -1017,17 +1017,35 @@ static int __ip_append_data(struct sock *sk,
            (!exthdrlen || (rt->dst.dev->features & NETIF_F_HW_ESP_TX_CSUM)))
                csummode = CHECKSUM_PARTIAL;
 
-       if (flags & MSG_ZEROCOPY && length && sock_flag(sk, SOCK_ZEROCOPY)) {
-               uarg = msg_zerocopy_realloc(sk, length, skb_zcopy(skb));
-               if (!uarg)
-                       return -ENOBUFS;
-               extra_uref = !skb_zcopy(skb);   /* only ref on new uarg */
-               if (rt->dst.dev->features & NETIF_F_SG &&
-                   csummode == CHECKSUM_PARTIAL) {
-                       paged = true;
-               } else {
-                       uarg->zerocopy = 0;
-                       skb_zcopy_set(skb, uarg, &extra_uref);
+       if ((flags & MSG_ZEROCOPY) && length) {
+               struct msghdr *msg = from;
+
+               if (getfrag == ip_generic_getfrag && msg->msg_ubuf) {
+                       if (skb_zcopy(skb) && msg->msg_ubuf != skb_zcopy(skb))
+                               return -EINVAL;
+
+                       /* Leave uarg NULL if can't zerocopy, callers should
+                        * be able to handle it.
+                        */
+                       if ((rt->dst.dev->features & NETIF_F_SG) &&
+                           csummode == CHECKSUM_PARTIAL) {
+                               paged = true;
+                               zc = true;
+                               uarg = msg->msg_ubuf;
+                       }
+               } else if (sock_flag(sk, SOCK_ZEROCOPY)) {
+                       uarg = msg_zerocopy_realloc(sk, length, skb_zcopy(skb));
+                       if (!uarg)
+                               return -ENOBUFS;
+                       extra_uref = !skb_zcopy(skb);   /* only ref on new uarg */
+                       if (rt->dst.dev->features & NETIF_F_SG &&
+                           csummode == CHECKSUM_PARTIAL) {
+                               paged = true;
+                               zc = true;
+                       } else {
+                               uarg->zerocopy = 0;
+                               skb_zcopy_set(skb, uarg, &extra_uref);
+                       }
                }
        }
 
@@ -1091,9 +1109,12 @@ alloc_new_skb:
                                 (fraglen + alloc_extra < SKB_MAX_ALLOC ||
                                  !(rt->dst.dev->features & NETIF_F_SG)))
                                alloclen = fraglen;
-                       else {
+                       else if (!zc) {
                                alloclen = min_t(int, fraglen, MAX_HEADER);
                                pagedlen = fraglen - alloclen;
+                       } else {
+                               alloclen = fragheaderlen + transhdrlen;
+                               pagedlen = datalen - transhdrlen;
                        }
 
                        alloclen += alloc_extra;
@@ -1188,13 +1209,14 @@ alloc_new_skb:
                                err = -EFAULT;
                                goto error;
                        }
-               } else if (!uarg || !uarg->zerocopy) {
+               } else if (!zc) {
                        int i = skb_shinfo(skb)->nr_frags;
 
                        err = -ENOMEM;
                        if (!sk_page_frag_refill(sk, pfrag))
                                goto error;
 
+                       skb_zcopy_downgrade_managed(skb);
                        if (!skb_can_coalesce(skb, i, pfrag->page,
                                              pfrag->offset)) {
                                err = -EMSGSIZE;
index 445a9ec..a8a323e 100644 (file)
@@ -782,7 +782,7 @@ static int ip_set_mcast_msfilter(struct sock *sk, sockptr_t optval, int optlen)
        /* numsrc >= (4G-140)/128 overflow in 32 bits */
        err = -ENOBUFS;
        if (gsf->gf_numsrc >= 0x1ffffff ||
-           gsf->gf_numsrc > sock_net(sk)->ipv4.sysctl_igmp_max_msf)
+           gsf->gf_numsrc > READ_ONCE(sock_net(sk)->ipv4.sysctl_igmp_max_msf))
                goto out_free_gsf;
 
        err = -EINVAL;
@@ -832,7 +832,7 @@ static int compat_ip_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
 
        /* numsrc >= (4G-140)/128 overflow in 32 bits */
        err = -ENOBUFS;
-       if (n > sock_net(sk)->ipv4.sysctl_igmp_max_msf)
+       if (n > READ_ONCE(sock_net(sk)->ipv4.sysctl_igmp_max_msf))
                goto out_free_gsf;
        err = set_mcast_msfilter(sk, gf32->gf_interface, n, gf32->gf_fmode,
                                 &gf32->gf_group, gf32->gf_slist_flex);
@@ -1244,7 +1244,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, int optname,
                }
                /* numsrc >= (1G-4) overflow in 32 bits */
                if (msf->imsf_numsrc >= 0x3ffffffcU ||
-                   msf->imsf_numsrc > net->ipv4.sysctl_igmp_max_msf) {
+                   msf->imsf_numsrc > READ_ONCE(net->ipv4.sysctl_igmp_max_msf)) {
                        kfree(msf);
                        err = -ENOBUFS;
                        break;
@@ -1606,7 +1606,7 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
        {
                struct net *net = sock_net(sk);
                val = (inet->uc_ttl == -1 ?
-                      net->ipv4.sysctl_ip_default_ttl :
+                      READ_ONCE(net->ipv4.sysctl_ip_default_ttl) :
                       inet->uc_ttl);
                break;
        }
index 6b2dc7b..cc1caab 100644 (file)
@@ -410,7 +410,7 @@ int skb_tunnel_check_pmtu(struct sk_buff *skb, struct dst_entry *encap_dst,
        u32 mtu = dst_mtu(encap_dst) - headroom;
 
        if ((skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu)) ||
-           (!skb_is_gso(skb) && (skb->len - skb_mac_header_len(skb)) <= mtu))
+           (!skb_is_gso(skb) && (skb->len - skb_network_offset(skb)) <= mtu))
                return 0;
 
        skb_dst_update_pmtu_no_confirm(skb, mtu);
index 918c61f..d640adc 100644 (file)
@@ -62,7 +62,7 @@ struct sk_buff *nf_reject_skb_v4_tcp_reset(struct net *net,
 
        skb_reserve(nskb, LL_MAX_HEADER);
        niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_TCP,
-                                  net->ipv4.sysctl_ip_default_ttl);
+                                  READ_ONCE(net->ipv4.sysctl_ip_default_ttl));
        nf_reject_ip_tcphdr_put(nskb, oldskb, oth);
        niph->tot_len = htons(nskb->len);
        ip_send_check(niph);
@@ -117,7 +117,7 @@ struct sk_buff *nf_reject_skb_v4_unreach(struct net *net,
 
        skb_reserve(nskb, LL_MAX_HEADER);
        niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_ICMP,
-                                  net->ipv4.sysctl_ip_default_ttl);
+                                  READ_ONCE(net->ipv4.sysctl_ip_default_ttl));
 
        skb_reset_transport_header(nskb);
        icmph = skb_put_zero(nskb, sizeof(struct icmphdr));
index e459a39..853a75a 100644 (file)
@@ -1858,7 +1858,7 @@ static void __remove_nexthop_fib(struct net *net, struct nexthop *nh)
                /* __ip6_del_rt does a release, so do a hold here */
                fib6_info_hold(f6i);
                ipv6_stub->ip6_del_rt(net, f6i,
-                                     !net->ipv4.sysctl_nexthop_compat_mode);
+                                     !READ_ONCE(net->ipv4.sysctl_nexthop_compat_mode));
        }
 }
 
@@ -2361,7 +2361,8 @@ out:
        if (!rc) {
                nh_base_seq_inc(net);
                nexthop_notify(RTM_NEWNEXTHOP, new_nh, &cfg->nlinfo);
-               if (replace_notify && net->ipv4.sysctl_nexthop_compat_mode)
+               if (replace_notify &&
+                   READ_ONCE(net->ipv4.sysctl_nexthop_compat_mode))
                        nexthop_replace_notify(net, new_nh, &cfg->nlinfo);
        }
 
index 2883607..0088a4c 100644 (file)
@@ -387,7 +387,7 @@ static int snmp_seq_show_ipstats(struct seq_file *seq, void *v)
 
        seq_printf(seq, "\nIp: %d %d",
                   IPV4_DEVCONF_ALL(net, FORWARDING) ? 1 : 2,
-                  net->ipv4.sysctl_ip_default_ttl);
+                  READ_ONCE(net->ipv4.sysctl_ip_default_ttl));
 
        BUILD_BUG_ON(offsetof(struct ipstats_mib, mibs) != 0);
        snmp_get_cpu_field64_batch(buff64, snmp4_ipstats_list,
index 356f535..4702c61 100644 (file)
@@ -1398,7 +1398,7 @@ u32 ip_mtu_from_fib_result(struct fib_result *res, __be32 daddr)
        struct fib_info *fi = res->fi;
        u32 mtu = 0;
 
-       if (dev_net(dev)->ipv4.sysctl_ip_fwd_use_pmtu ||
+       if (READ_ONCE(dev_net(dev)->ipv4.sysctl_ip_fwd_use_pmtu) ||
            fi->fib_metrics->metrics[RTAX_LOCK - 1] & (1 << RTAX_MTU))
                mtu = fi->fib_mtu;
 
@@ -1929,7 +1929,7 @@ static u32 fib_multipath_custom_hash_outer(const struct net *net,
                                           const struct sk_buff *skb,
                                           bool *p_has_inner)
 {
-       u32 hash_fields = net->ipv4.sysctl_fib_multipath_hash_fields;
+       u32 hash_fields = READ_ONCE(net->ipv4.sysctl_fib_multipath_hash_fields);
        struct flow_keys keys, hash_keys;
 
        if (!(hash_fields & FIB_MULTIPATH_HASH_FIELD_OUTER_MASK))
@@ -1958,7 +1958,7 @@ static u32 fib_multipath_custom_hash_inner(const struct net *net,
                                           const struct sk_buff *skb,
                                           bool has_inner)
 {
-       u32 hash_fields = net->ipv4.sysctl_fib_multipath_hash_fields;
+       u32 hash_fields = READ_ONCE(net->ipv4.sysctl_fib_multipath_hash_fields);
        struct flow_keys keys, hash_keys;
 
        /* We assume the packet carries an encapsulation, but if none was
@@ -2018,7 +2018,7 @@ static u32 fib_multipath_custom_hash_skb(const struct net *net,
 static u32 fib_multipath_custom_hash_fl4(const struct net *net,
                                         const struct flowi4 *fl4)
 {
-       u32 hash_fields = net->ipv4.sysctl_fib_multipath_hash_fields;
+       u32 hash_fields = READ_ONCE(net->ipv4.sysctl_fib_multipath_hash_fields);
        struct flow_keys hash_keys;
 
        if (!(hash_fields & FIB_MULTIPATH_HASH_FIELD_OUTER_MASK))
@@ -2048,7 +2048,7 @@ int fib_multipath_hash(const struct net *net, const struct flowi4 *fl4,
        struct flow_keys hash_keys;
        u32 mhash = 0;
 
-       switch (net->ipv4.sysctl_fib_multipath_hash_policy) {
+       switch (READ_ONCE(net->ipv4.sysctl_fib_multipath_hash_policy)) {
        case 0:
                memset(&hash_keys, 0, sizeof(hash_keys));
                hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
index f33c31d..942d2df 100644 (file)
@@ -247,12 +247,12 @@ bool cookie_timestamp_decode(const struct net *net,
                return true;
        }
 
-       if (!net->ipv4.sysctl_tcp_timestamps)
+       if (!READ_ONCE(net->ipv4.sysctl_tcp_timestamps))
                return false;
 
        tcp_opt->sack_ok = (options & TS_OPT_SACK) ? TCP_SACK_SEEN : 0;
 
-       if (tcp_opt->sack_ok && !net->ipv4.sysctl_tcp_sack)
+       if (tcp_opt->sack_ok && !READ_ONCE(net->ipv4.sysctl_tcp_sack))
                return false;
 
        if ((options & TS_OPT_WSCALE_MASK) == TS_OPT_WSCALE_MASK)
@@ -261,7 +261,7 @@ bool cookie_timestamp_decode(const struct net *net,
        tcp_opt->wscale_ok = 1;
        tcp_opt->snd_wscale = options & TS_OPT_WSCALE_MASK;
 
-       return net->ipv4.sysctl_tcp_window_scaling != 0;
+       return READ_ONCE(net->ipv4.sysctl_tcp_window_scaling) != 0;
 }
 EXPORT_SYMBOL(cookie_timestamp_decode);
 
@@ -273,7 +273,7 @@ bool cookie_ecn_ok(const struct tcp_options_received *tcp_opt,
        if (!ecn_ok)
                return false;
 
-       if (net->ipv4.sysctl_tcp_ecn)
+       if (READ_ONCE(net->ipv4.sysctl_tcp_ecn))
                return true;
 
        return dst_feature(dst, RTAX_FEATURE_ECN);
@@ -340,7 +340,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
        struct flowi4 fl4;
        u32 tsoff = 0;
 
-       if (!sock_net(sk)->ipv4.sysctl_tcp_syncookies || !th->ack || th->rst)
+       if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_syncookies) ||
+           !th->ack || th->rst)
                goto out;
 
        if (tcp_synq_no_recent_overflow(sk))
index cd448cd..5490c28 100644 (file)
@@ -84,7 +84,7 @@ static int ipv4_local_port_range(struct ctl_table *table, int write,
                 * port limit.
                 */
                if ((range[1] < range[0]) ||
-                   (range[0] < net->ipv4.sysctl_ip_prot_sock))
+                   (range[0] < READ_ONCE(net->ipv4.sysctl_ip_prot_sock)))
                        ret = -EINVAL;
                else
                        set_local_port_range(net, range);
@@ -110,7 +110,7 @@ static int ipv4_privileged_ports(struct ctl_table *table, int write,
                .extra2 = &ip_privileged_port_max,
        };
 
-       pports = net->ipv4.sysctl_ip_prot_sock;
+       pports = READ_ONCE(net->ipv4.sysctl_ip_prot_sock);
 
        ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
 
@@ -122,7 +122,7 @@ static int ipv4_privileged_ports(struct ctl_table *table, int write,
                if (range[0] < pports)
                        ret = -EINVAL;
                else
-                       net->ipv4.sysctl_ip_prot_sock = pports;
+                       WRITE_ONCE(net->ipv4.sysctl_ip_prot_sock, pports);
        }
 
        return ret;
@@ -350,61 +350,6 @@ bad_key:
        return ret;
 }
 
-static void proc_configure_early_demux(int enabled, int protocol)
-{
-       struct net_protocol *ipprot;
-#if IS_ENABLED(CONFIG_IPV6)
-       struct inet6_protocol *ip6prot;
-#endif
-
-       rcu_read_lock();
-
-       ipprot = rcu_dereference(inet_protos[protocol]);
-       if (ipprot)
-               ipprot->early_demux = enabled ? ipprot->early_demux_handler :
-                                               NULL;
-
-#if IS_ENABLED(CONFIG_IPV6)
-       ip6prot = rcu_dereference(inet6_protos[protocol]);
-       if (ip6prot)
-               ip6prot->early_demux = enabled ? ip6prot->early_demux_handler :
-                                                NULL;
-#endif
-       rcu_read_unlock();
-}
-
-static int proc_tcp_early_demux(struct ctl_table *table, int write,
-                               void *buffer, size_t *lenp, loff_t *ppos)
-{
-       int ret = 0;
-
-       ret = proc_dou8vec_minmax(table, write, buffer, lenp, ppos);
-
-       if (write && !ret) {
-               int enabled = init_net.ipv4.sysctl_tcp_early_demux;
-
-               proc_configure_early_demux(enabled, IPPROTO_TCP);
-       }
-
-       return ret;
-}
-
-static int proc_udp_early_demux(struct ctl_table *table, int write,
-                               void *buffer, size_t *lenp, loff_t *ppos)
-{
-       int ret = 0;
-
-       ret = proc_dou8vec_minmax(table, write, buffer, lenp, ppos);
-
-       if (write && !ret) {
-               int enabled = init_net.ipv4.sysctl_udp_early_demux;
-
-               proc_configure_early_demux(enabled, IPPROTO_UDP);
-       }
-
-       return ret;
-}
-
 static int proc_tfo_blackhole_detect_timeout(struct ctl_table *table,
                                             int write, void *buffer,
                                             size_t *lenp, loff_t *ppos)
@@ -599,6 +544,8 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(u8),
                .mode           = 0644,
                .proc_handler   = proc_dou8vec_minmax,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE
        },
        {
                .procname       = "icmp_echo_enable_probe",
@@ -615,6 +562,8 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(u8),
                .mode           = 0644,
                .proc_handler   = proc_dou8vec_minmax,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE
        },
        {
                .procname       = "icmp_ignore_bogus_error_responses",
@@ -622,6 +571,8 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(u8),
                .mode           = 0644,
                .proc_handler   = proc_dou8vec_minmax,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE
        },
        {
                .procname       = "icmp_errors_use_inbound_ifaddr",
@@ -629,6 +580,8 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(u8),
                .mode           = 0644,
                .proc_handler   = proc_dou8vec_minmax,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE
        },
        {
                .procname       = "icmp_ratelimit",
@@ -668,6 +621,8 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(u8),
                .mode           = 0644,
                .proc_handler   = proc_dou8vec_minmax,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_TWO,
        },
        {
                .procname       = "tcp_ecn_fallback",
@@ -675,6 +630,8 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(u8),
                .mode           = 0644,
                .proc_handler   = proc_dou8vec_minmax,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
        {
                .procname       = "ip_dynaddr",
@@ -695,14 +652,14 @@ static struct ctl_table ipv4_net_table[] = {
                .data           = &init_net.ipv4.sysctl_udp_early_demux,
                .maxlen         = sizeof(u8),
                .mode           = 0644,
-               .proc_handler   = proc_udp_early_demux
+               .proc_handler   = proc_dou8vec_minmax,
        },
        {
                .procname       = "tcp_early_demux",
                .data           = &init_net.ipv4.sysctl_tcp_early_demux,
                .maxlen         = sizeof(u8),
                .mode           = 0644,
-               .proc_handler   = proc_tcp_early_demux
+               .proc_handler   = proc_dou8vec_minmax,
        },
        {
                .procname       = "nexthop_compat_mode",
index 028513d..a628daa 100644 (file)
@@ -441,7 +441,7 @@ void tcp_init_sock(struct sock *sk)
        tp->snd_cwnd_clamp = ~0;
        tp->mss_cache = TCP_MSS_DEFAULT;
 
-       tp->reordering = sock_net(sk)->ipv4.sysctl_tcp_reordering;
+       tp->reordering = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_reordering);
        tcp_assign_congestion_control(sk);
 
        tp->tsoffset = 0;
@@ -452,8 +452,8 @@ void tcp_init_sock(struct sock *sk)
 
        icsk->icsk_sync_mss = tcp_sync_mss;
 
-       WRITE_ONCE(sk->sk_sndbuf, sock_net(sk)->ipv4.sysctl_tcp_wmem[1]);
-       WRITE_ONCE(sk->sk_rcvbuf, sock_net(sk)->ipv4.sysctl_tcp_rmem[1]);
+       WRITE_ONCE(sk->sk_sndbuf, READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_wmem[1]));
+       WRITE_ONCE(sk->sk_rcvbuf, READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_rmem[1]));
 
        sk_sockets_allocated_inc(sk);
 }
@@ -686,7 +686,7 @@ static bool tcp_should_autocork(struct sock *sk, struct sk_buff *skb,
                                int size_goal)
 {
        return skb->len < size_goal &&
-              sock_net(sk)->ipv4.sysctl_tcp_autocorking &&
+              READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_autocorking) &&
               !tcp_rtx_queue_empty(sk) &&
               refcount_read(&sk->sk_wmem_alloc) > skb->truesize &&
               tcp_skb_can_collapse_to(skb);
@@ -1150,7 +1150,8 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg,
        struct sockaddr *uaddr = msg->msg_name;
        int err, flags;
 
-       if (!(sock_net(sk)->ipv4.sysctl_tcp_fastopen & TFO_CLIENT_ENABLE) ||
+       if (!(READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_fastopen) &
+             TFO_CLIENT_ENABLE) ||
            (uaddr && msg->msg_namelen >= sizeof(uaddr->sa_family) &&
             uaddr->sa_family == AF_UNSPEC))
                return -EOPNOTSUPP;
@@ -1202,17 +1203,23 @@ int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size)
 
        flags = msg->msg_flags;
 
-       if (flags & MSG_ZEROCOPY && size && sock_flag(sk, SOCK_ZEROCOPY)) {
+       if ((flags & MSG_ZEROCOPY) && size) {
                skb = tcp_write_queue_tail(sk);
-               uarg = msg_zerocopy_realloc(sk, size, skb_zcopy(skb));
-               if (!uarg) {
-                       err = -ENOBUFS;
-                       goto out_err;
-               }
 
-               zc = sk->sk_route_caps & NETIF_F_SG;
-               if (!zc)
-                       uarg->zerocopy = 0;
+               if (msg->msg_ubuf) {
+                       uarg = msg->msg_ubuf;
+                       net_zcopy_get(uarg);
+                       zc = sk->sk_route_caps & NETIF_F_SG;
+               } else if (sock_flag(sk, SOCK_ZEROCOPY)) {
+                       uarg = msg_zerocopy_realloc(sk, size, skb_zcopy(skb));
+                       if (!uarg) {
+                               err = -ENOBUFS;
+                               goto out_err;
+                       }
+                       zc = sk->sk_route_caps & NETIF_F_SG;
+                       if (!zc)
+                               uarg->zerocopy = 0;
+               }
        }
 
        if (unlikely(flags & MSG_FASTOPEN || inet_sk(sk)->defer_connect) &&
@@ -1335,8 +1342,13 @@ new_segment:
 
                        copy = min_t(int, copy, pfrag->size - pfrag->offset);
 
-                       if (tcp_downgrade_zcopy_pure(sk, skb) ||
-                           !sk_wmem_schedule(sk, copy))
+                       if (unlikely(skb_zcopy_pure(skb) || skb_zcopy_managed(skb))) {
+                               if (tcp_downgrade_zcopy_pure(sk, skb))
+                                       goto wait_for_space;
+                               skb_zcopy_downgrade_managed(skb);
+                       }
+
+                       if (!sk_wmem_schedule(sk, copy))
                                goto wait_for_space;
 
                        err = skb_copy_to_page_nocache(sk, &msg->msg_iter, skb,
@@ -1723,7 +1735,7 @@ int tcp_set_rcvlowat(struct sock *sk, int val)
        if (sk->sk_userlocks & SOCK_RCVBUF_LOCK)
                cap = sk->sk_rcvbuf >> 1;
        else
-               cap = sock_net(sk)->ipv4.sysctl_tcp_rmem[2] >> 1;
+               cap = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_rmem[2]) >> 1;
        val = min(val, cap);
        WRITE_ONCE(sk->sk_rcvlowat, val ? : 1);
 
@@ -2715,7 +2727,8 @@ static void tcp_orphan_update(struct timer_list *unused)
 
 static bool tcp_too_many_orphans(int shift)
 {
-       return READ_ONCE(tcp_orphan_cache) << shift > sysctl_tcp_max_orphans;
+       return READ_ONCE(tcp_orphan_cache) << shift >
+               READ_ONCE(sysctl_tcp_max_orphans);
 }
 
 bool tcp_check_oom(struct sock *sk, int shift)
@@ -3616,7 +3629,8 @@ static int do_tcp_setsockopt(struct sock *sk, int level, int optname,
        case TCP_FASTOPEN_CONNECT:
                if (val > 1 || val < 0) {
                        err = -EINVAL;
-               } else if (net->ipv4.sysctl_tcp_fastopen & TFO_CLIENT_ENABLE) {
+               } else if (READ_ONCE(net->ipv4.sysctl_tcp_fastopen) &
+                          TFO_CLIENT_ENABLE) {
                        if (sk->sk_state == TCP_CLOSE)
                                tp->fastopen_connect = val;
                        else
@@ -3966,12 +3980,13 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
                val = keepalive_probes(tp);
                break;
        case TCP_SYNCNT:
-               val = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_syn_retries;
+               val = icsk->icsk_syn_retries ? :
+                       READ_ONCE(net->ipv4.sysctl_tcp_syn_retries);
                break;
        case TCP_LINGER2:
                val = tp->linger2;
                if (val >= 0)
-                       val = (val ? : net->ipv4.sysctl_tcp_fin_timeout) / HZ;
+                       val = (val ? : READ_ONCE(net->ipv4.sysctl_tcp_fin_timeout)) / HZ;
                break;
        case TCP_DEFER_ACCEPT:
                val = retrans_to_secs(icsk->icsk_accept_queue.rskq_defer_accept,
@@ -4455,9 +4470,18 @@ tcp_inbound_md5_hash(const struct sock *sk, const struct sk_buff *skb,
                return SKB_DROP_REASON_TCP_MD5UNEXPECTED;
        }
 
-       /* check the signature */
-       genhash = tp->af_specific->calc_md5_hash(newhash, hash_expected,
-                                                NULL, skb);
+       /* Check the signature.
+        * To support dual stack listeners, we need to handle
+        * IPv4-mapped case.
+        */
+       if (family == AF_INET)
+               genhash = tcp_v4_md5_hash_skb(newhash,
+                                             hash_expected,
+                                             NULL, skb);
+       else
+               genhash = tp->af_specific->calc_md5_hash(newhash,
+                                                        hash_expected,
+                                                        NULL, skb);
 
        if (genhash || memcmp(hash_location, newhash, 16) != 0) {
                NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMD5FAILURE);
index fdbcf2a..825b216 100644 (file)
@@ -332,7 +332,7 @@ static bool tcp_fastopen_no_cookie(const struct sock *sk,
                                   const struct dst_entry *dst,
                                   int flag)
 {
-       return (sock_net(sk)->ipv4.sysctl_tcp_fastopen & flag) ||
+       return (READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_fastopen) & flag) ||
               tcp_sk(sk)->fastopen_no_cookie ||
               (dst && dst_metric(dst, RTAX_FASTOPEN_NO_COOKIE));
 }
@@ -347,7 +347,7 @@ struct sock *tcp_try_fastopen(struct sock *sk, struct sk_buff *skb,
                              const struct dst_entry *dst)
 {
        bool syn_data = TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq + 1;
-       int tcp_fastopen = sock_net(sk)->ipv4.sysctl_tcp_fastopen;
+       int tcp_fastopen = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_fastopen);
        struct tcp_fastopen_cookie valid_foc = { .len = -1 };
        struct sock *child;
        int ret = 0;
@@ -489,7 +489,7 @@ void tcp_fastopen_active_disable(struct sock *sk)
 {
        struct net *net = sock_net(sk);
 
-       if (!sock_net(sk)->ipv4.sysctl_tcp_fastopen_blackhole_timeout)
+       if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_fastopen_blackhole_timeout))
                return;
 
        /* Paired with READ_ONCE() in tcp_fastopen_active_should_disable() */
@@ -510,7 +510,8 @@ void tcp_fastopen_active_disable(struct sock *sk)
  */
 bool tcp_fastopen_active_should_disable(struct sock *sk)
 {
-       unsigned int tfo_bh_timeout = sock_net(sk)->ipv4.sysctl_tcp_fastopen_blackhole_timeout;
+       unsigned int tfo_bh_timeout =
+               READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_fastopen_blackhole_timeout);
        unsigned long timeout;
        int tfo_da_times;
        int multiplier;
index 2e2a9ec..b163799 100644 (file)
@@ -426,7 +426,7 @@ static void tcp_sndbuf_expand(struct sock *sk)
 
        if (sk->sk_sndbuf < sndmem)
                WRITE_ONCE(sk->sk_sndbuf,
-                          min(sndmem, sock_net(sk)->ipv4.sysctl_tcp_wmem[2]));
+                          min(sndmem, READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_wmem[2])));
 }
 
 /* 2. Tuning advertised window (window_clamp, rcv_ssthresh)
@@ -461,7 +461,7 @@ static int __tcp_grow_window(const struct sock *sk, const struct sk_buff *skb,
        struct tcp_sock *tp = tcp_sk(sk);
        /* Optimize this! */
        int truesize = tcp_win_from_space(sk, skbtruesize) >> 1;
-       int window = tcp_win_from_space(sk, sock_net(sk)->ipv4.sysctl_tcp_rmem[2]) >> 1;
+       int window = tcp_win_from_space(sk, READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_rmem[2])) >> 1;
 
        while (tp->rcv_ssthresh <= window) {
                if (truesize <= skb->len)
@@ -534,7 +534,7 @@ static void tcp_grow_window(struct sock *sk, const struct sk_buff *skb,
  */
 static void tcp_init_buffer_space(struct sock *sk)
 {
-       int tcp_app_win = sock_net(sk)->ipv4.sysctl_tcp_app_win;
+       int tcp_app_win = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_app_win);
        struct tcp_sock *tp = tcp_sk(sk);
        int maxwin;
 
@@ -574,16 +574,17 @@ static void tcp_clamp_window(struct sock *sk)
        struct tcp_sock *tp = tcp_sk(sk);
        struct inet_connection_sock *icsk = inet_csk(sk);
        struct net *net = sock_net(sk);
+       int rmem2;
 
        icsk->icsk_ack.quick = 0;
+       rmem2 = READ_ONCE(net->ipv4.sysctl_tcp_rmem[2]);
 
-       if (sk->sk_rcvbuf < net->ipv4.sysctl_tcp_rmem[2] &&
+       if (sk->sk_rcvbuf < rmem2 &&
            !(sk->sk_userlocks & SOCK_RCVBUF_LOCK) &&
            !tcp_under_memory_pressure(sk) &&
            sk_memory_allocated(sk) < sk_prot_mem_limits(sk, 0)) {
                WRITE_ONCE(sk->sk_rcvbuf,
-                          min(atomic_read(&sk->sk_rmem_alloc),
-                              net->ipv4.sysctl_tcp_rmem[2]));
+                          min(atomic_read(&sk->sk_rmem_alloc), rmem2));
        }
        if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf)
                tp->rcv_ssthresh = min(tp->window_clamp, 2U * tp->advmss);
@@ -724,7 +725,7 @@ void tcp_rcv_space_adjust(struct sock *sk)
         * <prev RTT . ><current RTT .. ><next RTT .... >
         */
 
-       if (sock_net(sk)->ipv4.sysctl_tcp_moderate_rcvbuf &&
+       if (READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_moderate_rcvbuf) &&
            !(sk->sk_userlocks & SOCK_RCVBUF_LOCK)) {
                int rcvmem, rcvbuf;
                u64 rcvwin, grow;
@@ -745,7 +746,7 @@ void tcp_rcv_space_adjust(struct sock *sk)
 
                do_div(rcvwin, tp->advmss);
                rcvbuf = min_t(u64, rcvwin * rcvmem,
-                              sock_net(sk)->ipv4.sysctl_tcp_rmem[2]);
+                              READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_rmem[2]));
                if (rcvbuf > sk->sk_rcvbuf) {
                        WRITE_ONCE(sk->sk_rcvbuf, rcvbuf);
 
@@ -910,9 +911,9 @@ static void tcp_update_pacing_rate(struct sock *sk)
         *       end of slow start and should slow down.
         */
        if (tcp_snd_cwnd(tp) < tp->snd_ssthresh / 2)
-               rate *= sock_net(sk)->ipv4.sysctl_tcp_pacing_ss_ratio;
+               rate *= READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_pacing_ss_ratio);
        else
-               rate *= sock_net(sk)->ipv4.sysctl_tcp_pacing_ca_ratio;
+               rate *= READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_pacing_ca_ratio);
 
        rate *= max(tcp_snd_cwnd(tp), tp->packets_out);
 
@@ -1051,7 +1052,7 @@ static void tcp_check_sack_reordering(struct sock *sk, const u32 low_seq,
                         tp->undo_marker ? tp->undo_retrans : 0);
 #endif
                tp->reordering = min_t(u32, (metric + mss - 1) / mss,
-                                      sock_net(sk)->ipv4.sysctl_tcp_max_reordering);
+                                      READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_max_reordering));
        }
 
        /* This exciting event is worth to be remembered. 8) */
@@ -2030,7 +2031,7 @@ static void tcp_check_reno_reordering(struct sock *sk, const int addend)
                return;
 
        tp->reordering = min_t(u32, tp->packets_out + addend,
-                              sock_net(sk)->ipv4.sysctl_tcp_max_reordering);
+                              READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_max_reordering));
        tp->reord_seen++;
        NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPRENOREORDER);
 }
@@ -2095,7 +2096,8 @@ static inline void tcp_init_undo(struct tcp_sock *tp)
 
 static bool tcp_is_rack(const struct sock *sk)
 {
-       return sock_net(sk)->ipv4.sysctl_tcp_recovery & TCP_RACK_LOSS_DETECTION;
+       return READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_recovery) &
+               TCP_RACK_LOSS_DETECTION;
 }
 
 /* If we detect SACK reneging, forget all SACK information
@@ -2139,6 +2141,7 @@ void tcp_enter_loss(struct sock *sk)
        struct tcp_sock *tp = tcp_sk(sk);
        struct net *net = sock_net(sk);
        bool new_recovery = icsk->icsk_ca_state < TCP_CA_Recovery;
+       u8 reordering;
 
        tcp_timeout_mark_lost(sk);
 
@@ -2159,10 +2162,12 @@ void tcp_enter_loss(struct sock *sk)
        /* Timeout in disordered state after receiving substantial DUPACKs
         * suggests that the degree of reordering is over-estimated.
         */
+       reordering = READ_ONCE(net->ipv4.sysctl_tcp_reordering);
        if (icsk->icsk_ca_state <= TCP_CA_Disorder &&
-           tp->sacked_out >= net->ipv4.sysctl_tcp_reordering)
+           tp->sacked_out >= reordering)
                tp->reordering = min_t(unsigned int, tp->reordering,
-                                      net->ipv4.sysctl_tcp_reordering);
+                                      reordering);
+
        tcp_set_ca_state(sk, TCP_CA_Loss);
        tp->high_seq = tp->snd_nxt;
        tcp_ecn_queue_cwr(tp);
@@ -2171,7 +2176,7 @@ void tcp_enter_loss(struct sock *sk)
         * loss recovery is underway except recurring timeout(s) on
         * the same SND.UNA (sec 3.2). Disable F-RTO on path MTU probing
         */
-       tp->frto = net->ipv4.sysctl_tcp_frto &&
+       tp->frto = READ_ONCE(net->ipv4.sysctl_tcp_frto) &&
                   (new_recovery || icsk->icsk_retransmits) &&
                   !inet_csk(sk)->icsk_mtup.probe_size;
 }
@@ -3054,7 +3059,7 @@ static void tcp_fastretrans_alert(struct sock *sk, const u32 prior_snd_una,
 
 static void tcp_update_rtt_min(struct sock *sk, u32 rtt_us, const int flag)
 {
-       u32 wlen = sock_net(sk)->ipv4.sysctl_tcp_min_rtt_wlen * HZ;
+       u32 wlen = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_min_rtt_wlen) * HZ;
        struct tcp_sock *tp = tcp_sk(sk);
 
        if ((flag & FLAG_ACK_MAYBE_DELAYED) && rtt_us > tcp_min_rtt(tp)) {
@@ -3464,7 +3469,8 @@ static inline bool tcp_may_raise_cwnd(const struct sock *sk, const int flag)
         * new SACK or ECE mark may first advance cwnd here and later reduce
         * cwnd in tcp_fastretrans_alert() based on more states.
         */
-       if (tcp_sk(sk)->reordering > sock_net(sk)->ipv4.sysctl_tcp_reordering)
+       if (tcp_sk(sk)->reordering >
+           READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_reordering))
                return flag & FLAG_FORWARD_PROGRESS;
 
        return flag & FLAG_DATA_ACKED;
@@ -3576,7 +3582,8 @@ static bool __tcp_oow_rate_limited(struct net *net, int mib_idx,
        if (*last_oow_ack_time) {
                s32 elapsed = (s32)(tcp_jiffies32 - *last_oow_ack_time);
 
-               if (0 <= elapsed && elapsed < net->ipv4.sysctl_tcp_invalid_ratelimit) {
+               if (0 <= elapsed &&
+                   elapsed < READ_ONCE(net->ipv4.sysctl_tcp_invalid_ratelimit)) {
                        NET_INC_STATS(net, mib_idx);
                        return true;    /* rate-limited: don't send yet! */
                }
@@ -3624,7 +3631,7 @@ static void tcp_send_challenge_ack(struct sock *sk)
        /* Then check host-wide RFC 5961 rate limit. */
        now = jiffies / HZ;
        if (now != challenge_timestamp) {
-               u32 ack_limit = net->ipv4.sysctl_tcp_challenge_ack_limit;
+               u32 ack_limit = READ_ONCE(net->ipv4.sysctl_tcp_challenge_ack_limit);
                u32 half = (ack_limit + 1) >> 1;
 
                challenge_timestamp = now;
@@ -4056,7 +4063,7 @@ void tcp_parse_options(const struct net *net,
                                break;
                        case TCPOPT_WINDOW:
                                if (opsize == TCPOLEN_WINDOW && th->syn &&
-                                   !estab && net->ipv4.sysctl_tcp_window_scaling) {
+                                   !estab && READ_ONCE(net->ipv4.sysctl_tcp_window_scaling)) {
                                        __u8 snd_wscale = *(__u8 *)ptr;
                                        opt_rx->wscale_ok = 1;
                                        if (snd_wscale > TCP_MAX_WSCALE) {
@@ -4072,7 +4079,7 @@ void tcp_parse_options(const struct net *net,
                        case TCPOPT_TIMESTAMP:
                                if ((opsize == TCPOLEN_TIMESTAMP) &&
                                    ((estab && opt_rx->tstamp_ok) ||
-                                    (!estab && net->ipv4.sysctl_tcp_timestamps))) {
+                                    (!estab && READ_ONCE(net->ipv4.sysctl_tcp_timestamps)))) {
                                        opt_rx->saw_tstamp = 1;
                                        opt_rx->rcv_tsval = get_unaligned_be32(ptr);
                                        opt_rx->rcv_tsecr = get_unaligned_be32(ptr + 4);
@@ -4080,7 +4087,7 @@ void tcp_parse_options(const struct net *net,
                                break;
                        case TCPOPT_SACK_PERM:
                                if (opsize == TCPOLEN_SACK_PERM && th->syn &&
-                                   !estab && net->ipv4.sysctl_tcp_sack) {
+                                   !estab && READ_ONCE(net->ipv4.sysctl_tcp_sack)) {
                                        opt_rx->sack_ok = TCP_SACK_SEEN;
                                        tcp_sack_reset(opt_rx);
                                }
@@ -4421,7 +4428,7 @@ static void tcp_dsack_set(struct sock *sk, u32 seq, u32 end_seq)
 {
        struct tcp_sock *tp = tcp_sk(sk);
 
-       if (tcp_is_sack(tp) && sock_net(sk)->ipv4.sysctl_tcp_dsack) {
+       if (tcp_is_sack(tp) && READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_dsack)) {
                int mib_idx;
 
                if (before(seq, tp->rcv_nxt))
@@ -4468,7 +4475,7 @@ static void tcp_send_dupack(struct sock *sk, const struct sk_buff *skb)
                NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOST);
                tcp_enter_quickack_mode(sk, TCP_MAX_QUICKACKS);
 
-               if (tcp_is_sack(tp) && sock_net(sk)->ipv4.sysctl_tcp_dsack) {
+               if (tcp_is_sack(tp) && READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_dsack)) {
                        u32 end_seq = TCP_SKB_CB(skb)->end_seq;
 
                        tcp_rcv_spurious_retrans(sk, skb);
@@ -5514,7 +5521,7 @@ send_now:
        }
 
        if (!tcp_is_sack(tp) ||
-           tp->compressed_ack >= sock_net(sk)->ipv4.sysctl_tcp_comp_sack_nr)
+           tp->compressed_ack >= READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_comp_sack_nr))
                goto send_now;
 
        if (tp->compressed_ack_rcv_nxt != tp->rcv_nxt) {
@@ -5535,11 +5542,12 @@ send_now:
        if (tp->srtt_us && tp->srtt_us < rtt)
                rtt = tp->srtt_us;
 
-       delay = min_t(unsigned long, sock_net(sk)->ipv4.sysctl_tcp_comp_sack_delay_ns,
+       delay = min_t(unsigned long,
+                     READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_comp_sack_delay_ns),
                      rtt * (NSEC_PER_USEC >> 3)/20);
        sock_hold(sk);
        hrtimer_start_range_ns(&tp->compressed_ack_timer, ns_to_ktime(delay),
-                              sock_net(sk)->ipv4.sysctl_tcp_comp_sack_slack_ns,
+                              READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_comp_sack_slack_ns),
                               HRTIMER_MODE_REL_PINNED_SOFT);
 }
 
@@ -5567,7 +5575,7 @@ static void tcp_check_urg(struct sock *sk, const struct tcphdr *th)
        struct tcp_sock *tp = tcp_sk(sk);
        u32 ptr = ntohs(th->urg_ptr);
 
-       if (ptr && !sock_net(sk)->ipv4.sysctl_tcp_stdurg)
+       if (ptr && !READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_stdurg))
                ptr--;
        ptr += ntohl(th->seq);
 
@@ -6729,7 +6737,7 @@ static void tcp_ecn_create_request(struct request_sock *req,
 
        ect = !INET_ECN_is_not_ect(TCP_SKB_CB(skb)->ip_dsfield);
        ecn_ok_dst = dst_feature(dst, DST_FEATURE_ECN_MASK);
-       ecn_ok = net->ipv4.sysctl_tcp_ecn || ecn_ok_dst;
+       ecn_ok = READ_ONCE(net->ipv4.sysctl_tcp_ecn) || ecn_ok_dst;
 
        if (((!ect || th->res1) && ecn_ok) || tcp_ca_needs_ecn(listen_sk) ||
            (ecn_ok_dst & DST_FEATURE_ECN_CA) ||
@@ -6797,11 +6805,14 @@ static bool tcp_syn_flood_action(const struct sock *sk, const char *proto)
 {
        struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue;
        const char *msg = "Dropping request";
-       bool want_cookie = false;
        struct net *net = sock_net(sk);
+       bool want_cookie = false;
+       u8 syncookies;
+
+       syncookies = READ_ONCE(net->ipv4.sysctl_tcp_syncookies);
 
 #ifdef CONFIG_SYN_COOKIES
-       if (net->ipv4.sysctl_tcp_syncookies) {
+       if (syncookies) {
                msg = "Sending cookies";
                want_cookie = true;
                __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPREQQFULLDOCOOKIES);
@@ -6809,8 +6820,7 @@ static bool tcp_syn_flood_action(const struct sock *sk, const char *proto)
 #endif
                __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPREQQFULLDROP);
 
-       if (!queue->synflood_warned &&
-           net->ipv4.sysctl_tcp_syncookies != 2 &&
+       if (!queue->synflood_warned && syncookies != 2 &&
            xchg(&queue->synflood_warned, 1) == 0)
                net_info_ratelimited("%s: Possible SYN flooding on port %d. %s.  Check SNMP counters.\n",
                                     proto, sk->sk_num, msg);
@@ -6859,7 +6869,7 @@ u16 tcp_get_syncookie_mss(struct request_sock_ops *rsk_ops,
        struct tcp_sock *tp = tcp_sk(sk);
        u16 mss;
 
-       if (sock_net(sk)->ipv4.sysctl_tcp_syncookies != 2 &&
+       if (READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_syncookies) != 2 &&
            !inet_csk_reqsk_queue_is_full(sk))
                return 0;
 
@@ -6893,13 +6903,15 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
        bool want_cookie = false;
        struct dst_entry *dst;
        struct flowi fl;
+       u8 syncookies;
+
+       syncookies = READ_ONCE(net->ipv4.sysctl_tcp_syncookies);
 
        /* TW buckets are converted to open requests without
         * limitations, they conserve resources and peer is
         * evidently real one.
         */
-       if ((net->ipv4.sysctl_tcp_syncookies == 2 ||
-            inet_csk_reqsk_queue_is_full(sk)) && !isn) {
+       if ((syncookies == 2 || inet_csk_reqsk_queue_is_full(sk)) && !isn) {
                want_cookie = tcp_syn_flood_action(sk, rsk_ops->slab_name);
                if (!want_cookie)
                        goto drop;
@@ -6948,10 +6960,12 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
                tcp_rsk(req)->ts_off = af_ops->init_ts_off(net, skb);
 
        if (!want_cookie && !isn) {
+               int max_syn_backlog = READ_ONCE(net->ipv4.sysctl_max_syn_backlog);
+
                /* Kill the following clause, if you dislike this way. */
-               if (!net->ipv4.sysctl_tcp_syncookies &&
-                   (net->ipv4.sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) <
-                    (net->ipv4.sysctl_max_syn_backlog >> 2)) &&
+               if (!syncookies &&
+                   (max_syn_backlog - inet_csk_reqsk_queue_len(sk) <
+                    (max_syn_backlog >> 2)) &&
                    !tcp_peer_is_proven(req, dst)) {
                        /* Without syncookies last quarter of
                         * backlog is filled with destinations,
index fe8f23b..586c102 100644 (file)
@@ -108,10 +108,10 @@ static u32 tcp_v4_init_ts_off(const struct net *net, const struct sk_buff *skb)
 
 int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp)
 {
+       int reuse = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_tw_reuse);
        const struct inet_timewait_sock *tw = inet_twsk(sktw);
        const struct tcp_timewait_sock *tcptw = tcp_twsk(sktw);
        struct tcp_sock *tp = tcp_sk(sk);
-       int reuse = sock_net(sk)->ipv4.sysctl_tcp_tw_reuse;
 
        if (reuse == 2) {
                /* Still does not detect *everything* that goes through
@@ -1006,7 +1006,7 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst,
        if (skb) {
                __tcp_v4_send_check(skb, ireq->ir_loc_addr, ireq->ir_rmt_addr);
 
-               tos = sock_net(sk)->ipv4.sysctl_tcp_reflect_tos ?
+               tos = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_reflect_tos) ?
                                (tcp_rsk(req)->syn_tos & ~INET_ECN_MASK) |
                                (inet_sk(sk)->tos & INET_ECN_MASK) :
                                inet_sk(sk)->tos;
@@ -1526,7 +1526,7 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,
        /* Set ToS of the new socket based upon the value of incoming SYN.
         * ECT bits are set later in tcp_init_transfer().
         */
-       if (sock_net(sk)->ipv4.sysctl_tcp_reflect_tos)
+       if (READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_reflect_tos))
                newinet->tos = tcp_rsk(req)->syn_tos & ~INET_ECN_MASK;
 
        if (!dst) {
@@ -1964,7 +1964,10 @@ process:
                struct sock *nsk;
 
                sk = req->rsk_listener;
-               drop_reason = tcp_inbound_md5_hash(sk, skb,
+               if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))
+                       drop_reason = SKB_DROP_REASON_XFRM_POLICY;
+               else
+                       drop_reason = tcp_inbound_md5_hash(sk, skb,
                                                   &iph->saddr, &iph->daddr,
                                                   AF_INET, dif, sdif);
                if (unlikely(drop_reason)) {
@@ -2016,6 +2019,7 @@ process:
                        }
                        goto discard_and_relse;
                }
+               nf_reset_ct(skb);
                if (nsk == sk) {
                        reqsk_put(req);
                        tcp_v4_restore_cb(skb);
index 7029b0e..d58e672 100644 (file)
@@ -329,7 +329,7 @@ void tcp_update_metrics(struct sock *sk)
        int m;
 
        sk_dst_confirm(sk);
-       if (net->ipv4.sysctl_tcp_nometrics_save || !dst)
+       if (READ_ONCE(net->ipv4.sysctl_tcp_nometrics_save) || !dst)
                return;
 
        rcu_read_lock();
@@ -385,7 +385,7 @@ void tcp_update_metrics(struct sock *sk)
 
        if (tcp_in_initial_slowstart(tp)) {
                /* Slow start still did not finish. */
-               if (!net->ipv4.sysctl_tcp_no_ssthresh_metrics_save &&
+               if (!READ_ONCE(net->ipv4.sysctl_tcp_no_ssthresh_metrics_save) &&
                    !tcp_metric_locked(tm, TCP_METRIC_SSTHRESH)) {
                        val = tcp_metric_get(tm, TCP_METRIC_SSTHRESH);
                        if (val && (tcp_snd_cwnd(tp) >> 1) > val)
@@ -401,7 +401,7 @@ void tcp_update_metrics(struct sock *sk)
        } else if (!tcp_in_slow_start(tp) &&
                   icsk->icsk_ca_state == TCP_CA_Open) {
                /* Cong. avoidance phase, cwnd is reliable. */
-               if (!net->ipv4.sysctl_tcp_no_ssthresh_metrics_save &&
+               if (!READ_ONCE(net->ipv4.sysctl_tcp_no_ssthresh_metrics_save) &&
                    !tcp_metric_locked(tm, TCP_METRIC_SSTHRESH))
                        tcp_metric_set(tm, TCP_METRIC_SSTHRESH,
                                       max(tcp_snd_cwnd(tp) >> 1, tp->snd_ssthresh));
@@ -418,7 +418,7 @@ void tcp_update_metrics(struct sock *sk)
                        tcp_metric_set(tm, TCP_METRIC_CWND,
                                       (val + tp->snd_ssthresh) >> 1);
                }
-               if (!net->ipv4.sysctl_tcp_no_ssthresh_metrics_save &&
+               if (!READ_ONCE(net->ipv4.sysctl_tcp_no_ssthresh_metrics_save) &&
                    !tcp_metric_locked(tm, TCP_METRIC_SSTHRESH)) {
                        val = tcp_metric_get(tm, TCP_METRIC_SSTHRESH);
                        if (val && tp->snd_ssthresh > val)
@@ -428,7 +428,8 @@ void tcp_update_metrics(struct sock *sk)
                if (!tcp_metric_locked(tm, TCP_METRIC_REORDERING)) {
                        val = tcp_metric_get(tm, TCP_METRIC_REORDERING);
                        if (val < tp->reordering &&
-                           tp->reordering != net->ipv4.sysctl_tcp_reordering)
+                           tp->reordering !=
+                           READ_ONCE(net->ipv4.sysctl_tcp_reordering))
                                tcp_metric_set(tm, TCP_METRIC_REORDERING,
                                               tp->reordering);
                }
@@ -462,7 +463,7 @@ void tcp_init_metrics(struct sock *sk)
        if (tcp_metric_locked(tm, TCP_METRIC_CWND))
                tp->snd_cwnd_clamp = tcp_metric_get(tm, TCP_METRIC_CWND);
 
-       val = net->ipv4.sysctl_tcp_no_ssthresh_metrics_save ?
+       val = READ_ONCE(net->ipv4.sysctl_tcp_no_ssthresh_metrics_save) ?
              0 : tcp_metric_get(tm, TCP_METRIC_SSTHRESH);
        if (val) {
                tp->snd_ssthresh = val;
index 6854bb1..cb95d88 100644 (file)
@@ -173,7 +173,7 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
                         * Oh well... nobody has a sufficient solution to this
                         * protocol bug yet.
                         */
-                       if (twsk_net(tw)->ipv4.sysctl_tcp_rfc1337 == 0) {
+                       if (!READ_ONCE(twsk_net(tw)->ipv4.sysctl_tcp_rfc1337)) {
 kill:
                                inet_twsk_deschedule_put(tw);
                                return TCP_TW_SUCCESS;
@@ -781,7 +781,7 @@ listen_overflow:
        if (sk != req->rsk_listener)
                __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMIGRATEREQFAILURE);
 
-       if (!sock_net(sk)->ipv4.sysctl_tcp_abort_on_overflow) {
+       if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_abort_on_overflow)) {
                inet_rsk(req)->acked = 1;
                return NULL;
        }
index 1c05443..4c376b6 100644 (file)
@@ -167,16 +167,13 @@ static void tcp_event_data_sent(struct tcp_sock *tp,
        if (tcp_packets_in_flight(tp) == 0)
                tcp_ca_event(sk, CA_EVENT_TX_START);
 
-       /* If this is the first data packet sent in response to the
-        * previous received data,
-        * and it is a reply for ato after last received packet,
-        * increase pingpong count.
-        */
-       if (before(tp->lsndtime, icsk->icsk_ack.lrcvtime) &&
-           (u32)(now - icsk->icsk_ack.lrcvtime) < icsk->icsk_ack.ato)
-               inet_csk_inc_pingpong_cnt(sk);
-
        tp->lsndtime = now;
+
+       /* If it is a reply for ato after last received
+        * packet, enter pingpong mode.
+        */
+       if ((u32)(now - icsk->icsk_ack.lrcvtime) < icsk->icsk_ack.ato)
+               inet_csk_enter_pingpong_mode(sk);
 }
 
 /* Account for an ACK we sent. */
@@ -230,7 +227,7 @@ void tcp_select_initial_window(const struct sock *sk, int __space, __u32 mss,
         * which we interpret as a sign the remote TCP is not
         * misinterpreting the window field as a signed quantity.
         */
-       if (sock_net(sk)->ipv4.sysctl_tcp_workaround_signed_windows)
+       if (READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_workaround_signed_windows))
                (*rcv_wnd) = min(space, MAX_TCP_WINDOW);
        else
                (*rcv_wnd) = min_t(u32, space, U16_MAX);
@@ -241,7 +238,7 @@ void tcp_select_initial_window(const struct sock *sk, int __space, __u32 mss,
        *rcv_wscale = 0;
        if (wscale_ok) {
                /* Set window scaling on max possible window */
-               space = max_t(u32, space, sock_net(sk)->ipv4.sysctl_tcp_rmem[2]);
+               space = max_t(u32, space, READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_rmem[2]));
                space = max_t(u32, space, sysctl_rmem_max);
                space = min_t(u32, space, *window_clamp);
                *rcv_wscale = clamp_t(int, ilog2(space) - 15,
@@ -285,7 +282,7 @@ static u16 tcp_select_window(struct sock *sk)
         * scaled window.
         */
        if (!tp->rx_opt.rcv_wscale &&
-           sock_net(sk)->ipv4.sysctl_tcp_workaround_signed_windows)
+           READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_workaround_signed_windows))
                new_win = min(new_win, MAX_TCP_WINDOW);
        else
                new_win = min(new_win, (65535U << tp->rx_opt.rcv_wscale));
@@ -324,7 +321,7 @@ static void tcp_ecn_send_syn(struct sock *sk, struct sk_buff *skb)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        bool bpf_needs_ecn = tcp_bpf_ca_needs_ecn(sk);
-       bool use_ecn = sock_net(sk)->ipv4.sysctl_tcp_ecn == 1 ||
+       bool use_ecn = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_ecn) == 1 ||
                tcp_ca_needs_ecn(sk) || bpf_needs_ecn;
 
        if (!use_ecn) {
@@ -346,7 +343,7 @@ static void tcp_ecn_send_syn(struct sock *sk, struct sk_buff *skb)
 
 static void tcp_ecn_clear_syn(struct sock *sk, struct sk_buff *skb)
 {
-       if (sock_net(sk)->ipv4.sysctl_tcp_ecn_fallback)
+       if (READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_ecn_fallback))
                /* tp->ecn_flags are cleared at a later point in time when
                 * SYN ACK is ultimatively being received.
                 */
@@ -791,18 +788,18 @@ static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb,
        opts->mss = tcp_advertise_mss(sk);
        remaining -= TCPOLEN_MSS_ALIGNED;
 
-       if (likely(sock_net(sk)->ipv4.sysctl_tcp_timestamps && !*md5)) {
+       if (likely(READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_timestamps) && !*md5)) {
                opts->options |= OPTION_TS;
                opts->tsval = tcp_skb_timestamp(skb) + tp->tsoffset;
                opts->tsecr = tp->rx_opt.ts_recent;
                remaining -= TCPOLEN_TSTAMP_ALIGNED;
        }
-       if (likely(sock_net(sk)->ipv4.sysctl_tcp_window_scaling)) {
+       if (likely(READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_window_scaling))) {
                opts->ws = tp->rx_opt.rcv_wscale;
                opts->options |= OPTION_WSCALE;
                remaining -= TCPOLEN_WSCALE_ALIGNED;
        }
-       if (likely(sock_net(sk)->ipv4.sysctl_tcp_sack)) {
+       if (likely(READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_sack))) {
                opts->options |= OPTION_SACK_ADVERTISE;
                if (unlikely(!(OPTION_TS & opts->options)))
                        remaining -= TCPOLEN_SACKPERM_ALIGNED;
@@ -1719,7 +1716,8 @@ static inline int __tcp_mtu_to_mss(struct sock *sk, int pmtu)
        mss_now -= icsk->icsk_ext_hdr_len;
 
        /* Then reserve room for full set of TCP options and 8 bytes of data */
-       mss_now = max(mss_now, sock_net(sk)->ipv4.sysctl_tcp_min_snd_mss);
+       mss_now = max(mss_now,
+                     READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_min_snd_mss));
        return mss_now;
 }
 
@@ -1762,10 +1760,10 @@ void tcp_mtup_init(struct sock *sk)
        struct inet_connection_sock *icsk = inet_csk(sk);
        struct net *net = sock_net(sk);
 
-       icsk->icsk_mtup.enabled = net->ipv4.sysctl_tcp_mtu_probing > 1;
+       icsk->icsk_mtup.enabled = READ_ONCE(net->ipv4.sysctl_tcp_mtu_probing) > 1;
        icsk->icsk_mtup.search_high = tp->rx_opt.mss_clamp + sizeof(struct tcphdr) +
                               icsk->icsk_af_ops->net_header_len;
-       icsk->icsk_mtup.search_low = tcp_mss_to_mtu(sk, net->ipv4.sysctl_tcp_base_mss);
+       icsk->icsk_mtup.search_low = tcp_mss_to_mtu(sk, READ_ONCE(net->ipv4.sysctl_tcp_base_mss));
        icsk->icsk_mtup.probe_size = 0;
        if (icsk->icsk_mtup.enabled)
                icsk->icsk_mtup.probe_timestamp = tcp_jiffies32;
@@ -1897,7 +1895,7 @@ static void tcp_cwnd_validate(struct sock *sk, bool is_cwnd_limited)
                if (tp->packets_out > tp->snd_cwnd_used)
                        tp->snd_cwnd_used = tp->packets_out;
 
-               if (sock_net(sk)->ipv4.sysctl_tcp_slow_start_after_idle &&
+               if (READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_slow_start_after_idle) &&
                    (s32)(tcp_jiffies32 - tp->snd_cwnd_stamp) >= inet_csk(sk)->icsk_rto &&
                    !ca_ops->cong_control)
                        tcp_cwnd_application_limited(sk);
@@ -1975,7 +1973,7 @@ static u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now,
 
        bytes = sk->sk_pacing_rate >> READ_ONCE(sk->sk_pacing_shift);
 
-       r = tcp_min_rtt(tcp_sk(sk)) >> sock_net(sk)->ipv4.sysctl_tcp_tso_rtt_log;
+       r = tcp_min_rtt(tcp_sk(sk)) >> READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_tso_rtt_log);
        if (r < BITS_PER_TYPE(sk->sk_gso_max_size))
                bytes += sk->sk_gso_max_size >> r;
 
@@ -1994,7 +1992,7 @@ static u32 tcp_tso_segs(struct sock *sk, unsigned int mss_now)
 
        min_tso = ca_ops->min_tso_segs ?
                        ca_ops->min_tso_segs(sk) :
-                       sock_net(sk)->ipv4.sysctl_tcp_min_tso_segs;
+                       READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_min_tso_segs);
 
        tso_segs = tcp_tso_autosize(sk, mss_now, min_tso);
        return min_t(u32, tso_segs, sk->sk_gso_max_segs);
@@ -2282,7 +2280,7 @@ static inline void tcp_mtu_check_reprobe(struct sock *sk)
        u32 interval;
        s32 delta;
 
-       interval = net->ipv4.sysctl_tcp_probe_interval;
+       interval = READ_ONCE(net->ipv4.sysctl_tcp_probe_interval);
        delta = tcp_jiffies32 - icsk->icsk_mtup.probe_timestamp;
        if (unlikely(delta >= interval * HZ)) {
                int mss = tcp_current_mss(sk);
@@ -2366,7 +2364,7 @@ static int tcp_mtu_probe(struct sock *sk)
         * probing process by not resetting search range to its orignal.
         */
        if (probe_size > tcp_mtu_to_mss(sk, icsk->icsk_mtup.search_high) ||
-               interval < net->ipv4.sysctl_tcp_probe_threshold) {
+           interval < READ_ONCE(net->ipv4.sysctl_tcp_probe_threshold)) {
                /* Check whether enough time has elaplased for
                 * another round of probing.
                 */
@@ -2506,7 +2504,7 @@ static bool tcp_small_queue_check(struct sock *sk, const struct sk_buff *skb,
                      sk->sk_pacing_rate >> READ_ONCE(sk->sk_pacing_shift));
        if (sk->sk_pacing_status == SK_PACING_NONE)
                limit = min_t(unsigned long, limit,
-                             sock_net(sk)->ipv4.sysctl_tcp_limit_output_bytes);
+                             READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_limit_output_bytes));
        limit <<= factor;
 
        if (static_branch_unlikely(&tcp_tx_delay_enabled) &&
@@ -2740,7 +2738,7 @@ bool tcp_schedule_loss_probe(struct sock *sk, bool advancing_rto)
        if (rcu_access_pointer(tp->fastopen_rsk))
                return false;
 
-       early_retrans = sock_net(sk)->ipv4.sysctl_tcp_early_retrans;
+       early_retrans = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_early_retrans);
        /* Schedule a loss probe in 2*RTT for SACK capable connections
         * not in loss recovery, that are either limited by cwnd or application.
         */
@@ -3104,7 +3102,7 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *to,
        struct sk_buff *skb = to, *tmp;
        bool first = true;
 
-       if (!sock_net(sk)->ipv4.sysctl_tcp_retrans_collapse)
+       if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_retrans_collapse))
                return;
        if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN)
                return;
@@ -3646,7 +3644,7 @@ static void tcp_connect_init(struct sock *sk)
         * See tcp_input.c:tcp_rcv_state_process case TCP_SYN_SENT.
         */
        tp->tcp_header_len = sizeof(struct tcphdr);
-       if (sock_net(sk)->ipv4.sysctl_tcp_timestamps)
+       if (READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_timestamps))
                tp->tcp_header_len += TCPOLEN_TSTAMP_ALIGNED;
 
 #ifdef CONFIG_TCP_MD5SIG
@@ -3682,7 +3680,7 @@ static void tcp_connect_init(struct sock *sk)
                                  tp->advmss - (tp->rx_opt.ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0),
                                  &tp->rcv_wnd,
                                  &tp->window_clamp,
-                                 sock_net(sk)->ipv4.sysctl_tcp_window_scaling,
+                                 READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_window_scaling),
                                  &rcv_wscale,
                                  rcv_wnd);
 
@@ -4089,7 +4087,7 @@ void tcp_send_probe0(struct sock *sk)
 
        icsk->icsk_probes_out++;
        if (err <= 0) {
-               if (icsk->icsk_backoff < net->ipv4.sysctl_tcp_retries2)
+               if (icsk->icsk_backoff < READ_ONCE(net->ipv4.sysctl_tcp_retries2))
                        icsk->icsk_backoff++;
                timeout = tcp_probe0_when(sk, TCP_RTO_MAX);
        } else {
index 48f30e7..50abaa9 100644 (file)
@@ -14,7 +14,8 @@ static u32 tcp_rack_reo_wnd(const struct sock *sk)
                        return 0;
 
                if (tp->sacked_out >= tp->reordering &&
-                   !(sock_net(sk)->ipv4.sysctl_tcp_recovery & TCP_RACK_NO_DUPTHRESH))
+                   !(READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_recovery) &
+                     TCP_RACK_NO_DUPTHRESH))
                        return 0;
        }
 
@@ -187,7 +188,8 @@ void tcp_rack_update_reo_wnd(struct sock *sk, struct rate_sample *rs)
 {
        struct tcp_sock *tp = tcp_sk(sk);
 
-       if (sock_net(sk)->ipv4.sysctl_tcp_recovery & TCP_RACK_STATIC_REO_WND ||
+       if ((READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_recovery) &
+            TCP_RACK_STATIC_REO_WND) ||
            !rs->prior_delivered)
                return;
 
index 20cf4a9..50bba37 100644 (file)
@@ -143,7 +143,7 @@ static int tcp_out_of_resources(struct sock *sk, bool do_reset)
  */
 static int tcp_orphan_retries(struct sock *sk, bool alive)
 {
-       int retries = sock_net(sk)->ipv4.sysctl_tcp_orphan_retries; /* May be zero. */
+       int retries = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_orphan_retries); /* May be zero. */
 
        /* We know from an ICMP that something is wrong. */
        if (sk->sk_err_soft && !alive)
@@ -163,7 +163,7 @@ static void tcp_mtu_probing(struct inet_connection_sock *icsk, struct sock *sk)
        int mss;
 
        /* Black hole detection */
-       if (!net->ipv4.sysctl_tcp_mtu_probing)
+       if (!READ_ONCE(net->ipv4.sysctl_tcp_mtu_probing))
                return;
 
        if (!icsk->icsk_mtup.enabled) {
@@ -171,9 +171,9 @@ static void tcp_mtu_probing(struct inet_connection_sock *icsk, struct sock *sk)
                icsk->icsk_mtup.probe_timestamp = tcp_jiffies32;
        } else {
                mss = tcp_mtu_to_mss(sk, icsk->icsk_mtup.search_low) >> 1;
-               mss = min(net->ipv4.sysctl_tcp_base_mss, mss);
-               mss = max(mss, net->ipv4.sysctl_tcp_mtu_probe_floor);
-               mss = max(mss, net->ipv4.sysctl_tcp_min_snd_mss);
+               mss = min(READ_ONCE(net->ipv4.sysctl_tcp_base_mss), mss);
+               mss = max(mss, READ_ONCE(net->ipv4.sysctl_tcp_mtu_probe_floor));
+               mss = max(mss, READ_ONCE(net->ipv4.sysctl_tcp_min_snd_mss));
                icsk->icsk_mtup.search_low = tcp_mss_to_mtu(sk, mss);
        }
        tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
@@ -239,17 +239,18 @@ static int tcp_write_timeout(struct sock *sk)
        if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
                if (icsk->icsk_retransmits)
                        __dst_negative_advice(sk);
-               retry_until = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_syn_retries;
+               retry_until = icsk->icsk_syn_retries ? :
+                       READ_ONCE(net->ipv4.sysctl_tcp_syn_retries);
                expired = icsk->icsk_retransmits >= retry_until;
        } else {
-               if (retransmits_timed_out(sk, net->ipv4.sysctl_tcp_retries1, 0)) {
+               if (retransmits_timed_out(sk, READ_ONCE(net->ipv4.sysctl_tcp_retries1), 0)) {
                        /* Black hole detection */
                        tcp_mtu_probing(icsk, sk);
 
                        __dst_negative_advice(sk);
                }
 
-               retry_until = net->ipv4.sysctl_tcp_retries2;
+               retry_until = READ_ONCE(net->ipv4.sysctl_tcp_retries2);
                if (sock_flag(sk, SOCK_DEAD)) {
                        const bool alive = icsk->icsk_rto < TCP_RTO_MAX;
 
@@ -380,7 +381,7 @@ static void tcp_probe_timer(struct sock *sk)
                 msecs_to_jiffies(icsk->icsk_user_timeout))
                goto abort;
 
-       max_probes = sock_net(sk)->ipv4.sysctl_tcp_retries2;
+       max_probes = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_retries2);
        if (sock_flag(sk, SOCK_DEAD)) {
                const bool alive = inet_csk_rto_backoff(icsk, TCP_RTO_MAX) < TCP_RTO_MAX;
 
@@ -406,12 +407,15 @@ abort:            tcp_write_err(sk);
 static void tcp_fastopen_synack_timer(struct sock *sk, struct request_sock *req)
 {
        struct inet_connection_sock *icsk = inet_csk(sk);
-       int max_retries = icsk->icsk_syn_retries ? :
-           sock_net(sk)->ipv4.sysctl_tcp_synack_retries + 1; /* add one more retry for fastopen */
        struct tcp_sock *tp = tcp_sk(sk);
+       int max_retries;
 
        req->rsk_ops->syn_ack_timeout(req);
 
+       /* add one more retry for fastopen */
+       max_retries = icsk->icsk_syn_retries ? :
+               READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_synack_retries) + 1;
+
        if (req->num_timeout >= max_retries) {
                tcp_write_err(sk);
                return;
@@ -574,7 +578,7 @@ out_reset_timer:
         * linear-timeout retransmissions into a black hole
         */
        if (sk->sk_state == TCP_ESTABLISHED &&
-           (tp->thin_lto || net->ipv4.sysctl_tcp_thin_linear_timeouts) &&
+           (tp->thin_lto || READ_ONCE(net->ipv4.sysctl_tcp_thin_linear_timeouts)) &&
            tcp_stream_is_thin(tp) &&
            icsk->icsk_retransmits <= TCP_THIN_LINEAR_RETRIES) {
                icsk->icsk_backoff = 0;
@@ -585,7 +589,7 @@ out_reset_timer:
        }
        inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
                                  tcp_clamp_rto_to_user_timeout(sk), TCP_RTO_MAX);
-       if (retransmits_timed_out(sk, net->ipv4.sysctl_tcp_retries1 + 1, 0))
+       if (retransmits_timed_out(sk, READ_ONCE(net->ipv4.sysctl_tcp_retries1) + 1, 0))
                __sk_dst_reset(sk);
 
 out:;
index bf2e5e5..658bfed 100644 (file)
@@ -7,6 +7,7 @@
 menuconfig IPV6
        tristate "The IPv6 protocol"
        default y
+       select CRYPTO_LIB_SHA1
        help
          Support for IP version 6 (IPv6).
 
index 1b19325..49cc658 100644 (file)
@@ -1109,10 +1109,6 @@ ipv6_add_addr(struct inet6_dev *idev, struct ifa6_config *cfg,
                goto out;
        }
 
-       if (net->ipv6.devconf_all->disable_policy ||
-           idev->cnf.disable_policy)
-               f6i->dst_nopolicy = true;
-
        neigh_parms_data_state_setall(idev->nd_parms);
 
        ifa->addr = *cfg->pfx;
@@ -5172,9 +5168,9 @@ next:
                fillargs->event = RTM_GETMULTICAST;
 
                /* multicast address */
-               for (ifmca = rcu_dereference(idev->mc_list);
+               for (ifmca = rtnl_dereference(idev->mc_list);
                     ifmca;
-                    ifmca = rcu_dereference(ifmca->next), ip_idx++) {
+                    ifmca = rtnl_dereference(ifmca->next), ip_idx++) {
                        if (ip_idx < s_ip_idx)
                                continue;
                        err = inet6_fill_ifmcaddr(skb, ifmca, fillargs);
index 70564dd..6f354f8 100644 (file)
@@ -226,7 +226,7 @@ lookup_protocol:
        RCU_INIT_POINTER(inet->mc_list, NULL);
        inet->rcv_tos   = 0;
 
-       if (net->ipv4.sysctl_ip_no_pmtu_disc)
+       if (READ_ONCE(net->ipv4.sysctl_ip_no_pmtu_disc))
                inet->pmtudisc = IP_PMTUDISC_DONT;
        else
                inet->pmtudisc = IP_PMTUDISC_WANT;
index 6177022..9d92d51 100644 (file)
@@ -925,7 +925,7 @@ static int icmpv6_rcv(struct sk_buff *skb)
                break;
        case ICMPV6_EXT_ECHO_REQUEST:
                if (!net->ipv6.sysctl.icmpv6_echo_ignore_all &&
-                   net->ipv4.sysctl_icmp_echo_enable_probe)
+                   READ_ONCE(net->ipv4.sysctl_icmp_echo_enable_probe))
                        icmpv6_echo_reply(skb);
                break;
 
index 0322cc8..e1ebf5e 100644 (file)
 #include <net/inet_ecn.h>
 #include <net/dst_metadata.h>
 
-INDIRECT_CALLABLE_DECLARE(void tcp_v6_early_demux(struct sk_buff *));
 static void ip6_rcv_finish_core(struct net *net, struct sock *sk,
                                struct sk_buff *skb)
 {
-       void (*edemux)(struct sk_buff *skb);
-
-       if (net->ipv4.sysctl_ip_early_demux && !skb_dst(skb) && skb->sk == NULL) {
-               const struct inet6_protocol *ipprot;
-
-               ipprot = rcu_dereference(inet6_protos[ipv6_hdr(skb)->nexthdr]);
-               if (ipprot && (edemux = READ_ONCE(ipprot->early_demux)))
-                       INDIRECT_CALL_2(edemux, tcp_v6_early_demux,
-                                       udp_v6_early_demux, skb);
+       if (READ_ONCE(net->ipv4.sysctl_ip_early_demux) &&
+           !skb_dst(skb) && !skb->sk) {
+               switch (ipv6_hdr(skb)->nexthdr) {
+               case IPPROTO_TCP:
+                       if (READ_ONCE(net->ipv4.sysctl_tcp_early_demux))
+                               tcp_v6_early_demux(skb);
+                       break;
+               case IPPROTO_UDP:
+                       if (READ_ONCE(net->ipv4.sysctl_udp_early_demux))
+                               udp_v6_early_demux(skb);
+                       break;
+               }
        }
+
        if (!skb_valid_dst(skb))
                ip6_route_input(skb);
 }
index 77e3f59..897ca4f 100644 (file)
@@ -1464,6 +1464,7 @@ static int __ip6_append_data(struct sock *sk,
        int copy;
        int err;
        int offset = 0;
+       bool zc = false;
        u32 tskey = 0;
        struct rt6_info *rt = (struct rt6_info *)cork->dst;
        struct ipv6_txoptions *opt = v6_cork->opt;
@@ -1541,17 +1542,35 @@ emsgsize:
            rt->dst.dev->features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM))
                csummode = CHECKSUM_PARTIAL;
 
-       if (flags & MSG_ZEROCOPY && length && sock_flag(sk, SOCK_ZEROCOPY)) {
-               uarg = msg_zerocopy_realloc(sk, length, skb_zcopy(skb));
-               if (!uarg)
-                       return -ENOBUFS;
-               extra_uref = !skb_zcopy(skb);   /* only ref on new uarg */
-               if (rt->dst.dev->features & NETIF_F_SG &&
-                   csummode == CHECKSUM_PARTIAL) {
-                       paged = true;
-               } else {
-                       uarg->zerocopy = 0;
-                       skb_zcopy_set(skb, uarg, &extra_uref);
+       if ((flags & MSG_ZEROCOPY) && length) {
+               struct msghdr *msg = from;
+
+               if (getfrag == ip_generic_getfrag && msg->msg_ubuf) {
+                       if (skb_zcopy(skb) && msg->msg_ubuf != skb_zcopy(skb))
+                               return -EINVAL;
+
+                       /* Leave uarg NULL if can't zerocopy, callers should
+                        * be able to handle it.
+                        */
+                       if ((rt->dst.dev->features & NETIF_F_SG) &&
+                           csummode == CHECKSUM_PARTIAL) {
+                               paged = true;
+                               zc = true;
+                               uarg = msg->msg_ubuf;
+                       }
+               } else if (sock_flag(sk, SOCK_ZEROCOPY)) {
+                       uarg = msg_zerocopy_realloc(sk, length, skb_zcopy(skb));
+                       if (!uarg)
+                               return -ENOBUFS;
+                       extra_uref = !skb_zcopy(skb);   /* only ref on new uarg */
+                       if (rt->dst.dev->features & NETIF_F_SG &&
+                           csummode == CHECKSUM_PARTIAL) {
+                               paged = true;
+                               zc = true;
+                       } else {
+                               uarg->zerocopy = 0;
+                               skb_zcopy_set(skb, uarg, &extra_uref);
+                       }
                }
        }
 
@@ -1630,9 +1649,12 @@ alloc_new_skb:
                                 (fraglen + alloc_extra < SKB_MAX_ALLOC ||
                                  !(rt->dst.dev->features & NETIF_F_SG)))
                                alloclen = fraglen;
-                       else {
+                       else if (!zc) {
                                alloclen = min_t(int, fraglen, MAX_HEADER);
                                pagedlen = fraglen - alloclen;
+                       } else {
+                               alloclen = fragheaderlen + transhdrlen;
+                               pagedlen = datalen - transhdrlen;
                        }
                        alloclen += alloc_extra;
 
@@ -1742,13 +1764,14 @@ alloc_new_skb:
                                err = -EFAULT;
                                goto error;
                        }
-               } else if (!uarg || !uarg->zerocopy) {
+               } else if (!zc) {
                        int i = skb_shinfo(skb)->nr_frags;
 
                        err = -ENOMEM;
                        if (!sk_page_frag_refill(sk, pfrag))
                                goto error;
 
+                       skb_zcopy_downgrade_managed(skb);
                        if (!skb_can_coalesce(skb, i, pfrag->page,
                                              pfrag->offset)) {
                                err = -EMSGSIZE;
index 7f695c3..87c699d 100644 (file)
@@ -1522,7 +1522,6 @@ static void mld_query_work(struct work_struct *work)
 
                if (++cnt >= MLD_MAX_QUEUE) {
                        rework = true;
-                       schedule_delayed_work(&idev->mc_query_work, 0);
                        break;
                }
        }
@@ -1533,8 +1532,10 @@ static void mld_query_work(struct work_struct *work)
                __mld_query_work(skb);
        mutex_unlock(&idev->mc_lock);
 
-       if (!rework)
-               in6_dev_put(idev);
+       if (rework && queue_delayed_work(mld_wq, &idev->mc_query_work, 0))
+               return;
+
+       in6_dev_put(idev);
 }
 
 /* called with rcu_read_lock() */
@@ -1624,7 +1625,6 @@ static void mld_report_work(struct work_struct *work)
 
                if (++cnt >= MLD_MAX_QUEUE) {
                        rework = true;
-                       schedule_delayed_work(&idev->mc_report_work, 0);
                        break;
                }
        }
@@ -1635,8 +1635,10 @@ static void mld_report_work(struct work_struct *work)
                __mld_report_work(skb);
        mutex_unlock(&idev->mc_lock);
 
-       if (!rework)
-               in6_dev_put(idev);
+       if (rework && queue_delayed_work(mld_wq, &idev->mc_report_work, 0))
+               return;
+
+       in6_dev_put(idev);
 }
 
 static bool is_in(struct ifmcaddr6 *pmc, struct ip6_sf_list *psf, int type,
index ecf3a55..8c6c2d8 100644 (file)
 #include <linux/proc_fs.h>
 #include <net/ping.h>
 
+static void ping_v6_destroy(struct sock *sk)
+{
+       inet6_destroy_sock(sk);
+}
+
 /* Compatibility glue so we can support IPv6 when it's compiled as a module */
 static int dummy_ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len,
                                 int *addr_len)
@@ -181,6 +186,7 @@ struct proto pingv6_prot = {
        .owner =        THIS_MODULE,
        .init =         ping_init_sock,
        .close =        ping_close,
+       .destroy =      ping_v6_destroy,
        .connect =      ip6_datagram_connect_v6_only,
        .disconnect =   __udp_disconnect,
        .setsockopt =   ipv6_setsockopt,
index d25dc83..9164179 100644 (file)
@@ -4569,8 +4569,15 @@ struct fib6_info *addrconf_f6i_alloc(struct net *net,
        }
 
        f6i = ip6_route_info_create(&cfg, gfp_flags, NULL);
-       if (!IS_ERR(f6i))
+       if (!IS_ERR(f6i)) {
                f6i->dst_nocount = true;
+
+               if (!anycast &&
+                   (net->ipv6.devconf_all->disable_policy ||
+                    idev->cnf.disable_policy))
+                       f6i->dst_nopolicy = true;
+       }
+
        return f6i;
 }
 
@@ -5734,7 +5741,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
                if (nexthop_is_blackhole(rt->nh))
                        rtm->rtm_type = RTN_BLACKHOLE;
 
-               if (net->ipv4.sysctl_nexthop_compat_mode &&
+               if (READ_ONCE(net->ipv4.sysctl_nexthop_compat_mode) &&
                    rt6_fill_node_nexthop(skb, rt->nh, &nh_flags) < 0)
                        goto nla_put_failure;
 
index 6de0118..d43c50a 100644 (file)
@@ -406,7 +406,6 @@ int __net_init seg6_hmac_net_init(struct net *net)
 
        return rhashtable_init(&sdata->hmac_infos, &rht_params);
 }
-EXPORT_SYMBOL(seg6_hmac_net_init);
 
 void seg6_hmac_exit(void)
 {
index d648550..e756ba7 100644 (file)
@@ -189,6 +189,8 @@ int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto)
        }
 #endif
 
+       hdr->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
+
        skb_postpush_rcsum(skb, hdr, tot_len);
 
        return 0;
@@ -241,6 +243,8 @@ int seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh)
        }
 #endif
 
+       hdr->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
+
        skb_postpush_rcsum(skb, hdr, sizeof(struct ipv6hdr) + hdrlen);
 
        return 0;
@@ -302,7 +306,6 @@ static int seg6_do_srh(struct sk_buff *skb)
                break;
        }
 
-       ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
        skb_set_transport_header(skb, sizeof(struct ipv6hdr));
        nf_reset_ct(skb);
 
index 98a3428..2cd4a8d 100644 (file)
@@ -826,7 +826,6 @@ static int input_action_end_b6(struct sk_buff *skb, struct seg6_local_lwt *slwt)
        if (err)
                goto drop;
 
-       ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
        skb_set_transport_header(skb, sizeof(struct ipv6hdr));
 
        seg6_lookup_nexthop(skb, NULL, 0);
@@ -858,7 +857,6 @@ static int input_action_end_b6_encap(struct sk_buff *skb,
        if (err)
                goto drop;
 
-       ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
        skb_set_transport_header(skb, sizeof(struct ipv6hdr));
 
        seg6_lookup_nexthop(skb, NULL, 0);
index c0b138c..6bcd5e4 100644 (file)
@@ -323,8 +323,6 @@ static int ipip6_tunnel_get_prl(struct net_device *dev, struct ip_tunnel_prl __u
                kcalloc(cmax, sizeof(*kp), GFP_KERNEL_ACCOUNT | __GFP_NOWARN) :
                NULL;
 
-       rcu_read_lock();
-
        ca = min(t->prl_count, cmax);
 
        if (!kp) {
@@ -341,7 +339,7 @@ static int ipip6_tunnel_get_prl(struct net_device *dev, struct ip_tunnel_prl __u
                }
        }
 
-       c = 0;
+       rcu_read_lock();
        for_each_prl_rcu(t->prl) {
                if (c >= cmax)
                        break;
@@ -353,7 +351,7 @@ static int ipip6_tunnel_get_prl(struct net_device *dev, struct ip_tunnel_prl __u
                if (kprl.addr != htonl(INADDR_ANY))
                        break;
        }
-out:
+
        rcu_read_unlock();
 
        len = sizeof(*kp) * c;
@@ -362,7 +360,7 @@ out:
                ret = -EFAULT;
 
        kfree(kp);
-
+out:
        return ret;
 }
 
index 9cc123f..5014aa6 100644 (file)
@@ -141,7 +141,8 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
        __u8 rcv_wscale;
        u32 tsoff = 0;
 
-       if (!sock_net(sk)->ipv4.sysctl_tcp_syncookies || !th->ack || th->rst)
+       if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_syncookies) ||
+           !th->ack || th->rst)
                goto out;
 
        if (tcp_synq_no_recent_overflow(sk))
index f37dd4a..be09941 100644 (file)
@@ -546,7 +546,7 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst,
                if (np->repflow && ireq->pktopts)
                        fl6->flowlabel = ip6_flowlabel(ipv6_hdr(ireq->pktopts));
 
-               tclass = sock_net(sk)->ipv4.sysctl_tcp_reflect_tos ?
+               tclass = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_reflect_tos) ?
                                (tcp_rsk(req)->syn_tos & ~INET_ECN_MASK) |
                                (np->tclass & INET_ECN_MASK) :
                                np->tclass;
@@ -1314,7 +1314,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
        /* Set ToS of the new socket based upon the value of incoming SYN.
         * ECT bits are set later in tcp_init_transfer().
         */
-       if (sock_net(sk)->ipv4.sysctl_tcp_reflect_tos)
+       if (READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_reflect_tos))
                newnp->tclass = tcp_rsk(req)->syn_tos & ~INET_ECN_MASK;
 
        /* Clone native IPv6 options from listening socket (if any)
@@ -1822,7 +1822,7 @@ do_time_wait:
        goto discard_it;
 }
 
-INDIRECT_CALLABLE_SCOPE void tcp_v6_early_demux(struct sk_buff *skb)
+void tcp_v6_early_demux(struct sk_buff *skb)
 {
        const struct ipv6hdr *hdr;
        const struct tcphdr *th;
@@ -2176,12 +2176,7 @@ struct proto tcpv6_prot = {
 };
 EXPORT_SYMBOL_GPL(tcpv6_prot);
 
-/* thinking of making this const? Don't.
- * early_demux can change based on sysctl.
- */
-static struct inet6_protocol tcpv6_protocol = {
-       .early_demux    =       tcp_v6_early_demux,
-       .early_demux_handler =  tcp_v6_early_demux,
+static const struct inet6_protocol tcpv6_protocol = {
        .handler        =       tcp_v6_rcv,
        .err_handler    =       tcp_v6_err,
        .flags          =       INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
index 55afd7f..e2f2e08 100644 (file)
@@ -1052,7 +1052,7 @@ static struct sock *__udp6_lib_demux_lookup(struct net *net,
        return NULL;
 }
 
-INDIRECT_CALLABLE_SCOPE void udp_v6_early_demux(struct sk_buff *skb)
+void udp_v6_early_demux(struct sk_buff *skb)
 {
        struct net *net = dev_net(skb->dev);
        const struct udphdr *uh;
@@ -1660,12 +1660,7 @@ int udpv6_getsockopt(struct sock *sk, int level, int optname,
        return ipv6_getsockopt(sk, level, optname, optval, optlen);
 }
 
-/* thinking of making this const? Don't.
- * early_demux can change based on sysctl.
- */
-static struct inet6_protocol udpv6_protocol = {
-       .early_demux    =       udp_v6_early_demux,
-       .early_demux_handler =  udp_v6_early_demux,
+static const struct inet6_protocol udpv6_protocol = {
        .handler        =       udpv6_rcv,
        .err_handler    =       udpv6_err,
        .flags          =       INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
index f7896f2..4ddf297 100644 (file)
@@ -4468,14 +4468,14 @@ EXPORT_SYMBOL_GPL(ieee80211_color_change_finish);
 
 void
 ieeee80211_obss_color_collision_notify(struct ieee80211_vif *vif,
-                                      u64 color_bitmap)
+                                      u64 color_bitmap, gfp_t gfp)
 {
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
 
        if (sdata->vif.color_change_active || sdata->vif.csa_active)
                return;
 
-       cfg80211_obss_color_collision_notify(sdata->dev, color_bitmap);
+       cfg80211_obss_color_collision_notify(sdata->dev, color_bitmap, gfp);
 }
 EXPORT_SYMBOL_GPL(ieeee80211_obss_color_collision_notify);
 
index 4153147..1a9ada4 100644 (file)
@@ -378,6 +378,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
        struct cfg80211_nan_func *func;
 
        clear_bit(SDATA_STATE_RUNNING, &sdata->state);
+       synchronize_rcu(); /* flush _ieee80211_wake_txqs() */
 
        cancel_scan = rcu_access_pointer(local->scan_sdata) == sdata;
        if (cancel_scan)
index 3c08ae0..1675f8c 100644 (file)
@@ -3217,7 +3217,8 @@ ieee80211_rx_check_bss_color_collision(struct ieee80211_rx_data *rx)
                                      IEEE80211_HE_OPERATION_BSS_COLOR_MASK);
                if (color == bss_conf->he_bss_color.color)
                        ieeee80211_obss_color_collision_notify(&rx->sdata->vif,
-                                                              BIT_ULL(color));
+                                                              BIT_ULL(color),
+                                                              GFP_ATOMIC);
        }
 }
 
index 0e4efc0..c425f4f 100644 (file)
@@ -2818,19 +2818,10 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
        /*
         * If the skb is shared we need to obtain our own copy.
         */
-       if (skb_shared(skb)) {
-               struct sk_buff *tmp_skb = skb;
-
-               /* can't happen -- skb is a clone if info_id != 0 */
-               WARN_ON(info_id);
-
-               skb = skb_clone(skb, GFP_ATOMIC);
-               kfree_skb(tmp_skb);
-
-               if (!skb) {
-                       ret = -ENOMEM;
-                       goto free;
-               }
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (unlikely(!skb)) {
+               ret = -ENOMEM;
+               goto free;
        }
 
        hdr.frame_control = fc;
@@ -3539,15 +3530,9 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
 
        /* after this point (skb is modified) we cannot return false */
 
-       if (skb_shared(skb)) {
-               struct sk_buff *tmp_skb = skb;
-
-               skb = skb_clone(skb, GFP_ATOMIC);
-               kfree_skb(tmp_skb);
-
-               if (!skb)
-                       return true;
-       }
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (unlikely(!skb))
+               return true;
 
        if ((hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) &&
            ieee80211_amsdu_aggregate(sdata, sta, fast_tx, skb))
@@ -4437,7 +4422,7 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
                                struct net_device *dev, struct sta_info *sta,
                                struct ieee80211_key *key, struct sk_buff *skb)
 {
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_tx_info *info;
        struct ieee80211_local *local = sdata->local;
        struct tid_ampdu_tx *tid_tx;
        u8 tid;
@@ -4452,6 +4437,11 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
            test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
                goto out_free;
 
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (unlikely(!skb))
+               return;
+
+       info = IEEE80211_SKB_CB(skb);
        memset(info, 0, sizeof(*info));
 
        ieee80211_aggr_check(sdata, sta, skb);
index 1e26b52..dad42d4 100644 (file)
@@ -301,6 +301,9 @@ static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
        local_bh_disable();
        spin_lock(&fq->lock);
 
+       if (!test_bit(SDATA_STATE_RUNNING, &sdata->state))
+               goto out;
+
        if (sdata->vif.type == NL80211_IFTYPE_AP)
                ps = &sdata->bss->ps;
 
index 62c6733..d50480b 100644 (file)
@@ -147,8 +147,8 @@ u16 __ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
        bool qos;
 
        /* all mesh/ocb stations are required to support WME */
-       if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
-           sdata->vif.type == NL80211_IFTYPE_OCB)
+       if (sta && (sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
+                   sdata->vif.type == NL80211_IFTYPE_OCB))
                qos = true;
        else if (sta)
                qos = sta->sta.wme;
index be3b918..30d2890 100644 (file)
@@ -765,6 +765,7 @@ static noinline bool mptcp_established_options_rst(struct sock *sk, struct sk_bu
        opts->suboptions |= OPTION_MPTCP_RST;
        opts->reset_transient = subflow->reset_transient;
        opts->reset_reason = subflow->reset_reason;
+       MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPRSTTX);
 
        return true;
 }
@@ -788,6 +789,7 @@ static bool mptcp_established_options_fastclose(struct sock *sk,
        opts->rcvr_key = msk->remote_key;
 
        pr_debug("FASTCLOSE key=%llu", opts->rcvr_key);
+       MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPFASTCLOSETX);
        return true;
 }
 
@@ -809,6 +811,7 @@ static bool mptcp_established_options_mp_fail(struct sock *sk,
        opts->fail_seq = subflow->map_seq;
 
        pr_debug("MP_FAIL fail_seq=%llu", opts->fail_seq);
+       MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPFAILTX);
 
        return true;
 }
@@ -833,13 +836,11 @@ bool mptcp_established_options(struct sock *sk, struct sk_buff *skb,
                    mptcp_established_options_mp_fail(sk, &opt_size, remaining, opts)) {
                        *size += opt_size;
                        remaining -= opt_size;
-                       MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPFASTCLOSETX);
                }
                /* MP_RST can be used with MP_FASTCLOSE and MP_FAIL if there is room */
                if (mptcp_established_options_rst(sk, skb, &opt_size, remaining, opts)) {
                        *size += opt_size;
                        remaining -= opt_size;
-                       MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPRSTTX);
                }
                return true;
        }
@@ -966,7 +967,7 @@ static bool check_fully_established(struct mptcp_sock *msk, struct sock *ssk,
                        goto reset;
                subflow->mp_capable = 0;
                pr_fallback(msk);
-               __mptcp_do_fallback(msk);
+               mptcp_do_fallback(ssk);
                return false;
        }
 
@@ -1270,7 +1271,7 @@ raise_win:
                if (unlikely(th->syn))
                        new_win = min(new_win, 65535U) << tp->rx_opt.rcv_wscale;
                if (!tp->rx_opt.rcv_wscale &&
-                   sock_net(ssk)->ipv4.sysctl_tcp_workaround_signed_windows)
+                   READ_ONCE(sock_net(ssk)->ipv4.sysctl_tcp_workaround_signed_windows))
                        new_win = min(new_win, MAX_TCP_WINDOW);
                else
                        new_win = min(new_win, (65535U << tp->rx_opt.rcv_wscale));
@@ -1583,6 +1584,9 @@ mp_rst:
                *ptr++ = mptcp_option(MPTCPOPT_MP_PRIO,
                                      TCPOLEN_MPTCP_PRIO,
                                      opts->backup, TCPOPT_NOP);
+
+               MPTCP_INC_STATS(sock_net((const struct sock *)tp),
+                               MPTCP_MIB_MPPRIOTX);
        }
 
 mp_capable_done:
index 59a8522..45e2a48 100644 (file)
@@ -299,23 +299,21 @@ void mptcp_pm_mp_fail_received(struct sock *sk, u64 fail_seq)
 {
        struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
        struct mptcp_sock *msk = mptcp_sk(subflow->conn);
-       struct sock *s = (struct sock *)msk;
 
        pr_debug("fail_seq=%llu", fail_seq);
 
        if (!READ_ONCE(msk->allow_infinite_fallback))
                return;
 
-       if (!READ_ONCE(subflow->mp_fail_response_expect)) {
+       if (!subflow->fail_tout) {
                pr_debug("send MP_FAIL response and infinite map");
 
                subflow->send_mp_fail = 1;
-               MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPFAILTX);
                subflow->send_infinite_map = 1;
-       } else if (!sock_flag(sk, SOCK_DEAD)) {
+               tcp_send_ack(sk);
+       } else {
                pr_debug("MP_FAIL response received");
-
-               sk_stop_timer(s, &s->sk_timer);
+               WRITE_ONCE(subflow->fail_tout, 0);
        }
 }
 
index e099f2a..7c7395b 100644 (file)
@@ -717,9 +717,10 @@ void mptcp_pm_nl_addr_send_ack(struct mptcp_sock *msk)
        }
 }
 
-static int mptcp_pm_nl_mp_prio_send_ack(struct mptcp_sock *msk,
-                                       struct mptcp_addr_info *addr,
-                                       u8 bkup)
+int mptcp_pm_nl_mp_prio_send_ack(struct mptcp_sock *msk,
+                                struct mptcp_addr_info *addr,
+                                struct mptcp_addr_info *rem,
+                                u8 bkup)
 {
        struct mptcp_subflow_context *subflow;
 
@@ -727,24 +728,29 @@ static int mptcp_pm_nl_mp_prio_send_ack(struct mptcp_sock *msk,
 
        mptcp_for_each_subflow(msk, subflow) {
                struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
-               struct sock *sk = (struct sock *)msk;
-               struct mptcp_addr_info local;
+               struct mptcp_addr_info local, remote;
+               bool slow;
 
                local_address((struct sock_common *)ssk, &local);
                if (!mptcp_addresses_equal(&local, addr, addr->port))
                        continue;
 
+               if (rem && rem->family != AF_UNSPEC) {
+                       remote_address((struct sock_common *)ssk, &remote);
+                       if (!mptcp_addresses_equal(&remote, rem, rem->port))
+                               continue;
+               }
+
+               slow = lock_sock_fast(ssk);
                if (subflow->backup != bkup)
                        msk->last_snd = NULL;
                subflow->backup = bkup;
                subflow->send_mp_prio = 1;
                subflow->request_bkup = bkup;
-               __MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPPRIOTX);
 
-               spin_unlock_bh(&msk->pm.lock);
                pr_debug("send ack for mp_prio");
-               mptcp_subflow_send_ack(ssk);
-               spin_lock_bh(&msk->pm.lock);
+               __mptcp_subflow_send_ack(ssk);
+               unlock_sock_fast(ssk, slow);
 
                return 0;
        }
@@ -801,7 +807,8 @@ static void mptcp_pm_nl_rm_addr_or_subflow(struct mptcp_sock *msk,
                        removed = true;
                        __MPTCP_INC_STATS(sock_net(sk), rm_type);
                }
-               __set_bit(rm_list->ids[i], msk->pm.id_avail_bitmap);
+               if (rm_type == MPTCP_MIB_RMSUBFLOW)
+                       __set_bit(rm_list->ids[i], msk->pm.id_avail_bitmap);
                if (!removed)
                        continue;
 
@@ -1816,8 +1823,10 @@ static void mptcp_pm_nl_fullmesh(struct mptcp_sock *msk,
 
        list.ids[list.nr++] = addr->id;
 
+       spin_lock_bh(&msk->pm.lock);
        mptcp_pm_nl_rm_subflow_received(msk, &list);
        mptcp_pm_create_subflow_or_signal_addr(msk);
+       spin_unlock_bh(&msk->pm.lock);
 }
 
 static int mptcp_nl_set_flags(struct net *net,
@@ -1835,12 +1844,10 @@ static int mptcp_nl_set_flags(struct net *net,
                        goto next;
 
                lock_sock(sk);
-               spin_lock_bh(&msk->pm.lock);
                if (changed & MPTCP_PM_ADDR_FLAG_BACKUP)
-                       ret = mptcp_pm_nl_mp_prio_send_ack(msk, addr, bkup);
+                       ret = mptcp_pm_nl_mp_prio_send_ack(msk, addr, NULL, bkup);
                if (changed & MPTCP_PM_ADDR_FLAG_FULLMESH)
                        mptcp_pm_nl_fullmesh(msk, addr);
-               spin_unlock_bh(&msk->pm.lock);
                release_sock(sk);
 
 next:
@@ -1854,6 +1861,9 @@ next:
 static int mptcp_nl_cmd_set_flags(struct sk_buff *skb, struct genl_info *info)
 {
        struct mptcp_pm_addr_entry addr = { .addr = { .family = AF_UNSPEC }, }, *entry;
+       struct mptcp_pm_addr_entry remote = { .addr = { .family = AF_UNSPEC }, };
+       struct nlattr *attr_rem = info->attrs[MPTCP_PM_ATTR_ADDR_REMOTE];
+       struct nlattr *token = info->attrs[MPTCP_PM_ATTR_TOKEN];
        struct nlattr *attr = info->attrs[MPTCP_PM_ATTR_ADDR];
        struct pm_nl_pernet *pernet = genl_info_pm_nl(info);
        u8 changed, mask = MPTCP_PM_ADDR_FLAG_BACKUP |
@@ -1866,6 +1876,12 @@ static int mptcp_nl_cmd_set_flags(struct sk_buff *skb, struct genl_info *info)
        if (ret < 0)
                return ret;
 
+       if (attr_rem) {
+               ret = mptcp_pm_parse_entry(attr_rem, info, false, &remote);
+               if (ret < 0)
+                       return ret;
+       }
+
        if (addr.flags & MPTCP_PM_ADDR_FLAG_BACKUP)
                bkup = 1;
        if (addr.addr.family == AF_UNSPEC) {
@@ -1874,6 +1890,10 @@ static int mptcp_nl_cmd_set_flags(struct sk_buff *skb, struct genl_info *info)
                        return -EOPNOTSUPP;
        }
 
+       if (token)
+               return mptcp_userspace_pm_set_flags(sock_net(skb->sk),
+                                                   token, &addr, &remote, bkup);
+
        spin_lock_bh(&pernet->lock);
        entry = __lookup_addr(pernet, &addr.addr, lookup_by_id);
        if (!entry) {
index f56378e..9e82250 100644 (file)
@@ -5,6 +5,7 @@
  */
 
 #include "protocol.h"
+#include "mib.h"
 
 void mptcp_free_local_addr_list(struct mptcp_sock *msk)
 {
@@ -306,15 +307,11 @@ static struct sock *mptcp_nl_find_ssk(struct mptcp_sock *msk,
                                      const struct mptcp_addr_info *local,
                                      const struct mptcp_addr_info *remote)
 {
-       struct sock *sk = &msk->sk.icsk_inet.sk;
        struct mptcp_subflow_context *subflow;
-       struct sock *found = NULL;
 
        if (local->family != remote->family)
                return NULL;
 
-       lock_sock(sk);
-
        mptcp_for_each_subflow(msk, subflow) {
                const struct inet_sock *issk;
                struct sock *ssk;
@@ -347,16 +344,11 @@ static struct sock *mptcp_nl_find_ssk(struct mptcp_sock *msk,
                }
 
                if (issk->inet_sport == local->port &&
-                   issk->inet_dport == remote->port) {
-                       found = ssk;
-                       goto found;
-               }
+                   issk->inet_dport == remote->port)
+                       return ssk;
        }
 
-found:
-       release_sock(sk);
-
-       return found;
+       return NULL;
 }
 
 int mptcp_nl_cmd_sf_destroy(struct sk_buff *skb, struct genl_info *info)
@@ -412,18 +404,51 @@ int mptcp_nl_cmd_sf_destroy(struct sk_buff *skb, struct genl_info *info)
        }
 
        sk = &msk->sk.icsk_inet.sk;
+       lock_sock(sk);
        ssk = mptcp_nl_find_ssk(msk, &addr_l, &addr_r);
        if (ssk) {
                struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
 
                mptcp_subflow_shutdown(sk, ssk, RCV_SHUTDOWN | SEND_SHUTDOWN);
                mptcp_close_ssk(sk, ssk, subflow);
+               MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RMSUBFLOW);
                err = 0;
        } else {
                err = -ESRCH;
        }
+       release_sock(sk);
 
- destroy_err:
+destroy_err:
        sock_put((struct sock *)msk);
        return err;
 }
+
+int mptcp_userspace_pm_set_flags(struct net *net, struct nlattr *token,
+                                struct mptcp_pm_addr_entry *loc,
+                                struct mptcp_pm_addr_entry *rem, u8 bkup)
+{
+       struct mptcp_sock *msk;
+       int ret = -EINVAL;
+       u32 token_val;
+
+       token_val = nla_get_u32(token);
+
+       msk = mptcp_token_get_sock(net, token_val);
+       if (!msk)
+               return ret;
+
+       if (!mptcp_pm_is_userspace(msk))
+               goto set_flags_err;
+
+       if (loc->addr.family == AF_UNSPEC ||
+           rem->addr.family == AF_UNSPEC)
+               goto set_flags_err;
+
+       lock_sock((struct sock *)msk);
+       ret = mptcp_pm_nl_mp_prio_send_ack(msk, &loc->addr, &rem->addr, bkup);
+       release_sock((struct sock *)msk);
+
+set_flags_err:
+       sock_put((struct sock *)msk);
+       return ret;
+}
index 17e1339..7e1518b 100644 (file)
@@ -500,19 +500,24 @@ static void mptcp_set_timeout(struct sock *sk)
        __mptcp_set_timeout(sk, tout);
 }
 
-static bool tcp_can_send_ack(const struct sock *ssk)
+static inline bool tcp_can_send_ack(const struct sock *ssk)
 {
        return !((1 << inet_sk_state_load(ssk)) &
               (TCPF_SYN_SENT | TCPF_SYN_RECV | TCPF_TIME_WAIT | TCPF_CLOSE | TCPF_LISTEN));
 }
 
+void __mptcp_subflow_send_ack(struct sock *ssk)
+{
+       if (tcp_can_send_ack(ssk))
+               tcp_send_ack(ssk);
+}
+
 void mptcp_subflow_send_ack(struct sock *ssk)
 {
        bool slow;
 
        slow = lock_sock_fast(ssk);
-       if (tcp_can_send_ack(ssk))
-               tcp_send_ack(ssk);
+       __mptcp_subflow_send_ack(ssk);
        unlock_sock_fast(ssk, slow);
 }
 
@@ -1245,7 +1250,7 @@ static void mptcp_update_infinite_map(struct mptcp_sock *msk,
        MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_INFINITEMAPTX);
        mptcp_subflow_ctx(ssk)->send_infinite_map = 0;
        pr_fallback(msk);
-       __mptcp_do_fallback(msk);
+       mptcp_do_fallback(ssk);
 }
 
 static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk,
@@ -1903,7 +1908,7 @@ static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied)
        if (msk->rcvq_space.copied <= msk->rcvq_space.space)
                goto new_measure;
 
-       if (sock_net(sk)->ipv4.sysctl_tcp_moderate_rcvbuf &&
+       if (READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_moderate_rcvbuf) &&
            !(sk->sk_userlocks & SOCK_RCVBUF_LOCK)) {
                int rcvmem, rcvbuf;
                u64 rcvwin, grow;
@@ -1921,7 +1926,7 @@ static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied)
 
                do_div(rcvwin, advmss);
                rcvbuf = min_t(u64, rcvwin * rcvmem,
-                              sock_net(sk)->ipv4.sysctl_tcp_rmem[2]);
+                              READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_rmem[2]));
 
                if (rcvbuf > sk->sk_rcvbuf) {
                        u32 window_clamp;
@@ -2175,21 +2180,6 @@ static void mptcp_retransmit_timer(struct timer_list *t)
        sock_put(sk);
 }
 
-static struct mptcp_subflow_context *
-mp_fail_response_expect_subflow(struct mptcp_sock *msk)
-{
-       struct mptcp_subflow_context *subflow, *ret = NULL;
-
-       mptcp_for_each_subflow(msk, subflow) {
-               if (READ_ONCE(subflow->mp_fail_response_expect)) {
-                       ret = subflow;
-                       break;
-               }
-       }
-
-       return ret;
-}
-
 static void mptcp_timeout_timer(struct timer_list *t)
 {
        struct sock *sk = from_timer(sk, t, sk_timer);
@@ -2346,6 +2336,11 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk,
                kfree_rcu(subflow, rcu);
        } else {
                /* otherwise tcp will dispose of the ssk and subflow ctx */
+               if (ssk->sk_state == TCP_LISTEN) {
+                       tcp_set_state(ssk, TCP_CLOSE);
+                       mptcp_subflow_queue_clean(ssk);
+                       inet_csk_listen_stop(ssk);
+               }
                __tcp_close(ssk, 0);
 
                /* close acquired an extra ref */
@@ -2518,27 +2513,50 @@ reset_timer:
                mptcp_reset_timer(sk);
 }
 
+/* schedule the timeout timer for the relevant event: either close timeout
+ * or mp_fail timeout. The close timeout takes precedence on the mp_fail one
+ */
+void mptcp_reset_timeout(struct mptcp_sock *msk, unsigned long fail_tout)
+{
+       struct sock *sk = (struct sock *)msk;
+       unsigned long timeout, close_timeout;
+
+       if (!fail_tout && !sock_flag(sk, SOCK_DEAD))
+               return;
+
+       close_timeout = inet_csk(sk)->icsk_mtup.probe_timestamp - tcp_jiffies32 + jiffies + TCP_TIMEWAIT_LEN;
+
+       /* the close timeout takes precedence on the fail one, and here at least one of
+        * them is active
+        */
+       timeout = sock_flag(sk, SOCK_DEAD) ? close_timeout : fail_tout;
+
+       sk_reset_timer(sk, &sk->sk_timer, timeout);
+}
+
 static void mptcp_mp_fail_no_response(struct mptcp_sock *msk)
 {
-       struct mptcp_subflow_context *subflow;
-       struct sock *ssk;
+       struct sock *ssk = msk->first;
        bool slow;
 
-       subflow = mp_fail_response_expect_subflow(msk);
-       if (subflow) {
-               pr_debug("MP_FAIL doesn't respond, reset the subflow");
+       if (!ssk)
+               return;
 
-               ssk = mptcp_subflow_tcp_sock(subflow);
-               slow = lock_sock_fast(ssk);
-               mptcp_subflow_reset(ssk);
-               unlock_sock_fast(ssk, slow);
-       }
+       pr_debug("MP_FAIL doesn't respond, reset the subflow");
+
+       slow = lock_sock_fast(ssk);
+       mptcp_subflow_reset(ssk);
+       WRITE_ONCE(mptcp_subflow_ctx(ssk)->fail_tout, 0);
+       unlock_sock_fast(ssk, slow);
+
+       mptcp_reset_timeout(msk, 0);
 }
 
 static void mptcp_worker(struct work_struct *work)
 {
        struct mptcp_sock *msk = container_of(work, struct mptcp_sock, work);
        struct sock *sk = &msk->sk.icsk_inet.sk;
+       unsigned long fail_tout;
        int state;
 
        lock_sock(sk);
@@ -2575,7 +2593,9 @@ static void mptcp_worker(struct work_struct *work)
        if (test_and_clear_bit(MPTCP_WORK_RTX, &msk->flags))
                __mptcp_retrans(sk);
 
-       mptcp_mp_fail_no_response(msk);
+       fail_tout = msk->first ? READ_ONCE(mptcp_subflow_ctx(msk->first)->fail_tout) : 0;
+       if (fail_tout && time_after(jiffies, fail_tout))
+               mptcp_mp_fail_no_response(msk);
 
 unlock:
        release_sock(sk);
@@ -2649,8 +2669,8 @@ static int mptcp_init_sock(struct sock *sk)
        mptcp_ca_reset(sk);
 
        sk_sockets_allocated_inc(sk);
-       sk->sk_rcvbuf = sock_net(sk)->ipv4.sysctl_tcp_rmem[1];
-       sk->sk_sndbuf = sock_net(sk)->ipv4.sysctl_tcp_wmem[1];
+       sk->sk_rcvbuf = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_rmem[1]);
+       sk->sk_sndbuf = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_wmem[1]);
 
        return 0;
 }
@@ -2822,6 +2842,7 @@ static void __mptcp_destroy_sock(struct sock *sk)
 static void mptcp_close(struct sock *sk, long timeout)
 {
        struct mptcp_subflow_context *subflow;
+       struct mptcp_sock *msk = mptcp_sk(sk);
        bool do_cancel_work = false;
 
        lock_sock(sk);
@@ -2840,10 +2861,16 @@ static void mptcp_close(struct sock *sk, long timeout)
 cleanup:
        /* orphan all the subflows */
        inet_csk(sk)->icsk_mtup.probe_timestamp = tcp_jiffies32;
-       mptcp_for_each_subflow(mptcp_sk(sk), subflow) {
+       mptcp_for_each_subflow(msk, subflow) {
                struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
                bool slow = lock_sock_fast_nested(ssk);
 
+               /* since the close timeout takes precedence on the fail one,
+                * cancel the latter
+                */
+               if (ssk == msk->first)
+                       subflow->fail_tout = 0;
+
                sock_orphan(ssk);
                unlock_sock_fast(ssk, slow);
        }
@@ -2852,13 +2879,13 @@ cleanup:
        sock_hold(sk);
        pr_debug("msk=%p state=%d", sk, sk->sk_state);
        if (mptcp_sk(sk)->token)
-               mptcp_event(MPTCP_EVENT_CLOSED, mptcp_sk(sk), NULL, GFP_KERNEL);
+               mptcp_event(MPTCP_EVENT_CLOSED, msk, NULL, GFP_KERNEL);
 
        if (sk->sk_state == TCP_CLOSE) {
                __mptcp_destroy_sock(sk);
                do_cancel_work = true;
        } else {
-               sk_reset_timer(sk, &sk->sk_timer, jiffies + TCP_TIMEWAIT_LEN);
+               mptcp_reset_timeout(msk, 0);
        }
        release_sock(sk);
        if (do_cancel_work)
@@ -2892,12 +2919,12 @@ static void mptcp_copy_inaddrs(struct sock *msk, const struct sock *ssk)
 
 static int mptcp_disconnect(struct sock *sk, int flags)
 {
-       struct mptcp_subflow_context *subflow;
+       struct mptcp_subflow_context *subflow, *tmp;
        struct mptcp_sock *msk = mptcp_sk(sk);
 
        inet_sk_state_store(sk, TCP_CLOSE);
 
-       mptcp_for_each_subflow(msk, subflow) {
+       list_for_each_entry_safe(subflow, tmp, &msk->conn_list, node) {
                struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
 
                __mptcp_close_ssk(sk, ssk, subflow, MPTCP_CF_FASTCLOSE);
index 200f89f..480c532 100644 (file)
@@ -306,6 +306,7 @@ struct mptcp_sock {
 
        u32 setsockopt_seq;
        char            ca_name[TCP_CA_NAME_MAX];
+       struct mptcp_sock       *dl_next;
 };
 
 #define mptcp_data_lock(sk) spin_lock_bh(&(sk)->sk_lock.slock)
@@ -468,7 +469,6 @@ struct mptcp_subflow_context {
                local_id_valid : 1, /* local_id is correctly initialized */
                valid_csum_seen : 1;        /* at least one csum validated */
        enum mptcp_data_avail data_avail;
-       bool    mp_fail_response_expect;
        u32     remote_nonce;
        u64     thmac;
        u32     local_nonce;
@@ -482,6 +482,7 @@ struct mptcp_subflow_context {
        u8      stale_count;
 
        long    delegated_status;
+       unsigned long   fail_tout;
 
        );
 
@@ -606,8 +607,10 @@ void __init mptcp_subflow_init(void);
 void mptcp_subflow_shutdown(struct sock *sk, struct sock *ssk, int how);
 void mptcp_close_ssk(struct sock *sk, struct sock *ssk,
                     struct mptcp_subflow_context *subflow);
+void __mptcp_subflow_send_ack(struct sock *ssk);
 void mptcp_subflow_send_ack(struct sock *ssk);
 void mptcp_subflow_reset(struct sock *ssk);
+void mptcp_subflow_queue_clean(struct sock *ssk);
 void mptcp_sock_graft(struct sock *sk, struct socket *parent);
 struct socket *__mptcp_nmpc_socket(const struct mptcp_sock *msk);
 
@@ -662,6 +665,7 @@ void mptcp_get_options(const struct sk_buff *skb,
 
 void mptcp_finish_connect(struct sock *sk);
 void __mptcp_set_connected(struct sock *sk);
+void mptcp_reset_timeout(struct mptcp_sock *msk, unsigned long fail_tout);
 static inline bool mptcp_is_fully_established(struct sock *sk)
 {
        return inet_sk_state_load(sk) == TCP_ESTABLISHED &&
@@ -768,6 +772,10 @@ void mptcp_pm_rm_addr_received(struct mptcp_sock *msk,
                               const struct mptcp_rm_list *rm_list);
 void mptcp_pm_mp_prio_received(struct sock *sk, u8 bkup);
 void mptcp_pm_mp_fail_received(struct sock *sk, u64 fail_seq);
+int mptcp_pm_nl_mp_prio_send_ack(struct mptcp_sock *msk,
+                                struct mptcp_addr_info *addr,
+                                struct mptcp_addr_info *rem,
+                                u8 bkup);
 bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk,
                              const struct mptcp_pm_addr_entry *entry);
 void mptcp_pm_free_anno_list(struct mptcp_sock *msk);
@@ -784,7 +792,9 @@ int mptcp_pm_get_flags_and_ifindex_by_id(struct mptcp_sock *msk,
 int mptcp_userspace_pm_get_flags_and_ifindex_by_id(struct mptcp_sock *msk,
                                                   unsigned int id,
                                                   u8 *flags, int *ifindex);
-
+int mptcp_userspace_pm_set_flags(struct net *net, struct nlattr *token,
+                                struct mptcp_pm_addr_entry *loc,
+                                struct mptcp_pm_addr_entry *rem, u8 bkup);
 int mptcp_pm_announce_addr(struct mptcp_sock *msk,
                           const struct mptcp_addr_info *addr,
                           bool echo);
@@ -926,12 +936,25 @@ static inline void __mptcp_do_fallback(struct mptcp_sock *msk)
        set_bit(MPTCP_FALLBACK_DONE, &msk->flags);
 }
 
-static inline void mptcp_do_fallback(struct sock *sk)
+static inline void mptcp_do_fallback(struct sock *ssk)
 {
-       struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
-       struct mptcp_sock *msk = mptcp_sk(subflow->conn);
+       struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
+       struct sock *sk = subflow->conn;
+       struct mptcp_sock *msk;
 
+       msk = mptcp_sk(sk);
        __mptcp_do_fallback(msk);
+       if (READ_ONCE(msk->snd_data_fin_enable) && !(ssk->sk_shutdown & SEND_SHUTDOWN)) {
+               gfp_t saved_allocation = ssk->sk_allocation;
+
+               /* we are in a atomic (BH) scope, override ssk default for data
+                * fin allocation
+                */
+               ssk->sk_allocation = GFP_ATOMIC;
+               ssk->sk_shutdown |= SEND_SHUTDOWN;
+               tcp_shutdown(ssk, SEND_SHUTDOWN);
+               ssk->sk_allocation = saved_allocation;
+       }
 }
 
 #define pr_fallback(a) pr_debug("%s:fallback to TCP (msk=%p)", __func__, a)
index 8841e8c..af28f3b 100644 (file)
@@ -843,7 +843,8 @@ enum mapping_status {
        MAPPING_INVALID,
        MAPPING_EMPTY,
        MAPPING_DATA_FIN,
-       MAPPING_DUMMY
+       MAPPING_DUMMY,
+       MAPPING_BAD_CSUM
 };
 
 static void dbg_bad_map(struct mptcp_subflow_context *subflow, u32 ssn)
@@ -958,11 +959,7 @@ static enum mapping_status validate_data_csum(struct sock *ssk, struct sk_buff *
                                 subflow->map_data_csum);
        if (unlikely(csum)) {
                MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_DATACSUMERR);
-               if (subflow->mp_join || subflow->valid_csum_seen) {
-                       subflow->send_mp_fail = 1;
-                       MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_MPFAILTX);
-               }
-               return subflow->mp_join ? MAPPING_INVALID : MAPPING_DUMMY;
+               return MAPPING_BAD_CSUM;
        }
 
        subflow->valid_csum_seen = 1;
@@ -974,7 +971,6 @@ static enum mapping_status get_mapping_status(struct sock *ssk,
 {
        struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
        bool csum_reqd = READ_ONCE(msk->csum_enabled);
-       struct sock *sk = (struct sock *)msk;
        struct mptcp_ext *mpext;
        struct sk_buff *skb;
        u16 data_len;
@@ -1016,9 +1012,6 @@ static enum mapping_status get_mapping_status(struct sock *ssk,
                pr_debug("infinite mapping received");
                MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_INFINITEMAPRX);
                subflow->map_data_len = 0;
-               if (!sock_flag(ssk, SOCK_DEAD))
-                       sk_stop_timer(sk, &sk->sk_timer);
-
                return MAPPING_INVALID;
        }
 
@@ -1165,6 +1158,33 @@ static bool subflow_can_fallback(struct mptcp_subflow_context *subflow)
                return !subflow->fully_established;
 }
 
+static void mptcp_subflow_fail(struct mptcp_sock *msk, struct sock *ssk)
+{
+       struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
+       unsigned long fail_tout;
+
+       /* greceful failure can happen only on the MPC subflow */
+       if (WARN_ON_ONCE(ssk != READ_ONCE(msk->first)))
+               return;
+
+       /* since the close timeout take precedence on the fail one,
+        * no need to start the latter when the first is already set
+        */
+       if (sock_flag((struct sock *)msk, SOCK_DEAD))
+               return;
+
+       /* we don't need extreme accuracy here, use a zero fail_tout as special
+        * value meaning no fail timeout at all;
+        */
+       fail_tout = jiffies + TCP_RTO_MAX;
+       if (!fail_tout)
+               fail_tout = 1;
+       WRITE_ONCE(subflow->fail_tout, fail_tout);
+       tcp_send_ack(ssk);
+
+       mptcp_reset_timeout(msk, subflow->fail_tout);
+}
+
 static bool subflow_check_data_avail(struct sock *ssk)
 {
        struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
@@ -1184,10 +1204,8 @@ static bool subflow_check_data_avail(struct sock *ssk)
 
                status = get_mapping_status(ssk, msk);
                trace_subflow_check_data_avail(status, skb_peek(&ssk->sk_receive_queue));
-               if (unlikely(status == MAPPING_INVALID))
-                       goto fallback;
-
-               if (unlikely(status == MAPPING_DUMMY))
+               if (unlikely(status == MAPPING_INVALID || status == MAPPING_DUMMY ||
+                            status == MAPPING_BAD_CSUM))
                        goto fallback;
 
                if (status != MAPPING_OK)
@@ -1229,22 +1247,17 @@ no_data:
 fallback:
        if (!__mptcp_check_fallback(msk)) {
                /* RFC 8684 section 3.7. */
-               if (subflow->send_mp_fail) {
+               if (status == MAPPING_BAD_CSUM &&
+                   (subflow->mp_join || subflow->valid_csum_seen)) {
+                       subflow->send_mp_fail = 1;
+
                        if (!READ_ONCE(msk->allow_infinite_fallback)) {
-                               ssk->sk_err = EBADMSG;
-                               tcp_set_state(ssk, TCP_CLOSE);
                                subflow->reset_transient = 0;
                                subflow->reset_reason = MPTCP_RST_EMIDDLEBOX;
-                               tcp_send_active_reset(ssk, GFP_ATOMIC);
-                               while ((skb = skb_peek(&ssk->sk_receive_queue)))
-                                       sk_eat_skb(ssk, skb);
-                       } else if (!sock_flag(ssk, SOCK_DEAD)) {
-                               WRITE_ONCE(subflow->mp_fail_response_expect, true);
-                               sk_reset_timer((struct sock *)msk,
-                                              &((struct sock *)msk)->sk_timer,
-                                              jiffies + TCP_RTO_MAX);
+                               goto reset;
                        }
-                       WRITE_ONCE(subflow->data_avail, MPTCP_SUBFLOW_NODATA);
+                       mptcp_subflow_fail(msk, ssk);
+                       WRITE_ONCE(subflow->data_avail, MPTCP_SUBFLOW_DATA_AVAIL);
                        return true;
                }
 
@@ -1252,16 +1265,20 @@ fallback:
                        /* fatal protocol error, close the socket.
                         * subflow_error_report() will introduce the appropriate barriers
                         */
-                       ssk->sk_err = EBADMSG;
-                       tcp_set_state(ssk, TCP_CLOSE);
                        subflow->reset_transient = 0;
                        subflow->reset_reason = MPTCP_RST_EMPTCP;
+
+reset:
+                       ssk->sk_err = EBADMSG;
+                       tcp_set_state(ssk, TCP_CLOSE);
+                       while ((skb = skb_peek(&ssk->sk_receive_queue)))
+                               sk_eat_skb(ssk, skb);
                        tcp_send_active_reset(ssk, GFP_ATOMIC);
                        WRITE_ONCE(subflow->data_avail, MPTCP_SUBFLOW_NODATA);
                        return false;
                }
 
-               __mptcp_do_fallback(msk);
+               mptcp_do_fallback(ssk);
        }
 
        skb = skb_peek(&ssk->sk_receive_queue);
@@ -1516,7 +1533,7 @@ int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_addr_info *loc,
        mptcp_sock_graft(ssk, sk->sk_socket);
        iput(SOCK_INODE(sf));
        WRITE_ONCE(msk->allow_infinite_fallback, false);
-       return err;
+       return 0;
 
 failed_unlink:
        list_del(&subflow->node);
@@ -1706,6 +1723,58 @@ static void subflow_state_change(struct sock *sk)
        }
 }
 
+void mptcp_subflow_queue_clean(struct sock *listener_ssk)
+{
+       struct request_sock_queue *queue = &inet_csk(listener_ssk)->icsk_accept_queue;
+       struct mptcp_sock *msk, *next, *head = NULL;
+       struct request_sock *req;
+
+       /* build a list of all unaccepted mptcp sockets */
+       spin_lock_bh(&queue->rskq_lock);
+       for (req = queue->rskq_accept_head; req; req = req->dl_next) {
+               struct mptcp_subflow_context *subflow;
+               struct sock *ssk = req->sk;
+               struct mptcp_sock *msk;
+
+               if (!sk_is_mptcp(ssk))
+                       continue;
+
+               subflow = mptcp_subflow_ctx(ssk);
+               if (!subflow || !subflow->conn)
+                       continue;
+
+               /* skip if already in list */
+               msk = mptcp_sk(subflow->conn);
+               if (msk->dl_next || msk == head)
+                       continue;
+
+               msk->dl_next = head;
+               head = msk;
+       }
+       spin_unlock_bh(&queue->rskq_lock);
+       if (!head)
+               return;
+
+       /* can't acquire the msk socket lock under the subflow one,
+        * or will cause ABBA deadlock
+        */
+       release_sock(listener_ssk);
+
+       for (msk = head; msk; msk = next) {
+               struct sock *sk = (struct sock *)msk;
+               bool slow;
+
+               slow = lock_sock_fast_nested(sk);
+               next = msk->dl_next;
+               msk->first = NULL;
+               msk->dl_next = NULL;
+               unlock_sock_fast(sk, slow);
+       }
+
+       /* we are still under the listener msk socket lock */
+       lock_sock_nested(listener_ssk, SINGLE_DEPTH_NESTING);
+}
+
 static int subflow_ulp_init(struct sock *sk)
 {
        struct inet_connection_sock *icsk = inet_csk(sk);
index 7881441..80713fe 100644 (file)
@@ -1803,7 +1803,8 @@ struct ncsi_dev *ncsi_register_dev(struct net_device *dev,
        pdev = to_platform_device(dev->dev.parent);
        if (pdev) {
                np = pdev->dev.of_node;
-               if (np && of_get_property(np, "mlx,multi-host", NULL))
+               if (np && (of_get_property(np, "mellanox,multi-host", NULL) ||
+                          of_get_property(np, "mlx,multi-host", NULL)))
                        ndp->mlx_multi_host = true;
        }
 
index 082a2fd..369aeab 100644 (file)
@@ -729,6 +729,9 @@ static void nf_ct_gc_expired(struct nf_conn *ct)
        if (!refcount_inc_not_zero(&ct->ct_general.use))
                return;
 
+       /* load ->status after refcount increase */
+       smp_acquire__after_ctrl_dep();
+
        if (nf_ct_should_gc(ct))
                nf_ct_kill(ct);
 
@@ -795,6 +798,9 @@ __nf_conntrack_find_get(struct net *net, const struct nf_conntrack_zone *zone,
                 */
                ct = nf_ct_tuplehash_to_ctrack(h);
                if (likely(refcount_inc_not_zero(&ct->ct_general.use))) {
+                       /* re-check key after refcount */
+                       smp_acquire__after_ctrl_dep();
+
                        if (likely(nf_ct_key_equal(h, tuple, zone, net)))
                                goto found;
 
@@ -1387,6 +1393,9 @@ static unsigned int early_drop_list(struct net *net,
                if (!refcount_inc_not_zero(&tmp->ct_general.use))
                        continue;
 
+               /* load ->ct_net and ->status after refcount increase */
+               smp_acquire__after_ctrl_dep();
+
                /* kill only if still in same netns -- might have moved due to
                 * SLAB_TYPESAFE_BY_RCU rules.
                 *
@@ -1536,6 +1545,9 @@ static void gc_worker(struct work_struct *work)
                        if (!refcount_inc_not_zero(&tmp->ct_general.use))
                                continue;
 
+                       /* load ->status after refcount increase */
+                       smp_acquire__after_ctrl_dep();
+
                        if (gc_worker_skip_ct(tmp)) {
                                nf_ct_put(tmp);
                                continue;
@@ -1775,6 +1787,16 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
        if (!exp)
                __nf_ct_try_assign_helper(ct, tmpl, GFP_ATOMIC);
 
+       /* Other CPU might have obtained a pointer to this object before it was
+        * released.  Because refcount is 0, refcount_inc_not_zero() will fail.
+        *
+        * After refcount_set(1) it will succeed; ensure that zeroing of
+        * ct->status and the correct ct->net pointer are visible; else other
+        * core might observe CONFIRMED bit which means the entry is valid and
+        * in the hash table, but its not (anymore).
+        */
+       smp_wmb();
+
        /* Now it is going to be associated with an sk_buff, set refcount to 1. */
        refcount_set(&ct->ct_general.use, 1);
 
index 722af5e..f5905b5 100644 (file)
@@ -1203,6 +1203,7 @@ restart:
                                           hnnode) {
                        ct = nf_ct_tuplehash_to_ctrack(h);
                        if (nf_ct_is_expired(ct)) {
+                               /* need to defer nf_ct_kill() until lock is released */
                                if (i < ARRAY_SIZE(nf_ct_evict) &&
                                    refcount_inc_not_zero(&ct->ct_general.use))
                                        nf_ct_evict[i++] = ct;
index 6ad7bbc..0589587 100644 (file)
@@ -306,6 +306,9 @@ static int ct_seq_show(struct seq_file *s, void *v)
        if (unlikely(!refcount_inc_not_zero(&ct->ct_general.use)))
                return 0;
 
+       /* load ->status after refcount increase */
+       smp_acquire__after_ctrl_dep();
+
        if (nf_ct_should_gc(ct)) {
                nf_ct_kill(ct);
                goto release;
index 77bcb10..cb894f0 100644 (file)
@@ -67,7 +67,7 @@ dump_arp_packet(struct nf_log_buf *m,
        unsigned int logflags;
        struct arphdr _arph;
 
-       ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
+       ah = skb_header_pointer(skb, nhoff, sizeof(_arph), &_arph);
        if (!ah) {
                nf_log_buf_add(m, "TRUNCATED");
                return;
@@ -96,7 +96,7 @@ dump_arp_packet(struct nf_log_buf *m,
            ah->ar_pln != sizeof(__be32))
                return;
 
-       ap = skb_header_pointer(skb, sizeof(_arph), sizeof(_arpp), &_arpp);
+       ap = skb_header_pointer(skb, nhoff + sizeof(_arph), sizeof(_arpp), &_arpp);
        if (!ap) {
                nf_log_buf_add(m, " INCOMPLETE [%zu bytes]",
                               skb->len - sizeof(_arph));
@@ -149,7 +149,7 @@ static void nf_log_arp_packet(struct net *net, u_int8_t pf,
 
        nf_log_dump_packet_common(m, pf, hooknum, skb, in, out, loginfo,
                                  prefix);
-       dump_arp_packet(m, loginfo, skb, 0);
+       dump_arp_packet(m, loginfo, skb, skb_network_offset(skb));
 
        nf_log_buf_close(m);
 }
@@ -850,7 +850,7 @@ static void nf_log_ip_packet(struct net *net, u_int8_t pf,
        if (in)
                dump_mac_header(m, loginfo, skb);
 
-       dump_ipv4_packet(net, m, loginfo, skb, 0);
+       dump_ipv4_packet(net, m, loginfo, skb, skb_network_offset(skb));
 
        nf_log_buf_close(m);
 }
index e479dd0..16915f8 100644 (file)
@@ -405,7 +405,7 @@ synproxy_build_ip(struct net *net, struct sk_buff *skb, __be32 saddr,
        iph->tos        = 0;
        iph->id         = 0;
        iph->frag_off   = htons(IP_DF);
-       iph->ttl        = net->ipv4.sysctl_ip_default_ttl;
+       iph->ttl        = READ_ONCE(net->ipv4.sysctl_ip_default_ttl);
        iph->protocol   = IPPROTO_TCP;
        iph->check      = 0;
        iph->saddr      = saddr;
index 51144fc..9f976b1 100644 (file)
@@ -3340,6 +3340,8 @@ int nft_chain_validate(const struct nft_ctx *ctx, const struct nft_chain *chain)
                        if (err < 0)
                                return err;
                }
+
+               cond_resched();
        }
 
        return 0;
@@ -5213,13 +5215,20 @@ static int nft_setelem_parse_data(struct nft_ctx *ctx, struct nft_set *set,
                                  struct nft_data *data,
                                  struct nlattr *attr)
 {
+       u32 dtype;
        int err;
 
        err = nft_data_init(ctx, data, NFT_DATA_VALUE_MAXLEN, desc, attr);
        if (err < 0)
                return err;
 
-       if (desc->type != NFT_DATA_VERDICT && desc->len != set->dlen) {
+       if (set->dtype == NFT_DATA_VERDICT)
+               dtype = NFT_DATA_VERDICT;
+       else
+               dtype = NFT_DATA_VALUE;
+
+       if (dtype != desc->type ||
+           set->dlen != desc->len) {
                nft_data_release(data, desc->type);
                return -EINVAL;
        }
@@ -5826,8 +5835,11 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
        if (!nla[NFTA_SET_ELEM_KEY] && !(flags & NFT_SET_ELEM_CATCHALL))
                return -EINVAL;
 
-       if (flags != 0)
-               nft_set_ext_add(&tmpl, NFT_SET_EXT_FLAGS);
+       if (flags != 0) {
+               err = nft_set_ext_add(&tmpl, NFT_SET_EXT_FLAGS);
+               if (err < 0)
+                       return err;
+       }
 
        if (set->flags & NFT_SET_MAP) {
                if (nla[NFTA_SET_ELEM_DATA] == NULL &&
@@ -5936,7 +5948,9 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
                if (err < 0)
                        goto err_set_elem_expr;
 
-               nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);
+               err = nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);
+               if (err < 0)
+                       goto err_parse_key;
        }
 
        if (nla[NFTA_SET_ELEM_KEY_END]) {
@@ -5945,22 +5959,31 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
                if (err < 0)
                        goto err_parse_key;
 
-               nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY_END, set->klen);
+               err = nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY_END, set->klen);
+               if (err < 0)
+                       goto err_parse_key_end;
        }
 
        if (timeout > 0) {
-               nft_set_ext_add(&tmpl, NFT_SET_EXT_EXPIRATION);
-               if (timeout != set->timeout)
-                       nft_set_ext_add(&tmpl, NFT_SET_EXT_TIMEOUT);
+               err = nft_set_ext_add(&tmpl, NFT_SET_EXT_EXPIRATION);
+               if (err < 0)
+                       goto err_parse_key_end;
+
+               if (timeout != set->timeout) {
+                       err = nft_set_ext_add(&tmpl, NFT_SET_EXT_TIMEOUT);
+                       if (err < 0)
+                               goto err_parse_key_end;
+               }
        }
 
        if (num_exprs) {
                for (i = 0; i < num_exprs; i++)
                        size += expr_array[i]->ops->size;
 
-               nft_set_ext_add_length(&tmpl, NFT_SET_EXT_EXPRESSIONS,
-                                      sizeof(struct nft_set_elem_expr) +
-                                      size);
+               err = nft_set_ext_add_length(&tmpl, NFT_SET_EXT_EXPRESSIONS,
+                                            sizeof(struct nft_set_elem_expr) + size);
+               if (err < 0)
+                       goto err_parse_key_end;
        }
 
        if (nla[NFTA_SET_ELEM_OBJREF] != NULL) {
@@ -5975,7 +5998,9 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
                        err = PTR_ERR(obj);
                        goto err_parse_key_end;
                }
-               nft_set_ext_add(&tmpl, NFT_SET_EXT_OBJREF);
+               err = nft_set_ext_add(&tmpl, NFT_SET_EXT_OBJREF);
+               if (err < 0)
+                       goto err_parse_key_end;
        }
 
        if (nla[NFTA_SET_ELEM_DATA] != NULL) {
@@ -6009,7 +6034,9 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
                                                          NFT_VALIDATE_NEED);
                }
 
-               nft_set_ext_add_length(&tmpl, NFT_SET_EXT_DATA, desc.len);
+               err = nft_set_ext_add_length(&tmpl, NFT_SET_EXT_DATA, desc.len);
+               if (err < 0)
+                       goto err_parse_data;
        }
 
        /* The full maximum length of userdata can exceed the maximum
@@ -6019,9 +6046,12 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
        ulen = 0;
        if (nla[NFTA_SET_ELEM_USERDATA] != NULL) {
                ulen = nla_len(nla[NFTA_SET_ELEM_USERDATA]);
-               if (ulen > 0)
-                       nft_set_ext_add_length(&tmpl, NFT_SET_EXT_USERDATA,
-                                              ulen);
+               if (ulen > 0) {
+                       err = nft_set_ext_add_length(&tmpl, NFT_SET_EXT_USERDATA,
+                                                    ulen);
+                       if (err < 0)
+                               goto err_parse_data;
+               }
        }
 
        err = -ENOMEM;
@@ -6249,8 +6279,11 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
 
        nft_set_ext_prepare(&tmpl);
 
-       if (flags != 0)
-               nft_set_ext_add(&tmpl, NFT_SET_EXT_FLAGS);
+       if (flags != 0) {
+               err = nft_set_ext_add(&tmpl, NFT_SET_EXT_FLAGS);
+               if (err < 0)
+                       return err;
+       }
 
        if (nla[NFTA_SET_ELEM_KEY]) {
                err = nft_setelem_parse_key(ctx, set, &elem.key.val,
@@ -6258,16 +6291,20 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
                if (err < 0)
                        return err;
 
-               nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);
+               err = nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);
+               if (err < 0)
+                       goto fail_elem;
        }
 
        if (nla[NFTA_SET_ELEM_KEY_END]) {
                err = nft_setelem_parse_key(ctx, set, &elem.key_end.val,
                                            nla[NFTA_SET_ELEM_KEY_END]);
                if (err < 0)
-                       return err;
+                       goto fail_elem;
 
-               nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY_END, set->klen);
+               err = nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY_END, set->klen);
+               if (err < 0)
+                       goto fail_elem_key_end;
        }
 
        err = -ENOMEM;
@@ -6275,7 +6312,7 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
                                      elem.key_end.val.data, NULL, 0, 0,
                                      GFP_KERNEL_ACCOUNT);
        if (elem.priv == NULL)
-               goto fail_elem;
+               goto fail_elem_key_end;
 
        ext = nft_set_elem_ext(set, elem.priv);
        if (flags)
@@ -6299,6 +6336,8 @@ fail_ops:
        kfree(trans);
 fail_trans:
        kfree(elem.priv);
+fail_elem_key_end:
+       nft_data_release(&elem.key_end.val, NFT_DATA_VALUE);
 fail_elem:
        nft_data_release(&elem.key.val, NFT_DATA_VALUE);
        return err;
@@ -9330,9 +9369,13 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx,
                                break;
                        }
                }
+
+               cond_resched();
        }
 
        list_for_each_entry(set, &ctx->table->sets, list) {
+               cond_resched();
+
                if (!nft_is_active_next(ctx->net, set))
                        continue;
                if (!(set->flags & NFT_SET_MAP) ||
index 53f40e4..3ddce24 100644 (file)
@@ -25,9 +25,7 @@ static noinline void __nft_trace_packet(struct nft_traceinfo *info,
                                        const struct nft_chain *chain,
                                        enum nft_trace_types type)
 {
-       const struct nft_pktinfo *pkt = info->pkt;
-
-       if (!info->trace || !pkt->skb->nf_trace)
+       if (!info->trace || !info->nf_trace)
                return;
 
        info->chain = chain;
@@ -42,11 +40,24 @@ static inline void nft_trace_packet(struct nft_traceinfo *info,
                                    enum nft_trace_types type)
 {
        if (static_branch_unlikely(&nft_trace_enabled)) {
+               const struct nft_pktinfo *pkt = info->pkt;
+
+               info->nf_trace = pkt->skb->nf_trace;
                info->rule = rule;
                __nft_trace_packet(info, chain, type);
        }
 }
 
+static inline void nft_trace_copy_nftrace(struct nft_traceinfo *info)
+{
+       if (static_branch_unlikely(&nft_trace_enabled)) {
+               const struct nft_pktinfo *pkt = info->pkt;
+
+               if (info->trace)
+                       info->nf_trace = pkt->skb->nf_trace;
+       }
+}
+
 static void nft_bitwise_fast_eval(const struct nft_expr *expr,
                                  struct nft_regs *regs)
 {
@@ -85,6 +96,7 @@ static noinline void __nft_trace_verdict(struct nft_traceinfo *info,
                                         const struct nft_chain *chain,
                                         const struct nft_regs *regs)
 {
+       const struct nft_pktinfo *pkt = info->pkt;
        enum nft_trace_types type;
 
        switch (regs->verdict.code) {
@@ -92,8 +104,13 @@ static noinline void __nft_trace_verdict(struct nft_traceinfo *info,
        case NFT_RETURN:
                type = NFT_TRACETYPE_RETURN;
                break;
+       case NF_STOLEN:
+               type = NFT_TRACETYPE_RULE;
+               /* can't access skb->nf_trace; use copy */
+               break;
        default:
                type = NFT_TRACETYPE_RULE;
+               info->nf_trace = pkt->skb->nf_trace;
                break;
        }
 
@@ -254,6 +271,7 @@ next_rule:
                switch (regs.verdict.code) {
                case NFT_BREAK:
                        regs.verdict.code = NFT_CONTINUE;
+                       nft_trace_copy_nftrace(&info);
                        continue;
                case NFT_CONTINUE:
                        nft_trace_packet(&info, chain, rule,
index 5041725..1163ba9 100644 (file)
@@ -7,7 +7,7 @@
 #include <linux/module.h>
 #include <linux/static_key.h>
 #include <linux/hash.h>
-#include <linux/jhash.h>
+#include <linux/siphash.h>
 #include <linux/if_vlan.h>
 #include <linux/init.h>
 #include <linux/skbuff.h>
 DEFINE_STATIC_KEY_FALSE(nft_trace_enabled);
 EXPORT_SYMBOL_GPL(nft_trace_enabled);
 
-static int trace_fill_id(struct sk_buff *nlskb, struct sk_buff *skb)
-{
-       __be32 id;
-
-       /* using skb address as ID results in a limited number of
-        * values (and quick reuse).
-        *
-        * So we attempt to use as many skb members that will not
-        * change while skb is with netfilter.
-        */
-       id = (__be32)jhash_2words(hash32_ptr(skb), skb_get_hash(skb),
-                                 skb->skb_iif);
-
-       return nla_put_be32(nlskb, NFTA_TRACE_ID, id);
-}
-
 static int trace_fill_header(struct sk_buff *nlskb, u16 type,
                             const struct sk_buff *skb,
                             int off, unsigned int len)
@@ -186,6 +170,7 @@ void nft_trace_notify(struct nft_traceinfo *info)
        struct nlmsghdr *nlh;
        struct sk_buff *skb;
        unsigned int size;
+       u32 mark = 0;
        u16 event;
 
        if (!nfnetlink_has_listeners(nft_net(pkt), NFNLGRP_NFTRACE))
@@ -229,7 +214,7 @@ void nft_trace_notify(struct nft_traceinfo *info)
        if (nla_put_be32(skb, NFTA_TRACE_TYPE, htonl(info->type)))
                goto nla_put_failure;
 
-       if (trace_fill_id(skb, pkt->skb))
+       if (nla_put_u32(skb, NFTA_TRACE_ID, info->skbid))
                goto nla_put_failure;
 
        if (nla_put_string(skb, NFTA_TRACE_CHAIN, info->chain->name))
@@ -249,16 +234,24 @@ void nft_trace_notify(struct nft_traceinfo *info)
        case NFT_TRACETYPE_RULE:
                if (nft_verdict_dump(skb, NFTA_TRACE_VERDICT, info->verdict))
                        goto nla_put_failure;
+
+               /* pkt->skb undefined iff NF_STOLEN, disable dump */
+               if (info->verdict->code == NF_STOLEN)
+                       info->packet_dumped = true;
+               else
+                       mark = pkt->skb->mark;
+
                break;
        case NFT_TRACETYPE_POLICY:
+               mark = pkt->skb->mark;
+
                if (nla_put_be32(skb, NFTA_TRACE_POLICY,
                                 htonl(info->basechain->policy)))
                        goto nla_put_failure;
                break;
        }
 
-       if (pkt->skb->mark &&
-           nla_put_be32(skb, NFTA_TRACE_MARK, htonl(pkt->skb->mark)))
+       if (mark && nla_put_be32(skb, NFTA_TRACE_MARK, htonl(mark)))
                goto nla_put_failure;
 
        if (!info->packet_dumped) {
@@ -283,9 +276,20 @@ void nft_trace_init(struct nft_traceinfo *info, const struct nft_pktinfo *pkt,
                    const struct nft_verdict *verdict,
                    const struct nft_chain *chain)
 {
+       static siphash_key_t trace_key __read_mostly;
+       struct sk_buff *skb = pkt->skb;
+
        info->basechain = nft_base_chain(chain);
        info->trace = true;
+       info->nf_trace = pkt->skb->nf_trace;
        info->packet_dumped = false;
        info->pkt = pkt;
        info->verdict = verdict;
+
+       net_get_random_once(&trace_key, sizeof(trace_key));
+
+       info->skbid = (u32)siphash_3u32(hash32_ptr(skb),
+                                       skb_get_hash(skb),
+                                       skb->skb_iif,
+                                       &trace_key);
 }
index a364f8e..87a9009 100644 (file)
@@ -843,11 +843,16 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
 }
 
 static int
-nfqnl_mangle(void *data, int data_len, struct nf_queue_entry *e, int diff)
+nfqnl_mangle(void *data, unsigned int data_len, struct nf_queue_entry *e, int diff)
 {
        struct sk_buff *nskb;
 
        if (diff < 0) {
+               unsigned int min_len = skb_transport_offset(e->skb);
+
+               if (data_len < min_len)
+                       return -EINVAL;
+
                if (pskb_trim(e->skb, data_len))
                        return -ENOMEM;
        } else if (diff > 0) {
index 15e4b76..da29e92 100644 (file)
@@ -68,6 +68,31 @@ static void nft_queue_sreg_eval(const struct nft_expr *expr,
        regs->verdict.code = ret;
 }
 
+static int nft_queue_validate(const struct nft_ctx *ctx,
+                             const struct nft_expr *expr,
+                             const struct nft_data **data)
+{
+       static const unsigned int supported_hooks = ((1 << NF_INET_PRE_ROUTING) |
+                                                    (1 << NF_INET_LOCAL_IN) |
+                                                    (1 << NF_INET_FORWARD) |
+                                                    (1 << NF_INET_LOCAL_OUT) |
+                                                    (1 << NF_INET_POST_ROUTING));
+
+       switch (ctx->family) {
+       case NFPROTO_IPV4:
+       case NFPROTO_IPV6:
+       case NFPROTO_INET:
+       case NFPROTO_BRIDGE:
+               break;
+       case NFPROTO_NETDEV: /* lacks okfn */
+               fallthrough;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return nft_chain_validate_hooks(ctx->chain, supported_hooks);
+}
+
 static const struct nla_policy nft_queue_policy[NFTA_QUEUE_MAX + 1] = {
        [NFTA_QUEUE_NUM]        = { .type = NLA_U16 },
        [NFTA_QUEUE_TOTAL]      = { .type = NLA_U16 },
@@ -164,6 +189,7 @@ static const struct nft_expr_ops nft_queue_ops = {
        .eval           = nft_queue_eval,
        .init           = nft_queue_init,
        .dump           = nft_queue_dump,
+       .validate       = nft_queue_validate,
        .reduce         = NFT_REDUCE_READONLY,
 };
 
@@ -173,6 +199,7 @@ static const struct nft_expr_ops nft_queue_sreg_ops = {
        .eval           = nft_queue_sreg_eval,
        .init           = nft_queue_sreg_init,
        .dump           = nft_queue_sreg_dump,
+       .validate       = nft_queue_validate,
        .reduce         = NFT_REDUCE_READONLY,
 };
 
index df40314..76de6c8 100644 (file)
@@ -143,6 +143,7 @@ static bool nft_rhash_update(struct nft_set *set, const u32 *key,
        /* Another cpu may race to insert the element with the same key */
        if (prev) {
                nft_set_elem_destroy(set, he, true);
+               atomic_dec(&set->nelems);
                he = prev;
        }
 
@@ -152,6 +153,7 @@ out:
 
 err2:
        nft_set_elem_destroy(set, he, true);
+       atomic_dec(&set->nelems);
 err1:
        return false;
 }
index 2c8051d..4f9299b 100644 (file)
@@ -2125,6 +2125,32 @@ out_scratch:
 }
 
 /**
+ * nft_set_pipapo_match_destroy() - Destroy elements from key mapping array
+ * @set:       nftables API set representation
+ * @m:         matching data pointing to key mapping array
+ */
+static void nft_set_pipapo_match_destroy(const struct nft_set *set,
+                                        struct nft_pipapo_match *m)
+{
+       struct nft_pipapo_field *f;
+       int i, r;
+
+       for (i = 0, f = m->f; i < m->field_count - 1; i++, f++)
+               ;
+
+       for (r = 0; r < f->rules; r++) {
+               struct nft_pipapo_elem *e;
+
+               if (r < f->rules - 1 && f->mt[r + 1].e == f->mt[r].e)
+                       continue;
+
+               e = f->mt[r].e;
+
+               nft_set_elem_destroy(set, e, true);
+       }
+}
+
+/**
  * nft_pipapo_destroy() - Free private data for set and all committed elements
  * @set:       nftables API set representation
  */
@@ -2132,26 +2158,13 @@ static void nft_pipapo_destroy(const struct nft_set *set)
 {
        struct nft_pipapo *priv = nft_set_priv(set);
        struct nft_pipapo_match *m;
-       struct nft_pipapo_field *f;
-       int i, r, cpu;
+       int cpu;
 
        m = rcu_dereference_protected(priv->match, true);
        if (m) {
                rcu_barrier();
 
-               for (i = 0, f = m->f; i < m->field_count - 1; i++, f++)
-                       ;
-
-               for (r = 0; r < f->rules; r++) {
-                       struct nft_pipapo_elem *e;
-
-                       if (r < f->rules - 1 && f->mt[r + 1].e == f->mt[r].e)
-                               continue;
-
-                       e = f->mt[r].e;
-
-                       nft_set_elem_destroy(set, e, true);
-               }
+               nft_set_pipapo_match_destroy(set, m);
 
 #ifdef NFT_PIPAPO_ALIGN
                free_percpu(m->scratch_aligned);
@@ -2165,6 +2178,11 @@ static void nft_pipapo_destroy(const struct nft_set *set)
        }
 
        if (priv->clone) {
+               m = priv->clone;
+
+               if (priv->dirty)
+                       nft_set_pipapo_match_destroy(set, m);
+
 #ifdef NFT_PIPAPO_ALIGN
                free_percpu(priv->clone->scratch_aligned);
 #endif
index fee6409..eb0b819 100644 (file)
@@ -227,8 +227,8 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
 {
        struct rose_neigh *s;
 
-       rose_stop_ftimer(rose_neigh);
-       rose_stop_t0timer(rose_neigh);
+       del_timer_sync(&rose_neigh->ftimer);
+       del_timer_sync(&rose_neigh->t0timer);
 
        skb_queue_purge(&rose_neigh->queue);
 
index b3138fc..f06ddbe 100644 (file)
@@ -31,89 +31,89 @@ static void rose_idletimer_expiry(struct timer_list *);
 
 void rose_start_heartbeat(struct sock *sk)
 {
-       del_timer(&sk->sk_timer);
+       sk_stop_timer(sk, &sk->sk_timer);
 
        sk->sk_timer.function = rose_heartbeat_expiry;
        sk->sk_timer.expires  = jiffies + 5 * HZ;
 
-       add_timer(&sk->sk_timer);
+       sk_reset_timer(sk, &sk->sk_timer, sk->sk_timer.expires);
 }
 
 void rose_start_t1timer(struct sock *sk)
 {
        struct rose_sock *rose = rose_sk(sk);
 
-       del_timer(&rose->timer);
+       sk_stop_timer(sk, &rose->timer);
 
        rose->timer.function = rose_timer_expiry;
        rose->timer.expires  = jiffies + rose->t1;
 
-       add_timer(&rose->timer);
+       sk_reset_timer(sk, &rose->timer, rose->timer.expires);
 }
 
 void rose_start_t2timer(struct sock *sk)
 {
        struct rose_sock *rose = rose_sk(sk);
 
-       del_timer(&rose->timer);
+       sk_stop_timer(sk, &rose->timer);
 
        rose->timer.function = rose_timer_expiry;
        rose->timer.expires  = jiffies + rose->t2;
 
-       add_timer(&rose->timer);
+       sk_reset_timer(sk, &rose->timer, rose->timer.expires);
 }
 
 void rose_start_t3timer(struct sock *sk)
 {
        struct rose_sock *rose = rose_sk(sk);
 
-       del_timer(&rose->timer);
+       sk_stop_timer(sk, &rose->timer);
 
        rose->timer.function = rose_timer_expiry;
        rose->timer.expires  = jiffies + rose->t3;
 
-       add_timer(&rose->timer);
+       sk_reset_timer(sk, &rose->timer, rose->timer.expires);
 }
 
 void rose_start_hbtimer(struct sock *sk)
 {
        struct rose_sock *rose = rose_sk(sk);
 
-       del_timer(&rose->timer);
+       sk_stop_timer(sk, &rose->timer);
 
        rose->timer.function = rose_timer_expiry;
        rose->timer.expires  = jiffies + rose->hb;
 
-       add_timer(&rose->timer);
+       sk_reset_timer(sk, &rose->timer, rose->timer.expires);
 }
 
 void rose_start_idletimer(struct sock *sk)
 {
        struct rose_sock *rose = rose_sk(sk);
 
-       del_timer(&rose->idletimer);
+       sk_stop_timer(sk, &rose->idletimer);
 
        if (rose->idle > 0) {
                rose->idletimer.function = rose_idletimer_expiry;
                rose->idletimer.expires  = jiffies + rose->idle;
 
-               add_timer(&rose->idletimer);
+               sk_reset_timer(sk, &rose->idletimer, rose->idletimer.expires);
        }
 }
 
 void rose_stop_heartbeat(struct sock *sk)
 {
-       del_timer(&sk->sk_timer);
+       sk_stop_timer(sk, &sk->sk_timer);
 }
 
 void rose_stop_timer(struct sock *sk)
 {
-       del_timer(&rose_sk(sk)->timer);
+       sk_stop_timer(sk, &rose_sk(sk)->timer);
 }
 
 void rose_stop_idletimer(struct sock *sk)
 {
-       del_timer(&rose_sk(sk)->idletimer);
+       sk_stop_timer(sk, &rose_sk(sk)->idletimer);
 }
 
 static void rose_heartbeat_expiry(struct timer_list *t)
@@ -130,6 +130,7 @@ static void rose_heartbeat_expiry(struct timer_list *t)
                    (sk->sk_state == TCP_LISTEN && sock_flag(sk, SOCK_DEAD))) {
                        bh_unlock_sock(sk);
                        rose_destroy_socket(sk);
+                       sock_put(sk);
                        return;
                }
                break;
@@ -152,6 +153,7 @@ static void rose_heartbeat_expiry(struct timer_list *t)
 
        rose_start_heartbeat(sk);
        bh_unlock_sock(sk);
+       sock_put(sk);
 }
 
 static void rose_timer_expiry(struct timer_list *t)
@@ -181,6 +183,7 @@ static void rose_timer_expiry(struct timer_list *t)
                break;
        }
        bh_unlock_sock(sk);
+       sock_put(sk);
 }
 
 static void rose_idletimer_expiry(struct timer_list *t)
@@ -205,4 +208,5 @@ static void rose_idletimer_expiry(struct timer_list *t)
                sock_set_flag(sk, SOCK_DEAD);
        }
        bh_unlock_sock(sk);
+       sock_put(sk);
 }
index da9733d..817065a 100644 (file)
@@ -588,7 +588,8 @@ static int tcf_idr_release_unsafe(struct tc_action *p)
 }
 
 static int tcf_del_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb,
-                         const struct tc_action_ops *ops)
+                         const struct tc_action_ops *ops,
+                         struct netlink_ext_ack *extack)
 {
        struct nlattr *nest;
        int n_i = 0;
@@ -604,20 +605,25 @@ static int tcf_del_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb,
        if (nla_put_string(skb, TCA_KIND, ops->kind))
                goto nla_put_failure;
 
+       ret = 0;
        mutex_lock(&idrinfo->lock);
        idr_for_each_entry_ul(idr, p, tmp, id) {
                if (IS_ERR(p))
                        continue;
                ret = tcf_idr_release_unsafe(p);
-               if (ret == ACT_P_DELETED) {
+               if (ret == ACT_P_DELETED)
                        module_put(ops->owner);
-                       n_i++;
-               } else if (ret < 0) {
-                       mutex_unlock(&idrinfo->lock);
-                       goto nla_put_failure;
-               }
+               else if (ret < 0)
+                       break;
+               n_i++;
        }
        mutex_unlock(&idrinfo->lock);
+       if (ret < 0) {
+               if (n_i)
+                       NL_SET_ERR_MSG(extack, "Unable to flush all TC actions");
+               else
+                       goto nla_put_failure;
+       }
 
        ret = nla_put_u32(skb, TCA_FCNT, n_i);
        if (ret)
@@ -638,7 +644,7 @@ int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
        struct tcf_idrinfo *idrinfo = tn->idrinfo;
 
        if (type == RTM_DELACTION) {
-               return tcf_del_walker(idrinfo, skb, ops);
+               return tcf_del_walker(idrinfo, skb, ops, extack);
        } else if (type == RTM_GETACTION) {
                return tcf_dump_walker(idrinfo, skb, cb);
        } else {
index 79c8901..b759628 100644 (file)
@@ -442,7 +442,7 @@ static int tcf_police_act_to_flow_act(int tc_act, u32 *extval,
                act_id = FLOW_ACTION_JUMP;
                *extval = tc_act & TC_ACT_EXT_VAL_MASK;
        } else if (tc_act == TC_ACT_UNSPEC) {
-               NL_SET_ERR_MSG_MOD(extack, "Offload not supported when conform/exceed action is \"continue\"");
+               act_id = FLOW_ACTION_CONTINUE;
        } else {
                NL_SET_ERR_MSG_MOD(extack, "Unsupported conform/exceed action offload");
        }
index 9bb4d3d..ac366c9 100644 (file)
@@ -3533,7 +3533,7 @@ int tc_setup_action(struct flow_action *flow_action,
                    struct tc_action *actions[],
                    struct netlink_ext_ack *extack)
 {
-       int i, j, index, err = 0;
+       int i, j, k, index, err = 0;
        struct tc_action *act;
 
        BUILD_BUG_ON(TCA_ACT_HW_STATS_ANY != FLOW_ACTION_HW_STATS_ANY);
@@ -3553,14 +3553,18 @@ int tc_setup_action(struct flow_action *flow_action,
                if (err)
                        goto err_out_locked;
 
-               entry->hw_stats = tc_act_hw_stats(act->hw_stats);
-               entry->hw_index = act->tcfa_index;
                index = 0;
                err = tc_setup_offload_act(act, entry, &index, extack);
-               if (!err)
-                       j += index;
-               else
+               if (err)
                        goto err_out_locked;
+
+               for (k = 0; k < index ; k++) {
+                       entry[k].hw_stats = tc_act_hw_stats(act->hw_stats);
+                       entry[k].hw_index = act->tcfa_index;
+               }
+
+               j += index;
+
                spin_unlock_bh(&act->tcfa_lock);
        }
 
index be29da0..3460abc 100644 (file)
@@ -229,9 +229,8 @@ static struct sctp_association *sctp_association_init(
        if (!sctp_ulpq_init(&asoc->ulpq, asoc))
                goto fail_init;
 
-       if (sctp_stream_init(&asoc->stream, asoc->c.sinit_num_ostreams,
-                            0, gfp))
-               goto fail_init;
+       if (sctp_stream_init(&asoc->stream, asoc->c.sinit_num_ostreams, 0, gfp))
+               goto stream_free;
 
        /* Initialize default path MTU. */
        asoc->pathmtu = sp->pathmtu;
index 35928fe..1a094b0 100644 (file)
@@ -358,7 +358,7 @@ static int sctp_v4_available(union sctp_addr *addr, struct sctp_sock *sp)
        if (addr->v4.sin_addr.s_addr != htonl(INADDR_ANY) &&
           ret != RTN_LOCAL &&
           !sp->inet.freebind &&
-          !net->ipv4.sysctl_ip_nonlocal_bind)
+           !READ_ONCE(net->ipv4.sysctl_ip_nonlocal_bind))
                return 0;
 
        if (ipv6_only_sock(sctp_opt2sk(sp)))
index 6dc95dc..ef9fcea 100644 (file)
@@ -137,7 +137,7 @@ int sctp_stream_init(struct sctp_stream *stream, __u16 outcnt, __u16 incnt,
 
        ret = sctp_stream_alloc_out(stream, outcnt, gfp);
        if (ret)
-               goto out_err;
+               return ret;
 
        for (i = 0; i < stream->outcnt; i++)
                SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
@@ -145,22 +145,9 @@ int sctp_stream_init(struct sctp_stream *stream, __u16 outcnt, __u16 incnt,
 handle_in:
        sctp_stream_interleave_init(stream);
        if (!incnt)
-               goto out;
-
-       ret = sctp_stream_alloc_in(stream, incnt, gfp);
-       if (ret)
-               goto in_err;
-
-       goto out;
+               return 0;
 
-in_err:
-       sched->free(stream);
-       genradix_free(&stream->in);
-out_err:
-       genradix_free(&stream->out);
-       stream->outcnt = 0;
-out:
-       return ret;
+       return sctp_stream_alloc_in(stream, incnt, gfp);
 }
 
 int sctp_stream_init_ext(struct sctp_stream *stream, __u16 sid)
index 518b1b9..1ad565e 100644 (file)
@@ -160,7 +160,7 @@ int sctp_sched_set_sched(struct sctp_association *asoc,
                if (!SCTP_SO(&asoc->stream, i)->ext)
                        continue;
 
-               ret = n->init_sid(&asoc->stream, i, GFP_KERNEL);
+               ret = n->init_sid(&asoc->stream, i, GFP_ATOMIC);
                if (ret)
                        goto err;
        }
index c4d057b..0bde36b 100644 (file)
@@ -2122,7 +2122,7 @@ void smc_llc_lgr_init(struct smc_link_group *lgr, struct smc_sock *smc)
        init_waitqueue_head(&lgr->llc_flow_waiter);
        init_waitqueue_head(&lgr->llc_msg_waiter);
        mutex_init(&lgr->llc_conf_mutex);
-       lgr->llc_testlink_time = net->ipv4.sysctl_tcp_keepalive_time;
+       lgr->llc_testlink_time = READ_ONCE(net->ipv4.sysctl_tcp_keepalive_time);
 }
 
 /* called after lgr was removed from lgr_list */
index 2bc8773..ec9ef13 100644 (file)
@@ -2106,6 +2106,7 @@ int __sys_sendto(int fd, void __user *buff, size_t len, unsigned int flags,
        msg.msg_control = NULL;
        msg.msg_controllen = 0;
        msg.msg_namelen = 0;
+       msg.msg_ubuf = NULL;
        if (addr) {
                err = move_addr_to_kernel(addr, addr_len, &address);
                if (err < 0)
@@ -2149,10 +2150,13 @@ SYSCALL_DEFINE4(send, int, fd, void __user *, buff, size_t, len,
 int __sys_recvfrom(int fd, void __user *ubuf, size_t size, unsigned int flags,
                   struct sockaddr __user *addr, int __user *addr_len)
 {
+       struct sockaddr_storage address;
+       struct msghdr msg = {
+               /* Save some cycles and don't copy the address if not needed */
+               .msg_name = addr ? (struct sockaddr *)&address : NULL,
+       };
        struct socket *sock;
        struct iovec iov;
-       struct msghdr msg;
-       struct sockaddr_storage address;
        int err, err2;
        int fput_needed;
 
@@ -2163,14 +2167,6 @@ int __sys_recvfrom(int fd, void __user *ubuf, size_t size, unsigned int flags,
        if (!sock)
                goto out;
 
-       msg.msg_control = NULL;
-       msg.msg_controllen = 0;
-       /* Save some cycles and don't copy the address if not needed */
-       msg.msg_name = addr ? (struct sockaddr *)&address : NULL;
-       /* We assume all kernel code knows the size of sockaddr_storage */
-       msg.msg_namelen = 0;
-       msg.msg_iocb = NULL;
-       msg.msg_flags = 0;
        if (sock->file->f_flags & O_NONBLOCK)
                flags |= MSG_DONTWAIT;
        err = sock_recvmsg(sock, &msg, flags);
@@ -2363,24 +2359,20 @@ struct used_address {
        unsigned int name_len;
 };
 
-int __copy_msghdr_from_user(struct msghdr *kmsg,
-                           struct user_msghdr __user *umsg,
-                           struct sockaddr __user **save_addr,
-                           struct iovec __user **uiov, size_t *nsegs)
+int __copy_msghdr(struct msghdr *kmsg,
+                 struct user_msghdr *msg,
+                 struct sockaddr __user **save_addr)
 {
-       struct user_msghdr msg;
        ssize_t err;
 
-       if (copy_from_user(&msg, umsg, sizeof(*umsg)))
-               return -EFAULT;
-
        kmsg->msg_control_is_user = true;
-       kmsg->msg_control_user = msg.msg_control;
-       kmsg->msg_controllen = msg.msg_controllen;
-       kmsg->msg_flags = msg.msg_flags;
+       kmsg->msg_get_inq = 0;
+       kmsg->msg_control_user = msg->msg_control;
+       kmsg->msg_controllen = msg->msg_controllen;
+       kmsg->msg_flags = msg->msg_flags;
 
-       kmsg->msg_namelen = msg.msg_namelen;
-       if (!msg.msg_name)
+       kmsg->msg_namelen = msg->msg_namelen;
+       if (!msg->msg_name)
                kmsg->msg_namelen = 0;
 
        if (kmsg->msg_namelen < 0)
@@ -2390,11 +2382,11 @@ int __copy_msghdr_from_user(struct msghdr *kmsg,
                kmsg->msg_namelen = sizeof(struct sockaddr_storage);
 
        if (save_addr)
-               *save_addr = msg.msg_name;
+               *save_addr = msg->msg_name;
 
-       if (msg.msg_name && kmsg->msg_namelen) {
+       if (msg->msg_name && kmsg->msg_namelen) {
                if (!save_addr) {
-                       err = move_addr_to_kernel(msg.msg_name,
+                       err = move_addr_to_kernel(msg->msg_name,
                                                  kmsg->msg_namelen,
                                                  kmsg->msg_name);
                        if (err < 0)
@@ -2405,12 +2397,11 @@ int __copy_msghdr_from_user(struct msghdr *kmsg,
                kmsg->msg_namelen = 0;
        }
 
-       if (msg.msg_iovlen > UIO_MAXIOV)
+       if (msg->msg_iovlen > UIO_MAXIOV)
                return -EMSGSIZE;
 
        kmsg->msg_iocb = NULL;
-       *uiov = msg.msg_iov;
-       *nsegs = msg.msg_iovlen;
+       kmsg->msg_ubuf = NULL;
        return 0;
 }
 
@@ -2422,8 +2413,10 @@ static int copy_msghdr_from_user(struct msghdr *kmsg,
        struct user_msghdr msg;
        ssize_t err;
 
-       err = __copy_msghdr_from_user(kmsg, umsg, save_addr, &msg.msg_iov,
-                                       &msg.msg_iovlen);
+       if (copy_from_user(&msg, umsg, sizeof(*umsg)))
+               return -EFAULT;
+
+       err = __copy_msghdr(kmsg, &msg, save_addr);
        if (err)
                return err;
 
index f87a2d8..5d2b3e6 100644 (file)
@@ -984,7 +984,7 @@ static noinline __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr,
        p = page_address(*xdr->page_ptr);
        xdr->p = p + frag2bytes;
        space_left = xdr->buf->buflen - xdr->buf->len;
-       if (space_left - nbytes >= PAGE_SIZE)
+       if (space_left - frag1bytes >= PAGE_SIZE)
                xdr->end = p + PAGE_SIZE;
        else
                xdr->end = p + space_left - frag1bytes;
index 6ef95ce..b48d97c 100644 (file)
@@ -472,8 +472,8 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr, u8 *peer_id,
                                   bool preliminary)
 {
        struct tipc_net *tn = net_generic(net, tipc_net_id);
+       struct tipc_link *l, *snd_l = tipc_bc_sndlink(net);
        struct tipc_node *n, *temp_node;
-       struct tipc_link *l;
        unsigned long intv;
        int bearer_id;
        int i;
@@ -488,6 +488,16 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr, u8 *peer_id,
                        goto exit;
                /* A preliminary node becomes "real" now, refresh its data */
                tipc_node_write_lock(n);
+               if (!tipc_link_bc_create(net, tipc_own_addr(net), addr, peer_id, U16_MAX,
+                                        tipc_link_min_win(snd_l), tipc_link_max_win(snd_l),
+                                        n->capabilities, &n->bc_entry.inputq1,
+                                        &n->bc_entry.namedq, snd_l, &n->bc_entry.link)) {
+                       pr_warn("Broadcast rcv link refresh failed, no memory\n");
+                       tipc_node_write_unlock_fast(n);
+                       tipc_node_put(n);
+                       n = NULL;
+                       goto exit;
+               }
                n->preliminary = false;
                n->addr = addr;
                hlist_del_rcu(&n->hash);
@@ -567,7 +577,16 @@ update:
        n->signature = INVALID_NODE_SIG;
        n->active_links[0] = INVALID_BEARER_ID;
        n->active_links[1] = INVALID_BEARER_ID;
-       n->bc_entry.link = NULL;
+       if (!preliminary &&
+           !tipc_link_bc_create(net, tipc_own_addr(net), addr, peer_id, U16_MAX,
+                                tipc_link_min_win(snd_l), tipc_link_max_win(snd_l),
+                                n->capabilities, &n->bc_entry.inputq1,
+                                &n->bc_entry.namedq, snd_l, &n->bc_entry.link)) {
+               pr_warn("Broadcast rcv link creation failed, no memory\n");
+               kfree(n);
+               n = NULL;
+               goto exit;
+       }
        tipc_node_get(n);
        timer_setup(&n->timer, tipc_node_timeout, 0);
        /* Start a slow timer anyway, crypto needs it */
@@ -1155,7 +1174,7 @@ void tipc_node_check_dest(struct net *net, u32 addr,
                          bool *respond, bool *dupl_addr)
 {
        struct tipc_node *n;
-       struct tipc_link *l, *snd_l;
+       struct tipc_link *l;
        struct tipc_link_entry *le;
        bool addr_match = false;
        bool sign_match = false;
@@ -1175,22 +1194,6 @@ void tipc_node_check_dest(struct net *net, u32 addr,
                return;
 
        tipc_node_write_lock(n);
-       if (unlikely(!n->bc_entry.link)) {
-               snd_l = tipc_bc_sndlink(net);
-               if (!tipc_link_bc_create(net, tipc_own_addr(net),
-                                        addr, peer_id, U16_MAX,
-                                        tipc_link_min_win(snd_l),
-                                        tipc_link_max_win(snd_l),
-                                        n->capabilities,
-                                        &n->bc_entry.inputq1,
-                                        &n->bc_entry.namedq, snd_l,
-                                        &n->bc_entry.link)) {
-                       pr_warn("Broadcast rcv link creation failed, no mem\n");
-                       tipc_node_write_unlock_fast(n);
-                       tipc_node_put(n);
-                       return;
-               }
-       }
 
        le = &n->links[b->identity];
 
index 17f8c52..f1c3b8e 100644 (file)
@@ -502,6 +502,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock,
        sock_init_data(sock, sk);
        tipc_set_sk_state(sk, TIPC_OPEN);
        if (tipc_sk_insert(tsk)) {
+               sk_free(sk);
                pr_warn("Socket create failed; port number exhausted\n");
                return -EINVAL;
        }
@@ -516,7 +517,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock,
        timer_setup(&sk->sk_timer, tipc_sk_timeout, 0);
        sk->sk_shutdown = 0;
        sk->sk_backlog_rcv = tipc_sk_backlog_rcv;
-       sk->sk_rcvbuf = sysctl_tipc_rmem[1];
+       sk->sk_rcvbuf = READ_ONCE(sysctl_tipc_rmem[1]);
        sk->sk_data_ready = tipc_data_ready;
        sk->sk_write_space = tipc_write_space;
        sk->sk_destruct = tipc_sock_destruct;
index ec6f4b6..9975df3 100644 (file)
@@ -97,13 +97,16 @@ static void tls_device_queue_ctx_destruction(struct tls_context *ctx)
        unsigned long flags;
 
        spin_lock_irqsave(&tls_device_lock, flags);
+       if (unlikely(!refcount_dec_and_test(&ctx->refcount)))
+               goto unlock;
+
        list_move_tail(&ctx->list, &tls_device_gc_list);
 
        /* schedule_work inside the spinlock
         * to make sure tls_device_down waits for that work.
         */
        schedule_work(&tls_device_gc_work);
-
+unlock:
        spin_unlock_irqrestore(&tls_device_lock, flags);
 }
 
@@ -194,8 +197,7 @@ void tls_device_sk_destruct(struct sock *sk)
                clean_acked_data_disable(inet_csk(sk));
        }
 
-       if (refcount_dec_and_test(&tls_ctx->refcount))
-               tls_device_queue_ctx_destruction(tls_ctx);
+       tls_device_queue_ctx_destruction(tls_ctx);
 }
 EXPORT_SYMBOL_GPL(tls_device_sk_destruct);
 
@@ -1374,8 +1376,13 @@ static int tls_device_down(struct net_device *netdev)
                 * by tls_device_free_ctx. rx_conf and tx_conf stay in TLS_HW.
                 * Now release the ref taken above.
                 */
-               if (refcount_dec_and_test(&ctx->refcount))
+               if (refcount_dec_and_test(&ctx->refcount)) {
+                       /* sk_destruct ran after tls_device_down took a ref, and
+                        * it returned early. Complete the destruction here.
+                        */
+                       list_del(&ctx->list);
                        tls_device_free_ctx(ctx);
+               }
        }
 
        up_write(&device_offload_lock);
@@ -1419,9 +1426,9 @@ static struct notifier_block tls_dev_notifier = {
        .notifier_call  = tls_dev_event,
 };
 
-void __init tls_device_init(void)
+int __init tls_device_init(void)
 {
-       register_netdevice_notifier(&tls_dev_notifier);
+       return register_netdevice_notifier(&tls_dev_notifier);
 }
 
 void __exit tls_device_cleanup(void)
index 2ffede4..d80ab3d 100644 (file)
@@ -1048,7 +1048,12 @@ static int __init tls_register(void)
        if (err)
                return err;
 
-       tls_device_init();
+       err = tls_device_init();
+       if (err) {
+               unregister_pernet_subsys(&tls_proc_ops);
+               return err;
+       }
+
        tcp_register_ulp(&tcp_tls_ulp_ops);
 
        return 0;
index 0513f82..e30649f 100644 (file)
@@ -267,9 +267,6 @@ static int tls_do_decryption(struct sock *sk,
        }
        darg->async = false;
 
-       if (ret == -EBADMSG)
-               TLS_INC_STATS(sock_net(sk), LINUX_MIB_TLSDECRYPTERROR);
-
        return ret;
 }
 
@@ -1579,8 +1576,11 @@ static int decrypt_skb_update(struct sock *sk, struct sk_buff *skb,
        }
 
        err = decrypt_internal(sk, skb, dest, NULL, darg);
-       if (err < 0)
+       if (err < 0) {
+               if (err == -EBADMSG)
+                       TLS_INC_STATS(sock_net(sk), LINUX_MIB_TLSDECRYPTERROR);
                return err;
+       }
        if (darg->async)
                goto decrypt_next;
 
index ff4d48f..607a689 100644 (file)
@@ -1031,7 +1031,8 @@ void __cfg80211_port_authorized(struct wireless_dev *wdev, const u8 *bssid)
 {
        ASSERT_WDEV_LOCK(wdev);
 
-       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION &&
+                   wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
                return;
 
        if (WARN_ON(!wdev->current_bss) ||
index 87bdd71..f701121 100644 (file)
@@ -332,6 +332,7 @@ static void __xp_dma_unmap(struct xsk_dma_map *dma_map, unsigned long attrs)
        for (i = 0; i < dma_map->dma_pages_cnt; i++) {
                dma = &dma_map->dma_pages[i];
                if (*dma) {
+                       *dma &= ~XSK_NEXT_PG_CONTIG_MASK;
                        dma_unmap_page_attrs(dma_map->dev, *dma, PAGE_SIZE,
                                             DMA_BIDIRECTIONAL, attrs);
                        *dma = 0;
index f1876ea..f1a0bab 100644 (file)
@@ -2678,8 +2678,10 @@ static int xfrm_expand_policies(const struct flowi *fl, u16 family,
                *num_xfrms = 0;
                return 0;
        }
-       if (IS_ERR(pols[0]))
+       if (IS_ERR(pols[0])) {
+               *num_pols = 0;
                return PTR_ERR(pols[0]);
+       }
 
        *num_xfrms = pols[0]->xfrm_nr;
 
@@ -2694,6 +2696,7 @@ static int xfrm_expand_policies(const struct flowi *fl, u16 family,
                if (pols[1]) {
                        if (IS_ERR(pols[1])) {
                                xfrm_pols_put(pols, *num_pols);
+                               *num_pols = 0;
                                return PTR_ERR(pols[1]);
                        }
                        (*num_pols)++;
index 08564e0..ccfb172 100644 (file)
@@ -2620,7 +2620,7 @@ int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload)
        int err;
 
        if (family == AF_INET &&
-           xs_net(x)->ipv4.sysctl_ip_no_pmtu_disc)
+           READ_ONCE(xs_net(x)->ipv4.sysctl_ip_no_pmtu_disc))
                x->props.flags |= XFRM_STATE_NOPMTUDISC;
 
        err = -EPROTONOSUPPORT;
index 01ee6c8..e22da85 100644 (file)
 
 #define BACKTRACE_DEPTH 16
 #define MAX_SYMBOL_LEN 4096
-struct fprobe sample_probe;
+static struct fprobe sample_probe;
 static unsigned long nhit;
 
 static char symbol[MAX_SYMBOL_LEN] = "kernel_clone";
 module_param_string(symbol, symbol, sizeof(symbol), 0644);
+MODULE_PARM_DESC(symbol, "Probed symbol(s), given by comma separated symbols or a wildcard pattern.");
+
 static char nosymbol[MAX_SYMBOL_LEN] = "";
 module_param_string(nosymbol, nosymbol, sizeof(nosymbol), 0644);
+MODULE_PARM_DESC(nosymbol, "Not-probed symbols, given by a wildcard pattern.");
+
 static bool stackdump = true;
 module_param(stackdump, bool, 0644);
+MODULE_PARM_DESC(stackdump, "Enable stackdump.");
+
 static bool use_trace = false;
 module_param(use_trace, bool, 0644);
+MODULE_PARM_DESC(use_trace, "Use trace_printk instead of printk. This is only for debugging.");
 
 static void show_backtrace(void)
 {
index f991a66..fd346f5 100644 (file)
@@ -16,9 +16,8 @@
 #include <linux/module.h>
 #include <linux/kprobes.h>
 
-#define MAX_SYMBOL_LEN 64
-static char symbol[MAX_SYMBOL_LEN] = "kernel_clone";
-module_param_string(symbol, symbol, sizeof(symbol), 0644);
+static char symbol[KSYM_NAME_LEN] = "kernel_clone";
+module_param_string(symbol, symbol, KSYM_NAME_LEN, 0644);
 
 /* For each probe you need to allocate a kprobe structure */
 static struct kprobe kp = {
index 228321e..cbf1654 100644 (file)
 #include <linux/module.h>
 #include <linux/kprobes.h>
 #include <linux/ktime.h>
-#include <linux/limits.h>
 #include <linux/sched.h>
 
-static char func_name[NAME_MAX] = "kernel_clone";
-module_param_string(func, func_name, NAME_MAX, S_IRUGO);
+static char func_name[KSYM_NAME_LEN] = "kernel_clone";
+module_param_string(func, func_name, KSYM_NAME_LEN, 0644);
 MODULE_PARM_DESC(func, "Function to kretprobe; this module will report the"
                        " function's execution time");
 
index d142577..3fb6a99 100644 (file)
@@ -236,6 +236,7 @@ objtool_args =                                                              \
        $(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount)             \
        $(if $(CONFIG_UNWINDER_ORC), --orc)                             \
        $(if $(CONFIG_RETPOLINE), --retpoline)                          \
+       $(if $(CONFIG_RETHUNK), --rethunk)                              \
        $(if $(CONFIG_SLS), --sls)                                      \
        $(if $(CONFIG_STACK_VALIDATION), --stackval)                    \
        $(if $(CONFIG_HAVE_STATIC_CALL_INLINE), --static-call)          \
index c2c43a0..16a02e9 100644 (file)
@@ -28,9 +28,6 @@ modules := $(patsubst $(extmod_prefix)%, $(dst)/%$(suffix-y), $(modules))
 __modinst: $(modules)
        @:
 
-quiet_cmd_none =
-      cmd_none = :
-
 #
 # Installation
 #
index 3c97a15..8401981 100644 (file)
@@ -44,7 +44,7 @@ objtool-enabled := $(or $(delay-objtool),$(CONFIG_NOINSTR_VALIDATION))
 
 objtool_args := \
        $(if $(delay-objtool),$(objtool_args)) \
-       $(if $(CONFIG_NOINSTR_VALIDATION), --noinstr) \
+       $(if $(CONFIG_NOINSTR_VALIDATION), --noinstr $(if $(CONFIG_CPU_UNRET_ENTRY), --unret)) \
        $(if $(CONFIG_GCOV_KERNEL), --no-unreachable) \
        --link
 
index 1d1bde1..47da25b 100755 (executable)
@@ -157,10 +157,10 @@ def cmdfiles_for_modorder(modorder):
             if ext != '.ko':
                 sys.exit('{}: module path must end with .ko'.format(ko))
             mod = base + '.mod'
-           # The first line of *.mod lists the objects that compose the module.
+            # Read from *.mod, to get a list of objects that compose the module.
             with open(mod) as m:
-                for obj in m.readline().split():
-                    yield to_cmdfile(obj)
+                for mod_line in m:
+                    yield to_cmdfile(mod_line.rstrip())
 
 
 def process_line(root_directory, command_prefix, file_path):
index 46f7542..dc07b6d 100644 (file)
@@ -180,7 +180,7 @@ lx-symbols command."""
                 self.breakpoint.delete()
                 self.breakpoint = None
             self.breakpoint = LoadModuleBreakpoint(
-                "kernel/module.c:do_init_module", self)
+                "kernel/module/main.c:do_init_module", self)
         else:
             gdb.write("Note: symbol update on module loading not supported "
                       "with this gdb version\n")
index faacf70..653fadb 100755 (executable)
@@ -56,4 +56,7 @@ EOT
 # point addresses.
 sed -e 's/^\.//' |
 sort -u |
+# Ignore __this_module. It's not an exported symbol, and will be resolved
+# when the final .ko's are linked.
+grep -v '^__this_module$' |
 sed -e 's/\(.*\)/#define __KSYM_\1 1/' >> "$output_file"
index 76cfb96..5c5397e 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/perl
+#!/usr/bin/env perl
 # SPDX-License-Identifier: GPL-2.0
 
 use strict;
index 7516949..aea0436 100755 (executable)
@@ -427,6 +427,13 @@ sub print_lineno {
         print ".. LINENO " . $lineno . "\n";
     }
 }
+
+sub emit_warning {
+    my $location = shift;
+    my $msg = shift;
+    print STDERR "$location: warning: $msg";
+    ++$warnings;
+}
 ##
 # dumps section contents to arrays/hashes intended for that purpose.
 #
@@ -451,8 +458,7 @@ sub dump_section {
        if (defined($sections{$name}) && ($sections{$name} ne "")) {
            # Only warn on user specified duplicate section names.
            if ($name ne $section_default) {
-               print STDERR "${file}:$.: warning: duplicate section name '$name'\n";
-               ++$warnings;
+               emit_warning("${file}:$.", "duplicate section name '$name'\n");
            }
            $sections{$name} .= $contents;
        } else {
@@ -1094,7 +1100,7 @@ sub dump_struct($$) {
 
     if ($members) {
        if ($identifier ne $declaration_name) {
-           print STDERR "${file}:$.: warning: expecting prototype for $decl_type $identifier. Prototype was for $decl_type $declaration_name instead\n";
+           emit_warning("${file}:$.", "expecting prototype for $decl_type $identifier. Prototype was for $decl_type $declaration_name instead\n");
            return;
        }
 
@@ -1298,9 +1304,9 @@ sub dump_enum($$) {
     if ($members) {
        if ($identifier ne $declaration_name) {
            if ($identifier eq "") {
-               print STDERR "${file}:$.: warning: wrong kernel-doc identifier on line:\n";
+               emit_warning("${file}:$.", "wrong kernel-doc identifier on line:\n");
            } else {
-               print STDERR "${file}:$.: warning: expecting prototype for enum $identifier. Prototype was for enum $declaration_name instead\n";
+               emit_warning("${file}:$.", "expecting prototype for enum $identifier. Prototype was for enum $declaration_name instead\n");
            }
            return;
        }
@@ -1316,7 +1322,7 @@ sub dump_enum($$) {
            if (!$parameterdescs{$arg}) {
                $parameterdescs{$arg} = $undescribed;
                if (show_warnings("enum", $declaration_name)) {
-                       print STDERR "${file}:$.: warning: Enum value '$arg' not described in enum '$declaration_name'\n";
+                       emit_warning("${file}:$.", "Enum value '$arg' not described in enum '$declaration_name'\n");
                }
            }
            $_members{$arg} = 1;
@@ -1325,7 +1331,7 @@ sub dump_enum($$) {
        while (my ($k, $v) = each %parameterdescs) {
            if (!exists($_members{$k})) {
                if (show_warnings("enum", $declaration_name)) {
-                    print STDERR "${file}:$.: warning: Excess enum value '$k' description in '$declaration_name'\n";
+                    emit_warning("${file}:$.", "Excess enum value '$k' description in '$declaration_name'\n");
                }
            }
         }
@@ -1367,7 +1373,7 @@ sub dump_typedef($$) {
        $return_type =~ s/^\s+//;
 
        if ($identifier ne $declaration_name) {
-           print STDERR "${file}:$.: warning: expecting prototype for typedef $identifier. Prototype was for typedef $declaration_name instead\n";
+           emit_warning("${file}:$.", "expecting prototype for typedef $identifier. Prototype was for typedef $declaration_name instead\n");
            return;
        }
 
@@ -1398,7 +1404,7 @@ sub dump_typedef($$) {
        $declaration_name = $1;
 
        if ($identifier ne $declaration_name) {
-           print STDERR "${file}:$.: warning: expecting prototype for typedef $identifier. Prototype was for typedef $declaration_name instead\n";
+           emit_warning("${file}:$.", "expecting prototype for typedef $identifier. Prototype was for typedef $declaration_name instead\n");
            return;
        }
 
@@ -1554,9 +1560,7 @@ sub push_parameter($$$$$) {
                $parameterdescs{$param} = $undescribed;
 
                if (show_warnings($type, $declaration_name) && $param !~ /\./) {
-                       print STDERR
-                             "${file}:$.: warning: Function parameter or member '$param' not described in '$declaration_name'\n";
-                       ++$warnings;
+                       emit_warning("${file}:$.", "Function parameter or member '$param' not described in '$declaration_name'\n");
                }
        }
 
@@ -1604,11 +1608,10 @@ sub check_sections($$$$$) {
                }
                if ($err) {
                        if ($decl_type eq "function") {
-                               print STDERR "${file}:$.: warning: " .
+                               emit_warning("${file}:$.",
                                        "Excess function parameter " .
                                        "'$sects[$sx]' " .
-                                       "description in '$decl_name'\n";
-                               ++$warnings;
+                                       "description in '$decl_name'\n");
                        }
                }
        }
@@ -1629,10 +1632,9 @@ sub check_return_section {
 
         if (!defined($sections{$section_return}) ||
             $sections{$section_return} eq "") {
-                print STDERR "${file}:$.: warning: " .
+                emit_warning("${file}:$.",
                         "No description found for return value of " .
-                        "'$declaration_name'\n";
-                ++$warnings;
+                        "'$declaration_name'\n");
         }
 }
 
@@ -1714,12 +1716,12 @@ sub dump_function($$) {
 
        create_parameterlist($args, ',', $file, $declaration_name);
     } else {
-       print STDERR "${file}:$.: warning: cannot understand function prototype: '$prototype'\n";
+       emit_warning("${file}:$.", "cannot understand function prototype: '$prototype'\n");
        return;
     }
 
     if ($identifier ne $declaration_name) {
-       print STDERR "${file}:$.: warning: expecting prototype for $identifier(). Prototype was for $declaration_name() instead\n";
+       emit_warning("${file}:$.", "expecting prototype for $identifier(). Prototype was for $declaration_name() instead\n");
        return;
     }
 
@@ -1801,8 +1803,8 @@ sub tracepoint_munge($) {
                $tracepointargs = $1;
        }
        if (($tracepointname eq 0) || ($tracepointargs eq 0)) {
-               print STDERR "${file}:$.: warning: Unrecognized tracepoint format: \n".
-                            "$prototype\n";
+               emit_warning("${file}:$.", "Unrecognized tracepoint format: \n".
+                            "$prototype\n");
        } else {
                $prototype = "static inline void trace_$tracepointname($tracepointargs)";
                $identifier = "trace_$identifier";
@@ -2027,22 +2029,16 @@ sub process_name($$) {
        }
 
        if (!$is_kernel_comment) {
-           print STDERR "${file}:$.: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst\n";
-           print STDERR $_;
-           ++$warnings;
+           emit_warning("${file}:$.", "This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst\n$_");
            $state = STATE_NORMAL;
        }
 
        if (($declaration_purpose eq "") && $verbose) {
-           print STDERR "${file}:$.: warning: missing initial short description on line:\n";
-           print STDERR $_;
-           ++$warnings;
+           emit_warning("${file}:$.", "missing initial short description on line:\n$_");
        }
 
        if ($identifier eq "" && $decl_type ne "enum") {
-           print STDERR "${file}:$.: warning: wrong kernel-doc identifier on line:\n";
-           print STDERR $_;
-           ++$warnings;
+           emit_warning("${file}:$.", "wrong kernel-doc identifier on line:\n$_");
            $state = STATE_NORMAL;
        }
 
@@ -2050,9 +2046,7 @@ sub process_name($$) {
            print STDERR "${file}:$.: info: Scanning doc for $decl_type $identifier\n";
        }
     } else {
-       print STDERR "${file}:$.: warning: Cannot understand $_ on line $.",
-           " - I thought it was a doc line\n";
-       ++$warnings;
+       emit_warning("${file}:$.", "Cannot understand $_ on line $. - I thought it was a doc line\n");
        $state = STATE_NORMAL;
     }
 }
@@ -2071,8 +2065,7 @@ sub process_body($$) {
        $section =~ s/\.\.\.$//;
 
        if ($verbose) {
-           print STDERR "${file}:$.: warning: Variable macro arguments should be documented without dots\n";
-           ++$warnings;
+           emit_warning("${file}:$.", "Variable macro arguments should be documented without dots\n");
        }
     }
 
@@ -2101,8 +2094,7 @@ sub process_body($$) {
 
        if (($contents ne "") && ($contents ne "\n")) {
            if (!$in_doc_sect && $verbose) {
-               print STDERR "${file}:$.: warning: contents before sections\n";
-               ++$warnings;
+               emit_warning("${file}:$.", "contents before sections\n");
            }
            dump_section($file, $section, $contents);
            $section = $section_default;
@@ -2128,8 +2120,7 @@ sub process_body($$) {
        }
        # look for doc_com + <text> + doc_end:
        if ($_ =~ m'\s*\*\s*[a-zA-Z_0-9:\.]+\*/') {
-           print STDERR "${file}:$.: warning: suspicious ending line: $_";
-           ++$warnings;
+           emit_warning("${file}:$.", "suspicious ending line: $_");
        }
 
        $prototype = "";
@@ -2173,8 +2164,7 @@ sub process_body($$) {
        }
     } else {
        # i dont know - bad line?  ignore.
-       print STDERR "${file}:$.: warning: bad line: $_";
-       ++$warnings;
+       emit_warning("${file}:$.", "bad line: $_");
     }
 }
 
@@ -2268,9 +2258,7 @@ sub process_inline($$) {
            }
        } elsif ($inline_doc_state == STATE_INLINE_NAME) {
            $inline_doc_state = STATE_INLINE_ERROR;
-           print STDERR "${file}:$.: warning: ";
-           print STDERR "Incorrect use of kernel-doc format: $_";
-           ++$warnings;
+           emit_warning("${file}:$.", "Incorrect use of kernel-doc format: $_");
        }
     }
 }
@@ -2319,11 +2307,11 @@ sub process_file($) {
     if ($initial_section_counter == $section_counter && $
        output_mode ne "none") {
        if ($output_selection == OUTPUT_INCLUDE) {
-           print STDERR "${file}:1: warning: '$_' not found\n"
+           emit_warning("${file}:1", "'$_' not found\n")
                for keys %function_table;
        }
        else {
-           print STDERR "${file}:1: warning: no structured comments found\n";
+           emit_warning("${file}:1", "no structured comments found\n");
        }
     }
     close IN_FILE;
index 29d5a84..29474ce 100644 (file)
@@ -980,7 +980,7 @@ static const struct sectioncheck sectioncheck[] = {
 },
 /* Do not export init/exit functions or data */
 {
-       .fromsec = { "__ksymtab*", NULL },
+       .fromsec = { "___ksymtab*", NULL },
        .bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
        .mismatch = EXPORT_TO_INIT_EXIT,
        .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
@@ -2191,6 +2191,9 @@ static void add_header(struct buffer *b, struct module *mod)
 
        if (strstarts(mod->name, "drivers/staging"))
                buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
+
+       if (strstarts(mod->name, "tools/testing"))
+               buf_printf(b, "\nMODULE_INFO(test, \"Y\");\n");
 }
 
 static void add_exported_symbols(struct buffer *buf, struct module *mod)
index 7adab46..379e86c 100755 (executable)
@@ -41,3 +41,5 @@ if [ -n "${building_out_of_srctree}" ]; then
 fi
 
 rm -f scripts/extract-cert
+
+rm -f arch/x86/purgatory/kexec-purgatory.c
index f126ecb..ec84fc6 100755 (executable)
@@ -25,6 +25,7 @@ my $need_sphinx = 0;
 my $need_pip = 0;
 my $need_virtualenv = 0;
 my $rec_sphinx_upgrade = 0;
+my $verbose_warn_install = 1;
 my $install = "";
 my $virtenv_dir = "";
 my $python_cmd = "";
@@ -103,10 +104,12 @@ sub check_missing(%)
                        next;
                }
 
-               if ($is_optional) {
-                       print "Warning: better to also install \"$prog\".\n";
-               } else {
-                       print "ERROR: please install \"$prog\", otherwise, build won't work.\n";
+               if ($verbose_warn_install) {
+                       if ($is_optional) {
+                               print "Warning: better to also install \"$prog\".\n";
+                       } else {
+                               print "ERROR: please install \"$prog\", otherwise, build won't work.\n";
+                       }
                }
                if (defined($map{$prog})) {
                        $install .= " " . $map{$prog};
@@ -386,7 +389,8 @@ sub give_debian_hints()
        check_missing(\%map);
 
        return if (!$need && !$optional);
-       printf("You should run:\n\n\tsudo apt-get install $install\n");
+       printf("You should run:\n") if ($verbose_warn_install);
+       printf("\n\tsudo apt-get install $install\n");
 }
 
 sub give_redhat_hints()
@@ -458,10 +462,12 @@ sub give_redhat_hints()
 
        if (!$old) {
                # dnf, for Fedora 18+
-               printf("You should run:\n\n\tsudo dnf install -y $install\n");
+               printf("You should run:\n") if ($verbose_warn_install);
+               printf("\n\tsudo dnf install -y $install\n");
        } else {
                # yum, for RHEL (and clones) or Fedora version < 18
-               printf("You should run:\n\n\tsudo yum install -y $install\n");
+               printf("You should run:\n") if ($verbose_warn_install);
+               printf("\n\tsudo yum install -y $install\n");
        }
 }
 
@@ -509,7 +515,8 @@ sub give_opensuse_hints()
        check_missing(\%map);
 
        return if (!$need && !$optional);
-       printf("You should run:\n\n\tsudo zypper install --no-recommends $install\n");
+       printf("You should run:\n") if ($verbose_warn_install);
+       printf("\n\tsudo zypper install --no-recommends $install\n");
 }
 
 sub give_mageia_hints()
@@ -553,7 +560,8 @@ sub give_mageia_hints()
        check_missing(\%map);
 
        return if (!$need && !$optional);
-       printf("You should run:\n\n\tsudo $packager_cmd $install\n");
+       printf("You should run:\n") if ($verbose_warn_install);
+       printf("\n\tsudo $packager_cmd $install\n");
 }
 
 sub give_arch_linux_hints()
@@ -583,7 +591,8 @@ sub give_arch_linux_hints()
        check_missing(\%map);
 
        return if (!$need && !$optional);
-       printf("You should run:\n\n\tsudo pacman -S $install\n");
+       printf("You should run:\n") if ($verbose_warn_install);
+       printf("\n\tsudo pacman -S $install\n");
 }
 
 sub give_gentoo_hints()
@@ -610,7 +619,8 @@ sub give_gentoo_hints()
 
        return if (!$need && !$optional);
 
-       printf("You should run:\n\n");
+       printf("You should run:\n") if ($verbose_warn_install);
+       printf("\n");
 
        my $imagemagick = "media-gfx/imagemagick svg png";
        my $cairo = "media-gfx/graphviz cairo pdf";
@@ -700,7 +710,7 @@ sub check_distros()
 
 sub deactivate_help()
 {
-       printf "\nIf you want to exit the virtualenv, you can use:\n";
+       printf "\n    If you want to exit the virtualenv, you can use:\n";
        printf "\tdeactivate\n";
 }
 
@@ -720,6 +730,12 @@ sub get_virtenv()
                next if (! -f $sphinx_cmd);
 
                my $ver = get_sphinx_version($sphinx_cmd);
+
+               if (!$ver) {
+                       $f =~ s#/bin/activate##;
+                       print("Warning: virtual environment $f is not working.\nPython version upgrade? Remove it with:\n\n\trm -rf $f\n\n");
+               }
+
                if ($need_sphinx && ($ver ge $min_version)) {
                        return ($f, $ver);
                } elsif ($ver gt $cur_version) {
@@ -741,7 +757,7 @@ sub recommend_sphinx_upgrade()
 
        # Get the highest version from sphinx_*/bin/sphinx-build and the
        # corresponding command to activate the venv/virtenv
-       $activate_cmd = get_virtenv();
+       ($activate_cmd, $venv_ver) = get_virtenv();
 
        # Store the highest version from Sphinx existing virtualenvs
        if (($activate_cmd ne "") && ($venv_ver gt $cur_version)) {
@@ -759,10 +775,14 @@ sub recommend_sphinx_upgrade()
        # Either there are already a virtual env or a new one should be created
        $need_pip = 1;
 
+       return if (!$latest_avail_ver);
+
        # Return if the reason is due to an upgrade or not
        if ($latest_avail_ver lt $rec_version) {
                $rec_sphinx_upgrade = 1;
        }
+
+       return $latest_avail_ver;
 }
 
 #
@@ -775,12 +795,13 @@ sub recommend_sphinx_version($)
 {
        my $virtualenv_cmd = shift;
 
-       if ($latest_avail_ver lt $min_pdf_version) {
-               print "note: If you want pdf, you need at least Sphinx $min_pdf_version.\n";
-       }
-
        # Version is OK. Nothing to do.
-       return if ($cur_version && ($cur_version ge $rec_version));
+       if ($cur_version && ($cur_version ge $rec_version)) {
+               if ($cur_version lt $min_pdf_version) {
+                       print "note: If you want pdf, you need at least Sphinx $min_pdf_version.\n";
+               }
+               return;
+       };
 
        if (!$need_sphinx) {
                # sphinx-build is present and its version is >= $min_version
@@ -820,13 +841,17 @@ sub recommend_sphinx_version($)
        }
 
        # Suggest newer versions if current ones are too old
-       if ($latest_avail_ver && $cur_version ge $min_version) {
+       if ($latest_avail_ver && $latest_avail_ver ge $min_version) {
                # If there's a good enough version, ask the user to enable it
                if ($latest_avail_ver ge $rec_version) {
                        printf "\nNeed to activate Sphinx (version $latest_avail_ver) on virtualenv with:\n";
                        printf "\t. $activate_cmd\n";
                        deactivate_help();
 
+                       if ($latest_avail_ver lt $min_pdf_version) {
+                               print "note: If you want pdf, you need at least Sphinx $min_pdf_version.\n";
+                       }
+
                        return;
                }
 
@@ -848,7 +873,7 @@ sub recommend_sphinx_version($)
                        print "To upgrade Sphinx, use:\n\n";
                }
        } else {
-               print "Sphinx needs to be installed either as a package or via pip/pypi with:\n";
+               print "\nSphinx needs to be installed either:\n1) via pip/pypi with:\n\n";
        }
 
        $python_cmd = find_python_no_venv();
@@ -858,6 +883,29 @@ sub recommend_sphinx_version($)
        printf "\t. $virtenv_dir/bin/activate\n";
        printf "\tpip install -r $requirement_file\n";
        deactivate_help();
+
+       printf "\n2) As a package with:\n";
+
+       my $old_need = $need;
+       my $old_optional = $optional;
+       %missing = ();
+       $pdf = 0;
+       $optional = 0;
+       $install = "";
+       $verbose_warn_install = 0;
+
+       add_package("python-sphinx", 0);
+       check_python_module("sphinx_rtd_theme", 1);
+
+       check_distros();
+
+       $need = $old_need;
+       $optional = $old_optional;
+
+       printf "\n    Please note that Sphinx >= 3.0 will currently produce false-positive\n";
+       printf "   warning when the same name is used for more than one type (functions,\n";
+       printf "   structs, enums,...). This is known Sphinx bug. For more details, see:\n";
+       printf "\thttps://github.com/sphinx-doc/sphinx/pull/8313\n";
 }
 
 sub check_needs()
@@ -897,7 +945,7 @@ sub check_needs()
                }
        }
 
-       recommend_sphinx_upgrade();
+       my $venv_ver = recommend_sphinx_upgrade();
 
        my $virtualenv_cmd;
 
index f29e4c6..e6db09a 100644 (file)
@@ -54,17 +54,6 @@ config SECURITY_NETWORK
          implement socket and networking access controls.
          If you are unsure how to answer this question, answer N.
 
-config PAGE_TABLE_ISOLATION
-       bool "Remove the kernel mapping in user mode"
-       default y
-       depends on (X86_64 || X86_PAE) && !UML
-       help
-         This feature reduces the number of hardware side channels by
-         ensuring that the majority of kernel addresses are not mapped
-         into userspace.
-
-         See Documentation/x86/pti.rst for more details.
-
 config SECURITY_INFINIBAND
        bool "Infiniband Security Hooks"
        depends on SECURITY && INFINIBAND
index 5c18d2f..7954cb2 100644 (file)
@@ -177,7 +177,7 @@ static void policy_unpack_test_unpack_array_out_of_bounds(struct kunit *test)
 
        array_size = unpack_array(puf->e, name);
 
-       KUNIT_EXPECT_EQ(test, array_size, (u16)0);
+       KUNIT_EXPECT_EQ(test, array_size, 0);
        KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
                puf->e->start + TEST_NAMED_ARRAY_BUF_OFFSET);
 }
@@ -391,10 +391,10 @@ static void policy_unpack_test_unpack_u16_chunk_basic(struct kunit *test)
 
        size = unpack_u16_chunk(puf->e, &chunk);
 
-       KUNIT_EXPECT_PTR_EQ(test, (void *)chunk,
+       KUNIT_EXPECT_PTR_EQ(test, chunk,
                            puf->e->start + TEST_U16_OFFSET + 2);
-       KUNIT_EXPECT_EQ(test, size, (size_t)TEST_U16_DATA);
-       KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, (void *)(chunk + TEST_U16_DATA));
+       KUNIT_EXPECT_EQ(test, size, TEST_U16_DATA);
+       KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, (chunk + TEST_U16_DATA));
 }
 
 static void policy_unpack_test_unpack_u16_chunk_out_of_bounds_1(
@@ -408,7 +408,7 @@ static void policy_unpack_test_unpack_u16_chunk_out_of_bounds_1(
 
        size = unpack_u16_chunk(puf->e, &chunk);
 
-       KUNIT_EXPECT_EQ(test, size, (size_t)0);
+       KUNIT_EXPECT_EQ(test, size, 0);
        KUNIT_EXPECT_NULL(test, chunk);
        KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, puf->e->end - 1);
 }
@@ -430,7 +430,7 @@ static void policy_unpack_test_unpack_u16_chunk_out_of_bounds_2(
 
        size = unpack_u16_chunk(puf->e, &chunk);
 
-       KUNIT_EXPECT_EQ(test, size, (size_t)0);
+       KUNIT_EXPECT_EQ(test, size, 0);
        KUNIT_EXPECT_NULL(test, chunk);
        KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, puf->e->start + TEST_U16_OFFSET);
 }
index a733aff..708de96 100644 (file)
@@ -75,7 +75,7 @@ static struct shash_desc *init_desc(char type, uint8_t hash_algo)
 {
        long rc;
        const char *algo;
-       struct crypto_shash **tfm, *tmp_tfm = NULL;
+       struct crypto_shash **tfm, *tmp_tfm;
        struct shash_desc *desc;
 
        if (type == EVM_XATTR_HMAC) {
@@ -120,16 +120,13 @@ unlock:
 alloc:
        desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(*tfm),
                        GFP_KERNEL);
-       if (!desc) {
-               crypto_free_shash(tmp_tfm);
+       if (!desc)
                return ERR_PTR(-ENOMEM);
-       }
 
        desc->tfm = *tfm;
 
        rc = crypto_shash_init(desc);
        if (rc) {
-               crypto_free_shash(tmp_tfm);
                kfree(desc);
                return ERR_PTR(rc);
        }
index cc88f02..2e6fb6e 100644 (file)
@@ -36,42 +36,36 @@ static const char * const integrity_status_msg[] = {
 int evm_hmac_attrs;
 
 static struct xattr_list evm_config_default_xattrnames[] = {
-       {.name = XATTR_NAME_SELINUX,
-#ifdef CONFIG_SECURITY_SELINUX
-        .enabled = true
-#endif
+       {
+        .name = XATTR_NAME_SELINUX,
+        .enabled = IS_ENABLED(CONFIG_SECURITY_SELINUX)
        },
-       {.name = XATTR_NAME_SMACK,
-#ifdef CONFIG_SECURITY_SMACK
-        .enabled = true
-#endif
+       {
+        .name = XATTR_NAME_SMACK,
+        .enabled = IS_ENABLED(CONFIG_SECURITY_SMACK)
        },
-       {.name = XATTR_NAME_SMACKEXEC,
-#ifdef CONFIG_EVM_EXTRA_SMACK_XATTRS
-        .enabled = true
-#endif
+       {
+        .name = XATTR_NAME_SMACKEXEC,
+        .enabled = IS_ENABLED(CONFIG_EVM_EXTRA_SMACK_XATTRS)
        },
-       {.name = XATTR_NAME_SMACKTRANSMUTE,
-#ifdef CONFIG_EVM_EXTRA_SMACK_XATTRS
-        .enabled = true
-#endif
+       {
+        .name = XATTR_NAME_SMACKTRANSMUTE,
+        .enabled = IS_ENABLED(CONFIG_EVM_EXTRA_SMACK_XATTRS)
        },
-       {.name = XATTR_NAME_SMACKMMAP,
-#ifdef CONFIG_EVM_EXTRA_SMACK_XATTRS
-        .enabled = true
-#endif
+       {
+        .name = XATTR_NAME_SMACKMMAP,
+        .enabled = IS_ENABLED(CONFIG_EVM_EXTRA_SMACK_XATTRS)
        },
-       {.name = XATTR_NAME_APPARMOR,
-#ifdef CONFIG_SECURITY_APPARMOR
-        .enabled = true
-#endif
+       {
+        .name = XATTR_NAME_APPARMOR,
+        .enabled = IS_ENABLED(CONFIG_SECURITY_APPARMOR)
        },
-       {.name = XATTR_NAME_IMA,
-#ifdef CONFIG_IMA_APPRAISE
-        .enabled = true
-#endif
+       {
+        .name = XATTR_NAME_IMA,
+        .enabled = IS_ENABLED(CONFIG_IMA_APPRAISE)
        },
-       {.name = XATTR_NAME_CAPS,
+       {
+        .name = XATTR_NAME_CAPS,
         .enabled = true
        },
 };
@@ -755,13 +749,14 @@ void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
        evm_update_evmxattr(dentry, xattr_name, NULL, 0);
 }
 
-static int evm_attr_change(struct dentry *dentry, struct iattr *attr)
+static int evm_attr_change(struct user_namespace *mnt_userns,
+                          struct dentry *dentry, struct iattr *attr)
 {
        struct inode *inode = d_backing_inode(dentry);
        unsigned int ia_valid = attr->ia_valid;
 
-       if ((!(ia_valid & ATTR_UID) || uid_eq(attr->ia_uid, inode->i_uid)) &&
-           (!(ia_valid & ATTR_GID) || gid_eq(attr->ia_gid, inode->i_gid)) &&
+       if (!i_uid_needs_update(mnt_userns, attr, inode) &&
+           !i_gid_needs_update(mnt_userns, attr, inode) &&
            (!(ia_valid & ATTR_MODE) || attr->ia_mode == inode->i_mode))
                return 0;
 
@@ -775,7 +770,8 @@ static int evm_attr_change(struct dentry *dentry, struct iattr *attr)
  * Permit update of file attributes when files have a valid EVM signature,
  * except in the case of them having an immutable portable signature.
  */
-int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
+int evm_inode_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
+                     struct iattr *attr)
 {
        unsigned int ia_valid = attr->ia_valid;
        enum integrity_status evm_status;
@@ -801,7 +797,7 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
                return 0;
 
        if (evm_status == INTEGRITY_PASS_IMMUTABLE &&
-           !evm_attr_change(dentry, attr))
+           !evm_attr_change(mnt_userns, dentry, attr))
                return 0;
 
        integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry),
index cdb84dc..bde74fc 100644 (file)
@@ -514,7 +514,8 @@ int ima_appraise_measurement(enum ima_hooks func,
                goto out;
        }
 
-       status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, rc, iint);
+       status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value,
+                                rc < 0 ? 0 : rc, iint);
        switch (status) {
        case INTEGRITY_PASS:
        case INTEGRITY_PASS_IMMUTABLE:
index a7206cc..6449905 100644 (file)
@@ -205,6 +205,7 @@ out_array:
 
                crypto_free_shash(ima_algo_array[i].tfm);
        }
+       kfree(ima_algo_array);
 out:
        crypto_free_shash(ima_shash_tfm);
        return rc;
index 71786d0..9db66fe 100644 (file)
@@ -67,6 +67,8 @@ const char * const *arch_get_ima_policy(void)
        if (IS_ENABLED(CONFIG_IMA_ARCH_POLICY) && arch_ima_get_secureboot()) {
                if (IS_ENABLED(CONFIG_MODULE_SIG))
                        set_module_sig_enforced();
+               if (IS_ENABLED(CONFIG_KEXEC_SIG))
+                       set_kexec_sig_enforced();
                return sb_arch_rules;
        }
        return NULL;
index 1375313..419dc40 100644 (file)
@@ -137,7 +137,7 @@ void ima_add_kexec_buffer(struct kimage *image)
 /*
  * Restore the measurement list from the previous kernel.
  */
-void ima_load_kexec_buffer(void)
+void __init ima_load_kexec_buffer(void)
 {
        void *kexec_buffer = NULL;
        size_t kexec_buffer_size = 0;
index 7391741..a8802b8 100644 (file)
@@ -2247,6 +2247,10 @@ bool ima_appraise_signature(enum kernel_read_file_id id)
        if (id >= READING_MAX_ID)
                return false;
 
+       if (id == READING_KEXEC_IMAGE && !(ima_appraise & IMA_APPRAISE_ENFORCE)
+           && security_locked_down(LOCKDOWN_KEXEC))
+               return false;
+
        func = read_idmap[id] ?: FILE_CHECK;
 
        rcu_read_lock();
index c877f01..7bf9b15 100644 (file)
@@ -323,10 +323,10 @@ static int ima_eventdigest_init_common(const u8 *digest, u32 digestsize,
        else
                /*
                 * If digest is NULL, the event being recorded is a violation.
-                * Make room for the digest by increasing the offset of
-                * IMA_DIGEST_SIZE.
+                * Make room for the digest by increasing the offset by the
+                * hash algorithm digest size.
                 */
-               offset += IMA_DIGEST_SIZE;
+               offset += hash_digest_size[hash_algo];
 
        return ima_write_template_field_data(buffer, offset + digestsize,
                                             fmt, field_data);
index 91be65d..70e7985 100644 (file)
@@ -18,3 +18,19 @@ config SECURITY_LOADPIN_ENFORCE
          If selected, LoadPin will enforce pinning at boot. If not
          selected, it can be enabled at boot with the kernel parameter
          "loadpin.enforce=1".
+
+config SECURITY_LOADPIN_VERITY
+       bool "Allow reading files from certain other filesystems that use dm-verity"
+       depends on SECURITY_LOADPIN && DM_VERITY=y && SECURITYFS
+       help
+         If selected LoadPin can allow reading files from filesystems
+         that use dm-verity. LoadPin maintains a list of verity root
+         digests it considers trusted. A verity backed filesystem is
+         considered trusted if its root digest is found in the list
+         of trusted digests.
+
+         The list of trusted verity can be populated through an ioctl
+         on the LoadPin securityfs entry 'dm-verity'. The ioctl
+         expects a file descriptor of a file with verity digests as
+         parameter. The file must be located on the pinned root and
+         contain a comma separated list of digests.
index ad4e675..6ab5f2b 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/path.h>
 #include <linux/sched.h>       /* current */
 #include <linux/string_helpers.h>
+#include <linux/dm-verity-loadpin.h>
+#include <uapi/linux/loadpin.h>
 
 static void report_load(const char *origin, struct file *file, char *operation)
 {
@@ -43,6 +45,9 @@ static char *exclude_read_files[READING_MAX_ID];
 static int ignore_read_file_id[READING_MAX_ID] __ro_after_init;
 static struct super_block *pinned_root;
 static DEFINE_SPINLOCK(pinned_root_spinlock);
+#ifdef CONFIG_SECURITY_LOADPIN_VERITY
+static bool deny_reading_verity_digests;
+#endif
 
 #ifdef CONFIG_SYSCTL
 
@@ -171,7 +176,8 @@ static int loadpin_read_file(struct file *file, enum kernel_read_file_id id,
                spin_unlock(&pinned_root_spinlock);
        }
 
-       if (IS_ERR_OR_NULL(pinned_root) || load_root != pinned_root) {
+       if (IS_ERR_OR_NULL(pinned_root) ||
+           ((load_root != pinned_root) && !dm_verity_loadpin_is_bdev_trusted(load_root->s_bdev))) {
                if (unlikely(!enforce)) {
                        report_load(origin, file, "pinning-ignored");
                        return 0;
@@ -237,6 +243,7 @@ static int __init loadpin_init(void)
                enforce ? "" : "not ");
        parse_exclude();
        security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks), "loadpin");
+
        return 0;
 }
 
@@ -245,6 +252,164 @@ DEFINE_LSM(loadpin) = {
        .init = loadpin_init,
 };
 
+#ifdef CONFIG_SECURITY_LOADPIN_VERITY
+
+enum loadpin_securityfs_interface_index {
+       LOADPIN_DM_VERITY,
+};
+
+static int read_trusted_verity_root_digests(unsigned int fd)
+{
+       struct fd f;
+       void *data;
+       int rc;
+       char *p, *d;
+
+       if (deny_reading_verity_digests)
+               return -EPERM;
+
+       /* The list of trusted root digests can only be set up once */
+       if (!list_empty(&dm_verity_loadpin_trusted_root_digests))
+               return -EPERM;
+
+       f = fdget(fd);
+       if (!f.file)
+               return -EINVAL;
+
+       data = kzalloc(SZ_4K, GFP_KERNEL);
+       if (!data) {
+               rc = -ENOMEM;
+               goto err;
+       }
+
+       rc = kernel_read_file(f.file, 0, (void **)&data, SZ_4K - 1, NULL, READING_POLICY);
+       if (rc < 0)
+               goto err;
+
+       p = data;
+       p[rc] = '\0';
+       p = strim(p);
+
+       p = strim(data);
+       while ((d = strsep(&p, "\n")) != NULL) {
+               int len = strlen(d);
+               struct dm_verity_loadpin_trusted_root_digest *trd;
+
+               if (len % 2) {
+                       rc = -EPROTO;
+                       goto err;
+               }
+
+               len /= 2;
+
+               trd = kzalloc(struct_size(trd, data, len), GFP_KERNEL);
+               if (!trd) {
+                       rc = -ENOMEM;
+                       goto err;
+               }
+
+               if (hex2bin(trd->data, d, len)) {
+                       kfree(trd);
+                       rc = -EPROTO;
+                       goto err;
+               }
+
+               trd->len = len;
+
+               list_add_tail(&trd->node, &dm_verity_loadpin_trusted_root_digests);
+       }
+
+       if (list_empty(&dm_verity_loadpin_trusted_root_digests)) {
+               rc = -EPROTO;
+               goto err;
+       }
+
+       kfree(data);
+       fdput(f);
+
+       return 0;
+
+err:
+       kfree(data);
+
+       /* any failure in loading/parsing invalidates the entire list */
+       {
+               struct dm_verity_loadpin_trusted_root_digest *trd, *tmp;
+
+               list_for_each_entry_safe(trd, tmp, &dm_verity_loadpin_trusted_root_digests, node) {
+                       list_del(&trd->node);
+                       kfree(trd);
+               }
+       }
+
+       /* disallow further attempts after reading a corrupt/invalid file */
+       deny_reading_verity_digests = true;
+
+       fdput(f);
+
+       return rc;
+}
+
+/******************************** securityfs ********************************/
+
+static long dm_verity_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+       void __user *uarg = (void __user *)arg;
+       unsigned int fd;
+       int rc;
+
+       switch (cmd) {
+       case LOADPIN_IOC_SET_TRUSTED_VERITY_DIGESTS:
+               rc = copy_from_user(&fd, uarg, sizeof(fd));
+               if (rc)
+                       return rc;
+
+               return read_trusted_verity_root_digests(fd);
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static const struct file_operations loadpin_dm_verity_ops = {
+       .unlocked_ioctl = dm_verity_ioctl,
+       .compat_ioctl = compat_ptr_ioctl,
+};
+
+/**
+ * init_loadpin_securityfs - create the securityfs directory for LoadPin
+ *
+ * We can not put this method normally under the loadpin_init() code path since
+ * the security subsystem gets initialized before the vfs caches.
+ *
+ * Returns 0 if the securityfs directory creation was successful.
+ */
+static int __init init_loadpin_securityfs(void)
+{
+       struct dentry *loadpin_dir, *dentry;
+
+       loadpin_dir = securityfs_create_dir("loadpin", NULL);
+       if (IS_ERR(loadpin_dir)) {
+               pr_err("LoadPin: could not create securityfs dir: %ld\n",
+                      PTR_ERR(loadpin_dir));
+               return PTR_ERR(loadpin_dir);
+       }
+
+       dentry = securityfs_create_file("dm-verity", 0600, loadpin_dir,
+                                       (void *)LOADPIN_DM_VERITY, &loadpin_dm_verity_ops);
+       if (IS_ERR(dentry)) {
+               pr_err("LoadPin: could not create securityfs entry 'dm-verity': %ld\n",
+                      PTR_ERR(dentry));
+               return PTR_ERR(dentry);
+       }
+
+       return 0;
+}
+
+fs_initcall(init_loadpin_securityfs);
+
+#endif /* CONFIG_SECURITY_LOADPIN_VERITY */
+
 /* Should not be mutable after boot, so not listed in sysfs (perm == 0). */
 module_param(enforce, int, 0);
 MODULE_PARM_DESC(enforce, "Enforce module/firmware pinning");
index 963f4ad..e806739 100644 (file)
@@ -97,15 +97,9 @@ static int safesetid_security_capable(const struct cred *cred,
                return 0;
 
        /*
-        * If CAP_SET{U/G}ID is currently used for a setid() syscall, we want to
-        * let it go through here; the real security check happens later, in the
-        * task_fix_set{u/g}id hook.
-         *
-         * NOTE:
-         * Until we add support for restricting setgroups() calls, GID security
-         * policies offer no meaningful security since we always return 0 here
-         * when called from within the setgroups() syscall and there is no
-         * additional hook later on to enforce security policies for setgroups().
+        * If CAP_SET{U/G}ID is currently used for a setid or setgroups syscall, we
+        * want to let it go through here; the real security check happens later, in
+        * the task_fix_set{u/g}id or task_fix_setgroups hooks.
         */
        if ((opts & CAP_OPT_INSETID) != 0)
                return 0;
@@ -241,9 +235,36 @@ static int safesetid_task_fix_setgid(struct cred *new,
        return -EACCES;
 }
 
+static int safesetid_task_fix_setgroups(struct cred *new, const struct cred *old)
+{
+       int i;
+
+       /* Do nothing if there are no setgid restrictions for our old RGID. */
+       if (setid_policy_lookup((kid_t){.gid = old->gid}, INVALID_ID, GID) == SIDPOL_DEFAULT)
+               return 0;
+
+       get_group_info(new->group_info);
+       for (i = 0; i < new->group_info->ngroups; i++) {
+               if (!id_permitted_for_cred(old, (kid_t){.gid = new->group_info->gid[i]}, GID)) {
+                       put_group_info(new->group_info);
+                       /*
+                        * Kill this process to avoid potential security vulnerabilities
+                        * that could arise from a missing allowlist entry preventing a
+                        * privileged process from dropping to a lesser-privileged one.
+                        */
+                       force_sig(SIGKILL);
+                       return -EACCES;
+               }
+       }
+
+       put_group_info(new->group_info);
+       return 0;
+}
+
 static struct security_hook_list safesetid_security_hooks[] = {
        LSM_HOOK_INIT(task_fix_setuid, safesetid_task_fix_setuid),
        LSM_HOOK_INIT(task_fix_setgid, safesetid_task_fix_setgid),
+       LSM_HOOK_INIT(task_fix_setgroups, safesetid_task_fix_setgroups),
        LSM_HOOK_INIT(capable, safesetid_security_capable)
 };
 
index 188b8f7..14d30fe 100644 (file)
@@ -1324,7 +1324,8 @@ int security_inode_permission(struct inode *inode, int mask)
        return call_int_hook(inode_permission, 0, inode, mask);
 }
 
-int security_inode_setattr(struct dentry *dentry, struct iattr *attr)
+int security_inode_setattr(struct user_namespace *mnt_userns,
+                          struct dentry *dentry, struct iattr *attr)
 {
        int ret;
 
@@ -1333,7 +1334,7 @@ int security_inode_setattr(struct dentry *dentry, struct iattr *attr)
        ret = call_int_hook(inode_setattr, 0, dentry, attr);
        if (ret)
                return ret;
-       return evm_inode_setattr(dentry, attr);
+       return evm_inode_setattr(mnt_userns, dentry, attr);
 }
 EXPORT_SYMBOL_GPL(security_inode_setattr);
 
@@ -1803,6 +1804,11 @@ int security_task_fix_setgid(struct cred *new, const struct cred *old,
        return call_int_hook(task_fix_setgid, 0, new, old, flags);
 }
 
+int security_task_fix_setgroups(struct cred *new, const struct cred *old)
+{
+       return call_int_hook(task_fix_setgroups, 0, new, old);
+}
+
 int security_task_setpgid(struct task_struct *p, pid_t pgid)
 {
        return call_int_hook(task_setpgid, 0, p, pgid);
index 1bbd533..7957350 100644 (file)
@@ -640,7 +640,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
         * we need to skip the double mount verification.
         *
         * This does open a hole in which we will not notice if the first
-        * mount using this sb set explict options and a second mount using
+        * mount using this sb set explicit options and a second mount using
         * this sb does not set any security options.  (The first options
         * will be used for both mounts)
         */
@@ -944,10 +944,12 @@ out:
        return rc;
 }
 
+/*
+ * NOTE: the caller is resposible for freeing the memory even if on error.
+ */
 static int selinux_add_opt(int token, const char *s, void **mnt_opts)
 {
        struct selinux_mnt_opts *opts = *mnt_opts;
-       bool is_alloc_opts = false;
        u32 *dst_sid;
        int rc;
 
@@ -955,7 +957,7 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts)
                /* eaten and completely ignored */
                return 0;
        if (!s)
-               return -ENOMEM;
+               return -EINVAL;
 
        if (!selinux_initialized(&selinux_state)) {
                pr_warn("SELinux: Unable to set superblock options before the security server is initialized\n");
@@ -967,7 +969,6 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts)
                if (!opts)
                        return -ENOMEM;
                *mnt_opts = opts;
-               is_alloc_opts = true;
        }
 
        switch (token) {
@@ -1002,10 +1003,6 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts)
        return rc;
 
 err:
-       if (is_alloc_opts) {
-               kfree(opts);
-               *mnt_opts = NULL;
-       }
        pr_warn(SEL_MOUNT_FAIL_MSG);
        return -EINVAL;
 }
@@ -1019,7 +1016,7 @@ static int show_sid(struct seq_file *m, u32 sid)
        rc = security_sid_to_context(&selinux_state, sid,
                                             &context, &len);
        if (!rc) {
-               bool has_comma = context && strchr(context, ',');
+               bool has_comma = strchr(context, ',');
 
                seq_putc(m, '=');
                if (has_comma)
@@ -6792,7 +6789,7 @@ static u32 bpf_map_fmode_to_av(fmode_t fmode)
 }
 
 /* This function will check the file pass through unix socket or binder to see
- * if it is a bpf related object. And apply correspinding checks on the bpf
+ * if it is a bpf related object. And apply corresponding checks on the bpf
  * object based on the type. The bpf maps and programs, not like other files and
  * socket, are using a shared anonymous inode inside the kernel as their inode.
  * So checking that inode cannot identify if the process have privilege to
index 1cba83d..406bceb 100644 (file)
@@ -18,7 +18,7 @@
 /**
  *     selinux_audit_rule_init - alloc/init an selinux audit rule structure.
  *     @field: the field this rule refers to
- *     @op: the operater the rule uses
+ *     @op: the operator the rule uses
  *     @rulestr: the text "target" of the rule
  *     @rule: pointer to the new rule structure returned via this
  *
index 2b372f9..5525b94 100644 (file)
@@ -53,7 +53,7 @@ struct selinux_audit_data {
        u32 denied;
        int result;
        struct selinux_state *state;
-};
+} __randomize_layout;
 
 /*
  * AVC operations
index c24d4e1..ffc4e7b 100644 (file)
@@ -370,6 +370,8 @@ static inline int put_entry(const void *buf, size_t bytes, int num, struct polic
 {
        size_t len = bytes * num;
 
+       if (len > fp->len)
+               return -EINVAL;
        memcpy(fp->data, buf, len);
        fp->data += len;
        fp->len -= len;
index 69b2734..fe5fcf5 100644 (file)
@@ -4048,6 +4048,7 @@ int security_read_policy(struct selinux_state *state,
 int security_read_state_kernel(struct selinux_state *state,
                               void **data, size_t *len)
 {
+       int err;
        struct selinux_policy *policy;
 
        policy = rcu_dereference_protected(
@@ -4060,5 +4061,11 @@ int security_read_state_kernel(struct selinux_state *state,
        if (!*data)
                return -ENOMEM;
 
-       return __security_read_policy(policy, *data, len);
+       err = __security_read_policy(policy, *data, len);
+       if (err) {
+               vfree(*data);
+               *data = NULL;
+               *len = 0;
+       }
+       return err;
 }
index d2186e2..585e5e3 100644 (file)
@@ -465,12 +465,9 @@ char *smk_parse_smack(const char *string, int len)
        if (i == 0 || i >= SMK_LONGLABEL)
                return ERR_PTR(-EINVAL);
 
-       smack = kzalloc(i + 1, GFP_NOFS);
-       if (smack == NULL)
+       smack = kstrndup(string, i, GFP_NOFS);
+       if (!smack)
                return ERR_PTR(-ENOMEM);
-
-       strncpy(smack, string, i);
-
        return smack;
 }
 
index 6207762..0018314 100644 (file)
@@ -766,13 +766,6 @@ static int smack_set_mnt_opts(struct super_block *sb,
        if (sp->smk_flags & SMK_SB_INITIALIZED)
                return 0;
 
-       if (inode->i_security == NULL) {
-               int rc = lsm_inode_alloc(inode);
-
-               if (rc)
-                       return rc;
-       }
-
        if (!smack_privileged(CAP_MAC_ADMIN)) {
                /*
                 * Unprivileged mounts don't get to specify Smack values.
index bd60308..8634004 100644 (file)
@@ -74,36 +74,36 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci,
        err = snd_cs46xx_create(card, pci,
                                external_amp[dev], thinkpad[dev]);
        if (err < 0)
-               return err;
+               goto error;
        card->private_data = chip;
        chip->accept_valid = mmap_valid[dev];
        err = snd_cs46xx_pcm(chip, 0);
        if (err < 0)
-               return err;
+               goto error;
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
        err = snd_cs46xx_pcm_rear(chip, 1);
        if (err < 0)
-               return err;
+               goto error;
        err = snd_cs46xx_pcm_iec958(chip, 2);
        if (err < 0)
-               return err;
+               goto error;
 #endif
        err = snd_cs46xx_mixer(chip, 2);
        if (err < 0)
-               return err;
+               goto error;
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
        if (chip->nr_ac97_codecs ==2) {
                err = snd_cs46xx_pcm_center_lfe(chip, 3);
                if (err < 0)
-                       return err;
+                       goto error;
        }
 #endif
        err = snd_cs46xx_midi(chip, 0);
        if (err < 0)
-               return err;
+               goto error;
        err = snd_cs46xx_start_dsp(chip);
        if (err < 0)
-               return err;
+               goto error;
 
        snd_cs46xx_gameport(chip);
 
@@ -117,11 +117,15 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci,
 
        err = snd_card_register(card);
        if (err < 0)
-               return err;
+               goto error;
 
        pci_set_drvdata(pci, card);
        dev++;
        return 0;
+
+ error:
+       snd_card_free(card);
+       return err;
 }
 
 static struct pci_driver cs46xx_driver = {
index 3e541a4..83ae21a 100644 (file)
@@ -944,6 +944,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
        SND_PCI_QUIRK(0x103c, 0x828c, "HP EliteBook 840 G4", CXT_FIXUP_HP_DOCK),
        SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x103c, 0x82b4, "HP ProDesk 600 G3", CXT_FIXUP_HP_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x836e, "HP ProBook 455 G5", CXT_FIXUP_MUTE_LED_GPIO),
        SND_PCI_QUIRK(0x103c, 0x837f, "HP ProBook 470 G5", CXT_FIXUP_MUTE_LED_GPIO),
        SND_PCI_QUIRK(0x103c, 0x83b2, "HP EliteBook 840 G5", CXT_FIXUP_HP_DOCK),
index cee69fa..2f55bc4 100644 (file)
@@ -6901,6 +6901,7 @@ enum {
        ALC298_FIXUP_LENOVO_SPK_VOLUME,
        ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER,
        ALC269_FIXUP_ATIV_BOOK_8,
+       ALC221_FIXUP_HP_288PRO_MIC_NO_PRESENCE,
        ALC221_FIXUP_HP_MIC_NO_PRESENCE,
        ALC256_FIXUP_ASUS_HEADSET_MODE,
        ALC256_FIXUP_ASUS_MIC,
@@ -7837,6 +7838,16 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC269_FIXUP_NO_SHUTUP
        },
+       [ALC221_FIXUP_HP_288PRO_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { 0x1a, 0x01813030 }, /* use as headphone mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE
+       },
        [ALC221_FIXUP_HP_MIC_NO_PRESENCE] = {
                .type = HDA_FIXUP_PINS,
                .v.pins = (const struct hda_pintbl[]) {
@@ -8886,6 +8897,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x1290, "Acer Veriton Z4860G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
        SND_PCI_QUIRK(0x1025, 0x1291, "Acer Veriton Z4660G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
        SND_PCI_QUIRK(0x1025, 0x129c, "Acer SWIFT SF314-55", ALC256_FIXUP_ACER_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1025, 0x129d, "Acer SWIFT SF313-51", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1025, 0x1300, "Acer SWIFT SF314-56", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1025, 0x1308, "Acer Aspire Z24-890", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
        SND_PCI_QUIRK(0x1025, 0x132a, "Acer TravelMate B114-21", ALC233_FIXUP_ACER_HEADSET_MIC),
@@ -8895,6 +8907,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x1430, "Acer TravelMate B311R-31", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1025, 0x1466, "Acer Aspire A515-56", ALC255_FIXUP_ACER_HEADPHONE_AND_MIC),
        SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
+       SND_PCI_QUIRK(0x1028, 0x053c, "Dell Latitude E5430", ALC292_FIXUP_DELL_E7X),
        SND_PCI_QUIRK(0x1028, 0x054b, "Dell XPS one 2710", ALC275_FIXUP_DELL_XPS),
        SND_PCI_QUIRK(0x1028, 0x05bd, "Dell Latitude E6440", ALC292_FIXUP_DELL_E7X),
        SND_PCI_QUIRK(0x1028, 0x05be, "Dell Latitude E6540", ALC292_FIXUP_DELL_E7X),
@@ -9010,6 +9023,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x2335, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x2336, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x2337, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2b5e, "HP 288 Pro G2 MT", ALC221_FIXUP_HP_288PRO_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x802e, "HP Z240 SFF", ALC221_FIXUP_HP_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x802f, "HP Z240", ALC221_FIXUP_HP_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x8077, "HP", ALC256_FIXUP_HP_HEADSET_MIC),
@@ -9096,6 +9110,10 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x89c6, "Zbook Fury 17 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x89ca, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
        SND_PCI_QUIRK(0x103c, 0x8a78, "HP Dev One", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x103c, 0x8aa0, "HP ProBook 440 G9 (MB 8A9E)", ALC236_FIXUP_HP_GPIO_LED),
+       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(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
        SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
        SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -9212,6 +9230,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1558, 0x70f4, "Clevo NH77EPY", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x70f6, "Clevo NH77DPQ-Y", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x7716, "Clevo NS50PU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x7718, "Clevo L140PU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x8228, "Clevo NR40BU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x8520, "Clevo NH50D[CD]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x8521, "Clevo NH77D[CD]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
@@ -9354,6 +9373,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1d72, 0x1602, "RedmiBook", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
        SND_PCI_QUIRK(0x1d72, 0x1701, "XiaomiNotebook Pro", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1d72, 0x1901, "RedmiBook 14", ALC256_FIXUP_ASUS_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1d72, 0x1945, "Redmi G", ALC256_FIXUP_ASUS_HEADSET_MIC),
        SND_PCI_QUIRK(0x1d72, 0x1947, "RedmiBook Air", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
        SND_PCI_QUIRK(0x8086, 0x2074, "Intel NUC 8", ALC233_FIXUP_INTEL_NUC8_DMIC),
        SND_PCI_QUIRK(0x8086, 0x2080, "Intel NUC 8 Rugged", ALC256_FIXUP_INTEL_NUC8_RUGGED),
@@ -11216,6 +11236,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
        SND_PCI_QUIRK(0x103c, 0x8719, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
        SND_PCI_QUIRK(0x103c, 0x873e, "HP", ALC671_FIXUP_HP_HEADSET_MIC2),
+       SND_PCI_QUIRK(0x103c, 0x877e, "HP 288 Pro G6", ALC671_FIXUP_HP_HEADSET_MIC2),
        SND_PCI_QUIRK(0x103c, 0x885f, "HP 288 Pro G8", ALC671_FIXUP_HP_HEADSET_MIC2),
        SND_PCI_QUIRK(0x1043, 0x1080, "Asus UX501VW", ALC668_FIXUP_HEADSET_MODE),
        SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50),
index 55e773f..93606e5 100644 (file)
@@ -868,10 +868,12 @@ static void ak4613_parse_of(struct ak4613_priv *priv,
 
        /*
         * connected STDI
+        * TDM support is assuming it is probed via Audio-Graph-Card style here.
+        * Default is SDTIx1 if it was probed via Simple-Audio-Card for now.
         */
        sdti_num = of_graph_get_endpoint_count(np);
-       if (WARN_ON((sdti_num > 3) || (sdti_num < 1)))
-               return;
+       if ((sdti_num >= SDTx_MAX) || (sdti_num < 1))
+               sdti_num = 1;
 
        AK4613_CONFIG_SDTI_set(priv, sdti_num);
 }
index e32871b..7434aee 100644 (file)
@@ -1760,8 +1760,8 @@ static bool arizona_aif_cfg_changed(struct snd_soc_component *component,
        if (bclk != (val & ARIZONA_AIF1_BCLK_FREQ_MASK))
                return true;
 
-       val = snd_soc_component_read(component, base + ARIZONA_AIF_TX_BCLK_RATE);
-       if (lrclk != (val & ARIZONA_AIF1TX_BCPF_MASK))
+       val = snd_soc_component_read(component, base + ARIZONA_AIF_RX_BCLK_RATE);
+       if (lrclk != (val & ARIZONA_AIF1RX_BCPF_MASK))
                return true;
 
        val = snd_soc_component_read(component, base + ARIZONA_AIF_FRAME_CTRL_1);
index 6d3070e..198cfe5 100644 (file)
@@ -37,8 +37,8 @@ static const struct reg_default cs35l41_reg[] = {
        { CS35L41_DAC_PCM1_SRC,                 0x00000008 },
        { CS35L41_ASP_TX1_SRC,                  0x00000018 },
        { CS35L41_ASP_TX2_SRC,                  0x00000019 },
-       { CS35L41_ASP_TX3_SRC,                  0x00000020 },
-       { CS35L41_ASP_TX4_SRC,                  0x00000021 },
+       { CS35L41_ASP_TX3_SRC,                  0x00000000 },
+       { CS35L41_ASP_TX4_SRC,                  0x00000000 },
        { CS35L41_DSP1_RX1_SRC,                 0x00000008 },
        { CS35L41_DSP1_RX2_SRC,                 0x00000009 },
        { CS35L41_DSP1_RX3_SRC,                 0x00000018 },
@@ -644,6 +644,8 @@ static const struct reg_sequence cs35l41_reva0_errata_patch[] = {
        { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 },
        { CS35L41_PWR_CTRL2,             0x00000000 },
        { CS35L41_AMP_GAIN_CTRL,         0x00000000 },
+       { CS35L41_ASP_TX3_SRC,           0x00000000 },
+       { CS35L41_ASP_TX4_SRC,           0x00000000 },
 };
 
 static const struct reg_sequence cs35l41_revb0_errata_patch[] = {
@@ -655,6 +657,8 @@ static const struct reg_sequence cs35l41_revb0_errata_patch[] = {
        { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 },
        { CS35L41_PWR_CTRL2,             0x00000000 },
        { CS35L41_AMP_GAIN_CTRL,         0x00000000 },
+       { CS35L41_ASP_TX3_SRC,           0x00000000 },
+       { CS35L41_ASP_TX4_SRC,           0x00000000 },
 };
 
 static const struct reg_sequence cs35l41_revb2_errata_patch[] = {
@@ -666,6 +670,8 @@ static const struct reg_sequence cs35l41_revb2_errata_patch[] = {
        { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 },
        { CS35L41_PWR_CTRL2,             0x00000000 },
        { CS35L41_AMP_GAIN_CTRL,         0x00000000 },
+       { CS35L41_ASP_TX3_SRC,           0x00000000 },
+       { CS35L41_ASP_TX4_SRC,           0x00000000 },
 };
 
 static const struct reg_sequence cs35l41_fs_errata_patch[] = {
index 3e68a07..71ab2a5 100644 (file)
@@ -333,7 +333,7 @@ static const struct snd_kcontrol_new cs35l41_aud_controls[] = {
        SOC_SINGLE("HW Noise Gate Enable", CS35L41_NG_CFG, 8, 63, 0),
        SOC_SINGLE("HW Noise Gate Delay", CS35L41_NG_CFG, 4, 7, 0),
        SOC_SINGLE("HW Noise Gate Threshold", CS35L41_NG_CFG, 0, 7, 0),
-       SOC_SINGLE("Aux Noise Gate CH1 Enable",
+       SOC_SINGLE("Aux Noise Gate CH1 Switch",
                   CS35L41_MIXER_NGATE_CH1_CFG, 16, 1, 0),
        SOC_SINGLE("Aux Noise Gate CH1 Entry Delay",
                   CS35L41_MIXER_NGATE_CH1_CFG, 8, 15, 0),
@@ -341,15 +341,15 @@ static const struct snd_kcontrol_new cs35l41_aud_controls[] = {
                   CS35L41_MIXER_NGATE_CH1_CFG, 0, 7, 0),
        SOC_SINGLE("Aux Noise Gate CH2 Entry Delay",
                   CS35L41_MIXER_NGATE_CH2_CFG, 8, 15, 0),
-       SOC_SINGLE("Aux Noise Gate CH2 Enable",
+       SOC_SINGLE("Aux Noise Gate CH2 Switch",
                   CS35L41_MIXER_NGATE_CH2_CFG, 16, 1, 0),
        SOC_SINGLE("Aux Noise Gate CH2 Threshold",
                   CS35L41_MIXER_NGATE_CH2_CFG, 0, 7, 0),
-       SOC_SINGLE("SCLK Force", CS35L41_SP_FORMAT, CS35L41_SCLK_FRC_SHIFT, 1, 0),
-       SOC_SINGLE("LRCLK Force", CS35L41_SP_FORMAT, CS35L41_LRCLK_FRC_SHIFT, 1, 0),
-       SOC_SINGLE("Invert Class D", CS35L41_AMP_DIG_VOL_CTRL,
+       SOC_SINGLE("SCLK Force Switch", CS35L41_SP_FORMAT, CS35L41_SCLK_FRC_SHIFT, 1, 0),
+       SOC_SINGLE("LRCLK Force Switch", CS35L41_SP_FORMAT, CS35L41_LRCLK_FRC_SHIFT, 1, 0),
+       SOC_SINGLE("Invert Class D Switch", CS35L41_AMP_DIG_VOL_CTRL,
                   CS35L41_AMP_INV_PCM_SHIFT, 1, 0),
-       SOC_SINGLE("Amp Gain ZC", CS35L41_AMP_GAIN_CTRL,
+       SOC_SINGLE("Amp Gain ZC Switch", CS35L41_AMP_GAIN_CTRL,
                   CS35L41_AMP_GAIN_ZC_SHIFT, 1, 0),
        WM_ADSP2_PRELOAD_SWITCH("DSP1", 1),
        WM_ADSP_FW_CONTROL("DSP1", 0),
index 391fd7d..1c7d52b 100644 (file)
@@ -122,6 +122,9 @@ static int cs47l15_in1_adc_put(struct snd_kcontrol *kcontrol,
                snd_soc_kcontrol_component(kcontrol);
        struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component);
 
+       if (!!ucontrol->value.integer.value[0] == cs47l15->in1_lp_mode)
+               return 0;
+
        switch (ucontrol->value.integer.value[0]) {
        case 0:
                /* Set IN1 to normal mode */
@@ -150,7 +153,7 @@ static int cs47l15_in1_adc_put(struct snd_kcontrol *kcontrol,
                break;
        }
 
-       return 0;
+       return 1;
 }
 
 static const struct snd_kcontrol_new cs47l15_snd_controls[] = {
index a1b8dcd..444026b 100644 (file)
@@ -119,7 +119,13 @@ static int cs47l92_put_demux(struct snd_kcontrol *kcontrol,
 end:
        snd_soc_dapm_mutex_unlock(dapm);
 
-       return snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL);
+       ret = snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL);
+       if (ret < 0) {
+               dev_err(madera->dev, "Failed to update demux power state: %d\n", ret);
+               return ret;
+       }
+
+       return change;
 }
 
 static SOC_ENUM_SINGLE_DECL(cs47l92_outdemux_enum,
index 272041c..b9f19fb 100644 (file)
@@ -618,7 +618,13 @@ int madera_out1_demux_put(struct snd_kcontrol *kcontrol,
 end:
        snd_soc_dapm_mutex_unlock(dapm);
 
-       return snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL);
+       ret = snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL);
+       if (ret < 0) {
+               dev_err(madera->dev, "Failed to update demux power state: %d\n", ret);
+               return ret;
+       }
+
+       return change;
 }
 EXPORT_SYMBOL_GPL(madera_out1_demux_put);
 
@@ -893,7 +899,7 @@ static int madera_adsp_rate_put(struct snd_kcontrol *kcontrol,
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        const int adsp_num = e->shift_l;
        const unsigned int item = ucontrol->value.enumerated.item[0];
-       int ret;
+       int ret = 0;
 
        if (item >= e->items)
                return -EINVAL;
@@ -910,10 +916,10 @@ static int madera_adsp_rate_put(struct snd_kcontrol *kcontrol,
                         "Cannot change '%s' while in use by active audio paths\n",
                         kcontrol->id.name);
                ret = -EBUSY;
-       } else {
+       } else if (priv->adsp_rate_cache[adsp_num] != e->values[item]) {
                /* Volatile register so defer until the codec is powered up */
                priv->adsp_rate_cache[adsp_num] = e->values[item];
-               ret = 0;
+               ret = 1;
        }
 
        mutex_unlock(&priv->rate_lock);
index f47e956..97b6447 100644 (file)
@@ -862,6 +862,16 @@ static int max98373_sdw_probe(struct sdw_slave *slave,
        return max98373_init(slave, regmap);
 }
 
+static int max98373_sdw_remove(struct sdw_slave *slave)
+{
+       struct max98373_priv *max98373 = dev_get_drvdata(&slave->dev);
+
+       if (max98373->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
+       return 0;
+}
+
 #if defined(CONFIG_OF)
 static const struct of_device_id max98373_of_match[] = {
        { .compatible = "maxim,max98373", },
@@ -893,7 +903,7 @@ static struct sdw_driver max98373_sdw_driver = {
                .pm = &max98373_pm,
        },
        .probe = max98373_sdw_probe,
-       .remove = NULL,
+       .remove = max98373_sdw_remove,
        .ops = &max98373_slave_ops,
        .id_table = max98373_id,
 };
index 56eb62b..34db388 100644 (file)
@@ -342,12 +342,15 @@ static int max98396_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
        struct snd_soc_component *component = codec_dai->component;
        struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component);
-       unsigned int format = 0;
+       unsigned int format_mask, format = 0;
        unsigned int bclk_pol = 0;
        int ret, status;
        int reg;
        bool update = false;
 
+       format_mask = MAX98396_PCM_MODE_CFG_FORMAT_MASK |
+                     MAX98396_PCM_MODE_CFG_LRCLKEDGE;
+
        dev_dbg(component->dev, "%s: fmt 0x%08X\n", __func__, fmt);
 
        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
@@ -395,7 +398,7 @@ static int max98396_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
                ret = regmap_read(max98396->regmap, MAX98396_R2041_PCM_MODE_CFG, &reg);
                if (ret < 0)
                        return -EINVAL;
-               if (format != (reg & MAX98396_PCM_BCLKEDGE_BSEL_MASK)) {
+               if (format != (reg & format_mask)) {
                        update = true;
                } else {
                        ret = regmap_read(max98396->regmap,
@@ -412,8 +415,7 @@ static int max98396_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 
        regmap_update_bits(max98396->regmap,
                           MAX98396_R2041_PCM_MODE_CFG,
-                          MAX98396_PCM_BCLKEDGE_BSEL_MASK,
-                          format);
+                          format_mask, format);
 
        regmap_update_bits(max98396->regmap,
                           MAX98396_R2042_PCM_CLK_SETUP,
index 1c11b42..72f673f 100644 (file)
@@ -691,6 +691,16 @@ static int rt1308_sdw_probe(struct sdw_slave *slave,
        return 0;
 }
 
+static int rt1308_sdw_remove(struct sdw_slave *slave)
+{
+       struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(&slave->dev);
+
+       if (rt1308->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
+       return 0;
+}
+
 static const struct sdw_device_id rt1308_id[] = {
        SDW_SLAVE_ENTRY_EXT(0x025d, 0x1308, 0x2, 0, 0),
        {},
@@ -750,6 +760,7 @@ static struct sdw_driver rt1308_sdw_driver = {
                .pm = &rt1308_pm,
        },
        .probe = rt1308_sdw_probe,
+       .remove = rt1308_sdw_remove,
        .ops = &rt1308_slave_ops,
        .id_table = rt1308_id,
 };
index 60baa9f..2d6b5f9 100644 (file)
@@ -676,6 +676,16 @@ static int rt1316_sdw_probe(struct sdw_slave *slave,
        return rt1316_sdw_init(&slave->dev, regmap, slave);
 }
 
+static int rt1316_sdw_remove(struct sdw_slave *slave)
+{
+       struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(&slave->dev);
+
+       if (rt1316->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
+       return 0;
+}
+
 static const struct sdw_device_id rt1316_id[] = {
        SDW_SLAVE_ENTRY_EXT(0x025d, 0x1316, 0x3, 0x1, 0),
        {},
@@ -735,6 +745,7 @@ static struct sdw_driver rt1316_sdw_driver = {
                .pm = &rt1316_pm,
        },
        .probe = rt1316_sdw_probe,
+       .remove = rt1316_sdw_remove,
        .ops = &rt1316_slave_ops,
        .id_table = rt1316_id,
 };
index 69c80d8..18b3da9 100644 (file)
@@ -1984,7 +1984,12 @@ static int rt5640_set_bias_level(struct snd_soc_component *component,
                snd_soc_component_write(component, RT5640_PWR_DIG2, 0x0000);
                snd_soc_component_write(component, RT5640_PWR_VOL, 0x0000);
                snd_soc_component_write(component, RT5640_PWR_MIXER, 0x0000);
-               snd_soc_component_write(component, RT5640_PWR_ANLG1, 0x0000);
+               if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER)
+                       snd_soc_component_write(component, RT5640_PWR_ANLG1,
+                               0x0018);
+               else
+                       snd_soc_component_write(component, RT5640_PWR_ANLG1,
+                               0x0000);
                snd_soc_component_write(component, RT5640_PWR_ANLG2, 0x0000);
                break;
 
@@ -2393,9 +2398,15 @@ static void rt5640_jack_work(struct work_struct *work)
 static irqreturn_t rt5640_irq(int irq, void *data)
 {
        struct rt5640_priv *rt5640 = data;
+       int delay = 0;
+
+       if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER) {
+               cancel_delayed_work_sync(&rt5640->jack_work);
+               delay = 100;
+       }
 
        if (rt5640->jack)
-               queue_delayed_work(system_long_wq, &rt5640->jack_work, 0);
+               queue_delayed_work(system_long_wq, &rt5640->jack_work, delay);
 
        return IRQ_HANDLED;
 }
@@ -2580,6 +2591,12 @@ static void rt5640_enable_hda_jack_detect(
 
        snd_soc_component_update_bits(component, RT5640_DUMMY1, 0x400, 0x0);
 
+       snd_soc_component_update_bits(component, RT5640_PWR_ANLG1,
+               RT5640_PWR_VREF2, RT5640_PWR_VREF2);
+       usleep_range(10000, 15000);
+       snd_soc_component_update_bits(component, RT5640_PWR_ANLG1,
+               RT5640_PWR_FV2, RT5640_PWR_FV2);
+
        rt5640->jack = jack;
 
        ret = request_irq(rt5640->irq, rt5640_irq,
@@ -2696,16 +2713,13 @@ static int rt5640_probe(struct snd_soc_component *component)
 
        if (device_property_read_u32(component->dev,
                                     "realtek,jack-detect-source", &val) == 0) {
-               if (val <= RT5640_JD_SRC_GPIO4) {
+               if (val <= RT5640_JD_SRC_GPIO4)
                        rt5640->jd_src = val << RT5640_JD_SFT;
-               } else if (val == RT5640_JD_SRC_HDA_HEADER) {
+               else if (val == RT5640_JD_SRC_HDA_HEADER)
                        rt5640->jd_src = RT5640_JD_SRC_HDA_HEADER;
-                       snd_soc_component_update_bits(component, RT5640_DUMMY1,
-                               0x0300, 0x0);
-               } else {
+               else
                        dev_warn(component->dev, "Warning: Invalid jack-detect-source value: %d, leaving jack-detect disabled\n",
                                 val);
-               }
        }
 
        if (!device_property_read_bool(component->dev, "realtek,jack-detect-not-inverted"))
index 248257a..f04e18c 100644 (file)
@@ -719,9 +719,12 @@ static int rt5682_sdw_remove(struct sdw_slave *slave)
 {
        struct rt5682_priv *rt5682 = dev_get_drvdata(&slave->dev);
 
-       if (rt5682 && rt5682->hw_init)
+       if (rt5682->hw_init)
                cancel_delayed_work_sync(&rt5682->jack_detect_work);
 
+       if (rt5682->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
        return 0;
 }
 
index bda5948..f7439e4 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/soundwire/sdw_type.h>
 #include <linux/soundwire/sdw_registers.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <sound/soc.h>
 #include "rt700.h"
@@ -463,11 +464,14 @@ static int rt700_sdw_remove(struct sdw_slave *slave)
 {
        struct rt700_priv *rt700 = dev_get_drvdata(&slave->dev);
 
-       if (rt700 && rt700->hw_init) {
+       if (rt700->hw_init) {
                cancel_delayed_work_sync(&rt700->jack_detect_work);
                cancel_delayed_work_sync(&rt700->jack_btn_check_work);
        }
 
+       if (rt700->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
        return 0;
 }
 
index af32295..9bceeeb 100644 (file)
@@ -162,7 +162,7 @@ static void rt700_jack_detect_handler(struct work_struct *work)
        if (!rt700->hs_jack)
                return;
 
-       if (!rt700->component->card->instantiated)
+       if (!rt700->component->card || !rt700->component->card->instantiated)
                return;
 
        reg = RT700_VERB_GET_PIN_SENSE | RT700_HP_OUT;
@@ -315,17 +315,27 @@ static int rt700_set_jack_detect(struct snd_soc_component *component,
        struct snd_soc_jack *hs_jack, void *data)
 {
        struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component);
+       int ret;
 
        rt700->hs_jack = hs_jack;
 
-       if (!rt700->hw_init) {
-               dev_dbg(&rt700->slave->dev,
-                       "%s hw_init not ready yet\n", __func__);
+       ret = pm_runtime_resume_and_get(component->dev);
+       if (ret < 0) {
+               if (ret != -EACCES) {
+                       dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret);
+                       return ret;
+               }
+
+               /* pm_runtime not enabled yet */
+               dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__);
                return 0;
        }
 
        rt700_jack_init(rt700);
 
+       pm_runtime_mark_last_busy(component->dev);
+       pm_runtime_put_autosuspend(component->dev);
+
        return 0;
 }
 
@@ -1115,6 +1125,11 @@ int rt700_init(struct device *dev, struct regmap *sdw_regmap,
 
        mutex_init(&rt700->disable_irq_lock);
 
+       INIT_DELAYED_WORK(&rt700->jack_detect_work,
+                         rt700_jack_detect_handler);
+       INIT_DELAYED_WORK(&rt700->jack_btn_check_work,
+                         rt700_btn_check_handler);
+
        /*
         * Mark hw_init to false
         * HW init will be performed when device reports present
@@ -1209,13 +1224,6 @@ int rt700_io_init(struct device *dev, struct sdw_slave *slave)
        /* Finish Initial Settings, set power to D3 */
        regmap_write(rt700->regmap, RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
 
-       if (!rt700->first_hw_init) {
-               INIT_DELAYED_WORK(&rt700->jack_detect_work,
-                       rt700_jack_detect_handler);
-               INIT_DELAYED_WORK(&rt700->jack_btn_check_work,
-                       rt700_btn_check_handler);
-       }
-
        /*
         * if set_jack callback occurred early than io_init,
         * we set up the jack detection function now
index aaf5af1..a085b2f 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/mod_devicetable.h>
 #include <linux/soundwire/sdw_registers.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 
 #include "rt711-sdca.h"
 #include "rt711-sdca-sdw.h"
@@ -364,11 +365,17 @@ static int rt711_sdca_sdw_remove(struct sdw_slave *slave)
 {
        struct rt711_sdca_priv *rt711 = dev_get_drvdata(&slave->dev);
 
-       if (rt711 && rt711->hw_init) {
+       if (rt711->hw_init) {
                cancel_delayed_work_sync(&rt711->jack_detect_work);
                cancel_delayed_work_sync(&rt711->jack_btn_check_work);
        }
 
+       if (rt711->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
+       mutex_destroy(&rt711->calibrate_mutex);
+       mutex_destroy(&rt711->disable_irq_lock);
+
        return 0;
 }
 
index 57629c1..5ad53bb 100644 (file)
@@ -34,7 +34,7 @@ static int rt711_sdca_index_write(struct rt711_sdca_priv *rt711,
 
        ret = regmap_write(regmap, addr, value);
        if (ret < 0)
-               dev_err(rt711->component->dev,
+               dev_err(&rt711->slave->dev,
                        "Failed to set private value: %06x <= %04x ret=%d\n",
                        addr, value, ret);
 
@@ -50,7 +50,7 @@ static int rt711_sdca_index_read(struct rt711_sdca_priv *rt711,
 
        ret = regmap_read(regmap, addr, value);
        if (ret < 0)
-               dev_err(rt711->component->dev,
+               dev_err(&rt711->slave->dev,
                        "Failed to get private value: %06x => %04x ret=%d\n",
                        addr, *value, ret);
 
@@ -294,7 +294,7 @@ static void rt711_sdca_jack_detect_handler(struct work_struct *work)
        if (!rt711->hs_jack)
                return;
 
-       if (!rt711->component->card->instantiated)
+       if (!rt711->component->card || !rt711->component->card->instantiated)
                return;
 
        /* SDW_SCP_SDCA_INT_SDCA_0 is used for jack detection */
@@ -487,16 +487,27 @@ static int rt711_sdca_set_jack_detect(struct snd_soc_component *component,
        struct snd_soc_jack *hs_jack, void *data)
 {
        struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+       int ret;
 
        rt711->hs_jack = hs_jack;
 
-       if (!rt711->hw_init) {
-               dev_dbg(&rt711->slave->dev,
-                       "%s hw_init not ready yet\n", __func__);
+       ret = pm_runtime_resume_and_get(component->dev);
+       if (ret < 0) {
+               if (ret != -EACCES) {
+                       dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret);
+                       return ret;
+               }
+
+               /* pm_runtime not enabled yet */
+               dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__);
                return 0;
        }
 
        rt711_sdca_jack_init(rt711);
+
+       pm_runtime_mark_last_busy(component->dev);
+       pm_runtime_put_autosuspend(component->dev);
+
        return 0;
 }
 
@@ -1190,14 +1201,6 @@ static int rt711_sdca_probe(struct snd_soc_component *component)
        return 0;
 }
 
-static void rt711_sdca_remove(struct snd_soc_component *component)
-{
-       struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
-
-       regcache_cache_only(rt711->regmap, true);
-       regcache_cache_only(rt711->mbq_regmap, true);
-}
-
 static const struct snd_soc_component_driver soc_sdca_dev_rt711 = {
        .probe = rt711_sdca_probe,
        .controls = rt711_sdca_snd_controls,
@@ -1207,7 +1210,6 @@ static const struct snd_soc_component_driver soc_sdca_dev_rt711 = {
        .dapm_routes = rt711_sdca_audio_map,
        .num_dapm_routes = ARRAY_SIZE(rt711_sdca_audio_map),
        .set_jack = rt711_sdca_set_jack_detect,
-       .remove = rt711_sdca_remove,
        .endianness = 1,
 };
 
@@ -1412,8 +1414,12 @@ int rt711_sdca_init(struct device *dev, struct regmap *regmap,
        rt711->regmap = regmap;
        rt711->mbq_regmap = mbq_regmap;
 
+       mutex_init(&rt711->calibrate_mutex);
        mutex_init(&rt711->disable_irq_lock);
 
+       INIT_DELAYED_WORK(&rt711->jack_detect_work, rt711_sdca_jack_detect_handler);
+       INIT_DELAYED_WORK(&rt711->jack_btn_check_work, rt711_sdca_btn_check_handler);
+
        /*
         * Mark hw_init to false
         * HW init will be performed when device reports present
@@ -1545,14 +1551,6 @@ int rt711_sdca_io_init(struct device *dev, struct sdw_slave *slave)
        rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL,
                RT711_PUSH_BTN_INT_CTL0, 0x20, 0x00);
 
-       if (!rt711->first_hw_init) {
-               INIT_DELAYED_WORK(&rt711->jack_detect_work,
-                       rt711_sdca_jack_detect_handler);
-               INIT_DELAYED_WORK(&rt711->jack_btn_check_work,
-                       rt711_sdca_btn_check_handler);
-               mutex_init(&rt711->calibrate_mutex);
-       }
-
        /* calibration */
        ret = rt711_sdca_calibration(rt711);
        if (ret < 0)
index bda2cc9..4fe68bc 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/soundwire/sdw_type.h>
 #include <linux/soundwire/sdw_registers.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <sound/soc.h>
 #include "rt711.h"
@@ -464,12 +465,18 @@ static int rt711_sdw_remove(struct sdw_slave *slave)
 {
        struct rt711_priv *rt711 = dev_get_drvdata(&slave->dev);
 
-       if (rt711 && rt711->hw_init) {
+       if (rt711->hw_init) {
                cancel_delayed_work_sync(&rt711->jack_detect_work);
                cancel_delayed_work_sync(&rt711->jack_btn_check_work);
                cancel_work_sync(&rt711->calibration_work);
        }
 
+       if (rt711->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
+       mutex_destroy(&rt711->calibrate_mutex);
+       mutex_destroy(&rt711->disable_irq_lock);
+
        return 0;
 }
 
index 9838fb4..9df800a 100644 (file)
@@ -242,7 +242,7 @@ static void rt711_jack_detect_handler(struct work_struct *work)
        if (!rt711->hs_jack)
                return;
 
-       if (!rt711->component->card->instantiated)
+       if (!rt711->component->card || !rt711->component->card->instantiated)
                return;
 
        if (pm_runtime_status_suspended(rt711->slave->dev.parent)) {
@@ -457,17 +457,27 @@ static int rt711_set_jack_detect(struct snd_soc_component *component,
        struct snd_soc_jack *hs_jack, void *data)
 {
        struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
+       int ret;
 
        rt711->hs_jack = hs_jack;
 
-       if (!rt711->hw_init) {
-               dev_dbg(&rt711->slave->dev,
-                       "%s hw_init not ready yet\n", __func__);
+       ret = pm_runtime_resume_and_get(component->dev);
+       if (ret < 0) {
+               if (ret != -EACCES) {
+                       dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret);
+                       return ret;
+               }
+
+               /* pm_runtime not enabled yet */
+               dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__);
                return 0;
        }
 
        rt711_jack_init(rt711);
 
+       pm_runtime_mark_last_busy(component->dev);
+       pm_runtime_put_autosuspend(component->dev);
+
        return 0;
 }
 
@@ -932,13 +942,6 @@ static int rt711_probe(struct snd_soc_component *component)
        return 0;
 }
 
-static void rt711_remove(struct snd_soc_component *component)
-{
-       struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
-
-       regcache_cache_only(rt711->regmap, true);
-}
-
 static const struct snd_soc_component_driver soc_codec_dev_rt711 = {
        .probe = rt711_probe,
        .set_bias_level = rt711_set_bias_level,
@@ -949,7 +952,6 @@ static const struct snd_soc_component_driver soc_codec_dev_rt711 = {
        .dapm_routes = rt711_audio_map,
        .num_dapm_routes = ARRAY_SIZE(rt711_audio_map),
        .set_jack = rt711_set_jack_detect,
-       .remove = rt711_remove,
        .endianness = 1,
 };
 
@@ -1204,8 +1206,13 @@ int rt711_init(struct device *dev, struct regmap *sdw_regmap,
        rt711->sdw_regmap = sdw_regmap;
        rt711->regmap = regmap;
 
+       mutex_init(&rt711->calibrate_mutex);
        mutex_init(&rt711->disable_irq_lock);
 
+       INIT_DELAYED_WORK(&rt711->jack_detect_work, rt711_jack_detect_handler);
+       INIT_DELAYED_WORK(&rt711->jack_btn_check_work, rt711_btn_check_handler);
+       INIT_WORK(&rt711->calibration_work, rt711_calibration_work);
+
        /*
         * Mark hw_init to false
         * HW init will be performed when device reports present
@@ -1313,15 +1320,8 @@ int rt711_io_init(struct device *dev, struct sdw_slave *slave)
 
        if (rt711->first_hw_init)
                rt711_calibration(rt711);
-       else {
-               INIT_DELAYED_WORK(&rt711->jack_detect_work,
-                       rt711_jack_detect_handler);
-               INIT_DELAYED_WORK(&rt711->jack_btn_check_work,
-                       rt711_btn_check_handler);
-               mutex_init(&rt711->calibrate_mutex);
-               INIT_WORK(&rt711->calibration_work, rt711_calibration_work);
+       else
                schedule_work(&rt711->calibration_work);
-       }
 
        /*
         * if set_jack callback occurred early than io_init,
index 0ecd294..13e731d 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/soundwire/sdw_type.h>
 #include <linux/soundwire/sdw_registers.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <sound/soc.h>
 #include "rt715-sdca.h"
@@ -193,6 +194,16 @@ static int rt715_sdca_sdw_probe(struct sdw_slave *slave,
        return rt715_sdca_init(&slave->dev, mbq_regmap, regmap, slave);
 }
 
+static int rt715_sdca_sdw_remove(struct sdw_slave *slave)
+{
+       struct rt715_sdca_priv *rt715 = dev_get_drvdata(&slave->dev);
+
+       if (rt715->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
+       return 0;
+}
+
 static const struct sdw_device_id rt715_sdca_id[] = {
        SDW_SLAVE_ENTRY_EXT(0x025d, 0x715, 0x3, 0x1, 0),
        SDW_SLAVE_ENTRY_EXT(0x025d, 0x714, 0x3, 0x1, 0),
@@ -267,6 +278,7 @@ static struct sdw_driver rt715_sdw_driver = {
                .pm = &rt715_pm,
        },
        .probe = rt715_sdca_sdw_probe,
+       .remove = rt715_sdca_sdw_remove,
        .ops = &rt715_sdca_slave_ops,
        .id_table = rt715_sdca_id,
 };
index a7b21b0..b047bf8 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/soundwire/sdw_type.h>
 #include <linux/soundwire/sdw_registers.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 #include <linux/of.h>
 #include <linux/regmap.h>
 #include <sound/soc.h>
@@ -514,6 +515,16 @@ static int rt715_sdw_probe(struct sdw_slave *slave,
        return 0;
 }
 
+static int rt715_sdw_remove(struct sdw_slave *slave)
+{
+       struct rt715_priv *rt715 = dev_get_drvdata(&slave->dev);
+
+       if (rt715->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
+       return 0;
+}
+
 static const struct sdw_device_id rt715_id[] = {
        SDW_SLAVE_ENTRY_EXT(0x025d, 0x714, 0x2, 0, 0),
        SDW_SLAVE_ENTRY_EXT(0x025d, 0x715, 0x2, 0, 0),
@@ -575,6 +586,7 @@ static struct sdw_driver rt715_sdw_driver = {
                   .pm = &rt715_pm,
                   },
        .probe = rt715_sdw_probe,
+       .remove = rt715_sdw_remove,
        .ops = &rt715_slave_ops,
        .id_table = rt715_id,
 };
index 2aa48ae..3363d16 100644 (file)
@@ -1795,6 +1795,9 @@ static int sgtl5000_i2c_remove(struct i2c_client *client)
 {
        struct sgtl5000_priv *sgtl5000 = i2c_get_clientdata(client);
 
+       regmap_write(sgtl5000->regmap, SGTL5000_CHIP_DIG_POWER, SGTL5000_DIG_POWER_DEFAULT);
+       regmap_write(sgtl5000->regmap, SGTL5000_CHIP_ANA_POWER, SGTL5000_ANA_POWER_DEFAULT);
+
        clk_disable_unprepare(sgtl5000->mclk);
        regulator_bulk_disable(sgtl5000->num_supplies, sgtl5000->supplies);
        regulator_bulk_free(sgtl5000->num_supplies, sgtl5000->supplies);
@@ -1802,6 +1805,11 @@ static int sgtl5000_i2c_remove(struct i2c_client *client)
        return 0;
 }
 
+static void sgtl5000_i2c_shutdown(struct i2c_client *client)
+{
+       sgtl5000_i2c_remove(client);
+}
+
 static const struct i2c_device_id sgtl5000_id[] = {
        {"sgtl5000", 0},
        {},
@@ -1822,6 +1830,7 @@ static struct i2c_driver sgtl5000_i2c_driver = {
        },
        .probe_new = sgtl5000_i2c_probe,
        .remove = sgtl5000_i2c_remove,
+       .shutdown = sgtl5000_i2c_shutdown,
        .id_table = sgtl5000_id,
 };
 
index 56ec586..3a808c7 100644 (file)
@@ -80,6 +80,7 @@
 /*
  * SGTL5000_CHIP_DIG_POWER
  */
+#define SGTL5000_DIG_POWER_DEFAULT             0x0000
 #define SGTL5000_ADC_EN                                0x0040
 #define SGTL5000_DAC_EN                                0x0020
 #define SGTL5000_DAP_POWERUP                   0x0010
index d395fef..4cb788f 100644 (file)
@@ -42,10 +42,12 @@ static void tas2764_reset(struct tas2764_priv *tas2764)
                gpiod_set_value_cansleep(tas2764->reset_gpio, 0);
                msleep(20);
                gpiod_set_value_cansleep(tas2764->reset_gpio, 1);
+               usleep_range(1000, 2000);
        }
 
        snd_soc_component_write(tas2764->component, TAS2764_SW_RST,
                                TAS2764_RST);
+       usleep_range(1000, 2000);
 }
 
 static int tas2764_set_bias_level(struct snd_soc_component *component,
@@ -107,8 +109,10 @@ static int tas2764_codec_resume(struct snd_soc_component *component)
        struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
        int ret;
 
-       if (tas2764->sdz_gpio)
+       if (tas2764->sdz_gpio) {
                gpiod_set_value_cansleep(tas2764->sdz_gpio, 1);
+               usleep_range(1000, 2000);
+       }
 
        ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
                                            TAS2764_PWR_CTRL_MASK,
@@ -131,7 +135,8 @@ static const char * const tas2764_ASI1_src[] = {
 };
 
 static SOC_ENUM_SINGLE_DECL(
-       tas2764_ASI1_src_enum, TAS2764_TDM_CFG2, 4, tas2764_ASI1_src);
+       tas2764_ASI1_src_enum, TAS2764_TDM_CFG2, TAS2764_TDM_CFG2_SCFG_SHIFT,
+       tas2764_ASI1_src);
 
 static const struct snd_kcontrol_new tas2764_asi1_mux =
        SOC_DAPM_ENUM("ASI1 Source", tas2764_ASI1_src_enum);
@@ -329,20 +334,22 @@ static int tas2764_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
        struct snd_soc_component *component = dai->component;
        struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
-       u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0;
-       int iface;
+       u8 tdm_rx_start_slot = 0, asi_cfg_0 = 0, asi_cfg_1 = 0;
        int ret;
 
        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_IF:
+               asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START;
+               fallthrough;
        case SND_SOC_DAIFMT_NB_NF:
                asi_cfg_1 = TAS2764_TDM_CFG1_RX_RISING;
                break;
+       case SND_SOC_DAIFMT_IB_IF:
+               asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START;
+               fallthrough;
        case SND_SOC_DAIFMT_IB_NF:
                asi_cfg_1 = TAS2764_TDM_CFG1_RX_FALLING;
                break;
-       default:
-               dev_err(tas2764->dev, "ASI format Inverse is not found\n");
-               return -EINVAL;
        }
 
        ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG1,
@@ -353,13 +360,13 @@ static int tas2764_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
+               asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START;
+               fallthrough;
        case SND_SOC_DAIFMT_DSP_A:
-               iface = TAS2764_TDM_CFG2_SCFG_I2S;
                tdm_rx_start_slot = 1;
                break;
        case SND_SOC_DAIFMT_DSP_B:
        case SND_SOC_DAIFMT_LEFT_J:
-               iface = TAS2764_TDM_CFG2_SCFG_LEFT_J;
                tdm_rx_start_slot = 0;
                break;
        default:
@@ -368,14 +375,15 @@ static int tas2764_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                return -EINVAL;
        }
 
-       ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG1,
-                                           TAS2764_TDM_CFG1_MASK,
-                                           (tdm_rx_start_slot << TAS2764_TDM_CFG1_51_SHIFT));
+       ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG0,
+                                           TAS2764_TDM_CFG0_FRAME_START,
+                                           asi_cfg_0);
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG2,
-                                           TAS2764_TDM_CFG2_SCFG_MASK, iface);
+       ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG1,
+                                           TAS2764_TDM_CFG1_MASK,
+                                           (tdm_rx_start_slot << TAS2764_TDM_CFG1_51_SHIFT));
        if (ret < 0)
                return ret;
 
@@ -501,8 +509,10 @@ static int tas2764_codec_probe(struct snd_soc_component *component)
 
        tas2764->component = component;
 
-       if (tas2764->sdz_gpio)
+       if (tas2764->sdz_gpio) {
                gpiod_set_value_cansleep(tas2764->sdz_gpio, 1);
+               usleep_range(1000, 2000);
+       }
 
        tas2764_reset(tas2764);
 
@@ -526,12 +536,12 @@ static int tas2764_codec_probe(struct snd_soc_component *component)
 }
 
 static DECLARE_TLV_DB_SCALE(tas2764_digital_tlv, 1100, 50, 0);
-static DECLARE_TLV_DB_SCALE(tas2764_playback_volume, -10000, 50, 0);
+static DECLARE_TLV_DB_SCALE(tas2764_playback_volume, -10050, 50, 1);
 
 static const struct snd_kcontrol_new tas2764_snd_controls[] = {
        SOC_SINGLE_TLV("Speaker Volume", TAS2764_DVC, 0,
                       TAS2764_DVC_MAX, 1, tas2764_playback_volume),
-       SOC_SINGLE_TLV("Amp Gain Volume", TAS2764_CHNL_0, 0, 0x14, 0,
+       SOC_SINGLE_TLV("Amp Gain Volume", TAS2764_CHNL_0, 1, 0x14, 0,
                       tas2764_digital_tlv),
 };
 
@@ -556,7 +566,7 @@ static const struct reg_default tas2764_reg_defaults[] = {
        { TAS2764_SW_RST, 0x00 },
        { TAS2764_PWR_CTRL, 0x1a },
        { TAS2764_DVC, 0x00 },
-       { TAS2764_CHNL_0, 0x00 },
+       { TAS2764_CHNL_0, 0x28 },
        { TAS2764_TDM_CFG0, 0x09 },
        { TAS2764_TDM_CFG1, 0x02 },
        { TAS2764_TDM_CFG2, 0x0a },
index 67d6fd9..f015f22 100644 (file)
@@ -47,6 +47,7 @@
 #define TAS2764_TDM_CFG0_MASK          GENMASK(3, 1)
 #define TAS2764_TDM_CFG0_44_1_48KHZ    BIT(3)
 #define TAS2764_TDM_CFG0_88_2_96KHZ    (BIT(3) | BIT(1))
+#define TAS2764_TDM_CFG0_FRAME_START   BIT(0)
 
 /* TDM Configuration Reg1 */
 #define TAS2764_TDM_CFG1               TAS2764_REG(0X0, 0x09)
 #define TAS2764_TDM_CFG2_RXS_16BITS    0x0
 #define TAS2764_TDM_CFG2_RXS_24BITS    BIT(0)
 #define TAS2764_TDM_CFG2_RXS_32BITS    BIT(1)
-#define TAS2764_TDM_CFG2_SCFG_MASK     GENMASK(5, 4)
-#define TAS2764_TDM_CFG2_SCFG_I2S      0x0
-#define TAS2764_TDM_CFG2_SCFG_LEFT_J   BIT(4)
-#define TAS2764_TDM_CFG2_SCFG_RIGHT_J  BIT(5)
+#define TAS2764_TDM_CFG2_SCFG_SHIFT    4
 
 /* TDM Configuration Reg3 */
 #define TAS2764_TDM_CFG3               TAS2764_REG(0X0, 0x0c)
index b55f0b8..0b72965 100644 (file)
@@ -33,7 +33,6 @@ struct adcx140_priv {
        bool micbias_vg;
 
        unsigned int dai_fmt;
-       unsigned int tdm_delay;
        unsigned int slot_width;
 };
 
@@ -792,12 +791,13 @@ static int adcx140_set_dai_tdm_slot(struct snd_soc_dai *codec_dai,
 {
        struct snd_soc_component *component = codec_dai->component;
        struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(component);
-       unsigned int lsb;
 
-       /* TDM based on DSP mode requires slots to be adjacent */
-       lsb = __ffs(tx_mask);
-       if ((lsb + 1) != __fls(tx_mask)) {
-               dev_err(component->dev, "Invalid mask, slots must be adjacent\n");
+       /*
+        * The chip itself supports arbitrary masks, but the driver currently
+        * only supports adjacent slots beginning at the first slot.
+        */
+       if (tx_mask != GENMASK(__fls(tx_mask), 0)) {
+               dev_err(component->dev, "Only lower adjacent slots are supported\n");
                return -EINVAL;
        }
 
@@ -812,7 +812,6 @@ static int adcx140_set_dai_tdm_slot(struct snd_soc_dai *codec_dai,
                return -EINVAL;
        }
 
-       adcx140->tdm_delay = lsb;
        adcx140->slot_width = slot_width;
 
        return 0;
index 617a36a..3cb7a3e 100644 (file)
@@ -342,7 +342,7 @@ struct wcd9335_codec {
        struct regulator_bulk_data supplies[WCD9335_MAX_SUPPLY];
 
        unsigned int rx_port_value[WCD9335_RX_MAX];
-       unsigned int tx_port_value;
+       unsigned int tx_port_value[WCD9335_TX_MAX];
        int hph_l_gain;
        int hph_r_gain;
        u32 rx_bias_count;
@@ -1287,11 +1287,17 @@ static int slim_rx_mux_put(struct snd_kcontrol *kc,
        struct snd_soc_dapm_update *update = NULL;
        u32 port_id = w->shift;
 
+       if (wcd->rx_port_value[port_id] == ucontrol->value.enumerated.item[0])
+               return 0;
+
        wcd->rx_port_value[port_id] = ucontrol->value.enumerated.item[0];
 
+       /* Remove channel from any list it's in before adding it to a new one */
+       list_del_init(&wcd->rx_chs[port_id].list);
+
        switch (wcd->rx_port_value[port_id]) {
        case 0:
-               list_del_init(&wcd->rx_chs[port_id].list);
+               /* Channel already removed from lists. Nothing to do here */
                break;
        case 1:
                list_add_tail(&wcd->rx_chs[port_id].list,
@@ -1328,8 +1334,13 @@ static int slim_tx_mixer_get(struct snd_kcontrol *kc,
 
        struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kc);
        struct wcd9335_codec *wcd = dev_get_drvdata(dapm->dev);
+       struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kc);
+       struct soc_mixer_control *mixer =
+                       (struct soc_mixer_control *)kc->private_value;
+       int dai_id = widget->shift;
+       int port_id = mixer->shift;
 
-       ucontrol->value.integer.value[0] = wcd->tx_port_value;
+       ucontrol->value.integer.value[0] = wcd->tx_port_value[port_id] == dai_id;
 
        return 0;
 }
@@ -1352,12 +1363,12 @@ static int slim_tx_mixer_put(struct snd_kcontrol *kc,
        case AIF2_CAP:
        case AIF3_CAP:
                /* only add to the list if value not set */
-               if (enable && !(wcd->tx_port_value & BIT(port_id))) {
-                       wcd->tx_port_value |= BIT(port_id);
+               if (enable && wcd->tx_port_value[port_id] != dai_id) {
+                       wcd->tx_port_value[port_id] = dai_id;
                        list_add_tail(&wcd->tx_chs[port_id].list,
                                        &wcd->dai[dai_id].slim_ch_list);
-               } else if (!enable && (wcd->tx_port_value & BIT(port_id))) {
-                       wcd->tx_port_value &= ~BIT(port_id);
+               } else if (!enable && wcd->tx_port_value[port_id] == dai_id) {
+                       wcd->tx_port_value[port_id] = -1;
                        list_del_init(&wcd->tx_chs[port_id].list);
                }
                break;
index c1b61b9..781ae56 100644 (file)
@@ -2519,6 +2519,9 @@ static int wcd938x_tx_mode_put(struct snd_kcontrol *kcontrol,
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        int path = e->shift_l;
 
+       if (wcd938x->tx_mode[path] == ucontrol->value.enumerated.item[0])
+               return 0;
+
        wcd938x->tx_mode[path] = ucontrol->value.enumerated.item[0];
 
        return 1;
@@ -2541,6 +2544,9 @@ static int wcd938x_rx_hph_mode_put(struct snd_kcontrol *kcontrol,
        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
        struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
 
+       if (wcd938x->hph_mode == ucontrol->value.enumerated.item[0])
+               return 0;
+
        wcd938x->hph_mode = ucontrol->value.enumerated.item[0];
 
        return 1;
@@ -2632,6 +2638,9 @@ static int wcd938x_ldoh_put(struct snd_kcontrol *kcontrol,
        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
        struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
 
+       if (wcd938x->ldoh == ucontrol->value.integer.value[0])
+               return 0;
+
        wcd938x->ldoh = ucontrol->value.integer.value[0];
 
        return 1;
@@ -2654,6 +2663,9 @@ static int wcd938x_bcs_put(struct snd_kcontrol *kcontrol,
        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
        struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
 
+       if (wcd938x->bcs_dis == ucontrol->value.integer.value[0])
+               return 0;
+
        wcd938x->bcs_dis = ucontrol->value.integer.value[0];
 
        return 1;
index da2f899..b034df4 100644 (file)
@@ -680,12 +680,17 @@ static int wm5102_out_comp_coeff_put(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
        struct arizona *arizona = dev_get_drvdata(component->dev->parent);
+       uint16_t dac_comp_coeff = get_unaligned_be16(ucontrol->value.bytes.data);
+       int ret = 0;
 
        mutex_lock(&arizona->dac_comp_lock);
-       arizona->dac_comp_coeff = get_unaligned_be16(ucontrol->value.bytes.data);
+       if (arizona->dac_comp_coeff != dac_comp_coeff) {
+               arizona->dac_comp_coeff = dac_comp_coeff;
+               ret = 1;
+       }
        mutex_unlock(&arizona->dac_comp_lock);
 
-       return 0;
+       return ret;
 }
 
 static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol,
@@ -706,12 +711,20 @@ static int wm5102_out_comp_switch_put(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
        struct arizona *arizona = dev_get_drvdata(component->dev->parent);
+       struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
+       int ret = 0;
+
+       if (ucontrol->value.integer.value[0] > mc->max)
+               return -EINVAL;
 
        mutex_lock(&arizona->dac_comp_lock);
-       arizona->dac_comp_enabled = ucontrol->value.integer.value[0];
+       if (arizona->dac_comp_enabled != ucontrol->value.integer.value[0]) {
+               arizona->dac_comp_enabled = ucontrol->value.integer.value[0];
+               ret = 1;
+       }
        mutex_unlock(&arizona->dac_comp_lock);
 
-       return 0;
+       return ret;
 }
 
 static const char * const wm5102_osr_text[] = {
index 4973ba1..4ab7a67 100644 (file)
@@ -413,6 +413,7 @@ static int wm5110_put_dre(struct snd_kcontrol *kcontrol,
        unsigned int rnew = (!!ucontrol->value.integer.value[1]) << mc->rshift;
        unsigned int lold, rold;
        unsigned int lena, rena;
+       bool change = false;
        int ret;
 
        snd_soc_dapm_mutex_lock(dapm);
@@ -440,8 +441,8 @@ static int wm5110_put_dre(struct snd_kcontrol *kcontrol,
                goto err;
        }
 
-       ret = regmap_update_bits(arizona->regmap, ARIZONA_DRE_ENABLE,
-                                mask, lnew | rnew);
+       ret = regmap_update_bits_check(arizona->regmap, ARIZONA_DRE_ENABLE,
+                                      mask, lnew | rnew, &change);
        if (ret) {
                dev_err(arizona->dev, "Failed to set DRE: %d\n", ret);
                goto err;
@@ -454,6 +455,9 @@ static int wm5110_put_dre(struct snd_kcontrol *kcontrol,
        if (!rnew && rold)
                wm5110_clear_pga_volume(arizona, mc->rshift);
 
+       if (change)
+               ret = 1;
+
 err:
        snd_soc_dapm_mutex_unlock(dapm);
 
index 00b59fc..ab54811 100644 (file)
@@ -108,6 +108,7 @@ static int wm8998_inmux_put(struct snd_kcontrol *kcontrol,
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int mode_reg, mode_index;
        unsigned int mux, inmode, src_val, mode_val;
+       int change, ret;
 
        mux = ucontrol->value.enumerated.item[0];
        if (mux > 1)
@@ -137,14 +138,20 @@ static int wm8998_inmux_put(struct snd_kcontrol *kcontrol,
        snd_soc_component_update_bits(component, mode_reg,
                                      ARIZONA_IN1_MODE_MASK, mode_val);
 
-       snd_soc_component_update_bits(component, e->reg,
-                                     ARIZONA_IN1L_SRC_MASK |
-                                     ARIZONA_IN1L_SRC_SE_MASK,
-                                     src_val);
+       change = snd_soc_component_update_bits(component, e->reg,
+                                              ARIZONA_IN1L_SRC_MASK |
+                                              ARIZONA_IN1L_SRC_SE_MASK,
+                                              src_val);
 
-       return snd_soc_dapm_mux_update_power(dapm, kcontrol,
-                                            ucontrol->value.enumerated.item[0],
-                                            e, NULL);
+       ret = snd_soc_dapm_mux_update_power(dapm, kcontrol,
+                                           ucontrol->value.enumerated.item[0],
+                                           e, NULL);
+       if (ret < 0) {
+               dev_err(arizona->dev, "Failed to update demux power state: %d\n", ret);
+               return ret;
+       }
+
+       return change;
 }
 
 static const char * const wm8998_inmux_texts[] = {
index 6d7fd88..a7784ac 100644 (file)
@@ -997,7 +997,7 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
                snd_soc_dapm_sync(dapm);
        }
 
-       return 0;
+       return 1;
 }
 EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put);
 
index 77ac405..d34b29a 100644 (file)
@@ -90,12 +90,12 @@ links indicates connection part of CPU side (= A).
                        ports@0 {
 (X) (A)                        mcpu:   port@0 { mcpu0_ep: endpoint { remote-endpoint = <&mcodec0_ep>; }; };
 (y)                            port@1 { mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>; }; };
-(y)                            port@1 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; };
+(y)                            port@2 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; };
                        };
                        ports@1 {
 (X)                            port@0 { mcodec0_ep: endpoint { remote-endpoint = <&mcpu0_ep>; }; };
-(y)                            port@0 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; };
-(y)                            port@1 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; };
+(y)                            port@1 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; };
+(y)                            port@2 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; };
                        };
                };
        };
index 0d11cc8..6a06fe3 100644 (file)
@@ -128,10 +128,10 @@ struct avs_tplg_token_parser {
 static int
 avs_parse_uuid_token(struct snd_soc_component *comp, void *elem, void *object, u32 offset)
 {
-       struct snd_soc_tplg_vendor_value_elem *tuple = elem;
+       struct snd_soc_tplg_vendor_uuid_elem *tuple = elem;
        guid_t *val = (guid_t *)((u8 *)object + offset);
 
-       guid_copy((guid_t *)val, (const guid_t *)&tuple->value);
+       guid_copy((guid_t *)val, (const guid_t *)&tuple->uuid);
 
        return 0;
 }
index 00384c6..330c0ac 100644 (file)
@@ -421,8 +421,17 @@ static int snd_byt_wm5102_mc_probe(struct platform_device *pdev)
        priv->spkvdd_en_gpio = gpiod_get(codec_dev, "wlf,spkvdd-ena", GPIOD_OUT_LOW);
        put_device(codec_dev);
 
-       if (IS_ERR(priv->spkvdd_en_gpio))
-               return dev_err_probe(dev, PTR_ERR(priv->spkvdd_en_gpio), "getting spkvdd-GPIO\n");
+       if (IS_ERR(priv->spkvdd_en_gpio)) {
+               ret = PTR_ERR(priv->spkvdd_en_gpio);
+               /*
+                * The spkvdd gpio-lookup is registered by: drivers/mfd/arizona-spi.c,
+                * so -ENOENT means that arizona-spi hasn't probed yet.
+                */
+               if (ret == -ENOENT)
+                       ret = -EPROBE_DEFER;
+
+               return dev_err_probe(dev, ret, "getting spkvdd-GPIO\n");
+       }
 
        /* override platform name, if required */
        byt_wm5102_card.dev = dev;
index 5d67a2c..4a90a0a 100644 (file)
@@ -69,11 +69,10 @@ static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN |
 
 static int is_legacy_cpu;
 
-static struct snd_soc_jack sof_hdmi[3];
-
 struct sof_hdmi_pcm {
        struct list_head head;
        struct snd_soc_dai *codec_dai;
+       struct snd_soc_jack hdmi_jack;
        int device;
 };
 
@@ -434,7 +433,6 @@ static int sof_card_late_probe(struct snd_soc_card *card)
        char jack_name[NAME_SIZE];
        struct sof_hdmi_pcm *pcm;
        int err;
-       int i = 0;
 
        /* HDMI is not supported by SOF on Baytrail/CherryTrail */
        if (is_legacy_cpu || !ctx->idisp_codec)
@@ -455,17 +453,15 @@ static int sof_card_late_probe(struct snd_soc_card *card)
                snprintf(jack_name, sizeof(jack_name),
                         "HDMI/DP, pcm=%d Jack", pcm->device);
                err = snd_soc_card_jack_new(card, jack_name,
-                                           SND_JACK_AVOUT, &sof_hdmi[i]);
+                                           SND_JACK_AVOUT, &pcm->hdmi_jack);
 
                if (err)
                        return err;
 
                err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
-                                         &sof_hdmi[i]);
+                                         &pcm->hdmi_jack);
                if (err < 0)
                        return err;
-
-               i++;
        }
 
        if (sof_rt5682_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) {
index 1f00679..ad826ad 100644 (file)
@@ -1398,6 +1398,33 @@ static struct snd_soc_card card_sof_sdw = {
        .late_probe = sof_sdw_card_late_probe,
 };
 
+static void mc_dailink_exit_loop(struct snd_soc_card *card)
+{
+       struct snd_soc_dai_link *link;
+       int ret;
+       int i, j;
+
+       for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
+               if (!codec_info_list[i].exit)
+                       continue;
+               /*
+                * We don't need to call .exit function if there is no matched
+                * dai link found.
+                */
+               for_each_card_prelinks(card, j, link) {
+                       if (!strcmp(link->codecs[0].dai_name,
+                                   codec_info_list[i].dai_name)) {
+                               ret = codec_info_list[i].exit(card, link);
+                               if (ret)
+                                       dev_warn(card->dev,
+                                                "codec exit failed %d\n",
+                                                ret);
+                               break;
+                       }
+               }
+       }
+}
+
 static int mc_probe(struct platform_device *pdev)
 {
        struct snd_soc_card *card = &card_sof_sdw;
@@ -1462,6 +1489,7 @@ static int mc_probe(struct platform_device *pdev)
        ret = devm_snd_soc_register_card(&pdev->dev, card);
        if (ret) {
                dev_err(card->dev, "snd_soc_register_card failed %d\n", ret);
+               mc_dailink_exit_loop(card);
                return ret;
        }
 
@@ -1473,29 +1501,8 @@ static int mc_probe(struct platform_device *pdev)
 static int mc_remove(struct platform_device *pdev)
 {
        struct snd_soc_card *card = platform_get_drvdata(pdev);
-       struct snd_soc_dai_link *link;
-       int ret;
-       int i, j;
 
-       for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
-               if (!codec_info_list[i].exit)
-                       continue;
-               /*
-                * We don't need to call .exit function if there is no matched
-                * dai link found.
-                */
-               for_each_card_prelinks(card, j, link) {
-                       if (!strcmp(link->codecs[0].dai_name,
-                                   codec_info_list[i].dai_name)) {
-                               ret = codec_info_list[i].exit(card, link);
-                               if (ret)
-                                       dev_warn(&pdev->dev,
-                                                "codec exit failed %d\n",
-                                                ret);
-                               break;
-                       }
-               }
-       }
+       mc_dailink_exit_loop(card);
 
        return 0;
 }
index 2439a57..deb7b82 100644 (file)
@@ -99,7 +99,6 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks,
        struct nhlt_fmt_cfg *fmt_cfg;
        struct wav_fmt_ext *wav_fmt;
        unsigned long rate;
-       bool present = false;
        int rate_index = 0;
        u16 channels, bps;
        u8 clk_src;
@@ -112,9 +111,12 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks,
        if (fmt->fmt_count == 0)
                return;
 
+       fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config;
        for (i = 0; i < fmt->fmt_count; i++) {
-               fmt_cfg = &fmt->fmt_config[i];
-               wav_fmt = &fmt_cfg->fmt_ext;
+               struct nhlt_fmt_cfg *saved_fmt_cfg = fmt_cfg;
+               bool present = false;
+
+               wav_fmt = &saved_fmt_cfg->fmt_ext;
 
                channels = wav_fmt->fmt.channels;
                bps = wav_fmt->fmt.bits_per_sample;
@@ -132,12 +134,18 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks,
                 * derive the rate.
                 */
                for (j = i; j < fmt->fmt_count; j++) {
-                       fmt_cfg = &fmt->fmt_config[j];
-                       wav_fmt = &fmt_cfg->fmt_ext;
+                       struct nhlt_fmt_cfg *tmp_fmt_cfg = fmt_cfg;
+
+                       wav_fmt = &tmp_fmt_cfg->fmt_ext;
                        if ((fs == wav_fmt->fmt.samples_per_sec) &&
-                          (bps == wav_fmt->fmt.bits_per_sample))
+                          (bps == wav_fmt->fmt.bits_per_sample)) {
                                channels = max_t(u16, channels,
                                                wav_fmt->fmt.channels);
+                               saved_fmt_cfg = tmp_fmt_cfg;
+                       }
+                       /* Move to the next nhlt_fmt_cfg */
+                       tmp_fmt_cfg = (struct nhlt_fmt_cfg *)(tmp_fmt_cfg->config.caps +
+                                                             tmp_fmt_cfg->config.size);
                }
 
                rate = channels * bps * fs;
@@ -153,8 +161,11 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks,
 
                /* Fill rate and parent for sclk/sclkfs */
                if (!present) {
+                       struct nhlt_fmt_cfg *first_fmt_cfg;
+
+                       first_fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config;
                        i2s_config_ext = (struct skl_i2s_config_blob_ext *)
-                                               fmt->fmt_config[0].config.caps;
+                                               first_fmt_cfg->config.caps;
 
                        /* MCLK Divider Source Select */
                        if (is_legacy_blob(i2s_config_ext->hdr.sig)) {
@@ -168,6 +179,9 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks,
 
                        parent = skl_get_parent_clk(clk_src);
 
+                       /* Move to the next nhlt_fmt_cfg */
+                       fmt_cfg = (struct nhlt_fmt_cfg *)(fmt_cfg->config.caps +
+                                                         fmt_cfg->config.size);
                        /*
                         * Do not copy the config data if there is no parent
                         * clock available for this clock source select
@@ -176,9 +190,9 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks,
                                continue;
 
                        sclk[id].rate_cfg[rate_index].rate = rate;
-                       sclk[id].rate_cfg[rate_index].config = fmt_cfg;
+                       sclk[id].rate_cfg[rate_index].config = saved_fmt_cfg;
                        sclkfs[id].rate_cfg[rate_index].rate = rate;
-                       sclkfs[id].rate_cfg[rate_index].config = fmt_cfg;
+                       sclkfs[id].rate_cfg[rate_index].config = saved_fmt_cfg;
                        sclk[id].parent_name = parent->name;
                        sclkfs[id].parent_name = parent->name;
 
@@ -192,13 +206,13 @@ static void skl_get_mclk(struct skl_dev *skl, struct skl_ssp_clk *mclk,
 {
        struct skl_i2s_config_blob_ext *i2s_config_ext;
        struct skl_i2s_config_blob_legacy *i2s_config;
-       struct nhlt_specific_cfg *fmt_cfg;
+       struct nhlt_fmt_cfg *fmt_cfg;
        struct skl_clk_parent_src *parent;
        u32 clkdiv, div_ratio;
        u8 clk_src;
 
-       fmt_cfg = &fmt->fmt_config[0].config;
-       i2s_config_ext = (struct skl_i2s_config_blob_ext *)fmt_cfg->caps;
+       fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config;
+       i2s_config_ext = (struct skl_i2s_config_blob_ext *)fmt_cfg->config.caps;
 
        /* MCLK Divider Source Select and divider */
        if (is_legacy_blob(i2s_config_ext->hdr.sig)) {
@@ -227,7 +241,7 @@ static void skl_get_mclk(struct skl_dev *skl, struct skl_ssp_clk *mclk,
                return;
 
        mclk[id].rate_cfg[0].rate = parent->rate/div_ratio;
-       mclk[id].rate_cfg[0].config = &fmt->fmt_config[0];
+       mclk[id].rate_cfg[0].config = fmt_cfg;
        mclk[id].parent_name = parent->name;
 }
 
index 19c4a90..ee59ef3 100644 (file)
@@ -147,6 +147,12 @@ static int q6apm_dai_prepare(struct snd_soc_component *component,
        cfg.num_channels = runtime->channels;
        cfg.bit_width = prtd->bits_per_sample;
 
+       if (prtd->state) {
+               /* clear the previous setup if any  */
+               q6apm_graph_stop(prtd->graph);
+               q6apm_unmap_memory_regions(prtd->graph, substream->stream);
+       }
+
        prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
        prtd->pos = 0;
        /* rate and channels are sent to audio driver */
index f424d7a..7940192 100644 (file)
@@ -75,6 +75,7 @@ static struct audioreach_graph *q6apm_get_audioreach_graph(struct q6apm *apm, ui
        id = idr_alloc(&apm->graph_idr, graph, graph_id, graph_id + 1, GFP_KERNEL);
        if (id < 0) {
                dev_err(apm->dev, "Unable to allocate graph id (%d)\n", graph_id);
+               kfree(graph->graph);
                kfree(graph);
                mutex_unlock(&apm->lock);
                return ERR_PTR(id);
index 869c765..a8e842e 100644 (file)
@@ -62,6 +62,8 @@ struct snd_soc_dapm_widget *
 snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
                         const struct snd_soc_dapm_widget *widget);
 
+static unsigned int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg);
+
 /* dapm power sequences - make this per codec in the future */
 static int dapm_up_seq[] = {
        [snd_soc_dapm_pre] = 1,
@@ -442,6 +444,9 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
 
                        snd_soc_dapm_add_path(widget->dapm, data->widget,
                                              widget, NULL, NULL);
+               } else if (e->reg != SND_SOC_NOPM) {
+                       data->value = soc_dapm_read(widget->dapm, e->reg) &
+                                     (e->mask << e->shift_l);
                }
                break;
        default:
index e693070..d867f44 100644 (file)
@@ -526,7 +526,7 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
                return -EINVAL;
        if (mc->platform_max && tmp > mc->platform_max)
                return -EINVAL;
-       if (tmp > mc->max - mc->min + 1)
+       if (tmp > mc->max - mc->min)
                return -EINVAL;
 
        if (invert)
@@ -547,7 +547,7 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
                        return -EINVAL;
                if (mc->platform_max && tmp > mc->platform_max)
                        return -EINVAL;
-               if (tmp > mc->max - mc->min + 1)
+               if (tmp > mc->max - mc->min)
                        return -EINVAL;
 
                if (invert)
index 000ea90..e24eea7 100644 (file)
@@ -181,12 +181,20 @@ int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask)
  * Power Management.
  */
 
-static int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask)
+int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask)
 {
+       struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+       const struct sof_intel_dsp_desc *chip = hda->desc;
        unsigned int cpa;
        u32 adspcs;
        int ret;
 
+       /* restrict core_mask to host managed cores mask */
+       core_mask &= chip->host_managed_cores_mask;
+       /* return if core_mask is not valid */
+       if (!core_mask)
+               return 0;
+
        /* update bits */
        snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS,
                                HDA_DSP_ADSPCS_SPA_MASK(core_mask),
index 6429012..145d483 100644 (file)
@@ -95,9 +95,9 @@ out_put:
 }
 
 /*
- * first boot sequence has some extra steps. core 0 waits for power
- * status on core 1, so power up core 1 also momentarily, keep it in
- * reset/stall and then turn it off
+ * first boot sequence has some extra steps.
+ * power on all host managed cores and only unstall/run the boot core to boot the
+ * DSP then turn off all non boot cores (if any) is powered on.
  */
 static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
 {
@@ -110,7 +110,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
        int ret;
 
        /* step 1: power up corex */
-       ret = hda_dsp_enable_core(sdev, chip->host_managed_cores_mask);
+       ret = hda_dsp_core_power_up(sdev, chip->host_managed_cores_mask);
        if (ret < 0) {
                if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
                        dev_err(sdev->dev, "error: dsp core 0/1 power up failed\n");
@@ -127,7 +127,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
        snd_sof_dsp_write(sdev, HDA_DSP_BAR, chip->ipc_req, ipc_hdr);
 
        /* step 3: unset core 0 reset state & unstall/run core 0 */
-       ret = hda_dsp_core_run(sdev, BIT(0));
+       ret = hda_dsp_core_run(sdev, chip->init_core_mask);
        if (ret < 0) {
                if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
                        dev_err(sdev->dev,
@@ -389,7 +389,8 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
        struct snd_dma_buffer dmab;
        int ret, ret1, i;
 
-       if (hda->imrboot_supported && !sdev->first_boot) {
+       if (sdev->system_suspend_target < SOF_SUSPEND_S4 &&
+           hda->imrboot_supported && !sdev->first_boot) {
                dev_dbg(sdev->dev, "IMR restore supported, booting from IMR directly\n");
                hda->boot_iteration = 0;
                ret = hda_dsp_boot_imr(sdev);
index dc1f743..6888e0a 100644 (file)
@@ -192,79 +192,7 @@ snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev,
                goto found;
        }
 
-       switch (sof_hda_position_quirk) {
-       case SOF_HDA_POSITION_QUIRK_USE_SKYLAKE_LEGACY:
-               /*
-                * This legacy code, inherited from the Skylake driver,
-                * mixes DPIB registers and DPIB DDR updates and
-                * does not seem to follow any known hardware recommendations.
-                * It's not clear e.g. why there is a different flow
-                * for capture and playback, the only information that matters is
-                * what traffic class is used, and on all SOF-enabled platforms
-                * only VC0 is supported so the work-around was likely not necessary
-                * and quite possibly wrong.
-                */
-
-               /* DPIB/posbuf position mode:
-                * For Playback, Use DPIB register from HDA space which
-                * reflects the actual data transferred.
-                * For Capture, Use the position buffer for pointer, as DPIB
-                * is not accurate enough, its update may be completed
-                * earlier than the data written to DDR.
-                */
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-                       pos = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
-                                              AZX_REG_VS_SDXDPIB_XBASE +
-                                              (AZX_REG_VS_SDXDPIB_XINTERVAL *
-                                               hstream->index));
-               } else {
-                       /*
-                        * For capture stream, we need more workaround to fix the
-                        * position incorrect issue:
-                        *
-                        * 1. Wait at least 20us before reading position buffer after
-                        * the interrupt generated(IOC), to make sure position update
-                        * happens on frame boundary i.e. 20.833uSec for 48KHz.
-                        * 2. Perform a dummy Read to DPIB register to flush DMA
-                        * position value.
-                        * 3. Read the DMA Position from posbuf. Now the readback
-                        * value should be >= period boundary.
-                        */
-                       usleep_range(20, 21);
-                       snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
-                                        AZX_REG_VS_SDXDPIB_XBASE +
-                                        (AZX_REG_VS_SDXDPIB_XINTERVAL *
-                                         hstream->index));
-                       pos = snd_hdac_stream_get_pos_posbuf(hstream);
-               }
-               break;
-       case SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS:
-               /*
-                * In case VC1 traffic is disabled this is the recommended option
-                */
-               pos = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
-                                      AZX_REG_VS_SDXDPIB_XBASE +
-                                      (AZX_REG_VS_SDXDPIB_XINTERVAL *
-                                       hstream->index));
-               break;
-       case SOF_HDA_POSITION_QUIRK_USE_DPIB_DDR_UPDATE:
-               /*
-                * This is the recommended option when VC1 is enabled.
-                * While this isn't needed for SOF platforms it's added for
-                * consistency and debug.
-                */
-               pos = snd_hdac_stream_get_pos_posbuf(hstream);
-               break;
-       default:
-               dev_err_once(sdev->dev, "hda_position_quirk value %d not supported\n",
-                            sof_hda_position_quirk);
-               pos = 0;
-               break;
-       }
-
-       if (pos >= hstream->bufsize)
-               pos = 0;
-
+       pos = hda_dsp_stream_get_position(hstream, substream->stream, true);
 found:
        pos = bytes_to_frames(substream->runtime, pos);
 
index daeb64c..d95ae17 100644 (file)
@@ -707,12 +707,13 @@ bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev)
 }
 
 static void
-hda_dsp_set_bytes_transferred(struct hdac_stream *hstream, u64 buffer_size)
+hda_dsp_compr_bytes_transferred(struct hdac_stream *hstream, int direction)
 {
+       u64 buffer_size = hstream->bufsize;
        u64 prev_pos, pos, num_bytes;
 
        div64_u64_rem(hstream->curr_pos, buffer_size, &prev_pos);
-       pos = snd_hdac_stream_get_pos_posbuf(hstream);
+       pos = hda_dsp_stream_get_position(hstream, direction, false);
 
        if (pos < prev_pos)
                num_bytes = (buffer_size - prev_pos) +  pos;
@@ -748,8 +749,7 @@ static bool hda_dsp_stream_check(struct hdac_bus *bus, u32 status)
                        if (s->substream && sof_hda->no_ipc_position) {
                                snd_sof_pcm_period_elapsed(s->substream);
                        } else if (s->cstream) {
-                               hda_dsp_set_bytes_transferred(s,
-                                       s->cstream->runtime->buffer_size);
+                               hda_dsp_compr_bytes_transferred(s, s->cstream->direction);
                                snd_compr_fragment_elapsed(s->cstream);
                        }
                }
@@ -1009,3 +1009,89 @@ void hda_dsp_stream_free(struct snd_sof_dev *sdev)
                devm_kfree(sdev->dev, hda_stream);
        }
 }
+
+snd_pcm_uframes_t hda_dsp_stream_get_position(struct hdac_stream *hstream,
+                                             int direction, bool can_sleep)
+{
+       struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
+       struct sof_intel_hda_stream *hda_stream = hstream_to_sof_hda_stream(hext_stream);
+       struct snd_sof_dev *sdev = hda_stream->sdev;
+       snd_pcm_uframes_t pos;
+
+       switch (sof_hda_position_quirk) {
+       case SOF_HDA_POSITION_QUIRK_USE_SKYLAKE_LEGACY:
+               /*
+                * This legacy code, inherited from the Skylake driver,
+                * mixes DPIB registers and DPIB DDR updates and
+                * does not seem to follow any known hardware recommendations.
+                * It's not clear e.g. why there is a different flow
+                * for capture and playback, the only information that matters is
+                * what traffic class is used, and on all SOF-enabled platforms
+                * only VC0 is supported so the work-around was likely not necessary
+                * and quite possibly wrong.
+                */
+
+               /* DPIB/posbuf position mode:
+                * For Playback, Use DPIB register from HDA space which
+                * reflects the actual data transferred.
+                * For Capture, Use the position buffer for pointer, as DPIB
+                * is not accurate enough, its update may be completed
+                * earlier than the data written to DDR.
+                */
+               if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+                       pos = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
+                                              AZX_REG_VS_SDXDPIB_XBASE +
+                                              (AZX_REG_VS_SDXDPIB_XINTERVAL *
+                                               hstream->index));
+               } else {
+                       /*
+                        * For capture stream, we need more workaround to fix the
+                        * position incorrect issue:
+                        *
+                        * 1. Wait at least 20us before reading position buffer after
+                        * the interrupt generated(IOC), to make sure position update
+                        * happens on frame boundary i.e. 20.833uSec for 48KHz.
+                        * 2. Perform a dummy Read to DPIB register to flush DMA
+                        * position value.
+                        * 3. Read the DMA Position from posbuf. Now the readback
+                        * value should be >= period boundary.
+                        */
+                       if (can_sleep)
+                               usleep_range(20, 21);
+
+                       snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
+                                        AZX_REG_VS_SDXDPIB_XBASE +
+                                        (AZX_REG_VS_SDXDPIB_XINTERVAL *
+                                         hstream->index));
+                       pos = snd_hdac_stream_get_pos_posbuf(hstream);
+               }
+               break;
+       case SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS:
+               /*
+                * In case VC1 traffic is disabled this is the recommended option
+                */
+               pos = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
+                                      AZX_REG_VS_SDXDPIB_XBASE +
+                                      (AZX_REG_VS_SDXDPIB_XINTERVAL *
+                                       hstream->index));
+               break;
+       case SOF_HDA_POSITION_QUIRK_USE_DPIB_DDR_UPDATE:
+               /*
+                * This is the recommended option when VC1 is enabled.
+                * While this isn't needed for SOF platforms it's added for
+                * consistency and debug.
+                */
+               pos = snd_hdac_stream_get_pos_posbuf(hstream);
+               break;
+       default:
+               dev_err_once(sdev->dev, "hda_position_quirk value %d not supported\n",
+                            sof_hda_position_quirk);
+               pos = 0;
+               break;
+       }
+
+       if (pos >= hstream->bufsize)
+               pos = 0;
+
+       return pos;
+}
index 3e0f7b0..06476ff 100644 (file)
@@ -497,6 +497,7 @@ struct sof_intel_hda_stream {
  */
 int hda_dsp_probe(struct snd_sof_dev *sdev);
 int hda_dsp_remove(struct snd_sof_dev *sdev);
+int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask);
 int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask);
 int hda_dsp_enable_core(struct snd_sof_dev *sdev, unsigned int core_mask);
 int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev,
@@ -564,6 +565,9 @@ int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev,
 bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev);
 bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev);
 
+snd_pcm_uframes_t hda_dsp_stream_get_position(struct hdac_stream *hstream,
+                                             int direction, bool can_sleep);
+
 struct hdac_ext_stream *
        hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction, u32 flags);
 int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag);
index 043554d..10740c5 100644 (file)
@@ -1577,24 +1577,23 @@ static int sof_ipc3_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_
        struct sof_ipc_ctrl_data *cdata;
        int ret;
 
-       scontrol->ipc_control_data = kzalloc(scontrol->max_size, GFP_KERNEL);
-       if (!scontrol->ipc_control_data)
-               return -ENOMEM;
-
-       if (scontrol->max_size < sizeof(*cdata) ||
-           scontrol->max_size < sizeof(struct sof_abi_hdr)) {
-               ret = -EINVAL;
-               goto err;
+       if (scontrol->max_size < (sizeof(*cdata) + sizeof(struct sof_abi_hdr))) {
+               dev_err(sdev->dev, "%s: insufficient size for a bytes control: %zu.\n",
+                       __func__, scontrol->max_size);
+               return -EINVAL;
        }
 
-       /* init the get/put bytes data */
        if (scontrol->priv_size > scontrol->max_size - sizeof(*cdata)) {
-               dev_err(sdev->dev, "err: bytes data size %zu exceeds max %zu.\n",
+               dev_err(sdev->dev,
+                       "%s: bytes data size %zu exceeds max %zu.\n", __func__,
                        scontrol->priv_size, scontrol->max_size - sizeof(*cdata));
-               ret = -EINVAL;
-               goto err;
+               return -EINVAL;
        }
 
+       scontrol->ipc_control_data = kzalloc(scontrol->max_size, GFP_KERNEL);
+       if (!scontrol->ipc_control_data)
+               return -ENOMEM;
+
        scontrol->size = sizeof(struct sof_ipc_ctrl_data) + scontrol->priv_size;
 
        cdata = scontrol->ipc_control_data;
index 3333a06..e006532 100644 (file)
@@ -392,7 +392,7 @@ static int mt8186_dsp_probe(struct snd_sof_dev *sdev)
                                                      PLATFORM_DEVID_NONE,
                                                      pdev, sizeof(*pdev));
        if (IS_ERR(priv->ipc_dev)) {
-               ret = IS_ERR(priv->ipc_dev);
+               ret = PTR_ERR(priv->ipc_dev);
                dev_err(sdev->dev, "failed to create mtk-adsp-ipc device\n");
                goto err_adsp_off;
        }
index 18eb327..df740be 100644 (file)
@@ -23,6 +23,9 @@ static u32 snd_sof_dsp_power_target(struct snd_sof_dev *sdev)
        u32 target_dsp_state;
 
        switch (sdev->system_suspend_target) {
+       case SOF_SUSPEND_S5:
+       case SOF_SUSPEND_S4:
+               /* DSP should be in D3 if the system is suspending to S3+ */
        case SOF_SUSPEND_S3:
                /* DSP should be in D3 if the system is suspending to S3 */
                target_dsp_state = SOF_DSP_PM_D3;
@@ -335,8 +338,24 @@ int snd_sof_prepare(struct device *dev)
                return 0;
 
 #if defined(CONFIG_ACPI)
-       if (acpi_target_system_state() == ACPI_STATE_S0)
+       switch (acpi_target_system_state()) {
+       case ACPI_STATE_S0:
                sdev->system_suspend_target = SOF_SUSPEND_S0IX;
+               break;
+       case ACPI_STATE_S1:
+       case ACPI_STATE_S2:
+       case ACPI_STATE_S3:
+               sdev->system_suspend_target = SOF_SUSPEND_S3;
+               break;
+       case ACPI_STATE_S4:
+               sdev->system_suspend_target = SOF_SUSPEND_S4;
+               break;
+       case ACPI_STATE_S5:
+               sdev->system_suspend_target = SOF_SUSPEND_S5;
+               break;
+       default:
+               break;
+       }
 #endif
 
        return 0;
index 9d7f53f..f0f3d72 100644 (file)
@@ -85,6 +85,8 @@ enum sof_system_suspend_state {
        SOF_SUSPEND_NONE = 0,
        SOF_SUSPEND_S0IX,
        SOF_SUSPEND_S3,
+       SOF_SUSPEND_S4,
+       SOF_SUSPEND_S5,
 };
 
 enum sof_dfsentry_type {
index 7865cda..da519ea 100644 (file)
@@ -316,8 +316,6 @@ static inline int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg,
 
 /* Sidetone specific API */
 int omap_mcbsp_st_init(struct platform_device *pdev);
-void omap_mcbsp_st_cleanup(struct platform_device *pdev);
-
 int omap_mcbsp_st_start(struct omap_mcbsp *mcbsp);
 int omap_mcbsp_st_stop(struct omap_mcbsp *mcbsp);
 
index 0bc7d26..7e8179c 100644 (file)
@@ -347,7 +347,7 @@ int omap_mcbsp_st_init(struct platform_device *pdev)
        if (!st_data)
                return -ENOMEM;
 
-       st_data->mcbsp_iclk = clk_get(mcbsp->dev, "ick");
+       st_data->mcbsp_iclk = devm_clk_get(mcbsp->dev, "ick");
        if (IS_ERR(st_data->mcbsp_iclk)) {
                dev_warn(mcbsp->dev,
                         "Failed to get ick, sidetone might be broken\n");
@@ -359,7 +359,7 @@ int omap_mcbsp_st_init(struct platform_device *pdev)
        if (!st_data->io_base_st)
                return -ENOMEM;
 
-       ret = sysfs_create_group(&mcbsp->dev->kobj, &sidetone_attr_group);
+       ret = devm_device_add_group(mcbsp->dev, &sidetone_attr_group);
        if (ret)
                return ret;
 
@@ -368,16 +368,6 @@ int omap_mcbsp_st_init(struct platform_device *pdev)
        return 0;
 }
 
-void omap_mcbsp_st_cleanup(struct platform_device *pdev)
-{
-       struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
-
-       if (mcbsp->st_data) {
-               sysfs_remove_group(&mcbsp->dev->kobj, &sidetone_attr_group);
-               clk_put(mcbsp->st_data->mcbsp_iclk);
-       }
-}
-
 static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
                                    struct snd_ctl_elem_info *uinfo)
 {
index 4479d74..9933b33 100644 (file)
@@ -702,8 +702,7 @@ static int omap_mcbsp_init(struct platform_device *pdev)
                mcbsp->max_tx_thres = max_thres(mcbsp) - 0x10;
                mcbsp->max_rx_thres = max_thres(mcbsp) - 0x10;
 
-               ret = sysfs_create_group(&mcbsp->dev->kobj,
-                                        &additional_attr_group);
+               ret = devm_device_add_group(mcbsp->dev, &additional_attr_group);
                if (ret) {
                        dev_err(mcbsp->dev,
                                "Unable to create additional controls\n");
@@ -711,16 +710,7 @@ static int omap_mcbsp_init(struct platform_device *pdev)
                }
        }
 
-       ret = omap_mcbsp_st_init(pdev);
-       if (ret)
-               goto err_st;
-
-       return 0;
-
-err_st:
-       if (mcbsp->pdata->buffer_size)
-               sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
-       return ret;
+       return omap_mcbsp_st_init(pdev);
 }
 
 /*
@@ -1431,11 +1421,6 @@ static int asoc_mcbsp_remove(struct platform_device *pdev)
        if (cpu_latency_qos_request_active(&mcbsp->pm_qos_req))
                cpu_latency_qos_remove_request(&mcbsp->pm_qos_req);
 
-       if (mcbsp->pdata->buffer_size)
-               sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
-
-       omap_mcbsp_st_cleanup(pdev);
-
        return 0;
 }
 
index 4f56e17..f93201a 100644 (file)
@@ -3803,6 +3803,54 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 },
 
 /*
+ * MacroSilicon MS2100/MS2106 based AV capture cards
+ *
+ * These claim 96kHz 1ch in the descriptors, but are actually 48kHz 2ch.
+ * They also need QUIRK_FLAG_ALIGN_TRANSFER, which makes one wonder if
+ * they pretend to be 96kHz mono as a workaround for stereo being broken
+ * by that...
+ *
+ * They also have an issue with initial stream alignment that causes the
+ * channels to be swapped and out of phase, which is dealt with in quirks.c.
+ */
+{
+       USB_AUDIO_DEVICE(0x534d, 0x0021),
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .vendor_name = "MacroSilicon",
+               .product_name = "MS210x",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = &(const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_AUDIO_STANDARD_MIXER,
+                       },
+                       {
+                               .ifnum = 3,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                                       .channels = 2,
+                                       .iface = 3,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .attributes = 0,
+                                       .endpoint = 0x82,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC |
+                                               USB_ENDPOINT_SYNC_ASYNC,
+                                       .rates = SNDRV_PCM_RATE_CONTINUOUS,
+                                       .rate_min = 48000,
+                                       .rate_max = 48000,
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
+
+/*
  * MacroSilicon MS2109 based HDMI capture cards
  *
  * These claim 96kHz 1ch in the descriptors, but are actually 48kHz 2ch.
@@ -4119,6 +4167,206 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
+{
+       /*
+        * Fiero SC-01 (firmware v1.0.0 @ 48 kHz)
+        */
+       USB_DEVICE(0x2b53, 0x0023),
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .vendor_name = "Fiero",
+               .product_name = "SC-01",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = &(const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       /* Playback */
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 2,
+                                       .fmt_bits = 24,
+                                       .iface = 1,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x01,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC |
+                                                  USB_ENDPOINT_SYNC_ASYNC,
+                                       .rates = SNDRV_PCM_RATE_48000,
+                                       .rate_min = 48000,
+                                       .rate_max = 48000,
+                                       .nr_rates = 1,
+                                       .rate_table = (unsigned int[]) { 48000 },
+                                       .clock = 0x29
+                               }
+                       },
+                       /* Capture */
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 2,
+                                       .fmt_bits = 24,
+                                       .iface = 2,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x82,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC |
+                                                  USB_ENDPOINT_SYNC_ASYNC |
+                                                  USB_ENDPOINT_USAGE_IMPLICIT_FB,
+                                       .rates = SNDRV_PCM_RATE_48000,
+                                       .rate_min = 48000,
+                                       .rate_max = 48000,
+                                       .nr_rates = 1,
+                                       .rate_table = (unsigned int[]) { 48000 },
+                                       .clock = 0x29
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
+{
+       /*
+        * Fiero SC-01 (firmware v1.0.0 @ 96 kHz)
+        */
+       USB_DEVICE(0x2b53, 0x0024),
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .vendor_name = "Fiero",
+               .product_name = "SC-01",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = &(const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       /* Playback */
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 2,
+                                       .fmt_bits = 24,
+                                       .iface = 1,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x01,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC |
+                                                  USB_ENDPOINT_SYNC_ASYNC,
+                                       .rates = SNDRV_PCM_RATE_96000,
+                                       .rate_min = 96000,
+                                       .rate_max = 96000,
+                                       .nr_rates = 1,
+                                       .rate_table = (unsigned int[]) { 96000 },
+                                       .clock = 0x29
+                               }
+                       },
+                       /* Capture */
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 2,
+                                       .fmt_bits = 24,
+                                       .iface = 2,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x82,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC |
+                                                  USB_ENDPOINT_SYNC_ASYNC |
+                                                  USB_ENDPOINT_USAGE_IMPLICIT_FB,
+                                       .rates = SNDRV_PCM_RATE_96000,
+                                       .rate_min = 96000,
+                                       .rate_max = 96000,
+                                       .nr_rates = 1,
+                                       .rate_table = (unsigned int[]) { 96000 },
+                                       .clock = 0x29
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
+{
+       /*
+        * Fiero SC-01 (firmware v1.1.0)
+        */
+       USB_DEVICE(0x2b53, 0x0031),
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .vendor_name = "Fiero",
+               .product_name = "SC-01",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = &(const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       /* Playback */
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 2,
+                                       .fmt_bits = 24,
+                                       .iface = 1,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x01,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC |
+                                                  USB_ENDPOINT_SYNC_ASYNC,
+                                       .rates = SNDRV_PCM_RATE_48000 |
+                                                SNDRV_PCM_RATE_96000,
+                                       .rate_min = 48000,
+                                       .rate_max = 96000,
+                                       .nr_rates = 2,
+                                       .rate_table = (unsigned int[]) { 48000, 96000 },
+                                       .clock = 0x29
+                               }
+                       },
+                       /* Capture */
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 2,
+                                       .fmt_bits = 24,
+                                       .iface = 2,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x82,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC |
+                                                  USB_ENDPOINT_SYNC_ASYNC |
+                                                  USB_ENDPOINT_USAGE_IMPLICIT_FB,
+                                       .rates = SNDRV_PCM_RATE_48000 |
+                                                SNDRV_PCM_RATE_96000,
+                                       .rate_min = 48000,
+                                       .rate_max = 96000,
+                                       .nr_rates = 2,
+                                       .rate_table = (unsigned int[]) { 48000, 96000 },
+                                       .clock = 0x29
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
 
 #undef USB_DEVICE_VENDOR_SPEC
 #undef USB_AUDIO_DEVICE
index e8468f9..968d90c 100644 (file)
@@ -1478,6 +1478,7 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
        case USB_ID(0x041e, 0x3f19): /* E-Mu 0204 USB */
                set_format_emu_quirk(subs, fmt);
                break;
+       case USB_ID(0x534d, 0x0021): /* MacroSilicon MS2100/MS2106 */
        case USB_ID(0x534d, 0x2109): /* MacroSilicon MS2109 */
                subs->stream_offset_adj = 2;
                break;
@@ -1842,6 +1843,10 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
                   QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
        DEVICE_FLG(0x1395, 0x740a, /* Sennheiser DECT */
                   QUIRK_FLAG_GET_SAMPLE_RATE),
+       DEVICE_FLG(0x1397, 0x0508, /* Behringer UMC204HD */
+                  QUIRK_FLAG_PLAYBACK_FIRST | QUIRK_FLAG_GENERIC_IMPLICIT_FB),
+       DEVICE_FLG(0x1397, 0x0509, /* Behringer UMC404HD */
+                  QUIRK_FLAG_PLAYBACK_FIRST | QUIRK_FLAG_GENERIC_IMPLICIT_FB),
        DEVICE_FLG(0x13e5, 0x0001, /* Serato Phono */
                   QUIRK_FLAG_IGNORE_CTL_ERROR),
        DEVICE_FLG(0x154e, 0x1002, /* Denon DCD-1500RE */
@@ -1904,10 +1909,18 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
                   QUIRK_FLAG_IGNORE_CTL_ERROR),
        DEVICE_FLG(0x413c, 0xa506, /* Dell AE515 sound bar */
                   QUIRK_FLAG_GET_SAMPLE_RATE),
+       DEVICE_FLG(0x534d, 0x0021, /* MacroSilicon MS2100/MS2106 */
+                  QUIRK_FLAG_ALIGN_TRANSFER),
        DEVICE_FLG(0x534d, 0x2109, /* MacroSilicon MS2109 */
                   QUIRK_FLAG_ALIGN_TRANSFER),
        DEVICE_FLG(0x1224, 0x2a25, /* Jieli Technology USB PHY 2.0 */
                   QUIRK_FLAG_GET_SAMPLE_RATE),
+       DEVICE_FLG(0x2b53, 0x0023, /* Fiero SC-01 (firmware v1.0.0 @ 48 kHz) */
+                  QUIRK_FLAG_GENERIC_IMPLICIT_FB),
+       DEVICE_FLG(0x2b53, 0x0024, /* Fiero SC-01 (firmware v1.0.0 @ 96 kHz) */
+                  QUIRK_FLAG_GENERIC_IMPLICIT_FB),
+       DEVICE_FLG(0x2b53, 0x0031, /* Fiero SC-01 (firmware v1.1.0) */
+                  QUIRK_FLAG_GENERIC_IMPLICIT_FB),
 
        /* Vendor matches */
        VENDOR_FLG(0x045e, /* MS Lifecam */
index c074e42..e497875 100644 (file)
@@ -78,6 +78,9 @@ bpf/%: FORCE
 libapi: FORCE
        $(call descend,lib/api)
 
+nolibc: FORCE
+       $(call descend,include/nolibc)
+
 nolibc_%: FORCE
        $(call descend,include/nolibc,$(patsubst nolibc_%,%,$@))
 
index c1b6ddc..3bb1343 100644 (file)
@@ -139,8 +139,10 @@ struct kvm_guest_debug_arch {
        __u64 dbg_wvr[KVM_ARM_MAX_DBG_REGS];
 };
 
+#define KVM_DEBUG_ARCH_HSR_HIGH_VALID  (1 << 0)
 struct kvm_debug_exit_arch {
        __u32 hsr;
+       __u32 hsr_high; /* ESR_EL2[61:32] */
        __u64 far;      /* used for watchpoints */
 };
 
@@ -332,6 +334,40 @@ struct kvm_arm_copy_mte_tags {
 #define KVM_ARM64_SVE_VLS_WORDS        \
        ((KVM_ARM64_SVE_VQ_MAX - KVM_ARM64_SVE_VQ_MIN) / 64 + 1)
 
+/* Bitmap feature firmware registers */
+#define KVM_REG_ARM_FW_FEAT_BMAP               (0x0016 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM_FW_FEAT_BMAP_REG(r)                (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
+                                               KVM_REG_ARM_FW_FEAT_BMAP |      \
+                                               ((r) & 0xffff))
+
+#define KVM_REG_ARM_STD_BMAP                   KVM_REG_ARM_FW_FEAT_BMAP_REG(0)
+
+enum {
+       KVM_REG_ARM_STD_BIT_TRNG_V1_0   = 0,
+#ifdef __KERNEL__
+       KVM_REG_ARM_STD_BMAP_BIT_COUNT,
+#endif
+};
+
+#define KVM_REG_ARM_STD_HYP_BMAP               KVM_REG_ARM_FW_FEAT_BMAP_REG(1)
+
+enum {
+       KVM_REG_ARM_STD_HYP_BIT_PV_TIME = 0,
+#ifdef __KERNEL__
+       KVM_REG_ARM_STD_HYP_BMAP_BIT_COUNT,
+#endif
+};
+
+#define KVM_REG_ARM_VENDOR_HYP_BMAP            KVM_REG_ARM_FW_FEAT_BMAP_REG(2)
+
+enum {
+       KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT    = 0,
+       KVM_REG_ARM_VENDOR_HYP_BIT_PTP          = 1,
+#ifdef __KERNEL__
+       KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_COUNT,
+#endif
+};
+
 /* Device Control API: ARM VGIC */
 #define KVM_DEV_ARM_VGIC_GRP_ADDR      0
 #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1
index e17de69..a77b915 100644 (file)
 #define X86_FEATURE_INVPCID_SINGLE     ( 7*32+ 7) /* Effectively INVPCID && CR4.PCIDE=1 */
 #define X86_FEATURE_HW_PSTATE          ( 7*32+ 8) /* AMD HW-PState */
 #define X86_FEATURE_PROC_FEEDBACK      ( 7*32+ 9) /* AMD ProcFeedbackInterface */
-/* FREE!                                ( 7*32+10) */
+#define X86_FEATURE_XCOMPACTED         ( 7*32+10) /* "" Use compacted XSTATE (XSAVES or XSAVEC) */
 #define X86_FEATURE_PTI                        ( 7*32+11) /* Kernel Page Table Isolation enabled */
-#define X86_FEATURE_RETPOLINE          ( 7*32+12) /* "" Generic Retpoline mitigation for Spectre variant 2 */
-#define X86_FEATURE_RETPOLINE_LFENCE   ( 7*32+13) /* "" Use LFENCE for Spectre variant 2 */
+#define X86_FEATURE_KERNEL_IBRS                ( 7*32+12) /* "" Set/clear IBRS on kernel entry/exit */
+#define X86_FEATURE_RSB_VMEXIT         ( 7*32+13) /* "" Fill RSB on VM-Exit */
 #define X86_FEATURE_INTEL_PPIN         ( 7*32+14) /* Intel Processor Inventory Number */
 #define X86_FEATURE_CDP_L2             ( 7*32+15) /* Code and Data Prioritization L2 */
 #define X86_FEATURE_MSR_SPEC_CTRL      ( 7*32+16) /* "" MSR SPEC_CTRL is implemented */
 #define X86_FEATURE_SSBD               ( 7*32+17) /* Speculative Store Bypass Disable */
 #define X86_FEATURE_MBA                        ( 7*32+18) /* Memory Bandwidth Allocation */
 #define X86_FEATURE_RSB_CTXSW          ( 7*32+19) /* "" Fill RSB on context switches */
-/* FREE!                                ( 7*32+20) */
+#define X86_FEATURE_PERFMON_V2         ( 7*32+20) /* AMD Performance Monitoring Version 2 */
 #define X86_FEATURE_USE_IBPB           ( 7*32+21) /* "" Indirect Branch Prediction Barrier enabled */
 #define X86_FEATURE_USE_IBRS_FW                ( 7*32+22) /* "" Use IBRS during runtime firmware calls */
 #define X86_FEATURE_SPEC_STORE_BYPASS_DISABLE  ( 7*32+23) /* "" Disable Speculative Store Bypass. */
 #define X86_FEATURE_VMW_VMMCALL                ( 8*32+19) /* "" VMware prefers VMMCALL hypercall instruction */
 #define X86_FEATURE_PVUNLOCK           ( 8*32+20) /* "" PV unlock function */
 #define X86_FEATURE_VCPUPREEMPT                ( 8*32+21) /* "" PV vcpu_is_preempted function */
+#define X86_FEATURE_TDX_GUEST          ( 8*32+22) /* Intel Trust Domain Extensions Guest */
 
 /* Intel-defined CPU features, CPUID level 0x00000007:0 (EBX), word 9 */
 #define X86_FEATURE_FSGSBASE           ( 9*32+ 0) /* RDFSBASE, WRFSBASE, RDGSBASE, WRGSBASE instructions*/
 #define X86_FEATURE_PER_THREAD_MBA     (11*32+ 7) /* "" Per-thread Memory Bandwidth Allocation */
 #define X86_FEATURE_SGX1               (11*32+ 8) /* "" Basic SGX */
 #define X86_FEATURE_SGX2               (11*32+ 9) /* "" SGX Enclave Dynamic Memory Management (EDMM) */
+#define X86_FEATURE_ENTRY_IBPB         (11*32+10) /* "" Issue an IBPB on kernel entry */
+#define X86_FEATURE_RRSBA_CTRL         (11*32+11) /* "" RET prediction control */
+#define X86_FEATURE_RETPOLINE          (11*32+12) /* "" Generic Retpoline mitigation for Spectre variant 2 */
+#define X86_FEATURE_RETPOLINE_LFENCE   (11*32+13) /* "" Use LFENCE for Spectre variant 2 */
+#define X86_FEATURE_RETHUNK            (11*32+14) /* "" Use REturn THUNK */
+#define X86_FEATURE_UNRET              (11*32+15) /* "" AMD BTB untrain return */
+#define X86_FEATURE_USE_IBPB_FW                (11*32+16) /* "" Use IBPB during runtime firmware calls */
 
 /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */
 #define X86_FEATURE_AVX_VNNI           (12*32+ 4) /* AVX VNNI instructions */
 #define X86_FEATURE_VIRT_SSBD          (13*32+25) /* Virtualized Speculative Store Bypass Disable */
 #define X86_FEATURE_AMD_SSB_NO         (13*32+26) /* "" Speculative Store Bypass is fixed in hardware. */
 #define X86_FEATURE_CPPC               (13*32+27) /* Collaborative Processor Performance Control */
+#define X86_FEATURE_BTC_NO             (13*32+29) /* "" Not vulnerable to Branch Type Confusion */
+#define X86_FEATURE_BRS                        (13*32+31) /* Branch Sampling available */
 
 /* Thermal and Power Management Leaf, CPUID level 0x00000006 (EAX), word 14 */
 #define X86_FEATURE_DTHERM             (14*32+ 0) /* Digital Thermal Sensor */
 #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_V_TSC_AUX          (19*32+ 9) /* "" Virtual TSC_AUX */
 #define X86_FEATURE_SME_COHERENT       (19*32+10) /* "" AMD hardware-enforced cache coherency */
 
 /*
 #define X86_BUG_ITLB_MULTIHIT          X86_BUG(23) /* CPU may incur MCE during certain page attribute changes */
 #define X86_BUG_SRBDS                  X86_BUG(24) /* CPU may leak RNG bits if not mitigated */
 #define X86_BUG_MMIO_STALE_DATA                X86_BUG(25) /* CPU is affected by Processor MMIO Stale Data vulnerabilities */
+#define X86_BUG_RETBLEED               X86_BUG(26) /* CPU is affected by RETBleed */
 
 #endif /* _ASM_X86_CPUFEATURES_H */
index 1ae0fab..33d2cd0 100644 (file)
 # define DISABLE_PTI           (1 << (X86_FEATURE_PTI & 31))
 #endif
 
+#ifdef CONFIG_RETPOLINE
+# define DISABLE_RETPOLINE     0
+#else
+# define DISABLE_RETPOLINE     ((1 << (X86_FEATURE_RETPOLINE & 31)) | \
+                                (1 << (X86_FEATURE_RETPOLINE_LFENCE & 31)))
+#endif
+
+#ifdef CONFIG_RETHUNK
+# define DISABLE_RETHUNK       0
+#else
+# define DISABLE_RETHUNK       (1 << (X86_FEATURE_RETHUNK & 31))
+#endif
+
+#ifdef CONFIG_CPU_UNRET_ENTRY
+# define DISABLE_UNRET         0
+#else
+# define DISABLE_UNRET         (1 << (X86_FEATURE_UNRET & 31))
+#endif
+
 #ifdef CONFIG_INTEL_IOMMU_SVM
 # define DISABLE_ENQCMD                0
 #else
 # define DISABLE_SGX   (1 << (X86_FEATURE_SGX & 31))
 #endif
 
+#ifdef CONFIG_INTEL_TDX_GUEST
+# define DISABLE_TDX_GUEST     0
+#else
+# define DISABLE_TDX_GUEST     (1 << (X86_FEATURE_TDX_GUEST & 31))
+#endif
+
 /*
  * Make sure to add features to the correct mask
  */
 #define DISABLED_MASK5 0
 #define DISABLED_MASK6 0
 #define DISABLED_MASK7 (DISABLE_PTI)
-#define DISABLED_MASK8 0
+#define DISABLED_MASK8 (DISABLE_TDX_GUEST)
 #define DISABLED_MASK9 (DISABLE_SGX)
 #define DISABLED_MASK10        0
-#define DISABLED_MASK11        0
+#define DISABLED_MASK11        (DISABLE_RETPOLINE|DISABLE_RETHUNK|DISABLE_UNRET)
 #define DISABLED_MASK12        0
 #define DISABLED_MASK13        0
 #define DISABLED_MASK14        0
index d27e058..cc615be 100644 (file)
@@ -51,6 +51,8 @@
 #define SPEC_CTRL_STIBP                        BIT(SPEC_CTRL_STIBP_SHIFT)      /* STIBP mask */
 #define SPEC_CTRL_SSBD_SHIFT           2          /* Speculative Store Bypass Disable bit */
 #define SPEC_CTRL_SSBD                 BIT(SPEC_CTRL_SSBD_SHIFT)       /* Speculative Store Bypass Disable */
+#define SPEC_CTRL_RRSBA_DIS_S_SHIFT    6          /* Disable RRSBA behavior */
+#define SPEC_CTRL_RRSBA_DIS_S          BIT(SPEC_CTRL_RRSBA_DIS_S_SHIFT)
 
 #define MSR_IA32_PRED_CMD              0x00000049 /* Prediction Command */
 #define PRED_CMD_IBPB                  BIT(0)     /* Indirect Branch Prediction Barrier */
@@ -93,6 +95,7 @@
 #define MSR_IA32_ARCH_CAPABILITIES     0x0000010a
 #define ARCH_CAP_RDCL_NO               BIT(0)  /* Not susceptible to Meltdown */
 #define ARCH_CAP_IBRS_ALL              BIT(1)  /* Enhanced IBRS support */
+#define ARCH_CAP_RSBA                  BIT(2)  /* RET may use alternative branch predictors */
 #define ARCH_CAP_SKIP_VMENTRY_L1DFLUSH BIT(3)  /* Skip L1D flush on vmentry */
 #define ARCH_CAP_SSB_NO                        BIT(4)  /*
                                                 * Not susceptible to Speculative Store Bypass
                                                 * bit available to control VERW
                                                 * behavior.
                                                 */
+#define ARCH_CAP_RRSBA                 BIT(19) /*
+                                                * Indicates RET may use predictors
+                                                * other than the RSB. With eIBRS
+                                                * enabled predictions in kernel mode
+                                                * are restricted to targets in
+                                                * kernel.
+                                                */
 
 #define MSR_IA32_FLUSH_CMD             0x0000010b
 #define L1D_FLUSH                      BIT(0)  /*
 /* Fam 17h MSRs */
 #define MSR_F17H_IRPERF                        0xc00000e9
 
+#define MSR_ZEN2_SPECTRAL_CHICKEN      0xc00110e3
+#define MSR_ZEN2_SPECTRAL_CHICKEN_BIT  BIT_ULL(1)
+
 /* Fam 16h MSRs */
 #define MSR_F16H_L2I_PERF_CTL          0xc0010230
 #define MSR_F16H_L2I_PERF_CTR          0xc0010231
index 2161480..ec53c9f 100644 (file)
@@ -198,13 +198,13 @@ struct kvm_msrs {
        __u32 nmsrs; /* number of msrs in entries */
        __u32 pad;
 
-       struct kvm_msr_entry entries[0];
+       struct kvm_msr_entry entries[];
 };
 
 /* for KVM_GET_MSR_INDEX_LIST */
 struct kvm_msr_list {
        __u32 nmsrs; /* number of msrs in entries */
-       __u32 indices[0];
+       __u32 indices[];
 };
 
 /* Maximum size of any access bitmap in bytes */
@@ -241,7 +241,7 @@ struct kvm_cpuid_entry {
 struct kvm_cpuid {
        __u32 nent;
        __u32 padding;
-       struct kvm_cpuid_entry entries[0];
+       struct kvm_cpuid_entry entries[];
 };
 
 struct kvm_cpuid_entry2 {
@@ -263,7 +263,7 @@ struct kvm_cpuid_entry2 {
 struct kvm_cpuid2 {
        __u32 nent;
        __u32 padding;
-       struct kvm_cpuid_entry2 entries[0];
+       struct kvm_cpuid_entry2 entries[];
 };
 
 /* for KVM_GET_PIT and KVM_SET_PIT */
@@ -389,7 +389,7 @@ struct kvm_xsave {
         * the contents of CPUID leaf 0xD on the host.
         */
        __u32 region[1024];
-       __u32 extra[0];
+       __u32 extra[];
 };
 
 #define KVM_MAX_XCRS   16
@@ -516,7 +516,7 @@ struct kvm_pmu_event_filter {
        __u32 fixed_counter_bitmap;
        __u32 flags;
        __u32 pad[4];
-       __u64 events[0];
+       __u64 events[];
 };
 
 #define KVM_PMU_EVENT_ALLOW 0
index efa9693..f69c168 100644 (file)
 #define SVM_VMGEXIT_AP_JUMP_TABLE              0x80000005
 #define SVM_VMGEXIT_SET_AP_JUMP_TABLE          0
 #define SVM_VMGEXIT_GET_AP_JUMP_TABLE          1
+#define SVM_VMGEXIT_PSC                                0x80000010
+#define SVM_VMGEXIT_GUEST_REQUEST              0x80000011
+#define SVM_VMGEXIT_EXT_GUEST_REQUEST          0x80000012
+#define SVM_VMGEXIT_AP_CREATION                        0x80000013
+#define SVM_VMGEXIT_AP_CREATE_ON_INIT          0
+#define SVM_VMGEXIT_AP_CREATE                  1
+#define SVM_VMGEXIT_AP_DESTROY                 2
+#define SVM_VMGEXIT_HV_FEATURES                        0x8000fffd
 #define SVM_VMGEXIT_UNSUPPORTED_EVENT          0x8000ffff
 
 /* Exit code reserved for hypervisor/software use */
        { SVM_VMGEXIT_NMI_COMPLETE,     "vmgexit_nmi_complete" }, \
        { SVM_VMGEXIT_AP_HLT_LOOP,      "vmgexit_ap_hlt_loop" }, \
        { SVM_VMGEXIT_AP_JUMP_TABLE,    "vmgexit_ap_jump_table" }, \
+       { SVM_VMGEXIT_PSC,              "vmgexit_page_state_change" }, \
+       { SVM_VMGEXIT_GUEST_REQUEST,    "vmgexit_guest_request" }, \
+       { SVM_VMGEXIT_EXT_GUEST_REQUEST, "vmgexit_ext_guest_request" }, \
+       { SVM_VMGEXIT_AP_CREATION,      "vmgexit_ap_creation" }, \
+       { SVM_VMGEXIT_HV_FEATURES,      "vmgexit_hypervisor_feature" }, \
        { SVM_EXIT_ERR,         "invalid_guest_state" }
 
 
index 15b940e..62c54ff 100644 (file)
@@ -32,11 +32,16 @@ struct unwind_hint {
  *
  * UNWIND_HINT_FUNC: Generate the unwind metadata of a callable function.
  * Useful for code which doesn't have an ELF function annotation.
+ *
+ * UNWIND_HINT_ENTRY: machine entry without stack, SYSCALL/SYSENTER etc.
  */
 #define UNWIND_HINT_TYPE_CALL          0
 #define UNWIND_HINT_TYPE_REGS          1
 #define UNWIND_HINT_TYPE_REGS_PARTIAL  2
 #define UNWIND_HINT_TYPE_FUNC          3
+#define UNWIND_HINT_TYPE_ENTRY         4
+#define UNWIND_HINT_TYPE_SAVE          5
+#define UNWIND_HINT_TYPE_RESTORE       6
 
 #ifdef CONFIG_OBJTOOL
 
@@ -62,7 +67,7 @@ struct unwind_hint {
  * It should only be used in special cases where you're 100% sure it won't
  * affect the reliability of frame pointers and kernel stack traces.
  *
- * For more information, see tools/objtool/Documentation/stack-validation.txt.
+ * For more information, see tools/objtool/Documentation/objtool.txt.
  */
 #define STACK_FRAME_NON_STANDARD(func) \
        static void __used __section(".discard.func_stack_frame_non_standard") \
@@ -124,7 +129,7 @@ struct unwind_hint {
  * the debuginfo as necessary.  It will also warn if it sees any
  * inconsistencies.
  */
-.macro UNWIND_HINT sp_reg:req sp_offset=0 type:req end=0
+.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 end=0
 .Lunwind_hint_ip_\@:
        .pushsection .discard.unwind_hints
                /* struct unwind_hint */
@@ -177,7 +182,7 @@ struct unwind_hint {
 #define ASM_REACHABLE
 #else
 #define ANNOTATE_INTRA_FUNCTION_CALL
-.macro UNWIND_HINT sp_reg:req sp_offset=0 type:req end=0
+.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 end=0
 .endm
 .macro STACK_FRAME_NON_STANDARD func:req
 .endm
index c8d9f19..967294b 100644 (file)
@@ -1,4 +1,6 @@
 #ifndef _TOOLS_PERF_LINUX_SCHED_MM_H
 #define _TOOLS_PERF_LINUX_SCHED_MM_H
 
+#define might_alloc(gfp)       do { } while (0)
+
 #endif  /* _TOOLS_PERF_LINUX_SCHED_MM_H */
index 7a16d91..cfd0676 100644 (file)
@@ -7,13 +7,46 @@ ifeq ($(srctree),)
 srctree := $(patsubst %/tools/include/,%,$(dir $(CURDIR)))
 endif
 
+# when run as make -C tools/ nolibc_<foo> the arch is not set
+ifeq ($(ARCH),)
+include $(srctree)/scripts/subarch.include
+ARCH = $(SUBARCH)
+endif
+
+# OUTPUT is only set when run from the main makefile, otherwise
+# it defaults to this nolibc directory.
+OUTPUT ?= $(CURDIR)/
+
+ifeq ($(V),1)
+Q=
+else
+Q=@
+endif
+
 nolibc_arch := $(patsubst arm64,aarch64,$(ARCH))
 arch_file := arch-$(nolibc_arch).h
 all_files := ctype.h errno.h nolibc.h signal.h std.h stdio.h stdlib.h string.h \
              sys.h time.h types.h unistd.h
 
 # install all headers needed to support a bare-metal compiler
-all:
+all: headers
+
+install: help
+
+help:
+       @echo "Supported targets under nolibc:"
+       @echo "  all                 call \"headers\""
+       @echo "  clean               clean the sysroot"
+       @echo "  headers             prepare a sysroot in tools/include/nolibc/sysroot"
+       @echo "  headers_standalone  like \"headers\", and also install kernel headers"
+       @echo "  help                this help"
+       @echo ""
+       @echo "These targets may also be called from tools as \"make nolibc_<target>\"."
+       @echo ""
+       @echo "Currently using the following variables:"
+       @echo "  ARCH    = $(ARCH)"
+       @echo "  OUTPUT  = $(OUTPUT)"
+       @echo ""
 
 # Note: when ARCH is "x86" we concatenate both x86_64 and i386
 headers:
@@ -36,7 +69,7 @@ headers:
 
 headers_standalone: headers
        $(Q)$(MAKE) -C $(srctree) headers
-       $(Q)$(MAKE) -C $(srctree) headers_install INSTALL_HDR_PATH=$(OUTPUT)/sysroot
+       $(Q)$(MAKE) -C $(srctree) headers_install INSTALL_HDR_PATH=$(OUTPUT)sysroot
 
 clean:
        $(call QUIET_CLEAN, nolibc) rm -rf "$(OUTPUT)sysroot"
index 15dedf8..a3cebc4 100644 (file)
@@ -273,7 +273,7 @@ int vfprintf(FILE *stream, const char *fmt, va_list args)
        return written;
 }
 
-static __attribute__((unused))
+static __attribute__((unused, format(printf, 2, 3)))
 int fprintf(FILE *stream, const char *fmt, ...)
 {
        va_list args;
@@ -285,7 +285,7 @@ int fprintf(FILE *stream, const char *fmt, ...)
        return ret;
 }
 
-static __attribute__((unused))
+static __attribute__((unused, format(printf, 1, 2)))
 int printf(const char *fmt, ...)
 {
        va_list args;
index 8fd32ea..92378c4 100644 (file)
@@ -128,10 +128,9 @@ void *malloc(size_t len)
 static __attribute__((unused))
 void *calloc(size_t size, size_t nmemb)
 {
-       void *orig;
-       size_t res = 0;
+       size_t x = size * nmemb;
 
-       if (__builtin_expect(__builtin_mul_overflow(nmemb, size, &res), 0)) {
+       if (__builtin_expect(size && ((x / size) != nmemb), 0)) {
                SET_ERRNO(ENOMEM);
                return NULL;
        }
@@ -140,7 +139,7 @@ void *calloc(size_t size, size_t nmemb)
         * No need to zero the heap, the MAP_ANONYMOUS in malloc()
         * already does it.
         */
-       return malloc(res);
+       return malloc(x);
 }
 
 static __attribute__((unused))
index 0197042..1ecdb91 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
 #ifndef _ASM_GENERIC_FCNTL_H
 #define _ASM_GENERIC_FCNTL_H
 
@@ -90,7 +91,7 @@
 
 /* a horrid kludge trying to make sure that this will fail on old kernels */
 #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
-#define O_TMPFILE_MASK (__O_TMPFILE | O_DIRECTORY | O_CREAT)
+#define O_TMPFILE_MASK (__O_TMPFILE | O_DIRECTORY | O_CREAT)      
 
 #ifndef O_NDELAY
 #define O_NDELAY       O_NONBLOCK
 #define F_GETSIG       11      /* for sockets. */
 #endif
 
+#if __BITS_PER_LONG == 32 || defined(__KERNEL__)
 #ifndef F_GETLK64
 #define F_GETLK64      12      /*  using 'struct flock64' */
 #define F_SETLK64      13
 #define F_SETLKW64     14
 #endif
+#endif /* __BITS_PER_LONG == 32 || defined(__KERNEL__) */
 
 #ifndef F_SETOWN_EX
 #define F_SETOWN_EX    15
@@ -178,6 +181,10 @@ struct f_owner_ex {
                                   blocking */
 #define LOCK_UN                8       /* remove lock */
 
+/*
+ * LOCK_MAND support has been removed from the kernel. We leave the symbols
+ * here to not break legacy builds, but these should not be used in new code.
+ */
 #define LOCK_MAND      32      /* This is a mandatory flock ... */
 #define LOCK_READ      64      /* which allows concurrent read operations */
 #define LOCK_WRITE     128     /* which allows concurrent write operations */
@@ -185,6 +192,7 @@ struct f_owner_ex {
 
 #define F_LINUX_SPECIFIC_BASE  1024
 
+#ifndef HAVE_ARCH_STRUCT_FLOCK
 struct flock {
        short   l_type;
        short   l_whence;
@@ -209,5 +217,6 @@ struct flock64 {
        __ARCH_FLOCK64_PAD
 #endif
 };
+#endif /* HAVE_ARCH_STRUCT_FLOCK */
 
 #endif /* _ASM_GENERIC_FCNTL_H */
index 05c3642..b28ff5d 100644 (file)
@@ -154,25 +154,77 @@ enum i915_mocs_table_index {
        I915_MOCS_CACHED,
 };
 
-/*
+/**
+ * enum drm_i915_gem_engine_class - uapi engine type enumeration
+ *
  * Different engines serve different roles, and there may be more than one
- * engine serving each role. enum drm_i915_gem_engine_class provides a
- * classification of the role of the engine, which may be used when requesting
- * operations to be performed on a certain subset of engines, or for providing
- * information about that group.
+ * engine serving each role.  This enum provides a classification of the role
+ * of the engine, which may be used when requesting operations to be performed
+ * on a certain subset of engines, or for providing information about that
+ * group.
  */
 enum drm_i915_gem_engine_class {
+       /**
+        * @I915_ENGINE_CLASS_RENDER:
+        *
+        * Render engines support instructions used for 3D, Compute (GPGPU),
+        * and programmable media workloads.  These instructions fetch data and
+        * dispatch individual work items to threads that operate in parallel.
+        * The threads run small programs (called "kernels" or "shaders") on
+        * the GPU's execution units (EUs).
+        */
        I915_ENGINE_CLASS_RENDER        = 0,
+
+       /**
+        * @I915_ENGINE_CLASS_COPY:
+        *
+        * Copy engines (also referred to as "blitters") support instructions
+        * that move blocks of data from one location in memory to another,
+        * or that fill a specified location of memory with fixed data.
+        * Copy engines can perform pre-defined logical or bitwise operations
+        * on the source, destination, or pattern data.
+        */
        I915_ENGINE_CLASS_COPY          = 1,
+
+       /**
+        * @I915_ENGINE_CLASS_VIDEO:
+        *
+        * Video engines (also referred to as "bit stream decode" (BSD) or
+        * "vdbox") support instructions that perform fixed-function media
+        * decode and encode.
+        */
        I915_ENGINE_CLASS_VIDEO         = 2,
+
+       /**
+        * @I915_ENGINE_CLASS_VIDEO_ENHANCE:
+        *
+        * Video enhancement engines (also referred to as "vebox") support
+        * instructions related to image enhancement.
+        */
        I915_ENGINE_CLASS_VIDEO_ENHANCE = 3,
 
-       /* should be kept compact */
+       /**
+        * @I915_ENGINE_CLASS_COMPUTE:
+        *
+        * Compute engines support a subset of the instructions available
+        * on render engines:  compute engines support Compute (GPGPU) and
+        * programmable media workloads, but do not support the 3D pipeline.
+        */
+       I915_ENGINE_CLASS_COMPUTE       = 4,
 
+       /* Values in this enum should be kept compact. */
+
+       /**
+        * @I915_ENGINE_CLASS_INVALID:
+        *
+        * Placeholder value to represent an invalid engine class assignment.
+        */
        I915_ENGINE_CLASS_INVALID       = -1
 };
 
-/*
+/**
+ * struct i915_engine_class_instance - Engine class/instance identifier
+ *
  * There may be more than one engine fulfilling any role within the system.
  * Each engine of a class is given a unique instance number and therefore
  * any engine can be specified by its class:instance tuplet. APIs that allow
@@ -180,10 +232,21 @@ enum drm_i915_gem_engine_class {
  * for this identification.
  */
 struct i915_engine_class_instance {
-       __u16 engine_class; /* see enum drm_i915_gem_engine_class */
-       __u16 engine_instance;
+       /**
+        * @engine_class:
+        *
+        * Engine class from enum drm_i915_gem_engine_class
+        */
+       __u16 engine_class;
 #define I915_ENGINE_CLASS_INVALID_NONE -1
 #define I915_ENGINE_CLASS_INVALID_VIRTUAL -2
+
+       /**
+        * @engine_instance:
+        *
+        * Engine instance.
+        */
+       __u16 engine_instance;
 };
 
 /**
@@ -2060,7 +2123,7 @@ struct i915_context_engines_load_balance {
 
        __u64 mbz64; /* reserved for future use; must be zero */
 
-       struct i915_engine_class_instance engines[0];
+       struct i915_engine_class_instance engines[];
 } __attribute__((packed));
 
 #define I915_DEFINE_CONTEXT_ENGINES_LOAD_BALANCE(name__, N__) struct { \
@@ -2098,7 +2161,7 @@ struct i915_context_engines_bond {
        __u64 flags; /* all undefined flags must be zero */
        __u64 mbz64[4]; /* reserved for future use; must be zero */
 
-       struct i915_engine_class_instance engines[0];
+       struct i915_engine_class_instance engines[];
 } __attribute__((packed));
 
 #define I915_DEFINE_CONTEXT_ENGINES_BOND(name__, N__) struct { \
@@ -2225,7 +2288,7 @@ struct i915_context_engines_parallel_submit {
         * length = width (i) * num_siblings (j)
         * index = j + i * num_siblings
         */
-       struct i915_engine_class_instance engines[0];
+       struct i915_engine_class_instance engines[];
 
 } __packed;
 
@@ -2657,24 +2720,65 @@ enum drm_i915_perf_record_type {
        DRM_I915_PERF_RECORD_MAX /* non-ABI */
 };
 
-/*
+/**
+ * struct drm_i915_perf_oa_config
+ *
  * Structure to upload perf dynamic configuration into the kernel.
  */
 struct drm_i915_perf_oa_config {
-       /** String formatted like "%08x-%04x-%04x-%04x-%012x" */
+       /**
+        * @uuid:
+        *
+        * String formatted like "%\08x-%\04x-%\04x-%\04x-%\012x"
+        */
        char uuid[36];
 
+       /**
+        * @n_mux_regs:
+        *
+        * Number of mux regs in &mux_regs_ptr.
+        */
        __u32 n_mux_regs;
+
+       /**
+        * @n_boolean_regs:
+        *
+        * Number of boolean regs in &boolean_regs_ptr.
+        */
        __u32 n_boolean_regs;
+
+       /**
+        * @n_flex_regs:
+        *
+        * Number of flex regs in &flex_regs_ptr.
+        */
        __u32 n_flex_regs;
 
-       /*
-        * These fields are pointers to tuples of u32 values (register address,
-        * value). For example the expected length of the buffer pointed by
-        * mux_regs_ptr is (2 * sizeof(u32) * n_mux_regs).
+       /**
+        * @mux_regs_ptr:
+        *
+        * Pointer to tuples of u32 values (register address, value) for mux
+        * registers.  Expected length of buffer is (2 * sizeof(u32) *
+        * &n_mux_regs).
         */
        __u64 mux_regs_ptr;
+
+       /**
+        * @boolean_regs_ptr:
+        *
+        * Pointer to tuples of u32 values (register address, value) for mux
+        * registers.  Expected length of buffer is (2 * sizeof(u32) *
+        * &n_boolean_regs).
+        */
        __u64 boolean_regs_ptr;
+
+       /**
+        * @flex_regs_ptr:
+        *
+        * Pointer to tuples of u32 values (register address, value) for mux
+        * registers.  Expected length of buffer is (2 * sizeof(u32) *
+        * &n_flex_regs).
+        */
        __u64 flex_regs_ptr;
 };
 
@@ -2685,12 +2789,24 @@ struct drm_i915_perf_oa_config {
  * @data_ptr is also depends on the specific @query_id.
  */
 struct drm_i915_query_item {
-       /** @query_id: The id for this query */
+       /**
+        * @query_id:
+        *
+        * The id for this query.  Currently accepted query IDs are:
+        *  - %DRM_I915_QUERY_TOPOLOGY_INFO (see struct drm_i915_query_topology_info)
+        *  - %DRM_I915_QUERY_ENGINE_INFO (see struct drm_i915_engine_info)
+        *  - %DRM_I915_QUERY_PERF_CONFIG (see struct drm_i915_query_perf_config)
+        *  - %DRM_I915_QUERY_MEMORY_REGIONS (see struct drm_i915_query_memory_regions)
+        *  - %DRM_I915_QUERY_HWCONFIG_BLOB (see `GuC HWCONFIG blob uAPI`)
+        *  - %DRM_I915_QUERY_GEOMETRY_SUBSLICES (see struct drm_i915_query_topology_info)
+        */
        __u64 query_id;
-#define DRM_I915_QUERY_TOPOLOGY_INFO    1
-#define DRM_I915_QUERY_ENGINE_INFO     2
-#define DRM_I915_QUERY_PERF_CONFIG      3
-#define DRM_I915_QUERY_MEMORY_REGIONS   4
+#define DRM_I915_QUERY_TOPOLOGY_INFO           1
+#define DRM_I915_QUERY_ENGINE_INFO             2
+#define DRM_I915_QUERY_PERF_CONFIG             3
+#define DRM_I915_QUERY_MEMORY_REGIONS          4
+#define DRM_I915_QUERY_HWCONFIG_BLOB           5
+#define DRM_I915_QUERY_GEOMETRY_SUBSLICES      6
 /* Must be kept compact -- no holes and well documented */
 
        /**
@@ -2706,14 +2822,17 @@ struct drm_i915_query_item {
        /**
         * @flags:
         *
-        * When query_id == DRM_I915_QUERY_TOPOLOGY_INFO, must be 0.
+        * When &query_id == %DRM_I915_QUERY_TOPOLOGY_INFO, must be 0.
         *
-        * When query_id == DRM_I915_QUERY_PERF_CONFIG, must be one of the
+        * When &query_id == %DRM_I915_QUERY_PERF_CONFIG, must be one of the
         * following:
         *
-        *      - DRM_I915_QUERY_PERF_CONFIG_LIST
-        *      - DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_UUID
-        *      - DRM_I915_QUERY_PERF_CONFIG_FOR_UUID
+        *      - %DRM_I915_QUERY_PERF_CONFIG_LIST
+        *      - %DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_UUID
+        *      - %DRM_I915_QUERY_PERF_CONFIG_FOR_UUID
+        *
+        * When &query_id == %DRM_I915_QUERY_GEOMETRY_SUBSLICES must contain
+        * a struct i915_engine_class_instance that references a render engine.
         */
        __u32 flags;
 #define DRM_I915_QUERY_PERF_CONFIG_LIST          1
@@ -2771,66 +2890,112 @@ struct drm_i915_query {
        __u64 items_ptr;
 };
 
-/*
- * Data written by the kernel with query DRM_I915_QUERY_TOPOLOGY_INFO :
- *
- * data: contains the 3 pieces of information :
- *
- * - the slice mask with one bit per slice telling whether a slice is
- *   available. The availability of slice X can be queried with the following
- *   formula :
- *
- *           (data[X / 8] >> (X % 8)) & 1
- *
- * - the subslice mask for each slice with one bit per subslice telling
- *   whether a subslice is available. Gen12 has dual-subslices, which are
- *   similar to two gen11 subslices. For gen12, this array represents dual-
- *   subslices. The availability of subslice Y in slice X can be queried
- *   with the following formula :
- *
- *           (data[subslice_offset +
- *                 X * subslice_stride +
- *                 Y / 8] >> (Y % 8)) & 1
- *
- * - the EU mask for each subslice in each slice with one bit per EU telling
- *   whether an EU is available. The availability of EU Z in subslice Y in
- *   slice X can be queried with the following formula :
+/**
+ * struct drm_i915_query_topology_info
  *
- *           (data[eu_offset +
- *                 (X * max_subslices + Y) * eu_stride +
- *                 Z / 8] >> (Z % 8)) & 1
+ * Describes slice/subslice/EU information queried by
+ * %DRM_I915_QUERY_TOPOLOGY_INFO
  */
 struct drm_i915_query_topology_info {
-       /*
+       /**
+        * @flags:
+        *
         * Unused for now. Must be cleared to zero.
         */
        __u16 flags;
 
+       /**
+        * @max_slices:
+        *
+        * The number of bits used to express the slice mask.
+        */
        __u16 max_slices;
+
+       /**
+        * @max_subslices:
+        *
+        * The number of bits used to express the subslice mask.
+        */
        __u16 max_subslices;
+
+       /**
+        * @max_eus_per_subslice:
+        *
+        * The number of bits in the EU mask that correspond to a single
+        * subslice's EUs.
+        */
        __u16 max_eus_per_subslice;
 
-       /*
+       /**
+        * @subslice_offset:
+        *
         * Offset in data[] at which the subslice masks are stored.
         */
        __u16 subslice_offset;
 
-       /*
+       /**
+        * @subslice_stride:
+        *
         * Stride at which each of the subslice masks for each slice are
         * stored.
         */
        __u16 subslice_stride;
 
-       /*
+       /**
+        * @eu_offset:
+        *
         * Offset in data[] at which the EU masks are stored.
         */
        __u16 eu_offset;
 
-       /*
+       /**
+        * @eu_stride:
+        *
         * Stride at which each of the EU masks for each subslice are stored.
         */
        __u16 eu_stride;
 
+       /**
+        * @data:
+        *
+        * Contains 3 pieces of information :
+        *
+        * - The slice mask with one bit per slice telling whether a slice is
+        *   available. The availability of slice X can be queried with the
+        *   following formula :
+        *
+        *   .. code:: c
+        *
+        *      (data[X / 8] >> (X % 8)) & 1
+        *
+        *   Starting with Xe_HP platforms, Intel hardware no longer has
+        *   traditional slices so i915 will always report a single slice
+        *   (hardcoded slicemask = 0x1) which contains all of the platform's
+        *   subslices.  I.e., the mask here does not reflect any of the newer
+        *   hardware concepts such as "gslices" or "cslices" since userspace
+        *   is capable of inferring those from the subslice mask.
+        *
+        * - The subslice mask for each slice with one bit per subslice telling
+        *   whether a subslice is available.  Starting with Gen12 we use the
+        *   term "subslice" to refer to what the hardware documentation
+        *   describes as a "dual-subslices."  The availability of subslice Y
+        *   in slice X can be queried with the following formula :
+        *
+        *   .. code:: c
+        *
+        *      (data[subslice_offset + X * subslice_stride + Y / 8] >> (Y % 8)) & 1
+        *
+        * - The EU mask for each subslice in each slice, with one bit per EU
+        *   telling whether an EU is available. The availability of EU Z in
+        *   subslice Y in slice X can be queried with the following formula :
+        *
+        *   .. code:: c
+        *
+        *      (data[eu_offset +
+        *            (X * max_subslices + Y) * eu_stride +
+        *            Z / 8
+        *       ] >> (Z % 8)) & 1
+        */
        __u8 data[];
 };
 
@@ -2951,52 +3116,68 @@ struct drm_i915_query_engine_info {
        struct drm_i915_engine_info engines[];
 };
 
-/*
- * Data written by the kernel with query DRM_I915_QUERY_PERF_CONFIG.
+/**
+ * struct drm_i915_query_perf_config
+ *
+ * Data written by the kernel with query %DRM_I915_QUERY_PERF_CONFIG and
+ * %DRM_I915_QUERY_GEOMETRY_SUBSLICES.
  */
 struct drm_i915_query_perf_config {
        union {
-               /*
-                * When query_item.flags == DRM_I915_QUERY_PERF_CONFIG_LIST, i915 sets
-                * this fields to the number of configurations available.
+               /**
+                * @n_configs:
+                *
+                * When &drm_i915_query_item.flags ==
+                * %DRM_I915_QUERY_PERF_CONFIG_LIST, i915 sets this fields to
+                * the number of configurations available.
                 */
                __u64 n_configs;
 
-               /*
-                * When query_id == DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_ID,
-                * i915 will use the value in this field as configuration
-                * identifier to decide what data to write into config_ptr.
+               /**
+                * @config:
+                *
+                * When &drm_i915_query_item.flags ==
+                * %DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_ID, i915 will use the
+                * value in this field as configuration identifier to decide
+                * what data to write into config_ptr.
                 */
                __u64 config;
 
-               /*
-                * When query_id == DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_UUID,
-                * i915 will use the value in this field as configuration
-                * identifier to decide what data to write into config_ptr.
+               /**
+                * @uuid:
+                *
+                * When &drm_i915_query_item.flags ==
+                * %DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_UUID, i915 will use the
+                * value in this field as configuration identifier to decide
+                * what data to write into config_ptr.
                 *
                 * String formatted like "%08x-%04x-%04x-%04x-%012x"
                 */
                char uuid[36];
        };
 
-       /*
+       /**
+        * @flags:
+        *
         * Unused for now. Must be cleared to zero.
         */
        __u32 flags;
 
-       /*
-        * When query_item.flags == DRM_I915_QUERY_PERF_CONFIG_LIST, i915 will
-        * write an array of __u64 of configuration identifiers.
+       /**
+        * @data:
         *
-        * When query_item.flags == DRM_I915_QUERY_PERF_CONFIG_DATA, i915 will
-        * write a struct drm_i915_perf_oa_config. If the following fields of
-        * drm_i915_perf_oa_config are set not set to 0, i915 will write into
-        * the associated pointers the values of submitted when the
+        * When &drm_i915_query_item.flags == %DRM_I915_QUERY_PERF_CONFIG_LIST,
+        * i915 will write an array of __u64 of configuration identifiers.
+        *
+        * When &drm_i915_query_item.flags == %DRM_I915_QUERY_PERF_CONFIG_DATA,
+        * i915 will write a struct drm_i915_perf_oa_config. If the following
+        * fields of struct drm_i915_perf_oa_config are not set to 0, i915 will
+        * write into the associated pointers the values of submitted when the
         * configuration was created :
         *
-        *         - n_mux_regs
-        *         - n_boolean_regs
-        *         - n_flex_regs
+        *  - &drm_i915_perf_oa_config.n_mux_regs
+        *  - &drm_i915_perf_oa_config.n_boolean_regs
+        *  - &drm_i915_perf_oa_config.n_flex_regs
         */
        __u8 data[];
 };
@@ -3135,6 +3316,16 @@ struct drm_i915_query_memory_regions {
 };
 
 /**
+ * DOC: GuC HWCONFIG blob uAPI
+ *
+ * The GuC produces a blob with information about the current device.
+ * i915 reads this blob from GuC and makes it available via this uAPI.
+ *
+ * The format and meaning of the blob content are documented in the
+ * Programmer's Reference Manual.
+ */
+
+/**
  * struct drm_i915_gem_create_ext - Existing gem_create behaviour, with added
  * extension support using struct i915_user_extension.
  *
index f4009db..ef78e0e 100644 (file)
@@ -5222,22 +5222,25 @@ union bpf_attr {
  *     Return
  *             Nothing. Always succeeds.
  *
- * long bpf_dynptr_read(void *dst, u32 len, struct bpf_dynptr *src, u32 offset)
+ * long bpf_dynptr_read(void *dst, u32 len, struct bpf_dynptr *src, u32 offset, u64 flags)
  *     Description
  *             Read *len* bytes from *src* into *dst*, starting from *offset*
  *             into *src*.
+ *             *flags* is currently unused.
  *     Return
  *             0 on success, -E2BIG if *offset* + *len* exceeds the length
- *             of *src*'s data, -EINVAL if *src* is an invalid dynptr.
+ *             of *src*'s data, -EINVAL if *src* is an invalid dynptr or if
+ *             *flags* is not 0.
  *
- * long bpf_dynptr_write(struct bpf_dynptr *dst, u32 offset, void *src, u32 len)
+ * long bpf_dynptr_write(struct bpf_dynptr *dst, u32 offset, void *src, u32 len, u64 flags)
  *     Description
  *             Write *len* bytes from *src* into *dst*, starting from *offset*
  *             into *dst*.
+ *             *flags* is currently unused.
  *     Return
  *             0 on success, -E2BIG if *offset* + *len* exceeds the length
  *             of *dst*'s data, -EINVAL if *dst* is an invalid dynptr or if *dst*
- *             is a read-only dynptr.
+ *             is a read-only dynptr or if *flags* is not 0.
  *
  * void *bpf_dynptr_data(struct bpf_dynptr *ptr, u32 offset, u32 len)
  *     Description
index bdf7b40..b7b5687 100644 (file)
@@ -90,7 +90,7 @@ struct file_dedupe_range {
        __u16 dest_count;       /* in - total elements in info array */
        __u16 reserved1;        /* must be zero */
        __u32 reserved2;        /* must be zero */
-       struct file_dedupe_range_info info[0];
+       struct file_dedupe_range_info info[];
 };
 
 /* And dynamically-tunable limits and defaults: */
index 454ae31..2ec07de 100644 (file)
@@ -108,7 +108,7 @@ struct tun_pi {
 struct tun_filter {
        __u16  flags; /* TUN_FLT_ flags see above */
        __u16  count; /* Number of addresses */
-       __u8   addr[0][ETH_ALEN];
+       __u8   addr[][ETH_ALEN];
 };
 
 #endif /* _UAPI__IF_TUN_H */
index 6a184d2..cb6e384 100644 (file)
@@ -444,6 +444,9 @@ struct kvm_run {
 #define KVM_SYSTEM_EVENT_SHUTDOWN       1
 #define KVM_SYSTEM_EVENT_RESET          2
 #define KVM_SYSTEM_EVENT_CRASH          3
+#define KVM_SYSTEM_EVENT_WAKEUP         4
+#define KVM_SYSTEM_EVENT_SUSPEND        5
+#define KVM_SYSTEM_EVENT_SEV_TERM       6
                        __u32 type;
                        __u32 ndata;
                        union {
@@ -539,7 +542,7 @@ struct kvm_coalesced_mmio {
 
 struct kvm_coalesced_mmio_ring {
        __u32 first, last;
-       struct kvm_coalesced_mmio coalesced_mmio[0];
+       struct kvm_coalesced_mmio coalesced_mmio[];
 };
 
 #define KVM_COALESCED_MMIO_MAX \
@@ -618,7 +621,7 @@ struct kvm_clear_dirty_log {
 /* for KVM_SET_SIGNAL_MASK */
 struct kvm_signal_mask {
        __u32 len;
-       __u8  sigset[0];
+       __u8  sigset[];
 };
 
 /* for KVM_TPR_ACCESS_REPORTING */
@@ -646,6 +649,7 @@ struct kvm_vapic_addr {
 #define KVM_MP_STATE_OPERATING         7
 #define KVM_MP_STATE_LOAD              8
 #define KVM_MP_STATE_AP_RESET_HOLD     9
+#define KVM_MP_STATE_SUSPENDED         10
 
 struct kvm_mp_state {
        __u32 mp_state;
@@ -1150,8 +1154,9 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_S390_MEM_OP_EXTENSION 211
 #define KVM_CAP_PMU_CAPABILITY 212
 #define KVM_CAP_DISABLE_QUIRKS2 213
-/* #define KVM_CAP_VM_TSC_CONTROL 214 */
+#define KVM_CAP_VM_TSC_CONTROL 214
 #define KVM_CAP_SYSTEM_EVENT_DATA 215
+#define KVM_CAP_ARM_SYSTEM_SUSPEND 216
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -1216,7 +1221,7 @@ struct kvm_irq_routing_entry {
 struct kvm_irq_routing {
        __u32 nr;
        __u32 flags;
-       struct kvm_irq_routing_entry entries[0];
+       struct kvm_irq_routing_entry entries[];
 };
 
 #endif
@@ -1240,6 +1245,7 @@ struct kvm_x86_mce {
 #define KVM_XEN_HVM_CONFIG_SHARED_INFO         (1 << 2)
 #define KVM_XEN_HVM_CONFIG_RUNSTATE            (1 << 3)
 #define KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL       (1 << 4)
+#define KVM_XEN_HVM_CONFIG_EVTCHN_SEND         (1 << 5)
 
 struct kvm_xen_hvm_config {
        __u32 flags;
@@ -1335,7 +1341,7 @@ struct kvm_dirty_tlb {
 
 struct kvm_reg_list {
        __u64 n; /* number of regs */
-       __u64 reg[0];
+       __u64 reg[];
 };
 
 struct kvm_one_reg {
@@ -1478,7 +1484,8 @@ struct kvm_s390_ucas_mapping {
 #define KVM_SET_PIT2              _IOW(KVMIO,  0xa0, struct kvm_pit_state2)
 /* Available with KVM_CAP_PPC_GET_PVINFO */
 #define KVM_PPC_GET_PVINFO       _IOW(KVMIO,  0xa1, struct kvm_ppc_pvinfo)
-/* Available with KVM_CAP_TSC_CONTROL */
+/* Available with KVM_CAP_TSC_CONTROL for a vCPU, or with
+*  KVM_CAP_VM_TSC_CONTROL to set defaults for a VM */
 #define KVM_SET_TSC_KHZ           _IO(KVMIO,  0xa2)
 #define KVM_GET_TSC_KHZ           _IO(KVMIO,  0xa3)
 /* Available with KVM_CAP_PCI_2_3 */
@@ -1694,6 +1701,32 @@ struct kvm_xen_hvm_attr {
                struct {
                        __u64 gfn;
                } shared_info;
+               struct {
+                       __u32 send_port;
+                       __u32 type; /* EVTCHNSTAT_ipi / EVTCHNSTAT_interdomain */
+                       __u32 flags;
+#define KVM_XEN_EVTCHN_DEASSIGN                (1 << 0)
+#define KVM_XEN_EVTCHN_UPDATE          (1 << 1)
+#define KVM_XEN_EVTCHN_RESET           (1 << 2)
+                       /*
+                        * Events sent by the guest are either looped back to
+                        * the guest itself (potentially on a different port#)
+                        * or signalled via an eventfd.
+                        */
+                       union {
+                               struct {
+                                       __u32 port;
+                                       __u32 vcpu;
+                                       __u32 priority;
+                               } port;
+                               struct {
+                                       __u32 port; /* Zero for eventfd */
+                                       __s32 fd;
+                               } eventfd;
+                               __u32 padding[4];
+                       } deliver;
+               } evtchn;
+               __u32 xen_version;
                __u64 pad[8];
        } u;
 };
@@ -1702,11 +1735,17 @@ struct kvm_xen_hvm_attr {
 #define KVM_XEN_ATTR_TYPE_LONG_MODE            0x0
 #define KVM_XEN_ATTR_TYPE_SHARED_INFO          0x1
 #define KVM_XEN_ATTR_TYPE_UPCALL_VECTOR                0x2
+/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_EVTCHN_SEND */
+#define KVM_XEN_ATTR_TYPE_EVTCHN               0x3
+#define KVM_XEN_ATTR_TYPE_XEN_VERSION          0x4
 
 /* Per-vCPU Xen attributes */
 #define KVM_XEN_VCPU_GET_ATTR  _IOWR(KVMIO, 0xca, struct kvm_xen_vcpu_attr)
 #define KVM_XEN_VCPU_SET_ATTR  _IOW(KVMIO,  0xcb, struct kvm_xen_vcpu_attr)
 
+/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_EVTCHN_SEND */
+#define KVM_XEN_HVM_EVTCHN_SEND        _IOW(KVMIO,  0xd0, struct kvm_irq_routing_xen_evtchn)
+
 #define KVM_GET_SREGS2             _IOR(KVMIO,  0xcc, struct kvm_sregs2)
 #define KVM_SET_SREGS2             _IOW(KVMIO,  0xcd, struct kvm_sregs2)
 
@@ -1724,6 +1763,13 @@ struct kvm_xen_vcpu_attr {
                        __u64 time_blocked;
                        __u64 time_offline;
                } runstate;
+               __u32 vcpu_id;
+               struct {
+                       __u32 port;
+                       __u32 priority;
+                       __u64 expires_ns;
+               } timer;
+               __u8 vector;
        } u;
 };
 
@@ -1734,6 +1780,10 @@ struct kvm_xen_vcpu_attr {
 #define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_CURRENT        0x3
 #define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA   0x4
 #define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST 0x5
+/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_EVTCHN_SEND */
+#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_ID         0x6
+#define KVM_XEN_VCPU_ATTR_TYPE_TIMER           0x7
+#define KVM_XEN_VCPU_ATTR_TYPE_UPCALL_VECTOR   0x8
 
 /* Secure Encrypted Virtualization command */
 enum sev_cmd_id {
@@ -2033,7 +2083,8 @@ struct kvm_stats_header {
 #define KVM_STATS_UNIT_BYTES           (0x1 << KVM_STATS_UNIT_SHIFT)
 #define KVM_STATS_UNIT_SECONDS         (0x2 << KVM_STATS_UNIT_SHIFT)
 #define KVM_STATS_UNIT_CYCLES          (0x3 << KVM_STATS_UNIT_SHIFT)
-#define KVM_STATS_UNIT_MAX             KVM_STATS_UNIT_CYCLES
+#define KVM_STATS_UNIT_BOOLEAN         (0x4 << KVM_STATS_UNIT_SHIFT)
+#define KVM_STATS_UNIT_MAX             KVM_STATS_UNIT_BOOLEAN
 
 #define KVM_STATS_BASE_SHIFT           8
 #define KVM_STATS_BASE_MASK            (0xF << KVM_STATS_BASE_SHIFT)
index d37629d..4653834 100644 (file)
@@ -491,7 +491,7 @@ struct perf_event_query_bpf {
        /*
         * User provided buffer to store program ids
         */
-       __u32   ids[0];
+       __u32   ids[];
 };
 
 /*
index 1215377..3faee01 100644 (file)
@@ -180,7 +180,7 @@ struct tc_u32_sel {
 
        short                   hoff;
        __be32                  hmask;
-       struct tc_u32_key       keys[0];
+       struct tc_u32_key       keys[];
 };
 
 struct tc_u32_mark {
@@ -192,7 +192,7 @@ struct tc_u32_mark {
 struct tc_u32_pcnt {
        __u64 rcnt;
        __u64 rhit;
-       __u64 kcnts[0];
+       __u64 kcnts[];
 };
 
 /* Flags */
index 286e8d6..f94baf1 100644 (file)
@@ -30,7 +30,7 @@ struct ipv6_sr_hdr {
        __u8    flags;
        __u16   tag;
 
-       struct in6_addr segments[0];
+       struct in6_addr segments[];
 };
 
 #define SR6_FLAG1_PROTECTED    (1 << 6)
@@ -49,7 +49,7 @@ struct ipv6_sr_hdr {
 struct sr6_tlv {
        __u8 type;
        __u8 len;
-       __u8 data[0];
+       __u8 data[];
 };
 
 #endif
index cf525cd..74a84e0 100644 (file)
@@ -131,7 +131,7 @@ struct usbdevfs_urb {
        unsigned int signr;     /* signal to be sent on completion,
                                  or 0 if none should be sent. */
        void __user *usercontext;
-       struct usbdevfs_iso_packet_desc iso_frame_desc[0];
+       struct usbdevfs_iso_packet_desc iso_frame_desc[];
 };
 
 /* ioctls for talking directly to drivers */
@@ -176,7 +176,7 @@ struct usbdevfs_disconnect_claim {
 struct usbdevfs_streams {
        unsigned int num_streams; /* Not used by USBDEVFS_FREE_STREAMS */
        unsigned int num_eps;
-       unsigned char eps[0];
+       unsigned char eps[];
 };
 
 /*
index 5d99e7c..cab645d 100644 (file)
 
 /* Set or get vhost backend capability */
 
-/* Use message type V2 */
-#define VHOST_BACKEND_F_IOTLB_MSG_V2 0x1
-/* IOTLB can accept batching hints */
-#define VHOST_BACKEND_F_IOTLB_BATCH  0x2
-
 #define VHOST_SET_BACKEND_FEATURES _IOW(VHOST_VIRTIO, 0x25, __u64)
 #define VHOST_GET_BACKEND_FEATURES _IOR(VHOST_VIRTIO, 0x26, __u64)
 
 /* Get the valid iova range */
 #define VHOST_VDPA_GET_IOVA_RANGE      _IOR(VHOST_VIRTIO, 0x78, \
                                             struct vhost_vdpa_iova_range)
-
 /* Get the config size */
 #define VHOST_VDPA_GET_CONFIG_SIZE     _IOR(VHOST_VIRTIO, 0x79, __u32)
 
 /* Get the count of all virtqueues */
 #define VHOST_VDPA_GET_VQS_COUNT       _IOR(VHOST_VIRTIO, 0x80, __u32)
 
+/* Get the number of virtqueue groups. */
+#define VHOST_VDPA_GET_GROUP_NUM       _IOR(VHOST_VIRTIO, 0x81, __u32)
+
+/* Get the number of address spaces. */
+#define VHOST_VDPA_GET_AS_NUM          _IOR(VHOST_VIRTIO, 0x7A, unsigned int)
+
+/* Get the group for a virtqueue: read index, write group in num,
+ * The virtqueue index is stored in the index field of
+ * vhost_vring_state. The group for this specific virtqueue is
+ * returned via num field of vhost_vring_state.
+ */
+#define VHOST_VDPA_GET_VRING_GROUP     _IOWR(VHOST_VIRTIO, 0x7B,       \
+                                             struct vhost_vring_state)
+/* Set the ASID for a virtqueue group. The group index is stored in
+ * the index field of vhost_vring_state, the ASID associated with this
+ * group is stored at num field of vhost_vring_state.
+ */
+#define VHOST_VDPA_SET_GROUP_ASID      _IOW(VHOST_VIRTIO, 0x7C, \
+                                            struct vhost_vring_state)
+
 #endif
index 2d3e5df..3974a2a 100644 (file)
@@ -1106,7 +1106,7 @@ struct snd_ctl_elem_value {
 struct snd_ctl_tlv {
        unsigned int numid;     /* control element numeric identification */
        unsigned int length;    /* in bytes aligned to 4 */
-       unsigned int tlv[0];    /* first TLV */
+       unsigned int tlv[];     /* first TLV */
 };
 
 #define SNDRV_CTL_IOCTL_PVERSION       _IOR('U', 0x00, int)
index 8b990a5..c260006 100644 (file)
@@ -787,3 +787,8 @@ bool arch_is_retpoline(struct symbol *sym)
 {
        return !strncmp(sym->name, "__x86_indirect_", 15);
 }
+
+bool arch_is_rethunk(struct symbol *sym)
+{
+       return !strcmp(sym->name, "__x86_return_thunk");
+}
index f4c3a50..24fbe80 100644 (file)
@@ -68,6 +68,8 @@ const struct option check_options[] = {
        OPT_BOOLEAN('n', "noinstr", &opts.noinstr, "validate noinstr rules"),
        OPT_BOOLEAN('o', "orc", &opts.orc, "generate ORC metadata"),
        OPT_BOOLEAN('r', "retpoline", &opts.retpoline, "validate and annotate retpoline usage"),
+       OPT_BOOLEAN(0,   "rethunk", &opts.rethunk, "validate and annotate rethunk usage"),
+       OPT_BOOLEAN(0,   "unret", &opts.unret, "validate entry unret placement"),
        OPT_BOOLEAN('l', "sls", &opts.sls, "validate straight-line-speculation mitigations"),
        OPT_BOOLEAN('s', "stackval", &opts.stackval, "validate frame pointer rules"),
        OPT_BOOLEAN('t', "static-call", &opts.static_call, "annotate static calls"),
@@ -123,6 +125,7 @@ static bool opts_valid(void)
            opts.noinstr                ||
            opts.orc                    ||
            opts.retpoline              ||
+           opts.rethunk                ||
            opts.sls                    ||
            opts.stackval               ||
            opts.static_call            ||
@@ -135,6 +138,11 @@ static bool opts_valid(void)
                return true;
        }
 
+       if (opts.unret && !opts.rethunk) {
+               ERROR("--unret requires --rethunk");
+               return false;
+       }
+
        if (opts.dump_orc)
                return true;
 
@@ -163,6 +171,11 @@ static bool link_opts_valid(struct objtool_file *file)
                return false;
        }
 
+       if (opts.unret) {
+               ERROR("--unret requires --link");
+               return false;
+       }
+
        return true;
 }
 
index 864bb9d..0cec74d 100644 (file)
@@ -376,7 +376,8 @@ static int decode_instructions(struct objtool_file *file)
                        sec->text = true;
 
                if (!strcmp(sec->name, ".noinstr.text") ||
-                   !strcmp(sec->name, ".entry.text"))
+                   !strcmp(sec->name, ".entry.text") ||
+                   !strncmp(sec->name, ".text.__x86.", 12))
                        sec->noinstr = true;
 
                for (offset = 0; offset < sec->sh.sh_size; offset += insn->len) {
@@ -749,6 +750,52 @@ static int create_retpoline_sites_sections(struct objtool_file *file)
        return 0;
 }
 
+static int create_return_sites_sections(struct objtool_file *file)
+{
+       struct instruction *insn;
+       struct section *sec;
+       int idx;
+
+       sec = find_section_by_name(file->elf, ".return_sites");
+       if (sec) {
+               WARN("file already has .return_sites, skipping");
+               return 0;
+       }
+
+       idx = 0;
+       list_for_each_entry(insn, &file->return_thunk_list, call_node)
+               idx++;
+
+       if (!idx)
+               return 0;
+
+       sec = elf_create_section(file->elf, ".return_sites", 0,
+                                sizeof(int), idx);
+       if (!sec) {
+               WARN("elf_create_section: .return_sites");
+               return -1;
+       }
+
+       idx = 0;
+       list_for_each_entry(insn, &file->return_thunk_list, call_node) {
+
+               int *site = (int *)sec->data->d_buf + idx;
+               *site = 0;
+
+               if (elf_add_reloc_to_insn(file->elf, sec,
+                                         idx * sizeof(int),
+                                         R_X86_64_PC32,
+                                         insn->sec, insn->offset)) {
+                       WARN("elf_add_reloc_to_insn: .return_sites");
+                       return -1;
+               }
+
+               idx++;
+       }
+
+       return 0;
+}
+
 static int create_ibt_endbr_seal_sections(struct objtool_file *file)
 {
        struct instruction *insn;
@@ -1083,6 +1130,11 @@ __weak bool arch_is_retpoline(struct symbol *sym)
        return false;
 }
 
+__weak bool arch_is_rethunk(struct symbol *sym)
+{
+       return false;
+}
+
 #define NEGATIVE_RELOC ((void *)-1L)
 
 static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *insn)
@@ -1250,6 +1302,19 @@ static void add_retpoline_call(struct objtool_file *file, struct instruction *in
        annotate_call_site(file, insn, false);
 }
 
+static void add_return_call(struct objtool_file *file, struct instruction *insn, bool add)
+{
+       /*
+        * Return thunk tail calls are really just returns in disguise,
+        * so convert them accordingly.
+        */
+       insn->type = INSN_RETURN;
+       insn->retpoline_safe = true;
+
+       if (add)
+               list_add_tail(&insn->call_node, &file->return_thunk_list);
+}
+
 static bool same_function(struct instruction *insn1, struct instruction *insn2)
 {
        return insn1->func->pfunc == insn2->func->pfunc;
@@ -1302,6 +1367,9 @@ static int add_jump_destinations(struct objtool_file *file)
                } else if (reloc->sym->retpoline_thunk) {
                        add_retpoline_call(file, insn);
                        continue;
+               } else if (reloc->sym->return_thunk) {
+                       add_return_call(file, insn, true);
+                       continue;
                } else if (insn->func) {
                        /*
                         * External sibling call or internal sibling call with
@@ -1320,6 +1388,21 @@ static int add_jump_destinations(struct objtool_file *file)
 
                jump_dest = find_insn(file, dest_sec, dest_off);
                if (!jump_dest) {
+                       struct symbol *sym = find_symbol_by_offset(dest_sec, dest_off);
+
+                       /*
+                        * This is a special case for zen_untrain_ret().
+                        * It jumps to __x86_return_thunk(), but objtool
+                        * can't find the thunk's starting RET
+                        * instruction, because the RET is also in the
+                        * middle of another instruction.  Objtool only
+                        * knows about the outer instruction.
+                        */
+                       if (sym && sym->return_thunk) {
+                               add_return_call(file, insn, false);
+                               continue;
+                       }
+
                        WARN_FUNC("can't find jump dest instruction at %s+0x%lx",
                                  insn->sec, insn->offset, dest_sec->name,
                                  dest_off);
@@ -1949,16 +2032,35 @@ static int read_unwind_hints(struct objtool_file *file)
 
                insn->hint = true;
 
-               if (opts.ibt && hint->type == UNWIND_HINT_TYPE_REGS_PARTIAL) {
+               if (hint->type == UNWIND_HINT_TYPE_SAVE) {
+                       insn->hint = false;
+                       insn->save = true;
+                       continue;
+               }
+
+               if (hint->type == UNWIND_HINT_TYPE_RESTORE) {
+                       insn->restore = true;
+                       continue;
+               }
+
+               if (hint->type == UNWIND_HINT_TYPE_REGS_PARTIAL) {
                        struct symbol *sym = find_symbol_by_offset(insn->sec, insn->offset);
 
-                       if (sym && sym->bind == STB_GLOBAL &&
-                           insn->type != INSN_ENDBR && !insn->noendbr) {
-                               WARN_FUNC("UNWIND_HINT_IRET_REGS without ENDBR",
-                                         insn->sec, insn->offset);
+                       if (sym && sym->bind == STB_GLOBAL) {
+                               if (opts.ibt && insn->type != INSN_ENDBR && !insn->noendbr) {
+                                       WARN_FUNC("UNWIND_HINT_IRET_REGS without ENDBR",
+                                                 insn->sec, insn->offset);
+                               }
+
+                               insn->entry = 1;
                        }
                }
 
+               if (hint->type == UNWIND_HINT_TYPE_ENTRY) {
+                       hint->type = UNWIND_HINT_TYPE_CALL;
+                       insn->entry = 1;
+               }
+
                if (hint->type == UNWIND_HINT_TYPE_FUNC) {
                        insn->cfi = &func_cfi;
                        continue;
@@ -2032,8 +2134,10 @@ static int read_retpoline_hints(struct objtool_file *file)
                }
 
                if (insn->type != INSN_JUMP_DYNAMIC &&
-                   insn->type != INSN_CALL_DYNAMIC) {
-                       WARN_FUNC("retpoline_safe hint not an indirect jump/call",
+                   insn->type != INSN_CALL_DYNAMIC &&
+                   insn->type != INSN_RETURN &&
+                   insn->type != INSN_NOP) {
+                       WARN_FUNC("retpoline_safe hint not an indirect jump/call/ret/nop",
                                  insn->sec, insn->offset);
                        return -1;
                }
@@ -2184,6 +2288,9 @@ static int classify_symbols(struct objtool_file *file)
                        if (arch_is_retpoline(func))
                                func->retpoline_thunk = true;
 
+                       if (arch_is_rethunk(func))
+                               func->return_thunk = true;
+
                        if (!strcmp(func->name, "__fentry__"))
                                func->fentry = true;
 
@@ -3190,7 +3297,7 @@ static struct instruction *next_insn_to_validate(struct objtool_file *file,
  * Follow the branch starting at the given instruction, and recursively follow
  * any other branches (jumps).  Meanwhile, track the frame pointer state at
  * each instruction and validate all the rules described in
- * tools/objtool/Documentation/stack-validation.txt.
+ * tools/objtool/Documentation/objtool.txt.
  */
 static int validate_branch(struct objtool_file *file, struct symbol *func,
                           struct instruction *insn, struct insn_state state)
@@ -3218,8 +3325,8 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
                        return 1;
                }
 
-               visited = 1 << state.uaccess;
-               if (insn->visited) {
+               visited = VISITED_BRANCH << state.uaccess;
+               if (insn->visited & VISITED_BRANCH_MASK) {
                        if (!insn->hint && !insn_cfi_match(insn, &state.cfi))
                                return 1;
 
@@ -3233,6 +3340,35 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
                        state.instr += insn->instr;
 
                if (insn->hint) {
+                       if (insn->restore) {
+                               struct instruction *save_insn, *i;
+
+                               i = insn;
+                               save_insn = NULL;
+
+                               sym_for_each_insn_continue_reverse(file, func, i) {
+                                       if (i->save) {
+                                               save_insn = i;
+                                               break;
+                                       }
+                               }
+
+                               if (!save_insn) {
+                                       WARN_FUNC("no corresponding CFI save for CFI restore",
+                                                 sec, insn->offset);
+                                       return 1;
+                               }
+
+                               if (!save_insn->visited) {
+                                       WARN_FUNC("objtool isn't smart enough to handle this CFI save/restore combo",
+                                                 sec, insn->offset);
+                                       return 1;
+                               }
+
+                               insn->cfi = save_insn->cfi;
+                               nr_cfi_reused++;
+                       }
+
                        state.cfi = *insn->cfi;
                } else {
                        /* XXX track if we actually changed state.cfi */
@@ -3433,6 +3569,145 @@ static int validate_unwind_hints(struct objtool_file *file, struct section *sec)
        return warnings;
 }
 
+/*
+ * Validate rethunk entry constraint: must untrain RET before the first RET.
+ *
+ * Follow every branch (intra-function) and ensure ANNOTATE_UNRET_END comes
+ * before an actual RET instruction.
+ */
+static int validate_entry(struct objtool_file *file, struct instruction *insn)
+{
+       struct instruction *next, *dest;
+       int ret, warnings = 0;
+
+       for (;;) {
+               next = next_insn_to_validate(file, insn);
+
+               if (insn->visited & VISITED_ENTRY)
+                       return 0;
+
+               insn->visited |= VISITED_ENTRY;
+
+               if (!insn->ignore_alts && !list_empty(&insn->alts)) {
+                       struct alternative *alt;
+                       bool skip_orig = false;
+
+                       list_for_each_entry(alt, &insn->alts, list) {
+                               if (alt->skip_orig)
+                                       skip_orig = true;
+
+                               ret = validate_entry(file, alt->insn);
+                               if (ret) {
+                                       if (opts.backtrace)
+                                               BT_FUNC("(alt)", insn);
+                                       return ret;
+                               }
+                       }
+
+                       if (skip_orig)
+                               return 0;
+               }
+
+               switch (insn->type) {
+
+               case INSN_CALL_DYNAMIC:
+               case INSN_JUMP_DYNAMIC:
+               case INSN_JUMP_DYNAMIC_CONDITIONAL:
+                       WARN_FUNC("early indirect call", insn->sec, insn->offset);
+                       return 1;
+
+               case INSN_JUMP_UNCONDITIONAL:
+               case INSN_JUMP_CONDITIONAL:
+                       if (!is_sibling_call(insn)) {
+                               if (!insn->jump_dest) {
+                                       WARN_FUNC("unresolved jump target after linking?!?",
+                                                 insn->sec, insn->offset);
+                                       return -1;
+                               }
+                               ret = validate_entry(file, insn->jump_dest);
+                               if (ret) {
+                                       if (opts.backtrace) {
+                                               BT_FUNC("(branch%s)", insn,
+                                                       insn->type == INSN_JUMP_CONDITIONAL ? "-cond" : "");
+                                       }
+                                       return ret;
+                               }
+
+                               if (insn->type == INSN_JUMP_UNCONDITIONAL)
+                                       return 0;
+
+                               break;
+                       }
+
+                       /* fallthrough */
+               case INSN_CALL:
+                       dest = find_insn(file, insn->call_dest->sec,
+                                        insn->call_dest->offset);
+                       if (!dest) {
+                               WARN("Unresolved function after linking!?: %s",
+                                    insn->call_dest->name);
+                               return -1;
+                       }
+
+                       ret = validate_entry(file, dest);
+                       if (ret) {
+                               if (opts.backtrace)
+                                       BT_FUNC("(call)", insn);
+                               return ret;
+                       }
+                       /*
+                        * If a call returns without error, it must have seen UNTRAIN_RET.
+                        * Therefore any non-error return is a success.
+                        */
+                       return 0;
+
+               case INSN_RETURN:
+                       WARN_FUNC("RET before UNTRAIN", insn->sec, insn->offset);
+                       return 1;
+
+               case INSN_NOP:
+                       if (insn->retpoline_safe)
+                               return 0;
+                       break;
+
+               default:
+                       break;
+               }
+
+               if (!next) {
+                       WARN_FUNC("teh end!", insn->sec, insn->offset);
+                       return -1;
+               }
+               insn = next;
+       }
+
+       return warnings;
+}
+
+/*
+ * Validate that all branches starting at 'insn->entry' encounter UNRET_END
+ * before RET.
+ */
+static int validate_unret(struct objtool_file *file)
+{
+       struct instruction *insn;
+       int ret, warnings = 0;
+
+       for_each_insn(file, insn) {
+               if (!insn->entry)
+                       continue;
+
+               ret = validate_entry(file, insn);
+               if (ret < 0) {
+                       WARN_FUNC("Failed UNRET validation", insn->sec, insn->offset);
+                       return ret;
+               }
+               warnings += ret;
+       }
+
+       return warnings;
+}
+
 static int validate_retpoline(struct objtool_file *file)
 {
        struct instruction *insn;
@@ -3440,7 +3715,8 @@ static int validate_retpoline(struct objtool_file *file)
 
        for_each_insn(file, insn) {
                if (insn->type != INSN_JUMP_DYNAMIC &&
-                   insn->type != INSN_CALL_DYNAMIC)
+                   insn->type != INSN_CALL_DYNAMIC &&
+                   insn->type != INSN_RETURN)
                        continue;
 
                if (insn->retpoline_safe)
@@ -3455,9 +3731,17 @@ static int validate_retpoline(struct objtool_file *file)
                if (!strcmp(insn->sec->name, ".init.text") && !opts.module)
                        continue;
 
-               WARN_FUNC("indirect %s found in RETPOLINE build",
-                         insn->sec, insn->offset,
-                         insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call");
+               if (insn->type == INSN_RETURN) {
+                       if (opts.rethunk) {
+                               WARN_FUNC("'naked' return found in RETHUNK build",
+                                         insn->sec, insn->offset);
+                       } else
+                               continue;
+               } else {
+                       WARN_FUNC("indirect %s found in RETPOLINE build",
+                                 insn->sec, insn->offset,
+                                 insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call");
+               }
 
                warnings++;
        }
@@ -3826,8 +4110,7 @@ static int validate_ibt(struct objtool_file *file)
                    !strcmp(sec->name, "__bug_table")                   ||
                    !strcmp(sec->name, "__ex_table")                    ||
                    !strcmp(sec->name, "__jump_table")                  ||
-                   !strcmp(sec->name, "__mcount_loc")                  ||
-                   !strcmp(sec->name, "__tracepoints"))
+                   !strcmp(sec->name, "__mcount_loc"))
                        continue;
 
                list_for_each_entry(reloc, &sec->reloc->reloc_list, list)
@@ -3946,6 +4229,17 @@ int check(struct objtool_file *file)
                warnings += ret;
        }
 
+       if (opts.unret) {
+               /*
+                * Must be after validate_branch() and friends, it plays
+                * further games with insn->visited.
+                */
+               ret = validate_unret(file);
+               if (ret < 0)
+                       return ret;
+               warnings += ret;
+       }
+
        if (opts.ibt) {
                ret = validate_ibt(file);
                if (ret < 0)
@@ -3974,6 +4268,13 @@ int check(struct objtool_file *file)
                warnings += ret;
        }
 
+       if (opts.rethunk) {
+               ret = create_return_sites_sections(file);
+               if (ret < 0)
+                       goto out;
+               warnings += ret;
+       }
+
        if (opts.mcount) {
                ret = create_mcount_loc_sections(file);
                if (ret < 0)
index 9b19cc3..beb2f3a 100644 (file)
@@ -89,6 +89,7 @@ const char *arch_ret_insn(int len);
 int arch_decode_hint_reg(u8 sp_reg, int *base);
 
 bool arch_is_retpoline(struct symbol *sym);
+bool arch_is_rethunk(struct symbol *sym);
 
 int arch_rewrite_retpolines(struct objtool_file *file);
 
index 280ea18..42a52f1 100644 (file)
@@ -19,6 +19,8 @@ struct opts {
        bool noinstr;
        bool orc;
        bool retpoline;
+       bool rethunk;
+       bool unret;
        bool sls;
        bool stackval;
        bool static_call;
index f10d737..036129c 100644 (file)
@@ -46,16 +46,19 @@ struct instruction {
        enum insn_type type;
        unsigned long immediate;
 
-       u8 dead_end     : 1,
-          ignore       : 1,
-          ignore_alts  : 1,
-          hint         : 1,
-          retpoline_safe : 1,
-          noendbr      : 1;
-               /* 2 bit hole */
+       u16 dead_end            : 1,
+          ignore               : 1,
+          ignore_alts          : 1,
+          hint                 : 1,
+          save                 : 1,
+          restore              : 1,
+          retpoline_safe       : 1,
+          noendbr              : 1,
+          entry                : 1;
+               /* 7 bit hole */
+
        s8 instr;
        u8 visited;
-       /* u8 hole */
 
        struct alt_group *alt_group;
        struct symbol *call_dest;
@@ -69,6 +72,11 @@ struct instruction {
        struct cfi_state *cfi;
 };
 
+#define VISITED_BRANCH         0x01
+#define VISITED_BRANCH_UACCESS 0x02
+#define VISITED_BRANCH_MASK    0x03
+#define VISITED_ENTRY          0x04
+
 static inline bool is_static_jump(struct instruction *insn)
 {
        return insn->type == INSN_JUMP_CONDITIONAL ||
index adebfbc..16f4067 100644 (file)
@@ -57,6 +57,7 @@ struct symbol {
        u8 uaccess_safe      : 1;
        u8 static_call_tramp : 1;
        u8 retpoline_thunk   : 1;
+       u8 return_thunk      : 1;
        u8 fentry            : 1;
        u8 profiling_func    : 1;
        struct list_head pv_target;
index a6e72d9..7f2d1b0 100644 (file)
@@ -24,6 +24,7 @@ struct objtool_file {
        struct list_head insn_list;
        DECLARE_HASHTABLE(insn_hash, 20);
        struct list_head retpoline_call_list;
+       struct list_head return_thunk_list;
        struct list_head static_call_list;
        struct list_head mcount_loc_list;
        struct list_head endbr_list;
index 512669c..a7ecc32 100644 (file)
@@ -102,6 +102,7 @@ struct objtool_file *objtool_open_read(const char *_objname)
        INIT_LIST_HEAD(&file.insn_list);
        hash_init(file.insn_hash);
        INIT_LIST_HEAD(&file.retpoline_call_list);
+       INIT_LIST_HEAD(&file.return_thunk_list);
        INIT_LIST_HEAD(&file.static_call_list);
        INIT_LIST_HEAD(&file.mcount_loc_list);
        INIT_LIST_HEAD(&file.endbr_list);
index a75bf11..54d4e50 100644 (file)
@@ -891,7 +891,9 @@ static int copy_kcore_dir(struct perf_inject *inject)
        if (ret < 0)
                return ret;
        pr_debug("%s\n", cmd);
-       return system(cmd);
+       ret = system(cmd);
+       free(cmd);
+       return ret;
 }
 
 static int output_fd(struct perf_inject *inject)
@@ -916,7 +918,7 @@ static int __cmd_inject(struct perf_inject *inject)
                inject->tool.tracing_data = perf_event__repipe_tracing_data;
        }
 
-       output_data_offset = session->header.data_offset;
+       output_data_offset = perf_session__data_offset(session->evlist);
 
        if (inject->build_id_all) {
                inject->tool.mmap         = perf_event__repipe_buildid_mmap;
index 4ce87a8..d2ecd4d 100644 (file)
@@ -2586,6 +2586,8 @@ int cmd_stat(int argc, const char **argv)
        if (evlist__initialize_ctlfd(evsel_list, stat_config.ctl_fd, stat_config.ctl_fd_ack))
                goto out;
 
+       /* Enable ignoring missing threads when -p option is defined. */
+       evlist__first(evsel_list)->ignore_missing_thread = target.pid;
        status = 0;
        for (run_idx = 0; forever || run_idx < stat_config.run_count; run_idx++) {
                if (stat_config.run_count != 1 && verbose > 0)
index 897fc50..f075cf3 100644 (file)
@@ -4280,6 +4280,7 @@ static int trace__replay(struct trace *trace)
                goto out;
 
        evsel = evlist__find_tracepoint_by_name(session->evlist, "raw_syscalls:sys_enter");
+       trace->syscalls.events.sys_enter = evsel;
        /* older kernels have syscalls tp versus raw_syscalls */
        if (evsel == NULL)
                evsel = evlist__find_tracepoint_by_name(session->evlist, "syscalls:sys_enter");
@@ -4292,6 +4293,7 @@ static int trace__replay(struct trace *trace)
        }
 
        evsel = evlist__find_tracepoint_by_name(session->evlist, "raw_syscalls:sys_exit");
+       trace->syscalls.events.sys_exit = evsel;
        if (evsel == NULL)
                evsel = evlist__find_tracepoint_by_name(session->evlist, "syscalls:sys_exit");
        if (evsel &&
index 5f57d98..4339692 100755 (executable)
@@ -61,7 +61,7 @@ def get_optional(perf_dict, field):
 
 def get_offset(perf_dict, field):
        if field in perf_dict:
-               return f"+0x{perf_dict[field]:x}"
+               return "+%#x" % perf_dict[field]
        return ""
 
 def get_dso_file_path(dso_name, dso_build_id):
@@ -76,7 +76,7 @@ def get_dso_file_path(dso_name, dso_build_id):
        else:
                append = "/elf"
 
-       dso_path = f"{os.environ['PERF_BUILDID_DIR']}/{dso_name}/{dso_build_id}{append}"
+       dso_path = os.environ['PERF_BUILDID_DIR'] + "/" + dso_name + "/" + dso_build_id + append;
        # Replace duplicate slash chars to single slash char
        dso_path = dso_path.replace('//', '/', 1)
        return dso_path
@@ -94,8 +94,8 @@ def read_disam(dso_fname, dso_start, start_addr, stop_addr):
                start_addr = start_addr - dso_start;
                stop_addr = stop_addr - dso_start;
                disasm = [ options.objdump_name, "-d", "-z",
-                          f"--start-address=0x{start_addr:x}",
-                          f"--stop-address=0x{stop_addr:x}" ]
+                          "--start-address="+format(start_addr,"#x"),
+                          "--stop-address="+format(stop_addr,"#x") ]
                disasm += [ dso_fname ]
                disasm_output = check_output(disasm).decode('utf-8').split('\n')
                disasm_cache[addr_range] = disasm_output
@@ -109,12 +109,14 @@ def print_disam(dso_fname, dso_start, start_addr, stop_addr):
                        m = disasm_re.search(line)
                        if m is None:
                                continue
-               print(f"\t{line}")
+               print("\t" + line)
 
 def print_sample(sample):
-       print(f"Sample = {{ cpu: {sample['cpu']:04} addr: 0x{sample['addr']:016x} " \
-             f"phys_addr: 0x{sample['phys_addr']:016x} ip: 0x{sample['ip']:016x} " \
-             f"pid: {sample['pid']} tid: {sample['tid']} period: {sample['period']} time: {sample['time']} }}")
+       print("Sample = { cpu: %04d addr: 0x%016x phys_addr: 0x%016x ip: 0x%016x " \
+             "pid: %d tid: %d period: %d time: %d }" % \
+             (sample['cpu'], sample['addr'], sample['phys_addr'], \
+              sample['ip'], sample['pid'], sample['tid'], \
+              sample['period'], sample['time']))
 
 def trace_begin():
        print('ARM CoreSight Trace Data Assembler Dump')
@@ -131,7 +133,7 @@ def common_start_str(comm, sample):
        cpu = sample["cpu"]
        pid = sample["pid"]
        tid = sample["tid"]
-       return f"{comm:>16} {pid:>5}/{tid:<5} [{cpu:04}] {sec:9}.{ns:09}  "
+       return "%16s %5u/%-5u [%04u] %9u.%09u  " % (comm, pid, tid, cpu, sec, ns)
 
 # This code is copied from intel-pt-events.py for printing source code
 # line and symbols.
@@ -171,7 +173,7 @@ def print_srccode(comm, param_dict, sample, symbol, dso):
        glb_line_number = line_number
        glb_source_file_name = source_file_name
 
-       print(f"{start_str}{src_str}")
+       print(start_str, src_str)
 
 def process_event(param_dict):
        global cache_size
@@ -188,7 +190,7 @@ def process_event(param_dict):
        symbol = get_optional(param_dict, "symbol")
 
        if (options.verbose == True):
-               print(f"Event type: {name}")
+               print("Event type: %s" % name)
                print_sample(sample)
 
        # If cannot find dso so cannot dump assembler, bail out
@@ -197,7 +199,7 @@ def process_event(param_dict):
 
        # Validate dso start and end addresses
        if ((dso_start == '[unknown]') or (dso_end == '[unknown]')):
-               print(f"Failed to find valid dso map for dso {dso}")
+               print("Failed to find valid dso map for dso %s" % dso)
                return
 
        if (name[0:12] == "instructions"):
@@ -244,15 +246,15 @@ def process_event(param_dict):
 
        # Handle CS_ETM_TRACE_ON packet if start_addr=0 and stop_addr=4
        if (start_addr == 0 and stop_addr == 4):
-               print(f"CPU{cpu}: CS_ETM_TRACE_ON packet is inserted")
+               print("CPU%d: CS_ETM_TRACE_ON packet is inserted" % cpu)
                return
 
        if (start_addr < int(dso_start) or start_addr > int(dso_end)):
-               print(f"Start address 0x{start_addr:x} is out of range [ 0x{dso_start:x} .. 0x{dso_end:x} ] for dso {dso}")
+               print("Start address 0x%x is out of range [ 0x%x .. 0x%x ] for dso %s" % (start_addr, int(dso_start), int(dso_end), dso))
                return
 
        if (stop_addr < int(dso_start) or stop_addr > int(dso_end)):
-               print(f"Stop address 0x{stop_addr:x} is out of range [ 0x{dso_start:x} .. 0x{dso_end:x} ] for dso {dso}")
+               print("Stop address 0x%x is out of range [ 0x%x .. 0x%x ] for dso %s" % (stop_addr, int(dso_start), int(dso_end), dso))
                return
 
        if (options.objdump_name != None):
@@ -267,6 +269,6 @@ def process_event(param_dict):
                if path.exists(dso_fname):
                        print_disam(dso_fname, dso_vm_start, start_addr, stop_addr)
                else:
-                       print(f"Failed to find dso {dso} for address range [ 0x{start_addr:x} .. 0x{stop_addr:x} ]")
+                       print("Failed to find dso %s for address range [ 0x%x .. 0x%x ]" % (dso, start_addr, stop_addr))
 
        print_srccode(comm, param_dict, sample, symbol, dso)
index 4ad0dfb..7c7d20f 100644 (file)
@@ -20,8 +20,6 @@
 #include "tsc.h"
 #include "mmap.h"
 #include "tests.h"
-#include "pmu.h"
-#include "pmu-hybrid.h"
 
 /*
  * Except x86_64/i386 and Arm64, other archs don't support TSC in perf.  Just
@@ -106,28 +104,21 @@ static int test__perf_time_to_tsc(struct test_suite *test __maybe_unused, int su
 
        evlist__config(evlist, &opts, NULL);
 
-       evsel = evlist__first(evlist);
-
-       evsel->core.attr.comm = 1;
-       evsel->core.attr.disabled = 1;
-       evsel->core.attr.enable_on_exec = 0;
-
-       /*
-        * For hybrid "cycles:u", it creates two events.
-        * Init the second evsel here.
-        */
-       if (perf_pmu__has_hybrid() && perf_pmu__hybrid_mounted("cpu_atom")) {
-               evsel = evsel__next(evsel);
+       /* For hybrid "cycles:u", it creates two events */
+       evlist__for_each_entry(evlist, evsel) {
                evsel->core.attr.comm = 1;
                evsel->core.attr.disabled = 1;
                evsel->core.attr.enable_on_exec = 0;
        }
 
-       if (evlist__open(evlist) == -ENOENT) {
-               err = TEST_SKIP;
+       ret = evlist__open(evlist);
+       if (ret < 0) {
+               if (ret == -ENOENT)
+                       err = TEST_SKIP;
+               else
+                       pr_debug("evlist__open() failed\n");
                goto out_err;
        }
-       CHECK__(evlist__open(evlist));
 
        CHECK__(evlist__mmap(evlist, UINT_MAX));
 
@@ -167,10 +158,12 @@ static int test__perf_time_to_tsc(struct test_suite *test __maybe_unused, int su
                                goto next_event;
 
                        if (strcmp(event->comm.comm, comm1) == 0) {
+                               CHECK_NOT_NULL__(evsel = evlist__event2evsel(evlist, event));
                                CHECK__(evsel__parse_sample(evsel, event, &sample));
                                comm1_time = sample.time;
                        }
                        if (strcmp(event->comm.comm, comm2) == 0) {
+                               CHECK_NOT_NULL__(evsel = evlist__event2evsel(evlist, event));
                                CHECK__(evsel__parse_sample(evsel, event, &sample));
                                comm2_time = sample.time;
                        }
index 2c5f72f..37c53ba 100755 (executable)
@@ -33,23 +33,13 @@ create_errno_lookup_func()
        local arch=$(arch_string "$1")
        local nr name
 
-       cat <<EoFuncBegin
-static const char *errno_to_name__$arch(int err)
-{
-       switch (err) {
-EoFuncBegin
+       printf "static const char *errno_to_name__%s(int err)\n{\n\tswitch (err) {\n" $arch
 
        while read name nr; do
                printf '\tcase %d: return "%s";\n' $nr $name
        done
 
-       cat <<EoFuncEnd
-       default:
-               return "(unknown)";
-       }
-}
-
-EoFuncEnd
+       printf '\tdefault: return "(unknown)";\n\t}\n}\n'
 }
 
 process_arch()
index f8ad581..cdd6463 100644 (file)
@@ -63,20 +63,16 @@ static struct hashmap *bpf_map_hash;
 static struct bpf_perf_object *
 bpf_perf_object__next(struct bpf_perf_object *prev)
 {
-       struct bpf_perf_object *next;
-
-       if (!prev)
-               next = list_first_entry(&bpf_objects_list,
-                                       struct bpf_perf_object,
-                                       list);
-       else
-               next = list_next_entry(prev, list);
+       if (!prev) {
+               if (list_empty(&bpf_objects_list))
+                       return NULL;
 
-       /* Empty list is noticed here so don't need checking on entry. */
-       if (&next->list == &bpf_objects_list)
+               return list_first_entry(&bpf_objects_list, struct bpf_perf_object, list);
+       }
+       if (list_is_last(&prev->list, &bpf_objects_list))
                return NULL;
 
-       return next;
+       return list_next_entry(prev, list);
 }
 
 #define bpf_perf_object__for_each(perf_obj, tmp)       \
index e271e05..80b1d2b 100644 (file)
@@ -149,11 +149,10 @@ get_bpf_prog_info_linear(int fd, __u64 arrays)
                count = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
                size  = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
 
-               data_len += count * size;
+               data_len += roundup(count * size, sizeof(__u64));
        }
 
        /* step 3: allocate continuous memory */
-       data_len = roundup(data_len, sizeof(__u64));
        info_linear = malloc(sizeof(struct perf_bpil) + data_len);
        if (!info_linear)
                return ERR_PTR(-ENOMEM);
@@ -180,7 +179,7 @@ get_bpf_prog_info_linear(int fd, __u64 arrays)
                bpf_prog_info_set_offset_u64(&info_linear->info,
                                             desc->array_offset,
                                             ptr_to_u64(ptr));
-               ptr += count * size;
+               ptr += roundup(count * size, sizeof(__u64));
        }
 
        /* step 5: call syscall again to get required arrays */
index b73e84a..f289b77 100644 (file)
@@ -265,6 +265,12 @@ int off_cpu_write(struct perf_session *session)
 
        sample_type = evsel->core.attr.sample_type;
 
+       if (sample_type & ~OFFCPU_SAMPLE_TYPES) {
+               pr_err("not supported sample type: %llx\n",
+                      (unsigned long long)sample_type);
+               return -1;
+       }
+
        if (sample_type & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER)) {
                if (evsel->core.id)
                        sid = evsel->core.id[0];
@@ -319,7 +325,6 @@ int off_cpu_write(struct perf_session *session)
                }
                if (sample_type & PERF_SAMPLE_CGROUP)
                        data.array[n++] = key.cgroup_id;
-               /* TODO: handle more sample types */
 
                size = n * sizeof(u64);
                data.hdr.size = size;
index 792ae28..cc6d7fd 100644 (file)
@@ -71,6 +71,11 @@ struct {
        __uint(max_entries, 1);
 } cgroup_filter SEC(".maps");
 
+/* new kernel task_struct definition */
+struct task_struct___new {
+       long __state;
+} __attribute__((preserve_access_index));
+
 /* old kernel task_struct definition */
 struct task_struct___old {
        long state;
@@ -93,14 +98,17 @@ const volatile bool uses_cgroup_v1 = false;
  */
 static inline int get_task_state(struct task_struct *t)
 {
-       if (bpf_core_field_exists(t->__state))
-               return BPF_CORE_READ(t, __state);
+       /* recast pointer to capture new type for compiler */
+       struct task_struct___new *t_new = (void *)t;
 
-       /* recast pointer to capture task_struct___old type for compiler */
-       struct task_struct___old *t_old = (void *)t;
+       if (bpf_core_field_exists(t_new->__state)) {
+               return BPF_CORE_READ(t_new, __state);
+       } else {
+               /* recast pointer to capture old type for compiler */
+               struct task_struct___old *t_old = (void *)t;
 
-       /* now use old "state" name of the field */
-       return BPF_CORE_READ(t_old, state);
+               return BPF_CORE_READ(t_old, state);
+       }
 }
 
 static inline __u64 get_cgroup_id(struct task_struct *t)
index 82f3d46..328668f 100644 (file)
@@ -872,6 +872,30 @@ out_free:
        return err;
 }
 
+static int filename__read_build_id_ns(const char *filename,
+                                     struct build_id *bid,
+                                     struct nsinfo *nsi)
+{
+       struct nscookie nsc;
+       int ret;
+
+       nsinfo__mountns_enter(nsi, &nsc);
+       ret = filename__read_build_id(filename, bid);
+       nsinfo__mountns_exit(&nsc);
+
+       return ret;
+}
+
+static bool dso__build_id_mismatch(struct dso *dso, const char *name)
+{
+       struct build_id bid;
+
+       if (filename__read_build_id_ns(name, &bid, dso->nsinfo) < 0)
+               return false;
+
+       return !dso__build_id_equal(dso, &bid);
+}
+
 static int dso__cache_build_id(struct dso *dso, struct machine *machine,
                               void *priv __maybe_unused)
 {
@@ -886,6 +910,10 @@ static int dso__cache_build_id(struct dso *dso, struct machine *machine,
                is_kallsyms = true;
                name = machine->mmap_name;
        }
+
+       if (!is_kallsyms && dso__build_id_mismatch(dso, name))
+               return 0;
+
        return build_id_cache__add_b(&dso->bid, name, dso->nsinfo,
                                     is_kallsyms, is_vdso);
 }
index ce499c5..094b0a9 100644 (file)
@@ -48,6 +48,7 @@
 #include "util.h"
 #include "hashmap.h"
 #include "pmu-hybrid.h"
+#include "off_cpu.h"
 #include "../perf-sys.h"
 #include "util/parse-branch-options.h"
 #include <internal/xyarray.h>
@@ -1102,6 +1103,11 @@ static void evsel__set_default_freq_period(struct record_opts *opts,
        }
 }
 
+static bool evsel__is_offcpu_event(struct evsel *evsel)
+{
+       return evsel__is_bpf_output(evsel) && !strcmp(evsel->name, OFFCPU_EVENT);
+}
+
 /*
  * The enable_on_exec/disabled value strategy:
  *
@@ -1366,6 +1372,9 @@ void evsel__config(struct evsel *evsel, struct record_opts *opts,
         */
        if (evsel__is_dummy_event(evsel))
                evsel__reset_sample_bit(evsel, BRANCH_STACK);
+
+       if (evsel__is_offcpu_event(evsel))
+               evsel->core.attr.sample_type &= OFFCPU_SAMPLE_TYPES;
 }
 
 int evsel__set_filter(struct evsel *evsel, const char *filter)
index 53332da..6ad629d 100644 (file)
@@ -3686,6 +3686,20 @@ int perf_session__write_header(struct perf_session *session,
        return perf_session__do_write_header(session, evlist, fd, at_exit, NULL);
 }
 
+size_t perf_session__data_offset(const struct evlist *evlist)
+{
+       struct evsel *evsel;
+       size_t data_offset;
+
+       data_offset = sizeof(struct perf_file_header);
+       evlist__for_each_entry(evlist, evsel) {
+               data_offset += evsel->core.ids * sizeof(u64);
+       }
+       data_offset += evlist->core.nr_entries * sizeof(struct perf_file_attr);
+
+       return data_offset;
+}
+
 int perf_session__inject_header(struct perf_session *session,
                                struct evlist *evlist,
                                int fd,
index 08563c1..56916da 100644 (file)
@@ -136,6 +136,8 @@ int perf_session__inject_header(struct perf_session *session,
                                int fd,
                                struct feat_copier *fc);
 
+size_t perf_session__data_offset(const struct evlist *evlist);
+
 void perf_header__set_feat(struct perf_header *header, int feat);
 void perf_header__clear_feat(struct perf_header *header, int feat);
 bool perf_header__has_feat(const struct perf_header *header, int feat);
index 548008f..2dd67c6 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef PERF_UTIL_OFF_CPU_H
 #define PERF_UTIL_OFF_CPU_H
 
+#include <linux/perf_event.h>
+
 struct evlist;
 struct target;
 struct perf_session;
@@ -8,6 +10,13 @@ struct record_opts;
 
 #define OFFCPU_EVENT  "offcpu-time"
 
+#define OFFCPU_SAMPLE_TYPES  (PERF_SAMPLE_IDENTIFIER | PERF_SAMPLE_IP | \
+                             PERF_SAMPLE_TID | PERF_SAMPLE_TIME | \
+                             PERF_SAMPLE_ID | PERF_SAMPLE_CPU | \
+                             PERF_SAMPLE_PERIOD | PERF_SAMPLE_CALLCHAIN | \
+                             PERF_SAMPLE_CGROUP)
+
+
 #ifdef HAVE_BPF_SKEL
 int off_cpu_prepare(struct evlist *evlist, struct target *target,
                    struct record_opts *opts);
index ecd3779..b3be5b1 100644 (file)
@@ -233,6 +233,33 @@ Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
        return NULL;
 }
 
+static int elf_read_program_header(Elf *elf, u64 vaddr, GElf_Phdr *phdr)
+{
+       size_t i, phdrnum;
+       u64 sz;
+
+       if (elf_getphdrnum(elf, &phdrnum))
+               return -1;
+
+       for (i = 0; i < phdrnum; i++) {
+               if (gelf_getphdr(elf, i, phdr) == NULL)
+                       return -1;
+
+               if (phdr->p_type != PT_LOAD)
+                       continue;
+
+               sz = max(phdr->p_memsz, phdr->p_filesz);
+               if (!sz)
+                       continue;
+
+               if (vaddr >= phdr->p_vaddr && (vaddr < phdr->p_vaddr + sz))
+                       return 0;
+       }
+
+       /* Not found any valid program header */
+       return -1;
+}
+
 static bool want_demangle(bool is_kernel_sym)
 {
        return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle;
@@ -1209,6 +1236,7 @@ dso__load_sym_internal(struct dso *dso, struct map *map, struct symsrc *syms_ss,
                                        sym.st_value);
                        used_opd = true;
                }
+
                /*
                 * When loading symbols in a data mapping, ABS symbols (which
                 * has a value of SHN_ABS in its st_shndx) failed at
@@ -1227,6 +1255,17 @@ dso__load_sym_internal(struct dso *dso, struct map *map, struct symsrc *syms_ss,
 
                gelf_getshdr(sec, &shdr);
 
+               /*
+                * If the attribute bit SHF_ALLOC is not set, the section
+                * doesn't occupy memory during process execution.
+                * E.g. ".gnu.warning.*" section is used by linker to generate
+                * warnings when calling deprecated functions, the symbols in
+                * the section aren't loaded to memory during process execution,
+                * so skip them.
+                */
+               if (!(shdr.sh_flags & SHF_ALLOC))
+                       continue;
+
                secstrs = secstrs_sym;
 
                /*
@@ -1262,11 +1301,20 @@ dso__load_sym_internal(struct dso *dso, struct map *map, struct symsrc *syms_ss,
                                goto out_elf_end;
                } else if ((used_opd && runtime_ss->adjust_symbols) ||
                           (!used_opd && syms_ss->adjust_symbols)) {
+                       GElf_Phdr phdr;
+
+                       if (elf_read_program_header(syms_ss->elf,
+                                                   (u64)sym.st_value, &phdr)) {
+                               pr_warning("%s: failed to find program header for "
+                                          "symbol: %s st_value: %#" PRIx64 "\n",
+                                          __func__, elf_name, (u64)sym.st_value);
+                               continue;
+                       }
                        pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " "
-                                 "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__,
-                                 (u64)sym.st_value, (u64)shdr.sh_addr,
-                                 (u64)shdr.sh_offset);
-                       sym.st_value -= shdr.sh_addr - shdr.sh_offset;
+                                 "p_vaddr: %#" PRIx64 " p_offset: %#" PRIx64 "\n",
+                                 __func__, (u64)sym.st_value, (u64)phdr.p_vaddr,
+                                 (u64)phdr.p_offset);
+                       sym.st_value -= phdr.p_vaddr - phdr.p_offset;
                }
 
                demangled = demangle_sym(dso, kmodule, elf_name);
index 27acdc5..84d17bd 100644 (file)
@@ -754,7 +754,7 @@ static int __event__synthesize_thread(union perf_event *comm_event,
        snprintf(filename, sizeof(filename), "%s/proc/%d/task",
                 machine->root_dir, pid);
 
-       n = scandir(filename, &dirent, filter_task, alphasort);
+       n = scandir(filename, &dirent, filter_task, NULL);
        if (n < 0)
                return n;
 
@@ -767,11 +767,12 @@ static int __event__synthesize_thread(union perf_event *comm_event,
                if (*end)
                        continue;
 
-               rc = -1;
+               /* some threads may exit just after scan, ignore it */
                if (perf_event__prepare_comm(comm_event, pid, _pid, machine,
                                             &tgid, &ppid, &kernel_thread) != 0)
-                       break;
+                       continue;
 
+               rc = -1;
                if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid,
                                                ppid, process, machine) < 0)
                        break;
@@ -987,7 +988,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
                return 0;
 
        snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir);
-       n = scandir(proc_path, &dirent, filter_task, alphasort);
+       n = scandir(proc_path, &dirent, filter_task, NULL);
        if (n < 0)
                return err;
 
index 6e5b8cc..81b6bd6 100644 (file)
@@ -197,7 +197,7 @@ out_err:
 #ifndef NO_LIBUNWIND_DEBUG_FRAME
 static u64 elf_section_offset(int fd, const char *name)
 {
-       u64 address, offset;
+       u64 address, offset = 0;
 
        if (elf_section_address_and_offset(fd, name, &address, &offset))
                return 0;
index da468bd..e6020c0 100644 (file)
@@ -6,7 +6,7 @@
    |_|                    |___/          |_|
 
    pm-graph: suspend/resume/boot timing analysis tools
-    Version: 5.8
+    Version: 5.9
      Author: Todd Brandt <todd.e.brandt@intel.com>
   Home Page: https://01.org/pm-graph
 
@@ -97,8 +97,8 @@
         (kernel/pre-3.15/enable_trace_events_suspend_resume.patch)
         (kernel/pre-3.15/enable_trace_events_device_pm_callback.patch)
 
-       If you're using a kernel older than 3.15.0, the following
-        additional kernel parameters are required:
+       If you're using bootgraph, or sleepgraph with a kernel older than 3.15.0,
+               the following additional kernel parameters are required:
         (e.g. in file /etc/default/grub)
         GRUB_CMDLINE_LINUX_DEFAULT="... initcall_debug log_buf_len=32M ..."
 
index 2823cd3..f96f50e 100755 (executable)
@@ -69,22 +69,24 @@ class SystemValues(aslib.SystemValues):
        bootloader = 'grub'
        blexec = []
        def __init__(self):
-               self.hostname = platform.node()
+               self.kernel, self.hostname = 'unknown', platform.node()
                self.testtime = datetime.now().strftime('%Y-%m-%d_%H:%M:%S')
                if os.path.exists('/proc/version'):
                        fp = open('/proc/version', 'r')
-                       val = fp.read().strip()
+                       self.kernel = self.kernelVersion(fp.read().strip())
                        fp.close()
-                       self.kernel = self.kernelVersion(val)
-               else:
-                       self.kernel = 'unknown'
                self.testdir = datetime.now().strftime('boot-%y%m%d-%H%M%S')
        def kernelVersion(self, msg):
-               return msg.split()[2]
+               m = re.match('^[Ll]inux *[Vv]ersion *(?P<v>\S*) .*', msg)
+               if m:
+                       return m.group('v')
+               return 'unknown'
        def checkFtraceKernelVersion(self):
-               val = tuple(map(int, self.kernel.split('-')[0].split('.')))
-               if val >= (4, 10, 0):
-                       return True
+               m = re.match('^(?P<x>[0-9]*)\.(?P<y>[0-9]*)\.(?P<z>[0-9]*).*', self.kernel)
+               if m:
+                       val = tuple(map(int, m.groups()))
+                       if val >= (4, 10, 0):
+                               return True
                return False
        def kernelParams(self):
                cmdline = 'initcall_debug log_buf_len=32M'
index 962e576..4f80ad7 100644 (file)
@@ -125,7 +125,7 @@ acpi_suspend_begin:
 suspend_console:
 acpi_pm_prepare:
 syscore_suspend:
-arch_thaw_secondary_cpus_end:
+arch_enable_nonboot_cpus_end:
 syscore_resume:
 acpi_pm_finish:
 resume_console:
index ffd5095..33981ad 100755 (executable)
@@ -66,8 +66,13 @@ from threading import Thread
 from subprocess import call, Popen, PIPE
 import base64
 
+debugtiming = False
+mystarttime = time.time()
 def pprint(msg):
-       print(msg)
+       if debugtiming:
+               print('[%09.3f] %s' % (time.time()-mystarttime, msg))
+       else:
+               print(msg)
        sys.stdout.flush()
 
 def ascii(text):
@@ -81,13 +86,14 @@ def ascii(text):
 #       store system values and test parameters
 class SystemValues:
        title = 'SleepGraph'
-       version = '5.8'
+       version = '5.9'
        ansi = False
        rs = 0
        display = ''
        gzip = False
        sync = False
        wifi = False
+       netfix = False
        verbose = False
        testlog = True
        dmesglog = True
@@ -108,6 +114,7 @@ class SystemValues:
        cpucount = 0
        memtotal = 204800
        memfree = 204800
+       osversion = ''
        srgap = 0
        cgexp = False
        testdir = ''
@@ -116,6 +123,7 @@ class SystemValues:
        fpdtpath = '/sys/firmware/acpi/tables/FPDT'
        epath = '/sys/kernel/debug/tracing/events/power/'
        pmdpath = '/sys/power/pm_debug_messages'
+       s0ixpath = '/sys/module/intel_pmc_core/parameters/warn_on_s0ix_failures'
        acpipath='/sys/module/acpi/parameters/debug_level'
        traceevents = [
                'suspend_resume',
@@ -156,6 +164,7 @@ class SystemValues:
        ftop = False
        usetraceevents = False
        usetracemarkers = True
+       useftrace = True
        usekprobes = True
        usedevsrc = False
        useprocmon = False
@@ -279,10 +288,16 @@ class SystemValues:
                'intel_fbdev_set_suspend': {},
        }
        infocmds = [
+               [0, 'sysinfo', 'uname', '-a'],
+               [0, 'cpuinfo', 'head', '-7', '/proc/cpuinfo'],
                [0, 'kparams', 'cat', '/proc/cmdline'],
                [0, 'mcelog', 'mcelog'],
                [0, 'pcidevices', 'lspci', '-tv'],
-               [0, 'usbdevices', 'lsusb', '-t'],
+               [0, 'usbdevices', 'lsusb', '-tv'],
+               [0, 'acpidevices', 'sh', '-c', 'ls -l /sys/bus/acpi/devices/*/physical_node'],
+               [0, 's0ix_require', 'cat', '/sys/kernel/debug/pmc_core/substate_requirements'],
+               [0, 's0ix_debug', 'cat', '/sys/kernel/debug/pmc_core/slp_s0_debug_status'],
+               [1, 's0ix_residency', 'cat', '/sys/kernel/debug/pmc_core/slp_s0_residency_usec'],
                [1, 'interrupts', 'cat', '/proc/interrupts'],
                [1, 'wakeups', 'cat', '/sys/kernel/debug/wakeup_sources'],
                [2, 'gpecounts', 'sh', '-c', 'grep -v invalid /sys/firmware/acpi/interrupts/*'],
@@ -358,8 +373,19 @@ class SystemValues:
                        self.outputResult({'error':msg})
                        sys.exit(1)
                return False
-       def usable(self, file):
-               return (os.path.exists(file) and os.path.getsize(file) > 0)
+       def usable(self, file, ishtml=False):
+               if not os.path.exists(file) or os.path.getsize(file) < 1:
+                       return False
+               if ishtml:
+                       try:
+                               fp = open(file, 'r')
+                               res = fp.read(1000)
+                               fp.close()
+                       except:
+                               return False
+                       if '<html>' not in res:
+                               return False
+               return True
        def getExec(self, cmd):
                try:
                        fp = Popen(['which', cmd], stdout=PIPE, stderr=PIPE).stdout
@@ -413,12 +439,16 @@ class SystemValues:
                r = info['bios-release-date'] if 'bios-release-date' in info else ''
                self.sysstamp = '# sysinfo | man:%s | plat:%s | cpu:%s | bios:%s | biosdate:%s | numcpu:%d | memsz:%d | memfr:%d' % \
                        (m, p, c, b, r, self.cpucount, self.memtotal, self.memfree)
+               if self.osversion:
+                       self.sysstamp += ' | os:%s' % self.osversion
        def printSystemInfo(self, fatal=False):
                self.rootCheck(True)
                out = dmidecode(self.mempath, fatal)
                if len(out) < 1:
                        return
                fmt = '%-24s: %s'
+               if self.osversion:
+                       print(fmt % ('os-version', self.osversion))
                for name in sorted(out):
                        print(fmt % (name, out[name]))
                print(fmt % ('cpucount', ('%d' % self.cpucount)))
@@ -426,20 +456,25 @@ class SystemValues:
                print(fmt % ('memfree', ('%d kB' % self.memfree)))
        def cpuInfo(self):
                self.cpucount = 0
-               fp = open('/proc/cpuinfo', 'r')
-               for line in fp:
-                       if re.match('^processor[ \t]*:[ \t]*[0-9]*', line):
-                               self.cpucount += 1
-               fp.close()
-               fp = open('/proc/meminfo', 'r')
-               for line in fp:
-                       m = re.match('^MemTotal:[ \t]*(?P<sz>[0-9]*) *kB', line)
-                       if m:
-                               self.memtotal = int(m.group('sz'))
-                       m = re.match('^MemFree:[ \t]*(?P<sz>[0-9]*) *kB', line)
-                       if m:
-                               self.memfree = int(m.group('sz'))
-               fp.close()
+               if os.path.exists('/proc/cpuinfo'):
+                       with open('/proc/cpuinfo', 'r') as fp:
+                               for line in fp:
+                                       if re.match('^processor[ \t]*:[ \t]*[0-9]*', line):
+                                               self.cpucount += 1
+               if os.path.exists('/proc/meminfo'):
+                       with open('/proc/meminfo', 'r') as fp:
+                               for line in fp:
+                                       m = re.match('^MemTotal:[ \t]*(?P<sz>[0-9]*) *kB', line)
+                                       if m:
+                                               self.memtotal = int(m.group('sz'))
+                                       m = re.match('^MemFree:[ \t]*(?P<sz>[0-9]*) *kB', line)
+                                       if m:
+                                               self.memfree = int(m.group('sz'))
+               if os.path.exists('/etc/os-release'):
+                       with open('/etc/os-release', 'r') as fp:
+                               for line in fp:
+                                       if line.startswith('PRETTY_NAME='):
+                                               self.osversion = line[12:].strip().replace('"', '')
        def initTestOutput(self, name):
                self.prefix = self.hostname
                v = open('/proc/version', 'r').read().strip()
@@ -698,6 +733,8 @@ class SystemValues:
                        return False
                return True
        def fsetVal(self, val, path):
+               if not self.useftrace:
+                       return False
                return self.setVal(val, self.tpath+path)
        def getVal(self, file):
                res = ''
@@ -711,9 +748,11 @@ class SystemValues:
                        pass
                return res
        def fgetVal(self, path):
+               if not self.useftrace:
+                       return ''
                return self.getVal(self.tpath+path)
        def cleanupFtrace(self):
-               if(self.usecallgraph or self.usetraceevents or self.usedevsrc):
+               if self.useftrace:
                        self.fsetVal('0', 'events/kprobes/enable')
                        self.fsetVal('', 'kprobe_events')
                        self.fsetVal('1024', 'buffer_size_kb')
@@ -734,13 +773,14 @@ class SystemValues:
                                return True
                return False
        def initFtrace(self, quiet=False):
+               if not self.useftrace:
+                       return
                if not quiet:
                        sysvals.printSystemInfo(False)
                        pprint('INITIALIZING FTRACE...')
                # turn trace off
                self.fsetVal('0', 'tracing_on')
                self.cleanupFtrace()
-               self.testVal(self.pmdpath, 'basic', '1')
                # set the trace clock to global
                self.fsetVal('global', 'trace_clock')
                self.fsetVal('nop', 'current_tracer')
@@ -766,6 +806,10 @@ class SystemValues:
                        # set trace type
                        self.fsetVal('function_graph', 'current_tracer')
                        self.fsetVal('', 'set_ftrace_filter')
+                       # temporary hack to fix https://bugzilla.kernel.org/show_bug.cgi?id=212761
+                       fp = open(self.tpath+'set_ftrace_notrace', 'w')
+                       fp.write('native_queued_spin_lock_slowpath\ndev_driver_string')
+                       fp.close()
                        # set trace format options
                        self.fsetVal('print-parent', 'trace_options')
                        self.fsetVal('funcgraph-abstime', 'trace_options')
@@ -846,6 +890,8 @@ class SystemValues:
                                fp.write('# turbostat %s\n' % test['turbo'])
                        if 'wifi' in test:
                                fp.write('# wifi %s\n' % test['wifi'])
+                       if 'netfix' in test:
+                               fp.write('# netfix %s\n' % test['netfix'])
                        if test['error'] or len(testdata) > 1:
                                fp.write('# enter_sleep_error %s\n' % test['error'])
                return fp
@@ -865,6 +911,8 @@ class SystemValues:
                        fp.write('error%s: %s\n' % (n, testdata['error']))
                else:
                        fp.write('result%s: pass\n' % n)
+               if 'mode' in testdata:
+                       fp.write('mode%s: %s\n' % (n, testdata['mode']))
                for v in ['suspend', 'resume', 'boot', 'lastinit']:
                        if v in testdata:
                                fp.write('%s%s: %.3f\n' % (v, n, testdata[v]))
@@ -901,6 +949,8 @@ class SystemValues:
                        fp.write(text)
                        fp.close()
        def dlog(self, text):
+               if not self.dmesgfile:
+                       return
                self.putlog(self.dmesgfile, '# %s\n' % text)
        def flog(self, text):
                self.putlog(self.ftracefile, text)
@@ -954,34 +1004,31 @@ class SystemValues:
                        dirname = props[dev].syspath
                        if not dirname or not os.path.exists(dirname):
                                continue
-                       with open(dirname+'/power/async') as fp:
-                               text = fp.read()
-                               props[dev].isasync = False
-                               if 'enabled' in text:
+                       props[dev].isasync = False
+                       if os.path.exists(dirname+'/power/async'):
+                               fp = open(dirname+'/power/async')
+                               if 'enabled' in fp.read():
                                        props[dev].isasync = True
+                               fp.close()
                        fields = os.listdir(dirname)
-                       if 'product' in fields:
-                               with open(dirname+'/product', 'rb') as fp:
-                                       props[dev].altname = ascii(fp.read())
-                       elif 'name' in fields:
-                               with open(dirname+'/name', 'rb') as fp:
-                                       props[dev].altname = ascii(fp.read())
-                       elif 'model' in fields:
-                               with open(dirname+'/model', 'rb') as fp:
-                                       props[dev].altname = ascii(fp.read())
-                       elif 'description' in fields:
-                               with open(dirname+'/description', 'rb') as fp:
-                                       props[dev].altname = ascii(fp.read())
-                       elif 'id' in fields:
-                               with open(dirname+'/id', 'rb') as fp:
-                                       props[dev].altname = ascii(fp.read())
-                       elif 'idVendor' in fields and 'idProduct' in fields:
-                               idv, idp = '', ''
-                               with open(dirname+'/idVendor', 'rb') as fp:
-                                       idv = ascii(fp.read()).strip()
-                               with open(dirname+'/idProduct', 'rb') as fp:
-                                       idp = ascii(fp.read()).strip()
-                               props[dev].altname = '%s:%s' % (idv, idp)
+                       for file in ['product', 'name', 'model', 'description', 'id', 'idVendor']:
+                               if file not in fields:
+                                       continue
+                               try:
+                                       with open(os.path.join(dirname, file), 'rb') as fp:
+                                               props[dev].altname = ascii(fp.read())
+                               except:
+                                       continue
+                               if file == 'idVendor':
+                                       idv, idp = props[dev].altname.strip(), ''
+                                       try:
+                                               with open(os.path.join(dirname, 'idProduct'), 'rb') as fp:
+                                                       idp = ascii(fp.read()).strip()
+                                       except:
+                                               props[dev].altname = ''
+                                               break
+                                       props[dev].altname = '%s:%s' % (idv, idp)
+                               break
                        if props[dev].altname:
                                out = props[dev].altname.strip().replace('\n', ' ')\
                                        .replace(',', ' ').replace(';', ' ')
@@ -1047,7 +1094,7 @@ class SystemValues:
                                self.cmd1[name] = self.dictify(info, delta)
                        elif not debug and delta and name in self.cmd1:
                                before, after = self.cmd1[name], self.dictify(info, delta)
-                               dinfo = ('\t%s\n' % before['@']) if '@' in before else ''
+                               dinfo = ('\t%s\n' % before['@']) if '@' in before and len(before) > 1 else ''
                                prefix = self.commonPrefix(list(before.keys()))
                                for key in sorted(before):
                                        if key in after and before[key] != after[key]:
@@ -1128,6 +1175,22 @@ class SystemValues:
                        val = valline[idx]
                        out.append('%s=%s' % (key, val))
                return '|'.join(out)
+       def netfixon(self, net='both'):
+               cmd = self.getExec('netfix')
+               if not cmd:
+                       return ''
+               fp = Popen([cmd, '-s', net, 'on'], stdout=PIPE, stderr=PIPE).stdout
+               out = ascii(fp.read()).strip()
+               fp.close()
+               return out
+       def wifiRepair(self):
+               out = self.netfixon('wifi')
+               if not out or 'error' in out.lower():
+                       return ''
+               m = re.match('WIFI \S* ONLINE (?P<action>\S*)', out)
+               if not m:
+                       return 'dead'
+               return m.group('action')
        def wifiDetails(self, dev):
                try:
                        info = open('/sys/class/net/%s/device/uevent' % dev, 'r').read().strip()
@@ -1144,12 +1207,12 @@ class SystemValues:
                except:
                        return ''
                for line in reversed(w.split('\n')):
-                       m = re.match(' *(?P<dev>.*): (?P<stat>[0-9a-f]*) .*', w.split('\n')[-1])
+                       m = re.match(' *(?P<dev>.*): (?P<stat>[0-9a-f]*) .*', line)
                        if not m or (dev and dev != m.group('dev')):
                                continue
                        return m.group('dev')
                return ''
-       def pollWifi(self, dev, timeout=60):
+       def pollWifi(self, dev, timeout=10):
                start = time.time()
                while (time.time() - start) < timeout:
                        w = self.checkWifi(dev)
@@ -1157,6 +1220,11 @@ class SystemValues:
                                return '%s reconnected %.2f' % \
                                        (self.wifiDetails(dev), max(0, time.time() - start))
                        time.sleep(0.01)
+               if self.netfix:
+                       res = self.wifiRepair()
+                       if res:
+                               timeout = max(0, time.time() - start)
+                               return '%s %s %d' % (self.wifiDetails(dev), res, timeout)
                return '%s timeout %d' % (self.wifiDetails(dev), timeout)
        def errorSummary(self, errinfo, msg):
                found = False
@@ -1283,10 +1351,10 @@ sysvals = SystemValues()
 switchvalues = ['enable', 'disable', 'on', 'off', 'true', 'false', '1', '0']
 switchoff = ['disable', 'off', 'false', '0']
 suspendmodename = {
-       'freeze': 'Freeze (S0)',
-       'standby': 'Standby (S1)',
-       'mem': 'Suspend (S3)',
-       'disk': 'Hibernate (S4)'
+       'standby': 'standby (S1)',
+       'freeze': 'freeze (S2idle)',
+       'mem': 'suspend (S3)',
+       'disk': 'hibernate (S4)'
 }
 
 # Class: DevProps
@@ -1376,6 +1444,7 @@ class Data:
                'INVALID' : r'(?i).*\bINVALID\b.*',
                'CRASH'   : r'(?i).*\bCRASHED\b.*',
                'TIMEOUT' : r'(?i).*\bTIMEOUT\b.*',
+               'ABORT'   : r'(?i).*\bABORT\b.*',
                'IRQ'     : r'.*\bgenirq: .*',
                'TASKFAIL': r'.*Freezing of tasks *.*',
                'ACPI'    : r'.*\bACPI *(?P<b>[A-Za-z]*) *Error[: ].*',
@@ -1724,9 +1793,9 @@ class Data:
                                if 'waking' in self.dmesg[lp]:
                                        tCnt = self.dmesg[lp]['waking'][0]
                                        if self.dmesg[lp]['waking'][1] >= 0.001:
-                                               tTry = '-%.0f' % (round(self.dmesg[lp]['waking'][1] * 1000))
+                                               tTry = '%.0f' % (round(self.dmesg[lp]['waking'][1] * 1000))
                                        else:
-                                               tTry = '-%.3f' % (self.dmesg[lp]['waking'][1] * 1000)
+                                               tTry = '%.3f' % (self.dmesg[lp]['waking'][1] * 1000)
                                        text = '%.0f (%s ms waking %d times)' % (tL * 1000, tTry, tCnt)
                                else:
                                        text = '%.0f' % (tL * 1000)
@@ -2107,6 +2176,30 @@ class Data:
                # set resume complete to end at end marker
                if 'resume_complete' in dm:
                        dm['resume_complete']['end'] = time
+       def initcall_debug_call(self, line, quick=False):
+               m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) .* (?P<f>.*)\: '+\
+                       'PM: *calling .* @ (?P<n>.*), parent: (?P<p>.*)', line)
+               if not m:
+                       m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) .* (?P<f>.*)\: '+\
+                               'calling .* @ (?P<n>.*), parent: (?P<p>.*)', line)
+               if not m:
+                       m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) calling  '+\
+                               '(?P<f>.*)\+ @ (?P<n>.*), parent: (?P<p>.*)', line)
+               if m:
+                       return True if quick else m.group('t', 'f', 'n', 'p')
+               return False if quick else ('', '', '', '')
+       def initcall_debug_return(self, line, quick=False):
+               m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) .* (?P<f>.*)\: PM: '+\
+                       '.* returned (?P<r>[0-9]*) after (?P<dt>[0-9]*) usecs', line)
+               if not m:
+                       m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) .* (?P<f>.*)\: '+\
+                               '.* returned (?P<r>[0-9]*) after (?P<dt>[0-9]*) usecs', line)
+               if not m:
+                       m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) call '+\
+                               '(?P<f>.*)\+ returned .* after (?P<dt>.*) usecs', line)
+               if m:
+                       return True if quick else m.group('t', 'f', 'dt')
+               return False if quick else ('', '', '')
        def debugPrint(self):
                for p in self.sortedPhases():
                        list = self.dmesg[p]['list']
@@ -2880,10 +2973,11 @@ class TestProps:
        cmdlinefmt = '^# command \| (?P<cmd>.*)'
        kparamsfmt = '^# kparams \| (?P<kp>.*)'
        devpropfmt = '# Device Properties: .*'
-       pinfofmt   = '# platform-(?P<val>[a-z,A-Z,0-9]*): (?P<info>.*)'
+       pinfofmt   = '# platform-(?P<val>[a-z,A-Z,0-9,_]*): (?P<info>.*)'
        tracertypefmt = '# tracer: (?P<t>.*)'
        firmwarefmt = '# fwsuspend (?P<s>[0-9]*) fwresume (?P<r>[0-9]*)$'
        procexecfmt = 'ps - (?P<ps>.*)$'
+       procmultifmt = '@(?P<n>[0-9]*)\|(?P<ps>.*)$'
        ftrace_line_fmt_fg = \
                '^ *(?P<time>[0-9\.]*) *\| *(?P<cpu>[0-9]*)\)'+\
                ' *(?P<proc>.*)-(?P<pid>[0-9]*) *\|'+\
@@ -2893,6 +2987,9 @@ class TestProps:
                '(?P<flags>\S*) *(?P<time>[0-9\.]*): *'+\
                '(?P<msg>.*)'
        machinesuspend = 'machine_suspend\[.*'
+       multiproclist = dict()
+       multiproctime = 0.0
+       multiproccnt = 0
        def __init__(self):
                self.stamp = ''
                self.sysinfo = ''
@@ -3063,6 +3160,7 @@ class TestRun:
                self.ttemp = dict()
 
 class ProcessMonitor:
+       maxchars = 512
        def __init__(self):
                self.proclist = dict()
                self.running = False
@@ -3088,19 +3186,23 @@ class ProcessMonitor:
                        if ujiff > 0 or kjiff > 0:
                                running[pid] = ujiff + kjiff
                process.wait()
-               out = ''
+               out = ['']
                for pid in running:
                        jiffies = running[pid]
                        val = self.proclist[pid]
-                       if out:
-                               out += ','
-                       out += '%s-%s %d' % (val['name'], pid, jiffies)
-               return 'ps - '+out
+                       if len(out[-1]) > self.maxchars:
+                               out.append('')
+                       elif len(out[-1]) > 0:
+                               out[-1] += ','
+                       out[-1] += '%s-%s %d' % (val['name'], pid, jiffies)
+               if len(out) > 1:
+                       for line in out:
+                               sysvals.fsetVal('ps - @%d|%s' % (len(out), line), 'trace_marker')
+               else:
+                       sysvals.fsetVal('ps - %s' % out[0], 'trace_marker')
        def processMonitor(self, tid):
                while self.running:
-                       out = self.procstat()
-                       if out:
-                               sysvals.fsetVal(out, 'trace_marker')
+                       self.procstat()
        def start(self):
                self.thread = Thread(target=self.processMonitor, args=(0,))
                self.running = True
@@ -3144,7 +3246,6 @@ def doesTraceLogHaveTraceEvents():
 
 # Function: appendIncompleteTraceLog
 # Description:
-#       [deprecated for kernel 3.15 or newer]
 #       Adds callgraph data which lacks trace event data. This is only
 #       for timelines generated from 3.15 or older
 # Arguments:
@@ -3246,6 +3347,61 @@ def appendIncompleteTraceLog(testruns):
                                                                dev['ftrace'] = cg
                                                break
 
+# Function: loadTraceLog
+# Description:
+#       load the ftrace file into memory and fix up any ordering issues
+# Output:
+#       TestProps instance and an array of lines in proper order
+def loadTraceLog():
+       tp, data, lines, trace = TestProps(), dict(), [], []
+       tf = sysvals.openlog(sysvals.ftracefile, 'r')
+       for line in tf:
+               # remove any latent carriage returns
+               line = line.replace('\r\n', '')
+               if tp.stampInfo(line, sysvals):
+                       continue
+               # ignore all other commented lines
+               if line[0] == '#':
+                       continue
+               # ftrace line: parse only valid lines
+               m = re.match(tp.ftrace_line_fmt, line)
+               if(not m):
+                       continue
+               dur = m.group('dur') if tp.cgformat else 'traceevent'
+               info = (m.group('time'), m.group('proc'), m.group('pid'),
+                       m.group('msg'), dur)
+               # group the data by timestamp
+               t = float(info[0])
+               if t in data:
+                       data[t].append(info)
+               else:
+                       data[t] = [info]
+               # we only care about trace event ordering
+               if (info[3].startswith('suspend_resume:') or \
+                       info[3].startswith('tracing_mark_write:')) and t not in trace:
+                               trace.append(t)
+       tf.close()
+       for t in sorted(data):
+               first, last, blk = [], [], data[t]
+               if len(blk) > 1 and t in trace:
+                       # move certain lines to the start or end of a timestamp block
+                       for i in range(len(blk)):
+                               if 'SUSPEND START' in blk[i][3]:
+                                       first.append(i)
+                               elif re.match('.* timekeeping_freeze.*begin', blk[i][3]):
+                                       last.append(i)
+                               elif re.match('.* timekeeping_freeze.*end', blk[i][3]):
+                                       first.append(i)
+                               elif 'RESUME COMPLETE' in blk[i][3]:
+                                       last.append(i)
+                       if len(first) == 1 and len(last) == 0:
+                               blk.insert(0, blk.pop(first[0]))
+                       elif len(last) == 1 and len(first) == 0:
+                               blk.append(blk.pop(last[0]))
+               for info in blk:
+                       lines.append(info)
+       return (tp, lines)
+
 # Function: parseTraceLog
 # Description:
 #       Analyze an ftrace log output file generated from this app during
@@ -3271,32 +3427,12 @@ def parseTraceLog(live=False):
 
        # extract the callgraph and traceevent data
        s2idle_enter = hwsus = False
-       tp = TestProps()
        testruns, testdata = [], []
        testrun, data, limbo = 0, 0, True
-       tf = sysvals.openlog(sysvals.ftracefile, 'r')
        phase = 'suspend_prepare'
-       for line in tf:
-               # remove any latent carriage returns
-               line = line.replace('\r\n', '')
-               if tp.stampInfo(line, sysvals):
-                       continue
-               # ignore all other commented lines
-               if line[0] == '#':
-                       continue
-               # ftrace line: parse only valid lines
-               m = re.match(tp.ftrace_line_fmt, line)
-               if(not m):
-                       continue
+       tp, tf = loadTraceLog()
+       for m_time, m_proc, m_pid, m_msg, m_param3 in tf:
                # gather the basic message data from the line
-               m_time = m.group('time')
-               m_proc = m.group('proc')
-               m_pid = m.group('pid')
-               m_msg = m.group('msg')
-               if(tp.cgformat):
-                       m_param3 = m.group('dur')
-               else:
-                       m_param3 = 'traceevent'
                if(m_time and m_pid and m_msg):
                        t = FTraceLine(m_time, m_msg, m_param3)
                        pid = int(m_pid)
@@ -3322,14 +3458,29 @@ def parseTraceLog(live=False):
                if t.type == 'tracing_mark_write':
                        m = re.match(tp.procexecfmt, t.name)
                        if(m):
-                               proclist = dict()
-                               for ps in m.group('ps').split(','):
+                               parts, msg = 1, m.group('ps')
+                               m = re.match(tp.procmultifmt, msg)
+                               if(m):
+                                       parts, msg = int(m.group('n')), m.group('ps')
+                                       if tp.multiproccnt == 0:
+                                               tp.multiproctime = t.time
+                                               tp.multiproclist = dict()
+                                       proclist = tp.multiproclist
+                                       tp.multiproccnt += 1
+                               else:
+                                       proclist = dict()
+                                       tp.multiproccnt = 0
+                               for ps in msg.split(','):
                                        val = ps.split()
-                                       if not val:
+                                       if not val or len(val) != 2:
                                                continue
                                        name = val[0].replace('--', '-')
                                        proclist[name] = int(val[1])
-                               data.pstl[t.time] = proclist
+                               if parts == 1:
+                                       data.pstl[t.time] = proclist
+                               elif parts == tp.multiproccnt:
+                                       data.pstl[tp.multiproctime] = proclist
+                                       tp.multiproccnt = 0
                                continue
                # find the end of resume
                if(t.endMarker()):
@@ -3545,7 +3696,6 @@ def parseTraceLog(live=False):
                                testrun.ftemp[key].append(FTraceCallGraph(pid, sysvals))
                        if(res == -1):
                                testrun.ftemp[key][-1].addLine(t)
-       tf.close()
        if len(testdata) < 1:
                sysvals.vprint('WARNING: ftrace start marker is missing')
        if data and not data.devicegroups:
@@ -3667,7 +3817,13 @@ def parseTraceLog(live=False):
                        if p not in data.dmesg:
                                if not terr:
                                        ph = p if 'machine' in p else lp
-                                       terr = '%s%s failed in %s phase' % (sysvals.suspendmode, tn, ph)
+                                       if p == 'suspend_machine':
+                                               sm = sysvals.suspendmode
+                                               if sm in suspendmodename:
+                                                       sm = suspendmodename[sm]
+                                               terr = 'test%s did not enter %s power mode' % (tn, sm)
+                                       else:
+                                               terr = '%s%s failed in %s phase' % (sysvals.suspendmode, tn, ph)
                                        pprint('TEST%s FAILED: %s' % (tn, terr))
                                        error.append(terr)
                                        if data.tSuspended == 0:
@@ -3708,9 +3864,7 @@ def parseTraceLog(live=False):
 
 # Function: loadKernelLog
 # Description:
-#       [deprecated for kernel 3.15.0 or newer]
 #       load the dmesg file into memory and fix up any ordering issues
-#       The dmesg filename is taken from sysvals
 # Output:
 #       An array of empty Data objects with only their dmesgtext attributes set
 def loadKernelLog():
@@ -3736,7 +3890,8 @@ def loadKernelLog():
                if(not m):
                        continue
                msg = m.group("msg")
-               if(re.match('PM: Syncing filesystems.*', msg)):
+               if re.match('PM: Syncing filesystems.*', msg) or \
+                       re.match('PM: suspend entry.*', msg):
                        if(data):
                                testruns.append(data)
                        data = Data(len(testruns))
@@ -3747,11 +3902,17 @@ def loadKernelLog():
                if(m):
                        sysvals.stamp['kernel'] = m.group('k')
                m = re.match('PM: Preparing system for (?P<m>.*) sleep', msg)
-               if(m):
+               if not m:
+                       m = re.match('PM: Preparing system for sleep \((?P<m>.*)\)', msg)
+               if m:
                        sysvals.stamp['mode'] = sysvals.suspendmode = m.group('m')
                data.dmesgtext.append(line)
        lf.close()
 
+       if sysvals.suspendmode == 's2idle':
+               sysvals.suspendmode = 'freeze'
+       elif sysvals.suspendmode == 'deep':
+               sysvals.suspendmode = 'mem'
        if data:
                testruns.append(data)
        if len(testruns) < 1:
@@ -3762,12 +3923,9 @@ def loadKernelLog():
        for data in testruns:
                last = ''
                for line in data.dmesgtext:
-                       mc = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) calling  '+\
-                               '(?P<f>.*)\+ @ .*, parent: .*', line)
-                       mr = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) call '+\
-                               '(?P<f>.*)\+ returned .* after (?P<dt>.*) usecs', last)
-                       if(mc and mr and (mc.group('t') == mr.group('t')) and
-                               (mc.group('f') == mr.group('f'))):
+                       ct, cf, n, p = data.initcall_debug_call(line)
+                       rt, rf, l = data.initcall_debug_return(last)
+                       if ct and rt and ct == rt and cf == rf:
                                i = data.dmesgtext.index(last)
                                j = data.dmesgtext.index(line)
                                data.dmesgtext[i] = line
@@ -3777,7 +3935,6 @@ def loadKernelLog():
 
 # Function: parseKernelLog
 # Description:
-#       [deprecated for kernel 3.15.0 or newer]
 #       Analyse a dmesg log output file generated from this app during
 #       the execution phase. Create a set of device structures in memory
 #       for subsequent formatting in the html output file
@@ -3796,30 +3953,30 @@ def parseKernelLog(data):
 
        # dmesg phase match table
        dm = {
-               'suspend_prepare': ['PM: Syncing filesystems.*'],
-                       'suspend': ['PM: Entering [a-z]* sleep.*', 'Suspending console.*'],
-                  'suspend_late': ['PM: suspend of devices complete after.*'],
-                 'suspend_noirq': ['PM: late suspend of devices complete after.*'],
-               'suspend_machine': ['PM: noirq suspend of devices complete after.*'],
-                'resume_machine': ['ACPI: Low-level resume complete.*'],
-                  'resume_noirq': ['ACPI: Waking up from system sleep state.*'],
-                  'resume_early': ['PM: noirq resume of devices complete after.*'],
-                        'resume': ['PM: early resume of devices complete after.*'],
-               'resume_complete': ['PM: resume of devices complete after.*'],
+               'suspend_prepare': ['PM: Syncing filesystems.*', 'PM: suspend entry.*'],
+                       'suspend': ['PM: Entering [a-z]* sleep.*', 'Suspending console.*',
+                                   'PM: Suspending system .*'],
+                  'suspend_late': ['PM: suspend of devices complete after.*',
+                                                       'PM: freeze of devices complete after.*'],
+                 'suspend_noirq': ['PM: late suspend of devices complete after.*',
+                                                       'PM: late freeze of devices complete after.*'],
+               'suspend_machine': ['PM: suspend-to-idle',
+                                                       'PM: noirq suspend of devices complete after.*',
+                                                       'PM: noirq freeze of devices complete after.*'],
+                'resume_machine': ['PM: Timekeeping suspended for.*',
+                                                       'ACPI: Low-level resume complete.*',
+                                                       'ACPI: resume from mwait',
+                                                       'Suspended for [0-9\.]* seconds'],
+                  'resume_noirq': ['PM: resume from suspend-to-idle',
+                                                       'ACPI: Waking up from system sleep state.*'],
+                  'resume_early': ['PM: noirq resume of devices complete after.*',
+                                                       'PM: noirq restore of devices complete after.*'],
+                        'resume': ['PM: early resume of devices complete after.*',
+                                                       'PM: early restore of devices complete after.*'],
+               'resume_complete': ['PM: resume of devices complete after.*',
+                                                       'PM: restore of devices complete after.*'],
                    'post_resume': ['.*Restarting tasks \.\.\..*'],
        }
-       if(sysvals.suspendmode == 'standby'):
-               dm['resume_machine'] = ['PM: Restoring platform NVS memory']
-       elif(sysvals.suspendmode == 'disk'):
-               dm['suspend_late'] = ['PM: freeze of devices complete after.*']
-               dm['suspend_noirq'] = ['PM: late freeze of devices complete after.*']
-               dm['suspend_machine'] = ['PM: noirq freeze of devices complete after.*']
-               dm['resume_machine'] = ['PM: Restoring platform NVS memory']
-               dm['resume_early'] = ['PM: noirq restore of devices complete after.*']
-               dm['resume'] = ['PM: early restore of devices complete after.*']
-               dm['resume_complete'] = ['PM: restore of devices complete after.*']
-       elif(sysvals.suspendmode == 'freeze'):
-               dm['resume_machine'] = ['ACPI: resume from mwait']
 
        # action table (expected events that occur and show up in dmesg)
        at = {
@@ -3867,12 +4024,13 @@ def parseKernelLog(data):
                        for s in dm[p]:
                                if(re.match(s, msg)):
                                        phasechange, phase = True, p
+                                       dm[p] = [s]
                                        break
 
                # hack for determining resume_machine end for freeze
                if(not sysvals.usetraceevents and sysvals.suspendmode == 'freeze' \
                        and phase == 'resume_machine' and \
-                       re.match('calling  (?P<f>.*)\+ @ .*, parent: .*', msg)):
+                       data.initcall_debug_call(line, True)):
                        data.setPhase(phase, ktime, False)
                        phase = 'resume_noirq'
                        data.setPhase(phase, ktime, True)
@@ -3945,26 +4103,18 @@ def parseKernelLog(data):
                # -- device callbacks --
                if(phase in data.sortedPhases()):
                        # device init call
-                       if(re.match('calling  (?P<f>.*)\+ @ .*, parent: .*', msg)):
-                               sm = re.match('calling  (?P<f>.*)\+ @ '+\
-                                       '(?P<n>.*), parent: (?P<p>.*)', msg);
-                               f = sm.group('f')
-                               n = sm.group('n')
-                               p = sm.group('p')
-                               if(f and n and p):
-                                       data.newAction(phase, f, int(n), p, ktime, -1, '')
-                       # device init return
-                       elif(re.match('call (?P<f>.*)\+ returned .* after '+\
-                               '(?P<t>.*) usecs', msg)):
-                               sm = re.match('call (?P<f>.*)\+ returned .* after '+\
-                                       '(?P<t>.*) usecs(?P<a>.*)', msg);
-                               f = sm.group('f')
-                               t = sm.group('t')
-                               list = data.dmesg[phase]['list']
-                               if(f in list):
-                                       dev = list[f]
-                                       dev['length'] = int(t)
-                                       dev['end'] = ktime
+                       t, f, n, p = data.initcall_debug_call(line)
+                       if t and f and n and p:
+                               data.newAction(phase, f, int(n), p, ktime, -1, '')
+                       else:
+                               # device init return
+                               t, f, l = data.initcall_debug_return(line)
+                               if t and f and l:
+                                       list = data.dmesg[phase]['list']
+                                       if(f in list):
+                                               dev = list[f]
+                                               dev['length'] = int(l)
+                                               dev['end'] = ktime
 
                # if trace events are not available, these are better than nothing
                if(not sysvals.usetraceevents):
@@ -4006,6 +4156,8 @@ def parseKernelLog(data):
        # fill in any missing phases
        phasedef = data.phasedef
        terr, lp = '', 'suspend_prepare'
+       if lp not in data.dmesg:
+               doError('dmesg log format has changed, could not find start of suspend')
        for p in sorted(phasedef, key=lambda k:phasedef[k]['order']):
                if p not in data.dmesg:
                        if not terr:
@@ -5302,7 +5454,7 @@ def executeSuspend(quiet=False):
        sv.dlog('read dmesg')
        sv.initdmesg()
        # start ftrace
-       if(sv.usecallgraph or sv.usetraceevents):
+       if sv.useftrace:
                if not quiet:
                        pprint('START TRACING')
                sv.dlog('start ftrace tracing')
@@ -5334,8 +5486,7 @@ def executeSuspend(quiet=False):
                        sv.dlog('enable RTC wake alarm')
                        sv.rtcWakeAlarmOn()
                # start of suspend trace marker
-               if(sv.usecallgraph or sv.usetraceevents):
-                       sv.fsetVal(datetime.now().strftime(sv.tmstart), 'trace_marker')
+               sv.fsetVal(datetime.now().strftime(sv.tmstart), 'trace_marker')
                # predelay delay
                if(count == 1 and sv.predelay > 0):
                        sv.fsetVal('WAIT %d' % sv.predelay, 'trace_marker')
@@ -5384,11 +5535,17 @@ def executeSuspend(quiet=False):
                        sv.fsetVal('WAIT END', 'trace_marker')
                # return from suspend
                pprint('RESUME COMPLETE')
-               if(sv.usecallgraph or sv.usetraceevents):
-                       sv.fsetVal(datetime.now().strftime(sv.tmend), 'trace_marker')
+               sv.fsetVal(datetime.now().strftime(sv.tmend), 'trace_marker')
                if sv.wifi and wifi:
                        tdata['wifi'] = sv.pollWifi(wifi)
                        sv.dlog('wifi check, %s' % tdata['wifi'])
+                       if sv.netfix:
+                               netfixout = sv.netfixon('wired')
+               elif sv.netfix:
+                       netfixout = sv.netfixon()
+               if sv.netfix and netfixout:
+                       tdata['netfix'] = netfixout
+                       sv.dlog('netfix, %s' % tdata['netfix'])
                if(sv.suspendmode == 'mem' or sv.suspendmode == 'command'):
                        sv.dlog('read the ACPI FPDT')
                        tdata['fw'] = getFPDT(False)
@@ -5396,7 +5553,7 @@ def executeSuspend(quiet=False):
        sv.dlog('run the cmdinfo list after')
        cmdafter = sv.cmdinfo(False)
        # stop ftrace
-       if(sv.usecallgraph or sv.usetraceevents):
+       if sv.useftrace:
                if sv.useprocmon:
                        sv.dlog('stop the process monitor')
                        pm.stop()
@@ -5407,7 +5564,7 @@ def executeSuspend(quiet=False):
        sysvals.dlog('EXECUTION TRACE END')
        sv.getdmesg(testdata)
        # grab a copy of the ftrace output
-       if(sv.usecallgraph or sv.usetraceevents):
+       if sv.useftrace:
                if not quiet:
                        pprint('CAPTURING TRACE')
                op = sv.writeDatafileHeader(sv.ftracefile, testdata)
@@ -5838,13 +5995,19 @@ def statusCheck(probecheck=False):
                        pprint('      please choose one with -m')
 
        # check if ftrace is available
-       res = sysvals.colorText('NO')
-       ftgood = sysvals.verifyFtrace()
-       if(ftgood):
-               res = 'YES'
-       elif(sysvals.usecallgraph):
-               status = 'ftrace is not properly supported'
-       pprint('    is ftrace supported: %s' % res)
+       if sysvals.useftrace:
+               res = sysvals.colorText('NO')
+               sysvals.useftrace = sysvals.verifyFtrace()
+               efmt = '"{0}" uses ftrace, and it is not properly supported'
+               if sysvals.useftrace:
+                       res = 'YES'
+               elif sysvals.usecallgraph:
+                       status = efmt.format('-f')
+               elif sysvals.usedevsrc:
+                       status = efmt.format('-dev')
+               elif sysvals.useprocmon:
+                       status = efmt.format('-proc')
+               pprint('    is ftrace supported: %s' % res)
 
        # check if kprobes are available
        if sysvals.usekprobes:
@@ -5857,8 +6020,8 @@ def statusCheck(probecheck=False):
                pprint('    are kprobes supported: %s' % res)
 
        # what data source are we using
-       res = 'DMESG'
-       if(ftgood):
+       res = 'DMESG (very limited, ftrace is preferred)'
+       if sysvals.useftrace:
                sysvals.usetraceevents = True
                for e in sysvals.traceevents:
                        if not os.path.exists(sysvals.epath+e):
@@ -5879,7 +6042,7 @@ def statusCheck(probecheck=False):
        pprint('    optional commands this tool may use for info:')
        no = sysvals.colorText('MISSING')
        yes = sysvals.colorText('FOUND', 32)
-       for c in ['turbostat', 'mcelog', 'lspci', 'lsusb']:
+       for c in ['turbostat', 'mcelog', 'lspci', 'lsusb', 'netfix']:
                if c == 'turbostat':
                        res = yes if sysvals.haveTurbostat() else no
                else:
@@ -5971,7 +6134,7 @@ def processData(live=False, quiet=False):
        if not sysvals.stamp:
                pprint('ERROR: data does not include the expected stamp')
                return (testruns, {'error': 'timeline generation failed'})
-       shown = ['bios', 'biosdate', 'cpu', 'host', 'kernel', 'man', 'memfr',
+       shown = ['os', 'bios', 'biosdate', 'cpu', 'host', 'kernel', 'man', 'memfr',
                        'memsz', 'mode', 'numcpu', 'plat', 'time', 'wifi']
        sysvals.vprint('System Info:')
        for key in sorted(sysvals.stamp):
@@ -6052,6 +6215,8 @@ def runTest(n=0, quiet=False):
                if sysvals.display:
                        ret = sysvals.displayControl('init')
                        sysvals.dlog('xset display init, ret = %d' % ret)
+       sysvals.testVal(sysvals.pmdpath, 'basic', '1')
+       sysvals.testVal(sysvals.s0ixpath, 'basic', 'Y')
        sysvals.dlog('initialize ftrace')
        sysvals.initFtrace(quiet)
 
@@ -6145,9 +6310,12 @@ def data_from_html(file, outpath, issues, fulldetail=False):
                                elist[err[0]] += 1
                for i in elist:
                        ilist.append('%sx%d' % (i, elist[i]) if elist[i] > 1 else i)
-       wifi = find_in_html(html, 'Wifi Resume: ', '</td>')
-       if wifi:
-               extra['wifi'] = wifi
+               line = find_in_html(log, '# wifi ', '\n')
+               if line:
+                       extra['wifi'] = line
+               line = find_in_html(log, '# netfix ', '\n')
+               if line:
+                       extra['netfix'] = line
        low = find_in_html(html, 'freeze time: <b>', ' ms</b>')
        for lowstr in ['waking', '+']:
                if not low:
@@ -6243,7 +6411,7 @@ def genHtml(subdir, force=False):
                                        sysvals.ftracefile = file
                sysvals.setOutputFile()
                if (sysvals.dmesgfile or sysvals.ftracefile) and sysvals.htmlfile and \
-                       (force or not sysvals.usable(sysvals.htmlfile)):
+                       (force or not sysvals.usable(sysvals.htmlfile, True)):
                        pprint('FTRACE: %s' % sysvals.ftracefile)
                        if sysvals.dmesgfile:
                                pprint('DMESG : %s' % sysvals.dmesgfile)
@@ -6533,6 +6701,7 @@ def printHelp():
        '   -skiphtml    Run the test and capture the trace logs, but skip the timeline (default: disabled)\n'\
        '   -result fn   Export a results table to a text file for parsing.\n'\
        '   -wifi        If a wifi connection is available, check that it reconnects after resume.\n'\
+       '   -netfix      Use netfix to reset the network in the event it fails to resume.\n'\
        '  [testprep]\n'\
        '   -sync        Sync the filesystems before starting the test\n'\
        '   -rs on/off   Enable/disable runtime suspend for all devices, restore all after test\n'\
@@ -6615,6 +6784,8 @@ if __name__ == '__main__':
                elif(arg == '-v'):
                        pprint("Version %s" % sysvals.version)
                        sys.exit(0)
+               elif(arg == '-debugtiming'):
+                       debugtiming = True
                elif(arg == '-x2'):
                        sysvals.execcount = 2
                elif(arg == '-x2delay'):
@@ -6657,6 +6828,8 @@ if __name__ == '__main__':
                        sysvals.sync = True
                elif(arg == '-wifi'):
                        sysvals.wifi = True
+               elif(arg == '-netfix'):
+                       sysvals.netfix = True
                elif(arg == '-gzip'):
                        sysvals.gzip = True
                elif(arg == '-info'):
@@ -6819,7 +6992,7 @@ if __name__ == '__main__':
                        sysvals.outdir = val
                        sysvals.notestrun = True
                        if(os.path.isdir(val) == False):
-                               doError('%s is not accessible' % val)
+                               doError('%s is not accesible' % val)
                elif(arg == '-filter'):
                        try:
                                val = next(args)
@@ -6942,12 +7115,11 @@ if __name__ == '__main__':
                                time.sleep(sysvals.multitest['delay'])
                        fmt = 'suspend-%y%m%d-%H%M%S'
                        sysvals.testdir = os.path.join(sysvals.outdir, datetime.now().strftime(fmt))
-                       ret = runTest(i+1, True)
+                       ret = runTest(i+1, not sysvals.verbose)
                        failcnt = 0 if not ret else failcnt + 1
                        if sysvals.maxfail > 0 and failcnt >= sysvals.maxfail:
                                pprint('Maximum fail count of %d reached, aborting multitest' % (sysvals.maxfail))
                                break
-                       time.sleep(5)
                        sysvals.resetlog()
                        sysvals.multistat(False, i, finish)
                        if 'time' in sysvals.multitest and datetime.now() >= finish:
index 1e7d3de..c7b26a3 100644 (file)
@@ -92,40 +92,66 @@ displays the statistics gathered since it was forked.
 .SH ROW DESCRIPTIONS
 The system configuration dump (if --quiet is not used) is followed by statistics.  The first row of the statistics labels the content of each column (below).  The second row of statistics is the system summary line.  The system summary line has a '-' in the columns for the Package, Core, and CPU.  The contents of the system summary line depends on the type of column.  Columns that count items (eg. IRQ) show the sum across all CPUs in the system.  Columns that show a percentage show the average across all CPUs in the system.  Columns that dump raw MSR values simply show 0 in the summary.  After the system summary row, each row describes a specific Package/Core/CPU.  Note that if the --cpu parameter is used to limit which specific CPUs are displayed, turbostat will still collect statistics for all CPUs in the system and will still show the system summary for all CPUs in the system.
 .SH COLUMN DESCRIPTIONS
-.nf
+.PP
 \fBusec\fP For each CPU, the number of microseconds elapsed during counter collection, including thread migration -- if any.  This counter is disabled by default, and is enabled with "--enable usec", or --debug.  On the summary row, usec refers to the total elapsed time to collect the counters on all cpus.
+.PP
 \fBTime_Of_Day_Seconds\fP For each CPU, the gettimeofday(2) value (seconds.subsec since Epoch) when the counters ending the measurement interval were collected.  This column is disabled by default, and can be enabled with "--enable Time_Of_Day_Seconds" or "--debug".  On the summary row, Time_Of_Day_Seconds refers to the timestamp following collection of counters on the last CPU.
+.PP
 \fBCore\fP processor core number.  Note that multiple CPUs per core indicate support for Intel(R) Hyper-Threading Technology (HT).
+.PP
 \fBCPU\fP Linux CPU (logical processor) number.  Yes, it is okay that on many systems the CPUs are not listed in numerical order -- for efficiency reasons, turbostat runs in topology order, so HT siblings appear together.
+.PP
 \fBPackage\fP processor package number -- not present on systems with a single processor package.
+.PP
 \fBAvg_MHz\fP number of cycles executed divided by time elapsed.  Note that this includes idle-time when 0 instructions are executed.
+.PP
 \fBBusy%\fP percent of the measurement interval that the CPU executes instructions, aka. % of time in "C0" state.
+.PP
 \fBBzy_MHz\fP average clock rate while the CPU was not idle (ie. in "c0" state).
+.PP
 \fBTSC_MHz\fP average MHz that the TSC ran during the entire interval.
+.PP
 \fBIRQ\fP The number of interrupts serviced by that CPU during the measurement interval.  The system total line is the sum of interrupts serviced across all CPUs.  turbostat parses /proc/interrupts to generate this summary.
+.PP
 \fBSMI\fP The number of System Management Interrupts  serviced CPU during the measurement interval.  While this counter is actually per-CPU, SMI are triggered on all processors, so the number should be the same for all CPUs.
+.PP
 \fBC1, C2, C3...\fP The number times Linux requested the C1, C2, C3 idle state during the measurement interval.  The system summary line shows the sum for all CPUs.  These are C-state names as exported in /sys/devices/system/cpu/cpu*/cpuidle/state*/name.  While their names are generic, their attributes are processor specific. They the system description section of output shows what MWAIT sub-states they are mapped to on each system.
+.PP
 \fBC1%, C2%, C3%\fP The residency percentage that Linux requested C1, C2, C3....  The system summary is the average of all CPUs in the system.  Note that these are software, reflecting what was requested.  The hardware counters reflect what was actually achieved.
+.PP
 \fBCPU%c1, CPU%c3, CPU%c6, CPU%c7\fP show the percentage residency in hardware core idle states.  These numbers are from hardware residency counters.
+.PP
 \fBCoreTmp\fP Degrees Celsius reported by the per-core Digital Thermal Sensor.
+.PP
 \fBPkgTmp\fP Degrees Celsius reported by the per-package Package Thermal Monitor.
+.PP
 \fBGFX%rc6\fP The percentage of time the GPU is in the "render C6" state, rc6, during the measurement interval. From /sys/class/drm/card0/power/rc6_residency_ms.
+.PP
 \fBGFXMHz\fP Instantaneous snapshot of what sysfs presents at the end of the measurement interval. From /sys/class/graphics/fb0/device/drm/card0/gt_cur_freq_mhz.
+.PP
 \fBPkg%pc2, Pkg%pc3, Pkg%pc6, Pkg%pc7\fP percentage residency in hardware package idle states.  These numbers are from hardware residency counters.
+.PP
 \fBPkgWatt\fP Watts consumed by the whole package.
+.PP
 \fBCorWatt\fP Watts consumed by the core part of the package.
+.PP
 \fBGFXWatt\fP Watts consumed by the Graphics part of the package -- available only on client processors.
+.PP
 \fBRAMWatt\fP Watts consumed by the DRAM DIMMS -- available only on server processors.
+.PP
 \fBPKG_%\fP percent of the interval that RAPL throttling was active on the Package.  Note that the system summary is the sum of the package throttling time, and thus may be higher than 100% on a multi-package system.  Note that the meaning of this field is model specific.  For example, some hardware increments this counter when RAPL responds to thermal limits, but does not increment this counter when RAPL responds to power limits.  Comparing PkgWatt and PkgTmp to system limits is necessary.
+.PP
 \fBRAM_%\fP percent of the interval that RAPL throttling was active on DRAM.
-.fi
+.PP
+\fBUncMHz\fP uncore MHz, instantaneous sample.
 .SH TOO MUCH INFORMATION EXAMPLE
 By default, turbostat dumps all possible information -- a system configuration header, followed by columns for all counters.
 This is ideal for remote debugging, use the "--out" option to save everything to a text file, and get that file to the expert helping you debug.
 .PP
 When you are not interested in all that information, and there are several ways to see only what you want.  First the "--quiet" option will skip the configuration information, and turbostat will show only the counter columns.  Second, you can reduce the columns with the "--hide" and "--show" options.  If you use the "--show" option, then turbostat will show only the columns you list.  If you use the "--hide" option, turbostat will show all columns, except the ones you list.
 .PP
-To find out what columns are available for --show and --hide, the "--list" option is available.  For convenience, the special strings "sysfs" can be used to refer to all of the sysfs C-state counters at once:
+To find out what columns are available for --show and --hide, the "--list" option is available.  Usually, the CATEGORY names above are used to refer to groups of counters.  Also, for convenience, the special string "sysfs" can be used to refer to all of the sysfs C-state counters at once:
+.PP
 .nf
 sudo ./turbostat --show sysfs --quiet sleep 10
 10.003837 sec
@@ -158,32 +184,29 @@ Without a command to fork, turbostat displays statistics ever 5 seconds.
 Periodic output goes to stdout, by default, unless --out is used to specify an output file.
 The 5-second interval can be changed with the "-i sec" option.
 .nf
-sudo ./turbostat --quiet --hide sysfs,IRQ,SMI,CoreTmp,PkgTmp,GFX%rc6,GFXMHz,PkgWatt,CorWatt,GFXWatt
-       Core    CPU     Avg_MHz Busy%   Bzy_MHz TSC_MHz CPU%c1  CPU%c3  CPU%c6  CPU%c7
-       -       -       488     12.52   3900    3498    12.50   0.00    0.00    74.98
-       0       0       5       0.13    3900    3498    99.87   0.00    0.00    0.00
-       0       4       3897    99.99   3900    3498    0.01
-       1       1       0       0.00    3856    3498    0.01    0.00    0.00    99.98
-       1       5       0       0.00    3861    3498    0.01
-       2       2       1       0.02    3889    3498    0.03    0.00    0.00    99.95
-       2       6       0       0.00    3863    3498    0.05
-       3       3       0       0.01    3869    3498    0.02    0.00    0.00    99.97
-       3       7       0       0.00    3878    3498    0.03
-       Core    CPU     Avg_MHz Busy%   Bzy_MHz TSC_MHz CPU%c1  CPU%c3  CPU%c6  CPU%c7
-       -       -       491     12.59   3900    3498    12.42   0.00    0.00    74.99
-       0       0       27      0.69    3900    3498    99.31   0.00    0.00    0.00
-       0       4       3898    99.99   3900    3498    0.01
-       1       1       0       0.00    3883    3498    0.01    0.00    0.00    99.99
-       1       5       0       0.00    3898    3498    0.01
-       2       2       0       0.01    3889    3498    0.02    0.00    0.00    99.98
-       2       6       0       0.00    3889    3498    0.02
-       3       3       0       0.00    3856    3498    0.01    0.00    0.00    99.99
-       3       7       0       0.00    3897    3498    0.01
+sudo turbostat --quiet --show CPU,frequency
+       Core    CPU     Avg_MHz Busy%   Bzy_MHz TSC_MHz CPU%c7  UncMhz
+       -       -       524     12.48   4198    3096    74.53   3800
+       0       0       4       0.09    4081    3096    98.88   3800
+       0       4       1       0.02    4063    3096
+       1       1       2       0.06    4063    3096    99.60
+       1       5       2       0.05    4070    3096
+       2       2       4178    99.52   4199    3096    0.00
+       2       6       3       0.08    4159    3096
+       3       3       1       0.04    4046    3096    99.66
+       3       7       0       0.01    3989    3096
+       Core    CPU     Avg_MHz Busy%   Bzy_MHz TSC_MHz CPU%c7  UncMhz
+       -       -       525     12.52   4198    3096    74.54   3800
+       0       0       4       0.10    4051    3096    99.49   3800
+       0       4       2       0.04    3993    3096
+       1       1       3       0.07    4054    3096    99.56
+       1       5       4       0.10    4018    3096
+       2       2       4178    99.51   4199    3096    0.00
+       2       6       4       0.09    4143    3096
+       3       3       2       0.06    4026    3096    99.10
+       3       7       7       0.17    4074    3096
 .fi
-This example also shows the use of the --hide option to skip columns that are not wanted.
-Note that cpu4 in this example is 99.99% busy, while the other CPUs are all under 1% busy.
-Notice that cpu4's HT sibling is cpu0, which is under 1% busy, but can get into CPU%c1 only,
-because its cpu4's activity on shared hardware keeps it from entering a deeper C-state.
+This example also shows the use of the --show option to show only the desired columns.
 
 .SH SYSTEM CONFIGURATION INFORMATION EXAMPLE
 
@@ -191,61 +214,86 @@ By default, turbostat always dumps system configuration information
 before taking measurements.  In the example above, "--quiet" is used
 to suppress that output.  Here is an example of the configuration information:
 .nf
-turbostat version 2017.02.15 - Len Brown <lenb@kernel.org>
-CPUID(0): GenuineIntel 13 CPUID levels; family:model:stepping 0x6:3c:3 (6:60:3)
-CPUID(1): SSE3 MONITOR - EIST TM2 TSC MSR ACPI-TM TM
-CPUID(6): APERF, TURBO, DTS, PTM, No-HWP, No-HWPnotify, No-HWPwindow, No-HWPepp, No-HWPpkg, EPB
-cpu4: MSR_IA32_MISC_ENABLE: 0x00850089 (TCC EIST No-MWAIT PREFETCH TURBO)
-CPUID(7): No-SGX
-cpu4: MSR_MISC_PWR_MGMT: 0x00400000 (ENable-EIST_Coordination DISable-EPB DISable-OOB)
-RAPL: 3121 sec. Joule Counter Range, at 84 Watts
-cpu4: MSR_PLATFORM_INFO: 0x80838f3012300
+turbostat version 2022.04.16 - Len Brown <lenb@kernel.org>
+Kernel command line: BOOT_IMAGE=/boot/vmlinuz-5.18.0-rc6-00001-ge6891250e3b5 ...
+CPUID(0): GenuineIntel 0x16 CPUID levels
+CPUID(1): family:model:stepping 0x6:9e:9 (6:158:9) microcode 0xea
+CPUID(0x80000000): max_extended_levels: 0x80000008
+CPUID(1): SSE3 MONITOR - EIST TM2 TSC MSR ACPI-TM HT TM
+CPUID(6): APERF, TURBO, DTS, PTM, HWP, HWPnotify, HWPwindow, HWPepp, No-HWPpkg, EPB
+cpu7: MSR_IA32_MISC_ENABLE: 0x00850089 (TCC EIST MWAIT PREFETCH TURBO)
+CPUID(7): SGX
+cpu7: MSR_IA32_FEATURE_CONTROL: 0x00000005 (Locked )
+CPUID(0x15): eax_crystal: 2 ebx_tsc: 258 ecx_crystal_hz: 0
+TSC: 3096 MHz (24000000 Hz * 258 / 2 / 1000000)
+CPUID(0x16): base_mhz: 3100 max_mhz: 4200 bus_mhz: 100
+cpu7: MSR_MISC_PWR_MGMT: 0x00401cc0 (ENable-EIST_Coordination DISable-EPB DISable-OOB)
+RAPL: 5825 sec. Joule Counter Range, at 45 Watts
+cpu7: MSR_PLATFORM_INFO: 0x80839f1011f00
 8 * 100.0 = 800.0 MHz max efficiency frequency
-35 * 100.0 = 3500.0 MHz base frequency
-cpu4: MSR_IA32_POWER_CTL: 0x0004005d (C1E auto-promotion: DISabled)
-cpu4: MSR_TURBO_RATIO_LIMIT: 0x25262727
-37 * 100.0 = 3700.0 MHz max turbo 4 active cores
-38 * 100.0 = 3800.0 MHz max turbo 3 active cores
-39 * 100.0 = 3900.0 MHz max turbo 2 active cores
-39 * 100.0 = 3900.0 MHz max turbo 1 active cores
-cpu4: MSR_CONFIG_TDP_NOMINAL: 0x00000023 (base_ratio=35)
-cpu4: MSR_CONFIG_TDP_LEVEL_1: 0x00000000 ()
-cpu4: MSR_CONFIG_TDP_LEVEL_2: 0x00000000 ()
-cpu4: MSR_CONFIG_TDP_CONTROL: 0x80000000 ( lock=1)
-cpu4: MSR_TURBO_ACTIVATION_RATIO: 0x00000000 (MAX_NON_TURBO_RATIO=0 lock=0)
-cpu4: MSR_PKG_CST_CONFIG_CONTROL: 0x1e000400 (UNdemote-C3, UNdemote-C1, demote-C3, demote-C1, UNlocked: pkg-cstate-limit=0: pc0)
-cpu4: POLL: CPUIDLE CORE POLL IDLE
-cpu4: C1: MWAIT 0x00
-cpu4: C1E: MWAIT 0x01
-cpu4: C3: MWAIT 0x10
-cpu4: C6: MWAIT 0x20
-cpu4: C7s: MWAIT 0x32
-cpu4: MSR_MISC_FEATURE_CONTROL: 0x00000000 (L2-Prefetch L2-Prefetch-pair L1-Prefetch L1-IP-Prefetch)
-cpu0: MSR_IA32_ENERGY_PERF_BIAS: 0x00000006 (balanced)
-cpu0: MSR_CORE_PERF_LIMIT_REASONS, 0x31200000 (Active: ) (Logged: Transitions, MultiCoreTurbo, Amps, Auto-HWP, )
-cpu0: MSR_GFX_PERF_LIMIT_REASONS, 0x00000000 (Active: ) (Logged: )
-cpu0: MSR_RING_PERF_LIMIT_REASONS, 0x0d000000 (Active: ) (Logged: Amps, PkgPwrL1, PkgPwrL2, )
+31 * 100.0 = 3100.0 MHz base frequency
+cpu7: MSR_IA32_POWER_CTL: 0x002c005d (C1E auto-promotion: DISabled)
+cpu7: MSR_TURBO_RATIO_LIMIT: 0x2728292a
+39 * 100.0 = 3900.0 MHz max turbo 4 active cores
+40 * 100.0 = 4000.0 MHz max turbo 3 active cores
+41 * 100.0 = 4100.0 MHz max turbo 2 active cores
+42 * 100.0 = 4200.0 MHz max turbo 1 active cores
+cpu7: MSR_CONFIG_TDP_NOMINAL: 0x0000001f (base_ratio=31)
+cpu7: MSR_CONFIG_TDP_LEVEL_1: 0x00000000 ()
+cpu7: MSR_CONFIG_TDP_LEVEL_2: 0x00000000 ()
+cpu7: MSR_CONFIG_TDP_CONTROL: 0x80000000 ( lock=1)
+cpu7: MSR_TURBO_ACTIVATION_RATIO: 0x00000000 (MAX_NON_TURBO_RATIO=0 lock=0)
+cpu7: MSR_PKG_CST_CONFIG_CONTROL: 0x1e008008 (UNdemote-C3, UNdemote-C1, demote-C3, demote-C1, locked, pkg-cstate-limit=8 (unlimited))
+Uncore Frequency pkg0 die0: 800 - 3900 MHz (800 - 3900 MHz)
+/dev/cpu_dma_latency: 2000000000 usec (default)
+current_driver: intel_idle
+current_governor: menu
+current_governor_ro: menu
+cpu7: POLL: CPUIDLE CORE POLL IDLE
+cpu7: C1: MWAIT 0x00
+cpu7: C1E: MWAIT 0x01
+cpu7: C3: MWAIT 0x10
+cpu7: C6: MWAIT 0x20
+cpu7: C7s: MWAIT 0x33
+cpu7: C8: MWAIT 0x40
+cpu7: C9: MWAIT 0x50
+cpu7: C10: MWAIT 0x60
+cpu7: cpufreq driver: intel_pstate
+cpu7: cpufreq governor: performance
+cpufreq intel_pstate no_turbo: 0
+cpu7: MSR_MISC_FEATURE_CONTROL: 0x00000000 (L2-Prefetch L2-Prefetch-pair L1-Prefetch L1-IP-Prefetch)
+cpu0: MSR_PM_ENABLE: 0x00000001 (HWP)
+cpu0: MSR_HWP_CAPABILITIES: 0x01101f53 (high 83 guar 31 eff 16 low 1)
+cpu0: MSR_HWP_REQUEST: 0x00005353 (min 83 max 83 des 0 epp 0x0 window 0x0 pkg 0x0)
+cpu0: MSR_HWP_INTERRUPT: 0x00000001 (EN_Guaranteed_Perf_Change, Dis_Excursion_Min)
+cpu0: MSR_HWP_STATUS: 0x00000004 (No-Guaranteed_Perf_Change, No-Excursion_Min)
+cpu0: EPB: 6 (balanced)
 cpu0: MSR_RAPL_POWER_UNIT: 0x000a0e03 (0.125000 Watts, 0.000061 Joules, 0.000977 sec.)
-cpu0: MSR_PKG_POWER_INFO: 0x000002a0 (84 W TDP, RAPL 0 - 0 W, 0.000000 sec.)
-cpu0: MSR_PKG_POWER_LIMIT: 0x428348001a82a0 (UNlocked)
-cpu0: PKG Limit #1: ENabled (84.000000 Watts, 8.000000 sec, clamp DISabled)
-cpu0: PKG Limit #2: ENabled (105.000000 Watts, 0.002441* sec, clamp DISabled)
+cpu0: MSR_PKG_POWER_INFO: 0x00000168 (45 W TDP, RAPL 0 - 0 W, 0.000000 sec.)
+cpu0: MSR_PKG_POWER_LIMIT: 0x42820800218208 (UNlocked)
+cpu0: PKG Limit #1: ENabled (65.000 Watts, 64.000000 sec, clamp ENabled)
+cpu0: PKG Limit #2: ENabled (65.000 Watts, 0.002441* sec, clamp DISabled)
+cpu0: MSR_VR_CURRENT_CONFIG: 0x00000000
+cpu0: PKG Limit #4: 0.000000 Watts (UNlocked)
+cpu0: MSR_DRAM_POWER_LIMIT: 0x5400de00000000 (UNlocked)
+cpu0: DRAM Limit: DISabled (0.000 Watts, 0.000977 sec, clamp DISabled)
 cpu0: MSR_PP0_POLICY: 0
 cpu0: MSR_PP0_POWER_LIMIT: 0x00000000 (UNlocked)
-cpu0: Cores Limit: DISabled (0.000000 Watts, 0.000977 sec, clamp DISabled)
+cpu0: Cores Limit: DISabled (0.000 Watts, 0.000977 sec, clamp DISabled)
 cpu0: MSR_PP1_POLICY: 0
 cpu0: MSR_PP1_POWER_LIMIT: 0x00000000 (UNlocked)
-cpu0: GFX Limit: DISabled (0.000000 Watts, 0.000977 sec, clamp DISabled)
-cpu0: MSR_IA32_TEMPERATURE_TARGET: 0x00641400 (100 C)
-cpu0: MSR_IA32_PACKAGE_THERM_STATUS: 0x884c0800 (24 C)
-cpu0: MSR_IA32_THERM_STATUS: 0x884c0000 (24 C +/- 1)
-cpu1: MSR_IA32_THERM_STATUS: 0x88510000 (19 C +/- 1)
-cpu2: MSR_IA32_THERM_STATUS: 0x884e0000 (22 C +/- 1)
-cpu3: MSR_IA32_THERM_STATUS: 0x88510000 (19 C +/- 1)
-cpu4: MSR_PKGC3_IRTL: 0x00008842 (valid, 67584 ns)
-cpu4: MSR_PKGC6_IRTL: 0x00008873 (valid, 117760 ns)
-cpu4: MSR_PKGC7_IRTL: 0x00008891 (valid, 148480 ns)
+cpu0: GFX Limit: DISabled (0.000 Watts, 0.000977 sec, clamp DISabled)
+cpu0: MSR_IA32_TEMPERATURE_TARGET: 0x00640000 (100 C) (100 default - 0 offset)
+cpu0: MSR_IA32_PACKAGE_THERM_STATUS: 0x88200800 (68 C)
+cpu0: MSR_IA32_PACKAGE_THERM_INTERRUPT: 0x00000003 (100 C, 100 C)
+cpu7: MSR_PKGC3_IRTL: 0x0000884e (valid, 79872 ns)
+cpu7: MSR_PKGC6_IRTL: 0x00008876 (valid, 120832 ns)
+cpu7: MSR_PKGC7_IRTL: 0x00008894 (valid, 151552 ns)
+cpu7: MSR_PKGC8_IRTL: 0x000088fa (valid, 256000 ns)
+cpu7: MSR_PKGC9_IRTL: 0x0000894c (valid, 339968 ns)
+cpu7: MSR_PKGC10_IRTL: 0x00008bf2 (valid, 1034240 ns)
 .fi
+.PP
 The \fBmax efficiency\fP frequency, a.k.a. Low Frequency Mode, is the frequency
 available at the minimum package voltage.  The \fBTSC frequency\fP is the base
 frequency of the processor -- this should match the brand string
index ede31a4..831dc32 100644 (file)
@@ -126,6 +126,7 @@ struct msr_counter bic[] = {
        { 0x0, "GFXAMHz", "", 0, 0, 0, NULL, 0 },
        { 0x0, "IPC", "", 0, 0, 0, NULL, 0 },
        { 0x0, "CoreThr", "", 0, 0, 0, NULL, 0 },
+       { 0x0, "UncMHz", "", 0, 0, 0, NULL, 0 },
 };
 
 #define MAX_BIC (sizeof(bic) / sizeof(struct msr_counter))
@@ -183,10 +184,11 @@ struct msr_counter bic[] = {
 #define        BIC_GFXACTMHz   (1ULL << 51)
 #define        BIC_IPC         (1ULL << 52)
 #define        BIC_CORE_THROT_CNT      (1ULL << 53)
+#define        BIC_UNCORE_MHZ          (1ULL << 54)
 
 #define BIC_TOPOLOGY (BIC_Package | BIC_Node | BIC_CoreCnt | BIC_PkgCnt | BIC_Core | BIC_CPU | BIC_Die )
 #define BIC_THERMAL_PWR ( BIC_CoreTmp | BIC_PkgTmp | BIC_PkgWatt | BIC_CorWatt | BIC_GFXWatt | BIC_RAMWatt | BIC_PKG__ | BIC_RAM__)
-#define BIC_FREQUENCY ( BIC_Avg_MHz | BIC_Busy | BIC_Bzy_MHz | BIC_TSC_MHz | BIC_GFXMHz | BIC_GFXACTMHz )
+#define BIC_FREQUENCY ( BIC_Avg_MHz | BIC_Busy | BIC_Bzy_MHz | BIC_TSC_MHz | BIC_GFXMHz | BIC_GFXACTMHz | BIC_UNCORE_MHZ)
 #define BIC_IDLE ( BIC_sysfs | BIC_CPU_c1 | BIC_CPU_c3 | BIC_CPU_c6 | BIC_CPU_c7 | BIC_GFX_rc6 | BIC_Pkgpc2 | BIC_Pkgpc3 | BIC_Pkgpc6 | BIC_Pkgpc7 | BIC_Pkgpc8 | BIC_Pkgpc9 | BIC_Pkgpc10 | BIC_CPU_LPI | BIC_SYS_LPI | BIC_Mod_c6 | BIC_Totl_c0 | BIC_Any_c0 | BIC_GFX_c0 | BIC_CPUGFX)
 #define BIC_OTHER ( BIC_IRQ | BIC_SMI | BIC_ThreadC | BIC_CoreTmp | BIC_IPC)
 
@@ -228,6 +230,7 @@ unsigned int do_slm_cstates;
 unsigned int use_c1_residency_msr;
 unsigned int has_aperf;
 unsigned int has_epb;
+unsigned int is_hybrid;
 unsigned int do_irtl_snb;
 unsigned int do_irtl_hsw;
 unsigned int units = 1000000;  /* MHz etc */
@@ -393,6 +396,7 @@ struct pkg_data {
        unsigned long long rapl_pkg_perf_status;        /* MSR_PKG_PERF_STATUS */
        unsigned long long rapl_dram_perf_status;       /* MSR_DRAM_PERF_STATUS */
        unsigned int pkg_temp_c;
+       unsigned int uncore_mhz;
        unsigned long long counter[MAX_ADDED_COUNTERS];
 } *package_even, *package_odd;
 
@@ -988,6 +992,9 @@ void print_header(char *delim)
                if (DO_BIC(BIC_RAM__))
                        outp += sprintf(outp, "%sRAM_%%", (printed++ ? delim : ""));
        }
+       if (DO_BIC(BIC_UNCORE_MHZ))
+               outp += sprintf(outp, "%sUncMHz", (printed++ ? delim : ""));
+
        for (mp = sys.pp; mp; mp = mp->next) {
                if (mp->format == FORMAT_RAW) {
                        if (mp->width == 64)
@@ -1370,6 +1377,9 @@ int format_counters(struct thread_data *t, struct core_data *c, struct pkg_data
                outp +=
                    sprintf(outp, fmt8, (printed++ ? delim : ""),
                            100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float);
+       /* UncMHz */
+       if (DO_BIC(BIC_UNCORE_MHZ))
+               outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), p->uncore_mhz);
 
        for (i = 0, mp = sys.pp; mp; i++, mp = mp->next) {
                if (mp->format == FORMAT_RAW) {
@@ -1471,6 +1481,7 @@ int delta_package(struct pkg_data *new, struct pkg_data *old)
        else
                old->gfx_rc6_ms = new->gfx_rc6_ms - old->gfx_rc6_ms;
 
+       old->uncore_mhz = new->uncore_mhz;
        old->gfx_mhz = new->gfx_mhz;
        old->gfx_act_mhz = new->gfx_act_mhz;
 
@@ -1689,6 +1700,7 @@ void clear_counters(struct thread_data *t, struct core_data *c, struct pkg_data
        p->pkg_temp_c = 0;
 
        p->gfx_rc6_ms = 0;
+       p->uncore_mhz = 0;
        p->gfx_mhz = 0;
        p->gfx_act_mhz = 0;
        for (i = 0, mp = sys.tp; mp; i++, mp = mp->next)
@@ -1788,6 +1800,7 @@ int sum_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
        average.packages.energy_gfx += p->energy_gfx;
 
        average.packages.gfx_rc6_ms = p->gfx_rc6_ms;
+       average.packages.uncore_mhz = p->uncore_mhz;
        average.packages.gfx_mhz = p->gfx_mhz;
        average.packages.gfx_act_mhz = p->gfx_act_mhz;
 
@@ -1948,6 +1961,16 @@ int get_mp(int cpu, struct msr_counter *mp, unsigned long long *counterp)
        return 0;
 }
 
+unsigned long long get_uncore_mhz(int package, int die)
+{
+       char path[128];
+
+       sprintf(path, "/sys/devices/system/cpu/intel_uncore_frequency/package_0%d_die_0%d/current_freq_khz", package,
+               die);
+
+       return (snapshot_sysfs_counter(path) / 1000);
+}
+
 int get_epb(int cpu)
 {
        char path[128 + PATH_BYTES];
@@ -2035,9 +2058,9 @@ int get_core_throt_cnt(int cpu, unsigned long long *cnt)
        if (!fp)
                return -1;
        ret = fscanf(fp, "%lld", &tmp);
+       fclose(fp);
        if (ret != 1)
                return -1;
-       fclose(fp);
        *cnt = tmp;
 
        return 0;
@@ -2297,6 +2320,10 @@ retry:
        if (DO_BIC(BIC_GFX_rc6))
                p->gfx_rc6_ms = gfx_cur_rc6_ms;
 
+       /* n.b. assume die0 uncore frequency applies to whole package */
+       if (DO_BIC(BIC_UNCORE_MHZ))
+               p->uncore_mhz = get_uncore_mhz(p->package_id, 0);
+
        if (DO_BIC(BIC_GFXMHz))
                p->gfx_mhz = gfx_cur_mhz;
 
@@ -2494,6 +2521,7 @@ int has_turbo_ratio_group_limits(int family, int model)
        case INTEL_FAM6_ATOM_GOLDMONT:
        case INTEL_FAM6_SKYLAKE_X:
        case INTEL_FAM6_ICELAKE_X:
+       case INTEL_FAM6_SAPPHIRERAPIDS_X:
        case INTEL_FAM6_ATOM_GOLDMONT_D:
        case INTEL_FAM6_ATOM_TREMONT_D:
                return 1;
@@ -2502,13 +2530,14 @@ int has_turbo_ratio_group_limits(int family, int model)
        }
 }
 
-static void dump_turbo_ratio_limits(int family, int model)
+static void dump_turbo_ratio_limits(int trl_msr_offset, int family, int model)
 {
        unsigned long long msr, core_counts;
-       unsigned int ratio, group_size;
+       int shift;
 
-       get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT, &msr);
-       fprintf(outf, "cpu%d: MSR_TURBO_RATIO_LIMIT: 0x%08llx\n", base_cpu, msr);
+       get_msr(base_cpu, trl_msr_offset, &msr);
+       fprintf(outf, "cpu%d: MSR_%sTURBO_RATIO_LIMIT: 0x%08llx\n",
+               base_cpu, trl_msr_offset == MSR_SECONDARY_TURBO_RATIO_LIMIT ? "SECONDARY" : "", msr);
 
        if (has_turbo_ratio_group_limits(family, model)) {
                get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT1, &core_counts);
@@ -2517,53 +2546,16 @@ static void dump_turbo_ratio_limits(int family, int model)
                core_counts = 0x0807060504030201;
        }
 
-       ratio = (msr >> 56) & 0xFF;
-       group_size = (core_counts >> 56) & 0xFF;
-       if (ratio)
-               fprintf(outf, "%d * %.1f = %.1f MHz max turbo %d active cores\n",
-                       ratio, bclk, ratio * bclk, group_size);
+       for (shift = 56; shift >= 0; shift -= 8) {
+               unsigned int ratio, group_size;
 
-       ratio = (msr >> 48) & 0xFF;
-       group_size = (core_counts >> 48) & 0xFF;
-       if (ratio)
-               fprintf(outf, "%d * %.1f = %.1f MHz max turbo %d active cores\n",
-                       ratio, bclk, ratio * bclk, group_size);
-
-       ratio = (msr >> 40) & 0xFF;
-       group_size = (core_counts >> 40) & 0xFF;
-       if (ratio)
-               fprintf(outf, "%d * %.1f = %.1f MHz max turbo %d active cores\n",
-                       ratio, bclk, ratio * bclk, group_size);
-
-       ratio = (msr >> 32) & 0xFF;
-       group_size = (core_counts >> 32) & 0xFF;
-       if (ratio)
-               fprintf(outf, "%d * %.1f = %.1f MHz max turbo %d active cores\n",
-                       ratio, bclk, ratio * bclk, group_size);
-
-       ratio = (msr >> 24) & 0xFF;
-       group_size = (core_counts >> 24) & 0xFF;
-       if (ratio)
-               fprintf(outf, "%d * %.1f = %.1f MHz max turbo %d active cores\n",
-                       ratio, bclk, ratio * bclk, group_size);
-
-       ratio = (msr >> 16) & 0xFF;
-       group_size = (core_counts >> 16) & 0xFF;
-       if (ratio)
-               fprintf(outf, "%d * %.1f = %.1f MHz max turbo %d active cores\n",
-                       ratio, bclk, ratio * bclk, group_size);
-
-       ratio = (msr >> 8) & 0xFF;
-       group_size = (core_counts >> 8) & 0xFF;
-       if (ratio)
-               fprintf(outf, "%d * %.1f = %.1f MHz max turbo %d active cores\n",
-                       ratio, bclk, ratio * bclk, group_size);
+               ratio = (msr >> shift) & 0xFF;
+               group_size = (core_counts >> shift) & 0xFF;
+               if (ratio)
+                       fprintf(outf, "%d * %.1f = %.1f MHz max turbo %d active cores\n",
+                               ratio, bclk, ratio * bclk, group_size);
+       }
 
-       ratio = (msr >> 0) & 0xFF;
-       group_size = (core_counts >> 0) & 0xFF;
-       if (ratio)
-               fprintf(outf, "%d * %.1f = %.1f MHz max turbo %d active cores\n",
-                       ratio, bclk, ratio * bclk, group_size);
        return;
 }
 
@@ -2976,7 +2968,7 @@ int get_thread_siblings(struct cpu_topology *thiscpu)
                                }
                        }
                }
-       } while (!strncmp(&character, ",", 1));
+       } while (character == ',');
        fclose(filep);
 
        return CPU_COUNT_S(size, thiscpu->put_ids);
@@ -3742,6 +3734,7 @@ int probe_nhm_msrs(unsigned int family, unsigned int model)
                has_misc_feature_control = 1;
                break;
        case INTEL_FAM6_SKYLAKE_X:      /* SKX */
+       case INTEL_FAM6_SAPPHIRERAPIDS_X:       /* SPR */
                pkg_cstate_limits = skx_pkg_cstate_limits;
                has_misc_feature_control = 1;
                break;
@@ -3871,6 +3864,22 @@ int is_icx(unsigned int family, unsigned int model)
        return 0;
 }
 
+int is_spr(unsigned int family, unsigned int model)
+{
+
+       if (!genuine_intel)
+               return 0;
+
+       if (family != 6)
+               return 0;
+
+       switch (model) {
+       case INTEL_FAM6_SAPPHIRERAPIDS_X:
+               return 1;
+       }
+       return 0;
+}
+
 int is_ehl(unsigned int family, unsigned int model)
 {
        if (!genuine_intel)
@@ -3988,6 +3997,7 @@ int has_glm_turbo_ratio_limit(unsigned int family, unsigned int model)
        case INTEL_FAM6_ATOM_GOLDMONT:
        case INTEL_FAM6_SKYLAKE_X:
        case INTEL_FAM6_ICELAKE_X:
+       case INTEL_FAM6_SAPPHIRERAPIDS_X:
                return 1;
        default:
                return 0;
@@ -4015,7 +4025,7 @@ int has_config_tdp(unsigned int family, unsigned int model)
        case INTEL_FAM6_CANNONLAKE_L:   /* CNL */
        case INTEL_FAM6_SKYLAKE_X:      /* SKX */
        case INTEL_FAM6_ICELAKE_X:      /* ICX */
-
+       case INTEL_FAM6_SAPPHIRERAPIDS_X:       /* SPR */
        case INTEL_FAM6_XEON_PHI_KNL:   /* Knights Landing */
                return 1;
        default:
@@ -4083,8 +4093,12 @@ static void dump_cstate_pstate_config_info(unsigned int family, unsigned int mod
        if (has_ivt_turbo_ratio_limit(family, model))
                dump_ivt_turbo_ratio_limits();
 
-       if (has_turbo_ratio_limit(family, model))
-               dump_turbo_ratio_limits(family, model);
+       if (has_turbo_ratio_limit(family, model)) {
+               dump_turbo_ratio_limits(MSR_TURBO_RATIO_LIMIT, family, model);
+
+               if (is_hybrid)
+                       dump_turbo_ratio_limits(MSR_SECONDARY_TURBO_RATIO_LIMIT, family, model);
+       }
 
        if (has_atom_turbo_ratio_limit(family, model))
                dump_atom_turbo_ratio_limits();
@@ -4098,6 +4112,24 @@ static void dump_cstate_pstate_config_info(unsigned int family, unsigned int mod
        dump_nhm_cst_cfg();
 }
 
+static int read_sysfs_int(char *path)
+{
+       FILE *input;
+       int retval = -1;
+
+       input = fopen(path, "r");
+       if (input == NULL) {
+               if (debug)
+                       fprintf(outf, "NSFOD %s\n", path);
+               return (-1);
+       }
+       if (fscanf(input, "%d", &retval) != 1)
+               err(1, "%s: failed to read int from file", path);
+       fclose(input);
+
+       return (retval);
+}
+
 static void dump_sysfs_file(char *path)
 {
        FILE *input;
@@ -4116,6 +4148,48 @@ static void dump_sysfs_file(char *path)
        fprintf(outf, "%s: %s", strrchr(path, '/') + 1, cpuidle_buf);
 }
 
+static void intel_uncore_frequency_probe(void)
+{
+       int i, j;
+       char path[128];
+
+       if (!genuine_intel)
+               return;
+
+       if (access("/sys/devices/system/cpu/intel_uncore_frequency/package_00_die_00", R_OK))
+               return;
+
+       if (!access("/sys/devices/system/cpu/intel_uncore_frequency/package_00_die_00/current_freq_khz", R_OK))
+               BIC_PRESENT(BIC_UNCORE_MHZ);
+
+       if (quiet)
+               return;
+
+       for (i = 0; i < topo.num_packages; ++i) {
+               for (j = 0; j < topo.num_die; ++j) {
+                       int k, l;
+
+                       sprintf(path, "/sys/devices/system/cpu/intel_uncore_frequency/package_0%d_die_0%d/min_freq_khz",
+                               i, j);
+                       k = read_sysfs_int(path);
+                       sprintf(path, "/sys/devices/system/cpu/intel_uncore_frequency/package_0%d_die_0%d/max_freq_khz",
+                               i, j);
+                       l = read_sysfs_int(path);
+                       fprintf(outf, "Uncore Frequency pkg%d die%d: %d - %d MHz ", i, j, k / 1000, l / 1000);
+
+                       sprintf(path,
+                               "/sys/devices/system/cpu/intel_uncore_frequency/package_0%d_die_0%d/initial_min_freq_khz",
+                               i, j);
+                       k = read_sysfs_int(path);
+                       sprintf(path,
+                               "/sys/devices/system/cpu/intel_uncore_frequency/package_0%d_die_0%d/initial_max_freq_khz",
+                               i, j);
+                       l = read_sysfs_int(path);
+                       fprintf(outf, "(%d - %d MHz)\n", k / 1000, l / 1000);
+               }
+       }
+}
+
 static void dump_sysfs_cstate_config(void)
 {
        char path[64];
@@ -4486,6 +4560,7 @@ static double rapl_dram_energy_units_probe(int model, double rapl_energy_units)
        case INTEL_FAM6_SKYLAKE_X:      /* SKX */
        case INTEL_FAM6_XEON_PHI_KNL:   /* KNL */
        case INTEL_FAM6_ICELAKE_X:      /* ICX */
+       case INTEL_FAM6_SAPPHIRERAPIDS_X:       /* SPR */
                return (rapl_dram_energy_units = 15.3 / 1000000);
        default:
                return (rapl_energy_units);
@@ -4575,6 +4650,7 @@ void rapl_probe_intel(unsigned int family, unsigned int model)
        case INTEL_FAM6_BROADWELL_X:    /* BDX */
        case INTEL_FAM6_SKYLAKE_X:      /* SKX */
        case INTEL_FAM6_ICELAKE_X:      /* ICX */
+       case INTEL_FAM6_SAPPHIRERAPIDS_X:       /* SPR */
        case INTEL_FAM6_XEON_PHI_KNL:   /* KNL */
                do_rapl =
                    RAPL_PKG | RAPL_DRAM | RAPL_DRAM_POWER_INFO | RAPL_DRAM_PERF_STATUS | RAPL_PKG_PERF_STATUS |
@@ -4740,13 +4816,19 @@ void perf_limit_reasons_probe(unsigned int family, unsigned int model)
 
 void automatic_cstate_conversion_probe(unsigned int family, unsigned int model)
 {
-       if (is_skx(family, model) || is_bdx(family, model) || is_icx(family, model))
+       if (family != 6)
+               return;
+
+       switch (model) {
+       case INTEL_FAM6_BROADWELL_X:
+       case INTEL_FAM6_SKYLAKE_X:
                has_automatic_cstate_conversion = 1;
+       }
 }
 
 void prewake_cstate_probe(unsigned int family, unsigned int model)
 {
-       if (is_icx(family, model))
+       if (is_icx(family, model) || is_spr(family, model))
                dis_cstate_prewake = 1;
 }
 
@@ -4975,6 +5057,7 @@ int has_snb_msrs(unsigned int family, unsigned int model)
        case INTEL_FAM6_CANNONLAKE_L:   /* CNL */
        case INTEL_FAM6_SKYLAKE_X:      /* SKX */
        case INTEL_FAM6_ICELAKE_X:      /* ICX */
+       case INTEL_FAM6_SAPPHIRERAPIDS_X:       /* SPR */
        case INTEL_FAM6_ATOM_GOLDMONT:  /* BXT */
        case INTEL_FAM6_ATOM_GOLDMONT_PLUS:
        case INTEL_FAM6_ATOM_GOLDMONT_D:        /* DNV */
@@ -5361,13 +5444,15 @@ unsigned int intel_model_duplicates(unsigned int model)
        case INTEL_FAM6_LAKEFIELD:
        case INTEL_FAM6_ALDERLAKE:
        case INTEL_FAM6_ALDERLAKE_L:
+       case INTEL_FAM6_ALDERLAKE_N:
+       case INTEL_FAM6_RAPTORLAKE:
+       case INTEL_FAM6_RAPTORLAKE_P:
                return INTEL_FAM6_CANNONLAKE_L;
 
        case INTEL_FAM6_ATOM_TREMONT_L:
                return INTEL_FAM6_ATOM_TREMONT;
 
        case INTEL_FAM6_ICELAKE_D:
-       case INTEL_FAM6_SAPPHIRERAPIDS_X:
                return INTEL_FAM6_ICELAKE_X;
        }
        return model;
@@ -5398,7 +5483,7 @@ void print_dev_latency(void)
 }
 
 /*
- * Linux-perf manages the the HW instructions-retired counter
+ * Linux-perf manages the HW instructions-retired counter
  * by enabling when requested, and hiding rollover
  */
 void linux_perf_init(void)
@@ -5543,7 +5628,10 @@ void process_cpuid()
                __cpuid_count(0x7, 0, eax, ebx, ecx, edx);
 
                has_sgx = ebx & (1 << 2);
-               fprintf(outf, "CPUID(7): %sSGX\n", has_sgx ? "" : "No-");
+
+               is_hybrid = edx & (1 << 15);
+
+               fprintf(outf, "CPUID(7): %sSGX %sHybrid\n", has_sgx ? "" : "No-", is_hybrid ? "" : "No-");
 
                if (has_sgx)
                        decode_feature_control_msr();
@@ -5654,7 +5742,7 @@ void process_cpuid()
                BIC_NOT_PRESENT(BIC_Pkgpc7);
                use_c1_residency_msr = 1;
        }
-       if (is_skx(family, model) || is_icx(family, model)) {
+       if (is_skx(family, model) || is_icx(family, model) || is_spr(family, model)) {
                BIC_NOT_PRESENT(BIC_CPU_c3);
                BIC_NOT_PRESENT(BIC_Pkgpc3);
                BIC_NOT_PRESENT(BIC_CPU_c7);
@@ -5699,6 +5787,7 @@ void process_cpuid()
 
        if (!quiet)
                dump_cstate_pstate_config_info(family, model);
+       intel_uncore_frequency_probe();
 
        if (!quiet)
                print_dev_latency();
@@ -6128,7 +6217,30 @@ int get_and_dump_counters(void)
 
 void print_version()
 {
-       fprintf(outf, "turbostat version 2022.04.16 - Len Brown <lenb@kernel.org>\n");
+       fprintf(outf, "turbostat version 2022.07.28 - Len Brown <lenb@kernel.org>\n");
+}
+
+#define COMMAND_LINE_SIZE 2048
+
+void print_bootcmd(void)
+{
+       char bootcmd[COMMAND_LINE_SIZE];
+       FILE *fp;
+       int ret;
+
+       memset(bootcmd, 0, COMMAND_LINE_SIZE);
+       fp = fopen("/proc/cmdline", "r");
+       if (!fp)
+               return;
+
+       ret = fread(bootcmd, sizeof(char), COMMAND_LINE_SIZE - 1, fp);
+       if (ret) {
+               bootcmd[ret] = '\0';
+               /* the last character is already '\n' */
+               fprintf(outf, "Kernel command line: %s", bootcmd);
+       }
+
+       fclose(fp);
 }
 
 int add_counter(unsigned int msr_num, char *path, char *name,
@@ -6602,8 +6714,10 @@ int main(int argc, char **argv)
        outf = stderr;
        cmdline(argc, argv);
 
-       if (!quiet)
+       if (!quiet) {
                print_version();
+               print_bootcmd();
+       }
 
        probe_sysfs();
 
index 83844f8..b0ca44c 100644 (file)
@@ -417,6 +417,7 @@ int main(int argc, char *argv[])
 {
        int ret = 0;
        int fd;
+       uint32_t request;
 
        parse_opts(argc, argv);
 
@@ -430,13 +431,23 @@ int main(int argc, char *argv[])
        /*
         * spi mode
         */
+       /* WR is make a request to assign 'mode' */
+       request = mode;
        ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);
        if (ret == -1)
                pabort("can't set spi mode");
 
+       /* RD is read what mode the device actually is in */
        ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode);
        if (ret == -1)
                pabort("can't get spi mode");
+       /* Drivers can reject some mode bits without returning an error.
+        * Read the current value to identify what mode it is in, and if it
+        * differs from the requested mode, warn the user.
+        */
+       if (request != mode)
+               printf("WARNING device does not support requested mode 0x%x\n",
+                       request);
 
        /*
         * bits per word
diff --git a/tools/testing/kunit/configs/arch_uml.config b/tools/testing/kunit/configs/arch_uml.config
new file mode 100644 (file)
index 0000000..e824ce4
--- /dev/null
@@ -0,0 +1,5 @@
+# Config options which are added to UML builds by default
+
+# Enable virtio/pci, as a lot of tests require it.
+CONFIG_VIRTIO_UML=y
+CONFIG_UML_PCI_OVER_VIRTIO=y
diff --git a/tools/testing/kunit/configs/coverage_uml.config b/tools/testing/kunit/configs/coverage_uml.config
new file mode 100644 (file)
index 0000000..bacb776
--- /dev/null
@@ -0,0 +1,11 @@
+# This config fragment enables coverage on UML, which is different from the
+# normal gcov used in other arches (no debugfs).
+# Example usage:
+# ./tools/testing/kunit/kunit.py run \
+#   --kunitconfig=tools/testing/kunit/configs/all_tests_uml.config \
+#   --kunitconfig=tools/testing/kunit/configs/coverage_uml.config
+
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
+CONFIG_GCOV=y
index 13bd72e..e132b06 100755 (executable)
@@ -10,6 +10,7 @@
 import argparse
 import os
 import re
+import shlex
 import sys
 import time
 
@@ -22,6 +23,7 @@ from typing import Iterable, List, Optional, Sequence, Tuple
 import kunit_json
 import kunit_kernel
 import kunit_parser
+from kunit_printer import stdout
 
 class KunitStatus(Enum):
        SUCCESS = auto()
@@ -72,7 +74,7 @@ def get_kernel_root_path() -> str:
 
 def config_tests(linux: kunit_kernel.LinuxSourceTree,
                 request: KunitConfigRequest) -> KunitResult:
-       kunit_parser.print_with_timestamp('Configuring KUnit Kernel ...')
+       stdout.print_with_timestamp('Configuring KUnit Kernel ...')
 
        config_start = time.time()
        success = linux.build_reconfig(request.build_dir, request.make_options)
@@ -85,7 +87,7 @@ def config_tests(linux: kunit_kernel.LinuxSourceTree,
 
 def build_tests(linux: kunit_kernel.LinuxSourceTree,
                request: KunitBuildRequest) -> KunitResult:
-       kunit_parser.print_with_timestamp('Building KUnit Kernel ...')
+       stdout.print_with_timestamp('Building KUnit Kernel ...')
 
        build_start = time.time()
        success = linux.build_kernel(request.alltests,
@@ -158,7 +160,7 @@ def exec_tests(linux: kunit_kernel.LinuxSourceTree, request: KunitExecRequest) -
        test_counts = kunit_parser.TestCounts()
        exec_time = 0.0
        for i, filter_glob in enumerate(filter_globs):
-               kunit_parser.print_with_timestamp('Starting KUnit Kernel ({}/{})...'.format(i+1, len(filter_globs)))
+               stdout.print_with_timestamp('Starting KUnit Kernel ({}/{})...'.format(i+1, len(filter_globs)))
 
                test_start = time.time()
                run_result = linux.run_kernel(
@@ -221,7 +223,7 @@ def parse_tests(request: KunitParseRequest, metadata: kunit_json.Metadata, input
                else:
                        with open(request.json, 'w') as f:
                                f.write(json_str)
-                       kunit_parser.print_with_timestamp("Test results stored in %s" %
+                       stdout.print_with_timestamp("Test results stored in %s" %
                                os.path.abspath(request.json))
 
        if test_result.status != kunit_parser.TestStatus.SUCCESS:
@@ -245,7 +247,7 @@ def run_tests(linux: kunit_kernel.LinuxSourceTree,
 
        run_end = time.time()
 
-       kunit_parser.print_with_timestamp((
+       stdout.print_with_timestamp((
                'Elapsed time: %.3fs total, %.3fs configuring, %.3fs ' +
                'building, %.3fs running\n') % (
                                run_end - run_start,
@@ -291,8 +293,9 @@ def add_common_opts(parser) -> None:
        parser.add_argument('--kunitconfig',
                             help='Path to Kconfig fragment that enables KUnit tests.'
                             ' If given a directory, (e.g. lib/kunit), "/.kunitconfig" '
-                            'will get  automatically appended.',
-                            metavar='PATH')
+                            'will get  automatically appended. If repeated, the files '
+                            'blindly concatenated, which might not work in all cases.',
+                            action='append', metavar='PATHS')
        parser.add_argument('--kconfig_add',
                             help='Additional Kconfig options to append to the '
                             '.kunitconfig, e.g. CONFIG_KASAN=y. Can be repeated.',
@@ -323,6 +326,10 @@ def add_common_opts(parser) -> None:
                                  'a QemuArchParams object.'),
                            type=str, metavar='FILE')
 
+       parser.add_argument('--qemu_args',
+                           help='Additional QEMU arguments, e.g. "-smp 8"',
+                           action='append', metavar='')
+
 def add_build_opts(parser) -> None:
        parser.add_argument('--jobs',
                            help='As in the make command, "Specifies  the number of '
@@ -365,7 +372,25 @@ def add_parse_opts(parser) -> None:
                            'filename is specified',
                            type=str, const='stdout', default=None, metavar='FILE')
 
-def main(argv, linux=None):
+
+def tree_from_args(cli_args: argparse.Namespace) -> kunit_kernel.LinuxSourceTree:
+       """Returns a LinuxSourceTree based on the user's arguments."""
+       # Allow users to specify multiple arguments in one string, e.g. '-smp 8'
+       qemu_args: List[str] = []
+       if cli_args.qemu_args:
+               for arg in cli_args.qemu_args:
+                       qemu_args.extend(shlex.split(arg))
+
+       return kunit_kernel.LinuxSourceTree(cli_args.build_dir,
+                       kunitconfig_paths=cli_args.kunitconfig,
+                       kconfig_add=cli_args.kconfig_add,
+                       arch=cli_args.arch,
+                       cross_compile=cli_args.cross_compile,
+                       qemu_config_path=cli_args.qemu_config,
+                       extra_qemu_args=qemu_args)
+
+
+def main(argv):
        parser = argparse.ArgumentParser(
                        description='Helps writing and running KUnit tests.')
        subparser = parser.add_subparsers(dest='subcommand')
@@ -412,14 +437,7 @@ def main(argv, linux=None):
                if not os.path.exists(cli_args.build_dir):
                        os.mkdir(cli_args.build_dir)
 
-               if not linux:
-                       linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir,
-                                       kunitconfig_path=cli_args.kunitconfig,
-                                       kconfig_add=cli_args.kconfig_add,
-                                       arch=cli_args.arch,
-                                       cross_compile=cli_args.cross_compile,
-                                       qemu_config_path=cli_args.qemu_config)
-
+               linux = tree_from_args(cli_args)
                request = KunitRequest(build_dir=cli_args.build_dir,
                                       make_options=cli_args.make_options,
                                       jobs=cli_args.jobs,
@@ -438,50 +456,29 @@ def main(argv, linux=None):
                                not os.path.exists(cli_args.build_dir)):
                        os.mkdir(cli_args.build_dir)
 
-               if not linux:
-                       linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir,
-                                       kunitconfig_path=cli_args.kunitconfig,
-                                       kconfig_add=cli_args.kconfig_add,
-                                       arch=cli_args.arch,
-                                       cross_compile=cli_args.cross_compile,
-                                       qemu_config_path=cli_args.qemu_config)
-
+               linux = tree_from_args(cli_args)
                request = KunitConfigRequest(build_dir=cli_args.build_dir,
                                             make_options=cli_args.make_options)
                result = config_tests(linux, request)
-               kunit_parser.print_with_timestamp((
+               stdout.print_with_timestamp((
                        'Elapsed time: %.3fs\n') % (
                                result.elapsed_time))
                if result.status != KunitStatus.SUCCESS:
                        sys.exit(1)
        elif cli_args.subcommand == 'build':
-               if not linux:
-                       linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir,
-                                       kunitconfig_path=cli_args.kunitconfig,
-                                       kconfig_add=cli_args.kconfig_add,
-                                       arch=cli_args.arch,
-                                       cross_compile=cli_args.cross_compile,
-                                       qemu_config_path=cli_args.qemu_config)
-
+               linux = tree_from_args(cli_args)
                request = KunitBuildRequest(build_dir=cli_args.build_dir,
                                            make_options=cli_args.make_options,
                                            jobs=cli_args.jobs,
                                            alltests=cli_args.alltests)
                result = config_and_build_tests(linux, request)
-               kunit_parser.print_with_timestamp((
+               stdout.print_with_timestamp((
                        'Elapsed time: %.3fs\n') % (
                                result.elapsed_time))
                if result.status != KunitStatus.SUCCESS:
                        sys.exit(1)
        elif cli_args.subcommand == 'exec':
-               if not linux:
-                       linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir,
-                                       kunitconfig_path=cli_args.kunitconfig,
-                                       kconfig_add=cli_args.kconfig_add,
-                                       arch=cli_args.arch,
-                                       cross_compile=cli_args.cross_compile,
-                                       qemu_config_path=cli_args.qemu_config)
-
+               linux = tree_from_args(cli_args)
                exec_request = KunitExecRequest(raw_output=cli_args.raw_output,
                                                build_dir=cli_args.build_dir,
                                                json=cli_args.json,
@@ -491,7 +488,7 @@ def main(argv, linux=None):
                                                kernel_args=cli_args.kernel_args,
                                                run_isolated=cli_args.run_isolated)
                result = exec_tests(linux, exec_request)
-               kunit_parser.print_with_timestamp((
+               stdout.print_with_timestamp((
                        'Elapsed time: %.3fs\n') % (result.elapsed_time))
                if result.status != KunitStatus.SUCCESS:
                        sys.exit(1)
index 75a8dc1..48b5f34 100644 (file)
@@ -8,7 +8,7 @@
 
 from dataclasses import dataclass
 import re
-from typing import List, Set
+from typing import Dict, Iterable, List, Set, Tuple
 
 CONFIG_IS_NOT_SET_PATTERN = r'^# CONFIG_(\w+) is not set$'
 CONFIG_PATTERN = r'^CONFIG_(\w+)=(\S+|".*")$'
@@ -32,35 +32,51 @@ class Kconfig:
        """Represents defconfig or .config specified using the Kconfig language."""
 
        def __init__(self) -> None:
-               self._entries = []  # type: List[KconfigEntry]
+               self._entries = {}  # type: Dict[str, str]
 
-       def entries(self) -> Set[KconfigEntry]:
-               return set(self._entries)
+       def __eq__(self, other) -> bool:
+               if not isinstance(other, self.__class__):
+                       return False
+               return self._entries == other._entries
 
-       def add_entry(self, entry: KconfigEntry) -> None:
-               self._entries.append(entry)
+       def __repr__(self) -> str:
+               return ','.join(str(e) for e in self.as_entries())
+
+       def as_entries(self) -> Iterable[KconfigEntry]:
+               for name, value in self._entries.items():
+                       yield KconfigEntry(name, value)
+
+       def add_entry(self, name: str, value: str) -> None:
+               self._entries[name] = value
 
        def is_subset_of(self, other: 'Kconfig') -> bool:
-               other_dict = {e.name: e.value for e in other.entries()}
-               for a in self.entries():
-                       b = other_dict.get(a.name)
+               for name, value in self._entries.items():
+                       b = other._entries.get(name)
                        if b is None:
-                               if a.value == 'n':
+                               if value == 'n':
                                        continue
                                return False
-                       if a.value != b:
+                       if value != b:
                                return False
                return True
 
+       def conflicting_options(self, other: 'Kconfig') -> List[Tuple[KconfigEntry, KconfigEntry]]:
+               diff = []  # type: List[Tuple[KconfigEntry, KconfigEntry]]
+               for name, value in self._entries.items():
+                       b = other._entries.get(name)
+                       if b and value != b:
+                               pair = (KconfigEntry(name, value), KconfigEntry(name, b))
+                               diff.append(pair)
+               return diff
+
        def merge_in_entries(self, other: 'Kconfig') -> None:
-               if other.is_subset_of(self):
-                       return
-               self._entries = list(self.entries().union(other.entries()))
+               for name, value in other._entries.items():
+                       self._entries[name] = value
 
        def write_to_file(self, path: str) -> None:
                with open(path, 'a+') as f:
-                       for entry in self.entries():
-                               f.write(str(entry) + '\n')
+                       for e in self.as_entries():
+                               f.write(str(e) + '\n')
 
 def parse_file(path: str) -> Kconfig:
        with open(path, 'r') as f:
@@ -78,14 +94,12 @@ def parse_from_string(blob: str) -> Kconfig:
 
                match = config_matcher.match(line)
                if match:
-                       entry = KconfigEntry(match.group(1), match.group(2))
-                       kconfig.add_entry(entry)
+                       kconfig.add_entry(match.group(1), match.group(2))
                        continue
 
                empty_match = is_not_set_matcher.match(line)
                if empty_match:
-                       entry = KconfigEntry(empty_match.group(1), 'n')
-                       kconfig.add_entry(entry)
+                       kconfig.add_entry(empty_match.group(1), 'n')
                        continue
 
                if line[0] == '#':
index 3539efa..f5c26ea 100644 (file)
@@ -18,7 +18,7 @@ import threading
 from typing import Iterator, List, Optional, Tuple
 
 import kunit_config
-import kunit_parser
+from kunit_printer import stdout
 import qemu_config
 
 KCONFIG_PATH = '.config'
@@ -26,6 +26,7 @@ KUNITCONFIG_PATH = '.kunitconfig'
 OLD_KUNITCONFIG_PATH = 'last_used_kunitconfig'
 DEFAULT_KUNITCONFIG_PATH = 'tools/testing/kunit/configs/default.config'
 BROKEN_ALLCONFIG_PATH = 'tools/testing/kunit/configs/broken_on_uml.config'
+UML_KCONFIG_PATH = 'tools/testing/kunit/configs/arch_uml.config'
 OUTFILE_PATH = 'test.log'
 ABS_TOOL_PATH = os.path.abspath(os.path.dirname(__file__))
 QEMU_CONFIGS_DIR = os.path.join(ABS_TOOL_PATH, 'qemu_configs')
@@ -53,8 +54,8 @@ class LinuxSourceTreeOperations:
                except subprocess.CalledProcessError as e:
                        raise ConfigError(e.output.decode())
 
-       def make_arch_qemuconfig(self, base_kunitconfig: kunit_config.Kconfig) -> None:
-               pass
+       def make_arch_config(self, base_kunitconfig: kunit_config.Kconfig) -> kunit_config.Kconfig:
+               return base_kunitconfig
 
        def make_allyesconfig(self, build_dir: str, make_options) -> None:
                raise ConfigError('Only the "um" arch is supported for alltests')
@@ -109,9 +110,10 @@ class LinuxSourceTreeOperationsQemu(LinuxSourceTreeOperations):
                self._kernel_command_line = qemu_arch_params.kernel_command_line + ' kunit_shutdown=reboot'
                self._extra_qemu_params = qemu_arch_params.extra_qemu_params
 
-       def make_arch_qemuconfig(self, base_kunitconfig: kunit_config.Kconfig) -> None:
+       def make_arch_config(self, base_kunitconfig: kunit_config.Kconfig) -> kunit_config.Kconfig:
                kconfig = kunit_config.parse_from_string(self._kconfig)
-               base_kunitconfig.merge_in_entries(kconfig)
+               kconfig.merge_in_entries(base_kunitconfig)
+               return kconfig
 
        def start(self, params: List[str], build_dir: str) -> subprocess.Popen:
                kernel_path = os.path.join(build_dir, self._kernel_path)
@@ -137,8 +139,13 @@ class LinuxSourceTreeOperationsUml(LinuxSourceTreeOperations):
        def __init__(self, cross_compile=None):
                super().__init__(linux_arch='um', cross_compile=cross_compile)
 
+       def make_arch_config(self, base_kunitconfig: kunit_config.Kconfig) -> kunit_config.Kconfig:
+               kconfig = kunit_config.parse_file(UML_KCONFIG_PATH)
+               kconfig.merge_in_entries(base_kunitconfig)
+               return kconfig
+
        def make_allyesconfig(self, build_dir: str, make_options) -> None:
-               kunit_parser.print_with_timestamp(
+               stdout.print_with_timestamp(
                        'Enabling all CONFIGs for UML...')
                command = ['make', 'ARCH=um', 'O=' + build_dir, 'allyesconfig']
                if make_options:
@@ -148,18 +155,19 @@ class LinuxSourceTreeOperationsUml(LinuxSourceTreeOperations):
                        stdout=subprocess.DEVNULL,
                        stderr=subprocess.STDOUT)
                process.wait()
-               kunit_parser.print_with_timestamp(
+               stdout.print_with_timestamp(
                        'Disabling broken configs to run KUnit tests...')
 
                with open(get_kconfig_path(build_dir), 'a') as config:
                        with open(BROKEN_ALLCONFIG_PATH, 'r') as disable:
                                config.write(disable.read())
-               kunit_parser.print_with_timestamp(
+               stdout.print_with_timestamp(
                        'Starting Kernel with all configs takes a few minutes...')
 
        def start(self, params: List[str], build_dir: str) -> subprocess.Popen:
                """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'])
                return subprocess.Popen([linux_bin] + params,
                                           stdin=subprocess.PIPE,
                                           stdout=subprocess.PIPE,
@@ -175,22 +183,44 @@ def get_kunitconfig_path(build_dir: str) -> str:
 def get_old_kunitconfig_path(build_dir: str) -> str:
        return os.path.join(build_dir, OLD_KUNITCONFIG_PATH)
 
+def get_parsed_kunitconfig(build_dir: str,
+                          kunitconfig_paths: Optional[List[str]]=None) -> kunit_config.Kconfig:
+       if not kunitconfig_paths:
+               path = get_kunitconfig_path(build_dir)
+               if not os.path.exists(path):
+                       shutil.copyfile(DEFAULT_KUNITCONFIG_PATH, path)
+               return kunit_config.parse_file(path)
+
+       merged = kunit_config.Kconfig()
+
+       for path in kunitconfig_paths:
+               if os.path.isdir(path):
+                       path = os.path.join(path, KUNITCONFIG_PATH)
+               if not os.path.exists(path):
+                       raise ConfigError(f'Specified kunitconfig ({path}) does not exist')
+
+               partial = kunit_config.parse_file(path)
+               diff = merged.conflicting_options(partial)
+               if diff:
+                       diff_str = '\n\n'.join(f'{a}\n  vs from {path}\n{b}' for a, b in diff)
+                       raise ConfigError(f'Multiple values specified for {len(diff)} options in kunitconfig:\n{diff_str}')
+               merged.merge_in_entries(partial)
+       return merged
+
 def get_outfile_path(build_dir: str) -> str:
        return os.path.join(build_dir, OUTFILE_PATH)
 
-def get_source_tree_ops(arch: str, cross_compile: Optional[str]) -> LinuxSourceTreeOperations:
+def _default_qemu_config_path(arch: str) -> str:
        config_path = os.path.join(QEMU_CONFIGS_DIR, arch + '.py')
-       if arch == 'um':
-               return LinuxSourceTreeOperationsUml(cross_compile=cross_compile)
        if os.path.isfile(config_path):
-               return get_source_tree_ops_from_qemu_config(config_path, cross_compile)[1]
+               return config_path
 
        options = [f[:-3] for f in os.listdir(QEMU_CONFIGS_DIR) if f.endswith('.py')]
        raise ConfigError(arch + ' is not a valid arch, options are ' + str(sorted(options)))
 
-def get_source_tree_ops_from_qemu_config(config_path: str,
-                                        cross_compile: Optional[str]) -> Tuple[
-                                                        str, LinuxSourceTreeOperations]:
+def _get_qemu_ops(config_path: str,
+                 extra_qemu_args: Optional[List[str]],
+                 cross_compile: Optional[str]) -> Tuple[str, LinuxSourceTreeOperations]:
        # The module name/path has very little to do with where the actual file
        # exists (I learned this through experimentation and could not find it
        # anywhere in the Python documentation).
@@ -210,6 +240,8 @@ def get_source_tree_ops_from_qemu_config(config_path: str,
        if not hasattr(config, 'QEMU_ARCH'):
                raise ValueError('qemu_config module missing "QEMU_ARCH": ' + config_path)
        params: qemu_config.QemuArchParams = config.QEMU_ARCH  # type: ignore
+       if extra_qemu_args:
+               params.extra_qemu_params.extend(extra_qemu_args)
        return params.linux_arch, LinuxSourceTreeOperationsQemu(
                        params, cross_compile=cross_compile)
 
@@ -219,34 +251,24 @@ class LinuxSourceTree:
        def __init__(
              self,
              build_dir: str,
-             load_config=True,
-             kunitconfig_path='',
+             kunitconfig_paths: Optional[List[str]]=None,
              kconfig_add: Optional[List[str]]=None,
              arch=None,
              cross_compile=None,
-             qemu_config_path=None) -> None:
+             qemu_config_path=None,
+             extra_qemu_args=None) -> None:
                signal.signal(signal.SIGINT, self.signal_handler)
                if qemu_config_path:
-                       self._arch, self._ops = get_source_tree_ops_from_qemu_config(
-                                       qemu_config_path, cross_compile)
+                       self._arch, self._ops = _get_qemu_ops(qemu_config_path, extra_qemu_args, cross_compile)
                else:
                        self._arch = 'um' if arch is None else arch
-                       self._ops = get_source_tree_ops(self._arch, cross_compile)
-
-               if not load_config:
-                       return
+                       if self._arch == 'um':
+                               self._ops = LinuxSourceTreeOperationsUml(cross_compile=cross_compile)
+                       else:
+                               qemu_config_path = _default_qemu_config_path(self._arch)
+                               _, self._ops = _get_qemu_ops(qemu_config_path, extra_qemu_args, cross_compile)
 
-               if kunitconfig_path:
-                       if os.path.isdir(kunitconfig_path):
-                               kunitconfig_path = os.path.join(kunitconfig_path, KUNITCONFIG_PATH)
-                       if not os.path.exists(kunitconfig_path):
-                               raise ConfigError(f'Specified kunitconfig ({kunitconfig_path}) does not exist')
-               else:
-                       kunitconfig_path = get_kunitconfig_path(build_dir)
-                       if not os.path.exists(kunitconfig_path):
-                               shutil.copyfile(DEFAULT_KUNITCONFIG_PATH, kunitconfig_path)
-
-               self._kconfig = kunit_config.parse_file(kunitconfig_path)
+               self._kconfig = get_parsed_kunitconfig(build_dir, kunitconfig_paths)
                if kconfig_add:
                        kconfig = kunit_config.parse_from_string('\n'.join(kconfig_add))
                        self._kconfig.merge_in_entries(kconfig)
@@ -267,10 +289,10 @@ class LinuxSourceTree:
                validated_kconfig = kunit_config.parse_file(kconfig_path)
                if self._kconfig.is_subset_of(validated_kconfig):
                        return True
-               invalid = self._kconfig.entries() - validated_kconfig.entries()
+               missing = set(self._kconfig.as_entries()) - set(validated_kconfig.as_entries())
                message = 'Not all Kconfig options selected in kunitconfig were in the generated .config.\n' \
                          'This is probably due to unsatisfied dependencies.\n' \
-                         'Missing: ' + ', '.join([str(e) for e in invalid])
+                         'Missing: ' + ', '.join(str(e) for e in missing)
                if self._arch == 'um':
                        message += '\nNote: many Kconfig options aren\'t available on UML. You can try running ' \
                                   'on a different architecture with something like "--arch=x86_64".'
@@ -282,7 +304,7 @@ class LinuxSourceTree:
                if build_dir and not os.path.exists(build_dir):
                        os.mkdir(build_dir)
                try:
-                       self._ops.make_arch_qemuconfig(self._kconfig)
+                       self._kconfig = self._ops.make_arch_config(self._kconfig)
                        self._kconfig.write_to_file(kconfig_path)
                        self._ops.make_olddefconfig(build_dir, make_options)
                except ConfigError as e:
@@ -303,7 +325,7 @@ class LinuxSourceTree:
                        return True
 
                old_kconfig = kunit_config.parse_file(old_path)
-               return old_kconfig.entries() != self._kconfig.entries()
+               return old_kconfig != self._kconfig
 
        def build_reconfig(self, build_dir: str, make_options) -> bool:
                """Creates a new .config if it is not a subset of the .kunitconfig."""
@@ -313,7 +335,8 @@ class LinuxSourceTree:
                        return self.build_config(build_dir, make_options)
 
                existing_kconfig = kunit_config.parse_file(kconfig_path)
-               self._ops.make_arch_qemuconfig(self._kconfig)
+               self._kconfig = self._ops.make_arch_config(self._kconfig)
+
                if self._kconfig.is_subset_of(existing_kconfig) and not self._kunitconfig_changed(build_dir):
                        return True
                print('Regenerating .config ...')
@@ -334,7 +357,6 @@ class LinuxSourceTree:
        def run_kernel(self, args=None, build_dir='', filter_glob='', timeout=None) -> Iterator[str]:
                if not args:
                        args = []
-               args.extend(['mem=1G', 'console=tty', 'kunit_shutdown=halt'])
                if filter_glob:
                        args.append('kunit.filter_glob='+filter_glob)
 
index c5569b3..12d3ec7 100644 (file)
@@ -13,10 +13,11 @@ from __future__ import annotations
 import re
 import sys
 
-import datetime
 from enum import Enum, auto
 from typing import Iterable, Iterator, List, Optional, Tuple
 
+from kunit_printer import stdout
+
 class Test:
        """
        A class to represent a test parsed from KTAP results. All KTAP
@@ -55,7 +56,7 @@ class Test:
        def add_error(self, error_message: str) -> None:
                """Records an error that occurred while parsing this test."""
                self.counts.errors += 1
-               print_with_timestamp(red('[ERROR]') + f' Test: {self.name}: {error_message}')
+               stdout.print_with_timestamp(stdout.red('[ERROR]') + f' Test: {self.name}: {error_message}')
 
 class TestStatus(Enum):
        """An enumeration class to represent the status of a test."""
@@ -461,32 +462,6 @@ def parse_diagnostic(lines: LineStream) -> List[str]:
 
 DIVIDER = '=' * 60
 
-RESET = '\033[0;0m'
-
-def red(text: str) -> str:
-       """Returns inputted string with red color code."""
-       if not sys.stdout.isatty():
-               return text
-       return '\033[1;31m' + text + RESET
-
-def yellow(text: str) -> str:
-       """Returns inputted string with yellow color code."""
-       if not sys.stdout.isatty():
-               return text
-       return '\033[1;33m' + text + RESET
-
-def green(text: str) -> str:
-       """Returns inputted string with green color code."""
-       if not sys.stdout.isatty():
-               return text
-       return '\033[1;32m' + text + RESET
-
-ANSI_LEN = len(red(''))
-
-def print_with_timestamp(message: str) -> None:
-       """Prints message with timestamp at beginning."""
-       print('[%s] %s' % (datetime.datetime.now().strftime('%H:%M:%S'), message))
-
 def format_test_divider(message: str, len_message: int) -> str:
        """
        Returns string with message centered in fixed width divider.
@@ -529,12 +504,12 @@ def print_test_header(test: Test) -> None:
                        message += ' (1 subtest)'
                else:
                        message += f' ({test.expected_count} subtests)'
-       print_with_timestamp(format_test_divider(message, len(message)))
+       stdout.print_with_timestamp(format_test_divider(message, len(message)))
 
 def print_log(log: Iterable[str]) -> None:
        """Prints all strings in saved log for test in yellow."""
        for m in log:
-               print_with_timestamp(yellow(m))
+               stdout.print_with_timestamp(stdout.yellow(m))
 
 def format_test_result(test: Test) -> str:
        """
@@ -551,16 +526,16 @@ def format_test_result(test: Test) -> str:
        String containing formatted test result
        """
        if test.status == TestStatus.SUCCESS:
-               return green('[PASSED] ') + test.name
+               return stdout.green('[PASSED] ') + test.name
        if test.status == TestStatus.SKIPPED:
-               return yellow('[SKIPPED] ') + test.name
+               return stdout.yellow('[SKIPPED] ') + test.name
        if test.status == TestStatus.NO_TESTS:
-               return yellow('[NO TESTS RUN] ') + test.name
+               return stdout.yellow('[NO TESTS RUN] ') + test.name
        if test.status == TestStatus.TEST_CRASHED:
                print_log(test.log)
-               return red('[CRASHED] ') + test.name
+               return stdout.red('[CRASHED] ') + test.name
        print_log(test.log)
-       return red('[FAILED] ') + test.name
+       return stdout.red('[FAILED] ') + test.name
 
 def print_test_result(test: Test) -> None:
        """
@@ -572,7 +547,7 @@ def print_test_result(test: Test) -> None:
        Parameters:
        test - Test object representing current test being printed
        """
-       print_with_timestamp(format_test_result(test))
+       stdout.print_with_timestamp(format_test_result(test))
 
 def print_test_footer(test: Test) -> None:
        """
@@ -585,8 +560,8 @@ def print_test_footer(test: Test) -> None:
        test - Test object representing current test being printed
        """
        message = format_test_result(test)
-       print_with_timestamp(format_test_divider(message,
-               len(message) - ANSI_LEN))
+       stdout.print_with_timestamp(format_test_divider(message,
+               len(message) - stdout.color_len()))
 
 def print_summary_line(test: Test) -> None:
        """
@@ -603,12 +578,12 @@ def print_summary_line(test: Test) -> None:
        test - Test object representing current test being printed
        """
        if test.status == TestStatus.SUCCESS:
-               color = green
+               color = stdout.green
        elif test.status in (TestStatus.SKIPPED, TestStatus.NO_TESTS):
-               color = yellow
+               color = stdout.yellow
        else:
-               color = red
-       print_with_timestamp(color(f'Testing complete. {test.counts}'))
+               color = stdout.red
+       stdout.print_with_timestamp(color(f'Testing complete. {test.counts}'))
 
 # Other methods:
 
@@ -762,7 +737,7 @@ def parse_run_tests(kernel_output: Iterable[str]) -> Test:
        Return:
        Test - the main test object with all subtests.
        """
-       print_with_timestamp(DIVIDER)
+       stdout.print_with_timestamp(DIVIDER)
        lines = extract_tap_lines(kernel_output)
        test = Test()
        if not lines:
@@ -773,6 +748,6 @@ def parse_run_tests(kernel_output: Iterable[str]) -> Test:
                test = parse_test(lines, 0, [])
                if test.status != TestStatus.NO_TESTS:
                        test.status = test.counts.get_status()
-       print_with_timestamp(DIVIDER)
+       stdout.print_with_timestamp(DIVIDER)
        print_summary_line(test)
        return test
diff --git a/tools/testing/kunit/kunit_printer.py b/tools/testing/kunit/kunit_printer.py
new file mode 100644 (file)
index 0000000..5f1cc55
--- /dev/null
@@ -0,0 +1,48 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+#
+# Utilities for printing and coloring output.
+#
+# Copyright (C) 2022, Google LLC.
+# Author: Daniel Latypov <dlatypov@google.com>
+
+import datetime
+import sys
+import typing
+
+_RESET = '\033[0;0m'
+
+class Printer:
+       """Wraps a file object, providing utilities for coloring output, etc."""
+
+       def __init__(self, output: typing.IO):
+               self._output = output
+               self._use_color = output.isatty()
+
+       def print(self, message: str) -> None:
+               print(message, file=self._output)
+
+       def print_with_timestamp(self, message: str) -> None:
+               ts = datetime.datetime.now().strftime('%H:%M:%S')
+               self.print(f'[{ts}] {message}')
+
+       def _color(self, code: str, text: str) -> str:
+               if not self._use_color:
+                       return text
+               return code + text + _RESET
+
+       def red(self, text: str) -> str:
+               return self._color('\033[1;31m', text)
+
+       def yellow(self, text: str) -> str:
+               return self._color('\033[1;33m', text)
+
+       def green(self, text: str) -> str:
+               return self._color('\033[1;32m', text)
+
+       def color_len(self) -> int:
+               """Returns the length of the color escape codes."""
+               return len(self.red(''))
+
+# Provides a default instance that prints to stdout
+stdout = Printer(sys.stdout)
index 25a2eb3..446ac43 100755 (executable)
@@ -45,7 +45,7 @@ class KconfigTest(unittest.TestCase):
                self.assertTrue(kconfig0.is_subset_of(kconfig0))
 
                kconfig1 = kunit_config.Kconfig()
-               kconfig1.add_entry(kunit_config.KconfigEntry('TEST', 'y'))
+               kconfig1.add_entry('TEST', 'y')
                self.assertTrue(kconfig1.is_subset_of(kconfig1))
                self.assertTrue(kconfig0.is_subset_of(kconfig1))
                self.assertFalse(kconfig1.is_subset_of(kconfig0))
@@ -56,40 +56,28 @@ class KconfigTest(unittest.TestCase):
                kconfig = kunit_config.parse_file(kconfig_path)
 
                expected_kconfig = kunit_config.Kconfig()
-               expected_kconfig.add_entry(
-                       kunit_config.KconfigEntry('UML', 'y'))
-               expected_kconfig.add_entry(
-                       kunit_config.KconfigEntry('MMU', 'y'))
-               expected_kconfig.add_entry(
-                       kunit_config.KconfigEntry('TEST', 'y'))
-               expected_kconfig.add_entry(
-                       kunit_config.KconfigEntry('EXAMPLE_TEST', 'y'))
-               expected_kconfig.add_entry(
-                       kunit_config.KconfigEntry('MK8', 'n'))
-
-               self.assertEqual(kconfig.entries(), expected_kconfig.entries())
+               expected_kconfig.add_entry('UML', 'y')
+               expected_kconfig.add_entry('MMU', 'y')
+               expected_kconfig.add_entry('TEST', 'y')
+               expected_kconfig.add_entry('EXAMPLE_TEST', 'y')
+               expected_kconfig.add_entry('MK8', 'n')
+
+               self.assertEqual(kconfig, expected_kconfig)
 
        def test_write_to_file(self):
                kconfig_path = os.path.join(test_tmpdir, '.config')
 
                expected_kconfig = kunit_config.Kconfig()
-               expected_kconfig.add_entry(
-                       kunit_config.KconfigEntry('UML', 'y'))
-               expected_kconfig.add_entry(
-                       kunit_config.KconfigEntry('MMU', 'y'))
-               expected_kconfig.add_entry(
-                       kunit_config.KconfigEntry('TEST', 'y'))
-               expected_kconfig.add_entry(
-                       kunit_config.KconfigEntry('EXAMPLE_TEST', 'y'))
-               expected_kconfig.add_entry(
-                       kunit_config.KconfigEntry('MK8', 'n'))
+               expected_kconfig.add_entry('UML', 'y')
+               expected_kconfig.add_entry('MMU', 'y')
+               expected_kconfig.add_entry('TEST', 'y')
+               expected_kconfig.add_entry('EXAMPLE_TEST', 'y')
+               expected_kconfig.add_entry('MK8', 'n')
 
                expected_kconfig.write_to_file(kconfig_path)
 
                actual_kconfig = kunit_config.parse_file(kconfig_path)
-
-               self.assertEqual(actual_kconfig.entries(),
-                                expected_kconfig.entries())
+               self.assertEqual(actual_kconfig, expected_kconfig)
 
 class KUnitParserTest(unittest.TestCase):
 
@@ -222,7 +210,7 @@ class KUnitParserTest(unittest.TestCase):
 
        def test_no_kunit_output(self):
                crash_log = test_data_path('test_insufficient_memory.log')
-               print_mock = mock.patch('builtins.print').start()
+               print_mock = mock.patch('kunit_printer.Printer.print').start()
                with open(crash_log) as file:
                        result = kunit_parser.parse_run_tests(
                                kunit_parser.extract_tap_lines(file.readlines()))
@@ -368,21 +356,53 @@ class LinuxSourceTreeTest(unittest.TestCase):
 
        def test_invalid_kunitconfig(self):
                with self.assertRaisesRegex(kunit_kernel.ConfigError, 'nonexistent.* does not exist'):
-                       kunit_kernel.LinuxSourceTree('', kunitconfig_path='/nonexistent_file')
+                       kunit_kernel.LinuxSourceTree('', kunitconfig_paths=['/nonexistent_file'])
 
        def test_valid_kunitconfig(self):
                with tempfile.NamedTemporaryFile('wt') as kunitconfig:
-                       kunit_kernel.LinuxSourceTree('', kunitconfig_path=kunitconfig.name)
+                       kunit_kernel.LinuxSourceTree('', kunitconfig_paths=[kunitconfig.name])
 
        def test_dir_kunitconfig(self):
                with tempfile.TemporaryDirectory('') as dir:
                        with open(os.path.join(dir, '.kunitconfig'), 'w'):
                                pass
-                       kunit_kernel.LinuxSourceTree('', kunitconfig_path=dir)
+                       kunit_kernel.LinuxSourceTree('', kunitconfig_paths=[dir])
+
+       def test_multiple_kunitconfig(self):
+               want_kconfig = kunit_config.Kconfig()
+               want_kconfig.add_entry('KUNIT', 'y')
+               want_kconfig.add_entry('KUNIT_TEST', 'm')
+
+               with tempfile.TemporaryDirectory('') as dir:
+                       other = os.path.join(dir, 'otherkunitconfig')
+                       with open(os.path.join(dir, '.kunitconfig'), 'w') as f:
+                               f.write('CONFIG_KUNIT=y')
+                       with open(other, 'w') as f:
+                               f.write('CONFIG_KUNIT_TEST=m')
+                               pass
+
+                       tree = kunit_kernel.LinuxSourceTree('', kunitconfig_paths=[dir, other])
+                       self.assertTrue(want_kconfig.is_subset_of(tree._kconfig), msg=tree._kconfig)
+
+
+       def test_multiple_kunitconfig_invalid(self):
+               with tempfile.TemporaryDirectory('') as dir:
+                       other = os.path.join(dir, 'otherkunitconfig')
+                       with open(os.path.join(dir, '.kunitconfig'), 'w') as f:
+                               f.write('CONFIG_KUNIT=y')
+                       with open(other, 'w') as f:
+                               f.write('CONFIG_KUNIT=m')
+
+                       with self.assertRaisesRegex(kunit_kernel.ConfigError, '(?s)Multiple values.*CONFIG_KUNIT'):
+                               kunit_kernel.LinuxSourceTree('', kunitconfig_paths=[dir, other])
+
 
        def test_kconfig_add(self):
+               want_kconfig = kunit_config.Kconfig()
+               want_kconfig.add_entry('NOT_REAL', 'y')
+
                tree = kunit_kernel.LinuxSourceTree('', kconfig_add=['CONFIG_NOT_REAL=y'])
-               self.assertIn(kunit_config.KconfigEntry('NOT_REAL', 'y'), tree._kconfig.entries())
+               self.assertTrue(want_kconfig.is_subset_of(tree._kconfig), msg=tree._kconfig)
 
        def test_invalid_arch(self):
                with self.assertRaisesRegex(kunit_kernel.ConfigError, 'not a valid arch, options are.*x86_64'):
@@ -393,7 +413,7 @@ class LinuxSourceTreeTest(unittest.TestCase):
                        return subprocess.Popen(['echo "hi\nbye"'], shell=True, text=True, stdout=subprocess.PIPE)
 
                with tempfile.TemporaryDirectory('') as build_dir:
-                       tree = kunit_kernel.LinuxSourceTree(build_dir, load_config=False)
+                       tree = kunit_kernel.LinuxSourceTree(build_dir)
                        mock.patch.object(tree._ops, 'start', side_effect=fake_start).start()
 
                        with self.assertRaises(ValueError):
@@ -410,6 +430,10 @@ class LinuxSourceTreeTest(unittest.TestCase):
                                f.write('CONFIG_KUNIT=y')
 
                        tree = kunit_kernel.LinuxSourceTree(build_dir)
+                       # Stub out the source tree operations, so we don't have
+                       # the defaults for any given architecture get in the
+                       # way.
+                       tree._ops = kunit_kernel.LinuxSourceTreeOperations('none', None)
                        mock_build_config = mock.patch.object(tree, 'build_config').start()
 
                        # Should generate the .config
@@ -427,6 +451,10 @@ class LinuxSourceTreeTest(unittest.TestCase):
                                f.write('CONFIG_KUNIT=y\nCONFIG_KUNIT_TEST=y')
 
                        tree = kunit_kernel.LinuxSourceTree(build_dir)
+                       # Stub out the source tree operations, so we don't have
+                       # the defaults for any given architecture get in the
+                       # way.
+                       tree._ops = kunit_kernel.LinuxSourceTreeOperations('none', None)
                        mock_build_config = mock.patch.object(tree, 'build_config').start()
 
                        self.assertTrue(tree.build_reconfig(build_dir, make_options=[]))
@@ -443,6 +471,10 @@ class LinuxSourceTreeTest(unittest.TestCase):
                                f.write('CONFIG_KUNIT=y\nCONFIG_KUNIT_TEST=y')
 
                        tree = kunit_kernel.LinuxSourceTree(build_dir)
+                       # Stub out the source tree operations, so we don't have
+                       # the defaults for any given architecture get in the
+                       # way.
+                       tree._ops = kunit_kernel.LinuxSourceTreeOperations('none', None)
                        mock_build_config = mock.patch.object(tree, 'build_config').start()
 
                        # ... so we should trigger a call to build_config()
@@ -500,27 +532,28 @@ class KUnitMainTest(unittest.TestCase):
                with open(path) as file:
                        all_passed_log = file.readlines()
 
-               self.print_mock = mock.patch('builtins.print').start()
+               self.print_mock = mock.patch('kunit_printer.Printer.print').start()
                self.addCleanup(mock.patch.stopall)
 
-               self.linux_source_mock = mock.Mock()
-               self.linux_source_mock.build_reconfig = mock.Mock(return_value=True)
-               self.linux_source_mock.build_kernel = mock.Mock(return_value=True)
-               self.linux_source_mock.run_kernel = mock.Mock(return_value=all_passed_log)
+               self.mock_linux_init = mock.patch.object(kunit_kernel, 'LinuxSourceTree').start()
+               self.linux_source_mock = self.mock_linux_init.return_value
+               self.linux_source_mock.build_reconfig.return_value = True
+               self.linux_source_mock.build_kernel.return_value = True
+               self.linux_source_mock.run_kernel.return_value = all_passed_log
 
        def test_config_passes_args_pass(self):
-               kunit.main(['config', '--build_dir=.kunit'], self.linux_source_mock)
+               kunit.main(['config', '--build_dir=.kunit'])
                self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 1)
                self.assertEqual(self.linux_source_mock.run_kernel.call_count, 0)
 
        def test_build_passes_args_pass(self):
-               kunit.main(['build'], self.linux_source_mock)
+               kunit.main(['build'])
                self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 1)
                self.linux_source_mock.build_kernel.assert_called_once_with(False, kunit.get_default_jobs(), '.kunit', None)
                self.assertEqual(self.linux_source_mock.run_kernel.call_count, 0)
 
        def test_exec_passes_args_pass(self):
-               kunit.main(['exec'], self.linux_source_mock)
+               kunit.main(['exec'])
                self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 0)
                self.assertEqual(self.linux_source_mock.run_kernel.call_count, 1)
                self.linux_source_mock.run_kernel.assert_called_once_with(
@@ -528,7 +561,7 @@ class KUnitMainTest(unittest.TestCase):
                self.print_mock.assert_any_call(StrContains('Testing complete.'))
 
        def test_run_passes_args_pass(self):
-               kunit.main(['run'], self.linux_source_mock)
+               kunit.main(['run'])
                self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 1)
                self.assertEqual(self.linux_source_mock.run_kernel.call_count, 1)
                self.linux_source_mock.run_kernel.assert_called_once_with(
@@ -538,13 +571,13 @@ class KUnitMainTest(unittest.TestCase):
        def test_exec_passes_args_fail(self):
                self.linux_source_mock.run_kernel = mock.Mock(return_value=[])
                with self.assertRaises(SystemExit) as e:
-                       kunit.main(['exec'], self.linux_source_mock)
+                       kunit.main(['exec'])
                self.assertEqual(e.exception.code, 1)
 
        def test_run_passes_args_fail(self):
                self.linux_source_mock.run_kernel = mock.Mock(return_value=[])
                with self.assertRaises(SystemExit) as e:
-                       kunit.main(['run'], self.linux_source_mock)
+                       kunit.main(['run'])
                self.assertEqual(e.exception.code, 1)
                self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 1)
                self.assertEqual(self.linux_source_mock.run_kernel.call_count, 1)
@@ -553,7 +586,7 @@ class KUnitMainTest(unittest.TestCase):
        def test_exec_no_tests(self):
                self.linux_source_mock.run_kernel = mock.Mock(return_value=['TAP version 14', '1..0'])
                with self.assertRaises(SystemExit) as e:
-                       kunit.main(['run'], self.linux_source_mock)
+                       kunit.main(['run'])
                self.assertEqual(e.exception.code, 1)
                self.linux_source_mock.run_kernel.assert_called_once_with(
                        args=None, build_dir='.kunit', filter_glob='', timeout=300)
@@ -561,7 +594,7 @@ class KUnitMainTest(unittest.TestCase):
 
        def test_exec_raw_output(self):
                self.linux_source_mock.run_kernel = mock.Mock(return_value=[])
-               kunit.main(['exec', '--raw_output'], self.linux_source_mock)
+               kunit.main(['exec', '--raw_output'])
                self.assertEqual(self.linux_source_mock.run_kernel.call_count, 1)
                for call in self.print_mock.call_args_list:
                        self.assertNotEqual(call, mock.call(StrContains('Testing complete.')))
@@ -569,7 +602,7 @@ class KUnitMainTest(unittest.TestCase):
 
        def test_run_raw_output(self):
                self.linux_source_mock.run_kernel = mock.Mock(return_value=[])
-               kunit.main(['run', '--raw_output'], self.linux_source_mock)
+               kunit.main(['run', '--raw_output'])
                self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 1)
                self.assertEqual(self.linux_source_mock.run_kernel.call_count, 1)
                for call in self.print_mock.call_args_list:
@@ -578,7 +611,7 @@ class KUnitMainTest(unittest.TestCase):
 
        def test_run_raw_output_kunit(self):
                self.linux_source_mock.run_kernel = mock.Mock(return_value=[])
-               kunit.main(['run', '--raw_output=kunit'], self.linux_source_mock)
+               kunit.main(['run', '--raw_output=kunit'])
                self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 1)
                self.assertEqual(self.linux_source_mock.run_kernel.call_count, 1)
                for call in self.print_mock.call_args_list:
@@ -588,27 +621,27 @@ class KUnitMainTest(unittest.TestCase):
        def test_run_raw_output_invalid(self):
                self.linux_source_mock.run_kernel = mock.Mock(return_value=[])
                with self.assertRaises(SystemExit) as e:
-                       kunit.main(['run', '--raw_output=invalid'], self.linux_source_mock)
+                       kunit.main(['run', '--raw_output=invalid'])
                self.assertNotEqual(e.exception.code, 0)
 
        def test_run_raw_output_does_not_take_positional_args(self):
                # --raw_output is a string flag, but we don't want it to consume
                # any positional arguments, only ones after an '='
                self.linux_source_mock.run_kernel = mock.Mock(return_value=[])
-               kunit.main(['run', '--raw_output', 'filter_glob'], self.linux_source_mock)
+               kunit.main(['run', '--raw_output', 'filter_glob'])
                self.linux_source_mock.run_kernel.assert_called_once_with(
                        args=None, build_dir='.kunit', filter_glob='filter_glob', timeout=300)
 
        def test_exec_timeout(self):
                timeout = 3453
-               kunit.main(['exec', '--timeout', str(timeout)], self.linux_source_mock)
+               kunit.main(['exec', '--timeout', str(timeout)])
                self.linux_source_mock.run_kernel.assert_called_once_with(
                        args=None, build_dir='.kunit', filter_glob='', timeout=timeout)
                self.print_mock.assert_any_call(StrContains('Testing complete.'))
 
        def test_run_timeout(self):
                timeout = 3453
-               kunit.main(['run', '--timeout', str(timeout)], self.linux_source_mock)
+               kunit.main(['run', '--timeout', str(timeout)])
                self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 1)
                self.linux_source_mock.run_kernel.assert_called_once_with(
                        args=None, build_dir='.kunit', filter_glob='', timeout=timeout)
@@ -616,7 +649,7 @@ class KUnitMainTest(unittest.TestCase):
 
        def test_run_builddir(self):
                build_dir = '.kunit'
-               kunit.main(['run', '--build_dir=.kunit'], self.linux_source_mock)
+               kunit.main(['run', '--build_dir=.kunit'])
                self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 1)
                self.linux_source_mock.run_kernel.assert_called_once_with(
                        args=None, build_dir=build_dir, filter_glob='', timeout=300)
@@ -624,60 +657,81 @@ class KUnitMainTest(unittest.TestCase):
 
        def test_config_builddir(self):
                build_dir = '.kunit'
-               kunit.main(['config', '--build_dir', build_dir], self.linux_source_mock)
+               kunit.main(['config', '--build_dir', build_dir])
                self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 1)
 
        def test_build_builddir(self):
                build_dir = '.kunit'
                jobs = kunit.get_default_jobs()
-               kunit.main(['build', '--build_dir', build_dir], self.linux_source_mock)
+               kunit.main(['build', '--build_dir', build_dir])
                self.linux_source_mock.build_kernel.assert_called_once_with(False, jobs, build_dir, None)
 
        def test_exec_builddir(self):
                build_dir = '.kunit'
-               kunit.main(['exec', '--build_dir', build_dir], self.linux_source_mock)
+               kunit.main(['exec', '--build_dir', build_dir])
                self.linux_source_mock.run_kernel.assert_called_once_with(
                        args=None, build_dir=build_dir, filter_glob='', timeout=300)
                self.print_mock.assert_any_call(StrContains('Testing complete.'))
 
-       @mock.patch.object(kunit_kernel, 'LinuxSourceTree')
-       def test_run_kunitconfig(self, mock_linux_init):
-               mock_linux_init.return_value = self.linux_source_mock
+       def test_run_kunitconfig(self):
                kunit.main(['run', '--kunitconfig=mykunitconfig'])
                # Just verify that we parsed and initialized it correctly here.
-               mock_linux_init.assert_called_once_with('.kunit',
-                                                       kunitconfig_path='mykunitconfig',
-                                                       kconfig_add=None,
-                                                       arch='um',
-                                                       cross_compile=None,
-                                                       qemu_config_path=None)
+               self.mock_linux_init.assert_called_once_with('.kunit',
+                                               kunitconfig_paths=['mykunitconfig'],
+                                               kconfig_add=None,
+                                               arch='um',
+                                               cross_compile=None,
+                                               qemu_config_path=None,
+                                               extra_qemu_args=[])
+
+       def test_config_kunitconfig(self):
+               kunit.main(['config', '--kunitconfig=mykunitconfig'])
+               # Just verify that we parsed and initialized it correctly here.
+               self.mock_linux_init.assert_called_once_with('.kunit',
+                                               kunitconfig_paths=['mykunitconfig'],
+                                               kconfig_add=None,
+                                               arch='um',
+                                               cross_compile=None,
+                                               qemu_config_path=None,
+                                               extra_qemu_args=[])
 
        @mock.patch.object(kunit_kernel, 'LinuxSourceTree')
-       def test_config_kunitconfig(self, mock_linux_init):
+       def test_run_multiple_kunitconfig(self, mock_linux_init):
                mock_linux_init.return_value = self.linux_source_mock
-               kunit.main(['config', '--kunitconfig=mykunitconfig'])
+               kunit.main(['run', '--kunitconfig=mykunitconfig', '--kunitconfig=other'])
                # Just verify that we parsed and initialized it correctly here.
                mock_linux_init.assert_called_once_with('.kunit',
-                                                       kunitconfig_path='mykunitconfig',
+                                                       kunitconfig_paths=['mykunitconfig', 'other'],
                                                        kconfig_add=None,
                                                        arch='um',
                                                        cross_compile=None,
-                                                       qemu_config_path=None)
+                                                       qemu_config_path=None,
+                                                       extra_qemu_args=[])
 
-       @mock.patch.object(kunit_kernel, 'LinuxSourceTree')
-       def test_run_kconfig_add(self, mock_linux_init):
-               mock_linux_init.return_value = self.linux_source_mock
+       def test_run_kconfig_add(self):
                kunit.main(['run', '--kconfig_add=CONFIG_KASAN=y', '--kconfig_add=CONFIG_KCSAN=y'])
                # Just verify that we parsed and initialized it correctly here.
-               mock_linux_init.assert_called_once_with('.kunit',
-                                                       kunitconfig_path=None,
-                                                       kconfig_add=['CONFIG_KASAN=y', 'CONFIG_KCSAN=y'],
-                                                       arch='um',
-                                                       cross_compile=None,
-                                                       qemu_config_path=None)
+               self.mock_linux_init.assert_called_once_with('.kunit',
+                                               kunitconfig_paths=None,
+                                               kconfig_add=['CONFIG_KASAN=y', 'CONFIG_KCSAN=y'],
+                                               arch='um',
+                                               cross_compile=None,
+                                               qemu_config_path=None,
+                                               extra_qemu_args=[])
+
+       def test_run_qemu_args(self):
+               kunit.main(['run', '--arch=x86_64', '--qemu_args', '-m 2048'])
+               # Just verify that we parsed and initialized it correctly here.
+               self.mock_linux_init.assert_called_once_with('.kunit',
+                                               kunitconfig_paths=None,
+                                               kconfig_add=None,
+                                               arch='x86_64',
+                                               cross_compile=None,
+                                               qemu_config_path=None,
+                                               extra_qemu_args=['-m', '2048'])
 
        def test_run_kernel_args(self):
-               kunit.main(['run', '--kernel_args=a=1', '--kernel_args=b=2'], self.linux_source_mock)
+               kunit.main(['run', '--kernel_args=a=1', '--kernel_args=b=2'])
                self.assertEqual(self.linux_source_mock.build_reconfig.call_count, 1)
                self.linux_source_mock.run_kernel.assert_called_once_with(
                      args=['a=1','b=2'], build_dir='.kunit', filter_glob='', timeout=300)
@@ -699,7 +753,7 @@ class KUnitMainTest(unittest.TestCase):
        @mock.patch.object(kunit, '_list_tests')
        def test_run_isolated_by_suite(self, mock_tests):
                mock_tests.return_value = ['suite.test1', 'suite.test2', 'suite2.test1']
-               kunit.main(['exec', '--run_isolated=suite', 'suite*.test*'], self.linux_source_mock)
+               kunit.main(['exec', '--run_isolated=suite', 'suite*.test*'])
 
                # Should respect the user's filter glob when listing tests.
                mock_tests.assert_called_once_with(mock.ANY,
@@ -712,7 +766,7 @@ class KUnitMainTest(unittest.TestCase):
        @mock.patch.object(kunit, '_list_tests')
        def test_run_isolated_by_test(self, mock_tests):
                mock_tests.return_value = ['suite.test1', 'suite.test2', 'suite2.test1']
-               kunit.main(['exec', '--run_isolated=test', 'suite*'], self.linux_source_mock)
+               kunit.main(['exec', '--run_isolated=test', 'suite*'])
 
                # Should respect the user's filter glob when listing tests.
                mock_tests.assert_called_once_with(mock.ANY,
index de11992..5047d8e 100644 (file)
@@ -143,7 +143,6 @@ endif
 # Prepare for headers install
 include $(top_srcdir)/scripts/subarch.include
 ARCH           ?= $(SUBARCH)
-export KSFT_KHDR_INSTALL_DONE := 1
 export BUILD
 export KHDR_INCLUDES
 
@@ -151,30 +150,7 @@ export KHDR_INCLUDES
 # all isn't the first target in the file.
 .DEFAULT_GOAL := all
 
-# Install headers here once for all tests. KSFT_KHDR_INSTALL_DONE
-# is used to avoid running headers_install from lib.mk.
-# Invoke headers install with --no-builtin-rules to avoid circular
-# dependency in "make kselftest" case. In this case, second level
-# make inherits builtin-rules which will use the rule generate
-# Makefile.o and runs into
-# "Circular Makefile.o <- prepare dependency dropped."
-# and headers_install fails and test compile fails.
-#
-# O= KBUILD_OUTPUT cases don't run into this error, since main Makefile
-# invokes them as sub-makes and --no-builtin-rules is not necessary,
-# but doesn't cause any failures. Keep it simple and use the same
-# flags in both cases.
-# Local build cases: "make kselftest", "make -C" - headers are installed
-# in the default INSTALL_HDR_PATH usr/include.
-khdr:
-ifeq (1,$(DEFAULT_INSTALL_HDR_PATH))
-       $(MAKE) --no-builtin-rules ARCH=$(ARCH) -C $(top_srcdir) headers_install
-else
-       $(MAKE) --no-builtin-rules INSTALL_HDR_PATH=$(abs_objtree)/usr \
-               ARCH=$(ARCH) -C $(top_srcdir) headers_install
-endif
-
-all: khdr
+all:
        @ret=1;                                                 \
        for TARGET in $(TARGETS); do                            \
                BUILD_TARGET=$$BUILD/$$TARGET;                  \
@@ -253,7 +229,7 @@ ifdef INSTALL_PATH
        for TARGET in $(TARGETS); do \
                BUILD_TARGET=$$BUILD/$$TARGET;  \
                [ ! -d $(INSTALL_PATH)/$$TARGET ] && echo "Skipping non-existent dir: $$TARGET" && continue; \
-               echo -n "Emit Tests for $$TARGET\n"; \
+               echo -ne "Emit Tests for $$TARGET\n"; \
                $(MAKE) -s --no-print-directory OUTPUT=$$BUILD_TARGET COLLECTION=$$TARGET \
                        -C $$TARGET emit_tests >> $(TEST_LIST); \
        done;
@@ -274,4 +250,4 @@ clean:
                $(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET clean;\
        done;
 
-.PHONY: khdr all run_tests hotplug run_hotplug clean_hotplug run_pstore_crash install clean gen_tar
+.PHONY: all run_tests hotplug run_hotplug clean_hotplug run_pstore_crash install clean gen_tar
index 409e3e5..a5a0744 100644 (file)
@@ -22,7 +22,6 @@ ifeq ($(mte_cc_support),1)
 TEST_GEN_PROGS := $(PROGS)
 
 # Get Kernel headers installed and use them.
-KSFT_KHDR_INSTALL := 1
 else
     $(warning compiler "$(CC)" does not support the ARMv8.5 MTE extension.)
     $(warning test program "mte" will not be created.)
index ac4ad00..be7520a 100644 (file)
@@ -11,7 +11,6 @@ PROGS := $(patsubst %.c,%,$(SRCS))
 TEST_GEN_PROGS := $(notdir $(PROGS))
 
 # Get Kernel headers installed and use them.
-KSFT_KHDR_INSTALL := 1
 
 # Including KSFT lib.mk here will also mangle the TEST_GEN_PROGS list
 # to account for any OUTPUT target-dirs optionally provided by
index c70fdec..0c64583 100644 (file)
@@ -9,9 +9,7 @@
 #include <ucontext.h>
 
 /*
- * Using ARCH specific and sanitized Kernel headers installed by KSFT
- * framework since we asked for it by setting flag KSFT_KHDR_INSTALL
- * in our Makefile.
+ * Using ARCH specific and sanitized Kernel headers from the tree.
  */
 #include <asm/ptrace.h>
 #include <asm/hwcap.h>
index af293ea..e172d89 100644 (file)
@@ -4,6 +4,7 @@
  * Tests for sockmap/sockhash holding kTLS sockets.
  */
 
+#include <netinet/tcp.h>
 #include "test_progs.h"
 
 #define MAX_TEST_NAME 80
@@ -92,9 +93,78 @@ close_srv:
        close(srv);
 }
 
+static void test_sockmap_ktls_update_fails_when_sock_has_ulp(int family, int map)
+{
+       struct sockaddr_storage addr = {};
+       socklen_t len = sizeof(addr);
+       struct sockaddr_in6 *v6;
+       struct sockaddr_in *v4;
+       int err, s, zero = 0;
+
+       switch (family) {
+       case AF_INET:
+               v4 = (struct sockaddr_in *)&addr;
+               v4->sin_family = AF_INET;
+               break;
+       case AF_INET6:
+               v6 = (struct sockaddr_in6 *)&addr;
+               v6->sin6_family = AF_INET6;
+               break;
+       default:
+               PRINT_FAIL("unsupported socket family %d", family);
+               return;
+       }
+
+       s = socket(family, SOCK_STREAM, 0);
+       if (!ASSERT_GE(s, 0, "socket"))
+               return;
+
+       err = bind(s, (struct sockaddr *)&addr, len);
+       if (!ASSERT_OK(err, "bind"))
+               goto close;
+
+       err = getsockname(s, (struct sockaddr *)&addr, &len);
+       if (!ASSERT_OK(err, "getsockname"))
+               goto close;
+
+       err = connect(s, (struct sockaddr *)&addr, len);
+       if (!ASSERT_OK(err, "connect"))
+               goto close;
+
+       /* save sk->sk_prot and set it to tls_prots */
+       err = setsockopt(s, IPPROTO_TCP, TCP_ULP, "tls", strlen("tls"));
+       if (!ASSERT_OK(err, "setsockopt(TCP_ULP)"))
+               goto close;
+
+       /* sockmap update should not affect saved sk_prot */
+       err = bpf_map_update_elem(map, &zero, &s, BPF_ANY);
+       if (!ASSERT_ERR(err, "sockmap update elem"))
+               goto close;
+
+       /* call sk->sk_prot->setsockopt to dispatch to saved sk_prot */
+       err = setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &zero, sizeof(zero));
+       ASSERT_OK(err, "setsockopt(TCP_NODELAY)");
+
+close:
+       close(s);
+}
+
+static const char *fmt_test_name(const char *subtest_name, int family,
+                                enum bpf_map_type map_type)
+{
+       const char *map_type_str = BPF_MAP_TYPE_SOCKMAP ? "SOCKMAP" : "SOCKHASH";
+       const char *family_str = AF_INET ? "IPv4" : "IPv6";
+       static char test_name[MAX_TEST_NAME];
+
+       snprintf(test_name, MAX_TEST_NAME,
+                "sockmap_ktls %s %s %s",
+                subtest_name, family_str, map_type_str);
+
+       return test_name;
+}
+
 static void run_tests(int family, enum bpf_map_type map_type)
 {
-       char test_name[MAX_TEST_NAME];
        int map;
 
        map = bpf_map_create(map_type, NULL, sizeof(int), sizeof(int), 1, NULL);
@@ -103,14 +173,10 @@ static void run_tests(int family, enum bpf_map_type map_type)
                return;
        }
 
-       snprintf(test_name, MAX_TEST_NAME,
-                "sockmap_ktls disconnect_after_delete %s %s",
-                family == AF_INET ? "IPv4" : "IPv6",
-                map_type == BPF_MAP_TYPE_SOCKMAP ? "SOCKMAP" : "SOCKHASH");
-       if (!test__start_subtest(test_name))
-               return;
-
-       test_sockmap_ktls_disconnect_after_delete(family, map);
+       if (test__start_subtest(fmt_test_name("disconnect_after_delete", family, map_type)))
+               test_sockmap_ktls_disconnect_after_delete(family, map);
+       if (test__start_subtest(fmt_test_name("update_fails_when_sock_has_ulp", family, map_type)))
+               test_sockmap_ktls_update_fails_when_sock_has_ulp(family, map);
 
        close(map);
 }
index d811cff..0a26c24 100644 (file)
@@ -140,12 +140,12 @@ int use_after_invalid(void *ctx)
 
        bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(read_data), 0, &ptr);
 
-       bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0);
+       bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
 
        bpf_ringbuf_submit_dynptr(&ptr, 0);
 
        /* this should fail */
-       bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0);
+       bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
 
        return 0;
 }
@@ -338,7 +338,7 @@ int invalid_helper2(void *ctx)
        get_map_val_dynptr(&ptr);
 
        /* this should fail */
-       bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 8, 0);
+       bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 8, 0, 0);
 
        return 0;
 }
@@ -377,7 +377,7 @@ int invalid_write2(void *ctx)
        memcpy((void *)&ptr + 8, &x, sizeof(x));
 
        /* this should fail */
-       bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0);
+       bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
 
        bpf_ringbuf_submit_dynptr(&ptr, 0);
 
@@ -473,7 +473,7 @@ int invalid_read2(void *ctx)
        get_map_val_dynptr(&ptr);
 
        /* this should fail */
-       bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 1, 0);
+       bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 1, 0, 0);
 
        return 0;
 }
index d67be48..a3a6103 100644 (file)
@@ -43,10 +43,10 @@ int test_read_write(void *ctx)
        bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(write_data), 0, &ptr);
 
        /* Write data into the dynptr */
-       err = err ?: bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data));
+       err = bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0);
 
        /* Read the data that was written into the dynptr */
-       err = err ?: bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0);
+       err = err ?: bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
 
        /* Ensure the data we read matches the data we wrote */
        for (i = 0; i < sizeof(read_data); i++) {
index 6ddc418..1a27a62 100644 (file)
        .result = ACCEPT,
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
+{
+       "jeq32/jne32: bounds checking",
+       .insns = {
+       BPF_MOV64_IMM(BPF_REG_6, 563),
+       BPF_MOV64_IMM(BPF_REG_2, 0),
+       BPF_ALU64_IMM(BPF_NEG, BPF_REG_2, 0),
+       BPF_ALU64_IMM(BPF_NEG, BPF_REG_2, 0),
+       BPF_ALU32_REG(BPF_OR, BPF_REG_2, BPF_REG_6),
+       BPF_JMP32_IMM(BPF_JNE, BPF_REG_2, 8, 5),
+       BPF_JMP_IMM(BPF_JSGE, BPF_REG_2, 500, 2),
+       BPF_MOV64_IMM(BPF_REG_0, 2),
+       BPF_EXIT_INSN(),
+       BPF_MOV64_REG(BPF_REG_0, BPF_REG_4),
+       BPF_EXIT_INSN(),
+       BPF_MOV64_IMM(BPF_REG_0, 1),
+       BPF_EXIT_INSN(),
+       },
+       .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+       .result = ACCEPT,
+       .retval = 1,
+},
index 6f951d1..497fe17 100644 (file)
        .result = ACCEPT,
        .retval = 3,
 },
+{
+       "jump & dead code elimination",
+       .insns = {
+       BPF_MOV64_IMM(BPF_REG_0, 1),
+       BPF_MOV64_IMM(BPF_REG_3, 0),
+       BPF_ALU64_IMM(BPF_NEG, BPF_REG_3, 0),
+       BPF_ALU64_IMM(BPF_NEG, BPF_REG_3, 0),
+       BPF_ALU64_IMM(BPF_OR, BPF_REG_3, 32767),
+       BPF_JMP_IMM(BPF_JSGE, BPF_REG_3, 0, 1),
+       BPF_EXIT_INSN(),
+       BPF_JMP_IMM(BPF_JSLE, BPF_REG_3, 0x8000, 1),
+       BPF_EXIT_INSN(),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, -32767),
+       BPF_MOV64_IMM(BPF_REG_0, 2),
+       BPF_JMP_IMM(BPF_JLE, BPF_REG_3, 0, 1),
+       BPF_MOV64_REG(BPF_REG_0, BPF_REG_4),
+       BPF_EXIT_INSN(),
+       },
+       .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+       .result = ACCEPT,
+       .retval = 2,
+},
index 0189db8..0328ac0 100644 (file)
@@ -26,3 +26,13 @@ do
                exit 1
        fi
 done
+
+permission_error="Operation not permitted"
+for f in attrs target_ids monitor_on
+do
+       status=$( cat "$DBGFS/$f" 2>&1 )
+       if [ "${status#*$permission_error}" != "$status" ]; then
+               echo "Permission for reading $DBGFS/$f denied; maybe secureboot enabled?"
+               exit $ksft_skip
+       fi
+done
index de1c4e6..c812080 100644 (file)
@@ -32,7 +32,8 @@ int main(int argc, char *argv[])
 
        devfd = open("/dev/udmabuf", O_RDWR);
        if (devfd < 0) {
-               printf("%s: [skip,no-udmabuf]\n", TEST_PREFIX);
+               printf("%s: [skip,no-udmabuf: Unable to access DMA buffer device file]\n",
+                      TEST_PREFIX);
                exit(77);
        }
 
index b789dc8..09c76cd 100755 (executable)
@@ -3,7 +3,7 @@
 # Runs API tests for struct drm_mm (DRM range manager)
 
 if ! /sbin/modprobe -n -q test-drm_mm; then
-       echo "drivers/gpu/drm_mm: [skip]"
+       echo "drivers/gpu/drm_mm: module test-drm_mm is not found in /lib/modules/`uname -r` [skip]"
        exit 77
 fi
 
@@ -11,6 +11,6 @@ if /sbin/modprobe -q test-drm_mm; then
        /sbin/modprobe -q -r test-drm_mm
        echo "drivers/gpu/drm_mm: ok"
 else
-       echo "drivers/gpu/drm_mm: [FAIL]"
+       echo "drivers/gpu/drm_mm: module test-drm_mm could not be removed [FAIL]"
        exit 1
 fi
index 5e701d2..891215a 100644 (file)
@@ -11,7 +11,6 @@ else
 TEST_GEN_PROGS := test_uvdevice
 
 top_srcdir ?= ../../../../../..
-KSFT_KHDR_INSTALL := 1
 khdr_dir = $(top_srcdir)/usr/include
 LINUX_TOOL_ARCH_INCLUDE = $(top_srcdir)/tools/arch/$(ARCH)/include
 
index b8152c5..7321490 100644 (file)
@@ -22,7 +22,6 @@ TEST_GEN_FILES := \
 TEST_PROGS := run.sh
 
 top_srcdir = ../../../../..
-KSFT_KHDR_INSTALL := 1
 DEFAULT_INSTALL_HDR_PATH := 1
 include ../../lib.mk
 
index 71b3066..616ed40 100644 (file)
@@ -3,6 +3,6 @@
 TEST_PROGS := gpio-mockup.sh gpio-sim.sh
 TEST_FILES := gpio-mockup-sysfs.sh
 TEST_GEN_PROGS_EXTENDED := gpio-mockup-cdev gpio-chip-info gpio-line-name
-CFLAGS += -O2 -g -Wall -I../../../../usr/include/
+CFLAGS += -O2 -g -Wall -I../../../../usr/include/ $(KHDR_INCLUDES)
 
 include ../lib.mk
index 6ea7b9f..25110c7 100644 (file)
@@ -88,6 +88,9 @@ int main(int argc, char **argv)
                int pid2 = getpid();
                int ret;
 
+               ksft_print_header();
+               ksft_set_plan(3);
+
                fd2 = open(kpath, O_RDWR, 0644);
                if (fd2 < 0) {
                        perror("Can't open file");
@@ -152,7 +155,6 @@ int main(int argc, char **argv)
                        ksft_inc_pass_cnt();
                }
 
-               ksft_print_cnts();
 
                if (ret)
                        ksft_exit_fail();
@@ -162,5 +164,5 @@ int main(int argc, char **argv)
 
        waitpid(pid2, &status, P_ALL);
 
-       return ksft_exit_pass();
+       return 0;
 }
index 00e60d6..708cb54 100755 (executable)
@@ -26,7 +26,7 @@ echo "  main Makefile when optional -p is specified."
 echo "- Prints pass/fail dependency check for each tests/sub-test."
 echo "- Prints pass/fail targets and libraries."
 echo "- Default: runs dependency checks on all tests."
-echo "- Optional test name can be specified to check dependencies for it."
+echo "- Optional: test name can be specified to check dependencies for it."
 exit 1
 
 }
index e2ea41d..63cd748 100644 (file)
@@ -3,6 +3,7 @@
 #define __KSELFTEST_MODULE_H
 
 #include <linux/module.h>
+#include <linux/panic.h>
 
 /*
  * Test framework for writing test modules to be loaded by kselftest.
@@ -41,6 +42,7 @@ static inline int kstm_report(unsigned int total_tests, unsigned int failed_test
 static int __init __module##_init(void)                        \
 {                                                      \
        pr_info("loaded.\n");                           \
+       add_taint(TAINT_TEST, LOCKDEP_STILL_OK);        \
        selftest();                                     \
        return kstm_report(total_tests, failed_tests, skipped_tests);   \
 }                                                      \
@@ -51,4 +53,6 @@ static void __exit __module##_exit(void)              \
 module_init(__module##_init);                          \
 module_exit(__module##_exit)
 
+MODULE_INFO(test, "Y");
+
 #endif /* __KSELFTEST_MODULE_H */
index 22423c8..120951f 100644 (file)
@@ -4,7 +4,6 @@ include ../../../build/Build.include
 all:
 
 top_srcdir = ../../../..
-KSFT_KHDR_INSTALL := 1
 
 # For cross-builds to work, UNAME_M has to map to ARCH and arch specific
 # directories and targets in this Makefile. "uname -m" doesn't map to
index 4158da0..2237d1a 100644 (file)
@@ -82,8 +82,9 @@ static int next_cpu(int cpu)
        return cpu;
 }
 
-static void *migration_worker(void *ign)
+static void *migration_worker(void *__rseq_tid)
 {
+       pid_t rseq_tid = (pid_t)(unsigned long)__rseq_tid;
        cpu_set_t allowed_mask;
        int r, i, cpu;
 
@@ -106,7 +107,7 @@ static void *migration_worker(void *ign)
                 * stable, i.e. while changing affinity is in-progress.
                 */
                smp_wmb();
-               r = sched_setaffinity(0, sizeof(allowed_mask), &allowed_mask);
+               r = sched_setaffinity(rseq_tid, sizeof(allowed_mask), &allowed_mask);
                TEST_ASSERT(!r, "sched_setaffinity failed, errno = %d (%s)",
                            errno, strerror(errno));
                smp_wmb();
@@ -231,7 +232,8 @@ int main(int argc, char *argv[])
        vm = vm_create_default(VCPU_ID, 0, guest_code);
        ucall_init(vm, NULL);
 
-       pthread_create(&migration_thread, NULL, migration_worker, 0);
+       pthread_create(&migration_thread, NULL, migration_worker,
+                      (void *)(unsigned long)gettid());
 
        for (i = 0; !done; i++) {
                vcpu_run(vm, VCPU_ID);
index 0b0049e..a6959df 100644 (file)
@@ -8,17 +8,11 @@ TEST_GEN_PROGS := $(src_test:.c=)
 
 TEST_GEN_PROGS_EXTENDED := true
 
-KSFT_KHDR_INSTALL := 1
 OVERRIDE_TARGETS := 1
 include ../lib.mk
 
-khdr_dir = $(top_srcdir)/usr/include
-
-$(khdr_dir)/linux/landlock.h: khdr
-       @:
-
 $(OUTPUT)/true: true.c
        $(LINK.c) $< $(LDLIBS) -o $@ -static
 
-$(OUTPUT)/%_test: %_test.c $(khdr_dir)/linux/landlock.h ../kselftest_harness.h common.h
-       $(LINK.c) $< $(LDLIBS) -o $@ -lcap -I$(khdr_dir)
+$(OUTPUT)/%_test: %_test.c ../kselftest_harness.h common.h
+       $(LINK.c) $< $(LDLIBS) -o $@ -lcap
index 1a5cc3c..947fc72 100644 (file)
@@ -51,45 +51,7 @@ 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))
 
-ifdef KSFT_KHDR_INSTALL
-top_srcdir ?= ../../../..
-include $(top_srcdir)/scripts/subarch.include
-ARCH           ?= $(SUBARCH)
-
-# set default goal to all, so make without a target runs all, even when
-# all isn't the first target in the file.
-.DEFAULT_GOAL := all
-
-# Invoke headers install with --no-builtin-rules to avoid circular
-# dependency in "make kselftest" case. In this case, second level
-# make inherits builtin-rules which will use the rule generate
-# Makefile.o and runs into
-# "Circular Makefile.o <- prepare dependency dropped."
-# and headers_install fails and test compile fails.
-# O= KBUILD_OUTPUT cases don't run into this error, since main Makefile
-# invokes them as sub-makes and --no-builtin-rules is not necessary,
-# but doesn't cause any failures. Keep it simple and use the same
-# flags in both cases.
-# Note that the support to install headers from lib.mk is necessary
-# when test Makefile is run directly with "make -C".
-# When local build is done, headers are installed in the default
-# INSTALL_HDR_PATH usr/include.
-.PHONY: khdr
-.NOTPARALLEL:
-khdr:
-ifndef KSFT_KHDR_INSTALL_DONE
-ifeq (1,$(DEFAULT_INSTALL_HDR_PATH))
-       $(MAKE) --no-builtin-rules ARCH=$(ARCH) -C $(top_srcdir) headers_install
-else
-       $(MAKE) --no-builtin-rules INSTALL_HDR_PATH=$$OUTPUT/usr \
-               ARCH=$(ARCH) -C $(top_srcdir) headers_install
-endif
-endif
-
-all: khdr $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES)
-else
 all: $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES)
-endif
 
 define RUN_TESTS
        BASE_DIR="$(selfdir)";                  \
index a29f796..ffc35a2 100644 (file)
@@ -36,4 +36,5 @@ test_unix_oob
 gro
 ioam6_parser
 toeplitz
+tun
 cmsg_sender
index 7ea54af..d0460a9 100644 (file)
@@ -11,7 +11,7 @@ TEST_PROGS += udpgso_bench.sh fib_rule_tests.sh msg_zerocopy.sh psock_snd.sh
 TEST_PROGS += udpgro_bench.sh udpgro.sh test_vxlan_under_vrf.sh reuseport_addr_any.sh
 TEST_PROGS += test_vxlan_fdb_changelink.sh so_txtime.sh ipv6_flowlabel.sh
 TEST_PROGS += tcp_fastopen_backup_key.sh fcnal-test.sh l2tp.sh traceroute.sh
-TEST_PROGS += fin_ack_lat.sh fib_nexthop_multiprefix.sh fib_nexthops.sh
+TEST_PROGS += fin_ack_lat.sh fib_nexthop_multiprefix.sh fib_nexthops.sh fib_nexthop_nongw.sh
 TEST_PROGS += altnames.sh icmp.sh icmp_redirect.sh ip6_gre_headroom.sh
 TEST_PROGS += route_localnet.sh
 TEST_PROGS += reuseaddr_ports_exhausted.sh
@@ -54,15 +54,15 @@ TEST_GEN_FILES += ipsec
 TEST_GEN_FILES += ioam6_parser
 TEST_GEN_FILES += gro
 TEST_GEN_PROGS = reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa
-TEST_GEN_PROGS += reuseport_dualstack reuseaddr_conflict tls
+TEST_GEN_PROGS += reuseport_dualstack reuseaddr_conflict tls tun
 TEST_GEN_FILES += toeplitz
 TEST_GEN_FILES += cmsg_sender
 TEST_GEN_FILES += stress_reuseport_listen
 TEST_PROGS += test_vxlan_vnifiltering.sh
+TEST_GEN_FILES += io_uring_zerocopy_tx
 
 TEST_FILES := settings
 
-KSFT_KHDR_INSTALL := 1
 include ../lib.mk
 
 include bpf/Makefile
index 8a69c91..8ccaf87 100644 (file)
@@ -2,7 +2,7 @@
 
 CLANG ?= clang
 CCINCLUDE += -I../../bpf
-CCINCLUDE += -I../../../lib
+CCINCLUDE += -I../../../../lib
 CCINCLUDE += -I../../../../../usr/include/
 
 TEST_CUSTOM_PROGS = $(OUTPUT)/bpf/nat6to4.o
diff --git a/tools/testing/selftests/net/fib_nexthop_nongw.sh b/tools/testing/selftests/net/fib_nexthop_nongw.sh
new file mode 100755 (executable)
index 0000000..b7b928b
--- /dev/null
@@ -0,0 +1,119 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# ns: h1               | ns: h2
+#   192.168.0.1/24     |
+#            eth0      |
+#                      |       192.168.1.1/32
+#            veth0 <---|---> veth1
+# Validate source address selection for route without gateway
+
+PAUSE_ON_FAIL=no
+VERBOSE=0
+ret=0
+
+################################################################################
+# helpers
+
+log_test()
+{
+       local rc=$1
+       local expected=$2
+       local msg="$3"
+
+       if [ ${rc} -eq ${expected} ]; then
+               printf "TEST: %-60s  [ OK ]\n" "${msg}"
+               nsuccess=$((nsuccess+1))
+       else
+               ret=1
+               nfail=$((nfail+1))
+               printf "TEST: %-60s  [FAIL]\n" "${msg}"
+               if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
+                       echo
+                       echo "hit enter to continue, 'q' to quit"
+                       read a
+                       [ "$a" = "q" ] && exit 1
+               fi
+       fi
+
+       [ "$VERBOSE" = "1" ] && echo
+}
+
+run_cmd()
+{
+       local cmd="$*"
+       local out
+       local rc
+
+       if [ "$VERBOSE" = "1" ]; then
+               echo "COMMAND: $cmd"
+       fi
+
+       out=$(eval $cmd 2>&1)
+       rc=$?
+       if [ "$VERBOSE" = "1" -a -n "$out" ]; then
+               echo "$out"
+       fi
+
+       [ "$VERBOSE" = "1" ] && echo
+
+       return $rc
+}
+
+################################################################################
+# config
+setup()
+{
+       ip netns add h1
+       ip -n h1 link set lo up
+       ip netns add h2
+       ip -n h2 link set lo up
+
+       # Add a fake eth0 to support an ip address
+       ip -n h1 link add name eth0 type dummy
+       ip -n h1 link set eth0 up
+       ip -n h1 address add 192.168.0.1/24 dev eth0
+
+       # Configure veths (same @mac, arp off)
+       ip -n h1 link add name veth0 type veth peer name veth1 netns h2
+       ip -n h1 link set veth0 up
+
+       ip -n h2 link set veth1 up
+
+       # Configure @IP in the peer netns
+       ip -n h2 address add 192.168.1.1/32 dev veth1
+       ip -n h2 route add default dev veth1
+
+       # Add a nexthop without @gw and use it in a route
+       ip -n h1 nexthop add id 1 dev veth0
+       ip -n h1 route add 192.168.1.1 nhid 1
+}
+
+cleanup()
+{
+       ip netns del h1 2>/dev/null
+       ip netns del h2 2>/dev/null
+}
+
+trap cleanup EXIT
+
+################################################################################
+# main
+
+while getopts :pv o
+do
+       case $o in
+               p) PAUSE_ON_FAIL=yes;;
+               v) VERBOSE=1;;
+       esac
+done
+
+cleanup
+setup
+
+run_cmd ip -netns h1 route get 192.168.1.1
+log_test $? 0 "nexthop: get route with nexthop without gw"
+run_cmd ip netns exec h1 ping -c1 192.168.1.1
+log_test $? 0 "nexthop: ping through nexthop without gw"
+
+exit $ret
index 8f48121..57b84e0 100644 (file)
@@ -37,6 +37,7 @@ TEST_PROGS = bridge_igmp.sh \
        ipip_hier_gre_key.sh \
        ipip_hier_gre_keys.sh \
        ipip_hier_gre.sh \
+       local_termination.sh \
        loopback.sh \
        mirror_gre_bound.sh \
        mirror_gre_bridge_1d.sh \
@@ -52,6 +53,7 @@ TEST_PROGS = bridge_igmp.sh \
        mirror_gre_vlan_bridge_1q.sh \
        mirror_gre_vlan.sh \
        mirror_vlan.sh \
+       no_forwarding.sh \
        pedit_dsfield.sh \
        pedit_ip.sh \
        pedit_l4port.sh \
index 37ae49d..3ffb9d6 100755 (executable)
@@ -1240,6 +1240,7 @@ learning_test()
        # FDB entry was installed.
        bridge link set dev $br_port1 flood off
 
+       ip link set $host1_if promisc on
        tc qdisc add dev $host1_if ingress
        tc filter add dev $host1_if ingress protocol ip pref 1 handle 101 \
                flower dst_mac $mac action drop
@@ -1250,7 +1251,7 @@ learning_test()
        tc -j -s filter show dev $host1_if ingress \
                | jq -e ".[] | select(.options.handle == 101) \
                | select(.options.actions[0].stats.packets == 1)" &> /dev/null
-       check_fail $? "Packet reached second host when should not"
+       check_fail $? "Packet reached first host when should not"
 
        $MZ $host1_if -c 1 -p 64 -a $mac -t ip -q
        sleep 1
@@ -1289,6 +1290,7 @@ learning_test()
 
        tc filter del dev $host1_if ingress protocol ip pref 1 handle 101 flower
        tc qdisc del dev $host1_if ingress
+       ip link set $host1_if promisc off
 
        bridge link set dev $br_port1 flood on
 
@@ -1306,6 +1308,7 @@ flood_test_do()
 
        # Add an ACL on `host2_if` which will tell us whether the packet
        # was flooded to it or not.
+       ip link set $host2_if promisc on
        tc qdisc add dev $host2_if ingress
        tc filter add dev $host2_if ingress protocol ip pref 1 handle 101 \
                flower dst_mac $mac action drop
@@ -1323,6 +1326,7 @@ flood_test_do()
 
        tc filter del dev $host2_if ingress protocol ip pref 1 handle 101 flower
        tc qdisc del dev $host2_if ingress
+       ip link set $host2_if promisc off
 
        return $err
 }
diff --git a/tools/testing/selftests/net/io_uring_zerocopy_tx.c b/tools/testing/selftests/net/io_uring_zerocopy_tx.c
new file mode 100644 (file)
index 0000000..9d64c56
--- /dev/null
@@ -0,0 +1,605 @@
+/* SPDX-License-Identifier: MIT */
+/* based on linux-kernel/tools/testing/selftests/net/msg_zerocopy.c */
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+#include <linux/errqueue.h>
+#include <linux/if_packet.h>
+#include <linux/io_uring.h>
+#include <linux/ipv6.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+
+#define NOTIF_TAG 0xfffffffULL
+#define NONZC_TAG 0
+#define ZC_TAG 1
+
+enum {
+       MODE_NONZC      = 0,
+       MODE_ZC         = 1,
+       MODE_ZC_FIXED   = 2,
+       MODE_MIXED      = 3,
+};
+
+static bool cfg_flush          = false;
+static bool cfg_cork           = false;
+static int  cfg_mode           = MODE_ZC_FIXED;
+static int  cfg_nr_reqs                = 8;
+static int  cfg_family         = PF_UNSPEC;
+static int  cfg_payload_len;
+static int  cfg_port           = 8000;
+static int  cfg_runtime_ms     = 4200;
+
+static socklen_t cfg_alen;
+static struct sockaddr_storage cfg_dst_addr;
+
+static char payload[IP_MAXPACKET] __attribute__((aligned(4096)));
+
+struct io_sq_ring {
+       unsigned *head;
+       unsigned *tail;
+       unsigned *ring_mask;
+       unsigned *ring_entries;
+       unsigned *flags;
+       unsigned *array;
+};
+
+struct io_cq_ring {
+       unsigned *head;
+       unsigned *tail;
+       unsigned *ring_mask;
+       unsigned *ring_entries;
+       struct io_uring_cqe *cqes;
+};
+
+struct io_uring_sq {
+       unsigned *khead;
+       unsigned *ktail;
+       unsigned *kring_mask;
+       unsigned *kring_entries;
+       unsigned *kflags;
+       unsigned *kdropped;
+       unsigned *array;
+       struct io_uring_sqe *sqes;
+
+       unsigned sqe_head;
+       unsigned sqe_tail;
+
+       size_t ring_sz;
+};
+
+struct io_uring_cq {
+       unsigned *khead;
+       unsigned *ktail;
+       unsigned *kring_mask;
+       unsigned *kring_entries;
+       unsigned *koverflow;
+       struct io_uring_cqe *cqes;
+
+       size_t ring_sz;
+};
+
+struct io_uring {
+       struct io_uring_sq sq;
+       struct io_uring_cq cq;
+       int ring_fd;
+};
+
+#ifdef __alpha__
+# ifndef __NR_io_uring_setup
+#  define __NR_io_uring_setup          535
+# endif
+# ifndef __NR_io_uring_enter
+#  define __NR_io_uring_enter          536
+# endif
+# ifndef __NR_io_uring_register
+#  define __NR_io_uring_register       537
+# endif
+#else /* !__alpha__ */
+# ifndef __NR_io_uring_setup
+#  define __NR_io_uring_setup          425
+# endif
+# ifndef __NR_io_uring_enter
+#  define __NR_io_uring_enter          426
+# endif
+# ifndef __NR_io_uring_register
+#  define __NR_io_uring_register       427
+# endif
+#endif
+
+#if defined(__x86_64) || defined(__i386__)
+#define read_barrier() __asm__ __volatile__("":::"memory")
+#define write_barrier()        __asm__ __volatile__("":::"memory")
+#else
+
+#define read_barrier() __sync_synchronize()
+#define write_barrier()        __sync_synchronize()
+#endif
+
+static int io_uring_setup(unsigned int entries, struct io_uring_params *p)
+{
+       return syscall(__NR_io_uring_setup, entries, p);
+}
+
+static int io_uring_enter(int fd, unsigned int to_submit,
+                         unsigned int min_complete,
+                         unsigned int flags, sigset_t *sig)
+{
+       return syscall(__NR_io_uring_enter, fd, to_submit, min_complete,
+                       flags, sig, _NSIG / 8);
+}
+
+static int io_uring_register_buffers(struct io_uring *ring,
+                                    const struct iovec *iovecs,
+                                    unsigned nr_iovecs)
+{
+       int ret;
+
+       ret = syscall(__NR_io_uring_register, ring->ring_fd,
+                     IORING_REGISTER_BUFFERS, iovecs, nr_iovecs);
+       return (ret < 0) ? -errno : ret;
+}
+
+static int io_uring_register_notifications(struct io_uring *ring,
+                                          unsigned nr,
+                                          struct io_uring_notification_slot *slots)
+{
+       int ret;
+       struct io_uring_notification_register r = {
+               .nr_slots = nr,
+               .data = (unsigned long)slots,
+       };
+
+       ret = syscall(__NR_io_uring_register, ring->ring_fd,
+                     IORING_REGISTER_NOTIFIERS, &r, sizeof(r));
+       return (ret < 0) ? -errno : ret;
+}
+
+static int io_uring_mmap(int fd, struct io_uring_params *p,
+                        struct io_uring_sq *sq, struct io_uring_cq *cq)
+{
+       size_t size;
+       void *ptr;
+       int ret;
+
+       sq->ring_sz = p->sq_off.array + p->sq_entries * sizeof(unsigned);
+       ptr = mmap(0, sq->ring_sz, PROT_READ | PROT_WRITE,
+                  MAP_SHARED | MAP_POPULATE, fd, IORING_OFF_SQ_RING);
+       if (ptr == MAP_FAILED)
+               return -errno;
+       sq->khead = ptr + p->sq_off.head;
+       sq->ktail = ptr + p->sq_off.tail;
+       sq->kring_mask = ptr + p->sq_off.ring_mask;
+       sq->kring_entries = ptr + p->sq_off.ring_entries;
+       sq->kflags = ptr + p->sq_off.flags;
+       sq->kdropped = ptr + p->sq_off.dropped;
+       sq->array = ptr + p->sq_off.array;
+
+       size = p->sq_entries * sizeof(struct io_uring_sqe);
+       sq->sqes = mmap(0, size, PROT_READ | PROT_WRITE,
+                       MAP_SHARED | MAP_POPULATE, fd, IORING_OFF_SQES);
+       if (sq->sqes == MAP_FAILED) {
+               ret = -errno;
+err:
+               munmap(sq->khead, sq->ring_sz);
+               return ret;
+       }
+
+       cq->ring_sz = p->cq_off.cqes + p->cq_entries * sizeof(struct io_uring_cqe);
+       ptr = mmap(0, cq->ring_sz, PROT_READ | PROT_WRITE,
+                       MAP_SHARED | MAP_POPULATE, fd, IORING_OFF_CQ_RING);
+       if (ptr == MAP_FAILED) {
+               ret = -errno;
+               munmap(sq->sqes, p->sq_entries * sizeof(struct io_uring_sqe));
+               goto err;
+       }
+       cq->khead = ptr + p->cq_off.head;
+       cq->ktail = ptr + p->cq_off.tail;
+       cq->kring_mask = ptr + p->cq_off.ring_mask;
+       cq->kring_entries = ptr + p->cq_off.ring_entries;
+       cq->koverflow = ptr + p->cq_off.overflow;
+       cq->cqes = ptr + p->cq_off.cqes;
+       return 0;
+}
+
+static int io_uring_queue_init(unsigned entries, struct io_uring *ring,
+                              unsigned flags)
+{
+       struct io_uring_params p;
+       int fd, ret;
+
+       memset(ring, 0, sizeof(*ring));
+       memset(&p, 0, sizeof(p));
+       p.flags = flags;
+
+       fd = io_uring_setup(entries, &p);
+       if (fd < 0)
+               return fd;
+       ret = io_uring_mmap(fd, &p, &ring->sq, &ring->cq);
+       if (!ret)
+               ring->ring_fd = fd;
+       else
+               close(fd);
+       return ret;
+}
+
+static int io_uring_submit(struct io_uring *ring)
+{
+       struct io_uring_sq *sq = &ring->sq;
+       const unsigned mask = *sq->kring_mask;
+       unsigned ktail, submitted, to_submit;
+       int ret;
+
+       read_barrier();
+       if (*sq->khead != *sq->ktail) {
+               submitted = *sq->kring_entries;
+               goto submit;
+       }
+       if (sq->sqe_head == sq->sqe_tail)
+               return 0;
+
+       ktail = *sq->ktail;
+       to_submit = sq->sqe_tail - sq->sqe_head;
+       for (submitted = 0; submitted < to_submit; submitted++) {
+               read_barrier();
+               sq->array[ktail++ & mask] = sq->sqe_head++ & mask;
+       }
+       if (!submitted)
+               return 0;
+
+       if (*sq->ktail != ktail) {
+               write_barrier();
+               *sq->ktail = ktail;
+               write_barrier();
+       }
+submit:
+       ret = io_uring_enter(ring->ring_fd, submitted, 0,
+                               IORING_ENTER_GETEVENTS, NULL);
+       return ret < 0 ? -errno : ret;
+}
+
+static inline void io_uring_prep_send(struct io_uring_sqe *sqe, int sockfd,
+                                     const void *buf, size_t len, int flags)
+{
+       memset(sqe, 0, sizeof(*sqe));
+       sqe->opcode = (__u8) IORING_OP_SEND;
+       sqe->fd = sockfd;
+       sqe->addr = (unsigned long) buf;
+       sqe->len = len;
+       sqe->msg_flags = (__u32) flags;
+}
+
+static inline void io_uring_prep_sendzc(struct io_uring_sqe *sqe, int sockfd,
+                                       const void *buf, size_t len, int flags,
+                                       unsigned slot_idx, unsigned zc_flags)
+{
+       io_uring_prep_send(sqe, sockfd, buf, len, flags);
+       sqe->opcode = (__u8) IORING_OP_SENDZC_NOTIF;
+       sqe->notification_idx = slot_idx;
+       sqe->ioprio = zc_flags;
+}
+
+static struct io_uring_sqe *io_uring_get_sqe(struct io_uring *ring)
+{
+       struct io_uring_sq *sq = &ring->sq;
+
+       if (sq->sqe_tail + 1 - sq->sqe_head > *sq->kring_entries)
+               return NULL;
+       return &sq->sqes[sq->sqe_tail++ & *sq->kring_mask];
+}
+
+static int io_uring_wait_cqe(struct io_uring *ring, struct io_uring_cqe **cqe_ptr)
+{
+       struct io_uring_cq *cq = &ring->cq;
+       const unsigned mask = *cq->kring_mask;
+       unsigned head = *cq->khead;
+       int ret;
+
+       *cqe_ptr = NULL;
+       do {
+               read_barrier();
+               if (head != *cq->ktail) {
+                       *cqe_ptr = &cq->cqes[head & mask];
+                       break;
+               }
+               ret = io_uring_enter(ring->ring_fd, 0, 1,
+                                       IORING_ENTER_GETEVENTS, NULL);
+               if (ret < 0)
+                       return -errno;
+       } while (1);
+
+       return 0;
+}
+
+static inline void io_uring_cqe_seen(struct io_uring *ring)
+{
+       *(&ring->cq)->khead += 1;
+       write_barrier();
+}
+
+static unsigned long gettimeofday_ms(void)
+{
+       struct timeval tv;
+
+       gettimeofday(&tv, NULL);
+       return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
+}
+
+static void do_setsockopt(int fd, int level, int optname, int val)
+{
+       if (setsockopt(fd, level, optname, &val, sizeof(val)))
+               error(1, errno, "setsockopt %d.%d: %d", level, optname, val);
+}
+
+static int do_setup_tx(int domain, int type, int protocol)
+{
+       int fd;
+
+       fd = socket(domain, type, protocol);
+       if (fd == -1)
+               error(1, errno, "socket t");
+
+       do_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, 1 << 21);
+
+       if (connect(fd, (void *) &cfg_dst_addr, cfg_alen))
+               error(1, errno, "connect");
+       return fd;
+}
+
+static void do_tx(int domain, int type, int protocol)
+{
+       struct io_uring_notification_slot b[1] = {{.tag = NOTIF_TAG}};
+       struct io_uring_sqe *sqe;
+       struct io_uring_cqe *cqe;
+       unsigned long packets = 0, bytes = 0;
+       struct io_uring ring;
+       struct iovec iov;
+       uint64_t tstop;
+       int i, fd, ret;
+       int compl_cqes = 0;
+
+       fd = do_setup_tx(domain, type, protocol);
+
+       ret = io_uring_queue_init(512, &ring, 0);
+       if (ret)
+               error(1, ret, "io_uring: queue init");
+
+       ret = io_uring_register_notifications(&ring, 1, b);
+       if (ret)
+               error(1, ret, "io_uring: tx ctx registration");
+
+       iov.iov_base = payload;
+       iov.iov_len = cfg_payload_len;
+
+       ret = io_uring_register_buffers(&ring, &iov, 1);
+       if (ret)
+               error(1, ret, "io_uring: buffer registration");
+
+       tstop = gettimeofday_ms() + cfg_runtime_ms;
+       do {
+               if (cfg_cork)
+                       do_setsockopt(fd, IPPROTO_UDP, UDP_CORK, 1);
+
+               for (i = 0; i < cfg_nr_reqs; i++) {
+                       unsigned zc_flags = 0;
+                       unsigned buf_idx = 0;
+                       unsigned slot_idx = 0;
+                       unsigned mode = cfg_mode;
+                       unsigned msg_flags = 0;
+
+                       if (cfg_mode == MODE_MIXED)
+                               mode = rand() % 3;
+
+                       sqe = io_uring_get_sqe(&ring);
+
+                       if (mode == MODE_NONZC) {
+                               io_uring_prep_send(sqe, fd, payload,
+                                                  cfg_payload_len, msg_flags);
+                               sqe->user_data = NONZC_TAG;
+                       } else {
+                               if (cfg_flush) {
+                                       zc_flags |= IORING_RECVSEND_NOTIF_FLUSH;
+                                       compl_cqes++;
+                               }
+                               io_uring_prep_sendzc(sqe, fd, payload,
+                                                    cfg_payload_len,
+                                                    msg_flags, slot_idx, zc_flags);
+                               if (mode == MODE_ZC_FIXED) {
+                                       sqe->ioprio |= IORING_RECVSEND_FIXED_BUF;
+                                       sqe->buf_index = buf_idx;
+                               }
+                               sqe->user_data = ZC_TAG;
+                       }
+               }
+
+               ret = io_uring_submit(&ring);
+               if (ret != cfg_nr_reqs)
+                       error(1, ret, "submit");
+
+               for (i = 0; i < cfg_nr_reqs; i++) {
+                       ret = io_uring_wait_cqe(&ring, &cqe);
+                       if (ret)
+                               error(1, ret, "wait cqe");
+
+                       if (cqe->user_data == NOTIF_TAG) {
+                               compl_cqes--;
+                               i--;
+                       } else if (cqe->user_data != NONZC_TAG &&
+                                  cqe->user_data != ZC_TAG) {
+                               error(1, cqe->res, "invalid user_data");
+                       } else if (cqe->res <= 0 && cqe->res != -EAGAIN) {
+                               error(1, cqe->res, "send failed");
+                       } else {
+                               if (cqe->res > 0) {
+                                       packets++;
+                                       bytes += cqe->res;
+                               }
+                               /* failed requests don't flush */
+                               if (cfg_flush &&
+                                   cqe->res <= 0 &&
+                                   cqe->user_data == ZC_TAG)
+                                       compl_cqes--;
+                       }
+                       io_uring_cqe_seen(&ring);
+               }
+               if (cfg_cork)
+                       do_setsockopt(fd, IPPROTO_UDP, UDP_CORK, 0);
+       } while (gettimeofday_ms() < tstop);
+
+       if (close(fd))
+               error(1, errno, "close");
+
+       fprintf(stderr, "tx=%lu (MB=%lu), tx/s=%lu (MB/s=%lu)\n",
+                       packets, bytes >> 20,
+                       packets / (cfg_runtime_ms / 1000),
+                       (bytes >> 20) / (cfg_runtime_ms / 1000));
+
+       while (compl_cqes) {
+               ret = io_uring_wait_cqe(&ring, &cqe);
+               if (ret)
+                       error(1, ret, "wait cqe");
+               io_uring_cqe_seen(&ring);
+               compl_cqes--;
+       }
+}
+
+static void do_test(int domain, int type, int protocol)
+{
+       int i;
+
+       for (i = 0; i < IP_MAXPACKET; i++)
+               payload[i] = 'a' + (i % 26);
+       do_tx(domain, type, protocol);
+}
+
+static void usage(const char *filepath)
+{
+       error(1, 0, "Usage: %s [-f] [-n<N>] [-z0] [-s<payload size>] "
+                   "(-4|-6) [-t<time s>] -D<dst_ip> udp", filepath);
+}
+
+static void parse_opts(int argc, char **argv)
+{
+       const int max_payload_len = sizeof(payload) -
+                                   sizeof(struct ipv6hdr) -
+                                   sizeof(struct tcphdr) -
+                                   40 /* max tcp options */;
+       struct sockaddr_in6 *addr6 = (void *) &cfg_dst_addr;
+       struct sockaddr_in *addr4 = (void *) &cfg_dst_addr;
+       char *daddr = NULL;
+       int c;
+
+       if (argc <= 1)
+               usage(argv[0]);
+       cfg_payload_len = max_payload_len;
+
+       while ((c = getopt(argc, argv, "46D:p:s:t:n:fc:m:")) != -1) {
+               switch (c) {
+               case '4':
+                       if (cfg_family != PF_UNSPEC)
+                               error(1, 0, "Pass one of -4 or -6");
+                       cfg_family = PF_INET;
+                       cfg_alen = sizeof(struct sockaddr_in);
+                       break;
+               case '6':
+                       if (cfg_family != PF_UNSPEC)
+                               error(1, 0, "Pass one of -4 or -6");
+                       cfg_family = PF_INET6;
+                       cfg_alen = sizeof(struct sockaddr_in6);
+                       break;
+               case 'D':
+                       daddr = optarg;
+                       break;
+               case 'p':
+                       cfg_port = strtoul(optarg, NULL, 0);
+                       break;
+               case 's':
+                       cfg_payload_len = strtoul(optarg, NULL, 0);
+                       break;
+               case 't':
+                       cfg_runtime_ms = 200 + strtoul(optarg, NULL, 10) * 1000;
+                       break;
+               case 'n':
+                       cfg_nr_reqs = strtoul(optarg, NULL, 0);
+                       break;
+               case 'f':
+                       cfg_flush = 1;
+                       break;
+               case 'c':
+                       cfg_cork = strtol(optarg, NULL, 0);
+                       break;
+               case 'm':
+                       cfg_mode = strtol(optarg, NULL, 0);
+                       break;
+               }
+       }
+
+       switch (cfg_family) {
+       case PF_INET:
+               memset(addr4, 0, sizeof(*addr4));
+               addr4->sin_family = AF_INET;
+               addr4->sin_port = htons(cfg_port);
+               if (daddr &&
+                   inet_pton(AF_INET, daddr, &(addr4->sin_addr)) != 1)
+                       error(1, 0, "ipv4 parse error: %s", daddr);
+               break;
+       case PF_INET6:
+               memset(addr6, 0, sizeof(*addr6));
+               addr6->sin6_family = AF_INET6;
+               addr6->sin6_port = htons(cfg_port);
+               if (daddr &&
+                   inet_pton(AF_INET6, daddr, &(addr6->sin6_addr)) != 1)
+                       error(1, 0, "ipv6 parse error: %s", daddr);
+               break;
+       default:
+               error(1, 0, "illegal domain");
+       }
+
+       if (cfg_payload_len > max_payload_len)
+               error(1, 0, "-s: payload exceeds max (%d)", max_payload_len);
+       if (cfg_mode == MODE_NONZC && cfg_flush)
+               error(1, 0, "-f: only zerocopy modes support notifications");
+       if (optind != argc - 1)
+               usage(argv[0]);
+}
+
+int main(int argc, char **argv)
+{
+       const char *cfg_test = argv[argc - 1];
+
+       parse_opts(argc, argv);
+
+       if (!strcmp(cfg_test, "tcp"))
+               do_test(cfg_family, SOCK_STREAM, 0);
+       else if (!strcmp(cfg_test, "udp"))
+               do_test(cfg_family, SOCK_DGRAM, 0);
+       else
+               error(1, 0, "unknown cfg_test %s", cfg_test);
+       return 0;
+}
diff --git a/tools/testing/selftests/net/io_uring_zerocopy_tx.sh b/tools/testing/selftests/net/io_uring_zerocopy_tx.sh
new file mode 100755 (executable)
index 0000000..6a65e44
--- /dev/null
@@ -0,0 +1,131 @@
+#!/bin/bash
+#
+# Send data between two processes across namespaces
+# Run twice: once without and once with zerocopy
+
+set -e
+
+readonly DEV="veth0"
+readonly DEV_MTU=65535
+readonly BIN_TX="./io_uring_zerocopy_tx"
+readonly BIN_RX="./msg_zerocopy"
+
+readonly RAND="$(mktemp -u XXXXXX)"
+readonly NSPREFIX="ns-${RAND}"
+readonly NS1="${NSPREFIX}1"
+readonly NS2="${NSPREFIX}2"
+
+readonly SADDR4='192.168.1.1'
+readonly DADDR4='192.168.1.2'
+readonly SADDR6='fd::1'
+readonly DADDR6='fd::2'
+
+readonly path_sysctl_mem="net.core.optmem_max"
+
+# No arguments: automated test
+if [[ "$#" -eq "0" ]]; then
+       IPs=( "4" "6" )
+       protocols=( "tcp" "udp" )
+
+       for IP in "${IPs[@]}"; do
+               for proto in "${protocols[@]}"; do
+                       for mode in $(seq 1 3); do
+                               $0 "$IP" "$proto" -m "$mode" -t 1 -n 32
+                               $0 "$IP" "$proto" -m "$mode" -t 1 -n 32 -f
+                               $0 "$IP" "$proto" -m "$mode" -t 1 -n 32 -c -f
+                       done
+               done
+       done
+
+       echo "OK. All tests passed"
+       exit 0
+fi
+
+# Argument parsing
+if [[ "$#" -lt "2" ]]; then
+       echo "Usage: $0 [4|6] [tcp|udp|raw|raw_hdrincl|packet|packet_dgram] <args>"
+       exit 1
+fi
+
+readonly IP="$1"
+shift
+readonly TXMODE="$1"
+shift
+readonly EXTRA_ARGS="$@"
+
+# Argument parsing: configure addresses
+if [[ "${IP}" == "4" ]]; then
+       readonly SADDR="${SADDR4}"
+       readonly DADDR="${DADDR4}"
+elif [[ "${IP}" == "6" ]]; then
+       readonly SADDR="${SADDR6}"
+       readonly DADDR="${DADDR6}"
+else
+       echo "Invalid IP version ${IP}"
+       exit 1
+fi
+
+# Argument parsing: select receive mode
+#
+# This differs from send mode for
+# - packet:    use raw recv, because packet receives skb clones
+# - raw_hdrinc: use raw recv, because hdrincl is a tx-only option
+case "${TXMODE}" in
+'packet' | 'packet_dgram' | 'raw_hdrincl')
+       RXMODE='raw'
+       ;;
+*)
+       RXMODE="${TXMODE}"
+       ;;
+esac
+
+# Start of state changes: install cleanup handler
+save_sysctl_mem="$(sysctl -n ${path_sysctl_mem})"
+
+cleanup() {
+       ip netns del "${NS2}"
+       ip netns del "${NS1}"
+       sysctl -w -q "${path_sysctl_mem}=${save_sysctl_mem}"
+}
+
+trap cleanup EXIT
+
+# Configure system settings
+sysctl -w -q "${path_sysctl_mem}=1000000"
+
+# Create virtual ethernet pair between network namespaces
+ip netns add "${NS1}"
+ip netns add "${NS2}"
+
+ip link add "${DEV}" mtu "${DEV_MTU}" netns "${NS1}" type veth \
+  peer name "${DEV}" mtu "${DEV_MTU}" netns "${NS2}"
+
+# Bring the devices up
+ip -netns "${NS1}" link set "${DEV}" up
+ip -netns "${NS2}" link set "${DEV}" up
+
+# Set fixed MAC addresses on the devices
+ip -netns "${NS1}" link set dev "${DEV}" address 02:02:02:02:02:02
+ip -netns "${NS2}" link set dev "${DEV}" address 06:06:06:06:06:06
+
+# Add fixed IP addresses to the devices
+ip -netns "${NS1}" addr add 192.168.1.1/24 dev "${DEV}"
+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
+
+# Optionally disable sg or csum offload to test edge cases
+# ip netns exec "${NS1}" ethtool -K "${DEV}" sg off
+
+do_test() {
+       local readonly ARGS="$1"
+
+       echo "ipv${IP} ${TXMODE} ${ARGS}"
+       ip netns exec "${NS2}" "${BIN_RX}" "-${IP}" -t 2 -C 2 -S "${SADDR}" -D "${DADDR}" -r "${RXMODE}" &
+       sleep 0.2
+       ip netns exec "${NS1}" "${BIN_TX}" "-${IP}" -t 1 -D "${DADDR}" ${ARGS} "${TXMODE}"
+       wait
+}
+
+do_test "${EXTRA_ARGS}"
+echo ok
index f905d53..43a7236 100644 (file)
@@ -1,12 +1,11 @@
 # SPDX-License-Identifier: GPL-2.0
 
 top_srcdir = ../../../../..
-KSFT_KHDR_INSTALL := 1
 
 CFLAGS =  -Wall -Wl,--no-as-needed -O2 -g -I$(top_srcdir)/usr/include $(KHDR_INCLUDES)
 
 TEST_PROGS := mptcp_connect.sh pm_netlink.sh mptcp_join.sh diag.sh \
-             simult_flows.sh mptcp_sockopt.sh
+             simult_flows.sh mptcp_sockopt.sh userspace_pm.sh
 
 TEST_GEN_FILES = mptcp_connect pm_nl_ctl mptcp_sockopt mptcp_inq
 
index 9dd43d7..515859a 100755 (executable)
@@ -61,6 +61,39 @@ chk_msk_nr()
        __chk_nr "grep -c token:" $*
 }
 
+wait_msk_nr()
+{
+       local condition="grep -c token:"
+       local expected=$1
+       local timeout=20
+       local msg nr
+       local max=0
+       local i=0
+
+       shift 1
+       msg=$*
+
+       while [ $i -lt $timeout ]; do
+               nr=$(ss -inmHMN $ns | $condition)
+               [ $nr == $expected ] && break;
+               [ $nr -gt $max ] && max=$nr
+               i=$((i + 1))
+               sleep 1
+       done
+
+       printf "%-50s" "$msg"
+       if [ $i -ge $timeout ]; then
+               echo "[ fail ] timeout while expecting $expected max $max last $nr"
+               ret=$test_cnt
+       elif [ $nr != $expected ]; then
+               echo "[ fail ] expected $expected found $nr"
+               ret=$test_cnt
+       else
+               echo "[  ok  ]"
+       fi
+       test_cnt=$((test_cnt+1))
+}
+
 chk_msk_fallback_nr()
 {
                __chk_nr "grep -c fallback" $*
@@ -146,7 +179,7 @@ ip -n $ns link set dev lo up
 echo "a" | \
        timeout ${timeout_test} \
                ip netns exec $ns \
-                       ./mptcp_connect -p 10000 -l -t ${timeout_poll} \
+                       ./mptcp_connect -p 10000 -l -t ${timeout_poll} -w 20 \
                                0.0.0.0 >/dev/null &
 wait_local_port_listen $ns 10000
 chk_msk_nr 0 "no msk on netns creation"
@@ -155,7 +188,7 @@ chk_msk_listen 10000
 echo "b" | \
        timeout ${timeout_test} \
                ip netns exec $ns \
-                       ./mptcp_connect -p 10000 -r 0 -t ${timeout_poll} \
+                       ./mptcp_connect -p 10000 -r 0 -t ${timeout_poll} -w 20 \
                                127.0.0.1 >/dev/null &
 wait_connected $ns 10000
 chk_msk_nr 2 "after MPC handshake "
@@ -167,13 +200,13 @@ flush_pids
 echo "a" | \
        timeout ${timeout_test} \
                ip netns exec $ns \
-                       ./mptcp_connect -p 10001 -l -s TCP -t ${timeout_poll} \
+                       ./mptcp_connect -p 10001 -l -s TCP -t ${timeout_poll} -w 20 \
                                0.0.0.0 >/dev/null &
 wait_local_port_listen $ns 10001
 echo "b" | \
        timeout ${timeout_test} \
                ip netns exec $ns \
-                       ./mptcp_connect -p 10001 -r 0 -t ${timeout_poll} \
+                       ./mptcp_connect -p 10001 -r 0 -t ${timeout_poll} -w 20 \
                                127.0.0.1 >/dev/null &
 wait_connected $ns 10001
 chk_msk_fallback_nr 1 "check fallback"
@@ -184,7 +217,7 @@ for I in `seq 1 $NR_CLIENTS`; do
        echo "a" | \
                timeout ${timeout_test} \
                        ip netns exec $ns \
-                               ./mptcp_connect -p $((I+10001)) -l -w 10 \
+                               ./mptcp_connect -p $((I+10001)) -l -w 20 \
                                        -t ${timeout_poll} 0.0.0.0 >/dev/null &
 done
 wait_local_port_listen $ns $((NR_CLIENTS + 10001))
@@ -193,12 +226,11 @@ for I in `seq 1 $NR_CLIENTS`; do
        echo "b" | \
                timeout ${timeout_test} \
                        ip netns exec $ns \
-                               ./mptcp_connect -p $((I+10001)) -w 10 \
+                               ./mptcp_connect -p $((I+10001)) -w 20 \
                                        -t ${timeout_poll} 127.0.0.1 >/dev/null &
 done
-sleep 1.5
 
-chk_msk_nr $((NR_CLIENTS*2)) "many msk socket present"
+wait_msk_nr $((NR_CLIENTS*2)) "many msk socket present"
 flush_pids
 
 exit $ret
index 8628aa6..e2ea6c1 100644 (file)
@@ -265,7 +265,7 @@ static void sock_test_tcpulp(int sock, int proto, unsigned int line)
 static int sock_listen_mptcp(const char * const listenaddr,
                             const char * const port)
 {
-       int sock;
+       int sock = -1;
        struct addrinfo hints = {
                .ai_protocol = IPPROTO_TCP,
                .ai_socktype = SOCK_STREAM,
index 29f75e2..8672d89 100644 (file)
@@ -88,7 +88,7 @@ static void xgetaddrinfo(const char *node, const char *service,
 static int sock_listen_mptcp(const char * const listenaddr,
                             const char * const port)
 {
-       int sock;
+       int sock = -1;
        struct addrinfo hints = {
                .ai_protocol = IPPROTO_TCP,
                .ai_socktype = SOCK_STREAM,
index ac9a4d9..ae61f39 100644 (file)
@@ -136,7 +136,7 @@ static void xgetaddrinfo(const char *node, const char *service,
 static int sock_listen_mptcp(const char * const listenaddr,
                             const char * const port)
 {
-       int sock;
+       int sock = -1;
        struct addrinfo hints = {
                .ai_protocol = IPPROTO_TCP,
                .ai_socktype = SOCK_STREAM,
index 6a2f4b9..cb79f07 100644 (file)
@@ -39,7 +39,7 @@ static void syntax(char *argv[])
        fprintf(stderr, "\tdsf lip <local-ip> lport <local-port> rip <remote-ip> rport <remote-port> token <token>\n");
        fprintf(stderr, "\tdel <id> [<ip>]\n");
        fprintf(stderr, "\tget <id>\n");
-       fprintf(stderr, "\tset [<ip>] [id <nr>] flags [no]backup|[no]fullmesh [port <nr>]\n");
+       fprintf(stderr, "\tset [<ip>] [id <nr>] flags [no]backup|[no]fullmesh [port <nr>] [token <token>] [rip <ip>] [rport <port>]\n");
        fprintf(stderr, "\tflush\n");
        fprintf(stderr, "\tdump\n");
        fprintf(stderr, "\tlimits [<rcv addr max> <subflow max>]\n");
@@ -1279,7 +1279,10 @@ int set_flags(int fd, int pm_family, int argc, char *argv[])
        struct rtattr *rta, *nest;
        struct nlmsghdr *nh;
        u_int32_t flags = 0;
+       u_int32_t token = 0;
+       u_int16_t rport = 0;
        u_int16_t family;
+       void *rip = NULL;
        int nest_start;
        int use_id = 0;
        u_int8_t id;
@@ -1339,7 +1342,13 @@ int set_flags(int fd, int pm_family, int argc, char *argv[])
                error(1, 0, " missing flags keyword");
 
        for (; arg < argc; arg++) {
-               if (!strcmp(argv[arg], "flags")) {
+               if (!strcmp(argv[arg], "token")) {
+                       if (++arg >= argc)
+                               error(1, 0, " missing token value");
+
+                       /* token */
+                       token = atoi(argv[arg]);
+               } else if (!strcmp(argv[arg], "flags")) {
                        char *tok, *str;
 
                        /* flags */
@@ -1378,12 +1387,72 @@ int set_flags(int fd, int pm_family, int argc, char *argv[])
                        rta->rta_len = RTA_LENGTH(2);
                        memcpy(RTA_DATA(rta), &port, 2);
                        off += NLMSG_ALIGN(rta->rta_len);
+               } else if (!strcmp(argv[arg], "rport")) {
+                       if (++arg >= argc)
+                               error(1, 0, " missing remote port");
+
+                       rport = atoi(argv[arg]);
+               } else if (!strcmp(argv[arg], "rip")) {
+                       if (++arg >= argc)
+                               error(1, 0, " missing remote ip");
+
+                       rip = argv[arg];
                } else {
                        error(1, 0, "unknown keyword %s", argv[arg]);
                }
        }
        nest->rta_len = off - nest_start;
 
+       /* token */
+       if (token) {
+               rta = (void *)(data + off);
+               rta->rta_type = MPTCP_PM_ATTR_TOKEN;
+               rta->rta_len = RTA_LENGTH(4);
+               memcpy(RTA_DATA(rta), &token, 4);
+               off += NLMSG_ALIGN(rta->rta_len);
+       }
+
+       /* remote addr/port */
+       if (rip) {
+               nest_start = off;
+               nest = (void *)(data + off);
+               nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR_REMOTE;
+               nest->rta_len = RTA_LENGTH(0);
+               off += NLMSG_ALIGN(nest->rta_len);
+
+               /* addr data */
+               rta = (void *)(data + off);
+               if (inet_pton(AF_INET, rip, RTA_DATA(rta))) {
+                       family = AF_INET;
+                       rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4;
+                       rta->rta_len = RTA_LENGTH(4);
+               } else if (inet_pton(AF_INET6, rip, RTA_DATA(rta))) {
+                       family = AF_INET6;
+                       rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6;
+                       rta->rta_len = RTA_LENGTH(16);
+               } else {
+                       error(1, errno, "can't parse ip %s", (char *)rip);
+               }
+               off += NLMSG_ALIGN(rta->rta_len);
+
+               /* family */
+               rta = (void *)(data + off);
+               rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY;
+               rta->rta_len = RTA_LENGTH(2);
+               memcpy(RTA_DATA(rta), &family, 2);
+               off += NLMSG_ALIGN(rta->rta_len);
+
+               if (rport) {
+                       rta = (void *)(data + off);
+                       rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT;
+                       rta->rta_len = RTA_LENGTH(2);
+                       memcpy(RTA_DATA(rta), &rport, 2);
+                       off += NLMSG_ALIGN(rta->rta_len);
+               }
+
+               nest->rta_len = off - nest_start;
+       }
+
        do_nl_req(fd, nh, off, 0);
        return 0;
 }
index 78d0bb6..abe3d4e 100755 (executable)
@@ -770,10 +770,42 @@ test_subflows()
        rm -f "$evts"
 }
 
+test_prio()
+{
+       local count
+
+       # Send MP_PRIO signal from client to server machine
+       ip netns exec "$ns2" ./pm_nl_ctl set 10.0.1.2 port "$client4_port" flags backup token "$client4_token" rip 10.0.1.1 rport "$server4_port"
+       sleep 0.5
+
+       # Check TX
+       stdbuf -o0 -e0 printf "MP_PRIO TX                                                 \t"
+       count=$(ip netns exec "$ns2" nstat -as | grep MPTcpExtMPPrioTx | awk '{print $2}')
+       [ -z "$count" ] && count=0
+       if [ $count != 1 ]; then
+               stdbuf -o0 -e0 printf "[FAIL]\n"
+               exit 1
+       else
+               stdbuf -o0 -e0 printf "[OK]\n"
+       fi
+
+       # Check RX
+       stdbuf -o0 -e0 printf "MP_PRIO RX                                                 \t"
+       count=$(ip netns exec "$ns1" nstat -as | grep MPTcpExtMPPrioRx | awk '{print $2}')
+       [ -z "$count" ] && count=0
+       if [ $count != 1 ]; then
+               stdbuf -o0 -e0 printf "[FAIL]\n"
+               exit 1
+       else
+               stdbuf -o0 -e0 printf "[OK]\n"
+       fi
+}
+
 make_connection
 make_connection "v6"
 test_announce
 test_remove
 test_subflows
+test_prio
 
 exit 0
diff --git a/tools/testing/selftests/net/tun.c b/tools/testing/selftests/net/tun.c
new file mode 100644 (file)
index 0000000..fa83918
--- /dev/null
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include "../kselftest_harness.h"
+
+static int tun_attach(int fd, char *dev)
+{
+       struct ifreq ifr;
+
+       memset(&ifr, 0, sizeof(ifr));
+       strcpy(ifr.ifr_name, dev);
+       ifr.ifr_flags = IFF_ATTACH_QUEUE;
+
+       return ioctl(fd, TUNSETQUEUE, (void *) &ifr);
+}
+
+static int tun_detach(int fd, char *dev)
+{
+       struct ifreq ifr;
+
+       memset(&ifr, 0, sizeof(ifr));
+       strcpy(ifr.ifr_name, dev);
+       ifr.ifr_flags = IFF_DETACH_QUEUE;
+
+       return ioctl(fd, TUNSETQUEUE, (void *) &ifr);
+}
+
+static int tun_alloc(char *dev)
+{
+       struct ifreq ifr;
+       int fd, err;
+
+       fd = open("/dev/net/tun", O_RDWR);
+       if (fd < 0) {
+               fprintf(stderr, "can't open tun: %s\n", strerror(errno));
+               return fd;
+       }
+
+       memset(&ifr, 0, sizeof(ifr));
+       strcpy(ifr.ifr_name, dev);
+       ifr.ifr_flags = IFF_TAP | IFF_NAPI | IFF_MULTI_QUEUE;
+
+       err = ioctl(fd, TUNSETIFF, (void *) &ifr);
+       if (err < 0) {
+               fprintf(stderr, "can't TUNSETIFF: %s\n", strerror(errno));
+               close(fd);
+               return err;
+       }
+       strcpy(dev, ifr.ifr_name);
+       return fd;
+}
+
+static int tun_delete(char *dev)
+{
+       struct {
+               struct nlmsghdr  nh;
+               struct ifinfomsg ifm;
+               unsigned char    data[64];
+       } req;
+       struct rtattr *rta;
+       int ret, rtnl;
+
+       rtnl = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+       if (rtnl < 0) {
+               fprintf(stderr, "can't open rtnl: %s\n", strerror(errno));
+               return 1;
+       }
+
+       memset(&req, 0, sizeof(req));
+       req.nh.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.ifm)));
+       req.nh.nlmsg_flags = NLM_F_REQUEST;
+       req.nh.nlmsg_type = RTM_DELLINK;
+
+       req.ifm.ifi_family = AF_UNSPEC;
+
+       rta = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.nh.nlmsg_len));
+       rta->rta_type = IFLA_IFNAME;
+       rta->rta_len = RTA_LENGTH(IFNAMSIZ);
+       req.nh.nlmsg_len += rta->rta_len;
+       memcpy(RTA_DATA(rta), dev, IFNAMSIZ);
+
+       ret = send(rtnl, &req, req.nh.nlmsg_len, 0);
+       if (ret < 0)
+               fprintf(stderr, "can't send: %s\n", strerror(errno));
+       ret = (unsigned int)ret != req.nh.nlmsg_len;
+
+       close(rtnl);
+       return ret;
+}
+
+FIXTURE(tun)
+{
+       char ifname[IFNAMSIZ];
+       int fd, fd2;
+};
+
+FIXTURE_SETUP(tun)
+{
+       memset(self->ifname, 0, sizeof(self->ifname));
+
+       self->fd = tun_alloc(self->ifname);
+       ASSERT_GE(self->fd, 0);
+
+       self->fd2 = tun_alloc(self->ifname);
+       ASSERT_GE(self->fd2, 0);
+}
+
+FIXTURE_TEARDOWN(tun)
+{
+       if (self->fd >= 0)
+               close(self->fd);
+       if (self->fd2 >= 0)
+               close(self->fd2);
+}
+
+TEST_F(tun, delete_detach_close) {
+       EXPECT_EQ(tun_delete(self->ifname), 0);
+       EXPECT_EQ(tun_detach(self->fd, self->ifname), -1);
+       EXPECT_EQ(errno, 22);
+}
+
+TEST_F(tun, detach_delete_close) {
+       EXPECT_EQ(tun_detach(self->fd, self->ifname), 0);
+       EXPECT_EQ(tun_delete(self->ifname), 0);
+}
+
+TEST_F(tun, detach_close_delete) {
+       EXPECT_EQ(tun_detach(self->fd, self->ifname), 0);
+       close(self->fd);
+       self->fd = -1;
+       EXPECT_EQ(tun_delete(self->ifname), 0);
+}
+
+TEST_F(tun, reattach_delete_close) {
+       EXPECT_EQ(tun_detach(self->fd, self->ifname), 0);
+       EXPECT_EQ(tun_attach(self->fd, self->ifname), 0);
+       EXPECT_EQ(tun_delete(self->ifname), 0);
+}
+
+TEST_F(tun, reattach_close_delete) {
+       EXPECT_EQ(tun_detach(self->fd, self->ifname), 0);
+       EXPECT_EQ(tun_attach(self->fd, self->ifname), 0);
+       close(self->fd);
+       self->fd = -1;
+       EXPECT_EQ(tun_delete(self->ifname), 0);
+}
+
+TEST_HARNESS_MAIN
index f8a19f5..ebbd0b2 100755 (executable)
@@ -34,7 +34,7 @@ cfg_veth() {
        ip -netns "${PEER_NS}" addr add dev veth1 192.168.1.1/24
        ip -netns "${PEER_NS}" addr add dev veth1 2001:db8::1/64 nodad
        ip -netns "${PEER_NS}" link set dev veth1 up
-       ip -n "${PEER_NS}" link set veth1 xdp object ../bpf/xdp_dummy.o section xdp_dummy
+       ip -n "${PEER_NS}" link set veth1 xdp object ../bpf/xdp_dummy.o section xdp
 }
 
 run_one() {
index 820bc50..fad2d1a 100755 (executable)
@@ -34,7 +34,7 @@ run_one() {
        ip -netns "${PEER_NS}" addr add dev veth1 2001:db8::1/64 nodad
        ip -netns "${PEER_NS}" link set dev veth1 up
 
-       ip -n "${PEER_NS}" link set veth1 xdp object ../bpf/xdp_dummy.o section xdp_dummy
+       ip -n "${PEER_NS}" link set veth1 xdp object ../bpf/xdp_dummy.o section xdp
        ip netns exec "${PEER_NS}" ./udpgso_bench_rx ${rx_args} -r &
        ip netns exec "${PEER_NS}" ./udpgso_bench_rx -t ${rx_args} -r &
 
index 807b74c..832c738 100755 (executable)
@@ -36,7 +36,7 @@ run_one() {
        ip netns exec "${PEER_NS}" ethtool -K veth1 rx-gro-list on
 
 
-       ip -n "${PEER_NS}" link set veth1 xdp object ../bpf/xdp_dummy.o section xdp_dummy
+       ip -n "${PEER_NS}" link set veth1 xdp object ../bpf/xdp_dummy.o section xdp
        tc -n "${PEER_NS}" qdisc add dev veth1 clsact
        tc -n "${PEER_NS}" filter add dev veth1 ingress prio 4 protocol ipv6 bpf object-file ../bpf/nat6to4.o section schedcls/ingress6/nat_6  direct-action
        tc -n "${PEER_NS}" filter add dev veth1 egress prio 4 protocol ip bpf object-file ../bpf/nat6to4.o section schedcls/egress4/snat4 direct-action
index 6f05e06..1bcd82e 100755 (executable)
@@ -46,7 +46,7 @@ create_ns() {
                ip -n $BASE$ns addr add dev veth$ns $BM_NET_V4$ns/24
                ip -n $BASE$ns addr add dev veth$ns $BM_NET_V6$ns/64 nodad
        done
-       ip -n $NS_DST link set veth$DST xdp object ../bpf/xdp_dummy.o section xdp_dummy 2>/dev/null
+       ip -n $NS_DST link set veth$DST xdp object ../bpf/xdp_dummy.o section xdp 2>/dev/null
 }
 
 create_vxlan_endpoint() {
index 80b5d35..dc932fd 100755 (executable)
@@ -120,7 +120,7 @@ run_all() {
        run_udp "${ipv4_args}"
 
        echo "ipv6"
-       run_tcp "${ipv4_args}"
+       run_tcp "${ipv6_args}"
        run_udp "${ipv6_args}"
 }
 
index 19eac3e..430895d 100755 (executable)
@@ -289,14 +289,14 @@ if [ $CPUS -gt 1 ]; then
        ip netns exec $NS_SRC ethtool -L veth$SRC rx 1 tx 2 2>/dev/null
        printf "%-60s" "bad setting: XDP with RX nr less than TX"
        ip -n $NS_DST link set dev veth$DST xdp object ../bpf/xdp_dummy.o \
-               section xdp_dummy 2>/dev/null &&\
+               section xdp 2>/dev/null &&\
                echo "fail - set operation successful ?!?" || echo " ok "
 
        # the following tests will run with multiple channels active
        ip netns exec $NS_SRC ethtool -L veth$SRC rx 2
        ip netns exec $NS_DST ethtool -L veth$DST rx 2
        ip -n $NS_DST link set dev veth$DST xdp object ../bpf/xdp_dummy.o \
-               section xdp_dummy 2>/dev/null
+               section xdp 2>/dev/null
        printf "%-60s" "bad setting: reducing RX nr below peer TX with XDP set"
        ip netns exec $NS_DST ethtool -L veth$DST rx 1 2>/dev/null &&\
                echo "fail - set operation successful ?!?" || echo " ok "
@@ -311,7 +311,7 @@ if [ $CPUS -gt 2 ]; then
        chk_channels "setting invalid channels nr" $DST 2 2
 fi
 
-ip -n $NS_DST link set dev veth$DST xdp object ../bpf/xdp_dummy.o section xdp_dummy 2>/dev/null
+ip -n $NS_DST link set dev veth$DST xdp object ../bpf/xdp_dummy.o section xdp 2>/dev/null
 chk_gro_flag "with xdp attached - gro flag" $DST on
 chk_gro_flag "        - peer gro flag" $SRC off
 chk_tso_flag "        - tso flag" $SRC off
index f17000a..ed0ec7f 100755 (executable)
@@ -35,7 +35,7 @@ then
        exit 1
 fi
 
-# Remember where we started so that we can get back and the end.
+# Remember where we started so that we can get back at the end.
 curcommit="`git status | head -1 | awk '{ print $NF }'`"
 
 nfail=0
@@ -73,15 +73,10 @@ do
                # Test the specified commit.
                git checkout $i > $resdir/$ds/$idir/git-checkout.out 2>&1
                echo git checkout return code: $? "(Commit $ntry: $i)"
-               kvm.sh --allcpus --duration 3 --trust-make > $resdir/$ds/$idir/kvm.sh.out 2>&1
+               kvm.sh --allcpus --duration 3 --trust-make --datestamp "$ds/$idir" > $resdir/$ds/$idir/kvm.sh.out 2>&1
                ret=$?
                echo kvm.sh return code $ret for commit $i from branch $gitbr
-
-               # Move the build products to their resting place.
-               runresdir="`grep -m 1 '^Results directory:' < $resdir/$ds/$idir/kvm.sh.out | sed -e 's/^Results directory://'`"
-               mv $runresdir $resdir/$ds/$idir
-               rrd="`echo $runresdir | sed -e 's,^.*/,,'`"
-               echo Run results: $resdir/$ds/$idir/$rrd
+               echo Run results: $resdir/$ds/$idir
                if test "$ret" -ne 0
                then
                        # Failure, so leave all evidence intact.
index 0ff59bd..9f0a5d5 100755 (executable)
@@ -262,6 +262,7 @@ echo All batches started. `date` | tee -a "$oldrun/remote-log"
 # Wait for all remaining scenarios to complete and collect results.
 for i in $systems
 do
+       echo " ---" Waiting for $i `date` | tee -a "$oldrun/remote-log"
        while checkremotefile "$i" "$resdir/$ds/remote.run"
        do
                sleep 30
index 263e16a..6c73481 100755 (executable)
@@ -164,7 +164,7 @@ do
                shift
                ;;
        --gdb)
-               TORTURE_KCONFIG_GDB_ARG="CONFIG_DEBUG_INFO=y"; export TORTURE_KCONFIG_GDB_ARG
+               TORTURE_KCONFIG_GDB_ARG="CONFIG_DEBUG_INFO_NONE=n CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y"; export TORTURE_KCONFIG_GDB_ARG
                TORTURE_BOOT_GDB_ARG="nokaslr"; export TORTURE_BOOT_GDB_ARG
                TORTURE_QEMU_GDB_ARG="-s -S"; export TORTURE_QEMU_GDB_ARG
                ;;
@@ -180,7 +180,7 @@ do
                shift
                ;;
        --kasan)
-               TORTURE_KCONFIG_KASAN_ARG="CONFIG_DEBUG_INFO=y CONFIG_KASAN=y"; export TORTURE_KCONFIG_KASAN_ARG
+               TORTURE_KCONFIG_KASAN_ARG="CONFIG_DEBUG_INFO_NONE=n CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y CONFIG_KASAN=y"; export TORTURE_KCONFIG_KASAN_ARG
                if test -n "$torture_qemu_mem_default"
                then
                        TORTURE_QEMU_MEM=2G
@@ -192,7 +192,7 @@ do
                shift
                ;;
        --kcsan)
-               TORTURE_KCONFIG_KCSAN_ARG="CONFIG_DEBUG_INFO=y CONFIG_KCSAN=y CONFIG_KCSAN_STRICT=y CONFIG_KCSAN_REPORT_ONCE_IN_MS=100000 CONFIG_KCSAN_VERBOSE=y CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=y"; export TORTURE_KCONFIG_KCSAN_ARG
+               TORTURE_KCONFIG_KCSAN_ARG="CONFIG_DEBUG_INFO_NONE=n CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y CONFIG_KCSAN=y CONFIG_KCSAN_STRICT=y CONFIG_KCSAN_REPORT_ONCE_IN_MS=100000 CONFIG_KCSAN_VERBOSE=y CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=y"; export TORTURE_KCONFIG_KCSAN_ARG
                ;;
        --kmake-arg|--kmake-args)
                checkarg --kmake-arg "(kernel make arguments)" $# "$2" '.*' '^error$'
index b86642f..3a391c9 100644 (file)
@@ -86,7 +86,7 @@ do {                                                                  \
 
 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs)               \
        RSEQ_INJECT_ASM(1)                                              \
-       "la     "RSEQ_ASM_TMP_REG_1 ", " __rseq_str(cs_label) "\n"      \
+       "la     " RSEQ_ASM_TMP_REG_1 ", " __rseq_str(cs_label) "\n"     \
        REG_S   RSEQ_ASM_TMP_REG_1 ", %[" __rseq_str(rseq_cs) "]\n"     \
        __rseq_str(label) ":\n"
 
@@ -103,17 +103,17 @@ do {                                                                      \
 
 #define RSEQ_ASM_OP_CMPEQ(var, expect, label)                          \
        REG_L   RSEQ_ASM_TMP_REG_1 ", %[" __rseq_str(var) "]\n"         \
-       "bne    "RSEQ_ASM_TMP_REG_1 ", %[" __rseq_str(expect) "] ,"     \
+       "bne    " RSEQ_ASM_TMP_REG_1 ", %[" __rseq_str(expect) "] ,"    \
                  __rseq_str(label) "\n"
 
 #define RSEQ_ASM_OP_CMPEQ32(var, expect, label)                                \
-       "lw     "RSEQ_ASM_TMP_REG_1 ", %[" __rseq_str(var) "]\n"        \
-       "bne    "RSEQ_ASM_TMP_REG_1 ", %[" __rseq_str(expect) "] ,"     \
+       "lw     " RSEQ_ASM_TMP_REG_1 ", %[" __rseq_str(var) "]\n"       \
+       "bne    " RSEQ_ASM_TMP_REG_1 ", %[" __rseq_str(expect) "] ,"    \
                  __rseq_str(label) "\n"
 
 #define RSEQ_ASM_OP_CMPNE(var, expect, label)                          \
        REG_L   RSEQ_ASM_TMP_REG_1 ", %[" __rseq_str(var) "]\n"         \
-       "beq    "RSEQ_ASM_TMP_REG_1 ", %[" __rseq_str(expect) "] ,"     \
+       "beq    " RSEQ_ASM_TMP_REG_1 ", %[" __rseq_str(expect) "] ,"    \
                  __rseq_str(label) "\n"
 
 #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label)             \
@@ -127,12 +127,12 @@ do {                                                                      \
        REG_S   RSEQ_ASM_TMP_REG_1 ", %[" __rseq_str(var) "]\n"
 
 #define RSEQ_ASM_OP_R_LOAD_OFF(offset)                                 \
-       "add    "RSEQ_ASM_TMP_REG_1 ", %[" __rseq_str(offset) "], "     \
+       "add    " RSEQ_ASM_TMP_REG_1 ", %[" __rseq_str(offset) "], "    \
                 RSEQ_ASM_TMP_REG_1 "\n"                                \
        REG_L   RSEQ_ASM_TMP_REG_1 ", (" RSEQ_ASM_TMP_REG_1 ")\n"
 
 #define RSEQ_ASM_OP_R_ADD(count)                                       \
-       "add    "RSEQ_ASM_TMP_REG_1 ", " RSEQ_ASM_TMP_REG_1             \
+       "add    " RSEQ_ASM_TMP_REG_1 ", " RSEQ_ASM_TMP_REG_1            \
                ", %[" __rseq_str(count) "]\n"
 
 #define RSEQ_ASM_OP_FINAL_STORE(value, var, post_commit_label)         \
@@ -194,8 +194,8 @@ int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
                                  RSEQ_ASM_DEFINE_ABORT(4, abort)
                                  : /* gcc asm goto does not allow outputs */
                                  : [cpu_id]            "r" (cpu),
-                                   [current_cpu_id]    "m" (__rseq_abi.cpu_id),
-                                   [rseq_cs]           "m" (__rseq_abi.rseq_cs),
+                                   [current_cpu_id]    "m" (rseq_get_abi()->cpu_id),
+                                   [rseq_cs]           "m" (rseq_get_abi()->rseq_cs.arch.ptr),
                                    [v]                 "m" (*v),
                                    [expect]            "r" (expect),
                                    [newv]              "r" (newv)
@@ -251,8 +251,8 @@ int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot,
                                  RSEQ_ASM_DEFINE_ABORT(4, abort)
                                  : /* gcc asm goto does not allow outputs */
                                  : [cpu_id]            "r" (cpu),
-                                   [current_cpu_id]    "m" (__rseq_abi.cpu_id),
-                                   [rseq_cs]           "m" (__rseq_abi.rseq_cs),
+                                   [current_cpu_id]    "m" (rseq_get_abi()->cpu_id),
+                                   [rseq_cs]           "m" (rseq_get_abi()->rseq_cs.arch.ptr),
                                    [v]                 "m" (*v),
                                    [expectnot]         "r" (expectnot),
                                    [load]              "m" (*load),
@@ -301,8 +301,8 @@ int rseq_addv(intptr_t *v, intptr_t count, int cpu)
                                  RSEQ_ASM_DEFINE_ABORT(4, abort)
                                  : /* gcc asm goto does not allow outputs */
                                  : [cpu_id]            "r" (cpu),
-                                   [current_cpu_id]    "m" (__rseq_abi.cpu_id),
-                                   [rseq_cs]           "m" (__rseq_abi.rseq_cs),
+                                   [current_cpu_id]    "m" (rseq_get_abi()->cpu_id),
+                                   [rseq_cs]           "m" (rseq_get_abi()->rseq_cs.arch.ptr),
                                    [v]                 "m" (*v),
                                    [count]             "r" (count)
                                    RSEQ_INJECT_INPUT
@@ -352,8 +352,8 @@ int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect,
                                  RSEQ_ASM_DEFINE_ABORT(4, abort)
                                  : /* gcc asm goto does not allow outputs */
                                  : [cpu_id]            "r" (cpu),
-                                   [current_cpu_id]    "m" (__rseq_abi.cpu_id),
-                                   [rseq_cs]           "m" (__rseq_abi.rseq_cs),
+                                   [current_cpu_id]    "m" (rseq_get_abi()->cpu_id),
+                                   [rseq_cs]           "m" (rseq_get_abi()->rseq_cs.arch.ptr),
                                    [expect]            "r" (expect),
                                    [v]                 "m" (*v),
                                    [newv]              "r" (newv),
@@ -411,8 +411,8 @@ int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect,
                                  RSEQ_ASM_DEFINE_ABORT(4, abort)
                                  : /* gcc asm goto does not allow outputs */
                                  : [cpu_id]            "r" (cpu),
-                                   [current_cpu_id]    "m" (__rseq_abi.cpu_id),
-                                   [rseq_cs]           "m" (__rseq_abi.rseq_cs),
+                                   [current_cpu_id]    "m" (rseq_get_abi()->cpu_id),
+                                   [rseq_cs]           "m" (rseq_get_abi()->rseq_cs.arch.ptr),
                                    [expect]            "r" (expect),
                                    [v]                 "m" (*v),
                                    [newv]              "r" (newv),
@@ -472,8 +472,8 @@ int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect,
                                  RSEQ_ASM_DEFINE_ABORT(4, abort)
                                  : /* gcc asm goto does not allow outputs */
                                  : [cpu_id]            "r" (cpu),
-                                   [current_cpu_id]    "m" (__rseq_abi.cpu_id),
-                                   [rseq_cs]           "m" (__rseq_abi.rseq_cs),
+                                   [current_cpu_id]    "m" (rseq_get_abi()->cpu_id),
+                                   [rseq_cs]           "m" (rseq_get_abi()->rseq_cs.arch.ptr),
                                    [v]                 "m" (*v),
                                    [expect]            "r" (expect),
                                    [v2]                        "m" (*v2),
@@ -532,8 +532,8 @@ int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect,
                                  RSEQ_ASM_DEFINE_ABORT(4, abort)
                                  : /* gcc asm goto does not allow outputs */
                                  : [cpu_id]            "r" (cpu),
-                                   [current_cpu_id]    "m" (__rseq_abi.cpu_id),
-                                   [rseq_cs]           "m" (__rseq_abi.rseq_cs),
+                                   [current_cpu_id]    "m" (rseq_get_abi()->cpu_id),
+                                   [rseq_cs]           "m" (rseq_get_abi()->rseq_cs.arch.ptr),
                                    [expect]            "r" (expect),
                                    [v]                 "m" (*v),
                                    [newv]              "r" (newv),
@@ -593,8 +593,8 @@ int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect,
                                  RSEQ_ASM_DEFINE_ABORT(4, abort)
                                  : /* gcc asm goto does not allow outputs */
                                  : [cpu_id]            "r" (cpu),
-                                   [current_cpu_id]    "m" (__rseq_abi.cpu_id),
-                                   [rseq_cs]           "m" (__rseq_abi.rseq_cs),
+                                   [current_cpu_id]    "m" (rseq_get_abi()->cpu_id),
+                                   [rseq_cs]           "m" (rseq_get_abi()->rseq_cs.arch.ptr),
                                    [expect]            "r" (expect),
                                    [v]                 "m" (*v),
                                    [newv]              "r" (newv),
@@ -651,8 +651,8 @@ int rseq_offset_deref_addv(intptr_t *ptr, off_t off, intptr_t inc, int cpu)
                                  RSEQ_ASM_DEFINE_ABORT(4, abort)
                                  : /* gcc asm goto does not allow outputs */
                                  : [cpu_id]            "r" (cpu),
-                                   [current_cpu_id]      "m" (__rseq_abi.cpu_id),
-                                   [rseq_cs]           "m" (__rseq_abi.rseq_cs),
+                                   [current_cpu_id]      "m" (rseq_get_abi()->cpu_id),
+                                   [rseq_cs]           "m" (rseq_get_abi()->rseq_cs.arch.ptr),
                                    [ptr]                       "r" (ptr),
                                    [off]                       "er" (off),
                                    [inc]                       "er" (inc)
index 986b945..4177f95 100644 (file)
@@ -111,7 +111,8 @@ void rseq_init(void)
        libc_rseq_offset_p = dlsym(RTLD_NEXT, "__rseq_offset");
        libc_rseq_size_p = dlsym(RTLD_NEXT, "__rseq_size");
        libc_rseq_flags_p = dlsym(RTLD_NEXT, "__rseq_flags");
-       if (libc_rseq_size_p && libc_rseq_offset_p && libc_rseq_flags_p) {
+       if (libc_rseq_size_p && libc_rseq_offset_p && libc_rseq_flags_p &&
+                       *libc_rseq_size_p != 0) {
                /* rseq registration owned by glibc */
                rseq_offset = *libc_rseq_offset_p;
                rseq_size = *libc_rseq_size_p;
index fa02c4d..e815bbf 100644 (file)
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
-# Makefile for mount selftests.
+# Makefile for SafeSetID selftest.
 CFLAGS = -Wall -O2
 LDLIBS = -lcap
 
index 4b809c9..eb9bf0a 100644 (file)
@@ -3,6 +3,7 @@
 #include <stdio.h>
 #include <errno.h>
 #include <pwd.h>
+#include <grp.h>
 #include <string.h>
 #include <syscall.h>
 #include <sys/capability.h>
 #include <stdbool.h>
 #include <stdarg.h>
 
+/*
+ * NOTES about this test:
+ * - requries libcap-dev to be installed on test system
+ * - requires securityfs to me mounted at /sys/kernel/security, e.g.:
+ * mount -n -t securityfs -o nodev,noexec,nosuid securityfs /sys/kernel/security
+ * - needs CONFIG_SECURITYFS and CONFIG_SAFESETID to be enabled
+ */
+
 #ifndef CLONE_NEWUSER
 # define CLONE_NEWUSER 0x10000000
 #endif
 
-#define ROOT_USER 0
-#define RESTRICTED_PARENT 1
-#define ALLOWED_CHILD1 2
-#define ALLOWED_CHILD2 3
-#define NO_POLICY_USER 4
+#define ROOT_UGID 0
+#define RESTRICTED_PARENT_UGID 1
+#define ALLOWED_CHILD1_UGID 2
+#define ALLOWED_CHILD2_UGID 3
+#define NO_POLICY_UGID 4
+
+#define UGID_POLICY_STRING "1:2\n1:3\n2:2\n3:3\n"
 
-char* add_whitelist_policy_file = "/sys/kernel/security/safesetid/add_whitelist_policy";
+char* add_uid_whitelist_policy_file = "/sys/kernel/security/safesetid/uid_allowlist_policy";
+char* add_gid_whitelist_policy_file = "/sys/kernel/security/safesetid/gid_allowlist_policy";
 
 static void die(char *fmt, ...)
 {
@@ -106,9 +118,10 @@ static void ensure_user_exists(uid_t uid)
                        die("couldn't open file\n");
                if (fseek(fd, 0, SEEK_END))
                        die("couldn't fseek\n");
-               snprintf(name_str, 10, "%d", uid);
+               snprintf(name_str, 10, "user %d", uid);
                p.pw_name=name_str;
                p.pw_uid=uid;
+               p.pw_gid=uid;
                p.pw_gecos="Test account";
                p.pw_dir="/dev/null";
                p.pw_shell="/bin/false";
@@ -120,9 +133,36 @@ static void ensure_user_exists(uid_t uid)
        }
 }
 
+static void ensure_group_exists(gid_t gid)
+{
+       struct group g;
+
+       FILE *fd;
+       char name_str[10];
+
+       if (getgrgid(gid) == NULL) {
+               memset(&g,0x00,sizeof(g));
+               fd=fopen("/etc/group","a");
+               if (fd == NULL)
+                       die("couldn't open group file\n");
+               if (fseek(fd, 0, SEEK_END))
+                       die("couldn't fseek group file\n");
+               snprintf(name_str, 10, "group %d", gid);
+               g.gr_name=name_str;
+               g.gr_gid=gid;
+               g.gr_passwd=NULL;
+               g.gr_mem=NULL;
+               int value = putgrent(&g,fd);
+               if (value != 0)
+                       die("putgrent failed\n");
+               if (fclose(fd))
+                       die("fclose failed\n");
+       }
+}
+
 static void ensure_securityfs_mounted(void)
 {
-       int fd = open(add_whitelist_policy_file, O_WRONLY);
+       int fd = open(add_uid_whitelist_policy_file, O_WRONLY);
        if (fd < 0) {
                if (errno == ENOENT) {
                        // Need to mount securityfs
@@ -135,39 +175,60 @@ static void ensure_securityfs_mounted(void)
        } else {
                if (close(fd) != 0) {
                        die("close of %s failed: %s\n",
-                               add_whitelist_policy_file, strerror(errno));
+                               add_uid_whitelist_policy_file, strerror(errno));
+               }
+       }
+}
+
+static void write_uid_policies()
+{
+       static char *policy_str = UGID_POLICY_STRING;
+       ssize_t written;
+       int fd;
+
+       fd = open(add_uid_whitelist_policy_file, O_WRONLY);
+       if (fd < 0)
+               die("can't open add_uid_whitelist_policy file\n");
+       written = write(fd, policy_str, strlen(policy_str));
+       if (written != strlen(policy_str)) {
+               if (written >= 0) {
+                       die("short write to %s\n", add_uid_whitelist_policy_file);
+               } else {
+                       die("write to %s failed: %s\n",
+                               add_uid_whitelist_policy_file, strerror(errno));
                }
        }
+       if (close(fd) != 0) {
+               die("close of %s failed: %s\n",
+                       add_uid_whitelist_policy_file, strerror(errno));
+       }
 }
 
-static void write_policies(void)
+static void write_gid_policies()
 {
-       static char *policy_str =
-               "1:2\n"
-               "1:3\n"
-               "2:2\n"
-               "3:3\n";
+       static char *policy_str = UGID_POLICY_STRING;
        ssize_t written;
        int fd;
 
-       fd = open(add_whitelist_policy_file, O_WRONLY);
+       fd = open(add_gid_whitelist_policy_file, O_WRONLY);
        if (fd < 0)
-               die("can't open add_whitelist_policy file\n");
+               die("can't open add_gid_whitelist_policy file\n");
        written = write(fd, policy_str, strlen(policy_str));
        if (written != strlen(policy_str)) {
                if (written >= 0) {
-                       die("short write to %s\n", add_whitelist_policy_file);
+                       die("short write to %s\n", add_gid_whitelist_policy_file);
                } else {
                        die("write to %s failed: %s\n",
-                               add_whitelist_policy_file, strerror(errno));
+                               add_gid_whitelist_policy_file, strerror(errno));
                }
        }
        if (close(fd) != 0) {
                die("close of %s failed: %s\n",
-                       add_whitelist_policy_file, strerror(errno));
+                       add_gid_whitelist_policy_file, strerror(errno));
        }
 }
 
+
 static bool test_userns(bool expect_success)
 {
        uid_t uid;
@@ -194,7 +255,7 @@ static bool test_userns(bool expect_success)
                        printf("preparing file name string failed");
                        return false;
                }
-               success = write_file(map_file_name, "0 0 1", uid);
+               success = write_file(map_file_name, "0 %d 1", uid);
                return success == expect_success;
        }
 
@@ -258,13 +319,144 @@ static void test_setuid(uid_t child_uid, bool expect_success)
        die("should not reach here\n");
 }
 
+static void test_setgid(gid_t child_gid, bool expect_success)
+{
+       pid_t cpid, w;
+       int wstatus;
+
+       cpid = fork();
+       if (cpid == -1) {
+               die("fork\n");
+       }
+
+       if (cpid == 0) {            /* Code executed by child */
+               if (setgid(child_gid) < 0)
+                       exit(EXIT_FAILURE);
+               if (getgid() == child_gid)
+                       exit(EXIT_SUCCESS);
+               else
+                       exit(EXIT_FAILURE);
+       } else {                 /* Code executed by parent */
+               do {
+                       w = waitpid(cpid, &wstatus, WUNTRACED | WCONTINUED);
+                       if (w == -1) {
+                               die("waitpid\n");
+                       }
+
+                       if (WIFEXITED(wstatus)) {
+                               if (WEXITSTATUS(wstatus) == EXIT_SUCCESS) {
+                                       if (expect_success) {
+                                               return;
+                                       } else {
+                                               die("unexpected success\n");
+                                       }
+                               } else {
+                                       if (expect_success) {
+                                               die("unexpected failure\n");
+                                       } else {
+                                               return;
+                                       }
+                               }
+                       } else if (WIFSIGNALED(wstatus)) {
+                               if (WTERMSIG(wstatus) == 9) {
+                                       if (expect_success)
+                                               die("killed unexpectedly\n");
+                                       else
+                                               return;
+                               } else {
+                                       die("unexpected signal: %d\n", wstatus);
+                               }
+                       } else {
+                               die("unexpected status: %d\n", wstatus);
+                       }
+               } while (!WIFEXITED(wstatus) && !WIFSIGNALED(wstatus));
+       }
+
+       die("should not reach here\n");
+}
+
+static void test_setgroups(gid_t* child_groups, size_t len, bool expect_success)
+{
+       pid_t cpid, w;
+       int wstatus;
+       gid_t groupset[len];
+       int i, j;
+
+       cpid = fork();
+       if (cpid == -1) {
+               die("fork\n");
+       }
+
+       if (cpid == 0) {            /* Code executed by child */
+               if (setgroups(len, child_groups) != 0)
+                       exit(EXIT_FAILURE);
+               if (getgroups(len, groupset) != len)
+                       exit(EXIT_FAILURE);
+               for (i = 0; i < len; i++) {
+                       for (j = 0; j < len; j++) {
+                               if (child_groups[i] == groupset[j])
+                                       break;
+                               if (j == len - 1)
+                                       exit(EXIT_FAILURE);
+                       }
+               }
+               exit(EXIT_SUCCESS);
+       } else {                 /* Code executed by parent */
+               do {
+                       w = waitpid(cpid, &wstatus, WUNTRACED | WCONTINUED);
+                       if (w == -1) {
+                               die("waitpid\n");
+                       }
+
+                       if (WIFEXITED(wstatus)) {
+                               if (WEXITSTATUS(wstatus) == EXIT_SUCCESS) {
+                                       if (expect_success) {
+                                               return;
+                                       } else {
+                                               die("unexpected success\n");
+                                       }
+                               } else {
+                                       if (expect_success) {
+                                               die("unexpected failure\n");
+                                       } else {
+                                               return;
+                                       }
+                               }
+                       } else if (WIFSIGNALED(wstatus)) {
+                               if (WTERMSIG(wstatus) == 9) {
+                                       if (expect_success)
+                                               die("killed unexpectedly\n");
+                                       else
+                                               return;
+                               } else {
+                                       die("unexpected signal: %d\n", wstatus);
+                               }
+                       } else {
+                               die("unexpected status: %d\n", wstatus);
+                       }
+               } while (!WIFEXITED(wstatus) && !WIFSIGNALED(wstatus));
+       }
+
+       die("should not reach here\n");
+}
+
+
 static void ensure_users_exist(void)
 {
-       ensure_user_exists(ROOT_USER);
-       ensure_user_exists(RESTRICTED_PARENT);
-       ensure_user_exists(ALLOWED_CHILD1);
-       ensure_user_exists(ALLOWED_CHILD2);
-       ensure_user_exists(NO_POLICY_USER);
+       ensure_user_exists(ROOT_UGID);
+       ensure_user_exists(RESTRICTED_PARENT_UGID);
+       ensure_user_exists(ALLOWED_CHILD1_UGID);
+       ensure_user_exists(ALLOWED_CHILD2_UGID);
+       ensure_user_exists(NO_POLICY_UGID);
+}
+
+static void ensure_groups_exist(void)
+{
+       ensure_group_exists(ROOT_UGID);
+       ensure_group_exists(RESTRICTED_PARENT_UGID);
+       ensure_group_exists(ALLOWED_CHILD1_UGID);
+       ensure_group_exists(ALLOWED_CHILD2_UGID);
+       ensure_group_exists(NO_POLICY_UGID);
 }
 
 static void drop_caps(bool setid_retained)
@@ -283,41 +475,52 @@ static void drop_caps(bool setid_retained)
 
 int main(int argc, char **argv)
 {
+       ensure_groups_exist();
        ensure_users_exist();
        ensure_securityfs_mounted();
-       write_policies();
+       write_uid_policies();
+       write_gid_policies();
 
        if (prctl(PR_SET_KEEPCAPS, 1L))
                die("Error with set keepcaps\n");
 
-       // First test to make sure we can write userns mappings from a user
-       // that doesn't have any restrictions (as long as it has CAP_SETUID);
-       if (setuid(NO_POLICY_USER) < 0)
-               die("Error with set uid(%d)\n", NO_POLICY_USER);
-       if (setgid(NO_POLICY_USER) < 0)
-               die("Error with set gid(%d)\n", NO_POLICY_USER);
-
+       // First test to make sure we can write userns mappings from a non-root
+       // user that doesn't have any restrictions (as long as it has
+       // CAP_SETUID);
+       if (setgid(NO_POLICY_UGID) < 0)
+               die("Error with set gid(%d)\n", NO_POLICY_UGID);
+       if (setuid(NO_POLICY_UGID) < 0)
+               die("Error with set uid(%d)\n", NO_POLICY_UGID);
        // Take away all but setid caps
        drop_caps(true);
-
        // Need PR_SET_DUMPABLE flag set so we can write /proc/[pid]/uid_map
        // from non-root parent process.
        if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0))
                die("Error with set dumpable\n");
-
        if (!test_userns(true)) {
                die("test_userns failed when it should work\n");
        }
 
-       if (setuid(RESTRICTED_PARENT) < 0)
-               die("Error with set uid(%d)\n", RESTRICTED_PARENT);
-       if (setgid(RESTRICTED_PARENT) < 0)
-               die("Error with set gid(%d)\n", RESTRICTED_PARENT);
+       // Now switch to a user/group with restrictions
+       if (setgid(RESTRICTED_PARENT_UGID) < 0)
+               die("Error with set gid(%d)\n", RESTRICTED_PARENT_UGID);
+       if (setuid(RESTRICTED_PARENT_UGID) < 0)
+               die("Error with set uid(%d)\n", RESTRICTED_PARENT_UGID);
+
+       test_setuid(ROOT_UGID, false);
+       test_setuid(ALLOWED_CHILD1_UGID, true);
+       test_setuid(ALLOWED_CHILD2_UGID, true);
+       test_setuid(NO_POLICY_UGID, false);
+
+       test_setgid(ROOT_UGID, false);
+       test_setgid(ALLOWED_CHILD1_UGID, true);
+       test_setgid(ALLOWED_CHILD2_UGID, true);
+       test_setgid(NO_POLICY_UGID, false);
 
-       test_setuid(ROOT_USER, false);
-       test_setuid(ALLOWED_CHILD1, true);
-       test_setuid(ALLOWED_CHILD2, true);
-       test_setuid(NO_POLICY_USER, false);
+       gid_t allowed_supp_groups[2] = {ALLOWED_CHILD1_UGID, ALLOWED_CHILD2_UGID};
+       gid_t disallowed_supp_groups[2] = {ROOT_UGID, NO_POLICY_UGID};
+       test_setgroups(allowed_supp_groups, 2, true);
+       test_setgroups(disallowed_supp_groups, 2, false);
 
        if (!test_userns(false)) {
                die("test_userns worked when it should fail\n");
@@ -328,8 +531,12 @@ int main(int argc, char **argv)
        test_setuid(2, false);
        test_setuid(3, false);
        test_setuid(4, false);
+       test_setgid(2, false);
+       test_setgid(3, false);
+       test_setgid(4, false);
 
        // NOTE: this test doesn't clean up users that were created in
        // /etc/passwd or flush policies that were added to the LSM.
+       printf("test successful!\n");
        return EXIT_SUCCESS;
 }
index 136df5b..4ae6c89 100644 (file)
@@ -809,7 +809,7 @@ void kill_thread_or_group(struct __test_metadata *_metadata,
                .len = (unsigned short)ARRAY_SIZE(filter_thread),
                .filter = filter_thread,
        };
-       int kill = kill_how == KILL_PROCESS ? SECCOMP_RET_KILL_PROCESS : 0xAAAAAAAAA;
+       int kill = kill_how == KILL_PROCESS ? SECCOMP_RET_KILL_PROCESS : 0xAAAAAAAA;
        struct sock_filter filter_process[] = {
                BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
                        offsetof(struct seccomp_data, nr)),
index 4d63927..cb553ea 100644 (file)
@@ -5,7 +5,6 @@ top_srcdir = $(abspath ../../../..)
 APIDIR := $(top_scrdir)/include/uapi
 TEST_GEN_FILES = action.o
 
-KSFT_KHDR_INSTALL := 1
 include ../lib.mk
 
 PROBE := $(shell $(LLC) -march=bpf -mcpu=probe -filetype=null /dev/null 2>&1)
index b24494c..c652e8c 100644 (file)
         "teardown": [
             "$TC actions flush action gact"
         ]
+    },
+    {
+        "id": "7f52",
+        "name": "Try to flush action which is referenced by filter",
+        "category": [
+            "actions",
+            "gact"
+        ],
+        "plugins": {
+            "requires": "nsPlugin"
+        },
+        "setup": [
+            [
+                "$TC actions flush action gact",
+                0,
+                1,
+                255
+            ],
+            "$TC qdisc add dev $DEV1 ingress",
+            "$TC actions add action pass index 1",
+            "$TC filter add dev $DEV1 protocol all ingress prio 1 handle 0x1234 matchall action gact index 1"
+        ],
+        "cmdUnderTest": "$TC actions flush action gact",
+        "expExitCode": "1",
+        "verifyCmd": "$TC actions ls action gact",
+        "matchPattern": "total acts 1.*action order [0-9]*: gact action pass.*index 1 ref 2 bind 1",
+        "matchCount": "1",
+        "teardown": [
+            "$TC qdisc del dev $DEV1 ingress",
+            [
+                "sleep 1; $TC actions flush action gact",
+                0,
+                1
+            ]
+        ]
+    },
+    {
+        "id": "ae1e",
+        "name": "Try to flush actions when last one is referenced by filter",
+        "category": [
+            "actions",
+            "gact"
+        ],
+        "plugins": {
+            "requires": "nsPlugin"
+        },
+        "setup": [
+            [
+                "$TC actions flush action gact",
+                0,
+                1,
+                255
+            ],
+            "$TC qdisc add dev $DEV1 ingress",
+           [
+                "$TC actions add action pass index 1",
+               0,
+               1,
+               255
+           ],
+            "$TC actions add action reclassify index 2",
+            "$TC actions add action drop index 3",
+            "$TC filter add dev $DEV1 protocol all ingress prio 1 handle 0x1234 matchall action gact index 3"
+        ],
+        "cmdUnderTest": "$TC actions flush action gact",
+        "expExitCode": "0",
+        "verifyCmd": "$TC actions ls action gact",
+        "matchPattern": "total acts 1.*action order [0-9]*: gact action drop.*index 3 ref 2 bind 1",
+        "matchCount": "1",
+        "teardown": [
+            "$TC qdisc del dev $DEV1 ingress",
+            [
+                "sleep 1; $TC actions flush action gact",
+                0,
+                1
+            ]
+        ]
     }
 ]
index 3a5936c..f0d51d4 100644 (file)
@@ -1,4 +1,4 @@
-TEST_GEN_PROGS := timens timerfd timer clock_nanosleep procfs exec futex
+TEST_GEN_PROGS := timens timerfd timer clock_nanosleep procfs exec futex vfork_exec
 TEST_GEN_PROGS_EXTENDED := gettime_perf
 
 CFLAGS := -Wall -Werror -pthread
diff --git a/tools/testing/selftests/timens/vfork_exec.c b/tools/testing/selftests/timens/vfork_exec.c
new file mode 100644 (file)
index 0000000..e6ccd90
--- /dev/null
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "log.h"
+#include "timens.h"
+
+#define OFFSET (36000)
+
+int main(int argc, char *argv[])
+{
+       struct timespec now, tst;
+       int status, i;
+       pid_t pid;
+
+       if (argc > 1) {
+               if (sscanf(argv[1], "%ld", &now.tv_sec) != 1)
+                       return pr_perror("sscanf");
+
+               for (i = 0; i < 2; i++) {
+                       _gettime(CLOCK_MONOTONIC, &tst, i);
+                       if (abs(tst.tv_sec - now.tv_sec) > 5)
+                               return pr_fail("%ld %ld\n", now.tv_sec, tst.tv_sec);
+               }
+               return 0;
+       }
+
+       nscheck();
+
+       ksft_set_plan(1);
+
+       clock_gettime(CLOCK_MONOTONIC, &now);
+
+       if (unshare_timens())
+               return 1;
+
+       if (_settime(CLOCK_MONOTONIC, OFFSET))
+               return 1;
+
+       for (i = 0; i < 2; i++) {
+               _gettime(CLOCK_MONOTONIC, &tst, i);
+               if (abs(tst.tv_sec - now.tv_sec) > 5)
+                       return pr_fail("%ld %ld\n",
+                                       now.tv_sec, tst.tv_sec);
+       }
+
+       pid = vfork();
+       if (pid < 0)
+               return pr_perror("fork");
+
+       if (pid == 0) {
+               char now_str[64];
+               char *cargv[] = {"exec", now_str, NULL};
+               char *cenv[] = {NULL};
+
+               // Check that we are still in the source timens.
+               for (i = 0; i < 2; i++) {
+                       _gettime(CLOCK_MONOTONIC, &tst, i);
+                       if (abs(tst.tv_sec - now.tv_sec) > 5)
+                               return pr_fail("%ld %ld\n",
+                                               now.tv_sec, tst.tv_sec);
+               }
+
+               /* Check for proper vvar offsets after execve. */
+               snprintf(now_str, sizeof(now_str), "%ld", now.tv_sec + OFFSET);
+               execve("/proc/self/exe", cargv, cenv);
+               return pr_perror("execve");
+       }
+
+       if (waitpid(pid, &status, 0) != pid)
+               return pr_perror("waitpid");
+
+       if (status)
+               ksft_exit_fail();
+
+       ksft_test_result_pass("exec\n");
+       ksft_exit_pass();
+       return 0;
+}
index 54d8d87..47e05fd 100644 (file)
@@ -165,7 +165,7 @@ int check_tick_adj(long tickval)
        return  0;
 }
 
-int main(int argv, char **argc)
+int main(int argc, char **argv)
 {
        struct timespec raw;
        long tick, max, interval, err;
index 54da4b0..4332b49 100644 (file)
@@ -92,7 +92,7 @@ long long timespec_sub(struct timespec a, struct timespec b)
        return ret;
 }
 
-int final_ret = 0;
+int final_ret;
 
 void sigalarm(int signo)
 {
index c4eab71..992a77f 100644 (file)
@@ -55,7 +55,7 @@ int change_skew_test(int ppm)
 }
 
 
-int main(int argv, char **argc)
+int main(int argc, char **argv)
 {
        struct timex tx;
        int i, ret;
index ef8eb36..c526459 100644 (file)
  */
 
 
+#include <fcntl.h>
 #include <stdio.h>
-#include <unistd.h>
 #include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/timex.h>
-#include <time.h>
 #include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <string.h>
 #include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
 #include "../kselftest.h"
 
 
@@ -110,21 +110,40 @@ int run_tests(int secs)
 
        sprintf(buf, "./inconsistency-check -t %i", secs);
        ret = system(buf);
-       if (ret)
-               return ret;
+       if (WIFEXITED(ret) && WEXITSTATUS(ret))
+               return WEXITSTATUS(ret);
        ret = system("./nanosleep");
-       return ret;
+       return WIFEXITED(ret) ? WEXITSTATUS(ret) : 0;
 }
 
 
 char clocksource_list[10][30];
 
-int main(int argv, char **argc)
+int main(int argc, char **argv)
 {
        char orig_clk[512];
-       int count, i, status;
+       int count, i, status, opt;
+       int do_sanity_check = 1;
+       int runtime = 60;
        pid_t pid;
 
+       /* Process arguments */
+       while ((opt = getopt(argc, argv, "st:")) != -1) {
+               switch (opt) {
+               case 's':
+                       do_sanity_check = 0;
+                       break;
+               case 't':
+                       runtime = atoi(optarg);
+                       break;
+               default:
+                       printf("Usage: %s [-s] [-t <secs>]\n", argv[0]);
+                       printf("        -s: skip sanity checks\n");
+                       printf("        -t: Number of seconds to run\n");
+                       exit(-1);
+               }
+       }
+
        get_cur_clocksource(orig_clk, 512);
 
        count = get_clocksources(clocksource_list);
@@ -135,23 +154,25 @@ int main(int argv, char **argc)
        }
 
        /* Check everything is sane before we start switching asynchronously */
-       for (i = 0; i < count; i++) {
-               printf("Validating clocksource %s\n", clocksource_list[i]);
-               if (change_clocksource(clocksource_list[i])) {
-                       status = -1;
-                       goto out;
-               }
-               if (run_tests(5)) {
-                       status = -1;
-                       goto out;
+       if (do_sanity_check) {
+               for (i = 0; i < count; i++) {
+                       printf("Validating clocksource %s\n",
+                               clocksource_list[i]);
+                       if (change_clocksource(clocksource_list[i])) {
+                               status = -1;
+                               goto out;
+                       }
+                       if (run_tests(5)) {
+                               status = -1;
+                               goto out;
+                       }
                }
        }
 
-
        printf("Running Asynchronous Switching Tests...\n");
        pid = fork();
        if (!pid)
-               return run_tests(60);
+               return run_tests(runtime);
 
        while (pid != waitpid(pid, &status, WNOHANG))
                for (i = 0; i < count; i++)
@@ -162,7 +183,9 @@ int main(int argv, char **argc)
 out:
        change_clocksource(orig_clk);
 
-       if (status)
-               return ksft_exit_fail();
-       return ksft_exit_pass();
+       /* Print at the end to not mix output with child process */
+       ksft_print_header();
+       ksft_set_plan(1);
+       ksft_test_result(!status, "clocksource-switch\n");
+       ksft_exit(!status);
 }
index e6756d9..36a49fb 100644 (file)
@@ -122,30 +122,28 @@ int consistency_test(int clock_type, unsigned long seconds)
                if (inconsistent >= 0) {
                        unsigned long long delta;
 
-                       printf("\%s\n", start_str);
+                       ksft_print_msg("\%s\n", start_str);
                        for (i = 0; i < CALLS_PER_LOOP; i++) {
                                if (i == inconsistent)
-                                       printf("--------------------\n");
-                               printf("%lu:%lu\n", list[i].tv_sec,
+                                       ksft_print_msg("--------------------\n");
+                               ksft_print_msg("%lu:%lu\n", list[i].tv_sec,
                                                        list[i].tv_nsec);
                                if (i == inconsistent + 1)
-                                       printf("--------------------\n");
+                                       ksft_print_msg("--------------------\n");
                        }
                        delta = list[inconsistent].tv_sec * NSEC_PER_SEC;
                        delta += list[inconsistent].tv_nsec;
                        delta -= list[inconsistent+1].tv_sec * NSEC_PER_SEC;
                        delta -= list[inconsistent+1].tv_nsec;
-                       printf("Delta: %llu ns\n", delta);
+                       ksft_print_msg("Delta: %llu ns\n", delta);
                        fflush(0);
                        /* timestamp inconsistency*/
                        t = time(0);
-                       printf("%s\n", ctime(&t));
-                       printf("[FAILED]\n");
+                       ksft_print_msg("%s\n", ctime(&t));
                        return -1;
                }
                now = list[0].tv_sec;
        }
-       printf("[OK]\n");
        return 0;
 }
 
@@ -178,16 +176,22 @@ int main(int argc, char *argv[])
 
        setbuf(stdout, NULL);
 
+       ksft_print_header();
+       ksft_set_plan(maxclocks - userclock);
+
        for (clockid = userclock; clockid < maxclocks; clockid++) {
 
-               if (clockid == CLOCK_HWSPECIFIC)
+               if (clockid == CLOCK_HWSPECIFIC || clock_gettime(clockid, &ts)) {
+                       ksft_test_result_skip("%-31s\n", clockstring(clockid));
                        continue;
+               }
 
-               if (!clock_gettime(clockid, &ts)) {
-                       printf("Consistent %-30s ", clockstring(clockid));
-                       if (consistency_test(clockid, runtime))
-                               return ksft_exit_fail();
+               if (consistency_test(clockid, runtime)) {
+                       ksft_test_result_fail("%-31s\n", clockstring(clockid));
+                       ksft_exit_fail();
+               } else {
+                       ksft_test_result_pass("%-31s\n", clockstring(clockid));
                }
        }
-       return ksft_exit_pass();
+       ksft_exit_pass();
 }
index 71b5441..df1d035 100644 (file)
@@ -133,33 +133,37 @@ int main(int argc, char **argv)
        long long length;
        int clockid, ret;
 
+       ksft_print_header();
+       ksft_set_plan(NR_CLOCKIDS);
+
        for (clockid = CLOCK_REALTIME; clockid < NR_CLOCKIDS; clockid++) {
 
                /* Skip cputime clockids since nanosleep won't increment cputime */
                if (clockid == CLOCK_PROCESS_CPUTIME_ID ||
                                clockid == CLOCK_THREAD_CPUTIME_ID ||
-                               clockid == CLOCK_HWSPECIFIC)
+                               clockid == CLOCK_HWSPECIFIC) {
+                       ksft_test_result_skip("%-31s\n", clockstring(clockid));
                        continue;
+               }
 
-               printf("Nanosleep %-31s ", clockstring(clockid));
                fflush(stdout);
 
                length = 10;
                while (length <= (NSEC_PER_SEC * 10)) {
                        ret = nanosleep_test(clockid, length);
                        if (ret == UNSUPPORTED) {
-                               printf("[UNSUPPORTED]\n");
+                               ksft_test_result_skip("%-31s\n", clockstring(clockid));
                                goto next;
                        }
                        if (ret < 0) {
-                               printf("[FAILED]\n");
-                               return ksft_exit_fail();
+                               ksft_test_result_fail("%-31s\n", clockstring(clockid));
+                               ksft_exit_fail();
                        }
                        length *= 100;
                }
-               printf("[OK]\n");
+               ksft_test_result_pass("%-31s\n", clockstring(clockid));
 next:
                ret = 0;
        }
-       return ksft_exit_pass();
+       ksft_exit_pass();
 }
index b41d8dd..5beceee 100644 (file)
@@ -89,7 +89,7 @@ void get_monotonic_and_raw(struct timespec *mon, struct timespec *raw)
        }
 }
 
-int main(int argv, char **argc)
+int main(int argc, char **argv)
 {
        struct timespec mon, raw, start, end;
        long long delta1, delta2, interval, eppm, ppm;
index 8066be9..63913f7 100644 (file)
@@ -38,7 +38,7 @@
 
 #define NSEC_PER_SEC 1000000000LL
 
-int main(int argv, char **argc)
+int main(int argc, char **argv)
 {
        struct timex tx;
        int ret, ppm;
index 5397de7..48b9a80 100644 (file)
@@ -40,7 +40,7 @@
 #define ADJ_SETOFFSET 0x0100
 
 #include <sys/syscall.h>
-static int clock_adjtime(clockid_t id, struct timex *tx)
+int clock_adjtime(clockid_t id, struct timex *tx)
 {
        return syscall(__NR_clock_adjtime, id, tx);
 }
diff --git a/tools/testing/selftests/tpm2/settings b/tools/testing/selftests/tpm2/settings
new file mode 100644 (file)
index 0000000..a62d2fa
--- /dev/null
@@ -0,0 +1 @@
+timeout=600
index 44f25ac..108587c 100644 (file)
@@ -94,7 +94,6 @@ TEST_PROGS := run_vmtests.sh
 TEST_FILES := test_vmalloc.sh
 TEST_FILES += test_hmm.sh
 
-KSFT_KHDR_INSTALL := 1
 include ../lib.mk
 
 $(OUTPUT)/madv_populate: vm_util.c
index 0bdfc19..4bc2458 100644 (file)
@@ -860,7 +860,7 @@ static int stress(struct uffd_stats *uffd_stats)
        /*
         * Be strict and immediately zap area_src, the whole area has
         * been transferred already by the background treads. The
-        * area_src could then be faulted in in a racy way by still
+        * area_src could then be faulted in a racy way by still
         * running uffdio_threads reading zeropages after we zapped
         * area_src (but they're guaranteed to get -EEXIST from
         * UFFDIO_COPY without writing zero pages into area_dst
index 7d1b809..9700358 100644 (file)
@@ -19,8 +19,6 @@ endif
 MIRROR := https://download.wireguard.com/qemu-test/distfiles/
 
 KERNEL_BUILD_PATH := $(BUILD_PATH)/kernel$(if $(findstring yes,$(DEBUG_KERNEL)),-debug)
-rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d))
-WIREGUARD_SOURCES := $(call rwildcard,$(KERNEL_PATH)/drivers/net/wireguard/,*)
 
 default: qemu
 
@@ -109,20 +107,22 @@ CHOST := x86_64-linux-musl
 QEMU_ARCH := x86_64
 KERNEL_ARCH := x86_64
 KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/x86/boot/bzImage
+QEMU_VPORT_RESULT := virtio-serial-device
 ifeq ($(HOST_ARCH),$(ARCH))
-QEMU_MACHINE := -cpu host -machine q35,accel=kvm
+QEMU_MACHINE := -cpu host -machine microvm,accel=kvm,pit=off,pic=off,rtc=off -no-acpi
 else
-QEMU_MACHINE := -cpu max -machine q35
+QEMU_MACHINE := -cpu max -machine microvm -no-acpi
 endif
 else ifeq ($(ARCH),i686)
 CHOST := i686-linux-musl
 QEMU_ARCH := i386
 KERNEL_ARCH := x86
 KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/x86/boot/bzImage
+QEMU_VPORT_RESULT := virtio-serial-device
 ifeq ($(subst x86_64,i686,$(HOST_ARCH)),$(ARCH))
-QEMU_MACHINE := -cpu host -machine q35,accel=kvm
+QEMU_MACHINE := -cpu host -machine microvm,accel=kvm,pit=off,pic=off,rtc=off -no-acpi
 else
-QEMU_MACHINE := -cpu max -machine q35
+QEMU_MACHINE := -cpu coreduo -machine microvm -no-acpi
 endif
 else ifeq ($(ARCH),mips64)
 CHOST := mips64-linux-musl
@@ -208,10 +208,11 @@ QEMU_ARCH := m68k
 KERNEL_ARCH := m68k
 KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/vmlinux
 KERNEL_CMDLINE := $(shell sed -n 's/CONFIG_CMDLINE=\(.*\)/\1/p' arch/m68k.config)
+QEMU_VPORT_RESULT := virtio-serial-device
 ifeq ($(HOST_ARCH),$(ARCH))
-QEMU_MACHINE := -cpu host,accel=kvm -machine q800 -append $(KERNEL_CMDLINE)
+QEMU_MACHINE := -cpu host,accel=kvm -machine virt -append $(KERNEL_CMDLINE)
 else
-QEMU_MACHINE := -machine q800 -smp 1 -append $(KERNEL_CMDLINE)
+QEMU_MACHINE := -machine virt -smp 1 -append $(KERNEL_CMDLINE)
 endif
 else ifeq ($(ARCH),riscv64)
 CHOST := riscv64-linux-musl
@@ -322,8 +323,9 @@ $(KERNEL_BUILD_PATH)/.config: $(TOOLCHAIN_PATH)/.installed kernel.config arch/$(
        cd $(KERNEL_BUILD_PATH) && ARCH=$(KERNEL_ARCH) $(KERNEL_PATH)/scripts/kconfig/merge_config.sh -n $(KERNEL_BUILD_PATH)/.config $(KERNEL_BUILD_PATH)/minimal.config
        $(if $(findstring yes,$(DEBUG_KERNEL)),cp debug.config $(KERNEL_BUILD_PATH) && cd $(KERNEL_BUILD_PATH) && ARCH=$(KERNEL_ARCH) $(KERNEL_PATH)/scripts/kconfig/merge_config.sh -n $(KERNEL_BUILD_PATH)/.config debug.config,)
 
-$(KERNEL_BZIMAGE): $(TOOLCHAIN_PATH)/.installed $(KERNEL_BUILD_PATH)/.config $(BUILD_PATH)/init-cpio-spec.txt $(IPERF_PATH)/src/iperf3 $(IPUTILS_PATH)/ping $(BASH_PATH)/bash $(IPROUTE2_PATH)/misc/ss $(IPROUTE2_PATH)/ip/ip $(IPTABLES_PATH)/iptables/xtables-legacy-multi $(NMAP_PATH)/ncat/ncat $(WIREGUARD_TOOLS_PATH)/src/wg $(BUILD_PATH)/init ../netns.sh $(WIREGUARD_SOURCES)
+$(KERNEL_BZIMAGE): $(TOOLCHAIN_PATH)/.installed $(KERNEL_BUILD_PATH)/.config $(BUILD_PATH)/init-cpio-spec.txt $(IPERF_PATH)/src/iperf3 $(IPUTILS_PATH)/ping $(BASH_PATH)/bash $(IPROUTE2_PATH)/misc/ss $(IPROUTE2_PATH)/ip/ip $(IPTABLES_PATH)/iptables/xtables-legacy-multi $(NMAP_PATH)/ncat/ncat $(WIREGUARD_TOOLS_PATH)/src/wg $(BUILD_PATH)/init
        $(MAKE) -C $(KERNEL_PATH) O=$(KERNEL_BUILD_PATH) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(CROSS_COMPILE)
+.PHONY: $(KERNEL_BZIMAGE)
 
 $(TOOLCHAIN_PATH)/$(CHOST)/include/linux/.installed: | $(KERNEL_BUILD_PATH)/.config $(TOOLCHAIN_PATH)/.installed
        rm -rf $(TOOLCHAIN_PATH)/$(CHOST)/include/linux
index fc7959b..0579c66 100644 (file)
@@ -7,6 +7,7 @@ CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
 CONFIG_VIRTIO_MENU=y
 CONFIG_VIRTIO_MMIO=y
 CONFIG_VIRTIO_CONSOLE=y
+CONFIG_COMPAT_32BIT_TIME=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="console=ttyAMA0 wg.success=vport0p1 panic_on_warn=1"
 CONFIG_FRAME_WARN=1024
index f3066be..2a3307b 100644 (file)
@@ -7,6 +7,7 @@ CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
 CONFIG_VIRTIO_MENU=y
 CONFIG_VIRTIO_MMIO=y
 CONFIG_VIRTIO_CONSOLE=y
+CONFIG_COMPAT_32BIT_TIME=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="console=ttyAMA0 wg.success=vport0p1 panic_on_warn=1"
 CONFIG_CPU_BIG_ENDIAN=y
index 6d90892..35b0650 100644 (file)
@@ -1,6 +1,10 @@
-CONFIG_ACPI=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_VIRTIO_MENU=y
+CONFIG_VIRTIO_MMIO=y
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
+CONFIG_COMPAT_32BIT_TIME=y
 CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1 panic_on_warn=1"
+CONFIG_CMDLINE="console=ttyS0 wg.success=vport0p1 panic_on_warn=1 reboot=t"
 CONFIG_FRAME_WARN=1024
index 82c925e..39c48cb 100644 (file)
@@ -1,9 +1,7 @@
 CONFIG_MMU=y
+CONFIG_VIRT=y
 CONFIG_M68KCLASSIC=y
-CONFIG_M68040=y
-CONFIG_MAC=y
-CONFIG_SERIAL_PMACZILOG=y
-CONFIG_SERIAL_PMACZILOG_TTYS=y
-CONFIG_SERIAL_PMACZILOG_CONSOLE=y
-CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1 panic_on_warn=1"
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_COMPAT_32BIT_TIME=y
+CONFIG_CMDLINE="console=ttyGF0 wg.success=vport0p1 panic_on_warn=1"
 CONFIG_FRAME_WARN=1024
index d7ec63c..2a84402 100644 (file)
@@ -6,6 +6,7 @@ CONFIG_POWER_RESET=y
 CONFIG_POWER_RESET_SYSCON=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_COMPAT_32BIT_TIME=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1 panic_on_warn=1"
 CONFIG_FRAME_WARN=1024
index 18a4982..56146a1 100644 (file)
@@ -7,6 +7,7 @@ CONFIG_POWER_RESET=y
 CONFIG_POWER_RESET_SYSCON=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_COMPAT_32BIT_TIME=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1 panic_on_warn=1"
 CONFIG_FRAME_WARN=1024
index 5e04882..174a9ff 100644 (file)
@@ -4,6 +4,7 @@ CONFIG_PPC_85xx=y
 CONFIG_PHYS_64BIT=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_COMPAT_32BIT_TIME=y
 CONFIG_MATH_EMULATION=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1 panic_on_warn=1"
index efa0069..cf2d137 100644 (file)
@@ -1,6 +1,9 @@
-CONFIG_ACPI=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_VIRTIO_MENU=y
+CONFIG_VIRTIO_MMIO=y
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
 CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1 panic_on_warn=1"
+CONFIG_CMDLINE="console=ttyS0 wg.success=vport0p1 panic_on_warn=1 reboot=t"
 CONFIG_FRAME_WARN=1280
index c9e1284..3e49924 100644 (file)
@@ -11,6 +11,7 @@
 #include <stdlib.h>
 #include <stdbool.h>
 #include <fcntl.h>
+#include <time.h>
 #include <sys/wait.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
@@ -70,6 +71,15 @@ static void seed_rng(void)
        close(fd);
 }
 
+static void set_time(void)
+{
+       if (time(NULL))
+               return;
+       pretty_message("[+] Setting fake time...");
+       if (stime(&(time_t){1433512680}) < 0)
+               panic("settimeofday()");
+}
+
 static void mount_filesystems(void)
 {
        pretty_message("[+] Mounting filesystems...");
@@ -259,6 +269,7 @@ int main(int argc, char *argv[])
        print_banner();
        mount_filesystems();
        seed_rng();
+       set_time();
        kmod_selftests();
        enable_logging();
        clear_leaks();
index bad88f4..e1858ce 100644 (file)
@@ -58,7 +58,6 @@ CONFIG_NO_HZ_IDLE=y
 CONFIG_NO_HZ_FULL=n
 CONFIG_HZ_PERIODIC=n
 CONFIG_HIGH_RES_TIMERS=y
-CONFIG_ARCH_RANDOM=y
 CONFIG_FILE_LOCKING=y
 CONFIG_POSIX_TIMERS=y
 CONFIG_DEVTMPFS=y
index 296f69c..da20088 100644 (file)
@@ -27,7 +27,7 @@
 
 /**************************************************************************
  * PID (Proportional-Integral-Derivative) controller is commonly used in
- * linear control system, consider the the process.
+ * linear control system, consider the process.
  * G(s) = U(s)/E(s)
  * kp = proportional gain
  * ki = integral gain
index c9066ec..44d16d7 100644 (file)
@@ -27,6 +27,9 @@
 #define NR_LINES_TZDATA 1
 #define TMON_LOG_FILE "/var/tmp/tmon.log"
 
+#include <sys/time.h>
+#include <pthread.h>
+
 extern unsigned long ticktime;
 extern double time_elapsed;
 extern unsigned long target_temp_user;
index 9b68658..5b98f3e 100644 (file)
@@ -233,6 +233,24 @@ static unsigned long read_slab_obj(struct slabinfo *s, const char *name)
        return l;
 }
 
+static unsigned long read_debug_slab_obj(struct slabinfo *s, const char *name)
+{
+       char x[128];
+       FILE *f;
+       size_t l;
+
+       snprintf(x, 128, "/sys/kernel/debug/slab/%s/%s", s->name, name);
+       f = fopen(x, "r");
+       if (!f) {
+               buffer[0] = 0;
+               l = 0;
+       } else {
+               l = fread(buffer, 1, sizeof(buffer), f);
+               buffer[l] = 0;
+               fclose(f);
+       }
+       return l;
+}
 
 /*
  * Put a size string together
@@ -409,14 +427,18 @@ static void show_tracking(struct slabinfo *s)
 {
        printf("\n%s: Kernel object allocation\n", s->name);
        printf("-----------------------------------------------------------------------\n");
-       if (read_slab_obj(s, "alloc_calls"))
+       if (read_debug_slab_obj(s, "alloc_traces"))
+               printf("%s", buffer);
+       else if (read_slab_obj(s, "alloc_calls"))
                printf("%s", buffer);
        else
                printf("No Data\n");
 
        printf("\n%s: Kernel object freeing\n", s->name);
        printf("------------------------------------------------------------------------\n");
-       if (read_slab_obj(s, "free_calls"))
+       if (read_debug_slab_obj(s, "free_traces"))
+               printf("%s", buffer);
+       else if (read_slab_obj(s, "free_calls"))
                printf("%s", buffer);
        else
                printf("No Data\n");